Provided by: icmake_10.03.00-1_amd64 bug

NAME

       icmscript - The C-like icmake scripting language

DESCRIPTION

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

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

       This man-page covers the icmake scripting language in de following sections:

       o      DATA TYPES
              - int, list, string, and void (for functions);

       o      OUTLINE
              - outline of icmake scripts: what are their requirements, the structure and organization of  their
              main-functions.

       o      PREPROCESSOR DIRECTIVES
              - supported preprocessor directives, like #include and #define;

       o      PREDEFINED CONSTANTS
              - like O_FILE, OFF, and S_IFREG;

       o      OPERATORS
              - like +, younger, and casts

       o      FLOW CONTROL
              - if, for, while, etc. (the switch is not available);

       o      PREDEFINED FUNCTIONS
              -  executing  programs,  changing directories, operations on string and list type variables, etc..
              Functions are marked as INT FUNCTIONS, LIST FUNCTIONS, STRING FUNCTIONS

       o      USER DEFINED FUNCTIONS
              - at least main, with or without its common parameters argc, argv, and envp.

DATA TYPES

       Icmake supports the following five data and value types:

       o      ASCII character constants
              ASCII character constants are ascii-characters, surrounded by  single  or  double  quotes.  Single
              characters  (e.g., ’a’) represent the character itself. Standard escape sequences (e.g., ’\n’) are
              supported and are converted to their well-known values  (e.g.,  ’\n’  represents  ascii  value  10
              (decimal)).  Non-standard  escape  sequences  (e.g.,  ’\x’)  are  converted to the ascii character
              following the escape character (so ’\x’ equals ’x’). Escaped sequences consisting of  three  octal
              digits  represent  the  ascii character corresponding to the octal value, modulo 256 (e.g., ’\113’
              represents ’K’). Escape sequences consisting of an x followed by two hexadecimal digits  represent
              the ascii character corresponding to the hexadecimal value (e.g., ’\x4b’, also representing ’K’);

       o      int
              Integral  values,  ranging  from -0x8000 through 0x7fff. 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 ASCII character constants;

       o      string
              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. Multiple
              string constants, only separated by white space (i.e., blanks, newlines, comment) are concatenated
              and are considered one single string constant. To indicate an end-of-line in a string constant use
              the \n escape sequence;

              If arithmetic expressions use at least one int operand then those  expressions  may  also  contain
              single  character  ASCII  constants  using  double  quotes.  In  those  cases  they  represent the
              ascii-values of their characters.

              Conversely, ASCII character constants using single quotes may be used in situations where   string
              operands are expected;

       o      list
              A  list  is  a data structure containing a series of individually accessible string values. When a
              list contains elements, its first element has index 0;

              Lists may be written to the standard output stream or to file (using printf or fprintf). Lists can
              also  be  inserted  into  string  variables  using strformat. In these cases all (space delimited)
              elements of the lists are inserted into their destinations;

              Lists can also be defined as constants. They consist of an  optional  series  of  comma  separated
              string constants surrounded by a pair of square brackets. E.g.,

                  list words = ["a", "list", "constant"];

       o      void
              The  type  void  is  used  when  defining  functions to indicate that such functions do not return
              values. Alternatively, functions may return int, string or list values (cf. section  USER  DEFINED
              FUNCTIONS).

       Variables can be defined at the global level inside functions (not only at the top of compound statements
       but also between statements and in the initialization section of for- and  if-statements).  When  defined
       inside  functions,  the  standard C scoping and visibility rules apply. Variables are strongly typed, and
       cannot have type 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.

OUTLINE

       Icmake scripts require a user-defined function main. The function main  has  three  optional  parameters,
       which may be omitted from the last one (envp) to the first one (argc), like in C. Its full prototype is:

           void main(int argc, list argv, list envp)

       or

           int main(int argc, list argv, list envp)

       When  a  void  main  function  ends  (using  a return; statement or when its execution reaches its body’s
       closing curly) the value 0 is returned to the operating system. When int main functions end using  return
       statements  then those statements must be provided with int-expressions. It’s OK when the execution of an
       int main function reaches its body’s closing curly, om which case 0  is  automatically  returned  to  the
       operating system

       In main the parameter

       o      argc represents the number of elements in argv;

       o      argv  contains  the  arguments, with element 0 being equal to the name of the .bim file, that were
              passed to the .bim file. The OPTIONS section of the icmake(1) manpage covers how  these  arguments
              are forwarded to the icmake script using options -e, -s, and -t.

       o      envp  contains  the  `environment’  variables.  The  (predefined)  function listlen can be used to
              determine  the  number  of  its  elements.  Elements  in  envp  use  the  format   variable=value.
              Alternatively,  the  (predefined)  function  getenv can be used to retrieve a specific environment
              variable immediately.

       Example (the implementations of the user-defined functions usage, modified, and compile are  left  as  an
       exercise for the reader):

           void main(int argc, list argv)
           {
               if (argc == 1)
                   usage(argv[0])
       ;

       if   (list   toCompile   =   modified("*.cc"))   {   for   (int   idx   =  listlen(toCompile);  idx--;  )
       compile(toCompile[idx]); } } ) When executing an icmake script icmake’s  run-time  support  system  first
       initializes  all  all global variables in the order of their definitions. Followin this the function main
       is called. The script ens once once main returns or when the (predefined) function exit is called by  the
       script).

PREPROCESSOR DIRECTIVES

       Before  actually  compiling  icmake scripts they are first pre-processed by the icmake pre-processor. The
       pre-processor removes comment, includes files specified by include-directives, and processes #define  and
       comparable directives.

       The following preprocessor directives are recognized:

       o      comment:
              standard  C comment (everything from /* through */) as well as comment-to-end-of-line (starting at
              //, continuing to the end of the line) is ignored;

       o      Shell startup: The first line of the icmake-script may start with #!path, where path  defines  the
              absolute location of the icmake program. By making the script executable, it can be called without
              explicitly calling icmake.

              E.g., if the first line of an (executable) icmakefile ’icm’ (without extension) contains

                  #!/usr/bin/icmake -t.

              then icm can be issued as a command, interpreting the remaining content of the script as an icmake
              source  which is compiled and then executed by icmake. In these cases the binary files are removed
              when the scipts end;

       o      #include "filename"
              The file filename is included at the location of the directive;

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

       o      #define identifier [definition]
              The text identifier is replaced by definition. The definition may contain  references  to  already
              defined  identifiers,  using  the  format  ${identifier}. If the ${identifier} hasn’t been defined
              (yet), the literal text  ${identifier}  is  used.  To  prevent  infinite  recursion  at  most  100
              ${identifier} replacements are accepted;

              If  the  last  character  on a line is a backslash (\) then definitions continue at the next line.
              (the backslash is not included in the definition).  The  preprocessor  concatenates  double-quoted
              strings.  Double  quoted  strings  may not span multiple lines. Multiple blanks (outside of double
              quoted strings) in definitions are contracted to a single blank space;

              Following the #define’s identifier a definition may optional be provided. If omitted, the macro is
              defined,  so  it  can  be  used  in  #if(n)def  directives  (see  below), but in those cases these
              intentifiers are simply removed from icmake code statements.

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

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

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

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

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

PREDEFINED CONSTANTS

       The following predefined int constants are available (the functions listed in the intended for column are
       described in the upcoming sections covering the predefined functions):

       ─────────────────────────────────
       symbol      value   intended for
       ─────────────────────────────────
       O_ALL       8       makelist
       O_DIR       2       makelist
       O_FILE      1       makelist
       O_SUBDIR    4       makelist
       ─────────────────────────────────
       OFF         0       echo
       ON          1       echo
       ─────────────────────────────────
       P_CHECK     0       system calls
       P_NOCHECK   1       system calls
       ─────────────────────────────────
       S_IEXEC     32      stat
       S_IFCHR     1       stat
       S_IFDIR     2       stat
       S_IFREG     4       stat
       S_IREAD     8       stat
       S_IWRITE    16      stat
       ─────────────────────────────────

       The following constants are architecture dependent:

       ──────────────────────────────────────────────────────────────
       symbol           1 when defined on the platform, otherwise 0
       ──────────────────────────────────────────────────────────────
       unix             Unix, usually with GNU’s gcc compiler
       UNIX             may alternatively be available
       linux            x86 running Linux (usually with gcc)
       LINUX            may alternatively be available
       M_SYSV, M_UNIX   x86 running SCO/Unix
       _POSIX           _SOURCE   Unix with Posix compliant compiler
       __hpux           HP-UX, with the native HP compiler
       ──────────────────────────────────────────────────────────────

OPERATORS

       Since  icmake  version  10.00.00  the  <<  operator  can be used like the C++ insertion operator. See the
       description of the functions printf and fprintf below.

       int-operators:

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

       string-operators:

       For string variables and/or constants the following operators are  available  (lhs  and  rhs  are  string
       variables or constants):

       o      lhs  +  rhs:  returns a new string value containing the concatenation of strings lhs and rhs. Note
              that string constants can also directly be concatetated (not using  the  +  operator),  e.g.,  the
              following two lines both define the string "hello world":

                  "hello "   "world"
                  "hello " + "world"

       o      lhs += rhs: lhs must be a string variable, to which the string variable or value rhs is appended;

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

       o      !lhs:  the boolean ! (not) operator returns 1 if the string lhs is empty, otherwise 0 is returned.
              Strings containing white-space characters are not empty;

       o      lhs younger rhs, lhs newer rhs: returns 1 if  file  lhs  is  more  recent  than  file  rhs.  E.g.,
              "source.cc" newer "source.o". The files lhs and rhs do not have to exist:

              o      if both don’t exist 0 is returned,

              o      if lhs doesn’t exist 0 is returned,

              o      if rhs doesn’t exist, 1 is returned,

              o      if they are equally old 0 is returned.

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

       o      lhs older rhs: returns 1 if file lhs is older than file rhs. E.g., "libprog.a"  older  "source.o".
              The files lhs and rhs do not have to exist:

              o      if both don’t exist 0 is returned,

              o      if lhs doesn’t exist 1 is returned,

              o      if rhs doesn’t exist, 0 is returned,

              o      if they are equally old 0 is returned.

       o      []:  the  index  operator  returns  a  character  from  a string variable or constant. A string is
              returned as an rvalue. Thus, the following statement compiles OK:

                  lhs = rhs[3];

              but the following statement won’t compile:

                  lhs[3] = "a";

              If an invalid (out of bounds) index value is specified an empty string is returned.

       o      The backtick operator (`string cmd`)
              A string placed between two backticks is executed as a separate command. Different from  the  exec
              and  system  calls  the backtick operator collects the standard output produced by `cmd’ returning
              this output as a list. The elements of the list contain the subsequent lines of output  (including
              a final newline, if present) produced by `cmd’. An empty list indicates that the command could not
              be executed.

              Note that a command that could be executed but that did not produce  any  output  returns  a  list
              containing  one  string  element,  which  is  empty. The command’s standard error stream output is
              ignored by the backtick operator. However, standard shell redirection may be used to  collect  the
              standard error stream’s output. Example:

                  printf << `"ls"`;   // prints the elements in
                                      // the current directory

              Also  note  that  the  backtick operator requires a string argument: either a string constant or a
              string variable.

              The predefined function eval(string cmd) behaves exactly like  the  backtick  operator:  they  are
              synonyms.

       list-operators:

       For list variables and/or values the following operators are available:

       o      lhs  +  rhs:  returns a new list value containing the concatenation of the values of lists lhs and
              rhs. This is not a set operation: if an element appears both in lhs and in  rhs,  then  both  will
              appear in the resulting list (set-addition is provided by the built-in function listunion);

       o      lhs  -  rhs:  returns a new list value containing the elements in lhs that are not present in rhs.
              This is a set-difference operation. The ordering of the remaining elements in the returned list is
              equal to the ordering of those elements in lhs;

       o      lhs += rhs: elements in rhs are added to the elements in lhs, which must be a list variable.  This
              is not a set operation;

       o      lhs -= rhs: elements in rhs are removed from the elements in lhs.  This is a  set  operation:  all
              elements of lhs that are found in rhs are removed from lhs. The ordering of the remaining elements
              in lhs is not altered;

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

       o      !lhs: the boolean ! operator returns 1 if the list lhs is empty, otherwise 0 is returned;

       o      []: the index operator retrieves an element from a list  variable:  it  returns  a  string  as  an
              rvalue. Thus, the following statement compiles OK:

                  // assume lst is a list, str is a string
                  str = lst[3];

              but the following statement won’t compile:

                  lst[3] = str;

              If an invalid (out of bounds) index value is specified an empty string is returned.

       Casting:

       Type-casts using the standard C-style cast-operator can be used to cast:

       o      strings to ints and vice versa ((int)"123", (string)55)
              If the content of a string does not represent a (decimal) int value 0 the cast returns  0;

       o      Strings  to lists (list lst = (list)"hello"): this returns a list having one element (hello) (note
              that casting a string to a list as shown is overkill as list lst =  ["hello"]  performs  the  same
              initialization).

FLOW CONTROL

       Icmake offers a subset of C’s flow control statements. They can be used as in the C programming language.

       o      expression ;
              The plain expression statement.

              Insert-expression  statements  are  defined  for  the  functions  fprintf  and  printf. Expression
              statements may start with printf << or fprintf <<  filename  <<.  The  values  of  all  subsequent
              expressions,  separated by << operators (which in this context are called insertion operators) are
              written to the standard output stream (when using printf  <<),  or  to  the  file  whose  name  is
              provided in the string filename (when using fprintf << filename <<).  Examples:

                  printf << "hello" << ’ ’ << "world" << ’\n’;
                  fprintf << "out.txt" << "hello" << ’ ’ << "world" << ’\n’;

       o      The compound statement
              Variables  may be defined and initialized inside compound statements at locations where expression
              statements can also be used. The visibility of variables starts at their points of definition;

       o      if ([definition;] condition) statement
              The [definition;] phrase is optional. If used it defines a type followed by a comma-separated list
              of variables which may be provided with initialization expressions.

              The condition phrase is required, and may define and initialize a variable. E.g,

                  if (string str = getText())
                      process(str);

              In this example, process is not called if getText() returns an empty string.

              Variables  defined in the definition and condition phrases do not exist either before or after the
              if statement.

       o      if ([definition;] condition) statement1 else statement2
              Acts like the previous statement. If  the  condition  is  true  statement1  is  executed;  if  the
              condition is false statement2 is executed;

       o      for (init; condition; increment) statement
              Variables  (of a single type) may be initialized (and optionally defined) in the init section. The
              condition phrase may define and initialize a variable. The init, condition and increment  sections
              may remain empty. An empty condition section is interpreted as `always true’;

       o      while (condition) statement
              Inside the condition a variable may be defined and initialized.

              A  complementary  do  ... while() statement is not available. Note that when a variable is defined
              and initialized in the condition  section  the  initialization  expression  is  executed  at  each
              iteration  of  the  while statement. Thus the following statement never ends, and displays a never
              ending stream of values 10:

                  while (int x = 10)
                      printf(x--, "\n");

       o      return;, and return expression;
              Plain return statements can be used in void functions, and return expression statements  are  used
              in other type of functions.

       o      break
              break; statements can only be used in for and while statements, ending those statements;

       o      continue
              continue;  statements  can  only  be  used  in  for  and  while  statements, continuing their next
              iteration.

PREDEFINED FUNCTIONS

       Icmake provides the following predefined functions, which can be used anywhere in icmake scripts. In  the
       following  overview  the  functions  are  ordered  by  categories, and within categories they are ordered
       alphabetically by function name.

       Five categories are distinguished:

       o      Functions operating on ints (see INT FUNCTIONS below):
              these functions receive int arguments, processing those arguments;

       o      Functions operating on strings (see STRING FUNCTIONS below):
              these functions operate on the strings which are passed to these functions as arguments;

       o      Functions operating on lists (see LIST FUNCTIONS below):
              these functions operate on the lists which are passed to these functions as arguments;

       o      Functions manipulating file system entries (see FILESYSTEM FUNCTIONS below):
              these functions receive the names of file-system  entries  (files,  directories,  etc.)  as  their
              string arguments.

              Note  that these functions are not listed in the STRING FUNCTIONS section, as they do not directly
              operate on their string arguments, but merely use those arguments to identify file system entries.

              On the other hand, functions like change_base do  not  operate  on  file-system  entries  and  are
              therefore entries in the STRING FUNCTIONS section;

       o      System-related functions (see SYSTEM FUNCTIONS below):
              these  functions interface to facilities provided by the operating system, like executing programs
              or changing the script’s environment variables. Some of these functions  use  specialized  support
              functions, which are also included in this section.

       INT FUNCTIONS:

       o      string ascii(int value)
              returns value as a string: ascii(65) returns the string "A";

       o      echo(int opt)
              controls  echoing  of  called  programs  (and  their  arguments),  specify  OFF  if echoing is not
              requested. By default echo(ON) is active.

       STRING FUNCTIONS:

       o      int ascii(string str)
              returns the first character of str as an in: ascii("A") returns 65;

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

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

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

       o      string element(int index, string var)
              acts identically to the index operator: refer to the index ([]) operator in section OPERATORS;

       o      string get_base(string file)
              returns the base name of 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 a.b equals a, the  base  name
              of a.b.c equals a.b, the base name of a/b/c equals c;

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

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

       o      string get_path(string file)
              returns 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 file does not contain a path-element, then an empty string is returned;

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

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

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

       o      string strformat(string format, argument(s))
              returns  a  string constructed from the 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 n are provided then additional 0 arguments are provided
              by icmake. Example:

                  void main()
                  {
                      string s2 = = strformat("%1 %2 %1\n", 10, 20);
                      printf("s2 = ", s2);        // shows: s2 = 10 20 10
                  }

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

       o      string strlwr(string str)
              returns a lower-case duplicate of str;

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

       o      string strupr(string str)
              returns an upper-case duplicate of str.

       o      string substr(string text, int offset, int count)
              returns a substring of text, starting at offset, consisting of count characters. If offset exceeds
              (or  equals)  the string’s length or if count <= 0, then an empty string is returned. If offset is
              less than 0 then offset = 0 is used. If offset + count exceeds text’s length  then  the  available
              substring starting at text[offset] is returned (which may be empty);

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

       o      string trimleft(string str)
              returns a copy of str without leading white spaces;

       o      string trimright(string str)
              Returns a copy of str without trailing white spaces.

       LIST FUNCTIONS:

       o      string element(int index, list var)
              acts identically to the index operator: refer to the index ([]) operator in section OPERATORS;

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

       o      int listlen(list l)
              returns the number of elements in list;

       o      list listunion(list lhs, list rhs)
              returns a list containing the union of the elements in lhs and the elements of rhs.  The  original
              order of the elements in lhs is kept. Subsequent elements in rhs that are not available in lhs are
              added to the end of lhs;

       o      list listunion(list lst, string str)
              returns a list containing the union of the elements in lst and str.  The  original  order  of  the
              elements in lhs is kept. If rhs is not available in lhs then it is added to the end of lhs.

       FILESYSTEM FUNCTIONS:

       o      string chdir([int check,] string dir)
              changes  the  script’s working directory to dir (which may be specified as absolute or relative to
              the script’s current working directory). The first argument is optional: if omitted  and  changing
              the working directory fails then the icmake-script ends with exit value 1; by specifying P_NOCHECK
              the function won’t terminate the script but merely returns the script’s current working directory.
              The  script’s working directory after completing the change-dir request is returned as an absolute
              path, ending in a `/’ directory separator.

              Use chdir(".") to merely obtain the current working directory; use chdir("") to change-dir to  the
              script’s startup working directory;

       o      int exists(string file)
              if file exists, 1 is returned, otherwise 0 is returned;

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

              The returned list has four elements:

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

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

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

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

              To read multiple lines, pass the returned list as argument to fgets:

                  list ret;
                  while (ret = fgets("filename", ret))
                      process(ret);

              Be careful not to define list ret in while’s condition, as this will reset ret to an empty list at
              each iteration;

       o      int fprintf(string filename, argument(s))
              appends  all  (comma or left-shift (insertion) operator separated) arguments to the file filename.
              Returns the number of printed arguments.

              If the first argument (following filename) contains  placeholders  (%1,  %2,  ...  %n)  then  that
              argument  is  considered  a format string (see also the function strformat in the string functions
              section for additional information about format strings). Some examples:

                  fprintf("out", "hello", "world", ’\n’);
                  fprintf << "out" << "hello" << "world" << ’\n’;

                  fprintf("out", "%1 %2\n", "hello", "world");           // 1
                  fprintf << "out" << "hello" << ’ ’ << "world" << ’\n’; // 2
                  fprintf << "out" << "%1 %2\n" << "hello" << "world";   // 3

              When writing statement 1 using insertion operators (cf. the expression  statement  description  in
              section  FLOW CONTROL)  statement 2 would normally be encountered, although statement 3, using the
              format string, would still be accepted;

       o      string getch()
              returns the next pressed key as a string (pressing the `Enter’-key is not required).  The  pressed
              key is not echoed. If the key should be echoed use, e.g., printf(getch());

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

       o      list makelist([int type = O_FILE], string mask)
              the  argument type is optional, in which case O_FILE is used.  Makelist returns a list of all type
              file-system entries matching mask. E.g., makelist("*.c")  returns  a  list  containing  all  files
              ending  in  .c.  For type one of the following set of values can be used to obtain a more specific
              selection of directory entries:

              symbol     meaning
              O_ALL      obtain all directory entries
              O_DIR      obtain all directories, including . and ..
              O_FILE     obtain a list of regular files
              O_SUBDIR   obtain all directories except for . and ..

              In Unix-type operating systems the pattern * does not match entries starting with  a  dot  (hidden
              entries). To obtain a list of such entries use the pattern .*;

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

       o      int printf(argument(s))
              the function’s (comma or left-shift (insertion) operator separated) arguments are written  to  the
              standard  output  file (cf.  the expression statement description in section FLOW CONTROL and this
              section’s description of the fprintf function). If the first argument  contains  %1,  %2,  ...  %n
              specifications then it’s considered a format string (see also the function strformat in the STRING
              FUNCTIONS section for additional information about format strings). Like  fprintf  printf  returns
              the number of printed arguments;

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

              The returned list has two elements:

              its first element ([0]) holds the entry’s attributes.  Attributes are returned as  the  file  type
              and mode of the specified file (cf. stat(2) and inode(7)). E.g.,

                  S_IRUSR  - owner has read permission
                  S_IWUSR  - owner has write permission
                  S_IXUSR  - owner has execute permission

                  S_IFSOCK - socket
                  S_IFLNK  - symbolic link
                  S_IFREG  - regular file
                  S_IFBLK  - block device
                  S_IFDIR  - directory
                  S_IFCHR  - character device
                  S_IFIFO  - FIFO

              its  second  element  ([1])  contains  the  entry’s  size in bytes. If P_NOCHECK was specified and
              ’entry’ doesn’t exists then a list having one element is returned containing -1.

       SYSTEM FUNCTIONS:

       o      void arghead(string str)
              support function of exec() (see also below at exec()): defines the `argument head’  that  is  used
              with exec(). By default, the `argument head’ is an empty string. The argument head is text that is
              prefixed to all exec arguments, like a directory in which provided arguments are found;

       o      void argtail (string str)
              support function of exec() (see also below at exec()): defines the `argument tail’  that  is  used
              with exec(). By default, the `argument tail’ is an empty string. The argument tail is text that is
              appended to all exec arguments, like the extensions of files that are passed as arguments to exec;

       o      cmdhead(string str)
              support function of exec() (see also below at exec()).  Defines a `command head’ that is used with
              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 arghead and argtail.  The cmdhead argument itself is  not
              modified by arghead or argtail;

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

       o      list eval(string str)
              this  function  can  be used instead of the backtick operator (cf. section OPERATORS). The example
              provided with the backtick operator could therefore also have been written like this:

                  printf << eval("ls");   // prints the elements in the current
                                          // directory

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

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

              The remaining arguments may be ints, strings or lists. Int and list arguments are cast to strings.
              Their string representations are then appended to cmd;

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

       o      exit(expression)
              Ends  the  execution  of  an icmake-script. The expression must evaluate to an int value, which is
              used as the script’s exit value;

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

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

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

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

       o      int putenv(string envvar)
              adds or modifies envvar to the current icmake-script environment. Use the format: "VAR=value". Use
              "VAR"  to  remove  "VAR"  from  the environment. The function returns 0 unless envvar is empty, in
              which case 1 is returned;

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

USER DEFINED FUNCTIONS

       In addition to main additional functions are usually defined. Once defined, they can be  called.  Forward
       referencing  of  either variables or functions is not supported, but calling functions recursively is. As
       function declarations are not supported indirect recursion cannot be used.

       User-defined functions must have the following elements:

       o      The function’s return type, which must be void, int, string or list. There is no default type;

       o      The function’s name, e.g., compile;

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

       o      A body surrounded by a pair of curly braces ({ and }).

       Function bodies may contain variable definitions (optionally initialized at their definitions).  Variable
       definitions  start  with  a type name, followed by one or more comma separated and optionally initialized
       variable identifiers.

       If a variable is not explicitly initialized it is initialized by default: int variables  are  initialized
       to  0, string variables are initialized to empty strings ("") and list variables are initialized to empty
       lists.

       Function bodies may also contain zero or more statements (cf. section FLOW CONTROL). Note that  variables
       may  be defined (and optionally initialized) anywhere inside functions where expression statements can be
       used, and also in the condition sections of if, for, and  while  statements  and  in  the  initialization
       sections of if andd for statements.

EXAMPLE

       In  the  following example all C++ source files in the current directory are compiled unless their object
       files are more recent. The main function creates a list of source files and then passes each of them to a
       function  inspect. That function inspects whether the source file is younger than its object file, and if
       so it calls compile. The function compile uses exec to call the compiler.  If  a  compilation  fails  the
       script  stops  so  the  error  can  be repaired. Source files for which the compilation succeeded are not
       recompiled when the script is rerun. Assuming the script is named compile.im then it can be called  using
       icmake  -s  compile.im.  This  also  creates  compile.bim,  so  after  the  -s call the command icmake -e
       compile.bim can be used to immediately execute the bim-file:

           void compile(string src)
           {
               exec("g++ -c " + src);      // compile ’src’
           }

           void inspect(string src)
           {                               // get the obj-file’s name:
                                           // only compile if necessary
               if (src younger change_ext(src, ".o"))
                   compile(src);
           }

           int main()
           {                               // find all .cc source files
               list sources = makelist("*.cc");

               for (                       // visit all source files
                   int idx = 0, end = listlen(sources);
                       idx != end;
                           ++idx
               )
                   inspect(sources[idx]);  // compile if needed
           }

SEE ALSO

       icmake(1), icmbuild(1), icmconf(7), icmstart(1), icmstart.rc(7)

BUGS

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

       Path names containing blanks are not supported.

COPYRIGHT

       This is free software, distributed under the terms of the GNU General Public License (GPL).

AUTHOR

       Frank B. Brokken (f.b.brokken@rug.nl).