Initial revision
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@189 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
0bb69689e4
commit
aa398c8e2c
31
src/tools/jam/Build.com
Executable file
31
src/tools/jam/Build.com
Executable file
@ -0,0 +1,31 @@
|
||||
! Bootstrap build script for Jam
|
||||
$ cxx /define=VMS builtins.c
|
||||
$ cxx /define=VMS command.c
|
||||
$ cxx /define=VMS compile.c
|
||||
$ cxx /define=VMS expand.c
|
||||
$ cxx /define=VMS execvms.c
|
||||
$ cxx /define=VMS filevms.c
|
||||
$ cxx /define=VMS glob.c
|
||||
$ cxx /define=VMS hash.c
|
||||
$ cxx /define=VMS headers.c
|
||||
$ cxx /define=VMS jambase.c
|
||||
$ cxx /define=VMS lists.c
|
||||
$ cxx /define=VMS make.c
|
||||
$ cxx /define=VMS make1.c
|
||||
$ cxx /define=VMS newstr.c
|
||||
$ cxx /define=VMS option.c
|
||||
$ cxx /define=VMS parse.c
|
||||
$ cxx /define=VMS pathvms.c
|
||||
$ cxx /define=VMS regexp.c
|
||||
$ cxx /define=VMS rules.c
|
||||
$ cxx /define=VMS scan.c
|
||||
$ cxx /define=VMS search.c
|
||||
$ cxx /define=VMS timestamp.c
|
||||
$ cxx /define=VMS variable.c
|
||||
$ cxx /define=VMS jam.c
|
||||
$ cxx /define=VMS jamgram.c
|
||||
$ cxxlink/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, builtins.obj
|
47
src/tools/jam/Build.mpw
Normal file
47
src/tools/jam/Build.mpw
Normal file
@ -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"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1350
src/tools/jam/Jam.html
Normal file
1350
src/tools/jam/Jam.html
Normal file
File diff suppressed because it is too large
Load Diff
1866
src/tools/jam/Jambase
Normal file
1866
src/tools/jam/Jambase
Normal file
File diff suppressed because it is too large
Load Diff
931
src/tools/jam/Jambase.html
Normal file
931
src/tools/jam/Jambase.html
Normal file
@ -0,0 +1,931 @@
|
||||
<HTML>
|
||||
<TITLE>
|
||||
Jambase Reference
|
||||
</TITLE>
|
||||
<BODY>
|
||||
<CENTER>
|
||||
<a href=http://www.perforce.com/jam/jam.html>
|
||||
Jam/MR
|
||||
</a>
|
||||
<H1>
|
||||
<A NAME="TOP">
|
||||
Jambase Reference
|
||||
</A>
|
||||
</H1>
|
||||
</CENTER>
|
||||
<P>
|
||||
Jambase is a base set of Jam/MR rules which
|
||||
provide roughly make(1)-like functionality for
|
||||
<a href="Jam.html"><b>jam</b></A>, the Jam/MR executable program.
|
||||
This document, which started out as the Jambase(5) man page,
|
||||
is a reference guide to the
|
||||
<A href="#RULES">rules</A>,
|
||||
<A href="#PSEUDOTARGETS">pseudotargets</A>,
|
||||
and <A href="#VARS">variables</A>
|
||||
defined in Jambase for use in Jamfiles.
|
||||
<P>
|
||||
For further information see:
|
||||
<UL>
|
||||
<LI>
|
||||
<a href="Jamfile.html">Using Jamfiles and Jambase</A>
|
||||
<LI>
|
||||
<a href="Jam.html">The Jam/MR Executable Program</A>
|
||||
</UL>
|
||||
<P>
|
||||
Jam/MR documentation and source are available from the
|
||||
<A HREF=http://public.perforce.com/public/index.html>Perforce Public Depot</a>.
|
||||
For detailed information about any of the rules summarized below,
|
||||
see the
|
||||
<A HREF=http://public.perforce.com/public/jam/src/Jambase>Jambase</a>
|
||||
file itself.
|
||||
<HR>
|
||||
<H2>
|
||||
<A NAME="RULES">
|
||||
Jambase Rules
|
||||
</A>
|
||||
</H2>
|
||||
<P>
|
||||
<B>As</B> <I>obj.o</I> : <I>source.s</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Assemble the file <I>source.s.</I> Called by the Object
|
||||
rule.
|
||||
</BLOCKQUOTE>
|
||||
<B>Bulk</B> <I>directory</I> : <I>sources</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Copies <I>sources</I> into <I>directory.</I>
|
||||
</BLOCKQUOTE>
|
||||
<B>Cc</B> <I>object</I> : <I>source</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Compile the file <I>source</I> into <I>object,</I> using the C
|
||||
compiler $(CC), its flags $(CCFLAGS) and $(OPTIM),
|
||||
and the header file directories $(HDRS). Called by
|
||||
the Object rule.
|
||||
</BLOCKQUOTE>
|
||||
<B>C++</B> <I>obj.o</I> : <I>source.cc</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Compile the C++ source file <I>source.cc.</I> Called by
|
||||
the Object rule.
|
||||
</BLOCKQUOTE>
|
||||
<B>Chmod</B> <I>target</I> ;
|
||||
<BLOCKQUOTE>
|
||||
<I>(Unix and VMS only.)</I>
|
||||
Change file permissions on <I>target</I> to
|
||||
target-specific $(MODE) value set by Link, File,
|
||||
Install*, and Shell rules.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<B>Clean</B> <I>clean</I> : <I>targets</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Removes existing <I>targets</I> when <I>clean</I> is built.
|
||||
clean is not a dependency of all, and must be built
|
||||
explicitly for targets to be removed.
|
||||
</BLOCKQUOTE>
|
||||
<B>FDefines</B> <I>defines</I> ; <BLOCKQUOTE>
|
||||
Expands a list of definitions into a list of compiler
|
||||
(or preprocessor) switches (such as
|
||||
-D<I>symbol</I>=<I>val</I> on Unix)
|
||||
to pass the definitions.
|
||||
</BLOCKQUOTE>
|
||||
<B>File</B> <I>target</I> : <I>source</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Copies <I>source</I> into <I>target.</I>
|
||||
</BLOCKQUOTE>
|
||||
<B>FIncludes</B> <I>dirs</I> ; <BLOCKQUOTE>
|
||||
Expands a list of directories into a list of compiler
|
||||
(or preprocessor) switches (such as -I<I>dir</I> on Unix)
|
||||
to add the directories to the header inclusion search path.
|
||||
</BLOCKQUOTE>
|
||||
<B>Fortran</B> <I>obj.o</I> : <I>source.f</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Compile the Fortran source file <I>source.f.</I> Called
|
||||
by the Object rule.
|
||||
</BLOCKQUOTE>
|
||||
<B>FQuote</B> <I>files</I> ; <BLOCKQUOTE>
|
||||
Returns each of <I>files</I> suitably quoted so as to hide shell
|
||||
metacharacters (such as whitespace and filename matching wildcards)
|
||||
from the shell.
|
||||
</BLOCKQUOTE>
|
||||
<P>
|
||||
<B>GenFile</B> <I>target</I> : <I>image</I> <I>sources</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Runs the command "<I>image</I> <I>target</I> <I>sources</I>"
|
||||
to create <I>target</I> from <I>sources</I> and
|
||||
<I>image</I>. (where <I>image</I> is an
|
||||
executable built by the Main rule.)
|
||||
</BLOCKQUOTE>
|
||||
<B>HardLink</B> <I>target</I> : <I>source</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Makes <I>target</I> a hard link to <I>source,</I> if it isn't one
|
||||
already. (Unix only.)
|
||||
</BLOCKQUOTE>
|
||||
<B>HdrRule</B> <I>source</I> : <I>headers</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Arranges the proper dependencies when the file
|
||||
<I>source</I> includes the files <I>headers</I> through the
|
||||
"#include" C preprocessor directive.
|
||||
<P>
|
||||
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).
|
||||
</BLOCKQUOTE>
|
||||
<B>InstallBin</B> <I>dir</I> : <I>sources</I> ; <BLOCKQUOTE>
|
||||
Copy <I>sources</I> into <I>dir</I> with mode
|
||||
$(EXEMODE).
|
||||
</BLOCKQUOTE>
|
||||
<B>InstallLib</B> <I>dir</I> : <I>sources</I> ; <BLOCKQUOTE>
|
||||
Copy <I>sources</I> into <I>dir</I> with mode
|
||||
$(FILEMODE).
|
||||
</BLOCKQUOTE>
|
||||
<B>InstallMan</B> <I>dir</I> : <I>sources</I> ; <BLOCKQUOTE>
|
||||
Copy <I>sources</I> into the appropriate subdirectory
|
||||
of <I>dir</I> with mode $(FILEMODE). The subdirectory
|
||||
is man<I>s,</I> where <I>s</I> is the suffix of
|
||||
each of sources.
|
||||
</BLOCKQUOTE>
|
||||
<B>InstallShell</B> <I>dir</I> : <I>sources</I> ; <BLOCKQUOTE>
|
||||
Copy <I>sources</I> into <I>dir</I> with mode
|
||||
$(SHELLMODE).
|
||||
</BLOCKQUOTE>
|
||||
<B>Lex</B> <I>source.c</I> : <I>source.l</I> ; <BLOCKQUOTE>
|
||||
Process the lex(1) source file <I>source.l</I> and
|
||||
rename the lex.yy.c to <I>source.c.</I> Called by
|
||||
the Object rule.
|
||||
</BLOCKQUOTE>
|
||||
<B>Library</B> <I>library</I> : <I>sources</I> ; <BLOCKQUOTE>
|
||||
Compiles <I>sources</I> and archives them into
|
||||
<I>library.</I> The intermediate <I>objects</I>
|
||||
are deleted. Calls Objects and LibraryFromObjects.
|
||||
<P>
|
||||
If Library is invoked with no suffix on <I>library</I>,
|
||||
the $(SUFLIB) suffix is used.
|
||||
</BLOCKQUOTE>
|
||||
<B>LibraryFromObjects</B> <I>library</I> : <I>objects</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Archives <I>objects</I> into <I>library.</I> The
|
||||
<I>objects</I> are then deleted.
|
||||
<P>
|
||||
If <I>library</I> has no suffix, the $(SUFLIB) suffix is used.
|
||||
</BLOCKQUOTE>
|
||||
<B>Link</B> <I>image</I> : <I>objects</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Links <I>image</I> from <I>objects</I> and sets
|
||||
permissions on <I>image</I> to $(EXEMODE).
|
||||
<I>Image</I> must be actual filename; suffix is not
|
||||
supplied.
|
||||
Called by Main.
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<B>LinkLibraries</B> <I>image</I> : <I>libraries</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Makes <I>image</I> depend on <I>libraries</I> and
|
||||
includes them during the linking.
|
||||
<P>
|
||||
<I>Image</I> may be referenced without a suffix in this
|
||||
rule invocation; LinkLibraries supplies the suffix.
|
||||
</BLOCKQUOTE>
|
||||
<B>Main</B> <I>image</I> : <I>sources</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Compiles <I>sources</I> and links them into <I>image.</I>
|
||||
Calls Objects and MainFromObjects.
|
||||
<P>
|
||||
<I>Image</I> may be referenced without a suffix in this
|
||||
rule invocation; Main supplies the suffix.
|
||||
</BLOCKQUOTE>
|
||||
<B>MainFromObjects</B> <I>image</I> : <I>objects</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Links <I>objects</I> into <I>image.</I> Dependency
|
||||
of exe. MainFromObjects supplies the suffix on <I>image</I>
|
||||
filename.
|
||||
</BLOCKQUOTE>
|
||||
<B>MakeLocate</B> <I>target</I> : <I>dir</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Creates <I>dir</I> and causes <I>target</I> to be built
|
||||
into <I>dir</I>.
|
||||
</BLOCKQUOTE>
|
||||
<B>MkDir</B> <I>dir</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Creates <I>dir</I> and its parent directories.
|
||||
</BLOCKQUOTE>
|
||||
<B>Object</B> <I>object</I> : <I>source</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Compiles a <I>single</I> source file source into
|
||||
<I>object.</I> The Main and Library rules use
|
||||
this rule to compile source files.
|
||||
<P>
|
||||
Causes <I>source</I> to be scanned for "#include"
|
||||
directives and calls HdrRule to make all included
|
||||
files dependedencies of <I>object</I>.
|
||||
<P>
|
||||
Calls one of the following rules to do the actual
|
||||
compiling, depending on the suffix of source:
|
||||
<PRE>
|
||||
*.c: Cc
|
||||
*.cc: C++
|
||||
*.cpp: C++
|
||||
*.C: C++
|
||||
*.l: Lex
|
||||
*.y: Yacc
|
||||
*.*: UserObject
|
||||
</PRE>
|
||||
</BLOCKQUOTE>
|
||||
<B>ObjectC++Flags</B> <I>source</I> : <I>flags</I> ;
|
||||
<BR>
|
||||
<B>ObjectCcFlags</B> <I>source</I> : <I>flags</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Add <I>flags</I> to the source-specific
|
||||
value of $(CCFLAGS) or $(C++FLAGS) when compiling <I>source.</I>
|
||||
Any file suffix on <I>source</I> is ignored.
|
||||
</BLOCKQUOTE>
|
||||
<B>ObjectDefines</B> <I>object</I> : <I>defines</I> ; <BLOCKQUOTE>
|
||||
Adds preprocessor symbol definitions to the (gristed)
|
||||
target-specific $(CCDEFS) for the <I>object</i>.
|
||||
</BLOCKQUOTE>
|
||||
<B>ObjectHdrs</B> <I>source</I> : <I>dirs</I> ; <BLOCKQUOTE>
|
||||
Add <I>dirs</I> to the source-specific value of
|
||||
$(HDRS) when scanning and compiling <I>source.</I>
|
||||
Any file suffix on <I>source</I> is ignored.
|
||||
</BLOCKQUOTE>
|
||||
<B>Objects</B> <I>sources</I> ; <BLOCKQUOTE>
|
||||
For each source file in <I>sources,</I> calls
|
||||
Object to compile the source file into a similarly
|
||||
named object file.
|
||||
</BLOCKQUOTE>
|
||||
<B>RmTemps</B> <I>targets</I> : <I>sources</I> ; <BLOCKQUOTE>
|
||||
Marks <I>sources</I> as temporary with the TEMPORARY
|
||||
rule, and deletes <I>sources</I> once <I>targets</I>
|
||||
are built. Must be the last rule invoked on
|
||||
<I>targets.</I> Used internally by LibraryFromObjects rule.
|
||||
</BLOCKQUOTE>
|
||||
<B>Setuid</B> <I>images</I> ; <BLOCKQUOTE>
|
||||
Sets the setuid bit on each of <I>images</I> after
|
||||
linking. (Unix only.)
|
||||
|
||||
</BLOCKQUOTE>
|
||||
<B>SoftLink</B> <I>target</I> : <I>source</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Makes <I>target</I> a symbolic link to <I>source,</I> if it isn't one
|
||||
already. (Unix only.)
|
||||
</BLOCKQUOTE>
|
||||
<B>SubDir</B> <I>VAR d1 ... dn</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Sets up housekeeping for the source files located
|
||||
in <I><CODE>$(VAR)/d1/.../dn</CODE></I>:
|
||||
<UL>
|
||||
<LI>Reads in rules file associated with <I>VAR</I>,
|
||||
if it hasn't already been read.
|
||||
<LI>Initializes variables for search paths,
|
||||
output directories, compiler
|
||||
flags, and grist, using <I>d1 ... dn</I> tokens.
|
||||
</UL>
|
||||
<P>
|
||||
<I>VAR</I> is the name of a variable;
|
||||
<I>d1</I> thru <I>dn</I> are elements
|
||||
of a directory path.
|
||||
</BLOCKQUOTE>
|
||||
<B>SubDirC++Flags</B> <I>flags</I> ;
|
||||
<BR>
|
||||
<B>SubDirCcFlags</B> <I>flags</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Adds <I>flags</I> to the compiler flags for source files
|
||||
in SubDir's directory.
|
||||
</BLOCKQUOTE>
|
||||
<B>SubDirHdrs</B> <I>d1 ... dn</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Adds the path <I>d1/.../dn/</I> to the header search paths for
|
||||
source files in SubDir's directory. <I>d1</I> through <I>dn</I>
|
||||
are elements of a directory path.
|
||||
</BLOCKQUOTE>
|
||||
<B>SubInclude</B> <I>VAR d1 ... dn</I> ;
|
||||
<BLOCKQUOTE>
|
||||
Reads the Jamfile in <I><CODE>$(VAR)/d1/.../dn/</CODE></I>.
|
||||
</BLOCKQUOTE>
|
||||
<B>Shell</B> <I>image</I> : <I>source</I> ; <BLOCKQUOTE>
|
||||
Copies <I>source</I> into the executable sh(1)
|
||||
script <I>image.</I> Ensures that the first line of
|
||||
the script is $(SHELLHEADER) (default #!/bin/sh).
|
||||
</BLOCKQUOTE>
|
||||
<B>Undefines</B> <I>images</I> : <I>symbols</I> ; <BLOCKQUOTE>
|
||||
Adds flags to mark <I>symbols</I> as undefined
|
||||
on link command for <I>images</I>.
|
||||
<I>Images</I> may be referenced unsuffixed; the
|
||||
Undefines rule supplies the suffix.
|
||||
</BLOCKQUOTE>
|
||||
<B>UserObject</B> <I>object</I> : <I>source</I> ; <BLOCKQUOTE>
|
||||
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 <I>source</I> with
|
||||
files suffixes it does not recognize.
|
||||
</BLOCKQUOTE>
|
||||
<B>Yacc</B> <I>source.c</I> : <I>source.y</I> ; <BLOCKQUOTE>
|
||||
Process the yacc(1) file <I>source.y</I> and renamed
|
||||
the resulting y.tab.c and y.tab.h to <I>source.c.</I>
|
||||
Produces a y.tab.h and renames it to <I>source.h.</I>
|
||||
Called by the <B>Object</B> rule.
|
||||
</BLOCKQUOTE>
|
||||
<P>
|
||||
<HR>
|
||||
<A NAME="PSEUDOTARGETS">
|
||||
<H3>
|
||||
Jambase Pseudotargets
|
||||
</H3>
|
||||
</A>
|
||||
<P>
|
||||
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:
|
||||
<CENTER>
|
||||
<TABLE CELLPADDING=5%>
|
||||
<TR><TD>exe
|
||||
<TD>Executables linked by the Main or MainFromObjects rules
|
||||
|
||||
<TR><TD>lib
|
||||
<TD>Libraries created by the Library or LibraryFromObjects rules
|
||||
|
||||
<TR><TD>obj
|
||||
<TD>Compiled objects used to create Main or Library targets
|
||||
|
||||
<TR><TD>dirs
|
||||
<TD>Directories where target files are written
|
||||
|
||||
<TR><TD>file
|
||||
<TD>Files copied by File and Bulk rules
|
||||
|
||||
<TR><TD>shell
|
||||
<TD>Files copied by Shell rule
|
||||
|
||||
<TR><TD>clean
|
||||
<TD>Removal of built targets (except files copied by Install* rules)
|
||||
|
||||
<TR><TD>install
|
||||
<TD>Files copied by Install* rules
|
||||
|
||||
<TR><TD>uninstall
|
||||
<TD>Removal of targets copied by Install* rules
|
||||
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
<P>
|
||||
In addition, Jambase makes the <b>jam</b> default target "all"
|
||||
depend on "exe", "lib", "obj", "files", and "shell".
|
||||
<P>
|
||||
|
||||
<HR>
|
||||
<A NAME="VARS">
|
||||
<H3>
|
||||
Jambase Variables
|
||||
</H3>
|
||||
</A>
|
||||
<P>
|
||||
Most of the following variables have default values for
|
||||
each platform; refer to the Jambase file to see what those
|
||||
defaults are.
|
||||
<P>
|
||||
ALL_LOCATE_TARGET
|
||||
<BLOCKQUOTE>
|
||||
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 <b>jam</b>
|
||||
to write built targets to a location outside
|
||||
the source tree.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
AR
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The archive command used to update Library
|
||||
and LibraryFromObjects targets.
|
||||
</BLOCKQUOTE>
|
||||
AS
|
||||
<BLOCKQUOTE>
|
||||
The assembler for As rule targets.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
ASFLAGS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Flags handed to the assembler for As.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
AWK
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The name of awk interpreter, used when copying a
|
||||
shell script for the Shell rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
BCCROOT
|
||||
<BLOCKQUOTE>
|
||||
Selects Borland compile and link actions on NT.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
BINDIR
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Not longer used.
|
||||
(I.e., used only for backward compatibility with the
|
||||
obsolete INSTALLBIN rule.)
|
||||
</BLOCKQUOTE>
|
||||
|
||||
CC
|
||||
|
||||
<BLOCKQUOTE>
|
||||
C compiler used for Cc rule targets.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
CCFLAGS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Compile flags for Cc rule targets.
|
||||
The Cc rule sets target-specific $(CCFLAGS)
|
||||
values on its targets.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
C++
|
||||
|
||||
<BLOCKQUOTE>
|
||||
C++ compiler used for C++ rule targets.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
C++FLAGS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Compile flags for C++ rule targets.
|
||||
The C++ rule sets target-specific $(C++FLAGS)
|
||||
values on its targets.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
CHMOD
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Program (usually chmod(1)) used to set file
|
||||
permissions for Chmod rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
CP
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The file copy program, used by File and Install* rules.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
CRELIB
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
CW
|
||||
|
||||
<BLOCKQUOTE>
|
||||
On Macintosh, the root of the Code Warrior Pro 5 directory.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
DEFINES
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Preprocessor symbol definitions for Cc and C++ rule targets.
|
||||
The Cc and C++ rules set target-specific $(CCDEFS)
|
||||
values on their targets, based on $(DEFINES). (The
|
||||
"indirection" here is required to support compilers,
|
||||
like VMS, with baroque command line syntax for
|
||||
setting symbols).
|
||||
</BLOCKQUOTE>
|
||||
|
||||
DOT
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The operating system-specific name for the current directory.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
DOTDOT
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The operating system-specific name for the parent directory.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
EXEMODE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Permissions for executables linked with Link, Main,
|
||||
and MainFromObjects, on platforms with a Chmod action.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
FILEMODE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Permissions for files copied by File or Bulk,
|
||||
on platforms with a Chmod action.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
FORTRAN
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The Fortran compiler used by Fortran rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
FORTRANFLAGS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Fortran compiler flags for Fortran rule targets.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
GROUP
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<I>(Unix only.)</I>
|
||||
The group owner for Install* rule targets.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
HDRGRIST
|
||||
|
||||
<BLOCKQUOTE>
|
||||
If set, used by the HdrRule to distinguish header files
|
||||
with the same name in diffrent directories.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
HDRPATTERN
|
||||
|
||||
<BLOCKQUOTE>
|
||||
A regular expression pattern that matches
|
||||
C preprocessor "#include" directives in source files
|
||||
and returns the name of the included file.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
HDRRULE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Name of the rule to invoke with the results of header file
|
||||
scanning. Default is "HdrRule".
|
||||
<P>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
HDRS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Directories to be searched for header files.
|
||||
This is used by the Object rule to:
|
||||
<UL>
|
||||
<LI>set up search paths for finding files returned
|
||||
by header scans
|
||||
<LI>add -I flags on compile commands
|
||||
</UL>
|
||||
(See STDHDRS.)
|
||||
</BLOCKQUOTE>
|
||||
|
||||
HDRSCAN
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Regular expression pattern to use for header file
|
||||
scanning. The Object rule sets this to $(HDRPATTERN).
|
||||
This is a jam-special variable; see HDRRULE.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
HDRSEARCH
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Used by the HdrRule to fix the list of directories where
|
||||
header files can be found for a given source file.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
INSTALLGRIST
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Used by the Install* rules to grist paths to installed
|
||||
files; defaults to "installed".
|
||||
</BLOCKQUOTE>
|
||||
|
||||
JAMFILE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Default is "Jamfile"; the name of the user-written
|
||||
rules file found in each source directory.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
JAMRULES
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Default is "Jamrules"; the name of a rule definition
|
||||
file to be read in at the first SubDir rule invocation.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
KEEPOBJS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
If set, tells the LibraryFromObjects rule not to delete
|
||||
object files once they are archived.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LEX
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The lex(1) command and flags.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LIBDIR
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Not longer used.
|
||||
(I.e., used only for backward compatibility with the
|
||||
obsolete INSTALLLIB rule.)
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LINK
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The linker. Defaults to $(CC).
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LINKFLAGS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Flags handed to the linker. Defaults to $(CCFLAGS).
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LINKLIBS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
List of external libraries to link with. The target image
|
||||
does not depend on these libraries.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LN
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The hard link command for HardLink rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LOCATE_SOURCE
|
||||
<BLOCKQUOTE>
|
||||
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.)
|
||||
</BLOCKQUOTE>
|
||||
|
||||
LOCATE_TARGET
|
||||
<BLOCKQUOTE>
|
||||
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.)
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
MANDIR
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Not longer used.
|
||||
(I.e., used only for backward compatibility with the
|
||||
obsolete INSTALLMAN rule.)
|
||||
</BLOCKQUOTE>
|
||||
|
||||
MKDIR
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The 'create directory' command used for the MkDir
|
||||
rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
MODE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
MSVC
|
||||
<BLOCKQUOTE>
|
||||
Selects Microsoft Visual C 16-bit compile & link
|
||||
actions on NT.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
MSVCNT
|
||||
<BLOCKQUOTE>
|
||||
Selects Microsoft Visual C NT compile & link
|
||||
actions on NT.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
MV
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The file rename command and options.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
NEEDLIBS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The list of libraries used when linking an executable.
|
||||
Used by the Link rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
NOARSCAN
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
NOARUPDATE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
If set, indicates that libraries can't be updated, but only
|
||||
created whole.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
OPTIM
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The C compiler flag for optimization, used by Cc and C++
|
||||
rules.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
OSFULL
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
OWNER
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The owner of installed files. Used by Install* rules.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
RANLIB
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
RELOCATE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
RM
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The command and options to remove a file.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SEARCH_SOURCE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SHELLHEADER
|
||||
|
||||
<BLOCKQUOTE>
|
||||
A string inserted to the first line of every file
|
||||
created by the Shell rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SHELLMODE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
Permissions for files installed by Shell rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SOURCE_GRIST
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
STDHDRS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
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.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SUBDIR
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The path from the current directory to the directory
|
||||
last named by the SubDir rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
TOP
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The path from the current directory to the directory
|
||||
that has the Jamrules file. Used by the SubDir rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SUFEXE
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The suffix for executable files, if none provided.
|
||||
Used by the Main rule.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SUFLIB
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The suffix for libraries. Used by the Library and
|
||||
related rules.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
SUFOBJ
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The suffix for object files. Used by the Objects
|
||||
and related rules.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
UNDEFFLAG
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The flag prefixed to each symbol for the Undefines
|
||||
rule (i.e., the compiler flag for undefined symbols).
|
||||
</BLOCKQUOTE>
|
||||
|
||||
WATCOM
|
||||
<BLOCKQUOTE>
|
||||
Selects Watcom compile and link actions on OS2.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
YACC
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The yacc(1) command.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
YACCFILES
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The base filename generated by yacc(1).
|
||||
</BLOCKQUOTE>
|
||||
|
||||
YACCFLAGS
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The yacc(1) command flags.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
YACCGEN
|
||||
|
||||
<BLOCKQUOTE>
|
||||
The suffix used on generated yacc(1) output.
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>
|
||||
<HR>
|
||||
<A HREF="#TOP">Back to top.</A>
|
||||
<P>
|
||||
Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
<BR>
|
||||
Comments to <A HREF="mailto:info@perforce.com">info@perforce.com</A>
|
||||
<BR>
|
||||
Last updated: Dec 31, 2000
|
||||
<BR>
|
||||
$Id: //public/jam/src/Jambase.html#7 $
|
||||
</BODY>
|
||||
</HTML>
|
1450
src/tools/jam/Jamfile.html
Normal file
1450
src/tools/jam/Jamfile.html
Normal file
File diff suppressed because it is too large
Load Diff
71
src/tools/jam/Makefile
Normal file
71
src/tools/jam/Makefile
Normal file
@ -0,0 +1,71 @@
|
||||
# Makefile for jam
|
||||
|
||||
CC = cc
|
||||
TARGET = -o jam0
|
||||
CFLAGS =
|
||||
|
||||
# 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
|
||||
|
||||
# NT (with Microsoft compiler)
|
||||
# People with DevStudio settings already in shell environment.
|
||||
#CC = cl /nologo
|
||||
#CFLAGS = -DNT
|
||||
#TARGET = /Fejam0
|
||||
|
||||
# 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__
|
||||
|
||||
# MingW32
|
||||
#CC = gcc
|
||||
#CFLAGS = -DMINGW
|
||||
|
||||
# MPEIX
|
||||
#CC = gcc
|
||||
#CFLAGS = -I/usr/include -D_POSIX_SOURCE
|
||||
|
||||
# QNX rtp (neutrino)
|
||||
#CC = gcc
|
||||
|
||||
SOURCES = \
|
||||
builtins.c \
|
||||
command.c compile.c execunix.c execvms.c expand.c \
|
||||
filent.c fileos2.c fileunix.c filevms.c glob.c hash.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 timestamp.c variable.c
|
||||
|
||||
all: jam0
|
||||
jam0
|
||||
|
||||
jam0:
|
||||
$(CC) $(TARGET) $(CFLAGS) $(SOURCES) $(LINKLIBS)
|
68
src/tools/jam/Porting
Normal file
68
src/tools/jam/Porting
Normal file
@ -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.
|
149
src/tools/jam/README
Normal file
149
src/tools/jam/README
Normal file
@ -0,0 +1,149 @@
|
||||
Jam/MR (aka "jam - make(1) redux")
|
||||
|
||||
/+\
|
||||
+\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
\+/
|
||||
|
||||
This is Release 2.4 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 and language reference.
|
||||
|
||||
Jambase.html Reference for the Jambase boilerplate file.
|
||||
|
||||
Jamfile.html Easy reading on creating a Jamfile and using jam.
|
||||
|
||||
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
|
||||
March, 2002 - release 2.4
|
||||
|
||||
|
||||
Christopher Seiwald
|
||||
|
||||
seiwald@perforce.com
|
924
src/tools/jam/RELNOTES
Normal file
924
src/tools/jam/RELNOTES
Normal file
@ -0,0 +1,924 @@
|
||||
Release notes for Jam/MR 2.4
|
||||
(aka Jam - make(1) redux)
|
||||
|
||||
1. Release info:
|
||||
|
||||
Jam/MR 2.4
|
||||
March, 21, 2002
|
||||
VERSION 2.4
|
||||
|
||||
2. Compatibility
|
||||
|
||||
Jam 2.4 is upward compatible with Jam 2.3
|
||||
|
||||
The Jam 2.4 language is a superset of the 2.3 language;
|
||||
Jamfiles, Jambase, and other rulesets used in 2.3 can be used
|
||||
with the 2.4 language support.
|
||||
|
||||
3. Changes since 2.3.
|
||||
|
||||
3.1. Changes to Jam Language
|
||||
|
||||
The mechanism for calling rules that return values - "[ rule
|
||||
args ...]", (and 'return' in the rule body), is now a
|
||||
documented part of the language.
|
||||
|
||||
Add "on <target> <rulename> <field1> ..." syntax, to invoke a
|
||||
rule under the influence of a target's specific variables.
|
||||
|
||||
Add "[ on targ rule ... ]" to call a rule returning a value,
|
||||
under the influence of a target's specific variables.
|
||||
|
||||
New 'Glob' builtin that returns a list of files, given a list
|
||||
of directories, and a list of filename patterns.
|
||||
|
||||
New 'while expr { block }' construct.
|
||||
|
||||
New :E=value modifier provides default value if variable unset.
|
||||
|
||||
New :J=joinval modifier concatenates list elements into single
|
||||
element, separated by joinval.
|
||||
|
||||
\ can now be used to escape a space (or any single whitespace
|
||||
character), so that you don't have to resort to quotes.
|
||||
|
||||
New 'Match regexp : string' rule matches regexp against string
|
||||
and returns list of results.
|
||||
|
||||
Rules can now be invoked indirectly, through variable names.
|
||||
If the variable expands to an empty list, no rule is run.
|
||||
If the variable expands to multiple entries, each rule is
|
||||
run with the same arguments. The result of the rule invocation
|
||||
is the concatenation of the results of the rules invoked.
|
||||
|
||||
'Echo' and 'Exit' now have aliases 'echo' and 'exit', since it
|
||||
is really hard to tell that these are built-in rules and not
|
||||
part of the language, like 'include'. Real rules continue to
|
||||
start with a capital.
|
||||
|
||||
3.2. Jambase Changes
|
||||
|
||||
Support for YACCGEN, the suffix used on generated yacc output.
|
||||
|
||||
Fix ups to have jam and p4 build with borland C 5.5,
|
||||
and minor win98 jam support for jam clean
|
||||
|
||||
SubDirHdrs now takes directory names in the same format as
|
||||
SubInclude : one directory element per word.
|
||||
|
||||
More portable support for specifying includes and #defines:
|
||||
New ASHDRS, CCHDRS, CCDEFS, DEFINES, ObjectDefines, FQuote,
|
||||
FIncludes, FDefines. Ordering of cc and c++ flags grossly
|
||||
rearranged.
|
||||
|
||||
Jambase has been compacted by applying the new E: and J:
|
||||
expansion modifiers.
|
||||
|
||||
New SoftLink rule, courtesy of David Lindes. It currently
|
||||
assumes you can pass a -s flag to $(LN).
|
||||
|
||||
3.3 'jam' Changes (See Jam.html)
|
||||
|
||||
Added '-q' (quit quick) option; jam will exit promptly (as if it
|
||||
received an interrupt), as soon as any target fails.
|
||||
|
||||
Added experimental '-g' (build newest sources first) option:
|
||||
all things being equal, normally targets are simply built in
|
||||
the order they appear in the Jamfiles. With this flag, targets
|
||||
with the newest sources are built first. From an idea by Arnt
|
||||
Gulbrandsen. Undocumented (outside this note).
|
||||
|
||||
3.4. Jam internal code changes
|
||||
|
||||
jamgram.yy now defines YYMAXDEPTH to 10000, what it is on
|
||||
FreeBSD, for older yaccs that left it at 150 or so. This is
|
||||
needed for the right-recursion now used in the grammar.
|
||||
|
||||
Optimize rule compilation, with right-recursion instead of left.
|
||||
|
||||
Split jam's built-in rules out to builtins.c from compile.c,
|
||||
so that compile.c only deals with the language.
|
||||
|
||||
Split jam's pathsys.h from filesys.h, since they are really
|
||||
two different pieces.
|
||||
|
||||
evaluate_if(), which evaluated the condition tree for 'if' and
|
||||
returned an int, has been replaced with compile_eval(), which does
|
||||
essentially the same but returns a LIST.
|
||||
|
||||
4. Fixed bugs
|
||||
|
||||
Missing TEMPORARY targets with multiple parents no longer spoil one
|
||||
parent's time with another. The parents' time is used for comparison
|
||||
with dependents, but no longer taken on as the target's own time.
|
||||
|
||||
'actions updated', not 'actions together', now protects targets
|
||||
from being deleted on failed/interrupted updates.
|
||||
|
||||
Fixed broken $(v[1-]), which always returned an empty expansion.
|
||||
Thanks to Ian Godin <ian@sgrail.com>.
|
||||
|
||||
Defining a rule within another rule, and invoking the enclosing
|
||||
rule more than once, would result in giving the first rule a
|
||||
null definition. Fixed.
|
||||
|
||||
$(d:P) now works properly on the mac, climbing up directories.
|
||||
Thanks to Miklos Fazekas <boga@mac.com>.
|
||||
|
||||
No longer (sometimes) treat \ as a directory separator on
|
||||
UNIX. It isn't supposed to be, but was due to bungled ifdefs.
|
||||
|
||||
Applying just :U or :D (or :E, :J) mods no longer causes the
|
||||
variable value to be treated as a filename (parsed and rebuilt
|
||||
using the OS specific pathsys routines). Previously, if _any_
|
||||
mods were present then the value was parsed and rebuilt as if
|
||||
a filename, and that could in certain cases munge the value.
|
||||
Only the file modifiers (:GDBSM) treat the value as a
|
||||
filename.
|
||||
|
||||
Four rules makeCommon, makeGrist, makeString, makeSubDir from
|
||||
jam 2.2 missing in 2.3 have been re-added, with apologies to
|
||||
dtb@cisco.com.
|
||||
|
||||
Return status more likely to be correct when using -d0, now that
|
||||
targets are could as being built even with no debugging output.
|
||||
Thanks to Miklos Fazekas <boga@mac.com>.
|
||||
|
||||
yyacc now suffixes all terminals it defines with _t, so that they
|
||||
don't conflict with other symbols (like RULE with the typedef
|
||||
in rules.h). Thanks to Michael Allard.
|
||||
|
||||
InstallInto now handles multiple sources properly, rather than
|
||||
acting as if each installed target depended on all sources to
|
||||
be installed. $(INSTALLGRIST) is now the default grist for
|
||||
installed targets, rather than the hardcoded 'installed'. Thanks
|
||||
to Stephen Goodson.
|
||||
|
||||
5. Porting
|
||||
|
||||
[MACINTOSH] Paths are now downshifted (internally) so as to
|
||||
handle its case insensitivity. Thanks to Miklos Fazekas
|
||||
<boga@mac.com>.
|
||||
|
||||
[NT] MS changed the macro for the IA64 Windows NT 64bit
|
||||
compiler.
|
||||
|
||||
[CYGWIN] Cygwin jam porting: dance around bison and yyacc.
|
||||
Use bison's -y flag to use yacc's output file naming
|
||||
conventions, and don't use yyacc on systems whose SUFEXE is
|
||||
set.
|
||||
|
||||
[VMS] The Jambase itself was not formatting the CCHDRS and
|
||||
CCDEFS properly: on VMS they can't be appended to, because
|
||||
multiple /define or /include directives don't work. Instead
|
||||
now CCHDRS and CCDEFS is reformatted from HDRS and DEFINES
|
||||
anytime those latter two change. This requires the recent
|
||||
change to jam to allow access to target-specific variables
|
||||
when setting other variables.
|
||||
|
||||
[VMS] Remove exception call when file_dirscan() can't, for
|
||||
some reason, scan a directory. Use a better set of #ifdefs to
|
||||
determine if we're on a vax, rather than relying on the C
|
||||
compiler being a specific version: we're able to build with
|
||||
the C++ compiler now.
|
||||
|
||||
[VMS] Port new jam to run with just cxx compiler.
|
||||
(The C compiler being a extra-cost item).
|
||||
|
||||
[NT] Add entry for DevStudio when the settings are already in the
|
||||
system environment.
|
||||
|
||||
[NT] default $(MV) to "move /y" in Jambase.
|
||||
|
||||
[MINGW] Mingw port by Max Blagai.
|
||||
|
||||
===============================================================================
|
||||
===============================================================================
|
||||
|
||||
|
||||
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 <time.h> /* could be <sys/time.h> */
|
||||
|
||||
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 <john@nanaon-sha.co.jp>.
|
||||
|
||||
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
|
||||
|
||||
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 <gsar@engin.umich.edu>)
|
||||
|
||||
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<x> 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.
|
293
src/tools/jam/builtins.c
Normal file
293
src/tools/jam/builtins.c
Normal file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
|
||||
# include "lists.h"
|
||||
# include "parse.h"
|
||||
# include "builtins.h"
|
||||
# include "rules.h"
|
||||
# include "filesys.h"
|
||||
# include "newstr.h"
|
||||
# include "regexp.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
/*
|
||||
* builtins.c - builtin jam rules
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* load_builtin() - define builtin rules
|
||||
*
|
||||
* Internal routines:
|
||||
*
|
||||
* builtin_depends() - DEPENDS/INCLUDES rule
|
||||
* builtin_echo() - ECHO rule
|
||||
* builtin_exit() - EXIT rule
|
||||
* builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
|
||||
* builtin_glob() - GLOB rule
|
||||
* builtin_match() - MATCH rule
|
||||
*
|
||||
* 01/10/01 (seiwald) - split from compile.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* compile_builtin() - define builtin rules
|
||||
*/
|
||||
|
||||
# define P0 (PARSE *)0
|
||||
# define C0 (char *)0
|
||||
|
||||
LIST *builtin_depends( PARSE *parse, LOL *args );
|
||||
LIST *builtin_echo( PARSE *parse, LOL *args );
|
||||
LIST *builtin_exit( PARSE *parse, LOL *args );
|
||||
LIST *builtin_flags( PARSE *parse, LOL *args );
|
||||
LIST *builtin_glob( PARSE *parse, LOL *args );
|
||||
LIST *builtin_match( PARSE *parse, LOL *args );
|
||||
|
||||
int glob( char *s, char *c );
|
||||
|
||||
void
|
||||
load_builtins()
|
||||
{
|
||||
bindrule( "Always" )->procedure =
|
||||
bindrule( "ALWAYS" )->procedure =
|
||||
parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_TOUCHED );
|
||||
|
||||
bindrule( "Depends" )->procedure =
|
||||
bindrule( "DEPENDS" )->procedure =
|
||||
parse_make( builtin_depends, P0, P0, P0, C0, C0, T_DEPS_DEPENDS );
|
||||
|
||||
bindrule( "echo" )->procedure =
|
||||
bindrule( "Echo" )->procedure =
|
||||
bindrule( "ECHO" )->procedure =
|
||||
parse_make( builtin_echo, P0, P0, P0, C0, C0, 0 );
|
||||
|
||||
bindrule( "exit" )->procedure =
|
||||
bindrule( "Exit" )->procedure =
|
||||
bindrule( "EXIT" )->procedure =
|
||||
parse_make( builtin_exit, P0, P0, P0, C0, C0, 0 );
|
||||
|
||||
bindrule( "Glob" )->procedure =
|
||||
bindrule( "GLOB" )->procedure =
|
||||
parse_make( builtin_glob, P0, P0, P0, C0, C0, 0 );
|
||||
|
||||
bindrule( "Includes" )->procedure =
|
||||
bindrule( "INCLUDES" )->procedure =
|
||||
parse_make( builtin_depends, P0, P0, P0, C0, C0, T_DEPS_INCLUDES );
|
||||
|
||||
bindrule( "Leaves" )->procedure =
|
||||
bindrule( "LEAVES" )->procedure =
|
||||
parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_LEAVES );
|
||||
|
||||
bindrule( "Match" )->procedure =
|
||||
bindrule( "MATCH" )->procedure =
|
||||
parse_make( builtin_match, P0, P0, P0, C0, C0, 0 );
|
||||
|
||||
bindrule( "NoCare" )->procedure =
|
||||
bindrule( "NOCARE" )->procedure =
|
||||
parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_NOCARE );
|
||||
|
||||
bindrule( "NOTIME" )->procedure =
|
||||
bindrule( "NotFile" )->procedure =
|
||||
bindrule( "NOTFILE" )->procedure =
|
||||
parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_NOTFILE );
|
||||
|
||||
bindrule( "NoUpdate" )->procedure =
|
||||
bindrule( "NOUPDATE" )->procedure =
|
||||
parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_NOUPDATE );
|
||||
|
||||
bindrule( "Temporary" )->procedure =
|
||||
bindrule( "TEMPORARY" )->procedure =
|
||||
parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_TEMP );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
LIST *
|
||||
builtin_depends(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *targets = lol_get( args, 0 );
|
||||
LIST *sources = lol_get( 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.
|
||||
*/
|
||||
|
||||
LIST *
|
||||
builtin_echo(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
list_print( lol_get( 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.
|
||||
*/
|
||||
|
||||
LIST *
|
||||
builtin_exit(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
list_print( lol_get( 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.
|
||||
*/
|
||||
|
||||
LIST *
|
||||
builtin_flags(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *l = lol_get( args, 0 );
|
||||
|
||||
for( ; l; l = list_next( l ) )
|
||||
bindtarget( l->string )->flags |= parse->num;
|
||||
|
||||
return L0;
|
||||
}
|
||||
|
||||
/*
|
||||
* builtin_globbing() - GLOB rule
|
||||
*/
|
||||
|
||||
struct globbing {
|
||||
LIST *patterns;
|
||||
LIST *results;
|
||||
} ;
|
||||
|
||||
static void
|
||||
builtin_glob_back(
|
||||
void *closure,
|
||||
char *file,
|
||||
int status,
|
||||
time_t time )
|
||||
{
|
||||
struct globbing *globbing = (struct globbing *)closure;
|
||||
LIST *l;
|
||||
PATHNAME f;
|
||||
char buf[ MAXJPATH ];
|
||||
|
||||
/* Null out directory for matching. */
|
||||
/* We wish we had file_dirscan() pass up a PATHNAME. */
|
||||
|
||||
path_parse( file, &f );
|
||||
f.f_dir.len = 0;
|
||||
path_build( &f, buf, 0 );
|
||||
|
||||
for( l = globbing->patterns; l; l = l->next )
|
||||
if( !glob( l->string, buf ) )
|
||||
{
|
||||
globbing->results = list_new( globbing->results, newstr( file ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LIST *
|
||||
builtin_glob(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *l = lol_get( args, 0 );
|
||||
LIST *r = lol_get( args, 1 );
|
||||
|
||||
struct globbing globbing;
|
||||
|
||||
globbing.results = L0;
|
||||
globbing.patterns = r;
|
||||
|
||||
for( ; l; l = list_next( l ) )
|
||||
file_dirscan( l->string, builtin_glob_back, &globbing );
|
||||
|
||||
return globbing.results;
|
||||
}
|
||||
|
||||
/*
|
||||
* builtin_match() - MATCH rule, regexp matching
|
||||
*/
|
||||
|
||||
LIST *
|
||||
builtin_match(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *l, *r;
|
||||
LIST *result = 0;
|
||||
|
||||
/* For each pattern */
|
||||
|
||||
for( l = lol_get( args, 0 ); l; l = l->next )
|
||||
{
|
||||
regexp *re = regcomp( l->string );
|
||||
|
||||
/* For each string to match against */
|
||||
|
||||
for( r = lol_get( args, 1 ); r; r = r->next )
|
||||
if( regexec( re, r->string ) )
|
||||
{
|
||||
int i, top;
|
||||
|
||||
/* Find highest parameter */
|
||||
|
||||
for( top = NSUBEXP; top-- > 1; )
|
||||
if( re->startp[top] )
|
||||
break;
|
||||
|
||||
/* And add all parameters up to highest onto list. */
|
||||
/* Must have parameters to have results! */
|
||||
|
||||
for( i = 1; i <= top; i++ )
|
||||
{
|
||||
char buf[ MAXSYM ];
|
||||
int l = re->endp[i] - re->startp[i];
|
||||
memcpy( buf, re->startp[i], l );
|
||||
buf[ l ] = 0;
|
||||
result = list_new( result, newstr( buf ) );
|
||||
}
|
||||
}
|
||||
|
||||
free( (char *)re );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
12
src/tools/jam/builtins.h
Normal file
12
src/tools/jam/builtins.h
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* builtins.h - compile parsed jam statements
|
||||
*/
|
||||
|
||||
void load_builtins();
|
||||
|
63
src/tools/jam/command.c
Normal file
63
src/tools/jam/command.c
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* 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 ) );
|
||||
|
||||
cmd->rule = rule;
|
||||
cmd->shell = shell;
|
||||
cmd->next = 0;
|
||||
|
||||
lol_init( &cmd->args );
|
||||
lol_add( &cmd->args, targets );
|
||||
lol_add( &cmd->args, sources );
|
||||
|
||||
/* Bail if the result won't fit in MAXLINE */
|
||||
/* We don't free targets/sources/shell if bailing. */
|
||||
|
||||
if( var_string( rule->actions, cmd->buf, MAXLINE, &cmd->args ) < 0 )
|
||||
{
|
||||
cmd_free( cmd );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd_free() - free a CMD
|
||||
*/
|
||||
|
||||
void
|
||||
cmd_free( CMD *cmd )
|
||||
{
|
||||
lol_free( &cmd->args );
|
||||
list_free( cmd->shell );
|
||||
free( (char *)cmd );
|
||||
}
|
58
src/tools/jam/command.h
Normal file
58
src/tools/jam/command.h
Normal file
@ -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[ MAXLINE ]; /* 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)
|
808
src/tools/jam/compile.c
Normal file
808
src/tools/jam/compile.c
Normal file
@ -0,0 +1,808 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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 "variable.h"
|
||||
# include "expand.h"
|
||||
# include "rules.h"
|
||||
# include "newstr.h"
|
||||
# include "search.h"
|
||||
|
||||
/*
|
||||
* compile.c - compile parsed jam statements
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* compile_append() - append list results of two statements
|
||||
* compile_eval() - evaluate if to determine which leg to compile
|
||||
* compile_foreach() - compile the "for x in y" statement
|
||||
* compile_if() - compile 'if' 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_on() - run rule under influence of on-target variables
|
||||
* 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_rule() - execute a rule invocation
|
||||
*
|
||||
* 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.
|
||||
* 01/10/00 (seiwald) - built-ins split out to builtin.c.
|
||||
*/
|
||||
|
||||
static void debug_compile( int which, char *s );
|
||||
int glob( char *s, char *c );
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 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,
|
||||
LOL *args )
|
||||
{
|
||||
/* Append right to left. */
|
||||
|
||||
return list_append(
|
||||
(*parse->left->func)( parse->left, args ),
|
||||
(*parse->right->func)( parse->right, args ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* compile_eval() - evaluate if to determine which leg to compile
|
||||
*
|
||||
* Returns:
|
||||
* list if expression true - compile 'then' clause
|
||||
* L0 if expression false - compile 'else' clause
|
||||
*/
|
||||
|
||||
static int
|
||||
lcmp( LIST *t, LIST *s )
|
||||
{
|
||||
int 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;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
LIST *
|
||||
compile_eval(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *ll, *lr, *s, *t;
|
||||
int status = 0;
|
||||
|
||||
/* Short circuit lr eval for &&, ||, and 'in' */
|
||||
|
||||
ll = (*parse->left->func)( parse->left, args );
|
||||
lr = 0;
|
||||
|
||||
switch( parse->num )
|
||||
{
|
||||
case EXPR_AND:
|
||||
case EXPR_IN: if( ll ) goto eval; break;
|
||||
case EXPR_OR: if( !ll ) goto eval; break;
|
||||
default: eval: lr = (*parse->right->func)( parse->right, args );
|
||||
}
|
||||
|
||||
/* Now eval */
|
||||
|
||||
switch( parse->num )
|
||||
{
|
||||
case EXPR_NOT:
|
||||
if( !ll ) status = 1;
|
||||
break;
|
||||
|
||||
case EXPR_AND:
|
||||
if( ll && lr ) status = 1;
|
||||
break;
|
||||
|
||||
case EXPR_OR:
|
||||
if( ll || lr ) status = 1;
|
||||
break;
|
||||
|
||||
case EXPR_IN:
|
||||
/* "a in b": make sure each of */
|
||||
/* ll is equal to something in lr. */
|
||||
|
||||
for( t = ll; t; t = list_next( t ) )
|
||||
{
|
||||
for( s = lr; s; s = list_next( s ) )
|
||||
if( !strcmp( t->string, s->string ) )
|
||||
break;
|
||||
if( !s ) break;
|
||||
}
|
||||
|
||||
/* No more ll? Success */
|
||||
|
||||
if( !t ) status = 1;
|
||||
|
||||
break;
|
||||
|
||||
case EXPR_EXISTS: if( lcmp( ll, L0 ) != 0 ) status = 1; break;
|
||||
case EXPR_EQUALS: if( lcmp( ll, lr ) == 0 ) status = 1; break;
|
||||
case EXPR_NOTEQ: if( lcmp( ll, lr ) != 0 ) status = 1; break;
|
||||
case EXPR_LESS: if( lcmp( ll, lr ) < 0 ) status = 1; break;
|
||||
case EXPR_LESSEQ: if( lcmp( ll, lr ) <= 0 ) status = 1; break;
|
||||
case EXPR_MORE: if( lcmp( ll, lr ) > 0 ) status = 1; break;
|
||||
case EXPR_MOREEQ: if( lcmp( ll, lr ) >= 0 ) status = 1; break;
|
||||
|
||||
}
|
||||
|
||||
if( DEBUG_IF )
|
||||
{
|
||||
debug_compile( 0, "if" );
|
||||
list_print( ll );
|
||||
printf( "(%d) ", status );
|
||||
list_print( lr );
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
/* Find something to return. */
|
||||
/* In odd circumstances (like "" = "") */
|
||||
/* we'll have to return a new string. */
|
||||
|
||||
if( !status ) t = 0;
|
||||
else if( ll ) t = ll, ll = 0;
|
||||
else if( lr ) t = lr, lr = 0;
|
||||
else t = list_new( L0, newstr( "1" ) );
|
||||
|
||||
if( ll ) list_free( ll );
|
||||
if( lr ) list_free( lr );
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *nv = (*parse->left->func)( parse->left, args );
|
||||
LIST *l;
|
||||
|
||||
/* 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, args ) );
|
||||
}
|
||||
|
||||
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,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *l = (*p->left->func)( p->left, args );
|
||||
|
||||
if( l )
|
||||
{
|
||||
list_free( l );
|
||||
return (*p->right->func)( p->right, args );
|
||||
}
|
||||
else
|
||||
{
|
||||
return (*p->third->func)( p->third, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *nt = (*parse->left->func)( parse->left, args );
|
||||
|
||||
if( DEBUG_COMPILE )
|
||||
{
|
||||
debug_compile( 0, "include" );
|
||||
list_print( nt );
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
if( nt )
|
||||
{
|
||||
TARGET *t = bindtarget( nt->string );
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
|
||||
list_free( nt );
|
||||
|
||||
return L0;
|
||||
}
|
||||
|
||||
/*
|
||||
* compile_list() - expand and return a list
|
||||
*
|
||||
* parse->string - character string to expand
|
||||
*/
|
||||
|
||||
LIST *
|
||||
compile_list(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
/* voodoo 1 means: s is a copyable string */
|
||||
char *s = parse->string;
|
||||
return var_expand( L0, s, s + strlen( s ), 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,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *l;
|
||||
SETTINGS *s = 0;
|
||||
LIST *nt = (*parse->left->func)( parse->left, args );
|
||||
LIST *ns = (*parse->right->func)( parse->right, args );
|
||||
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, args );
|
||||
popsettings( s );
|
||||
|
||||
freesettings( s );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* compile_null() - do nothing -- a stub for parsing
|
||||
*/
|
||||
|
||||
LIST *
|
||||
compile_null(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
return L0;
|
||||
}
|
||||
|
||||
/*
|
||||
* compile_on() - run rule under influence of on-target variables
|
||||
*
|
||||
* parse->left list of files to include (can only do 1)
|
||||
* parse->right rule to run
|
||||
*
|
||||
* EXPERIMENTAL!
|
||||
*/
|
||||
|
||||
LIST *
|
||||
compile_on(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *nt = (*parse->left->func)( parse->left, args );
|
||||
LIST *result = 0;
|
||||
|
||||
if( DEBUG_COMPILE )
|
||||
{
|
||||
debug_compile( 0, "on" );
|
||||
list_print( nt );
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
if( nt )
|
||||
{
|
||||
TARGET *t = bindtarget( nt->string );
|
||||
|
||||
pushsettings( t->settings );
|
||||
result = (*parse->right->func)( parse->right, args );
|
||||
t->boundname = search( t->name, &t->time );
|
||||
popsettings( t->settings );
|
||||
|
||||
}
|
||||
|
||||
list_free( nt );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* compile_rule() - compile a single user defined rule
|
||||
*
|
||||
* parse->left list of rules to run
|
||||
* parse->right parameters (list of lists) to rule, recursing left
|
||||
*
|
||||
* Wrapped around evaluate_rule() so that headers() can share it.
|
||||
*/
|
||||
|
||||
LIST *
|
||||
compile_rule(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
LOL nargs[1];
|
||||
LIST *result = 0;
|
||||
LIST *ll, *l;
|
||||
PARSE *p;
|
||||
|
||||
/* list of rules to run -- normally 1! */
|
||||
|
||||
ll = (*parse->left->func)( parse->left, args );
|
||||
|
||||
/* Build up the list of arg lists */
|
||||
|
||||
lol_init( nargs );
|
||||
|
||||
for( p = parse->right; p; p = p->left )
|
||||
lol_add( nargs, (*p->right->func)( p->right, args ) );
|
||||
|
||||
/* Run rules, appending results from each */
|
||||
|
||||
for( l = ll; l; l = list_next( l ) )
|
||||
result = evaluate_rule( l->string, nargs, result );
|
||||
|
||||
list_free( ll );
|
||||
lol_free( nargs );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* evaluate_rule() - execute a rule invocation
|
||||
*/
|
||||
|
||||
LIST *
|
||||
evaluate_rule(
|
||||
char *rulename,
|
||||
LOL *args,
|
||||
LIST *result )
|
||||
{
|
||||
RULE *rule = bindrule( rulename );
|
||||
|
||||
if( DEBUG_COMPILE )
|
||||
{
|
||||
debug_compile( 1, rulename );
|
||||
lol_print( args );
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
/* 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( args, 0 ) );
|
||||
action->sources = targetlist( (TARGETS *)0, lol_get( 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 )
|
||||
{
|
||||
PARSE *parse = rule->procedure;
|
||||
parse_refer( parse );
|
||||
result = list_append( result, (*parse->func)( parse, args ) );
|
||||
parse_free( parse );
|
||||
}
|
||||
|
||||
if( DEBUG_COMPILE )
|
||||
debug_compile( -1, 0 );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* compile_rules() - compile a chain of rules
|
||||
*
|
||||
* parse->left single rule
|
||||
* parse->right more compile_rules() by right-recursion
|
||||
*/
|
||||
|
||||
LIST *
|
||||
compile_rules(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
/* Ignore result from first statement; return the 2nd. */
|
||||
/* Optimize recursion on the right by looping. */
|
||||
|
||||
do list_free( (*parse->left->func)( parse->left, args ) );
|
||||
while( (parse = parse->right)->func == compile_rules );
|
||||
|
||||
return (*parse->func)( parse, args );
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *nt = (*parse->left->func)( parse->left, args );
|
||||
LIST *ns = (*parse->right->func)( parse->right, args );
|
||||
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_setcomp() - support for `rule` - save parse tree
|
||||
*
|
||||
* parse->string rule name
|
||||
* parse->left rules for rule
|
||||
*/
|
||||
|
||||
LIST *
|
||||
compile_setcomp(
|
||||
PARSE *parse,
|
||||
LOL *args )
|
||||
{
|
||||
RULE *rule = bindrule( parse->string );
|
||||
|
||||
if( DEBUG_COMPILE )
|
||||
{
|
||||
debug_compile( 0, "rule" );
|
||||
printf( " %s\n", parse->string );
|
||||
}
|
||||
|
||||
/* Free old one, if present */
|
||||
|
||||
if( rule->procedure )
|
||||
parse_free( rule->procedure );
|
||||
|
||||
rule->procedure = parse->left;
|
||||
|
||||
/* we now own this parse tree */
|
||||
/* don't let parse_free() release it */
|
||||
|
||||
parse_refer( 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,
|
||||
LOL *args )
|
||||
{
|
||||
RULE *rule = bindrule( parse->string );
|
||||
LIST *bindlist = (*parse->left->func)( parse->left, args );
|
||||
|
||||
/* Free old one, if present */
|
||||
|
||||
if( rule->actions )
|
||||
{
|
||||
freestr( rule->actions );
|
||||
list_free( rule->bindlist );
|
||||
}
|
||||
|
||||
rule->actions = copystr( parse->string1 );
|
||||
rule->bindlist = bindlist;
|
||||
rule->flags = 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,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *nt = (*parse->left->func)( parse->left, args );
|
||||
LIST *ns = (*parse->third->func)( parse->third, args );
|
||||
LIST *targets = (*parse->right->func)( parse->right, args );
|
||||
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,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *nt = (*parse->left->func)( parse->left, args );
|
||||
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, args );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_free( nt );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* compile_while() - compile 'while' rule
|
||||
*
|
||||
* parse->left condition tree
|
||||
* parse->right execution tree
|
||||
*/
|
||||
|
||||
LIST *
|
||||
compile_while(
|
||||
PARSE *p,
|
||||
LOL *args )
|
||||
{
|
||||
LIST *r = 0;
|
||||
LIST *l;
|
||||
|
||||
/* Returns the value from the last execution of the block */
|
||||
|
||||
while( l = (*p->left->func)( p->left, args ) )
|
||||
{
|
||||
list_free( l );
|
||||
if( r ) list_free( r );
|
||||
r = (*p->right->func)( p->right, args );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
|
||||
int i = ((1+level) * 2) % 35;
|
||||
|
||||
if( which >= 0 )
|
||||
printf( "%*.*s ", i, i, indent );
|
||||
|
||||
if( s )
|
||||
printf( "%s ", s );
|
||||
|
||||
level += which;
|
||||
}
|
52
src/tools/jam/compile.h
Normal file
52
src/tools/jam/compile.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* compile.h - compile parsed jam statements
|
||||
*/
|
||||
|
||||
void compile_builtins();
|
||||
|
||||
LIST *compile_append( PARSE *parse, LOL *args );
|
||||
LIST *compile_foreach( PARSE *parse, LOL *args );
|
||||
LIST *compile_if( PARSE *parse, LOL *args );
|
||||
LIST *compile_eval( PARSE *parse, LOL *args );
|
||||
LIST *compile_include( PARSE *parse, LOL *args );
|
||||
LIST *compile_list( PARSE *parse, LOL *args );
|
||||
LIST *compile_local( PARSE *parse, LOL *args );
|
||||
LIST *compile_null( PARSE *parse, LOL *args );
|
||||
LIST *compile_on( PARSE *parse, LOL *args );
|
||||
LIST *compile_rule( PARSE *parse, LOL *args );
|
||||
LIST *compile_rules( PARSE *parse, LOL *args );
|
||||
LIST *compile_set( PARSE *parse, LOL *args );
|
||||
LIST *compile_setcomp( PARSE *parse, LOL *args );
|
||||
LIST *compile_setexec( PARSE *parse, LOL *args );
|
||||
LIST *compile_settings( PARSE *parse, LOL *args );
|
||||
LIST *compile_switch( PARSE *parse, LOL *args );
|
||||
LIST *compile_while( PARSE *parse, LOL *args );
|
||||
|
||||
LIST *evaluate_rule( char *rulename, LOL *args, LIST *result );
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* Conditions for compile_if() */
|
||||
|
||||
# define EXPR_NOT 0 /* ! cond */
|
||||
# define EXPR_AND 1 /* cond && cond */
|
||||
# define EXPR_OR 2 /* cond || cond */
|
||||
|
||||
# define EXPR_EXISTS 3 /* arg */
|
||||
# define EXPR_EQUALS 4 /* arg = arg */
|
||||
# define EXPR_NOTEQ 5 /* arg != arg */
|
||||
# define EXPR_LESS 6 /* arg < arg */
|
||||
# define EXPR_LESSEQ 7 /* arg <= arg */
|
||||
# define EXPR_MORE 8 /* arg > arg */
|
||||
# define EXPR_MOREEQ 9 /* arg >= arg */
|
||||
# define EXPR_IN 10 /* arg in arg */
|
23
src/tools/jam/execcmd.h
Normal file
23
src/tools/jam/execcmd.h
Normal file
@ -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
|
69
src/tools/jam/execmac.c
Normal file
69
src/tools/jam/execmac.c
Normal file
@ -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 <errno.h>
|
||||
|
||||
# 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 */
|
370
src/tools/jam/execunix.c
Normal file
370
src/tools/jam/execunix.c
Normal file
@ -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 <errno.h>
|
||||
|
||||
# ifdef USE_EXECUNIX
|
||||
|
||||
# ifdef NO_VFORK
|
||||
# define vfork() fork()
|
||||
# endif
|
||||
|
||||
# if defined( OS_NT ) || defined( OS_OS2 )
|
||||
|
||||
# define USE_EXECNT
|
||||
|
||||
# include <process.h>
|
||||
|
||||
# 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 <windows.h> /* 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 */
|
167
src/tools/jam/execvms.c
Normal file
167
src/tools/jam/execvms.c
Normal file
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <iodef.h>
|
||||
#include <ssdef.h>
|
||||
#include <descrip.h>
|
||||
#include <dvidef.h>
|
||||
#include <clidef.h>
|
||||
|
||||
/*
|
||||
* 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 */
|
527
src/tools/jam/expand.c
Normal file
527
src/tools/jam/expand.c
Normal file
@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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 "pathsys.h"
|
||||
# include "newstr.h"
|
||||
|
||||
/*
|
||||
* expand.c - expand a buffer, given variable values
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* var_expand() - variable-expand input string into list of strings
|
||||
*
|
||||
* Internal routines:
|
||||
*
|
||||
* var_edit_parse() - parse : modifiers into PATHNAME structure
|
||||
* var_edit_file() - copy input target name to output, modifying filename
|
||||
* var_edit_shift() - do upshift/downshift mods
|
||||
*
|
||||
* 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)
|
||||
* 04/13/94 (seiwald) - added shorthand L0 for null list pointer
|
||||
* 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
PATHNAME f; /* :GDBSMR -- pieces */
|
||||
char parent; /* :P -- go to parent directory */
|
||||
char filemods; /* one of the above applied */
|
||||
char downshift; /* :L -- downshift result */
|
||||
char upshift; /* :U -- upshift result */
|
||||
PATHPART empty; /* :E -- default for empties */
|
||||
PATHPART join; /* :J -- join list with char */
|
||||
} VAR_EDITS ;
|
||||
|
||||
static void var_edit_parse( char *mods, VAR_EDITS *edits );
|
||||
static void var_edit_file( char *in, char *out, VAR_EDITS *edits );
|
||||
static void var_edit_shift( char *out, VAR_EDITS *edits );
|
||||
|
||||
# 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 )
|
||||
{
|
||||
char out_buf[ MAXSYM ];
|
||||
char *out = out_buf;
|
||||
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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Just try simple copy of in to out. */
|
||||
|
||||
while( in < end )
|
||||
if( ( *out++ = *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(). */
|
||||
|
||||
*out = '\0';
|
||||
|
||||
if( cancopyin )
|
||||
return list_new( l, copystr( inp ) );
|
||||
else
|
||||
return list_new( l, newstr( out_buf ) );
|
||||
|
||||
expand:
|
||||
/*
|
||||
* 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;
|
||||
out--, in++;
|
||||
ov = out;
|
||||
|
||||
while( in < end && depth )
|
||||
{
|
||||
switch( *ov++ = *in++ )
|
||||
{
|
||||
case '(': depth++; break;
|
||||
case ')': depth--; break;
|
||||
case ':': ov[-1] = MAGIC_COLON; break;
|
||||
case '[': ov[-1] = MAGIC_LEFT; break;
|
||||
case ']': ov[-1] = MAGIC_RIGHT; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copied ) - back up. */
|
||||
|
||||
ov--;
|
||||
|
||||
/*
|
||||
* 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, *evalue = 0;
|
||||
char *colon;
|
||||
char *bracket;
|
||||
char varname[ MAXSYM ];
|
||||
int sub1 = 0, sub2 = -1;
|
||||
VAR_EDITS edits;
|
||||
|
||||
/* Look for a : modifier in the variable name */
|
||||
/* Must copy into varname so we can modify it */
|
||||
|
||||
strcpy( varname, vars->string );
|
||||
|
||||
if( colon = strchr( varname, MAGIC_COLON ) )
|
||||
{
|
||||
*colon = '\0';
|
||||
var_edit_parse( colon + 1, &edits );
|
||||
}
|
||||
|
||||
/* Look for [x-y] subscripting */
|
||||
/* sub1 is x (0 default) */
|
||||
/* sub2 is length (-1 means forever) */
|
||||
|
||||
if( bracket = strchr( varname, MAGIC_LEFT ) )
|
||||
{
|
||||
char *dash;
|
||||
|
||||
if( dash = strchr( bracket + 1, '-' ) )
|
||||
*dash = '\0';
|
||||
|
||||
sub1 = atoi( bracket + 1 ) - 1;
|
||||
|
||||
if( !dash )
|
||||
sub2 = 1;
|
||||
else if( !dash[1] || dash[1] == MAGIC_RIGHT )
|
||||
sub2 = -1;
|
||||
else
|
||||
sub2 = atoi( dash + 1 ) - sub1;
|
||||
|
||||
*bracket = '\0';
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
/* This is only an optimization */
|
||||
|
||||
if( out == out_buf && !bracket && !colon && in == end )
|
||||
{
|
||||
l = list_copy( l, value );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle start subscript */
|
||||
|
||||
while( sub1 > 0 && value )
|
||||
--sub1, value = list_next( value );
|
||||
|
||||
/* Empty w/ :E=default? */
|
||||
|
||||
if( !value && colon && edits.empty.ptr )
|
||||
evalue = value = list_new( L0, newstr( edits.empty.ptr ) );
|
||||
|
||||
/* For each variable value */
|
||||
|
||||
for( ; value; value = list_next( value ) )
|
||||
{
|
||||
LIST *rem;
|
||||
char *out1;
|
||||
|
||||
/* Handle end subscript (length actually) */
|
||||
|
||||
if( sub2 >= 0 && --sub2 < 0 )
|
||||
break;
|
||||
|
||||
/* Apply : mods, if present */
|
||||
|
||||
if( colon && edits.filemods )
|
||||
var_edit_file( value->string, out, &edits );
|
||||
else
|
||||
strcpy( out, value->string );
|
||||
|
||||
if( colon && ( edits.upshift || edits.downshift ) )
|
||||
var_edit_shift( out, &edits );
|
||||
|
||||
/* Handle :J=joinval */
|
||||
/* If we have more values for this var, just */
|
||||
/* keep appending them (with the join value) */
|
||||
/* rather than creating separate LIST elements. */
|
||||
|
||||
if( colon && edits.join.ptr &&
|
||||
( list_next( value ) || list_next( vars ) ) )
|
||||
{
|
||||
out += strlen( out );
|
||||
strcpy( out, edits.join.ptr );
|
||||
out += strlen( out );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If no remainder, append result to output chain. */
|
||||
|
||||
if( in == end )
|
||||
{
|
||||
l = list_new( l, newstr( out_buf ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* For each remainder, append the complete string */
|
||||
/* to the output chain. */
|
||||
/* Remember the end of the variable expansion so */
|
||||
/* we can just tack on each instance of 'remainder' */
|
||||
|
||||
out1 = out + strlen( out );
|
||||
|
||||
for( rem = remainder; rem; rem = list_next( rem ) )
|
||||
{
|
||||
strcpy( out1, rem->string );
|
||||
l = list_new( l, newstr( out_buf ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Toss used empty */
|
||||
|
||||
if( evalue )
|
||||
list_free( evalue );
|
||||
}
|
||||
|
||||
/* 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" );
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* var_edit_parse() - parse : modifiers into PATHNAME structure
|
||||
*
|
||||
* The : modifiers in a $(varname:modifier) currently support replacing
|
||||
* or omitting elements of a filename, and so they are parsed into a
|
||||
* PATHNAME 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 <grist>
|
||||
* 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_file() below and path_build() obligingly follow this convention.
|
||||
*/
|
||||
|
||||
static void
|
||||
var_edit_parse(
|
||||
char *mods,
|
||||
VAR_EDITS *edits )
|
||||
{
|
||||
int havezeroed = 0;
|
||||
memset( (char *)edits, 0, sizeof( *edits ) );
|
||||
|
||||
while( *mods )
|
||||
{
|
||||
char *p;
|
||||
PATHPART *fp;
|
||||
|
||||
switch( *mods++ )
|
||||
{
|
||||
case 'L': edits->downshift = 1; continue;
|
||||
case 'U': edits->upshift = 1; continue;
|
||||
case 'P': edits->parent = edits->filemods = 1; continue;
|
||||
case 'E': fp = &edits->empty; goto strval;
|
||||
case 'J': fp = &edits->join; goto strval;
|
||||
case 'G': fp = &edits->f.f_grist; goto fileval;
|
||||
case 'R': fp = &edits->f.f_root; goto fileval;
|
||||
case 'D': fp = &edits->f.f_dir; goto fileval;
|
||||
case 'B': fp = &edits->f.f_base; goto fileval;
|
||||
case 'S': fp = &edits->f.f_suffix; goto fileval;
|
||||
case 'M': fp = &edits->f.f_member; goto fileval;
|
||||
|
||||
default: return; /* should complain, but so what... */
|
||||
}
|
||||
|
||||
fileval:
|
||||
|
||||
/* Handle :CHARS, where each char (without a following =) */
|
||||
/* selects a particular file path element. On the first such */
|
||||
/* char, we deselect all others (by setting ptr = "", len = 0) */
|
||||
/* and for each char we select that element (by setting ptr = 0) */
|
||||
|
||||
edits->filemods = 1;
|
||||
|
||||
if( *mods != '=' )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !havezeroed++ )
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
edits->f.part[ i ].len = 0;
|
||||
edits->f.part[ i ].ptr = "";
|
||||
}
|
||||
|
||||
fp->ptr = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
strval:
|
||||
|
||||
/* Handle :X=value, or :X */
|
||||
|
||||
if( *mods != '=' )
|
||||
{
|
||||
fp->ptr = "";
|
||||
fp->len = 0;
|
||||
}
|
||||
else if( p = strchr( mods, MAGIC_COLON ) )
|
||||
{
|
||||
*p = 0;
|
||||
fp->ptr = ++mods;
|
||||
fp->len = p - mods;
|
||||
mods = p + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fp->ptr = ++mods;
|
||||
fp->len = strlen( mods );
|
||||
mods += fp->len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* var_edit_file() - copy input target name to output, modifying filename
|
||||
*/
|
||||
|
||||
static void
|
||||
var_edit_file(
|
||||
char *in,
|
||||
char *out,
|
||||
VAR_EDITS *edits )
|
||||
{
|
||||
PATHNAME pathname;
|
||||
|
||||
/* Parse apart original filename, putting parts into "pathname" */
|
||||
|
||||
path_parse( in, &pathname );
|
||||
|
||||
/* Replace any pathname with edits->f */
|
||||
|
||||
if( edits->f.f_grist.ptr )
|
||||
pathname.f_grist = edits->f.f_grist;
|
||||
|
||||
if( edits->f.f_root.ptr )
|
||||
pathname.f_root = edits->f.f_root;
|
||||
|
||||
if( edits->f.f_dir.ptr )
|
||||
pathname.f_dir = edits->f.f_dir;
|
||||
|
||||
if( edits->f.f_base.ptr )
|
||||
pathname.f_base = edits->f.f_base;
|
||||
|
||||
if( edits->f.f_suffix.ptr )
|
||||
pathname.f_suffix = edits->f.f_suffix;
|
||||
|
||||
if( edits->f.f_member.ptr )
|
||||
pathname.f_member = edits->f.f_member;
|
||||
|
||||
/* If requested, modify pathname to point to parent */
|
||||
|
||||
if( edits->parent )
|
||||
path_parent( &pathname );
|
||||
|
||||
/* Put filename back together */
|
||||
|
||||
path_build( &pathname, out, 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* var_edit_shift() - do upshift/downshift mods
|
||||
*/
|
||||
|
||||
static void
|
||||
var_edit_shift(
|
||||
char *out,
|
||||
VAR_EDITS *edits )
|
||||
{
|
||||
/* Handle upshifting, downshifting now */
|
||||
|
||||
if( edits->upshift )
|
||||
{
|
||||
for( ; *out; ++out )
|
||||
*out = toupper( *out );
|
||||
}
|
||||
else if( edits->downshift )
|
||||
{
|
||||
for( ; *out; ++out )
|
||||
*out = tolower( *out );
|
||||
}
|
||||
}
|
11
src/tools/jam/expand.h
Normal file
11
src/tools/jam/expand.h
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 );
|
165
src/tools/jam/filemac.c
Normal file
165
src/tools/jam/filemac.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "filesys.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
# ifdef OS_MAC
|
||||
|
||||
#include <Files.h>
|
||||
#include <Folders.h>
|
||||
|
||||
# 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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
PATHNAME f;
|
||||
char filename[ MAXJPATH ];
|
||||
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)( closure, 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;
|
||||
|
||||
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;
|
||||
|
||||
path_build( &f, filename, 0 );
|
||||
|
||||
(*func)( closure, filename, 0 /* not stat()'ed */, (time_t)0 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
# endif /* macintosh */
|
||||
|
265
src/tools/jam/filent.c
Normal file
265
src/tools/jam/filent.c
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "filesys.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
# ifdef OS_NT
|
||||
|
||||
# ifdef __BORLANDC__
|
||||
# if __BORLANDC__ < 0x550
|
||||
# include <dir.h>
|
||||
# include <dos.h>
|
||||
# endif
|
||||
# undef PATHNAME /* cpp namespace collision */
|
||||
# define _finddata_t ffblk
|
||||
# endif
|
||||
|
||||
# include <io.h>
|
||||
# include <sys/stat.h>
|
||||
|
||||
/*
|
||||
* 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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
PATHNAME f;
|
||||
char filespec[ MAXJPATH ];
|
||||
char filename[ MAXJPATH ];
|
||||
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)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
|
||||
else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
|
||||
(*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
|
||||
|
||||
/* Now enter contents of directory */
|
||||
|
||||
sprintf( filespec, "%s/*", dir );
|
||||
|
||||
if( DEBUG_BINDSCAN )
|
||||
printf( "scan directory %s\n", dir );
|
||||
|
||||
# if defined(__BORLANDC__) && __BORLANDC__ < 0x550
|
||||
if ( ret = findfirst( filespec, finfo, FA_NORMAL | FA_DIREC ) )
|
||||
return;
|
||||
|
||||
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 );
|
||||
|
||||
path_build( &f, filename );
|
||||
|
||||
(*func)( closure, filename, 1 /* stat()'ed */, time_write );
|
||||
|
||||
ret = findnext( finfo );
|
||||
}
|
||||
# else
|
||||
handle = _findfirst( filespec, finfo );
|
||||
|
||||
if( ret = ( handle < 0L ) )
|
||||
return;
|
||||
|
||||
while( !ret )
|
||||
{
|
||||
f.f_base.ptr = finfo->name;
|
||||
f.f_base.len = strlen( finfo->name );
|
||||
|
||||
path_build( &f, filename, 0 );
|
||||
|
||||
(*func)( closure, filename, 1 /* stat()'ed */, finfo->time_write );
|
||||
|
||||
ret = _findnext( handle, finfo );
|
||||
}
|
||||
|
||||
_findclose( handle );
|
||||
# endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 "!<arch>\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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
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)( closure, buf, 1 /* time valid */, (time_t)lar_date );
|
||||
|
||||
offset += SARHDR + lar_size;
|
||||
lseek( fd, offset, 0 );
|
||||
}
|
||||
|
||||
close( fd );
|
||||
}
|
||||
|
||||
# endif /* NT */
|
131
src/tools/jam/fileos2.c
Normal file
131
src/tools/jam/fileos2.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "filesys.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
# ifdef OS_OS2
|
||||
|
||||
# include <io.h>
|
||||
# include <dos.h>
|
||||
|
||||
/*
|
||||
* 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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
PATHNAME f;
|
||||
char filespec[ MAXJPATH ];
|
||||
char filename[ MAXJPATH ];
|
||||
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 */
|
||||
|
||||
strcpy( filespec, dir );
|
||||
|
||||
if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
|
||||
(*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
|
||||
else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
|
||||
(*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
|
||||
else
|
||||
strcat( filespec, "/" );
|
||||
|
||||
strcat( filespec, "*" );
|
||||
|
||||
/* Now enter contents of directory */
|
||||
|
||||
if( DEBUG_BINDSCAN )
|
||||
printf( "scan directory %s\n", filespec );
|
||||
|
||||
/* 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, _A_NORMAL|_A_RDONLY|_A_SUBDIR, finfo ) )
|
||||
{
|
||||
do
|
||||
{
|
||||
f.f_base.ptr = finfo->name;
|
||||
f.f_base.len = strlen( finfo->name );
|
||||
|
||||
path_build( &f, filename, 0 );
|
||||
|
||||
(*func)( closure, filename, 0 /* not stat()'ed */, (time_t)0 );
|
||||
}
|
||||
while( !_dos_findnext( finfo ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
}
|
||||
|
||||
# endif /* OS2 */
|
||||
|
16
src/tools/jam/filesys.h
Normal file
16
src/tools/jam/filesys.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* filesys.h - OS specific file routines
|
||||
*/
|
||||
|
||||
typedef void (*scanback)( void *closure, char *file, int found, time_t t );
|
||||
|
||||
void file_dirscan( char *dir, scanback func, void *closure );
|
||||
void file_archscan( char *arch, scanback func, void *closure );
|
||||
|
||||
int file_time( char *filename, time_t *time );
|
331
src/tools/jam/fileunix.c
Normal file
331
src/tools/jam/fileunix.c
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "filesys.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
# ifdef USE_FILEUNIX
|
||||
|
||||
# if defined( OS_SEQUENT ) || \
|
||||
defined( OS_DGUX ) || \
|
||||
defined( OS_SCO ) || \
|
||||
defined( OS_ISC )
|
||||
# define PORTAR 1
|
||||
# endif
|
||||
|
||||
# if defined( OS_RHAPSODY ) || \
|
||||
defined( OS_MACOSX ) || \
|
||||
defined( OS_NEXT )
|
||||
/* need unistd for rhapsody's proper lseek */
|
||||
# include <sys/dir.h>
|
||||
# include <unistd.h>
|
||||
# define STRUCT_DIRENT struct direct
|
||||
# else
|
||||
# include <dirent.h>
|
||||
# define STRUCT_DIRENT struct dirent
|
||||
# endif
|
||||
|
||||
# ifdef OS_COHERENT
|
||||
# include <arcoff.h>
|
||||
# define HAVE_AR
|
||||
# endif
|
||||
|
||||
# if defined( OS_MVS ) || \
|
||||
defined( OS_INTERIX ) || defined(OS_AIX)
|
||||
|
||||
#define ARMAG "!<arch>\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 <ar.h>
|
||||
# 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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
PATHNAME f;
|
||||
DIR *d;
|
||||
STRUCT_DIRENT *dirent;
|
||||
char filename[ MAXJPATH ];
|
||||
|
||||
/* 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)( closure, 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 );
|
||||
|
||||
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 );
|
||||
|
||||
path_build( &f, filename, 0 );
|
||||
|
||||
(*func)( closure, filename, 0 /* not stat()'ed */, (time_t)0 );
|
||||
}
|
||||
|
||||
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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
# 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)( closure, 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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
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)( closure, buf, 1 /* time valid */, (time_t)lar_date );
|
||||
}
|
||||
|
||||
close( fd );
|
||||
}
|
||||
|
||||
# endif /* AIAMAG - RS6000 AIX */
|
||||
|
||||
# endif /* USE_FILEUNIX */
|
||||
|
318
src/tools/jam/filevms.c
Normal file
318
src/tools/jam/filevms.c
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "filesys.h"
|
||||
# include "pathsys.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 <rms.h>
|
||||
# include <iodef.h>
|
||||
# include <ssdef.h>
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <descrip.h>
|
||||
|
||||
#include <lbrdef.h>
|
||||
#include <credef.h>
|
||||
#include <mhddef.h>
|
||||
#include <lhidef.h>
|
||||
#include <lib$routines.h>
|
||||
#include <starlet.h>
|
||||
|
||||
/* Supply missing prototypes for lbr$-routines*/
|
||||
|
||||
extern "C" {
|
||||
|
||||
int lbr$set_module(
|
||||
void **,
|
||||
unsigned long *,
|
||||
struct dsc$descriptor_s *,
|
||||
unsigned short *,
|
||||
void * );
|
||||
|
||||
int lbr$open( void **,
|
||||
struct dsc$descriptor_s *,
|
||||
void *,
|
||||
void *,
|
||||
void *,
|
||||
void *,
|
||||
void * );
|
||||
|
||||
int lbr$ini_control(
|
||||
void **,
|
||||
unsigned long *,
|
||||
unsigned long *,
|
||||
void * );
|
||||
|
||||
int lbr$get_index(
|
||||
void **,
|
||||
unsigned long *,
|
||||
int (*func)( struct dsc$descriptor_s *, unsigned long *),
|
||||
void * );
|
||||
|
||||
int lbr$close(
|
||||
void ** );
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
|
||||
struct FAB xfab;
|
||||
struct NAM xnam;
|
||||
struct XABDAT xab;
|
||||
char esa[256];
|
||||
char filename[256];
|
||||
char filename2[256];
|
||||
char dirname[256];
|
||||
register int status;
|
||||
PATHNAME 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)( closure, "[000000]", 1 /* time valid */, 1 /* old but true */ );
|
||||
}
|
||||
|
||||
/* Add bogus directory for [] */
|
||||
|
||||
if( !strcmp( dir, "[]" ) )
|
||||
{
|
||||
(*func)( closure, "[]", 1 /* time valid */, 1 /* old but true */ );
|
||||
(*func)( closure, "[-]", 1 /* time valid */, 1 /* old but true */ );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
path_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)( closure, filename2, 1 /* time valid */, time );
|
||||
}
|
||||
}
|
||||
|
||||
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 scanback VMS_func;
|
||||
static void *VMS_closure;
|
||||
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)( VMS_closure, buf, 1 /* time valid */, (time_t)library_date );
|
||||
|
||||
return ( 1 );
|
||||
}
|
||||
|
||||
void
|
||||
file_archscan(
|
||||
char *archive,
|
||||
scanback func,
|
||||
void *closure )
|
||||
{
|
||||
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;
|
||||
VMS_closure = closure;
|
||||
|
||||
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 */
|
||||
|
157
src/tools/jam/glob.c
Normal file
157
src/tools/jam/glob.c
Normal file
@ -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;
|
||||
}
|
259
src/tools/jam/hash.c
Normal file
259
src/tools/jam/hash.c
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
# 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 );
|
||||
}
|
18
src/tools/jam/hash.h
Normal file
18
src/tools/jam/hash.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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 );
|
||||
|
||||
# define hashenter( hp, data ) !hashitem( hp, data, !0 )
|
||||
# define hashcheck( hp, data ) hashitem( hp, data, 0 )
|
130
src/tools/jam/headers.c
Normal file
130
src/tools/jam/headers.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 "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) <target> : <include files> ;
|
||||
*
|
||||
* 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[] );
|
||||
|
||||
/*
|
||||
* headers() - scan a target for include files and call HDRRULE
|
||||
*/
|
||||
|
||||
# define MAXINC 10
|
||||
|
||||
void
|
||||
headers( TARGET *t )
|
||||
{
|
||||
LIST *hdrscan;
|
||||
LIST *hdrrule;
|
||||
LIST *headlist = 0;
|
||||
LOL lol;
|
||||
regexp *re[ MAXINC ];
|
||||
int rec = 0;
|
||||
|
||||
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++] = regcomp( hdrscan->string );
|
||||
hdrscan = list_next( hdrscan );
|
||||
}
|
||||
|
||||
/* Doctor up call to HDRRULE rule */
|
||||
/* Call headers1() to get LIST of included files. */
|
||||
|
||||
lol_init( &lol );
|
||||
lol_add( &lol, list_new( L0, t->name ) );
|
||||
lol_add( &lol, headers1( headlist, t->boundname, rec, re ) );
|
||||
|
||||
if( lol_get( &lol, 1 ) )
|
||||
list_free( evaluate_rule( hdrrule->string, &lol, L0 ) );
|
||||
|
||||
/* Clean up */
|
||||
|
||||
lol_free( &lol );
|
||||
|
||||
while( rec )
|
||||
free( (char *)re[--rec] );
|
||||
}
|
||||
|
||||
/*
|
||||
* headers1() - using regexp, scan a file and build include LIST
|
||||
*/
|
||||
|
||||
static LIST *
|
||||
headers1(
|
||||
LIST *l,
|
||||
char *file,
|
||||
int rec,
|
||||
regexp *re[] )
|
||||
{
|
||||
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] ) );
|
||||
}
|
||||
}
|
||||
|
||||
fclose( f );
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void
|
||||
regerror( char *s )
|
||||
{
|
||||
printf( "re error %s\n", s );
|
||||
}
|
11
src/tools/jam/headers.h
Normal file
11
src/tools/jam/headers.h
Normal file
@ -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 );
|
365
src/tools/jam/jam.c
Normal file
365
src/tools/jam/jam.c
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* /+\
|
||||
* +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
* \+/
|
||||
*
|
||||
* 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 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
|
||||
* | | | \
|
||||
* | | | \
|
||||
* | | | \
|
||||
* builtins timestamp command execute
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* filesys
|
||||
*
|
||||
*
|
||||
* The support routines are called by all of the above, but themselves
|
||||
* are layered thus:
|
||||
*
|
||||
* variable|expand
|
||||
* / | | |
|
||||
* / | | |
|
||||
* / | | |
|
||||
* lists | | pathsys
|
||||
* \ | |
|
||||
* \ | |
|
||||
* \ | |
|
||||
* newstr |
|
||||
* \ |
|
||||
* \ |
|
||||
* \ |
|
||||
* hash
|
||||
*
|
||||
* Roughly, the modules are:
|
||||
*
|
||||
* builtins.c - jam's built-in rules
|
||||
* 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
|
||||
* file*.c - scan directories and archives on *
|
||||
* hash.c - simple in-memory hashing routines
|
||||
* 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
|
||||
* path*.c - manipulate file names on *
|
||||
* hash.c - simple in-memory hashing routines
|
||||
* 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.
|
||||
* 01/10/01 (seiwald) - pathsys.h split from filesys.h
|
||||
*/
|
||||
|
||||
# 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 "builtins.h"
|
||||
# include "rules.h"
|
||||
# include "newstr.h"
|
||||
# include "scan.h"
|
||||
# include "timestamp.h"
|
||||
# include "make.h"
|
||||
|
||||
/* Macintosh is "special" */
|
||||
|
||||
# ifdef OS_MAC
|
||||
# include <QuickDraw.h>
|
||||
# endif
|
||||
|
||||
/* And UNIX for this */
|
||||
|
||||
# ifdef unix
|
||||
# include <sys/utsname.h>
|
||||
# endif
|
||||
|
||||
struct globs globs = {
|
||||
0, /* noexec */
|
||||
1, /* jobs */
|
||||
0, /* quitquick */
|
||||
0, /* newestfirst */
|
||||
# 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
|
||||
|
||||
# ifndef use_environ
|
||||
# define use_environ environ
|
||||
# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
|
||||
extern char **environ;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
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:gs:t:ano:qv", 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( "-g Build from newest sources first.\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( "-q Quit quickly as soon as a target fails.\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 %s. %s. ", VERSION, OSMINOR );
|
||||
printf( "Copyright 1993-2002 Christopher Seiwald.\n" );
|
||||
|
||||
return EXITOK;
|
||||
}
|
||||
|
||||
/* Pick up interesting options */
|
||||
|
||||
if( ( s = getoptval( optv, 'n', 0 ) ) )
|
||||
globs.noexec++, globs.debug[2] = 1;
|
||||
|
||||
if( ( s = getoptval( optv, 'q', 0 ) ) )
|
||||
globs.quitquick = 1;
|
||||
|
||||
if( ( s = getoptval( optv, 'a', 0 ) ) )
|
||||
anyhow++;
|
||||
|
||||
if( ( s = getoptval( optv, 'j', 0 ) ) )
|
||||
globs.jobs = atoi( s );
|
||||
|
||||
if( ( s = getoptval( optv, 'g', 0 ) ) )
|
||||
globs.newestfirst = 1;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
|
||||
/* 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 built-in rules */
|
||||
|
||||
load_builtins();
|
||||
|
||||
/* Parse ruleset */
|
||||
|
||||
for( n = 0; s = getoptval( optv, 'f', n ); n++ )
|
||||
parse_file( s );
|
||||
|
||||
if( !n )
|
||||
parse_file( "+" );
|
||||
|
||||
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 );
|
||||
|
||||
/* Widely scattered cleanup */
|
||||
|
||||
var_done();
|
||||
donerules();
|
||||
donestamps();
|
||||
donestr();
|
||||
|
||||
/* close cmdout */
|
||||
|
||||
if( globs.cmdout )
|
||||
fclose( globs.cmdout );
|
||||
|
||||
return status ? EXITBAD : EXITOK;
|
||||
}
|
507
src/tools/jam/jam.h
Normal file
507
src/tools/jam/jam.h
Normal file
@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
# define unlink remove
|
||||
|
||||
# include <types.h>
|
||||
# include <file.h>
|
||||
# include <stat.h>
|
||||
# include <stdio.h>
|
||||
# include <ctype.h>
|
||||
# include <stdlib.h>
|
||||
# include <signal.h>
|
||||
# include <string.h>
|
||||
# include <time.h>
|
||||
# include <unixlib.h>
|
||||
|
||||
# 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
|
||||
|
||||
/* Do any of these work? */
|
||||
# if defined( VAX ) || defined( __VAX ) || defined( vax )
|
||||
# define OSPLAT "OSPLAT=VAX"
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Windows NT
|
||||
*/
|
||||
|
||||
# ifdef NT
|
||||
|
||||
# include <fcntl.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <ctype.h>
|
||||
# include <malloc.h>
|
||||
# include <memory.h>
|
||||
# include <signal.h>
|
||||
# include <string.h>
|
||||
# include <time.h>
|
||||
|
||||
# define OSMAJOR "NT=true"
|
||||
# define OSMINOR "OS=NT"
|
||||
# define OS_NT
|
||||
# define SPLITPATH ';'
|
||||
# define MAXLINE 996 /* longest 'together' actions */
|
||||
# define USE_EXECUNIX
|
||||
# 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
|
||||
|
||||
/*
|
||||
* Windows MingW32
|
||||
*/
|
||||
|
||||
# ifdef MINGW
|
||||
|
||||
# include <fcntl.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <ctype.h>
|
||||
# include <malloc.h>
|
||||
# include <memory.h>
|
||||
# include <signal.h>
|
||||
# include <string.h>
|
||||
# include <time.h>
|
||||
|
||||
# define OSMAJOR "MINGW=true"
|
||||
# define OSMINOR "OS=MINGW"
|
||||
# define OS_NT
|
||||
# define SPLITPATH ';'
|
||||
# define MAXLINE 996 /* longest 'together' actions */
|
||||
# define USE_EXECUNIX
|
||||
# define USE_PATHUNIX
|
||||
# define PATH_DELIM '\\'
|
||||
# define DOWNSHIFT_PATHS
|
||||
|
||||
# endif
|
||||
|
||||
/*
|
||||
* OS2
|
||||
*/
|
||||
|
||||
# ifdef __OS2__
|
||||
|
||||
# include <fcntl.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <ctype.h>
|
||||
# include <malloc.h>
|
||||
# include <signal.h>
|
||||
# include <string.h>
|
||||
# include <time.h>
|
||||
|
||||
# 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
|
||||
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Macintosh MPW
|
||||
*/
|
||||
|
||||
# ifdef macintosh
|
||||
|
||||
# include <time.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
|
||||
# define OSMAJOR "MAC=true"
|
||||
# define OSMINOR "OS=MAC"
|
||||
# define OS_MAC
|
||||
# define SPLITPATH ','
|
||||
# define DOWNSHIFT_PATHS
|
||||
|
||||
# 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 <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
|
||||
# ifndef OS_MPEIX
|
||||
# include <sys/file.h>
|
||||
# endif
|
||||
|
||||
# include <fcntl.h>
|
||||
# include <stdio.h>
|
||||
# include <ctype.h>
|
||||
# include <signal.h>
|
||||
# include <string.h>
|
||||
# include <time.h>
|
||||
|
||||
# ifndef OS_QNX
|
||||
# include <memory.h>
|
||||
# endif
|
||||
|
||||
# ifndef OS_ULTRIX
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
|
||||
# if !defined(OS_BSDI) && \
|
||||
!defined(OS_FREEBSD) && \
|
||||
!defined(OS_NEXT) && \
|
||||
!defined(OS_MACHTEN) && \
|
||||
!defined(OS_MACOSX) && \
|
||||
!defined(OS_RHAPSODY) && \
|
||||
!defined(OS_MVS)
|
||||
# include <malloc.h>
|
||||
# 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__ ) || \
|
||||
defined( _M_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 10
|
||||
|
||||
struct globs {
|
||||
int noexec;
|
||||
int jobs;
|
||||
int quitquick;
|
||||
int newestfirst; /* build newest sources first */
|
||||
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 */
|
||||
|
1219
src/tools/jam/jambase.c
Normal file
1219
src/tools/jam/jambase.c
Normal file
File diff suppressed because it is too large
Load Diff
15
src/tools/jam/jambase.h
Normal file
15
src/tools/jam/jambase.h
Normal file
@ -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[];
|
876
src/tools/jam/jamgram.c
Normal file
876
src/tools/jam/jamgram.c
Normal file
@ -0,0 +1,876 @@
|
||||
#ifndef lint
|
||||
static char const
|
||||
yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bde Exp $";
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#define YYBYACC 1
|
||||
#define YYMAJOR 1
|
||||
#define YYMINOR 9
|
||||
#define YYLEX yylex()
|
||||
#define YYEMPTY -1
|
||||
#define yyclearin (yychar=(YYEMPTY))
|
||||
#define yyerrok (yyerrflag=0)
|
||||
#define YYRECOVERING() (yyerrflag!=0)
|
||||
static int yygrowstack();
|
||||
#define YYPREFIX "yy"
|
||||
#line 89 "jamgram.y"
|
||||
#include "jam.h"
|
||||
|
||||
#include "lists.h"
|
||||
#include "parse.h"
|
||||
#include "scan.h"
|
||||
#include "compile.h"
|
||||
#include "newstr.h"
|
||||
#include "rules.h"
|
||||
|
||||
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
|
||||
|
||||
# define F0 (LIST *(*)(PARSE *, LOL *))0
|
||||
# define P0 (PARSE *)0
|
||||
# define S0 (char *)0
|
||||
|
||||
# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
|
||||
# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
|
||||
# define pfor( s,l,r ) parse_make( compile_foreach,l,r,P0,s,S0,0 )
|
||||
# define pif( l,r,t ) parse_make( compile_if,l,r,t,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 pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
|
||||
# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
|
||||
# define prule( a,p ) parse_make( compile_rule,a,p,P0,S0,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 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 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 pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
|
||||
|
||||
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
|
||||
# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
|
||||
|
||||
#line 54 "y.tab.c"
|
||||
#define YYERRCODE 256
|
||||
#define _BANG_t 257
|
||||
#define _BANG_EQUALS_t 258
|
||||
#define _AMPER_t 259
|
||||
#define _AMPERAMPER_t 260
|
||||
#define _LPAREN_t 261
|
||||
#define _RPAREN_t 262
|
||||
#define _PLUS_EQUALS_t 263
|
||||
#define _COLON_t 264
|
||||
#define _SEMIC_t 265
|
||||
#define _LANGLE_t 266
|
||||
#define _LANGLE_EQUALS_t 267
|
||||
#define _EQUALS_t 268
|
||||
#define _RANGLE_t 269
|
||||
#define _RANGLE_EQUALS_t 270
|
||||
#define _QUESTION_EQUALS_t 271
|
||||
#define _LBRACKET_t 272
|
||||
#define _RBRACKET_t 273
|
||||
#define ACTIONS_t 274
|
||||
#define BIND_t 275
|
||||
#define CASE_t 276
|
||||
#define DEFAULT_t 277
|
||||
#define ELSE_t 278
|
||||
#define EXISTING_t 279
|
||||
#define FOR_t 280
|
||||
#define IF_t 281
|
||||
#define IGNORE_t 282
|
||||
#define IN_t 283
|
||||
#define INCLUDE_t 284
|
||||
#define LOCAL_t 285
|
||||
#define ON_t 286
|
||||
#define PIECEMEAL_t 287
|
||||
#define QUIETLY_t 288
|
||||
#define RETURN_t 289
|
||||
#define RULE_t 290
|
||||
#define SWITCH_t 291
|
||||
#define TOGETHER_t 292
|
||||
#define UPDATED_t 293
|
||||
#define WHILE_t 294
|
||||
#define _LBRACE_t 295
|
||||
#define _BAR_t 296
|
||||
#define _BARBAR_t 297
|
||||
#define _RBRACE_t 298
|
||||
#define ARG 299
|
||||
#define STRING 300
|
||||
const short yylhs[] = { -1,
|
||||
0, 0, 2, 2, 1, 1, 1, 1, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 12, 13, 3, 7, 7, 7, 7, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 8, 8, 14, 6, 6, 4, 15, 15,
|
||||
5, 17, 5, 16, 16, 16, 10, 10, 18, 18,
|
||||
18, 18, 18, 18, 11, 11,
|
||||
};
|
||||
const short yylen[] = { 2,
|
||||
0, 1, 0, 1, 1, 2, 4, 6, 3, 3,
|
||||
3, 4, 6, 3, 7, 5, 5, 7, 5, 3,
|
||||
3, 0, 0, 9, 1, 1, 1, 2, 1, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 3, 0, 2, 4, 1, 3, 1, 0, 2,
|
||||
1, 0, 4, 2, 4, 4, 0, 2, 1, 1,
|
||||
1, 1, 1, 1, 0, 2,
|
||||
};
|
||||
const short yydefred[] = { 0,
|
||||
52, 57, 0, 0, 49, 49, 0, 49, 0, 49,
|
||||
0, 0, 51, 0, 2, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 4, 0, 6, 26, 25, 27, 0, 49,
|
||||
0, 0, 49, 0, 49, 0, 64, 61, 63, 62,
|
||||
60, 59, 0, 58, 49, 41, 0, 49, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
|
||||
50, 0, 49, 21, 14, 20, 0, 0, 9, 28,
|
||||
0, 49, 11, 0, 0, 54, 53, 49, 0, 0,
|
||||
42, 40, 0, 0, 0, 32, 33, 0, 34, 35,
|
||||
0, 0, 0, 7, 0, 0, 0, 0, 0, 49,
|
||||
47, 12, 49, 49, 66, 22, 0, 0, 0, 0,
|
||||
16, 44, 19, 0, 56, 55, 0, 0, 0, 8,
|
||||
0, 13, 23, 15, 18, 45, 0, 24,
|
||||
};
|
||||
const short yydgoto[] = { 14,
|
||||
33, 34, 16, 41, 23, 42, 43, 107, 24, 19,
|
||||
89, 127, 137, 108, 26, 46, 18, 54,
|
||||
};
|
||||
const short yysindex[] = { -44,
|
||||
0, 0, -278, -232, 0, 0, -191, 0, -273, 0,
|
||||
-232, -44, 0, 0, 0, -44, -154, -245, -66, -252,
|
||||
-232, -232, -250, -103, -228, -191, -249, 31, -206, 31,
|
||||
-230, -90, 0, -219, 0, 0, 0, 0, -200, 0,
|
||||
-194, -180, 0, -191, 0, -187, 0, 0, 0, 0,
|
||||
0, 0, -172, 0, 0, 0, -58, 0, -232, -232,
|
||||
-232, -232, -232, -232, -232, -232, -44, -232, -232, 0,
|
||||
0, -44, 0, 0, 0, 0, -169, -44, 0, 0,
|
||||
-48, 0, 0, -152, -233, 0, 0, 0, -179, -175,
|
||||
0, 0, -35, -1, -1, 0, 0, -35, 0, 0,
|
||||
-176, -6, -6, 0, -141, -174, -161, -169, -150, 0,
|
||||
0, 0, 0, 0, 0, 0, -44, -148, -44, -138,
|
||||
0, 0, 0, -91, 0, 0, -125, -115, 31, 0,
|
||||
-44, 0, 0, 0, 0, 0, -113, 0,
|
||||
};
|
||||
const short yyrindex[] = { 186,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, -102, 0, 0, 0, 3, -74, 0, 0, 0,
|
||||
0, 0, -108, 0, 0, -124, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
-223, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, -100, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, -102, 0, 0, 0,
|
||||
0, 4, 0, 0, 0, 0, -101, -102, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, -224, -168, -78, 0, 0, -207, 0, 0,
|
||||
0, -213, -185, 0, 0, 0, 0, -101, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, -102, 1, 4, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
-276, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
const short yygindex[] = { 0,
|
||||
8, -55, -23, 5, 2, -39, 118, 95, 36, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
#define YYTABLESIZE 330
|
||||
const short yytable[] = { 3,
|
||||
17, 17, 5, 3, 74, 86, 76, 15, 28, 25,
|
||||
27, 101, 29, 17, 31, 72, 104, 17, 73, 45,
|
||||
20, 3, 109, 35, 21, 30, 1, 71, 22, 17,
|
||||
55, 17, 58, 31, 31, 31, 70, 31, 1, 1,
|
||||
44, 46, 111, 31, 81, 85, 32, 84, 38, 46,
|
||||
30, 30, 30, 13, 30, 113, 56, 57, 75, 90,
|
||||
30, 128, 92, 130, 77, 13, 13, 80, 17, 82,
|
||||
31, 31, 31, 17, 126, 136, 39, 105, 79, 17,
|
||||
1, 38, 38, 38, 83, 87, 114, 30, 30, 30,
|
||||
36, 36, 115, 36, 93, 94, 95, 96, 97, 98,
|
||||
99, 100, 88, 102, 103, 135, 106, 13, 36, 39,
|
||||
39, 39, 112, 37, 124, 116, 38, 125, 17, 117,
|
||||
17, 118, 39, 119, 120, 131, 36, 36, 36, 129,
|
||||
17, 40, 17, 48, 48, 48, 121, 48, 48, 48,
|
||||
48, 48, 48, 48, 48, 48, 48, 123, 48, 29,
|
||||
29, 29, 48, 29, 59, 60, 61, 29, 29, 29,
|
||||
29, 29, 62, 63, 64, 65, 66, 59, 60, 61,
|
||||
48, 48, 48, 132, 133, 62, 63, 64, 65, 66,
|
||||
37, 37, 134, 37, 138, 1, 29, 29, 29, 49,
|
||||
49, 67, 68, 69, 65, 3, 43, 49, 110, 59,
|
||||
60, 61, 122, 91, 78, 68, 69, 62, 63, 64,
|
||||
65, 66, 47, 0, 36, 48, 37, 37, 37, 37,
|
||||
49, 50, 38, 0, 49, 51, 52, 1, 39, 2,
|
||||
62, 63, 53, 65, 66, 3, 4, 68, 69, 5,
|
||||
6, 7, 0, 0, 8, 9, 10, 0, 0, 11,
|
||||
12, 59, 60, 61, 13, 0, 59, 0, 0, 62,
|
||||
63, 64, 65, 66, 62, 63, 64, 65, 66, 0,
|
||||
0, 0, 17, 0, 17, 0, 17, 0, 5, 3,
|
||||
17, 17, 0, 0, 17, 17, 17, 0, 0, 17,
|
||||
17, 17, 0, 0, 17, 17, 0, 0, 17, 17,
|
||||
5, 3, 1, 0, 2, 0, 0, 0, 0, 0,
|
||||
3, 4, 0, 0, 5, 0, 7, 0, 0, 8,
|
||||
9, 10, 0, 0, 11, 12, 0, 0, 0, 13,
|
||||
};
|
||||
const short yycheck[] = { 276,
|
||||
0, 0, 0, 0, 28, 45, 30, 0, 7, 5,
|
||||
6, 67, 8, 12, 10, 265, 72, 16, 268, 18,
|
||||
299, 298, 78, 16, 257, 299, 272, 26, 261, 28,
|
||||
283, 30, 283, 258, 259, 260, 265, 262, 272, 272,
|
||||
286, 265, 82, 268, 40, 44, 11, 43, 262, 273,
|
||||
258, 259, 260, 299, 262, 289, 21, 22, 265, 55,
|
||||
268, 117, 58, 119, 295, 299, 299, 268, 67, 264,
|
||||
295, 296, 297, 72, 114, 131, 262, 73, 298, 78,
|
||||
272, 295, 296, 297, 265, 273, 85, 295, 296, 297,
|
||||
259, 260, 88, 262, 59, 60, 61, 62, 63, 64,
|
||||
65, 66, 275, 68, 69, 129, 276, 299, 263, 295,
|
||||
296, 297, 265, 268, 110, 295, 271, 113, 117, 295,
|
||||
119, 298, 277, 265, 299, 264, 295, 296, 297, 278,
|
||||
129, 286, 131, 258, 259, 260, 298, 262, 263, 264,
|
||||
265, 266, 267, 268, 269, 270, 271, 298, 273, 258,
|
||||
259, 260, 277, 262, 258, 259, 260, 266, 267, 268,
|
||||
269, 270, 266, 267, 268, 269, 270, 258, 259, 260,
|
||||
295, 296, 297, 265, 300, 266, 267, 268, 269, 270,
|
||||
259, 260, 298, 262, 298, 0, 295, 296, 297, 264,
|
||||
265, 295, 296, 297, 295, 298, 298, 272, 81, 258,
|
||||
259, 260, 108, 262, 295, 296, 297, 266, 267, 268,
|
||||
269, 270, 279, -1, 263, 282, 295, 296, 297, 268,
|
||||
287, 288, 271, -1, 299, 292, 293, 272, 277, 274,
|
||||
266, 267, 299, 269, 270, 280, 281, 296, 297, 284,
|
||||
285, 286, -1, -1, 289, 290, 291, -1, -1, 294,
|
||||
295, 258, 259, 260, 299, -1, 258, -1, -1, 266,
|
||||
267, 268, 269, 270, 266, 267, 268, 269, 270, -1,
|
||||
-1, -1, 272, -1, 274, -1, 276, -1, 276, 276,
|
||||
280, 281, -1, -1, 284, 285, 286, -1, -1, 289,
|
||||
290, 291, -1, -1, 294, 295, -1, -1, 298, 299,
|
||||
298, 298, 272, -1, 274, -1, -1, -1, -1, -1,
|
||||
280, 281, -1, -1, 284, -1, 286, -1, -1, 289,
|
||||
290, 291, -1, -1, 294, 295, -1, -1, -1, 299,
|
||||
};
|
||||
#define YYFINAL 14
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
#define YYMAXTOKEN 300
|
||||
#if YYDEBUG
|
||||
const char * const yyname[] = {
|
||||
"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"_BANG_t","_BANG_EQUALS_t",
|
||||
"_AMPER_t","_AMPERAMPER_t","_LPAREN_t","_RPAREN_t","_PLUS_EQUALS_t","_COLON_t",
|
||||
"_SEMIC_t","_LANGLE_t","_LANGLE_EQUALS_t","_EQUALS_t","_RANGLE_t",
|
||||
"_RANGLE_EQUALS_t","_QUESTION_EQUALS_t","_LBRACKET_t","_RBRACKET_t","ACTIONS_t",
|
||||
"BIND_t","CASE_t","DEFAULT_t","ELSE_t","EXISTING_t","FOR_t","IF_t","IGNORE_t",
|
||||
"IN_t","INCLUDE_t","LOCAL_t","ON_t","PIECEMEAL_t","QUIETLY_t","RETURN_t",
|
||||
"RULE_t","SWITCH_t","TOGETHER_t","UPDATED_t","WHILE_t","_LBRACE_t","_BAR_t",
|
||||
"_BARBAR_t","_RBRACE_t","ARG","STRING",
|
||||
};
|
||||
const char * const yyrule[] = {
|
||||
"$accept : run",
|
||||
"run :",
|
||||
"run : rules",
|
||||
"block :",
|
||||
"block : rules",
|
||||
"rules : rule",
|
||||
"rules : rule rules",
|
||||
"rules : LOCAL_t list _SEMIC_t block",
|
||||
"rules : LOCAL_t list _EQUALS_t list _SEMIC_t block",
|
||||
"rule : _LBRACE_t block _RBRACE_t",
|
||||
"rule : INCLUDE_t list _SEMIC_t",
|
||||
"rule : arg lol _SEMIC_t",
|
||||
"rule : arg assign list _SEMIC_t",
|
||||
"rule : arg ON_t list assign list _SEMIC_t",
|
||||
"rule : RETURN_t list _SEMIC_t",
|
||||
"rule : FOR_t ARG IN_t list _LBRACE_t block _RBRACE_t",
|
||||
"rule : SWITCH_t list _LBRACE_t cases _RBRACE_t",
|
||||
"rule : IF_t expr _LBRACE_t block _RBRACE_t",
|
||||
"rule : IF_t expr _LBRACE_t block _RBRACE_t ELSE_t rule",
|
||||
"rule : WHILE_t expr _LBRACE_t block _RBRACE_t",
|
||||
"rule : RULE_t ARG rule",
|
||||
"rule : ON_t arg rule",
|
||||
"$$1 :",
|
||||
"$$2 :",
|
||||
"rule : ACTIONS_t eflags ARG bindlist _LBRACE_t $$1 STRING $$2 _RBRACE_t",
|
||||
"assign : _EQUALS_t",
|
||||
"assign : _PLUS_EQUALS_t",
|
||||
"assign : _QUESTION_EQUALS_t",
|
||||
"assign : DEFAULT_t _EQUALS_t",
|
||||
"expr : arg",
|
||||
"expr : expr _EQUALS_t expr",
|
||||
"expr : expr _BANG_EQUALS_t expr",
|
||||
"expr : expr _LANGLE_t expr",
|
||||
"expr : expr _LANGLE_EQUALS_t expr",
|
||||
"expr : expr _RANGLE_t expr",
|
||||
"expr : expr _RANGLE_EQUALS_t expr",
|
||||
"expr : expr _AMPER_t expr",
|
||||
"expr : expr _AMPERAMPER_t expr",
|
||||
"expr : expr _BAR_t expr",
|
||||
"expr : expr _BARBAR_t expr",
|
||||
"expr : arg IN_t list",
|
||||
"expr : _BANG_t expr",
|
||||
"expr : _LPAREN_t expr _RPAREN_t",
|
||||
"cases :",
|
||||
"cases : case cases",
|
||||
"case : CASE_t ARG _COLON_t block",
|
||||
"lol : list",
|
||||
"lol : list _COLON_t lol",
|
||||
"list : listp",
|
||||
"listp :",
|
||||
"listp : listp arg",
|
||||
"arg : ARG",
|
||||
"$$3 :",
|
||||
"arg : _LBRACKET_t $$3 func _RBRACKET_t",
|
||||
"func : arg lol",
|
||||
"func : ON_t arg arg lol",
|
||||
"func : ON_t arg RETURN_t list",
|
||||
"eflags :",
|
||||
"eflags : eflags eflag",
|
||||
"eflag : UPDATED_t",
|
||||
"eflag : TOGETHER_t",
|
||||
"eflag : IGNORE_t",
|
||||
"eflag : QUIETLY_t",
|
||||
"eflag : PIECEMEAL_t",
|
||||
"eflag : EXISTING_t",
|
||||
"bindlist :",
|
||||
"bindlist : BIND_t list",
|
||||
};
|
||||
#endif
|
||||
#ifndef YYSTYPE
|
||||
typedef int YYSTYPE;
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef YYSTACKSIZE
|
||||
#undef YYMAXDEPTH
|
||||
#define YYMAXDEPTH YYSTACKSIZE
|
||||
#else
|
||||
#ifdef YYMAXDEPTH
|
||||
#define YYSTACKSIZE YYMAXDEPTH
|
||||
#else
|
||||
#define YYSTACKSIZE 10000
|
||||
#define YYMAXDEPTH 10000
|
||||
#endif
|
||||
#endif
|
||||
#define YYINITSTACKSIZE 200
|
||||
int yydebug;
|
||||
int yynerrs;
|
||||
int yyerrflag;
|
||||
int yychar;
|
||||
short *yyssp;
|
||||
YYSTYPE *yyvsp;
|
||||
YYSTYPE yyval;
|
||||
YYSTYPE yylval;
|
||||
short *yyss;
|
||||
short *yysslim;
|
||||
YYSTYPE *yyvs;
|
||||
int yystacksize;
|
||||
/* allocate initial stack or double stack size, up to YYMAXDEPTH */
|
||||
static int yygrowstack()
|
||||
{
|
||||
int newsize, i;
|
||||
short *newss;
|
||||
YYSTYPE *newvs;
|
||||
|
||||
if ((newsize = yystacksize) == 0)
|
||||
newsize = YYINITSTACKSIZE;
|
||||
else if (newsize >= YYMAXDEPTH)
|
||||
return -1;
|
||||
else if ((newsize *= 2) > YYMAXDEPTH)
|
||||
newsize = YYMAXDEPTH;
|
||||
i = yyssp - yyss;
|
||||
newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :
|
||||
(short *)malloc(newsize * sizeof *newss);
|
||||
if (newss == NULL)
|
||||
return -1;
|
||||
yyss = newss;
|
||||
yyssp = newss + i;
|
||||
newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :
|
||||
(YYSTYPE *)malloc(newsize * sizeof *newvs);
|
||||
if (newvs == NULL)
|
||||
return -1;
|
||||
yyvs = newvs;
|
||||
yyvsp = newvs + i;
|
||||
yystacksize = newsize;
|
||||
yysslim = yyss + newsize - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define YYABORT goto yyabort
|
||||
#define YYREJECT goto yyabort
|
||||
#define YYACCEPT goto yyaccept
|
||||
#define YYERROR goto yyerrlab
|
||||
|
||||
#ifndef YYPARSE_PARAM
|
||||
#if defined(__cplusplus) || __STDC__
|
||||
#define YYPARSE_PARAM_ARG void
|
||||
#define YYPARSE_PARAM_DECL
|
||||
#else /* ! ANSI-C/C++ */
|
||||
#define YYPARSE_PARAM_ARG
|
||||
#define YYPARSE_PARAM_DECL
|
||||
#endif /* ANSI-C/C++ */
|
||||
#else /* YYPARSE_PARAM */
|
||||
#ifndef YYPARSE_PARAM_TYPE
|
||||
#define YYPARSE_PARAM_TYPE void *
|
||||
#endif
|
||||
#if defined(__cplusplus) || __STDC__
|
||||
#define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM
|
||||
#define YYPARSE_PARAM_DECL
|
||||
#else /* ! ANSI-C/C++ */
|
||||
#define YYPARSE_PARAM_ARG YYPARSE_PARAM
|
||||
#define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM;
|
||||
#endif /* ANSI-C/C++ */
|
||||
#endif /* ! YYPARSE_PARAM */
|
||||
|
||||
int
|
||||
yyparse (YYPARSE_PARAM_ARG)
|
||||
YYPARSE_PARAM_DECL
|
||||
{
|
||||
register int yym, yyn, yystate;
|
||||
#if YYDEBUG
|
||||
register const char *yys;
|
||||
|
||||
if ((yys = getenv("YYDEBUG")))
|
||||
{
|
||||
yyn = *yys;
|
||||
if (yyn >= '0' && yyn <= '9')
|
||||
yydebug = yyn - '0';
|
||||
}
|
||||
#endif
|
||||
|
||||
yynerrs = 0;
|
||||
yyerrflag = 0;
|
||||
yychar = (-1);
|
||||
|
||||
if (yyss == NULL && yygrowstack()) goto yyoverflow;
|
||||
yyssp = yyss;
|
||||
yyvsp = yyvs;
|
||||
*yyssp = yystate = 0;
|
||||
|
||||
yyloop:
|
||||
if ((yyn = yydefred[yystate])) goto yyreduce;
|
||||
if (yychar < 0)
|
||||
{
|
||||
if ((yychar = yylex()) < 0) yychar = 0;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("%sdebug: state %d, reading %d (%s)\n",
|
||||
YYPREFIX, yystate, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: state %d, shifting to state %d\n",
|
||||
YYPREFIX, yystate, yytable[yyn]);
|
||||
#endif
|
||||
if (yyssp >= yysslim && yygrowstack())
|
||||
{
|
||||
goto yyoverflow;
|
||||
}
|
||||
*++yyssp = yystate = yytable[yyn];
|
||||
*++yyvsp = yylval;
|
||||
yychar = (-1);
|
||||
if (yyerrflag > 0) --yyerrflag;
|
||||
goto yyloop;
|
||||
}
|
||||
if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
|
||||
{
|
||||
yyn = yytable[yyn];
|
||||
goto yyreduce;
|
||||
}
|
||||
if (yyerrflag) goto yyinrecovery;
|
||||
#if defined(lint) || defined(__GNUC__)
|
||||
goto yynewerror;
|
||||
#endif
|
||||
yynewerror:
|
||||
yyerror("syntax error");
|
||||
#if defined(lint) || defined(__GNUC__)
|
||||
goto yyerrlab;
|
||||
#endif
|
||||
yyerrlab:
|
||||
++yynerrs;
|
||||
yyinrecovery:
|
||||
if (yyerrflag < 3)
|
||||
{
|
||||
yyerrflag = 3;
|
||||
for (;;)
|
||||
{
|
||||
if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: state %d, error recovery shifting\
|
||||
to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
|
||||
#endif
|
||||
if (yyssp >= yysslim && yygrowstack())
|
||||
{
|
||||
goto yyoverflow;
|
||||
}
|
||||
*++yyssp = yystate = yytable[yyn];
|
||||
*++yyvsp = yylval;
|
||||
goto yyloop;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: error recovery discarding state %d\n",
|
||||
YYPREFIX, *yyssp);
|
||||
#endif
|
||||
if (yyssp <= yyss) goto yyabort;
|
||||
--yyssp;
|
||||
--yyvsp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yychar == 0) goto yyabort;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
|
||||
YYPREFIX, yystate, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
yychar = (-1);
|
||||
goto yyloop;
|
||||
}
|
||||
yyreduce:
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: state %d, reducing by rule %d (%s)\n",
|
||||
YYPREFIX, yystate, yyn, yyrule[yyn]);
|
||||
#endif
|
||||
yym = yylen[yyn];
|
||||
yyval = yyvsp[1-yym];
|
||||
switch (yyn)
|
||||
{
|
||||
case 2:
|
||||
#line 132 "jamgram.y"
|
||||
{ parse_save( yyvsp[0].parse ); }
|
||||
break;
|
||||
case 3:
|
||||
#line 143 "jamgram.y"
|
||||
{ yyval.parse = pnull(); }
|
||||
break;
|
||||
case 4:
|
||||
#line 145 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[0].parse; }
|
||||
break;
|
||||
case 5:
|
||||
#line 149 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[0].parse; }
|
||||
break;
|
||||
case 6:
|
||||
#line 151 "jamgram.y"
|
||||
{ yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 7:
|
||||
#line 153 "jamgram.y"
|
||||
{ yyval.parse = plocal( yyvsp[-2].parse, pnull(), yyvsp[0].parse ); }
|
||||
break;
|
||||
case 8:
|
||||
#line 155 "jamgram.y"
|
||||
{ yyval.parse = plocal( yyvsp[-4].parse, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 9:
|
||||
#line 159 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[-1].parse; }
|
||||
break;
|
||||
case 10:
|
||||
#line 161 "jamgram.y"
|
||||
{ yyval.parse = pincl( yyvsp[-1].parse ); }
|
||||
break;
|
||||
case 11:
|
||||
#line 163 "jamgram.y"
|
||||
{ yyval.parse = prule( yyvsp[-2].parse, yyvsp[-1].parse ); }
|
||||
break;
|
||||
case 12:
|
||||
#line 165 "jamgram.y"
|
||||
{ yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
|
||||
break;
|
||||
case 13:
|
||||
#line 167 "jamgram.y"
|
||||
{ yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
|
||||
break;
|
||||
case 14:
|
||||
#line 169 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[-1].parse; }
|
||||
break;
|
||||
case 15:
|
||||
#line 171 "jamgram.y"
|
||||
{ yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse ); }
|
||||
break;
|
||||
case 16:
|
||||
#line 173 "jamgram.y"
|
||||
{ yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); }
|
||||
break;
|
||||
case 17:
|
||||
#line 175 "jamgram.y"
|
||||
{ yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); }
|
||||
break;
|
||||
case 18:
|
||||
#line 177 "jamgram.y"
|
||||
{ yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 19:
|
||||
#line 179 "jamgram.y"
|
||||
{ yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); }
|
||||
break;
|
||||
case 20:
|
||||
#line 181 "jamgram.y"
|
||||
{ yyval.parse = psetc( yyvsp[-1].string, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 21:
|
||||
#line 183 "jamgram.y"
|
||||
{ yyval.parse = pon( yyvsp[-1].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 22:
|
||||
#line 185 "jamgram.y"
|
||||
{ yymode( SCAN_STRING ); }
|
||||
break;
|
||||
case 23:
|
||||
#line 187 "jamgram.y"
|
||||
{ yymode( SCAN_NORMAL ); }
|
||||
break;
|
||||
case 24:
|
||||
#line 189 "jamgram.y"
|
||||
{ yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); }
|
||||
break;
|
||||
case 25:
|
||||
#line 197 "jamgram.y"
|
||||
{ yyval.number = ASSIGN_SET; }
|
||||
break;
|
||||
case 26:
|
||||
#line 199 "jamgram.y"
|
||||
{ yyval.number = ASSIGN_APPEND; }
|
||||
break;
|
||||
case 27:
|
||||
#line 201 "jamgram.y"
|
||||
{ yyval.number = ASSIGN_DEFAULT; }
|
||||
break;
|
||||
case 28:
|
||||
#line 203 "jamgram.y"
|
||||
{ yyval.number = ASSIGN_DEFAULT; }
|
||||
break;
|
||||
case 29:
|
||||
#line 211 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_EXISTS, yyvsp[0].parse, pnull() ); }
|
||||
break;
|
||||
case 30:
|
||||
#line 213 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 31:
|
||||
#line 215 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 32:
|
||||
#line 217 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_LESS, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 33:
|
||||
#line 219 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 34:
|
||||
#line 221 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_MORE, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 35:
|
||||
#line 223 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 36:
|
||||
#line 225 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 37:
|
||||
#line 227 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 38:
|
||||
#line 229 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 39:
|
||||
#line 231 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 40:
|
||||
#line 233 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_IN, yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 41:
|
||||
#line 235 "jamgram.y"
|
||||
{ yyval.parse = peval( EXPR_NOT, yyvsp[0].parse, pnull() ); }
|
||||
break;
|
||||
case 42:
|
||||
#line 237 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[-1].parse; }
|
||||
break;
|
||||
case 43:
|
||||
#line 247 "jamgram.y"
|
||||
{ yyval.parse = P0; }
|
||||
break;
|
||||
case 44:
|
||||
#line 249 "jamgram.y"
|
||||
{ yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 45:
|
||||
#line 253 "jamgram.y"
|
||||
{ yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 46:
|
||||
#line 262 "jamgram.y"
|
||||
{ yyval.parse = pnode( P0, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 47:
|
||||
#line 264 "jamgram.y"
|
||||
{ yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); }
|
||||
break;
|
||||
case 48:
|
||||
#line 274 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); }
|
||||
break;
|
||||
case 49:
|
||||
#line 278 "jamgram.y"
|
||||
{ yyval.parse = pnull(); yymode( SCAN_PUNCT ); }
|
||||
break;
|
||||
case 50:
|
||||
#line 280 "jamgram.y"
|
||||
{ yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 51:
|
||||
#line 284 "jamgram.y"
|
||||
{ yyval.parse = plist( yyvsp[0].string ); }
|
||||
break;
|
||||
case 52:
|
||||
#line 285 "jamgram.y"
|
||||
{ yymode( SCAN_NORMAL ); }
|
||||
break;
|
||||
case 53:
|
||||
#line 286 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[-1].parse; }
|
||||
break;
|
||||
case 54:
|
||||
#line 295 "jamgram.y"
|
||||
{ yyval.parse = prule( yyvsp[-1].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 55:
|
||||
#line 297 "jamgram.y"
|
||||
{ yyval.parse = pon( yyvsp[-2].parse, prule( yyvsp[-1].parse, yyvsp[0].parse ) ); }
|
||||
break;
|
||||
case 56:
|
||||
#line 299 "jamgram.y"
|
||||
{ yyval.parse = pon( yyvsp[-2].parse, yyvsp[0].parse ); }
|
||||
break;
|
||||
case 57:
|
||||
#line 308 "jamgram.y"
|
||||
{ yyval.number = 0; }
|
||||
break;
|
||||
case 58:
|
||||
#line 310 "jamgram.y"
|
||||
{ yyval.number = yyvsp[-1].number | yyvsp[0].number; }
|
||||
break;
|
||||
case 59:
|
||||
#line 314 "jamgram.y"
|
||||
{ yyval.number = RULE_UPDATED; }
|
||||
break;
|
||||
case 60:
|
||||
#line 316 "jamgram.y"
|
||||
{ yyval.number = RULE_TOGETHER; }
|
||||
break;
|
||||
case 61:
|
||||
#line 318 "jamgram.y"
|
||||
{ yyval.number = RULE_IGNORE; }
|
||||
break;
|
||||
case 62:
|
||||
#line 320 "jamgram.y"
|
||||
{ yyval.number = RULE_QUIETLY; }
|
||||
break;
|
||||
case 63:
|
||||
#line 322 "jamgram.y"
|
||||
{ yyval.number = RULE_PIECEMEAL; }
|
||||
break;
|
||||
case 64:
|
||||
#line 324 "jamgram.y"
|
||||
{ yyval.number = RULE_EXISTING; }
|
||||
break;
|
||||
case 65:
|
||||
#line 333 "jamgram.y"
|
||||
{ yyval.parse = pnull(); }
|
||||
break;
|
||||
case 66:
|
||||
#line 335 "jamgram.y"
|
||||
{ yyval.parse = yyvsp[0].parse; }
|
||||
break;
|
||||
#line 821 "y.tab.c"
|
||||
}
|
||||
yyssp -= yym;
|
||||
yystate = *yyssp;
|
||||
yyvsp -= yym;
|
||||
yym = yylhs[yyn];
|
||||
if (yystate == 0 && yym == 0)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: after reduction, shifting from state 0 to\
|
||||
state %d\n", YYPREFIX, YYFINAL);
|
||||
#endif
|
||||
yystate = YYFINAL;
|
||||
*++yyssp = YYFINAL;
|
||||
*++yyvsp = yyval;
|
||||
if (yychar < 0)
|
||||
{
|
||||
if ((yychar = yylex()) < 0) yychar = 0;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("%sdebug: state %d, reading %d (%s)\n",
|
||||
YYPREFIX, YYFINAL, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (yychar == 0) goto yyaccept;
|
||||
goto yyloop;
|
||||
}
|
||||
if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
|
||||
yystate = yytable[yyn];
|
||||
else
|
||||
yystate = yydgoto[yym];
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: after reduction, shifting from state %d \
|
||||
to state %d\n", YYPREFIX, *yyssp, yystate);
|
||||
#endif
|
||||
if (yyssp >= yysslim && yygrowstack())
|
||||
{
|
||||
goto yyoverflow;
|
||||
}
|
||||
*++yyssp = yystate;
|
||||
*++yyvsp = yyval;
|
||||
goto yyloop;
|
||||
yyoverflow:
|
||||
yyerror("yacc stack overflow");
|
||||
yyabort:
|
||||
return (1);
|
||||
yyaccept:
|
||||
return (0);
|
||||
}
|
48
src/tools/jam/jamgram.h
Normal file
48
src/tools/jam/jamgram.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef YYERRCODE
|
||||
#define YYERRCODE 256
|
||||
#endif
|
||||
|
||||
#define _BANG_t 257
|
||||
#define _BANG_EQUALS_t 258
|
||||
#define _AMPER_t 259
|
||||
#define _AMPERAMPER_t 260
|
||||
#define _LPAREN_t 261
|
||||
#define _RPAREN_t 262
|
||||
#define _PLUS_EQUALS_t 263
|
||||
#define _COLON_t 264
|
||||
#define _SEMIC_t 265
|
||||
#define _LANGLE_t 266
|
||||
#define _LANGLE_EQUALS_t 267
|
||||
#define _EQUALS_t 268
|
||||
#define _RANGLE_t 269
|
||||
#define _RANGLE_EQUALS_t 270
|
||||
#define _QUESTION_EQUALS_t 271
|
||||
#define _LBRACKET_t 272
|
||||
#define _RBRACKET_t 273
|
||||
#define ACTIONS_t 274
|
||||
#define BIND_t 275
|
||||
#define CASE_t 276
|
||||
#define DEFAULT_t 277
|
||||
#define ELSE_t 278
|
||||
#define EXISTING_t 279
|
||||
#define FOR_t 280
|
||||
#define IF_t 281
|
||||
#define IGNORE_t 282
|
||||
#define IN_t 283
|
||||
#define INCLUDE_t 284
|
||||
#define LOCAL_t 285
|
||||
#define ON_t 286
|
||||
#define PIECEMEAL_t 287
|
||||
#define QUIETLY_t 288
|
||||
#define RETURN_t 289
|
||||
#define RULE_t 290
|
||||
#define SWITCH_t 291
|
||||
#define TOGETHER_t 292
|
||||
#define UPDATED_t 293
|
||||
#define WHILE_t 294
|
||||
#define _LBRACE_t 295
|
||||
#define _BAR_t 296
|
||||
#define _BARBAR_t 297
|
||||
#define _RBRACE_t 298
|
||||
#define ARG 299
|
||||
#define STRING 300
|
338
src/tools/jam/jamgram.y
Normal file
338
src/tools/jam/jamgram.y
Normal file
@ -0,0 +1,338 @@
|
||||
%token _BANG_t
|
||||
%token _BANG_EQUALS_t
|
||||
%token _AMPER_t
|
||||
%token _AMPERAMPER_t
|
||||
%token _LPAREN_t
|
||||
%token _RPAREN_t
|
||||
%token _PLUS_EQUALS_t
|
||||
%token _COLON_t
|
||||
%token _SEMIC_t
|
||||
%token _LANGLE_t
|
||||
%token _LANGLE_EQUALS_t
|
||||
%token _EQUALS_t
|
||||
%token _RANGLE_t
|
||||
%token _RANGLE_EQUALS_t
|
||||
%token _QUESTION_EQUALS_t
|
||||
%token _LBRACKET_t
|
||||
%token _RBRACKET_t
|
||||
%token ACTIONS_t
|
||||
%token BIND_t
|
||||
%token CASE_t
|
||||
%token DEFAULT_t
|
||||
%token ELSE_t
|
||||
%token EXISTING_t
|
||||
%token FOR_t
|
||||
%token IF_t
|
||||
%token IGNORE_t
|
||||
%token IN_t
|
||||
%token INCLUDE_t
|
||||
%token LOCAL_t
|
||||
%token ON_t
|
||||
%token PIECEMEAL_t
|
||||
%token QUIETLY_t
|
||||
%token RETURN_t
|
||||
%token RULE_t
|
||||
%token SWITCH_t
|
||||
%token TOGETHER_t
|
||||
%token UPDATED_t
|
||||
%token WHILE_t
|
||||
%token _LBRACE_t
|
||||
%token _BAR_t
|
||||
%token _BARBAR_t
|
||||
%token _RBRACE_t
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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_t _BAR_t
|
||||
%left _AMPERAMPER_t _AMPER_t
|
||||
%left _EQUALS_t _BANG_EQUALS_t IN_t
|
||||
%left _LANGLE_t _LANGLE_EQUALS_t _RANGLE_t _RANGLE_EQUALS_t
|
||||
%left _BANG_t
|
||||
|
||||
%{
|
||||
#include "jam.h"
|
||||
|
||||
#include "lists.h"
|
||||
#include "parse.h"
|
||||
#include "scan.h"
|
||||
#include "compile.h"
|
||||
#include "newstr.h"
|
||||
#include "rules.h"
|
||||
|
||||
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
|
||||
|
||||
# define F0 (LIST *(*)(PARSE *, LOL *))0
|
||||
# define P0 (PARSE *)0
|
||||
# define S0 (char *)0
|
||||
|
||||
# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
|
||||
# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
|
||||
# define pfor( s,l,r ) parse_make( compile_foreach,l,r,P0,s,S0,0 )
|
||||
# define pif( l,r,t ) parse_make( compile_if,l,r,t,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 pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
|
||||
# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
|
||||
# define prule( a,p ) parse_make( compile_rule,a,p,P0,S0,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 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 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 pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
|
||||
|
||||
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
|
||||
# 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_t list _SEMIC_t block
|
||||
{ $$.parse = plocal( $2.parse, pnull(), $4.parse ); }
|
||||
| LOCAL_t list _EQUALS_t list _SEMIC_t block
|
||||
{ $$.parse = plocal( $2.parse, $4.parse, $6.parse ); }
|
||||
;
|
||||
|
||||
rule : _LBRACE_t block _RBRACE_t
|
||||
{ $$.parse = $2.parse; }
|
||||
| INCLUDE_t list _SEMIC_t
|
||||
{ $$.parse = pincl( $2.parse ); }
|
||||
| arg lol _SEMIC_t
|
||||
{ $$.parse = prule( $1.parse, $2.parse ); }
|
||||
| arg assign list _SEMIC_t
|
||||
{ $$.parse = pset( $1.parse, $3.parse, $2.number ); }
|
||||
| arg ON_t list assign list _SEMIC_t
|
||||
{ $$.parse = pset1( $1.parse, $3.parse, $5.parse, $4.number ); }
|
||||
| RETURN_t list _SEMIC_t
|
||||
{ $$.parse = $2.parse; }
|
||||
| FOR_t ARG IN_t list _LBRACE_t block _RBRACE_t
|
||||
{ $$.parse = pfor( $2.string, $4.parse, $6.parse ); }
|
||||
| SWITCH_t list _LBRACE_t cases _RBRACE_t
|
||||
{ $$.parse = pswitch( $2.parse, $4.parse ); }
|
||||
| IF_t expr _LBRACE_t block _RBRACE_t
|
||||
{ $$.parse = pif( $2.parse, $4.parse, pnull() ); }
|
||||
| IF_t expr _LBRACE_t block _RBRACE_t ELSE_t rule
|
||||
{ $$.parse = pif( $2.parse, $4.parse, $7.parse ); }
|
||||
| WHILE_t expr _LBRACE_t block _RBRACE_t
|
||||
{ $$.parse = pwhile( $2.parse, $4.parse ); }
|
||||
| RULE_t ARG rule
|
||||
{ $$.parse = psetc( $2.string, $3.parse ); }
|
||||
| ON_t arg rule
|
||||
{ $$.parse = pon( $2.parse, $3.parse ); }
|
||||
| ACTIONS_t eflags ARG bindlist _LBRACE_t
|
||||
{ yymode( SCAN_STRING ); }
|
||||
STRING
|
||||
{ yymode( SCAN_NORMAL ); }
|
||||
_RBRACE_t
|
||||
{ $$.parse = psete( $3.string,$4.parse,$7.string,$2.number ); }
|
||||
;
|
||||
|
||||
/*
|
||||
* assign - = or +=
|
||||
*/
|
||||
|
||||
assign : _EQUALS_t
|
||||
{ $$.number = ASSIGN_SET; }
|
||||
| _PLUS_EQUALS_t
|
||||
{ $$.number = ASSIGN_APPEND; }
|
||||
| _QUESTION_EQUALS_t
|
||||
{ $$.number = ASSIGN_DEFAULT; }
|
||||
| DEFAULT_t _EQUALS_t
|
||||
{ $$.number = ASSIGN_DEFAULT; }
|
||||
;
|
||||
|
||||
/*
|
||||
* expr - an expression for if
|
||||
*/
|
||||
|
||||
expr : arg
|
||||
{ $$.parse = peval( EXPR_EXISTS, $1.parse, pnull() ); }
|
||||
| expr _EQUALS_t expr
|
||||
{ $$.parse = peval( EXPR_EQUALS, $1.parse, $3.parse ); }
|
||||
| expr _BANG_EQUALS_t expr
|
||||
{ $$.parse = peval( EXPR_NOTEQ, $1.parse, $3.parse ); }
|
||||
| expr _LANGLE_t expr
|
||||
{ $$.parse = peval( EXPR_LESS, $1.parse, $3.parse ); }
|
||||
| expr _LANGLE_EQUALS_t expr
|
||||
{ $$.parse = peval( EXPR_LESSEQ, $1.parse, $3.parse ); }
|
||||
| expr _RANGLE_t expr
|
||||
{ $$.parse = peval( EXPR_MORE, $1.parse, $3.parse ); }
|
||||
| expr _RANGLE_EQUALS_t expr
|
||||
{ $$.parse = peval( EXPR_MOREEQ, $1.parse, $3.parse ); }
|
||||
| expr _AMPER_t expr
|
||||
{ $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); }
|
||||
| expr _AMPERAMPER_t expr
|
||||
{ $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); }
|
||||
| expr _BAR_t expr
|
||||
{ $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); }
|
||||
| expr _BARBAR_t expr
|
||||
{ $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); }
|
||||
| arg IN_t list
|
||||
{ $$.parse = peval( EXPR_IN, $1.parse, $3.parse ); }
|
||||
| _BANG_t expr
|
||||
{ $$.parse = peval( EXPR_NOT, $2.parse, pnull() ); }
|
||||
| _LPAREN_t expr _RPAREN_t
|
||||
{ $$.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_t ARG _COLON_t 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_t 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_t { yymode( SCAN_NORMAL ); } func _RBRACKET_t
|
||||
{ $$.parse = $3.parse; }
|
||||
;
|
||||
|
||||
/*
|
||||
* func - a function call (inside [])
|
||||
* This needs to be split cleanly out of 'rule'
|
||||
*/
|
||||
|
||||
func : arg lol
|
||||
{ $$.parse = prule( $1.parse, $2.parse ); }
|
||||
| ON_t arg arg lol
|
||||
{ $$.parse = pon( $2.parse, prule( $3.parse, $4.parse ) ); }
|
||||
| ON_t arg RETURN_t list
|
||||
{ $$.parse = pon( $2.parse, $4.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_t
|
||||
{ $$.number = RULE_UPDATED; }
|
||||
| TOGETHER_t
|
||||
{ $$.number = RULE_TOGETHER; }
|
||||
| IGNORE_t
|
||||
{ $$.number = RULE_IGNORE; }
|
||||
| QUIETLY_t
|
||||
{ $$.number = RULE_QUIETLY; }
|
||||
| PIECEMEAL_t
|
||||
{ $$.number = RULE_PIECEMEAL; }
|
||||
| EXISTING_t
|
||||
{ $$.number = RULE_EXISTING; }
|
||||
;
|
||||
|
||||
|
||||
/*
|
||||
* bindlist - list of variable to bind for an action
|
||||
*/
|
||||
|
||||
bindlist : /* empty */
|
||||
{ $$.parse = pnull(); }
|
||||
| BIND_t list
|
||||
{ $$.parse = $2.parse; }
|
||||
;
|
||||
|
||||
|
296
src/tools/jam/jamgram.yy
Normal file
296
src/tools/jam/jamgram.yy
Normal file
@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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 `=` `!=` `in`
|
||||
%left `<` `<=` `>` `>=`
|
||||
%left `!`
|
||||
|
||||
%{
|
||||
#include "jam.h"
|
||||
|
||||
#include "lists.h"
|
||||
#include "parse.h"
|
||||
#include "scan.h"
|
||||
#include "compile.h"
|
||||
#include "newstr.h"
|
||||
#include "rules.h"
|
||||
|
||||
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
|
||||
|
||||
# define F0 (LIST *(*)(PARSE *, LOL *))0
|
||||
# define P0 (PARSE *)0
|
||||
# define S0 (char *)0
|
||||
|
||||
# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
|
||||
# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
|
||||
# define pfor( s,l,r ) parse_make( compile_foreach,l,r,P0,s,S0,0 )
|
||||
# define pif( l,r,t ) parse_make( compile_if,l,r,t,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 pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
|
||||
# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
|
||||
# define prule( a,p ) parse_make( compile_rule,a,p,P0,S0,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 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 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 pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
|
||||
|
||||
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
|
||||
# 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 `;` block
|
||||
{ $$.parse = plocal( $2.parse, pnull(), $4.parse ); }
|
||||
| `local` list `=` list `;` block
|
||||
{ $$.parse = plocal( $2.parse, $4.parse, $6.parse ); }
|
||||
;
|
||||
|
||||
rule : `{` block `}`
|
||||
{ $$.parse = $2.parse; }
|
||||
| `include` list `;`
|
||||
{ $$.parse = pincl( $2.parse ); }
|
||||
| arg lol `;`
|
||||
{ $$.parse = prule( $1.parse, $2.parse ); }
|
||||
| arg assign list `;`
|
||||
{ $$.parse = pset( $1.parse, $3.parse, $2.number ); }
|
||||
| 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 ); }
|
||||
| `switch` list `{` cases `}`
|
||||
{ $$.parse = pswitch( $2.parse, $4.parse ); }
|
||||
| `if` expr `{` block `}`
|
||||
{ $$.parse = pif( $2.parse, $4.parse, pnull() ); }
|
||||
| `if` expr `{` block `}` `else` rule
|
||||
{ $$.parse = pif( $2.parse, $4.parse, $7.parse ); }
|
||||
| `while` expr `{` block `}`
|
||||
{ $$.parse = pwhile( $2.parse, $4.parse ); }
|
||||
| `rule` ARG rule
|
||||
{ $$.parse = psetc( $2.string, $3.parse ); }
|
||||
| `on` arg rule
|
||||
{ $$.parse = pon( $2.parse, $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; }
|
||||
;
|
||||
|
||||
/*
|
||||
* expr - an expression for if
|
||||
*/
|
||||
|
||||
expr : arg
|
||||
{ $$.parse = peval( EXPR_EXISTS, $1.parse, pnull() ); }
|
||||
| expr `=` expr
|
||||
{ $$.parse = peval( EXPR_EQUALS, $1.parse, $3.parse ); }
|
||||
| expr `!=` expr
|
||||
{ $$.parse = peval( EXPR_NOTEQ, $1.parse, $3.parse ); }
|
||||
| expr `<` expr
|
||||
{ $$.parse = peval( EXPR_LESS, $1.parse, $3.parse ); }
|
||||
| expr `<=` expr
|
||||
{ $$.parse = peval( EXPR_LESSEQ, $1.parse, $3.parse ); }
|
||||
| expr `>` expr
|
||||
{ $$.parse = peval( EXPR_MORE, $1.parse, $3.parse ); }
|
||||
| expr `>=` expr
|
||||
{ $$.parse = peval( EXPR_MOREEQ, $1.parse, $3.parse ); }
|
||||
| expr `&` expr
|
||||
{ $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); }
|
||||
| expr `&&` expr
|
||||
{ $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); }
|
||||
| expr `|` expr
|
||||
{ $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); }
|
||||
| expr `||` expr
|
||||
{ $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); }
|
||||
| arg `in` list
|
||||
{ $$.parse = peval( EXPR_IN, $1.parse, $3.parse ); }
|
||||
| `!` expr
|
||||
{ $$.parse = peval( EXPR_NOT, $2.parse, pnull() ); }
|
||||
| `(` expr `)`
|
||||
{ $$.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 ); }
|
||||
| `[` { yymode( SCAN_NORMAL ); } func `]`
|
||||
{ $$.parse = $3.parse; }
|
||||
;
|
||||
|
||||
/*
|
||||
* func - a function call (inside [])
|
||||
* This needs to be split cleanly out of 'rule'
|
||||
*/
|
||||
|
||||
func : arg lol
|
||||
{ $$.parse = prule( $1.parse, $2.parse ); }
|
||||
| `on` arg arg lol
|
||||
{ $$.parse = pon( $2.parse, prule( $3.parse, $4.parse ) ); }
|
||||
| `on` arg `return` list
|
||||
{ $$.parse = pon( $2.parse, $4.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 = RULE_UPDATED; }
|
||||
| `together`
|
||||
{ $$.number = RULE_TOGETHER; }
|
||||
| `ignore`
|
||||
{ $$.number = RULE_IGNORE; }
|
||||
| `quietly`
|
||||
{ $$.number = RULE_QUIETLY; }
|
||||
| `piecemeal`
|
||||
{ $$.number = RULE_PIECEMEAL; }
|
||||
| `existing`
|
||||
{ $$.number = RULE_EXISTING; }
|
||||
;
|
||||
|
||||
|
||||
/*
|
||||
* bindlist - list of variable to bind for an action
|
||||
*/
|
||||
|
||||
bindlist : /* empty */
|
||||
{ $$.parse = pnull(); }
|
||||
| `bind` list
|
||||
{ $$.parse = $2.parse; }
|
||||
;
|
||||
|
||||
|
42
src/tools/jam/jamgramtab.h
Normal file
42
src/tools/jam/jamgramtab.h
Normal file
@ -0,0 +1,42 @@
|
||||
{ "!", _BANG_t },
|
||||
{ "!=", _BANG_EQUALS_t },
|
||||
{ "&", _AMPER_t },
|
||||
{ "&&", _AMPERAMPER_t },
|
||||
{ "(", _LPAREN_t },
|
||||
{ ")", _RPAREN_t },
|
||||
{ "+=", _PLUS_EQUALS_t },
|
||||
{ ":", _COLON_t },
|
||||
{ ";", _SEMIC_t },
|
||||
{ "<", _LANGLE_t },
|
||||
{ "<=", _LANGLE_EQUALS_t },
|
||||
{ "=", _EQUALS_t },
|
||||
{ ">", _RANGLE_t },
|
||||
{ ">=", _RANGLE_EQUALS_t },
|
||||
{ "?=", _QUESTION_EQUALS_t },
|
||||
{ "[", _LBRACKET_t },
|
||||
{ "]", _RBRACKET_t },
|
||||
{ "actions", ACTIONS_t },
|
||||
{ "bind", BIND_t },
|
||||
{ "case", CASE_t },
|
||||
{ "default", DEFAULT_t },
|
||||
{ "else", ELSE_t },
|
||||
{ "existing", EXISTING_t },
|
||||
{ "for", FOR_t },
|
||||
{ "if", IF_t },
|
||||
{ "ignore", IGNORE_t },
|
||||
{ "in", IN_t },
|
||||
{ "include", INCLUDE_t },
|
||||
{ "local", LOCAL_t },
|
||||
{ "on", ON_t },
|
||||
{ "piecemeal", PIECEMEAL_t },
|
||||
{ "quietly", QUIETLY_t },
|
||||
{ "return", RETURN_t },
|
||||
{ "rule", RULE_t },
|
||||
{ "switch", SWITCH_t },
|
||||
{ "together", TOGETHER_t },
|
||||
{ "updated", UPDATED_t },
|
||||
{ "while", WHILE_t },
|
||||
{ "{", _LBRACE_t },
|
||||
{ "|", _BAR_t },
|
||||
{ "||", _BARBAR_t },
|
||||
{ "}", _RBRACE_t },
|
243
src/tools/jam/lists.c
Normal file
243
src/tools/jam/lists.c
Normal file
@ -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] );
|
||||
}
|
||||
}
|
80
src/tools/jam/lists.h
Normal file
80
src/tools/jam/lists.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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()
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 );
|
479
src/tools/jam/make.c
Normal file
479
src/tools/jam/make.c
Normal file
@ -0,0 +1,479 @@
|
||||
/*
|
||||
* 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
|
||||
* make0sort() - reorder TARGETS chain by their time (newest to oldest)
|
||||
*
|
||||
* 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.
|
||||
* 03/14/02 (seiwald) - TEMPORARY targets no longer take on parents age
|
||||
* 03/16/02 (seiwald) - support for -g (reorder builds by source time)
|
||||
*/
|
||||
|
||||
# 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, time_t ptime, int depth,
|
||||
COUNTS *counts, int anyhow );
|
||||
|
||||
static TARGETS *make0sort( TARGETS *c );
|
||||
|
||||
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) ( " " + 16 - ( x > 16 ? 16 : 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, (time_t)0, 0, counts, anyhow );
|
||||
}
|
||||
|
||||
if( DEBUG_MAKE )
|
||||
{
|
||||
if( counts->targets )
|
||||
printf( "...found %d target(s)...\n", counts->targets );
|
||||
if( counts->temp )
|
||||
printf( "...using %d temp target(s)...\n", counts->temp );
|
||||
if( counts->updating )
|
||||
printf( "...updating %d target(s)...\n", counts->updating );
|
||||
if( counts->cantfind )
|
||||
printf( "...can't find %d target(s)...\n", counts->cantfind );
|
||||
if( counts->cantmake )
|
||||
printf( "...can't make %d target(s)...\n", counts->cantmake );
|
||||
}
|
||||
|
||||
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,
|
||||
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;
|
||||
|
||||
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 but parent does, use parent */
|
||||
|
||||
if( t->binding == T_BIND_MISSING && t->flags & T_FLAG_TEMP && ptime )
|
||||
t->binding = T_BIND_PARENTS;
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
/* Pass our time or our parent's time down. */
|
||||
|
||||
int time = t->binding == T_BIND_PARENTS ? ptime : t->time;
|
||||
|
||||
make0( c->target, 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 than parent, make temp.
|
||||
If deliberately touched, make it.
|
||||
If up-to-date temp file present, use it.
|
||||
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 > ptime )
|
||||
{
|
||||
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 && 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 3e: sort dependents by their update time. */
|
||||
|
||||
if( globs.newestfirst )
|
||||
t->deps[ T_DEPS_DEPENDS ] = make0sort( t->deps[ T_DEPS_DEPENDS ] );
|
||||
|
||||
/*
|
||||
* 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, 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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* make0sort() - reorder TARGETS chain by their time (newest to oldest)
|
||||
*/
|
||||
|
||||
static TARGETS *
|
||||
make0sort( TARGETS *chain )
|
||||
{
|
||||
TARGETS *result = 0;
|
||||
|
||||
/* We walk chain, taking each item and inserting it on the */
|
||||
/* sorted result, with newest items at the front. This involves */
|
||||
/* updating each TARGETS' c->next and c->tail. Note that we */
|
||||
/* make c->tail a valid prev pointer for every entry. Normally, */
|
||||
/* it is only valid at the head, where prev == tail. Note also */
|
||||
/* that while tail is a loop, next ends at the end of the chain. */
|
||||
|
||||
/* Walk current target list */
|
||||
|
||||
while( chain )
|
||||
{
|
||||
TARGETS *c = chain;
|
||||
TARGETS *s = result;
|
||||
|
||||
chain = chain->next;
|
||||
|
||||
/* Find point s in result for c */
|
||||
|
||||
while( s && s->target->time > c->target->time )
|
||||
s = s->next;
|
||||
|
||||
/* Insert c in front of s (might be 0). */
|
||||
/* Don't even think of deciphering this. */
|
||||
|
||||
c->next = s; /* good even if s = 0 */
|
||||
if( result == s ) result = c; /* new head of chain? */
|
||||
if( !s ) s = result; /* wrap to ensure a next */
|
||||
if( result != c ) s->tail->next = c; /* not head? be prev's next */
|
||||
c->tail = s->tail; /* take on next's prev */
|
||||
s->tail = c; /* make next's prev us */
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
12
src/tools/jam/make.h
Normal file
12
src/tools/jam/make.h
Normal file
@ -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 );
|
647
src/tools/jam/make1.c
Normal file
647
src/tools/jam/make1.c
Normal file
@ -0,0 +1,647 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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 );
|
||||
|
||||
if( DEBUG_MAKE && counts->skipped )
|
||||
printf( "...skipped %d target(s)...\n", counts->skipped );
|
||||
|
||||
if( DEBUG_MAKE && counts->made )
|
||||
printf( "...updated %d target(s)...\n", counts->made );
|
||||
|
||||
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 )
|
||||
{
|
||||
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->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( status == EXEC_CMD_FAIL && ( cmd->rule->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( globs.quitquick ) ++intr;
|
||||
}
|
||||
|
||||
/* If the command was interrupted or failed and the target */
|
||||
/* is not "precious", remove the targets. */
|
||||
/* Precious == 'actions updated' -- the target maintains state. */
|
||||
|
||||
if( status != EXEC_CMD_OK && !( cmd->rule->flags & RULE_UPDATED ) )
|
||||
{
|
||||
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_UPDATED 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;
|
||||
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( !rule->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, rule->flags );
|
||||
|
||||
if( rule->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, rule->flags );
|
||||
a1->action->running = 1;
|
||||
}
|
||||
|
||||
/* If doing only updated (or existing) sources, but none have */
|
||||
/* been updated (or exist), skip this action. */
|
||||
|
||||
if( !ns && ( rule->flags & ( RULE_UPDATED | RULE_EXISTING ) ) )
|
||||
{
|
||||
list_free( nt );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we had 'actions xxx bind vars' we bind the vars now */
|
||||
|
||||
boundvars = make1settings( rule->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( ( rule->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_UPDATED ) && 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 );
|
||||
}
|
124
src/tools/jam/mkjambase.c
Normal file
124
src/tools/jam/mkjambase.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
# include <string.h>
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
96
src/tools/jam/newstr.c
Normal file
96
src/tools/jam/newstr.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 );
|
||||
|
||||
if (DEBUG_MEM)
|
||||
printf("newstr: allocating %d bytes\n", 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 );
|
||||
}
|
14
src/tools/jam/newstr.h
Normal file
14
src/tools/jam/newstr.h
Normal file
@ -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();
|
103
src/tools/jam/option.c
Normal file
103
src/tools/jam/option.c
Normal file
@ -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 <option.h>.
|
||||
* 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;
|
||||
}
|
23
src/tools/jam/option.h
Normal file
23
src/tools/jam/option.h
Normal file
@ -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 );
|
116
src/tools/jam/parse.c
Normal file
116
src/tools/jam/parse.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* 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 )
|
||||
{
|
||||
/* 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(;;)
|
||||
{
|
||||
LOL l;
|
||||
PARSE *p;
|
||||
|
||||
/* $(<) and $(>) empty in outer scope. */
|
||||
|
||||
lol_init( &l );
|
||||
|
||||
/* 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, &l );
|
||||
|
||||
parse_free( p );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
parse_save( PARSE *p )
|
||||
{
|
||||
yypsave = p;
|
||||
}
|
||||
|
||||
PARSE *
|
||||
parse_make(
|
||||
LIST *(*func)( PARSE *p, LOL *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;
|
||||
|
||||
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 );
|
||||
|
||||
free( (char *)p );
|
||||
}
|
41
src/tools/jam/parse.h
Normal file
41
src/tools/jam/parse.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 1993, 2000 Christopher Seiwald.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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, LOL *args );
|
||||
PARSE *left;
|
||||
PARSE *right;
|
||||
PARSE *third;
|
||||
char *string;
|
||||
char *string1;
|
||||
int num;
|
||||
int refs;
|
||||
} ;
|
||||
|
||||
void parse_file( char *f );
|
||||
void parse_save( PARSE *p );
|
||||
|
||||
PARSE * parse_make(
|
||||
LIST *(*func)( PARSE *p, LOL *args ),
|
||||
PARSE *left,
|
||||
PARSE *right,
|
||||
PARSE *third,
|
||||
char *string,
|
||||
char *string1,
|
||||
int num );
|
||||
|
||||
void parse_refer( PARSE *p );
|
||||
void parse_free( PARSE *p );
|
5
src/tools/jam/patchlevel.h
Normal file
5
src/tools/jam/patchlevel.h
Normal file
@ -0,0 +1,5 @@
|
||||
/* Keep JAMVERSYM in sync with VERSION. */
|
||||
/* It can be accessed as $(JAMVERSION) in the Jamfile. */
|
||||
|
||||
#define VERSION "2.4"
|
||||
#define JAMVERSYM "JAMVERSION=2.4"
|
282
src/tools/jam/pathmac.c
Normal file
282
src/tools/jam/pathmac.c
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
# ifdef OS_MAC
|
||||
|
||||
# define DELIM ':'
|
||||
|
||||
/*
|
||||
* pathunix.c - manipulate file names on UNIX, NT, OS2
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
* path_build() - build a filename given dir/base/suffix/member
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*
|
||||
* File_parse() and path_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 path_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.
|
||||
* 01/10/01 (seiwald) - path_parse now strips the trailing : from the
|
||||
* directory name, unless the directory name is all
|
||||
* :'s, so that $(d:P) works.
|
||||
*/
|
||||
|
||||
/*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
*/
|
||||
|
||||
void
|
||||
path_parse(
|
||||
char *file,
|
||||
PATHNAME *f )
|
||||
{
|
||||
char *p, *q;
|
||||
char *end;
|
||||
|
||||
memset( (char *)f, 0, sizeof( *f ) );
|
||||
|
||||
/* Look for <grist> */
|
||||
|
||||
if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
|
||||
{
|
||||
f->f_grist.ptr = file;
|
||||
f->f_grist.len = p - file;
|
||||
file = p + 1;
|
||||
}
|
||||
|
||||
/* Look for dir: */
|
||||
|
||||
if( p = strrchr( file, DELIM ) )
|
||||
{
|
||||
f->f_dir.ptr = file;
|
||||
f->f_dir.len = p - file;
|
||||
file = p + 1;
|
||||
|
||||
/* All :'s? Include last : as part of directory name */
|
||||
|
||||
while( p > f->f_dir.ptr && *--p == DELIM )
|
||||
;
|
||||
|
||||
if( p == f->f_dir.ptr )
|
||||
f->f_dir.len++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* path_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
|
||||
path_build(
|
||||
PATHNAME *f,
|
||||
char *file,
|
||||
int binding )
|
||||
{
|
||||
char *ofile = file;
|
||||
int dflag, rflag, act;
|
||||
|
||||
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] != '<' ) *file++ = '<';
|
||||
memcpy( file, f->f_grist.ptr, f->f_grist.len );
|
||||
file += f->f_grist.len;
|
||||
if( file[-1] != '>' ) *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 */
|
||||
*file++ = DELIM;
|
||||
/* fall through */
|
||||
|
||||
case G_DIR:
|
||||
/* take dir */
|
||||
memcpy( file, f->f_dir.ptr, f->f_dir.len );
|
||||
file += f->f_dir.len;
|
||||
break;
|
||||
|
||||
case G_ROOT:
|
||||
/* take root */
|
||||
memcpy( file, f->f_root.ptr, f->f_root.len );
|
||||
file += f->f_root.len;
|
||||
break;
|
||||
|
||||
case G_CAT:
|
||||
/* prepend root to dir */
|
||||
memcpy( file, f->f_root.ptr, f->f_root.len );
|
||||
file += f->f_root.len;
|
||||
if( file[-1] == DELIM ) --file;
|
||||
memcpy( file, f->f_dir.ptr, f->f_dir.len );
|
||||
file += f->f_dir.len;
|
||||
break;
|
||||
|
||||
case G_DDDD:
|
||||
/* make it ::: (../..) */
|
||||
strcpy( file, ":::" );
|
||||
file += 3;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Put : between dir and file (if none already) */
|
||||
|
||||
if( act != G_MT &&
|
||||
file[-1] != DELIM &&
|
||||
( f->f_base.len || f->f_suffix.len ) )
|
||||
{
|
||||
*file++ = DELIM;
|
||||
}
|
||||
|
||||
if( f->f_base.len )
|
||||
{
|
||||
memcpy( file, f->f_base.ptr, f->f_base.len );
|
||||
file += f->f_base.len;
|
||||
}
|
||||
|
||||
if( f->f_suffix.len )
|
||||
{
|
||||
memcpy( file, f->f_suffix.ptr, f->f_suffix.len );
|
||||
file += f->f_suffix.len;
|
||||
}
|
||||
|
||||
if( f->f_member.len )
|
||||
{
|
||||
*file++ = '(';
|
||||
memcpy( file, f->f_member.ptr, f->f_member.len );
|
||||
file += f->f_member.len;
|
||||
*file++ = ')';
|
||||
}
|
||||
*file = 0;
|
||||
|
||||
if( DEBUG_SEARCH )
|
||||
printf(" -> '%s'\n", ofile);
|
||||
}
|
||||
|
||||
/*
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*/
|
||||
|
||||
void
|
||||
path_parent( PATHNAME *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 */
|
49
src/tools/jam/pathsys.h
Normal file
49
src/tools/jam/pathsys.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pathsys.h - PATHNAME struct
|
||||
*/
|
||||
|
||||
/*
|
||||
* PATHNAME - a name of a file, broken into <grist>dir/base/suffix(member)
|
||||
*
|
||||
* <grist> 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 path_parse(), path_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.
|
||||
*/
|
||||
|
||||
typedef struct _pathname PATHNAME;
|
||||
typedef struct _pathpart PATHPART;
|
||||
|
||||
struct _pathpart {
|
||||
char *ptr;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct _pathname {
|
||||
PATHPART 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 path_build( PATHNAME *f, char *file, int binding );
|
||||
void path_parse( char *file, PATHNAME *f );
|
||||
void path_parent( PATHNAME *f );
|
||||
|
234
src/tools/jam/pathunix.c
Normal file
234
src/tools/jam/pathunix.c
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
# ifdef USE_PATHUNIX
|
||||
|
||||
/*
|
||||
* pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
* path_build() - build a filename given dir/base/suffix/member
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*
|
||||
* File_parse() and path_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 path_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.
|
||||
* 01/13/01 (seiwald) - turn on \ handling on UNIX, on by accident
|
||||
*/
|
||||
|
||||
/*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
*/
|
||||
|
||||
void
|
||||
path_parse(
|
||||
char *file,
|
||||
PATHNAME *f )
|
||||
{
|
||||
char *p, *q;
|
||||
char *end;
|
||||
|
||||
memset( (char *)f, 0, sizeof( *f ) );
|
||||
|
||||
/* Look for <grist> */
|
||||
|
||||
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, '/' );
|
||||
|
||||
# if PATH_DELIM == '\\'
|
||||
/* On NT, look for dir\ as well */
|
||||
{
|
||||
char *p1 = strrchr( file, '\\' );
|
||||
p = p1 > p ? p1 : p;
|
||||
}
|
||||
# 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;
|
||||
|
||||
# if PATH_DELIM == '\\'
|
||||
/* Special case for D:/ - dirname is D:/, not "D:" */
|
||||
|
||||
if( f->f_dir.len == 2 && file[1] == ':' )
|
||||
f->f_dir.len = 3;
|
||||
# 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* path_build() - build a filename given dir/base/suffix/member
|
||||
*/
|
||||
|
||||
void
|
||||
path_build(
|
||||
PATHNAME *f,
|
||||
char *file,
|
||||
int binding )
|
||||
{
|
||||
/* 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] != '<' ) *file++ = '<';
|
||||
memcpy( file, f->f_grist.ptr, f->f_grist.len );
|
||||
file += f->f_grist.len;
|
||||
if( file[-1] != '>' ) *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 */
|
||||
|
||||
{
|
||||
memcpy( file, f->f_root.ptr, f->f_root.len );
|
||||
file += f->f_root.len;
|
||||
*file++ = PATH_DELIM;
|
||||
}
|
||||
|
||||
if( f->f_dir.len )
|
||||
{
|
||||
memcpy( file, f->f_dir.ptr, f->f_dir.len );
|
||||
file += 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 ) )
|
||||
*file++ = PATH_DELIM;
|
||||
}
|
||||
|
||||
if( f->f_base.len )
|
||||
{
|
||||
memcpy( file, f->f_base.ptr, f->f_base.len );
|
||||
file += f->f_base.len;
|
||||
}
|
||||
|
||||
if( f->f_suffix.len )
|
||||
{
|
||||
memcpy( file, f->f_suffix.ptr, f->f_suffix.len );
|
||||
file += f->f_suffix.len;
|
||||
}
|
||||
|
||||
if( f->f_member.len )
|
||||
{
|
||||
*file++ = '(';
|
||||
memcpy( file, f->f_member.ptr, f->f_member.len );
|
||||
file += f->f_member.len;
|
||||
*file++ = ')';
|
||||
}
|
||||
*file = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*/
|
||||
|
||||
void
|
||||
path_parent( PATHNAME *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 */
|
430
src/tools/jam/pathvms.c
Normal file
430
src/tools/jam/pathvms.c
Normal file
@ -0,0 +1,430 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "pathsys.h"
|
||||
|
||||
# ifdef OS_VMS
|
||||
|
||||
# define DEBUG
|
||||
|
||||
/*
|
||||
* pathvms.c - manipulate file names on VMS
|
||||
*
|
||||
* External routines:
|
||||
*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
* path_build() - build a filename given dir/base/suffix/member
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*
|
||||
* File_parse() and path_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
|
||||
*/
|
||||
|
||||
/*
|
||||
* path_parse() - split a file name into dir/base/suffix/member
|
||||
*/
|
||||
|
||||
void
|
||||
path_parse(
|
||||
char *file,
|
||||
PATHNAME *f )
|
||||
{
|
||||
char *p, *q;
|
||||
char *end;
|
||||
|
||||
memset( (char *)f, 0, sizeof( *f ) );
|
||||
|
||||
/* Look for <grist> */
|
||||
|
||||
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 = (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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* path_build() - build a filename given dir/base/suffix/member
|
||||
*/
|
||||
|
||||
void
|
||||
path_build(
|
||||
PATHNAME *f,
|
||||
char *file,
|
||||
int binding )
|
||||
{
|
||||
char *ofile = file;
|
||||
struct dirinf root, dir;
|
||||
int g;
|
||||
|
||||
/* 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] != '<' ) *file++ = '<';
|
||||
memcpy( file, f->f_grist.ptr, f->f_grist.len );
|
||||
file += f->f_grist.len;
|
||||
if( file[-1] != '>' ) *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 */
|
||||
memcpy( file, f->f_dir.ptr, f->f_dir.len );
|
||||
file += f->f_dir.len;
|
||||
break;
|
||||
|
||||
case G_ROOT:
|
||||
/* take root */
|
||||
memcpy( file, f->f_root.ptr, f->f_root.len );
|
||||
file += f->f_root.len;
|
||||
break;
|
||||
|
||||
case G_VAD:
|
||||
/* root's dev + abs directory */
|
||||
memcpy( file, root.dev.ptr, root.dev.len );
|
||||
file += root.dev.len;
|
||||
memcpy( file, dir.dir.ptr, dir.dir.len );
|
||||
file += dir.dir.len;
|
||||
break;
|
||||
|
||||
case G_DRD:
|
||||
case G_DDD:
|
||||
/* root's dev:[dir] + rel directory */
|
||||
memcpy( file, f->f_root.ptr, f->f_root.len );
|
||||
file += f->f_root.len;
|
||||
|
||||
/* sanity checks: root ends with ] */
|
||||
|
||||
if( file[-1] == ']' )
|
||||
--file;
|
||||
|
||||
/* Add . if separating two -'s */
|
||||
|
||||
if( g == G_DDD )
|
||||
*file++ = '.';
|
||||
|
||||
/* skip [ of dir */
|
||||
memcpy( file, dir.dir.ptr + 1, dir.dir.len - 1 );
|
||||
file += dir.dir.len - 1;
|
||||
break;
|
||||
|
||||
case G_VRD:
|
||||
/* root's dev + rel directory made abs */
|
||||
memcpy( file, root.dev.ptr, root.dev.len );
|
||||
file += root.dev.len;
|
||||
*file++ = '[';
|
||||
/* skip [. of rel dir */
|
||||
memcpy( file, dir.dir.ptr + 2, dir.dir.len - 2 );
|
||||
file += dir.dir.len - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
# ifdef DEBUG
|
||||
if( DEBUG_SEARCH && ( root.flags || dir.flags ) )
|
||||
{
|
||||
*file = 0;
|
||||
printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
|
||||
grid[ root.flags ][ dir.flags ], ofile );
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Now do the special :P modifier when no file was present.
|
||||
* (none) (none)
|
||||
* [dir1.dir2] [dir1]
|
||||
* [dir] [000000]
|
||||
* [.dir] []
|
||||
* [] []
|
||||
*/
|
||||
|
||||
if( file[-1] == ']' && f->parent )
|
||||
{
|
||||
while( file-- > ofile )
|
||||
{
|
||||
if( *file == '.' )
|
||||
{
|
||||
*file++ = ']';
|
||||
break;
|
||||
}
|
||||
else if( *file == '-' )
|
||||
{
|
||||
/* handle .- or - */
|
||||
if( file > ofile && file[-1] == '.' )
|
||||
--file;
|
||||
*file++ = ']';
|
||||
break;
|
||||
}
|
||||
else if( *file == '[' )
|
||||
{
|
||||
if( file[1] == ']' )
|
||||
{
|
||||
file += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy( file, "[000000]" );
|
||||
file += 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now copy the file pieces. */
|
||||
|
||||
if( f->f_base.len )
|
||||
{
|
||||
memcpy( file, f->f_base.ptr, f->f_base.len );
|
||||
file += 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 )
|
||||
{
|
||||
memcpy( file, f->f_suffix.ptr, f->f_suffix.len );
|
||||
file += f->f_suffix.len;
|
||||
}
|
||||
else if( binding && f->f_base.len )
|
||||
{
|
||||
*file++ = '.';
|
||||
}
|
||||
|
||||
if( f->f_member.len )
|
||||
{
|
||||
*file++ = '(';
|
||||
memcpy( file, f->f_member.ptr, f->f_member.len );
|
||||
file += f->f_member.len;
|
||||
*file++ = ')';
|
||||
}
|
||||
*file = 0;
|
||||
|
||||
# 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,
|
||||
ofile );
|
||||
# endif
|
||||
}
|
||||
|
||||
/*
|
||||
* path_parent() - make a PATHNAME point to its parent dir
|
||||
*/
|
||||
|
||||
void
|
||||
path_parent( PATHNAME *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 */
|
1317
src/tools/jam/regexp.c
Normal file
1317
src/tools/jam/regexp.c
Normal file
File diff suppressed because it is too large
Load Diff
26
src/tools/jam/regexp.h
Normal file
26
src/tools/jam/regexp.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Definitions etc. for regexp(3) routines.
|
||||
*
|
||||
* Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
|
||||
* not the System V one.
|
||||
*/
|
||||
#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
|
267
src/tools/jam/rules.c
Normal file
267
src/tools/jam/rules.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* 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 *rulehash = 0;
|
||||
static struct hash *targethash = 0;
|
||||
|
||||
|
||||
/*
|
||||
* bindrule() - return pointer to RULE, creating it if necessary
|
||||
*/
|
||||
|
||||
RULE *
|
||||
bindrule( char *rulename )
|
||||
{
|
||||
RULE rule, *r = &rule;
|
||||
|
||||
if( !rulehash )
|
||||
rulehash = hashinit( sizeof( RULE ), "rules" );
|
||||
|
||||
r->name = rulename;
|
||||
|
||||
if( hashenter( rulehash, (HASHDATA **)&r ) )
|
||||
{
|
||||
r->name = newstr( rulename ); /* never freed */
|
||||
r->procedure = (PARSE *)0;
|
||||
r->actions = (char *)0;
|
||||
r->bindlist = L0;
|
||||
r->flags = 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 *)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 );
|
||||
free( (char *)v );
|
||||
|
||||
v = n;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* donerules() - free RULE and TARGET tables
|
||||
*/
|
||||
|
||||
void
|
||||
donerules()
|
||||
{
|
||||
hashdone( rulehash );
|
||||
hashdone( targethash );
|
||||
}
|
172
src/tools/jam/rules.h
Normal file
172
src/tools/jam/rules.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 1993, 1995 Christopher Seiwald.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
struct _rule {
|
||||
char *name;
|
||||
PARSE *procedure; /* parse tree from RULE */
|
||||
char *actions; /* command string from ACTIONS */
|
||||
LIST *bindlist; /* variable to bind for actions */
|
||||
int flags; /* modifiers on ACTIONS */
|
||||
|
||||
# define RULE_UPDATED 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 */
|
||||
|
||||
} ;
|
||||
|
||||
/* 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 */
|
||||
|
||||
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 */
|
||||
|
||||
# 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 );
|
||||
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();
|
393
src/tools/jam/scan.c
Normal file
393
src/tools/jam/scan.c
Normal file
@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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;
|
||||
struct keyword *k;
|
||||
int inquote = 0;
|
||||
int notkeyword;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* While scanning the word, disqualify it for (expensive) */
|
||||
/* keyword lookup when we can: $anything, "anything", \anything */
|
||||
|
||||
notkeyword = c == '$';
|
||||
|
||||
/* look for white space to delimit word */
|
||||
/* "'s get stripped but preserve white space */
|
||||
/* \ protects next character */
|
||||
|
||||
while(
|
||||
c != EOF &&
|
||||
b < buf + sizeof( buf ) &&
|
||||
( inquote || !isspace( c ) ) )
|
||||
{
|
||||
if( c == '"' )
|
||||
{
|
||||
/* begin or end " */
|
||||
inquote = !inquote;
|
||||
notkeyword = 1;
|
||||
}
|
||||
else if( c != '\\' )
|
||||
{
|
||||
/* normal char */
|
||||
*b++ = c;
|
||||
}
|
||||
else if( ( c = yychar()) != EOF )
|
||||
{
|
||||
/* \c */
|
||||
*b++ = c;
|
||||
notkeyword = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* \EOF */
|
||||
break;
|
||||
}
|
||||
|
||||
c = yychar();
|
||||
}
|
||||
|
||||
/* 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 obviously not a keyword or if its */
|
||||
/* an alphabetic when were looking for punctuation */
|
||||
|
||||
*b = 0;
|
||||
yylval.type = ARG;
|
||||
|
||||
if( !notkeyword && !( 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;
|
||||
}
|
52
src/tools/jam/scan.h
Normal file
52
src/tools/jam/scan.h
Normal file
@ -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 */
|
85
src/tools/jam/search.c
Normal file
85
src/tools/jam/search.c
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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 "pathsys.h"
|
||||
# include "variable.h"
|
||||
# include "newstr.h"
|
||||
|
||||
/*
|
||||
* search.c - find a target along $(SEARCH) or $(LOCATE)
|
||||
*/
|
||||
|
||||
char *
|
||||
search(
|
||||
char *target,
|
||||
time_t *time )
|
||||
{
|
||||
PATHNAME f[1];
|
||||
LIST *varlist;
|
||||
char buf[ MAXJPATH ];
|
||||
|
||||
/* Parse the filename */
|
||||
|
||||
path_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 );
|
||||
|
||||
path_build( f, buf, 1 );
|
||||
|
||||
if( DEBUG_SEARCH )
|
||||
printf( "locate %s: %s\n", target, buf );
|
||||
|
||||
timestamp( buf, time );
|
||||
|
||||
return newstr( buf );
|
||||
}
|
||||
else if( varlist = var_get( "SEARCH" ) )
|
||||
{
|
||||
while( varlist )
|
||||
{
|
||||
f->f_root.ptr = varlist->string;
|
||||
f->f_root.len = strlen( varlist->string );
|
||||
|
||||
path_build( f, buf, 1 );
|
||||
|
||||
if( DEBUG_SEARCH )
|
||||
printf( "search %s: %s\n", target, buf );
|
||||
|
||||
timestamp( buf, time );
|
||||
|
||||
if( *time )
|
||||
return newstr( buf );
|
||||
|
||||
varlist = list_next( varlist );
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
path_build( f, buf, 1 );
|
||||
|
||||
if( DEBUG_SEARCH )
|
||||
printf( "search %s: %s\n", target, buf );
|
||||
|
||||
timestamp( buf, time );
|
||||
|
||||
return newstr( buf );
|
||||
}
|
11
src/tools/jam/search.h
Normal file
11
src/tools/jam/search.h
Normal file
@ -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 );
|
203
src/tools/jam/timestamp.c
Normal file
203
src/tools/jam/timestamp.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* This file is part of Jam - see jam.c for Copyright information.
|
||||
*/
|
||||
|
||||
# include "jam.h"
|
||||
# include "hash.h"
|
||||
# include "filesys.h"
|
||||
# include "pathsys.h"
|
||||
# include "timestamp.h"
|
||||
# include "newstr.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( void *, char *, int , time_t );
|
||||
|
||||
static char *time_progress[] =
|
||||
{
|
||||
"INIT",
|
||||
"NOENTRY",
|
||||
"SPOTTED",
|
||||
"MISSING",
|
||||
"FOUND"
|
||||
} ;
|
||||
|
||||
|
||||
/*
|
||||
* timestamp() - return timestamp on a file, if present
|
||||
*/
|
||||
|
||||
void
|
||||
timestamp(
|
||||
char *target,
|
||||
time_t *time )
|
||||
{
|
||||
PATHNAME f1, f2;
|
||||
BINDING binding, *b = &binding;
|
||||
char buf[ MAXJPATH ];
|
||||
|
||||
# ifdef DOWNSHIFT_PATHS
|
||||
char path[ MAXJPATH ];
|
||||
char *p = path;
|
||||
|
||||
do *p++ = tolower( *target );
|
||||
while( *target++ );
|
||||
|
||||
target = path;
|
||||
# endif
|
||||
|
||||
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 */
|
||||
|
||||
path_parse( target, &f1 );
|
||||
|
||||
/* Scan directory if not already done so */
|
||||
|
||||
{
|
||||
BINDING binding, *b = &binding;
|
||||
|
||||
f2 = f1;
|
||||
f2.f_grist.len = 0;
|
||||
path_parent( &f2 );
|
||||
path_build( &f2, buf, 0 );
|
||||
|
||||
b->name = buf;
|
||||
b->time = b->flags = 0;
|
||||
b->progress = BIND_INIT;
|
||||
|
||||
if( hashenter( bindhash, (HASHDATA **)&b ) )
|
||||
b->name = newstr( buf ); /* never freed */
|
||||
|
||||
if( !( b->flags & BIND_SCANNED ) )
|
||||
{
|
||||
file_dirscan( buf, time_enter, bindhash );
|
||||
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;
|
||||
path_build( &f2, buf, 0 );
|
||||
|
||||
b->name = buf;
|
||||
b->time = b->flags = 0;
|
||||
b->progress = BIND_INIT;
|
||||
|
||||
if( hashenter( bindhash, (HASHDATA **)&b ) )
|
||||
b->name = newstr( buf ); /* never freed */
|
||||
|
||||
if( !( b->flags & BIND_SCANNED ) )
|
||||
{
|
||||
file_archscan( buf, time_enter, bindhash );
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
time_enter(
|
||||
void *closure,
|
||||
char *target,
|
||||
int found,
|
||||
time_t time )
|
||||
{
|
||||
BINDING binding, *b = &binding;
|
||||
struct hash *bindhash = (struct hash *)closure;
|
||||
|
||||
# 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 );
|
||||
}
|
12
src/tools/jam/timestamp.h
Normal file
12
src/tools/jam/timestamp.h
Normal file
@ -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();
|
341
src/tools/jam/variable.c
Normal file
341
src/tools/jam/variable.c
Normal file
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
|
||||
*
|
||||
* 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 "newstr.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 )
|
||||
{
|
||||
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
|
||||
char buf[ MAXSYM ];
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
strncpy( buf, pp, p - pp );
|
||||
buf[ p - pp ] = '\0';
|
||||
l = list_new( l, newstr( buf ) );
|
||||
}
|
||||
|
||||
l = list_new( l, newstr( pp ) );
|
||||
|
||||
/* Get name */
|
||||
|
||||
strncpy( buf, *e, val - *e );
|
||||
buf[ val - *e ] = '\0';
|
||||
|
||||
var_set( buf, l, VAR_SET );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 );
|
||||
}
|
25
src/tools/jam/variable.h
Normal file
25
src/tools/jam/variable.h
Normal file
@ -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 */
|
||||
|
89
src/tools/jam/yyacc
Executable file
89
src/tools/jam/yyacc
Executable file
@ -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/</_LANGLE/
|
||||
s/>/_RANGLE/
|
||||
s/\./_PERIOD/
|
||||
s/?/_QUESTION/
|
||||
s/=/_EQUALS/
|
||||
s/,/_COMMA/
|
||||
s/\[/_LBRACKET/
|
||||
s/]/_RBRACKET/
|
||||
s/{/_LBRACE/
|
||||
s/}/_RBRACE/
|
||||
s/(/_LPAREN/
|
||||
s/)/_RPAREN/
|
||||
s/.*/&_t/
|
||||
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
|
Loading…
Reference in New Issue
Block a user