Provided by: icmake_12.03.00-1ubuntu1_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 ends 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’. A command that could be executed  but  that
              did  not  produce any output returns a list containing one string element, which is
              empty.

              An empty list indicates that the command could not be executed.

              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

              As  mentioned  at  the  backtick  operator:  the  elements  of the list contain the
              subsequent lines of output (including a final  newline,  if  present)  produced  by
              `cmd’. A command that could be executed but that did not produce any output returns
              a list containing one string element, which is empty.

              An empty list indicates that the command could not be executed.

       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).