From 49ba2cf8dd415c100fef66f35e6686b362abe6ee Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 6 Nov 2001 15:36:16 +0000 Subject: [PATCH] merged to main trunk [SVN r11610] --- historic/jam/src/Build.com | 30 + historic/jam/src/Build.mpw | 47 + historic/jam/src/INSTALL | 120 ++ historic/jam/src/Jam.html | 1201 ++++++++++++ historic/jam/src/Jambase | 2288 +++++++++++++++++++++++ historic/jam/src/Jambase.html | 881 +++++++++ historic/jam/src/Jamfile | 227 +++ historic/jam/src/Jamfile.html | 1450 ++++++++++++++ historic/jam/src/Makefile | 88 + historic/jam/src/Porting | 68 + historic/jam/src/README | 157 ++ historic/jam/src/RELNOTES | 754 ++++++++ historic/jam/src/command.c | 84 + historic/jam/src/command.h | 58 + historic/jam/src/common.mk | 17 + historic/jam/src/compile.c | 1390 ++++++++++++++ historic/jam/src/compile.h | 74 + historic/jam/src/debugjam0.bat | 10 + historic/jam/src/debugjam0.sh | 7 + historic/jam/src/execcmd.h | 23 + historic/jam/src/execmac.c | 69 + historic/jam/src/execnt.c | 651 +++++++ historic/jam/src/execunix.c | 370 ++++ historic/jam/src/execvms.c | 167 ++ historic/jam/src/expand.c | 591 ++++++ historic/jam/src/expand.h | 12 + historic/jam/src/filemac.c | 165 ++ historic/jam/src/filent.c | 275 +++ historic/jam/src/fileos2.c | 130 ++ historic/jam/src/filesys.c | 33 + historic/jam/src/filesys.h | 62 + historic/jam/src/fileunix.c | 336 ++++ historic/jam/src/filevms.c | 302 +++ historic/jam/src/frames.h | 19 + historic/jam/src/glob.c | 157 ++ historic/jam/src/hash.c | 277 +++ historic/jam/src/hash.h | 19 + historic/jam/src/hdrmacro.c | 135 ++ historic/jam/src/hdrmacro.h | 14 + historic/jam/src/headers.c | 164 ++ historic/jam/src/headers.h | 11 + historic/jam/src/jam.c | 385 ++++ historic/jam/src/jam.h | 483 +++++ historic/jam/src/jambase.c | 1554 +++++++++++++++ historic/jam/src/jambase.h | 15 + historic/jam/src/jamgram.c | 1212 ++++++++++++ historic/jam/src/jamgram.h | 49 + historic/jam/src/jamgram.y | 328 ++++ historic/jam/src/jamgram.yy | 287 +++ historic/jam/src/jamgramtab.h | 41 + historic/jam/src/lists.c | 243 +++ historic/jam/src/lists.h | 85 + historic/jam/src/make.c | 447 +++++ historic/jam/src/make.h | 12 + historic/jam/src/make1.c | 659 +++++++ historic/jam/src/makecygwindebugjam.bat | 4 + historic/jam/src/makedebugjam.bat | 5 + historic/jam/src/makedebugjam.sh | 6 + historic/jam/src/mkjambase.c | 125 ++ historic/jam/src/modules.c | 95 + historic/jam/src/modules.h | 25 + historic/jam/src/newstr.c | 93 + historic/jam/src/newstr.h | 14 + historic/jam/src/option.c | 103 + historic/jam/src/option.h | 23 + historic/jam/src/parse.c | 117 ++ historic/jam/src/parse.h | 50 + historic/jam/src/patchlevel.h | 5 + historic/jam/src/pathmac.c | 249 +++ historic/jam/src/pathunix.c | 222 +++ historic/jam/src/pathvms.c | 410 ++++ historic/jam/src/regexp.c | 1317 +++++++++++++ historic/jam/src/regexp.h | 31 + historic/jam/src/rules.c | 397 ++++ historic/jam/src/rules.h | 216 +++ historic/jam/src/scan.c | 374 ++++ historic/jam/src/scan.h | 52 + historic/jam/src/search.c | 144 ++ historic/jam/src/search.h | 11 + historic/jam/src/strings.c | 142 ++ historic/jam/src/strings.h | 25 + historic/jam/src/subst.c | 92 + historic/jam/src/timestamp.c | 211 +++ historic/jam/src/timestamp.h | 12 + historic/jam/src/variable.c | 344 ++++ historic/jam/src/variable.h | 25 + historic/jam/src/yyacc | 89 + jam_src/Build.com | 30 + jam_src/Build.mpw | 47 + jam_src/INSTALL | 120 ++ jam_src/Jam.html | 1201 ++++++++++++ jam_src/Jambase | 2288 +++++++++++++++++++++++ jam_src/Jambase.html | 881 +++++++++ jam_src/Jamfile | 227 +++ jam_src/Jamfile.html | 1450 ++++++++++++++ jam_src/Makefile | 88 + jam_src/Porting | 68 + jam_src/README | 157 ++ jam_src/RELNOTES | 754 ++++++++ jam_src/command.c | 84 + jam_src/command.h | 58 + jam_src/common.mk | 17 + jam_src/compile.c | 1390 ++++++++++++++ jam_src/compile.h | 74 + jam_src/debugjam0.bat | 10 + jam_src/debugjam0.sh | 7 + jam_src/execcmd.h | 23 + jam_src/execmac.c | 69 + jam_src/execnt.c | 651 +++++++ jam_src/execunix.c | 370 ++++ jam_src/execvms.c | 167 ++ jam_src/expand.c | 591 ++++++ jam_src/expand.h | 12 + jam_src/filemac.c | 165 ++ jam_src/filent.c | 275 +++ jam_src/fileos2.c | 130 ++ jam_src/filesys.c | 33 + jam_src/filesys.h | 62 + jam_src/fileunix.c | 336 ++++ jam_src/filevms.c | 302 +++ jam_src/frames.h | 19 + jam_src/glob.c | 157 ++ jam_src/hash.c | 277 +++ jam_src/hash.h | 19 + jam_src/hdrmacro.c | 135 ++ jam_src/hdrmacro.h | 14 + jam_src/headers.c | 164 ++ jam_src/headers.h | 11 + jam_src/jam.c | 385 ++++ jam_src/jam.h | 483 +++++ jam_src/jambase.c | 1554 +++++++++++++++ jam_src/jambase.h | 15 + jam_src/jamgram.c | 1212 ++++++++++++ jam_src/jamgram.h | 49 + jam_src/jamgram.y | 328 ++++ jam_src/jamgram.yy | 287 +++ jam_src/jamgramtab.h | 41 + jam_src/lists.c | 243 +++ jam_src/lists.h | 85 + jam_src/make.c | 447 +++++ jam_src/make.h | 12 + jam_src/make1.c | 659 +++++++ jam_src/makecygwindebugjam.bat | 4 + jam_src/makedebugjam.bat | 5 + jam_src/makedebugjam.sh | 6 + jam_src/mkjambase.c | 125 ++ jam_src/modules.c | 95 + jam_src/modules.h | 25 + jam_src/newstr.c | 93 + jam_src/newstr.h | 14 + jam_src/option.c | 103 + jam_src/option.h | 23 + jam_src/parse.c | 117 ++ jam_src/parse.h | 50 + jam_src/patchlevel.h | 5 + jam_src/pathmac.c | 249 +++ jam_src/pathunix.c | 222 +++ jam_src/pathvms.c | 410 ++++ jam_src/regexp.c | 1317 +++++++++++++ jam_src/regexp.h | 31 + jam_src/rules.c | 397 ++++ jam_src/rules.h | 216 +++ jam_src/scan.c | 374 ++++ jam_src/scan.h | 52 + jam_src/search.c | 144 ++ jam_src/search.h | 11 + jam_src/strings.c | 142 ++ jam_src/strings.h | 25 + jam_src/subst.c | 92 + jam_src/timestamp.c | 211 +++ jam_src/timestamp.h | 12 + jam_src/variable.c | 344 ++++ jam_src/variable.h | 25 + jam_src/yyacc | 89 + 174 files changed, 47522 insertions(+) create mode 100755 historic/jam/src/Build.com create mode 100644 historic/jam/src/Build.mpw create mode 100644 historic/jam/src/INSTALL create mode 100644 historic/jam/src/Jam.html create mode 100644 historic/jam/src/Jambase create mode 100644 historic/jam/src/Jambase.html create mode 100644 historic/jam/src/Jamfile create mode 100644 historic/jam/src/Jamfile.html create mode 100644 historic/jam/src/Makefile create mode 100644 historic/jam/src/Porting create mode 100644 historic/jam/src/README create mode 100644 historic/jam/src/RELNOTES create mode 100644 historic/jam/src/command.c create mode 100644 historic/jam/src/command.h create mode 100644 historic/jam/src/common.mk create mode 100644 historic/jam/src/compile.c create mode 100644 historic/jam/src/compile.h create mode 100755 historic/jam/src/debugjam0.bat create mode 100644 historic/jam/src/debugjam0.sh create mode 100644 historic/jam/src/execcmd.h create mode 100644 historic/jam/src/execmac.c create mode 100644 historic/jam/src/execnt.c create mode 100644 historic/jam/src/execunix.c create mode 100644 historic/jam/src/execvms.c create mode 100644 historic/jam/src/expand.c create mode 100644 historic/jam/src/expand.h create mode 100644 historic/jam/src/filemac.c create mode 100644 historic/jam/src/filent.c create mode 100644 historic/jam/src/fileos2.c create mode 100644 historic/jam/src/filesys.c create mode 100644 historic/jam/src/filesys.h create mode 100644 historic/jam/src/fileunix.c create mode 100644 historic/jam/src/filevms.c create mode 100644 historic/jam/src/frames.h create mode 100644 historic/jam/src/glob.c create mode 100644 historic/jam/src/hash.c create mode 100644 historic/jam/src/hash.h create mode 100644 historic/jam/src/hdrmacro.c create mode 100644 historic/jam/src/hdrmacro.h create mode 100644 historic/jam/src/headers.c create mode 100644 historic/jam/src/headers.h create mode 100644 historic/jam/src/jam.c create mode 100644 historic/jam/src/jam.h create mode 100644 historic/jam/src/jambase.c create mode 100644 historic/jam/src/jambase.h create mode 100644 historic/jam/src/jamgram.c create mode 100644 historic/jam/src/jamgram.h create mode 100644 historic/jam/src/jamgram.y create mode 100644 historic/jam/src/jamgram.yy create mode 100644 historic/jam/src/jamgramtab.h create mode 100644 historic/jam/src/lists.c create mode 100644 historic/jam/src/lists.h create mode 100644 historic/jam/src/make.c create mode 100644 historic/jam/src/make.h create mode 100644 historic/jam/src/make1.c create mode 100755 historic/jam/src/makecygwindebugjam.bat create mode 100755 historic/jam/src/makedebugjam.bat create mode 100644 historic/jam/src/makedebugjam.sh create mode 100644 historic/jam/src/mkjambase.c create mode 100644 historic/jam/src/modules.c create mode 100644 historic/jam/src/modules.h create mode 100644 historic/jam/src/newstr.c create mode 100644 historic/jam/src/newstr.h create mode 100644 historic/jam/src/option.c create mode 100644 historic/jam/src/option.h create mode 100644 historic/jam/src/parse.c create mode 100644 historic/jam/src/parse.h create mode 100644 historic/jam/src/patchlevel.h create mode 100644 historic/jam/src/pathmac.c create mode 100644 historic/jam/src/pathunix.c create mode 100644 historic/jam/src/pathvms.c create mode 100644 historic/jam/src/regexp.c create mode 100644 historic/jam/src/regexp.h create mode 100644 historic/jam/src/rules.c create mode 100644 historic/jam/src/rules.h create mode 100644 historic/jam/src/scan.c create mode 100644 historic/jam/src/scan.h create mode 100644 historic/jam/src/search.c create mode 100644 historic/jam/src/search.h create mode 100644 historic/jam/src/strings.c create mode 100644 historic/jam/src/strings.h create mode 100644 historic/jam/src/subst.c create mode 100644 historic/jam/src/timestamp.c create mode 100644 historic/jam/src/timestamp.h create mode 100644 historic/jam/src/variable.c create mode 100644 historic/jam/src/variable.h create mode 100644 historic/jam/src/yyacc create mode 100755 jam_src/Build.com create mode 100644 jam_src/Build.mpw create mode 100644 jam_src/INSTALL create mode 100644 jam_src/Jam.html create mode 100644 jam_src/Jambase create mode 100644 jam_src/Jambase.html create mode 100644 jam_src/Jamfile create mode 100644 jam_src/Jamfile.html create mode 100644 jam_src/Makefile create mode 100644 jam_src/Porting create mode 100644 jam_src/README create mode 100644 jam_src/RELNOTES create mode 100644 jam_src/command.c create mode 100644 jam_src/command.h create mode 100644 jam_src/common.mk create mode 100644 jam_src/compile.c create mode 100644 jam_src/compile.h create mode 100755 jam_src/debugjam0.bat create mode 100644 jam_src/debugjam0.sh create mode 100644 jam_src/execcmd.h create mode 100644 jam_src/execmac.c create mode 100644 jam_src/execnt.c create mode 100644 jam_src/execunix.c create mode 100644 jam_src/execvms.c create mode 100644 jam_src/expand.c create mode 100644 jam_src/expand.h create mode 100644 jam_src/filemac.c create mode 100644 jam_src/filent.c create mode 100644 jam_src/fileos2.c create mode 100644 jam_src/filesys.c create mode 100644 jam_src/filesys.h create mode 100644 jam_src/fileunix.c create mode 100644 jam_src/filevms.c create mode 100644 jam_src/frames.h create mode 100644 jam_src/glob.c create mode 100644 jam_src/hash.c create mode 100644 jam_src/hash.h create mode 100644 jam_src/hdrmacro.c create mode 100644 jam_src/hdrmacro.h create mode 100644 jam_src/headers.c create mode 100644 jam_src/headers.h create mode 100644 jam_src/jam.c create mode 100644 jam_src/jam.h create mode 100644 jam_src/jambase.c create mode 100644 jam_src/jambase.h create mode 100644 jam_src/jamgram.c create mode 100644 jam_src/jamgram.h create mode 100644 jam_src/jamgram.y create mode 100644 jam_src/jamgram.yy create mode 100644 jam_src/jamgramtab.h create mode 100644 jam_src/lists.c create mode 100644 jam_src/lists.h create mode 100644 jam_src/make.c create mode 100644 jam_src/make.h create mode 100644 jam_src/make1.c create mode 100755 jam_src/makecygwindebugjam.bat create mode 100755 jam_src/makedebugjam.bat create mode 100644 jam_src/makedebugjam.sh create mode 100644 jam_src/mkjambase.c create mode 100644 jam_src/modules.c create mode 100644 jam_src/modules.h create mode 100644 jam_src/newstr.c create mode 100644 jam_src/newstr.h create mode 100644 jam_src/option.c create mode 100644 jam_src/option.h create mode 100644 jam_src/parse.c create mode 100644 jam_src/parse.h create mode 100644 jam_src/patchlevel.h create mode 100644 jam_src/pathmac.c create mode 100644 jam_src/pathunix.c create mode 100644 jam_src/pathvms.c create mode 100644 jam_src/regexp.c create mode 100644 jam_src/regexp.h create mode 100644 jam_src/rules.c create mode 100644 jam_src/rules.h create mode 100644 jam_src/scan.c create mode 100644 jam_src/scan.h create mode 100644 jam_src/search.c create mode 100644 jam_src/search.h create mode 100644 jam_src/strings.c create mode 100644 jam_src/strings.h create mode 100644 jam_src/subst.c create mode 100644 jam_src/timestamp.c create mode 100644 jam_src/timestamp.h create mode 100644 jam_src/variable.c create mode 100644 jam_src/variable.h create mode 100644 jam_src/yyacc 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: + +

+ + + +
OSOS identifier string +
OSPLATUnderlying architecture, when applicable +
MACtrue on MAC platform +
NTtrue on NT platform +
OS2true on OS2 platform +
UNIXtrue on Unix platforms +
VMStrue on VMS platform + +
+ +

Jam Version Variables

+ +

+ + + +
JAMDATETime and date at jam start-up. +
JAMUNAMEOuput of uname(1) command (Unix only) +
JAMVERSIONjam 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 Reference + +

+
+

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


+

+ +Jambase Rules + +

+

+ 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: + +

+ 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: + + (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: +

+

    +
  1. Change the name of your buildable file or directory that conflicts. +

    +

  2. Modify your Jambase and change the name of the conflicting pseudotarget. +(Pseudotargets are defined in Jambase using the NOTFILE rule.) +

    +

  3. 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.exemain.obj, util.obj, libtree.lib +
libtree.libtreemake.obj, treetrav.obj +
treetrav.objtreetrav.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: +

+

    +
  1. Preface the Jamfile in each directory with an invocation + of the SubDir rule. +

    +

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

    +

  3. 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: +

    +
  1. 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. +

    +

  2. + 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: + +

    + + + +
    OSOS identifier string +
    OSPLATUnderlying architecture, when applicable +
    MACtrue on MAC platform +
    NTtrue on NT platform +
    OS2true on OS2 platform +
    UNIXtrue on Unix platforms +
    VMStrue on VMS platform + +
    + +

    Jam Version Variables

    + +

    + + + +
    JAMDATETime and date at jam start-up. +
    JAMUNAMEOuput of uname(1) command (Unix only) +
    JAMVERSIONjam 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 Reference + +

    +
    +

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


    +

    + +Jambase Rules + +

    +

    + 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: +

    +

      +
    1. Change the name of your buildable file or directory that conflicts. +

      +

    2. Modify your Jambase and change the name of the conflicting pseudotarget. +(Pseudotargets are defined in Jambase using the NOTFILE rule.) +

      +

    3. 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.exemain.obj, util.obj, libtree.lib +
    libtree.libtreemake.obj, treetrav.obj +
    treetrav.objtreetrav.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: +

    +

      +
    1. Preface the Jamfile in each directory with an invocation + of the SubDir rule. +

      +

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

      +

    3. 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: +

      +
    1. 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. +

      +

    2. + 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 */ + + 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/jam_src/pathunix.c b/jam_src/pathunix.c new file mode 100644 index 000000000..559d9c578 --- /dev/null +++ b/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/jam_src/pathvms.c b/jam_src/pathvms.c new file mode 100644 index 000000000..f89c95226 --- /dev/null +++ b/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/jam_src/regexp.c b/jam_src/regexp.c new file mode 100644 index 000000000..92ee8efd8 --- /dev/null +++ b/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/jam_src/regexp.h b/jam_src/regexp.h new file mode 100644 index 000000000..63507b475 --- /dev/null +++ b/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/jam_src/rules.c b/jam_src/rules.c new file mode 100644 index 000000000..bad40d6d6 --- /dev/null +++ b/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/jam_src/rules.h b/jam_src/rules.h new file mode 100644 index 000000000..ab1cff4ce --- /dev/null +++ b/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/jam_src/scan.c b/jam_src/scan.c new file mode 100644 index 000000000..f26f99204 --- /dev/null +++ b/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/jam_src/scan.h b/jam_src/scan.h new file mode 100644 index 000000000..37b026f1f --- /dev/null +++ b/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/jam_src/search.c b/jam_src/search.c new file mode 100644 index 000000000..b92f12961 --- /dev/null +++ b/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/jam_src/search.h b/jam_src/search.h new file mode 100644 index 000000000..bb8035723 --- /dev/null +++ b/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/jam_src/strings.c b/jam_src/strings.c new file mode 100644 index 000000000..7760d1fac --- /dev/null +++ b/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/jam_src/strings.h b/jam_src/strings.h new file mode 100644 index 000000000..6854eaaac --- /dev/null +++ b/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/jam_src/subst.c b/jam_src/subst.c new file mode 100644 index 000000000..471b8a563 --- /dev/null +++ b/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/jam_src/timestamp.c b/jam_src/timestamp.c new file mode 100644 index 000000000..3bd87d086 --- /dev/null +++ b/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/jam_src/timestamp.h b/jam_src/timestamp.h new file mode 100644 index 000000000..f290f82cb --- /dev/null +++ b/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/jam_src/variable.c b/jam_src/variable.c new file mode 100644 index 000000000..9dccea7fd --- /dev/null +++ b/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/jam_src/variable.h b/jam_src/variable.h new file mode 100644 index 000000000..77b89f1ea --- /dev/null +++ b/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/jam_src/yyacc b/jam_src/yyacc new file mode 100644 index 000000000..c6f7f5d15 --- /dev/null +++ b/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