icmscript - The C-like icmake scripting language
Contents
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).
Data Types
Icmake supports the following five data and value types:
o ASCIIcharacterconstants
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 or single 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 or single 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 the function 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 which do not return values. Alternatively, functions
may return int,string or list values (cf. section USERDEFINEDFUNCTIONS).
Variables can be defined at the global level and 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.
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 DATATYPES
- 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 PREPROCESSORDIRECTIVES
- supported preprocessor directives, like #include and #define;
o PREDEFINEDCONSTANTS
- like O_FILE,OFF, and S_IFREG;
o OPERATORS
- like +,younger, and casts
o FLOWCONTROL
- if,for,while, etc. (the switch is not available);
o PREDEFINEDFUNCTIONS
- executing programs, changing directories, operations on string and list type variables, etc..
Functions are marked as INTFUNCTIONS, LISTFUNCTIONS, STRINGFUNCTIONS
o USERDEFINEDFUNCTIONS
- at least main, with or without its common parameters argc,argv, and envp.
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.
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
}
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 insertionoperators) are
written to the standard output stream (when using printf<<), or to the file whose name is
provided in the stringfilename (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)statement1elsestatement2
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 returnexpression;
Plain return statements can be used in void functions, and returnexpression statements are used
in other type of functions.
o breakbreak; statements can only be used in for and while statements, ending those statements;
o continuecontinue; statements can only be used in for and while statements, continuing their next
iteration.
Name
icmscript - The C-like icmake scripting language
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 stringslhs 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 "helloworld":
"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 stringlhs is empty, otherwise 0 is returned.
Strings merely containing white-space characters are not empty;
o lhsyoungerrhs,lhsnewerrhs: 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 function exists() (see below, section PREDEFINEDFUNCTIONS) can be used to test whether a file
exists;
o lhsolderrhs: 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 (as lhs[3] is an rvalue):
lhs[3] = "a";
If an invalid (out of bounds) index value is specified an empty string is returned.
o The backtick operator (`stringcmd`)
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
Note that the backtick operator requires a string argument: either a string constant or a string
variable.
The function eval(stringcmd) 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 listslhs 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 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 listlhs 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 (as lst[3] is an rvalue):
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 (listlst=(list)"hello"): this returns a list having one element (hello) (note
that casting a string to a list as shown is overkill as listlst=["hello"] performs the same
initialization).
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 voidmain 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 intmain functions end using return
statements then those statements must be provided with int-expressions. Itβs OK when the execution of an
intmain function reaches its bodyβs closing curly, in 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 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. Following this the function main is called. The script ends
when main returns or when the function exit is called by the script.
Predefined Constants
The following predefined int constants are available (the functions listed in the intendedfor 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
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
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 INTFUNCTIONS below):
these functions receive int arguments, processing those arguments;
o Functions operating on strings (see STRINGFUNCTIONS below):
these functions operate on the strings which are passed to these functions as arguments;
o Functions operating on lists (see LISTFUNCTIONS below):
these functions operate on the lists which are passed to these functions as arguments;
o Functions manipulating file system entries (see FILESYSTEMFUNCTIONS 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 STRINGFUNCTIONS 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 STRINGFUNCTIONS section;
o System-related functions (see SYSTEMFUNCTIONS 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.
INTFUNCTIONS:
o stringascii(intvalue)
returns value as a string: ascii(65) returns the string "A";
o echo(intopt)
controls echoing of called programs (and their arguments), specify OFF if echoing is not
requested. By default echo(ON) is active.
STRINGFUNCTIONS:
o intascii(stringstr)
returns the first character of str as an in: ascii("A") returns 65;
o stringchange_base(stringfile,stringbase)
returns file whose base name is changed into base: change_base("/path/demo.im","out") returns
"/path/out.im";
o stringchange_ext(stringfile,stringext)
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 stringchange_path(stringfile,stringpath)
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 stringelement(intindex,stringvar)
acts identically to the index operator: refer to the index ([]) operator in section OPERATORS;
o stringget_base(stringfile)
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 stringget_dext(stringfile)
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 stringget_ext(stringfile)
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 stringget_path(stringfile)
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 stringresize(stringstr,intnewlength) 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 intstrchr(stringstr,stringchars)
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 intstrfind(stringhaystack,stringneedle)
returns index in haystack where needle is found, or -1 if needle is not found in haystack;
o stringstrformat(stringformat,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 intstrlen(stringstr)
returns the number of characters in str (not counting the terminating NUL-character);
o stringstrlwr(stringstr)
returns a lower-case duplicate of str;
o liststrtok(stringstr,stringseparators)
returns a list containing all substrings of str separated by one or more (consecutive) characters
in separators: strtok("helloicmakeβs+world","+") returns a list containing the three strings
"hello", "icmakeβs", and "world";
o stringstrupr(stringstr)
returns an upper-case duplicate of str.
o stringsubstr(stringtext,intoffset,intcount)
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 stringtrim(stringstr)
returns a copy of str without leading and trailing white spaces;
o stringtrimleft(stringstr)
returns a copy of str without leading white spaces;
o stringtrimright(stringstr)
Returns a copy of str without trailing white spaces.
LISTFUNCTIONS:
o stringelement(intindex,listvar)
acts identically to the index operator: refer to the index ([]) operator in section OPERATORS;
o intlistfind(listlst,stringstr)
returns the smallest index in lst where the string str is found, or -1 if lst does not contain
str;
o intlistlen(listl)
returns the number of elements in list;
o listlistunion(listlhs,listrhs)
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 listlistunion(listlst,stringstr)
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.
FILESYSTEMFUNCTIONS:
o stringchdir([intcheck,]stringdir)
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 intexists(stringfile)
if file exists, 1 is returned, otherwise 0 is returned;
o listfgets(stringfile,listoffset)
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 listret in whileβs condition, as this will reset ret to an empty list at
each iteration;
o intfprintf(stringfilename,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 FLOWCONTROL) statement 2 would normally be encountered, although statement 3, using the
format string, would still be accepted;
o stringgetch()
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 stringgets()
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 listmakelist([inttype=O_FILE],stringmask)
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 listmakelist([inttype=O_FILE,]stringmask,{newer,older,younger},stringcomparefile)
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 intprintf(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 FLOWCONTROL 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 STRINGFUNCTIONS section for additional information about format strings). Like fprintfprintf returns
the number of printed arguments;
o liststat([intcheck,]stringentry)
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.
SYSTEMFUNCTIONS:
o voidarghead(stringstr)
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 voidargtail(stringstr)
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(stringstr)
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(stringstr)
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 listeval(stringstr)
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 intexec([intcheck,]stringcmd,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_NOCHECKexec 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 intexecute([intchecking,]stringcmd,stringcmdhead,stringarghead,argument(s),stringargtail,stringcmdtail)
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 listgetenv(stringenvvar)
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 intgetpid()
returns the process-id of the icmake byte code interpreter icm-exec;
o intputenv(stringenvvar)
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 intsystem([intcheck,]stringcommand)
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_NOCHECKicmakeβ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.
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
(usually 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) icmake script βicmβ (without extension) contains
#!/usr/bin/icmake -t.
then icm can be issued as a command, interpreting the remaining lines of the script as an icmake
source which is compiled and then executed by icmake. The icmake(1) man-pageβs section EXECUTINGICMAKESCRIPTS covers the elements of the first line of icmake scripts.
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 #defineidentifier[definition]
The text identifier is replaced by definition. The definition may contain references to already
defined identifiers, using the syntax ${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 themselves may not span multiple lines. Multiple blanks (outside of
double quoted strings) in definitions are contracted to a single space character;
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 #ifdefidentifier
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 code block is ignored;
o #ifndefidentifier
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 code block is ignored;
o #else
Terminates #ifdef and #ifndef code blocks, reversing the acceptance decision about the following
code block. Only one #else directive can be associated with #if(n)def directives;
o #endif
Terminates the code block starting beyond the matching #ifdef, #ifndef or #else directive.
Associated #if(n)def,#else, and #endif directives must be specified in the same file;
o #undefidentifier
Remove identifier from the set of defined symbols. This does not affect the specification of any
previously defined symbols using identifierβs definition. If identifier hasnβt been defined a
warning is issued.
See Also
icmake(1), icmbuild(1), icmconf(7), icmstart(1), icmstart.rc(7)
User Defined Functions
In addition to main additional functions can be 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.
Function overloading (based on differently typed parameters) is supported.
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.,
(stringoutfile,stringsource);
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 FLOWCONTROL). 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.
