The node, file, and dir functions define location-independent references to files and directories.
In omake, the commands to build a target are executed in the target's directory. Since there may be
many directories in an omake project, the build system provides a way to construct a reference to a file
in one directory, and use it in another without explicitly modifying the file name. The functions have the following
syntax, where the name should refer to a file or directory.

For example, we can construct a reference to a file foo in the current directory.

FOO = $(file foo)
.SUBDIRS: bar

If the FOO variable is expanded in the bar subdirectory, it will expand to ../foo.

These commands are often used in the top-level OMakefile to provide location-independent references to
top-level directories, so that build commands may refer to these directories as if they were absolute.

ROOT = $(dir .)
LIB = $(dir lib)
BIN = $(dir bin)

Once these variables are defined, they can be used in build commands in subdirectories as follows, where
$(BIN) will expand to the location of the bin directory relative to the command being executed.

install: hello
cp hello $(BIN)

The node function is like the file function except that names of .PHONY
targets are more permissive. The file function requires an explicit qualifier,
the node function does not.

The in function is closely related to the dir and
file functions. It takes a directory and an expression, and
evaluates the expression in that effective directory.
For example, one common way to install a file is to define a symbol link, where the
value of the link is relative to the directory where the link is created.

The following commands create links in the $(LIB) directory.

FOO = $(file foo)
install:
ln -s $(in $(LIB), $(FOO)) $(LIB)/foo

Note that the in function only affects the expansion of Node
(File and Dir) values.

The homename function returns the name of a file in
tilde form, if possible. The unexpanded forms are computed
lazily: the homename function will usually evaluate to an absolute
pathname until the first tilde-expansion for the same directory.

The where function is similar to which, except it returns the list of
all the locations of the given executable (in the order in which the
corresponding directories appear in $PATH). In case a command is handled
internally by the Shell object, the first string in the output will
describe the command as a built-in function.

The digest and digest-optional functions compute MD5 digests
of files. The digest function raises an exception if a file
does no exist. The digest-optional returns false if a
file does no exist. MD5 digests are cached.

The find-in-path function searches for the files in a search
path. Only the tail of the filename is significant. The find-in-path
function raises an exception if the file can't be found.
The find-in-path-optional function silently removes
files that can't be found.

The digest-in-path function searches for the files in a search
path and returns the file and digest for each file. Only the tail of the
filename is significant. The digest-in-path function raises an exception
if the file can't be found. The digest-in-path-optional
function silently removes elements that can't be found.

The file-exists function checks whether the files listed exist.
The target-exists function is similar to the file-exists function.
However, it returns true if the file exists or if it can be built
by the current project. The target-is-proper returns true only
if the file can be generated in the current project.

The filter-exists, filter-targets, and filter-proper-targets
functions remove files from a list of files.

filter-exists: the result is the list of files that exist.

filter-targets: the result is the list of files either exist, or
can be built by the current project.

filter-proper-targets: the result is the list of files that can
be built in the current project.

Creating a “distclean” target

One way to create a simple “distclean” rule that removes generated files from
the project is by removing all files that can be built in the current
project.

CAUTION: you should be careful before you do this. The rule
removes any file that can potentially be reconstructed.
There is no check to make sure that the commands to rebuild the file
would actually succeed. Also, note that no file outside the
current project will be deleted.

.PHONY: distclean
distclean:
rm $(filter-proper-targets $(ls R, .))

If you use CVS, you may wish to utilize the cvs_realclean program that
is distributed with OMake in order to create a “distclean” rule that would
delete all the files thare are not known to CVS. For example, if you already have a more traditional
“clean” target defined in your project, and if you want the “distclean” rule to
be interactive by default, you can write the following:

The find-target-in-path function searches for targets in the
search path. For each file file in the file list, the path is
searched sequentially for a directory dir such that the target
dir/file exists. If so, the file dir/file is returned.

For example, suppose you are building a C project, and project
contains a subdirectory src/ containing only the files
fee.c and foo.c. The following expression
evaluates to the files src/fee.osrc/foo.o even
if the files have not already been built.

The find-ocaml-targets-in-path-optional function is very similar to the
find-targets-in-path-optional one, except an OCaml-style search
is used, where for every element of the search path and for every name being
searched for, first the uncapitalized version is tried and if it is not buildable,
then the capitalized version is tried next.

In the case, the sorter produces the result d b c a.
That is, a target is sorted after its dependencies.
The sorter is frequently used to sort files that are to be linked
by their dependencies (for languages where this matters).

There are three important restrictions to the sorter:

The sorter can be used only within a rule body.
The reason for this is that all dependencies
must be known before the sort is performed.

The sorter can only sort files that are buildable
in the current project.

It is possible to further constrain the sorter through the use of
sort rules. A sort rule is declared in two steps. The
target must be listed as an .ORDER target; and then
a set of sort rules must be given. A sort rule defines
a pattern constraint.

In this example, the .MYORDER sort rule specifies that any
file with a suffix .foo should be placed after any file with
suffix .bar, and any file with suffix .bar should be
placed after a file with suffix .baz.

OMake commands are “glob-expanded” before being executed. That is,
names may contain patterns that are expanded to sequences of
file and directory names. The syntax follows the standard bash(1), csh(1),
syntax, with the following rules.

A pathname is a sequence of directory and file names separated by
one of the / or \ characters. For example, the following pathnames
refer to the same file: /home/jyh/OMakefile and /home\jyh/OMakefile.

Glob-expansion is performed on the components of a path. If a path contains
occurrences of special characters (listed below), the path is viewed as a pattern
to be matched against the actual files in the system. The expansion produces a
sequence of all file/directory names that match.

For the following examples, suppose that a directory /dir contains files
named a, -a, a.b, and b.c.

*

Matches any sequence of zero-or-more characters. For example,
the pattern /dir/a* expands to /dir/a /dir/aa /dir/a.b.

Square brackets denote character sets and ranges
in the ASCII character set. The pattern may contain individual characters c
or character ranges c1-c2. The pattern matches any of the
individual characters specified, or any characters in the range. A leading “hat”
inverts the send of the pattern. To specify a pattern that contains the
literal characters -, the - should occur as the first character in
the range.

Pattern

Expansion

/dir/[a-b]*

/dir/a /dir/a.b /dir/b.c

/dir/[-a-b]*

/dir/a /dir/-a /dir/a.b /dir/b.c

/dir/[-a]*

/dir/a /dir/-a /dir/a.b

{s1,...,sN}

Braces indicate brace-expansion.
The braces delimit a sequence of strings separated by commas.
Given N strings, the result produces N copies of the pattern,
one for each of the strings si.

Pattern

Expansion

a{b,c,d}

ab ac ad

a{b{c,d},e}

abc abd ae

a{?{[A-Z],d},*}

a?[A-Z] a?d a*

The tilde is used to specify home directories.
Depending on your system, these might be possible expansions.

Pattern

Expansion

~jyh

/home/jyh

~bob/*.c

c:\Documents and Settings\users\bob

The \ character is both a pathname separator
and an escape character. If followed by a special glob character,
the \ changes the sense of the following character to non-special
status. Otherwise, \ is viewed as a pathname separator.

Pattern

Expansion

~jyh/\*

~jyh/* (* is literal)

/dir/\[a-z?

/dir/[a-z? ([ is literal, ? is a pattern).

c:\Program Files\[A-z]

c:\Program Files[A-z]*

Note that the final case might be considered to be ambiguous (where \ should
be viewed as a pathname separator, not as an escape for the subsequent [
character. If you want to avoid this ambiguity on Win32, you should use the
forward slash / even for Win32 pathnames (the / is translated
to \ in the output).

The rename function changes the name of a file or directory named old
to new.

The mv function is similar, but if new is a directory, and it exists,
then the files specified by the sequence are moved into the directory. If not,
the behavior of mv is identical to rename. The cp function
is similar, but the original file is not removed.

“Mount” the src directory on the dst directory. This is
a virtual mount, changing the behavior of the $(file ...) function.
When the $(file str) function is used, the resulting file is taken
relative to the src directory if the file exists. Otherwise, the
file is relative to the current directory.

The main purpose of the vmount function is to support multiple
builds with separate configurations or architectures.

Removed the directories from the set of directories that omake considers to be part
of the project. This is mainly used to cancel a .SUBDIRS from including
a directory if it is determined that the directory does not need to be compiled.

file1-effile2 : On Unix, file1 and file2 have the
same device and inode number.
On Win32, file1 and file2 have the
same name.

file1-ntfile2 : file1 is newer than file2

file1-otfile2 : file1 is older than file2

-bfile : The file is a block special file

-cfile : The file is a character special file

-dfile : The file is a directory

-efile : The file exists

-ffile : The file is a normal file

-gfile : The set-group-id bit is set on the file

-Gfile : The file's group is the current effective group

-hfile : The file is a symbolic link (also -L)

-kfile : The file's sticky bit is set

-Lfile : The file is a symbolic link (also -h)

-Ofile : The file's owner is the current effective user

-pfile : The file is a named pipe

-rfile : The file is readable

-sfile : The file is empty

-Sfile : The file is a socket

-ufile : The set-user-id bit is set on the file

-wfile : The file is writable

-xfile : The file is executable

A string is any sequence of characters; leading - characters are allowed.

An int is a string that can be interpreted as an integer. Unlike traditional
versions of the test program, the leading characters may specify an arity. The
prefix 0b means the numbers is in binary; the prefix 0o means
the number is in octal; the prefix 0x means the number is in hexadecimal.
An int can also be specified as -lstring, which evaluates to the length of
the string.

A file is a string that represents the name of a file.

The syntax mirrors that of the test(1) program. If you are on a Unix system, the man page
explains more. Here are some examples.

In the 4-argument form, the write function writes
bytes to the output channel channel from the buffer,
starting at position offset. Up to amount bytes
are written. The function returns the number of bytes that were
written.

The 3-argument form is similar, but the offset is 0.

In the 2-argument form, the offset is 0, and the amount
if the length of the buffer.

If an end-of-file condition is reached,
the function raises a RuntimeException exception.

The set-nonblock-mode function sets the nonblocking flag on the
given channel. When IO is performed on the channel, and the operation
cannot be completed immediately, the operations raises a RuntimeException.

The select function polls for possible IO on a set of channels.
The rfd are a sequence of channels for reading, wfd are a
sequence of channels for writing, and efd are a sequence of
channels to poll for error conditions. The timeout specifies
the maximum amount of time to wait for events.

On successful return, select returns a Select object,
which has the following fields:

The fgets function returns the next line from a file that has been
opened for reading with fopen. The function returns the empty string
if the end of file has been reached. The returned string is returned as
literal data. The line terminator is not removed.

The fprintv functions print to a file that has been previously opened with
fopen. The printv functions print to the standard output channel, and
the eprintv functions print to the standard error channel.

The scan function provides input processing in command-line form.
The function takes file/filename arguments. If called with no
arguments, the input is taken from stdin. If arguments are provided,
each specifies an InChannel, or the name of a file for input.
Output is always to stdout.

The scan function operates by reading the input one line at a time,
and processing it according to the following algorithm.

For each line,
the record is first split into fields, and
the fields are bound to the variables $1, $2, .... The variable
$0 is defined to be the entire line, and $* is an array
of all the field values. The $(NF) variable is defined to be the number
of fields.

Next, a case expression is selected. If string_i matches the token $1,
then body_i is evaluated. If the body ends in an export, the state
is passed to the next clause. Otherwise the value is discarded.

For example, here is an scan function that acts as a simple command processor.

Parse each line as an argument list, where arguments
may be quoted. For example, the following line has three words,
“ls”, “-l”, “Program Files”.

ls -l "Program Files"

O

Parse each line using white space as the separator, using the
usual OMake algorithm for string parsing. This is the default.

x

Once each line is split, reduce each word using the
hex representation. This is the usual hex representation used
in URL specifiers, so the string “Program Files” may be
alternately represented in the form ProgramProgram+Files.

Note, if you want to redirect the output to a file, the easiest way is to
redefine the stdout variable. The stdout variable is scoped the
same way as other variables, so this definition does not affect the meaning of
stdout outside the calc function.

The awk function provides input processing similar to awk(1),
but more limited. The input-files argument is a sequence of values,
each specifies an InChannel, or the name of a file for input.
If called with no options and no file arguments, the input is taken from stdin.
Output is always to stdout.

The variables RS and FS define record and field separators
as regular expressions.
The default value of RS is the regular expression \r|\n|\r\n.
The default value of FS is the regular expression [ \t]+.

The awk function operates by reading the input one record at a time,
and processing it according to the following algorithm.

For each line,
the record is first split into fields using the field separator FS, and
the fields are bound to the variables $1, $2, .... The variable
$0 is defined to be the entire line, and $* is an array
of all the field values. The $(NF) variable is defined to be the number
of fields.

Next, the cases are evaluated in order.
For each case, if the regular expression pattern_i matches the record $0,
then body_i is evaluated. If the body ends in an export, the state
is passed to the next clause. Otherwise the value is discarded. If the regular
expression contains \(r\) expression, those expression override the
fields $1, $2, ....

For example, here is an awk function to print the text between two
delimiters \begin{<name>} and \end{<name>}, where the <name>
must belong to a set passed as an argument to the filter function.

Note, if you want to redirect the output to a file, the easiest way is to
redefine the stdout variable. The stdout variable is scoped the
same way as other variables, so this definition does not affect the meaning of
stdout outside the filter function.

The fsubst function provides a sed(1)-like substitution
function. Similar to awk, if fsubst is called with no
arguments, the input is taken from stdin. If arguments are provided,
each specifies an InChannel, or the name of a file for input.

The RS variable defines a regular expression that determines a record separator,
The default value of RS is the regular expression \r|\n|\r\n.

The fsubst function reads the file one record at a time.

For each record, the cases are evaluated in order. Each case defines
a substitution from a substring matching the pattern to
replacement text defined by the body.

Currently, there is only one option: g.
If specified, each clause specifies a global replacement,
and all instances of the pattern define a substitution.
Otherwise, the substitution is applied only once.

Output can be redirected by redefining the stdout variable.

For example, the following program replaces all occurrences of
an expression word. with its capitalized form.

The lex function provides a simple lexical-style scanner
function. The input is a sequence of files or channels. The cases
specify regular expressions. Each time the input is read, the regular
expression that matches the longest prefix of the input is selected,
and the body is evaluated.

If two clauses both match the same input, the last one is selected
for execution. The default case matches the regular expression .;
you probably want to place it first in the pattern list.

If the body end with an export directive,
the state is passed to the next clause.

For example, the following program collects all occurrences of alphanumeric
words in an input file.

The lex-search function is like the lex function, but input that
does not match any of the regular expressions is skipped. If the clauses include
a default case, then the default matches any skipped text.

For example, the following program collects all occurrences of alphanumeric
words in an input file, skipping any other text.

The Lexer object defines a facility for lexical analysis, similar to the
lex(1) and flex(1) programs.

In omake, lexical analyzers can be constructed dynamically by extending
the Lexer class. A lexer definition consists of a set of directives specified
with method calls, and set of clauses specified as rules.

For example, consider the following lexer definition, which is intended
for lexical analysis of simple arithmetic expressions for a desktop
calculator.

This program defines an object lexer1 the extends the Lexer
object, which defines lexing environment.

The remainder of the definition consists of a set of clauses,
each with a method name before the colon; a regular expression
after the colon; and in this case, a body. The body is optional,
if it is not specified, the method with the given name should
already exist in the lexer definition.

NB The clause that matches the longest prefix of the input
is selected. If two clauses match the same input prefix, then the last
one is selected. This is unlike most standard lexers, but makes more sense
for extensible grammars.

The first clause matches any input that is not matched by the other clauses.
In this case, an error message is printed for any unknown character, and
the input is skipped. Note that this clause is selected only if no other
clause matches.

The second clause is responsible for ignoring white space.
If whitespace is found, it is ignored, and the lexer is called
recursively.

The third clause is responsible for the arithmetic operators.
It makes use of the Token object, which defines three
fields: a loc field that represents the source location;
a name; and a value.

The lexer defines the loc variable to be the location
of the current lexeme in each of the method bodies, so we can use
that value to create the tokens.

The Token.unit($(loc), name)
method constructs a new Token object with the given name,
and a default value.

The number clause matches nonnegative integer constants.
The Token.pair($(loc), name, value) constructs a token with the
given name and value.

Lexer object operate on InChannel objects.
The method lexer1.lex-channel(channel) reads the next
token from the channel argument.

During lexical analysis, clauses are selected by longest match.
That is, the clause that matches the longest sequence of input
characters is chosen for evaluation. If no clause matches, the
lexer raises a RuntimeException. If more than one clause
matches the same amount of input, the first one is chosen
for evaluation.

Clause bodies may also end with an export directive. In this case
the lexer object itself is used as the returned token. If used with
the Parser object below, the lexer should define the loc, name
and value fields in each export clause. Each time
the Parser calls the lexer, it calls it with the lexer returned
from the previous lex invocation.

Parsers are defined as extensions of the Parser class.
A Parser object must have a lexer field. The lexer
is not required to be a Lexer object, but it must provide
a lexer.lex() method that returns a token object with
name and value fields. For this example, we use the
lexer1 object that we defined previously.

The next step is to define precedences for the terminal symbols.
The precedences are defined with the left, right,
and nonassoc methods in order of increasing precedence.

The grammar must have at least one start symbol, declared with
the start method.

Next, the productions in the grammar are listed as rules.
The name of the production is listed before the colon, and
a sequence of variables is listed to the right of the colon.
The body is a semantic action to be evaluated when the production
is recognized as part of the input.

In this example, these are the productions for the arithmetic
expressions recognized by the desktop calculator. The semantic
action performs the calculation. The variables $1, $2, ...
correspond to the values associated with each of the variables
on the right-hand-side of the production.

The parser is called with the $(parser1.parse-channel start, channel)
or $(parser1.parse-file start, file) functions. The start
argument is the start symbol, and the channel or file
is the input to the parser.

The parser generator generates a pushdown automation based on LALR(1)
tables. As usual, if the grammar is ambiguous, this may generate shift/reduce
or reduce/reduce conflicts. These conflicts are printed to standard
output when the automaton is generated.

By default, the automaton is not constructed until the parser is
first used.

The build(debug) method forces the construction of the automaton.
While not required, it is wise to finish each complete parser with
a call to the build(debug) method. If the debug variable
is set, this also prints with parser table together with any conflicts.

The loc variable is defined within action bodies, and represents
the input range for all tokens on the right-hand-side of the production.

Next, we extend the parser to handle these new operators.
We intend that the bitwise operators have lower precedence
than the other arithmetic operators. The two-argument form
of the left method accomplishes this.

The getpwents function returns an array of Passwd objects, one for every user
fund in the system user database. Note that depending on the operating system and on the setup
of the user database, the returned array may be incomplete or even empty.

The tgetstr function looks up the terminal capability with the indicated id.
This assumes the terminfo to lookup is given in the TERM environment variable. This
function returns an empty value if the given terminal capability is not defined.

When the TERM environment variable indicates that the XTerm title setting capability is available,
$(xterm-escape s) is equivalent to $(xterm-escape-begin)s$(xterm-escape-end). Otherwise, it
returns an empty value.

The prompt-invisible will wrap its argument with $(prompt-invisible-begin) and
$(prompt-invisible-end). All the `invisible” sections of the shell prompt (such as various
escape sequences) must be wrapped this way.