Quake(7)                  MODULA-3 PROGRAMMERS MANUAL                 Quake(7)

NAME
       quake- The Quake extension language and interpreter

SYNOPSIS
       quake [options]

DESCRIPTION
       Quake  is  a  simple, specialized language and its interpreter draws on
       elements of the C language, the Bourne shell, and the C  pre-processor.
        The  cm3  compiler  includes a quake interpreter as its extension lan-
       guage. In fact, the  configuration  files,  cm3.cfg,  m3makefiles,  and
       m3overrides are quake scripts.

       Quake  was  designed to be a simple extension language for the Modula-3
       builder. Building a complete, general-purpose language was not  one  of
       the  goals.   The functionality of the builder (i.e., the quake engine)
       has been incorporated within the cm3 compiler itself, and is no  longer
       a separate executable.

       Cm3  calls  out to quake every time it needs to do something that needs
       to be specialized such  as  compiling  C  files  or  linking.   Consult
       cm3.cfg  in your installation (in the same directory as cm3 executable)
       for more information.

HISTORY
       During the history of Modula-3, there have also been several  different
       versions  and  implementations  of  quake. The first Modula-3 compilers
       didn't have any quake support at all.  Unix makefiles were generated by
       the m3make utility from m3makefiles.

       The  first  quake implementation was written in C and called as a stan-
       dalone executable. Later, in the PM3 and CM3 distributions,  quake  was
       reimplemented  in  Modula-3,  and  then  integrated  into  the  builder
       (m3build) and later the compiler frontend, which  led  to  considerable
       performance improvements of the Modula-3 compilation process.

       This  manual  cannot achieve to document all the different variants and
       versions of quake. If not otherwise stated, it  refers  to  the  latest
       version of quake as it is contained in CM3 5.6.0 and later.

LANGUAGE
   VALUES
       Quake  is  designed  to  make  it easy to assemble arrays and tables of
       strings. The value space is strings, arrays of strings, and  tables  of
       strings.  An  array  is  a  list  of  elements, and a table is a set of
       key/value pairs where the keys in a table are all distinct.

       Quake also has some limited support for integers and booleans (at least
       internally),  those  everything  is  converted on the fly to the needed
       type (which is almost always  string).   Denotations  for  boolean  and
       integer values as well as arithmetic operations are mostly missing.

   STRINGS
       A string is a sequence (delimited by ") of characters excluding newline
       and double quote. Several special characters may be quoted  (with    as
       follows:

           new-line    ignored
           \\          \
           \n          new-line
           \r          return
           \t          tab
           \b          backspace
           \f          formfeed
           \"          double quote

   ARRAYS
       An  array is constructed using [ and ]. [] is the empty array, ["a"] is
       an array of the single string "a".  Elements are separated by ,.   Thus
       ["a", "b"] is an array of two elements---the strings "a" and "b".

       Arrays  are  flattened  whenever  they are referenced.  This means that
       ["a", ["b", "c"]] is converted the the array  ["a",  "b",  "c"].   This
       means that an array can never be the element of another array.

       Arrays  are accessed by an integer index.  a[2] is the third element of
       the array a.  The index expression may also be a string which  will  be
       converted  to  an  integer.   The range of the index is checked at run-
       time.

   TABLES
       A table is constructed using { and }.  {} is the empty table.  Elements
       of  a  table are given as key/value pairs.  An empty value may be omit-
       ted.  {"a", "b"} is a table containing two keys---the strings  "a"  and
       "b".   {"p"  :  "q"} is the constructor for a table with the single key
       "p" whose value is the string "q".  Missing values are returned as  the
       empty string "".

       Tables  are accessed using expressions of the form s{"a"}.  This evalu-
       ates to the value of the key "a" in the table s.

   NAMES
       Names in quake start with an letter (a..z, A..Z) or an underscore  (_),
       followed  by  those  characters, digits (0..9), hyphens (-), or periods
       (.).

       If the lookup for a name fails (it is undefined in any of the enclosing
       scopes)  it  is  installed  in the current scope with an initial string
       value of the text of the name.

   COMMENTS
       C-style comments are supported (delimited by /*  and  */)  and  do  not
       nest.  Single-line comments are introduced with % and terminated with a
       new-line.

   CONDITIONALS
       A Boolean value is represented as a string. The empty string is  false,
       and any other string is true. If builtin quake functions return boolean
       values, they use "TRUE" for true and "" for false.

   EXPRESSIONS
       An expression is:

           string:                  "baz"
           name:                    foo
           environment variable:    $CPU_TYPE
           array selector:          array[5]
           array constructor:       ["a", "b"]
           table selector:          t{"a"}
           table constructor:       {"a" : "p", b}
           function call:           f(a, "b")
           parentheses:             a and (b or f(c))

       Operators are all left-associative, precedence is decreases from top to
       bottom in the following list.

           &           string catenation ("Hello, " & foo)
           contains    table inclusion (s contains "a")
           not         logical negation (not a)
           and         logical conjunction (c and not d)
           or          logical disjunction (a or b)

       A  note  on  string  catenation. Operands of & are converted to strings
       whenever required and possible.  Arrays and  tables  are  converted  to
       strings by catenating their elements (for tables, their keys) separated
       by a single spaces.  For example, the expression

           "a" & " " & ["b", "c"]

       evaluates to the string "a b c".

   STATEMENTS
       A statement is either an assignment, a procedure definition,  a  proce-
       dure invocation, a conditional statement, or a loop.

       There  is no explicit statement separator or terminator, which may seem
       quite unfamiliar to those used to C or  Algol-derived  languages.   The
       next statement just starts after the previous is finished without semi-
       colon or line-break.

       Assign an expression (the string "bar") to the variable foo with

           foo = "bar"

       If foo already exists, and is an array, then

           foo += "baz"

       extends the array to include a new final element; the string "baz".

   SCOPE
       Quake has a global name space, but local scopes are  always  introduced
       when a procedure is called, and a foreach loop is executed.

       Scopes  are  searched  from  innermost to outermost each time a name is
       looked up. The outermost scope is always the global scope.

       Assignments can be made local to the innermost scope by  prefixing  the
       assignment statement with the keyword local. For example,

           local foo = "bog"

       In  which case the values of any other instances of foo in other scopes
       are hidden.  The previous value of foo is restored once the local scope
       is released by exiting the procedure or foreach loop.

       To protect a name in the current scope, use

           readonly dec = "digital"

       If  local  or  readonly  are not used, all variables are located in the
       outermost (global) scope. Beware of side-effects!

   PROCEDURES
       Procedures may be defined in the global scope only.  Here is the  defi-
       nition  of  a procedure simple, taking two arguments bound to the local
       names prefix and suffix in the procedures local scope.

           proc simple(prefix, suffix) is
             q = prefix & "." & suffix
           end

       The string prefix & "." & suffix is assigned to the global variable  q.

       This procedure can then be invoked with

           simple("Hello", "m3")

       Procedures can return values, in which case they become functions.  For
       example,

           proc combine(prefix, suffix) is
             return prefix & "." & suffix
           end

       defines a function  combine  which  catenates  and  returns  the  three
       strings  prefix, ".", and suffix.  Now the function combine can be used
       in an expression, for example

           q = combine("Hello", "m3")

       assigns the string "Hello.m3" to q.

   CONDITIONAL STATEMENTS
       Values may be tested using the if statement. For example,

           if compiling
             message = "compiling"
           end

       If statements may have an else part, for example

           if not (ready or interested)
             return
           else
             message = "congratulations"
           end

       returns from the current procedure if the test succeeds, otherwise exe-
       cutes the assignment statement.

   LOOPS
       Foreach  statements  iterate over the string values in an array or in a
       table. For example,

           foreach file in [".login", ".profile", ".Xdefaults"]
             write("Copying " & file & " to " & backup_dir & "0)
             copy_file(file, backup_dir)
           end

       binds the name file to each of ".login", ".profile",  and  ".Xdefaults"
       in turn in a local scope. This example assumes that the procedures
        copy_file, and the variable backup_dir have already been defined.

       Here is a function squeeze to remove duplicates from an array

           proc squeeze(array) is
             local t = {}

             foreach i in array
               t{i} = ""
             end

             return [t]
           end

   KEYWORDS
       Here is a list of reserved words in quake:

           and  contains  else  end  foreach  if  in
           is  local  not  or  proc  readonly  return
       Quake  has a small collection of built-in procedures.  Built-ins cannot
       be redefined. The built-ins write, error, and exec are variadic.

       The list of built-ins was substantially extended in CM3 5.6 due to  the
       needs  of  enhanced  regression  testing  on different target platforms
       without further prerequisites.

   Input / Output
       write(...)
              Writes its arguments to the current output stream.   Unlike  the
              conversion  of  arrays  to  strings,  there  are no extra spaces
              inserted between arguments.

       error(...)
              Writes its arguments to the standard error stream and stop  run-
              ning quake with an error return value.

   Code Execution
       include(file)
              The  contents  of  file  is interpreted by quake in place of the
              call to include. This is analogous the #include directive in the
              C preprocessor.  Calls to include nest until you run out of file
              descriptors or something equally bad.

       exec(...)
              The arguments are catenated and passed to the  operating  system
              to be executed as a child process. The command may start - or @.
              These are stripped before the command is passed to  the  command
              interpreter.

              A  prefix of @ indicates that the default action of printing the
              command to the standard output stream before execution should be
              overridden.  A  prefix  character of - overrides quake's default
              action of aborting if it detects an error return code after exe-
              cuting the command.

       cm3_exec(...) compatibility, since CM3 d5.5.1

              Same  as  the  above, but imitating the old implementation which
              merged stdout and stderr streams.

       quake( code ) since CM3 d5.6.0
              Executes the quake code passed as a text.

       try_exec(...) --> int
              The arguments are catenated and passed to the  operating  system
              to be executed as a child process. The command may start - or @.
              These are stripped before the command is passed to  the  command
              interpreter.

              A  prefix of @ indicates that the default action of printing the
              command to the standard output stream before execution should be
              overridden. The exit code of the program is returned.

       try_cm3_exec(...) --> int compatibility, since CM3 d5.5.1
              Same  as  the  above, but imitating the old implementation which
              merged stdout and stderr streams.

       q_exec( cmd ) --> int since CM3 d5.6.0
              Executes the passed command or command list  which  may  contain
              the following input/output redirections:

                       < fn   : read stdin from file fn
                       > fn   : write stdout into file fn
                       1> fn  : write stdout into file fn
                       2> fn  : write stderr into file fn
                       &> fn  : write stdout and stderr into file fn
                       >> fn  : append stdout to file fn
                       1>> fn : append stdout to file fn
                       2>> fn : append stderr to file fn
                       &>> fn : append stdout and stderr to file fn

              cmd  is parsed and split into single commands at every ;, |, &&,
              and ||.  The concatenation  characters  have  the  usual  Bourne
              Shell meaning:

                       a ; b    execute a followed by b
                       a  | b    execute a and pipe its output to b's standard
              input
                       a && b   execute a, then b if a has succeeded (returned
              0)
                       a  ||  b    execute a, then b if a has failed (returned
              #0)

                  Token may be grouped by single or double quotes.

                  The exit code of the command list is returned.

       q_exec_put( cmd, text ) --> int since CM3 d5.6.0
              Executes the given single command and pipe text to its  standard
              input.  No other redirections are performed.

              The exit code of the command list is returned.

       q_exec_get( cmd ) --> [int, text] since CM3 d5.6.0
              Executes  the  given  single command and captures its stdout and
              stderr output in text.

              This functions returns an array with two elements: First is  the
              exit code of the command, second the captured output.

   File System Functions and Procedures
       cp_if(src,dest)
              If  the file src differs from the file dest, or dest is missing,
              copy src to dest.

       fs_touch( pn ) since CM3 d5.6.0
              Touches file pn, i.e. sets its access time to the current  time.
              If the files doesn't exist, it is created.

       fs_rmfile( pn ) since CM3 d5.6.0
              Removes file pn if it exists.

       fs_rmdir( pn ) since CM3 d5.6.0
              Removes directory pn if it exists and is empty.

       fs_rmrec( pn ) since CM3 d5.6.0
              Removes the complete directory hierarchy at pn.

       fs_mkdir( pn ) since CM3 d5.6.0
              Creates all non-existing elements of pathname pn as directories.

       fs_cp( pn, pn2 ) since CM3 d5.6.0
              Copies file pn to pn2.

       fs_putfile( pn, text ) since CM3 d5.6.0
              Replaces the contents of file pn with text. If  the  files  does
              not exist, it is created.

       stale(target, deps) --> bool
              target  is  interpreted  as a file name, as is deps (or the ele-
              ments of deps if it's an array). If the  files  target  or  deps
              cannot be found, or if (one of) deps is more recent than target,
              stale returns true, otherwise false.

       unlink_file(f) --> bool
              Deletes the file f. Returns "TRUE" in case of success, else  "".

       path() --> text
              Returns  the  directory  of  the  currently  executing file as a
              string.

       fs_exists( pn ) --> bool since CM3 d5.6.0
              Returns "TRUE" if pn exists as a file  system  object,  else  ""
              (false).

       fs_readable( pn ) --> bool since CM3 d5.6.0
              Returns "TRUE" if pn is readable, else "" (false).

       fs_writable( pn ) --> bool since CM3 d5.6.0
              Returns "TRUE" if pn is writable, else "" (false).

       fs_executable( pn ) --> bool since CM3 d5.6.0
              Returns  "TRUE"  if  pn  is considered to be executable, else ""
              (false).

       fs_isdir( pn ) --> bool since CM3 d5.6.0
              Returns "TRUE" if pn is a directory, else "" (false).

       fs_isfile( pn ) --> bool since CM3 d5.6.0
              Returns "TRUE" if pn is an ordinary file, else "" (false).

       fs_lsdirs( pn, baseonly ) --> text[] since CM3 d5.6.0
              Returns an array of all subdirectories of pn.  If baseonly is ""
              (false),  only  the  basenames  are returned, else pathnames are
              returned.

       fs_lsfiles( pn, baseonly ) --> text[] since CM3 d5.6.0
              Returns an array of all ordinary  files  in  directory  pn.   If
              baseonly  is  ""  (false), only the basenames are returned, else
              pathnames are returned.

       fs_contents( pn ) --> text since CM3 d5.6.0
              Returns the contents of file pn as a text.

   Pathname Functions
       pn_valid(pn) --> bool
              "TRUE" iff pn is a valid pathname.

       pn_absolute(pn) --> bool
              "TRUE" iff pn is an absolute pathname.

       pn_compose(text[]) --> text
              Builds a new pathname from text[]. The first element is the root
              (which may be empty), the rest are arcs of the pathname.

       pn_decompose(pn) --> text[]
              Decomposes pn into its root and arcs.

       pn_prefix(pn) --> text
              Strips the last arc from pn.

       pn_last(pn) --> text
              Returns the last arc of pn.

       pn_base(pn) --> text
              Strips the last extension from pn.

       pn_lastbase(pn) --> text
              Returns the last arc from pn without its extension.

       pn_lastext(pn) --> text
              Returns the extension of the last arc of pn.

       pn_join(pna, pnb) --> text
              Returns the concatenation of pna and pnb. pnb must be a relative
              pathname.

       pn_join2(pna, pnb, ext) --> text
              Returns the concatenation of pna and pnb and the extension  ext.
              pnb must be a relative pathname.

       pn_replace_text(pn) --> text
              Replaces the extension of the last arc of pn.

       pn_current() --> text
              Returns  a representation of the special arc denotating the cur-
              rent directory.

       pn_parent() --> text
              Returns a representation of the special arc denotating the  par-
              ent directory.

   Argument Lists
       arglist(pfx, array)

       This  function  may  be used to avoid the problems of limited space for
       argument lists in some command interpreters. Some commands (notably m3,
       the  Modula-3  driver  program) are prepared to accept arguments from a
       file. The syntax for this is -Ffile.

       Thus, arglist("-F",  really_huge_array)  returns  either  the  original
       array  if it's not really all that huge, or it creates a temporary file
       containing a list of the strings in the  array  (one  to  a  line)  and
       returns  the  string  "-Ftemp"  where temp is the name of the temporary
       file.

   Generic Predicates
       defined(foo) --> bool
              Returns true if foo is defined, otherwise returns false.  Remem-
              ber  that  the  Boolean values false and true are represented as
              empty and non-empty strings respectively. In this  example,  foo
              looks  like  a  name,  and  is  evaluated before begin passed to
              defined. So if you really  want  to  find  out  whether  foo  is
              defined, use defined("foo").

       empty(foo) --> bool
              Returns true if the string, array, or table is empty, false oth-
              erwise.

       equal(foo, bar) --> bool
              Returns true if the strings foo and bar are the equivalent.  For
              arrays  and  tables,  equal is treated as reference equality and
              not as structural equality as in Modula-3.

   Text Functions
       escape(s) --> text
              Returns the string s with backslash characters doubled.

       format(s, a...) --> text
              Returns the string s with each instance of %s replaced  by  suc-
              cessive  a  arguments.  The number of a arguments must match the
              number of %ss.

       normalize(p, q) --> text
              If the path p is a prefix of the path q, returns the  path  from
              directory p to file q. Otherwise, returns q.

       split( text, seps ) --> text[] since CM3 d5.6.0
              Splits  the text into an array at every occurence of a character
              in seps.

       sub( text, off, len ) --> text since CM3 d5.6.0
              Returns the subtext of text starting at position off  of  length
              len.

       skipl( text ) --> text since CM3 d5.6.0
              Removes all white space at the left of the text.

       skipr( text ) --> text since CM3 d5.6.0
              Removes all white space at the right of the text.

       BR "compress( text ) --> text" " since CM3 d5.6.0"
              Removes all white space at the start and end of text.

       squeeze( text ) --> text since CM3 d5.6.0
              Removes multiple empty lines within text.

       pos( text, sub ) --> int since CM3 d5.6.0
              Returns  the  position  of  sub  within text or -1 if sub is not
              found.

       tcontains( text, sub ) --> bool since CM3 d5.6.0
              Returns true if sub is contained in text.

       bool( text ) --> bool since CM3 d5.6.0
              Returns "TRUE" for "true", "TRUE", "T", "yes", "YES", "1",  oth-
              erwise "" (false).

       subst_chars( text, a, b ) --> text since CM3 d5.6.0
              Returns  text in which every character of a is replaced with the
              character at the same position of b. a and b must be of the same
              length.

       del_chars( text, a ) --> text since CM3 d5.6.0
              Returns  text  in  which every occurence of characters from a is
              removed.

       subst( text, a, b, n ) --> text since CM3 d5.6.0
              Returns text in which the subtext a is replaced by subtext b for
              at most n times.

       subst_env( text ) --> text since CM3 d5.6.0
              Returns text in which all environment variables with the denota-
              tion
               ${name} or $name are replaced by the values of the current pro-
              cess execution environment.

       add_prefix( text[], pre ) --> text[] since CM3 d5.6.0
              Returns  an  array  of  text where each element is prefixed with
              pre.

       add_suffix( text[], suf ) --> text[] since CM3 d5.6.0
              Returns an array of text where each  element  is  suffixed  with
              suf.

   Directory (Stack) Functions and Procedures
       pushd( dir ) since CM3 d5.6.0
              Pushes  the  current  directory  onto  the stack and changes the
              working directory of the quake process to dir.

       popd() since CM3 d5.6.0
              Pops the topmost directory from the directory stack and makes it
              the working directory of the quake process.

       cd( dir ) since CM3 d5.6.0
              Changes the current directory of the quake process to dir.

       getwd() --> text since CM3 d5.6.0
              Returns the current working directory of the quake process.

   System Information
       hostname() --> text since CM3 d5.6.0
              Returns the hostname of the computer quake is running on.

       date() --> text since CM3 d5.6.0
              Returns the current date in ISO format: YYYY-MM-DD.

       datetime() --> text since CM3 d5.6.0
              Returns  the  current  date  and  time in ISO format: YYYY-MM-DD
              hh:mm:ss.

       datestamp() --> text since CM3 d5.6.0
              Returns the current date and time in this format: YYYY-MM-DD-hh-
              mm-ss.
       Sorry about the syntax for this. Suggestions (YACC permitting) welcome.

       Output (from the write built-in procedure)  may  be  temporarily  redi-
       rected as follows:

           > "foo.txt" in
             write("Hello, world0)
           end

       The output of the calls to write is written to the file foo.txt.

       Output may be appended to a file by using >> in place of >.

       The special file names _stdout and _stderr are special and are bound to
       the file descriptors corresponding to normal and error terminal  output
       respectively.

       The default for output is the normal terminal stream.
       Older  versions  of  quake  were used as standalone executables and run
       like this:

           quake [definitions|files ...]

       Each file argument is executed as it is encountered.

       Since the integration of quake into the builder and compiler  frontend,
       this is no more available (though it can be easily re-added it needed).

       Quake is now run implicitly by invoking the compiler with

           cm3 -build | -clean

       Usually, the file src/m3makefile is executed. If  -override  or  -x  is
       specified, the definitions from src/m3overrides are executed before.

       A definition has the form -Dvar or -Dvar=string. The first form defines
       var in the global scope of the program, the  second  form  gives  it  a
       value.

       The  quake interpreter is built into the CM3 Modula-3 compiler, whereas
       it was a separate executable for earlier ones, such as PM3.
       The Critical Mass Modula-3 compiler  cm3(1),  and  the  man  pages  for
       m3makefile(7), and m3override(7) files.

AUTHOR
       (man page) Peter Eiserloh (eiserlohpp -at- yahoo.com)
       (original author) Stephen Harrison.