diff --git a/historic/jam/src/Build.com b/historic/jam/src/Build.com
new file mode 100755
index 000000000..9ad1ec28c
--- /dev/null
+++ b/historic/jam/src/Build.com
@@ -0,0 +1,30 @@
+! Bootstrap build script for Jam
+$ cc command.c
+$ cc compile.c
+$ cc expand.c
+$ cc execvms.c
+$ cc filevms.c
+$ cc glob.c
+$ cc hash.c
+$ cc headers.c
+$ cc jambase.c
+$ cc lists.c
+$ cc make.c
+$ cc make1.c
+$ cc newstr.c
+$ cc option.c
+$ cc parse.c
+$ cc pathvms.c
+$ cc regexp.c
+$ cc rules.c
+$ cc scan.c
+$ cc search.c
+$ cc timestamp.c
+$ cc variable.c
+$ cc jam.c
+$ cc jamgram.c
+$ link/exe=jam.exe command.obj, compile.obj, execvms.obj, expand.obj, -
+ filevms.obj, glob.obj, hash.obj, headers.obj, lists.obj, make.obj, -
+ make1.obj, newstr.obj, option.obj, parse.obj, pathvms.obj, regexp.obj, -
+ rules.obj, scan.obj, search.obj, timestamp.obj, variable.obj, jam.obj, -
+ jamgram.obj, jambase.obj
diff --git a/historic/jam/src/Build.mpw b/historic/jam/src/Build.mpw
new file mode 100644
index 000000000..661bd8624
--- /dev/null
+++ b/historic/jam/src/Build.mpw
@@ -0,0 +1,47 @@
+# This line must be set manually to the CodeWarrior Pro 5 installation.
+# Good luck!
+
+set CW "malyn_apps:CodeWarrior Pro 5:MetroWerks CodeWarrior"
+
+set -e MWCincludes "{CW}:MacOS Support:Universal:Interfaces:CIncludes,{CW}:MacOS Support:OpenTransport:Open Tpt Client Developer:Includes:CIncludes,{CW}:MacOS Support:Headers:Apple MPW,{CW}:MSL:MSL_C:MSL_Common:Include,{CW}:MSL:MSL_C++:MSL_Common:Include,{CW}:MSL:MSL_C:MSL_MacOS:Include"
+
+mwcppc -o :bin.mac:command.o -nomapcr -w off command.c
+mwcppc -o :bin.mac:compile.o -nomapcr -w off compile.c
+mwcppc -o :bin.mac:execmac.o -nomapcr -w off execmac.c
+mwcppc -o :bin.mac:filemac.o -nomapcr -w off filemac.c
+mwcppc -o :bin.mac:pathmac.o -nomapcr -w off pathmac.c
+mwcppc -o :bin.mac:jamgram.o -nomapcr -w off jamgram.c
+mwcppc -o :bin.mac:expand.o -nomapcr -w off expand.c
+mwcppc -o :bin.mac:glob.o -nomapcr -w off glob.c
+mwcppc -o :bin.mac:hash.o -nomapcr -w off hash.c
+mwcppc -o :bin.mac:headers.o -nomapcr -w off headers.c
+mwcppc -o :bin.mac:lists.o -nomapcr -w off lists.c
+mwcppc -o :bin.mac:make.o -nomapcr -w off make.c
+mwcppc -o :bin.mac:make1.o -nomapcr -w off make1.c
+mwcppc -o :bin.mac:newstr.o -nomapcr -w off newstr.c
+mwcppc -o :bin.mac:option.o -nomapcr -w off option.c
+mwcppc -o :bin.mac:parse.o -nomapcr -w off parse.c
+mwcppc -o :bin.mac:regexp.o -nomapcr -w off regexp.c
+mwcppc -o :bin.mac:rules.o -nomapcr -w off rules.c
+mwcppc -o :bin.mac:scan.o -nomapcr -w off scan.c
+mwcppc -o :bin.mac:search.o -nomapcr -w off search.c
+mwcppc -o :bin.mac:timestamp.o -nomapcr -w off timestamp.c
+mwcppc -o :bin.mac:variable.o -nomapcr -w off variable.c
+
+mwlinkppc -library -o :bin.mac:libjam.lib :bin.mac:command.o :bin.mac:compile.o :bin.mac:execmac.o :bin.mac:filemac.o :bin.mac:pathmac.o :bin.mac:jamgram.o :bin.mac:expand.o :bin.mac:glob.o :bin.mac:hash.o :bin.mac:headers.o :bin.mac:lists.o :bin.mac:make.o :bin.mac:make1.o :bin.mac:newstr.o :bin.mac:option.o :bin.mac:parse.o :bin.mac:regexp.o :bin.mac:rules.o :bin.mac:scan.o :bin.mac:search.o :bin.mac:timestamp.o :bin.mac:variable.o
+mwcppc -o :bin.mac:mkjambase.o -nomapcr -w off mkjambase.c
+
+mwlinkppc -o :bin.mac:mkjambase -mpwtool -warn :bin.mac:mkjambase.o "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Interfacelib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:ThreadsLib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Mathlib" "{CW}:MacOS Support:Libraries:Apple MPW PPC:PPCToolLibs.o" "{CW}:MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib" "{CW}:MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib"
+mwcppc -o :bin.mac:jam.o -nomapcr -w off jam.c
+
+:bin.mac:mkjambase jambase.c Jambase
+
+mwcppc -o :bin.mac:jambase.o -nomapcr -w off jambase.c
+
+mwlinkppc -o :bin.mac:jam -mpwtool -warn :bin.mac:jam.o :bin.mac:jambase.o :bin.mac:libjam.lib "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Interfacelib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:ThreadsLib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Mathlib" "{CW}:MacOS Support:Libraries:Apple MPW PPC:PPCToolLibs.o" "{CW}:MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib" "{CW}:MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib"
+
+
+
+
+
+
diff --git a/historic/jam/src/INSTALL b/historic/jam/src/INSTALL
new file mode 100644
index 000000000..8ec9f4e86
--- /dev/null
+++ b/historic/jam/src/INSTALL
@@ -0,0 +1,120 @@
+I. Compiling FT Jam:
+--------------------
+
+ 1. With a previous version of Jam:
+ ----------------------------------
+
+ The easiest way to compile Jam is to use a previous version of the
+ program. If you already have one installed on your system, simply
+ type "jam" in this directory.
+
+ This will create a new executable named "jam" or "jam.exe", located
+ in a new system-dependent directory, whose name can be:
+
+ bin.ntx86\jam.exe
+ bin.linux86\jam
+ etc..
+
+
+ 2. Without jam:
+ ---------------
+
+ If you don't have a jam binary installed, you can still compile the
+ program using one of these methods:
+
+ - on Unix systems, simply type "make" to use the "Makefile" provided
+ in this directory. This should work flawlessly
+
+ - on other systems, you can also modify the content of "Makefile"
+ to adapt it to your OS. Simply uncomment the lines specific to
+ your system, and invoke your make tool
+
+
+ Note that the Makefile is used to build a boot-strap version of jam,
+ called "jam0". Once it is built, the "jam0" executable is called to
+ re-build itself.
+
+ If this second pass doesn't work, this is probably because you didn't
+ set some environment variable that indicates which compiler to use to
+ Jam. Read the Jam documentation for more information on this..
+
+
+
+ 3. With toolset-specific makefiles:
+ -----------------------------------
+
+ You can also use one of the Makefiles located in the "builds"
+ directory. Here's what you need to type on the command line,
+ depending on your system and compiler:
+
+
+ a. Windows + Visual C++:
+
+ set VISUALC=/install/path/to/visual/compiler
+ set JAM_TOOLSET=VISUALC
+ nmake -f builds\win32-visualc.mk
+
+
+ b. Windows + Borland C++: (be sure to use the Borland "make" tool)
+
+ set BORLANDC=/install/path/to/borland/compiler
+ set JAM_TOOLSET=BORLANDC
+ make -fbuilds\win32-visualc.mk
+
+
+ c. Windows + Mingw (gcc):
+
+ set BORLANDC=/install/path/to/borland/compiler
+ set JAM_TOOLSET=BORLANDC
+ make -f builds\win32-visualc.mk
+
+
+ WE DO NOT PROVIDE PROJECT FILES FOR ANY SPECIFIC COMPILER/TOOLSET
+
+
+
+
+II. Installation:
+-----------------
+
+ For now, we do not provide any sophisticated
+ installation pass. Simply copy the new jam executable
+ to any directory in your current path.. and start
+ using it !!
+
+
+III. Default files:
+-------------------
+
+ All default files for Jam are compiled within the
+ executable itself.
+
+ There are no special configuration directory to
+ place global or user preferences. Until further
+ notice, all defaults can only be changed by using
+ command line switches and setting environment
+ variables..
+
+
+IV. Windows and OS/2 Binary packages:
+-------------------------------------
+
+ It's possible to create zip files of the binaries
+ on Windows and OS/2 system by following these simple
+ steps (you need to have the "zip" utility in your
+ path !!):
+
+ 1. build jam
+ 2. strip the jam.exe executable in bin.ntx86 when
+ possible
+ 3. call "jam package"
+
+ you should see a file named "ftjam-xxxxx-win32.zip"
+ or "ftjam-xxxxx-os2.zip" in the current directory,
+ as well as "ftjam-xxxxx.zip" (containing the sources)
+
+
+Good luck,
+
+
+- David Turner, 28 Jul 2001
diff --git a/historic/jam/src/Jam.html b/historic/jam/src/Jam.html
new file mode 100644
index 000000000..5d612ecba
--- /dev/null
+++ b/historic/jam/src/Jam.html
@@ -0,0 +1,1201 @@
+
+
+
Jam/MR - Make(1) Redux
+
+
+
+
+
+ Jam/MR - Make(1) Redux
+
+ The Jam/MR Executable
+
+
+
+
+
+-
USAGE
-
+
+
+jam [ -a ] [ -n ] [ -v ]
+ [ -d debug ]
+ [ -f jambase ]
+ [ -j jobs ]
+ [ -o actionsfile ]
+ [ -s var=value ]
+ [ -t target ]
+ [ target ... ]
+
+
+ -
DESCRIPTION
-
+
+
+
+ Jam is a program construction tool, like make(1).
+
+
+
+ Jam recursively builds target files from source files,
+ using dependency information and updating actions expressed in
+ the Jambase file, which is written in jam's own interpreted
+ language. The default Jambase is compiled into jam and
+ provides a boilerplate for common use, relying on a user-provide
+ file "Jamfile" to enumerate actual targets and sources.
+
+
+
+ The Jambase is described in the Jambase
+ Reference and the document Using
+ Jamfiles and Jambase.
+
+
-
OPTIONS
-
+
+
+
+ If target is provided on the command line, jam
+ builds target; otherwise jam builds the target
+ 'all'.
+
+
+
+ Jam may be invoked with the following options:
+
+
+
+ -a
+ | Build all targets anyway, even if they are up-to-date.
+
+ |
-d n
+ | Enable cummulative debugging levels from 1 to n.
+ Interesting values are:
+
+
+ - 1
- Show actions (the default)
+
- 2
- Show "quiet" actions and display all action text
+
- 3
- Show dependency analysis, and target/source
+ timestamps/paths
+
- 4
- Show shell arguments
+
- 5
- Show rule invocations and variable expansions
+
- 6
- Show directory/header file/archive scans
+
- 7
- Show variable settings
+
- 8
- Show variable fetches
+
- 9
- Show variable manipulation, scanner tokens
+
+
+ |
-d +n
+ | Enable debugging level n.
+
+ |
-d 0
+ | Turn off all debugging levels. Only errors are not suppressed.
+
+ |
-f jambase
+ | Read jambase instead of using the built-in Jambase.
+ Only one -f flag is permitted, but the jambase may
+ explicitly include other files.
+
+ |
-j n
+ | Run up to n shell commands concurrently (UNIX
+ and NT only). The default is 1.
+
+ |
-n
+ | Don't actually execute the updating actions, but do
+ everything else. This changes the debug level default to -d2.
+
+ |
-o file
+ | Write the updating actions to the specified file instead
+ of running them (or outputting them, as on the Mac).
+
+ |
-s var=value
+ | Set the variable var to value, overriding
+ both internal variables and variables imported from the
+ environment.
+
+ |
-t target
+ | Rebuild target and everything that depends on it,
+ even if it is up-to-date.
+
+ |
-v
+ | Print the version of jam and exit.
+
+ |
+
+ -
OPERATION
-
+
+
+
+ Jam has four phases of operation: start-up, parsing,
+ binding, and updating.
+
+
-
Start-up
-
+
+
+
+ Upon start-up, jam imports environment variable settings
+ into jam variables. Environment variables are split at
+ blanks with each word becoming an element in the variable's list
+ of values. Environment variables whose names end in PATH are
+ split at $(SPLITPATH) characters (e.g., ":" for Unix).
+
+
+
+ To set a variable's value on the command line, overriding the
+ variable's environment value, use the -s option. To see variable
+ assignments made during jam's execution, use the -d+7
+ option.
+
+
-
Parsing
-
+
+
+
+ In the parsing phase, jam reads and parses the Jambase
+ file, by default the built-in one. It is written in the jam
+ language. See Language below. The
+ last action of the Jambase is to read (via the "include" rule)
+ a user-provided file called "Jamfile".
+
+
+
+ Collectively, the purpose of the Jambase and the Jamfile is to
+ name built target and source files, construct the dependency
+ graph among them, and associate build actions with targets.
+ The Jambase defines boilerplate rules and variable assignments,
+ and the Jamfile uses these to specify the actual relationship
+ among the target and source files. See the Jambase Reference and the document Using Jamfiles and Jambase for information.
+
+
+-
Binding
-
+
+
+
+
+
Binding
+
+ After parsing, jam recursively descends the dependency
+ graph and binds every file target with a location in the
+ filesystem. If jam detects a circular dependency in the
+ graph, it issues a warning.
+
+
+
+ File target names are given as absolute or relative path names
+ in the filesystem. If the path name is absolute, it is bound
+ as is. If the path name is relative, it is normally bound as
+ is, and thus relative to the current directory. This can be
+ modified by the settings of the $(SEARCH) and $(LOCATE) variables,
+ which enable jam to find and build targets spread across
+ a directory tree. See SEARCH and LOCATE
+ Variables below.
+
+
Update Determination
+
+ After binding each target, jam determines whether the
+ target needs updating, and if so marks the target for the updating
+ phase. A target is normally so marked if it is missing, it is
+ older than any of its sources, or any of its sources are marked
+ for updating. This behavior can be modified by the application
+ of special built-in rules, ALWAYS, LEAVES, NOCARE, NOTFILE,
+ NOUPDATE, and TEMPORARY. See Modifying
+ Binding below.
+
+
Header File Scanning
+
+
+
+ During the binding phase, jam also performs header file
+ scanning, where it looks inside source files for the implicit
+ dependencies on other files caused by C's #include syntax. This
+ is controlled by the special variables $(HDRSCAN) and $(HDRRULE).
+ The result of the scan is formed into a rule invocation, with
+ the scanned file as the target and the found included file names
+ as the sources. Note that this is the only case where rules
+ are invoked outside the parsing phase. See HDRSCAN and HDRRULE Variables below.
+
+
-
Updating
-
+
+
+
+ After binding, jam again recursively descends the dependency
+ graph, this time executing the update actions for each target
+ marked for update during the binding phase. If a target's
+ updating actions fail, then all other targets which depend on
+ that target are skipped.
+
+
+
+ The -j flag instructs jam to build more than one target
+ at a time. If there are multiple actions on a single target,
+ they are run sequentially.
+
+
+-
LANGUAGE
-
+
+
+
-
Overview
-
+
+ Jam has an interpreted, procedural language. Statements
+ in jam are rule (procedure) definitions, rule invocations,
+ flow-of-control structures, variable assignments, and sundry
+ language support.
+
+
-
Lexical Features
-
+
+
+
+ Jam treats its input files as whitespace-separated tokens,
+ with two exceptions: double quotes (") can enclose whitespace
+ to embed it into a token, and everything between the matching
+ curly braces ({}) in the definition of a rule action is treated
+ as a single string. A backslash (\) can escape a double quote.
+
+
+
+ Jam requires whitespace (blanks, tabs, or newlines) to
+ surround all tokens, including the colon (:) and semicolon
+ (;) tokens.
+
+
+
+ Jam keywords (an mentioned in this document) are reserved
+ and generally must be quoted with double quotes (") to be used
+ as arbitrary tokens, such as variable or target names.
+
+
-
Targets
-
+
+
+
+ The essential jam data entity is a target. Built targets
+ are files to be updated. Source targets are the files used in
+ updating built targets. Built targets and source targets are
+ collectively referred to as file targets, and frequently built
+ targets are source targets for other built targets. Pseudotargets
+ are symbols which represent dependencies on other targets, but
+ which are not themselves associated with any real file.
+
+
+
+ A file target's identifier is generally the file's name, which
+ can be absolutely rooted, relative to the directory of jam's
+ invocation, or simply local (no directory). Most often it is
+ the last case, and the actual file path is bound using the
+ $(SEARCH) and $(LOCATE) special variables. See
+ SEARCH and LOCATE Variables below. A local filename is
+ optionally qualified with grist, a string value used to assure
+ uniqueness. A file target with an identifier of the form
+ file(member) is a library member (usually an ar(1) archive
+ on UNIX).
+
+
-
Rules
-
+
+
+
+ The basic jam language entity is called a rule. A rule
+ is defined in two parts: the procedure and the actions. The
+ procedure is a body of jam statements to be run when the
+ rule is invoked; the actions are the OS shell commands to execute
+ when updating the built targets of the rule.
+
+
+
+ The jam statements for defining and invoking rules are
+ as follows:
+
+
+
+ -
+ rule rulename { statements }
+
+
+ - Define a rule's procedure, replacing any previous
+ definition.
+
+
-
+ actions [ modifiers ] rulename { commands }
+
+
+ - Define a rule's updating actions, replacing any
+ previous definition.
+
+
-
+ rulename field1 : field2 : ...
+ : fieldN ;
+
+
+ - Invoke a rule.
+
+
|
+
+
+
+ A rule is invoked with values in field1 through
+ fieldN. They may be referenced in the procedure's
+ statements as $(1) through $(N), and the first
+ two only may be referenced in the action's commands as
+ $(1) and $(2). $(<) and $(>) are synonymous with $(1)
+ and $(2).
+
+
+
+ Rules fall into two categories: updating rules (with actions),
+ and pure procedure rules (without actions). Updating rules
+ treat arguments $(1) and $(2) as built targets and sources,
+ respectively, while pure procedure rules can take arbitrary
+ arguments.
+
+
+
+ When an updating rule is invoked, its updating actions are added
+ to those associated with its built targets ($(1)) before the
+ rule's procedure is run. Later, to build the targets in the
+ updating phase, commands are passed to the OS command
+ shell, with $(1) and $(2) replaced by bound versions of the
+ target names. See Binding above.
+
+
+
+
+
Action Modifiers
+
+
+
+
+ The following action modifiers are understood:
+
+
+
+ actions bind vars
+ - $(vars) will be replaced with bound values.
+
+
actions existing
+ - $(>) includes only source targets currently existing.
+
+
actions ignore
+ - The return status of the commands is ignored.
+
+
actions piecemeal
+ - commands are repeatedly invoked with a subset
+ of $(>) small enough to fit in the command buffer on this
+ OS.
+
+
actions quietly
+ - The action is not echoed to the standard output.
+
+
actions together
+ - The $(>) from multiple invocations of the same action
+ on the same built target are glommed together.
+
+
actions updated
+ - $(>) includes only source targets themselves marked
+ for updating.
+
+
|
+
+
+ -
Built-in Rules
-
+
+
+ Jam has ten built-in rules, all of which are pure
+ procedure rules without updating actions. They are in
+ three groups: the first builds the dependency graph;
+ the second modifies it; and the third are just utility
+ rules.
+
+
+
+
Dependency Building
+
+
+
+
+ DEPENDS targets1 : targets2 ;
+
+
+ - Builds a direct dependency: makes each of targets1
+ depend on each of targets2. Generally, targets1
+ will be rebuilt if targets2 are themselves rebuilt are
+ or are newer than targets1.
+
+
+ INCLUDES targets1 : targets2 ;
+
+
+ - Builds a sibling dependency: makes each of targets2
+ depend on anything upon which each of targets1 depends.
+ This reflects the dependencies that arise when one source file
+ includes another: the object built from the source file depends
+ both on the original and included source file, but the two
+ sources files don't depend on each other. For example:
+
+
+ DEPENDS foo.o : foo.c ;
+ INCLUDES foo.c : foo.h ;
+
+
+
+
+ "foo.h" depends on "foo.c" and "foo.h" in this example.
+
+ |
+
+
+
Modifying Binding
+
+
+
+
+ The six rules ALWAYS, LEAVES, NOCARE, NOTFILE, NOUPDATE, and
+ TEMPORARY modify the dependency graph so that jam treats
+ the targets differently during its target binding phase. See
+ Binding above. Normally, jam
+ updates a target if it is missing, if its filesystem modification
+ time is older than any of its dependencies (recursively), or if
+ any of its dependencies are being updated. This basic behavior
+ can be changed by invoking the following rules:
+
+
+
+
+ ALWAYS targets ;
+
+
+ - Causes targets to be rebuilt regardless of whether
+ they are up-to-date (they must still be in the dependency graph).
+ This is used for the clean and uninstall targets, as they have
+ no dependencies and would otherwise appear never to need building.
+ It is best applied to targets that are also NOTFILE targets,
+ but it can also be used to force a real file to be updated as
+ well.
+
+
+ LEAVES targets ;
+
+
+ - Makes each of targets depend only on its leaf sources,
+ and not on any intermediate targets. This makes it immune to
+ its dependencies being updated, as the "leaf" dependencies are
+ those without their own dependencies and without updating actions.
+ This allows a target to be updated only if original source files
+ change.
+
+
+ NOCARE targets ;
+
+
+ - Causes jam to ignore targets that neither
+ can be found nor have updating actions to build them. Normally
+ for such targets jam issues a warning and then skips
+ other targets that depend on these missing targets. The HdrRule
+ in Jambase uses NOCARE on the header file names found during
+ header file scanning, to let jam know that the included
+ files may not exist. For example, if a #include is within an
+ #ifdef, the included file may not actually be around.
+
+
+ NOTFILE targets ;
+
+
+ - Marks targets as pseudotargets and not real files.
+ No timestamp is checked, and so the actions on such a target
+ are only executed if the target's dependencies are updated, or
+ if the target is also marked with ALWAYS. The default jam
+ target "all" is a pseudotarget. In Jambase, NOTFILE is used to
+ define several addition convenient pseudotargets.
+
+
+ NOUPDATE targets ;
+
+
+ - Causes the timestamps on targets to be ignored.
+ This has two effects: first, once the target has been created
+ it will never be updated; second, manually updating target will
+ not cause other targets to be updated. In Jambase, for example,
+ this rule is applied to directories by the MkDir rule, because
+ MkDir only cares that the target directory exists, not when it
+ has last been updated.
+
+
+ TEMPORARY targets ;
+
+
+ - Marks targets as temporary, allowing them to be
+ removed after other targets that depend upon them have been
+ updated. If a TEMPORARY target is missing, jam uses the
+ timestamp of the target's parent. Jambase uses TEMPORARY to
+ mark object files that are archived in a library after they are
+ built, so that they can be deleted after they are archived.
+
+
|
+
+
Utility Rules
+
+
+
+ The two rules ECHO and EXIT are utility rules, used only in
+ jam's parsing phase.
+
+
+
+
+ ECHO args ;
+
+
+ - Blurts out the message args to stdout.
+
+
+ EXIT args ;
+
+
+ - Blurts out the message args to stdout and then exits
+ with a failure status.
+
+
|
+
+ -
Flow-of-Control
-
+
+
+
+ Jam has several simple flow-of-control statements:
+
+
+
+
+
+ for var in list { statements }
+
+
+
+ - Executes statements for each element in
+ list, setting the variable var to the element
+ value.
+
+
+
+ if cond { statements }
+ [ else statements ]
+
+
+
+ - Does the obvious; the else clause is optional.
+ cond is built of:
+
+
+
+ a |
+ true if any a element is a non-zero-length
+ string |
+ a = b |
+ list a matches list b
+ string-for-string |
+ a != b |
+ list a does not match list b |
+ a < b |
+ a[i] string is less than b[i]
+ string, where i is first mismatched element
+ in lists a and b |
+ a <= b |
+ every a string is less than or equal to
+ its b counterpart |
+ a > b |
+ a[i] string is greater than b[i]
+ string, where i is first mismatched element |
+ a >= b |
+ every a string is greater than or equal to
+ its b counterpart |
+ a in b |
+ true if all elements of a can be found
+ in b, or if a has no elements |
+ ! cond |
+ condition not true |
+ cond && cond |
+ conjunction |
+ cond || cond |
+ disjunction |
+ ( cond ) |
+ precedence grouping |
+
+
+
+ -
+
+ include file ;
+
+
+
+ - Causes jam to read the named file.
+ The file is bound like a regular target (see Binding above) but unlike a regular
+ target the include file cannot be built.
+
+
+
+ The include file is inserted into the input stream during
+ the parsing phase. The primary input file and all the included
+ file(s) are treated as a single file; that is, jam
+ infers no scope boundaries from included files.
+
+ -
+
+ local vars [ = values ] ;
+
+
+
+ - Creates new vars inside to the enclosing {}
+ block, obscuring any previous values they might have. The
+ previous values for vars are restored when the current
+ block ends. Any rule called or file included will see the
+ local and not the previous value (this is sometimes called
+ Dynamic Scoping). The local statement may appear anywhere,
+ even outside of a block (in which case the previous value
+ is restored when the input ends). The vars are
+ initialized to values if present, or left uninitialized
+ otherwise.
+
+
-
+
+ switch value
+ {
+ case pattern1 : statements ;
+ case pattern2 : statements ;
+ ...
+ }
+
+
+
+ - The switch statement executes zero or one of the
+ enclosed statements, depending on which, if any, is
+ the first case whose pattern matches value.
+ The pattern values are not variable-expanded. The
+ pattern values may include the following wildcards:
+
+
+
+ ? |
+ match any single character |
+ * |
+ match zero or more characters |
+ [chars] |
+ match any single character in chars |
+
+
+
+ |
+
+ -
Variables
-
+
+
+
+ Jam variables are lists of zero or more elements, with
+ each element being a string value. An undefined variable is
+ indistinguishable from a variable with an empty list, however,
+ a defined variable may have one more elements which are null
+ strings. All variables are referenced as $(variable).
+
+
+
+ Variables are either global or target-specific. In the latter
+ case, the variable takes on the given value only during the
+ updating of the specific target.
+
+
+
+ A variable is defined with:
+
+
+
+
+ variable = elements ;
+
+ variable += elements ;
+
+ variable on targets = elements ;
+
+ variable on targets += elements ;
+
+ variable default = elements ;
+
+ variable ?= elements ;
+
+ |
+
+
+
+ The first two forms set variable globally. The third
+ and forth forms set a target-specific variable. The = operator
+ replaces any previous elements of variable with
+ elements; the += operation adds elements to
+ variable's list of elements. The final two forms are
+ synonymous: they set variable globally, but only if it
+ was previously unset.
+
+
+
+ Variables referenced in updating commands will be replaced with
+ their values; target-specific values take precedence over global
+ values. Variables passed as arguments ($(1) and $(2)) to actions
+ are replaced with their bound values; the "bind" modifier can
+ be used on actions to cause other variables to be replaced with
+ bound values. See Action Modifiers
+ above.
+
+
+
+ Jam variables are not re-exported to the environment of
+ the shell that executes the updating actions, but the updating
+ actions can reference jam variables with $(variable).
+
+
Variable Expansion
+
+
+
+ During parsing, jam performs variable expansion on each
+ token that is not a keyword or rule name. Such tokens with
+ embedded variable references are replaced with zero or more
+ tokens. Variable references are of the form $(v) or
+ $(vm), where v is the variable name, and m
+ are optional modifiers.
+
+
+
+ Variable expansion in a rule's actions is similar to variable
+ expansion in statements, except that the action string is
+ tokenized at whitespace regardless of quoting.
+
+
+
+ The result of a token after variable expansion is the
+ product of the components of the token, where each
+ component is a literal substring or a list substituting a variable
+ reference. For example:
+
+
+
+ $(X) -> a b c
+ t$(X) -> ta tb tc
+ $(X)z -> az bz cz
+ $(X)-$(X) -> a-a a-b a-c b-a b-b b-c c-a c-b c-c
+
+ |
+
+
+
+ The variable name and modifiers can themselves contain
+ a variable reference, and this partakes of the product
+ as well:
+
+
+
+ $(X) -> a b c
+ $(Y) -> 1 2
+ $(Z) -> X Y
+ $($(Z)) -> a b c 1 2
+
+ |
+
+
+
+ Because of this product expansion, if any variable reference in
+ a token is undefined, the result of the expansion is an empty
+ list. If any variable element is a null string, the result
+ propagates the non-null elements:
+
+
+
+ $(X) -> a ""
+ $(Y) -> "" 1
+ $(Z) ->
+ *$(X)$(Y)* -> *a* *a1* ** *1*
+ *$(X)$(Z)* ->
+
+ |
+
+
+
+ A variable element's string value can be parsed into grist and
+ filename-related components. Modifiers to a variable are used
+ to select elements, select components, and replace components.
+ The modifiers are:
+
+
+
+ [n]
+ | Select element number n (starting at 1). If
+ the variable contains fewer than n elements,
+ the result is a zero-element list.
+
+ |
[n-m]
+ | Select elements number n through m.
+
+ |
[n-]
+ | Select elements number n through the last.
+
+ |
:B
+ | Select filename base.
+
+ |
:S
+ | Select (last) filename suffix.
+
+ |
:M
+ | Select archive member name.
+
+ |
:D
+ | Select directory path.
+
+ |
:P
+ | Select parent directory.
+
+ |
:G
+ | Select grist.
+
+ |
:U
+ | Replace lowercase characters with uppercase.
+
+ |
:L
+ | Replace uppercase characters with lowercase.
+
+ |
:chars
+ | Select the components listed in chars.
+
+ |
:G=grist
+ | Replace grist with grist.
+
+ |
:D=path
+ | Replace directory with path.
+
+ |
:B=base
+ | Replace the base part of file name with base.
+
+ |
:S=suf
+ | Replace the suffix of file name with suf.
+
+ |
:M=mem
+ | Replace the archive member name with mem.
+
+ |
:R=root
+ | Prepend root to the whole file name, if not
+ already rooted.
+
+ |
+
+
+
+ On VMS, $(var:P) is the parent directory of $(var:D); on Unix
+ and NT, $(var:P) and $(var:D) are the same.
+
+
-
Built-in Variables
-
+
+
+
+ This section discusses variables that have special meaning to
+ jam.
+
+
+
SEARCH and LOCATE Variables
+
+
+
+
+ These two variables control the binding of file target names to
+ locations in the file system. Generally, $(SEARCH) is used to
+ find existing sources while $(LOCATE) is used to fix the location
+ for built targets.
+
+
+
+ Rooted (absolute path) file targets are bound as is. Unrooted
+ file target names are also normally bound as is, and thus relative
+ to the current directory, but the settings of $(LOCATE) and
+ $(SEARCH) alter this:
+
+
+
+
+
+ - If $(LOCATE) is set then the target is bound relative to
+ the first directory in $(LOCATE). Only the first element is
+ used for binding.
+
+
- If $(SEARCH) is set then the target is bound to the first
+ directory in $(SEARCH) where the target file already exists.
+
+
- If the $(SEARCH) search fails, the target is bound relative
+ to the current directory anyhow.
+
+
+
+
+
+ Both $(SEARCH) and $(LOCATE) should be set target-specific and
+ not globally. If they were set globally, jam would use
+ the same paths for all file binding, which is not likely to
+ produce sane results. When writing your own rules, especially
+ ones not built upon those in Jambase, you may need to set
+ $(SEARCH) or $(LOCATE) directly. Almost all of the rules defined
+ in Jambase set $(SEARCH) and $(LOCATE) to sensible values for
+ sources they are looking for and targets they create, respectively.
+
+
+
HDRSCAN and HDRRULE Variables
+
+
+
+
+ These two variable control header file scanning. $(HDRSCAN) is
+ an egrep(1) pattern, with ()'s surrounding the file name,
+ used to find file inclusion statements in source files. Jambase
+ uses $(HDRPATTERN) as the pattern for $(HDRSCAN). $(HDRRULE)
+ is the name of a rule to invoke with the results of the scan:
+ the scanned file is the target, the found files are the sources.
+ This is the only place where jam invokes a rule through
+ a variable setting.
+
+
+
+ Both $(HDRSCAN) and $(HDRRULE) must be set for header file
+ scanning to take place, and they should be set target-specific
+ and not globally. If they were set globally, all files, including
+ executables and libraries, would be scanned for header file
+ include statements.
+
+
+
+ The scanning for header file inclusions is not exact, but it is
+ at least dynamic, so there is no need to run something like
+ makedepend(GNU) to create a static dependency file. The
+ scanning mechanism errs on the side of inclusion (i.e., it is
+ more likely to return filenames that are not actually used by
+ the compiler than to miss include files) because it can't tell
+ if #include lines are inside #ifdefs or other conditional logic.
+ In Jambase, HdrRule applies the NOCARE rule to each header file
+ found during scanning so that if the file isn't present yet
+ doesn't cause the compilation to fail, jam won't care.
+
+
+
+ Also, scanning for regular expressions only works where the
+ included file name is literally in the source file. It can't
+ handle languages that allow including files using variable names
+ (as the Jam language itself does).
+
+
Platform Identifier Variables
+
+
+
+ A number of Jam built-in variables can be used to identify
+ runtime platform:
+
+
+
+
+
+ | OS | OS identifier string
+ |
| OSPLAT | Underlying architecture, when applicable
+ |
| MAC | true on MAC platform
+ |
| NT | true on NT platform
+ |
| OS2 | true on OS2 platform
+ |
| UNIX | true on Unix platforms
+ |
| VMS | true on VMS platform
+
+ |
+
+
Jam Version Variables
+
+
+
+
+
+ | JAMDATE | Time and date at jam start-up.
+ |
| JAMUNAME | Ouput of uname(1) command (Unix only)
+ |
| JAMVERSION | jam version, currently "2.3"
+
+ |
+
+
JAMSHELL Variable
+
+
+
+ When jam executes a rule's action block, it forks and
+ execs a shell, passing the action block as an argument to the
+ shell. The invocation of the shell can be controlled by
+ $(JAMSHELL). The default on Unix is, for example:
+
+
+
+ JAMSHELL = /bin/sh -c % ;
+
+
+
+ The % is replaced with the text of the action block.
+
+
+
+ Jam does not directly support building in parallel across
+ multiple hosts, since that is heavily dependent on the local
+ environment. To build in parallel across multiple hosts, you
+ need to write your own shell that provides access to the multiple
+ hosts. You then reset $(JAMSHELL) to reference it.
+
+
+
+ Just as jam expands a % to be the text of the rule's
+ action block, it expands a ! to be the multi-process slot number.
+ The slot number varies between 1 and the number of concurrent
+ jobs permitted by the -j flag given on the command line. Armed
+ with this, it is possible to write a multiple host shell. For
+ example:
+
+
+
+
+
+ #!/bin/sh
+
+ # This sample JAMSHELL uses the SunOS on(1) command to execute a
+ # command string with an identical environment on another host.
+
+ # Set JAMSHELL = jamshell ! %
+ #
+ # where jamshell is the name of this shell file.
+ #
+ # This version handles up to -j6; after that they get executed
+ # locally.
+
+ case $1 in
+ 1|4) on winken sh -c "$2";;
+ 2|5) on blinken sh -c "$2";;
+ 3|6) on nod sh -c "$2";;
+ *) eval "$2";;
+ esac
+
+ |
+
+
+ -
DIAGNOSTICS
-
+
+
+
+ In addition to generic error messages, jam may emit one of
+ the following:
+
+
+
+ warning: unknown rule X -
+
+ A rule was invoked that has not been defined with
+ an "actions" or "rule" statement.
+
+
using N temp target(s) -
+
+ Targets marked as being temporary (but nonetheless
+ present) have been found.
+
+
updating N target(s) -
+
+ Targets are out-of-date and will be updated.
+
+
can't find N target(s) -
+
+ Source files can't be found and there are no
+ actions to create them.
+
+
can't make N target(s) -
+
+ Due to sources not being found, other targets cannot be made.
+
+
warning: X depends on itself -
+
+ A target depends on itself either directly or
+ through its sources.
+
+
don't know how to make X -
+
+ A target is not present and no actions have been
+ defined to create it.
+
+
X skipped for lack of Y -
+
+ A source failed to build, and thus a target cannot
+ be built.
+
+
warning: using independent target X -
+
+ A target that is not a dependency of any other
+ target is being referenced with $(<) or $(>).
+
+
X removed -
+
+ Jam removed a partially built target after being
+ interrupted.
+
+
|
+
+ -
BUGS, LIMITATIONS
-
+
+
+
+ The -j flag can cause jam to get confused when single
+ actions update more than one target at a time. jam may
+ proceed as if the targets were built even though they are still
+ under construction.
+
+
+
+ For parallel building to be successful, the dependencies among
+ files must be properly spelled out, as targets tend to get built
+ in a quickest-first ordering. Also, beware of un-parallelizable
+ commands that drop fixed-named files into the current directory,
+ like yacc(1) does.
+
+
+
+ With the -j flag, errors from failed commands can get staggeringly
+ mixed up.
+
+
+
+ A poorly set $(JAMSHELL) is likely to result in silent failure.
+
+
-
SEE ALSO
-
+
+
+
+
+
+
+
+ Jam documentation and source are available from the Perforce
+ Public Depot.
+
+
-
AUTHOR
-
+
+
+ Jam's author is Christopher Seiwald (seiwald@perforce.com).
+ Documentation is provided by
+ Perforce Software, Inc.
+
+
+
+
+
+
+
+ Copyright 1997, 2000 Perforce Software, Inc.
+
+ Comments to info@perforce.com
+
+ Last updated: December 31, 2000
+
+ $Id$
+
+
+
+
diff --git a/historic/jam/src/Jambase b/historic/jam/src/Jambase
new file mode 100644
index 000000000..dcd9ec0a1
--- /dev/null
+++ b/historic/jam/src/Jambase
@@ -0,0 +1,2288 @@
+#
+# /+\
+# +\ Copyright 1993, 2000 Christopher Seiwald.
+# \+/
+#
+# This file is part of Jam - see jam.c for Copyright information.
+#
+
+# This file is ALSO:
+# (C) Copyright David Abrahams 2001. Permission to copy, use,
+# modify, sell and distribute this software is granted provided this
+# copyright notice appears in all copies. This software is provided
+# "as is" without express or implied warranty, and with no claim as
+# to its suitability for any purpose.
+
+# The logic for finding the build system:
+#
+# The process is controlled by variables (in decreasing
+# precedence):
+#
+# If JAMBASE is set, it specifies the build system filename
+#
+# Otherwise, if BOOST_BUILD_PATH or BOOST_ROOT is set, the build system filename
+# is boost-build.jam.
+#
+# If the build system filename does not contain a path specification, the build
+# system file is searched for on $(BOOST_BUILD_PATH) then at
+# $(BOOST_ROOT)/tools/build.
+#
+# If neither JAMBASE, BOOST_ROOT, nor BOOST_BUILD_PATH is set, we use the
+# built-in Jambase (this file) and load the user's Jamfile. Perforce Jam has
+# this behavior, and it is used for building Jam itself. Thus, if you rebuild
+# Jam, these variables should be unset.
+if $(BOOST_ROOT)
+{
+ BOOST_BUILD_PATH ?= $(BOOST_ROOT)/tools/build ;
+}
+
+if $(BOOST_BUILD_PATH)
+{
+ JAMBASE ?= boost-build.jam ;
+}
+
+if $(JAMBASE)
+{
+ JAMBASE = $(JAMBASE:G=jam-module) ; # puts the Jambase target in a different
+ # namespace from other targets so that
+ # it doesn't collide.
+ SEARCH on $(JAMBASE) = $(JAMBASE_PATH) $(BOOST_BUILD_PATH) ;
+ include $(JAMBASE) ;
+}
+else
+{
+
+#
+# JAMBASE - jam 2.3 ruleset providing make(1)-like functionality
+#
+# Supports UNIX, NT, and VMS.
+#
+# 12/27/93 (seiwald) - purturb library sources with SOURCE_GRIST
+# 04/18/94 (seiwald) - use '?=' when setting OS specific vars
+# 04/21/94 (seiwald) - do RmTemps together
+# 05/05/94 (seiwald) - all supported C compilers support -o: relegate
+# RELOCATE as an option; set Ranlib to "" to disable it
+# 06/01/94 (seiwald) - new 'actions existing' to do existing sources
+# 08/25/94 (seiwald) - new ObjectCcFlags rule to append to per-target CCFLAGS
+# 08/29/94 (seiwald) - new ObjectHdrs rule to append to per-target HDRS
+# 09/19/94 (seiwald) - LinkLibraries and Undefs now append
+# - Rule names downshifted.
+# 10/06/94 (seiwald) - Dumb yyacc stuff moved into Jamfile.
+# 10/14/94 (seiwald) - (Crude) support for .s, .C, .cc, .cpp, and .f files.
+# 01/08/95 (seiwald) - Shell now handled with awk, not sed
+# 01/09/95 (seiwald) - Install* now take dest directory as target
+# 01/10/95 (seiwald) - All entries sorted.
+# 01/10/95 (seiwald) - NT support moved in, with LauraW's help.
+# 01/10/95 (seiwald) - VMS support moved in.
+# 02/06/95 (seiwald) - ObjectC++Flags and SubDirC++Flags added.
+# 02/07/95 (seiwald) - Iron out when HDRSEARCH uses "" or SEARCH_SOURCE.
+# 02/08/95 (seiwald) - SubDir works on VMS.
+# 02/14/95 (seiwald) - MkDir and entourage.
+# 04/30/95 (seiwald) - Use install -c flag so that it copies, not moves.
+# 07/10/95 (taylor) - Support for Microsoft C++.
+# 11/21/96 (peterk) - Support for BeOS
+# 07/19/99 (sickel) - Support for Mac OS X Server (and maybe client)
+# 02/18/00 (belmonte)- Support for Cygwin.
+
+# Special targets defined in this file:
+#
+# all - parent of first, shell, files, lib, exe
+# first - first dependent of 'all', for potential initialization
+# shell - parent of all Shell targets
+# files - parent of all File targets
+# lib - parent of all Library targets
+# exe - parent of all Main targets
+# dirs - parent of all MkDir targets
+# clean - removes all Shell, File, Library, and Main targets
+# uninstall - removes all Install targets
+#
+
+# Rules defined by this file:
+#
+# as obj.o : source.s ; .s -> .o
+# Bulk dir : files ; populate directory with many files
+# Cc obj.o : source.c ; .c -> .o
+# C++ obj.o : source.cc ; .cc -> .o
+# Clean clean : sources ; remove sources with 'jam clean'
+# File dest : source ; copy file
+# Fortran obj.o : source.f ; .f -> .o
+# GenFile source.c : program args ; make custom file
+# Hardlink target : source ; make link from source to target
+# HdrRule source : headers ; handle #includes
+# InstallInto dir : sources ; install any files
+# InstallBin dir : sources ; install binaries
+# InstallLib dir : sources ; install files
+# InstallFile dir : sources ; install files
+# InstallMan dir : sources ; install man pages
+# InstallShell dir : sources ; install shell scripts
+# Lex source.c : source.l ; .l -> .c
+# Library lib : source ; archive library from compiled sources
+# LibraryFromObjects lib : objects ; archive library from objects
+# LinkLibraries images : libraries ; bag libraries onto Mains
+# Main image : source ; link executable from compiled sources
+# MainFromObjects image : objects ; link executable from objects
+# MkDir dir ; make a directory, if not there
+# Object object : source ; compile object from source
+# ObjectCcFlags source : flags ; add compiler flags for object
+# ObjectC++Flags source : flags ; add compiler flags for object
+# ObjectHdrs source : dirs ; add include directories for object
+# Objects sources ; compile sources
+# RmTemps target : sources ; remove temp sources after target made
+# Setuid images ; mark executables Setuid
+# SubDir TOP d1 d2 ... ; start a subdirectory Jamfile
+# SubDirCcFlags flags ; add compiler flags until next SubDir
+# SubDirC++Flags flags ; add compiler flags until next SubDir
+# SubDirHdrs dirs ; add include dirs until next SubDir
+# SubInclude TOP d1 d2 ... ; include a subdirectory Jamfile
+# Shell exe : source ; make a shell executable
+# Undefines images : symbols ; save undef's for linking
+# UserObject object : source ; handle unknown suffixes for Object
+# Yacc source.c : source.y ; .y -> .c
+#
+# Utility rules that have no side effects (not supported):
+#
+# FAppendSuffix f1 f2 ... : $(SUF) ; return $(<) with suffixes
+# FConcat value ... ; return contatenated values
+# FDirName d1 d2 ... ; return path from root to dir
+# FGrist d1 d2 ... ; return d1!d2!...
+# FGristFiles value ; return $(value:G=$(SOURCE_GRIST))
+# FGristSourceFiles value ; return $(value:G=$(SOURCE_GRIST))
+# FRelPath d1 : d2 ; return rel path from d1 to d2
+# FSubDir d1 d2 ... ; return path to root
+#
+
+
+# Brief review of the jam language:
+#
+# Statements:
+# rule RULE - statements to process a rule
+# actions RULE - system commands to carry out target update
+#
+# Modifiers on actions:
+# together - multiple instances of same rule on target get executed
+# once with their sources ($(>)) concatenated
+# updated - refers to updated sources ($(>)) only
+# ignore - ignore return status of command
+# quietly - don't trace its execution unless verbose
+# piecemeal - iterate command each time with a small subset of $(>)
+# existing - refers to currently existing sources ($(>)) only
+# bind vars - subject to binding before expanding in actions
+#
+# Special rules:
+# ALWAYS - always build a target
+# DEPENDS - builds the dependency graph
+# ECHO - blurt out targets on stdout
+# EXIT - blurt out targets and exit
+# INCLUDES - marks sources as headers for target (a codependency)
+# NOCARE - don't panic if the target can't be built
+# NOUPDATE - create the target if needed but never update it
+# NOTFILE - ignore the timestamp of the target (it's not a file)
+# TEMPORARY - target need not be present if sources haven't changed
+#
+# Special variables set by jam:
+# $(<) - targets of a rule (to the left of the :)
+# $(>) - sources of a rule (to the right of the :)
+# $(xxx) - true on xxx (UNIX, VMS, NT, OS2, MAC)
+# $(OS) - name of OS - varies wildly
+# $(JAMVERSION) - version number (2.3)
+#
+# Special variables used by jam:
+# SEARCH - where to find something (used during binding and actions)
+# LOCATE - where to plop something not found with SEARCH
+# HDRRULE - rule to call to handle include files
+# HDRSCAN - egrep regex to extract include files
+#
+# Special targets:
+# all - default if none given on command line
+#
+
+# Initialize variables
+#
+
+#
+# OS specific variable settings
+#
+
+if $(NT)
+{
+ # the list of supported toolsets on Windows NT and Windows 95/98
+ #
+ local SUPPORTED_TOOLSETS = "BORLANDC" "VISUALC" "VISUALC16" "INTELC" "WATCOM"
+ "MINGW" "LCC" ;
+
+ # this variable holds the current toolset
+ #
+ TOOLSET = "" ;
+
+ # if the JAM_TOOLSET environment variable is defined, check that it is
+ # one of our supported values
+ #
+ if $(JAM_TOOLSET)
+ {
+ local t ;
+
+ for t in $(SUPPORTED_TOOLSETS)
+ {
+ if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }
+ }
+
+ if ! $(TOOLSET)
+ {
+ ECHO "The JAM_TOOLSET environment variable is defined but its value" ;
+ ECHO "is invalid, please use one of the following:" ;
+ ECHO ;
+
+ for t in $(SUPPORTED_TOOLSETS) { ECHO " " $(t) ; }
+ EXIT ;
+ }
+ }
+
+ # if TOOLSET is empty, we'll try to detect the toolset from other
+ # environment variables to remain backwards compatible with Jam 2.3
+ #
+ if ! $(TOOLSET)
+ {
+ if $(BCCROOT)
+ {
+ TOOLSET = BORLANDC ;
+ BORLANDC = $(BCCROOT) ;
+ }
+ else if $(MSVC)
+ {
+ TOOLSET = VISUALC16 ;
+ VISUALC16 = $(MSVC) ;
+ }
+ else if $(MSVCNT)
+ {
+ TOOLSET = VISUALC ;
+ VISUALC = $(MSVCNT) ;
+ }
+ else if $(MINGW)
+ {
+ TOOLSET = MINGW ;
+ }
+ else
+ {
+ ECHO "Jam cannot be run because you didn't indicate which compilation toolset" ;
+ ECHO "to use. To do so, follow these simple instructions:" ;
+ ECHO ;
+ ECHO " - define one of the following environment variable, with the" ;
+ ECHO " appropriate value according to this list:" ;
+ ECHO ;
+ ECHO " Variable Toolset Description" ;
+ ECHO ;
+ ECHO " BORLANDC Borland C++ BC++ install path" ;
+ ECHO " VISUALC Microsoft Visual C++ VC++ install path" ;
+ ECHO " VISUALC16 Microsoft Visual C++ 16 bit VC++ 16 bit install" ;
+ ECHO " INTELC Intel C/C++ IC++ install path" ;
+ ECHO " WATCOM Watcom C/C++ Watcom install path" ;
+ ECHO " MINGW MinGW (gcc) MinGW install path" ;
+ ECHO " LCC Win32-LCC LCC-Win32 install path" ;
+ ECHO ;
+ ECHO " - define the JAM_TOOLSET environment variable with the *name*" ;
+ ECHO " of the toolset variable you want to use." ;
+ ECHO ;
+ ECHO " e.g.: set VISUALC=C:\Visual6" ;
+ ECHO " set JAM_TOOLSET=VISUALC" ;
+ ECHO ;
+ EXIT ;
+ }
+ }
+
+ CP ?= copy ;
+ RM ?= del /f/q ;
+ SLASH ?= \\ ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ SUFEXE ?= .exe ;
+
+ if $(TOOLSET) = BORLANDC
+ {
+ ECHO "Compiler is Borland C++" ;
+
+ AR ?= tlib /C /P64 ;
+ CC ?= bcc32 ;
+ CCFLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus ;
+ C++ ?= bcc32 ;
+ C++FLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus -P ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= $(CCFLAGS) ;
+ STDLIBPATH ?= $(BORLANDC)\\lib ;
+ STDHDRS ?= $(BORLANDC)\\include ;
+ NOARSCAN ?= true ;
+ }
+ else if $(TOOLSET) = VISUALC16
+ {
+ ECHO "Compiler is Microsoft Visual C++ 16 bit" ;
+
+ AR ?= lib /nologo ;
+ CC ?= cl /nologo ;
+ CCFLAGS ?= /D \"WIN\" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= $(CCFLAGS) ;
+ LINKLIBS ?=
+ #$(VISUALC16)\\lib\\advapi32.lib
+ #$(VISUALC16)\\lib\\libcmt.lib
+ $(VISUALC16)\\lib\\mlibce.lib
+ #$(VISUALC16)\\lib\\slibce.lib
+ $(VISUALC16)\\lib\\oldnames.lib
+ #$(VISUALC16)\\lib\\kernel32.lib
+ ;
+ LINKLIBS ?= ;
+ NOARSCAN ?= true ;
+ OPTIM ?= "" ;
+ STDHDRS ?= $(VISUALC16)\\include ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = VISUALC
+ {
+ ECHO "Compiler is Microsoft Visual C++" ;
+
+ AR ?= lib ;
+ AS ?= masm386 ;
+ CC ?= cl /nologo ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= link /nologo ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= $(VISUALC)\\lib\\advapi32.lib
+ # $(VISUALC)\\lib\\libc.lib
+ # $(VISUALC)\\lib\\oldnames.lib
+ $(VISUALC)\\lib\\gdi32.lib
+ $(VISUALC)\\lib\\user32.lib
+ $(VISUALC)\\lib\\kernel32.lib ;
+ OPTIM ?= "" ;
+ STDHDRS ?= $(VISUALC)\\include ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = INTELC
+ {
+ ECHO "Compiler is Intel C/C++" ;
+
+ if ! $(VISUALC)
+ {
+ ECHO "As a special exception, when using the Intel C++ compiler, you need" ;
+ ECHO "to define the VISUALC environment variable to indicate the location" ;
+ ECHO "of your Visual C++ installation. Aborting.." ;
+ EXIT ;
+ }
+
+ AR ?= lib ;
+ AS ?= masm386 ;
+ CC ?= icl /nologo ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= link /nologo ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= $(VISUALC)\\lib\\advapi32.lib
+ # $(VISUALC)\\lib\\libc.lib
+ # $(VISUALC)\\lib\\oldnames.lib
+ $(VISUALC)\\lib\\kernel32.lib
+ ;
+ OPTIM ?= "" ;
+ STDHDRS ?= $(INTELC)\include $(VISUALC)\\include ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = WATCOM
+ {
+ ECHO "Compiler is Watcom C/C++" ;
+
+ AR ?= wlib ;
+ CC ?= wcc386 ;
+ CCFLAGS ?= /zq /DWIN32 /I$(WATCOM)\\h ; # zq=quiet
+ C++ ?= wpp386 ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ CP ?= copy ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ LINK ?= wcl386 ;
+ LINKFLAGS ?= /zq ; # zq=quiet
+ LINKLIBS ?= ;
+ MV ?= move ;
+ NOARSCAN ?= true ;
+ OPTIM ?= ;
+ RM ?= del /f ;
+ SLASH ?= \\ ;
+ STDHDRS ?= $(WATCOM)\\h $(WATCOM)\\h\\nt ;
+ SUFEXE ?= .exe ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = MINGW
+ {
+ ECHO "Compiler is GCC with Mingw" ;
+
+ AR ?= ar -ru ;
+ CC ?= gcc ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= "" ;
+ OPTIM ?= ;
+ SUFOBJ = .o ;
+ SUFLIB = .a ;
+ SLASH = / ;
+# NOARSCAN ?= true ;
+ }
+ else if $(TOOLSET) = LCC
+ {
+ ECHO "Compiler is Win32-LCC" ;
+
+ AR ?= lcclib ;
+ CC ?= lcc ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= lcclnk ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= "" ;
+ OPTIM ?= ;
+ NOARSCAN = true ;
+ }
+ else
+ {
+#
+# XXX: We need better comments here !!
+#
+ EXIT On NT, set BCCROOT, MSVCNT, MINGW or MSVC to the root of the
+ Borland or Microsoft directories. ;
+ }
+
+}
+else if $(OS2)
+{
+ # the list of supported toolsets on Windows NT and Windows 95/98
+ #
+ local SUPPORTED_TOOLSETS = "EMX" "WATCOM" ;
+
+ # this variable holds the current toolset
+ #
+ TOOLSET = "" ;
+
+ # if the JAM_TOOLSET environment variable is defined, check that it is
+ # one of our supported values
+ #
+ if $(JAM_TOOLSET)
+ {
+ local t ;
+
+ for t in $(SUPPORTED_TOOLSETS)
+ {
+ if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }
+ }
+
+ if ! $(TOOLSET)
+ {
+ ECHO "The JAM_TOOLSET environment variable is defined but its value" ;
+ ECHO "is invalid, please use one of the following:" ;
+ ECHO ;
+
+ for t in $(SUPPORTED_TOOLSETS) { ECHO " " $(t) ; }
+ EXIT ;
+ }
+ }
+
+ # if TOOLSET is empty, we'll try to detect the toolset from other
+ # environment variables to remain backwards compatible with Jam 2.3
+ #
+ if ! $(TOOLSET)
+ {
+ if $(watcom)
+ {
+ WATCOM = $(watcom) ;
+ TOOLSET = WATCOM ;
+ }
+ else
+ {
+ ECHO "Jam cannot be run because you didn't indicate which compilation toolset" ;
+ ECHO "to use. To do so, follow these simple instructions:" ;
+ ECHO ;
+ ECHO " - define one of the following environment variable, with the" ;
+ ECHO " appropriate value according to this list:" ;
+ ECHO ;
+ ECHO " Variable Toolset Description" ;
+ ECHO ;
+ ECHO " WATCOM Watcom C/C++ Watcom install path" ;
+ ECHO " EMX EMX (gcc) EMX install path" ;
+ ECHO " VISUALAGE IBM Visual Age C/C++ VisualAge install path" ;
+ ECHO ;
+ ECHO " - define the JAM_TOOLSET environment variable with the *name*" ;
+ ECHO " of the toolset variable you want to use." ;
+ ECHO ;
+ ECHO " e.g.: set WATCOM=C:\WATCOM" ;
+ ECHO " set JAM_TOOLSET=WATCOM" ;
+ ECHO ;
+ EXIT ;
+ }
+ }
+
+ RM = del /f ;
+ CP = copy ;
+ MV ?= move ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ SUFEXE ?= .exe ;
+
+ if $(TOOLSET) = WATCOM
+ {
+ AR ?= wlib ;
+ BINDIR ?= \\os2\\apps ;
+ CC ?= wcc386 ;
+ CCFLAGS ?= /zq /DOS2 /I$(WATCOM)\\h ; # zq=quiet
+ C++ ?= wpp386 ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= wcl386 ;
+ LINKFLAGS ?= /zq ; # zq=quiet
+ LINKLIBS ?= ;
+ NOARSCAN ?= true ;
+ OPTIM ?= ;
+ SLASH ?= \\ ;
+ STDHDRS ?= $(WATCOM)\\h ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = EMX
+ {
+ ECHO "Compiler is GCC-EMX" ;
+ AR ?= ar -ru ;
+ CC ?= gcc ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= "" ;
+ OPTIM ?= ;
+ SUFOBJ = .o ;
+ SUFLIB = .a ;
+ UNDEFFLAG ?= "-U" ;
+ SLASH = / ;
+# NOARSCAN ?= true ;
+ }
+ else
+ {
+ # should never happen
+ EXIT "Sorry, but the $(JAM_TOOLSET) toolset isn't supported for now" ;
+ }
+}
+else if $(VMS)
+{
+ C++ ?= cxx ;
+ C++FLAGS ?= ;
+ CC ?= cc ;
+ CCFLAGS ?= ;
+ CHMOD ?= set file/prot= ;
+ CP ?= copy/replace ;
+ CRELIB ?= true ;
+ DOT ?= [] ;
+ DOTDOT ?= [-] ;
+ EXEMODE ?= (w:e) ;
+ FILEMODE ?= (w:r) ;
+ HDRS ?= ;
+ LINK ?= link ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= ;
+ MKDIR ?= create/dir ;
+ MV ?= rename ;
+ OPTIM ?= "" ;
+ RM ?= delete ;
+ RUNVMS ?= mcr ;
+ SHELLMODE ?= (w:er) ;
+ SLASH ?= . ;
+ STDHDRS ?= decc$library_include ;
+ SUFEXE ?= .exe ;
+ SUFLIB ?= .olb ;
+ SUFOBJ ?= .obj ;
+
+ switch $(OS)
+ {
+ case OPENVMS : CCFLAGS ?= /stand=vaxc ;
+ case VMS : LINKLIBS ?= sys$library:vaxcrtl.olb/lib ;
+ }
+}
+else if $(MAC)
+{
+ local OPT ;
+
+ CW ?= "{CW}" ;
+
+ MACHDRS ?=
+ "$(UMACHDRS):Universal:Interfaces:CIncludes"
+ "$(CW):MSL:MSL_C:MSL_Common:Include"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Include" ;
+
+ MACLIBS ?=
+ "$(CW):MacOS Support:Universal:Libraries:StubLibraries:Interfacelib"
+ "$(CW):MacOS Support:Universal:Libraries:StubLibraries:Mathlib" ;
+
+ MPWLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib" ;
+
+ MPWNLLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW(NL).Lib" ;
+
+ SIOUXHDRS ?= ;
+
+ SIOUXLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL SIOUX.PPC.Lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC.Lib" ;
+
+ C++ ?= mwcppc ;
+ C++FLAGS ?= -w off -nomapcr ;
+ CC ?= mwcppc ;
+ CCFLAGS ?= -w off -nomapcr ;
+ CP ?= duplicate -y ;
+ DOT ?= ":" ;
+ DOTDOT ?= "::" ;
+ HDRS ?= $(MACHDRS) $(MPWHDRS) ;
+ LINK ?= mwlinkppc ;
+ LINKFLAGS ?= -mpwtool -warn ;
+ LINKLIBS ?= $(MACLIBS) $(MPWLIBS) ;
+ MKDIR ?= newfolder ;
+ MV ?= rename -y ;
+ NOARSCAN ?= true ;
+ OPTIM ?= ;
+ RM ?= delete -y ;
+ SLASH ?= ":" ;
+ STDHDRS ?= ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .o ;
+}
+else if $(OS) = BEOS && $(METROWERKS)
+{
+ AR ?= mwld -xml -o ;
+ BINDIR ?= /boot/apps ;
+ CC ?= mwcc ;
+ CCFLAGS ?= -nosyspath ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= -nosyspath ;
+ FORTRAN ?= "" ;
+ LIBDIR ?= /boot/develop/libraries ;
+ LINK ?= mwld ;
+ LINKFLAGS ?= "" ;
+ MANDIR ?= /boot/documentation/"Shell Tools"/HTML ;
+ NOARSCAN ?= true ;
+ STDHDRS ?= /boot/develop/headers/posix ;
+}
+else if $(OS) = BEOS
+{
+ BINDIR ?= /boot/apps ;
+ CC ?= gcc ;
+ C++ ?= $(CC) ;
+ FORTRAN ?= "" ;
+ LIBDIR ?= /boot/develop/libraries ;
+ LINK ?= gcc ;
+ LINKLIBS ?= -lnet ;
+ NOARSCAN ?= true ;
+ STDHDRS ?= /boot/develop/headers/posix ;
+}
+else if $(UNIX)
+{
+ switch $(OS)
+ {
+ case AIX :
+ LINKLIBS ?= -lbsd ;
+
+ case AMIGA :
+ CC ?= gcc ;
+ YACC ?= bison ;
+
+ case CYGWIN :
+ CC ?= gcc ;
+ CCFLAGS += -D__cygwin__ ;
+ LEX ?= flex ;
+ JAMSHELL ?= sh -c ;
+ RANLIB ?= "" ;
+ SUFEXE ?= .exe ;
+ YACC ?= bison ;
+
+ case DGUX :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+
+ case HPUX :
+ RANLIB ?= "" ;
+
+ case INTERIX :
+ CC ?= gcc ;
+ JAMSHELL ?= sh -c ;
+ RANLIB ?= "" ;
+
+ case IRIX :
+ RANLIB ?= "" ;
+
+ case MPEIX :
+ CC ?= gcc ;
+ C++ ?= gcc ;
+ CCFLAGS += -D_POSIX_SOURCE ;
+ HDRS += /usr/include ;
+ RANLIB ?= "" ;
+ NOARSCAN ?= true ;
+ NOARUPDATE ?= true ;
+
+ case MVS :
+ RANLIB ?= "" ;
+
+ case NEXT :
+ AR ?= libtool -o ;
+ RANLIB ?= "" ;
+
+ case MACOSX :
+ AR ?= libtool -o ;
+ C++ ?= c++ ;
+ MANDIR ?= /usr/local/share/man ;
+ RANLIB ?= "" ;
+
+ case NCR :
+ RANLIB ?= "" ;
+
+ case PTX :
+ RANLIB ?= "" ;
+
+ case QNX :
+ AR ?= wlib ;
+ CC ?= cc ;
+ CCFLAGS ?= -Q ; # quiet
+ C++ ?= $(CC) ;
+ C++FLAGS ?= -Q ; # quiet
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= -Q ; # quiet
+ NOARSCAN ?= true ;
+ RANLIB ?= "" ;
+
+ case SCO :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+
+ case SINIX :
+ RANLIB ?= "" ;
+
+ case SOLARIS :
+ RANLIB ?= "" ;
+ AR ?= "/usr/ccs/bin/ar ru" ;
+
+ case UNICOS :
+ NOARSCAN ?= true ;
+ OPTIM ?= -O0 ;
+
+ case UNIXWARE :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+ }
+
+ # UNIX defaults
+
+ CCFLAGS ?= ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ CHMOD ?= chmod ;
+ LEX ?= lex ;
+ LINKFLAGS ?= $(CCFLAGS) ;
+ LINKLIBS ?= ;
+ OPTIM ?= -O ;
+ RANLIB ?= ranlib ;
+ YACC ?= yacc ;
+ YACCFILES ?= y.tab ;
+ YACCFLAGS ?= -d ;
+}
+
+#
+# General defaults; a lot like UNIX
+#
+
+ AR ?= ar ru ;
+ AS ?= as ;
+ ASFLAGS ?= ;
+ AWK ?= awk ;
+ BINDIR ?= /usr/local/bin ;
+ C++ ?= cc ;
+ C++FLAGS ?= ;
+ CC ?= cc ;
+ CCFLAGS ?= ;
+ CP ?= cp -f ;
+ CRELIB ?= ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ EXEMODE ?= 711 ;
+ FILEMODE ?= 644 ;
+ FORTRAN ?= f77 ;
+ FORTRANFLAGS ?= ;
+ HDRS ?= ;
+ JAMFILE ?= Jamfile ;
+ JAMRULES ?= Jamrules ;
+ LEX ?= ;
+ LIBDIR ?= /usr/local/lib ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= ;
+ LINKLIBS ?= ;
+ LN ?= ln ;
+ MANDIR ?= /usr/local/man ;
+ MKDIR ?= mkdir ;
+ MV ?= mv -f ;
+ OPTIM ?= ;
+ RCP ?= rcp ;
+ RM ?= rm -f ;
+ RSH ?= rsh ;
+ SED ?= sed ;
+ SHELLHEADER ?= "#!/bin/sh" ;
+ SHELLMODE ?= 755 ;
+ SLASH ?= / ;
+ STDHDRS ?= /usr/include ;
+ SUFEXE ?= "" ;
+ SUFLIB ?= .a ;
+ SUFOBJ ?= .o ;
+ UNDEFFLAG ?= "-u _" ;
+ YACC ?= ;
+ YACCFILES ?= ;
+ YACCFLAGS ?= ;
+
+ HDRPATTERN =
+ "^[ ]*#[ ]*include[ ]*[<\"]([^\">]*)[\">].*$" ;
+
+ OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;
+
+
+#
+# Base dependencies - first for "bootstrap" kinds of rules
+#
+
+DEPENDS all : shell files lib exe obj ;
+DEPENDS all shell files lib exe obj : first ;
+NOTFILE all first shell files lib exe obj dirs clean uninstall ;
+ALWAYS clean uninstall ;
+
+#
+# Rules
+#
+
+rule As
+{
+ DEPENDS $(<) : $(>) ;
+ ASFLAGS on $(<) += $(ASFLAGS) $(SUBDIRASFLAGS) ;
+}
+
+rule Bulk
+{
+ local i ;
+
+ for i in $(>)
+ {
+ File $(i:D=$(<)) : $(i) ;
+ }
+}
+
+rule Cc
+{
+ local _h ;
+
+ DEPENDS $(<) : $(>) ;
+
+ # Just to clarify here: this sets the per-target CCFLAGS to
+ # be the current value of (global) CCFLAGS and SUBDIRCCFLAGS.
+
+ CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) ;
+
+ # If the compiler's -o flag doesn't work, relocate the .o
+
+ if $(RELOCATE)
+ {
+ CcMv $(<) : $(>) ;
+ }
+
+ _h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;
+
+ if $(VMS) && $(_h)
+ {
+ SLASHINC on $(<) = "/inc=(" $(_h[1]) ,$(_h[2-]) ")" ;
+ }
+ else if $(MAC) && $(_h)
+ {
+ local _i _j ;
+ _j = $(_h[1]) ;
+ for _i in $(_h[2-])
+ {
+ _j = $(_j),$(_i) ;
+ }
+ MACINC on $(<) = \"$(_j)\" ;
+ }
+}
+
+rule C++
+{
+ local _h ;
+
+ DEPENDS $(<) : $(>) ;
+ C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) ;
+
+ if $(RELOCATE)
+ {
+ CcMv $(<) : $(>) ;
+ }
+
+ _h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;
+
+ if $(VMS) && $(_h)
+ {
+ SLASHINC on $(<) = "/inc=(" $(_h[1]) ,$(_h[2-]) ")" ;
+ }
+ else if $(MAC) && $(_h)
+ {
+ local _i _j ;
+ _j = $(_h[1]) ;
+ for _i in $(_h[2-])
+ {
+ _j = $(_j),$(_i) ;
+ }
+ MACINC on $(<) = \"$(_j)\" ;
+ }
+}
+
+rule Chmod
+{
+ if $(CHMOD) { Chmod1 $(<) ; }
+}
+
+rule File
+{
+ DEPENDS files : $(<) ;
+ DEPENDS $(<) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+ MODE on $(<) = $(FILEMODE) ;
+ Chmod $(<) ;
+}
+
+rule Fortran
+{
+ DEPENDS $(<) : $(>) ;
+}
+
+rule GenFile
+{
+ local _t = [ FGristSourceFiles $(<) ] ;
+ local _s = [ FAppendSuffix $(>[1]) : $(SUFEXE) ] ;
+ Depends $(_t) : $(_s) $(>[2-]) ;
+ GenFile1 $(_t) : $(_s) $(>[2-]) ;
+ Clean clean : $(_t) ;
+}
+
+rule GenFile1
+{
+ MakeLocate $(<) : $(LOCATE_SOURCE) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+}
+
+rule HardLink
+{
+ DEPENDS files : $(<) ;
+ DEPENDS $(<) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+}
+
+rule HdrMacroFile
+{
+ # HdrMacroFile file ;
+ #
+ # this rule is used to indicate that a given file contains definitions
+ # for filename macros (e.g. "#define MYFILE_H ") that can
+ # later be used in #include statements in the rest of the source
+ #
+ # theses files must be parsed before any make is tried..
+ #
+ HDRMACRO $(<) ;
+}
+
+rule HdrRule
+{
+ # HdrRule source : headers ;
+
+ # N.B. This rule is called during binding, potentially after
+ # the fate of many targets has been determined, and must be
+ # used with caution: don't add dependencies to unrelated
+ # targets, and don't set variables on $(<).
+
+ # Tell Jam that anything depending on $(<) also depends on $(>),
+ # set SEARCH so Jam can find the headers, but then say we don't
+ # care if we can't actually find the headers (they may have been
+ # within ifdefs),
+
+ local s ;
+
+ if $(HDRGRIST)
+ {
+ s = $(>:G=$(HDRGRIST)) ;
+ } else {
+ s = $(>) ;
+ }
+
+ INCLUDES $(<) : $(s) ;
+ SEARCH on $(s) = $(HDRSEARCH) ;
+ NOCARE $(s) ;
+
+ # Propagate on $(<) to $(>)
+
+ HDRSEARCH on $(s) = $(HDRSEARCH) ;
+ HDRSCAN on $(s) = $(HDRSCAN) ;
+ HDRRULE on $(s) = $(HDRRULE) ;
+ HDRGRIST on $(s) = $(HDRGRIST) ;
+}
+
+rule InstallInto
+{
+ local i t ;
+
+ t = $(>:G=installed) ;
+
+ DEPENDS install : $(t) ;
+ DEPENDS $(t) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+ MakeLocate $(t) : $(<) ;
+
+ # Arrange for jam uninstall
+
+ Clean uninstall : $(t) ;
+
+ for i in $(>)
+ {
+ Install $(i:G=installed) : $(i) ;
+ }
+
+ Chmod $(t) ;
+
+ if $(UNIX)
+ {
+ if $(OWNER) { Chown $(t) ; OWNER on $(t) = $(OWNER) ; }
+ if $(GROUP) { Chgrp $(t) ; GROUP on $(t) = $(GROUP) ; }
+ }
+}
+
+rule InstallBin
+{
+ local _t = [ FAppendSuffix $(>) : $(SUFEXE) ] ;
+
+ InstallInto $(<) : $(_t) ;
+ MODE on $(_t:G=installed) = $(EXEMODE) ;
+}
+
+rule InstallFile
+{
+ InstallInto $(<) : $(>) ;
+ MODE on $(>:G=installed) = $(FILEMODE) ;
+}
+
+rule InstallLib
+{
+ InstallInto $(<) : $(>) ;
+ MODE on $(>:G=installed) = $(FILEMODE) ;
+}
+
+rule InstallMan
+{
+ # Really this just strips the . from the suffix
+
+ local i s d ;
+
+ for i in $(>)
+ {
+ switch $(i:S)
+ {
+ case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;
+ case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;
+ case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;
+ case .n : s = n ; case .man : s = 1 ;
+ }
+
+ d = man$(s) ;
+
+ InstallInto $(d:R=$(<)) : $(i) ;
+ }
+
+ MODE on $(>:G=installed) = $(FILEMODE) ;
+}
+
+rule InstallShell
+{
+ InstallInto $(<) : $(>) ;
+ MODE on $(>:G=installed) = $(SHELLMODE) ;
+}
+
+rule Lex
+{
+ LexMv $(<) : $(>) ;
+ DEPENDS $(<) : $(>) ;
+ MakeLocate $(<) : $(LOCATE_SOURCE) ;
+ Clean clean : $(<) ;
+}
+
+rule Library
+{
+ LibraryFromObjects $(<) : $(>:S=$(SUFOBJ)) ;
+ Objects $(>) ;
+}
+
+rule LibraryFromObjects
+{
+ local _i _l _s ;
+
+ # Add grist to file names
+
+ _s = [ FGristFiles $(>) ] ;
+ _l = $(<:S=$(SUFLIB)) ;
+
+ # library depends on its member objects
+
+ if $(KEEPOBJS)
+ {
+ DEPENDS obj : $(_s) ;
+ }
+ else
+ {
+ DEPENDS lib : $(_l) ;
+ }
+
+ # Set LOCATE for the library and its contents. The bound
+ # value shows up as $(NEEDLIBS) on the Link actions.
+ # For compatibility, we only do this if the library doesn't
+ # already have a path.
+
+ if ! $(_l:D)
+ {
+ MakeLocate $(_l) $(_l)($(_s:BS)) : $(LOCATE_TARGET) ;
+ }
+
+ if $(NOARSCAN)
+ {
+ # If we can't scan the library to timestamp its contents,
+ # we have to just make the library depend directly on the
+ # on-disk object files.
+
+ DEPENDS $(_l) : $(_s) ;
+ }
+ else
+ {
+ # If we can scan the library, we make the library depend
+ # on its members and each member depend on the on-disk
+ # object file.
+
+ DEPENDS $(_l) : $(_l)($(_s:BS)) ;
+
+ for _i in $(_s)
+ {
+ DEPENDS $(_l)($(_i:BS)) : $(_i) ;
+ }
+ }
+
+ Clean clean : $(_l) ;
+
+ if $(CRELIB) { CreLib $(_l) : $(_s[1]) ; }
+
+ Archive $(_l) : $(_s) ;
+
+ if $(RANLIB) { Ranlib $(_l) ; }
+
+ # If we can't scan the library, we have to leave the .o's around.
+
+ if ! ( $(NOARSCAN) || $(KEEPOBJS) ) { RmTemps $(_l) : $(_s) ; }
+}
+
+rule Link
+{
+ MODE on $(<) = $(EXEMODE) ;
+ Chmod $(<) ;
+}
+
+rule LinkLibraries
+{
+ # make library dependencies of target
+ # set NEEDLIBS variable used by 'actions Main'
+
+ local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
+
+ DEPENDS $(_t) : $(>:S=$(SUFLIB)) ;
+ NEEDLIBS on $(_t) += $(>:S=$(SUFLIB)) ;
+}
+
+rule Main
+{
+ MainFromObjects $(<) : $(>:S=$(SUFOBJ)) ;
+ Objects $(>) ;
+}
+
+rule MainFromObjects
+{
+ local _s _t ;
+
+ # Add grist to file names
+ # Add suffix to exe
+
+ _s = [ FGristFiles $(>) ] ;
+ _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
+
+ if $(_t) != $(<)
+ {
+ DEPENDS $(<) : $(_t) ;
+ NOTFILE $(<) ;
+ }
+
+ # make compiled sources a dependency of target
+
+ DEPENDS exe : $(_t) ;
+ DEPENDS $(_t) : $(_s) ;
+ MakeLocate $(_t) : $(LOCATE_TARGET) ;
+
+ Clean clean : $(_t) ;
+
+ Link $(_t) : $(_s) ;
+}
+
+rule MakeLocate
+{
+ if $(>)
+ {
+ LOCATE on $(<) = $(>) ;
+ Depends $(<) : $(>[1]) ;
+ MkDir $(>[1]) ;
+ }
+}
+
+rule MkDir
+{
+ # If dir exists, don't update it
+ # Do this even for $(DOT).
+
+ NOUPDATE $(<) ;
+
+ if $(<) != $(DOT) && ! $($(<)-mkdir)
+ {
+ local s ;
+
+ # Cheesy gate to prevent multiple invocations on same dir
+ # MkDir1 has the actions
+ # Arrange for jam dirs
+
+ $(<)-mkdir = true ;
+ MkDir1 $(<) ;
+ Depends dirs : $(<) ;
+
+ # Recursively make parent directories.
+ # $(<:P) = $(<)'s parent, & we recurse until root
+
+ s = $(<:P) ;
+
+ if $(NT)
+ {
+ switch $(s)
+ {
+ case *: : s = ;
+ case *:\\ : s = ;
+ }
+ }
+
+ if $(s) && $(s) != $(<)
+ {
+ Depends $(<) : $(s) ;
+ MkDir $(s) ;
+ }
+ else if $(s)
+ {
+ NOTFILE $(s) ;
+ }
+
+ }
+}
+
+rule Object
+{
+ local h ;
+
+ # locate object and search for source, if wanted
+
+ Clean clean : $(<) ;
+
+ MakeLocate $(<) : $(LOCATE_TARGET) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+
+ # Save HDRS for -I$(HDRS) on compile.
+ # We shouldn't need -I$(SEARCH_SOURCE) as cc can find headers
+ # in the .c file's directory, but generated .c files (from
+ # yacc, lex, etc) are located in $(LOCATE_TARGET), possibly
+ # different from $(SEARCH_SOURCE).
+
+ HDRS on $(<) = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;
+
+ # handle #includes for source: Jam scans for headers with
+ # the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
+ # with the scanned file as the target and the found headers
+ # as the sources. HDRSEARCH is the value of SEARCH used for
+ # the found header files. Finally, if jam must deal with
+ # header files of the same name in different directories,
+ # they can be distinguished with HDRGRIST.
+
+ # $(h) is where cc first looks for #include "foo.h" files.
+ # If the source file is in a distant directory, look there.
+ # Else, look in "" (the current directory).
+
+ if $(SEARCH_SOURCE)
+ {
+ h = $(SEARCH_SOURCE) ;
+ }
+ else
+ {
+ h = "" ;
+ }
+
+ HDRRULE on $(>) = HdrRule ;
+ HDRSCAN on $(>) = $(HDRPATTERN) ;
+ HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(h) $(STDHDRS) ;
+ HDRGRIST on $(>) = $(HDRGRIST) ;
+
+ # if source is not .c, generate .c with specific rule
+
+ switch $(>:S)
+ {
+ case .asm : As $(<) : $(>) ;
+ case .c : Cc $(<) : $(>) ;
+ case .C : C++ $(<) : $(>) ;
+ case .cc : C++ $(<) : $(>) ;
+ case .cpp : C++ $(<) : $(>) ;
+ case .f : Fortran $(<) : $(>) ;
+ case .l : Cc $(<) : $(<:S=.c) ;
+ Lex $(<:S=.c) : $(>) ;
+ case .s : As $(<) : $(>) ;
+ case .y : Cc $(<) : $(<:S=.c) ;
+ Yacc $(<:S=.c) : $(>) ;
+ case * : UserObject $(<) : $(>) ;
+ }
+}
+
+
+rule ObjectCcFlags
+{
+ CCFLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;
+}
+
+rule ObjectC++Flags
+{
+ C++FLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;
+}
+
+rule ObjectHdrs
+{
+ HDRS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;
+}
+
+rule Objects
+{
+ local _i ;
+
+ for _i in [ FGristFiles $(<) ]
+ {
+ Object $(_i:S=$(SUFOBJ)) : $(_i) ;
+ DEPENDS obj : $(_i:S=$(SUFOBJ)) ;
+ }
+}
+
+rule RmTemps
+{
+ TEMPORARY $(>) ;
+}
+
+rule Setuid
+{
+ MODE on [ FAppendSuffix $(<) : $(SUFEXE) ] = 4711 ;
+}
+
+rule Shell
+{
+ DEPENDS shell : $(<) ;
+ DEPENDS $(<) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+ MODE on $(<) = $(SHELLMODE) ;
+ Clean clean : $(<) ;
+ Chmod $(<) ;
+}
+
+rule SubDir
+{
+ local _r _s ;
+
+ #
+ # SubDir TOP d1 [ ... ]
+ #
+ # This introduces a Jamfile that is part of a project tree
+ # rooted at $(TOP). It (only once) includes the project-specific
+ # rules file $(TOP)/Jamrules and then sets search & locate stuff.
+ #
+ # If the variable $(TOPRULES) is set (where TOP is the first arg
+ # to SubDir), that file is included instead of $(TOP)/Jamrules.
+ #
+ # d1 ... are the directory elements that lead to this directory
+ # from $(TOP). We construct the system dependent path from these
+ # directory elements in order to set search&locate stuff.
+ #
+
+ if ! $($(<[1]))
+ {
+ if ! $(<[1])
+ {
+ EXIT SubDir syntax error ;
+ }
+
+ $(<[1]) = [ FSubDir $(<[2-]) ] ;
+ }
+
+ #
+ # If $(TOP)/Jamrules hasn't been included, do so.
+ #
+
+ if ! $($(<[1])-included)
+ {
+ # Gated entry.
+
+ $(<[1])-included = TRUE ;
+
+ # File is $(TOPRULES) or $(TOP)/Jamrules.
+
+ _r = $($(<[1])RULES) ;
+
+ if ! $(_r)
+ {
+ _r = $(JAMRULES:R=$($(<[1]))) ;
+ }
+
+ # Include it.
+
+ include $(_r) ;
+ }
+
+ # Get path to current directory from root using SubDir.
+ # Save dir tokens for other potential uses.
+
+ _s = [ FDirName $(<[2-]) ] ;
+ SUBDIR = $(_s:R=$($(<[1]))) ;
+ SUBDIR_TOKENS = $(<[2-]) ;
+
+ # Now set up SEARCH_SOURCE, LOCATE_TARGET, SOURCE_GRIST
+ # These can be reset if needed. For example, if the source
+ # directory should not hold object files, LOCATE_TARGET can
+ # subsequently be redefined.
+
+ SEARCH_SOURCE = $(SUBDIR) ;
+ LOCATE_SOURCE = $(ALL_LOCATE_TARGET) $(SUBDIR) ;
+ LOCATE_TARGET = $(ALL_LOCATE_TARGET) $(SUBDIR) ;
+ SOURCE_GRIST = [ FGrist $(<[2-]) ] ;
+
+ # Reset per-directory ccflags, hdrs
+
+ SUBDIRCCFLAGS = ;
+ SUBDIRC++FLAGS = ;
+ SUBDIRHDRS = ;
+}
+
+rule SubDirCcFlags
+{
+ SUBDIRCCFLAGS += $(<) ;
+}
+
+rule SubDirC++Flags
+{
+ SUBDIRC++FLAGS += $(<) ;
+}
+
+rule SubDirHdrs
+{
+ SUBDIRHDRS += $(<) ;
+}
+
+rule SubInclude
+{
+ local _s ;
+
+ # That's
+ # SubInclude TOP d1 [ d2 [ d3 [ d4 ] ] ]
+ #
+ # to include a subdirectory's Jamfile.
+
+ if ! $($(<[1]))
+ {
+ EXIT Top level of source tree has not been set with $(<[1]) ;
+ }
+
+ _s = [ FDirName $(<[2-]) ] ;
+
+ include $(JAMFILE:D=$(_s):R=$($(<[1]))) ;
+}
+
+rule Undefines
+{
+ UNDEFS on [ FAppendSuffix $(<) : $(SUFEXE) ] += $(UNDEFFLAG)$(>) ;
+}
+
+rule UserObject
+{
+ EXIT "Unknown suffix on" $(>) "- see UserObject rule in Jamfile(5)." ;
+}
+
+rule Yacc
+{
+ local _h ;
+
+ _h = $(<:BS=.h) ;
+
+ # Some places don't have a yacc.
+
+ MakeLocate $(<) $(_h) : $(LOCATE_SOURCE) ;
+
+ if $(YACC)
+ {
+ DEPENDS $(<) $(_h) : $(>) ;
+ Yacc1 $(<) $(_h) : $(>) ;
+ YaccMv $(<) $(_h) : $(>) ;
+ Clean clean : $(<) $(_h) ;
+ }
+
+ # make sure someone includes $(_h) else it will be
+ # a deadly independent target
+
+ INCLUDES $(<) : $(_h) ;
+}
+
+#
+# Utility rules; no side effects on these
+#
+
+rule FGrist
+{
+ # Turn individual elements in $(<) into grist.
+
+ local _g _i ;
+
+ _g = $(<[1]) ;
+
+ for _i in $(<[2-])
+ {
+ _g = $(_g)!$(_i) ;
+ }
+
+ return $(_g) ;
+}
+
+rule FGristFiles
+{
+ if ! $(SOURCE_GRIST)
+ {
+ return $(<) ;
+ }
+ else
+ {
+ return $(<:G=$(SOURCE_GRIST)) ;
+ }
+}
+
+rule FGristSourceFiles
+{
+ # Produce source file name name with grist in it,
+ # if SOURCE_GRIST is set.
+
+ # Leave header files alone, because they have a global
+ # visibility.
+
+ if ! $(SOURCE_GRIST)
+ {
+ return $(<) ;
+ }
+ else
+ {
+ local _i _o ;
+
+ for _i in $(<)
+ {
+ switch $(_i)
+ {
+ case *.h : _o += $(_i) ;
+ case * : _o += $(_i:G=$(SOURCE_GRIST)) ;
+ }
+ }
+
+ return $(_o) ;
+ }
+}
+
+rule FConcat
+{
+ # Puts the variables together, removing spaces.
+
+ local _t _r ;
+
+ $(_r) = $(<[1]) ;
+
+ for _t in $(<[2-])
+ {
+ $(_r) = $(_r)$(_t) ;
+ }
+
+ return $(_r) ;
+}
+
+rule FSubDir
+{
+ local _i _d ;
+
+ # If $(>) is the path to the current directory, compute the
+ # path (using ../../ etc) back to that root directory.
+ # Sets result in $(<)
+
+ if ! $(<[1])
+ {
+ _d = $(DOT) ;
+ }
+ else
+ {
+ _d = $(DOTDOT) ;
+
+ for _i in $(<[2-])
+ {
+ _d = $(_d:R=$(DOTDOT)) ;
+ }
+ }
+
+ return $(_d) ;
+}
+
+rule FDirName
+{
+ local _s _i ;
+
+ # Turn individual elements in $(<) into a usable path.
+
+ if ! $(<)
+ {
+ _s = $(DOT) ;
+ }
+ else if $(VMS)
+ {
+ # This handles the following cases:
+ # a -> [.a]
+ # a b c -> [.a.b.c]
+ # x: -> x:
+ # x: a -> x:[a]
+ # x:[a] b -> x:[a.b]
+
+ switch $(<[1])
+ {
+ case *:* : _s = $(<[1]) ;
+ case \\[*\\] : _s = $(<[1]) ;
+ case * : _s = [.$(<[1])] ;
+ }
+
+ for _i in [.$(<[2-])]
+ {
+ _s = $(_i:R=$(_s)) ;
+ }
+ }
+ else if $(MAC)
+ {
+ _s = $(DOT) ;
+
+ for _i in $(<)
+ {
+ _s = $(_i:R=$(_s)) ;
+ }
+ }
+ else
+ {
+ _s = $(<[1]) ;
+
+ for _i in $(<[2-])
+ {
+ _s = $(_i:R=$(_s)) ;
+ }
+ }
+
+ return $(_s) ;
+}
+
+
+rule _makeCommon
+{
+ # strip common initial elements
+
+ if $($(<)[1]) && $($(<)[1]) = $($(>)[1])
+ {
+ $(<) = $($(<)[2-]) ;
+ $(>) = $($(>)[2-]) ;
+ _makeCommon $(<) : $(>) ;
+ }
+}
+
+
+rule FRelPath
+{
+ local _l _r ;
+
+ # first strip off common parts
+
+ _l = $(<) ;
+ _r = $(>) ;
+
+ _makeCommon _l : _r ;
+
+ # now make path to root and path down
+
+ _l = [ FSubDir $(_l) ] ;
+ _r = [ FDirName $(_r) ] ;
+
+ # Concatenate and save
+
+ # XXX This should be better
+
+ if $(_r) = $(DOT) {
+ return $(_l) ;
+ } else {
+ return $(_r:R=$(_l)) ;
+ }
+}
+
+rule FAppendSuffix
+{
+ # E.g., "FAppendSuffix yacc lex foo.bat : $(SUFEXE) ;"
+ # returns (yacc,lex,foo.bat) on Unix and
+ # (yacc.exe,lex.exe,foo.bat) on NT.
+
+ if $(>)
+ {
+ local _i _o ;
+
+ for _i in $(<)
+ {
+ if $(_i:S)
+ {
+ _o += $(_i) ;
+ }
+ else
+ {
+ _o += $(_i:S=$(>)) ;
+ }
+ }
+ return $(_o) ;
+ }
+ else
+ {
+ return $(<) ;
+ }
+}
+
+rule unmakeDir
+{
+ if $(>[1]:D) && $(>[1]:D) != $(>[1]) && $(>[1]:D) != \\\\
+ {
+ unmakeDir $(<) : $(>[1]:D) $(>[1]:BS) $(>[2-]) ;
+ }
+ else
+ {
+ $(<) = $(>) ;
+ }
+}
+
+
+rule FConvertToSlashes
+{
+ local _d, _s, _i ;
+
+ unmakeDir _d : $(<) ;
+
+ _s = $(_d[1]) ;
+ for _i in $(_d[2-])
+ {
+ _s = $(_s)/$(_i) ;
+ }
+ return $(_s) ;
+}
+
+
+#
+# Actions
+#
+
+#
+# First the defaults
+#
+
+actions updated together piecemeal Archive
+{
+ $(AR) $(<) $(>)
+}
+
+actions As
+{
+ $(AS) $(ASFLAGS) -I$(HDRS) -o $(<) $(>)
+}
+
+actions C++
+{
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
+}
+
+actions Cc
+{
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
+}
+
+actions Chgrp
+{
+ chgrp $(GROUP) $(<)
+}
+
+actions Chmod1
+{
+ $(CHMOD) $(MODE) $(<)
+}
+
+actions Chown
+{
+ chown $(OWNER) $(<)
+}
+
+actions piecemeal together existing Clean
+{
+ $(RM) $(>)
+}
+
+actions File
+{
+ $(CP) $(>) $(<)
+}
+
+actions GenFile1
+{
+ $(>[1]) $(<) $(>[2-])
+}
+
+actions Fortran
+{
+ $(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)
+}
+
+actions HardLink
+{
+ $(RM) $(<) && $(LN) $(>) $(<)
+}
+
+actions Install
+{
+ $(CP) $(>) $(<)
+}
+
+actions Lex
+{
+ $(LEX) $(>)
+}
+
+actions LexMv
+{
+ $(MV) lex.yy.c $(<)
+}
+
+actions Link bind NEEDLIBS
+{
+ $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+}
+
+actions MkDir1
+{
+ $(MKDIR) $(<)
+}
+
+actions together Ranlib
+{
+ $(RANLIB) $(<)
+}
+
+actions quietly updated piecemeal together RmTemps
+{
+ $(RM) $(>)
+}
+
+actions Shell
+{
+ $(AWK) '
+ NR == 1 { print "$(SHELLHEADER)" }
+ NR == 1 && /^[#:]/ { next }
+ /^##/ { next }
+ { print }
+ ' < $(>) > $(<)
+}
+
+actions Yacc1
+{
+ $(YACC) $(YACCFLAGS) $(>)
+}
+
+actions YaccMv
+{
+ $(MV) $(YACCFILES).c $(<[1])
+ $(MV) $(YACCFILES).h $(<[2])
+}
+
+#
+# RELOCATE - for compilers with broken -o flags
+#
+
+if $(RELOCATE)
+{
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) $(>)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) $(>)
+ }
+
+ actions ignore CcMv
+ {
+ [ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)
+ }
+}
+
+#
+# NOARUPDATE - can't update an archive
+#
+
+if $(NOARUPDATE)
+{
+ actions Archive
+ {
+ $(AR) $(<) $(>)
+ }
+}
+
+#
+# NT specific actions
+#
+
+if $(NT)
+{
+ if $(TOOLSET) = VISUALC || $(TOOLSET) = INTELC
+ {
+ actions updated together piecemeal Archive
+ {
+ if exist $(<) set _$(<:B)_=$(<)
+ $(AR) /out:$(<) %_$(<:B)_% $(>)
+ }
+
+ actions As
+ {
+ $(AS) /Ml /p /v /w2 $(>) $(<) ,nul,nul;
+ }
+
+ actions Cc
+ {
+ $(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) /Tp$(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+ }
+ else if $(TOOLSET) = VISUALC16
+ {
+ actions updated together piecemeal Archive
+ {
+ $(AR) $(<) -+$(>)
+ }
+
+ actions Cc
+ {
+ $(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /Tp$(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+ }
+ else if $(TOOLSET) = BORLANDC
+ {
+ actions updated together piecemeal Archive
+ {
+ $(AR) $(<) -+$(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) -e$(<) $(LINKFLAGS) $(UNDEFS) -L$(LINKLIBS) $(NEEDLIBS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ }
+ else if $(TOOLSET) = MINGW
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) $(>:T)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+ }
+ else if $(TOOLSET) = WATCOM
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) +-$(>)
+ }
+
+ actions Cc
+ {
+ $(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+ }
+ else if $(TOOLSET) = LCC
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) /out:$(<) $(>)
+ }
+
+ actions Cc
+ {
+ $(CC) $(CCFLAGS) $(OPTIM) -Fo$(<) -I$(HDRS) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+ }
+}
+
+#
+# OS2 specific actions
+#
+
+else if $(OS2)
+{
+ if $(TOOLSET) = WATCOM
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) +-$(>)
+ }
+
+ actions Cc
+ {
+ $(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+ }
+ else if $(TOOLSET) = EMX
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) $(>:T)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+ }
+}
+
+#
+# VMS specific actions
+#
+
+else if $(VMS)
+{
+ actions updated together piecemeal Archive
+ {
+ lib/replace $(<) $(>[1]) ,$(>[2-])
+ }
+
+ actions Cc
+ {
+ $(CC)/obj=$(<) $(CCFLAGS) $(OPTIM) $(SLASHINC) $(>)
+ }
+
+ actions C++
+ {
+ $(C++)/obj=$(<) $(C++FLAGS) $(OPTIM) $(SLASHINC) $(>)
+ }
+
+ actions piecemeal together existing Clean
+ {
+ $(RM) $(>[1]);* ,$(>[2-]);*
+ }
+
+ actions together quietly CreLib
+ {
+ if f$search("$(<)") .eqs. "" then lib/create $(<)
+ }
+
+ actions GenFile1
+ {
+ mcr $(>[1]) $(<) $(>[2-])
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK)/exe=$(<) $(LINKFLAGS) $(>[1]) ,$(>[2-]) ,$(NEEDLIBS)/lib ,$(LINKLIBS)
+ }
+
+ actions quietly updated piecemeal together RmTemps
+ {
+ $(RM) $(>[1]);* ,$(>[2-]);*
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+}
+
+#
+# Mac specifc actions
+#
+
+else if $(MAC)
+{
+ actions together Archive
+ {
+ $(LINK) -library -o $(<) $(>)
+ }
+
+ actions Cc
+ {
+ set -e MWCincludes $(MACINC)
+ $(CC) -o $(<) $(CCFLAGS) $(OPTIM) $(>)
+ }
+
+ actions C++
+ {
+ set -e MWCincludes $(MACINC)
+ $(CC) -o $(<) $(C++FLAGS) $(OPTIM) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) -o $(<) $(LINKFLAGS) $(>) $(NEEDLIBS) "$(LINKLIBS)"
+ }
+}
+
+#
+# Backwards compatibility with jam 1, where rules were uppercased.
+#
+
+rule BULK { Bulk $(<) : $(>) ; }
+rule FILE { File $(<) : $(>) ; }
+rule HDRRULE { HdrRule $(<) : $(>) ; }
+rule INSTALL { Install $(<) : $(>) ; }
+rule LIBRARY { Library $(<) : $(>) ; }
+rule LIBS { LinkLibraries $(<) : $(>) ; }
+rule LINK { Link $(<) : $(>) ; }
+rule MAIN { Main $(<) : $(>) ; }
+rule SETUID { Setuid $(<) ; }
+rule SHELL { Shell $(<) : $(>) ; }
+rule UNDEFINES { Undefines $(<) : $(>) ; }
+
+# Old INSTALL* didn't take dest directory.
+
+rule INSTALLBIN { InstallBin $(BINDIR) : $(<) ; }
+rule INSTALLLIB { InstallLib $(LIBDIR) : $(<) ; }
+rule INSTALLMAN { InstallMan $(MANDIR) : $(<) ; }
+
+# Compatibility with jam 2.2.
+
+rule addDirName { $(<) += [ FDirName $(>) ] ; }
+rule makeDirName { $(<) = [ FDirName $(>) ] ; }
+rule makeGristedName { $(<) = [ FGristSourceFiles $(>) ] ; }
+rule makeRelPath { $(<[1]) = [ FRelPath $(<[2-]) : $(>) ] ; }
+rule makeSuffixed { $(<[1]) = [ FAppendSuffix $(>) : $(<[2]) ] ; }
+
+#
+# Now include the user's Jamfile.
+#
+
+{
+ if $(JAMFILE) { include $(JAMFILE) ; }
+}
+
+}
\ No newline at end of file
diff --git a/historic/jam/src/Jambase.html b/historic/jam/src/Jambase.html
new file mode 100644
index 000000000..2c108f8fa
--- /dev/null
+++ b/historic/jam/src/Jambase.html
@@ -0,0 +1,881 @@
+
+
+Jambase Reference
+
+
+
+
+Jam/MR
+
+
+
+
+ Jambase is a base set of Jam/MR rules which
+ provide roughly make(1)-like functionality for
+ jam, the Jam/MR executable program.
+ This document, which started out as the Jambase(5) man page,
+ is a reference guide to the
+ rules,
+ pseudotargets,
+ and variables
+ defined in Jambase for use in Jamfiles.
+
+ For further information see:
+
+
+Jam/MR documentation and source are available from the
+Perforce Public Depot.
+For detailed information about any of the rules summarized below,
+see the
+Jambase
+file itself.
+
+
+
+ As obj.o : source.s ;
+
+ Assemble the file source.s. Called by the Object
+ rule.
+
+ Bulk directory : sources ;
+
+ Copies sources into directory.
+
+ Cc object : source ;
+
+ Compile the file source into object, using the C
+ compiler $(CC), its flags $(CCFLAGS) and $(OPTIM),
+ and the header file directories $(HDRS). Called by
+ the Object rule.
+
+ C++ obj.o : source.cc ;
+
+ Compile the C++ source file source.cc. Called by
+ the Object rule.
+
+ Chmod target ;
+
+ (Unix and VMS only.)
+ Change file permissions on target to
+ target-specific $(MODE) value set by Link, File,
+ Install*, and Shell rules.
+
+
+ Clean clean : targets ;
+
+ Removes existing targets when clean is built.
+ clean is not a dependency of all, and must be built
+ explicitly for targets to be removed.
+
+ File target : source ;
+
+ Copies source into target.
+
+ Fortran obj.o : source.f ;
+
+ Compile the Fortran source file source.f. Called
+ by the Object rule.
+
+
+ GenFile target : image sources ;
+
+ Runs the command "image target sources"
+ to create target from sources and
+ image. (where image is an
+ executable built by the Main rule.)
+
+ HardLink target : source ;
+
+ Makes target a hard link to source, if it isn't one
+ already. (Unix only.)
+
+ HdrRule source : headers ;
+
+ Arranges the proper dependencies when the file
+ source includes the files headers through the
+ "#include" C preprocessor directive.
+
+ This rule is not intended to be called explicitly.
+ It is called automatically during header scanning on
+ sources handled by the Object rule (e.g., sources in
+ Main or Library rules).
+
+ InstallBin dir : sources ;
+ Copy sources into dir with mode
+ $(EXEMODE).
+
+ InstallLib dir : sources ;
+ Copy sources into dir with mode
+ $(FILEMODE).
+
+ InstallMan dir : sources ;
+ Copy sources into the appropriate subdirectory
+ of dir with mode $(FILEMODE). The subdirectory
+ is mans, where s is the suffix of
+ each of sources.
+
+ InstallShell dir : sources ;
+ Copy sources into dir with mode
+ $(SHELLMODE).
+
+ Lex source.c : source.l ;
+ Process the lex(1) source file source.l and
+ rename the lex.yy.c to source.c. Called by
+ the Object rule.
+
+ Library library : sources ;
+ Compiles sources and archives them into
+ library. The intermediate objects
+ are deleted. Calls Objects and LibraryFromObjects.
+
+ If Library is invoked with no suffix on library,
+ the $(SUFLIB) suffix is used.
+
+ LibraryFromObjects library : objects ;
+
+ Archives objects into library. The
+ objects are then deleted.
+
+ If library has no suffix, the $(SUFLIB) suffix is used.
+
+ Link image : objects ;
+
+ Links image from objects and sets
+ permissions on image to $(EXEMODE).
+ Image must be actual filename; suffix is not
+ supplied.
+ Called by Main.
+
+
+ LinkLibraries image : libraries ;
+
+ Makes image depend on libraries and
+ includes them during the linking.
+
+ Image may be referenced without a suffix in this
+ rule invocation; LinkLibraries supplies the suffix.
+
+ Main image : sources ;
+
+ Compiles sources and links them into image.
+ Calls Objects and MainFromObjects.
+
+ Image may be referenced without a suffix in this
+ rule invocation; Main supplies the suffix.
+
+ MainFromObjects image : objects ;
+
+ Links objects into image. Dependency
+ of exe. MainFromObjects supplies the suffix on image
+ filename.
+
+ MakeLocate target : dir ;
+
+ Creates dir and causes target to be built
+ into dir.
+
+ MkDir dir ;
+
+ Creates dir and its parent directories.
+
+ Object object : source ;
+
+ Compiles a single source file source into
+ object. The Main and Library rules use
+ this rule to compile source files.
+
+ Causes source to be scanned for "#include"
+ directives and calls HdrRule to make all included
+ files dependedencies of object.
+
+ Calls one of the following rules to do the actual
+ compiling, depending on the suffix of source:
+
+ *.c: Cc
+ *.cc: C++
+ *.cpp: C++
+ *.C: C++
+ *.l: Lex
+ *.y: Yacc
+ *.*: UserObject
+
+
+ ObjectC++Flags source : flags ;
+
+ ObjectCcFlags source : flags ;
+
+ Add flags to the source-specific
+ value of $(CCFLAGS) or $(C++FLAGS) when compiling source.
+ Any file suffix on source is ignored.
+
+ ObjectHdrs source : dirs ;
+ Add dirs to the source-specific value of
+ $(HDRS) when scanning and compiling source.
+ Any file suffix on source is ignored.
+
+ Objects sources ;
+ For each source file in sources, calls
+ Object to compile the source file into a similarly
+ named object file.
+
+ RmTemps targets : sources ;
+ Marks sources as temporary with the TEMPORARY
+ rule, and deletes sources once targets
+ are built. Must be the last rule invoked on
+ targets. Used internally by LibraryFromObjects rule.
+
+ Setuid images ;
+ Sets the setuid bit on each of images after
+ linking. (Unix only.)
+
+
+ SubDir VAR d1 ... dn ;
+
+ Sets up housekeeping for the source files located
+ in $(VAR)/d1/.../dn:
+
+ - Reads in rules file associated with VAR,
+ if it hasn't already been read.
+
- Initializes variables for search paths,
+ output directories, compiler
+ flags, and grist, using d1 ... dn tokens.
+
+
+ VAR is the name of a variable;
+ d1 thru dn are elements
+ of a directory path.
+
+ SubDirC++Flags flags ;
+
+ SubDirCcFlags flags ;
+
+ Adds flags to the compiler flags for source files
+ in SubDir's directory.
+
+ SubDirHdrs paths ;
+
+ Adds paths to the header search paths for source files
+ in SubDir's directory.
+
+ SubInclude VAR d1 ... dn ;
+
+ Reads the Jamfile in $(VAR)/d1/.../dn/.
+
+ Shell image : source ;
+ Copies source into the executable sh(1)
+ script image. Ensures that the first line of
+ the script is $(SHELLHEADER) (default #!/bin/sh).
+
+ Undefines images : symbols ;
+ Adds flags to mark symbols as undefined
+ on link command for images.
+ Images may be referenced unsuffixed; the
+ Undefines rule supplies the suffix.
+
+ UserObject object : source ;
+ This rule is called by Object for source
+ files with unknown suffixes, and should be defined
+ in Jamrules
+ with a user-provided rule to handle the source file
+ types not handled by the Object rule.
+ The Jambase UserObject rule merely issues a
+ complaint when it encounters source with
+ files suffixes it does not recognize.
+
+ Yacc source.c : source.y ;
+ Process the yacc(1) file source.y and renamed
+ the resulting y.tab.c and y.tab.h to source.c.
+ Produces a y.tab.h and renames it to source.h.
+ Called by the Object rule.
+
+
+
+
+
+Jambase Pseudotargets
+
+
+
+There are two kinds of Jam targets: file targets and pseudotargets.
+File targets are objects that can be found in the filesystem.
+Pseudotargets are symbolic, and usually represent other targets.
+Most Jambase rules that define file targets also define pseudotargets
+which are dependent on types of file targets. The Jambase pseudotargets
+are:
+
+
+| exe
+ | Executables linked by the Main or MainFromObjects rules
+
+ |
| lib
+ | Libraries created by the Library or LibraryFromObjects rules
+
+ |
| obj
+ | Compiled objects used to create Main or Library targets
+
+ |
| dirs
+ | Directories where target files are written
+
+ |
| file
+ | Files copied by File and Bulk rules
+
+ |
| shell
+ | Files copied by Shell rule
+
+ |
| clean
+ | Removal of built targets (except files copied by Install* rules)
+
+ |
| install
+ | Files copied by Install* rules
+
+ |
| uninstall
+ | Removal of targets copied by Install* rules
+
+ |
+
+
+In addition, Jambase makes the jam default target "all"
+depend on "exe", "lib", "obj", "files", and "shell".
+
+
+
+
+
+Jambase Variables
+
+
+
+ Most of the following variables have default values for
+ each platform; refer to the Jambase file to see what those
+ defaults are.
+
+ ALL_LOCATE_TARGET
+
+ Alternative location of built targets. By default,
+ Jambase rules locate built targets in the source
+ tree. By setting $(ALL_LOCATE_TARGET)
+ in Jamrules, you can cause jam
+ to write built targets to a location outside
+ the source tree.
+
+
+ AR
+
+
+ The archive command used to update Library
+ and LibraryFromObjects targets.
+
+ AS
+
+ The assembler for As rule targets.
+
+
+ ASFLAGS
+
+
+ Flags handed to the assembler for As.
+
+
+ AWK
+
+
+ The name of awk interpreter, used when copying a
+ shell script for the Shell rule.
+
+
+ BCCROOT
+
+ Selects Borland compile and link actions on NT.
+
+
+
+ BINDIR
+
+
+ Not longer used.
+ (I.e., used only for backward compatibility with the
+ obsolete INSTALLBIN rule.)
+
+
+ CC
+
+
+ C compiler used for Cc rule targets.
+
+
+ CCFLAGS
+
+
+ Compile flags for Cc rule targets.
+ The Cc rule sets target-specific $(CCFLAGS)
+ values on its targets.
+
+
+ C++
+
+
+ C++ compiler used for C++ rule targets.
+
+
+ C++FLAGS
+
+
+ Compile flags for C++ rule targets.
+ The C++ rule sets target-specific $(C++FLAGS)
+ values on its targets.
+
+
+ CHMOD
+
+
+ Program (usually chmod(1)) used to set file
+ permissions for Chmod rule.
+
+
+ CP
+
+
+ The file copy program, used by File and Install* rules.
+
+
+ CRELIB
+
+
+ If set, causes the Library rule to invoke the CreLib
+ rule on the target library before attempting to archive
+ any members, so that the library can be created if
+ needed.
+
+
+ CW
+
+
+ On Macintosh, the root of the Code Warrior Pro 5 directory.
+
+
+ DOT
+
+
+ The operating system-specific name for the current directory.
+
+
+ DOTDOT
+
+
+ The operating system-specific name for the parent directory.
+
+
+ EXEMODE
+
+
+ Permissions for executables linked with Link, Main,
+ and MainFromObjects, on platforms with a Chmod action.
+
+
+ FILEMODE
+
+
+ Permissions for files copied by File or Bulk,
+ on platforms with a Chmod action.
+
+
+ FORTRAN
+
+
+ The Fortran compiler used by Fortran rule.
+
+
+ FORTRANFLAGS
+
+
+ Fortran compiler flags for Fortran rule targets.
+
+
+ GROUP
+
+
+ (Unix only.)
+ The group owner for Install* rule targets.
+
+
+ HDRGRIST
+
+
+ If set, used by the HdrRule to distinguish header files
+ with the same name in diffrent directories.
+
+
+ HDRPATTERN
+
+
+ A regular expression pattern that matches
+ C preprocessor "#include" directives in source files
+ and returns the name of the included file.
+
+
+ HDRRULE
+
+
+ Name of the rule to invoke with the results of header file
+ scanning. Default is "HdrRule".
+
+ This is a jam-special variable. If both HDRRULE and HDRSCAN
+ are set on a target,
+ that target will be scanned for lines
+ matching $(HDRSCAN), and $(HDDRULE) will be
+ invoked on included files found in the matching $(HDRSCAN) lines.
+
+
+ HDRS
+
+
+ Directories to be searched for header files.
+ This is used by the Object rule to:
+
+ - set up search paths for finding files returned
+ by header scans
+
- add -I flags on compile commands
+
+ (See STDHDRS.)
+
+
+ HDRSCAN
+
+
+ Regular expression pattern to use for header file
+ scanning. The Object rule sets this to $(HDRPATTERN).
+ This is a jam-special variable; see HDRRULE.
+
+
+ HDRSEARCH
+
+
+ Used by the HdrRule to fix the list of directories where
+ header files can be found for a given source file.
+
+
+ JAMFILE
+
+
+ Default is "Jamfile"; the name of the user-written
+ rules file found in each source directory.
+
+
+ JAMRULES
+
+
+ Default is "Jamrules"; the name of a rule definition
+ file to be read in at the first SubDir rule invocation.
+
+
+ KEEPOBJS
+
+
+ If set, tells the LibraryFromObjects rule not to delete
+ object files once they are archived.
+
+
+ LEX
+
+
+ The lex(1) command and flags.
+
+
+ LIBDIR
+
+
+ Not longer used.
+ (I.e., used only for backward compatibility with the
+ obsolete INSTALLLIB rule.)
+
+
+ LINK
+
+
+ The linker. Defaults to $(CC).
+
+
+ LINKFLAGS
+
+
+ Flags handed to the linker. Defaults to $(CCFLAGS).
+
+
+ LINKLIBS
+
+
+ List of external libraries to link with. The target image
+ does not depend on these libraries.
+
+
+ LN
+
+
+ The hard link command for HardLink rule.
+
+
+ LOCATE_SOURCE
+
+ Used to set the location of generated source files.
+ The Yacc, Lex, and GenFile rules set LOCATE on
+ their targets to $(LOCATE_SOURCE).
+ $(LOCATE_SOURCE) is initialized by the SubDir rule
+ to the source directory itself.
+ (Also, see ALL_LOCATE_TARGET.)
+
+
+ LOCATE_TARGET
+
+ Used to set the location of built binary targets.
+ The Object rule, and hence the Main and Library rules,
+ set LOCATE on their targets to $(LOCATE_TARGET).
+ $(LOCATE_TARGET) is initialized by the
+ SubDir rule to the source directory itself.
+ (See ALL_LOCATE_TARGET.)
+
+
+
+ MANDIR
+
+
+ Not longer used.
+ (I.e., used only for backward compatibility with the
+ obsolete INSTALLMAN rule.)
+
+
+ MKDIR
+
+
+ The 'create directory' command used for the MkDir
+ rule.
+
+
+ MODE
+
+
+ The target-specific file mode (permissions) for targets
+ of the Shell, Setuid, Link, and Install* rules.
+ Used by the Chmod action; hence relevant to NT and VMS
+ only.
+
+
+ MSVC
+
+ Selects Microsoft Visual C 16-bit compile & link
+ actions on NT.
+
+
+ MSVCNT
+
+ Selects Microsoft Visual C NT compile & link
+ actions on NT.
+
+
+
+ MV
+
+
+ The file rename command and options.
+
+
+ NEEDLIBS
+
+
+ The list of libraries used when linking an executable.
+ Used by the Link rule.
+
+
+ NOARSCAN
+
+
+ If set, indicates that library members' timestamps can't
+ be found, and prevents the individual objects from being
+ deleted, so that their timestamps can be used instead.
+
+
+ NOARUPDATE
+
+
+ If set, indicates that libraries can't be updated, but only
+ created whole.
+
+
+ OPTIM
+
+
+ The C compiler flag for optimization, used by Cc and C++
+ rules.
+
+
+ OSFULL
+
+
+ The concatenation of $(OS)$(OSVER)$(OSPLAT), used when jam
+ builds itself to determine the target binary directory.
+ $(OS) and $(OSPLAT) are determined by jam at its compile
+ time (in jam.h). $(OSVER) can optionally be set by the user.
+
+
+
+ OWNER
+
+
+ The owner of installed files. Used by Install* rules.
+
+
+ RANLIB
+
+
+ The name of the ranlib command. If set, causes
+ the Ranlib action to be applied after the
+ Archive action to targets of the Library rule.
+
+
+ RELOCATE
+
+
+ If set, tells the Cc rule to move the output object
+ file to its target directory because the cc command
+ has a broken -o option.
+
+
+ RM
+
+
+ The command and options to remove a file.
+
+
+ SEARCH_SOURCE
+
+
+ The directory to find sources listed with Main,
+ Library, Object, Bulk, File, Shell, InstallBin,
+ InstallLib, and InstallMan rules. This works by
+ setting the jam-special variable SEARCH to the
+ value of $(SEARCH_SOURCE) for each of the rules'
+ sources. The SubDir rule initializes SEARCH_SOURCE
+ for each directory.
+
+
+ SHELLHEADER
+
+
+ A string inserted to the first line of every file
+ created by the Shell rule.
+
+
+ SHELLMODE
+
+
+ Permissions for files installed by Shell rule.
+
+
+ SOURCE_GRIST
+
+
+ Set by the SubDir to a value derived from the
+ directory name, and used by Objects and related
+ rules as 'grist' to perturb file names.
+
+
+ STDHDRS
+
+
+ Directories where headers can be found without
+ resorting to using the flag to the C compiler.
+ The $(STDHDRS) directories are used to find
+ headers during scanning, but are not passed to the
+ compiler commands as -I paths.
+
+
+ SUBDIR
+
+
+ The path from the current directory to the directory
+ last named by the SubDir rule.
+
+
+ TOP
+
+
+ The path from the current directory to the directory
+ that has the Jamrules file. Used by the SubDir rule.
+
+
+ SUFEXE
+
+
+ The suffix for executable files, if none provided.
+ Used by the Main rule.
+
+
+ SUFLIB
+
+
+ The suffix for libraries. Used by the Library and
+ related rules.
+
+
+ SUFOBJ
+
+
+ The suffix for object files. Used by the Objects
+ and related rules.
+
+
+ UNDEFFLAG
+
+
+ The flag prefixed to each symbol for the Undefines
+ rule (i.e., the compiler flag for undefined symbols).
+
+
+ WATCOM
+
+ Selects Watcom compile and link actions on OS2.
+
+
+ YACC
+
+
+ The yacc(1) command.
+
+
+ YACCFILES
+
+
+ The base filename generated by yacc(1).
+
+
+ YACCFLAGS
+
+
+ The yacc(1) command flags.
+
+
+
+
+Back to top.
+
+ Copyright 1997, 2000 Perforce Software, Inc.
+
+ Comments to info@perforce.com
+
+ Last updated: Dec 31, 2000
+
+ $Id$
+
+
diff --git a/historic/jam/src/Jamfile b/historic/jam/src/Jamfile
new file mode 100644
index 000000000..fc4d385a4
--- /dev/null
+++ b/historic/jam/src/Jamfile
@@ -0,0 +1,227 @@
+#
+# Jamfile to build Jam (a make(1)-like program)
+#
+# There are no user-serviceable parts in this file.
+#
+# Put executables in platform-specific subdirectory.
+
+# compile without assertions by default
+CCFLAGS ?= -DNDEBUG ;
+
+if $(VMS) { LOCATE_TARGET ?= [.binvms] ; }
+else if $(MAC) { LOCATE_TARGET ?= :bin.mac ; }
+else { LOCATE_TARGET ?= bin.$(OSFULL[1]:L) ; }
+
+# Leave generated source in current directory; it would be nice to use
+# these lines below to build the source into the platform-specific
+# directory, but getting scan.c to include the right jambase.h is
+# hard: with ""'s, it always gets the bootstrap version; with <>'s,
+# it won't find the bootstrap version.
+
+# SEARCH_SOURCE ?= $(LOCATE_TARGET) $(DOT) ;
+# LOCATE_SOURCE ?= $(LOCATE_TARGET) ;
+
+#
+# We have some different files for UNIX, VMS, and NT.
+#
+
+if $(NT) {
+ code = execnt.c filent.c pathunix.c ;
+ if $(OSTYPE) = cygwin
+ {
+ YACC ?= bison -t -d -l -v --yacc ;
+ YACCFILES = y.tab ;
+ }
+}
+else if $(OS2)
+{
+ # special case for OS/2. When building Jam with GCC/EMX
+ # we need to use the "fileunix.c" file
+ #
+ # when we build it with other toolsets, we use "fileos2.c"
+ #
+ code = execunix.c pathunix.c ;
+ if $(TOOLSET) = EMX
+ {
+ CCFLAGS += -D__OS2__ ;
+ code += fileunix.c ;
+ }
+ else
+ {
+ code += fileos2.c ;
+ }
+}
+else if $(VMS) { code = execvms.c filevms.c pathvms.c ; }
+else if $(MAC) { code = execmac.c filemac.c pathmac.c ; }
+else { code = execunix.c fileunix.c pathunix.c ; }
+
+# We have to signal jam.h for these
+
+if $(OS) = NT
+{
+ if $(TOOLSET) = MINGW || $(TOOLSET) = LCC
+ {
+ CCFLAGS += -DNT ;
+ }
+ else
+ {
+ CCFLAGS += /DNT ;
+ }
+}
+
+# Do we know yacc?
+
+if $(YACC) { code += jamgram.y ; }
+else { code += jamgram.c ; }
+
+#
+# Build the jamgram.y from the jamgram.yy
+# yyacc is a slippery script that makes grammars a little
+# easier to read/maintain.
+#
+
+if ( $(UNIX) || $(NT) ) && $(YACC)
+{
+ local SUFEXE = ; # yyacc is a script with no suffix - this handles cygwin
+ GenFile jamgram.y jamgramtab.h : ./yyacc jamgram.yy ;
+}
+
+#
+# How to build the compiled in jambase.
+#
+
+Main mkjambase : mkjambase.c ;
+
+#
+# The guts of the Jamfile: how to build Jam
+#
+
+Main jam : jam.c jambase.c ;
+LinkLibraries jam : libjam.a ;
+GenFile jambase.c : mkjambase$(SUFEXE) Jambase ;
+
+Library libjam.a :
+ command.c compile.c $(code) expand.c glob.c
+ hash.c headers.c hdrmacro.c lists.c make.c make1.c newstr.c
+ option.c parse.c regexp.c rules.c scan.c search.c subst.c
+ timestamp.c variable.c modules.c strings.c filesys.c ;
+
+
+if $(BINDIR) { InstallBin $(BINDIR) : jam ; }
+
+#
+# Distribution making from here on out.
+#
+
+ALLSOURCE =
+ Build.com Build.mpw Jam.html Jambase Jambase.html Jamfile
+ Jamfile.html Makefile Porting README RELNOTES command.c command.h
+ compile.c compile.h execcmd.h execmac.c execunix.c execnt.c execvms.c
+ expand.c expand.h filemac.c filent.c fileos2.c filesys.h fileunix.c
+ filevms.c glob.c hash.c hash.h hdrmacro.c hdrmacro.h headers.c
+ headers.h jam.c jam.h jambase.c jambase.h jamgram.c jamgram.h
+ jamgram.y jamgram.yy jamgramtab.h lists.c lists.h make.c make.h
+ make1.c mkjambase.c modules.c newstr.c newstr.h option.c option.h parse.c
+ parse.h patchlevel.h pathmac.c pathunix.c pathvms.c regexp.c regexp.h
+ rules.c rules.h scan.c scan.h search.c search.h strings.c subst.c timestamp.c
+ timestamp.h variable.c variable.h filesys.c filesys.h yyacc
+ INSTALL
+ common.mk
+ builds/win32-visualc.mk
+ builds/win32-borlandc.mk
+ builds/win32-gcc.mk
+ ;
+
+
+rule Binary
+{
+ NotFile package ;
+ Depends package : $(<) ;
+
+ DEPENDS $(<) : $(>) ;
+
+ switch $(<)
+ {
+ case *-win32.zip : Zip-Exe $(<) : $(>) ;
+ case *-os2.zip : Zip-Exe $(<) : $(>) ;
+ case *-linux-libc6.tar : GZip-Exe $(<) : $(>) ;
+ }
+}
+
+
+rule Package
+{
+ NotFile package ;
+ Depends package : $(<) ;
+
+ DEPENDS $(<) : $(>) ;
+
+ switch $(<)
+ {
+ case *.tar : { Tar-Gz $(<) : $(>) ; Tar-Bz2 $(<) : $(>) ; }
+ case *.zip : Zip $(<) : $(>) ;
+ }
+}
+
+VERSION = ftjam-2.3.5 ;
+
+
+actions Tar-Gz
+{
+ ln -s . $(VERSION)
+ tar cvhf $(<) $(VERSION)/$(>)
+ rm $(VERSION)
+ gzip -9 $(<)
+}
+
+actions Tar-Bz2
+{
+ ln -s . $(VERSION)
+ tar cvhf $(<) $(VERSION)/$(>)
+ rm $(VERSION)
+ bzip2 -9 $(<)
+}
+
+
+actions Zip
+{
+ zip -9r $(<) $(>)
+}
+
+actions Zip-Exe
+{
+ zip -9j $(<) $(LOCATE_TARGET)\jam.exe
+}
+
+actions GZip-Exe
+{
+ ln -s $(LOCATE_TARGET)/jam jam
+ strip jam
+ tar chf $(<) jam
+ rm -f jam
+ gzip -9 $(<)
+}
+
+
+
+if $(NT)
+{
+ Binary $(VERSION)-win32.zip : $(ALLSOURCE) ;
+ Package $(VERSION).zip : $(ALLSOURCE) ;
+}
+else if $(OS2)
+{
+ Binary $(VERSION)-os2.zip : $(ALLSOURCE) ;
+ Package $(VERSION).zip : $(ALLSOURCE) ;
+}
+else if $(OS) = LINUX
+{
+ # how can we detect the C library version reliably ??
+ # for now, this should only be used for convenience
+ # purposes, until we add .rpm and .deb support in..
+
+ Binary $(VERSION)-linux-libc6.tar : jam ;
+
+ Package $(VERSION).tar : $(ALLSOURCE) ;
+ Package $(VERSION).zip : $(ALLSOURCE) ;
+}
diff --git a/historic/jam/src/Jamfile.html b/historic/jam/src/Jamfile.html
new file mode 100644
index 000000000..2f94ddf9d
--- /dev/null
+++ b/historic/jam/src/Jamfile.html
@@ -0,0 +1,1450 @@
+
+
+Jamfiles and Jambase
+
+
+
+
+Jam/MR
+
+
+
+Using Jamfiles and Jambase
+
+
+
+
+This document describes how to write Jamfiles using the Jam/MR Jambase
+rules to build software products.
+Related documents of interest are:
+
+
+Jam/MR documentation and source are available from the
+Perforce Public Depot.
+
+
+
+Overview
+
+
+ jam, the Jam executable program,
+ recursively builds target files from source files
+ using dependency and build specifications defined
+ in Jam rules files.
+ jam parses the rules files to identify targets
+ and sources,
+ examines the filesystem to determine which
+ targets need updating, and issues OS commands to update
+ targets.
+
+ A base rules file called "Jambase" is provided with the
+ Jam distribution.
+ The Jambase file defines rules and variables which support
+ standard software build operations, like compiling, linking,
+ etc.
+
+ When the Jambase rules are used,
+ jam reads Jambase, then reads a file called
+ "Jamfile" in the current directory.
+ The Jamfile describes what to do with the source files in
+ its directory. It may also cause
+ Jamfiles in other directories to be read.
+
+ Under certain circumstances, the first Jamfile read
+ also causes a site-specific "Jamrules" file to be read.
+ The Jamrules file is an optional set of rule and variable
+ definitions used to define site-specific processing.
+
+
+The Basic Jamfile
+
+
+Jamfiles contain rule invocations, which usually look like:
+
+ RuleName targets : targets ;
+
+The target(s) to the left of the colon usually indicate
+what gets built, and the target(s) to the right of the
+colon usually indicate what it is built from.
+
+
+A Jamfile can be as simple as this:
+
+ Main myprog : main.c util.c ;
+
+This specifies that there is a main.c and util.c file in the same
+directory as the Jamfile, and that those source files should be
+compiled and linked into an executable called myprog.
+If you cd to the directory where this Jamfile lives,
+you can see the exactly how jam would
+build myprog with:
+
+ jam -n
+
+Or, you can actually build myprog with the command:
+
+ jam
+
+
+
+
+Whitespace
+
+Jamfile elements are delimited by whitespace (blanks, tabs, or
+newlines). Elements to be delimited include rule names, targets,
+colons, and semicolons. A common mistake users make is to forget the
+whitespace, e.g.,
+
+ Main myprog: main.c util.c ; #WRONG!
+
+Jam doesn't distinguish between a typo and a target called "myprog:",
+so if you get strange results, the first thing
+you should check for in your Jamfile is missing whitespace.
+
+
+Filenames, Target Identifiers, and Buildable Targets
+
+
+Consider this Jamfile:
+
+ Main myprog : main.c util.c ;
+ LinkLibraries myprog : libtree ;
+ Library libtree : treemake.c treetrav.c ;
+
+
+The Main rule specifies that an executable called myprog will be built.
+The compiled main.c and util.c objects will be linked to produce
+myprog.
+The LinkLibraries rule specifies that libtree will
+be linked into myprog as well.
+The Library rule specifies which source files will be compiled and
+archived into the libtree library.
+
+The Jamfile above refers to targets like "myprog" and "libtree".
+However, depending on the platform you're building on, the actual
+filenames of those targets could be "myprog.exe" and "libtree.lib".
+Most Jambase rules supply the actual filenames of targets,
+so that Jamfiles themselves need not make any
+platform-specific filename references.
+
+The jam program builds up a list of unique target identifiers.
+Unless you are using the SubDir rules (described later),
+the default identifier for a file target is its filename. In the above
+example, the target identifiers are the filenames: myprog.exe,
+libtree.lib, main.obj, etc.
+
+While all Jambase rules refer to "targets",
+not all targets are buildable.
+There are two kinds of buildable targets:
+file targets and pseudotargets.
+File targets are objects that can be found in the filesystem.
+Pseudotargets are symbolic, and represent other targets.
+
+You can use any buildable target on the jam command line to
+build a subset of defined targets. For example:
+
+ jam libtree.a
+
+on Unix builds the libtree library and all the compiled objects
+that go in it.
+
+
+Pseudotargets
+
+
+Most Jambase rules that define file targets also define pseudotargets
+which are dependent on types of file targets.
+For example, Jambase defines a pseudotarget called "lib", which
+is dependent on file targets created by the Library rule. So
+the command:
+
+ jam lib
+
+used with the above example would cause the libtree library to be built.
+Also, there is one pseudotarget built into jam itself, called
+"all". Jambase sets "all" dependent on (almost) all other targets.
+
+In the unfortunate case where you have a buildable target whose name
+is the same as one of the Jambase pseudotargets, you'll have problems
+with the conflicting target name.
+Your workaround choices are:
+
+
+- Change the name of your buildable file or directory that conflicts.
+
+
- Modify your Jambase and change the name of the conflicting pseudotarget.
+(Pseudotargets are defined in Jambase using the NOTFILE rule.)
+
+
- Use grist on the conflicting target name in your Jamfile. E.g., instead
+ of
+
+ File lib : libfoo.a ;
+
+ try
+
+ File <dir>lib : libfoo.a ;
+
+
+
+
+
+Dependencies
+
+
+Jambase rules set dependencies on targets, so that if you update a
+source file, all the file targets that depend on that source
+file, and only the ones that depend on that source file,
+will be updated (rebuilt) the next time you run jam.
+
+Here are some of the dependencies
+that get set when jam runs on NT using the example Jamfile above:
+
+
+| Target | | Depends on |
+
| myprog.exe | | main.obj, util.obj, libtree.lib
+ |
| libtree.lib | | treemake.obj, treetrav.obj
+ |
| treetrav.obj | | treetrav.c
+ |
+
+
+Furthermore, the Main and Library rules set up recursive
+header scanning on their source targets.
+So after jam has finished parsing the Jamfile and
+setting the rule-driven dependencies, it scans the source
+files for "#include" lines. All #include files found during
+this scan become dependencies of the compiled object.
+E.g., all header files used to compile treetrav.c would
+be made dependencies of treetrav.obj.
+
+As a result, when you run jam, it will rebuild targets
+if either the source files change or the
+header files change. You can't tell by looking at a Jamfile
+which header files are dependencies, but you can easily
+display those dependencies with:
+
+ jam -nd+3
+
+
+Rule Ordering
+
+
+Rules which specify dependencies, like the Main, Library, and
+LinkLibrary rules, can be invoked in any order. jam
+figures out the order in which targets are built from
+their dependencies.
+
+Some rules, however, set variables which are used by subsequent
+rule invocations, and their ordering is important.
+For example, the SubDir* rules (discussed
+later) must be invoked in a particular order.
+
+
+
+Detailed Jambase Specifications
+
+
+This document describes how to use various Jambase rules
+from a functional point of view.
+You can see the summary of available Jambase rules in the
+Jambase Reference.
+The detailed specifications for any Jambase rule
+can be found by reading the rule definition itself
+in the Jambase file.
+
+
+
+
+Handling Directory Trees
+
+ The SubDir* rules are used to
+ define source code directory hierarchies.
+ With SubDir and SubInclude, you can use jam
+ to build software from source files and Jamfiles spread
+ across many directories, as is typical for large projects.
+ The SubDir* rules unify an entire
+ source code tree so that jam can read in
+ all the Jamfiles in one pass and
+ compute dependencies across the entire project.
+
+ To use the SubDir* rules, you must:
+
+
+ - Preface the Jamfile in each directory with an invocation
+ of the SubDir rule.
+
+
- Place at the root of the tree a file named Jamrules.
+ This file could be empty, but in
+ practice it contains user-provided rules and variable
+ definitions that are shared throughout the
+ tree. Examples of such definitions are library
+ names, header directories, install directories,
+ compiler flags, etc. This file is good candidate
+ for automatic customizing with autoconf(GNU).
+
+
- Optionally, set an environment variable pointing
+ to the root directory of the srouce tree. The
+ variable's name is left up to you, but in these
+ examples, we use TOP.
+
+
+
+ SubDir Rule
+
+
+ The SubDir rule must be invoked before any rules that
+ refer to the contents of the directory - it is best to put
+ it at the top of each Jamfile. For example:
+
+ # Jamfile in $(TOP)/src/util directory.
+
+ SubDir TOP src util ;
+
+ Main myprog : main.c util.c ;
+ LinkLibraries myprog : libtree ;
+ Library libtree : treemake.c treetrav.c ;
+
+ This compiles four files in $(TOP)/src/util, archives
+ two of the objects into libtree, and links the whole
+ thing into myprog.
+ Outputs are placed in the $(TOP)/src/util
+ directory.
+
+ This doesn't appear to be any different from
+ the previous example that didn't have a SubDir rule,
+ but two things are happening behind the scenes:
+
+ - The SubDir rule causes jam to read
+ in the $(TOP)/Jamrules file.
+ (The Jamrules file can alternately be named by the
+ variable $(xxxRULES), where xxx is the name of the
+ root variable, e.g., $(TOPRULES)).
+
+ The Jamrules file can contain variable definitions
+ and rule definitions specific to your codeline.
+ It allows you to completely customize your build
+ environment without having to rewrite Jambase.
+ Jamrules is only read
+ in once, at the first SubDir invocation.
+
+
-
+ The SubDir rule initializes a set of variables
+ that are used by Main and other rules to
+ uniquely identify the source files in this
+ directory and assign locations to the targets
+ built from files in this directory.
+
+ When you have set a root variable, e.g., $(TOP),
+ SubDir constructs path names rooted with $(TOP),
+ e.g., $(TOP)/src/util.
+ Otherwise, SubDir constructs relative pathnames
+ to the root directory, computed from the number
+ of arguments to the first SubDir rule, e.g.,
+ ../../src/util. In either case, the SubDir
+ rule constructs the path names that locate source
+ files.
+ You'll see how this is useful later.
+
+
+
+
+ The SubDir rule takes as its first argument the root
+ variable's name and takes as subsequent arguments the
+ directory names leading from the root to the directory of
+ the current Jamfile. Note that the name of the subdirectory
+ is given as individual elements: the SubDir rule
+ does not use system-specific directory name syntax.
+
+
+
+ SubInclude Rule
+
+ The SubInclude rule is used in a Jamfile to cause another
+ Jamfile to be read in.
+ Its arguments are in the same format as
+ SubDir's.
+
+ The recommended practice is only to include one level of
+ subdirectories at a time, and let the Jamfile in each subdirectory
+ include its own subdirectories. This allows a
+ user to sit in any arbitrary directory of the source tree
+ and build that subtree. For example:
+
+ # This is $(TOP)/Jamfile, top level Jamfile for mondo project.
+
+ SubInclude TOP src ;
+ SubInclude TOP man ;
+ SubInclude TOP misc ;
+ SubInclude TOP util ;
+
+ If a directory has both subdirectories of its own as well
+ as files that need building, the SubIncludes should be
+ either before the SubDir rule or be at the end of the Jamfile
+ - not between the SubDir and other rule invocations.
+ For example:
+
+ # This is $(TOP)/src/Jamfile:
+
+ SubDir TOP src ;
+
+ Main mondo : mondo.c ;
+ LinkLibraries mondo : libmisc libutil ;
+
+ SubInclude TOP src misc ;
+ SubInclude TOP src util ;
+
+
+ (jam processes all the Jamfiles it reads as if
+ it were reading one single, large Jamfile.
+ Build rules like Main and LinkLibraries rely on the
+ preceding SubDir rule to set up source file and
+ output file locations, and SubIncludes rules read in
+ Jamfiles that contain SubDir rules. So if you put
+ a SubIncludes rule between a SubDir and a Main
+ rule, jam will try to find the source files
+ for the Main rule in the wrong directory.)
+
+
+ Variables Used to Handle Directory Trees
+
+ The following variables are set by the SubDir rule
+ and used by the Jambase rules that define file targets:
+
+
+
+|
+ SEARCH_SOURCE
+ | | The SubDir targets (e.g., "TOP src util")
+ are used to construct a pathname (e.g., $(TOP)/src/util),
+ and that pathname is assigned to $(SEARCH_SOURCE).
+ Rules like Main and Library use $(SEARCH_SOURCE)
+ to set search paths on source files.
+ |
|
+ LOCATE_SOURCE
+ | | Initialized by the SubDir rule to the same
+ value as $(SEARCH_SOURCE), unless ALL_LOCATE_TARGET
+ is set.
+ $(LOCATE_SOURCE) is used by rules that build
+ generated source files (e.g., Yacc and Lex) to
+ set location of output files.
+ Thus the default location of built source files
+ is the directory of the Jamfile that defines them.
+ |
|
+ LOCATE_TARGET
+ | | Initalized by the SubDir rule to the same
+ value as $(SEARCH_SOURCE), unless ALL_LOCATE_TARGET
+ is set.
+ $(LOCATE_TARGET) is used by rules that build
+ binary objects (e.g., Main and Library) to
+ set location of output files.
+ Thus the default location of built binaray files
+ is the directory of the Jamfile that defines them.
+ |
|
+ ALL_LOCATE_TARGET
+ | |
+ If $(ALL_LOCATE_TARGET) is set, LOCATE_SOURCE
+ and and LOCATE_TARGET are set to $(ALL_LOCATE_TARGET)
+ instead of to $(SEARCH_SOURCE). This can be used to
+ direct built files to be written to a location outside
+ of the source tree, and enables building from read-only
+ source trees.
+ |
|
+ SOURCE_GRIST
+ | | The SubDir targets are formed into a string
+ like "src!util" and that string is assigned to
+ SOURCE_GRIST. Rules that define file targets
+ use $(SOURCE_GRIST) to set the "grist" attribute
+ on targets. This is used to assure uniqueness
+ of target identifiers where filenames themselves
+ are not unique.
+ For example, the target identifiers of
+ $(TOP)/src/client/main.c and $(TOP)/src/server/main.c
+ would be <src!client>main.c and <src!server>main.c.
+ |
+
+
+ The $(LOCATE_TARGET) and $(SEARCH_SOURCE) variables are used
+ extensively by rules in Jambase: most rules that generate
+ targets (like Main, Object, etc.) set $(LOCATE) to
+ $(LOCATE_TARGET) for the targets they generate, and rules
+ that use sources (most all of them) set $(SEARCH) to be
+ $(SEARCH_SOURCE) for the sources they use.
+
+ $(LOCATE) and $(SEARCH) are better explained in
+ The Jam Executable Program
+ but in brief they tell jam where to create new targets and
+ where to find existing ones, respectively.
+
+ Note that you can reset these variables
+ after SubDir sets them. For example, this Jamfile builds
+ a program called gensrc, then runs it to create a source file
+ called new.c:
+
+ SubDir TOP src util ;
+ Main gensrc : gensrc.c ;
+ LOCATE_SOURCE = $(NEWSRC) ;
+ GenFile new.c : gensrc ;
+
+ By default, new.c would be written into the
+ $(TOP)/src/util directory, but resetting LOCATE_SOURCE causes
+ it to be written to the $(NEWSRC) directory. ($(NEWSRC) is assumed
+ to have been set elsewhere, e.g., in Jamrules.)
+
+
+ VMS Notes
+
+ On VMS, the logical name table is not imported as is the
+ environment on UNIX. To use the SubDir and related rules,
+ you must set the value of the variable that names the root
+ directory. For example:
+
+ TOP = USR_DISK:[JONES.SRC] ;
+
+ SubInclude TOP util ;
+
+ The variable must have a value that looks like a directory
+ or device. If you choose, you can use a concealed logical.
+ For example:
+
+ TOP = TOP: ;
+
+ SubInclude TOP util ;
+
+ The : at the end of TOP makes the value of $(TOP) look
+ like a device name, which jam respects as a directory name
+ and will use when trying to access files. TOP must then
+ be defined from DCL:
+
+ $ define/job/translation=concealed TOP DK100:[USERS.JONES.SRC.]
+
+ Note three things: the concealed translation allows the
+ logical to be used as a device name; the device name in
+ the logical (here DK100) cannot itself be concealed logical
+ (VMS rules, man); and the directory component of the
+ definition must end in a period (more VMS rules).
+
+
+Building Executables and Libraries
+
+
+The rules that build executables and libraries are: Main, Library,
+and LinkLibraries.
+
+ Main Rule
+
+ The Main rule compiles source files and links the resulting
+ objects into an executable. For example:
+
+ Main myprog : main.c util.c ;
+
+ This compiles main.c and util.c and links main.o and
+ util.o into myprog. The object files and resulting
+ executable are named appropriately for the platform.
+
+ Main can also be used to build shared libraries and/or
+ dynamic link libraries, since those are also linked
+ objects. E.g.:
+
+ Main driver$(SUFSHR) : driver.c ;
+
+ Normally, Main uses $(SUFEXE) to determine the suffix on
+ the filename of the built target. To override it,
+ you can supply a suffix explicity.
+ In this case,
+ $(SUFSHR) is assumed to be the OS-specific shared library
+ suffix, defined in Jamrules with something
+ like:
+
+ if $(UNIX) { SUFSHR = .so ; }
+ else if $(NT) { SUFSHR = .dll ; }
+
+
+ Main uses the Objects rule to compile source targets.
+
+
+ Library Rule
+
+ The Library rule compiles source files, archives the
+ resulting object files into a library, and then deletes
+ the object files. For example:
+
+ Library libstring : strcmp.c strcpy.c strlen.c ;
+ Library libtree : treemake.c treetrav.c ;
+
+ This compiles five source files, archives three of the
+ object files into libstring and the other two into libtree.
+ Actual library filenames are formed with the $(SUFLIB) suffix.
+ Once the objects are safely in the libraries, the
+ objects are deleted.
+
+ Library uses the Objects rule to compile source files.
+
+
+ LinkLibraries Rule
+
+ To link executables with built libraries, use
+ the LinkLibraries rule. For example:
+
+ Main myprog : main.c util.c ;
+ LinkLibraries myprog : libstring libtree ;
+
+ The LinkLibraries rule does two things: it makes the
+ libraries dependencies of the executable, so that they get
+ built first; and it makes the libraries show up on the
+ command line that links the executable. The ordering of
+ the lines above is not important, because jam builds targets
+ in the order that they are needed.
+
+ You can put multiple libraries on a single invocation of
+ the LinkLibraries rule, or you can provide them in multiple
+ invocations. In both cases, the libraries appear on
+ the link command line in the order in which they were
+ encountered. You can also provide multiple executables to
+ the LinkLibraries rule, if they need the same libraries,
+ e.g.:
+
+ LinkLibraries prog1 prog2 prog3 : libstring libtree ;
+
+
+
+ Variables Used in Building Executables and Libraries
+
+
+
+|
+ AR
+ | | Archive command, used for Library targets.
+ |
|
+ SUFEXE
+ | * | Suffix on filenames of executables referenced
+ by Main and LinkLibraries.
+ |
|
+ LINK
+ | | Link command, used for Main targets.
+ |
|
+ LINKFLAGS
+ | | Linker flags.
+ |
|
+ LINKLIBS
+ | | Link libraries that aren't dependencies. (See note
+ below.)
+ |
|
+ EXEMODE
+ | * | File permissions on Main targets.
+ |
|
+ MODE
+ | | Target-specific file permissions on Main targets
+ (set from $(EXEMODE))
+ |
|
+ RANLIB
+ | | Name of ranlib program, if any.
+ |
+
+
+
+ Variables above marked with "*" are used by the Main,
+ Library, and LinkLibraries rules. Their values at the
+ time the rules are invoked are used to set target-specific
+ variables.
+
+ All other variables listed above are globally defined,
+ and are used in actions that update Main and Library
+ targets. This means that the global values of those
+ variables are used, uness target-specific values have
+ been set.
+ (For instance, a target-specific MODE value is set by
+ the Main rule.)
+ The target-specific values always override
+ global values.
+
+ Note that there are two ways to specify link libraries for
+ executables:
+
+ - Use the LinkLibraries rule
+ to specify built libraries; i.e., libraries
+ that are built by Library rules. This assures that
+ these libraries are built first, and that Main targets are
+ rebuilt when the libraries are updated.
+
+
- Use the LINKLIBS variable to specify external
+ libraries; e.g., system libraries or third-party libraries.
+ The LINKLIBS variable must be set to the the actual
+ link command flag that specifies the libraries.
+
+
+
+ For example:
+
+ #In Jamrules:
+ if $(UNIX) { X11LINKLIBS = -lXext -lX11 ; }
+ if $(NT) { X11LINKLIBS = libext.lib libX11.lib ; }
+
+ #In Jamfile:
+ Main xprog : xprog.c ;
+ LINKLIBS on xprog$(SUFEXE) = $(X11LINKLIBS) ;
+ LinkLibraries xprog : libxutil ;
+ Library libxutil : xtop.c xbottom.c xutil.c ;
+
+ This example uses the Jam syntax "variable on target" to
+ set a target-specific variable. In this way, only xprog
+ will be linked with this special $(X11LINKLIBS),
+ even if other executables were going to be built
+ by the same Jamfile. Note that when you set a variable
+ on a target, you have to specify the target identifer
+ exactly, which in this case is the suffixed filename of
+ the executable.
+ The actual link command line on Unix, for example, would
+ look something like this:
+
+ cc -o xprog xprog.o libxutil.a -lXext -lX11
+
+
+Compiling
+
+ Compiling of source files occurs normally as a byproduct
+ of the Main or Library rules, which call the rules
+ described here. These rules may also be called explicitly
+ if the Main and Library behavior doesn't satisfy your
+ requirements.
+
+
+ Objects Rule
+
+ The Main and Library rules call the Objects rule on source files.
+ Compiled object files built by
+ the Objects rule are a dependency of the obj
+ pseudotarget, so "jam obj" will build object files used in
+ Main and Library rules.
+
+ Target identifiers created by the Objects rule have grist
+ set to $(SOURCE_GRIST). So given this Jamfile:
+
+ SubDir TOP src lock ;
+ Main locker : lock.c ;
+
+ the object file created is lock.o (or lock.obj) and
+ its target identifier is <src!lock>lock.o
+ (or <src!lock>lock.obj).
+
+
+ You can also call Objects directly. For example:
+
+ Objects a.c b.c c.c ;
+
+ This compiles a.c into a.o, b.c into b.o, etc. The object
+ file suffix is supplied by the Objects rule.
+
+
+ Object Rule
+
+ Objects gets its work done by calling the Object rule on
+ each of the source files.
+ You could use the Object rule directly.
+ For example, on Unix, you could use:
+
+ Object foo.o : foo.c ;
+
+ However, the Object rule does not provide suffixes, and
+ it does not provide the grist needed to construct target
+ identifiers if you are using the SubDir* rules.
+ A portable and robust Jamfile would need to invoke Object thus:
+
+ Object <src!util>foo$(SUFOBJ) : <src!util>foo.c ;
+
+ which is inelegant and clearly shows why using Objects
+ is better than using Object.
+
+ If there's any advantage to the Object rule, it's
+ that it doesn't require that the object name bear
+ any relationship to the source. It is thus possible to
+ compile the same file into different objects. For example:
+
+
+ Object a.o : foo.c ;
+ Object b.o : foo.c ;
+ Object c.o : foo.c ;
+
+ This compiles foo.c (three times) into a.o, b.o, and c.o.
+ Later examples show how this is useful.
+
+ The Object rule looks at the suffix of the source file and
+ calls the appropriate rules to do the actual preprocessing
+ (if any) and compiling needed to produce the output object file.
+ The Object rule is
+ capable of the generating of an object file from any
+ type of source. For example:
+
+ Object grammar$(SUFOBJ) : grammar.y ;
+ Object scanner$(SUFOBJ) : scanner.l ;
+ Object fastf$(SUFOBJ) : fastf.f ;
+ Object util$(SUFOBJ) : util.c ;
+
+ An even more elegant way to get the same result is to let the
+ Objects rule call Object:
+
+ Objects grammar.y scanner.l fastf.f util.c ;
+
+
+ In addition to calling the compile rules, Object sets up
+ a bunch of variables specific to the source and target
+ files. (See Variables Used in Compiling, below.)
+
+
+ Cc, C++, Yacc, Lex, Fortran, As, etc. Rules
+
+
+ The Object rule calls compile rules specific to the suffix of
+ the source file. (You can see which suffixes are supported
+ by looking at the Object rule definition in Jambase.)
+ Because the extra work done by the
+ Object rule, it is not always useful to call the compile
+ rules directly. But the adventurous user might attempt
+ it. For example:
+
+ Yacc grammar.c : grammar.y ;
+ Lex scan.c : scan.l ;
+ Cc prog.o : prog.c ;
+
+ These examples individually run yacc(1), lex(1), and the C
+ compiler on their sources.
+
+
+ UserObject Rule
+
+ Any files with suffixes not understood by the Object rule
+ are passed to the UserObject rule. The default definition
+ of UserObject simply emits a warning that the suffix is
+ not understood. This Jambase rule definition is intended to be
+ overridden in Jamrules with one that recognizes the project-specific
+ source file suffixes. For example:
+
+
+ #In Jamrules:
+
+ rule UserObject
+ {
+ switch $(>)
+ {
+ case *.rc : ResourceCompiler $(<) : $(>) ;
+ case * : ECHO "unknown suffix on" $(>) ;
+ }
+ }
+
+ rule ResourceCompiler
+ {
+ DEPENDS $(<) : $(>) ;
+ Clean clean : $(<) ;
+ }
+
+ actions ResourceCompiler
+ {
+ rc /fo $(<) $(RCFLAGS) $(>)
+ }
+
+
+ #In Jamfile:
+
+ Library liblock : lockmgr.c ;
+ if $(NT) { Library liblock : lock.rc ; }
+
+
+ In this example, the UserObject definition in Jamrules
+ allows *.rc files to be handle as regular Main and Library
+ sources. The lock.rc file is compiled into lock.obj
+ by the "rc" command, and lock.obj is archived into a library
+ with other compiled objects.
+
+ LibraryFromObjects Rule
+
+ Sometimes the Library rule's straightforward compiling of
+ source into object modules to be archived isn't flexible
+ enough. The LibraryFromObjects rule does the archiving
+ (and deleting) job of the Library rule, but not the compiling.
+ The user can make use of the Objects or Object
+ rule for that. For example:
+
+ LibraryFromObjects libfoo.a : max.o min.o ;
+ Object max.o : maxmin.c ;
+ Object min.o : maxmin.c ;
+ ObjectCcFlags max.o : -DUSEMAX ;
+ ObjectCcFlags min.o : -DUSEMIN ;
+
+ This Unix-specific example compiles the same source file into
+ two different
+ objects, with different compile flags, and archives them.
+ (The ObjectCcFlags rule is described shortly.)
+ Unfortunately, the portable and robust implementation of the
+ above example is not as pleasant to read:
+
+ SubDir TOP foo bar ;
+ LibraryFromObjects libfoo$(SUFLIB) : <foo!bar>max$(SUFOBJ)
+ <foo!bar>min$(SUFOBJ) ;
+ Object <foo!bar>min$(SUFOBJ) : <foo!bar>maxmin.c ;
+ Object <foo!bar>max$(SUFOBJ) : <foo!bar>maxmin.c ;
+ ObjectCcFlags <foo!bar>min$(SUFOBJ) : -DUSEMIN ;
+ ObjectCcFlags <foo!bar>max$(SUFOBJ) : -DUSEMAX ;
+
+ Note that, among other things, you must supply the library
+ file suffix when using the LibraryFromObjects rule.
+
+
+ MainFromObjects Rule
+
+ Similar to LibraryFromObjects, MainFromObjects does the
+ linking part of the Main rule, but not the compiling.
+ MainFromObjects can be used when there are no
+ objects at all, and everything is to be loaded from
+ libraries. For example:
+
+ MainFromObjects testprog ;
+ LinkLibraries testprog : libprog ;
+ Library libprog : main.c util.c ;
+
+ On Unix, say, this generates a link command that looks like:
+
+ cc -o testprog libprog.a
+
+ Linking purely from libraries is something that doesn't
+ work everywhere: it depends on the symbol "main" being
+ undefined when the linker encounters the library that contains
+ the definition of "main".
+
+
+ Variables Used in Compiling
+
+ The following variables control the compiling of source
+ files:
+
+
+
+|
+ C++
+ | | The C++ compiler command
+ |
|
+ CC
+ | | The C compiler command
+ |
+ C++FLAGS
+
+ CCFLAGS
+ | | Compile flags, used to
+ create or update compiled objects
+ |
+ SUBDIRC++FLAGS
+
+ SUBDIRCCFLAGS
+ | | Additonal compile flags
+ for source files in this directory.
+ |
|
+ OPTIM
+ | | Compiler optimization flag. The Cc and C++
+ actions use this as well as C++FLAGS or CCFLAGS.
+ |
|
+ HDRS
+ | | Non-standard header directories; i.e.,
+ the directories the compiler will not look in
+ by default and which therefore must be supplied
+ to the compile command. These directories are
+ also used by jam to scan for include files.
+ |
|
+ STDHDRS
+ | | Standard header directories, i.e., the
+ directories the compiler searches automatically.
+ These are not passed to the compiler, but they
+ are used by jam to scan for include files.
+ |
|
+ SUBDIRHDRS
+ | | Additional paths to add to HDRS for source files
+ in this directory.
+ |
|
+ LEX
+ | | The lex(1) command
+ |
|
+ YACC
+ | | The yacc(1) command
+ |
+
+
+ The Cc rule sets a target-specific $(CCFLAGS) to the current
+ value of $(CCFLAGS) and $(SUBDIRCCFLAGS). Similarly
+ for the C++ rule. The Object rule sets a target-specific
+ $(HDRS) to the current value of $(HDRS) and $(SUBDDIRHDRS).
+
+
+ $(CC), $(C++), $(CCFLAGS), $(C++FLAGS), $(OPTIM), and
+ $(HDRS) all affect the compiling of C and C++ files.
+ $(OPTIM) is separate from $(CCFLAGS) and $(C++FLAGS) so
+ they can be set independently.
+
+ $(HDRS) lists the directories to search for header files,
+ and it is used in two ways: first, it is passed to the C
+ compiler (with the flag -I prepended); second, it is used
+ by HdrRule to locate the header files whose names were
+ found when scanning source files. $(STDHDRS) lists the
+ header directories that the C compiler already knows
+ about. It does not need passing to the C compiler, but is
+ used by HdrRule.
+
+ Note that these variables, if set as target-specific variables,
+ must be set on the target, not the source file.
+ The target file in this case is the object file to be generated.
+ For example:
+
+ Library libximage : xtiff.c xjpeg.c xgif.c ;
+
+ HDRS on xjpeg$(SUFOBJ) = /usr/local/src/jpeg ;
+ CCFLAGS on xtiff$(SUFOBJ) = -DHAVE_TIFF ;
+
+ This can be done more easily with the rules that follow.
+
+
+ ObjectCcFlags, ObjectC++Flags, ObjectHdrs Rules
+
+ $(CCFLAGS), $(C++FLAGS) and $(HDRS) can be set on object file
+ targets
+ directly, but there are rules that allow these variables
+ to be set by referring to the original source file name,
+ rather than to the derived object file name. ObjectCcFlags
+ adds object-specific flags to the $(CCFLAGS) variable,
+ ObjectC++Flags adds object-specific flags to the
+ $(C++FLAGS) variable, and ObjectHdrs add object-specific
+ directories to the $(HDRS) variable. For example:
+
+ #In Jamrules:
+ if $(NT) { CCFLAGS_X = /DXVERSION ;
+ HDRS_X = \\\\SPARKY\\X11\\INCLUDE\\X11 ;
+ }
+
+ #In Jamfile:
+ Main xviewer : viewer.c ;
+ ObjectCcFlags viewer.c : $(CCFLAGS_X) ;
+ ObjectHdrs viewer.c : $(HDRS_X) ;
+
+ The ObjectCcFlags and ObjectHdrs rules take .c files
+ as targets, but actually set $(CCFLAGS) and $(HDRS) values
+ on the .obj (or .o) files. As a result, the action
+ that updates the target .obj file uses the target-specific
+ values of $(CCFLAGS) and $(HDRS).
+
+
+ SubDirCcFlags, SubDirC++Flags, SubDirHdrs Rules
+
+ These rules set the values of $(SUBDIRCCFLAGS), $(SUBDIRC++FLAGS)
+ and $(SUBDIRHDRS), which are used by the Cc,
+ C++, and Object rules when setting the target-specific
+ values for $(CCFLAGS), $(C++FLAGS) and $(HDRS). The SubDir
+ rule clears these variables out, and thus they provide
+ directory-specific values of $(CCFLAGS), $(C++FLAGS) and
+ $(HDRS). For example:
+
+ #In Jamrules:
+ GZHDRS = $(TOP)/src/gz/include ;
+ GZFLAG = -DGZ ;
+
+ #In Jamfile:
+ SubDir TOP src gz utils ;
+
+ SubDirHdrs $(GZHDRS) ;
+ SubDirCcFlags $(GZFLAG) ;
+
+ Library libgz : gizmo.c ;
+ Main gizmo : main.c ;
+ LinkLibraries gizmo : libgz ;
+
+ All .c files in this directory files will be compiled with
+ $(GZFLAG) as well as the default $(CCFLAG), and the include
+ paths used on the compile command will be $(GZHDRS) as well
+ as the default $(HDRS).
+
+Header File Processing
+
+ One of the functions of the Object rule is set up
+ scanning of source
+ files for (C style) header file inclusions. To do so, it
+ sets the special variables $(HDRSCAN) and $(HDRRULE)
+ as target-specific variables on the source file. The
+ presence of these variables triggers a special mechanism
+ in jam for scanning a file for header file inclusions and
+ invoking a rule with the results of the scan. The
+ $(HDRSCAN) variable is set to an egrep(1) pattern that
+ matches "#include" statements in C source files, and the
+ $(HDRRULE) variable is set to the name of the rule that
+ gets invoked as such:
+
+ $(HDRRULE) source-file : included-files ;
+
+ This rule is supposed to set up the dependencies between
+ the source file and the included files. The Object rule
+ uses HdrRule to do the job. HdrRule itself expects
+ another variable, $(HDRSEARCH), to be set to the list of
+ directories where the included files can be found. Object
+ does this as well, setting $(HDRSEARCH) to $(HDRS) and
+ $(STDHDRS).
+
+ The header file scanning occurs during the "file binding"
+ phase of jam, which means that the target-specific
+ variables (for the source file) are in effect. To accomodate
+ nested includes, one of the HdrRule's jobs is to pass
+ the target-specific values of $(HDRRULE), $(HDRSCAN), and
+ $(HDRSEARCH) onto the included files, so that they will be
+ scanned as well.
+
+
+ HdrRule Rule
+
+ Normally, HdrRule is not invoked directly; the Object rule
+ (called by Main and Library) invokes it.
+
+ If there are special dependencies that need to be set,
+ and which are not set by HdrRule itself, you can define
+ another rule and let it invoke HdrRule. For example:
+
+
+ #In Jamrules:
+ rule BuiltHeaders
+ {
+ DEPENDS $(>) : mkhdr$(SUFEXE) ;
+ HdrRule $(<) : $(>) ;
+ }
+
+ #In Jamfile:
+ Main mkhdr : mkhdr.c ;
+ Main ugly : ugly.c ;
+
+ HDRRULE on ugly.c = BuiltHeaders ;
+
+
+ This example just says that the files included by "ugly.c"
+ are generated by the program "mkhdr", which can be built
+ from "mkhdr.c". During the binding phase, jam will
+ scan ugly.c, and if it finds an include file, ughdr.h,
+ for example, it will automatically invoke the rule:
+
+ BuiltHeaders ugly.c : ughdr.h ;
+
+ By calling HdrRule at the end of BuiltHeaders,
+ all the gadgetry of HdrRule takes effect and it
+ doesn't need to be duplicated.
+
+
+ Variables Used for Header Scanning
+
+
+
+|
+ HDRPATTERN
+ | | Default scan pattern for "include" lines.
+ |
|
+ HDRSCAN
+ | | Scan pattern to use.
+ This is a special variable: during binding, if
+ both HDRSCAN and HDRRULE are set, scanning is activated
+ on the target being bound.
+ The HdrRule and Object rules sets this
+ to $(HDRPATTERN) on their source targets.
+ |
|
+ HDRRULE
+ | | Name of rule to invoked on files found in header
+ scan. The HdrRule and Object rules set this to "HdrRule"
+ on their source targets. This is also a special variable;
+ it's the only jam variable that can hold the
+ name of a rule to be invoked.
+ |
|
+ HDRSEARCH
+ | | Search paths for files found during header scanning.
+ This is set from $(HDRS) and $(STDHDRS), which are
+ described in the Compiling section.
+ jam will search $(HDRSEARCH) directories for
+ the files found by header scans.
+ |
+
+
+ The Object rule sets HDRRULE and HDRSCAN specifically for
+ the source files to be scanned, rather than globally. If
+ they were set globally, jam would attempt to scan all
+ files, even library archives and executables, for header
+ file inclusions. That would be slow and probably not
+ yield desirable results.
+
+
+Copying Files
+
+
+ File Rule
+
+ The File rule copies one file to another. The target name
+ needn't be the same as the source name. For
+ example:
+
+ switch $(OS)
+ {
+ case NT* : File config.h : confignt.h ;
+ case * : File config.h : configunix.h ;
+ }
+ LOCATE on config.h = $(LOCATE_SOURCE) ;
+
+ This creates a config.h file from either confignt.h or
+ configunix.h, depending on the current build platform.
+
+ The File rule does not
+ use the LOCATE_SOURCE variable set by the
+ SubDir rule (although it does use SEARCH_SOURCE), which
+ means you have to set the copied file's output directory
+ yourself. That's done by setting the special
+ LOCATE variable on the target, as shown above,
+ or with the MakeLocate rule described below.
+
+ Bulk Rule
+
+ The Bulk rule is a shorthand for many invocations of the
+ File rule when all files are going to the same directory.
+ For example:
+
+ #In Jamrules:
+ DISTRIB_GROB = d:\\distrib\\grob ;
+
+ #In Jamfile:
+ Bulk $(DISTRIB_GROB) : grobvals.txt grobvars.txt ;
+
+ This causes gobvals.txt and grobvars.txt to be copied
+ into the $(DISTRIB_GROB) directory.
+
+ HardLink Rule
+
+ The Unix-only HardLink rule makes a hard link (using ln(1)) from the
+ source to the target, if there isn't one already. For
+ example:
+
+ HardLink config.h : configunix.h ;
+
+
+ Shell Rule
+
+ The Shell rule is like the File rule, except that on Unix it makes
+ sure the first line of the target is "#!/bin/sh" and sets
+ the permission to make the file executable. For example:
+
+ Shell /usr/local/bin/add : add.sh ;
+
+
+ You can also use $(SHELLHEADER) to dictate
+ what the first line of the copied file will be.
+ For
+ example:
+
+ Shell /usr/local/bin/add : add.awk ;
+ SHELLHEADER on /usr/local/bin/add = "#!/bin/awk -f" ;
+
+ This installs an awk(1) script.
+
+
+ Variables Used When Copying Files
+
+
+
+|
+ FILEMODE
+ | | Default file permissions for copied files
+ |
|
+ SHELLMODE
+ | | Default file permissions for Shell rule targets
+ |
|
+ MODE
+ | | File permissions set on files copied by
+ File, Bulk, and Shell rules.
+ File and Shell sets a target-specific MODE to the current
+ value of $(FILEMODE) or $(SHELLMODE), respectively.
+ |
|
+ SHELLHEADER
+ | | String to write in first line of Shell targets
+ (default is #!/bin/sh).
+
+ |
+
+
+
+
+Installing Files
+
+Jambase provides a set of Install* rules to copy files
+into an destination directory and set permissions on them.
+On Unix, the install(1) program is used.
+If the destination directory does not exist, jam
+creates it first.
+
+All files copied with the Install* rules are dependencies
+of the install pseudotarget, which means that the
+command "jam install" will cause the installed copies to
+be updated. Also, "jam uninstall" will cause the installed
+copies to be removed.
+
+The Install* rules are:
+
+
+| InstallBin
+ | Copies file and sets its permission to $(EXEMODE).
+ You must specify the suffixed executable name. E.g.:
+ InstallBin $(BINDIR) : thing$(SUFEXE) ;
+
+
+ |
| InstallFile
+ | Copies file and sets its permission to $(FILEMODE). E.g.:
+ InstallFile $(DESTDIR) : readme.txt ;
+
+
+ |
| InstallLib
+ | Copies file and sets its permission to $(FILEMODE).
+ You must specify the suffixed library name. E.g.:
+ InstallLib $(LIBDIR) : libzoo$(SUFLIB) ;
+
+
+ |
| InstallMan
+ | Copies file into the mann
+ subdirectory of the target directory
+ and sets its permission to $(FILEMODE). E.g.,
+ this copies foo.5 into the $(DESTDIR)/man5 directory:
+ InstallMan $(DESTDIR) : foo.5 ;
+
+
+ |
| InstallShell
+ | Copies file and sets its permission to $(SHELLMODE). E.g.:
+ InstallShell $(DESTDIR) : startup ;
+
+
+ |
+
+
+
+
+ Variables
+
+ The following variables control the installation rules:
+
+
+
+|
+ INSTALL
+ | | The install program (Unix only)
+ |
|
+ FILEMODE
+ | | Default file permissions on readable files.
+ |
|
+ EXEMODE
+ | | Default file permission executable files.
+ |
|
+ SHELLMODE
+ | | Default file permission on shell script files.
+ |
|
+ MODE
+ | | Target-specific file permissions
+ |
+
+
+
+ The Install rules set a target-specific MODE to the current
+ value of $(FILEMODE), $(EXEMODE), or $(SHELLMODE),
+ depending on which Install rule was invoked.
+
+ The directory variables are just defined for convenience:
+ they must be passed as the target to the appropriate
+ Install rule. The $(INSTALL) and mode variables must be
+ set (globally) before calling the Install rules in order
+ to take effect.
+
+
+Miscellaneous Rules
+
+
+Clean Rule
+
+
+The Clean rule defines files to be removed when you run "jam clean".
+Any site-specific build rules defined in your Jamrules should invoke
+Clean so that outputs can be removed. E.g.,
+
+ rule ResourceCompiler
+ {
+ DEPENDS $(<) : $(>) ;
+ Clean clean : $(<) ;
+ }
+
+
+
+Most Jambase rules invoke the Clean rule on their built targets,
+so "jam clean" will remove all compiled objects, libraries,
+executables, etc.
+
+
+MakeLocate Rule
+
+ MakeLocate is a single convenient rule that creates a directory,
+ sets LOCATE on a target to that directory, and makes the directory
+ a dependency of the target. It is used by many Jambase rules,
+ and can be invoked directly, e.g.:
+
+ GenFile data.tbl : hxtract data.h ;
+ MakeLocate data.tbl : $(TABLEDIR) ;
+
+ In this example, the File rule creates data.tbl from data.h.
+ The MakeLocate causes data.tbl to be written into the $(TABLEDIR)
+ directory; and if the directory doesn't exist, it is created first.
+
+ The MakeLocate rule invokes another Jambase rule, MkDir,
+ to (recursively) create
+ directories. MkDir uses the $(MKDIR) variable to determine the
+ platform-specific command that creates directories.
+
+
+RmTemps Rule
+
+ Some intermediate files are meant to be temporary.
+ The RmTemps rule can be used to cause
+ jam to delete them after they are used.
+
+ RmTemps must be:
+
+ -
+ the last rule
+ invoked on the permanent file that uses
+ the temporary file(s)
+
-
+ invoked with the permanent file as the output
+ target and the temporary file(s) as the input target
+
-
+ invoked with the exact target identifiers of
+ the permanent file and the temporary file(s)
+
+ For
+ example:
+
+ SubDir TOP src big ;
+ GenFile big.y : joinfiles part1.y part2.y part3.y ;
+ Main bigworld : main.c big.y ;
+ RmTemps bigworld$(SUFEXE) : <src!big>big.y ;
+
+ This causes big.y to be deleted after it has been used to create
+ the bigworld executable.
+ The exact target identifier of big.y is <src!big>big.y
+ (the GenFile and Main rules tack on the grist automatically);
+ the exact target identifier of the bigworld executable
+ is bigworld$(SUFEXE).
+
+
+Back to top.
+
+ Copyright 1997, 2000 Perforce Software, Inc.
+
+ Comments to info@perforce.com
+
+ Last updated: Dec 31, 2000
+
+ $Id$
+
+
diff --git a/historic/jam/src/Makefile b/historic/jam/src/Makefile
new file mode 100644
index 000000000..90e890983
--- /dev/null
+++ b/historic/jam/src/Makefile
@@ -0,0 +1,88 @@
+# The following Makefile will build Jam on Unix systems
+# You can also modify it to compile the program on other
+# systems, or also use one of the specific Makefiles
+# located in the "builds" directory
+#
+
+CC = cc
+TARGET = -o jam0
+CFLAGS =
+
+# Borland C++ on Windows
+#CC = bcc32
+#TARGET = -ejam0
+#CFLAGS = /DNT -w- -q
+
+# Special flavors - uncomment appropriate lines
+
+# NCR seems to have a broken readdir() -- use gnu
+#CC = gcc
+
+# AIX needs -lbsd, and has no identifying cpp symbol
+# Use _AIX41 if you're not on 3.2 anymore.
+#LINKLIBS = -lbsd
+#CFLAGS = -D_AIX
+
+# NT (with Microsoft compiler)
+# Use FATFS if building on a DOS FAT file system
+#Lib = $(MSVCNT)/lib
+#Include = $(MSVCNT)/include
+#CC = cl /nologo
+#CFLAGS = -I $(Include) -DNT
+#TARGET = /Fejam0
+#LINKLIBS = $(Lib)/oldnames.lib $(Lib)/kernel32.lib $(Lib)/libc.lib
+
+# BeOS - Metroworks CodeWarrior
+#CC = mwcc
+#Include = /NewDisk/develop/headers/posix
+#CFLAGS = -I $(Include)
+
+# BeOS - gcc
+#CC = gcc
+#LINKLIBS = -lnet
+
+# Interix - gcc
+#CC = gcc
+
+# Cygwin - gcc & cygwin
+#CC = gcc
+#CFLAGS = -D__cygwin__
+
+# MingW - gcc on Win32
+#
+#CC = gcc
+#CFLAGS = -DNT
+
+# MPEIX
+#CC = gcc
+#CFLAGS = -I/usr/include -D_POSIX_SOURCE
+
+# QNX rtp (neutrino)
+#CC = gcc
+
+
+#
+#SOURCES = \
+# command.c compile.c execnt.c execunix.c execvms.c expand.c \
+# filent.c fileos2.c fileunix.c filevms.c glob.c hash.c \
+# hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c \
+# newstr.c option.c parse.c pathunix.c pathvms.c regexp.c \
+# rules.c scan.c search.c subst.c timestamp.c variable.c
+
+# for Unix systems
+#
+# we need to ensure that "jambase.c" has write permissions, since it is
+# going to be re-generated from "Jambase".
+#
+all: jam0
+ chmod a+w jambase.c
+ ./jam0
+
+# for other systems
+#all: jam0
+# jam0
+
+include common.mk
+
+#jam0:
+# $(CC) $(TARGET) $(CFLAGS) $(SOURCES) $(LINKLIBS)
diff --git a/historic/jam/src/Porting b/historic/jam/src/Porting
new file mode 100644
index 000000000..750556572
--- /dev/null
+++ b/historic/jam/src/Porting
@@ -0,0 +1,68 @@
+Notes on porting Jam - revised 12/31/2000
+
+1) Working out system dependencies in the Jam code.
+
+ Jam's OS footprint is fairly small. For OS independent work Jam
+ liberally uses standard libc functions like stdio, malloc, and
+ string. The OS dependent interfaces are:
+
+ From filesys.h:
+
+ file_parse() - split a file name into dir/base/suffix/member
+ file_build() - build a filename given dir/base/suffix/member
+ file_dirscan() - scan a directory for files
+ file_archscan() - scan an archive for files
+ file_time() - get the timestamp of a file, if not already
+ done by file_dirscan().
+
+ From execcmd.h:
+
+ execcmd() - execute a shell script
+ execwait() - wait for any outstanding execcmd()'s.
+
+ The current implementations are:
+
+ filemac.c - mac MPW
+ filent.c - NT
+ fileos2.c - OS/2
+ fileunix.c - all UNIX
+ filevms.c - VMS
+
+ execmac.c - mac MPW
+ execunix.c - UNIX, OS/2, NT
+ execvms.c - VMS
+
+2) Defining OSMAJOR, OSMINOR in jam.h
+
+ So that the Jambase and Jamfile know their host, Jam defines $(OS)
+ to be something useful for each platform. Make sure that there is
+ code in jam.h to generate a useful value for $(OS), and key it off
+ the platform specific C-preprocessor symbol. If the C-preprocessor
+ doesn't itself defines such a symbol, add a define to the Makefile.
+
+ In addition to $(OS), you can also set $(OSPLAT) if the OS runs on
+ multiple platforms (like Linux or NT).
+
+3) Working out system dependencies in the Jambase
+
+ With the value of $(OS) available, the Jambase can be extended to
+ support special variables or rules for new platforms. See the
+ current support for VMS, NT, and Mac.
+
+4) Yacc troubles
+
+ The generated files jamgram.h and jamgram.c are distributed for the
+ poor souls without yacc.
+
+5) Known problematic systems:
+
+ - Pyramid has no malloc.h, memory.h
+
+ - Encore has no stdlib.h
+
+ - Bull DPX has sys/file.h problems
+
+6) Send the results back.
+
+ If you do porting work, the result can be integrated into future
+ releases if you send it back to the author's address in the README.
diff --git a/historic/jam/src/README b/historic/jam/src/README
new file mode 100644
index 000000000..6f94add06
--- /dev/null
+++ b/historic/jam/src/README
@@ -0,0 +1,157 @@
+This is the FreeType version of Jam. For more information, please see
+ http://www.freetype.org/jam/index.html
+
+The complete and detailed list of changes is available at:
+ http://www.freetype.org/jam/changes.html
+
+------------------------------------------------------------------------------
+
+Jam/MR (aka "jam - make(1) redux")
+
+ /+\
+ +\ Copyright 1993, 2000 Christopher Seiwald.
+ \+/
+
+ This is Release 2.3 of Jam/MR, a make-like program.
+
+ License is hereby granted to use this software and distribute it
+ freely, as long as this copyright notice is retained and modifications
+ are clearly marked.
+
+ ALL WARRANTIES ARE HEREBY DISCLAIMED.
+
+FEATURES
+
+ -> Jam is a make(1) replacement that makes building simple things
+ simple and building complicated things manageable.
+
+ -> Jam's language is expressive, making Jamfiles (c.f. Makefiles)
+ compact. Here's a sample:
+
+ Main smail : main.c map.c resolve.c deliver.c
+ misc.c parser.y alias.c pw.c headers.c
+ scanner.l getpath.c str.c ;
+
+ This builds "smail" from a dozen source files. Jam handles
+ header file dependencies automatically and on-the-fly.
+
+ -> Jam is very portable: it runs on UNIX, VMS, Mac, and NT.
+ Most Jamfiles themselves are portable, like the sample above.
+
+ -> Jam is unintrusive: it is small, it has negligible CPU
+ overhead, and it doesn't create any of its own funny files
+ (c.f. Odin, nmake, SunOS make).
+
+ -> Jam can build large projects spread across many directories
+ in one pass, without recursing, tracking the relationships
+ among all files. Jam can do this with multiple, concurrent
+ processes.
+
+ -> Jam isn't under the blinkin GNU copyright, so you can
+ incorporate it into commercial products.
+
+
+INFORMATION GUIDE
+
+ Jam.html jam command usage
+
+ Jambase.html Reference for the Jambase boilerplate file.
+
+ Jamfile.html Easy reading on creating a Jamfile and using jam.
+
+ Jamlang.html The Jam language description.
+
+ RELNOTES Release 2.3 release notes.
+
+ Porting Notes on porting jam to wildcat platforms.
+
+ README This file. Includes installation instructions.
+
+ jam.c Contains the jam command's main() as well as an
+ introduction to the code, for serious hackers.
+
+
+INSTALLING
+
+ The Makefile (UNIX, NT), build.com (VMS), Build.mpw (Mac MPW) are
+ for bootstrapping. Once jam is built, it can rebuild itself.
+
+ UNIX
+
+ Build jam with make(1) on:
+
+ Platform $(OS)
+ -------------------------
+ AIX AIX *
+ BSD/386 1.0 BSDI
+ COHERENT/386 COHERENT
+ DGUX 5.4 DGUX
+ FreeBSD FREEBSD
+ HPUX 9.0 HPUX
+ IRIX 5.0 IRIX
+ Linux LINUX
+ NEXTSTEP 3.2 NEXT
+ OSF/1 OSF
+ PTX V2.1.0 PTX
+ Solaris 2 SOLARIS *
+ SunOS4.1 SUNOS
+ Ultrix 4.2 ULTRIX
+ BeOS BEOS *
+
+ * requires editing Makefile
+
+ Windows
+
+ Build jam with nmake on:
+
+ Platform $(OS)
+ -------------------------
+ NT NT *
+ OS/2 OS2 *
+
+ The NT MAXLINE (command line length) is still set in jam.h to
+ 996, which was apparently the NT 3.5 limit. On 4.0, the limit
+ is somewhere around 10K. For now, you can increase MAXLINE in
+ jam.h so that a jam running on 4.0 will use the full command
+ line length, but that jam.exe will fail miserably on the older OS.
+
+ On NT, a variable must be set before invoking jam to tell
+ it where the C compiler lives. The name of this variable
+ depends on which compiler you are using:
+
+ BCCROOT: The Borland C compiler
+ MSVCNT: The Microsoft Compiler 5.0 (for NT)
+ MSVC: The Microsoft Compiler 1.5 (for Windows)
+
+ Only MSVCNT has really been tested and is known to work.
+
+ Macintosh
+
+ Build jam with Build.mpw on:
+
+ Platform $(OS)
+ -------------------------
+ Macintosh MAC
+
+ You'll need to edit Build.mpw to set CW.
+
+ VMS
+
+ Build jam with @build.com on:
+
+ Platform $(OS)
+ -------------------------
+ VMS 5.4 VMS
+ OPENVMS OPENVMS
+
+Comments to the author!
+
+November, 1993 - release 1.0
+March, 1995 - release 2.0
+February, 1996 - release 2.1
+November, 1997 - release 2.2
+December, 2000 - release 2.3
+
+Christopher Seiwald
+
+seiwald@perforce.com
diff --git a/historic/jam/src/RELNOTES b/historic/jam/src/RELNOTES
new file mode 100644
index 000000000..47b7bfe69
--- /dev/null
+++ b/historic/jam/src/RELNOTES
@@ -0,0 +1,754 @@
+Release notes for FTJam 2.3.5 (previous release was named "20010626")
+
+0. Bugs fixed since 20010626:
+
+ DEBUG OUTPUT FORMATTING: indentation was "wrapped" when too many levels
+ were reached, making debugging extremly difficult
+
+1. Release info:
+
+ FTJam 2.3.5 (based on Jam 2.3.2)
+ July 30, 2001
+ VERSION 2.3.5
+ PATCHLEVEL 3
+
+2. Compatibility
+
+ FTJam 2.3.5 is upward compatible with Jam 2.3 and 2.2
+ Only a few new builtin rules were added, and some small bugs fixed
+
+3. Changes since 20010626:
+
+ Added a new builtin named FAIL_EXPECTED. It is used to invert the result
+ of a given action. Used by the Boost.Build sub-system.
+
+============================================================================
+============================================================================
+
+
+Release notes for Jam/MR 2.3
+(aka Jam - make(1) redux)
+
+0. Bugs fixed since 2.3.1
+
+ PATCHLEVEL 2 - 3/12/2001
+
+ NOCARE changed back: it once again does not applies to targets
+ with sources and/or actions. In 2.3 it was changed to apply to
+ such targets, but that broke header file builds: files that are
+ #included get marked with NOCARE, but if they have source or
+ actions, they still should get built.
+
+1. Release info:
+
+ Jam/MR 2.3
+ November 16, 2000
+ VERSION 2.3
+ PATCHLEVEL 1
+
+2. Compatibility
+
+ Jam 2.3 is upward compatible with Jam 2.2.
+
+ The Jam 2.3 language is a superset of the 2.2 language;
+ Jamfiles, Jambase, and other rulesets used in 2.2 can be used
+ with the 2.3 language support.
+
+3. Changes since 2.2
+
+3.1. Changes to Jam Language
+
+ Rules now can have values, which can expanded into a list with
+ the new "[ rule args ... ]" syntax. A rule's value is the value
+ of its last statement, though only the following statements have
+ values: if (value of the leg chosen), switch (ditto), set (value
+ of the resulting variable), return (its arguments). Note that
+ 'return' doesn't actually return. This support is EXPERIEMENTAL
+ and otherwise undocumented. (2.3.1)
+
+ Because of the new way lists are processed, if a rule has no
+ targets a warning message is no longer issued.
+
+ NOCARE now applies to targets with sources and/or actions,
+ rather than just those without.
+
+3.2. Jambase Changes
+
+ The HDRPATTERN variable now allows for leading blanks before
+ the #include, to keep up with ANSI. By john@nanaon-sha.co.jp
+ (John Belmonte) (2.2.3).
+
+ HDRPATTERN has been adjusted to avoid mistaking cases like:
+
+ # include /* could be */
+
+ MkDir now NOUPDATE's $(DOT), so that there are no dependencies
+ on the current directory's timestamp. By john@nanaon-sha.co.jp
+ (John Belmonte).
+
+ The old mock functions like makeDirName, which assigned their
+ results to the variable named as their first argument, have
+ been replaced with real functions using the new [] synxtax.
+ E.g. "makeDirName foo : bar ola" is now "foo = [ fDirName bar ]"
+
+ Install now always does a cp/chmod/etc, rather than using
+ the system's install(1), which invariably seems broken.
+
+3.3. Jam internal code changes
+
+ $JAMUNAME is set on UNIX. (2.2.4).
+
+ Jam ANSI-fied (2.3.0).
+
+ jam.h now defines a bunch of symbols used by the other source
+ files, so as minimize compiler- and platform-specific ifdefs.
+
+ OSVER is no longer set by jam.h (it was only set for AIX).
+ Jam does not depend on this variable at all, except to set
+ $(OSFULL), which is used to determine jam's build directory.
+ If the user needs to distinguish between various revs of
+ OSs, he must set OSVER in the environment.
+
+4. Fixed bugs
+
+ Redefining a rule while it was executing could cause jam to
+ crash. Reference counts are now used to prevent that, thanks
+ to Matt Armstrong.
+
+ Logic for computing chunk size when executing PIECEMEAL rules
+ has been reworked to be a little more accurate, without danger
+ of overflow, at the cost of being a little more compute intensive.
+ Instead of computing an estimate chunksize in the (now gone)
+ make1chunk(), make1cmds() now just goes full bore and tries to
+ use all args. When that fails, it backs off by 10% of the source
+ args until the command fits. It takes a little bit more compute
+ time compared to the old logic, but when you're executing actions
+ to build all of Shinola it's still pretty small in the scheme
+ of things.
+
+ The NT handle leak in execunix.c has been fixed, thanks to
+ Gurusamy Sarathy. (2.2.1).
+
+5. Porting
+
+ Platforms newly supported or updated:
+
+ AmigaOS (with gcc), courtesy of Alain Penders (2.2.2).
+
+ Beos
+
+ CYGWIN 1.1.4, courtesy of John Belmonte .
+
+ IBM AS400 via Visual Age on NT (primitive)
+
+ IBM OS/390 Unix System Services
+
+ Linux SuSE on OS390
+
+ Linux Mips, ARM
+
+ Lynx
+
+ HPUX 11, IA64
+
+ Mac OS X Server, courtesy of Jeff_Sickel@sickel.com (2.2.5).
+
+ Mac Rhapsody
+
+ MPE IX 6.0
+
+ NetBSD
+
+ QNX RTP (QNX 6.0)
+
+ Siemens Sinix
+
+ UNICOS
+
+ VMS 6.2, 7.1
+
+ Windows NT IA64
+
+5.1. NT Porting Notes
+
+ Always create tmp .bat file for actions if JAMSHELL is set.
+ That way, if JAMSHELL is a .bat file itself, it can handle
+ single-command actions with more than 9 cmd line args.
+
+ COMSPEC is no longer examined: cmd.exe is always used
+ instead. Only cmd.exe can execute the Jambase rules anyhow.
+
+ Jam can be built with Borland C++ 5.5.
+
+ OS2 fixes: InstallBin now works. Filenames are now downshifted,
+ so mixed case works better there, too. file_dirscan() can now scan
+ the root ("c:\" or "\") directory, which it couldn't handle before.
+
+ var_defines now ignores OS=Windows_NT, because it conflicts
+ with Jam's setting of OS (to NT).
+
+5.2. Mac OS 8/9 Notes
+
+ The support for Mac is curious at best. It runs under MPW.
+
+ It requires CodeWarrior Pro 5, but no longer requires GUSI.
+
+ Use Build.mpw to bootstrap the build.
+
+ The Mac specific definitions in the Jambase are not intended
+ to be of general purpose, but are sufficient to have Jam build
+ itself.
+
+===============================================================================
+===============================================================================
+
+
+Release Notes for Jam 2.2
+
+1. Release info:
+
+ Jam 2.2
+ October 22, 1997
+ VERSION 2.2
+ PATCHLEVEL 1
+
+2. Compatibility
+
+ Jam 2.2 is a roll-up of 'Jam - make(1) redux' release 2.1+.
+ Most of the changes described below were available before this,
+ in the jam.2.1.plus.tar ball.
+
+ The Jam 2.2 language is a superset of the 2.1 language;
+ Jamfiles, Jambase, and other rulesets used in 2.1 can be used
+ with the 2.2 language support.
+
+ See 'Jambase Changes', below, to see if your Jamfiles need any
+ changes to work with the 2.2 Jambase.
+
+
+3. Changes Since 2.1
+
+ New product name: Jam. (Executable program is still named 'jam'.)
+
+ Documentation rewritten; HTML versions supplied.
+
+
+3.1 Changes to Jam Language (See Jamlang.html)
+
+ Rules may now have more fields than just $(<) and $(>).
+
+ Local variables are now supported.
+
+ The expression 'if $(A) in $(B)' is now supported.
+
+ New variable modifiers :U and :L result in uppercased or lowercased
+ values.
+
+ New variable modifier :P reliably results in parent directory
+ of either a file or directory. (Previously, :D was used, but on VMS
+ :D of a directory name is just the directory name.)
+
+ The :S variable modifier now results in the _last_ suffix if a
+ filename has more than one dot (.) in it.
+
+ New predefined $(JAMDATE) variable is initialized at runtime for
+ simple date stamping.
+
+ New predefined variables $(OSVER) and $(OSPLAT) are used to
+ distinguish among operating system versions and hardware platforms,
+ when possible.
+
+ New 'bind' qualifier on action definitions allows variables
+ other than $(<) and $(>) to be bound with SEARCH and LOCATE paths.
+
+ Action buffer size is no longer limited by MAXCMD. Instead, each
+ line in an action is limited by MAXLINE, defined for each OS, and
+ the entire action size is limited by CMDBUF.
+
+
+3.2 Jambase Changes (See Jamfile.html)
+
+ Jambase has been reworked to incorporate new language features.
+
+ A handful of new utility rules has been added: makeString,
+ makeDirName, etc.
+
+ New HDRGRIST variable in Jambase allows for headers with the same
+ name to be distinguished.
+
+ LOCATE_TARGET now has a new flavor, LOCATE_SOURCE, that is used by
+ rules that generate source files (e.g., Yacc and Lex).
+
+ Header file includes now happen in the proper order. The limit of
+ 10 include files has been eliminated.
+
+ The old "Install" rule is no longer available. Use InstallBin,
+ InstallFile, InstallLib, InstallMan, or InstallShell instead.
+
+
+3.3 'jam' Changes (See Jam.html)
+
+ 'jam' can now be built as a stand-alone program, with Jambase
+ compiled into the executable. An external or alternate Jambase can
+ still be referenced explicitly with -f.
+
+ On command failure, 'jam' now emits the text of the command that
+ failed. This is a compromise between the normal -d1 behavior (where
+ commands were never seen) and -d2 (where commands are always seen).
+
+ 'jam' now exits non-zero if it doesn't have a total success. A parse
+ error, sources that can't be found, and targets that can't be built
+ all generate non-zero exit status.
+
+ The debugging levels (-d flags) have been slightly redefined.
+
+ The supplied Jamfile now builds 'jam' into a platform specific
+ subdirectory. This lets you use the same source directory to
+ build 'jam' for more than one platform.
+
+ The supplied Jamfile does not rebuild generated source files by
+ default. (They are supplied with the distribution.) See Jamfile
+ for more information.
+
+
+4. Fixed Bugs
+
+ The 'include' bug has finally been fixed, so that include
+ statements take effect exactly when they are executed,
+ rather than after the current statement block. This also
+ corrects the problem where an 'include' within an 'if'
+ block would wind up including the file one token after the
+ 'if' block's closing brace. Credit goes to Thomas Woods
+ for suggesting that the parse tree generation and parse
+ tree execution be paired in their own loop, rather than
+ having the parser execute the tree directly.
+
+ The setting and extracting of grist has been regularized:
+ normally, if you set a component of a filename (using the
+ :DBSMG= modifiers), you are supposed to include the delimiters
+ that set off the component: that is, you say "$(x:S=.suffix)",
+ including the ".". But with grist it was inconsistent
+ between setting and getting: setting grist required no
+ <>'s, while getting grist included them. Getting grist
+ continues to return the <>'s, but now setting grist can
+ either include them (the new way) or not (the old way).
+
+ 'actions together' now suppresses duplicate sources from
+ showing up in $(>).
+
+ Accessing variables whose names contained ['s (as happens with
+ MkDir on VMS) wasn't working, because it treated the [ as an
+ array subscript. Now [ and ] are, like :, handled specially so
+ that they can appear in variable values.
+
+ The 'if' statement now compares all elements in expressions;
+ previously, it only compared the first element of each list.
+
+ If a command line in an action is longer than MAXLINE (formerly
+ MAXCMD), 'jam' now issues an error and exits rather than dumping
+ core.
+
+ If a Jamfile ended without a trailing newline, jam dumped core.
+ This has been fixed.
+
+
+5. Porting
+
+ See jam.h for the definitive list of supported platforms.
+ Since 2.1, support has been added for:
+
+ Macintosh MPW
+ Alpha VMS
+ Alpha NT
+ NT PowerPC
+ BeOS
+ MVS OE
+ UNIXWARE
+ QNX
+ SINIX (Nixdorf)
+ OS/2
+ Interactive UNIX (ISC), courtesy of Matthew Newhook
+
+
+5.1 NT Support Fixes
+
+ The NT command executor now handles multiple line actions, by writing
+ multi-line actions to a batch file and executing that.
+
+ Targets are universally lowercased on NT. (Matthew Newhook)
+
+ Concurrent process support is fully enabled for NT.
+ (Gurusamy Sarathy )
+
+ Path handling: Jam now knows that the directory component of "D:\"
+ is "D:\", just as on unix it knows that the directory component of
+ "/" is "/". It also now successfully gets the timestamp for "D:\"
+ or just plain "\".
+
+
+5.2 VMS Support Fixes
+
+ VMS support is much, much better now. The path name manipulation
+ routines (in pathvms.c) were more or less rewritten, and they now
+ handle the vagaries of combining directory and file names properly.
+
+ Targets are universally lowercased on VMS.
+
+ Multi-line command blocks on VMS are now executed in a single system()
+ call rather than separate ones for each line, so that actions can
+ be DCL scripts.
+
+===============================================================================
+===============================================================================
+
+
+Release notes for Jam 2.1.
+
+1. Release info:
+ Jam 2.1
+ February 1, 1996
+ VERSION 2.1
+ PATCHLEVEL 0
+
+2. Porting
+
+ Linux is now supported.
+
+ FREEBSD is now supported.
+
+ SCO ("M_XENIX") now supported.
+
+ NCR now supported.
+
+ NEXT support from karthy@dannug.dk (Karsten Thygesen)
+
+ DECC support from zinser@axp614.gsi.de (Martin P.J. Zinser)
+
+ I have changes for OS/2, but no way to test them. Volunteers?
+ I have VMS multiprocess support, but no way to test it. Volunteers?
+
+2.1. NT Support fixes.
+
+ The NT support is considerably more real than it was in 2.0.
+ Filent.c had its syntax error corrected, it no longer skips the
+ first entry when scanning directories, and it handles string
+ tables in archives (for long object file names).
+
+ The Jambase was changed a bit to support the various C/C++
+ compilers on NT, although it has only been thorougly tested
+ with MSVC20.
+
+ You still need to set MSVCNT or BCCROOT to the root of the
+ the compiler's directory tree, and you'll get an error if you
+ don't set it (rather than getting a pile of mysterious errors).
+
+2.2. Other porting fixes.
+
+ SPLITPATH now set up for UNIX (:), NT (;), VMS (,)
+
+ Jambase support for Solaris works better now: the location of
+ AR is hardwired to /usr/ccs/bin/ar and it knowns "install"
+ doesn't take -c. Solaris -- how the mighty have fallen.
+
+ To handle Linux's wacko yacc, jamgram.h is now included after
+ scan.h so that YYSTYPE is define.
+
+3. Jambase Changes (see Jamfile.html)
+
+ SubDir now computes the root directory for the source tree, if
+ the variable naming the root directory isn't set in the environment.
+ It counts the number of directory elements leading from the root
+ to the current directory (as passed to SubDir) and uses that many
+ "../"'s to identify the root. This means that to use SubDir you
+ no longer have to have anything special set in the environment.
+
+ InstallFile is now an alias for InstallLib.
+
+ 'first' is now dependency of all pseudo-targets (all, files,
+ exe, lib, shell), so that jamming any of these pseudo-targets
+ also builds any dependencies of 'first'.
+
+ The File rule definition in the Jambase was missing an &.
+
+ The File rule now calls the Clean rule, so that installed files
+ get cleaned.
+
+4. Jam changes (see Jam.html)
+
+ Variables may now be set on the command line with -svar=value.
+
+ Targets marked with NOUPDATE are now immune to the -a (anyhow)
+ flag. Previously, the MkDir rule would try to recreate directories
+ that already exist when jam was invoked with -a.
+
+ A new variable, $(JAMVERSION), joins the small list of built-in
+ variables. It it set to the release of jam, currently "2.1".
+
+ If an actions fails, jam now deletes the target(s). It won't
+ delete libraries or other targets that are composites. This is
+ now consistent with jam's behavior on interrupts (it deletes the
+ targets).
+
+ Jam had a nasty bug when setting multiple variables to the same
+ value: if the first two variable names were the same, the variable
+ value got trashed. This also affected "on target" variables if
+ the first two targets were the same. For example:
+
+ FOO on bar.c bar.c foo.c = a b c ;
+
+ This would mangle the value of FOO for bar.c and foo.c. This has
+ been fixed.
+
+ Jam would generate bogus numbers when reporting the number of
+ targets updated after an interrupt. It now is more careful about
+ counting.
+
+ The debugging flag -d has been extended. In addition to supporting
+ -dx (turn on debugging for all levels up to x) there is also now
+ -d+x (turn on debugging at only level x). The default output
+ level is -d1 (-or d2 if -n is given); this can be turned off with
+ -d0. The debug levels are listed in jam.1 and jam.h.
+
+ The parsing debug output now uses indenting to indicate when
+ one rule invokes another.
+
+===============================================================================
+===============================================================================
+
+
+Release notes for Jam 2.0.
+
+1. Release info:
+ Jam 2.0
+ March 10, 1994
+ VERSION 2.0
+ PATCHLEVEL 5
+
+2. Porting
+
+ Windows/NT is now (crudely) supported, courtesy of Brett Taylor
+ and Laura Wingerd.
+
+ COHERENT/386 is now supported, courtesy of Fred Smith.
+
+ Solaris archive string table for long archive names is now
+ supported, thanks to Mike Matrigali.
+
+3. Compatibility
+
+ Jam 2.0 syntax is a superset of Jam 1.0 syntax, and thus it can
+ interpret a Jam 1.0 Jambase.
+
+ The Jam 2.0 Jambase is a superset of the Jam 1.0 Jambase, and
+ thus it can include a Jamfile written for Jam 1.0.
+
+4. Changes from Jam 1.0 to Jam 2.0
+
+4.1. Documentation changes
+
+ New Jamfile.5 manual page, with lots of examples and easy
+ reading. It replaces both the old "Examples" file as well as
+ the old Jambase.5 manual page.
+
+ jam.1 edited by Stephen W. Liddle and Diane Holt.
+
+4.2. Jambase Changes (see Jamfile.5)
+
+4.2.1. New rules:
+
+ There are new rules to make handling subdirectories easier:
+ SubDir, SubInclude, SubDirCcFlags, SubDirHdrs.
+
+ There are new rules to handle file-specific CCFLAGS and HDRS:
+ ObjectCcFlags and ObjectHdrs.
+
+ Misc new rules: HardLink, InstallShell, MkDir.
+
+ New rule "clean" that deletes exactly what jam has built, and
+ "uninstall" that deletes exactly what was installed.
+
+ New rules for handling suffixes .s, .f, .cc, .cpp, .C.
+
+4.2.2. Old rules:
+
+ The InstallBin, Lib, Man, and the new Shell rules now take the
+ destination directory as the target and the files to be copied
+ as sources. These rules formerly took the files to be copied
+ as targets, and used built-in destination directories of
+ $(BINDIR), $(LIBDIR), $(MANDIR), and $(BINDIR).
+
+ The InstallBin, Lib, Man, and Shell rules use the install(1)
+ program now, instead of doing their own copying.
+
+ The Cc rule now uses -o when possible, rather than moving the
+ result. Some platforms (Pyramid?) have a broken -o.
+
+ Jambase rules taking libraries, objects, and executables now
+ all ignore the suffixes provided and use the one defined in the
+ Jambase for the platform.
+
+ Stupid yyacc support moved out of Jambase, as jam is its only
+ likely user.
+
+ Jambase now purturbs library sources with a "grist" of
+ SOURCE_GRIST.
+
+4.2.3. Misc:
+
+ The names of the default rules defined in Jambase have been
+ lowercased and un-abbreviated, to be more imake(1) like.
+
+ The Jambase has been reorganized and sorted, with VMS and NT
+ support moved in from their own files.
+
+ The Jambase has been relocated on UNIX from /usr/local/lib/jam
+ to /usr/local/lib.
+
+4.3. Jam changes (see jam.1)
+
+4.3.1. Flags:
+
+ New -a (anyhow) flag: means build everything.
+
+ New -j flag: run jobs in parallel.
+
+ Old -t now rebuilds the touched target, rather that just the
+ target's parents.
+
+ -n now implies -d2, so that you see what's happening. The
+ debug level can be subsequently overridden.
+
+ New -v to dump version.
+
+4.3.2. Rules:
+
+ New ALWAYS rule behaves like -t: always builds target.
+
+ New EXIT rule makes it possible to raise a fatal error.
+
+ New LEAVES rule which say target depends only on the update
+ times of the leaf sources.
+
+ New NOUPDATE rule says built targets only if they don't exist.
+
+ NOTIME has been renamed NOTFILE, to more accurately reflect its
+ meaning (it says a target is not to be bound to a file).
+
+4.3.3. Variables:
+
+ New special variable JAMSHELL: argv template for command execution
+ shell.
+
+ Variables, both normal and target-specific, can have their
+ value appended with the syntax "var += value" or "var on target
+ += value".
+
+ "?=" is now synonymous with "default =".
+
+ Imported enviroment variable values are now split at blanks
+ (:'s if the variable name ends in PATH), so that they become
+ proper list values.
+
+4.3.4. Misc:
+
+ Files to be sourced with "include" are now bound first, so
+ $(SEARCH) and $(LOCATE) affect them. They still can't be
+ built, though.
+
+ New modifier on "actions": "existing" causes $(>) to expand
+ only those files that currently exist.
+
+4.3.5. Bug fixes:
+
+ When scanning tokens known to be argument lists (such as the
+ arguments to rule invocations and variable assignment), the
+ parser now tells the scanner to ignore alphabetic keywords, as
+ all such lists terminate with punctuation keywords (like : or
+ ;). This way, alphabetic keywords don't need to be quoted when
+ they appear as arguments.
+
+ The scanner has been fixed to handle oversized tokens,
+ unterminated quotes, unterminated action blocks, and tokens
+ abutting EOF (i.e. a token with no white space before EOF).
+
+ The progress report "...on xth target..." used to count all
+ targets, rather than just those with updating actions. Since
+ the original pronouncement of targets to be udpated included
+ only those with updating actions, the progress report has been
+ changed to match.
+
+ 'If' conditionals now must be single arguments. Previously,
+ they could be zero or more arguments, which didn't make much
+ sense, and made things like 'foo == bar' true. The comparison
+ operator is '=', and '==' just looked like the second of three
+ arguments in the unary "non-empty argument list" conditional.
+
+ Header files indirectly including themselves were mistakenly
+ reported as being dependent on themselves. Recursing through
+ header file dependencies is now done after determining the fate
+ of the target.
+
+ The variable expansion support was expanding $(X)$(UNDEF) as if
+ it were $(X). It now expands to an empty list, like it
+ should.
+
+ The UNIX version of file_build() didn't handle "dir/.suffix"
+ right. Now it does.
+
+ The VMS command buffer was assumed to be as large as 1024 bytes,
+ which isn't the case everywhere as it is related to some weird
+ quota. It has been lowered to 256.
+
+ $(>) and $(<) wouldn't expand in action blocks if the targets
+ were marked with NOTIME. Now they expand properly.
+
+ Malloc() return values are now checked.
+
+ The variable expansion routine var_expand() is now a little
+ faster, by taking a few often needed shortcuts.
+
+ The VMS version of file_build() used the wrong length when
+ re-rooting file names that already had directory compoents.
+ This was fixed.
+
+ Various tracing adjustments were made.
+
+5. Limitations/Known Bugs
+
+ The new Windows/NT support has only been marginally tested. It
+ is dependent on certain variables being set depending on which
+ compiler you are using. You'll need to look in the file
+ Jambase and see what variables are expected to be set.
+
+ The VMS support has been tested, courtesy of the DEC guest
+ machine, but has not been hammered fully in release 2.0. It
+ was used quite a bit in Jam 1.0.
+
+ Jam clean when there is nothing to clean claims it is updating
+ a target.
+
+ Because the include statement works by pushing a new file in
+ the input stream of the scanner rather than recursively
+ invoking the parser on the new file, multiple include
+ statements in a rule's procedure causes the files to be
+ included in reverse order.
+
+ If the include statement appears inside an if block, the
+ parser's attempt to find the else will cause the text of the
+ included file to appear after the first token following the
+ statement block. This is rarely what is intended.
+
+ In a rule's actions, only $(<) and $(>) refer to the bound file
+ names: all other variable references get the unbound names.
+ This is a pain for $(NEEDLIBS), because it means that library
+ path can't be bound using $(SEARCH) and $(LOCATE).
+
+ With the -j flag, errors from failed commands can get
+ staggeringly mixed up. Also, because targets tend to get built
+ in a quickest-first ordering, dependency information must be
+ quite exact. Finally, beware of parallelizing commands that
+ drop fixed-named files into the current directory, like yacc(1)
+ does.
+
+ A poorly set $(JAMSHELL) is likely to result in silent
+ failure.
diff --git a/historic/jam/src/command.c b/historic/jam/src/command.c
new file mode 100644
index 000000000..c05ce3601
--- /dev/null
+++ b/historic/jam/src/command.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * command.c - maintain lists of commands
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "rules.h"
+
+# include "command.h"
+# include
+
+/*
+ * cmd_new() - return a new CMD or 0 if too many args
+ */
+
+CMD *
+cmd_new(
+ RULE *rule,
+ LIST *targets,
+ LIST *sources,
+ LIST *shell )
+{
+ CMD *cmd = (CMD *)malloc( sizeof( CMD ) );
+ /* lift line-length limitation entirely when JAMSHELL is just "%" */
+ int expand_line = ( shell && !strcmp(shell->string,"%") && !list_next(shell) );
+ int max_line = MAXLINE;
+ int allocated = -1;
+
+ cmd->rule = rule;
+ cmd->shell = shell;
+ cmd->next = 0;
+
+ lol_init( &cmd->args );
+ lol_add( &cmd->args, targets );
+ lol_add( &cmd->args, sources );
+ cmd->buf = 0;
+
+ do
+ {
+ free(cmd->buf); /* free any buffer from previous iteration */
+
+ cmd->buf = (char*)malloc(max_line + 1);
+
+ if (cmd->buf == 0)
+ break;
+
+ allocated = var_string( rule->actions->command, cmd->buf, max_line, &cmd->args );
+
+ max_line = max_line * 2;
+ }
+ while( expand_line && allocated < 0 && max_line < INT_MAX / 2 );
+
+ /* Bail if the result won't fit in MAXLINE */
+ /* We don't free targets/sources/shell if bailing. */
+ if( allocated < 0 )
+ {
+ cmd_free( cmd );
+ cmd = 0;
+ }
+
+ return cmd;
+}
+
+/*
+ * cmd_free() - free a CMD
+ */
+
+void
+cmd_free( CMD *cmd )
+{
+ lol_free( &cmd->args );
+ list_free( cmd->shell );
+ free( cmd->buf );
+ free( (char *)cmd );
+}
diff --git a/historic/jam/src/command.h b/historic/jam/src/command.h
new file mode 100644
index 000000000..6e4752ffe
--- /dev/null
+++ b/historic/jam/src/command.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1994 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * command.h - the CMD structure and routines to manipulate them
+ *
+ * Both ACTION and CMD contain a rule, targets, and sources. An
+ * ACTION describes a rule to be applied to the given targets and
+ * sources; a CMD is what actually gets executed by the shell. The
+ * differences are due to:
+ *
+ * ACTIONS must be combined if 'actions together' is given.
+ * ACTIONS must be split if 'actions piecemeal' is given.
+ * ACTIONS must have current sources omitted for 'actions updated'.
+ *
+ * The CMD datatype holds a single command that is to be executed
+ * against a target, and they can chain together to represent the
+ * full collection of commands used to update a target.
+ *
+ * Structures:
+ *
+ * CMD - an action, ready to be formatted into a buffer and executed
+ *
+ * External routines:
+ *
+ * cmd_new() - return a new CMD or 0 if too many args
+ * cmd_free() - delete CMD and its parts
+ * cmd_next() - walk the CMD chain
+ */
+
+/*
+ * CMD - an action, ready to be formatted into a buffer and executed
+ */
+
+typedef struct _cmd CMD;
+
+struct _cmd
+{
+ CMD *next;
+ CMD *tail; /* valid on in head */
+ RULE *rule; /* rule->actions contains shell script */
+ LIST *shell; /* $(SHELL) value */
+ LOL args; /* LISTs for $(<), $(>) */
+ char* buf; /* actual commands */
+} ;
+
+CMD *cmd_new(
+ RULE *rule, /* rule (referenced) */
+ LIST *targets, /* $(<) (freed) */
+ LIST *sources, /* $(>) (freed) */
+ LIST *shell ); /* $(SHELL) (freed) */
+
+void cmd_free( CMD *cmd );
+
+# define cmd_next( c ) ((c)->next)
diff --git a/historic/jam/src/common.mk b/historic/jam/src/common.mk
new file mode 100644
index 000000000..6abd3e86b
--- /dev/null
+++ b/historic/jam/src/common.mk
@@ -0,0 +1,17 @@
+# Common Makefile rules
+#
+
+# the Jam sources needed to build "jam0"
+#
+SOURCES = \
+ command.c compile.c execnt.c execunix.c execvms.c expand.c \
+ filent.c fileos2.c fileunix.c filevms.c glob.c hash.c \
+ hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c \
+ newstr.c option.c parse.c pathunix.c pathvms.c regexp.c \
+ rules.c scan.c search.c subst.c timestamp.c variable.c modules.c \
+ strings.c filesys.c
+
+# the bootstrap "jam0" build tool
+#
+jam0:
+ $(CC) $(TARGET) $(CFLAGS) $(SOURCES) $(LINKLIBS)
diff --git a/historic/jam/src/compile.c b/historic/jam/src/compile.c
new file mode 100644
index 000000000..93f3007ec
--- /dev/null
+++ b/historic/jam/src/compile.c
@@ -0,0 +1,1390 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/* This file is ALSO:
+ * (C) Copyright David Abrahams 2001. Permission to copy, use,
+ * modify, sell and distribute this software is granted provided this
+ * copyright notice appears in all copies. This software is provided
+ * "as is" without express or implied warranty, and with no claim as
+ * to its suitability for any purpose.
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "compile.h"
+# include "variable.h"
+# include "expand.h"
+# include "rules.h"
+# include "newstr.h"
+# include "make.h"
+# include "search.h"
+# include "hdrmacro.h"
+# include "hash.h"
+# include "modules.h"
+# include "strings.h"
+
+# include
+# include
+
+/*
+ * compile.c - compile parsed jam statements
+ *
+ * External routines:
+ *
+ * compile_append() - append list results of two statements
+ * compile_foreach() - compile the "for x in y" statement
+ * compile_if() - compile 'if' rule
+ * compile_while() - compile 'while' rule
+ * compile_include() - support for 'include' - call include() on file
+ * compile_list() - expand and return a list
+ * compile_local() - declare (and set) local variables
+ * compile_null() - do nothing -- a stub for parsing
+ * compile_rule() - compile a single user defined rule
+ * compile_rules() - compile a chain of rules
+ * compile_set() - compile the "set variable" statement
+ * compile_setcomp() - support for `rule` - save parse tree
+ * compile_setexec() - support for `actions` - save execution string
+ * compile_settings() - compile the "on =" (set variable on exec) statement
+ * compile_switch() - compile 'switch' rule
+ *
+ * Internal routines:
+ *
+ * debug_compile() - printf with indent to show rule expansion.
+ *
+ * evaluate_if() - evaluate if to determine which leg to compile
+ * evaluate_rule() - execute a rule invocation
+ *
+ * builtin_depends() - DEPENDS/INCLUDES rule
+ * builtin_echo() - ECHO rule
+ * builtin_exit() - EXIT rule
+ * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
+ *
+ * 02/03/94 (seiwald) - Changed trace output to read "setting" instead of
+ * the awkward sounding "settings".
+ * 04/12/94 (seiwald) - Combined build_depends() with build_includes().
+ * 04/12/94 (seiwald) - actionlist() now just appends a single action.
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 05/13/94 (seiwald) - include files are now bound as targets, and thus
+ * can make use of $(SEARCH)
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
+ * 01/22/95 (seiwald) - Exit rule.
+ * 02/02/95 (seiwald) - Always rule; LEAVES rule.
+ * 02/14/95 (seiwald) - NoUpdate rule.
+ * 09/11/00 (seiwald) - new evaluate_rule() for headers().
+ * 09/11/00 (seiwald) - compile_xxx() now return LIST *.
+ * New compile_append() and compile_list() in
+ * support of building lists here, rather than
+ * in jamgram.yy.
+ */
+
+static void debug_compile( int which, char *s );
+
+static int evaluate_if( PARSE *parse, FRAME *frame );
+
+static LIST *builtin_depends( PARSE *parse, FRAME *frame );
+static LIST *builtin_echo( PARSE *parse, FRAME *frame );
+static LIST *builtin_exit( PARSE *parse, FRAME *frame );
+static LIST *builtin_flags( PARSE *parse, FRAME *frame );
+static LIST *builtin_hdrmacro( PARSE *parse, FRAME *frame );
+static LIST *builtin_import( PARSE *parse, FRAME *frame );
+static LIST *builtin_caller_module( PARSE *parse, FRAME *frame );
+LIST *builtin_subst( PARSE *parse, FRAME *frame );
+
+int glob( char *s, char *c );
+
+
+void frame_init( FRAME* frame )
+{
+ frame->prev = 0;
+ lol_init(frame->args);
+ frame->module = root_module();
+}
+
+void frame_free( FRAME* frame )
+{
+ lol_free( frame->args );
+}
+
+/*
+ * compile_builtin() - define builtin rules
+ */
+
+# define P0 (PARSE *)0
+# define C0 (char *)0
+
+static void lol_build( LOL* lol, char** elements )
+{
+ LIST* l = L0;
+ lol_init( lol );
+
+ while ( elements && *elements )
+ {
+ if ( !strcmp( *elements, ":" ) )
+ {
+ lol_add( lol, l );
+ l = L0 ;
+ }
+ else
+ {
+ l = list_new( l, newstr( *elements ) );
+ }
+ ++elements;
+ }
+
+ if ( l != L0 )
+ lol_add( lol, l );
+}
+
+static RULE* bind_builtin( char* name, LIST*(*f)(PARSE*, FRAME*), int flags, char** args )
+{
+ argument_list* arg_list = 0;
+ RULE* builtin_rule;
+
+ if ( args )
+ {
+ arg_list = args_new();
+ lol_build( arg_list->data, args );
+ }
+
+ return new_rule_body( root_module(), name, arg_list,
+ parse_make( f, P0, P0, P0, C0, C0, flags ) );
+}
+
+static RULE* duplicate_rule( char* name, RULE* other )
+{
+ return import_rule( other, root_module(), name );
+}
+
+void
+compile_builtins()
+{
+ duplicate_rule( "Always", bind_builtin( "ALWAYS", builtin_flags, T_FLAG_TOUCHED, 0 ) );
+ duplicate_rule( "Depends", bind_builtin( "DEPENDS", builtin_depends, T_DEPS_DEPENDS, 0 ) );
+ duplicate_rule( "Echo", bind_builtin( "ECHO", builtin_echo, 0, 0 ) );
+ duplicate_rule( "Exit", bind_builtin( "EXIT", builtin_exit, 0, 0 ) );
+ duplicate_rule( "Includes", bind_builtin( "INCLUDES", builtin_depends, T_DEPS_INCLUDES, 0 ) );
+ duplicate_rule( "HdrMacro", bind_builtin( "HDRMACRO", builtin_hdrmacro, 0, 0 ) );
+ duplicate_rule( "Leaves", bind_builtin( "LEAVES", builtin_flags, T_FLAG_LEAVES, 0 ) );
+ duplicate_rule( "NoCare", bind_builtin( "NOCARE", builtin_flags, T_FLAG_NOCARE, 0 ) );
+ duplicate_rule( "NOTIME",
+ duplicate_rule( "NotFile",
+ bind_builtin( "NOTFILE", builtin_flags, T_FLAG_NOTFILE, 0 ) ) );
+
+ duplicate_rule( "NoUpdate", bind_builtin( "NOUPDATE", builtin_flags, T_FLAG_NOUPDATE, 0 ) );
+ duplicate_rule( "Temporary", bind_builtin( "TEMPORARY", builtin_flags, T_FLAG_TEMP, 0 ) );
+
+ /* FAIL_EXPECTED is an experimental built-in that is used to indicate */
+ /* that the result of a target build action should be inverted (ok <=> fail) */
+ /* this can be useful when performing test runs from Jamfiles.. */
+ /* */
+ /* Beware that this rule might disappear or be renamed in the future.. */
+ /* contact david.turner@freetype.org for more details.. */
+ bind_builtin( "FAIL_EXPECTED", builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
+
+ {
+ char* args[] = { "string", "pattern", "replacements", "+", 0 };
+ duplicate_rule( "subst", bind_builtin( "SUBST", builtin_subst, 0, args ) );
+ }
+
+ {
+ char* args[] = {
+ "target_module", "?"
+ , ":", "source_module", "?"
+ , ":", "rule_names", "*"
+ , ":", "target_names", "*", 0
+ };
+
+ bind_builtin( "IMPORT", builtin_import, 0, args );
+ }
+
+ {
+ char* args[] = { 0 };
+ bind_builtin( "CALLER_MODULE", builtin_caller_module, 0, args );
+ }
+}
+
+/*
+ * compile_append() - append list results of two statements
+ *
+ * parse->left more compile_append() by left-recursion
+ * parse->right single rule
+ */
+
+LIST *
+compile_append(
+ PARSE *parse,
+ FRAME *frame )
+{
+ /* Append right to left. */
+
+ return list_append(
+ (*parse->left->func)( parse->left, frame ),
+ (*parse->right->func)( parse->right, frame ) );
+}
+
+/*
+ * compile_foreach() - compile the "for x in y" statement
+ *
+ * Compile_foreach() resets the given variable name to each specified
+ * value, executing the commands enclosed in braces for each iteration.
+ *
+ * parse->string index variable
+ * parse->left variable values
+ * parse->right rule to compile
+ */
+
+LIST *
+compile_foreach(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nv = (*parse->left->func)( parse->left, frame );
+ LIST *l;
+ SETTINGS *s = 0;
+
+ if ( parse->num )
+ {
+ s = addsettings( s, 0, parse->string, L0 );
+ pushsettings( s );
+ }
+
+ /* Call var_set to reset $(parse->string) for each val. */
+
+ for( l = nv; l; l = list_next( l ) )
+ {
+ LIST *val = list_new( L0, copystr( l->string ) );
+
+ var_set( parse->string, val, VAR_SET );
+
+ list_free( (*parse->right->func)( parse->right, frame ) );
+ }
+
+ if ( parse->num )
+ popsettings( s );
+
+ list_free( nv );
+
+ return L0;
+}
+
+/*
+ * compile_if() - compile 'if' rule
+ *
+ * parse->left condition tree
+ * parse->right then tree
+ * parse->third else tree
+ */
+
+LIST *
+compile_if(
+ PARSE *p,
+ FRAME *frame )
+{
+ if( evaluate_if( p->left, frame ) )
+ {
+ return (*p->right->func)( p->right, frame );
+ }
+ else
+ {
+ return (*p->third->func)( p->third, frame );
+ }
+}
+
+LIST *
+compile_while(
+ PARSE *p,
+ FRAME *frame )
+{
+ while ( evaluate_if( p->left, frame ) )
+ {
+ list_free( (*p->right->func)( p->right, frame ) );
+ }
+ return L0;
+}
+
+/*
+ * evaluate_if() - evaluate if to determine which leg to compile
+ *
+ * Returns:
+ * !0 if expression true - compile 'then' clause
+ * 0 if expression false - compile 'else' clause
+ */
+
+static int
+evaluate_if(
+ PARSE *parse,
+ FRAME *frame )
+{
+ int status;
+
+ if( parse->num <= COND_OR )
+ {
+ /* Handle one of the logical operators */
+
+ switch( parse->num )
+ {
+ case COND_NOT:
+ status = !evaluate_if( parse->left, frame );
+ break;
+
+ case COND_AND:
+ status = evaluate_if( parse->left, frame ) &&
+ evaluate_if( parse->right, frame );
+ break;
+
+ case COND_OR:
+ status = evaluate_if( parse->left, frame ) ||
+ evaluate_if( parse->right, frame );
+ break;
+
+ default:
+ status = 0; /* can't happen */
+ }
+ }
+ else
+ {
+ /* Handle one of the comparison operators */
+ /* Expand targets and sources */
+
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+
+ /* "a in b" make sure each of a is equal to something in b. */
+ /* Otherwise, step through pairwise comparison. */
+
+ if( parse->num == COND_IN )
+ {
+ LIST *s, *t;
+
+ /* Try each t until failure. */
+
+ for( status = 1, t = nt; status && t; t = list_next( t ) )
+ {
+ int stat1;
+
+ /* Try each s until success */
+
+ for( stat1 = 0, s = ns; !stat1 && s; s = list_next( s ) )
+ stat1 = !strcmp( t->string, s->string );
+
+ status = stat1;
+ }
+ }
+ else
+ {
+ LIST *s = ns, *t = nt;
+
+ status = 0;
+
+ while( !status && ( t || s ) )
+ {
+ char *st = t ? t->string : "";
+ char *ss = s ? s->string : "";
+
+ status = strcmp( st, ss );
+
+ t = t ? list_next( t ) : t;
+ s = s ? list_next( s ) : s;
+ }
+ }
+
+ switch( parse->num )
+ {
+ case COND_EXISTS: status = status > 0 ; break;
+ case COND_EQUALS: status = !status; break;
+ case COND_NOTEQ: status = status != 0; break;
+ case COND_LESS: status = status < 0; break;
+ case COND_LESSEQ: status = status <= 0; break;
+ case COND_MORE: status = status > 0; break;
+ case COND_MOREEQ: status = status >= 0; break;
+ case COND_IN: /* status = status */ break;
+ }
+
+ if( DEBUG_IF )
+ {
+ debug_compile( 0, "if" );
+ list_print( nt );
+ printf( "(%d)", status );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ list_free( nt );
+ list_free( ns );
+
+ }
+
+ return status;
+}
+
+/*
+ * compile_include() - support for 'include' - call include() on file
+ *
+ * parse->left list of files to include (can only do 1)
+ */
+
+LIST *
+compile_include(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "include" );
+ list_print( nt );
+ printf( "\n" );
+ }
+
+ if( nt )
+ {
+ TARGET *t = bindtarget( nt->string );
+
+ /* DWA 2001/10/22 - Perforce Jam clears the arguments here, which
+ * prevents an included file from being treated as part of the body
+ * of a rule. I didn't see any reason to do that, so I lifted the
+ * restriction.
+ */
+
+ /* Bind the include file under the influence of */
+ /* "on-target" variables. Though they are targets, */
+ /* include files are not built with make(). */
+
+ pushsettings( t->settings );
+ t->boundname = search( t->name, &t->time );
+ popsettings( t->settings );
+
+ parse_file( t->boundname, frame );
+ }
+
+ list_free( nt );
+
+ return L0;
+}
+
+LIST *
+compile_module(
+ PARSE *p,
+ FRAME *frame )
+{
+ /* Here we are entering a module declaration block.
+ */
+ LIST* module_name = (*p->left->func)( p->left, frame );
+ LIST* result;
+
+ module* outer_module = frame->module;
+ frame->module = module_name ? bindmodule( module_name->string ) : root_module();
+
+ if ( outer_module != frame->module )
+ {
+ exit_module( outer_module );
+ enter_module( frame->module );
+ }
+
+ result = (*p->right->func)( p->right, frame );
+
+ if ( outer_module != frame->module )
+ {
+ exit_module( frame->module );
+ enter_module( outer_module );
+ frame->module = outer_module;
+ }
+
+ list_free( module_name );
+ return result;
+}
+
+
+/*
+ * compile_list() - expand and return a list
+ *
+ * parse->string - character string to expand
+ */
+
+LIST *
+compile_list(
+ PARSE *parse,
+ FRAME *frame )
+{
+ /* voodoo 1 means: s is a copyable string */
+ char *s = parse->string;
+ return var_expand( L0, s, s + strlen( s ), frame->args, 1 );
+}
+
+/*
+ * compile_local() - declare (and set) local variables
+ *
+ * parse->left list of variables
+ * parse->right list of values
+ * parse->third rules to execute
+ */
+
+LIST *
+compile_local(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *l;
+ SETTINGS *s = 0;
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+ LIST *result;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "local" );
+ list_print( nt );
+ printf( " = " );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Initial value is ns */
+
+ for( l = nt; l; l = list_next( l ) )
+ s = addsettings( s, 0, l->string, list_copy( (LIST*)0, ns ) );
+
+ list_free( ns );
+ list_free( nt );
+
+ /* Note that callees of the current context get this "local" */
+ /* variable, making it not so much local as layered. */
+
+ pushsettings( s );
+ result = (*parse->third->func)( parse->third, frame );
+ popsettings( s );
+
+ freesettings( s );
+
+ return result;
+}
+
+/*
+ * compile_null() - do nothing -- a stub for parsing
+ */
+
+LIST *
+compile_null(
+ PARSE *parse,
+ FRAME *frame )
+{
+ return L0;
+}
+
+/*
+ * compile_rule() - compile a single user defined rule
+ *
+ * parse->string name of user defined rule
+ * parse->left parameters (list of lists) to rule, recursing left
+ *
+ * Wrapped around evaluate_rule() so that headers() can share it.
+ */
+
+LIST *
+compile_rule(
+ PARSE *parse,
+ FRAME *frame )
+{
+ FRAME inner[1];
+ LIST *result;
+ PARSE *p;
+
+
+ /* Build up the list of arg lists */
+
+ frame_init( inner );
+ inner->prev = frame;
+ inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below */
+
+ for( p = parse->left; p; p = p->left )
+ lol_add( inner->args, (*p->right->func)( p->right, frame ) );
+
+ /* And invoke rule */
+
+ result = evaluate_rule( parse->string, inner );
+
+ frame_free( inner );
+
+ return result;
+}
+
+static void argument_error( char* message, RULE* rule, LOL* actual, LIST* arg )
+{
+ printf( "### argument error\n# rule %s ( ", rule->name );
+ lol_print( rule->arguments->data );
+ printf( ")\n# called with: ( " );
+ lol_print( actual );
+ printf( ")\n# %s %s", message, arg ? arg->string : "" );
+ printf("\n");
+ exit(1);
+}
+
+
+/*
+ * collect_arguments() - local argument checking and collection
+ */
+static SETTINGS *
+collect_arguments( RULE* rule, LOL* all_actual )
+{
+ SETTINGS *locals = 0;
+
+ LOL *all_formal = rule->arguments ? rule->arguments->data : 0;
+ if ( all_formal ) /* Nothing to set; nothing to check */
+ {
+ int max = all_formal->count > all_actual->count
+ ? all_formal->count
+ : all_actual->count;
+
+ int n;
+ for ( n = 0; n < max ; ++n )
+ {
+ LIST *formal = lol_get( all_formal, n );
+ LIST *actual = lol_get( all_actual, n );
+ while ( formal )
+ {
+ char* name = formal->string;
+ char modifier = 0;
+ LIST* value = 0;
+ if ( formal->next )
+ {
+ char *next = formal->next->string;
+ if ( next && next[0] != 0 && next[1] == 0 )
+ modifier = next[0];
+ }
+
+ if ( !actual && modifier != '?' && modifier != '*' )
+ {
+ argument_error( "missing argument", rule, all_actual, formal );
+ }
+
+ switch ( modifier )
+ {
+ case '+':
+ case '*':
+ value = list_copy( 0, actual );
+ actual = 0;
+ /* skip an extra element for the modifier */
+ formal = formal->next;
+ break;
+ case '?':
+ /* skip an extra element for the modifier */
+ formal = formal->next;
+ /* fall through */
+ default:
+ if ( actual ) /* in case actual is missing */
+ {
+ value = list_new( 0, actual->string );
+ actual = actual->next;
+ }
+ }
+
+ locals = addsettings( locals, 0, name, value );
+ formal = formal->next;
+ }
+
+ if ( actual )
+ {
+ argument_error( "extra argument", rule, all_actual, actual );
+ }
+ }
+ }
+ return locals;
+}
+
+struct profile_info
+{
+ char* name; /* name of rule being called */
+ clock_t cumulative; /* cumulative time spent in rule */
+ clock_t subrules; /* time spent in subrules */
+ unsigned long num_entries; /* number of time rule was entered */
+};
+typedef struct profile_info profile_info;
+
+struct profile_frame
+{
+ profile_info* info; /* permanent storage where data accumulates */
+ clock_t overhead; /* overhead for profiling in this call */
+ clock_t entry_time; /* time of last entry to rule */
+ struct profile_frame* caller; /* stack frame of caller */
+};
+typedef struct profile_frame profile_frame;
+
+static profile_frame* profile_stack = 0;
+static struct hash* profile_hash = 0;
+
+static void profile_enter( char* rulename, profile_frame* frame )
+{
+ clock_t start = clock();
+ profile_info info, *p = &info;
+
+ if ( !profile_hash )
+ profile_hash = hashinit(sizeof(profile_info), "profile");
+
+ info.name = rulename;
+
+ if ( hashenter( profile_hash, (HASHDATA **)&p ) )
+ p->cumulative = p->subrules = p->num_entries = 0;
+
+ ++(p->num_entries);
+
+ frame->info = p;
+
+ frame->caller = profile_stack;
+ profile_stack = frame;
+
+ frame->entry_time = clock();
+ frame->overhead = 0;
+
+ /* caller pays for the time it takes to play with the hash table */
+ if ( frame->caller )
+ frame->caller->overhead += frame->entry_time - start;
+}
+
+static void profile_exit(profile_frame* frame)
+{
+ /* cumulative time for this call */
+ clock_t t = clock() - frame->entry_time - frame->overhead;
+ frame->info->cumulative += t;
+
+ if (frame->caller)
+ {
+ /* caller's cumulative time must account for this overhead */
+ frame->caller->overhead += frame->overhead;
+ frame->caller->info->subrules += t;
+ }
+ /* pop this stack frame */
+ profile_stack = frame->caller;
+}
+
+static void dump_profile_entry(void* p_, void* ignored)
+{
+ profile_info* p = p_;
+ clock_t total = p->cumulative;
+ printf("%10d %10d %10d %s\n", total, total - p->subrules, p->num_entries, p->name);
+}
+
+void profile_dump()
+{
+ if ( profile_hash )
+ {
+ printf("%10s %10s %10s %s\n", "gross", "net", "# entries", "name");
+ hashenumerate( profile_hash, dump_profile_entry, 0 );
+ }
+}
+
+/*
+ * evaluate_rule() - execute a rule invocation
+ */
+
+LIST *
+evaluate_rule(
+ char *rulename,
+ FRAME *frame )
+{
+ LIST *result = L0;
+ RULE *rule;
+ profile_frame prof[1];
+ module *prev_module = frame->module;
+
+ LIST* l = var_expand( L0, rulename, rulename+strlen(rulename), frame->args, 0 );
+
+ if ( !l )
+ {
+ printf( "warning: rulename %s expands to empty string\n", rulename );
+ return result;
+ }
+
+ if ( DEBUG_COMPILE )
+ {
+ debug_compile( 1, l->string );
+ lol_print( frame->args );
+ printf( "\n" );
+ }
+ rulename = l->string;
+ rule = bindrule( l->string, frame->module );
+
+ if ( rule->procedure && rule->procedure->module != prev_module )
+ {
+ /* propagate current module to nested rule invocations */
+ frame->module = rule->procedure->module;
+
+ /* swap variables */
+ exit_module( prev_module );
+ enter_module( rule->procedure->module );
+ }
+
+ list_free( l );
+
+ if ( DEBUG_PROFILE && rule->procedure )
+ profile_enter( rule->procedure->rulename, prof );
+
+ /* Check traditional targets $(<) and sources $(>) */
+
+ if( !rule->actions && !rule->procedure )
+ printf( "warning: unknown rule %s\n", rule->name );
+
+ /* If this rule will be executed for updating the targets */
+ /* then construct the action for make(). */
+
+ if( rule->actions )
+ {
+ TARGETS *t;
+ ACTION *action;
+
+ /* The action is associated with this instance of this rule */
+
+ action = (ACTION *)malloc( sizeof( ACTION ) );
+ memset( (char *)action, '\0', sizeof( *action ) );
+
+ action->rule = rule;
+ action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) );
+ action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) );
+
+ /* Append this action to the actions of each target */
+
+ for( t = action->targets; t; t = t->next )
+ t->target->actions = actionlist( t->target->actions, action );
+ }
+
+ /* Now recursively compile any parse tree associated with this rule */
+ /* refer/free to ensure rule not freed during use */
+
+ if( rule->procedure )
+ {
+ SETTINGS *local_args = collect_arguments( rule, frame->args );
+ PARSE *parse = rule->procedure;
+ parse_refer( parse );
+
+ pushsettings( local_args );
+ result = (*parse->func)( parse, frame );
+ popsettings( local_args );
+
+ parse_free( parse );
+ }
+
+ if ( frame->module != prev_module )
+ {
+ exit_module( frame->module );
+ enter_module( prev_module );
+ }
+
+ if ( DEBUG_PROFILE && rule->procedure )
+ profile_exit( prof );
+
+ if( DEBUG_COMPILE )
+ debug_compile( -1, 0 );
+
+ return result;
+}
+
+/*
+ * compile_rules() - compile a chain of rules
+ *
+ * parse->left more compile_rules() by left-recursion
+ * parse->right single rule
+ */
+
+LIST *
+compile_rules(
+ PARSE *parse,
+ FRAME *frame )
+{
+ /* Ignore result from first statement; return the 2nd. */
+
+ list_free( (*parse->left->func)( parse->left, frame ) );
+ return (*parse->right->func)( parse->right, frame );
+}
+
+/*
+ * compile_set() - compile the "set variable" statement
+ *
+ * parse->left variable names
+ * parse->right variable values
+ * parse->num ASSIGN_SET/APPEND/DEFAULT
+ */
+
+LIST *
+compile_set(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+ LIST *l;
+ int setflag;
+ char *trace;
+
+ switch( parse->num )
+ {
+ case ASSIGN_SET: setflag = VAR_SET; trace = "="; break;
+ case ASSIGN_APPEND: setflag = VAR_APPEND; trace = "+="; break;
+ case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break;
+ default: setflag = VAR_SET; trace = ""; break;
+ }
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "set" );
+ list_print( nt );
+ printf( " %s ", trace );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Call var_set to set variable */
+ /* var_set keeps ns, so need to copy it */
+
+ for( l = nt; l; l = list_next( l ) )
+ var_set( l->string, list_copy( L0, ns ), setflag );
+
+ list_free( nt );
+
+ return ns;
+}
+
+/*
+ * compile_set_module() - compile the "module local set variable" statement
+ *
+ * parse->left variable names
+ * parse->right variable values
+ */
+LIST *
+compile_set_module(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+ LIST *l;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "set module" );
+ printf( "(%s)", frame->module->name );
+ list_print( nt );
+ printf( " = " );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Call var_set to set variable */
+ /* var_set keeps ns, so need to copy it */
+
+ for( l = nt; l; l = list_next( l ) )
+ {
+ bind_module_var( frame->module, l->string );
+ var_set( l->string, list_copy( L0, ns ), VAR_SET );
+ }
+
+ list_free( nt );
+
+ return ns;
+}
+
+
+/*
+ * compile_setcomp() - support for `rule` - save parse tree
+ *
+ * parse->string rule name
+ * parse->left rules for rule
+ * parse->right optional list-of-lists describing arguments
+ */
+
+LIST *
+compile_setcomp(
+ PARSE *parse,
+ FRAME *frame)
+{
+ argument_list* arg_list = 0;
+
+ /* Create new LOL describing argument requirements if supplied */
+ if ( parse->right )
+ {
+ PARSE *p;
+ arg_list = args_new();
+ for( p = parse->right; p; p = p->left )
+ lol_add( arg_list->data, (*p->right->func)( p->right, frame ) );
+ }
+
+ new_rule_body( frame->module, parse->string, arg_list, parse->left );
+ return L0;
+}
+
+/*
+ * compile_setexec() - support for `actions` - save execution string
+ *
+ * parse->string rule name
+ * parse->string1 OS command string
+ * parse->num flags
+ * parse->left `bind` variables
+ *
+ * Note that the parse flags (as defined in compile.h) are transfered
+ * directly to the rule flags (as defined in rules.h).
+ */
+
+LIST *
+compile_setexec(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST* bindlist = (*parse->left->func)( parse->left, frame );
+
+ new_rule_actions( frame->module, parse->string, parse->string1, bindlist, parse->num );
+
+ return L0;
+}
+
+/*
+ * compile_settings() - compile the "on =" (set variable on exec) statement
+ *
+ * parse->left variable names
+ * parse->right target name
+ * parse->third variable value
+ * parse->num ASSIGN_SET/APPEND
+ */
+
+LIST *
+compile_settings(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->third->func)( parse->third, frame );
+ LIST *targets = (*parse->right->func)( parse->right, frame );
+ LIST *ts;
+ int append = parse->num == ASSIGN_APPEND;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "set" );
+ list_print( nt );
+ printf( "on " );
+ list_print( targets );
+ printf( " %s ", append ? "+=" : "=" );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Call addsettings to save variable setting */
+ /* addsettings keeps ns, so need to copy it */
+ /* Pass append flag to addsettings() */
+
+ for( ts = targets; ts; ts = list_next( ts ) )
+ {
+ TARGET *t = bindtarget( ts->string );
+ LIST *l;
+
+ for( l = nt; l; l = list_next( l ) )
+ t->settings = addsettings( t->settings, append,
+ l->string, list_copy( (LIST*)0, ns ) );
+ }
+
+ list_free( nt );
+ list_free( targets );
+
+ return ns;
+}
+
+/*
+ * compile_switch() - compile 'switch' rule
+ *
+ * parse->left switch value (only 1st used)
+ * parse->right cases
+ *
+ * cases->left 1st case
+ * cases->right next cases
+ *
+ * case->string argument to match
+ * case->left parse tree to execute
+ */
+
+LIST *
+compile_switch(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *result = 0;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "switch" );
+ list_print( nt );
+ printf( "\n" );
+ }
+
+ /* Step through cases */
+
+ for( parse = parse->right; parse; parse = parse->right )
+ {
+ if( !glob( parse->left->string, nt ? nt->string : "" ) )
+ {
+ /* Get & exec parse tree for this case */
+ parse = parse->left->left;
+ result = (*parse->func)( parse, frame );
+ break;
+ }
+ }
+
+ list_free( nt );
+
+ return result;
+}
+
+
+
+/*
+ * builtin_depends() - DEPENDS/INCLUDES rule
+ *
+ * The DEPENDS builtin rule appends each of the listed sources on the
+ * dependency list of each of the listed targets. It binds both the
+ * targets and sources as TARGETs.
+ */
+
+static LIST *
+builtin_depends(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *targets = lol_get( frame->args, 0 );
+ LIST *sources = lol_get( frame->args, 1 );
+ int which = parse->num;
+ LIST *l;
+
+ for( l = targets; l; l = list_next( l ) )
+ {
+ TARGET *t = bindtarget( l->string );
+ t->deps[ which ] = targetlist( t->deps[ which ], sources );
+ }
+
+ return L0;
+}
+
+/*
+ * builtin_echo() - ECHO rule
+ *
+ * The ECHO builtin rule echoes the targets to the user. No other
+ * actions are taken.
+ */
+
+static LIST *
+builtin_echo(
+ PARSE *parse,
+ FRAME *frame )
+{
+ list_print( lol_get( frame->args, 0 ) );
+ printf( "\n" );
+ return L0;
+}
+
+/*
+ * builtin_exit() - EXIT rule
+ *
+ * The EXIT builtin rule echoes the targets to the user and exits
+ * the program with a failure status.
+ */
+
+static LIST *
+builtin_exit(
+ PARSE *parse,
+ FRAME *frame )
+{
+ list_print( lol_get( frame->args, 0 ) );
+ printf( "\n" );
+ exit( EXITBAD ); /* yeech */
+ return L0;
+}
+
+/*
+ * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
+ *
+ * Builtin_flags() marks the target with the appropriate flag, for use
+ * by make0(). It binds each target as a TARGET.
+ */
+
+static LIST *
+builtin_flags(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *l = lol_get( frame->args, 0 );
+
+ for( ; l; l = list_next( l ) )
+ bindtarget( l->string )->flags |= parse->num;
+
+ return L0;
+}
+
+
+static LIST *
+builtin_hdrmacro(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST* l = lol_get( frame->args, 0 );
+
+ for ( ; l; l = list_next(l) )
+ {
+ TARGET* t = bindtarget( l->string );
+
+ /* scan file for header filename macro definitions */
+ if ( DEBUG_HEADER )
+ printf( "scanning '%s' for header file macro definitions\n",
+ l->string );
+
+ macro_headers( t );
+ }
+
+ return L0;
+}
+
+
+/*
+ * builtin_import() - IMPORT ( TARGET_MODULE ? : SOURCE_MODULE ? : RULE_NAMES * : TARGET_NAMES * )
+ *
+ * The IMPORT rule imports rules from the SOURCE_MODULE into the
+ * TARGET_MODULE. If either SOURCE_MODULE or TARGET_MODULE is not supplied, it
+ * refers to the root module. If any RULE_NAMES are supplied, they specify which
+ * rules from the SOURCE_MODULE to import, otherwise all rules are imported. The
+ * rules are given the names in TARGET_NAMES; if not enough TARGET_NAMES are
+ * supplied, the excess rules are given the names in RULE_NAMES. If RULE_NAMES
+ * is not supplied, TARGET_NAMES is ignored.
+ */
+
+struct import_data
+{
+ module* target_module;
+ LIST* target_names;
+};
+typedef struct import_data import_data;
+
+static void import_rule1( void* r_, void* data_ )
+{
+ RULE* r = r_;
+ import_data* data = data_;
+
+ char* target_name = data->target_names ? data->target_names->string : r->name;
+ if (data->target_names)
+ data->target_names = list_next(data->target_names);
+
+ import_rule( r, data->target_module, target_name );
+}
+
+static LIST *
+builtin_import(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *target_module_name = lol_get( frame->args, 0 );
+ LIST *source_module_name = lol_get( frame->args, 1 );
+ LIST *rule_names = lol_get( frame->args, 2 );
+ LIST *target_names = lol_get( frame->args, 3 );
+
+ module* target_module = bindmodule( target_module_name ? target_module_name->string : 0 );
+ module* source_module = bindmodule( source_module_name ? source_module_name->string : 0 );
+
+ if ( rule_names == 0 )
+ {
+ import_data data;
+ data.target_module = target_module;
+ data.target_names = target_names;
+ hashenumerate( source_module->rules, import_rule1, &data );
+ }
+ else
+ {
+ LIST *old_name, *target_name;
+
+ for ( old_name = rule_names, target_name = target_names;
+ old_name;
+ old_name = list_next( old_name )
+ , target_name = list_next( target_name ) )
+ {
+ RULE r_, *r = &r_;
+ r_.name = old_name->string;
+
+ if ( !target_name )
+ target_name = old_name;
+
+ if ( hashcheck( source_module->rules, (HASHDATA**)&r ) )
+ {
+ import_rule( r, target_module, target_name->string );
+ }
+ }
+ }
+
+ return L0;
+}
+
+/*
+ * builtin_caller_module() - CALLER_MODULE ( )
+ *
+ * Returns the name of the module of the rule which called the one calling this
+ * one, or, if no such module exists, returns the empty list. Also returns the
+ * empty list when the module in question is the global module. This rule is
+ * needed for implementing module import behavior.
+ */
+static LIST *builtin_caller_module( PARSE *parse, FRAME *frame )
+{
+ char buffer[4096] = "";
+ int len;
+
+ int i;
+ for (i = 0; i < 2 && frame->prev; ++i)
+ frame = frame->prev;
+
+ if ( frame->module == root_module() )
+ {
+ return L0;
+ }
+ else
+ {
+ LIST* result;
+
+ string name;
+ string_copy( &name, frame->module->name );
+ string_pop_back( &name );
+
+ result = list_new( L0, newstr(name.value) );
+
+ string_free( &name );
+
+ return result;
+ }
+}
+
+/*
+ * debug_compile() - printf with indent to show rule expansion.
+ */
+
+static void
+debug_compile( int which, char *s )
+{
+ static int level = 0;
+ static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
+
+ if ( which >= 0 )
+ {
+ int i;
+
+ i = (level+1)*2;
+ while ( i > 35 )
+ {
+ printf( indent );
+ i -= 35;
+ }
+ printf( "%*.*s ", i, i, indent );
+ }
+
+ if( s )
+ printf( "%s ", s );
+
+ level += which;
+}
diff --git a/historic/jam/src/compile.h b/historic/jam/src/compile.h
new file mode 100644
index 000000000..e18cd16cd
--- /dev/null
+++ b/historic/jam/src/compile.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+#ifndef COMPILE_DWA20011022_H
+# define COMPILE_DWA20011022_H
+
+# include "frames.h"
+# include "parse.h"
+# include "regexp.h"
+
+/*
+ * compile.h - compile parsed jam statements
+ */
+
+void compile_builtins();
+
+LIST *compile_append( PARSE *parse, FRAME *frame );
+LIST *compile_foreach( PARSE *parse, FRAME *frame );
+LIST *compile_if( PARSE *parse, FRAME *frame );
+LIST *compile_include( PARSE *parse, FRAME *frame );
+LIST *compile_list( PARSE *parse, FRAME *frame );
+LIST *compile_local( PARSE *parse, FRAME *frame );
+LIST *compile_module( PARSE *parse, FRAME *frame );
+LIST *compile_null( PARSE *parse, FRAME *frame );
+LIST *compile_rule( PARSE *parse, FRAME *frame );
+LIST *compile_rules( PARSE *parse, FRAME *frame );
+LIST *compile_set( PARSE *parse, FRAME *frame );
+LIST *compile_set_module( PARSE *parse, FRAME *frame );
+LIST *compile_setcomp( PARSE *parse, FRAME *frame );
+LIST *compile_setexec( PARSE *parse, FRAME *frame );
+LIST *compile_settings( PARSE *parse, FRAME *frame );
+LIST *compile_switch( PARSE *parse, FRAME *frame );
+LIST *compile_while( PARSE *parse, FRAME *frame );
+
+LIST *evaluate_rule( char *rulename, FRAME *frame );
+
+regexp* regex_compile( const char* pattern );
+
+void profile_dump();
+
+/* Flags for compile_set(), etc */
+
+# define ASSIGN_SET 0x00 /* = assign variable */
+# define ASSIGN_APPEND 0x01 /* += append variable */
+# define ASSIGN_DEFAULT 0x02 /* set only if unset */
+
+/* Flags for compile_setexec() */
+
+# define EXEC_UPDATED 0x01 /* executes updated */
+# define EXEC_TOGETHER 0x02 /* executes together */
+# define EXEC_IGNORE 0x04 /* executes ignore */
+# define EXEC_QUIETLY 0x08 /* executes quietly */
+# define EXEC_PIECEMEAL 0x10 /* executes piecemeal */
+# define EXEC_EXISTING 0x20 /* executes existing */
+
+/* Conditions for compile_if() */
+
+# define COND_NOT 0 /* ! cond */
+# define COND_AND 1 /* cond && cond */
+# define COND_OR 2 /* cond || cond */
+
+# define COND_EXISTS 3 /* arg */
+# define COND_EQUALS 4 /* arg = arg */
+# define COND_NOTEQ 5 /* arg != arg */
+# define COND_LESS 6 /* arg < arg */
+# define COND_LESSEQ 7 /* arg <= arg */
+# define COND_MORE 8 /* arg > arg */
+# define COND_MOREEQ 9 /* arg >= arg */
+# define COND_IN 10 /* arg in arg */
+
+#endif // COMPILE_DWA20011022_H
diff --git a/historic/jam/src/debugjam0.bat b/historic/jam/src/debugjam0.bat
new file mode 100755
index 000000000..d38e10bd0
--- /dev/null
+++ b/historic/jam/src/debugjam0.bat
@@ -0,0 +1,10 @@
+bash .\yyacc jamgram.y jamgramtab.h jamgram.yy
+set VISUALC=c:\tools\msvc6\vc98
+set JAM_TOOLSET=VISUALC
+set YACC="bison -t -d -l -v --debug --yacc"
+set YACCFILES=y.tab
+set CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd"
+set LINKLIBS="%VISUALC%\lib\advapi32.lib %VISUALC%\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib %VISUALC%\lib\user32.lib %VISUALC%\lib\kernel32.lib"
+set LINKFLAGS="/DEBUG"
+rm -rf bin.ntx86
+jam0 %*
diff --git a/historic/jam/src/debugjam0.sh b/historic/jam/src/debugjam0.sh
new file mode 100644
index 000000000..930499528
--- /dev/null
+++ b/historic/jam/src/debugjam0.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+# This script can be used to recover from aborted builds in which Jam has
+# removed some of its products (e.g. jamgramtab.h) upon failing some action
+./yyacc jamgram.y jamgramtab.h jamgram.yy
+export VISUALC=c:\tools\msvc6\vc98
+export JAM_TOOLSET=VISUALC
+jam0 -sCCFLAGS="/GZ /Zi /MLd" -sYACC="bison -t -d -l -v --yacc" -sLINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" -sLINKFLAGS="/DEBUG"
diff --git a/historic/jam/src/execcmd.h b/historic/jam/src/execcmd.h
new file mode 100644
index 000000000..1e7a60835
--- /dev/null
+++ b/historic/jam/src/execcmd.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * execcmd.h - execute a shell script
+ *
+ * 05/04/94 (seiwald) - async multiprocess interface
+ */
+
+void execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell );
+
+int execwait();
+
+# define EXEC_CMD_OK 0
+# define EXEC_CMD_FAIL 1
+# define EXEC_CMD_INTR 2
diff --git a/historic/jam/src/execmac.c b/historic/jam/src/execmac.c
new file mode 100644
index 000000000..20217dab1
--- /dev/null
+++ b/historic/jam/src/execmac.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+# include
+
+# ifdef OS_MAC
+
+/*
+ * execunix.c - execute a shell script on UNIX
+ *
+ * If $(JAMSHELL) is defined, uses that to formulate execvp().
+ * The default is:
+ *
+ * /bin/sh -c %
+ *
+ * Each word must be an individual element in a jam variable value.
+ *
+ * In $(JAMSHELL), % expands to the command string and ! expands to
+ * the slot number (starting at 1) for multiprocess (-j) invocations.
+ * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
+ * argument.
+ *
+ * Don't just set JAMSHELL to /bin/sh - it won't work!
+ *
+ * External routines:
+ * execcmd() - launch an async command execution
+ * execwait() - wait and drive at most one execution completion
+ *
+ * Internal routines:
+ * onintr() - bump intr to note command interruption
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 05/04/94 (seiwald) - async multiprocess interface
+ * 01/22/95 (seiwald) - $(JAMSHELL) support
+ */
+
+/*
+ * execcmd() - launch an async command execution
+ */
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+
+ printf( "%s", string );
+ (*func)( closure, EXEC_CMD_OK );
+}
+
+/*
+ * execwait() - wait and drive at most one execution completion
+ */
+
+int
+execwait()
+{
+ return 0;
+}
+
+# endif /* OS_MAC */
diff --git a/historic/jam/src/execnt.c b/historic/jam/src/execnt.c
new file mode 100644
index 000000000..3ddc67b62
--- /dev/null
+++ b/historic/jam/src/execnt.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+# include
+
+# ifdef USE_EXECNT
+
+# define WIN32_LEAN_AND_MEAN
+# include /* do the ugly deed */
+# include
+
+# if !defined( __BORLANDC__ ) && !defined( OS_OS2 )
+# define wait my_wait
+static int my_wait( int *status );
+# endif
+
+/*
+ * execnt.c - execute a shell command on Windows NT and Windows 95/98
+ *
+ * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
+ * The default is:
+ *
+ * /bin/sh -c % [ on UNIX/AmigaOS ]
+ * cmd.exe /c % [ on Windows NT ]
+ *
+ * Each word must be an individual element in a jam variable value.
+ *
+ * In $(JAMSHELL), % expands to the command string and ! expands to
+ * the slot number (starting at 1) for multiprocess (-j) invocations.
+ * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
+ * argument.
+ *
+ * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
+ *
+ * External routines:
+ * execcmd() - launch an async command execution
+ * execwait() - wait and drive at most one execution completion
+ *
+ * Internal routines:
+ * onintr() - bump intr to note command interruption
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 05/04/94 (seiwald) - async multiprocess interface
+ * 01/22/95 (seiwald) - $(JAMSHELL) support
+ * 06/02/97 (gsar) - full async multiprocess support for Win32
+ */
+
+static int intr = 0;
+static int cmdsrunning = 0;
+static void (*istat)( int );
+
+static int is_nt_351 = 0;
+static int is_win95 = 1;
+static int is_win95_defined = 0;
+
+
+static struct
+{
+ int pid; /* on win32, a real process handle */
+ void (*func)( void *closure, int status );
+ void *closure;
+ char *tempfile;
+
+} cmdtab[ MAXJOBS ] = {{0}};
+
+
+static void
+set_is_win95( void )
+{
+ OSVERSIONINFO os_info;
+
+ os_info.dwOSVersionInfoSize = sizeof(os_info);
+ os_info.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
+ GetVersionEx( &os_info );
+
+ is_win95 = (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+ is_win95_defined = 1;
+
+ /* now, test wether we're running Windows 3.51 */
+ /* this is later used to limit the system call command length */
+ if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ is_nt_351 = os_info.dwMajorVersion == 3;
+}
+
+
+static char**
+string_to_args( const char* string, int* pcount )
+{
+ int total = strlen( string );
+ int in_quote = 0,
+ num_args = 0; /* was uninitialized -- dwa */
+ char* line;
+ char* p;
+ char** arg;
+ char** args;
+
+ *pcount = 0;
+
+ /* do not copy trailing newlines, if any */
+ {
+ int i;
+
+ for ( i = total-1; i > 0; i-- )
+ {
+ if ( string[i] != '\n' && string[i] != '\r' )
+ break;
+ total --;
+ }
+ }
+
+ /* first of all, copy the input string */
+ line = (char*)malloc( total+2 );
+ if (!line)
+ return 0;
+
+ memcpy( line+1, string, total );
+ line[0] = 0;
+ line[total+1] = 0;
+
+ in_quote = 0;
+ for ( p = line+1; p[0]; p++ )
+ {
+ switch (p[0])
+ {
+ case '"':
+ in_quote = !in_quote;
+ break;
+
+ case ' ':
+ case '\t':
+ if (!in_quote)
+ p[0] = 0;
+
+ default:
+ ;
+ }
+ }
+
+ /* now count the arguments.. */
+ for ( p = line; p < line+total+1; p++ )
+ if ( !p[0] && p[1] )
+ num_args++;
+
+ /* allocate the args array */
+ /* dwa -- did you really mean to allocate only 2 additional bytes? */
+#if 0 /* was like this */
+ args = (char**)malloc( num_args*sizeof(char*)+2 );
+#endif
+ args = (char**)malloc( (num_args + 2) * sizeof(char*) );
+ if (!args)
+ {
+ free( line );
+ return 0;
+ }
+
+ arg = args+1;
+ for ( p = line; p < line+total+1; p++ )
+ if ( !p[0] && p[1] )
+ {
+ arg[0] = p+1;
+ arg++;
+ }
+ arg[0] = 0;
+ *pcount = num_args;
+ args[0] = line;
+ return args+1;
+}
+
+static void
+free_args( char** args )
+{
+ free( args[-1] );
+ free( args-1 );
+}
+
+
+/* process a "del" or "erase" command under Windows 95/98 */
+static int
+process_del( char* command )
+{
+ char** arg;
+ char* p = command, *q;
+ int wildcard = 0, result = 0;
+
+ /* first of all, skip the command itself */
+ if ( p[0] == 'd' )
+ p += 3; /* assumes "del..;" */
+ else if ( p[0] == 'e' )
+ p += 5; /* assumes "erase.." */
+ else
+ return 1; /* invalid command */
+
+ /* process all targets independently */
+ for (;;)
+ {
+ /* skip leading spaces */
+ while ( *p && isspace(*p) )
+ p++;
+
+ /* exit if we encounter an end of string */
+ if (!*p)
+ return 0;
+
+ /* ignore toggles/flags */
+ if (*p == '/')
+ {
+ p++;
+ while ( *p && isalnum(*p) )
+ p++;
+ }
+ else
+ {
+ int in_quote = 0;
+ int wildcard = 0;
+ int go_on = 1;
+
+ q = p;
+ while (go_on)
+ {
+ switch (*p)
+ {
+ case '"':
+ in_quote = !in_quote;
+ break;
+
+ case '?':
+ case '*':
+ if (!in_quote)
+ wildcard = 1;
+ break;
+
+ case '\0':
+ if (in_quote)
+ return 1;
+ /* fall-through */
+
+ case ' ':
+ case '\t':
+ if (!in_quote)
+ {
+ int len = p - q;
+ int result;
+ char* line;
+
+ /* q..p-1 contains the delete argument */
+ if ( len <= 0 )
+ return 1;
+
+ line = (char*)malloc( len+4+1 );
+ if (!line)
+ return 1;
+
+ strncpy( line, "del ", 4 );
+ strncpy( line+4, q, len );
+ line[len+4] = '\0';
+
+ if ( wildcard )
+ result = system( line );
+ else
+ result = !DeleteFile( line+4 );
+
+ free( line );
+ if (result)
+ return 1;
+
+ go_on = 0;
+ }
+
+ default:
+ ;
+ }
+ p++;
+ } /* while (go_on) */
+ }
+ }
+}
+
+
+/*
+ * onintr() - bump intr to note command interruption
+ */
+
+void
+onintr( int disp )
+{
+ intr++;
+ printf( "...interrupted\n" );
+}
+
+/*
+ * execcmd() - launch an async command execution
+ */
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+ int pid;
+ int slot;
+ int max_line;
+ int raw_cmd = 0 ;
+ char *argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
+ char **argv = argv_static;
+ char *p;
+
+ /* Check to see if we need to hack around the line-length limitation. */
+ /* Look for a JAMSHELL setting of "%", indicating that the command
+ * should be invoked directly */
+ if ( shell && !strcmp(shell->string,"%") && !list_next(shell) )
+ {
+ raw_cmd = 1;
+ shell = 0;
+ }
+
+ if ( !is_win95_defined )
+ set_is_win95();
+
+ /* Find a slot in the running commands table for this one. */
+ if ( is_win95 )
+ {
+ /* only synchronous spans are supported on Windows 95/98 */
+ slot = 0;
+ }
+ else
+ {
+ for( slot = 0; slot < MAXJOBS; slot++ )
+ if( !cmdtab[ slot ].pid )
+ break;
+ }
+ if( slot == MAXJOBS )
+ {
+ printf( "no slots for child!\n" );
+ exit( EXITBAD );
+ }
+
+ if( !cmdtab[ slot ].tempfile )
+ {
+ char *tempdir;
+
+ if( !( tempdir = getenv( "TEMP" ) ) &&
+ !( tempdir = getenv( "TMP" ) ) )
+ tempdir = "\\temp";
+
+ cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 14 );
+
+ sprintf( cmdtab[ slot ].tempfile, "%s\\jamtmp%02d.bat",
+ tempdir, slot );
+ }
+
+ /* Trim leading, ending white space */
+
+ while( isspace( *string ) )
+ ++string;
+
+ p = strchr( string, '\n' );
+
+ while( p && isspace( *p ) )
+ ++p;
+
+ /* on Windows NT 3.51, the maximul line length is 996 bytes !! */
+ /* while it's much bigger NT 4 and 2k */
+ max_line = is_nt_351 ? 996 : MAXLINE;
+
+ /* If multi line, or too long, or JAMSHELL is set, write to bat file. */
+ /* Otherwise, exec directly. */
+ /* Frankly, if it is a single long line I don't think the */
+ /* command interpreter will do any better -- it will fail. */
+
+ if( p && *p || !raw_cmd && strlen( string ) > max_line || shell )
+ {
+ FILE *f;
+
+ /* Write command to bat file. */
+
+ f = fopen( cmdtab[ slot ].tempfile, "w" );
+ fputs( string, f );
+ fclose( f );
+
+ string = cmdtab[ slot ].tempfile;
+ }
+
+ /* Forumulate argv */
+ /* If shell was defined, be prepared for % and ! subs. */
+ /* Otherwise, use stock /bin/sh (on unix) or cmd.exe (on NT). */
+
+ if( shell )
+ {
+ int i;
+ char jobno[4];
+ int gotpercent = 0;
+
+ sprintf( jobno, "%d", slot + 1 );
+
+ for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
+ {
+ switch( shell->string[0] )
+ {
+ case '%': argv[i] = string; gotpercent++; break;
+ case '!': argv[i] = jobno; break;
+ default: argv[i] = shell->string;
+ }
+ if( DEBUG_EXECCMD )
+ printf( "argv[%d] = '%s'\n", i, argv[i] );
+ }
+
+ if( !gotpercent )
+ argv[i++] = string;
+
+ argv[i] = 0;
+ }
+ else if (raw_cmd)
+ {
+ int ignored;
+ argv = string_to_args(string, &ignored);
+ }
+ else
+ {
+ /* don't worry, this is ignored on Win95/98, see later.. */
+ argv[0] = "cmd.exe";
+ argv[1] = "/Q/C"; /* anything more is non-portable */
+ argv[2] = string;
+ argv[3] = 0;
+ }
+
+ /* Catch interrupts whenever commands are running. */
+
+ if( !cmdsrunning++ )
+ istat = signal( SIGINT, onintr );
+
+ /* Start the command */
+
+ /* on Win95, we only do a synchronous call */
+ if ( is_win95 )
+ {
+ static const char* hard_coded[] =
+ {
+ "del", "erase", "copy", "mkdir", "rmdir", "cls", "dir",
+ "ren", "rename", "move", 0
+ };
+
+ const char** keyword;
+ int len, spawn = 1;
+ int result;
+
+ for ( keyword = hard_coded; keyword[0]; keyword++ )
+ {
+ len = strlen( keyword[0] );
+ if ( strnicmp( string, keyword[0], len ) == 0 &&
+ !isalnum(string[len]) )
+ {
+ /* this is one of the hard coded symbols, use 'system' to run */
+ /* them.. except for "del"/"erase" */
+ if ( keyword - hard_coded < 2 )
+ result = process_del( string );
+ else
+ result = system( string );
+
+ spawn = 0;
+ break;
+ }
+ }
+
+ if (spawn)
+ {
+ char** args;
+ int num_args;
+
+ /* convert the string into an array of arguments */
+ /* we need to take care of double quotes !! */
+ args = string_to_args( string, &num_args );
+ if ( args )
+ {
+#if 0
+ char** arg;
+ fprintf( stderr, "%s: ", args[0] );
+ arg = args+1;
+ while ( arg[0] )
+ {
+ fprintf( stderr, " {%s}", arg[0] );
+ arg++;
+ }
+ fprintf( stderr, "\n" );
+#endif
+ result = spawnvp( P_WAIT, args[0], args );
+ free_args( args );
+ }
+ else
+ result = 1;
+ }
+ func( closure, result ? EXEC_CMD_FAIL : EXEC_CMD_OK );
+ return;
+ }
+
+ /* the rest is for Windows NT only */
+ if( ( pid = spawnvp( P_NOWAIT, argv[0], argv ) ) == -1 )
+ {
+ perror( "spawn" );
+ exit( EXITBAD );
+ }
+ /* Save the operation for execwait() to find. */
+
+ cmdtab[ slot ].pid = pid;
+ cmdtab[ slot ].func = func;
+ cmdtab[ slot ].closure = closure;
+
+ /* Wait until we're under the limit of concurrent commands. */
+ /* Don't trust globs.jobs alone. */
+
+ while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
+ if( !execwait() )
+ break;
+
+ if (argv != argv_static)
+ {
+ free_args(argv);
+ }
+}
+
+/*
+ * execwait() - wait and drive at most one execution completion
+ */
+
+int
+execwait()
+{
+ int i;
+ int status, w;
+ int rstat;
+
+ /* Handle naive make1() which doesn't know if cmds are running. */
+
+ if( !cmdsrunning )
+ return 0;
+
+ if ( is_win95 )
+ return 0;
+
+ /* Pick up process pid and status */
+
+ while( ( w = wait( &status ) ) == -1 && errno == EINTR )
+ ;
+
+ if( w == -1 )
+ {
+ printf( "child process(es) lost!\n" );
+ perror("wait");
+ exit( EXITBAD );
+ }
+
+ /* Find the process in the cmdtab. */
+
+ for( i = 0; i < MAXJOBS; i++ )
+ if( w == cmdtab[ i ].pid )
+ break;
+
+ if( i == MAXJOBS )
+ {
+ printf( "waif child found!\n" );
+ exit( EXITBAD );
+ }
+
+ /* Drive the completion */
+
+ if( !--cmdsrunning )
+ signal( SIGINT, istat );
+
+ if( intr )
+ rstat = EXEC_CMD_INTR;
+ else if( w == -1 || status != 0 )
+ rstat = EXEC_CMD_FAIL;
+ else
+ rstat = EXEC_CMD_OK;
+
+ cmdtab[ i ].pid = 0;
+
+ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat );
+
+ return 1;
+}
+
+# if !defined( __BORLANDC__ )
+
+static int
+my_wait( int *status )
+{
+ int i, num_active = 0;
+ DWORD exitcode, waitcode;
+ static HANDLE *active_handles = 0;
+
+ if (!active_handles)
+ active_handles = (HANDLE *)malloc(globs.jobs * sizeof(HANDLE) );
+
+ /* first see if any non-waited-for processes are dead,
+ * and return if so.
+ */
+ for ( i = 0; i < globs.jobs; i++ ) {
+ if ( cmdtab[i].pid ) {
+ if ( GetExitCodeProcess((HANDLE)cmdtab[i].pid, &exitcode) ) {
+ if ( exitcode == STILL_ACTIVE )
+ active_handles[num_active++] = (HANDLE)cmdtab[i].pid;
+ else {
+ CloseHandle((HANDLE)cmdtab[i].pid);
+ *status = (int)((exitcode & 0xff) << 8);
+ return cmdtab[i].pid;
+ }
+ }
+ else
+ goto FAILED;
+ }
+ }
+
+ /* if a child exists, wait for it to die */
+ if ( !num_active ) {
+ errno = ECHILD;
+ return -1;
+ }
+ waitcode = WaitForMultipleObjects( num_active,
+ active_handles,
+ FALSE,
+ INFINITE );
+ if ( waitcode != WAIT_FAILED ) {
+ if ( waitcode >= WAIT_ABANDONED_0
+ && waitcode < WAIT_ABANDONED_0 + num_active )
+ i = waitcode - WAIT_ABANDONED_0;
+ else
+ i = waitcode - WAIT_OBJECT_0;
+ if ( GetExitCodeProcess(active_handles[i], &exitcode) ) {
+ CloseHandle(active_handles[i]);
+ *status = (int)((exitcode & 0xff) << 8);
+ return (int)active_handles[i];
+ }
+ }
+
+FAILED:
+ errno = GetLastError();
+ return -1;
+
+}
+
+# endif /* !__BORLANDC__ */
+
+# endif /* USE_EXECNT */
diff --git a/historic/jam/src/execunix.c b/historic/jam/src/execunix.c
new file mode 100644
index 000000000..0eb03ca3a
--- /dev/null
+++ b/historic/jam/src/execunix.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+# include
+
+# ifdef USE_EXECUNIX
+
+# ifdef NO_VFORK
+# define vfork() fork()
+# endif
+
+# if defined( OS_NT ) || defined( OS_OS2 )
+
+# define USE_EXECNT
+
+# include
+
+# if !defined( __BORLANDC__ ) && !defined( OS_OS2 )
+# define wait my_wait
+static int my_wait( int *status );
+# endif
+
+# endif
+
+/*
+ * execunix.c - execute a shell script on UNIX/WinNT/OS2/AmigaOS
+ *
+ * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
+ * The default is:
+ *
+ * /bin/sh -c % [ on UNIX/AmigaOS ]
+ * cmd.exe /c % [ on OS2/WinNT ]
+ *
+ * Each word must be an individual element in a jam variable value.
+ *
+ * In $(JAMSHELL), % expands to the command string and ! expands to
+ * the slot number (starting at 1) for multiprocess (-j) invocations.
+ * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
+ * argument.
+ *
+ * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
+ *
+ * External routines:
+ * execcmd() - launch an async command execution
+ * execwait() - wait and drive at most one execution completion
+ *
+ * Internal routines:
+ * onintr() - bump intr to note command interruption
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 05/04/94 (seiwald) - async multiprocess interface
+ * 01/22/95 (seiwald) - $(JAMSHELL) support
+ * 06/02/97 (gsar) - full async multiprocess support for Win32
+ */
+
+static int intr = 0;
+static int cmdsrunning = 0;
+static void (*istat)( int );
+
+static struct
+{
+ int pid; /* on win32, a real process handle */
+ void (*func)( void *closure, int status );
+ void *closure;
+
+# ifdef USE_EXECNT
+ char *tempfile;
+# endif
+
+} cmdtab[ MAXJOBS ] = {{0}};
+
+/*
+ * onintr() - bump intr to note command interruption
+ */
+
+void
+onintr( int disp )
+{
+ intr++;
+ printf( "...interrupted\n" );
+}
+
+/*
+ * execcmd() - launch an async command execution
+ */
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+ int pid;
+ int slot;
+ char *argv[ MAXARGC + 1 ]; /* +1 for NULL */
+
+# ifdef USE_EXECNT
+ char *p;
+# endif
+
+ /* Find a slot in the running commands table for this one. */
+
+ for( slot = 0; slot < MAXJOBS; slot++ )
+ if( !cmdtab[ slot ].pid )
+ break;
+
+ if( slot == MAXJOBS )
+ {
+ printf( "no slots for child!\n" );
+ exit( EXITBAD );
+ }
+
+# ifdef USE_EXECNT
+ if( !cmdtab[ slot ].tempfile )
+ {
+ char *tempdir;
+
+ if( !( tempdir = getenv( "TEMP" ) ) &&
+ !( tempdir = getenv( "TMP" ) ) )
+ tempdir = "\\temp";
+
+ cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 14 );
+
+ sprintf( cmdtab[ slot ].tempfile, "%s\\jamtmp%02d.bat",
+ tempdir, slot );
+ }
+
+ /* Trim leading, ending white space */
+
+ while( isspace( *string ) )
+ ++string;
+
+ p = strchr( string, '\n' );
+
+ while( p && isspace( *p ) )
+ ++p;
+
+ /* If multi line, or too long, or JAMSHELL is set, write to bat file. */
+ /* Otherwise, exec directly. */
+ /* Frankly, if it is a single long line I don't think the */
+ /* command interpreter will do any better -- it will fail. */
+
+ if( p && *p || strlen( string ) > MAXLINE || shell )
+ {
+ FILE *f;
+
+ /* Write command to bat file. */
+
+ f = fopen( cmdtab[ slot ].tempfile, "w" );
+ fputs( string, f );
+ fclose( f );
+
+ string = cmdtab[ slot ].tempfile;
+ }
+# endif
+
+ /* Forumulate argv */
+ /* If shell was defined, be prepared for % and ! subs. */
+ /* Otherwise, use stock /bin/sh (on unix) or cmd.exe (on NT). */
+
+ if( shell )
+ {
+ int i;
+ char jobno[4];
+ int gotpercent = 0;
+
+ sprintf( jobno, "%d", slot + 1 );
+
+ for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
+ {
+ switch( shell->string[0] )
+ {
+ case '%': argv[i] = string; gotpercent++; break;
+ case '!': argv[i] = jobno; break;
+ default: argv[i] = shell->string;
+ }
+ if( DEBUG_EXECCMD )
+ printf( "argv[%d] = '%s'\n", i, argv[i] );
+ }
+
+ if( !gotpercent )
+ argv[i++] = string;
+
+ argv[i] = 0;
+ }
+ else
+ {
+# ifdef USE_EXECNT
+ argv[0] = "cmd.exe";
+ argv[1] = "/Q/C"; /* anything more is non-portable */
+# else
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+# endif
+ argv[2] = string;
+ argv[3] = 0;
+ }
+
+ /* Catch interrupts whenever commands are running. */
+
+ if( !cmdsrunning++ )
+ istat = signal( SIGINT, onintr );
+
+ /* Start the command */
+
+# ifdef USE_EXECNT
+ if( ( pid = spawnvp( P_NOWAIT, argv[0], argv ) ) == -1 )
+ {
+ perror( "spawn" );
+ exit( EXITBAD );
+ }
+# else
+ if ((pid = vfork()) == 0)
+ {
+ execvp( argv[0], argv );
+ _exit(127);
+ }
+
+ if( pid == -1 )
+ {
+ perror( "vfork" );
+ exit( EXITBAD );
+ }
+# endif
+ /* Save the operation for execwait() to find. */
+
+ cmdtab[ slot ].pid = pid;
+ cmdtab[ slot ].func = func;
+ cmdtab[ slot ].closure = closure;
+
+ /* Wait until we're under the limit of concurrent commands. */
+ /* Don't trust globs.jobs alone. */
+
+ while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
+ if( !execwait() )
+ break;
+}
+
+/*
+ * execwait() - wait and drive at most one execution completion
+ */
+
+int
+execwait()
+{
+ int i;
+ int status, w;
+ int rstat;
+
+ /* Handle naive make1() which doesn't know if cmds are running. */
+
+ if( !cmdsrunning )
+ return 0;
+
+ /* Pick up process pid and status */
+
+ while( ( w = wait( &status ) ) == -1 && errno == EINTR )
+ ;
+
+ if( w == -1 )
+ {
+ printf( "child process(es) lost!\n" );
+ perror("wait");
+ exit( EXITBAD );
+ }
+
+ /* Find the process in the cmdtab. */
+
+ for( i = 0; i < MAXJOBS; i++ )
+ if( w == cmdtab[ i ].pid )
+ break;
+
+ if( i == MAXJOBS )
+ {
+ printf( "waif child found!\n" );
+ exit( EXITBAD );
+ }
+
+ /* Drive the completion */
+
+ if( !--cmdsrunning )
+ signal( SIGINT, istat );
+
+ if( intr )
+ rstat = EXEC_CMD_INTR;
+ else if( w == -1 || status != 0 )
+ rstat = EXEC_CMD_FAIL;
+ else
+ rstat = EXEC_CMD_OK;
+
+ cmdtab[ i ].pid = 0;
+
+ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat );
+
+ return 1;
+}
+
+# if defined( OS_NT ) && !defined( __BORLANDC__ )
+
+# define WIN32_LEAN_AND_MEAN
+
+# include /* do the ugly deed */
+
+static int
+my_wait( int *status )
+{
+ int i, num_active = 0;
+ DWORD exitcode, waitcode;
+ static HANDLE *active_handles = 0;
+
+ if (!active_handles)
+ active_handles = (HANDLE *)malloc(globs.jobs * sizeof(HANDLE) );
+
+ /* first see if any non-waited-for processes are dead,
+ * and return if so.
+ */
+ for ( i = 0; i < globs.jobs; i++ ) {
+ if ( cmdtab[i].pid ) {
+ if ( GetExitCodeProcess((HANDLE)cmdtab[i].pid, &exitcode) ) {
+ if ( exitcode == STILL_ACTIVE )
+ active_handles[num_active++] = (HANDLE)cmdtab[i].pid;
+ else {
+ CloseHandle((HANDLE)cmdtab[i].pid);
+ *status = (int)((exitcode & 0xff) << 8);
+ return cmdtab[i].pid;
+ }
+ }
+ else
+ goto FAILED;
+ }
+ }
+
+ /* if a child exists, wait for it to die */
+ if ( !num_active ) {
+ errno = ECHILD;
+ return -1;
+ }
+ waitcode = WaitForMultipleObjects( num_active,
+ active_handles,
+ FALSE,
+ INFINITE );
+ if ( waitcode != WAIT_FAILED ) {
+ if ( waitcode >= WAIT_ABANDONED_0
+ && waitcode < WAIT_ABANDONED_0 + num_active )
+ i = waitcode - WAIT_ABANDONED_0;
+ else
+ i = waitcode - WAIT_OBJECT_0;
+ if ( GetExitCodeProcess(active_handles[i], &exitcode) ) {
+ CloseHandle(active_handles[i]);
+ *status = (int)((exitcode & 0xff) << 8);
+ return (int)active_handles[i];
+ }
+ }
+
+FAILED:
+ errno = GetLastError();
+ return -1;
+
+}
+
+# endif /* NT && !__BORLANDC__ */
+
+# endif /* USE_EXECUNIX */
diff --git a/historic/jam/src/execvms.c b/historic/jam/src/execvms.c
new file mode 100644
index 000000000..0bf5486f2
--- /dev/null
+++ b/historic/jam/src/execvms.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+
+# ifdef OS_VMS
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * execvms.c - execute a shell script, ala VMS
+ *
+ * The approach is this:
+ *
+ * If the command is a single line, and shorter than WRTLEN (what we
+ * believe to be the maximum line length), we just system() it.
+ *
+ * If the command is multi-line, or longer than WRTLEN, we write the
+ * command block to a temp file, splitting long lines (using "-" at
+ * the end of the line to indicate contiuation), and then source that
+ * temp file. We use special logic to make sure we don't continue in
+ * the middle of a quoted string.
+ *
+ * 05/04/94 (seiwald) - async multiprocess interface; noop on VMS
+ * 12/20/96 (seiwald) - rewritten to handle multi-line commands well
+ * 01/14/96 (seiwald) - don't put -'s between "'s
+ */
+
+#define WRTLEN 240
+
+#define MIN( a, b ) ((a) < (b) ? (a) : (b))
+
+/* 1 for the @ and 4 for the .com */
+
+char tempnambuf[ L_tmpnam + 1 + 4 ] = {0};
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+ char *s, *e, *p;
+ int rstat = EXEC_CMD_OK;
+ int status;
+
+ /* See if string is more than one line */
+ /* discounting leading/trailing white space */
+
+ for( s = string; *s && isspace( *s ); s++ )
+ ;
+
+ e = p = strchr( s, '\n' );
+
+ while( p && isspace( *p ) )
+ ++p;
+
+ /* If multi line or long, write to com file. */
+ /* Otherwise, exec directly. */
+
+ if( p && *p || e - s > WRTLEN )
+ {
+ FILE *f;
+
+ /* Create temp file invocation "@sys$scratch:tempfile.com" */
+
+ if( !*tempnambuf )
+ {
+ tempnambuf[0] = '@';
+ (void)tmpnam( tempnambuf + 1 );
+ strcat( tempnambuf, ".com" );
+ }
+
+ /* Open tempfile */
+
+ if( !( f = fopen( tempnambuf + 1, "w" ) ) )
+ {
+ printf( "can't open command file\n" );
+ (*func)( closure, EXEC_CMD_FAIL );
+ return;
+ }
+
+ /* For each line of the string */
+
+ while( *string )
+ {
+ char *s = strchr( string, '\n' );
+ int len = s ? s + 1 - string : strlen( string );
+
+ fputc( '$', f );
+
+ /* For each chunk of a line that needs to be split */
+
+ while( len > 0 )
+ {
+ char *q = string;
+ char *qe = string + MIN( len, WRTLEN );
+ char *qq = q;
+ int quote = 0;
+
+ /* Look for matching "'s */
+
+ for( ; q < qe; q++ )
+ if( *q == '"' && ( quote = !quote ) )
+ qq = q;
+
+ /* Back up to opening quote, if in one */
+
+ if( quote )
+ q = qq;
+
+ fwrite( string, ( q - string ), 1, f );
+
+ len -= ( q - string );
+ string = q;
+
+ if( len )
+ {
+ fputc( '-', f );
+ fputc( '\n', f );
+ }
+ }
+ }
+
+ fclose( f );
+
+ status = system( tempnambuf ) & 0x07;
+
+ unlink( tempnambuf + 1 );
+ }
+ else
+ {
+ /* Execute single line command */
+ /* Strip trailing newline before execing */
+ if( e ) *e = 0;
+ status = system( s ) & 0x07;
+ }
+
+ /* Fail for error or fatal error */
+ /* OK on OK, warning, or info exit */
+
+ if( status == 2 || status == 4 )
+ rstat = EXEC_CMD_FAIL;
+
+ (*func)( closure, rstat );
+}
+
+int
+execwait()
+{
+ return 0;
+}
+
+# endif /* VMS */
diff --git a/historic/jam/src/expand.c b/historic/jam/src/expand.c
new file mode 100644
index 000000000..9c66dfc4b
--- /dev/null
+++ b/historic/jam/src/expand.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "variable.h"
+# include "expand.h"
+# include "filesys.h"
+# include "newstr.h"
+# include "strings.h"
+
+# include
+# include
+/*
+ * expand.c - expand a buffer, given variable values
+ *
+ * External routines:
+ *
+ * var_expand() - variable-expand input string into list of strings
+ *
+ * Internal routines:
+ *
+ * var_edit() - copy input target name to output, performing : modifiers
+ * var_mods() - parse : modifiers into FILENAME structure
+ *
+ * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ */
+
+typedef struct {
+ char downshift; /* :L -- downshift result */
+ char upshift; /* :U -- upshift result */
+ char parent; /* :P -- go to parent directory */
+ char to_slashes; /* :T -- convert "\" to "/" */
+} VAR_ACTS ;
+
+static void var_edit( char *in, char *mods, string *out );
+static void var_mods( char *mods, FILENAME *f, VAR_ACTS *acts );
+
+static int adjust_index( int index, int length );
+
+# define MAGIC_COLON '\001'
+# define MAGIC_LEFT '\002'
+# define MAGIC_RIGHT '\003'
+
+/*
+ * var_expand() - variable-expand input string into list of strings
+ *
+ * Would just copy input to output, performing variable expansion,
+ * except that since variables can contain multiple values the result
+ * of variable expansion may contain multiple values (a list). Properly
+ * performs "product" operations that occur in "$(var1)xxx$(var2)" or
+ * even "$($(var2))".
+ *
+ * Returns a newly created list.
+ */
+
+LIST *
+var_expand(
+ LIST *l,
+ char *in,
+ char *end,
+ LOL *lol,
+ int cancopyin )
+{
+ string buf[1];
+ size_t prefix_length;
+ char *out;
+ char *inp = in;
+ char *ov; /* for temp copy of variable in outbuf */
+ int depth;
+
+ if( DEBUG_VAREXP )
+ printf( "expand '%.*s'\n", end - in, in );
+
+ /* This gets alot of cases: $(<) and $(>) */
+
+ if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] )
+ {
+ switch( in[2] )
+ {
+ case '1':
+ case '<':
+ return list_copy( l, lol_get( lol, 0 ) );
+
+ case '2':
+ case '>':
+ return list_copy( l, lol_get( lol, 1 ) );
+ }
+ }
+
+ /* See if we can use a simple copy of in to out. */
+
+ while ( in < end )
+ if ( *in++ == '$' && *in == '(' )
+ goto expand;
+
+ /* No variables expanded - just add copy of input string to list. */
+
+ /* Cancopyin is an optimization: if the input was already a list */
+ /* item, we can use the copystr() to put it on the new list. */
+ /* Otherwise, we use the slower newstr(). */
+
+ if ( cancopyin )
+ {
+ return list_new( l, copystr( inp ) );
+ }
+ else
+ {
+ LIST* r;
+ string_new( buf );
+ string_append_range( buf, inp, in );
+
+ r = list_new( l, newstr( buf->value ) );
+ string_free( buf );
+ return r;
+ }
+
+ expand:
+ string_new( buf );
+ string_append_range( buf, inp, in - 1 ); /* copy in initial stuff */
+ /*
+ * Input so far (ignore blanks):
+ *
+ * stuff-in-outbuf $(variable) remainder
+ * ^ ^
+ * in end
+ * Output so far:
+ *
+ * stuff-in-outbuf $
+ * ^ ^
+ * out_buf out
+ *
+ *
+ * We just copied the $ of $(...), so back up one on the output.
+ * We now find the matching close paren, copying the variable and
+ * modifiers between the $( and ) temporarily into out_buf, so that
+ * we can replace :'s with MAGIC_COLON. This is necessary to avoid
+ * being confused by modifier values that are variables containing
+ * :'s. Ugly.
+ */
+
+ depth = 1;
+ inp = ++in; /* skip over the '(' */
+
+ while( in < end && depth )
+ {
+ switch( *in++ )
+ {
+ case '(': depth++; break;
+ case ')': depth--; break;
+ }
+ }
+
+ /*
+ * Input so far (ignore blanks):
+ *
+ * stuff-in-outbuf $(variable) remainder
+ * ^ ^ ^
+ * inp in end
+ */
+ prefix_length = buf->size;
+ string_append_range( buf, inp, in - 1 );
+
+ out = buf->value + prefix_length;
+ for ( ov = out; ov < buf->value + buf->size; ++ov )
+ {
+ switch( *ov )
+ {
+ case ':': *ov = MAGIC_COLON; break;
+ case '[': *ov = MAGIC_LEFT; break;
+ case ']': *ov = MAGIC_RIGHT; break;
+ }
+ }
+
+ /*
+ * Input so far (ignore blanks):
+ *
+ * stuff-in-outbuf $(variable) remainder
+ * ^ ^
+ * in end
+ * Output so far:
+ *
+ * stuff-in-outbuf variable
+ * ^ ^ ^
+ * out_buf out ov
+ *
+ * Later we will overwrite 'variable' in out_buf, but we'll be
+ * done with it by then. 'variable' may be a multi-element list,
+ * so may each value for '$(variable element)', and so may 'remainder'.
+ * Thus we produce a product of three lists.
+ */
+
+ {
+ LIST *variables = 0;
+ LIST *remainder = 0;
+ LIST *vars;
+
+ /* Recursively expand variable name & rest of input */
+
+ if( out < ov )
+ variables = var_expand( L0, out, ov, lol, 0 );
+ if( in < end )
+ remainder = var_expand( L0, in, end, lol, 0 );
+
+ /* Now produce the result chain */
+
+ /* For each variable name */
+
+ for( vars = variables; vars; vars = list_next( vars ) )
+ {
+ LIST *value;
+ char *colon;
+ char *bracket;
+ int i, sub1, sub2;
+ string variable;
+ char *varname;
+
+ /* Look for a : modifier in the variable name */
+ /* Must copy into varname so we can modify it */
+
+ string_copy( &variable, vars->string );
+ varname = variable.value;
+
+ if( colon = strchr( varname, MAGIC_COLON ) )
+ {
+ string_truncate( &variable, colon - varname );
+ }
+
+ if( bracket = strchr( varname, MAGIC_LEFT ) )
+ {
+ char *dash = 0;
+
+ if( bracket[1] && ( dash = strchr( bracket + 2, '-' ) ) )
+ {
+ string_truncate( &variable, dash - varname );
+ sub1 = atoi( bracket + 1 );
+ sub2 = atoi( dash + 1 );
+ }
+ else
+ {
+ sub1 = sub2 = atoi( bracket + 1 );
+ }
+
+ string_truncate( &variable, bracket - varname );
+ }
+ else
+ {
+ sub1 = sub2 = 0; /* not needed */
+ }
+
+ /* Get variable value, specially handling $(<), $(>), $(n) */
+
+ if( varname[0] == '<' && !varname[1] )
+ {
+ value = lol_get( lol, 0 );
+ }
+ else if( varname[0] == '>' && !varname[1] )
+ {
+ value = lol_get( lol, 1 );
+ }
+ else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] )
+ {
+ value = lol_get( lol, varname[0] - '1' );
+ }
+ else
+ {
+ value = var_get( varname );
+ }
+
+ /* The fast path: $(x) - just copy the variable value. */
+
+ if( out == buf->value && !bracket && !colon && in == end )
+ {
+ string_free( &variable );
+ l = list_copy( l, value );
+ continue;
+ }
+
+ /* Adjust negative indices */
+ if ( sub1 < 0 || sub2 < 0 )
+ {
+ int length = list_length( value );
+ sub1 = adjust_index( sub1, length );
+ sub2 = adjust_index( sub2, length );
+ }
+
+ /* For each variable value */
+ for( i = 1; value; i++, value = list_next( value ) )
+ {
+ LIST *rem;
+ size_t postfix_start;
+
+ /* Skip members not in subscript */
+
+ if( bracket && ( i < sub1 || sub2 && i > sub2 ) )
+ continue;
+
+ string_truncate( buf, prefix_length );
+
+ /* Apply : mods, if present */
+
+ if( colon )
+ var_edit( value->string, colon + 1, buf );
+ else
+ string_append( buf, value->string );
+
+ /* If no remainder, append result to output chain. */
+
+ if( in == end )
+ {
+ l = list_new( l, newstr( buf->value ) );
+ continue;
+ }
+
+ /* Remember the end of the variable expansion so */
+ /* we can just tack on each instance of 'remainder' */
+
+ postfix_start = buf->size;
+
+ /* For each remainder, or just once if no remainder, */
+ /* append the complete string to the output chain */
+
+ for( rem = remainder; rem; rem = list_next( rem ) )
+ {
+ string_truncate( buf, postfix_start );
+ string_append( buf, rem->string );
+ l = list_new( l, newstr( buf->value ) );
+ }
+ }
+ string_free( &variable );
+ }
+
+ /* variables & remainder were gifts from var_expand */
+ /* and must be freed */
+
+ if( variables )
+ list_free( variables );
+ if( remainder)
+ list_free( remainder );
+
+ if( DEBUG_VAREXP )
+ {
+ printf( "expanded to " );
+ list_print( l );
+ printf( "\n" );
+ }
+
+ string_free( buf );
+ return l;
+ }
+}
+
+/*
+ * var_edit() - copy input target name to output, performing : modifiers
+ */
+
+static void
+var_edit(
+ char *in,
+ char *mods,
+ string *out)
+{
+ FILENAME oldf, newf;
+ VAR_ACTS acts;
+
+ /* Parse apart original filename, putting parts into "oldf" */
+
+ file_parse( in, &oldf );
+
+ /* Parse apart modifiers, putting them into "newf" */
+
+ var_mods( mods, &newf, &acts );
+
+ /* Replace any oldf with newf */
+
+ if( newf.f_grist.ptr )
+ oldf.f_grist = newf.f_grist;
+
+ if( newf.f_root.ptr )
+ oldf.f_root = newf.f_root;
+
+ if( newf.f_dir.ptr )
+ oldf.f_dir = newf.f_dir;
+
+ if( newf.f_base.ptr )
+ oldf.f_base = newf.f_base;
+
+ if( newf.f_suffix.ptr )
+ oldf.f_suffix = newf.f_suffix;
+
+ if( newf.f_member.ptr )
+ oldf.f_member = newf.f_member;
+
+ /* If requested, modify oldf to point to parent */
+
+ if( acts.parent )
+ file_parent( &oldf );
+
+ /* Put filename back together */
+
+ file_build( &oldf, out, 0 );
+
+ /* Handle upshifting, downshifting now */
+ /* Handle conversion of "\" to "/" */
+ {
+ char* p;
+ for ( p = out->value; *p; ++p)
+ {
+ if( acts.upshift )
+ {
+ *p = toupper( *p );
+ }
+ else if( acts.downshift )
+ {
+ *p = tolower( *p );
+ }
+ if ( acts.to_slashes )
+ {
+ if ( *p == '\\' )
+ *p = '/';
+ }
+ }
+ out->size = p - out->value;
+ }
+}
+
+
+/*
+ * var_mods() - parse : modifiers into FILENAME structure
+ *
+ * The : modifiers in a $(varname:modifier) currently support replacing
+ * or omitting elements of a filename, and so they are parsed into a
+ * FILENAME structure (which contains pointers into the original string).
+ *
+ * Modifiers of the form "X=value" replace the component X with
+ * the given value. Modifiers without the "=value" cause everything
+ * but the component X to be omitted. X is one of:
+ *
+ * G
+ * D directory name
+ * B base name
+ * S .suffix
+ * M (member)
+ * R root directory - prepended to whole path
+ *
+ * This routine sets:
+ *
+ * f->f_xxx.ptr = 0
+ * f->f_xxx.len = 0
+ * -> leave the original component xxx
+ *
+ * f->f_xxx.ptr = string
+ * f->f_xxx.len = strlen( string )
+ * -> replace component xxx with string
+ *
+ * f->f_xxx.ptr = ""
+ * f->f_xxx.len = 0
+ * -> omit component xxx
+ *
+ * var_edit() above and file_build() obligingly follow this convention.
+ */
+
+static void
+var_mods(
+ char *mods,
+ FILENAME *f,
+ VAR_ACTS *acts )
+{
+ char *flags = "GRDBSMT";
+ int havezeroed = 0;
+ memset( (char *)f, 0, sizeof( *f ) );
+ memset( (char *)acts, 0, sizeof( *acts ) );
+
+ while( *mods )
+ {
+ char *fl;
+ FILEPART *fp;
+
+ /* First take care of :U or :L (upshift, downshift) */
+
+ if( *mods == 'L' )
+ {
+ acts->downshift = 1;
+ ++mods;
+ continue;
+ }
+ else if( *mods == 'U' )
+ {
+ acts->upshift = 1;
+ ++mods;
+ continue;
+ }
+ else if( *mods == 'P' )
+ {
+ acts->parent = 1;
+ ++mods;
+ continue;
+ }
+ else if ( *mods == 'T' )
+ {
+ acts->to_slashes = 1;
+ ++mods;
+ continue;
+ }
+
+ /* Now handle the file component flags */
+
+ if( !( fl = strchr( flags, *mods++ ) ) )
+ break; /* should complain, but so what... */
+
+ fp = &f->part[ fl - flags ];
+
+ if( *mods++ != '=' )
+ {
+ /* :X - turn everything but X off */
+
+ int i;
+
+ mods--;
+
+ if( !havezeroed++ )
+ for( i = 0; i < 6; i++ )
+ {
+ f->part[ i ].len = 0;
+ f->part[ i ].ptr = "";
+ }
+
+ fp->ptr = 0;
+ }
+ else
+ {
+ /* :X=value - set X to value */
+
+ char *p;
+
+ if( p = strchr( mods, MAGIC_COLON ) )
+ {
+ fp->ptr = mods;
+ fp->len = p - mods;
+ mods = p + 1;
+ }
+ else
+ {
+ fp->ptr = mods;
+ fp->len = strlen( mods );
+ mods += fp->len;
+ }
+ }
+ }
+}
+
+static int adjust_index( int index, int length )
+{
+ if ( index < 0 )
+ index = length + 1 + index;
+ if ( index < 0 )
+ index = 0;
+ return index;
+}
+
+#ifndef NDEBUG
+void var_expand_unit_test()
+{
+ LOL lol[1];
+ LIST* l, *l2;
+ LIST *expected = list_new( list_new( L0, newstr( "axb" ) ), newstr( "ayb" ) );
+ LIST *e2;
+ char axyb[] = "a$(xy)b";
+ char azb[] = "a$($(z))b";
+
+ lol_init(lol);
+ var_set("xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET );
+ var_set("z", list_new( L0, newstr( "xy" ) ), VAR_SET );
+
+ l = var_expand( 0, axyb, axyb + sizeof(axyb) - 1, lol, 0 );
+ for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) )
+ assert( !strcmp( e2->string, l2->string ) );
+ list_free(l);
+
+ l = var_expand( 0, azb, azb + sizeof(azb) - 1, lol, 0 );
+ for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) )
+ assert( !strcmp( e2->string, l2->string ) );
+ list_free(l);
+
+ lol_free(lol);
+}
+#endif
diff --git a/historic/jam/src/expand.h b/historic/jam/src/expand.h
new file mode 100644
index 000000000..77ee74bf1
--- /dev/null
+++ b/historic/jam/src/expand.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * expand.h - expand a buffer, given variable values
+ */
+
+LIST *var_expand( LIST *l, char *in, char *end, LOL *lol, int cancopyin );
+void var_expand_unit_test();
diff --git a/historic/jam/src/filemac.c b/historic/jam/src/filemac.c
new file mode 100644
index 000000000..9892a7dbb
--- /dev/null
+++ b/historic/jam/src/filemac.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+# ifdef OS_MAC
+
+#include
+#include
+
+# include <:sys:stat.h>
+
+/*
+ * filemac.c - manipulate file names and scan directories on macintosh
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 12/19/94 (mikem) - solaris string table insanity support
+ * 02/14/95 (seiwald) - parse and build /xxx properly
+ * 05/03/96 (seiwald) - split into pathunix.c
+ * 11/21/96 (peterk) - BEOS does not have Unix-style archives
+ */
+
+void CopyC2PStr(const char * cstr, StringPtr pstr)
+{
+ int len;
+
+ for (len = 0; *cstr && len<255; pstr[++len] = *cstr++)
+ ;
+
+ pstr[0] = len;
+}
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int s, time_t t ) )
+{
+ FILENAME f;
+ string filename[1];
+ unsigned char fullPath[ 512 ];
+
+ FSSpec spec;
+ WDPBRec vol;
+ Str63 volName;
+ CInfoPBRec lastInfo;
+ int index = 1;
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+ /* Special case ":" - enter it */
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == ':' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+
+ /* Now enter contents of directory */
+
+ vol.ioNamePtr = volName;
+
+ if( PBHGetVolSync( &vol ) )
+ return;
+
+ CopyC2PStr( dir, fullPath );
+
+ if( FSMakeFSSpec( vol.ioWDVRefNum, vol.ioWDDirID, fullPath, &spec ) )
+ return;
+
+ lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
+ lastInfo.dirInfo.ioDrDirID = spec.parID;
+ lastInfo.dirInfo.ioNamePtr = spec.name;
+ lastInfo.dirInfo.ioFDirIndex = 0;
+ lastInfo.dirInfo.ioACUser = 0;
+
+ if( PBGetCatInfoSync(&lastInfo) )
+ return;
+
+ if (!(lastInfo.dirInfo.ioFlAttrib & 0x10))
+ return;
+
+ // ioDrDirID must be reset each time.
+
+ spec.parID = lastInfo.dirInfo.ioDrDirID;
+
+ string_new( filename );
+ for( ;; )
+ {
+ lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
+ lastInfo.dirInfo.ioDrDirID = spec.parID;
+ lastInfo.dirInfo.ioNamePtr = fullPath;
+ lastInfo.dirInfo.ioFDirIndex = index++;
+
+ if( PBGetCatInfoSync(&lastInfo) )
+ return;
+
+ f.f_base.ptr = (char *)fullPath + 1;
+ f.f_base.len = *fullPath;
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+ (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 );
+ }
+ string_free( filename );
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+
+ return 0;
+}
+
+/*
+ * file_archscan() - scan an archive for files
+ */
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int s, time_t t ) )
+
+{
+}
+
+
+# endif /* macintosh */
+
diff --git a/historic/jam/src/filent.c b/historic/jam/src/filent.c
new file mode 100644
index 000000000..951e74a3c
--- /dev/null
+++ b/historic/jam/src/filent.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+# include "strings.h"
+
+# ifdef OS_NT
+
+# ifdef __BORLANDC__
+# if __BORLANDC__ < 0x550
+# include
+# include
+# endif
+# undef FILENAME /* cpp namespace collision */
+# define _finddata_t ffblk
+# endif
+
+# include
+# include
+
+/*
+ * filent.c - scan directories and archives on NT
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 07/10/95 (taylor) Findfirst() returns the first file on NT.
+ * 05/03/96 (seiwald) split apart into pathnt.c
+ */
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ FILENAME f;
+ string filespec[1];
+ string filename[1];
+ long handle;
+ int ret;
+ struct _finddata_t finfo[1];
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ dir = *dir ? dir : ".";
+
+ /* Special case \ or d:\ : enter it */
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+ else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+
+ /* Now enter contents of directory */
+
+ string_copy( filespec, dir );
+ string_append( filespec, "/*" );
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+# if defined(__BORLANDC__) && __BORLANDC__ < 0x550
+ if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
+ {
+ string_free( filespec );
+ return;
+ }
+
+ string_new( filename );
+ while( !ret )
+ {
+ time_t time_write = finfo->ff_fdate;
+
+ time_write = (time_write << 16) | finfo->ff_ftime;
+ f.f_base.ptr = finfo->ff_name;
+ f.f_base.len = strlen( finfo->ff_name );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename );
+
+ (*func)( filename->value, 1 /* stat()'ed */, time_write );
+
+ ret = findnext( finfo );
+ }
+# else
+ handle = _findfirst( filespec->value, finfo );
+
+ if( ret = ( handle < 0L ) )
+ {
+ string_free( filespec );
+ return;
+ }
+
+ string_new( filename );
+ while( !ret )
+ {
+ f.f_base.ptr = finfo->name;
+ f.f_base.len = strlen( finfo->name );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+
+ (*func)( filename->value, 1 /* stat()'ed */, finfo->time_write );
+
+ ret = _findnext( handle, finfo );
+ }
+
+ _findclose( handle );
+# endif
+ string_free( filename );
+ string_free( filespec );
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ /* On NT this is called only for C:/ */
+
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+
+ return 0;
+}
+
+/*
+ * file_archscan() - scan an archive for files
+ */
+
+/* Straight from SunOS */
+
+#define ARMAG "!\n"
+#define SARMAG 8
+
+#define ARFMAG "`\n"
+
+struct ar_hdr {
+ char ar_name[16];
+ char ar_date[12];
+ char ar_uid[6];
+ char ar_gid[6];
+ char ar_mode[8];
+ char ar_size[10];
+ char ar_fmag[2];
+};
+
+# define SARFMAG 2
+# define SARHDR sizeof( struct ar_hdr )
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ struct ar_hdr ar_hdr;
+ char *string_table = 0;
+ char buf[ MAXJPATH ];
+ long offset;
+ int fd;
+
+ if( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 )
+ return;
+
+ if( read( fd, buf, SARMAG ) != SARMAG ||
+ strncmp( ARMAG, buf, SARMAG ) )
+ {
+ close( fd );
+ return;
+ }
+
+ offset = SARMAG;
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan archive %s\n", archive );
+
+ while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
+ !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
+ {
+ long lar_date;
+ long lar_size;
+ char *name = 0;
+ char *endname;
+ char *c;
+
+ sscanf( ar_hdr.ar_date, "%ld", &lar_date );
+ sscanf( ar_hdr.ar_size, "%ld", &lar_size );
+
+ lar_size = ( lar_size + 1 ) & ~1;
+
+ if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' )
+ {
+ /* this is the "string table" entry of the symbol table,
+ ** which holds strings of filenames that are longer than
+ ** 15 characters (ie. don't fit into a ar_name
+ */
+
+ string_table = malloc(lar_size);
+ if (read(fd, string_table, lar_size) != lar_size)
+ printf("error reading string table\n");
+ offset += SARHDR + lar_size;
+ continue;
+ }
+ else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ')
+ {
+ /* Long filenames are recognized by "/nnnn" where nnnn is
+ ** the offset of the string in the string table represented
+ ** in ASCII decimals.
+ */
+
+ name = string_table + atoi( ar_hdr.ar_name + 1 );
+ endname = name + strlen( name );
+ }
+ else
+ {
+ /* normal name */
+ name = ar_hdr.ar_name;
+ endname = name + sizeof( ar_hdr.ar_name );
+ }
+
+ /* strip trailing space, slashes, and backslashes */
+
+ while( endname-- > name )
+ if( *endname != ' ' && *endname != '\\' && *endname != '/' )
+ break;
+ *++endname = 0;
+
+ /* strip leading directory names, an NT specialty */
+
+ if( c = strrchr( name, '/' ) )
+ name = c + 1;
+ if( c = strrchr( name, '\\' ) )
+ name = c + 1;
+
+ sprintf( buf, "%s(%.*s)", archive, endname - name, name );
+ (*func)( buf, 1 /* time valid */, (time_t)lar_date );
+
+ offset += SARHDR + lar_size;
+ lseek( fd, offset, 0 );
+ }
+
+ close( fd );
+}
+
+# endif /* NT */
diff --git a/historic/jam/src/fileos2.c b/historic/jam/src/fileos2.c
new file mode 100644
index 000000000..e536c4e70
--- /dev/null
+++ b/historic/jam/src/fileos2.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+/* note that we use "fileunix.c" when compiling with EMX on OS/2 */
+# if defined(OS_OS2) && !defined(__EMX__)
+
+# include
+# include
+
+/*
+ * fileos2.c - scan directories and archives on NT
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 07/10/95 (taylor) Findfirst() returns the first file on NT.
+ * 05/03/96 (seiwald) split apart into pathnt.c
+ * 09/22/00 (seiwald) handle \ and c:\ specially: don't add extra /
+ */
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ FILENAME f;
+ string filespec[1];
+ long handle;
+ int ret;
+ struct _find_t finfo[1];
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ dir = *dir ? dir : ".";
+
+ /* Special case \ or d:\ : enter it */
+ string_copy( filespec, dir );
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+ else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+ else
+ string_push_back( filespec, '/' );
+
+ string_push_back( filespec, '*' );
+
+ /* Now enter contents of directory */
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", filespec->value );
+
+ /* Time info in dos find_t is not very useful. It consists */
+ /* of a separate date and time, and putting them together is */
+ /* not easy. So we leave that to a later stat() call. */
+
+ if( !_dos_findfirst( filespec->value, _A_NORMAL|_A_RDONLY|_A_SUBDIR, finfo ) )
+ {
+ string filename[1];
+ string_new( filename );
+ do
+ {
+
+ f.f_base.ptr = finfo->name;
+ f.f_base.len = strlen( finfo->name );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+ (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 );
+ }
+ while( !_dos_findnext( finfo ) );
+ string_free( filename );
+ }
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ /* This is called on OS2, not NT. */
+ /* NT fills in the time in the dirscan. */
+
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+
+ return 0;
+}
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+}
+
+# endif /* OS2 && !__EMX__ */
+
diff --git a/historic/jam/src/filesys.c b/historic/jam/src/filesys.c
new file mode 100644
index 000000000..c38d9e468
--- /dev/null
+++ b/historic/jam/src/filesys.c
@@ -0,0 +1,33 @@
+# include "jam.h"
+# include "filesys.h"
+# include "strings.h"
+
+void
+file_build1(
+ FILENAME *f,
+ string* file)
+{
+ if( DEBUG_SEARCH )
+ {
+ printf("build file: ");
+ if( f->f_root.len )
+ printf( "root = '%.*s' ", f->f_root.len, f->f_root.ptr );
+ if( f->f_dir.len )
+ printf( "dir = '%.*s' ", f->f_dir.len, f->f_dir.ptr );
+ if( f->f_base.len )
+ printf( "base = '%.*s' ", f->f_base.len, f->f_base.ptr );
+ }
+
+ /* Start with the grist. If the current grist isn't */
+ /* surrounded by <>'s, add them. */
+
+ if( f->f_grist.len )
+ {
+ if( f->f_grist.ptr[0] != '<' )
+ string_push_back( file, '<' );
+ string_append_range(
+ file, f->f_grist.ptr, f->f_grist.ptr + f->f_grist.len );
+ if( file->value[file->size - 1] != '>' )
+ string_push_back( file, '>' );
+ }
+}
diff --git a/historic/jam/src/filesys.h b/historic/jam/src/filesys.h
new file mode 100644
index 000000000..c46b1c2a5
--- /dev/null
+++ b/historic/jam/src/filesys.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * filesys.h - FILENAME struct and OS specific file routines
+ */
+
+/*
+ * FILENAME - a name of a file, broken into dir/base/suffix(member)
+ *
+ * is salt to distinguish between targets that otherwise would
+ * have the same name: it never appears in the bound name of a target.
+ * (member) is an archive member name: the syntax is arbitrary, but must
+ * agree in file_parse(), file_build() and the Jambase.
+ *
+ * On VMS, we keep track of whether the original path was a directory
+ * (without a file), so that $(VAR:D) can climb to the parent.
+ */
+
+#ifndef FILESYS_DWA20011025_H
+# define FILESYS_DWA20011025_H
+
+# include "strings.h"
+
+typedef struct _filename FILENAME;
+typedef struct _filepart FILEPART;
+
+struct _filepart {
+ char *ptr;
+ int len;
+};
+
+struct _filename {
+ FILEPART part[6];
+# ifdef OS_VMS
+ int parent;
+# endif
+
+# define f_grist part[0]
+# define f_root part[1]
+# define f_dir part[2]
+# define f_base part[3]
+# define f_suffix part[4]
+# define f_member part[5]
+
+} ;
+
+void file_build( FILENAME *f, string *file, int binding );
+void file_build1( FILENAME *f, string *file );
+
+void file_parse( char *file, FILENAME *f );
+void file_parent( FILENAME *f );
+
+void file_dirscan( char *dir, void (*func)( char *f, int s, time_t t ) );
+void file_archscan( char *arch, void (*func)( char *f, int s, time_t t ) );
+
+int file_time( char *filename, time_t *time );
+
+#endif // FILESYS_DWA20011025_H
diff --git a/historic/jam/src/fileunix.c b/historic/jam/src/fileunix.c
new file mode 100644
index 000000000..8ea80a506
--- /dev/null
+++ b/historic/jam/src/fileunix.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+# include "strings.h"
+
+# ifdef USE_FILEUNIX
+
+# if defined( OS_SEQUENT ) || \
+ defined( OS_DGUX ) || \
+ defined( OS_SCO ) || \
+ defined( OS_ISC )
+# define PORTAR 1
+# endif
+
+# ifdef __EMX__
+# include
+# include
+# endif
+
+# if defined( OS_RHAPSODY ) || \
+ defined( OS_MACOSX ) || \
+ defined( OS_NEXT )
+/* need unistd for rhapsody's proper lseek */
+# include
+# include
+# define STRUCT_DIRENT struct direct
+# else
+# include
+# define STRUCT_DIRENT struct dirent
+# endif
+
+# ifdef OS_COHERENT
+# include
+# define HAVE_AR
+# endif
+
+# if defined( OS_MVS ) || \
+ defined( OS_INTERIX )
+
+#define ARMAG "!\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+struct ar_hdr /* archive file member header - printable ascii */
+{
+ char ar_name[16]; /* file member name - `/' terminated */
+ char ar_date[12]; /* file member date - decimal */
+ char ar_uid[6]; /* file member user id - decimal */
+ char ar_gid[6]; /* file member group id - decimal */
+ char ar_mode[8]; /* file member mode - octal */
+ char ar_size[10]; /* file member size - decimal */
+ char ar_fmag[2]; /* ARFMAG - string to end header */
+};
+
+# define HAVE_AR
+# endif
+
+# if defined( OS_QNX ) || \
+ defined( OS_BEOS ) || \
+ defined( OS_MPEIX )
+# define NO_AR
+# define HAVE_AR
+# endif
+
+# ifndef HAVE_AR
+# include
+# endif
+
+/*
+ * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 12/19/94 (mikem) - solaris string table insanity support
+ * 02/14/95 (seiwald) - parse and build /xxx properly
+ * 05/03/96 (seiwald) - split into pathunix.c
+ * 11/21/96 (peterk) - BEOS does not have Unix-style archives
+ */
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ FILENAME f;
+ DIR *d;
+ STRUCT_DIRENT *dirent;
+ string filename[1];
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ dir = *dir ? dir : ".";
+
+ /* Special case / : enter it */
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+
+ /* Now enter contents of directory */
+
+ if( !( d = opendir( dir ) ) )
+ return;
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+ string_new( filename );
+ while( dirent = readdir( d ) )
+ {
+# ifdef old_sinix
+ /* Broken structure definition on sinix. */
+ f.f_base.ptr = dirent->d_name - 2;
+# else
+ f.f_base.ptr = dirent->d_name;
+# endif
+ f.f_base.len = strlen( f.f_base.ptr );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+
+ (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 );
+ }
+ string_free( filename );
+
+ closedir( d );
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+ return 0;
+}
+
+/*
+ * file_archscan() - scan an archive for files
+ */
+
+# ifndef AIAMAG /* God-fearing UNIX */
+
+# define SARFMAG 2
+# define SARHDR sizeof( struct ar_hdr )
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+# ifndef NO_AR
+ struct ar_hdr ar_hdr;
+ char buf[ MAXJPATH ];
+ long offset;
+ char *string_table = 0;
+ int fd;
+
+ if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
+ return;
+
+ if( read( fd, buf, SARMAG ) != SARMAG ||
+ strncmp( ARMAG, buf, SARMAG ) )
+ {
+ close( fd );
+ return;
+ }
+
+ offset = SARMAG;
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan archive %s\n", archive );
+
+ while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
+ !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
+ {
+ char lar_name[256];
+ long lar_date;
+ long lar_size;
+ long lar_offset;
+ char *c;
+ char *src, *dest;
+
+ strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
+
+ sscanf( ar_hdr.ar_date, "%ld", &lar_date );
+ sscanf( ar_hdr.ar_size, "%ld", &lar_size );
+
+ if (ar_hdr.ar_name[0] == '/')
+ {
+ if (ar_hdr.ar_name[1] == '/')
+ {
+ /* this is the "string table" entry of the symbol table,
+ ** which holds strings of filenames that are longer than
+ ** 15 characters (ie. don't fit into a ar_name
+ */
+
+ string_table = (char *)malloc(lar_size);
+ lseek(fd, offset + SARHDR, 0);
+ if (read(fd, string_table, lar_size) != lar_size)
+ printf("error reading string table\n");
+ }
+ else if (string_table && ar_hdr.ar_name[1] != ' ')
+ {
+ /* Long filenames are recognized by "/nnnn" where nnnn is
+ ** the offset of the string in the string table represented
+ ** in ASCII decimals.
+ */
+ dest = lar_name;
+ lar_offset = atoi(lar_name + 1);
+ src = &string_table[lar_offset];
+ while (*src != '/')
+ *dest++ = *src++;
+ *dest = '/';
+ }
+ }
+
+ c = lar_name - 1;
+ while( *++c != ' ' && *c != '/' )
+ ;
+ *c = '\0';
+
+ if ( DEBUG_BINDSCAN )
+ printf( "archive name %s found\n", lar_name );
+
+ sprintf( buf, "%s(%s)", archive, lar_name );
+
+ (*func)( buf, 1 /* time valid */, (time_t)lar_date );
+
+ offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
+ lseek( fd, offset, 0 );
+ }
+
+ if (string_table)
+ free(string_table);
+
+ close( fd );
+
+# endif /* NO_AR */
+
+}
+
+# else /* AIAMAG - RS6000 AIX */
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ struct fl_hdr fl_hdr;
+
+ struct {
+ struct ar_hdr hdr;
+ char pad[ 256 ];
+ } ar_hdr ;
+
+ char buf[ MAXJPATH ];
+ long offset;
+ int fd;
+
+ if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
+ return;
+
+ if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
+ strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
+ {
+ close( fd );
+ return;
+ }
+
+ sscanf( fl_hdr.fl_fstmoff, "%ld", &offset );
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan archive %s\n", archive );
+
+ while( offset > 0 &&
+ lseek( fd, offset, 0 ) >= 0 &&
+ read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) )
+ {
+ long lar_date;
+ int lar_namlen;
+
+ sscanf( ar_hdr.hdr.ar_namlen, "%d", &lar_namlen );
+ sscanf( ar_hdr.hdr.ar_date, "%ld", &lar_date );
+ sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset );
+
+ if( !lar_namlen )
+ continue;
+
+ ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
+
+ sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
+
+ (*func)( buf, 1 /* time valid */, (time_t)lar_date );
+ }
+
+ close( fd );
+}
+
+# endif /* AIAMAG - RS6000 AIX */
+
+# endif /* USE_FILEUNIX */
+
diff --git a/historic/jam/src/filevms.c b/historic/jam/src/filevms.c
new file mode 100644
index 000000000..ad19725b0
--- /dev/null
+++ b/historic/jam/src/filevms.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+# ifdef OS_VMS
+
+/*
+ * filevms.c - scan directories and libaries on VMS
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
+ * 05/03/96 (seiwald) - split into pathvms.c
+ */
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Supply missing prototypes for lbr$-routines*/
+int lbr$close();
+int lbr$get_index();
+int lbr$ini_control();
+int lbr$open();
+int lbr$set_module();
+
+/*
+ * unlink() - remove a file
+ */
+
+#if __CRTL_VER < 70000000
+
+unlink( char *f )
+{
+ remove( f );
+}
+
+#endif
+
+static void
+file_cvttime(
+ unsigned int *curtime,
+ time_t *unixtime )
+{
+ static const size_t divisor = 10000000;
+ static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
+ int delta[2], remainder;
+
+ lib$subx( curtime, bastim, delta );
+ lib$ediv( &divisor, delta, unixtime, &remainder );
+}
+
+# define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
+
+# define min( a,b ) ((a)<(b)?(a):(b))
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+
+ struct FAB xfab;
+ struct NAM xnam;
+ struct XABDAT xab;
+ char esa[256];
+ char filename[256];
+ string filename2[1];
+ char dirname[256];
+ register int status;
+ FILENAME f;
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_root.ptr = dir;
+ f.f_root.len = strlen( dir );
+
+ /* get the input file specification
+ */
+ xnam = cc$rms_nam;
+ xnam.nam$l_esa = esa;
+ xnam.nam$b_ess = sizeof( esa ) - 1;
+ xnam.nam$l_rsa = filename;
+ xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS );
+
+ xab = cc$rms_xabdat; /* initialize extended attributes */
+ xab.xab$b_cod = XAB$C_DAT; /* ask for date */
+ xab.xab$l_nxt = NULL; /* terminate XAB chain */
+
+ xfab = cc$rms_fab;
+ xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION;
+ xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1;
+ xfab.fab$l_fop = FAB$M_NAM;
+ xfab.fab$l_fna = dir; /* address of file name */
+ xfab.fab$b_fns = strlen( dir ); /* length of file name */
+ xfab.fab$l_nam = &xnam; /* address of NAB block */
+ xfab.fab$l_xab = (char *)&xab; /* address of XAB block */
+
+
+ status = sys$parse( &xfab );
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+ if ( !( status & 1 ) )
+ return;
+
+
+
+ /* Add bogus directory for [000000] */
+
+ if( !strcmp( dir, "[000000]" ) )
+ {
+ (*func)( "[000000]", 1 /* time valid */, 1 /* old but true */ );
+ }
+
+ /* Add bogus directory for [] */
+
+ if( !strcmp( dir, "[]" ) )
+ {
+ (*func)( "[]", 1 /* time valid */, 1 /* old but true */ );
+ (*func)( "[-]", 1 /* time valid */, 1 /* old but true */ );
+ }
+
+ string_new( filename2 );
+ while ( (status = sys$search( &xfab )) & 1 )
+ {
+ char *s;
+ time_t time;
+
+ /* "I think that might work" - eml */
+
+ sys$open( &xfab );
+ sys$close( &xfab );
+
+ file_cvttime( (unsigned int *)&xab.xab$q_rdt, &time );
+
+ filename[xnam.nam$b_rsl] = '\0';
+
+ /* What we do with the name depends on the suffix: */
+ /* .dir is a directory */
+ /* .xxx is a file with a suffix */
+ /* . is no suffix at all */
+
+ if( xnam.nam$b_type == 4 && !strncmp( xnam.nam$l_type, ".DIR", 4 ) )
+ {
+ /* directory */
+ sprintf( dirname, "[.%.*s]", xnam.nam$b_name, xnam.nam$l_name );
+ f.f_dir.ptr = dirname;
+ f.f_dir.len = strlen( dirname );
+ f.f_base.ptr = 0;
+ f.f_base.len = 0;
+ f.f_suffix.ptr = 0;
+ f.f_suffix.len = 0;
+ }
+ else
+ {
+ /* normal file with a suffix */
+ f.f_dir.ptr = 0;
+ f.f_dir.len = 0;
+ f.f_base.ptr = xnam.nam$l_name;
+ f.f_base.len = xnam.nam$b_name;
+ f.f_suffix.ptr = xnam.nam$l_type;
+ f.f_suffix.len = xnam.nam$b_type;
+ }
+
+ string_truncate( filename2, 0 );
+ file_build( &f, filename2, 0 );
+
+ /*
+ if( DEBUG_SEARCH )
+ printf("root '%s' base %.*s suf %.*s = %s\n",
+ dir,
+ xnam.nam$b_name, xnam.nam$l_name,
+ xnam.nam$b_type, xnam.nam$l_type,
+ filename2);
+ */
+
+ (*func)( filename2->value, 1 /* time valid */, time );
+ }
+ string_free( filename2 );
+
+ if ( status != RMS$_NMF && status != RMS$_FNF )
+ lib$signal( xfab.fab$l_sts, xfab.fab$l_stv );
+}
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ /* This should never be called, as all files are */
+ /* timestampped in file_dirscan() and file_archscan() */
+ return -1;
+}
+
+static char *VMS_archive = 0;
+static void (*VMS_func)( char *file, int status, time_t t ) = 0;
+static void *context;
+
+static int
+file_archmember(
+ struct dsc$descriptor_s *module,
+ unsigned long *rfa )
+{
+ static struct dsc$descriptor_s bufdsc =
+ {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
+
+ struct mhddef *mhd;
+ char filename[128];
+ char buf[ MAXJPATH ];
+
+ int status;
+ time_t library_date;
+
+ register int i;
+ register char *p;
+
+ bufdsc.dsc$a_pointer = filename;
+ bufdsc.dsc$w_length = sizeof( filename );
+ status = lbr$set_module( &context, rfa, &bufdsc,
+ &bufdsc.dsc$w_length, NULL );
+ if ( !(status & 1) )
+ return ( 1 );
+
+ mhd = (struct mhddef *)filename;
+
+ file_cvttime( &mhd->mhd$l_datim, &library_date );
+
+ for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; i++, p++ )
+ filename[i] = *p;
+
+ filename[i] = '\0';
+
+ sprintf( buf, "%s(%s.obj)", VMS_archive, filename );
+
+ (*VMS_func)( buf, 1 /* time valid */, (time_t)library_date );
+
+ return ( 1 );
+}
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ static struct dsc$descriptor_s library =
+ {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
+
+ unsigned long lfunc = LBR$C_READ;
+ unsigned long typ = LBR$C_TYP_UNK;
+ unsigned long index = 1;
+
+ register int status;
+
+ VMS_archive = archive;
+ VMS_func = func;
+
+ status = lbr$ini_control( &context, &lfunc, &typ, NULL );
+ if ( !( status & 1 ) )
+ return;
+
+ library.dsc$a_pointer = archive;
+ library.dsc$w_length = strlen( archive );
+
+ status = lbr$open( &context, &library, NULL, NULL, NULL, NULL, NULL );
+ if ( !( status & 1 ) )
+ return;
+
+ (void) lbr$get_index( &context, &index, file_archmember, NULL );
+
+ (void) lbr$close( &context );
+}
+
+# endif /* VMS */
+
diff --git a/historic/jam/src/frames.h b/historic/jam/src/frames.h
new file mode 100644
index 000000000..e0dc6761e
--- /dev/null
+++ b/historic/jam/src/frames.h
@@ -0,0 +1,19 @@
+#ifndef FRAMES_DWA20011021_H
+# define FRAMES_DWA20011021_H
+
+# include "lists.h"
+# include "modules.h"
+
+typedef struct frame FRAME;
+
+struct frame
+{
+ FRAME* prev;
+ LOL args[1];
+ module* module;
+};
+
+void frame_init( FRAME* ); /* implemented in compile.c */
+void frame_free( FRAME* ); /* implemented in compile.c */
+
+#endif // FRAMES_DWA20011021_H
diff --git a/historic/jam/src/glob.c b/historic/jam/src/glob.c
new file mode 100644
index 000000000..abb56eb1b
--- /dev/null
+++ b/historic/jam/src/glob.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 1994 Christopher Seiwald. All rights reserved.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * glob.c - match a string against a simple pattern
+ *
+ * Understands the following patterns:
+ *
+ * * any number of characters
+ * ? any single character
+ * [a-z] any single character in the range a-z
+ * [^a-z] any single character not in the range a-z
+ * \x match x
+ *
+ * External functions:
+ *
+ * glob() - match a string against a simple pattern
+ *
+ * Internal functions:
+ *
+ * globchars() - build a bitlist to check for character group match
+ */
+
+# include "jam.h"
+
+# define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
+# define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
+
+static void globchars( char *s, char *e, char *b );
+
+/*
+ * glob() - match a string against a simple pattern
+ */
+
+int
+glob(
+ register char *c,
+ register char *s )
+{
+ char bitlist[ BITLISTSIZE ];
+ char *here;
+
+ for( ;; )
+ switch( *c++ )
+ {
+ case '\0':
+ return *s ? -1 : 0;
+
+ case '?':
+ if( !*s++ )
+ return 1;
+ break;
+
+ case '[':
+ /* scan for matching ] */
+
+ here = c;
+ do if( !*c++ )
+ return 1;
+ while( here == c || *c != ']' );
+ c++;
+
+ /* build character class bitlist */
+
+ globchars( here, c, bitlist );
+
+ if( !CHECK_BIT( bitlist, *(unsigned char *)s ) )
+ return 1;
+ s++;
+ break;
+
+ case '*':
+ here = s;
+
+ while( *s )
+ s++;
+
+ /* Try to match the rest of the pattern in a recursive */
+ /* call. If the match fails we'll back up chars, retrying. */
+
+ while( s != here )
+ {
+ int r;
+
+ /* A fast path for the last token in a pattern */
+
+ r = *c ? glob( c, s ) : *s ? -1 : 0;
+
+ if( !r )
+ return 0;
+ else if( r < 0 )
+ return 1;
+
+ --s;
+ }
+ break;
+
+ case '\\':
+ /* Force literal match of next char. */
+
+ if( !*c || *s++ != *c++ )
+ return 1;
+ break;
+
+ default:
+ if( *s++ != c[-1] )
+ return 1;
+ break;
+ }
+}
+
+/*
+ * globchars() - build a bitlist to check for character group match
+ */
+
+static void
+globchars(
+ char *s,
+ char *e,
+ char *b )
+{
+ int neg = 0;
+
+ memset( b, '\0', BITLISTSIZE );
+
+ if( *s == '^')
+ neg++, s++;
+
+ while( s < e )
+ {
+ int c;
+
+ if( s+2 < e && s[1] == '-' )
+ {
+ for( c = s[0]; c <= s[2]; c++ )
+ b[ c/8 ] |= (1<<(c%8));
+ s += 3;
+ } else {
+ c = *s++;
+ b[ c/8 ] |= (1<<(c%8));
+ }
+ }
+
+ if( neg )
+ {
+ int i;
+ for( i = 0; i < BITLISTSIZE; i++ )
+ b[ i ] ^= 0377;
+ }
+
+ /* Don't include \0 in either $[chars] or $[^chars] */
+
+ b[0] &= 0376;
+}
diff --git a/historic/jam/src/hash.c b/historic/jam/src/hash.c
new file mode 100644
index 000000000..c632c8fe9
--- /dev/null
+++ b/historic/jam/src/hash.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "hash.h"
+
+/*
+ * hash.c - simple in-memory hashing routines
+ *
+ * External routines:
+ *
+ * hashinit() - initialize a hash table, returning a handle
+ * hashitem() - find a record in the table, and optionally enter a new one
+ * hashdone() - free a hash table, given its handle
+ *
+ * Internal routines:
+ *
+ * hashrehash() - resize and rebuild hp->tab, the hash table
+ *
+ * 4/29/93 - ensure ITEM's are aligned
+ */
+
+char *hashsccssid="@(#)hash.c 1.14 () 6/20/88";
+
+/* Header attached to all data items entered into a hash table. */
+
+struct hashhdr {
+ struct item *next;
+ int keyval; /* for quick comparisons */
+} ;
+
+/* This structure overlays the one handed to hashenter(). */
+/* It's actual size is given to hashinit(). */
+
+struct hashdata {
+ char *key;
+ /* rest of user data */
+} ;
+
+typedef struct item {
+ struct hashhdr hdr;
+ struct hashdata data;
+} ITEM ;
+
+# define MAX_LISTS 32
+
+struct hash
+{
+ /*
+ * the hash table, just an array of item pointers
+ */
+ struct {
+ int nel;
+ ITEM **base;
+ } tab;
+
+ int bloat; /* tab.nel / items.nel */
+ int inel; /* initial number of elements */
+
+ /*
+ * the array of records, maintained by these routines
+ * essentially a microallocator
+ */
+ struct {
+ int more; /* how many more ITEMs fit in lists[ list ] */
+ char *next; /* where to put more ITEMs in lists[ list ] */
+ int datalen; /* length of records in this hash table */
+ int size; /* sizeof( ITEM ) + aligned datalen */
+ int nel; /* total ITEMs held by all lists[] */
+ int list; /* index into lists[] */
+
+ struct {
+ int nel; /* total ITEMs held by this list */
+ char *base; /* base of ITEMs array */
+ } lists[ MAX_LISTS ];
+ } items;
+
+ char *name; /* just for hashstats() */
+} ;
+
+static void hashrehash( struct hash *hp );
+static void hashstat( struct hash *hp );
+
+/*
+ * hashitem() - find a record in the table, and optionally enter a new one
+ */
+
+int
+hashitem(
+ register struct hash *hp,
+ HASHDATA **data,
+ int enter )
+{
+ ITEM **base;
+ register ITEM *i;
+ char *b = (*data)->key;
+ int keyval;
+
+ if( enter && !hp->items.more )
+ hashrehash( hp );
+
+ if( !enter && !hp->items.nel )
+ return 0;
+
+ keyval = *b;
+
+ while( *b )
+ keyval = keyval * 2147059363 + *b++;
+
+ keyval &= 0x7FFFFFFF;
+
+ base = hp->tab.base + ( keyval % hp->tab.nel );
+
+ for( i = *base; i; i = i->hdr.next )
+ if( keyval == i->hdr.keyval &&
+ !strcmp( i->data.key, (*data)->key ) )
+ {
+ *data = &i->data;
+ return !0;
+ }
+
+ if( enter )
+ {
+ i = (ITEM *)hp->items.next;
+ hp->items.next += hp->items.size;
+ hp->items.more--;
+ memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
+ i->hdr.keyval = keyval;
+ i->hdr.next = *base;
+ *base = i;
+ *data = &i->data;
+ }
+
+ return 0;
+}
+
+/*
+ * hashrehash() - resize and rebuild hp->tab, the hash table
+ */
+
+static void hashrehash( register struct hash *hp )
+{
+ int i = ++hp->items.list;
+
+ hp->items.more = i ? 2 * hp->items.nel : hp->inel;
+ hp->items.next = (char *)malloc( hp->items.more * hp->items.size );
+
+ hp->items.lists[i].nel = hp->items.more;
+ hp->items.lists[i].base = hp->items.next;
+ hp->items.nel += hp->items.more;
+
+ if( hp->tab.base )
+ free( (char *)hp->tab.base );
+
+ hp->tab.nel = hp->items.nel * hp->bloat;
+ hp->tab.base = (ITEM **)malloc( hp->tab.nel * sizeof(ITEM **) );
+
+ memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
+
+ for( i = 0; i < hp->items.list; i++ )
+ {
+ int nel = hp->items.lists[i].nel;
+ char *next = hp->items.lists[i].base;
+
+ for( ; nel--; next += hp->items.size )
+ {
+ register ITEM *i = (ITEM *)next;
+ ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
+
+ i->hdr.next = *ip;
+ *ip = i;
+ }
+ }
+}
+
+void hashenumerate( struct hash *hp, void (*f)(void*,void*), void* data )
+{
+ int i;
+ for( i = 0; i <= hp->items.list; i++ )
+ {
+ char *next = hp->items.lists[i].base;
+ int nel = hp->items.lists[i].nel;
+ if ( i == hp->items.list )
+ nel -= hp->items.more;
+
+ for( ; nel--; next += hp->items.size )
+ {
+ register ITEM *i = (ITEM *)next;
+ f(&i->data, data);
+ }
+ }
+}
+
+/* --- */
+
+# define ALIGNED(x) ( ( x + sizeof( ITEM ) - 1 ) & ~( sizeof( ITEM ) - 1 ) )
+
+/*
+ * hashinit() - initialize a hash table, returning a handle
+ */
+
+struct hash *
+hashinit(
+ int datalen,
+ char *name )
+{
+ struct hash *hp = (struct hash *)malloc( sizeof( *hp ) );
+
+ hp->bloat = 3;
+ hp->tab.nel = 0;
+ hp->tab.base = (ITEM **)0;
+ hp->items.more = 0;
+ hp->items.datalen = datalen;
+ hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
+ hp->items.list = -1;
+ hp->items.nel = 0;
+ hp->inel = 11;
+ hp->name = name;
+
+ return hp;
+}
+
+/*
+ * hashdone() - free a hash table, given its handle
+ */
+
+void
+hashdone( struct hash *hp )
+{
+ int i;
+
+ if( !hp )
+ return;
+
+ if( DEBUG_MEM )
+ hashstat( hp );
+
+ if( hp->tab.base )
+ free( (char *)hp->tab.base );
+ for( i = 0; i <= hp->items.list; i++ )
+ free( hp->items.lists[i].base );
+ free( (char *)hp );
+}
+
+/* ---- */
+
+static void
+hashstat( struct hash *hp )
+{
+ ITEM **tab = hp->tab.base;
+ int nel = hp->tab.nel;
+ int count = 0;
+ int sets = 0;
+ int run = ( tab[ nel - 1 ] != (ITEM *)0 );
+ int i, here;
+
+ for( i = nel; i > 0; i-- )
+ {
+ if( here = ( *tab++ != (ITEM *)0 ) )
+ count++;
+ if( here && !run )
+ sets++;
+ run = here;
+ }
+
+ printf( "%s table: %d+%d+%d (%dK+%dK) items+table+hash, %f density\n",
+ hp->name,
+ count,
+ hp->items.nel,
+ hp->tab.nel,
+ hp->items.nel * hp->items.size / 1024,
+ hp->tab.nel * sizeof( ITEM ** ) / 1024,
+ (float)count / (float)sets );
+}
diff --git a/historic/jam/src/hash.h b/historic/jam/src/hash.h
new file mode 100644
index 000000000..a9fd4ce17
--- /dev/null
+++ b/historic/jam/src/hash.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * hash.h - simple in-memory hashing routines
+ */
+
+typedef struct hashdata HASHDATA;
+
+struct hash * hashinit( int datalen, char *name );
+int hashitem( struct hash *hp, HASHDATA **data, int enter );
+void hashdone( struct hash *hp );
+void hashenumerate( struct hash *hp, void (*f)(void*,void*), void* data );
+
+# define hashenter( hp, data ) !hashitem( hp, data, !0 )
+# define hashcheck( hp, data ) hashitem( hp, data, 0 )
diff --git a/historic/jam/src/hdrmacro.c b/historic/jam/src/hdrmacro.c
new file mode 100644
index 000000000..a59de44e3
--- /dev/null
+++ b/historic/jam/src/hdrmacro.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "compile.h"
+# include "rules.h"
+# include "variable.h"
+# include "regexp.h"
+# include "hdrmacro.h"
+# include "hash.h"
+# include "newstr.h"
+# include "strings.h"
+
+/*
+ * hdrmacro.c - handle header files that define macros used in
+ * #include statements.
+ *
+ * we look for lines like "#define MACRO <....>" or '#define MACRO " "'
+ * in the target file. When found, we
+ *
+ * we then phony up a rule invocation like:
+ *
+ * $(HDRRULE) : ;
+ *
+ * External routines:
+ * headers1() - scan a target for "#include MACRO" lines and try
+ * to resolve them when needed
+ *
+ * Internal routines:
+ * headers1() - using regexp, scan a file and build include LIST
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule,
+ * so that headers() doesn't have to mock up a parse structure
+ * just to invoke a rule.
+ */
+
+static LIST *header_macros1( LIST *l, char *file, int rec, regexp *re[] );
+
+/* this type is used to store a dictionary of file header macros */
+typedef struct header_macro
+{
+ char* symbol;
+ char* filename; /* we could maybe use a LIST here ?? */
+
+} HEADER_MACRO;
+
+static struct hash* header_macros_hash = 0;
+
+/*
+ * headers() - scan a target for include files and call HDRRULE
+ */
+
+# define MAXINC 10
+
+void
+macro_headers( TARGET *t )
+{
+ LIST *hdrrule;
+ static regexp *re = 0;
+ FILE *f;
+ char buf[ 1024 ];
+ int i;
+
+ if ( DEBUG_HEADER )
+ printf( "macro header scan for %s\n", t->name );
+
+ /* this regexp is used to detect lines of the form */
+ /* "#define MACRO <....>" or "#define MACRO "....." */
+ /* in the header macro files.. */
+ if ( re == 0 )
+ {
+ re = regex_compile(
+ "^[ ]*#[ ]*define[ ]*([A-Za-z][A-Za-z0-9_]*)[ ]*"
+ "[<\"]([^\">]*)[\">].*$" );
+ }
+
+ if( !( f = fopen( t->boundname, "r" ) ) )
+ return;
+
+ while( fgets( buf, sizeof( buf ), f ) )
+ {
+ HEADER_MACRO var, *v = &var;
+
+ if ( regexec( re, buf ) && re->startp[1] )
+ {
+ /* we detected a line that looks like "#define MACRO filename */
+ re->endp[1][0] = '\0';
+ re->endp[2][0] = '\0';
+
+ if ( DEBUG_HEADER )
+ printf( "macro '%s' used to define filename '%s' in '%s'\n",
+ re->startp[1], re->startp[2], t->boundname );
+
+ /* add macro definition to hash table */
+ if ( !header_macros_hash )
+ header_macros_hash = hashinit( sizeof( HEADER_MACRO ), "hdrmacros" );
+
+ v->symbol = re->startp[1];
+ v->filename = 0;
+ if ( hashenter( header_macros_hash, (HASHDATA **)&v ) )
+ {
+ v->symbol = newstr( re->startp[1] ); /* never freed */
+ v->filename = newstr( re->startp[2] ); /* never freed */
+ }
+ /* XXXX: FOR NOW, WE IGNORE MULTIPLE MACRO DEFINITIONS !! */
+ /* WE MIGHT AS WELL USE A LIST TO STORE THEM.. */
+ }
+ }
+
+ fclose( f );
+}
+
+
+char*
+macro_header_get( const char* macro_name )
+{
+ HEADER_MACRO var, *v = &var;
+
+ v->symbol = (char*)macro_name;
+
+ if( header_macros_hash && hashcheck( header_macros_hash, (HASHDATA **)&v ) )
+ {
+ if ( DEBUG_HEADER )
+ printf( "### macro '%s' evaluated to '%s'\n", macro_name, v->filename );
+ return v->filename;
+ }
+ return 0;
+}
+
diff --git a/historic/jam/src/hdrmacro.h b/historic/jam/src/hdrmacro.h
new file mode 100644
index 000000000..08cc11160
--- /dev/null
+++ b/historic/jam/src/hdrmacro.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * hdrmacro.h - parses header files for #define MACRO or
+ * #define MACRO "filename" definitions
+ */
+
+void macro_headers( TARGET *t );
+
+char* macro_header_get( const char* macro_name );
diff --git a/historic/jam/src/headers.c b/historic/jam/src/headers.c
new file mode 100644
index 000000000..78a9beda1
--- /dev/null
+++ b/historic/jam/src/headers.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "compile.h"
+# include "rules.h"
+# include "variable.h"
+# include "regexp.h"
+# include "headers.h"
+# include "hdrmacro.h"
+# include "newstr.h"
+
+/*
+ * headers.c - handle #includes in source files
+ *
+ * Using regular expressions provided as the variable $(HDRSCAN),
+ * headers() searches a file for #include files and phonies up a
+ * rule invocation:
+ *
+ * $(HDRRULE) : ;
+ *
+ * External routines:
+ * headers() - scan a target for include files and call HDRRULE
+ *
+ * Internal routines:
+ * headers1() - using regexp, scan a file and build include LIST
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule,
+ * so that headers() doesn't have to mock up a parse structure
+ * just to invoke a rule.
+ */
+
+static LIST *headers1( LIST *l, char *file, int rec, regexp *re[],
+ regexp* re_macros );
+
+/*
+ * headers() - scan a target for include files and call HDRRULE
+ */
+
+# define MAXINC 10
+
+void
+headers( TARGET *t )
+{
+ LIST *hdrscan;
+ LIST *hdrrule;
+ LIST *headlist = 0;
+ regexp *re[ MAXINC ];
+ int rec = 0;
+
+ /* the following regexp is used to detect cases where a */
+ /* file is included through a line line "#include MACRO" */
+ static regexp *re_macros = 0;
+ if ( re_macros == 0 )
+ {
+ re_macros = regex_compile(
+ "^[ ]*#[ ]*include[ ]*([A-Za-z][A-Za-z0-9_]*).*$" );
+ }
+
+ if( !( hdrscan = var_get( "HDRSCAN" ) ) ||
+ !( hdrrule = var_get( "HDRRULE" ) ) )
+ return;
+
+ if( DEBUG_HEADER )
+ printf( "header scan %s\n", t->name );
+
+ /* Compile all regular expressions in HDRSCAN */
+
+ while( rec < MAXINC && hdrscan )
+ {
+ re[rec++] = regex_compile( hdrscan->string );
+ hdrscan = list_next( hdrscan );
+ }
+
+ /* Doctor up call to HDRRULE rule */
+ /* Call headers1() to get LIST of included files. */
+ {
+ FRAME frame[1];
+ frame_init( frame );
+ lol_add( frame->args, list_new( L0, t->name ) );
+ lol_add( frame->args, headers1( headlist, t->boundname, rec, re, re_macros ) );
+
+ if( lol_get( frame->args, 1 ) )
+ evaluate_rule( hdrrule->string, frame );
+
+ /* Clean up */
+
+ frame_free( frame );
+ }
+}
+
+/*
+ * headers1() - using regexp, scan a file and build include LIST
+ */
+
+static LIST *
+headers1(
+ LIST *l,
+ char *file,
+ int rec,
+ regexp *re[],
+ regexp *re_macros )
+{
+ FILE *f;
+ char buf[ 1024 ];
+ int i;
+
+ if( !( f = fopen( file, "r" ) ) )
+ return l;
+
+ while( fgets( buf, sizeof( buf ), f ) )
+ {
+ for( i = 0; i < rec; i++ )
+ if( regexec( re[i], buf ) && re[i]->startp[1] )
+ {
+ re[i]->endp[1][0] = '\0';
+
+ if( DEBUG_HEADER )
+ printf( "header found: %s\n", re[i]->startp[1] );
+
+ l = list_new( l, newstr( re[i]->startp[1] ) );
+ }
+
+ /* special treatment for #include MACRO */
+ if ( regexec( re_macros, buf ) && re_macros->startp[1] )
+ {
+ char* header_filename;
+
+ re_macros->endp[1][0] = '\0';
+
+ if ( DEBUG_HEADER )
+ printf( "macro header found: %s", re_macros->startp[1] );
+
+ header_filename = macro_header_get( re_macros->startp[1] );
+ if (header_filename)
+ {
+ if ( DEBUG_HEADER )
+ printf( " resolved to '%s'\n", header_filename );
+ l = list_new( l, newstr( header_filename ) );
+ }
+ else
+ {
+ if ( DEBUG_HEADER )
+ printf( " ignored !!\n" );
+ }
+ }
+ }
+
+ fclose( f );
+
+ return l;
+}
+
+void
+regerror( char *s )
+{
+ printf( "re error %s\n", s );
+}
diff --git a/historic/jam/src/headers.h b/historic/jam/src/headers.h
new file mode 100644
index 000000000..8c33735c6
--- /dev/null
+++ b/historic/jam/src/headers.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * headers.h - handle #includes in source files
+ */
+
+void headers( TARGET *t );
diff --git a/historic/jam/src/jam.c b/historic/jam/src/jam.c
new file mode 100644
index 000000000..92965f3a1
--- /dev/null
+++ b/historic/jam/src/jam.c
@@ -0,0 +1,385 @@
+/*
+ * /+\
+ * +\ Copyright 1993, 2000 Christopher Seiwald.
+ * \+/
+ *
+ * This file is part of jam.
+ *
+ * License is hereby granted to use this software and distribute it
+ * freely, as long as this copyright notice is retained and modifications
+ * are clearly marked.
+ *
+ * ALL WARRANTIES ARE HEREBY DISCLAIMED.
+ */
+
+/*
+ * jam.c - make redux
+ *
+ * See Jam.html and Jamlang.html for usage information.
+ *
+ * These comments document the code.
+ *
+ * The top half of the code is structured such:
+ *
+ * jam
+ * / | \
+ * +---+ | \
+ * / | \
+ * jamgram option \
+ * / | \ \
+ * / | \ \
+ * / | \ |
+ * scan | compile make
+ * | | / \ / | \
+ * | | / \ / | \
+ * | | / \ / | \
+ * jambase parse rules search make1
+ * | | \
+ * | | \
+ * | | \
+ * timestamp command execute
+ *
+ *
+ * The support routines are called by all of the above, but themselves
+ * are layered thus:
+ *
+ * variable|expand
+ * / | | |
+ * / | | |
+ * / | | |
+ * lists | | filesys
+ * \ | |
+ * \ | |
+ * \ | |
+ * newstr |
+ * \ |
+ * \ |
+ * \ |
+ * hash
+ *
+ * Roughly, the modules are:
+ *
+ * command.c - maintain lists of commands
+ * compile.c - compile parsed jam statements
+ * execunix.c - execute a shell script on UNIX
+ * execvms.c - execute a shell script, ala VMS
+ * expand.c - expand a buffer, given variable values
+ * fileunix.c - manipulate file names and scan directories on UNIX
+ * filevms.c - manipulate file names and scan directories on VMS
+ * fileos2.c - manipulate file names and scan directories on OS/2
+ * filent.c - manipulate file names and scan directories on Windows
+ * hash.c - simple in-memory hashing routines
+ * hdrmacro.c - handle header file parsing for filename macro definitions
+ * headers.c - handle #includes in source files
+ * jambase.c - compilable copy of Jambase
+ * jamgram.y - jam grammar
+ * lists.c - maintain lists of strings
+ * make.c - bring a target up to date, once rules are in place
+ * make1.c - execute command to bring targets up to date
+ * newstr.c - string manipulation routines
+ * option.c - command line option processing
+ * parse.c - make and destroy parse trees as driven by the parser
+ * regexp.c - Henry Spencer's regexp
+ * rules.c - access to RULEs, TARGETs, and ACTIONs
+ * scan.c - the jam yacc scanner
+ * search.c - find a target along $(SEARCH) or $(LOCATE)
+ * timestamp.c - get the timestamp of a file or archive member
+ * variable.c - handle jam multi-element variables
+ *
+ * 05/04/94 (seiwald) - async multiprocess (-j) support
+ * 02/08/95 (seiwald) - -n implies -d2.
+ * 02/22/95 (seiwald) - -v for version info.
+ * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
+ */
+
+# include "jam.h"
+# include "option.h"
+# include "patchlevel.h"
+
+/* These get various function declarations. */
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "compile.h"
+# include "rules.h"
+# include "newstr.h"
+# include "scan.h"
+# include "timestamp.h"
+# include "make.h"
+
+/* Macintosh is "special" */
+
+# ifdef OS_MAC
+# include
+# endif
+
+/* And UNIX for this */
+
+# ifdef unix
+# include
+# endif
+
+struct globs globs = {
+ 0, /* noexec */
+ 1, /* jobs */
+# ifdef OS_MAC
+ { 0, 0 }, /* debug - suppress tracing output */
+# else
+ { 0, 1 }, /* debug ... */
+# endif
+ 0 /* output commands, not run them */
+} ;
+
+/* Symbols to be defined as true for use in Jambase */
+
+static char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ;
+
+/* Known for sure:
+ * mac needs arg_enviro
+ * OS2 needs extern environ
+ */
+
+# ifdef OS_MAC
+# define use_environ arg_environ
+# ifdef MPW
+QDGlobals qd;
+# endif
+# endif
+
+/* on Win32-LCC */
+# if defined( OS_NT ) && defined( __LCC__ )
+# define use_environ _environ
+# endif
+
+
+# ifndef use_environ
+# define use_environ environ
+# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
+extern char **environ;
+# endif
+# endif
+
+extern int yydebug;
+
+#ifndef NDEBUG
+static void run_unit_tests()
+{
+ var_expand_unit_test();
+}
+#endif
+
+int main( int argc, char **argv, char **arg_environ )
+{
+ int n;
+ char *s;
+ struct option optv[N_OPTS];
+ char *all = "all";
+ int anyhow = 0;
+ int status;
+
+# ifdef OS_MAC
+ InitGraf(&qd.thePort);
+# endif
+
+ argc--, argv++;
+
+ if( ( n = getoptions( argc, argv, "d:j:f:s:t:ano:v", optv ) ) < 0 )
+ {
+ printf( "\nusage: jam [ options ] targets...\n\n" );
+
+ printf( "-a Build all targets, even if they are current.\n" );
+ printf( "-dx Set the debug level to x (0-9).\n" );
+ printf( "-fx Read x instead of Jambase.\n" );
+ printf( "-jx Run up to x shell commands concurrently.\n" );
+ printf( "-n Don't actually execute the updating actions.\n" );
+ printf( "-ox Write the updating actions to file x.\n" );
+ printf( "-sx=y Set variable x=y, overriding environment.\n" );
+ printf( "-tx Rebuild x, even if it is up-to-date.\n" );
+ printf( "-v Print the version of jam and exit.\n\n" );
+
+ exit( EXITBAD );
+ }
+
+ argc -= n, argv += n;
+
+ /* Version info. */
+
+ if( ( s = getoptval( optv, 'v', 0 ) ) )
+ {
+ printf( "Jam/MR " );
+ printf( "Version %s. ", VERSION );
+ printf( "Copyright 1993, 2000 Christopher Seiwald. " );
+ printf( "%s.\n", OSMINOR );
+
+ return EXITOK;
+ }
+
+ /* Pick up interesting options */
+
+ if( ( s = getoptval( optv, 'n', 0 ) ) )
+ globs.noexec++, globs.debug[2] = 1;
+
+ if( ( s = getoptval( optv, 'a', 0 ) ) )
+ anyhow++;
+
+ if( ( s = getoptval( optv, 'j', 0 ) ) )
+ globs.jobs = atoi( s );
+
+ /* Turn on/off debugging */
+
+ for( n = 0; s = getoptval( optv, 'd', n ); n++ )
+ {
+ int i;
+
+ /* First -d, turn off defaults. */
+
+ if( !n )
+ for( i = 0; i < DEBUG_MAX; i++ )
+ globs.debug[i] = 0;
+
+ i = atoi( s );
+
+ if( i < 0 || i >= DEBUG_MAX )
+ {
+ printf( "Invalid debug level '%s'.\n", s );
+ continue;
+ }
+
+ /* n turns on levels 1-n */
+ /* +n turns on level n */
+
+ if( *s == '+' )
+ globs.debug[i] = 1;
+ else while( i )
+ globs.debug[i--] = 1;
+ }
+
+#ifndef NDEBUG
+ run_unit_tests();
+#endif // NDEBUG
+ if ( DEBUG_PARSE )
+ yydebug = 1;
+
+ /* Set JAMDATE first */
+
+ {
+ char *date;
+ time_t clock;
+ time( &clock );
+ date = newstr( ctime( &clock ) );
+
+ /* Trim newline from date */
+
+ if( strlen( date ) == 25 )
+ date[ 24 ] = 0;
+
+ var_set( "JAMDATE", list_new( L0, newstr( date ) ), VAR_SET );
+ }
+
+ var_set( "JAM_VERSION",
+ list_new( list_new( L0, newstr( "03" ) ), newstr( "00" ) ),
+ VAR_SET );
+
+ /* And JAMUNAME */
+# ifdef unix
+ {
+ struct utsname u;
+
+ if( uname( &u ) >= 0 )
+ {
+ var_set( "JAMUNAME",
+ list_new(
+ list_new(
+ list_new(
+ list_new(
+ list_new( L0,
+ newstr( u.sysname ) ),
+ newstr( u.nodename ) ),
+ newstr( u.release ) ),
+ newstr( u.version ) ),
+ newstr( u.machine ) ), VAR_SET );
+ }
+ }
+# endif /* unix */
+
+ /*
+ * Jam defined variables OS, OSPLAT
+ */
+
+ var_defines( othersyms );
+
+ /* load up environment variables */
+
+ var_defines( use_environ );
+
+ /* Load up variables set on command line. */
+
+ for( n = 0; s = getoptval( optv, 's', n ); n++ )
+ {
+ char *symv[2];
+ symv[0] = s;
+ symv[1] = 0;
+ var_defines( symv );
+ }
+
+ /* Initialize builtins */
+
+
+ compile_builtins();
+
+ /* Parse ruleset */
+
+ {
+ FRAME frame[1];
+ frame_init( frame );
+ for( n = 0; s = getoptval( optv, 'f', n ); n++ )
+ parse_file( s, frame );
+
+ if( !n )
+ parse_file( "+", frame );
+ }
+
+ status = yyanyerrors();
+
+ /* Manually touch -t targets */
+
+ for( n = 0; s = getoptval( optv, 't', n ); n++ )
+ touchtarget( s );
+
+ /* If an output file is specified, set globs.cmdout to that */
+
+ if( s = getoptval( optv, 'o', 0 ) )
+ {
+ if( !( globs.cmdout = fopen( s, "w" ) ) )
+ {
+ printf( "Failed to write to '%s'\n", s );
+ exit( EXITBAD );
+ }
+ globs.noexec++;
+ }
+
+ /* Now make target */
+
+ if( !argc )
+ status |= make( 1, &all, anyhow );
+ else
+ status |= make( argc, argv, anyhow );
+
+ if ( DEBUG_PROFILE )
+ profile_dump();
+
+ /* Widely scattered cleanup */
+
+ var_done();
+ donerules();
+ donestamps();
+ donestr();
+
+ /* close cmdout */
+
+ if( globs.cmdout )
+ fclose( globs.cmdout );
+
+ return status ? EXITBAD : EXITOK;
+}
diff --git a/historic/jam/src/jam.h b/historic/jam/src/jam.h
new file mode 100644
index 000000000..90267fc86
--- /dev/null
+++ b/historic/jam/src/jam.h
@@ -0,0 +1,483 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jam.h - includes and globals for jam
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 04/21/94 (seiwald) - DGUX is __DGUX__, not just __DGUX.
+ * 05/04/94 (seiwald) - new globs.jobs (-j jobs)
+ * 11/01/94 (wingerd) - let us define path of Jambase at compile time.
+ * 12/30/94 (wingerd) - changed command buffer size for NT (MS-DOS shell).
+ * 02/22/95 (seiwald) - Jambase now in /usr/local/lib.
+ * 04/30/95 (seiwald) - FreeBSD added. Live Free or Die.
+ * 05/10/95 (seiwald) - SPLITPATH character set up here.
+ * 08/20/95 (seiwald) - added LINUX.
+ * 08/21/95 (seiwald) - added NCR.
+ * 10/23/95 (seiwald) - added SCO.
+ * 01/03/96 (seiwald) - SINIX (nixdorf) added.
+ * 03/13/96 (seiwald) - Jambase now compiled in; remove JAMBASE variable.
+ * 04/29/96 (seiwald) - AIX now has 31 and 42 OSVERs.
+ * 11/21/96 (peterk) - added BeOS with MW CW mwcc
+ * 12/21/96 (seiwald) - OSPLAT now defined for NT.
+ * 07/19/99 (sickel) - Mac OS X Server and Client support added
+ * 02/18/00 (belmonte)- Support for Cygwin.
+ * 09/12/00 (seiwald) - OSSYMS split to OSMAJOR/OSMINOR/OSPLAT
+ * 12/29/00 (seiwald) - OSVER dropped.
+ */
+
+/*
+ * VMS, OPENVMS
+ */
+
+# ifdef VMS
+
+int unlink( char *f ); /* In filevms.c */
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# define OSMINOR "OS=VMS"
+# define OSMAJOR "VMS=true"
+# define OS_VMS
+# define MAXLINE 1024 /* longest 'together' actions */
+# define SPLITPATH ','
+# define EXITOK 1
+# define EXITBAD 0
+# define DOWNSHIFT_PATHS
+
+/* This may be inaccurate */
+# ifndef __DECC
+# define OSPLAT "OSPLAT=VAX"
+# endif
+
+# endif
+
+/*
+ * Windows NT
+ */
+
+# ifdef NT
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# define OSMAJOR "NT=true"
+# define OSMINOR "OS=NT"
+# define OS_NT
+# define SPLITPATH ';'
+/* Windows NT 3.51 only allows 996 chars per line, but we deal */
+/* with problem in "execnt.c". */
+# define MAXLINE 2047 /* longest 'together' actions */
+# define USE_EXECNT
+# define USE_PATHUNIX
+# define PATH_DELIM '\\'
+# define DOWNSHIFT_PATHS
+
+/* AS400 cross-compile from NT */
+
+# ifdef AS400
+# undef OSMINOR
+# undef OSMAJOR
+# define OSMAJOR "AS400=true"
+# define OSMINOR "OS=AS400"
+# define OS_AS400
+# endif
+
+# endif
+
+/*
+ * OS2
+ */
+
+# ifdef __OS2__
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# define OSMAJOR "OS2=true"
+# define OSMINOR "OS=OS2"
+# define OS_OS2
+# define SPLITPATH ';'
+# define MAXLINE 996 /* longest 'together' actions */
+# define USE_EXECUNIX
+# define USE_PATHUNIX
+# define PATH_DELIM '\\'
+# define DOWNSHIFT_PATHS
+
+# ifdef __EMX__
+# define USE_FILEUNIX
+# endif
+
+# endif
+
+/*
+ * Macintosh MPW
+ */
+
+# ifdef macintosh
+
+# include
+# include
+# include
+# include
+
+# define OSMAJOR "MAC=true"
+# define OSMINOR "OS=MAC"
+# define OS_MAC
+# define SPLITPATH ','
+
+# endif
+
+/*
+ * God fearing UNIX
+ */
+
+# ifndef OSMINOR
+
+# define OSMAJOR "UNIX=true"
+# define USE_EXECUNIX
+# define USE_FILEUNIX
+# define USE_PATHUNIX
+# define PATH_DELIM '/'
+
+# ifdef _AIX
+# define unix
+# define OSMINOR "OS=AIX"
+# define OS_AIX
+# define NO_VFORK
+# endif
+# ifdef AMIGA
+# define OSMINOR "OS=AMIGA"
+# define OS_AMIGA
+# endif
+# ifdef __BEOS__
+# define unix
+# define OSMINOR "OS=BEOS"
+# define OS_BEOS
+# define NO_VFORK
+# endif
+# ifdef __bsdi__
+# define OSMINOR "OS=BSDI"
+# define OS_BSDI
+# endif
+# if defined (COHERENT) && defined (_I386)
+# define OSMINOR "OS=COHERENT"
+# define OS_COHERENT
+# define NO_VFORK
+# endif
+# ifdef __cygwin__
+# define OSMINOR "OS=CYGWIN"
+# define OS_CYGWIN
+# endif
+# ifdef __FreeBSD__
+# define OSMINOR "OS=FREEBSD"
+# define OS_FREEBSD
+# endif
+# ifdef __DGUX__
+# define OSMINOR "OS=DGUX"
+# define OS_DGUX
+# endif
+# ifdef __hpux
+# define OSMINOR "OS=HPUX"
+# define OS_HPUX
+# endif
+# ifdef __OPENNT
+# define unix
+# define OSMINOR "OS=INTERIX"
+# define OS_INTERIX
+# define NO_VFORK
+# endif
+# ifdef __sgi
+# define OSMINOR "OS=IRIX"
+# define OS_IRIX
+# define NO_VFORK
+# endif
+# ifdef __ISC
+# define OSMINOR "OS=ISC"
+# define OS_ISC
+# define NO_VFORK
+# endif
+# ifdef linux
+# define OSMINOR "OS=LINUX"
+# define OS_LINUX
+# endif
+# ifdef __Lynx__
+# define OSMINOR "OS=LYNX"
+# define OS_LYNX
+# define NO_VFORK
+# define unix
+# endif
+# ifdef __MACHTEN__
+# define OSMINOR "OS=MACHTEN"
+# define OS_MACHTEN
+# endif
+# ifdef mpeix
+# define unix
+# define OSMINOR "OS=MPEIX"
+# define OS_MPEIX
+# define NO_VFORK
+# endif
+# ifdef __MVS__
+# define unix
+# define OSMINOR "OS=MVS"
+# define OS_MVS
+# endif
+# ifdef _ATT4
+# define OSMINOR "OS=NCR"
+# define OS_NCR
+# endif
+# ifdef __NetBSD__
+# define unix
+# define OSMINOR "OS=NETBSD"
+# define OS_NETBSD
+# define NO_VFORK
+# endif
+# ifdef __QNX__
+# ifdef __QNXNTO__
+# define OSMINOR "OS=QNXNTO"
+# define OS_QNXNTO
+# else
+# define unix
+# define OSMINOR "OS=QNX"
+# define OS_QNX
+# define NO_VFORK
+# define MAXLINE 996
+# endif
+# endif
+# ifdef NeXT
+# ifdef __APPLE__
+# define OSMINOR "OS=RHAPSODY"
+# define OS_RHAPSODY
+# else
+# define OSMINOR "OS=NEXT"
+# define OS_NEXT
+# endif
+# endif
+# ifdef __APPLE__
+# define unix
+# define OSMINOR "OS=MACOSX"
+# define OS_MACOSX
+# endif
+# ifdef __osf__
+# define OSMINOR "OS=OSF"
+# define OS_OSF
+# endif
+# ifdef _SEQUENT_
+# define OSMINOR "OS=PTX"
+# define OS_PTX
+# endif
+# ifdef M_XENIX
+# define OSMINOR "OS=SCO"
+# define OS_SCO
+# define NO_VFORK
+# endif
+# ifdef sinix
+# define unix
+# define OSMINOR "OS=SINIX"
+# define OS_SINIX
+# endif
+# ifdef sun
+# if defined(__svr4__) || defined(__SVR4)
+# define OSMINOR "OS=SOLARIS"
+# define OS_SOLARIS
+# else
+# define OSMINOR "OS=SUNOS"
+# define OS_SUNOS
+# endif
+# endif
+# ifdef ultrix
+# define OSMINOR "OS=ULTRIX"
+# define OS_ULTRIX
+# endif
+# ifdef _UNICOS
+# define OSMINOR "OS=UNICOS"
+# define OS_UNICOS
+# endif
+# if defined(__USLC__) && !defined(M_XENIX)
+# define OSMINOR "OS=UNIXWARE"
+# define OS_UNIXWARE
+# endif
+# ifndef OSMINOR
+# define OSMINOR "OS=UNKNOWN"
+# endif
+
+/* All the UNIX includes */
+
+# include
+# include
+
+# ifndef OS_MPEIX
+# include
+# endif
+
+# include
+# include
+# include
+# include
+# include
+# include
+
+# ifndef OS_QNX
+# include
+# endif
+
+# ifndef OS_ULTRIX
+# include
+# endif
+
+# if !defined(OS_BSDI) && \
+ !defined(OS_FREEBSD) && \
+ !defined(OS_NEXT) && \
+ !defined(OS_MACHTEN) && \
+ !defined(OS_MACOSX) && \
+ !defined(OS_RHAPSODY) && \
+ !defined(OS_MVS)
+# include
+# endif
+
+# endif
+
+/*
+ * OSPLAT definitions - suppressed when it's a one-of-a-kind
+ */
+
+# if defined( _M_PPC ) || \
+ defined( PPC ) || \
+ defined( ppc ) || \
+ defined( __powerpc__ ) || \
+ defined( __ppc__ )
+# define OSPLAT "OSPLAT=PPC"
+# endif
+
+# if defined( _ALPHA_ ) || \
+ defined( __alpha__ )
+# define OSPLAT "OSPLAT=AXP"
+# endif
+
+# if defined( _i386_ ) || \
+ defined( __i386__ ) || \
+ defined( _M_IX86 )
+# if !defined( OS_FREEBSD ) && \
+ !defined( OS_OS2 ) && \
+ !defined( OS_AS400 )
+# define OSPLAT "OSPLAT=X86"
+# endif
+# endif
+
+# ifdef __sparc__
+# if !defined( OS_SUNOS ) && \
+ !defined( OS_SOLARIS )
+# define OSPLAT "OSPLAT=SPARC"
+# endif
+# endif
+
+# ifdef __mips__
+# if !defined( OS_SGI )
+# define OSPLAT "OSPLAT=MIPS"
+# endif
+# endif
+
+# ifdef __arm__
+# define OSPLAT "OSPLAT=ARM"
+# endif
+
+# if defined( __ia64__ ) || defined( __IA64__ )
+# define OSPLAT "OSPLAT=IA64"
+# endif
+
+# ifdef __s390__
+# define OSPLAT "OSPLAT=390"
+# endif
+
+# ifndef OSPLAT
+# define OSPLAT ""
+# endif
+
+/*
+ * Jam implementation misc.
+ */
+
+# ifndef MAXLINE
+# define MAXLINE 10240 /* longest 'together' actions' */
+# endif
+
+# ifndef EXITOK
+# define EXITOK 0
+# define EXITBAD 1
+# endif
+
+# ifndef SPLITPATH
+# define SPLITPATH ':'
+# endif
+
+/* You probably don't need to muck with these. */
+
+# define MAXSYM 1024 /* longest symbol in the environment */
+# define MAXJPATH 1024 /* longest filename */
+
+# define MAXJOBS 64 /* silently enforce -j limit */
+# define MAXARGC 32 /* words in $(JAMSHELL) */
+
+/* Jam private definitions below. */
+
+# define DEBUG_MAX 12
+
+struct globs {
+ int noexec;
+ int jobs;
+ char debug[DEBUG_MAX];
+ FILE *cmdout; /* print cmds, not run them */
+} ;
+
+extern struct globs globs;
+
+# define DEBUG_MAKE ( globs.debug[ 1 ] ) /* show actions when executed */
+# define DEBUG_MAKEQ ( globs.debug[ 2 ] ) /* show even quiet actions */
+# define DEBUG_EXEC ( globs.debug[ 2 ] ) /* show text of actons */
+# define DEBUG_MAKEPROG ( globs.debug[ 3 ] ) /* show progress of make0 */
+# define DEBUG_BIND ( globs.debug[ 3 ] ) /* show when files bound */
+
+# define DEBUG_EXECCMD ( globs.debug[ 4 ] ) /* show execcmds()'s work */
+
+# define DEBUG_COMPILE ( globs.debug[ 5 ] ) /* show rule invocations */
+
+# define DEBUG_HEADER ( globs.debug[ 6 ] ) /* show result of header scan */
+# define DEBUG_BINDSCAN ( globs.debug[ 6 ] ) /* show result of dir scan */
+# define DEBUG_SEARCH ( globs.debug[ 6 ] ) /* show attempts at binding */
+
+# define DEBUG_VARSET ( globs.debug[ 7 ] ) /* show variable settings */
+# define DEBUG_VARGET ( globs.debug[ 8 ] ) /* show variable fetches */
+# define DEBUG_VAREXP ( globs.debug[ 8 ] ) /* show variable expansions */
+# define DEBUG_IF ( globs.debug[ 8 ] ) /* show 'if' calculations */
+# define DEBUG_LISTS ( globs.debug[ 9 ] ) /* show list manipulation */
+# define DEBUG_SCAN ( globs.debug[ 9 ] ) /* show scanner tokens */
+# define DEBUG_MEM ( globs.debug[ 9 ] ) /* show memory use */
+
+# define DEBUG_PROFILE ( globs.debug[ 10 ] ) /* dump rule execution times */
+# define DEBUG_PARSE ( globs.debug[ 11 ] ) /* debug parsing */
+
diff --git a/historic/jam/src/jambase.c b/historic/jam/src/jambase.c
new file mode 100644
index 000000000..a478931ef
--- /dev/null
+++ b/historic/jam/src/jambase.c
@@ -0,0 +1,1554 @@
+/* Generated by mkjambase from Jambase */
+char *jambase[] = {
+/* Jambase */
+"if $(BOOST_ROOT)\n",
+"{\n",
+"BOOST_BUILD_PATH ?= $(BOOST_ROOT)/tools/build ;\n",
+"}\n",
+"if $(BOOST_BUILD_PATH)\n",
+"{\n",
+"JAMBASE ?= boost-build.jam ;\n",
+"}\n",
+"if $(JAMBASE)\n",
+"{\n",
+"JAMBASE = $(JAMBASE:G=jam-module) ; # puts the Jambase target in a different\n",
+"SEARCH on $(JAMBASE) = $(JAMBASE_PATH) $(BOOST_BUILD_PATH) ;\n",
+"include $(JAMBASE) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"if $(NT)\n",
+"{\n",
+"local SUPPORTED_TOOLSETS = \"BORLANDC\" \"VISUALC\" \"VISUALC16\" \"INTELC\" \"WATCOM\"\n",
+"\"MINGW\" \"LCC\" ;\n",
+"TOOLSET = \"\" ;\n",
+"if $(JAM_TOOLSET)\n",
+"{\n",
+"local t ;\n",
+"for t in $(SUPPORTED_TOOLSETS)\n",
+"{\n",
+"if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"ECHO \"The JAM_TOOLSET environment variable is defined but its value\" ;\n",
+"ECHO \"is invalid, please use one of the following:\" ;\n",
+"ECHO ;\n",
+"for t in $(SUPPORTED_TOOLSETS) { ECHO \" \" $(t) ; }\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"if $(BCCROOT)\n",
+"{\n",
+"TOOLSET = BORLANDC ;\n",
+"BORLANDC = $(BCCROOT) ;\n",
+"}\n",
+"else if $(MSVC)\n",
+"{\n",
+"TOOLSET = VISUALC16 ;\n",
+"VISUALC16 = $(MSVC) ;\n",
+"}\n",
+"else if $(MSVCNT)\n",
+"{\n",
+"TOOLSET = VISUALC ;\n",
+"VISUALC = $(MSVCNT) ;\n",
+"}\n",
+"else if $(MINGW)\n",
+"{\n",
+"TOOLSET = MINGW ;\n",
+"}\n",
+"else\n",
+"{\n",
+"ECHO \"Jam cannot be run because you didn't indicate which compilation toolset\" ;\n",
+"ECHO \"to use. To do so, follow these simple instructions:\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define one of the following environment variable, with the\" ;\n",
+"ECHO \" appropriate value according to this list:\" ;\n",
+"ECHO ;\n",
+"ECHO \" Variable Toolset Description\" ;\n",
+"ECHO ;\n",
+"ECHO \" BORLANDC Borland C++ BC++ install path\" ;\n",
+"ECHO \" VISUALC Microsoft Visual C++ VC++ install path\" ;\n",
+"ECHO \" VISUALC16 Microsoft Visual C++ 16 bit VC++ 16 bit install\" ;\n",
+"ECHO \" INTELC Intel C/C++ IC++ install path\" ;\n",
+"ECHO \" WATCOM Watcom C/C++ Watcom install path\" ;\n",
+"ECHO \" MINGW MinGW (gcc) MinGW install path\" ;\n",
+"ECHO \" LCC Win32-LCC LCC-Win32 install path\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define the JAM_TOOLSET environment variable with the *name*\" ;\n",
+"ECHO \" of the toolset variable you want to use.\" ;\n",
+"ECHO ;\n",
+"ECHO \" e.g.: set VISUALC=C:\\Visual6\" ;\n",
+"ECHO \" set JAM_TOOLSET=VISUALC\" ;\n",
+"ECHO ;\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"CP ?= copy ;\n",
+"RM ?= del /f/q ;\n",
+"SLASH ?= \\\\ ;\n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .obj ;\n",
+"SUFEXE ?= .exe ;\n",
+"if $(TOOLSET) = BORLANDC\n",
+"{\n",
+"ECHO \"Compiler is Borland C++\" ;\n",
+"AR ?= tlib /C /P64 ;\n",
+"CC ?= bcc32 ;\n",
+"CCFLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus ;\n",
+"C++ ?= bcc32 ;\n",
+"C++FLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus -P ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= $(CCFLAGS) ;\n",
+"STDLIBPATH ?= $(BORLANDC)\\\\lib ;\n",
+"STDHDRS ?= $(BORLANDC)\\\\include ;\n",
+"NOARSCAN ?= true ;\n",
+"}\n",
+"else if $(TOOLSET) = VISUALC16\n",
+"{\n",
+"ECHO \"Compiler is Microsoft Visual C++ 16 bit\" ;\n",
+"AR ?= lib /nologo ;\n",
+"CC ?= cl /nologo ;\n",
+"CCFLAGS ?= /D \\\"WIN\\\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= $(CCFLAGS) ;\n",
+"LINKLIBS ?= \n",
+"$(VISUALC16)\\\\lib\\\\mlibce.lib\n",
+"$(VISUALC16)\\\\lib\\\\oldnames.lib\n",
+";\n",
+"LINKLIBS ?= ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= \"\" ;\n",
+"STDHDRS ?= $(VISUALC16)\\\\include ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = VISUALC\n",
+"{\n",
+"ECHO \"Compiler is Microsoft Visual C++\" ;\n",
+"AR ?= lib ;\n",
+"AS ?= masm386 ;\n",
+"CC ?= cl /nologo ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= link /nologo ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= $(VISUALC)\\\\lib\\\\advapi32.lib\n",
+"$(VISUALC)\\\\lib\\\\gdi32.lib\n",
+"$(VISUALC)\\\\lib\\\\user32.lib\n",
+"$(VISUALC)\\\\lib\\\\kernel32.lib ;\n",
+"OPTIM ?= \"\" ;\n",
+"STDHDRS ?= $(VISUALC)\\\\include ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = INTELC\n",
+"{\n",
+"ECHO \"Compiler is Intel C/C++\" ;\n",
+"if ! $(VISUALC)\n",
+"{\n",
+"ECHO \"As a special exception, when using the Intel C++ compiler, you need\" ;\n",
+"ECHO \"to define the VISUALC environment variable to indicate the location\" ;\n",
+"ECHO \"of your Visual C++ installation. Aborting..\" ;\n",
+"EXIT ;\n",
+"}\n",
+"AR ?= lib ;\n",
+"AS ?= masm386 ;\n",
+"CC ?= icl /nologo ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= link /nologo ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= $(VISUALC)\\\\lib\\\\advapi32.lib\n",
+"$(VISUALC)\\\\lib\\\\kernel32.lib\n",
+";\n",
+"OPTIM ?= \"\" ;\n",
+"STDHDRS ?= $(INTELC)\\include $(VISUALC)\\\\include ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = WATCOM\n",
+"{\n",
+"ECHO \"Compiler is Watcom C/C++\" ;\n",
+"AR ?= wlib ;\n",
+"CC ?= wcc386 ;\n",
+"CCFLAGS ?= /zq /DWIN32 /I$(WATCOM)\\\\h ; # zq=quiet\n",
+"C++ ?= wpp386 ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"CP ?= copy ;\n",
+"DOT ?= . ;\n",
+"DOTDOT ?= .. ;\n",
+"LINK ?= wcl386 ;\n",
+"LINKFLAGS ?= /zq ; # zq=quiet\n",
+"LINKLIBS ?= ;\n",
+"MV ?= move ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= ;\n",
+"RM ?= del /f ;\n",
+"SLASH ?= \\\\ ;\n",
+"STDHDRS ?= $(WATCOM)\\\\h $(WATCOM)\\\\h\\\\nt ;\n",
+"SUFEXE ?= .exe ;\n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .obj ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = MINGW\n",
+"{\n",
+"ECHO \"Compiler is GCC with Mingw\" ;\n",
+"AR ?= ar -ru ;\n",
+"CC ?= gcc ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= \"\" ;\n",
+"OPTIM ?= ;\n",
+"SUFOBJ = .o ;\n",
+"SUFLIB = .a ;\n",
+"SLASH = / ;\n",
+"}\n",
+"else if $(TOOLSET) = LCC\n",
+"{\n",
+"ECHO \"Compiler is Win32-LCC\" ;\n",
+"AR ?= lcclib ;\n",
+"CC ?= lcc ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= lcclnk ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= \"\" ;\n",
+"OPTIM ?= ;\n",
+"NOARSCAN = true ;\n",
+"}\n",
+"else\n",
+"{\n",
+"EXIT On NT, set BCCROOT, MSVCNT, MINGW or MSVC to the root of the\n",
+"Borland or Microsoft directories. ;\n",
+"}\n",
+"}\n",
+"else if $(OS2)\n",
+"{\n",
+"local SUPPORTED_TOOLSETS = \"EMX\" \"WATCOM\" ;\n",
+"TOOLSET = \"\" ;\n",
+"if $(JAM_TOOLSET)\n",
+"{\n",
+"local t ;\n",
+"for t in $(SUPPORTED_TOOLSETS)\n",
+"{\n",
+"if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"ECHO \"The JAM_TOOLSET environment variable is defined but its value\" ;\n",
+"ECHO \"is invalid, please use one of the following:\" ;\n",
+"ECHO ;\n",
+"for t in $(SUPPORTED_TOOLSETS) { ECHO \" \" $(t) ; }\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"if $(watcom)\n",
+"{\n",
+"WATCOM = $(watcom) ;\n",
+"TOOLSET = WATCOM ;\n",
+"}\n",
+"else\n",
+"{\n",
+"ECHO \"Jam cannot be run because you didn't indicate which compilation toolset\" ;\n",
+"ECHO \"to use. To do so, follow these simple instructions:\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define one of the following environment variable, with the\" ;\n",
+"ECHO \" appropriate value according to this list:\" ;\n",
+"ECHO ;\n",
+"ECHO \" Variable Toolset Description\" ;\n",
+"ECHO ;\n",
+"ECHO \" WATCOM Watcom C/C++ Watcom install path\" ;\n",
+"ECHO \" EMX EMX (gcc) EMX install path\" ;\n",
+"ECHO \" VISUALAGE IBM Visual Age C/C++ VisualAge install path\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define the JAM_TOOLSET environment variable with the *name*\" ;\n",
+"ECHO \" of the toolset variable you want to use.\" ;\n",
+"ECHO ;\n",
+"ECHO \" e.g.: set WATCOM=C:\\WATCOM\" ;\n",
+"ECHO \" set JAM_TOOLSET=WATCOM\" ;\n",
+"ECHO ;\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"RM = del /f ;\n",
+"CP = copy ;\n",
+"MV ?= move ;\n",
+"DOT ?= . ;\n",
+"DOTDOT ?= .. ;\n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .obj ;\n",
+"SUFEXE ?= .exe ;\n",
+"if $(TOOLSET) = WATCOM\n",
+"{\n",
+"AR ?= wlib ;\n",
+"BINDIR ?= \\\\os2\\\\apps ;\n",
+"CC ?= wcc386 ;\n",
+"CCFLAGS ?= /zq /DOS2 /I$(WATCOM)\\\\h ; # zq=quiet\n",
+"C++ ?= wpp386 ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= wcl386 ;\n",
+"LINKFLAGS ?= /zq ; # zq=quiet\n",
+"LINKLIBS ?= ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= ;\n",
+"SLASH ?= \\\\ ;\n",
+"STDHDRS ?= $(WATCOM)\\\\h ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = EMX\n",
+"{\n",
+"ECHO \"Compiler is GCC-EMX\" ;\n",
+"AR ?= ar -ru ;\n",
+"CC ?= gcc ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= \"\" ;\n",
+"OPTIM ?= ;\n",
+"SUFOBJ = .o ;\n",
+"SUFLIB = .a ;\n",
+"UNDEFFLAG ?= \"-U\" ;\n",
+"SLASH = / ;\n",
+"}\n",
+"else\n",
+"{\n",
+"EXIT \"Sorry, but the $(JAM_TOOLSET) toolset isn't supported for now\" ;\n",
+"}\n",
+"}\n",
+"else if $(VMS)\n",
+"{\n",
+"C++ ?= cxx ;\n",
+"C++FLAGS ?= ;\n",
+"CC ?= cc ;\n",
+"CCFLAGS ?= ;\n",
+"CHMOD ?= set file/prot= ;\n",
+"CP ?= copy/replace ;\n",
+"CRELIB ?= true ;\n",
+"DOT ?= [] ;\n",
+"DOTDOT ?= [-] ;\n",
+"EXEMODE ?= (w:e) ;\n",
+"FILEMODE ?= (w:r) ;\n",
+"HDRS ?= ;\n",
+"LINK ?= link ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= ;\n",
+"MKDIR ?= create/dir ;\n",
+"MV ?= rename ;\n",
+"OPTIM ?= \"\" ;\n",
+"RM ?= delete ;\n",
+"RUNVMS ?= mcr ;\n",
+"SHELLMODE ?= (w:er) ;\n",
+"SLASH ?= . ;\n",
+"STDHDRS ?= decc$library_include ;\n",
+"SUFEXE ?= .exe ;\n",
+"SUFLIB ?= .olb ;\n",
+"SUFOBJ ?= .obj ;\n",
+"switch $(OS) \n",
+"{\n",
+"case OPENVMS : CCFLAGS ?= /stand=vaxc ;\n",
+"case VMS : LINKLIBS ?= sys$library:vaxcrtl.olb/lib ;\n",
+"}\n",
+"}\n",
+"else if $(MAC)\n",
+"{\n",
+"local OPT ;\n",
+"CW ?= \"{CW}\" ;\n",
+"MACHDRS ?=\n",
+"\"$(UMACHDRS):Universal:Interfaces:CIncludes\"\n",
+"\"$(CW):MSL:MSL_C:MSL_Common:Include\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Include\" ;\n",
+"MACLIBS ?=\n",
+"\"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Interfacelib\"\n",
+"\"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Mathlib\" ;\n",
+"MPWLIBS ?= \n",
+"\"$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib\" ;\n",
+"MPWNLLIBS ?= \n",
+"\"$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW(NL).Lib\" ;\n",
+"SIOUXHDRS ?= ;\n",
+"SIOUXLIBS ?= \n",
+"\"$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.lib\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL SIOUX.PPC.Lib\" \n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC.Lib\" ;\n",
+"C++ ?= mwcppc ;\n",
+"C++FLAGS ?= -w off -nomapcr ;\n",
+"CC ?= mwcppc ;\n",
+"CCFLAGS ?= -w off -nomapcr ;\n",
+"CP ?= duplicate -y ;\n",
+"DOT ?= \":\" ;\n",
+"DOTDOT ?= \"::\" ;\n",
+"HDRS ?= $(MACHDRS) $(MPWHDRS) ;\n",
+"LINK ?= mwlinkppc ;\n",
+"LINKFLAGS ?= -mpwtool -warn ; \n",
+"LINKLIBS ?= $(MACLIBS) $(MPWLIBS) ; \n",
+"MKDIR ?= newfolder ;\n",
+"MV ?= rename -y ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= ;\n",
+"RM ?= delete -y ;\n",
+"SLASH ?= \":\" ;\n",
+"STDHDRS ?= ; \n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .o ;\n",
+"}\n",
+"else if $(OS) = BEOS && $(METROWERKS)\n",
+"{\n",
+"AR ?= mwld -xml -o ;\n",
+"BINDIR ?= /boot/apps ;\n",
+"CC ?= mwcc ;\n",
+"CCFLAGS ?= -nosyspath ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= -nosyspath ;\n",
+"FORTRAN ?= \"\" ;\n",
+"LIBDIR ?= /boot/develop/libraries ;\n",
+"LINK ?= mwld ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"MANDIR ?= /boot/documentation/\"Shell Tools\"/HTML ;\n",
+"NOARSCAN ?= true ;\n",
+"STDHDRS ?= /boot/develop/headers/posix ;\n",
+"}\n",
+"else if $(OS) = BEOS \n",
+"{\n",
+"BINDIR ?= /boot/apps ;\n",
+"CC ?= gcc ;\n",
+"C++ ?= $(CC) ;\n",
+"FORTRAN ?= \"\" ;\n",
+"LIBDIR ?= /boot/develop/libraries ;\n",
+"LINK ?= gcc ;\n",
+"LINKLIBS ?= -lnet ;\n",
+"NOARSCAN ?= true ;\n",
+"STDHDRS ?= /boot/develop/headers/posix ;\n",
+"}\n",
+"else if $(UNIX)\n",
+"{\n",
+"switch $(OS)\n",
+"{\n",
+"case AIX :\n",
+"LINKLIBS ?= -lbsd ;\n",
+"case AMIGA :\n",
+"CC ?= gcc ;\n",
+"YACC ?= bison ;\n",
+"case CYGWIN : \n",
+"CC ?= gcc ;\n",
+"CCFLAGS += -D__cygwin__ ;\n",
+"LEX ?= flex ;\n",
+"JAMSHELL ?= sh -c ;\n",
+"RANLIB ?= \"\" ;\n",
+"SUFEXE ?= .exe ;\n",
+"YACC ?= bison ;\n",
+"case DGUX :\n",
+"RANLIB ?= \"\" ;\n",
+"RELOCATE ?= true ;\n",
+"case HPUX :\n",
+"RANLIB ?= \"\" ;\n",
+"case INTERIX :\n",
+"CC ?= gcc ;\n",
+"JAMSHELL ?= sh -c ;\n",
+"RANLIB ?= \"\" ;\n",
+"case IRIX :\n",
+"RANLIB ?= \"\" ;\n",
+"case MPEIX :\n",
+"CC ?= gcc ;\n",
+"C++ ?= gcc ;\n",
+"CCFLAGS += -D_POSIX_SOURCE ;\n",
+"HDRS += /usr/include ;\n",
+"RANLIB ?= \"\" ; \n",
+"NOARSCAN ?= true ;\n",
+"NOARUPDATE ?= true ;\n",
+"case MVS :\n",
+"RANLIB ?= \"\" ; \n",
+"case NEXT :\n",
+"AR ?= libtool -o ;\n",
+"RANLIB ?= \"\" ;\n",
+"case MACOSX :\n",
+"AR ?= libtool -o ;\n",
+"C++ ?= c++ ;\n",
+"MANDIR ?= /usr/local/share/man ;\n",
+"RANLIB ?= \"\" ;\n",
+"case NCR :\n",
+"RANLIB ?= \"\" ;\n",
+"case PTX :\n",
+"RANLIB ?= \"\" ;\n",
+"case QNX :\n",
+"AR ?= wlib ;\n",
+"CC ?= cc ;\n",
+"CCFLAGS ?= -Q ; # quiet\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= -Q ; # quiet\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= -Q ; # quiet\n",
+"NOARSCAN ?= true ;\n",
+"RANLIB ?= \"\" ;\n",
+"case SCO :\n",
+"RANLIB ?= \"\" ;\n",
+"RELOCATE ?= true ;\n",
+"case SINIX :\n",
+"RANLIB ?= \"\" ;\n",
+"case SOLARIS :\n",
+"RANLIB ?= \"\" ;\n",
+"AR ?= \"/usr/ccs/bin/ar ru\" ;\n",
+"case UNICOS :\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= -O0 ;\n",
+"case UNIXWARE :\n",
+"RANLIB ?= \"\" ;\n",
+"RELOCATE ?= true ;\n",
+"}\n",
+"CCFLAGS ?= ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"CHMOD ?= chmod ;\n",
+"LEX ?= lex ;\n",
+"LINKFLAGS ?= $(CCFLAGS) ;\n",
+"LINKLIBS ?= ;\n",
+"OPTIM ?= -O ;\n",
+"RANLIB ?= ranlib ;\n",
+"YACC ?= yacc ;\n",
+"YACCFILES ?= y.tab ;\n",
+"YACCFLAGS ?= -d ;\n",
+"}\n",
+"AR ?= ar ru ;\n",
+"AS ?= as ;\n",
+"ASFLAGS ?= ;\n",
+"AWK ?= awk ;\n",
+"BINDIR ?= /usr/local/bin ;\n",
+"C++ ?= cc ;\n",
+"C++FLAGS ?= ;\n",
+"CC ?= cc ;\n",
+"CCFLAGS ?= ;\n",
+"CP ?= cp -f ;\n",
+"CRELIB ?= ;\n",
+"DOT ?= . ;\n",
+"DOTDOT ?= .. ;\n",
+"EXEMODE ?= 711 ;\n",
+"FILEMODE ?= 644 ;\n",
+"FORTRAN ?= f77 ;\n",
+"FORTRANFLAGS ?= ;\n",
+"HDRS ?= ;\n",
+"JAMFILE ?= Jamfile ;\n",
+"JAMRULES ?= Jamrules ;\n",
+"LEX ?= ;\n",
+"LIBDIR ?= /usr/local/lib ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= ;\n",
+"LINKLIBS ?= ;\n",
+"LN ?= ln ;\n",
+"MANDIR ?= /usr/local/man ;\n",
+"MKDIR ?= mkdir ;\n",
+"MV ?= mv -f ;\n",
+"OPTIM ?= ;\n",
+"RCP ?= rcp ;\n",
+"RM ?= rm -f ;\n",
+"RSH ?= rsh ;\n",
+"SED ?= sed ;\n",
+"SHELLHEADER ?= \"#!/bin/sh\" ;\n",
+"SHELLMODE ?= 755 ;\n",
+"SLASH ?= / ;\n",
+"STDHDRS ?= /usr/include ;\n",
+"SUFEXE ?= \"\" ;\n",
+"SUFLIB ?= .a ;\n",
+"SUFOBJ ?= .o ;\n",
+"UNDEFFLAG ?= \"-u _\" ;\n",
+"YACC ?= ;\n",
+"YACCFILES ?= ;\n",
+"YACCFLAGS ?= ;\n",
+"HDRPATTERN = \n",
+"\"^[ ]*#[ ]*include[ ]*[<\\\"]([^\\\">]*)[\\\">].*$\" ;\n",
+"OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;\n",
+"DEPENDS all : shell files lib exe obj ;\n",
+"DEPENDS all shell files lib exe obj : first ;\n",
+"NOTFILE all first shell files lib exe obj dirs clean uninstall ;\n",
+"ALWAYS clean uninstall ;\n",
+"rule As\n",
+"{\n",
+"DEPENDS $(<) : $(>) ;\n",
+"ASFLAGS on $(<) += $(ASFLAGS) $(SUBDIRASFLAGS) ;\n",
+"}\n",
+"rule Bulk\n",
+"{\n",
+"local i ;\n",
+"for i in $(>)\n",
+"{\n",
+"File $(i:D=$(<)) : $(i) ;\n",
+"}\n",
+"}\n",
+"rule Cc\n",
+"{\n",
+"local _h ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) ;\n",
+"if $(RELOCATE)\n",
+"{\n",
+"CcMv $(<) : $(>) ;\n",
+"}\n",
+"_h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;\n",
+"if $(VMS) && $(_h)\n",
+"{\n",
+"SLASHINC on $(<) = \"/inc=(\" $(_h[1]) ,$(_h[2-]) \")\" ;\n",
+"}\n",
+"else if $(MAC) && $(_h)\n",
+"{\n",
+"local _i _j ;\n",
+"_j = $(_h[1]) ;\n",
+"for _i in $(_h[2-])\n",
+"{\n",
+"_j = $(_j),$(_i) ;\n",
+"}\n",
+"MACINC on $(<) = \\\"$(_j)\\\" ;\n",
+"}\n",
+"}\n",
+"rule C++\n",
+"{\n",
+"local _h ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) ;\n",
+"if $(RELOCATE)\n",
+"{\n",
+"CcMv $(<) : $(>) ;\n",
+"}\n",
+"_h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;\n",
+"if $(VMS) && $(_h)\n",
+"{\n",
+"SLASHINC on $(<) = \"/inc=(\" $(_h[1]) ,$(_h[2-]) \")\" ;\n",
+"}\n",
+"else if $(MAC) && $(_h)\n",
+"{\n",
+"local _i _j ;\n",
+"_j = $(_h[1]) ;\n",
+"for _i in $(_h[2-])\n",
+"{\n",
+"_j = $(_j),$(_i) ;\n",
+"}\n",
+"MACINC on $(<) = \\\"$(_j)\\\" ;\n",
+"}\n",
+"}\n",
+"rule Chmod\n",
+"{\n",
+"if $(CHMOD) { Chmod1 $(<) ; }\n",
+"}\n",
+"rule File\n",
+"{\n",
+"DEPENDS files : $(<) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"MODE on $(<) = $(FILEMODE) ;\n",
+"Chmod $(<) ;\n",
+"}\n",
+"rule Fortran\n",
+"{\n",
+"DEPENDS $(<) : $(>) ;\n",
+"}\n",
+"rule GenFile \n",
+"{\n",
+"local _t = [ FGristSourceFiles $(<) ] ;\n",
+"local _s = [ FAppendSuffix $(>[1]) : $(SUFEXE) ] ;\n",
+"Depends $(_t) : $(_s) $(>[2-]) ;\n",
+"GenFile1 $(_t) : $(_s) $(>[2-]) ;\n",
+"Clean clean : $(_t) ;\n",
+"}\n",
+"rule GenFile1\n",
+"{\n",
+"MakeLocate $(<) : $(LOCATE_SOURCE) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"}\n",
+"rule HardLink\n",
+"{\n",
+"DEPENDS files : $(<) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"}\n",
+"rule HdrMacroFile\n",
+"{\n",
+"HDRMACRO $(<) ;\n",
+"}\n",
+"rule HdrRule\n",
+"{\n",
+"local s ;\n",
+"if $(HDRGRIST) \n",
+"{ \n",
+"s = $(>:G=$(HDRGRIST)) ;\n",
+"} else { \n",
+"s = $(>) ; \n",
+"}\n",
+"INCLUDES $(<) : $(s) ;\n",
+"SEARCH on $(s) = $(HDRSEARCH) ;\n",
+"NOCARE $(s) ;\n",
+"HDRSEARCH on $(s) = $(HDRSEARCH) ;\n",
+"HDRSCAN on $(s) = $(HDRSCAN) ;\n",
+"HDRRULE on $(s) = $(HDRRULE) ;\n",
+"HDRGRIST on $(s) = $(HDRGRIST) ;\n",
+"}\n",
+"rule InstallInto\n",
+"{\n",
+"local i t ;\n",
+"t = $(>:G=installed) ;\n",
+"DEPENDS install : $(t) ;\n",
+"DEPENDS $(t) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"MakeLocate $(t) : $(<) ;\n",
+"Clean uninstall : $(t) ;\n",
+"for i in $(>)\n",
+"{\n",
+"Install $(i:G=installed) : $(i) ;\n",
+"}\n",
+"Chmod $(t) ;\n",
+"if $(UNIX)\n",
+"{\n",
+"if $(OWNER) { Chown $(t) ; OWNER on $(t) = $(OWNER) ; }\n",
+"if $(GROUP) { Chgrp $(t) ; GROUP on $(t) = $(GROUP) ; }\n",
+"}\n",
+"}\n",
+"rule InstallBin\n",
+"{\n",
+"local _t = [ FAppendSuffix $(>) : $(SUFEXE) ] ;\n",
+"InstallInto $(<) : $(_t) ;\n",
+"MODE on $(_t:G=installed) = $(EXEMODE) ;\n",
+"}\n",
+"rule InstallFile\n",
+"{\n",
+"InstallInto $(<) : $(>) ;\n",
+"MODE on $(>:G=installed) = $(FILEMODE) ;\n",
+"}\n",
+"rule InstallLib\n",
+"{\n",
+"InstallInto $(<) : $(>) ;\n",
+"MODE on $(>:G=installed) = $(FILEMODE) ;\n",
+"}\n",
+"rule InstallMan\n",
+"{\n",
+"local i s d ;\n",
+"for i in $(>)\n",
+"{\n",
+"switch $(i:S)\n",
+"{\n",
+"case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;\n",
+"case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;\n",
+"case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;\n",
+"case .n : s = n ; case .man : s = 1 ;\n",
+"}\n",
+"d = man$(s) ;\n",
+"InstallInto $(d:R=$(<)) : $(i) ;\n",
+"}\n",
+"MODE on $(>:G=installed) = $(FILEMODE) ;\n",
+"}\n",
+"rule InstallShell\n",
+"{\n",
+"InstallInto $(<) : $(>) ;\n",
+"MODE on $(>:G=installed) = $(SHELLMODE) ;\n",
+"}\n",
+"rule Lex\n",
+"{\n",
+"LexMv $(<) : $(>) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"MakeLocate $(<) : $(LOCATE_SOURCE) ;\n",
+"Clean clean : $(<) ;\n",
+"}\n",
+"rule Library\n",
+"{\n",
+"LibraryFromObjects $(<) : $(>:S=$(SUFOBJ)) ;\n",
+"Objects $(>) ;\n",
+"}\n",
+"rule LibraryFromObjects\n",
+"{\n",
+"local _i _l _s ;\n",
+"_s = [ FGristFiles $(>) ] ;\n",
+"_l = $(<:S=$(SUFLIB)) ;\n",
+"if $(KEEPOBJS)\n",
+"{\n",
+"DEPENDS obj : $(_s) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"DEPENDS lib : $(_l) ;\n",
+"}\n",
+"if ! $(_l:D)\n",
+"{\n",
+"MakeLocate $(_l) $(_l)($(_s:BS)) : $(LOCATE_TARGET) ;\n",
+"}\n",
+"if $(NOARSCAN) \n",
+"{ \n",
+"DEPENDS $(_l) : $(_s) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"DEPENDS $(_l) : $(_l)($(_s:BS)) ;\n",
+"for _i in $(_s)\n",
+"{\n",
+"DEPENDS $(_l)($(_i:BS)) : $(_i) ;\n",
+"}\n",
+"}\n",
+"Clean clean : $(_l) ;\n",
+"if $(CRELIB) { CreLib $(_l) : $(_s[1]) ; }\n",
+"Archive $(_l) : $(_s) ;\n",
+"if $(RANLIB) { Ranlib $(_l) ; }\n",
+"if ! ( $(NOARSCAN) || $(KEEPOBJS) ) { RmTemps $(_l) : $(_s) ; }\n",
+"}\n",
+"rule Link\n",
+"{\n",
+"MODE on $(<) = $(EXEMODE) ;\n",
+"Chmod $(<) ;\n",
+"}\n",
+"rule LinkLibraries\n",
+"{\n",
+"local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;\n",
+"DEPENDS $(_t) : $(>:S=$(SUFLIB)) ;\n",
+"NEEDLIBS on $(_t) += $(>:S=$(SUFLIB)) ;\n",
+"}\n",
+"rule Main\n",
+"{\n",
+"MainFromObjects $(<) : $(>:S=$(SUFOBJ)) ;\n",
+"Objects $(>) ;\n",
+"}\n",
+"rule MainFromObjects\n",
+"{\n",
+"local _s _t ;\n",
+"_s = [ FGristFiles $(>) ] ;\n",
+"_t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;\n",
+"if $(_t) != $(<)\n",
+"{\n",
+"DEPENDS $(<) : $(_t) ;\n",
+"NOTFILE $(<) ;\n",
+"}\n",
+"DEPENDS exe : $(_t) ;\n",
+"DEPENDS $(_t) : $(_s) ;\n",
+"MakeLocate $(_t) : $(LOCATE_TARGET) ;\n",
+"Clean clean : $(_t) ;\n",
+"Link $(_t) : $(_s) ;\n",
+"}\n",
+"rule MakeLocate\n",
+"{\n",
+"if $(>)\n",
+"{\n",
+"LOCATE on $(<) = $(>) ;\n",
+"Depends $(<) : $(>[1]) ;\n",
+"MkDir $(>[1]) ;\n",
+"}\n",
+"}\n",
+"rule MkDir\n",
+"{\n",
+"NOUPDATE $(<) ;\n",
+"if $(<) != $(DOT) && ! $($(<)-mkdir) \n",
+"{\n",
+"local s ;\n",
+"$(<)-mkdir = true ;\n",
+"MkDir1 $(<) ;\n",
+"Depends dirs : $(<) ;\n",
+"s = $(<:P) ;\n",
+"if $(NT)\n",
+"{\n",
+"switch $(s)\n",
+"{\n",
+"case *: : s = ;\n",
+"case *:\\\\ : s = ;\n",
+"}\n",
+"}\n",
+"if $(s) && $(s) != $(<)\n",
+"{\n",
+"Depends $(<) : $(s) ;\n",
+"MkDir $(s) ;\n",
+"}\n",
+"else if $(s)\n",
+"{\n",
+"NOTFILE $(s) ;\n",
+"}\n",
+"}\n",
+"}\n",
+"rule Object\n",
+"{\n",
+"local h ;\n",
+"Clean clean : $(<) ;\n",
+"MakeLocate $(<) : $(LOCATE_TARGET) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"HDRS on $(<) = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;\n",
+"if $(SEARCH_SOURCE)\n",
+"{\n",
+"h = $(SEARCH_SOURCE) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"h = \"\" ;\n",
+"}\n",
+"HDRRULE on $(>) = HdrRule ;\n",
+"HDRSCAN on $(>) = $(HDRPATTERN) ;\n",
+"HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(h) $(STDHDRS) ;\n",
+"HDRGRIST on $(>) = $(HDRGRIST) ;\n",
+"switch $(>:S)\n",
+"{\n",
+"case .asm : As $(<) : $(>) ;\n",
+"case .c : Cc $(<) : $(>) ;\n",
+"case .C : C++ $(<) : $(>) ;\n",
+"case .cc : C++ $(<) : $(>) ;\n",
+"case .cpp : C++ $(<) : $(>) ;\n",
+"case .f : Fortran $(<) : $(>) ;\n",
+"case .l : Cc $(<) : $(<:S=.c) ;\n",
+"Lex $(<:S=.c) : $(>) ;\n",
+"case .s : As $(<) : $(>) ;\n",
+"case .y : Cc $(<) : $(<:S=.c) ;\n",
+"Yacc $(<:S=.c) : $(>) ;\n",
+"case * : UserObject $(<) : $(>) ;\n",
+"}\n",
+"}\n",
+"rule ObjectCcFlags\n",
+"{\n",
+"CCFLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
+"}\n",
+"rule ObjectC++Flags\n",
+"{\n",
+"C++FLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
+"}\n",
+"rule ObjectHdrs\n",
+"{\n",
+"HDRS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
+"}\n",
+"rule Objects\n",
+"{\n",
+"local _i ;\n",
+"for _i in [ FGristFiles $(<) ]\n",
+"{\n",
+"Object $(_i:S=$(SUFOBJ)) : $(_i) ;\n",
+"DEPENDS obj : $(_i:S=$(SUFOBJ)) ;\n",
+"}\n",
+"}\n",
+"rule RmTemps\n",
+"{\n",
+"TEMPORARY $(>) ;\n",
+"}\n",
+"rule Setuid\n",
+"{\n",
+"MODE on [ FAppendSuffix $(<) : $(SUFEXE) ] = 4711 ;\n",
+"}\n",
+"rule Shell\n",
+"{\n",
+"DEPENDS shell : $(<) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"MODE on $(<) = $(SHELLMODE) ;\n",
+"Clean clean : $(<) ;\n",
+"Chmod $(<) ;\n",
+"}\n",
+"rule SubDir\n",
+"{\n",
+"local _r _s ;\n",
+"if ! $($(<[1]))\n",
+"{\n",
+"if ! $(<[1])\n",
+"{\n",
+"EXIT SubDir syntax error ;\n",
+"}\n",
+"$(<[1]) = [ FSubDir $(<[2-]) ] ;\n",
+"}\n",
+"if ! $($(<[1])-included)\n",
+"{\n",
+"$(<[1])-included = TRUE ;\n",
+"_r = $($(<[1])RULES) ;\n",
+"if ! $(_r)\n",
+"{\n",
+"_r = $(JAMRULES:R=$($(<[1]))) ;\n",
+"}\n",
+"include $(_r) ;\n",
+"}\n",
+"_s = [ FDirName $(<[2-]) ] ;\n",
+"SUBDIR = $(_s:R=$($(<[1]))) ;\n",
+"SUBDIR_TOKENS = $(<[2-]) ;\n",
+"SEARCH_SOURCE = $(SUBDIR) ;\n",
+"LOCATE_SOURCE = $(ALL_LOCATE_TARGET) $(SUBDIR) ;\n",
+"LOCATE_TARGET = $(ALL_LOCATE_TARGET) $(SUBDIR) ;\n",
+"SOURCE_GRIST = [ FGrist $(<[2-]) ] ;\n",
+"SUBDIRCCFLAGS = ;\n",
+"SUBDIRC++FLAGS = ;\n",
+"SUBDIRHDRS = ;\n",
+"}\n",
+"rule SubDirCcFlags\n",
+"{\n",
+"SUBDIRCCFLAGS += $(<) ;\n",
+"}\n",
+"rule SubDirC++Flags\n",
+"{\n",
+"SUBDIRC++FLAGS += $(<) ;\n",
+"}\n",
+"rule SubDirHdrs\n",
+"{\n",
+"SUBDIRHDRS += $(<) ;\n",
+"}\n",
+"rule SubInclude\n",
+"{\n",
+"local _s ;\n",
+"if ! $($(<[1]))\n",
+"{\n",
+"EXIT Top level of source tree has not been set with $(<[1]) ;\n",
+"}\n",
+"_s = [ FDirName $(<[2-]) ] ;\n",
+"include $(JAMFILE:D=$(_s):R=$($(<[1]))) ;\n",
+"}\n",
+"rule Undefines\n",
+"{\n",
+"UNDEFS on [ FAppendSuffix $(<) : $(SUFEXE) ] += $(UNDEFFLAG)$(>) ;\n",
+"}\n",
+"rule UserObject\n",
+"{\n",
+"EXIT \"Unknown suffix on\" $(>) \"- see UserObject rule in Jamfile(5).\" ;\n",
+"}\n",
+"rule Yacc\n",
+"{\n",
+"local _h ;\n",
+"_h = $(<:BS=.h) ;\n",
+"MakeLocate $(<) $(_h) : $(LOCATE_SOURCE) ;\n",
+"if $(YACC)\n",
+"{\n",
+"DEPENDS $(<) $(_h) : $(>) ;\n",
+"Yacc1 $(<) $(_h) : $(>) ;\n",
+"YaccMv $(<) $(_h) : $(>) ;\n",
+"Clean clean : $(<) $(_h) ;\n",
+"}\n",
+"INCLUDES $(<) : $(_h) ;\n",
+"}\n",
+"rule FGrist\n",
+"{\n",
+"local _g _i ;\n",
+"_g = $(<[1]) ;\n",
+"for _i in $(<[2-])\n",
+"{\n",
+"_g = $(_g)!$(_i) ;\n",
+"}\n",
+"return $(_g) ;\n",
+"}\n",
+"rule FGristFiles \n",
+"{\n",
+"if ! $(SOURCE_GRIST)\n",
+"{\n",
+"return $(<) ;\n",
+"}\n",
+"else \n",
+"{\n",
+"return $(<:G=$(SOURCE_GRIST)) ;\n",
+"}\n",
+"}\n",
+"rule FGristSourceFiles\n",
+"{\n",
+"if ! $(SOURCE_GRIST)\n",
+"{\n",
+"return $(<) ;\n",
+"}\n",
+"else \n",
+"{\n",
+"local _i _o ;\n",
+"for _i in $(<)\n",
+"{\n",
+"switch $(_i)\n",
+"{\n",
+"case *.h : _o += $(_i) ;\n",
+"case * : _o += $(_i:G=$(SOURCE_GRIST)) ;\n",
+"}\n",
+"}\n",
+"return $(_o) ;\n",
+"}\n",
+"}\n",
+"rule FConcat\n",
+"{\n",
+"local _t _r ;\n",
+"$(_r) = $(<[1]) ;\n",
+"for _t in $(<[2-])\n",
+"{\n",
+"$(_r) = $(_r)$(_t) ;\n",
+"}\n",
+"return $(_r) ;\n",
+"}\n",
+"rule FSubDir\n",
+"{\n",
+"local _i _d ;\n",
+"if ! $(<[1]) \n",
+"{\n",
+"_d = $(DOT) ;\n",
+"} \n",
+"else\n",
+"{\n",
+"_d = $(DOTDOT) ;\n",
+"for _i in $(<[2-])\n",
+"{\n",
+"_d = $(_d:R=$(DOTDOT)) ;\n",
+"}\n",
+"}\n",
+"return $(_d) ;\n",
+"}\n",
+"rule FDirName\n",
+"{\n",
+"local _s _i ;\n",
+"if ! $(<)\n",
+"{\n",
+"_s = $(DOT) ;\n",
+"}\n",
+"else if $(VMS)\n",
+"{\n",
+"switch $(<[1])\n",
+"{\n",
+"case *:* : _s = $(<[1]) ;\n",
+"case \\\\[*\\\\] : _s = $(<[1]) ;\n",
+"case * : _s = [.$(<[1])] ;\n",
+"}\n",
+"for _i in [.$(<[2-])]\n",
+"{\n",
+"_s = $(_i:R=$(_s)) ;\n",
+"}\n",
+"}\n",
+"else if $(MAC)\n",
+"{\n",
+"_s = $(DOT) ;\n",
+"for _i in $(<)\n",
+"{\n",
+"_s = $(_i:R=$(_s)) ;\n",
+"}\n",
+"}\n",
+"else\n",
+"{\n",
+"_s = $(<[1]) ; \n",
+"for _i in $(<[2-])\n",
+"{\n",
+"_s = $(_i:R=$(_s)) ;\n",
+"}\n",
+"}\n",
+"return $(_s) ;\n",
+"}\n",
+"rule _makeCommon\n",
+"{\n",
+"if $($(<)[1]) && $($(<)[1]) = $($(>)[1])\n",
+"{\n",
+"$(<) = $($(<)[2-]) ;\n",
+"$(>) = $($(>)[2-]) ;\n",
+"_makeCommon $(<) : $(>) ;\n",
+"}\n",
+"}\n",
+"rule FRelPath\n",
+"{\n",
+"local _l _r ;\n",
+"_l = $(<) ;\n",
+"_r = $(>) ;\n",
+"_makeCommon _l : _r ;\n",
+"_l = [ FSubDir $(_l) ] ;\n",
+"_r = [ FDirName $(_r) ] ;\n",
+"if $(_r) = $(DOT) {\n",
+"return $(_l) ;\n",
+"} else {\n",
+"return $(_r:R=$(_l)) ;\n",
+"}\n",
+"}\n",
+"rule FAppendSuffix\n",
+"{\n",
+"if $(>)\n",
+"{\n",
+"local _i _o ;\n",
+"for _i in $(<)\n",
+"{\n",
+"if $(_i:S)\n",
+"{\n",
+"_o += $(_i) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"_o += $(_i:S=$(>)) ;\n",
+"}\n",
+"}\n",
+"return $(_o) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"return $(<) ;\n",
+"}\n",
+"}\n",
+"rule unmakeDir\n",
+"{\n",
+"if $(>[1]:D) && $(>[1]:D) != $(>[1]) && $(>[1]:D) != \\\\\\\\ \n",
+"{\n",
+"unmakeDir $(<) : $(>[1]:D) $(>[1]:BS) $(>[2-]) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"$(<) = $(>) ;\n",
+"}\n",
+"}\n",
+"rule FConvertToSlashes\n",
+"{\n",
+"local _d, _s, _i ;\n",
+"unmakeDir _d : $(<) ;\n",
+"_s = $(_d[1]) ; \n",
+"for _i in $(_d[2-])\n",
+"{\n",
+"_s = $(_s)/$(_i) ;\n",
+"}\n",
+"return $(_s) ;\n",
+"}\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) $(>)\n",
+"}\n",
+"actions As\n",
+"{\n",
+"$(AS) $(ASFLAGS) -I$(HDRS) -o $(<) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)\n",
+"}\n",
+"actions Chgrp\n",
+"{\n",
+"chgrp $(GROUP) $(<)\n",
+"}\n",
+"actions Chmod1\n",
+"{\n",
+"$(CHMOD) $(MODE) $(<)\n",
+"}\n",
+"actions Chown\n",
+"{\n",
+"chown $(OWNER) $(<)\n",
+"}\n",
+"actions piecemeal together existing Clean\n",
+"{\n",
+"$(RM) $(>)\n",
+"}\n",
+"actions File\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"actions GenFile1\n",
+"{\n",
+"$(>[1]) $(<) $(>[2-])\n",
+"}\n",
+"actions Fortran\n",
+"{\n",
+"$(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)\n",
+"}\n",
+"actions HardLink\n",
+"{\n",
+"$(RM) $(<) && $(LN) $(>) $(<)\n",
+"}\n",
+"actions Install\n",
+"{\n",
+"$(CP) $(>) $(<) \n",
+"}\n",
+"actions Lex\n",
+"{\n",
+"$(LEX) $(>)\n",
+"}\n",
+"actions LexMv\n",
+"{\n",
+"$(MV) lex.yy.c $(<)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) \n",
+"}\n",
+"actions MkDir1\n",
+"{\n",
+"$(MKDIR) $(<)\n",
+"}\n",
+"actions together Ranlib\n",
+"{\n",
+"$(RANLIB) $(<)\n",
+"}\n",
+"actions quietly updated piecemeal together RmTemps\n",
+"{\n",
+"$(RM) $(>)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(AWK) '\n",
+"NR == 1 { print \"$(SHELLHEADER)\" }\n",
+"NR == 1 && /^[#:]/ { next }\n",
+"/^##/ { next }\n",
+"{ print }\n",
+"' < $(>) > $(<)\n",
+"}\n",
+"actions Yacc1\n",
+"{\n",
+"$(YACC) $(YACCFLAGS) $(>)\n",
+"}\n",
+"actions YaccMv\n",
+"{\n",
+"$(MV) $(YACCFILES).c $(<[1])\n",
+"$(MV) $(YACCFILES).h $(<[2])\n",
+"}\n",
+"if $(RELOCATE)\n",
+"{\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) $(>)\n",
+"}\n",
+"actions ignore CcMv\n",
+"{\n",
+"[ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)\n",
+"}\n",
+"}\n",
+"if $(NOARUPDATE)\n",
+"{\n",
+"actions Archive\n",
+"{\n",
+"$(AR) $(<) $(>)\n",
+"}\n",
+"}\n",
+"if $(NT)\n",
+"{\n",
+"if $(TOOLSET) = VISUALC || $(TOOLSET) = INTELC\n",
+"{\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"if exist $(<) set _$(<:B)_=$(<)\n",
+"$(AR) /out:$(<) %_$(<:B)_% $(>)\n",
+"}\n",
+"actions As\n",
+"{\n",
+"$(AS) /Ml /p /v /w2 $(>) $(<) ,nul,nul;\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) /Tp$(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = VISUALC16\n",
+"{\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) -+$(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /Tp$(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = BORLANDC\n",
+"{\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) -+$(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) -e$(<) $(LINKFLAGS) $(UNDEFS) -L$(LINKLIBS) $(NEEDLIBS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = MINGW\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) $(>:T)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = WATCOM\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) +-$(>) \n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = LCC\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) /out:$(<) $(>) \n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) $(CCFLAGS) $(OPTIM) -Fo$(<) -I$(HDRS) $(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"}\n",
+"else if $(OS2) \n",
+"{\n",
+"if $(TOOLSET) = WATCOM\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) +-$(>) \n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = EMX\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) $(>:T)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"}\n",
+"}\n",
+"else if $(VMS)\n",
+"{\n",
+"actions updated together piecemeal Archive \n",
+"{\n",
+"lib/replace $(<) $(>[1]) ,$(>[2-])\n",
+"}\n",
+"actions Cc\n",
+"{ \n",
+"$(CC)/obj=$(<) $(CCFLAGS) $(OPTIM) $(SLASHINC) $(>) \n",
+"}\n",
+"actions C++\n",
+"{ \n",
+"$(C++)/obj=$(<) $(C++FLAGS) $(OPTIM) $(SLASHINC) $(>) \n",
+"}\n",
+"actions piecemeal together existing Clean\n",
+"{\n",
+"$(RM) $(>[1]);* ,$(>[2-]);*\n",
+"}\n",
+"actions together quietly CreLib\n",
+"{\n",
+"if f$search(\"$(<)\") .eqs. \"\" then lib/create $(<)\n",
+"}\n",
+"actions GenFile1\n",
+"{\n",
+"mcr $(>[1]) $(<) $(>[2-])\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK)/exe=$(<) $(LINKFLAGS) $(>[1]) ,$(>[2-]) ,$(NEEDLIBS)/lib ,$(LINKLIBS)\n",
+"}\n",
+"actions quietly updated piecemeal together RmTemps\n",
+"{\n",
+"$(RM) $(>[1]);* ,$(>[2-]);*\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"else if $(MAC)\n",
+"{\n",
+"actions together Archive \n",
+"{\n",
+"$(LINK) -library -o $(<) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"set -e MWCincludes $(MACINC)\n",
+"$(CC) -o $(<) $(CCFLAGS) $(OPTIM) $(>) \n",
+"}\n",
+"actions C++\n",
+"{ \n",
+"set -e MWCincludes $(MACINC)\n",
+"$(CC) -o $(<) $(C++FLAGS) $(OPTIM) $(>) \n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) -o $(<) $(LINKFLAGS) $(>) $(NEEDLIBS) \"$(LINKLIBS)\"\n",
+"}\n",
+"}\n",
+"rule BULK { Bulk $(<) : $(>) ; }\n",
+"rule FILE { File $(<) : $(>) ; }\n",
+"rule HDRRULE { HdrRule $(<) : $(>) ; }\n",
+"rule INSTALL { Install $(<) : $(>) ; }\n",
+"rule LIBRARY { Library $(<) : $(>) ; }\n",
+"rule LIBS { LinkLibraries $(<) : $(>) ; }\n",
+"rule LINK { Link $(<) : $(>) ; }\n",
+"rule MAIN { Main $(<) : $(>) ; }\n",
+"rule SETUID { Setuid $(<) ; }\n",
+"rule SHELL { Shell $(<) : $(>) ; }\n",
+"rule UNDEFINES { Undefines $(<) : $(>) ; }\n",
+"rule INSTALLBIN { InstallBin $(BINDIR) : $(<) ; }\n",
+"rule INSTALLLIB { InstallLib $(LIBDIR) : $(<) ; }\n",
+"rule INSTALLMAN { InstallMan $(MANDIR) : $(<) ; }\n",
+"rule addDirName { $(<) += [ FDirName $(>) ] ; }\n",
+"rule makeDirName { $(<) = [ FDirName $(>) ] ; }\n",
+"rule makeGristedName { $(<) = [ FGristSourceFiles $(>) ] ; }\n",
+"rule makeRelPath { $(<[1]) = [ FRelPath $(<[2-]) : $(>) ] ; }\n",
+"rule makeSuffixed { $(<[1]) = [ FAppendSuffix $(>) : $(<[2]) ] ; }\n",
+"{\n",
+"if $(JAMFILE) { include $(JAMFILE) ; }\n",
+"}\n",
+"}\n",
+0 };
diff --git a/historic/jam/src/jambase.h b/historic/jam/src/jambase.h
new file mode 100644
index 000000000..75393f4cc
--- /dev/null
+++ b/historic/jam/src/jambase.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jambase.h - declaration for the internal jambase
+ *
+ * The file Jambase is turned into a C array of strings in jambase.c
+ * so that it can be built in to the executable. This is the
+ * declaration for that array.
+ */
+
+extern char *jambase[];
diff --git a/historic/jam/src/jamgram.c b/historic/jam/src/jamgram.c
new file mode 100644
index 000000000..ae916fef5
--- /dev/null
+++ b/historic/jam/src/jamgram.c
@@ -0,0 +1,1212 @@
+
+/* A Bison parser, made from jamgram.y
+ by GNU Bison version 1.28 */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define _BANG 257
+#define _BANG_EQUALS 258
+#define _AMPERAMPER 259
+#define _LPAREN 260
+#define _RPAREN 261
+#define _PLUS_EQUALS 262
+#define _COLON 263
+#define _SEMIC 264
+#define _LANGLE 265
+#define _LANGLE_EQUALS 266
+#define _EQUALS 267
+#define _RANGLE 268
+#define _RANGLE_EQUALS 269
+#define _QUESTION_EQUALS 270
+#define _LBRACKET 271
+#define _RBRACKET 272
+#define ACTIONS 273
+#define BIND 274
+#define CASE 275
+#define DEFAULT 276
+#define ELSE 277
+#define EXISTING 278
+#define FOR 279
+#define IF 280
+#define IGNORE 281
+#define IN 282
+#define INCLUDE 283
+#define LOCAL 284
+#define MODULE 285
+#define ON 286
+#define PIECEMEAL 287
+#define QUIETLY 288
+#define RETURN 289
+#define RULE 290
+#define SWITCH 291
+#define TOGETHER 292
+#define UPDATED 293
+#define WHILE 294
+#define _LBRACE 295
+#define _BARBAR 296
+#define _RBRACE 297
+#define ARG 298
+#define STRING 299
+
+
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "newstr.h"
+
+# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define P0 (PARSE *)0
+# define S0 (char *)0
+
+# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
+# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
+# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
+# define psetmodule( l,r ) parse_make( compile_set_module,l,r,P0,S0,S0,0 )
+# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
+# define psetc( s,p ) parse_make( compile_setcomp,p,P0,P0,s,S0,0 )
+# define psetc_args( s,p,a ) parse_make( compile_setcomp,p,a,P0,s,S0,0 )
+# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#ifndef YYDEBUG
+#define YYDEBUG 1
+#endif
+
+#include
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define YYFINAL 145
+#define YYFLAG -32768
+#define YYNTBASE 46
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 299 ? yytranslate[x] : 64)
+
+static const char yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = { 0,
+ 0, 1, 3, 4, 6, 8, 11, 17, 18, 21,
+ 25, 29, 33, 38, 44, 51, 55, 63, 72, 78,
+ 84, 90, 96, 104, 111, 115, 116, 117, 127, 129,
+ 131, 133, 136, 138, 142, 146, 150, 154, 158, 162,
+ 166, 169, 173, 177, 181, 182, 185, 190, 192, 196,
+ 198, 199, 202, 204, 209, 210, 213, 215, 217, 219,
+ 221, 223, 225, 226
+};
+
+static const short yyrhs[] = { -1,
+ 48, 0, 0, 48, 0, 50, 0, 50, 48, 0,
+ 30, 58, 49, 10, 47, 0, 0, 13, 58, 0,
+ 41, 47, 43, 0, 29, 58, 10, 0, 44, 57,
+ 10, 0, 60, 53, 58, 10, 0, 31, 30, 58,
+ 49, 10, 0, 60, 32, 58, 53, 58, 10, 0,
+ 35, 58, 10, 0, 25, 44, 28, 58, 41, 47,
+ 43, 0, 25, 30, 44, 28, 58, 41, 47, 43,
+ 0, 37, 58, 41, 55, 43, 0, 26, 54, 41,
+ 47, 43, 0, 31, 58, 41, 47, 43, 0, 40,
+ 54, 41, 47, 43, 0, 26, 54, 41, 47, 43,
+ 23, 50, 0, 36, 44, 6, 57, 7, 50, 0,
+ 36, 44, 50, 0, 0, 0, 19, 61, 44, 63,
+ 41, 51, 45, 52, 43, 0, 13, 0, 8, 0,
+ 16, 0, 22, 13, 0, 60, 0, 60, 13, 60,
+ 0, 60, 4, 60, 0, 60, 11, 60, 0, 60,
+ 12, 60, 0, 60, 14, 60, 0, 60, 15, 60,
+ 0, 60, 28, 58, 0, 3, 54, 0, 54, 5,
+ 54, 0, 54, 42, 54, 0, 6, 54, 7, 0,
+ 0, 56, 55, 0, 21, 44, 9, 47, 0, 58,
+ 0, 58, 9, 57, 0, 59, 0, 0, 59, 60,
+ 0, 44, 0, 17, 44, 57, 18, 0, 0, 61,
+ 62, 0, 39, 0, 38, 0, 27, 0, 34, 0,
+ 33, 0, 24, 0, 0, 20, 58, 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+ 125, 127, 138, 140, 144, 146, 148, 152, 154, 158,
+ 160, 162, 164, 166, 168, 170, 172, 174, 176, 178,
+ 180, 182, 184, 186, 188, 190, 193, 195, 202, 204,
+ 206, 208, 216, 218, 220, 222, 224, 226, 228, 230,
+ 232, 234, 236, 238, 248, 250, 254, 263, 265, 275,
+ 279, 281, 285, 287, 297, 299, 303, 305, 307, 309,
+ 311, 313, 322, 324
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = { "$","error","$undefined.","_BANG",
+"_BANG_EQUALS","_AMPERAMPER","_LPAREN","_RPAREN","_PLUS_EQUALS","_COLON","_SEMIC",
+"_LANGLE","_LANGLE_EQUALS","_EQUALS","_RANGLE","_RANGLE_EQUALS","_QUESTION_EQUALS",
+"_LBRACKET","_RBRACKET","ACTIONS","BIND","CASE","DEFAULT","ELSE","EXISTING",
+"FOR","IF","IGNORE","IN","INCLUDE","LOCAL","MODULE","ON","PIECEMEAL","QUIETLY",
+"RETURN","RULE","SWITCH","TOGETHER","UPDATED","WHILE","_LBRACE","_BARBAR","_RBRACE",
+"ARG","STRING","run","block","rules","assign_list_opt","rule","@1","@2","assign",
+"cond","cases","case","lol","list","listp","arg","eflags","eflag","bindlist", NULL
+};
+#endif
+
+static const short yyr1[] = { 0,
+ 46, 46, 47, 47, 48, 48, 48, 49, 49, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 51, 52, 50, 53, 53,
+ 53, 53, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 55, 55, 56, 57, 57, 58,
+ 59, 59, 60, 60, 61, 61, 62, 62, 62, 62,
+ 62, 62, 63, 63
+};
+
+static const short yyr2[] = { 0,
+ 0, 1, 0, 1, 1, 2, 5, 0, 2, 3,
+ 3, 3, 4, 5, 6, 3, 7, 8, 5, 5,
+ 5, 5, 7, 6, 3, 0, 0, 9, 1, 1,
+ 1, 2, 1, 3, 3, 3, 3, 3, 3, 3,
+ 2, 3, 3, 3, 0, 2, 4, 1, 3, 1,
+ 0, 2, 1, 4, 0, 2, 1, 1, 1, 1,
+ 1, 1, 0, 2
+};
+
+static const short yydefact[] = { 1,
+ 0, 55, 0, 0, 51, 51, 51, 51, 0, 51,
+ 0, 3, 53, 2, 5, 0, 51, 0, 0, 0,
+ 0, 0, 53, 0, 33, 0, 50, 8, 51, 0,
+ 0, 0, 0, 0, 0, 4, 0, 48, 6, 30,
+ 29, 31, 0, 51, 51, 0, 62, 59, 61, 60,
+ 58, 57, 63, 56, 0, 51, 41, 0, 0, 3,
+ 0, 0, 0, 0, 0, 0, 0, 51, 11, 52,
+ 51, 0, 8, 3, 16, 51, 25, 45, 3, 10,
+ 12, 51, 32, 0, 0, 54, 51, 0, 51, 0,
+ 44, 42, 0, 43, 35, 36, 37, 34, 38, 39,
+ 40, 9, 3, 0, 0, 0, 0, 0, 45, 0,
+ 49, 51, 13, 64, 26, 0, 3, 20, 7, 14,
+ 21, 0, 0, 19, 46, 22, 0, 0, 3, 0,
+ 0, 24, 3, 15, 27, 0, 17, 23, 47, 0,
+ 18, 28, 0, 0, 0
+};
+
+static const short yydefgoto[] = { 143,
+ 35, 36, 72, 15, 128, 140, 45, 24, 108, 109,
+ 37, 38, 27, 16, 18, 54, 88
+};
+
+static const short yypact[] = { 106,
+ -34,-32768, -13, 8,-32768,-32768, -17,-32768, -16,-32768,
+ 8, 106, 24,-32768, 106, 174,-32768, 95, -15, -12,
+ 8, 8,-32768, 4, 166, 22, -2, 23,-32768, -6,
+ 28, 80, 2, 18, 1,-32768, 39, 45,-32768,-32768,
+-32768,-32768, 42,-32768,-32768, 43,-32768,-32768,-32768,-32768,
+-32768,-32768, 49,-32768, 34,-32768,-32768, 15, 8, 106,
+ 8, -2, -2, -2, -2, -2, -2,-32768,-32768,-32768,
+-32768, 60, 23, 106,-32768,-32768,-32768, 52, 106,-32768,
+-32768,-32768,-32768, 59, 64,-32768,-32768, 36,-32768, 37,
+-32768,-32768, 40, 74,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768, 106, 85, 53, 91, 56, 58, 52, 61,
+-32768,-32768,-32768,-32768,-32768, 67, 106, 79,-32768,-32768,
+-32768, 132, 101,-32768,-32768,-32768, 102, 68, 106, 71,
+ 132,-32768, 106,-32768,-32768, 75,-32768,-32768,-32768, 83,
+-32768,-32768, 127, 130,-32768
+};
+
+static const short yypgoto[] = {-32768,
+ -53, 12, 65, -28,-32768,-32768, 69, -3, 31,-32768,
+ -11, -5,-32768, 26,-32768,-32768,-32768
+};
+
+
+#define YYLAST 206
+
+
+static const short yytable[] = { 26,
+ 28, 30, 31, 77, 33, 46, 93, 34, 59, 17,
+ 21, 14, 29, 22, 1, 56, 19, 57, 58, 59,
+ 105, 91, 59, 73, 1, 110, 39, 32, 55, 25,
+ 20, 69, -51, -51, 74, 71, 25, 75, 84, 85,
+ -51, 23, 78, 80, 60, 61, 25, 25, 81, 119,
+ 90, 23, 70, 82, 83, 92, 61, 94, 79, 61,
+ 86, 89, 101, 130, 106, 102, 40, -51, 87, 103,
+ 111, 41, 107, 113, 42, 136, 115, 117, 59, 139,
+ 43, 114, 118, 116, 25, 76, 25, 95, 96, 97,
+ 98, 99, 100, 132, 120, 121, 1, 122, 2, 123,
+ 124, 131, 138, 126, 3, 4, 127, 129, 5, 133,
+ 7, 134, 135, 137, 8, 9, 10, 141, 47, 11,
+ 12, 48, 1, 13, 2, 142, 144, 49, 50, 145,
+ 3, 4, 51, 52, 5, 6, 7, 104, 53, 125,
+ 8, 9, 10, 0, 0, 11, 12, 0, 1, 13,
+ 2, 0, 112, 0, 0, 0, 3, 4, 0, 0,
+ 5, 0, 7, 0, 0, 0, 8, 9, 10, 62,
+ 0, 11, 12, 0, 0, 13, 63, 64, 65, 66,
+ 67, 40, 0, 0, 0, 0, 41, 0, 0, 42,
+ 0, 0, 0, 68, 0, 43, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 44
+};
+
+static const short yycheck[] = { 5,
+ 6, 7, 8, 32, 10, 17, 60, 11, 5, 44,
+ 3, 0, 30, 6, 17, 28, 30, 21, 22, 5,
+ 74, 7, 5, 29, 17, 79, 15, 44, 44, 4,
+ 44, 10, 9, 10, 41, 13, 11, 10, 44, 45,
+ 17, 44, 41, 43, 41, 42, 21, 22, 10, 103,
+ 56, 44, 27, 9, 13, 59, 42, 61, 41, 42,
+ 18, 28, 68, 117, 76, 71, 8, 44, 20, 10,
+ 82, 13, 21, 10, 16, 129, 41, 41, 5, 133,
+ 22, 87, 43, 89, 59, 6, 61, 62, 63, 64,
+ 65, 66, 67, 122, 10, 43, 17, 7, 19, 44,
+ 43, 23, 131, 43, 25, 26, 112, 41, 29, 9,
+ 31, 10, 45, 43, 35, 36, 37, 43, 24, 40,
+ 41, 27, 17, 44, 19, 43, 0, 33, 34, 0,
+ 25, 26, 38, 39, 29, 30, 31, 73, 44, 109,
+ 35, 36, 37, -1, -1, 40, 41, -1, 17, 44,
+ 19, -1, 84, -1, -1, -1, 25, 26, -1, -1,
+ 29, -1, 31, -1, -1, -1, 35, 36, 37, 4,
+ -1, 40, 41, -1, -1, 44, 11, 12, 13, 14,
+ 15, 8, -1, -1, -1, -1, 13, -1, -1, 16,
+ -1, -1, -1, 28, -1, 22, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 32
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
+#include
+#else /* not sparc */
+#if defined (MSDOS) && !defined (__TURBOC__)
+#include
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+#include
+ #pragma alloca
+#else /* not MSDOS, __TURBOC__, or _AIX */
+#ifdef __hpux
+#ifdef __cplusplus
+extern "C" {
+void *alloca (unsigned int);
+};
+#else /* not __cplusplus */
+void *alloca ();
+#endif /* not __cplusplus */
+#endif /* __hpux */
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc. */
+#endif /* not GNU C. */
+#endif /* alloca not defined. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT return(0)
+#define YYABORT return(1)
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { yychar = (token), yylval = (value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+#ifndef YYPURE
+#define YYLEX yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int yychar; /* the lookahead symbol */
+YYSTYPE yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int yynerrs; /* number of parse errors so far */
+#endif /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+int yyparse (void);
+#endif
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (to, from, count)
+ char *to;
+ char *from;
+ int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (char *to, char *from, int count)
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int yystate;
+ register int yyn;
+ register short *yyssp;
+ register YYSTYPE *yyvsp;
+ int yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short yyssa[YYINITDEPTH]; /* the state stack */
+ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+
+ short *yyss = yyssa; /* refer to the stacks thru separate pointers */
+ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+
+#ifdef YYPURE
+ int yychar;
+ YYSTYPE yylval;
+ int yynerrs;
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylloc;
+#endif
+#endif
+
+ YYSTYPE yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int yylen;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+yynewstate:
+
+ *yyssp++ = yystate;
+
+ if (yyssp >= yyss + yystacksize)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+#else
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+#endif
+
+ yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+ yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror("parser stack overflow");
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+ yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp));
+ yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+ yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size;
+ yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+ if (yyssp >= yyss + yystacksize)
+ YYABORT;
+ }
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+ goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (yyerrstatus) yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+/* Do the default action for the current state. */
+yydefault:
+
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+
+/* Do a reduction. yyn is the number of a rule to reduce with. */
+yyreduce:
+ yylen = yyr2[yyn];
+ if (yylen > 0)
+ yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+
+ switch (yyn) {
+
+case 2:
+{ parse_save( yyvsp[0].parse ); ;
+ break;}
+case 3:
+{ yyval.parse = pnull(); ;
+ break;}
+case 4:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+case 5:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+case 6:
+{ yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); ;
+ break;}
+case 7:
+{ yyval.parse = plocal( yyvsp[-3].parse, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 8:
+{ yyval.parse = pnull(); ;
+ break;}
+case 9:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+case 10:
+{ yyval.parse = yyvsp[-1].parse; ;
+ break;}
+case 11:
+{ yyval.parse = pincl( yyvsp[-1].parse ); ;
+ break;}
+case 12:
+{ yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); ;
+ break;}
+case 13:
+{ yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); ;
+ break;}
+case 14:
+{ yyval.parse = psetmodule( yyvsp[-2].parse, yyvsp[-1].parse ); ;
+ break;}
+case 15:
+{ yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); ;
+ break;}
+case 16:
+{ yyval.parse = yyvsp[-1].parse; ;
+ break;}
+case 17:
+{ yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, 0 ); ;
+ break;}
+case 18:
+{ yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, 1 ); ;
+ break;}
+case 19:
+{ yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); ;
+ break;}
+case 20:
+{ yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); ;
+ break;}
+case 21:
+{ yyval.parse = pmodule( yyvsp[-3].parse, yyvsp[-1].parse ); ;
+ break;}
+case 22:
+{ yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); ;
+ break;}
+case 23:
+{ yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); ;
+ break;}
+case 24:
+{ yyval.parse = psetc_args( yyvsp[-4].string, yyvsp[0].parse, yyvsp[-2].parse ); ;
+ break;}
+case 25:
+{ yyval.parse = psetc( yyvsp[-1].string, yyvsp[0].parse ); ;
+ break;}
+case 26:
+{ yymode( SCAN_STRING ); ;
+ break;}
+case 27:
+{ yymode( SCAN_NORMAL ); ;
+ break;}
+case 28:
+{ yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); ;
+ break;}
+case 29:
+{ yyval.number = ASSIGN_SET; ;
+ break;}
+case 30:
+{ yyval.number = ASSIGN_APPEND; ;
+ break;}
+case 31:
+{ yyval.number = ASSIGN_DEFAULT; ;
+ break;}
+case 32:
+{ yyval.number = ASSIGN_DEFAULT; ;
+ break;}
+case 33:
+{ yyval.parse = pcnode( COND_EXISTS, yyvsp[0].parse, pnull() ); ;
+ break;}
+case 34:
+{ yyval.parse = pcnode( COND_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 35:
+{ yyval.parse = pcnode( COND_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 36:
+{ yyval.parse = pcnode( COND_LESS, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 37:
+{ yyval.parse = pcnode( COND_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 38:
+{ yyval.parse = pcnode( COND_MORE, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 39:
+{ yyval.parse = pcnode( COND_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 40:
+{ yyval.parse = pcnode( COND_IN, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 41:
+{ yyval.parse = pcnode( COND_NOT, yyvsp[0].parse, P0 ); ;
+ break;}
+case 42:
+{ yyval.parse = pcnode( COND_AND, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 43:
+{ yyval.parse = pcnode( COND_OR, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 44:
+{ yyval.parse = yyvsp[-1].parse; ;
+ break;}
+case 45:
+{ yyval.parse = P0; ;
+ break;}
+case 46:
+{ yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); ;
+ break;}
+case 47:
+{ yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); ;
+ break;}
+case 48:
+{ yyval.parse = pnode( P0, yyvsp[0].parse ); ;
+ break;}
+case 49:
+{ yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); ;
+ break;}
+case 50:
+{ yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); ;
+ break;}
+case 51:
+{ yyval.parse = pnull(); yymode( SCAN_PUNCT ); ;
+ break;}
+case 52:
+{ yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); ;
+ break;}
+case 53:
+{ yyval.parse = plist( yyvsp[0].string ); ;
+ break;}
+case 54:
+{ yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); ;
+ break;}
+case 55:
+{ yyval.number = 0; ;
+ break;}
+case 56:
+{ yyval.number = yyvsp[-1].number | yyvsp[0].number; ;
+ break;}
+case 57:
+{ yyval.number = EXEC_UPDATED; ;
+ break;}
+case 58:
+{ yyval.number = EXEC_TOGETHER; ;
+ break;}
+case 59:
+{ yyval.number = EXEC_IGNORE; ;
+ break;}
+case 60:
+{ yyval.number = EXEC_QUIETLY; ;
+ break;}
+case 61:
+{ yyval.number = EXEC_PIECEMEAL; ;
+ break;}
+case 62:
+{ yyval.number = EXEC_EXISTING; ;
+ break;}
+case 63:
+{ yyval.parse = pnull(); ;
+ break;}
+case 64:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *ssp1++);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+ yylsp++;
+ if (yylen == 0)
+ {
+ yylsp->first_line = yylloc.first_line;
+ yylsp->first_column = yylloc.first_column;
+ yylsp->last_line = (yylsp-1)->last_line;
+ yylsp->last_column = (yylsp-1)->last_column;
+ yylsp->text = 0;
+ }
+ else
+ {
+ yylsp->last_line = (yylsp+yylen-1)->last_line;
+ yylsp->last_column = (yylsp+yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *(yyssp - 1);
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *(yyssp - 1))
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+yyerrlab: /* here on detecting error */
+
+ if (! yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen(yytname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, yytname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ yyerror(msg);
+ free(msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror("parse error");
+ }
+
+ goto yyerrlab1;
+yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (yyn) goto yydefault;
+#endif
+
+yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (yyssp - 1 == yyss) YYABORT;
+ yyvsp--;
+ yyssp--;
+ yystate = *(yyssp - 1);
+#ifdef YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *ssp1++);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+yyerrhandle:
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+}
+
+
diff --git a/historic/jam/src/jamgram.h b/historic/jam/src/jamgram.h
new file mode 100644
index 000000000..74acdd439
--- /dev/null
+++ b/historic/jam/src/jamgram.h
@@ -0,0 +1,49 @@
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#define _BANG 257
+#define _BANG_EQUALS 258
+#define _AMPERAMPER 259
+#define _LPAREN 260
+#define _RPAREN 261
+#define _PLUS_EQUALS 262
+#define _COLON 263
+#define _SEMIC 264
+#define _LANGLE 265
+#define _LANGLE_EQUALS 266
+#define _EQUALS 267
+#define _RANGLE 268
+#define _RANGLE_EQUALS 269
+#define _QUESTION_EQUALS 270
+#define _LBRACKET 271
+#define _RBRACKET 272
+#define ACTIONS 273
+#define BIND 274
+#define CASE 275
+#define DEFAULT 276
+#define ELSE 277
+#define EXISTING 278
+#define FOR 279
+#define IF 280
+#define IGNORE 281
+#define IN 282
+#define INCLUDE 283
+#define LOCAL 284
+#define MODULE 285
+#define ON 286
+#define PIECEMEAL 287
+#define QUIETLY 288
+#define RETURN 289
+#define RULE 290
+#define SWITCH 291
+#define TOGETHER 292
+#define UPDATED 293
+#define WHILE 294
+#define _LBRACE 295
+#define _BARBAR 296
+#define _RBRACE 297
+#define ARG 298
+#define STRING 299
+
+
+extern YYSTYPE yylval;
diff --git a/historic/jam/src/jamgram.y b/historic/jam/src/jamgram.y
new file mode 100644
index 000000000..17569c76c
--- /dev/null
+++ b/historic/jam/src/jamgram.y
@@ -0,0 +1,328 @@
+%token _BANG
+%token _BANG_EQUALS
+%token _AMPERAMPER
+%token _LPAREN
+%token _RPAREN
+%token _PLUS_EQUALS
+%token _COLON
+%token _SEMIC
+%token _LANGLE
+%token _LANGLE_EQUALS
+%token _EQUALS
+%token _RANGLE
+%token _RANGLE_EQUALS
+%token _QUESTION_EQUALS
+%token _LBRACKET
+%token _RBRACKET
+%token ACTIONS
+%token BIND
+%token CASE
+%token DEFAULT
+%token ELSE
+%token EXISTING
+%token FOR
+%token IF
+%token IGNORE
+%token IN
+%token INCLUDE
+%token LOCAL
+%token MODULE
+%token ON
+%token PIECEMEAL
+%token QUIETLY
+%token RETURN
+%token RULE
+%token SWITCH
+%token TOGETHER
+%token UPDATED
+%token WHILE
+%token _LBRACE
+%token _BARBAR
+%token _RBRACE
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jamgram.yy - jam grammar
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ * 08/31/94 (seiwald) - Allow ?= as alias for "default =".
+ * 09/15/94 (seiwald) - if conditionals take only single arguments, so
+ * that 'if foo == bar' gives syntax error (use =).
+ * 02/11/95 (seiwald) - when scanning arguments to rules, only treat
+ * punctuation keywords as keywords. All arg lists
+ * are terminated with punctuation keywords.
+ *
+ * 09/11/00 (seiwald) - Support for function calls:
+ *
+ * Rules now return lists (LIST *), rather than void.
+ *
+ * New "[ rule ]" syntax evals rule into a LIST.
+ *
+ * Lists are now generated by compile_list() and
+ * compile_append(), and any other rule that indirectly
+ * makes a list, rather than being built directly here,
+ * so that lists values can contain rule evaluations.
+ *
+ * New 'return' rule sets the return value, though
+ * other statements also may have return values.
+ *
+ * 'run' production split from 'block' production so
+ * that empty blocks can be handled separately.
+ */
+
+%token ARG STRING
+
+%left _BARBAR
+%left _AMPERAMPER
+%left _BANG
+
+%{
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "newstr.h"
+
+# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define P0 (PARSE *)0
+# define S0 (char *)0
+
+# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
+# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
+# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
+# define psetmodule( l,r ) parse_make( compile_set_module,l,r,P0,S0,S0,0 )
+# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
+# define psetc( s,p ) parse_make( compile_setcomp,p,P0,P0,s,S0,0 )
+# define psetc_args( s,p,a ) parse_make( compile_setcomp,p,a,P0,s,S0,0 )
+# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+%}
+
+%%
+
+run : /* empty */
+ /* do nothing */
+ | rules
+ { parse_save( $1.parse ); }
+ ;
+
+/*
+ * block - zero or more rules
+ * rules - one or more rules
+ * rule - any one of jam's rules
+ * right-recursive so rules execute in order.
+ */
+
+block : /* empty */
+ { $$.parse = pnull(); }
+ | rules
+ { $$.parse = $1.parse; }
+ ;
+
+rules : rule
+ { $$.parse = $1.parse; }
+ | rule rules
+ { $$.parse = prules( $1.parse, $2.parse ); }
+ | LOCAL list assign_list_opt _SEMIC block
+ { $$.parse = plocal( $2.parse, $3.parse, $5.parse ); }
+ ;
+
+assign_list_opt : /* empty */
+ { $$.parse = pnull(); }
+ | _EQUALS list
+ { $$.parse = $2.parse; }
+ ;
+
+rule : _LBRACE block _RBRACE
+ { $$.parse = $2.parse; }
+ | INCLUDE list _SEMIC
+ { $$.parse = pincl( $2.parse ); }
+ | ARG lol _SEMIC
+ { $$.parse = prule( $1.string, $2.parse ); }
+ | arg assign list _SEMIC
+ { $$.parse = pset( $1.parse, $3.parse, $2.number ); }
+ | MODULE LOCAL list assign_list_opt _SEMIC
+ { $$.parse = psetmodule( $3.parse, $4.parse ); }
+ | arg ON list assign list _SEMIC
+ { $$.parse = pset1( $1.parse, $3.parse, $5.parse, $4.number ); }
+ | RETURN list _SEMIC
+ { $$.parse = $2.parse; }
+ | FOR ARG IN list _LBRACE block _RBRACE
+ { $$.parse = pfor( $2.string, $4.parse, $6.parse, 0 ); }
+ | FOR LOCAL ARG IN list _LBRACE block _RBRACE
+ { $$.parse = pfor( $3.string, $5.parse, $7.parse, 1 ); }
+ | SWITCH list _LBRACE cases _RBRACE
+ { $$.parse = pswitch( $2.parse, $4.parse ); }
+ | IF cond _LBRACE block _RBRACE
+ { $$.parse = pif( $2.parse, $4.parse, pnull() ); }
+ | MODULE list _LBRACE block _RBRACE
+ { $$.parse = pmodule( $2.parse, $4.parse ); }
+ | WHILE cond _LBRACE block _RBRACE
+ { $$.parse = pwhile( $2.parse, $4.parse ); }
+ | IF cond _LBRACE block _RBRACE ELSE rule
+ { $$.parse = pif( $2.parse, $4.parse, $7.parse ); }
+ | RULE ARG _LPAREN lol _RPAREN rule
+ { $$.parse = psetc_args( $2.string, $6.parse, $4.parse ); }
+ | RULE ARG rule
+ { $$.parse = psetc( $2.string, $3.parse ); }
+ | ACTIONS eflags ARG bindlist _LBRACE
+ { yymode( SCAN_STRING ); }
+ STRING
+ { yymode( SCAN_NORMAL ); }
+ _RBRACE
+ { $$.parse = psete( $3.string,$4.parse,$7.string,$2.number ); }
+ ;
+
+/*
+ * assign - = or +=
+ */
+
+assign : _EQUALS
+ { $$.number = ASSIGN_SET; }
+ | _PLUS_EQUALS
+ { $$.number = ASSIGN_APPEND; }
+ | _QUESTION_EQUALS
+ { $$.number = ASSIGN_DEFAULT; }
+ | DEFAULT _EQUALS
+ { $$.number = ASSIGN_DEFAULT; }
+ ;
+
+/*
+ * cond - a conditional for 'if'
+ */
+
+cond : arg
+ { $$.parse = pcnode( COND_EXISTS, $1.parse, pnull() ); }
+ | arg _EQUALS arg
+ { $$.parse = pcnode( COND_EQUALS, $1.parse, $3.parse ); }
+ | arg _BANG_EQUALS arg
+ { $$.parse = pcnode( COND_NOTEQ, $1.parse, $3.parse ); }
+ | arg _LANGLE arg
+ { $$.parse = pcnode( COND_LESS, $1.parse, $3.parse ); }
+ | arg _LANGLE_EQUALS arg
+ { $$.parse = pcnode( COND_LESSEQ, $1.parse, $3.parse ); }
+ | arg _RANGLE arg
+ { $$.parse = pcnode( COND_MORE, $1.parse, $3.parse ); }
+ | arg _RANGLE_EQUALS arg
+ { $$.parse = pcnode( COND_MOREEQ, $1.parse, $3.parse ); }
+ | arg IN list
+ { $$.parse = pcnode( COND_IN, $1.parse, $3.parse ); }
+ | _BANG cond
+ { $$.parse = pcnode( COND_NOT, $2.parse, P0 ); }
+ | cond _AMPERAMPER cond
+ { $$.parse = pcnode( COND_AND, $1.parse, $3.parse ); }
+ | cond _BARBAR cond
+ { $$.parse = pcnode( COND_OR, $1.parse, $3.parse ); }
+ | _LPAREN cond _RPAREN
+ { $$.parse = $2.parse; }
+ ;
+
+/*
+ * cases - action elements inside a 'switch'
+ * case - a single action element inside a 'switch'
+ * right-recursive rule so cases can be examined in order.
+ */
+
+cases : /* empty */
+ { $$.parse = P0; }
+ | case cases
+ { $$.parse = pnode( $1.parse, $2.parse ); }
+ ;
+
+case : CASE ARG _COLON block
+ { $$.parse = psnode( $2.string, $4.parse ); }
+ ;
+
+/*
+ * lol - list of lists
+ * right-recursive rule so that lists can be added in order.
+ */
+
+lol : list
+ { $$.parse = pnode( P0, $1.parse ); }
+ | list _COLON lol
+ { $$.parse = pnode( $3.parse, $1.parse ); }
+ ;
+
+/*
+ * list - zero or more args in a LIST
+ * listp - list (in puncutation only mode)
+ * arg - one ARG or function call
+ */
+
+list : listp
+ { $$.parse = $1.parse; yymode( SCAN_NORMAL ); }
+ ;
+
+listp : /* empty */
+ { $$.parse = pnull(); yymode( SCAN_PUNCT ); }
+ | listp arg
+ { $$.parse = pappend( $1.parse, $2.parse ); }
+ ;
+
+arg : ARG
+ { $$.parse = plist( $1.string ); }
+ | _LBRACKET ARG lol _RBRACKET
+ { $$.parse = prule( $2.string, $3.parse ); }
+ ;
+
+
+/*
+ * eflags - zero or more modifiers to 'executes'
+ * eflag - a single modifier to 'executes'
+ */
+
+eflags : /* empty */
+ { $$.number = 0; }
+ | eflags eflag
+ { $$.number = $1.number | $2.number; }
+ ;
+
+eflag : UPDATED
+ { $$.number = EXEC_UPDATED; }
+ | TOGETHER
+ { $$.number = EXEC_TOGETHER; }
+ | IGNORE
+ { $$.number = EXEC_IGNORE; }
+ | QUIETLY
+ { $$.number = EXEC_QUIETLY; }
+ | PIECEMEAL
+ { $$.number = EXEC_PIECEMEAL; }
+ | EXISTING
+ { $$.number = EXEC_EXISTING; }
+ ;
+
+
+/*
+ * bindlist - list of variable to bind for an action
+ */
+
+bindlist : /* empty */
+ { $$.parse = pnull(); }
+ | BIND list
+ { $$.parse = $2.parse; }
+ ;
+
+
diff --git a/historic/jam/src/jamgram.yy b/historic/jam/src/jamgram.yy
new file mode 100644
index 000000000..2ece67fae
--- /dev/null
+++ b/historic/jam/src/jamgram.yy
@@ -0,0 +1,287 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jamgram.yy - jam grammar
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ * 08/31/94 (seiwald) - Allow ?= as alias for "default =".
+ * 09/15/94 (seiwald) - if conditionals take only single arguments, so
+ * that 'if foo == bar' gives syntax error (use =).
+ * 02/11/95 (seiwald) - when scanning arguments to rules, only treat
+ * punctuation keywords as keywords. All arg lists
+ * are terminated with punctuation keywords.
+ *
+ * 09/11/00 (seiwald) - Support for function calls:
+ *
+ * Rules now return lists (LIST *), rather than void.
+ *
+ * New "[ rule ]" syntax evals rule into a LIST.
+ *
+ * Lists are now generated by compile_list() and
+ * compile_append(), and any other rule that indirectly
+ * makes a list, rather than being built directly here,
+ * so that lists values can contain rule evaluations.
+ *
+ * New 'return' rule sets the return value, though
+ * other statements also may have return values.
+ *
+ * 'run' production split from 'block' production so
+ * that empty blocks can be handled separately.
+ */
+
+%token ARG STRING
+
+%left `||`
+%left `&&`
+%left `!`
+
+%{
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "newstr.h"
+
+# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define P0 (PARSE *)0
+# define S0 (char *)0
+
+# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
+# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
+# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
+# define psetmodule( l,r ) parse_make( compile_set_module,l,r,P0,S0,S0,0 )
+# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
+# define psetc( s,p ) parse_make( compile_setcomp,p,P0,P0,s,S0,0 )
+# define psetc_args( s,p,a ) parse_make( compile_setcomp,p,a,P0,s,S0,0 )
+# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+%}
+
+%%
+
+run : /* empty */
+ /* do nothing */
+ | rules
+ { parse_save( $1.parse ); }
+ ;
+
+/*
+ * block - zero or more rules
+ * rules - one or more rules
+ * rule - any one of jam's rules
+ * right-recursive so rules execute in order.
+ */
+
+block : /* empty */
+ { $$.parse = pnull(); }
+ | rules
+ { $$.parse = $1.parse; }
+ ;
+
+rules : rule
+ { $$.parse = $1.parse; }
+ | rule rules
+ { $$.parse = prules( $1.parse, $2.parse ); }
+ | `local` list assign_list_opt `;` block
+ { $$.parse = plocal( $2.parse, $3.parse, $5.parse ); }
+ ;
+
+assign_list_opt : /* empty */
+ { $$.parse = pnull(); }
+ | `=` list
+ { $$.parse = $2.parse; }
+ ;
+
+rule : `{` block `}`
+ { $$.parse = $2.parse; }
+ | `include` list `;`
+ { $$.parse = pincl( $2.parse ); }
+ | ARG lol `;`
+ { $$.parse = prule( $1.string, $2.parse ); }
+ | arg assign list `;`
+ { $$.parse = pset( $1.parse, $3.parse, $2.number ); }
+ | `module` `local` list assign_list_opt `;`
+ { $$.parse = psetmodule( $3.parse, $4.parse ); }
+ | arg `on` list assign list `;`
+ { $$.parse = pset1( $1.parse, $3.parse, $5.parse, $4.number ); }
+ | `return` list `;`
+ { $$.parse = $2.parse; }
+ | `for` ARG `in` list `{` block `}`
+ { $$.parse = pfor( $2.string, $4.parse, $6.parse, 0 ); }
+ | `for` `local` ARG `in` list `{` block `}`
+ { $$.parse = pfor( $3.string, $5.parse, $7.parse, 1 ); }
+ | `switch` list `{` cases `}`
+ { $$.parse = pswitch( $2.parse, $4.parse ); }
+ | `if` cond `{` block `}`
+ { $$.parse = pif( $2.parse, $4.parse, pnull() ); }
+ | `module` list `{` block `}`
+ { $$.parse = pmodule( $2.parse, $4.parse ); }
+ | `while` cond `{` block `}`
+ { $$.parse = pwhile( $2.parse, $4.parse ); }
+ | `if` cond `{` block `}` `else` rule
+ { $$.parse = pif( $2.parse, $4.parse, $7.parse ); }
+ | `rule` ARG `(` lol `)` rule
+ { $$.parse = psetc_args( $2.string, $6.parse, $4.parse ); }
+ | `rule` ARG rule
+ { $$.parse = psetc( $2.string, $3.parse ); }
+ | `actions` eflags ARG bindlist `{`
+ { yymode( SCAN_STRING ); }
+ STRING
+ { yymode( SCAN_NORMAL ); }
+ `}`
+ { $$.parse = psete( $3.string,$4.parse,$7.string,$2.number ); }
+ ;
+
+/*
+ * assign - = or +=
+ */
+
+assign : `=`
+ { $$.number = ASSIGN_SET; }
+ | `+=`
+ { $$.number = ASSIGN_APPEND; }
+ | `?=`
+ { $$.number = ASSIGN_DEFAULT; }
+ | `default` `=`
+ { $$.number = ASSIGN_DEFAULT; }
+ ;
+
+/*
+ * cond - a conditional for 'if'
+ */
+
+cond : arg
+ { $$.parse = pcnode( COND_EXISTS, $1.parse, pnull() ); }
+ | arg `=` arg
+ { $$.parse = pcnode( COND_EQUALS, $1.parse, $3.parse ); }
+ | arg `!=` arg
+ { $$.parse = pcnode( COND_NOTEQ, $1.parse, $3.parse ); }
+ | arg `<` arg
+ { $$.parse = pcnode( COND_LESS, $1.parse, $3.parse ); }
+ | arg `<=` arg
+ { $$.parse = pcnode( COND_LESSEQ, $1.parse, $3.parse ); }
+ | arg `>` arg
+ { $$.parse = pcnode( COND_MORE, $1.parse, $3.parse ); }
+ | arg `>=` arg
+ { $$.parse = pcnode( COND_MOREEQ, $1.parse, $3.parse ); }
+ | arg `in` list
+ { $$.parse = pcnode( COND_IN, $1.parse, $3.parse ); }
+ | `!` cond
+ { $$.parse = pcnode( COND_NOT, $2.parse, P0 ); }
+ | cond `&&` cond
+ { $$.parse = pcnode( COND_AND, $1.parse, $3.parse ); }
+ | cond `||` cond
+ { $$.parse = pcnode( COND_OR, $1.parse, $3.parse ); }
+ | `(` cond `)`
+ { $$.parse = $2.parse; }
+ ;
+
+/*
+ * cases - action elements inside a 'switch'
+ * case - a single action element inside a 'switch'
+ * right-recursive rule so cases can be examined in order.
+ */
+
+cases : /* empty */
+ { $$.parse = P0; }
+ | case cases
+ { $$.parse = pnode( $1.parse, $2.parse ); }
+ ;
+
+case : `case` ARG `:` block
+ { $$.parse = psnode( $2.string, $4.parse ); }
+ ;
+
+/*
+ * lol - list of lists
+ * right-recursive rule so that lists can be added in order.
+ */
+
+lol : list
+ { $$.parse = pnode( P0, $1.parse ); }
+ | list `:` lol
+ { $$.parse = pnode( $3.parse, $1.parse ); }
+ ;
+
+/*
+ * list - zero or more args in a LIST
+ * listp - list (in puncutation only mode)
+ * arg - one ARG or function call
+ */
+
+list : listp
+ { $$.parse = $1.parse; yymode( SCAN_NORMAL ); }
+ ;
+
+listp : /* empty */
+ { $$.parse = pnull(); yymode( SCAN_PUNCT ); }
+ | listp arg
+ { $$.parse = pappend( $1.parse, $2.parse ); }
+ ;
+
+arg : ARG
+ { $$.parse = plist( $1.string ); }
+ | `[` ARG lol `]`
+ { $$.parse = prule( $2.string, $3.parse ); }
+ ;
+
+
+/*
+ * eflags - zero or more modifiers to 'executes'
+ * eflag - a single modifier to 'executes'
+ */
+
+eflags : /* empty */
+ { $$.number = 0; }
+ | eflags eflag
+ { $$.number = $1.number | $2.number; }
+ ;
+
+eflag : `updated`
+ { $$.number = EXEC_UPDATED; }
+ | `together`
+ { $$.number = EXEC_TOGETHER; }
+ | `ignore`
+ { $$.number = EXEC_IGNORE; }
+ | `quietly`
+ { $$.number = EXEC_QUIETLY; }
+ | `piecemeal`
+ { $$.number = EXEC_PIECEMEAL; }
+ | `existing`
+ { $$.number = EXEC_EXISTING; }
+ ;
+
+
+/*
+ * bindlist - list of variable to bind for an action
+ */
+
+bindlist : /* empty */
+ { $$.parse = pnull(); }
+ | `bind` list
+ { $$.parse = $2.parse; }
+ ;
+
+
diff --git a/historic/jam/src/jamgramtab.h b/historic/jam/src/jamgramtab.h
new file mode 100644
index 000000000..018555b93
--- /dev/null
+++ b/historic/jam/src/jamgramtab.h
@@ -0,0 +1,41 @@
+ { "!", _BANG },
+ { "!=", _BANG_EQUALS },
+ { "&&", _AMPERAMPER },
+ { "(", _LPAREN },
+ { ")", _RPAREN },
+ { "+=", _PLUS_EQUALS },
+ { ":", _COLON },
+ { ";", _SEMIC },
+ { "<", _LANGLE },
+ { "<=", _LANGLE_EQUALS },
+ { "=", _EQUALS },
+ { ">", _RANGLE },
+ { ">=", _RANGLE_EQUALS },
+ { "?=", _QUESTION_EQUALS },
+ { "[", _LBRACKET },
+ { "]", _RBRACKET },
+ { "actions", ACTIONS },
+ { "bind", BIND },
+ { "case", CASE },
+ { "default", DEFAULT },
+ { "else", ELSE },
+ { "existing", EXISTING },
+ { "for", FOR },
+ { "if", IF },
+ { "ignore", IGNORE },
+ { "in", IN },
+ { "include", INCLUDE },
+ { "local", LOCAL },
+ { "module", MODULE },
+ { "on", ON },
+ { "piecemeal", PIECEMEAL },
+ { "quietly", QUIETLY },
+ { "return", RETURN },
+ { "rule", RULE },
+ { "switch", SWITCH },
+ { "together", TOGETHER },
+ { "updated", UPDATED },
+ { "while", WHILE },
+ { "{", _LBRACE },
+ { "||", _BARBAR },
+ { "}", _RBRACE },
diff --git a/historic/jam/src/lists.c b/historic/jam/src/lists.c
new file mode 100644
index 000000000..919c71210
--- /dev/null
+++ b/historic/jam/src/lists.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "newstr.h"
+# include "lists.h"
+
+/*
+ * lists.c - maintain lists of strings
+ *
+ * This implementation essentially uses a singly linked list, but
+ * guarantees that the head element of every list has a valid pointer
+ * to the tail of the list, so the new elements can efficiently and
+ * properly be appended to the end of a list.
+ *
+ * To avoid massive allocation, list_free() just tacks the whole freed
+ * chain onto freelist and list_new() looks on freelist first for an
+ * available list struct. list_free() does not free the strings in the
+ * chain: it lazily lets list_new() do so.
+ *
+ * 08/23/94 (seiwald) - new list_append()
+ * 09/07/00 (seiwald) - documented lol_*() functions
+ */
+
+static LIST *freelist = 0; /* junkpile for list_free() */
+
+/*
+ * list_append() - append a list onto another one, returning total
+ */
+
+LIST *
+list_append(
+ LIST *l,
+ LIST *nl )
+{
+ if( !nl )
+ {
+ /* Just return l */
+ }
+ else if( !l )
+ {
+ l = nl;
+ }
+ else
+ {
+ /* Graft two non-empty lists. */
+ l->tail->next = nl;
+ l->tail = nl->tail;
+ }
+
+ return l;
+}
+
+/*
+ * list_new() - tack a string onto the end of a list of strings
+ */
+
+LIST *
+list_new(
+ LIST *head,
+ char *string )
+{
+ LIST *l;
+
+ if( DEBUG_LISTS )
+ printf( "list > %s <\n", string );
+
+ /* Get list struct from freelist, if one available. */
+ /* Otherwise allocate. */
+ /* If from freelist, must free string first */
+
+ if( freelist )
+ {
+ l = freelist;
+ freestr( l->string );
+ freelist = freelist->next;
+ }
+ else
+ {
+ l = (LIST *)malloc( sizeof( *l ) );
+ }
+
+ /* If first on chain, head points here. */
+ /* If adding to chain, tack us on. */
+ /* Tail must point to this new, last element. */
+
+ if( !head ) head = l;
+ else head->tail->next = l;
+ head->tail = l;
+ l->next = 0;
+
+ l->string = string;
+
+ return head;
+}
+
+/*
+ * list_copy() - copy a whole list of strings (nl) onto end of another (l)
+ */
+
+LIST *
+list_copy(
+ LIST *l,
+ LIST *nl )
+{
+ for( ; nl; nl = list_next( nl ) )
+ l = list_new( l, copystr( nl->string ) );
+
+ return l;
+}
+
+/*
+ * list_sublist() - copy a subset of a list of strings
+ */
+
+LIST *
+list_sublist(
+ LIST *l,
+ int start,
+ int count )
+{
+ LIST *nl = 0;
+
+ for( ; l && start--; l = list_next( l ) )
+ ;
+
+ for( ; l && count--; l = list_next( l ) )
+ nl = list_new( nl, copystr( l->string ) );
+
+ return nl;
+}
+
+/*
+ * list_free() - free a list of strings
+ */
+
+void
+list_free( LIST *head )
+{
+ /* Just tack onto freelist. */
+
+ if( head )
+ {
+ head->tail->next = freelist;
+ freelist = head;
+ }
+}
+
+/*
+ * list_print() - print a list of strings to stdout
+ */
+
+void
+list_print( LIST *l )
+{
+ for( ; l; l = list_next( l ) )
+ printf( "%s ", l->string );
+}
+
+/*
+ * list_length() - return the number of items in the list
+ */
+
+int
+list_length( LIST *l )
+{
+ int n = 0;
+
+ for( ; l; l = list_next( l ), ++n )
+ ;
+
+ return n;
+}
+
+/*
+ * lol_init() - initialize a LOL (list of lists)
+ */
+
+void
+lol_init( LOL *lol )
+{
+ lol->count = 0;
+}
+
+/*
+ * lol_add() - append a LIST onto an LOL
+ */
+
+void
+lol_add(
+ LOL *lol,
+ LIST *l )
+{
+ if( lol->count < LOL_MAX )
+ lol->list[ lol->count++ ] = l;
+}
+
+/*
+ * lol_free() - free the LOL and its LISTs
+ */
+
+void
+lol_free( LOL *lol )
+{
+ int i;
+
+ for( i = 0; i < lol->count; i++ )
+ list_free( lol->list[i] );
+
+ lol->count = 0;
+}
+
+/*
+ * lol_get() - return one of the LISTs in the LOL
+ */
+
+LIST *
+lol_get(
+ LOL *lol,
+ int i )
+{
+ return i < lol->count ? lol->list[i] : 0;
+}
+
+/*
+ * lol_print() - debug print LISTS separated by ":"
+ */
+
+void
+lol_print( LOL *lol )
+{
+ int i;
+
+ for( i = 0; i < lol->count; i++ )
+ {
+ if( i )
+ printf( " : " );
+ list_print( lol->list[i] );
+ }
+}
diff --git a/historic/jam/src/lists.h b/historic/jam/src/lists.h
new file mode 100644
index 000000000..4ed262f44
--- /dev/null
+++ b/historic/jam/src/lists.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * lists.h - the LIST structure and routines to manipulate them
+ *
+ * The whole of jam relies on lists of strings as a datatype. This
+ * module, in conjunction with newstr.c, handles these relatively
+ * efficiently.
+ *
+ * Structures defined:
+ *
+ * LIST - list of strings
+ * LOL - list of LISTs
+ *
+ * External routines:
+ *
+ * list_append() - append a list onto another one, returning total
+ * list_new() - tack a string onto the end of a list of strings
+ * list_copy() - copy a whole list of strings
+ * list_sublist() - copy a subset of a list of strings
+ * list_free() - free a list of strings
+ * list_print() - print a list of strings to stdout
+ * list_length() - return the number of items in the list
+ *
+ * lol_init() - initialize a LOL (list of lists)
+ * lol_add() - append a LIST onto an LOL
+ * lol_free() - free the LOL and its LISTs
+ * lol_get() - return one of the LISTs in the LOL
+ * lol_print() - debug print LISTS separated by ":"
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 08/23/94 (seiwald) - new list_append()
+ */
+
+#ifndef LISTS_DWA20011022_H
+# define LISTS_DWA20011022_H
+
+/*
+ * LIST - list of strings
+ */
+
+typedef struct _list LIST;
+
+struct _list {
+ LIST *next;
+ LIST *tail; /* only valid in head node */
+ char *string; /* private copy */
+} ;
+
+/*
+ * LOL - list of LISTs
+ */
+
+typedef struct _lol LOL;
+
+# define LOL_MAX 9
+
+struct _lol {
+ int count;
+ LIST *list[ LOL_MAX ];
+} ;
+
+LIST * list_append( LIST *l, LIST *nl );
+LIST * list_copy( LIST *l, LIST *nl );
+void list_free( LIST *head );
+LIST * list_new( LIST *head, char *string );
+void list_print( LIST *l );
+int list_length( LIST *l );
+LIST * list_sublist( LIST *l, int start, int count );
+
+# define list_next( l ) ((l)->next)
+
+# define L0 ((LIST *)0)
+
+void lol_add( LOL *lol, LIST *l );
+void lol_init( LOL *lol );
+void lol_free( LOL *lol );
+LIST * lol_get( LOL *lol, int i );
+void lol_print( LOL *lol );
+
+#endif // LISTS_DWA20011022_H
diff --git a/historic/jam/src/make.c b/historic/jam/src/make.c
new file mode 100644
index 000000000..13af6a053
--- /dev/null
+++ b/historic/jam/src/make.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * make.c - bring a target up to date, once rules are in place
+ *
+ * This modules controls the execution of rules to bring a target and
+ * its dependencies up to date. It is invoked after the targets, rules,
+ * et. al. described in rules.h are created by the interpreting of the
+ * jam files.
+ *
+ * This file contains the main make() entry point and the first pass
+ * make0(). The second pass, make1(), which actually does the command
+ * execution, is in make1.c.
+ *
+ * External routines:
+ * make() - make a target, given its name
+ *
+ * Internal routines:
+ * make0() - bind and scan everything to make a TARGET
+ *
+ * 12/26/93 (seiwald) - allow NOTIME targets to be expanded via $(<), $(>)
+ * 01/04/94 (seiwald) - print all targets, bounded, when tracing commands
+ * 04/08/94 (seiwald) - progress report now reflects only targets with actions
+ * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.
+ * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
+ * 12/20/94 (seiwald) - make0() headers after determining fate of target, so
+ * that headers aren't seen as dependents on themselves.
+ * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
+ * 02/02/95 (seiwald) - propagate leaf source time for new LEAVES rule.
+ * 02/14/95 (seiwald) - NOUPDATE rule means don't update existing target.
+ * 08/22/95 (seiwald) - NOUPDATE targets immune to anyhow (-a) flag.
+ * 09/06/00 (seiwald) - NOCARE affects targets with sources/actions.
+ * 03/02/01 (seiwald) - reverse NOCARE change.
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "rules.h"
+
+# include "search.h"
+# include "newstr.h"
+# include "make.h"
+# include "headers.h"
+# include "command.h"
+
+# ifndef max
+# define max( a,b ) ((a)>(b)?(a):(b))
+# endif
+
+typedef struct {
+ int temp;
+ int updating;
+ int cantfind;
+ int cantmake;
+ int targets;
+ int made;
+} COUNTS ;
+
+static void make0( TARGET *t, int pbinding, time_t ptime,
+ int depth, COUNTS *counts, int anyhow );
+
+static char *target_fate[] =
+{
+ "init", /* T_FATE_INIT */
+ "making", /* T_FATE_MAKING */
+ "stable", /* T_FATE_STABLE */
+ "newer", /* T_FATE_NEWER */
+ "temp", /* T_FATE_ISTMP */
+ "touched", /* T_FATE_TOUCHED */
+ "missing", /* T_FATE_MISSING */
+ "old", /* T_FATE_OUTDATED */
+ "update", /* T_FATE_UPDATE */
+ "nofind", /* T_FATE_CANTFIND */
+ "nomake" /* T_FATE_CANTMAKE */
+} ;
+
+static char *target_bind[] =
+{
+ "unbound",
+ "missing",
+ "parents",
+ "exists",
+} ;
+
+# define spaces(x) ( " " + ( x > 20 ? 0 : 20-x ) )
+
+/*
+ * make() - make a target, given its name
+ */
+
+int
+make(
+ int n_targets,
+ char **targets,
+ int anyhow )
+{
+ int i;
+ COUNTS counts[1];
+ int status = 0; /* 1 if anything fails */
+
+ memset( (char *)counts, 0, sizeof( *counts ) );
+
+ for( i = 0; i < n_targets; i++ )
+ {
+ TARGET *t = bindtarget( targets[i] );
+
+ make0( t, T_BIND_UNBOUND, (time_t)0, 0, counts, anyhow );
+ }
+
+ if( DEBUG_MAKE )
+ {
+ if( counts->targets )
+ printf( "...found %d target%s...\n", counts->targets,
+ counts->targets > 1 ? "s" : "" );
+ if( counts->temp )
+ printf( "...using %d temp target%s...\n", counts->temp,
+ counts->temp > 1 ? "s" : "" );
+ if( counts->updating )
+ printf( "...updating %d target%s...\n", counts->updating,
+ counts->updating > 1 ? "s" : "" );
+ if( counts->cantfind )
+ printf( "...can't find %d target%s...\n", counts->cantfind,
+ counts->cantfind > 1 ? "s" : "" );
+ if( counts->cantmake )
+ printf( "...can't make %d target%s...\n", counts->cantmake,
+ counts->cantmake > 1 ? "s" : "" );
+ }
+
+ status = counts->cantfind || counts->cantmake;
+
+ for( i = 0; i < n_targets; i++ )
+ status |= make1( bindtarget( targets[i] ) );
+
+ return status;
+}
+
+/*
+ * make0() - bind and scan everything to make a TARGET
+ *
+ * Make0() recursively binds a target, searches for #included headers,
+ * calls itself on those headers, and calls itself on any dependents.
+ */
+
+static void
+make0(
+ TARGET *t,
+ int pbinding, /* parent target's binding */
+ time_t ptime, /* parent target's timestamp */
+ int depth, /* for display purposes */
+ COUNTS *counts, /* for reporting */
+ int anyhow ) /* forcibly touch all (real) targets */
+{
+ TARGETS *c;
+ int fate, hfate;
+ time_t last, leaf, hlast, hleaf;
+ char *flag = "";
+
+ if( DEBUG_MAKEPROG )
+ printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+
+ /*
+ * Step 1: don't remake if already trying or tried
+ */
+
+ switch( t->fate )
+ {
+ case T_FATE_MAKING:
+ printf( "warning: %s depends on itself\n", t->name );
+ return;
+
+ /* Deal with TEMPORARY targets with multiple parents. When a missing
+ * TEMPORARY target is determined to be stable, it inherits the
+ * timestamp of the parent being checked, and is given a binding of
+ * T_BIND_PARENTS. To avoid outdating parents with earlier modification
+ * times, we set the target's time to the minimum time of all parents.
+ */
+ case T_FATE_STABLE:
+ if ( t->binding == T_BIND_PARENTS && t->time > ptime && t->flags & T_FLAG_TEMP )
+ t->time = ptime;
+ return;
+
+ default:
+ return;
+
+ case T_FATE_INIT:
+ break;
+ }
+
+ t->fate = T_FATE_MAKING;
+
+ /*
+ * Step 2: under the influence of "on target" variables,
+ * bind the target and search for headers.
+ */
+
+ /* Step 2a: set "on target" variables. */
+
+ pushsettings( t->settings );
+
+ /* Step 2b: find and timestamp the target file (if it's a file). */
+
+ if( t->binding == T_BIND_UNBOUND && !( t->flags & T_FLAG_NOTFILE ) )
+ {
+ t->boundname = search( t->name, &t->time );
+ t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
+ }
+
+ /* If temp file doesn't exist, use parent */
+
+ if( t->binding == T_BIND_MISSING && t->flags & T_FLAG_TEMP && ptime )
+ {
+ t->time = ptime;
+ t->binding = t->time ? T_BIND_PARENTS : T_BIND_MISSING;
+ }
+
+ /* Step 2c: If its a file, search for headers. */
+
+ if( t->binding == T_BIND_EXISTS )
+ headers( t );
+
+ /* Step 2d: reset "on target" variables */
+
+ popsettings( t->settings );
+
+ /*
+ * Pause for a little progress reporting
+ */
+
+ if( DEBUG_BIND )
+ {
+ if( strcmp( t->name, t->boundname ) )
+ {
+ printf( "bind\t--\t%s%s: %s\n",
+ spaces( depth ), t->name, t->boundname );
+ }
+
+ switch( t->binding )
+ {
+ case T_BIND_UNBOUND:
+ case T_BIND_MISSING:
+ case T_BIND_PARENTS:
+ printf( "time\t--\t%s%s: %s\n",
+ spaces( depth ), t->name, target_bind[ t->binding ] );
+ break;
+
+ case T_BIND_EXISTS:
+ printf( "time\t--\t%s%s: %s",
+ spaces( depth ), t->name, ctime( &t->time ) );
+ break;
+ }
+ }
+
+ /*
+ * Step 3: recursively make0() dependents
+ */
+
+ last = 0;
+ leaf = 0;
+ fate = T_FATE_STABLE;
+
+ for( c = t->deps[ T_DEPS_DEPENDS ]; c; c = c->next )
+ {
+ make0( c->target, t->binding, t->time, depth + 1, counts, anyhow );
+ leaf = max( leaf, c->target->leaf );
+ leaf = max( leaf, c->target->hleaf );
+
+ /* If LEAVES has been applied, we only heed the timestamps of */
+ /* the leaf source nodes. */
+
+ if( t->flags & T_FLAG_LEAVES )
+ {
+ last = leaf;
+ continue;
+ }
+
+ last = max( last, c->target->time );
+ last = max( last, c->target->htime );
+ fate = max( fate, c->target->fate );
+ fate = max( fate, c->target->hfate );
+ }
+
+ /* If a NOUPDATE file exists, make dependents eternally old. */
+
+ if( t->flags & T_FLAG_NOUPDATE )
+ {
+ last = 0;
+ t->time = 0;
+
+ /*
+ * Don't inherit our fate from our dependents. Decide fate
+ * based only upon other flags and our binding (done later).
+ */
+
+ fate = T_FATE_STABLE;
+ }
+
+ /* Step 3b: determine fate: rebuild target or what? */
+
+ /*
+ In English:
+ If can't find or make child, can't make target.
+ If children changed, make target.
+ If target missing, make it.
+ If children newer, make target.
+ If temp's children newer, make temp.
+ If deliberately touched, make it.
+ If up-to-date temp file present, use it.
+ If target exists but parent not, mark target newer.
+ If target newer than parent, mark target newer.
+ Don't propagate child's "newer" status.
+ */
+
+ if( fate >= T_FATE_BROKEN )
+ {
+ fate = T_FATE_CANTMAKE;
+ }
+ else if( fate >= T_FATE_SPOIL )
+ {
+ fate = T_FATE_UPDATE;
+ }
+ else if( t->binding == T_BIND_MISSING )
+ {
+ fate = T_FATE_MISSING;
+ }
+ else if( t->binding == T_BIND_EXISTS && last > t->time )
+ {
+ fate = T_FATE_OUTDATED;
+ }
+ else if( t->binding == T_BIND_PARENTS && last > t->time )
+ {
+ fate = T_FATE_OUTDATED;
+ }
+ else if( t->flags & T_FLAG_TOUCHED )
+ {
+ fate = T_FATE_TOUCHED;
+ }
+ else if( anyhow && !( t->flags & T_FLAG_NOUPDATE ) )
+ {
+ fate = T_FATE_TOUCHED;
+ }
+ else if( t->binding == T_BIND_EXISTS && t->flags & T_FLAG_TEMP )
+ {
+ fate = T_FATE_ISTMP;
+ }
+ else if( t->binding == T_BIND_EXISTS && pbinding == T_BIND_MISSING )
+ {
+ fate = T_FATE_NEWER;
+ }
+ else if( t->binding == T_BIND_EXISTS && ptime && t->time > ptime )
+ {
+ fate = T_FATE_NEWER;
+ }
+ else if( fate == T_FATE_NEWER )
+ {
+ fate = T_FATE_STABLE;
+ }
+
+ /* Step 3c: handle missing files */
+ /* If it's missing and there are no actions to create it, boom. */
+ /* If we can't make a target we don't care about, 'sokay */
+ /* We could insist that there are updating actions for all missing */
+ /* files, but if they have dependents we just pretend it's NOTFILE. */
+
+ if( fate == T_FATE_MISSING &&
+ !t->actions &&
+ !t->deps[ T_DEPS_DEPENDS ] )
+ {
+ if( t->flags & T_FLAG_NOCARE )
+ {
+ fate = T_FATE_STABLE;
+ }
+ else
+ {
+ printf( "don't know how to make %s\n", t->name );
+
+ fate = T_FATE_CANTFIND;
+ }
+ }
+
+ /* Step 3d: propagate dependents' time & fate. */
+ /* Set leaf time to be our time only if this is a leaf. */
+
+ t->time = max( t->time, last );
+ t->leaf = leaf ? leaf : t->time ;
+ t->fate = fate;
+
+ /*
+ * Step 4: Recursively make0() headers.
+ */
+
+ /* Step 4a: recursively make0() headers */
+
+ hlast = 0;
+ hleaf = 0;
+ hfate = T_FATE_STABLE;
+
+ for( c = t->deps[ T_DEPS_INCLUDES ]; c; c = c->next )
+ {
+ make0( c->target, pbinding, ptime, depth + 1, counts, anyhow );
+ hlast = max( hlast, c->target->time );
+ hlast = max( hlast, c->target->htime );
+ hleaf = max( hleaf, c->target->leaf );
+ hleaf = max( hleaf, c->target->hleaf );
+ hfate = max( hfate, c->target->fate );
+ hfate = max( hfate, c->target->hfate );
+ }
+
+ /* Step 4b: propagate dependents' time & fate. */
+
+ t->htime = hlast;
+ t->hleaf = hleaf ? hleaf : t->htime;
+ t->hfate = hfate;
+
+ /*
+ * Step 5: a little harmless tabulating for tracing purposes
+ */
+
+ if( !( ++counts->targets % 1000 ) && DEBUG_MAKE )
+ printf( "...patience...\n" );
+
+ if( fate == T_FATE_ISTMP )
+ counts->temp++;
+ else if( fate == T_FATE_CANTFIND )
+ counts->cantfind++;
+ else if( fate == T_FATE_CANTMAKE && t->actions )
+ counts->cantmake++;
+ else if( fate >= T_FATE_BUILD && fate < T_FATE_BROKEN && t->actions )
+ counts->updating++;
+
+ if( !( t->flags & T_FLAG_NOTFILE ) && fate >= T_FATE_SPOIL )
+ flag = "+";
+ else if( t->binding == T_BIND_EXISTS && ptime && t->time > ptime )
+ flag = "*";
+
+ if( DEBUG_MAKEPROG )
+ printf( "made%s\t%s\t%s%s\n",
+ flag, target_fate[ t->fate ],
+ spaces( depth ), t->name );
+}
+
diff --git a/historic/jam/src/make.h b/historic/jam/src/make.h
new file mode 100644
index 000000000..87ca86209
--- /dev/null
+++ b/historic/jam/src/make.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * make.h - bring a target up to date, once rules are in place
+ */
+
+int make( int n_targets, char **targets, int anyhow );
+int make1( TARGET *t );
diff --git a/historic/jam/src/make1.c b/historic/jam/src/make1.c
new file mode 100644
index 000000000..863adad37
--- /dev/null
+++ b/historic/jam/src/make1.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * make1.c - execute command to bring targets up to date
+ *
+ * This module contains make1(), the entry point called by make() to
+ * recursively decend the dependency graph executing update actions as
+ * marked by make0().
+ *
+ * External routines:
+ *
+ * make1() - execute commands to update a TARGET and all its dependents
+ *
+ * Internal routines, the recursive/asynchronous command executors:
+ *
+ * make1a() - recursively traverse target tree, calling make1b()
+ * make1b() - dependents of target built, now build target with make1c()
+ * make1c() - launch target's next command, call make1b() when done
+ * make1d() - handle command execution completion and call back make1c()
+ *
+ * Internal support routines:
+ *
+ * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
+ * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
+ * make1settings() - for vars that get bound values, build up replacement lists
+ * make1bind() - bind targets that weren't bound in dependency analysis
+ *
+ * 04/16/94 (seiwald) - Split from make.c.
+ * 04/21/94 (seiwald) - Handle empty "updated" actions.
+ * 05/04/94 (seiwald) - async multiprocess (-j) support
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
+ * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
+ * 01/22/94 (seiwald) - pass per-target JAMSHELL down to execcmd().
+ * 02/28/95 (seiwald) - Handle empty "existing" actions.
+ * 03/10/95 (seiwald) - Fancy counts.
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "rules.h"
+
+# include "search.h"
+# include "newstr.h"
+# include "make.h"
+# include "command.h"
+# include "execcmd.h"
+
+static void make1a( TARGET *t, TARGET *parent );
+static void make1b( TARGET *t );
+static void make1c( TARGET *t );
+static void make1d( void *closure, int status );
+
+static CMD *make1cmds( ACTIONS *a0 );
+static LIST *make1list( LIST *l, TARGETS *targets, int flags );
+static SETTINGS *make1settings( LIST *vars );
+static void make1bind( TARGET *t, int warn );
+
+/* Ugly static - it's too hard to carry it through the callbacks. */
+
+static struct {
+ int failed;
+ int skipped;
+ int total;
+ int made;
+} counts[1] ;
+
+/*
+ * make1() - execute commands to update a TARGET and all its dependents
+ */
+
+static int intr = 0;
+
+int
+make1( TARGET *t )
+{
+ memset( (char *)counts, 0, sizeof( *counts ) );
+
+ /* Recursively make the target and its dependents */
+
+ make1a( t, (TARGET *)0 );
+
+ /* Wait for any outstanding commands to finish running. */
+
+ while( execwait() )
+ ;
+
+ /* Talk about it */
+
+ if( DEBUG_MAKE && counts->failed )
+ printf( "...failed updating %d target%s...\n", counts->failed,
+ counts->failed > 1 ? "s" : "" );
+
+ if( DEBUG_MAKE && counts->skipped )
+ printf( "...skipped %d target%s...\n", counts->skipped,
+ counts->skipped > 1 ? "s" : "" );
+
+ if( DEBUG_MAKE && counts->made )
+ printf( "...updated %d target%s...\n", counts->made,
+ counts->made > 1 ? "s" : "" );
+
+ return counts->total != counts->made;
+}
+
+/*
+ * make1a() - recursively traverse target tree, calling make1b()
+ */
+
+static void
+make1a(
+ TARGET *t,
+ TARGET *parent )
+{
+ TARGETS *c;
+ int i;
+
+ /* If the parent is the first to try to build this target */
+ /* or this target is in the make1c() quagmire, arrange for the */
+ /* parent to be notified when this target is built. */
+
+ if( parent )
+ switch( t->progress )
+ {
+ case T_MAKE_INIT:
+ case T_MAKE_ACTIVE:
+ case T_MAKE_RUNNING:
+ t->parents = targetentry( t->parents, parent );
+ parent->asynccnt++;
+ }
+
+ if( t->progress != T_MAKE_INIT )
+ return;
+
+ /* Asynccnt counts the dependents preventing this target from */
+ /* proceeding to make1b() for actual building. We start off with */
+ /* a count of 1 to prevent anything from happening until we can */
+ /* call all dependents. This 1 is accounted for when we call */
+ /* make1b() ourselves, below. */
+
+ t->asynccnt = 1;
+
+ /* Recurse on our dependents, manipulating progress to guard */
+ /* against circular dependency. */
+
+ t->progress = T_MAKE_ONSTACK;
+
+ for( i = T_DEPS_DEPENDS; i <= T_DEPS_INCLUDES; i++ )
+ for( c = t->deps[i]; c && !intr; c = c->next )
+ make1a( c->target, t );
+
+ t->progress = T_MAKE_ACTIVE;
+
+ /* Now that all dependents have bumped asynccnt, we now allow */
+ /* decrement our reference to asynccnt. */
+
+ make1b( t );
+}
+
+/*
+ * make1b() - dependents of target built, now build target with make1c()
+ */
+
+static void
+make1b( TARGET *t )
+{
+ TARGETS *c;
+ int i;
+ char *failed = "dependents";
+
+ /* If any dependents are still outstanding, wait until they */
+ /* call make1b() to signal their completion. */
+
+ if( --t->asynccnt )
+ return;
+
+ /* Now ready to build target 't'... if dependents built ok. */
+
+ /* Collect status from dependents */
+
+ for( i = T_DEPS_DEPENDS; i <= T_DEPS_INCLUDES; i++ )
+ for( c = t->deps[i]; c; c = c->next )
+ if( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
+ {
+ failed = c->target->name;
+ t->status = c->target->status;
+ }
+
+ /* If actions on deps have failed, bail. */
+ /* Otherwise, execute all actions to make target */
+
+ if( t->status == EXEC_CMD_FAIL && t->actions )
+ {
+ ++counts->skipped;
+ printf( "...skipped %s for lack of %s...\n", t->name, failed );
+ }
+
+ if( t->status == EXEC_CMD_OK )
+ switch( t->fate )
+ {
+ case T_FATE_INIT:
+ case T_FATE_MAKING:
+ /* shouldn't happen */
+
+ case T_FATE_STABLE:
+ case T_FATE_NEWER:
+ break;
+
+ case T_FATE_CANTFIND:
+ case T_FATE_CANTMAKE:
+ t->status = EXEC_CMD_FAIL;
+ break;
+
+ case T_FATE_ISTMP:
+ if( DEBUG_MAKE )
+ printf( "...using %s...\n", t->name );
+ break;
+
+ case T_FATE_TOUCHED:
+ case T_FATE_MISSING:
+ case T_FATE_OUTDATED:
+ case T_FATE_UPDATE:
+ /* Set "on target" vars, build actions, unset vars */
+ /* Set "progress" so that make1c() counts this target among */
+ /* the successes/failures. */
+
+ if( t->actions )
+ {
+ ++counts->total;
+ if( DEBUG_MAKE && !( counts->total % 100 ) )
+ printf( "...on %dth target...\n", counts->total );
+
+ pushsettings( t->settings );
+ t->cmds = (char *)make1cmds( t->actions );
+ popsettings( t->settings );
+
+ t->progress = T_MAKE_RUNNING;
+ }
+
+ break;
+ }
+
+ /* Call make1c() to begin the execution of the chain of commands */
+ /* needed to build target. If we're not going to build target */
+ /* (because of dependency failures or because no commands need to */
+ /* be run) the chain will be empty and make1c() will directly */
+ /* signal the completion of target. */
+
+ make1c( t );
+}
+
+/*
+ * make1c() - launch target's next command, call make1b() when done
+ */
+
+static void
+make1c( TARGET *t )
+{
+ CMD *cmd = (CMD *)t->cmds;
+
+ /* If there are (more) commands to run to build this target */
+ /* (and we haven't hit an error running earlier comands) we */
+ /* launch the command with execcmd(). */
+
+ /* If there are no more commands to run, we collect the status */
+ /* from all the actions then report our completion to all the */
+ /* parents. */
+
+ if( cmd && t->status == EXEC_CMD_OK )
+ {
+ if( DEBUG_MAKE )
+ if( DEBUG_MAKEQ || ! ( cmd->rule->actions->flags & RULE_QUIETLY ) )
+ {
+ printf( "%s ", cmd->rule->name );
+ list_print( lol_get( &cmd->args, 0 ) );
+ printf( "\n" );
+ }
+
+ if( DEBUG_EXEC )
+ printf( "%s\n", cmd->buf );
+
+ if( globs.cmdout )
+ fprintf( globs.cmdout, "%s", cmd->buf );
+
+ if( globs.noexec )
+ {
+ make1d( t, EXEC_CMD_OK );
+ }
+ else
+ {
+ fflush( stdout );
+ execcmd( cmd->buf, make1d, t, cmd->shell );
+ }
+ }
+ else
+ {
+ TARGETS *c;
+ ACTIONS *actions;
+
+ /* Collect status from actions, and distribute it as well */
+
+ for( actions = t->actions; actions; actions = actions->next )
+ if( actions->action->status > t->status )
+ t->status = actions->action->status;
+
+ for( actions = t->actions; actions; actions = actions->next )
+ if( t->status > actions->action->status )
+ actions->action->status = t->status;
+
+ /* Tally success/failure for those we tried to update. */
+
+ if( t->progress == T_MAKE_RUNNING )
+ switch( t->status )
+ {
+ case EXEC_CMD_OK:
+ ++counts->made;
+ break;
+ case EXEC_CMD_FAIL:
+ ++counts->failed;
+ break;
+ }
+
+ /* Tell parents dependent has been built */
+
+ t->progress = T_MAKE_DONE;
+
+ for( c = t->parents; c; c = c->next )
+ make1b( c->target );
+ }
+}
+
+/*
+ * make1d() - handle command execution completion and call back make1c()
+ */
+
+static void
+make1d(
+ void *closure,
+ int status )
+{
+ TARGET *t = (TARGET *)closure;
+ CMD *cmd = (CMD *)t->cmds;
+
+ /* Execcmd() has completed. All we need to do is fiddle with the */
+ /* status and signal our completion so make1c() can run the next */
+ /* command. On interrupts, we bail heavily. */
+
+ if ( t->flags & T_FLAG_FAIL_EXPECTED )
+ {
+ /* invert execution result when FAIL_EXPECTED was applied */
+ switch (status)
+ {
+ case EXEC_CMD_FAIL: status = EXEC_CMD_OK; break;
+ case EXEC_CMD_OK: status = EXEC_CMD_FAIL; break;
+ default:
+ ;
+ }
+ }
+
+ if( status == EXEC_CMD_FAIL && ( cmd->rule->actions->flags & RULE_IGNORE ) )
+ status = EXEC_CMD_OK;
+
+ /* On interrupt, set intr so _everything_ fails */
+
+ if( status == EXEC_CMD_INTR )
+ ++intr;
+
+ if( status == EXEC_CMD_FAIL && DEBUG_MAKE )
+ {
+ /* Print command text on failure */
+
+ if( !DEBUG_EXEC )
+ printf( "%s\n", cmd->buf );
+
+ printf( "...failed %s ", cmd->rule->name );
+ list_print( lol_get( &cmd->args, 0 ) );
+ printf( "...\n" );
+ }
+
+ /* If the command was interrupted or failed and the target */
+ /* is not "precious", remove the targets */
+
+ if( status != EXEC_CMD_OK && !( cmd->rule->actions->flags & RULE_TOGETHER ) )
+ {
+ LIST *targets = lol_get( &cmd->args, 0 );
+
+ for( ; targets; targets = list_next( targets ) )
+ if( !unlink( targets->string ) )
+ printf( "...removing %s\n", targets->string );
+ }
+
+ /* Free this command and call make1c() to move onto next command. */
+
+ t->status = status;
+ t->cmds = (char *)cmd_next( cmd );
+
+ cmd_free( cmd );
+
+ make1c( t );
+}
+
+/*
+ * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
+ *
+ * Essentially copies a chain of ACTIONs to a chain of CMDs,
+ * grouping RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions,
+ * and handling RULE_NEWSRCS actions. The result is a chain of
+ * CMDs which can be expanded by var_string() and executed with
+ * execcmd().
+ */
+
+static CMD *
+make1cmds( ACTIONS *a0 )
+{
+ CMD *cmds = 0;
+ LIST *shell = var_get( "JAMSHELL" ); /* shell is per-target */
+
+ /* Step through actions */
+ /* Actions may be shared with other targets or grouped with */
+ /* RULE_TOGETHER, so actions already seen are skipped. */
+
+ for( ; a0; a0 = a0->next )
+ {
+ RULE *rule = a0->action->rule;
+ rule_actions *actions = rule->actions;
+ SETTINGS *boundvars;
+ LIST *nt, *ns;
+ ACTIONS *a1;
+ CMD *cmd;
+ int start, chunk, length;
+
+ /* Only do rules with commands to execute. */
+ /* If this action has already been executed, use saved status */
+
+ if( !actions || a0->action->running )
+ continue;
+
+ a0->action->running = 1;
+
+ /* Make LISTS of targets and sources */
+ /* If `execute together` has been specified for this rule, tack */
+ /* on sources from each instance of this rule for this target. */
+
+ nt = make1list( L0, a0->action->targets, 0 );
+ ns = make1list( L0, a0->action->sources, actions->flags );
+
+ if( actions->flags & RULE_TOGETHER )
+ for( a1 = a0->next; a1; a1 = a1->next )
+ if( a1->action->rule == rule && !a1->action->running )
+ {
+ ns = make1list( ns, a1->action->sources, actions->flags );
+ a1->action->running = 1;
+ }
+
+ /* If doing only updated (or existing) sources, but none have */
+ /* been updated (or exist), skip this action. */
+
+ if( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
+ {
+ list_free( nt );
+ continue;
+ }
+
+ /* If we had 'actions xxx bind vars' we bind the vars now */
+
+ boundvars = make1settings( actions->bindlist );
+ pushsettings( boundvars );
+
+ /*
+ * Build command, starting with all source args.
+ *
+ * If cmd_new returns 0, it's because the resulting command
+ * length is > MAXLINE. In this case, we'll slowly reduce
+ * the number of source arguments presented until it does
+ * fit. This only applies to actions that allow PIECEMEAL
+ * commands.
+ *
+ * While reducing slowly takes a bit of compute time to get
+ * things just right, it's worth it to get as close to MAXLINE
+ * as possible, because launching the commands we're executing
+ * is likely to be much more compute intensive!
+ *
+ * Note we loop through at least once, for sourceless actions.
+ */
+
+ start = 0;
+ chunk = length = list_length( ns );
+
+ do
+ {
+ /* Build cmd: cmd_new consumes its lists. */
+
+ CMD *cmd = cmd_new( rule,
+ list_copy( L0, nt ),
+ list_sublist( ns, start, chunk ),
+ list_copy( L0, shell ) );
+
+ if( cmd )
+ {
+ /* It fit: chain it up. */
+
+ if( !cmds ) cmds = cmd;
+ else cmds->tail->next = cmd;
+ cmds->tail = cmd;
+ start += chunk;
+ }
+ else if( ( actions->flags & RULE_PIECEMEAL ) && chunk > 1 )
+ {
+ /* Reduce chunk size slowly. */
+
+ chunk = chunk * 9 / 10;
+ }
+ else
+ {
+ /* Too long and not splittable. */
+
+ printf( "%s actions too long (max %d)!\n",
+ rule->name, MAXLINE );
+ exit( EXITBAD );
+ }
+ }
+ while( start < length );
+
+ /* These were always copied when used. */
+
+ list_free( nt );
+ list_free( ns );
+
+ /* Free the variables whose values were bound by */
+ /* 'actions xxx bind vars' */
+
+ popsettings( boundvars );
+ freesettings( boundvars );
+ }
+
+ return cmds;
+}
+
+/*
+ * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
+ */
+
+static LIST *
+make1list(
+ LIST *l,
+ TARGETS *targets,
+ int flags )
+{
+ for( ; targets; targets = targets->next )
+ {
+ TARGET *t = targets->target;
+
+ /* Sources to 'actions existing' are never in the dependency */
+ /* graph (if they were, they'd get built and 'existing' would */
+ /* be superfluous, so throttle warning message about independent */
+ /* targets. */
+
+ if( t->binding == T_BIND_UNBOUND )
+ make1bind( t, !( flags & RULE_EXISTING ) );
+
+ if( ( flags & RULE_EXISTING ) && t->binding != T_BIND_EXISTS )
+ continue;
+
+ if( ( flags & RULE_NEWSRCS ) && t->fate <= T_FATE_STABLE )
+ continue;
+
+ /* Prohibit duplicates for RULE_TOGETHER */
+
+ if( flags & RULE_TOGETHER )
+ {
+ LIST *m;
+
+ for( m = l; m; m = m->next )
+ if( !strcmp( m->string, t->boundname ) )
+ break;
+
+ if( m )
+ continue;
+ }
+
+ /* Build new list */
+
+ l = list_new( l, copystr( t->boundname ) );
+ }
+
+ return l;
+}
+
+/*
+ * make1settings() - for vars that get bound values, build up replacement lists
+ */
+
+static SETTINGS *
+make1settings( LIST *vars )
+{
+ SETTINGS *settings = 0;
+
+ for( ; vars; vars = list_next( vars ) )
+ {
+ LIST *l = var_get( vars->string );
+ LIST *nl = 0;
+
+ for( ; l; l = list_next( l ) )
+ {
+ TARGET *t = bindtarget( l->string );
+
+ /* Make sure the target is bound, warning if it is not in the */
+ /* dependency graph. */
+
+ if( t->binding == T_BIND_UNBOUND )
+ make1bind( t, 1 );
+
+ /* Build new list */
+
+ nl = list_new( nl, copystr( t->boundname ) );
+ }
+
+ /* Add to settings chain */
+
+ settings = addsettings( settings, 0, vars->string, nl );
+ }
+
+ return settings;
+}
+
+/*
+ * make1bind() - bind targets that weren't bound in dependency analysis
+ *
+ * Spot the kludge! If a target is not in the dependency tree, it didn't
+ * get bound by make0(), so we have to do it here. Ugly.
+ */
+
+static void
+make1bind(
+ TARGET *t,
+ int warn )
+{
+ if( t->flags & T_FLAG_NOTFILE )
+ return;
+
+ /* Sources to 'actions existing' are never in the dependency */
+ /* graph (if they were, they'd get built and 'existing' would */
+ /* be superfluous, so throttle warning message about independent */
+ /* targets. */
+
+ if( warn )
+ printf( "warning: using independent target %s\n", t->name );
+
+ pushsettings( t->settings );
+ t->boundname = search( t->name, &t->time );
+ t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
+ popsettings( t->settings );
+}
diff --git a/historic/jam/src/makecygwindebugjam.bat b/historic/jam/src/makecygwindebugjam.bat
new file mode 100755
index 000000000..bc34fb5fb
--- /dev/null
+++ b/historic/jam/src/makecygwindebugjam.bat
@@ -0,0 +1,4 @@
+set VISUALC=c:\tools\msvc6\vc98
+set JAM_TOOLSET=VISUALC
+rm -rf bin.ntx86
+make -fbuilds/win32-gcc.mk CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd" YACC="bison -t -d -l -v --yacc" LINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" LINKFLAGS="/DEBUG" %*
diff --git a/historic/jam/src/makedebugjam.bat b/historic/jam/src/makedebugjam.bat
new file mode 100755
index 000000000..f855b437d
--- /dev/null
+++ b/historic/jam/src/makedebugjam.bat
@@ -0,0 +1,5 @@
+set VISUALC=c:\tools\msvc6\vc98
+set JAM_TOOLSET=VISUALC
+rm -rf bin.ntx86
+mkdir bin.ntx86
+nmake -fbuilds/win32-visualc.mk JAMBASE= BOOST_ROOT= BOOST_BUILD_PATH= CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd" LINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" LINKFLAGS="/DEBUG" YACC="bison -t -d -l -v --debug --yacc" YACCFILES="y.tab" %*
diff --git a/historic/jam/src/makedebugjam.sh b/historic/jam/src/makedebugjam.sh
new file mode 100644
index 000000000..b4dfed0af
--- /dev/null
+++ b/historic/jam/src/makedebugjam.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+./yyacc jamgram.y jamgramtab.h jamgram.yy
+export VISUALC=c:\tools\msvc6\vc98
+export JAM_TOOLSET=VISUALC
+rm -rf bin.ntx86
+nmake -fbuilds/win32-visualc.mk CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd" YACC="bison -t -d -l -v --debug --yacc" LINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" LINKFLAGS="/DEBUG"
diff --git a/historic/jam/src/mkjambase.c b/historic/jam/src/mkjambase.c
new file mode 100644
index 000000000..c856356ef
--- /dev/null
+++ b/historic/jam/src/mkjambase.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * mkjambase.c - turn Jambase into a big C structure
+ *
+ * Usage: mkjambase jambase.c Jambase ...
+ *
+ * Results look like this:
+ *
+ * char *jambase[] = {
+ * "...\n",
+ * ...
+ * 0 };
+ *
+ * Handles \'s and "'s specially; knows to delete blank and comment lines.
+ *
+ */
+
+# include
+# include
+
+int main( int argc, char **argv, char **envp )
+{
+ char buf[ 1024 ];
+ FILE *fin;
+ FILE *fout;
+ char *p;
+ int doDotC = 0;
+
+ if( argc < 3 )
+ {
+ fprintf( stderr, "usage: %s jambase.c Jambase ...\n", argv[0] );
+ return -1;
+ }
+
+ if( !( fout = fopen( argv[1], "w" ) ) )
+ {
+ perror( argv[1] );
+ return -1;
+ }
+
+ /* If the file ends in .c generate a C source file */
+
+ if( ( p = strrchr( argv[1], '.' ) ) && !strcmp( p, ".c" ) )
+ doDotC++;
+
+ /* Now process the files */
+
+ argc -= 2, argv += 2;
+
+ if( doDotC )
+ {
+ fprintf( fout, "/* Generated by mkjambase from Jambase */\n" );
+ fprintf( fout, "char *jambase[] = {\n" );
+ }
+
+ for( ; argc--; argv++ )
+ {
+ if( !( fin = fopen( *argv, "r" ) ) )
+ {
+ perror( *argv );
+ return -1;
+ }
+
+ if( doDotC )
+ {
+ fprintf( fout, "/* %s */\n", *argv );
+ }
+ else
+ {
+ fprintf( fout, "### %s ###\n", *argv );
+ }
+
+ while( fgets( buf, sizeof( buf ), fin ) )
+ {
+ if( doDotC )
+ {
+ char *p = buf;
+
+ /* Strip leading whitespace. */
+
+ while( *p == ' ' || *p == '\t' || *p == '\n' )
+ p++;
+
+ /* Drop comments and empty lines. */
+
+ if( *p == '#' || !*p )
+ continue;
+
+ /* Copy */
+
+ putc( '"', fout );
+
+ for( ; *p && *p != '\n'; p++ )
+ switch( *p )
+ {
+ case '\\': putc( '\\', fout ); putc( '\\', fout ); break;
+ case '"': putc( '\\', fout ); putc( '"', fout ); break;
+ case '\r': break;
+ default: putc( *p, fout ); break;
+ }
+
+ fprintf( fout, "\\n\",\n" );
+ }
+ else
+ {
+ fprintf( fout, "%s", buf );
+ }
+
+ }
+
+ fclose( fin );
+ }
+
+ if( doDotC )
+ fprintf( fout, "0 };\n" );
+
+ fclose( fout );
+
+ return 0;
+}
diff --git a/historic/jam/src/modules.c b/historic/jam/src/modules.c
new file mode 100644
index 000000000..fef81e3e7
--- /dev/null
+++ b/historic/jam/src/modules.c
@@ -0,0 +1,95 @@
+/* (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
+ * distribute this software is granted provided this copyright notice appears
+ * in all copies. This software is provided "as is" without express or implied
+ * warranty, and with no claim as to its suitability for any purpose.
+ */
+#include "modules.h"
+#include "jam.h"
+#include "string.h"
+#include "hash.h"
+#include "newstr.h"
+#include "lists.h"
+#include "parse.h"
+#include "rules.h"
+#include "variable.h"
+#include "strings.h"
+
+static struct hash* module_hash = 0;
+
+static char* new_module_str( module* m, char* suffix )
+{
+ char* result;
+ string s;
+ string_copy( &s, m->name );
+ string_append( &s, suffix );
+ result = newstr( s.value );
+ string_free( &s );
+ return result;
+}
+
+module* bindmodule( char* name )
+{
+ string s;
+ module m_, *m = &m_;
+
+ if( !module_hash )
+ module_hash = hashinit( sizeof( module ), "modules" );
+
+ string_new( &s );
+ if (name)
+ {
+ string_append( &s, name );
+ string_push_back( &s, '.' );
+ }
+
+ m->name = s.value;
+
+ if ( hashenter( module_hash, (HASHDATA **)&m ) )
+ {
+ m->name = newstr( m->name );
+ m->local_names = 0;
+ m->locals = 0;
+ m->rules = hashinit( sizeof( RULE ), new_module_str( m, "rules" ) );
+ }
+ string_free( &s );
+ return m;
+}
+
+module* root_module()
+{
+ static module* root = 0;
+ if ( !root )
+ root = bindmodule(0);
+ return root;
+}
+
+/*
+ * bind_module_var --
+ *
+ * Add the symbol to the module's list of symbols if it is not already in the
+ * module. m is assumed to be the current module and if the symbol is new, any
+ * current value is replaced by an empty list until the module is exited.
+ *
+ */
+void bind_module_var( module* m, char* symbol )
+{
+ char** name = &symbol;
+
+ if ( !m->local_names )
+ m->local_names = hashinit( sizeof( char* ), new_module_str( m, "variables" ) );
+
+ if ( hashenter( m->local_names, (HASHDATA **)&name ) )
+ {
+ m->locals = addsettings( m->locals, 0, symbol, var_swap( symbol, 0 ) );
+ }
+}
+
+void enter_module( module* m )
+{
+ pushsettings( m->locals );
+}
+
+void exit_module( module* m )
+{
+ popsettings( m->locals );
+}
diff --git a/historic/jam/src/modules.h b/historic/jam/src/modules.h
new file mode 100644
index 000000000..06b30fbb8
--- /dev/null
+++ b/historic/jam/src/modules.h
@@ -0,0 +1,25 @@
+/* (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
+ * distribute this software is granted provided this copyright notice appears
+ * in all copies. This software is provided "as is" without express or implied
+ * warranty, and with no claim as to its suitability for any purpose.
+ */
+#ifndef MODULES_DWA10182001_H
+# define MODULES_DWA10182001_H
+
+struct module
+{
+ char* name;
+ struct hash* rules;
+ struct hash* local_names;
+ struct _settings* locals;
+};
+
+typedef struct module module; /* MSVC debugger gets confused unless this is provided */
+
+module* bindmodule( char* name );
+module* root_module();
+void bind_module_var( module*, char* name );
+void enter_module( module* );
+void exit_module( module* );
+
+#endif // MODULES_DWA10182001_H
diff --git a/historic/jam/src/newstr.c b/historic/jam/src/newstr.c
new file mode 100644
index 000000000..470f2a9a0
--- /dev/null
+++ b/historic/jam/src/newstr.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "newstr.h"
+# include "hash.h"
+
+/*
+ * newstr.c - string manipulation routines
+ *
+ * To minimize string copying, string creation, copying, and freeing
+ * is done through newstr.
+ *
+ * External functions:
+ *
+ * newstr() - return a malloc'ed copy of a string
+ * copystr() - return a copy of a string previously returned by newstr()
+ * freestr() - free a string returned by newstr() or copystr()
+ * donestr() - free string tables
+ *
+ * Once a string is passed to newstr(), the returned string is readonly.
+ *
+ * This implementation builds a hash table of all strings, so that multiple
+ * calls of newstr() on the same string allocate memory for the string once.
+ * Strings are never actually freed.
+ */
+
+typedef char *STRING;
+
+static struct hash *strhash = 0;
+static int strtotal = 0;
+
+/*
+ * newstr() - return a malloc'ed copy of a string
+ */
+
+char *
+newstr( char *string )
+{
+ STRING str, *s = &str;
+
+ if( !strhash )
+ strhash = hashinit( sizeof( STRING ), "strings" );
+
+ *s = string;
+
+ if( hashenter( strhash, (HASHDATA **)&s ) )
+ {
+ int l = strlen( string );
+ char *m = (char *)malloc( l + 1 );
+
+ strtotal += l + 1;
+ memcpy( m, string, l + 1 );
+ *s = m;
+ }
+
+ return *s;
+}
+
+/*
+ * copystr() - return a copy of a string previously returned by newstr()
+ */
+
+char *
+copystr( char *s )
+{
+ return s;
+}
+
+/*
+ * freestr() - free a string returned by newstr() or copystr()
+ */
+
+void
+freestr( char *s )
+{
+}
+
+/*
+ * donestr() - free string tables
+ */
+
+void
+donestr()
+{
+ hashdone( strhash );
+
+ if( DEBUG_MEM )
+ printf( "%dK in strings\n", strtotal / 1024 );
+}
diff --git a/historic/jam/src/newstr.h b/historic/jam/src/newstr.h
new file mode 100644
index 000000000..cf2dd34b7
--- /dev/null
+++ b/historic/jam/src/newstr.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * newstr.h - string manipulation routines
+ */
+
+char *newstr( char *string );
+char *copystr( char *s );
+void freestr( char *s );
+void donestr();
diff --git a/historic/jam/src/option.c b/historic/jam/src/option.c
new file mode 100644
index 000000000..e4491523c
--- /dev/null
+++ b/historic/jam/src/option.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "option.h"
+
+/*
+ * option.c - command line option processing
+ *
+ * {o >o
+ * \<>) "Process command line options as defined in .
+ * Return the number of argv[] elements used up by options,
+ * or -1 if an invalid option flag was given or an argument
+ * was supplied for an option that does not require one."
+ */
+
+int
+getoptions(
+ int argc,
+ char **argv,
+ char *opts,
+ option *optv )
+{
+ int i;
+ int optc = N_OPTS;
+
+ memset( (char *)optv, '\0', sizeof( *optv ) * N_OPTS );
+
+ for( i = 0; i < argc; i++ )
+ {
+ char *arg;
+
+ if( argv[i][0] != '-' || !isalpha( argv[i][1] ) )
+ break;
+
+ if( !optc-- )
+ {
+ printf( "too many options (%d max)\n", N_OPTS );
+ return -1;
+ }
+
+ for( arg = &argv[i][1]; *arg; arg++ )
+ {
+ char *f;
+
+ for( f = opts; *f; f++ )
+ if( *f == *arg )
+ break;
+
+ if( !*f )
+ {
+ printf( "Invalid option: -%c\n", *arg );
+ return -1;
+ }
+
+ optv->flag = *f;
+
+ if( f[1] != ':' )
+ {
+ optv++->val = "true";
+ }
+ else if( arg[1] )
+ {
+ optv++->val = &arg[1];
+ break;
+ }
+ else if( ++i < argc )
+ {
+ optv++->val = argv[i];
+ break;
+ }
+ else
+ {
+ printf( "option: -%c needs argument\n", *f );
+ return -1;
+ }
+ }
+ }
+
+ return i;
+}
+
+/*
+ * Name: getoptval() - find an option given its character
+ */
+
+char *
+getoptval(
+ option *optv,
+ char opt,
+ int subopt )
+{
+ int i;
+
+ for( i = 0; i < N_OPTS; i++, optv++ )
+ if( optv->flag == opt && !subopt-- )
+ return optv->val;
+
+ return 0;
+}
diff --git a/historic/jam/src/option.h b/historic/jam/src/option.h
new file mode 100644
index 000000000..657a763a0
--- /dev/null
+++ b/historic/jam/src/option.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * option.h - command line option processing
+ *
+ * {o >o
+ * \ -) "Command line option."
+ */
+
+typedef struct option
+{
+ char flag; /* filled in by getoption() */
+ char *val; /* set to random address if true */
+} option;
+
+# define N_OPTS 256
+
+int getoptions( int argc, char **argv, char *opts, option *optv );
+char * getoptval( option *optv, char opt, int subopt );
diff --git a/historic/jam/src/parse.c b/historic/jam/src/parse.c
new file mode 100644
index 000000000..931873543
--- /dev/null
+++ b/historic/jam/src/parse.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "scan.h"
+# include "newstr.h"
+# include "modules.h"
+# include "frames.h"
+
+/*
+ * parse.c - make and destroy parse trees as driven by the parser
+ *
+ * 09/07/00 (seiwald) - ref count on PARSE to avoid freeing when used,
+ * as per Matt Armstrong.
+ * 09/11/00 (seiwald) - structure reworked to reflect that (*func)()
+ * returns a LIST *.
+ */
+
+static PARSE *yypsave;
+
+void
+parse_file( char *f, FRAME* frame )
+{
+ /* Suspend scan of current file */
+ /* and push this new file in the stream */
+
+ yyfparse(f);
+
+ /* Now parse each block of rules and execute it. */
+ /* Execute it outside of the parser so that recursive */
+ /* calls to yyrun() work (no recursive yyparse's). */
+
+ for(;;)
+ {
+ PARSE *p;
+
+ /* Filled by yyparse() calling parse_save() */
+
+ yypsave = 0;
+
+ /* If parse error or empty parse, outta here */
+
+ if( yyparse() || !( p = yypsave ) )
+ break;
+
+ /* Run the parse tree. */
+
+ (*(p->func))( p, frame );
+
+ parse_free( p );
+ }
+}
+
+void
+parse_save( PARSE *p )
+{
+ yypsave = p;
+}
+
+PARSE *
+parse_make(
+ LIST *(*func)( PARSE *p, FRAME *args ),
+ PARSE *left,
+ PARSE *right,
+ PARSE *third,
+ char *string,
+ char *string1,
+ int num )
+{
+ PARSE *p = (PARSE *)malloc( sizeof( PARSE ) );
+
+ p->func = func;
+ p->left = left;
+ p->right = right;
+ p->third = third;
+ p->string = string;
+ p->string1 = string1;
+ p->num = num;
+ p->refs = 1;
+ p->module = 0;
+ p->rulename = 0;
+
+ return p;
+}
+
+void
+parse_refer( PARSE *p )
+{
+ ++p->refs;
+}
+
+void
+parse_free( PARSE *p )
+{
+ if( --p->refs )
+ return;
+
+ if( p->string )
+ freestr( p->string );
+ if( p->string1 )
+ freestr( p->string1 );
+ if( p->left )
+ parse_free( p->left );
+ if( p->right )
+ parse_free( p->right );
+ if( p->third )
+ parse_free( p->third );
+ if ( p->rulename )
+ freestr( p->rulename );
+
+ free( (char *)p );
+}
diff --git a/historic/jam/src/parse.h b/historic/jam/src/parse.h
new file mode 100644
index 000000000..3cb91f489
--- /dev/null
+++ b/historic/jam/src/parse.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+#ifndef PARSE_DWA20011020_H
+# define PARSE_DWA20011020_H
+# include "frames.h"
+# include "modules.h"
+
+/*
+ * parse.h - make and destroy parse trees as driven by the parser
+ */
+
+/*
+ * parse tree node
+ */
+
+typedef struct _PARSE PARSE;
+
+struct _PARSE {
+ LIST *(*func)( PARSE *p, FRAME *frame );
+ PARSE *left;
+ PARSE *right;
+ PARSE *third;
+ char *string;
+ char *string1;
+ int num;
+ int refs;
+ module* module;
+ char* rulename;
+} ;
+
+void parse_file( char *f, FRAME* frame );
+void parse_save( PARSE *p );
+
+PARSE * parse_make(
+ LIST *(*func)( PARSE *p, FRAME* frame ),
+ PARSE *left,
+ PARSE *right,
+ PARSE *third,
+ char *string,
+ char *string1,
+ int num );
+
+void parse_refer( PARSE *p );
+void parse_free( PARSE *p );
+
+#endif // PARSE_DWA20011020_H
diff --git a/historic/jam/src/patchlevel.h b/historic/jam/src/patchlevel.h
new file mode 100644
index 000000000..0d0af9597
--- /dev/null
+++ b/historic/jam/src/patchlevel.h
@@ -0,0 +1,5 @@
+/* Keep JAMVERSYM in sync with VERSION. */
+/* It can be accessed as $(JAMVERSION) in the Jamfile. */
+
+#define VERSION "2.3.2"
+#define JAMVERSYM "JAMVERSION=2.3"
diff --git a/historic/jam/src/pathmac.c b/historic/jam/src/pathmac.c
new file mode 100644
index 000000000..a4292f0a3
--- /dev/null
+++ b/historic/jam/src/pathmac.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+# ifdef OS_MAC
+
+# define DELIM ':'
+
+/*
+ * pathunix.c - manipulate file names on UNIX, NT, OS2
+ *
+ * External routines:
+ *
+ * file_parse() - split a file name into dir/base/suffix/member
+ * file_build() - build a filename given dir/base/suffix/member
+ * file_parent() - make a FILENAME point to its parent dir
+ *
+ * File_parse() and file_build() just manipuate a string and a structure;
+ * they do not make system calls.
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 12/26/93 (seiwald) - handle dir/.suffix properly in file_build()
+ * 12/19/94 (mikem) - solaris string table insanity support
+ * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
+ * 02/14/95 (seiwald) - parse and build /xxx properly
+ * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
+ * should expect hdr searches to come up with strings
+ * like "thing/thing.h". So we need to test for "/" as
+ * well as "\" when parsing pathnames.
+ * 03/16/95 (seiwald) - fixed accursed typo on line 69.
+ * 05/03/96 (seiwald) - split from filent.c, fileunix.c
+ * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
+ * don't include the archive member name.
+ */
+
+/*
+ * file_parse() - split a file name into dir/base/suffix/member
+ */
+
+void
+file_parse(
+ char *file,
+ FILENAME *f )
+{
+ char *p, *q;
+ char *end;
+
+ memset( (char *)f, 0, sizeof( *f ) );
+
+ /* Look for */
+
+ if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
+ {
+ f->f_grist.ptr = file;
+ f->f_grist.len = p - file;
+ file = p + 1;
+ }
+
+ /* Look for dir: */
+
+ p = strrchr( file, DELIM );
+
+ if( p )
+ {
+ f->f_dir.ptr = file;
+ f->f_dir.len = p - file;
+
+ /* Dir of : is : */
+ f->f_dir.len++;
+ file = p + 1;
+ }
+
+ end = file + strlen( file );
+
+ /* Look for (member) */
+
+ if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
+ {
+ f->f_member.ptr = p + 1;
+ f->f_member.len = end - p - 2;
+ end = p;
+ }
+
+ /* Look for .suffix */
+ /* This would be memrchr() */
+
+ p = 0;
+ q = file;
+
+ while( q = memchr( q, '.', end - q ) )
+ p = q++;
+
+ if( p )
+ {
+ f->f_suffix.ptr = p;
+ f->f_suffix.len = end - p;
+ end = p;
+ }
+
+ /* Leaves base */
+
+ f->f_base.ptr = file;
+ f->f_base.len = end - file;
+}
+
+/*
+ * file_build() - build a filename given dir/base/suffix/member
+ */
+
+# define DIR_EMPTY 0 /* "" */
+# define DIR_DOT 1 /* : */
+# define DIR_DOTDOT 2 /* :: */
+# define DIR_ABS 3 /* dira:dirb: */
+# define DIR_REL 4 /* :dira:dirb: */
+
+# define G_DIR 0 /* take dir */
+# define G_ROOT 1 /* take root */
+# define G_CAT 2 /* prepend root to dir */
+# define G_DTDR 3 /* :: of rel dir */
+# define G_DDDD 4 /* make it ::: (../..) */
+# define G_MT 5 /* leave it empty */
+
+char grid[5][5] = {
+/* EMPTY DOT DOTDOT ABS REL */
+/* EMPTY */ { G_MT, G_DIR, G_DIR, G_DIR, G_DIR },
+/* DOT */ { G_ROOT, G_DIR, G_DIR, G_DIR, G_DIR },
+/* DOTDOT */ { G_ROOT, G_ROOT, G_DDDD, G_DIR, G_DTDR },
+/* ABS */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT },
+/* REL */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT }
+} ;
+
+static int
+file_flags(
+ char *ptr,
+ int len )
+{
+ if( !len )
+ return DIR_EMPTY;
+ if( len == 1 && ptr[0] == DELIM )
+ return DIR_DOT;
+ if( len == 2 && ptr[0] == DELIM && ptr[1] == DELIM )
+ return DIR_DOTDOT;
+ if( ptr[0] == DELIM )
+ return DIR_REL;
+ return DIR_ABS;
+}
+
+void
+file_build(
+ FILENAME *f,
+ string* file,
+ int binding )
+{
+ int dflag, rflag, act;
+
+ file_build1( f, file );
+
+ /* Combine root & directory, according to the grid. */
+
+ dflag = file_flags( f->f_dir.ptr, f->f_dir.len );
+ rflag = file_flags( f->f_root.ptr, f->f_root.len );
+
+ switch( act = grid[ rflag ][ dflag ] )
+ {
+ case G_DTDR:
+ {
+ /* :: of rel dir */
+ string_push_back( file, DELIM );
+ }
+ /* fall through */
+
+ case G_DIR:
+ /* take dir */
+ string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
+ break;
+
+ case G_ROOT:
+ /* take root */
+ string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
+ break;
+
+ case G_CAT:
+ /* prepend root to dir */
+ string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
+ if( file->value[file->size - 1] == DELIM )
+ string_pop_back( file );
+ string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
+ break;
+
+ case G_DDDD:
+ /* make it ::: (../..) */
+ string_append( file, ":::" );
+ break;
+ }
+
+ /* Put : between dir and file (if none already) */
+
+ if( act != G_MT &&
+ file->value[file->size - 1] != DELIM &&
+ ( f->f_base.len || f->f_suffix.len ) )
+ {
+ string_push_back( file, DELIM );
+ }
+
+ if( f->f_base.len )
+ {
+ string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
+ }
+
+ if( f->f_suffix.len )
+ {
+ string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
+ }
+
+ if( f->f_member.len )
+ {
+ string_push_back( file, '(' );
+ string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
+ string_push_back( file, ')' );
+ }
+
+ if( DEBUG_SEARCH )
+ printf(" -> '%s'\n", file->value);
+}
+
+/*
+ * file_parent() - make a FILENAME point to its parent dir
+ */
+
+void
+file_parent( FILENAME *f )
+{
+ /* just set everything else to nothing */
+
+ f->f_base.ptr =
+ f->f_suffix.ptr =
+ f->f_member.ptr = "";
+
+ f->f_base.len =
+ f->f_suffix.len =
+ f->f_member.len = 0;
+}
+
+# endif /* OS_MAC */
diff --git a/historic/jam/src/pathunix.c b/historic/jam/src/pathunix.c
new file mode 100644
index 000000000..559d9c578
--- /dev/null
+++ b/historic/jam/src/pathunix.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+# include "strings.h"
+
+# ifdef USE_PATHUNIX
+
+/*
+ * pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
+ *
+ * External routines:
+ *
+ * file_parse() - split a file name into dir/base/suffix/member
+ * file_build() - build a filename given dir/base/suffix/member
+ * file_parent() - make a FILENAME point to its parent dir
+ *
+ * File_parse() and file_build() just manipuate a string and a structure;
+ * they do not make system calls.
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 12/26/93 (seiwald) - handle dir/.suffix properly in file_build()
+ * 12/19/94 (mikem) - solaris string table insanity support
+ * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
+ * 02/14/95 (seiwald) - parse and build /xxx properly
+ * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
+ * should expect hdr searches to come up with strings
+ * like "thing/thing.h". So we need to test for "/" as
+ * well as "\" when parsing pathnames.
+ * 03/16/95 (seiwald) - fixed accursed typo on line 69.
+ * 05/03/96 (seiwald) - split from filent.c, fileunix.c
+ * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
+ * don't include the archive member name.
+ */
+
+/*
+ * file_parse() - split a file name into dir/base/suffix/member
+ */
+
+void
+file_parse(
+ char *file,
+ FILENAME *f )
+{
+ char *p, *q;
+ char *end;
+
+ memset( (char *)f, 0, sizeof( *f ) );
+
+ /* Look for */
+
+ if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
+ {
+ f->f_grist.ptr = file;
+ f->f_grist.len = p - file;
+ file = p + 1;
+ }
+
+ /* Look for dir/ */
+
+ p = strrchr( file, '/' );
+
+# ifndef UNIX
+# ifndef AMIGA
+ /* On NT, look for dir\ as well */
+ {
+ char *p1 = strrchr( file, '\\' );
+ p = p1 > p ? p1 : p;
+ }
+# endif
+# endif
+
+ if( p )
+ {
+ f->f_dir.ptr = file;
+ f->f_dir.len = p - file;
+
+ /* Special case for / - dirname is /, not "" */
+
+ if( !f->f_dir.len )
+ f->f_dir.len = 1;
+
+# ifndef UNIX
+# ifndef AMIGA
+ /* Special case for D:/ - dirname is D:/, not "D:" */
+
+ if( f->f_dir.len == 2 && file[1] == ':' )
+ f->f_dir.len = 3;
+# endif
+# endif
+
+ file = p + 1;
+ }
+
+ end = file + strlen( file );
+
+ /* Look for (member) */
+
+ if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
+ {
+ f->f_member.ptr = p + 1;
+ f->f_member.len = end - p - 2;
+ end = p;
+ }
+
+ /* Look for .suffix */
+ /* This would be memrchr() */
+
+ p = 0;
+ q = file;
+
+ while( q = (char *)memchr( q, '.', end - q ) )
+ p = q++;
+
+ if( p )
+ {
+ f->f_suffix.ptr = p;
+ f->f_suffix.len = end - p;
+ end = p;
+ }
+
+ /* Leaves base */
+
+ f->f_base.ptr = file;
+ f->f_base.len = end - file;
+}
+
+/*
+ * file_build() - build a filename given dir/base/suffix/member
+ */
+
+void
+file_build(
+ FILENAME *f,
+ string *file,
+ int binding )
+{
+ file_build1( f, file );
+
+ /* Don't prepend root if it's . or directory is rooted */
+# if PATH_DELIM == '/'
+
+ if( f->f_root.len
+ && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
+ && !( f->f_dir.len && f->f_dir.ptr[0] == '/' ) )
+
+# else /* unix */
+
+ if( f->f_root.len
+ && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
+ && !( f->f_dir.len && f->f_dir.ptr[0] == '/' )
+ && !( f->f_dir.len && f->f_dir.ptr[0] == '\\' )
+ && !( f->f_dir.len && f->f_dir.ptr[1] == ':' ) )
+
+# endif /* unix */
+
+ {
+ string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
+ string_push_back( file, PATH_DELIM );
+ }
+
+ if( f->f_dir.len )
+ {
+ string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
+ }
+
+ /* UNIX: Put / between dir and file */
+ /* NT: Put \ between dir and file */
+
+ if( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
+ {
+ /* UNIX: Special case for dir \ : don't add another \ */
+ /* NT: Special case for dir / : don't add another / */
+
+# if PATH_DELIM == '\\'
+ if( !( f->f_dir.len == 3 && f->f_dir.ptr[1] == ':' ) )
+# endif
+ if( !( f->f_dir.len == 1 && f->f_dir.ptr[0] == PATH_DELIM ) )
+ string_push_back( file, PATH_DELIM );
+ }
+
+ if( f->f_base.len )
+ {
+ string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
+ }
+
+ if( f->f_suffix.len )
+ {
+ string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
+ }
+
+ if( f->f_member.len )
+ {
+ string_push_back( file, '(' );
+ string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
+ string_push_back( file, ')' );
+ }
+}
+
+/*
+ * file_parent() - make a FILENAME point to its parent dir
+ */
+
+void
+file_parent( FILENAME *f )
+{
+ /* just set everything else to nothing */
+
+ f->f_base.ptr =
+ f->f_suffix.ptr =
+ f->f_member.ptr = "";
+
+ f->f_base.len =
+ f->f_suffix.len =
+ f->f_member.len = 0;
+}
+
+# endif /* unix, NT, OS/2, AmigaOS */
diff --git a/historic/jam/src/pathvms.c b/historic/jam/src/pathvms.c
new file mode 100644
index 000000000..f89c95226
--- /dev/null
+++ b/historic/jam/src/pathvms.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+# ifdef OS_VMS
+
+# define DEBUG
+
+/*
+ * pathvms.c - manipulate file names on VMS
+ *
+ * External routines:
+ *
+ * file_parse() - split a file name into dir/base/suffix/member
+ * file_build() - build a filename given dir/base/suffix/member
+ * file_parent() - make a FILENAME point to its parent dir
+ *
+ * File_parse() and file_build() just manipuate a string and a structure;
+ * they do not make system calls.
+ *
+ * WARNING! This file contains voodoo logic, as black magic is
+ * necessary for wrangling with VMS file name. Woe be to people
+ * who mess with this code.
+ *
+ * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
+ * 05/03/96 (seiwald) - split from filevms.c
+ */
+
+/*
+ * file_parse() - split a file name into dir/base/suffix/member
+ */
+
+void
+file_parse(
+ char *file,
+ FILENAME *f )
+{
+ char *p, *q;
+ char *end;
+
+ memset( (char *)f, 0, sizeof( *f ) );
+
+ /* Look for */
+
+ if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
+ {
+ f->f_grist.ptr = file;
+ f->f_grist.len = p - file;
+ file = p + 1;
+ }
+
+ /* Look for dev:[dir] or dev: */
+
+ if( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) )
+ {
+ f->f_dir.ptr = file;
+ f->f_dir.len = p + 1 - file;
+ file = p + 1;
+ }
+
+ end = file + strlen( file );
+
+ /* Look for (member) */
+
+ if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
+ {
+ f->f_member.ptr = p + 1;
+ f->f_member.len = end - p - 2;
+ end = p;
+ }
+
+ /* Look for .suffix */
+ /* This would be memrchr() */
+
+ p = 0;
+ q = file;
+
+ while( q = memchr( q, '.', end - q ) )
+ p = q++;
+
+ if( p )
+ {
+ f->f_suffix.ptr = p;
+ f->f_suffix.len = end - p;
+ end = p;
+ }
+
+ /* Leaves base */
+
+ f->f_base.ptr = file;
+ f->f_base.len = end - file;
+
+ /* Is this a directory without a file spec? */
+
+ f->parent = 0;
+}
+
+/*
+ * dir mods result
+ * --- --- ------
+ * Rerooting:
+ *
+ * (none) :R=dev: dev:
+ * devd: :R=dev: devd:
+ * devd:[dir] :R=dev: devd:[dir]
+ * [.dir] :R=dev: dev:[dir] questionable
+ * [dir] :R=dev: dev:[dir]
+ *
+ * (none) :R=[rdir] [rdir] questionable
+ * devd: :R=[rdir] devd:
+ * devd:[dir] :R=[rdir] devd:[dir]
+ * [.dir] :R=[rdir] [rdir.dir] questionable
+ * [dir] :R=[rdir] [rdir]
+ *
+ * (none) :R=dev:[root] dev:[root]
+ * devd: :R=dev:[root] devd:
+ * devd:[dir] :R=dev:[root] devd:[dir]
+ * [.dir] :R=dev:[root] dev:[root.dir]
+ * [dir] :R=dev:[root] [dir]
+ *
+ * Climbing to parent:
+ *
+ */
+
+# define DIR_EMPTY 0 /* empty string */
+# define DIR_DEV 1 /* dev: */
+# define DIR_DEVDIR 2 /* dev:[dir] */
+# define DIR_DOTDIR 3 /* [.dir] */
+# define DIR_DASHDIR 4 /* [-] or [-.dir] */
+# define DIR_ABSDIR 5 /* [dir] */
+# define DIR_ROOT 6 /* [000000] or dev:[000000] */
+
+# define G_DIR 0 /* take just dir */
+# define G_ROOT 1 /* take just root */
+# define G_VAD 2 /* root's dev: + [abs] */
+# define G_DRD 3 /* root's dev:[dir] + [.rel] */
+# define G_VRD 4 /* root's dev: + [.rel] made [abs] */
+# define G_DDD 5 /* root's dev:[dir] + . + [dir] */
+
+static int grid[7][7] = {
+
+/* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */
+/* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR,
+/* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD,
+/* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD,
+/* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
+/* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR,
+/* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
+/* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR,
+
+} ;
+
+struct dirinf {
+ int flags;
+
+ struct {
+ char *ptr;
+ int len;
+ } dev, dir;
+} ;
+
+static char *
+strnchr(
+ char *buf,
+ int c,
+ int len )
+{
+ while( len-- )
+ if( *buf && *buf++ == c )
+ return buf - 1;
+
+ return 0;
+}
+
+static void
+dir_flags(
+ char *buf,
+ int len,
+ struct dirinf *i )
+{
+ char *p;
+
+ if( !buf || !len )
+ {
+ i->flags = DIR_EMPTY;
+ i->dev.ptr =
+ i->dir.ptr = 0;
+ i->dev.len =
+ i->dir.len = 0;
+ }
+ else if( p = strnchr( buf, ':', len ) )
+ {
+ i->dev.ptr = buf;
+ i->dev.len = p + 1 - buf;
+ i->dir.ptr = buf + i->dev.len;
+ i->dir.len = len - i->dev.len;
+ i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV;
+ }
+ else
+ {
+ i->dev.ptr = buf;
+ i->dev.len = 0;
+ i->dir.ptr = buf;
+ i->dir.len = len;
+
+ if( *buf == '[' && buf[1] == ']' )
+ i->flags = DIR_EMPTY;
+ else if( *buf == '[' && buf[1] == '.' )
+ i->flags = DIR_DOTDIR;
+ else if( *buf == '[' && buf[1] == '-' )
+ i->flags = DIR_DASHDIR;
+ else
+ i->flags = DIR_ABSDIR;
+ }
+
+ /* But if its rooted in any way */
+
+ if( i->dir.len == 8 && !strncmp( i->dir.ptr, "[000000]", 8 ) )
+ i->flags = DIR_ROOT;
+}
+
+/*
+ * file_build() - build a filename given dir/base/suffix/member
+ */
+
+void
+file_build(
+ FILENAME *f,
+ string *file,
+ int binding )
+{
+ struct dirinf root, dir;
+ int g;
+
+ file_build1( f, file );
+
+ /* Get info on root and dir for combining. */
+
+ dir_flags( f->f_root.ptr, f->f_root.len, &root );
+ dir_flags( f->f_dir.ptr, f->f_dir.len, &dir );
+
+ /* Combine */
+
+ switch( g = grid[ root.flags ][ dir.flags ] )
+ {
+ case G_DIR:
+ /* take dir */
+ string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
+ break;
+
+ case G_ROOT:
+ /* take root */
+ string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
+ break;
+
+ case G_VAD:
+ /* root's dev + abs directory */
+ string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
+ string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len );
+ break;
+
+ case G_DRD:
+ case G_DDD:
+ /* root's dev:[dir] + rel directory */
+ string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
+
+ /* sanity checks: root ends with ] */
+
+ if( file->value[file->size - 1] == ']' )
+ string_pop_back( file );
+
+ /* Add . if separating two -'s */
+
+ if( g == G_DDD )
+ string_push_back( file, '.' );
+
+ /* skip [ of dir */
+ string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1 );
+ break;
+
+ case G_VRD:
+ /* root's dev + rel directory made abs */
+ string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
+ string_push_back( file, '[' );
+ /* skip [. of rel dir */
+ string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2 );
+ break;
+ }
+
+# ifdef DEBUG
+ if( DEBUG_SEARCH && ( root.flags || dir.flags ) )
+ {
+ printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
+ grid[ root.flags ][ dir.flags ], file->value );
+ }
+# endif
+
+ /*
+ * Now do the special :P modifier when no file was present.
+ * (none) (none)
+ * [dir1.dir2] [dir1]
+ * [dir] [000000]
+ * [.dir] []
+ * [] []
+ */
+
+ if( file->value[file->size - 1] == ']' && f->parent )
+ {
+ char* p = file->value + file->size;
+ while( p-- > file->value )
+ {
+ if( *p == '.' )
+ {
+ string_truncate( file, p - file->value );
+ string_push_back( file, ']' );
+ break;
+ }
+ else if( *p == '-' )
+ {
+ /* handle .- or - */
+ if( p > file->value && p[-1] == '.' )
+ --p;
+
+ *p++ = ']';
+ break;
+ }
+ else if( *p == '[' )
+ {
+ if( p[1] == ']' )
+ {
+ p += 2;
+ }
+ else
+ {
+ string_truncate( file, p - file->value );
+ string_append( file, "[000000]" );
+ }
+ break;
+ }
+ }
+ }
+
+ /* Now copy the file pieces. */
+
+ if( f->f_base.len )
+ {
+ string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
+ }
+
+ /* If there is no suffix, we append a "." onto all generated */
+ /* names. This keeps VMS from appending its own (wrong) idea */
+ /* of what the suffix should be. */
+
+ if( f->f_suffix.len )
+ {
+ string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
+ }
+ else if( binding && f->f_base.len )
+ {
+ string_push_back( file, '.' );
+ }
+
+ if( f->f_member.len )
+ {
+ string_push_back( file, '(' );
+ string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
+ string_push_back( file, ')' );
+ }
+
+# ifdef DEBUG
+ if( DEBUG_SEARCH )
+ printf("built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n",
+ f->f_root.len, f->f_root.ptr,
+ f->f_dir.len, f->f_dir.ptr,
+ f->f_base.len, f->f_base.ptr,
+ f->f_suffix.len, f->f_suffix.ptr,
+ f->f_member.len, f->f_member.ptr,
+ file->value );
+# endif
+}
+
+/*
+ * file_parent() - make a FILENAME point to its parent dir
+ */
+
+void
+file_parent( FILENAME *f )
+{
+ if( f->f_base.len )
+ {
+ f->f_base.ptr =
+ f->f_suffix.ptr =
+ f->f_member.ptr = "";
+
+ f->f_base.len =
+ f->f_suffix.len =
+ f->f_member.len = 0;
+ }
+ else
+ {
+ f->parent = 1;
+ }
+}
+
+# endif /* VMS */
diff --git a/historic/jam/src/regexp.c b/historic/jam/src/regexp.c
new file mode 100644
index 000000000..92ee8efd8
--- /dev/null
+++ b/historic/jam/src/regexp.c
@@ -0,0 +1,1317 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
+ *** to assist in implementing egrep.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
+ *** as in BSD grep and ex.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
+ *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
+ *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
+ *** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald
+ *** seiwald@vix.com, on 28 August 1993, for use in jam. Regmagic.h
+ *** was moved into regexp.h, and the include of regexp.h now uses "'s
+ *** to avoid conflicting with the system regexp.h. Const, bless its
+ *** soul, was removed so it can compile everywhere. The declaration
+ *** of strchr() was in conflict on AIX, so it was removed (as it is
+ *** happily defined in string.h).
+ *** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald
+ *** seiwald@perforce.com, on 20 January 2000, to use function prototypes.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+#include "regexp.h"
+#include
+#include
+#ifndef ultrix
+#include
+#endif
+#include
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match any character in this string. */
+#define ANYBUT 5 /* str Match any character not in this string. */
+#define BRANCH 6 /* node Match this alternative, or the next... */
+#define BACK 7 /* no Match "", "next" ptr points backward. */
+#define EXACTLY 8 /* str Match this string. */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more times. */
+#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
+#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */
+#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */
+#define OPEN 20 /* no Mark this point in input as start of #n. */
+ /* OPEN+1 is number 1, etc. */
+#define CLOSE 30 /* no Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+#define FAIL(m) { regerror(m); return(NULL); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 04 /* Starts with * or +. */
+#define WORST 0 /* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+static char *regparse; /* Input-scan pointer. */
+static int regnpar; /* () count. */
+static char regdummy;
+static char *regcode; /* Code-emit pointer; ®dummy = don't. */
+static long regsize; /* Code size. */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define STATIC static
+#endif
+STATIC char *reg( int paren, int *flagp );
+STATIC char *regbranch( int *flagp );
+STATIC char *regpiece( int *flagp );
+STATIC char *regatom( int *flagp );
+STATIC char *regnode( int op );
+STATIC char *regnext( register char *p );
+STATIC void regc( int b );
+STATIC void reginsert( char op, char *opnd );
+STATIC void regtail( char *p, char *val );
+STATIC void regoptail( char *p, char *val );
+#ifdef STRCSPN
+STATIC int strcspn();
+#endif
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *
+regcomp( char *exp )
+{
+ register regexp *r;
+ register char *scan;
+ register char *longest;
+ register unsigned len;
+ int flags;
+
+ if (exp == NULL)
+ FAIL("NULL argument");
+
+ /* First pass: determine size, legality. */
+#ifdef notdef
+ if (exp[0] == '.' && exp[1] == '*') exp += 2; /* aid grep */
+#endif
+ regparse = (char *)exp;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = ®dummy;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ FAIL("regexp too big");
+
+ /* Allocate space. */
+ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
+ if (r == NULL)
+ FAIL("out of space");
+
+ /* Second pass: emit code. */
+ regparse = (char *)exp;
+ regnpar = 1;
+ regcode = r->program;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = '\0'; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = NULL;
+ r->regmlen = 0;
+ scan = r->program+1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == EXACTLY)
+ r->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ r->reganch++;
+
+ /*
+ * If there's something expensive in the r.e., find the
+ * longest literal string that must appear and make it the
+ * regmust. Resolve ties in favor of later strings, since
+ * the regstart check works with the beginning of the r.e.
+ * and avoiding duplication strengthens checking. Not a
+ * strong reason, but sufficient in the absence of others.
+ */
+ if (flags&SPSTART) {
+ longest = NULL;
+ len = 0;
+ for (; scan != NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+
+ return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(
+ int paren, /* Parenthesized? */
+ int *flagp )
+{
+ register char *ret;
+ register char *br;
+ register char *ender;
+ register int parno;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ if (regnpar >= NSUBEXP)
+ FAIL("too many ()");
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(OPEN+parno);
+ } else
+ ret = NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ if (ret != NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*regparse == '|' || *regparse == '\n') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode((paren) ? CLOSE+parno : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != ')') {
+ FAIL("unmatched ()");
+ } else if (!paren && *regparse != '\0') {
+ if (*regparse == ')') {
+ FAIL("unmatched ()");
+ } else
+ FAIL("junk on end"); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+
+ return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch( int *flagp )
+{
+ register char *ret;
+ register char *chain;
+ register char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = NULL;
+ while (*regparse != '\0' && *regparse != ')' &&
+ *regparse != '\n' && *regparse != '|') {
+ latest = regpiece(&flags);
+ if (latest == NULL)
+ return(NULL);
+ *flagp |= flags&HASWIDTH;
+ if (chain == NULL) /* First piece. */
+ *flagp |= flags&SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == NULL) /* Loop ran zero times. */
+ (void) regnode(NOTHING);
+
+ return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece( int *flagp )
+{
+ register char *ret;
+ register char op;
+ register char *next;
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == NULL)
+ return(NULL);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?')
+ FAIL("*+ operand could be empty");
+ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+ if (op == '*' && (flags&SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '+' && (flags&SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '?') {
+ /* Emit x? as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING); /* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ regparse++;
+ if (ISMULT(*regparse))
+ FAIL("nested *?+");
+
+ return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *
+regatom( int *flagp )
+{
+ register char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ /* FIXME: these chars only have meaning at beg/end of pat? */
+ case '^':
+ ret = regnode(BOL);
+ break;
+ case '$':
+ ret = regnode(EOL);
+ break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ register int classr;
+ register int classend;
+
+ if (*regparse == '^') { /* Complement of range. */
+ ret = regnode(ANYBUT);
+ regparse++;
+ } else
+ ret = regnode(ANYOF);
+ if (*regparse == ']' || *regparse == '-')
+ regc(*regparse++);
+ while (*regparse != '\0' && *regparse != ']') {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == ']' || *regparse == '\0')
+ regc('-');
+ else {
+ classr = UCHARAT(regparse-2)+1;
+ classend = UCHARAT(regparse);
+ if (classr > classend+1)
+ FAIL("invalid [] range");
+ for (; classr <= classend; classr++)
+ regc(classr);
+ regparse++;
+ }
+ } else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != ']')
+ FAIL("unmatched []");
+ regparse++;
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == NULL)
+ return(NULL);
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case '\n':
+ case ')':
+ FAIL("internal urp"); /* Supposed to be caught earlier. */
+ break;
+ case '?':
+ case '+':
+ case '*':
+ FAIL("?+* follows nothing");
+ break;
+ case '\\':
+ switch (*regparse++) {
+ case '\0':
+ FAIL("trailing \\");
+ break;
+ case '<':
+ ret = regnode(WORDA);
+ break;
+ case '>':
+ ret = regnode(WORDZ);
+ break;
+ /* FIXME: Someday handle \1, \2, ... */
+ default:
+ /* Handle general quoted chars in exact-match routine */
+ goto de_fault;
+ }
+ break;
+ de_fault:
+ default:
+ /*
+ * Encode a string of characters to be matched exactly.
+ *
+ * This is a bit tricky due to quoted chars and due to
+ * '*', '+', and '?' taking the SINGLE char previous
+ * as their operand.
+ *
+ * On entry, the char at regparse[-1] is going to go
+ * into the string, no matter what it is. (It could be
+ * following a \ if we are entered from the '\' case.)
+ *
+ * Basic idea is to pick up a good char in ch and
+ * examine the next char. If it's *+? then we twiddle.
+ * If it's \ then we frozzle. If it's other magic char
+ * we push ch and terminate the string. If none of the
+ * above, we push ch on the string and go around again.
+ *
+ * regprev is used to remember where "the current char"
+ * starts in the string, if due to a *+? we need to back
+ * up and put the current char in a separate, 1-char, string.
+ * When regprev is NULL, ch is the only char in the
+ * string; this is used in *+? handling, and in setting
+ * flags |= SIMPLE at the end.
+ */
+ {
+ char *regprev;
+ register char ch;
+
+ regparse--; /* Look at cur char */
+ ret = regnode(EXACTLY);
+ for ( regprev = 0 ; ; ) {
+ ch = *regparse++; /* Get current char */
+ switch (*regparse) { /* look at next one */
+
+ default:
+ regc(ch); /* Add cur to string */
+ break;
+
+ case '.': case '[': case '(':
+ case ')': case '|': case '\n':
+ case '$': case '^':
+ case '\0':
+ /* FIXME, $ and ^ should not always be magic */
+ magic:
+ regc(ch); /* dump cur char */
+ goto done; /* and we are done */
+
+ case '?': case '+': case '*':
+ if (!regprev) /* If just ch in str, */
+ goto magic; /* use it */
+ /* End mult-char string one early */
+ regparse = regprev; /* Back up parse */
+ goto done;
+
+ case '\\':
+ regc(ch); /* Cur char OK */
+ switch (regparse[1]){ /* Look after \ */
+ case '\0':
+ case '<':
+ case '>':
+ /* FIXME: Someday handle \1, \2, ... */
+ goto done; /* Not quoted */
+ default:
+ /* Backup point is \, scan * point is after it. */
+ regprev = regparse;
+ regparse++;
+ continue; /* NOT break; */
+ }
+ }
+ regprev = regparse; /* Set backup point */
+ }
+ done:
+ regc('\0');
+ *flagp |= HASWIDTH;
+ if (!regprev) /* One char? */
+ *flagp |= SIMPLE;
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char * /* Location. */
+regnode( int op )
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == ®dummy) {
+ regsize += 3;
+ return(ret);
+ }
+
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc( int b )
+{
+ if (regcode != ®dummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(
+ char op,
+ char *opnd )
+{
+ register char *src;
+ register char *dst;
+ register char *place;
+
+ if (regcode == ®dummy) {
+ regsize += 3;
+ return;
+ }
+
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(
+ char *p,
+ char *val )
+{
+ register char *scan;
+ register char *temp;
+ register int offset;
+
+ if (p == ®dummy)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == NULL)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan+1) = (offset>>8)&0377;
+ *(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+
+static void
+regoptail(
+ char *p,
+ char *val )
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == NULL || p == ®dummy || OP(p) != BRANCH)
+ return;
+ regtail(OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *reginput; /* String-input pointer. */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry( regexp *prog, char *string );
+STATIC int regmatch( char *prog );
+STATIC int regrepeat( char *p );
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+STATIC char *regprop();
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int
+regexec(
+ register regexp *prog,
+ register char *string )
+{
+ register char *s;
+
+ /* Be paranoid... */
+ if (prog == NULL || string == NULL) {
+ regerror("NULL parameter");
+ return(0);
+ }
+
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("corrupted program");
+ return(0);
+ }
+
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != NULL) {
+ s = (char *)string;
+ while ((s = strchr(s, prog->regmust[0])) != NULL) {
+ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+ break; /* Found it. */
+ s++;
+ }
+ if (s == NULL) /* Not present. */
+ return(0);
+ }
+
+ /* Mark beginning of line for ^ . */
+ regbol = (char *)string;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch)
+ return(regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = (char *)string;
+ if (prog->regstart != '\0')
+ /* We know what char it must start with. */
+ while ((s = strchr(s, prog->regstart)) != NULL) {
+ if (regtry(prog, s))
+ return(1);
+ s++;
+ }
+ else
+ /* We don't -- general case. */
+ do {
+ if (regtry(prog, s))
+ return(1);
+ } while (*s++ != '\0');
+
+ /* Failure. */
+ return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int /* 0 failure, 1 success */
+regtry(
+ regexp *prog,
+ char *string )
+{
+ register int i;
+ register char **sp;
+ register char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ for (i = NSUBEXP; i > 0; i--) {
+ *sp++ = NULL;
+ *ep++ = NULL;
+ }
+ if (regmatch(prog->program + 1)) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return(1);
+ } else
+ return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int /* 0 failure, 1 success */
+regmatch( char *prog )
+{
+ register char *scan; /* Current node. */
+ char *next; /* Next node. */
+
+ scan = prog;
+#ifdef DEBUG
+ if (scan != NULL && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != NULL) {
+#ifdef DEBUG
+ if (regnarrate)
+ fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+ next = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol)
+ return(0);
+ break;
+ case EOL:
+ if (*reginput != '\0')
+ return(0);
+ break;
+ case WORDA:
+ /* Must be looking at a letter, digit, or _ */
+ if ((!isalnum(*reginput)) && *reginput != '_')
+ return(0);
+ /* Prev must be BOL or nonword */
+ if (reginput > regbol &&
+ (isalnum(reginput[-1]) || reginput[-1] == '_'))
+ return(0);
+ break;
+ case WORDZ:
+ /* Must be looking at non letter, digit, or _ */
+ if (isalnum(*reginput) || *reginput == '_')
+ return(0);
+ /* We don't care what the previous char was */
+ break;
+ case ANY:
+ if (*reginput == '\0')
+ return(0);
+ reginput++;
+ break;
+ case EXACTLY: {
+ register int len;
+ register char *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first character, for speed. */
+ if (*opnd != *reginput)
+ return(0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return(0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+ return(0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+ return(0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set startp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regstartp[no] == NULL)
+ regstartp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set endp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regendp[no] == NULL)
+ regendp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case BRANCH: {
+ register char *save;
+
+ if (OP(next) != BRANCH) /* No choice. */
+ next = OPERAND(scan); /* Avoid recursion. */
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return(1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != NULL && OP(scan) == BRANCH);
+ return(0);
+ /* NOTREACHED */
+ }
+ }
+ break;
+ case STAR:
+ case PLUS: {
+ register char nextch;
+ register int no;
+ register char *save;
+ register int min;
+
+ /*
+ * Lookahead to avoid useless match attempts
+ * when we know what character comes next.
+ */
+ nextch = '\0';
+ if (OP(next) == EXACTLY)
+ nextch = *OPERAND(next);
+ min = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= min) {
+ /* If it could work, try it. */
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(next))
+ return(1);
+ /* Couldn't or didn't -- back up. */
+ no--;
+ reginput = save + no;
+ }
+ return(0);
+ }
+ break;
+ case END:
+ return(1); /* Success! */
+ break;
+ default:
+ regerror("memory corruption");
+ return(0);
+ break;
+ }
+
+ scan = next;
+ }
+
+ /*
+ * We get here only if there's trouble -- normally "case END" is
+ * the terminating point.
+ */
+ regerror("corrupted pointers");
+ return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int
+regrepeat( char *p )
+{
+ register int count = 0;
+ register char *scan;
+ register char *opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = strlen(scan);
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ regerror("internal foulup");
+ count = 0; /* Best compromise. */
+ break;
+ }
+ reginput = scan;
+
+ return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *
+regnext( register char *p )
+{
+ register int offset;
+
+ if (p == ®dummy)
+ return(NULL);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return(NULL);
+
+ if (OP(p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+#ifdef DEBUG
+
+STATIC char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void
+regdump( regexp *r )
+{
+ register char *s;
+ register char op = EXACTLY; /* Arbitrary non-END op. */
+ register char *next;
+
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+ op = OP(s);
+ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
+ next = regnext(s);
+ if (next == NULL) /* Next ptr. */
+ printf("(0)");
+ else
+ printf("(%d)", (s-r->program)+(next-s));
+ s += 3;
+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+ /* Literal string, where present. */
+ while (*s != '\0') {
+ putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != '\0')
+ printf("start `%c' ", r->regstart);
+ if (r->reganch)
+ printf("anchored ");
+ if (r->regmust != NULL)
+ printf("must have \"%s\"", r->regmust);
+ printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *
+regprop( char *op )
+{
+ register char *p;
+ static char buf[50];
+
+ (void) strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case ANYBUT:
+ p = "ANYBUT";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9:
+ sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+ p = NULL;
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9:
+ sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+ p = NULL;
+ break;
+ case STAR:
+ p = "STAR";
+ break;
+ case PLUS:
+ p = "PLUS";
+ break;
+ case WORDA:
+ p = "WORDA";
+ break;
+ case WORDZ:
+ p = "WORDZ";
+ break;
+ default:
+ regerror("corrupted opcode");
+ break;
+ }
+ if (p != NULL)
+ (void) strcat(buf, p);
+ return(buf);
+}
+#endif
+
+/*
+ * The following is provided for those people who do not have strcspn() in
+ * their C libraries. They should get off their butts and do something
+ * about it; at least one public-domain implementation of those (highly
+ * useful) string routines has been published on Usenet.
+ */
+#ifdef STRCSPN
+/*
+ * strcspn - find length of initial segment of s1 consisting entirely
+ * of characters not from s2
+ */
+
+static int
+strcspn(
+ char *s1,
+ char *s2 )
+{
+ register char *scan1;
+ register char *scan2;
+ register int count;
+
+ count = 0;
+ for (scan1 = s1; *scan1 != '\0'; scan1++) {
+ for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
+ if (*scan1 == *scan2++)
+ return(count);
+ count++;
+ }
+ return(count);
+}
+#endif
diff --git a/historic/jam/src/regexp.h b/historic/jam/src/regexp.h
new file mode 100644
index 000000000..63507b475
--- /dev/null
+++ b/historic/jam/src/regexp.h
@@ -0,0 +1,31 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+#ifndef REGEXP_DWA20011023_H
+# define REGEXP_DWA20011023_H
+
+#define NSUBEXP 10
+typedef struct regexp {
+ char *startp[NSUBEXP];
+ char *endp[NSUBEXP];
+ char regstart; /* Internal use only. */
+ char reganch; /* Internal use only. */
+ char *regmust; /* Internal use only. */
+ int regmlen; /* Internal use only. */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+} regexp;
+
+regexp *regcomp( char *exp );
+int regexec( regexp *prog, char *string );
+void regerror( char *s );
+
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
+
+#endif // REGEXP_DWA20011023_H
diff --git a/historic/jam/src/rules.c b/historic/jam/src/rules.c
new file mode 100644
index 000000000..bad40d6d6
--- /dev/null
+++ b/historic/jam/src/rules.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "rules.h"
+# include "newstr.h"
+# include "hash.h"
+# include "modules.h"
+
+/*
+ * rules.c - access to RULEs, TARGETs, and ACTIONs
+ *
+ * External routines:
+ *
+ * bindrule() - return pointer to RULE, creating it if necessary
+ * bindtarget() - return pointer to TARGET, creating it if necessary
+ * touchtarget() - mark a target to simulate being new
+ * targetlist() - turn list of target names into a TARGET chain
+ * targetentry() - add a TARGET to a chain of TARGETS
+ * actionlist() - append to an ACTION chain
+ * addsettings() - add a deferred "set" command to a target
+ * usesettings() - set all target specific variables
+ * pushsettings() - set all target specific variables
+ * popsettings() - reset target specific variables to their pre-push values
+ * freesettings() - delete a settings list
+ * donerules() - free RULE and TARGET tables
+ *
+ * 04/12/94 (seiwald) - actionlist() now just appends a single action.
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ */
+
+static struct hash *targethash = 0;
+
+
+/*
+ * bindrule() - return pointer to RULE, creating it if necessary
+ */
+
+static RULE *
+enter_rule( char *rulename, module* m )
+{
+ RULE rule, *r = &rule;
+
+ r->name = rulename;
+
+ if( hashenter( m->rules, (HASHDATA **)&r ) )
+ {
+ r->name = newstr( rulename ); /* never freed */
+ r->procedure = (PARSE *)0;
+ r->actions = 0;
+ r->arguments = 0;
+ }
+
+ return r;
+}
+
+/*
+ * bindtarget() - return pointer to TARGET, creating it if necessary
+ */
+
+TARGET *
+bindtarget( char *targetname )
+{
+ TARGET target, *t = ⌖
+
+ if( !targethash )
+ targethash = hashinit( sizeof( TARGET ), "targets" );
+
+ t->name = targetname;
+
+ if( hashenter( targethash, (HASHDATA **)&t ) )
+ {
+ memset( (char *)t, '\0', sizeof( *t ) );
+ t->name = newstr( targetname ); /* never freed */
+ t->boundname = t->name; /* default for T_FLAG_NOTFILE */
+ }
+
+ return t;
+}
+
+/*
+ * touchtarget() - mark a target to simulate being new
+ */
+
+void
+touchtarget( char *t )
+{
+ bindtarget( t )->flags |= T_FLAG_TOUCHED;
+}
+
+/*
+ * targetlist() - turn list of target names into a TARGET chain
+ *
+ * Inputs:
+ * chain existing TARGETS to append to
+ * targets list of target names
+ */
+
+TARGETS *
+targetlist(
+ TARGETS *chain,
+ LIST *targets )
+{
+ for( ; targets; targets = list_next( targets ) )
+ chain = targetentry( chain, bindtarget( targets->string ) );
+
+ return chain;
+}
+
+/*
+ * targetentry() - add a TARGET to a chain of TARGETS
+ *
+ * Inputs:
+ * chain exisitng TARGETS to append to
+ * target new target to append
+ */
+
+TARGETS *
+targetentry(
+ TARGETS *chain,
+ TARGET *target )
+{
+ TARGETS *c;
+
+ c = (TARGETS *)malloc( sizeof( TARGETS ) );
+ c->target = target;
+
+ if( !chain ) chain = c;
+ else chain->tail->next = c;
+ chain->tail = c;
+ c->next = 0;
+
+ return chain;
+}
+
+/*
+ * actionlist() - append to an ACTION chain
+ */
+
+ACTIONS *
+actionlist(
+ ACTIONS *chain,
+ ACTION *action )
+{
+ ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) );
+
+ actions->action = action;
+
+ if( !chain ) chain = actions;
+ else chain->tail->next = actions;
+ chain->tail = actions;
+ actions->next = 0;
+
+ return chain;
+}
+
+static SETTINGS* settings_freelist;
+
+/*
+ * addsettings() - add a deferred "set" command to a target
+ *
+ * Adds a variable setting (varname=list) onto a chain of settings
+ * for a particular target. Replaces the previous previous value,
+ * if any, unless 'append' says to append the new list onto the old.
+ * Returns the head of the chain of settings.
+ */
+
+SETTINGS *
+addsettings(
+ SETTINGS *head,
+ int append,
+ char *symbol,
+ LIST *value )
+{
+ SETTINGS *v;
+
+ /* Look for previous setting */
+
+ for( v = head; v; v = v->next )
+ if( !strcmp( v->symbol, symbol ) )
+ break;
+
+ /* If not previously set, alloc a new. */
+ /* If appending, do so. */
+ /* Else free old and set new. */
+
+ if( !v )
+ {
+ v = settings_freelist;
+
+ if ( v )
+ settings_freelist = v->next;
+ else
+ v = (SETTINGS *)malloc( sizeof( *v ) );
+
+ v->symbol = newstr( symbol );
+ v->value = value;
+ v->next = head;
+ head = v;
+ }
+ else if( append )
+ {
+ v->value = list_append( v->value, value );
+ }
+ else
+ {
+ list_free( v->value );
+ v->value = value;
+ }
+
+ /* Return (new) head of list. */
+
+ return head;
+}
+
+/*
+ * pushsettings() - set all target specific variables
+ */
+
+void
+pushsettings( SETTINGS *v )
+{
+ for( ; v; v = v->next )
+ v->value = var_swap( v->symbol, v->value );
+}
+
+/*
+ * popsettings() - reset target specific variables to their pre-push values
+ */
+
+void
+popsettings( SETTINGS *v )
+{
+ pushsettings( v ); /* just swap again */
+}
+
+/*
+ * freesettings() - delete a settings list
+ */
+
+void
+freesettings( SETTINGS *v )
+{
+ while( v )
+ {
+ SETTINGS *n = v->next;
+
+ freestr( v->symbol );
+ list_free( v->value );
+ v->next = settings_freelist;
+ settings_freelist = v;
+
+ v = n;
+ }
+}
+
+/*
+ * donerules() - free TARGET tables
+ */
+
+void
+donerules()
+{
+ hashdone( targethash );
+ while ( settings_freelist )
+ {
+ SETTINGS* n = settings_freelist->next;
+ free( settings_freelist );
+ settings_freelist = n;
+ }
+}
+
+argument_list* args_new()
+{
+ argument_list* r = malloc( sizeof(argument_list) );
+ r->reference_count = 0;
+ lol_init(r->data);
+ return r;
+}
+
+void args_refer( argument_list* a )
+{
+ ++a->reference_count;
+}
+
+void args_free( argument_list* a )
+{
+ if (--a->reference_count <= 0)
+ {
+ lol_free(a->data);
+ free(a);
+ }
+}
+
+void actions_refer(rule_actions* a)
+{
+ ++a->reference_count;
+}
+
+void actions_free(rule_actions* a)
+{
+ if (--a->reference_count <= 0)
+ {
+ freestr(a->command);
+ list_free(a->bindlist);
+ free(a);
+ }
+}
+
+void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure )
+{
+ if ( args )
+ args_refer( args );
+ if ( rule->arguments )
+ args_free( rule->arguments );
+ rule->arguments = args;
+
+ if ( procedure )
+ parse_refer( procedure );
+ if ( rule->procedure )
+ parse_free( rule->procedure );
+ rule->procedure = procedure;
+}
+
+static RULE* global_rule( char* rulename, module* m )
+{
+ char global_name[4096] = "";
+ strncat(global_name, m->name, sizeof(global_name) - 1);
+ strncat(global_name, rulename, sizeof(global_name) - 1);
+ return enter_rule( global_name, root_module() );
+}
+
+RULE* new_rule_body( module* m, char* rulename, argument_list* args, PARSE* procedure )
+{
+ RULE* local = enter_rule( rulename, m );
+ RULE* global = global_rule( rulename, m );
+ procedure->module = m;
+ procedure->rulename = copystr( global->name );
+ set_rule_body( local, args, procedure );
+ set_rule_body( global, args, procedure );
+
+ return local;
+}
+
+static void set_rule_actions( RULE* rule, rule_actions* actions )
+{
+ if ( actions )
+ actions_refer( actions );
+ if ( rule->actions )
+ actions_free( rule->actions );
+ rule->actions = actions;
+
+}
+
+static rule_actions* actions_new( char* command, LIST* bindlist, int flags )
+{
+ rule_actions* result = malloc(sizeof(rule_actions));
+ result->command = copystr( command );
+ result->bindlist = bindlist;
+ result->flags = flags;
+ result->reference_count = 0;
+ return result;
+}
+
+RULE* new_rule_actions( module* m, char* rulename, char* command, LIST* bindlist, int flags )
+{
+ RULE* local = enter_rule( rulename, m );
+ RULE* global = global_rule( rulename, m );
+ set_rule_actions( local, actions_new( command, bindlist, flags ) );
+ set_rule_actions( global, local->actions );
+ return local;
+}
+
+RULE *bindrule( char *rulename, module* m )
+{
+ RULE rule, *r = &rule;
+ r->name = rulename;
+
+ if ( hashcheck( m->rules, (HASHDATA **)&r ) )
+ return r;
+ else
+ return enter_rule( rulename, root_module() );
+}
+
+RULE* import_rule( RULE* source, module* m, char* name )
+{
+ RULE* dest = enter_rule( name, m );
+ set_rule_body( dest, source->arguments, source->procedure );
+ set_rule_actions( dest, source->actions );
+ return dest;
+}
diff --git a/historic/jam/src/rules.h b/historic/jam/src/rules.h
new file mode 100644
index 000000000..ab1cff4ce
--- /dev/null
+++ b/historic/jam/src/rules.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+#ifndef RULES_DWA_20011020_H
+# define RULES_DWA_20011020_H
+
+# include "modules.h"
+
+/*
+ * rules.h - targets, rules, and related information
+ *
+ * This file describes the structures holding the targets, rules, and
+ * related information accumulated by interpreting the statements
+ * of the jam files.
+ *
+ * The following are defined:
+ *
+ * RULE - a generic jam rule, the product of RULE and ACTIONS
+ * ACTIONS - a chain of ACTIONs
+ * ACTION - a RULE instance with targets and sources
+ * SETTINGS - variables to set when executing a TARGET's ACTIONS
+ * TARGETS - a chain of TARGETs
+ * TARGET - a file or "thing" that can be built
+ *
+ * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.
+ * 04/12/94 (seiwald) - actionlist() now just appends a single action.
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
+ * 01/19/95 (seiwald) - split DONTKNOW into CANTFIND/CANTMAKE.
+ * 02/02/95 (seiwald) - new LEAVES modifier on targets.
+ * 02/14/95 (seiwald) - new NOUPDATE modifier on targets.
+ */
+
+typedef struct _rule RULE;
+typedef struct _target TARGET;
+typedef struct _targets TARGETS;
+typedef struct _action ACTION;
+typedef struct _actions ACTIONS;
+typedef struct _settings SETTINGS ;
+
+/* RULE - a generic jam rule, the product of RULE and ACTIONS */
+
+/* A rule's argument list */
+struct argument_list
+{
+ int reference_count;
+ LOL data[1];
+};
+
+/* The build actions corresponding to a rule */
+struct rule_actions
+{
+ int reference_count;
+ char* command; /* command string from ACTIONS */
+ LIST* bindlist;
+ int flags; /* modifiers on ACTIONS */
+
+# define RULE_NEWSRCS 0x01 /* $(>) is updated sources only */
+# define RULE_TOGETHER 0x02 /* combine actions on single target */
+# define RULE_IGNORE 0x04 /* ignore return status of executes */
+# define RULE_QUIETLY 0x08 /* don't mention it unless verbose */
+# define RULE_PIECEMEAL 0x10 /* split exec so each $(>) is small */
+# define RULE_EXISTING 0x20 /* $(>) is pre-exisitng sources only */
+};
+
+typedef struct rule_actions rule_actions;
+typedef struct argument_list argument_list;
+
+struct _rule {
+ char *name;
+ PARSE *procedure; /* parse tree from RULE */
+ argument_list* arguments; /* argument checking info, or NULL for unchecked */
+ rule_actions* actions; /* build actions, or NULL for no actions */
+} ;
+
+/* ACTIONS - a chain of ACTIONs */
+
+struct _actions {
+ ACTIONS *next;
+ ACTIONS *tail; /* valid only for head */
+ ACTION *action;
+} ;
+
+/* ACTION - a RULE instance with targets and sources */
+
+struct _action {
+ RULE *rule;
+ TARGETS *targets;
+ TARGETS *sources; /* aka $(>) */
+ char running; /* has been started */
+ char status; /* see TARGET status */
+} ;
+
+/* SETTINGS - variables to set when executing a TARGET's ACTIONS */
+
+struct _settings {
+ SETTINGS *next;
+ char *symbol; /* symbol name for var_set() */
+ LIST *value; /* symbol value for var_set() */
+} ;
+
+/* TARGETS - a chain of TARGETs */
+
+struct _targets {
+ TARGETS *next;
+ TARGETS *tail; /* valid only for head */
+ TARGET *target;
+} ;
+
+/* TARGET - a file or "thing" that can be built */
+
+struct _target {
+ char *name;
+ char *boundname; /* if search() relocates target */
+ ACTIONS *actions; /* rules to execute, if any */
+ SETTINGS *settings; /* variables to define */
+
+ char flags; /* status info */
+
+# define T_FLAG_TEMP 0x01 /* TEMPORARY applied */
+# define T_FLAG_NOCARE 0x02 /* NOCARE applied */
+# define T_FLAG_NOTFILE 0x04 /* NOTFILE applied */
+# define T_FLAG_TOUCHED 0x08 /* ALWAYS applied or -t target */
+# define T_FLAG_LEAVES 0x10 /* LEAVES applied */
+# define T_FLAG_NOUPDATE 0x20 /* NOUPDATE applied */
+
+/* this flag was added to support a new builting rule named "FAIL_EXPECTED" */
+/* it is used to indicate that the result of running a given action should */
+/* be inverted (i.e. ok <=> fail). This is useful to launch certain test */
+/* runs from a Jamfile.. */
+/* */
+# define T_FLAG_FAIL_EXPECTED 0x40 /* FAIL_EXPECTED applied */
+
+ char binding; /* how target relates to real file */
+
+# define T_BIND_UNBOUND 0 /* a disembodied name */
+# define T_BIND_MISSING 1 /* couldn't find real file */
+# define T_BIND_PARENTS 2 /* using parent's timestamp */
+# define T_BIND_EXISTS 3 /* real file, timestamp valid */
+
+ TARGETS *deps[2]; /* dependencies, with possible
+ * duplicates. Element 1 holds
+ * dependencies generated by INCLUDES */
+
+# define T_DEPS_DEPENDS 0 /* due to DEPENDS */
+# define T_DEPS_INCLUDES 1 /* due to INCLUDES */
+
+ time_t time; /* update time */
+ time_t leaf; /* update time of leaf sources */
+ time_t htime; /* header's time */
+ time_t hleaf; /* update time of leaf headers */
+
+ char fate; /* make0()'s diagnosis */
+ char hfate; /* collected fate for headers */
+
+# define T_FATE_INIT 0 /* nothing done to target */
+# define T_FATE_MAKING 1 /* make0(target) on stack */
+
+# define T_FATE_STABLE 2 /* target didn't need updating */
+# define T_FATE_NEWER 3 /* target newer than parent */
+
+# define T_FATE_SPOIL 4 /* >= SPOIL rebuilds parents */
+# define T_FATE_ISTMP 4 /* unneeded temp target oddly present */
+
+# define T_FATE_BUILD 5 /* >= BUILD rebuilds target */
+# define T_FATE_TOUCHED 5 /* manually touched with -t */
+# define T_FATE_MISSING 6 /* is missing, needs updating */
+# define T_FATE_OUTDATED 7 /* is out of date, needs updating */
+# define T_FATE_UPDATE 8 /* deps updated, needs updating */
+
+# define T_FATE_BROKEN 9 /* >= BROKEN ruins parents */
+# define T_FATE_CANTFIND 9 /* no rules to make missing target */
+# define T_FATE_CANTMAKE 10 /* can't find dependents */
+
+ char progress; /* tracks make1() progress */
+
+# define T_MAKE_INIT 0 /* make1(target) not yet called */
+# define T_MAKE_ONSTACK 1 /* make1(target) on stack */
+# define T_MAKE_ACTIVE 2 /* make1(target) in make1b() */
+# define T_MAKE_RUNNING 3 /* make1(target) running commands */
+# define T_MAKE_DONE 4 /* make1(target) done */
+
+ char status; /* execcmd() result */
+
+ int asynccnt; /* child deps outstanding */
+ TARGETS *parents; /* used by make1() for completion */
+ char *cmds; /* type-punned command list */
+} ;
+
+RULE *bindrule( char *rulename, module* );
+
+RULE* import_rule( RULE* source, module* m, char* name );
+RULE* new_rule_body( module* m, char* rulename, argument_list* args, PARSE* procedure );
+RULE* new_rule_actions( module* m, char* rulename, char* command, LIST* bindlist, int flags );
+TARGET *bindtarget( char *targetname );
+void touchtarget( char *t );
+TARGETS *targetlist( TARGETS *chain, LIST *targets );
+TARGETS *targetentry( TARGETS *chain, TARGET *target );
+ACTIONS *actionlist( ACTIONS *chain, ACTION *action );
+SETTINGS *addsettings( SETTINGS *head, int append, char *symbol, LIST *value );
+void pushsettings( SETTINGS *v );
+void popsettings( SETTINGS *v );
+void freesettings( SETTINGS *v );
+void donerules();
+
+argument_list* args_new();
+void args_refer( argument_list* );
+void args_free( argument_list* );
+
+void actions_refer(rule_actions*);
+void actions_free(rule_actions*);
+
+#endif // RULES_DWA_20011020_H
diff --git a/historic/jam/src/scan.c b/historic/jam/src/scan.c
new file mode 100644
index 000000000..f26f99204
--- /dev/null
+++ b/historic/jam/src/scan.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "scan.h"
+# include "jamgram.h"
+# include "jambase.h"
+# include "newstr.h"
+
+/*
+ * scan.c - the jam yacc scanner
+ *
+ * 12/26/93 (seiwald) - bump buf in yylex to 10240 - yuk.
+ * 09/16/94 (seiwald) - check for overflows, unmatched {}'s, etc.
+ * Also handle tokens abutting EOF by remembering
+ * to return EOF now matter how many times yylex()
+ * reinvokes yyline().
+ * 02/11/95 (seiwald) - honor only punctuation keywords if SCAN_PUNCT.
+ * 07/27/95 (seiwald) - Include jamgram.h after scan.h, so that YYSTYPE is
+ * defined before Linux's yacc tries to redefine it.
+ */
+
+struct keyword {
+ char *word;
+ int type;
+} keywords[] = {
+# include "jamgramtab.h"
+ { 0, 0 }
+} ;
+
+struct include {
+ struct include *next; /* next serial include file */
+ char *string; /* pointer into current line */
+ char **strings; /* for yyfparse() -- text to parse */
+ FILE *file; /* for yyfparse() -- file being read */
+ char *fname; /* for yyfparse() -- file name */
+ int line; /* line counter for error messages */
+ char buf[ 512 ]; /* for yyfparse() -- line buffer */
+} ;
+
+static struct include *incp = 0; /* current file; head of chain */
+
+static int scanmode = SCAN_NORMAL;
+static int anyerrors = 0;
+static char *symdump( YYSTYPE *s );
+
+# define BIGGEST_TOKEN 10240 /* no single token can be larger */
+
+/*
+ * Set parser mode: normal, string, or keyword
+ */
+
+void
+yymode( int n )
+{
+ scanmode = n;
+}
+
+void
+yyerror( char *s )
+{
+ if( incp )
+ printf( "%s: line %d: ", incp->fname, incp->line );
+
+ printf( "%s at %s\n", s, symdump( &yylval ) );
+
+ ++anyerrors;
+}
+
+int
+yyanyerrors()
+{
+ return anyerrors != 0;
+}
+
+void
+yyfparse( char *s )
+{
+ struct include *i = (struct include *)malloc( sizeof( *i ) );
+
+ /* Push this onto the incp chain. */
+
+ i->string = "";
+ i->strings = 0;
+ i->file = 0;
+ i->fname = copystr( s );
+ i->line = 0;
+ i->next = incp;
+ incp = i;
+
+ /* If the filename is "+", it means use the internal jambase. */
+
+ if( !strcmp( s, "+" ) )
+ i->strings = jambase;
+}
+
+/*
+ * yyline() - read new line and return first character
+ *
+ * Fabricates a continuous stream of characters across include files,
+ * returning EOF at the bitter end.
+ */
+
+int
+yyline()
+{
+ struct include *i = incp;
+
+ if( !incp )
+ return EOF;
+
+ /* Once we start reading from the input stream, we reset the */
+ /* include insertion point so that the next include file becomes */
+ /* the head of the list. */
+
+ /* If there is more data in this line, return it. */
+
+ if( *i->string )
+ return *i->string++;
+
+ /* If we're reading from an internal string list, go to the */
+ /* next string. */
+
+ if( i->strings )
+ {
+ if( !*i->strings )
+ goto next;
+
+ i->line++;
+ i->string = *(i->strings++);
+ return *i->string++;
+ }
+
+ /* If necessary, open the file */
+
+ if( !i->file )
+ {
+ FILE *f = stdin;
+
+ if( strcmp( i->fname, "-" ) && !( f = fopen( i->fname, "r" ) ) )
+ perror( i->fname );
+
+ i->file = f;
+ }
+
+ /* If there's another line in this file, start it. */
+
+ if( i->file && fgets( i->buf, sizeof( i->buf ), i->file ) )
+ {
+ i->line++;
+ i->string = i->buf;
+ return *i->string++;
+ }
+
+ next:
+ /* This include is done. */
+ /* Free it up and return EOF so yyparse() returns to parse_file(). */
+
+ incp = i->next;
+
+ /* Close file, free name */
+
+ if( i->file && i->file != stdin )
+ fclose( i->file );
+ freestr( i->fname );
+ free( (char *)i );
+
+ return EOF;
+}
+
+/*
+ * yylex() - set yylval to current token; return its type
+ *
+ * Macros to move things along:
+ *
+ * yychar() - return and advance character; invalid after EOF
+ * yyprev() - back up one character; invalid before yychar()
+ *
+ * yychar() returns a continuous stream of characters, until it hits
+ * the EOF of the current include file.
+ */
+
+# define yychar() ( *incp->string ? *incp->string++ : yyline() )
+# define yyprev() ( incp->string-- )
+
+int
+yylex()
+{
+ int c;
+ char buf[BIGGEST_TOKEN];
+ char *b = buf;
+
+ if( !incp )
+ goto eof;
+
+ /* Get first character (whitespace or of token) */
+
+ c = yychar();
+
+ if( scanmode == SCAN_STRING )
+ {
+ /* If scanning for a string (action's {}'s), look for the */
+ /* closing brace. We handle matching braces, if they match! */
+
+ int nest = 1;
+
+ while( c != EOF && b < buf + sizeof( buf ) )
+ {
+ if( c == '{' )
+ nest++;
+
+ if( c == '}' && !--nest )
+ break;
+
+ *b++ = c;
+
+ c = yychar();
+ }
+
+ /* We ate the ending brace -- regurgitate it. */
+
+ if( c != EOF )
+ yyprev();
+
+ /* Check obvious errors. */
+
+ if( b == buf + sizeof( buf ) )
+ {
+ yyerror( "action block too big" );
+ goto eof;
+ }
+
+ if( nest )
+ {
+ yyerror( "unmatched {} in action block" );
+ goto eof;
+ }
+
+ *b = 0;
+ yylval.type = STRING;
+ yylval.string = newstr( buf );
+
+ }
+ else
+ {
+ char *b = buf;
+ int inquote = 0;
+ int literal = 0;
+ int hasquote = 0;
+ struct keyword *k;
+
+ /* Eat white space */
+
+ for( ;; )
+ {
+ /* Skip past white space */
+
+ while( c != EOF && isspace( c ) )
+ c = yychar();
+
+ /* Not a comment? Swallow up comment line. */
+
+ if( c != '#' )
+ break;
+ while( ( c = yychar() ) != EOF && c != '\n' )
+ ;
+ }
+
+ /* c now points to the first character of a token. */
+
+ if( c == EOF )
+ goto eof;
+
+ /* look for white space to delimit word */
+ /* "'s get stripped but preserve white space */
+
+ while( b < buf + sizeof( buf ) )
+ {
+ if( literal )
+ *b++ = c, literal = 0;
+ else if( c == '\\' )
+ literal++;
+ else if( c == '"' )
+ inquote = !inquote, hasquote++;
+ else
+ *b++ = c;
+
+ if( ( c = yychar() ) == EOF || !inquote && isspace( c ) )
+ break;
+ }
+
+ /* Check obvious errors. */
+
+ if( b == buf + sizeof( buf ) )
+ {
+ yyerror( "string too big" );
+ goto eof;
+ }
+
+ if( inquote )
+ {
+ yyerror( "unmatched \" in string" );
+ goto eof;
+ }
+
+ /* We looked ahead a character - back up. */
+
+ if( c != EOF )
+ yyprev();
+
+ /* scan token table */
+ /* don't scan if it's "anything", $anything, */
+ /* or an alphabetic when were looking for punctuation */
+
+ *b = 0;
+ yylval.type = ARG;
+
+ if( !hasquote &&
+ *buf != '$' &&
+ !( isalpha( *buf ) && scanmode == SCAN_PUNCT ) )
+ {
+ for( k = keywords; k->word; k++ )
+ if( *buf == *k->word && !strcmp( k->word, buf ) )
+ {
+ yylval.type = k->type;
+ yylval.string = k->word; /* used by symdump */
+ break;
+ }
+ }
+
+ if( yylval.type == ARG )
+ yylval.string = newstr( buf );
+ }
+
+ if( DEBUG_SCAN )
+ printf( "scan %s\n", symdump( &yylval ) );
+
+ return yylval.type;
+
+eof:
+ yylval.type = EOF;
+ return yylval.type;
+}
+
+static char *
+symdump( YYSTYPE *s )
+{
+ static char buf[ BIGGEST_TOKEN + 20 ];
+
+ switch( s->type )
+ {
+ case EOF:
+ sprintf( buf, "EOF" );
+ break;
+ case 0:
+ sprintf( buf, "unknown symbol %s", s->string );
+ break;
+ case ARG:
+ sprintf( buf, "argument %s", s->string );
+ break;
+ case STRING:
+ sprintf( buf, "string \"%s\"", s->string );
+ break;
+ default:
+ sprintf( buf, "keyword %s", s->string );
+ break;
+ }
+ return buf;
+}
diff --git a/historic/jam/src/scan.h b/historic/jam/src/scan.h
new file mode 100644
index 000000000..37b026f1f
--- /dev/null
+++ b/historic/jam/src/scan.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * scan.h - the jam yacc scanner
+ *
+ * External functions:
+ *
+ * yyerror( char *s ) - print a parsing error message
+ * yyfparse( char *s ) - scan include file s
+ * yylex() - parse the next token, returning its type
+ * yymode() - adjust lexicon of scanner
+ * yyparse() - declaration for yacc parser
+ * yyanyerrors() - indicate if any parsing errors occured
+ *
+ * The yymode() function is for the parser to adjust the lexicon of the
+ * scanner. Aside from normal keyword scanning, there is a mode to
+ * handle action strings (look only for the closing }) and a mode to
+ * ignore most keywords when looking for a punctuation keyword. This
+ * allows non-punctuation keywords to be used in lists without quoting.
+ */
+
+/*
+ * YYSTYPE - value of a lexical token
+ */
+
+# define YYSTYPE YYSYMBOL
+
+typedef struct _YYSTYPE {
+ int type;
+ char *string;
+ PARSE *parse;
+ LIST *list;
+ int number;
+} YYSTYPE;
+
+extern YYSTYPE yylval;
+
+void yymode( int n );
+void yyerror( char *s );
+int yyanyerrors();
+void yyfparse( char *s );
+int yyline();
+int yylex();
+int yyparse();
+
+# define SCAN_NORMAL 0 /* normal parsing */
+# define SCAN_STRING 1 /* look only for matching } */
+# define SCAN_PUNCT 2 /* only punctuation keywords */
diff --git a/historic/jam/src/search.c b/historic/jam/src/search.c
new file mode 100644
index 000000000..b92f12961
--- /dev/null
+++ b/historic/jam/src/search.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "search.h"
+# include "timestamp.h"
+# include "filesys.h"
+# include "variable.h"
+# include "newstr.h"
+# include "compile.h"
+# include "strings.h"
+# include
+
+static void call_bind_rule(
+ char* target_,
+ char* boundname_ )
+{
+ LIST* bind_rule = var_get( "BINDRULE" );
+ if( bind_rule )
+ {
+ /* No guarantee that target is an allocated string, so be on the
+ * safe side */
+ char* target = copystr( target_ );
+
+ /* Likewise, don't rely on implementation details of newstr.c: allocate
+ * a copy of boundname */
+ char* boundname = copystr( boundname_ );
+ if( boundname && target )
+ {
+ /* Prepare the argument list */
+ FRAME frame[1];
+ frame_init( frame );
+
+ /* First argument is the target name */
+ lol_add( frame->args, list_new( L0, target ) );
+
+ lol_add( frame->args, list_new( L0, boundname ) );
+ if( lol_get( frame->args, 1 ) )
+ evaluate_rule( bind_rule->string, frame );
+
+ /* Clean up */
+ frame_free( frame );
+ }
+ else
+ {
+ if( boundname )
+ freestr( boundname );
+ if( target )
+ freestr( target );
+ }
+ }
+}
+
+/*
+ * search.c - find a target along $(SEARCH) or $(LOCATE)
+ */
+
+char *
+search(
+ char *target,
+ time_t *time )
+{
+ FILENAME f[1];
+ LIST *varlist;
+ string buf[1];
+ int found = 0;
+ char *boundname = 0;
+
+ string_new( buf );
+ /* Parse the filename */
+
+ file_parse( target, f );
+
+ f->f_grist.ptr = 0;
+ f->f_grist.len = 0;
+
+ if( varlist = var_get( "LOCATE" ) )
+ {
+ f->f_root.ptr = varlist->string;
+ f->f_root.len = strlen( varlist->string );
+
+ file_build( f, buf, 1 );
+
+ if( DEBUG_SEARCH )
+ printf( "locate %s: %s\n", target, buf->value );
+
+ timestamp( buf->value, time );
+ found = 1;
+ }
+ else if( varlist = var_get( "SEARCH" ) )
+ {
+ while( varlist )
+ {
+ f->f_root.ptr = varlist->string;
+ f->f_root.len = strlen( varlist->string );
+
+ string_truncate( buf, 0 );
+ file_build( f, buf, 1 );
+
+ if( DEBUG_SEARCH )
+ printf( "search %s: %s\n", target, buf->value );
+
+ timestamp( buf->value, time );
+
+ if( *time )
+ {
+ found = 1;
+ break;
+ }
+
+ varlist = list_next( varlist );
+ }
+ }
+
+ if (!found)
+ {
+ /* Look for the obvious */
+ /* This is a questionable move. Should we look in the */
+ /* obvious place if SEARCH is set? */
+
+ f->f_root.ptr = 0;
+ f->f_root.len = 0;
+
+ string_truncate( buf, 0 );
+ file_build( f, buf, 1 );
+
+ if( DEBUG_SEARCH )
+ printf( "search %s: %s\n", target, buf->value );
+
+ timestamp( buf->value, time );
+ }
+
+ boundname = newstr( buf->value );
+ string_free( buf );
+
+ /* prepare a call to BINDRULE if the variable is set */
+ call_bind_rule( target, boundname );
+
+ return boundname;
+}
diff --git a/historic/jam/src/search.h b/historic/jam/src/search.h
new file mode 100644
index 000000000..bb8035723
--- /dev/null
+++ b/historic/jam/src/search.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * search.h - find a target along $(SEARCH) or $(LOCATE)
+ */
+
+char *search( char *target, time_t *time );
diff --git a/historic/jam/src/strings.c b/historic/jam/src/strings.c
new file mode 100644
index 000000000..7760d1fac
--- /dev/null
+++ b/historic/jam/src/strings.c
@@ -0,0 +1,142 @@
+#include "strings.h"
+#include
+#include
+#include
+
+#ifndef NDEBUG
+static void assert_invariants( string* self )
+{
+ assert( self->size < self->capacity );
+ assert( ( self->capacity <= sizeof(self->opt) ) == ( self->value == self->opt ) );
+ assert( strlen( self->value ) == self->size );
+}
+#else
+# define assert_invariants(x) do {} while (0)
+#endif
+
+void string_new( string* s )
+{
+ s->value = s->opt;
+ s->size = 0;
+ s->capacity = sizeof(s->opt);
+ s->opt[0] = 0;
+ assert_invariants( s );
+}
+
+void string_free( string* s )
+{
+ assert_invariants( s );
+ if ( s->value != s->opt )
+ free( s->value );
+}
+
+static void string_reserve_internal( string* self, size_t capacity )
+{
+ if ( self->value == self->opt )
+ {
+ self->value = malloc( capacity );
+ self->value[0] = 0;
+ strcat( self->value, self->opt );
+ }
+ else
+ {
+ self->value = realloc( self->value, capacity );
+ }
+ self->capacity = capacity;
+}
+
+void string_reserve( string* self, size_t capacity )
+{
+ assert_invariants( self );
+ if ( capacity <= self->capacity )
+ return;
+ string_reserve_internal( self, capacity );
+ assert_invariants( self );
+}
+
+static void extend_full( string* self, char* start, char *finish )
+{
+ size_t new_size = self->capacity + ( finish - start );
+ size_t new_capacity = self->capacity;
+ size_t old_size = self->capacity;
+ while ( new_capacity < new_size + 1)
+ new_capacity <<= 1;
+ string_reserve_internal( self, new_capacity );
+ memcpy( self->value + old_size, start, new_size - old_size );
+ self->value[new_size] = 0;
+ self->size = new_size;
+}
+
+void string_append( string* self, char* rhs )
+{
+ char* p = self->value + self->size;
+ char* end = self->value + self->capacity;
+ assert_invariants( self );
+
+ while ( *rhs && p != end)
+ *p++ = *rhs++;
+
+ if ( p != end )
+ {
+ *p = 0;
+ self->size = p - self->value;
+ }
+ else
+ {
+ extend_full( self, rhs, rhs + strlen(rhs) );
+ }
+ assert_invariants( self );
+}
+
+void string_append_range( string* self, char* start, char* finish )
+{
+ char* p = self->value + self->size;
+ char* end = self->value + self->capacity;
+ assert_invariants( self );
+
+ while ( p != end && start != finish )
+ *p++ = *start++;
+
+ if ( p != end )
+ {
+ *p = 0;
+ self->size = p - self->value;
+ }
+ else
+ {
+ extend_full( self, start, finish );
+ }
+ assert_invariants( self );
+}
+
+void string_copy( string* s, char* rhs )
+{
+ string_new( s );
+ string_append( s, rhs );
+}
+
+void string_truncate( string* self, size_t n )
+{
+ assert_invariants( self );
+ assert( n <= self->capacity );
+ self->value[self->size = n] = 0;
+ assert_invariants( self );
+}
+
+void string_pop_back( string* self )
+{
+ string_truncate( self, self->size - 1 );
+}
+
+void string_push_back( string* self, char x )
+{
+ assert_invariants( self );
+ string_append_range( self, &x, &x + 1 );
+ assert_invariants( self );
+}
+
+char string_back( string* self )
+{
+ assert_invariants( self );
+ return self->value[self->size - 1];
+}
diff --git a/historic/jam/src/strings.h b/historic/jam/src/strings.h
new file mode 100644
index 000000000..6854eaaac
--- /dev/null
+++ b/historic/jam/src/strings.h
@@ -0,0 +1,25 @@
+#ifndef STRINGS_DWA20011024_H
+# define STRINGS_DWA20011024_H
+
+# include
+
+typedef struct string
+{
+ char* value;
+ unsigned long size;
+ unsigned long capacity;
+ char opt[32];
+} string;
+
+void string_new( string* );
+void string_copy( string*, char* );
+void string_free( string* );
+void string_append( string*, char* );
+void string_append_range( string*, char*, char* );
+void string_push_back( string* s, char x );
+void string_reserve( string*, size_t );
+void string_truncate( string*, size_t );
+void string_pop_back( string* );
+char string_back( string* );
+
+#endif // STRINGS_DWA20011024_H
diff --git a/historic/jam/src/subst.c b/historic/jam/src/subst.c
new file mode 100644
index 000000000..471b8a563
--- /dev/null
+++ b/historic/jam/src/subst.c
@@ -0,0 +1,92 @@
+#include
+#include "regexp.h"
+#include "hash.h"
+
+#include "newstr.h"
+#include "lists.h"
+#include "parse.h"
+#include "compile.h"
+#include "frames.h"
+
+struct regex_entry
+{
+ const char* pattern;
+ regexp* regex;
+};
+typedef struct regex_entry regex_entry;
+
+static struct hash* regex_hash;
+
+regexp* regex_compile( const char* pattern )
+{
+ regex_entry entry, *e = &entry;
+ entry.pattern = pattern;
+
+ if ( !regex_hash )
+ regex_hash = hashinit(sizeof(regex_entry), "regex");
+
+ if ( hashenter( regex_hash, (HASHDATA **)&e ) )
+ e->regex = regcomp( (char*)pattern );
+
+ return e->regex;
+}
+
+LIST*
+builtin_subst(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST* result = L0;
+ LIST* arg1 = lol_get( frame->args, 0 );
+
+ if ( arg1 && list_next(arg1) && list_next(list_next(arg1)) )
+ {
+
+ const char* source = arg1->string;
+ const char* pattern = list_next(arg1)->string;
+ regexp* repat = regex_compile( pattern );
+
+ if ( regexec( repat, (char*)source) )
+ {
+ LIST* subst = list_next(arg1);
+
+ while ((subst = list_next(subst)) != L0)
+ {
+# define BUFLEN 4096
+ char buf[BUFLEN + 1];
+ const char* in = subst->string;
+ char* out = buf;
+
+ for ( in = subst->string; *in && out < buf + BUFLEN; ++in )
+ {
+ if ( *in == '\\' || *in == '$' )
+ {
+ ++in;
+ if ( *in == 0 )
+ {
+ break;
+ }
+ else if ( *in >= '0' && *in <= '9' )
+ {
+ unsigned n = *in - '0';
+ const size_t srclen = repat->endp[n] - repat->startp[n];
+ const size_t remaining = buf + BUFLEN - out;
+ const size_t len = srclen < remaining ? srclen : remaining;
+ memcpy( out, repat->startp[n], len );
+ out += len;
+ continue;
+ }
+ /* fall through and copy the next character */
+ }
+ *out++ = *in;
+ }
+ *out = 0;
+
+ result = list_new( result, newstr( buf ) );
+#undef BUFLEN
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/historic/jam/src/timestamp.c b/historic/jam/src/timestamp.c
new file mode 100644
index 000000000..3bd87d086
--- /dev/null
+++ b/historic/jam/src/timestamp.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "hash.h"
+# include "filesys.h"
+# include "timestamp.h"
+# include "newstr.h"
+# include "strings.h"
+
+/*
+ * timestamp.c - get the timestamp of a file or archive member
+ *
+ * 09/22/00 (seiwald) - downshift names on OS2, too
+ */
+
+/*
+ * BINDING - all known files
+ */
+
+typedef struct _binding BINDING;
+
+struct _binding {
+ char *name;
+ short flags;
+
+# define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
+
+ short progress;
+
+# define BIND_INIT 0 /* never seen */
+# define BIND_NOENTRY 1 /* timestamp requested but file never found */
+# define BIND_SPOTTED 2 /* file found but not timed yet */
+# define BIND_MISSING 3 /* file found but can't get timestamp */
+# define BIND_FOUND 4 /* file found and time stamped */
+
+ time_t time; /* update time - 0 if not exist */
+} ;
+
+static struct hash *bindhash = 0;
+static void time_enter( char *target, int found, time_t time );
+
+static char *time_progress[] =
+{
+ "INIT",
+ "NOENTRY",
+ "SPOTTED",
+ "MISSING",
+ "FOUND"
+} ;
+
+
+/*
+ * timestamp() - return timestamp on a file, if present
+ */
+
+void
+timestamp(
+ char *target,
+ time_t *time )
+{
+ FILENAME f1, f2;
+ BINDING binding, *b = &binding;
+ string buf[1];
+
+# ifdef DOWNSHIFT_PATHS
+ string path;
+ char *p;
+
+ string_copy( &path, target );
+ p = path.value;
+
+ do
+ *p = tolower( *p );
+ while( *p++ );
+
+ target = path.value;
+# endif
+ string_new( buf );
+
+ if( !bindhash )
+ bindhash = hashinit( sizeof( BINDING ), "bindings" );
+
+ /* Quick path - is it there? */
+
+ b->name = target;
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+
+ if( hashenter( bindhash, (HASHDATA **)&b ) )
+ b->name = newstr( target ); /* never freed */
+
+ if( b->progress != BIND_INIT )
+ goto afterscanning;
+
+ b->progress = BIND_NOENTRY;
+
+ /* Not found - have to scan for it */
+
+ file_parse( target, &f1 );
+
+ /* Scan directory if not already done so */
+
+ {
+ BINDING binding, *b = &binding;
+
+ f2 = f1;
+ f2.f_grist.len = 0;
+ file_parent( &f2 );
+ file_build( &f2, buf, 0 );
+
+ b->name = buf->value;
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+
+ if( hashenter( bindhash, (HASHDATA **)&b ) )
+ b->name = newstr( buf->value ); /* never freed */
+
+ if( !( b->flags & BIND_SCANNED ) )
+ {
+ file_dirscan( buf->value, time_enter );
+ b->flags |= BIND_SCANNED;
+ }
+ }
+
+ /* Scan archive if not already done so */
+
+ if( f1.f_member.len )
+ {
+ BINDING binding, *b = &binding;
+
+ f2 = f1;
+ f2.f_grist.len = 0;
+ f2.f_member.len = 0;
+ string_truncate( buf, 0 );
+ file_build( &f2, buf, 0 );
+
+ b->name = buf->value;
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+
+ if( hashenter( bindhash, (HASHDATA **)&b ) )
+ b->name = newstr( buf->value ); /* never freed */
+
+ if( !( b->flags & BIND_SCANNED ) )
+ {
+ file_archscan( buf->value, time_enter );
+ b->flags |= BIND_SCANNED;
+ }
+ }
+
+ afterscanning:
+
+ if( b->progress == BIND_SPOTTED )
+ {
+ if( file_time( b->name, &b->time ) < 0 )
+ b->progress = BIND_MISSING;
+ else
+ b->progress = BIND_FOUND;
+ }
+
+ *time = b->progress == BIND_FOUND ? b->time : 0;
+ string_free( buf );
+# ifdef DOWNSHIFT_PATHS
+ string_free( &path );
+#endif
+}
+
+static void
+time_enter(
+ char *target,
+ int found,
+ time_t time )
+{
+ BINDING binding, *b = &binding;
+
+# ifdef DOWNSHIFT_PATHS
+ char path[ MAXJPATH ];
+ char *p = path;
+
+ do *p++ = tolower( *target );
+ while( *target++ );
+
+ target = path;
+# endif
+
+ b->name = target;
+ b->flags = 0;
+
+ if( hashenter( bindhash, (HASHDATA **)&b ) )
+ b->name = newstr( target ); /* never freed */
+
+ b->time = time;
+ b->progress = found ? BIND_FOUND : BIND_SPOTTED;
+
+ if( DEBUG_BINDSCAN )
+ printf( "time ( %s ) : %s\n", target, time_progress[b->progress] );
+}
+
+/*
+ * donestamps() - free timestamp tables
+ */
+
+void
+donestamps()
+{
+ hashdone( bindhash );
+}
diff --git a/historic/jam/src/timestamp.h b/historic/jam/src/timestamp.h
new file mode 100644
index 000000000..f290f82cb
--- /dev/null
+++ b/historic/jam/src/timestamp.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * timestamp.h - get the timestamp of a file or archive member
+ */
+
+void timestamp( char *target, time_t *time );
+void donestamps();
diff --git a/historic/jam/src/variable.c b/historic/jam/src/variable.c
new file mode 100644
index 000000000..9dccea7fd
--- /dev/null
+++ b/historic/jam/src/variable.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "expand.h"
+# include "hash.h"
+# include "filesys.h"
+# include "newstr.h"
+# include "strings.h"
+
+/*
+ * variable.c - handle jam multi-element variables
+ *
+ * External routines:
+ *
+ * var_defines() - load a bunch of variable=value settings
+ * var_string() - expand a string with variables in it
+ * var_get() - get value of a user defined symbol
+ * var_set() - set a variable in jam's user defined symbol table
+ * var_swap() - swap a variable's value with the given one
+ * var_done() - free variable tables
+ *
+ * Internal routines:
+ *
+ * var_enter() - make new var symbol table entry, returning var ptr
+ * var_dump() - dump a variable to stdout
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ * 01/22/95 (seiwald) - split environment variables at blanks or :'s
+ * 05/10/95 (seiwald) - split path variables at SPLITPATH (not :)
+ * 09/11/00 (seiwald) - defunct var_list() removed
+ */
+
+static struct hash *varhash = 0;
+
+/*
+ * VARIABLE - a user defined multi-value variable
+ */
+
+typedef struct _variable VARIABLE ;
+
+struct _variable {
+ char *symbol;
+ LIST *value;
+} ;
+
+static VARIABLE *var_enter( char *symbol );
+static void var_dump( char *symbol, LIST *value, char *what );
+
+
+
+/*
+ * var_defines() - load a bunch of variable=value settings
+ *
+ * If variable name ends in PATH, split value at :'s.
+ * Otherwise, split at blanks.
+ */
+
+void
+var_defines( char **e )
+{
+ string buf[1];
+
+ string_new( buf );
+
+ for( ; *e; e++ )
+ {
+ char *val;
+
+ /* Just say "no": windows defines this in the env, */
+ /* but we don't want it to override our notion of OS. */
+
+ if( !strcmp( *e, "OS=Windows_NT" ) )
+ continue;
+
+# ifdef OS_MAC
+ /* On the mac (MPW), the var=val is actually var\0val */
+ /* Think different. */
+
+ if( ( val = strchr( *e, '=' ) ) || ( val = *e + strlen( *e ) ) )
+# else
+ if( val = strchr( *e, '=' ) )
+# endif
+ {
+ LIST *l = L0;
+ char *pp, *p;
+# ifdef OS_MAC
+ char split = ',';
+# else
+ char split = ' ';
+# endif
+ /* Split *PATH at :'s, not spaces */
+
+ if( val - 4 >= *e )
+ {
+ if( !strncmp( val - 4, "PATH", 4 ) ||
+ !strncmp( val - 4, "Path", 4 ) ||
+ !strncmp( val - 4, "path", 4 ) )
+ split = SPLITPATH;
+ }
+
+ /* Do the split */
+
+ for( pp = val + 1; p = strchr( pp, split ); pp = p + 1 )
+ {
+ string_append_range( buf, pp, p );
+ l = list_new( l, newstr( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+
+ l = list_new( l, newstr( pp ) );
+
+ /* Get name */
+ string_append_range( buf, *e, val );
+ var_set( buf->value, l, VAR_SET );
+ string_truncate( buf, 0 );
+ }
+ }
+ string_free( buf );
+}
+
+/*
+ * var_string() - expand a string with variables in it
+ *
+ * Copies in to out; doesn't modify targets & sources.
+ */
+
+int
+var_string(
+ char *in,
+ char *out,
+ int outsize,
+ LOL *lol )
+{
+ char *out0 = out;
+ char *oute = out + outsize - 1;
+
+ while( *in )
+ {
+ char *lastword;
+ int dollar = 0;
+
+ /* Copy white space */
+
+ while( isspace( *in ) )
+ {
+ if( out >= oute )
+ return -1;
+
+ *out++ = *in++;
+ }
+
+ lastword = out;
+
+ /* Copy non-white space, watching for variables */
+
+ while( *in && !isspace( *in ) )
+ {
+ if( out >= oute )
+ return -1;
+
+ if( in[0] == '$' && in[1] == '(' )
+ dollar++;
+
+ *out++ = *in++;
+ }
+
+ /* If a variable encountered, expand it and and embed the */
+ /* space-separated members of the list in the output. */
+
+ if( dollar )
+ {
+ LIST *l;
+
+ l = var_expand( L0, lastword, out, lol, 0 );
+
+ out = lastword;
+
+ for( ; l; l = list_next( l ) )
+ {
+ int so = strlen( l->string );
+
+ if( out + so >= oute )
+ return -1;
+
+ strcpy( out, l->string );
+ out += so;
+ *out++ = ' ';
+ }
+
+ list_free( l );
+ }
+ }
+
+ if( out >= oute )
+ return -1;
+
+ *out++ = '\0';
+
+ return out - out0;
+}
+
+/*
+ * var_get() - get value of a user defined symbol
+ *
+ * Returns NULL if symbol unset.
+ */
+
+LIST *
+var_get( char *symbol )
+{
+ VARIABLE var, *v = &var;
+
+ v->symbol = symbol;
+
+ if( varhash && hashcheck( varhash, (HASHDATA **)&v ) )
+ {
+ if( DEBUG_VARGET )
+ var_dump( v->symbol, v->value, "get" );
+ return v->value;
+ }
+
+ return 0;
+}
+
+/*
+ * var_set() - set a variable in jam's user defined symbol table
+ *
+ * 'flag' controls the relationship between new and old values of
+ * the variable: SET replaces the old with the new; APPEND appends
+ * the new to the old; DEFAULT only uses the new if the variable
+ * was previously unset.
+ *
+ * Copies symbol. Takes ownership of value.
+ */
+
+void
+var_set(
+ char *symbol,
+ LIST *value,
+ int flag )
+{
+ VARIABLE *v = var_enter( symbol );
+
+ if( DEBUG_VARSET )
+ var_dump( symbol, value, "set" );
+
+ switch( flag )
+ {
+ case VAR_SET:
+ /* Replace value */
+ list_free( v->value );
+ v->value = value;
+ break;
+
+ case VAR_APPEND:
+ /* Append value */
+ v->value = list_append( v->value, value );
+ break;
+
+ case VAR_DEFAULT:
+ /* Set only if unset */
+ if( !v->value )
+ v->value = value;
+ else
+ list_free( value );
+ break;
+ }
+}
+
+/*
+ * var_swap() - swap a variable's value with the given one
+ */
+
+LIST *
+var_swap(
+ char *symbol,
+ LIST *value )
+{
+ VARIABLE *v = var_enter( symbol );
+ LIST *oldvalue = v->value;
+
+ if( DEBUG_VARSET )
+ var_dump( symbol, value, "set" );
+
+ v->value = value;
+
+ return oldvalue;
+}
+
+
+
+/*
+ * var_enter() - make new var symbol table entry, returning var ptr
+ */
+
+static VARIABLE *
+var_enter( char *symbol )
+{
+ VARIABLE var, *v = &var;
+
+ if( !varhash )
+ varhash = hashinit( sizeof( VARIABLE ), "variables" );
+
+ v->symbol = symbol;
+ v->value = 0;
+
+ if( hashenter( varhash, (HASHDATA **)&v ) )
+ v->symbol = newstr( symbol ); /* never freed */
+
+ return v;
+}
+
+/*
+ * var_dump() - dump a variable to stdout
+ */
+
+static void
+var_dump(
+ char *symbol,
+ LIST *value,
+ char *what )
+{
+ printf( "%s %s = ", what, symbol );
+ list_print( value );
+ printf( "\n" );
+}
+
+/*
+ * var_done() - free variable tables
+ */
+
+void
+var_done()
+{
+ hashdone( varhash );
+}
diff --git a/historic/jam/src/variable.h b/historic/jam/src/variable.h
new file mode 100644
index 000000000..77b89f1ea
--- /dev/null
+++ b/historic/jam/src/variable.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * variable.h - handle jam multi-element variables
+ */
+
+void var_defines( char **e );
+int var_string( char *in, char *out, int outsize, LOL *lol );
+LIST * var_get( char *symbol );
+void var_set( char *symbol, LIST *value, int flag );
+LIST * var_swap( char *symbol, LIST *value );
+void var_done();
+
+/*
+ * Defines for var_set().
+ */
+
+# define VAR_SET 0 /* override previous value */
+# define VAR_APPEND 1 /* append to previous value */
+# define VAR_DEFAULT 2 /* set only if no previous value */
+
diff --git a/historic/jam/src/yyacc b/historic/jam/src/yyacc
new file mode 100644
index 000000000..c6f7f5d15
--- /dev/null
+++ b/historic/jam/src/yyacc
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+# yyacc - yacc wrapper
+#
+# Allows tokens to be written as `literal` and then automatically
+# substituted with #defined tokens.
+#
+# Usage:
+# yyacc file.y filetab.h file.yy
+#
+# inputs:
+# file.yy yacc grammar with ` literals
+#
+# outputs:
+# file.y yacc grammar
+# filetab.h array of string <-> token mappings
+#
+# 3-13-93
+# Documented and p moved in sed command (for some reason,
+# s/x/y/p doesn't work).
+# 10-12-93
+# Take basename as second argument.
+# 12-31-96
+# reversed order of args to be compatible with GenFile rule
+
+outy=${1?}
+outh=${2?}
+in=${3?}
+out=`basename $in .yy`
+
+T=/tmp/yy$$
+trap 'rm -f $T.*' 0
+
+sed '
+ : 1
+ /`/{
+ h
+ s/[^`]*`\([^`]*\)`.*/\1/
+ p
+ g
+ s/[^`]*`[^`]*`//
+ b 1
+ }
+ d
+' $in | sort -u | sed '
+ h
+ y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
+ s/:/_COLON/
+ s/!/_BANG/
+ s/&&/_AMPERAMPER/
+ s/&/_AMPER/
+ s/+/_PLUS/
+ s/||/_BARBAR/
+ s/|/_BAR/
+ s/;/_SEMIC/
+ s/-/_MINUS/
+ s//_RANGLE/
+ s/\./_PERIOD/
+ s/?/_QUESTION/
+ s/=/_EQUALS/
+ s/,/_COMMA/
+ s/\[/_LBRACKET/
+ s/]/_RBRACKET/
+ s/{/_LBRACE/
+ s/}/_RBRACE/
+ s/(/_LPAREN/
+ s/)/_RPAREN/
+ s/FILE/_FILE_/
+ G
+ s/\n/ /
+' > $T.1
+
+sed '
+ s:^\(.*\) \(.*\)$:s/`\2`/\1/g:
+ s:\.:\\.:g
+ s:\[:\\[:g
+' $T.1 > $T.s
+
+rm -f $outy $outh
+
+(
+ sed 's:^\(.*\) \(.*\)$:%token \1:' $T.1
+ sed -f $T.s $in
+) > $outy
+
+(
+ sed 's:^\(.*\) \(.*\)$: { "\2", \1 },:' $T.1
+) > $outh
diff --git a/jam_src/Build.com b/jam_src/Build.com
new file mode 100755
index 000000000..9ad1ec28c
--- /dev/null
+++ b/jam_src/Build.com
@@ -0,0 +1,30 @@
+! Bootstrap build script for Jam
+$ cc command.c
+$ cc compile.c
+$ cc expand.c
+$ cc execvms.c
+$ cc filevms.c
+$ cc glob.c
+$ cc hash.c
+$ cc headers.c
+$ cc jambase.c
+$ cc lists.c
+$ cc make.c
+$ cc make1.c
+$ cc newstr.c
+$ cc option.c
+$ cc parse.c
+$ cc pathvms.c
+$ cc regexp.c
+$ cc rules.c
+$ cc scan.c
+$ cc search.c
+$ cc timestamp.c
+$ cc variable.c
+$ cc jam.c
+$ cc jamgram.c
+$ link/exe=jam.exe command.obj, compile.obj, execvms.obj, expand.obj, -
+ filevms.obj, glob.obj, hash.obj, headers.obj, lists.obj, make.obj, -
+ make1.obj, newstr.obj, option.obj, parse.obj, pathvms.obj, regexp.obj, -
+ rules.obj, scan.obj, search.obj, timestamp.obj, variable.obj, jam.obj, -
+ jamgram.obj, jambase.obj
diff --git a/jam_src/Build.mpw b/jam_src/Build.mpw
new file mode 100644
index 000000000..661bd8624
--- /dev/null
+++ b/jam_src/Build.mpw
@@ -0,0 +1,47 @@
+# This line must be set manually to the CodeWarrior Pro 5 installation.
+# Good luck!
+
+set CW "malyn_apps:CodeWarrior Pro 5:MetroWerks CodeWarrior"
+
+set -e MWCincludes "{CW}:MacOS Support:Universal:Interfaces:CIncludes,{CW}:MacOS Support:OpenTransport:Open Tpt Client Developer:Includes:CIncludes,{CW}:MacOS Support:Headers:Apple MPW,{CW}:MSL:MSL_C:MSL_Common:Include,{CW}:MSL:MSL_C++:MSL_Common:Include,{CW}:MSL:MSL_C:MSL_MacOS:Include"
+
+mwcppc -o :bin.mac:command.o -nomapcr -w off command.c
+mwcppc -o :bin.mac:compile.o -nomapcr -w off compile.c
+mwcppc -o :bin.mac:execmac.o -nomapcr -w off execmac.c
+mwcppc -o :bin.mac:filemac.o -nomapcr -w off filemac.c
+mwcppc -o :bin.mac:pathmac.o -nomapcr -w off pathmac.c
+mwcppc -o :bin.mac:jamgram.o -nomapcr -w off jamgram.c
+mwcppc -o :bin.mac:expand.o -nomapcr -w off expand.c
+mwcppc -o :bin.mac:glob.o -nomapcr -w off glob.c
+mwcppc -o :bin.mac:hash.o -nomapcr -w off hash.c
+mwcppc -o :bin.mac:headers.o -nomapcr -w off headers.c
+mwcppc -o :bin.mac:lists.o -nomapcr -w off lists.c
+mwcppc -o :bin.mac:make.o -nomapcr -w off make.c
+mwcppc -o :bin.mac:make1.o -nomapcr -w off make1.c
+mwcppc -o :bin.mac:newstr.o -nomapcr -w off newstr.c
+mwcppc -o :bin.mac:option.o -nomapcr -w off option.c
+mwcppc -o :bin.mac:parse.o -nomapcr -w off parse.c
+mwcppc -o :bin.mac:regexp.o -nomapcr -w off regexp.c
+mwcppc -o :bin.mac:rules.o -nomapcr -w off rules.c
+mwcppc -o :bin.mac:scan.o -nomapcr -w off scan.c
+mwcppc -o :bin.mac:search.o -nomapcr -w off search.c
+mwcppc -o :bin.mac:timestamp.o -nomapcr -w off timestamp.c
+mwcppc -o :bin.mac:variable.o -nomapcr -w off variable.c
+
+mwlinkppc -library -o :bin.mac:libjam.lib :bin.mac:command.o :bin.mac:compile.o :bin.mac:execmac.o :bin.mac:filemac.o :bin.mac:pathmac.o :bin.mac:jamgram.o :bin.mac:expand.o :bin.mac:glob.o :bin.mac:hash.o :bin.mac:headers.o :bin.mac:lists.o :bin.mac:make.o :bin.mac:make1.o :bin.mac:newstr.o :bin.mac:option.o :bin.mac:parse.o :bin.mac:regexp.o :bin.mac:rules.o :bin.mac:scan.o :bin.mac:search.o :bin.mac:timestamp.o :bin.mac:variable.o
+mwcppc -o :bin.mac:mkjambase.o -nomapcr -w off mkjambase.c
+
+mwlinkppc -o :bin.mac:mkjambase -mpwtool -warn :bin.mac:mkjambase.o "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Interfacelib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:ThreadsLib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Mathlib" "{CW}:MacOS Support:Libraries:Apple MPW PPC:PPCToolLibs.o" "{CW}:MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib" "{CW}:MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib"
+mwcppc -o :bin.mac:jam.o -nomapcr -w off jam.c
+
+:bin.mac:mkjambase jambase.c Jambase
+
+mwcppc -o :bin.mac:jambase.o -nomapcr -w off jambase.c
+
+mwlinkppc -o :bin.mac:jam -mpwtool -warn :bin.mac:jam.o :bin.mac:jambase.o :bin.mac:libjam.lib "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Interfacelib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:ThreadsLib" "{CW}:MacOS Support:Universal:Libraries:StubLibraries:Mathlib" "{CW}:MacOS Support:Libraries:Apple MPW PPC:PPCToolLibs.o" "{CW}:MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib" "{CW}:MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib"
+
+
+
+
+
+
diff --git a/jam_src/INSTALL b/jam_src/INSTALL
new file mode 100644
index 000000000..8ec9f4e86
--- /dev/null
+++ b/jam_src/INSTALL
@@ -0,0 +1,120 @@
+I. Compiling FT Jam:
+--------------------
+
+ 1. With a previous version of Jam:
+ ----------------------------------
+
+ The easiest way to compile Jam is to use a previous version of the
+ program. If you already have one installed on your system, simply
+ type "jam" in this directory.
+
+ This will create a new executable named "jam" or "jam.exe", located
+ in a new system-dependent directory, whose name can be:
+
+ bin.ntx86\jam.exe
+ bin.linux86\jam
+ etc..
+
+
+ 2. Without jam:
+ ---------------
+
+ If you don't have a jam binary installed, you can still compile the
+ program using one of these methods:
+
+ - on Unix systems, simply type "make" to use the "Makefile" provided
+ in this directory. This should work flawlessly
+
+ - on other systems, you can also modify the content of "Makefile"
+ to adapt it to your OS. Simply uncomment the lines specific to
+ your system, and invoke your make tool
+
+
+ Note that the Makefile is used to build a boot-strap version of jam,
+ called "jam0". Once it is built, the "jam0" executable is called to
+ re-build itself.
+
+ If this second pass doesn't work, this is probably because you didn't
+ set some environment variable that indicates which compiler to use to
+ Jam. Read the Jam documentation for more information on this..
+
+
+
+ 3. With toolset-specific makefiles:
+ -----------------------------------
+
+ You can also use one of the Makefiles located in the "builds"
+ directory. Here's what you need to type on the command line,
+ depending on your system and compiler:
+
+
+ a. Windows + Visual C++:
+
+ set VISUALC=/install/path/to/visual/compiler
+ set JAM_TOOLSET=VISUALC
+ nmake -f builds\win32-visualc.mk
+
+
+ b. Windows + Borland C++: (be sure to use the Borland "make" tool)
+
+ set BORLANDC=/install/path/to/borland/compiler
+ set JAM_TOOLSET=BORLANDC
+ make -fbuilds\win32-visualc.mk
+
+
+ c. Windows + Mingw (gcc):
+
+ set BORLANDC=/install/path/to/borland/compiler
+ set JAM_TOOLSET=BORLANDC
+ make -f builds\win32-visualc.mk
+
+
+ WE DO NOT PROVIDE PROJECT FILES FOR ANY SPECIFIC COMPILER/TOOLSET
+
+
+
+
+II. Installation:
+-----------------
+
+ For now, we do not provide any sophisticated
+ installation pass. Simply copy the new jam executable
+ to any directory in your current path.. and start
+ using it !!
+
+
+III. Default files:
+-------------------
+
+ All default files for Jam are compiled within the
+ executable itself.
+
+ There are no special configuration directory to
+ place global or user preferences. Until further
+ notice, all defaults can only be changed by using
+ command line switches and setting environment
+ variables..
+
+
+IV. Windows and OS/2 Binary packages:
+-------------------------------------
+
+ It's possible to create zip files of the binaries
+ on Windows and OS/2 system by following these simple
+ steps (you need to have the "zip" utility in your
+ path !!):
+
+ 1. build jam
+ 2. strip the jam.exe executable in bin.ntx86 when
+ possible
+ 3. call "jam package"
+
+ you should see a file named "ftjam-xxxxx-win32.zip"
+ or "ftjam-xxxxx-os2.zip" in the current directory,
+ as well as "ftjam-xxxxx.zip" (containing the sources)
+
+
+Good luck,
+
+
+- David Turner, 28 Jul 2001
diff --git a/jam_src/Jam.html b/jam_src/Jam.html
new file mode 100644
index 000000000..5d612ecba
--- /dev/null
+++ b/jam_src/Jam.html
@@ -0,0 +1,1201 @@
+
+
+ Jam/MR - Make(1) Redux
+
+
+
+
+
+ Jam/MR - Make(1) Redux
+
+ The Jam/MR Executable
+
+
+
+
+
+-
USAGE
-
+
+
+jam [ -a ] [ -n ] [ -v ]
+ [ -d debug ]
+ [ -f jambase ]
+ [ -j jobs ]
+ [ -o actionsfile ]
+ [ -s var=value ]
+ [ -t target ]
+ [ target ... ]
+
+
+ -
DESCRIPTION
-
+
+
+
+ Jam is a program construction tool, like make(1).
+
+
+
+ Jam recursively builds target files from source files,
+ using dependency information and updating actions expressed in
+ the Jambase file, which is written in jam's own interpreted
+ language. The default Jambase is compiled into jam and
+ provides a boilerplate for common use, relying on a user-provide
+ file "Jamfile" to enumerate actual targets and sources.
+
+
+
+ The Jambase is described in the Jambase
+ Reference and the document Using
+ Jamfiles and Jambase.
+
+
-
OPTIONS
-
+
+
+
+ If target is provided on the command line, jam
+ builds target; otherwise jam builds the target
+ 'all'.
+
+
+
+ Jam may be invoked with the following options:
+
+
+
+ -a
+ | Build all targets anyway, even if they are up-to-date.
+
+ |
-d n
+ | Enable cummulative debugging levels from 1 to n.
+ Interesting values are:
+
+
+ - 1
- Show actions (the default)
+
- 2
- Show "quiet" actions and display all action text
+
- 3
- Show dependency analysis, and target/source
+ timestamps/paths
+
- 4
- Show shell arguments
+
- 5
- Show rule invocations and variable expansions
+
- 6
- Show directory/header file/archive scans
+
- 7
- Show variable settings
+
- 8
- Show variable fetches
+
- 9
- Show variable manipulation, scanner tokens
+
+
+ |
-d +n
+ | Enable debugging level n.
+
+ |
-d 0
+ | Turn off all debugging levels. Only errors are not suppressed.
+
+ |
-f jambase
+ | Read jambase instead of using the built-in Jambase.
+ Only one -f flag is permitted, but the jambase may
+ explicitly include other files.
+
+ |
-j n
+ | Run up to n shell commands concurrently (UNIX
+ and NT only). The default is 1.
+
+ |
-n
+ | Don't actually execute the updating actions, but do
+ everything else. This changes the debug level default to -d2.
+
+ |
-o file
+ | Write the updating actions to the specified file instead
+ of running them (or outputting them, as on the Mac).
+
+ |
-s var=value
+ | Set the variable var to value, overriding
+ both internal variables and variables imported from the
+ environment.
+
+ |
-t target
+ | Rebuild target and everything that depends on it,
+ even if it is up-to-date.
+
+ |
-v
+ | Print the version of jam and exit.
+
+ |
+
+ -
OPERATION
-
+
+
+
+ Jam has four phases of operation: start-up, parsing,
+ binding, and updating.
+
+
-
Start-up
-
+
+
+
+ Upon start-up, jam imports environment variable settings
+ into jam variables. Environment variables are split at
+ blanks with each word becoming an element in the variable's list
+ of values. Environment variables whose names end in PATH are
+ split at $(SPLITPATH) characters (e.g., ":" for Unix).
+
+
+
+ To set a variable's value on the command line, overriding the
+ variable's environment value, use the -s option. To see variable
+ assignments made during jam's execution, use the -d+7
+ option.
+
+
-
Parsing
-
+
+
+
+ In the parsing phase, jam reads and parses the Jambase
+ file, by default the built-in one. It is written in the jam
+ language. See Language below. The
+ last action of the Jambase is to read (via the "include" rule)
+ a user-provided file called "Jamfile".
+
+
+
+ Collectively, the purpose of the Jambase and the Jamfile is to
+ name built target and source files, construct the dependency
+ graph among them, and associate build actions with targets.
+ The Jambase defines boilerplate rules and variable assignments,
+ and the Jamfile uses these to specify the actual relationship
+ among the target and source files. See the Jambase Reference and the document Using Jamfiles and Jambase for information.
+
+
+-
Binding
-
+
+
+
+
+
Binding
+
+ After parsing, jam recursively descends the dependency
+ graph and binds every file target with a location in the
+ filesystem. If jam detects a circular dependency in the
+ graph, it issues a warning.
+
+
+
+ File target names are given as absolute or relative path names
+ in the filesystem. If the path name is absolute, it is bound
+ as is. If the path name is relative, it is normally bound as
+ is, and thus relative to the current directory. This can be
+ modified by the settings of the $(SEARCH) and $(LOCATE) variables,
+ which enable jam to find and build targets spread across
+ a directory tree. See SEARCH and LOCATE
+ Variables below.
+
+
Update Determination
+
+ After binding each target, jam determines whether the
+ target needs updating, and if so marks the target for the updating
+ phase. A target is normally so marked if it is missing, it is
+ older than any of its sources, or any of its sources are marked
+ for updating. This behavior can be modified by the application
+ of special built-in rules, ALWAYS, LEAVES, NOCARE, NOTFILE,
+ NOUPDATE, and TEMPORARY. See Modifying
+ Binding below.
+
+
Header File Scanning
+
+
+
+ During the binding phase, jam also performs header file
+ scanning, where it looks inside source files for the implicit
+ dependencies on other files caused by C's #include syntax. This
+ is controlled by the special variables $(HDRSCAN) and $(HDRRULE).
+ The result of the scan is formed into a rule invocation, with
+ the scanned file as the target and the found included file names
+ as the sources. Note that this is the only case where rules
+ are invoked outside the parsing phase. See HDRSCAN and HDRRULE Variables below.
+
+
-
Updating
-
+
+
+
+ After binding, jam again recursively descends the dependency
+ graph, this time executing the update actions for each target
+ marked for update during the binding phase. If a target's
+ updating actions fail, then all other targets which depend on
+ that target are skipped.
+
+
+
+ The -j flag instructs jam to build more than one target
+ at a time. If there are multiple actions on a single target,
+ they are run sequentially.
+
+
+-
LANGUAGE
-
+
+
+
-
Overview
-
+
+ Jam has an interpreted, procedural language. Statements
+ in jam are rule (procedure) definitions, rule invocations,
+ flow-of-control structures, variable assignments, and sundry
+ language support.
+
+
-
Lexical Features
-
+
+
+
+ Jam treats its input files as whitespace-separated tokens,
+ with two exceptions: double quotes (") can enclose whitespace
+ to embed it into a token, and everything between the matching
+ curly braces ({}) in the definition of a rule action is treated
+ as a single string. A backslash (\) can escape a double quote.
+
+
+
+ Jam requires whitespace (blanks, tabs, or newlines) to
+ surround all tokens, including the colon (:) and semicolon
+ (;) tokens.
+
+
+
+ Jam keywords (an mentioned in this document) are reserved
+ and generally must be quoted with double quotes (") to be used
+ as arbitrary tokens, such as variable or target names.
+
+
-
Targets
-
+
+
+
+ The essential jam data entity is a target. Built targets
+ are files to be updated. Source targets are the files used in
+ updating built targets. Built targets and source targets are
+ collectively referred to as file targets, and frequently built
+ targets are source targets for other built targets. Pseudotargets
+ are symbols which represent dependencies on other targets, but
+ which are not themselves associated with any real file.
+
+
+
+ A file target's identifier is generally the file's name, which
+ can be absolutely rooted, relative to the directory of jam's
+ invocation, or simply local (no directory). Most often it is
+ the last case, and the actual file path is bound using the
+ $(SEARCH) and $(LOCATE) special variables. See
+ SEARCH and LOCATE Variables below. A local filename is
+ optionally qualified with grist, a string value used to assure
+ uniqueness. A file target with an identifier of the form
+ file(member) is a library member (usually an ar(1) archive
+ on UNIX).
+
+
-
Rules
-
+
+
+
+ The basic jam language entity is called a rule. A rule
+ is defined in two parts: the procedure and the actions. The
+ procedure is a body of jam statements to be run when the
+ rule is invoked; the actions are the OS shell commands to execute
+ when updating the built targets of the rule.
+
+
+
+ The jam statements for defining and invoking rules are
+ as follows:
+
+
+
+ -
+ rule rulename { statements }
+
+
+ - Define a rule's procedure, replacing any previous
+ definition.
+
+
-
+ actions [ modifiers ] rulename { commands }
+
+
+ - Define a rule's updating actions, replacing any
+ previous definition.
+
+
-
+ rulename field1 : field2 : ...
+ : fieldN ;
+
+
+ - Invoke a rule.
+
+
|
+
+
+
+ A rule is invoked with values in field1 through
+ fieldN. They may be referenced in the procedure's
+ statements as $(1) through $(N), and the first
+ two only may be referenced in the action's commands as
+ $(1) and $(2). $(<) and $(>) are synonymous with $(1)
+ and $(2).
+
+
+
+ Rules fall into two categories: updating rules (with actions),
+ and pure procedure rules (without actions). Updating rules
+ treat arguments $(1) and $(2) as built targets and sources,
+ respectively, while pure procedure rules can take arbitrary
+ arguments.
+
+
+
+ When an updating rule is invoked, its updating actions are added
+ to those associated with its built targets ($(1)) before the
+ rule's procedure is run. Later, to build the targets in the
+ updating phase, commands are passed to the OS command
+ shell, with $(1) and $(2) replaced by bound versions of the
+ target names. See Binding above.
+
+
+
+
+
Action Modifiers
+
+
+
+
+ The following action modifiers are understood:
+
+
+
+ actions bind vars
+ - $(vars) will be replaced with bound values.
+
+
actions existing
+ - $(>) includes only source targets currently existing.
+
+
actions ignore
+ - The return status of the commands is ignored.
+
+
actions piecemeal
+ - commands are repeatedly invoked with a subset
+ of $(>) small enough to fit in the command buffer on this
+ OS.
+
+
actions quietly
+ - The action is not echoed to the standard output.
+
+
actions together
+ - The $(>) from multiple invocations of the same action
+ on the same built target are glommed together.
+
+
actions updated
+ - $(>) includes only source targets themselves marked
+ for updating.
+
+
|
+
+
+ -
Built-in Rules
-
+
+
+ Jam has ten built-in rules, all of which are pure
+ procedure rules without updating actions. They are in
+ three groups: the first builds the dependency graph;
+ the second modifies it; and the third are just utility
+ rules.
+
+
+
+
Dependency Building
+
+
+
+
+ DEPENDS targets1 : targets2 ;
+
+
+ - Builds a direct dependency: makes each of targets1
+ depend on each of targets2. Generally, targets1
+ will be rebuilt if targets2 are themselves rebuilt are
+ or are newer than targets1.
+
+
+ INCLUDES targets1 : targets2 ;
+
+
+ - Builds a sibling dependency: makes each of targets2
+ depend on anything upon which each of targets1 depends.
+ This reflects the dependencies that arise when one source file
+ includes another: the object built from the source file depends
+ both on the original and included source file, but the two
+ sources files don't depend on each other. For example:
+
+
+ DEPENDS foo.o : foo.c ;
+ INCLUDES foo.c : foo.h ;
+
+
+
+
+ "foo.h" depends on "foo.c" and "foo.h" in this example.
+
+ |
+
+
+
Modifying Binding
+
+
+
+
+ The six rules ALWAYS, LEAVES, NOCARE, NOTFILE, NOUPDATE, and
+ TEMPORARY modify the dependency graph so that jam treats
+ the targets differently during its target binding phase. See
+ Binding above. Normally, jam
+ updates a target if it is missing, if its filesystem modification
+ time is older than any of its dependencies (recursively), or if
+ any of its dependencies are being updated. This basic behavior
+ can be changed by invoking the following rules:
+
+
+
+
+ ALWAYS targets ;
+
+
+ - Causes targets to be rebuilt regardless of whether
+ they are up-to-date (they must still be in the dependency graph).
+ This is used for the clean and uninstall targets, as they have
+ no dependencies and would otherwise appear never to need building.
+ It is best applied to targets that are also NOTFILE targets,
+ but it can also be used to force a real file to be updated as
+ well.
+
+
+ LEAVES targets ;
+
+
+ - Makes each of targets depend only on its leaf sources,
+ and not on any intermediate targets. This makes it immune to
+ its dependencies being updated, as the "leaf" dependencies are
+ those without their own dependencies and without updating actions.
+ This allows a target to be updated only if original source files
+ change.
+
+
+ NOCARE targets ;
+
+
+ - Causes jam to ignore targets that neither
+ can be found nor have updating actions to build them. Normally
+ for such targets jam issues a warning and then skips
+ other targets that depend on these missing targets. The HdrRule
+ in Jambase uses NOCARE on the header file names found during
+ header file scanning, to let jam know that the included
+ files may not exist. For example, if a #include is within an
+ #ifdef, the included file may not actually be around.
+
+
+ NOTFILE targets ;
+
+
+ - Marks targets as pseudotargets and not real files.
+ No timestamp is checked, and so the actions on such a target
+ are only executed if the target's dependencies are updated, or
+ if the target is also marked with ALWAYS. The default jam
+ target "all" is a pseudotarget. In Jambase, NOTFILE is used to
+ define several addition convenient pseudotargets.
+
+
+ NOUPDATE targets ;
+
+
+ - Causes the timestamps on targets to be ignored.
+ This has two effects: first, once the target has been created
+ it will never be updated; second, manually updating target will
+ not cause other targets to be updated. In Jambase, for example,
+ this rule is applied to directories by the MkDir rule, because
+ MkDir only cares that the target directory exists, not when it
+ has last been updated.
+
+
+ TEMPORARY targets ;
+
+
+ - Marks targets as temporary, allowing them to be
+ removed after other targets that depend upon them have been
+ updated. If a TEMPORARY target is missing, jam uses the
+ timestamp of the target's parent. Jambase uses TEMPORARY to
+ mark object files that are archived in a library after they are
+ built, so that they can be deleted after they are archived.
+
+
|
+
+
Utility Rules
+
+
+
+ The two rules ECHO and EXIT are utility rules, used only in
+ jam's parsing phase.
+
+
+
+
+ ECHO args ;
+
+
+ - Blurts out the message args to stdout.
+
+
+ EXIT args ;
+
+
+ - Blurts out the message args to stdout and then exits
+ with a failure status.
+
+
|
+
+ -
Flow-of-Control
-
+
+
+
+ Jam has several simple flow-of-control statements:
+
+
+
+
+
+ for var in list { statements }
+
+
+
+ - Executes statements for each element in
+ list, setting the variable var to the element
+ value.
+
+
+
+ if cond { statements }
+ [ else statements ]
+
+
+
+ - Does the obvious; the else clause is optional.
+ cond is built of:
+
+
+
+ a |
+ true if any a element is a non-zero-length
+ string |
+ a = b |
+ list a matches list b
+ string-for-string |
+ a != b |
+ list a does not match list b |
+ a < b |
+ a[i] string is less than b[i]
+ string, where i is first mismatched element
+ in lists a and b |
+ a <= b |
+ every a string is less than or equal to
+ its b counterpart |
+ a > b |
+ a[i] string is greater than b[i]
+ string, where i is first mismatched element |
+ a >= b |
+ every a string is greater than or equal to
+ its b counterpart |
+ a in b |
+ true if all elements of a can be found
+ in b, or if a has no elements |
+ ! cond |
+ condition not true |
+ cond && cond |
+ conjunction |
+ cond || cond |
+ disjunction |
+ ( cond ) |
+ precedence grouping |
+
+
+
+ -
+
+ include file ;
+
+
+
+ - Causes jam to read the named file.
+ The file is bound like a regular target (see Binding above) but unlike a regular
+ target the include file cannot be built.
+
+
+
+ The include file is inserted into the input stream during
+ the parsing phase. The primary input file and all the included
+ file(s) are treated as a single file; that is, jam
+ infers no scope boundaries from included files.
+
+ -
+
+ local vars [ = values ] ;
+
+
+
+ - Creates new vars inside to the enclosing {}
+ block, obscuring any previous values they might have. The
+ previous values for vars are restored when the current
+ block ends. Any rule called or file included will see the
+ local and not the previous value (this is sometimes called
+ Dynamic Scoping). The local statement may appear anywhere,
+ even outside of a block (in which case the previous value
+ is restored when the input ends). The vars are
+ initialized to values if present, or left uninitialized
+ otherwise.
+
+
-
+
+ switch value
+ {
+ case pattern1 : statements ;
+ case pattern2 : statements ;
+ ...
+ }
+
+
+
+ - The switch statement executes zero or one of the
+ enclosed statements, depending on which, if any, is
+ the first case whose pattern matches value.
+ The pattern values are not variable-expanded. The
+ pattern values may include the following wildcards:
+
+
+
+ ? |
+ match any single character |
+ * |
+ match zero or more characters |
+ [chars] |
+ match any single character in chars |
+
+
+
+ |
+
+ -
Variables
-
+
+
+
+ Jam variables are lists of zero or more elements, with
+ each element being a string value. An undefined variable is
+ indistinguishable from a variable with an empty list, however,
+ a defined variable may have one more elements which are null
+ strings. All variables are referenced as $(variable).
+
+
+
+ Variables are either global or target-specific. In the latter
+ case, the variable takes on the given value only during the
+ updating of the specific target.
+
+
+
+ A variable is defined with:
+
+
+
+
+ variable = elements ;
+
+ variable += elements ;
+
+ variable on targets = elements ;
+
+ variable on targets += elements ;
+
+ variable default = elements ;
+
+ variable ?= elements ;
+
+ |
+
+
+
+ The first two forms set variable globally. The third
+ and forth forms set a target-specific variable. The = operator
+ replaces any previous elements of variable with
+ elements; the += operation adds elements to
+ variable's list of elements. The final two forms are
+ synonymous: they set variable globally, but only if it
+ was previously unset.
+
+
+
+ Variables referenced in updating commands will be replaced with
+ their values; target-specific values take precedence over global
+ values. Variables passed as arguments ($(1) and $(2)) to actions
+ are replaced with their bound values; the "bind" modifier can
+ be used on actions to cause other variables to be replaced with
+ bound values. See Action Modifiers
+ above.
+
+
+
+ Jam variables are not re-exported to the environment of
+ the shell that executes the updating actions, but the updating
+ actions can reference jam variables with $(variable).
+
+
Variable Expansion
+
+
+
+ During parsing, jam performs variable expansion on each
+ token that is not a keyword or rule name. Such tokens with
+ embedded variable references are replaced with zero or more
+ tokens. Variable references are of the form $(v) or
+ $(vm), where v is the variable name, and m
+ are optional modifiers.
+
+
+
+ Variable expansion in a rule's actions is similar to variable
+ expansion in statements, except that the action string is
+ tokenized at whitespace regardless of quoting.
+
+
+
+ The result of a token after variable expansion is the
+ product of the components of the token, where each
+ component is a literal substring or a list substituting a variable
+ reference. For example:
+
+
+
+ $(X) -> a b c
+ t$(X) -> ta tb tc
+ $(X)z -> az bz cz
+ $(X)-$(X) -> a-a a-b a-c b-a b-b b-c c-a c-b c-c
+
+ |
+
+
+
+ The variable name and modifiers can themselves contain
+ a variable reference, and this partakes of the product
+ as well:
+
+
+
+ $(X) -> a b c
+ $(Y) -> 1 2
+ $(Z) -> X Y
+ $($(Z)) -> a b c 1 2
+
+ |
+
+
+
+ Because of this product expansion, if any variable reference in
+ a token is undefined, the result of the expansion is an empty
+ list. If any variable element is a null string, the result
+ propagates the non-null elements:
+
+
+
+ $(X) -> a ""
+ $(Y) -> "" 1
+ $(Z) ->
+ *$(X)$(Y)* -> *a* *a1* ** *1*
+ *$(X)$(Z)* ->
+
+ |
+
+
+
+ A variable element's string value can be parsed into grist and
+ filename-related components. Modifiers to a variable are used
+ to select elements, select components, and replace components.
+ The modifiers are:
+
+
+
+ [n]
+ | Select element number n (starting at 1). If
+ the variable contains fewer than n elements,
+ the result is a zero-element list.
+
+ |
[n-m]
+ | Select elements number n through m.
+
+ |
[n-]
+ | Select elements number n through the last.
+
+ |
:B
+ | Select filename base.
+
+ |
:S
+ | Select (last) filename suffix.
+
+ |
:M
+ | Select archive member name.
+
+ |
:D
+ | Select directory path.
+
+ |
:P
+ | Select parent directory.
+
+ |
:G
+ | Select grist.
+
+ |
:U
+ | Replace lowercase characters with uppercase.
+
+ |
:L
+ | Replace uppercase characters with lowercase.
+
+ |
:chars
+ | Select the components listed in chars.
+
+ |
:G=grist
+ | Replace grist with grist.
+
+ |
:D=path
+ | Replace directory with path.
+
+ |
:B=base
+ | Replace the base part of file name with base.
+
+ |
:S=suf
+ | Replace the suffix of file name with suf.
+
+ |
:M=mem
+ | Replace the archive member name with mem.
+
+ |
:R=root
+ | Prepend root to the whole file name, if not
+ already rooted.
+
+ |
+
+
+
+ On VMS, $(var:P) is the parent directory of $(var:D); on Unix
+ and NT, $(var:P) and $(var:D) are the same.
+
+
-
Built-in Variables
-
+
+
+
+ This section discusses variables that have special meaning to
+ jam.
+
+
+
SEARCH and LOCATE Variables
+
+
+
+
+ These two variables control the binding of file target names to
+ locations in the file system. Generally, $(SEARCH) is used to
+ find existing sources while $(LOCATE) is used to fix the location
+ for built targets.
+
+
+
+ Rooted (absolute path) file targets are bound as is. Unrooted
+ file target names are also normally bound as is, and thus relative
+ to the current directory, but the settings of $(LOCATE) and
+ $(SEARCH) alter this:
+
+
+
+
+
+ - If $(LOCATE) is set then the target is bound relative to
+ the first directory in $(LOCATE). Only the first element is
+ used for binding.
+
+
- If $(SEARCH) is set then the target is bound to the first
+ directory in $(SEARCH) where the target file already exists.
+
+
- If the $(SEARCH) search fails, the target is bound relative
+ to the current directory anyhow.
+
+
+
+
+
+ Both $(SEARCH) and $(LOCATE) should be set target-specific and
+ not globally. If they were set globally, jam would use
+ the same paths for all file binding, which is not likely to
+ produce sane results. When writing your own rules, especially
+ ones not built upon those in Jambase, you may need to set
+ $(SEARCH) or $(LOCATE) directly. Almost all of the rules defined
+ in Jambase set $(SEARCH) and $(LOCATE) to sensible values for
+ sources they are looking for and targets they create, respectively.
+
+
+
HDRSCAN and HDRRULE Variables
+
+
+
+
+ These two variable control header file scanning. $(HDRSCAN) is
+ an egrep(1) pattern, with ()'s surrounding the file name,
+ used to find file inclusion statements in source files. Jambase
+ uses $(HDRPATTERN) as the pattern for $(HDRSCAN). $(HDRRULE)
+ is the name of a rule to invoke with the results of the scan:
+ the scanned file is the target, the found files are the sources.
+ This is the only place where jam invokes a rule through
+ a variable setting.
+
+
+
+ Both $(HDRSCAN) and $(HDRRULE) must be set for header file
+ scanning to take place, and they should be set target-specific
+ and not globally. If they were set globally, all files, including
+ executables and libraries, would be scanned for header file
+ include statements.
+
+
+
+ The scanning for header file inclusions is not exact, but it is
+ at least dynamic, so there is no need to run something like
+ makedepend(GNU) to create a static dependency file. The
+ scanning mechanism errs on the side of inclusion (i.e., it is
+ more likely to return filenames that are not actually used by
+ the compiler than to miss include files) because it can't tell
+ if #include lines are inside #ifdefs or other conditional logic.
+ In Jambase, HdrRule applies the NOCARE rule to each header file
+ found during scanning so that if the file isn't present yet
+ doesn't cause the compilation to fail, jam won't care.
+
+
+
+ Also, scanning for regular expressions only works where the
+ included file name is literally in the source file. It can't
+ handle languages that allow including files using variable names
+ (as the Jam language itself does).
+
+
Platform Identifier Variables
+
+
+
+ A number of Jam built-in variables can be used to identify
+ runtime platform:
+
+
+
+
+
+ | OS | OS identifier string
+ |
| OSPLAT | Underlying architecture, when applicable
+ |
| MAC | true on MAC platform
+ |
| NT | true on NT platform
+ |
| OS2 | true on OS2 platform
+ |
| UNIX | true on Unix platforms
+ |
| VMS | true on VMS platform
+
+ |
+
+
Jam Version Variables
+
+
+
+
+
+ | JAMDATE | Time and date at jam start-up.
+ |
| JAMUNAME | Ouput of uname(1) command (Unix only)
+ |
| JAMVERSION | jam version, currently "2.3"
+
+ |
+
+
JAMSHELL Variable
+
+
+
+ When jam executes a rule's action block, it forks and
+ execs a shell, passing the action block as an argument to the
+ shell. The invocation of the shell can be controlled by
+ $(JAMSHELL). The default on Unix is, for example:
+
+
+
+ JAMSHELL = /bin/sh -c % ;
+
+
+
+ The % is replaced with the text of the action block.
+
+
+
+ Jam does not directly support building in parallel across
+ multiple hosts, since that is heavily dependent on the local
+ environment. To build in parallel across multiple hosts, you
+ need to write your own shell that provides access to the multiple
+ hosts. You then reset $(JAMSHELL) to reference it.
+
+
+
+ Just as jam expands a % to be the text of the rule's
+ action block, it expands a ! to be the multi-process slot number.
+ The slot number varies between 1 and the number of concurrent
+ jobs permitted by the -j flag given on the command line. Armed
+ with this, it is possible to write a multiple host shell. For
+ example:
+
+
+
+
+
+ #!/bin/sh
+
+ # This sample JAMSHELL uses the SunOS on(1) command to execute a
+ # command string with an identical environment on another host.
+
+ # Set JAMSHELL = jamshell ! %
+ #
+ # where jamshell is the name of this shell file.
+ #
+ # This version handles up to -j6; after that they get executed
+ # locally.
+
+ case $1 in
+ 1|4) on winken sh -c "$2";;
+ 2|5) on blinken sh -c "$2";;
+ 3|6) on nod sh -c "$2";;
+ *) eval "$2";;
+ esac
+
+ |
+
+
+ -
DIAGNOSTICS
-
+
+
+
+ In addition to generic error messages, jam may emit one of
+ the following:
+
+
+
+ warning: unknown rule X -
+
+ A rule was invoked that has not been defined with
+ an "actions" or "rule" statement.
+
+
using N temp target(s) -
+
+ Targets marked as being temporary (but nonetheless
+ present) have been found.
+
+
updating N target(s) -
+
+ Targets are out-of-date and will be updated.
+
+
can't find N target(s) -
+
+ Source files can't be found and there are no
+ actions to create them.
+
+
can't make N target(s) -
+
+ Due to sources not being found, other targets cannot be made.
+
+
warning: X depends on itself -
+
+ A target depends on itself either directly or
+ through its sources.
+
+
don't know how to make X -
+
+ A target is not present and no actions have been
+ defined to create it.
+
+
X skipped for lack of Y -
+
+ A source failed to build, and thus a target cannot
+ be built.
+
+
warning: using independent target X -
+
+ A target that is not a dependency of any other
+ target is being referenced with $(<) or $(>).
+
+
X removed -
+
+ Jam removed a partially built target after being
+ interrupted.
+
+
|
+
+ -
BUGS, LIMITATIONS
-
+
+
+
+ The -j flag can cause jam to get confused when single
+ actions update more than one target at a time. jam may
+ proceed as if the targets were built even though they are still
+ under construction.
+
+
+
+ For parallel building to be successful, the dependencies among
+ files must be properly spelled out, as targets tend to get built
+ in a quickest-first ordering. Also, beware of un-parallelizable
+ commands that drop fixed-named files into the current directory,
+ like yacc(1) does.
+
+
+
+ With the -j flag, errors from failed commands can get staggeringly
+ mixed up.
+
+
+
+ A poorly set $(JAMSHELL) is likely to result in silent failure.
+
+
-
SEE ALSO
-
+
+
+
+
+
+
+
+ Jam documentation and source are available from the Perforce
+ Public Depot.
+
+
-
AUTHOR
-
+
+
+ Jam's author is Christopher Seiwald (seiwald@perforce.com).
+ Documentation is provided by
+ Perforce Software, Inc.
+
+
+
+
+
+
+
+ Copyright 1997, 2000 Perforce Software, Inc.
+
+ Comments to info@perforce.com
+
+ Last updated: December 31, 2000
+
+ $Id$
+
+
+
+
diff --git a/jam_src/Jambase b/jam_src/Jambase
new file mode 100644
index 000000000..dcd9ec0a1
--- /dev/null
+++ b/jam_src/Jambase
@@ -0,0 +1,2288 @@
+#
+# /+\
+# +\ Copyright 1993, 2000 Christopher Seiwald.
+# \+/
+#
+# This file is part of Jam - see jam.c for Copyright information.
+#
+
+# This file is ALSO:
+# (C) Copyright David Abrahams 2001. Permission to copy, use,
+# modify, sell and distribute this software is granted provided this
+# copyright notice appears in all copies. This software is provided
+# "as is" without express or implied warranty, and with no claim as
+# to its suitability for any purpose.
+
+# The logic for finding the build system:
+#
+# The process is controlled by variables (in decreasing
+# precedence):
+#
+# If JAMBASE is set, it specifies the build system filename
+#
+# Otherwise, if BOOST_BUILD_PATH or BOOST_ROOT is set, the build system filename
+# is boost-build.jam.
+#
+# If the build system filename does not contain a path specification, the build
+# system file is searched for on $(BOOST_BUILD_PATH) then at
+# $(BOOST_ROOT)/tools/build.
+#
+# If neither JAMBASE, BOOST_ROOT, nor BOOST_BUILD_PATH is set, we use the
+# built-in Jambase (this file) and load the user's Jamfile. Perforce Jam has
+# this behavior, and it is used for building Jam itself. Thus, if you rebuild
+# Jam, these variables should be unset.
+if $(BOOST_ROOT)
+{
+ BOOST_BUILD_PATH ?= $(BOOST_ROOT)/tools/build ;
+}
+
+if $(BOOST_BUILD_PATH)
+{
+ JAMBASE ?= boost-build.jam ;
+}
+
+if $(JAMBASE)
+{
+ JAMBASE = $(JAMBASE:G=jam-module) ; # puts the Jambase target in a different
+ # namespace from other targets so that
+ # it doesn't collide.
+ SEARCH on $(JAMBASE) = $(JAMBASE_PATH) $(BOOST_BUILD_PATH) ;
+ include $(JAMBASE) ;
+}
+else
+{
+
+#
+# JAMBASE - jam 2.3 ruleset providing make(1)-like functionality
+#
+# Supports UNIX, NT, and VMS.
+#
+# 12/27/93 (seiwald) - purturb library sources with SOURCE_GRIST
+# 04/18/94 (seiwald) - use '?=' when setting OS specific vars
+# 04/21/94 (seiwald) - do RmTemps together
+# 05/05/94 (seiwald) - all supported C compilers support -o: relegate
+# RELOCATE as an option; set Ranlib to "" to disable it
+# 06/01/94 (seiwald) - new 'actions existing' to do existing sources
+# 08/25/94 (seiwald) - new ObjectCcFlags rule to append to per-target CCFLAGS
+# 08/29/94 (seiwald) - new ObjectHdrs rule to append to per-target HDRS
+# 09/19/94 (seiwald) - LinkLibraries and Undefs now append
+# - Rule names downshifted.
+# 10/06/94 (seiwald) - Dumb yyacc stuff moved into Jamfile.
+# 10/14/94 (seiwald) - (Crude) support for .s, .C, .cc, .cpp, and .f files.
+# 01/08/95 (seiwald) - Shell now handled with awk, not sed
+# 01/09/95 (seiwald) - Install* now take dest directory as target
+# 01/10/95 (seiwald) - All entries sorted.
+# 01/10/95 (seiwald) - NT support moved in, with LauraW's help.
+# 01/10/95 (seiwald) - VMS support moved in.
+# 02/06/95 (seiwald) - ObjectC++Flags and SubDirC++Flags added.
+# 02/07/95 (seiwald) - Iron out when HDRSEARCH uses "" or SEARCH_SOURCE.
+# 02/08/95 (seiwald) - SubDir works on VMS.
+# 02/14/95 (seiwald) - MkDir and entourage.
+# 04/30/95 (seiwald) - Use install -c flag so that it copies, not moves.
+# 07/10/95 (taylor) - Support for Microsoft C++.
+# 11/21/96 (peterk) - Support for BeOS
+# 07/19/99 (sickel) - Support for Mac OS X Server (and maybe client)
+# 02/18/00 (belmonte)- Support for Cygwin.
+
+# Special targets defined in this file:
+#
+# all - parent of first, shell, files, lib, exe
+# first - first dependent of 'all', for potential initialization
+# shell - parent of all Shell targets
+# files - parent of all File targets
+# lib - parent of all Library targets
+# exe - parent of all Main targets
+# dirs - parent of all MkDir targets
+# clean - removes all Shell, File, Library, and Main targets
+# uninstall - removes all Install targets
+#
+
+# Rules defined by this file:
+#
+# as obj.o : source.s ; .s -> .o
+# Bulk dir : files ; populate directory with many files
+# Cc obj.o : source.c ; .c -> .o
+# C++ obj.o : source.cc ; .cc -> .o
+# Clean clean : sources ; remove sources with 'jam clean'
+# File dest : source ; copy file
+# Fortran obj.o : source.f ; .f -> .o
+# GenFile source.c : program args ; make custom file
+# Hardlink target : source ; make link from source to target
+# HdrRule source : headers ; handle #includes
+# InstallInto dir : sources ; install any files
+# InstallBin dir : sources ; install binaries
+# InstallLib dir : sources ; install files
+# InstallFile dir : sources ; install files
+# InstallMan dir : sources ; install man pages
+# InstallShell dir : sources ; install shell scripts
+# Lex source.c : source.l ; .l -> .c
+# Library lib : source ; archive library from compiled sources
+# LibraryFromObjects lib : objects ; archive library from objects
+# LinkLibraries images : libraries ; bag libraries onto Mains
+# Main image : source ; link executable from compiled sources
+# MainFromObjects image : objects ; link executable from objects
+# MkDir dir ; make a directory, if not there
+# Object object : source ; compile object from source
+# ObjectCcFlags source : flags ; add compiler flags for object
+# ObjectC++Flags source : flags ; add compiler flags for object
+# ObjectHdrs source : dirs ; add include directories for object
+# Objects sources ; compile sources
+# RmTemps target : sources ; remove temp sources after target made
+# Setuid images ; mark executables Setuid
+# SubDir TOP d1 d2 ... ; start a subdirectory Jamfile
+# SubDirCcFlags flags ; add compiler flags until next SubDir
+# SubDirC++Flags flags ; add compiler flags until next SubDir
+# SubDirHdrs dirs ; add include dirs until next SubDir
+# SubInclude TOP d1 d2 ... ; include a subdirectory Jamfile
+# Shell exe : source ; make a shell executable
+# Undefines images : symbols ; save undef's for linking
+# UserObject object : source ; handle unknown suffixes for Object
+# Yacc source.c : source.y ; .y -> .c
+#
+# Utility rules that have no side effects (not supported):
+#
+# FAppendSuffix f1 f2 ... : $(SUF) ; return $(<) with suffixes
+# FConcat value ... ; return contatenated values
+# FDirName d1 d2 ... ; return path from root to dir
+# FGrist d1 d2 ... ; return d1!d2!...
+# FGristFiles value ; return $(value:G=$(SOURCE_GRIST))
+# FGristSourceFiles value ; return $(value:G=$(SOURCE_GRIST))
+# FRelPath d1 : d2 ; return rel path from d1 to d2
+# FSubDir d1 d2 ... ; return path to root
+#
+
+
+# Brief review of the jam language:
+#
+# Statements:
+# rule RULE - statements to process a rule
+# actions RULE - system commands to carry out target update
+#
+# Modifiers on actions:
+# together - multiple instances of same rule on target get executed
+# once with their sources ($(>)) concatenated
+# updated - refers to updated sources ($(>)) only
+# ignore - ignore return status of command
+# quietly - don't trace its execution unless verbose
+# piecemeal - iterate command each time with a small subset of $(>)
+# existing - refers to currently existing sources ($(>)) only
+# bind vars - subject to binding before expanding in actions
+#
+# Special rules:
+# ALWAYS - always build a target
+# DEPENDS - builds the dependency graph
+# ECHO - blurt out targets on stdout
+# EXIT - blurt out targets and exit
+# INCLUDES - marks sources as headers for target (a codependency)
+# NOCARE - don't panic if the target can't be built
+# NOUPDATE - create the target if needed but never update it
+# NOTFILE - ignore the timestamp of the target (it's not a file)
+# TEMPORARY - target need not be present if sources haven't changed
+#
+# Special variables set by jam:
+# $(<) - targets of a rule (to the left of the :)
+# $(>) - sources of a rule (to the right of the :)
+# $(xxx) - true on xxx (UNIX, VMS, NT, OS2, MAC)
+# $(OS) - name of OS - varies wildly
+# $(JAMVERSION) - version number (2.3)
+#
+# Special variables used by jam:
+# SEARCH - where to find something (used during binding and actions)
+# LOCATE - where to plop something not found with SEARCH
+# HDRRULE - rule to call to handle include files
+# HDRSCAN - egrep regex to extract include files
+#
+# Special targets:
+# all - default if none given on command line
+#
+
+# Initialize variables
+#
+
+#
+# OS specific variable settings
+#
+
+if $(NT)
+{
+ # the list of supported toolsets on Windows NT and Windows 95/98
+ #
+ local SUPPORTED_TOOLSETS = "BORLANDC" "VISUALC" "VISUALC16" "INTELC" "WATCOM"
+ "MINGW" "LCC" ;
+
+ # this variable holds the current toolset
+ #
+ TOOLSET = "" ;
+
+ # if the JAM_TOOLSET environment variable is defined, check that it is
+ # one of our supported values
+ #
+ if $(JAM_TOOLSET)
+ {
+ local t ;
+
+ for t in $(SUPPORTED_TOOLSETS)
+ {
+ if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }
+ }
+
+ if ! $(TOOLSET)
+ {
+ ECHO "The JAM_TOOLSET environment variable is defined but its value" ;
+ ECHO "is invalid, please use one of the following:" ;
+ ECHO ;
+
+ for t in $(SUPPORTED_TOOLSETS) { ECHO " " $(t) ; }
+ EXIT ;
+ }
+ }
+
+ # if TOOLSET is empty, we'll try to detect the toolset from other
+ # environment variables to remain backwards compatible with Jam 2.3
+ #
+ if ! $(TOOLSET)
+ {
+ if $(BCCROOT)
+ {
+ TOOLSET = BORLANDC ;
+ BORLANDC = $(BCCROOT) ;
+ }
+ else if $(MSVC)
+ {
+ TOOLSET = VISUALC16 ;
+ VISUALC16 = $(MSVC) ;
+ }
+ else if $(MSVCNT)
+ {
+ TOOLSET = VISUALC ;
+ VISUALC = $(MSVCNT) ;
+ }
+ else if $(MINGW)
+ {
+ TOOLSET = MINGW ;
+ }
+ else
+ {
+ ECHO "Jam cannot be run because you didn't indicate which compilation toolset" ;
+ ECHO "to use. To do so, follow these simple instructions:" ;
+ ECHO ;
+ ECHO " - define one of the following environment variable, with the" ;
+ ECHO " appropriate value according to this list:" ;
+ ECHO ;
+ ECHO " Variable Toolset Description" ;
+ ECHO ;
+ ECHO " BORLANDC Borland C++ BC++ install path" ;
+ ECHO " VISUALC Microsoft Visual C++ VC++ install path" ;
+ ECHO " VISUALC16 Microsoft Visual C++ 16 bit VC++ 16 bit install" ;
+ ECHO " INTELC Intel C/C++ IC++ install path" ;
+ ECHO " WATCOM Watcom C/C++ Watcom install path" ;
+ ECHO " MINGW MinGW (gcc) MinGW install path" ;
+ ECHO " LCC Win32-LCC LCC-Win32 install path" ;
+ ECHO ;
+ ECHO " - define the JAM_TOOLSET environment variable with the *name*" ;
+ ECHO " of the toolset variable you want to use." ;
+ ECHO ;
+ ECHO " e.g.: set VISUALC=C:\Visual6" ;
+ ECHO " set JAM_TOOLSET=VISUALC" ;
+ ECHO ;
+ EXIT ;
+ }
+ }
+
+ CP ?= copy ;
+ RM ?= del /f/q ;
+ SLASH ?= \\ ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ SUFEXE ?= .exe ;
+
+ if $(TOOLSET) = BORLANDC
+ {
+ ECHO "Compiler is Borland C++" ;
+
+ AR ?= tlib /C /P64 ;
+ CC ?= bcc32 ;
+ CCFLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus ;
+ C++ ?= bcc32 ;
+ C++FLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus -P ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= $(CCFLAGS) ;
+ STDLIBPATH ?= $(BORLANDC)\\lib ;
+ STDHDRS ?= $(BORLANDC)\\include ;
+ NOARSCAN ?= true ;
+ }
+ else if $(TOOLSET) = VISUALC16
+ {
+ ECHO "Compiler is Microsoft Visual C++ 16 bit" ;
+
+ AR ?= lib /nologo ;
+ CC ?= cl /nologo ;
+ CCFLAGS ?= /D \"WIN\" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= $(CCFLAGS) ;
+ LINKLIBS ?=
+ #$(VISUALC16)\\lib\\advapi32.lib
+ #$(VISUALC16)\\lib\\libcmt.lib
+ $(VISUALC16)\\lib\\mlibce.lib
+ #$(VISUALC16)\\lib\\slibce.lib
+ $(VISUALC16)\\lib\\oldnames.lib
+ #$(VISUALC16)\\lib\\kernel32.lib
+ ;
+ LINKLIBS ?= ;
+ NOARSCAN ?= true ;
+ OPTIM ?= "" ;
+ STDHDRS ?= $(VISUALC16)\\include ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = VISUALC
+ {
+ ECHO "Compiler is Microsoft Visual C++" ;
+
+ AR ?= lib ;
+ AS ?= masm386 ;
+ CC ?= cl /nologo ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= link /nologo ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= $(VISUALC)\\lib\\advapi32.lib
+ # $(VISUALC)\\lib\\libc.lib
+ # $(VISUALC)\\lib\\oldnames.lib
+ $(VISUALC)\\lib\\gdi32.lib
+ $(VISUALC)\\lib\\user32.lib
+ $(VISUALC)\\lib\\kernel32.lib ;
+ OPTIM ?= "" ;
+ STDHDRS ?= $(VISUALC)\\include ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = INTELC
+ {
+ ECHO "Compiler is Intel C/C++" ;
+
+ if ! $(VISUALC)
+ {
+ ECHO "As a special exception, when using the Intel C++ compiler, you need" ;
+ ECHO "to define the VISUALC environment variable to indicate the location" ;
+ ECHO "of your Visual C++ installation. Aborting.." ;
+ EXIT ;
+ }
+
+ AR ?= lib ;
+ AS ?= masm386 ;
+ CC ?= icl /nologo ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= link /nologo ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= $(VISUALC)\\lib\\advapi32.lib
+ # $(VISUALC)\\lib\\libc.lib
+ # $(VISUALC)\\lib\\oldnames.lib
+ $(VISUALC)\\lib\\kernel32.lib
+ ;
+ OPTIM ?= "" ;
+ STDHDRS ?= $(INTELC)\include $(VISUALC)\\include ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = WATCOM
+ {
+ ECHO "Compiler is Watcom C/C++" ;
+
+ AR ?= wlib ;
+ CC ?= wcc386 ;
+ CCFLAGS ?= /zq /DWIN32 /I$(WATCOM)\\h ; # zq=quiet
+ C++ ?= wpp386 ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ CP ?= copy ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ LINK ?= wcl386 ;
+ LINKFLAGS ?= /zq ; # zq=quiet
+ LINKLIBS ?= ;
+ MV ?= move ;
+ NOARSCAN ?= true ;
+ OPTIM ?= ;
+ RM ?= del /f ;
+ SLASH ?= \\ ;
+ STDHDRS ?= $(WATCOM)\\h $(WATCOM)\\h\\nt ;
+ SUFEXE ?= .exe ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = MINGW
+ {
+ ECHO "Compiler is GCC with Mingw" ;
+
+ AR ?= ar -ru ;
+ CC ?= gcc ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= "" ;
+ OPTIM ?= ;
+ SUFOBJ = .o ;
+ SUFLIB = .a ;
+ SLASH = / ;
+# NOARSCAN ?= true ;
+ }
+ else if $(TOOLSET) = LCC
+ {
+ ECHO "Compiler is Win32-LCC" ;
+
+ AR ?= lcclib ;
+ CC ?= lcc ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= lcclnk ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= "" ;
+ OPTIM ?= ;
+ NOARSCAN = true ;
+ }
+ else
+ {
+#
+# XXX: We need better comments here !!
+#
+ EXIT On NT, set BCCROOT, MSVCNT, MINGW or MSVC to the root of the
+ Borland or Microsoft directories. ;
+ }
+
+}
+else if $(OS2)
+{
+ # the list of supported toolsets on Windows NT and Windows 95/98
+ #
+ local SUPPORTED_TOOLSETS = "EMX" "WATCOM" ;
+
+ # this variable holds the current toolset
+ #
+ TOOLSET = "" ;
+
+ # if the JAM_TOOLSET environment variable is defined, check that it is
+ # one of our supported values
+ #
+ if $(JAM_TOOLSET)
+ {
+ local t ;
+
+ for t in $(SUPPORTED_TOOLSETS)
+ {
+ if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }
+ }
+
+ if ! $(TOOLSET)
+ {
+ ECHO "The JAM_TOOLSET environment variable is defined but its value" ;
+ ECHO "is invalid, please use one of the following:" ;
+ ECHO ;
+
+ for t in $(SUPPORTED_TOOLSETS) { ECHO " " $(t) ; }
+ EXIT ;
+ }
+ }
+
+ # if TOOLSET is empty, we'll try to detect the toolset from other
+ # environment variables to remain backwards compatible with Jam 2.3
+ #
+ if ! $(TOOLSET)
+ {
+ if $(watcom)
+ {
+ WATCOM = $(watcom) ;
+ TOOLSET = WATCOM ;
+ }
+ else
+ {
+ ECHO "Jam cannot be run because you didn't indicate which compilation toolset" ;
+ ECHO "to use. To do so, follow these simple instructions:" ;
+ ECHO ;
+ ECHO " - define one of the following environment variable, with the" ;
+ ECHO " appropriate value according to this list:" ;
+ ECHO ;
+ ECHO " Variable Toolset Description" ;
+ ECHO ;
+ ECHO " WATCOM Watcom C/C++ Watcom install path" ;
+ ECHO " EMX EMX (gcc) EMX install path" ;
+ ECHO " VISUALAGE IBM Visual Age C/C++ VisualAge install path" ;
+ ECHO ;
+ ECHO " - define the JAM_TOOLSET environment variable with the *name*" ;
+ ECHO " of the toolset variable you want to use." ;
+ ECHO ;
+ ECHO " e.g.: set WATCOM=C:\WATCOM" ;
+ ECHO " set JAM_TOOLSET=WATCOM" ;
+ ECHO ;
+ EXIT ;
+ }
+ }
+
+ RM = del /f ;
+ CP = copy ;
+ MV ?= move ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ SUFEXE ?= .exe ;
+
+ if $(TOOLSET) = WATCOM
+ {
+ AR ?= wlib ;
+ BINDIR ?= \\os2\\apps ;
+ CC ?= wcc386 ;
+ CCFLAGS ?= /zq /DOS2 /I$(WATCOM)\\h ; # zq=quiet
+ C++ ?= wpp386 ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= wcl386 ;
+ LINKFLAGS ?= /zq ; # zq=quiet
+ LINKLIBS ?= ;
+ NOARSCAN ?= true ;
+ OPTIM ?= ;
+ SLASH ?= \\ ;
+ STDHDRS ?= $(WATCOM)\\h ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(TOOLSET) = EMX
+ {
+ ECHO "Compiler is GCC-EMX" ;
+ AR ?= ar -ru ;
+ CC ?= gcc ;
+ CCFLAGS ?= "" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= "" ;
+ OPTIM ?= ;
+ SUFOBJ = .o ;
+ SUFLIB = .a ;
+ UNDEFFLAG ?= "-U" ;
+ SLASH = / ;
+# NOARSCAN ?= true ;
+ }
+ else
+ {
+ # should never happen
+ EXIT "Sorry, but the $(JAM_TOOLSET) toolset isn't supported for now" ;
+ }
+}
+else if $(VMS)
+{
+ C++ ?= cxx ;
+ C++FLAGS ?= ;
+ CC ?= cc ;
+ CCFLAGS ?= ;
+ CHMOD ?= set file/prot= ;
+ CP ?= copy/replace ;
+ CRELIB ?= true ;
+ DOT ?= [] ;
+ DOTDOT ?= [-] ;
+ EXEMODE ?= (w:e) ;
+ FILEMODE ?= (w:r) ;
+ HDRS ?= ;
+ LINK ?= link ;
+ LINKFLAGS ?= "" ;
+ LINKLIBS ?= ;
+ MKDIR ?= create/dir ;
+ MV ?= rename ;
+ OPTIM ?= "" ;
+ RM ?= delete ;
+ RUNVMS ?= mcr ;
+ SHELLMODE ?= (w:er) ;
+ SLASH ?= . ;
+ STDHDRS ?= decc$library_include ;
+ SUFEXE ?= .exe ;
+ SUFLIB ?= .olb ;
+ SUFOBJ ?= .obj ;
+
+ switch $(OS)
+ {
+ case OPENVMS : CCFLAGS ?= /stand=vaxc ;
+ case VMS : LINKLIBS ?= sys$library:vaxcrtl.olb/lib ;
+ }
+}
+else if $(MAC)
+{
+ local OPT ;
+
+ CW ?= "{CW}" ;
+
+ MACHDRS ?=
+ "$(UMACHDRS):Universal:Interfaces:CIncludes"
+ "$(CW):MSL:MSL_C:MSL_Common:Include"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Include" ;
+
+ MACLIBS ?=
+ "$(CW):MacOS Support:Universal:Libraries:StubLibraries:Interfacelib"
+ "$(CW):MacOS Support:Universal:Libraries:StubLibraries:Mathlib" ;
+
+ MPWLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib" ;
+
+ MPWNLLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW(NL).Lib" ;
+
+ SIOUXHDRS ?= ;
+
+ SIOUXLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL SIOUX.PPC.Lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC.Lib" ;
+
+ C++ ?= mwcppc ;
+ C++FLAGS ?= -w off -nomapcr ;
+ CC ?= mwcppc ;
+ CCFLAGS ?= -w off -nomapcr ;
+ CP ?= duplicate -y ;
+ DOT ?= ":" ;
+ DOTDOT ?= "::" ;
+ HDRS ?= $(MACHDRS) $(MPWHDRS) ;
+ LINK ?= mwlinkppc ;
+ LINKFLAGS ?= -mpwtool -warn ;
+ LINKLIBS ?= $(MACLIBS) $(MPWLIBS) ;
+ MKDIR ?= newfolder ;
+ MV ?= rename -y ;
+ NOARSCAN ?= true ;
+ OPTIM ?= ;
+ RM ?= delete -y ;
+ SLASH ?= ":" ;
+ STDHDRS ?= ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .o ;
+}
+else if $(OS) = BEOS && $(METROWERKS)
+{
+ AR ?= mwld -xml -o ;
+ BINDIR ?= /boot/apps ;
+ CC ?= mwcc ;
+ CCFLAGS ?= -nosyspath ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= -nosyspath ;
+ FORTRAN ?= "" ;
+ LIBDIR ?= /boot/develop/libraries ;
+ LINK ?= mwld ;
+ LINKFLAGS ?= "" ;
+ MANDIR ?= /boot/documentation/"Shell Tools"/HTML ;
+ NOARSCAN ?= true ;
+ STDHDRS ?= /boot/develop/headers/posix ;
+}
+else if $(OS) = BEOS
+{
+ BINDIR ?= /boot/apps ;
+ CC ?= gcc ;
+ C++ ?= $(CC) ;
+ FORTRAN ?= "" ;
+ LIBDIR ?= /boot/develop/libraries ;
+ LINK ?= gcc ;
+ LINKLIBS ?= -lnet ;
+ NOARSCAN ?= true ;
+ STDHDRS ?= /boot/develop/headers/posix ;
+}
+else if $(UNIX)
+{
+ switch $(OS)
+ {
+ case AIX :
+ LINKLIBS ?= -lbsd ;
+
+ case AMIGA :
+ CC ?= gcc ;
+ YACC ?= bison ;
+
+ case CYGWIN :
+ CC ?= gcc ;
+ CCFLAGS += -D__cygwin__ ;
+ LEX ?= flex ;
+ JAMSHELL ?= sh -c ;
+ RANLIB ?= "" ;
+ SUFEXE ?= .exe ;
+ YACC ?= bison ;
+
+ case DGUX :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+
+ case HPUX :
+ RANLIB ?= "" ;
+
+ case INTERIX :
+ CC ?= gcc ;
+ JAMSHELL ?= sh -c ;
+ RANLIB ?= "" ;
+
+ case IRIX :
+ RANLIB ?= "" ;
+
+ case MPEIX :
+ CC ?= gcc ;
+ C++ ?= gcc ;
+ CCFLAGS += -D_POSIX_SOURCE ;
+ HDRS += /usr/include ;
+ RANLIB ?= "" ;
+ NOARSCAN ?= true ;
+ NOARUPDATE ?= true ;
+
+ case MVS :
+ RANLIB ?= "" ;
+
+ case NEXT :
+ AR ?= libtool -o ;
+ RANLIB ?= "" ;
+
+ case MACOSX :
+ AR ?= libtool -o ;
+ C++ ?= c++ ;
+ MANDIR ?= /usr/local/share/man ;
+ RANLIB ?= "" ;
+
+ case NCR :
+ RANLIB ?= "" ;
+
+ case PTX :
+ RANLIB ?= "" ;
+
+ case QNX :
+ AR ?= wlib ;
+ CC ?= cc ;
+ CCFLAGS ?= -Q ; # quiet
+ C++ ?= $(CC) ;
+ C++FLAGS ?= -Q ; # quiet
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= -Q ; # quiet
+ NOARSCAN ?= true ;
+ RANLIB ?= "" ;
+
+ case SCO :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+
+ case SINIX :
+ RANLIB ?= "" ;
+
+ case SOLARIS :
+ RANLIB ?= "" ;
+ AR ?= "/usr/ccs/bin/ar ru" ;
+
+ case UNICOS :
+ NOARSCAN ?= true ;
+ OPTIM ?= -O0 ;
+
+ case UNIXWARE :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+ }
+
+ # UNIX defaults
+
+ CCFLAGS ?= ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ CHMOD ?= chmod ;
+ LEX ?= lex ;
+ LINKFLAGS ?= $(CCFLAGS) ;
+ LINKLIBS ?= ;
+ OPTIM ?= -O ;
+ RANLIB ?= ranlib ;
+ YACC ?= yacc ;
+ YACCFILES ?= y.tab ;
+ YACCFLAGS ?= -d ;
+}
+
+#
+# General defaults; a lot like UNIX
+#
+
+ AR ?= ar ru ;
+ AS ?= as ;
+ ASFLAGS ?= ;
+ AWK ?= awk ;
+ BINDIR ?= /usr/local/bin ;
+ C++ ?= cc ;
+ C++FLAGS ?= ;
+ CC ?= cc ;
+ CCFLAGS ?= ;
+ CP ?= cp -f ;
+ CRELIB ?= ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ EXEMODE ?= 711 ;
+ FILEMODE ?= 644 ;
+ FORTRAN ?= f77 ;
+ FORTRANFLAGS ?= ;
+ HDRS ?= ;
+ JAMFILE ?= Jamfile ;
+ JAMRULES ?= Jamrules ;
+ LEX ?= ;
+ LIBDIR ?= /usr/local/lib ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= ;
+ LINKLIBS ?= ;
+ LN ?= ln ;
+ MANDIR ?= /usr/local/man ;
+ MKDIR ?= mkdir ;
+ MV ?= mv -f ;
+ OPTIM ?= ;
+ RCP ?= rcp ;
+ RM ?= rm -f ;
+ RSH ?= rsh ;
+ SED ?= sed ;
+ SHELLHEADER ?= "#!/bin/sh" ;
+ SHELLMODE ?= 755 ;
+ SLASH ?= / ;
+ STDHDRS ?= /usr/include ;
+ SUFEXE ?= "" ;
+ SUFLIB ?= .a ;
+ SUFOBJ ?= .o ;
+ UNDEFFLAG ?= "-u _" ;
+ YACC ?= ;
+ YACCFILES ?= ;
+ YACCFLAGS ?= ;
+
+ HDRPATTERN =
+ "^[ ]*#[ ]*include[ ]*[<\"]([^\">]*)[\">].*$" ;
+
+ OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;
+
+
+#
+# Base dependencies - first for "bootstrap" kinds of rules
+#
+
+DEPENDS all : shell files lib exe obj ;
+DEPENDS all shell files lib exe obj : first ;
+NOTFILE all first shell files lib exe obj dirs clean uninstall ;
+ALWAYS clean uninstall ;
+
+#
+# Rules
+#
+
+rule As
+{
+ DEPENDS $(<) : $(>) ;
+ ASFLAGS on $(<) += $(ASFLAGS) $(SUBDIRASFLAGS) ;
+}
+
+rule Bulk
+{
+ local i ;
+
+ for i in $(>)
+ {
+ File $(i:D=$(<)) : $(i) ;
+ }
+}
+
+rule Cc
+{
+ local _h ;
+
+ DEPENDS $(<) : $(>) ;
+
+ # Just to clarify here: this sets the per-target CCFLAGS to
+ # be the current value of (global) CCFLAGS and SUBDIRCCFLAGS.
+
+ CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) ;
+
+ # If the compiler's -o flag doesn't work, relocate the .o
+
+ if $(RELOCATE)
+ {
+ CcMv $(<) : $(>) ;
+ }
+
+ _h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;
+
+ if $(VMS) && $(_h)
+ {
+ SLASHINC on $(<) = "/inc=(" $(_h[1]) ,$(_h[2-]) ")" ;
+ }
+ else if $(MAC) && $(_h)
+ {
+ local _i _j ;
+ _j = $(_h[1]) ;
+ for _i in $(_h[2-])
+ {
+ _j = $(_j),$(_i) ;
+ }
+ MACINC on $(<) = \"$(_j)\" ;
+ }
+}
+
+rule C++
+{
+ local _h ;
+
+ DEPENDS $(<) : $(>) ;
+ C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) ;
+
+ if $(RELOCATE)
+ {
+ CcMv $(<) : $(>) ;
+ }
+
+ _h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;
+
+ if $(VMS) && $(_h)
+ {
+ SLASHINC on $(<) = "/inc=(" $(_h[1]) ,$(_h[2-]) ")" ;
+ }
+ else if $(MAC) && $(_h)
+ {
+ local _i _j ;
+ _j = $(_h[1]) ;
+ for _i in $(_h[2-])
+ {
+ _j = $(_j),$(_i) ;
+ }
+ MACINC on $(<) = \"$(_j)\" ;
+ }
+}
+
+rule Chmod
+{
+ if $(CHMOD) { Chmod1 $(<) ; }
+}
+
+rule File
+{
+ DEPENDS files : $(<) ;
+ DEPENDS $(<) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+ MODE on $(<) = $(FILEMODE) ;
+ Chmod $(<) ;
+}
+
+rule Fortran
+{
+ DEPENDS $(<) : $(>) ;
+}
+
+rule GenFile
+{
+ local _t = [ FGristSourceFiles $(<) ] ;
+ local _s = [ FAppendSuffix $(>[1]) : $(SUFEXE) ] ;
+ Depends $(_t) : $(_s) $(>[2-]) ;
+ GenFile1 $(_t) : $(_s) $(>[2-]) ;
+ Clean clean : $(_t) ;
+}
+
+rule GenFile1
+{
+ MakeLocate $(<) : $(LOCATE_SOURCE) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+}
+
+rule HardLink
+{
+ DEPENDS files : $(<) ;
+ DEPENDS $(<) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+}
+
+rule HdrMacroFile
+{
+ # HdrMacroFile file ;
+ #
+ # this rule is used to indicate that a given file contains definitions
+ # for filename macros (e.g. "#define MYFILE_H ") that can
+ # later be used in #include statements in the rest of the source
+ #
+ # theses files must be parsed before any make is tried..
+ #
+ HDRMACRO $(<) ;
+}
+
+rule HdrRule
+{
+ # HdrRule source : headers ;
+
+ # N.B. This rule is called during binding, potentially after
+ # the fate of many targets has been determined, and must be
+ # used with caution: don't add dependencies to unrelated
+ # targets, and don't set variables on $(<).
+
+ # Tell Jam that anything depending on $(<) also depends on $(>),
+ # set SEARCH so Jam can find the headers, but then say we don't
+ # care if we can't actually find the headers (they may have been
+ # within ifdefs),
+
+ local s ;
+
+ if $(HDRGRIST)
+ {
+ s = $(>:G=$(HDRGRIST)) ;
+ } else {
+ s = $(>) ;
+ }
+
+ INCLUDES $(<) : $(s) ;
+ SEARCH on $(s) = $(HDRSEARCH) ;
+ NOCARE $(s) ;
+
+ # Propagate on $(<) to $(>)
+
+ HDRSEARCH on $(s) = $(HDRSEARCH) ;
+ HDRSCAN on $(s) = $(HDRSCAN) ;
+ HDRRULE on $(s) = $(HDRRULE) ;
+ HDRGRIST on $(s) = $(HDRGRIST) ;
+}
+
+rule InstallInto
+{
+ local i t ;
+
+ t = $(>:G=installed) ;
+
+ DEPENDS install : $(t) ;
+ DEPENDS $(t) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+ MakeLocate $(t) : $(<) ;
+
+ # Arrange for jam uninstall
+
+ Clean uninstall : $(t) ;
+
+ for i in $(>)
+ {
+ Install $(i:G=installed) : $(i) ;
+ }
+
+ Chmod $(t) ;
+
+ if $(UNIX)
+ {
+ if $(OWNER) { Chown $(t) ; OWNER on $(t) = $(OWNER) ; }
+ if $(GROUP) { Chgrp $(t) ; GROUP on $(t) = $(GROUP) ; }
+ }
+}
+
+rule InstallBin
+{
+ local _t = [ FAppendSuffix $(>) : $(SUFEXE) ] ;
+
+ InstallInto $(<) : $(_t) ;
+ MODE on $(_t:G=installed) = $(EXEMODE) ;
+}
+
+rule InstallFile
+{
+ InstallInto $(<) : $(>) ;
+ MODE on $(>:G=installed) = $(FILEMODE) ;
+}
+
+rule InstallLib
+{
+ InstallInto $(<) : $(>) ;
+ MODE on $(>:G=installed) = $(FILEMODE) ;
+}
+
+rule InstallMan
+{
+ # Really this just strips the . from the suffix
+
+ local i s d ;
+
+ for i in $(>)
+ {
+ switch $(i:S)
+ {
+ case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;
+ case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;
+ case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;
+ case .n : s = n ; case .man : s = 1 ;
+ }
+
+ d = man$(s) ;
+
+ InstallInto $(d:R=$(<)) : $(i) ;
+ }
+
+ MODE on $(>:G=installed) = $(FILEMODE) ;
+}
+
+rule InstallShell
+{
+ InstallInto $(<) : $(>) ;
+ MODE on $(>:G=installed) = $(SHELLMODE) ;
+}
+
+rule Lex
+{
+ LexMv $(<) : $(>) ;
+ DEPENDS $(<) : $(>) ;
+ MakeLocate $(<) : $(LOCATE_SOURCE) ;
+ Clean clean : $(<) ;
+}
+
+rule Library
+{
+ LibraryFromObjects $(<) : $(>:S=$(SUFOBJ)) ;
+ Objects $(>) ;
+}
+
+rule LibraryFromObjects
+{
+ local _i _l _s ;
+
+ # Add grist to file names
+
+ _s = [ FGristFiles $(>) ] ;
+ _l = $(<:S=$(SUFLIB)) ;
+
+ # library depends on its member objects
+
+ if $(KEEPOBJS)
+ {
+ DEPENDS obj : $(_s) ;
+ }
+ else
+ {
+ DEPENDS lib : $(_l) ;
+ }
+
+ # Set LOCATE for the library and its contents. The bound
+ # value shows up as $(NEEDLIBS) on the Link actions.
+ # For compatibility, we only do this if the library doesn't
+ # already have a path.
+
+ if ! $(_l:D)
+ {
+ MakeLocate $(_l) $(_l)($(_s:BS)) : $(LOCATE_TARGET) ;
+ }
+
+ if $(NOARSCAN)
+ {
+ # If we can't scan the library to timestamp its contents,
+ # we have to just make the library depend directly on the
+ # on-disk object files.
+
+ DEPENDS $(_l) : $(_s) ;
+ }
+ else
+ {
+ # If we can scan the library, we make the library depend
+ # on its members and each member depend on the on-disk
+ # object file.
+
+ DEPENDS $(_l) : $(_l)($(_s:BS)) ;
+
+ for _i in $(_s)
+ {
+ DEPENDS $(_l)($(_i:BS)) : $(_i) ;
+ }
+ }
+
+ Clean clean : $(_l) ;
+
+ if $(CRELIB) { CreLib $(_l) : $(_s[1]) ; }
+
+ Archive $(_l) : $(_s) ;
+
+ if $(RANLIB) { Ranlib $(_l) ; }
+
+ # If we can't scan the library, we have to leave the .o's around.
+
+ if ! ( $(NOARSCAN) || $(KEEPOBJS) ) { RmTemps $(_l) : $(_s) ; }
+}
+
+rule Link
+{
+ MODE on $(<) = $(EXEMODE) ;
+ Chmod $(<) ;
+}
+
+rule LinkLibraries
+{
+ # make library dependencies of target
+ # set NEEDLIBS variable used by 'actions Main'
+
+ local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
+
+ DEPENDS $(_t) : $(>:S=$(SUFLIB)) ;
+ NEEDLIBS on $(_t) += $(>:S=$(SUFLIB)) ;
+}
+
+rule Main
+{
+ MainFromObjects $(<) : $(>:S=$(SUFOBJ)) ;
+ Objects $(>) ;
+}
+
+rule MainFromObjects
+{
+ local _s _t ;
+
+ # Add grist to file names
+ # Add suffix to exe
+
+ _s = [ FGristFiles $(>) ] ;
+ _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;
+
+ if $(_t) != $(<)
+ {
+ DEPENDS $(<) : $(_t) ;
+ NOTFILE $(<) ;
+ }
+
+ # make compiled sources a dependency of target
+
+ DEPENDS exe : $(_t) ;
+ DEPENDS $(_t) : $(_s) ;
+ MakeLocate $(_t) : $(LOCATE_TARGET) ;
+
+ Clean clean : $(_t) ;
+
+ Link $(_t) : $(_s) ;
+}
+
+rule MakeLocate
+{
+ if $(>)
+ {
+ LOCATE on $(<) = $(>) ;
+ Depends $(<) : $(>[1]) ;
+ MkDir $(>[1]) ;
+ }
+}
+
+rule MkDir
+{
+ # If dir exists, don't update it
+ # Do this even for $(DOT).
+
+ NOUPDATE $(<) ;
+
+ if $(<) != $(DOT) && ! $($(<)-mkdir)
+ {
+ local s ;
+
+ # Cheesy gate to prevent multiple invocations on same dir
+ # MkDir1 has the actions
+ # Arrange for jam dirs
+
+ $(<)-mkdir = true ;
+ MkDir1 $(<) ;
+ Depends dirs : $(<) ;
+
+ # Recursively make parent directories.
+ # $(<:P) = $(<)'s parent, & we recurse until root
+
+ s = $(<:P) ;
+
+ if $(NT)
+ {
+ switch $(s)
+ {
+ case *: : s = ;
+ case *:\\ : s = ;
+ }
+ }
+
+ if $(s) && $(s) != $(<)
+ {
+ Depends $(<) : $(s) ;
+ MkDir $(s) ;
+ }
+ else if $(s)
+ {
+ NOTFILE $(s) ;
+ }
+
+ }
+}
+
+rule Object
+{
+ local h ;
+
+ # locate object and search for source, if wanted
+
+ Clean clean : $(<) ;
+
+ MakeLocate $(<) : $(LOCATE_TARGET) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+
+ # Save HDRS for -I$(HDRS) on compile.
+ # We shouldn't need -I$(SEARCH_SOURCE) as cc can find headers
+ # in the .c file's directory, but generated .c files (from
+ # yacc, lex, etc) are located in $(LOCATE_TARGET), possibly
+ # different from $(SEARCH_SOURCE).
+
+ HDRS on $(<) = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;
+
+ # handle #includes for source: Jam scans for headers with
+ # the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
+ # with the scanned file as the target and the found headers
+ # as the sources. HDRSEARCH is the value of SEARCH used for
+ # the found header files. Finally, if jam must deal with
+ # header files of the same name in different directories,
+ # they can be distinguished with HDRGRIST.
+
+ # $(h) is where cc first looks for #include "foo.h" files.
+ # If the source file is in a distant directory, look there.
+ # Else, look in "" (the current directory).
+
+ if $(SEARCH_SOURCE)
+ {
+ h = $(SEARCH_SOURCE) ;
+ }
+ else
+ {
+ h = "" ;
+ }
+
+ HDRRULE on $(>) = HdrRule ;
+ HDRSCAN on $(>) = $(HDRPATTERN) ;
+ HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(h) $(STDHDRS) ;
+ HDRGRIST on $(>) = $(HDRGRIST) ;
+
+ # if source is not .c, generate .c with specific rule
+
+ switch $(>:S)
+ {
+ case .asm : As $(<) : $(>) ;
+ case .c : Cc $(<) : $(>) ;
+ case .C : C++ $(<) : $(>) ;
+ case .cc : C++ $(<) : $(>) ;
+ case .cpp : C++ $(<) : $(>) ;
+ case .f : Fortran $(<) : $(>) ;
+ case .l : Cc $(<) : $(<:S=.c) ;
+ Lex $(<:S=.c) : $(>) ;
+ case .s : As $(<) : $(>) ;
+ case .y : Cc $(<) : $(<:S=.c) ;
+ Yacc $(<:S=.c) : $(>) ;
+ case * : UserObject $(<) : $(>) ;
+ }
+}
+
+
+rule ObjectCcFlags
+{
+ CCFLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;
+}
+
+rule ObjectC++Flags
+{
+ C++FLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;
+}
+
+rule ObjectHdrs
+{
+ HDRS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;
+}
+
+rule Objects
+{
+ local _i ;
+
+ for _i in [ FGristFiles $(<) ]
+ {
+ Object $(_i:S=$(SUFOBJ)) : $(_i) ;
+ DEPENDS obj : $(_i:S=$(SUFOBJ)) ;
+ }
+}
+
+rule RmTemps
+{
+ TEMPORARY $(>) ;
+}
+
+rule Setuid
+{
+ MODE on [ FAppendSuffix $(<) : $(SUFEXE) ] = 4711 ;
+}
+
+rule Shell
+{
+ DEPENDS shell : $(<) ;
+ DEPENDS $(<) : $(>) ;
+ SEARCH on $(>) = $(SEARCH_SOURCE) ;
+ MODE on $(<) = $(SHELLMODE) ;
+ Clean clean : $(<) ;
+ Chmod $(<) ;
+}
+
+rule SubDir
+{
+ local _r _s ;
+
+ #
+ # SubDir TOP d1 [ ... ]
+ #
+ # This introduces a Jamfile that is part of a project tree
+ # rooted at $(TOP). It (only once) includes the project-specific
+ # rules file $(TOP)/Jamrules and then sets search & locate stuff.
+ #
+ # If the variable $(TOPRULES) is set (where TOP is the first arg
+ # to SubDir), that file is included instead of $(TOP)/Jamrules.
+ #
+ # d1 ... are the directory elements that lead to this directory
+ # from $(TOP). We construct the system dependent path from these
+ # directory elements in order to set search&locate stuff.
+ #
+
+ if ! $($(<[1]))
+ {
+ if ! $(<[1])
+ {
+ EXIT SubDir syntax error ;
+ }
+
+ $(<[1]) = [ FSubDir $(<[2-]) ] ;
+ }
+
+ #
+ # If $(TOP)/Jamrules hasn't been included, do so.
+ #
+
+ if ! $($(<[1])-included)
+ {
+ # Gated entry.
+
+ $(<[1])-included = TRUE ;
+
+ # File is $(TOPRULES) or $(TOP)/Jamrules.
+
+ _r = $($(<[1])RULES) ;
+
+ if ! $(_r)
+ {
+ _r = $(JAMRULES:R=$($(<[1]))) ;
+ }
+
+ # Include it.
+
+ include $(_r) ;
+ }
+
+ # Get path to current directory from root using SubDir.
+ # Save dir tokens for other potential uses.
+
+ _s = [ FDirName $(<[2-]) ] ;
+ SUBDIR = $(_s:R=$($(<[1]))) ;
+ SUBDIR_TOKENS = $(<[2-]) ;
+
+ # Now set up SEARCH_SOURCE, LOCATE_TARGET, SOURCE_GRIST
+ # These can be reset if needed. For example, if the source
+ # directory should not hold object files, LOCATE_TARGET can
+ # subsequently be redefined.
+
+ SEARCH_SOURCE = $(SUBDIR) ;
+ LOCATE_SOURCE = $(ALL_LOCATE_TARGET) $(SUBDIR) ;
+ LOCATE_TARGET = $(ALL_LOCATE_TARGET) $(SUBDIR) ;
+ SOURCE_GRIST = [ FGrist $(<[2-]) ] ;
+
+ # Reset per-directory ccflags, hdrs
+
+ SUBDIRCCFLAGS = ;
+ SUBDIRC++FLAGS = ;
+ SUBDIRHDRS = ;
+}
+
+rule SubDirCcFlags
+{
+ SUBDIRCCFLAGS += $(<) ;
+}
+
+rule SubDirC++Flags
+{
+ SUBDIRC++FLAGS += $(<) ;
+}
+
+rule SubDirHdrs
+{
+ SUBDIRHDRS += $(<) ;
+}
+
+rule SubInclude
+{
+ local _s ;
+
+ # That's
+ # SubInclude TOP d1 [ d2 [ d3 [ d4 ] ] ]
+ #
+ # to include a subdirectory's Jamfile.
+
+ if ! $($(<[1]))
+ {
+ EXIT Top level of source tree has not been set with $(<[1]) ;
+ }
+
+ _s = [ FDirName $(<[2-]) ] ;
+
+ include $(JAMFILE:D=$(_s):R=$($(<[1]))) ;
+}
+
+rule Undefines
+{
+ UNDEFS on [ FAppendSuffix $(<) : $(SUFEXE) ] += $(UNDEFFLAG)$(>) ;
+}
+
+rule UserObject
+{
+ EXIT "Unknown suffix on" $(>) "- see UserObject rule in Jamfile(5)." ;
+}
+
+rule Yacc
+{
+ local _h ;
+
+ _h = $(<:BS=.h) ;
+
+ # Some places don't have a yacc.
+
+ MakeLocate $(<) $(_h) : $(LOCATE_SOURCE) ;
+
+ if $(YACC)
+ {
+ DEPENDS $(<) $(_h) : $(>) ;
+ Yacc1 $(<) $(_h) : $(>) ;
+ YaccMv $(<) $(_h) : $(>) ;
+ Clean clean : $(<) $(_h) ;
+ }
+
+ # make sure someone includes $(_h) else it will be
+ # a deadly independent target
+
+ INCLUDES $(<) : $(_h) ;
+}
+
+#
+# Utility rules; no side effects on these
+#
+
+rule FGrist
+{
+ # Turn individual elements in $(<) into grist.
+
+ local _g _i ;
+
+ _g = $(<[1]) ;
+
+ for _i in $(<[2-])
+ {
+ _g = $(_g)!$(_i) ;
+ }
+
+ return $(_g) ;
+}
+
+rule FGristFiles
+{
+ if ! $(SOURCE_GRIST)
+ {
+ return $(<) ;
+ }
+ else
+ {
+ return $(<:G=$(SOURCE_GRIST)) ;
+ }
+}
+
+rule FGristSourceFiles
+{
+ # Produce source file name name with grist in it,
+ # if SOURCE_GRIST is set.
+
+ # Leave header files alone, because they have a global
+ # visibility.
+
+ if ! $(SOURCE_GRIST)
+ {
+ return $(<) ;
+ }
+ else
+ {
+ local _i _o ;
+
+ for _i in $(<)
+ {
+ switch $(_i)
+ {
+ case *.h : _o += $(_i) ;
+ case * : _o += $(_i:G=$(SOURCE_GRIST)) ;
+ }
+ }
+
+ return $(_o) ;
+ }
+}
+
+rule FConcat
+{
+ # Puts the variables together, removing spaces.
+
+ local _t _r ;
+
+ $(_r) = $(<[1]) ;
+
+ for _t in $(<[2-])
+ {
+ $(_r) = $(_r)$(_t) ;
+ }
+
+ return $(_r) ;
+}
+
+rule FSubDir
+{
+ local _i _d ;
+
+ # If $(>) is the path to the current directory, compute the
+ # path (using ../../ etc) back to that root directory.
+ # Sets result in $(<)
+
+ if ! $(<[1])
+ {
+ _d = $(DOT) ;
+ }
+ else
+ {
+ _d = $(DOTDOT) ;
+
+ for _i in $(<[2-])
+ {
+ _d = $(_d:R=$(DOTDOT)) ;
+ }
+ }
+
+ return $(_d) ;
+}
+
+rule FDirName
+{
+ local _s _i ;
+
+ # Turn individual elements in $(<) into a usable path.
+
+ if ! $(<)
+ {
+ _s = $(DOT) ;
+ }
+ else if $(VMS)
+ {
+ # This handles the following cases:
+ # a -> [.a]
+ # a b c -> [.a.b.c]
+ # x: -> x:
+ # x: a -> x:[a]
+ # x:[a] b -> x:[a.b]
+
+ switch $(<[1])
+ {
+ case *:* : _s = $(<[1]) ;
+ case \\[*\\] : _s = $(<[1]) ;
+ case * : _s = [.$(<[1])] ;
+ }
+
+ for _i in [.$(<[2-])]
+ {
+ _s = $(_i:R=$(_s)) ;
+ }
+ }
+ else if $(MAC)
+ {
+ _s = $(DOT) ;
+
+ for _i in $(<)
+ {
+ _s = $(_i:R=$(_s)) ;
+ }
+ }
+ else
+ {
+ _s = $(<[1]) ;
+
+ for _i in $(<[2-])
+ {
+ _s = $(_i:R=$(_s)) ;
+ }
+ }
+
+ return $(_s) ;
+}
+
+
+rule _makeCommon
+{
+ # strip common initial elements
+
+ if $($(<)[1]) && $($(<)[1]) = $($(>)[1])
+ {
+ $(<) = $($(<)[2-]) ;
+ $(>) = $($(>)[2-]) ;
+ _makeCommon $(<) : $(>) ;
+ }
+}
+
+
+rule FRelPath
+{
+ local _l _r ;
+
+ # first strip off common parts
+
+ _l = $(<) ;
+ _r = $(>) ;
+
+ _makeCommon _l : _r ;
+
+ # now make path to root and path down
+
+ _l = [ FSubDir $(_l) ] ;
+ _r = [ FDirName $(_r) ] ;
+
+ # Concatenate and save
+
+ # XXX This should be better
+
+ if $(_r) = $(DOT) {
+ return $(_l) ;
+ } else {
+ return $(_r:R=$(_l)) ;
+ }
+}
+
+rule FAppendSuffix
+{
+ # E.g., "FAppendSuffix yacc lex foo.bat : $(SUFEXE) ;"
+ # returns (yacc,lex,foo.bat) on Unix and
+ # (yacc.exe,lex.exe,foo.bat) on NT.
+
+ if $(>)
+ {
+ local _i _o ;
+
+ for _i in $(<)
+ {
+ if $(_i:S)
+ {
+ _o += $(_i) ;
+ }
+ else
+ {
+ _o += $(_i:S=$(>)) ;
+ }
+ }
+ return $(_o) ;
+ }
+ else
+ {
+ return $(<) ;
+ }
+}
+
+rule unmakeDir
+{
+ if $(>[1]:D) && $(>[1]:D) != $(>[1]) && $(>[1]:D) != \\\\
+ {
+ unmakeDir $(<) : $(>[1]:D) $(>[1]:BS) $(>[2-]) ;
+ }
+ else
+ {
+ $(<) = $(>) ;
+ }
+}
+
+
+rule FConvertToSlashes
+{
+ local _d, _s, _i ;
+
+ unmakeDir _d : $(<) ;
+
+ _s = $(_d[1]) ;
+ for _i in $(_d[2-])
+ {
+ _s = $(_s)/$(_i) ;
+ }
+ return $(_s) ;
+}
+
+
+#
+# Actions
+#
+
+#
+# First the defaults
+#
+
+actions updated together piecemeal Archive
+{
+ $(AR) $(<) $(>)
+}
+
+actions As
+{
+ $(AS) $(ASFLAGS) -I$(HDRS) -o $(<) $(>)
+}
+
+actions C++
+{
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
+}
+
+actions Cc
+{
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
+}
+
+actions Chgrp
+{
+ chgrp $(GROUP) $(<)
+}
+
+actions Chmod1
+{
+ $(CHMOD) $(MODE) $(<)
+}
+
+actions Chown
+{
+ chown $(OWNER) $(<)
+}
+
+actions piecemeal together existing Clean
+{
+ $(RM) $(>)
+}
+
+actions File
+{
+ $(CP) $(>) $(<)
+}
+
+actions GenFile1
+{
+ $(>[1]) $(<) $(>[2-])
+}
+
+actions Fortran
+{
+ $(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)
+}
+
+actions HardLink
+{
+ $(RM) $(<) && $(LN) $(>) $(<)
+}
+
+actions Install
+{
+ $(CP) $(>) $(<)
+}
+
+actions Lex
+{
+ $(LEX) $(>)
+}
+
+actions LexMv
+{
+ $(MV) lex.yy.c $(<)
+}
+
+actions Link bind NEEDLIBS
+{
+ $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+}
+
+actions MkDir1
+{
+ $(MKDIR) $(<)
+}
+
+actions together Ranlib
+{
+ $(RANLIB) $(<)
+}
+
+actions quietly updated piecemeal together RmTemps
+{
+ $(RM) $(>)
+}
+
+actions Shell
+{
+ $(AWK) '
+ NR == 1 { print "$(SHELLHEADER)" }
+ NR == 1 && /^[#:]/ { next }
+ /^##/ { next }
+ { print }
+ ' < $(>) > $(<)
+}
+
+actions Yacc1
+{
+ $(YACC) $(YACCFLAGS) $(>)
+}
+
+actions YaccMv
+{
+ $(MV) $(YACCFILES).c $(<[1])
+ $(MV) $(YACCFILES).h $(<[2])
+}
+
+#
+# RELOCATE - for compilers with broken -o flags
+#
+
+if $(RELOCATE)
+{
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) $(>)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) $(>)
+ }
+
+ actions ignore CcMv
+ {
+ [ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)
+ }
+}
+
+#
+# NOARUPDATE - can't update an archive
+#
+
+if $(NOARUPDATE)
+{
+ actions Archive
+ {
+ $(AR) $(<) $(>)
+ }
+}
+
+#
+# NT specific actions
+#
+
+if $(NT)
+{
+ if $(TOOLSET) = VISUALC || $(TOOLSET) = INTELC
+ {
+ actions updated together piecemeal Archive
+ {
+ if exist $(<) set _$(<:B)_=$(<)
+ $(AR) /out:$(<) %_$(<:B)_% $(>)
+ }
+
+ actions As
+ {
+ $(AS) /Ml /p /v /w2 $(>) $(<) ,nul,nul;
+ }
+
+ actions Cc
+ {
+ $(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) /Tp$(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+ }
+ else if $(TOOLSET) = VISUALC16
+ {
+ actions updated together piecemeal Archive
+ {
+ $(AR) $(<) -+$(>)
+ }
+
+ actions Cc
+ {
+ $(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /Tp$(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+ }
+ else if $(TOOLSET) = BORLANDC
+ {
+ actions updated together piecemeal Archive
+ {
+ $(AR) $(<) -+$(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) -e$(<) $(LINKFLAGS) $(UNDEFS) -L$(LINKLIBS) $(NEEDLIBS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ }
+ else if $(TOOLSET) = MINGW
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) $(>:T)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+ }
+ else if $(TOOLSET) = WATCOM
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) +-$(>)
+ }
+
+ actions Cc
+ {
+ $(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+ }
+ else if $(TOOLSET) = LCC
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) /out:$(<) $(>)
+ }
+
+ actions Cc
+ {
+ $(CC) $(CCFLAGS) $(OPTIM) -Fo$(<) -I$(HDRS) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+ }
+}
+
+#
+# OS2 specific actions
+#
+
+else if $(OS2)
+{
+ if $(TOOLSET) = WATCOM
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) +-$(>)
+ }
+
+ actions Cc
+ {
+ $(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+ }
+ else if $(TOOLSET) = EMX
+ {
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) $(>:T)
+ }
+
+ actions Cc
+ {
+ $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+
+ actions C++
+ {
+ $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)
+ }
+ }
+}
+
+#
+# VMS specific actions
+#
+
+else if $(VMS)
+{
+ actions updated together piecemeal Archive
+ {
+ lib/replace $(<) $(>[1]) ,$(>[2-])
+ }
+
+ actions Cc
+ {
+ $(CC)/obj=$(<) $(CCFLAGS) $(OPTIM) $(SLASHINC) $(>)
+ }
+
+ actions C++
+ {
+ $(C++)/obj=$(<) $(C++FLAGS) $(OPTIM) $(SLASHINC) $(>)
+ }
+
+ actions piecemeal together existing Clean
+ {
+ $(RM) $(>[1]);* ,$(>[2-]);*
+ }
+
+ actions together quietly CreLib
+ {
+ if f$search("$(<)") .eqs. "" then lib/create $(<)
+ }
+
+ actions GenFile1
+ {
+ mcr $(>[1]) $(<) $(>[2-])
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK)/exe=$(<) $(LINKFLAGS) $(>[1]) ,$(>[2-]) ,$(NEEDLIBS)/lib ,$(LINKLIBS)
+ }
+
+ actions quietly updated piecemeal together RmTemps
+ {
+ $(RM) $(>[1]);* ,$(>[2-]);*
+ }
+
+ actions Shell
+ {
+ $(CP) $(>) $(<)
+ }
+}
+
+#
+# Mac specifc actions
+#
+
+else if $(MAC)
+{
+ actions together Archive
+ {
+ $(LINK) -library -o $(<) $(>)
+ }
+
+ actions Cc
+ {
+ set -e MWCincludes $(MACINC)
+ $(CC) -o $(<) $(CCFLAGS) $(OPTIM) $(>)
+ }
+
+ actions C++
+ {
+ set -e MWCincludes $(MACINC)
+ $(CC) -o $(<) $(C++FLAGS) $(OPTIM) $(>)
+ }
+
+ actions Link bind NEEDLIBS
+ {
+ $(LINK) -o $(<) $(LINKFLAGS) $(>) $(NEEDLIBS) "$(LINKLIBS)"
+ }
+}
+
+#
+# Backwards compatibility with jam 1, where rules were uppercased.
+#
+
+rule BULK { Bulk $(<) : $(>) ; }
+rule FILE { File $(<) : $(>) ; }
+rule HDRRULE { HdrRule $(<) : $(>) ; }
+rule INSTALL { Install $(<) : $(>) ; }
+rule LIBRARY { Library $(<) : $(>) ; }
+rule LIBS { LinkLibraries $(<) : $(>) ; }
+rule LINK { Link $(<) : $(>) ; }
+rule MAIN { Main $(<) : $(>) ; }
+rule SETUID { Setuid $(<) ; }
+rule SHELL { Shell $(<) : $(>) ; }
+rule UNDEFINES { Undefines $(<) : $(>) ; }
+
+# Old INSTALL* didn't take dest directory.
+
+rule INSTALLBIN { InstallBin $(BINDIR) : $(<) ; }
+rule INSTALLLIB { InstallLib $(LIBDIR) : $(<) ; }
+rule INSTALLMAN { InstallMan $(MANDIR) : $(<) ; }
+
+# Compatibility with jam 2.2.
+
+rule addDirName { $(<) += [ FDirName $(>) ] ; }
+rule makeDirName { $(<) = [ FDirName $(>) ] ; }
+rule makeGristedName { $(<) = [ FGristSourceFiles $(>) ] ; }
+rule makeRelPath { $(<[1]) = [ FRelPath $(<[2-]) : $(>) ] ; }
+rule makeSuffixed { $(<[1]) = [ FAppendSuffix $(>) : $(<[2]) ] ; }
+
+#
+# Now include the user's Jamfile.
+#
+
+{
+ if $(JAMFILE) { include $(JAMFILE) ; }
+}
+
+}
\ No newline at end of file
diff --git a/jam_src/Jambase.html b/jam_src/Jambase.html
new file mode 100644
index 000000000..2c108f8fa
--- /dev/null
+++ b/jam_src/Jambase.html
@@ -0,0 +1,881 @@
+
+
+Jambase Reference
+
+
+
+
+Jam/MR
+
+
+
+
+ Jambase is a base set of Jam/MR rules which
+ provide roughly make(1)-like functionality for
+ jam, the Jam/MR executable program.
+ This document, which started out as the Jambase(5) man page,
+ is a reference guide to the
+ rules,
+ pseudotargets,
+ and variables
+ defined in Jambase for use in Jamfiles.
+
+ For further information see:
+
+
+Jam/MR documentation and source are available from the
+Perforce Public Depot.
+For detailed information about any of the rules summarized below,
+see the
+Jambase
+file itself.
+
+
+
+ As obj.o : source.s ;
+
+ Assemble the file source.s. Called by the Object
+ rule.
+
+ Bulk directory : sources ;
+
+ Copies sources into directory.
+
+ Cc object : source ;
+
+ Compile the file source into object, using the C
+ compiler $(CC), its flags $(CCFLAGS) and $(OPTIM),
+ and the header file directories $(HDRS). Called by
+ the Object rule.
+
+ C++ obj.o : source.cc ;
+
+ Compile the C++ source file source.cc. Called by
+ the Object rule.
+
+ Chmod target ;
+
+ (Unix and VMS only.)
+ Change file permissions on target to
+ target-specific $(MODE) value set by Link, File,
+ Install*, and Shell rules.
+
+
+ Clean clean : targets ;
+
+ Removes existing targets when clean is built.
+ clean is not a dependency of all, and must be built
+ explicitly for targets to be removed.
+
+ File target : source ;
+
+ Copies source into target.
+
+ Fortran obj.o : source.f ;
+
+ Compile the Fortran source file source.f. Called
+ by the Object rule.
+
+
+ GenFile target : image sources ;
+
+ Runs the command "image target sources"
+ to create target from sources and
+ image. (where image is an
+ executable built by the Main rule.)
+
+ HardLink target : source ;
+
+ Makes target a hard link to source, if it isn't one
+ already. (Unix only.)
+
+ HdrRule source : headers ;
+
+ Arranges the proper dependencies when the file
+ source includes the files headers through the
+ "#include" C preprocessor directive.
+
+ This rule is not intended to be called explicitly.
+ It is called automatically during header scanning on
+ sources handled by the Object rule (e.g., sources in
+ Main or Library rules).
+
+ InstallBin dir : sources ;
+ Copy sources into dir with mode
+ $(EXEMODE).
+
+ InstallLib dir : sources ;
+ Copy sources into dir with mode
+ $(FILEMODE).
+
+ InstallMan dir : sources ;
+ Copy sources into the appropriate subdirectory
+ of dir with mode $(FILEMODE). The subdirectory
+ is mans, where s is the suffix of
+ each of sources.
+
+ InstallShell dir : sources ;
+ Copy sources into dir with mode
+ $(SHELLMODE).
+
+ Lex source.c : source.l ;
+ Process the lex(1) source file source.l and
+ rename the lex.yy.c to source.c. Called by
+ the Object rule.
+
+ Library library : sources ;
+ Compiles sources and archives them into
+ library. The intermediate objects
+ are deleted. Calls Objects and LibraryFromObjects.
+
+ If Library is invoked with no suffix on library,
+ the $(SUFLIB) suffix is used.
+
+ LibraryFromObjects library : objects ;
+
+ Archives objects into library. The
+ objects are then deleted.
+
+ If library has no suffix, the $(SUFLIB) suffix is used.
+
+ Link image : objects ;
+
+ Links image from objects and sets
+ permissions on image to $(EXEMODE).
+ Image must be actual filename; suffix is not
+ supplied.
+ Called by Main.
+
+
+ LinkLibraries image : libraries ;
+
+ Makes image depend on libraries and
+ includes them during the linking.
+
+ Image may be referenced without a suffix in this
+ rule invocation; LinkLibraries supplies the suffix.
+
+ Main image : sources ;
+
+ Compiles sources and links them into image.
+ Calls Objects and MainFromObjects.
+
+ Image may be referenced without a suffix in this
+ rule invocation; Main supplies the suffix.
+
+ MainFromObjects image : objects ;
+
+ Links objects into image. Dependency
+ of exe. MainFromObjects supplies the suffix on image
+ filename.
+
+ MakeLocate target : dir ;
+
+ Creates dir and causes target to be built
+ into dir.
+
+ MkDir dir ;
+
+ Creates dir and its parent directories.
+
+ Object object : source ;
+
+ Compiles a single source file source into
+ object. The Main and Library rules use
+ this rule to compile source files.
+
+ Causes source to be scanned for "#include"
+ directives and calls HdrRule to make all included
+ files dependedencies of object.
+
+ Calls one of the following rules to do the actual
+ compiling, depending on the suffix of source:
+
+ *.c: Cc
+ *.cc: C++
+ *.cpp: C++
+ *.C: C++
+ *.l: Lex
+ *.y: Yacc
+ *.*: UserObject
+
+
+ ObjectC++Flags source : flags ;
+
+ ObjectCcFlags source : flags ;
+
+ Add flags to the source-specific
+ value of $(CCFLAGS) or $(C++FLAGS) when compiling source.
+ Any file suffix on source is ignored.
+
+ ObjectHdrs source : dirs ;
+ Add dirs to the source-specific value of
+ $(HDRS) when scanning and compiling source.
+ Any file suffix on source is ignored.
+
+ Objects sources ;
+ For each source file in sources, calls
+ Object to compile the source file into a similarly
+ named object file.
+
+ RmTemps targets : sources ;
+ Marks sources as temporary with the TEMPORARY
+ rule, and deletes sources once targets
+ are built. Must be the last rule invoked on
+ targets. Used internally by LibraryFromObjects rule.
+
+ Setuid images ;
+ Sets the setuid bit on each of images after
+ linking. (Unix only.)
+
+
+ SubDir VAR d1 ... dn ;
+
+ Sets up housekeeping for the source files located
+ in $(VAR)/d1/.../dn:
+
+ - Reads in rules file associated with VAR,
+ if it hasn't already been read.
+
- Initializes variables for search paths,
+ output directories, compiler
+ flags, and grist, using d1 ... dn tokens.
+
+
+ VAR is the name of a variable;
+ d1 thru dn are elements
+ of a directory path.
+
+ SubDirC++Flags flags ;
+
+ SubDirCcFlags flags ;
+
+ Adds flags to the compiler flags for source files
+ in SubDir's directory.
+
+ SubDirHdrs paths ;
+
+ Adds paths to the header search paths for source files
+ in SubDir's directory.
+
+ SubInclude VAR d1 ... dn ;
+
+ Reads the Jamfile in $(VAR)/d1/.../dn/.
+
+ Shell image : source ;
+ Copies source into the executable sh(1)
+ script image. Ensures that the first line of
+ the script is $(SHELLHEADER) (default #!/bin/sh).
+
+ Undefines images : symbols ;
+ Adds flags to mark symbols as undefined
+ on link command for images.
+ Images may be referenced unsuffixed; the
+ Undefines rule supplies the suffix.
+
+ UserObject object : source ;
+ This rule is called by Object for source
+ files with unknown suffixes, and should be defined
+ in Jamrules
+ with a user-provided rule to handle the source file
+ types not handled by the Object rule.
+ The Jambase UserObject rule merely issues a
+ complaint when it encounters source with
+ files suffixes it does not recognize.
+
+ Yacc source.c : source.y ;
+ Process the yacc(1) file source.y and renamed
+ the resulting y.tab.c and y.tab.h to source.c.
+ Produces a y.tab.h and renames it to source.h.
+ Called by the Object rule.
+
+
+
+
+
+Jambase Pseudotargets
+
+
+
+There are two kinds of Jam targets: file targets and pseudotargets.
+File targets are objects that can be found in the filesystem.
+Pseudotargets are symbolic, and usually represent other targets.
+Most Jambase rules that define file targets also define pseudotargets
+which are dependent on types of file targets. The Jambase pseudotargets
+are:
+
+
+| exe
+ | Executables linked by the Main or MainFromObjects rules
+
+ |
| lib
+ | Libraries created by the Library or LibraryFromObjects rules
+
+ |
| obj
+ | Compiled objects used to create Main or Library targets
+
+ |
| dirs
+ | Directories where target files are written
+
+ |
| file
+ | Files copied by File and Bulk rules
+
+ |
| shell
+ | Files copied by Shell rule
+
+ |
| clean
+ | Removal of built targets (except files copied by Install* rules)
+
+ |
| install
+ | Files copied by Install* rules
+
+ |
| uninstall
+ | Removal of targets copied by Install* rules
+
+ |
+
+
+In addition, Jambase makes the jam default target "all"
+depend on "exe", "lib", "obj", "files", and "shell".
+
+
+
+
+
+Jambase Variables
+
+
+
+ Most of the following variables have default values for
+ each platform; refer to the Jambase file to see what those
+ defaults are.
+
+ ALL_LOCATE_TARGET
+
+ Alternative location of built targets. By default,
+ Jambase rules locate built targets in the source
+ tree. By setting $(ALL_LOCATE_TARGET)
+ in Jamrules, you can cause jam
+ to write built targets to a location outside
+ the source tree.
+
+
+ AR
+
+
+ The archive command used to update Library
+ and LibraryFromObjects targets.
+
+ AS
+
+ The assembler for As rule targets.
+
+
+ ASFLAGS
+
+
+ Flags handed to the assembler for As.
+
+
+ AWK
+
+
+ The name of awk interpreter, used when copying a
+ shell script for the Shell rule.
+
+
+ BCCROOT
+
+ Selects Borland compile and link actions on NT.
+
+
+
+ BINDIR
+
+
+ Not longer used.
+ (I.e., used only for backward compatibility with the
+ obsolete INSTALLBIN rule.)
+
+
+ CC
+
+
+ C compiler used for Cc rule targets.
+
+
+ CCFLAGS
+
+
+ Compile flags for Cc rule targets.
+ The Cc rule sets target-specific $(CCFLAGS)
+ values on its targets.
+
+
+ C++
+
+
+ C++ compiler used for C++ rule targets.
+
+
+ C++FLAGS
+
+
+ Compile flags for C++ rule targets.
+ The C++ rule sets target-specific $(C++FLAGS)
+ values on its targets.
+
+
+ CHMOD
+
+
+ Program (usually chmod(1)) used to set file
+ permissions for Chmod rule.
+
+
+ CP
+
+
+ The file copy program, used by File and Install* rules.
+
+
+ CRELIB
+
+
+ If set, causes the Library rule to invoke the CreLib
+ rule on the target library before attempting to archive
+ any members, so that the library can be created if
+ needed.
+
+
+ CW
+
+
+ On Macintosh, the root of the Code Warrior Pro 5 directory.
+
+
+ DOT
+
+
+ The operating system-specific name for the current directory.
+
+
+ DOTDOT
+
+
+ The operating system-specific name for the parent directory.
+
+
+ EXEMODE
+
+
+ Permissions for executables linked with Link, Main,
+ and MainFromObjects, on platforms with a Chmod action.
+
+
+ FILEMODE
+
+
+ Permissions for files copied by File or Bulk,
+ on platforms with a Chmod action.
+
+
+ FORTRAN
+
+
+ The Fortran compiler used by Fortran rule.
+
+
+ FORTRANFLAGS
+
+
+ Fortran compiler flags for Fortran rule targets.
+
+
+ GROUP
+
+
+ (Unix only.)
+ The group owner for Install* rule targets.
+
+
+ HDRGRIST
+
+
+ If set, used by the HdrRule to distinguish header files
+ with the same name in diffrent directories.
+
+
+ HDRPATTERN
+
+
+ A regular expression pattern that matches
+ C preprocessor "#include" directives in source files
+ and returns the name of the included file.
+
+
+ HDRRULE
+
+
+ Name of the rule to invoke with the results of header file
+ scanning. Default is "HdrRule".
+
+ This is a jam-special variable. If both HDRRULE and HDRSCAN
+ are set on a target,
+ that target will be scanned for lines
+ matching $(HDRSCAN), and $(HDDRULE) will be
+ invoked on included files found in the matching $(HDRSCAN) lines.
+
+
+ HDRS
+
+
+ Directories to be searched for header files.
+ This is used by the Object rule to:
+
+ - set up search paths for finding files returned
+ by header scans
+
- add -I flags on compile commands
+
+ (See STDHDRS.)
+
+
+ HDRSCAN
+
+
+ Regular expression pattern to use for header file
+ scanning. The Object rule sets this to $(HDRPATTERN).
+ This is a jam-special variable; see HDRRULE.
+
+
+ HDRSEARCH
+
+
+ Used by the HdrRule to fix the list of directories where
+ header files can be found for a given source file.
+
+
+ JAMFILE
+
+
+ Default is "Jamfile"; the name of the user-written
+ rules file found in each source directory.
+
+
+ JAMRULES
+
+
+ Default is "Jamrules"; the name of a rule definition
+ file to be read in at the first SubDir rule invocation.
+
+
+ KEEPOBJS
+
+
+ If set, tells the LibraryFromObjects rule not to delete
+ object files once they are archived.
+
+
+ LEX
+
+
+ The lex(1) command and flags.
+
+
+ LIBDIR
+
+
+ Not longer used.
+ (I.e., used only for backward compatibility with the
+ obsolete INSTALLLIB rule.)
+
+
+ LINK
+
+
+ The linker. Defaults to $(CC).
+
+
+ LINKFLAGS
+
+
+ Flags handed to the linker. Defaults to $(CCFLAGS).
+
+
+ LINKLIBS
+
+
+ List of external libraries to link with. The target image
+ does not depend on these libraries.
+
+
+ LN
+
+
+ The hard link command for HardLink rule.
+
+
+ LOCATE_SOURCE
+
+ Used to set the location of generated source files.
+ The Yacc, Lex, and GenFile rules set LOCATE on
+ their targets to $(LOCATE_SOURCE).
+ $(LOCATE_SOURCE) is initialized by the SubDir rule
+ to the source directory itself.
+ (Also, see ALL_LOCATE_TARGET.)
+
+
+ LOCATE_TARGET
+
+ Used to set the location of built binary targets.
+ The Object rule, and hence the Main and Library rules,
+ set LOCATE on their targets to $(LOCATE_TARGET).
+ $(LOCATE_TARGET) is initialized by the
+ SubDir rule to the source directory itself.
+ (See ALL_LOCATE_TARGET.)
+
+
+
+ MANDIR
+
+
+ Not longer used.
+ (I.e., used only for backward compatibility with the
+ obsolete INSTALLMAN rule.)
+
+
+ MKDIR
+
+
+ The 'create directory' command used for the MkDir
+ rule.
+
+
+ MODE
+
+
+ The target-specific file mode (permissions) for targets
+ of the Shell, Setuid, Link, and Install* rules.
+ Used by the Chmod action; hence relevant to NT and VMS
+ only.
+
+
+ MSVC
+
+ Selects Microsoft Visual C 16-bit compile & link
+ actions on NT.
+
+
+ MSVCNT
+
+ Selects Microsoft Visual C NT compile & link
+ actions on NT.
+
+
+
+ MV
+
+
+ The file rename command and options.
+
+
+ NEEDLIBS
+
+
+ The list of libraries used when linking an executable.
+ Used by the Link rule.
+
+
+ NOARSCAN
+
+
+ If set, indicates that library members' timestamps can't
+ be found, and prevents the individual objects from being
+ deleted, so that their timestamps can be used instead.
+
+
+ NOARUPDATE
+
+
+ If set, indicates that libraries can't be updated, but only
+ created whole.
+
+
+ OPTIM
+
+
+ The C compiler flag for optimization, used by Cc and C++
+ rules.
+
+
+ OSFULL
+
+
+ The concatenation of $(OS)$(OSVER)$(OSPLAT), used when jam
+ builds itself to determine the target binary directory.
+ $(OS) and $(OSPLAT) are determined by jam at its compile
+ time (in jam.h). $(OSVER) can optionally be set by the user.
+
+
+
+ OWNER
+
+
+ The owner of installed files. Used by Install* rules.
+
+
+ RANLIB
+
+
+ The name of the ranlib command. If set, causes
+ the Ranlib action to be applied after the
+ Archive action to targets of the Library rule.
+
+
+ RELOCATE
+
+
+ If set, tells the Cc rule to move the output object
+ file to its target directory because the cc command
+ has a broken -o option.
+
+
+ RM
+
+
+ The command and options to remove a file.
+
+
+ SEARCH_SOURCE
+
+
+ The directory to find sources listed with Main,
+ Library, Object, Bulk, File, Shell, InstallBin,
+ InstallLib, and InstallMan rules. This works by
+ setting the jam-special variable SEARCH to the
+ value of $(SEARCH_SOURCE) for each of the rules'
+ sources. The SubDir rule initializes SEARCH_SOURCE
+ for each directory.
+
+
+ SHELLHEADER
+
+
+ A string inserted to the first line of every file
+ created by the Shell rule.
+
+
+ SHELLMODE
+
+
+ Permissions for files installed by Shell rule.
+
+
+ SOURCE_GRIST
+
+
+ Set by the SubDir to a value derived from the
+ directory name, and used by Objects and related
+ rules as 'grist' to perturb file names.
+
+
+ STDHDRS
+
+
+ Directories where headers can be found without
+ resorting to using the flag to the C compiler.
+ The $(STDHDRS) directories are used to find
+ headers during scanning, but are not passed to the
+ compiler commands as -I paths.
+
+
+ SUBDIR
+
+
+ The path from the current directory to the directory
+ last named by the SubDir rule.
+
+
+ TOP
+
+
+ The path from the current directory to the directory
+ that has the Jamrules file. Used by the SubDir rule.
+
+
+ SUFEXE
+
+
+ The suffix for executable files, if none provided.
+ Used by the Main rule.
+
+
+ SUFLIB
+
+
+ The suffix for libraries. Used by the Library and
+ related rules.
+
+
+ SUFOBJ
+
+
+ The suffix for object files. Used by the Objects
+ and related rules.
+
+
+ UNDEFFLAG
+
+
+ The flag prefixed to each symbol for the Undefines
+ rule (i.e., the compiler flag for undefined symbols).
+
+
+ WATCOM
+
+ Selects Watcom compile and link actions on OS2.
+
+
+ YACC
+
+
+ The yacc(1) command.
+
+
+ YACCFILES
+
+
+ The base filename generated by yacc(1).
+
+
+ YACCFLAGS
+
+
+ The yacc(1) command flags.
+
+
+
+
+Back to top.
+
+ Copyright 1997, 2000 Perforce Software, Inc.
+
+ Comments to info@perforce.com
+
+ Last updated: Dec 31, 2000
+
+ $Id$
+
+
diff --git a/jam_src/Jamfile b/jam_src/Jamfile
new file mode 100644
index 000000000..fc4d385a4
--- /dev/null
+++ b/jam_src/Jamfile
@@ -0,0 +1,227 @@
+#
+# Jamfile to build Jam (a make(1)-like program)
+#
+# There are no user-serviceable parts in this file.
+#
+# Put executables in platform-specific subdirectory.
+
+# compile without assertions by default
+CCFLAGS ?= -DNDEBUG ;
+
+if $(VMS) { LOCATE_TARGET ?= [.binvms] ; }
+else if $(MAC) { LOCATE_TARGET ?= :bin.mac ; }
+else { LOCATE_TARGET ?= bin.$(OSFULL[1]:L) ; }
+
+# Leave generated source in current directory; it would be nice to use
+# these lines below to build the source into the platform-specific
+# directory, but getting scan.c to include the right jambase.h is
+# hard: with ""'s, it always gets the bootstrap version; with <>'s,
+# it won't find the bootstrap version.
+
+# SEARCH_SOURCE ?= $(LOCATE_TARGET) $(DOT) ;
+# LOCATE_SOURCE ?= $(LOCATE_TARGET) ;
+
+#
+# We have some different files for UNIX, VMS, and NT.
+#
+
+if $(NT) {
+ code = execnt.c filent.c pathunix.c ;
+ if $(OSTYPE) = cygwin
+ {
+ YACC ?= bison -t -d -l -v --yacc ;
+ YACCFILES = y.tab ;
+ }
+}
+else if $(OS2)
+{
+ # special case for OS/2. When building Jam with GCC/EMX
+ # we need to use the "fileunix.c" file
+ #
+ # when we build it with other toolsets, we use "fileos2.c"
+ #
+ code = execunix.c pathunix.c ;
+ if $(TOOLSET) = EMX
+ {
+ CCFLAGS += -D__OS2__ ;
+ code += fileunix.c ;
+ }
+ else
+ {
+ code += fileos2.c ;
+ }
+}
+else if $(VMS) { code = execvms.c filevms.c pathvms.c ; }
+else if $(MAC) { code = execmac.c filemac.c pathmac.c ; }
+else { code = execunix.c fileunix.c pathunix.c ; }
+
+# We have to signal jam.h for these
+
+if $(OS) = NT
+{
+ if $(TOOLSET) = MINGW || $(TOOLSET) = LCC
+ {
+ CCFLAGS += -DNT ;
+ }
+ else
+ {
+ CCFLAGS += /DNT ;
+ }
+}
+
+# Do we know yacc?
+
+if $(YACC) { code += jamgram.y ; }
+else { code += jamgram.c ; }
+
+#
+# Build the jamgram.y from the jamgram.yy
+# yyacc is a slippery script that makes grammars a little
+# easier to read/maintain.
+#
+
+if ( $(UNIX) || $(NT) ) && $(YACC)
+{
+ local SUFEXE = ; # yyacc is a script with no suffix - this handles cygwin
+ GenFile jamgram.y jamgramtab.h : ./yyacc jamgram.yy ;
+}
+
+#
+# How to build the compiled in jambase.
+#
+
+Main mkjambase : mkjambase.c ;
+
+#
+# The guts of the Jamfile: how to build Jam
+#
+
+Main jam : jam.c jambase.c ;
+LinkLibraries jam : libjam.a ;
+GenFile jambase.c : mkjambase$(SUFEXE) Jambase ;
+
+Library libjam.a :
+ command.c compile.c $(code) expand.c glob.c
+ hash.c headers.c hdrmacro.c lists.c make.c make1.c newstr.c
+ option.c parse.c regexp.c rules.c scan.c search.c subst.c
+ timestamp.c variable.c modules.c strings.c filesys.c ;
+
+
+if $(BINDIR) { InstallBin $(BINDIR) : jam ; }
+
+#
+# Distribution making from here on out.
+#
+
+ALLSOURCE =
+ Build.com Build.mpw Jam.html Jambase Jambase.html Jamfile
+ Jamfile.html Makefile Porting README RELNOTES command.c command.h
+ compile.c compile.h execcmd.h execmac.c execunix.c execnt.c execvms.c
+ expand.c expand.h filemac.c filent.c fileos2.c filesys.h fileunix.c
+ filevms.c glob.c hash.c hash.h hdrmacro.c hdrmacro.h headers.c
+ headers.h jam.c jam.h jambase.c jambase.h jamgram.c jamgram.h
+ jamgram.y jamgram.yy jamgramtab.h lists.c lists.h make.c make.h
+ make1.c mkjambase.c modules.c newstr.c newstr.h option.c option.h parse.c
+ parse.h patchlevel.h pathmac.c pathunix.c pathvms.c regexp.c regexp.h
+ rules.c rules.h scan.c scan.h search.c search.h strings.c subst.c timestamp.c
+ timestamp.h variable.c variable.h filesys.c filesys.h yyacc
+ INSTALL
+ common.mk
+ builds/win32-visualc.mk
+ builds/win32-borlandc.mk
+ builds/win32-gcc.mk
+ ;
+
+
+rule Binary
+{
+ NotFile package ;
+ Depends package : $(<) ;
+
+ DEPENDS $(<) : $(>) ;
+
+ switch $(<)
+ {
+ case *-win32.zip : Zip-Exe $(<) : $(>) ;
+ case *-os2.zip : Zip-Exe $(<) : $(>) ;
+ case *-linux-libc6.tar : GZip-Exe $(<) : $(>) ;
+ }
+}
+
+
+rule Package
+{
+ NotFile package ;
+ Depends package : $(<) ;
+
+ DEPENDS $(<) : $(>) ;
+
+ switch $(<)
+ {
+ case *.tar : { Tar-Gz $(<) : $(>) ; Tar-Bz2 $(<) : $(>) ; }
+ case *.zip : Zip $(<) : $(>) ;
+ }
+}
+
+VERSION = ftjam-2.3.5 ;
+
+
+actions Tar-Gz
+{
+ ln -s . $(VERSION)
+ tar cvhf $(<) $(VERSION)/$(>)
+ rm $(VERSION)
+ gzip -9 $(<)
+}
+
+actions Tar-Bz2
+{
+ ln -s . $(VERSION)
+ tar cvhf $(<) $(VERSION)/$(>)
+ rm $(VERSION)
+ bzip2 -9 $(<)
+}
+
+
+actions Zip
+{
+ zip -9r $(<) $(>)
+}
+
+actions Zip-Exe
+{
+ zip -9j $(<) $(LOCATE_TARGET)\jam.exe
+}
+
+actions GZip-Exe
+{
+ ln -s $(LOCATE_TARGET)/jam jam
+ strip jam
+ tar chf $(<) jam
+ rm -f jam
+ gzip -9 $(<)
+}
+
+
+
+if $(NT)
+{
+ Binary $(VERSION)-win32.zip : $(ALLSOURCE) ;
+ Package $(VERSION).zip : $(ALLSOURCE) ;
+}
+else if $(OS2)
+{
+ Binary $(VERSION)-os2.zip : $(ALLSOURCE) ;
+ Package $(VERSION).zip : $(ALLSOURCE) ;
+}
+else if $(OS) = LINUX
+{
+ # how can we detect the C library version reliably ??
+ # for now, this should only be used for convenience
+ # purposes, until we add .rpm and .deb support in..
+
+ Binary $(VERSION)-linux-libc6.tar : jam ;
+
+ Package $(VERSION).tar : $(ALLSOURCE) ;
+ Package $(VERSION).zip : $(ALLSOURCE) ;
+}
diff --git a/jam_src/Jamfile.html b/jam_src/Jamfile.html
new file mode 100644
index 000000000..2f94ddf9d
--- /dev/null
+++ b/jam_src/Jamfile.html
@@ -0,0 +1,1450 @@
+
+
+Jamfiles and Jambase
+
+
+
+
+Jam/MR
+
+
+
+Using Jamfiles and Jambase
+
+
+
+
+This document describes how to write Jamfiles using the Jam/MR Jambase
+rules to build software products.
+Related documents of interest are:
+
+
+Jam/MR documentation and source are available from the
+Perforce Public Depot.
+
+
+
+Overview
+
+
+ jam, the Jam executable program,
+ recursively builds target files from source files
+ using dependency and build specifications defined
+ in Jam rules files.
+ jam parses the rules files to identify targets
+ and sources,
+ examines the filesystem to determine which
+ targets need updating, and issues OS commands to update
+ targets.
+
+ A base rules file called "Jambase" is provided with the
+ Jam distribution.
+ The Jambase file defines rules and variables which support
+ standard software build operations, like compiling, linking,
+ etc.
+
+ When the Jambase rules are used,
+ jam reads Jambase, then reads a file called
+ "Jamfile" in the current directory.
+ The Jamfile describes what to do with the source files in
+ its directory. It may also cause
+ Jamfiles in other directories to be read.
+
+ Under certain circumstances, the first Jamfile read
+ also causes a site-specific "Jamrules" file to be read.
+ The Jamrules file is an optional set of rule and variable
+ definitions used to define site-specific processing.
+
+
+The Basic Jamfile
+
+
+Jamfiles contain rule invocations, which usually look like:
+
+ RuleName targets : targets ;
+
+The target(s) to the left of the colon usually indicate
+what gets built, and the target(s) to the right of the
+colon usually indicate what it is built from.
+
+
+A Jamfile can be as simple as this:
+
+ Main myprog : main.c util.c ;
+
+This specifies that there is a main.c and util.c file in the same
+directory as the Jamfile, and that those source files should be
+compiled and linked into an executable called myprog.
+If you cd to the directory where this Jamfile lives,
+you can see the exactly how jam would
+build myprog with:
+
+ jam -n
+
+Or, you can actually build myprog with the command:
+
+ jam
+
+
+
+
+Whitespace
+
+Jamfile elements are delimited by whitespace (blanks, tabs, or
+newlines). Elements to be delimited include rule names, targets,
+colons, and semicolons. A common mistake users make is to forget the
+whitespace, e.g.,
+
+ Main myprog: main.c util.c ; #WRONG!
+
+Jam doesn't distinguish between a typo and a target called "myprog:",
+so if you get strange results, the first thing
+you should check for in your Jamfile is missing whitespace.
+
+
+Filenames, Target Identifiers, and Buildable Targets
+
+
+Consider this Jamfile:
+
+ Main myprog : main.c util.c ;
+ LinkLibraries myprog : libtree ;
+ Library libtree : treemake.c treetrav.c ;
+
+
+The Main rule specifies that an executable called myprog will be built.
+The compiled main.c and util.c objects will be linked to produce
+myprog.
+The LinkLibraries rule specifies that libtree will
+be linked into myprog as well.
+The Library rule specifies which source files will be compiled and
+archived into the libtree library.
+
+The Jamfile above refers to targets like "myprog" and "libtree".
+However, depending on the platform you're building on, the actual
+filenames of those targets could be "myprog.exe" and "libtree.lib".
+Most Jambase rules supply the actual filenames of targets,
+so that Jamfiles themselves need not make any
+platform-specific filename references.
+
+The jam program builds up a list of unique target identifiers.
+Unless you are using the SubDir rules (described later),
+the default identifier for a file target is its filename. In the above
+example, the target identifiers are the filenames: myprog.exe,
+libtree.lib, main.obj, etc.
+
+While all Jambase rules refer to "targets",
+not all targets are buildable.
+There are two kinds of buildable targets:
+file targets and pseudotargets.
+File targets are objects that can be found in the filesystem.
+Pseudotargets are symbolic, and represent other targets.
+
+You can use any buildable target on the jam command line to
+build a subset of defined targets. For example:
+
+ jam libtree.a
+
+on Unix builds the libtree library and all the compiled objects
+that go in it.
+
+
+Pseudotargets
+
+
+Most Jambase rules that define file targets also define pseudotargets
+which are dependent on types of file targets.
+For example, Jambase defines a pseudotarget called "lib", which
+is dependent on file targets created by the Library rule. So
+the command:
+
+ jam lib
+
+used with the above example would cause the libtree library to be built.
+Also, there is one pseudotarget built into jam itself, called
+"all". Jambase sets "all" dependent on (almost) all other targets.
+
+In the unfortunate case where you have a buildable target whose name
+is the same as one of the Jambase pseudotargets, you'll have problems
+with the conflicting target name.
+Your workaround choices are:
+
+
+- Change the name of your buildable file or directory that conflicts.
+
+
- Modify your Jambase and change the name of the conflicting pseudotarget.
+(Pseudotargets are defined in Jambase using the NOTFILE rule.)
+
+
- Use grist on the conflicting target name in your Jamfile. E.g., instead
+ of
+
+ File lib : libfoo.a ;
+
+ try
+
+ File <dir>lib : libfoo.a ;
+
+
+
+
+
+Dependencies
+
+
+Jambase rules set dependencies on targets, so that if you update a
+source file, all the file targets that depend on that source
+file, and only the ones that depend on that source file,
+will be updated (rebuilt) the next time you run jam.
+
+Here are some of the dependencies
+that get set when jam runs on NT using the example Jamfile above:
+
+
+| Target | | Depends on |
+
| myprog.exe | | main.obj, util.obj, libtree.lib
+ |
| libtree.lib | | treemake.obj, treetrav.obj
+ |
| treetrav.obj | | treetrav.c
+ |
+
+
+Furthermore, the Main and Library rules set up recursive
+header scanning on their source targets.
+So after jam has finished parsing the Jamfile and
+setting the rule-driven dependencies, it scans the source
+files for "#include" lines. All #include files found during
+this scan become dependencies of the compiled object.
+E.g., all header files used to compile treetrav.c would
+be made dependencies of treetrav.obj.
+
+As a result, when you run jam, it will rebuild targets
+if either the source files change or the
+header files change. You can't tell by looking at a Jamfile
+which header files are dependencies, but you can easily
+display those dependencies with:
+
+ jam -nd+3
+
+
+Rule Ordering
+
+
+Rules which specify dependencies, like the Main, Library, and
+LinkLibrary rules, can be invoked in any order. jam
+figures out the order in which targets are built from
+their dependencies.
+
+Some rules, however, set variables which are used by subsequent
+rule invocations, and their ordering is important.
+For example, the SubDir* rules (discussed
+later) must be invoked in a particular order.
+
+
+
+Detailed Jambase Specifications
+
+
+This document describes how to use various Jambase rules
+from a functional point of view.
+You can see the summary of available Jambase rules in the
+Jambase Reference.
+The detailed specifications for any Jambase rule
+can be found by reading the rule definition itself
+in the Jambase file.
+
+
+
+
+Handling Directory Trees
+
+ The SubDir* rules are used to
+ define source code directory hierarchies.
+ With SubDir and SubInclude, you can use jam
+ to build software from source files and Jamfiles spread
+ across many directories, as is typical for large projects.
+ The SubDir* rules unify an entire
+ source code tree so that jam can read in
+ all the Jamfiles in one pass and
+ compute dependencies across the entire project.
+
+ To use the SubDir* rules, you must:
+
+
+ - Preface the Jamfile in each directory with an invocation
+ of the SubDir rule.
+
+
- Place at the root of the tree a file named Jamrules.
+ This file could be empty, but in
+ practice it contains user-provided rules and variable
+ definitions that are shared throughout the
+ tree. Examples of such definitions are library
+ names, header directories, install directories,
+ compiler flags, etc. This file is good candidate
+ for automatic customizing with autoconf(GNU).
+
+
- Optionally, set an environment variable pointing
+ to the root directory of the srouce tree. The
+ variable's name is left up to you, but in these
+ examples, we use TOP.
+
+
+
+ SubDir Rule
+
+
+ The SubDir rule must be invoked before any rules that
+ refer to the contents of the directory - it is best to put
+ it at the top of each Jamfile. For example:
+
+ # Jamfile in $(TOP)/src/util directory.
+
+ SubDir TOP src util ;
+
+ Main myprog : main.c util.c ;
+ LinkLibraries myprog : libtree ;
+ Library libtree : treemake.c treetrav.c ;
+
+ This compiles four files in $(TOP)/src/util, archives
+ two of the objects into libtree, and links the whole
+ thing into myprog.
+ Outputs are placed in the $(TOP)/src/util
+ directory.
+
+ This doesn't appear to be any different from
+ the previous example that didn't have a SubDir rule,
+ but two things are happening behind the scenes:
+
+ - The SubDir rule causes jam to read
+ in the $(TOP)/Jamrules file.
+ (The Jamrules file can alternately be named by the
+ variable $(xxxRULES), where xxx is the name of the
+ root variable, e.g., $(TOPRULES)).
+
+ The Jamrules file can contain variable definitions
+ and rule definitions specific to your codeline.
+ It allows you to completely customize your build
+ environment without having to rewrite Jambase.
+ Jamrules is only read
+ in once, at the first SubDir invocation.
+
+
-
+ The SubDir rule initializes a set of variables
+ that are used by Main and other rules to
+ uniquely identify the source files in this
+ directory and assign locations to the targets
+ built from files in this directory.
+
+ When you have set a root variable, e.g., $(TOP),
+ SubDir constructs path names rooted with $(TOP),
+ e.g., $(TOP)/src/util.
+ Otherwise, SubDir constructs relative pathnames
+ to the root directory, computed from the number
+ of arguments to the first SubDir rule, e.g.,
+ ../../src/util. In either case, the SubDir
+ rule constructs the path names that locate source
+ files.
+ You'll see how this is useful later.
+
+
+
+
+ The SubDir rule takes as its first argument the root
+ variable's name and takes as subsequent arguments the
+ directory names leading from the root to the directory of
+ the current Jamfile. Note that the name of the subdirectory
+ is given as individual elements: the SubDir rule
+ does not use system-specific directory name syntax.
+
+
+
+ SubInclude Rule
+
+ The SubInclude rule is used in a Jamfile to cause another
+ Jamfile to be read in.
+ Its arguments are in the same format as
+ SubDir's.
+
+ The recommended practice is only to include one level of
+ subdirectories at a time, and let the Jamfile in each subdirectory
+ include its own subdirectories. This allows a
+ user to sit in any arbitrary directory of the source tree
+ and build that subtree. For example:
+
+ # This is $(TOP)/Jamfile, top level Jamfile for mondo project.
+
+ SubInclude TOP src ;
+ SubInclude TOP man ;
+ SubInclude TOP misc ;
+ SubInclude TOP util ;
+
+ If a directory has both subdirectories of its own as well
+ as files that need building, the SubIncludes should be
+ either before the SubDir rule or be at the end of the Jamfile
+ - not between the SubDir and other rule invocations.
+ For example:
+
+ # This is $(TOP)/src/Jamfile:
+
+ SubDir TOP src ;
+
+ Main mondo : mondo.c ;
+ LinkLibraries mondo : libmisc libutil ;
+
+ SubInclude TOP src misc ;
+ SubInclude TOP src util ;
+
+
+ (jam processes all the Jamfiles it reads as if
+ it were reading one single, large Jamfile.
+ Build rules like Main and LinkLibraries rely on the
+ preceding SubDir rule to set up source file and
+ output file locations, and SubIncludes rules read in
+ Jamfiles that contain SubDir rules. So if you put
+ a SubIncludes rule between a SubDir and a Main
+ rule, jam will try to find the source files
+ for the Main rule in the wrong directory.)
+
+
+ Variables Used to Handle Directory Trees
+
+ The following variables are set by the SubDir rule
+ and used by the Jambase rules that define file targets:
+
+
+
+|
+ SEARCH_SOURCE
+ | | The SubDir targets (e.g., "TOP src util")
+ are used to construct a pathname (e.g., $(TOP)/src/util),
+ and that pathname is assigned to $(SEARCH_SOURCE).
+ Rules like Main and Library use $(SEARCH_SOURCE)
+ to set search paths on source files.
+ |
|
+ LOCATE_SOURCE
+ | | Initialized by the SubDir rule to the same
+ value as $(SEARCH_SOURCE), unless ALL_LOCATE_TARGET
+ is set.
+ $(LOCATE_SOURCE) is used by rules that build
+ generated source files (e.g., Yacc and Lex) to
+ set location of output files.
+ Thus the default location of built source files
+ is the directory of the Jamfile that defines them.
+ |
|
+ LOCATE_TARGET
+ | | Initalized by the SubDir rule to the same
+ value as $(SEARCH_SOURCE), unless ALL_LOCATE_TARGET
+ is set.
+ $(LOCATE_TARGET) is used by rules that build
+ binary objects (e.g., Main and Library) to
+ set location of output files.
+ Thus the default location of built binaray files
+ is the directory of the Jamfile that defines them.
+ |
|
+ ALL_LOCATE_TARGET
+ | |
+ If $(ALL_LOCATE_TARGET) is set, LOCATE_SOURCE
+ and and LOCATE_TARGET are set to $(ALL_LOCATE_TARGET)
+ instead of to $(SEARCH_SOURCE). This can be used to
+ direct built files to be written to a location outside
+ of the source tree, and enables building from read-only
+ source trees.
+ |
|
+ SOURCE_GRIST
+ | | The SubDir targets are formed into a string
+ like "src!util" and that string is assigned to
+ SOURCE_GRIST. Rules that define file targets
+ use $(SOURCE_GRIST) to set the "grist" attribute
+ on targets. This is used to assure uniqueness
+ of target identifiers where filenames themselves
+ are not unique.
+ For example, the target identifiers of
+ $(TOP)/src/client/main.c and $(TOP)/src/server/main.c
+ would be <src!client>main.c and <src!server>main.c.
+ |
+
+
+ The $(LOCATE_TARGET) and $(SEARCH_SOURCE) variables are used
+ extensively by rules in Jambase: most rules that generate
+ targets (like Main, Object, etc.) set $(LOCATE) to
+ $(LOCATE_TARGET) for the targets they generate, and rules
+ that use sources (most all of them) set $(SEARCH) to be
+ $(SEARCH_SOURCE) for the sources they use.
+
+ $(LOCATE) and $(SEARCH) are better explained in
+ The Jam Executable Program
+ but in brief they tell jam where to create new targets and
+ where to find existing ones, respectively.
+
+ Note that you can reset these variables
+ after SubDir sets them. For example, this Jamfile builds
+ a program called gensrc, then runs it to create a source file
+ called new.c:
+
+ SubDir TOP src util ;
+ Main gensrc : gensrc.c ;
+ LOCATE_SOURCE = $(NEWSRC) ;
+ GenFile new.c : gensrc ;
+
+ By default, new.c would be written into the
+ $(TOP)/src/util directory, but resetting LOCATE_SOURCE causes
+ it to be written to the $(NEWSRC) directory. ($(NEWSRC) is assumed
+ to have been set elsewhere, e.g., in Jamrules.)
+
+
+ VMS Notes
+
+ On VMS, the logical name table is not imported as is the
+ environment on UNIX. To use the SubDir and related rules,
+ you must set the value of the variable that names the root
+ directory. For example:
+
+ TOP = USR_DISK:[JONES.SRC] ;
+
+ SubInclude TOP util ;
+
+ The variable must have a value that looks like a directory
+ or device. If you choose, you can use a concealed logical.
+ For example:
+
+ TOP = TOP: ;
+
+ SubInclude TOP util ;
+
+ The : at the end of TOP makes the value of $(TOP) look
+ like a device name, which jam respects as a directory name
+ and will use when trying to access files. TOP must then
+ be defined from DCL:
+
+ $ define/job/translation=concealed TOP DK100:[USERS.JONES.SRC.]
+
+ Note three things: the concealed translation allows the
+ logical to be used as a device name; the device name in
+ the logical (here DK100) cannot itself be concealed logical
+ (VMS rules, man); and the directory component of the
+ definition must end in a period (more VMS rules).
+
+
+Building Executables and Libraries
+
+
+The rules that build executables and libraries are: Main, Library,
+and LinkLibraries.
+
+ Main Rule
+
+ The Main rule compiles source files and links the resulting
+ objects into an executable. For example:
+
+ Main myprog : main.c util.c ;
+
+ This compiles main.c and util.c and links main.o and
+ util.o into myprog. The object files and resulting
+ executable are named appropriately for the platform.
+
+ Main can also be used to build shared libraries and/or
+ dynamic link libraries, since those are also linked
+ objects. E.g.:
+
+ Main driver$(SUFSHR) : driver.c ;
+
+ Normally, Main uses $(SUFEXE) to determine the suffix on
+ the filename of the built target. To override it,
+ you can supply a suffix explicity.
+ In this case,
+ $(SUFSHR) is assumed to be the OS-specific shared library
+ suffix, defined in Jamrules with something
+ like:
+
+ if $(UNIX) { SUFSHR = .so ; }
+ else if $(NT) { SUFSHR = .dll ; }
+
+
+ Main uses the Objects rule to compile source targets.
+
+
+ Library Rule
+
+ The Library rule compiles source files, archives the
+ resulting object files into a library, and then deletes
+ the object files. For example:
+
+ Library libstring : strcmp.c strcpy.c strlen.c ;
+ Library libtree : treemake.c treetrav.c ;
+
+ This compiles five source files, archives three of the
+ object files into libstring and the other two into libtree.
+ Actual library filenames are formed with the $(SUFLIB) suffix.
+ Once the objects are safely in the libraries, the
+ objects are deleted.
+
+ Library uses the Objects rule to compile source files.
+
+
+ LinkLibraries Rule
+
+ To link executables with built libraries, use
+ the LinkLibraries rule. For example:
+
+ Main myprog : main.c util.c ;
+ LinkLibraries myprog : libstring libtree ;
+
+ The LinkLibraries rule does two things: it makes the
+ libraries dependencies of the executable, so that they get
+ built first; and it makes the libraries show up on the
+ command line that links the executable. The ordering of
+ the lines above is not important, because jam builds targets
+ in the order that they are needed.
+
+ You can put multiple libraries on a single invocation of
+ the LinkLibraries rule, or you can provide them in multiple
+ invocations. In both cases, the libraries appear on
+ the link command line in the order in which they were
+ encountered. You can also provide multiple executables to
+ the LinkLibraries rule, if they need the same libraries,
+ e.g.:
+
+ LinkLibraries prog1 prog2 prog3 : libstring libtree ;
+
+
+
+ Variables Used in Building Executables and Libraries
+
+
+
+|
+ AR
+ | | Archive command, used for Library targets.
+ |
|
+ SUFEXE
+ | * | Suffix on filenames of executables referenced
+ by Main and LinkLibraries.
+ |
|
+ LINK
+ | | Link command, used for Main targets.
+ |
|
+ LINKFLAGS
+ | | Linker flags.
+ |
|
+ LINKLIBS
+ | | Link libraries that aren't dependencies. (See note
+ below.)
+ |
|
+ EXEMODE
+ | * | File permissions on Main targets.
+ |
|
+ MODE
+ | | Target-specific file permissions on Main targets
+ (set from $(EXEMODE))
+ |
|
+ RANLIB
+ | | Name of ranlib program, if any.
+ |
+
+
+
+ Variables above marked with "*" are used by the Main,
+ Library, and LinkLibraries rules. Their values at the
+ time the rules are invoked are used to set target-specific
+ variables.
+
+ All other variables listed above are globally defined,
+ and are used in actions that update Main and Library
+ targets. This means that the global values of those
+ variables are used, uness target-specific values have
+ been set.
+ (For instance, a target-specific MODE value is set by
+ the Main rule.)
+ The target-specific values always override
+ global values.
+
+ Note that there are two ways to specify link libraries for
+ executables:
+
+ - Use the LinkLibraries rule
+ to specify built libraries; i.e., libraries
+ that are built by Library rules. This assures that
+ these libraries are built first, and that Main targets are
+ rebuilt when the libraries are updated.
+
+
- Use the LINKLIBS variable to specify external
+ libraries; e.g., system libraries or third-party libraries.
+ The LINKLIBS variable must be set to the the actual
+ link command flag that specifies the libraries.
+
+
+
+ For example:
+
+ #In Jamrules:
+ if $(UNIX) { X11LINKLIBS = -lXext -lX11 ; }
+ if $(NT) { X11LINKLIBS = libext.lib libX11.lib ; }
+
+ #In Jamfile:
+ Main xprog : xprog.c ;
+ LINKLIBS on xprog$(SUFEXE) = $(X11LINKLIBS) ;
+ LinkLibraries xprog : libxutil ;
+ Library libxutil : xtop.c xbottom.c xutil.c ;
+
+ This example uses the Jam syntax "variable on target" to
+ set a target-specific variable. In this way, only xprog
+ will be linked with this special $(X11LINKLIBS),
+ even if other executables were going to be built
+ by the same Jamfile. Note that when you set a variable
+ on a target, you have to specify the target identifer
+ exactly, which in this case is the suffixed filename of
+ the executable.
+ The actual link command line on Unix, for example, would
+ look something like this:
+
+ cc -o xprog xprog.o libxutil.a -lXext -lX11
+
+
+Compiling
+
+ Compiling of source files occurs normally as a byproduct
+ of the Main or Library rules, which call the rules
+ described here. These rules may also be called explicitly
+ if the Main and Library behavior doesn't satisfy your
+ requirements.
+
+
+ Objects Rule
+
+ The Main and Library rules call the Objects rule on source files.
+ Compiled object files built by
+ the Objects rule are a dependency of the obj
+ pseudotarget, so "jam obj" will build object files used in
+ Main and Library rules.
+
+ Target identifiers created by the Objects rule have grist
+ set to $(SOURCE_GRIST). So given this Jamfile:
+
+ SubDir TOP src lock ;
+ Main locker : lock.c ;
+
+ the object file created is lock.o (or lock.obj) and
+ its target identifier is <src!lock>lock.o
+ (or <src!lock>lock.obj).
+
+
+ You can also call Objects directly. For example:
+
+ Objects a.c b.c c.c ;
+
+ This compiles a.c into a.o, b.c into b.o, etc. The object
+ file suffix is supplied by the Objects rule.
+
+
+ Object Rule
+
+ Objects gets its work done by calling the Object rule on
+ each of the source files.
+ You could use the Object rule directly.
+ For example, on Unix, you could use:
+
+ Object foo.o : foo.c ;
+
+ However, the Object rule does not provide suffixes, and
+ it does not provide the grist needed to construct target
+ identifiers if you are using the SubDir* rules.
+ A portable and robust Jamfile would need to invoke Object thus:
+
+ Object <src!util>foo$(SUFOBJ) : <src!util>foo.c ;
+
+ which is inelegant and clearly shows why using Objects
+ is better than using Object.
+
+ If there's any advantage to the Object rule, it's
+ that it doesn't require that the object name bear
+ any relationship to the source. It is thus possible to
+ compile the same file into different objects. For example:
+
+
+ Object a.o : foo.c ;
+ Object b.o : foo.c ;
+ Object c.o : foo.c ;
+
+ This compiles foo.c (three times) into a.o, b.o, and c.o.
+ Later examples show how this is useful.
+
+ The Object rule looks at the suffix of the source file and
+ calls the appropriate rules to do the actual preprocessing
+ (if any) and compiling needed to produce the output object file.
+ The Object rule is
+ capable of the generating of an object file from any
+ type of source. For example:
+
+ Object grammar$(SUFOBJ) : grammar.y ;
+ Object scanner$(SUFOBJ) : scanner.l ;
+ Object fastf$(SUFOBJ) : fastf.f ;
+ Object util$(SUFOBJ) : util.c ;
+
+ An even more elegant way to get the same result is to let the
+ Objects rule call Object:
+
+ Objects grammar.y scanner.l fastf.f util.c ;
+
+
+ In addition to calling the compile rules, Object sets up
+ a bunch of variables specific to the source and target
+ files. (See Variables Used in Compiling, below.)
+
+
+ Cc, C++, Yacc, Lex, Fortran, As, etc. Rules
+
+
+ The Object rule calls compile rules specific to the suffix of
+ the source file. (You can see which suffixes are supported
+ by looking at the Object rule definition in Jambase.)
+ Because the extra work done by the
+ Object rule, it is not always useful to call the compile
+ rules directly. But the adventurous user might attempt
+ it. For example:
+
+ Yacc grammar.c : grammar.y ;
+ Lex scan.c : scan.l ;
+ Cc prog.o : prog.c ;
+
+ These examples individually run yacc(1), lex(1), and the C
+ compiler on their sources.
+
+
+ UserObject Rule
+
+ Any files with suffixes not understood by the Object rule
+ are passed to the UserObject rule. The default definition
+ of UserObject simply emits a warning that the suffix is
+ not understood. This Jambase rule definition is intended to be
+ overridden in Jamrules with one that recognizes the project-specific
+ source file suffixes. For example:
+
+
+ #In Jamrules:
+
+ rule UserObject
+ {
+ switch $(>)
+ {
+ case *.rc : ResourceCompiler $(<) : $(>) ;
+ case * : ECHO "unknown suffix on" $(>) ;
+ }
+ }
+
+ rule ResourceCompiler
+ {
+ DEPENDS $(<) : $(>) ;
+ Clean clean : $(<) ;
+ }
+
+ actions ResourceCompiler
+ {
+ rc /fo $(<) $(RCFLAGS) $(>)
+ }
+
+
+ #In Jamfile:
+
+ Library liblock : lockmgr.c ;
+ if $(NT) { Library liblock : lock.rc ; }
+
+
+ In this example, the UserObject definition in Jamrules
+ allows *.rc files to be handle as regular Main and Library
+ sources. The lock.rc file is compiled into lock.obj
+ by the "rc" command, and lock.obj is archived into a library
+ with other compiled objects.
+
+ LibraryFromObjects Rule
+
+ Sometimes the Library rule's straightforward compiling of
+ source into object modules to be archived isn't flexible
+ enough. The LibraryFromObjects rule does the archiving
+ (and deleting) job of the Library rule, but not the compiling.
+ The user can make use of the Objects or Object
+ rule for that. For example:
+
+ LibraryFromObjects libfoo.a : max.o min.o ;
+ Object max.o : maxmin.c ;
+ Object min.o : maxmin.c ;
+ ObjectCcFlags max.o : -DUSEMAX ;
+ ObjectCcFlags min.o : -DUSEMIN ;
+
+ This Unix-specific example compiles the same source file into
+ two different
+ objects, with different compile flags, and archives them.
+ (The ObjectCcFlags rule is described shortly.)
+ Unfortunately, the portable and robust implementation of the
+ above example is not as pleasant to read:
+
+ SubDir TOP foo bar ;
+ LibraryFromObjects libfoo$(SUFLIB) : <foo!bar>max$(SUFOBJ)
+ <foo!bar>min$(SUFOBJ) ;
+ Object <foo!bar>min$(SUFOBJ) : <foo!bar>maxmin.c ;
+ Object <foo!bar>max$(SUFOBJ) : <foo!bar>maxmin.c ;
+ ObjectCcFlags <foo!bar>min$(SUFOBJ) : -DUSEMIN ;
+ ObjectCcFlags <foo!bar>max$(SUFOBJ) : -DUSEMAX ;
+
+ Note that, among other things, you must supply the library
+ file suffix when using the LibraryFromObjects rule.
+
+
+ MainFromObjects Rule
+
+ Similar to LibraryFromObjects, MainFromObjects does the
+ linking part of the Main rule, but not the compiling.
+ MainFromObjects can be used when there are no
+ objects at all, and everything is to be loaded from
+ libraries. For example:
+
+ MainFromObjects testprog ;
+ LinkLibraries testprog : libprog ;
+ Library libprog : main.c util.c ;
+
+ On Unix, say, this generates a link command that looks like:
+
+ cc -o testprog libprog.a
+
+ Linking purely from libraries is something that doesn't
+ work everywhere: it depends on the symbol "main" being
+ undefined when the linker encounters the library that contains
+ the definition of "main".
+
+
+ Variables Used in Compiling
+
+ The following variables control the compiling of source
+ files:
+
+
+
+|
+ C++
+ | | The C++ compiler command
+ |
|
+ CC
+ | | The C compiler command
+ |
+ C++FLAGS
+
+ CCFLAGS
+ | | Compile flags, used to
+ create or update compiled objects
+ |
+ SUBDIRC++FLAGS
+
+ SUBDIRCCFLAGS
+ | | Additonal compile flags
+ for source files in this directory.
+ |
|
+ OPTIM
+ | | Compiler optimization flag. The Cc and C++
+ actions use this as well as C++FLAGS or CCFLAGS.
+ |
|
+ HDRS
+ | | Non-standard header directories; i.e.,
+ the directories the compiler will not look in
+ by default and which therefore must be supplied
+ to the compile command. These directories are
+ also used by jam to scan for include files.
+ |
|
+ STDHDRS
+ | | Standard header directories, i.e., the
+ directories the compiler searches automatically.
+ These are not passed to the compiler, but they
+ are used by jam to scan for include files.
+ |
|
+ SUBDIRHDRS
+ | | Additional paths to add to HDRS for source files
+ in this directory.
+ |
|
+ LEX
+ | | The lex(1) command
+ |
|
+ YACC
+ | | The yacc(1) command
+ |
+
+
+ The Cc rule sets a target-specific $(CCFLAGS) to the current
+ value of $(CCFLAGS) and $(SUBDIRCCFLAGS). Similarly
+ for the C++ rule. The Object rule sets a target-specific
+ $(HDRS) to the current value of $(HDRS) and $(SUBDDIRHDRS).
+
+
+ $(CC), $(C++), $(CCFLAGS), $(C++FLAGS), $(OPTIM), and
+ $(HDRS) all affect the compiling of C and C++ files.
+ $(OPTIM) is separate from $(CCFLAGS) and $(C++FLAGS) so
+ they can be set independently.
+
+ $(HDRS) lists the directories to search for header files,
+ and it is used in two ways: first, it is passed to the C
+ compiler (with the flag -I prepended); second, it is used
+ by HdrRule to locate the header files whose names were
+ found when scanning source files. $(STDHDRS) lists the
+ header directories that the C compiler already knows
+ about. It does not need passing to the C compiler, but is
+ used by HdrRule.
+
+ Note that these variables, if set as target-specific variables,
+ must be set on the target, not the source file.
+ The target file in this case is the object file to be generated.
+ For example:
+
+ Library libximage : xtiff.c xjpeg.c xgif.c ;
+
+ HDRS on xjpeg$(SUFOBJ) = /usr/local/src/jpeg ;
+ CCFLAGS on xtiff$(SUFOBJ) = -DHAVE_TIFF ;
+
+ This can be done more easily with the rules that follow.
+
+
+ ObjectCcFlags, ObjectC++Flags, ObjectHdrs Rules
+
+ $(CCFLAGS), $(C++FLAGS) and $(HDRS) can be set on object file
+ targets
+ directly, but there are rules that allow these variables
+ to be set by referring to the original source file name,
+ rather than to the derived object file name. ObjectCcFlags
+ adds object-specific flags to the $(CCFLAGS) variable,
+ ObjectC++Flags adds object-specific flags to the
+ $(C++FLAGS) variable, and ObjectHdrs add object-specific
+ directories to the $(HDRS) variable. For example:
+
+ #In Jamrules:
+ if $(NT) { CCFLAGS_X = /DXVERSION ;
+ HDRS_X = \\\\SPARKY\\X11\\INCLUDE\\X11 ;
+ }
+
+ #In Jamfile:
+ Main xviewer : viewer.c ;
+ ObjectCcFlags viewer.c : $(CCFLAGS_X) ;
+ ObjectHdrs viewer.c : $(HDRS_X) ;
+
+ The ObjectCcFlags and ObjectHdrs rules take .c files
+ as targets, but actually set $(CCFLAGS) and $(HDRS) values
+ on the .obj (or .o) files. As a result, the action
+ that updates the target .obj file uses the target-specific
+ values of $(CCFLAGS) and $(HDRS).
+
+
+ SubDirCcFlags, SubDirC++Flags, SubDirHdrs Rules
+
+ These rules set the values of $(SUBDIRCCFLAGS), $(SUBDIRC++FLAGS)
+ and $(SUBDIRHDRS), which are used by the Cc,
+ C++, and Object rules when setting the target-specific
+ values for $(CCFLAGS), $(C++FLAGS) and $(HDRS). The SubDir
+ rule clears these variables out, and thus they provide
+ directory-specific values of $(CCFLAGS), $(C++FLAGS) and
+ $(HDRS). For example:
+
+ #In Jamrules:
+ GZHDRS = $(TOP)/src/gz/include ;
+ GZFLAG = -DGZ ;
+
+ #In Jamfile:
+ SubDir TOP src gz utils ;
+
+ SubDirHdrs $(GZHDRS) ;
+ SubDirCcFlags $(GZFLAG) ;
+
+ Library libgz : gizmo.c ;
+ Main gizmo : main.c ;
+ LinkLibraries gizmo : libgz ;
+
+ All .c files in this directory files will be compiled with
+ $(GZFLAG) as well as the default $(CCFLAG), and the include
+ paths used on the compile command will be $(GZHDRS) as well
+ as the default $(HDRS).
+
+Header File Processing
+
+ One of the functions of the Object rule is set up
+ scanning of source
+ files for (C style) header file inclusions. To do so, it
+ sets the special variables $(HDRSCAN) and $(HDRRULE)
+ as target-specific variables on the source file. The
+ presence of these variables triggers a special mechanism
+ in jam for scanning a file for header file inclusions and
+ invoking a rule with the results of the scan. The
+ $(HDRSCAN) variable is set to an egrep(1) pattern that
+ matches "#include" statements in C source files, and the
+ $(HDRRULE) variable is set to the name of the rule that
+ gets invoked as such:
+
+ $(HDRRULE) source-file : included-files ;
+
+ This rule is supposed to set up the dependencies between
+ the source file and the included files. The Object rule
+ uses HdrRule to do the job. HdrRule itself expects
+ another variable, $(HDRSEARCH), to be set to the list of
+ directories where the included files can be found. Object
+ does this as well, setting $(HDRSEARCH) to $(HDRS) and
+ $(STDHDRS).
+
+ The header file scanning occurs during the "file binding"
+ phase of jam, which means that the target-specific
+ variables (for the source file) are in effect. To accomodate
+ nested includes, one of the HdrRule's jobs is to pass
+ the target-specific values of $(HDRRULE), $(HDRSCAN), and
+ $(HDRSEARCH) onto the included files, so that they will be
+ scanned as well.
+
+
+ HdrRule Rule
+
+ Normally, HdrRule is not invoked directly; the Object rule
+ (called by Main and Library) invokes it.
+
+ If there are special dependencies that need to be set,
+ and which are not set by HdrRule itself, you can define
+ another rule and let it invoke HdrRule. For example:
+
+
+ #In Jamrules:
+ rule BuiltHeaders
+ {
+ DEPENDS $(>) : mkhdr$(SUFEXE) ;
+ HdrRule $(<) : $(>) ;
+ }
+
+ #In Jamfile:
+ Main mkhdr : mkhdr.c ;
+ Main ugly : ugly.c ;
+
+ HDRRULE on ugly.c = BuiltHeaders ;
+
+
+ This example just says that the files included by "ugly.c"
+ are generated by the program "mkhdr", which can be built
+ from "mkhdr.c". During the binding phase, jam will
+ scan ugly.c, and if it finds an include file, ughdr.h,
+ for example, it will automatically invoke the rule:
+
+ BuiltHeaders ugly.c : ughdr.h ;
+
+ By calling HdrRule at the end of BuiltHeaders,
+ all the gadgetry of HdrRule takes effect and it
+ doesn't need to be duplicated.
+
+
+ Variables Used for Header Scanning
+
+
+
+|
+ HDRPATTERN
+ | | Default scan pattern for "include" lines.
+ |
|
+ HDRSCAN
+ | | Scan pattern to use.
+ This is a special variable: during binding, if
+ both HDRSCAN and HDRRULE are set, scanning is activated
+ on the target being bound.
+ The HdrRule and Object rules sets this
+ to $(HDRPATTERN) on their source targets.
+ |
|
+ HDRRULE
+ | | Name of rule to invoked on files found in header
+ scan. The HdrRule and Object rules set this to "HdrRule"
+ on their source targets. This is also a special variable;
+ it's the only jam variable that can hold the
+ name of a rule to be invoked.
+ |
|
+ HDRSEARCH
+ | | Search paths for files found during header scanning.
+ This is set from $(HDRS) and $(STDHDRS), which are
+ described in the Compiling section.
+ jam will search $(HDRSEARCH) directories for
+ the files found by header scans.
+ |
+
+
+ The Object rule sets HDRRULE and HDRSCAN specifically for
+ the source files to be scanned, rather than globally. If
+ they were set globally, jam would attempt to scan all
+ files, even library archives and executables, for header
+ file inclusions. That would be slow and probably not
+ yield desirable results.
+
+
+Copying Files
+
+
+ File Rule
+
+ The File rule copies one file to another. The target name
+ needn't be the same as the source name. For
+ example:
+
+ switch $(OS)
+ {
+ case NT* : File config.h : confignt.h ;
+ case * : File config.h : configunix.h ;
+ }
+ LOCATE on config.h = $(LOCATE_SOURCE) ;
+
+ This creates a config.h file from either confignt.h or
+ configunix.h, depending on the current build platform.
+
+ The File rule does not
+ use the LOCATE_SOURCE variable set by the
+ SubDir rule (although it does use SEARCH_SOURCE), which
+ means you have to set the copied file's output directory
+ yourself. That's done by setting the special
+ LOCATE variable on the target, as shown above,
+ or with the MakeLocate rule described below.
+
+ Bulk Rule
+
+ The Bulk rule is a shorthand for many invocations of the
+ File rule when all files are going to the same directory.
+ For example:
+
+ #In Jamrules:
+ DISTRIB_GROB = d:\\distrib\\grob ;
+
+ #In Jamfile:
+ Bulk $(DISTRIB_GROB) : grobvals.txt grobvars.txt ;
+
+ This causes gobvals.txt and grobvars.txt to be copied
+ into the $(DISTRIB_GROB) directory.
+
+ HardLink Rule
+
+ The Unix-only HardLink rule makes a hard link (using ln(1)) from the
+ source to the target, if there isn't one already. For
+ example:
+
+ HardLink config.h : configunix.h ;
+
+
+ Shell Rule
+
+ The Shell rule is like the File rule, except that on Unix it makes
+ sure the first line of the target is "#!/bin/sh" and sets
+ the permission to make the file executable. For example:
+
+ Shell /usr/local/bin/add : add.sh ;
+
+
+ You can also use $(SHELLHEADER) to dictate
+ what the first line of the copied file will be.
+ For
+ example:
+
+ Shell /usr/local/bin/add : add.awk ;
+ SHELLHEADER on /usr/local/bin/add = "#!/bin/awk -f" ;
+
+ This installs an awk(1) script.
+
+
+ Variables Used When Copying Files
+
+
+
+|
+ FILEMODE
+ | | Default file permissions for copied files
+ |
|
+ SHELLMODE
+ | | Default file permissions for Shell rule targets
+ |
|
+ MODE
+ | | File permissions set on files copied by
+ File, Bulk, and Shell rules.
+ File and Shell sets a target-specific MODE to the current
+ value of $(FILEMODE) or $(SHELLMODE), respectively.
+ |
|
+ SHELLHEADER
+ | | String to write in first line of Shell targets
+ (default is #!/bin/sh).
+
+ |
+
+
+
+
+Installing Files
+
+Jambase provides a set of Install* rules to copy files
+into an destination directory and set permissions on them.
+On Unix, the install(1) program is used.
+If the destination directory does not exist, jam
+creates it first.
+
+All files copied with the Install* rules are dependencies
+of the install pseudotarget, which means that the
+command "jam install" will cause the installed copies to
+be updated. Also, "jam uninstall" will cause the installed
+copies to be removed.
+
+The Install* rules are:
+
+
+| InstallBin
+ | Copies file and sets its permission to $(EXEMODE).
+ You must specify the suffixed executable name. E.g.:
+ InstallBin $(BINDIR) : thing$(SUFEXE) ;
+
+
+ |
| InstallFile
+ | Copies file and sets its permission to $(FILEMODE). E.g.:
+ InstallFile $(DESTDIR) : readme.txt ;
+
+
+ |
| InstallLib
+ | Copies file and sets its permission to $(FILEMODE).
+ You must specify the suffixed library name. E.g.:
+ InstallLib $(LIBDIR) : libzoo$(SUFLIB) ;
+
+
+ |
| InstallMan
+ | Copies file into the mann
+ subdirectory of the target directory
+ and sets its permission to $(FILEMODE). E.g.,
+ this copies foo.5 into the $(DESTDIR)/man5 directory:
+ InstallMan $(DESTDIR) : foo.5 ;
+
+
+ |
| InstallShell
+ | Copies file and sets its permission to $(SHELLMODE). E.g.:
+ InstallShell $(DESTDIR) : startup ;
+
+
+ |
+
+
+
+
+ Variables
+
+ The following variables control the installation rules:
+
+
+
+|
+ INSTALL
+ | | The install program (Unix only)
+ |
|
+ FILEMODE
+ | | Default file permissions on readable files.
+ |
|
+ EXEMODE
+ | | Default file permission executable files.
+ |
|
+ SHELLMODE
+ | | Default file permission on shell script files.
+ |
|
+ MODE
+ | | Target-specific file permissions
+ |
+
+
+
+ The Install rules set a target-specific MODE to the current
+ value of $(FILEMODE), $(EXEMODE), or $(SHELLMODE),
+ depending on which Install rule was invoked.
+
+ The directory variables are just defined for convenience:
+ they must be passed as the target to the appropriate
+ Install rule. The $(INSTALL) and mode variables must be
+ set (globally) before calling the Install rules in order
+ to take effect.
+
+
+Miscellaneous Rules
+
+
+Clean Rule
+
+
+The Clean rule defines files to be removed when you run "jam clean".
+Any site-specific build rules defined in your Jamrules should invoke
+Clean so that outputs can be removed. E.g.,
+
+ rule ResourceCompiler
+ {
+ DEPENDS $(<) : $(>) ;
+ Clean clean : $(<) ;
+ }
+
+
+
+Most Jambase rules invoke the Clean rule on their built targets,
+so "jam clean" will remove all compiled objects, libraries,
+executables, etc.
+
+
+MakeLocate Rule
+
+ MakeLocate is a single convenient rule that creates a directory,
+ sets LOCATE on a target to that directory, and makes the directory
+ a dependency of the target. It is used by many Jambase rules,
+ and can be invoked directly, e.g.:
+
+ GenFile data.tbl : hxtract data.h ;
+ MakeLocate data.tbl : $(TABLEDIR) ;
+
+ In this example, the File rule creates data.tbl from data.h.
+ The MakeLocate causes data.tbl to be written into the $(TABLEDIR)
+ directory; and if the directory doesn't exist, it is created first.
+
+ The MakeLocate rule invokes another Jambase rule, MkDir,
+ to (recursively) create
+ directories. MkDir uses the $(MKDIR) variable to determine the
+ platform-specific command that creates directories.
+
+
+RmTemps Rule
+
+ Some intermediate files are meant to be temporary.
+ The RmTemps rule can be used to cause
+ jam to delete them after they are used.
+
+ RmTemps must be:
+
+ -
+ the last rule
+ invoked on the permanent file that uses
+ the temporary file(s)
+
-
+ invoked with the permanent file as the output
+ target and the temporary file(s) as the input target
+
-
+ invoked with the exact target identifiers of
+ the permanent file and the temporary file(s)
+
+ For
+ example:
+
+ SubDir TOP src big ;
+ GenFile big.y : joinfiles part1.y part2.y part3.y ;
+ Main bigworld : main.c big.y ;
+ RmTemps bigworld$(SUFEXE) : <src!big>big.y ;
+
+ This causes big.y to be deleted after it has been used to create
+ the bigworld executable.
+ The exact target identifier of big.y is <src!big>big.y
+ (the GenFile and Main rules tack on the grist automatically);
+ the exact target identifier of the bigworld executable
+ is bigworld$(SUFEXE).
+
+
+Back to top.
+
+ Copyright 1997, 2000 Perforce Software, Inc.
+
+ Comments to info@perforce.com
+
+ Last updated: Dec 31, 2000
+
+ $Id$
+
+
diff --git a/jam_src/Makefile b/jam_src/Makefile
new file mode 100644
index 000000000..90e890983
--- /dev/null
+++ b/jam_src/Makefile
@@ -0,0 +1,88 @@
+# The following Makefile will build Jam on Unix systems
+# You can also modify it to compile the program on other
+# systems, or also use one of the specific Makefiles
+# located in the "builds" directory
+#
+
+CC = cc
+TARGET = -o jam0
+CFLAGS =
+
+# Borland C++ on Windows
+#CC = bcc32
+#TARGET = -ejam0
+#CFLAGS = /DNT -w- -q
+
+# Special flavors - uncomment appropriate lines
+
+# NCR seems to have a broken readdir() -- use gnu
+#CC = gcc
+
+# AIX needs -lbsd, and has no identifying cpp symbol
+# Use _AIX41 if you're not on 3.2 anymore.
+#LINKLIBS = -lbsd
+#CFLAGS = -D_AIX
+
+# NT (with Microsoft compiler)
+# Use FATFS if building on a DOS FAT file system
+#Lib = $(MSVCNT)/lib
+#Include = $(MSVCNT)/include
+#CC = cl /nologo
+#CFLAGS = -I $(Include) -DNT
+#TARGET = /Fejam0
+#LINKLIBS = $(Lib)/oldnames.lib $(Lib)/kernel32.lib $(Lib)/libc.lib
+
+# BeOS - Metroworks CodeWarrior
+#CC = mwcc
+#Include = /NewDisk/develop/headers/posix
+#CFLAGS = -I $(Include)
+
+# BeOS - gcc
+#CC = gcc
+#LINKLIBS = -lnet
+
+# Interix - gcc
+#CC = gcc
+
+# Cygwin - gcc & cygwin
+#CC = gcc
+#CFLAGS = -D__cygwin__
+
+# MingW - gcc on Win32
+#
+#CC = gcc
+#CFLAGS = -DNT
+
+# MPEIX
+#CC = gcc
+#CFLAGS = -I/usr/include -D_POSIX_SOURCE
+
+# QNX rtp (neutrino)
+#CC = gcc
+
+
+#
+#SOURCES = \
+# command.c compile.c execnt.c execunix.c execvms.c expand.c \
+# filent.c fileos2.c fileunix.c filevms.c glob.c hash.c \
+# hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c \
+# newstr.c option.c parse.c pathunix.c pathvms.c regexp.c \
+# rules.c scan.c search.c subst.c timestamp.c variable.c
+
+# for Unix systems
+#
+# we need to ensure that "jambase.c" has write permissions, since it is
+# going to be re-generated from "Jambase".
+#
+all: jam0
+ chmod a+w jambase.c
+ ./jam0
+
+# for other systems
+#all: jam0
+# jam0
+
+include common.mk
+
+#jam0:
+# $(CC) $(TARGET) $(CFLAGS) $(SOURCES) $(LINKLIBS)
diff --git a/jam_src/Porting b/jam_src/Porting
new file mode 100644
index 000000000..750556572
--- /dev/null
+++ b/jam_src/Porting
@@ -0,0 +1,68 @@
+Notes on porting Jam - revised 12/31/2000
+
+1) Working out system dependencies in the Jam code.
+
+ Jam's OS footprint is fairly small. For OS independent work Jam
+ liberally uses standard libc functions like stdio, malloc, and
+ string. The OS dependent interfaces are:
+
+ From filesys.h:
+
+ file_parse() - split a file name into dir/base/suffix/member
+ file_build() - build a filename given dir/base/suffix/member
+ file_dirscan() - scan a directory for files
+ file_archscan() - scan an archive for files
+ file_time() - get the timestamp of a file, if not already
+ done by file_dirscan().
+
+ From execcmd.h:
+
+ execcmd() - execute a shell script
+ execwait() - wait for any outstanding execcmd()'s.
+
+ The current implementations are:
+
+ filemac.c - mac MPW
+ filent.c - NT
+ fileos2.c - OS/2
+ fileunix.c - all UNIX
+ filevms.c - VMS
+
+ execmac.c - mac MPW
+ execunix.c - UNIX, OS/2, NT
+ execvms.c - VMS
+
+2) Defining OSMAJOR, OSMINOR in jam.h
+
+ So that the Jambase and Jamfile know their host, Jam defines $(OS)
+ to be something useful for each platform. Make sure that there is
+ code in jam.h to generate a useful value for $(OS), and key it off
+ the platform specific C-preprocessor symbol. If the C-preprocessor
+ doesn't itself defines such a symbol, add a define to the Makefile.
+
+ In addition to $(OS), you can also set $(OSPLAT) if the OS runs on
+ multiple platforms (like Linux or NT).
+
+3) Working out system dependencies in the Jambase
+
+ With the value of $(OS) available, the Jambase can be extended to
+ support special variables or rules for new platforms. See the
+ current support for VMS, NT, and Mac.
+
+4) Yacc troubles
+
+ The generated files jamgram.h and jamgram.c are distributed for the
+ poor souls without yacc.
+
+5) Known problematic systems:
+
+ - Pyramid has no malloc.h, memory.h
+
+ - Encore has no stdlib.h
+
+ - Bull DPX has sys/file.h problems
+
+6) Send the results back.
+
+ If you do porting work, the result can be integrated into future
+ releases if you send it back to the author's address in the README.
diff --git a/jam_src/README b/jam_src/README
new file mode 100644
index 000000000..6f94add06
--- /dev/null
+++ b/jam_src/README
@@ -0,0 +1,157 @@
+This is the FreeType version of Jam. For more information, please see
+ http://www.freetype.org/jam/index.html
+
+The complete and detailed list of changes is available at:
+ http://www.freetype.org/jam/changes.html
+
+------------------------------------------------------------------------------
+
+Jam/MR (aka "jam - make(1) redux")
+
+ /+\
+ +\ Copyright 1993, 2000 Christopher Seiwald.
+ \+/
+
+ This is Release 2.3 of Jam/MR, a make-like program.
+
+ License is hereby granted to use this software and distribute it
+ freely, as long as this copyright notice is retained and modifications
+ are clearly marked.
+
+ ALL WARRANTIES ARE HEREBY DISCLAIMED.
+
+FEATURES
+
+ -> Jam is a make(1) replacement that makes building simple things
+ simple and building complicated things manageable.
+
+ -> Jam's language is expressive, making Jamfiles (c.f. Makefiles)
+ compact. Here's a sample:
+
+ Main smail : main.c map.c resolve.c deliver.c
+ misc.c parser.y alias.c pw.c headers.c
+ scanner.l getpath.c str.c ;
+
+ This builds "smail" from a dozen source files. Jam handles
+ header file dependencies automatically and on-the-fly.
+
+ -> Jam is very portable: it runs on UNIX, VMS, Mac, and NT.
+ Most Jamfiles themselves are portable, like the sample above.
+
+ -> Jam is unintrusive: it is small, it has negligible CPU
+ overhead, and it doesn't create any of its own funny files
+ (c.f. Odin, nmake, SunOS make).
+
+ -> Jam can build large projects spread across many directories
+ in one pass, without recursing, tracking the relationships
+ among all files. Jam can do this with multiple, concurrent
+ processes.
+
+ -> Jam isn't under the blinkin GNU copyright, so you can
+ incorporate it into commercial products.
+
+
+INFORMATION GUIDE
+
+ Jam.html jam command usage
+
+ Jambase.html Reference for the Jambase boilerplate file.
+
+ Jamfile.html Easy reading on creating a Jamfile and using jam.
+
+ Jamlang.html The Jam language description.
+
+ RELNOTES Release 2.3 release notes.
+
+ Porting Notes on porting jam to wildcat platforms.
+
+ README This file. Includes installation instructions.
+
+ jam.c Contains the jam command's main() as well as an
+ introduction to the code, for serious hackers.
+
+
+INSTALLING
+
+ The Makefile (UNIX, NT), build.com (VMS), Build.mpw (Mac MPW) are
+ for bootstrapping. Once jam is built, it can rebuild itself.
+
+ UNIX
+
+ Build jam with make(1) on:
+
+ Platform $(OS)
+ -------------------------
+ AIX AIX *
+ BSD/386 1.0 BSDI
+ COHERENT/386 COHERENT
+ DGUX 5.4 DGUX
+ FreeBSD FREEBSD
+ HPUX 9.0 HPUX
+ IRIX 5.0 IRIX
+ Linux LINUX
+ NEXTSTEP 3.2 NEXT
+ OSF/1 OSF
+ PTX V2.1.0 PTX
+ Solaris 2 SOLARIS *
+ SunOS4.1 SUNOS
+ Ultrix 4.2 ULTRIX
+ BeOS BEOS *
+
+ * requires editing Makefile
+
+ Windows
+
+ Build jam with nmake on:
+
+ Platform $(OS)
+ -------------------------
+ NT NT *
+ OS/2 OS2 *
+
+ The NT MAXLINE (command line length) is still set in jam.h to
+ 996, which was apparently the NT 3.5 limit. On 4.0, the limit
+ is somewhere around 10K. For now, you can increase MAXLINE in
+ jam.h so that a jam running on 4.0 will use the full command
+ line length, but that jam.exe will fail miserably on the older OS.
+
+ On NT, a variable must be set before invoking jam to tell
+ it where the C compiler lives. The name of this variable
+ depends on which compiler you are using:
+
+ BCCROOT: The Borland C compiler
+ MSVCNT: The Microsoft Compiler 5.0 (for NT)
+ MSVC: The Microsoft Compiler 1.5 (for Windows)
+
+ Only MSVCNT has really been tested and is known to work.
+
+ Macintosh
+
+ Build jam with Build.mpw on:
+
+ Platform $(OS)
+ -------------------------
+ Macintosh MAC
+
+ You'll need to edit Build.mpw to set CW.
+
+ VMS
+
+ Build jam with @build.com on:
+
+ Platform $(OS)
+ -------------------------
+ VMS 5.4 VMS
+ OPENVMS OPENVMS
+
+Comments to the author!
+
+November, 1993 - release 1.0
+March, 1995 - release 2.0
+February, 1996 - release 2.1
+November, 1997 - release 2.2
+December, 2000 - release 2.3
+
+Christopher Seiwald
+
+seiwald@perforce.com
diff --git a/jam_src/RELNOTES b/jam_src/RELNOTES
new file mode 100644
index 000000000..47b7bfe69
--- /dev/null
+++ b/jam_src/RELNOTES
@@ -0,0 +1,754 @@
+Release notes for FTJam 2.3.5 (previous release was named "20010626")
+
+0. Bugs fixed since 20010626:
+
+ DEBUG OUTPUT FORMATTING: indentation was "wrapped" when too many levels
+ were reached, making debugging extremly difficult
+
+1. Release info:
+
+ FTJam 2.3.5 (based on Jam 2.3.2)
+ July 30, 2001
+ VERSION 2.3.5
+ PATCHLEVEL 3
+
+2. Compatibility
+
+ FTJam 2.3.5 is upward compatible with Jam 2.3 and 2.2
+ Only a few new builtin rules were added, and some small bugs fixed
+
+3. Changes since 20010626:
+
+ Added a new builtin named FAIL_EXPECTED. It is used to invert the result
+ of a given action. Used by the Boost.Build sub-system.
+
+============================================================================
+============================================================================
+
+
+Release notes for Jam/MR 2.3
+(aka Jam - make(1) redux)
+
+0. Bugs fixed since 2.3.1
+
+ PATCHLEVEL 2 - 3/12/2001
+
+ NOCARE changed back: it once again does not applies to targets
+ with sources and/or actions. In 2.3 it was changed to apply to
+ such targets, but that broke header file builds: files that are
+ #included get marked with NOCARE, but if they have source or
+ actions, they still should get built.
+
+1. Release info:
+
+ Jam/MR 2.3
+ November 16, 2000
+ VERSION 2.3
+ PATCHLEVEL 1
+
+2. Compatibility
+
+ Jam 2.3 is upward compatible with Jam 2.2.
+
+ The Jam 2.3 language is a superset of the 2.2 language;
+ Jamfiles, Jambase, and other rulesets used in 2.2 can be used
+ with the 2.3 language support.
+
+3. Changes since 2.2
+
+3.1. Changes to Jam Language
+
+ Rules now can have values, which can expanded into a list with
+ the new "[ rule args ... ]" syntax. A rule's value is the value
+ of its last statement, though only the following statements have
+ values: if (value of the leg chosen), switch (ditto), set (value
+ of the resulting variable), return (its arguments). Note that
+ 'return' doesn't actually return. This support is EXPERIEMENTAL
+ and otherwise undocumented. (2.3.1)
+
+ Because of the new way lists are processed, if a rule has no
+ targets a warning message is no longer issued.
+
+ NOCARE now applies to targets with sources and/or actions,
+ rather than just those without.
+
+3.2. Jambase Changes
+
+ The HDRPATTERN variable now allows for leading blanks before
+ the #include, to keep up with ANSI. By john@nanaon-sha.co.jp
+ (John Belmonte) (2.2.3).
+
+ HDRPATTERN has been adjusted to avoid mistaking cases like:
+
+ # include /* could be */
+
+ MkDir now NOUPDATE's $(DOT), so that there are no dependencies
+ on the current directory's timestamp. By john@nanaon-sha.co.jp
+ (John Belmonte).
+
+ The old mock functions like makeDirName, which assigned their
+ results to the variable named as their first argument, have
+ been replaced with real functions using the new [] synxtax.
+ E.g. "makeDirName foo : bar ola" is now "foo = [ fDirName bar ]"
+
+ Install now always does a cp/chmod/etc, rather than using
+ the system's install(1), which invariably seems broken.
+
+3.3. Jam internal code changes
+
+ $JAMUNAME is set on UNIX. (2.2.4).
+
+ Jam ANSI-fied (2.3.0).
+
+ jam.h now defines a bunch of symbols used by the other source
+ files, so as minimize compiler- and platform-specific ifdefs.
+
+ OSVER is no longer set by jam.h (it was only set for AIX).
+ Jam does not depend on this variable at all, except to set
+ $(OSFULL), which is used to determine jam's build directory.
+ If the user needs to distinguish between various revs of
+ OSs, he must set OSVER in the environment.
+
+4. Fixed bugs
+
+ Redefining a rule while it was executing could cause jam to
+ crash. Reference counts are now used to prevent that, thanks
+ to Matt Armstrong.
+
+ Logic for computing chunk size when executing PIECEMEAL rules
+ has been reworked to be a little more accurate, without danger
+ of overflow, at the cost of being a little more compute intensive.
+ Instead of computing an estimate chunksize in the (now gone)
+ make1chunk(), make1cmds() now just goes full bore and tries to
+ use all args. When that fails, it backs off by 10% of the source
+ args until the command fits. It takes a little bit more compute
+ time compared to the old logic, but when you're executing actions
+ to build all of Shinola it's still pretty small in the scheme
+ of things.
+
+ The NT handle leak in execunix.c has been fixed, thanks to
+ Gurusamy Sarathy. (2.2.1).
+
+5. Porting
+
+ Platforms newly supported or updated:
+
+ AmigaOS (with gcc), courtesy of Alain Penders (2.2.2).
+
+ Beos
+
+ CYGWIN 1.1.4, courtesy of John Belmonte .
+
+ IBM AS400 via Visual Age on NT (primitive)
+
+ IBM OS/390 Unix System Services
+
+ Linux SuSE on OS390
+
+ Linux Mips, ARM
+
+ Lynx
+
+ HPUX 11, IA64
+
+ Mac OS X Server, courtesy of Jeff_Sickel@sickel.com (2.2.5).
+
+ Mac Rhapsody
+
+ MPE IX 6.0
+
+ NetBSD
+
+ QNX RTP (QNX 6.0)
+
+ Siemens Sinix
+
+ UNICOS
+
+ VMS 6.2, 7.1
+
+ Windows NT IA64
+
+5.1. NT Porting Notes
+
+ Always create tmp .bat file for actions if JAMSHELL is set.
+ That way, if JAMSHELL is a .bat file itself, it can handle
+ single-command actions with more than 9 cmd line args.
+
+ COMSPEC is no longer examined: cmd.exe is always used
+ instead. Only cmd.exe can execute the Jambase rules anyhow.
+
+ Jam can be built with Borland C++ 5.5.
+
+ OS2 fixes: InstallBin now works. Filenames are now downshifted,
+ so mixed case works better there, too. file_dirscan() can now scan
+ the root ("c:\" or "\") directory, which it couldn't handle before.
+
+ var_defines now ignores OS=Windows_NT, because it conflicts
+ with Jam's setting of OS (to NT).
+
+5.2. Mac OS 8/9 Notes
+
+ The support for Mac is curious at best. It runs under MPW.
+
+ It requires CodeWarrior Pro 5, but no longer requires GUSI.
+
+ Use Build.mpw to bootstrap the build.
+
+ The Mac specific definitions in the Jambase are not intended
+ to be of general purpose, but are sufficient to have Jam build
+ itself.
+
+===============================================================================
+===============================================================================
+
+
+Release Notes for Jam 2.2
+
+1. Release info:
+
+ Jam 2.2
+ October 22, 1997
+ VERSION 2.2
+ PATCHLEVEL 1
+
+2. Compatibility
+
+ Jam 2.2 is a roll-up of 'Jam - make(1) redux' release 2.1+.
+ Most of the changes described below were available before this,
+ in the jam.2.1.plus.tar ball.
+
+ The Jam 2.2 language is a superset of the 2.1 language;
+ Jamfiles, Jambase, and other rulesets used in 2.1 can be used
+ with the 2.2 language support.
+
+ See 'Jambase Changes', below, to see if your Jamfiles need any
+ changes to work with the 2.2 Jambase.
+
+
+3. Changes Since 2.1
+
+ New product name: Jam. (Executable program is still named 'jam'.)
+
+ Documentation rewritten; HTML versions supplied.
+
+
+3.1 Changes to Jam Language (See Jamlang.html)
+
+ Rules may now have more fields than just $(<) and $(>).
+
+ Local variables are now supported.
+
+ The expression 'if $(A) in $(B)' is now supported.
+
+ New variable modifiers :U and :L result in uppercased or lowercased
+ values.
+
+ New variable modifier :P reliably results in parent directory
+ of either a file or directory. (Previously, :D was used, but on VMS
+ :D of a directory name is just the directory name.)
+
+ The :S variable modifier now results in the _last_ suffix if a
+ filename has more than one dot (.) in it.
+
+ New predefined $(JAMDATE) variable is initialized at runtime for
+ simple date stamping.
+
+ New predefined variables $(OSVER) and $(OSPLAT) are used to
+ distinguish among operating system versions and hardware platforms,
+ when possible.
+
+ New 'bind' qualifier on action definitions allows variables
+ other than $(<) and $(>) to be bound with SEARCH and LOCATE paths.
+
+ Action buffer size is no longer limited by MAXCMD. Instead, each
+ line in an action is limited by MAXLINE, defined for each OS, and
+ the entire action size is limited by CMDBUF.
+
+
+3.2 Jambase Changes (See Jamfile.html)
+
+ Jambase has been reworked to incorporate new language features.
+
+ A handful of new utility rules has been added: makeString,
+ makeDirName, etc.
+
+ New HDRGRIST variable in Jambase allows for headers with the same
+ name to be distinguished.
+
+ LOCATE_TARGET now has a new flavor, LOCATE_SOURCE, that is used by
+ rules that generate source files (e.g., Yacc and Lex).
+
+ Header file includes now happen in the proper order. The limit of
+ 10 include files has been eliminated.
+
+ The old "Install" rule is no longer available. Use InstallBin,
+ InstallFile, InstallLib, InstallMan, or InstallShell instead.
+
+
+3.3 'jam' Changes (See Jam.html)
+
+ 'jam' can now be built as a stand-alone program, with Jambase
+ compiled into the executable. An external or alternate Jambase can
+ still be referenced explicitly with -f.
+
+ On command failure, 'jam' now emits the text of the command that
+ failed. This is a compromise between the normal -d1 behavior (where
+ commands were never seen) and -d2 (where commands are always seen).
+
+ 'jam' now exits non-zero if it doesn't have a total success. A parse
+ error, sources that can't be found, and targets that can't be built
+ all generate non-zero exit status.
+
+ The debugging levels (-d flags) have been slightly redefined.
+
+ The supplied Jamfile now builds 'jam' into a platform specific
+ subdirectory. This lets you use the same source directory to
+ build 'jam' for more than one platform.
+
+ The supplied Jamfile does not rebuild generated source files by
+ default. (They are supplied with the distribution.) See Jamfile
+ for more information.
+
+
+4. Fixed Bugs
+
+ The 'include' bug has finally been fixed, so that include
+ statements take effect exactly when they are executed,
+ rather than after the current statement block. This also
+ corrects the problem where an 'include' within an 'if'
+ block would wind up including the file one token after the
+ 'if' block's closing brace. Credit goes to Thomas Woods
+ for suggesting that the parse tree generation and parse
+ tree execution be paired in their own loop, rather than
+ having the parser execute the tree directly.
+
+ The setting and extracting of grist has been regularized:
+ normally, if you set a component of a filename (using the
+ :DBSMG= modifiers), you are supposed to include the delimiters
+ that set off the component: that is, you say "$(x:S=.suffix)",
+ including the ".". But with grist it was inconsistent
+ between setting and getting: setting grist required no
+ <>'s, while getting grist included them. Getting grist
+ continues to return the <>'s, but now setting grist can
+ either include them (the new way) or not (the old way).
+
+ 'actions together' now suppresses duplicate sources from
+ showing up in $(>).
+
+ Accessing variables whose names contained ['s (as happens with
+ MkDir on VMS) wasn't working, because it treated the [ as an
+ array subscript. Now [ and ] are, like :, handled specially so
+ that they can appear in variable values.
+
+ The 'if' statement now compares all elements in expressions;
+ previously, it only compared the first element of each list.
+
+ If a command line in an action is longer than MAXLINE (formerly
+ MAXCMD), 'jam' now issues an error and exits rather than dumping
+ core.
+
+ If a Jamfile ended without a trailing newline, jam dumped core.
+ This has been fixed.
+
+
+5. Porting
+
+ See jam.h for the definitive list of supported platforms.
+ Since 2.1, support has been added for:
+
+ Macintosh MPW
+ Alpha VMS
+ Alpha NT
+ NT PowerPC
+ BeOS
+ MVS OE
+ UNIXWARE
+ QNX
+ SINIX (Nixdorf)
+ OS/2
+ Interactive UNIX (ISC), courtesy of Matthew Newhook
+
+
+5.1 NT Support Fixes
+
+ The NT command executor now handles multiple line actions, by writing
+ multi-line actions to a batch file and executing that.
+
+ Targets are universally lowercased on NT. (Matthew Newhook)
+
+ Concurrent process support is fully enabled for NT.
+ (Gurusamy Sarathy )
+
+ Path handling: Jam now knows that the directory component of "D:\"
+ is "D:\", just as on unix it knows that the directory component of
+ "/" is "/". It also now successfully gets the timestamp for "D:\"
+ or just plain "\".
+
+
+5.2 VMS Support Fixes
+
+ VMS support is much, much better now. The path name manipulation
+ routines (in pathvms.c) were more or less rewritten, and they now
+ handle the vagaries of combining directory and file names properly.
+
+ Targets are universally lowercased on VMS.
+
+ Multi-line command blocks on VMS are now executed in a single system()
+ call rather than separate ones for each line, so that actions can
+ be DCL scripts.
+
+===============================================================================
+===============================================================================
+
+
+Release notes for Jam 2.1.
+
+1. Release info:
+ Jam 2.1
+ February 1, 1996
+ VERSION 2.1
+ PATCHLEVEL 0
+
+2. Porting
+
+ Linux is now supported.
+
+ FREEBSD is now supported.
+
+ SCO ("M_XENIX") now supported.
+
+ NCR now supported.
+
+ NEXT support from karthy@dannug.dk (Karsten Thygesen)
+
+ DECC support from zinser@axp614.gsi.de (Martin P.J. Zinser)
+
+ I have changes for OS/2, but no way to test them. Volunteers?
+ I have VMS multiprocess support, but no way to test it. Volunteers?
+
+2.1. NT Support fixes.
+
+ The NT support is considerably more real than it was in 2.0.
+ Filent.c had its syntax error corrected, it no longer skips the
+ first entry when scanning directories, and it handles string
+ tables in archives (for long object file names).
+
+ The Jambase was changed a bit to support the various C/C++
+ compilers on NT, although it has only been thorougly tested
+ with MSVC20.
+
+ You still need to set MSVCNT or BCCROOT to the root of the
+ the compiler's directory tree, and you'll get an error if you
+ don't set it (rather than getting a pile of mysterious errors).
+
+2.2. Other porting fixes.
+
+ SPLITPATH now set up for UNIX (:), NT (;), VMS (,)
+
+ Jambase support for Solaris works better now: the location of
+ AR is hardwired to /usr/ccs/bin/ar and it knowns "install"
+ doesn't take -c. Solaris -- how the mighty have fallen.
+
+ To handle Linux's wacko yacc, jamgram.h is now included after
+ scan.h so that YYSTYPE is define.
+
+3. Jambase Changes (see Jamfile.html)
+
+ SubDir now computes the root directory for the source tree, if
+ the variable naming the root directory isn't set in the environment.
+ It counts the number of directory elements leading from the root
+ to the current directory (as passed to SubDir) and uses that many
+ "../"'s to identify the root. This means that to use SubDir you
+ no longer have to have anything special set in the environment.
+
+ InstallFile is now an alias for InstallLib.
+
+ 'first' is now dependency of all pseudo-targets (all, files,
+ exe, lib, shell), so that jamming any of these pseudo-targets
+ also builds any dependencies of 'first'.
+
+ The File rule definition in the Jambase was missing an &.
+
+ The File rule now calls the Clean rule, so that installed files
+ get cleaned.
+
+4. Jam changes (see Jam.html)
+
+ Variables may now be set on the command line with -svar=value.
+
+ Targets marked with NOUPDATE are now immune to the -a (anyhow)
+ flag. Previously, the MkDir rule would try to recreate directories
+ that already exist when jam was invoked with -a.
+
+ A new variable, $(JAMVERSION), joins the small list of built-in
+ variables. It it set to the release of jam, currently "2.1".
+
+ If an actions fails, jam now deletes the target(s). It won't
+ delete libraries or other targets that are composites. This is
+ now consistent with jam's behavior on interrupts (it deletes the
+ targets).
+
+ Jam had a nasty bug when setting multiple variables to the same
+ value: if the first two variable names were the same, the variable
+ value got trashed. This also affected "on target" variables if
+ the first two targets were the same. For example:
+
+ FOO on bar.c bar.c foo.c = a b c ;
+
+ This would mangle the value of FOO for bar.c and foo.c. This has
+ been fixed.
+
+ Jam would generate bogus numbers when reporting the number of
+ targets updated after an interrupt. It now is more careful about
+ counting.
+
+ The debugging flag -d has been extended. In addition to supporting
+ -dx (turn on debugging for all levels up to x) there is also now
+ -d+x (turn on debugging at only level x). The default output
+ level is -d1 (-or d2 if -n is given); this can be turned off with
+ -d0. The debug levels are listed in jam.1 and jam.h.
+
+ The parsing debug output now uses indenting to indicate when
+ one rule invokes another.
+
+===============================================================================
+===============================================================================
+
+
+Release notes for Jam 2.0.
+
+1. Release info:
+ Jam 2.0
+ March 10, 1994
+ VERSION 2.0
+ PATCHLEVEL 5
+
+2. Porting
+
+ Windows/NT is now (crudely) supported, courtesy of Brett Taylor
+ and Laura Wingerd.
+
+ COHERENT/386 is now supported, courtesy of Fred Smith.
+
+ Solaris archive string table for long archive names is now
+ supported, thanks to Mike Matrigali.
+
+3. Compatibility
+
+ Jam 2.0 syntax is a superset of Jam 1.0 syntax, and thus it can
+ interpret a Jam 1.0 Jambase.
+
+ The Jam 2.0 Jambase is a superset of the Jam 1.0 Jambase, and
+ thus it can include a Jamfile written for Jam 1.0.
+
+4. Changes from Jam 1.0 to Jam 2.0
+
+4.1. Documentation changes
+
+ New Jamfile.5 manual page, with lots of examples and easy
+ reading. It replaces both the old "Examples" file as well as
+ the old Jambase.5 manual page.
+
+ jam.1 edited by Stephen W. Liddle and Diane Holt.
+
+4.2. Jambase Changes (see Jamfile.5)
+
+4.2.1. New rules:
+
+ There are new rules to make handling subdirectories easier:
+ SubDir, SubInclude, SubDirCcFlags, SubDirHdrs.
+
+ There are new rules to handle file-specific CCFLAGS and HDRS:
+ ObjectCcFlags and ObjectHdrs.
+
+ Misc new rules: HardLink, InstallShell, MkDir.
+
+ New rule "clean" that deletes exactly what jam has built, and
+ "uninstall" that deletes exactly what was installed.
+
+ New rules for handling suffixes .s, .f, .cc, .cpp, .C.
+
+4.2.2. Old rules:
+
+ The InstallBin, Lib, Man, and the new Shell rules now take the
+ destination directory as the target and the files to be copied
+ as sources. These rules formerly took the files to be copied
+ as targets, and used built-in destination directories of
+ $(BINDIR), $(LIBDIR), $(MANDIR), and $(BINDIR).
+
+ The InstallBin, Lib, Man, and Shell rules use the install(1)
+ program now, instead of doing their own copying.
+
+ The Cc rule now uses -o when possible, rather than moving the
+ result. Some platforms (Pyramid?) have a broken -o.
+
+ Jambase rules taking libraries, objects, and executables now
+ all ignore the suffixes provided and use the one defined in the
+ Jambase for the platform.
+
+ Stupid yyacc support moved out of Jambase, as jam is its only
+ likely user.
+
+ Jambase now purturbs library sources with a "grist" of
+ SOURCE_GRIST.
+
+4.2.3. Misc:
+
+ The names of the default rules defined in Jambase have been
+ lowercased and un-abbreviated, to be more imake(1) like.
+
+ The Jambase has been reorganized and sorted, with VMS and NT
+ support moved in from their own files.
+
+ The Jambase has been relocated on UNIX from /usr/local/lib/jam
+ to /usr/local/lib.
+
+4.3. Jam changes (see jam.1)
+
+4.3.1. Flags:
+
+ New -a (anyhow) flag: means build everything.
+
+ New -j flag: run jobs in parallel.
+
+ Old -t now rebuilds the touched target, rather that just the
+ target's parents.
+
+ -n now implies -d2, so that you see what's happening. The
+ debug level can be subsequently overridden.
+
+ New -v to dump version.
+
+4.3.2. Rules:
+
+ New ALWAYS rule behaves like -t: always builds target.
+
+ New EXIT rule makes it possible to raise a fatal error.
+
+ New LEAVES rule which say target depends only on the update
+ times of the leaf sources.
+
+ New NOUPDATE rule says built targets only if they don't exist.
+
+ NOTIME has been renamed NOTFILE, to more accurately reflect its
+ meaning (it says a target is not to be bound to a file).
+
+4.3.3. Variables:
+
+ New special variable JAMSHELL: argv template for command execution
+ shell.
+
+ Variables, both normal and target-specific, can have their
+ value appended with the syntax "var += value" or "var on target
+ += value".
+
+ "?=" is now synonymous with "default =".
+
+ Imported enviroment variable values are now split at blanks
+ (:'s if the variable name ends in PATH), so that they become
+ proper list values.
+
+4.3.4. Misc:
+
+ Files to be sourced with "include" are now bound first, so
+ $(SEARCH) and $(LOCATE) affect them. They still can't be
+ built, though.
+
+ New modifier on "actions": "existing" causes $(>) to expand
+ only those files that currently exist.
+
+4.3.5. Bug fixes:
+
+ When scanning tokens known to be argument lists (such as the
+ arguments to rule invocations and variable assignment), the
+ parser now tells the scanner to ignore alphabetic keywords, as
+ all such lists terminate with punctuation keywords (like : or
+ ;). This way, alphabetic keywords don't need to be quoted when
+ they appear as arguments.
+
+ The scanner has been fixed to handle oversized tokens,
+ unterminated quotes, unterminated action blocks, and tokens
+ abutting EOF (i.e. a token with no white space before EOF).
+
+ The progress report "...on xth target..." used to count all
+ targets, rather than just those with updating actions. Since
+ the original pronouncement of targets to be udpated included
+ only those with updating actions, the progress report has been
+ changed to match.
+
+ 'If' conditionals now must be single arguments. Previously,
+ they could be zero or more arguments, which didn't make much
+ sense, and made things like 'foo == bar' true. The comparison
+ operator is '=', and '==' just looked like the second of three
+ arguments in the unary "non-empty argument list" conditional.
+
+ Header files indirectly including themselves were mistakenly
+ reported as being dependent on themselves. Recursing through
+ header file dependencies is now done after determining the fate
+ of the target.
+
+ The variable expansion support was expanding $(X)$(UNDEF) as if
+ it were $(X). It now expands to an empty list, like it
+ should.
+
+ The UNIX version of file_build() didn't handle "dir/.suffix"
+ right. Now it does.
+
+ The VMS command buffer was assumed to be as large as 1024 bytes,
+ which isn't the case everywhere as it is related to some weird
+ quota. It has been lowered to 256.
+
+ $(>) and $(<) wouldn't expand in action blocks if the targets
+ were marked with NOTIME. Now they expand properly.
+
+ Malloc() return values are now checked.
+
+ The variable expansion routine var_expand() is now a little
+ faster, by taking a few often needed shortcuts.
+
+ The VMS version of file_build() used the wrong length when
+ re-rooting file names that already had directory compoents.
+ This was fixed.
+
+ Various tracing adjustments were made.
+
+5. Limitations/Known Bugs
+
+ The new Windows/NT support has only been marginally tested. It
+ is dependent on certain variables being set depending on which
+ compiler you are using. You'll need to look in the file
+ Jambase and see what variables are expected to be set.
+
+ The VMS support has been tested, courtesy of the DEC guest
+ machine, but has not been hammered fully in release 2.0. It
+ was used quite a bit in Jam 1.0.
+
+ Jam clean when there is nothing to clean claims it is updating
+ a target.
+
+ Because the include statement works by pushing a new file in
+ the input stream of the scanner rather than recursively
+ invoking the parser on the new file, multiple include
+ statements in a rule's procedure causes the files to be
+ included in reverse order.
+
+ If the include statement appears inside an if block, the
+ parser's attempt to find the else will cause the text of the
+ included file to appear after the first token following the
+ statement block. This is rarely what is intended.
+
+ In a rule's actions, only $(<) and $(>) refer to the bound file
+ names: all other variable references get the unbound names.
+ This is a pain for $(NEEDLIBS), because it means that library
+ path can't be bound using $(SEARCH) and $(LOCATE).
+
+ With the -j flag, errors from failed commands can get
+ staggeringly mixed up. Also, because targets tend to get built
+ in a quickest-first ordering, dependency information must be
+ quite exact. Finally, beware of parallelizing commands that
+ drop fixed-named files into the current directory, like yacc(1)
+ does.
+
+ A poorly set $(JAMSHELL) is likely to result in silent
+ failure.
diff --git a/jam_src/command.c b/jam_src/command.c
new file mode 100644
index 000000000..c05ce3601
--- /dev/null
+++ b/jam_src/command.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * command.c - maintain lists of commands
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "rules.h"
+
+# include "command.h"
+# include
+
+/*
+ * cmd_new() - return a new CMD or 0 if too many args
+ */
+
+CMD *
+cmd_new(
+ RULE *rule,
+ LIST *targets,
+ LIST *sources,
+ LIST *shell )
+{
+ CMD *cmd = (CMD *)malloc( sizeof( CMD ) );
+ /* lift line-length limitation entirely when JAMSHELL is just "%" */
+ int expand_line = ( shell && !strcmp(shell->string,"%") && !list_next(shell) );
+ int max_line = MAXLINE;
+ int allocated = -1;
+
+ cmd->rule = rule;
+ cmd->shell = shell;
+ cmd->next = 0;
+
+ lol_init( &cmd->args );
+ lol_add( &cmd->args, targets );
+ lol_add( &cmd->args, sources );
+ cmd->buf = 0;
+
+ do
+ {
+ free(cmd->buf); /* free any buffer from previous iteration */
+
+ cmd->buf = (char*)malloc(max_line + 1);
+
+ if (cmd->buf == 0)
+ break;
+
+ allocated = var_string( rule->actions->command, cmd->buf, max_line, &cmd->args );
+
+ max_line = max_line * 2;
+ }
+ while( expand_line && allocated < 0 && max_line < INT_MAX / 2 );
+
+ /* Bail if the result won't fit in MAXLINE */
+ /* We don't free targets/sources/shell if bailing. */
+ if( allocated < 0 )
+ {
+ cmd_free( cmd );
+ cmd = 0;
+ }
+
+ return cmd;
+}
+
+/*
+ * cmd_free() - free a CMD
+ */
+
+void
+cmd_free( CMD *cmd )
+{
+ lol_free( &cmd->args );
+ list_free( cmd->shell );
+ free( cmd->buf );
+ free( (char *)cmd );
+}
diff --git a/jam_src/command.h b/jam_src/command.h
new file mode 100644
index 000000000..6e4752ffe
--- /dev/null
+++ b/jam_src/command.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1994 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * command.h - the CMD structure and routines to manipulate them
+ *
+ * Both ACTION and CMD contain a rule, targets, and sources. An
+ * ACTION describes a rule to be applied to the given targets and
+ * sources; a CMD is what actually gets executed by the shell. The
+ * differences are due to:
+ *
+ * ACTIONS must be combined if 'actions together' is given.
+ * ACTIONS must be split if 'actions piecemeal' is given.
+ * ACTIONS must have current sources omitted for 'actions updated'.
+ *
+ * The CMD datatype holds a single command that is to be executed
+ * against a target, and they can chain together to represent the
+ * full collection of commands used to update a target.
+ *
+ * Structures:
+ *
+ * CMD - an action, ready to be formatted into a buffer and executed
+ *
+ * External routines:
+ *
+ * cmd_new() - return a new CMD or 0 if too many args
+ * cmd_free() - delete CMD and its parts
+ * cmd_next() - walk the CMD chain
+ */
+
+/*
+ * CMD - an action, ready to be formatted into a buffer and executed
+ */
+
+typedef struct _cmd CMD;
+
+struct _cmd
+{
+ CMD *next;
+ CMD *tail; /* valid on in head */
+ RULE *rule; /* rule->actions contains shell script */
+ LIST *shell; /* $(SHELL) value */
+ LOL args; /* LISTs for $(<), $(>) */
+ char* buf; /* actual commands */
+} ;
+
+CMD *cmd_new(
+ RULE *rule, /* rule (referenced) */
+ LIST *targets, /* $(<) (freed) */
+ LIST *sources, /* $(>) (freed) */
+ LIST *shell ); /* $(SHELL) (freed) */
+
+void cmd_free( CMD *cmd );
+
+# define cmd_next( c ) ((c)->next)
diff --git a/jam_src/common.mk b/jam_src/common.mk
new file mode 100644
index 000000000..6abd3e86b
--- /dev/null
+++ b/jam_src/common.mk
@@ -0,0 +1,17 @@
+# Common Makefile rules
+#
+
+# the Jam sources needed to build "jam0"
+#
+SOURCES = \
+ command.c compile.c execnt.c execunix.c execvms.c expand.c \
+ filent.c fileos2.c fileunix.c filevms.c glob.c hash.c \
+ hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c \
+ newstr.c option.c parse.c pathunix.c pathvms.c regexp.c \
+ rules.c scan.c search.c subst.c timestamp.c variable.c modules.c \
+ strings.c filesys.c
+
+# the bootstrap "jam0" build tool
+#
+jam0:
+ $(CC) $(TARGET) $(CFLAGS) $(SOURCES) $(LINKLIBS)
diff --git a/jam_src/compile.c b/jam_src/compile.c
new file mode 100644
index 000000000..93f3007ec
--- /dev/null
+++ b/jam_src/compile.c
@@ -0,0 +1,1390 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/* This file is ALSO:
+ * (C) Copyright David Abrahams 2001. Permission to copy, use,
+ * modify, sell and distribute this software is granted provided this
+ * copyright notice appears in all copies. This software is provided
+ * "as is" without express or implied warranty, and with no claim as
+ * to its suitability for any purpose.
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "compile.h"
+# include "variable.h"
+# include "expand.h"
+# include "rules.h"
+# include "newstr.h"
+# include "make.h"
+# include "search.h"
+# include "hdrmacro.h"
+# include "hash.h"
+# include "modules.h"
+# include "strings.h"
+
+# include
+# include
+
+/*
+ * compile.c - compile parsed jam statements
+ *
+ * External routines:
+ *
+ * compile_append() - append list results of two statements
+ * compile_foreach() - compile the "for x in y" statement
+ * compile_if() - compile 'if' rule
+ * compile_while() - compile 'while' rule
+ * compile_include() - support for 'include' - call include() on file
+ * compile_list() - expand and return a list
+ * compile_local() - declare (and set) local variables
+ * compile_null() - do nothing -- a stub for parsing
+ * compile_rule() - compile a single user defined rule
+ * compile_rules() - compile a chain of rules
+ * compile_set() - compile the "set variable" statement
+ * compile_setcomp() - support for `rule` - save parse tree
+ * compile_setexec() - support for `actions` - save execution string
+ * compile_settings() - compile the "on =" (set variable on exec) statement
+ * compile_switch() - compile 'switch' rule
+ *
+ * Internal routines:
+ *
+ * debug_compile() - printf with indent to show rule expansion.
+ *
+ * evaluate_if() - evaluate if to determine which leg to compile
+ * evaluate_rule() - execute a rule invocation
+ *
+ * builtin_depends() - DEPENDS/INCLUDES rule
+ * builtin_echo() - ECHO rule
+ * builtin_exit() - EXIT rule
+ * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
+ *
+ * 02/03/94 (seiwald) - Changed trace output to read "setting" instead of
+ * the awkward sounding "settings".
+ * 04/12/94 (seiwald) - Combined build_depends() with build_includes().
+ * 04/12/94 (seiwald) - actionlist() now just appends a single action.
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 05/13/94 (seiwald) - include files are now bound as targets, and thus
+ * can make use of $(SEARCH)
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
+ * 01/22/95 (seiwald) - Exit rule.
+ * 02/02/95 (seiwald) - Always rule; LEAVES rule.
+ * 02/14/95 (seiwald) - NoUpdate rule.
+ * 09/11/00 (seiwald) - new evaluate_rule() for headers().
+ * 09/11/00 (seiwald) - compile_xxx() now return LIST *.
+ * New compile_append() and compile_list() in
+ * support of building lists here, rather than
+ * in jamgram.yy.
+ */
+
+static void debug_compile( int which, char *s );
+
+static int evaluate_if( PARSE *parse, FRAME *frame );
+
+static LIST *builtin_depends( PARSE *parse, FRAME *frame );
+static LIST *builtin_echo( PARSE *parse, FRAME *frame );
+static LIST *builtin_exit( PARSE *parse, FRAME *frame );
+static LIST *builtin_flags( PARSE *parse, FRAME *frame );
+static LIST *builtin_hdrmacro( PARSE *parse, FRAME *frame );
+static LIST *builtin_import( PARSE *parse, FRAME *frame );
+static LIST *builtin_caller_module( PARSE *parse, FRAME *frame );
+LIST *builtin_subst( PARSE *parse, FRAME *frame );
+
+int glob( char *s, char *c );
+
+
+void frame_init( FRAME* frame )
+{
+ frame->prev = 0;
+ lol_init(frame->args);
+ frame->module = root_module();
+}
+
+void frame_free( FRAME* frame )
+{
+ lol_free( frame->args );
+}
+
+/*
+ * compile_builtin() - define builtin rules
+ */
+
+# define P0 (PARSE *)0
+# define C0 (char *)0
+
+static void lol_build( LOL* lol, char** elements )
+{
+ LIST* l = L0;
+ lol_init( lol );
+
+ while ( elements && *elements )
+ {
+ if ( !strcmp( *elements, ":" ) )
+ {
+ lol_add( lol, l );
+ l = L0 ;
+ }
+ else
+ {
+ l = list_new( l, newstr( *elements ) );
+ }
+ ++elements;
+ }
+
+ if ( l != L0 )
+ lol_add( lol, l );
+}
+
+static RULE* bind_builtin( char* name, LIST*(*f)(PARSE*, FRAME*), int flags, char** args )
+{
+ argument_list* arg_list = 0;
+ RULE* builtin_rule;
+
+ if ( args )
+ {
+ arg_list = args_new();
+ lol_build( arg_list->data, args );
+ }
+
+ return new_rule_body( root_module(), name, arg_list,
+ parse_make( f, P0, P0, P0, C0, C0, flags ) );
+}
+
+static RULE* duplicate_rule( char* name, RULE* other )
+{
+ return import_rule( other, root_module(), name );
+}
+
+void
+compile_builtins()
+{
+ duplicate_rule( "Always", bind_builtin( "ALWAYS", builtin_flags, T_FLAG_TOUCHED, 0 ) );
+ duplicate_rule( "Depends", bind_builtin( "DEPENDS", builtin_depends, T_DEPS_DEPENDS, 0 ) );
+ duplicate_rule( "Echo", bind_builtin( "ECHO", builtin_echo, 0, 0 ) );
+ duplicate_rule( "Exit", bind_builtin( "EXIT", builtin_exit, 0, 0 ) );
+ duplicate_rule( "Includes", bind_builtin( "INCLUDES", builtin_depends, T_DEPS_INCLUDES, 0 ) );
+ duplicate_rule( "HdrMacro", bind_builtin( "HDRMACRO", builtin_hdrmacro, 0, 0 ) );
+ duplicate_rule( "Leaves", bind_builtin( "LEAVES", builtin_flags, T_FLAG_LEAVES, 0 ) );
+ duplicate_rule( "NoCare", bind_builtin( "NOCARE", builtin_flags, T_FLAG_NOCARE, 0 ) );
+ duplicate_rule( "NOTIME",
+ duplicate_rule( "NotFile",
+ bind_builtin( "NOTFILE", builtin_flags, T_FLAG_NOTFILE, 0 ) ) );
+
+ duplicate_rule( "NoUpdate", bind_builtin( "NOUPDATE", builtin_flags, T_FLAG_NOUPDATE, 0 ) );
+ duplicate_rule( "Temporary", bind_builtin( "TEMPORARY", builtin_flags, T_FLAG_TEMP, 0 ) );
+
+ /* FAIL_EXPECTED is an experimental built-in that is used to indicate */
+ /* that the result of a target build action should be inverted (ok <=> fail) */
+ /* this can be useful when performing test runs from Jamfiles.. */
+ /* */
+ /* Beware that this rule might disappear or be renamed in the future.. */
+ /* contact david.turner@freetype.org for more details.. */
+ bind_builtin( "FAIL_EXPECTED", builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
+
+ {
+ char* args[] = { "string", "pattern", "replacements", "+", 0 };
+ duplicate_rule( "subst", bind_builtin( "SUBST", builtin_subst, 0, args ) );
+ }
+
+ {
+ char* args[] = {
+ "target_module", "?"
+ , ":", "source_module", "?"
+ , ":", "rule_names", "*"
+ , ":", "target_names", "*", 0
+ };
+
+ bind_builtin( "IMPORT", builtin_import, 0, args );
+ }
+
+ {
+ char* args[] = { 0 };
+ bind_builtin( "CALLER_MODULE", builtin_caller_module, 0, args );
+ }
+}
+
+/*
+ * compile_append() - append list results of two statements
+ *
+ * parse->left more compile_append() by left-recursion
+ * parse->right single rule
+ */
+
+LIST *
+compile_append(
+ PARSE *parse,
+ FRAME *frame )
+{
+ /* Append right to left. */
+
+ return list_append(
+ (*parse->left->func)( parse->left, frame ),
+ (*parse->right->func)( parse->right, frame ) );
+}
+
+/*
+ * compile_foreach() - compile the "for x in y" statement
+ *
+ * Compile_foreach() resets the given variable name to each specified
+ * value, executing the commands enclosed in braces for each iteration.
+ *
+ * parse->string index variable
+ * parse->left variable values
+ * parse->right rule to compile
+ */
+
+LIST *
+compile_foreach(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nv = (*parse->left->func)( parse->left, frame );
+ LIST *l;
+ SETTINGS *s = 0;
+
+ if ( parse->num )
+ {
+ s = addsettings( s, 0, parse->string, L0 );
+ pushsettings( s );
+ }
+
+ /* Call var_set to reset $(parse->string) for each val. */
+
+ for( l = nv; l; l = list_next( l ) )
+ {
+ LIST *val = list_new( L0, copystr( l->string ) );
+
+ var_set( parse->string, val, VAR_SET );
+
+ list_free( (*parse->right->func)( parse->right, frame ) );
+ }
+
+ if ( parse->num )
+ popsettings( s );
+
+ list_free( nv );
+
+ return L0;
+}
+
+/*
+ * compile_if() - compile 'if' rule
+ *
+ * parse->left condition tree
+ * parse->right then tree
+ * parse->third else tree
+ */
+
+LIST *
+compile_if(
+ PARSE *p,
+ FRAME *frame )
+{
+ if( evaluate_if( p->left, frame ) )
+ {
+ return (*p->right->func)( p->right, frame );
+ }
+ else
+ {
+ return (*p->third->func)( p->third, frame );
+ }
+}
+
+LIST *
+compile_while(
+ PARSE *p,
+ FRAME *frame )
+{
+ while ( evaluate_if( p->left, frame ) )
+ {
+ list_free( (*p->right->func)( p->right, frame ) );
+ }
+ return L0;
+}
+
+/*
+ * evaluate_if() - evaluate if to determine which leg to compile
+ *
+ * Returns:
+ * !0 if expression true - compile 'then' clause
+ * 0 if expression false - compile 'else' clause
+ */
+
+static int
+evaluate_if(
+ PARSE *parse,
+ FRAME *frame )
+{
+ int status;
+
+ if( parse->num <= COND_OR )
+ {
+ /* Handle one of the logical operators */
+
+ switch( parse->num )
+ {
+ case COND_NOT:
+ status = !evaluate_if( parse->left, frame );
+ break;
+
+ case COND_AND:
+ status = evaluate_if( parse->left, frame ) &&
+ evaluate_if( parse->right, frame );
+ break;
+
+ case COND_OR:
+ status = evaluate_if( parse->left, frame ) ||
+ evaluate_if( parse->right, frame );
+ break;
+
+ default:
+ status = 0; /* can't happen */
+ }
+ }
+ else
+ {
+ /* Handle one of the comparison operators */
+ /* Expand targets and sources */
+
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+
+ /* "a in b" make sure each of a is equal to something in b. */
+ /* Otherwise, step through pairwise comparison. */
+
+ if( parse->num == COND_IN )
+ {
+ LIST *s, *t;
+
+ /* Try each t until failure. */
+
+ for( status = 1, t = nt; status && t; t = list_next( t ) )
+ {
+ int stat1;
+
+ /* Try each s until success */
+
+ for( stat1 = 0, s = ns; !stat1 && s; s = list_next( s ) )
+ stat1 = !strcmp( t->string, s->string );
+
+ status = stat1;
+ }
+ }
+ else
+ {
+ LIST *s = ns, *t = nt;
+
+ status = 0;
+
+ while( !status && ( t || s ) )
+ {
+ char *st = t ? t->string : "";
+ char *ss = s ? s->string : "";
+
+ status = strcmp( st, ss );
+
+ t = t ? list_next( t ) : t;
+ s = s ? list_next( s ) : s;
+ }
+ }
+
+ switch( parse->num )
+ {
+ case COND_EXISTS: status = status > 0 ; break;
+ case COND_EQUALS: status = !status; break;
+ case COND_NOTEQ: status = status != 0; break;
+ case COND_LESS: status = status < 0; break;
+ case COND_LESSEQ: status = status <= 0; break;
+ case COND_MORE: status = status > 0; break;
+ case COND_MOREEQ: status = status >= 0; break;
+ case COND_IN: /* status = status */ break;
+ }
+
+ if( DEBUG_IF )
+ {
+ debug_compile( 0, "if" );
+ list_print( nt );
+ printf( "(%d)", status );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ list_free( nt );
+ list_free( ns );
+
+ }
+
+ return status;
+}
+
+/*
+ * compile_include() - support for 'include' - call include() on file
+ *
+ * parse->left list of files to include (can only do 1)
+ */
+
+LIST *
+compile_include(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "include" );
+ list_print( nt );
+ printf( "\n" );
+ }
+
+ if( nt )
+ {
+ TARGET *t = bindtarget( nt->string );
+
+ /* DWA 2001/10/22 - Perforce Jam clears the arguments here, which
+ * prevents an included file from being treated as part of the body
+ * of a rule. I didn't see any reason to do that, so I lifted the
+ * restriction.
+ */
+
+ /* Bind the include file under the influence of */
+ /* "on-target" variables. Though they are targets, */
+ /* include files are not built with make(). */
+
+ pushsettings( t->settings );
+ t->boundname = search( t->name, &t->time );
+ popsettings( t->settings );
+
+ parse_file( t->boundname, frame );
+ }
+
+ list_free( nt );
+
+ return L0;
+}
+
+LIST *
+compile_module(
+ PARSE *p,
+ FRAME *frame )
+{
+ /* Here we are entering a module declaration block.
+ */
+ LIST* module_name = (*p->left->func)( p->left, frame );
+ LIST* result;
+
+ module* outer_module = frame->module;
+ frame->module = module_name ? bindmodule( module_name->string ) : root_module();
+
+ if ( outer_module != frame->module )
+ {
+ exit_module( outer_module );
+ enter_module( frame->module );
+ }
+
+ result = (*p->right->func)( p->right, frame );
+
+ if ( outer_module != frame->module )
+ {
+ exit_module( frame->module );
+ enter_module( outer_module );
+ frame->module = outer_module;
+ }
+
+ list_free( module_name );
+ return result;
+}
+
+
+/*
+ * compile_list() - expand and return a list
+ *
+ * parse->string - character string to expand
+ */
+
+LIST *
+compile_list(
+ PARSE *parse,
+ FRAME *frame )
+{
+ /* voodoo 1 means: s is a copyable string */
+ char *s = parse->string;
+ return var_expand( L0, s, s + strlen( s ), frame->args, 1 );
+}
+
+/*
+ * compile_local() - declare (and set) local variables
+ *
+ * parse->left list of variables
+ * parse->right list of values
+ * parse->third rules to execute
+ */
+
+LIST *
+compile_local(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *l;
+ SETTINGS *s = 0;
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+ LIST *result;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "local" );
+ list_print( nt );
+ printf( " = " );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Initial value is ns */
+
+ for( l = nt; l; l = list_next( l ) )
+ s = addsettings( s, 0, l->string, list_copy( (LIST*)0, ns ) );
+
+ list_free( ns );
+ list_free( nt );
+
+ /* Note that callees of the current context get this "local" */
+ /* variable, making it not so much local as layered. */
+
+ pushsettings( s );
+ result = (*parse->third->func)( parse->third, frame );
+ popsettings( s );
+
+ freesettings( s );
+
+ return result;
+}
+
+/*
+ * compile_null() - do nothing -- a stub for parsing
+ */
+
+LIST *
+compile_null(
+ PARSE *parse,
+ FRAME *frame )
+{
+ return L0;
+}
+
+/*
+ * compile_rule() - compile a single user defined rule
+ *
+ * parse->string name of user defined rule
+ * parse->left parameters (list of lists) to rule, recursing left
+ *
+ * Wrapped around evaluate_rule() so that headers() can share it.
+ */
+
+LIST *
+compile_rule(
+ PARSE *parse,
+ FRAME *frame )
+{
+ FRAME inner[1];
+ LIST *result;
+ PARSE *p;
+
+
+ /* Build up the list of arg lists */
+
+ frame_init( inner );
+ inner->prev = frame;
+ inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below */
+
+ for( p = parse->left; p; p = p->left )
+ lol_add( inner->args, (*p->right->func)( p->right, frame ) );
+
+ /* And invoke rule */
+
+ result = evaluate_rule( parse->string, inner );
+
+ frame_free( inner );
+
+ return result;
+}
+
+static void argument_error( char* message, RULE* rule, LOL* actual, LIST* arg )
+{
+ printf( "### argument error\n# rule %s ( ", rule->name );
+ lol_print( rule->arguments->data );
+ printf( ")\n# called with: ( " );
+ lol_print( actual );
+ printf( ")\n# %s %s", message, arg ? arg->string : "" );
+ printf("\n");
+ exit(1);
+}
+
+
+/*
+ * collect_arguments() - local argument checking and collection
+ */
+static SETTINGS *
+collect_arguments( RULE* rule, LOL* all_actual )
+{
+ SETTINGS *locals = 0;
+
+ LOL *all_formal = rule->arguments ? rule->arguments->data : 0;
+ if ( all_formal ) /* Nothing to set; nothing to check */
+ {
+ int max = all_formal->count > all_actual->count
+ ? all_formal->count
+ : all_actual->count;
+
+ int n;
+ for ( n = 0; n < max ; ++n )
+ {
+ LIST *formal = lol_get( all_formal, n );
+ LIST *actual = lol_get( all_actual, n );
+ while ( formal )
+ {
+ char* name = formal->string;
+ char modifier = 0;
+ LIST* value = 0;
+ if ( formal->next )
+ {
+ char *next = formal->next->string;
+ if ( next && next[0] != 0 && next[1] == 0 )
+ modifier = next[0];
+ }
+
+ if ( !actual && modifier != '?' && modifier != '*' )
+ {
+ argument_error( "missing argument", rule, all_actual, formal );
+ }
+
+ switch ( modifier )
+ {
+ case '+':
+ case '*':
+ value = list_copy( 0, actual );
+ actual = 0;
+ /* skip an extra element for the modifier */
+ formal = formal->next;
+ break;
+ case '?':
+ /* skip an extra element for the modifier */
+ formal = formal->next;
+ /* fall through */
+ default:
+ if ( actual ) /* in case actual is missing */
+ {
+ value = list_new( 0, actual->string );
+ actual = actual->next;
+ }
+ }
+
+ locals = addsettings( locals, 0, name, value );
+ formal = formal->next;
+ }
+
+ if ( actual )
+ {
+ argument_error( "extra argument", rule, all_actual, actual );
+ }
+ }
+ }
+ return locals;
+}
+
+struct profile_info
+{
+ char* name; /* name of rule being called */
+ clock_t cumulative; /* cumulative time spent in rule */
+ clock_t subrules; /* time spent in subrules */
+ unsigned long num_entries; /* number of time rule was entered */
+};
+typedef struct profile_info profile_info;
+
+struct profile_frame
+{
+ profile_info* info; /* permanent storage where data accumulates */
+ clock_t overhead; /* overhead for profiling in this call */
+ clock_t entry_time; /* time of last entry to rule */
+ struct profile_frame* caller; /* stack frame of caller */
+};
+typedef struct profile_frame profile_frame;
+
+static profile_frame* profile_stack = 0;
+static struct hash* profile_hash = 0;
+
+static void profile_enter( char* rulename, profile_frame* frame )
+{
+ clock_t start = clock();
+ profile_info info, *p = &info;
+
+ if ( !profile_hash )
+ profile_hash = hashinit(sizeof(profile_info), "profile");
+
+ info.name = rulename;
+
+ if ( hashenter( profile_hash, (HASHDATA **)&p ) )
+ p->cumulative = p->subrules = p->num_entries = 0;
+
+ ++(p->num_entries);
+
+ frame->info = p;
+
+ frame->caller = profile_stack;
+ profile_stack = frame;
+
+ frame->entry_time = clock();
+ frame->overhead = 0;
+
+ /* caller pays for the time it takes to play with the hash table */
+ if ( frame->caller )
+ frame->caller->overhead += frame->entry_time - start;
+}
+
+static void profile_exit(profile_frame* frame)
+{
+ /* cumulative time for this call */
+ clock_t t = clock() - frame->entry_time - frame->overhead;
+ frame->info->cumulative += t;
+
+ if (frame->caller)
+ {
+ /* caller's cumulative time must account for this overhead */
+ frame->caller->overhead += frame->overhead;
+ frame->caller->info->subrules += t;
+ }
+ /* pop this stack frame */
+ profile_stack = frame->caller;
+}
+
+static void dump_profile_entry(void* p_, void* ignored)
+{
+ profile_info* p = p_;
+ clock_t total = p->cumulative;
+ printf("%10d %10d %10d %s\n", total, total - p->subrules, p->num_entries, p->name);
+}
+
+void profile_dump()
+{
+ if ( profile_hash )
+ {
+ printf("%10s %10s %10s %s\n", "gross", "net", "# entries", "name");
+ hashenumerate( profile_hash, dump_profile_entry, 0 );
+ }
+}
+
+/*
+ * evaluate_rule() - execute a rule invocation
+ */
+
+LIST *
+evaluate_rule(
+ char *rulename,
+ FRAME *frame )
+{
+ LIST *result = L0;
+ RULE *rule;
+ profile_frame prof[1];
+ module *prev_module = frame->module;
+
+ LIST* l = var_expand( L0, rulename, rulename+strlen(rulename), frame->args, 0 );
+
+ if ( !l )
+ {
+ printf( "warning: rulename %s expands to empty string\n", rulename );
+ return result;
+ }
+
+ if ( DEBUG_COMPILE )
+ {
+ debug_compile( 1, l->string );
+ lol_print( frame->args );
+ printf( "\n" );
+ }
+ rulename = l->string;
+ rule = bindrule( l->string, frame->module );
+
+ if ( rule->procedure && rule->procedure->module != prev_module )
+ {
+ /* propagate current module to nested rule invocations */
+ frame->module = rule->procedure->module;
+
+ /* swap variables */
+ exit_module( prev_module );
+ enter_module( rule->procedure->module );
+ }
+
+ list_free( l );
+
+ if ( DEBUG_PROFILE && rule->procedure )
+ profile_enter( rule->procedure->rulename, prof );
+
+ /* Check traditional targets $(<) and sources $(>) */
+
+ if( !rule->actions && !rule->procedure )
+ printf( "warning: unknown rule %s\n", rule->name );
+
+ /* If this rule will be executed for updating the targets */
+ /* then construct the action for make(). */
+
+ if( rule->actions )
+ {
+ TARGETS *t;
+ ACTION *action;
+
+ /* The action is associated with this instance of this rule */
+
+ action = (ACTION *)malloc( sizeof( ACTION ) );
+ memset( (char *)action, '\0', sizeof( *action ) );
+
+ action->rule = rule;
+ action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) );
+ action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) );
+
+ /* Append this action to the actions of each target */
+
+ for( t = action->targets; t; t = t->next )
+ t->target->actions = actionlist( t->target->actions, action );
+ }
+
+ /* Now recursively compile any parse tree associated with this rule */
+ /* refer/free to ensure rule not freed during use */
+
+ if( rule->procedure )
+ {
+ SETTINGS *local_args = collect_arguments( rule, frame->args );
+ PARSE *parse = rule->procedure;
+ parse_refer( parse );
+
+ pushsettings( local_args );
+ result = (*parse->func)( parse, frame );
+ popsettings( local_args );
+
+ parse_free( parse );
+ }
+
+ if ( frame->module != prev_module )
+ {
+ exit_module( frame->module );
+ enter_module( prev_module );
+ }
+
+ if ( DEBUG_PROFILE && rule->procedure )
+ profile_exit( prof );
+
+ if( DEBUG_COMPILE )
+ debug_compile( -1, 0 );
+
+ return result;
+}
+
+/*
+ * compile_rules() - compile a chain of rules
+ *
+ * parse->left more compile_rules() by left-recursion
+ * parse->right single rule
+ */
+
+LIST *
+compile_rules(
+ PARSE *parse,
+ FRAME *frame )
+{
+ /* Ignore result from first statement; return the 2nd. */
+
+ list_free( (*parse->left->func)( parse->left, frame ) );
+ return (*parse->right->func)( parse->right, frame );
+}
+
+/*
+ * compile_set() - compile the "set variable" statement
+ *
+ * parse->left variable names
+ * parse->right variable values
+ * parse->num ASSIGN_SET/APPEND/DEFAULT
+ */
+
+LIST *
+compile_set(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+ LIST *l;
+ int setflag;
+ char *trace;
+
+ switch( parse->num )
+ {
+ case ASSIGN_SET: setflag = VAR_SET; trace = "="; break;
+ case ASSIGN_APPEND: setflag = VAR_APPEND; trace = "+="; break;
+ case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break;
+ default: setflag = VAR_SET; trace = ""; break;
+ }
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "set" );
+ list_print( nt );
+ printf( " %s ", trace );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Call var_set to set variable */
+ /* var_set keeps ns, so need to copy it */
+
+ for( l = nt; l; l = list_next( l ) )
+ var_set( l->string, list_copy( L0, ns ), setflag );
+
+ list_free( nt );
+
+ return ns;
+}
+
+/*
+ * compile_set_module() - compile the "module local set variable" statement
+ *
+ * parse->left variable names
+ * parse->right variable values
+ */
+LIST *
+compile_set_module(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->right->func)( parse->right, frame );
+ LIST *l;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "set module" );
+ printf( "(%s)", frame->module->name );
+ list_print( nt );
+ printf( " = " );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Call var_set to set variable */
+ /* var_set keeps ns, so need to copy it */
+
+ for( l = nt; l; l = list_next( l ) )
+ {
+ bind_module_var( frame->module, l->string );
+ var_set( l->string, list_copy( L0, ns ), VAR_SET );
+ }
+
+ list_free( nt );
+
+ return ns;
+}
+
+
+/*
+ * compile_setcomp() - support for `rule` - save parse tree
+ *
+ * parse->string rule name
+ * parse->left rules for rule
+ * parse->right optional list-of-lists describing arguments
+ */
+
+LIST *
+compile_setcomp(
+ PARSE *parse,
+ FRAME *frame)
+{
+ argument_list* arg_list = 0;
+
+ /* Create new LOL describing argument requirements if supplied */
+ if ( parse->right )
+ {
+ PARSE *p;
+ arg_list = args_new();
+ for( p = parse->right; p; p = p->left )
+ lol_add( arg_list->data, (*p->right->func)( p->right, frame ) );
+ }
+
+ new_rule_body( frame->module, parse->string, arg_list, parse->left );
+ return L0;
+}
+
+/*
+ * compile_setexec() - support for `actions` - save execution string
+ *
+ * parse->string rule name
+ * parse->string1 OS command string
+ * parse->num flags
+ * parse->left `bind` variables
+ *
+ * Note that the parse flags (as defined in compile.h) are transfered
+ * directly to the rule flags (as defined in rules.h).
+ */
+
+LIST *
+compile_setexec(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST* bindlist = (*parse->left->func)( parse->left, frame );
+
+ new_rule_actions( frame->module, parse->string, parse->string1, bindlist, parse->num );
+
+ return L0;
+}
+
+/*
+ * compile_settings() - compile the "on =" (set variable on exec) statement
+ *
+ * parse->left variable names
+ * parse->right target name
+ * parse->third variable value
+ * parse->num ASSIGN_SET/APPEND
+ */
+
+LIST *
+compile_settings(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *ns = (*parse->third->func)( parse->third, frame );
+ LIST *targets = (*parse->right->func)( parse->right, frame );
+ LIST *ts;
+ int append = parse->num == ASSIGN_APPEND;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "set" );
+ list_print( nt );
+ printf( "on " );
+ list_print( targets );
+ printf( " %s ", append ? "+=" : "=" );
+ list_print( ns );
+ printf( "\n" );
+ }
+
+ /* Call addsettings to save variable setting */
+ /* addsettings keeps ns, so need to copy it */
+ /* Pass append flag to addsettings() */
+
+ for( ts = targets; ts; ts = list_next( ts ) )
+ {
+ TARGET *t = bindtarget( ts->string );
+ LIST *l;
+
+ for( l = nt; l; l = list_next( l ) )
+ t->settings = addsettings( t->settings, append,
+ l->string, list_copy( (LIST*)0, ns ) );
+ }
+
+ list_free( nt );
+ list_free( targets );
+
+ return ns;
+}
+
+/*
+ * compile_switch() - compile 'switch' rule
+ *
+ * parse->left switch value (only 1st used)
+ * parse->right cases
+ *
+ * cases->left 1st case
+ * cases->right next cases
+ *
+ * case->string argument to match
+ * case->left parse tree to execute
+ */
+
+LIST *
+compile_switch(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *nt = (*parse->left->func)( parse->left, frame );
+ LIST *result = 0;
+
+ if( DEBUG_COMPILE )
+ {
+ debug_compile( 0, "switch" );
+ list_print( nt );
+ printf( "\n" );
+ }
+
+ /* Step through cases */
+
+ for( parse = parse->right; parse; parse = parse->right )
+ {
+ if( !glob( parse->left->string, nt ? nt->string : "" ) )
+ {
+ /* Get & exec parse tree for this case */
+ parse = parse->left->left;
+ result = (*parse->func)( parse, frame );
+ break;
+ }
+ }
+
+ list_free( nt );
+
+ return result;
+}
+
+
+
+/*
+ * builtin_depends() - DEPENDS/INCLUDES rule
+ *
+ * The DEPENDS builtin rule appends each of the listed sources on the
+ * dependency list of each of the listed targets. It binds both the
+ * targets and sources as TARGETs.
+ */
+
+static LIST *
+builtin_depends(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *targets = lol_get( frame->args, 0 );
+ LIST *sources = lol_get( frame->args, 1 );
+ int which = parse->num;
+ LIST *l;
+
+ for( l = targets; l; l = list_next( l ) )
+ {
+ TARGET *t = bindtarget( l->string );
+ t->deps[ which ] = targetlist( t->deps[ which ], sources );
+ }
+
+ return L0;
+}
+
+/*
+ * builtin_echo() - ECHO rule
+ *
+ * The ECHO builtin rule echoes the targets to the user. No other
+ * actions are taken.
+ */
+
+static LIST *
+builtin_echo(
+ PARSE *parse,
+ FRAME *frame )
+{
+ list_print( lol_get( frame->args, 0 ) );
+ printf( "\n" );
+ return L0;
+}
+
+/*
+ * builtin_exit() - EXIT rule
+ *
+ * The EXIT builtin rule echoes the targets to the user and exits
+ * the program with a failure status.
+ */
+
+static LIST *
+builtin_exit(
+ PARSE *parse,
+ FRAME *frame )
+{
+ list_print( lol_get( frame->args, 0 ) );
+ printf( "\n" );
+ exit( EXITBAD ); /* yeech */
+ return L0;
+}
+
+/*
+ * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
+ *
+ * Builtin_flags() marks the target with the appropriate flag, for use
+ * by make0(). It binds each target as a TARGET.
+ */
+
+static LIST *
+builtin_flags(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *l = lol_get( frame->args, 0 );
+
+ for( ; l; l = list_next( l ) )
+ bindtarget( l->string )->flags |= parse->num;
+
+ return L0;
+}
+
+
+static LIST *
+builtin_hdrmacro(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST* l = lol_get( frame->args, 0 );
+
+ for ( ; l; l = list_next(l) )
+ {
+ TARGET* t = bindtarget( l->string );
+
+ /* scan file for header filename macro definitions */
+ if ( DEBUG_HEADER )
+ printf( "scanning '%s' for header file macro definitions\n",
+ l->string );
+
+ macro_headers( t );
+ }
+
+ return L0;
+}
+
+
+/*
+ * builtin_import() - IMPORT ( TARGET_MODULE ? : SOURCE_MODULE ? : RULE_NAMES * : TARGET_NAMES * )
+ *
+ * The IMPORT rule imports rules from the SOURCE_MODULE into the
+ * TARGET_MODULE. If either SOURCE_MODULE or TARGET_MODULE is not supplied, it
+ * refers to the root module. If any RULE_NAMES are supplied, they specify which
+ * rules from the SOURCE_MODULE to import, otherwise all rules are imported. The
+ * rules are given the names in TARGET_NAMES; if not enough TARGET_NAMES are
+ * supplied, the excess rules are given the names in RULE_NAMES. If RULE_NAMES
+ * is not supplied, TARGET_NAMES is ignored.
+ */
+
+struct import_data
+{
+ module* target_module;
+ LIST* target_names;
+};
+typedef struct import_data import_data;
+
+static void import_rule1( void* r_, void* data_ )
+{
+ RULE* r = r_;
+ import_data* data = data_;
+
+ char* target_name = data->target_names ? data->target_names->string : r->name;
+ if (data->target_names)
+ data->target_names = list_next(data->target_names);
+
+ import_rule( r, data->target_module, target_name );
+}
+
+static LIST *
+builtin_import(
+ PARSE *parse,
+ FRAME *frame )
+{
+ LIST *target_module_name = lol_get( frame->args, 0 );
+ LIST *source_module_name = lol_get( frame->args, 1 );
+ LIST *rule_names = lol_get( frame->args, 2 );
+ LIST *target_names = lol_get( frame->args, 3 );
+
+ module* target_module = bindmodule( target_module_name ? target_module_name->string : 0 );
+ module* source_module = bindmodule( source_module_name ? source_module_name->string : 0 );
+
+ if ( rule_names == 0 )
+ {
+ import_data data;
+ data.target_module = target_module;
+ data.target_names = target_names;
+ hashenumerate( source_module->rules, import_rule1, &data );
+ }
+ else
+ {
+ LIST *old_name, *target_name;
+
+ for ( old_name = rule_names, target_name = target_names;
+ old_name;
+ old_name = list_next( old_name )
+ , target_name = list_next( target_name ) )
+ {
+ RULE r_, *r = &r_;
+ r_.name = old_name->string;
+
+ if ( !target_name )
+ target_name = old_name;
+
+ if ( hashcheck( source_module->rules, (HASHDATA**)&r ) )
+ {
+ import_rule( r, target_module, target_name->string );
+ }
+ }
+ }
+
+ return L0;
+}
+
+/*
+ * builtin_caller_module() - CALLER_MODULE ( )
+ *
+ * Returns the name of the module of the rule which called the one calling this
+ * one, or, if no such module exists, returns the empty list. Also returns the
+ * empty list when the module in question is the global module. This rule is
+ * needed for implementing module import behavior.
+ */
+static LIST *builtin_caller_module( PARSE *parse, FRAME *frame )
+{
+ char buffer[4096] = "";
+ int len;
+
+ int i;
+ for (i = 0; i < 2 && frame->prev; ++i)
+ frame = frame->prev;
+
+ if ( frame->module == root_module() )
+ {
+ return L0;
+ }
+ else
+ {
+ LIST* result;
+
+ string name;
+ string_copy( &name, frame->module->name );
+ string_pop_back( &name );
+
+ result = list_new( L0, newstr(name.value) );
+
+ string_free( &name );
+
+ return result;
+ }
+}
+
+/*
+ * debug_compile() - printf with indent to show rule expansion.
+ */
+
+static void
+debug_compile( int which, char *s )
+{
+ static int level = 0;
+ static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
+
+ if ( which >= 0 )
+ {
+ int i;
+
+ i = (level+1)*2;
+ while ( i > 35 )
+ {
+ printf( indent );
+ i -= 35;
+ }
+ printf( "%*.*s ", i, i, indent );
+ }
+
+ if( s )
+ printf( "%s ", s );
+
+ level += which;
+}
diff --git a/jam_src/compile.h b/jam_src/compile.h
new file mode 100644
index 000000000..e18cd16cd
--- /dev/null
+++ b/jam_src/compile.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+#ifndef COMPILE_DWA20011022_H
+# define COMPILE_DWA20011022_H
+
+# include "frames.h"
+# include "parse.h"
+# include "regexp.h"
+
+/*
+ * compile.h - compile parsed jam statements
+ */
+
+void compile_builtins();
+
+LIST *compile_append( PARSE *parse, FRAME *frame );
+LIST *compile_foreach( PARSE *parse, FRAME *frame );
+LIST *compile_if( PARSE *parse, FRAME *frame );
+LIST *compile_include( PARSE *parse, FRAME *frame );
+LIST *compile_list( PARSE *parse, FRAME *frame );
+LIST *compile_local( PARSE *parse, FRAME *frame );
+LIST *compile_module( PARSE *parse, FRAME *frame );
+LIST *compile_null( PARSE *parse, FRAME *frame );
+LIST *compile_rule( PARSE *parse, FRAME *frame );
+LIST *compile_rules( PARSE *parse, FRAME *frame );
+LIST *compile_set( PARSE *parse, FRAME *frame );
+LIST *compile_set_module( PARSE *parse, FRAME *frame );
+LIST *compile_setcomp( PARSE *parse, FRAME *frame );
+LIST *compile_setexec( PARSE *parse, FRAME *frame );
+LIST *compile_settings( PARSE *parse, FRAME *frame );
+LIST *compile_switch( PARSE *parse, FRAME *frame );
+LIST *compile_while( PARSE *parse, FRAME *frame );
+
+LIST *evaluate_rule( char *rulename, FRAME *frame );
+
+regexp* regex_compile( const char* pattern );
+
+void profile_dump();
+
+/* Flags for compile_set(), etc */
+
+# define ASSIGN_SET 0x00 /* = assign variable */
+# define ASSIGN_APPEND 0x01 /* += append variable */
+# define ASSIGN_DEFAULT 0x02 /* set only if unset */
+
+/* Flags for compile_setexec() */
+
+# define EXEC_UPDATED 0x01 /* executes updated */
+# define EXEC_TOGETHER 0x02 /* executes together */
+# define EXEC_IGNORE 0x04 /* executes ignore */
+# define EXEC_QUIETLY 0x08 /* executes quietly */
+# define EXEC_PIECEMEAL 0x10 /* executes piecemeal */
+# define EXEC_EXISTING 0x20 /* executes existing */
+
+/* Conditions for compile_if() */
+
+# define COND_NOT 0 /* ! cond */
+# define COND_AND 1 /* cond && cond */
+# define COND_OR 2 /* cond || cond */
+
+# define COND_EXISTS 3 /* arg */
+# define COND_EQUALS 4 /* arg = arg */
+# define COND_NOTEQ 5 /* arg != arg */
+# define COND_LESS 6 /* arg < arg */
+# define COND_LESSEQ 7 /* arg <= arg */
+# define COND_MORE 8 /* arg > arg */
+# define COND_MOREEQ 9 /* arg >= arg */
+# define COND_IN 10 /* arg in arg */
+
+#endif // COMPILE_DWA20011022_H
diff --git a/jam_src/debugjam0.bat b/jam_src/debugjam0.bat
new file mode 100755
index 000000000..d38e10bd0
--- /dev/null
+++ b/jam_src/debugjam0.bat
@@ -0,0 +1,10 @@
+bash .\yyacc jamgram.y jamgramtab.h jamgram.yy
+set VISUALC=c:\tools\msvc6\vc98
+set JAM_TOOLSET=VISUALC
+set YACC="bison -t -d -l -v --debug --yacc"
+set YACCFILES=y.tab
+set CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd"
+set LINKLIBS="%VISUALC%\lib\advapi32.lib %VISUALC%\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib %VISUALC%\lib\user32.lib %VISUALC%\lib\kernel32.lib"
+set LINKFLAGS="/DEBUG"
+rm -rf bin.ntx86
+jam0 %*
diff --git a/jam_src/debugjam0.sh b/jam_src/debugjam0.sh
new file mode 100644
index 000000000..930499528
--- /dev/null
+++ b/jam_src/debugjam0.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+# This script can be used to recover from aborted builds in which Jam has
+# removed some of its products (e.g. jamgramtab.h) upon failing some action
+./yyacc jamgram.y jamgramtab.h jamgram.yy
+export VISUALC=c:\tools\msvc6\vc98
+export JAM_TOOLSET=VISUALC
+jam0 -sCCFLAGS="/GZ /Zi /MLd" -sYACC="bison -t -d -l -v --yacc" -sLINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" -sLINKFLAGS="/DEBUG"
diff --git a/jam_src/execcmd.h b/jam_src/execcmd.h
new file mode 100644
index 000000000..1e7a60835
--- /dev/null
+++ b/jam_src/execcmd.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * execcmd.h - execute a shell script
+ *
+ * 05/04/94 (seiwald) - async multiprocess interface
+ */
+
+void execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell );
+
+int execwait();
+
+# define EXEC_CMD_OK 0
+# define EXEC_CMD_FAIL 1
+# define EXEC_CMD_INTR 2
diff --git a/jam_src/execmac.c b/jam_src/execmac.c
new file mode 100644
index 000000000..20217dab1
--- /dev/null
+++ b/jam_src/execmac.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+# include
+
+# ifdef OS_MAC
+
+/*
+ * execunix.c - execute a shell script on UNIX
+ *
+ * If $(JAMSHELL) is defined, uses that to formulate execvp().
+ * The default is:
+ *
+ * /bin/sh -c %
+ *
+ * Each word must be an individual element in a jam variable value.
+ *
+ * In $(JAMSHELL), % expands to the command string and ! expands to
+ * the slot number (starting at 1) for multiprocess (-j) invocations.
+ * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
+ * argument.
+ *
+ * Don't just set JAMSHELL to /bin/sh - it won't work!
+ *
+ * External routines:
+ * execcmd() - launch an async command execution
+ * execwait() - wait and drive at most one execution completion
+ *
+ * Internal routines:
+ * onintr() - bump intr to note command interruption
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 05/04/94 (seiwald) - async multiprocess interface
+ * 01/22/95 (seiwald) - $(JAMSHELL) support
+ */
+
+/*
+ * execcmd() - launch an async command execution
+ */
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+
+ printf( "%s", string );
+ (*func)( closure, EXEC_CMD_OK );
+}
+
+/*
+ * execwait() - wait and drive at most one execution completion
+ */
+
+int
+execwait()
+{
+ return 0;
+}
+
+# endif /* OS_MAC */
diff --git a/jam_src/execnt.c b/jam_src/execnt.c
new file mode 100644
index 000000000..3ddc67b62
--- /dev/null
+++ b/jam_src/execnt.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+# include
+
+# ifdef USE_EXECNT
+
+# define WIN32_LEAN_AND_MEAN
+# include /* do the ugly deed */
+# include
+
+# if !defined( __BORLANDC__ ) && !defined( OS_OS2 )
+# define wait my_wait
+static int my_wait( int *status );
+# endif
+
+/*
+ * execnt.c - execute a shell command on Windows NT and Windows 95/98
+ *
+ * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
+ * The default is:
+ *
+ * /bin/sh -c % [ on UNIX/AmigaOS ]
+ * cmd.exe /c % [ on Windows NT ]
+ *
+ * Each word must be an individual element in a jam variable value.
+ *
+ * In $(JAMSHELL), % expands to the command string and ! expands to
+ * the slot number (starting at 1) for multiprocess (-j) invocations.
+ * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
+ * argument.
+ *
+ * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
+ *
+ * External routines:
+ * execcmd() - launch an async command execution
+ * execwait() - wait and drive at most one execution completion
+ *
+ * Internal routines:
+ * onintr() - bump intr to note command interruption
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 05/04/94 (seiwald) - async multiprocess interface
+ * 01/22/95 (seiwald) - $(JAMSHELL) support
+ * 06/02/97 (gsar) - full async multiprocess support for Win32
+ */
+
+static int intr = 0;
+static int cmdsrunning = 0;
+static void (*istat)( int );
+
+static int is_nt_351 = 0;
+static int is_win95 = 1;
+static int is_win95_defined = 0;
+
+
+static struct
+{
+ int pid; /* on win32, a real process handle */
+ void (*func)( void *closure, int status );
+ void *closure;
+ char *tempfile;
+
+} cmdtab[ MAXJOBS ] = {{0}};
+
+
+static void
+set_is_win95( void )
+{
+ OSVERSIONINFO os_info;
+
+ os_info.dwOSVersionInfoSize = sizeof(os_info);
+ os_info.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
+ GetVersionEx( &os_info );
+
+ is_win95 = (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+ is_win95_defined = 1;
+
+ /* now, test wether we're running Windows 3.51 */
+ /* this is later used to limit the system call command length */
+ if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ is_nt_351 = os_info.dwMajorVersion == 3;
+}
+
+
+static char**
+string_to_args( const char* string, int* pcount )
+{
+ int total = strlen( string );
+ int in_quote = 0,
+ num_args = 0; /* was uninitialized -- dwa */
+ char* line;
+ char* p;
+ char** arg;
+ char** args;
+
+ *pcount = 0;
+
+ /* do not copy trailing newlines, if any */
+ {
+ int i;
+
+ for ( i = total-1; i > 0; i-- )
+ {
+ if ( string[i] != '\n' && string[i] != '\r' )
+ break;
+ total --;
+ }
+ }
+
+ /* first of all, copy the input string */
+ line = (char*)malloc( total+2 );
+ if (!line)
+ return 0;
+
+ memcpy( line+1, string, total );
+ line[0] = 0;
+ line[total+1] = 0;
+
+ in_quote = 0;
+ for ( p = line+1; p[0]; p++ )
+ {
+ switch (p[0])
+ {
+ case '"':
+ in_quote = !in_quote;
+ break;
+
+ case ' ':
+ case '\t':
+ if (!in_quote)
+ p[0] = 0;
+
+ default:
+ ;
+ }
+ }
+
+ /* now count the arguments.. */
+ for ( p = line; p < line+total+1; p++ )
+ if ( !p[0] && p[1] )
+ num_args++;
+
+ /* allocate the args array */
+ /* dwa -- did you really mean to allocate only 2 additional bytes? */
+#if 0 /* was like this */
+ args = (char**)malloc( num_args*sizeof(char*)+2 );
+#endif
+ args = (char**)malloc( (num_args + 2) * sizeof(char*) );
+ if (!args)
+ {
+ free( line );
+ return 0;
+ }
+
+ arg = args+1;
+ for ( p = line; p < line+total+1; p++ )
+ if ( !p[0] && p[1] )
+ {
+ arg[0] = p+1;
+ arg++;
+ }
+ arg[0] = 0;
+ *pcount = num_args;
+ args[0] = line;
+ return args+1;
+}
+
+static void
+free_args( char** args )
+{
+ free( args[-1] );
+ free( args-1 );
+}
+
+
+/* process a "del" or "erase" command under Windows 95/98 */
+static int
+process_del( char* command )
+{
+ char** arg;
+ char* p = command, *q;
+ int wildcard = 0, result = 0;
+
+ /* first of all, skip the command itself */
+ if ( p[0] == 'd' )
+ p += 3; /* assumes "del..;" */
+ else if ( p[0] == 'e' )
+ p += 5; /* assumes "erase.." */
+ else
+ return 1; /* invalid command */
+
+ /* process all targets independently */
+ for (;;)
+ {
+ /* skip leading spaces */
+ while ( *p && isspace(*p) )
+ p++;
+
+ /* exit if we encounter an end of string */
+ if (!*p)
+ return 0;
+
+ /* ignore toggles/flags */
+ if (*p == '/')
+ {
+ p++;
+ while ( *p && isalnum(*p) )
+ p++;
+ }
+ else
+ {
+ int in_quote = 0;
+ int wildcard = 0;
+ int go_on = 1;
+
+ q = p;
+ while (go_on)
+ {
+ switch (*p)
+ {
+ case '"':
+ in_quote = !in_quote;
+ break;
+
+ case '?':
+ case '*':
+ if (!in_quote)
+ wildcard = 1;
+ break;
+
+ case '\0':
+ if (in_quote)
+ return 1;
+ /* fall-through */
+
+ case ' ':
+ case '\t':
+ if (!in_quote)
+ {
+ int len = p - q;
+ int result;
+ char* line;
+
+ /* q..p-1 contains the delete argument */
+ if ( len <= 0 )
+ return 1;
+
+ line = (char*)malloc( len+4+1 );
+ if (!line)
+ return 1;
+
+ strncpy( line, "del ", 4 );
+ strncpy( line+4, q, len );
+ line[len+4] = '\0';
+
+ if ( wildcard )
+ result = system( line );
+ else
+ result = !DeleteFile( line+4 );
+
+ free( line );
+ if (result)
+ return 1;
+
+ go_on = 0;
+ }
+
+ default:
+ ;
+ }
+ p++;
+ } /* while (go_on) */
+ }
+ }
+}
+
+
+/*
+ * onintr() - bump intr to note command interruption
+ */
+
+void
+onintr( int disp )
+{
+ intr++;
+ printf( "...interrupted\n" );
+}
+
+/*
+ * execcmd() - launch an async command execution
+ */
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+ int pid;
+ int slot;
+ int max_line;
+ int raw_cmd = 0 ;
+ char *argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
+ char **argv = argv_static;
+ char *p;
+
+ /* Check to see if we need to hack around the line-length limitation. */
+ /* Look for a JAMSHELL setting of "%", indicating that the command
+ * should be invoked directly */
+ if ( shell && !strcmp(shell->string,"%") && !list_next(shell) )
+ {
+ raw_cmd = 1;
+ shell = 0;
+ }
+
+ if ( !is_win95_defined )
+ set_is_win95();
+
+ /* Find a slot in the running commands table for this one. */
+ if ( is_win95 )
+ {
+ /* only synchronous spans are supported on Windows 95/98 */
+ slot = 0;
+ }
+ else
+ {
+ for( slot = 0; slot < MAXJOBS; slot++ )
+ if( !cmdtab[ slot ].pid )
+ break;
+ }
+ if( slot == MAXJOBS )
+ {
+ printf( "no slots for child!\n" );
+ exit( EXITBAD );
+ }
+
+ if( !cmdtab[ slot ].tempfile )
+ {
+ char *tempdir;
+
+ if( !( tempdir = getenv( "TEMP" ) ) &&
+ !( tempdir = getenv( "TMP" ) ) )
+ tempdir = "\\temp";
+
+ cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 14 );
+
+ sprintf( cmdtab[ slot ].tempfile, "%s\\jamtmp%02d.bat",
+ tempdir, slot );
+ }
+
+ /* Trim leading, ending white space */
+
+ while( isspace( *string ) )
+ ++string;
+
+ p = strchr( string, '\n' );
+
+ while( p && isspace( *p ) )
+ ++p;
+
+ /* on Windows NT 3.51, the maximul line length is 996 bytes !! */
+ /* while it's much bigger NT 4 and 2k */
+ max_line = is_nt_351 ? 996 : MAXLINE;
+
+ /* If multi line, or too long, or JAMSHELL is set, write to bat file. */
+ /* Otherwise, exec directly. */
+ /* Frankly, if it is a single long line I don't think the */
+ /* command interpreter will do any better -- it will fail. */
+
+ if( p && *p || !raw_cmd && strlen( string ) > max_line || shell )
+ {
+ FILE *f;
+
+ /* Write command to bat file. */
+
+ f = fopen( cmdtab[ slot ].tempfile, "w" );
+ fputs( string, f );
+ fclose( f );
+
+ string = cmdtab[ slot ].tempfile;
+ }
+
+ /* Forumulate argv */
+ /* If shell was defined, be prepared for % and ! subs. */
+ /* Otherwise, use stock /bin/sh (on unix) or cmd.exe (on NT). */
+
+ if( shell )
+ {
+ int i;
+ char jobno[4];
+ int gotpercent = 0;
+
+ sprintf( jobno, "%d", slot + 1 );
+
+ for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
+ {
+ switch( shell->string[0] )
+ {
+ case '%': argv[i] = string; gotpercent++; break;
+ case '!': argv[i] = jobno; break;
+ default: argv[i] = shell->string;
+ }
+ if( DEBUG_EXECCMD )
+ printf( "argv[%d] = '%s'\n", i, argv[i] );
+ }
+
+ if( !gotpercent )
+ argv[i++] = string;
+
+ argv[i] = 0;
+ }
+ else if (raw_cmd)
+ {
+ int ignored;
+ argv = string_to_args(string, &ignored);
+ }
+ else
+ {
+ /* don't worry, this is ignored on Win95/98, see later.. */
+ argv[0] = "cmd.exe";
+ argv[1] = "/Q/C"; /* anything more is non-portable */
+ argv[2] = string;
+ argv[3] = 0;
+ }
+
+ /* Catch interrupts whenever commands are running. */
+
+ if( !cmdsrunning++ )
+ istat = signal( SIGINT, onintr );
+
+ /* Start the command */
+
+ /* on Win95, we only do a synchronous call */
+ if ( is_win95 )
+ {
+ static const char* hard_coded[] =
+ {
+ "del", "erase", "copy", "mkdir", "rmdir", "cls", "dir",
+ "ren", "rename", "move", 0
+ };
+
+ const char** keyword;
+ int len, spawn = 1;
+ int result;
+
+ for ( keyword = hard_coded; keyword[0]; keyword++ )
+ {
+ len = strlen( keyword[0] );
+ if ( strnicmp( string, keyword[0], len ) == 0 &&
+ !isalnum(string[len]) )
+ {
+ /* this is one of the hard coded symbols, use 'system' to run */
+ /* them.. except for "del"/"erase" */
+ if ( keyword - hard_coded < 2 )
+ result = process_del( string );
+ else
+ result = system( string );
+
+ spawn = 0;
+ break;
+ }
+ }
+
+ if (spawn)
+ {
+ char** args;
+ int num_args;
+
+ /* convert the string into an array of arguments */
+ /* we need to take care of double quotes !! */
+ args = string_to_args( string, &num_args );
+ if ( args )
+ {
+#if 0
+ char** arg;
+ fprintf( stderr, "%s: ", args[0] );
+ arg = args+1;
+ while ( arg[0] )
+ {
+ fprintf( stderr, " {%s}", arg[0] );
+ arg++;
+ }
+ fprintf( stderr, "\n" );
+#endif
+ result = spawnvp( P_WAIT, args[0], args );
+ free_args( args );
+ }
+ else
+ result = 1;
+ }
+ func( closure, result ? EXEC_CMD_FAIL : EXEC_CMD_OK );
+ return;
+ }
+
+ /* the rest is for Windows NT only */
+ if( ( pid = spawnvp( P_NOWAIT, argv[0], argv ) ) == -1 )
+ {
+ perror( "spawn" );
+ exit( EXITBAD );
+ }
+ /* Save the operation for execwait() to find. */
+
+ cmdtab[ slot ].pid = pid;
+ cmdtab[ slot ].func = func;
+ cmdtab[ slot ].closure = closure;
+
+ /* Wait until we're under the limit of concurrent commands. */
+ /* Don't trust globs.jobs alone. */
+
+ while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
+ if( !execwait() )
+ break;
+
+ if (argv != argv_static)
+ {
+ free_args(argv);
+ }
+}
+
+/*
+ * execwait() - wait and drive at most one execution completion
+ */
+
+int
+execwait()
+{
+ int i;
+ int status, w;
+ int rstat;
+
+ /* Handle naive make1() which doesn't know if cmds are running. */
+
+ if( !cmdsrunning )
+ return 0;
+
+ if ( is_win95 )
+ return 0;
+
+ /* Pick up process pid and status */
+
+ while( ( w = wait( &status ) ) == -1 && errno == EINTR )
+ ;
+
+ if( w == -1 )
+ {
+ printf( "child process(es) lost!\n" );
+ perror("wait");
+ exit( EXITBAD );
+ }
+
+ /* Find the process in the cmdtab. */
+
+ for( i = 0; i < MAXJOBS; i++ )
+ if( w == cmdtab[ i ].pid )
+ break;
+
+ if( i == MAXJOBS )
+ {
+ printf( "waif child found!\n" );
+ exit( EXITBAD );
+ }
+
+ /* Drive the completion */
+
+ if( !--cmdsrunning )
+ signal( SIGINT, istat );
+
+ if( intr )
+ rstat = EXEC_CMD_INTR;
+ else if( w == -1 || status != 0 )
+ rstat = EXEC_CMD_FAIL;
+ else
+ rstat = EXEC_CMD_OK;
+
+ cmdtab[ i ].pid = 0;
+
+ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat );
+
+ return 1;
+}
+
+# if !defined( __BORLANDC__ )
+
+static int
+my_wait( int *status )
+{
+ int i, num_active = 0;
+ DWORD exitcode, waitcode;
+ static HANDLE *active_handles = 0;
+
+ if (!active_handles)
+ active_handles = (HANDLE *)malloc(globs.jobs * sizeof(HANDLE) );
+
+ /* first see if any non-waited-for processes are dead,
+ * and return if so.
+ */
+ for ( i = 0; i < globs.jobs; i++ ) {
+ if ( cmdtab[i].pid ) {
+ if ( GetExitCodeProcess((HANDLE)cmdtab[i].pid, &exitcode) ) {
+ if ( exitcode == STILL_ACTIVE )
+ active_handles[num_active++] = (HANDLE)cmdtab[i].pid;
+ else {
+ CloseHandle((HANDLE)cmdtab[i].pid);
+ *status = (int)((exitcode & 0xff) << 8);
+ return cmdtab[i].pid;
+ }
+ }
+ else
+ goto FAILED;
+ }
+ }
+
+ /* if a child exists, wait for it to die */
+ if ( !num_active ) {
+ errno = ECHILD;
+ return -1;
+ }
+ waitcode = WaitForMultipleObjects( num_active,
+ active_handles,
+ FALSE,
+ INFINITE );
+ if ( waitcode != WAIT_FAILED ) {
+ if ( waitcode >= WAIT_ABANDONED_0
+ && waitcode < WAIT_ABANDONED_0 + num_active )
+ i = waitcode - WAIT_ABANDONED_0;
+ else
+ i = waitcode - WAIT_OBJECT_0;
+ if ( GetExitCodeProcess(active_handles[i], &exitcode) ) {
+ CloseHandle(active_handles[i]);
+ *status = (int)((exitcode & 0xff) << 8);
+ return (int)active_handles[i];
+ }
+ }
+
+FAILED:
+ errno = GetLastError();
+ return -1;
+
+}
+
+# endif /* !__BORLANDC__ */
+
+# endif /* USE_EXECNT */
diff --git a/jam_src/execunix.c b/jam_src/execunix.c
new file mode 100644
index 000000000..0eb03ca3a
--- /dev/null
+++ b/jam_src/execunix.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+# include
+
+# ifdef USE_EXECUNIX
+
+# ifdef NO_VFORK
+# define vfork() fork()
+# endif
+
+# if defined( OS_NT ) || defined( OS_OS2 )
+
+# define USE_EXECNT
+
+# include
+
+# if !defined( __BORLANDC__ ) && !defined( OS_OS2 )
+# define wait my_wait
+static int my_wait( int *status );
+# endif
+
+# endif
+
+/*
+ * execunix.c - execute a shell script on UNIX/WinNT/OS2/AmigaOS
+ *
+ * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
+ * The default is:
+ *
+ * /bin/sh -c % [ on UNIX/AmigaOS ]
+ * cmd.exe /c % [ on OS2/WinNT ]
+ *
+ * Each word must be an individual element in a jam variable value.
+ *
+ * In $(JAMSHELL), % expands to the command string and ! expands to
+ * the slot number (starting at 1) for multiprocess (-j) invocations.
+ * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
+ * argument.
+ *
+ * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
+ *
+ * External routines:
+ * execcmd() - launch an async command execution
+ * execwait() - wait and drive at most one execution completion
+ *
+ * Internal routines:
+ * onintr() - bump intr to note command interruption
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 05/04/94 (seiwald) - async multiprocess interface
+ * 01/22/95 (seiwald) - $(JAMSHELL) support
+ * 06/02/97 (gsar) - full async multiprocess support for Win32
+ */
+
+static int intr = 0;
+static int cmdsrunning = 0;
+static void (*istat)( int );
+
+static struct
+{
+ int pid; /* on win32, a real process handle */
+ void (*func)( void *closure, int status );
+ void *closure;
+
+# ifdef USE_EXECNT
+ char *tempfile;
+# endif
+
+} cmdtab[ MAXJOBS ] = {{0}};
+
+/*
+ * onintr() - bump intr to note command interruption
+ */
+
+void
+onintr( int disp )
+{
+ intr++;
+ printf( "...interrupted\n" );
+}
+
+/*
+ * execcmd() - launch an async command execution
+ */
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+ int pid;
+ int slot;
+ char *argv[ MAXARGC + 1 ]; /* +1 for NULL */
+
+# ifdef USE_EXECNT
+ char *p;
+# endif
+
+ /* Find a slot in the running commands table for this one. */
+
+ for( slot = 0; slot < MAXJOBS; slot++ )
+ if( !cmdtab[ slot ].pid )
+ break;
+
+ if( slot == MAXJOBS )
+ {
+ printf( "no slots for child!\n" );
+ exit( EXITBAD );
+ }
+
+# ifdef USE_EXECNT
+ if( !cmdtab[ slot ].tempfile )
+ {
+ char *tempdir;
+
+ if( !( tempdir = getenv( "TEMP" ) ) &&
+ !( tempdir = getenv( "TMP" ) ) )
+ tempdir = "\\temp";
+
+ cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 14 );
+
+ sprintf( cmdtab[ slot ].tempfile, "%s\\jamtmp%02d.bat",
+ tempdir, slot );
+ }
+
+ /* Trim leading, ending white space */
+
+ while( isspace( *string ) )
+ ++string;
+
+ p = strchr( string, '\n' );
+
+ while( p && isspace( *p ) )
+ ++p;
+
+ /* If multi line, or too long, or JAMSHELL is set, write to bat file. */
+ /* Otherwise, exec directly. */
+ /* Frankly, if it is a single long line I don't think the */
+ /* command interpreter will do any better -- it will fail. */
+
+ if( p && *p || strlen( string ) > MAXLINE || shell )
+ {
+ FILE *f;
+
+ /* Write command to bat file. */
+
+ f = fopen( cmdtab[ slot ].tempfile, "w" );
+ fputs( string, f );
+ fclose( f );
+
+ string = cmdtab[ slot ].tempfile;
+ }
+# endif
+
+ /* Forumulate argv */
+ /* If shell was defined, be prepared for % and ! subs. */
+ /* Otherwise, use stock /bin/sh (on unix) or cmd.exe (on NT). */
+
+ if( shell )
+ {
+ int i;
+ char jobno[4];
+ int gotpercent = 0;
+
+ sprintf( jobno, "%d", slot + 1 );
+
+ for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
+ {
+ switch( shell->string[0] )
+ {
+ case '%': argv[i] = string; gotpercent++; break;
+ case '!': argv[i] = jobno; break;
+ default: argv[i] = shell->string;
+ }
+ if( DEBUG_EXECCMD )
+ printf( "argv[%d] = '%s'\n", i, argv[i] );
+ }
+
+ if( !gotpercent )
+ argv[i++] = string;
+
+ argv[i] = 0;
+ }
+ else
+ {
+# ifdef USE_EXECNT
+ argv[0] = "cmd.exe";
+ argv[1] = "/Q/C"; /* anything more is non-portable */
+# else
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+# endif
+ argv[2] = string;
+ argv[3] = 0;
+ }
+
+ /* Catch interrupts whenever commands are running. */
+
+ if( !cmdsrunning++ )
+ istat = signal( SIGINT, onintr );
+
+ /* Start the command */
+
+# ifdef USE_EXECNT
+ if( ( pid = spawnvp( P_NOWAIT, argv[0], argv ) ) == -1 )
+ {
+ perror( "spawn" );
+ exit( EXITBAD );
+ }
+# else
+ if ((pid = vfork()) == 0)
+ {
+ execvp( argv[0], argv );
+ _exit(127);
+ }
+
+ if( pid == -1 )
+ {
+ perror( "vfork" );
+ exit( EXITBAD );
+ }
+# endif
+ /* Save the operation for execwait() to find. */
+
+ cmdtab[ slot ].pid = pid;
+ cmdtab[ slot ].func = func;
+ cmdtab[ slot ].closure = closure;
+
+ /* Wait until we're under the limit of concurrent commands. */
+ /* Don't trust globs.jobs alone. */
+
+ while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
+ if( !execwait() )
+ break;
+}
+
+/*
+ * execwait() - wait and drive at most one execution completion
+ */
+
+int
+execwait()
+{
+ int i;
+ int status, w;
+ int rstat;
+
+ /* Handle naive make1() which doesn't know if cmds are running. */
+
+ if( !cmdsrunning )
+ return 0;
+
+ /* Pick up process pid and status */
+
+ while( ( w = wait( &status ) ) == -1 && errno == EINTR )
+ ;
+
+ if( w == -1 )
+ {
+ printf( "child process(es) lost!\n" );
+ perror("wait");
+ exit( EXITBAD );
+ }
+
+ /* Find the process in the cmdtab. */
+
+ for( i = 0; i < MAXJOBS; i++ )
+ if( w == cmdtab[ i ].pid )
+ break;
+
+ if( i == MAXJOBS )
+ {
+ printf( "waif child found!\n" );
+ exit( EXITBAD );
+ }
+
+ /* Drive the completion */
+
+ if( !--cmdsrunning )
+ signal( SIGINT, istat );
+
+ if( intr )
+ rstat = EXEC_CMD_INTR;
+ else if( w == -1 || status != 0 )
+ rstat = EXEC_CMD_FAIL;
+ else
+ rstat = EXEC_CMD_OK;
+
+ cmdtab[ i ].pid = 0;
+
+ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat );
+
+ return 1;
+}
+
+# if defined( OS_NT ) && !defined( __BORLANDC__ )
+
+# define WIN32_LEAN_AND_MEAN
+
+# include /* do the ugly deed */
+
+static int
+my_wait( int *status )
+{
+ int i, num_active = 0;
+ DWORD exitcode, waitcode;
+ static HANDLE *active_handles = 0;
+
+ if (!active_handles)
+ active_handles = (HANDLE *)malloc(globs.jobs * sizeof(HANDLE) );
+
+ /* first see if any non-waited-for processes are dead,
+ * and return if so.
+ */
+ for ( i = 0; i < globs.jobs; i++ ) {
+ if ( cmdtab[i].pid ) {
+ if ( GetExitCodeProcess((HANDLE)cmdtab[i].pid, &exitcode) ) {
+ if ( exitcode == STILL_ACTIVE )
+ active_handles[num_active++] = (HANDLE)cmdtab[i].pid;
+ else {
+ CloseHandle((HANDLE)cmdtab[i].pid);
+ *status = (int)((exitcode & 0xff) << 8);
+ return cmdtab[i].pid;
+ }
+ }
+ else
+ goto FAILED;
+ }
+ }
+
+ /* if a child exists, wait for it to die */
+ if ( !num_active ) {
+ errno = ECHILD;
+ return -1;
+ }
+ waitcode = WaitForMultipleObjects( num_active,
+ active_handles,
+ FALSE,
+ INFINITE );
+ if ( waitcode != WAIT_FAILED ) {
+ if ( waitcode >= WAIT_ABANDONED_0
+ && waitcode < WAIT_ABANDONED_0 + num_active )
+ i = waitcode - WAIT_ABANDONED_0;
+ else
+ i = waitcode - WAIT_OBJECT_0;
+ if ( GetExitCodeProcess(active_handles[i], &exitcode) ) {
+ CloseHandle(active_handles[i]);
+ *status = (int)((exitcode & 0xff) << 8);
+ return (int)active_handles[i];
+ }
+ }
+
+FAILED:
+ errno = GetLastError();
+ return -1;
+
+}
+
+# endif /* NT && !__BORLANDC__ */
+
+# endif /* USE_EXECUNIX */
diff --git a/jam_src/execvms.c b/jam_src/execvms.c
new file mode 100644
index 000000000..0bf5486f2
--- /dev/null
+++ b/jam_src/execvms.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "execcmd.h"
+
+# ifdef OS_VMS
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * execvms.c - execute a shell script, ala VMS
+ *
+ * The approach is this:
+ *
+ * If the command is a single line, and shorter than WRTLEN (what we
+ * believe to be the maximum line length), we just system() it.
+ *
+ * If the command is multi-line, or longer than WRTLEN, we write the
+ * command block to a temp file, splitting long lines (using "-" at
+ * the end of the line to indicate contiuation), and then source that
+ * temp file. We use special logic to make sure we don't continue in
+ * the middle of a quoted string.
+ *
+ * 05/04/94 (seiwald) - async multiprocess interface; noop on VMS
+ * 12/20/96 (seiwald) - rewritten to handle multi-line commands well
+ * 01/14/96 (seiwald) - don't put -'s between "'s
+ */
+
+#define WRTLEN 240
+
+#define MIN( a, b ) ((a) < (b) ? (a) : (b))
+
+/* 1 for the @ and 4 for the .com */
+
+char tempnambuf[ L_tmpnam + 1 + 4 ] = {0};
+
+void
+execcmd(
+ char *string,
+ void (*func)( void *closure, int status ),
+ void *closure,
+ LIST *shell )
+{
+ char *s, *e, *p;
+ int rstat = EXEC_CMD_OK;
+ int status;
+
+ /* See if string is more than one line */
+ /* discounting leading/trailing white space */
+
+ for( s = string; *s && isspace( *s ); s++ )
+ ;
+
+ e = p = strchr( s, '\n' );
+
+ while( p && isspace( *p ) )
+ ++p;
+
+ /* If multi line or long, write to com file. */
+ /* Otherwise, exec directly. */
+
+ if( p && *p || e - s > WRTLEN )
+ {
+ FILE *f;
+
+ /* Create temp file invocation "@sys$scratch:tempfile.com" */
+
+ if( !*tempnambuf )
+ {
+ tempnambuf[0] = '@';
+ (void)tmpnam( tempnambuf + 1 );
+ strcat( tempnambuf, ".com" );
+ }
+
+ /* Open tempfile */
+
+ if( !( f = fopen( tempnambuf + 1, "w" ) ) )
+ {
+ printf( "can't open command file\n" );
+ (*func)( closure, EXEC_CMD_FAIL );
+ return;
+ }
+
+ /* For each line of the string */
+
+ while( *string )
+ {
+ char *s = strchr( string, '\n' );
+ int len = s ? s + 1 - string : strlen( string );
+
+ fputc( '$', f );
+
+ /* For each chunk of a line that needs to be split */
+
+ while( len > 0 )
+ {
+ char *q = string;
+ char *qe = string + MIN( len, WRTLEN );
+ char *qq = q;
+ int quote = 0;
+
+ /* Look for matching "'s */
+
+ for( ; q < qe; q++ )
+ if( *q == '"' && ( quote = !quote ) )
+ qq = q;
+
+ /* Back up to opening quote, if in one */
+
+ if( quote )
+ q = qq;
+
+ fwrite( string, ( q - string ), 1, f );
+
+ len -= ( q - string );
+ string = q;
+
+ if( len )
+ {
+ fputc( '-', f );
+ fputc( '\n', f );
+ }
+ }
+ }
+
+ fclose( f );
+
+ status = system( tempnambuf ) & 0x07;
+
+ unlink( tempnambuf + 1 );
+ }
+ else
+ {
+ /* Execute single line command */
+ /* Strip trailing newline before execing */
+ if( e ) *e = 0;
+ status = system( s ) & 0x07;
+ }
+
+ /* Fail for error or fatal error */
+ /* OK on OK, warning, or info exit */
+
+ if( status == 2 || status == 4 )
+ rstat = EXEC_CMD_FAIL;
+
+ (*func)( closure, rstat );
+}
+
+int
+execwait()
+{
+ return 0;
+}
+
+# endif /* VMS */
diff --git a/jam_src/expand.c b/jam_src/expand.c
new file mode 100644
index 000000000..9c66dfc4b
--- /dev/null
+++ b/jam_src/expand.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "variable.h"
+# include "expand.h"
+# include "filesys.h"
+# include "newstr.h"
+# include "strings.h"
+
+# include
+# include
+/*
+ * expand.c - expand a buffer, given variable values
+ *
+ * External routines:
+ *
+ * var_expand() - variable-expand input string into list of strings
+ *
+ * Internal routines:
+ *
+ * var_edit() - copy input target name to output, performing : modifiers
+ * var_mods() - parse : modifiers into FILENAME structure
+ *
+ * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ */
+
+typedef struct {
+ char downshift; /* :L -- downshift result */
+ char upshift; /* :U -- upshift result */
+ char parent; /* :P -- go to parent directory */
+ char to_slashes; /* :T -- convert "\" to "/" */
+} VAR_ACTS ;
+
+static void var_edit( char *in, char *mods, string *out );
+static void var_mods( char *mods, FILENAME *f, VAR_ACTS *acts );
+
+static int adjust_index( int index, int length );
+
+# define MAGIC_COLON '\001'
+# define MAGIC_LEFT '\002'
+# define MAGIC_RIGHT '\003'
+
+/*
+ * var_expand() - variable-expand input string into list of strings
+ *
+ * Would just copy input to output, performing variable expansion,
+ * except that since variables can contain multiple values the result
+ * of variable expansion may contain multiple values (a list). Properly
+ * performs "product" operations that occur in "$(var1)xxx$(var2)" or
+ * even "$($(var2))".
+ *
+ * Returns a newly created list.
+ */
+
+LIST *
+var_expand(
+ LIST *l,
+ char *in,
+ char *end,
+ LOL *lol,
+ int cancopyin )
+{
+ string buf[1];
+ size_t prefix_length;
+ char *out;
+ char *inp = in;
+ char *ov; /* for temp copy of variable in outbuf */
+ int depth;
+
+ if( DEBUG_VAREXP )
+ printf( "expand '%.*s'\n", end - in, in );
+
+ /* This gets alot of cases: $(<) and $(>) */
+
+ if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] )
+ {
+ switch( in[2] )
+ {
+ case '1':
+ case '<':
+ return list_copy( l, lol_get( lol, 0 ) );
+
+ case '2':
+ case '>':
+ return list_copy( l, lol_get( lol, 1 ) );
+ }
+ }
+
+ /* See if we can use a simple copy of in to out. */
+
+ while ( in < end )
+ if ( *in++ == '$' && *in == '(' )
+ goto expand;
+
+ /* No variables expanded - just add copy of input string to list. */
+
+ /* Cancopyin is an optimization: if the input was already a list */
+ /* item, we can use the copystr() to put it on the new list. */
+ /* Otherwise, we use the slower newstr(). */
+
+ if ( cancopyin )
+ {
+ return list_new( l, copystr( inp ) );
+ }
+ else
+ {
+ LIST* r;
+ string_new( buf );
+ string_append_range( buf, inp, in );
+
+ r = list_new( l, newstr( buf->value ) );
+ string_free( buf );
+ return r;
+ }
+
+ expand:
+ string_new( buf );
+ string_append_range( buf, inp, in - 1 ); /* copy in initial stuff */
+ /*
+ * Input so far (ignore blanks):
+ *
+ * stuff-in-outbuf $(variable) remainder
+ * ^ ^
+ * in end
+ * Output so far:
+ *
+ * stuff-in-outbuf $
+ * ^ ^
+ * out_buf out
+ *
+ *
+ * We just copied the $ of $(...), so back up one on the output.
+ * We now find the matching close paren, copying the variable and
+ * modifiers between the $( and ) temporarily into out_buf, so that
+ * we can replace :'s with MAGIC_COLON. This is necessary to avoid
+ * being confused by modifier values that are variables containing
+ * :'s. Ugly.
+ */
+
+ depth = 1;
+ inp = ++in; /* skip over the '(' */
+
+ while( in < end && depth )
+ {
+ switch( *in++ )
+ {
+ case '(': depth++; break;
+ case ')': depth--; break;
+ }
+ }
+
+ /*
+ * Input so far (ignore blanks):
+ *
+ * stuff-in-outbuf $(variable) remainder
+ * ^ ^ ^
+ * inp in end
+ */
+ prefix_length = buf->size;
+ string_append_range( buf, inp, in - 1 );
+
+ out = buf->value + prefix_length;
+ for ( ov = out; ov < buf->value + buf->size; ++ov )
+ {
+ switch( *ov )
+ {
+ case ':': *ov = MAGIC_COLON; break;
+ case '[': *ov = MAGIC_LEFT; break;
+ case ']': *ov = MAGIC_RIGHT; break;
+ }
+ }
+
+ /*
+ * Input so far (ignore blanks):
+ *
+ * stuff-in-outbuf $(variable) remainder
+ * ^ ^
+ * in end
+ * Output so far:
+ *
+ * stuff-in-outbuf variable
+ * ^ ^ ^
+ * out_buf out ov
+ *
+ * Later we will overwrite 'variable' in out_buf, but we'll be
+ * done with it by then. 'variable' may be a multi-element list,
+ * so may each value for '$(variable element)', and so may 'remainder'.
+ * Thus we produce a product of three lists.
+ */
+
+ {
+ LIST *variables = 0;
+ LIST *remainder = 0;
+ LIST *vars;
+
+ /* Recursively expand variable name & rest of input */
+
+ if( out < ov )
+ variables = var_expand( L0, out, ov, lol, 0 );
+ if( in < end )
+ remainder = var_expand( L0, in, end, lol, 0 );
+
+ /* Now produce the result chain */
+
+ /* For each variable name */
+
+ for( vars = variables; vars; vars = list_next( vars ) )
+ {
+ LIST *value;
+ char *colon;
+ char *bracket;
+ int i, sub1, sub2;
+ string variable;
+ char *varname;
+
+ /* Look for a : modifier in the variable name */
+ /* Must copy into varname so we can modify it */
+
+ string_copy( &variable, vars->string );
+ varname = variable.value;
+
+ if( colon = strchr( varname, MAGIC_COLON ) )
+ {
+ string_truncate( &variable, colon - varname );
+ }
+
+ if( bracket = strchr( varname, MAGIC_LEFT ) )
+ {
+ char *dash = 0;
+
+ if( bracket[1] && ( dash = strchr( bracket + 2, '-' ) ) )
+ {
+ string_truncate( &variable, dash - varname );
+ sub1 = atoi( bracket + 1 );
+ sub2 = atoi( dash + 1 );
+ }
+ else
+ {
+ sub1 = sub2 = atoi( bracket + 1 );
+ }
+
+ string_truncate( &variable, bracket - varname );
+ }
+ else
+ {
+ sub1 = sub2 = 0; /* not needed */
+ }
+
+ /* Get variable value, specially handling $(<), $(>), $(n) */
+
+ if( varname[0] == '<' && !varname[1] )
+ {
+ value = lol_get( lol, 0 );
+ }
+ else if( varname[0] == '>' && !varname[1] )
+ {
+ value = lol_get( lol, 1 );
+ }
+ else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] )
+ {
+ value = lol_get( lol, varname[0] - '1' );
+ }
+ else
+ {
+ value = var_get( varname );
+ }
+
+ /* The fast path: $(x) - just copy the variable value. */
+
+ if( out == buf->value && !bracket && !colon && in == end )
+ {
+ string_free( &variable );
+ l = list_copy( l, value );
+ continue;
+ }
+
+ /* Adjust negative indices */
+ if ( sub1 < 0 || sub2 < 0 )
+ {
+ int length = list_length( value );
+ sub1 = adjust_index( sub1, length );
+ sub2 = adjust_index( sub2, length );
+ }
+
+ /* For each variable value */
+ for( i = 1; value; i++, value = list_next( value ) )
+ {
+ LIST *rem;
+ size_t postfix_start;
+
+ /* Skip members not in subscript */
+
+ if( bracket && ( i < sub1 || sub2 && i > sub2 ) )
+ continue;
+
+ string_truncate( buf, prefix_length );
+
+ /* Apply : mods, if present */
+
+ if( colon )
+ var_edit( value->string, colon + 1, buf );
+ else
+ string_append( buf, value->string );
+
+ /* If no remainder, append result to output chain. */
+
+ if( in == end )
+ {
+ l = list_new( l, newstr( buf->value ) );
+ continue;
+ }
+
+ /* Remember the end of the variable expansion so */
+ /* we can just tack on each instance of 'remainder' */
+
+ postfix_start = buf->size;
+
+ /* For each remainder, or just once if no remainder, */
+ /* append the complete string to the output chain */
+
+ for( rem = remainder; rem; rem = list_next( rem ) )
+ {
+ string_truncate( buf, postfix_start );
+ string_append( buf, rem->string );
+ l = list_new( l, newstr( buf->value ) );
+ }
+ }
+ string_free( &variable );
+ }
+
+ /* variables & remainder were gifts from var_expand */
+ /* and must be freed */
+
+ if( variables )
+ list_free( variables );
+ if( remainder)
+ list_free( remainder );
+
+ if( DEBUG_VAREXP )
+ {
+ printf( "expanded to " );
+ list_print( l );
+ printf( "\n" );
+ }
+
+ string_free( buf );
+ return l;
+ }
+}
+
+/*
+ * var_edit() - copy input target name to output, performing : modifiers
+ */
+
+static void
+var_edit(
+ char *in,
+ char *mods,
+ string *out)
+{
+ FILENAME oldf, newf;
+ VAR_ACTS acts;
+
+ /* Parse apart original filename, putting parts into "oldf" */
+
+ file_parse( in, &oldf );
+
+ /* Parse apart modifiers, putting them into "newf" */
+
+ var_mods( mods, &newf, &acts );
+
+ /* Replace any oldf with newf */
+
+ if( newf.f_grist.ptr )
+ oldf.f_grist = newf.f_grist;
+
+ if( newf.f_root.ptr )
+ oldf.f_root = newf.f_root;
+
+ if( newf.f_dir.ptr )
+ oldf.f_dir = newf.f_dir;
+
+ if( newf.f_base.ptr )
+ oldf.f_base = newf.f_base;
+
+ if( newf.f_suffix.ptr )
+ oldf.f_suffix = newf.f_suffix;
+
+ if( newf.f_member.ptr )
+ oldf.f_member = newf.f_member;
+
+ /* If requested, modify oldf to point to parent */
+
+ if( acts.parent )
+ file_parent( &oldf );
+
+ /* Put filename back together */
+
+ file_build( &oldf, out, 0 );
+
+ /* Handle upshifting, downshifting now */
+ /* Handle conversion of "\" to "/" */
+ {
+ char* p;
+ for ( p = out->value; *p; ++p)
+ {
+ if( acts.upshift )
+ {
+ *p = toupper( *p );
+ }
+ else if( acts.downshift )
+ {
+ *p = tolower( *p );
+ }
+ if ( acts.to_slashes )
+ {
+ if ( *p == '\\' )
+ *p = '/';
+ }
+ }
+ out->size = p - out->value;
+ }
+}
+
+
+/*
+ * var_mods() - parse : modifiers into FILENAME structure
+ *
+ * The : modifiers in a $(varname:modifier) currently support replacing
+ * or omitting elements of a filename, and so they are parsed into a
+ * FILENAME structure (which contains pointers into the original string).
+ *
+ * Modifiers of the form "X=value" replace the component X with
+ * the given value. Modifiers without the "=value" cause everything
+ * but the component X to be omitted. X is one of:
+ *
+ * G
+ * D directory name
+ * B base name
+ * S .suffix
+ * M (member)
+ * R root directory - prepended to whole path
+ *
+ * This routine sets:
+ *
+ * f->f_xxx.ptr = 0
+ * f->f_xxx.len = 0
+ * -> leave the original component xxx
+ *
+ * f->f_xxx.ptr = string
+ * f->f_xxx.len = strlen( string )
+ * -> replace component xxx with string
+ *
+ * f->f_xxx.ptr = ""
+ * f->f_xxx.len = 0
+ * -> omit component xxx
+ *
+ * var_edit() above and file_build() obligingly follow this convention.
+ */
+
+static void
+var_mods(
+ char *mods,
+ FILENAME *f,
+ VAR_ACTS *acts )
+{
+ char *flags = "GRDBSMT";
+ int havezeroed = 0;
+ memset( (char *)f, 0, sizeof( *f ) );
+ memset( (char *)acts, 0, sizeof( *acts ) );
+
+ while( *mods )
+ {
+ char *fl;
+ FILEPART *fp;
+
+ /* First take care of :U or :L (upshift, downshift) */
+
+ if( *mods == 'L' )
+ {
+ acts->downshift = 1;
+ ++mods;
+ continue;
+ }
+ else if( *mods == 'U' )
+ {
+ acts->upshift = 1;
+ ++mods;
+ continue;
+ }
+ else if( *mods == 'P' )
+ {
+ acts->parent = 1;
+ ++mods;
+ continue;
+ }
+ else if ( *mods == 'T' )
+ {
+ acts->to_slashes = 1;
+ ++mods;
+ continue;
+ }
+
+ /* Now handle the file component flags */
+
+ if( !( fl = strchr( flags, *mods++ ) ) )
+ break; /* should complain, but so what... */
+
+ fp = &f->part[ fl - flags ];
+
+ if( *mods++ != '=' )
+ {
+ /* :X - turn everything but X off */
+
+ int i;
+
+ mods--;
+
+ if( !havezeroed++ )
+ for( i = 0; i < 6; i++ )
+ {
+ f->part[ i ].len = 0;
+ f->part[ i ].ptr = "";
+ }
+
+ fp->ptr = 0;
+ }
+ else
+ {
+ /* :X=value - set X to value */
+
+ char *p;
+
+ if( p = strchr( mods, MAGIC_COLON ) )
+ {
+ fp->ptr = mods;
+ fp->len = p - mods;
+ mods = p + 1;
+ }
+ else
+ {
+ fp->ptr = mods;
+ fp->len = strlen( mods );
+ mods += fp->len;
+ }
+ }
+ }
+}
+
+static int adjust_index( int index, int length )
+{
+ if ( index < 0 )
+ index = length + 1 + index;
+ if ( index < 0 )
+ index = 0;
+ return index;
+}
+
+#ifndef NDEBUG
+void var_expand_unit_test()
+{
+ LOL lol[1];
+ LIST* l, *l2;
+ LIST *expected = list_new( list_new( L0, newstr( "axb" ) ), newstr( "ayb" ) );
+ LIST *e2;
+ char axyb[] = "a$(xy)b";
+ char azb[] = "a$($(z))b";
+
+ lol_init(lol);
+ var_set("xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET );
+ var_set("z", list_new( L0, newstr( "xy" ) ), VAR_SET );
+
+ l = var_expand( 0, axyb, axyb + sizeof(axyb) - 1, lol, 0 );
+ for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) )
+ assert( !strcmp( e2->string, l2->string ) );
+ list_free(l);
+
+ l = var_expand( 0, azb, azb + sizeof(azb) - 1, lol, 0 );
+ for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next(l2), e2 = list_next(e2) )
+ assert( !strcmp( e2->string, l2->string ) );
+ list_free(l);
+
+ lol_free(lol);
+}
+#endif
diff --git a/jam_src/expand.h b/jam_src/expand.h
new file mode 100644
index 000000000..77ee74bf1
--- /dev/null
+++ b/jam_src/expand.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * expand.h - expand a buffer, given variable values
+ */
+
+LIST *var_expand( LIST *l, char *in, char *end, LOL *lol, int cancopyin );
+void var_expand_unit_test();
diff --git a/jam_src/filemac.c b/jam_src/filemac.c
new file mode 100644
index 000000000..9892a7dbb
--- /dev/null
+++ b/jam_src/filemac.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+# ifdef OS_MAC
+
+#include
+#include
+
+# include <:sys:stat.h>
+
+/*
+ * filemac.c - manipulate file names and scan directories on macintosh
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 12/19/94 (mikem) - solaris string table insanity support
+ * 02/14/95 (seiwald) - parse and build /xxx properly
+ * 05/03/96 (seiwald) - split into pathunix.c
+ * 11/21/96 (peterk) - BEOS does not have Unix-style archives
+ */
+
+void CopyC2PStr(const char * cstr, StringPtr pstr)
+{
+ int len;
+
+ for (len = 0; *cstr && len<255; pstr[++len] = *cstr++)
+ ;
+
+ pstr[0] = len;
+}
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int s, time_t t ) )
+{
+ FILENAME f;
+ string filename[1];
+ unsigned char fullPath[ 512 ];
+
+ FSSpec spec;
+ WDPBRec vol;
+ Str63 volName;
+ CInfoPBRec lastInfo;
+ int index = 1;
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+ /* Special case ":" - enter it */
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == ':' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+
+ /* Now enter contents of directory */
+
+ vol.ioNamePtr = volName;
+
+ if( PBHGetVolSync( &vol ) )
+ return;
+
+ CopyC2PStr( dir, fullPath );
+
+ if( FSMakeFSSpec( vol.ioWDVRefNum, vol.ioWDDirID, fullPath, &spec ) )
+ return;
+
+ lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
+ lastInfo.dirInfo.ioDrDirID = spec.parID;
+ lastInfo.dirInfo.ioNamePtr = spec.name;
+ lastInfo.dirInfo.ioFDirIndex = 0;
+ lastInfo.dirInfo.ioACUser = 0;
+
+ if( PBGetCatInfoSync(&lastInfo) )
+ return;
+
+ if (!(lastInfo.dirInfo.ioFlAttrib & 0x10))
+ return;
+
+ // ioDrDirID must be reset each time.
+
+ spec.parID = lastInfo.dirInfo.ioDrDirID;
+
+ string_new( filename );
+ for( ;; )
+ {
+ lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
+ lastInfo.dirInfo.ioDrDirID = spec.parID;
+ lastInfo.dirInfo.ioNamePtr = fullPath;
+ lastInfo.dirInfo.ioFDirIndex = index++;
+
+ if( PBGetCatInfoSync(&lastInfo) )
+ return;
+
+ f.f_base.ptr = (char *)fullPath + 1;
+ f.f_base.len = *fullPath;
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+ (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 );
+ }
+ string_free( filename );
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+
+ return 0;
+}
+
+/*
+ * file_archscan() - scan an archive for files
+ */
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int s, time_t t ) )
+
+{
+}
+
+
+# endif /* macintosh */
+
diff --git a/jam_src/filent.c b/jam_src/filent.c
new file mode 100644
index 000000000..951e74a3c
--- /dev/null
+++ b/jam_src/filent.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+# include "strings.h"
+
+# ifdef OS_NT
+
+# ifdef __BORLANDC__
+# if __BORLANDC__ < 0x550
+# include
+# include
+# endif
+# undef FILENAME /* cpp namespace collision */
+# define _finddata_t ffblk
+# endif
+
+# include
+# include
+
+/*
+ * filent.c - scan directories and archives on NT
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 07/10/95 (taylor) Findfirst() returns the first file on NT.
+ * 05/03/96 (seiwald) split apart into pathnt.c
+ */
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ FILENAME f;
+ string filespec[1];
+ string filename[1];
+ long handle;
+ int ret;
+ struct _finddata_t finfo[1];
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ dir = *dir ? dir : ".";
+
+ /* Special case \ or d:\ : enter it */
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+ else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+
+ /* Now enter contents of directory */
+
+ string_copy( filespec, dir );
+ string_append( filespec, "/*" );
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+# if defined(__BORLANDC__) && __BORLANDC__ < 0x550
+ if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
+ {
+ string_free( filespec );
+ return;
+ }
+
+ string_new( filename );
+ while( !ret )
+ {
+ time_t time_write = finfo->ff_fdate;
+
+ time_write = (time_write << 16) | finfo->ff_ftime;
+ f.f_base.ptr = finfo->ff_name;
+ f.f_base.len = strlen( finfo->ff_name );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename );
+
+ (*func)( filename->value, 1 /* stat()'ed */, time_write );
+
+ ret = findnext( finfo );
+ }
+# else
+ handle = _findfirst( filespec->value, finfo );
+
+ if( ret = ( handle < 0L ) )
+ {
+ string_free( filespec );
+ return;
+ }
+
+ string_new( filename );
+ while( !ret )
+ {
+ f.f_base.ptr = finfo->name;
+ f.f_base.len = strlen( finfo->name );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+
+ (*func)( filename->value, 1 /* stat()'ed */, finfo->time_write );
+
+ ret = _findnext( handle, finfo );
+ }
+
+ _findclose( handle );
+# endif
+ string_free( filename );
+ string_free( filespec );
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ /* On NT this is called only for C:/ */
+
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+
+ return 0;
+}
+
+/*
+ * file_archscan() - scan an archive for files
+ */
+
+/* Straight from SunOS */
+
+#define ARMAG "!\n"
+#define SARMAG 8
+
+#define ARFMAG "`\n"
+
+struct ar_hdr {
+ char ar_name[16];
+ char ar_date[12];
+ char ar_uid[6];
+ char ar_gid[6];
+ char ar_mode[8];
+ char ar_size[10];
+ char ar_fmag[2];
+};
+
+# define SARFMAG 2
+# define SARHDR sizeof( struct ar_hdr )
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ struct ar_hdr ar_hdr;
+ char *string_table = 0;
+ char buf[ MAXJPATH ];
+ long offset;
+ int fd;
+
+ if( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 )
+ return;
+
+ if( read( fd, buf, SARMAG ) != SARMAG ||
+ strncmp( ARMAG, buf, SARMAG ) )
+ {
+ close( fd );
+ return;
+ }
+
+ offset = SARMAG;
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan archive %s\n", archive );
+
+ while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
+ !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
+ {
+ long lar_date;
+ long lar_size;
+ char *name = 0;
+ char *endname;
+ char *c;
+
+ sscanf( ar_hdr.ar_date, "%ld", &lar_date );
+ sscanf( ar_hdr.ar_size, "%ld", &lar_size );
+
+ lar_size = ( lar_size + 1 ) & ~1;
+
+ if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' )
+ {
+ /* this is the "string table" entry of the symbol table,
+ ** which holds strings of filenames that are longer than
+ ** 15 characters (ie. don't fit into a ar_name
+ */
+
+ string_table = malloc(lar_size);
+ if (read(fd, string_table, lar_size) != lar_size)
+ printf("error reading string table\n");
+ offset += SARHDR + lar_size;
+ continue;
+ }
+ else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ')
+ {
+ /* Long filenames are recognized by "/nnnn" where nnnn is
+ ** the offset of the string in the string table represented
+ ** in ASCII decimals.
+ */
+
+ name = string_table + atoi( ar_hdr.ar_name + 1 );
+ endname = name + strlen( name );
+ }
+ else
+ {
+ /* normal name */
+ name = ar_hdr.ar_name;
+ endname = name + sizeof( ar_hdr.ar_name );
+ }
+
+ /* strip trailing space, slashes, and backslashes */
+
+ while( endname-- > name )
+ if( *endname != ' ' && *endname != '\\' && *endname != '/' )
+ break;
+ *++endname = 0;
+
+ /* strip leading directory names, an NT specialty */
+
+ if( c = strrchr( name, '/' ) )
+ name = c + 1;
+ if( c = strrchr( name, '\\' ) )
+ name = c + 1;
+
+ sprintf( buf, "%s(%.*s)", archive, endname - name, name );
+ (*func)( buf, 1 /* time valid */, (time_t)lar_date );
+
+ offset += SARHDR + lar_size;
+ lseek( fd, offset, 0 );
+ }
+
+ close( fd );
+}
+
+# endif /* NT */
diff --git a/jam_src/fileos2.c b/jam_src/fileos2.c
new file mode 100644
index 000000000..e536c4e70
--- /dev/null
+++ b/jam_src/fileos2.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+/* note that we use "fileunix.c" when compiling with EMX on OS/2 */
+# if defined(OS_OS2) && !defined(__EMX__)
+
+# include
+# include
+
+/*
+ * fileos2.c - scan directories and archives on NT
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 07/10/95 (taylor) Findfirst() returns the first file on NT.
+ * 05/03/96 (seiwald) split apart into pathnt.c
+ * 09/22/00 (seiwald) handle \ and c:\ specially: don't add extra /
+ */
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ FILENAME f;
+ string filespec[1];
+ long handle;
+ int ret;
+ struct _find_t finfo[1];
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ dir = *dir ? dir : ".";
+
+ /* Special case \ or d:\ : enter it */
+ string_copy( filespec, dir );
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+ else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+ else
+ string_push_back( filespec, '/' );
+
+ string_push_back( filespec, '*' );
+
+ /* Now enter contents of directory */
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", filespec->value );
+
+ /* Time info in dos find_t is not very useful. It consists */
+ /* of a separate date and time, and putting them together is */
+ /* not easy. So we leave that to a later stat() call. */
+
+ if( !_dos_findfirst( filespec->value, _A_NORMAL|_A_RDONLY|_A_SUBDIR, finfo ) )
+ {
+ string filename[1];
+ string_new( filename );
+ do
+ {
+
+ f.f_base.ptr = finfo->name;
+ f.f_base.len = strlen( finfo->name );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+ (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 );
+ }
+ while( !_dos_findnext( finfo ) );
+ string_free( filename );
+ }
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ /* This is called on OS2, not NT. */
+ /* NT fills in the time in the dirscan. */
+
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+
+ return 0;
+}
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+}
+
+# endif /* OS2 && !__EMX__ */
+
diff --git a/jam_src/filesys.c b/jam_src/filesys.c
new file mode 100644
index 000000000..c38d9e468
--- /dev/null
+++ b/jam_src/filesys.c
@@ -0,0 +1,33 @@
+# include "jam.h"
+# include "filesys.h"
+# include "strings.h"
+
+void
+file_build1(
+ FILENAME *f,
+ string* file)
+{
+ if( DEBUG_SEARCH )
+ {
+ printf("build file: ");
+ if( f->f_root.len )
+ printf( "root = '%.*s' ", f->f_root.len, f->f_root.ptr );
+ if( f->f_dir.len )
+ printf( "dir = '%.*s' ", f->f_dir.len, f->f_dir.ptr );
+ if( f->f_base.len )
+ printf( "base = '%.*s' ", f->f_base.len, f->f_base.ptr );
+ }
+
+ /* Start with the grist. If the current grist isn't */
+ /* surrounded by <>'s, add them. */
+
+ if( f->f_grist.len )
+ {
+ if( f->f_grist.ptr[0] != '<' )
+ string_push_back( file, '<' );
+ string_append_range(
+ file, f->f_grist.ptr, f->f_grist.ptr + f->f_grist.len );
+ if( file->value[file->size - 1] != '>' )
+ string_push_back( file, '>' );
+ }
+}
diff --git a/jam_src/filesys.h b/jam_src/filesys.h
new file mode 100644
index 000000000..c46b1c2a5
--- /dev/null
+++ b/jam_src/filesys.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * filesys.h - FILENAME struct and OS specific file routines
+ */
+
+/*
+ * FILENAME - a name of a file, broken into dir/base/suffix(member)
+ *
+ * is salt to distinguish between targets that otherwise would
+ * have the same name: it never appears in the bound name of a target.
+ * (member) is an archive member name: the syntax is arbitrary, but must
+ * agree in file_parse(), file_build() and the Jambase.
+ *
+ * On VMS, we keep track of whether the original path was a directory
+ * (without a file), so that $(VAR:D) can climb to the parent.
+ */
+
+#ifndef FILESYS_DWA20011025_H
+# define FILESYS_DWA20011025_H
+
+# include "strings.h"
+
+typedef struct _filename FILENAME;
+typedef struct _filepart FILEPART;
+
+struct _filepart {
+ char *ptr;
+ int len;
+};
+
+struct _filename {
+ FILEPART part[6];
+# ifdef OS_VMS
+ int parent;
+# endif
+
+# define f_grist part[0]
+# define f_root part[1]
+# define f_dir part[2]
+# define f_base part[3]
+# define f_suffix part[4]
+# define f_member part[5]
+
+} ;
+
+void file_build( FILENAME *f, string *file, int binding );
+void file_build1( FILENAME *f, string *file );
+
+void file_parse( char *file, FILENAME *f );
+void file_parent( FILENAME *f );
+
+void file_dirscan( char *dir, void (*func)( char *f, int s, time_t t ) );
+void file_archscan( char *arch, void (*func)( char *f, int s, time_t t ) );
+
+int file_time( char *filename, time_t *time );
+
+#endif // FILESYS_DWA20011025_H
diff --git a/jam_src/fileunix.c b/jam_src/fileunix.c
new file mode 100644
index 000000000..8ea80a506
--- /dev/null
+++ b/jam_src/fileunix.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+# include "strings.h"
+
+# ifdef USE_FILEUNIX
+
+# if defined( OS_SEQUENT ) || \
+ defined( OS_DGUX ) || \
+ defined( OS_SCO ) || \
+ defined( OS_ISC )
+# define PORTAR 1
+# endif
+
+# ifdef __EMX__
+# include
+# include
+# endif
+
+# if defined( OS_RHAPSODY ) || \
+ defined( OS_MACOSX ) || \
+ defined( OS_NEXT )
+/* need unistd for rhapsody's proper lseek */
+# include
+# include
+# define STRUCT_DIRENT struct direct
+# else
+# include
+# define STRUCT_DIRENT struct dirent
+# endif
+
+# ifdef OS_COHERENT
+# include
+# define HAVE_AR
+# endif
+
+# if defined( OS_MVS ) || \
+ defined( OS_INTERIX )
+
+#define ARMAG "!\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+struct ar_hdr /* archive file member header - printable ascii */
+{
+ char ar_name[16]; /* file member name - `/' terminated */
+ char ar_date[12]; /* file member date - decimal */
+ char ar_uid[6]; /* file member user id - decimal */
+ char ar_gid[6]; /* file member group id - decimal */
+ char ar_mode[8]; /* file member mode - octal */
+ char ar_size[10]; /* file member size - decimal */
+ char ar_fmag[2]; /* ARFMAG - string to end header */
+};
+
+# define HAVE_AR
+# endif
+
+# if defined( OS_QNX ) || \
+ defined( OS_BEOS ) || \
+ defined( OS_MPEIX )
+# define NO_AR
+# define HAVE_AR
+# endif
+
+# ifndef HAVE_AR
+# include
+# endif
+
+/*
+ * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 12/19/94 (mikem) - solaris string table insanity support
+ * 02/14/95 (seiwald) - parse and build /xxx properly
+ * 05/03/96 (seiwald) - split into pathunix.c
+ * 11/21/96 (peterk) - BEOS does not have Unix-style archives
+ */
+
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ FILENAME f;
+ DIR *d;
+ STRUCT_DIRENT *dirent;
+ string filename[1];
+
+ /* First enter directory itself */
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_dir.ptr = dir;
+ f.f_dir.len = strlen(dir);
+
+ dir = *dir ? dir : ".";
+
+ /* Special case / : enter it */
+
+ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' )
+ (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
+
+ /* Now enter contents of directory */
+
+ if( !( d = opendir( dir ) ) )
+ return;
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+ string_new( filename );
+ while( dirent = readdir( d ) )
+ {
+# ifdef old_sinix
+ /* Broken structure definition on sinix. */
+ f.f_base.ptr = dirent->d_name - 2;
+# else
+ f.f_base.ptr = dirent->d_name;
+# endif
+ f.f_base.len = strlen( f.f_base.ptr );
+
+ string_truncate( filename, 0 );
+ file_build( &f, filename, 0 );
+
+ (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 );
+ }
+ string_free( filename );
+
+ closedir( d );
+}
+
+/*
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ */
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ struct stat statbuf;
+
+ if( stat( filename, &statbuf ) < 0 )
+ return -1;
+
+ *time = statbuf.st_mtime;
+ return 0;
+}
+
+/*
+ * file_archscan() - scan an archive for files
+ */
+
+# ifndef AIAMAG /* God-fearing UNIX */
+
+# define SARFMAG 2
+# define SARHDR sizeof( struct ar_hdr )
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+# ifndef NO_AR
+ struct ar_hdr ar_hdr;
+ char buf[ MAXJPATH ];
+ long offset;
+ char *string_table = 0;
+ int fd;
+
+ if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
+ return;
+
+ if( read( fd, buf, SARMAG ) != SARMAG ||
+ strncmp( ARMAG, buf, SARMAG ) )
+ {
+ close( fd );
+ return;
+ }
+
+ offset = SARMAG;
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan archive %s\n", archive );
+
+ while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
+ !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
+ {
+ char lar_name[256];
+ long lar_date;
+ long lar_size;
+ long lar_offset;
+ char *c;
+ char *src, *dest;
+
+ strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
+
+ sscanf( ar_hdr.ar_date, "%ld", &lar_date );
+ sscanf( ar_hdr.ar_size, "%ld", &lar_size );
+
+ if (ar_hdr.ar_name[0] == '/')
+ {
+ if (ar_hdr.ar_name[1] == '/')
+ {
+ /* this is the "string table" entry of the symbol table,
+ ** which holds strings of filenames that are longer than
+ ** 15 characters (ie. don't fit into a ar_name
+ */
+
+ string_table = (char *)malloc(lar_size);
+ lseek(fd, offset + SARHDR, 0);
+ if (read(fd, string_table, lar_size) != lar_size)
+ printf("error reading string table\n");
+ }
+ else if (string_table && ar_hdr.ar_name[1] != ' ')
+ {
+ /* Long filenames are recognized by "/nnnn" where nnnn is
+ ** the offset of the string in the string table represented
+ ** in ASCII decimals.
+ */
+ dest = lar_name;
+ lar_offset = atoi(lar_name + 1);
+ src = &string_table[lar_offset];
+ while (*src != '/')
+ *dest++ = *src++;
+ *dest = '/';
+ }
+ }
+
+ c = lar_name - 1;
+ while( *++c != ' ' && *c != '/' )
+ ;
+ *c = '\0';
+
+ if ( DEBUG_BINDSCAN )
+ printf( "archive name %s found\n", lar_name );
+
+ sprintf( buf, "%s(%s)", archive, lar_name );
+
+ (*func)( buf, 1 /* time valid */, (time_t)lar_date );
+
+ offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
+ lseek( fd, offset, 0 );
+ }
+
+ if (string_table)
+ free(string_table);
+
+ close( fd );
+
+# endif /* NO_AR */
+
+}
+
+# else /* AIAMAG - RS6000 AIX */
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ struct fl_hdr fl_hdr;
+
+ struct {
+ struct ar_hdr hdr;
+ char pad[ 256 ];
+ } ar_hdr ;
+
+ char buf[ MAXJPATH ];
+ long offset;
+ int fd;
+
+ if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
+ return;
+
+ if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
+ strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
+ {
+ close( fd );
+ return;
+ }
+
+ sscanf( fl_hdr.fl_fstmoff, "%ld", &offset );
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan archive %s\n", archive );
+
+ while( offset > 0 &&
+ lseek( fd, offset, 0 ) >= 0 &&
+ read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) )
+ {
+ long lar_date;
+ int lar_namlen;
+
+ sscanf( ar_hdr.hdr.ar_namlen, "%d", &lar_namlen );
+ sscanf( ar_hdr.hdr.ar_date, "%ld", &lar_date );
+ sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset );
+
+ if( !lar_namlen )
+ continue;
+
+ ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
+
+ sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
+
+ (*func)( buf, 1 /* time valid */, (time_t)lar_date );
+ }
+
+ close( fd );
+}
+
+# endif /* AIAMAG - RS6000 AIX */
+
+# endif /* USE_FILEUNIX */
+
diff --git a/jam_src/filevms.c b/jam_src/filevms.c
new file mode 100644
index 000000000..ad19725b0
--- /dev/null
+++ b/jam_src/filevms.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+# ifdef OS_VMS
+
+/*
+ * filevms.c - scan directories and libaries on VMS
+ *
+ * External routines:
+ *
+ * file_dirscan() - scan a directory for files
+ * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_archscan() - scan an archive for files
+ *
+ * File_dirscan() and file_archscan() call back a caller provided function
+ * for each file found. A flag to this callback function lets file_dirscan()
+ * and file_archscan() indicate that a timestamp is being provided with the
+ * file. If file_dirscan() or file_archscan() do not provide the file's
+ * timestamp, interested parties may later call file_time().
+ *
+ * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
+ * 05/03/96 (seiwald) - split into pathvms.c
+ */
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Supply missing prototypes for lbr$-routines*/
+int lbr$close();
+int lbr$get_index();
+int lbr$ini_control();
+int lbr$open();
+int lbr$set_module();
+
+/*
+ * unlink() - remove a file
+ */
+
+#if __CRTL_VER < 70000000
+
+unlink( char *f )
+{
+ remove( f );
+}
+
+#endif
+
+static void
+file_cvttime(
+ unsigned int *curtime,
+ time_t *unixtime )
+{
+ static const size_t divisor = 10000000;
+ static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
+ int delta[2], remainder;
+
+ lib$subx( curtime, bastim, delta );
+ lib$ediv( &divisor, delta, unixtime, &remainder );
+}
+
+# define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
+
+# define min( a,b ) ((a)<(b)?(a):(b))
+
+void
+file_dirscan(
+ char *dir,
+ void (*func)( char *file, int status, time_t t ) )
+{
+
+ struct FAB xfab;
+ struct NAM xnam;
+ struct XABDAT xab;
+ char esa[256];
+ char filename[256];
+ string filename2[1];
+ char dirname[256];
+ register int status;
+ FILENAME f;
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+
+ f.f_root.ptr = dir;
+ f.f_root.len = strlen( dir );
+
+ /* get the input file specification
+ */
+ xnam = cc$rms_nam;
+ xnam.nam$l_esa = esa;
+ xnam.nam$b_ess = sizeof( esa ) - 1;
+ xnam.nam$l_rsa = filename;
+ xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS );
+
+ xab = cc$rms_xabdat; /* initialize extended attributes */
+ xab.xab$b_cod = XAB$C_DAT; /* ask for date */
+ xab.xab$l_nxt = NULL; /* terminate XAB chain */
+
+ xfab = cc$rms_fab;
+ xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION;
+ xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1;
+ xfab.fab$l_fop = FAB$M_NAM;
+ xfab.fab$l_fna = dir; /* address of file name */
+ xfab.fab$b_fns = strlen( dir ); /* length of file name */
+ xfab.fab$l_nam = &xnam; /* address of NAB block */
+ xfab.fab$l_xab = (char *)&xab; /* address of XAB block */
+
+
+ status = sys$parse( &xfab );
+
+ if( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", dir );
+
+ if ( !( status & 1 ) )
+ return;
+
+
+
+ /* Add bogus directory for [000000] */
+
+ if( !strcmp( dir, "[000000]" ) )
+ {
+ (*func)( "[000000]", 1 /* time valid */, 1 /* old but true */ );
+ }
+
+ /* Add bogus directory for [] */
+
+ if( !strcmp( dir, "[]" ) )
+ {
+ (*func)( "[]", 1 /* time valid */, 1 /* old but true */ );
+ (*func)( "[-]", 1 /* time valid */, 1 /* old but true */ );
+ }
+
+ string_new( filename2 );
+ while ( (status = sys$search( &xfab )) & 1 )
+ {
+ char *s;
+ time_t time;
+
+ /* "I think that might work" - eml */
+
+ sys$open( &xfab );
+ sys$close( &xfab );
+
+ file_cvttime( (unsigned int *)&xab.xab$q_rdt, &time );
+
+ filename[xnam.nam$b_rsl] = '\0';
+
+ /* What we do with the name depends on the suffix: */
+ /* .dir is a directory */
+ /* .xxx is a file with a suffix */
+ /* . is no suffix at all */
+
+ if( xnam.nam$b_type == 4 && !strncmp( xnam.nam$l_type, ".DIR", 4 ) )
+ {
+ /* directory */
+ sprintf( dirname, "[.%.*s]", xnam.nam$b_name, xnam.nam$l_name );
+ f.f_dir.ptr = dirname;
+ f.f_dir.len = strlen( dirname );
+ f.f_base.ptr = 0;
+ f.f_base.len = 0;
+ f.f_suffix.ptr = 0;
+ f.f_suffix.len = 0;
+ }
+ else
+ {
+ /* normal file with a suffix */
+ f.f_dir.ptr = 0;
+ f.f_dir.len = 0;
+ f.f_base.ptr = xnam.nam$l_name;
+ f.f_base.len = xnam.nam$b_name;
+ f.f_suffix.ptr = xnam.nam$l_type;
+ f.f_suffix.len = xnam.nam$b_type;
+ }
+
+ string_truncate( filename2, 0 );
+ file_build( &f, filename2, 0 );
+
+ /*
+ if( DEBUG_SEARCH )
+ printf("root '%s' base %.*s suf %.*s = %s\n",
+ dir,
+ xnam.nam$b_name, xnam.nam$l_name,
+ xnam.nam$b_type, xnam.nam$l_type,
+ filename2);
+ */
+
+ (*func)( filename2->value, 1 /* time valid */, time );
+ }
+ string_free( filename2 );
+
+ if ( status != RMS$_NMF && status != RMS$_FNF )
+ lib$signal( xfab.fab$l_sts, xfab.fab$l_stv );
+}
+
+int
+file_time(
+ char *filename,
+ time_t *time )
+{
+ /* This should never be called, as all files are */
+ /* timestampped in file_dirscan() and file_archscan() */
+ return -1;
+}
+
+static char *VMS_archive = 0;
+static void (*VMS_func)( char *file, int status, time_t t ) = 0;
+static void *context;
+
+static int
+file_archmember(
+ struct dsc$descriptor_s *module,
+ unsigned long *rfa )
+{
+ static struct dsc$descriptor_s bufdsc =
+ {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
+
+ struct mhddef *mhd;
+ char filename[128];
+ char buf[ MAXJPATH ];
+
+ int status;
+ time_t library_date;
+
+ register int i;
+ register char *p;
+
+ bufdsc.dsc$a_pointer = filename;
+ bufdsc.dsc$w_length = sizeof( filename );
+ status = lbr$set_module( &context, rfa, &bufdsc,
+ &bufdsc.dsc$w_length, NULL );
+ if ( !(status & 1) )
+ return ( 1 );
+
+ mhd = (struct mhddef *)filename;
+
+ file_cvttime( &mhd->mhd$l_datim, &library_date );
+
+ for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; i++, p++ )
+ filename[i] = *p;
+
+ filename[i] = '\0';
+
+ sprintf( buf, "%s(%s.obj)", VMS_archive, filename );
+
+ (*VMS_func)( buf, 1 /* time valid */, (time_t)library_date );
+
+ return ( 1 );
+}
+
+void
+file_archscan(
+ char *archive,
+ void (*func)( char *file, int status, time_t t ) )
+{
+ static struct dsc$descriptor_s library =
+ {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
+
+ unsigned long lfunc = LBR$C_READ;
+ unsigned long typ = LBR$C_TYP_UNK;
+ unsigned long index = 1;
+
+ register int status;
+
+ VMS_archive = archive;
+ VMS_func = func;
+
+ status = lbr$ini_control( &context, &lfunc, &typ, NULL );
+ if ( !( status & 1 ) )
+ return;
+
+ library.dsc$a_pointer = archive;
+ library.dsc$w_length = strlen( archive );
+
+ status = lbr$open( &context, &library, NULL, NULL, NULL, NULL, NULL );
+ if ( !( status & 1 ) )
+ return;
+
+ (void) lbr$get_index( &context, &index, file_archmember, NULL );
+
+ (void) lbr$close( &context );
+}
+
+# endif /* VMS */
+
diff --git a/jam_src/frames.h b/jam_src/frames.h
new file mode 100644
index 000000000..e0dc6761e
--- /dev/null
+++ b/jam_src/frames.h
@@ -0,0 +1,19 @@
+#ifndef FRAMES_DWA20011021_H
+# define FRAMES_DWA20011021_H
+
+# include "lists.h"
+# include "modules.h"
+
+typedef struct frame FRAME;
+
+struct frame
+{
+ FRAME* prev;
+ LOL args[1];
+ module* module;
+};
+
+void frame_init( FRAME* ); /* implemented in compile.c */
+void frame_free( FRAME* ); /* implemented in compile.c */
+
+#endif // FRAMES_DWA20011021_H
diff --git a/jam_src/glob.c b/jam_src/glob.c
new file mode 100644
index 000000000..abb56eb1b
--- /dev/null
+++ b/jam_src/glob.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 1994 Christopher Seiwald. All rights reserved.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * glob.c - match a string against a simple pattern
+ *
+ * Understands the following patterns:
+ *
+ * * any number of characters
+ * ? any single character
+ * [a-z] any single character in the range a-z
+ * [^a-z] any single character not in the range a-z
+ * \x match x
+ *
+ * External functions:
+ *
+ * glob() - match a string against a simple pattern
+ *
+ * Internal functions:
+ *
+ * globchars() - build a bitlist to check for character group match
+ */
+
+# include "jam.h"
+
+# define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
+# define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
+
+static void globchars( char *s, char *e, char *b );
+
+/*
+ * glob() - match a string against a simple pattern
+ */
+
+int
+glob(
+ register char *c,
+ register char *s )
+{
+ char bitlist[ BITLISTSIZE ];
+ char *here;
+
+ for( ;; )
+ switch( *c++ )
+ {
+ case '\0':
+ return *s ? -1 : 0;
+
+ case '?':
+ if( !*s++ )
+ return 1;
+ break;
+
+ case '[':
+ /* scan for matching ] */
+
+ here = c;
+ do if( !*c++ )
+ return 1;
+ while( here == c || *c != ']' );
+ c++;
+
+ /* build character class bitlist */
+
+ globchars( here, c, bitlist );
+
+ if( !CHECK_BIT( bitlist, *(unsigned char *)s ) )
+ return 1;
+ s++;
+ break;
+
+ case '*':
+ here = s;
+
+ while( *s )
+ s++;
+
+ /* Try to match the rest of the pattern in a recursive */
+ /* call. If the match fails we'll back up chars, retrying. */
+
+ while( s != here )
+ {
+ int r;
+
+ /* A fast path for the last token in a pattern */
+
+ r = *c ? glob( c, s ) : *s ? -1 : 0;
+
+ if( !r )
+ return 0;
+ else if( r < 0 )
+ return 1;
+
+ --s;
+ }
+ break;
+
+ case '\\':
+ /* Force literal match of next char. */
+
+ if( !*c || *s++ != *c++ )
+ return 1;
+ break;
+
+ default:
+ if( *s++ != c[-1] )
+ return 1;
+ break;
+ }
+}
+
+/*
+ * globchars() - build a bitlist to check for character group match
+ */
+
+static void
+globchars(
+ char *s,
+ char *e,
+ char *b )
+{
+ int neg = 0;
+
+ memset( b, '\0', BITLISTSIZE );
+
+ if( *s == '^')
+ neg++, s++;
+
+ while( s < e )
+ {
+ int c;
+
+ if( s+2 < e && s[1] == '-' )
+ {
+ for( c = s[0]; c <= s[2]; c++ )
+ b[ c/8 ] |= (1<<(c%8));
+ s += 3;
+ } else {
+ c = *s++;
+ b[ c/8 ] |= (1<<(c%8));
+ }
+ }
+
+ if( neg )
+ {
+ int i;
+ for( i = 0; i < BITLISTSIZE; i++ )
+ b[ i ] ^= 0377;
+ }
+
+ /* Don't include \0 in either $[chars] or $[^chars] */
+
+ b[0] &= 0376;
+}
diff --git a/jam_src/hash.c b/jam_src/hash.c
new file mode 100644
index 000000000..c632c8fe9
--- /dev/null
+++ b/jam_src/hash.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "hash.h"
+
+/*
+ * hash.c - simple in-memory hashing routines
+ *
+ * External routines:
+ *
+ * hashinit() - initialize a hash table, returning a handle
+ * hashitem() - find a record in the table, and optionally enter a new one
+ * hashdone() - free a hash table, given its handle
+ *
+ * Internal routines:
+ *
+ * hashrehash() - resize and rebuild hp->tab, the hash table
+ *
+ * 4/29/93 - ensure ITEM's are aligned
+ */
+
+char *hashsccssid="@(#)hash.c 1.14 () 6/20/88";
+
+/* Header attached to all data items entered into a hash table. */
+
+struct hashhdr {
+ struct item *next;
+ int keyval; /* for quick comparisons */
+} ;
+
+/* This structure overlays the one handed to hashenter(). */
+/* It's actual size is given to hashinit(). */
+
+struct hashdata {
+ char *key;
+ /* rest of user data */
+} ;
+
+typedef struct item {
+ struct hashhdr hdr;
+ struct hashdata data;
+} ITEM ;
+
+# define MAX_LISTS 32
+
+struct hash
+{
+ /*
+ * the hash table, just an array of item pointers
+ */
+ struct {
+ int nel;
+ ITEM **base;
+ } tab;
+
+ int bloat; /* tab.nel / items.nel */
+ int inel; /* initial number of elements */
+
+ /*
+ * the array of records, maintained by these routines
+ * essentially a microallocator
+ */
+ struct {
+ int more; /* how many more ITEMs fit in lists[ list ] */
+ char *next; /* where to put more ITEMs in lists[ list ] */
+ int datalen; /* length of records in this hash table */
+ int size; /* sizeof( ITEM ) + aligned datalen */
+ int nel; /* total ITEMs held by all lists[] */
+ int list; /* index into lists[] */
+
+ struct {
+ int nel; /* total ITEMs held by this list */
+ char *base; /* base of ITEMs array */
+ } lists[ MAX_LISTS ];
+ } items;
+
+ char *name; /* just for hashstats() */
+} ;
+
+static void hashrehash( struct hash *hp );
+static void hashstat( struct hash *hp );
+
+/*
+ * hashitem() - find a record in the table, and optionally enter a new one
+ */
+
+int
+hashitem(
+ register struct hash *hp,
+ HASHDATA **data,
+ int enter )
+{
+ ITEM **base;
+ register ITEM *i;
+ char *b = (*data)->key;
+ int keyval;
+
+ if( enter && !hp->items.more )
+ hashrehash( hp );
+
+ if( !enter && !hp->items.nel )
+ return 0;
+
+ keyval = *b;
+
+ while( *b )
+ keyval = keyval * 2147059363 + *b++;
+
+ keyval &= 0x7FFFFFFF;
+
+ base = hp->tab.base + ( keyval % hp->tab.nel );
+
+ for( i = *base; i; i = i->hdr.next )
+ if( keyval == i->hdr.keyval &&
+ !strcmp( i->data.key, (*data)->key ) )
+ {
+ *data = &i->data;
+ return !0;
+ }
+
+ if( enter )
+ {
+ i = (ITEM *)hp->items.next;
+ hp->items.next += hp->items.size;
+ hp->items.more--;
+ memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
+ i->hdr.keyval = keyval;
+ i->hdr.next = *base;
+ *base = i;
+ *data = &i->data;
+ }
+
+ return 0;
+}
+
+/*
+ * hashrehash() - resize and rebuild hp->tab, the hash table
+ */
+
+static void hashrehash( register struct hash *hp )
+{
+ int i = ++hp->items.list;
+
+ hp->items.more = i ? 2 * hp->items.nel : hp->inel;
+ hp->items.next = (char *)malloc( hp->items.more * hp->items.size );
+
+ hp->items.lists[i].nel = hp->items.more;
+ hp->items.lists[i].base = hp->items.next;
+ hp->items.nel += hp->items.more;
+
+ if( hp->tab.base )
+ free( (char *)hp->tab.base );
+
+ hp->tab.nel = hp->items.nel * hp->bloat;
+ hp->tab.base = (ITEM **)malloc( hp->tab.nel * sizeof(ITEM **) );
+
+ memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
+
+ for( i = 0; i < hp->items.list; i++ )
+ {
+ int nel = hp->items.lists[i].nel;
+ char *next = hp->items.lists[i].base;
+
+ for( ; nel--; next += hp->items.size )
+ {
+ register ITEM *i = (ITEM *)next;
+ ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
+
+ i->hdr.next = *ip;
+ *ip = i;
+ }
+ }
+}
+
+void hashenumerate( struct hash *hp, void (*f)(void*,void*), void* data )
+{
+ int i;
+ for( i = 0; i <= hp->items.list; i++ )
+ {
+ char *next = hp->items.lists[i].base;
+ int nel = hp->items.lists[i].nel;
+ if ( i == hp->items.list )
+ nel -= hp->items.more;
+
+ for( ; nel--; next += hp->items.size )
+ {
+ register ITEM *i = (ITEM *)next;
+ f(&i->data, data);
+ }
+ }
+}
+
+/* --- */
+
+# define ALIGNED(x) ( ( x + sizeof( ITEM ) - 1 ) & ~( sizeof( ITEM ) - 1 ) )
+
+/*
+ * hashinit() - initialize a hash table, returning a handle
+ */
+
+struct hash *
+hashinit(
+ int datalen,
+ char *name )
+{
+ struct hash *hp = (struct hash *)malloc( sizeof( *hp ) );
+
+ hp->bloat = 3;
+ hp->tab.nel = 0;
+ hp->tab.base = (ITEM **)0;
+ hp->items.more = 0;
+ hp->items.datalen = datalen;
+ hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
+ hp->items.list = -1;
+ hp->items.nel = 0;
+ hp->inel = 11;
+ hp->name = name;
+
+ return hp;
+}
+
+/*
+ * hashdone() - free a hash table, given its handle
+ */
+
+void
+hashdone( struct hash *hp )
+{
+ int i;
+
+ if( !hp )
+ return;
+
+ if( DEBUG_MEM )
+ hashstat( hp );
+
+ if( hp->tab.base )
+ free( (char *)hp->tab.base );
+ for( i = 0; i <= hp->items.list; i++ )
+ free( hp->items.lists[i].base );
+ free( (char *)hp );
+}
+
+/* ---- */
+
+static void
+hashstat( struct hash *hp )
+{
+ ITEM **tab = hp->tab.base;
+ int nel = hp->tab.nel;
+ int count = 0;
+ int sets = 0;
+ int run = ( tab[ nel - 1 ] != (ITEM *)0 );
+ int i, here;
+
+ for( i = nel; i > 0; i-- )
+ {
+ if( here = ( *tab++ != (ITEM *)0 ) )
+ count++;
+ if( here && !run )
+ sets++;
+ run = here;
+ }
+
+ printf( "%s table: %d+%d+%d (%dK+%dK) items+table+hash, %f density\n",
+ hp->name,
+ count,
+ hp->items.nel,
+ hp->tab.nel,
+ hp->items.nel * hp->items.size / 1024,
+ hp->tab.nel * sizeof( ITEM ** ) / 1024,
+ (float)count / (float)sets );
+}
diff --git a/jam_src/hash.h b/jam_src/hash.h
new file mode 100644
index 000000000..a9fd4ce17
--- /dev/null
+++ b/jam_src/hash.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * hash.h - simple in-memory hashing routines
+ */
+
+typedef struct hashdata HASHDATA;
+
+struct hash * hashinit( int datalen, char *name );
+int hashitem( struct hash *hp, HASHDATA **data, int enter );
+void hashdone( struct hash *hp );
+void hashenumerate( struct hash *hp, void (*f)(void*,void*), void* data );
+
+# define hashenter( hp, data ) !hashitem( hp, data, !0 )
+# define hashcheck( hp, data ) hashitem( hp, data, 0 )
diff --git a/jam_src/hdrmacro.c b/jam_src/hdrmacro.c
new file mode 100644
index 000000000..a59de44e3
--- /dev/null
+++ b/jam_src/hdrmacro.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "compile.h"
+# include "rules.h"
+# include "variable.h"
+# include "regexp.h"
+# include "hdrmacro.h"
+# include "hash.h"
+# include "newstr.h"
+# include "strings.h"
+
+/*
+ * hdrmacro.c - handle header files that define macros used in
+ * #include statements.
+ *
+ * we look for lines like "#define MACRO <....>" or '#define MACRO " "'
+ * in the target file. When found, we
+ *
+ * we then phony up a rule invocation like:
+ *
+ * $(HDRRULE) : ;
+ *
+ * External routines:
+ * headers1() - scan a target for "#include MACRO" lines and try
+ * to resolve them when needed
+ *
+ * Internal routines:
+ * headers1() - using regexp, scan a file and build include LIST
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule,
+ * so that headers() doesn't have to mock up a parse structure
+ * just to invoke a rule.
+ */
+
+static LIST *header_macros1( LIST *l, char *file, int rec, regexp *re[] );
+
+/* this type is used to store a dictionary of file header macros */
+typedef struct header_macro
+{
+ char* symbol;
+ char* filename; /* we could maybe use a LIST here ?? */
+
+} HEADER_MACRO;
+
+static struct hash* header_macros_hash = 0;
+
+/*
+ * headers() - scan a target for include files and call HDRRULE
+ */
+
+# define MAXINC 10
+
+void
+macro_headers( TARGET *t )
+{
+ LIST *hdrrule;
+ static regexp *re = 0;
+ FILE *f;
+ char buf[ 1024 ];
+ int i;
+
+ if ( DEBUG_HEADER )
+ printf( "macro header scan for %s\n", t->name );
+
+ /* this regexp is used to detect lines of the form */
+ /* "#define MACRO <....>" or "#define MACRO "....." */
+ /* in the header macro files.. */
+ if ( re == 0 )
+ {
+ re = regex_compile(
+ "^[ ]*#[ ]*define[ ]*([A-Za-z][A-Za-z0-9_]*)[ ]*"
+ "[<\"]([^\">]*)[\">].*$" );
+ }
+
+ if( !( f = fopen( t->boundname, "r" ) ) )
+ return;
+
+ while( fgets( buf, sizeof( buf ), f ) )
+ {
+ HEADER_MACRO var, *v = &var;
+
+ if ( regexec( re, buf ) && re->startp[1] )
+ {
+ /* we detected a line that looks like "#define MACRO filename */
+ re->endp[1][0] = '\0';
+ re->endp[2][0] = '\0';
+
+ if ( DEBUG_HEADER )
+ printf( "macro '%s' used to define filename '%s' in '%s'\n",
+ re->startp[1], re->startp[2], t->boundname );
+
+ /* add macro definition to hash table */
+ if ( !header_macros_hash )
+ header_macros_hash = hashinit( sizeof( HEADER_MACRO ), "hdrmacros" );
+
+ v->symbol = re->startp[1];
+ v->filename = 0;
+ if ( hashenter( header_macros_hash, (HASHDATA **)&v ) )
+ {
+ v->symbol = newstr( re->startp[1] ); /* never freed */
+ v->filename = newstr( re->startp[2] ); /* never freed */
+ }
+ /* XXXX: FOR NOW, WE IGNORE MULTIPLE MACRO DEFINITIONS !! */
+ /* WE MIGHT AS WELL USE A LIST TO STORE THEM.. */
+ }
+ }
+
+ fclose( f );
+}
+
+
+char*
+macro_header_get( const char* macro_name )
+{
+ HEADER_MACRO var, *v = &var;
+
+ v->symbol = (char*)macro_name;
+
+ if( header_macros_hash && hashcheck( header_macros_hash, (HASHDATA **)&v ) )
+ {
+ if ( DEBUG_HEADER )
+ printf( "### macro '%s' evaluated to '%s'\n", macro_name, v->filename );
+ return v->filename;
+ }
+ return 0;
+}
+
diff --git a/jam_src/hdrmacro.h b/jam_src/hdrmacro.h
new file mode 100644
index 000000000..08cc11160
--- /dev/null
+++ b/jam_src/hdrmacro.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * hdrmacro.h - parses header files for #define MACRO or
+ * #define MACRO "filename" definitions
+ */
+
+void macro_headers( TARGET *t );
+
+char* macro_header_get( const char* macro_name );
diff --git a/jam_src/headers.c b/jam_src/headers.c
new file mode 100644
index 000000000..78a9beda1
--- /dev/null
+++ b/jam_src/headers.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "compile.h"
+# include "rules.h"
+# include "variable.h"
+# include "regexp.h"
+# include "headers.h"
+# include "hdrmacro.h"
+# include "newstr.h"
+
+/*
+ * headers.c - handle #includes in source files
+ *
+ * Using regular expressions provided as the variable $(HDRSCAN),
+ * headers() searches a file for #include files and phonies up a
+ * rule invocation:
+ *
+ * $(HDRRULE) : ;
+ *
+ * External routines:
+ * headers() - scan a target for include files and call HDRRULE
+ *
+ * Internal routines:
+ * headers1() - using regexp, scan a file and build include LIST
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule,
+ * so that headers() doesn't have to mock up a parse structure
+ * just to invoke a rule.
+ */
+
+static LIST *headers1( LIST *l, char *file, int rec, regexp *re[],
+ regexp* re_macros );
+
+/*
+ * headers() - scan a target for include files and call HDRRULE
+ */
+
+# define MAXINC 10
+
+void
+headers( TARGET *t )
+{
+ LIST *hdrscan;
+ LIST *hdrrule;
+ LIST *headlist = 0;
+ regexp *re[ MAXINC ];
+ int rec = 0;
+
+ /* the following regexp is used to detect cases where a */
+ /* file is included through a line line "#include MACRO" */
+ static regexp *re_macros = 0;
+ if ( re_macros == 0 )
+ {
+ re_macros = regex_compile(
+ "^[ ]*#[ ]*include[ ]*([A-Za-z][A-Za-z0-9_]*).*$" );
+ }
+
+ if( !( hdrscan = var_get( "HDRSCAN" ) ) ||
+ !( hdrrule = var_get( "HDRRULE" ) ) )
+ return;
+
+ if( DEBUG_HEADER )
+ printf( "header scan %s\n", t->name );
+
+ /* Compile all regular expressions in HDRSCAN */
+
+ while( rec < MAXINC && hdrscan )
+ {
+ re[rec++] = regex_compile( hdrscan->string );
+ hdrscan = list_next( hdrscan );
+ }
+
+ /* Doctor up call to HDRRULE rule */
+ /* Call headers1() to get LIST of included files. */
+ {
+ FRAME frame[1];
+ frame_init( frame );
+ lol_add( frame->args, list_new( L0, t->name ) );
+ lol_add( frame->args, headers1( headlist, t->boundname, rec, re, re_macros ) );
+
+ if( lol_get( frame->args, 1 ) )
+ evaluate_rule( hdrrule->string, frame );
+
+ /* Clean up */
+
+ frame_free( frame );
+ }
+}
+
+/*
+ * headers1() - using regexp, scan a file and build include LIST
+ */
+
+static LIST *
+headers1(
+ LIST *l,
+ char *file,
+ int rec,
+ regexp *re[],
+ regexp *re_macros )
+{
+ FILE *f;
+ char buf[ 1024 ];
+ int i;
+
+ if( !( f = fopen( file, "r" ) ) )
+ return l;
+
+ while( fgets( buf, sizeof( buf ), f ) )
+ {
+ for( i = 0; i < rec; i++ )
+ if( regexec( re[i], buf ) && re[i]->startp[1] )
+ {
+ re[i]->endp[1][0] = '\0';
+
+ if( DEBUG_HEADER )
+ printf( "header found: %s\n", re[i]->startp[1] );
+
+ l = list_new( l, newstr( re[i]->startp[1] ) );
+ }
+
+ /* special treatment for #include MACRO */
+ if ( regexec( re_macros, buf ) && re_macros->startp[1] )
+ {
+ char* header_filename;
+
+ re_macros->endp[1][0] = '\0';
+
+ if ( DEBUG_HEADER )
+ printf( "macro header found: %s", re_macros->startp[1] );
+
+ header_filename = macro_header_get( re_macros->startp[1] );
+ if (header_filename)
+ {
+ if ( DEBUG_HEADER )
+ printf( " resolved to '%s'\n", header_filename );
+ l = list_new( l, newstr( header_filename ) );
+ }
+ else
+ {
+ if ( DEBUG_HEADER )
+ printf( " ignored !!\n" );
+ }
+ }
+ }
+
+ fclose( f );
+
+ return l;
+}
+
+void
+regerror( char *s )
+{
+ printf( "re error %s\n", s );
+}
diff --git a/jam_src/headers.h b/jam_src/headers.h
new file mode 100644
index 000000000..8c33735c6
--- /dev/null
+++ b/jam_src/headers.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * headers.h - handle #includes in source files
+ */
+
+void headers( TARGET *t );
diff --git a/jam_src/jam.c b/jam_src/jam.c
new file mode 100644
index 000000000..92965f3a1
--- /dev/null
+++ b/jam_src/jam.c
@@ -0,0 +1,385 @@
+/*
+ * /+\
+ * +\ Copyright 1993, 2000 Christopher Seiwald.
+ * \+/
+ *
+ * This file is part of jam.
+ *
+ * License is hereby granted to use this software and distribute it
+ * freely, as long as this copyright notice is retained and modifications
+ * are clearly marked.
+ *
+ * ALL WARRANTIES ARE HEREBY DISCLAIMED.
+ */
+
+/*
+ * jam.c - make redux
+ *
+ * See Jam.html and Jamlang.html for usage information.
+ *
+ * These comments document the code.
+ *
+ * The top half of the code is structured such:
+ *
+ * jam
+ * / | \
+ * +---+ | \
+ * / | \
+ * jamgram option \
+ * / | \ \
+ * / | \ \
+ * / | \ |
+ * scan | compile make
+ * | | / \ / | \
+ * | | / \ / | \
+ * | | / \ / | \
+ * jambase parse rules search make1
+ * | | \
+ * | | \
+ * | | \
+ * timestamp command execute
+ *
+ *
+ * The support routines are called by all of the above, but themselves
+ * are layered thus:
+ *
+ * variable|expand
+ * / | | |
+ * / | | |
+ * / | | |
+ * lists | | filesys
+ * \ | |
+ * \ | |
+ * \ | |
+ * newstr |
+ * \ |
+ * \ |
+ * \ |
+ * hash
+ *
+ * Roughly, the modules are:
+ *
+ * command.c - maintain lists of commands
+ * compile.c - compile parsed jam statements
+ * execunix.c - execute a shell script on UNIX
+ * execvms.c - execute a shell script, ala VMS
+ * expand.c - expand a buffer, given variable values
+ * fileunix.c - manipulate file names and scan directories on UNIX
+ * filevms.c - manipulate file names and scan directories on VMS
+ * fileos2.c - manipulate file names and scan directories on OS/2
+ * filent.c - manipulate file names and scan directories on Windows
+ * hash.c - simple in-memory hashing routines
+ * hdrmacro.c - handle header file parsing for filename macro definitions
+ * headers.c - handle #includes in source files
+ * jambase.c - compilable copy of Jambase
+ * jamgram.y - jam grammar
+ * lists.c - maintain lists of strings
+ * make.c - bring a target up to date, once rules are in place
+ * make1.c - execute command to bring targets up to date
+ * newstr.c - string manipulation routines
+ * option.c - command line option processing
+ * parse.c - make and destroy parse trees as driven by the parser
+ * regexp.c - Henry Spencer's regexp
+ * rules.c - access to RULEs, TARGETs, and ACTIONs
+ * scan.c - the jam yacc scanner
+ * search.c - find a target along $(SEARCH) or $(LOCATE)
+ * timestamp.c - get the timestamp of a file or archive member
+ * variable.c - handle jam multi-element variables
+ *
+ * 05/04/94 (seiwald) - async multiprocess (-j) support
+ * 02/08/95 (seiwald) - -n implies -d2.
+ * 02/22/95 (seiwald) - -v for version info.
+ * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
+ */
+
+# include "jam.h"
+# include "option.h"
+# include "patchlevel.h"
+
+/* These get various function declarations. */
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "compile.h"
+# include "rules.h"
+# include "newstr.h"
+# include "scan.h"
+# include "timestamp.h"
+# include "make.h"
+
+/* Macintosh is "special" */
+
+# ifdef OS_MAC
+# include
+# endif
+
+/* And UNIX for this */
+
+# ifdef unix
+# include
+# endif
+
+struct globs globs = {
+ 0, /* noexec */
+ 1, /* jobs */
+# ifdef OS_MAC
+ { 0, 0 }, /* debug - suppress tracing output */
+# else
+ { 0, 1 }, /* debug ... */
+# endif
+ 0 /* output commands, not run them */
+} ;
+
+/* Symbols to be defined as true for use in Jambase */
+
+static char *othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 } ;
+
+/* Known for sure:
+ * mac needs arg_enviro
+ * OS2 needs extern environ
+ */
+
+# ifdef OS_MAC
+# define use_environ arg_environ
+# ifdef MPW
+QDGlobals qd;
+# endif
+# endif
+
+/* on Win32-LCC */
+# if defined( OS_NT ) && defined( __LCC__ )
+# define use_environ _environ
+# endif
+
+
+# ifndef use_environ
+# define use_environ environ
+# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
+extern char **environ;
+# endif
+# endif
+
+extern int yydebug;
+
+#ifndef NDEBUG
+static void run_unit_tests()
+{
+ var_expand_unit_test();
+}
+#endif
+
+int main( int argc, char **argv, char **arg_environ )
+{
+ int n;
+ char *s;
+ struct option optv[N_OPTS];
+ char *all = "all";
+ int anyhow = 0;
+ int status;
+
+# ifdef OS_MAC
+ InitGraf(&qd.thePort);
+# endif
+
+ argc--, argv++;
+
+ if( ( n = getoptions( argc, argv, "d:j:f:s:t:ano:v", optv ) ) < 0 )
+ {
+ printf( "\nusage: jam [ options ] targets...\n\n" );
+
+ printf( "-a Build all targets, even if they are current.\n" );
+ printf( "-dx Set the debug level to x (0-9).\n" );
+ printf( "-fx Read x instead of Jambase.\n" );
+ printf( "-jx Run up to x shell commands concurrently.\n" );
+ printf( "-n Don't actually execute the updating actions.\n" );
+ printf( "-ox Write the updating actions to file x.\n" );
+ printf( "-sx=y Set variable x=y, overriding environment.\n" );
+ printf( "-tx Rebuild x, even if it is up-to-date.\n" );
+ printf( "-v Print the version of jam and exit.\n\n" );
+
+ exit( EXITBAD );
+ }
+
+ argc -= n, argv += n;
+
+ /* Version info. */
+
+ if( ( s = getoptval( optv, 'v', 0 ) ) )
+ {
+ printf( "Jam/MR " );
+ printf( "Version %s. ", VERSION );
+ printf( "Copyright 1993, 2000 Christopher Seiwald. " );
+ printf( "%s.\n", OSMINOR );
+
+ return EXITOK;
+ }
+
+ /* Pick up interesting options */
+
+ if( ( s = getoptval( optv, 'n', 0 ) ) )
+ globs.noexec++, globs.debug[2] = 1;
+
+ if( ( s = getoptval( optv, 'a', 0 ) ) )
+ anyhow++;
+
+ if( ( s = getoptval( optv, 'j', 0 ) ) )
+ globs.jobs = atoi( s );
+
+ /* Turn on/off debugging */
+
+ for( n = 0; s = getoptval( optv, 'd', n ); n++ )
+ {
+ int i;
+
+ /* First -d, turn off defaults. */
+
+ if( !n )
+ for( i = 0; i < DEBUG_MAX; i++ )
+ globs.debug[i] = 0;
+
+ i = atoi( s );
+
+ if( i < 0 || i >= DEBUG_MAX )
+ {
+ printf( "Invalid debug level '%s'.\n", s );
+ continue;
+ }
+
+ /* n turns on levels 1-n */
+ /* +n turns on level n */
+
+ if( *s == '+' )
+ globs.debug[i] = 1;
+ else while( i )
+ globs.debug[i--] = 1;
+ }
+
+#ifndef NDEBUG
+ run_unit_tests();
+#endif // NDEBUG
+ if ( DEBUG_PARSE )
+ yydebug = 1;
+
+ /* Set JAMDATE first */
+
+ {
+ char *date;
+ time_t clock;
+ time( &clock );
+ date = newstr( ctime( &clock ) );
+
+ /* Trim newline from date */
+
+ if( strlen( date ) == 25 )
+ date[ 24 ] = 0;
+
+ var_set( "JAMDATE", list_new( L0, newstr( date ) ), VAR_SET );
+ }
+
+ var_set( "JAM_VERSION",
+ list_new( list_new( L0, newstr( "03" ) ), newstr( "00" ) ),
+ VAR_SET );
+
+ /* And JAMUNAME */
+# ifdef unix
+ {
+ struct utsname u;
+
+ if( uname( &u ) >= 0 )
+ {
+ var_set( "JAMUNAME",
+ list_new(
+ list_new(
+ list_new(
+ list_new(
+ list_new( L0,
+ newstr( u.sysname ) ),
+ newstr( u.nodename ) ),
+ newstr( u.release ) ),
+ newstr( u.version ) ),
+ newstr( u.machine ) ), VAR_SET );
+ }
+ }
+# endif /* unix */
+
+ /*
+ * Jam defined variables OS, OSPLAT
+ */
+
+ var_defines( othersyms );
+
+ /* load up environment variables */
+
+ var_defines( use_environ );
+
+ /* Load up variables set on command line. */
+
+ for( n = 0; s = getoptval( optv, 's', n ); n++ )
+ {
+ char *symv[2];
+ symv[0] = s;
+ symv[1] = 0;
+ var_defines( symv );
+ }
+
+ /* Initialize builtins */
+
+
+ compile_builtins();
+
+ /* Parse ruleset */
+
+ {
+ FRAME frame[1];
+ frame_init( frame );
+ for( n = 0; s = getoptval( optv, 'f', n ); n++ )
+ parse_file( s, frame );
+
+ if( !n )
+ parse_file( "+", frame );
+ }
+
+ status = yyanyerrors();
+
+ /* Manually touch -t targets */
+
+ for( n = 0; s = getoptval( optv, 't', n ); n++ )
+ touchtarget( s );
+
+ /* If an output file is specified, set globs.cmdout to that */
+
+ if( s = getoptval( optv, 'o', 0 ) )
+ {
+ if( !( globs.cmdout = fopen( s, "w" ) ) )
+ {
+ printf( "Failed to write to '%s'\n", s );
+ exit( EXITBAD );
+ }
+ globs.noexec++;
+ }
+
+ /* Now make target */
+
+ if( !argc )
+ status |= make( 1, &all, anyhow );
+ else
+ status |= make( argc, argv, anyhow );
+
+ if ( DEBUG_PROFILE )
+ profile_dump();
+
+ /* Widely scattered cleanup */
+
+ var_done();
+ donerules();
+ donestamps();
+ donestr();
+
+ /* close cmdout */
+
+ if( globs.cmdout )
+ fclose( globs.cmdout );
+
+ return status ? EXITBAD : EXITOK;
+}
diff --git a/jam_src/jam.h b/jam_src/jam.h
new file mode 100644
index 000000000..90267fc86
--- /dev/null
+++ b/jam_src/jam.h
@@ -0,0 +1,483 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jam.h - includes and globals for jam
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 04/21/94 (seiwald) - DGUX is __DGUX__, not just __DGUX.
+ * 05/04/94 (seiwald) - new globs.jobs (-j jobs)
+ * 11/01/94 (wingerd) - let us define path of Jambase at compile time.
+ * 12/30/94 (wingerd) - changed command buffer size for NT (MS-DOS shell).
+ * 02/22/95 (seiwald) - Jambase now in /usr/local/lib.
+ * 04/30/95 (seiwald) - FreeBSD added. Live Free or Die.
+ * 05/10/95 (seiwald) - SPLITPATH character set up here.
+ * 08/20/95 (seiwald) - added LINUX.
+ * 08/21/95 (seiwald) - added NCR.
+ * 10/23/95 (seiwald) - added SCO.
+ * 01/03/96 (seiwald) - SINIX (nixdorf) added.
+ * 03/13/96 (seiwald) - Jambase now compiled in; remove JAMBASE variable.
+ * 04/29/96 (seiwald) - AIX now has 31 and 42 OSVERs.
+ * 11/21/96 (peterk) - added BeOS with MW CW mwcc
+ * 12/21/96 (seiwald) - OSPLAT now defined for NT.
+ * 07/19/99 (sickel) - Mac OS X Server and Client support added
+ * 02/18/00 (belmonte)- Support for Cygwin.
+ * 09/12/00 (seiwald) - OSSYMS split to OSMAJOR/OSMINOR/OSPLAT
+ * 12/29/00 (seiwald) - OSVER dropped.
+ */
+
+/*
+ * VMS, OPENVMS
+ */
+
+# ifdef VMS
+
+int unlink( char *f ); /* In filevms.c */
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# define OSMINOR "OS=VMS"
+# define OSMAJOR "VMS=true"
+# define OS_VMS
+# define MAXLINE 1024 /* longest 'together' actions */
+# define SPLITPATH ','
+# define EXITOK 1
+# define EXITBAD 0
+# define DOWNSHIFT_PATHS
+
+/* This may be inaccurate */
+# ifndef __DECC
+# define OSPLAT "OSPLAT=VAX"
+# endif
+
+# endif
+
+/*
+ * Windows NT
+ */
+
+# ifdef NT
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# define OSMAJOR "NT=true"
+# define OSMINOR "OS=NT"
+# define OS_NT
+# define SPLITPATH ';'
+/* Windows NT 3.51 only allows 996 chars per line, but we deal */
+/* with problem in "execnt.c". */
+# define MAXLINE 2047 /* longest 'together' actions */
+# define USE_EXECNT
+# define USE_PATHUNIX
+# define PATH_DELIM '\\'
+# define DOWNSHIFT_PATHS
+
+/* AS400 cross-compile from NT */
+
+# ifdef AS400
+# undef OSMINOR
+# undef OSMAJOR
+# define OSMAJOR "AS400=true"
+# define OSMINOR "OS=AS400"
+# define OS_AS400
+# endif
+
+# endif
+
+/*
+ * OS2
+ */
+
+# ifdef __OS2__
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# define OSMAJOR "OS2=true"
+# define OSMINOR "OS=OS2"
+# define OS_OS2
+# define SPLITPATH ';'
+# define MAXLINE 996 /* longest 'together' actions */
+# define USE_EXECUNIX
+# define USE_PATHUNIX
+# define PATH_DELIM '\\'
+# define DOWNSHIFT_PATHS
+
+# ifdef __EMX__
+# define USE_FILEUNIX
+# endif
+
+# endif
+
+/*
+ * Macintosh MPW
+ */
+
+# ifdef macintosh
+
+# include
+# include
+# include
+# include
+
+# define OSMAJOR "MAC=true"
+# define OSMINOR "OS=MAC"
+# define OS_MAC
+# define SPLITPATH ','
+
+# endif
+
+/*
+ * God fearing UNIX
+ */
+
+# ifndef OSMINOR
+
+# define OSMAJOR "UNIX=true"
+# define USE_EXECUNIX
+# define USE_FILEUNIX
+# define USE_PATHUNIX
+# define PATH_DELIM '/'
+
+# ifdef _AIX
+# define unix
+# define OSMINOR "OS=AIX"
+# define OS_AIX
+# define NO_VFORK
+# endif
+# ifdef AMIGA
+# define OSMINOR "OS=AMIGA"
+# define OS_AMIGA
+# endif
+# ifdef __BEOS__
+# define unix
+# define OSMINOR "OS=BEOS"
+# define OS_BEOS
+# define NO_VFORK
+# endif
+# ifdef __bsdi__
+# define OSMINOR "OS=BSDI"
+# define OS_BSDI
+# endif
+# if defined (COHERENT) && defined (_I386)
+# define OSMINOR "OS=COHERENT"
+# define OS_COHERENT
+# define NO_VFORK
+# endif
+# ifdef __cygwin__
+# define OSMINOR "OS=CYGWIN"
+# define OS_CYGWIN
+# endif
+# ifdef __FreeBSD__
+# define OSMINOR "OS=FREEBSD"
+# define OS_FREEBSD
+# endif
+# ifdef __DGUX__
+# define OSMINOR "OS=DGUX"
+# define OS_DGUX
+# endif
+# ifdef __hpux
+# define OSMINOR "OS=HPUX"
+# define OS_HPUX
+# endif
+# ifdef __OPENNT
+# define unix
+# define OSMINOR "OS=INTERIX"
+# define OS_INTERIX
+# define NO_VFORK
+# endif
+# ifdef __sgi
+# define OSMINOR "OS=IRIX"
+# define OS_IRIX
+# define NO_VFORK
+# endif
+# ifdef __ISC
+# define OSMINOR "OS=ISC"
+# define OS_ISC
+# define NO_VFORK
+# endif
+# ifdef linux
+# define OSMINOR "OS=LINUX"
+# define OS_LINUX
+# endif
+# ifdef __Lynx__
+# define OSMINOR "OS=LYNX"
+# define OS_LYNX
+# define NO_VFORK
+# define unix
+# endif
+# ifdef __MACHTEN__
+# define OSMINOR "OS=MACHTEN"
+# define OS_MACHTEN
+# endif
+# ifdef mpeix
+# define unix
+# define OSMINOR "OS=MPEIX"
+# define OS_MPEIX
+# define NO_VFORK
+# endif
+# ifdef __MVS__
+# define unix
+# define OSMINOR "OS=MVS"
+# define OS_MVS
+# endif
+# ifdef _ATT4
+# define OSMINOR "OS=NCR"
+# define OS_NCR
+# endif
+# ifdef __NetBSD__
+# define unix
+# define OSMINOR "OS=NETBSD"
+# define OS_NETBSD
+# define NO_VFORK
+# endif
+# ifdef __QNX__
+# ifdef __QNXNTO__
+# define OSMINOR "OS=QNXNTO"
+# define OS_QNXNTO
+# else
+# define unix
+# define OSMINOR "OS=QNX"
+# define OS_QNX
+# define NO_VFORK
+# define MAXLINE 996
+# endif
+# endif
+# ifdef NeXT
+# ifdef __APPLE__
+# define OSMINOR "OS=RHAPSODY"
+# define OS_RHAPSODY
+# else
+# define OSMINOR "OS=NEXT"
+# define OS_NEXT
+# endif
+# endif
+# ifdef __APPLE__
+# define unix
+# define OSMINOR "OS=MACOSX"
+# define OS_MACOSX
+# endif
+# ifdef __osf__
+# define OSMINOR "OS=OSF"
+# define OS_OSF
+# endif
+# ifdef _SEQUENT_
+# define OSMINOR "OS=PTX"
+# define OS_PTX
+# endif
+# ifdef M_XENIX
+# define OSMINOR "OS=SCO"
+# define OS_SCO
+# define NO_VFORK
+# endif
+# ifdef sinix
+# define unix
+# define OSMINOR "OS=SINIX"
+# define OS_SINIX
+# endif
+# ifdef sun
+# if defined(__svr4__) || defined(__SVR4)
+# define OSMINOR "OS=SOLARIS"
+# define OS_SOLARIS
+# else
+# define OSMINOR "OS=SUNOS"
+# define OS_SUNOS
+# endif
+# endif
+# ifdef ultrix
+# define OSMINOR "OS=ULTRIX"
+# define OS_ULTRIX
+# endif
+# ifdef _UNICOS
+# define OSMINOR "OS=UNICOS"
+# define OS_UNICOS
+# endif
+# if defined(__USLC__) && !defined(M_XENIX)
+# define OSMINOR "OS=UNIXWARE"
+# define OS_UNIXWARE
+# endif
+# ifndef OSMINOR
+# define OSMINOR "OS=UNKNOWN"
+# endif
+
+/* All the UNIX includes */
+
+# include
+# include
+
+# ifndef OS_MPEIX
+# include
+# endif
+
+# include
+# include
+# include
+# include
+# include
+# include
+
+# ifndef OS_QNX
+# include
+# endif
+
+# ifndef OS_ULTRIX
+# include
+# endif
+
+# if !defined(OS_BSDI) && \
+ !defined(OS_FREEBSD) && \
+ !defined(OS_NEXT) && \
+ !defined(OS_MACHTEN) && \
+ !defined(OS_MACOSX) && \
+ !defined(OS_RHAPSODY) && \
+ !defined(OS_MVS)
+# include
+# endif
+
+# endif
+
+/*
+ * OSPLAT definitions - suppressed when it's a one-of-a-kind
+ */
+
+# if defined( _M_PPC ) || \
+ defined( PPC ) || \
+ defined( ppc ) || \
+ defined( __powerpc__ ) || \
+ defined( __ppc__ )
+# define OSPLAT "OSPLAT=PPC"
+# endif
+
+# if defined( _ALPHA_ ) || \
+ defined( __alpha__ )
+# define OSPLAT "OSPLAT=AXP"
+# endif
+
+# if defined( _i386_ ) || \
+ defined( __i386__ ) || \
+ defined( _M_IX86 )
+# if !defined( OS_FREEBSD ) && \
+ !defined( OS_OS2 ) && \
+ !defined( OS_AS400 )
+# define OSPLAT "OSPLAT=X86"
+# endif
+# endif
+
+# ifdef __sparc__
+# if !defined( OS_SUNOS ) && \
+ !defined( OS_SOLARIS )
+# define OSPLAT "OSPLAT=SPARC"
+# endif
+# endif
+
+# ifdef __mips__
+# if !defined( OS_SGI )
+# define OSPLAT "OSPLAT=MIPS"
+# endif
+# endif
+
+# ifdef __arm__
+# define OSPLAT "OSPLAT=ARM"
+# endif
+
+# if defined( __ia64__ ) || defined( __IA64__ )
+# define OSPLAT "OSPLAT=IA64"
+# endif
+
+# ifdef __s390__
+# define OSPLAT "OSPLAT=390"
+# endif
+
+# ifndef OSPLAT
+# define OSPLAT ""
+# endif
+
+/*
+ * Jam implementation misc.
+ */
+
+# ifndef MAXLINE
+# define MAXLINE 10240 /* longest 'together' actions' */
+# endif
+
+# ifndef EXITOK
+# define EXITOK 0
+# define EXITBAD 1
+# endif
+
+# ifndef SPLITPATH
+# define SPLITPATH ':'
+# endif
+
+/* You probably don't need to muck with these. */
+
+# define MAXSYM 1024 /* longest symbol in the environment */
+# define MAXJPATH 1024 /* longest filename */
+
+# define MAXJOBS 64 /* silently enforce -j limit */
+# define MAXARGC 32 /* words in $(JAMSHELL) */
+
+/* Jam private definitions below. */
+
+# define DEBUG_MAX 12
+
+struct globs {
+ int noexec;
+ int jobs;
+ char debug[DEBUG_MAX];
+ FILE *cmdout; /* print cmds, not run them */
+} ;
+
+extern struct globs globs;
+
+# define DEBUG_MAKE ( globs.debug[ 1 ] ) /* show actions when executed */
+# define DEBUG_MAKEQ ( globs.debug[ 2 ] ) /* show even quiet actions */
+# define DEBUG_EXEC ( globs.debug[ 2 ] ) /* show text of actons */
+# define DEBUG_MAKEPROG ( globs.debug[ 3 ] ) /* show progress of make0 */
+# define DEBUG_BIND ( globs.debug[ 3 ] ) /* show when files bound */
+
+# define DEBUG_EXECCMD ( globs.debug[ 4 ] ) /* show execcmds()'s work */
+
+# define DEBUG_COMPILE ( globs.debug[ 5 ] ) /* show rule invocations */
+
+# define DEBUG_HEADER ( globs.debug[ 6 ] ) /* show result of header scan */
+# define DEBUG_BINDSCAN ( globs.debug[ 6 ] ) /* show result of dir scan */
+# define DEBUG_SEARCH ( globs.debug[ 6 ] ) /* show attempts at binding */
+
+# define DEBUG_VARSET ( globs.debug[ 7 ] ) /* show variable settings */
+# define DEBUG_VARGET ( globs.debug[ 8 ] ) /* show variable fetches */
+# define DEBUG_VAREXP ( globs.debug[ 8 ] ) /* show variable expansions */
+# define DEBUG_IF ( globs.debug[ 8 ] ) /* show 'if' calculations */
+# define DEBUG_LISTS ( globs.debug[ 9 ] ) /* show list manipulation */
+# define DEBUG_SCAN ( globs.debug[ 9 ] ) /* show scanner tokens */
+# define DEBUG_MEM ( globs.debug[ 9 ] ) /* show memory use */
+
+# define DEBUG_PROFILE ( globs.debug[ 10 ] ) /* dump rule execution times */
+# define DEBUG_PARSE ( globs.debug[ 11 ] ) /* debug parsing */
+
diff --git a/jam_src/jambase.c b/jam_src/jambase.c
new file mode 100644
index 000000000..a478931ef
--- /dev/null
+++ b/jam_src/jambase.c
@@ -0,0 +1,1554 @@
+/* Generated by mkjambase from Jambase */
+char *jambase[] = {
+/* Jambase */
+"if $(BOOST_ROOT)\n",
+"{\n",
+"BOOST_BUILD_PATH ?= $(BOOST_ROOT)/tools/build ;\n",
+"}\n",
+"if $(BOOST_BUILD_PATH)\n",
+"{\n",
+"JAMBASE ?= boost-build.jam ;\n",
+"}\n",
+"if $(JAMBASE)\n",
+"{\n",
+"JAMBASE = $(JAMBASE:G=jam-module) ; # puts the Jambase target in a different\n",
+"SEARCH on $(JAMBASE) = $(JAMBASE_PATH) $(BOOST_BUILD_PATH) ;\n",
+"include $(JAMBASE) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"if $(NT)\n",
+"{\n",
+"local SUPPORTED_TOOLSETS = \"BORLANDC\" \"VISUALC\" \"VISUALC16\" \"INTELC\" \"WATCOM\"\n",
+"\"MINGW\" \"LCC\" ;\n",
+"TOOLSET = \"\" ;\n",
+"if $(JAM_TOOLSET)\n",
+"{\n",
+"local t ;\n",
+"for t in $(SUPPORTED_TOOLSETS)\n",
+"{\n",
+"if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"ECHO \"The JAM_TOOLSET environment variable is defined but its value\" ;\n",
+"ECHO \"is invalid, please use one of the following:\" ;\n",
+"ECHO ;\n",
+"for t in $(SUPPORTED_TOOLSETS) { ECHO \" \" $(t) ; }\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"if $(BCCROOT)\n",
+"{\n",
+"TOOLSET = BORLANDC ;\n",
+"BORLANDC = $(BCCROOT) ;\n",
+"}\n",
+"else if $(MSVC)\n",
+"{\n",
+"TOOLSET = VISUALC16 ;\n",
+"VISUALC16 = $(MSVC) ;\n",
+"}\n",
+"else if $(MSVCNT)\n",
+"{\n",
+"TOOLSET = VISUALC ;\n",
+"VISUALC = $(MSVCNT) ;\n",
+"}\n",
+"else if $(MINGW)\n",
+"{\n",
+"TOOLSET = MINGW ;\n",
+"}\n",
+"else\n",
+"{\n",
+"ECHO \"Jam cannot be run because you didn't indicate which compilation toolset\" ;\n",
+"ECHO \"to use. To do so, follow these simple instructions:\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define one of the following environment variable, with the\" ;\n",
+"ECHO \" appropriate value according to this list:\" ;\n",
+"ECHO ;\n",
+"ECHO \" Variable Toolset Description\" ;\n",
+"ECHO ;\n",
+"ECHO \" BORLANDC Borland C++ BC++ install path\" ;\n",
+"ECHO \" VISUALC Microsoft Visual C++ VC++ install path\" ;\n",
+"ECHO \" VISUALC16 Microsoft Visual C++ 16 bit VC++ 16 bit install\" ;\n",
+"ECHO \" INTELC Intel C/C++ IC++ install path\" ;\n",
+"ECHO \" WATCOM Watcom C/C++ Watcom install path\" ;\n",
+"ECHO \" MINGW MinGW (gcc) MinGW install path\" ;\n",
+"ECHO \" LCC Win32-LCC LCC-Win32 install path\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define the JAM_TOOLSET environment variable with the *name*\" ;\n",
+"ECHO \" of the toolset variable you want to use.\" ;\n",
+"ECHO ;\n",
+"ECHO \" e.g.: set VISUALC=C:\\Visual6\" ;\n",
+"ECHO \" set JAM_TOOLSET=VISUALC\" ;\n",
+"ECHO ;\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"CP ?= copy ;\n",
+"RM ?= del /f/q ;\n",
+"SLASH ?= \\\\ ;\n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .obj ;\n",
+"SUFEXE ?= .exe ;\n",
+"if $(TOOLSET) = BORLANDC\n",
+"{\n",
+"ECHO \"Compiler is Borland C++\" ;\n",
+"AR ?= tlib /C /P64 ;\n",
+"CC ?= bcc32 ;\n",
+"CCFLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus ;\n",
+"C++ ?= bcc32 ;\n",
+"C++FLAGS ?= -q -y -d -v -w-par -w-ccc -w-rch -w-pro -w-aus -P ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= $(CCFLAGS) ;\n",
+"STDLIBPATH ?= $(BORLANDC)\\\\lib ;\n",
+"STDHDRS ?= $(BORLANDC)\\\\include ;\n",
+"NOARSCAN ?= true ;\n",
+"}\n",
+"else if $(TOOLSET) = VISUALC16\n",
+"{\n",
+"ECHO \"Compiler is Microsoft Visual C++ 16 bit\" ;\n",
+"AR ?= lib /nologo ;\n",
+"CC ?= cl /nologo ;\n",
+"CCFLAGS ?= /D \\\"WIN\\\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= $(CCFLAGS) ;\n",
+"LINKLIBS ?= \n",
+"$(VISUALC16)\\\\lib\\\\mlibce.lib\n",
+"$(VISUALC16)\\\\lib\\\\oldnames.lib\n",
+";\n",
+"LINKLIBS ?= ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= \"\" ;\n",
+"STDHDRS ?= $(VISUALC16)\\\\include ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = VISUALC\n",
+"{\n",
+"ECHO \"Compiler is Microsoft Visual C++\" ;\n",
+"AR ?= lib ;\n",
+"AS ?= masm386 ;\n",
+"CC ?= cl /nologo ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= link /nologo ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= $(VISUALC)\\\\lib\\\\advapi32.lib\n",
+"$(VISUALC)\\\\lib\\\\gdi32.lib\n",
+"$(VISUALC)\\\\lib\\\\user32.lib\n",
+"$(VISUALC)\\\\lib\\\\kernel32.lib ;\n",
+"OPTIM ?= \"\" ;\n",
+"STDHDRS ?= $(VISUALC)\\\\include ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = INTELC\n",
+"{\n",
+"ECHO \"Compiler is Intel C/C++\" ;\n",
+"if ! $(VISUALC)\n",
+"{\n",
+"ECHO \"As a special exception, when using the Intel C++ compiler, you need\" ;\n",
+"ECHO \"to define the VISUALC environment variable to indicate the location\" ;\n",
+"ECHO \"of your Visual C++ installation. Aborting..\" ;\n",
+"EXIT ;\n",
+"}\n",
+"AR ?= lib ;\n",
+"AS ?= masm386 ;\n",
+"CC ?= icl /nologo ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= link /nologo ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= $(VISUALC)\\\\lib\\\\advapi32.lib\n",
+"$(VISUALC)\\\\lib\\\\kernel32.lib\n",
+";\n",
+"OPTIM ?= \"\" ;\n",
+"STDHDRS ?= $(INTELC)\\include $(VISUALC)\\\\include ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = WATCOM\n",
+"{\n",
+"ECHO \"Compiler is Watcom C/C++\" ;\n",
+"AR ?= wlib ;\n",
+"CC ?= wcc386 ;\n",
+"CCFLAGS ?= /zq /DWIN32 /I$(WATCOM)\\\\h ; # zq=quiet\n",
+"C++ ?= wpp386 ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"CP ?= copy ;\n",
+"DOT ?= . ;\n",
+"DOTDOT ?= .. ;\n",
+"LINK ?= wcl386 ;\n",
+"LINKFLAGS ?= /zq ; # zq=quiet\n",
+"LINKLIBS ?= ;\n",
+"MV ?= move ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= ;\n",
+"RM ?= del /f ;\n",
+"SLASH ?= \\\\ ;\n",
+"STDHDRS ?= $(WATCOM)\\\\h $(WATCOM)\\\\h\\\\nt ;\n",
+"SUFEXE ?= .exe ;\n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .obj ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = MINGW\n",
+"{\n",
+"ECHO \"Compiler is GCC with Mingw\" ;\n",
+"AR ?= ar -ru ;\n",
+"CC ?= gcc ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= \"\" ;\n",
+"OPTIM ?= ;\n",
+"SUFOBJ = .o ;\n",
+"SUFLIB = .a ;\n",
+"SLASH = / ;\n",
+"}\n",
+"else if $(TOOLSET) = LCC\n",
+"{\n",
+"ECHO \"Compiler is Win32-LCC\" ;\n",
+"AR ?= lcclib ;\n",
+"CC ?= lcc ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= lcclnk ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= \"\" ;\n",
+"OPTIM ?= ;\n",
+"NOARSCAN = true ;\n",
+"}\n",
+"else\n",
+"{\n",
+"EXIT On NT, set BCCROOT, MSVCNT, MINGW or MSVC to the root of the\n",
+"Borland or Microsoft directories. ;\n",
+"}\n",
+"}\n",
+"else if $(OS2)\n",
+"{\n",
+"local SUPPORTED_TOOLSETS = \"EMX\" \"WATCOM\" ;\n",
+"TOOLSET = \"\" ;\n",
+"if $(JAM_TOOLSET)\n",
+"{\n",
+"local t ;\n",
+"for t in $(SUPPORTED_TOOLSETS)\n",
+"{\n",
+"if $(t) = $(JAM_TOOLSET) { TOOLSET = $(t) ; }\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"ECHO \"The JAM_TOOLSET environment variable is defined but its value\" ;\n",
+"ECHO \"is invalid, please use one of the following:\" ;\n",
+"ECHO ;\n",
+"for t in $(SUPPORTED_TOOLSETS) { ECHO \" \" $(t) ; }\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"if ! $(TOOLSET)\n",
+"{\n",
+"if $(watcom)\n",
+"{\n",
+"WATCOM = $(watcom) ;\n",
+"TOOLSET = WATCOM ;\n",
+"}\n",
+"else\n",
+"{\n",
+"ECHO \"Jam cannot be run because you didn't indicate which compilation toolset\" ;\n",
+"ECHO \"to use. To do so, follow these simple instructions:\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define one of the following environment variable, with the\" ;\n",
+"ECHO \" appropriate value according to this list:\" ;\n",
+"ECHO ;\n",
+"ECHO \" Variable Toolset Description\" ;\n",
+"ECHO ;\n",
+"ECHO \" WATCOM Watcom C/C++ Watcom install path\" ;\n",
+"ECHO \" EMX EMX (gcc) EMX install path\" ;\n",
+"ECHO \" VISUALAGE IBM Visual Age C/C++ VisualAge install path\" ;\n",
+"ECHO ;\n",
+"ECHO \" - define the JAM_TOOLSET environment variable with the *name*\" ;\n",
+"ECHO \" of the toolset variable you want to use.\" ;\n",
+"ECHO ;\n",
+"ECHO \" e.g.: set WATCOM=C:\\WATCOM\" ;\n",
+"ECHO \" set JAM_TOOLSET=WATCOM\" ;\n",
+"ECHO ;\n",
+"EXIT ;\n",
+"}\n",
+"}\n",
+"RM = del /f ;\n",
+"CP = copy ;\n",
+"MV ?= move ;\n",
+"DOT ?= . ;\n",
+"DOTDOT ?= .. ;\n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .obj ;\n",
+"SUFEXE ?= .exe ;\n",
+"if $(TOOLSET) = WATCOM\n",
+"{\n",
+"AR ?= wlib ;\n",
+"BINDIR ?= \\\\os2\\\\apps ;\n",
+"CC ?= wcc386 ;\n",
+"CCFLAGS ?= /zq /DOS2 /I$(WATCOM)\\\\h ; # zq=quiet\n",
+"C++ ?= wpp386 ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= wcl386 ;\n",
+"LINKFLAGS ?= /zq ; # zq=quiet\n",
+"LINKLIBS ?= ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= ;\n",
+"SLASH ?= \\\\ ;\n",
+"STDHDRS ?= $(WATCOM)\\\\h ;\n",
+"UNDEFFLAG ?= \"/u _\" ;\n",
+"}\n",
+"else if $(TOOLSET) = EMX\n",
+"{\n",
+"ECHO \"Compiler is GCC-EMX\" ;\n",
+"AR ?= ar -ru ;\n",
+"CC ?= gcc ;\n",
+"CCFLAGS ?= \"\" ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= \"\" ;\n",
+"OPTIM ?= ;\n",
+"SUFOBJ = .o ;\n",
+"SUFLIB = .a ;\n",
+"UNDEFFLAG ?= \"-U\" ;\n",
+"SLASH = / ;\n",
+"}\n",
+"else\n",
+"{\n",
+"EXIT \"Sorry, but the $(JAM_TOOLSET) toolset isn't supported for now\" ;\n",
+"}\n",
+"}\n",
+"else if $(VMS)\n",
+"{\n",
+"C++ ?= cxx ;\n",
+"C++FLAGS ?= ;\n",
+"CC ?= cc ;\n",
+"CCFLAGS ?= ;\n",
+"CHMOD ?= set file/prot= ;\n",
+"CP ?= copy/replace ;\n",
+"CRELIB ?= true ;\n",
+"DOT ?= [] ;\n",
+"DOTDOT ?= [-] ;\n",
+"EXEMODE ?= (w:e) ;\n",
+"FILEMODE ?= (w:r) ;\n",
+"HDRS ?= ;\n",
+"LINK ?= link ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"LINKLIBS ?= ;\n",
+"MKDIR ?= create/dir ;\n",
+"MV ?= rename ;\n",
+"OPTIM ?= \"\" ;\n",
+"RM ?= delete ;\n",
+"RUNVMS ?= mcr ;\n",
+"SHELLMODE ?= (w:er) ;\n",
+"SLASH ?= . ;\n",
+"STDHDRS ?= decc$library_include ;\n",
+"SUFEXE ?= .exe ;\n",
+"SUFLIB ?= .olb ;\n",
+"SUFOBJ ?= .obj ;\n",
+"switch $(OS) \n",
+"{\n",
+"case OPENVMS : CCFLAGS ?= /stand=vaxc ;\n",
+"case VMS : LINKLIBS ?= sys$library:vaxcrtl.olb/lib ;\n",
+"}\n",
+"}\n",
+"else if $(MAC)\n",
+"{\n",
+"local OPT ;\n",
+"CW ?= \"{CW}\" ;\n",
+"MACHDRS ?=\n",
+"\"$(UMACHDRS):Universal:Interfaces:CIncludes\"\n",
+"\"$(CW):MSL:MSL_C:MSL_Common:Include\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Include\" ;\n",
+"MACLIBS ?=\n",
+"\"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Interfacelib\"\n",
+"\"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Mathlib\" ;\n",
+"MPWLIBS ?= \n",
+"\"$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW.Lib\" ;\n",
+"MPWNLLIBS ?= \n",
+"\"$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL MPWCRuntime.lib\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC MPW(NL).Lib\" ;\n",
+"SIOUXHDRS ?= ;\n",
+"SIOUXLIBS ?= \n",
+"\"$(CW):MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.lib\"\n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL SIOUX.PPC.Lib\" \n",
+"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL C.PPC.Lib\" ;\n",
+"C++ ?= mwcppc ;\n",
+"C++FLAGS ?= -w off -nomapcr ;\n",
+"CC ?= mwcppc ;\n",
+"CCFLAGS ?= -w off -nomapcr ;\n",
+"CP ?= duplicate -y ;\n",
+"DOT ?= \":\" ;\n",
+"DOTDOT ?= \"::\" ;\n",
+"HDRS ?= $(MACHDRS) $(MPWHDRS) ;\n",
+"LINK ?= mwlinkppc ;\n",
+"LINKFLAGS ?= -mpwtool -warn ; \n",
+"LINKLIBS ?= $(MACLIBS) $(MPWLIBS) ; \n",
+"MKDIR ?= newfolder ;\n",
+"MV ?= rename -y ;\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= ;\n",
+"RM ?= delete -y ;\n",
+"SLASH ?= \":\" ;\n",
+"STDHDRS ?= ; \n",
+"SUFLIB ?= .lib ;\n",
+"SUFOBJ ?= .o ;\n",
+"}\n",
+"else if $(OS) = BEOS && $(METROWERKS)\n",
+"{\n",
+"AR ?= mwld -xml -o ;\n",
+"BINDIR ?= /boot/apps ;\n",
+"CC ?= mwcc ;\n",
+"CCFLAGS ?= -nosyspath ;\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= -nosyspath ;\n",
+"FORTRAN ?= \"\" ;\n",
+"LIBDIR ?= /boot/develop/libraries ;\n",
+"LINK ?= mwld ;\n",
+"LINKFLAGS ?= \"\" ;\n",
+"MANDIR ?= /boot/documentation/\"Shell Tools\"/HTML ;\n",
+"NOARSCAN ?= true ;\n",
+"STDHDRS ?= /boot/develop/headers/posix ;\n",
+"}\n",
+"else if $(OS) = BEOS \n",
+"{\n",
+"BINDIR ?= /boot/apps ;\n",
+"CC ?= gcc ;\n",
+"C++ ?= $(CC) ;\n",
+"FORTRAN ?= \"\" ;\n",
+"LIBDIR ?= /boot/develop/libraries ;\n",
+"LINK ?= gcc ;\n",
+"LINKLIBS ?= -lnet ;\n",
+"NOARSCAN ?= true ;\n",
+"STDHDRS ?= /boot/develop/headers/posix ;\n",
+"}\n",
+"else if $(UNIX)\n",
+"{\n",
+"switch $(OS)\n",
+"{\n",
+"case AIX :\n",
+"LINKLIBS ?= -lbsd ;\n",
+"case AMIGA :\n",
+"CC ?= gcc ;\n",
+"YACC ?= bison ;\n",
+"case CYGWIN : \n",
+"CC ?= gcc ;\n",
+"CCFLAGS += -D__cygwin__ ;\n",
+"LEX ?= flex ;\n",
+"JAMSHELL ?= sh -c ;\n",
+"RANLIB ?= \"\" ;\n",
+"SUFEXE ?= .exe ;\n",
+"YACC ?= bison ;\n",
+"case DGUX :\n",
+"RANLIB ?= \"\" ;\n",
+"RELOCATE ?= true ;\n",
+"case HPUX :\n",
+"RANLIB ?= \"\" ;\n",
+"case INTERIX :\n",
+"CC ?= gcc ;\n",
+"JAMSHELL ?= sh -c ;\n",
+"RANLIB ?= \"\" ;\n",
+"case IRIX :\n",
+"RANLIB ?= \"\" ;\n",
+"case MPEIX :\n",
+"CC ?= gcc ;\n",
+"C++ ?= gcc ;\n",
+"CCFLAGS += -D_POSIX_SOURCE ;\n",
+"HDRS += /usr/include ;\n",
+"RANLIB ?= \"\" ; \n",
+"NOARSCAN ?= true ;\n",
+"NOARUPDATE ?= true ;\n",
+"case MVS :\n",
+"RANLIB ?= \"\" ; \n",
+"case NEXT :\n",
+"AR ?= libtool -o ;\n",
+"RANLIB ?= \"\" ;\n",
+"case MACOSX :\n",
+"AR ?= libtool -o ;\n",
+"C++ ?= c++ ;\n",
+"MANDIR ?= /usr/local/share/man ;\n",
+"RANLIB ?= \"\" ;\n",
+"case NCR :\n",
+"RANLIB ?= \"\" ;\n",
+"case PTX :\n",
+"RANLIB ?= \"\" ;\n",
+"case QNX :\n",
+"AR ?= wlib ;\n",
+"CC ?= cc ;\n",
+"CCFLAGS ?= -Q ; # quiet\n",
+"C++ ?= $(CC) ;\n",
+"C++FLAGS ?= -Q ; # quiet\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= -Q ; # quiet\n",
+"NOARSCAN ?= true ;\n",
+"RANLIB ?= \"\" ;\n",
+"case SCO :\n",
+"RANLIB ?= \"\" ;\n",
+"RELOCATE ?= true ;\n",
+"case SINIX :\n",
+"RANLIB ?= \"\" ;\n",
+"case SOLARIS :\n",
+"RANLIB ?= \"\" ;\n",
+"AR ?= \"/usr/ccs/bin/ar ru\" ;\n",
+"case UNICOS :\n",
+"NOARSCAN ?= true ;\n",
+"OPTIM ?= -O0 ;\n",
+"case UNIXWARE :\n",
+"RANLIB ?= \"\" ;\n",
+"RELOCATE ?= true ;\n",
+"}\n",
+"CCFLAGS ?= ;\n",
+"C++FLAGS ?= $(CCFLAGS) ;\n",
+"CHMOD ?= chmod ;\n",
+"LEX ?= lex ;\n",
+"LINKFLAGS ?= $(CCFLAGS) ;\n",
+"LINKLIBS ?= ;\n",
+"OPTIM ?= -O ;\n",
+"RANLIB ?= ranlib ;\n",
+"YACC ?= yacc ;\n",
+"YACCFILES ?= y.tab ;\n",
+"YACCFLAGS ?= -d ;\n",
+"}\n",
+"AR ?= ar ru ;\n",
+"AS ?= as ;\n",
+"ASFLAGS ?= ;\n",
+"AWK ?= awk ;\n",
+"BINDIR ?= /usr/local/bin ;\n",
+"C++ ?= cc ;\n",
+"C++FLAGS ?= ;\n",
+"CC ?= cc ;\n",
+"CCFLAGS ?= ;\n",
+"CP ?= cp -f ;\n",
+"CRELIB ?= ;\n",
+"DOT ?= . ;\n",
+"DOTDOT ?= .. ;\n",
+"EXEMODE ?= 711 ;\n",
+"FILEMODE ?= 644 ;\n",
+"FORTRAN ?= f77 ;\n",
+"FORTRANFLAGS ?= ;\n",
+"HDRS ?= ;\n",
+"JAMFILE ?= Jamfile ;\n",
+"JAMRULES ?= Jamrules ;\n",
+"LEX ?= ;\n",
+"LIBDIR ?= /usr/local/lib ;\n",
+"LINK ?= $(CC) ;\n",
+"LINKFLAGS ?= ;\n",
+"LINKLIBS ?= ;\n",
+"LN ?= ln ;\n",
+"MANDIR ?= /usr/local/man ;\n",
+"MKDIR ?= mkdir ;\n",
+"MV ?= mv -f ;\n",
+"OPTIM ?= ;\n",
+"RCP ?= rcp ;\n",
+"RM ?= rm -f ;\n",
+"RSH ?= rsh ;\n",
+"SED ?= sed ;\n",
+"SHELLHEADER ?= \"#!/bin/sh\" ;\n",
+"SHELLMODE ?= 755 ;\n",
+"SLASH ?= / ;\n",
+"STDHDRS ?= /usr/include ;\n",
+"SUFEXE ?= \"\" ;\n",
+"SUFLIB ?= .a ;\n",
+"SUFOBJ ?= .o ;\n",
+"UNDEFFLAG ?= \"-u _\" ;\n",
+"YACC ?= ;\n",
+"YACCFILES ?= ;\n",
+"YACCFLAGS ?= ;\n",
+"HDRPATTERN = \n",
+"\"^[ ]*#[ ]*include[ ]*[<\\\"]([^\\\">]*)[\\\">].*$\" ;\n",
+"OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;\n",
+"DEPENDS all : shell files lib exe obj ;\n",
+"DEPENDS all shell files lib exe obj : first ;\n",
+"NOTFILE all first shell files lib exe obj dirs clean uninstall ;\n",
+"ALWAYS clean uninstall ;\n",
+"rule As\n",
+"{\n",
+"DEPENDS $(<) : $(>) ;\n",
+"ASFLAGS on $(<) += $(ASFLAGS) $(SUBDIRASFLAGS) ;\n",
+"}\n",
+"rule Bulk\n",
+"{\n",
+"local i ;\n",
+"for i in $(>)\n",
+"{\n",
+"File $(i:D=$(<)) : $(i) ;\n",
+"}\n",
+"}\n",
+"rule Cc\n",
+"{\n",
+"local _h ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) ;\n",
+"if $(RELOCATE)\n",
+"{\n",
+"CcMv $(<) : $(>) ;\n",
+"}\n",
+"_h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;\n",
+"if $(VMS) && $(_h)\n",
+"{\n",
+"SLASHINC on $(<) = \"/inc=(\" $(_h[1]) ,$(_h[2-]) \")\" ;\n",
+"}\n",
+"else if $(MAC) && $(_h)\n",
+"{\n",
+"local _i _j ;\n",
+"_j = $(_h[1]) ;\n",
+"for _i in $(_h[2-])\n",
+"{\n",
+"_j = $(_j),$(_i) ;\n",
+"}\n",
+"MACINC on $(<) = \\\"$(_j)\\\" ;\n",
+"}\n",
+"}\n",
+"rule C++\n",
+"{\n",
+"local _h ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) ;\n",
+"if $(RELOCATE)\n",
+"{\n",
+"CcMv $(<) : $(>) ;\n",
+"}\n",
+"_h = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;\n",
+"if $(VMS) && $(_h)\n",
+"{\n",
+"SLASHINC on $(<) = \"/inc=(\" $(_h[1]) ,$(_h[2-]) \")\" ;\n",
+"}\n",
+"else if $(MAC) && $(_h)\n",
+"{\n",
+"local _i _j ;\n",
+"_j = $(_h[1]) ;\n",
+"for _i in $(_h[2-])\n",
+"{\n",
+"_j = $(_j),$(_i) ;\n",
+"}\n",
+"MACINC on $(<) = \\\"$(_j)\\\" ;\n",
+"}\n",
+"}\n",
+"rule Chmod\n",
+"{\n",
+"if $(CHMOD) { Chmod1 $(<) ; }\n",
+"}\n",
+"rule File\n",
+"{\n",
+"DEPENDS files : $(<) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"MODE on $(<) = $(FILEMODE) ;\n",
+"Chmod $(<) ;\n",
+"}\n",
+"rule Fortran\n",
+"{\n",
+"DEPENDS $(<) : $(>) ;\n",
+"}\n",
+"rule GenFile \n",
+"{\n",
+"local _t = [ FGristSourceFiles $(<) ] ;\n",
+"local _s = [ FAppendSuffix $(>[1]) : $(SUFEXE) ] ;\n",
+"Depends $(_t) : $(_s) $(>[2-]) ;\n",
+"GenFile1 $(_t) : $(_s) $(>[2-]) ;\n",
+"Clean clean : $(_t) ;\n",
+"}\n",
+"rule GenFile1\n",
+"{\n",
+"MakeLocate $(<) : $(LOCATE_SOURCE) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"}\n",
+"rule HardLink\n",
+"{\n",
+"DEPENDS files : $(<) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"}\n",
+"rule HdrMacroFile\n",
+"{\n",
+"HDRMACRO $(<) ;\n",
+"}\n",
+"rule HdrRule\n",
+"{\n",
+"local s ;\n",
+"if $(HDRGRIST) \n",
+"{ \n",
+"s = $(>:G=$(HDRGRIST)) ;\n",
+"} else { \n",
+"s = $(>) ; \n",
+"}\n",
+"INCLUDES $(<) : $(s) ;\n",
+"SEARCH on $(s) = $(HDRSEARCH) ;\n",
+"NOCARE $(s) ;\n",
+"HDRSEARCH on $(s) = $(HDRSEARCH) ;\n",
+"HDRSCAN on $(s) = $(HDRSCAN) ;\n",
+"HDRRULE on $(s) = $(HDRRULE) ;\n",
+"HDRGRIST on $(s) = $(HDRGRIST) ;\n",
+"}\n",
+"rule InstallInto\n",
+"{\n",
+"local i t ;\n",
+"t = $(>:G=installed) ;\n",
+"DEPENDS install : $(t) ;\n",
+"DEPENDS $(t) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"MakeLocate $(t) : $(<) ;\n",
+"Clean uninstall : $(t) ;\n",
+"for i in $(>)\n",
+"{\n",
+"Install $(i:G=installed) : $(i) ;\n",
+"}\n",
+"Chmod $(t) ;\n",
+"if $(UNIX)\n",
+"{\n",
+"if $(OWNER) { Chown $(t) ; OWNER on $(t) = $(OWNER) ; }\n",
+"if $(GROUP) { Chgrp $(t) ; GROUP on $(t) = $(GROUP) ; }\n",
+"}\n",
+"}\n",
+"rule InstallBin\n",
+"{\n",
+"local _t = [ FAppendSuffix $(>) : $(SUFEXE) ] ;\n",
+"InstallInto $(<) : $(_t) ;\n",
+"MODE on $(_t:G=installed) = $(EXEMODE) ;\n",
+"}\n",
+"rule InstallFile\n",
+"{\n",
+"InstallInto $(<) : $(>) ;\n",
+"MODE on $(>:G=installed) = $(FILEMODE) ;\n",
+"}\n",
+"rule InstallLib\n",
+"{\n",
+"InstallInto $(<) : $(>) ;\n",
+"MODE on $(>:G=installed) = $(FILEMODE) ;\n",
+"}\n",
+"rule InstallMan\n",
+"{\n",
+"local i s d ;\n",
+"for i in $(>)\n",
+"{\n",
+"switch $(i:S)\n",
+"{\n",
+"case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;\n",
+"case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;\n",
+"case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;\n",
+"case .n : s = n ; case .man : s = 1 ;\n",
+"}\n",
+"d = man$(s) ;\n",
+"InstallInto $(d:R=$(<)) : $(i) ;\n",
+"}\n",
+"MODE on $(>:G=installed) = $(FILEMODE) ;\n",
+"}\n",
+"rule InstallShell\n",
+"{\n",
+"InstallInto $(<) : $(>) ;\n",
+"MODE on $(>:G=installed) = $(SHELLMODE) ;\n",
+"}\n",
+"rule Lex\n",
+"{\n",
+"LexMv $(<) : $(>) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"MakeLocate $(<) : $(LOCATE_SOURCE) ;\n",
+"Clean clean : $(<) ;\n",
+"}\n",
+"rule Library\n",
+"{\n",
+"LibraryFromObjects $(<) : $(>:S=$(SUFOBJ)) ;\n",
+"Objects $(>) ;\n",
+"}\n",
+"rule LibraryFromObjects\n",
+"{\n",
+"local _i _l _s ;\n",
+"_s = [ FGristFiles $(>) ] ;\n",
+"_l = $(<:S=$(SUFLIB)) ;\n",
+"if $(KEEPOBJS)\n",
+"{\n",
+"DEPENDS obj : $(_s) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"DEPENDS lib : $(_l) ;\n",
+"}\n",
+"if ! $(_l:D)\n",
+"{\n",
+"MakeLocate $(_l) $(_l)($(_s:BS)) : $(LOCATE_TARGET) ;\n",
+"}\n",
+"if $(NOARSCAN) \n",
+"{ \n",
+"DEPENDS $(_l) : $(_s) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"DEPENDS $(_l) : $(_l)($(_s:BS)) ;\n",
+"for _i in $(_s)\n",
+"{\n",
+"DEPENDS $(_l)($(_i:BS)) : $(_i) ;\n",
+"}\n",
+"}\n",
+"Clean clean : $(_l) ;\n",
+"if $(CRELIB) { CreLib $(_l) : $(_s[1]) ; }\n",
+"Archive $(_l) : $(_s) ;\n",
+"if $(RANLIB) { Ranlib $(_l) ; }\n",
+"if ! ( $(NOARSCAN) || $(KEEPOBJS) ) { RmTemps $(_l) : $(_s) ; }\n",
+"}\n",
+"rule Link\n",
+"{\n",
+"MODE on $(<) = $(EXEMODE) ;\n",
+"Chmod $(<) ;\n",
+"}\n",
+"rule LinkLibraries\n",
+"{\n",
+"local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;\n",
+"DEPENDS $(_t) : $(>:S=$(SUFLIB)) ;\n",
+"NEEDLIBS on $(_t) += $(>:S=$(SUFLIB)) ;\n",
+"}\n",
+"rule Main\n",
+"{\n",
+"MainFromObjects $(<) : $(>:S=$(SUFOBJ)) ;\n",
+"Objects $(>) ;\n",
+"}\n",
+"rule MainFromObjects\n",
+"{\n",
+"local _s _t ;\n",
+"_s = [ FGristFiles $(>) ] ;\n",
+"_t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;\n",
+"if $(_t) != $(<)\n",
+"{\n",
+"DEPENDS $(<) : $(_t) ;\n",
+"NOTFILE $(<) ;\n",
+"}\n",
+"DEPENDS exe : $(_t) ;\n",
+"DEPENDS $(_t) : $(_s) ;\n",
+"MakeLocate $(_t) : $(LOCATE_TARGET) ;\n",
+"Clean clean : $(_t) ;\n",
+"Link $(_t) : $(_s) ;\n",
+"}\n",
+"rule MakeLocate\n",
+"{\n",
+"if $(>)\n",
+"{\n",
+"LOCATE on $(<) = $(>) ;\n",
+"Depends $(<) : $(>[1]) ;\n",
+"MkDir $(>[1]) ;\n",
+"}\n",
+"}\n",
+"rule MkDir\n",
+"{\n",
+"NOUPDATE $(<) ;\n",
+"if $(<) != $(DOT) && ! $($(<)-mkdir) \n",
+"{\n",
+"local s ;\n",
+"$(<)-mkdir = true ;\n",
+"MkDir1 $(<) ;\n",
+"Depends dirs : $(<) ;\n",
+"s = $(<:P) ;\n",
+"if $(NT)\n",
+"{\n",
+"switch $(s)\n",
+"{\n",
+"case *: : s = ;\n",
+"case *:\\\\ : s = ;\n",
+"}\n",
+"}\n",
+"if $(s) && $(s) != $(<)\n",
+"{\n",
+"Depends $(<) : $(s) ;\n",
+"MkDir $(s) ;\n",
+"}\n",
+"else if $(s)\n",
+"{\n",
+"NOTFILE $(s) ;\n",
+"}\n",
+"}\n",
+"}\n",
+"rule Object\n",
+"{\n",
+"local h ;\n",
+"Clean clean : $(<) ;\n",
+"MakeLocate $(<) : $(LOCATE_TARGET) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"HDRS on $(<) = $(SEARCH_SOURCE) $(HDRS) $(SUBDIRHDRS) ;\n",
+"if $(SEARCH_SOURCE)\n",
+"{\n",
+"h = $(SEARCH_SOURCE) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"h = \"\" ;\n",
+"}\n",
+"HDRRULE on $(>) = HdrRule ;\n",
+"HDRSCAN on $(>) = $(HDRPATTERN) ;\n",
+"HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(h) $(STDHDRS) ;\n",
+"HDRGRIST on $(>) = $(HDRGRIST) ;\n",
+"switch $(>:S)\n",
+"{\n",
+"case .asm : As $(<) : $(>) ;\n",
+"case .c : Cc $(<) : $(>) ;\n",
+"case .C : C++ $(<) : $(>) ;\n",
+"case .cc : C++ $(<) : $(>) ;\n",
+"case .cpp : C++ $(<) : $(>) ;\n",
+"case .f : Fortran $(<) : $(>) ;\n",
+"case .l : Cc $(<) : $(<:S=.c) ;\n",
+"Lex $(<:S=.c) : $(>) ;\n",
+"case .s : As $(<) : $(>) ;\n",
+"case .y : Cc $(<) : $(<:S=.c) ;\n",
+"Yacc $(<:S=.c) : $(>) ;\n",
+"case * : UserObject $(<) : $(>) ;\n",
+"}\n",
+"}\n",
+"rule ObjectCcFlags\n",
+"{\n",
+"CCFLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
+"}\n",
+"rule ObjectC++Flags\n",
+"{\n",
+"C++FLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
+"}\n",
+"rule ObjectHdrs\n",
+"{\n",
+"HDRS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
+"}\n",
+"rule Objects\n",
+"{\n",
+"local _i ;\n",
+"for _i in [ FGristFiles $(<) ]\n",
+"{\n",
+"Object $(_i:S=$(SUFOBJ)) : $(_i) ;\n",
+"DEPENDS obj : $(_i:S=$(SUFOBJ)) ;\n",
+"}\n",
+"}\n",
+"rule RmTemps\n",
+"{\n",
+"TEMPORARY $(>) ;\n",
+"}\n",
+"rule Setuid\n",
+"{\n",
+"MODE on [ FAppendSuffix $(<) : $(SUFEXE) ] = 4711 ;\n",
+"}\n",
+"rule Shell\n",
+"{\n",
+"DEPENDS shell : $(<) ;\n",
+"DEPENDS $(<) : $(>) ;\n",
+"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
+"MODE on $(<) = $(SHELLMODE) ;\n",
+"Clean clean : $(<) ;\n",
+"Chmod $(<) ;\n",
+"}\n",
+"rule SubDir\n",
+"{\n",
+"local _r _s ;\n",
+"if ! $($(<[1]))\n",
+"{\n",
+"if ! $(<[1])\n",
+"{\n",
+"EXIT SubDir syntax error ;\n",
+"}\n",
+"$(<[1]) = [ FSubDir $(<[2-]) ] ;\n",
+"}\n",
+"if ! $($(<[1])-included)\n",
+"{\n",
+"$(<[1])-included = TRUE ;\n",
+"_r = $($(<[1])RULES) ;\n",
+"if ! $(_r)\n",
+"{\n",
+"_r = $(JAMRULES:R=$($(<[1]))) ;\n",
+"}\n",
+"include $(_r) ;\n",
+"}\n",
+"_s = [ FDirName $(<[2-]) ] ;\n",
+"SUBDIR = $(_s:R=$($(<[1]))) ;\n",
+"SUBDIR_TOKENS = $(<[2-]) ;\n",
+"SEARCH_SOURCE = $(SUBDIR) ;\n",
+"LOCATE_SOURCE = $(ALL_LOCATE_TARGET) $(SUBDIR) ;\n",
+"LOCATE_TARGET = $(ALL_LOCATE_TARGET) $(SUBDIR) ;\n",
+"SOURCE_GRIST = [ FGrist $(<[2-]) ] ;\n",
+"SUBDIRCCFLAGS = ;\n",
+"SUBDIRC++FLAGS = ;\n",
+"SUBDIRHDRS = ;\n",
+"}\n",
+"rule SubDirCcFlags\n",
+"{\n",
+"SUBDIRCCFLAGS += $(<) ;\n",
+"}\n",
+"rule SubDirC++Flags\n",
+"{\n",
+"SUBDIRC++FLAGS += $(<) ;\n",
+"}\n",
+"rule SubDirHdrs\n",
+"{\n",
+"SUBDIRHDRS += $(<) ;\n",
+"}\n",
+"rule SubInclude\n",
+"{\n",
+"local _s ;\n",
+"if ! $($(<[1]))\n",
+"{\n",
+"EXIT Top level of source tree has not been set with $(<[1]) ;\n",
+"}\n",
+"_s = [ FDirName $(<[2-]) ] ;\n",
+"include $(JAMFILE:D=$(_s):R=$($(<[1]))) ;\n",
+"}\n",
+"rule Undefines\n",
+"{\n",
+"UNDEFS on [ FAppendSuffix $(<) : $(SUFEXE) ] += $(UNDEFFLAG)$(>) ;\n",
+"}\n",
+"rule UserObject\n",
+"{\n",
+"EXIT \"Unknown suffix on\" $(>) \"- see UserObject rule in Jamfile(5).\" ;\n",
+"}\n",
+"rule Yacc\n",
+"{\n",
+"local _h ;\n",
+"_h = $(<:BS=.h) ;\n",
+"MakeLocate $(<) $(_h) : $(LOCATE_SOURCE) ;\n",
+"if $(YACC)\n",
+"{\n",
+"DEPENDS $(<) $(_h) : $(>) ;\n",
+"Yacc1 $(<) $(_h) : $(>) ;\n",
+"YaccMv $(<) $(_h) : $(>) ;\n",
+"Clean clean : $(<) $(_h) ;\n",
+"}\n",
+"INCLUDES $(<) : $(_h) ;\n",
+"}\n",
+"rule FGrist\n",
+"{\n",
+"local _g _i ;\n",
+"_g = $(<[1]) ;\n",
+"for _i in $(<[2-])\n",
+"{\n",
+"_g = $(_g)!$(_i) ;\n",
+"}\n",
+"return $(_g) ;\n",
+"}\n",
+"rule FGristFiles \n",
+"{\n",
+"if ! $(SOURCE_GRIST)\n",
+"{\n",
+"return $(<) ;\n",
+"}\n",
+"else \n",
+"{\n",
+"return $(<:G=$(SOURCE_GRIST)) ;\n",
+"}\n",
+"}\n",
+"rule FGristSourceFiles\n",
+"{\n",
+"if ! $(SOURCE_GRIST)\n",
+"{\n",
+"return $(<) ;\n",
+"}\n",
+"else \n",
+"{\n",
+"local _i _o ;\n",
+"for _i in $(<)\n",
+"{\n",
+"switch $(_i)\n",
+"{\n",
+"case *.h : _o += $(_i) ;\n",
+"case * : _o += $(_i:G=$(SOURCE_GRIST)) ;\n",
+"}\n",
+"}\n",
+"return $(_o) ;\n",
+"}\n",
+"}\n",
+"rule FConcat\n",
+"{\n",
+"local _t _r ;\n",
+"$(_r) = $(<[1]) ;\n",
+"for _t in $(<[2-])\n",
+"{\n",
+"$(_r) = $(_r)$(_t) ;\n",
+"}\n",
+"return $(_r) ;\n",
+"}\n",
+"rule FSubDir\n",
+"{\n",
+"local _i _d ;\n",
+"if ! $(<[1]) \n",
+"{\n",
+"_d = $(DOT) ;\n",
+"} \n",
+"else\n",
+"{\n",
+"_d = $(DOTDOT) ;\n",
+"for _i in $(<[2-])\n",
+"{\n",
+"_d = $(_d:R=$(DOTDOT)) ;\n",
+"}\n",
+"}\n",
+"return $(_d) ;\n",
+"}\n",
+"rule FDirName\n",
+"{\n",
+"local _s _i ;\n",
+"if ! $(<)\n",
+"{\n",
+"_s = $(DOT) ;\n",
+"}\n",
+"else if $(VMS)\n",
+"{\n",
+"switch $(<[1])\n",
+"{\n",
+"case *:* : _s = $(<[1]) ;\n",
+"case \\\\[*\\\\] : _s = $(<[1]) ;\n",
+"case * : _s = [.$(<[1])] ;\n",
+"}\n",
+"for _i in [.$(<[2-])]\n",
+"{\n",
+"_s = $(_i:R=$(_s)) ;\n",
+"}\n",
+"}\n",
+"else if $(MAC)\n",
+"{\n",
+"_s = $(DOT) ;\n",
+"for _i in $(<)\n",
+"{\n",
+"_s = $(_i:R=$(_s)) ;\n",
+"}\n",
+"}\n",
+"else\n",
+"{\n",
+"_s = $(<[1]) ; \n",
+"for _i in $(<[2-])\n",
+"{\n",
+"_s = $(_i:R=$(_s)) ;\n",
+"}\n",
+"}\n",
+"return $(_s) ;\n",
+"}\n",
+"rule _makeCommon\n",
+"{\n",
+"if $($(<)[1]) && $($(<)[1]) = $($(>)[1])\n",
+"{\n",
+"$(<) = $($(<)[2-]) ;\n",
+"$(>) = $($(>)[2-]) ;\n",
+"_makeCommon $(<) : $(>) ;\n",
+"}\n",
+"}\n",
+"rule FRelPath\n",
+"{\n",
+"local _l _r ;\n",
+"_l = $(<) ;\n",
+"_r = $(>) ;\n",
+"_makeCommon _l : _r ;\n",
+"_l = [ FSubDir $(_l) ] ;\n",
+"_r = [ FDirName $(_r) ] ;\n",
+"if $(_r) = $(DOT) {\n",
+"return $(_l) ;\n",
+"} else {\n",
+"return $(_r:R=$(_l)) ;\n",
+"}\n",
+"}\n",
+"rule FAppendSuffix\n",
+"{\n",
+"if $(>)\n",
+"{\n",
+"local _i _o ;\n",
+"for _i in $(<)\n",
+"{\n",
+"if $(_i:S)\n",
+"{\n",
+"_o += $(_i) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"_o += $(_i:S=$(>)) ;\n",
+"}\n",
+"}\n",
+"return $(_o) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"return $(<) ;\n",
+"}\n",
+"}\n",
+"rule unmakeDir\n",
+"{\n",
+"if $(>[1]:D) && $(>[1]:D) != $(>[1]) && $(>[1]:D) != \\\\\\\\ \n",
+"{\n",
+"unmakeDir $(<) : $(>[1]:D) $(>[1]:BS) $(>[2-]) ;\n",
+"}\n",
+"else\n",
+"{\n",
+"$(<) = $(>) ;\n",
+"}\n",
+"}\n",
+"rule FConvertToSlashes\n",
+"{\n",
+"local _d, _s, _i ;\n",
+"unmakeDir _d : $(<) ;\n",
+"_s = $(_d[1]) ; \n",
+"for _i in $(_d[2-])\n",
+"{\n",
+"_s = $(_s)/$(_i) ;\n",
+"}\n",
+"return $(_s) ;\n",
+"}\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) $(>)\n",
+"}\n",
+"actions As\n",
+"{\n",
+"$(AS) $(ASFLAGS) -I$(HDRS) -o $(<) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)\n",
+"}\n",
+"actions Chgrp\n",
+"{\n",
+"chgrp $(GROUP) $(<)\n",
+"}\n",
+"actions Chmod1\n",
+"{\n",
+"$(CHMOD) $(MODE) $(<)\n",
+"}\n",
+"actions Chown\n",
+"{\n",
+"chown $(OWNER) $(<)\n",
+"}\n",
+"actions piecemeal together existing Clean\n",
+"{\n",
+"$(RM) $(>)\n",
+"}\n",
+"actions File\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"actions GenFile1\n",
+"{\n",
+"$(>[1]) $(<) $(>[2-])\n",
+"}\n",
+"actions Fortran\n",
+"{\n",
+"$(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)\n",
+"}\n",
+"actions HardLink\n",
+"{\n",
+"$(RM) $(<) && $(LN) $(>) $(<)\n",
+"}\n",
+"actions Install\n",
+"{\n",
+"$(CP) $(>) $(<) \n",
+"}\n",
+"actions Lex\n",
+"{\n",
+"$(LEX) $(>)\n",
+"}\n",
+"actions LexMv\n",
+"{\n",
+"$(MV) lex.yy.c $(<)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) \n",
+"}\n",
+"actions MkDir1\n",
+"{\n",
+"$(MKDIR) $(<)\n",
+"}\n",
+"actions together Ranlib\n",
+"{\n",
+"$(RANLIB) $(<)\n",
+"}\n",
+"actions quietly updated piecemeal together RmTemps\n",
+"{\n",
+"$(RM) $(>)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(AWK) '\n",
+"NR == 1 { print \"$(SHELLHEADER)\" }\n",
+"NR == 1 && /^[#:]/ { next }\n",
+"/^##/ { next }\n",
+"{ print }\n",
+"' < $(>) > $(<)\n",
+"}\n",
+"actions Yacc1\n",
+"{\n",
+"$(YACC) $(YACCFLAGS) $(>)\n",
+"}\n",
+"actions YaccMv\n",
+"{\n",
+"$(MV) $(YACCFILES).c $(<[1])\n",
+"$(MV) $(YACCFILES).h $(<[2])\n",
+"}\n",
+"if $(RELOCATE)\n",
+"{\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) $(>)\n",
+"}\n",
+"actions ignore CcMv\n",
+"{\n",
+"[ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)\n",
+"}\n",
+"}\n",
+"if $(NOARUPDATE)\n",
+"{\n",
+"actions Archive\n",
+"{\n",
+"$(AR) $(<) $(>)\n",
+"}\n",
+"}\n",
+"if $(NT)\n",
+"{\n",
+"if $(TOOLSET) = VISUALC || $(TOOLSET) = INTELC\n",
+"{\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"if exist $(<) set _$(<:B)_=$(<)\n",
+"$(AR) /out:$(<) %_$(<:B)_% $(>)\n",
+"}\n",
+"actions As\n",
+"{\n",
+"$(AS) /Ml /p /v /w2 $(>) $(<) ,nul,nul;\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /I$(STDHDRS) /Tp$(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = VISUALC16\n",
+"{\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) -+$(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) /c $(CCFLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) /c $(C++FLAGS) $(OPTIM) /Fo$(<) /I$(HDRS) /Tp$(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = BORLANDC\n",
+"{\n",
+"actions updated together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) -+$(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) -e$(<) $(LINKFLAGS) $(UNDEFS) -L$(LINKLIBS) $(NEEDLIBS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = MINGW\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) $(>:T)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = WATCOM\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) +-$(>) \n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = LCC\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) /out:$(<) $(>) \n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) $(CCFLAGS) $(OPTIM) -Fo$(<) -I$(HDRS) $(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"}\n",
+"else if $(OS2) \n",
+"{\n",
+"if $(TOOLSET) = WATCOM\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) +-$(>) \n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) $(CCFLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) $(C++FLAGS) $(OPTIM) /Fo=$(<) /I$(HDRS) $(>)\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"else if $(TOOLSET) = EMX\n",
+"{\n",
+"actions together piecemeal Archive\n",
+"{\n",
+"$(AR) $(<) $(>:T)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"$(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"actions C++\n",
+"{\n",
+"$(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o$(<) $(>)\n",
+"}\n",
+"}\n",
+"}\n",
+"else if $(VMS)\n",
+"{\n",
+"actions updated together piecemeal Archive \n",
+"{\n",
+"lib/replace $(<) $(>[1]) ,$(>[2-])\n",
+"}\n",
+"actions Cc\n",
+"{ \n",
+"$(CC)/obj=$(<) $(CCFLAGS) $(OPTIM) $(SLASHINC) $(>) \n",
+"}\n",
+"actions C++\n",
+"{ \n",
+"$(C++)/obj=$(<) $(C++FLAGS) $(OPTIM) $(SLASHINC) $(>) \n",
+"}\n",
+"actions piecemeal together existing Clean\n",
+"{\n",
+"$(RM) $(>[1]);* ,$(>[2-]);*\n",
+"}\n",
+"actions together quietly CreLib\n",
+"{\n",
+"if f$search(\"$(<)\") .eqs. \"\" then lib/create $(<)\n",
+"}\n",
+"actions GenFile1\n",
+"{\n",
+"mcr $(>[1]) $(<) $(>[2-])\n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK)/exe=$(<) $(LINKFLAGS) $(>[1]) ,$(>[2-]) ,$(NEEDLIBS)/lib ,$(LINKLIBS)\n",
+"}\n",
+"actions quietly updated piecemeal together RmTemps\n",
+"{\n",
+"$(RM) $(>[1]);* ,$(>[2-]);*\n",
+"}\n",
+"actions Shell\n",
+"{\n",
+"$(CP) $(>) $(<)\n",
+"}\n",
+"}\n",
+"else if $(MAC)\n",
+"{\n",
+"actions together Archive \n",
+"{\n",
+"$(LINK) -library -o $(<) $(>)\n",
+"}\n",
+"actions Cc\n",
+"{\n",
+"set -e MWCincludes $(MACINC)\n",
+"$(CC) -o $(<) $(CCFLAGS) $(OPTIM) $(>) \n",
+"}\n",
+"actions C++\n",
+"{ \n",
+"set -e MWCincludes $(MACINC)\n",
+"$(CC) -o $(<) $(C++FLAGS) $(OPTIM) $(>) \n",
+"}\n",
+"actions Link bind NEEDLIBS\n",
+"{\n",
+"$(LINK) -o $(<) $(LINKFLAGS) $(>) $(NEEDLIBS) \"$(LINKLIBS)\"\n",
+"}\n",
+"}\n",
+"rule BULK { Bulk $(<) : $(>) ; }\n",
+"rule FILE { File $(<) : $(>) ; }\n",
+"rule HDRRULE { HdrRule $(<) : $(>) ; }\n",
+"rule INSTALL { Install $(<) : $(>) ; }\n",
+"rule LIBRARY { Library $(<) : $(>) ; }\n",
+"rule LIBS { LinkLibraries $(<) : $(>) ; }\n",
+"rule LINK { Link $(<) : $(>) ; }\n",
+"rule MAIN { Main $(<) : $(>) ; }\n",
+"rule SETUID { Setuid $(<) ; }\n",
+"rule SHELL { Shell $(<) : $(>) ; }\n",
+"rule UNDEFINES { Undefines $(<) : $(>) ; }\n",
+"rule INSTALLBIN { InstallBin $(BINDIR) : $(<) ; }\n",
+"rule INSTALLLIB { InstallLib $(LIBDIR) : $(<) ; }\n",
+"rule INSTALLMAN { InstallMan $(MANDIR) : $(<) ; }\n",
+"rule addDirName { $(<) += [ FDirName $(>) ] ; }\n",
+"rule makeDirName { $(<) = [ FDirName $(>) ] ; }\n",
+"rule makeGristedName { $(<) = [ FGristSourceFiles $(>) ] ; }\n",
+"rule makeRelPath { $(<[1]) = [ FRelPath $(<[2-]) : $(>) ] ; }\n",
+"rule makeSuffixed { $(<[1]) = [ FAppendSuffix $(>) : $(<[2]) ] ; }\n",
+"{\n",
+"if $(JAMFILE) { include $(JAMFILE) ; }\n",
+"}\n",
+"}\n",
+0 };
diff --git a/jam_src/jambase.h b/jam_src/jambase.h
new file mode 100644
index 000000000..75393f4cc
--- /dev/null
+++ b/jam_src/jambase.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jambase.h - declaration for the internal jambase
+ *
+ * The file Jambase is turned into a C array of strings in jambase.c
+ * so that it can be built in to the executable. This is the
+ * declaration for that array.
+ */
+
+extern char *jambase[];
diff --git a/jam_src/jamgram.c b/jam_src/jamgram.c
new file mode 100644
index 000000000..ae916fef5
--- /dev/null
+++ b/jam_src/jamgram.c
@@ -0,0 +1,1212 @@
+
+/* A Bison parser, made from jamgram.y
+ by GNU Bison version 1.28 */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define _BANG 257
+#define _BANG_EQUALS 258
+#define _AMPERAMPER 259
+#define _LPAREN 260
+#define _RPAREN 261
+#define _PLUS_EQUALS 262
+#define _COLON 263
+#define _SEMIC 264
+#define _LANGLE 265
+#define _LANGLE_EQUALS 266
+#define _EQUALS 267
+#define _RANGLE 268
+#define _RANGLE_EQUALS 269
+#define _QUESTION_EQUALS 270
+#define _LBRACKET 271
+#define _RBRACKET 272
+#define ACTIONS 273
+#define BIND 274
+#define CASE 275
+#define DEFAULT 276
+#define ELSE 277
+#define EXISTING 278
+#define FOR 279
+#define IF 280
+#define IGNORE 281
+#define IN 282
+#define INCLUDE 283
+#define LOCAL 284
+#define MODULE 285
+#define ON 286
+#define PIECEMEAL 287
+#define QUIETLY 288
+#define RETURN 289
+#define RULE 290
+#define SWITCH 291
+#define TOGETHER 292
+#define UPDATED 293
+#define WHILE 294
+#define _LBRACE 295
+#define _BARBAR 296
+#define _RBRACE 297
+#define ARG 298
+#define STRING 299
+
+
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "newstr.h"
+
+# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define P0 (PARSE *)0
+# define S0 (char *)0
+
+# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
+# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
+# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
+# define psetmodule( l,r ) parse_make( compile_set_module,l,r,P0,S0,S0,0 )
+# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
+# define psetc( s,p ) parse_make( compile_setcomp,p,P0,P0,s,S0,0 )
+# define psetc_args( s,p,a ) parse_make( compile_setcomp,p,a,P0,s,S0,0 )
+# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#ifndef YYDEBUG
+#define YYDEBUG 1
+#endif
+
+#include
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define YYFINAL 145
+#define YYFLAG -32768
+#define YYNTBASE 46
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 299 ? yytranslate[x] : 64)
+
+static const char yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = { 0,
+ 0, 1, 3, 4, 6, 8, 11, 17, 18, 21,
+ 25, 29, 33, 38, 44, 51, 55, 63, 72, 78,
+ 84, 90, 96, 104, 111, 115, 116, 117, 127, 129,
+ 131, 133, 136, 138, 142, 146, 150, 154, 158, 162,
+ 166, 169, 173, 177, 181, 182, 185, 190, 192, 196,
+ 198, 199, 202, 204, 209, 210, 213, 215, 217, 219,
+ 221, 223, 225, 226
+};
+
+static const short yyrhs[] = { -1,
+ 48, 0, 0, 48, 0, 50, 0, 50, 48, 0,
+ 30, 58, 49, 10, 47, 0, 0, 13, 58, 0,
+ 41, 47, 43, 0, 29, 58, 10, 0, 44, 57,
+ 10, 0, 60, 53, 58, 10, 0, 31, 30, 58,
+ 49, 10, 0, 60, 32, 58, 53, 58, 10, 0,
+ 35, 58, 10, 0, 25, 44, 28, 58, 41, 47,
+ 43, 0, 25, 30, 44, 28, 58, 41, 47, 43,
+ 0, 37, 58, 41, 55, 43, 0, 26, 54, 41,
+ 47, 43, 0, 31, 58, 41, 47, 43, 0, 40,
+ 54, 41, 47, 43, 0, 26, 54, 41, 47, 43,
+ 23, 50, 0, 36, 44, 6, 57, 7, 50, 0,
+ 36, 44, 50, 0, 0, 0, 19, 61, 44, 63,
+ 41, 51, 45, 52, 43, 0, 13, 0, 8, 0,
+ 16, 0, 22, 13, 0, 60, 0, 60, 13, 60,
+ 0, 60, 4, 60, 0, 60, 11, 60, 0, 60,
+ 12, 60, 0, 60, 14, 60, 0, 60, 15, 60,
+ 0, 60, 28, 58, 0, 3, 54, 0, 54, 5,
+ 54, 0, 54, 42, 54, 0, 6, 54, 7, 0,
+ 0, 56, 55, 0, 21, 44, 9, 47, 0, 58,
+ 0, 58, 9, 57, 0, 59, 0, 0, 59, 60,
+ 0, 44, 0, 17, 44, 57, 18, 0, 0, 61,
+ 62, 0, 39, 0, 38, 0, 27, 0, 34, 0,
+ 33, 0, 24, 0, 0, 20, 58, 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+ 125, 127, 138, 140, 144, 146, 148, 152, 154, 158,
+ 160, 162, 164, 166, 168, 170, 172, 174, 176, 178,
+ 180, 182, 184, 186, 188, 190, 193, 195, 202, 204,
+ 206, 208, 216, 218, 220, 222, 224, 226, 228, 230,
+ 232, 234, 236, 238, 248, 250, 254, 263, 265, 275,
+ 279, 281, 285, 287, 297, 299, 303, 305, 307, 309,
+ 311, 313, 322, 324
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = { "$","error","$undefined.","_BANG",
+"_BANG_EQUALS","_AMPERAMPER","_LPAREN","_RPAREN","_PLUS_EQUALS","_COLON","_SEMIC",
+"_LANGLE","_LANGLE_EQUALS","_EQUALS","_RANGLE","_RANGLE_EQUALS","_QUESTION_EQUALS",
+"_LBRACKET","_RBRACKET","ACTIONS","BIND","CASE","DEFAULT","ELSE","EXISTING",
+"FOR","IF","IGNORE","IN","INCLUDE","LOCAL","MODULE","ON","PIECEMEAL","QUIETLY",
+"RETURN","RULE","SWITCH","TOGETHER","UPDATED","WHILE","_LBRACE","_BARBAR","_RBRACE",
+"ARG","STRING","run","block","rules","assign_list_opt","rule","@1","@2","assign",
+"cond","cases","case","lol","list","listp","arg","eflags","eflag","bindlist", NULL
+};
+#endif
+
+static const short yyr1[] = { 0,
+ 46, 46, 47, 47, 48, 48, 48, 49, 49, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 51, 52, 50, 53, 53,
+ 53, 53, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 55, 55, 56, 57, 57, 58,
+ 59, 59, 60, 60, 61, 61, 62, 62, 62, 62,
+ 62, 62, 63, 63
+};
+
+static const short yyr2[] = { 0,
+ 0, 1, 0, 1, 1, 2, 5, 0, 2, 3,
+ 3, 3, 4, 5, 6, 3, 7, 8, 5, 5,
+ 5, 5, 7, 6, 3, 0, 0, 9, 1, 1,
+ 1, 2, 1, 3, 3, 3, 3, 3, 3, 3,
+ 2, 3, 3, 3, 0, 2, 4, 1, 3, 1,
+ 0, 2, 1, 4, 0, 2, 1, 1, 1, 1,
+ 1, 1, 0, 2
+};
+
+static const short yydefact[] = { 1,
+ 0, 55, 0, 0, 51, 51, 51, 51, 0, 51,
+ 0, 3, 53, 2, 5, 0, 51, 0, 0, 0,
+ 0, 0, 53, 0, 33, 0, 50, 8, 51, 0,
+ 0, 0, 0, 0, 0, 4, 0, 48, 6, 30,
+ 29, 31, 0, 51, 51, 0, 62, 59, 61, 60,
+ 58, 57, 63, 56, 0, 51, 41, 0, 0, 3,
+ 0, 0, 0, 0, 0, 0, 0, 51, 11, 52,
+ 51, 0, 8, 3, 16, 51, 25, 45, 3, 10,
+ 12, 51, 32, 0, 0, 54, 51, 0, 51, 0,
+ 44, 42, 0, 43, 35, 36, 37, 34, 38, 39,
+ 40, 9, 3, 0, 0, 0, 0, 0, 45, 0,
+ 49, 51, 13, 64, 26, 0, 3, 20, 7, 14,
+ 21, 0, 0, 19, 46, 22, 0, 0, 3, 0,
+ 0, 24, 3, 15, 27, 0, 17, 23, 47, 0,
+ 18, 28, 0, 0, 0
+};
+
+static const short yydefgoto[] = { 143,
+ 35, 36, 72, 15, 128, 140, 45, 24, 108, 109,
+ 37, 38, 27, 16, 18, 54, 88
+};
+
+static const short yypact[] = { 106,
+ -34,-32768, -13, 8,-32768,-32768, -17,-32768, -16,-32768,
+ 8, 106, 24,-32768, 106, 174,-32768, 95, -15, -12,
+ 8, 8,-32768, 4, 166, 22, -2, 23,-32768, -6,
+ 28, 80, 2, 18, 1,-32768, 39, 45,-32768,-32768,
+-32768,-32768, 42,-32768,-32768, 43,-32768,-32768,-32768,-32768,
+-32768,-32768, 49,-32768, 34,-32768,-32768, 15, 8, 106,
+ 8, -2, -2, -2, -2, -2, -2,-32768,-32768,-32768,
+-32768, 60, 23, 106,-32768,-32768,-32768, 52, 106,-32768,
+-32768,-32768,-32768, 59, 64,-32768,-32768, 36,-32768, 37,
+-32768,-32768, 40, 74,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768, 106, 85, 53, 91, 56, 58, 52, 61,
+-32768,-32768,-32768,-32768,-32768, 67, 106, 79,-32768,-32768,
+-32768, 132, 101,-32768,-32768,-32768, 102, 68, 106, 71,
+ 132,-32768, 106,-32768,-32768, 75,-32768,-32768,-32768, 83,
+-32768,-32768, 127, 130,-32768
+};
+
+static const short yypgoto[] = {-32768,
+ -53, 12, 65, -28,-32768,-32768, 69, -3, 31,-32768,
+ -11, -5,-32768, 26,-32768,-32768,-32768
+};
+
+
+#define YYLAST 206
+
+
+static const short yytable[] = { 26,
+ 28, 30, 31, 77, 33, 46, 93, 34, 59, 17,
+ 21, 14, 29, 22, 1, 56, 19, 57, 58, 59,
+ 105, 91, 59, 73, 1, 110, 39, 32, 55, 25,
+ 20, 69, -51, -51, 74, 71, 25, 75, 84, 85,
+ -51, 23, 78, 80, 60, 61, 25, 25, 81, 119,
+ 90, 23, 70, 82, 83, 92, 61, 94, 79, 61,
+ 86, 89, 101, 130, 106, 102, 40, -51, 87, 103,
+ 111, 41, 107, 113, 42, 136, 115, 117, 59, 139,
+ 43, 114, 118, 116, 25, 76, 25, 95, 96, 97,
+ 98, 99, 100, 132, 120, 121, 1, 122, 2, 123,
+ 124, 131, 138, 126, 3, 4, 127, 129, 5, 133,
+ 7, 134, 135, 137, 8, 9, 10, 141, 47, 11,
+ 12, 48, 1, 13, 2, 142, 144, 49, 50, 145,
+ 3, 4, 51, 52, 5, 6, 7, 104, 53, 125,
+ 8, 9, 10, 0, 0, 11, 12, 0, 1, 13,
+ 2, 0, 112, 0, 0, 0, 3, 4, 0, 0,
+ 5, 0, 7, 0, 0, 0, 8, 9, 10, 62,
+ 0, 11, 12, 0, 0, 13, 63, 64, 65, 66,
+ 67, 40, 0, 0, 0, 0, 41, 0, 0, 42,
+ 0, 0, 0, 68, 0, 43, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 44
+};
+
+static const short yycheck[] = { 5,
+ 6, 7, 8, 32, 10, 17, 60, 11, 5, 44,
+ 3, 0, 30, 6, 17, 28, 30, 21, 22, 5,
+ 74, 7, 5, 29, 17, 79, 15, 44, 44, 4,
+ 44, 10, 9, 10, 41, 13, 11, 10, 44, 45,
+ 17, 44, 41, 43, 41, 42, 21, 22, 10, 103,
+ 56, 44, 27, 9, 13, 59, 42, 61, 41, 42,
+ 18, 28, 68, 117, 76, 71, 8, 44, 20, 10,
+ 82, 13, 21, 10, 16, 129, 41, 41, 5, 133,
+ 22, 87, 43, 89, 59, 6, 61, 62, 63, 64,
+ 65, 66, 67, 122, 10, 43, 17, 7, 19, 44,
+ 43, 23, 131, 43, 25, 26, 112, 41, 29, 9,
+ 31, 10, 45, 43, 35, 36, 37, 43, 24, 40,
+ 41, 27, 17, 44, 19, 43, 0, 33, 34, 0,
+ 25, 26, 38, 39, 29, 30, 31, 73, 44, 109,
+ 35, 36, 37, -1, -1, 40, 41, -1, 17, 44,
+ 19, -1, 84, -1, -1, -1, 25, 26, -1, -1,
+ 29, -1, 31, -1, -1, -1, 35, 36, 37, 4,
+ -1, 40, 41, -1, -1, 44, 11, 12, 13, 14,
+ 15, 8, -1, -1, -1, -1, 13, -1, -1, 16,
+ -1, -1, -1, 28, -1, 22, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 32
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
+#include
+#else /* not sparc */
+#if defined (MSDOS) && !defined (__TURBOC__)
+#include
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+#include
+ #pragma alloca
+#else /* not MSDOS, __TURBOC__, or _AIX */
+#ifdef __hpux
+#ifdef __cplusplus
+extern "C" {
+void *alloca (unsigned int);
+};
+#else /* not __cplusplus */
+void *alloca ();
+#endif /* not __cplusplus */
+#endif /* __hpux */
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc. */
+#endif /* not GNU C. */
+#endif /* alloca not defined. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT return(0)
+#define YYABORT return(1)
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { yychar = (token), yylval = (value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+#ifndef YYPURE
+#define YYLEX yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int yychar; /* the lookahead symbol */
+YYSTYPE yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int yynerrs; /* number of parse errors so far */
+#endif /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+int yyparse (void);
+#endif
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (to, from, count)
+ char *to;
+ char *from;
+ int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (char *to, char *from, int count)
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int yystate;
+ register int yyn;
+ register short *yyssp;
+ register YYSTYPE *yyvsp;
+ int yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short yyssa[YYINITDEPTH]; /* the state stack */
+ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+
+ short *yyss = yyssa; /* refer to the stacks thru separate pointers */
+ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+
+#ifdef YYPURE
+ int yychar;
+ YYSTYPE yylval;
+ int yynerrs;
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylloc;
+#endif
+#endif
+
+ YYSTYPE yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int yylen;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+yynewstate:
+
+ *yyssp++ = yystate;
+
+ if (yyssp >= yyss + yystacksize)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+#else
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+#endif
+
+ yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+ yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror("parser stack overflow");
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+ yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp));
+ yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+ yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size;
+ yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+ if (yyssp >= yyss + yystacksize)
+ YYABORT;
+ }
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+ goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (yyerrstatus) yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+/* Do the default action for the current state. */
+yydefault:
+
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+
+/* Do a reduction. yyn is the number of a rule to reduce with. */
+yyreduce:
+ yylen = yyr2[yyn];
+ if (yylen > 0)
+ yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+
+ switch (yyn) {
+
+case 2:
+{ parse_save( yyvsp[0].parse ); ;
+ break;}
+case 3:
+{ yyval.parse = pnull(); ;
+ break;}
+case 4:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+case 5:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+case 6:
+{ yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); ;
+ break;}
+case 7:
+{ yyval.parse = plocal( yyvsp[-3].parse, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 8:
+{ yyval.parse = pnull(); ;
+ break;}
+case 9:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+case 10:
+{ yyval.parse = yyvsp[-1].parse; ;
+ break;}
+case 11:
+{ yyval.parse = pincl( yyvsp[-1].parse ); ;
+ break;}
+case 12:
+{ yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); ;
+ break;}
+case 13:
+{ yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); ;
+ break;}
+case 14:
+{ yyval.parse = psetmodule( yyvsp[-2].parse, yyvsp[-1].parse ); ;
+ break;}
+case 15:
+{ yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); ;
+ break;}
+case 16:
+{ yyval.parse = yyvsp[-1].parse; ;
+ break;}
+case 17:
+{ yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, 0 ); ;
+ break;}
+case 18:
+{ yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, 1 ); ;
+ break;}
+case 19:
+{ yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); ;
+ break;}
+case 20:
+{ yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); ;
+ break;}
+case 21:
+{ yyval.parse = pmodule( yyvsp[-3].parse, yyvsp[-1].parse ); ;
+ break;}
+case 22:
+{ yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); ;
+ break;}
+case 23:
+{ yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); ;
+ break;}
+case 24:
+{ yyval.parse = psetc_args( yyvsp[-4].string, yyvsp[0].parse, yyvsp[-2].parse ); ;
+ break;}
+case 25:
+{ yyval.parse = psetc( yyvsp[-1].string, yyvsp[0].parse ); ;
+ break;}
+case 26:
+{ yymode( SCAN_STRING ); ;
+ break;}
+case 27:
+{ yymode( SCAN_NORMAL ); ;
+ break;}
+case 28:
+{ yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); ;
+ break;}
+case 29:
+{ yyval.number = ASSIGN_SET; ;
+ break;}
+case 30:
+{ yyval.number = ASSIGN_APPEND; ;
+ break;}
+case 31:
+{ yyval.number = ASSIGN_DEFAULT; ;
+ break;}
+case 32:
+{ yyval.number = ASSIGN_DEFAULT; ;
+ break;}
+case 33:
+{ yyval.parse = pcnode( COND_EXISTS, yyvsp[0].parse, pnull() ); ;
+ break;}
+case 34:
+{ yyval.parse = pcnode( COND_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 35:
+{ yyval.parse = pcnode( COND_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 36:
+{ yyval.parse = pcnode( COND_LESS, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 37:
+{ yyval.parse = pcnode( COND_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 38:
+{ yyval.parse = pcnode( COND_MORE, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 39:
+{ yyval.parse = pcnode( COND_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 40:
+{ yyval.parse = pcnode( COND_IN, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 41:
+{ yyval.parse = pcnode( COND_NOT, yyvsp[0].parse, P0 ); ;
+ break;}
+case 42:
+{ yyval.parse = pcnode( COND_AND, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 43:
+{ yyval.parse = pcnode( COND_OR, yyvsp[-2].parse, yyvsp[0].parse ); ;
+ break;}
+case 44:
+{ yyval.parse = yyvsp[-1].parse; ;
+ break;}
+case 45:
+{ yyval.parse = P0; ;
+ break;}
+case 46:
+{ yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); ;
+ break;}
+case 47:
+{ yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); ;
+ break;}
+case 48:
+{ yyval.parse = pnode( P0, yyvsp[0].parse ); ;
+ break;}
+case 49:
+{ yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); ;
+ break;}
+case 50:
+{ yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); ;
+ break;}
+case 51:
+{ yyval.parse = pnull(); yymode( SCAN_PUNCT ); ;
+ break;}
+case 52:
+{ yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); ;
+ break;}
+case 53:
+{ yyval.parse = plist( yyvsp[0].string ); ;
+ break;}
+case 54:
+{ yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); ;
+ break;}
+case 55:
+{ yyval.number = 0; ;
+ break;}
+case 56:
+{ yyval.number = yyvsp[-1].number | yyvsp[0].number; ;
+ break;}
+case 57:
+{ yyval.number = EXEC_UPDATED; ;
+ break;}
+case 58:
+{ yyval.number = EXEC_TOGETHER; ;
+ break;}
+case 59:
+{ yyval.number = EXEC_IGNORE; ;
+ break;}
+case 60:
+{ yyval.number = EXEC_QUIETLY; ;
+ break;}
+case 61:
+{ yyval.number = EXEC_PIECEMEAL; ;
+ break;}
+case 62:
+{ yyval.number = EXEC_EXISTING; ;
+ break;}
+case 63:
+{ yyval.parse = pnull(); ;
+ break;}
+case 64:
+{ yyval.parse = yyvsp[0].parse; ;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *ssp1++);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+ yylsp++;
+ if (yylen == 0)
+ {
+ yylsp->first_line = yylloc.first_line;
+ yylsp->first_column = yylloc.first_column;
+ yylsp->last_line = (yylsp-1)->last_line;
+ yylsp->last_column = (yylsp-1)->last_column;
+ yylsp->text = 0;
+ }
+ else
+ {
+ yylsp->last_line = (yylsp+yylen-1)->last_line;
+ yylsp->last_column = (yylsp+yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *(yyssp - 1);
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *(yyssp - 1))
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+yyerrlab: /* here on detecting error */
+
+ if (! yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen(yytname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, yytname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ yyerror(msg);
+ free(msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror("parse error");
+ }
+
+ goto yyerrlab1;
+yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (yyn) goto yydefault;
+#endif
+
+yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (yyssp - 1 == yyss) YYABORT;
+ yyvsp--;
+ yyssp--;
+ yystate = *(yyssp - 1);
+#ifdef YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *ssp1++);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+yyerrhandle:
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+}
+
+
diff --git a/jam_src/jamgram.h b/jam_src/jamgram.h
new file mode 100644
index 000000000..74acdd439
--- /dev/null
+++ b/jam_src/jamgram.h
@@ -0,0 +1,49 @@
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#define _BANG 257
+#define _BANG_EQUALS 258
+#define _AMPERAMPER 259
+#define _LPAREN 260
+#define _RPAREN 261
+#define _PLUS_EQUALS 262
+#define _COLON 263
+#define _SEMIC 264
+#define _LANGLE 265
+#define _LANGLE_EQUALS 266
+#define _EQUALS 267
+#define _RANGLE 268
+#define _RANGLE_EQUALS 269
+#define _QUESTION_EQUALS 270
+#define _LBRACKET 271
+#define _RBRACKET 272
+#define ACTIONS 273
+#define BIND 274
+#define CASE 275
+#define DEFAULT 276
+#define ELSE 277
+#define EXISTING 278
+#define FOR 279
+#define IF 280
+#define IGNORE 281
+#define IN 282
+#define INCLUDE 283
+#define LOCAL 284
+#define MODULE 285
+#define ON 286
+#define PIECEMEAL 287
+#define QUIETLY 288
+#define RETURN 289
+#define RULE 290
+#define SWITCH 291
+#define TOGETHER 292
+#define UPDATED 293
+#define WHILE 294
+#define _LBRACE 295
+#define _BARBAR 296
+#define _RBRACE 297
+#define ARG 298
+#define STRING 299
+
+
+extern YYSTYPE yylval;
diff --git a/jam_src/jamgram.y b/jam_src/jamgram.y
new file mode 100644
index 000000000..17569c76c
--- /dev/null
+++ b/jam_src/jamgram.y
@@ -0,0 +1,328 @@
+%token _BANG
+%token _BANG_EQUALS
+%token _AMPERAMPER
+%token _LPAREN
+%token _RPAREN
+%token _PLUS_EQUALS
+%token _COLON
+%token _SEMIC
+%token _LANGLE
+%token _LANGLE_EQUALS
+%token _EQUALS
+%token _RANGLE
+%token _RANGLE_EQUALS
+%token _QUESTION_EQUALS
+%token _LBRACKET
+%token _RBRACKET
+%token ACTIONS
+%token BIND
+%token CASE
+%token DEFAULT
+%token ELSE
+%token EXISTING
+%token FOR
+%token IF
+%token IGNORE
+%token IN
+%token INCLUDE
+%token LOCAL
+%token MODULE
+%token ON
+%token PIECEMEAL
+%token QUIETLY
+%token RETURN
+%token RULE
+%token SWITCH
+%token TOGETHER
+%token UPDATED
+%token WHILE
+%token _LBRACE
+%token _BARBAR
+%token _RBRACE
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jamgram.yy - jam grammar
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ * 08/31/94 (seiwald) - Allow ?= as alias for "default =".
+ * 09/15/94 (seiwald) - if conditionals take only single arguments, so
+ * that 'if foo == bar' gives syntax error (use =).
+ * 02/11/95 (seiwald) - when scanning arguments to rules, only treat
+ * punctuation keywords as keywords. All arg lists
+ * are terminated with punctuation keywords.
+ *
+ * 09/11/00 (seiwald) - Support for function calls:
+ *
+ * Rules now return lists (LIST *), rather than void.
+ *
+ * New "[ rule ]" syntax evals rule into a LIST.
+ *
+ * Lists are now generated by compile_list() and
+ * compile_append(), and any other rule that indirectly
+ * makes a list, rather than being built directly here,
+ * so that lists values can contain rule evaluations.
+ *
+ * New 'return' rule sets the return value, though
+ * other statements also may have return values.
+ *
+ * 'run' production split from 'block' production so
+ * that empty blocks can be handled separately.
+ */
+
+%token ARG STRING
+
+%left _BARBAR
+%left _AMPERAMPER
+%left _BANG
+
+%{
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "newstr.h"
+
+# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define P0 (PARSE *)0
+# define S0 (char *)0
+
+# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
+# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
+# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
+# define psetmodule( l,r ) parse_make( compile_set_module,l,r,P0,S0,S0,0 )
+# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
+# define psetc( s,p ) parse_make( compile_setcomp,p,P0,P0,s,S0,0 )
+# define psetc_args( s,p,a ) parse_make( compile_setcomp,p,a,P0,s,S0,0 )
+# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+%}
+
+%%
+
+run : /* empty */
+ /* do nothing */
+ | rules
+ { parse_save( $1.parse ); }
+ ;
+
+/*
+ * block - zero or more rules
+ * rules - one or more rules
+ * rule - any one of jam's rules
+ * right-recursive so rules execute in order.
+ */
+
+block : /* empty */
+ { $$.parse = pnull(); }
+ | rules
+ { $$.parse = $1.parse; }
+ ;
+
+rules : rule
+ { $$.parse = $1.parse; }
+ | rule rules
+ { $$.parse = prules( $1.parse, $2.parse ); }
+ | LOCAL list assign_list_opt _SEMIC block
+ { $$.parse = plocal( $2.parse, $3.parse, $5.parse ); }
+ ;
+
+assign_list_opt : /* empty */
+ { $$.parse = pnull(); }
+ | _EQUALS list
+ { $$.parse = $2.parse; }
+ ;
+
+rule : _LBRACE block _RBRACE
+ { $$.parse = $2.parse; }
+ | INCLUDE list _SEMIC
+ { $$.parse = pincl( $2.parse ); }
+ | ARG lol _SEMIC
+ { $$.parse = prule( $1.string, $2.parse ); }
+ | arg assign list _SEMIC
+ { $$.parse = pset( $1.parse, $3.parse, $2.number ); }
+ | MODULE LOCAL list assign_list_opt _SEMIC
+ { $$.parse = psetmodule( $3.parse, $4.parse ); }
+ | arg ON list assign list _SEMIC
+ { $$.parse = pset1( $1.parse, $3.parse, $5.parse, $4.number ); }
+ | RETURN list _SEMIC
+ { $$.parse = $2.parse; }
+ | FOR ARG IN list _LBRACE block _RBRACE
+ { $$.parse = pfor( $2.string, $4.parse, $6.parse, 0 ); }
+ | FOR LOCAL ARG IN list _LBRACE block _RBRACE
+ { $$.parse = pfor( $3.string, $5.parse, $7.parse, 1 ); }
+ | SWITCH list _LBRACE cases _RBRACE
+ { $$.parse = pswitch( $2.parse, $4.parse ); }
+ | IF cond _LBRACE block _RBRACE
+ { $$.parse = pif( $2.parse, $4.parse, pnull() ); }
+ | MODULE list _LBRACE block _RBRACE
+ { $$.parse = pmodule( $2.parse, $4.parse ); }
+ | WHILE cond _LBRACE block _RBRACE
+ { $$.parse = pwhile( $2.parse, $4.parse ); }
+ | IF cond _LBRACE block _RBRACE ELSE rule
+ { $$.parse = pif( $2.parse, $4.parse, $7.parse ); }
+ | RULE ARG _LPAREN lol _RPAREN rule
+ { $$.parse = psetc_args( $2.string, $6.parse, $4.parse ); }
+ | RULE ARG rule
+ { $$.parse = psetc( $2.string, $3.parse ); }
+ | ACTIONS eflags ARG bindlist _LBRACE
+ { yymode( SCAN_STRING ); }
+ STRING
+ { yymode( SCAN_NORMAL ); }
+ _RBRACE
+ { $$.parse = psete( $3.string,$4.parse,$7.string,$2.number ); }
+ ;
+
+/*
+ * assign - = or +=
+ */
+
+assign : _EQUALS
+ { $$.number = ASSIGN_SET; }
+ | _PLUS_EQUALS
+ { $$.number = ASSIGN_APPEND; }
+ | _QUESTION_EQUALS
+ { $$.number = ASSIGN_DEFAULT; }
+ | DEFAULT _EQUALS
+ { $$.number = ASSIGN_DEFAULT; }
+ ;
+
+/*
+ * cond - a conditional for 'if'
+ */
+
+cond : arg
+ { $$.parse = pcnode( COND_EXISTS, $1.parse, pnull() ); }
+ | arg _EQUALS arg
+ { $$.parse = pcnode( COND_EQUALS, $1.parse, $3.parse ); }
+ | arg _BANG_EQUALS arg
+ { $$.parse = pcnode( COND_NOTEQ, $1.parse, $3.parse ); }
+ | arg _LANGLE arg
+ { $$.parse = pcnode( COND_LESS, $1.parse, $3.parse ); }
+ | arg _LANGLE_EQUALS arg
+ { $$.parse = pcnode( COND_LESSEQ, $1.parse, $3.parse ); }
+ | arg _RANGLE arg
+ { $$.parse = pcnode( COND_MORE, $1.parse, $3.parse ); }
+ | arg _RANGLE_EQUALS arg
+ { $$.parse = pcnode( COND_MOREEQ, $1.parse, $3.parse ); }
+ | arg IN list
+ { $$.parse = pcnode( COND_IN, $1.parse, $3.parse ); }
+ | _BANG cond
+ { $$.parse = pcnode( COND_NOT, $2.parse, P0 ); }
+ | cond _AMPERAMPER cond
+ { $$.parse = pcnode( COND_AND, $1.parse, $3.parse ); }
+ | cond _BARBAR cond
+ { $$.parse = pcnode( COND_OR, $1.parse, $3.parse ); }
+ | _LPAREN cond _RPAREN
+ { $$.parse = $2.parse; }
+ ;
+
+/*
+ * cases - action elements inside a 'switch'
+ * case - a single action element inside a 'switch'
+ * right-recursive rule so cases can be examined in order.
+ */
+
+cases : /* empty */
+ { $$.parse = P0; }
+ | case cases
+ { $$.parse = pnode( $1.parse, $2.parse ); }
+ ;
+
+case : CASE ARG _COLON block
+ { $$.parse = psnode( $2.string, $4.parse ); }
+ ;
+
+/*
+ * lol - list of lists
+ * right-recursive rule so that lists can be added in order.
+ */
+
+lol : list
+ { $$.parse = pnode( P0, $1.parse ); }
+ | list _COLON lol
+ { $$.parse = pnode( $3.parse, $1.parse ); }
+ ;
+
+/*
+ * list - zero or more args in a LIST
+ * listp - list (in puncutation only mode)
+ * arg - one ARG or function call
+ */
+
+list : listp
+ { $$.parse = $1.parse; yymode( SCAN_NORMAL ); }
+ ;
+
+listp : /* empty */
+ { $$.parse = pnull(); yymode( SCAN_PUNCT ); }
+ | listp arg
+ { $$.parse = pappend( $1.parse, $2.parse ); }
+ ;
+
+arg : ARG
+ { $$.parse = plist( $1.string ); }
+ | _LBRACKET ARG lol _RBRACKET
+ { $$.parse = prule( $2.string, $3.parse ); }
+ ;
+
+
+/*
+ * eflags - zero or more modifiers to 'executes'
+ * eflag - a single modifier to 'executes'
+ */
+
+eflags : /* empty */
+ { $$.number = 0; }
+ | eflags eflag
+ { $$.number = $1.number | $2.number; }
+ ;
+
+eflag : UPDATED
+ { $$.number = EXEC_UPDATED; }
+ | TOGETHER
+ { $$.number = EXEC_TOGETHER; }
+ | IGNORE
+ { $$.number = EXEC_IGNORE; }
+ | QUIETLY
+ { $$.number = EXEC_QUIETLY; }
+ | PIECEMEAL
+ { $$.number = EXEC_PIECEMEAL; }
+ | EXISTING
+ { $$.number = EXEC_EXISTING; }
+ ;
+
+
+/*
+ * bindlist - list of variable to bind for an action
+ */
+
+bindlist : /* empty */
+ { $$.parse = pnull(); }
+ | BIND list
+ { $$.parse = $2.parse; }
+ ;
+
+
diff --git a/jam_src/jamgram.yy b/jam_src/jamgram.yy
new file mode 100644
index 000000000..2ece67fae
--- /dev/null
+++ b/jam_src/jamgram.yy
@@ -0,0 +1,287 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * jamgram.yy - jam grammar
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 08/23/94 (seiwald) - Support for '+=' (append to variable)
+ * 08/31/94 (seiwald) - Allow ?= as alias for "default =".
+ * 09/15/94 (seiwald) - if conditionals take only single arguments, so
+ * that 'if foo == bar' gives syntax error (use =).
+ * 02/11/95 (seiwald) - when scanning arguments to rules, only treat
+ * punctuation keywords as keywords. All arg lists
+ * are terminated with punctuation keywords.
+ *
+ * 09/11/00 (seiwald) - Support for function calls:
+ *
+ * Rules now return lists (LIST *), rather than void.
+ *
+ * New "[ rule ]" syntax evals rule into a LIST.
+ *
+ * Lists are now generated by compile_list() and
+ * compile_append(), and any other rule that indirectly
+ * makes a list, rather than being built directly here,
+ * so that lists values can contain rule evaluations.
+ *
+ * New 'return' rule sets the return value, though
+ * other statements also may have return values.
+ *
+ * 'run' production split from 'block' production so
+ * that empty blocks can be handled separately.
+ */
+
+%token ARG STRING
+
+%left `||`
+%left `&&`
+%left `!`
+
+%{
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "newstr.h"
+
+# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define P0 (PARSE *)0
+# define S0 (char *)0
+
+# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
+# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
+# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
+# define psetmodule( l,r ) parse_make( compile_set_module,l,r,P0,S0,S0,0 )
+# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
+# define psetc( s,p ) parse_make( compile_setcomp,p,P0,P0,s,S0,0 )
+# define psetc_args( s,p,a ) parse_make( compile_setcomp,p,a,P0,s,S0,0 )
+# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+%}
+
+%%
+
+run : /* empty */
+ /* do nothing */
+ | rules
+ { parse_save( $1.parse ); }
+ ;
+
+/*
+ * block - zero or more rules
+ * rules - one or more rules
+ * rule - any one of jam's rules
+ * right-recursive so rules execute in order.
+ */
+
+block : /* empty */
+ { $$.parse = pnull(); }
+ | rules
+ { $$.parse = $1.parse; }
+ ;
+
+rules : rule
+ { $$.parse = $1.parse; }
+ | rule rules
+ { $$.parse = prules( $1.parse, $2.parse ); }
+ | `local` list assign_list_opt `;` block
+ { $$.parse = plocal( $2.parse, $3.parse, $5.parse ); }
+ ;
+
+assign_list_opt : /* empty */
+ { $$.parse = pnull(); }
+ | `=` list
+ { $$.parse = $2.parse; }
+ ;
+
+rule : `{` block `}`
+ { $$.parse = $2.parse; }
+ | `include` list `;`
+ { $$.parse = pincl( $2.parse ); }
+ | ARG lol `;`
+ { $$.parse = prule( $1.string, $2.parse ); }
+ | arg assign list `;`
+ { $$.parse = pset( $1.parse, $3.parse, $2.number ); }
+ | `module` `local` list assign_list_opt `;`
+ { $$.parse = psetmodule( $3.parse, $4.parse ); }
+ | arg `on` list assign list `;`
+ { $$.parse = pset1( $1.parse, $3.parse, $5.parse, $4.number ); }
+ | `return` list `;`
+ { $$.parse = $2.parse; }
+ | `for` ARG `in` list `{` block `}`
+ { $$.parse = pfor( $2.string, $4.parse, $6.parse, 0 ); }
+ | `for` `local` ARG `in` list `{` block `}`
+ { $$.parse = pfor( $3.string, $5.parse, $7.parse, 1 ); }
+ | `switch` list `{` cases `}`
+ { $$.parse = pswitch( $2.parse, $4.parse ); }
+ | `if` cond `{` block `}`
+ { $$.parse = pif( $2.parse, $4.parse, pnull() ); }
+ | `module` list `{` block `}`
+ { $$.parse = pmodule( $2.parse, $4.parse ); }
+ | `while` cond `{` block `}`
+ { $$.parse = pwhile( $2.parse, $4.parse ); }
+ | `if` cond `{` block `}` `else` rule
+ { $$.parse = pif( $2.parse, $4.parse, $7.parse ); }
+ | `rule` ARG `(` lol `)` rule
+ { $$.parse = psetc_args( $2.string, $6.parse, $4.parse ); }
+ | `rule` ARG rule
+ { $$.parse = psetc( $2.string, $3.parse ); }
+ | `actions` eflags ARG bindlist `{`
+ { yymode( SCAN_STRING ); }
+ STRING
+ { yymode( SCAN_NORMAL ); }
+ `}`
+ { $$.parse = psete( $3.string,$4.parse,$7.string,$2.number ); }
+ ;
+
+/*
+ * assign - = or +=
+ */
+
+assign : `=`
+ { $$.number = ASSIGN_SET; }
+ | `+=`
+ { $$.number = ASSIGN_APPEND; }
+ | `?=`
+ { $$.number = ASSIGN_DEFAULT; }
+ | `default` `=`
+ { $$.number = ASSIGN_DEFAULT; }
+ ;
+
+/*
+ * cond - a conditional for 'if'
+ */
+
+cond : arg
+ { $$.parse = pcnode( COND_EXISTS, $1.parse, pnull() ); }
+ | arg `=` arg
+ { $$.parse = pcnode( COND_EQUALS, $1.parse, $3.parse ); }
+ | arg `!=` arg
+ { $$.parse = pcnode( COND_NOTEQ, $1.parse, $3.parse ); }
+ | arg `<` arg
+ { $$.parse = pcnode( COND_LESS, $1.parse, $3.parse ); }
+ | arg `<=` arg
+ { $$.parse = pcnode( COND_LESSEQ, $1.parse, $3.parse ); }
+ | arg `>` arg
+ { $$.parse = pcnode( COND_MORE, $1.parse, $3.parse ); }
+ | arg `>=` arg
+ { $$.parse = pcnode( COND_MOREEQ, $1.parse, $3.parse ); }
+ | arg `in` list
+ { $$.parse = pcnode( COND_IN, $1.parse, $3.parse ); }
+ | `!` cond
+ { $$.parse = pcnode( COND_NOT, $2.parse, P0 ); }
+ | cond `&&` cond
+ { $$.parse = pcnode( COND_AND, $1.parse, $3.parse ); }
+ | cond `||` cond
+ { $$.parse = pcnode( COND_OR, $1.parse, $3.parse ); }
+ | `(` cond `)`
+ { $$.parse = $2.parse; }
+ ;
+
+/*
+ * cases - action elements inside a 'switch'
+ * case - a single action element inside a 'switch'
+ * right-recursive rule so cases can be examined in order.
+ */
+
+cases : /* empty */
+ { $$.parse = P0; }
+ | case cases
+ { $$.parse = pnode( $1.parse, $2.parse ); }
+ ;
+
+case : `case` ARG `:` block
+ { $$.parse = psnode( $2.string, $4.parse ); }
+ ;
+
+/*
+ * lol - list of lists
+ * right-recursive rule so that lists can be added in order.
+ */
+
+lol : list
+ { $$.parse = pnode( P0, $1.parse ); }
+ | list `:` lol
+ { $$.parse = pnode( $3.parse, $1.parse ); }
+ ;
+
+/*
+ * list - zero or more args in a LIST
+ * listp - list (in puncutation only mode)
+ * arg - one ARG or function call
+ */
+
+list : listp
+ { $$.parse = $1.parse; yymode( SCAN_NORMAL ); }
+ ;
+
+listp : /* empty */
+ { $$.parse = pnull(); yymode( SCAN_PUNCT ); }
+ | listp arg
+ { $$.parse = pappend( $1.parse, $2.parse ); }
+ ;
+
+arg : ARG
+ { $$.parse = plist( $1.string ); }
+ | `[` ARG lol `]`
+ { $$.parse = prule( $2.string, $3.parse ); }
+ ;
+
+
+/*
+ * eflags - zero or more modifiers to 'executes'
+ * eflag - a single modifier to 'executes'
+ */
+
+eflags : /* empty */
+ { $$.number = 0; }
+ | eflags eflag
+ { $$.number = $1.number | $2.number; }
+ ;
+
+eflag : `updated`
+ { $$.number = EXEC_UPDATED; }
+ | `together`
+ { $$.number = EXEC_TOGETHER; }
+ | `ignore`
+ { $$.number = EXEC_IGNORE; }
+ | `quietly`
+ { $$.number = EXEC_QUIETLY; }
+ | `piecemeal`
+ { $$.number = EXEC_PIECEMEAL; }
+ | `existing`
+ { $$.number = EXEC_EXISTING; }
+ ;
+
+
+/*
+ * bindlist - list of variable to bind for an action
+ */
+
+bindlist : /* empty */
+ { $$.parse = pnull(); }
+ | `bind` list
+ { $$.parse = $2.parse; }
+ ;
+
+
diff --git a/jam_src/jamgramtab.h b/jam_src/jamgramtab.h
new file mode 100644
index 000000000..018555b93
--- /dev/null
+++ b/jam_src/jamgramtab.h
@@ -0,0 +1,41 @@
+ { "!", _BANG },
+ { "!=", _BANG_EQUALS },
+ { "&&", _AMPERAMPER },
+ { "(", _LPAREN },
+ { ")", _RPAREN },
+ { "+=", _PLUS_EQUALS },
+ { ":", _COLON },
+ { ";", _SEMIC },
+ { "<", _LANGLE },
+ { "<=", _LANGLE_EQUALS },
+ { "=", _EQUALS },
+ { ">", _RANGLE },
+ { ">=", _RANGLE_EQUALS },
+ { "?=", _QUESTION_EQUALS },
+ { "[", _LBRACKET },
+ { "]", _RBRACKET },
+ { "actions", ACTIONS },
+ { "bind", BIND },
+ { "case", CASE },
+ { "default", DEFAULT },
+ { "else", ELSE },
+ { "existing", EXISTING },
+ { "for", FOR },
+ { "if", IF },
+ { "ignore", IGNORE },
+ { "in", IN },
+ { "include", INCLUDE },
+ { "local", LOCAL },
+ { "module", MODULE },
+ { "on", ON },
+ { "piecemeal", PIECEMEAL },
+ { "quietly", QUIETLY },
+ { "return", RETURN },
+ { "rule", RULE },
+ { "switch", SWITCH },
+ { "together", TOGETHER },
+ { "updated", UPDATED },
+ { "while", WHILE },
+ { "{", _LBRACE },
+ { "||", _BARBAR },
+ { "}", _RBRACE },
diff --git a/jam_src/lists.c b/jam_src/lists.c
new file mode 100644
index 000000000..919c71210
--- /dev/null
+++ b/jam_src/lists.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "newstr.h"
+# include "lists.h"
+
+/*
+ * lists.c - maintain lists of strings
+ *
+ * This implementation essentially uses a singly linked list, but
+ * guarantees that the head element of every list has a valid pointer
+ * to the tail of the list, so the new elements can efficiently and
+ * properly be appended to the end of a list.
+ *
+ * To avoid massive allocation, list_free() just tacks the whole freed
+ * chain onto freelist and list_new() looks on freelist first for an
+ * available list struct. list_free() does not free the strings in the
+ * chain: it lazily lets list_new() do so.
+ *
+ * 08/23/94 (seiwald) - new list_append()
+ * 09/07/00 (seiwald) - documented lol_*() functions
+ */
+
+static LIST *freelist = 0; /* junkpile for list_free() */
+
+/*
+ * list_append() - append a list onto another one, returning total
+ */
+
+LIST *
+list_append(
+ LIST *l,
+ LIST *nl )
+{
+ if( !nl )
+ {
+ /* Just return l */
+ }
+ else if( !l )
+ {
+ l = nl;
+ }
+ else
+ {
+ /* Graft two non-empty lists. */
+ l->tail->next = nl;
+ l->tail = nl->tail;
+ }
+
+ return l;
+}
+
+/*
+ * list_new() - tack a string onto the end of a list of strings
+ */
+
+LIST *
+list_new(
+ LIST *head,
+ char *string )
+{
+ LIST *l;
+
+ if( DEBUG_LISTS )
+ printf( "list > %s <\n", string );
+
+ /* Get list struct from freelist, if one available. */
+ /* Otherwise allocate. */
+ /* If from freelist, must free string first */
+
+ if( freelist )
+ {
+ l = freelist;
+ freestr( l->string );
+ freelist = freelist->next;
+ }
+ else
+ {
+ l = (LIST *)malloc( sizeof( *l ) );
+ }
+
+ /* If first on chain, head points here. */
+ /* If adding to chain, tack us on. */
+ /* Tail must point to this new, last element. */
+
+ if( !head ) head = l;
+ else head->tail->next = l;
+ head->tail = l;
+ l->next = 0;
+
+ l->string = string;
+
+ return head;
+}
+
+/*
+ * list_copy() - copy a whole list of strings (nl) onto end of another (l)
+ */
+
+LIST *
+list_copy(
+ LIST *l,
+ LIST *nl )
+{
+ for( ; nl; nl = list_next( nl ) )
+ l = list_new( l, copystr( nl->string ) );
+
+ return l;
+}
+
+/*
+ * list_sublist() - copy a subset of a list of strings
+ */
+
+LIST *
+list_sublist(
+ LIST *l,
+ int start,
+ int count )
+{
+ LIST *nl = 0;
+
+ for( ; l && start--; l = list_next( l ) )
+ ;
+
+ for( ; l && count--; l = list_next( l ) )
+ nl = list_new( nl, copystr( l->string ) );
+
+ return nl;
+}
+
+/*
+ * list_free() - free a list of strings
+ */
+
+void
+list_free( LIST *head )
+{
+ /* Just tack onto freelist. */
+
+ if( head )
+ {
+ head->tail->next = freelist;
+ freelist = head;
+ }
+}
+
+/*
+ * list_print() - print a list of strings to stdout
+ */
+
+void
+list_print( LIST *l )
+{
+ for( ; l; l = list_next( l ) )
+ printf( "%s ", l->string );
+}
+
+/*
+ * list_length() - return the number of items in the list
+ */
+
+int
+list_length( LIST *l )
+{
+ int n = 0;
+
+ for( ; l; l = list_next( l ), ++n )
+ ;
+
+ return n;
+}
+
+/*
+ * lol_init() - initialize a LOL (list of lists)
+ */
+
+void
+lol_init( LOL *lol )
+{
+ lol->count = 0;
+}
+
+/*
+ * lol_add() - append a LIST onto an LOL
+ */
+
+void
+lol_add(
+ LOL *lol,
+ LIST *l )
+{
+ if( lol->count < LOL_MAX )
+ lol->list[ lol->count++ ] = l;
+}
+
+/*
+ * lol_free() - free the LOL and its LISTs
+ */
+
+void
+lol_free( LOL *lol )
+{
+ int i;
+
+ for( i = 0; i < lol->count; i++ )
+ list_free( lol->list[i] );
+
+ lol->count = 0;
+}
+
+/*
+ * lol_get() - return one of the LISTs in the LOL
+ */
+
+LIST *
+lol_get(
+ LOL *lol,
+ int i )
+{
+ return i < lol->count ? lol->list[i] : 0;
+}
+
+/*
+ * lol_print() - debug print LISTS separated by ":"
+ */
+
+void
+lol_print( LOL *lol )
+{
+ int i;
+
+ for( i = 0; i < lol->count; i++ )
+ {
+ if( i )
+ printf( " : " );
+ list_print( lol->list[i] );
+ }
+}
diff --git a/jam_src/lists.h b/jam_src/lists.h
new file mode 100644
index 000000000..4ed262f44
--- /dev/null
+++ b/jam_src/lists.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * lists.h - the LIST structure and routines to manipulate them
+ *
+ * The whole of jam relies on lists of strings as a datatype. This
+ * module, in conjunction with newstr.c, handles these relatively
+ * efficiently.
+ *
+ * Structures defined:
+ *
+ * LIST - list of strings
+ * LOL - list of LISTs
+ *
+ * External routines:
+ *
+ * list_append() - append a list onto another one, returning total
+ * list_new() - tack a string onto the end of a list of strings
+ * list_copy() - copy a whole list of strings
+ * list_sublist() - copy a subset of a list of strings
+ * list_free() - free a list of strings
+ * list_print() - print a list of strings to stdout
+ * list_length() - return the number of items in the list
+ *
+ * lol_init() - initialize a LOL (list of lists)
+ * lol_add() - append a LIST onto an LOL
+ * lol_free() - free the LOL and its LISTs
+ * lol_get() - return one of the LISTs in the LOL
+ * lol_print() - debug print LISTS separated by ":"
+ *
+ * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
+ * 08/23/94 (seiwald) - new list_append()
+ */
+
+#ifndef LISTS_DWA20011022_H
+# define LISTS_DWA20011022_H
+
+/*
+ * LIST - list of strings
+ */
+
+typedef struct _list LIST;
+
+struct _list {
+ LIST *next;
+ LIST *tail; /* only valid in head node */
+ char *string; /* private copy */
+} ;
+
+/*
+ * LOL - list of LISTs
+ */
+
+typedef struct _lol LOL;
+
+# define LOL_MAX 9
+
+struct _lol {
+ int count;
+ LIST *list[ LOL_MAX ];
+} ;
+
+LIST * list_append( LIST *l, LIST *nl );
+LIST * list_copy( LIST *l, LIST *nl );
+void list_free( LIST *head );
+LIST * list_new( LIST *head, char *string );
+void list_print( LIST *l );
+int list_length( LIST *l );
+LIST * list_sublist( LIST *l, int start, int count );
+
+# define list_next( l ) ((l)->next)
+
+# define L0 ((LIST *)0)
+
+void lol_add( LOL *lol, LIST *l );
+void lol_init( LOL *lol );
+void lol_free( LOL *lol );
+LIST * lol_get( LOL *lol, int i );
+void lol_print( LOL *lol );
+
+#endif // LISTS_DWA20011022_H
diff --git a/jam_src/make.c b/jam_src/make.c
new file mode 100644
index 000000000..13af6a053
--- /dev/null
+++ b/jam_src/make.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * make.c - bring a target up to date, once rules are in place
+ *
+ * This modules controls the execution of rules to bring a target and
+ * its dependencies up to date. It is invoked after the targets, rules,
+ * et. al. described in rules.h are created by the interpreting of the
+ * jam files.
+ *
+ * This file contains the main make() entry point and the first pass
+ * make0(). The second pass, make1(), which actually does the command
+ * execution, is in make1.c.
+ *
+ * External routines:
+ * make() - make a target, given its name
+ *
+ * Internal routines:
+ * make0() - bind and scan everything to make a TARGET
+ *
+ * 12/26/93 (seiwald) - allow NOTIME targets to be expanded via $(<), $(>)
+ * 01/04/94 (seiwald) - print all targets, bounded, when tracing commands
+ * 04/08/94 (seiwald) - progress report now reflects only targets with actions
+ * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.
+ * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
+ * 12/20/94 (seiwald) - make0() headers after determining fate of target, so
+ * that headers aren't seen as dependents on themselves.
+ * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
+ * 02/02/95 (seiwald) - propagate leaf source time for new LEAVES rule.
+ * 02/14/95 (seiwald) - NOUPDATE rule means don't update existing target.
+ * 08/22/95 (seiwald) - NOUPDATE targets immune to anyhow (-a) flag.
+ * 09/06/00 (seiwald) - NOCARE affects targets with sources/actions.
+ * 03/02/01 (seiwald) - reverse NOCARE change.
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "rules.h"
+
+# include "search.h"
+# include "newstr.h"
+# include "make.h"
+# include "headers.h"
+# include "command.h"
+
+# ifndef max
+# define max( a,b ) ((a)>(b)?(a):(b))
+# endif
+
+typedef struct {
+ int temp;
+ int updating;
+ int cantfind;
+ int cantmake;
+ int targets;
+ int made;
+} COUNTS ;
+
+static void make0( TARGET *t, int pbinding, time_t ptime,
+ int depth, COUNTS *counts, int anyhow );
+
+static char *target_fate[] =
+{
+ "init", /* T_FATE_INIT */
+ "making", /* T_FATE_MAKING */
+ "stable", /* T_FATE_STABLE */
+ "newer", /* T_FATE_NEWER */
+ "temp", /* T_FATE_ISTMP */
+ "touched", /* T_FATE_TOUCHED */
+ "missing", /* T_FATE_MISSING */
+ "old", /* T_FATE_OUTDATED */
+ "update", /* T_FATE_UPDATE */
+ "nofind", /* T_FATE_CANTFIND */
+ "nomake" /* T_FATE_CANTMAKE */
+} ;
+
+static char *target_bind[] =
+{
+ "unbound",
+ "missing",
+ "parents",
+ "exists",
+} ;
+
+# define spaces(x) ( " " + ( x > 20 ? 0 : 20-x ) )
+
+/*
+ * make() - make a target, given its name
+ */
+
+int
+make(
+ int n_targets,
+ char **targets,
+ int anyhow )
+{
+ int i;
+ COUNTS counts[1];
+ int status = 0; /* 1 if anything fails */
+
+ memset( (char *)counts, 0, sizeof( *counts ) );
+
+ for( i = 0; i < n_targets; i++ )
+ {
+ TARGET *t = bindtarget( targets[i] );
+
+ make0( t, T_BIND_UNBOUND, (time_t)0, 0, counts, anyhow );
+ }
+
+ if( DEBUG_MAKE )
+ {
+ if( counts->targets )
+ printf( "...found %d target%s...\n", counts->targets,
+ counts->targets > 1 ? "s" : "" );
+ if( counts->temp )
+ printf( "...using %d temp target%s...\n", counts->temp,
+ counts->temp > 1 ? "s" : "" );
+ if( counts->updating )
+ printf( "...updating %d target%s...\n", counts->updating,
+ counts->updating > 1 ? "s" : "" );
+ if( counts->cantfind )
+ printf( "...can't find %d target%s...\n", counts->cantfind,
+ counts->cantfind > 1 ? "s" : "" );
+ if( counts->cantmake )
+ printf( "...can't make %d target%s...\n", counts->cantmake,
+ counts->cantmake > 1 ? "s" : "" );
+ }
+
+ status = counts->cantfind || counts->cantmake;
+
+ for( i = 0; i < n_targets; i++ )
+ status |= make1( bindtarget( targets[i] ) );
+
+ return status;
+}
+
+/*
+ * make0() - bind and scan everything to make a TARGET
+ *
+ * Make0() recursively binds a target, searches for #included headers,
+ * calls itself on those headers, and calls itself on any dependents.
+ */
+
+static void
+make0(
+ TARGET *t,
+ int pbinding, /* parent target's binding */
+ time_t ptime, /* parent target's timestamp */
+ int depth, /* for display purposes */
+ COUNTS *counts, /* for reporting */
+ int anyhow ) /* forcibly touch all (real) targets */
+{
+ TARGETS *c;
+ int fate, hfate;
+ time_t last, leaf, hlast, hleaf;
+ char *flag = "";
+
+ if( DEBUG_MAKEPROG )
+ printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+
+ /*
+ * Step 1: don't remake if already trying or tried
+ */
+
+ switch( t->fate )
+ {
+ case T_FATE_MAKING:
+ printf( "warning: %s depends on itself\n", t->name );
+ return;
+
+ /* Deal with TEMPORARY targets with multiple parents. When a missing
+ * TEMPORARY target is determined to be stable, it inherits the
+ * timestamp of the parent being checked, and is given a binding of
+ * T_BIND_PARENTS. To avoid outdating parents with earlier modification
+ * times, we set the target's time to the minimum time of all parents.
+ */
+ case T_FATE_STABLE:
+ if ( t->binding == T_BIND_PARENTS && t->time > ptime && t->flags & T_FLAG_TEMP )
+ t->time = ptime;
+ return;
+
+ default:
+ return;
+
+ case T_FATE_INIT:
+ break;
+ }
+
+ t->fate = T_FATE_MAKING;
+
+ /*
+ * Step 2: under the influence of "on target" variables,
+ * bind the target and search for headers.
+ */
+
+ /* Step 2a: set "on target" variables. */
+
+ pushsettings( t->settings );
+
+ /* Step 2b: find and timestamp the target file (if it's a file). */
+
+ if( t->binding == T_BIND_UNBOUND && !( t->flags & T_FLAG_NOTFILE ) )
+ {
+ t->boundname = search( t->name, &t->time );
+ t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
+ }
+
+ /* If temp file doesn't exist, use parent */
+
+ if( t->binding == T_BIND_MISSING && t->flags & T_FLAG_TEMP && ptime )
+ {
+ t->time = ptime;
+ t->binding = t->time ? T_BIND_PARENTS : T_BIND_MISSING;
+ }
+
+ /* Step 2c: If its a file, search for headers. */
+
+ if( t->binding == T_BIND_EXISTS )
+ headers( t );
+
+ /* Step 2d: reset "on target" variables */
+
+ popsettings( t->settings );
+
+ /*
+ * Pause for a little progress reporting
+ */
+
+ if( DEBUG_BIND )
+ {
+ if( strcmp( t->name, t->boundname ) )
+ {
+ printf( "bind\t--\t%s%s: %s\n",
+ spaces( depth ), t->name, t->boundname );
+ }
+
+ switch( t->binding )
+ {
+ case T_BIND_UNBOUND:
+ case T_BIND_MISSING:
+ case T_BIND_PARENTS:
+ printf( "time\t--\t%s%s: %s\n",
+ spaces( depth ), t->name, target_bind[ t->binding ] );
+ break;
+
+ case T_BIND_EXISTS:
+ printf( "time\t--\t%s%s: %s",
+ spaces( depth ), t->name, ctime( &t->time ) );
+ break;
+ }
+ }
+
+ /*
+ * Step 3: recursively make0() dependents
+ */
+
+ last = 0;
+ leaf = 0;
+ fate = T_FATE_STABLE;
+
+ for( c = t->deps[ T_DEPS_DEPENDS ]; c; c = c->next )
+ {
+ make0( c->target, t->binding, t->time, depth + 1, counts, anyhow );
+ leaf = max( leaf, c->target->leaf );
+ leaf = max( leaf, c->target->hleaf );
+
+ /* If LEAVES has been applied, we only heed the timestamps of */
+ /* the leaf source nodes. */
+
+ if( t->flags & T_FLAG_LEAVES )
+ {
+ last = leaf;
+ continue;
+ }
+
+ last = max( last, c->target->time );
+ last = max( last, c->target->htime );
+ fate = max( fate, c->target->fate );
+ fate = max( fate, c->target->hfate );
+ }
+
+ /* If a NOUPDATE file exists, make dependents eternally old. */
+
+ if( t->flags & T_FLAG_NOUPDATE )
+ {
+ last = 0;
+ t->time = 0;
+
+ /*
+ * Don't inherit our fate from our dependents. Decide fate
+ * based only upon other flags and our binding (done later).
+ */
+
+ fate = T_FATE_STABLE;
+ }
+
+ /* Step 3b: determine fate: rebuild target or what? */
+
+ /*
+ In English:
+ If can't find or make child, can't make target.
+ If children changed, make target.
+ If target missing, make it.
+ If children newer, make target.
+ If temp's children newer, make temp.
+ If deliberately touched, make it.
+ If up-to-date temp file present, use it.
+ If target exists but parent not, mark target newer.
+ If target newer than parent, mark target newer.
+ Don't propagate child's "newer" status.
+ */
+
+ if( fate >= T_FATE_BROKEN )
+ {
+ fate = T_FATE_CANTMAKE;
+ }
+ else if( fate >= T_FATE_SPOIL )
+ {
+ fate = T_FATE_UPDATE;
+ }
+ else if( t->binding == T_BIND_MISSING )
+ {
+ fate = T_FATE_MISSING;
+ }
+ else if( t->binding == T_BIND_EXISTS && last > t->time )
+ {
+ fate = T_FATE_OUTDATED;
+ }
+ else if( t->binding == T_BIND_PARENTS && last > t->time )
+ {
+ fate = T_FATE_OUTDATED;
+ }
+ else if( t->flags & T_FLAG_TOUCHED )
+ {
+ fate = T_FATE_TOUCHED;
+ }
+ else if( anyhow && !( t->flags & T_FLAG_NOUPDATE ) )
+ {
+ fate = T_FATE_TOUCHED;
+ }
+ else if( t->binding == T_BIND_EXISTS && t->flags & T_FLAG_TEMP )
+ {
+ fate = T_FATE_ISTMP;
+ }
+ else if( t->binding == T_BIND_EXISTS && pbinding == T_BIND_MISSING )
+ {
+ fate = T_FATE_NEWER;
+ }
+ else if( t->binding == T_BIND_EXISTS && ptime && t->time > ptime )
+ {
+ fate = T_FATE_NEWER;
+ }
+ else if( fate == T_FATE_NEWER )
+ {
+ fate = T_FATE_STABLE;
+ }
+
+ /* Step 3c: handle missing files */
+ /* If it's missing and there are no actions to create it, boom. */
+ /* If we can't make a target we don't care about, 'sokay */
+ /* We could insist that there are updating actions for all missing */
+ /* files, but if they have dependents we just pretend it's NOTFILE. */
+
+ if( fate == T_FATE_MISSING &&
+ !t->actions &&
+ !t->deps[ T_DEPS_DEPENDS ] )
+ {
+ if( t->flags & T_FLAG_NOCARE )
+ {
+ fate = T_FATE_STABLE;
+ }
+ else
+ {
+ printf( "don't know how to make %s\n", t->name );
+
+ fate = T_FATE_CANTFIND;
+ }
+ }
+
+ /* Step 3d: propagate dependents' time & fate. */
+ /* Set leaf time to be our time only if this is a leaf. */
+
+ t->time = max( t->time, last );
+ t->leaf = leaf ? leaf : t->time ;
+ t->fate = fate;
+
+ /*
+ * Step 4: Recursively make0() headers.
+ */
+
+ /* Step 4a: recursively make0() headers */
+
+ hlast = 0;
+ hleaf = 0;
+ hfate = T_FATE_STABLE;
+
+ for( c = t->deps[ T_DEPS_INCLUDES ]; c; c = c->next )
+ {
+ make0( c->target, pbinding, ptime, depth + 1, counts, anyhow );
+ hlast = max( hlast, c->target->time );
+ hlast = max( hlast, c->target->htime );
+ hleaf = max( hleaf, c->target->leaf );
+ hleaf = max( hleaf, c->target->hleaf );
+ hfate = max( hfate, c->target->fate );
+ hfate = max( hfate, c->target->hfate );
+ }
+
+ /* Step 4b: propagate dependents' time & fate. */
+
+ t->htime = hlast;
+ t->hleaf = hleaf ? hleaf : t->htime;
+ t->hfate = hfate;
+
+ /*
+ * Step 5: a little harmless tabulating for tracing purposes
+ */
+
+ if( !( ++counts->targets % 1000 ) && DEBUG_MAKE )
+ printf( "...patience...\n" );
+
+ if( fate == T_FATE_ISTMP )
+ counts->temp++;
+ else if( fate == T_FATE_CANTFIND )
+ counts->cantfind++;
+ else if( fate == T_FATE_CANTMAKE && t->actions )
+ counts->cantmake++;
+ else if( fate >= T_FATE_BUILD && fate < T_FATE_BROKEN && t->actions )
+ counts->updating++;
+
+ if( !( t->flags & T_FLAG_NOTFILE ) && fate >= T_FATE_SPOIL )
+ flag = "+";
+ else if( t->binding == T_BIND_EXISTS && ptime && t->time > ptime )
+ flag = "*";
+
+ if( DEBUG_MAKEPROG )
+ printf( "made%s\t%s\t%s%s\n",
+ flag, target_fate[ t->fate ],
+ spaces( depth ), t->name );
+}
+
diff --git a/jam_src/make.h b/jam_src/make.h
new file mode 100644
index 000000000..87ca86209
--- /dev/null
+++ b/jam_src/make.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * make.h - bring a target up to date, once rules are in place
+ */
+
+int make( int n_targets, char **targets, int anyhow );
+int make1( TARGET *t );
diff --git a/jam_src/make1.c b/jam_src/make1.c
new file mode 100644
index 000000000..863adad37
--- /dev/null
+++ b/jam_src/make1.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * make1.c - execute command to bring targets up to date
+ *
+ * This module contains make1(), the entry point called by make() to
+ * recursively decend the dependency graph executing update actions as
+ * marked by make0().
+ *
+ * External routines:
+ *
+ * make1() - execute commands to update a TARGET and all its dependents
+ *
+ * Internal routines, the recursive/asynchronous command executors:
+ *
+ * make1a() - recursively traverse target tree, calling make1b()
+ * make1b() - dependents of target built, now build target with make1c()
+ * make1c() - launch target's next command, call make1b() when done
+ * make1d() - handle command execution completion and call back make1c()
+ *
+ * Internal support routines:
+ *
+ * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
+ * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
+ * make1settings() - for vars that get bound values, build up replacement lists
+ * make1bind() - bind targets that weren't bound in dependency analysis
+ *
+ * 04/16/94 (seiwald) - Split from make.c.
+ * 04/21/94 (seiwald) - Handle empty "updated" actions.
+ * 05/04/94 (seiwald) - async multiprocess (-j) support
+ * 06/01/94 (seiwald) - new 'actions existing' does existing sources
+ * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
+ * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
+ * 01/22/94 (seiwald) - pass per-target JAMSHELL down to execcmd().
+ * 02/28/95 (seiwald) - Handle empty "existing" actions.
+ * 03/10/95 (seiwald) - Fancy counts.
+ */
+
+# include "jam.h"
+
+# include "lists.h"
+# include "parse.h"
+# include "variable.h"
+# include "rules.h"
+
+# include "search.h"
+# include "newstr.h"
+# include "make.h"
+# include "command.h"
+# include "execcmd.h"
+
+static void make1a( TARGET *t, TARGET *parent );
+static void make1b( TARGET *t );
+static void make1c( TARGET *t );
+static void make1d( void *closure, int status );
+
+static CMD *make1cmds( ACTIONS *a0 );
+static LIST *make1list( LIST *l, TARGETS *targets, int flags );
+static SETTINGS *make1settings( LIST *vars );
+static void make1bind( TARGET *t, int warn );
+
+/* Ugly static - it's too hard to carry it through the callbacks. */
+
+static struct {
+ int failed;
+ int skipped;
+ int total;
+ int made;
+} counts[1] ;
+
+/*
+ * make1() - execute commands to update a TARGET and all its dependents
+ */
+
+static int intr = 0;
+
+int
+make1( TARGET *t )
+{
+ memset( (char *)counts, 0, sizeof( *counts ) );
+
+ /* Recursively make the target and its dependents */
+
+ make1a( t, (TARGET *)0 );
+
+ /* Wait for any outstanding commands to finish running. */
+
+ while( execwait() )
+ ;
+
+ /* Talk about it */
+
+ if( DEBUG_MAKE && counts->failed )
+ printf( "...failed updating %d target%s...\n", counts->failed,
+ counts->failed > 1 ? "s" : "" );
+
+ if( DEBUG_MAKE && counts->skipped )
+ printf( "...skipped %d target%s...\n", counts->skipped,
+ counts->skipped > 1 ? "s" : "" );
+
+ if( DEBUG_MAKE && counts->made )
+ printf( "...updated %d target%s...\n", counts->made,
+ counts->made > 1 ? "s" : "" );
+
+ return counts->total != counts->made;
+}
+
+/*
+ * make1a() - recursively traverse target tree, calling make1b()
+ */
+
+static void
+make1a(
+ TARGET *t,
+ TARGET *parent )
+{
+ TARGETS *c;
+ int i;
+
+ /* If the parent is the first to try to build this target */
+ /* or this target is in the make1c() quagmire, arrange for the */
+ /* parent to be notified when this target is built. */
+
+ if( parent )
+ switch( t->progress )
+ {
+ case T_MAKE_INIT:
+ case T_MAKE_ACTIVE:
+ case T_MAKE_RUNNING:
+ t->parents = targetentry( t->parents, parent );
+ parent->asynccnt++;
+ }
+
+ if( t->progress != T_MAKE_INIT )
+ return;
+
+ /* Asynccnt counts the dependents preventing this target from */
+ /* proceeding to make1b() for actual building. We start off with */
+ /* a count of 1 to prevent anything from happening until we can */
+ /* call all dependents. This 1 is accounted for when we call */
+ /* make1b() ourselves, below. */
+
+ t->asynccnt = 1;
+
+ /* Recurse on our dependents, manipulating progress to guard */
+ /* against circular dependency. */
+
+ t->progress = T_MAKE_ONSTACK;
+
+ for( i = T_DEPS_DEPENDS; i <= T_DEPS_INCLUDES; i++ )
+ for( c = t->deps[i]; c && !intr; c = c->next )
+ make1a( c->target, t );
+
+ t->progress = T_MAKE_ACTIVE;
+
+ /* Now that all dependents have bumped asynccnt, we now allow */
+ /* decrement our reference to asynccnt. */
+
+ make1b( t );
+}
+
+/*
+ * make1b() - dependents of target built, now build target with make1c()
+ */
+
+static void
+make1b( TARGET *t )
+{
+ TARGETS *c;
+ int i;
+ char *failed = "dependents";
+
+ /* If any dependents are still outstanding, wait until they */
+ /* call make1b() to signal their completion. */
+
+ if( --t->asynccnt )
+ return;
+
+ /* Now ready to build target 't'... if dependents built ok. */
+
+ /* Collect status from dependents */
+
+ for( i = T_DEPS_DEPENDS; i <= T_DEPS_INCLUDES; i++ )
+ for( c = t->deps[i]; c; c = c->next )
+ if( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
+ {
+ failed = c->target->name;
+ t->status = c->target->status;
+ }
+
+ /* If actions on deps have failed, bail. */
+ /* Otherwise, execute all actions to make target */
+
+ if( t->status == EXEC_CMD_FAIL && t->actions )
+ {
+ ++counts->skipped;
+ printf( "...skipped %s for lack of %s...\n", t->name, failed );
+ }
+
+ if( t->status == EXEC_CMD_OK )
+ switch( t->fate )
+ {
+ case T_FATE_INIT:
+ case T_FATE_MAKING:
+ /* shouldn't happen */
+
+ case T_FATE_STABLE:
+ case T_FATE_NEWER:
+ break;
+
+ case T_FATE_CANTFIND:
+ case T_FATE_CANTMAKE:
+ t->status = EXEC_CMD_FAIL;
+ break;
+
+ case T_FATE_ISTMP:
+ if( DEBUG_MAKE )
+ printf( "...using %s...\n", t->name );
+ break;
+
+ case T_FATE_TOUCHED:
+ case T_FATE_MISSING:
+ case T_FATE_OUTDATED:
+ case T_FATE_UPDATE:
+ /* Set "on target" vars, build actions, unset vars */
+ /* Set "progress" so that make1c() counts this target among */
+ /* the successes/failures. */
+
+ if( t->actions )
+ {
+ ++counts->total;
+ if( DEBUG_MAKE && !( counts->total % 100 ) )
+ printf( "...on %dth target...\n", counts->total );
+
+ pushsettings( t->settings );
+ t->cmds = (char *)make1cmds( t->actions );
+ popsettings( t->settings );
+
+ t->progress = T_MAKE_RUNNING;
+ }
+
+ break;
+ }
+
+ /* Call make1c() to begin the execution of the chain of commands */
+ /* needed to build target. If we're not going to build target */
+ /* (because of dependency failures or because no commands need to */
+ /* be run) the chain will be empty and make1c() will directly */
+ /* signal the completion of target. */
+
+ make1c( t );
+}
+
+/*
+ * make1c() - launch target's next command, call make1b() when done
+ */
+
+static void
+make1c( TARGET *t )
+{
+ CMD *cmd = (CMD *)t->cmds;
+
+ /* If there are (more) commands to run to build this target */
+ /* (and we haven't hit an error running earlier comands) we */
+ /* launch the command with execcmd(). */
+
+ /* If there are no more commands to run, we collect the status */
+ /* from all the actions then report our completion to all the */
+ /* parents. */
+
+ if( cmd && t->status == EXEC_CMD_OK )
+ {
+ if( DEBUG_MAKE )
+ if( DEBUG_MAKEQ || ! ( cmd->rule->actions->flags & RULE_QUIETLY ) )
+ {
+ printf( "%s ", cmd->rule->name );
+ list_print( lol_get( &cmd->args, 0 ) );
+ printf( "\n" );
+ }
+
+ if( DEBUG_EXEC )
+ printf( "%s\n", cmd->buf );
+
+ if( globs.cmdout )
+ fprintf( globs.cmdout, "%s", cmd->buf );
+
+ if( globs.noexec )
+ {
+ make1d( t, EXEC_CMD_OK );
+ }
+ else
+ {
+ fflush( stdout );
+ execcmd( cmd->buf, make1d, t, cmd->shell );
+ }
+ }
+ else
+ {
+ TARGETS *c;
+ ACTIONS *actions;
+
+ /* Collect status from actions, and distribute it as well */
+
+ for( actions = t->actions; actions; actions = actions->next )
+ if( actions->action->status > t->status )
+ t->status = actions->action->status;
+
+ for( actions = t->actions; actions; actions = actions->next )
+ if( t->status > actions->action->status )
+ actions->action->status = t->status;
+
+ /* Tally success/failure for those we tried to update. */
+
+ if( t->progress == T_MAKE_RUNNING )
+ switch( t->status )
+ {
+ case EXEC_CMD_OK:
+ ++counts->made;
+ break;
+ case EXEC_CMD_FAIL:
+ ++counts->failed;
+ break;
+ }
+
+ /* Tell parents dependent has been built */
+
+ t->progress = T_MAKE_DONE;
+
+ for( c = t->parents; c; c = c->next )
+ make1b( c->target );
+ }
+}
+
+/*
+ * make1d() - handle command execution completion and call back make1c()
+ */
+
+static void
+make1d(
+ void *closure,
+ int status )
+{
+ TARGET *t = (TARGET *)closure;
+ CMD *cmd = (CMD *)t->cmds;
+
+ /* Execcmd() has completed. All we need to do is fiddle with the */
+ /* status and signal our completion so make1c() can run the next */
+ /* command. On interrupts, we bail heavily. */
+
+ if ( t->flags & T_FLAG_FAIL_EXPECTED )
+ {
+ /* invert execution result when FAIL_EXPECTED was applied */
+ switch (status)
+ {
+ case EXEC_CMD_FAIL: status = EXEC_CMD_OK; break;
+ case EXEC_CMD_OK: status = EXEC_CMD_FAIL; break;
+ default:
+ ;
+ }
+ }
+
+ if( status == EXEC_CMD_FAIL && ( cmd->rule->actions->flags & RULE_IGNORE ) )
+ status = EXEC_CMD_OK;
+
+ /* On interrupt, set intr so _everything_ fails */
+
+ if( status == EXEC_CMD_INTR )
+ ++intr;
+
+ if( status == EXEC_CMD_FAIL && DEBUG_MAKE )
+ {
+ /* Print command text on failure */
+
+ if( !DEBUG_EXEC )
+ printf( "%s\n", cmd->buf );
+
+ printf( "...failed %s ", cmd->rule->name );
+ list_print( lol_get( &cmd->args, 0 ) );
+ printf( "...\n" );
+ }
+
+ /* If the command was interrupted or failed and the target */
+ /* is not "precious", remove the targets */
+
+ if( status != EXEC_CMD_OK && !( cmd->rule->actions->flags & RULE_TOGETHER ) )
+ {
+ LIST *targets = lol_get( &cmd->args, 0 );
+
+ for( ; targets; targets = list_next( targets ) )
+ if( !unlink( targets->string ) )
+ printf( "...removing %s\n", targets->string );
+ }
+
+ /* Free this command and call make1c() to move onto next command. */
+
+ t->status = status;
+ t->cmds = (char *)cmd_next( cmd );
+
+ cmd_free( cmd );
+
+ make1c( t );
+}
+
+/*
+ * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
+ *
+ * Essentially copies a chain of ACTIONs to a chain of CMDs,
+ * grouping RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions,
+ * and handling RULE_NEWSRCS actions. The result is a chain of
+ * CMDs which can be expanded by var_string() and executed with
+ * execcmd().
+ */
+
+static CMD *
+make1cmds( ACTIONS *a0 )
+{
+ CMD *cmds = 0;
+ LIST *shell = var_get( "JAMSHELL" ); /* shell is per-target */
+
+ /* Step through actions */
+ /* Actions may be shared with other targets or grouped with */
+ /* RULE_TOGETHER, so actions already seen are skipped. */
+
+ for( ; a0; a0 = a0->next )
+ {
+ RULE *rule = a0->action->rule;
+ rule_actions *actions = rule->actions;
+ SETTINGS *boundvars;
+ LIST *nt, *ns;
+ ACTIONS *a1;
+ CMD *cmd;
+ int start, chunk, length;
+
+ /* Only do rules with commands to execute. */
+ /* If this action has already been executed, use saved status */
+
+ if( !actions || a0->action->running )
+ continue;
+
+ a0->action->running = 1;
+
+ /* Make LISTS of targets and sources */
+ /* If `execute together` has been specified for this rule, tack */
+ /* on sources from each instance of this rule for this target. */
+
+ nt = make1list( L0, a0->action->targets, 0 );
+ ns = make1list( L0, a0->action->sources, actions->flags );
+
+ if( actions->flags & RULE_TOGETHER )
+ for( a1 = a0->next; a1; a1 = a1->next )
+ if( a1->action->rule == rule && !a1->action->running )
+ {
+ ns = make1list( ns, a1->action->sources, actions->flags );
+ a1->action->running = 1;
+ }
+
+ /* If doing only updated (or existing) sources, but none have */
+ /* been updated (or exist), skip this action. */
+
+ if( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
+ {
+ list_free( nt );
+ continue;
+ }
+
+ /* If we had 'actions xxx bind vars' we bind the vars now */
+
+ boundvars = make1settings( actions->bindlist );
+ pushsettings( boundvars );
+
+ /*
+ * Build command, starting with all source args.
+ *
+ * If cmd_new returns 0, it's because the resulting command
+ * length is > MAXLINE. In this case, we'll slowly reduce
+ * the number of source arguments presented until it does
+ * fit. This only applies to actions that allow PIECEMEAL
+ * commands.
+ *
+ * While reducing slowly takes a bit of compute time to get
+ * things just right, it's worth it to get as close to MAXLINE
+ * as possible, because launching the commands we're executing
+ * is likely to be much more compute intensive!
+ *
+ * Note we loop through at least once, for sourceless actions.
+ */
+
+ start = 0;
+ chunk = length = list_length( ns );
+
+ do
+ {
+ /* Build cmd: cmd_new consumes its lists. */
+
+ CMD *cmd = cmd_new( rule,
+ list_copy( L0, nt ),
+ list_sublist( ns, start, chunk ),
+ list_copy( L0, shell ) );
+
+ if( cmd )
+ {
+ /* It fit: chain it up. */
+
+ if( !cmds ) cmds = cmd;
+ else cmds->tail->next = cmd;
+ cmds->tail = cmd;
+ start += chunk;
+ }
+ else if( ( actions->flags & RULE_PIECEMEAL ) && chunk > 1 )
+ {
+ /* Reduce chunk size slowly. */
+
+ chunk = chunk * 9 / 10;
+ }
+ else
+ {
+ /* Too long and not splittable. */
+
+ printf( "%s actions too long (max %d)!\n",
+ rule->name, MAXLINE );
+ exit( EXITBAD );
+ }
+ }
+ while( start < length );
+
+ /* These were always copied when used. */
+
+ list_free( nt );
+ list_free( ns );
+
+ /* Free the variables whose values were bound by */
+ /* 'actions xxx bind vars' */
+
+ popsettings( boundvars );
+ freesettings( boundvars );
+ }
+
+ return cmds;
+}
+
+/*
+ * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
+ */
+
+static LIST *
+make1list(
+ LIST *l,
+ TARGETS *targets,
+ int flags )
+{
+ for( ; targets; targets = targets->next )
+ {
+ TARGET *t = targets->target;
+
+ /* Sources to 'actions existing' are never in the dependency */
+ /* graph (if they were, they'd get built and 'existing' would */
+ /* be superfluous, so throttle warning message about independent */
+ /* targets. */
+
+ if( t->binding == T_BIND_UNBOUND )
+ make1bind( t, !( flags & RULE_EXISTING ) );
+
+ if( ( flags & RULE_EXISTING ) && t->binding != T_BIND_EXISTS )
+ continue;
+
+ if( ( flags & RULE_NEWSRCS ) && t->fate <= T_FATE_STABLE )
+ continue;
+
+ /* Prohibit duplicates for RULE_TOGETHER */
+
+ if( flags & RULE_TOGETHER )
+ {
+ LIST *m;
+
+ for( m = l; m; m = m->next )
+ if( !strcmp( m->string, t->boundname ) )
+ break;
+
+ if( m )
+ continue;
+ }
+
+ /* Build new list */
+
+ l = list_new( l, copystr( t->boundname ) );
+ }
+
+ return l;
+}
+
+/*
+ * make1settings() - for vars that get bound values, build up replacement lists
+ */
+
+static SETTINGS *
+make1settings( LIST *vars )
+{
+ SETTINGS *settings = 0;
+
+ for( ; vars; vars = list_next( vars ) )
+ {
+ LIST *l = var_get( vars->string );
+ LIST *nl = 0;
+
+ for( ; l; l = list_next( l ) )
+ {
+ TARGET *t = bindtarget( l->string );
+
+ /* Make sure the target is bound, warning if it is not in the */
+ /* dependency graph. */
+
+ if( t->binding == T_BIND_UNBOUND )
+ make1bind( t, 1 );
+
+ /* Build new list */
+
+ nl = list_new( nl, copystr( t->boundname ) );
+ }
+
+ /* Add to settings chain */
+
+ settings = addsettings( settings, 0, vars->string, nl );
+ }
+
+ return settings;
+}
+
+/*
+ * make1bind() - bind targets that weren't bound in dependency analysis
+ *
+ * Spot the kludge! If a target is not in the dependency tree, it didn't
+ * get bound by make0(), so we have to do it here. Ugly.
+ */
+
+static void
+make1bind(
+ TARGET *t,
+ int warn )
+{
+ if( t->flags & T_FLAG_NOTFILE )
+ return;
+
+ /* Sources to 'actions existing' are never in the dependency */
+ /* graph (if they were, they'd get built and 'existing' would */
+ /* be superfluous, so throttle warning message about independent */
+ /* targets. */
+
+ if( warn )
+ printf( "warning: using independent target %s\n", t->name );
+
+ pushsettings( t->settings );
+ t->boundname = search( t->name, &t->time );
+ t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
+ popsettings( t->settings );
+}
diff --git a/jam_src/makecygwindebugjam.bat b/jam_src/makecygwindebugjam.bat
new file mode 100755
index 000000000..bc34fb5fb
--- /dev/null
+++ b/jam_src/makecygwindebugjam.bat
@@ -0,0 +1,4 @@
+set VISUALC=c:\tools\msvc6\vc98
+set JAM_TOOLSET=VISUALC
+rm -rf bin.ntx86
+make -fbuilds/win32-gcc.mk CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd" YACC="bison -t -d -l -v --yacc" LINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" LINKFLAGS="/DEBUG" %*
diff --git a/jam_src/makedebugjam.bat b/jam_src/makedebugjam.bat
new file mode 100755
index 000000000..f855b437d
--- /dev/null
+++ b/jam_src/makedebugjam.bat
@@ -0,0 +1,5 @@
+set VISUALC=c:\tools\msvc6\vc98
+set JAM_TOOLSET=VISUALC
+rm -rf bin.ntx86
+mkdir bin.ntx86
+nmake -fbuilds/win32-visualc.mk JAMBASE= BOOST_ROOT= BOOST_BUILD_PATH= CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd" LINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" LINKFLAGS="/DEBUG" YACC="bison -t -d -l -v --debug --yacc" YACCFILES="y.tab" %*
diff --git a/jam_src/makedebugjam.sh b/jam_src/makedebugjam.sh
new file mode 100644
index 000000000..b4dfed0af
--- /dev/null
+++ b/jam_src/makedebugjam.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+./yyacc jamgram.y jamgramtab.h jamgram.yy
+export VISUALC=c:\tools\msvc6\vc98
+export JAM_TOOLSET=VISUALC
+rm -rf bin.ntx86
+nmake -fbuilds/win32-visualc.mk CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd" YACC="bison -t -d -l -v --debug --yacc" LINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" LINKFLAGS="/DEBUG"
diff --git a/jam_src/mkjambase.c b/jam_src/mkjambase.c
new file mode 100644
index 000000000..c856356ef
--- /dev/null
+++ b/jam_src/mkjambase.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * mkjambase.c - turn Jambase into a big C structure
+ *
+ * Usage: mkjambase jambase.c Jambase ...
+ *
+ * Results look like this:
+ *
+ * char *jambase[] = {
+ * "...\n",
+ * ...
+ * 0 };
+ *
+ * Handles \'s and "'s specially; knows to delete blank and comment lines.
+ *
+ */
+
+# include
+# include
+
+int main( int argc, char **argv, char **envp )
+{
+ char buf[ 1024 ];
+ FILE *fin;
+ FILE *fout;
+ char *p;
+ int doDotC = 0;
+
+ if( argc < 3 )
+ {
+ fprintf( stderr, "usage: %s jambase.c Jambase ...\n", argv[0] );
+ return -1;
+ }
+
+ if( !( fout = fopen( argv[1], "w" ) ) )
+ {
+ perror( argv[1] );
+ return -1;
+ }
+
+ /* If the file ends in .c generate a C source file */
+
+ if( ( p = strrchr( argv[1], '.' ) ) && !strcmp( p, ".c" ) )
+ doDotC++;
+
+ /* Now process the files */
+
+ argc -= 2, argv += 2;
+
+ if( doDotC )
+ {
+ fprintf( fout, "/* Generated by mkjambase from Jambase */\n" );
+ fprintf( fout, "char *jambase[] = {\n" );
+ }
+
+ for( ; argc--; argv++ )
+ {
+ if( !( fin = fopen( *argv, "r" ) ) )
+ {
+ perror( *argv );
+ return -1;
+ }
+
+ if( doDotC )
+ {
+ fprintf( fout, "/* %s */\n", *argv );
+ }
+ else
+ {
+ fprintf( fout, "### %s ###\n", *argv );
+ }
+
+ while( fgets( buf, sizeof( buf ), fin ) )
+ {
+ if( doDotC )
+ {
+ char *p = buf;
+
+ /* Strip leading whitespace. */
+
+ while( *p == ' ' || *p == '\t' || *p == '\n' )
+ p++;
+
+ /* Drop comments and empty lines. */
+
+ if( *p == '#' || !*p )
+ continue;
+
+ /* Copy */
+
+ putc( '"', fout );
+
+ for( ; *p && *p != '\n'; p++ )
+ switch( *p )
+ {
+ case '\\': putc( '\\', fout ); putc( '\\', fout ); break;
+ case '"': putc( '\\', fout ); putc( '"', fout ); break;
+ case '\r': break;
+ default: putc( *p, fout ); break;
+ }
+
+ fprintf( fout, "\\n\",\n" );
+ }
+ else
+ {
+ fprintf( fout, "%s", buf );
+ }
+
+ }
+
+ fclose( fin );
+ }
+
+ if( doDotC )
+ fprintf( fout, "0 };\n" );
+
+ fclose( fout );
+
+ return 0;
+}
diff --git a/jam_src/modules.c b/jam_src/modules.c
new file mode 100644
index 000000000..fef81e3e7
--- /dev/null
+++ b/jam_src/modules.c
@@ -0,0 +1,95 @@
+/* (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
+ * distribute this software is granted provided this copyright notice appears
+ * in all copies. This software is provided "as is" without express or implied
+ * warranty, and with no claim as to its suitability for any purpose.
+ */
+#include "modules.h"
+#include "jam.h"
+#include "string.h"
+#include "hash.h"
+#include "newstr.h"
+#include "lists.h"
+#include "parse.h"
+#include "rules.h"
+#include "variable.h"
+#include "strings.h"
+
+static struct hash* module_hash = 0;
+
+static char* new_module_str( module* m, char* suffix )
+{
+ char* result;
+ string s;
+ string_copy( &s, m->name );
+ string_append( &s, suffix );
+ result = newstr( s.value );
+ string_free( &s );
+ return result;
+}
+
+module* bindmodule( char* name )
+{
+ string s;
+ module m_, *m = &m_;
+
+ if( !module_hash )
+ module_hash = hashinit( sizeof( module ), "modules" );
+
+ string_new( &s );
+ if (name)
+ {
+ string_append( &s, name );
+ string_push_back( &s, '.' );
+ }
+
+ m->name = s.value;
+
+ if ( hashenter( module_hash, (HASHDATA **)&m ) )
+ {
+ m->name = newstr( m->name );
+ m->local_names = 0;
+ m->locals = 0;
+ m->rules = hashinit( sizeof( RULE ), new_module_str( m, "rules" ) );
+ }
+ string_free( &s );
+ return m;
+}
+
+module* root_module()
+{
+ static module* root = 0;
+ if ( !root )
+ root = bindmodule(0);
+ return root;
+}
+
+/*
+ * bind_module_var --
+ *
+ * Add the symbol to the module's list of symbols if it is not already in the
+ * module. m is assumed to be the current module and if the symbol is new, any
+ * current value is replaced by an empty list until the module is exited.
+ *
+ */
+void bind_module_var( module* m, char* symbol )
+{
+ char** name = &symbol;
+
+ if ( !m->local_names )
+ m->local_names = hashinit( sizeof( char* ), new_module_str( m, "variables" ) );
+
+ if ( hashenter( m->local_names, (HASHDATA **)&name ) )
+ {
+ m->locals = addsettings( m->locals, 0, symbol, var_swap( symbol, 0 ) );
+ }
+}
+
+void enter_module( module* m )
+{
+ pushsettings( m->locals );
+}
+
+void exit_module( module* m )
+{
+ popsettings( m->locals );
+}
diff --git a/jam_src/modules.h b/jam_src/modules.h
new file mode 100644
index 000000000..06b30fbb8
--- /dev/null
+++ b/jam_src/modules.h
@@ -0,0 +1,25 @@
+/* (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
+ * distribute this software is granted provided this copyright notice appears
+ * in all copies. This software is provided "as is" without express or implied
+ * warranty, and with no claim as to its suitability for any purpose.
+ */
+#ifndef MODULES_DWA10182001_H
+# define MODULES_DWA10182001_H
+
+struct module
+{
+ char* name;
+ struct hash* rules;
+ struct hash* local_names;
+ struct _settings* locals;
+};
+
+typedef struct module module; /* MSVC debugger gets confused unless this is provided */
+
+module* bindmodule( char* name );
+module* root_module();
+void bind_module_var( module*, char* name );
+void enter_module( module* );
+void exit_module( module* );
+
+#endif // MODULES_DWA10182001_H
diff --git a/jam_src/newstr.c b/jam_src/newstr.c
new file mode 100644
index 000000000..470f2a9a0
--- /dev/null
+++ b/jam_src/newstr.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "newstr.h"
+# include "hash.h"
+
+/*
+ * newstr.c - string manipulation routines
+ *
+ * To minimize string copying, string creation, copying, and freeing
+ * is done through newstr.
+ *
+ * External functions:
+ *
+ * newstr() - return a malloc'ed copy of a string
+ * copystr() - return a copy of a string previously returned by newstr()
+ * freestr() - free a string returned by newstr() or copystr()
+ * donestr() - free string tables
+ *
+ * Once a string is passed to newstr(), the returned string is readonly.
+ *
+ * This implementation builds a hash table of all strings, so that multiple
+ * calls of newstr() on the same string allocate memory for the string once.
+ * Strings are never actually freed.
+ */
+
+typedef char *STRING;
+
+static struct hash *strhash = 0;
+static int strtotal = 0;
+
+/*
+ * newstr() - return a malloc'ed copy of a string
+ */
+
+char *
+newstr( char *string )
+{
+ STRING str, *s = &str;
+
+ if( !strhash )
+ strhash = hashinit( sizeof( STRING ), "strings" );
+
+ *s = string;
+
+ if( hashenter( strhash, (HASHDATA **)&s ) )
+ {
+ int l = strlen( string );
+ char *m = (char *)malloc( l + 1 );
+
+ strtotal += l + 1;
+ memcpy( m, string, l + 1 );
+ *s = m;
+ }
+
+ return *s;
+}
+
+/*
+ * copystr() - return a copy of a string previously returned by newstr()
+ */
+
+char *
+copystr( char *s )
+{
+ return s;
+}
+
+/*
+ * freestr() - free a string returned by newstr() or copystr()
+ */
+
+void
+freestr( char *s )
+{
+}
+
+/*
+ * donestr() - free string tables
+ */
+
+void
+donestr()
+{
+ hashdone( strhash );
+
+ if( DEBUG_MEM )
+ printf( "%dK in strings\n", strtotal / 1024 );
+}
diff --git a/jam_src/newstr.h b/jam_src/newstr.h
new file mode 100644
index 000000000..cf2dd34b7
--- /dev/null
+++ b/jam_src/newstr.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * newstr.h - string manipulation routines
+ */
+
+char *newstr( char *string );
+char *copystr( char *s );
+void freestr( char *s );
+void donestr();
diff --git a/jam_src/option.c b/jam_src/option.c
new file mode 100644
index 000000000..e4491523c
--- /dev/null
+++ b/jam_src/option.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "option.h"
+
+/*
+ * option.c - command line option processing
+ *
+ * {o >o
+ * \<>) "Process command line options as defined in .
+ * Return the number of argv[] elements used up by options,
+ * or -1 if an invalid option flag was given or an argument
+ * was supplied for an option that does not require one."
+ */
+
+int
+getoptions(
+ int argc,
+ char **argv,
+ char *opts,
+ option *optv )
+{
+ int i;
+ int optc = N_OPTS;
+
+ memset( (char *)optv, '\0', sizeof( *optv ) * N_OPTS );
+
+ for( i = 0; i < argc; i++ )
+ {
+ char *arg;
+
+ if( argv[i][0] != '-' || !isalpha( argv[i][1] ) )
+ break;
+
+ if( !optc-- )
+ {
+ printf( "too many options (%d max)\n", N_OPTS );
+ return -1;
+ }
+
+ for( arg = &argv[i][1]; *arg; arg++ )
+ {
+ char *f;
+
+ for( f = opts; *f; f++ )
+ if( *f == *arg )
+ break;
+
+ if( !*f )
+ {
+ printf( "Invalid option: -%c\n", *arg );
+ return -1;
+ }
+
+ optv->flag = *f;
+
+ if( f[1] != ':' )
+ {
+ optv++->val = "true";
+ }
+ else if( arg[1] )
+ {
+ optv++->val = &arg[1];
+ break;
+ }
+ else if( ++i < argc )
+ {
+ optv++->val = argv[i];
+ break;
+ }
+ else
+ {
+ printf( "option: -%c needs argument\n", *f );
+ return -1;
+ }
+ }
+ }
+
+ return i;
+}
+
+/*
+ * Name: getoptval() - find an option given its character
+ */
+
+char *
+getoptval(
+ option *optv,
+ char opt,
+ int subopt )
+{
+ int i;
+
+ for( i = 0; i < N_OPTS; i++, optv++ )
+ if( optv->flag == opt && !subopt-- )
+ return optv->val;
+
+ return 0;
+}
diff --git a/jam_src/option.h b/jam_src/option.h
new file mode 100644
index 000000000..657a763a0
--- /dev/null
+++ b/jam_src/option.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * option.h - command line option processing
+ *
+ * {o >o
+ * \ -) "Command line option."
+ */
+
+typedef struct option
+{
+ char flag; /* filled in by getoption() */
+ char *val; /* set to random address if true */
+} option;
+
+# define N_OPTS 256
+
+int getoptions( int argc, char **argv, char *opts, option *optv );
+char * getoptval( option *optv, char opt, int subopt );
diff --git a/jam_src/parse.c b/jam_src/parse.c
new file mode 100644
index 000000000..931873543
--- /dev/null
+++ b/jam_src/parse.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "lists.h"
+# include "parse.h"
+# include "scan.h"
+# include "newstr.h"
+# include "modules.h"
+# include "frames.h"
+
+/*
+ * parse.c - make and destroy parse trees as driven by the parser
+ *
+ * 09/07/00 (seiwald) - ref count on PARSE to avoid freeing when used,
+ * as per Matt Armstrong.
+ * 09/11/00 (seiwald) - structure reworked to reflect that (*func)()
+ * returns a LIST *.
+ */
+
+static PARSE *yypsave;
+
+void
+parse_file( char *f, FRAME* frame )
+{
+ /* Suspend scan of current file */
+ /* and push this new file in the stream */
+
+ yyfparse(f);
+
+ /* Now parse each block of rules and execute it. */
+ /* Execute it outside of the parser so that recursive */
+ /* calls to yyrun() work (no recursive yyparse's). */
+
+ for(;;)
+ {
+ PARSE *p;
+
+ /* Filled by yyparse() calling parse_save() */
+
+ yypsave = 0;
+
+ /* If parse error or empty parse, outta here */
+
+ if( yyparse() || !( p = yypsave ) )
+ break;
+
+ /* Run the parse tree. */
+
+ (*(p->func))( p, frame );
+
+ parse_free( p );
+ }
+}
+
+void
+parse_save( PARSE *p )
+{
+ yypsave = p;
+}
+
+PARSE *
+parse_make(
+ LIST *(*func)( PARSE *p, FRAME *args ),
+ PARSE *left,
+ PARSE *right,
+ PARSE *third,
+ char *string,
+ char *string1,
+ int num )
+{
+ PARSE *p = (PARSE *)malloc( sizeof( PARSE ) );
+
+ p->func = func;
+ p->left = left;
+ p->right = right;
+ p->third = third;
+ p->string = string;
+ p->string1 = string1;
+ p->num = num;
+ p->refs = 1;
+ p->module = 0;
+ p->rulename = 0;
+
+ return p;
+}
+
+void
+parse_refer( PARSE *p )
+{
+ ++p->refs;
+}
+
+void
+parse_free( PARSE *p )
+{
+ if( --p->refs )
+ return;
+
+ if( p->string )
+ freestr( p->string );
+ if( p->string1 )
+ freestr( p->string1 );
+ if( p->left )
+ parse_free( p->left );
+ if( p->right )
+ parse_free( p->right );
+ if( p->third )
+ parse_free( p->third );
+ if ( p->rulename )
+ freestr( p->rulename );
+
+ free( (char *)p );
+}
diff --git a/jam_src/parse.h b/jam_src/parse.h
new file mode 100644
index 000000000..3cb91f489
--- /dev/null
+++ b/jam_src/parse.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1993, 2000 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+#ifndef PARSE_DWA20011020_H
+# define PARSE_DWA20011020_H
+# include "frames.h"
+# include "modules.h"
+
+/*
+ * parse.h - make and destroy parse trees as driven by the parser
+ */
+
+/*
+ * parse tree node
+ */
+
+typedef struct _PARSE PARSE;
+
+struct _PARSE {
+ LIST *(*func)( PARSE *p, FRAME *frame );
+ PARSE *left;
+ PARSE *right;
+ PARSE *third;
+ char *string;
+ char *string1;
+ int num;
+ int refs;
+ module* module;
+ char* rulename;
+} ;
+
+void parse_file( char *f, FRAME* frame );
+void parse_save( PARSE *p );
+
+PARSE * parse_make(
+ LIST *(*func)( PARSE *p, FRAME* frame ),
+ PARSE *left,
+ PARSE *right,
+ PARSE *third,
+ char *string,
+ char *string1,
+ int num );
+
+void parse_refer( PARSE *p );
+void parse_free( PARSE *p );
+
+#endif // PARSE_DWA20011020_H
diff --git a/jam_src/patchlevel.h b/jam_src/patchlevel.h
new file mode 100644
index 000000000..0d0af9597
--- /dev/null
+++ b/jam_src/patchlevel.h
@@ -0,0 +1,5 @@
+/* Keep JAMVERSYM in sync with VERSION. */
+/* It can be accessed as $(JAMVERSION) in the Jamfile. */
+
+#define VERSION "2.3.2"
+#define JAMVERSYM "JAMVERSION=2.3"
diff --git a/jam_src/pathmac.c b/jam_src/pathmac.c
new file mode 100644
index 000000000..a4292f0a3
--- /dev/null
+++ b/jam_src/pathmac.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "filesys.h"
+
+# ifdef OS_MAC
+
+# define DELIM ':'
+
+/*
+ * pathunix.c - manipulate file names on UNIX, NT, OS2
+ *
+ * External routines:
+ *
+ * file_parse() - split a file name into dir/base/suffix/member
+ * file_build() - build a filename given dir/base/suffix/member
+ * file_parent() - make a FILENAME point to its parent dir
+ *
+ * File_parse() and file_build() just manipuate a string and a structure;
+ * they do not make system calls.
+ *
+ * 04/08/94 (seiwald) - Coherent/386 support added.
+ * 12/26/93 (seiwald) - handle dir/.suffix properly in file_build()
+ * 12/19/94 (mikem) - solaris string table insanity support
+ * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
+ * 02/14/95 (seiwald) - parse and build /xxx properly
+ * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
+ * should expect hdr searches to come up with strings
+ * like "thing/thing.h". So we need to test for "/" as
+ * well as "\" when parsing pathnames.
+ * 03/16/95 (seiwald) - fixed accursed typo on line 69.
+ * 05/03/96 (seiwald) - split from filent.c, fileunix.c
+ * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
+ * don't include the archive member name.
+ */
+
+/*
+ * file_parse() - split a file name into dir/base/suffix/member
+ */
+
+void
+file_parse(
+ char *file,
+ FILENAME *f )
+{
+ char *p, *q;
+ char *end;
+
+ memset( (char *)f, 0, sizeof( *f ) );
+
+ /* Look for