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