The SubDir rule initializes a set of variables
that are used by Main and other rules to
uniquely identify the source files in this
directory and assign locations to the targets
built from files in this directory.
When you have set a root variable, e.g., $(TOP),
SubDir constructs path names rooted with $(TOP),
e.g., $(TOP)/src/util.
Otherwise, SubDir constructs relative pathnames
to the root directory, computed from the number
of arguments to the first SubDir rule, e.g.,
../../src/util. In either case, the SubDir
rule constructs the path names that locate source
files.
You'll see how this is useful later.
The SubDir rule takes as its first argument the root
variable's name and takes as subsequent arguments the
directory names leading from the root to the directory of
the current Jamfile. Note that the name of the subdirectory
is given as individual elements: the SubDir rule
does not use system-specific directory name syntax.
SubInclude Rule
The SubInclude rule is used in a Jamfile to cause another
Jamfile to be read in.
Its arguments are in the same format as
SubDir's.
The recommended practice is only to include one level of
subdirectories at a time, and let the Jamfile in each subdirectory
include its own subdirectories. This allows a
user to sit in any arbitrary directory of the source tree
and build that subtree. For example:
# This is $(TOP)/Jamfile, top level Jamfile for mondo project.
SubInclude TOP src ;
SubInclude TOP man ;
SubInclude TOP misc ;
SubInclude TOP util ;
If a directory has both subdirectories of its own as well
as files that need building, the SubIncludes should be
either before the SubDir rule or be at the end of the Jamfile
- not between the SubDir and other rule invocations.
For example:
# This is $(TOP)/src/Jamfile:
SubDir TOP src ;
Main mondo : mondo.c ;
LinkLibraries mondo : libmisc libutil ;
SubInclude TOP src misc ;
SubInclude TOP src util ;
(jam processes all the Jamfiles it reads as if
it were reading one single, large Jamfile.
Build rules like Main and LinkLibraries rely on the
preceding SubDir rule to set up source file and
output file locations, and SubIncludes rules read in
Jamfiles that contain SubDir rules. So if you put
a SubIncludes rule between a SubDir and a Main
rule, jam will try to find the source files
for the Main rule in the wrong directory.)
Variables Used to Handle Directory Trees
The following variables are set by the SubDir rule
and used by the Jambase rules that define file targets:
SEARCH_SOURCE
| | The SubDir targets (e.g., "TOP src util")
are used to construct a pathname (e.g., $(TOP)/src/util),
and that pathname is assigned to $(SEARCH_SOURCE).
Rules like Main and Library use $(SEARCH_SOURCE)
to set search paths on source files.
|
LOCATE_SOURCE
| | Initialized by the SubDir rule to the same
value as $(SEARCH_SOURCE), unless ALL_LOCATE_TARGET
is set.
$(LOCATE_SOURCE) is used by rules that build
generated source files (e.g., Yacc and Lex) to
set location of output files.
Thus the default location of built source files
is the directory of the Jamfile that defines them.
|
LOCATE_TARGET
| | Initalized by the SubDir rule to the same
value as $(SEARCH_SOURCE), unless ALL_LOCATE_TARGET
is set.
$(LOCATE_TARGET) is used by rules that build
binary objects (e.g., Main and Library) to
set location of output files.
Thus the default location of built binaray files
is the directory of the Jamfile that defines them.
|
ALL_LOCATE_TARGET
| |
If $(ALL_LOCATE_TARGET) is set, LOCATE_SOURCE
and and LOCATE_TARGET are set to $(ALL_LOCATE_TARGET)
instead of to $(SEARCH_SOURCE). This can be used to
direct built files to be written to a location outside
of the source tree, and enables building from read-only
source trees.
|
SOURCE_GRIST
| | The SubDir targets are formed into a string
like "src!util" and that string is assigned to
SOURCE_GRIST. Rules that define file targets
use $(SOURCE_GRIST) to set the "grist" attribute
on targets. This is used to assure uniqueness
of target identifiers where filenames themselves
are not unique.
For example, the target identifiers of
$(TOP)/src/client/main.c and $(TOP)/src/server/main.c
would be <src!client>main.c and <src!server>main.c.
|
The $(LOCATE_TARGET) and $(SEARCH_SOURCE) variables are used
extensively by rules in Jambase: most rules that generate
targets (like Main, Object, etc.) set $(LOCATE) to
$(LOCATE_TARGET) for the targets they generate, and rules
that use sources (most all of them) set $(SEARCH) to be
$(SEARCH_SOURCE) for the sources they use.
$(LOCATE) and $(SEARCH) are better explained in
The Jam Executable Program
but in brief they tell jam where to create new targets and
where to find existing ones, respectively.
Note that you can reset these variables
after SubDir sets them. For example, this Jamfile builds
a program called gensrc, then runs it to create a source file
called new.c:
SubDir TOP src util ;
Main gensrc : gensrc.c ;
LOCATE_SOURCE = $(NEWSRC) ;
GenFile new.c : gensrc ;
By default, new.c would be written into the
$(TOP)/src/util directory, but resetting LOCATE_SOURCE causes
it to be written to the $(NEWSRC) directory. ($(NEWSRC) is assumed
to have been set elsewhere, e.g., in Jamrules.)
VMS Notes
On VMS, the logical name table is not imported as is the
environment on UNIX. To use the SubDir and related rules,
you must set the value of the variable that names the root
directory. For example:
TOP = USR_DISK:[JONES.SRC] ;
SubInclude TOP util ;
The variable must have a value that looks like a directory
or device. If you choose, you can use a concealed logical.
For example:
TOP = TOP: ;
SubInclude TOP util ;
The : at the end of TOP makes the value of $(TOP) look
like a device name, which jam respects as a directory name
and will use when trying to access files. TOP must then
be defined from DCL:
$ define/job/translation=concealed TOP DK100:[USERS.JONES.SRC.]
Note three things: the concealed translation allows the
logical to be used as a device name; the device name in
the logical (here DK100) cannot itself be concealed logical
(VMS rules, man); and the directory component of the
definition must end in a period (more VMS rules).
Building Executables and Libraries
The rules that build executables and libraries are: Main, Library,
and LinkLibraries.
Main Rule
The Main rule compiles source files and links the resulting
objects into an executable. For example:
Main myprog : main.c util.c ;
This compiles main.c and util.c and links main.o and
util.o into myprog. The object files and resulting
executable are named appropriately for the platform.
Main can also be used to build shared libraries and/or
dynamic link libraries, since those are also linked
objects. E.g.:
Main driver$(SUFSHR) : driver.c ;
Normally, Main uses $(SUFEXE) to determine the suffix on
the filename of the built target. To override it,
you can supply a suffix explicity.
In this case,
$(SUFSHR) is assumed to be the OS-specific shared library
suffix, defined in Jamrules with something
like:
if $(UNIX) { SUFSHR = .so ; }
else if $(NT) { SUFSHR = .dll ; }
Main uses the Objects rule to compile source targets.
Library Rule
The Library rule compiles source files, archives the
resulting object files into a library, and then deletes
the object files. For example:
Library libstring : strcmp.c strcpy.c strlen.c ;
Library libtree : treemake.c treetrav.c ;
This compiles five source files, archives three of the
object files into libstring and the other two into libtree.
Actual library filenames are formed with the $(SUFLIB) suffix.
Once the objects are safely in the libraries, the
objects are deleted.
Library uses the Objects rule to compile source files.
LinkLibraries Rule
To link executables with built libraries, use
the LinkLibraries rule. For example:
Main myprog : main.c util.c ;
LinkLibraries myprog : libstring libtree ;
The LinkLibraries rule does two things: it makes the
libraries dependencies of the executable, so that they get
built first; and it makes the libraries show up on the
command line that links the executable. The ordering of
the lines above is not important, because jam builds targets
in the order that they are needed.
You can put multiple libraries on a single invocation of
the LinkLibraries rule, or you can provide them in multiple
invocations. In both cases, the libraries appear on
the link command line in the order in which they were
encountered. You can also provide multiple executables to
the LinkLibraries rule, if they need the same libraries,
e.g.:
LinkLibraries prog1 prog2 prog3 : libstring libtree ;
Variables Used in Building Executables and Libraries
AR
| | Archive command, used for Library targets.
|
SUFEXE
| * | Suffix on filenames of executables referenced
by Main and LinkLibraries.
|
LINK
| | Link command, used for Main targets.
|
LINKFLAGS
| | Linker flags.
|
LINKLIBS
| | Link libraries that aren't dependencies. (See note
below.)
|
EXEMODE
| * | File permissions on Main targets.
|
MODE
| | Target-specific file permissions on Main targets
(set from $(EXEMODE))
|
RANLIB
| | Name of ranlib program, if any.
|
Variables above marked with "*" are used by the Main,
Library, and LinkLibraries rules. Their values at the
time the rules are invoked are used to set target-specific
variables.
All other variables listed above are globally defined,
and are used in actions that update Main and Library
targets. This means that the global values of those
variables are used, uness target-specific values have
been set.
(For instance, a target-specific MODE value is set by
the Main rule.)
The target-specific values always override
global values.
Note that there are two ways to specify link libraries for
executables:
- Use the LinkLibraries rule
to specify built libraries; i.e., libraries
that are built by Library rules. This assures that
these libraries are built first, and that Main targets are
rebuilt when the libraries are updated.
- Use the LINKLIBS variable to specify external
libraries; e.g., system libraries or third-party libraries.
The LINKLIBS variable must be set to the the actual
link command flag that specifies the libraries.
For example:
#In Jamrules:
if $(UNIX) { X11LINKLIBS = -lXext -lX11 ; }
if $(NT) { X11LINKLIBS = libext.lib libX11.lib ; }
#In Jamfile:
Main xprog : xprog.c ;
LINKLIBS on xprog$(SUFEXE) = $(X11LINKLIBS) ;
LinkLibraries xprog : libxutil ;
Library libxutil : xtop.c xbottom.c xutil.c ;
This example uses the Jam syntax "variable on target" to
set a target-specific variable. In this way, only xprog
will be linked with this special $(X11LINKLIBS),
even if other executables were going to be built
by the same Jamfile. Note that when you set a variable
on a target, you have to specify the target identifer
exactly, which in this case is the suffixed filename of
the executable.
The actual link command line on Unix, for example, would
look something like this:
cc -o xprog xprog.o libxutil.a -lXext -lX11
Compiling
Compiling of source files occurs normally as a byproduct
of the Main or Library rules, which call the rules
described here. These rules may also be called explicitly
if the Main and Library behavior doesn't satisfy your
requirements.
Objects Rule
The Main and Library rules call the Objects rule on source files.
Compiled object files built by
the Objects rule are a dependency of the obj
pseudotarget, so "jam obj" will build object files used in
Main and Library rules.
Target identifiers created by the Objects rule have grist
set to $(SOURCE_GRIST). So given this Jamfile:
SubDir TOP src lock ;
Main locker : lock.c ;
the object file created is lock.o (or lock.obj) and
its target identifier is <src!lock>lock.o
(or <src!lock>lock.obj).
You can also call Objects directly. For example:
Objects a.c b.c c.c ;
This compiles a.c into a.o, b.c into b.o, etc. The object
file suffix is supplied by the Objects rule.
Object Rule
Objects gets its work done by calling the Object rule on
each of the source files.
You could use the Object rule directly.
For example, on Unix, you could use:
Object foo.o : foo.c ;
However, the Object rule does not provide suffixes, and
it does not provide the grist needed to construct target
identifiers if you are using the SubDir* rules.
A portable and robust Jamfile would need to invoke Object thus:
Object <src!util>foo$(SUFOBJ) : <src!util>foo.c ;
which is inelegant and clearly shows why using Objects
is better than using Object.
If there's any advantage to the Object rule, it's
that it doesn't require that the object name bear
any relationship to the source. It is thus possible to
compile the same file into different objects. For example:
Object a.o : foo.c ;
Object b.o : foo.c ;
Object c.o : foo.c ;
This compiles foo.c (three times) into a.o, b.o, and c.o.
Later examples show how this is useful.
The Object rule looks at the suffix of the source file and
calls the appropriate rules to do the actual preprocessing
(if any) and compiling needed to produce the output object file.
The Object rule is
capable of the generating of an object file from any
type of source. For example:
Object grammar$(SUFOBJ) : grammar.y ;
Object scanner$(SUFOBJ) : scanner.l ;
Object fastf$(SUFOBJ) : fastf.f ;
Object util$(SUFOBJ) : util.c ;
An even more elegant way to get the same result is to let the
Objects rule call Object:
Objects grammar.y scanner.l fastf.f util.c ;
In addition to calling the compile rules, Object sets up
a bunch of variables specific to the source and target
files. (See Variables Used in Compiling, below.)
Cc, C++, Yacc, Lex, Fortran, As, etc. Rules
The Object rule calls compile rules specific to the suffix of
the source file. (You can see which suffixes are supported
by looking at the Object rule definition in Jambase.)
Because the extra work done by the
Object rule, it is not always useful to call the compile
rules directly. But the adventurous user might attempt
it. For example:
Yacc grammar.c : grammar.y ;
Lex scan.c : scan.l ;
Cc prog.o : prog.c ;
These examples individually run yacc(1), lex(1), and the C
compiler on their sources.
UserObject Rule
Any files with suffixes not understood by the Object rule
are passed to the UserObject rule. The default definition
of UserObject simply emits a warning that the suffix is
not understood. This Jambase rule definition is intended to be
overridden in Jamrules with one that recognizes the project-specific
source file suffixes. For example:
#In Jamrules:
rule UserObject
{
switch $(>)
{
case *.rc : ResourceCompiler $(<) : $(>) ;
case * : ECHO "unknown suffix on" $(>) ;
}
}
rule ResourceCompiler
{
DEPENDS $(<) : $(>) ;
Clean clean : $(<) ;
}
actions ResourceCompiler
{
rc /fo $(<) $(RCFLAGS) $(>)
}
#In Jamfile:
Library liblock : lockmgr.c ;
if $(NT) { Library liblock : lock.rc ; }
In this example, the UserObject definition in Jamrules
allows *.rc files to be handle as regular Main and Library
sources. The lock.rc file is compiled into lock.obj
by the "rc" command, and lock.obj is archived into a library
with other compiled objects.
LibraryFromObjects Rule
Sometimes the Library rule's straightforward compiling of
source into object modules to be archived isn't flexible
enough. The LibraryFromObjects rule does the archiving
(and deleting) job of the Library rule, but not the compiling.
The user can make use of the Objects or Object
rule for that. For example:
LibraryFromObjects libfoo.a : max.o min.o ;
Object max.o : maxmin.c ;
Object min.o : maxmin.c ;
ObjectCcFlags max.o : -DUSEMAX ;
ObjectCcFlags min.o : -DUSEMIN ;
This Unix-specific example compiles the same source file into
two different
objects, with different compile flags, and archives them.
(The ObjectCcFlags rule is described shortly.)
Unfortunately, the portable and robust implementation of the
above example is not as pleasant to read:
SubDir TOP foo bar ;
LibraryFromObjects libfoo$(SUFLIB) : <foo!bar>max$(SUFOBJ)
<foo!bar>min$(SUFOBJ) ;
Object <foo!bar>min$(SUFOBJ) : <foo!bar>maxmin.c ;
Object <foo!bar>max$(SUFOBJ) : <foo!bar>maxmin.c ;
ObjectCcFlags <foo!bar>min$(SUFOBJ) : -DUSEMIN ;
ObjectCcFlags <foo!bar>max$(SUFOBJ) : -DUSEMAX ;
Note that, among other things, you must supply the library
file suffix when using the LibraryFromObjects rule.
MainFromObjects Rule
Similar to LibraryFromObjects, MainFromObjects does the
linking part of the Main rule, but not the compiling.
MainFromObjects can be used when there are no
objects at all, and everything is to be loaded from
libraries. For example:
MainFromObjects testprog ;
LinkLibraries testprog : libprog ;
Library libprog : main.c util.c ;
On Unix, say, this generates a link command that looks like:
cc -o testprog libprog.a
Linking purely from libraries is something that doesn't
work everywhere: it depends on the symbol "main" being
undefined when the linker encounters the library that contains
the definition of "main".
Variables Used in Compiling
The following variables control the compiling of source
files:
C++
| | The C++ compiler command
|
CC
| | The C compiler command
|
C++FLAGS
CCFLAGS
| | Compile flags, used to
create or update compiled objects
|
SUBDIRC++FLAGS
SUBDIRCCFLAGS
| | Additonal compile flags
for source files in this directory.
|
OPTIM
| | Compiler optimization flag. The Cc and C++
actions use this as well as C++FLAGS or CCFLAGS.
|
HDRS
| | Non-standard header directories; i.e.,
the directories the compiler will not look in
by default and which therefore must be supplied
to the compile command. These directories are
also used by jam to scan for include files.
|
STDHDRS
| | Standard header directories, i.e., the
directories the compiler searches automatically.
These are not passed to the compiler, but they
are used by jam to scan for include files.
|
SUBDIRHDRS
| | Additional paths to add to HDRS for source files
in this directory.
|
LEX
| | The lex(1) command
|
YACC
| | The yacc(1) command
|
The Cc rule sets a target-specific $(CCFLAGS) to the current
value of $(CCFLAGS) and $(SUBDIRCCFLAGS). Similarly
for the C++ rule. The Object rule sets a target-specific
$(HDRS) to the current value of $(HDRS) and $(SUBDDIRHDRS).
$(CC), $(C++), $(CCFLAGS), $(C++FLAGS), $(OPTIM), and
$(HDRS) all affect the compiling of C and C++ files.
$(OPTIM) is separate from $(CCFLAGS) and $(C++FLAGS) so
they can be set independently.
$(HDRS) lists the directories to search for header files,
and it is used in two ways: first, it is passed to the C
compiler (with the flag -I prepended); second, it is used
by HdrRule to locate the header files whose names were
found when scanning source files. $(STDHDRS) lists the
header directories that the C compiler already knows
about. It does not need passing to the C compiler, but is
used by HdrRule.
Note that these variables, if set as target-specific variables,
must be set on the target, not the source file.
The target file in this case is the object file to be generated.
For example:
Library libximage : xtiff.c xjpeg.c xgif.c ;
HDRS on xjpeg$(SUFOBJ) = /usr/local/src/jpeg ;
CCFLAGS on xtiff$(SUFOBJ) = -DHAVE_TIFF ;
This can be done more easily with the rules that follow.
ObjectCcFlags, ObjectC++Flags, ObjectHdrs Rules
$(CCFLAGS), $(C++FLAGS) and $(HDRS) can be set on object file
targets
directly, but there are rules that allow these variables
to be set by referring to the original source file name,
rather than to the derived object file name. ObjectCcFlags
adds object-specific flags to the $(CCFLAGS) variable,
ObjectC++Flags adds object-specific flags to the
$(C++FLAGS) variable, and ObjectHdrs add object-specific
directories to the $(HDRS) variable. For example:
#In Jamrules:
if $(NT) { CCFLAGS_X = /DXVERSION ;
HDRS_X = \\\\SPARKY\\X11\\INCLUDE\\X11 ;
}
#In Jamfile:
Main xviewer : viewer.c ;
ObjectCcFlags viewer.c : $(CCFLAGS_X) ;
ObjectHdrs viewer.c : $(HDRS_X) ;
The ObjectCcFlags and ObjectHdrs rules take .c files
as targets, but actually set $(CCFLAGS) and $(HDRS) values
on the .obj (or .o) files. As a result, the action
that updates the target .obj file uses the target-specific
values of $(CCFLAGS) and $(HDRS).
SubDirCcFlags, SubDirC++Flags, SubDirHdrs Rules
These rules set the values of $(SUBDIRCCFLAGS), $(SUBDIRC++FLAGS)
and $(SUBDIRHDRS), which are used by the Cc,
C++, and Object rules when setting the target-specific
values for $(CCFLAGS), $(C++FLAGS) and $(HDRS). The SubDir
rule clears these variables out, and thus they provide
directory-specific values of $(CCFLAGS), $(C++FLAGS) and
$(HDRS). For example:
#In Jamrules:
GZHDRS = $(TOP)/src/gz/include ;
GZFLAG = -DGZ ;
#In Jamfile:
SubDir TOP src gz utils ;
SubDirHdrs $(GZHDRS) ;
SubDirCcFlags $(GZFLAG) ;
Library libgz : gizmo.c ;
Main gizmo : main.c ;
LinkLibraries gizmo : libgz ;
All .c files in this directory files will be compiled with
$(GZFLAG) as well as the default $(CCFLAG), and the include
paths used on the compile command will be $(GZHDRS) as well
as the default $(HDRS).
Header File Processing
One of the functions of the Object rule is set up
scanning of source
files for (C style) header file inclusions. To do so, it
sets the special variables $(HDRSCAN) and $(HDRRULE)
as target-specific variables on the source file. The
presence of these variables triggers a special mechanism
in jam for scanning a file for header file inclusions and
invoking a rule with the results of the scan. The
$(HDRSCAN) variable is set to an egrep(1) pattern that
matches "#include" statements in C source files, and the
$(HDRRULE) variable is set to the name of the rule that
gets invoked as such:
$(HDRRULE) source-file : included-files ;
This rule is supposed to set up the dependencies between
the source file and the included files. The Object rule
uses HdrRule to do the job. HdrRule itself expects
another variable, $(HDRSEARCH), to be set to the list of
directories where the included files can be found. Object
does this as well, setting $(HDRSEARCH) to $(HDRS) and
$(STDHDRS).
The header file scanning occurs during the "file binding"
phase of jam, which means that the target-specific
variables (for the source file) are in effect. To accomodate
nested includes, one of the HdrRule's jobs is to pass
the target-specific values of $(HDRRULE), $(HDRSCAN), and
$(HDRSEARCH) onto the included files, so that they will be
scanned as well.
HdrRule Rule
Normally, HdrRule is not invoked directly; the Object rule
(called by Main and Library) invokes it.
If there are special dependencies that need to be set,
and which are not set by HdrRule itself, you can define
another rule and let it invoke HdrRule. For example:
#In Jamrules:
rule BuiltHeaders
{
DEPENDS $(>) : mkhdr$(SUFEXE) ;
HdrRule $(<) : $(>) ;
}
#In Jamfile:
Main mkhdr : mkhdr.c ;
Main ugly : ugly.c ;
HDRRULE on ugly.c = BuiltHeaders ;
This example just says that the files included by "ugly.c"
are generated by the program "mkhdr", which can be built
from "mkhdr.c". During the binding phase, jam will
scan ugly.c, and if it finds an include file, ughdr.h,
for example, it will automatically invoke the rule:
BuiltHeaders ugly.c : ughdr.h ;
By calling HdrRule at the end of BuiltHeaders,
all the gadgetry of HdrRule takes effect and it
doesn't need to be duplicated.
Variables Used for Header Scanning
HDRPATTERN
| | Default scan pattern for "include" lines.
|
HDRSCAN
| | Scan pattern to use.
This is a special variable: during binding, if
both HDRSCAN and HDRRULE are set, scanning is activated
on the target being bound.
The HdrRule and Object rules sets this
to $(HDRPATTERN) on their source targets.
|
HDRRULE
| | Name of rule to invoked on files found in header
scan. The HdrRule and Object rules set this to "HdrRule"
on their source targets. This is also a special variable;
it's the only jam variable that can hold the
name of a rule to be invoked.
|
HDRSEARCH
| | Search paths for files found during header scanning.
This is set from $(HDRS) and $(STDHDRS), which are
described in the Compiling section.
jam will search $(HDRSEARCH) directories for
the files found by header scans.
|
The Object rule sets HDRRULE and HDRSCAN specifically for
the source files to be scanned, rather than globally. If
they were set globally, jam would attempt to scan all
files, even library archives and executables, for header
file inclusions. That would be slow and probably not
yield desirable results.
Copying Files
File Rule
The File rule copies one file to another. The target name
needn't be the same as the source name. For
example:
switch $(OS)
{
case NT* : File config.h : confignt.h ;
case * : File config.h : configunix.h ;
}
LOCATE on config.h = $(LOCATE_SOURCE) ;
This creates a config.h file from either confignt.h or
configunix.h, depending on the current build platform.
The File rule does not
use the LOCATE_SOURCE variable set by the
SubDir rule (although it does use SEARCH_SOURCE), which
means you have to set the copied file's output directory
yourself. That's done by setting the special
LOCATE variable on the target, as shown above,
or with the MakeLocate rule described below.
Bulk Rule
The Bulk rule is a shorthand for many invocations of the
File rule when all files are going to the same directory.
For example:
#In Jamrules:
DISTRIB_GROB = d:\\distrib\\grob ;
#In Jamfile:
Bulk $(DISTRIB_GROB) : grobvals.txt grobvars.txt ;
This causes gobvals.txt and grobvars.txt to be copied
into the $(DISTRIB_GROB) directory.
HardLink Rule
The Unix-only HardLink rule makes a hard link (using ln(1)) from the
source to the target, if there isn't one already. For
example:
HardLink config.h : configunix.h ;
Shell Rule
The Shell rule is like the File rule, except that on Unix it makes
sure the first line of the target is "#!/bin/sh" and sets
the permission to make the file executable. For example:
Shell /usr/local/bin/add : add.sh ;
You can also use $(SHELLHEADER) to dictate
what the first line of the copied file will be.
For
example:
Shell /usr/local/bin/add : add.awk ;
SHELLHEADER on /usr/local/bin/add = "#!/bin/awk -f" ;
This installs an awk(1) script.
Variables Used When Copying Files
FILEMODE
| | Default file permissions for copied files
|
SHELLMODE
| | Default file permissions for Shell rule targets
|
MODE
| | File permissions set on files copied by
File, Bulk, and Shell rules.
File and Shell sets a target-specific MODE to the current
value of $(FILEMODE) or $(SHELLMODE), respectively.
|
SHELLHEADER
| | String to write in first line of Shell targets
(default is #!/bin/sh).
|
Installing Files
Jambase provides a set of Install* rules to copy files
into an destination directory and set permissions on them.
On Unix, the install(1) program is used.
If the destination directory does not exist, jam
creates it first.
All files copied with the Install* rules are dependencies
of the install pseudotarget, which means that the
command "jam install" will cause the installed copies to
be updated. Also, "jam uninstall" will cause the installed
copies to be removed.
The Install* rules are:
InstallBin
| Copies file and sets its permission to $(EXEMODE).
You must specify the suffixed executable name. E.g.:
InstallBin $(BINDIR) : thing$(SUFEXE) ;
|
InstallFile
| Copies file and sets its permission to $(FILEMODE). E.g.:
InstallFile $(DESTDIR) : readme.txt ;
|
InstallLib
| Copies file and sets its permission to $(FILEMODE).
You must specify the suffixed library name. E.g.:
InstallLib $(LIBDIR) : libzoo$(SUFLIB) ;
|
InstallMan
| Copies file into the mann
subdirectory of the target directory
and sets its permission to $(FILEMODE). E.g.,
this copies foo.5 into the $(DESTDIR)/man5 directory:
InstallMan $(DESTDIR) : foo.5 ;
|
InstallShell
| Copies file and sets its permission to $(SHELLMODE). E.g.:
InstallShell $(DESTDIR) : startup ;
|
Variables
The following variables control the installation rules:
INSTALL
| | The install program (Unix only)
|
FILEMODE
| | Default file permissions on readable files.
|
EXEMODE
| | Default file permission executable files.
|
SHELLMODE
| | Default file permission on shell script files.
|
MODE
| | Target-specific file permissions
|
The Install rules set a target-specific MODE to the current
value of $(FILEMODE), $(EXEMODE), or $(SHELLMODE),
depending on which Install rule was invoked.
The directory variables are just defined for convenience:
they must be passed as the target to the appropriate
Install rule. The $(INSTALL) and mode variables must be
set (globally) before calling the Install rules in order
to take effect.
Miscellaneous Rules
Clean Rule
The Clean rule defines files to be removed when you run "jam clean".
Any site-specific build rules defined in your Jamrules should invoke
Clean so that outputs can be removed. E.g.,
rule ResourceCompiler
{
DEPENDS $(<) : $(>) ;
Clean clean : $(<) ;
}
Most Jambase rules invoke the Clean rule on their built targets,
so "jam clean" will remove all compiled objects, libraries,
executables, etc.
MakeLocate Rule
MakeLocate is a single convenient rule that creates a directory,
sets LOCATE on a target to that directory, and makes the directory
a dependency of the target. It is used by many Jambase rules,
and can be invoked directly, e.g.:
GenFile data.tbl : hxtract data.h ;
MakeLocate data.tbl : $(TABLEDIR) ;
In this example, the File rule creates data.tbl from data.h.
The MakeLocate causes data.tbl to be written into the $(TABLEDIR)
directory; and if the directory doesn't exist, it is created first.
The MakeLocate rule invokes another Jambase rule, MkDir,
to (recursively) create
directories. MkDir uses the $(MKDIR) variable to determine the
platform-specific command that creates directories.
RmTemps Rule
Some intermediate files are meant to be temporary.
The RmTemps rule can be used to cause
jam to delete them after they are used.
RmTemps must be:
-
the last rule
invoked on the permanent file that uses
the temporary file(s)
-
invoked with the permanent file as the output
target and the temporary file(s) as the input target
-
invoked with the exact target identifiers of
the permanent file and the temporary file(s)
For
example:
SubDir TOP src big ;
GenFile big.y : joinfiles part1.y part2.y part3.y ;
Main bigworld : main.c big.y ;
RmTemps bigworld$(SUFEXE) : <src!big>big.y ;
This causes big.y to be deleted after it has been used to create
the bigworld executable.
The exact target identifier of big.y is <src!big>big.y
(the GenFile and Main rules tack on the grist automatically);
the exact target identifier of the bigworld executable
is bigworld$(SUFEXE).
Back to top.
Copyright 1997, 2000 Perforce Software, Inc.
Comments to info@perforce.com
Last updated: Dec 31, 2000
$Id: //public/jam/src/Jamfile.html#6 $
jam-2.5/Makefile 0100440 0000503 0000454 00000002553 07651415176 012736 0 ustar seiwald team # Makefile for jam
CC = cc
CFLAGS =
EXENAME = ./jam0
TARGET = -o $(EXENAME)
# 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
#EXENAME = .\jam0.exe
# NT (with Microsoft compiler)
# People with DevStudio settings already in shell environment.
#CC = cl /nologo
#CFLAGS = -DNT
#TARGET = /Fejam0
#EXENAME = .\jam0.exe
# 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: $(EXENAME)
$(EXENAME)
$(EXENAME):
$(CC) $(TARGET) $(CFLAGS) $(SOURCES) $(LINKLIBS)
jam-2.5/Porting 0100440 0000503 0000454 00000004146 07651415176 012643 0 ustar seiwald team 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.
jam-2.5/README 0100640 0000503 0000454 00000007755 10111166162 012150 0 ustar seiwald team Jam - make(1) redux
/+\
+\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
\+/
This is Release 2.5 of Jam, 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
MSVCDIR: The Microsoft Compiler 6.0 (for NT)
MSVCNT: The Microsoft Compiler 5.0 (for NT)
MSVC: The Microsoft Compiler 1.5 (for Windows)
Only MSVCNT and MSVCDIR have really been tested and are 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
December, 2002 - release 2.5 rc1
January, 2003 - release 2.5 rc2
April, 2003 - release 2.5 rc3
August, 2004 - release 2.5 (rc3 moniker merely dropped)
Christopher Seiwald
seiwald@perforce.com
jam-2.5/RELNOTES 0100640 0000503 0000454 00000112746 10111167400 012437 0 ustar seiwald team ===============================================================================
===============================================================================
Release notes for Jam 2.5
(aka Jam - make(1) redux)
1. Release info:
Jam 2.5
August 19, 2004
VERSION 2.5
(n.b. Jam 2.5 is merely Jam 2.5rc3 of April 2003 with the rc3
moniker removed.)
2. Compatibility
Jam 2.5 is upward compatible with Jam 2.4
The Jam 2.5 language is a superset of the 2.4 language;
Jamfiles, Jambase, and other rulesets used in 2.4 can be used
with the 2.5 language support.
3. Changes since 2.4.
3.1. Changes to Jam Language
The 'return' statement now actually returns, and there are now
break & continue statements for for & while loops.
3.2. Jambase Changes
MkDir now grists directories with 'dir', so that directory
targets can be distinguished from other targets.
SubDir now allows multiple overlapping roots (top level
directories): the first SubDir of a new root uses the CWD of
jam to set that root; subsquent SubDirs use the current SUBDIR
to set the new root. New FSubDirPath to compute a path (given
SubDir arguments) and SubRules to include another root's
Jamrules. Jamrules only included if present; no error issued
if no Jamrules file.
Using SubDir to include a subpart of an SubDir tree now works.
Previously, you could only include the root of another SubDir
tree. This example includes the ../server/support/Jamfile,
without getting confused as to the current directory:
SubDir ALL src builds ;
SubInclude ALL src server support ;
$(RMDIR) has been defined for NT and defaulted to $(RM)
everwhere else. Not much tested. For Michael Champigny.
GenFile actions (on UNIX) now put . in the PATH for the execution
of the command, so that (at least) when jam builds itself . does
not need to be in the global path. It is the rare case where a
target bound in the current directory can't be used directly,
so we fudge it by setting PATH.
Undocumented support for SUBDIRRULES, user-provided rules
to invoke at the end of the SubDir rule, and SUBDIRRESET,
SUBDIR variables to reset (like SUBDIRC++FLAGS, SUBDIRHDRS, etc)
for each new SubDir.
3.3 'jam' Changes (See Jam.html)
The whole /MR of Jam's name has been dropped. It was intended
to avoid trademark infringement of JYACC's JAM, but as far as
we can tell (a) it wasn't enough to avoid infringement and (b)
the trademark has lapsed anyhow.
If header dependencies cause an object to be recompiled and
the source file is a temporary, the temporary is now
reconstructed. Previously, headers weren't considered when
deciding when to reconstruct a temporary.
-d has been reworked to make it easier to display more useful
tracing information separate from the debugging gunk:
-da - show all actions (formerly -d2)
-dc - show 'causes' for rebuilding (new output)
-dd - show dependencies (new output)
-dm - show make graph (aka -d3)
-dx - show executable text (formerly -d2)
-dd is new, and more display options are anticipated.
-n now implies -dax.
The message "...using xxx..." now only shows up with -da.
Jam.html was extensively updated, in an attempt at lucidity.
3.4. Jam internal code changes
Removed spurious search() in 'on' statement handling, thanks
(again) to Ingo Weinhold.
Fix 'includes' support so that included files aren't treated
as direct dependencies during the command execution phase. If
an included file failed to build, make1() would bypass the
including file. Now make0() appends each child's 'includes'
onto its own 'depends' list, eliminating 'includes'-specific
code in make0() and make1().
Rewrite of the past: updated all jam's source with comments to
reflect changes since about 2.3, very early 2001.
4. Fixed bugs
Fixed the description of the :E modifier in Jam.html.
Setting target-specific variables while under the influence of
the target's target-specific variables caused the _global_ values
to be modified. This happened both during header file scanning
(HdrRule is called when target-specific variables are in effect)
and with the "on target statement" syntax. Now setting
target-specific variables works again. Thanks to Matt Armstrong.
Setting "var on target ?= value" now works as expected: if the
variable is already set on the target, it is left unchanged.
Previously, ?= was ignored and the variable was set anyway.
Thanks to Chris Antos.
Variable expansion in actions has always put an extra blank
space after the last list element, but the expansion is described
in the code as "space separated". Now the last blank is suppressed
to match. From Miklos Fazekas.
The temp file name used by jam for .bat files on NT now contains
jam's pid, so that multiple jams can run on the same system (with
the same $TEMP). Thanks to Steve Anichini.
Several uninitialized memory accesses have been corrected in
var_expand() and file_archscan(), thanks to Matt Armstrong.
5. Porting
The Makefile now uses $(EXENAME) (./jam0 on UNIX, .\jam0.exe
on NT) instead of just "jam0", so that . doesn't need to be in
your PATH to bootstrap.
MACOSX updates: use 'ar' instead of libtool, as libtool can't
update a library and we archive too many things to do it in
one go; add piles of code to file_archscan() to handle new
BSD4.4 style "#1/nnnn" archive entry names, where the real
entry name follows the header and nnnn is the length of the
name.
The jam code underwent a const-ing, to work with compilers
that don't like "" being passed as a non-const char *.
Compiling on solaris w/ sparc now sets OSPLAT to "sparc".
Previously, it suppressed this, assuming (wrongly) that sparc
was the only solaris platform. Thanks to Michael Champigny
.
Jambase no longer announces the compiler it is using on
Windows. It doesn't announce anything else, so why?
Jambase no longer refers to advapi32.lib on NT, as it isn't
needed for linking jam itself and it seems to move from
release to release (of MS Visual Studio).
Makefile/Jambase: BEOS updates from "Ingo Weinhold"
.
The NoCare rule can be used to suppress error messages when
an 'include' file can't be found.
AIX "big" archives are now supported, thanks to suggestions
from Randy Roesler.
MSVCDIR now works as well as MSVCNT for the Microsoft Visual C
compiler directory. It changed names in VC 6.0. Thanks to
Matt Armstrong.
Allow jam to build with BorlandC 5.5
For WinXP IA64; set MSVCNT to the root of the SDK and MSVCVer
to Win64; change handle type to long long (too much to include
windows.h?); bury IA64 in the library path in Jambase.
Mac classic MPW Codewarrior 7 upgrades: minor compiling
issues, new paths in Jambase for libraries and includes, and
separate out GenFile1 that sets PATH for UNIX only, as it
does't work under MPW (or anything other than with sh).
Minor Cray porting: make hashitem()'s key value unsigned so
we're guaranteed no integer overflows.
Remove NT FQuote rule, as, \" is required to pass quotes on
the command line.
Remove temp .bat files created on NT. They used to all have
the same name and get reused, but with 2.5 the names were salted
with the PID and they would litter $TEMP. Now they get removed
after being used.
===============================================================================
===============================================================================
Release notes for Jam 2.4
(aka Jam - make(1) redux)
1. Release info:
Jam 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 ..." 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 .
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 .
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 .
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
.
[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 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 2.3
November 16, 2000
VERSION 2.3
PATCHLEVEL 1
2. Compatibility
Jam 2.3 is upward compatible with Jam 2.2.
The Jam 2.3 language is a superset of the 2.2 language;
Jamfiles, Jambase, and other rulesets used in 2.2 can be used
with the 2.3 language support.
3. Changes since 2.2
3.1. Changes to Jam Language
Rules now can have values, which can expanded into a list with
the new "[ rule args ... ]" syntax. A rule's value is the value
of its last statement, though only the following statements have
values: if (value of the leg chosen), switch (ditto), set (value
of the resulting variable), return (its arguments). Note that
'return' doesn't actually return. This support is EXPERIEMENTAL
and otherwise undocumented. (2.3.1)
Because of the new way lists are processed, if a rule has no
targets a warning message is no longer issued.
NOCARE now applies to targets with sources and/or actions,
rather than just those without.
3.2. Jambase Changes
The HDRPATTERN variable now allows for leading blanks before
the #include, to keep up with ANSI. By john@nanaon-sha.co.jp
(John Belmonte) (2.2.3).
HDRPATTERN has been adjusted to avoid mistaking cases like:
# include /* could be */
MkDir now NOUPDATE's $(DOT), so that there are no dependencies
on the current directory's timestamp. By john@nanaon-sha.co.jp
(John Belmonte).
The old mock functions like makeDirName, which assigned their
results to the variable named as their first argument, have
been replaced with real functions using the new [] syntax.
E.g. "makeDirName foo : bar ola" is now "foo = [ fDirName bar ]"
Install now always does a cp/chmod/etc, rather than using
the system's install(1), which invariably seems broken.
3.3. Jam internal code changes
$JAMUNAME is set on UNIX. (2.2.4).
Jam ANSI-fied (2.3.0).
jam.h now defines a bunch of symbols used by the other source
files, so as minimize compiler- and platform-specific ifdefs.
OSVER is no longer set by jam.h (it was only set for AIX).
Jam does not depend on this variable at all, except to set
$(OSFULL), which is used to determine jam's build directory.
If the user needs to distinguish between various revs of
OSs, he must set OSVER in the environment.
4. Fixed bugs
Redefining a rule while it was executing could cause jam to
crash. Reference counts are now used to prevent that, thanks
to Matt Armstrong.
Logic for computing chunk size when executing PIECEMEAL rules
has been reworked to be a little more accurate, without danger
of overflow, at the cost of being a little more compute intensive.
Instead of computing an estimate chunksize in the (now gone)
make1chunk(), make1cmds() now just goes full bore and tries to
use all args. When that fails, it backs off by 10% of the source
args until the command fits. It takes a little bit more compute
time compared to the old logic, but when you're executing actions
to build all of Shinola it's still pretty small in the scheme
of things.
The NT handle leak in execunix.c has been fixed, thanks to
Gurusamy Sarathy. (2.2.1).
5. Porting
Platforms newly supported or updated:
AmigaOS (with gcc), courtesy of Alain Penders (2.2.2).
Beos
CYGWIN 1.1.4, courtesy of John Belmonte .
IBM AS400 via Visual Age on NT (primitive)
IBM OS/390 Unix System Services
Linux SuSE on OS390
Linux Mips, ARM
Lynx
HPUX 11, IA64
Mac OS X Server, courtesy of Jeff_Sickel@sickel.com (2.2.5).
Mac Rhapsody
MPE IX 6.0
NetBSD
QNX RTP (QNX 6.0)
Siemens Sinix
UNICOS
VMS 6.2, 7.1
Windows NT IA64
5.1. NT Porting Notes
Always create tmp .bat file for actions if JAMSHELL is set.
That way, if JAMSHELL is a .bat file itself, it can handle
single-command actions with more than 9 cmd line args.
COMSPEC is no longer examined: cmd.exe is always used
instead. Only cmd.exe can execute the Jambase rules anyhow.
Jam can be built with Borland C++ 5.5.
OS2 fixes: InstallBin now works. Filenames are now downshifted,
so mixed case works better there, too. file_dirscan() can now scan
the root ("c:\" or "\") directory, which it couldn't handle before.
var_defines now ignores OS=Windows_NT, because it conflicts
with Jam's setting of OS (to NT).
5.2. Mac OS 8/9 Notes
The support for Mac is curious at best. It runs under MPW.
It requires CodeWarrior Pro 5, but no longer requires GUSI.
Use Build.mpw to bootstrap the build.
The Mac specific definitions in the Jambase are not intended
to be of general purpose, but are sufficient to have Jam build
itself.
===============================================================================
===============================================================================
Release Notes for Jam 2.2
1. Release info:
Jam 2.2
October 22, 1997
VERSION 2.2
PATCHLEVEL 1
2. Compatibility
Jam 2.2 is a roll-up of 'Jam - make(1) redux' release 2.1+.
Most of the changes described below were available before this,
in the jam.2.1.plus.tar ball.
The Jam 2.2 language is a superset of the 2.1 language;
Jamfiles, Jambase, and other rulesets used in 2.1 can be used
with the 2.2 language support.
See 'Jambase Changes', below, to see if your Jamfiles need any
changes to work with the 2.2 Jambase.
3. Changes Since 2.1
New product name: Jam. (Executable program is still named 'jam'.)
Documentation rewritten; HTML versions supplied.
3.1 Changes to Jam Language
Rules may now have more fields than just $(<) and $(>).
Local variables are now supported.
The expression 'if $(A) in $(B)' is now supported.
New variable modifiers :U and :L result in uppercased or lowercased
values.
New variable modifier :P reliably results in parent directory
of either a file or directory. (Previously, :D was used, but on VMS
:D of a directory name is just the directory name.)
The :S variable modifier now results in the _last_ suffix if a
filename has more than one dot (.) in it.
New predefined $(JAMDATE) variable is initialized at runtime for
simple date stamping.
New predefined variables $(OSVER) and $(OSPLAT) are used to
distinguish among operating system versions and hardware platforms,
when possible.
New 'bind' qualifier on action definitions allows variables
other than $(<) and $(>) to be bound with SEARCH and LOCATE paths.
Action buffer size is no longer limited by MAXCMD. Instead, each
line in an action is limited by MAXLINE, defined for each OS, and
the entire action size is limited by CMDBUF.
3.2 Jambase Changes (See Jamfile.html)
Jambase has been reworked to incorporate new language features.
A handful of new utility rules has been added: makeString,
makeDirName, etc.
New HDRGRIST variable in Jambase allows for headers with the same
name to be distinguished.
LOCATE_TARGET now has a new flavor, LOCATE_SOURCE, that is used by
rules that generate source files (e.g., Yacc and Lex).
Header file includes now happen in the proper order. The limit of
10 include files has been eliminated.
The old "Install" rule is no longer available. Use InstallBin,
InstallFile, InstallLib, InstallMan, or InstallShell instead.
3.3 'jam' Changes (See Jam.html)
'jam' can now be built as a stand-alone program, with Jambase
compiled into the executable. An external or alternate Jambase can
still be referenced explicitly with -f.
On command failure, 'jam' now emits the text of the command that
failed. This is a compromise between the normal -d1 behavior (where
commands were never seen) and -d2 (where commands are always seen).
'jam' now exits non-zero if it doesn't have a total success. A parse
error, sources that can't be found, and targets that can't be built
all generate non-zero exit status.
The debugging levels (-d flags) have been slightly redefined.
The supplied Jamfile now builds 'jam' into a platform specific
subdirectory. This lets you use the same source directory to
build 'jam' for more than one platform.
The supplied Jamfile does not rebuild generated source files by
default. (They are supplied with the distribution.) See Jamfile
for more information.
4. Fixed Bugs
The 'include' bug has finally been fixed, so that include
statements take effect exactly when they are executed,
rather than after the current statement block. This also
corrects the problem where an 'include' within an 'if'
block would wind up including the file one token after the
'if' block's closing brace. Credit goes to Thomas Woods
for suggesting that the parse tree generation and parse
tree execution be paired in their own loop, rather than
having the parser execute the tree directly.
The setting and extracting of grist has been regularized:
normally, if you set a component of a filename (using the
:DBSMG= modifiers), you are supposed to include the delimiters
that set off the component: that is, you say "$(x:S=.suffix)",
including the ".". But with grist it was inconsistent
between setting and getting: setting grist required no
<>'s, while getting grist included them. Getting grist
continues to return the <>'s, but now setting grist can
either include them (the new way) or not (the old way).
'actions together' now suppresses duplicate sources from
showing up in $(>).
Accessing variables whose names contained ['s (as happens with
MkDir on VMS) wasn't working, because it treated the [ as an
array subscript. Now [ and ] are, like :, handled specially so
that they can appear in variable values.
The 'if' statement now compares all elements in expressions;
previously, it only compared the first element of each list.
If a command line in an action is longer than MAXLINE (formerly
MAXCMD), 'jam' now issues an error and exits rather than dumping
core.
If a Jamfile ended without a trailing newline, jam dumped core.
This has been fixed.
5. Porting
See jam.h for the definitive list of supported platforms.
Since 2.1, support has been added for:
Macintosh MPW
Alpha VMS
Alpha NT
NT PowerPC
BeOS
MVS OE
UNIXWARE
QNX
SINIX (Nixdorf)
OS/2
Interactive UNIX (ISC), courtesy of Matthew Newhook
5.1 NT Support Fixes
The NT command executor now handles multiple line actions, by writing
multi-line actions to a batch file and executing that.
Targets are universally lowercased on NT. (Matthew Newhook)
Concurrent process support is fully enabled for NT.
(Gurusamy Sarathy )
Path handling: Jam now knows that the directory component of "D:\"
is "D:\", just as on unix it knows that the directory component of
"/" is "/". It also now successfully gets the timestamp for "D:\"
or just plain "\".
5.2 VMS Support Fixes
VMS support is much, much better now. The path name manipulation
routines (in pathvms.c) were more or less rewritten, and they now
handle the vagaries of combining directory and file names properly.
Targets are universally lowercased on VMS.
Multi-line command blocks on VMS are now executed in a single system()
call rather than separate ones for each line, so that actions can
be DCL scripts.
===============================================================================
===============================================================================
Release notes for Jam 2.1.
1. Release info:
Jam 2.1
February 1, 1996
VERSION 2.1
PATCHLEVEL 0
2. Porting
Linux is now supported.
FREEBSD is now supported.
SCO ("M_XENIX") now supported.
NCR now supported.
NEXT support from karthy@dannug.dk (Karsten Thygesen)
DECC support from zinser@axp614.gsi.de (Martin P.J. Zinser)
I have changes for OS/2, but no way to test them. Volunteers?
I have VMS multiprocess support, but no way to test it. Volunteers?
2.1. NT Support fixes.
The NT support is considerably more real than it was in 2.0.
Filent.c had its syntax error corrected, it no longer skips the
first entry when scanning directories, and it handles string
tables in archives (for long object file names).
The Jambase was changed a bit to support the various C/C++
compilers on NT, although it has only been thorougly tested
with MSVC20.
You still need to set MSVCNT or BCCROOT to the root of the
the compiler's directory tree, and you'll get an error if you
don't set it (rather than getting a pile of mysterious errors).
2.2. Other porting fixes.
SPLITPATH now set up for UNIX (:), NT (;), VMS (,)
Jambase support for Solaris works better now: the location of
AR is hardwired to /usr/ccs/bin/ar and it knowns "install"
doesn't take -c. Solaris -- how the mighty have fallen.
To handle Linux's wacko yacc, jamgram.h is now included after
scan.h so that YYSTYPE is define.
3. Jambase Changes (see Jamfile.html)
SubDir now computes the root directory for the source tree, if
the variable naming the root directory isn't set in the environment.
It counts the number of directory elements leading from the root
to the current directory (as passed to SubDir) and uses that many
"../"'s to identify the root. This means that to use SubDir you
no longer have to have anything special set in the environment.
InstallFile is now an alias for InstallLib.
'first' is now dependency of all pseudo-targets (all, files,
exe, lib, shell), so that jamming any of these pseudo-targets
also builds any dependencies of 'first'.
The File rule definition in the Jambase was missing an &.
The File rule now calls the Clean rule, so that installed files
get cleaned.
4. Jam changes (see Jam.html)
Variables may now be set on the command line with -svar=value.
Targets marked with NOUPDATE are now immune to the -a (anyhow)
flag. Previously, the MkDir rule would try to recreate directories
that already exist when jam was invoked with -a.
A new variable, $(JAMVERSION), joins the small list of built-in
variables. It it set to the release of jam, currently "2.1".
If an actions fails, jam now deletes the target(s). It won't
delete libraries or other targets that are composites. This is
now consistent with jam's behavior on interrupts (it deletes the
targets).
Jam had a nasty bug when setting multiple variables to the same
value: if the first two variable names were the same, the variable
value got trashed. This also affected "on target" variables if
the first two targets were the same. For example:
FOO on bar.c bar.c foo.c = a b c ;
This would mangle the value of FOO for bar.c and foo.c. This has
been fixed.
Jam would generate bogus numbers when reporting the number of
targets updated after an interrupt. It now is more careful about
counting.
The debugging flag -d has been extended. In addition to supporting
-dx (turn on debugging for all levels up to x) there is also now
-d+x (turn on debugging at only level x). The default output
level is -d1 (-or d2 if -n is given); this can be turned off with
-d0. The debug levels are listed in jam.1 and jam.h.
The parsing debug output now uses indenting to indicate when
one rule invokes another.
===============================================================================
===============================================================================
Release notes for Jam 2.0.
1. Release info:
Jam 2.0
March 10, 1994
VERSION 2.0
PATCHLEVEL 5
2. Porting
Windows/NT is now (crudely) supported, courtesy of Brett Taylor
and Laura Wingerd.
COHERENT/386 is now supported, courtesy of Fred Smith.
Solaris archive string table for long archive names is now
supported, thanks to Mike Matrigali.
3. Compatibility
Jam 2.0 syntax is a superset of Jam 1.0 syntax, and thus it can
interpret a Jam 1.0 Jambase.
The Jam 2.0 Jambase is a superset of the Jam 1.0 Jambase, and
thus it can include a Jamfile written for Jam 1.0.
4. Changes from Jam 1.0 to Jam 2.0
4.1. Documentation changes
New Jamfile.5 manual page, with lots of examples and easy
reading. It replaces both the old "Examples" file as well as
the old Jambase.5 manual page.
jam.1 edited by Stephen W. Liddle and Diane Holt.
4.2. Jambase Changes (see Jamfile.5)
4.2.1. New rules:
There are new rules to make handling subdirectories easier:
SubDir, SubInclude, SubDirCcFlags, SubDirHdrs.
There are new rules to handle file-specific CCFLAGS and HDRS:
ObjectCcFlags and ObjectHdrs.
Misc new rules: HardLink, InstallShell, MkDir.
New rule "clean" that deletes exactly what jam has built, and
"uninstall" that deletes exactly what was installed.
New rules for handling suffixes .s, .f, .cc, .cpp, .C.
4.2.2. Old rules:
The InstallBin, Lib, Man, and the new Shell rules now take the
destination directory as the target and the files to be copied
as sources. These rules formerly took the files to be copied
as targets, and used built-in destination directories of
$(BINDIR), $(LIBDIR), $(MANDIR), and $(BINDIR).
The InstallBin, Lib, Man, and Shell rules use the install(1)
program now, instead of doing their own copying.
The Cc rule now uses -o when possible, rather than moving the
result. Some platforms (Pyramid?) have a broken -o.
Jambase rules taking libraries, objects, and executables now
all ignore the suffixes provided and use the one defined in the
Jambase for the platform.
Stupid yyacc support moved out of Jambase, as jam is its only
likely user.
Jambase now purturbs library sources with a "grist" of
SOURCE_GRIST.
4.2.3. Misc:
The names of the default rules defined in Jambase have been
lowercased and un-abbreviated, to be more imake(1) like.
The Jambase has been reorganized and sorted, with VMS and NT
support moved in from their own files.
The Jambase has been relocated on UNIX from /usr/local/lib/jam
to /usr/local/lib.
4.3. Jam changes (see jam.1)
4.3.1. Flags:
New -a (anyhow) flag: means build everything.
New -j flag: run jobs in parallel.
Old -t now rebuilds the touched target, rather that just the
target's parents.
-n now implies -d2, so that you see what's happening. The
debug level can be subsequently overridden.
New -v to dump version.
4.3.2. Rules:
New ALWAYS rule behaves like -t: always builds target.
New EXIT rule makes it possible to raise a fatal error.
New LEAVES rule which say target depends only on the update
times of the leaf sources.
New NOUPDATE rule says built targets only if they don't exist.
NOTIME has been renamed NOTFILE, to more accurately reflect its
meaning (it says a target is not to be bound to a file).
4.3.3. Variables:
New special variable JAMSHELL: argv template for command execution
shell.
Variables, both normal and target-specific, can have their
value appended with the syntax "var += value" or "var on target
+= value".
"?=" is now synonymous with "default =".
Imported enviroment variable values are now split at blanks
(:'s if the variable name ends in PATH), so that they become
proper list values.
4.3.4. Misc:
Files to be sourced with "include" are now bound first, so
$(SEARCH) and $(LOCATE) affect them. They still can't be
built, though.
New modifier on "actions": "existing" causes $(>) to expand
only those files that currently exist.
4.3.5. Bug fixes:
When scanning tokens known to be argument lists (such as the
arguments to rule invocations and variable assignment), the
parser now tells the scanner to ignore alphabetic keywords, as
all such lists terminate with punctuation keywords (like : or
;). This way, alphabetic keywords don't need to be quoted when
they appear as arguments.
The scanner has been fixed to handle oversized tokens,
unterminated quotes, unterminated action blocks, and tokens
abutting EOF (i.e. a token with no white space before EOF).
The progress report "...on xth target..." used to count all
targets, rather than just those with updating actions. Since
the original pronouncement of targets to be udpated included
only those with updating actions, the progress report has been
changed to match.
'If' conditionals now must be single arguments. Previously,
they could be zero or more arguments, which didn't make much
sense, and made things like 'foo == bar' true. The comparison
operator is '=', and '==' just looked like the second of three
arguments in the unary "non-empty argument list" conditional.
Header files indirectly including themselves were mistakenly
reported as being dependent on themselves. Recursing through
header file dependencies is now done after determining the fate
of the target.
The variable expansion support was expanding $(X)$(UNDEF) as if
it were $(X). It now expands to an empty list, like it
should.
The UNIX version of file_build() didn't handle "dir/.suffix"
right. Now it does.
The VMS command buffer was assumed to be as large as 1024 bytes,
which isn't the case everywhere as it is related to some weird
quota. It has been lowered to 256.
$(>) and $(<) wouldn't expand in action blocks if the targets
were marked with NOTIME. Now they expand properly.
Malloc() return values are now checked.
The variable expansion routine var_expand() is now a little
faster, by taking a few often needed shortcuts.
The VMS version of file_build() used the wrong length when
re-rooting file names that already had directory compoents.
This was fixed.
Various tracing adjustments were made.
5. Limitations/Known Bugs
The new Windows/NT support has only been marginally tested. It
is dependent on certain variables being set depending on which
compiler you are using. You'll need to look in the file
Jambase and see what variables are expected to be set.
The VMS support has been tested, courtesy of the DEC guest
machine, but has not been hammered fully in release 2.0. It
was used quite a bit in Jam 1.0.
Jam clean when there is nothing to clean claims it is updating
a target.
Because the include statement works by pushing a new file in
the input stream of the scanner rather than recursively
invoking the parser on the new file, multiple include
statements in a rule's procedure causes the files to be
included in reverse order.
If the include statement appears inside an if block, the
parser's attempt to find the else will cause the text of the
included file to appear after the first token following the
statement block. This is rarely what is intended.
In a rule's actions, only $(<) and $(>) refer to the bound file
names: all other variable references get the unbound names.
This is a pain for $(NEEDLIBS), because it means that library
path can't be bound using $(SEARCH) and $(LOCATE).
With the -j flag, errors from failed commands can get
staggeringly mixed up. Also, because targets tend to get built
in a quickest-first ordering, dependency information must be
quite exact. Finally, beware of parallelizing commands that
drop fixed-named files into the current directory, like yacc(1)
does.
A poorly set $(JAMSHELL) is likely to result in silent
failure.
jam-2.5/builtins.c 0100440 0000503 0000454 00000016035 07651415176 013273 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/08/01 (seiwald) - new 'Glob' (file expansion) builtin
* 03/02/02 (seiwald) - new 'Match' (regexp match) builtin
* 04/03/02 (seiwald) - Glob matches only filename, not directory
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 10/22/02 (seiwald) - working return/break/continue statements
* 11/04/02 (seiwald) - const-ing for string literals
* 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
* 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET
*/
# 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"
/*
* compile_builtin() - define builtin rules
*/
# define P0 (PARSE *)0
# define C0 (char *)0
LIST *builtin_depends( PARSE *parse, LOL *args, int *jmp );
LIST *builtin_echo( PARSE *parse, LOL *args, int *jmp );
LIST *builtin_exit( PARSE *parse, LOL *args, int *jmp );
LIST *builtin_flags( PARSE *parse, LOL *args, int *jmp );
LIST *builtin_glob( PARSE *parse, LOL *args, int *jmp );
LIST *builtin_match( PARSE *parse, LOL *args, int *jmp );
int glob( const char *s, const 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, 0 );
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, 1 );
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,
int *jmp )
{
LIST *targets = lol_get( args, 0 );
LIST *sources = lol_get( args, 1 );
LIST *l;
for( l = targets; l; l = list_next( l ) )
{
TARGET *t = bindtarget( l->string );
/* If doing INCLUDES, switch to the TARGET's include */
/* TARGET, creating it if needed. The internal include */
/* TARGET shares the name of its parent. */
if( parse->num )
{
if( !t->includes )
t->includes = copytarget( t );
t = t->includes;
}
t->depends = targetlist( t->depends, 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,
int *jmp )
{
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,
int *jmp )
{
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,
int *jmp )
{
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,
const 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, file, 0 );
break;
}
}
LIST *
builtin_glob(
PARSE *parse,
LOL *args,
int *jmp )
{
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,
int *jmp )
{
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, buf, 0 );
}
}
free( (char *)re );
}
return result;
}
jam-2.5/builtins.h 0100440 0000503 0000454 00000000422 07651415176 013271 0 ustar seiwald team /*
* 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
*
* 01/10/01 (seiwald) - split from compile.h
*/
void load_builtins();
jam-2.5/command.c 0100440 0000503 0000454 00000002157 07651415176 013060 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* command.c - maintain lists of commands
*
* 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
* 09/08/00 (seiwald) - bulletproof PIECEMEAL size computation
*/
# 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,
int maxline )
{
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 );
}
jam-2.5/command.h 0100440 0000503 0000454 00000003172 07651415176 013063 0 ustar seiwald team /*
* 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) */
int maxline ); /* max line length */
void cmd_free( CMD *cmd );
# define cmd_next( c ) ((c)->next)
jam-2.5/compile.c 0100440 0000503 0000454 00000047273 07651415176 013102 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* compile.c - compile parsed jam statements
*
* External routines:
*
* compile_append() - append list results of two statements
* compile_break() - compile 'break/continue/return' rule
* 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.
* 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
* 09/07/00 (seiwald) - stop crashing when a rule redefines itself
* 09/11/00 (seiwald) - new evaluate_rule() for headers().
* 09/11/00 (seiwald) - rules now return values, accessed via [ rule arg ... ]
* 09/12/00 (seiwald) - don't complain about rules invoked without targets
* 01/13/01 (seiwald) - fix case where rule is defined within another
* 01/10/01 (seiwald) - built-ins split out to builtin.c.
* 01/11/01 (seiwald) - optimize compile_rules() for tail recursion
* 01/21/01 (seiwald) - replace evaluate_if() with compile_eval()
* 01/24/01 (seiwald) - 'while' statement
* 03/23/01 (seiwald) - "[ on target rule ]" support
* 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
* 03/02/02 (seiwald) - rules can be invoked via variable names
* 03/12/02 (seiwald) - &&,&,||,|,in now short-circuit again
* 03/25/02 (seiwald) - if ( "" a b ) one again returns true
* 06/21/02 (seiwald) - support for named parameters
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 10/22/02 (seiwald) - working return/break/continue statements
* 11/04/02 (seiwald) - const-ing for string literals
* 11/18/02 (seiwald) - remove bogus search() in 'on' statement.
* 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
*/
# 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"
static const char *set_names[] = { "=", "+=", "?=" };
static void debug_compile( int which, const char *s );
int glob( const char *s, const 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,
int *jmp )
{
/* Append right to left. */
return list_append(
(*parse->left->func)( parse->left, args, jmp ),
(*parse->right->func)( parse->right, args, jmp ) );
}
/*
* compile_break() - compile 'break/continue/return' rule
*
* parse->left results
* parse->num JMP_BREAK/CONTINUE/RETURN
*/
LIST *
compile_break(
PARSE *parse,
LOL *args,
int *jmp )
{
LIST *lv = (*parse->left->func)( parse->left, args, jmp );
*jmp = parse->num;
return lv;
}
/*
* 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 ) )
{
const char *st = t ? t->string : "";
const 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,
int *jmp )
{
LIST *ll, *lr, *s, *t;
int status = 0;
/* Short circuit lr eval for &&, ||, and 'in' */
ll = (*parse->left->func)( parse->left, args, jmp );
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, jmp );
}
/* 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, "1", 0 );
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 *p,
LOL *args,
int *jmp )
{
LIST *nv = (*p->left->func)( p->left, args, jmp );
LIST *result = 0;
LIST *l;
/* for each value for var */
for( l = nv; l && *jmp == JMP_NONE; l = list_next( l ) )
{
/* Reset $(p->string) for each val. */
var_set( p->string, list_new( L0, l->string, 1 ), VAR_SET );
/* Keep only last result. */
list_free( result );
result = (*p->right->func)( p->right, args, jmp );
/* continue loop? */
if( *jmp == JMP_CONTINUE )
*jmp = JMP_NONE;
}
/* Here by break/continue? */
if( *jmp == JMP_BREAK || *jmp == JMP_CONTINUE )
*jmp = JMP_NONE;
list_free( nv );
/* Returns result of last loop */
return result;
}
/*
* compile_if() - compile 'if' rule
*
* parse->left condition tree
* parse->right then tree
* parse->third else tree
*/
LIST *
compile_if(
PARSE *p,
LOL *args,
int *jmp )
{
LIST *l = (*p->left->func)( p->left, args, jmp );
p = l ? p->right : p->third;
list_free( l );
return (*p->func)( p, args, jmp );
}
/*
* 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,
int *jmp )
{
LIST *nt = (*parse->left->func)( parse->left, args, jmp );
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(). */
/* Needn't copysettings(), as search sets no vars. */
pushsettings( t->settings );
t->boundname = search( t->name, &t->time );
popsettings( t->settings );
/* Don't parse missing file if NOCARE set */
if( t->time || !( t->flags & T_FLAG_NOCARE ) )
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,
int *jmp )
{
/* voodoo 1 means: s is a copyable string */
const 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,
int *jmp )
{
LIST *l;
SETTINGS *s = 0;
LIST *nt = (*parse->left->func)( parse->left, args, jmp );
LIST *ns = (*parse->right->func)( parse->right, args, jmp );
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, jmp );
popsettings( s );
freesettings( s );
return result;
}
/*
* compile_null() - do nothing -- a stub for parsing
*/
LIST *
compile_null(
PARSE *parse,
LOL *args,
int *jmp )
{
return L0;
}
/*
* compile_on() - run rule under influence of on-target variables
*
* parse->left target list; only first used
* parse->right rule to run
*/
LIST *
compile_on(
PARSE *parse,
LOL *args,
int *jmp )
{
LIST *nt = (*parse->left->func)( parse->left, args, jmp );
LIST *result = 0;
if( DEBUG_COMPILE )
{
debug_compile( 0, "on" );
list_print( nt );
printf( "\n" );
}
/*
* Copy settings, so that 'on target var on target = val'
* doesn't set var globally.
*/
if( nt )
{
TARGET *t = bindtarget( nt->string );
SETTINGS *s = copysettings( t->settings );
pushsettings( s );
result = (*parse->right->func)( parse->right, args, jmp );
popsettings( s );
freesettings( s );
}
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,
int *jmp )
{
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, jmp );
/* 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, jmp ) );
/* 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(
const 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 */
if( rule->procedure )
{
PARSE *parse = rule->procedure;
SETTINGS *s = 0;
int jmp = JMP_NONE;
LIST *l;
int i;
/* build parameters as local vars */
for( l = rule->params, i = 0; l; l = l->next, i++ )
s = addsettings( s, 0, l->string,
list_copy( L0, lol_get( args, i ) ) );
/* Run rule. */
/* Bring in local params. */
/* refer/free to ensure rule not freed during use. */
parse_refer( parse );
pushsettings( s );
result = list_append( result, (*parse->func)( parse, args, &jmp ) );
popsettings( s );
freesettings( s );
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,
int *jmp )
{
/* Ignore result from first statement; return the 2nd. */
/* Optimize recursion on the right by looping. */
LIST *result = 0;
while( *jmp == JMP_NONE && parse->func == compile_rules )
{
list_free( result );
result = (*parse->left->func)( parse->left, args, jmp );
parse = parse->right;
}
if( *jmp == JMP_NONE )
{
list_free( result );
result = (*parse->func)( parse, args, jmp );
}
return result;
}
/*
* compile_set() - compile the "set variable" statement
*
* parse->left variable names
* parse->right variable values
* parse->num VAR_SET/APPEND/DEFAULT
*/
LIST *
compile_set(
PARSE *parse,
LOL *args,
int *jmp )
{
LIST *nt = (*parse->left->func)( parse->left, args, jmp );
LIST *ns = (*parse->right->func)( parse->right, args, jmp );
LIST *l;
if( DEBUG_COMPILE )
{
debug_compile( 0, "set" );
list_print( nt );
printf( " %s ", set_names[ parse->num ] );
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 ), parse->num );
list_free( nt );
return ns;
}
/*
* compile_setcomp() - support for `rule` - save parse tree
*
* parse->string rule name
* parse->left list of argument names
* parse->right rules for rule
*/
LIST *
compile_setcomp(
PARSE *parse,
LOL *args,
int *jmp )
{
RULE *rule = bindrule( parse->string );
LIST *params = 0;
PARSE *p;
/* Build param list */
for( p = parse->left; p; p = p->left )
params = list_new( params, p->string, 1 );
if( DEBUG_COMPILE )
{
debug_compile( 0, "rule" );
printf( "%s ", parse->string );
list_print( params );
printf( "\n" );
}
/* Free old one, if present */
if( rule->procedure )
parse_free( rule->procedure );
if( rule->params )
list_free( rule->params );
rule->procedure = parse->right;
rule->params = params;
/* we now own this parse tree */
/* don't let parse_free() release it */
parse_refer( parse->right );
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,
int *jmp )
{
RULE *rule = bindrule( parse->string );
LIST *bindlist = (*parse->left->func)( parse->left, args, jmp );
/* 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 VAR_SET/APPEND/DEFAULT
*/
LIST *
compile_settings(
PARSE *parse,
LOL *args,
int *jmp )
{
LIST *nt = (*parse->left->func)( parse->left, args, jmp );
LIST *ns = (*parse->third->func)( parse->third, args, jmp );
LIST *targets = (*parse->right->func)( parse->right, args, jmp );
LIST *ts;
if( DEBUG_COMPILE )
{
debug_compile( 0, "set" );
list_print( nt );
printf( "on " );
list_print( targets );
printf( " %s ", set_names[ parse->num ] );
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, parse->num,
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,
int *jmp )
{
LIST *nt = (*parse->left->func)( parse->left, args, jmp );
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, jmp );
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,
int *jmp )
{
LIST *result = 0;
LIST *l;
/* Returns the value from the last execution of the block */
while( ( *jmp == JMP_NONE ) &&
( l = (*p->left->func)( p->left, args, jmp ) ) )
{
/* Always toss while's expression */
list_free( l );
/* Keep only last result. */
list_free( result );
result = (*p->right->func)( p->right, args, jmp );
/* continue loop? */
if( *jmp == JMP_CONTINUE )
*jmp = JMP_NONE;
}
/* Here by break/continue? */
if( *jmp == JMP_BREAK || *jmp == JMP_CONTINUE )
*jmp = JMP_NONE;
/* Returns result of last loop */
return result;
}
/*
* debug_compile() - printf with indent to show rule expansion.
*/
static void
debug_compile( int which, const 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;
}
jam-2.5/compile.h 0100440 0000503 0000454 00000004476 07651415176 013105 0 ustar seiwald team /*
* 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
*
* 01/22/01 (seiwald) - replace evaluate_if() with compile_eval()
* 01/24/01 (seiwald) - 'while' statement
* 03/02/02 (seiwald) - rules can be invoked via variable names
* 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
* 10/22/02 (seiwald) - working return/break/continue statements
* 11/04/02 (seiwald) - const-ing for string literals
*/
void compile_builtins();
LIST *compile_append( PARSE *parse, LOL *args, int *jmp );
LIST *compile_break( PARSE *parse, LOL *args, int *jmp );
LIST *compile_foreach( PARSE *parse, LOL *args, int *jmp );
LIST *compile_if( PARSE *parse, LOL *args, int *jmp );
LIST *compile_eval( PARSE *parse, LOL *args, int *jmp );
LIST *compile_include( PARSE *parse, LOL *args, int *jmp );
LIST *compile_list( PARSE *parse, LOL *args, int *jmp );
LIST *compile_local( PARSE *parse, LOL *args, int *jmp );
LIST *compile_null( PARSE *parse, LOL *args, int *jmp );
LIST *compile_on( PARSE *parse, LOL *args, int *jmp );
LIST *compile_rule( PARSE *parse, LOL *args, int *jmp );
LIST *compile_rules( PARSE *parse, LOL *args, int *jmp );
LIST *compile_set( PARSE *parse, LOL *args, int *jmp );
LIST *compile_setcomp( PARSE *parse, LOL *args, int *jmp );
LIST *compile_setexec( PARSE *parse, LOL *args, int *jmp );
LIST *compile_settings( PARSE *parse, LOL *args, int *jmp );
LIST *compile_switch( PARSE *parse, LOL *args, int *jmp );
LIST *compile_while( PARSE *parse, LOL *args, int *jmp );
LIST *evaluate_rule( const char *rulename, LOL *args, LIST *result );
/* 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 */
/* Flags for compile_return */
# define JMP_NONE 0 /* flow continues */
# define JMP_BREAK 1 /* break out of loop */
# define JMP_CONTINUE 2 /* step to end of loop */
# define JMP_RETURN 3 /* return from rule */
jam-2.5/execcmd.h 0100440 0000503 0000454 00000000645 07651415176 013057 0 ustar seiwald team /*
* 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
jam-2.5/execmac.c 0100440 0000503 0000454 00000002737 07651415176 013053 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
*/
# include "jam.h"
# include "lists.h"
# include "execcmd.h"
# include
# ifdef OS_MAC
/*
* 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 */
jam-2.5/execunix.c 0100440 0000503 0000454 00000017437 07651415176 013301 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
* 11/04/02 (seiwald) - const-ing for string literals
* 12/27/02 (seiwald) - grist .bat file with pid for system uniqueness
*/
# include "jam.h"
# include "lists.h"
# include "execcmd.h"
# include
# ifdef USE_EXECUNIX
# ifdef OS_OS2
# define USE_EXECNT
# include
# endif
# ifdef OS_NT
# define USE_EXECNT
# include
# define WIN32_LEAN_AND_MEAN
# include /* do the ugly deed */
# define USE_MYWAIT
# if !defined( __BORLANDC__ )
# define wait my_wait
static int my_wait( int *status );
# endif
# endif
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;
const 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";
/* +32 is room for \jamXXXXXtSS.bat (at least) */
cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 32 );
sprintf( cmdtab[ slot ].tempfile, "%s\\jam%dt%d.bat",
tempdir, GetCurrentProcessId(), 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
# ifdef NO_VFORK
if ((pid = fork()) == 0)
{
execvp( argv[0], argv );
_exit(127);
}
# else
if ((pid = vfork()) == 0)
{
execvp( argv[0], argv );
_exit(127);
}
# endif
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 );
}
# ifdef USE_EXECNT
/* Clear the temp file */
unlink( cmdtab[ i ].tempfile );
# endif
/* 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;
}
# ifdef USE_MYWAIT
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 /* USE_MYWAIT */
# endif /* USE_EXECUNIX */
jam-2.5/execvms.c 0100440 0000503 0000454 00000006477 07651415176 013125 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
*/
# include "jam.h"
# include "lists.h"
# include "execcmd.h"
# ifdef OS_VMS
#include
#include
#include
#include
#include
#include
#include
#include
#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 */
jam-2.5/expand.c 0100440 0000503 0000454 00000030707 07651415176 012723 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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/20/00 (seiwald) - Upgraded from K&R to ANSI C
* 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval
* 01/13/01 (seiwald) - :UDJE work on non-filename strings
* 02/19/01 (seiwald) - make $($(var):J=x) join multiple values of var
* 01/25/02 (seiwald) - fixed broken $(v[1-]), by ian godin
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 11/04/02 (seiwald) - const-ing for string literals
* 12/30/02 (armstrong) - fix out-of-bounds access in var_expand()
*/
# include "jam.h"
# include "lists.h"
# include "variable.h"
# include "expand.h"
# include "pathsys.h"
# include "newstr.h"
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( const char *mods, VAR_EDITS *edits );
static void var_edit_file( const 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,
const char *in,
const char *end,
LOL *lol,
int cancopyin )
{
char out_buf[ MAXSYM ];
char *out = out_buf;
const 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( end - in == 4 && in[0] == '$' && in[1] == '(' && in[3] == ')' )
{
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, inp, 1 );
else
return list_new( l, out_buf, 0 );
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, edits.empty.ptr, 0 );
/* 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, out_buf, 0 );
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, out_buf, 0 );
}
}
/* 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
* 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(
const 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(
const 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 );
}
}
jam-2.5/expand.h 0100440 0000503 0000454 00000000523 07651415176 012721 0 ustar seiwald team /*
* 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
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
LIST *var_expand(
LIST *l,
const char *in,
const char *end,
LOL *lol,
int cancopyin );
jam-2.5/filemac.c 0100440 0000503 0000454 00000007116 07651415176 013042 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/21/00 (malyn) - divorced from GUSI
* 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "filesys.h"
# include "pathsys.h"
# ifdef OS_MAC
#include
#include
# include <:sys:stat.h>
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(
const 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(
const 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(
const char *archive,
scanback func,
void *closure )
{
}
# endif /* macintosh */
jam-2.5/filent.c 0100440 0000503 0000454 00000013761 07651415176 012726 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
* 10/03/00 (anton) - Porting for Borland C++ 5.5
* 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
* 11/04/02 (seiwald) - const-ing for string literals
* 01/23/03 (seiwald) - long long handles for NT IA64
*/
# include "jam.h"
# include "filesys.h"
# include "pathsys.h"
# ifdef OS_NT
# ifdef __BORLANDC__
# if __BORLANDC__ < 0x550
# include
# include
# endif
# undef PATHNAME /* cpp namespace collision */
# define _finddata_t ffblk
# endif
# include
# include
/*
* file_dirscan() - scan a directory for files
*/
# ifdef _M_IA64
# define FINDTYPE long long
# else
# define FINDTYPE long
# endif
void
file_dirscan(
const char *dir,
scanback func,
void *closure )
{
PATHNAME f;
char filespec[ MAXJPATH ];
char filename[ MAXJPATH ];
FINDTYPE 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 == (FINDTYPE)(-1) ) )
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(
const char *filename,
time_t *time )
{
/* On NT this is called only for C:/ */
struct stat statbuf;
if( stat( filename, &statbuf ) < 0 )
return -1;
*time = statbuf.st_mtime;
return 0;
}
/*
* file_archscan() - scan an archive for files
*/
/* Straight from SunOS */
#define ARMAG "!\n"
#define SARMAG 8
#define ARFMAG "`\n"
struct ar_hdr {
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
};
# define SARFMAG 2
# define SARHDR sizeof( struct ar_hdr )
void
file_archscan(
const 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 */
jam-2.5/fileos2.c 0100440 0000503 0000454 00000005771 07651415176 013012 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/20/00 (seiwald) - Upgraded from K&R to ANSI C
* 09/22/00 (seiwald) handle \ and c:\ specially: don't add extra /
* 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "filesys.h"
# include "pathsys.h"
# ifdef OS_OS2
# include
# include
/*
* file_dirscan() - scan a directory for files
*/
void
file_dirscan(
const 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(
const 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(
const char *archive,
scanback func,
void *closure )
{
}
# endif /* OS2 */
jam-2.5/filesys.h 0100440 0000503 0000454 00000001023 07651415176 013114 0 ustar seiwald team /*
* 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
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
typedef void (*scanback)( void *closure, const char *file, int found, time_t t );
void file_dirscan( const char *dir, scanback func, void *closure );
void file_archscan( const char *arch, scanback func, void *closure );
int file_time( const char *filename, time_t *time );
jam-2.5/fileunix.c 0100440 0000503 0000454 00000021160 07651415177 013261 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
* 04/03/01 (seiwald) - AIX uses SARMAG
* 07/16/02 (seiwald) - Support BSD style long filename in archives.
* 11/04/02 (seiwald) - const-ing for string literals
* 12/27/02 (seiwald) - support for AIX big archives
* 12/30/02 (seiwald) - terminate ar_hdr for solaris sscanf()
* 12/30/02 (seiwald) - skip solaris' empty archive member names (/, //xxx)
*/
# 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
# include
# define STRUCT_DIRENT struct direct
# else
# include
# define STRUCT_DIRENT struct dirent
# endif
# ifdef OS_COHERENT
# include
# define HAVE_AR
# endif
# if defined( OS_MVS ) || \
defined( OS_INTERIX )
#define ARMAG "!\n"
#define SARMAG 8
#define ARFMAG "`\n"
struct ar_hdr /* archive file member header - printable ascii */
{
char ar_name[16]; /* file member name - `/' terminated */
char ar_date[12]; /* file member date - decimal */
char ar_uid[6]; /* file member user id - decimal */
char ar_gid[6]; /* file member group id - decimal */
char ar_mode[8]; /* file member mode - octal */
char ar_size[10]; /* file member size - decimal */
char ar_fmag[2]; /* ARFMAG - string to end header */
};
# define HAVE_AR
# endif
# if defined( OS_QNX ) || \
defined( OS_BEOS ) || \
defined( OS_MPEIX )
# define NO_AR
# define HAVE_AR
# endif
# ifndef HAVE_AR
# ifdef _AIX43
/* AIX 43 ar SUPPORTs only __AR_BIG__ */
# define __AR_BIG__
# endif
# include
# endif
/*
* file_dirscan() - scan a directory for files
*/
void
file_dirscan(
const 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(
const 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(
const 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 ) )
{
long lar_date;
long lar_size;
char lar_name[256];
char *dst = lar_name;
/* solaris sscanf() does strlen first, so terminate somewhere */
ar_hdr.ar_fmag[0] = 0;
/* Get date & size */
sscanf( ar_hdr.ar_date, "%ld", &lar_date );
sscanf( ar_hdr.ar_size, "%ld", &lar_size );
/* Handle solaris string table.
** The entry under the name // is the table,
** and entries with the name /nnnn refer to the table.
*/
if( ar_hdr.ar_name[0] != '/' )
{
/* traditional archive entry names:
** ends at the first space, /, or null.
*/
char *src = ar_hdr.ar_name;
const char *e = src + sizeof( ar_hdr.ar_name );
while( src < e && *src && *src != ' ' && *src != '/' )
*dst++ = *src++;
}
else 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.
*/
char *src = string_table + atoi( ar_hdr.ar_name + 1 );
while( *src != '/' )
*dst++ = *src++;
}
/* Terminate lar_name */
*dst = 0;
/* Modern (BSD4.4) long names: if the name is "#1/nnnn",
** then the actual name is the nnnn bytes after the header.
*/
if( !strcmp( lar_name, "#1" ) )
{
int len = atoi( ar_hdr.ar_name + 3 );
if( read( fd, lar_name, len ) != len )
printf("error reading archive entry\n");
lar_name[len] = 0;
}
/* Build name and pass it on. */
if( lar_name[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 );
}
/* Position at next member */
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(
const 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;
# ifdef __AR_BIG__
if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
strncmp( AIAMAGBIG, fl_hdr.fl_magic, SAIAMAG ) )
{
if( strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
printf( "Can't read new archive %s before AIX 4.3.\n" );
close( fd );
return;
}
# else
if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )
{
close( fd );
return;
}
# endif
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 */
jam-2.5/filevms.c 0100440 0000503 0000454 00000016346 07651415177 013115 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
* 03/23/01 (seiwald) - VMS C++ changes.
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "filesys.h"
# include "pathsys.h"
# ifdef OS_VMS
# include
# include
# include
# include
# include
# include
# include
#include
#include
#include
#include
#include
#include
/* 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(
const 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 = (char *)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(
const 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(
const 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 = (char *)archive;
VMS_func = func;
VMS_closure = closure;
status = lbr$ini_control( &context, &lfunc, &typ, NULL );
if ( !( status & 1 ) )
return;
library.dsc$a_pointer = (char *)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 */
jam-2.5/glob.c 0100440 0000503 0000454 00000005016 07651415177 012363 0 ustar seiwald team /*
* 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
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
# 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( const char *s, const char *e, char *b );
/*
* glob() - match a string against a simple pattern
*/
int
glob(
const char *c,
const char *s )
{
char bitlist[ BITLISTSIZE ];
const 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(
const char *s,
const 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;
}
jam-2.5/hash.c 0100440 0000503 0000454 00000012261 07651415177 012363 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 11/04/02 (seiwald) - const-ing for string literals
* 01/31/02 (seiwald) - keyval now unsigned (cray-ziness)
*/
# include "jam.h"
# include "hash.h"
/* Header attached to all data items entered into a hash table. */
struct hashhdr {
struct item *next;
unsigned 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;
const 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;
unsigned char *b = (unsigned char *)(*data)->key;
unsigned int keyval;
if( enter && !hp->items.more )
hashrehash( hp );
if( !enter && !hp->items.nel )
return 0;
keyval = *b;
while( *b )
keyval = keyval * 2147059363 + *b++;
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,
const 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 );
}
jam-2.5/hash.h 0100440 0000503 0000454 00000001033 07651415177 012363 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* hash.h - simple in-memory hashing routines
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
typedef struct hashdata HASHDATA;
struct hash * hashinit( int datalen, const 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 )
jam-2.5/headers.c 0100440 0000503 0000454 00000005525 07651415177 013060 0 ustar seiwald team /*
* Copyright 1993, 2000 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* headers.c - handle #includes in source files
*
* Using regular expressions provided as the variable $(HDRSCAN),
* headers() searches a file for #include files and phonies up a
* rule invocation:
*
* $(HDRRULE) : ;
*
* External routines:
* headers() - scan a target for include files and call HDRRULE
*
* Internal routines:
* headers1() - using regexp, scan a file and build include LIST
*
* 04/13/94 (seiwald) - added shorthand L0 for null list pointer
* 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule,
* so that headers() doesn't have to mock up a parse structure
* just to invoke a rule.
* 03/02/02 (seiwald) - rules can be invoked via variable names
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 11/04/02 (seiwald) - const-ing for string literals
* 12/09/02 (seiwald) - push regexp creation down to headers1().
*/
# 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"
static LIST *headers1( const char *file, LIST *hdrscan );
/*
* headers() - scan a target for include files and call HDRRULE
*/
# define MAXINC 10
void
headers( TARGET *t )
{
LIST *hdrscan;
LIST *hdrrule;
LIST *hdrcache;
LOL lol;
if( !( hdrscan = var_get( "HDRSCAN" ) ) ||
!( hdrrule = var_get( "HDRRULE" ) ) )
return;
/* Doctor up call to HDRRULE rule */
/* Call headers1() to get LIST of included files. */
if( DEBUG_HEADER )
printf( "header scan %s\n", t->name );
lol_init( &lol );
lol_add( &lol, list_new( L0, t->name, 1 ) );
lol_add( &lol, headers1( t->boundname, hdrscan ) );
if( lol_get( &lol, 1 ) )
list_free( evaluate_rule( hdrrule->string, &lol, L0 ) );
/* Clean up */
lol_free( &lol );
}
/*
* headers1() - using regexp, scan a file and build include LIST
*/
static LIST *
headers1(
const char *file,
LIST *hdrscan )
{
FILE *f;
int i;
int rec = 0;
LIST *result = 0;
regexp *re[ MAXINC ];
char buf[ 1024 ];
if( !( f = fopen( file, "r" ) ) )
return result;
while( rec < MAXINC && hdrscan )
{
re[rec++] = regcomp( hdrscan->string );
hdrscan = list_next( hdrscan );
}
while( fgets( buf, sizeof( buf ), f ) )
{
for( i = 0; i < rec; i++ )
if( regexec( re[i], buf ) && re[i]->startp[1] )
{
/* Copy and terminate extracted string. */
char buf2[ MAXSYM ];
int l = re[i]->endp[1] - re[i]->startp[1];
memcpy( buf2, re[i]->startp[1], l );
buf2[ l ] = 0;
result = list_new( result, buf2, 0 );
if( DEBUG_HEADER )
printf( "header found: %s\n", buf2 );
}
}
while( rec )
free( (char *)re[--rec] );
fclose( f );
return result;
}
jam-2.5/headers.h 0100440 0000503 0000454 00000000316 07651415177 013056 0 ustar seiwald team /*
* 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 );
jam-2.5/jam.c 0100440 0000503 0000454 00000022455 07651415177 012215 0 ustar seiwald team /*
* /+\
* +\ 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
* 01/21/02 (seiwald) - new -q to quit quickly on build failure
* 03/16/02 (seiwald) - support for -g (reorder builds by source time)
* 09/19/02 (seiwald) - new -d displays
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 11/04/02 (seiwald) - const-ing for string literals
*/
# 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
# endif
/* And UNIX for this */
# ifdef unix
# include
# endif
struct globs globs = {
0, /* noexec */
1, /* jobs */
0, /* quitquick */
0, /* newestfirst */
# ifdef OS_MAC
{ 0 }, /* display - suppress actions output */
# else
{ 0, 1 }, /* display actions */
# endif
0 /* output commands, not run them */
} ;
/* Symbols to be defined as true for use in Jambase */
static const 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;
const char *s;
struct option optv[N_OPTS];
const 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 Display (a)actions (c)causes (d)dependencies\n" );
printf( " (m)make tree (x)commands (0-9) debug levels.\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++, DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 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 = atoi( s );
/* First -d, turn off defaults. */
if( !n )
DEBUG_MAKE = DEBUG_MAKEQ = DEBUG_EXEC = 0;
/* n turns on levels 1-n */
/* +n turns on level n */
/* c turns on named display c */
if( i < 0 || i >= DEBUG_MAX )
{
printf( "Invalid debug level '%s'.\n", s );
}
else if( *s == '+' )
{
globs.debug[i] = 1;
}
else if( i ) while( i )
{
globs.debug[i--] = 1;
}
else while( *s ) switch( *s++ )
{
case 'a': DEBUG_MAKE = DEBUG_MAKEQ = 1; break;
case 'c': DEBUG_CAUSES = 1; break;
case 'd': DEBUG_DEPENDS = 1; break;
case 'm': DEBUG_MAKEPROG = 1; break;
case 'x': DEBUG_EXEC = 1; break;
case '0': break;
default: printf( "Invalid debug flag '%c'.\n", s[-1] );
}
}
/* Set JAMDATE first */
{
char buf[ 128 ];
time_t clock;
time( &clock );
strcpy( buf, ctime( &clock ) );
/* Trim newline from date */
if( strlen( buf ) == 25 )
buf[ 24 ] = 0;
var_set( "JAMDATE", list_new( L0, buf, 0 ), VAR_SET );
}
/* And JAMUNAME */
# ifdef unix
{
struct utsname u;
if( uname( &u ) >= 0 )
{
LIST *l = L0;
l = list_new( l, u.machine, 0 );
l = list_new( l, u.version, 0 );
l = list_new( l, u.release, 0 );
l = list_new( l, u.nodename, 0 );
l = list_new( l, u.sysname, 0 );
var_set( "JAMUNAME", l, VAR_SET );
}
}
# endif /* unix */
/*
* Jam defined variables OS, OSPLAT
*/
var_defines( othersyms );
/* load up environment variables */
var_defines( (const char **)use_environ );
/* Load up variables set on command line. */
for( n = 0; s = getoptval( optv, 's', n ); n++ )
{
const 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, (const char **)argv, anyhow );
/* Widely scattered cleanup */
var_done();
donerules();
donestamps();
donestr();
/* close cmdout */
if( globs.cmdout )
fclose( globs.cmdout );
return status ? EXITBAD : EXITOK;
}
jam-2.5/jam.h 0100440 0000503 0000454 00000025254 10066340700 012201 0 ustar seiwald team /*
* 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/22/01 (seiwald) - downshift paths on case-insensitive macintosh
* 03/23/01 (seiwald) - VMS C++ changes.
* 10/29/01 (brett) - More IA64 ifdefs for MS.
* 02/18/00 (belmonte)- Support for Cygwin.
* 09/12/00 (seiwald) - OSSYMS split to OSMAJOR/OSMINOR/OSPLAT
* 12/29/00 (seiwald) - OSVER dropped.
* 01/21/02 (seiwald) - new -q to quit quickly on build failure
* 03/16/02 (seiwald) - support for -g (reorder builds by source time)
* 03/20/02 (seiwald) - MINGW porting from Max Blagai
* 08/16/02 (seiwald) - BEOS porting from Ingo Weinhold
* 09/19/02 (seiwald) - new -d displays
* 11/05/02 (seiwald) - OSPLAT now set to sparc on solaris.
*/
/*
* VMS, OPENVMS
*/
# ifdef VMS
# define unlink remove
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include
# define OSMINOR "OS=VMS"
# define OSMAJOR "VMS=true"
# define OS_VMS
# define MAXLINE 1024 /* longest 'together' actions */
# define SPLITPATH ','
# define EXITOK 1
# define EXITBAD 0
# define DOWNSHIFT_PATHS
/* Do any of these work? */
# if defined( VAX ) || defined( __VAX ) || defined( vax )
# define OSPLAT "OSPLAT=VAX"
# endif
# endif
/*
* Windows NT
*/
# ifdef NT
# include
# include
# include
# include
# include
# include
# include
# include
# include
# define OSMAJOR "NT=true"
# define OSMINOR "OS=NT"
# define OS_NT
# define SPLITPATH ';'
# 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
# include
# include
# include
# include
# include
# include
# include
# include
# 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
# include
# include
# include
# include
# include
# include
# include
# define OSMAJOR "OS2=true"
# define OSMINOR "OS=OS2"
# define OS_OS2
# define SPLITPATH ';'
# define MAXLINE 996 /* longest 'together' actions */
# define USE_EXECUNIX
# define USE_PATHUNIX
# define PATH_DELIM '\\'
# define DOWNSHIFT_PATHS
# endif
/*
* Macintosh MPW
*/
# ifdef macintosh
# include
# include
# include
# include
# include
# 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
# include
# ifndef OS_MPEIX
# include
# endif
# include
# include
# include
# include
# include
# include
# ifndef OS_QNX
# include
# endif
# ifndef OS_ULTRIX
# include
# endif
# if !defined(OS_BSDI) && \
!defined(OS_FREEBSD) && \
!defined(OS_NEXT) && \
!defined(OS_MACHTEN) && \
!defined(OS_MACOSX) && \
!defined(OS_RHAPSODY) && \
!defined(OS_MVS)
# include
# endif
# endif
/*
* OSPLAT definitions - suppressed when it's a one-of-a-kind
*/
# if defined( _M_PPC ) || \
defined( PPC ) || \
defined( ppc ) || \
defined( __powerpc__ ) || \
defined( __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 )
# 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 15
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 ] ) /* -da show actions when executed */
# define DEBUG_MAKEPROG ( globs.debug[ 3 ] ) /* -dm show progress of make0 */
# define DEBUG_EXECCMD ( globs.debug[ 4 ] ) /* show execcmds()'s work */
# define DEBUG_COMPILE ( globs.debug[ 5 ] ) /* show rule invocations */
# define DEBUG_HEADER ( globs.debug[ 6 ] ) /* show result of header scan */
# define DEBUG_BINDSCAN ( globs.debug[ 6 ] ) /* show result of dir scan */
# define DEBUG_SEARCH ( globs.debug[ 6 ] ) /* show attempts at binding */
# define DEBUG_VARSET ( globs.debug[ 7 ] ) /* show variable settings */
# define DEBUG_VARGET ( globs.debug[ 8 ] ) /* show variable fetches */
# define DEBUG_VAREXP ( globs.debug[ 8 ] ) /* show variable expansions */
# define DEBUG_IF ( globs.debug[ 8 ] ) /* show 'if' calculations */
# define DEBUG_LISTS ( globs.debug[ 9 ] ) /* show list manipulation */
# define DEBUG_SCAN ( globs.debug[ 9 ] ) /* show scanner tokens */
# define DEBUG_MEM ( globs.debug[ 9 ] ) /* show memory use */
# define DEBUG_MAKEQ ( globs.debug[ 11 ] ) /* -da show even quiet actions */
# define DEBUG_EXEC ( globs.debug[ 12 ] ) /* -dx show text of actions */
# define DEBUG_DEPENDS ( globs.debug[ 13 ] ) /* -dd show dependency graph */
# define DEBUG_CAUSES ( globs.debug[ 14 ] ) /* -dc show dependency graph */
jam-2.5/jambase.c 0100640 0000503 0000454 00000072126 10111167467 013041 0 ustar seiwald team /* Generated by mkjambase from Jambase */
const char *jambase[] = {
/* Jambase */
"JAMBASEDATE = 2002.05.09 ;\n",
"if $(NT)\n",
"{\n",
"MV ?= move /y ;\n",
"CP ?= copy ;\n",
"RM ?= del /f/q ;\n",
"RMDIR ?= rmdir /s/q ;\n",
"SLASH ?= \\\\ ;\n",
"SUFLIB ?= .lib ;\n",
"SUFOBJ ?= .obj ;\n",
"SUFEXE ?= .exe ;\n",
"if $(BCCROOT)\n",
"{\n",
"AR ?= tlib /C /P64 ;\n",
"CC ?= bcc32 ;\n",
"CCFLAGS ?= -v -w- -q -DWIN -tWR -tWM -tWC ;\n",
"C++ ?= $(CC) ;\n",
"C++FLAGS ?= $(CCFLAGS) -P ;\n",
"LINK ?= $(CC) ;\n",
"LINKFLAGS ?= $(CCFLAGS) ;\n",
"STDLIBPATH ?= $(BCCROOT)\\\\lib ;\n",
"STDHDRS ?= $(BCCROOT)\\\\include ;\n",
"NOARSCAN ?= true ;\n",
"}\n",
"else if $(MSVC)\n",
"{\n",
"AR ?= lib /nologo ;\n",
"CC ?= cl /nologo ;\n",
"CCFLAGS ?= /D \\\"WIN\\\" ;\n",
"C++ ?= $(CC) ;\n",
"C++FLAGS ?= $(CCFLAGS) ;\n",
"LINK ?= $(CC) ;\n",
"LINKFLAGS ?= $(CCFLAGS) ;\n",
"LINKLIBS ?= \n",
"$(MSVC)\\\\lib\\\\mlibce.lib\n",
"$(MSVC)\\\\lib\\\\oldnames.lib\n",
";\n",
"LINKLIBS ?= ;\n",
"NOARSCAN ?= true ;\n",
"OPTIM ?= ;\n",
"STDHDRS ?= $(MSVC)\\\\include ;\n",
"UNDEFFLAG ?= \"/u _\" ;\n",
"}\n",
"else if $(MSVCNT) || $(MSVCDIR)\n",
"{\n",
"MSVCNT ?= $(MSVCDIR) ; \n",
"local I ; if $(OSPLAT) = IA64 { I = ia64\\\\ ; } else { I = \"\" ; }\n",
"AR ?= lib ;\n",
"AS ?= masm386 ;\n",
"CC ?= cl /nologo ;\n",
"CCFLAGS ?= \"\" ;\n",
"C++ ?= $(CC) ;\n",
"C++FLAGS ?= $(CCFLAGS) ;\n",
"LINK ?= link /nologo ;\n",
"LINKFLAGS ?= \"\" ;\n",
"LINKLIBS ?= \n",
"$(MSVCNT)\\\\lib\\\\$(I)libc.lib\n",
"$(MSVCNT)\\\\lib\\\\$(I)oldnames.lib\n",
"$(MSVCNT)\\\\lib\\\\$(I)kernel32.lib ;\n",
"OPTIM ?= \"\" ;\n",
"STDHDRS ?= $(MSVCNT)\\\\include ;\n",
"UNDEFFLAG ?= \"/u _\" ;\n",
"}\n",
"else\n",
"{\n",
"EXIT On NT, set BCCROOT, MSVCDIR, MSVCNT, or MSVC to the root\n",
"of the Borland or Microsoft directories. ;\n",
"}\n",
"}\n",
"else if $(MINGW)\n",
"{\n",
"Echo \"MingW32\" ;\n",
"CC ?= gcc ;\n",
"C++ ?= g++ ;\n",
"CCFLAGS += -DMINGW ;\n",
"RANLIB ?= \"ranlib\" ;\n",
"SUFEXE ?= .exe ;\n",
"}\n",
"else if $(OS2)\n",
"{\n",
"WATCOM ?= $(watcom) ;\n",
"if ! $(WATCOM)\n",
"{\n",
"Exit On OS2, set WATCOM to the root of the Watcom directory. ;\n",
"}\n",
"AR ?= wlib ;\n",
"BINDIR ?= \\\\os2\\\\apps ;\n",
"CC ?= wcc386 ;\n",
"CCFLAGS ?= /zq /DOS2 /I$(WATCOM)\\\\h ; # zq=quiet\n",
"C++ ?= wpp386 ;\n",
"C++FLAGS ?= $(CCFLAGS) ;\n",
"CP ?= copy ;\n",
"DOT ?= . ;\n",
"DOTDOT ?= .. ;\n",
"LINK ?= wcl386 ;\n",
"LINKFLAGS ?= /zq ; # zq=quiet\n",
"LINKLIBS ?= ;\n",
"MV ?= move ;\n",
"NOARSCAN ?= true ;\n",
"OPTIM ?= ;\n",
"RM ?= del /f ;\n",
"SLASH ?= \\\\ ;\n",
"STDHDRS ?= $(WATCOM)\\\\h ;\n",
"SUFEXE ?= .exe ;\n",
"SUFLIB ?= .lib ;\n",
"SUFOBJ ?= .obj ;\n",
"UNDEFFLAG ?= \"/u _\" ;\n",
"}\n",
"else if $(VMS)\n",
"{\n",
"C++ ?= cxx ;\n",
"C++FLAGS ?= ;\n",
"CC ?= cc ;\n",
"CCFLAGS ?= ;\n",
"CHMOD ?= set file/prot= ;\n",
"CP ?= copy/replace ;\n",
"CRELIB ?= true ;\n",
"DOT ?= [] ;\n",
"DOTDOT ?= [-] ;\n",
"EXEMODE ?= (w:e) ;\n",
"FILEMODE ?= (w:r) ;\n",
"HDRS ?= ;\n",
"LINK ?= link ;\n",
"LINKFLAGS ?= \"\" ;\n",
"LINKLIBS ?= ;\n",
"MKDIR ?= create/dir ;\n",
"MV ?= rename ;\n",
"OPTIM ?= \"\" ;\n",
"RM ?= delete ;\n",
"RUNVMS ?= mcr ;\n",
"SHELLMODE ?= (w:er) ;\n",
"SLASH ?= . ;\n",
"STDHDRS ?= decc$library_include ;\n",
"SUFEXE ?= .exe ;\n",
"SUFLIB ?= .olb ;\n",
"SUFOBJ ?= .obj ;\n",
"switch $(OS) \n",
"{\n",
"case OPENVMS : CCFLAGS ?= /stand=vaxc ;\n",
"case VMS : LINKLIBS ?= sys$library:vaxcrtl.olb/lib ;\n",
"}\n",
"}\n",
"else if $(MAC)\n",
"{\n",
"local OPT ;\n",
"CW ?= \"{CW}\" ;\n",
"MACHDRS ?=\n",
"\"$(UMACHDRS):Universal:Interfaces:CIncludes\"\n",
"\"$(CW):MSL:MSL_C:MSL_Common:Include\"\n",
"\"$(CW):MSL:MSL_C:MSL_MacOS:Include\" ;\n",
"MACLIBS ?=\n",
"\"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Interfacelib\"\n",
"\"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Mathlib\" ;\n",
"MPWLIBS ?= \n",
"\"$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_MPWCRuntime_PPC.lib\"\n",
"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC_MPW.Lib\" ;\n",
"MPWNLLIBS ?= \n",
"\"$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_MPWCRuntime_PPC.lib\"\n",
"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC_MPW(NL).Lib\" ;\n",
"SIOUXHDRS ?= ;\n",
"SIOUXLIBS ?= \n",
"\"$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_Runtime_PPC.lib\"\n",
"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_SIOUX_PPC.Lib\" \n",
"\"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC.Lib\" ;\n",
"C++ ?= mwcppc ;\n",
"C++FLAGS ?= -w off ;\n",
"CC ?= mwcppc ;\n",
"CCFLAGS ?= -w off ;\n",
"CP ?= duplicate -y ;\n",
"DOT ?= \":\" ;\n",
"DOTDOT ?= \"::\" ;\n",
"HDRS ?= $(MACHDRS) $(MPWHDRS) ;\n",
"LINK ?= mwlinkppc ;\n",
"LINKFLAGS ?= -mpwtool -warn ; \n",
"LINKLIBS ?= $(MACLIBS) $(MPWLIBS) ; \n",
"MKDIR ?= newfolder ;\n",
"MV ?= rename -y ;\n",
"NOARSCAN ?= true ;\n",
"OPTIM ?= ;\n",
"RM ?= delete -y ;\n",
"SLASH ?= \":\" ;\n",
"STDHDRS ?= ; \n",
"SUFLIB ?= .lib ;\n",
"SUFOBJ ?= .o ;\n",
"}\n",
"else if $(OS) = BEOS && $(OSPLAT) = PPC\n",
"{\n",
"AR ?= mwld -xml -o ;\n",
"BINDIR ?= /boot/home/config/bin ;\n",
"CC ?= mwcc ;\n",
"CCFLAGS ?= -nosyspath ;\n",
"C++ ?= $(CC) ;\n",
"C++FLAGS ?= -nosyspath ;\n",
"CHMOD ?= chmod ;\n",
"CHGRP ?= chgrp ;\n",
"CHOWN ?= chown ;\n",
"FORTRAN ?= \"\" ;\n",
"LEX ?= flex ;\n",
"LIBDIR ?= /boot/home/config/lib ;\n",
"LINK ?= mwld ;\n",
"LINKFLAGS ?= \"\" ;\n",
"MANDIR ?= /boot/home/config/man ;\n",
"NOARSCAN ?= true ;\n",
"RANLIB ?= ranlib ;\n",
"STDHDRS ?= /boot/develop/headers/posix ;\n",
"YACC ?= bison -y ;\n",
"YACCGEN ?= .c ;\n",
"YACCFILES ?= y.tab ;\n",
"YACCFLAGS ?= -d ;\n",
"}\n",
"else if $(OS) = BEOS \n",
"{\n",
"BINDIR ?= /boot/home/config/bin ;\n",
"CC ?= gcc ;\n",
"C++ ?= $(CC) ;\n",
"CHMOD ?= chmod ;\n",
"CHGRP ?= chgrp ;\n",
"CHOWN ?= chown ;\n",
"FORTRAN ?= \"\" ;\n",
"LEX ?= flex ;\n",
"LIBDIR ?= /boot/home/config/lib ;\n",
"LINK ?= gcc ;\n",
"MANDIR ?= /boot/home/config/man ;\n",
"NOARSCAN ?= true ;\n",
"RANLIB ?= ranlib ;\n",
"STDHDRS ?= /boot/develop/headers/posix ;\n",
"YACC ?= bison -y ;\n",
"YACCGEN ?= .c ;\n",
"YACCFILES ?= y.tab ;\n",
"YACCFLAGS ?= -d ;\n",
"}\n",
"else if $(UNIX)\n",
"{\n",
"switch $(OS)\n",
"{\n",
"case AIX :\n",
"LINKLIBS ?= -lbsd ;\n",
"case AMIGA :\n",
"CC ?= gcc ;\n",
"YACC ?= bison -y ;\n",
"case CYGWIN : \n",
"CC ?= gcc ;\n",
"CCFLAGS += -D__cygwin__ ;\n",
"LEX ?= flex ;\n",
"JAMSHELL ?= sh -c ;\n",
"RANLIB ?= \"\" ;\n",
"SUFEXE ?= .exe ;\n",
"YACC ?= bison -y ;\n",
"case DGUX :\n",
"RANLIB ?= \"\" ;\n",
"RELOCATE ?= true ;\n",
"case HPUX :\n",
"RANLIB ?= \"\" ;\n",
"case INTERIX :\n",
"CC ?= gcc ;\n",
"JAMSHELL ?= sh -c ;\n",
"RANLIB ?= \"\" ;\n",
"case IRIX :\n",
"RANLIB ?= \"\" ;\n",
"case MPEIX :\n",
"CC ?= gcc ;\n",
"C++ ?= gcc ;\n",
"CCFLAGS += -D_POSIX_SOURCE ;\n",
"HDRS += /usr/include ;\n",
"RANLIB ?= \"\" ; \n",
"NOARSCAN ?= true ;\n",
"NOARUPDATE ?= true ;\n",
"case MVS :\n",
"RANLIB ?= \"\" ; \n",
"case NEXT :\n",
"AR ?= libtool -o ;\n",
"RANLIB ?= \"\" ;\n",
"case MACOSX :\n",
"C++ ?= c++ ;\n",
"MANDIR ?= /usr/local/share/man ;\n",
"case NCR :\n",
"RANLIB ?= \"\" ;\n",
"case PTX :\n",
"RANLIB ?= \"\" ;\n",
"case QNX :\n",
"AR ?= wlib ;\n",
"CC ?= cc ;\n",
"CCFLAGS ?= -Q ; # quiet\n",
"C++ ?= $(CC) ;\n",
"C++FLAGS ?= -Q ; # quiet\n",
"LINK ?= $(CC) ;\n",
"LINKFLAGS ?= -Q ; # quiet\n",
"NOARSCAN ?= true ;\n",
"RANLIB ?= \"\" ;\n",
"case SCO :\n",
"RANLIB ?= \"\" ;\n",
"RELOCATE ?= true ;\n",
"case SINIX :\n",
"RANLIB ?= \"\" ;\n",
"case SOLARIS :\n",
"RANLIB ?= \"\" ;\n",
"AR ?= \"/usr/ccs/bin/ar ru\" ;\n",
"case UNICOS :\n",
"NOARSCAN ?= true ;\n",
"OPTIM ?= -O0 ;\n",
"case UNIXWARE :\n",
"RANLIB ?= \"\" ;\n",
"RELOCATE ?= true ;\n",
"}\n",
"CCFLAGS ?= ;\n",
"C++FLAGS ?= $(CCFLAGS) ;\n",
"CHMOD ?= chmod ;\n",
"CHGRP ?= chgrp ;\n",
"CHOWN ?= chown ;\n",
"LEX ?= lex ;\n",
"LINKFLAGS ?= $(CCFLAGS) ;\n",
"LINKLIBS ?= ;\n",
"OPTIM ?= -O ;\n",
"RANLIB ?= ranlib ;\n",
"YACC ?= yacc ;\n",
"YACCGEN ?= .c ;\n",
"YACCFILES ?= y.tab ;\n",
"YACCFLAGS ?= -d ;\n",
"}\n",
"AR ?= ar ru ;\n",
"AS ?= as ;\n",
"ASFLAGS ?= ;\n",
"AWK ?= awk ;\n",
"BINDIR ?= /usr/local/bin ;\n",
"C++ ?= cc ;\n",
"C++FLAGS ?= ;\n",
"CC ?= cc ;\n",
"CCFLAGS ?= ;\n",
"CP ?= cp -f ;\n",
"CRELIB ?= ;\n",
"DOT ?= . ;\n",
"DOTDOT ?= .. ;\n",
"EXEMODE ?= 711 ;\n",
"FILEMODE ?= 644 ;\n",
"FORTRAN ?= f77 ;\n",
"FORTRANFLAGS ?= ;\n",
"HDRS ?= ;\n",
"INSTALLGRIST ?= installed ;\n",
"JAMFILE ?= Jamfile ;\n",
"JAMRULES ?= Jamrules ;\n",
"LEX ?= ;\n",
"LIBDIR ?= /usr/local/lib ;\n",
"LINK ?= $(CC) ;\n",
"LINKFLAGS ?= ;\n",
"LINKLIBS ?= ;\n",
"LN ?= ln ;\n",
"MANDIR ?= /usr/local/man ;\n",
"MKDIR ?= mkdir ;\n",
"MV ?= mv -f ;\n",
"OPTIM ?= ;\n",
"RCP ?= rcp ;\n",
"RM ?= rm -f ;\n",
"RMDIR ?= $(RM) ;\n",
"RSH ?= rsh ;\n",
"SED ?= sed ;\n",
"SHELLHEADER ?= \"#!/bin/sh\" ;\n",
"SHELLMODE ?= 755 ;\n",
"SLASH ?= / ;\n",
"STDHDRS ?= /usr/include ;\n",
"SUBDIRRULES ?= ;\n",
"SUBDIRRESET ?= ASFLAGS HDRS C++FLAGS CCFLAGS ;\n",
"SUFEXE ?= \"\" ;\n",
"SUFLIB ?= .a ;\n",
"SUFOBJ ?= .o ;\n",
"UNDEFFLAG ?= \"-u _\" ;\n",
"YACC ?= ;\n",
"YACCGEN ?= ;\n",
"YACCFILES ?= ;\n",
"YACCFLAGS ?= ;\n",
"HDRPATTERN = \n",
"\"^[ ]*#[ ]*include[ ]*[<\\\"]([^\\\">]*)[\\\">].*$\" ;\n",
"OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;\n",
"Depends all : shell files lib exe obj ;\n",
"Depends all shell files lib exe obj : first ;\n",
"NotFile all first shell files lib exe obj dirs clean uninstall ;\n",
"Always clean uninstall ;\n",
"rule As\n",
"{\n",
"Depends $(<) : $(>) ;\n",
"ASFLAGS on $(<) += $(ASFLAGS) $(SUBDIRASFLAGS) ;\n",
"ASHDRS on $(<) = [ FIncludes $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ] ;\n",
"}\n",
"rule Bulk\n",
"{\n",
"local i ;\n",
"for i in $(>)\n",
"{\n",
"File $(i:D=$(<)) : $(i) ;\n",
"}\n",
"}\n",
"rule Cc\n",
"{\n",
"Depends $(<) : $(>) ;\n",
"if $(RELOCATE)\n",
"{\n",
"CcMv $(<) : $(>) ;\n",
"}\n",
"CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) $(OPTIM) ;\n",
"CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;\n",
"CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;\n",
"}\n",
"rule C++\n",
"{\n",
"Depends $(<) : $(>) ;\n",
"if $(RELOCATE)\n",
"{\n",
"CcMv $(<) : $(>) ;\n",
"}\n",
"C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) $(OPTIM) ;\n",
"CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;\n",
"CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;\n",
"}\n",
"rule Chmod\n",
"{\n",
"if $(CHMOD) { Chmod1 $(<) ; }\n",
"}\n",
"rule File\n",
"{\n",
"Depends files : $(<) ;\n",
"Depends $(<) : $(>) ;\n",
"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
"MODE on $(<) = $(FILEMODE) ;\n",
"Chmod $(<) ;\n",
"}\n",
"rule Fortran\n",
"{\n",
"Depends $(<) : $(>) ;\n",
"}\n",
"rule GenFile \n",
"{\n",
"local _t = [ FGristSourceFiles $(<) ] ;\n",
"local _s = [ FAppendSuffix $(>[1]) : $(SUFEXE) ] ;\n",
"Depends $(_t) : $(_s) $(>[2-]) ;\n",
"GenFile1 $(_t) : $(_s) $(>[2-]) ;\n",
"Clean clean : $(_t) ;\n",
"}\n",
"rule GenFile1\n",
"{\n",
"MakeLocate $(<) : $(LOCATE_SOURCE) ;\n",
"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
"}\n",
"rule HardLink\n",
"{\n",
"Depends files : $(<) ;\n",
"Depends $(<) : $(>) ;\n",
"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
"}\n",
"rule HdrRule\n",
"{\n",
"local s = $(>:G=$(HDRGRIST:E)) ;\n",
"Includes $(<) : $(s) ;\n",
"SEARCH on $(s) = $(HDRSEARCH) ;\n",
"NoCare $(s) ;\n",
"HDRSEARCH on $(s) = $(HDRSEARCH) ;\n",
"HDRSCAN on $(s) = $(HDRSCAN) ;\n",
"HDRRULE on $(s) = $(HDRRULE) ;\n",
"HDRGRIST on $(s) = $(HDRGRIST) ;\n",
"}\n",
"rule InstallInto\n",
"{\n",
"local i t ;\n",
"t = $(>:G=$(INSTALLGRIST)) ;\n",
"Depends install : $(t) ;\n",
"Clean uninstall : $(t) ;\n",
"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
"MakeLocate $(t) : $(<) ;\n",
"for i in $(>)\n",
"{\n",
"local tt = $(i:G=$(INSTALLGRIST)) ;\n",
"Depends $(tt) : $(i) ;\n",
"Install $(tt) : $(i) ;\n",
"Chmod $(tt) ;\n",
"if $(OWNER) && $(CHOWN) \n",
"{ \n",
"Chown $(tt) ;\n",
"OWNER on $(tt) = $(OWNER) ;\n",
"}\n",
"if $(GROUP) && $(CHGRP) \n",
"{ \n",
"Chgrp $(tt) ;\n",
"GROUP on $(tt) = $(GROUP) ;\n",
"}\n",
"}\n",
"}\n",
"rule InstallBin\n",
"{\n",
"local _t = [ FAppendSuffix $(>) : $(SUFEXE) ] ;\n",
"InstallInto $(<) : $(_t) ;\n",
"MODE on $(_t:G=$(INSTALLGRIST)) = $(EXEMODE) ;\n",
"}\n",
"rule InstallFile\n",
"{\n",
"InstallInto $(<) : $(>) ;\n",
"MODE on $(>:G=$(INSTALLGRIST)) = $(FILEMODE) ;\n",
"}\n",
"rule InstallLib\n",
"{\n",
"InstallInto $(<) : $(>) ;\n",
"MODE on $(>:G=$(INSTALLGRIST)) = $(FILEMODE) ;\n",
"}\n",
"rule InstallMan\n",
"{\n",
"local i s d ;\n",
"for i in $(>)\n",
"{\n",
"switch $(i:S)\n",
"{\n",
"case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;\n",
"case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;\n",
"case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;\n",
"case .n : s = n ; case .man : s = 1 ;\n",
"}\n",
"d = man$(s) ;\n",
"InstallInto $(d:R=$(<)) : $(i) ;\n",
"}\n",
"MODE on $(>:G=$(INSTALLGRIST)) = $(FILEMODE) ;\n",
"}\n",
"rule InstallShell\n",
"{\n",
"InstallInto $(<) : $(>) ;\n",
"MODE on $(>:G=$(INSTALLGRIST)) = $(SHELLMODE) ;\n",
"}\n",
"rule Lex\n",
"{\n",
"LexMv $(<) : $(>) ;\n",
"Depends $(<) : $(>) ;\n",
"MakeLocate $(<) : $(LOCATE_SOURCE) ;\n",
"Clean clean : $(<) ;\n",
"}\n",
"rule Library\n",
"{\n",
"LibraryFromObjects $(<) : $(>:S=$(SUFOBJ)) ;\n",
"Objects $(>) ;\n",
"}\n",
"rule LibraryFromObjects\n",
"{\n",
"local _i _l _s ;\n",
"_s = [ FGristFiles $(>) ] ;\n",
"_l = $(<:S=$(SUFLIB)) ;\n",
"if $(KEEPOBJS)\n",
"{\n",
"Depends obj : $(_s) ;\n",
"}\n",
"else\n",
"{\n",
"Depends lib : $(_l) ;\n",
"}\n",
"if ! $(_l:D)\n",
"{\n",
"MakeLocate $(_l) $(_l)($(_s:BS)) : $(LOCATE_TARGET) ;\n",
"}\n",
"if $(NOARSCAN) \n",
"{ \n",
"Depends $(_l) : $(_s) ;\n",
"}\n",
"else\n",
"{\n",
"Depends $(_l) : $(_l)($(_s:BS)) ;\n",
"for _i in $(_s)\n",
"{\n",
"Depends $(_l)($(_i:BS)) : $(_i) ;\n",
"}\n",
"}\n",
"Clean clean : $(_l) ;\n",
"if $(CRELIB) { CreLib $(_l) : $(_s[1]) ; }\n",
"Archive $(_l) : $(_s) ;\n",
"if $(RANLIB) { Ranlib $(_l) ; }\n",
"if ! ( $(NOARSCAN) || $(NOARUPDATE) ) { RmTemps $(_l) : $(_s) ; }\n",
"}\n",
"rule Link\n",
"{\n",
"MODE on $(<) = $(EXEMODE) ;\n",
"Chmod $(<) ;\n",
"}\n",
"rule LinkLibraries\n",
"{\n",
"local _t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;\n",
"Depends $(_t) : $(>:S=$(SUFLIB)) ;\n",
"NEEDLIBS on $(_t) += $(>:S=$(SUFLIB)) ;\n",
"}\n",
"rule Main\n",
"{\n",
"MainFromObjects $(<) : $(>:S=$(SUFOBJ)) ;\n",
"Objects $(>) ;\n",
"}\n",
"rule MainFromObjects\n",
"{\n",
"local _s _t ;\n",
"_s = [ FGristFiles $(>) ] ;\n",
"_t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;\n",
"if $(_t) != $(<)\n",
"{\n",
"Depends $(<) : $(_t) ;\n",
"NotFile $(<) ;\n",
"}\n",
"Depends exe : $(_t) ;\n",
"Depends $(_t) : $(_s) ;\n",
"MakeLocate $(_t) : $(LOCATE_TARGET) ;\n",
"Clean clean : $(_t) ;\n",
"Link $(_t) : $(_s) ;\n",
"}\n",
"rule MakeLocate\n",
"{\n",
"if $(>)\n",
"{\n",
"LOCATE on $(<) = $(>) ;\n",
"Depends $(<) : $(>[1]:G=dir) ;\n",
"MkDir $(>[1]:G=dir) ;\n",
"}\n",
"}\n",
"rule MkDir\n",
"{\n",
"NoUpdate $(<) ;\n",
"if $(<:G=) != $(DOT) && ! $($(<)-mkdir) \n",
"{\n",
"$(<)-mkdir = true ;\n",
"Depends dirs : $(<) ;\n",
"MkDir1 $(<) ;\n",
"local s = $(<:P) ;\n",
"if $(NT)\n",
"{\n",
"switch $(s)\n",
"{\n",
"case *: : s = ;\n",
"case *:\\\\ : s = ;\n",
"}\n",
"}\n",
"if $(s) = $(<)\n",
"{\n",
"NotFile $(s) ;\n",
"}\n",
"else if $(s:G=)\n",
"{\n",
"Depends $(<) : $(s) ;\n",
"MkDir $(s) ;\n",
"}\n",
"}\n",
"}\n",
"rule Object\n",
"{\n",
"Clean clean : $(<) ;\n",
"MakeLocate $(<) : $(LOCATE_TARGET) ;\n",
"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
"HDRS on $(<) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ;\n",
"HDRRULE on $(>) = HdrRule ;\n",
"HDRSCAN on $(>) = $(HDRPATTERN) ;\n",
"HDRSEARCH on $(>) = \n",
"$(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ;\n",
"HDRGRIST on $(>) = $(HDRGRIST) ;\n",
"DEFINES on $(<) += $(DEFINES) ;\n",
"switch $(>:S)\n",
"{\n",
"case .asm : As $(<) : $(>) ;\n",
"case .c : Cc $(<) : $(>) ;\n",
"case .C : C++ $(<) : $(>) ;\n",
"case .cc : C++ $(<) : $(>) ;\n",
"case .cpp : C++ $(<) : $(>) ;\n",
"case .f : Fortran $(<) : $(>) ;\n",
"case .l : Cc $(<) : $(<:S=.c) ;\n",
"Lex $(<:S=.c) : $(>) ;\n",
"case .s : As $(<) : $(>) ;\n",
"case .y : Cc $(<) : $(<:S=$(YACCGEN)) ;\n",
"Yacc $(<:S=$(YACCGEN)) : $(>) ;\n",
"case * : UserObject $(<) : $(>) ;\n",
"}\n",
"}\n",
"rule ObjectCcFlags\n",
"{\n",
"CCFLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
"}\n",
"rule ObjectC++Flags\n",
"{\n",
"C++FLAGS on [ FGristFiles $(<:S=$(SUFOBJ)) ] += $(>) ;\n",
"}\n",
"rule ObjectDefines\n",
"{\n",
"local s = [ FGristFiles $(<:S=$(SUFOBJ)) ] ;\n",
"DEFINES on $(s) += $(>) ;\n",
"CCDEFS on $(s) = [ on $(s) FDefines $(DEFINES) ] ;\n",
"}\n",
"rule ObjectHdrs\n",
"{\n",
"local s = [ FGristFiles $(<:S=$(SUFOBJ)) ] ;\n",
"HDRS on $(s) += $(>) ;\n",
"CCHDRS on $(s) = [ on $(s) FIncludes $(HDRS) ] ;\n",
"}\n",
"rule Objects\n",
"{\n",
"local _i ;\n",
"for _i in [ FGristFiles $(<) ]\n",
"{\n",
"Object $(_i:S=$(SUFOBJ)) : $(_i) ;\n",
"Depends obj : $(_i:S=$(SUFOBJ)) ;\n",
"}\n",
"}\n",
"rule RmTemps\n",
"{\n",
"Temporary $(>) ;\n",
"}\n",
"rule Setuid\n",
"{\n",
"MODE on [ FAppendSuffix $(<) : $(SUFEXE) ] = 4711 ;\n",
"}\n",
"rule Shell\n",
"{\n",
"Depends shell : $(<) ;\n",
"Depends $(<) : $(>) ;\n",
"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
"MODE on $(<) = $(SHELLMODE) ;\n",
"Clean clean : $(<) ;\n",
"Chmod $(<) ;\n",
"}\n",
"rule SoftLink\n",
"{\n",
"Depends files : $(<) ;\n",
"Depends $(<) : $(>) ;\n",
"SEARCH on $(>) = $(SEARCH_SOURCE) ;\n",
"Clean clean : $(<) ;\n",
"}\n",
"rule SubDir\n",
"{\n",
"local _top = $(<[1]) ;\n",
"local _tokens = $(<[2-]) ;\n",
"if ! $(_top)\n",
"{\n",
"Exit SubDir syntax error ;\n",
"}\n",
"if ! $($(_top)-SET)\n",
"{\n",
"$(_top)-SET = true ;\n",
"if $($(_top))\n",
"{\n",
"$(_top)-UP = ;\n",
"$(_top)-DOWN = ;\n",
"$(_top)-ROOT = $($(_top)) ;\n",
"}\n",
"else\n",
"{\n",
"_tokens = [ FReverse $(_tokens) ] ;\n",
"SUBDIR_DOWN = [ FReverse $(SUBDIR_DOWN) ] ;\n",
"FStripCommon _tokens : SUBDIR_DOWN ;\n",
"SUBDIR_DOWN = [ FReverse $(SUBDIR_DOWN) ] ;\n",
"_tokens = [ FReverse $(_tokens) ] ;\n",
"if $(SUBDIR_DOWN) && $(_tokens) \n",
"{ \n",
"Echo Warning: SubDir $(<) misplaced! ; \n",
"}\n",
"$(_top)-UP = $(SUBDIR_UP) $(_tokens) ;\n",
"$(_top)-DOWN = $(SUBDIR_DOWN) ;\n",
"$(_top)-ROOT = $(SUBDIR_ROOT:E=\"\") ;\n",
"$(_top) = [ FSubDirPath $(_top) ] ;\n",
"}\n",
"SUBDIR_UP = $($(_top)-UP) ;\n",
"SUBDIR_DOWN = ;\n",
"SUBDIR_ROOT = $($(_top)-ROOT) ;\n",
"if $($(_top)RULES) { \n",
"include $($(_top)RULES) ;\n",
"} else { \n",
"NoCare $(JAMRULES:R=$($(_top)):G=$(_top)) ;\n",
"include $(JAMRULES:R=$($(_top)):G=$(_top)) ;\n",
"}\n",
"}\n",
"SUBDIR_UP = $($(_top)-UP) ;\n",
"SUBDIR_DOWN = $($(_top)-DOWN) $(_tokens) ;\n",
"SUBDIR_ROOT = $($(_top)-ROOT) ;\n",
"SUBDIR_TOKENS = $(SUBDIR_DOWN) ;\n",
"SUBDIR = [ FSubDirPath $(<) ] ;\n",
"SEARCH_SOURCE = $(SUBDIR) ;\n",
"LOCATE_SOURCE = $(ALL_LOCATE_TARGET) $(SUBDIR) ;\n",
"LOCATE_TARGET = $(ALL_LOCATE_TARGET) $(SUBDIR) ;\n",
"SOURCE_GRIST = [ FGrist $(SUBDIR_TOKENS) ] ;\n",
"SUBDIR$(SUBDIRRESET) = ;\n",
"$(SUBDIRRULES) $(<) ;\n",
"}\n",
"rule FSubDirPath\n",
"{\n",
"local _r = [ FRelPath $($(<[1])-UP) : $($(<[1])-DOWN) $(<[2-]) ] ;\n",
"return $(_r:R=$($(<[1])-ROOT)) ;\n",
"}\n",
"rule SubDirCcFlags\n",
"{\n",
"SUBDIRCCFLAGS += $(<) ;\n",
"}\n",
"rule SubDirC++Flags\n",
"{\n",
"SUBDIRC++FLAGS += $(<) ;\n",
"}\n",
"rule SubDirHdrs\n",
"{\n",
"SUBDIRHDRS += [ FDirName $(<) ] ;\n",
"}\n",
"rule SubInclude\n",
"{\n",
"if ! $($(<[1]))\n",
"{\n",
"Exit SubInclude $(<[1]) without prior SubDir $(<[1]) ;\n",
"}\n",
"SubDir $(<) ;\n",
"include $(JAMFILE:D=$(SUBDIR)) ;\n",
"}\n",
"rule SubRules\n",
"{\n",
"if ! $($(<[1]))\n",
"{\n",
"Exit SubRules $(<[1]) without prior SubDir $(<[1]) ;\n",
"}\n",
"SubDir $(<) ;\n",
"SubDir $(>) ;\n",
"}\n",
"rule Undefines\n",
"{\n",
"UNDEFS on [ FAppendSuffix $(<) : $(SUFEXE) ] += $(UNDEFFLAG)$(>) ;\n",
"}\n",
"rule UserObject\n",
"{\n",
"Exit \"Unknown suffix on\" $(>) \"- see UserObject rule in Jamfile(5).\" ;\n",
"}\n",
"rule Yacc\n",
"{\n",
"local _h ;\n",
"_h = $(<:BS=.h) ;\n",
"MakeLocate $(<) $(_h) : $(LOCATE_SOURCE) ;\n",
"if $(YACC)\n",
"{\n",
"Depends $(<) $(_h) : $(>) ;\n",
"Yacc1 $(<) $(_h) : $(>) ;\n",
"YaccMv $(<) $(_h) : $(>) ;\n",
"Clean clean : $(<) $(_h) ;\n",
"}\n",
"Includes $(<) : $(_h) ;\n",
"}\n",
"rule FGrist\n",
"{\n",
"return $(<:J=!) ;\n",
"}\n",
"rule FGristFiles \n",
"{\n",
"return $(<:G=$(SOURCE_GRIST:E)) ;\n",
"}\n",
"rule FGristSourceFiles\n",
"{\n",
"if ! $(SOURCE_GRIST)\n",
"{\n",
"return $(<) ;\n",
"}\n",
"else \n",
"{\n",
"local _i _o ;\n",
"for _i in $(<)\n",
"{\n",
"switch $(_i)\n",
"{\n",
"case *.h : _o += $(_i) ;\n",
"case * : _o += $(_i:G=$(SOURCE_GRIST)) ;\n",
"}\n",
"}\n",
"return $(_o) ;\n",
"}\n",
"}\n",
"rule FReverse \n",
"{\n",
"if $(1) { return [ FReverse $(1[2-]) ] $(1[1]) ; }\n",
"}\n",
"rule FSubDir\n",
"{\n",
"if ! $(<[1]) \n",
"{\n",
"return $(DOT) ;\n",
"} \n",
"else\n",
"{\n",
"local _i _d ;\n",
"_d = $(DOTDOT) ;\n",
"for _i in $(<[2-])\n",
"{\n",
"_d = $(_d:R=$(DOTDOT)) ;\n",
"}\n",
"return $(_d) ;\n",
"}\n",
"}\n",
"rule FStripCommon\n",
"{\n",
"if $($(<)[1]) && $($(<)[1]) = $($(>)[1])\n",
"{\n",
"$(<) = $($(<)[2-]) ;\n",
"$(>) = $($(>)[2-]) ;\n",
"FStripCommon $(<) : $(>) ;\n",
"}\n",
"}\n",
"rule FRelPath\n",
"{\n",
"local _l _r ;\n",
"_l = $(<) ;\n",
"_r = $(>) ;\n",
"FStripCommon _l : _r ;\n",
"_l = [ FSubDir $(_l) ] ;\n",
"_r = [ FDirName $(_r) ] ;\n",
"if $(_r) = $(DOT) {\n",
"return $(_l) ;\n",
"} else {\n",
"return $(_r:R=$(_l)) ;\n",
"}\n",
"}\n",
"rule FAppendSuffix\n",
"{\n",
"if $(>)\n",
"{\n",
"local _i _o ;\n",
"for _i in $(<)\n",
"{\n",
"if $(_i:S)\n",
"{\n",
"_o += $(_i) ;\n",
"}\n",
"else\n",
"{\n",
"_o += $(_i:S=$(>)) ;\n",
"}\n",
"}\n",
"return $(_o) ;\n",
"}\n",
"else\n",
"{\n",
"return $(<) ;\n",
"}\n",
"}\n",
"rule FQuote { return \\\\\\\"$(<)\\\\\\\" ; }\n",
"rule FDefines { return -D$(<) ; }\n",
"rule FIncludes { return -I$(<) ; }\n",
"rule FDirName\n",
"{\n",
"local _i ;\n",
"local _s = $(DOT) ;\n",
"for _i in $(<)\n",
"{\n",
"_s = $(_i:R=$(_s)) ;\n",
"}\n",
"return $(_s) ;\n",
"}\n",
"if $(OS2)\n",
"{\n",
"rule FQuote { return \\\"$(<)\\\" ; }\n",
"rule FIncludes { return /I$(<) ; }\n",
"}\n",
"else if $(NT)\n",
"{\n",
"rule FDefines { return /D$(<) ; }\n",
"rule FIncludes { return /I$(<) ; }\n",
"}\n",
"else if $(MAC)\n",
"{\n",
"rule FQuote { return \\\"$(<)\\\" ; }\n",
"rule FDefines { return \"-define '$(<)'\" ; }\n",
"rule FIncludes { return \\\"$(<:J=,)\\\" ; }\n",
"}\n",
"else if $(VMS)\n",
"{\n",
"rule FQuote { return \\\"\\\"\\\"$(<)\\\"\\\"\\\" ; }\n",
"rule FDefines { return \"/define=( $(<:J=,) )\" ; }\n",
"rule FIncludes { return \"/inc=( $(<:J=,) )\" ; }\n",
"rule FDirName\n",
"{\n",
"local _s _i ;\n",
"if ! $(<)\n",
"{\n",
"_s = $(DOT) ;\n",
"}\n",
"else \n",
"{\n",
"switch $(<[1])\n",
"{\n",
"case *:* : _s = $(<[1]) ;\n",
"case \\\\[*\\\\] : _s = $(<[1]) ;\n",
"case * : _s = [.$(<[1])] ;\n",
"}\n",
"for _i in [.$(<[2-])]\n",
"{\n",
"_s = $(_i:R=$(_s)) ;\n",
"}\n",
"}\n",
"return $(_s) ;\n",
"}\n",
"}\n",
"actions updated together piecemeal Archive\n",
"{\n",
"$(AR) $(<) $(>)\n",
"}\n",
"actions As\n",
"{\n",
"$(AS) $(ASFLAGS) $(ASHDRS) -o $(<) $(>)\n",
"}\n",
"actions C++\n",
"{\n",
"$(C++) -c -o $(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions Cc\n",
"{\n",
"$(CC) -c -o $(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions Chgrp\n",
"{\n",
"$(CHGRP) $(GROUP) $(<)\n",
"}\n",
"actions Chmod1\n",
"{\n",
"$(CHMOD) $(MODE) $(<)\n",
"}\n",
"actions Chown\n",
"{\n",
"$(CHOWN) $(OWNER) $(<)\n",
"}\n",
"actions piecemeal together existing Clean\n",
"{\n",
"$(RM) $(>)\n",
"}\n",
"actions File\n",
"{\n",
"$(CP) $(>) $(<)\n",
"}\n",
"actions GenFile1\n",
"{\n",
"$(>[1]) $(<) $(>[2-])\n",
"}\n",
"actions Fortran\n",
"{\n",
"$(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)\n",
"}\n",
"actions HardLink\n",
"{\n",
"$(RM) $(<) && $(LN) $(>) $(<)\n",
"}\n",
"actions Install\n",
"{\n",
"$(CP) $(>) $(<) \n",
"}\n",
"actions Lex\n",
"{\n",
"$(LEX) $(>)\n",
"}\n",
"actions LexMv\n",
"{\n",
"$(MV) lex.yy.c $(<)\n",
"}\n",
"actions Link bind NEEDLIBS\n",
"{\n",
"$(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS) \n",
"}\n",
"actions MkDir1\n",
"{\n",
"$(MKDIR) $(<)\n",
"}\n",
"actions together Ranlib\n",
"{\n",
"$(RANLIB) $(<)\n",
"}\n",
"actions quietly updated piecemeal together RmTemps\n",
"{\n",
"$(RM) $(>)\n",
"}\n",
"actions Shell\n",
"{\n",
"$(AWK) '\n",
"NR == 1 { print \"$(SHELLHEADER)\" }\n",
"NR == 1 && /^[#:]/ { next }\n",
"/^##/ { next }\n",
"{ print }\n",
"' < $(>) > $(<)\n",
"}\n",
"actions SoftLink\n",
"{\n",
"$(RM) $(<) && $(LN) -s $(>) $(<)\n",
"}\n",
"actions Yacc1\n",
"{\n",
"$(YACC) $(YACCFLAGS) $(>)\n",
"}\n",
"actions YaccMv\n",
"{\n",
"$(MV) $(YACCFILES).c $(<[1])\n",
"$(MV) $(YACCFILES).h $(<[2])\n",
"}\n",
"if $(RELOCATE)\n",
"{\n",
"actions C++\n",
"{\n",
"$(C++) -c $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions Cc\n",
"{\n",
"$(CC) -c $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions ignore CcMv\n",
"{\n",
"[ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)\n",
"}\n",
"}\n",
"if $(NOARUPDATE)\n",
"{\n",
"actions Archive\n",
"{\n",
"$(AR) $(<) $(>)\n",
"}\n",
"}\n",
"if $(UNIX)\n",
"{\n",
"actions GenFile1\n",
"{\n",
"PATH=\"$PATH:.\"\n",
"$(>[1]) $(<) $(>[2-])\n",
"}\n",
"}\n",
"if $(NT) && $(MSVCNT)\n",
"{\n",
"actions updated together piecemeal Archive\n",
"{\n",
"if exist $(<) set _$(<:B)_=$(<)\n",
"$(AR) /out:$(<) %_$(<:B)_% $(>)\n",
"}\n",
"actions As\n",
"{\n",
"$(AS) /Ml /p /v /w2 $(>) $(<) ,nul,nul;\n",
"}\n",
"actions Cc\n",
"{\n",
"$(CC) /c /Fo$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) /I$(STDHDRS) $(>)\n",
"}\n",
"actions C++\n",
"{\n",
"$(C++) /c /Fo$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) /I$(STDHDRS) /Tp$(>)\n",
"}\n",
"actions Link bind NEEDLIBS\n",
"{\n",
"$(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
"}\n",
"}\n",
"else if $(NT) && $(MSVC)\n",
"{\n",
"actions updated together piecemeal Archive\n",
"{\n",
"$(AR) $(<) -+$(>)\n",
"}\n",
"actions Cc\n",
"{\n",
"$(CC) /c /Fo$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions C++\n",
"{\n",
"$(C++) /c /Fo$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) /Tp$(>)\n",
"}\n",
"actions Link bind NEEDLIBS\n",
"{\n",
"$(LINK) $(LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
"}\n",
"}\n",
"else if $(NT) && $(BCCROOT)\n",
"{\n",
"actions updated together piecemeal Archive\n",
"{\n",
"$(AR) $(<) -+$(>)\n",
"}\n",
"actions Link bind NEEDLIBS\n",
"{\n",
"$(LINK) -e$(<) $(LINKFLAGS) $(UNDEFS) -L$(LINKLIBS) $(NEEDLIBS) $(>)\n",
"}\n",
"actions C++\n",
"{\n",
"$(C++) -c -o$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions Cc\n",
"{\n",
"$(CC) -c -o$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"}\n",
"else if $(OS2) && $(WATCOM)\n",
"{\n",
"actions together piecemeal Archive\n",
"{\n",
"$(AR) $(<) +-$(>) \n",
"}\n",
"actions Cc\n",
"{\n",
"$(CC) /Fo=$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions C++\n",
"{\n",
"$(C++) /Fo=$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)\n",
"}\n",
"actions Link bind NEEDLIBS\n",
"{\n",
"$(LINK) $(LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)\n",
"}\n",
"actions Shell\n",
"{\n",
"$(CP) $(>) $(<)\n",
"}\n",
"}\n",
"else if $(VMS)\n",
"{\n",
"actions updated together piecemeal Archive \n",
"{\n",
"lib/replace $(<) $(>[1]) ,$(>[2-])\n",
"}\n",
"actions Cc\n",
"{ \n",
"$(CC)/obj=$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>) \n",
"}\n",
"actions C++\n",
"{ \n",
"$(C++)/obj=$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>) \n",
"}\n",
"actions piecemeal together existing Clean\n",
"{\n",
"$(RM) $(>[1]);* ,$(>[2-]);*\n",
"}\n",
"actions together quietly CreLib\n",
"{\n",
"if f$search(\"$(<)\") .eqs. \"\" then lib/create $(<)\n",
"}\n",
"actions GenFile1\n",
"{\n",
"mcr $(>[1]) $(<) $(>[2-])\n",
"}\n",
"actions Link bind NEEDLIBS\n",
"{\n",
"$(LINK)/exe=$(<) $(LINKFLAGS) $(>:J=,) ,$(NEEDLIBS)/lib ,$(LINKLIBS)\n",
"}\n",
"actions quietly updated piecemeal together RmTemps\n",
"{\n",
"$(RM) $(>[1]);* ,$(>[2-]);*\n",
"}\n",
"actions Shell\n",
"{\n",
"$(CP) $(>) $(<)\n",
"}\n",
"}\n",
"else if $(MAC)\n",
"{\n",
"actions together Archive \n",
"{\n",
"$(LINK) -library -o $(<) $(>)\n",
"}\n",
"actions Cc\n",
"{\n",
"set -e MWCincludes $(CCHDRS)\n",
"$(CC) -o $(<) $(CCFLAGS) $(CCDEFS) $(>) \n",
"}\n",
"actions C++\n",
"{\n",
"set -e MWCincludes $(CCHDRS)\n",
"$(CC) -o $(<) $(C++FLAGS) $(CCDEFS) $(>) \n",
"}\n",
"actions Link bind NEEDLIBS\n",
"{\n",
"$(LINK) -o $(<) $(LINKFLAGS) $(>) $(NEEDLIBS) \"$(LINKLIBS)\"\n",
"}\n",
"}\n",
"if $(WIN98)\n",
"{\n",
"actions existing Clean\n",
"{\n",
"del $(>)\n",
"}\n",
"}\n",
"rule BULK { Bulk $(<) : $(>) ; }\n",
"rule FILE { File $(<) : $(>) ; }\n",
"rule HDRRULE { HdrRule $(<) : $(>) ; }\n",
"rule INSTALL { Install $(<) : $(>) ; }\n",
"rule LIBRARY { Library $(<) : $(>) ; }\n",
"rule LIBS { LinkLibraries $(<) : $(>) ; }\n",
"rule LINK { Link $(<) : $(>) ; }\n",
"rule MAIN { Main $(<) : $(>) ; }\n",
"rule SETUID { Setuid $(<) ; }\n",
"rule SHELL { Shell $(<) : $(>) ; }\n",
"rule UNDEFINES { Undefines $(<) : $(>) ; }\n",
"rule INSTALLBIN { InstallBin $(BINDIR) : $(<) ; }\n",
"rule INSTALLLIB { InstallLib $(LIBDIR) : $(<) ; }\n",
"rule INSTALLMAN { InstallMan $(MANDIR) : $(<) ; }\n",
"rule addDirName { $(<) += [ FDirName $(>) ] ; }\n",
"rule makeCommon { FStripCommon $(<) : $(>) ; }\n",
"rule _makeCommon { FStripCommon $(<) : $(>) ; }\n",
"rule makeDirName { $(<) = [ FDirName $(>) ] ; }\n",
"rule makeGrist { $(<) = [ FGrist $(>) ] ; }\n",
"rule makeGristedName { $(<) = [ FGristSourceFiles $(>) ] ; }\n",
"rule makeRelPath { $(<[1]) = [ FRelPath $(<[2-]) : $(>) ] ; }\n",
"rule makeString { $(<) = $(>:J) ; }\n",
"rule makeSubDir { $(<) = [ FSubDir $(>) ] ; }\n",
"rule makeSuffixed { $(<[1]) = [ FAppendSuffix $(>) : $(<[2]) ] ; }\n",
"include $(JAMFILE) ;\n",
0 };
jam-2.5/jambase.h 0100440 0000503 0000454 00000000565 07651415177 013053 0 ustar seiwald team /*
* 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[];
jam-2.5/jamgram.c 0100640 0000503 0000454 00000070564 10111167466 013060 0 ustar seiwald team #ifndef lint
static char const
yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28.2.1 2001/07/19 05:46:39 peter Exp $";
#endif
#include
#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)
#if defined(__cplusplus) || __STDC__
static int yygrowstack(void);
#else
static int yygrowstack();
#endif
#define YYPREFIX "yy"
#line 85 "jamgram.y"
#include "jam.h"
#include "lists.h"
#include "variable.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 *, int *))0
# define P0 (PARSE *)0
# define S0 (char *)0
# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
# define pbreak( l,f ) parse_make( compile_break,l,P0,P0,S0,S0,f )
# 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,l,r ) parse_make( compile_setcomp,l,r,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 60 "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 BREAK_t 276
#define CASE_t 277
#define CONTINUE_t 278
#define DEFAULT_t 279
#define ELSE_t 280
#define EXISTING_t 281
#define FOR_t 282
#define IF_t 283
#define IGNORE_t 284
#define IN_t 285
#define INCLUDE_t 286
#define LOCAL_t 287
#define MAXLINE_t 288
#define ON_t 289
#define PIECEMEAL_t 290
#define QUIETLY_t 291
#define RETURN_t 292
#define RULE_t 293
#define SWITCH_t 294
#define TOGETHER_t 295
#define UPDATED_t 296
#define WHILE_t 297
#define _LBRACE_t 298
#define _BAR_t 299
#define _BARBAR_t 300
#define _RBRACE_t 301
#define ARG 302
#define STRING 303
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, 3, 3, 13, 14, 3, 7, 7, 7, 7,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 8, 8, 15, 10, 10, 10,
6, 6, 4, 16, 16, 5, 18, 5, 17, 17,
17, 11, 11, 19, 19, 19, 19, 19, 19, 19,
12, 12,
};
const short yylen[] = { 2,
0, 1, 0, 1, 1, 2, 4, 6, 3, 3,
3, 4, 6, 3, 3, 3, 7, 5, 5, 7,
5, 6, 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, 0, 3, 1,
1, 3, 1, 0, 2, 1, 0, 4, 2, 4,
4, 0, 2, 1, 1, 1, 1, 1, 1, 2,
0, 2,
};
const short yydefred[] = { 0,
57, 62, 54, 54, 0, 0, 54, 54, 0, 54,
0, 54, 0, 0, 56, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 4, 0, 6, 28,
27, 29, 0, 54, 0, 0, 54, 0, 54, 0,
69, 66, 0, 68, 67, 65, 64, 0, 63, 14,
55, 15, 54, 43, 0, 54, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 10, 0, 54,
23, 16, 0, 0, 0, 0, 9, 30, 0, 54,
11, 0, 0, 59, 58, 70, 54, 0, 0, 44,
42, 0, 0, 0, 34, 35, 0, 36, 37, 0,
0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
54, 52, 12, 54, 54, 72, 24, 0, 0, 0,
49, 0, 0, 18, 46, 21, 0, 61, 60, 0,
0, 0, 8, 22, 0, 13, 25, 17, 20, 47,
0, 26,
};
const short yydgoto[] = { 16,
37, 38, 18, 45, 28, 46, 47, 118, 29, 84,
21, 98, 140, 151, 119, 23, 50, 20, 59,
};
const short yysindex[] = { -40,
0, 0, 0, 0, -295, -233, 0, 0, -240, 0,
-284, 0, -233, -40, 0, 0, 0, -40, -7, -241,
49, -242, -240, -232, -239, -233, -233, -231, -75, -220,
-195, 34, -210, -243, -226, -59, 0, -223, 0, 0,
0, 0, -174, 0, -165, -164, 0, -240, 0, -173,
0, 0, -199, 0, 0, 0, 0, -166, 0, 0,
0, 0, 0, 0, -154, 0, -233, -233, -233, -233,
-233, -233, -233, -233, -40, -233, -233, 0, -40, 0,
0, 0, -153, -179, -157, -40, 0, 0, -42, 0,
0, -144, -185, 0, 0, 0, 0, -171, -170, 0,
0, -54, 94, 94, 0, 0, -54, 0, 0, -160,
88, 88, 0, -140, -243, -40, -151, -139, -157, -134,
0, 0, 0, 0, 0, 0, 0, -40, -149, -40,
0, -131, -93, 0, 0, 0, -85, 0, 0, -121,
-115, 34, 0, 0, -40, 0, 0, 0, 0, 0,
-105, 0,
};
const short yyrindex[] = { 197,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, -103, 0, 0, 0, 3, -235, 0,
0, 0, -110, 0, 0, 0, 0, -94, 0, 0,
0, 0, 0, -96, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, -246, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, -95, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, -103, 0, 0, 0, 4, 0,
0, 0, -84, 0, -79, -103, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, -202, -224, -176, 0, 0, -81, 0, 0, 0,
-257, -209, 0, 0, -96, -103, 0, 0, -79, 0,
0, 0, 0, 0, 0, 0, 0, -103, 1, 4,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, -237, 0, 0, 0, 0, 0,
0, 0,
};
const short yygindex[] = { 0,
26, -65, -32, 5, 2, -43, 131, 108, 66, 113,
0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#define YYTABLESIZE 364
const short yytable[] = { 81,
19, 19, 5, 3, 40, 94, 25, 22, 24, 110,
32, 30, 31, 113, 33, 19, 35, 34, 51, 19,
120, 49, 60, 26, 61, 17, 51, 27, 54, 54,
1, 1, 62, 19, 38, 38, 54, 38, 1, 3,
40, 40, 40, 39, 78, 63, 122, 48, 89, 93,
132, 92, 41, 66, 82, 33, 33, 33, 83, 33,
15, 15, 141, 3, 143, 33, 54, 99, 15, 79,
101, 85, 80, 38, 38, 38, 19, 87, 36, 150,
19, 139, 39, 39, 114, 39, 1, 19, 41, 41,
41, 64, 65, 88, 125, 33, 33, 33, 90, 95,
91, 126, 96, 67, 68, 69, 124, 100, 97, 149,
115, 70, 71, 72, 73, 74, 15, 19, 116, 117,
123, 39, 39, 39, 130, 137, 127, 128, 138, 19,
142, 19, 102, 103, 104, 105, 106, 107, 108, 109,
129, 111, 112, 19, 76, 77, 19, 53, 53, 53,
133, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 134, 53, 31, 31, 31, 136, 31, 53, 144,
145, 31, 31, 31, 31, 31, 32, 32, 32, 146,
32, 147, 67, 68, 69, 148, 32, 53, 53, 53,
70, 71, 72, 73, 74, 152, 1, 3, 67, 68,
69, 48, 71, 31, 31, 31, 70, 71, 72, 73,
74, 70, 71, 50, 73, 74, 32, 32, 32, 121,
40, 45, 75, 76, 77, 41, 135, 131, 42, 0,
0, 1, 0, 2, 0, 3, 43, 4, 86, 76,
77, 5, 6, 0, 0, 7, 8, 0, 9, 0,
0, 10, 11, 12, 0, 40, 13, 14, 0, 0,
41, 15, 0, 42, 0, 0, 0, 0, 0, 0,
0, 43, 19, 0, 19, 0, 19, 19, 19, 5,
3, 44, 19, 19, 0, 0, 19, 19, 0, 19,
0, 0, 19, 19, 19, 0, 0, 19, 19, 0,
0, 19, 19, 5, 3, 1, 0, 2, 0, 3,
0, 4, 0, 0, 0, 5, 6, 0, 0, 7,
0, 0, 9, 0, 0, 10, 11, 12, 0, 51,
13, 14, 52, 0, 0, 15, 53, 0, 54, 55,
0, 0, 0, 56, 57, 67, 68, 69, 0, 0,
58, 67, 0, 70, 71, 72, 73, 74, 0, 70,
71, 72, 73, 74,
};
const short yycheck[] = { 32,
0, 0, 0, 0, 262, 49, 302, 3, 4, 75,
9, 7, 8, 79, 10, 14, 12, 302, 265, 18,
86, 20, 265, 257, 23, 0, 273, 261, 264, 265,
272, 272, 265, 32, 259, 260, 272, 262, 272, 277,
298, 299, 300, 18, 265, 285, 90, 289, 44, 48,
116, 47, 262, 285, 265, 258, 259, 260, 302, 262,
302, 302, 128, 301, 130, 268, 302, 63, 302, 265,
66, 298, 268, 298, 299, 300, 75, 301, 13, 145,
79, 125, 259, 260, 80, 262, 272, 86, 298, 299,
300, 26, 27, 268, 93, 298, 299, 300, 264, 273,
265, 97, 302, 258, 259, 260, 292, 262, 275, 142,
264, 266, 267, 268, 269, 270, 302, 116, 298, 277,
265, 298, 299, 300, 265, 121, 298, 298, 124, 128,
280, 130, 67, 68, 69, 70, 71, 72, 73, 74,
301, 76, 77, 142, 299, 300, 145, 258, 259, 260,
302, 262, 263, 264, 265, 266, 267, 268, 269, 270,
271, 301, 273, 258, 259, 260, 301, 262, 279, 301,
264, 266, 267, 268, 269, 270, 258, 259, 260, 265,
262, 303, 258, 259, 260, 301, 268, 298, 299, 300,
266, 267, 268, 269, 270, 301, 0, 301, 258, 259,
260, 298, 298, 298, 299, 300, 266, 267, 268, 269,
270, 266, 267, 298, 269, 270, 298, 299, 300, 89,
263, 301, 298, 299, 300, 268, 119, 115, 271, -1,
-1, 272, -1, 274, -1, 276, 279, 278, 298, 299,
300, 282, 283, -1, -1, 286, 287, -1, 289, -1,
-1, 292, 293, 294, -1, 263, 297, 298, -1, -1,
268, 302, -1, 271, -1, -1, -1, -1, -1, -1,
-1, 279, 272, -1, 274, -1, 276, 277, 278, 277,
277, 289, 282, 283, -1, -1, 286, 287, -1, 289,
-1, -1, 292, 293, 294, -1, -1, 297, 298, -1,
-1, 301, 302, 301, 301, 272, -1, 274, -1, 276,
-1, 278, -1, -1, -1, 282, 283, -1, -1, 286,
-1, -1, 289, -1, -1, 292, 293, 294, -1, 281,
297, 298, 284, -1, -1, 302, 288, -1, 290, 291,
-1, -1, -1, 295, 296, 258, 259, 260, -1, -1,
302, 258, -1, 266, 267, 268, 269, 270, -1, 266,
267, 268, 269, 270,
};
#define YYFINAL 16
#ifndef YYDEBUG
#define YYDEBUG 0
#endif
#define YYMAXTOKEN 303
#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","BREAK_t","CASE_t","CONTINUE_t","DEFAULT_t","ELSE_t","EXISTING_t",
"FOR_t","IF_t","IGNORE_t","IN_t","INCLUDE_t","LOCAL_t","MAXLINE_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 : BREAK_t list _SEMIC_t",
"rule : CONTINUE_t 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 params _LBRACE_t block _RBRACE_t",
"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",
"params :",
"params : ARG _COLON_t params",
"params : ARG",
"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",
"eflag : MAXLINE_t ARG",
"bindlist :",
"bindlist : BIND_t list",
};
#endif
#ifndef YYSTYPE
typedef int YYSTYPE;
#endif
#if YYDEBUG
#include
#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 130 "jamgram.y"
{ parse_save( yyvsp[0].parse ); }
break;
case 3:
#line 141 "jamgram.y"
{ yyval.parse = pnull(); }
break;
case 4:
#line 143 "jamgram.y"
{ yyval.parse = yyvsp[0].parse; }
break;
case 5:
#line 147 "jamgram.y"
{ yyval.parse = yyvsp[0].parse; }
break;
case 6:
#line 149 "jamgram.y"
{ yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); }
break;
case 7:
#line 151 "jamgram.y"
{ yyval.parse = plocal( yyvsp[-2].parse, pnull(), yyvsp[0].parse ); }
break;
case 8:
#line 153 "jamgram.y"
{ yyval.parse = plocal( yyvsp[-4].parse, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 9:
#line 157 "jamgram.y"
{ yyval.parse = yyvsp[-1].parse; }
break;
case 10:
#line 159 "jamgram.y"
{ yyval.parse = pincl( yyvsp[-1].parse ); }
break;
case 11:
#line 161 "jamgram.y"
{ yyval.parse = prule( yyvsp[-2].parse, yyvsp[-1].parse ); }
break;
case 12:
#line 163 "jamgram.y"
{ yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
break;
case 13:
#line 165 "jamgram.y"
{ yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
break;
case 14:
#line 167 "jamgram.y"
{ yyval.parse = pbreak( yyvsp[-1].parse, JMP_BREAK ); }
break;
case 15:
#line 169 "jamgram.y"
{ yyval.parse = pbreak( yyvsp[-1].parse, JMP_CONTINUE ); }
break;
case 16:
#line 171 "jamgram.y"
{ yyval.parse = pbreak( yyvsp[-1].parse, JMP_RETURN ); }
break;
case 17:
#line 173 "jamgram.y"
{ yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse ); }
break;
case 18:
#line 175 "jamgram.y"
{ yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); }
break;
case 19:
#line 177 "jamgram.y"
{ yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); }
break;
case 20:
#line 179 "jamgram.y"
{ yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); }
break;
case 21:
#line 181 "jamgram.y"
{ yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); }
break;
case 22:
#line 183 "jamgram.y"
{ yyval.parse = psetc( yyvsp[-4].string, yyvsp[-3].parse, yyvsp[-1].parse ); }
break;
case 23:
#line 185 "jamgram.y"
{ yyval.parse = pon( yyvsp[-1].parse, yyvsp[0].parse ); }
break;
case 24:
#line 187 "jamgram.y"
{ yymode( SCAN_STRING ); }
break;
case 25:
#line 189 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 26:
#line 191 "jamgram.y"
{ yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); }
break;
case 27:
#line 199 "jamgram.y"
{ yyval.number = VAR_SET; }
break;
case 28:
#line 201 "jamgram.y"
{ yyval.number = VAR_APPEND; }
break;
case 29:
#line 203 "jamgram.y"
{ yyval.number = VAR_DEFAULT; }
break;
case 30:
#line 205 "jamgram.y"
{ yyval.number = VAR_DEFAULT; }
break;
case 31:
#line 213 "jamgram.y"
{ yyval.parse = peval( EXPR_EXISTS, yyvsp[0].parse, pnull() ); }
break;
case 32:
#line 215 "jamgram.y"
{ yyval.parse = peval( EXPR_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 33:
#line 217 "jamgram.y"
{ yyval.parse = peval( EXPR_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 34:
#line 219 "jamgram.y"
{ yyval.parse = peval( EXPR_LESS, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 35:
#line 221 "jamgram.y"
{ yyval.parse = peval( EXPR_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 36:
#line 223 "jamgram.y"
{ yyval.parse = peval( EXPR_MORE, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 37:
#line 225 "jamgram.y"
{ yyval.parse = peval( EXPR_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 38:
#line 227 "jamgram.y"
{ yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 39:
#line 229 "jamgram.y"
{ yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 40:
#line 231 "jamgram.y"
{ yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 41:
#line 233 "jamgram.y"
{ yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 42:
#line 235 "jamgram.y"
{ yyval.parse = peval( EXPR_IN, yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 43:
#line 237 "jamgram.y"
{ yyval.parse = peval( EXPR_NOT, yyvsp[0].parse, pnull() ); }
break;
case 44:
#line 239 "jamgram.y"
{ yyval.parse = yyvsp[-1].parse; }
break;
case 45:
#line 249 "jamgram.y"
{ yyval.parse = P0; }
break;
case 46:
#line 251 "jamgram.y"
{ yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); }
break;
case 47:
#line 255 "jamgram.y"
{ yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); }
break;
case 48:
#line 264 "jamgram.y"
{ yyval.parse = P0; }
break;
case 49:
#line 266 "jamgram.y"
{ yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); }
break;
case 50:
#line 268 "jamgram.y"
{ yyval.parse = psnode( yyvsp[0].string, P0 ); }
break;
case 51:
#line 277 "jamgram.y"
{ yyval.parse = pnode( P0, yyvsp[0].parse ); }
break;
case 52:
#line 279 "jamgram.y"
{ yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); }
break;
case 53:
#line 289 "jamgram.y"
{ yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); }
break;
case 54:
#line 293 "jamgram.y"
{ yyval.parse = pnull(); yymode( SCAN_PUNCT ); }
break;
case 55:
#line 295 "jamgram.y"
{ yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); }
break;
case 56:
#line 299 "jamgram.y"
{ yyval.parse = plist( yyvsp[0].string ); }
break;
case 57:
#line 300 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 58:
#line 301 "jamgram.y"
{ yyval.parse = yyvsp[-1].parse; }
break;
case 59:
#line 310 "jamgram.y"
{ yyval.parse = prule( yyvsp[-1].parse, yyvsp[0].parse ); }
break;
case 60:
#line 312 "jamgram.y"
{ yyval.parse = pon( yyvsp[-2].parse, prule( yyvsp[-1].parse, yyvsp[0].parse ) ); }
break;
case 61:
#line 314 "jamgram.y"
{ yyval.parse = pon( yyvsp[-2].parse, yyvsp[0].parse ); }
break;
case 62:
#line 323 "jamgram.y"
{ yyval.number = 0; }
break;
case 63:
#line 325 "jamgram.y"
{ yyval.number = yyvsp[-1].number | yyvsp[0].number; }
break;
case 64:
#line 329 "jamgram.y"
{ yyval.number = RULE_UPDATED; }
break;
case 65:
#line 331 "jamgram.y"
{ yyval.number = RULE_TOGETHER; }
break;
case 66:
#line 333 "jamgram.y"
{ yyval.number = RULE_IGNORE; }
break;
case 67:
#line 335 "jamgram.y"
{ yyval.number = RULE_QUIETLY; }
break;
case 68:
#line 337 "jamgram.y"
{ yyval.number = RULE_PIECEMEAL; }
break;
case 69:
#line 339 "jamgram.y"
{ yyval.number = RULE_EXISTING; }
break;
case 70:
#line 341 "jamgram.y"
{ yyval.number = atoi( yyvsp[0].string ) * RULE_MAXLINE; }
break;
case 71:
#line 350 "jamgram.y"
{ yyval.parse = pnull(); }
break;
case 72:
#line 352 "jamgram.y"
{ yyval.parse = yyvsp[0].parse; }
break;
#line 877 "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);
}
jam-2.5/jamgram.h 0100640 0000503 0000454 00000002057 10111167466 013055 0 ustar seiwald team #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 BREAK_t 276
#define CASE_t 277
#define CONTINUE_t 278
#define DEFAULT_t 279
#define ELSE_t 280
#define EXISTING_t 281
#define FOR_t 282
#define IF_t 283
#define IGNORE_t 284
#define IN_t 285
#define INCLUDE_t 286
#define LOCAL_t 287
#define MAXLINE_t 288
#define ON_t 289
#define PIECEMEAL_t 290
#define QUIETLY_t 291
#define RETURN_t 292
#define RULE_t 293
#define SWITCH_t 294
#define TOGETHER_t 295
#define UPDATED_t 296
#define WHILE_t 297
#define _LBRACE_t 298
#define _BAR_t 299
#define _BARBAR_t 300
#define _RBRACE_t 301
#define ARG 302
#define STRING 303
jam-2.5/jamgram.y 0100640 0000503 0000454 00000023044 07651416443 013104 0 ustar seiwald team %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 BREAK_t
%token CASE_t
%token CONTINUE_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 MAXLINE_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 return LIST *.
* 01/22/01 (seiwald) - replace evaluate_if() with compile_eval()
* 01/24/01 (seiwald) - 'while' statement
* 03/23/01 (seiwald) - "[ on target rule ]" support
* 02/27/02 (seiwald) - un-break "expr : arg in list" syntax
* 03/02/02 (seiwald) - rules can be invoked via variable names
* 03/12/02 (seiwald) - set YYMAXDEPTH for big, right-recursive rules
* 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
* 06/21/02 (seiwald) - support for named parameters
* 10/22/02 (seiwald) - working return/break/continue statements
*/
%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 "variable.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 *, int *))0
# define P0 (PARSE *)0
# define S0 (char *)0
# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
# define pbreak( l,f ) parse_make( compile_break,l,P0,P0,S0,S0,f )
# 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,l,r ) parse_make( compile_setcomp,l,r,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 ); }
| BREAK_t list _SEMIC_t
{ $$.parse = pbreak( $2.parse, JMP_BREAK ); }
| CONTINUE_t list _SEMIC_t
{ $$.parse = pbreak( $2.parse, JMP_CONTINUE ); }
| RETURN_t list _SEMIC_t
{ $$.parse = pbreak( $2.parse, JMP_RETURN ); }
| 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 params _LBRACE_t block _RBRACE_t
{ $$.parse = psetc( $2.string, $3.parse, $5.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 = VAR_SET; }
| _PLUS_EQUALS_t
{ $$.number = VAR_APPEND; }
| _QUESTION_EQUALS_t
{ $$.number = VAR_DEFAULT; }
| DEFAULT_t _EQUALS_t
{ $$.number = VAR_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 ); }
;
/*
* params - optional parameter names to rule definition
* right-recursive rule so that params can be added in order.
*/
params : /* empty */
{ $$.parse = P0; }
| ARG _COLON_t params
{ $$.parse = psnode( $1.string, $3.parse ); }
| ARG
{ $$.parse = psnode( $1.string, P0 ); }
;
/*
* 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; }
| MAXLINE_t ARG
{ $$.number = atoi( $2.string ) * RULE_MAXLINE; }
;
/*
* bindlist - list of variable to bind for an action
*/
bindlist : /* empty */
{ $$.parse = pnull(); }
| BIND_t list
{ $$.parse = $2.parse; }
;
jam-2.5/jamgram.yy 0100440 0000503 0000454 00000020653 07651415177 013301 0 ustar seiwald team /*
* 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 return LIST *.
* 01/22/01 (seiwald) - replace evaluate_if() with compile_eval()
* 01/24/01 (seiwald) - 'while' statement
* 03/23/01 (seiwald) - "[ on target rule ]" support
* 02/27/02 (seiwald) - un-break "expr : arg in list" syntax
* 03/02/02 (seiwald) - rules can be invoked via variable names
* 03/12/02 (seiwald) - set YYMAXDEPTH for big, right-recursive rules
* 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
* 06/21/02 (seiwald) - support for named parameters
* 10/22/02 (seiwald) - working return/break/continue statements
*/
%token ARG STRING
%left `||` `|`
%left `&&` `&`
%left `=` `!=` `in`
%left `<` `<=` `>` `>=`
%left `!`
%{
#include "jam.h"
#include "lists.h"
#include "variable.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 *, int *))0
# define P0 (PARSE *)0
# define S0 (char *)0
# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
# define pbreak( l,f ) parse_make( compile_break,l,P0,P0,S0,S0,f )
# 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,l,r ) parse_make( compile_setcomp,l,r,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 ); }
| `break` list `;`
{ $$.parse = pbreak( $2.parse, JMP_BREAK ); }
| `continue` list `;`
{ $$.parse = pbreak( $2.parse, JMP_CONTINUE ); }
| `return` list `;`
{ $$.parse = pbreak( $2.parse, JMP_RETURN ); }
| `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 params `{` block `}`
{ $$.parse = psetc( $2.string, $3.parse, $5.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 = VAR_SET; }
| `+=`
{ $$.number = VAR_APPEND; }
| `?=`
{ $$.number = VAR_DEFAULT; }
| `default` `=`
{ $$.number = VAR_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 ); }
;
/*
* params - optional parameter names to rule definition
* right-recursive rule so that params can be added in order.
*/
params : /* empty */
{ $$.parse = P0; }
| ARG `:` params
{ $$.parse = psnode( $1.string, $3.parse ); }
| ARG
{ $$.parse = psnode( $1.string, P0 ); }
;
/*
* 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; }
| `maxline` ARG
{ $$.number = atoi( $2.string ) * RULE_MAXLINE; }
;
/*
* bindlist - list of variable to bind for an action
*/
bindlist : /* empty */
{ $$.parse = pnull(); }
| `bind` list
{ $$.parse = $2.parse; }
;
jam-2.5/jamgramtab.h 0100640 0000503 0000454 00000002043 07651416443 013546 0 ustar seiwald team { "!", _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 },
{ "break", BREAK_t },
{ "case", CASE_t },
{ "continue", CONTINUE_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 },
{ "maxline", MAXLINE_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 },
jam-2.5/lists.c 0100440 0000503 0000454 00000011231 07651415177 012572 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 11/04/02 (seiwald) - const-ing for string literals
* 12/09/02 (seiwald) - new list_printq() for writing lists to Jambase
*/
# include "jam.h"
# include "newstr.h"
# include "lists.h"
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,
const char *string,
int copy )
{
LIST *l;
if( DEBUG_LISTS )
printf( "list > %s <\n", string );
/* Copy/newstr as needed */
string = copy ? copystr( string ) : newstr( 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, nl->string, 1 );
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, l->string, 1 );
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_printq() - print a list of safely quoted strings to a file
*/
void
list_printq( FILE *out, LIST *l )
{
/* Dump each word, enclosed in "s */
/* Suitable for Jambase use. */
for( ; l; l = list_next( l ) )
{
const char *p = l->string;
const char *ep = p + strlen( p );
const char *op = p;
fputc( '\n', out );
fputc( '\t', out );
fputc( '"', out );
/* Any embedded "'s? Escape them */
while( p = (char *)memchr( op, '"', ep - op ) )
{
fwrite( op, p - op, 1, out );
fputc( '\\', out );
fputc( '"', out );
op = p + 1;
}
/* Write remainder */
fwrite( op, ep - op, 1, out );
fputc( '"', out );
fputc( ' ', out );
}
}
/*
* 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] );
}
}
jam-2.5/lists.h 0100440 0000503 0000454 00000004322 07651415177 012602 0 ustar seiwald team /*
* 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_printq() - print a list of safely quoted strings to a file
* 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()
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 11/04/02 (seiwald) - const-ing for string literals
* 12/09/02 (seiwald) - new list_printq() for writing lists to Jambase
*/
/*
* LIST - list of strings
*/
typedef struct _list LIST;
struct _list {
LIST *next;
LIST *tail; /* only valid in head node */
const 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, const char *string, int copy );
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 );
jam-2.5/make.c 0100440 0000503 0000454 00000032445 07651415177 012363 0 ustar seiwald team /*
* 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)
* 07/17/02 (seiwald) - TEMPORARY sources for headers now get built
* 09/19/02 (seiwald) - new -d displays
* 09/23/02 (seiwald) - suppress "...using temp..." in default output
* 09/28/02 (seiwald) - make0() takes parent pointer; new -dc display
* 11/04/02 (seiwald) - const-ing for string literals
* 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
* 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
* 01/03/03 (seiwald) - T_FATE_NEWER once again gets set with missing parent
* 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET
* 04/04/03 (seiwald) - fix INTERNAL node binding to avoid T_BIND_PARENTS
*/
# 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, TARGET *p, int depth,
COUNTS *counts, int anyhow );
static TARGETS *make0sort( TARGETS *c );
static const 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 */
"needtmp", /* T_FATE_NEEDTMP */
"old", /* T_FATE_OUTDATED */
"update", /* T_FATE_UPDATE */
"nofind", /* T_FATE_CANTFIND */
"nomake" /* T_FATE_CANTMAKE */
} ;
static const 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,
const 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, 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,
TARGET *p, /* parent */
int depth, /* for display purposes */
COUNTS *counts, /* for reporting */
int anyhow ) /* forcibly touch all (real) targets */
{
TARGETS *c, *d, *incs;
TARGET *ptime = t;
time_t last, leaf, hlast;
int fate;
const char *flag = "";
SETTINGS *s;
/*
* Step 1: initialize
*/
if( DEBUG_MAKEPROG )
printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
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. */
s = copysettings( t->settings );
pushsettings( s );
/* 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;
}
/* INTERNAL, NOTFILE header nodes have the time of their parents */
if( p && t->flags & T_FLAG_INTERNAL )
ptime = p;
/* If temp file doesn't exist but parent does, use parent */
if( p && t->flags & T_FLAG_TEMP &&
t->binding == T_BIND_MISSING &&
p->binding != T_BIND_MISSING )
{
t->binding = T_BIND_PARENTS;
ptime = p;
}
/* Step 2c: If its a file, search for headers. */
if( t->binding == T_BIND_EXISTS )
headers( t );
/* Step 2d: reset "on target" variables */
popsettings( s );
freesettings( s );
/*
* Pause for a little progress reporting
*/
if( DEBUG_MAKEPROG )
{
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 & headers
*/
/* Step 3a: recursively make0() dependents */
for( c = t->depends; c; c = c->next )
{
int internal = t->flags & T_FLAG_INTERNAL;
if( DEBUG_DEPENDS )
printf( "%s \"%s\" : \"%s\" ;\n",
internal ? "Includes" : "Depends",
t->name, c->target->name );
/* Warn about circular deps, except for includes, */
/* which include each other alot. */
if( c->target->fate == T_FATE_INIT )
make0( c->target, ptime, depth + 1, counts, anyhow );
else if( c->target->fate == T_FATE_MAKING && !internal )
printf( "warning: %s depends on itself\n", c->target->name );
}
/* Step 3b: recursively make0() internal includes node */
if( t->includes )
make0( t->includes, p, depth + 1, counts, anyhow );
/* Step 3c: add dependents' includes to our direct dependencies */
incs = 0;
for( c = t->depends; c; c = c->next )
if( c->target->includes )
incs = targetentry( incs, c->target->includes );
t->depends = targetchain( t->depends, incs );
/*
* Step 4: compute time & fate
*/
/* Step 4a: pick up dependents' time and fate */
last = 0;
leaf = 0;
fate = T_FATE_STABLE;
for( c = t->depends; c; c = c->next )
{
/* If LEAVES has been applied, we only heed the timestamps of */
/* the leaf source nodes. */
leaf = max( leaf, c->target->leaf );
if( t->flags & T_FLAG_LEAVES )
{
last = leaf;
continue;
}
last = max( last, c->target->time );
fate = max( fate, c->target->fate );
}
/* Step 4b: pick up included headers time */
/*
* If a header is newer than a temp source that includes it,
* the temp source will need building.
*/
hlast = t->includes ? t->includes->time : 0;
/* Step 4c: handle NOUPDATE oddity */
/*
* If a NOUPDATE file exists, make dependents eternally old.
* Don't inherit our fate from our dependents. Decide fate
* based only upon other flags and our binding (done later).
*/
if( t->flags & T_FLAG_NOUPDATE )
{
last = 0;
t->time = 0;
fate = T_FATE_STABLE;
}
/* Step 4d: 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 temp's headers newer than parent, make temp.
If deliberately touched, make it.
If up-to-date temp file present, use it.
If target newer than non-notfile parent, mark target newer.
Otherwise, stable!
Note this block runs from least to most stable:
as we make it further down the list, the target's
fate is getting stabler.
*/
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 > p->time )
{
fate = T_FATE_NEEDTMP;
}
else if( t->binding == T_BIND_PARENTS && hlast > p->time )
{
fate = T_FATE_NEEDTMP;
}
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 && p &&
p->binding != T_BIND_UNBOUND && t->time > p->time )
{
fate = T_FATE_NEWER;
}
else
{
fate = T_FATE_STABLE;
}
/* Step 4e: 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->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 4f: 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 5: sort dependents by their update time.
*/
if( globs.newestfirst )
t->depends = make0sort( t->depends );
/*
* Step 6: a little harmless tabulating for tracing purposes
*/
/* Don't count or report interal includes nodes. */
if( t->flags & T_FLAG_INTERNAL )
return;
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 && p && t->time > p->time )
flag = "*";
if( DEBUG_MAKEPROG )
printf( "made%s\t%s\t%s%s\n",
flag, target_fate[ t->fate ],
spaces( depth ), t->name );
if( DEBUG_CAUSES &&
t->fate >= T_FATE_NEWER &&
t->fate <= T_FATE_MISSING )
printf( "%s %s\n", target_fate[ t->fate ], 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;
}
jam-2.5/make.h 0100440 0000503 0000454 00000000520 07651415177 012355 0 ustar seiwald team /*
* 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
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
int make( int n_targets, const char **targets, int anyhow );
int make1( TARGET *t );
jam-2.5/make1.c 0100440 0000503 0000454 00000040543 07651415177 012442 0 ustar seiwald team /*
* 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, 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.
* 02/07/01 (seiwald) - Fix jam -d0 return status.
* 01/21/02 (seiwald) - new -q to quit quickly on build failure
* 02/28/02 (seiwald) - don't delete 'actions updated' targets on failure
* 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
* 07/17/02 (seiwald) - TEMPORARY sources for headers now get built
* 09/23/02 (seiwald) - "...using temp..." only displayed on -da now.
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 11/04/02 (seiwald) - const-ing for string literals
* 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
*/
# 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;
/* 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( c = t->depends; 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;
const 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( c = t->depends; 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_MAKEQ )
printf( "...using %s...\n", t->name );
break;
case T_FATE_TOUCHED:
case T_FATE_MISSING:
case T_FATE_NEEDTMP:
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, maxline;
/* 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.
*
* Max line length is the action specific maxline or, if not
* given or bigger than MAXLINE, MAXLINE.
*/
start = 0;
chunk = length = list_length( ns );
maxline = rule->flags / RULE_MAXLINE;
maxline = maxline && maxline < MAXLINE ? maxline : MAXLINE;
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 ),
maxline );
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, t->boundname, 1 );
}
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, t->boundname, 1 );
}
/* 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 );
}
jam-2.5/mkjambase.c 0100440 0000503 0000454 00000004160 07651415177 013371 0 ustar seiwald team /*
* 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.
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include
# include
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, "const 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;
}
jam-2.5/newstr.c 0100440 0000503 0000454 00000003556 07651415177 012771 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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.
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "newstr.h"
# include "hash.h"
typedef const char *STRING;
static struct hash *strhash = 0;
static int strtotal = 0;
/*
* newstr() - return a malloc'ed copy of a string
*/
const char *
newstr( const 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()
*/
const char *
copystr( const char *s )
{
return s;
}
/*
* freestr() - free a string returned by newstr() or copystr()
*/
void
freestr( const char *s )
{
}
/*
* donestr() - free string tables
*/
void
donestr()
{
hashdone( strhash );
if( DEBUG_MEM )
printf( "%dK in strings\n", strtotal / 1024 );
}
jam-2.5/newstr.h 0100440 0000503 0000454 00000000546 07651415177 012772 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* newstr.h - string manipulation routines
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
const char *newstr( const char *string );
const char *copystr( const char *s );
void freestr( const char *s );
void donestr();
jam-2.5/option.c 0100440 0000503 0000454 00000003315 07651415200 012733 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* option.c - command line option processing
*
* {o >o
* \<>) "Process command line options as defined in .
* Return the number of argv[] elements used up by options,
* or -1 if an invalid option flag was given or an argument
* was supplied for an option that does not require one."
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "option.h"
int
getoptions(
int argc,
char **argv,
const 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++ )
{
const 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
*/
const 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;
}
jam-2.5/option.h 0100440 0000503 0000454 00000001070 07651415200 012734 0 ustar seiwald team /*
* 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."
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
typedef struct option
{
char flag; /* filled in by getoption() */
const char *val; /* set to random address if true */
} option;
# define N_OPTS 256
int getoptions( int argc, char **argv, const char *opts, option *optv );
const char * getoptval( option *optv, char opt, int subopt );
jam-2.5/parse.c 0100440 0000503 0000454 00000004140 07651415200 012532 0 ustar seiwald team /*
* Copyright 1993, 2000 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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 *.
* 10/22/02 (seiwald) - working return/break/continue statements
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "scan.h"
# include "newstr.h"
static PARSE *yypsave;
void
parse_file( const 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;
int jmp = 0; /* JMP_NONE */
/* $(<) 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. */
list_free( (*(p->func))( p, &l, &jmp ) );
parse_free( p );
}
}
void
parse_save( PARSE *p )
{
yypsave = p;
}
PARSE *
parse_make(
LIST *(*func)( PARSE *p, LOL *args, int *jmp ),
PARSE *left,
PARSE *right,
PARSE *third,
const char *string,
const 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 );
}
jam-2.5/parse.h 0100440 0000503 0000454 00000001537 07651415200 012546 0 ustar seiwald team /*
* 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
*
* 10/22/02 (seiwald) - working return/break/continue statements
* 11/04/02 (seiwald) - const-ing for string literals
*/
/*
* parse tree node
*/
typedef struct _PARSE PARSE;
struct _PARSE {
LIST *(*func)( PARSE *p, LOL *args, int *jmp );
PARSE *left;
PARSE *right;
PARSE *third;
const char *string;
const char *string1;
int num;
int refs;
} ;
void parse_file( const char *f );
void parse_save( PARSE *p );
PARSE * parse_make(
LIST *(*func)( PARSE *p, LOL *args, int *jmp ),
PARSE *left,
PARSE *right,
PARSE *third,
const char *string,
const char *string1,
int num );
void parse_refer( PARSE *p );
void parse_free( PARSE *p );
jam-2.5/patchlevel.h 0100640 0000503 0000454 00000000237 10111166175 013560 0 ustar seiwald team /* Keep JAMVERSYM in sync with VERSION. */
/* It can be accessed as $(JAMVERSION) in the Jamfile. */
#define VERSION "2.5"
#define JAMVERSYM "JAMVERSION=2.5"
jam-2.5/pathmac.c 0100440 0000503 0000454 00000014333 07651415200 013042 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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.
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "pathsys.h"
# ifdef OS_MAC
# define DELIM ':'
/*
* path_parse() - split a file name into dir/base/suffix/member
*/
void
path_parse(
const char *file,
PATHNAME *f )
{
const char *p, *q;
const char *end;
memset( (char *)f, 0, sizeof( *f ) );
/* Look for */
if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
{
f->f_grist.ptr = file;
f->f_grist.len = p - file;
file = p + 1;
}
/* Look for dir: */
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(
const 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 */
jam-2.5/pathsys.h 0100440 0000503 0000454 00000002325 07651415200 013123 0 ustar seiwald team /*
* 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
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
/*
* PATHNAME - a name of a file, broken into dir/base/suffix(member)
*
* is salt to distinguish between targets that otherwise would
* have the same name: it never appears in the bound name of a target.
* (member) is an archive member name: the syntax is arbitrary, but must
* agree in 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 {
const 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( const char *file, PATHNAME *f );
void path_parent( PATHNAME *f );
jam-2.5/pathunix.c 0100440 0000503 0000454 00000012212 07651415200 013257 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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 off \ handling on UNIX, on by accident
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "pathsys.h"
# ifdef USE_PATHUNIX
/*
* path_parse() - split a file name into dir/base/suffix/member
*/
void
path_parse(
const char *file,
PATHNAME *f )
{
const char *p, *q;
const char *end;
memset( (char *)f, 0, sizeof( *f ) );
/* Look for */
if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
{
f->f_grist.ptr = file;
f->f_grist.len = p - file;
file = p + 1;
}
/* Look for dir/ */
p = strrchr( file, '/' );
# 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 */
jam-2.5/pathvms.c 0100440 0000503 0000454 00000021256 07651415200 013111 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "pathsys.h"
# ifdef OS_VMS
# define DEBUG
/*
* path_parse() - split a file name into dir/base/suffix/member
*/
void
path_parse(
const char *file,
PATHNAME *f )
{
const char *p, *q;
const char *end;
memset( (char *)f, 0, sizeof( *f ) );
/* Look for */
if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
{
f->f_grist.ptr = file;
f->f_grist.len = p - file;
file = p + 1;
}
/* Look for dev:[dir] or dev: */
if( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) )
{
f->f_dir.ptr = file;
f->f_dir.len = p + 1 - file;
file = p + 1;
}
end = file + strlen( file );
/* Look for (member) */
if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
{
f->f_member.ptr = p + 1;
f->f_member.len = end - p - 2;
end = p;
}
/* Look for .suffix */
/* This would be memrchr() */
p = 0;
q = file;
while( q = (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(
const char *buf,
int len,
struct dirinf *i )
{
const 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( (char *)buf, ':', len ) )
{
i->dev.ptr = (char *)buf;
i->dev.len = p + 1 - buf;
i->dir.ptr = (char *)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 = (char *)buf;
i->dev.len = 0;
i->dir.ptr = (char *)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 */
jam-2.5/regexp.c 0100440 0000503 0000454 00000076672 07651415200 012735 0 ustar seiwald team /*
* regcomp and regexec -- regsub and regerror are elsewhere
*
* Copyright (c) 1986 by University of Toronto.
* Written by Henry Spencer. Not derived from licensed software.
*
* Permission is granted to anyone to use this software for any
* purpose on any computer system, and to redistribute it freely,
* subject to the following restrictions:
*
* 1. The author is not responsible for the consequences of use of
* this software, no matter how awful, even if they arise
* from defects in it.
*
* 2. The origin of this software must not be misrepresented, either
* by explicit claim or by omission.
*
* 3. Altered versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
*** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
*** to assist in implementing egrep.
*** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
*** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
*** as in BSD grep and ex.
*** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
*** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
*** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
*** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
*** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald
*** seiwald@vix.com, on 28 August 1993, for use in jam. Regmagic.h
*** was moved into regexp.h, and the include of regexp.h now uses "'s
*** to avoid conflicting with the system regexp.h. Const, bless its
*** soul, was removed so it can compile everywhere. The declaration
*** of strchr() was in conflict on AIX, so it was removed (as it is
*** happily defined in string.h).
*** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald
*** seiwald@perforce.com, on 20 January 2000, to use function prototypes.
*** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald
*** seiwald@perforce.com, on 05 November 2002, to const string literals.
*
* Beware that some of this code is subtly aware of the way operator
* precedence is structured in regular expressions. Serious changes in
* regular-expression syntax might require a total rethink.
*/
#include "regexp.h"
#include
#include
#ifndef ultrix
#include
#endif
#include
/*
* The "internal use only" fields in regexp.h are present to pass info from
* compile to execute that permits the execute phase to run lots faster on
* simple cases. They are:
*
* regstart char that must begin a match; '\0' if none obvious
* reganch is the match anchored (at beginning-of-line only)?
* regmust string (pointer into program) that match must include, or NULL
* regmlen length of regmust string
*
* Regstart and reganch permit very fast decisions on suitable starting points
* for a match, cutting down the work a lot. Regmust permits fast rejection
* of lines that cannot possibly match. The regmust tests are costly enough
* that regcomp() supplies a regmust only if the r.e. contains something
* potentially expensive (at present, the only such thing detected is * or +
* at the start of the r.e., which can involve a lot of backup). Regmlen is
* supplied because the test in regexec() needs it and regcomp() is computing
* it anyway.
*/
/*
* Structure for regexp "program". This is essentially a linear encoding
* of a nondeterministic finite-state machine (aka syntax charts or
* "railroad normal form" in parsing technology). Each node is an opcode
* plus a "next" pointer, possibly plus an operand. "Next" pointers of
* all nodes except BRANCH implement concatenation; a "next" pointer with
* a BRANCH on both ends of it is connecting two alternatives. (Here we
* have one of the subtle syntax dependencies: an individual BRANCH (as
* opposed to a collection of them) is never concatenated with anything
* because of operator precedence.) The operand of some types of node is
* a literal string; for others, it is a node leading into a sub-FSM. In
* particular, the operand of a BRANCH node is the first node of the branch.
* (NB this is *not* a tree structure: the tail of the branch connects
* to the thing following the set of BRANCHes.) The opcodes are:
*/
/* definition number opnd? meaning */
#define END 0 /* no End of program. */
#define BOL 1 /* no Match "" at beginning of line. */
#define EOL 2 /* no Match "" at end of line. */
#define ANY 3 /* no Match any one character. */
#define ANYOF 4 /* str Match any character in this string. */
#define ANYBUT 5 /* str Match any character not in this string. */
#define BRANCH 6 /* node Match this alternative, or the next... */
#define BACK 7 /* no Match "", "next" ptr points backward. */
#define EXACTLY 8 /* str Match this string. */
#define NOTHING 9 /* no Match empty string. */
#define STAR 10 /* node Match this (simple) thing 0 or more times. */
#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */
#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */
#define OPEN 20 /* no Mark this point in input as start of #n. */
/* OPEN+1 is number 1, etc. */
#define CLOSE 30 /* no Analogous to OPEN. */
/*
* Opcode notes:
*
* BRANCH The set of branches constituting a single choice are hooked
* together with their "next" pointers, since precedence prevents
* anything being concatenated to any individual branch. The
* "next" pointer of the last BRANCH in a choice points to the
* thing following the whole choice. This is also where the
* final "next" pointer of each individual branch points; each
* branch starts with the operand node of a BRANCH node.
*
* BACK Normal "next" pointers all implicitly point forward; BACK
* exists to make loop structures possible.
*
* STAR,PLUS '?', and complex '*' and '+', are implemented as circular
* BRANCH structures using BACK. Simple cases (one character
* per match) are implemented with STAR and PLUS for speed
* and to minimize recursive plunges.
*
* OPEN,CLOSE ...are numbered at compile time.
*/
/*
* A node is one char of opcode followed by two chars of "next" pointer.
* "Next" pointers are stored as two 8-bit pieces, high order first. The
* value is a positive offset from the opcode of the node containing it.
* An operand, if any, simply follows the node. (Note that much of the
* code generation knows about this implicit relationship.)
*
* Using two bytes for the "next" pointer is vast overkill for most things,
* but allows patterns to get big without disasters.
*/
#define OP(p) (*(p))
#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
#define OPERAND(p) ((p) + 3)
/*
* See regmagic.h for one further detail of program structure.
*/
/*
* Utility definitions.
*/
#ifndef CHARBITS
#define UCHARAT(p) ((int)*(unsigned char *)(p))
#else
#define UCHARAT(p) ((int)*(p)&CHARBITS)
#endif
#define FAIL(m) { regerror(m); return(NULL); }
#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
/*
* Flags to be passed up and down.
*/
#define HASWIDTH 01 /* Known never to match null string. */
#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
#define SPSTART 04 /* Starts with * or +. */
#define WORST 0 /* Worst case. */
/*
* Global work variables for regcomp().
*/
static char *regparse; /* Input-scan pointer. */
static int regnpar; /* () count. */
static char regdummy;
static char *regcode; /* Code-emit pointer; ®dummy = don't. */
static long regsize; /* Code size. */
/*
* Forward declarations for regcomp()'s friends.
*/
#ifndef STATIC
#define STATIC static
#endif
STATIC char *reg( int paren, int *flagp );
STATIC char *regbranch( int *flagp );
STATIC char *regpiece( int *flagp );
STATIC char *regatom( int *flagp );
STATIC char *regnode( int op );
STATIC char *regnext( register char *p );
STATIC void regc( int b );
STATIC void reginsert( char op, char *opnd );
STATIC void regtail( char *p, char *val );
STATIC void regoptail( char *p, char *val );
#ifdef STRCSPN
STATIC int strcspn();
#endif
/*
- regcomp - compile a regular expression into internal code
*
* We can't allocate space until we know how big the compiled form will be,
* but we can't compile it (and thus know how big it is) until we've got a
* place to put the code. So we cheat: we compile it twice, once with code
* generation turned off and size counting turned on, and once "for real".
* This also means that we don't allocate space until we are sure that the
* thing really will compile successfully, and we never have to move the
* code and thus invalidate pointers into it. (Note that it has to be in
* one piece because free() must be able to free it all.)
*
* Beware that the optimization-preparation code in here knows about some
* of the structure of the compiled regexp.
*/
regexp *
regcomp( const char *exp )
{
register regexp *r;
register char *scan;
register char *longest;
register unsigned len;
int flags;
if (exp == NULL)
FAIL("NULL argument");
/* First pass: determine size, legality. */
#ifdef notdef
if (exp[0] == '.' && exp[1] == '*') exp += 2; /* aid grep */
#endif
regparse = (char *)exp;
regnpar = 1;
regsize = 0L;
regcode = ®dummy;
regc(MAGIC);
if (reg(0, &flags) == NULL)
return(NULL);
/* Small enough for pointer-storage convention? */
if (regsize >= 32767L) /* Probably could be 65535L. */
FAIL("regexp too big");
/* Allocate space. */
r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
if (r == NULL)
FAIL("out of space");
/* Second pass: emit code. */
regparse = (char *)exp;
regnpar = 1;
regcode = r->program;
regc(MAGIC);
if (reg(0, &flags) == NULL)
return(NULL);
/* Dig out information for optimizations. */
r->regstart = '\0'; /* Worst-case defaults. */
r->reganch = 0;
r->regmust = NULL;
r->regmlen = 0;
scan = r->program+1; /* First BRANCH. */
if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
scan = OPERAND(scan);
/* Starting-point info. */
if (OP(scan) == EXACTLY)
r->regstart = *OPERAND(scan);
else if (OP(scan) == BOL)
r->reganch++;
/*
* If there's something expensive in the r.e., find the
* longest literal string that must appear and make it the
* regmust. Resolve ties in favor of later strings, since
* the regstart check works with the beginning of the r.e.
* and avoiding duplication strengthens checking. Not a
* strong reason, but sufficient in the absence of others.
*/
if (flags&SPSTART) {
longest = NULL;
len = 0;
for (; scan != NULL; scan = regnext(scan))
if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
longest = OPERAND(scan);
len = strlen(OPERAND(scan));
}
r->regmust = longest;
r->regmlen = len;
}
}
return(r);
}
/*
- reg - regular expression, i.e. main body or parenthesized thing
*
* Caller must absorb opening parenthesis.
*
* Combining parenthesis handling with the base level of regular expression
* is a trifle forced, but the need to tie the tails of the branches to what
* follows makes it hard to avoid.
*/
static char *
reg(
int paren, /* Parenthesized? */
int *flagp )
{
register char *ret;
register char *br;
register char *ender;
register int parno;
int flags;
*flagp = HASWIDTH; /* Tentatively. */
/* Make an OPEN node, if parenthesized. */
if (paren) {
if (regnpar >= NSUBEXP)
FAIL("too many ()");
parno = regnpar;
regnpar++;
ret = regnode(OPEN+parno);
} else
ret = NULL;
/* Pick up the branches, linking them together. */
br = regbranch(&flags);
if (br == NULL)
return(NULL);
if (ret != NULL)
regtail(ret, br); /* OPEN -> first. */
else
ret = br;
if (!(flags&HASWIDTH))
*flagp &= ~HASWIDTH;
*flagp |= flags&SPSTART;
while (*regparse == '|' || *regparse == '\n') {
regparse++;
br = regbranch(&flags);
if (br == NULL)
return(NULL);
regtail(ret, br); /* BRANCH -> BRANCH. */
if (!(flags&HASWIDTH))
*flagp &= ~HASWIDTH;
*flagp |= flags&SPSTART;
}
/* Make a closing node, and hook it on the end. */
ender = regnode((paren) ? CLOSE+parno : END);
regtail(ret, ender);
/* Hook the tails of the branches to the closing node. */
for (br = ret; br != NULL; br = regnext(br))
regoptail(br, ender);
/* Check for proper termination. */
if (paren && *regparse++ != ')') {
FAIL("unmatched ()");
} else if (!paren && *regparse != '\0') {
if (*regparse == ')') {
FAIL("unmatched ()");
} else
FAIL("junk on end"); /* "Can't happen". */
/* NOTREACHED */
}
return(ret);
}
/*
- regbranch - one alternative of an | operator
*
* Implements the concatenation operator.
*/
static char *
regbranch( int *flagp )
{
register char *ret;
register char *chain;
register char *latest;
int flags;
*flagp = WORST; /* Tentatively. */
ret = regnode(BRANCH);
chain = NULL;
while (*regparse != '\0' && *regparse != ')' &&
*regparse != '\n' && *regparse != '|') {
latest = regpiece(&flags);
if (latest == NULL)
return(NULL);
*flagp |= flags&HASWIDTH;
if (chain == NULL) /* First piece. */
*flagp |= flags&SPSTART;
else
regtail(chain, latest);
chain = latest;
}
if (chain == NULL) /* Loop ran zero times. */
(void) regnode(NOTHING);
return(ret);
}
/*
- regpiece - something followed by possible [*+?]
*
* Note that the branching code sequences used for ? and the general cases
* of * and + are somewhat optimized: they use the same NOTHING node as
* both the endmarker for their branch list and the body of the last branch.
* It might seem that this node could be dispensed with entirely, but the
* endmarker role is not redundant.
*/
static char *
regpiece( int *flagp )
{
register char *ret;
register char op;
register char *next;
int flags;
ret = regatom(&flags);
if (ret == NULL)
return(NULL);
op = *regparse;
if (!ISMULT(op)) {
*flagp = flags;
return(ret);
}
if (!(flags&HASWIDTH) && op != '?')
FAIL("*+ operand could be empty");
*flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
if (op == '*' && (flags&SIMPLE))
reginsert(STAR, ret);
else if (op == '*') {
/* Emit x* as (x&|), where & means "self". */
reginsert(BRANCH, ret); /* Either x */
regoptail(ret, regnode(BACK)); /* and loop */
regoptail(ret, ret); /* back */
regtail(ret, regnode(BRANCH)); /* or */
regtail(ret, regnode(NOTHING)); /* null. */
} else if (op == '+' && (flags&SIMPLE))
reginsert(PLUS, ret);
else if (op == '+') {
/* Emit x+ as x(&|), where & means "self". */
next = regnode(BRANCH); /* Either */
regtail(ret, next);
regtail(regnode(BACK), ret); /* loop back */
regtail(next, regnode(BRANCH)); /* or */
regtail(ret, regnode(NOTHING)); /* null. */
} else if (op == '?') {
/* Emit x? as (x|) */
reginsert(BRANCH, ret); /* Either x */
regtail(ret, regnode(BRANCH)); /* or */
next = regnode(NOTHING); /* null. */
regtail(ret, next);
regoptail(ret, next);
}
regparse++;
if (ISMULT(*regparse))
FAIL("nested *?+");
return(ret);
}
/*
- regatom - the lowest level
*
* Optimization: gobbles an entire sequence of ordinary characters so that
* it can turn them into a single node, which is smaller to store and
* faster to run. Backslashed characters are exceptions, each becoming a
* separate node; the code is simpler that way and it's not worth fixing.
*/
static char *
regatom( int *flagp )
{
register char *ret;
int flags;
*flagp = WORST; /* Tentatively. */
switch (*regparse++) {
/* FIXME: these chars only have meaning at beg/end of pat? */
case '^':
ret = regnode(BOL);
break;
case '$':
ret = regnode(EOL);
break;
case '.':
ret = regnode(ANY);
*flagp |= HASWIDTH|SIMPLE;
break;
case '[': {
register int classr;
register int classend;
if (*regparse == '^') { /* Complement of range. */
ret = regnode(ANYBUT);
regparse++;
} else
ret = regnode(ANYOF);
if (*regparse == ']' || *regparse == '-')
regc(*regparse++);
while (*regparse != '\0' && *regparse != ']') {
if (*regparse == '-') {
regparse++;
if (*regparse == ']' || *regparse == '\0')
regc('-');
else {
classr = UCHARAT(regparse-2)+1;
classend = UCHARAT(regparse);
if (classr > classend+1)
FAIL("invalid [] range");
for (; classr <= classend; classr++)
regc(classr);
regparse++;
}
} else
regc(*regparse++);
}
regc('\0');
if (*regparse != ']')
FAIL("unmatched []");
regparse++;
*flagp |= HASWIDTH|SIMPLE;
}
break;
case '(':
ret = reg(1, &flags);
if (ret == NULL)
return(NULL);
*flagp |= flags&(HASWIDTH|SPSTART);
break;
case '\0':
case '|':
case '\n':
case ')':
FAIL("internal urp"); /* Supposed to be caught earlier. */
break;
case '?':
case '+':
case '*':
FAIL("?+* follows nothing");
break;
case '\\':
switch (*regparse++) {
case '\0':
FAIL("trailing \\");
break;
case '<':
ret = regnode(WORDA);
break;
case '>':
ret = regnode(WORDZ);
break;
/* FIXME: Someday handle \1, \2, ... */
default:
/* Handle general quoted chars in exact-match routine */
goto de_fault;
}
break;
de_fault:
default:
/*
* Encode a string of characters to be matched exactly.
*
* This is a bit tricky due to quoted chars and due to
* '*', '+', and '?' taking the SINGLE char previous
* as their operand.
*
* On entry, the char at regparse[-1] is going to go
* into the string, no matter what it is. (It could be
* following a \ if we are entered from the '\' case.)
*
* Basic idea is to pick up a good char in ch and
* examine the next char. If it's *+? then we twiddle.
* If it's \ then we frozzle. If it's other magic char
* we push ch and terminate the string. If none of the
* above, we push ch on the string and go around again.
*
* regprev is used to remember where "the current char"
* starts in the string, if due to a *+? we need to back
* up and put the current char in a separate, 1-char, string.
* When regprev is NULL, ch is the only char in the
* string; this is used in *+? handling, and in setting
* flags |= SIMPLE at the end.
*/
{
char *regprev;
register char ch;
regparse--; /* Look at cur char */
ret = regnode(EXACTLY);
for ( regprev = 0 ; ; ) {
ch = *regparse++; /* Get current char */
switch (*regparse) { /* look at next one */
default:
regc(ch); /* Add cur to string */
break;
case '.': case '[': case '(':
case ')': case '|': case '\n':
case '$': case '^':
case '\0':
/* FIXME, $ and ^ should not always be magic */
magic:
regc(ch); /* dump cur char */
goto done; /* and we are done */
case '?': case '+': case '*':
if (!regprev) /* If just ch in str, */
goto magic; /* use it */
/* End mult-char string one early */
regparse = regprev; /* Back up parse */
goto done;
case '\\':
regc(ch); /* Cur char OK */
switch (regparse[1]){ /* Look after \ */
case '\0':
case '<':
case '>':
/* FIXME: Someday handle \1, \2, ... */
goto done; /* Not quoted */
default:
/* Backup point is \, scan * point is after it. */
regprev = regparse;
regparse++;
continue; /* NOT break; */
}
}
regprev = regparse; /* Set backup point */
}
done:
regc('\0');
*flagp |= HASWIDTH;
if (!regprev) /* One char? */
*flagp |= SIMPLE;
}
break;
}
return(ret);
}
/*
- regnode - emit a node
*/
static char * /* Location. */
regnode( int op )
{
register char *ret;
register char *ptr;
ret = regcode;
if (ret == ®dummy) {
regsize += 3;
return(ret);
}
ptr = ret;
*ptr++ = op;
*ptr++ = '\0'; /* Null "next" pointer. */
*ptr++ = '\0';
regcode = ptr;
return(ret);
}
/*
- regc - emit (if appropriate) a byte of code
*/
static void
regc( int b )
{
if (regcode != ®dummy)
*regcode++ = b;
else
regsize++;
}
/*
- reginsert - insert an operator in front of already-emitted operand
*
* Means relocating the operand.
*/
static void
reginsert(
char op,
char *opnd )
{
register char *src;
register char *dst;
register char *place;
if (regcode == ®dummy) {
regsize += 3;
return;
}
src = regcode;
regcode += 3;
dst = regcode;
while (src > opnd)
*--dst = *--src;
place = opnd; /* Op node, where operand used to be. */
*place++ = op;
*place++ = '\0';
*place++ = '\0';
}
/*
- regtail - set the next-pointer at the end of a node chain
*/
static void
regtail(
char *p,
char *val )
{
register char *scan;
register char *temp;
register int offset;
if (p == ®dummy)
return;
/* Find last node. */
scan = p;
for (;;) {
temp = regnext(scan);
if (temp == NULL)
break;
scan = temp;
}
if (OP(scan) == BACK)
offset = scan - val;
else
offset = val - scan;
*(scan+1) = (offset>>8)&0377;
*(scan+2) = offset&0377;
}
/*
- regoptail - regtail on operand of first argument; nop if operandless
*/
static void
regoptail(
char *p,
char *val )
{
/* "Operandless" and "op != BRANCH" are synonymous in practice. */
if (p == NULL || p == ®dummy || OP(p) != BRANCH)
return;
regtail(OPERAND(p), val);
}
/*
* regexec and friends
*/
/*
* Global work variables for regexec().
*/
static const char *reginput; /* String-input pointer. */
static char *regbol; /* Beginning of input, for ^ check. */
static const char **regstartp; /* Pointer to startp array. */
static const char **regendp; /* Ditto for endp. */
/*
* Forwards.
*/
STATIC int regtry( regexp *prog, const char *string );
STATIC int regmatch( char *prog );
STATIC int regrepeat( char *p );
#ifdef DEBUG
int regnarrate = 0;
void regdump();
STATIC char *regprop();
#endif
/*
- regexec - match a regexp against a string
*/
int
regexec(
register regexp *prog,
register const char *string )
{
register char *s;
/* Be paranoid... */
if (prog == NULL || string == NULL) {
regerror("NULL parameter");
return(0);
}
/* Check validity of program. */
if (UCHARAT(prog->program) != MAGIC) {
regerror("corrupted program");
return(0);
}
/* If there is a "must appear" string, look for it. */
if (prog->regmust != NULL) {
s = (char *)string;
while ((s = strchr(s, prog->regmust[0])) != NULL) {
if (strncmp(s, prog->regmust, prog->regmlen) == 0)
break; /* Found it. */
s++;
}
if (s == NULL) /* Not present. */
return(0);
}
/* Mark beginning of line for ^ . */
regbol = (char *)string;
/* Simplest case: anchored match need be tried only once. */
if (prog->reganch)
return(regtry(prog, string));
/* Messy cases: unanchored match. */
s = (char *)string;
if (prog->regstart != '\0')
/* We know what char it must start with. */
while ((s = strchr(s, prog->regstart)) != NULL) {
if (regtry(prog, s))
return(1);
s++;
}
else
/* We don't -- general case. */
do {
if (regtry(prog, s))
return(1);
} while (*s++ != '\0');
/* Failure. */
return(0);
}
/*
- regtry - try match at specific point
*/
static int /* 0 failure, 1 success */
regtry(
regexp *prog,
const char *string )
{
register int i;
register const char **sp;
register const char **ep;
reginput = string;
regstartp = prog->startp;
regendp = prog->endp;
sp = prog->startp;
ep = prog->endp;
for (i = NSUBEXP; i > 0; i--) {
*sp++ = NULL;
*ep++ = NULL;
}
if (regmatch(prog->program + 1)) {
prog->startp[0] = string;
prog->endp[0] = reginput;
return(1);
} else
return(0);
}
/*
- regmatch - main matching routine
*
* Conceptually the strategy is simple: check to see whether the current
* node matches, call self recursively to see whether the rest matches,
* and then act accordingly. In practice we make some effort to avoid
* recursion, in particular by going through "ordinary" nodes (that don't
* need to know whether the rest of the match failed) by a loop instead of
* by recursion.
*/
static int /* 0 failure, 1 success */
regmatch( char *prog )
{
register char *scan; /* Current node. */
char *next; /* Next node. */
scan = prog;
#ifdef DEBUG
if (scan != NULL && regnarrate)
fprintf(stderr, "%s(\n", regprop(scan));
#endif
while (scan != NULL) {
#ifdef DEBUG
if (regnarrate)
fprintf(stderr, "%s...\n", regprop(scan));
#endif
next = regnext(scan);
switch (OP(scan)) {
case BOL:
if (reginput != regbol)
return(0);
break;
case EOL:
if (*reginput != '\0')
return(0);
break;
case WORDA:
/* Must be looking at a letter, digit, or _ */
if ((!isalnum(*reginput)) && *reginput != '_')
return(0);
/* Prev must be BOL or nonword */
if (reginput > regbol &&
(isalnum(reginput[-1]) || reginput[-1] == '_'))
return(0);
break;
case WORDZ:
/* Must be looking at non letter, digit, or _ */
if (isalnum(*reginput) || *reginput == '_')
return(0);
/* We don't care what the previous char was */
break;
case ANY:
if (*reginput == '\0')
return(0);
reginput++;
break;
case EXACTLY: {
register int len;
register char *opnd;
opnd = OPERAND(scan);
/* Inline the first character, for speed. */
if (*opnd != *reginput)
return(0);
len = strlen(opnd);
if (len > 1 && strncmp(opnd, reginput, len) != 0)
return(0);
reginput += len;
}
break;
case ANYOF:
if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
return(0);
reginput++;
break;
case ANYBUT:
if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
return(0);
reginput++;
break;
case NOTHING:
break;
case BACK:
break;
case OPEN+1:
case OPEN+2:
case OPEN+3:
case OPEN+4:
case OPEN+5:
case OPEN+6:
case OPEN+7:
case OPEN+8:
case OPEN+9: {
register int no;
register const char *save;
no = OP(scan) - OPEN;
save = reginput;
if (regmatch(next)) {
/*
* Don't set startp if some later
* invocation of the same parentheses
* already has.
*/
if (regstartp[no] == NULL)
regstartp[no] = save;
return(1);
} else
return(0);
}
break;
case CLOSE+1:
case CLOSE+2:
case CLOSE+3:
case CLOSE+4:
case CLOSE+5:
case CLOSE+6:
case CLOSE+7:
case CLOSE+8:
case CLOSE+9: {
register int no;
register const char *save;
no = OP(scan) - CLOSE;
save = reginput;
if (regmatch(next)) {
/*
* Don't set endp if some later
* invocation of the same parentheses
* already has.
*/
if (regendp[no] == NULL)
regendp[no] = save;
return(1);
} else
return(0);
}
break;
case BRANCH: {
register const char *save;
if (OP(next) != BRANCH) /* No choice. */
next = OPERAND(scan); /* Avoid recursion. */
else {
do {
save = reginput;
if (regmatch(OPERAND(scan)))
return(1);
reginput = save;
scan = regnext(scan);
} while (scan != NULL && OP(scan) == BRANCH);
return(0);
/* NOTREACHED */
}
}
break;
case STAR:
case PLUS: {
register char nextch;
register int no;
register const char *save;
register int min;
/*
* Lookahead to avoid useless match attempts
* when we know what character comes next.
*/
nextch = '\0';
if (OP(next) == EXACTLY)
nextch = *OPERAND(next);
min = (OP(scan) == STAR) ? 0 : 1;
save = reginput;
no = regrepeat(OPERAND(scan));
while (no >= min) {
/* If it could work, try it. */
if (nextch == '\0' || *reginput == nextch)
if (regmatch(next))
return(1);
/* Couldn't or didn't -- back up. */
no--;
reginput = save + no;
}
return(0);
}
break;
case END:
return(1); /* Success! */
break;
default:
regerror("memory corruption");
return(0);
break;
}
scan = next;
}
/*
* We get here only if there's trouble -- normally "case END" is
* the terminating point.
*/
regerror("corrupted pointers");
return(0);
}
/*
- regrepeat - repeatedly match something simple, report how many
*/
static int
regrepeat( char *p )
{
register int count = 0;
register const char *scan;
register char *opnd;
scan = reginput;
opnd = OPERAND(p);
switch (OP(p)) {
case ANY:
count = strlen(scan);
scan += count;
break;
case EXACTLY:
while (*opnd == *scan) {
count++;
scan++;
}
break;
case ANYOF:
while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
count++;
scan++;
}
break;
case ANYBUT:
while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
count++;
scan++;
}
break;
default: /* Oh dear. Called inappropriately. */
regerror("internal foulup");
count = 0; /* Best compromise. */
break;
}
reginput = scan;
return(count);
}
/*
- regnext - dig the "next" pointer out of a node
*/
static char *
regnext( register char *p )
{
register int offset;
if (p == ®dummy)
return(NULL);
offset = NEXT(p);
if (offset == 0)
return(NULL);
if (OP(p) == BACK)
return(p-offset);
else
return(p+offset);
}
#ifdef DEBUG
STATIC char *regprop();
/*
- regdump - dump a regexp onto stdout in vaguely comprehensible form
*/
void
regdump( regexp *r )
{
register char *s;
register char op = EXACTLY; /* Arbitrary non-END op. */
register char *next;
s = r->program + 1;
while (op != END) { /* While that wasn't END last time... */
op = OP(s);
printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
next = regnext(s);
if (next == NULL) /* Next ptr. */
printf("(0)");
else
printf("(%d)", (s-r->program)+(next-s));
s += 3;
if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
/* Literal string, where present. */
while (*s != '\0') {
putchar(*s);
s++;
}
s++;
}
putchar('\n');
}
/* Header fields of interest. */
if (r->regstart != '\0')
printf("start `%c' ", r->regstart);
if (r->reganch)
printf("anchored ");
if (r->regmust != NULL)
printf("must have \"%s\"", r->regmust);
printf("\n");
}
/*
- regprop - printable representation of opcode
*/
static char *
regprop( char *op )
{
register char *p;
static char buf[50];
(void) strcpy(buf, ":");
switch (OP(op)) {
case BOL:
p = "BOL";
break;
case EOL:
p = "EOL";
break;
case ANY:
p = "ANY";
break;
case ANYOF:
p = "ANYOF";
break;
case ANYBUT:
p = "ANYBUT";
break;
case BRANCH:
p = "BRANCH";
break;
case EXACTLY:
p = "EXACTLY";
break;
case NOTHING:
p = "NOTHING";
break;
case BACK:
p = "BACK";
break;
case END:
p = "END";
break;
case OPEN+1:
case OPEN+2:
case OPEN+3:
case OPEN+4:
case OPEN+5:
case OPEN+6:
case OPEN+7:
case OPEN+8:
case OPEN+9:
sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
p = NULL;
break;
case CLOSE+1:
case CLOSE+2:
case CLOSE+3:
case CLOSE+4:
case CLOSE+5:
case CLOSE+6:
case CLOSE+7:
case CLOSE+8:
case CLOSE+9:
sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
p = NULL;
break;
case STAR:
p = "STAR";
break;
case PLUS:
p = "PLUS";
break;
case WORDA:
p = "WORDA";
break;
case WORDZ:
p = "WORDZ";
break;
default:
regerror("corrupted opcode");
break;
}
if (p != NULL)
(void) strcat(buf, p);
return(buf);
}
#endif
/*
* The following is provided for those people who do not have strcspn() in
* their C libraries. They should get off their butts and do something
* about it; at least one public-domain implementation of those (highly
* useful) string routines has been published on Usenet.
*/
#ifdef STRCSPN
/*
* strcspn - find length of initial segment of s1 consisting entirely
* of characters not from s2
*/
static int
strcspn(
char *s1,
char *s2 )
{
register char *scan1;
register char *scan2;
register int count;
count = 0;
for (scan1 = s1; *scan1 != '\0'; scan1++) {
for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
if (*scan1 == *scan2++)
return(count);
count++;
}
return(count);
}
#endif
void
regerror( const char *s )
{
printf( "re error %s\n", s );
}
jam-2.5/regexp.h 0100440 0000503 0000454 00000001465 07651415200 012726 0 ustar seiwald team /*
* Definitions etc. for regexp(3) routines.
*
* Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
* not the System V one.
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
#define NSUBEXP 10
typedef struct regexp {
const char *startp[NSUBEXP];
const 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( const char *exp );
int regexec( regexp *prog, const char *string );
void regerror( const 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
jam-2.5/rules.c 0100440 0000503 0000454 00000016513 07651415200 012561 0 ustar seiwald team /*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* copytarget() - make a new target with the old target's name
* 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
* targetchain() - append two TARGET chains
* actionlist() - append to an ACTION chain
* addsettings() - add a deferred "set" command to a target
* copysettings() - copy a settings list for temp use
* 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)
* 06/21/02 (seiwald) - support for named parameters
* 11/04/02 (seiwald) - const-ing for string literals
* 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
* 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
* 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET
*/
# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "variable.h"
# include "rules.h"
# include "newstr.h"
# include "hash.h"
static struct hash *rulehash = 0;
static struct hash *targethash = 0;
/*
* bindrule() - return pointer to RULE, creating it if necessary
*/
RULE *
bindrule( const 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->params = L0;
r->flags = 0;
}
return r;
}
/*
* bindtarget() - return pointer to TARGET, creating it if necessary
*/
TARGET *
bindtarget( const 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;
}
/*
* copytarget() - make a new target with the old target's name
*
* Not entered into hash table -- for internal nodes.
*/
TARGET *
copytarget( const TARGET *ot )
{
TARGET *t;
t = (TARGET *)malloc( sizeof( *t ) );
memset( (char *)t, '\0', sizeof( *t ) );
t->name = copystr( ot->name );
t->boundname = t->name;
t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
return t;
}
/*
* touchtarget() - mark a target to simulate being new
*/
void
touchtarget( const 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;
}
/*
* targetchain() - append two TARGET chains
*
* Inputs:
* chain exisitng TARGETS to append to
* target new target to append
*/
TARGETS *
targetchain(
TARGETS *chain,
TARGETS *targets )
{
TARGETS *c;
if( !targets )
return chain;
else if( !chain )
return targets;
chain->tail->next = targets;
chain->tail = targets->tail;
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 setflag,
const 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 switch( setflag )
{
case VAR_SET:
/* Toss old, set new */
list_free( v->value );
v->value = value;
break;
case VAR_APPEND:
/* Append new to old */
v->value = list_append( v->value, value );
break;
case VAR_DEFAULT:
/* Toss new, old already set */
list_free( value );
break;
}
/* Return (new) head of list. */
return head;
}
/*
* copysettings() - copy a settings list for temp use
*
* When target-specific variables are pushed into place with pushsettings(),
* any global variables with the same name are swapped onto the target's
* SETTINGS chain. If that chain gets modified (by using the "on target"
* syntax), popsettings() would wrongly swap those modified values back
* as the new global values.
*
* copysettings() protects the target's SETTINGS chain by providing a
* copy of the chain to pass to pushsettings() and popsettings(), so that
* the target's original SETTINGS chain can be modified using the usual
* "on target" syntax.
*/
SETTINGS *
copysettings( SETTINGS *from )
{
SETTINGS *head = 0, *v;
for( ; from; from = from->next )
{
SETTINGS *v = (SETTINGS *)malloc( sizeof( *v ) );
v->symbol = copystr( from->symbol );
v->value = list_copy( 0, from->value );
v->next = head;
head = v;
}
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 );
}
jam-2.5/rules.h 0100440 0000503 0000454 00000014527 07651415200 012571 0 ustar seiwald team /*
* 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.
* 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
* 06/21/02 (seiwald) - support for named parameters
* 07/17/02 (seiwald) - TEMPORARY sources for headers now get built
* 11/04/02 (seiwald) - const-ing for string literals
* 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends
* 12/17/02 (seiwald) - new copysettings() to protect target-specific vars
* 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET
*/
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 {
const char *name;
PARSE *procedure; /* parse tree from RULE */
const char *actions; /* command string from ACTIONS */
LIST *bindlist; /* variable to bind for actions */
LIST *params; /* bind args to local vars */
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 */
# define RULE_MAXLINE 0x40 /* cmd specific maxline (last) */
} ;
/* 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;
const 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 {
const char *name;
const 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 */
# define T_FLAG_INTERNAL 0x40 /* internal INCLUDES node */
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 *depends; /* dependencies */
TARGET *includes; /* includes */
time_t time; /* update time */
time_t leaf; /* update time of leaf sources */
char fate; /* make0()'s diagnosis */
# 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_NEEDTMP 7 /* missing temp that must be rebuild */
# define T_FATE_OUTDATED 8 /* is out of date, needs updating */
# define T_FATE_UPDATE 9 /* deps updated, needs updating */
# define T_FATE_BROKEN 10 /* >= BROKEN ruins parents */
# define T_FATE_CANTFIND 10 /* no rules to make missing target */
# define T_FATE_CANTMAKE 11 /* 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( const char *rulename );
TARGET *bindtarget( const char *targetname );
TARGET *copytarget( const TARGET *t );
void touchtarget( const char *t );
TARGETS *targetlist( TARGETS *chain, LIST *targets );
TARGETS *targetentry( TARGETS *chain, TARGET *target );
TARGETS *targetchain( TARGETS *chain, TARGETS *targets );
ACTIONS *actionlist( ACTIONS *chain, ACTION *action );
SETTINGS *addsettings( SETTINGS *v, int setflag, const char *sym, LIST *val );
SETTINGS *copysettings( SETTINGS *v );
void pushsettings( SETTINGS *v );
void popsettings( SETTINGS *v );
void freesettings( SETTINGS *v );
void donerules();
jam-2.5/scan.c 0100440 0000503 0000454 00000017025 07651415200 012352 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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.
* 01/10/01 (seiwald) - \ can now escape any whitespace char
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "scan.h"
# include "jamgram.h"
# include "jambase.h"
# include "newstr.h"
struct keyword {
const char *word;
int type;
} keywords[] = {
# include "jamgramtab.h"
{ 0, 0 }
} ;
struct include {
struct include *next; /* next serial include file */
const char *string; /* pointer into current line */
char **strings; /* for yyfparse() -- text to parse */
FILE *file; /* for yyfparse() -- file being read */
const 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( const 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( const 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;
}
jam-2.5/scan.h 0100440 0000503 0000454 00000002603 07651415200 012353 0 ustar seiwald team /*
* 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.
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
/*
* YYSTYPE - value of a lexical token
*/
# define YYSTYPE YYSYMBOL
typedef struct _YYSTYPE {
int type;
const char *string;
PARSE *parse;
LIST *list;
int number;
} YYSTYPE;
extern YYSTYPE yylval;
void yymode( int n );
void yyerror( const char *s );
int yyanyerrors();
void yyfparse( const 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 */
jam-2.5/search.c 0100440 0000503 0000454 00000003105 07651415200 012665 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* search.c - find a target along $(SEARCH) or $(LOCATE)
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "lists.h"
# include "search.h"
# include "timestamp.h"
# include "pathsys.h"
# include "variable.h"
# include "newstr.h"
const char *
search(
const 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 );
}
jam-2.5/search.h 0100440 0000503 0000454 00000000456 07651415200 012700 0 ustar seiwald team /*
* 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)
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
const char *search( const char *target, time_t *time );
jam-2.5/timestamp.c 0100440 0000503 0000454 00000007644 07651415200 013437 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* timestamp.c - get the timestamp of a file or archive member
*
* 09/22/00 (seiwald) - downshift names on OS2, too
* 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "hash.h"
# include "filesys.h"
# include "pathsys.h"
# include "timestamp.h"
# include "newstr.h"
/*
* BINDING - all known files
*/
typedef struct _binding BINDING;
struct _binding {
const 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 *, const char *, int , time_t );
static const 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,
const 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 );
}
jam-2.5/timestamp.h 0100440 0000503 0000454 00000000403 07651415200 013426 0 ustar seiwald team /*
* 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();
jam-2.5/variable.c 0100440 0000503 0000454 00000014366 07651415200 013220 0 ustar seiwald team /*
* Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* 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
* 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
* 11/04/02 (seiwald) - const-ing for string literals
*/
# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "variable.h"
# include "expand.h"
# include "hash.h"
# include "newstr.h"
static struct hash *varhash = 0;
/*
* VARIABLE - a user defined multi-value variable
*/
typedef struct _variable VARIABLE ;
struct _variable {
const char *symbol;
LIST *value;
} ;
static VARIABLE *var_enter( const char *symbol );
static void var_dump( const char *symbol, LIST *value, const 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( const char **e )
{
for( ; *e; e++ )
{
const 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;
const 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, buf, 0 );
}
l = list_new( l, pp, 0 );
/* 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(
const 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 = var_expand( L0, lastword, out, lol, 0 );
out = lastword;
while( l )
{
int so = strlen( l->string );
if( out + so >= oute )
return -1;
strcpy( out, l->string );
out += so;
/* Separate with space */
if( l = list_next( l ) )
*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( const 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(
const 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(
const 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( const 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(
const char *symbol,
LIST *value,
const char *what )
{
printf( "%s %s = ", what, symbol );
list_print( value );
printf( "\n" );
}
/*
* var_done() - free variable tables
*/
void
var_done()
{
hashdone( varhash );
}
jam-2.5/variable.h 0100440 0000503 0000454 00000001310 07651415200 013206 0 ustar seiwald team /*
* Copyright 1993, 2000 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
/*
* variable.h - handle jam multi-element variables
*
* 11/04/02 (seiwald) - const-ing for string literals
*/
void var_defines( const char **e );
int var_string( const char *in, char *out, int outsize, LOL *lol );
LIST * var_get( const char *symbol );
void var_set( const char *symbol, LIST *value, int flag );
LIST * var_swap( const 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 */
jam-2.5/yyacc 0100550 0000503 0000454 00000002616 07651415200 012317 0 ustar seiwald team #!/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
#
# 03-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
# 03/19/02 (seiwald) - suffix symbols with _t to avoid conflicts
#
outy=${1?}
outh=${2?}
in=${3?}
out=`basename $in .yy`
T=/tmp/yy$$
trap 'rm -f $T.*' 0
sed '
: 1
/`/{
h
s/[^`]*`\([^`]*\)`.*/\1/
p
g
s/[^`]*`[^`]*`//
b 1
}
d
' $in | sort -u | sed '
h
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
s/:/_COLON/
s/!/_BANG/
s/&&/_AMPERAMPER/
s/&/_AMPER/
s/+/_PLUS/
s/||/_BARBAR/
s/|/_BAR/
s/;/_SEMIC/
s/-/_MINUS/
s//_RANGLE/
s/\./_PERIOD/
s/?/_QUESTION/
s/=/_EQUALS/
s/,/_COMMA/
s/\[/_LBRACKET/
s/]/_RBRACKET/
s/{/_LBRACE/
s/}/_RBRACE/
s/(/_LPAREN/
s/)/_RPAREN/
s/.*/&_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