includefile(release.yo)

htmlbodyopt(text)(#27408B)
htmlbodyopt(bgcolor)(#FFFAF0)
whenhtml(mailto(Frank B. Brokken: f.b.brokken@rug.nl))

DEFINEMACRO(lsvoption)(3)(\
    bf(--ARG1)=tt(ARG3) (bf(-ARG2))\
)
DEFINEMACRO(lsoption)(2)(\
    bf(--ARG1) (bf(-ARG2))\
)
DEFINEMACRO(lvoption)(2)(\
    bf(--ARG1)=tt(ARG2)\
)
DEFINEMACRO(loption)(1)(\
    bf(--ARG1)\
)
DEFINEMACRO(svoption)(2)(\
    bf(-ARG1) tt(ARG2)\
)
DEFINEMACRO(soption)(1)(\
    bf(-ARG1)\
)

DEFINEMACRO(itt)(1)(\
    it()tt(ARG1)\
)

DEFINEMACRO(itb)(1)(\
    it()bf(ARG1)nl()\
)

DEFINEMACRO(icm)(0)(bf(icmake))
DEFINEMACRO(Icm)(0)(bf(Icmake))

DELETEMACRO(tt)
DEFINEMACRO(tt)(1)(em(ARG1))

COMMENT( man-request, section, date, distribution file, general name)
manpage(icmake)(1)(_CurYrs_)(icmake._CurVers_.tar.gz)
        (A program maintenance utility)

COMMENT( man-request, larger title )
manpagename(icmake)(A program maintenance (em(make)) utility using a
                    bf(C)-like grammar)

COMMENT( all other: add after () )
manpagesynopsis()
       icm() [options] tt(source[.im] [dest[.bim]]) [-- [args]]

       bf(icmun) tt(bimfile)

manpagedescription()

      Icm()(1) is a generic tool handling program maintenance that can be used
as an alternative for bf(make)(1). It's a generic tool in that
tt(icmake)-scripts, written in a language closely resembling the bf(C)
programming language, can perform tasks that are traditionally the domain of
scripting languages.

Icm() allows programmers to use a programming language (closely resembling the
well-known bf(C)-programming language) to define the actions that are required
for (complex) program maintenance. For this, icm() offers various special
operators as well as a set of support functions that have shown their
usefulness in program maintenance.

Although icm() scripts can be written from scratch, often the required
activities are highly comparable. This observation resulted in the
construction of two icm() scripts, which are now part of the standard
icm() distribution: bf(icmstart)(1), initializing a directory for program
development and bf(icmbuild)(1), handling the actual program maintenance. Both
come predefined as scripts tailored to initializing and maintaining bf(C++)
programs (or, after minimal adaptation, bf(C) programs), but can easily be
adapted to other programming languages. Both bf(icmstart) and bf(icmbuild) can
be run without explicitly calling icm().

This man-page covers icm() (the program), its support programs, and
the syntax and facilities offered by bf(icmake's) scripting language. Refer to
the bf(icmstart)(1)) man-page for information about how a directory can be
initialized (created) in which (by default) a bf(C++) or bf(C) program can be
developed and refer to the bf(icmbuild)(1) man-page for information about how
bf(icmbuild) can be used to handle program maintenance.
    
Icm(), its support programs, and scripts do not offer an em(Integrated
Development Environment) (IDE). Icm() merely performs tasks for which
scripts can be written, and only a minimal set of pre-defined
scripts (bf(icmstart)  and bf(icmbuild)) that repeatedly have shown to be
extremely useful when developing and maintaining programs are included in the
icm() distribution.

In its standard operation mode, icm() calls the following programs:
    itemization(
    itt(icm-pp)  to preprocess the icmake file 
    itt(icm-comp)   to byte-code compile the icm()  file(s)
    it()tt(icm-dep) to handle class-dependencies (see sections bf(ICM-DEP)
        in this and bf(icmbuild)(1)'s man-pages for more information about
        tt(icm-dep)).
    it()tt(icm-exec)   to execute the byte-code file
    )

    The program bf(icmun)(1) disassembles compiled byte-code (.bim)
files. bf(Icmun) is mainly used for illustration, education, and debugging. As
it is not required for icm()'s daily use it is not installed in a
standard tt(PATH) directory but (since bf(icmake's) version 9.02.00) in
tt(icmake's) tt(lib) directory, which commonly is tt(/usr/lib/icmake).

Traditional make-utilities recompile sources once header files are
modified. When developing bf(C++) programs this is often a bad idea, as adding
a new member to a class does not normally require you to recompile all of the
class's source files. To handle class dependencies bf(icmbuld)(1) may inspect
class dependencies, (re)compiling sources of dependent classes whenever
necessary.  By default, class-dependencies are not interpreted, but this can
easily be changed by activating the tt(PRECOMP) and/or tt(USE_ALL) defines
which are found in the file tt(icmconf). Refer to the bf(icmconf)(7) man-page
for further details.

Precompiled header files can also be used. Precompiled header files
dramatically reduce the time that is required for compiling the source files
of classes. Refer to the bf(icmconf)(7) man-page (in particular the
description of the tt(PRECOMP) define) for further details.

This manpage describes icm()'s options in the next section. Following that
section icm()'s bf(C)-like scripting language and support programs are
described in the following separate sections:
    itemization(
    itb(PREPROCESSOR DIRECTIVES) - supported preprocessor directives, like
        tt(#include) and tt(#define);
    itb(DATA TYPES) - tt(int, list, string), and tt(void) (for functions);
    itb(PREDEFINED CONSTANTS) - like tt(O_FILE, OFF), and tt(S_IFREG);
    itb(OPERATORS) - like tt(+, younger), and casts
    itb(FLOW CONTROL) - tt(if, for, while), etc. (the tt(switch) is not
        available);
    itb(PREDEFINED FUNCTIONS) - executing programs, changing directories,
        operations on tt(string) and tt(list) type variables, etc.;
    itb(USER DEFINED FUNCTIONS) - at least tt(main), with or without its
        common parameters tt(argc, argv,) and tt(envp).
    itb(ICM-DEP) - the bf(icm-dep) dependency analyzer.
    itb(ICMUN) - a brief section about bf(icmun).
    )

manpageoptions()

    Where available, single letter options are listed between parentheses
beyond their associated long-option variants. 

    itemization(
    itt(--)nl() 
       This option separates icm() arguments from arguments passed to the .bim
        file.nl()
       Arguments beyond tt(--) are passed to the .bim file as-is, and are
        available from the tt(list argv) parameter available from the icm()
        script's tt(main) function's second parameter (see below at section
        bf(USER DEFINED FUNCTIONS)). For some options (see below) the tt(--)
        separator is not required.

    it() lsoption(about)(a)nl()
        Show information about icm() and terminate.

    it() lsoption(compile)(c)nl()
        The icm() source file is compiled, generating a .bim file.

    it() lsoption(execute)(e)nl()
        Execute the icm() .bim file, given as icm()'s first file
        argument. Any additional arguments are passed to the .bim file as-is,
        and tt(--) should not be specified.

    it() lsoption(force)(f)nl()
       The icmake source file is recompiled (even if the tt(.bim) file is
        up-to-date) either when no other options are specified, or when in
        combination with options tt(--source) and tt(--tmpbin).

    it() lsoption(help)(h)nl()
        Provides usage info.

    it() lsoption(icm-dep)(d)nl()
       Calls tt(/usr/lib/icmake/icm-dep), passing it all remaining
        arguments. If no additional arguments are specified tt(icm-dep's)
        short usage information is shown to the std. output stream. See
        sections bf(ICM-DEP) in this and bf(icbuild)(1)'s man-pages for more
        information about the tt(icm-dep) support program. An overview of
        tt(icm-dep's) options follows below, after this overview of icm()'s
        options.

    it() lsoption(preprocess)(p)nl()
        The icm() source file is only preprocessed, and the preprocessed
        file is written to icm()'s second
        file argument (by default tt(`source'.pim)).

    it() lsoption(source)(i)nl()
        The first argument is the icm() source file, the default binary
        file is constructed if necessary. Any additional arguments are passed
        to the .bim file as-is, and tt(--) should not be specified.

    it() lsoption(summary)(F)nl()
        The filenames and flags as well as an overview of all actions to
        be performed by icm() are shown on the standard output stream.

    it() svoption(t)(tmpbim)nl() 
       The tt(tmpbim) argument following tt(-t) is the name of a temporary
        .bim file, which is removed after icm()'s call. When tt(.) is
        specified for tt(tmpbim) then the default temporary directory,
        followed by icm()'s process-id, followed by tt(.bim) is used.

        Following the name of the temporary .bim file the name of the icm()
        source script must be specified. Any additional arguments are passed
        to the .bim file as-is, and tt(--) should not be specified; After
        setting the source script file's executable flag (tt(chmod +x
        script)), and providing it with an initial line like this: verb(
    #!/usr/bin/icmake -t.
            )
        the icm() script can directly be called:
            verb(
    script arg1 arg2 
            )
        in which case the icm() script tt(`script') is executed while it
        receives the arguments tt(script arg1 arg2).


    it() svoption(T)(directory)nl() 
       The specified directory is used to store temporary files. E.g., when
        compiling an icm() script, the output of icm()'s preprocessor is a
        temporary file which is removed on exit. By default tt(/tmp) is used,
        unless tt(/tmp) is not a writable directory, in which case the current
        user's tt($HOME) directory is used. Implicit temporary filenames
        always start with the process id of the current icm() process.

    it() lsoption(version)(v)nl()
        Displays icm()'s version number.
    )


manpagesection(PREPROCESSOR DIRECTIVES)

The following preprocessor directives are recognized:
    itemization(
    it() comment:nl()
       standard bf(C) comment (everything from tt(/*) through tt(*/)) as well
        as comment-to-end-of-line (line content starting at tt(//)) is
        ignored.
        
    it() Shell startup: The first line of the icm()-script may start with
        tt(#!path), where tt(path) defines the absolute location of the icm()
        program. By making the script executable, it can be called without
        explicitly calling icm().  

       E.g., if the first line of an (executable) icmakefile 'icm'
                  (without extension) contains
        verb(
    #!/usr/bin/icmake -i
        )
       then tt(icm) may be issued as a command, thus executing
        verb(
    /usr/bin/icmake -i icm ...
        )
       Alternatively, 
        verb(
    #!/usr/bin/icmake -t /tmp/icm
        )
       may be used, resulting in the execution of
        verb(
    #!/usr/bin/icmake -t /tmp/icm icm ...
        )
       In this case the binary file is removed on exit.

    itt(#include "filename")nl()
        The file tt(filename) is included at the location of the directive

    itt(#include <filename>)nl() 
       The file tt(filename) is included at the location of the tt(#include)
        directive; tt(filename) is searched in the colon-separated directories
        specified by the tt(IM) environment variable. The first occurrence of
        tt(filename) in the directories specified by the tt(IM) environment
        variable is used.

    itt(#define identifier [definition])nl() 
       The text tt(identifier) is replaced by tt(definition). The
        definition may contain references to already defined identifiers,
        using the tt(${identifier}) format. If the tt(${identifier}) hasn't
        been defined (yet), the text tt(${identifier}) is literally kept. To
        prevent infinite recursion at most 100 tt(${identifier}) replacements
        are allowed.

        Definitions continue at the next line if the last character on a line
        is a backslash (tt(\)).  (which is not included in the
        definition). The preprocessor concatenates double-quuted strings, and
        double quoted strings may not span multiple lines. Multiple blanks
        (outside of double quoted strings) in definitions are contracted to a
        single blank space.

        The definition following the tt(#define's) identifier is optional. If
        omitted, the macro is defined, so it can be used in tt(#if(n)def)
        directives (see below), but they are not replaced by any text in
        icm() code statements.

    itt(#ifdef identifier)nl() 
       If the tt(identifier) macro was defined the next block of code (until a
        matching tt(#else) or tt(#endif) directive was read) is
        byte-compiled. Otherwise, the block of code is ignored.

    itt(#ifndef identifier)nl() 
        If the tt(identifier) macro was em(not) defined the next block of code
        (until a matching tt(#else) or tt(#endif) directive was detected) is
        byte-compiled. Otherwise, the block of code is ignored.

    itt(#else)nl()
       Terminates a tt(#ifdef) and tt(#ifndef) directive, reversing the
        acceptance decision about the following code. Only one tt(#else)
        directive can be associated with tt(#if(n)def) directives.

    itt(#endif)nl()
       Terminates the preprocessor block starting at the matching 
        tt(#ifdef), tt(#ifndef) or tt(#else) directive. The tt(#endif)
        directory and its matching tt(#if(n)def) directive must be specified
        in the same file.

    itt(#undef identifier) nl()
       Remove tt(identifier) from the set of defined symbols. This does not
        affect the specification of any previously defined symbols in which
        tt(identifier's) definition has been used. If tt(identifier) hasn't
        been defined a warning is issued.
    )

manpagesection(DATA TYPES)

    Icm() supports the following five data and value types:
    itemization(
    itt(ASCII character constants)nl() 
       ASCII character constants are individual characters, surrounded by
        single or double quotes. Single characters (e.g., tt('a')) represent
        the character itself. Standard escape sequences (e.g., tt('\n')) are
        supported and represent their standard converted value (e.g., tt('\n')
        represents ascii value 10 (decimal)). Non-standard escape sequences
        (e.g., tt('\x')) represent the ascii character following the escape
        character (so tt('\x') equals tt('x')). Escape sequences consisting of
        three octal digits represent the ascii character corresponding to the
        octal value modulo 256 (e.g., tt('\123')). Escape sequences consisting
        of an x followed by two hexadecimal digits represent the ascii
        character corresponding to the hexadecimal value (e.g., tt('\xa4')).

    itt(int)nl() 
       Integral values, ranging from tt(-0x8000) through tt(0x7fff). tt(int)
        constants may be specified as decimal numbers (starting with digits 1
        through 9), octal numbers (starting with 0, followed by one or more
        octal digits) hexadecimal numbers (starting with 0x, followed by one
        or more hexadecimal digits) or as tt(ASCII) character constants.

    itt(string)nl()
       Text values: text (or `string') constants are delimited by double
        quotes. Multiple string constants may be concatenated, but a single
        string constant may not span multiple lines. String constants
        separated by white space only (i.e., blanks, newlines, comment) are
        concatenated and represent one single string constant. To indicate an
        end-of-line in a string constant use the tt(\n) escape sequence.

        ASCII character constants using double quotes can also be used
        in arithmetic expressions if one of the operands is an tt(int). 

        Likewise, ASCII character constants using single quotes may be
        used in situations where  string operands are expected.
        
    itt(list)nl()
       A data structure containing a series of individually accessible
        tt(string) values. When a list contains elements, its first element has
        index 0.

        List constants can also be defined. They consist of comma-separated
        strings (which may be tt(string) variables or expressions returning
        tt(string) values) and are surrounded by square brackets. E.g.,
    verb(
    list words = ["a", "list", "constant"];
    )

    itt(void)nl()
       Used with function definitions to indicate that the function does not
        return a value.
    )
    
    Variables can be defined at the global level as well as inside functions
(not only at the top of compound statements but also between statements and in
the initialization section of for-statements). When defined inside functions,
the standard bf(C) scoping and visibility rules apply. Variables are strongly
typed, and cannot have type tt(void).

    Variables may be initialized when they are defined. Initializations are
expressions which may use predefined or user-defined functions, constant
values, and values of variables. Functions or variables that are used for
initialization must be visible at the initialization point.

manpagesection(PREDEFINED CONSTANTS)

    The following predefined tt(int) constants are available:
    table(3)(lll)(
        rowline()
        row(cell(symbol)cell(value)cell(intended for))
        rowline()
        row(cell(O_ALL)cell(8)cell(makelist))
        row(cell(O_DIR)cell(2)cell(makelist))
        row(cell(O_FILE)cell(1)cell(makelist))
        row(cell(O_SUBDIR)cell(4)cell(makelist))
        rowline()
        row(cell(OFF)cell(0)cell(echo))
        row(cell(ON)cell(1)cell(echo))
        rowline()
        row(cell(P_CHECK)cell(0)cell(system calls))
        row(cell(P_NOCHECK)cell(1)cell(system calls))
        rowline()
        row(cell(S_IEXEC)cell(32)cell(stat))
        row(cell(S_IFCHR)cell(1)cell(stat))
        row(cell(S_IFDIR)cell(2)cell(stat        ))
        row(cell(S_IFREG)cell(4)cell(stat))
        row(cell(S_IREAD)cell(8)cell(stat        ))
        row(cell(S_IWRITE)cell(16)cell(stat))
        rowline()
    )

    The following constants are architecture dependent:
    table(2)(ll)(
        rowline()
        row(cell(symbol)cell(1 when defined on the platform, otherwise 0))
        rowline()
        row(cell(unix)  cell(Unix, usually with GNU's gcc compiler))
        row(cell(UNIX)  cell(may alternatively be available))
        row(cell(linux) cell(x86 running Linux (usually with gcc)))
        row(cell(LINUX)  cell(may alternatively be available))
        row(cell(M_SYSV, M_UNIX) cell(x86 running SCO/Unix))
        row(cell(_POSIX)cell(_SOURCE   Unix with Posix compliant compiler))
        row(cell(__hpux)cell(HP-UX, with the native HP compiler))
        rowline()
    )

manpagesection(OPERATORS)

bf(int-operators:)

    All bf(C) operators (including the ternary operator) are available (except
for pointer operators, as icm() does not support pointers). They operate like
their bf(C)-programming language's counterparts. Comparison operators return 1
if the comparison is true, otherwise 0 is returned.

bf(string-operators:)

    For tt(string) variables and/or constants the following
operators are available (tt(a) and tt(b) represent tt(string) variables or
constants): 

    itemization(
    itt(a + b): returns a new tt(string) value containing the concatenation of
tt(string) values tt(a) and tt(b). Note that tt(string) constants may be
directly concatetated (without using the tt(+) operator), e.g., the following
two lines both define the string tt("hello world"):
        verb(
    "hello "   "world"
    "hello " + "world"
        )

    itt(a += b): tt(a) must be a  tt(string) variable, to which the tt(string)
variable or value tt(b) is appended.

    it() string comparisons: operators tt(== != <= >= < > !=) and tt(==)
return 1 if the comparison is true, otherwise 0. Ordering comparison operators
use the (case sensitive) character ordering defined by the tt(ASCII) character
set.

    itt(!a): the boolean tt(!) (not) operator returns 1 if the tt(string a) is
empty, otherwise it returns 0. Strings containing white-space characters are
not empty.

    itt(a younger b, a newer b): returns 1 if file tt(a) is more recent than
file tt(b). E.g., tt("source.cc" newer "source.o"). The files tt(a) and tt(b)
do not have to exist:nl() 
    if both don't exist 0 is returned;nl()
    if tt(a) doesn't exist 0 is returned;nl()
    if tt(b) doesn't exist, 1 is returned;nl()
    if they are equally old 0 is returned.

    The predefined function tt(exists()) (see below, section bf(PREDEFINED
FUNCTIONS)) can be used to test explicitly whether a file exists).

    itt(a older b): returns 1 if file tt(a) is older than file tt(b). E.g.,
tt("libprog.a" older "source.o"). The files tt(a) and tt(b) do not have to
exist:nl()
    if both don't exist 0 is returned;nl()
    if tt(a) doesn't exist, 1 is returned;nl() 
    if tt(b) doesn't exist 0 is returned;nl()
    if they are equally old 0 is returned.

    itt([]): the index operator retrieves a character from a string variable
or constant: it returns a string as an em(rvalue). Thus, the following
statement compiles OK:
        verb(
     // assume str1 and str2 are strings
    str1 = str2[3];
        )
    but the following statement won't compile:
        verb(
    str2[3] = "a"; 
        )
        If an invalid (out of bounds) index value is specified an empty string
is returned.

    it() The `backtick` operator (tt(`string cmd`))nl()
       A string placed between two backticks is executed by the tt(popen)(3)
        function. The standard output gererated by the command that is stored
        in the string argument is returned as a list. An empty list indicates
        that the command could not be executed.nl()
       A command that could be executed but did not produce any output returns
        a list containing one empty element. The command's standard error
        stream output is not collected by the backtick operator. However,
        standard shell redirection may be used to collect the standard error
        stream's output. Example:
       verb(
    printf(`"ls"`);     // prints the elements in 
                        // the current directory
            )
        The predefined function tt(eval(string cmd)) behaves exactly like the
        backtick operator: they are synonyms.
    )

bf(list-operators:)

    For tt(list) type variables and/or values the following
operators are available:
    itemization(
    itt(a + b): returns a new tt(list) value containing the concatenation of
tt(list) values tt(a) and tt(b). This is em(not) a set operation: if an
element appears both in tt(a) and in tt(b), they will appear twice in the
resulting list (set-addition is provided by the built-in function
tt(listunion)).

    itt(a - b): returns a new tt(list) value containing the elements in tt(a)
that are not present in tt(b). This em(is) a set-difference operation: the
returned list contains all elements in tt(a) that are not elements of tt(b).

    itt(a += b): elements in tt(b) are added to the elements in tt(a), which 
must be a  tt(list) variable.  This is em(not) a set operation.

    itt(a -= b): elements in tt(b) are removed from the elements in tt(a),
which must be a tt(list) variable.  This em(is) a set operation: all elements
of tt(a) that are found in tt(b) are removed from tt(a).

    it() list equality comparisons: operators tt(!=) and tt(==) may be applied
to tt(list) values or variables. Operator tt(==) returns 1 if both lists have
element-by-element identical elements, otherwise 0 is returned. Operator
tt(!=) reverses the result of tt(==).

    itt(!a): the boolean tt(!) operator returns 1 if the tt(list a) is
empty, otherwise 0 is returned.

    itt([]): the index operator retrieves a list element from a list variable:
it returns a string as an em(rvalue). Therefore, the following statement
compiles OK:
        verb(
    // assume lst is a list, str is a string
    str = lst[3];
        )
    but the following statement won't compile:
        verb(
    lst[3] = str;
        )
        If an invalid (out of bounds) index value is specified an empty string
        is returned.
    )

bf(Casting:)

    Type-casts using the standard bf(C) cast-operator can be used to cast
    itemization(
    it() strings to ints and vice versa (tt((int)"123", (string)55))nl()
        If the content of a string does not represent a (decimal) tt(int)
        value 0 the cast returns  0;
    it() Strings to lists (tt(list lst = (list)"hello")): this returns a list
        having one element (tt(hello)) (note that casting a string to a list
        as shown is overkill as tt(list lst = ["hello"]) performs the same
        initialization). 
    )

manpagesection(FLOW CONTROL)

    Icm() offers the following subset of bf(C)'s statements. They can be
used as in the bf(C) programming language.
    itemization(
    itt(expression ;)nl()
        The plain expression statement;

    it() The compound statement nl()
        Variables of any type may be defined and initialized anywhere inside
        any compound statement. The em(visibility) of a variable starts at its
        point of definition.

    itt(if (condition) statement)nl()
        Inside the condition a variable may be defined and initialized. E.g,
            verb(
    if (string str = getText())
        process(str);
            )
        In this example, tt(process) is not called if tt(getText()) returns an
        empty string. The variable tt(str) does not exist either before or
        after the tt(if) statement.nl()
       Initialization and then using the variable in a subsequent expression,
        separated by a semicolon from the definition is not supported (e.g.,
        tt(if (string str = getText() ; str)) cannot be used).

    itt(if (condition) statement else statement)nl()
       Like the previous statement, inside the condition a variable may be
        defined and initialized.

    itt(for (init; condition; increment) statement)nl() 
       Variables (of a single type) may be initialized (and optionally be
        defined) in the tt(init) section. The tt(init), tt(condition) and
        tt(increment) sections may remain empty. The empty condition section
        is interpreted as `always tt(true)'.

    itt(while (condition) statement)nl()
        Inside the condition a variable may be defined and initialized.nl()
        A complementary  tt(do ... while()) statement is not available. Note
        that defining a variable, using an initialization expression means
        that the initialization expressing is executed at each iteration of the
        tt(while) statement. Thus the following statement never ends, and
        displays a never ending stream of values 10:
       verb(
    while (int x = 10)
        printf(x--, "\n");
        )

    itt(return;), and tt(return expression;)nl()
       Plain tt(return) statements can be used in tt(void) functions,
        and tt(return expression) statements are used in other type of 
        functions. The function tt(main) has return type tt(void) and so in
        tt(main) only plain tt(return) statements can be used. 
        By default an icm() script's exit value equals 0. Use the built-in
        function tt(exit) (see below) to specify any other exit value. 

        bf(Be advised: ) the behavior of non-void functions not returning
        values is undefined.

    itt(break)nl()
       Leaves tt(for) and tt(while) statements, overruling the statement's
        condition.

    itt(continue)nl()
       Continues with the next iteration of a tt(for) or tt(while)
        statement.

    itt(exit(expression))nl()
       Ends the execution of an icm()-script. The tt(expression) must
        evaluate to an tt(int) value, which becomes the script's exit value.
    )    


manpagesection(PREDEFINED FUNCTIONS)

    Icm() provides the following predefined functions, which can be used
anywhere in icm() scripts. The functions are ordered by categories, and within
categories they are ordered alphabetically by function name. Five categories
are distinguished:
    itemization(
    it() Functions operating on ints:nl()
       these functions only have one purpose: they receive tt(int) arguments
        and simply process those arguments;
    it() Functions operating on lists:nl()
       these functions only have one purpose: their main argument is a
        tt(list), which is somehow manipulated;
    it() Functions operating on strings:nl()
       these functions only have one purpose: their main argument is a
        tt(string), which is somehow manipulated;
    it() Functions manipulating filenames:nl()
       these functions receive filenames as their tt(string) arguments, and
        return modified filenames (e.g., by changing the argument's
        extension);
    it() System-related functions:nl()
       these functions interface to facilities provided by the operating
        system, like executing programs or changing the environment.
    )


bf(Functions operating on ints:)

    itemization(
    itt(string ascii(int value))nl() 
       returns tt(value) as a string: tt(ascii(65)) returns the string
        tt("A");
    itt(echo(int opt))nl() 
       controls echoing of called programs (and their arguments), specify
        tt(OFF) if echoing is not requested. By default tt(echo(ON)) is used;
    )

bf(Functions operating on lists:)

    itemization(
    itt(string element(int index, list (or string) var))nl()
       acts identically to the index operator: refer to the index (tt([]))
        operator in section bf(OPERATORS).

    itt(list fgets(string file, list offset))nl()
        see the bf(system functions) section;

    itt(int listfind(list lst, string str))nl()
       returns the first index in tt(lst) where the string tt(str) is found,
        or -1 if tt(lst) does not contain tt(str);

    itt(int listlen(list l))nl()
        returns the number of elements in tt(list);

    itt(list listunion(list lhs, list rhs))nl()
       returns a list containing the union of the elements in tt(lhs) and
        the elements of tt(rhs);

    itt(list listunion(list lst, string str))nl()
       returns a list containing the union of the elements in tt(lst) and
        tt(str);
    )

bf(Functions operating on strings:)

    itemization(
    itt(int ascii(string str))nl()
       returns the first character of tt(str) as an in: tt(ascii("A")) returns
        65;

    itt(string resize(string str, int newlength)) 
       returns a copy of string tt(str), resized to tt(newlength) characters.
        If tt(newlength) is negative then an empty string is returned, if
        tt(newlength) exceeds tt(str's) length then the newly added characters
        are initialized to blank spaces;

    itt(int strchr(string str, string chars))nl()
       returns the first index in tt(str) where any of the characters in
        tt(chars) is found, or -1 if tt(str) does not contain any of the
        characters in tt(chars);

    itt(int strlen(string str))nl()
       returns the number of characters in tt(str) (not counting the
        terminating NUL-character);

    itt(int strfind(string haystack, string needle))nl()
       returns index in tt(haystack) where tt(needle) is found, or -1 if
        tt(needle) is not found in tt(haystack);

    itt(int strformat(string format, argument(s)))nl()
       returns a string constructed from the tt(format) string containing
        placeholders %1 .. %2 to refer to arguments following the format
        string. The specification %1 refers to the first argument following
        the format string. If fewer arguments than tt(n) are provided then
        additional 0 arguments are provided by icm(). Example:nl() 
     verb(
    void main()
    {
        string s2 = = strformat("%1 %2 %1\n", 10, 20);
        printf("s2 = ", s2);        // shows: s2 = 10 20 10
    }
        )

   itt(string strlwr(string str))nl()
       returns a lower-case duplicate of tt(str);

    itt(list strtok(string str, string separators))nl()
       returns a list containing all substrings of tt(str) separated by one
        or more (consecutive) characters in tt(separators):
        tt(strtok("hello icmake's+world", " +")) returns a list containing
        the three strings tt("hello"), tt("icmake's"), and tt("world");

    itt(string strupr(string str))nl()
       returns an upper-case duplicate of tt(str).

    itt(string substr(string text, int offset, int count))nl()
       returns a substring of tt(text), starting at tt(offset), consisting of
        tt(count) characters. If tt(offset) exceeds (or equals) the string's
        size or if tt(count <= 0), then an empty string is returned. If
        tt(offset) is less than 0 then tt(offset = 0) is used;

    itt(string trim(string str))nl()
       returns a copy of tt(str) without leading and trailing white spaces;

    itt(string trimleft(string str))nl()
       returns a copy of tt(str) without leading white spaces;

    itt(string trimright(string str))nl()
        Returns a copy of tt(str) without trailing white spaces;
    )

bf(Functions manipulating filenames):

    itemization(
    itt(string change_base(string file, string base))nl()
       returns tt(file) whose base name is changed into tt(base):
        tt(change_base("/path/demo.im", "out")) returns tt("/path/out.im");

    itt(string change_ext(string file, string ext))nl()
       returns tt(file) whose extension is changed into tt(ext):
        tt(rss_changeExt("source.cc", "o")) returns tt("source.o"). The
        extension of the returned tt(string) is separated from the file's base
        name by a single dot (e.g., tt(rss_changeExt("source.", ".cc"))
        returns tt("source.cc"));

    itt(string change_path(string file, string path))nl()
       return tt(file) whose path is changed into tt(path):
        tt(change_path("tmp/binary", "/usr/bin")) returns 
        tt("/usr/bin/binary"). To remove the path specify tt(path) as an empty
        string;

    itt(string get_base(string file))nl()
        returns the base name of tt(file). The base name is the file without
        its path prefix and without its extension. The extension is all
        information starting at the final dot in the filename. If no final dot
        is found, the file name is the base name. E.g., the base name of
        tt(a.b) equals tt(a), the base name of tt(a.b.c) equals tt(a.b), the
        base name of tt(a/b/c) equals tt(c);

    itt(string get_dext(string file))nl()
       returns the extension of tt(file), including the separating dot (hence
        the tt(d) in tt(dext)). The extension is all information starting at
        the filename's final dot. If tt(file) does not have a final dot then
        an empty string is returned;

    itt(string get_ext(string file))nl()
       returns the extension of tt(file), without the separating dot. The
        extension are all characters in tt(file) starting at tt(file's) final
        dot. If no final dot is found, an empty string is returned;

    itt(string get_path(string file))nl() 
       returns tt(file's) path-prefix. The path prefix is all information
        up to (and including) the final directory separator (which is,
        depending on the operating system, a forward slash or a backslash).
        If no path is found, an empty strring is returned;
    )

bf(System-related functions:)

    itemization(
    itt(void arghead(string h))nl()
       helper function of tt(exec()) (see also below at tt(exec())):
        defines the `argument head' that is used with tt(exec()). By default,
        the `argument head' is an empty string. The argument head is text that
        is prefixed to tt(exec) arguments, like a directory in which provided
        arguments are found;

    itt(void argtail (string t))nl()
       helper function of tt(exec()) (see also below at tt(exec())): defines
        the `argument tail' that is used with tt(exec()). By default, the
        `argument tail' is an empty string. The argument tail is text that
        is appended to tt(exec) arguments, like the extensions of files that
        are passed as arguments to tt(exec);
    
    itt(string chdir([int check,] string dir))nl()
       returns the script's working directory at the point where tt(chdir) is
        called as an absolute path, and changes the script's working directory
        to tt(dir) (which may be specified as absolute or relative to the
        script's current working directory). The first argument is optional:
        if omitted and the change of directory cannot be performed then the
        icm()-script ends with exit value 1; by specifying tt(P_NOCHECK) the
        function won't terminate the script but merely returns the script's
        current working directory.

       Use tt(chdir(".")) to merely obtain the current working directory;
        use tt(chdir("")) to obtain the script's startup working directory;

    itt(cmdhead(string h))nl()
       helper function of tt(exec()) (see also below at tt(exec())).  Defines
        a `command head' that is used with tt(exec()). By default it is an
        empty string. It can be used to specify, e.g., compiler options when
        the arguments themselves are modified by tt(arghead) and tt(argtail).
        tt(Cmdhead) is used unmodified;

    itt(cmdtail(string t))nl()
       helper function of tt(exec()) (see also below at tt(exec())).  Defines
        a `command tail that is used with tt(exec()). By default it is an
        empty string. It can be used to specify a final argument (not modified
        by tt(arghead) and tt(argtail));

    itt(list eval(string str))nl()
       this function can be used instead of the backtick operator. The example
        provided with the backtick operator could therefore also
        have been written like this:
       verb( 
    printf(eval("ls")); // prints the elements in the current 
                        // directory 
        )

    itt(int exec([int check,] string cmd, argument(s)))nl()
       Executes the command tt(cmd) with (optional) arguments. Each argument
        is prefixed by tt(arghead) and postfixed by tt(argtail). Note that no
        blanks are inserted between tt(arghead), argument(s), and
        tt(argtail). The thus modified arguments are concatenated, separated
        by single blanks. tt(Cmdhead) is inserted between tt(cmd) and the
        first argument (delimited by single blanks) and tt(cmdtail) is
        appended to the arguments, separated by a single blank. tt(PATH) is
        searched to locate tt(cmd). 0 is returned.

       The first argument is optional: if omitted and the command does not
        return 0 the icm() script terminates. By specifying tt(P_NOCHECK)
        tt(exec) won't terminate the script but returns the called command's
        exit status, or tt(0x7f00) if the command wasn't found;

    itt(execute([int checking,] string cmd, string cmdhead,
            string arghead, argument(s), string argtail, string cmdtail))nl()
       Same functionality as the previous function, but the tt(cmdhead,
        arghead, argtail,) and tt(cmdtail) are explicitly specified (and are
        reset to empty strings after executing tt(cmd));

    itt(int exists(string file))nl()
       if tt(file) exists, 1 is returned, otherwise 0 is returned;

    itt(list fgets(string file, list offset))nl()
       the next line found at offset value tt(offset[3]) is read from
        tt(file). Pass an empty list to tt(fgets) to read tt(file) from its
        beginning.

       The returned list has four elements:

       its first element ([0]) contains the read line (without the line's
        tt(\n) line terminator);

       its second element ([1]) contains the line's tt(\n) line terminator (or
        an empty string if the line was not terminated by a tt(\n));

       its third element ([2]) contains the string tt(OK) if the line was
        successfully read and tt(FAIL) if reading from file failed;

       its fourth element ([3]) contains the offset beyond the last read byte.

       To read multiple lines, pass the returned list as argument to
        tt(fgets):
    verb(
    list ret;
    while (ret = fgets("filename", ret))
    {
        process(ret);
    }
    )

    itt(int fprintf(string filename, argument(s)))nl()
       appends all (comma separated) arguments to the file
        tt(filename). Returns the number of printed arguments. 

       If the first argument (following tt(filename)) contains placeholders
        (tt(%1, %2, ... %n)) then that argument is considered a format string
        (see also the function tt(strformat) in the string functions section
        for additional information about format strings). Some examples:
  verb(
    fprintf("out", "hello", "world", '\n'); 
    fprintf("out", "%1 %2\n", "hello", "world"); 
  )

    itt(string getch())nl()
       returns the next pressed key as a string (pressing the `Enter'-key is
        not required);

    itt(list getenv(string envvar))nl()
       returns the value of environment variable tt(envvar) in a list
        containing two elements:

       if the first element ([0]) is tt("1") then the environment variable was
        defined;

       environment variables are of the form tt(variable=value).  If element
        tt([0]) is tt("1") then the returned list's second element [1] holds
        the tt(value) part of the environment variable, which is empty if the
        environment variable is merely defined;

    itt(int getpid())nl() 
       returns the process-id of the icmake byte code interpreter
        bf(icm-exec);

    itt(string gets())nl()
       returns the next line read from the keyboard as a tt(string). The line
        contains all enteed characters until the `Enter'-key was pressed. The
        `Enter'-key's value itself is not stored in the returned string;

    itt(list makelist([int type = O_FILE], string mask))nl() 
       the argument tt(type) is optional, in which case tt(O_FILE) is used.
        tt(Makelist) returns a list of all tt(type) entries matching
        tt(mask). E.g., tt(makelist("*.c")) returns a list containing all
        files ending in tt(.c). For tt(type) one of the following set of
        values can be used to obtain a more specific selection of directory
        entries:
    table()(ll)(
        rowline()
        row(cell(symbol)cell(meaning))
        rowline()
        row(cell(O_ALL)cell(obtain all directory entries))
        row(cell(O_DIR)cell(obtain all directories, including . and ..))
        row(cell(O_FILE)cell(obtain a list of files))
        row(cell(O_SUBDIR)cell(obtain all subdirectories))
        rowline()
    )
       In Unix-type operating systems the pattern tt(*) does not match
        entries starting with a dot (hidden entries). To obtain a list of such
        entries use the pattern tt(.*);

    itt(list makelist([int type = O_FILE,] string mask, {newer,older},
        string comparefile))nl()
       the (optional) parameter tt(type) may be specified as in the previous
        variant of tt(makelist). The third parameter must be either tt(newer)
        (or tt(younger)) or tt(older). A list of all files is returned
        matching mask which are, resp., newer or older than a provided
        tt(comparefile). Note that tt(newer) and tt(younger) are operators,
        not strings;

    itt(int printf(argument(s)))nl()
       the function's (comma separated) arguments are written to the standard
        output file. If the first argument contains tt(%1, %2, ... %n)
        specifications then it's considered a format string (see also the
        function tt(strformat) in the string functions section for additional
        information about format strings). Like tt(fprintf printf) returns the
        number of printed arguments;

    itt(int putenv(string envvar))nl()
       adds tt(envvar) to the current icm()-script environment. Use the
        format: tt("VAR=value"). The function returns 0;

    itt(list stat([int check,] string entry))nl()
       Returns bf(stat)(2) information of directory entry tt(entry) as a
        list. The first argument is optional: if omitted and calling the
        system tt(stat) function fails then the icm()-script ends with exit
        value 1; by specifying tt(P_NOCHECK) the function won't terminate the
        script but returns the return value of the system tt(stat) function.

       The returned list has two elements:

       its first element ([0]) holds the entry's attributes.  Attributes are
        returned as or-ed combinations of the following bit-flags
        (cf. bf(stat)(2)):
    verb(
    S_IFCHR     S_IFDIR     S_IFREG
    S_IREAD     S_IWRITE    S_IEXEC
    )
        its second element ([1]) contains the entry's size in bytes;

    itt(int system([int check,] string command))nl()
       executes tt(command) using the bf(system)(3) function. The first
        argument is optional: if omitted and calling the bf(system)(3)
        function does not return 0 then the icm()-script ends with exit value
        1; by specifying tt(P_NOCHECK) icm()'s tt(system) function won't
        terminate the script but returns the return value of the bf(system)(3)
        function (normally the executed command's exit value). The string
        tt(command) may use redirection and/or piping;
    )

manpagesection(USER DEFINED FUNCTIONS)

bf(void main)

    Icm() scripts must be provided with a user-defined function tt(main). The
function tt(main) has three optional parameters, which may be omitted from the
last one (tt(envp)) to the first (tt(argc)), like in bf(C). Its full prototype
is (note: bf(void) return type):
        verb(
    void main(int argc, list argv, list envp)
        )
    In tt(main) the parameter
    itemization(
    itt(argc) represents the number of elements in tt(argv);

    itt(argv) contains the arguments, with element 0 being equal to the
        name of the tt(.bim) file;

    itt(envp) contains the `environment' variables. The function tt(listlen)
can be used to determine the number of its elements. Elements in tt(envp) have
the form tt(variable=value). Alternatively, the function tt(getenv) can be
used to retrieve a specific environment variable immediately.
    )
    Example (the implementations of the user-defined functions tt(usage,
modified,) and tt(compile) are left as an exercise for the reader):
        verb(
    void main(int argc, list argv)
    {
        if (argc == 1)
            usage(element(0, argv));

        if (list toCompile = modified("*.cc"))
        {
            for (int idx = listlen(toCompile); idx--; )
                compile(toCompile[idx]);
        }
    }    
        )
    After initializing all global variables in order of their definitions
tt(main) is called by icm()'s run-time support system. Icm() scripts end once
tt(main) returns (or tt(exit) is called by the script).

bf(Additionally defined user functions)

Additional functions may be defined. Once defined, they can be called. Forward
referencing of either variables or functions is not supported, but recursively
calling functions is. As function declarations are not supported indirect
recursion is not supported.

User-defined functions must have the following elements:
    itemization(
    it() The function's return type, which must be one of tt(void, int,
        string) or tt(list).  There is no default type. 

    it() The function's name, e.g., tt(compile).

    it() A parameter list, defining zero or more comma-separated
        parameters. The parameters themselves consist of a type name (tt(int,
        string), or tt(list)) followed by the parameter's identifier. E.g.,
        tt((string outfile, string source)).

    it() A em(body) surrounded by a pair of curly braces (tt({) and tt(})).
    )
     
   Function bodies may contain (optionally initialized) variable
definitions. Variable definitions start with a type name, followed by one or
more comma separated (optionally initialized) variable identifiers.  If a
variable is not explicitly initialized it is initialized by default. By
default an tt(int) variable is initialized to 0, a tt(string) is initialized
to an empty string (tt("")) and a tt(list) is initialized to an empty list.

    In addition to variable definitions, bodies may contain zero or more
statements (cf. section bf(FLOW CONTROL)). Note that variables may be defined
(and optionally initialized) anywhere inside functions, and also in the
conditions of tt(if) and tt(while) statements and in the initialization
section of tt(for) statements.

    The behavior of icm()-scripts using non-void functions that do not return
values is not defined. 

manpagesection(ICM-DEP) 

    The bf(icm-dep) program is a support program for icm() to determine
source-file dependencies. It is called automatically when tt(USE_ALL) or
tt(PRECOMP) is specified in the tt(icmconf) file that is processed by icm().

    To start its work, the dependencies-analyzer tt(icm_dep) needs one
command-line argument: tt(go). Any other argument results in tt(icm_dep)
performing a `dry run': it then performs all its duties (and verbose messages
are displayed as if tt(go) had been specified), but no files (precompiled
headers or tt(USE_ALL) files) are touched or removed. If neither options
nor arguments are specified tt(icm_dep) writes its usage summary to the
standard output.

    Options of bf(icm-dep) may immediately after icm()'s tt(--icm-dep) option
be specified. The following options are recognized:
    itemization(
    it() lsvoption(classes)(c)(filename)nl()
       by default, bf(icm-dep) inspects dependencies of the classes whose
        directories are mentioned in the file tt(CLASSES). Furthermore, if the
        bf(icmconf)(7) file specifies tt(PARSER_DIR) and tt(SCANNER_DIR) then
        those directories are also considered.  Use this option if instead of
        tt(CLASSES) another file should be inspected;

    it() lsoption(help)(h)nl()
       bf(icm-dep) writes a summary of its usage to the standard output and
        terminates;

    it() lsvoption(icmconf)(i)(filename)nl() 
       by default bf(icm-dep) inspects the content of tt(icmconf) files,
        looking for tt(USE_ALL) and tt(PRECOMP) specifications. Use this
        option if instead of tt(icmconf) another file should be inspected;

    it() lsvoption(mainih)(m)(mainheader)nl()
       the tt(icmconf) file uses the tt(#define IH) parameter to specify the
        suffix of class header files that should be precompiled, their
        filenames being equal to the names of the classes mentioned in the
        tt(CLASSES) file. tt(CLASSES) does not specify a top-level
        directory. The name of the top-level header file to precompile can be
        specified using this option. By default it is tt(main.ih); 

    it() loption(gch)nl() 
       by default precompiled header files are inspected if tt(icmconf)
        contains a tt(#define PRECOMP) specification. If it does not, but
        precompiled headers should nonetheless be inspected, the option
        tt(--gch) can be provided;

    it() loption(no-gch)nl() 
       by default precompiled header files are inspected if tt(icmconf)
        contains a tt(#define PRECOMP) specification. If in that case
        precompiled headers should em(not) be inspected, the option
        tt(--no-gch) can be provided;

    it() loption(no-use-all)nl()
       by default files named at the tt(#define USE_ALL) specification are
        inspected if tt(icmconf) contains such a specification. To suppress
        inspections of tt(`USE_ALL') files provide this option;

    it() lvoption(use-all)(filename)nl()
       by default files named at tt(#define USE_ALL) specifications of
        tt(icmconf) files are inspected. If the tt(USE_ALL) define is not
        specified but tt(`USE_ALL') files should nonetheless be inspected,
        then provide this option, specifying the name of files to use as
        tt(USE_ALL) files;

    it() lsoption(verbose)(V)nl() 
       this option can be specified multiple times. The number of times it is
        specified determines bf(icm_dep)'s verbosity. If not used then
        bf(icm-dep) silently performs its duties. If specified once, then
        bf(icm-dep) reports to the standard output what actions it performs;
        if specified twice it also reports the class dependencies; if
        specified more often it reports what files it encountered and what
        situations caused it to make its decisions;

    it() lsoption(version)(v)nl() 
        bf(icm-dep) reports  its version number to the standard output and
        terminates. 
    )

manpagesection(icmun)

    The tt(icmun) program expects one argument, the binary (tt(bimfile)) file
produced by `icm() tt(-c)'. It disassembles the binary file an shows the
assembler instructions and structure of the binary file. Note that in standard
installations bf(icmun) is not located in one of the directories of the
tt(PATH) environment variable, but is located in the tt(/usr/lib/icmake)
directory.

As an illustration, assume the following script is compiled by icm() (e.g., by
calling tt(icmake -c demo.im)):
        verb(
    void main()
    {
        printf("hello world");
    }
        )
    the resulting tt(demo.bim) file can be processed by bf(icmun) (e.g.,
calling tt(/usr/lib/icmake/icmun demo.bim). bf(Icmun) then writes the
following to the standard output fle:

        verb(
    icmun by Frank B. Brokken (f.b.brokken@rug.nl)
    icmun V9.03.00, copyright (c) GPL 1992-2020.
    
    Binary file statistics:
        strings           at offset 0x0025
        variables         at offset 0x0031
        filenames         at offset 0x0031
        first instruction at offset 0x001f
    
    String constants dump:
        "hello world"
    
    Disassembled code:
        [0014] 06 00 00   push string "hello world"
        [0017] 05 01 00   push int 0001
        [001a] 1b 1d      callrss 29 (printf)
        [001c] 1c 02      add sp, 2
        [001e] 23         ret
        [001f] 21 14 00   call [0014]
        [0022] 04         push int 0
        [0023] 24         pop reg
        [0024] 1d         exit
        )

manpagefiles()

    The mentioned paths are sugestive only and may vary over different
icm()-installations:
    itemization(
    it() bf(/usr/bin/icmake): the main icm() program;
    it() bf(/usr/bin/icmbuild): the wrapper program around the tt(icmbuild)
        script handling standard program maintenance;
    it() bf(/usr/bin/icmstart): an icm()-script that is can be used to create
        the startup-files of new projects;
    it() bf(/usr/lib/icmake/icm-comp): the compiler called by icm();
    it() bf(/usr/lib/icmake/icm-exec): the byte-code interpreter called by
            icm(); 
    it() bf(/usr/lib/icmake/icm-dep): the support program handling class- and
            precompiled header dependencies;
    it() bf(/usr/lib/icmake/icm-pp): the preprocessor called by icm();
    it() bf(/usr/lib/icmake/icmun): the icm() unassembler.
    )

manpagesection(EXAMPLES)
    
    The distribution (usually in tt(/usr/share/doc/icmake)) contains a
directory tt(examples) containing additional examples of icm() script.

manpageseealso()
    bf(icmbuild)(1), bf(icmconf)(7), 
    bf(icmstart)(1), bf(icmstart.rc)(7), bf(make)(1)

manpagebugs()
    Standard comment starting  on lines containing preprocessor directives
        may not extend over multiple lines.

    Path names containing blanks are not supported.

    The functions tt(sizeof(list lst)) and tt(sizeoflist(list lst)) are
        deprecated and should no longer be used. They are removed in a future
        version of icm(). Use tt(listlen(list lst)) instead.

includefile(trailer.inc)
