Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v47i108: jam - make(1) redux, v2.0, Part01/07

31 views
Skip to first unread message

Christopher Seiwald

unread,
Apr 11, 1995, 3:00:00 AM4/11/95
to
Submitted-by: sei...@tea.org (Christopher Seiwald)
Posting-number: Volume 47, Issue 108
Archive-name: jam/part01
Environment: UNIX, NT, VMS
Supersedes: jam: Volume 27, Issue 81-85

This is Release 2.0 of jam, a make-like program.

Jam recursively builds target files from their source files, using
two files to define the dependency graph and the updating actions for
all targets. The file Jambase (usually located in /usr/local/lib)
defines rules, and the file Jamfile (located in the current directory)
lists the targets and sources in terms of those rules. Jam does not
need to rely on suffix-driven implicit rules or directory contents.
A Jambase is provided with jam; the user supplies the Jamfile.

Jambase contains a set of jam rule definitions that provide roughly
make(1)-like functionality. Jam reads Jambase, which in turn
includes the Jamfile from the current directory.

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, 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. See the accompanying paper. On UNIX, jam
can do this with multiple, concurrent processes.

-> Jam isn't under the blinkin GNU copyright, so you can
incorporate it into commercial products.


Supplied documentation:

jam.1 Jam man page - a terse description.
jam.ps

Jambase.5 Reference for the rule boilerplate file.
Jambase.ps

Jamfile.5 Easy reading on creating a Jamfile and using jam.
Jamfile.ps

Paper.ps The 1994 UNIX Application Development Symposium paper
on jam (reflects Release 1 - see RELNOTES for diffs).

RELNOTES Release 2.0 release notes.

Porting Notes on porting jam to wildcat platforms.

README Includes installation instructions.

jam.c Contains jam's main() as well as an introduction to the
code, for serious hackers.


sei...@tea.org
--------------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# Contents: README Paper.ps filent.c
# Wrapped by kent@ftp on Sat Mar 25 12:04:10 1995
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 7)."'
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3012 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
Xjam - make(1) redux
X
X /+\
X +\ Copyright 1993, 1995 Christopher Seiwald.
X \+/
X
X This is Release 2.0 of jam, a make-like program.
X The next release will be Release 2.1.
X
X License is hereby granted to use this software and distribute it
X freely, as long as this copyright notice is retained and modifications
X are clearly marked.
X
X ALL WARRANTIES ARE HEREBY DISCLAIMED.
X
X
XFEATURES
X
X -> Jam is a make(1) replacement that makes building simple things
X simple and building complicated things manageable.
X
X -> Jam's language is expressive, making Jamfiles (c.f. Makefiles)
X compact. Here's a sample:
X
X Main smail : main.c map.c resolve.c deliver.c
X misc.c parser.y alias.c pw.c headers.c
X scanner.l getpath.c str.c ;
X
X This builds "smail" from a dozen source files. Jam handles
X header file dependencies automatically and on-the-fly.
X
X -> Jam is very portable: it runs on UNIX, VMS, and NT. Most
X Jamfiles themselves are portable, like the sample above.
X
X -> Jam is unintrusive: it is small, it has negligible CPU
X overhead, and it doesn't create any of its own funny files
X (c.f. Odin, nmake, SunOS make).
X
X -> Jam can build large projects spread across many directories
X in one pass, without recursing, tracking the relationships
X among all files. See the accompanying paper. On UNIX, jam
X can do this with multiple, concurrent processes.
X
X -> Jam isn't under the blinkin GNU copyright, so you can
X incorporate it into commercial products.
X
X
XINFORMATION GUIDE
X
X jam.1 Jam man page - a terse description.
X jam.ps
X
X Jambase.5 Reference for the rule boilerplate file.
X Jambase.ps
X
X Jamfile.5 Easy reading on creating a Jamfile and using jam.
X Jamfile.ps
X
X Paper.ps The 1994 UNIX Application Development Symposium paper
X on jam (reflects Release 1 - see RELNOTES for diffs).
X
X RELNOTES Release 2.0 release notes.
X
X Porting Notes on porting jam to wildcat platforms.
X
X README This file. Includes installation instructions.
X
X jam.c Contains jam's main() as well as an introduction to the
X code, for serious hackers.
X
X
XINSTALLING
X
X Build jam with make(1) on:
X
X BSDI BSD/386 1.0
X COHERENT COHERENT/386
X DEC 3000/500 OSF/1
X DG AViiON DGUX 5.4
X HP 9000/700 HPUX 9.0
X IBM RS/6000 AIX *
X SGI R4000 IRIX 5.0
X Sequent 2000 PTX V2.1.0
X Sun 3 SunOS4.0
X Sun 4 Solaris 2 *+
X Sun 4 SunOS4.1
X VAX Ultrix 4.2
X
X IBM PC NT *
X
X * requires editing Makefile
X + only works with SUNSwpro CC (dirent confusion)
X
X Build jam with @build.com on:
X
X VAX VMS 5.4
X DEC 3000/500 OPENVMS *
X
X * requires editing build.com
X
X The Makefile (UNIX, NT) and build.com (VMS) are for bootstrapping.
X
X Once jam is built, read the Jamfile man page and give it a try.
X
X
XComments to the author!
X
XNovember, 1993 - release 1.0
XMarch, 1995 - release 2.0
X
X--- Christopher
Xsei...@tea.org
END_OF_FILE
if test 3012 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Paper.ps' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Paper.ps'\"
else
echo shar: Extracting \"'Paper.ps'\" \(70543 characters\)
sed "s/^X//" >'Paper.ps' <<'END_OF_FILE'
X%!PS-Adobe-3.0
X%%Creator: groff version 1.08
X%%DocumentNeededResources: font Times-Bold
X%%+ font Times-Roman
X%%+ font Times-Italic
X%%+ font Courier
X%%DocumentSuppliedResources: procset grops 1.08 0
X%%Pages: 10
X%%PageOrder: Ascend
X%%Orientation: Portrait
X%%EndComments
X%%BeginProlog
X%%BeginResource: procset grops 1.08 0
X/setpacking where{
Xpop
Xcurrentpacking
Xtrue setpacking
X}if
X/grops 120 dict dup begin
X/SC 32 def
X/A/show load def
X/B{0 SC 3 -1 roll widthshow}bind def
X/C{0 exch ashow}bind def
X/D{0 exch 0 SC 5 2 roll awidthshow}bind def
X/E{0 rmoveto show}bind def
X/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
X/G{0 rmoveto 0 exch ashow}bind def
X/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
X/I{0 exch rmoveto show}bind def
X/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
X/K{0 exch rmoveto 0 exch ashow}bind def
X/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
X/M{rmoveto show}bind def
X/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
X/O{rmoveto 0 exch ashow}bind def
X/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
X/Q{moveto show}bind def
X/R{moveto 0 SC 3 -1 roll widthshow}bind def
X/S{moveto 0 exch ashow}bind def
X/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
X/SF{
Xfindfont exch
X[exch dup 0 exch 0 exch neg 0 0]makefont
Xdup setfont
X[exch/setfont cvx]cvx bind def
X}bind def
X/MF{
Xfindfont
X[5 2 roll
X0 3 1 roll
Xneg 0 0]makefont
Xdup setfont
X[exch/setfont cvx]cvx bind def
X}bind def
X/level0 0 def
X/RES 0 def
X/PL 0 def
X/LS 0 def
X/PLG{
Xgsave newpath clippath pathbbox grestore
Xexch pop add exch pop
X}bind def
X/BP{
X/level0 save def
X1 setlinecap
X1 setlinejoin
X72 RES div dup scale
XLS{
X90 rotate
X}{
X0 PL translate
X}ifelse
X1 -1 scale
X}bind def
X/EP{
Xlevel0 restore
Xshowpage
X}bind def
X/DA{
Xnewpath arcn stroke
X}bind def
X/SN{
Xtransform
X.25 sub exch .25 sub exch
Xround .25 add exch round .25 add exch
Xitransform
X}bind def
X/DL{
XSN
Xmoveto
XSN
Xlineto stroke
X}bind def
X/DC{
Xnewpath 0 360 arc closepath
X}bind def
X/TM matrix def
X/DE{
XTM currentmatrix pop
Xtranslate scale newpath 0 0 .5 0 360 arc closepath
XTM setmatrix
X}bind def
X/RC/rcurveto load def
X/RL/rlineto load def
X/ST/stroke load def
X/MT/moveto load def
X/CL/closepath load def
X/FL{
Xcurrentgray exch setgray fill setgray
X}bind def
X/BL/fill load def
X/LW/setlinewidth load def
X/RE{
Xfindfont
Xdup maxlength 1 index/FontName known not{1 add}if dict begin
X{
X1 index/FID ne{def}{pop pop}ifelse
X}forall
X/Encoding exch def
Xdup/FontName exch def
Xcurrentdict end definefont pop
X}bind def
X/DEFS 0 def
X/EBEGIN{
Xmoveto
XDEFS begin
X}bind def
X/EEND/end load def
X/CNT 0 def
X/level1 0 def
X/PBEGIN{
X/level1 save def
Xtranslate
Xdiv 3 1 roll div exch scale
Xneg exch neg exch translate
X0 setgray
X0 setlinecap
X1 setlinewidth
X0 setlinejoin
X10 setmiterlimit
X[]0 setdash
X/setstrokeadjust where{
Xpop
Xfalse setstrokeadjust
X}if
X/setoverprint where{
Xpop
Xfalse setoverprint
X}if
Xnewpath
X/CNT countdictstack def
Xuserdict begin
X/showpage{}def
X}bind def
X/PEND{
Xclear
Xcountdictstack CNT sub{end}repeat
Xlevel1 restore
X}bind def
Xend def
X/setpacking where{
Xpop
Xsetpacking
X}if
X%%EndResource
X%%IncludeResource: font Times-Bold
X%%IncludeResource: font Times-Roman
X%%IncludeResource: font Times-Italic
X%%IncludeResource: font Courier
Xgrops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
X792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
X/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
X/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
X/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
X/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
X/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
X/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
X/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
X/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
X/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
X/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
X/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
X/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
X/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
X/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
X/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
X/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
X/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
X/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
X/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
X/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
X/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
X/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
X/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
X/udieresis/yacute/thorn/ydieresis]def/Courier@0 ENC0/Courier RE/Times-Italic@0
XENC0/Times-Italic RE/Times-Roman@0 ENC0/Times-Roman RE/Times-Bold@0 ENC0
X/Times-Bold RE
X%%EndProlog
X%%Page: 1 1
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 14/Times-Bold@0 SF -.21(Ja)236.378 100.8 S 3.5(m\212M).21 G(ak)296.046
X100.8 Q(e\(1\) Redux)-.14 E/F1 12/Times-Roman@0 SF(Christopher Seiw)256.896
X148.8 Q(ald)-.12 E/F2 12/Times-Italic@0 SF(INGRES Corpor)253.92 163.2 Q(ation)
X-.18 E F1(Seiw)253.038 177.6 Q(a...@Ingres.Com)-.12 E(March 11, 1994)267.84 192
XQ/F3 11/Times-Roman@0 SF(Abstract)287.366 234 Q/F4 10/Times-Roman@0 SF .171
X(Despite the progress of UNIX, the basic mechanism by which de)110 250.2 R -.15
X(ve)-.25 G .17(lopers b).15 F .17(uild their programs \212)-.2 F/F5 10
X/Times-Italic@0 SF(mak)110 262.2 Q(e)-.1 E F4 .399
X(\(1\) \212 has remained at its core unimpro)B -.15(ve)-.15 G 2.899(ds).15 G
X.399(ince its inception.)312.192 262.2 R .4(Most notably)5.4 F 2.9(,t)-.65 G
X(he)450.21 262.2 Q F5(mak)2.9 E(e)-.1 E F4(lan-)2.9 E .147(guage has seen fe)
X110 274.2 R 2.647(wi)-.25 G(mpro)193.088 274.2 Q -.15(ve)-.15 G 2.647
X(ments. Jam).15 F .146(is a)2.647 F F5(mak)2.646 E(e)-.1 E F4 .146
X(replacement that uses an e)2.646 F .146(xtensible, e)-.15 F(xpressi)-.15 E
X-.15(ve)-.25 G .59(language for describing w)110 286.2 R .591
X(ays in which \214les relate.)-.1 F .591(This ne)5.591 F 3.091(wl)-.25 G .591
X(anguage simpli\214es the description)363.847 286.2 R .381
X(of systems, both small and lar)110 298.2 R .381(ge, and renders e)-.18 F .381
X(xtending Jam')-.15 F 2.881(sf)-.55 G .38(unctionality not only possible b)
X366.78 298.2 R(ut)-.2 E(easy)110 310.2 Q(.)-.65 E .958(Jam e)110 330.6 R .958
X(xists no)-.15 F 3.458(wa)-.25 G .958(nd runs on man)180.524 330.6 R 3.458(yU)
X-.15 G .958(NIX platforms, VMS, and NT)260.866 330.6 R 5.958(.I)-.74 G 3.458
X(ti)396.286 330.6 S 3.459(sf)405.304 330.6 S .959(reely a)415.983 330.6 R -.25
X(va)-.2 G .959(ilable in the).25 F .326(comp.sources.unix archi)110 342.6 R
X-.15(ve)-.25 G 2.826(s. As).15 F .325(proof of concept, it has been used to b)
X2.826 F .325(uild a v)-.2 F .325(ery lar)-.15 F .325(ge commer)-.18 F(-)-.2 E
X(cial product, generating in a single in)110 354.6 Q -.2(vo)-.4 G
X(cation 1,000 deli).2 E -.15(ve)-.25 G
X(rable \214les from 12,000 source \214les.).15 E/F6 11/Times-Bold@0 SF 2.75
X(1. Intr)90 382.8 R(oduction)-.198 E F4 1.016(The UNIX)90 399 R F5(mak)3.516 E
X(e)-.1 E F4 1.016(\(1\) program [Feldman, 1986], which automates the b)B 1.017
X(uilding of tar)-.2 F 1.017(gets from their source)-.18 F 1.033
X(\214les, is widely used.)90 411 R -.8(To)6.033 G 1.033
X(gether with its compatible successors \().8 F F5(dmak)A(e)-.1 E F4([V)3.533 E
X1.033(adura, 1990], GNU)-1.11 F F5(mak)3.532 E(e)-.1 E F4([Stall-)3.532 E 1.02
X(man, 1991], NET2)90 423 R F5(mak)3.52 E(e)-.1 E F4 1.021([BSD, 1991], SunOS)
X3.52 F F5(mak)3.521 E(e)-.1 E F4 1.021([Sun, 1989]\) and mutations \()3.521 F
XF5(cak)A(e)-.1 E F4 1.021([Somogyi, 1987],)3.521 F F5(cook)90 435 Q F4([Miller)
X2.835 E 2.835(,1)-.4 G(993],)149.98 435 Q F5(nmak)2.835 E(e)-.1 E F4([F)2.835 E
X-.25(ow)-.15 G(ler).25 E 2.835(,1)-.4 G .335(985], Plan 9)243.675 435 R F5(mk)
X2.834 E F4([Flandrena],)2.834 E F5(mms)2.834 E F4 .334(on VMS, etc.\),)2.834 F
XF5(mak)2.834 E(e)-.1 E F4(enjo)2.834 E .334(ys w)-.1 F(orld)-.1 E
X(domination in its capacity)90 447 Q(.)-.65 E(As)90 463.2 Q F5(mak)3.446 E(e)
X-.1 E F4 2.046 -.55('s a)D(uthor).55 E 3.446(,S)-.4 G .946
X(tuart Feldman, noted,)172.328 463.2 R F5(mak)3.446 E(e)-.1 E F4 .946
X(itself is not suited for describing huge programs.)3.446 F .947(This is)5.947
XF(ar)90 475.2 Q .013(guably because the)-.18 F F5(mak)2.513 E(e)-.1 E F4 .013
X(language has one useful statement: the e)2.513 F .012
X(xpression of a direct dependenc)-.15 F 2.512(ya)-.15 G(mong)499.22 475.2 Q
X2.667(\214les. This)90 487.2 R(mak)2.667 E .167(es for a clumsy)-.1 F 2.667(,b)
X-.65 G .168(ottom-up description of ho)222.742 487.2 R 2.668(wt)-.25 G 2.668
X(ob)342.604 487.2 S .168(uild a system \212 describing lar)355.072 487.2 R .168
X(ge systems)-.18 F .26(this w)90 499.2 R .26(ay is unmanageable.)-.1 F F5(mak)
X5.26 E(e)-.1 E F4 1.36 -.55('s s)D .26(uccessors try to o).55 F -.15(ve)-.15 G
X.26(rcome this dif).15 F .26(\214culty with sundry tricks:)-.25 F(dependen-)
X5.26 E .234(cies with wild-carded names matched ag)90 511.2 R .235
X(ainst directory contents; parsing command output as Mak)-.05 F .235
X(e\214le syn-)-.1 F(tax; macro e)90 523.2 Q
X(xpansions with and without the help of the C preprocessor)-.15 E 2.5(,e)-.4 G
X(tc.)381.35 523.2 Q .668(Jam is an attempt to replace)90 539.4 R F5(mak)3.168 E
X(e)-.1 E F4 1.768 -.55('s r)D .667
X(ule system, with its bottom-up language and w).55 F(ayw)-.1 E .667
X(ard implicit rules,)-.1 F .986(with an e)90 551.4 R(xpressi)-.15 E 1.286 -.15
X(ve l)-.25 H .986(anguage that mak).15 F .986(es it possible to describe e)-.1
XF .986(xplicitly and cogently the compilation of)-.15 F 2.819(programs. The)90
X563.4 R .319(current practice of b)2.819 F .319
X(uilding source simply because it matched wildcards is unreliable in the)-.2 F
X-.1(fa)90 575.4 S 1.211(ce of debris left around by a careless programmer).1 F
X6.211(.A)-.55 G(rob)324.72 575.4 Q 1.211(ust product should be b)-.2 F 1.212
X(uilt e)-.2 F(xplicitly)-.15 E 3.712(,a)-.65 G 1.212(nd to)500.508 575.4 R(mak)
X90 587.4 Q 2.5(et)-.1 G(his palatable, Jam mak)116.84 587.4 Q
X(es it easy to be e)-.1 E(xplicit.)-.15 E 2.5(At)90 603.6 S
X(ypical sample of Jam')102.5 603.6 Q 2.5(sl)-.55 G
X(anguage as seen by end-users will serv)199.16 603.6 Q 2.5(et)-.15 G 2.5(oa)
X363.69 603.6 S(nchor its description:)375.63 603.6 Q/F7 10/Courier@0 SF
X(MAIN prog : prog.c ;)130 619.8 Q(LIBS prog : libaux.a ;)130 631.8 Q
X(LIBRARY libaux.a : compile.c gram.y scan.c ;)130 643.8 Q F4 .489(This e)90
X664.2 R .489(xample in)-.15 F -.2(vo)-.4 G -.1(ke).2 G 2.989(st).1 G .489
X(hree rules that instruct Jam to b)183.667 664.2 R .488(uild an archi)-.2 F
X.788 -.15(ve f)-.25 H .488(rom three source \214les, to compile a).15 F .106
X(fourth source \214le, and to link it ag)90 676.2 R .107(ainst the archi)-.05 F
X-.15(ve)-.25 G 5.107(.A).15 G .107
X(ll three rules, as well as all other rules gi)306.973 676.2 R -.15(ve)-.25 G
X2.607(na).15 G 2.607(se)490.663 676.2 S(xam-)501.45 676.2 Q(ples in this paper)
X90 688.2 Q 2.5(,a)-.4 G(re stock ones that come with Jam \(see)167.09 688.2 Q
XF5 -.35(Ja)2.5 G(mbase).35 E F4(\(5\) [Seiw)A(ald, 1993]\).)-.1 E EP
X%%Page: 2 2
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 11/Times-Bold@0 SF 2.75(2. The)90 96 R -.165(Ja)2.75 G 2.75(mL).165 G
X(anguage)154.922 96 Q/F1 10/Times-Roman@0 SF .429(As with)90 112.2 R/F2 10
X/Times-Italic@0 SF(mak)2.929 E(e)-.1 E F1 2.929(,t)C .429
X(he most important statement in the Jam language is the e)153.957 112.2 R .428
X(xpression of a relationship among)-.15 F 3.416(\214les. W)90 124.2 R(ith)-.4 E
XF2(mak)3.416 E(e)-.1 E F1 3.416(,t)C .916
X(he relationship is a direct dependenc)167.798 124.2 R .916
X(y; with Jam, the relationship is user)-.15 F 3.416(-de\214ned. The)-.2 F -.15
X(ex)90 136.2 S(pression of such a relationship is:).15 E/F3 10/Courier@0 SF
X(<RULE> <targets> [ : <sources> ] ;)130 152.4 Q F1 .658
X(This statement is referred to as a rule in)90 172.8 R -.2(vo)-.4 G .658
X(cation, with the name of the rule leading the statement.).2 F(Except)5.657 E
X.328(for a handful of b)90 184.8 R .329
X(uilt-in rules, the de\214nition of a rule is user)-.2 F 2.829(-de\214ned. The)
X-.2 F .329(<sources> are optional.)2.829 F .329(Each of)5.329 F
X(the three lines in the e)90 196.8 Q(xample abo)-.15 E .3 -.15(ve a)-.15 H
X(re rule in).15 E -.2(vo)-.4 G(cations.).2 E 1.732(Because rules in)90 213 R
X-.2(vo)-.4 G 1.932 -.1(ke e).2 H 1.732(ach other).1 F 4.232(,t)-.4 G 1.731
X(he e)234.19 213 R 1.731(xpression of a user)-.15 F 1.731
X(-de\214ned relationship can result in other user)-.2 F(-)-.2 E .724
X(de\214ned relationships being made among the same or dif)90 225 R .725
X(ferent \214les.)-.25 F .725(In the case of the e)5.725 F .725(xample gi)-.15 F
X-.15(ve)-.25 G .725(n, the).15 F(MAIN rule will in)90 237 Q -.2(vo)-.4 G .2 -.1
X(ke t).2 H(he rules:).1 E F3(CC prog.o : prog.c ;)130 253.2 Q
X(LINK prog : prog.o ;)130 265.2 Q F1 .465(These rules \(presumably\) handle th\
Xe cases of compiling an object module from a C source \214le and linking)90
X285.6 R(that object module into an e)90 297.6 Q -.15(xe)-.15 G(cutable.).15 E
XF0 2.75(2.1. Rule)90 313.8 R(De\214nition)2.75 E F1 2.973(Ar)90 330 S .473
X(ule is de\214ned in tw)103.523 330 R 2.973(op)-.1 G .474
X(arts: the Jam statements to e)194.398 330 R -.15(xe)-.15 G .474
X(cute when the rule is in).15 F -.2(vo)-.4 G -.1(ke).2 G 2.974(d\().1 G .474
X(essentially a proce-)443.852 330 R .881(dure call\); and the actions \()90 342
XR F2(sh)A F1 .881(\(1\) commands\) to e)B -.15(xe)-.15 G .881
X(cute in order to update the tar).15 F .881(gets of the rule.)-.18 F 3.381(Ar)
X5.881 G(ule)509.78 342 Q(may ha)90 354 Q .3 -.15(ve a p)-.2 H
X(rocedure de\214nition, actions, or both.).15 E 2.5(Ar)90 370.2 S(ule')103.05
X370.2 Q 2.5(sp)-.55 G(rocedure de\214nition is gi)129.44 370.2 Q -.15(ve)-.25 G
X2.5(nw).15 G(ith:)248.47 370.2 Q F3(rule <RULE> { <statements> })130 386.4 Q F1
X.191(This statement causes <statements> to be interpreted by Jam whene)90 406.8
XR -.15(ve)-.25 G 2.692(r<).15 G -.4(RU)383.382 406.8 S .192(LE> is in).4 F -.2
X(vo)-.4 G -.1(ke).2 G 2.692(d. The).1 F(<tar)2.692 E(gets>)-.18 E 1.13
X(and <sources> gi)90 418.8 R -.15(ve)-.25 G 3.63(na).15 G 3.63(tr)182.86 418.8
XS 1.13(ule in)192.6 418.8 R -.2(vo)-.4 G 1.13(cation are a).2 F -.25(va)-.2 G
X1.13(ilable as the special v).25 F 1.13
X(ariables $\(<\) and $\(>\) in the <state-)-.25 F .571
X(ments> de\214ning the rule.)90 430.8 R .572(<statements> may be an)5.572 F
X3.072(yo)-.15 G 3.072(ft)309.104 430.8 S .572
X(he Jam statements listed in this document.)318.286 430.8 R(Carry-)5.572 E
X(ing on the CC e)90 442.8 Q(xample, a de\214nition for the CC rule might be:)
X-.15 E F3(rule CC)130 459 Q({)130 471 Q(DEPENDS $\(<\) : $\(>\) ;)166 483 Q(})
X130 495 Q F1 1.003
X(This particular rule de\214nition simply arranges for the tar)90 515.4 R 1.002
X(gets to depend on the sources, using the b)-.18 F(uilt-in)-.2 E
X(rule DEPENDS \(described belo)90 527.4 Q(w\).)-.25 E 2.5(Ar)90 543.6 S(ule')
X103.05 543.6 Q 2.5(su)-.55 G(pdating actions are gi)129.44 543.6 Q -.15(ve)-.25
XG 2.5(nw).15 G(ith:)239.02 543.6 Q F3(actions <RULE> { <string> })130 559.8 Q
XF1 .29(This causes the)90 580.2 R F2(sh)2.79 E F1 .291
X(script <string> to be associated with the <tar)2.79 F .291(gets> in an)-.18 F
X2.791(yi)-.15 G -1.9 -.4(nv o)401.267 580.2 T .291(cation of <R).4 F 2.791
X(ULE>. Later)-.4 F(,)-.4 E .367(if Jam determines that the <tar)90 592.2 R .367
X(gets> are out-of-date, it will pass <string> to)-.18 F F2(sh)2.867 E F1 .367
X(for e)2.867 F -.15(xe)-.15 G 2.867(cution. Jam).15 F -.15(ex)2.867 G(pands).15
XE .065($\(<\) and $\(>\) in <string>, b)90 604.2 R .065
X(ut $\(<\) and $\(>\) in this case refer to the <tar)-.2 F .065
X(gets> and <sources> after the)-.18 F 2.565(yh)-.15 G -2.25 -.2(av e)508.47
X604.2 T .258(been bound to real \214le path names \(see Binding, belo)90 616.2
XR 2.758(w\). Finishing)-.25 F .258(out the CC e)2.758 F .257
X(xample, a de\214nition of CC)-.15 F(actions w)90 628.2 Q(ould be:)-.1 E F3
X(actions CC)130 644.4 Q({)130 656.4 Q(cc -c $\(CCFLAGS\) -I$\(HDRS\) $\(>\))178
X668.4 Q(})130 680.4 Q EP
X%%Page: 3 3
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 11/Times-Bold@0 SF 2.75(2.2. Rule)90 96 R(Effects)2.75 E/F1 10
X/Times-Roman@0 SF .631(Rule in)90 112.2 R -.2(vo)-.4 G .631(cations ha).2 F
X.931 -.15(ve n)-.2 H 3.131(oo).15 G .632(utputs or return v)200.454 112.2 R
X.632(alues and, instead, do their job through three distinct types of)-.25 F
X(side-ef)90 124.2 Q 3.793(fects. The)-.25 F 1.293(\214rst is when a rule')3.793
XF 3.793(sp)-.55 G 1.293(rocedure in)258.491 124.2 R -.2(vo)-.4 G -.1(ke).2 G
X3.793(sb).1 G 1.292(uilt-in rules to modify the tar)336.267 124.2 R 1.292
X(get dependenc)-.18 F(y)-.15 E 2.628(graph. These)90 136.2 R -.2(bu)2.628 G
X.128(ilt-ins will be discussed shortly).2 F 5.129(.T)-.65 G .129
X(he second is when a rule')294.759 136.2 R 2.629(sp)-.55 G .129
X(rocedure sets v)407.733 136.2 R 2.629(ariables. The)-.25 F .156
X(third is the association of the updating actions with the tar)90 148.2 R .155
X(gets, which occurs whene)-.18 F -.15(ve)-.25 G 2.655(rar).15 G .155
X(ule with updating)451.69 148.2 R(actions is in)90 160.2 Q -.2(vo)-.4 G -.1(ke)
X.2 G(d.).1 E F0 2.75(2.3. Built-in)90 176.4 R(Rules)2.75 E F1 .935
X(There are six b)90 192.6 R .935(uilt-in rules, \214v)-.2 F 3.435(eo)-.15 G
X3.435(fw)228.85 192.6 S .935(hich modify the tar)242.835 192.6 R .935
X(get dependenc)-.18 F 3.435(yg)-.15 G 3.436(raph. None)393.54 192.6 R .936
X(of these rules ha)3.436 F -.15(ve)-.2 G(updating actions.)90 204.6 Q(The b)5 E
X(uilt-in rules are:)-.2 E/F2 10/Courier@0 SF
X(DEPENDS, INCLUDES, ECHO, TEMPORARY, NOTIME, NOCARE)130 220.8 Q F1 .923
X(DEPENDS and INCLUDES tak)90 241.2 R 3.423(e<)-.1 G(tar)234.772 241.2 Q .923
X(gets> and <sources>.)-.18 F .923(ECHO tak)5.923 F .922(es only <tar)-.1 F
X3.422(gets>. TEMPORAR)-.18 F -1.29(Y,)-.65 G(NO)90 253.2 Q 1.169
X(TIME, and NOCARE tak)-.4 F 3.669(eo)-.1 G 1.169(nly <tar)222.766 253.2 R 1.169
X(gets> and mark them with attrib)-.18 F 1.17(utes to indicate special handling)
X-.2 F(when descending the dependenc)90 265.2 Q 2.5(yg)-.15 G(raph.)231.48 265.2
XQ(DEPENDS)90 281.4 Q .713(The basic b)115 293.4 R .712(uilder of the dependenc)
X-.2 F 3.212(yg)-.15 G .712(raph: it mak)271.664 293.4 R .712
X(es <sources> dependencies of <tar)-.1 F .712(gets>, just lik)-.18 F(e)-.1 E
X.594(the simple)115 305.4 R/F3 10/Times-Italic@0 SF(mak)3.094 E(e)-.1 E F1 .594
X(\231:\232 dependenc)3.094 F 4.394 -.65(y. I)-.15 H 3.095(f<).65 G .595
X(sources> are ne)269.375 305.4 R .595(wer than <tar)-.25 F .595
X(gets> \(using \214le update times for)-.18 F 2.239(comparison\), or if <sourc\
Xes> are being updated, then the updating actions of <tar)115 317.4 R 2.239
X(gets> will be)-.18 F -.15(exe)115 329.4 S(cuted.).15 E(INCLUDES)90 345.6 Q
X3.479(Av)115 357.6 S .979(ariation on DEPENDS: it mak)130.449 357.6 R .979
X(es <sources> dependencies of an)-.1 F 3.479(yt)-.15 G(ar)401.64 357.6 Q .98
X(gets of which <tar)-.18 F .98(gets> are)-.18 F 2.5(dependencies. This)115
X369.6 R -.15(ex)2.5 G(ample mak).15 E
X(es both foo.c and foo.h dependencies of foo.o:)-.1 E F2
X(DEPENDS foo.o : foo.c ;)155 385.8 Q(INCLUDES foo.c : foo.h ;)155 397.8 Q F1
X(ECHO)90 418.2 Q 1.684(Just echoes its tar)115 430.2 R 1.684
X(gets to the standard output, as a means for communicating with the user)-.18 F
X6.683(.J)-.55 G(am)509.78 430.2 Q(kno)115 442.2 Q(ws no f)-.25 E(atal error)-.1
XE 2.5(,s)-.4 G 2.5(ot)203.95 442.2 S
X(he message emitted by ECHO can only be advisory)214.23 442.2 Q(.)-.65 E
X(TEMPORAR)90 458.4 Q(Y)-.65 E(Allo)115 470.4 Q .097(ws for intermediate tar)
X-.25 F .098(gets to be missing and not updated if the \214nal tar)-.18 F .098
X(get is up-to-date.)-.18 F .098(If a tar)5.098 F(-)-.2 E 1.131(get mark)115
X482.4 R 1.131(ed TEMPORAR)-.1 F 3.631(Yi)-.65 G 3.631(sn)231.803 482.4 S 1.131
X(ot present, then it simply inherits its parent')244.324 482.4 R 3.63(st)-.55 G
X1.13(ime-stamp. TEMPO-)436.43 482.4 R(RAR)115 494.4 Q 3.077(Yc)-.65 G .577
X(an be used for an)149.647 494.4 R 3.077(yt)-.15 G .577(emporary tar)230.972
X494.4 R .577(get, such as the short-li)-.18 F -.15(ve)-.25 G 3.077(do).15 G
X.578(bject module that is to be part)399.654 494.4 R(of a library archi)115
X506.4 Q -.15(ve)-.25 G(.).15 E(NO)90 522.6 Q(TIME)-.4 E 1.052
X(Indicates that the tar)115 534.6 R 1.051
X(get is not really a \214le and therefore doesn')-.18 F 3.551(th)-.18 G -2.25
X-.2(av e)387.756 534.6 T 3.551(at)3.751 G 3.551(ime-stamp. An)415.608 534.6 R
X3.551(yu)-.15 G(pdating)492 534.6 Q .386(actions are only e)115 546.6 R -.15
X(xe)-.15 G .387(cuted if the tar).15 F(get')-.18 E 2.887(sd)-.55 G .387
X(ependencies were updated, rather than on the basis of time-)281.357 546.6 R
X.016(stamp comparisons.)115 558.6 R(NO)5.016 E .016
X(TIME is used for pseudo tar)-.4 F .015
X(gets such as \231all\232 or \231install\232, which ha)-.18 F .315 -.15(ve d)
X-.2 H(epen-).15 E(dencies b)115 570.6 Q(ut don')-.2 E 2.5(ta)-.18 G
X(ctually get b)190.44 570.6 Q(uilt themselv)-.2 E(es.)-.15 E(NOCARE)90 586.8 Q
X.58(Indicates that the tar)115 598.8 R .58(get may both be non-e)-.18 F .581
X(xistent and not ha)-.15 F .881 -.15(ve a)-.2 H .881 -.15(ny u).15 H .581
X(pdating actions.).15 F .581(This loophole)5.581 F(is used to mak)115 610.8 Q
X2.5(eu)-.1 G 2.5(pf)184.34 610.8 S(or the sloppiness of the header)195.17 610.8
XQ(-\214le scanning.)-.2 E F0 2.75(2.4. J)90 627 R(am V)-.165 E(ariables)-1.012
XE F1 -.15(Pa)90 643.2 S 1.015(rt of Jam').15 F 3.515(sp)-.55 G 1.015
X(rogrammability lies in its treatment of v)152.615 643.2 R 3.515(ariables. As)
X-.25 F(with)3.515 E F3(mak)3.515 E(e)-.1 E F1(and)3.514 E F3(sh)3.514 E F1
X3.514(,J)C 1.014(am v)454.692 643.2 R 1.014(ariables are)-.25 F .143
X(lists of strings, with zero or more elements.)90 655.2 R .143
X(But unique to Jam, the result of v)5.143 F .143(ariable e)-.25 F .144
X(xpansion is the prod-)-.15 F(uct of the v)90 667.2 Q(ariable v)-.25 E
X(alues and literal constants in the tok)-.25 E(en being e)-.1 E 2.5
X(xpanded. An)-.15 F -.15(ex)2.5 G(ample helps here:).15 E F2($\(X\) -> a b c)
X130 683.4 Q(t$\(X\) -> ta tb tc)130 695.4 Q
X($\(X\)$\(X\) -> aa ab ac ba bb bc ca cb cc)130 707.4 Q EP
X%%Page: 4 4
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 10/Times-Roman@0 SF .41(This approach mak)90 96 R .41(es quick w)-.1 F .41
X(ork of man)-.1 F 2.909(yn)-.15 G .409(ormal v)268.319 96 R .409
X(ariable manipulations: prepending a path name to a list)-.25 F(of \214le name\
Xs, prepending \231-l\232 to a list of library names, appending a \231,v\232 to\
X RCS \214le names, etc.)90 108 Q 1.459(Jam has a modicum of v)90 124.2 R 1.46
X(ariable editing options to replace components of a path name and to subselect)
X-.25 F(members of a list.)90 136.2 Q
X(These options are discussed in usable detail in Jam')5 E 2.5(sm)-.55 G
X(anual page [Seiw)386.92 136.2 Q(ald, 1993].)-.1 E(Unlik)90 152.4 Q(e)-.1 E/F1
X10/Times-Italic@0 SF(mak)3.336 E(e)-.1 E F0 3.336(,J)C .836
X(am does not defer e)151.182 152.4 R .835(xpansion of v)-.15 F 3.335
X(ariables. When)-.25 F 3.335(av)3.335 G .835(ariable is referenced, e)367.72
X152.4 R -.15(ve)-.25 G 3.335(nt).15 G 3.335(oa)480.89 152.4 S .835(ssign a)
X493.665 152.4 R(ne)90 164.4 Q 2.5(wv)-.25 G(ariable, the v)113.66 164.4 Q
X(alue is e)-.25 E(xpanded at that time.)-.15 E 1.563(Jam v)90 180.6 R 1.563
X(ariables ha)-.25 F 1.863 -.15(ve t)-.2 H 1.763 -.1(wo s).15 H 1.563
X(copes: global and tar).1 F 4.064(get-speci\214c. Global)-.18 F -.25(va)4.064 G
X1.564(riables beha).25 F 1.864 -.15(ve m)-.2 H 1.564(uch as one might).15 F
X-.15(ex)90 192.6 S .25(pect, holding their v).15 F .25(alue until reassigned.)
X-.25 F -.8(Ta)5.25 G -.18(rg).8 G .25(et-speci\214c v).18 F .25(ariables tak)
X-.25 F 2.75(ep)-.1 G .25(recedence o)395.46 192.6 R -.15(ve)-.15 G 2.75(rg).15
XG .25(lobal v)463.4 192.6 R(ariables)-.25 E .063(when the speci\214ed tar)90
X204.6 R .064(get is being bound \(see belo)-.18 F .064(w\) or updated.)-.25 F
X.064(The distinction between global and tar)5.064 F(get-)-.18 E .273
X(speci\214c v)90 216.6 R .273(ariables is made when the v)-.25 F .272
X(ariables are assigned.)-.25 F .272(The syntax for setting the tw)7.772 F 2.772
X(ot)-.1 G .272(ypes is, respec-)460.086 216.6 R(ti)90 228.6 Q -.15(ve)-.25 G
X(ly:).15 E/F2 10/Courier@0 SF(<var> = <value> ;)130 244.8 Q
X(<var> on <targets> = <value> ;)130 256.8 Q F0 -.8(Ta)90 277.2 S -.18(rg).8 G
X1.009(et-speci\214c v).18 F 1.009(ariables ha)-.25 F 1.309 -.15(ve s)-.2 H
X-2.15 -.25(ev e).15 H 1.009(ral uses.).25 F 3.509(As)6.009 G 1.009
X(imple one is to permit dif)285.684 277.2 R 1.01
X(ferent compiler \215ag settings for)-.25 F(dif)90 289.2 Q .06
X(ferent source \214les.)-.25 F .06(In this w)5.06 F(ay)-.1 E 2.56(,t)-.65 G .06
X(he actions of the CC rule may be used to compile an)231.28 289.2 R 2.56(yCs)
X-.15 G .06(ource \214le, with)461.61 289.2 R -.25(va)90 301.2 S .484
X(rious \215ags \(HDRS, CCFLA).25 F .484(GS\) being adjusted per)-.4 F(-tar)-.2
XE 2.985(get. Other)-.18 F .485(uses of tar)2.985 F .485(get-speci\214c v)-.18 F
X.485(ariables will be)-.25 F(discussed shortly)90 313.2 Q(.)-.65 E/F3 11
X/Times-Bold@0 SF 2.75(2.5. Flo)90 329.4 R(w-of-Contr)-.11 E(ol)-.198 E F0 .86
X(In addition to statements for de\214ning and in)90 345.6 R -.2(vo)-.4 G .859
X(king rules and setting v).2 F .859(ariables, the Jam language contains)-.25 F
X(statements for \215o)90 357.6 Q(w-of-control and \214le inclusion.)-.25 E
X(The statements are:)5 E F2
X(if <condition> { <statements> } [ else { <statements> } ])130 373.8 Q
X(for <var> in <value> { <statements> })130 397.8 Q
X(switch <value> { case <value> : <statements> ; ... })130 421.8 Q
X(include <file> ;)130 445.8 Q F0 .473(The \231if\232 statement does the ob)90
X466.2 R .474
X(vious; the <condition> is the usual mix of comparison and logical operators)
X-.15 F(applied to v)90 478.2 Q(ariables.)-.25 E .09
X(The \231for\232 statement iterates o)90 494.4 R -.15(ve)-.15 G 2.59(rt).15 G
X.089(he elements of <v)226.5 494.4 R .089(alue>, assigning the \(global\) v)
X-.25 F .089(ariable <v)-.25 F .089(ar> to each ele-)-.25 F(ment and e)90 506.4
XQ -.15(xe)-.15 G(cuting the statement block.).15 E
X(The \231switch\232 statement e)90 522.6 Q -.15(xe)-.15 G
X(cutes the statement block whose case <v).15 E(alue> matches the switch')-.25 E
X2.5(s<)-.55 G -.25(va)477.13 522.6 S(lue>.).25 E(The \231include\232 statement\
X sources another \214le containing Jam statements.)90 538.8 Q 1.377
X(Jam neither needs nor desires a macro preprocessor)90 555 R 6.377(.M)-.55 G
X1.377(aking rule de\214nitions and \214le inclusions normal)322.626 555 R 2.015
X(statements ob)90 567 R 2.014(viates a macro preprocessor for conditional comp\
Xilation, as these statements may appear)-.15 F .581(within Jam conditionals.)90
X579 R(Further)5.581 E 3.081(,p)-.4 G .581(reprocessing w)234.424 579 R .582
X(ould require the Jam language to play \231dodge-em\232 with)-.1 F
X(the preprocessor semantics.)90 591 Q EP
X%%Page: 5 5
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 11/Times-Bold@0 SF 2.75(3. Binding)90 96 R(Files)2.75 E/F1 10/Times-Roman@0
XSF .91(Jam can \214nd source and tar)90 112.2 R .91
X(get \214les in distant directories, much lik)-.18 F 3.41(et)-.1 G .91
X(he functionality of VP)375.33 112.2 R -1.11(AT)-.92 G 3.41(Hi)1.11 G 3.41(nG)
X491.93 112.2 S(NU)507.56 112.2 Q/F2 10/Times-Italic@0 SF(mak)90 124.2 Q(e)-.1 E
XF1(and)2.5 E F2(dmak)2.5 E(e)-.1 E F1(.)A .066(By def)90 140.4 R .066
X(ault, a tar)-.1 F .066(get is located at the actual path of the tar)-.18 F
X.066(get, relati)-.18 F .366 -.15(ve t)-.25 H 2.566(ot).15 G .066
X(he directory of Jam')379.24 140.4 R 2.566(si)-.55 G -1.9 -.4(nv o)468.934
X140.4 T 2.566(cation. If).4 F .051(the special v)90 152.4 R .051
X(ariable $\(LOCA)-.25 F .051
X(TE\) is set to a directory name, Jam locates the tar)-1.11 F .05
X(get in that directory \(correctly)-.18 F .273(concatenating the v)90 164.4 R
X.273(alue of $\(LOCA)-.25 F .274(TE\) and the tar)-1.11 F(get')-.18 E 2.774(sp)
X-.55 G .274(ath name\).)320.598 164.4 R .274(If $\(LOCA)5.274 F .274
X(TE\) is unset b)-1.11 F .274(ut the special)-.2 F -.25(va)90 176.4 S .203(ria\
Xble $\(SEARCH\) is set to a directory list, Jam searches along the directory l\
Xist for the tar).25 F .203(get \214le \(ag)-.18 F(ain,)-.05 E
X(correctly concatenating the path names\).)90 188.4 Q 1.18(Jam mak)90 204.6 R
X1.18(es a)-.1 F -.25(va)-.2 G 1.18(ilable the bound tar).25 F 1.181
X(get names by using them when e)-.18 F 1.181
X(xpanding $\(<\) and $\(>\) for updating)-.15 F 3.033(actions. Thus,)90 216.6 R
X3.033(at)3.033 G(ar)162.149 216.6 Q .533
X(get can be referred to by a short, unrooted name when in)-.18 F -.2(vo)-.4 G
X.533(king a rule to de\214ne a rela-).2 F .063(tionship, b)90 228.6 R .063
X(ut an)-.2 F 2.563(ys)-.15 G .064(hell commands manipulating the tar)163.179
X228.6 R .064(get see a path name usable from the current directory)-.18 F(.)
X-.65 E 2.23($\(SEARCH\) pro)90 244.8 R 2.23(vides VP)-.15 F -1.11(AT)-.92 G
X(H-lik)1.11 E 4.729(ef)-.1 G(unctionality)242.449 244.8 Q 4.729(,a)-.65 G(llo)
X301.248 244.8 Q 2.229(wing Jam to be in)-.25 F -.2(vo)-.4 G -.1(ke).2 G 4.729
X(di).1 G 4.729(nd)422.833 244.8 S 2.229(irectories other than)437.562 244.8 R
X.076(where the source li)90 256.8 R -.15(ve)-.25 G .076(s, while $\(LOCA).15 F
X.076(TE\) liberates Jam from the directory tree altogether)-1.11 F 5.077(.W)
X-.55 G .077(ith it, Jam can)465.659 256.8 R(run an)90 268.8 Q(ywhere.)-.15 E
X1.237(By setting $\(SEARCH\) and $\(LOCA)90 285 R 1.237(TE\) properly)-1.11 F
X3.737(,J)-.65 G 1.236(am can handle a v)305.922 285 R 1.236(ariety of b)-.25 F
X1.236(uild en)-.2 F 3.736(vironments. F)-.4 F(or)-.15 E -.15(ex)90 297 S .484(\
Xample, read-only source trees can be handled by pointing $\(SEARCH\) at a read\
X-only source code direc-).15 F .496(tory while pointing $\(LOCA)90 309 R .496
X(TE\) to a w)-1.11 F .496(orking directory)-.1 F 5.496(.A)-.65 G 2.996(sa)
X328.748 309 S .496(nother e)340.074 309 R .496
X(xample, \231sparse\232 source trees can be)-.15 F .323(handled by ha)90 321 R
X.324(ving $\(SEARCH\) contain tw)-.2 F 2.824(od)-.1 G .324
X(irectories: \214rst the de)276.072 321 R -.15(ve)-.25 G(loper').15 E 2.824(so)
X-.55 G .324(wn directory)405.588 321 R 2.824(,w)-.65 G .324(hich contains)
X468.626 321 R 1.097(only the \214les he is editing, and then his group')90 333
XR 3.597(sd)-.55 G(irectory)297.36 333 Q 3.597(,w)-.65 G 1.096
X(hich contains the master cop)341.127 333 R 3.596(yo)-.1 G 3.596(fa)472.878 333
XS 1.096(ll source.)484.244 333 R 1.932(Most importantly)90 345 R 4.432(,m)-.65
XG 1.932(uch of an)175.724 345 R 4.432(yb)-.15 G 1.933(uild en)230.88 345 R
X1.933(vironment can be encoded in the settings of $\(SEARCH\) and)-.4 F
X($\(LOCA)90 357 Q(TE\), which lea)-1.11 E -.15(ve)-.2 G 2.5(st).15 G
X(he \214le names used in rule in)201.85 357 Q -.2(vo)-.4 G
X(cations free from en).2 E(vironment.)-.4 E .774(The po)90 373.2 R .774
X(wer of $\(SEARCH\) and $\(LOCA)-.25 F .774(TE\) is realized when these v)-1.11
XF .774(ariables are set per)-.25 F(-tar)-.2 E .774(get rather than)-.18 F .486
X(just globally)90 385.2 R 5.486(.E)-.65 G .486(ach indi)153.662 385.2 R .486
X(vidual tar)-.25 F .486(get \214le can potentially be found along dif)-.18 F
X.486(ferent search paths.)-.25 F .486(In practice,)5.486 F 1.042
X(related \214les will ha)90 397.2 R 1.342 -.15(ve t)-.2 H 1.042
X(he same search path, b).15 F 1.042(ut Jam can ef)-.2 F 1.042
X(\214ciently accommodate the de)-.25 F 1.041(generate case of)-.15 F(ha)90
X409.2 Q .505(ving these v)-.2 F .505(ariables set per)-.25 F(-tar)-.2 E 3.005
X(get. In)-.18 F .505(this w)3.005 F(ay)-.1 E 3.005(,J)-.65 G .505(am can b)
X297.14 409.2 R .506(uild whole source trees, with source \214les scat-)-.2 F
X(tered across directories.)90 421.2 Q F0 2.75(4. Header)90 437.4 R
X(-File Inclusion)-.407 E F1 .581(Jam handles the incidental dependencies cause\
Xd when source \214les include other source \214les.)90 453.6 R 2.18 -.8
X(To \214)5.58 H .58(nd such).8 F 1.246
X(dependencies, Jam scans source \214les for header)90 465.6 R 1.246
X(-\214le inclusions, using a re)-.2 F 1.246(gular e)-.15 F 1.247
X(xpression pattern match)-.15 F([Spencer)90 477.6 Q 3.253(,1)-.4 G 3.253
X(986]. The)135.893 477.6 R(re)3.253 E .753(gular e)-.15 F .753(xpression is gi)
X-.15 F -.15(ve)-.25 G 3.253(ni).15 G 3.253(nt)296.351 477.6 S .752(he v)307.384
X477.6 R .752(ariable $\(HDRSCAN\).)-.25 F .752(The result of the scan is)5.752
XF .671(not interpreted directly by Jam; to arrange the necessary relationship,\
X Jam calls a user)90 489.6 R .672(-de\214ned rule named)-.2 F .796(in the v)90
X501.6 R .796(ariable $\(HDRR)-.25 F .796
X(ULE\), with the scanned \214le as <tar)-.4 F .796(gets> and the found header)
X-.18 F .796(-\214les as <sources>.)-.2 F(Usually)90 513.6 Q 3.034(,t)-.65 G
X.534(he de\214nition of $\(HDRR)128.774 513.6 R .534
X(ULE\) includes a call to the b)-.4 F .534
X(uilt-in rule INCLUDES, which updates the)-.2 F(dependenc)90 525.6 Q 2.5(yg)
X-.15 G(raph appropriately)145.11 525.6 Q 5(.A)-.65 G 2.5(ne)232.77 525.6 S
X(xample HDRSCAN that w)244.56 525.6 Q(orks for C preprocessor includes is:)-.1
XE/F3 10/Courier@0 SF
X(HDRSCAN = "^#[ \\t]*include[ \\t]*[<\\"]\(.*\)[\\">].*$" ;)130 541.8 Q F1
X1.693(The combination of $\(HDRSCAN\) and $\(HDRR)90 562.2 R 1.693
X(ULE\), when set per)-.4 F(-tar)-.2 E 1.693(get, enables Jam to handle just)
X-.18 F .679(about an)90 574.2 R 3.179(yi)-.15 G .679
X(nclude-\214le syntax or semantics.)135.648 574.2 R(Unfortunately)5.679 E 3.179
X(,t)-.65 G .679(his mechanism doesn')333.923 574.2 R 3.179(tu)-.18 G .68
X(nderstand conditional)434.94 574.2 R 1.103(includes \(#include within #ifdef\
X\), and can produce bogus dependencies that must be crudely pasted o)90 586.2 R
X-.15(ve)-.15 G(r).15 E(with the application of the b)90 598.2 Q
X(uilt-in NOCARE rule.)-.2 E F0 2.75(5. T)90 614.4 R(ime-Stamps)-.198 E F1(Lik)
X90 630.6 Q(e)-.1 E F2(mak)4.679 E(e)-.1 E F1 2.179
X(et. al., Jam uses time-stamps to determine when tar)4.679 F 2.18
X(gets are out-of-date.)-.18 F 2.18(Another possible)7.18 F 1.464
X(design, a more forw)90 642.6 R 1.464(ard-looking one, w)-.1 F 1.463(ould ha)
X-.1 F 1.763 -.15(ve J)-.2 H 1.463(am taking \214le update cues from an inte).15
XF 1.463(grated source)-.15 F .696(management system.)90 654.6 R .696(This w)
X5.696 F .696(as deferred for tw)-.1 F 3.196(or)-.1 G 3.196(easons: \214rst,)
X292.682 654.6 R .696(it w)3.196 F .696(ould require picking a source manage-)
X-.1 F .455(ment system with which to w)90 666.6 R .455
X(ork \(or attempting to engineer a generic interf)-.1 F .455
X(ace to source management sys-)-.1 F(tems\); second, it w)90 678.6 Q
X(ould preclude using Jam as a drop-in replacement for e)-.1 E(xisting uses of)
X-.15 E F2(mak)2.5 E(e)-.1 E F1(.)A .554(The code in Jam that checks dependenci\
Xes is isolated enough to be altered to w)90 694.8 R .554
X(ork with a source manage-)-.1 F .614(ment system.)90 706.8 R(Internally)5.613
XE 3.113(,J)-.65 G .613(am already distinguishes between updates due to ne)
X196.74 706.8 R .613(wer dependents and updates)-.25 F
X(due to updated dependents.)90 718.8 Q EP
X%%Page: 6 6
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 11/Times-Bold@0 SF 2.75(6. The)90 96 R(Base Rule Set)2.75 E/F1 10
X/Times-Roman@0 SF 2.838(Ac)90 112.2 S .338(ollection of rules pro)104.498 112.2
XR(viding)-.15 E/F2 10/Times-Italic@0 SF(mak)2.838 E(e)-.1 E F1(\255lik)A 2.839
X(ef)-.1 G .339(unctionality is supplied with Jam.)265.069 112.2 R .339
X(Called Jambase, the \214le pro-)5.339 F .685
X(vides a dozen-odd rules for compiling and linking C source code.)90 124.2 R
X(Dif)5.685 E .685(ferent v)-.25 F .685(ersions of Jambase e)-.15 F .685
X(xist for)-.15 F(UNIX, VMS, and NT)90 136.2 Q 2.5(,a)-.74 G(ll pro)185.63 136.2
XQ(viding the same rule set.)-.15 E(Figure 1 lists the rules de\214ned in the c\
Xurrent Jambase \(described comprehensi)90 152.4 Q -.15(ve)-.25 G(ly in).15 E F2
X-.35(Ja)2.5 G(mbase).35 E F1(\(5\)\).)A .4
X(The last act of Jambase is to include a \214le called Jam\214le from the in)90
X168.6 R -.2(vo)-.4 G .4(king user').2 F 2.9(sc)-.55 G .4(urrent directory)
X427.98 168.6 R 5.4(.U)-.65 G(sing)505.33 168.6 Q .33
X(the rules de\214ned in Jambase, the user')90 180.6 R 2.83(sJ)-.55 G .329
X(am\214le enumerates the source \214les and their relationship to the tar)
X254.51 180.6 R(-)-.2 E(gets to be b)90 192.6 Q(uilt.)-.2 E .231(The Jambase an\
Xd Jam\214le \214les share the same language; only their purposes distinguish t\
Xhem.)90 208.8 R .232(It is possible)5.232 F .012(to write a special-purpose re\
Xplacement Jambase that is totally self-contained and needs no directory-speci\
X\214c)90 220.8 R 3.499(Jam\214le. It)90 232.8 R .999
X(is also possible to use an)3.499 F 3.499(yJ)-.15 G 1
X(am syntax \212 including conditionals, rule de\214nitions, etc. \212 in a)
X252.842 232.8 R(Jam\214le.)90 244.8 Q F0 2.75(7. The)90 261 R(Example)2.75 E F1
X(Returning to our earlier e)90 277.2 Q(xample:)-.15 E/F3 10/Courier@0 SF
X(MAIN prog : prog.c ;)130 293.4 Q(LIBS prog : libaux.a ;)130 305.4 Q
X(LIBRARY libaux.a : compile.c gram.y scan.c ;)130 317.4 Q F1 .489(This e)90
X337.8 R .489(xample in)-.15 F -.2(vo)-.4 G -.1(ke).2 G 2.989(st).1 G .489
X(hree rules that instruct Jam to b)183.667 337.8 R .488(uild an archi)-.2 F
X.788 -.15(ve f)-.25 H .488(rom three source \214les, to compile a).15 F .528
X(fourth source \214le, and to link it ag)90 349.8 R .528(ainst the archi)-.05 F
X-.15(ve)-.25 G 5.528(.A).15 G .529
X(ll these rules are de\214ned by the Jambase \214le and do)311.19 349.8 R
X(most of their w)90 361.8 Q(ork by in)-.1 E -.2(vo)-.4 G
X(king other rules de\214ned in the Jambase.).2 E 1.068
X(MAIN calls LINK to set up the relationship between)90 378 R/F4 10/Times-Bold@0
XSF(pr)3.568 E(og)-.18 E F1(and)3.568 E F4(pr)3.568 E(og)-.18 E(.o)-.15 E F1
X3.568(,t)C 1.067(hen calls OBJECT to set up the)390.046 378 R .163
X(relationship between)90 390 R F4(pr)2.663 E(og)-.18 E(.o)-.15 E F1(and)2.664 E
XF4(pr)2.664 E(og)-.18 E(.c)-.15 E F1 5.164(.O)C .164
X(BJECT calls a rule speci\214c to the \214le suf)264.298 390 R .164
X(\214x, in this case, CC for)-.25 F F4(.c)90 402 Q F1 5(.A)C(long the w)111.66
X402 Q(ay)-.1 E 2.5(,t)-.65 G(he v)170.35 402 Q(arious rules in)-.25 E -.2(vo)
X-.4 G .2 -.1(ke t).2 H(he b).1 E(uilt-in DEPENDS rule to set up the dependenc)
X-.2 E 2.5(yg)-.15 G(raph.)483.18 402 Q .4 LW 95 441.6 90 441.6 DL 97 441.6 92
X441.6 DL 102 441.6 97 441.6 DL 107 441.6 102 441.6 DL 112 441.6 107 441.6 DL
X117 441.6 112 441.6 DL 122 441.6 117 441.6 DL 127 441.6 122 441.6 DL 132 441.6
X127 441.6 DL 137 441.6 132 441.6 DL 142 441.6 137 441.6 DL 147 441.6 142 441.6
XDL 152 441.6 147 441.6 DL 157 441.6 152 441.6 DL 162 441.6 157 441.6 DL 167
X441.6 162 441.6 DL 172 441.6 167 441.6 DL 177 441.6 172 441.6 DL 182 441.6 177
X441.6 DL 187 441.6 182 441.6 DL 192 441.6 187 441.6 DL 197 441.6 192 441.6 DL
X202 441.6 197 441.6 DL 207 441.6 202 441.6 DL 212 441.6 207 441.6 DL 217 441.6
X212 441.6 DL 222 441.6 217 441.6 DL 227 441.6 222 441.6 DL 232 441.6 227 441.6
XDL 237 441.6 232 441.6 DL 242 441.6 237 441.6 DL 247 441.6 242 441.6 DL 252
X441.6 247 441.6 DL 257 441.6 252 441.6 DL 262 441.6 257 441.6 DL 267 441.6 262
X441.6 DL 272 441.6 267 441.6 DL 277 441.6 272 441.6 DL 282 441.6 277 441.6 DL
X287 441.6 282 441.6 DL 292 441.6 287 441.6 DL 297 441.6 292 441.6 DL 302 441.6
X297 441.6 DL 307 441.6 302 441.6 DL 312 441.6 307 441.6 DL 317 441.6 312 441.6
XDL 322 441.6 317 441.6 DL 327 441.6 322 441.6 DL 332 441.6 327 441.6 DL 337
X441.6 332 441.6 DL 342 441.6 337 441.6 DL 347 441.6 342 441.6 DL 352 441.6 347
X441.6 DL 357 441.6 352 441.6 DL 362 441.6 357 441.6 DL 367 441.6 362 441.6 DL
X372 441.6 367 441.6 DL 377 441.6 372 441.6 DL 382 441.6 377 441.6 DL 387 441.6
X382 441.6 DL 392 441.6 387 441.6 DL 397 441.6 392 441.6 DL 402 441.6 397 441.6
XDL 407 441.6 402 441.6 DL 412 441.6 407 441.6 DL 417 441.6 412 441.6 DL 422
X441.6 417 441.6 DL 427 441.6 422 441.6 DL 432 441.6 427 441.6 DL 437 441.6 432
X441.6 DL 442 441.6 437 441.6 DL 447 441.6 442 441.6 DL 452 441.6 447 441.6 DL
X457 441.6 452 441.6 DL 462 441.6 457 441.6 DL 467 441.6 462 441.6 DL 472 441.6
X467 441.6 DL 477 441.6 472 441.6 DL 482 441.6 477 441.6 DL 487 441.6 482 441.6
XDL 492 441.6 487 441.6 DL 497 441.6 492 441.6 DL 502 441.6 497 441.6 DL 507
X441.6 502 441.6 DL 512 441.6 507 441.6 DL 517 441.6 512 441.6 DL 522 441.6 517
X441.6 DL/F5 9/Courier@0 SF(MAIN image : source ;)90 464.4 Q
X(link executable from compiled sources)246.6 464.4 Q(LIBS image : libraries ;)
X90 475.2 Q(link libraries onto a MAIN)246.6 475.2 Q
X(UNDEFINES image : symbols ;)90 486 Q(save undefs for linking)246.6 486 Q
X(SETUID image ;)90 496.8 Q(mark an executable SETUID)246.6 496.8 Q
X(LIBRARY lib : source ;)90 507.6 Q(archive library from compiled sources)246.6
X507.6 Q(OBJECT objname : source ;)90 518.4 Q(compile object from source)246.6
X518.4 Q(HDRRULE source : headers ;)90 529.2 Q(handle #includes)246.6 529.2 Q
X(CC obj.o : source.c ;)90 540 Q(.c -> .o)246.6 540 Q(LEX source.c : source.l ;)
X90 550.8 Q(.l -> .c)246.6 550.8 Q(YACC source.c : source.y ;)90 561.6 Q
X(.y -> .c)246.6 561.6 Q(YYACC source.y : source.yy ; .yy -> .y)90 572.4 Q
X(BULK dir : files ;)90 583.2 Q(populate directory with many files)246.6 583.2 Q
X(FILE dest : source ;)90 594 Q(copy file)246.6 594 Q(SHELL exe : source ;)90
X604.8 Q(install a shell executable)246.6 604.8 Q(RMTEMPS target : sources ;)90
X615.6 Q(remove temp sources after target made)246.6 615.6 Q
X(INSTALLBIN sources ;)90 626.4 Q(install binaries)246.6 626.4 Q
X(INSTALLLIB sources ;)90 637.2 Q(install files)246.6 637.2 Q
X(INSTALLMAN source ;)90 648 Q(install man pages)246.6 648 Q 95 660 90 660 DL 97
X660 92 660 DL 102 660 97 660 DL 107 660 102 660 DL 112 660 107 660 DL 117 660
X112 660 DL 122 660 117 660 DL 127 660 122 660 DL 132 660 127 660 DL 137 660 132
X660 DL 142 660 137 660 DL 147 660 142 660 DL 152 660 147 660 DL 157 660 152 660
XDL 162 660 157 660 DL 167 660 162 660 DL 172 660 167 660 DL 177 660 172 660 DL
X182 660 177 660 DL 187 660 182 660 DL 192 660 187 660 DL 197 660 192 660 DL 202
X660 197 660 DL 207 660 202 660 DL 212 660 207 660 DL 217 660 212 660 DL 222 660
X217 660 DL 227 660 222 660 DL 232 660 227 660 DL 237 660 232 660 DL 242 660 237
X660 DL 247 660 242 660 DL 252 660 247 660 DL 257 660 252 660 DL 262 660 257 660
XDL 267 660 262 660 DL 272 660 267 660 DL 277 660 272 660 DL 282 660 277 660 DL
X287 660 282 660 DL 292 660 287 660 DL 297 660 292 660 DL 302 660 297 660 DL 307
X660 302 660 DL 312 660 307 660 DL 317 660 312 660 DL 322 660 317 660 DL 327 660
X322 660 DL 332 660 327 660 DL 337 660 332 660 DL 342 660 337 660 DL 347 660 342
X660 DL 352 660 347 660 DL 357 660 352 660 DL 362 660 357 660 DL 367 660 362 660
XDL 372 660 367 660 DL 377 660 372 660 DL 382 660 377 660 DL 387 660 382 660 DL
X392 660 387 660 DL 397 660 392 660 DL 402 660 397 660 DL 407 660 402 660 DL 412
X660 407 660 DL 417 660 412 660 DL 422 660 417 660 DL 427 660 422 660 DL 432 660
X427 660 DL 437 660 432 660 DL 442 660 437 660 DL 447 660 442 660 DL 452 660 447
X660 DL 457 660 452 660 DL 462 660 457 660 DL 467 660 462 660 DL 472 660 467 660
XDL 477 660 472 660 DL 482 660 477 660 DL 487 660 482 660 DL 492 660 487 660 DL
X497 660 492 660 DL 502 660 497 660 DL 507 660 502 660 DL 512 660 507 660 DL 517
X660 512 660 DL 522 660 517 660 DL F1(Figure 1 \212 Rules supplied with Jam)
X232.665 684 Q EP
X%%Page: 7 7
X%%BeginPageSetup
XBP
X%%EndPageSetup
X.4 LW 95 108 90 108 DL 97 108 92 108 DL 102 108 97 108 DL 107 108 102 108 DL
X112 108 107 108 DL 117 108 112 108 DL 122 108 117 108 DL 127 108 122 108 DL 132
X108 127 108 DL 137 108 132 108 DL 142 108 137 108 DL 147 108 142 108 DL 152 108
X147 108 DL 157 108 152 108 DL 162 108 157 108 DL 167 108 162 108 DL 172 108 167
X108 DL 177 108 172 108 DL 182 108 177 108 DL 187 108 182 108 DL 192 108 187 108
XDL 197 108 192 108 DL 202 108 197 108 DL 207 108 202 108 DL 212 108 207 108 DL
X217 108 212 108 DL 222 108 217 108 DL 227 108 222 108 DL 232 108 227 108 DL 237
X108 232 108 DL 242 108 237 108 DL 247 108 242 108 DL 252 108 247 108 DL 257 108
X252 108 DL 262 108 257 108 DL 267 108 262 108 DL 272 108 267 108 DL 277 108 272
X108 DL 282 108 277 108 DL 287 108 282 108 DL 292 108 287 108 DL 297 108 292 108
XDL 302 108 297 108 DL 307 108 302 108 DL 312 108 307 108 DL 317 108 312 108 DL
X322 108 317 108 DL 327 108 322 108 DL 332 108 327 108 DL 337 108 332 108 DL 342
X108 337 108 DL 347 108 342 108 DL 352 108 347 108 DL 357 108 352 108 DL 362 108
X357 108 DL 367 108 362 108 DL 372 108 367 108 DL 377 108 372 108 DL 382 108 377
X108 DL 387 108 382 108 DL 392 108 387 108 DL 397 108 392 108 DL 402 108 397 108
XDL 407 108 402 108 DL 412 108 407 108 DL 417 108 412 108 DL 422 108 417 108 DL
X427 108 422 108 DL 432 108 427 108 DL 437 108 432 108 DL 442 108 437 108 DL 447
X108 442 108 DL 452 108 447 108 DL 457 108 452 108 DL 462 108 457 108 DL 467 108
X462 108 DL 472 108 467 108 DL 477 108 472 108 DL 482 108 477 108 DL 487 108 482
X108 DL 492 108 487 108 DL 497 108 492 108 DL 502 108 497 108 DL 507 108 502 108
XDL 512 108 507 108 DL 517 108 512 108 DL 522 108 517 108 DL/F0 9/Courier@0 SF
X(MAIN prog : prog.c ;)90 130.8 Q(DEPENDS exe : prog ;)100.8 141.6 Q
X(LINK prog : prog.o ;)100.8 152.4 Q(DEPENDS prog : prog.o ;)111.6 163.2 Q
X(OBJECT prog.o : prog.c ;)100.8 174 Q(CC prog.o : prog.c ;)111.6 184.8 Q
X(DEPENDS prog.o : prog.c ;)122.4 195.6 Q(LIBS prog : libaux.a ;)90 217.2 Q
X(DEPENDS prog : libaux.a ;)100.8 228 Q(NEEDLIBS on prog = libaux.a ;)100.8
X238.8 Q(LIBRARY libaux.a : compile.c gram.y scan.c ;)90 260.4 Q(DEPENDS libaux\
X.a : libaux.a\(compile.o\) libaux.a\(gram.o\) libaux.a\(scan.o\) ;)100.8 271.2
XQ(DEPENDS libaux.a\(compile.o\) : compile.o ;)100.8 282 Q
X(OBJECT compile.o : compile.c ;)100.8 292.8 Q(CC compile.o : compile.c ;)111.6
X303.6 Q(DEPENDS compile.o : compile.c)122.4 314.4 Q
X(DEPENDS libaux.a\(gram.o\) : gram.o ;)100.8 325.2 Q(OBJECT gram.o : gram.y ;)
X100.8 336 Q(CC gram.o : gram.c ;)111.6 346.8 Q(DEPENDS gram.o : gram.c)122.4
X357.6 Q(YACC gram.c : gram.y ;)111.6 368.4 Q(DEPENDS gram.c gram.h : gram.y ;)
X122.4 379.2 Q(INCLUDES gram.c : gram.h ;)122.4 390 Q
X(DEPENDS libaux.a\(scan.o\) : scan.o ;)100.8 400.8 Q(OBJECT scan.o : scan.c ;)
X100.8 411.6 Q(CC scan.o : scan.c ;)111.6 422.4 Q(DEPENDS scan.o : scan.c)122.4
X433.2 Q(ARCHIVE libaux.a : compile.o gram.o scan.o ;)100.8 444 Q
X(TEMPORARY compile.o gram.o scan.o ;)100.8 454.8 Q 95 466.8 90 466.8 DL 97
X466.8 92 466.8 DL 102 466.8 97 466.8 DL 107 466.8 102 466.8 DL 112 466.8 107
X466.8 DL 117 466.8 112 466.8 DL 122 466.8 117 466.8 DL 127 466.8 122 466.8 DL
X132 466.8 127 466.8 DL 137 466.8 132 466.8 DL 142 466.8 137 466.8 DL 147 466.8
X142 466.8 DL 152 466.8 147 466.8 DL 157 466.8 152 466.8 DL 162 466.8 157 466.8
XDL 167 466.8 162 466.8 DL 172 466.8 167 466.8 DL 177 466.8 172 466.8 DL 182
X466.8 177 466.8 DL 187 466.8 182 466.8 DL 192 466.8 187 466.8 DL 197 466.8 192
X466.8 DL 202 466.8 197 466.8 DL 207 466.8 202 466.8 DL 212 466.8 207 466.8 DL
X217 466.8 212 466.8 DL 222 466.8 217 466.8 DL 227 466.8 222 466.8 DL 232 466.8
X227 466.8 DL 237 466.8 232 466.8 DL 242 466.8 237 466.8 DL 247 466.8 242 466.8
XDL 252 466.8 247 466.8 DL 257 466.8 252 466.8 DL 262 466.8 257 466.8 DL 267
X466.8 262 466.8 DL 272 466.8 267 466.8 DL 277 466.8 272 466.8 DL 282 466.8 277
X466.8 DL 287 466.8 282 466.8 DL 292 466.8 287 466.8 DL 297 466.8 292 466.8 DL
X302 466.8 297 466.8 DL 307 466.8 302 466.8 DL 312 466.8 307 466.8 DL 317 466.8
X312 466.8 DL 322 466.8 317 466.8 DL 327 466.8 322 466.8 DL 332 466.8 327 466.8
XDL 337 466.8 332 466.8 DL 342 466.8 337 466.8 DL 347 466.8 342 466.8 DL 352
X466.8 347 466.8 DL 357 466.8 352 466.8 DL 362 466.8 357 466.8 DL 367 466.8 362
X466.8 DL 372 466.8 367 466.8 DL 377 466.8 372 466.8 DL 382 466.8 377 466.8 DL
X387 466.8 382 466.8 DL 392 466.8 387 466.8 DL 397 466.8 392 466.8 DL 402 466.8
X397 466.8 DL 407 466.8 402 466.8 DL 412 466.8 407 466.8 DL 417 466.8 412 466.8
XDL 422 466.8 417 466.8 DL 427 466.8 422 466.8 DL 432 466.8 427 466.8 DL 437
X466.8 432 466.8 DL 442 466.8 437 466.8 DL 447 466.8 442 466.8 DL 452 466.8 447
X466.8 DL 457 466.8 452 466.8 DL 462 466.8 457 466.8 DL 467 466.8 462 466.8 DL
X472 466.8 467 466.8 DL 477 466.8 472 466.8 DL 482 466.8 477 466.8 DL 487 466.8
X482 466.8 DL 492 466.8 487 466.8 DL 497 466.8 492 466.8 DL 502 466.8 497 466.8
XDL 507 466.8 502 466.8 DL 512 466.8 507 466.8 DL 517 466.8 512 466.8 DL 522
X466.8 517 466.8 DL/F1 10/Times-Roman@0 SF(Figure 2 \212 Rule e)186.125 490.8 Q
X-.15(xe)-.15 G(cution for the e).15 E(xample rule in)-.15 E -.2(vo)-.4 G
X(cations).2 E 1.039(LIBS is a rule that arranges for)90 514.8 R/F2 10
X/Times-Bold@0 SF(libaux.a)3.538 E F1 1.038(to become a dependenc)3.538 F 3.538
X(yo)-.15 G(f)371.432 514.8 Q F2(pr)3.538 E(og)-.18 E F1 3.538(,a)C 1.038
X(nd it sets the tar)408.598 514.8 R(get-speci\214c)-.18 E -.25(va)90 526.8 S
X1.096(riable NEEDLIBS to let the actions of LINK kno).25 F 3.596(wt)-.25 G(hat)
X317.944 526.8 Q F2(libaux.a)3.597 E F1 1.097
X(should be included on the link com-)3.597 F(mand line.)90 538.8 Q
X(LIBS has no actions of its o)5 E(wn.)-.25 E(LIBRAR)90 555 Q 2.79(Yi)-.65 G
X2.79(sar)138.81 555 S .289(ule that sets up the \(some)156.05 555 R .289
X(what complicated\) dependencies between the library)-.25 F F2(libaux.a)2.789 E
XF1 2.789(,i)C(ts)515.33 555 Q .167
X(members, and the temporary object modules that are to be its members.)90 567 R
X.167(It calls OBJECT to set up the rela-)5.167 F .65(tionship between each of \
Xthe temporary object modules and their source \214les.)90 579 R .65
X(It also calls the ARCHIVE)5.65 F(rule to handle the archi)90 591 Q
X(ving of the temporary object modules into)-.25 E F2(libaux.a)2.5 E F1(.)A 2.5
X(Am)90 607.2 S(ore complete list of rule in)107.5 607.2 Q -.2(vo)-.4 G
X(cations seen by Jam for this e).2 E(xample is gi)-.15 E -.15(ve)-.25 G 2.5(ni)
X.15 G 2.5(nF)408.54 607.2 S(igure 2.)421.6 607.2 Q .014
X(Probably lost in this litan)90 623.4 R 2.514(yo)-.15 G 2.515(fr)202.99 623.4 S
X.015(ules are some important features:)212.165 623.4 R .015
X(the OBJECT rule, when presented with the)5.015 F .527(task of making a \231.o\
X\232 \214le from a \231.y\232 \214le, called both the CC and Y)90 635.4 R -.4
X(AC)-1.2 G 3.027(Cr).4 G 3.027(ules. Note)393.185 635.4 R .527
X(that this is consider)3.027 F(-)-.2 E 1.117
X(ably easier and more deterministic than)90 647.4 R/F3 10/Times-Italic@0 SF
X(mak)3.617 E(e)-.1 E F1 2.217 -.55('s a)D 1.118
X(pproach of making a \231.o\232 from whate).55 F -.15(ve)-.25 G 3.618(rh).15 G
X1.118(appens to be)469.774 647.4 R -.2(av)90 659.4 S 4.267(ailable. Also,)-.05
XF 1.767(note that the Y)4.267 F -.4(AC)-1.2 G 4.266(Cr).4 G 1.766(ule took adv)
X251.59 659.4 R 1.766(antage of the INCLUDES b)-.25 F 1.766(uilt-in to mak)-.2 F
X4.266(es)-.1 G 1.766(ure the)492.744 659.4 R
X(dependencies on the generated \214le are accurately re)90 671.4 Q(gistered.)
X-.15 E(Actually)90 687.6 Q 3.479(,t)-.65 G .979
X(he rule de\214nitions include a fe)132.549 687.6 R 3.479(wm)-.25 G .979
X(ore machinations to gi)277.043 687.6 R 1.28 -.15(ve s)-.25 H .98(pecial v).15
XF .98(ariables sensible def)-.25 F(aults.)-.1 E -.15(Fo)90 699.6 S 4.64(rs).15
XG 2.139(ource code, $\(SEARCH\) is set to $\(SEARCH_SOURCE\); for object \214l\
Xes, $\(LOCA)112.27 699.6 R 2.139(TE\) is set to)-1.11 F($\(LOCA)90 711.6 Q
X1.111(TE_OBJECT\); for C source \214les, $\(HDRSCAN\) is set to the e)-1.11 F
X1.111(xample pattern mentioned abo)-.15 F -.15(ve)-.15 G(,).15 E(and $\(HDRR)90
X723.6 Q(ULE\) is set to \231HDRR)-.4 E(ULE\232, the generic header)-.4 E
X(-handling rule de\214ned in the Jambase \214le.)-.2 E EP
X%%Page: 8 8
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 11/Times-Bold@0 SF 2.75(8. Implementation)90 96 R/F1 10/Times-Roman@0 SF
X.618(The weight of Jam')90 112.2 R 3.118(si)-.55 G .618(mplementation is e)
X179.132 112.2 R -.15(ve)-.25 G .618(nly di).15 F .618
X(vided between its rule-processing subsystem \(dri)-.25 F -.15(ve)-.25 G 3.117
X(nb).15 G 3.117(ya)509.443 112.2 S/F2 10/Times-Italic@0 SF(yacc)90 124.2 Q F1
X(\(1\) grammar\), its recursi)A .3 -.15(ve b)-.25 H
X(inding and scanning subsystem, and its recursi).15 E .3 -.15(ve b)-.25 H
X(uild subsystem.)-.05 E .806(The rule-processing subsystem is entirely system \
Xindependent, only setting in-memory v)90 140.4 R .807(ariables, b)-.25 F
X(uilding)-.2 E 1.494(the dependenc)90 152.4 R 3.994(yg)-.15 G 1.494
X(raph, and associating update actions with tar)162.818 152.4 R 3.994(gets. The)
X-.18 F F2(yacc)3.994 E F1 1.494(grammar is less than 200)3.994 F(lines.)90
X164.4 Q .983(The recursi)90 180.6 R 1.283 -.15(ve b)-.25 H .983
X(inding and scanning subsystem is mostly system independent, b).15 F .984
X(ut calls system-dependent)-.2 F
X(routines to time-stamp \214les and to manipulate \214le names.)90 192.6 Q .754
X(The recursi)90 208.8 R 1.054 -.15(ve b)-.25 H .754
X(uild subsystem is mostly system independent, b)-.05 F .754
X(ut calls system-speci\214c routines to e)-.2 F -.15(xe)-.15 G(cute).15 E
X(shell commands \(which are system-speci\214c as well\).)90 220.8 Q 1.028
X(The system dependencies are hidden through three interf)90 237 R 1.028
X(aces: one to time-stamp \214les; one to manipulate)-.1 F
X(\214le names; and one to e)90 249 Q -.15(xe)-.15 G(cute shell commands.).15 E
X.524(The \214le time-stamp interf)90 265.2 R .524(ace has tw)-.1 F 3.024(ol)-.1
XG .524(ayers: a higher one that asks about indi)247.364 265.2 R .524
X(vidual \214les; and a lo)-.25 F .523(wer one)-.25 F .701
X(that scans directories and library archi)90 277.2 R -.15(ve)-.25 G 3.201(sw)
X.15 G 3.201(hole. The)269.316 277.2 R .701(latter is more ef)3.201 F .702
X(\214cient, and all current implementa-)-.25 F
X(tions \(UNIX, VMS, NT\) are coded ag)90 289.2 Q(ainst it.)-.05 E .479
X(The \214le name manipulation interf)90 305.4 R .479(ace consists of tw)-.1 F
X2.978(or)-.1 G .478(outines: one to break a \214le name do)309.71 305.4 R .478
X(wn into its com-)-.25 F 1.382(ponents and one to b)90 317.4 R 1.383
X(uild a \214le name from its components.)-.2 F 1.383
X(These are quite simple \212 e)6.383 F 1.383(xcept on VMS,)-.15 F
X(where concatenating path names is black art.)90 329.4 Q 1.049
X(The shell-command interf)90 345.6 R 1.049(ace currently approximates the UNIX)
X-.1 F F2(system)3.548 E F1 1.048(\(3\) call interf)B 1.048
X(ace, with an addition)-.1 F(for catching interrupts.)90 357.6 Q .649
X(Jam achie)90 373.8 R -.15(ve)-.25 G 3.149(si).15 G .649
X(ts functionality while going sparingly on features.)149.218 373.8 R .65
X(It has only four \215ags \(mostly to do with)5.649 F(deb)90 385.8 Q .292
X(ugging\), six b)-.2 F .292(uilt-in rules \(DEPENDS, INCLUDES, ECHO, NO)-.2 F
X.292(TIME, NOCARE, TEMPORAR)-.4 F .292(Y\) and)-.65 F .282(six special v)90
X397.8 R .283(ariables \($\(>\), $\(<\), $\(SEARCH\), $\(LOCA)-.25 F .283
X(TE\), $\(HDRSCAN\), $\(HDRR)-1.11 F 2.783(ULE\)\). The)-.4 F .283(whole of)
X2.783 F .079(Jam for UNIX is under 5,000 lines of code, e)90 409.8 R(xclusi)
X-.15 E .379 -.15(ve o)-.25 H 2.578(fH).15 G .078(enry Spencer')324.438 409.8 R
X(s)-.55 E F2 -.37(re)2.578 G -.1(ge)-.03 G(xp)-.1 E F1 .078(\(3\) re)B(gular)
X-.15 E(-e)-.2 E .078(xpression code)-.15 F(\(about another 1,300 lines\).)90
X421.8 Q 3.329(Ad)90 438 S .829(esign goal of Jam w)105.549 438 R .829
X(as portability)-.1 F 3.329(,s)-.65 G .83
X(peci\214cally so that the same mechanism could be used to b)251.153 438 R .83
X(uild the)-.2 F .365(same system on dif)90 450 R .365(ferent platforms.)-.25 F
X.364(Jam scores well in this cate)5.365 F .364(gory: the OS interf)-.15 F .364
X(ace is constricted, lea)-.1 F(v-)-.2 E .678(ing the b)90 462 R .679
X(ulk of the system dependencies in the Jambase \214le.)-.2 F(Ev)5.679 E .679
X(en the Jambase \214le is some)-.15 F .679(what portable,)-.25 F .194
X(with only the \214lename syntax and the actual update commands ha)90 474 R
X.193(ving to change between UNIX and VMS.)-.2 F(Jam\214le \214les themselv)90
X486 Q(es usually contain nothing system-speci\214c.)-.15 E F0 2.75(9. P)90 510
XR(erf)-.22 E(ormance)-.275 E F1 .17(Used to b)90 526.2 R .17
X(uild from scratch a lar)-.2 F .17(ge commerical softw)-.18 F .17
X(are system \(the INGRES relational DBMS\), lapse time)-.1 F(for Jam breaks do)
X90 538.2 Q(wn as follo)-.25 E(ws \(on an HP9000/710\):)-.25 E/F3 10/Courier@0
XSF(parsing 5,000 lines of Jamfiles)130 554.4 Q(16 seconds)418 554.4 Q
X(stat\(\)'ing 12,000 source files)130 566.4 Q 6(1m)418 566.4 S(inute)436 566.4
XQ(scanning 12,000 source files for headers)130 578.4 Q 6(9m)418 578.4 S(inutes)
X436 578.4 Q(actual building \(compiling, linking, etc\))130 590.4 Q(12 hours)
X418 590.4 Q F1 .702(The simple conclusion is that Jam')90 610.8 R 3.202(sp)-.55
XG .702(erformance in inconsequential.)244.212 610.8 R .701(When e)5.701 F -.15
X(ve)-.25 G .701(rything is up-to-date, only).15 F(fe)90 622.8 Q 2.595(wi)-.25 G
X(mpro)110.115 622.8 Q -.15(ve)-.15 G .095(ments could be made.).15 F F2(stat)
X5.095 E F1 .095(\(\)'ing \214les is essentially una)B -.2(vo)-.2 G .095
X(idable without resorting to other tech-).2 F 1.609
X(niques for determining outdated tar)90 634.8 R 4.109(gets. Scanning)-.18 F
X1.608(source \214les could be a)4.109 F -.2(vo)-.2 G 1.608
X(ided by caching header).2 F(-\214le)-.2 E(dependenc)90 646.8 Q 2.828(yi)-.15 G
X.328(nformation in state \214les.)143.218 646.8 R(SunOS)5.328 E F2(mak)2.829 E
X(e)-.1 E F1(and)2.829 E F2(nmak)2.829 E(e)-.1 E F1 .329(use this approach.)
X2.829 F .329(The only other recourse)5.329 F(is to hammer on the)90 658.8 Q F2
X-.37(re)2.5 G -.1(ge)-.03 G(xp)-.1 E F1(implementation.)2.5 E 1.428
X(The real performance limitation is in actual b)90 675 R 1.427(uilding time.)
X-.2 F 1.427(Jam does not yet support parallel command)6.427 F -.15(exe)90 687 S
X.934(cution, which on a lar).15 F .934(ge SMP system can reduce b)-.18 F .935
X(uild time by a f)-.2 F .935(actor of 5 or more.)-.1 F .935(This feature is)
X5.935 F(anticipated.)90 699 Q EP
X%%Page: 9 9
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 11/Times-Bold@0 SF 2.75(10. Comparisons)90 96 R/F1 10/Times-Roman@0 SF
X(Jam')90 112.2 Q 3.133(sp)-.55 G(er)120.913 112.2 Q(-tar)-.2 E .633(get v)-.18
XF .633(ariables are a con)-.25 F -.15(ve)-.4 G .633
X(nience approached only by SunOS).15 F/F2 10/Times-Italic@0 SF(mak)3.133 E(e)
X-.1 E F1 1.732 -.55('s \231)D(tar).55 E .632(get := macro = v)-.18 F(alue\232)
X-.25 E 3.447(syntax. Both)90 124.2 R .947(Jam and SunOS)3.447 F F2(mak)3.447 E
X(e)-.1 E F1(mak)3.447 E 3.447(eu)-.1 G .947(se of the v)271.139 124.2 R .947
X(alue when updating the tar)-.25 F .948(get, b)-.18 F .948(ut Jam gets added)
X-.2 F(mileage out of the f)90 136.2 Q(acility by using the v)-.1 E
X(alue during the binding and header)-.25 E(-\214le scanning.)-.2 E(Jam')90
X152.4 Q 3.749(ss)-.55 G 1.248(earching mechanism is superior to VP)120.419
X152.4 R -1.11(AT)-.92 G 3.748(Hi)1.11 G 3.748(nt)304.188 152.4 S 1.448 -.1
X(wo wa)315.716 152.4 T 3.748(ys: \214rst,).1 F 1.248(it pro)3.748 F 1.248
X(vides not only searching for)-.15 F -.15(ex)90 164.4 S .865(isting tar).15 F
X.865(gets, b)-.18 F .865(ut also binding for ne)-.2 F 3.365(wt)-.25 G(ar)
X264.155 164.4 Q .865(gets; second, Jam')-.18 F 3.365(sS)-.55 G .866
X(EARCH and LOCA)359.34 164.4 R .866(TE v)-1.11 F .866(ariables can be)-.25 F
X.167(set per)90 176.4 R(-tar)-.2 E 2.667(get. GNU)-.18 F F2(mak)2.667 E(e)-.1 E
XF1(allo)2.667 E .167(ws VP)-.25 F -1.11(AT)-.92 G 2.667(Ht)1.11 G 2.667(ob)
X263.202 176.4 S 2.667(es)275.869 176.4 S .166(et selecti)286.866 176.4 R -.15
X(ve)-.25 G(ly).15 E 2.666(,u)-.65 G .166
X(sing patterns, and the patterns could be full)348.638 176.4 R .51
X(\214le names, b)90 188.4 R .51(ut GNU)-.2 F F2(mak)3.01 E(e)-.1 E F1 .51
X(handles the de)3.01 F .51(generate case of separate v)-.15 F .51
X(alues per \214le poorly)-.25 F 5.51(.J)-.65 G(am')460.65 188.4 Q 3.01(sS)-.55
XG(EARCH)488.11 188.4 Q .777(and LOCA)90 200.4 R .777(TE mechanism can mak)-1.11
XF 3.277(et)-.1 G .777(he in)242.925 200.4 R -.2(vo)-.4 G -.1(ke).2 G(r').1 E
X3.276(sd)-.55 G .776(irectory irrele)300.438 200.4 R -.25(va)-.25 G .776
X(nt, which amounts to a complete solu-).25 F(tion.)90 212.4 Q(Jam')90 228.6 Q
X2.767(sp)-.55 G .267(attern-scanning method of header)120.547 228.6 R .267
X(-\214le scanning is f)-.2 F .267(aster than those that of)-.1 F .268
X(\215oad the problem to sepa-)-.25 F .078(rate programs \()90 240.6 R F2(dmak)A
X(e)-.1 E F1(,)A F2(cak)2.578 E(e)-.1 E F1 2.578(,G)C(NU)212.842 240.6 Q F2(mak)
X2.578 E(e)-.1 E F1 2.578(\). It)B .078(is not strictly correct, lik)2.578 F
X2.577(eS)-.1 G(unOS)381.295 240.6 Q F2(mak)2.577 E(e)-.1 E F1 .077(and GNU)
X2.577 F F2(mak)2.577 E(e)-.1 E F1 2.577(,w)C(hich)504.78 240.6 Q .574
X(use the C preprocessor)90 252.6 R 5.574(.J)-.55 G(am')193.946 252.6 Q 3.074
X(sm)-.55 G .575(echanism, dri)223.69 252.6 R -.15(ve)-.25 G 3.075(nb).15 G
X3.075(yp)300.26 252.6 S(er)313.335 252.6 Q(-tar)-.2 E .575(get v)-.18 F .575
X(ariables and user)-.25 F .575(-de\214ned relationships is,)-.2 F(ho)90 264.6 Q
X(we)-.25 E -.15(ve)-.25 G 2.032 -.4(r, q).15 H 1.232(uite \215e).4 F 3.732
X(xible. It)-.15 F 1.231(can handle languages that don')3.732 F 3.731(to)-.18 G
X-.25(ff)341.883 264.6 S 1.231(er a separate preprocessor).25 F 3.731(,a)-.4 G
X3.731(sw)465.817 264.6 S 1.231(ell as lan-)480.658 264.6 R .253(guages where t\
Xhe result of a \214le being included is more than just a simple dependenc)90
X276.6 R 4.054 -.65(y. F)-.15 H .254(or e).5 F .254(xample, when)-.15 F(a)90
X288.6 Q F2(yacc)3.527 E F1 1.027(\214le includes a C header)3.527 F 1.027(-\
X\214le, Jam can be made to understand that the generated C source \214le will)
X-.2 F(include the generated C header)90 300.6 Q 2.5(-\214le. Jam)-.2 F
X(supports these types of arrangements entirely in its language.)2.5 E .693
X(Jam is missing a fe)90 316.8 R 3.193(wf)-.25 G .693(eatures cherished by some)
X182.375 316.8 R F2(mak)3.194 E(e)-.1 E F1 .694
X(users: the ability to run update commands concur)3.194 F(-)-.2 E(rently and f)
X90 328.8 Q(anc)-.1 E 2.5(yv)-.15 G(ariable editing.)161.98 328.8 Q
X(These may appear in future v)5 E(ersions of Jam.)-.15 E F0 2.75
X(11. Discussion)90 345 R F1 .65(The comparison of Jam')90 361.2 R 3.15(sl)-.55
XG .65(anguage with)198.7 361.2 R F2(mak)3.15 E(e)-.1 E F1 1.75 -.55('s i)D 3.15
X(ss).55 G(ome)300.63 361.2 Q .65(what subjecti)-.25 F .95 -.15(ve a)-.25 H .65
X(nd complicated.).15 F .65(As stated in the)5.65 F .001
X(introduction, Jam is an attempt to replace)90 373.2 R F2(mak)2.502 E(e)-.1 E
XF1 1.102 -.55('s r)D .002(ule system with an e).55 F(xpressi)-.15 E .302 -.15
X(ve l)-.25 H .002(anguage that mak).15 F .002(es it pos-)-.1 F
X(sible to describe e)90 385.2 Q
X(xplicitly and cogently the compilation of programs.)-.15 E .563
X(In this respect, Jam is a success.)90 401.4 R -.15(Fo)5.563 G 3.063(rs).15 G
X.563(mall systems, the Jam\214le \214le is often not lar)247.944 401.4 R .563
X(ger than the three lines)-.18 F .217(that made up our e)90 413.4 R 2.717
X(xample. F)-.15 F .217(or lar)-.15 F .217(ge systems, an)-.18 F 2.717(ya)-.15 G
X.217(dded comple)299.623 413.4 R .217
X(xity can be centralized in the Jambase \214le,)-.15 F
X(while the Jam\214le \214le\(s\) in source directories remain simple.)90 425.4
XQ(Jam')90 441.6 Q 2.793(sr)-.55 G .293(ule semantics, that of e)118.903 441.6 R
X.293(xpressing named relationships among \214les, is Jam')-.15 F 2.793(ss)-.55
XG .292(ingle biggest adv)427.236 441.6 R(antage)-.25 E -.15(ove)90 453.6 S
X4.373(ri).15 G 1.873(ts contemporaries.)114.623 453.6 R 1.873(Its po)6.873 F
X1.873(wer and economy of e)-.25 F 1.874(xpression seem unmatched.)-.15 F 1.874
X(There are tw)6.874 F 4.374(oo)-.1 G(ther)506.45 453.6 Q 1.349
X(approaches deserving mention.)90 465.6 R F2(nmak)6.349 E(e)-.1 E F1(and)3.849
XE F2(dmak)3.849 E(e)-.1 E F1(allo)3.849 E 3.848(wn)-.25 G 1.848 -.25(ew o)
X331.992 465.6 T 1.348(perators \(replacements for the simple \231:\232).25 F
X(dependenc)90 477.6 Q 3.801(ys)-.15 G 1.302
X(tatement\) to be de\214ned as macros, and these can be used to create ne)
X145.301 477.6 R 3.802(wr)-.25 G 1.302(elationship types.)450.698 477.6 R
X(Unfortunately)90 489.6 Q 2.59(,t)-.65 G .09(he number of a)153.32 489.6 R -.25
X(va)-.2 G .09
X(ilable \231operator\232 characters is limited, and the coding of the macros w)
X.25 F(ould)-.1 E .744(curl the e)90 501.6 R(yebro)-.15 E .744(ws of e)-.25 F
X-.15(ve)-.25 G 3.244(ns).15 G(easoned)202.61 501.6 Q F2(sendmail)3.245 E F1
X(hack)3.245 E(ers.)-.1 E F2(cook)5.745 E F1(,)A F2(cak)3.245 E(e)-.1 E F1 3.245
X(,P)C .745(lan 9)370.255 501.6 R F2(mk)3.245 E F1 3.245(,a)C .745(nd NET2)
X415.81 501.6 R F2(mak)3.245 E(e)-.1 E F1 .745(promote a)3.245 F(dif)90 513.6 Q
X.55(ferent approach: that of de\214ning v)-.25 F .55
X(ariables and then #include'ing \231recipes\232 \(other)-.25 F F2(mak)3.05 E(e)
X-.1 E F1 .55(\214les\) that de\214ne)3.05 F .752(the relationships.)90 525.6 R
X.752(The recipes are the approximate equi)5.752 F -.25(va)-.25 G .753
X(lent of Jam rules, using pass-by-name v).25 F(ariables.)-.25 E .959
X(This scheme w)90 537.6 R .959(orks, b)-.1 F .959
X(ut it is an ugly ordeal to try to reco)-.2 F -.15(ve)-.15 G 3.458(rw).15 G
X.958(ith a preprocessor the functionality that is)350.162 537.6 R
X(lacking in a language.)90 549.6 Q .745(The Jam language turns out to be f)90
X565.8 R .745(airly straightforw)-.1 F .745(ard to program.)-.1 F -.4(Wi)5.745 G
X.745(th its reliance on k).4 F -.15(ey)-.1 G -.1(wo).15 G .745(rds rather).1 F
X.349(than special characters and its use of a \231;\232 to terminate statement\
Xs, it is easier reading than most)90 577.8 R F2(mak)2.849 E(e)-.1 E F1(syn-)
X2.848 E(tax.)90 589.8 Q(Abandoning)90 606 Q F2(mak)2.505 E(e)-.1 E F1 .005
X(syntax w)2.505 F .005(as an easy decision: e)-.1 F -.15(ve)-.25 G 2.505(nt).15
XG .005(hose ne)306.62 606 R(w)-.25 E F2(mak)2.505 E(e)-.1 E F1 2.506(st)C .006
X(hat understand traditional)376.546 606 R F2(mak)2.506 E(e)-.1 E F1(syn-)2.506
XE 1.092(tax get their added functionality through incompatible syntax.)90 618 R
X1.091(If compatibility with)6.091 F F2(mak)3.591 E(e)-.1 E F1 1.091
X(is the priority)3.591 F(,)-.65 E(users can just use)90 630 Q F2(mak)2.5 E(e)
X-.1 E F1 5(.I)C 2.5(fu)194.04 630 S(sers w)204.87 630 Q
X(ant greater functionality)-.1 E 2.5(,t)-.65 G(he)333.26 630 Q 2.5(yc)-.15 G
X(an')354.49 630 Q 2.5(tu)-.18 G(se v)377.36 630 Q(anilla)-.25 E F2(mak)2.5 E(e)
X-.1 E F1(an)2.5 E(yw)-.15 E(ay)-.1 E(.)-.65 E 1.509
X(The proof of Jam is in the pudding \(sorry)90 646.2 R 4.009(...\): it)-.65 F
X1.51(is w)4.009 F 1.51(orth mentioning that the timing information gi)-.1 F
X-.15(ve)-.25 G(n).15 E(abo)90 658.2 Q 1.062 -.15(ve i)-.15 H 3.262(sf).15 G
X.762(or a single, non-recursi)130.104 658.2 R 1.061 -.15(ve i)-.25 H -1.9 -.4
X(nv o).15 H .761
X(cation of Jam to compile 12,000 source \214les scattered throughout).4 F 1.495
X(300 directories, producing 7,000 intermediate tar)90 670.2 R 1.495
X(gets and 1,000 deli)-.18 F -.15(ve)-.25 G 1.495(rable \214les.).15 F 1.495
X(Each source directory)6.495 F .218(contains a single Jam\214le with an a)90
X682.2 R -.15(ve)-.2 G .218(rage of 1.5 w).15 F .218
X(ords per source \214le \(including the source \214le name\).)-.1 F(The)5.217 E
X(author kno)90 694.2 Q(ws of no other)-.25 E F2(mak)2.5 E(e)-.1 E F1
X(that can approach such completeness with such economy)2.5 E(.)-.65 E EP
X%%Page: 10 10
X%%BeginPageSetup
XBP
X%%EndPageSetup
X/F0 11/Times-Bold@0 SF 2.75(12. A)90 96 R -.11(va)-1.1 G(ilability).11 E/F1 10
X/Times-Roman@0 SF .643(Jam is freely a)90 112.2 R -.25(va)-.2 G .643
X(ilable in V).25 F .643(olume 27 of the comp.sources.unix archi)-1.29 F -.15
X(ve)-.25 G 3.144(s. It).15 F .644(is kno)3.144 F .644(wn to compile and w)-.25
XF(ork)-.1 E .452(on VMS \(Alpha and V)90 124.2 R .451(AX\) and the follo)-1.35
XF .451(wing v)-.25 F .451(ariants of UNIX: BSD/386, OSF/1, DGUX 5.4, HPUX 9.0,)
X-.25 F .462
X(AIX, IRIX 5.0, PTX V2.1.0, SunOS 4, Solaris 2, Ultrix 4.2, and Linux.)90 136.2
XR .462(Support for NT is not part of that)5.462 F(initial release b)90 148.2 Q
X(ut is a)-.2 E -.25(va)-.2 G(ilable from the author).25 E(.)-.55 E F0 2.75
X(13. Bibliograph)90 172.2 R(y)-.165 E F1([Brokk)90 188.4 Q(en, 1994])-.1 E .225
X(Frank B. Brokk)115 200.4 R .225(en and Karel K)-.1 F .225
X(ubat, \231ICMAKE \212 the Intelligent C-lik)-.15 F 2.724(eM)-.1 G(AKEr)416.254
X200.4 Q 2.724(,o)-.4 G 2.724(rt)449.958 200.4 S .224(he ICce MAKE)458.792 200.4
XR(utility\232, Linux Sources, 1994)115 212.4 Q([BSD, 1991])90 228.6 Q
X(BSD NET2 mak)115 240.6 Q
X(e\(1\) manual page, BSD NET2 documentation, July 1991.)-.1 E([Feldman, 1986])
X90 256.8 Q .57(S. I. Feldman, \231Mak)115 268.8 R 3.071(e\212AP)-.1 G .571
X(rogram for Maintaining Computer Programs\232, BSD NET2 documenta-)234.703
X268.8 R(tion, April 1986 \(re)115 280.8 Q(vision\).)-.25 E([Flandrena])90 297 Q
X(R. Flandrena, \231Plan 9 Mk\214les\232, a)115 309 Q -.25(va)-.2 G
X(ilable via anon).25 E(ymous FTP from plan9.att.com.)-.15 E([F)90 325.2 Q -.25
X(ow)-.15 G(ler).25 E 2.5(,1)-.4 G(985])130.86 325.2 Q 1.447(Glenn F)115 337.2 R
X-.25(ow)-.15 G(ler).25 E 3.947<2c99>-.4 G 1.447(The F)181.804 337.2 R 1.447
X(ourth Generation Mak)-.15 F 1.446
X(e\232, Proceedings of the USENIX Summer Conference,)-.1 F(June 1985.)115 349.2
XQ([Miller)90 365.4 Q 2.5(,1)-.4 G(993])127.93 365.4 Q(Peter Miller)115 377.4 Q
X2.5<2c99>-.4 G(Cook \212 A File Construction T)172.09 377.4 Q(ool\232, V)-.8 E
X(olume 26, comp.sources.unix archi)-1.29 E -.15(ve)-.25 G(s, 1993.).15 E([Seiw)
X90 393.6 Q(ald, 1993])-.1 E .386(Christopher Seiw)115 405.6 R .386
X(ald, Jam\(1\) and Jambase\(5\) manual pages, V)-.1 F .386
X(olume 27, comp.sources.unix archi)-1.29 F -.15(ve)-.25 G(s,).15 E(1993.)115
X417.6 Q([Spencer)90 433.8 Q 2.5(,1)-.4 G(986])135.14 433.8 Q(Henry Spencer)115
X445.8 Q 2.5(,R)-.4 G -.15(eg)185.97 445.8 S -.15(ex).15 G 2.5(pc).15 G
X(ode and comment, comp.sources.unix archi)216.49 445.8 Q -.15(ve)-.25 G
X(s, 1986.).15 E([Stallman, 1991])90 462 Q .124
X(Richard M. Stallman and Roland McGrath, \231GNU Mak)115 474 R 2.624(e\212AP)
X-.1 G .123(rogram for Directed Recompilation\232,)373.33 474 R(Free Softw)115
X486 Q(are F)-.1 E(oundation, 1991)-.15 E([Somogyi, 1987])90 502.2 Q .771
X(Zoltan Somogyi, \231Cak)115 514.2 R .771(e, a Fifth Generation V)-.1 F .772
X(ersion of Mak)-1.11 F .772(e\232, Australian Unix System User Group)-.1 F(Ne)
X115 526.2 Q(wsletter)-.25 E 2.5(,A)-.4 G(pril 1987.)169.89 526.2 Q([Sun, 1989])
X90 542.4 Q .351(Sun Microssytems Corporation, SunOS mak)115 554.4 R .351
X(e\(1\) manual page, SunOS 4.1.2 documentation, Septem-)-.1 F(ber 1989.)115
X566.4 Q([V)90 582.6 Q(adura, 1990])-1.11 E(Dennis V)115 594.6 Q(adura, dmak)
X-1.11 E(e\(1\) manual page, V)-.1 E(olume 27, comp.sources.misc archi)-1.29 E
X-.15(ve)-.25 G(s, 1990.).15 E EP
X%%Trailer
Xend
X%%EOF
END_OF_FILE
if test 70543 -ne `wc -c <'Paper.ps'`; then
echo shar: \"'Paper.ps'\" unpacked with wrong size!
fi
# end of 'Paper.ps'
fi
if test -f 'filent.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'filent.c'\"
else
echo shar: Extracting \"'filent.c'\" \(6563 characters\)
sed "s/^X//" >'filent.c' <<'END_OF_FILE'
X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X
X# ifdef NT
X
X# include "jam.h"
X# include "filesys.h"
X
X# include <io.h>
X
X/*
X * fileunix.c - manipulate file names and scan directories on UNIX
X *
X * External routines:
X *
X * file_parse() - split a file name into dir/base/suffix/member
X * file_build() - build a filename given dir/base/suffix/member
X * file_dirscan() - scan a directory for files
X * file_time() - get timestamp of file, if not done by file_dirscan()
X * file_archscan() - scan an archive for files
X *
X * File_parse() and file_build() just manipuate a string and a structure;
X * they do not make system calls.
X *
X * File_dirscan() and file_archscan() call back a caller provided function
X * for each file found. A flag to this callback function lets file_dirscan()
X * and file_archscan() indicate that a timestamp is being provided with the
X * file. If file_dirscan() or file_archscan() do not provide the file's
X * timestamp, interested parties may later call file_time().
X *
X * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
X * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
X * should expect hdr searches to come up with strings
X * like "thing/thing.h". So we need to test for "/" as
X * well as "\" when parsing pathnames.
X * 02/14/95 (seiwald) - parse and build /xxx properly
X */
X
X/*
X * file_parse() - split a file name into dir/base/suffix/member
X */
X
Xvoid
Xfile_parse( file, f )
Xchar *file;
XFILENAME *f;
X{
X char *p, *p1;
X char *end;
X
X memset( (char *)f, 0, sizeof( *f ) );
X
X /* Look for <grist> */
X
X if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
X {
X f->f_grist.ptr = file + 1;
X f->f_grist.len = p - file - 1;
X file = p + 1;
X }
X
X /* Look for dir/ */
X
X p = strrchr( file, '\\' );
X p1 = strrchr( file, '/' );
X p = p1 > p ? p1 : p
X
X /* Special case for \ - dirname is \, not "" */
X
X if( p )
X {
X f->f_dir.ptr = file;
X f->f_dir.len = p == file ? 1 : p - file;
X file = p + 1;
X }
X
X end = file + strlen( file );
X
X /* Look for (member) */
X
X if( ( p = strchr( file, '(' ) ) && end[-1] == ')' )
X {
X f->f_member.ptr = p + 1;
X f->f_member.len = end - p - 2;
X end = p;
X }
X
X /* Look for .suffix */
X
X if( ( p = strchr( file, '.' ) ) && p < end )
X {
X f->f_suffix.ptr = p;
X f->f_suffix.len = end - p;
X end = p;
X }
X
X /* Leaves base */
X
X f->f_base.ptr = file;
X f->f_base.len = end - file;
X}
X
X/*
X * file_build() - build a filename given dir/base/suffix/member
X */
X
Xvoid
Xfile_build( f, file )
XFILENAME *f;
Xchar *file;
X{
X if( f->f_grist.len )
X {
X *file++ = '<';
X memcpy( file, f->f_grist.ptr, f->f_grist.len );
X file += f->f_grist.len;
X *file++ = '>';
X }
X
X /* Don't prepend root if it's . or directory is rooted */
X
X if( f->f_root.len
X && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
X && !( f->f_dir.len && f->f_dir.ptr[0] == '\\' )
X && !( f->f_dir.len && f->f_dir.ptr[0] == '/' )
X && !( f->f_dir.len && f->f_dir.ptr[1] == ':' ) )
X {
X memcpy( file, f->f_root.ptr, f->f_root.len );
X file += f->f_root.len;
X *file++ = '\\';
X }
X
X if( f->f_dir.len )
X {
X memcpy( file, f->f_dir.ptr, f->f_dir.len );
X file += f->f_dir.len;
X }
X
X /* Put \ between dir and file */
X
X if( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
X {
X /* Special case for dir \ : don't add another \ */
X
X if( !( f->f_dir.len == 1 && f->f_dir.ptr[0] == '\\' ) )
X *file++ = '\\';
X }
X
X if( f->f_base.len )
X {
X memcpy( file, f->f_base.ptr, f->f_base.len );
X file += f->f_base.len;
X }
X
X if( f->f_suffix.len )
X {
X memcpy( file, f->f_suffix.ptr, f->f_suffix.len );
X file += f->f_suffix.len;
X }
X
X if( f->f_member.len )
X {
X *file++ = '(';
X memcpy( file, f->f_member.ptr, f->f_member.len );
X file += f->f_member.len;
X *file++ = ')';
X }
X *file = 0;
X}
X
X/*
X * file_dirscan() - scan a directory for files
X */
X
Xvoid
Xfile_dirscan( dir, func )
Xchar *dir;
Xvoid (*func)();
X{
X FILENAME f;
X char filespec[ MAXPATH ];
X char filename[ MAXPATH ];
X long handle;
X struct _finddata_t fileinfo[1];
X
X /* First enter directory itself */
X
X memset( (char *)&f, '\0', sizeof( f ) );
X
X f.f_dir.ptr = dir;
X f.f_dir.len = strlen(dir);
X
X dir = *dir ? dir : ".";
X
X /* Special case \ : enter it */
X
X if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
X (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
X
X /* Now enter contents of directory */
X
X sprintf( filespec, "%s/*", dir );
X
X if( ( handle = _findfirst( filespec, fileinfo ) ) < 0 )
X return;
X
X if( DEBUG_BINDSCAN )
X printf( "scan directory %s\n", dir );
X
X while( _findnext( handle, fileinfo ) >= 0 )
X {
X f.f_base.ptr = fileinfo->name;
X f.f_base.len = strlen( fileinfo->name );
X
X file_build( &f, filename );
X
X (*func)( filename, 1 /* stat()'ed */, fileinfo->time_write );
X }
X
X _findclose( handle );
X}
X
X/*
X * file_time() - get timestamp of file, if not done by file_dirscan()
X */
X
Xint
Xfile_time( filename, time )
Xchar *filename;
Xtime_t *time;
X{
X return 0;
X}
X
X/*
X * file_archscan() - scan an archive for files
X */
X
X/* Straight from SunOS */
X
X#define ARMAG "!<arch>\n"
X#define SARMAG 8
X
X#define ARFMAG "`\n"
X
Xstruct ar_hdr {
X char ar_name[16];
X char ar_date[12];
X char ar_uid[6];
X char ar_gid[6];
X char ar_mode[8];
X char ar_size[10];
X char ar_fmag[2];
X};
X
X# define SARFMAG 2
X# define SARHDR sizeof( struct ar_hdr )
X
Xvoid
Xfile_archscan( archive, func )
Xchar *archive;
Xvoid (*func)();
X{
X struct ar_hdr ar_hdr;
X char buf[ MAXPATH ];
X long offset;
X int fd;
X
X if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
X return;
X
X if( read( fd, buf, SARMAG ) != SARMAG ||
X strncmp( ARMAG, buf, SARMAG ) )
X {
X close( fd );
X return;
X }
X
X offset = SARMAG;
X
X if( DEBUG_BINDSCAN )
X printf( "scan archive %s\n", archive );
X
X while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
X !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
X {
X char lar_name[16];
X long lar_date;
X long lar_size;
X char *c;
X
X strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
X c = lar_name + sizeof( lar_name );
X while( *--c == ' ' || *c == '\\' || *c == '/' )
X ;
X *++c = '\0';
X
X sscanf( ar_hdr.ar_date, "%ld", &lar_date );
X sscanf( ar_hdr.ar_size, "%ld", &lar_size );
X
X sprintf( buf, "%s(%s)", archive, lar_name );
X
X (*func)( buf, 1 /* time valid */, (time_t)lar_date );
X
X offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
X lseek( fd, offset, 0 );
X }
X
X close( fd );
X}
X
X# endif /* NT */
END_OF_FILE
if test 6563 -ne `wc -c <'filent.c'`; then
echo shar: \"'filent.c'\" unpacked with wrong size!
fi
# end of 'filent.c'
fi
echo shar: End of archive 1 \(of 7\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 7 archives.
rm -f ark[1-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...

Christopher Seiwald

unread,
Apr 11, 1995, 3:00:00 AM4/11/95
to
Submitted-by: sei...@tea.org (Christopher Seiwald)
Posting-number: Volume 47, Issue 110
Archive-name: jam/part03

Environment: UNIX, NT, VMS
Supersedes: jam: Volume 27, Issue 81-85

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".

# Contents: jam.ps jamgram.y option.h regexp.c


# Wrapped by kent@ftp on Sat Mar 25 12:04:10 1995
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 3 (of 7)."'
if test -f 'jam.ps' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jam.ps'\"
else
echo shar: Extracting \"'jam.ps'\" \(42813 characters\)
sed "s/^X//" >'jam.ps' <<'END_OF_FILE'


X%!PS-Adobe-3.0
X%%Creator: groff version 1.08

X%%DocumentNeededResources: font Times-Roman
X%%+ font Times-Bold
X%%+ font Times-Italic


X%%DocumentSuppliedResources: procset grops 1.08 0

X%%Pages: 7

X%%IncludeResource: font Times-Roman
X%%IncludeResource: font Times-Bold
X%%IncludeResource: font Times-Italic

X/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
X/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE


X%%EndProlog
X%%Page: 1 1
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S 403.38(M\(1\) J).6 F(AM\(1\))-.6 E/F1 9
X/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E/F2 10/Times-Bold@0 SF(jam)108 96 Q F0
X<ad>2.5 E F2(mak)2.5 E(e)-.1 E F0(\(1\) redux)A F1(SYNOPSIS)72 124.8 Q F2(jam)
X108 136.8 Q F0([)2.5 E F2(-a)2.5 E F0 2.5(][)2.5 G F2(-n)A F0 2.5(][)2.5 G F2
X(-v)A F0 2.5(][)2.5 G F2(-d)A/F3 10/Times-Italic@0 SF(deb)2.5 E(ug)-.2 E F0 2.5
X(][)2.5 G F2(-f)A F3 -.35(Ja)2.5 G(mbase).35 E F0(... ] [)2.5 E F2(-j)2.5 E F3
X(jobs)2.5 E F0 2.5(][)2.5 G F2(-t)A F3(tar)2.5 E -.1(ge)-.37 G(t).1 E F0
X(... ] [)2.5 E F3(tar)2.5 E -.1(ge)-.37 G(t).1 E F0(... ])2.5 E F1(DESCRIPTION)
X72 165.6 Q F2 -.15(Ja)108 177.6 S(m).15 E F0(recursi)3.449 E -.15(ve)-.25 G
X.949(ly b).15 F .949(uilds tar)-.2 F .949
X(get \214les from their source \214les, using tw)-.18 F 3.449<6f8c>-.1 G .948
X(les to de\214ne the dependenc)396.829 177.6 R 3.448(yg)-.15 G(raph)522.23
X177.6 Q .862(and the updating actions for all tar)108 189.6 R 3.362(gets. The)
X-.18 F(\214le)3.362 E F2 -.15(Ja)3.362 G(mbase).15 E F0 .862
X(\(usually located in /usr/local/lib\) de\214nes rules,)3.362 F .89
X(and the \214le)108 201.6 R F2 -.15(Ja)3.39 G(m\214le).15 E F0 .89
X(\(located in the current directory\) lists the tar)3.39 F .889
X(gets and sources in terms of those rules.)-.18 F F2 -.15(Ja)108 213.6 S(m).15
XE F0 1.238(does not need to rely on suf)3.738 F(\214x-dri)-.25 E -.15(ve)-.25 G
X3.738(ni).15 G 1.238(mplicit rules or directory contents.)293.194 213.6 R(A)
X6.238 E F2 -.15(Ja)3.738 G(mbase).15 E F0 1.239(is pro)3.739 F(vided)-.15 E
X(with)108 225.6 Q F2(jam)2.5 E F0 2.5(;t)C(he user supplies the)153 225.6 Q F2
X-.15(Ja)2.5 G(m\214le).15 E F0(.)A(See)108 242.4 Q F2 -.15(Ja)2.658 G(m\214le)
X.15 E F0 .158(\(5\) for information on writing Jam\214les.)B .158
X(This manual page describes the program that interprets)5.158 F F2 -.15(Ja)108
X254.4 S(mbase).15 E F0(and)2.5 E F2 -.15(Ja)2.5 G(m\214le).15 E F0(.)A F1
X(OPTIONS)72 283.2 Q F0(If)108 295.2 Q F3(tar)3.789 E -.1(ge)-.37 G(t).1 E F0
X1.289(is pro)3.789 F 1.289(vided on the command line,)-.15 F F2(jam)3.789 E F0
X1.289(attempts to b)3.789 F 1.29(uild that tar)-.2 F 1.29(get; otherwise)-.18 F
XF2(jam)3.79 E F0 1.29(attempts to)3.79 F -.2(bu)108 307.2 S(ild the tar).2 E
X(get)-.18 E F3(all)2.5 E F0(.)A F2 -.15(Ja)108 324 S(m).15 E F0
X(supports the follo)2.5 E(wing options:)-.25 E 25.73(-a Build)108 340.8 R
X(all tar)2.5 E(gets, e)-.18 E -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)236.47 340.8 S
X(he)245.08 340.8 Q 2.5(ya)-.15 G(re up-to-date.)266.31 340.8 Q(-d)108 357.6 Q
XF3(<n>)A F0(Set the deb)9.17 E(ug le)-.2 E -.15(ve)-.25 G 2.5(lt).15 G(o)225.06
X357.6 Q F3(<n>)2.5 E F0 5(.I)C(nteresting v)261.89 357.6 Q(alues are:)-.25 E
X2.5(0E)144 374.4 S(mit only errors)157.61 374.4 Q 2.5(1E)144 386.4 S
X(mit update action tracing \(def)157.61 386.4 Q(ault\))-.1 E 2.5(2E)144 398.4 S
X(mit update commands)157.61 398.4 Q 2.5(3P)144 410.4 S(roduce dependenc)157.06
X410.4 Q 2.5(yi)-.15 G(nformation)239.66 410.4 Q 2.5(4S)144 422.4 S(ho)157.06
X422.4 Q 2.5(wm)-.25 G(odi\214cation times of bound \214les)184.31 422.4 Q 2.5
X(5S)144 434.4 S(ho)157.06 434.4 Q 2.5(wr)-.25 G(ule in)179.86 434.4 Q -.2(vo)
X-.4 G(cation).2 E(6-9 deb)144 446.4 Q(ugging)-.2 E(-f)108 463.2 Q F3(<\214le>)A
XF0(Read)144 475.2 Q F3(<\214le>)2.5 E F0(instead of)2.5 E F2 -.15(Ja)2.5 G
X(mbase).15 E F0(.)A(-j)108 492 Q F3(<jobs>)A F0(Run up to)144 504 Q F3(<jobs>)
X2.5 E F0(shell commands concurrently \(UNIX only\).)2.5 E(The def)5 E
X(ault is 1.)-.1 E 25.17(-n Don')108 520.8 R 2.5(ta)-.18 G(ctually e)174.09
X520.8 Q -.15(xe)-.15 G(cute the updating actions, b).15 E(ut do e)-.2 E -.15
X(ve)-.25 G(rything else.).15 E(This implies)5 E F2(-d)2.5 E F3(2)A F0(.)A(-t)
X108 537.6 Q F3(<tar)A -.1(ge)-.37 G(t>).1 E F0(Reb)144 549.6 Q(uild)-.2 E F3
X(<tar)2.5 E -.1(ge)-.37 G(t>).1 E F0 2.5(,e)C -.15(ve)224.08 549.6 S 2.5(ni).15
XG 2.5(fi)243.65 549.6 S 2.5(ti)252.26 549.6 S 2.5(su)260.32 549.6 S(p-to-date.)
X271.71 549.6 Q 25.17(-v Print)108 566.4 R(the v)2.5 E(ersion of)-.15 E F2(jam)
X2.5 E F0(and e)2.5 E(xit.)-.15 E F1(THE J)72 595.2 Q(AM LANGU)-.27 E -.495(AG)
X-.54 G(E).495 E F0(The)108 607.2 Q F2(jam)3.061 E F0 .561
X(language supports de\214ning rules, in)3.061 F -.2(vo)-.4 G .561
X(king rules, and setting v).2 F 3.06(ariables. It)-.25 F .56(also has a fe)3.06
XF 3.06<778d>-.25 G -.25(ow)513.04 607.2 S(-of-).25 E(control statements.)108
X619.2 Q F2 -.15(Ja)5 G(mbase).15 E F0(and)2.5 E F2 -.15(Ja)2.5 G(m\214le).15 E
XF0(share this language.)2.5 E F2(Lexical F)87 636 Q(eatur)-.25 E(es)-.18 E -.15
X(Ja)108 648 S(m).15 E F0 2.292
X(treats its input \214les as whitespace-separated tok)4.792 F 2.292
X(ens, with tw)-.1 F 4.792(oe)-.1 G 2.292(xceptions: double quotes \("\) can)
X401.77 648 R .503(enclose whitespace to embed it into a tok)108 660 R .502
X(en, and e)-.1 F -.15(ve)-.25 G .502
X(rything between the matching curly braces \({}\) in the).15 F
X(de\214nition of a rule action is treated as a single string.)108 672 Q 2.5(Ab)
X5 G(ackslash \(\\\) can escape a double quote.)339.64 672 Q F2 -.15(Ja)108
X688.8 S(m).15 E F0 1.615(requires whitespace \(blanks, tabs, or ne)4.115 F
X1.615(wlines\) to surround all tok)-.25 F 1.616
X(ens, including the colon \(:\) and)-.1 F .377(semicolon \(;\) tok)108 700.8 R
X2.877(ens. This)-.1 F .377(is because)2.877 F F2(jam)2.877 E F0 .377
X(runs on man)2.877 F 2.877(yp)-.15 G .377(latforms and no characters, sa)345.38
X700.8 R .676 -.15(ve w)-.2 H .376(hitespace, are).15 F
X(uncommon in the \214le names on all of those platforms.)108 712.8 Q
X(10 March 1995)275.45 768 Q(1)535 768 Q EP


X%%Page: 2 2
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S 403.38(M\(1\) J).6 F(AM\(1\))-.6 E/F1 10
X/Times-Bold@0 SF -.92(Ta)87 84 S -.1(rg).92 G(ets).1 E F0 -.8(Ta)108 96 S -.18
X(rg).8 G .077(ets are \214les to be updated and sources are the \214les used i\
Xn updating those tar).18 F 2.577(gets. Collecti)-.18 F -.15(ve)-.25 G(ly).15 E
X2.577(,t)-.65 G(he)510.923 96 Q 2.577(ya)-.15 G(re)532.23 96 Q .054
X(just referred to as "tar)108 108 R 2.554(gets". A)-.18 F(tar)2.554 E .053
X(get is simply a \214le name, either rooted or relati)-.18 F .353 -.15(ve t)
X-.25 H 2.553(ot).15 G .053(he directory of)455.141 108 R F1(jam)2.553 E F0 -.55
X('s)C(in)108 120 Q -.2(vo)-.4 G 4.843(cation. The).2 F 2.344(special syntax,)
X4.843 F/F2 10/Times-Italic@0 SF(\214le\(member\))4.844 E F0 4.844(,r)C 2.344
X(efers to an)307.688 120 R F1(ar)4.844 E F0 2.344(\(1\) library member)B 7.344
X(.T)-.55 G 2.344(he special syntax,)464.492 120 R F2(<grist>\214le)108 132 Q F0
X4.037(,p)C 1.537(erturbs a \214le name to distinguish it from other \214les wi\
Xth the same name.)163.597 132 R(The)6.536 E F2(<grist>)4.036 E F0(is)4.036 E
X(stripped from the name during binding \(q.v)108 144 Q(., belo)-.65 E(w\).)-.25
XE F1(Rules)87 160.8 Q -.15(Ja)108 172.8 S(m).15 E F0 1.562 -.55('s b)D .462
X(asic entity is called a rule, which is used to relate tar).55 F .463
X(gets to their sources.)-.18 F 2.963(Ar)5.463 G .463(ule is de\214ned in tw)
X457.138 172.8 R(o)-.1 E .313(parts: the)108 184.8 R F1(jam)2.813 E F0 .313
X(statements to e)2.813 F -.15(xe)-.15 G .312(cute when the rule is in).15 F -.2
X(vo)-.4 G -.1(ke).2 G 2.812(d\().1 G .312
X(essentially a procedure call\), and the actions)361.228 184.8 R .285
X(\(shell commands\) to e)108 196.8 R -.15(xe)-.15 G .286
X(cute in order to update the tar).15 F .286(gets of the rule.)-.18 F 2.786(Ar)
X5.286 G .286(ule may ha)407.57 196.8 R .586 -.15(ve a p)-.2 H .286
X(rocedure de\214ni-).15 F(tion, actions, or both.)108 208.8 Q(The)108 225.6 Q
XF1(jam)3.339 E F0 .838(statements for de\214ning and in)3.339 F -.2(vo)-.4 G
X.838(king rules are as follo).2 F(ws.)-.25 E F2(<tar)5.838 E -.1(ge)-.37 G(ts>)
X.1 E F0(and)3.338 E F2(<sour)3.338 E(ces>)-.37 E F0 .838(are lists of)3.338 F
X(\214le names;)108 237.6 Q F2(<statements>)2.5 E F0(are)2.5 E F1(jam)2.5 E F0
X(statements; and)2.5 E F2(<string>)2.5 E F0(is a shell script:)2.5 E(rule)144
X254.4 Q F2(<rulename>)2.5 E F0({)2.5 E F2(<statements>)2.5 E F0(})2.5 E
X(actions [)144 271.2 Q F2(modi\214er)2.5 E(s)-.1 E F0(])2.5 E F2(<rulename>)2.5
XE F0({)2.5 E F2(<string>)2.5 E F0(})2.5 E F2(<rulename> <tar)144 288 Q -.1(ge)
X-.37 G(ts>).1 E F0 2.5([:)2.5 G F2(<sour)A(ces>)-.37 E F0 2.5(];)2.5 G .832
X(The \214rst form de\214nes a rule')108 304.8 R 3.332(sp)-.55 G .832
X(rocedure; the second de\214nes the rule')238.53 304.8 R 3.332(su)-.55 G .832
X(pdating actions; the third in)404.042 304.8 R -.2(vo)-.4 G -.1(ke).2 G(s).1 E
X(the rule.)108 316.8 Q(Rede\214ning a rule')5 E 2.5(sp)-.55 G
X(rocedure or actions replaces the pre)228.82 316.8 Q(vious de\214nition.)-.25 E
X(In)108 333.6 Q -.2(vo)-.4 G .118(king a rule e).2 F -.15(xe)-.15 G .117
X(cutes the procedure for the rule \(if an).15 F .117(y\) and associates an)-.15
XF 2.617(yu)-.15 G .117(pdate actions for the tar)426.682 333.6 R(gets.)-.18 E
X.179(More than one update action may be associated with a tar)108 345.6 R .18
X(get: the actions are e)-.18 F -.15(xe)-.15 G .18(cuted in the order in which)
X.15 F(the)108 357.6 Q 2.5(ya)-.15 G(re added.)132.01 357.6 Q .26
X(In both the rule')108 374.4 R 2.76(sp)-.55 G .26
X(rocedure de\214nition and the rule')184.59 374.4 R 2.759(sa)-.55 G .259
X(ctions, the special v)325.029 374.4 R .259
X(ariables $\(<\) and $\(>\) refer to the)-.25 F F2(<tar)108 386.4 Q -.1(ge)-.37
XG(ts>).1 E F0(and)2.517 E F2(<sour)2.517 E(ces>)-.37 E F0(gi)2.517 E -.15(ve)
X-.25 G 2.517(na).15 G 2.517(tr)243.258 386.4 S .017(ule in)251.885 386.4 R -.2
X(vo)-.4 G 2.518(cation. Ho).2 F(we)-.25 E -.15(ve)-.25 G .818 -.4(r, i).15 H
X2.518(nt).4 G .018(he rule')369.456 386.4 R 2.518(sa)-.55 G .018
X(ctions, $\(<\) and $\(>\) refer to the)410.592 386.4 R F2(<tar)108 398.4 Q -.1
X(ge)-.37 G(ts>).1 E F0(and)3.782 E F2(<sour)3.782 E(ces>)-.37 E F0 1.282
X(after the)3.782 F 3.782(yh)-.15 G -2.25 -.2(av e)266.23 398.4 T 1.282
X(been bound by the binding phase \(q.v)3.982 F 1.282(., belo)-.65 F(w\).)-.25 E
XF1 -.15(Ja)6.282 G(m).15 E F0 1.281(issues a)3.781 F -.1(wa)108 410.4 S
X(rning if $\(<\) or $\(>\) ha).1 E .3 -.15(ve e)-.2 H
X(lements not in the dependenc).15 E 2.5(yg)-.15 G(raph.)356.68 410.4 Q
X(The follo)108 427.2 Q(wing action)-.25 E F2(modi\214er)2.5 E(s)-.1 E F0
X(are understood:)2.5 E F1(actions existing)144 444 Q F0
X($\(>\) includes only tar)180 456 Q(gets currently e)-.18 E(xisting.)-.15 E F1
X(actions ignor)144 472.8 Q(e)-.18 E F0
X(The return status of the shell commands is ignored.)180 484.8 Q F1
X(actions piecemeal)144 501.6 Q F0 .284(The shell commands are repeatedly in)180
X513.6 R -.2(vo)-.4 G -.1(ke).2 G 2.784(dw).1 G .285
X(ith a subset of $\(>\) small enough to \214t in a)367.074 513.6 R(command b)
X180 525.6 Q(uf)-.2 E(fer)-.25 E(.)-.55 E F1(actions quietly)144 542.4 Q F0
X(The action is not echoed to the standard output.)180 554.4 Q F1
X(actions together)144 571.2 Q F0 1.559
X(The $\(>\) from multiple instances of the same action on the same tar)180
X583.2 R 1.558(get are glommed)-.18 F(together)180 595.2 Q(.)-.55 E F1
X(actions updated)144 612 Q F0($\(>\) includes only tar)180 624 Q(gets mark)-.18
XE(ed for updating.)-.1 E F1(Built-in Rules)87 640.8 Q -.15(Ja)108 652.8 S(m).15
XE F0(has ten b)2.5 E(uilt-in rules, none of which ha)-.2 E .3 -.15(ve u)-.2 H
X(pdating actions:).15 E(AL)144 674.4 Q -1.15 -1.2(WA Y)-.74 H(S)1.2 E F2(<tar)
X2.5 E -.1(ge)-.37 G(ts>).1 E F0(;)2.5 E(Reb)180 686.4 Q(uilds)-.2 E F2(<tar)2.5
XE -.1(ge)-.37 G(ts>).1 E F0 2.5(,e)C -.15(ve)267.86 686.4 S 2.5(ni).15 G 2.5
X(ft)287.43 686.4 S(he)296.04 686.4 Q 2.5(ya)-.15 G(re up-to-date.)317.27 686.4
XQ(DEPENDS)144 703.2 Q F2(<tar)2.5 E -.1(ge)-.37 G(ts>).1 E F0(:)2.5 E F2(<sour)
X2.5 E(ces>)-.37 E F0(;)2.5 E(Mak)180 715.2 Q(es)-.1 E F2(<sour)2.5 E(ces>)-.37
XE F0(dependencies of)2.5 E F2(<tar)2.5 E -.1(ge)-.37 G(ts>).1 E F0(.)A
X(10 March 1995)275.45 768 Q(2)535 768 Q EP


X%%Page: 3 3
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S 403.38(M\(1\) J).6 F(AM\(1\))-.6 E(ECHO)
X144 84 Q/F1 10/Times-Italic@0 SF(<ar)2.5 E(gs>)-.37 E F0(;)2.5 E
X(Blurts out the message)180 96 Q F1(<ar)2.5 E(gs>)-.37 E F0(to stdout.)2.5 E
X(EXIT)144 112.8 Q F1(<ar)2.5 E(gs>)-.37 E F0(;)2.5 E(Blurts out the message)180
X124.8 Q F1(<ar)2.5 E(gs>)-.37 E F0(to stdout and then e)2.5 E(xits with a f)
X-.15 E(ailure status.)-.1 E(INCLUDES)144 141.6 Q F1(<tar)2.5 E -.1(ge)-.37 G
X(ts>).1 E F0(:)2.5 E F1(<sour)2.5 E(ces>)-.37 E F0(;)2.5 E(Mak)180 153.6 Q(es)
X-.1 E F1(<sour)2.5 E(ces>)-.37 E F0(dependencies of an)2.5 E(ything of which)
X-.15 E F1(<tar)2.5 E -.1(ge)-.37 G(ts>).1 E F0(are dependencies.)2.5 E(LEA)144
X170.4 Q(VES)-1.35 E F1(<tar)2.5 E -.1(ge)-.37 G(ts>).1 E F0(;)2.5 E(Mak)180
X182.4 Q 1.135(es each of)-.1 F F1(<tar)3.635 E -.1(ge)-.37 G(ts>).1 E F0 1.135
X(depend only on its leaf sources, and not on an)3.635 F 3.635(yi)-.15 G
X(ntermediate)492.79 182.4 Q(tar)180 194.4 Q 2.5(gets. Its)-.18 F
X(leaf sources are those dependencies without an)2.5 E 2.5(yd)-.15 G
X(ependencies themselv)426 194.4 Q(es.)-.15 E(NOCARE)144 211.2 Q F1(<tar)2.5 E
X-.1(ge)-.37 G(ts>).1 E F0(;)2.5 E(Marks)180 223.2 Q F1(<tar)2.5 E -.1(ge)-.37 G
X(ts>).1 E F0(as possibly being bogus.)2.5 E(NO)144 240 Q(TFILE)-.4 E F1(<tar)
X2.5 E -.1(ge)-.37 G(ts>).1 E F0(;)2.5 E(Marks)180 252 Q F1(<tar)2.5 E -.1(ge)
X-.37 G(ts>).1 E F0(as not being \214les.)2.5 E(NOUPD)144 268.8 Q -1.11(AT)-.4 G
X(E)1.11 E F1(<tar)2.5 E -.1(ge)-.37 G(ts>).1 E F0(;)2.5 E .112
X(Causes the timestamps of)180 280.8 R F1(<tar)2.612 E -.1(ge)-.37 G(ts>).1 E F0
X.112(to be ignored: either the tar)2.612 F .112(get e)-.18 F .112
X(xists or it doesn')-.15 F 2.612(t. If)-.18 F(it e)180 292.8 Q
X(xists, it is considered eternally old.)-.15 E(TEMPORAR)144 309.6 Q(Y)-.65 E F1
X(<tar)2.5 E -.1(ge)-.37 G(ts>).1 E F0(;)2.5 E(Marks)180 321.6 Q F1(<tar)2.5 E
X-.1(ge)-.37 G(ts>).1 E F0(as temporary)2.5 E(.)-.65 E(The)108 338.4 Q F1(AL)
X4.539 E -1.85 -.6(WA Y)-.55 H(S).6 E F0(,)A F1(LEA)4.539 E(VES)-1.05 E F0(,)A
XF1(NOCARE)4.539 E F0(,)A F1(NO)4.539 E(TFILE)-.4 E F0(,)A F1(NOUPD)4.539 E -.37
X(AT)-.35 G(E).37 E F0 4.539(,a)C(nd)367.194 338.4 Q F1(TEMPORAR)4.539 E(Y)-.18
XE F0(af)4.539 E 2.039(fect only the binding)-.25 F(phase \(q.v)108 350.4 Q
X(.\).)-.65 E/F2 10/Times-Bold@0 SF(Flo)87 367.2 Q(w-of-Contr)-.1 E(ol)-.18 E
X-.15(Ja)108 379.2 S(m).15 E F0(has se)2.5 E -.15(ve)-.25 G(ral simple \215o).15
XE(w-of-control statements:)-.25 E(include)144 396 Q F1(<a>)2.5 E F0(;)2.5 E
X(for)144 412.8 Q F1(<a>)2.5 E F0(in)2.5 E F1(<ar)2.5 E(gs>)-.37 E F0({)2.5 E F1
X(<statements>)2.5 E F0(})2.5 E(switch)144 429.6 Q F1(<a>)2.5 E F0 2.5({c)2.5 G
X(ase)205.35 429.6 Q F1(<v1>)2.5 E F0(:)2.5 E F1(<statements>)2.5 E F0 2.5(;c)
X2.5 G(ase)319.28 429.6 Q F1(<v2>)2.5 E F0(:)2.5 E F1(<statements>)2.5 E F0 2.5
X(;.)2.5 G(.. })431.27 429.6 Q(if)144 446.4 Q F1(<cond>)2.5 E F0({)2.5 E F1
X(<statements>)2.5 E F0 2.5(}[e)2.5 G(lse {)271.14 446.4 Q F1(<statements>)2.5 E
XF0 2.5(}])2.5 G(The)108 463.2 Q F2(include)2.809 E F0 .308
X(statement includes the named \214le.)2.809 F .308(The \214le is bound lik)
X5.308 F 2.808(er)-.1 G -.15(eg)394.918 463.2 S .308(ular tar).15 F .308
X(gets \(see)-.18 F F2(Binding)2.808 E F0 2.808(,b)C(elo)514.98 463.2 Q(w\),)
X-.25 E -.2(bu)108 475.2 S 2.5(tu).2 G(nlik)128.08 475.2 Q 2.5(er)-.1 G -.15(eg)
X153.81 475.2 S(ular tar).15 E(gets the include \214le cannot be b)-.18 E(uilt.)
X-.2 E(The)108 492 Q F2 -.25(fo)2.5 G(r).25 E F0(loop e)2.5 E -.15(xe)-.15 G
X(cutes).15 E F1(<statements>)2.5 E F0(for each v)2.5 E(alue in)-.25 E F1(<ar)
X2.5 E(gs>)-.37 E F0 2.5(,s)C(etting the v)365.17 492 Q(ariable)-.25 E F1(<a>)
X2.5 E F0(to the v)2.5 E(alue.)-.25 E(The)108 508.8 Q F2(switch)3.134 E F0 .634
X(statement e)3.134 F -.15(xe)-.15 G .635(cutes zero or one of the enclosed).15
XF F1(<statements>)3.135 E F0 3.135(,d)C .635(epending on which v)416.45 508.8 R
X(alue)-.25 E F1(<a>)3.135 E F0 3.898(matches. The)108 520.8 R F1(<v>)3.898 E F0
X-.25(va)3.898 G 1.398(lues are not v).25 F(ariable-e)-.25 E 3.898(xpanded. The)
X-.15 F F1(<v>)3.898 E F0 -.25(va)3.898 G 1.398(lues may include the follo).25 F
X1.397(wing wild-)-.25 F(cards:)108 532.8 Q 67.56(?m)144 549.6 S(atch an)223.78
X549.6 Q 2.5(ys)-.15 G(ingle character)263.62 549.6 Q 67(*m)144 561.6 S
X(atch zero or more characters)223.78 561.6 Q([)144 573.6 Q F1(<c)A(har)-.15 E
X(s>)-.1 E F0 29.87(]m)C(atch an)223.78 573.6 Q 2.5(ys)-.15 G
X(ingle character in)263.62 573.6 Q F1(<c)2.5 E(har)-.15 E(s>)-.1 E F0(The)108
X590.4 Q F2(if)2.5 E F0(statement does the ob)2.5 E(vious; the)-.15 E F2(else)
X2.5 E F0(clause is optional.)2.5 E F1(<cond>)5 E F0(is b)2.5 E(uilt of:)-.2 E
XF1(<a>)144 607.2 Q F0(true if)216 607.2 Q F1(<a>)2.5 E F0
X(is a non-zero-length string)2.5 E F1(<a>)144 619.2 Q F0(=)2.5 E F1(<b>)2.5 E
XF0(strings equal)216 619.2 Q F1(<a>)144 631.2 Q F0(!=)2.5 E F1(<b>)2.5 E F0
X(strings not equal)216 631.2 Q F1(<a>)144 643.2 Q F0(<)2.5 E F1(<b>)2.5 E F0
X(string less than)216 643.2 Q F1(<a>)144 655.2 Q F0(<=)2.5 E F1(<b>)2.5 E F0
X(string less than or equal to)216 655.2 Q F1(<a>)144 667.2 Q F0(>)2.5 E F1(<b>)
X2.5 E F0(string greater than)216 667.2 Q F1(<a>)144 679.2 Q F0(>=)2.5 E F1(<b>)
X2.5 E F0(string greater than or equal to)216 679.2 Q(!)144 696 Q F1(<cond>)2.5
XE F0(condition not true)252 696 Q F1(<cond>)144 708 Q F0(&&)2.5 E F1(<cond>)2.5
XE F0(conjunction)252 708 Q F1(<cond>)144 720 Q F0(||)2.5 E F1(<cond>)2.5 E F0
X(disjunction)252 720 Q(10 March 1995)275.45 768 Q(3)535 768 Q EP


X%%Page: 4 4
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S 403.38(M\(1\) J).6 F(AM\(1\))-.6 E(\()
X144 84 Q/F1 10/Times-Italic@0 SF(<cond>)2.5 E F0 63.4(\)g)2.5 G(rouping)257 84
XQ .322(In comparisons, the ar)108 100.8 R .322(guments may \(through v)-.18 F
X.322(ariable e)-.25 F .323(xpansion\) be more than one tok)-.15 F .323(en, b)
X-.1 F .323(ut only the \214rst)-.2 F(tok)108 112.8 Q 1.035(en tak)-.1 F 1.035
X(es part in the comparison.)-.1 F 1.035(If, through v)6.035 F 1.035(ariable e)
X-.25 F 1.035(xpansion, the ar)-.15 F 1.035(gument is zero tok)-.18 F 1.035
X(ens, a single)-.1 F(tok)108 124.8 Q
X(en of a zero-length string is used instead.)-.1 E/F2 10/Times-Bold@0 SF -.92
X(Va)87 141.6 S(riables).92 E -.15(Ja)108 153.6 S(m).15 E F0 -.25(va)3.272 G
X.773(riables are lists of strings, with zero or more elements.).25 F .773
X(An unde\214ned v)5.773 F .773(ariable is indistinguishable)-.25 F .032
X(from a v)108 165.6 R .032(ariable whose v)-.25 F .031(alue is an empty list.)
X-.25 F -1.11(Va)5.031 G .031(riables are either global or tar)1.11 F 2.531
X(get-speci\214c. All)-.18 F -.25(va)2.531 G .031(riables are).25 F
X(referenced as $\(V)108 177.6 Q(ARIABLE\).)-1.35 E 2.5(Av)108 194.4 S
X(ariable is de\214ned with:)122.47 194.4 Q F1(<variable>)144 211.2 Q F0(=)2.5 E
XF1(<values>)2.5 E F0(;)2.5 E F1(<variable>)144 228 Q F0(+=)2.5 E F1(<values>)
X2.5 E F0(;)2.5 E F1(<variable>)144 244.8 Q F0(on)2.5 E F1(<tar)2.5 E -.1(ge)
X-.37 G(ts>).1 E F0(=)2.5 E F1(<values>)2.5 E F0(;)2.5 E F1(<variable>)144 261.6
XQ F0(on)2.5 E F1(<tar)2.5 E -.1(ge)-.37 G(ts>).1 E F0(+=)2.5 E F1(<values>)2.5
XE F0(;)2.5 E F1(<variable>)144 278.4 Q F0(def)2.5 E(ault =)-.1 E F1(<values>)
X2.5 E F0(;)2.5 E .314(The \214rst tw)108 295.2 R 2.814(of)-.1 G .314(orms set)
X165.782 295.2 R F1(<variable>)2.814 E F0(globally)2.814 E 5.314(.T)-.65 G .315
X(he third and forth forms set a tar)298.218 295.2 R .315(get-speci\214c v)-.18
XF .315(ariable, where)-.25 F F1(<variable>)108 307.2 Q F0(tak)2.834 E .333
X(es on a v)-.1 F .333(alue only during the binding and updating)-.25 F F1(<tar)
X2.833 E -.1(ge)-.37 G(ts>).1 E F0 5.333(.T)C(he)433.158 307.2 Q F2(=)2.833 E F0
X.333(operator replaces an)2.833 F(y)-.15 E(pre)108 319.2 Q .946(vious v)-.25 F
X.946(alue of)-.25 F F1(<variable>)3.446 E F0(with)3.446 E F1(<values>)3.446 E
XF0 3.446(;t)C(he)301.826 319.2 Q F2(+=)3.446 E F0 .947(operation appends)3.446
XF F1(<values>)3.447 E F0 .947(to an)3.447 F 3.447(yp)-.15 G(re)483.453 319.2 Q
X.947(vious v)-.25 F(alue.)-.25 E(The \214nal form sets)108 331.2 Q F1
X(<variable>)2.5 E F0(globally)2.5 E 2.5(,b)-.65 G(ut only if it w)277.03 331.2
XQ(as pre)-.1 E(viously unset.)-.25 E .364(On program start-up,)108 348 R F2
X(jam)2.863 E F0 .363(imports the en)2.863 F .363(vironment v)-.4 F .363
X(ariable settings into)-.25 F F2(jam)2.863 E F0 -.25(va)2.863 G 2.863
X(riables. En).25 F .363(vironment v)-.4 F(ari-)-.25 E .92
X(ables are split at blanks with each w)108 360 R .92
X(ord becomming an element in the v)-.1 F(ariable')-.25 E 3.42(sl)-.55 G .92
X(ist v)445.48 360 R 3.42(alue. En)-.25 F(vironment)-.4 E -.25(va)108 372 S .11
X(riables whose names end in).25 F F2 -.74(PA)2.61 G(TH)-.21 E F0 .11
X(are split at colons \(")2.61 F F2(:)A F0("\).)A F2 -.15(Ja)5.109 G(m).15 E F0
X-.25(va)2.609 G .109(riables are not re-e).25 F .109(xported to the shell)-.15
XF 1.827(that e)108 384 R -.15(xe)-.15 G 1.827(cutes the updating actions, b).15
XF 1.827(ut the updating actions can reference)-.2 F F2(jam)4.327 E F0 -.25(va)
X4.327 G 1.828(riables with $\(V).25 F(ARI-)-1.35 E(ABLE\).)108 396 Q F2 -.92
X(Va)87 412.8 S(riable Expansion).92 E F0 .322(Before e)108 424.8 R -.15(xe)-.15
XG .322(cuting a statement,).15 F F2(jam)2.822 E F0 .322(performs v)2.822 F .322
X(ariable e)-.25 F .322(xpansion on each tok)-.15 F .322(en that is not a k)-.1
XF -.15(ey)-.1 G -.1(wo).15 G .321(rd or rule).1 F .246(name. Such tok)108 436.8
XR .246(ens with embedded v)-.1 F .247
X(ariable references are replaced with zero or more tok)-.25 F 2.747(ens. V)-.1
XF .247(ariable ref-)-1.11 F(erences are of the form $\()108 448.8 Q F1(v)A F0
X2.5(\)o)C 2.5(r$)226.28 448.8 S(\()237.11 448.8 Q F1(vm)A F0(\), where)A F1(v)
X2.5 E F0(is the v)2.5 E(ariable name, and)-.25 E F1(m)2.5 E F0
X(are optional modi\214ers.)2.5 E -1.11(Va)108 465.6 S .676(riable e)1.11 F .676
X(xpansion in a rule')-.15 F 3.176(sa)-.55 G .676(ctions is similar to v)236.48
X465.6 R .676(ariable e)-.25 F .675(xpansion in statements, e)-.15 F .675
X(xcept that the action)-.15 F(string is tok)108 477.6 Q
X(enized at whitespace re)-.1 E -.05(ga)-.15 G(rdless of quoting.).05 E .967
X(The result of a tok)108 494.4 R .968(en after v)-.1 F .968(ariable e)-.25 F
X.968(xpansion is the product of the components of the tok)-.15 F .968
X(en, where each)-.1 F
X(component is a literal substring or a list substituting a v)108 506.4 Q
X(ariable reference.)-.25 E -.15(Fo)5 G 2.5(re).15 G(xample:)424.35 506.4 Q
X50.62($\(X\) ->)144 523.2 R 2.5(abc)2.5 G 47.84(t$\(X\) ->)144 535.2 R
X(ta tb tc)2.5 E 46.18($\(X\)z ->)144 547.2 R(az bz cz)2.5 E 28.41
X($\(X\)-$\(X\) ->)144 559.2 R(a-a a-b a-c b-a b-b b-c c-a c-b c-c)2.5 E .162
X(The v)108 576 R .162(ariable name and modi\214ers can themselv)-.25 F .162
X(es contain a v)-.15 F .162(ariable reference, and this partak)-.25 F .161
X(es of the prod-)-.1 F(uct as well:)108 588 Q 50.62($\(X\) ->)144 604.8 R 2.5
X(abc)2.5 G 50.62($\(Y\) ->)144 616.8 R 2.5(12)2.5 G 51.73($\(Z\) ->)144 628.8 R
X2.5(XY)2.5 G 40.07($\($\(Z\)\) ->)144 640.8 R 2.5(abc12)2.5 G .161
X(Because of this product e)108 657.6 R .161(xpansion, if an)-.15 F 2.661(yv)
X-.15 G .161(ariable reference in a tok)281.327 657.6 R .161
X(en is unde\214ned, the result of the e)-.1 F(xpan-)-.15 E
X(sion is an empty list.)108 669.6 Q(Modi\214ers to a v)108 686.4 Q
X(ariable are of tw)-.25 E 2.5(ov)-.1 G
X(arieties: sub-element selection and \214le name editing.)248.76 686.4 Q(The)5
XE 2.5(ya)-.15 G(re:)491.35 686.4 Q([)108 708 Q F1(<n>)A F0 10.84(]S)C .083
X(elect only element number)149.56 708 R F1(<n>)2.583 E F0 .083
X(\(starting at 1\).)2.583 F .083(If the v)5.083 F .082(ariable contains fe)-.25
XF .082(wer than)-.25 F F1(<n>)2.582 E F0(elements,)2.582 E
X(the result is a zero-element list.)144 720 Q(10 March 1995)275.45 768 Q(4)535
X768 Q EP


X%%Page: 5 5
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S 403.38(M\(1\) J).6 F(AM\(1\))-.6 E([)108
X84 Q/F1 10/Times-Italic@0 SF(<n>)A F0(-)A F1(<m>)A F0(])A
X(Select only elements number)144 96 Q F1(<n>)2.5 E F0(through)2.5 E F1(<m>)2.5
XE F0(.)A([)108 112.8 Q F1(<n>)A F0 5.01(-] Select)B(only elements number)2.5 E
XF1(<n>)2.5 E F0(through the last.)2.5 E(:G=)108 129.6 Q F1(<grist>)A F0
X(Replace the grist of the \214le name with)144 141.6 Q F1(<grist>)2.5 E F0(.)A
X(:D=)108 158.4 Q F1(<path>)A F0
X(Replace directory component of \214le name with)144 170.4 Q F1(<path>)2.5 E F0
X(.)A(:B=)108 187.2 Q F1(<base>)A F0(Replace the base part of \214le name with)
X144 199.2 Q F1(<base>)2.5 E F0(.)A(:S=)108 216 Q F1(<suf>)A F0(Replace the suf)
X144 228 Q(\214x of \214le name with)-.25 E F1(<suf>)2.5 E F0(.)A(:M=)108 244.8
XQ F1(<mem>)A F0(Replace the archi)144 256.8 Q .3 -.15(ve m)-.25 H
X(ember name with).15 E F1(<mem>)2.5 E F0(.)A(:R=)108 273.6 Q F1(<r)A(oot>)-.45
XE F0(Prepend)144 285.6 Q F1(<r)2.5 E(oot>)-.45 E F0
X(to the whole \214le name, if not already rooted.)2.5 E(:)108 302.4 Q F1
X(<components>)A F0(Remo)144 314.4 Q .3 -.15(ve c)-.15 H
X(omponents not listed; components is one or more of).15 E/F2 10/Times-Bold@0 SF
X(GDBSM)2.5 E F0(.)A/F3 9/Times-Bold@0 SF(OPERA)72 343.2 Q(TION)-.855 E F2 -.15
X(Ja)108 355.2 S(m).15 E F0
X(has three phases of operation: parsing, binding, and updating.)2.5 E F2 -.1
X(Pa)87 372 S(rsing).1 E -.15(Ja)108 384 S(m).15 E F0 .323(parses the)2.823 F F2
X-.15(Ja)2.823 G(mbase).15 E F0 .324(\214le, which includes)2.823 F F2 -.15(Ja)
X2.824 G(m\214le).15 E F0 5.324(.T)C .324
X(he results of parsing are: the dependenc)338.168 384 R 2.824(yg)-.15 G .324
X(raph of)511.076 384 R(tar)108 396 Q
X(gets; update actions associated with the tar)-.18 E(gets; and v)-.18 E
X(ariables set to speci\214c v)-.25 E(alues.)-.25 E F2(Binding)87 417.6 Q F0
X1.393(After parsing,)108 429.6 R F2(jam)3.893 E F0(recursi)3.893 E -.15(ve)-.25
XG 1.393(ly descends the dependenc).15 F 3.893(yg)-.15 G 1.393
X(raph, attempting to locate each tar)349.911 429.6 R 1.392(get \214le and)-.18
XF(determine if it is in need of updating.)108 441.6 Q(If)5 E F2(jam)2.5 E F0
X(detects a c)2.5 E(ycle in the graph, it issues a w)-.15 E(arning.)-.1 E .038
X(By def)108 458.4 R .038(ault, a tar)-.1 F .038
X(get is located at the actual path of the tar)-.18 F .039(get, relati)-.18 F
X.339 -.15(ve t)-.25 H 2.539(ot).15 G .039(he directory of)396.825 458.4 R F2
X(jam)2.539 E F0 1.139 -.55('s i)D -1.9 -.4(nv o).55 H 2.539(cation. If).4 F
X.378(the special v)108 470.4 R .377(ariable $\(LOCA)-.25 F .377
X(TE\) is set to a directory name,)-1.11 F F2(jam)2.877 E F0 .377
X(prepends that directory name to the tar)2.877 F(get;)-.18 E .093
X(else if the special v)108 482.4 R .093
X(ariable $\(SEARCH\) is set to a directory list,)-.25 F F2(jam)2.593 E F0 .093
X(searches along the directory list for the)2.593 F(tar)108 494.4 Q .284
X(get \214le, and if the \214le is found prepends the directory name to the tar)
X-.18 F 2.784(get. If)-.18 F .284(the tar)2.784 F .283(get name has a rooted)
X-.18 F .001(directory component then $\(SEARCH\) and $\(LOCA)108 506.4 R .001
X(TE\) do not apply: the tar)-1.11 F .002(get is located at the actual path)-.18
XF .028(of the tar)108 518.4 R 2.528(get. If)-.18 F 2.528(at)2.528 G(ar)182.66
X518.4 Q .028(get is mark)-.18 F .028(ed as not being a \214le \(using the b)-.1
XF .028(uilt-in rule NO)-.2 F .027(TFILE\), it is left unbound to)-.4 F 2.5
X<618c>108 530.4 S(le name.)120.5 530.4 Q .235(After binding each tar)108 547.2
XR(get,)-.18 E F2(jam)2.735 E F0 .235(determines whether the tar)2.735 F .235
X(get needs updating, and marks the tar)-.18 F .235(get if neces-)-.18 F
X(sary for the updating phase.)108 559.2 Q 2.5(At)5 G(ar)236.31 559.2 Q
X(get is mark)-.18 E(ed for updating for an)-.1 E 2.5(yo)-.15 G 2.5(ft)387.79
X559.2 S(hese three reasons:)396.4 559.2 Q(It is missing.)144 576 Q
X(Its \214lesystem modi\214cation time is older than an)144 592.8 Q 2.5(yo)-.15
XG 2.5(fi)346.63 592.8 S(ts sources.)355.24 592.8 Q(An)144 609.6 Q 2.5(yo)-.15 G
X2.5(fi)168.57 609.6 S(ts sources are mark)177.18 609.6 Q(ed for updating.)-.1 E
X(This basic beha)108 626.4 Q
X(vior can be modi\214ed applying \(usually one of\) the follo)-.2 E(wing six b)
X-.25 E(uilt-in rules to the tar)-.2 E(get:)-.18 E(AL)144 643.2 Q -1.15 -1.2
X(WA Y)-.74 H(S)1.2 E(The tar)180 655.2 Q(get is al)-.18 E -.1(wa)-.1 G
X(ys updated.).1 E(LEA)144 672 Q(VES)-1.35 E .059(The tar)180 684 R .059
X(get is only updated if it is missing or if its leaf sources are ne)-.18 F(wer)
X-.25 E 5.059(.L)-.55 G .058(eaf sources are)480.474 684 R
X(those dependencies of the tar)180 696 Q(get that ha)-.18 E .3 -.15(ve n)-.2 H
X2.5(od).15 G(ependencies themselv)366.65 696 Q(es.)-.15 E(10 March 1995)275.45
X768 Q(5)535 768 Q EP


X%%Page: 6 6
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S 403.38(M\(1\) J).6 F(AM\(1\))-.6 E
X(NOCARE)144 84 Q .244(The tar)180 96 R .244
X(get is ignored if it is missing and has no updating actions.)-.18 F(Normally)
X5.245 E(,)-.65 E/F1 10/Times-Bold@0 SF(jam)2.745 E F0 .245(issues a)2.745 F -.1
X(wa)180 108 S(rning and skips other tar).1 E(gets that depend on missing tar)
X-.18 E(gets without updating actions.)-.18 E(TEMPORAR)144 124.8 Q(Y)-.65 E 2.28
X(If the tar)180 136.8 R 2.28(get is missing, then its parent')-.18 F 4.78(sm)
X-.55 G 2.28(odi\214cation time is used when comparing)366.11 136.8 R(ag)180
X148.8 Q(ainst sources.)-.05 E(NO)144 165.6 Q(TFILE)-.4 E(The tar)180 177.6 Q
X(get is only updated if an)-.18 E 2.5(yo)-.15 G 2.5(fi)317.15 177.6 S
X(ts sources are mark)325.76 177.6 Q(ed for updating.)-.1 E(NOUPD)144 194.4 Q
X-1.11(AT)-.4 G(E)1.11 E .722(The tar)180 206.4 R .722
X(get is only updated if it is missing.)-.18 F .722(Also, if it e)5.722 F .723
X(xists, it will appear eternally old;)-.15 F(that is, older than an)180 218.4 Q
X(ything that depends on it.)-.15 E .373(If a tar)108 235.2 R .373
X(get is a source \214le that includes other \214les,)-.18 F F1(jam)2.872 E F0
X.372(scans the source \214le for header \214le include lines.)2.872 F(It)5.372
XE .707(scans the \214le by matching each line ag)108 247.2 R .707(ainst a)-.05
XF F1 -.18(re)3.207 G(gexp).18 E F0 .707(\(3\) pattern that has \(\)')B 3.207
X(ss)-.55 G .707(urrounding the included \214le)426.498 247.2 R 5.495(name. The)
X108 259.2 R 2.995(pattern is pro)5.495 F 2.994
X(vided by the user through the special v)-.15 F 2.994
X(ariable $\(HDRSCAN\) \(see)-.25 F F1(HDR-)5.494 E -.74(PA)108 271.2 S(TTERN)
X-.21 E F0(in)3.143 E F1 -.15(Ja)3.143 G(mbase).15 E F0 .644(for an e)3.144 F
X3.144(xample\). The)-.15 F .644(result of the scan is formed into a rule in)
X3.144 F -.2(vo)-.4 G .644(cation, with the).2 F .638(scanned \214le as the tar)
X108 283.2 R .638(get and the found included \214le names as the sources.)-.18 F
X.638(The rule in)5.638 F -.2(vo)-.4 G -.1(ke).2 G 3.138(di).1 G 3.137(sn)
X493.176 283.2 S .637(amed by)505.203 283.2 R .129(the special v)108 295.2 R
X.129(ariable $\(HDRR)-.25 F(ULE\).)-.4 E F1 -.15(Ja)5.129 G(m).15 E F0 .129
X(only scans \214les if $\(HDRSCAN\) is set, and $\(HDRSCAN\) is nor)2.629 F(-)
X-.2 E(mally set tar)108 307.2 Q(get-speci\214c.)-.18 E
X(Between binding and updating,)108 324 Q F1(jam)2.5 E F0
X(announces the number of tar)2.5 E(gets to be updated.)-.18 E F1(Updating)87
X340.8 Q F0 .095(After binding,)108 352.8 R F1(jam)2.595 E F0(ag)2.595 E .095
X(ain recursi)-.05 F -.15(ve)-.25 G .094(ly descends the dependenc).15 F 2.594
X(yg)-.15 G .094(raph, this time e)366.146 352.8 R -.15(xe)-.15 G .094
X(cuting the update actions).15 F .513(for each tar)108 364.8 R .513(get mark)
X-.18 F .513(ed for update during the binding phase.)-.1 F .513(If a tar)5.513 F
X(get')-.18 E 3.014(su)-.55 G .514(pdating actions f)409.97 364.8 R .514
X(ail, then all tar)-.1 F(-)-.2 E(gets which depend on it are skipped.)108 376.8
XQ .095(\(UNIX only\).)108 393.6 R(The)5.095 E F1(-j)2.595 E F0 .095
X(\215ag instructs)2.595 F F1(jam)2.595 E F0 .095(to b)2.595 F .095
X(uild more than one tar)-.2 F .095(get at a time.)-.18 F .095
X(If there are multiple actions)5.095 F(on a single tar)108 405.6 Q(get, the)
X-.18 E 2.5(ya)-.15 G(re run sequentially)205.43 405.6 Q(.)-.65 E .001
X(\(UNIX only\).)108 422.4 R .001(The special v)5.001 F .001(ariable $\(J)-.25 F
X.001(AMSHELL\) gi)-.6 F -.15(ve)-.25 G(s).15 E F1(jam)2.501 E F0 2.501(ac)2.501
XG .001(ommand e)368.639 422.4 R -.15(xe)-.15 G .002
X(cution shell to be used instead).15 F .371(of /bin/sh.)108 434.4 R .371
X(This v)5.371 F(ariable')-.25 E 2.871(sv)-.55 G .371
X(alue must be a multi-element list, corresponding to the ar)221.204 434.4 R .37
X(gument v)-.18 F .37(ector for the)-.15 F 1.8(command shell.)108 446.4 R 1.8
X(An element ")6.8 F F1(%)A F0 4.3("i)C 4.3(sr)257.65 446.4 S 1.801
X(eplaced with the command string to e)269.17 446.4 R -.15(xe)-.15 G 4.301
X(cute. An).15 F 1.801(element ")4.301 F F1(!)A F0 4.301("i)C(s)536.11 446.4 Q
X.45(replaced with the multiprocess slot number)108 458.4 R 2.949(,w)-.4 G .449
X(hich is \(inclusi)294.999 458.4 R -.15(ve)-.25 G .449
X(ly\) between 1 and the maximum number of).15 F .074
X(concurrent jobs speci\214ed with the)108 470.4 R F1(-j)2.574 E F0 .074
X(\215ag \(def)2.574 F .074(ault 1\).)-.1 F .075(If no element of the list is ")
X5.074 F F1(%)A F0 .075(", the command string is)B(tack)108 482.4 Q
X(ed on as the last ar)-.1 E 2.5(gument. The)-.18 F(def)2.5 E(ault v)-.1 E
X(alue is: "/bin/sh -c %".)-.25 E/F2 9/Times-Bold@0 SF(DIA)72 511.2 Q(GNOSTICS)
X-.495 E F0(In addition to generic error messages,)108 523.2 Q F1(jam)2.5 E F0
X(may emit one of the follo)2.5 E(wing:)-.25 E -.1(wa)108 540 S(rning: unkno).1
XE(wn rule X)-.25 E 2.5(Ar)144 556.8 S(ule w)157.05 556.8 Q(as in)-.1 E -.2(vo)
X-.4 G -.1(ke).2 G 2.5(dt).1 G
X(hat has not been de\214ned with an "actions" or "rule" statement.)226.52 556.8
XQ(using N temp tar)108 573.6 Q(get\(s\))-.18 E -.8(Ta)144 590.4 S -.18(rg).8 G
X(ets mark).18 E(ed as being temporary \(b)-.1 E(ut nonetheless present\) ha)-.2
XE .3 -.15(ve b)-.2 H(een found.).15 E(updating N tar)108 607.2 Q(get\(s\))-.18
XE -.8(Ta)144 624 S -.18(rg).8 G(ets are out-of-date and will be updated.).18 E
X(can')108 640.8 Q 2.5<748c>-.18 G(nd N tar)135.87 640.8 Q(get\(s\))-.18 E
X(Source \214les can')144 657.6 Q 2.5(tb)-.18 G 2.5(ef)220.75 657.6 S
X(ound and there are no actions to create them.)231.02 657.6 Q(can')108 674.4 Q
X2.5(tm)-.18 G(ak)138.09 674.4 Q 2.5(eNt)-.1 G(ar)166.87 674.4 Q(get\(s\))-.18 E
X(Due to sources not being found, other tar)144 691.2 Q(gets cannot be made.)
X-.18 E -.1(wa)108 708 S(rning: X depends on itself).1 E(10 March 1995)275.45
X768 Q(6)535 768 Q EP


X%%Page: 7 7
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S 403.38(M\(1\) J).6 F(AM\(1\))-.6 E 2.5
X(At)144 84 S(ar)156.5 84 Q
X(get depends on itself either directly or through its sources.)-.18 E(don')108
X100.8 Q 2.5(tk)-.18 G(no)136.43 100.8 Q 2.5(wh)-.25 G .5 -.25(ow t)160.9 100.8
XT 2.5(om).25 G(ak)193.43 100.8 Q 2.5(eX)-.1 G 2.5(At)144 117.6 S(ar)156.5 117.6
XQ(get is not present and no actions ha)-.18 E .3 -.15(ve b)-.2 H
X(een de\214ned to create it.).15 E 2.5(Xs)108 134.4 S(kipped for lack of Y)
X121.61 134.4 Q 2.5(As)144 151.2 S(ource f)157.61 151.2 Q(ailed to b)-.1 E
X(uild, and thus a tar)-.2 E(get cannot be b)-.18 E(uilt.)-.2 E -.1(wa)108 168 S
X(rning: using independent tar).1 E(get X)-.18 E 2.5(At)144 184.8 S(ar)156.5
X184.8 Q(get that does is not a dependenc)-.18 E 2.5(yo)-.15 G 2.5(fa)303.64
X184.8 S .3 -.15(ny o)313.91 184.8 T(ther tar).15 E
X(get is being referenced with $\(<\) or $\(>\).)-.18 E 2.5(Xr)108 201.6 S(emo)
X121.05 201.6 Q -.15(ve)-.15 G(d).15 E/F1 10/Times-Bold@0 SF -.15(Ja)144 218.4 S
X(m).15 E F0(remo)2.5 E -.15(ve)-.15 G 2.5(dap).15 G(artially b)213.81 218.4 Q
X(uilt tar)-.2 E(get after being interrupted.)-.18 E/F2 9/Times-Bold@0 SF(FILES)
X72 247.2 Q F0(/usr/local/lib/Jambase)108 259.2 Q(Jam\214le)108 271.2 Q F2 -.09
X(BU)72 300 S(GS, LIMIT).09 E -.855(AT)-.81 G(IONS).855 E F0 .752(Because the)
X108 312 R F1(include)3.252 E F0 .751(statement w)3.251 F .751
X(orks by pushing a ne)-.1 F 3.251<778c>-.25 G .751
X(le in the input stream of the scanner rather than)344.671 312 R(recursi)108
X324 Q -.15(ve)-.25 G .294(ly in).15 F -.2(vo)-.4 G .294
X(king the parser on the ne).2 F 2.794<778c>-.25 G .294
X(le, multiple include statements in a rule')287.388 324 R 2.795(sp)-.55 G .295
X(rocedure causes the)461.11 324 R(\214les to be included in re)108 336 Q -.15
X(ve)-.25 G(rse order).15 E(.)-.55 E .069(If the)108 352.8 R F1(include)2.569 E
XF0 .069(statement appears inside an)2.569 F F1(if)2.569 E F0 .069
X(block, the parser')2.569 F 2.568(sa)-.55 G .068(ttempt to \214nd the)367.048
X352.8 R F1(else)2.568 E F0 .068(will cause the te)2.568 F .068(xt of)-.15 F
X2.183(the included \214le to appear after the \214rst tok)108 364.8 R 2.184
X(en follo)-.1 F 2.184(wing the statement block.)-.25 F 2.184
X(This is rarely what is)7.184 F(intended.)108 376.8 Q .993(In a rule')108 393.6
XR 3.492(sa)-.55 G .992
X(ctions, only $\(<\) and $\(>\) refer to the bound \214le names: all other v)
X157.908 393.6 R .992(ariable references get the)-.25 F(unbound names.)108 405.6
XQ -.4(Wi)108 422.4 S .285(th the).4 F F1(-j)2.785 E F0 .285
X(\215ag, errors from f)2.785 F .285(ailed commands can get staggeringly mix)-.1
XF .285(ed up.)-.15 F .286(Also, because tar)5.286 F .286(gets tend to)-.18 F
X.226(get b)108 434.4 R .226(uilt in a quick)-.2 F .226
X(est-\214rst ordering, dependenc)-.1 F 2.726(yi)-.15 G .226
X(nformation must be quite e)308.552 434.4 R 2.726(xact. Finally)-.15 F 2.726
X(,b)-.65 G -2.1 -.25(ew a)479.378 434.4 T .226(re of paral-).25 F
X(lelizing commands that drop \214x)108 446.4 Q
X(ed-named \214les into the current directory)-.15 E 2.5(,l)-.65 G(ik)403 446.4
XQ(e)-.1 E F1(yacc)2.5 E F0(\(1\) does.)A 2.5(Ap)108 463.2 S(oorly set $\(J)
X122.72 463.2 Q(AMSHELL\) is lik)-.6 E(ely to result in silent f)-.1 E(ailure.)
X-.1 E F2(SEE ALSO)72 492 Q F1 -.15(Ja)108 504 S(mbase).15 E F0(\(5\),)A F1 -.15
X(Ja)2.5 G(m\214le).15 E F0(\(5\))A(10 March 1995)275.45 768 Q(7)535 768 Q EP
X%%Trailer
Xend
X%%EOF
END_OF_FILE
if test 42813 -ne `wc -c <'jam.ps'`; then
echo shar: \"'jam.ps'\" unpacked with wrong size!
fi
# end of 'jam.ps'
fi
if test -f 'jamgram.y' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jamgram.y'\"
else
echo shar: Extracting \"'jamgram.y'\" \(6303 characters\)
sed "s/^X//" >'jamgram.y' <<'END_OF_FILE'
X%token _BANG
X%token _BANG_EQUALS
X%token _AMPERAMPER
X%token _LPAREN
X%token _RPAREN
X%token _PLUS_EQUALS
X%token _COLON
X%token _SEMIC
X%token _LANGLE
X%token _LANGLE_EQUALS
X%token _EQUALS
X%token _RANGLE
X%token _RANGLE_EQUALS
X%token _QUESTION_EQUALS
X%token ACTIONS
X%token CASE
X%token DEFAULT
X%token ELSE
X%token EXISTING
X%token FOR
X%token IF
X%token IGNORE
X%token IN
X%token INCLUDE
X%token ON
X%token PIECEMEAL
X%token QUIETLY
X%token RULE
X%token SWITCH
X%token TOGETHER
X%token UPDATED
X%token _LBRACE
X%token _BARBAR
X%token _RBRACE


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * jamgram.yy - jam grammar
X *
X * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
X * 06/01/94 (seiwald) - new 'actions existing' does existing sources
X * 08/23/94 (seiwald) - Support for '+=' (append to variable)
X * 08/31/94 (seiwald) - Allow ?= as alias for "default =".
X * 09/15/94 (seiwald) - if conditionals take only single arguments, so
X * that 'if foo == bar' gives syntax error (use =).
X * 02/11/95 (seiwald) - when scanning arguments to rules, only treat
X * punctuation keywords as keywords. All arg lists
X * are terminated with punctuation keywords.
X */
X
X%token ARG STRING
X
X%left _BARBAR
X%left _AMPERAMPER
X%left _BANG
X
X%{
X#include "lists.h"
X#include "parse.h"
X#include "scan.h"
X#include "compile.h"
X#include "newstr.h"
X
X# define F0 (void (*)())0
X# define P0 (PARSE *)0
X# define S0 (char *)0
X
X# define pset( l,r,a ) parse_make( compile_set,P0,P0,S0,S0,l,r,a )
X# define pset1( l,p,a ) parse_make( compile_settings,p,P0,S0,S0,l,L0,a )
X# define pstng( p,l,r,a ) pset1( p, parse_make( F0,P0,P0,S0,S0,l,r,0 ), a )
X# define prule( s,l,r ) parse_make( compile_rule,P0,P0,s,S0,l,r,0 )
X# define prules( l,r ) parse_make( compile_rules,l,r,S0,S0,L0,L0,0 )
X# define pfor( s,p,l ) parse_make( compile_foreach,p,P0,s,S0,l,L0,0 )
X# define psetc( s,p ) parse_make( compile_setcomp,p,P0,s,S0,L0,L0,0 )
X# define psete( s,s1,f ) parse_make( compile_setexec,P0,P0,s,s1,L0,L0,f )
X# define pincl( l ) parse_make( compile_include,P0,P0,S0,S0,l,L0,0 )
X# define pswitch( l,p ) parse_make( compile_switch,p,P0,S0,S0,l,L0,0 )
X# define pcases( l,r ) parse_make( F0,l,r,S0,S0,L0,L0,0 )
X# define pcase( s,p ) parse_make( F0,p,P0,s,S0,L0,L0,0 )
X# define pif( l,r ) parse_make( compile_if,l,r,S0,S0,L0,L0,0 )
X# define pthen( l,r ) parse_make( F0,l,r,S0,S0,L0,L0,0 )
X# define pcond( c,l,r ) parse_make( F0,l,r,S0,S0,L0,L0,c )
X# define pcomp( c,l,r ) parse_make( F0,P0,P0,S0,S0,l,r,c )
X
X%}
X
X%%
X
X/*
X * stmts - the contents of a JAMFILE
X */
X
Xstmts :
X {
X compile_builtins();
X }
X | stmts rule
X {
X (*($2.parse->func))( $2.parse, L0, L0 );
X parse_free( $2.parse );
X }
X ;
X
X/*
X * rules - a strings of rule's together
X * rule - any one of jam's rules
X */
X
Xrules : /* empty */
X { $$.parse = prules( P0, P0 ); }
X | rules rule
X { $$.parse = prules( $1.parse, $2.parse ); }
X ;
X
Xrule : INCLUDE args _SEMIC
X { $$.parse = pincl( $2.list ); }
X | ARG args _SEMIC
X { $$.parse = prule( $1.string, $2.list, L0 ); }
X | ARG args _COLON args _SEMIC
X { $$.parse = prule( $1.string, $2.list, $4.list ); }
X | arg1 assign args _SEMIC
X { $$.parse = pset( $1.list, $3.list, $2.number ); }
X | arg1 ON args assign args _SEMIC
X { $$.parse = pstng( $3.list, $1.list, $5.list, $4.number ); }
X | arg1 DEFAULT _EQUALS args _SEMIC
X { $$.parse = pset( $1.list, $4.list, ASSIGN_DEFAULT ); }
X | FOR ARG IN args _LBRACE rules _RBRACE
X { $$.parse = pfor( $2.string, $6.parse, $4.list ); }
X | SWITCH args _LBRACE cases _RBRACE
X { $$.parse = pswitch( $2.list, $4.parse ); }
X | IF cond _LBRACE rules _RBRACE
X { $$.parse = pif( $2.parse, pthen( $4.parse, P0 ) ); }
X | IF cond _LBRACE rules _RBRACE ELSE rule
X { $$.parse = pif( $2.parse, pthen( $4.parse, $7.parse ) ); }
X | RULE ARG rule
X { $$.parse = psetc( $2.string, $3.parse ); }
X | ACTIONS eflags ARG
X { yymode( SCAN_STRING ); }
X STRING
X { $$.parse = psete( $3.string, $5.string, $2.number );
X yymode( SCAN_NORMAL ); }
X | _LBRACE rules _RBRACE
X { $$.parse = $2.parse; }
X ;
X
X/*
X * assign - = or +=
X */
X
Xassign : _EQUALS
X { $$.number = ASSIGN_SET; }
X | _PLUS_EQUALS
X { $$.number = ASSIGN_APPEND; }
X | _QUESTION_EQUALS
X { $$.number = ASSIGN_DEFAULT; }
X ;
X
X/*
X * cond - a conditional for 'if'
X */
X
Xcond : arg1
X { $$.parse = pcomp( COND_EXISTS, $1.list, L0 ); }
X | arg1 _EQUALS arg1
X { $$.parse = pcomp( COND_EQUALS, $1.list, $3.list ); }
X | arg1 _BANG_EQUALS arg1
X { $$.parse = pcomp( COND_NOTEQ, $1.list, $3.list ); }
X | arg1 _LANGLE arg1
X { $$.parse = pcomp( COND_LESS, $1.list, $3.list ); }
X | arg1 _LANGLE_EQUALS arg1
X { $$.parse = pcomp( COND_LESSEQ, $1.list, $3.list ); }
X | arg1 _RANGLE arg1
X { $$.parse = pcomp( COND_MORE, $1.list, $3.list ); }
X | arg1 _RANGLE_EQUALS arg1
X { $$.parse = pcomp( COND_MOREEQ, $1.list, $3.list ); }
X | _BANG cond
X { $$.parse = pcond( COND_NOT, $2.parse, P0 ); }
X | cond _AMPERAMPER cond
X { $$.parse = pcond( COND_AND, $1.parse, $3.parse ); }
X | cond _BARBAR cond
X { $$.parse = pcond( COND_OR, $1.parse, $3.parse ); }
X | _LPAREN cond _RPAREN
X { $$.parse = $2.parse; }
X ;
X
X/*
X * cases - action elements inside a 'switch'
X * case - a single action element inside a 'switch'
X *
X * Unfortunately, a right-recursive rule.
X */
X
Xcases : /* empty */
X { $$.parse = P0; }
X | case cases
X { $$.parse = pcases( $1.parse, $2.parse ); }
X ;
X
Xcase : CASE ARG _COLON rules
X { $$.parse = pcase( $2.string, $4.parse ); }
X ;
X
X/*
X * args - zero or more ARGs in a LIST
X * arg1 - exactly one ARG in a LIST
X */
X
Xargs : argsany
X { yymode( SCAN_NORMAL ); }
X ;
X
Xargsany : /* empty */
X { $$.list = L0; yymode( SCAN_PUNCT ); }
X | argsany ARG
X { $$.list = list_new( $1.list, copystr( $2.string ) ); }
X ;
X
Xarg1 : ARG
X { $$.list = list_new( L0, copystr( $1.string ) ); }
X ;
X
X/*
X * eflags - zero or more modifiers to 'executes'
X * eflag - a single modifier to 'executes'
X */
X
Xeflags : /* empty */
X { $$.number = 0; }
X | eflags eflag
X { $$.number = $1.number | $2.number; }
X ;
X
Xeflag : UPDATED
X { $$.number = EXEC_UPDATED; }
X | TOGETHER
X { $$.number = EXEC_TOGETHER; }
X | IGNORE
X { $$.number = EXEC_IGNORE; }
X | QUIETLY
X { $$.number = EXEC_QUIETLY; }
X | PIECEMEAL
X { $$.number = EXEC_PIECEMEAL; }
X | EXISTING
X { $$.number = EXEC_EXISTING; }
X ;
X
END_OF_FILE
if test 6303 -ne `wc -c <'jamgram.y'`; then
echo shar: \"'jamgram.y'\" unpacked with wrong size!
fi
# end of 'jamgram.y'
fi
if test -f 'option.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'option.h'\"
else
echo shar: Extracting \"'option.h'\" \(504 characters\)
sed "s/^X//" >'option.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * option.h - command line option processing
X *
X * {o >o
X * \ -) "Command line option."
X */
X
Xtypedef struct option
X{
X char flag; /* filled in by getoption() */
X char *val; /* set to random address if true */
X} option;
X
X# define N_OPTS 10
X
Xint getoptions( /* int argc, char **argv, char *opts, option *optv */ );
Xchar *getoptval( /* option *optv, char opt, int subopt */ );
END_OF_FILE
if test 504 -ne `wc -c <'option.h'`; then
echo shar: \"'option.h'\" unpacked with wrong size!
fi
# end of 'option.h'
fi
if test -f 'regexp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'regexp.c'\"
else
echo shar: Extracting \"'regexp.c'\" \(31610 characters\)
sed "s/^X//" >'regexp.c' <<'END_OF_FILE'
X/*
X * regcomp and regexec -- regsub and regerror are elsewhere
X *
X * Copyright (c) 1986 by University of Toronto.
X * Written by Henry Spencer. Not derived from licensed software.
X *
X * Permission is granted to anyone to use this software for any
X * purpose on any computer system, and to redistribute it freely,
X * subject to the following restrictions:
X *
X * 1. The author is not responsible for the consequences of use of
X * this software, no matter how awful, even if they arise
X * from defects in it.
X *
X * 2. The origin of this software must not be misrepresented, either
X * by explicit claim or by omission.
X *
X * 3. Altered versions must be plainly marked as such, and must not
X * be misrepresented as being the original software.
X *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
X *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
X *** to assist in implementing egrep.
X *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
X *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
X *** as in BSD grep and ex.
X *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
X *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
X *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
X *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
X *** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald
X *** sei...@vix.com, on 28 August 1993, for use in jam. Regmagic.h
X *** was moved into regexp.h, and the include of regexp.h now uses "'s
X *** to avoid conflicting with the system regexp.h. Const, bless its
X *** soul, was removed so it can compile everywhere. The declaration
X *** of strchr() was in conflict on AIX, so it was removed (as it is
X *** happily defined in string.h).
X *
X * Beware that some of this code is subtly aware of the way operator
X * precedence is structured in regular expressions. Serious changes in
X * regular-expression syntax might require a total rethink.
X */
X#include "regexp.h"
X#include <stdio.h>
X#include <ctype.h>
X#ifndef ultrix
X#include <stdlib.h>
X#endif
X#include <string.h>
X
X/*
X * The "internal use only" fields in regexp.h are present to pass info from
X * compile to execute that permits the execute phase to run lots faster on
X * simple cases. They are:
X *
X * regstart char that must begin a match; '\0' if none obvious
X * reganch is the match anchored (at beginning-of-line only)?
X * regmust string (pointer into program) that match must include, or NULL
X * regmlen length of regmust string
X *
X * Regstart and reganch permit very fast decisions on suitable starting points
X * for a match, cutting down the work a lot. Regmust permits fast rejection
X * of lines that cannot possibly match. The regmust tests are costly enough
X * that regcomp() supplies a regmust only if the r.e. contains something
X * potentially expensive (at present, the only such thing detected is * or +
X * at the start of the r.e., which can involve a lot of backup). Regmlen is
X * supplied because the test in regexec() needs it and regcomp() is computing
X * it anyway.
X */
X
X/*
X * Structure for regexp "program". This is essentially a linear encoding
X * of a nondeterministic finite-state machine (aka syntax charts or
X * "railroad normal form" in parsing technology). Each node is an opcode
X * plus a "next" pointer, possibly plus an operand. "Next" pointers of
X * all nodes except BRANCH implement concatenation; a "next" pointer with
X * a BRANCH on both ends of it is connecting two alternatives. (Here we
X * have one of the subtle syntax dependencies: an individual BRANCH (as
X * opposed to a collection of them) is never concatenated with anything
X * because of operator precedence.) The operand of some types of node is
X * a literal string; for others, it is a node leading into a sub-FSM. In
X * particular, the operand of a BRANCH node is the first node of the branch.
X * (NB this is *not* a tree structure: the tail of the branch connects
X * to the thing following the set of BRANCHes.) The opcodes are:
X */
X
X/* definition number opnd? meaning */
X#define END 0 /* no End of program. */
X#define BOL 1 /* no Match "" at beginning of line. */
X#define EOL 2 /* no Match "" at end of line. */
X#define ANY 3 /* no Match any one character. */
X#define ANYOF 4 /* str Match any character in this string. */
X#define ANYBUT 5 /* str Match any character not in this string. */
X#define BRANCH 6 /* node Match this alternative, or the next... */
X#define BACK 7 /* no Match "", "next" ptr points backward. */
X#define EXACTLY 8 /* str Match this string. */
X#define NOTHING 9 /* no Match empty string. */
X#define STAR 10 /* node Match this (simple) thing 0 or more times. */
X#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
X#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */
X#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */
X#define OPEN 20 /* no Mark this point in input as start of #n. */
X /* OPEN+1 is number 1, etc. */
X#define CLOSE 30 /* no Analogous to OPEN. */
X
X/*
X * Opcode notes:
X *
X * BRANCH The set of branches constituting a single choice are hooked
X * together with their "next" pointers, since precedence prevents
X * anything being concatenated to any individual branch. The
X * "next" pointer of the last BRANCH in a choice points to the
X * thing following the whole choice. This is also where the
X * final "next" pointer of each individual branch points; each
X * branch starts with the operand node of a BRANCH node.
X *
X * BACK Normal "next" pointers all implicitly point forward; BACK
X * exists to make loop structures possible.
X *
X * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
X * BRANCH structures using BACK. Simple cases (one character
X * per match) are implemented with STAR and PLUS for speed
X * and to minimize recursive plunges.
X *
X * OPEN,CLOSE ...are numbered at compile time.
X */
X
X/*
X * A node is one char of opcode followed by two chars of "next" pointer.
X * "Next" pointers are stored as two 8-bit pieces, high order first. The
X * value is a positive offset from the opcode of the node containing it.
X * An operand, if any, simply follows the node. (Note that much of the
X * code generation knows about this implicit relationship.)
X *
X * Using two bytes for the "next" pointer is vast overkill for most things,
X * but allows patterns to get big without disasters.
X */
X#define OP(p) (*(p))
X#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
X#define OPERAND(p) ((p) + 3)
X
X/*
X * See regmagic.h for one further detail of program structure.
X */
X
X
X/*
X * Utility definitions.
X */
X#ifndef CHARBITS
X#define UCHARAT(p) ((int)*(unsigned char *)(p))
X#else
X#define UCHARAT(p) ((int)*(p)&CHARBITS)
X#endif
X
X#define FAIL(m) { regerror(m); return(NULL); }
X#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
X
X/*
X * Flags to be passed up and down.
X */
X#define HASWIDTH 01 /* Known never to match null string. */
X#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
X#define SPSTART 04 /* Starts with * or +. */
X#define WORST 0 /* Worst case. */
X
X/*
X * Global work variables for regcomp().
X */
Xstatic char *regparse; /* Input-scan pointer. */
Xstatic int regnpar; /* () count. */
Xstatic char regdummy;
Xstatic char *regcode; /* Code-emit pointer; &regdummy = don't. */
Xstatic long regsize; /* Code size. */
X
X/*
X * Forward declarations for regcomp()'s friends.
X */
X#ifndef STATIC
X#define STATIC static
X#endif
XSTATIC char *reg();
XSTATIC char *regbranch();
XSTATIC char *regpiece();
XSTATIC char *regatom();
XSTATIC char *regnode();
XSTATIC char *regnext();
XSTATIC void regc();
XSTATIC void reginsert();
XSTATIC void regtail();
XSTATIC void regoptail();
X#ifdef STRCSPN
XSTATIC int strcspn();
X#endif
X
X/*
X - regcomp - compile a regular expression into internal code
X *
X * We can't allocate space until we know how big the compiled form will be,
X * but we can't compile it (and thus know how big it is) until we've got a
X * place to put the code. So we cheat: we compile it twice, once with code
X * generation turned off and size counting turned on, and once "for real".
X * This also means that we don't allocate space until we are sure that the
X * thing really will compile successfully, and we never have to move the
X * code and thus invalidate pointers into it. (Note that it has to be in
X * one piece because free() must be able to free it all.)
X *
X * Beware that the optimization-preparation code in here knows about some
X * of the structure of the compiled regexp.
X */
Xregexp *
Xregcomp(exp)
Xchar *exp;
X{
X register regexp *r;
X register char *scan;
X register char *longest;
X register int len;
X int flags;
X
X if (exp == NULL)
X FAIL("NULL argument");
X
X /* First pass: determine size, legality. */
X#ifdef notdef
X if (exp[0] == '.' && exp[1] == '*') exp += 2; /* aid grep */
X#endif
X regparse = (char *)exp;
X regnpar = 1;
X regsize = 0L;
X regcode = &regdummy;
X regc(MAGIC);
X if (reg(0, &flags) == NULL)
X return(NULL);
X
X /* Small enough for pointer-storage convention? */
X if (regsize >= 32767L) /* Probably could be 65535L. */
X FAIL("regexp too big");
X
X /* Allocate space. */
X r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
X if (r == NULL)
X FAIL("out of space");
X
X /* Second pass: emit code. */
X regparse = (char *)exp;
X regnpar = 1;
X regcode = r->program;
X regc(MAGIC);
X if (reg(0, &flags) == NULL)
X return(NULL);
X
X /* Dig out information for optimizations. */
X r->regstart = '\0'; /* Worst-case defaults. */
X r->reganch = 0;
X r->regmust = NULL;
X r->regmlen = 0;
X scan = r->program+1; /* First BRANCH. */
X if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
X scan = OPERAND(scan);
X
X /* Starting-point info. */
X if (OP(scan) == EXACTLY)
X r->regstart = *OPERAND(scan);
X else if (OP(scan) == BOL)
X r->reganch++;
X
X /*
X * If there's something expensive in the r.e., find the
X * longest literal string that must appear and make it the
X * regmust. Resolve ties in favor of later strings, since
X * the regstart check works with the beginning of the r.e.
X * and avoiding duplication strengthens checking. Not a
X * strong reason, but sufficient in the absence of others.
X */
X if (flags&SPSTART) {
X longest = NULL;
X len = 0;
X for (; scan != NULL; scan = regnext(scan))
X if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
X longest = OPERAND(scan);
X len = strlen(OPERAND(scan));
X }
X r->regmust = longest;
X r->regmlen = len;
X }
X }
X
X return(r);
X}
X
X/*
X - reg - regular expression, i.e. main body or parenthesized thing
X *
X * Caller must absorb opening parenthesis.
X *
X * Combining parenthesis handling with the base level of regular expression
X * is a trifle forced, but the need to tie the tails of the branches to what
X * follows makes it hard to avoid.
X */
Xstatic char *
Xreg(paren, flagp)
Xint paren; /* Parenthesized? */
Xint *flagp;
X{
X register char *ret;
X register char *br;
X register char *ender;
X register int parno;
X int flags;
X
X *flagp = HASWIDTH; /* Tentatively. */
X
X /* Make an OPEN node, if parenthesized. */
X if (paren) {
X if (regnpar >= NSUBEXP)
X FAIL("too many ()");
X parno = regnpar;
X regnpar++;
X ret = regnode(OPEN+parno);
X } else
X ret = NULL;
X
X /* Pick up the branches, linking them together. */
X br = regbranch(&flags);
X if (br == NULL)
X return(NULL);
X if (ret != NULL)
X regtail(ret, br); /* OPEN -> first. */
X else
X ret = br;
X if (!(flags&HASWIDTH))
X *flagp &= ~HASWIDTH;
X *flagp |= flags&SPSTART;
X while (*regparse == '|' || *regparse == '\n') {
X regparse++;
X br = regbranch(&flags);
X if (br == NULL)
X return(NULL);
X regtail(ret, br); /* BRANCH -> BRANCH. */
X if (!(flags&HASWIDTH))
X *flagp &= ~HASWIDTH;
X *flagp |= flags&SPSTART;
X }
X
X /* Make a closing node, and hook it on the end. */
X ender = regnode((paren) ? CLOSE+parno : END);
X regtail(ret, ender);
X
X /* Hook the tails of the branches to the closing node. */
X for (br = ret; br != NULL; br = regnext(br))
X regoptail(br, ender);
X
X /* Check for proper termination. */
X if (paren && *regparse++ != ')') {
X FAIL("unmatched ()");
X } else if (!paren && *regparse != '\0') {
X if (*regparse == ')') {
X FAIL("unmatched ()");
X } else
X FAIL("junk on end"); /* "Can't happen". */
X /* NOTREACHED */
X }
X
X return(ret);
X}
X
X/*
X - regbranch - one alternative of an | operator
X *
X * Implements the concatenation operator.
X */
Xstatic char *
Xregbranch(flagp)
Xint *flagp;
X{
X register char *ret;
X register char *chain;
X register char *latest;
X int flags;
X
X *flagp = WORST; /* Tentatively. */
X
X ret = regnode(BRANCH);
X chain = NULL;
X while (*regparse != '\0' && *regparse != ')' &&
X *regparse != '\n' && *regparse != '|') {
X latest = regpiece(&flags);
X if (latest == NULL)
X return(NULL);
X *flagp |= flags&HASWIDTH;
X if (chain == NULL) /* First piece. */
X *flagp |= flags&SPSTART;
X else
X regtail(chain, latest);
X chain = latest;
X }
X if (chain == NULL) /* Loop ran zero times. */
X (void) regnode(NOTHING);
X
X return(ret);
X}
X
X/*
X - regpiece - something followed by possible [*+?]
X *
X * Note that the branching code sequences used for ? and the general cases
X * of * and + are somewhat optimized: they use the same NOTHING node as
X * both the endmarker for their branch list and the body of the last branch.
X * It might seem that this node could be dispensed with entirely, but the
X * endmarker role is not redundant.
X */
Xstatic char *
Xregpiece(flagp)
Xint *flagp;
X{
X register char *ret;
X register char op;
X register char *next;
X int flags;
X
X ret = regatom(&flags);
X if (ret == NULL)
X return(NULL);
X
X op = *regparse;
X if (!ISMULT(op)) {
X *flagp = flags;
X return(ret);
X }
X
X if (!(flags&HASWIDTH) && op != '?')
X FAIL("*+ operand could be empty");
X *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
X
X if (op == '*' && (flags&SIMPLE))
X reginsert(STAR, ret);
X else if (op == '*') {
X /* Emit x* as (x&|), where & means "self". */
X reginsert(BRANCH, ret); /* Either x */
X regoptail(ret, regnode(BACK)); /* and loop */
X regoptail(ret, ret); /* back */
X regtail(ret, regnode(BRANCH)); /* or */
X regtail(ret, regnode(NOTHING)); /* null. */
X } else if (op == '+' && (flags&SIMPLE))
X reginsert(PLUS, ret);
X else if (op == '+') {
X /* Emit x+ as x(&|), where & means "self". */
X next = regnode(BRANCH); /* Either */
X regtail(ret, next);
X regtail(regnode(BACK), ret); /* loop back */
X regtail(next, regnode(BRANCH)); /* or */
X regtail(ret, regnode(NOTHING)); /* null. */
X } else if (op == '?') {
X /* Emit x? as (x|) */
X reginsert(BRANCH, ret); /* Either x */
X regtail(ret, regnode(BRANCH)); /* or */
X next = regnode(NOTHING); /* null. */
X regtail(ret, next);
X regoptail(ret, next);
X }
X regparse++;
X if (ISMULT(*regparse))
X FAIL("nested *?+");
X
X return(ret);
X}
X
X/*
X - regatom - the lowest level
X *
X * Optimization: gobbles an entire sequence of ordinary characters so that
X * it can turn them into a single node, which is smaller to store and
X * faster to run. Backslashed characters are exceptions, each becoming a
X * separate node; the code is simpler that way and it's not worth fixing.
X */
Xstatic char *
Xregatom(flagp)
Xint *flagp;
X{
X register char *ret;
X int flags;
X
X *flagp = WORST; /* Tentatively. */
X
X switch (*regparse++) {
X /* FIXME: these chars only have meaning at beg/end of pat? */
X case '^':
X ret = regnode(BOL);
X break;
X case '$':
X ret = regnode(EOL);
X break;
X case '.':
X ret = regnode(ANY);
X *flagp |= HASWIDTH|SIMPLE;
X break;
X case '[': {
X register int class;
X register int classend;
X
X if (*regparse == '^') { /* Complement of range. */
X ret = regnode(ANYBUT);
X regparse++;
X } else
X ret = regnode(ANYOF);
X if (*regparse == ']' || *regparse == '-')
X regc(*regparse++);
X while (*regparse != '\0' && *regparse != ']') {
X if (*regparse == '-') {
X regparse++;
X if (*regparse == ']' || *regparse == '\0')
X regc('-');
X else {
X class = UCHARAT(regparse-2)+1;
X classend = UCHARAT(regparse);
X if (class > classend+1)
X FAIL("invalid [] range");
X for (; class <= classend; class++)
X regc(class);
X regparse++;
X }
X } else
X regc(*regparse++);
X }
X regc('\0');
X if (*regparse != ']')
X FAIL("unmatched []");
X regparse++;
X *flagp |= HASWIDTH|SIMPLE;
X }
X break;
X case '(':
X ret = reg(1, &flags);
X if (ret == NULL)
X return(NULL);
X *flagp |= flags&(HASWIDTH|SPSTART);
X break;
X case '\0':
X case '|':
X case '\n':
X case ')':
X FAIL("internal urp"); /* Supposed to be caught earlier. */
X break;
X case '?':
X case '+':
X case '*':
X FAIL("?+* follows nothing");
X break;
X case '\\':
X switch (*regparse++) {
X case '\0':
X FAIL("trailing \\");
X break;
X case '<':
X ret = regnode(WORDA);
X break;
X case '>':
X ret = regnode(WORDZ);
X break;
X /* FIXME: Someday handle \1, \2, ... */
X default:
X /* Handle general quoted chars in exact-match routine */
X goto de_fault;
X }
X break;
X de_fault:
X default:
X /*
X * Encode a string of characters to be matched exactly.
X *
X * This is a bit tricky due to quoted chars and due to
X * '*', '+', and '?' taking the SINGLE char previous
X * as their operand.
X *
X * On entry, the char at regparse[-1] is going to go
X * into the string, no matter what it is. (It could be
X * following a \ if we are entered from the '\' case.)
X *
X * Basic idea is to pick up a good char in ch and
X * examine the next char. If it's *+? then we twiddle.
X * If it's \ then we frozzle. If it's other magic char
X * we push ch and terminate the string. If none of the
X * above, we push ch on the string and go around again.
X *
X * regprev is used to remember where "the current char"
X * starts in the string, if due to a *+? we need to back
X * up and put the current char in a separate, 1-char, string.
X * When regprev is NULL, ch is the only char in the
X * string; this is used in *+? handling, and in setting
X * flags |= SIMPLE at the end.
X */
X {
X char *regprev;
X register char ch;
X
X regparse--; /* Look at cur char */
X ret = regnode(EXACTLY);
X for ( regprev = 0 ; ; ) {
X ch = *regparse++; /* Get current char */
X switch (*regparse) { /* look at next one */
X
X default:
X regc(ch); /* Add cur to string */
X break;
X
X case '.': case '[': case '(':
X case ')': case '|': case '\n':
X case '$': case '^':
X case '\0':
X /* FIXME, $ and ^ should not always be magic */
X magic:
X regc(ch); /* dump cur char */
X goto done; /* and we are done */
X
X case '?': case '+': case '*':
X if (!regprev) /* If just ch in str, */
X goto magic; /* use it */
X /* End mult-char string one early */
X regparse = regprev; /* Back up parse */
X goto done;
X
X case '\\':
X regc(ch); /* Cur char OK */
X switch (regparse[1]){ /* Look after \ */
X case '\0':
X case '<':
X case '>':
X /* FIXME: Someday handle \1, \2, ... */
X goto done; /* Not quoted */
X default:
X /* Backup point is \, scan * point is after it. */
X regprev = regparse;
X regparse++;
X continue; /* NOT break; */
X }
X }
X regprev = regparse; /* Set backup point */
X }
X done:
X regc('\0');
X *flagp |= HASWIDTH;
X if (!regprev) /* One char? */
X *flagp |= SIMPLE;
X }
X break;
X }
X
X return(ret);
X}
X
X/*
X - regnode - emit a node
X */
Xstatic char * /* Location. */
Xregnode(op)
Xchar op;
X{
X register char *ret;
X register char *ptr;
X
X ret = regcode;
X if (ret == &regdummy) {
X regsize += 3;
X return(ret);
X }
X
X ptr = ret;
X *ptr++ = op;
X *ptr++ = '\0'; /* Null "next" pointer. */
X *ptr++ = '\0';
X regcode = ptr;
X
X return(ret);
X}
X
X/*
X - regc - emit (if appropriate) a byte of code
X */
Xstatic void
Xregc(b)
Xchar b;
X{
X if (regcode != &regdummy)
X *regcode++ = b;
X else
X regsize++;
X}
X
X/*
X - reginsert - insert an operator in front of already-emitted operand
X *
X * Means relocating the operand.
X */
Xstatic void
Xreginsert(op, opnd)
Xchar op;
Xchar *opnd;
X{
X register char *src;
X register char *dst;
X register char *place;
X
X if (regcode == &regdummy) {
X regsize += 3;
X return;
X }
X
X src = regcode;
X regcode += 3;
X dst = regcode;
X while (src > opnd)
X *--dst = *--src;
X
X place = opnd; /* Op node, where operand used to be. */
X *place++ = op;
X *place++ = '\0';
X *place++ = '\0';
X}
X
X/*
X - regtail - set the next-pointer at the end of a node chain
X */
Xstatic void
Xregtail(p, val)
Xchar *p;
Xchar *val;
X{
X register char *scan;
X register char *temp;
X register int offset;
X
X if (p == &regdummy)
X return;
X
X /* Find last node. */
X scan = p;
X for (;;) {
X temp = regnext(scan);
X if (temp == NULL)
X break;
X scan = temp;
X }
X
X if (OP(scan) == BACK)
X offset = scan - val;
X else
X offset = val - scan;
X *(scan+1) = (offset>>8)&0377;
X *(scan+2) = offset&0377;
X}
X
X/*
X - regoptail - regtail on operand of first argument; nop if operandless
X */
Xstatic void
Xregoptail(p, val)
Xchar *p;
Xchar *val;
X{
X /* "Operandless" and "op != BRANCH" are synonymous in practice. */
X if (p == NULL || p == &regdummy || OP(p) != BRANCH)
X return;
X regtail(OPERAND(p), val);
X}
X
X/*
X * regexec and friends
X */
X
X/*
X * Global work variables for regexec().
X */
Xstatic char *reginput; /* String-input pointer. */
Xstatic char *regbol; /* Beginning of input, for ^ check. */
Xstatic char **regstartp; /* Pointer to startp array. */
Xstatic char **regendp; /* Ditto for endp. */
X
X/*
X * Forwards.
X */
XSTATIC int regtry();
XSTATIC int regmatch();
XSTATIC int regrepeat();
X
X#ifdef DEBUG
Xint regnarrate = 0;
Xvoid regdump();
XSTATIC char *regprop();
X#endif
X
X/*
X - regexec - match a regexp against a string
X */
Xint
Xregexec(prog, string)
Xregister regexp *prog;
Xregister char *string;
X{
X register char *s;
X
X /* Be paranoid... */
X if (prog == NULL || string == NULL) {
X regerror("NULL parameter");
X return(0);
X }
X
X /* Check validity of program. */
X if (UCHARAT(prog->program) != MAGIC) {
X regerror("corrupted program");
X return(0);
X }
X
X /* If there is a "must appear" string, look for it. */
X if (prog->regmust != NULL) {
X s = (char *)string;
X while ((s = strchr(s, prog->regmust[0])) != NULL) {
X if (strncmp(s, prog->regmust, prog->regmlen) == 0)
X break; /* Found it. */
X s++;
X }
X if (s == NULL) /* Not present. */
X return(0);
X }
X
X /* Mark beginning of line for ^ . */
X regbol = (char *)string;
X
X /* Simplest case: anchored match need be tried only once. */
X if (prog->reganch)
X return(regtry(prog, string));
X
X /* Messy cases: unanchored match. */
X s = (char *)string;
X if (prog->regstart != '\0')
X /* We know what char it must start with. */
X while ((s = strchr(s, prog->regstart)) != NULL) {
X if (regtry(prog, s))
X return(1);
X s++;
X }
X else
X /* We don't -- general case. */
X do {
X if (regtry(prog, s))
X return(1);
X } while (*s++ != '\0');
X
X /* Failure. */
X return(0);
X}
X
X/*
X - regtry - try match at specific point
X */
Xstatic int /* 0 failure, 1 success */
Xregtry(prog, string)
Xregexp *prog;
Xchar *string;
X{
X register int i;
X register char **sp;
X register char **ep;
X
X reginput = string;
X regstartp = prog->startp;
X regendp = prog->endp;
X
X sp = prog->startp;
X ep = prog->endp;
X for (i = NSUBEXP; i > 0; i--) {
X *sp++ = NULL;
X *ep++ = NULL;
X }
X if (regmatch(prog->program + 1)) {
X prog->startp[0] = string;
X prog->endp[0] = reginput;
X return(1);
X } else
X return(0);
X}
X
X/*
X - regmatch - main matching routine
X *
X * Conceptually the strategy is simple: check to see whether the current
X * node matches, call self recursively to see whether the rest matches,
X * and then act accordingly. In practice we make some effort to avoid
X * recursion, in particular by going through "ordinary" nodes (that don't
X * need to know whether the rest of the match failed) by a loop instead of
X * by recursion.
X */
Xstatic int /* 0 failure, 1 success */
Xregmatch(prog)
Xchar *prog;
X{
X register char *scan; /* Current node. */
X char *next; /* Next node. */
X
X scan = prog;
X#ifdef DEBUG
X if (scan != NULL && regnarrate)
X fprintf(stderr, "%s(\n", regprop(scan));
X#endif
X while (scan != NULL) {
X#ifdef DEBUG
X if (regnarrate)
X fprintf(stderr, "%s...\n", regprop(scan));
X#endif
X next = regnext(scan);
X
X switch (OP(scan)) {
X case BOL:
X if (reginput != regbol)
X return(0);
X break;
X case EOL:
X if (*reginput != '\0')
X return(0);
X break;
X case WORDA:
X /* Must be looking at a letter, digit, or _ */
X if ((!isalnum(*reginput)) && *reginput != '_')
X return(0);
X /* Prev must be BOL or nonword */
X if (reginput > regbol &&
X (isalnum(reginput[-1]) || reginput[-1] == '_'))
X return(0);
X break;
X case WORDZ:
X /* Must be looking at non letter, digit, or _ */
X if (isalnum(*reginput) || *reginput == '_')
X return(0);
X /* We don't care what the previous char was */
X break;
X case ANY:
X if (*reginput == '\0')
X return(0);
X reginput++;
X break;
X case EXACTLY: {
X register int len;
X register char *opnd;
X
X opnd = OPERAND(scan);
X /* Inline the first character, for speed. */
X if (*opnd != *reginput)
X return(0);
X len = strlen(opnd);
X if (len > 1 && strncmp(opnd, reginput, len) != 0)
X return(0);
X reginput += len;
X }
X break;
X case ANYOF:
X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
X return(0);
X reginput++;
X break;
X case ANYBUT:
X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
X return(0);
X reginput++;
X break;
X case NOTHING:
X break;
X case BACK:
X break;
X case OPEN+1:
X case OPEN+2:
X case OPEN+3:
X case OPEN+4:
X case OPEN+5:
X case OPEN+6:
X case OPEN+7:
X case OPEN+8:
X case OPEN+9: {
X register int no;
X register char *save;
X
X no = OP(scan) - OPEN;
X save = reginput;
X
X if (regmatch(next)) {
X /*
X * Don't set startp if some later
X * invocation of the same parentheses
X * already has.
X */
X if (regstartp[no] == NULL)
X regstartp[no] = save;
X return(1);
X } else
X return(0);
X }
X break;
X case CLOSE+1:
X case CLOSE+2:
X case CLOSE+3:
X case CLOSE+4:
X case CLOSE+5:
X case CLOSE+6:
X case CLOSE+7:
X case CLOSE+8:
X case CLOSE+9: {
X register int no;
X register char *save;
X
X no = OP(scan) - CLOSE;
X save = reginput;
X
X if (regmatch(next)) {
X /*
X * Don't set endp if some later
X * invocation of the same parentheses
X * already has.
X */
X if (regendp[no] == NULL)
X regendp[no] = save;
X return(1);
X } else
X return(0);
X }
X break;
X case BRANCH: {
X register char *save;
X
X if (OP(next) != BRANCH) /* No choice. */
X next = OPERAND(scan); /* Avoid recursion. */
X else {
X do {
X save = reginput;
X if (regmatch(OPERAND(scan)))
X return(1);
X reginput = save;
X scan = regnext(scan);
X } while (scan != NULL && OP(scan) == BRANCH);
X return(0);
X /* NOTREACHED */
X }
X }
X break;
X case STAR:
X case PLUS: {
X register char nextch;
X register int no;
X register char *save;
X register int min;
X
X /*
X * Lookahead to avoid useless match attempts
X * when we know what character comes next.
X */
X nextch = '\0';
X if (OP(next) == EXACTLY)
X nextch = *OPERAND(next);
X min = (OP(scan) == STAR) ? 0 : 1;
X save = reginput;
X no = regrepeat(OPERAND(scan));
X while (no >= min) {
X /* If it could work, try it. */
X if (nextch == '\0' || *reginput == nextch)
X if (regmatch(next))
X return(1);
X /* Couldn't or didn't -- back up. */
X no--;
X reginput = save + no;
X }
X return(0);
X }
X break;
X case END:
X return(1); /* Success! */
X break;
X default:
X regerror("memory corruption");
X return(0);
X break;
X }
X
X scan = next;
X }
X
X /*
X * We get here only if there's trouble -- normally "case END" is
X * the terminating point.
X */
X regerror("corrupted pointers");
X return(0);
X}
X
X/*
X - regrepeat - repeatedly match something simple, report how many
X */
Xstatic int
Xregrepeat(p)
Xchar *p;
X{
X register int count = 0;
X register char *scan;
X register char *opnd;
X
X scan = reginput;
X opnd = OPERAND(p);
X switch (OP(p)) {
X case ANY:
X count = strlen(scan);
X scan += count;
X break;
X case EXACTLY:
X while (*opnd == *scan) {
X count++;
X scan++;
X }
X break;
X case ANYOF:
X while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
X count++;
X scan++;
X }
X break;
X case ANYBUT:
X while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
X count++;
X scan++;
X }
X break;
X default: /* Oh dear. Called inappropriately. */
X regerror("internal foulup");
X count = 0; /* Best compromise. */
X break;
X }
X reginput = scan;
X
X return(count);
X}
X
X/*
X - regnext - dig the "next" pointer out of a node
X */
Xstatic char *
Xregnext(p)
Xregister char *p;
X{
X register int offset;
X
X if (p == &regdummy)
X return(NULL);
X
X offset = NEXT(p);
X if (offset == 0)
X return(NULL);
X
X if (OP(p) == BACK)
X return(p-offset);
X else
X return(p+offset);
X}
X
X#ifdef DEBUG
X
XSTATIC char *regprop();
X
X/*
X - regdump - dump a regexp onto stdout in vaguely comprehensible form
X */
Xvoid
Xregdump(r)
Xregexp *r;
X{
X register char *s;
X register char op = EXACTLY; /* Arbitrary non-END op. */
X register char *next;
X
X
X s = r->program + 1;
X while (op != END) { /* While that wasn't END last time... */
X op = OP(s);
X printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
X next = regnext(s);
X if (next == NULL) /* Next ptr. */
X printf("(0)");
X else
X printf("(%d)", (s-r->program)+(next-s));
X s += 3;
X if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
X /* Literal string, where present. */
X while (*s != '\0') {
X putchar(*s);
X s++;
X }
X s++;
X }
X putchar('\n');
X }
X
X /* Header fields of interest. */
X if (r->regstart != '\0')
X printf("start `%c' ", r->regstart);
X if (r->reganch)
X printf("anchored ");
X if (r->regmust != NULL)
X printf("must have \"%s\"", r->regmust);
X printf("\n");
X}
X
X/*
X - regprop - printable representation of opcode
X */
Xstatic char *
Xregprop(op)
Xchar *op;
X{
X register char *p;
X static char buf[50];
X
X (void) strcpy(buf, ":");
X
X switch (OP(op)) {
X case BOL:
X p = "BOL";
X break;
X case EOL:
X p = "EOL";
X break;
X case ANY:
X p = "ANY";
X break;
X case ANYOF:
X p = "ANYOF";
X break;
X case ANYBUT:
X p = "ANYBUT";
X break;
X case BRANCH:
X p = "BRANCH";
X break;
X case EXACTLY:
X p = "EXACTLY";
X break;
X case NOTHING:
X p = "NOTHING";
X break;
X case BACK:
X p = "BACK";
X break;
X case END:
X p = "END";
X break;
X case OPEN+1:
X case OPEN+2:
X case OPEN+3:
X case OPEN+4:
X case OPEN+5:
X case OPEN+6:
X case OPEN+7:
X case OPEN+8:
X case OPEN+9:
X sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
X p = NULL;
X break;
X case CLOSE+1:
X case CLOSE+2:
X case CLOSE+3:
X case CLOSE+4:
X case CLOSE+5:
X case CLOSE+6:
X case CLOSE+7:
X case CLOSE+8:
X case CLOSE+9:
X sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
X p = NULL;
X break;
X case STAR:
X p = "STAR";
X break;
X case PLUS:
X p = "PLUS";
X break;
X case WORDA:
X p = "WORDA";
X break;
X case WORDZ:
X p = "WORDZ";
X break;
X default:
X regerror("corrupted opcode");
X break;
X }
X if (p != NULL)
X (void) strcat(buf, p);
X return(buf);
X}
X#endif
X
X/*
X * The following is provided for those people who do not have strcspn() in
X * their C libraries. They should get off their butts and do something
X * about it; at least one public-domain implementation of those (highly
X * useful) string routines has been published on Usenet.
X */
X#ifdef STRCSPN
X/*
X * strcspn - find length of initial segment of s1 consisting entirely
X * of characters not from s2
X */
X
Xstatic int
Xstrcspn(s1, s2)
Xchar *s1;
Xchar *s2;
X{
X register char *scan1;
X register char *scan2;
X register int count;
X
X count = 0;
X for (scan1 = s1; *scan1 != '\0'; scan1++) {
X for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
X if (*scan1 == *scan2++)
X return(count);
X count++;
X }
X return(count);
X}
X#endif
END_OF_FILE
if test 31610 -ne `wc -c <'regexp.c'`; then
echo shar: \"'regexp.c'\" unpacked with wrong size!
fi
# end of 'regexp.c'
fi
echo shar: End of archive 3 \(of 7\).
cp /dev/null ark3isdone

Christopher Seiwald

unread,
Apr 11, 1995, 3:00:00 AM4/11/95
to
Submitted-by: sei...@tea.org (Christopher Seiwald)
Posting-number: Volume 47, Issue 111
Archive-name: jam/part04

Environment: UNIX, NT, VMS
Supersedes: jam: Volume 27, Issue 81-85

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".

# Contents: Jambase.5 Jambase.ps Jamfile.5 variable.h


# Wrapped by kent@ftp on Sat Mar 25 12:04:10 1995
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 4 (of 7)."'
if test -f 'Jambase.5' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Jambase.5'\"
else
echo shar: Extracting \"'Jambase.5'\" \(11960 characters\)
sed "s/^X//" >'Jambase.5' <<'END_OF_FILE'
X.TH JAMBASE 5 "10 March 1995"
X.SH NAME
X\fBJambase\fR \- \fBjam\fR(1) boilerplate
X.SH FILES
X\fB/usr/local/lib/Jambase\fR
X.br
X\fBJamfile\fR
X
X.SH DESCRIPTION
X.PP
X\fBJambase\fR contains a set of \fBjam\fR rule definitions that provide
Xroughly \fBmake\fR(1)-like functionality. \fBJam\fR reads
X\fBJambase\fR, which in turn includes the \fBJamfile\fR from the
Xcurrent directory.
X.PP
XThis manual page lists the rules and variables defined in
X\fBJambase\fR. For a more readable guide to writing a \fBJamfile\fR,
Xsee \fBJamfile\fR(5).
X.SS Rules
X.de RP
X.IP "\fI\\$1\fR \\$2"
X.IP
X..
X.RP As "obj.o : source.s ;"
XAssemble the file \fIsource.s\fR. Called by the \fIObject\fR rule.
X.RP Bulk "directory : sources ;"
XCopies \fIsources\fR into \fIdirectory\fR. Dependencies of \fIfiles\fR.
X.RP Cc "object : source ;"
XCompile the file \fIsource\fR into \fIobject\fR, using the C compiler
X$(CC), its flags $(CCFLAGS) and $(OPTIM), and the header file
Xdirectories $(HDRS). Called by the \fIObject\fR rule.
X.RP C++ "obj.o : source.cc ;"
XCompile the C++ source file \fIsource.cc\fR. Called by the
X\fIObject\fR rule.
X.RP Clean "clean : targets ;"
XRemoves existing \fItargets\fR when \fIclean\fR is built. \fIclean\fR
Xis not a dependency of \fIall\fR, and must be built explicitly for
X\fItargets\fR to be removed.
X.RP File "target : source ;"
XCopies \fIsource\fR into \fItarget\fR. Dependency of \fIfiles\fR.
X.RP Fortran "obj.o : source.f ;"
XCompile the Fortran source file \fIsource.f\fR. Called by the
X\fIObject\fR rule.
X.RP HardLink "target : source ;"
XMakes \fItarget\fR a hard link to \fIsource\fR, if it isn't one
Xalready.
X.RP HdrRule "source : headers ;"
XArranges the proper dependencies when the file \fIsource\fR includes
Xthe files \fIheaders\fR through the "#include" C preprocessor
Xdirective. The \fIObject\fR rule arranges for this rule to be called
Xwhen \fBjam\fR does its header file scan of \fIsource\fR.
X.RP Install "target : source ;"
XCopies \fIsource\fR into \fItarget\fR, using \fIinstall\fR(1). Used by
Xthe other \fIInstall\fR* rules.
X.RP InstallBin "dir : sources ; "
XCopy \fIsources\fR into \fIdir\fR with mode $(EXEMODE). Dependencies of
X\fIinstall\fR.
X.RP InstallLib "dir : sources ;"
XCopy \fIsources\fR into \fIdir\fR with mode $(FILEMODE). Dependencies of
X\fIinstall\fR.
X.RP InstallMan "dir : sources ;"
XCopy \fIsources\fR into the appropriate subdirectory of \fIdir\fR with
Xmode $(FILEMODE). The subdirectory is \fBman\fIs\fR, where \fIs\fR
Xis the suffix of each of \fIsources\fR. Dependencies of \fIinstall\fR.
X.RP InstallShell "dir : sources ;"
XCopy \fIsources\fR into \fIdir\fR with mode $(SHELLMODE). Dependencies
Xof \fIinstall\fR.
X.RP Lex "source.c : source.l ;"
XProcess the \fBlex\fR(1) source file \fIsource.l\fR and rename the
Xlex.yy.c to \fIsource.c\fR. Called by the \fIObject\fR rule.
X.RP Library "library : sources ;"
XCompiles \fIsources\fR and archives them into \fIlibrary\fR. The
Xintermediate objects are deleted. Calls \fIObjects\fR and
X\fILibraryFromObjects\fR. Dependency of \fIlib\fR.
X.RP LibraryFromObjects "library : objects ;"
XArchives \fIobjects\fR into \fIlibrary\fR. The \fIobjects\fR are then
Xdeleted. Dependency of \fIlib\fR.
X.RP LinkLibraries "image : libraries ;"
XMakes \fIimage\fR depend on \fIlibraries\fR and includes them during
Xthe linking.
X.RP Main "image : sources ;"
XCompiles \fIsources\fR and links them into \fIimage\fR. Calls
X\fIObjects\fR and \fIMainFromObjects\fR. Dependency of \fIexe\fR.
X.RP MainFromObjects "image : objects ;"
XLinks \fIobjects\fR into \fIimage\fR. Dependency of \fIexe\fR.
X.RP Object "object : source ;"
XCompiles a single source file \fIsource\fR into \fIobject\fR. Makes
X\fIobject\fR depend on all header files included by \fIsource\fR. Such
Xdependencies are "soft": missing headers are not an error.
X.IP
XCalls one of the rules listed to do the actual compiling, depending
Xon the suffix of \fIsource\fR:
X.RS
X.IP
Xsource.c: \fICc\fR
X.br
Xsource.cc: \fIC++\fR
X.br
Xsource.cpp: \fIC++\fR
X.br
Xsource.C: \fIC++\fR
X.br
Xsource.l: \fILex\fR
X.br
Xsource.y: \fIYacc\fR
X.br
Xsource.*: \fIUserObject\fR
X.RE
X.IP
XThis rule is used by \fBObjects\fR.
X.RP ObjectCcFlags "source : flags ;"
XAdd \fIflags\fR to the \fIsource\fR-specific value of $(CCFLAGS) when
Xcompiling \fIsource\fR. Any file suffix on \fIsource\fR is ignored.
X.RP ObjectHdrs "source : dirs ;"
XAdd \fIdirs\fR to the \fIsource\fR-specific value of $(HDRS) when
Xscanning and compiling \fIsource\fR. Any file suffix on \fIsource\fR
Xis ignored.
X.RP Objects "sources ;"
XFor each source file in \fIsources\fR,
Xcalls \fIObject\fR to compile the source file into a similarly named
Xobject file.
X.RP RmTemps "targets : sources ;"
XMarks \fIsources\fR as temporary with the \fBTEMPORARY\fR rule, and
Xdeletes \fIsources\fR once \fItargets\fR are built. Must be the last
Xrule invoked on \fItargets\fR. Used internally by \fBObject\fR.
X.RP Setuid "images ;"
XSets the setuid bit on each of \fIimages\fR after linking.
X.RP Shell "image : source ;"
XCopies \fIsource\fR into the executable \fBsh\fR(1) script \fIimage\fR.
XEnsures that the first line of the script is $(SHELLHEADER) (default
X\fI#!/bin/sh\fR). Dependency of \fIshell\fR.
X.RP Undefines "images : symbols ;"
XTries to convince the linker that symbols need to be "undefined" for
Xthe linking of \fIimages\fR.
X.RP UserObject "object : source ;"
XComplains that the suffix on \fIsource\fR is unknown. This rule is called
Xby \fIObject\fR for source files with unknown suffixes, and should be replaced
Xwith a user-provided rule to handle the source file types.
X.RP Yacc "source.c : source.y ;"
XProcess the \fByacc\fR(1) file \fIsource.y\fR and renamed the resulting
Xy.tab.c and y.tab.h to \fIsource.c\fR. Produces a y.tab.h and renames it
Xto \fIsource\fR.h. Called by the \fIObject\fR rule.
X.SS Variables
X.PP
XThese variables are set in \fBJambase\fR only if they are not set in the
Xuser's environment, and so can be overridden with environment settings.
XMost variables are used by the actions of the related rules. When the
Xvariable is used by a rule's procedure (and therefore must be set before
Xinvoking the rule), it is marked with a \(bu.
X.PP
XAR (default \fI"ar ru"\fR)
X.IP
XThe archiver used for \fBLibrary\fR.
X.PP
XAS (default \fIas\fR)
X.IP
XThe assembler for \fBAs\fR.
X.PP
XASFLAGS (no default)
X.IP
XFlags handed to the assembler for \fBAs\fR.
X.PP
XAWK (\fIawk\fR)
X.IP
XThe name of awk interpreter, used when copying a shell script for
Xthe \fIShell\fR rule.
X.PP
XBINDIR (default \fI/usr/local/bin\fR)
X.IP
XNot used. Set for convenience.
X.PP
XCC (default \fIcc\fR)
X.IP
XC compiler used for \fBCc\fR.
X.PP
XCCFLAGS (no default) \(bu
X.IP
XFlags handed to the C compiler for \fBObject\fR. \fBOPTIM\fR is also
Xhanded to the C compiler.
X.PP
XC++ (default \fIgcc\fR)
X.IP
XC++ compiler used for \fBC++\fR.
X.PP
XC++FLAGS (no default) \(bu
X.IP
XFlags handed to the C++ compiler for \fBC++\fR. \fBOPTIM\fR is also
Xhanded to the C++ compiler.
X.PP
XCP (default \fIcp\fR)
X.IP
XThe file copy program, used by \fIFile\fR and \fIInstall\fR.
X.PP
XEXEMODE (default \fI711\fR)
X.IP
XPermissions for executables linked with \fBMain\fR.
X.PP
XFILEMODE (default \fI644\fR) \(bu
X.IP
XPermissions for files copied by \fBFile\fR or \fBBulk\fR.
X.PP
XFORTRAN (default \fIf77\fR)
X.IP
XThe Fortran compiler used by \fBFortran\fR.
X.PP
XFORTRANFLAGS (no default)
X.IP
XFlags handed to the Fortran compiler for \fBFortran\fR.
X.PP
XGROUP (no default)
X.IP
XThe group owner of installed filed. Used by \fIInstall\fR.
X.PP
XHDRPATTERN (default ^#[\\t ]*include[\\t ]*[<"](.*)[">].*$) \(bu
X.IP
XThe \fBregexp\fR(3) pattern for finding header file includes in source
Xfiles. The \fBObject\fR rule sets the \fBjam\fR-special variable
X\fBHDRSCAN\fR to $(HDRPATTERN) for all of its sources. The
Xcorresponding target of the \fBObject\fR rule invocation depends on all
Xheader files found.
X.PP
XHDRRULE (default HdrRule)
X.IP
XThe rule to invoke with the results of header file scanning.
XThis is a \fBjam\fR-special variable.
X.PP
XHDRSCAN (default $(HDRPATTERN))
X.IP
XThe \fBregexp\fR(3) pattern for header file scanning. This variable
Xand $(HDRRULE) trigger the scanning. This is a \fBjam\fR-special
Xvariable.
X.PP
XHDRS (no default) \(bu
X.IP
XDirectories to be scanned for header files and handed to the C compiler
Xwith -I. The \fBObject\fR rule sets \fBHDRS\fR to $(HDRS) for each of
Xits sources.
X.PP
XINSTALL (default \fIinstall\fR)
X.IP
XThe file copying program for the \fIInstall\fR rule. If not set
X\fIInstall\fR uses $(CP).
X.PP
XJAMFILE (default \fIJamfile\fR)
X.IP
XThe user-provided file listing the sources to be built.
X.PP
XJAMRULES (default \fIJamrules\fR)
X.IP
XThe name of the file included by the \fISubDir\fR rule.
X.PP
XLEX (default \fIlex\fR )
X.IP
XThe \fBlex\fR(1) command and flags.
X.PP
XLIBDIR (default \fI/usr/local/lib\fR)
X.IP
XNot used. Set for convenience.
X.PP
XLINK (default \fIcc\fR)
X.IP
XThe linker.
X.PP
XLINKFLAGS (default $(CCFLAGS))
X.IP
XFlags handed to the linker.
X.PP
XLINKLIBS (no default)
X.IP
XLibraries to hand to the linker. The target image does not depend on
Xthese libraries.
X.PP
XLOCATE_TARGET (no default) \(bu
X.IP
XThe directory for object modules and other intermediate files generated
Xby \fBObject\fR. This works by setting the \fBjam\fR-special variable
X\fBLOCATE\fR to the value of $(LOCATE_TARGET) for each of
X\fBObject\fR's targets.
X.PP
XLN (default \fIln\fR)
X.IP
XThe hard link command for \fIHardLink\fR.
X.PP
XMANDIR (default \fI/usr/local/man\fR)
X.IP
XNot used. Set for convenience.
X.PP
XMKDIR (default \fImkdir\fR)
X.IP
XThe program to create directories for the \fIMkDir\fR rule.
X.PP
XMODE (default varies)
X.IP
XThe file mode for files installed with \fIInstall\fR. Is set to
X$(EXEMODE), $(FILEMODE), or $(SHELLMODE) depending which rule invoked
X\fIInstall\fR.
X.PP
XMV (default \fImv -f\fR)
X.IP
XThe file rename command and options.
X.PP
XOPTIM (default \fI-O\fR)
X.IP
XMore flags handed to the C compiler.
X.PP
XOWNER (no default)
X.IP
XThe owner of installed filed. Used by \fIInstall\fR.
X.PP
XRANLIB (default \fIranlib\fR) \(bu
X.IP
XIf set, the command string to be invoked on each library after
Xarchiving.
X.PP
XRELOCATE (default unset)
X.IP
XIf set, tells the \fICc\fR rule to move the output object file to
Xits target directory because the cc command has a broken -o option.
X.PP
XRM (default \fIrm -f\fR)
X.IP
XThe command and options to remove a file.
X.PP
XSEARCH_SOURCE (no default) \(bu
X.IP
XThe directory to find sources listed with \fBMain\fR, \fBLibrary\fR,
X\fBObject\fR, \fBBulk\fR, \fBFile\fR, \fBShell\fR, \fBInstallBin\fR,
X\fBInstallLib\fR, and \fBInstallMan\fR rules. This works by setting
Xthe \fBjam\fR-special variable \fBSEARCH\fR to the value of
X$(SEARCH_SOURCE) for each of the rules' sources.
X.PP
XSHELLHEADER (default \fI#!/bin/sh\fR)
X.IP
XA string inserted to the first line of every file created by the
X\fBShell\fR rule.
X.PP
XSHELLMODE (default \fI755\fR) \(bu
X.IP
XPermissions for files installed by \fBShell\fR.
X.PP
XSLASH (default \fI/\fR) \(bu
X.IP
XThe directory separator. Used by \fISubDir\fR and \fISubInclude\fR
Xto build up a directory path.
X.PP
XSOURCE_GRIST (no default) \(bu
X.IP
XSet by the \fISubDir\fR to a value derived from the directory name, and
Xused by \fIObjects\fR and related rules as 'grist' to perturb file names.
X.PP
XSTDHDRS (default \fI/usr/include\fR) \(bu
X.IP
XDirectories where headers can be found without resorting to using the
X\fIflag\fR to the C compiler.
X.PP
XSUBDIR (no default)
X.IP
XSet by \fISubDir\fR to be the named directory.
X.PP
XSUFEXE (default "") \(bu
X.IP
XThe suffix for executable files, if none provided. Used by the
X\fIMain\fR rule.
X.PP
XSUFLIB (default \fI.a\fR) \(bu
X.IP
XThe suffix for libraries. Used by the \fILibrary\fR and related rules.
X.PP
XSUFOBJ (default \fI.o\fR) \(bu
X.IP
XThe suffix for object files. Used by the \fIObjects\fR and related rules.
X.PP
XUNDEFFLAG (default \fI-u _\fR)
X.IP
XThe flag prefixed to each symbol for the \fBUndefines\fR rule.
X.PP
XYACC (default \fIyacc -d\fR)
X.IP
XThe \fByacc\fR(1) command and flags.
X
X.SH SEE ALSO
X\fBjam\fR(1), \fBJamfile\fR(5)
END_OF_FILE
if test 11960 -ne `wc -c <'Jambase.5'`; then
echo shar: \"'Jambase.5'\" unpacked with wrong size!
fi
# end of 'Jambase.5'
fi
if test -f 'Jambase.ps' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Jambase.ps'\"
else
echo shar: Extracting \"'Jambase.ps'\" \(28776 characters\)
sed "s/^X//" >'Jambase.ps' <<'END_OF_FILE'


X%!PS-Adobe-3.0
X%%Creator: groff version 1.08

X%%DocumentNeededResources: font Times-Roman
X%%+ font Times-Bold
X%%+ font Times-Italic

X%%DocumentSuppliedResources: procset grops 1.08 0

X%%Pages: 6

X%%IncludeResource: font Times-Roman
X%%IncludeResource: font Times-Bold
X%%IncludeResource: font Times-Italic

X/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
X/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0/Times-Roman RE


X%%EndProlog
X%%Page: 1 1
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S(MB).6 E 352.96(ASE\(5\) J)-.35 F(AMB)-.6
XE(ASE\(5\))-.35 E/F1 9/Times-Bold@0 SF -.18(NA)72 84 S(ME).18 E/F2 10
X/Times-Bold@0 SF -.15(Ja)108 96 S(mbase).15 E F0<ad>2.5 E F2(jam)2.5 E F0
X(\(1\) boilerplate)A F1(FILES)72 112.8 Q F2(/usr/local/lib/J)108 124.8 Q
X(ambase)-.15 E -.15(Ja)108 136.8 S(m\214le).15 E F1(DESCRIPTION)72 165.6 Q F2
X-.15(Ja)108 177.6 S(mbase).15 E F0 .28(contains a set of)2.78 F F2(jam)2.779 E
XF0 .279(rule de\214nitions that pro)2.779 F .279(vide roughly)-.15 F F2(mak)
X2.779 E(e)-.1 E F0(\(1\)-lik)A 2.779(ef)-.1 G(unctionality)443.032 177.6 Q(.)
X-.65 E F2 -.15(Ja)5.279 G(m).15 E F0(reads)2.779 E F2 -.15(Ja)108 189.6 S
X(mbase).15 E F0 2.5(,w)C(hich in turn includes the)157.29 189.6 Q F2 -.15(Ja)
X2.5 G(m\214le).15 E F0(from the current directory)2.5 E(.)-.65 E .422
X(This manual page lists the rules and v)108 206.4 R .423(ariables de\214ned in)
X-.25 F F2 -.15(Ja)2.923 G(mbase).15 E F0 5.423(.F)C .423
X(or a more readable guide to writing a)389.019 206.4 R F2 -.15(Ja)108 218.4 S
X(m\214le).15 E F0 2.5(,s)C(ee)147.85 218.4 Q F2 -.15(Ja)2.5 G(m\214le).15 E F0
X(\(5\).)A F2(Rules)87 235.2 Q/F3 10/Times-Italic@0 SF(As)108 247.2 Q F0
X(obj.o : source.s ;)2.5 E(Assemble the \214le)144 264 Q F3(sour)2.5 E(ce)-.37 E
X(.s)-.15 E F0 5(.C)C(alled by the)262.64 264 Q F3(Object)2.5 E F0(rule.)2.5 E
XF3(Bulk)108 280.8 Q F0(directory : sources ;)2.5 E(Copies)144 297.6 Q F3(sour)
X2.5 E(ces)-.37 E F0(into)2.5 E F3(dir)2.5 E(ectory)-.37 E F0 2.5(.D)C
X(ependencies of)273.53 297.6 Q F3(\214les)2.5 E F0(.)A F3(Cc)108 314.4 Q F0
X(object : source ;)2.5 E 2.15(Compile the \214le)144 331.2 R F3(sour)4.65 E(ce)
X-.37 E F0(into)4.65 E F3(object)4.65 E F0 4.65(,u)C 2.15
X(sing the C compiler $\(CC\), its \215ags $\(CCFLA)305.14 331.2 R 2.15
X(GS\) and)-.4 F($\(OPTIM\), and the header \214le directories $\(HDRS\).)144
X343.2 Q(Called by the)5 E F3(Object)2.5 E F0(rule.)2.5 E F3(C++)108 360 Q F0
X(obj.o : source.cc ;)2.5 E(Compile the C++ source \214le)144 376.8 Q F3(sour)
X2.5 E(ce)-.37 E(.cc)-.15 E F0 5(.C)C(alled by the)311.69 376.8 Q F3(Object)2.5
XE F0(rule.)2.5 E F3(Clean)108 393.6 Q F0(clean : tar)2.5 E(gets ;)-.18 E(Remo)
X144 410.4 Q -.15(ve)-.15 G 3.005(se).15 G(xisting)188.215 410.4 Q F3(tar)3.005
XE -.1(ge)-.37 G(ts).1 E F0(when)3.006 E F3(clean)3.006 E F0 .506(is b)3.006 F
X(uilt.)-.2 E F3(clean)5.506 E F0 .506(is not a dependenc)3.006 F 3.006(yo)-.15
XG(f)447.11 410.4 Q F3(all)3.006 E F0 3.006(,a)C .506(nd must be b)473.952 410.4
XR(uilt)-.2 E -.15(ex)144 422.4 S(plicitly for).15 E F3(tar)2.5 E -.1(ge)-.37 G
X(ts).1 E F0(to be remo)2.5 E -.15(ve)-.15 G(d.).15 E F3 -.45(Fi)108 439.2 S(le)
X.45 E F0(tar)2.5 E(get : source ;)-.18 E(Copies)144 456 Q F3(sour)2.5 E(ce)-.37
XE F0(into)2.5 E F3(tar)2.5 E -.1(ge)-.37 G(t).1 E F0 5(.D)C(ependenc)259.27 456
XQ 2.5(yo)-.15 G(f)309.38 456 Q F3(\214les)2.5 E F0(.)A F3 -1.05(Fo)108 472.8 S
X(rtr)1.05 E(an)-.15 E F0(obj.o : source.f ;)2.5 E(Compile the F)144 489.6 Q
X(ortran source \214le)-.15 E F3(sour)2.5 E(ce)-.37 E(.f)-.15 E F0 5(.C)C
X(alled by the)316.93 489.6 Q F3(Object)2.5 E F0(rule.)2.5 E F3(Har)108 506.4 Q
X(dLink)-.37 E F0(tar)2.5 E(get : source ;)-.18 E(Mak)144 523.2 Q(es)-.1 E F3
X(tar)2.5 E -.1(ge)-.37 G(t).1 E F0 2.5(ah)2.5 G(ard link to)210.92 523.2 Q F3
X(sour)2.5 E(ce)-.37 E F0 2.5(,i)C 2.5(fi)288.6 523.2 S 2.5(ti)297.21 523.2 S
X(sn')305.27 523.2 Q 2.5(to)-.18 G(ne already)327.59 523.2 Q(.)-.65 E F3
X(HdrRule)108 540 Q F0(source : headers ;)2.5 E 1.893
X(Arranges the proper dependencies when the \214le)144 556.8 R F3(sour)4.392 E
X(ce)-.37 E F0 1.892(includes the \214les)4.392 F F3(header)4.392 E(s)-.1 E F0
X1.892(through the)4.392 F .389("#include" C preprocessor directi)144 568.8 R
X-.15(ve)-.25 G 5.389(.T).15 G(he)301.616 568.8 Q F3(Object)2.889 E F0 .389
X(rule arranges for this rule to be called when)2.889 F F2(jam)2.89 E F0
X(does its header \214le scan of)144 580.8 Q F3(sour)2.5 E(ce)-.37 E F0(.)A F3
X(Install)108 597.6 Q F0(tar)2.5 E(get : source ;)-.18 E(Copies)144 614.4 Q F3
X(sour)2.5 E(ce)-.37 E F0(into)2.5 E F3(tar)2.5 E -.1(ge)-.37 G(t).1 E F0 2.5
X(,u)C(sing)254.55 614.4 Q F3(install)2.5 E F0 2.5(\(1\). Used)B(by the other)
X2.5 E F3(Install)2.5 E F0 2.5(*r)C(ules.)427.6 614.4 Q F3(InstallBin)108 631.2
XQ F0(dir : sources ;)2.5 E(Cop)144 648 Q(y)-.1 E F3(sour)2.5 E(ces)-.37 E F0
X(into)2.5 E F3(dir)2.5 E F0(with mode $\(EXEMODE\).)2.5 E(Dependencies of)5 E
XF3(install)2.5 E F0(.)A F3(InstallLib)108 664.8 Q F0(dir : sources ;)2.5 E(Cop)
X144 681.6 Q(y)-.1 E F3(sour)2.5 E(ces)-.37 E F0(into)2.5 E F3(dir)2.5 E F0
X(with mode $\(FILEMODE\).)2.5 E(Dependencies of)5 E F3(install)2.5 E F0(.)A F3
X(InstallMan)108 698.4 Q F0(dir : sources ;)2.5 E(Cop)144 715.2 Q(y)-.1 E F3
X(sour)3.415 E(ces)-.37 E F0 .914(into the appropriate subdirectory of)3.415 F
XF3(dir)3.414 E F0 .914(with mode $\(FILEMODE\).)3.414 F .914(The subdirec-)
X5.914 F(tory is)144 727.2 Q F2(man)2.5 E F3(s)A F0 2.5(,w)C(here)206.78 727.2 Q
XF3(s)2.5 E F0(is the suf)2.5 E(\214x of each of)-.25 E F3(sour)2.5 E(ces)-.37 E
XF0 5(.D)C(ependencies of)369.18 727.2 Q F3(install)2.5 E F0(.)A(10 March 1995)
X275.45 768 Q(1)535 768 Q EP


X%%Page: 2 2
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S(MB).6 E 352.96(ASE\(5\) J)-.35 F(AMB)-.6
XE(ASE\(5\))-.35 E/F1 10/Times-Italic@0 SF(InstallShell)108 84 Q F0
X(dir : sources ;)2.5 E(Cop)144 100.8 Q(y)-.1 E F1(sour)2.5 E(ces)-.37 E F0
X(into)2.5 E F1(dir)2.5 E F0(with mode $\(SHELLMODE\).)2.5 E(Dependencies of)5 E
XF1(install)2.5 E F0(.)A F1(Le)108 117.6 Q(x)-.2 E F0(source.c : source.l ;)2.5
XE .916(Process the)144 134.4 R/F2 10/Times-Bold@0 SF(lex)3.416 E F0 .916
X(\(1\) source \214le)B F1(sour)3.416 E(ce)-.37 E(.l)-.15 E F0 .917
X(and rename the le)3.417 F(x.yy)-.15 E .917(.c to)-.65 F F1(sour)3.417 E(ce)
X-.37 E(.c)-.15 E F0 5.917(.C)C .917(alled by the)461.429 134.4 R F1(Object)
X3.417 E F0(rule.)144 146.4 Q F1(Libr)108 163.2 Q(ary)-.15 E F0
X(library : sources ;)2.5 E(Compiles)144 180 Q F1(sour)4.285 E(ces)-.37 E F0
X1.784(and archi)4.285 F -.15(ve)-.25 G 4.284(st).15 G 1.784(hem into)279.798
X180 R F1(libr)4.284 E(ary)-.15 E F0 6.784(.T)C 1.784
X(he intermediate objects are deleted.)364.17 180 R(Calls)6.784 E F1(Objects)144
X192 Q F0(and)2.5 E F1(Libr)2.5 E(aryF)-.15 E -.45(ro)-.55 G(mObjects).45 E F0 5
X(.D)C(ependenc)290.89 192 Q 2.5(yo)-.15 G(f)341 192 Q F1(lib)2.5 E F0(.)A F1
X(Libr)108 208.8 Q(aryF)-.15 E -.45(ro)-.55 G(mObjects).45 E F0
X(library : objects ;)2.5 E(Archi)144 225.6 Q -.15(ve)-.25 G(s).15 E F1(objects)
X2.5 E F0(into)2.5 E F1(libr)2.5 E(ary)-.15 E F0 5(.T)C(he)272.33 225.6 Q F1
X(objects)2.5 E F0(are then deleted.)2.5 E(Dependenc)5 E 2.5(yo)-.15 G(f)443.24
X225.6 Q F1(lib)2.5 E F0(.)A F1(LinkLibr)108 242.4 Q(aries)-.15 E F0
X(image : libraries ;)2.5 E(Mak)144 259.2 Q(es)-.1 E F1(ima)2.5 E -.1(ge)-.1 G
XF0(depend on)2.6 E F1(libr)2.5 E(aries)-.15 E F0
X(and includes them during the linking.)2.5 E F1(Main)108 276 Q F0
X(image : sources ;)2.5 E(Compiles)144 292.8 Q F1(sour)3.23 E(ces)-.37 E F0 .73
X(and links them into)3.23 F F1(ima)3.23 E -.1(ge)-.1 G F0 5.73(.C).1 G(alls)
X340.49 292.8 Q F1(Objects)3.23 E F0(and)3.23 E F1(MainF)3.23 E -.45(ro)-.55 G
X(mObjects).45 E F0 5.73(.D)C(ependenc)497.39 292.8 Q(y)-.15 E(of)144 304.8 Q F1
X-.2(ex)2.5 G(e).2 E F0(.)A F1(MainF)108 321.6 Q -.45(ro)-.55 G(mObjects).45 E
XF0(image : objects ;)2.5 E(Links)144 338.4 Q F1(objects)2.5 E F0(into)2.5 E F1
X(ima)2.5 E -.1(ge)-.1 G F0 5(.D).1 G(ependenc)257.13 338.4 Q 2.5(yo)-.15 G(f)
X307.24 338.4 Q F1 -.2(ex)2.5 G(e).2 E F0(.)A F1(Object)108 355.2 Q F0
X(object : source ;)2.5 E .268(Compiles a single source \214le)144 372 R F1
X(sour)2.768 E(ce)-.37 E F0(into)2.768 E F1(object)2.768 E F0 5.268(.M)C(ak)
X351.874 372 Q(es)-.1 E F1(object)2.768 E F0 .268
X(depend on all header \214les included)2.768 F(by)144 384 Q F1(sour)2.5 E(ce)
X-.37 E F0 5(.S)C(uch dependencies are "soft": missing headers are not an error)
X195.85 384 Q(.)-.55 E(Calls one of the rules listed to do the actual compiling\
X, depending on the suf)144 400.8 Q(\214x of)-.25 E F1(sour)2.5 E(ce)-.37 E F0
X(:)A(source.c:)180 417.6 Q F1(Cc)2.5 E F0(source.cc:)180 429.6 Q F1(C++)2.5 E
XF0(source.cpp:)180 441.6 Q F1(C++)2.5 E F0(source.C:)180 453.6 Q F1(C++)2.5 E
XF0(source.l:)180 465.6 Q F1(Le)2.5 E(x)-.2 E F0(source.y:)180 477.6 Q F1 -.92
X(Ya)2.5 G(cc).92 E F0(source.*:)180 489.6 Q F1(UserObject)2.5 E F0
X(This rule is used by)144 506.4 Q F2(Objects)2.5 E F0(.)A F1(ObjectCcFla)108
X523.2 Q(gs)-.1 E F0(source : \215ags ;)2.5 E(Add)144 540 Q F1<8d61>2.708 E(gs)
X-.1 E F0 .208(to the)2.708 F F1(sour)2.708 E(ce)-.37 E F0 .208(-speci\214c v)B
X.208(alue of $\(CCFLA)-.25 F .209(GS\) when compiling)-.4 F F1(sour)2.709 E(ce)
X-.37 E F0 5.209(.A)C .509 -.15(ny \214)476.713 540 T .209(le suf).15 F .209
X(\214x on)-.25 F F1(sour)144 552 Q(ce)-.37 E F0(is ignored.)2.5 E F1(ObjectHdr)
X108 568.8 Q(s)-.1 E F0(source : dirs ;)2.5 E(Add)144 585.6 Q F1(dir)2.981 E(s)
X-.1 E F0 .481(to the)2.981 F F1(sour)2.981 E(ce)-.37 E F0 .481(-speci\214c v)B
X.481(alue of $\(HDRS\) when scanning and compiling)-.25 F F1(sour)2.98 E(ce)
X-.37 E F0 5.48(.A)C .78 -.15(ny \214)514.39 585.6 T(le).15 E(suf)144 597.6 Q
X(\214x on)-.25 E F1(sour)2.5 E(ce)-.37 E F0(is ignored.)2.5 E F1(Objects)108
X614.4 Q F0(sources ;)2.5 E -.15(Fo)144 631.2 S 4.143(re).15 G 1.643
X(ach source \214le in)166.323 631.2 R F1(sour)4.143 E(ces)-.37 E F0 4.143(,c)C
X(alls)284.698 631.2 Q F1(Object)4.143 E F0 1.643
X(to compile the source \214le into a similarly named)4.143 F(object \214le.)144
X643.2 Q F1(RmT)108 660 Q(emps)-.92 E F0(tar)2.5 E(gets : sources ;)-.18 E
X(Marks)144 676.8 Q F1(sour)3.6 E(ces)-.37 E F0 1.1(as temporary with the)3.6 F
XF2(TEMPORAR)3.6 E(Y)-.35 E F0 1.1(rule, and deletes)3.6 F F1(sour)3.6 E(ces)
X-.37 E F0(once)3.6 E F1(tar)3.6 E -.1(ge)-.37 G(ts).1 E F0(are)3.6 E -.2(bu)144
X688.8 S 2.5(ilt. Must).2 F(be the last rule in)2.5 E -.2(vo)-.4 G -.1(ke).2 G
X2.5(do).1 G(n)292.82 688.8 Q F1(tar)2.5 E -.1(ge)-.37 G(ts).1 E F0 5(.U)C
X(sed internally by)342.35 688.8 Q F2(Object)2.5 E F0(.)A F1(Setuid)108 705.6 Q
XF0(images ;)2.5 E(10 March 1995)275.45 768 Q(2)535 768 Q EP


X%%Page: 3 3
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S(MB).6 E 352.96(ASE\(5\) J)-.35 F(AMB)-.6
XE(ASE\(5\))-.35 E(Sets the setuid bit on each of)144 84 Q/F1 10/Times-Italic@0
XSF(ima)2.5 E -.1(ge)-.1 G(s).1 E F0(after linking.)2.5 E F1(Shell)108 100.8 Q
XF0(image : source ;)2.5 E(Copies)144 117.6 Q F1(sour)3.765 E(ce)-.37 E F0 1.265
X(into the e)3.765 F -.15(xe)-.15 G(cutable).15 E/F2 10/Times-Bold@0 SF(sh)3.765
XE F0 1.265(\(1\) script)B F1(ima)3.765 E -.1(ge)-.1 G F0 6.265(.E).1 G 1.265
X(nsures that the \214rst line of the script is)377.11 117.6 R
X($\(SHELLHEADER\) \(def)144 129.6 Q(ault)-.1 E F1(#!/bin/sh)2.5 E F0 2.5
X(\). Dependenc)B 2.5(yo)-.15 G(f)367.04 129.6 Q F1(shell)2.5 E F0(.)A F1
X(Unde\214nes)108 146.4 Q F0(images : symbols ;)2.5 E -.35(Tr)144 163.2 S
X(ies to con).35 E(vince the link)-.4 E
X(er that symbols need to be "unde\214ned" for the linking of)-.1 E F1(ima)2.5 E
X-.1(ge)-.1 G(s).1 E F0(.)A F1(UserObject)108 180 Q F0(object : source ;)2.5 E
X.161(Complains that the suf)144 196.8 R .161(\214x on)-.25 F F1(sour)2.661 E
X(ce)-.37 E F0 .161(is unkno)2.661 F 2.661(wn. This)-.25 F .16
X(rule is called by)2.661 F F1(Object)2.66 E F0 .16(for source \214les with)2.66
XF(unkno)144 208.8 Q .119(wn suf)-.25 F<8c78>-.25 E .119
X(es, and should be replaced with a user)-.15 F(-pro)-.2 E .12
X(vided rule to handle the source \214le types.)-.15 F F1 -.92(Ya)108 225.6 S
X(cc).92 E F0(source.c : source.y ;)2.5 E 1.175(Process the)144 242.4 R F2(yacc)
X3.675 E F0 1.175(\(1\) \214le)B F1(sour)3.675 E(ce)-.37 E(.y)-.15 E F0 1.174
X(and renamed the resulting y)3.674 F(.tab)-.65 E 1.174(.c and y)-.4 F(.tab)-.65
XE 1.174(.h to)-.4 F F1(sour)3.674 E(ce)-.37 E(.c)-.15 E F0 6.174(.P)C(ro-)
X528.34 242.4 Q(duces a y)144 254.4 Q(.tab)-.65 E(.h and renames it to)-.4 E F1
X(sour)2.5 E(ce)-.37 E F0 2.5(.h. Called)B(by the)2.5 E F1(Object)2.5 E F0
X(rule.)2.5 E F2 -.92(Va)87 271.2 S(riables).92 E F0 .125(These v)108 283.2 R
X.125(ariables are set in)-.25 F F2 -.15(Ja)2.625 G(mbase).15 E F0 .125
X(only if the)2.625 F 2.625(ya)-.15 G .125(re not set in the user')304.925 283.2
XR 2.625(se)-.55 G -.4(nv)400.105 283.2 S .125(ironment, and so can be o).4 F
X-.15(ve)-.15 G(rrid-).15 E .42(den with en)108 295.2 R .42(vironment settings.)
X-.4 F .42(Most v)5.42 F .42
X(ariables are used by the actions of the related rules.)-.25 F .42(When the v)
X5.42 F(ari-)-.25 E .138(able is used by a rule')108 307.2 R 2.638(sp)-.55 G
X.138(rocedure \(and therefore must be set before in)207.148 307.2 R -.2(vo)-.4
XG .138(king the rule\), it is mark).2 F .139(ed with a \203.)-.1 F(AR \(def)108
X324 Q(ault)-.1 E F1("ar ru")2.5 E F0(\))A(The archi)144 340.8 Q -.15(ve)-.25 G
X2.5(ru).15 G(sed for)201.91 340.8 Q F2(Library)2.5 E F0(.)A(AS \(def)108 357.6
XQ(ault)-.1 E F1(as)2.5 E F0(\))A(The assembler for)144 374.4 Q F2(As)2.5 E F0
X(.)A(ASFLA)108 391.2 Q(GS \(no def)-.4 E(ault\))-.1 E
X(Flags handed to the assembler for)144 408 Q F2(As)2.5 E F0(.)A -.9(AW)108
X424.8 S 2.5(K\().9 G F1(awk)136.81 424.8 Q F0(\))A(The name of a)144 441.6 Q
X(wk interpreter)-.15 E 2.5(,u)-.4 G(sed when cop)267.3 441.6 Q
X(ying a shell script for the)-.1 E F1(Shell)2.5 E F0(rule.)2.5 E(BINDIR \(def)
X108 458.4 Q(ault)-.1 E F1(/usr/local/bin)2.5 E F0(\))A(Not used.)144 475.2 Q
X(Set for con)5 E -.15(ve)-.4 G(nience.).15 E(CC \(def)108 492 Q(ault)-.1 E F1
X(cc)2.5 E F0(\))A 2.5(Cc)144 508.8 S(ompiler used for)157.61 508.8 Q F2(Cc)2.5
XE F0(.)A(CCFLA)108 525.6 Q(GS \(no def)-.4 E(ault\) \203)-.1 E
X(Flags handed to the C compiler for)144 542.4 Q F2(Object)2.5 E F0(.)A F2
X(OPTIM)5 E F0(is also handed to the C compiler)2.5 E(.)-.55 E(C++ \(def)108
X559.2 Q(ault)-.1 E F1(gcc)2.5 E F0(\))A(C++ compiler used for)144 576 Q F2(C++)
X2.5 E F0(.)A(C++FLA)108 592.8 Q(GS \(no def)-.4 E(ault\) \203)-.1 E
X(Flags handed to the C++ compiler for)144 609.6 Q F2(C++)2.5 E F0(.)A F2(OPTIM)
X5 E F0(is also handed to the C++ compiler)2.5 E(.)-.55 E(CP \(def)108 626.4 Q
X(ault)-.1 E F1(cp)2.5 E F0(\))A(The \214le cop)144 643.2 Q 2.5(yp)-.1 G
X(rogram, used by)204.17 643.2 Q F1 -.45(Fi)2.5 G(le).45 E F0(and)2.5 E F1
X(Install)2.5 E F0(.)A(EXEMODE \(def)108 660 Q(ault)-.1 E F1(711)2.5 E F0(\))A
X(Permissions for e)144 676.8 Q -.15(xe)-.15 G(cutables link).15 E(ed with)-.1 E
XF2(Main)2.5 E F0(.)A(FILEMODE \(def)108 693.6 Q(ault)-.1 E F1(644)2.5 E F0 2.5
X<2983>C(Permissions for \214les copied by)144 710.4 Q F2(File)2.5 E F0(or)2.5 E
XF2(Bulk)2.5 E F0(.)A(FOR)108 727.2 Q(TRAN \(def)-.6 E(ault)-.1 E F1(f77)2.5 E
XF0(\))A(10 March 1995)275.45 768 Q(3)535 768 Q EP


X%%Page: 4 4
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S(MB).6 E 352.96(ASE\(5\) J)-.35 F(AMB)-.6
XE(ASE\(5\))-.35 E(The F)144 84 Q(ortran compiler used by)-.15 E/F1 10
X/Times-Bold@0 SF -.25(Fo)2.5 G(rtran).25 E F0(.)A(FOR)108 100.8 Q(TRANFLA)-.6 E
X(GS \(no def)-.4 E(ault\))-.1 E(Flags handed to the F)144 117.6 Q
X(ortran compiler for)-.15 E F1 -.25(Fo)2.5 G(rtran).25 E F0(.)A(GR)108 134.4 Q
X(OUP \(no def)-.4 E(ault\))-.1 E(The group o)144 151.2 Q
X(wner of installed \214led.)-.25 E(Used by)5 E/F2 10/Times-Italic@0 SF(Install)
X2.5 E F0(.)A(HDRP)108 168 Q -1.11(AT)-.92 G(TERN \(def)1.11 E
X(ault ^#[\\t ]*include[\\t ]*[<"]\(.*\)[">].*$\) \203)-.1 E(The)144 184.8 Q F1
X-.18(re)3.788 G(gexp).18 E F0 1.287
X(\(3\) pattern for \214nding header \214le includes in source \214les.)B(The)
X6.287 E F1(Object)3.787 E F0 1.287(rule sets the)3.787 F F1(jam)144 196.8 Q F0
X.784(-special v)B(ariable)-.25 E F1(HDRSCAN)3.284 E F0 .784(to $\(HDRP)3.284 F
X-1.11(AT)-.92 G .785(TERN\) for all of its sources.)1.11 F .785
X(The corresponding)5.785 F(tar)144 208.8 Q(get of the)-.18 E F1(Object)2.5 E F0
X(rule in)2.5 E -.2(vo)-.4 G(cation depends on all header \214les found.).2 E
X(HDRR)108 225.6 Q(ULE \(def)-.4 E(ault HdrRule\))-.1 E(The rule to in)144 242.4
XQ -.2(vo)-.4 G .2 -.1(ke w).2 H(ith the results of header \214le scanning.).1 E
X(This is a)5 E F1(jam)2.5 E F0(-special v)A(ariable.)-.25 E(HDRSCAN \(def)108
X259.2 Q(ault $\(HDRP)-.1 E -1.11(AT)-.92 G(TERN\)\))1.11 E(The)144 276 Q F1
X-.18(re)2.927 G(gexp).18 E F0 .426(\(3\) pattern for header \214le scanning.)B
X.426(This v)5.426 F .426(ariable and $\(HDRR)-.25 F .426
X(ULE\) trigger the scan-)-.4 F 2.5(ning. This)144 288 R(is a)2.5 E F1(jam)2.5 E
XF0(-special v)A(ariable.)-.25 E(HDRS \(no def)108 304.8 Q(ault\) \203)-.1 E .57
X(Directories to be scanned for header \214les and handed to the C compiler wit\
Xh -I.)144 321.6 R(The)5.571 E F1(Object)3.071 E F0(rule)3.071 E(sets)144 333.6
XQ F1(HDRS)2.5 E F0(to $\(HDRS\) for each of its sources.)2.5 E(INST)108 350.4 Q
X(ALL \(def)-.93 E(ault)-.1 E F2(install)2.5 E F0(\))A(The \214le cop)144 367.2
XQ(ying program for the)-.1 E F2(Install)2.5 E F0 2.5(rule. If)2.5 F(not set)2.5
XE F2(Install)2.5 E F0(uses $\(CP\).)2.5 E -.6(JA)108 384 S(MFILE \(def).6 E
X(ault)-.1 E F2 -.35(Ja)2.5 G(m\214le).35 E F0(\))A(The user)144 400.8 Q(-pro)
X-.2 E(vided \214le listing the sources to be b)-.15 E(uilt.)-.2 E -.6(JA)108
X417.6 S(MR).6 E(ULES \(def)-.4 E(ault)-.1 E F2 -.35(Ja)2.5 G(mrules).35 E F0
X(\))A(The name of the \214le included by the)144 434.4 Q F2(SubDir)2.5 E F0
X(rule.)2.5 E(LEX \(def)108 451.2 Q(ault)-.1 E F2(le)2.5 E(x)-.2 E F0(\))2.5 E
X(The)144 468 Q F1(lex)2.5 E F0(\(1\) command and \215ags.)A(LIBDIR \(def)108
X484.8 Q(ault)-.1 E F2(/usr/local/lib)2.5 E F0(\))A(Not used.)144 501.6 Q
X(Set for con)5 E -.15(ve)-.4 G(nience.).15 E(LINK \(def)108 518.4 Q(ault)-.1 E
XF2(cc)2.5 E F0(\))A(The link)144 535.2 Q(er)-.1 E(.)-.55 E(LINKFLA)108 552 Q
X(GS \(def)-.4 E(ault $\(CCFLA)-.1 E(GS\)\))-.4 E(Flags handed to the link)144
X568.8 Q(er)-.1 E(.)-.55 E(LINKLIBS \(no def)108 585.6 Q(ault\))-.1 E
X(Libraries to hand to the link)144 602.4 Q(er)-.1 E 5(.T)-.55 G(he tar)276.11
X602.4 Q(get image does not depend on these libraries.)-.18 E(LOCA)108 619.2 Q
X(TE_T)-1.11 E(ARGET \(no def)-.93 E(ault\) \203)-.1 E .203
X(The directory for object modules and other intermediate \214les generated by)
X144 636 R F1(Object)2.703 E F0 5.203(.T)C .202(his w)488.586 636 R .202
X(orks by)-.1 F 2.046(setting the)144 648 R F1(jam)4.546 E F0 2.046(-special v)B
X(ariable)-.25 E F1(LOCA)4.546 E(TE)-.95 E F0 2.047(to the v)4.547 F 2.047
X(alue of $\(LOCA)-.25 F(TE_T)-1.11 E 2.047(ARGET\) for each of)-.93 F F1
X(Object)144 660 Q F0 1.1 -.55('s t)D(ar).55 E(gets.)-.18 E(LN \(def)108 676.8 Q
X(ault)-.1 E F2(ln)2.5 E F0(\))A(The hard link command for)144 693.6 Q F2(Har)
X2.5 E(dLink)-.37 E F0(.)A(MANDIR \(def)108 710.4 Q(ault)-.1 E F2
X(/usr/local/man)2.5 E F0(\))A(10 March 1995)275.45 768 Q(4)535 768 Q EP


X%%Page: 5 5
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S(MB).6 E 352.96(ASE\(5\) J)-.35 F(AMB)-.6
XE(ASE\(5\))-.35 E(Not used.)144 84 Q(Set for con)5 E -.15(ve)-.4 G(nience.).15
XE(MKDIR \(def)108 100.8 Q(ault)-.1 E/F1 10/Times-Italic@0 SF(mkdir)2.5 E F0(\))
XA(The program to create directories for the)144 117.6 Q F1(MkDir)2.5 E F0
X(rule.)2.5 E(MODE \(def)108 134.4 Q(ault v)-.1 E(aries\))-.25 E 3.093
X(The \214le mode for \214les installed with)144 151.2 R F1(Install)5.592 E F0
X8.092(.I)C 5.592(ss)353.18 151.2 S 3.092(et to $\(EXEMODE\), $\(FILEMODE\), or)
X366.552 151.2 R($\(SHELLMODE\) depending which rule in)144 163.2 Q -.2(vo)-.4 G
X-.1(ke).2 G(d).1 E F1(Install)2.5 E F0(.)A(MV \(def)108 180 Q(ault)-.1 E F1
X(mv -f)2.5 E F0(\))A(The \214le rename command and options.)144 196.8 Q
X(OPTIM \(def)108 213.6 Q(ault)-.1 E F1(-O)2.5 E F0(\))A
X(More \215ags handed to the C compiler)144 230.4 Q(.)-.55 E -.35(OW)108 247.2 S
X(NER \(no def).35 E(ault\))-.1 E(The o)144 264 Q(wner of installed \214led.)
X-.25 E(Used by)5 E F1(Install)2.5 E F0(.)A(RANLIB \(def)108 280.8 Q(ault)-.1 E
XF1 -.15(ra)2.5 G(nlib).15 E F0 2.5<2983>C(If set, the command string to be in)
X144 297.6 Q -.2(vo)-.4 G -.1(ke).2 G 2.5(do).1 G 2.5(ne)312.45 297.6 S
X(ach library after archi)324.39 297.6 Q(ving.)-.25 E(RELOCA)108 314.4 Q
X(TE \(def)-1.11 E(ault unset\))-.1 E .987(If set, tells the)144 331.2 R F1(Cc)
X3.487 E F0 .987(rule to mo)3.487 F 1.287 -.15(ve t)-.15 H .987
X(he output object \214le to its tar).15 F .988
X(get directory because the cc com-)-.18 F(mand has a brok)144 343.2 Q
X(en -o option.)-.1 E(RM \(def)108 360 Q(ault)-.1 E F1(rm -f)2.5 E F0(\))A
X(The command and options to remo)144 376.8 Q .3 -.15(ve a \214)-.15 H(le.).15 E
X(SEARCH_SOURCE \(no def)108 393.6 Q(ault\) \203)-.1 E 1.23
X(The directory to \214nd sources listed with)144 410.4 R/F2 10/Times-Bold@0 SF
X(Main)3.729 E F0(,)A F2(Library)3.729 E F0(,)A F2(Object)3.729 E F0(,)A F2
X(Bulk)3.729 E F0(,)A F2(File)3.729 E F0(,)A F2(Shell)3.729 E F0(,)A F2
X(InstallBin)3.729 E F0(,)A F2(InstallLib)144 422.4 Q F0 2.519(,a)C(nd)195.699
X422.4 Q F2(InstallMan)2.519 E F0 2.519(rules. This)2.519 F -.1(wo)2.519 G .019
X(rks by setting the).1 F F2(jam)2.519 E F0 .019(-special v)B(ariable)-.25 E F2
X(SEARCH)2.52 E F0 .02(to the)2.52 F -.25(va)144 434.4 S
X(lue of $\(SEARCH_SOURCE\) for each of the rules' sources.).25 E
X(SHELLHEADER \(def)108 451.2 Q(ault)-.1 E F1(#!/bin/sh)2.5 E F0(\))A 2.5(As)144
X468 S(tring inserted to the \214rst line of e)157.61 468 Q -.15(ve)-.25 G
X(ry \214le created by the).15 E F2(Shell)2.5 E F0(rule.)2.5 E(SHELLMODE \(def)
X108 484.8 Q(ault)-.1 E F1(755)2.5 E F0 2.5<2983>C
X(Permissions for \214les installed by)144 501.6 Q F2(Shell)2.5 E F0(.)A
X(SLASH \(def)108 518.4 Q(ault)-.1 E F1(/)2.5 E F0 2.5<2983>C
X(The directory separator)144 535.2 Q 5(.U)-.55 G(sed by)251.47 535.2 Q F1
X(SubDir)2.5 E F0(and)2.5 E F1(SubInclude)2.5 E F0(to b)2.5 E
X(uild up a directory path.)-.2 E(SOURCE_GRIST \(no def)108 552 Q(ault\) \203)
X-.1 E 1.148(Set by the)144 568.8 R F1(SubDir)3.647 E F0 1.147(to a v)3.647 F
X1.147(alue deri)-.25 F -.15(ve)-.25 G 3.647(df).15 G 1.147
X(rom the directory name, and used by)303.617 568.8 R F1(Objects)3.647 E F0
X1.147(and related)3.647 F(rules as 'grist' to perturb \214le names.)144 580.8 Q
X(STDHDRS \(def)108 597.6 Q(ault)-.1 E F1(/usr/include)2.5 E F0 2.5<2983>C
X(Directories where headers can be found without resorting to using the)144
X614.4 Q F1<8d61>2.5 E(g)-.1 E F0(to the C compiler)2.5 E(.)-.55 E
X(SUBDIR \(no def)108 631.2 Q(ault\))-.1 E(Set by)144 648 Q F1(SubDir)2.5 E F0
X(to be the named directory)2.5 E(.)-.65 E(SUFEXE \(def)108 664.8 Q
X(ault ""\) \203)-.1 E(The suf)144 681.6 Q(\214x for e)-.25 E -.15(xe)-.15 G
X(cutable \214les, if none pro).15 E 2.5(vided. Used)-.15 F(by the)2.5 E F1
X(Main)2.5 E F0(rule.)2.5 E(SUFLIB \(def)108 698.4 Q(ault)-.1 E F1(.a)2.5 E F0
X2.5<2983>C(The suf)144 715.2 Q(\214x for libraries.)-.25 E(Used by the)5 E F1
X(Libr)2.5 E(ary)-.15 E F0(and related rules.)2.5 E(10 March 1995)275.45 768 Q
X(5)535 768 Q EP


X%%Page: 6 6
X%%BeginPageSetup
XBP
X%%EndPageSetup

X/F0 10/Times-Roman@0 SF -.6(JA)72 48 S(MB).6 E 352.96(ASE\(5\) J)-.35 F(AMB)-.6
XE(ASE\(5\))-.35 E(SUFOBJ \(def)108 84 Q(ault)-.1 E/F1 10/Times-Italic@0 SF(.o)
X2.5 E F0 2.5<2983>C(The suf)144 100.8 Q(\214x for object \214les.)-.25 E
X(Used by the)5 E F1(Objects)2.5 E F0(and related rules.)2.5 E(UNDEFFLA)108
X117.6 Q 2.5(G\()-.4 G(def)172.87 117.6 Q(ault)-.1 E F1(-u _)2.5 E F0(\))A
X(The \215ag pre\214x)144 134.4 Q(ed to each symbol for the)-.15 E/F2 10
X/Times-Bold@0 SF(Unde\214nes)2.5 E F0(rule.)2.5 E -.5 -1.2(YA C)108 151.2 T 2.5
X(C\()1.2 G(def)140.01 151.2 Q(ault)-.1 E F1(yacc -d)2.5 E F0(\))A(The)144 168 Q
XF2(yacc)2.5 E F0(\(1\) command and \215ags.)A/F3 9/Times-Bold@0 SF(SEE ALSO)72
X196.8 Q F2(jam)108 208.8 Q F0(\(1\),)A F2 -.15(Ja)2.5 G(m\214le).15 E F0(\(5\))
XA(10 March 1995)275.45 768 Q(6)535 768 Q EP
X%%Trailer
Xend
X%%EOF
END_OF_FILE
if test 28776 -ne `wc -c <'Jambase.ps'`; then
echo shar: \"'Jambase.ps'\" unpacked with wrong size!
fi
# end of 'Jambase.ps'
fi
if test -f 'Jamfile.5' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Jamfile.5'\"
else
echo shar: Extracting \"'Jamfile.5'\" \(40692 characters\)
sed "s/^X//" >'Jamfile.5' <<'END_OF_FILE'
X.TH JAMFILE 5 "10 March 1995"
X.de BB
X.RS
X.PP
X.ft CW
X.na
X.nf
X..
X.de BE
X.RE
X.ft R
X.fi
X.ad
X..
X.de XB
XFor example:
X.BB
X..
X.de XE
X.BE
X..
X.SH NAME
X\fBJamfile\fR \- per-directory \fBjam\fR(1) instructions
X.SH DESCRIPTION
X.PP
XThis manual page gives instructions and examples for writing a
X\fBJamfile\fR, a file that tells the build tool \fBjam\fR what to
Xbuild. It consists of invocations of rules defined by the \fBjam\fR
Xboilerplate, \fBJambase\fR. \fBJambase\fR itself defines rules that
Xprovide roughly \fBmake\fR(1)-like functionality.
X.PP
XThe first section is a one-page overview of \fBjam\fR, to introduce the
Xsyntax. The remaining sections are examples and discussion.
X.PP
XThis description goes with \fBJam\fR Release 2.0.
X.SH JAM OVERVIEW
X.SS Invocation
X.PP
XThe examples in the following sections are parts of a \fBJamfile\fR.
XOnce you have written a \fBJamfile\fR, you can invoke \fBjam\fR to
Xbuild things. The simplest syntax is:
X.BB
Xjam [-n]
X.BE
X.PP
XThe \fB-n\fR tells \fBjam\fR to do a verbose dry-run.
X.SS Rules
X.PP
XThe \fBjam\fR language consists mostly of rule invocations. A rule is
Xinvoked with \fItargets\fR and \fIsources\fR. That is,
X.BB
XRule targets : sources ;
X.BE
X.PP
XEach rule definition has potentially two parts: the rule procedure
Xand the rule's actions. The procedure is just more \fBjam\fR
Xstatements to interpret when the rule is invoked. The actions are
Xthe shell commands to execute when the targets are to be updated.
X.PP
XThe \fBJambase\fR consists mostly of rule definitions, and your
X\fBJamfile\fR will contain mostly rule invocations.
X.SS Variables
X.PP
X\fBJam\fR has two types of variables: global ones and target-specific
Xones. The latter take effect only when the named target is being
Xbound, scanned for header files, or updated. Target-specific variables
Xenable generic actions (like the \fICc\fR rule's call to the C
Xcompiler) to be used for different targets. Only the target-specific
Xvariables (HDRS, CCFLAGS, etc.) vary.
X.PP
XThe \fBJambase\fR rules use variables in three ways:
X.IP "Procedure Input"
XIf a variable is procedure input, it must be set before invoking the
Xrule. This is sometimes used to pass additional parameters to the rule
X(beyond the targets and sources), and is sometimes used for conditional
Xdefinitions (e.g., if the RANLIB variable is set, invoke the
X\fIRanlib\fR rule). When we describe the variables in each section, we
Xmark procedure input variables with a *.
X.IP "Procedure Output"
XA rule procedure may set variables for later use. Except where noted,
Xall rules set these variables specific to the rule's targets.
XSometimes the variable are later used during the binding and header
Xfile scanning phase, and sometimes they are used by the actions.
X.IP "Actions Input"
XThe shell commands to update a target often contain variable references.
XThese variables may be set globally or target-specific. The latter take
Xprecedence.
X.PP
XOften, a variable will be used in more than just way: a variable set by
Xa rule procedure may quite likely be used by the actions. In some
Xcases, a variable that is input to a rule procedure may be output
X(target-specific) as well. This has the effect of freezing the
Xvariable's value for the target.
X.SS Whitespace Note
X.PP
X\fBJam\fR requires whitespace (blanks, tabs, or newlines) to surround
Xall tokens, including the colon (:) and semicolon (;)
Xtokens. This is because \fBjam\fR runs on many platforms and no
Xcharacters, save whitespace, are uncommon in the file names on all of
Xthose platforms.
X.SH BUILDING EXECUTABLES AND LIBRARIES
X.PP
XThe following rules compile source files and build executables and
Xlibraries.
X.SS Main Rule
X.PP
XThe \fIMain\fR rule compiles source files and links the resulting
Xobjects into an executable.
X.XB
XMain myprog : main.c util.c ;
X.XE
X.PP
XThis compiles main.c and util.c and links main.o and util.o into myprog.
XAs with all rules that compile source files, \fIMain\fR handles header file
Xdependencies automatically.
X.SS Library Rule
X.PP
XThe \fILibrary\fR rule compiles source files, archives the
Xresulting object files into a library, and then deletes the object
Xfiles.
X.XB
XLibrary libstring.a : strcmp.c strcpy.c strlen.c ;
XLibrary libtree.a : treemake.c treetrav.c ;
X.XE
X.PP
XThis compiles five source files, archives three of the object files
Xinto libstring.a and the other two into libtree.a. Once the
Xobjects are safely in the libraries, the objects are deleted.
X.SS LinkLibraries Rule
X.PP
XTo tell \fBjam\fR to link executables against libraries, you use the
X\fILinkLibraries\fR rule.
X.XB
XMain myprog : main.c util.c ;
XLinkLibraries myprog : libstring.a libtree.a ;
X
XLibrary libstring.a : strcmp.c strcpy.c strlen.c ;
XLibrary libtree.a : treemake.c treetrav.c ;
X.XE
X.PP
XThe \fILinkLibraries\fR rule does two things: it makes the libraries
Xdependencies of the executable, so that they get built first; and it
Xmakes the libraries show up on the command line that links the
Xexecutable. The ordering of the lines above is not important, because
X\fBjam\fR builds targets in the order that they are needed.
X.PP
XYou can put multiple libraries on a single invocation of the
X\fILinkLibraries\fR rule, or you can provide them in multiple
Xinvocations. In both cases, the libraries appear on the link command
Xline in the order in which they were encountered. You can also provide
Xmultiple executables to the \fILinkLibraries\fR rule, if they
Xneed the same libraries.
X.SS Variables
X.PP
XThe following variables control the linking of executables and the
Xarchiving of libraries.
X.BB
X$(AR) archive command (ar ru)
X$(EXEMODE) * default value for MODE (711)
X$(LINK) linker command (cc)
X$(LINKFLAGS) linker flags ()
X$(LINKLIBS) additional libraries that aren't dependencies ()
X$(MODE) permission on target
X$(RANLIB) name of ranlib program, if any (ranlib)
X.BE
X.PP
X\fIMain\fR sets a target-specific MODE to the current value of $(EXEMODE).
X.PP
XThe difference between and the arguments to \fILinkLibraries\fR
Xand the value of $(LINKLIBS) is that the former are expected to be
Xreal, buildable libraries, while the latter are just handed without
Xinspection to the $(LINK) command. The ordering on the link
Xcommand line is first \fILinkLibraries\fR and then $(LINKLIBS).
X.XB
XMain xprog : xprog.c ;
XLinkLibraries xprog : libxutil.a ;
XLINKFLAGS on xprog = -Bstatic ;
XLINKLIBS on xprog = -lXext -lX11 ;
X
XLibrary libxutil.a : xtop.c xbottom.c xutil.c ;
X.XE
X.PP
XThis example uses the \fBjam\fR syntax "variable \fIon\fR target" to
Xset a target-specific variable. In this way, only xprog will be linked
Xwith these special $(LINKFLAGS) and $(LINKLIBS), even if other
Xexecutables were going to be built by the same \fBJamfile\fR. The
Xactual link command line would look like this:
X.BB
Xcc -Bstatic -o xprog xprog.o libuxtil.a -lXext -lX11
X.BE
X.PP
XNote that the default link command is cc.
X.SH COMPILING
X.PP
XCompiling of source files occurs normally as a byproduct of the
X\fIMain\fR or \fILibrary\fR rules. If you want to control the
Xcompiling process with finer granularity, you can use the rules
Xdescribed here. \fIMain\fR and \fILibrary\fR use these rules.
X.SS Objects Rule
X.PP
XThe \fIMain\fR or \fILibrary\fR rules call the \fIObjects\fR rule on each of
Xtheir source files. You can also call \fIObjects\fR directly.
X.XB
XObjects a.c b.c c.c ;
X.XE
X.PP
XThis compiles a.c into a.o, b.c into b.o, etc.
X.SS Object Rule
X.PP
X\fIObjects\fR gets its work done by calling the \fIObject\fR rule on
Xeach of the source files, making the assumption that the object name
Xitself will be the source file name, with the suffix replaced
Xappropriately. To compile a single source file directly, use the
X\fIObject\fR rule.
X.XB
XObject foo.o : foo.c ;
X.XE
X.PP
XThe \fIObject\fR rule doesn't require that the object name bear any
Xrelationship to the source. It is thus possible to compile the same
Xfile into different objects.
X.XB
XObject a.o : foo.c ;
XObject b.o : foo.c ;
XObject c.o : foo.c ;
X.XE
X.PP
XThis compiles foo.c (three times) into a.o, b.o, and c.o. Later examples
Xshow how this is useful.
X.PP
XThe \fIObject\fR rule looks at the suffix of the source file and calls
Xthe appropriate rules to do the actual compiling. This invariably
Xinvolves a call to the \fICc\fR to turn the .c into a .o, but may also
Xrequire a call to other rules to turn the source file into a .c.
XThus the \fIObject\fR rule is responsible for the generation of an
Xobject file from any type of source.
X.XB
XObject grammar.o : grammar.y ;
XObject scanner.o : scanner.l ;
XObject fastf.o : fastf.f ;
XObject util.o : util.c ;
X.XE
X.PP
XIn addition to calling the compiling rule, \fIObject\fR sets up a bunch
Xof variables specific to the source and target files. These are discussed
Xbelow.
X.SS Cc, C++, Yacc, Lex, Fortran, As, etc. Rules
X.PP
XThe \fIObject\fR calls compiling rules specific to the suffix of the
Xsource file. Because the extra work done by the \fIObject\fR rule, it
Xis not always useful to call the compiling rules directly. But the
Xadventurous user might attempt it.
X.XB
XYacc grammar.c : grammar.y ;
XLex scan.c : scan.l ;
XCc prog.o : prog.c ;
X.XE
X.PP
XThese examples individually run \fByacc\fR(1), \fBlex\fR(1), and the
XC compiler on their sources.
X.SS UserObject Rule
XAny files with suffixes not understood by the \fIObject\fR rule are
Xpassed to the \fIUserObject\fR rule. The default definition of
X\fIUserObject\fR simply emits a warning that the suffix is not understood.
XThis rule definition is intended to be replaced with one that
Xrecognizes the suffix.
X.XB
Xrule UserObject
X{
X switch $(>)
X {
X case *.s : As $(<) : $(>) ;
X case * : ECHO "unknown suffix on" $(>) ;
X }
X}
X
Xrule As
X{
X DEPENDS $(<) : $(>) ;
X}
X
Xactions As
X{
X as -o $(<) $(>)
X}
X
XLibrary libsys.a : alloca.s memcpy.s ;
X.XE
X.PP
XIt should be mentioned that this example is contrived, in that the \fB.s\fR
Xsuffix is already handled by \fIObject\fR.
X.SS LibraryFromObjects Rule
X.PP
XSometimes the \fILibrary\fR rule's straightforward compiling of source
Xinto object modules to be archived isn't flexible enough. The
X\fILibraryFromObjects\fR rule does the archiving (and deleting) job
Xof the \fILibrary\fR rule, but not the compiling. The user can make
Xuse of the \fIObjects\fR or \fIObject\fR rule for that.
X.XB
XLibraryFromObjects libfoo.a : max.o min.o ;
XObject max.o : maxmin.c ;
XObject min.o : maxmin.c ;
XObjectCcFlags max.o : -DUSEMAX ;
XObjectCcFlags min.o : -DUSEMIN ;
X.XE
X.PP
XThis compiles the same source file into two different objects, with
Xdifferent compile flags, and archives them. The
X\fIObjectCcFlags\fR rule is described shortly.
X.SS MainFromObjects Rule
X.PP
XSimilar to \fILibraryFromObjects\fR, \fIMainFromObjects\fR does the linking
Xpart of the \fIMain\fR rule, but not the compiling.
X.XB
XMainFromObjects w : w.o ;
XMainFromObjects uptime : uptime.o ;
XObject w.o : uptime.c ;
XObject uptime.o : uptime.c ;
XObjectCcFlags w.c : -DW_CODE ;
X.XE
X.PP
XThis compiles two different programs, w and uptime, from the same
Xsource file with different C compiler flags. Another use of
X\fIMainFromObjects\fR is when there are no objects at all, and
Xeverything is to be loaded from libraries.
X.XB
XMainFromObjects testprog ;
XLinkLibraries testprog : libprog.a ;
XLibrary libprog.a : main.c util.c ;
X.XE
XThis generates a link command that looks like this:
X.BB
Xcc -o testprog libprog.a
X.BE
X.PP
XLinking purely from libraries is something that doesn't work everywhere:
Xit depends on the symbol "main" being undefined when the linker encounters
Xthe library that contains the definition of "main".
X.SS Variables
X.PP
XThe following variables control the compiling of source files.
X.BB
X$(C++) The C++ Compiler (gcc)
X$(C++FLAGS) * C++ compiler flags()
X$(CC) The C Compiler (cc)
X$(CCFLAGS) * C compiler flags()
X$(HDRS) * non-standard header directories ()
X$(LEX) The Lex program (lex)
X$(OPTIM) optimization flag, if desired (-O)
X$(STDHDRS) * standard header directories (/usr/include)
X$(SUBDIRC++FLAGS) * Per-directory C++FLAGS
X$(SUBDIRCCFLAGS) * Per-directory CCFLAGS
X$(SUBDIRHDRS) * Per-directory HDRS
X$(YACC) The Yacc program (yacc -d)
X.BE
X.PP
XThe \fICc\fR rule sets a target-specific $(CCFLAGS) to the current
Xvalue of $(CCFLAGS) and $(SUBDIRCCFLAGS). Similarly for the \fIC++\fR
Xrule. The \fIObject\fR rule sets a target-specific $(HDRS) to the
Xcurrent value of $(HDRS) and $(SUBDDIRHDRS).
X.PP
X$(CC), $(C++), $(CCFLAGS), $(C++FLAGS), $(OPTIM), and $(HDRS) all affect
Xthe compiling of C and C++ files. $(OPTIM) is separate from $(CCFLAGS)
Xand $(C++FLAGS) so they can be set independently.
X.PP
X$(HDRS) lists the directories to search for header files, and it is
Xused in two ways: first, it is passed to the C compiler (with the flag
X\fB-I\fR prepended); second, it is used by \fIHdrRule\fR to locate the
Xheader files whose names were found when scanning source files.
X$(STDHDRS) lists the header directories that the C compiler already
Xknows about. It does not need passing to the C compiler, but is used
Xby \fIHdrRule\fR.
X.PP
XNote that these variables, if set as target-specific variables, must be
Xset on the target, not the source file. The target file in this case
Xis the object file to be generated.
X.XB
XLibrary libximage.a : xtiff.c xjpeg.c xgif.c ;
X
XHDRS on xjpeg.o = /usr/local/src/jpeg ;
XCCFLAGS on xtiff.o = -DHAVE_TIFF ;
X.XE
X.PP
XThis can be done more easily with the rules that follow.
X.SS ObjectCcFlags, ObjectC++Flags, ObjectHdrs Rules
X.PP
X$(CCFLAGS), $(C++FLAGS) and $(HDRS) can be manipulated directly, but there are
Xrules that allow these variables to be set by referring to the original
Xsource file name, rather than to the derived object file name.
X\fIObjectCcFlags\fR adds object-specific flags to the $(CCFLAGS) variable,
X\fIObjectC++Flags\fR adds object-specific flags to the $(C++FLAGS) variable,
Xand \fIObjectHdrs\fR add object-specific directories to the $(HDRS)
Xvariable.
X.XB
XMain xviewer : viewer.c ;
XObjectCcFlags viewer.c : -DXVERSION ;
XObjectHdrs viewer.c : /usr/include/X11 ;
X.XE
X.PP
XActually, the file suffix (\fB.c\fR in this case) is ignored: the
Xrules know to refer to the object.
X.SS SubDirCcFlags, SubDirC++Flags, SubDirHdrs Rules
X.PP
XThese rules set the values of $(SUBDIRCCFLAGS), $(SUBDIRC++FLAGS) and
X$(SUBDIRHDRS), which are used by the \fICc\fR, \fIC++\fR, and
X\fIObject\fR rules when setting the target-specific values for
X$(CCFLAGS), $(C++FLAGS) and $(HDRS). The \fISubDir\fR rule clears
Xthese variables out, and thus they provide directory-specific values of
X$(CCFLAGS), $(C++FLAGS) and $(HDRS).
X.XB
XSubDir TOP src util ;
X
XSubDirHdrs $(TOP)/src/hdr ;
XSubDirCcFlags -DUSE_FAST_CODE ;
X.XE
X.SH HEADER FILE PROCESSING
X.PP
XOne of the functions of the \fIObject\fR rule is to scan source files
Xfor (C style) header file inclusions. To do so, it sets the
X\fBjam\fR-special variables $(HDRSCAN) and $(HDRRULE) as
Xtarget-specific variables for the source file. The presence of these
Xvariables triggers a special mechanism in \fBjam\fR for scanning a file
Xfor header file inclusions and invoking a rule with the results of the
Xscan. The $(HDRSCAN) variable is set to an \fBegrep\fR(1) pattern that
Xmatches "#include" statements in C source files, and the $(HDRRULE)
Xvariable is set to the name of the rule that gets invoked as such:
X.BB
X$(HDRRULE) source-file : included-files ;
X.BE
X.PP
XThis rule is supposed to set up the dependencies between the source
Xfile and the included files. The \fIObject\fR rule uses
X\fIHdrRule\fR to do the job. \fIHdrRule\fR itself expects another
Xvariable, $(HDRSEARCH), to be set to the list of directories where the
Xincluded files can be found. \fIObject\fR does this as well, setting
X$(HDRSEARCH) to $(HDRS) and $(STDHDRS).
X.PP
XThe header file scanning occurs during the "file binding" phase of
X\fBjam\fR, which means that the target-specific variables (for the
Xsource file) are in effect. To accomodate nested includes, one of the
X\fIHdrRule\fR's jobs is to pass the target-specific values of
X$(HDRRULE), $(HDRSCAN), and $(HDRSEARCH) onto the included files, so
Xthat they will be scanned as well.
X.SS HdrRule Rule
X.PP
X\fIHdrRule\fR can be invoked directly, but it is most usable as the
Xboilerplate in a user-defined $(HDRRULE).
X.XB
XMain mkhdr : mkhdr.c ;
XMain ugly : ugly.c ;
X
XHDRRULE on ugly.c = BuiltHeaders ;
X
Xrule BuiltHeaders
X{
X DEPENDS $(>) : mkhdr ;
X HdrRule $(<) : $(>) ;
X}
X.XE
X.PP
XThis example just says that the files included by "ugly.c" are generated
Xby the program "mkhdr", which can be built from "mkhdr.c". By calling
X\fIHdrRule\fR at the end of \fIBuiltHeaders\fR, all the gadgetry of
X\fIHdrRule\fR takes effect and it doesn't need to be duplicated.
X.SS Variables
X.PP
XThe complete list of variables used by the \fIHdrRule\fR coterie are:
X.BB
X$(HDRPATTERN) * scan pattern for $(HDRSCAN) (ugly egrep expression)
X$(HDRRULE) scan rule, when set activates scanning (HdrRule)
X$(HDRS) * non-standard directories for headers ()
X$(HDRSCAN) scan pattern when actually scanning ($(HDRPATTERN))
X$(HDRSEARCH) search list for HdrRule ($(HDRS) $(STDHDRS))
X$(STDHDRS) * standard directories for headers (/usr/include)
X.BE
X.PP
XThe \fIObject\fR rule sets HDRRULE and HDRSCAN specifically for the
Xsource files to be scanned, rather than globally. If they were set
Xglobally, \fBjam\fR would attempt to scan all files, even library
Xarchives and executables, for header file inclusions. That would
Xbe slow and probably not yield desirable results.
X.SH COPYING FILES
X.SS File Rule
XThe \fIFile\fR rule copies one file to another.
XThe target name needn't bear any relationship to the source name.
X.XB
XFile $(DESTDIR)/foo : bar ;
X.XE
X.SS Bulk Rule
XThe \fIBulk\fR rule is a shorthand for many invocations of the \fIFile\fR
Xrule when all files are going to the same directory.
X.XB
XBulk /usr/local/lib/grob : grobvals.txt grobvars.txt ;
X.XE
X.SS HardLink Rule
XThe \fIHardLink\fR rule makes a hard link (using \fBln\fR(1)) from the
Xsource to the target, if there isn't one already.
X.XB
XHardLink config.h : config.h.dist ;
X.XE
X.SS Shell Rule
XThe \fIShell\fR rule is like the \fIFile\fR rule, except that it makes
Xsure the first line of the target is "#!/bin/sh" and sets the permission
Xto make the file executable.
X.XB
XShell /usr/local/bin/add : add.sh ;
X.XE
X.SS Variables
XThe following variables are used when copying files:
X.BB
X$(FILEMODE) * default value for MODE for files (644)
X$(SHELLHEADER) first line of shell scripts (#!/bin/sh)
X$(SHELLMODE) * default value for MODE for shell scripts (755)
X$(MODE) permission on target
X.BE
X.PP
X\fIFile\fR and \fRShell\fR sets a target-specific MODE to the current value
Xof $(FILEMODE) or $(SHELLMODE), respectively.
X.XB
XShell /usr/local/bin/add : add.awk ;
XSHELLHEADER on /usr/local/bin/add = "#!/bin/awk -f" ;
X.XE
X.PP
XThis installs an \fBawk\fR(1) script.
X.SH INSTALLING FILES
X.SS InstallBin Rule
X.PP
X\fIInstallBin\fR calls \fBinstall\fR(1) to install executables in
Xthe target directory. $(BINDIR) is set to /usr/local/bin for convenience.
X.XB
XMain add : add.c ;
XMain sub : sub.c ;
XInstallBin $(BINDIR) : add sub ;
X.XE
X.SS InstallLib Rule
X\fIInstallLib\fR calls \fBinstall\fR(1) to install files in the target
Xdirectory. $(LIBDIR) is set to /usr/local/lib for convenience.
X.XB
XInstallLib $(LIBDIR) : bighelp.txt ;
X.XE
X.SS InstallMan Rule
X.PP
X\fIInstallMan\fR calls \fBinstall\fR(1) to install manual pages in
Xthe appropriate subdirectories of the target directory. $(MANDIR)
Xis set to /usr/local/man for convenience.
X.XB
XInstallMan $(MANDIR) : add.1 sub.1 bigfile.8 ;
X.XE
X.SS InstallShell Rule
X.PP
X\fIInstallShell\fR calls \fBinstall\fR(1) to install shell scripts in
Xthe target directory.
X.XB
XShell bugs : bugs.sh ;
XInstallShell $(BINDIR) : bugs ;
X.XE
X.PP
XThe difference between \fIShell\fR and \fIInstallShell\fR is not much: they
Xboth copy the source to the target. The former also makes
Xsure the script begins with the magic string "#!/bin/sh"; the latter uses
X\fBinstall\fR(1) for the copy.
X.SS MkDir Rule
X.PP
XAll the \fIInstall\fR rules invoke the \fIMkDir\fR rule to create the
Xdirectory for the target file. \fIMkDir\fR recursively invokes itself
Xon its parent directory, to make sure the whole path gets created.
X\fIMkDir\fR marks directories with the built-in rule \fINOUPDATE\fR,
Xwhich tells \fBjam\fR not to update a target once it exists. In that
Xway, the contents of the install directory can depend on the existence
Xof the install directory itself, and thus the directory will be made
Xbefore its contents are installed. You can call \fIMkDir\fR directly.
X.XB
XFile /usr/local/bin/junky : junky ;
XDEPENDS /usr/local/bin/junky : /usr/local/bin ;
XMkDir /usr/local/bin ;
X.XE
X.PP
XThis says that /usr/local/bin must be created before /usr/local/bin/junky
Xcan be built. Needless to say, \fBjam\fR can't do much if you don't have
Xpermissions to create directories along the path.
X.SS Variables
X.PP
XThe following variables control the installation rules:
X.BB
X$(BINDIR) InstallBin directory (/usr/local/bin)
X$(LIBDIR) InstallLib directory (/usr/local/lib)
X$(MANDIR) InstallMan directory (/usr/local/man)
X$(INSTALL) The install program; uses cp if not set (install)
X$(FILEMODE) * default MODE for InstallLib, InstallMan (644)
X$(EXEMODE) * default MODE for InstallBin (711)
X$(SHELLMODE) * default MODE for InstallShell (755)
X$(MODE) permission on target
X$(MKDIR) Program for creating a directory (mkdir)
X.BE
X.PP
XThe \fIInstall\fR rules set a target-specific MODE to the current value
Xof $(FILEMODE), $(EXEMODE), or $(SHELLMODE), depending on which \fIInstall\fR
Xrule was invoked.
X.PP
XThe directory variables are just defined for convenience: they must
Xbe passed as the target to the appropriate \fIInstall\fR rule.
XThe $(INSTALL) and mode variables must be set (globally) before
Xcalling the \fIInstall\fR rules in order to take effect.
X.SH HANDLING DIRECTORY TREES
X.PP
X\fBJam\fR can build large projects spread across many directories in
Xone pass, tracking the relationships among all files. It doesn't
Xrequire the user to change the invocations of normal rules like
X\fIMain\fR, \fILibrary\fR, etc. to use non-local pathnames: these
Xrules continue to refer to files in the directory of the
X\fBJamfile\fR. This section describes the rules and
Xvariables which support this.
X.PP
XTo build a whole directory tree at a time, the user must do three
Xthings:
X.IP 1.
XSet an environment variable pointing to the root directory of the
Xsource tree. The root variable's name is left up to the user, but in these
Xexamples we use TOP.
X.IP 2.
XPlace at the root of the tree a file named \fBJamrules\fR. (This file
Xcan alternately be named by the variable $(xxxRULES), where xxx is the
Xname of the root variable). This file could be empty, but in practice
Xit contains user-provided rules and variable definitions that are
Xshared throughout the tree. Examples of such definitions are library
Xnames, header directories, install directories, compiler flags, etc.
XThis file is good candidate for automatic customizing with
X\fBautoconf\fR(GNU).
X.IP 3.
XPreface the \fBJamfile\fR in each directory with an invocation of
Xthe \fISubDir\fR rule.
X.SS SubDir Rule
X.PP
XThe \fISubDir\fR rule does two things:
X.IP 1.
XIt reads in the \fBJamrules\fR at the root of the tree, if that file
Xhasn't already been read in by a previous invocation of \fISubDir\fR.
X.IP 2.
XIt sets a few variables that tell \fBjam\fR the name of the
X\fBJamfile\fR's directory, so that \fBjam\fR may find source files that
Xare named local to the \fBJamfile\fR's directory.
X.PP
XThe \fISubDir\fR rule takes as its first argument the root variable's
Xname and takes as subsequent arguments the directory names leading from
Xthe root to the directory of the current \fBJamfile\fR. Note that the
Xname of the subdirectory is given as individual elements: the
X\fISubDir\fR rule does not use system-specific directory name syntax.
X.PP
XThe \fISubDir\fR rule must be invoked before any rules that refer to
Xthe contents of the directory - it is best to put it at the top of each
X\fBJamfile\fR.
X.XB
X# Mondo src/util directory.
X
XSubDir TOP src util ;
X
XMain $(TOP)/bin/testutil : test.c ;
X
XLinkLibraries $(TOP)/bin/testutil : $(TOP)/lib/libutil.a ;
X
XLibrary $(TOP)/lib/libutil.a : gadgets.c gizmos.c widgets.c ;
X.XE
X.PP
XThis compiles four files in $(TOP)/src/util, archives three of the
Xobjects into libutil.a, and links the whole thing into $(TOP)/bin/testutil.
X.SS SubInclude Rule
X.PP
XThe \fISubInclude\fR rule sources the \fBJamfile\fR from the named
Xsubdirectory. Its arguments are in the same format as \fISubDir\fR's, and
Xits only reason for being is to allow including a subdirectory
X\fBJamfile\fR without having to use system-specific directory name
Xsyntax.
X.PP
XThe recommended practice is only to include one level of subdirectories
Xat a time, and let the \fBJamfile\fR in each subdirectory include its
Xown subdirectories. This allows a user to sit in any arbitrary directory
Xof the source tree and build that subtree.
X.XB
X# Top level Jamfile for mondo project.
X#
X# $(TOP) points to root of mondo tree (set in environment).
X
XSubInclude TOP src ;
XSubInclude TOP man ;
XSubInclude TOP misc ;
XSubInclude TOP util ;
X.XE
X.PP
XIf a directory has both subdirectories of its own as well as files that
Xneed building, the \fISubIncludes\fR should be either before the
X\fISubDir\fR rule or be at the end of the \fBJamfile\fR - \fInot\fR
Xbetween the \fISubDir\fR and other rule invocations.
X.XB
X# Mondo src code.
X
XSubDir TOP src ;
X
XMain mondo : mondo.c ;
XLinkLibraries mondo : $(TOP)/lib/libmisc.a $(TOP)/lib/libutil.a ;
X
XSubInclude TOP src misc ;
XSubInclude TOP src util ;
X.XE
X.SS Variables
XThe following variables are used when \fBjam\fR spans multiple directories:
X.BB
X$(LOCATE_TARGET) Directory to place targets.
X$(SEARCH_SOURCE) Directory to find sources.
X$(SOURCE_GRIST) Something to perturb source file names.
X.BE
X.PP
X\fISubDir\fR sets $(LOCATE_TARGET) and $(SEARCH_SOURCE) to be the
Xdirectory given to \fISubDir\fR. These variables are used extensively
Xby rules in \fBJambase\fR: most rules that generate targets (like
X\fIMain\fR, \fIObject\fR, etc.) set $(LOCATE) to be $(LOCATE_TARGET)
Xfor the targets they generate, and rules that use sources (most all of
Xthem) set $(SEARCH) to be $(SEARCH_SOURCE) for the sources they use.
X.PP
X$(LOCATE) and $(SEARCH) are better explained in \fBjam\fR(1), but in
Xbrief they tell \fBjam\fR where to create new targets and where to find
Xexisting ones, respectively.
X.PP
X\fISubDir\fR sets $(SOURCE_GRIST) to be a value derived from the
Xdirectory name. $(SOURCE_GRIST) is used by the rules that take
Xsource files to perturb file names in different directories that
Xwould otherwise be the same.
X.PP
XIt should be noted that the user can set these variables independently
Xof \fISubDir\fR, or after it. The most profitable example is setting
X$(LOCATE_TARGET) to be a directory outside the source tree: in this
Xcase, \fBjam\fR can build into a target directory (tree) without ever
Xmodifying the source tree.
X.SS VMS Notes
X.PP
XOn VMS, the logical name table is not imported as is the environment
Xon UNIX. To use the \fISubDir\fR and related rules, you must
Xset the value of the variable that names the root directory.
X.XB
XTOP = USR_DISK:[JONES.SRC] ;
X
XSubInclude TOP util ;
X.XE
X.PP
XThe variable must have a value that looks like a directory or device.
XIf you choose, you can use a concealed logical.
X.XB
XTOP = TOP: ;
X
XSubInclude TOP util ;
X.XE
X.PP
XThe \fB:\fR at the end of TOP makes the value of $(TOP) look like a
Xdevice name, which \fBjam\fR respects as a directory name and will use
Xwhen trying to access files. TOP must then be defined from DCL:
X.BB
X$ define/job/translation=concealed TOP DK100:[USERS.JONES.SRC.]
X.BE
X.PP
XNote three things: the concealed translation allows the logical to be
Xused as a device name; the device name in the logical (here DK100)
Xcannot itself be concealed logical (VMS rules, man); and the directory
Xcomponent of the definition must end in a period (more VMS rules).
X.SH MISCELLANEOUS RULES
X.SS Clean Rule
X.PP
XThe \fIClean\fR rule has only a simple action: to delete all of its
Xsources. It is normally invoked with generated files as sources, so
Xthat they can be cleaned out. \fIClean\fR must invoked with a target
Xas well, as different sets of files might be cleaned on with different
Xtargets. To actually remove the files to be cleaned, you invoke
X\fBjam\fR with the target name on the command line.
X.XB
XClean zap : junk1 junk2 junk3 ;
X.XE
X.PP
XSaying "\f(CWjam zap\fP" would cause it to delete junk1, junk2, and junk3.
X.PP
XAll rules listed in this manual page that generate targets, except the
X\fIInstall\fR rules, invoke the following \fIClean\fR rule:
X.BB
XClean clean : $(<) ;
X.BE
X.PP
XThe \fIInstall\fR rules invoke the following:
X.BB
XClean uninstall : $(<) ;
X.BE
X.PP
XThus a "\f(CWjam uninstall\fP" removes anything created with the \fIInstall\fR
Xrules, and a "\f(CWjam clean\fP" removes anything created by the other rules
Xlisted in this manual page. It should be noted that \fBjam\fR's cleaning
Xmechanism gets rid of exactly the files it created, not miscellaneous junk
Xleft around by the user.
X.PP
XGiven user-defined targets, the \fIClean\fR rule can selectively
Xremove other generated files.
X.XB
Xrule M4
X{
X # File depends on it's m4 source
X
X DEPENDS $(<) : $(>) ;
X
X Clean m4clean : $(<) ;
X}
X
Xactions M4
X{
X m4 < $(>) > $(<)
X}
X.XE
X.PP
XHere a "\f(CWjam m4clean\fR" would remove all files created by \fBm4\fR.
X.SS RmTemps Rule
X.PP
XSome intermediate files are meant to be temporary. The \fIRmTemps\fR
Xrule marks such files with the \fITEMPORARY\fR rule, and then deletes
Xthem after they are used. To delete them only when they are finished
Xbeing used, \fIRmTemps\fR must be the last rule (with actions) invoked on
Xthe target that uses the temporary files, and the sources to
X\fIRmTempts\fR must be the temporary files themselves.
X.XB
XSpecialUserRuleA foo : bar ;
XSpecialUserRuleB ola : foo ;
XRmTemps ola : foo ;
X.XE
X.PP
XThis says: build "foo" using \fISpecialUserRuleA\fR and "ola"
Xusing \fISpecialUserRuleB\fR. Once that is done, remove "foo".
X.SH SPECIAL TARGETS
X.PP
X\fBJam\fR has only one special target: \fIall\fR, which it tries
Xto build if no targets are on the command line. \fBJambase\fR defines
Xseveral special targets which are dependencies of \fIall\fR:
X.BB
Xall - parent of first, shell, files, lib, exe
Xfirst - first dependency of 'all', for potential initialization
Xshell - parent of all Shell targets
Xfiles - parent of all File targets
Xlib - parent of all Library targets
Xexe - parent of all Main target
Xdirs - parent of all MkDir targets
Xclean - removes all Shell, File, Library, and Main targets
Xuninstall - removes all Install targets
X.BE
X.PP
X\fBJambase\fR marks all of these targets with \fBjam\fR's \fINOTFILE\fR
Xattribute, meaning that they aren't to be found in the filesystem. You
Xcan build selected components by giving \fIshell\fR, \fIfiles\fR,
X\fIlib\fR, \fIexe\fR, or \fIdirs\fR as targets on the command line.
XYou can remove the files that \fBjam\fR built giving \fIclean\fR and
X\fIuninstall\fR as targets. And you can arrange for \fBjam\fR to run
Xinitialization commands by putting actions on the target \fIfirst\fR.
X.XB
Xactions Initialize
X{
X ECHO "This is a test of the jam initialization system."
X}
X
XInitialize first ;
X.XE
X.PP
XThis only gets run if \fBjam\fR is invoked with the \fIall\fR or \fIfirst\fR
Xtargets, or no target at all.
X.SH JAM BUILT-IN RULES AND VARIABLES
X.PP
XThis section discusses \fBjam\fR's built-in rules and variables. They
Xare described in \fBjam\fR(1) more precisely. Built-in rules are
Xuppercase, as opposed to the mixed-case rules defined by
X\fBJambase\fR. These built-in rules, along with the other \fBjam\fR
Xsyntax for manipulating variables, provide the foundation upon which
Xthe \fBJambase\fR is built. A \fBJamfile\fR, or (more likely) a
X\fBJamrules\fR (q.v.), can make use of these built-in rules and
Xvariables as well.
X.SS DEPENDS, INCLUDES Rules
X.PP
XTwo rules build the dependency graph. \fIDEPENDS\fR simply makes
Xits sources dependencies of its targets. \fIINCLUDES\fR makes its
Xsources dependencies of anything of which its targets are
Xdependencies. This reflects the dependencies that arise when one
Xsource file includes another: the object built from the source file
Xdepends both on the original and included source file, but the two
Xsources files don't depend on each other.
X.XB
XDEPENDS foo.o : foo.c ;
XINCLUDES foo.c : foo.h ;
X.XE
X.PP
XBoth "foo.c" and "foo.h" become dependencies of "foo.o" in this example.
X.SS ALWAYS, LEAVES, NOCARE, NOTFILE, NOUPDATE, TEMPORARY Rules
X.PP
XSix rules mark targets so that \fBjam\fR treats them differently
Xduring its target binding and updating phase. Normally, \fBjam\fR
Xupdates a target if it is missing, if its filesystem modification time
Xis older than any of its dependencies (recursively), or if any of its
Xdependencies are being updated. This basic behavior can be changed by
Xinvoking the following rules with the target name as the rule's
Xtarget:
X.PP
XThe \fIALWAYS\fR rule causes its targets to be always updated. This is
Xused for the \fIclean\fR and \fIuninstall\fR targets, as they have no
Xdependencies and would otherwise appear never to need building. It is
Xbest applied to targets that are also \fINOTFILE\fR targets, but it
Xcan also be used to force a real file to be updated as well.
X.PP
XThe \fINOCARE\fR rule causes \fBjam\fR to ignore its targets if they
Xcan't be found and have no updating actions. Normally, \fBjam\fR
Xissues a warning about a target that can't be built and then refuses to
Xbuild anything that depends on that target. The \fIHdrRule\fR uses
X\fINOCARE\fR on the header file names found during header file
Xscanning, to let \fBjam\fR know that the included files may not exist.
XFor example, if a #include is within an #ifdef, the included file may
Xnot actually be around.
X.PP
XThe \fINOTFILE\fR rule marks its targets as being pseudo targets, that
Xis, targets that aren't really files. The actions on such a target are
Xonly executed if the target's dependencies are updated, or if the target
Xis also marked with \fIALWAYS\fR. The \fIall\fR and \fIclean\fR
Xtargets are examples of such targets.
X.PP
XThe \fINOUPDATE\fR rule causes \fBjam\fR to ignore the modification
Xtime of the target. This has two effects: first, once the target has
Xbeen created it will never be updated; second, manually updating target
Xwill not cause other targets to be updated. This rule is applied to
Xdirectories by the \fIMkDir\fR rule, because \fIMkDir\fR only cares
Xthat the target directory exists, not when it has last been updated.
X.PP
XThe \fITEMPORARY\fR rule allows for targets to be deleted after they
Xare generated. If \fBjam\fR sees that a temporary target is missing,
Xit will use the target's parent's time when determining if the target
Xneeds updating. Object files that are also archived in a library are
Xmarked as such, so that they can be deleted after they are archived.
X.PP
XThe \fILEAVES\fR rule makes each of the targets depend only on its
X"leaf" dependencies. This makes it immune to its dependencies being
Xupdated, as the "leaf" dependencies are those without their own
Xdependencies and without updating actions. This allows a target to be
Xupdated only if original source files change.
X.SS ECHO, EXIT Rules
X.PP
XThese two rules help during the \fBJamfile\fR compiling phase.
XThe \fIECHO\fR rule just echoes its targets to the standard output.
XThe \fIEXIT\fR rule does the same and then does a brutal, fatal exit of
X\fBjam\fR.
X.SS SEARCH, LOCATE Variables
X.PP
XThese two variables control the binding of target names to real files:
Xthey indicate what path name is to be prepended to the target name to
Xget to the real file. $(SEARCH) provides a list of directories along
Xwhich \fBjam\fR scans looking for a target. $(LOCATE) overrides
X$(SEARCH), indicating the directory where the target must be.
XNormally, $(SEARCH) is set for existing targets while $(LOCATE) is set
Xfor the targets which \fBjam\fR must build. If neither $(SEARCH) nor
X$(LOCATE) are set, or if the name of the target is a rooted file name
X(i.e. on UNIX beginning with "/"), then the file name is assumed to be
Xthe target name.
X.PP
XBoth $(SEARCH) and $(LOCATE) should be set target-specific and not
Xglobally. If they were set globally, \fBjam\fR would use them for all
Xfile binding - including looking for the \fIJamfile\fR, and this is not
Xlikely to produce sane results. All of the rules defined in
X\fBJambase\fR (and described in this document) set $(SEARCH) and
X$(LOCATE) to sensible values for sources they are looking for and
Xtargets they create, respectively. These values are usually
X$(SEARCH_SOURCE) and $(LOCATE_TARGET), described above in the section
Xdescribing variables use when building whole directory trees. The header
Xfile processing rule \fIHdrRule\fR sets $(SEARCH) for header files
Xto be $(HDRS).
X.PP
XWhen writing your own rules, especially ones not built upon those in
X\fBJambase\fR, you may need to set $(SEARCH) or $(LOCATE) directly.
XMost often you'll set them to the prevailing value of $(SEARCH_SOURCE)
Xor $(LOCATE_TARGET). The best examples are those in \fBJambase\fR.
X.SS HDRSCAN, HDRRULE Variables
X.PP
XThese two variable control header file scanning. The first is an
X\fBegrep\fR(1) pattern, with ()'s surrounding the file name, used to
Xfind file inclusion statements in source files. The second is the
Xname of a rule to invoke with the results of the scan: the scanned
Xfile is the target, the found files are the sources. This is the only
Xplace where \fBjam\fR invokes a rule through a variable setting.
X.PP
XBoth $(HDRSCAN) and $(HDRRULE) must be set for header file scanning to
Xtake place, and they should be set target-specific and not globally.
XIf they were set globally, all files, including executables and libraries,
Xwould be scanned for header file include statements.
X.PP
XThe scanning for header file inclusions is not exact, but it is at
Xleast dynamic. That is, there is no need to run something like
X\fBmakedepend\fR(GNU) to create a static dependency file. Because
X\fBjam\fR uses regular expressions to find include files, it can't
Xknow when an include is within #ifdefs or other conditional logic. To
Xmake up for this, \fIHdrRule\fR applies the \fINOCARE\fR rule to each
Xheader file, just in case it is bogus. Also, regular expressions only
Xwork where the included file name is literally in the source file.
XThey can't handle languages that allow including files using variable
Xnames (as \fBjam\fR's own langauge does).
X.SS JAMSHELL Variable (Unix Only)
X.PP
XWhen \fBjam\fR executes a rule's action block, it forks and
Xexecs a shell, passing the action block as an argument to the shell.
XThe invocation of the shell is controlled by $(JAMSHELL), whose default
Xvalue is:
X.BB
XJAMSHELL = /bin/sh -c % ;
X.BE
X.PP
XThe \fB%\fR is replaced with the text of the action block.
X.PP
XOn UNIX \fBjam\fR can build targets in parallel, as long as the
Xdependencies among files are properly spelled out and actions don't
Xcreate fixed named files in the current directory. (If either of those
Xtwo provisions are violated, \fBjam\fR can trip over itself when
Xbuilding in parallel things which just happen to build OK sequentially.)
XWhen building in parallel, \fBjam\fR simply forks off more than
Xone shell at a time.
X.PP
X\fBJam\fR does not directly support building in parallel across
Xmultiple hosts, since that is heavily dependent on the local
Xenvironment. To build in parallel across multiple hosts, you need to
Xwrite your own shell that provides access to the multiple hosts.
XYou then reset $(JAMSHELL) to reference it.
X.PP
XJust as \fBjam\fR expands a \fB%\fR to be the text of the rule's action
Xblock, it expands a \fB!\fR to be the multi-process slot number. The slot
Xnumber varies between 1 and the number of concurrent jobs permitted by
Xthe \fB-j\fR flag given on the command line. Armed with this, it is
Xpossible to write a multiple host shell.
X.XB
X#!/bin/sh
X
X# This sample JAMSHELL uses the SunOS on(1) command to execute
X# a command string with an identical environment on another host.
X#
X# Set JAMSHELL = jamshell ! %
X#
X# where jamshell is the name of this shell file.
X#
X# This version handles up to -j6; after that they get executed
X# locally.
X
Xcase $1 in
X1|4) on winken sh -c "$2";;
X2|5) on blinken sh -c "$2";;
X3|6) on nod sh -c "$2";;
X*) eval "$2";;
Xesac
X.XE
X.SH SEE ALSO
X\fBjam\fR(1), \fBJambase\fR(5)
X.SH BUGS
XThis document shouldn't be a manual page.
END_OF_FILE
if test 40692 -ne `wc -c <'Jamfile.5'`; then
echo shar: \"'Jamfile.5'\" unpacked with wrong size!
fi
# end of 'Jamfile.5'
fi
if test -f 'variable.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'variable.h'\"
else
echo shar: Extracting \"'variable.h'\" \(551 characters\)
sed "s/^X//" >'variable.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * variable.h - handle jam multi-element variables
X *


X * 08/23/94 (seiwald) - Support for '+=' (append to variable)

X */
X
XLIST *var_get();
Xvoid var_defines();
Xvoid var_set();
XLIST *var_swap();
XLIST *var_list();
Xint var_string();
X
X/*
X * Defines for var_set().
X */
X
X# define VAR_SET 0 /* override previous value */
X# define VAR_APPEND 1 /* append to previous value */
X# define VAR_DEFAULT 2 /* set only if no previous value */
X
END_OF_FILE
if test 551 -ne `wc -c <'variable.h'`; then
echo shar: \"'variable.h'\" unpacked with wrong size!
fi
# end of 'variable.h'
fi
echo shar: End of archive 4 \(of 7\).
cp /dev/null ark4isdone

Christopher Seiwald

unread,
Apr 11, 1995, 3:00:00 AM4/11/95
to
Submitted-by: sei...@tea.org (Christopher Seiwald)
Posting-number: Volume 47, Issue 112
Archive-name: jam/part05

Environment: UNIX, NT, VMS
Supersedes: jam: Volume 27, Issue 81-85

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".

# Contents: Jambase filesys.h jam.1 jamgram.c make1.c
# Wrapped by kent@ftp on Sat Mar 25 12:04:11 1995


PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 5 (of 7)."'
if test -f 'Jambase' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Jambase'\"
else
echo shar: Extracting \"'Jambase'\" \(23751 characters\)
sed "s/^X//" >'Jambase' <<'END_OF_FILE'
X#
X# /+\
X# +\ Copyright 1993, 1995 Christopher Seiwald.
X# \+/
X#
X# This file is part of Jam - see jam.c for Copyright information.
X#
X
X#
X# JAMBASE - jam 2.0 ruleset providing make(1)-like functionality
X#
X# Supports UNIX, NT, and VMS.
X#
X# 12/27/93 (seiwald) - purturb library sources with SOURCE_GRIST
X# 04/18/94 (seiwald) - use 'default =' when setting OS specific vars
X# 04/21/94 (seiwald) - do RmTemps together
X# 05/05/94 (seiwald) - all supported C compilers support -o: relegate
X# RELOCATE as an option; set Ranlib to "" to disable it
X# 06/01/94 (seiwald) - new 'actions existing' to do existing sources
X# 08/25/94 (seiwald) - new ObjectCcFlags rule to append to per-target CCFLAGS
X# 08/29/94 (seiwald) - new ObjectHdrs rule to append to per-target HDRS
X# 09/19/94 (seiwald) - LinkLibraries and Undefs now append
X# - Rule names downshifted.
X# 10/06/94 (seiwald) - Dumb yyacc stuff moved into Jamfile.
X# 10/14/94 (seiwald) - (Crude) support for .s, .C, .cc, .cpp, and .f files.
X# 01/08/95 (seiwald) - Shell now handled with awk, not sed
X# 01/09/95 (seiwald) - Install* now take dest directory as target
X# 01/10/95 (seiwald) - All entries sorted.
X# 01/10/95 (seiwald) - NT support moved in, with LauraW's help.
X# 01/10/95 (seiwald) - VMS support moved in.
X# 02/06/95 (seiwald) - ObjectC++Flags and SubDirC++Flags added.
X# 02/07/95 (seiwald) - Iron out when HDRSEARCH uses "" or SEARCH_SOURCE.
X# 02/08/95 (seiwald) - SubDir works on VMS.
X# 02/14/95 (seiwald) - MkDir and entourage.
X
X# Special targets defined in this file:
X#
X# all - parent of first, shell, files, lib, exe
X# first - first dependent of 'all', for potential initialization
X# shell - parent of all Shell targets
X# files - parent of all File targets
X# lib - parent of all Library targets
X# exe - parent of all Main targets
X# dirs - parent of all MkDir targets
X# clean - removes all Shell, File, Library, and Main targets
X# uninstall - removes all Install targets
X#
X
X# Rules defined by this file:
X#
X# as obj.o : source.s ; .s -> .o
X# Bulk dir : files ; populate directory with many files
X# Cc obj.o : source.c ; .c -> .o
X# C++ obj.o : source.cc ; .cc -> .o
X# Clean clean : sources ; remove sources with 'jam clean'
X# File dest : source ; copy file
X# Fortran obj.o : source.f ; .f -> .o
X# Hardlink target : source ; make link from source to target
X# HdrRule source : headers ; handle #includes
X# Install target : source ; install any single file
X# InstallBin dir : sources ; install binaries
X# InstallLib dir : sources ; install files
X# InstallMan dir : sources ; install man pages
X# InstallShell dir : sources ; install shell scripts
X# Lex source.c : source.l ; .l -> .c
X# Library lib : source ; archive library from compiled sources
X# LibraryFromObjects lib : objects ; archive library from objects
X# LinkLibraries images : libraries ; bag libraries onto Mains
X# Main image : source ; link executable from compiled sources
X# MainFromObjects image : objects ; link executable from objects
X# MkDir dir ; make a directory, if not there
X# Object object : source ; compile object from source
X# ObjectCcFlags source : flags ; add compiler flags for object
X# ObjectC++Flags source : flags ; add compiler flags for object
X# ObjectHdrs source : dirs ; add include directories for object
X# Objects sources ; compile sources
X# RmTemps target : sources ; remove temp sources after target made
X# Setuid images ; mark executables Setuid
X# SubDir TOP d1 d2 ... ; start a subdirectory Jamfile
X# SubDirCcFlags flags ; add compiler flags until next SubDir
X# SubDirC++Flags flags ; add compiler flags until next SubDir
X# SubDirHdrs dirs ; add include dirs until next SubDir
X# SubInclude TOP d1 d2 ... ; include a subdirectory Jamfile
X# Shell exe : source ; make a shell executable
X# Undefines images : symbols ; save undef's for linking
X# UserObject object : source ; handle unknown suffixes for Object
X# Yacc source.c : source.y ; .y -> .c
X#
X
X# Brief review of the jam language:
X#
X# Statements:
X# rule RULE - statements to process a rule
X# actions RULE - system commands to carry out target update
X#
X# Modifiers on actions:
X# together - multiple instances of same rule on target get executed
X# once with their sources ($(>)) concatenated
X# updated - refers to updated sources ($(>)) only
X# ignore - ignore return status of command
X# quietly - don't trace its execution unless verbose
X# piecemeal - iterate command each time with a small subset of $(>)
X# existing - refers to currently existing sources ($(>)) only
X#
X# Special rules:
X# ALWAYS - always build a target
X# DEPENDS - builds the dependency graph
X# ECHO - blurt out targets on stdout
X# EXIT - blurt out targets and exit
X# INCLUDES - marks sources as headers for target (a codependency)
X# NOCARE - don't panic if the target can't be built
X# NOUPDATE - create the target if needed but never update it
X# NOTFILE - ignore the timestamp of the target (it's not a file)
X# TEMPORARY - target need not be present if sources haven't changed
X#
X# Special variables set by jam:
X# $(<) - targets of a rule (to the left of the :)
X# $(>) - sources of a rule (to the right of the :)
X# $(UNIX) - true on UNIX
X# $(VMS) - true on VMS
X# $(NT) - true on NT
X# $(OS) - name of OS - varies wildly
X#
X# Special variables used by jam:
X# SEARCH - where to find something (used during binding and actions)
X# LOCATE - where to plop something not found with SEARCH
X# HDRRULE - rule to call to handle include files
X# HDRSCAN - egrep regex to extract include files
X#
X# Special targets:
X# all - default if none given on command line
X#
X
X# Initialize variables
X#
X# "default =" - set only if unset
X
X#
X# OS specific variable settings
X#
X
Xswitch $(OS)
X{
Xcase AIX : LINKLIBS default = -lbsd ;
Xcase DGUX : RANLIB default = "" ;
Xcase IRIX : RANLIB default = "" ;
Xcase HPUX : RANLIB default = "" ;
X INSTALL default = "" ;
Xcase PTX : RANLIB default = "" ;
Xcase SOLARIS : RANLIB default = "" ;
X}
X
Xif $(UNIX)
X{
X AR default = ar ru ;
X AS default = as ;
X AWK default = awk ;
X ASFLAGS default = ;
X BINDIR default = /usr/local/bin ;
X C++ default = gcc ;
X C++FLAGS default = ;
X CC default = cc ;
X CCFLAGS default = ;
X CP default = cp ;
X CHMOD default = chmod ;
X EXEMODE default = 711 ;
X FILEMODE default = 644 ;
X FORTRAN default = f77 ;
X FORTRANFLAGS default = ;
X HDRS default = ;
X INSTALL default = install ;
X LEX default = lex ;
X LIBDIR default = /usr/local/lib ;
X LINK default = $(CC) ;
X LINKFLAGS default = $(CCFLAGS) ;
X LINKLIBS default = ;
X LN default = ln ;
X MANDIR default = /usr/local/man ;
X MKDIR default = mkdir ;
X MV default = mv -f ;
X OPTIM default = -O ;
X RANLIB default = ranlib ;
X RM default = rm -f ;
X SHELLHEADER default = "#!/bin/sh" ;
X SHELLMODE default = 755 ;
X SLASH default = / ;
X STDHDRS default = /usr/include ;
X SUFLIB default = .a ;
X SUFOBJ default = .o ;
X SUFEXE default = "" ;
X UNDEFFLAG default = "-u _" ;
X YACC default = yacc -d ;
X}
Xelse if $(NT)
X{
X if $(BCCROOT)
X {
X ECHO "Compiler is Borland C++" ;
X
X AR default = tlib ;
X ARFLAGS default = /C /P64 ;
X CC default = bcc32 ;
X CCFLAGS default = -v -w- ;
X MV default = rename ;
X RM default = del ;
X RW default = $(BCCROOT)\\lib\\rw ;
X RWLIBPATH default = $(RW)\\lib ;
X LINK default = $(CC) ;
X LINKFLAGS default = $(CCFLAGS) ;
X SLASH default = \\ ;
X STDLIBPATH default = $(BCCROOT)\\lib ;
X STDHDRS default = $(BCCROOT)\\include ;
X SUFLIB default = .lib ;
X SUFOBJ default = .obj ;
X SUFEXE default = .exe ;
X }
X else if $(MSVCNT)
X {
X ECHO "Compiler is Microsoft Visual C++" ;
X
X AR default = lib ;
X CC default = cl ;
X CCFLAGS default = /D \"NT\" ;
X MV default = rename ;
X RM default = del ;
X RW default = $(MSVCNT)\\lib\\rw ;
X RWLIBPATH default = $(RW)\\lib ;
X LINK default = $(CC) ;
X LINKFLAGS default = $(CCFLAGS) ;
X LINKLIBS default = $(MSVCNT)\\lib\\advapi32.lib
X $(MSVCNT)\\lib\\libcmt.lib
X $(MSVCNT)\\lib\\libc.lib
X $(MSVCNT)\\lib\\oldnames.lib
X $(MSVCNT)\\lib\\kernel32.lib ;
X OPTIM default = ;
X SLASH default = \\ ;
X STDHDRS default = $(MSVCNT)\\include ;
X SUFLIB default = .lib ;
X SUFOBJ default = .obj ;
X SUFEXE default = .exe ;
X UNDEFFLAG default = "/u _" ;
X }
X}
Xelse if $(VMS)
X{
X AS default = as ;
X CC default = cc ;
X CCFLAGS default = ;
X CRELIB default = true ;
X EXEMODE default = (w:e) ;
X FILEMODE default = (w:r) ;
X HDRS default = ;
X LEX default = lex ;
X LINK default = link ;
X LINKFLAGS default = ;
X LINKLIBS default = ;
X MV default = rename ;
X OPTIM default = ;
X RM default = delete ;
X SHELLMODE default = (w:er) ;
X SLASH default = . ;
X STDHDRS default = decc$library_include ;
X SUFLIB default = .olb ;
X SUFOBJ default = .obj ;
X SUFEXE default = .exe ;
X
X switch $(OS)
X {
X case OPENVMS : CCFLAGS default = /stand=vaxc ;
X case VMS : LINKLIBS default = sys$library:vaxcrtl.olb/lib ;
X }
X}
X
XJAMFILE default = Jamfile ;
XJAMRULES default = Jamrules ;
X
XHDRPATTERN = "^#[ ]*include[ ]*[<\"](.*)[\">].*$" ;
X
X#
X# Base dependencies - first for "bootstrap" kinds of rules
X#
X
XDEPENDS all : first shell files lib exe ;
XNOTFILE all first shell files lib exe dirs clean uninstall ;
XALWAYS clean uninstall ;
X
X#
X# Rules
X#


X
Xrule As
X{
X DEPENDS $(<) : $(>) ;
X}
X

Xrule Bulk
X{
X for i in $(>)
X {
X File $(i:D=$(<)) : $(i) ;
X }
X}
X
Xrule Cc


X{
X DEPENDS $(<) : $(>) ;
X

X # Just to clarify here: this sets the per-target CCFLAGS to
X # be the current value of (global) CCFLAGS and SUBDIRCCFLAGS.
X
X CCFLAGS on $(<) += $(CCFLAGS) $(SUBDIRCCFLAGS) ;
X
X # If the compiler's -o flag doesn't work, relocate the .o
X
X if $(RELOCATE)
X {
X CcMv $(<) : $(>) ;
X }
X
X if $(VMS) && $(HDRS[1])
X {
X SLASHINC on $(<) = "/inc=(" $(HDRS[1]) ,$(HDRS[2-]) ")" ;
X }
X}
X
Xrule C++


X{
X DEPENDS $(<) : $(>) ;

X C++FLAGS on $(<) += $(C++FLAGS) $(SUBDIRC++FLAGS) ;
X
X if $(VMS) && $(HDRS[1])
X {
X SLASHINC on $(<) = "/inc=(" $(HDRS[1]) ,$(HDRS[2-]) ")" ;
X }
X}
X
Xrule File
X{
X DEPENDS files : $(<) ;


X DEPENDS $(<) : $(>) ;

X SEARCH on $(>) = $(SEARCH_SOURCE) ;
X MODE on $(<) = $(FILEMODE) ;
X Chmod $(<) ;
X}
X
Xrule Fortran


X{
X DEPENDS $(<) : $(>) ;
X}
X

Xrule HardLink
X{
X DEPENDS files : $(<) ;


X DEPENDS $(<) : $(>) ;

X SEARCH on $(>) = $(SEARCH_SOURCE) ;
X}
X
Xrule HdrRule
X{
X # HdrRule source : headers ;
X
X # N.B. This rule is called during binding, potentially after
X # the fate of many targets has been determined, and must be
X # used with caution: don't add dependencies to unrelated
X # targets, and don't set variables on $(<).
X
X # Tell Jam that anything depending on $(<) also depends on $(>),
X # set SEARCH so Jam can find the headers, but then say we don't
X # care if we can't actually find the headers (they may have been
X # within ifdefs),
X
X INCLUDES $(<) : $(>) ;
X SEARCH on $(>) = $(HDRSEARCH) ;
X NOCARE $(>) ;
X
X # Propagate on $(<) to $(>)
X
X HDRSEARCH on $(>) = $(HDRSEARCH) ;
X HDRSCAN on $(>) = $(HDRSCAN) ;
X HDRRULE on $(>) = $(HDRRULE) ;
X}
X
Xrule Install
X{
X DEPENDS install : $(<) ;


X DEPENDS $(<) : $(>) ;

X SEARCH on $(>) = $(SEARCH_SOURCE) ;
X
X # depend upon and create the directory
X
X DEPENDS $(<) : $(<:D) ;
X MkDir $(<:D) ;
X
X # Arrange for jam uninstall
X
X Clean uninstall : $(<) ;
X
X if ! $(INSTALL)
X {
X Chmod $(<) ;
X
X if $(OWNER) { Chown $(<) ; OWNER on $(<) = $(OWNER) ; }
X if $(GROUP) { Chgrp $(<) ; GROUP on $(<) = $(GROUP) ; }
X }
X}
X
Xrule InstallBin
X{
X for i in $(>)
X {
X Install $(i:D=$(<)) : $(i) ;
X MODE on $(i:D=$(<)) = $(EXEMODE) ;
X }
X}
X
Xrule InstallLib
X{
X for i in $(>)
X {
X Install $(i:D=$(<)) : $(i) ;
X MODE on $(i:D=$(<)) = $(FILEMODE) ;
X }
X}
X
Xrule InstallMan
X{
X # Really this just strips the . from the suffix
X
X for i in $(>)
X {
X switch $(i:S)
X {
X case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;
X case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;
X case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;
X case .n : s = n ; case .man : s = 1 ;
X }
X
X d = $(i:D=man$(s):S=.$(s)) ;
X
X Install $(d:R=$(<)) : $(i) ;
X MODE on $(d:R=$(<)) = $(FILEMODE) ;
X }
X}
X
Xrule InstallShell
X{
X for i in $(>)
X {
X Install $(i:D=$(<)) : $(i) ;
X MODE on $(i:D=$(<)) = $(SHELLMODE) ;
X }
X}
X
Xrule Lex


X{
X DEPENDS $(<) : $(>) ;

X LOCATE on $(<) = $(LOCATE_TARGET) ;
X Clean clean : $(<) ;
X}
X
Xrule Library
X{
X LibraryFromObjects $(<) : $(>:S=$(SUFOBJ)) ;
X Objects $(>) ;
X}
X
Xrule LibraryFromObjects
X{
X # library depends on its member objects
X
X l = $(<:S=$(SUFLIB)) ;
X s = $(>) ;
X
X if $(SOURCE_GRIST)
X {
X s = $(>:G=$(SOURCE_GRIST)) ;
X }
X
X DEPENDS lib : $(l) ;
X DEPENDS $(l) : $(l)($(s:BS)) ;
X
X Clean clean : $(l) ;
X
X # We wish we could locate the library and it's contents,
X # but the reference to $(NEEDLIBS) in Main's actions
X # get the unbound names. Only $(<) and $(>) refer to
X # bound file name in rule actions. Sigh.
X #
X # LOCATE on $(<) $(<)($(s:BS)) = $(LOCATE_TARGET) ;
X
X # each archive member object depends on real object
X # each real object gets compiled from sources
X
X for i in $(s)
X {
X DEPENDS $(l)($(i:BS)) : $(i) ;
X }
X
X # must call separate Archive rule so that 'updated' modifier
X # on 'actions' refers to updated .o's.
X # delete objects after archive is made
X
X if $(CRELIB) { CreLib $(l) ; }
X
X Archive $(l) : $(s) ;
X RmTemps $(l) : $(s) ;
X
X if $(RANLIB) { Ranlib $(l) ; }
X}
X
Xrule Link
X{
X MODE on $(<) = $(EXEMODE) ;
X Chmod $(<) ;
X}
X
Xrule LinkLibraries
X{
X # make library dependencies of target
X # set NEEDLIBS variable used by 'actions Main'
X
X if $(<:S)
X {
X t = $(<) ;
X } else {
X t = $(<:S=$(SUFEXE)) ;
X }
X
X DEPENDS $(t) : $(>:S=$(SUFLIB)) ;
X NEEDLIBS on $(t) += $(>:S=$(SUFLIB)) ;
X}
X
Xrule Main
X{
X MainFromObjects $(<) : $(>:S=$(SUFOBJ)) ;
X Objects $(>) ;
X}
X
Xrule MainFromObjects
X{
X # make compiled sources a dependency of target
X
X s = $(>) ;
X
X if $(SOURCE_GRIST)
X {
X s = $(>:G=$(SOURCE_GRIST)) ;
X }
X
X if $(<:S)
X {
X t = $(<) ;
X } else {
X t = $(<:S=$(SUFEXE)) ;
X }
X
X DEPENDS exe : $(t) ;
X DEPENDS $(t) : $(s) ;
X LOCATE on $(t) = $(LOCATE_TARGET) ;
X
X Clean clean : $(t) ;
X
X Link $(t) : $(s) ;
X}
X
Xrule MkDir
X{
X if ! $($(<)-mkdir)
X {
X # Cheesy gate to prevent multiple invocations on same dir
X # MkDir1 has the actions
X # If dir exists, don't update it
X # Arrange for jam dirs
X
X $(<)-mkdir = true ;
X MkDir1 $(<) ;
X NOUPDATE $(<) ;
X Depends dirs : $(<) ;
X
X # Recursively make parent directories.
X # On UNIX, $(<:D) = $(<)'s parent, & we recurse until root
X # On VMS, $(<:D) = $(<), no recursing, but you don't need to
X # create parent directories explicitly there.
X
X s = $(<:D) ;
X
X if $(s) && $(s) != $(<)
X {
X Depends $(<) : $(s) ;
X MkDir $(s) ;
X }
X }
X}
X
Xrule Object
X{
X # locate object and search for source, if wanted
X
X Clean clean : $(<) ;
X
X LOCATE on $(<) = $(LOCATE_TARGET) ;
X SEARCH on $(>) = $(SEARCH_SOURCE) ;
X
X # Save HDRS for -I$(HDRS) on compile.
X # We shouldn't need -I$(SEARCH_SOURCE) as cc can find headers
X # in the .c file's directory, but generated .c files (from
X # yacc, lex, etc) are located in $(LOCATE_TARGET), possibly
X # different from $(SEARCH_SOURCE).
X
X HDRS on $(<) = $(HDRS) $(SUBDIRHDRS) $(SEARCH_SOURCE) ;
X
X # handle #includes for source: Jam scans for headers with
X # the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
X # with the scanned file as the target and the found headers
X # as the sources. HDRSEARCH is just grist for HdrRule.
X
X # $(h) is where cc first looks for #include "foo.h" files.
X # If the source file is in a distant directory, look there.
X # Else, look in "" (the current directory).
X
X if $(SEARCH_SOURCE)
X {
X h = $(SEARCH_SOURCE) ;
X }
X else
X {
X h = "" ;
X }
X
X HDRRULE on $(>) = HdrRule ;
X HDRSCAN on $(>) = $(HDRPATTERN) ;
X HDRSEARCH on $(>) = $(HDRS) $(SUBDIRHDRS) $(h) $(STDHDRS) ;
X
X # if source is not .c, generate .c with specific rule
X
X switch $(>:S)
X {
X case .c : Cc $(<) : $(>) ;
X case .C : C++ $(<) : $(>) ;
X case .cc : C++ $(<) : $(>) ;
X case .cpp : C++ $(<) : $(>) ;
X case .f : Fortran $(<) : $(>) ;
X case .l : Cc $(<) : $(<:S=.c) ;
X Lex $(<:S=.c) : $(>) ;
X case .s : As $(<) : $(>) ;
X case .y : Cc $(<) : $(<:S=.c) ;
X Yacc $(<:S=.c) : $(>) ;
X case * : UserObject $(<) : $(>) ;
X }
X}
X
Xrule ObjectCcFlags
X{
X s = $(<:S=$(SUFOBJ)) ;
X
X if $(SOURCE_GRIST)
X {
X s = $(s:G=$(SOURCE_GRIST)) ;
X }
X
X CCFLAGS on $(s) += $(>) ;
X}
X
Xrule ObjectC++Flags
X{
X s = $(<:S=$(SUFOBJ)) ;
X
X if $(SOURCE_GRIST)
X {
X s = $(s:G=$(SOURCE_GRIST)) ;
X }
X
X C++FLAGS on $(s) += $(>) ;
X}
X
Xrule ObjectHdrs
X{
X s = $(<:S=$(SUFOBJ)) ;
X
X if $(SOURCE_GRIST)
X {
X s = $(s:G=$(SOURCE_GRIST)) ;
X }
X
X HDRS on $(s) += $(>) ;
X}
X
Xrule Objects
X{
X s = $(<) ;
X
X if $(SOURCE_GRIST)
X {
X s = $(<:G=$(SOURCE_GRIST)) ;
X }
X
X for i in $(s)
X {
X Object $(i:S=$(SUFOBJ)) : $(i) ;
X }
X}
X
Xrule RmTemps
X{
X TEMPORARY $(>) ;
X}
X
Xrule Setuid
X{
X if $(<:S)
X {
X t = $(<) ;
X } else {
X t = $(<:S=$(SUFEXE)) ;
X }
X
X MODE on $(t) = 4711 ;
X}
X
Xrule Shell
X{
X DEPENDS shell : $(<) ;


X DEPENDS $(<) : $(>) ;

X SEARCH on $(>) = $(SEARCH_SOURCE) ;
X MODE on $(<) = $(SHELLMODE) ;
X Chmod $(<) ;
X}
X
Xrule SubDir
X{
X #
X # SubDir TOP d1 [ ... ]
X #
X # This introduces a Jamfile that is part of a project tree
X # rooted at $(TOP). It (only once) includes the project-specific
X # rules file $(TOP)/Jamrules and then sets search & locate stuff.
X #
X # If the variable $(TOPRULES) is set (where TOP is the first arg
X # to SubDir), that file is included instead of $(TOP)/Jamrules.
X #
X # d1 ... are the directory elements that lead to this directory
X # from $(TOP). We construct the system dependent path from these
X # directory elements in order to set search&locate stuff.
X #
X
X if ! $($(<[1]))
X {
X EXIT Top level of source tree has not been set with $(<[1]) ;
X }
X
X #
X # If $(TOP)/Jamrules hasn't been included, do so.
X #
X
X if ! $($(<[1])-included)
X {
X # Gated entry.
X
X $(<[1])-included = TRUE ;
X
X # File is $(TOPRULES) or $(TOP)/Jamrules.
X
X r = $($(<[1])RULES) ;
X
X if ! $(r)
X {
X r = $(JAMRULES:R=$($(<[1]))) ;
X }
X
X # Include it.
X
X include $(r) ;
X }
X
X # Get the grist $(g), search $(s), by concatenating the
X # directory elements using the OS specific path separator.
X
X g = $(<[2]) ;
X s = $(<[2]) ;
X
X for i in $(<[3-])
X {
X g = $(g)!$(i) ;
X s = $(s)$(SLASH)$(i) ;
X }
X
X if $(VMS)
X {
X s = [$(s)] ;
X }
X
X # Now set up SEARCH_SOURCE, LOCATE_TARGET, SOURCE_GRIST
X # These can be reset if needed. For example, if the source
X # directory should not hold object files, LOCATE_TARGET can
X # subsequently be redefined.
X
X SUBDIR = $(s:R=$($(<[1]))) ;
X SEARCH_SOURCE = $(SUBDIR) ;
X LOCATE_TARGET = $(SUBDIR) ;
X SOURCE_GRIST = $(g) ;
X
X # Reset per-directory ccflags, hdrs
X
X SUBDIRCCFLAGS = ;
X SUBDIRC++FLAGS = ;
X SUBDIRHDRS = ;
X}
X
Xrule SubDirCcFlags
X{
X SUBDIRCCFLAGS += $(<) ;
X}
X
Xrule SubDirC++Flags
X{
X SUBDIRC++FLAGS += $(<) ;
X}
X
Xrule SubDirHdrs
X{
X SUBDIRHDRS += $(<) ;
X}
X
Xrule SubInclude
X{
X # That's
X # SubInclude TOP d1 [ d2 [ d3 [ d4 ] ] ]
X #
X # to include a subdirectory's Jamfile.
X
X if ! $($(<[1]))
X {
X EXIT Top level of source tree has not been set with $(<[1]) ;
X }
X
X s = $(<[2]) ;
X
X for i in $(<[3-])
X {
X s = $(s)$(SLASH)$(i) ;
X }
X
X if $(VMS)
X {
X s = [$(s)] ;
X }
X
X include $(JAMFILE:D=$(s):R=$($(<[1]))) ;
X}
X
Xrule Undefines
X{
X if $(<:S)
X {
X t = $(<) ;
X } else {
X t = $(<:S=$(SUFEXE)) ;
X }
X
X UNDEFS on $(t) += $(UNDEFFLAG)$(>) ;
X}
X
Xrule UserObject
X{
X EXIT "Unknown suffix on" $(>) "- see UserObject rule in Jamfile(5)." ;
X}
X
Xrule Yacc
X{
X h = $(<:BS=.h) ;
X
X # Some places don't have a yacc.
X
X if $(YACC)
X {
X DEPENDS $(<) $(h) : $(>) ;
X Yacc1 $(<) $(h) : $(>) ;
X Clean clean : $(<) $(h) ;
X }
X
X # make sure someone includes $(h) else it will be
X # a deadly independent target
X
X INCLUDES $(<) : $(h) ;
X LOCATE on $(<) $(h) = $(LOCATE_TARGET) ;
X}
X
X#
X# Actions
X#
X
Xif $(UNIX)
X{
X
X actions updated together piecemeal Archive
X {
X $(AR) $(<) $(>)


X }
X
X actions As
X {

X $(AS) $(ASFLAGS) -o $(<) $(>) ;
X }
X
X actions C++
X {
X $(C++) -c $(C++FLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
X }
X
X actions Cc
X {
X $(CC) -c $(CCFLAGS) $(OPTIM) -I$(HDRS) -o $(<) $(>)
X }
X
X actions CcMv
X {
X [ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)
X }
X
X actions Chgrp
X {
X chgrp $(GROUP) $(<)
X }
X
X actions Chmod
X {
X chmod $(MODE) $(<)
X }
X
X actions Chown
X {
X chown $(OWNER) $(<)
X }
X
X actions piecemeal together existing Clean
X {
X $(RM) $(>)
X }
X
X actions File
X {
X $(RM) $(<)
X $(CP) $(>) $(<) &&
X }
X
X actions Fortran
X {
X $(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)
X }
X
X actions HardLink
X {
X $(RM) $(<) && $(LN) $(>) $(<)
X }
X
X if $(INSTALL)
X {
X actions Install
X {
X $(INSTALL) -m$(MODE) -o$(OWNER) -g$(GROUP) $(>) $(<)
X }
X }
X else
X {
X actions Install
X {
X $(CP) $(>) $(<)
X }
X }
X
X actions Lex
X {
X $(LEX) $(>) && $(MV) lex.yy.c $(<)
X }
X
X actions Link
X {
X if $(LINK) $(LINKFLAGS) -o $(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
X then :
X else $(RM) $(<) && exit 1
X fi
X }
X
X actions MkDir1
X {
X $(MKDIR) $(<)
X }
X
X actions together Ranlib
X {
X $(RANLIB) $(<)
X }
X
X actions quietly updated piecemeal together RmTemps
X {
X $(RM) $(>)
X }
X
X actions Shell
X {
X $(AWK) '
X NR == 1 { print "$(SHELLHEADER)" }
X NR == 1 && /^[#:]/ { next }
X /^##/ { next }
X { print }
X ' < $(>) > $(<)
X }
X
X actions Yacc1
X {
X $(YACC) $(>) &&
X {
X $(MV) y.tab.c $(<[1])
X $(MV) y.tab.h $(<[2])
X }
X }
X}
Xelse if $(NT)
X{
X if $(BCCROOT)
X {
X actions Link
X {
X $(LINK) -e$(<) $(LINKFLAGS) $(UNDEFS) -L$(LINKLIBS) $(NEEDLIBS) $(>) || del $(<) /f
X }
X
X actions together piecemeal Archive
X {
X $(AR) $(ARFLAGS) $(<) -+$(>)
X }
X }
X else if $(MSVCNT)
X {
X actions Link
X {
X $(LINK) $(LINKFLAGS) /o$(<) $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
X }
X
X actions together piecemeal Archive
X {
X $(AR) /out:$(<) $(>)
X }
X }
X
X actions Cc
X {
X $(CC) /c $(CCFLAGS) $(OPTIM) /out:$(<) /I$(HDRS) $(>)
X }
X
X actions Chmod
X {
X }
X
X actions piecemeal together existing Clean
X {
X $(RM) $(>) /f /q
X }
X
X actions File
X {
X copy $(>) $(<)
X }
X
X actions quietly updated piecemeal together RmTemps
X {
X $(RM) $(>)
X }
X}
Xelse if $(VMS)
X{
X
X actions updated together piecemeal Archive
X {
X lib/replace $(<) $(>[1]) ,$(>[2-])
X }
X
X actions Cc
X {
X cc/obj=$(<) $(CCFLAGS) $(OPTIM) $(SLASHINC) $(>)
X }
X
X actions Chmod
X {
X set file/prot=$(MODE) $(<)
X }
X
X actions piecemeal together existing Clean
X {
X $(RM) $(>[1]);* ,$(>[2-]);*
X }
X
X actions together quietly CreLib
X {
X if f$search("$(<)") .eqs. "" then lib/create $(<)
X }
X
X actions File
X {
X copy $(>) $(<)
X }
X
X actions Install
X {
X copy $(>) $(<)
X }
X
X actions Lex
X {
X $(LEX) $(>)
X $(MV) lex.yy.c $(<)
X }
X
X actions Link
X {
X $(LINK)/exe=$(<) $(LINKFLAGS) $(>[1]) ,$(>[2-]) ,$(NEEDLIBS)/lib ,$(LINKLIBS)
X }
X
X actions MkDir1
X {
X create/dir $(<)
X }
X
X actions quietly updated piecemeal together RmTemps
X {
X $(RM) $(>[1]);* ,$(>[2-]);*
X }
X
X actions Shell
X {
X copy $(>) $(<)
X }
X
X actions Yacc1
X {
X $(YACC) $(>)
X $(MV) y.tab.c $(<[1])
X $(MV) y.tab.h $(<[2])
X }
X}
X
X
X#
X# Backwards compatibility with jam 1, where rules were uppercased.
X#
X
Xrule BULK { Bulk $(<) : $(>) ; }
Xrule FILE { File $(<) : $(>) ; }
Xrule HDRRULE { HdrRule $(<) : $(>) ; }
Xrule INSTALL { Install $(<) : $(>) ; }
Xrule LIBRARY { Library $(<) : $(>) ; }
Xrule LIBS { LinkLibraries $(<) : $(>) ; }
Xrule LINK { Link $(<) : $(>) ; }
Xrule MAIN { Main $(<) : $(>) ; }
Xrule SETUID { Setuid $(<) ; }
Xrule SHELL { Shell $(<) : $(>) ; }
Xrule UNDEFINES { Undefines $(<) : $(>) ; }
X
X# Old INSTALL* didn't take dest directory.
X
Xrule INSTALLBIN { InstallBin $(BINDIR) : $(<) ; }
Xrule INSTALLLIB { InstallLib $(LIBDIR) : $(<) ; }
Xrule INSTALLMAN { InstallMan $(MANDIR) : $(<) ; }
X
X#
X# Now include the user's Jamfile.
X#
X
Xinclude $(JAMFILE) ;
X
END_OF_FILE
if test 23751 -ne `wc -c <'Jambase'`; then
echo shar: \"'Jambase'\" unpacked with wrong size!
fi
# end of 'Jambase'
fi
if test -f 'filesys.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'filesys.h'\"
else
echo shar: Extracting \"'filesys.h'\" \(918 characters\)
sed "s/^X//" >'filesys.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * filesys.h - FILENAME struct and OS specific file routines
X */
X
X/*
X * FILENAME - a name of a file, broken into <grist>dir/base/suffix(member)
X *
X * <grist> is salt to distinguish between targets that otherwise would
X * have the same name: it never appears in the bound name of a target.
X * (member) is an archive member name: the syntax is arbitrary, but must
X * agree in file_parse(), file_build() and the Jambase.
X */
X
Xtypedef struct _filename FILENAME;
X
Xstruct _filename {
X struct filepart {
X char *ptr;
X int len;
X } part[6];
X# define f_grist part[0]
X# define f_root part[1]
X# define f_dir part[2]
X# define f_base part[3]
X# define f_suffix part[4]
X# define f_member part[5]
X} ;
X
Xvoid file_parse();
Xvoid file_build();
X
Xvoid file_archscan();
Xvoid file_dirscan();
X
Xint file_time();
END_OF_FILE
if test 918 -ne `wc -c <'filesys.h'`; then
echo shar: \"'filesys.h'\" unpacked with wrong size!
fi
# end of 'filesys.h'
fi
if test -f 'jam.1' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jam.1'\"
else
echo shar: Extracting \"'jam.1'\" \(19224 characters\)
sed "s/^X//" >'jam.1' <<'END_OF_FILE'
X.TH JAM 1 "10 March 1995"
X.SH NAME
X\fBjam\fR
X\-
X\fBmake\fR(1)
Xredux
X
X.SH SYNOPSIS
X\fBjam\fR
X[ \fB-a\fR ]
X[ \fB-n\fR ]
X[ \fB-v\fR ]
X[ \fB-d \fIdebug\fR ]
X[ \fB-f \fIJambase\fR ... ]
X[ \fB-j \fIjobs\fR ]
X[ \fB-t \fItarget\fR ... ]
X[ \fItarget\fR ... ]
X
X.SH DESCRIPTION
X.PP
X\fBJam\fR recursively builds target files from their source files,
Xusing two files to define the dependency graph and the updating actions
Xfor all targets. The file \fBJambase\fR (usually located in
X/usr/local/lib) defines rules, and the file \fBJamfile\fR (located in
Xthe current directory) lists the targets and sources in terms of those
Xrules. \fBJam\fR does not need to rely on suffix-driven implicit rules
Xor directory contents. A \fBJambase\fR is provided with \fBjam\fR; the
Xuser supplies the \fBJamfile\fR.
X.PP
XSee \fBJamfile\fR(5) for information on writing Jamfiles. This manual
Xpage describes the program that interprets \fBJambase\fR and
X\fBJamfile\fR.
X
X.SH OPTIONS
X.PP
XIf \fItarget\fR is provided on the command line, \fBjam\fR attempts to
Xbuild that target; otherwise \fBjam\fR attempts to build the target
X\fIall\fR.
X.PP
X\fBJam\fR supports the following options:
X.IP "-a"
XBuild all targets, even if they are up-to-date.
X.IP "-d\fI<n>\fR"
XSet the debug level to \fI<n>\fR. Interesting values are:
X.PP
X.RS
X0 Emit only errors
X.br
X1 Emit update action tracing (default)
X.br
X2 Emit update commands
X.br
X3 Produce dependency information
X.br
X4 Show modification times of bound files
X.br
X5 Show rule invocation
X.br
X6-9 debugging
X.RE
X.IP "-f\fI<file>\fR"
XRead \fI<file>\fR instead of \fBJambase\fR.
X.IP "-j\fI<jobs>\fR"
XRun up to \fI<jobs>\fR shell commands concurrently (UNIX only).
XThe default is 1.
X.IP "-n"
XDon't actually execute the updating actions, but do everything else.
XThis implies \fB-d\fI2\fR.
X.IP "-t\fI<target>\fR"
XRebuild \fI<target>\fR, even if it is up-to-date.
X.IP "-v"
XPrint the version of \fBjam\fR and exit.
X
X.SH "THE JAM LANGUAGE"
X.PP
XThe \fBjam\fR language supports defining rules, invoking rules, and
Xsetting variables. It also has a few flow-of-control statements.
X\fBJambase\fR and \fBJamfile\fR share this language.
X.SS "Lexical Features"
X\fBJam\fR treats its input files as whitespace-separated tokens, with
Xtwo exceptions: double quotes (") can enclose whitespace to embed it
Xinto a token, and everything between the matching curly braces ({}) in
Xthe definition of a rule action is treated as a single string. A
Xbackslash (\\) can escape a double quote.

X.PP
X\fBJam\fR requires whitespace (blanks, tabs, or newlines) to surround

Xall tokens, including the colon (:) and semicolon (;) tokens. This is
Xbecause \fBjam\fR runs on many platforms and no characters, save
Xwhitespace, are uncommon in the file names on all of those platforms.
X.SS Targets
XTargets are files to be updated and sources are the files used in
Xupdating those targets. Collectively, they are just referred to as
X"targets". A target is simply a file name, either rooted or relative
Xto the directory of \fBjam\fR's invocation. The special syntax,
X\fIfile(member)\fR, refers to an \fBar\fR(1) library member. The
Xspecial syntax, \fI<grist>file\fR, perturbs a file name to distinguish
Xit from other files with the same name. The \fI<grist>\fR is stripped
Xfrom the name during binding (q.v., below).
X.SS Rules
X\fBJam\fR's basic entity is called a rule, which is used to relate
Xtargets to their sources. A rule is defined in two parts: the
X\fBjam\fR statements to execute when the rule is invoked (essentially a
Xprocedure call), and the actions (shell commands) to execute in order
Xto update the targets of the rule. A rule may have a procedure
Xdefinition, actions, or both.
X.PP
XThe \fBjam\fR statements for defining and invoking rules are as
Xfollows. \fI<targets>\fR and \fI<sources>\fR are lists of file names;
X\fI<statements>\fR are \fBjam\fR statements; and \fI<string>\fR is a
Xshell script:
X.IP
Xrule \fI<rulename>\fR { \fI<statements>\fR }
X.IP
Xactions [ \fImodifiers\fR ] \fI<rulename>\fR { \fI<string>\fR }
X.IP
X\fI<rulename>\fR \fI<targets>\fR [ : \fI<sources>\fR ] ;
X.PP
XThe first form defines a rule's procedure; the second defines the rule's
Xupdating actions; the third invokes the rule. Redefining a rule's
Xprocedure or actions replaces the previous definition.
X.PP
XInvoking a rule executes the procedure for the rule (if any) and
Xassociates any update actions for the targets. More than one update
Xaction may be associated with a target: the actions are executed in the
Xorder in which they are added.
X.PP
XIn both the rule's procedure definition and the rule's actions, the
Xspecial variables $(<) and $(>) refer to the \fI<targets>\fR and
X\fI<sources>\fR given at rule invocation. However, in the rule's
Xactions, $(<) and $(>) refer to the \fI<targets>\fR and \fI<sources>\fR
Xafter they have been bound by the binding phase (q.v., below).
X\fBJam\fR issues a warning if $(<) or $(>) have elements not in the
Xdependency graph.
X.PP
XThe following action \fImodifiers\fR are understood:
X.RS
X.IP "\fBactions existing\fR"
X$(>) includes only targets currently existing.
X.IP "\fBactions ignore\fR"
XThe return status of the shell commands is ignored.
X.IP "\fBactions piecemeal\fR"
XThe shell commands are repeatedly invoked with a subset of $(>)
Xsmall enough to fit in a command buffer.
X.IP "\fBactions quietly\fR"
XThe action is not echoed to the standard output.
X.IP "\fBactions together\fR"
XThe $(>) from multiple instances of the same action on the same
Xtarget are glommed together.
X.IP "\fBactions updated\fR"
X$(>) includes only targets marked for updating.
X.RE
X.SS "Built-in Rules"
X.PP
X\fBJam\fR has ten built-in rules, none of which have updating actions:
X.PP
X.RS
X.IP "ALWAYS \fI<targets>\fR ;"
X.br
XRebuilds \fI<targets>\fR, even if they are up-to-date.
X.IP "DEPENDS \fI<targets>\fR : \fI<sources>\fR ;"
X.br
XMakes \fI<sources>\fR dependencies of \fI<targets>\fR.
X.IP "ECHO \fI<args>\fR ;"
X.br
XBlurts out the message \fI<args>\fR to stdout.
X.IP "EXIT \fI<args>\fR ;"
X.br
XBlurts out the message \fI<args>\fR to stdout and then
Xexits with a failure status.
X.IP "INCLUDES \fI<targets>\fR : \fI<sources>\fR ;"
X.br
XMakes \fI<sources>\fR dependencies of anything of which \fI<targets>\fR
Xare dependencies.
X.IP "LEAVES \fI<targets>\fR ;"
X.br
XMakes each of \fI<targets>\fR depend only on its leaf sources, and not
Xon any intermediate targets. Its leaf sources are those dependencies
Xwithout any dependencies themselves.
X.IP "NOCARE \fI<targets>\fR ;"
X.br
XMarks \fI<targets>\fR as possibly being bogus.
X.IP "NOTFILE \fI<targets>\fR ;"
X.br
XMarks \fI<targets>\fR as not being files.
X.IP "NOUPDATE \fI<targets>\fR ;"
X.br
XCauses the timestamps of \fI<targets>\fR to be ignored: either the
Xtarget exists or it doesn't. If it exists, it is considered eternally
Xold.
X.IP "TEMPORARY \fI<targets>\fR ;"
X.br
XMarks \fI<targets>\fR as temporary.
X.RE
X.PP
XThe \fIALWAYS\fR, \fILEAVES\fR, \fINOCARE\fR, \fINOTFILE\fR,
X\fINOUPDATE\fR, and \fITEMPORARY\fR affect only the binding phase
X(q.v.).
X.SS "Flow-of-Control"
X.PP
X\fBJam\fR has several simple flow-of-control statements:
X.IP
Xinclude \fI<a>\fR ;
X.IP
Xfor \fI<a>\fR in \fI<args>\fR { \fI<statements>\fR }
X.IP
Xswitch \fI<a>\fR { case \fI<v1>\fR : \fI<statements>\fR ; case \fI<v2>\fR : \fI<statements>\fR ; ... }
X.IP
Xif \fI<cond>\fR { \fI<statements>\fR } [ else { \fI<statements>\fR } ]
X.PP
XThe \fBinclude\fR statement includes the named file. The file is bound
Xlike regular targets (see \fBBinding\fR, below), but unlike regular
Xtargets the include file cannot be built.
X.PP
XThe \fBfor\fR loop executes \fI<statements>\fR for each value in
X\fI<args>\fR, setting the variable \fI<a>\fR to the value.
X.PP
XThe \fBswitch\fR statement executes zero or one of the enclosed
X\fI<statements>\fR, depending on which value \fI<a>\fR matches. The
X\fI<v>\fR values are not variable-expanded. The \fI<v>\fR values may
Xinclude the following wildcards:
X.PP
X.RS
X? match any single character
X.br
X* match zero or more characters
X.br
X[\fI<chars>\fR] match any single character in \fI<chars>\fR
X.RE
X.PP
XThe \fBif\fR statement does the obvious; the \fBelse\fR clause is
Xoptional. \fI<cond>\fR is built of:
X.PP
X.RS
X\fI<a>\fR true if \fI<a>\fR is a non-zero-length string
X.br
X\fI<a>\fR = \fI<b>\fR strings equal
X.br
X\fI<a>\fR != \fI<b>\fR strings not equal
X.br
X\fI<a>\fR < \fI<b>\fR string less than
X.br
X\fI<a>\fR <= \fI<b>\fR string less than or equal to
X.br
X\fI<a>\fR > \fI<b>\fR string greater than
X.br
X\fI<a>\fR >= \fI<b>\fR string greater than or equal to
X.PP
X! \fI<cond>\fR condition not true
X.br
X\fI<cond>\fR && \fI<cond>\fR conjunction
X.br
X\fI<cond>\fR || \fI<cond>\fR disjunction
X.br
X( \fI<cond>\fR ) grouping
X.RE
X.PP
XIn comparisons, the arguments may (through variable expansion) be more
Xthan one token, but only the first token takes part in the comparison.
XIf, through variable expansion, the argument is zero tokens, a single
Xtoken of a zero-length string is used instead.
X.SS Variables
X.PP
X\fBJam\fR variables are lists of strings, with zero or more elements.
XAn undefined variable is indistinguishable from a variable whose value
Xis an empty list. Variables are either global or target-specific. All
Xvariables are referenced as $(VARIABLE).
X.PP
XA variable is defined with:
X.IP
X\fI<variable>\fR = \fI<values>\fR ;
X.IP
X\fI<variable>\fR += \fI<values>\fR ;
X.IP
X\fI<variable>\fR on \fI<targets>\fR = \fI<values>\fR ;
X.IP
X\fI<variable>\fR on \fI<targets>\fR += \fI<values>\fR ;
X.IP
X\fI<variable>\fR default = \fI<values>\fR ;
X.PP
XThe first two forms set \fI<variable>\fR globally. The third and forth
Xforms set a target-specific variable, where \fI<variable>\fR takes on a
Xvalue only during the binding and updating \fI<targets>\fR. The
X\fB=\fR operator replaces any previous value of \fI<variable>\fR with
X\fI<values>\fR; the \fB+=\fR operation appends \fI<values>\fR to any
Xprevious value. The final form sets \fI<variable>\fR globally, but
Xonly if it was previously unset.
X.PP
XOn program start-up, \fBjam\fR imports the environment variable
Xsettings into \fBjam\fR variables. Environment variables are split at
Xblanks with each word becomming an element in the variable's list
Xvalue. Environment variables whose names end in \fBPATH\fR are split
Xat colons ("\fB:\fR"). \fBJam\fR variables are not re-exported to
Xthe shell that executes the updating actions, but the updating actions
Xcan reference \fBjam\fR variables with $(VARIABLE).
X.SS "Variable Expansion"
X.PP
XBefore executing a statement, \fBjam\fR performs variable expansion on
Xeach token that is not a keyword or rule name. Such tokens with
Xembedded variable references are replaced with zero or more tokens.
XVariable references are of the form $(\fIv\fR) or $(\fIvm\fR), where
X\fIv\fR is the variable name, and \fIm\fR are optional modifiers.
X.PP
XVariable expansion in a rule's actions is similar to variable expansion
Xin statements, except that the action string is tokenized at whitespace
Xregardless of quoting.
X.PP
XThe result of a token after variable expansion is the product of the
Xcomponents of the token, where each component is a literal substring or
Xa list substituting a variable reference. For example:
X.PP
X.RS
X$(X) -> a b c
X.br
Xt$(X) -> ta tb tc
X.br
X$(X)z -> az bz cz
X.br
X$(X)-$(X) -> a-a a-b a-c b-a b-b b-c c-a c-b c-c
X.RE
X.PP
XThe variable name and modifiers can themselves contain a variable
Xreference, and this partakes of the product as well:
X.PP
X.RS
X$(X) -> a b c
X.br
X$(Y) -> 1 2
X.br
X$(Z) -> X Y
X.br
X$($(Z)) -> a b c 1 2
X.RE
X.PP
XBecause of this product expansion, if any variable reference in a token
Xis undefined, the result of the expansion is an empty list.
X.PP
XModifiers to a variable are of two varieties: sub-element selection and
Xfile name editing. They are:
X.PP
X.IP "[\fI<n>\fR]"
XSelect only element number \fI<n>\fR (starting at 1). If the variable contains
Xfewer than \fI<n>\fR elements, the result is a zero-element list.
X.IP "[\fI<n>\fR-\fI<m>\fR]"
XSelect only elements number \fI<n>\fR through \fI<m>\fR.
X.IP "[\fI<n>\fR-]"
XSelect only elements number \fI<n>\fR through the last.
X.IP ":G=\fI<grist>\fR"
XReplace the grist of the file name with \fI<grist>\fR.
X.IP ":D=\fI<path>\fR"
XReplace directory component of file name with \fI<path>\fR.
X.IP ":B=\fI<base>\fR"
XReplace the base part of file name with \fI<base>\fR.
X.IP ":S=\fI<suf>\fR"
XReplace the suffix of file name with \fI<suf>\fR.
X.IP ":M=\fI<mem>\fR"
XReplace the archive member name with \fI<mem>\fR.
X.IP ":R=\fI<root>\fR"
XPrepend \fI<root>\fR to the whole file name, if not already rooted.
X.IP ":\fI<components>\fR"
XRemove components not listed; components is one or more of
X\fBGDBSM\fR.
X
X.SH OPERATION
X\fBJam\fR has three phases of operation: parsing, binding, and
Xupdating.
X.SS Parsing
X.PP
X\fBJam\fR parses the \fBJambase\fR file, which includes \fBJamfile\fR.
XThe results of parsing are: the dependency graph of targets; update
Xactions associated with the targets; and variables set to specific
Xvalues.
X.PP
X.SS Binding
XAfter parsing, \fBjam\fR recursively descends the dependency graph,
Xattempting to locate each target file and determine if it is in need of
Xupdating. If \fBjam\fR detects a cycle in the graph, it issues a
Xwarning.
X.PP
XBy default, a target is located at the actual path of the target,
Xrelative to the directory of \fBjam\fR's invocation. If the special
Xvariable $(LOCATE) is set to a directory name, \fBjam\fR prepends that
Xdirectory name to the target; else if the special variable $(SEARCH) is
Xset to a directory list, \fBjam\fR searches along the directory list
Xfor the target file, and if the file is found prepends the directory
Xname to the target. If the target name has a rooted directory
Xcomponent then $(SEARCH) and $(LOCATE) do not apply: the target is
Xlocated at the actual path of the target. If a target is marked as not
Xbeing a file (using the built-in rule NOTFILE), it is left unbound to a
Xfile name.
X.PP
XAfter binding each target, \fBjam\fR determines whether the target
Xneeds updating, and marks the target if necessary for the updating
Xphase. A target is marked for updating for any of these three reasons:
X.IP
XIt is missing.
X.IP
XIts filesystem modification time is older than any of its sources.
X.IP
XAny of its sources are marked for updating.
X.PP
XThis basic behavior can be modified applying (usually one of) the
Xfollowing six built-in rules to the target:
X.RS
X.IP ALWAYS
XThe target is always updated.
X.IP LEAVES
XThe target is only updated if it is missing or if its leaf sources
Xare newer. Leaf sources are those dependencies of the target that have
Xno dependencies themselves.
X.IP NOCARE
XThe target is ignored if it is missing and has no updating actions.
XNormally, \fBjam\fR issues a warning and skips other targets that
Xdepend on missing targets without updating actions.
X.IP TEMPORARY
XIf the target is missing, then its parent's modification time is used
Xwhen comparing against sources.
X.IP NOTFILE
XThe target is only updated if any of its sources are marked for updating.
X.IP NOUPDATE
XThe target is only updated if it is missing. Also, if it exists, it
Xwill appear eternally old; that is, older than anything that depends on
Xit.
X.RE
X.PP
XIf a target is a source file that includes other files, \fBjam\fR scans
Xthe source file for header file include lines. It scans the file by
Xmatching each line against a \fBregexp\fR(3) pattern that has ()'s
Xsurrounding the included file name. The pattern is provided by the
Xuser through the special variable $(HDRSCAN) (see \fBHDRPATTERN\fR in
X\fBJambase\fR for an example). The result of the scan is formed into a
Xrule invocation, with the scanned file as the target and the found
Xincluded file names as the sources. The rule invoked is named by the
Xspecial variable $(HDRRULE). \fBJam\fR only scans files if $(HDRSCAN)
Xis set, and $(HDRSCAN) is normally set target-specific.
X.PP
XBetween binding and updating, \fBjam\fR announces the number of targets
Xto be updated.
X.SS Updating
XAfter binding, \fBjam\fR again recursively descends the dependency
Xgraph, this time executing the update actions for each target marked
Xfor update during the binding phase. If a target's updating actions
Xfail, then all targets which depend on it are skipped.
X.PP
X(UNIX only). The \fB-j\fR flag instructs \fBjam\fR to build more than
Xone target at a time. If there are multiple actions on a single
Xtarget, they are run sequentially.
X.PP
X(UNIX only). The special variable $(JAMSHELL) gives \fBjam\fR a
Xcommand execution shell to be used instead of /bin/sh. This variable's
Xvalue must be a multi-element list, corresponding to the argument
Xvector for the command shell. An element "\fB%\fR" is replaced with the
Xcommand string to execute. An element "\fB!\fR" is replaced with the
Xmultiprocess slot number, which is (inclusively) between 1 and the
Xmaximum number of concurrent jobs specified with the \fB-j\fR flag
X(default 1). If no element of the list is "\fB%\fR", the command
Xstring is tacked on as the last argument. The default value is:
X"/bin/sh -c %".
X
X.SH DIAGNOSTICS
X.PP
XIn addition to generic error messages,
X\fBjam\fR
Xmay emit one of the following:
X.PP
Xwarning: unknown rule X
X.IP
XA rule was invoked that has not been defined with
Xan "actions" or "rule" statement.
X.PP
Xusing N temp target(s)
X.IP
XTargets marked as being temporary (but nonetheless present)
Xhave been found.
X.PP
Xupdating N target(s)
X.IP
XTargets are out-of-date and will be updated.
X.PP
Xcan't find N target(s)
X.IP
XSource files can't be found and there are no actions to create them.
X.PP
Xcan't make N target(s)
X.IP
XDue to sources not being found, other targets cannot be made.
X.PP
Xwarning: X depends on itself
X.IP
XA target depends on itself either directly or through its sources.
X.PP
Xdon't know how to make X
X.IP
XA target is not present and no actions have been defined to create it.
X.PP
XX skipped for lack of Y
X.IP
XA source failed to build, and thus a target cannot be built.
X.PP
Xwarning: using independent target X
X.IP
XA target that does is not a dependency of any other target is
Xbeing referenced with $(<) or $(>).
X.PP
XX removed
X.IP
X\fBJam\fR
Xremoved a partially built target after being interrupted.
X
X.SH FILES
X/usr/local/lib/Jambase
X.br
XJamfile
X
X.SH BUGS, LIMITATIONS
X.PP
XBecause the \fBinclude\fR statement works by pushing a new file in the
Xinput stream of the scanner rather than recursively invoking the parser
Xon the new file, multiple include statements in a rule's procedure
Xcauses the files to be included in reverse order.
X.PP
XIf the \fBinclude\fR statement appears inside an \fBif\fR block, the
Xparser's attempt to find the \fBelse\fR will cause the text of the
Xincluded file to appear after the first token following the statement
Xblock. This is rarely what is intended.
X.PP
XIn a rule's actions, only $(<) and $(>) refer to the bound file names:
Xall other variable references get the unbound names.
X.PP
XWith the \fB-j\fR flag, errors from failed commands can get
Xstaggeringly mixed up. Also, because targets tend to get built in a
Xquickest-first ordering, dependency information must be quite exact.
XFinally, beware of parallelizing commands that drop fixed-named files
Xinto the current directory, like \fByacc\fR(1) does.
X.PP
XA poorly set $(JAMSHELL) is likely to result in silent failure.
X
X.SH SEE ALSO
X\fBJambase\fR(5), \fBJamfile\fR(5)
END_OF_FILE
if test 19224 -ne `wc -c <'jam.1'`; then
echo shar: \"'jam.1'\" unpacked with wrong size!
fi
# end of 'jam.1'
fi
if test -f 'jamgram.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jamgram.c'\"
else
echo shar: Extracting \"'jamgram.c'\" \(23346 characters\)
sed "s/^X//" >'jamgram.c' <<'END_OF_FILE'
Xextern char *malloc(), *realloc();
X# define _BANG 257
X# define _BANG_EQUALS 258
X# define _AMPERAMPER 259
X# define _LPAREN 260
X# define _RPAREN 261
X# define _PLUS_EQUALS 262
X# define _COLON 263
X# define _SEMIC 264
X# define _LANGLE 265
X# define _LANGLE_EQUALS 266
X# define _EQUALS 267
X# define _RANGLE 268
X# define _RANGLE_EQUALS 269
X# define _QUESTION_EQUALS 270
X# define ACTIONS 271
X# define CASE 272
X# define DEFAULT 273
X# define ELSE 274
X# define EXISTING 275
X# define FOR 276
X# define IF 277
X# define IGNORE 278
X# define IN 279
X# define INCLUDE 280
X# define ON 281
X# define PIECEMEAL 282
X# define QUIETLY 283
X# define RULE 284
X# define SWITCH 285
X# define TOGETHER 286
X# define UPDATED 287
X# define _LBRACE 288
X# define _BARBAR 289
X# define _RBRACE 290
X# define ARG 291
X# define STRING 292
X
X# line 62 "jamgram.y"

X#define yyclearin yychar = -1
X#define yyerrok yyerrflag = 0
Xextern int yychar;
Xextern int yyerrflag;
X#ifndef YYMAXDEPTH
X#define YYMAXDEPTH 150
X#endif
X#ifndef YYSTYPE
X#define YYSTYPE int
X#endif
XYYSTYPE yylval, yyval;
X# define YYERRCODE 256
Xint yyexca[] ={
X-1, 1,
X 0, -1,
X -2, 0,
X-1, 4,
X 263, 37,
X 264, 37,
X 291, 37,
X -2, 39,
X };
X# define YYNPROD 48
X# define YYLAST 173
Xint yyact[]={
X
X 10, 89, 87, 27, 32, 6, 8, 28, 25, 3,
X 21, 26, 85, 9, 7, 84, 10, 11, 39, 94,
X 4, 6, 8, 38, 93, 3, 41, 69, 79, 9,
X 7, 37, 10, 11, 90, 88, 4, 6, 8, 34,
X 33, 3, 27, 41, 83, 9, 7, 81, 10, 11,
X 63, 61, 4, 6, 8, 31, 42, 3, 92, 19,
X 41, 9, 7, 59, 18, 11, 56, 20, 4, 30,
X 58, 57, 40, 42, 55, 54, 19, 67, 60, 52,
X 2, 18, 44, 53, 20, 15, 13, 17, 68, 45,
X 46, 43, 47, 48, 5, 16, 12, 80, 29, 1,
X 0, 14, 23, 24, 22, 0, 0, 51, 0, 0,
X 70, 0, 35, 36, 0, 0, 0, 0, 0, 0,
X 24, 24, 64, 0, 0, 0, 0, 0, 49, 50,
X 0, 62, 0, 0, 65, 66, 24, 24, 73, 74,
X 75, 76, 77, 78, 71, 72, 86, 0, 0, 0,
X 0, 0, 0, 0, 91, 0, 0, 0, 0, 0,
X 0, 82, 95, 0, 0, 0, 0, 0, 0, 0,
X 0, 0, 96 };
Xint yypact[]={
X
X -1000, -223, -1000, -1000, -1000, -186, -281, -1000, -249, -284,
X -1000, -1000, -209, -287, -224, -1000, -1000, -236, -1000, -1000,
X -1000, -256, -270, -216, -176, -249, -249, -1000, -223, -212,
X -239, -1000, -1000, -1000, -1000, -214, -203, -1000, -1000, -245,
X -1000, -249, -249, -288, -288, -288, -288, -288, -288, -1000,
X -233, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
X -1000, -1000, -217, -1000, -1000, -220, -273, -278, -245, -289,
X -255, -1000, -199, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
X -291, -1000, -230, -1000, -1000, -1000, -1000, -205, -250, -1000,
X -1000, -271, -1000, -223, -1000, -223, -1000 };
Xint yypgo[]={
X
X 0, 99, 78, 69, 96, 94, 85, 77, 102, 98,
X 97, 88, 86, 83 };
Xint yyr1[]={
X
X 0, 1, 1, 3, 3, 2, 2, 2, 2, 2,
X 2, 2, 2, 2, 2, 2, 10, 2, 2, 6,
X 6, 6, 8, 8, 8, 8, 8, 8, 8, 8,
X 8, 8, 8, 7, 7, 11, 4, 12, 12, 5,
X 9, 9, 13, 13, 13, 13, 13, 13 };
Xint yyr2[]={
X
X 0, 1, 5, 1, 5, 7, 7, 11, 9, 13,
X 11, 15, 11, 11, 15, 7, 1, 11, 7, 3,
X 3, 3, 3, 7, 7, 7, 7, 7, 7, 5,
X 7, 7, 7, 1, 5, 9, 3, 1, 5, 3,
X 1, 5, 3, 3, 3, 3, 3, 3 };
Xint yychk[]={
X
X -1000, -1, -2, 280, 291, -5, 276, 285, 277, 284,
X 271, 288, -4, -12, -4, -6, 281, 273, 267, 262,
X 270, 291, -4, -8, -5, 257, 260, 291, 291, -9,
X -3, 264, 291, 264, 263, -4, -4, 267, 279, 288,
X 288, 259, 289, 267, 258, 265, 266, 268, 269, -8,
X -8, -2, 291, -13, 287, 286, 278, 283, 282, 275,
X -2, 290, -4, 264, -6, -4, -4, -7, -11, 272,
X -3, -8, -8, -5, -5, -5, -5, -5, -5, 261,
X -10, 264, -4, 264, 288, 290, -7, 291, 290, 292,
X 264, -3, 263, 274, 290, -3, -2 };
Xint yydef[]={
X
X 1, -2, 2, 37, -2, 0, 0, 37, 0, 0,
X 40, 3, 0, 36, 0, 37, 37, 0, 19, 20,
X 21, 0, 0, 0, 22, 0, 0, 39, 0, 0,
X 0, 5, 38, 6, 37, 0, 0, 37, 37, 33,
X 3, 0, 0, 0, 0, 0, 0, 0, 0, 29,
X 0, 15, 16, 41, 42, 43, 44, 45, 46, 47,
X 4, 18, 0, 8, 37, 0, 0, 0, 33, 0,
X 0, 30, 31, 23, 24, 25, 26, 27, 28, 32,
X 0, 7, 0, 10, 3, 12, 34, 0, 13, 17,
X 9, 0, 3, 0, 11, 35, 14 };
Xtypedef struct { char *t_name; int t_val; } yytoktype;
X#ifndef YYDEBUG
X# define YYDEBUG 0 /* don't allow debugging */
X#endif
X
X#if YYDEBUG
X
Xyytoktype yytoks[] =
X{
X "_BANG", 257,
X "_BANG_EQUALS", 258,
X "_AMPERAMPER", 259,
X "_LPAREN", 260,
X "_RPAREN", 261,
X "_PLUS_EQUALS", 262,
X "_COLON", 263,
X "_SEMIC", 264,
X "_LANGLE", 265,
X "_LANGLE_EQUALS", 266,
X "_EQUALS", 267,
X "_RANGLE", 268,
X "_RANGLE_EQUALS", 269,
X "_QUESTION_EQUALS", 270,
X "ACTIONS", 271,
X "CASE", 272,
X "DEFAULT", 273,
X "ELSE", 274,
X "EXISTING", 275,
X "FOR", 276,
X "IF", 277,
X "IGNORE", 278,
X "IN", 279,
X "INCLUDE", 280,
X "ON", 281,
X "PIECEMEAL", 282,
X "QUIETLY", 283,
X "RULE", 284,
X "SWITCH", 285,
X "TOGETHER", 286,
X "UPDATED", 287,
X "_LBRACE", 288,
X "_BARBAR", 289,
X "_RBRACE", 290,
X "ARG", 291,
X "STRING", 292,
X "-unknown-", -1 /* ends search */
X};
X
Xchar * yyreds[] =
X{
X "-no such reduction-",
X "stmts : /* empty */",
X "stmts : stmts rule",
X "rules : /* empty */",
X "rules : rules rule",
X "rule : INCLUDE args _SEMIC",
X "rule : ARG args _SEMIC",
X "rule : ARG args _COLON args _SEMIC",
X "rule : arg1 assign args _SEMIC",
X "rule : arg1 ON args assign args _SEMIC",
X "rule : arg1 DEFAULT _EQUALS args _SEMIC",
X "rule : FOR ARG IN args _LBRACE rules _RBRACE",
X "rule : SWITCH args _LBRACE cases _RBRACE",
X "rule : IF cond _LBRACE rules _RBRACE",
X "rule : IF cond _LBRACE rules _RBRACE ELSE rule",
X "rule : RULE ARG rule",
X "rule : ACTIONS eflags ARG",
X "rule : ACTIONS eflags ARG STRING",
X "rule : _LBRACE rules _RBRACE",
X "assign : _EQUALS",
X "assign : _PLUS_EQUALS",
X "assign : _QUESTION_EQUALS",
X "cond : arg1",
X "cond : arg1 _EQUALS arg1",
X "cond : arg1 _BANG_EQUALS arg1",
X "cond : arg1 _LANGLE arg1",
X "cond : arg1 _LANGLE_EQUALS arg1",
X "cond : arg1 _RANGLE arg1",
X "cond : arg1 _RANGLE_EQUALS arg1",
X "cond : _BANG cond",
X "cond : cond _AMPERAMPER cond",
X "cond : cond _BARBAR cond",
X "cond : _LPAREN cond _RPAREN",
X "cases : /* empty */",
X "cases : case cases",
X "case : CASE ARG _COLON rules",
X "args : argsany",
X "argsany : /* empty */",
X "argsany : argsany ARG",
X "arg1 : ARG",
X "eflags : /* empty */",
X "eflags : eflags eflag",
X "eflag : UPDATED",
X "eflag : TOGETHER",
X "eflag : IGNORE",
X "eflag : QUIETLY",
X "eflag : PIECEMEAL",
X "eflag : EXISTING",
X};
X#endif /* YYDEBUG */
X#line 1 "/usr/lib/yaccpar"
X/* @(#)yaccpar 1.10 89/04/04 SMI; from S5R3 1.10 */
X
X/*
X** Skeleton parser driver for yacc output
X*/
X
X/*
X** yacc user known macros and defines
X*/
X#define YYERROR goto yyerrlab
X#define YYACCEPT { free(yys); free(yyv); return(0); }
X#define YYABORT { free(yys); free(yyv); return(1); }
X#define YYBACKUP( newtoken, newvalue )\
X{\
X if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\
X {\
X yyerror( "syntax error - cannot backup" );\
X goto yyerrlab;\
X }\
X yychar = newtoken;\
X yystate = *yyps;\
X yylval = newvalue;\
X goto yynewstate;\
X}
X#define YYRECOVERING() (!!yyerrflag)
X#ifndef YYDEBUG
X# define YYDEBUG 1 /* make debugging available */
X#endif
X
X/*
X** user known globals
X*/
Xint yydebug; /* set to 1 to get debugging */
X
X/*
X** driver internal defines
X*/
X#define YYFLAG (-1000)
X
X/*
X** static variables used by the parser
X*/
Xstatic YYSTYPE *yyv; /* value stack */
Xstatic int *yys; /* state stack */
X
Xstatic YYSTYPE *yypv; /* top of value stack */
Xstatic int *yyps; /* top of state stack */
X
Xstatic int yystate; /* current state */
Xstatic int yytmp; /* extra var (lasts between blocks) */
X
Xint yynerrs; /* number of errors */
X
Xint yyerrflag; /* error recovery flag */
Xint yychar; /* current input token number */
X
X
X/*
X** yyparse - return 0 if worked, 1 if syntax error not recovered from
X*/
Xint
Xyyparse()
X{
X register YYSTYPE *yypvt; /* top of value stack for $vars */
X unsigned yymaxdepth = YYMAXDEPTH;
X
X /*
X ** Initialize externals - yyparse may be called more than once
X */
X yyv = (YYSTYPE*)malloc(yymaxdepth*sizeof(YYSTYPE));
X yys = (int*)malloc(yymaxdepth*sizeof(int));
X if (!yyv || !yys)
X {
X yyerror( "out of memory" );
X return(1);
X }
X yypv = &yyv[-1];
X yyps = &yys[-1];
X yystate = 0;
X yytmp = 0;
X yynerrs = 0;
X yyerrflag = 0;
X yychar = -1;
X
X goto yystack;
X {
X register YYSTYPE *yy_pv; /* top of value stack */
X register int *yy_ps; /* top of state stack */
X register int yy_state; /* current state */
X register int yy_n; /* internal state number info */
X
X /*
X ** get globals into registers.
X ** branch to here only if YYBACKUP was called.
X */
X yynewstate:
X yy_pv = yypv;
X yy_ps = yyps;
X yy_state = yystate;
X goto yy_newstate;
X
X /*
X ** get globals into registers.
X ** either we just started, or we just finished a reduction
X */
X yystack:
X yy_pv = yypv;
X yy_ps = yyps;
X yy_state = yystate;
X
X /*
X ** top of for (;;) loop while no reductions done
X */
X yy_stack:
X /*
X ** put a state and value onto the stacks
X */
X#if YYDEBUG
X /*
X ** if debugging, look up token value in list of value vs.
X ** name pairs. 0 and negative (-1) are special values.
X ** Note: linear search is used since time is not a real
X ** consideration while debugging.
X */
X if ( yydebug )
X {
X register int yy_i;
X
X (void)printf( "State %d, token ", yy_state );
X if ( yychar == 0 )
X (void)printf( "end-of-file\n" );
X else if ( yychar < 0 )
X (void)printf( "-none-\n" );
X else
X {
X for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
X yy_i++ )
X {
X if ( yytoks[yy_i].t_val == yychar )
X break;
X }
X (void)printf( "%s\n", yytoks[yy_i].t_name );
X }
X }
X#endif /* YYDEBUG */
X if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */
X {
X /*
X ** reallocate and recover. Note that pointers
X ** have to be reset, or bad things will happen
X */
X int yyps_index = (yy_ps - yys);
X int yypv_index = (yy_pv - yyv);
X int yypvt_index = (yypvt - yyv);
X yymaxdepth += YYMAXDEPTH;
X yyv = (YYSTYPE*)realloc((char*)yyv,
X yymaxdepth * sizeof(YYSTYPE));
X yys = (int*)realloc((char*)yys,
X yymaxdepth * sizeof(int));
X if (!yyv || !yys)
X {
X yyerror( "yacc stack overflow" );
X return(1);
X }
X yy_ps = yys + yyps_index;
X yy_pv = yyv + yypv_index;
X yypvt = yyv + yypvt_index;
X }
X *yy_ps = yy_state;
X *++yy_pv = yyval;
X
X /*
X ** we have a new state - find out what to do
X */
X yy_newstate:
X if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG )
X goto yydefault; /* simple state */
X#if YYDEBUG
X /*
X ** if debugging, need to mark whether new token grabbed
X */
X yytmp = yychar < 0;
X#endif
X if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) )
X yychar = 0; /* reached EOF */
X#if YYDEBUG
X if ( yydebug && yytmp )
X {
X register int yy_i;
X
X (void)printf( "Received token " );
X if ( yychar == 0 )
X (void)printf( "end-of-file\n" );
X else if ( yychar < 0 )
X (void)printf( "-none-\n" );
X else
X {
X for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
X yy_i++ )
X {
X if ( yytoks[yy_i].t_val == yychar )
X break;
X }
X (void)printf( "%s\n", yytoks[yy_i].t_name );
X }
X }
X#endif /* YYDEBUG */
X if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) )
X goto yydefault;
X if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/
X {
X yychar = -1;
X yyval = yylval;
X yy_state = yy_n;
X if ( yyerrflag > 0 )
X yyerrflag--;
X goto yy_stack;
X }
X
X yydefault:
X if ( ( yy_n = yydef[ yy_state ] ) == -2 )
X {
X#if YYDEBUG
X yytmp = yychar < 0;
X#endif
X if ( ( yychar < 0 ) && ( ( yychar = yylex() ) < 0 ) )
X yychar = 0; /* reached EOF */
X#if YYDEBUG
X if ( yydebug && yytmp )
X {
X register int yy_i;
X
X (void)printf( "Received token " );
X if ( yychar == 0 )
X (void)printf( "end-of-file\n" );
X else if ( yychar < 0 )
X (void)printf( "-none-\n" );
X else
X {
X for ( yy_i = 0;
X yytoks[yy_i].t_val >= 0;
X yy_i++ )
X {
X if ( yytoks[yy_i].t_val
X == yychar )


X {
X break;
X }
X }

X (void)printf( "%s\n", yytoks[yy_i].t_name );
X }
X }
X#endif /* YYDEBUG */
X /*
X ** look through exception table
X */
X {
X register int *yyxi = yyexca;
X
X while ( ( *yyxi != -1 ) ||
X ( yyxi[1] != yy_state ) )
X {
X yyxi += 2;
X }
X while ( ( *(yyxi += 2) >= 0 ) &&
X ( *yyxi != yychar ) )
X ;
X if ( ( yy_n = yyxi[1] ) < 0 )
X YYACCEPT;
X }
X }
X
X /*
X ** check for syntax error
X */
X if ( yy_n == 0 ) /* have an error */
X {
X /* no worry about speed here! */
X switch ( yyerrflag )
X {
X case 0: /* new error */
X yyerror( "syntax error" );
X goto skip_init;
X yyerrlab:
X /*
X ** get globals into registers.
X ** we have a user generated syntax type error
X */
X yy_pv = yypv;
X yy_ps = yyps;
X yy_state = yystate;
X yynerrs++;
X skip_init:
X case 1:
X case 2: /* incompletely recovered error */
X /* try again... */
X yyerrflag = 3;
X /*
X ** find state where "error" is a legal
X ** shift action
X */
X while ( yy_ps >= yys )
X {
X yy_n = yypact[ *yy_ps ] + YYERRCODE;
X if ( yy_n >= 0 && yy_n < YYLAST &&
X yychk[yyact[yy_n]] == YYERRCODE) {
X /*
X ** simulate shift of "error"
X */
X yy_state = yyact[ yy_n ];
X goto yy_stack;
X }
X /*
X ** current state has no shift on
X ** "error", pop stack
X */
X#if YYDEBUG
X# define _POP_ "Error recovery pops state %d, uncovers state %d\n"
X if ( yydebug )
X (void)printf( _POP_, *yy_ps,
X yy_ps[-1] );
X# undef _POP_
X#endif
X yy_ps--;
X yy_pv--;
X }
X /*
X ** there is no state on stack with "error" as
X ** a valid shift. give up.
X */
X YYABORT;
X case 3: /* no shift yet; eat a token */
X#if YYDEBUG
X /*
X ** if debugging, look up token in list of
X ** pairs. 0 and negative shouldn't occur,
X ** but since timing doesn't matter when
X ** debugging, it doesn't hurt to leave the
X ** tests here.
X */
X if ( yydebug )
X {
X register int yy_i;
X
X (void)printf( "Error recovery discards " );
X if ( yychar == 0 )
X (void)printf( "token end-of-file\n" );
X else if ( yychar < 0 )
X (void)printf( "token -none-\n" );
X else
X {
X for ( yy_i = 0;
X yytoks[yy_i].t_val >= 0;
X yy_i++ )
X {
X if ( yytoks[yy_i].t_val
X == yychar )


X {
X break;
X }
X }

X (void)printf( "token %s\n",
X yytoks[yy_i].t_name );
X }
X }
X#endif /* YYDEBUG */
X if ( yychar == 0 ) /* reached EOF. quit */
X YYABORT;
X yychar = -1;
X goto yy_newstate;
X }
X }/* end if ( yy_n == 0 ) */
X /*
X ** reduction by production yy_n
X ** put stack tops, etc. so things right after switch
X */
X#if YYDEBUG
X /*
X ** if debugging, print the string that is the user's
X ** specification of the reduction which is just about
X ** to be done.
X */
X if ( yydebug )
X (void)printf( "Reduce by (%d) \"%s\"\n",
X yy_n, yyreds[ yy_n ] );
X#endif
X yytmp = yy_n; /* value to switch over */
X yypvt = yy_pv; /* $vars top of value stack */
X /*
X ** Look in goto table for next state
X ** Sorry about using yy_state here as temporary
X ** register variable, but why not, if it works...
X ** If yyr2[ yy_n ] doesn't have the low order bit
X ** set, then there is no action to be done for
X ** this reduction. So, no saving & unsaving of
X ** registers done. The only difference between the
X ** code just after the if and the body of the if is
X ** the goto yy_stack in the body. This way the test
X ** can be made before the choice of what to do is needed.
X */
X {
X /* length of production doubled with extra bit */
X register int yy_len = yyr2[ yy_n ];
X
X if ( !( yy_len & 01 ) )
X {
X yy_len >>= 1;
X yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
X yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
X *( yy_ps -= yy_len ) + 1;
X if ( yy_state >= YYLAST ||
X yychk[ yy_state =
X yyact[ yy_state ] ] != -yy_n )
X {
X yy_state = yyact[ yypgo[ yy_n ] ];
X }
X goto yy_stack;
X }
X yy_len >>= 1;
X yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
X yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
X *( yy_ps -= yy_len ) + 1;
X if ( yy_state >= YYLAST ||
X yychk[ yy_state = yyact[ yy_state ] ] != -yy_n )
X {
X yy_state = yyact[ yypgo[ yy_n ] ];
X }
X }
X /* save until reenter driver code */
X yystate = yy_state;
X yyps = yy_ps;
X yypv = yy_pv;
X }
X /*
X ** code supplied by user is placed in this switch
X */
X switch( yytmp )
X {
X
Xcase 1:
X# line 98 "jamgram.y"
X{
X compile_builtins();
X } break;
Xcase 2:
X# line 102 "jamgram.y"
X{
X (*(yypvt[-0].parse->func))( yypvt[-0].parse, L0, L0 );
X parse_free( yypvt[-0].parse );
X } break;
Xcase 3:
X# line 114 "jamgram.y"
X{ yyval.parse = prules( P0, P0 ); } break;
Xcase 4:
X# line 116 "jamgram.y"
X{ yyval.parse = prules( yypvt[-1].parse, yypvt[-0].parse ); } break;
Xcase 5:
X# line 120 "jamgram.y"
X{ yyval.parse = pincl( yypvt[-1].list ); } break;
Xcase 6:
X# line 122 "jamgram.y"
X{ yyval.parse = prule( yypvt[-2].string, yypvt[-1].list, L0 ); } break;
Xcase 7:
X# line 124 "jamgram.y"
X{ yyval.parse = prule( yypvt[-4].string, yypvt[-3].list, yypvt[-1].list ); } break;
Xcase 8:
X# line 126 "jamgram.y"
X{ yyval.parse = pset( yypvt[-3].list, yypvt[-1].list, yypvt[-2].number ); } break;
Xcase 9:
X# line 128 "jamgram.y"
X{ yyval.parse = pstng( yypvt[-3].list, yypvt[-5].list, yypvt[-1].list, yypvt[-2].number ); } break;
Xcase 10:
X# line 130 "jamgram.y"
X{ yyval.parse = pset( yypvt[-4].list, yypvt[-1].list, ASSIGN_DEFAULT ); } break;
Xcase 11:
X# line 132 "jamgram.y"
X{ yyval.parse = pfor( yypvt[-5].string, yypvt[-1].parse, yypvt[-3].list ); } break;
Xcase 12:
X# line 134 "jamgram.y"
X{ yyval.parse = pswitch( yypvt[-3].list, yypvt[-1].parse ); } break;
Xcase 13:
X# line 136 "jamgram.y"
X{ yyval.parse = pif( yypvt[-3].parse, pthen( yypvt[-1].parse, P0 ) ); } break;
Xcase 14:
X# line 138 "jamgram.y"
X{ yyval.parse = pif( yypvt[-5].parse, pthen( yypvt[-3].parse, yypvt[-0].parse ) ); } break;
Xcase 15:
X# line 140 "jamgram.y"
X{ yyval.parse = psetc( yypvt[-1].string, yypvt[-0].parse ); } break;
Xcase 16:
X# line 142 "jamgram.y"
X{ yymode( SCAN_STRING ); } break;
Xcase 17:
X# line 144 "jamgram.y"
X{ yyval.parse = psete( yypvt[-2].string, yypvt[-0].string, yypvt[-3].number );
X yymode( SCAN_NORMAL ); } break;
Xcase 18:
X# line 147 "jamgram.y"
X{ yyval.parse = yypvt[-1].parse; } break;
Xcase 19:
X# line 155 "jamgram.y"
X{ yyval.number = ASSIGN_SET; } break;
Xcase 20:
X# line 157 "jamgram.y"
X{ yyval.number = ASSIGN_APPEND; } break;
Xcase 21:
X# line 159 "jamgram.y"
X{ yyval.number = ASSIGN_DEFAULT; } break;
Xcase 22:
X# line 167 "jamgram.y"
X{ yyval.parse = pcomp( COND_EXISTS, yypvt[-0].list, L0 ); } break;
Xcase 23:
X# line 169 "jamgram.y"
X{ yyval.parse = pcomp( COND_EQUALS, yypvt[-2].list, yypvt[-0].list ); } break;
Xcase 24:
X# line 171 "jamgram.y"
X{ yyval.parse = pcomp( COND_NOTEQ, yypvt[-2].list, yypvt[-0].list ); } break;
Xcase 25:
X# line 173 "jamgram.y"
X{ yyval.parse = pcomp( COND_LESS, yypvt[-2].list, yypvt[-0].list ); } break;
Xcase 26:
X# line 175 "jamgram.y"
X{ yyval.parse = pcomp( COND_LESSEQ, yypvt[-2].list, yypvt[-0].list ); } break;
Xcase 27:
X# line 177 "jamgram.y"
X{ yyval.parse = pcomp( COND_MORE, yypvt[-2].list, yypvt[-0].list ); } break;
Xcase 28:
X# line 179 "jamgram.y"
X{ yyval.parse = pcomp( COND_MOREEQ, yypvt[-2].list, yypvt[-0].list ); } break;
Xcase 29:
X# line 181 "jamgram.y"
X{ yyval.parse = pcond( COND_NOT, yypvt[-0].parse, P0 ); } break;
Xcase 30:
X# line 183 "jamgram.y"
X{ yyval.parse = pcond( COND_AND, yypvt[-2].parse, yypvt[-0].parse ); } break;
Xcase 31:
X# line 185 "jamgram.y"
X{ yyval.parse = pcond( COND_OR, yypvt[-2].parse, yypvt[-0].parse ); } break;
Xcase 32:
X# line 187 "jamgram.y"
X{ yyval.parse = yypvt[-1].parse; } break;
Xcase 33:
X# line 198 "jamgram.y"
X{ yyval.parse = P0; } break;
Xcase 34:
X# line 200 "jamgram.y"
X{ yyval.parse = pcases( yypvt[-1].parse, yypvt[-0].parse ); } break;
Xcase 35:
X# line 204 "jamgram.y"
X{ yyval.parse = pcase( yypvt[-2].string, yypvt[-0].parse ); } break;
Xcase 36:
X# line 213 "jamgram.y"
X{ yymode( SCAN_NORMAL ); } break;
Xcase 37:
X# line 217 "jamgram.y"
X{ yyval.list = L0; yymode( SCAN_PUNCT ); } break;
Xcase 38:
X# line 219 "jamgram.y"
X{ yyval.list = list_new( yypvt[-1].list, copystr( yypvt[-0].string ) ); } break;
Xcase 39:
X# line 223 "jamgram.y"
X{ yyval.list = list_new( L0, copystr( yypvt[-0].string ) ); } break;
Xcase 40:
X# line 232 "jamgram.y"
X{ yyval.number = 0; } break;
Xcase 41:
X# line 234 "jamgram.y"
X{ yyval.number = yypvt[-1].number | yypvt[-0].number; } break;
Xcase 42:
X# line 238 "jamgram.y"
X{ yyval.number = EXEC_UPDATED; } break;
Xcase 43:
X# line 240 "jamgram.y"
X{ yyval.number = EXEC_TOGETHER; } break;
Xcase 44:
X# line 242 "jamgram.y"
X{ yyval.number = EXEC_IGNORE; } break;
Xcase 45:
X# line 244 "jamgram.y"
X{ yyval.number = EXEC_QUIETLY; } break;
Xcase 46:
X# line 246 "jamgram.y"
X{ yyval.number = EXEC_PIECEMEAL; } break;
Xcase 47:
X# line 248 "jamgram.y"
X{ yyval.number = EXEC_EXISTING; } break;
X }
X goto yystack; /* reset registers in driver code */
X}
END_OF_FILE
if test 23346 -ne `wc -c <'jamgram.c'`; then
echo shar: \"'jamgram.c'\" unpacked with wrong size!
fi
# end of 'jamgram.c'
fi
if test -f 'make1.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'make1.c'\"
else
echo shar: Extracting \"'make1.c'\" \(13613 characters\)
sed "s/^X//" >'make1.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * make1.c - execute command to bring targets up to date
X *
X * This module contains make1(), the entry point called by make() to
X * recursively decend the dependency graph executing update actions as
X * marked by make0().


X *
X * External routines:
X *

X * make1() - execute commands to update a TARGET and all its dependents
X *
X * Internal routines, the recursive/asynchronous command executors:
X *
X * make1a() - recursively traverse target tree, calling make1b()
X * make1b() - dependents of target built, now build target with make1c()
X * make1c() - launch target's next command, call make1b() when done
X * make1d() - handle command execution completion and call back make1c()
X *
X * Internal support routines:
X *
X * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
X * make1chunk() - compute number of source that can fit on cmd line
X * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
X * make1remove() - remove targets after interrupted command
X *
X * 04/16/94 (seiwald) - Split from make.c.
X * 04/21/94 (seiwald) - Handle empty "updated" actions.
X * 05/04/94 (seiwald) - async multiprocess (-j) support


X * 06/01/94 (seiwald) - new 'actions existing' does existing sources

X * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
X * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
X * 01/22/94 (seiwald) - pass per-target JAMSHELL down to execcmd().
X * 02/28/95 (seiwald) - Handle empty "existing" actions.
X * 03/10/95 (seiwald) - Fancy counts.
X */
X
X# include "jam.h"
X
X# include "lists.h"
X# include "parse.h"
X# include "variable.h"
X# include "rules.h"
X
X# include "search.h"
X# include "newstr.h"
X# include "make.h"
X# include "command.h"
X# include "execcmd.h"
X
Xstatic void make1a();
Xstatic void make1b();
Xstatic void make1c();
Xstatic void make1d();
X
Xstatic CMD *make1cmds();
Xstatic int make1chunk();
Xstatic void make1remove();
Xstatic LIST *make1list();
Xstatic int make1exec();
X
X# define max( a,b ) ((a)>(b)?(a):(b))
X
X/* Ugly static - it's too hard to carry it through the callbacks. */
X
Xstatic struct {
X int failed;
X int skipped;
X int total;
X} counts[1] ;
X
X/*
X * make1() - execute commands to update a TARGET and all its dependents
X */
X
Xstatic int intr = 0;
X
Xvoid
Xmake1( t )
XTARGET *t;
X{
X memset( (char *)counts, 0, sizeof( *counts ) );
X
X /* Recursively make the target and its dependents */
X
X make1a( t, (TARGET *)0 );
X
X /* Wait for any outstanding commands to finish running. */
X
X while( execwait() )
X ;
X
X if( DEBUG_MAKE )
X {
X int failed = counts->failed - counts->skipped;
X int made = counts->total - counts->failed;
X
X if( failed )
X printf( "...failed updating %d target(s)...\n", failed );
X if( counts->skipped )
X printf( "...skipped %d target(s)...\n", counts->skipped );
X if( made )
X printf( "...updated %d target(s)...\n", made );
X }
X}
X
X/*
X * make1a() - recursively traverse target tree, calling make1b()
X */
X
Xstatic void
Xmake1a( t, parent )
XTARGET *t;
XTARGET *parent;
X{
X TARGETS *c;
X int i;
X
X /* If the parent is the first to try to build this target */
X /* or this target is in the make1c() quagmire, arrange for the */
X /* parent to be notified when this target is built. */
X
X if( t->progress == T_MAKE_INIT || t->progress == T_MAKE_RUNNING )
X if( parent )
X {
X t->parents = targetentry( t->parents, parent );
X parent->asynccnt++;
X }
X
X if( t->progress != T_MAKE_INIT )
X return;
X
X /* Asynccnt counts the dependents preventing this target from */
X /* proceeding to make1b() for actual building. We start off with */
X /* a count of 1 to prevent anything from happening until we can */
X /* call all dependent. This 1 is accounted for when we call */
X /* make1b() ourselves, below. */
X
X t->asynccnt = 1;
X
X /* Recurse on our dependents, manipulating progress to guard */
X /* against circular dependency. */
X
X t->progress = T_MAKE_ONSTACK;
X
X for( i = T_DEPS_DEPENDS; i <= T_DEPS_INCLUDES; i++ )
X for( c = t->deps[i]; c && !intr; c = c->next )
X make1a( c->target, t );
X
X t->progress = T_MAKE_RUNNING;
X
X /* Now that all dependents have bumped asynccnt, we now allow */
X /* decrement our reference to asynccnt. */
X
X make1b( t );
X}
X
X/*
X * make1b() - dependents of target built, now build target with make1c()
X */
X
Xstatic void
Xmake1b( t )
XTARGET *t;
X{
X TARGETS *c;
X int i;
X char *failed = "dependents";
X
X /* If any dependents are still outstanding, wait until they */
X /* call make1b() to signal their completion. */
X
X if( --t->asynccnt )
X return;
X
X /* Now ready to build target 't'... if dependents built ok. */
X
X /* Collect status from dependents */
X
X for( i = T_DEPS_DEPENDS; i <= T_DEPS_INCLUDES; i++ )
X for( c = t->deps[i]; c; c = c->next )
X if( c->target->status > t->status )
X {
X failed = c->target->name;
X t->status = c->target->status;
X }
X
X /* If actions on deps have failed, bail. */
X /* Otherwise, execute all actions to make target */
X
X if( t->status == EXEC_CMD_FAIL )
X {
X if( t->actions )
X {
X printf( "...skipped %s for lack of %s...\n", t->name, failed );
X ++counts->skipped;
X ++counts->total;
X }
X }
X else if( t->status == EXEC_CMD_INTR )
X {
X /* sokay */
X }
X else switch( t->fate ) /* EXEC_CMD_OK */
X {
X case T_FATE_INIT:
X case T_FATE_MAKING:
X /* shouldn't happen */
X
X case T_FATE_STABLE:
X break;
X
X case T_FATE_CANTFIND:
X case T_FATE_CANTMAKE:
X t->status = EXEC_CMD_FAIL;
X break;
X
X case T_FATE_ISTMP:
X if( DEBUG_MAKEQ )
X printf( "...using %s...\n", t->name );
X break;
X
X case T_FATE_TOUCHED:
X case T_FATE_MISSING:
X case T_FATE_OUTDATED:
X case T_FATE_UPDATE:
X /* Set "on target" vars, execute actions, unset vars */
X
X if( t->actions && !( ++counts->total % 100 ) && DEBUG_MAKE )
X printf( "...on %dth target...\n", counts->total );
X
X pushsettings( t->settings );
X t->cmds = (char *)make1cmds( t->actions );
X popsettings( t->settings );


X
X break;
X }
X

X /* Call make1c() to begin the execution of the chain of commands */
X /* needed to build target. If we're not going to build target */
X /* (because of dependency failures or because no commands need to */
X /* be run) the chain will be empty and make1c() will directly */
X /* signal the completion of target. */
X
X make1c( t );
X}
X
X/*
X * make1c() - launch target's next command, call make1b() when done
X */
X
Xstatic void
Xmake1c( t )
XTARGET *t;
X{
X CMD *cmd = (CMD *)t->cmds;
X
X /* If there are (more) commands to run to build this target */
X /* (and we haven't hit an error running earlier comands) we */
X /* launch the command with execcmd(). */
X
X /* If there are no more commands to run, we collect the status */
X /* from all the actions then report our completion to all the */
X /* parents. */
X
X if( cmd && t->status == EXEC_CMD_OK )
X {
X if( cmd->rule->flags & RULE_QUIETLY ? DEBUG_MAKEQ : DEBUG_MAKE )
X {
X printf( "%s ", cmd->rule->name );
X list_print( cmd->targets );


X printf( "\n" );
X }
X

X if( DEBUG_EXEC )
X printf( "%s\n", cmd->buf );
X
X if( DEBUG_MAKE && !globs.noexec )
X fflush( stdout );
X
X if( globs.noexec )
X {
X make1d( t, EXEC_CMD_OK );
X }
X else
X {
X execcmd( cmd->buf, make1d, t, cmd->shell );
X }
X }
X else
X {
X TARGETS *c;
X ACTIONS *actions;
X
X t->progress = T_MAKE_DONE;
X
X /* Collect status from actions, and distribute it as well */
X
X for( actions = t->actions; actions; actions = actions->next )
X if( actions->action->status > t->status )
X t->status = actions->action->status;
X
X for( actions = t->actions; actions; actions = actions->next )
X if( t->status > actions->action->status )
X actions->action->status = t->status;
X
X /* Tally failure */
X
X if( t->status != EXEC_CMD_OK && t->actions )
X counts->failed++;
X
X /* Tell parents dependent has been built */
X
X for( c = t->parents; c; c = c->next )
X make1b( c->target );
X }
X}
X
X/*
X * make1d() - handle command execution completion and call back make1c()
X */
X
Xstatic void
Xmake1d( t, status )
XTARGET *t;
Xint status;
X{
X CMD *cmd = (CMD *)t->cmds;
X
X /* Execcmd() has completed. All we need to do is fiddle with the */
X /* status and signal our completion so make1c() can run the next */
X /* command. On interrupts, we bail heavily. */
X
X if( status == EXEC_CMD_FAIL && ( cmd->rule->flags & RULE_IGNORE ) )
X status = EXEC_CMD_OK;
X
X if( status == EXEC_CMD_FAIL )
X {
X if( DEBUG_MAKE )
X {
X printf( "...failed %s ", cmd->rule->name );
X list_print( cmd->targets );
X printf( "...\n" );
X }
X }
X else if( status == EXEC_CMD_INTR )
X {
X /* If the command was interrupted and the target is not */
X /* "precious", remove the targets */
X
X if( !( cmd->rule->flags & RULE_TOGETHER ) )
X make1remove( cmd->targets );
X
X /* Set intr so _everything_ fails */
X
X ++intr;
X }
X
X t->status = status;
X t->cmds = (char *)cmd_next( cmd );
X
X cmd_free( cmd );
X
X make1c( t );
X}
X
X/*
X * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
X *
X * Essentially copies a chain of ACTIONs to a chain of CMDs,
X * grouping RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions,
X * and handling RULE_NEWSRCS actions. The result is a chain of
X * CMDs which can be expanded by var_string() and executed with
X * execcmd().
X */
X
Xstatic CMD *
Xmake1cmds( a0 )
XACTIONS *a0;
X{
X CMD *cmds = 0;
X LIST *shell = var_get( "JAMSHELL" ); /* shell is per-target */
X
X /* Step through actions */
X /* Actions may be shared with other targets or grouped with */
X /* RULE_TOGETHER, so actions already seen are skipped. */
X
X for( ; a0; a0 = a0->next )
X {
X RULE *rule = a0->action->rule;
X int chunk = 0;
X LIST *nt, *ns;
X ACTIONS *a1;
X
X /* Only do rules with commands to execute. */
X /* If this action has already been executed, use saved status */
X
X if( !rule->actions || a0->action->progress != T_MAKE_INIT )
X continue;
X
X a0->action->progress = T_MAKE_RUNNING;
X
X /* Make LISTS of targets and sources */
X /* If `execute together` has been specified for this rule, tack */
X /* on sources from each instance of this rule for this target. */
X
X nt = make1list( L0, a0->action->targets, 0 );
X ns = make1list( L0, a0->action->sources, rule->flags );
X
X if( rule->flags & RULE_TOGETHER )
X for( a1 = a0->next; a1; a1 = a1->next )
X if( a1->action->rule == rule &&
X a1->action->progress == T_MAKE_INIT )
X {
X ns = make1list( ns, a1->action->sources, rule->flags );
X a1->action->progress = T_MAKE_RUNNING;
X }
X
X /* If doing only updated (or existing) sources, but none have */
X /* been updated (or exist), skip this action. */
X
X if( !ns && ( rule->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
X {
X list_free( nt );
X continue;
X }
X
X /* If rule is to be cut into (at most) MAXCMD pieces, estimate */
X /* bytes per $(>) element and aim for using MAXCMD minus a */
X /* fudgefactor. */
X
X if( rule->flags & RULE_PIECEMEAL )
X chunk = make1chunk( rule->actions, nt, ns );
X
X if( chunk )
X {
X int start;
X LIST *somes;
X
X if( DEBUG_EXEC )
X printf( "%s: %d args per exec\n", rule->name, chunk );
X
X for( start = 0;
X somes = list_sublist( ns, start, chunk );
X start += chunk )
X {
X cmds = cmd_new( cmds, rule,
X list_copy( L0, nt ), somes,
X list_copy( L0, shell ) );
X }
X
X list_free( nt );
X list_free( ns );
X }
X else
X {
X cmds = cmd_new( cmds, rule, nt, ns, list_copy( L0, shell ) );
X }
X }
X
X return cmds;
X}
X
X/*
X * make1chunk() - compute number of source that can fit on cmd line


X */
X
Xstatic int

Xmake1chunk( cmd, targets, sources )
Xchar *cmd;
XLIST *targets;
XLIST *sources;
X{
X int onesize;
X int onediff;
X int chunk = 0;
X LIST *somes;
X char buf[ MAXCMD ];
X
X somes = list_sublist( sources, 0, 1 );
X onesize = var_string( cmd, buf, targets, somes );
X list_free( somes );
X
X somes = list_sublist( sources, 0, 2 );
X onediff = var_string( cmd, buf, targets, somes ) - onesize;
X list_free( somes );
X
X if( onediff > 0 )
X chunk = 3 * ( MAXCMD - onesize ) / 4 / onediff + 1;
X
X return chunk;
X}
X
X/*
X * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
X */
X
Xstatic LIST *
Xmake1list( l, targets, flags )
XLIST *l;
XTARGETS *targets;
Xint flags;
X{
X for( ; targets; targets = targets->next )
X {
X TARGET *t = targets->target;
X
X /*
X * spot the kludge! If a target is not in the dependency tree,
X * it didn't get bound by make0(), so we have to do it here.
X * Ugly.
X */
X
X if( t->binding == T_BIND_UNBOUND && !( t->flags & T_FLAG_NOTFILE ) )
X {
X /* Sources to 'actions existing' are never in the dependency */
X /* graph (if they were, they'd get built and 'existing' would */
X /* be superfluous, so throttle warning message about independent */
X /* targets. */
X
X if( !( flags & RULE_EXISTING ) )
X printf( "warning: using independent target %s\n", t->name );
X
X pushsettings( t->settings );
X t->boundname = search( t->name, &t->time );
X t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
X popsettings( t->settings );
X }
X
X if( ( flags & RULE_EXISTING ) && t->binding != T_BIND_EXISTS )
X continue;
X
X if( ( flags & RULE_NEWSRCS ) && t->fate <= T_FATE_STABLE )
X continue;
X
X /* boundname is null for T_FLAG_NOTFILE targets - use name */
X
X l = list_new( l, copystr( t->boundname ? t->boundname : t->name ) );
X }
X
X return l;
X}
X
X/*
X * make1remove() - remove targets after interrupted command
X */
X
Xstatic void
Xmake1remove( targets )
XLIST *targets;
X{
X for( ; targets; targets = list_next( targets ) )
X {
X if( !unlink( targets->string ) )
X printf( "%s removed\n", targets->string );
X }
X}
END_OF_FILE
if test 13613 -ne `wc -c <'make1.c'`; then
echo shar: \"'make1.c'\" unpacked with wrong size!
fi
# end of 'make1.c'
fi
echo shar: End of archive 5 \(of 7\).
cp /dev/null ark5isdone

Christopher Seiwald

unread,
Apr 11, 1995, 3:00:00 AM4/11/95
to
Submitted-by: sei...@tea.org (Christopher Seiwald)
Posting-number: Volume 47, Issue 113
Archive-name: jam/part06

Environment: UNIX, NT, VMS
Supersedes: jam: Volume 27, Issue 81-85

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".

# Contents: RELNOTES compile.c expand.c fileunix.c filevms.c hash.c
# jam.c lists.c make.c variable.c
# Wrapped by kent@ftp on Sat Mar 25 12:04:11 1995


PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 6 (of 7)."'
if test -f 'RELNOTES' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'RELNOTES'\"
else
echo shar: Extracting \"'RELNOTES'\" \(7759 characters\)
sed "s/^X//" >'RELNOTES' <<'END_OF_FILE'
XRelease notes for Jam 2.0.
X
X1. Release info:
X Jam 2.0
X March 10, 1994
X VERSION 2.0
X PATCHLEVEL 5
X
X2. Porting
X
X Windows/NT is now (crudely) supported, courtesy of Brett Taylor
X and Laura Wingerd.
X
X COHERENT/386 is now supported, courtesy of Fred Smith.
X
X Solaris archive string table for long archive names is now
X supported, thanks to Mike Matrigali.
X
X3. Compatibility
X
X Jam 2.0 syntax is a superset of Jam 1.0 syntax, and thus it can
X interpret a Jam 1.0 Jambase.
X
X The Jam 2.0 Jambase is a superset of the Jam 1.0 Jambase, and
X thus it can include a Jamfile written for Jam 1.0.
X
X4. Changes from Jam 1.0 to Jam 2.0
X
X4.1. Documentation changes
X
X New Jamfile.5 manual page, with lots of examples and easy
X reading. It replaces both the old "Examples" file as well as
X the old Jambase.5 manual page.
X
X jam.1 edited by Stephen W. Liddle and Diane Holt.
X
X4.2. Jambase Changes (see Jamfile.5)
X
X4.2.1. New rules:
X
X There are new rules to make handling subdirectories easier:
X SubDir, SubInclude, SubDirCcFlags, SubDirHdrs.
X
X There are new rules to handle file-specific CCFLAGS and HDRS:
X ObjectCcFlags and ObjectHdrs.
X
X Misc new rules: HardLink, InstallShell, MkDir.
X
X New rule "clean" that deletes exactly what jam has built, and
X "uninstall" that deletes exactly what was installed.
X
X New rules for handling suffixes .s, .f, .cc, .cpp, .C.
X
X4.2.2. Old rules:
X
X The InstallBin, Lib, Man, and the new Shell rules now take the
X destination directory as the target and the files to be copied
X as sources. These rules formerly took the files to be copied
X as targets, and used built-in destination directories of
X $(BINDIR), $(LIBDIR), $(MANDIR), and $(BINDIR).
X
X The InstallBin, Lib, Man, and Shell rules use the install(1)
X program now, instead of doing their own copying.
X
X The Cc rule now uses -o when possible, rather than moving the
X result. Some platforms (Pyramid?) have a broken -o.
X
X Jambase rules taking libraries, objects, and executables now
X all ignore the suffixes provided and use the one defined in the
X Jambase for the platform.
X
X Stupid yyacc support moved out of Jambase, as jam is its only
X likely user.
X
X Jambase now purturbs library sources with a "grist" of
X SOURCE_GRIST.
X
X4.2.3. Misc:
X
X The names of the default rules defined in Jambase have been
X lowercased and un-abbreviated, to be more imake(1) like.
X
X The Jambase has been reorganized and sorted, with VMS and NT
X support moved in from their own files.
X
X The Jambase has been relocated on UNIX from /usr/local/lib/jam
X to /usr/local/lib.
X
X4.3. Jam changes (see jam.1)
X
X4.3.1. Flags:
X
X New -a (anyhow) flag: means build everything.
X
X New -j<x> flag: run jobs in parallel.
X
X Old -t now rebuilds the touched target, rather that just the
X target's parents.
X
X -n now implies -d2, so that you see what's happening. The
X debug level can be subsequently overridden.
X
X New -v to dump version.
X
X4.3.2. Rules:
X
X New ALWAYS rule behaves like -t: always builds target.
X
X New EXIT rule makes it possible to raise a fatal error.
X
X New LEAVES rule which say target depends only on the update
X times of the leaf sources.
X
X New NOUPDATE rule says built targets only if they don't exist.
X
X NOTIME has been renamed NOTFILE, to more accurately reflect its
X meaning (it says a target is not to be bound to a file).
X
X4.3.3. Variables:
X
X New special variable JAMSHELL: argv template for command execution
X shell.
X
X Variables, both normal and target-specific, can have their
X value appended with the syntax "var += value" or "var on target
X += value".
X
X "?=" is now synonymous with "default =".
X
X Imported enviroment variable values are now split at blanks
X (:'s if the variable name ends in PATH), so that they become
X proper list values.
X
X4.3.4. Misc:
X
X Files to be sourced with "include" are now bound first, so
X $(SEARCH) and $(LOCATE) affect them. They still can't be
X built, though.
X
X New modifier on "actions": "existing" causes $(>) to expand
X only those files that currently exist.
X
X4.3.5. Bug fixes:
X
X When scanning tokens known to be argument lists (such as the
X arguments to rule invocations and variable assignment), the
X parser now tells the scanner to ignore alphabetic keywords, as
X all such lists terminate with punctuation keywords (like : or
X ;). This way, alphabetic keywords don't need to be quoted when
X they appear as arguments.
X
X The scanner has been fixed to handle oversized tokens,
X unterminated quotes, unterminated action blocks, and tokens
X abutting EOF (i.e. a token with no white space before EOF).
X
X The progress report "...on xth target..." used to count all
X targets, rather than just those with updating actions. Since
X the original pronouncement of targets to be udpated included
X only those with updating actions, the progress report has been
X changed to match.
X
X 'If' conditionals now must be single arguments. Previously,
X they could be zero or more arguments, which didn't make much
X sense, and made things like 'foo == bar' true. The comparison
X operator is '=', and '==' just looked like the second of three
X arguments in the unary "non-empty argument list" conditional.
X
X Header files indirectly including themselves were mistakenly
X reported as being dependent on themselves. Recursing through
X header file dependencies is now done after determining the fate
X of the target.
X
X The variable expansion support was expanding $(X)$(UNDEF) as if
X it were $(X). It now expands to an empty list, like it
X should.
X
X The UNIX version of file_build() didn't handle "dir/.suffix"
X right. Now it does.
X
X The VMS command buffer was assumed to be as large as 1024 bytes,
X which isn't the case everywhere as it is related to some weird
X quota. It has been lowered to 256.
X
X $(>) and $(<) wouldn't expand in action blocks if the targets
X were marked with NOTIME. Now they expand properly.
X
X Malloc() return values are now checked.
X
X The variable expansion routine var_expand() is now a little
X faster, by taking a few often needed shortcuts.
X
X The VMS version of file_build() used the wrong length when
X re-rooting file names that already had directory compoents.
X This was fixed.
X
X Various tracing adjustments were made.
X
X5. Limitations/Known Bugs
X
X The new Windows/NT support has only been marginally tested. It
X is dependent on certain variables being set depending on which
X compiler you are using. You'll need to look in the file
X Jambase and see what variables are expected to be set.
X
X The VMS support has been tested, courtesy of the DEC guest
X machine, but has not been hammered fully in release 2.0. It
X was used quite a bit in Jam 1.0.
X
X Jam clean when there is nothing to clean claims it is updating
X a target.
X
X Because the include statement works by pushing a new file in
X the input stream of the scanner rather than recursively
X invoking the parser on the new file, multiple include
X statements in a rule's procedure causes the files to be
X included in reverse order.
X
X If the include statement appears inside an if block, the
X parser's attempt to find the else will cause the text of the
X included file to appear after the first token following the
X statement block. This is rarely what is intended.
X
X In a rule's actions, only $(<) and $(>) refer to the bound file
X names: all other variable references get the unbound names.
X This is a pain for $(NEEDLIBS), because it means that library
X path can't be bound using $(SEARCH) and $(LOCATE).
X
X With the -j flag, errors from failed commands can get
X staggeringly mixed up. Also, because targets tend to get built
X in a quickest-first ordering, dependency information must be
X quite exact. Finally, beware of parallelizing commands that
X drop fixed-named files into the current directory, like yacc(1)
X does.
X
X A poorly set $(JAMSHELL) is likely to result in silent
X failure.
END_OF_FILE
if test 7759 -ne `wc -c <'RELNOTES'`; then
echo shar: \"'RELNOTES'\" unpacked with wrong size!
fi
# end of 'RELNOTES'
fi
if test -f 'compile.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'compile.c'\"
else
echo shar: Extracting \"'compile.c'\" \(15326 characters\)
sed "s/^X//" >'compile.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X
X# include "lists.h"
X# include "parse.h"

X# include "compile.h"


X# include "variable.h"
X# include "rules.h"

X# include "newstr.h"
X# include "make.h"

X# include "search.h"
X
X/*
X * compile.c - compile parsed jam statements


X *
X * External routines:
X *

X * compile_foreach() - compile the "for x in y" statement
X * compile_if() - compile 'if' rule
X * compile_include() - support for 'include' - call include() on file
X * compile_rule() - compile a single user defined rule
X * compile_rules() - compile a chain of rules
X * compile_set() - compile the "set variable" statement
X * compile_setcomp() - support for `compiles` - save parse tree
X * compile_setexec() - support for `executes` - save execution string
X * compile_settings() - compile the "on =" (set variable on exec) statement
X * compile_switch() - compile 'switch' rule
X *
X * Internal routines:
X *
X * evaluate_if() - evaluate if to determine which leg to compile
X *
X * builtin_depends() - DEPENDS/INCLUDES rule
X * builtin_echo() - ECHO rule
X * builtin_exit() - EXIT rule
X * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
X *
X * 02/03/94 (seiwald) - Changed trace output to read "setting" instead of
X * the awkward sounding "settings".
X * 04/12/94 (seiwald) - Combined build_depends() with build_includes().
X * 04/12/94 (seiwald) - actionlist() now just appends a single action.


X * 04/13/94 (seiwald) - added shorthand L0 for null list pointer

X * 05/13/94 (seiwald) - include files are now bound as targets, and thus
X * can make use of $(SEARCH)


X * 08/23/94 (seiwald) - Support for '+=' (append to variable)

X * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.

X * 01/22/95 (seiwald) - Exit rule.
X * 02/02/95 (seiwald) - Always rule; LEAVES rule.
X * 02/14/95 (seiwald) - NoUpdate rule.
X */
X
Xstatic int evaluate_if();
X
Xstatic void builtin_depends();
Xstatic void builtin_echo();
Xstatic void builtin_exit();
Xstatic void builtin_flags();
X
X
X
X/*
X * compile_builtin() - define builtin rules
X */
X


X# define P0 (PARSE *)0

X# define C0 (char *)0
X
Xvoid
Xcompile_builtins()
X{
X bindrule( "Always" )->procedure =
X bindrule( "ALWAYS" )->procedure =
X parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TOUCHED );
X
X bindrule( "Depends" )->procedure =
X bindrule( "DEPENDS" )->procedure =
X parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_DEPENDS );
X
X bindrule( "Echo" )->procedure =
X bindrule( "ECHO" )->procedure =
X parse_make( builtin_echo, P0, P0, C0, C0, L0, L0, 0 );
X
X bindrule( "Exit" )->procedure =
X bindrule( "EXIT" )->procedure =
X parse_make( builtin_exit, P0, P0, C0, C0, L0, L0, 0 );
X
X bindrule( "Includes" )->procedure =
X bindrule( "INCLUDES" )->procedure =
X parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_INCLUDES );
X
X bindrule( "Leaves" )->procedure =
X bindrule( "LEAVES" )->procedure =
X parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_LEAVES );
X
X bindrule( "NoCare" )->procedure =
X bindrule( "NOCARE" )->procedure =
X parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOCARE );
X
X bindrule( "NOTIME" )->procedure =
X bindrule( "NotFile" )->procedure =
X bindrule( "NOTFILE" )->procedure =
X parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOTFILE );
X
X bindrule( "NoUpdate" )->procedure =
X bindrule( "NOUPDATE" )->procedure =
X parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOUPDATE );
X
X bindrule( "Temporary" )->procedure =
X bindrule( "TEMPORARY" )->procedure =
X parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TEMP );
X}
X
X/*
X * compile_foreach() - compile the "for x in y" statement
X *
X * Compile_foreach() resets the given variable name to each specified
X * value, executing the commands enclosed in braces for each iteration.
X *
X * parse->string index variable
X * parse->left rule to compile
X * parse->llist variable values
X */
X
Xvoid
Xcompile_foreach( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *nv = var_list( parse->llist, targets, sources );
X LIST *l;
X
X /* Call var_set to reset $(parse->string) for each val. */
X
X for( l = nv; l; l = list_next( l ) )
X {
X LIST *val = list_new( L0, copystr( l->string ) );
X
X var_set( parse->string, val, VAR_SET );
X
X (*parse->left->func)( parse->left, targets, sources );
X }
X
X list_free( nv );
X}
X
X/*
X * compile_if() - compile 'if' rule
X *
X * parse->left condition tree
X * parse->right->left then tree
X * parse->right->right else tree
X */
X
Xvoid
Xcompile_if( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X PARSE *then = parse->right;
X
X if( evaluate_if( parse->left, targets, sources ) )
X (*then->left->func)( then->left, targets, sources );
X else if( then->right )
X (*then->right->func)( then->right, targets, sources );
X}
X
X/*
X * evaluate_if() - evaluate if to determine which leg to compile
X *
X * Returns:
X * !0 if expression true - compile 'then' clause
X * 0 if expression false - compile 'else' clause


X */
X
Xstatic int

Xevaluate_if( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X int status;
X
X if( parse->num <= COND_OR )
X {
X /* Handle one of the logical operators */
X
X switch( parse->num )
X {
X case COND_NOT:
X status = !evaluate_if( parse->left, targets, sources );
X break;
X
X case COND_AND:
X status = evaluate_if( parse->left, targets, sources ) &&
X evaluate_if( parse->right, targets, sources );
X break;
X
X case COND_OR:
X status = evaluate_if( parse->left, targets, sources ) ||
X evaluate_if( parse->right, targets, sources );
X break;
X }
X }
X else
X {
X /* Handle one of the comparison operators */
X
X LIST *nt;
X LIST *ns;
X char *st;
X char *ss;
X
X /* Expand targets and sources */
X
X st = ss = "";
X
X if( nt = var_list( parse->llist, targets, sources ) )
X st = nt->string;
X
X if( ns = var_list( parse->rlist, targets, sources ) )
X ss = ns->string;
X
X status = strcmp( st, ss );
X
X if( DEBUG_IF )
X printf( "if '%s' (%d) '%s'\n", st, status, ss );


X
X list_free( nt );

X list_free( ns );
X

X switch( parse->num )
X {
X case COND_EXISTS: status = status > 0 ; break;
X case COND_EQUALS: status = !status; break;
X case COND_NOTEQ: status = status != 0; break;
X case COND_LESS: status = status < 0; break;
X case COND_LESSEQ: status = status <= 0; break;
X case COND_MORE: status = status > 0; break;
X case COND_MOREEQ: status = status >= 0; break;
X }
X }
X
X return status;
X}
X
X/*
X * compile_include() - support for 'include' - call include() on file
X *
X * parse->llist list of files to include (can only do 1)
X */
X
Xvoid
Xcompile_include( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *nt = var_list( parse->llist, targets, sources );
X TARGET *t;
X
X if( DEBUG_COMPILE )
X {
X printf( "include " );
X list_print( nt );


X printf( "\n" );
X }
X

X if( nt )
X {
X TARGET *t = bindtarget( nt->string );
X
X /* Bind the include file under the influence of */
X /* "on-target" variables. Though they are targets, */
X /* include files are not built with make(). */


X
X pushsettings( t->settings );
X t->boundname = search( t->name, &t->time );

X popsettings( t->settings );
X

X yyfparse( t->boundname );
X }
X
X
X list_free( nt );
X}
X
X/*
X * compile_rule() - compile a single user defined rule
X *
X * parse->string name of user defined rule
X * parse->llist target of rule
X * parse->rlist sources of rule
X */
X
Xvoid
Xcompile_rule( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *nt = var_list( parse->llist, targets, sources );
X LIST *ns = var_list( parse->rlist, targets, sources );
X RULE *rule = bindrule( parse->string );
X
X if( DEBUG_COMPILE )
X {
X printf( ">>> %s ", parse->string );
X list_print( nt );
X printf( " : " );
X list_print( ns );


X printf( "\n" );
X }
X

X if( !nt )
X printf( "warning: no targets on rule %s %s\n",
X rule->name, parse->llist ? parse->llist->string : "" );
X
X if( !rule->actions && !rule->procedure )
X printf( "warning: unknown rule %s\n", rule->name );
X
X /* If this rule will be executed for updating the targets */
X /* then construct the action for make(). */
X
X if( rule->actions )
X {
X TARGETS *t;
X ACTION *action;
X
X /* The action is associated with this instance of this rule */
X
X action = (ACTION *)malloc( sizeof( ACTION ) );
X memset( (char *)action, '\0', sizeof( *action ) );
X
X action->rule = rule;
X action->targets = targetlist( (TARGETS *)0, nt );
X action->sources = targetlist( (TARGETS *)0, ns );
X
X /* Append this action to the actions of each target */
X
X for( t = action->targets; t; t = t->next )
X t->target->actions = actionlist( t->target->actions, action );
X }
X
X /* Now recursively compile any parse tree associated with this rule */
X
X if( rule->procedure )
X (*rule->procedure->func)( rule->procedure, nt, ns );
X


X list_free( nt );
X list_free( ns );
X

X if( DEBUG_COMPILE )
X printf( "<<< done\n" );
X}
X
X/*
X * compile_rules() - compile a chain of rules
X *
X * parse->left more compile_rules() by left-recursion
X * parse->right single rule
X */
X
Xvoid
Xcompile_rules( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X if( parse->left )
X (*parse->left->func)( parse->left, targets, sources );
X
X if( parse->right )
X (*parse->right->func)( parse->right, targets, sources );
X}
X
X/*
X * compile_set() - compile the "set variable" statement
X *
X * parse->llist variable names
X * parse->rlist variable values
X * parse->num ASSIGN_SET/APPEND/DEFAULT
X */
X
Xvoid
Xcompile_set( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *nt = var_list( parse->llist, targets, sources );
X LIST *ns = var_list( parse->rlist, targets, sources );
X LIST *l;
X int count = 0;
X int setflag;
X char *trace = "";
X
X switch( parse->num )
X {
X case ASSIGN_SET: setflag = VAR_SET; trace = "="; break;
X case ASSIGN_APPEND: setflag = VAR_APPEND; trace = "+="; break;
X case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break;
X }
X
X if( DEBUG_COMPILE )
X {
X printf( ">>> set " );
X list_print( nt );
X printf( " %s ", trace );
X list_print( ns );


X printf( "\n" );
X }
X

X /* Call var_set to set variable */
X /* var_set keeps ns, so need to copy it */
X
X for( l = nt; l; l = list_next( l ), count++ )
X var_set( l->string,
X count ? list_copy( (LIST*)0, ns ) : ns,
X setflag );
X
X if( !count )


X list_free( ns );
X

X list_free( nt );
X}
X
X/*
X * compile_setcomp() - support for `rule` - save parse tree
X *
X * parse->string rule name
X * parse->left rules for rule
X */
X
Xvoid
Xcompile_setcomp( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X RULE *rule = bindrule( parse->string );
X
X /* Free old one, if present */
X
X if( rule->procedure )
X parse_free( rule->procedure );
X
X rule->procedure = parse->left;
X
X /* we now own this parse tree */
X /* don't let parse_free() release it */
X
X parse->left = 0;
X}
X
X/*
X * compile_setexec() - support for `actions` - save execution string
X *
X * parse->string rule name
X * parse->string1 OS command string
X * parse->num flags
X *
X * Note that the parse flags (as defined in compile.h) are transfered
X * directly to the rule flags (as defined in rules.h).
X */
X
Xvoid
Xcompile_setexec( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X RULE *rule = bindrule( parse->string );
X
X /* Free old one, if present */
X
X if( rule->actions )
X freestr( rule->actions );
X
X rule->actions = copystr( parse->string1 );
X rule->flags |= parse->num; /* XXX */
X}
X
X/*
X * compile_settings() - compile the "on =" (set variable on exec) statement
X *
X * parse->llist target names
X * parse->left->llist variable names
X * parse->left->rlist variable values
X * parse->num ASSIGN_SET/APPEND
X */
X
Xvoid
Xcompile_settings( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *nt = var_list( parse->left->llist, targets, sources );
X LIST *ns = var_list( parse->left->rlist, targets, sources );
X LIST *ts;
X int append = parse->num == ASSIGN_APPEND;
X int count = 0;
X
X /* Reset targets */
X
X targets = var_list( parse->llist, targets, sources );
X
X if( DEBUG_COMPILE )
X {
X printf( ">>> setting " );
X list_print( nt );
X printf( "on " );
X list_print( targets );
X printf( " %s ", append ? "+=" : "=" );
X list_print( ns );


X printf( "\n" );
X }
X

X /* Call addsettings to save variable setting */
X /* addsettings keeps ns, so need to copy it */
X /* Pass append flag to addsettings() */
X
X for( ts = targets; ts; ts = list_next( ts ) )
X {
X TARGET *t = bindtarget( ts->string );
X LIST *l;
X
X for( l = nt; l; l = list_next( l ), count++ )
X t->settings = addsettings( t->settings, append, l->string,
X count ? list_copy( (LIST*)0, ns ) : ns );
X }
X
X if( !count )


X list_free( ns );
X
X list_free( nt );

X list_free( targets );
X}
X
X/*
X * compile_switch() - compile 'switch' rule
X *
X * parse->llist switch value (only 1st used)
X * parse->left cases
X *
X * cases->left 1st case
X * cases->right next cases
X *
X * case->string argument to match
X * case->left parse tree to execute
X */
X
Xvoid
Xcompile_switch( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *nt;
X
X nt = var_list( parse->llist, targets, sources );
X
X if( DEBUG_COMPILE )
X {
X printf( ">>> switch " );
X list_print( nt );


X printf( "\n" );
X }
X

X /* Step through cases */
X
X for( parse = parse->left; parse; parse = parse->right )
X {
X if( !glob( parse->left->string, nt ? nt->string : "" ) )
X {
X /* Get & exec parse tree for this case */
X parse = parse->left->left;
X (*parse->func)( parse, targets, sources );
X break;
X }
X }


X
X list_free( nt );
X}

X
X
X
X/*
X * builtin_depends() - DEPENDS/INCLUDES rule
X *
X * The DEPENDS builtin rule appends each of the listed sources on the
X * dependency list of each of the listed targets. It binds both the
X * targets and sources as TARGETs.


X */
X
Xstatic void

Xbuiltin_depends( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *l;
X int which = parse->num;
X
X for( l = targets; l; l = list_next( l ) )
X {
X TARGET *t = bindtarget( l->string );
X t->deps[ which ] = targetlist( t->deps[ which ], sources );
X }
X}
X
X/*
X * builtin_echo() - ECHO rule
X *
X * The ECHO builtin rule echoes the targets to the user. No other
X * actions are taken.


X */
X
Xstatic void

Xbuiltin_echo( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X list_print( targets );
X printf( "\n" );
X}
X
X/*
X * builtin_exit() - EXIT rule
X *
X * The EXIT builtin rule echoes the targets to the user and exits
X * the program with a failure status.


X */
X
Xstatic void

Xbuiltin_exit( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X list_print( targets );
X printf( "\n" );
X exit( EXITBAD ); /* yeech */
X}
X
X/*
X * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
X *
X * Builtin_flags() marks the target with the appropriate flag, for use
X * by make0(). It binds each target as a TARGET.


X */
X
Xstatic void

Xbuiltin_flags( parse, targets, sources )
XPARSE *parse;


XLIST *targets;
XLIST *sources;
X{

X LIST *l;
X
X for( l = targets; l; l = list_next( l ) )
X bindtarget( l->string )->flags |= parse->num;
X}
END_OF_FILE
if test 15326 -ne `wc -c <'compile.c'`; then
echo shar: \"'compile.c'\" unpacked with wrong size!
fi
# end of 'compile.c'
fi
if test -f 'expand.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'expand.c'\"
else
echo shar: Extracting \"'expand.c'\" \(8974 characters\)
sed "s/^X//" >'expand.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "lists.h"
X# include "variable.h"
X# include "expand.h"
X# include "filesys.h"
X# include "newstr.h"
X
X/*
X * expand.c - expand a buffer, given variable values


X *
X * External routines:
X *

X * var_expand() - variable-expand input string into list of strings
X *
X * Internal routines:
X *
X * var_edit() - copy input target name to output, performing : modifiers
X * var_mods() - parse : modifiers into FILENAME structure
X *
X * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)


X * 04/13/94 (seiwald) - added shorthand L0 for null list pointer

X */
X
Xstatic void var_edit();
Xstatic void var_mods();
X
X# define MAGIC_COLON '\001'
X
X/*
X * var_expand() - variable-expand input string into list of strings
X *
X * Would just copy input to output, performing variable expansion,
X * except that since variables can contain multiple values the result
X * of variable expansion may contain multiple values (a list). Properly
X * performs "product" operations that occur in "$(var1)xxx$(var2)" or
X * even "$($(var2))".
X *
X * Returns a newly created list.
X */
X
XLIST *
Xvar_expand( l, in, end, targets, sources, cancopyin )
XLIST *l;
Xchar *in;
Xchar *end;
XLIST *targets;
XLIST *sources;
Xint cancopyin;
X{
X char out_buf[ MAXSYM ];
X char *out = out_buf;
X char *inp = in;
X char *ov; /* for temp copy of variable in outbuf */
X int depth;
X
X if( DEBUG_VAREXP )
X printf( "expand '%.*s'\n", end - in, in );
X
X /* This gets alot of cases: $(<) and $(>) */
X
X if( in[0] == '$' && in[1] == '(' && in[3] == ')' && !in[4] )
X {
X if( in[2] == '<' )
X return list_copy( l, targets );
X
X if( in[2] == '>' )
X return list_copy( l, sources );
X }
X
X /* Just try simple copy of in to out. */
X
X while( in < end )
X if( ( *out++ = *in++ ) == '$' && *in == '(' )
X goto expand;
X
X /* No variables expanded - just add copy of input string to list. */
X
X /* Cancopyin is an optimization: if the input was already a list */
X /* item, we can use the copystr() to put it on the new list. */
X /* Otherwise, we use the slower newstr(). */
X
X *out = '\0';
X
X if( cancopyin )
X return list_new( l, copystr( inp ) );
X else
X return list_new( l, newstr( out_buf ) );
X
X expand:
X /*
X * Input so far (ignore blanks):
X *
X * stuff-in-outbuf $(variable) remainder
X * ^ ^
X * in end
X * Output so far:
X *
X * stuff-in-outbuf $
X * ^ ^
X * out_buf out
X *
X *
X * We just copied the $ of $(...), so back up one on the output.
X * We now find the matching close paren, copying the variable and
X * modifiers between the $( and ) temporarily into out_buf, so that
X * we can replace :'s with MAGIC_COLON. This is necessary to avoid
X * being confused by modifier values that are variables containing
X * :'s. Ugly.
X */
X
X depth = 1;
X out--, in++;
X ov = out;
X
X while( in < end && depth )
X {
X switch( *ov++ = *in++ )
X {
X case '(': depth++; break;
X case ')': depth--; break;
X case ':': ov[-1] = MAGIC_COLON;
X }
X }
X
X /* Copied ) - back up. */
X
X ov--;
X
X /*
X * Input so far (ignore blanks):
X *
X * stuff-in-outbuf $(variable) remainder
X * ^ ^
X * in end
X * Output so far:
X *
X * stuff-in-outbuf variable
X * ^ ^ ^
X * out_buf out ov
X *
X * Later we will overwrite 'variable' in out_buf, but we'll be
X * done with it by then. 'variable' may be a multi-element list,
X * so may each value for '$(variable element)', and so may 'remainder'.
X * Thus we produce a product of three lists.
X */
X
X {
X LIST *variables = 0;
X LIST *remainder = 0;
X LIST *vars;
X
X /* Recursively expand variable name & rest of input */
X
X if( out < ov )
X variables = var_expand( L0, out, ov, targets, sources, 0 );
X if( in < end )
X remainder = var_expand( L0, in, end, targets, sources, 0 );
X
X /* Now produce the result chain */
X
X /* For each variable name */
X
X for( vars = variables; vars; vars = list_next( vars ) )
X {
X LIST *value;
X char *colon;
X char *bracket;
X char varname[ MAXSYM ];
X int i, sub1, sub2;
X
X /* Look for a : modifier in the variable name */
X /* Must copy into varname so we can modify it */
X
X strcpy( varname, vars->string );
X
X if( colon = strchr( varname, MAGIC_COLON ) )
X *colon = '\0';
X
X if( bracket = strchr( varname, '[' ) )
X {
X char *dash;
X
X if( dash = strchr( bracket + 1, '-' ) )
X {
X *dash = '\0';
X sub1 = atoi( bracket + 1 );
X sub2 = atoi( dash + 1 );
X }
X else
X {
X sub1 = sub2 = atoi( bracket + 1 );
X }
X
X *bracket = '\0';
X }
X
X /* Get variable value, specially handling $(<) and $(>) */
X
X if( varname[0] == '<' && !varname[1] )
X value = targets;
X else if( varname[0] == '>' && !varname[1] )
X value = sources;
X else
X value = var_get( varname );
X
X /* The fast path: $(x) - just copy the variable value. */
X
X if( out == out_buf && !bracket && !colon && in == end )
X {
X l = list_copy( l, value );
X continue;
X }
X
X /* For each variable value */
X
X for( i = 1; value; i++, value = list_next( value ) )
X {
X LIST *rem;
X char *out1;
X
X /* Skip members not in subscript */
X
X if( bracket && ( i < sub1 || sub2 && i > sub2 ) )
X continue;
X
X /* Apply : mods, if present */
X
X if( colon )
X var_edit( value->string, colon + 1, out );
X else
X strcpy( out, value->string );
X
X /* If no remainder, append result to output chain. */
X
X if( in == end )
X {
X l = list_new( l, newstr( out_buf ) );
X continue;
X }
X
X /* Remember the end of the variable expansion so */
X /* we can just tack on each instance of 'remainder' */
X
X out1 = out + strlen( out );
X
X /* For each remainder, or just once if no remainder, */
X /* append the complete string to the output chain */
X
X for( rem = remainder; rem; rem = list_next( rem ) )
X {
X strcpy( out1, rem->string );
X l = list_new( l, newstr( out_buf ) );
X }
X }
X }
X
X /* variables & remainder were gifts from var_expand */
X /* and must be freed */
X
X if( variables )
X list_free( variables );
X if( remainder)
X list_free( remainder );
X
X if( DEBUG_VAREXP )
X {
X printf( "expanded to " );
X list_print( l );


X printf( "\n" );
X }
X

X return l;
X }
X}
X
X/*
X * var_edit() - copy input target name to output, performing : modifiers


X */
X
Xstatic void

Xvar_edit( in, mods, out )
Xchar *in;
Xchar *mods;
Xchar *out;
X{
X FILENAME old, new;
X
X /* Parse apart original filename, putting parts into "old" */
X
X file_parse( in, &old );
X
X /* Parse apart modifiers, putting them into "new" */
X
X var_mods( mods, &new );
X
X /* Replace any old with new */
X
X if( new.f_grist.ptr )
X old.f_grist = new.f_grist;
X
X if( new.f_root.ptr )
X old.f_root = new.f_root;
X
X if( new.f_dir.ptr )
X old.f_dir = new.f_dir;
X
X if( new.f_base.ptr )
X old.f_base = new.f_base;
X
X if( new.f_suffix.ptr )
X old.f_suffix = new.f_suffix;
X
X if( new.f_member.ptr )
X old.f_member = new.f_member;
X
X /* Put filename back together */
X
X file_build( &old, out );
X}
X
X
X/*
X * var_mods() - parse : modifiers into FILENAME structure
X *
X * The : modifiers in a $(varname:modifier) currently support replacing
X * or omitting elements of a filename, and so they are parsed into a
X * FILENAME structure (which contains pointers into the original string).
X *
X * Modifiers of the form "X=value" replace the component X with
X * the given value. Modifiers without the "=value" cause everything
X * but the component X to be omitted. X is one of:
X *
X * G <grist>
X * D directory name
X * B base name
X * S .suffix
X * M (member)
X * R root directory - prepended to whole path
X *
X * This routine sets:
X *
X * f->f_xxx.ptr = 0
X * f->f_xxx.len = 0
X * -> leave the original component xxx
X *
X * f->f_xxx.ptr = string
X * f->f_xxx.len = strlen( string )
X * -> replace component xxx with string
X *
X * f->f_xxx.ptr = ""
X * f->f_xxx.len = 0
X * -> omit component xxx
X *
X * var_edit() above and file_build() obligingly follow this convention.


X */
X
Xstatic void

Xvar_mods( mods, f )
Xchar *mods;
XFILENAME *f;
X{
X char *flags = "GRDBSM";
X int havezeroed = 0;


X memset( (char *)f, 0, sizeof( *f ) );
X

X while( *mods )
X {
X char *fl;
X struct filepart *fp;
X
X if( !( fl = strchr( flags, *mods++ ) ) )
X break; /* should complain, but so what... */
X
X fp = &f->part[ fl - flags ];
X
X if( *mods++ != '=' )
X {
X /* :X - turn everything but X off */
X
X int i;
X
X mods--;
X
X if( !havezeroed++ )
X for( i = 0; i < 6; i++ )
X {
X f->part[ i ].len = 0;
X f->part[ i ].ptr = "";
X }
X
X fp->ptr = 0;
X }
X else
X {
X /* :X=value - set X to value */
X
X char *p;
X
X if( p = strchr( mods, MAGIC_COLON ) )
X {
X fp->ptr = mods;
X fp->len = p - mods;
X mods = p + 1;
X }
X else
X {
X fp->ptr = mods;
X fp->len = strlen( mods );
X mods += fp->len;
X }
X }
X }
X}
END_OF_FILE
if test 8974 -ne `wc -c <'expand.c'`; then
echo shar: \"'expand.c'\" unpacked with wrong size!
fi
# end of 'expand.c'
fi
if test -f 'fileunix.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'fileunix.c'\"
else
echo shar: Extracting \"'fileunix.c'\" \(8400 characters\)
sed "s/^X//" >'fileunix.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "filesys.h"
X

X# ifdef unix
X
X# if defined(_SEQUENT_) || defined(__DGUX__)
X# define PORTAR 1
X# endif
X
X# include <dirent.h>
X
X# if defined (COHERENT) && defined (_I386)
X# include <arcoff.h>
X# else
X# include <ar.h>
X# endif /* COHERENT */
X
X
X/*


X * fileunix.c - manipulate file names and scan directories on UNIX
X *
X * External routines:
X *
X * file_parse() - split a file name into dir/base/suffix/member
X * file_build() - build a filename given dir/base/suffix/member
X * file_dirscan() - scan a directory for files
X * file_time() - get timestamp of file, if not done by file_dirscan()
X * file_archscan() - scan an archive for files
X *
X * File_parse() and file_build() just manipuate a string and a structure;
X * they do not make system calls.
X *
X * File_dirscan() and file_archscan() call back a caller provided function
X * for each file found. A flag to this callback function lets file_dirscan()
X * and file_archscan() indicate that a timestamp is being provided with the
X * file. If file_dirscan() or file_archscan() do not provide the file's
X * timestamp, interested parties may later call file_time().
X *

X * 12/26/93 (seiwald) - handle dir/.suffix properly in file_build()
X * 04/08/94 (seiwald) - Coherent/386 support added.
X * 12/19/94 (mikem) - solaris string table insanity support


X * 02/14/95 (seiwald) - parse and build /xxx properly
X */
X
X/*
X * file_parse() - split a file name into dir/base/suffix/member
X */
X
Xvoid
Xfile_parse( file, f )
Xchar *file;
XFILENAME *f;
X{

X char *p;

X char *end;
X
X memset( (char *)f, 0, sizeof( *f ) );
X
X /* Look for <grist> */
X
X if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
X {
X f->f_grist.ptr = file + 1;
X f->f_grist.len = p - file - 1;
X file = p + 1;
X }
X
X /* Look for dir/ */

X /* Special case for / - dirname is /, not "" */
X
X if( p = strrchr( file, '/' ) )

X && !( f->f_dir.len && f->f_dir.ptr[0] == '/' ) )


X {
X memcpy( file, f->f_root.ptr, f->f_root.len );
X file += f->f_root.len;

X *file++ = '/';


X }
X
X if( f->f_dir.len )
X {
X memcpy( file, f->f_dir.ptr, f->f_dir.len );
X file += f->f_dir.len;
X }
X

X /* Put / between dir and file */


X
X if( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
X {

X /* Special case for dir / : don't add another / */
X
X if( !( f->f_dir.len == 1 && f->f_dir.ptr[0] == '/' ) )
X *file++ = '/';

X DIR *d;
X struct dirent *dirent;
X char filename[ MAXPATH ];
X struct stat statbuf;


X
X /* First enter directory itself */
X
X memset( (char *)&f, '\0', sizeof( f ) );
X
X f.f_dir.ptr = dir;
X f.f_dir.len = strlen(dir);
X
X dir = *dir ? dir : ".";
X

X /* Special case / : enter it */
X
X if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' )


X (*func)( dir, 0 /* not stat()'ed */, (time_t)0 );
X
X /* Now enter contents of directory */
X

X if( !( d = opendir( dir ) ) )


X return;
X
X if( DEBUG_BINDSCAN )
X printf( "scan directory %s\n", dir );
X

X while( dirent = readdir( d ) )
X {
X f.f_base.ptr = dirent->d_name;
X f.f_base.len = strlen( dirent->d_name );


X
X file_build( &f, filename );
X

X (*func)( filename, 0 /* not stat()'ed */, (time_t)0 );
X }
X
X closedir( d );


X}
X
X/*
X * file_time() - get timestamp of file, if not done by file_dirscan()
X */
X
Xint
Xfile_time( filename, time )
Xchar *filename;
Xtime_t *time;
X{

X struct stat statbuf;
X
X if( stat( filename, &statbuf ) < 0 )
X return -1;
X
X *time = statbuf.st_mtime;


X return 0;
X}
X
X/*
X * file_archscan() - scan an archive for files
X */
X

X# ifndef AIAMAG /* God-fearing UNIX */


X
X# define SARFMAG 2
X# define SARHDR sizeof( struct ar_hdr )
X
Xvoid
Xfile_archscan( archive, func )
Xchar *archive;
Xvoid (*func)();
X{
X struct ar_hdr ar_hdr;
X char buf[ MAXPATH ];
X long offset;

X char *string_table = 0;


X int fd;
X
X if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
X return;
X
X if( read( fd, buf, SARMAG ) != SARMAG ||
X strncmp( ARMAG, buf, SARMAG ) )
X {
X close( fd );
X return;
X }
X
X offset = SARMAG;
X
X if( DEBUG_BINDSCAN )
X printf( "scan archive %s\n", archive );
X
X while( read( fd, &ar_hdr, SARHDR ) == SARHDR &&
X !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
X {

X char lar_name[256];


X long lar_date;
X long lar_size;

X long lar_offset;
X char *c;
X char *src, *dest;


X
X strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
X

X sscanf( ar_hdr.ar_date, "%ld", &lar_date );
X sscanf( ar_hdr.ar_size, "%ld", &lar_size );
X

X if (ar_hdr.ar_name[0] == '/')
X {
X if (ar_hdr.ar_name[1] == '/')
X {
X /* this is the "string table" entry of the symbol table,
X ** which holds strings of filenames that are longer than
X ** 15 characters (ie. don't fit into a ar_name
X */
X
X string_table = malloc(lar_size);
X lseek(fd, offset + SARHDR, 0);
X if (read(fd, string_table, lar_size) != lar_size)
X printf("error reading string table\n");
X }
X else if (ar_hdr.ar_name[1] != ' ')
X {
X /* Long filenames are recognized by "/nnnn" where nnnn is
X ** the offset of the string in the string table represented
X ** in ASCII decimals.
X */
X dest = lar_name;
X lar_offset = atoi(lar_name + 1);
X src = &string_table[lar_offset];
X while (*src != '/')
X *dest++ = *src++;
X *dest = '/';
X }
X }
X
X c = lar_name - 1;
X while( *++c != ' ' && *c != '/' )
X ;
X *c = '\0';
X
X if ( DEBUG_BINDSCAN )
X printf( "archive name %s found\n", lar_name );


X
X sprintf( buf, "%s(%s)", archive, lar_name );
X
X (*func)( buf, 1 /* time valid */, (time_t)lar_date );
X
X offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
X lseek( fd, offset, 0 );
X }
X

X if (string_table)
X free(string_table);


X
X close( fd );
X}
X

X# else /* AIAMAG - RS6000 AIX */


X
Xvoid
Xfile_archscan( archive, func )
Xchar *archive;
Xvoid (*func)();
X{

X struct fl_hdr fl_hdr;
X
X struct {
X struct ar_hdr hdr;
X char pad[ 256 ];
X } ar_hdr ;
X


X char buf[ MAXPATH ];
X long offset;
X int fd;
X
X if( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
X return;
X

X if( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ ||
X strncmp( AIAMAG, fl_hdr.fl_magic, SAIAMAG ) )


X {
X close( fd );
X return;
X }
X

X sscanf( fl_hdr.fl_fstmoff, "%ld", &offset );


X
X if( DEBUG_BINDSCAN )
X printf( "scan archive %s\n", archive );
X

X while( offset > 0 &&
X lseek( fd, offset, 0 ) >= 0 &&
X read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) )
X {
X long lar_date;
X int lar_namlen;
X
X sscanf( ar_hdr.hdr.ar_namlen, "%d", &lar_namlen );
X sscanf( ar_hdr.hdr.ar_date, "%ld", &lar_date );
X sscanf( ar_hdr.hdr.ar_nxtmem, "%ld", &offset );
X
X if( !lar_namlen )
X continue;
X
X ar_hdr.hdr._ar_name.ar_name[ lar_namlen ] = '\0';
X
X sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );


X
X (*func)( buf, 1 /* time valid */, (time_t)lar_date );
X }
X

X close( fd );
X}
X

X# endif /* AIAMAG - RS6000 AIX */
X
X# endif /* unix */
X
END_OF_FILE
if test 8400 -ne `wc -c <'fileunix.c'`; then
echo shar: \"'fileunix.c'\" unpacked with wrong size!
fi
# end of 'fileunix.c'
fi
if test -f 'filevms.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'filevms.c'\"
else
echo shar: Extracting \"'filevms.c'\" \(9560 characters\)
sed "s/^X//" >'filevms.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# ifdef VMS
X
X/*
X * filevms.c - manipulate file names and scan directories on VMS


X *
X * External routines:
X *
X * file_parse() - split a file name into dir/base/suffix/member
X * file_build() - build a filename given dir/base/suffix/member
X * file_dirscan() - scan a directory for files
X * file_time() - get timestamp of file, if not done by file_dirscan()
X * file_archscan() - scan an archive for files
X *
X * File_parse() and file_build() just manipuate a string and a structure;
X * they do not make system calls.
X *
X * File_dirscan() and file_archscan() call back a caller provided function
X * for each file found. A flag to this callback function lets file_dirscan()
X * and file_archscan() indicate that a timestamp is being provided with the
X * file. If file_dirscan() or file_archscan() do not provide the file's
X * timestamp, interested parties may later call file_time().
X *

X * WARNING! This file contains voodoo logic, as black magic is
X * necessary for wrangling with VMS file name. Woe be to people
X * who mess with this code.
X *
X * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
X */
X
X# include <rms.h>
X# include <iodef.h>
X# include <ssdef.h>
X# include <string.h>
X# include <stdlib.h>
X# include <ctype.h>
X# include <stdio.h>
X# include <descrip.h>
X
X#include <lbrdef.h>
X#include <credef.h>
X#include <mhddef.h>
X#include <lhidef.h>


X
X# include "jam.h"
X# include "filesys.h"
X

X/*
X * unlink() - remove a file
X */
X
Xunlink( f )
Xchar *f;
X{
X remove( f );
X}
X
X/*


X * file_parse() - split a file name into dir/base/suffix/member
X */
X
Xvoid
Xfile_parse( file, f )
Xchar *file;
XFILENAME *f;
X{

X char *p;

X char *end;
X
X memset( (char *)f, 0, sizeof( *f ) );
X
X /* Look for <grist> */
X
X if( file[0] == '<' && ( p = strchr( file, '>' ) ) )
X {
X f->f_grist.ptr = file + 1;
X f->f_grist.len = p - file - 1;
X file = p + 1;
X }
X

X /* Look for dev:[dir] or dev: */
X
X if( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) )
X {


X f->f_dir.ptr = file;

X f->f_dir.len = p + 1 - file;

X * file_flags() - find out what's in a directory name
X *
X * VMS directories get complicated. Valid combinations of root
X * and dir are:
X *
X * root dir result
X * ---- --- ------
X *
X * [dir] [dir]
X * dev dev:
X * dev [dir] dev:[dir]
X * dev: dev:
X * dev: [dir] dev:[dir]
X * [dir] [dir]
X * [dir] [dir] [dir.dir]
X * dev:[dir] dev:[dir]
X * dev:[dir] [dir] dev:[dir.dir]
X *
X * * dev dev
X * * dev: dev:
X * * dev:[dir] dev:[dir]
X *
X */
X
X# define HAS_NOTHING 0
X# define HAS_DEV 0x01
X# define HAS_DIR 0x02
X# define HAS_COLON 0x04
X
Xstatic int
Xfile_flags( buf, len )
Xchar *buf;
Xint len;
X{
X int flags = 0;
X
X if( len && *buf != '[' )
X flags |= HAS_DEV;
X
X while( len-- )
X switch( *buf++ )
X {
X case ':': flags |= HAS_COLON; break;
X case '[': flags |= HAS_DIR; break;
X }
X
X return flags;


X}
X
X/*
X * file_build() - build a filename given dir/base/suffix/member
X */
X
Xvoid
Xfile_build( f, file )
XFILENAME *f;
Xchar *file;
X{
X

X int dir_flags = HAS_DEV;
X int root_flags = 0;


X
X if( f->f_grist.len )
X {
X *file++ = '<';
X memcpy( file, f->f_grist.ptr, f->f_grist.len );
X file += f->f_grist.len;
X *file++ = '>';
X }
X

X if( f->f_root.len )
X {
X root_flags = file_flags( f->f_root.ptr, f->f_root.len );
X dir_flags = file_flags( f->f_dir.ptr, f->f_dir.len );
X }
X
X switch( dir_flags & 0x03 )
X {
X case HAS_DIR:
X case HAS_NOTHING:
X switch( root_flags & 0x03 )
X {
X case HAS_NOTHING:
X break;
X
X case HAS_DEV:


X memcpy( file, f->f_root.ptr, f->f_root.len );
X file += f->f_root.len;

X if( !( root_flags & HAS_COLON ) )
X *file++ = ':';
X break;
X
X case HAS_DIR:
X case HAS_DEV|HAS_DIR:


X memcpy( file, f->f_root.ptr, f->f_root.len );
X file += f->f_root.len;

X break;
X }
X
X if( dir_flags & HAS_DIR )
X {
X if( root_flags & HAS_DIR )
X {
X file[-1] = '.';
X memcpy( file, f->f_dir.ptr + 1, f->f_dir.len - 1 );
X file += f->f_dir.len - 1;
X }
X else


X {
X memcpy( file, f->f_dir.ptr, f->f_dir.len );
X file += f->f_dir.len;
X }
X }
X

X break;
X
X case HAS_DEV:
X case HAS_DEV|HAS_DIR:


X memcpy( file, f->f_dir.ptr, f->f_dir.len );
X file += f->f_dir.len;

X break;


X }
X
X if( f->f_base.len )
X {
X memcpy( file, f->f_base.ptr, f->f_base.len );
X file += f->f_base.len;
X }
X
X if( f->f_suffix.len )
X {
X memcpy( file, f->f_suffix.ptr, f->f_suffix.len );
X file += f->f_suffix.len;
X }
X
X if( f->f_member.len )
X {
X *file++ = '(';
X memcpy( file, f->f_member.ptr, f->f_member.len );
X file += f->f_member.len;
X *file++ = ')';
X }
X *file = 0;
X}
X

Xstatic void
Xfile_cvttime( curtime, unixtime )
Xunsigned int *curtime;
Xtime_t *unixtime;
X{
X static const size_t divisor = 10000000;
X static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
X int delta[2], remainder;
X
X LIB$SUBX( curtime, bastim, delta );
X LIB$EDIV( &divisor, delta, unixtime, &remainder );
X}
X
X# define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
X
X# define min( a,b ) ((a)<(b)?(a):(b))
X
Xvoid
Xfile_dirscan( char *dir, void (*func)() )
X{
X size_t SYS$PARSE( );
X size_t SYS$SEARCH( );
X size_t LIB$SIGNAL( );
X
X struct FAB xfab;
X struct NAM xnam;
X struct XABDAT xab;
X char esa[256];
X char filename[256];
X char filename2[256];
X register status;
X FILENAME f;


X
X memset( (char *)&f, '\0', sizeof( f ) );
X
X f.f_dir.ptr = dir;
X f.f_dir.len = strlen( dir );
X

X /* get the input file specification
X */
X xnam = cc$rms_nam;
X xnam.nam$l_esa = esa;
X xnam.nam$b_ess = sizeof( esa ) - 1;
X xnam.nam$l_rsa = filename;
X xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS );
X
X xab = cc$rms_xabdat; /* initialize extended attributes */
X xab.xab$b_cod = XAB$C_DAT; /* ask for date */
X xab.xab$l_nxt = NULL; /* terminate XAB chain */
X
X xfab = cc$rms_fab;
X xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION;
X xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1;
X xfab.fab$l_fop = FAB$M_NAM;
X xfab.fab$l_fna = dir; /* address of file name */
X xfab.fab$b_fns = strlen( dir ); /* length of file name */
X xfab.fab$l_nam = &xnam; /* address of NAB block */
X xfab.fab$l_xab = (char *)&xab; /* address of XAB block */
X
X
X status = SYS$PARSE( &xfab );


X
X if( DEBUG_BINDSCAN )
X printf( "scan directory %s\n", dir );
X

X if ( !( status & 1 ) )
X return;
X
X while ( (status = SYS$SEARCH( &xfab )) & 1 )
X {
X char *s;
X time_t time;
X
X /* "I think that might work" - eml */
X
X sys$open( &xfab );
X sys$close( &xfab );
X
X filename[xnam.nam$b_rsl] = '\0';
X for( s = xnam.nam$l_name; *s; s++ )
X if( isupper( *s ) )
X *s = tolower( *s );
X
X f.f_base.ptr = xnam.nam$l_name;
X f.f_base.len = xnam.nam$b_name;
X f.f_suffix.ptr = xnam.nam$l_type;
X f.f_suffix.len = xnam.nam$b_type;
X
X file_build( &f, filename2 );
X
X file_cvttime( &xab.xab$q_rdt, &time );
X
X (*func)( filename2, 1 /* time valid */, time );
X }
X
X if ( status != RMS$_NMF && status != RMS$_FNF )
X LIB$SIGNAL( xfab.fab$l_sts, xfab.fab$l_stv );
X}

X
Xint
Xfile_time( filename, time )
Xchar *filename;
Xtime_t *time;
X{

X /* This should never be called, as all files are */
X /* timestampped in file_dirscan() and file_archscan() */
X return -1;
X}
X
Xstatic char *VMS_archive = 0;
Xstatic void (*VMS_func)() = 0;
Xstatic void *context;
X
Xstatic int
Xfile_archmember( module, rfa )
Xstruct dsc$descriptor_s *module;
Xunsigned long *rfa;
X{
X static struct dsc$descriptor_s bufdsc =
X {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
X
X struct mhddef *mhd;
X char filename[128];


X char buf[ MAXPATH ];
X

X int library_date, status;


X
X register int i;

X register char *p;
X
X bufdsc.dsc$a_pointer = filename;
X bufdsc.dsc$w_length = sizeof( filename );
X status = LBR$SET_MODULE( &context, rfa, &bufdsc,
X &bufdsc.dsc$w_length, NULL );
X if ( !(status & 1) )
X return ( 1 );
X
X mhd = (struct mhddef *)filename;
X
X file_cvttime( &mhd->mhd$l_datim, &library_date );
X
X for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; i++, p++ )
X filename[i] = _tolower( *p );
X
X filename[i] = '\0';
X
X sprintf( buf, "%s(%s.obj)", VMS_archive, filename );
X
X (*VMS_func)( buf, 1 /* time valid */, (time_t)library_date );
X
X return ( 1 );
X}


X
Xvoid
Xfile_archscan( archive, func )
Xchar *archive;
Xvoid (*func)();
X{

X static struct dsc$descriptor_s library =
X {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
X
X unsigned long lfunc = LBR$C_READ;
X unsigned long typ = LBR$C_TYP_UNK;
X unsigned long index = 1;
X
X register status;
X
X VMS_archive = archive;
X VMS_func = func;
X
X status = LBR$INI_CONTROL( &context, &lfunc, &typ, NULL );
X if ( !( status & 1 ) )
X return;
X
X library.dsc$a_pointer = archive;
X library.dsc$w_length = strlen( archive );
X
X status = LBR$OPEN( &context, &library, NULL, NULL, NULL, NULL, NULL );
X if ( !( status & 1 ) )
X return;
X
X (void) LBR$GET_INDEX( &context, &index, file_archmember, NULL );
X
X (void) LBR$CLOSE( &context );
X}
X
X# endif /* VMS */
X
END_OF_FILE
if test 9560 -ne `wc -c <'filevms.c'`; then
echo shar: \"'filevms.c'\" unpacked with wrong size!
fi
# end of 'filevms.c'
fi
if test -f 'hash.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'hash.c'\"
else
echo shar: Extracting \"'hash.c'\" \(5147 characters\)
sed "s/^X//" >'hash.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "hash.h"
X
X/*
X * hash.c - simple in-memory hashing routines

X *
X * External routines:
X *

X * hashinit() - initialize a hash table, returning a handle
X * hashitem() - find a record in the table, and optionally enter a new one
X * hashdone() - free a hash table, given its handle
X *
X * Internal routines:
X *
X * hashrehash() - resize and rebuild hp->tab, the hash table
X *
X * 4/29/93 - ensure ITEM's are aligned
X */
X
Xchar *hashsccssid="@(#)hash.c 1.14 () 6/20/88";
X
X/* Header attached to all data items entered into a hash table. */
X
Xstruct hashhdr {
X struct item *next;
X int keyval; /* for quick comparisons */
X} ;
X
X/* This structure overlays the one handed to hashenter(). */
X/* It's actual size is given to hashinit(). */
X
Xstruct hashdata {
X char *key;
X /* rest of user data */
X} ;
X
Xtypedef struct item {
X struct hashhdr hdr;
X struct hashdata data;
X} ITEM ;
X
X# define MAX_LISTS 32
X
Xstruct hash
X{
X /*
X * the hash table, just an array of item pointers
X */
X struct {
X int nel;
X ITEM **base;
X } tab;
X
X int bloat; /* tab.nel / items.nel */
X int inel; /* initial number of elements */
X
X /*
X * the array of records, maintained by these routines
X * essentially a microallocator
X */
X struct {
X int more; /* how many more ITEMs fit in lists[ list ] */
X char *next; /* where to put more ITEMs in lists[ list ] */
X int datalen; /* length of records in this hash table */
X int size; /* sizeof( ITEM ) + aligned datalen */
X int nel; /* total ITEMs held by all lists[] */
X int list; /* index into lists[] */
X
X struct {
X int nel; /* total ITEMs held by this list */
X char *base; /* base of ITEMs array */
X } lists[ MAX_LISTS ];
X } items;
X
X char *name; /* just for hashstats() */
X} ;
X
Xstatic hashrehash();
X
X/*
X * hashitem() - find a record in the table, and optionally enter a new one
X */
X
Xint
Xhashitem( hp, data, enter )
Xregister struct hash *hp;
XHASHDATA **data;
X{
X ITEM **base;
X register ITEM *i;
X char *b = (*data)->key;
X int keyval = 0;
X
X if( enter && !hp->items.more )
X hashrehash( hp );
X
X if( !enter && !hp->items.nel )
X return 0;
X
X while( *b )
X keyval = ( ( keyval << 7 ) + ( keyval >> 25 ) ) + *b++;
X keyval &= 0x7FFFFFFF;
X
X base = hp->tab.base + ( keyval % hp->tab.nel );
X
X for( i = *base; i; i = i->hdr.next )
X if( keyval == i->hdr.keyval &&
X !strcmp( i->data.key, (*data)->key ) )
X {
X *data = &i->data;
X return !0;
X }
X
X if( enter )
X {
X i = (ITEM *)hp->items.next;
X hp->items.next += hp->items.size;
X hp->items.more--;
X memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
X i->hdr.keyval = keyval;
X i->hdr.next = *base;
X *base = i;
X *data = &i->data;
X }


X
X return 0;
X}
X
X/*

X * hashrehash() - resize and rebuild hp->tab, the hash table
X */
X
Xstatic hashrehash( hp )
Xregister struct hash *hp;
X{
X int i = ++hp->items.list;
X
X hp->items.more = i ? 2 * hp->items.nel : hp->inel;
X hp->items.next = (char *)malloc( hp->items.more * hp->items.size );
X
X hp->items.lists[i].nel = hp->items.more;
X hp->items.lists[i].base = hp->items.next;
X hp->items.nel += hp->items.more;
X
X if( hp->tab.base )
X free( (char *)hp->tab.base );
X
X hp->tab.nel = hp->items.nel * hp->bloat;
X hp->tab.base = (ITEM **)malloc( hp->tab.nel * sizeof(ITEM **) );
X
X memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
X
X for( i = 0; i < hp->items.list; i++ )
X {
X int nel = hp->items.lists[i].nel;
X char *next = hp->items.lists[i].base;
X
X for( ; nel--; next += hp->items.size )
X {
X register ITEM *i = (ITEM *)next;
X ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
X
X i->hdr.next = *ip;
X *ip = i;
X }
X }
X}
X
X/* --- */
X
X# define ALIGNED(x) ( ( x + sizeof( ITEM ) - 1 ) & ~( sizeof( ITEM ) - 1 ) )
X
X/*
X * hashinit() - initialize a hash table, returning a handle
X */
X
Xstruct hash *
Xhashinit( datalen, name )
Xchar *name;
X{
X struct hash *hp = (struct hash *)malloc( sizeof( *hp ) );
X
X hp->bloat = 3;
X hp->tab.nel = 0;
X hp->tab.base = (ITEM **)0;
X hp->items.more = 0;
X hp->items.datalen = datalen;
X hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
X hp->items.list = -1;
X hp->items.nel = 0;
X hp->inel = 11;
X hp->name = name;
X
X return hp;
X}
X
X/*
X * hashdone() - free a hash table, given its handle
X */
X
Xvoid
Xhashdone( hp )
Xstruct hash *hp;
X{
X int i;
X
X if( !hp )
X return;
X
X if( DEBUG_MEM )
X hashstat( hp );
X
X if( hp->tab.base )
X free( (char *)hp->tab.base );
X for( i = 0; i <= hp->items.list; i++ )
X free( hp->items.lists[i].base );
X free( (char *)hp );
X}
X
X/* ---- */
X
Xhashstat( hp )
Xstruct hash *hp;
X{
X ITEM **tab = hp->tab.base;
X int nel = hp->tab.nel;
X int count = 0;
X int sets = 0;
X int run = ( tab[ nel - 1 ] != (ITEM *)0 );
X int i, here;
X
X for( i = nel; i > 0; i-- )
X {
X if( here = ( *tab++ != (ITEM *)0 ) )
X count++;
X if( here && !run )
X sets++;
X run = here;
X }
X
X printf( "%s table: %d+%d+%d (%dK+%dK) items+table+hash, %f density\n",
X hp->name,
X count,
X hp->items.nel,
X hp->tab.nel,
X hp->items.nel * hp->items.size / 1024,
X hp->tab.nel * sizeof( ITEM ** ) / 1024,
X (float)count / (float)sets );
X}
END_OF_FILE
if test 5147 -ne `wc -c <'hash.c'`; then
echo shar: \"'hash.c'\" unpacked with wrong size!
fi
# end of 'hash.c'
fi
if test -f 'jam.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jam.c'\"
else
echo shar: Extracting \"'jam.c'\" \(5313 characters\)
sed "s/^X//" >'jam.c' <<'END_OF_FILE'
X/*
X * /+\
X * +\ Copyright 1993, 1995 Christopher Seiwald.
X * \+/
X *
X * This file is part of jam.
X *
X * License is hereby granted to use this software and distribute it
X * freely, as long as this copyright notice is retained and modifications
X * are clearly marked.
X *
X * ALL WARRANTIES ARE HEREBY DISCLAIMED.
X */
X
X# include "jam.h"
X# include "option.h"
X# include "make.h"
X# include "patchlevel.h"
X
X/*
X * jam.c - make redux
X *
X * See jam(1) and Jamfile(5) for usage information.
X *
X * These comments document the code.
X *
X * The top half of the code is structured such:
X *
X * jam
X * / | \
X * +---+ | \
X * / | \
X * jamgram option \
X * / | \ \
X * / | \ \
X * / | \ |
X * scan | compile make
X * | / \ / | \
X * | / \ / | \
X * | / \ / | \
X * parse rules search make1
X * | | \
X * | | \
X * | | \
X * timestamp command execute
X *
X *
X * The support routines are called by all of the above, but themselves
X * are layered thus:
X *
X * variable|expand
X * / | | |
X * / | | |
X * / | | |
X * lists | | filesys
X * \ | |
X * \ | |
X * \ | |
X * newstr |
X * \ |
X * \ |
X * \ |
X * hash
X *
X * Roughly, the modules are:
X *
X * command.c - maintain lists of commands
X * compile.c - compile parsed jam statements
X * execunix.c - execute a shell script on UNIX
X * execvms.c - execute a shell script, ala VMS
X * expand.c - expand a buffer, given variable values


X * fileunix.c - manipulate file names and scan directories on UNIX

X * filevms.c - manipulate file names and scan directories on VMS
X * hash.c - simple in-memory hashing routines
X * headers.c - handle #includes in source files
X * lists.c - maintain lists of strings
X * make.c - bring a target up to date, once rules are in place


X * make1.c - execute command to bring targets up to date

X * newstr.c - string manipulation routines
X * option.c - command line option processing
X * parse.c - make and destroy parse trees as driven by the parser
X * regexp.c - Henry Spencer's regexp
X * rules.c - access to RULEs, TARGETs, and ACTIONs
X * scan.c - the jam yacc scanner
X * search.c - find a target along $(SEARCH) or $(LOCATE)
X * timestamp.c - get the timestamp of a file or archive member
X * variable.c - handle jam multi-element variables


X * jamgram.yy - jam grammar
X *

X * 05/04/94 (seiwald) - async multiprocess (-j) support

X * 02/08/95 (seiwald) - -n implies -d2.
X * 02/22/95 (seiwald) - -v for version info.
X */
X
Xstruct globs globs = {
X 1, /* debug */
X 0, /* noexec */
X 1 /* jobs */
X} ;
X
X/* Symbols to be defined as true for use in Jambase */
X
Xstatic char *othersyms[] = { OTHERSYMS, 0 } ;
Xextern char **environ;
X
Xchar *usage =
X "jam [-anv -j<jobs> -f<Jambase> -d<debuglevel> -t<target>...] target...";
X
Xmain( argc, argv )
Xchar **argv;
X{
X int n;
X char *s;
X struct option optv[N_OPTS];
X char *all = "all";
X int anyhow = 0;
X
X argc--, argv++;
X
X if( ( n = getoptions( argc, argv, "d:j:f:t:anv", optv ) ) < 0 )
X {
X printf( "\nusage: %s\n\n", usage );
X
X printf( "-a Build all targets, even if they are current.\n" );
X printf( "-dx Set the debug level to x (0-9).\n" );
X printf( "-fx Read x instead of Jambase.\n" );
X printf( "-jx Run up to x shell commands concurrently.\n" );
X printf( "-n Don't actually execute the updating actions.\n" );
X printf( "-tx Rebuild x, even if it is up-to-date.\n" );
X printf( "-v Print the version of jam and exit.\n\n" );
X
X exit( EXITBAD );
X }
X
X argc -= n, argv += n;
X
X /* Version info. */
X
X if( ( s = getoptval( optv, 'v', 0 ) ) )
X {
X printf( "Jam - make(1) redux. " );
X printf( "Version %s.%s. ", VERSION, PATCHLEVEL );
X printf( "Copyright 1993, 1995 Christopher Seiwald.\n" );
X
X return EXITOK;
X }
X
X /* Pick up interesting options */
X
X if( ( s = getoptval( optv, 'n', 0 ) ) )
X globs.noexec++, globs.debug = 2;
X
X if( ( s = getoptval( optv, 'd', 0 ) ) )
X globs.debug = atoi( s );
X
X if( ( s = getoptval( optv, 'a', 0 ) ) )
X anyhow++;
X
X if( ( s = getoptval( optv, 'j', 0 ) ) )
X globs.jobs = atoi( s );
X
X /* load up environment variables */
X
X var_defines( othersyms );
X var_defines( environ );
X
X /* Parse ruleset */
X
X for( n = 0; s = getoptval( optv, 'f', n ); n++ )
X {
X yyfparse( s );
X yyparse();
X }
X
X if( !n )
X {
X yyfparse( JAMBASE );
X yyparse();
X }
X
X /* Manually touch -t targets */
X
X for( n = 0; s = getoptval( optv, 't', n ); n++ )
X touchtarget( s );
X
X /* Now make target */
X
X if( argc )
X make( argc, argv, anyhow );
X else
X make( 1, &all, anyhow );
X
X /* Widely scattered cleanup */
X
X var_done();
X donerules();
X donestamps();
X donestr();
X
X return EXITOK;
X}
END_OF_FILE
if test 5313 -ne `wc -c <'jam.c'`; then
echo shar: \"'jam.c'\" unpacked with wrong size!
fi
# end of 'jam.c'
fi
if test -f 'lists.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'lists.c'\"
else
echo shar: Extracting \"'lists.c'\" \(3284 characters\)
sed "s/^X//" >'lists.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "newstr.h"
X# include "lists.h"
X
X/*
X * lists.c - maintain lists of strings
X *
X * The whole of jam relies on lists of strings as a datatype. This
X * module, in conjunction with newstr.c, handles these relatively
X * efficiently.


X *
X * External routines:
X *

X * list_append() - append a list onto another one, returning total
X * list_new() - tack a string onto the end of a list of strings
X * list_copy() - copy a whole list of strings
X * list_sublist() - copy a subset of a list of strings
X * list_free() - free a list of strings
X * list_print() - print a list of strings to stdout
X *
X * This implementation essentially uses a singly linked list, but
X * guarantees that the head element of every list has a valid pointer
X * to the tail of the list, so the new elements can efficiently and
X * properly be appended to the end of a list.
X *
X * To avoid massive allocation, list_free() just tacks the whole freed
X * chain onto freelist and list_new() looks on freelist first for an
X * available list struct. list_free() does not free the strings in the
X * chain: it lazily lets list_new() do so.
X *
X * 08/23/94 (seiwald) - new list_append()
X */
X
Xstatic LIST *freelist = 0; /* junkpile for list_free() */
X
X/*
X * list_append() - append a list onto another one, returning total
X */
X
XLIST *
Xlist_append( l, nl )
XLIST *l;
XLIST *nl;
X{
X if( !nl )
X {
X /* Just return l */
X }
X else if( !l )
X {
X l = nl;
X }
X else
X {
X /* Graft two non-empty lists. */
X l->tail->next = nl;
X l->tail = nl->tail;


X }
X
X return l;

X}
X
X/*
X * list_new() - tack a string onto the end of a list of strings
X */
X
XLIST *
Xlist_new( head, string )
XLIST *head;
Xchar *string;
X{
X LIST *l;
X
X if( DEBUG_LISTS )
X printf( "list > %s <\n", string );
X
X /* Get list struct from freelist, if one available. */
X /* Otherwise allocate. */
X /* If from freelist, must free string first */
X
X if( freelist )
X {
X l = freelist;
X freestr( l->string );
X freelist = freelist->next;
X }
X else
X {
X l = (LIST *)malloc( sizeof( *l ) );
X }
X
X /* If first on chain, head points here. */
X /* If adding to chain, tack us on. */
X /* Tail must point to this new, last element. */
X
X if( !head ) head = l;
X else head->tail->next = l;
X head->tail = l;
X l->next = 0;
X
X l->string = string;
X
X return head;
X}
X
X/*
X * list_copy() - copy a whole list of strings (nl) onto end of another (l)
X */
X
XLIST *
Xlist_copy( l, nl )
XLIST *l;
XLIST *nl;
X{
X for( ; nl; nl = list_next( nl ) )
X l = list_new( l, copystr( nl->string ) );
X
X return l;
X}
X
X/*
X * list_sublist() - copy a subset of a list of strings
X */
X
XLIST *
Xlist_sublist( l, start, count )
XLIST *l;
X{
X LIST *nl = 0;
X
X for( ; l && start--; l = list_next( l ) )
X ;
X
X for( ; l && count--; l = list_next( l ) )
X nl = list_new( nl, copystr( l->string ) );
X
X return nl;
X}
X
X/*
X * list_free() - free a list of strings
X */
X
Xvoid
Xlist_free( head )
XLIST *head;
X{
X /* Just tack onto freelist. */
X
X if( head )
X {
X head->tail->next = freelist;
X freelist = head;
X }
X}
X
X/*
X * list_print() - print a list of strings to stdout
X */
X
Xvoid
Xlist_print( l )
XLIST *l;
X{
X for( ; l; l = list_next( l ) )
X printf( "%s ", l->string );
X}
END_OF_FILE
if test 3284 -ne `wc -c <'lists.c'`; then
echo shar: \"'lists.c'\" unpacked with wrong size!
fi
# end of 'lists.c'
fi
if test -f 'make.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'make.c'\"
else
echo shar: Extracting \"'make.c'\" \(8437 characters\)
sed "s/^X//" >'make.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * make.c - bring a target up to date, once rules are in place
X *
X * This modules controls the execution of rules to bring a target and
X * its dependencies up to date. It is invoked after the targets, rules,
X * et. al. described in rules.h are created by the interpreting of the
X * jam files.
X *
X * This file contains the main make() entry point and the first pass
X * make0(). The second pass, make1(), which actually does the command
X * execution, is in make1.c.


X *
X * External routines:

X * make() - make a target, given its name
X *
X * Internal routines:
X * make0() - bind and scan everything to make a TARGET
X *
X * 12/26/93 (seiwald) - allow NOTIME targets to be expanded via $(<), $(>)
X * 01/04/94 (seiwald) - print all targets, bounded, when tracing commands
X * 04/08/94 (seiwald) - progress report now reflects only targets with actions
X * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.


X * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.

X * 12/20/94 (seiwald) - make0() headers after determining fate of target, so
X * that headers aren't seen as dependents on themselves.


X * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.

X * 02/02/95 (seiwald) - propagate leaf source time for new LEAVES rule.
X * 02/14/95 (seiwald) - NOUPDATE rule means don't update existing target.


X */
X
X# include "jam.h"
X
X# include "lists.h"
X# include "parse.h"
X# include "variable.h"
X# include "rules.h"
X
X# include "search.h"
X# include "newstr.h"
X# include "make.h"

X# include "headers.h"
X# include "command.h"
X
Xstatic void make0();


X
X# define max( a,b ) ((a)>(b)?(a):(b))
X

Xtypedef struct {
X int temp;
X int updating;
X int cantfind;
X int cantmake;
X int targets;
X int made;
X} COUNTS ;
X
Xstatic char *target_fate[] =
X{
X "init",
X "making",
X "ok",
X "touched",
X "temp",
X "missing",
X "old",
X "update",
X "nofind",
X "nomake"
X} ;
X
X# define spaces(x) ( " " + 16 - ( x > 16 ? 16 : x ) )
X
X/*
X * make() - make a target, given its name
X */
X
Xvoid
Xmake( n_targets, targets, anyhow )
Xint n_targets;
Xchar **targets;
Xint anyhow;
X{
X int i;
X COUNTS counts[1];


X
X memset( (char *)counts, 0, sizeof( *counts ) );
X

X for( i = 0; i < n_targets; i++ )
X make0( bindtarget( targets[i] ), (time_t)0, 0, counts, anyhow );
X
X if( DEBUG_MAKEQ )
X {
X if( counts->targets )
X printf( "...found %d target(s)...\n", counts->targets );


X }
X
X if( DEBUG_MAKE )
X {

X if( counts->temp )
X printf( "...using %d temp target(s)...\n", counts->temp );
X if( counts->updating )
X printf( "...updating %d target(s)...\n", counts->updating );
X if( counts->cantfind )
X printf( "...can't find %d target(s)...\n", counts->cantfind );
X if( counts->cantmake )
X printf( "...can't make %d target(s)...\n", counts->cantmake );
X }
X
X for( i = 0; i < n_targets; i++ )
X make1( bindtarget( targets[i] ), counts );
X}
X
X/*
X * make0() - bind and scan everything to make a TARGET
X *
X * Make0() recursively binds a target, searches for #included headers,
X * calls itself on those headers, and calls itself on any dependents.


X */
X
Xstatic void

Xmake0( t, parent, depth, counts, anyhow )
XTARGET *t;
Xtime_t parent;
Xint depth;
XCOUNTS *counts;
Xint anyhow;
X{
X TARGETS *c;
X int fate, hfate;
X time_t last, leaf, hlast, hleaf;
X char *flag = "";
X
X if( DEBUG_MAKEPROG )
X printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
X
X /*
X * Step 1: don't remake if already trying or tried
X */
X
X switch( t->fate )
X {
X case T_FATE_MAKING:
X printf( "warning: %s depends on itself\n", t->name );
X return;
X
X default:
X return;
X
X case T_FATE_INIT:
X break;
X }
X
X t->fate = T_FATE_MAKING;
X
X /*
X * Step 2: under the influence of "on target" variables,
X * bind the target and search for headers.
X */
X
X /* Step 2a: set "on target" variables. */


X
X pushsettings( t->settings );
X

X /* Step 2b: find and timestamp the target file (if it's a file). */


X
X if( t->binding == T_BIND_UNBOUND && !( t->flags & T_FLAG_NOTFILE ) )
X {

X t->boundname = search( t->name, &t->time );
X t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
X }

X
X /* If temp file doesn't exist, use parent */
X
X if( t->binding == T_BIND_MISSING && t->flags & T_FLAG_TEMP && parent )
X {
X t->time = parent;
X t->binding = t->time ? T_BIND_PARENTS : T_BIND_MISSING;
X }
X
X /* Step 2c: If its a file, search for headers. */
X
X if( t->binding == T_BIND_EXISTS )
X headers( t );
X
X /* Step 2d: reset "on target" variables */
X


X popsettings( t->settings );
X

X /*
X * Step 3: recursively make0() dependents
X */
X
X last = 0;
X leaf = 0;
X fate = T_FATE_STABLE;
X
X for( c = t->deps[ T_DEPS_DEPENDS ]; c; c = c->next )
X {
X make0( c->target, t->time, depth + 1, counts, anyhow );
X leaf = max( leaf, c->target->leaf );
X leaf = max( leaf, c->target->hleaf );
X
X /* If LEAVES has been applied, we only heed the timestamps of */
X /* the leaf source nodes. */
X
X if( t->flags & T_FLAG_LEAVES )
X {
X last = leaf;
X continue;
X }
X
X last = max( last, c->target->time );
X last = max( last, c->target->htime );
X fate = max( fate, c->target->fate );
X fate = max( fate, c->target->hfate );
X }
X
X /* If a NOUPDATE file exists, make dependents eternally old. */
X
X if( t->flags & T_FLAG_NOUPDATE )
X {
X last = 0;
X t->time = 0;
X }
X
X /* Step 3b: determine fate: rebuild target or what? */
X
X /*
X In English:
X If can't find or make child, can't make target.
X If children changed, make target.
X If target missing, make it.
X If children newer, make target.
X If temp's children newer, make temp.
X If deliberately touched, make it.
X If up-to-date temp file present, use it.
X */
X
X if( fate >= T_FATE_CANTFIND )
X {
X fate = T_FATE_CANTMAKE;
X }
X else if( fate > T_FATE_STABLE )
X {
X fate = T_FATE_UPDATE;
X }
X else if( t->binding == T_BIND_MISSING )
X {
X fate = T_FATE_MISSING;
X }
X else if( t->binding == T_BIND_EXISTS && last > t->time )
X {
X fate = T_FATE_OUTDATED;
X }
X else if( t->binding == T_BIND_PARENTS && last > t->time )
X {
X fate = T_FATE_OUTDATED;
X }
X else if( t->flags & T_FLAG_TOUCHED || anyhow )
X {
X fate = T_FATE_TOUCHED;
X }
X else if( t->binding == T_BIND_EXISTS && t->flags & T_FLAG_TEMP )
X {
X fate = T_FATE_ISTMP;
X }
X
X /* Step 3c: handle missing files */
X /* If it's missing and there are no actions to create it, boom. */
X /* If we can't make a target we don't care about, 'sokay */
X /* We could insist that there are updating actions for all missing */
X /* files, but if they have dependents we just pretend it's NOTFILE. */
X
X if( fate == T_FATE_MISSING &&
X !t->actions &&
X !t->deps[ T_DEPS_DEPENDS ] )
X {
X if( t->flags & T_FLAG_NOCARE )
X {
X fate = T_FATE_STABLE;
X }
X else
X {
X printf( "don't know how to make %s\n", t->name );
X
X fate = T_FATE_CANTFIND;
X }
X }
X
X /* Step 3d: propagate dependents' time & fate. */
X /* Set leaf time to be our time only if this is a leaf. */
X
X t->time = max( t->time, last );
X t->leaf = leaf ? leaf : t->time ;
X t->fate = fate;
X
X /*
X * Step 4: Recursively make0() headers.
X */
X
X /* Step 4a: recursively make0() headers */
X
X hlast = 0;
X hleaf = 0;
X hfate = T_FATE_STABLE;
X
X for( c = t->deps[ T_DEPS_INCLUDES ]; c; c = c->next )
X {
X make0( c->target, parent, depth + 1, counts, anyhow );
X hlast = max( hlast, c->target->time );
X hlast = max( hlast, c->target->htime );
X hleaf = max( hleaf, c->target->leaf );
X hleaf = max( hleaf, c->target->hleaf );
X hfate = max( hfate, c->target->fate );
X hfate = max( hfate, c->target->hfate );
X }
X
X /* Step 4b: propagate dependents' time & fate. */
X
X t->htime = hlast;
X t->hleaf = hleaf ? hleaf : t->htime;
X t->hfate = hfate;
X
X /*
X * Step 5: a little harmless tabulating for tracing purposes
X */
X
X if( !( ++counts->targets % 1000 ) && DEBUG_MAKE )
X printf( "...patience...\n" );
X
X if( fate == T_FATE_ISTMP )
X counts->temp++;
X else if( fate == T_FATE_CANTFIND )
X counts->cantfind++;
X else if( fate == T_FATE_CANTMAKE && t->actions )
X counts->cantmake++;
X else if( fate > T_FATE_STABLE && fate < T_FATE_CANTFIND && t->actions )
X counts->updating++;
X
X if( !( t->flags & T_FLAG_NOTFILE ) && fate > T_FATE_STABLE )
X flag = "+";
X else if( t->binding == T_BIND_EXISTS && parent && t->time > parent )
X flag = "*";
X
X if( DEBUG_MAKEPROG )
X printf( "make%s\t%s\t%s%s\n",
X flag, target_fate[ t->fate ],
X spaces( depth ), t->name );
X}
X
END_OF_FILE
if test 8437 -ne `wc -c <'make.c'`; then
echo shar: \"'make.c'\" unpacked with wrong size!
fi
# end of 'make.c'
fi
if test -f 'variable.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'variable.c'\"
else
echo shar: Extracting \"'variable.c'\" \(5791 characters\)
sed "s/^X//" >'variable.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"


X# include "lists.h"
X# include "parse.h"
X# include "variable.h"

X# include "expand.h"
X# include "hash.h"
X# include "filesys.h"
X# include "newstr.h"
X
X/*
X * variable.c - handle jam multi-element variables


X *
X * External routines:
X *

X * var_defines() - load a bunch of variable=value settings
X * var_list() - variable expand an input list, generating a new list
X * var_string() - expand a string with variables in it
X * var_get() - get value of a user defined symbol
X * var_set() - set a variable in jam's user defined symbol table
X * var_swap() - swap a variable's value with the given one
X * var_done() - free variable tables
X *
X * Internal routines:
X *
X * var_enter() - make new var symbol table entry, returning var ptr
X * var_dump() - dump a variable to stdout


X *
X * 04/13/94 (seiwald) - added shorthand L0 for null list pointer

X * 08/23/94 (seiwald) - Support for '+=' (append to variable)

X * 01/22/94 (seiwald) - split environment variables at blanks or :'s
X */
X
Xstatic struct hash *varhash = 0;
X
X/*
X * VARIABLE - a user defined multi-value variable
X */
X
Xtypedef struct _variable VARIABLE ;
X
Xstruct _variable {
X char *symbol;
X LIST *value;
X} ;
X
Xstatic VARIABLE *var_enter();
Xstatic void var_dump();
X
X
X
X/*
X * var_defines() - load a bunch of variable=value settings
X *
X * If variable name ends in PATH, split value at :'s.
X * Otherwise, split at blanks.
X */
X
Xvoid
Xvar_defines( e )
Xchar **e;
X{
X for( ; *e; e++ )
X {
X char *val;
X
X if( val = strchr( *e, '=' ) )
X {
X LIST *l = L0;
X char *pp, *p;
X char split = ' ';
X char buf[ MAXSYM ];
X
X /* Split *PATH at :'s, not spaces */
X
X if( val - 4 >= *e && !strncmp( val - 4, "PATH", 4 ) )
X split = ':';
X
X /* Do the split */
X
X for( pp = val + 1; p = strchr( pp, split ); pp = p + 1 )
X {
X strncpy( buf, pp, p - pp );
X buf[ p - pp ] = '\0';
X l = list_new( l, newstr( buf ) );
X }
X
X l = list_new( l, newstr( pp ) );
X
X /* Get name */
X
X strncpy( buf, *e, val - *e );
X buf[ val - *e ] = '\0';
X
X var_set( buf, l, VAR_SET );
X }
X }
X}
X
X/*
X * var_list() - variable expand an input list, generating a new list
X *
X * Returns a newly created list.
X */
X
XLIST *
Xvar_list( ilist, targets, sources )
XLIST *ilist;


XLIST *targets;
XLIST *sources;
X{

X LIST *olist = 0;
X
X while( ilist )
X {
X char *s = ilist->string;
X olist = var_expand( olist, s, s + strlen(s), targets, sources, 1 );
X ilist = list_next( ilist );
X }
X
X return olist;
X}
X
X
X/*
X * var_string() - expand a string with variables in it
X *
X * Copies in to out; doesn't modify targets & sources.
X */
X
Xint
Xvar_string( in, out, targets, sources )
Xchar *in;
Xchar *out;


XLIST *targets;
XLIST *sources;
X{

X char *out0 = out;
X
X while( *in )
X {
X char *lastword;
X int dollar = 0;
X
X /* Copy white space */
X
X while( isspace( *in ) )
X *out++ = *in++;
X
X lastword = out;
X
X /* Copy non-white space, watching for variables */
X
X while( *in && !isspace( *in ) )
X {
X if( in[0] == '$' && in[1] == '(' )
X dollar++;
X *out++ = *in++;
X }
X
X /* If a variable encountered, expand it and and embed the */
X /* space-separated members of the list in the output. */
X
X if( dollar )
X {
X LIST *l;
X
X l = var_expand( L0, lastword, out, targets, sources, 0 );
X
X out = lastword;
X
X for( ; l; l = list_next( l ) )
X {
X strcpy( out, l->string );
X out += strlen( out );
X *out++ = ' ';
X }
X
X list_free( l );
X }
X }
X *out++ = '\0';
X
X return out - out0;
X}
X
X/*
X * var_get() - get value of a user defined symbol
X *
X * Returns NULL if symbol unset.
X */
X
XLIST *
Xvar_get( symbol )
Xchar *symbol;
X{
X VARIABLE var, *v = &var;
X
X v->symbol = symbol;
X
X if( varhash && hashcheck( varhash, (HASHDATA **)&v ) )
X {
X if( DEBUG_VARGET )
X var_dump( v->symbol, v->value, "get" );
X return v->value;
X }


X
X return 0;
X}
X
X/*

X * var_set() - set a variable in jam's user defined symbol table
X *
X * 'flag' controls the relationship between new and old values of
X * the variable: SET replaces the old with the new; APPEND appends
X * the new to the old; DEFAULT only uses the new if the variable
X * was previously unset.
X *
X * Copies symbol. Takes ownership of value.
X */
X
Xvoid
Xvar_set( symbol, value, flag )
Xchar *symbol;
XLIST *value;
Xint flag;
X{
X VARIABLE *v = var_enter( symbol );
X
X if( DEBUG_VARSET )
X var_dump( symbol, value, "set" );
X
X switch( flag )
X {
X case VAR_SET:
X /* Replace value */
X list_free( v->value );
X v->value = value;
X break;
X
X case VAR_APPEND:
X /* Append value */
X v->value = list_append( v->value, value );
X break;
X
X case VAR_DEFAULT:
X /* Set only if unset */
X if( !v->value )
X v->value = value;
X else
X list_free( value );
X break;
X }
X}
X
X/*
X * var_swap() - swap a variable's value with the given one
X */
X
XLIST *
Xvar_swap( symbol, value )
Xchar *symbol;
XLIST *value;
X{
X VARIABLE *v = var_enter( symbol );
X LIST *oldvalue = v->value;
X
X if( DEBUG_VARSET )
X var_dump( symbol, value, "set" );
X
X v->value = value;
X
X return oldvalue;
X}
X
X
X
X/*
X * var_enter() - make new var symbol table entry, returning var ptr
X */
X
Xstatic VARIABLE *
Xvar_enter( symbol )
Xchar *symbol;
X{
X VARIABLE var, *v = &var;
X
X if( !varhash )
X varhash = hashinit( sizeof( VARIABLE ), "variables" );
X
X v->symbol = symbol;
X v->value = 0;
X
X if( hashenter( varhash, (HASHDATA **)&v ) )
X v->symbol = newstr( symbol ); /* never freed */
X
X return v;
X}
X
X/*
X * var_dump() - dump a variable to stdout


X */
X
Xstatic void

Xvar_dump( symbol, value, what )
Xchar *symbol;
XLIST *value;
Xchar *what;
X{
X printf( "%s %s = ", what, symbol );
X list_print( value );
X printf( "\n" );
X}
X
X/*
X * var_done() - free variable tables
X */
X
Xvoid
Xvar_done()
X{
X hashdone( varhash );
X}
END_OF_FILE
if test 5791 -ne `wc -c <'variable.c'`; then
echo shar: \"'variable.c'\" unpacked with wrong size!
fi
# end of 'variable.c'
fi
echo shar: End of archive 6 \(of 7\).
cp /dev/null ark6isdone

Christopher Seiwald

unread,
Apr 11, 1995, 3:00:00 AM4/11/95
to
Submitted-by: sei...@tea.org (Christopher Seiwald)
Posting-number: Volume 47, Issue 114
Archive-name: jam/part07

Environment: UNIX, NT, VMS
Supersedes: jam: Volume 27, Issue 81-85

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".

# Contents: Build.com Jamfile Makefile Porting command.c command.h
# compile.h execcmd.h execunix.c execvms.c expand.h glob.c hash.h
# headers.c headers.h jam.h jamgram.h jamgramtab.h lists.h make.h
# newstr.c newstr.h option.c parse.c parse.h patchlevel.h regexp.h
# rules.c rules.h scan.c scan.h search.c search.h timestamp.c
# timestamp.h
# Wrapped by kent@ftp on Sat Mar 25 12:04:11 1995


PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 7 (of 7)."'
if test -f 'Build.com' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Build.com'\"
else
echo shar: Extracting \"'Build.com'\" \(914 characters\)
sed "s/^X//" >'Build.com' <<'END_OF_FILE'
X! Bootstrap build script for Jam
X! On OPENVMS you need the next line
X! $ cc := cc/stand=vaxc
X$ cc command.c
X$ cc compile.c
X$ cc expand.c
X$ cc execvms.c
X$ cc filevms.c
X$ cc glob.c
X$ cc hash.c
X$ cc headers.c
X$ cc lists.c
X$ cc make.c
X$ cc make1.c
X$ cc newstr.c
X$ cc option.c
X$ cc parse.c
X$ cc regexp.c
X$ cc rules.c
X$ cc scan.c
X$ cc search.c
X$ cc timestamp.c
X$ cc variable.c
X$ cc jam.c
X$ cc jamgram.c
X$ link/exe=jam.exe command.obj, compile.obj, execvms.obj, expand.obj, -
X filevms.obj, glob.obj, hash.obj, headers.obj, lists.obj, make.obj, -
X make1.obj, newstr.obj, option.obj, parse.obj, regexp.obj, rules.obj, -
X scan.obj, search.obj, timestamp.obj, variable.obj, jam.obj, jamgram.obj
X$ write sys$output "If that was successful, define a symbol for jam:"
X$ write sys$output ""
X$ write sys$output " jam :== $xxxx:jam.exe -f xxxx:jambase"
X$ write sys$output ""
X$ write sys$output "and then run jam here."
END_OF_FILE
if test 914 -ne `wc -c <'Build.com'`; then
echo shar: \"'Build.com'\" unpacked with wrong size!
fi
# end of 'Build.com'
fi
if test -f 'Jamfile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Jamfile'\"
else
echo shar: Extracting \"'Jamfile'\" \(866 characters\)
sed "s/^X//" >'Jamfile' <<'END_OF_FILE'
X#
X# Jamfile to build Jam (a make(1)-like program)
X#
X
X#
X# We have some different files for UNIX, VMS, and NT.


X#
X
Xswitch $(OS)
X{

Xcase VMS : code = vms ;
Xcase OPENVMS : code = vms ;
Xcase NT : code = nt ;
Xcase * : code = unix ;
X}
X
X
X#
X# The guts of the Jamfile: how to build Jam
X#
X
XMain jam : jam.c ;
XLinkLibraries jam : libjam.a ;
X
XLibrary libjam.a :
X command.c compile.c exec$(code).c expand.c
X file$(code).c glob.c hash.c headers.c jamgram.y
X lists.c make.c make1.c newstr.c option.c parse.c
X regexp.c rules.c scan.c search.c timestamp.c
X variable.c ;
X
X#
X# On UNIX, we install this stuff for easy use.
X# On VMS, one must define a symbol: jam :== $jam.exe -f jambase
X# On NT, you're on your own.


X#
X
Xif $(UNIX)
X{

X InstallBin $(BINDIR) : jam ;
X InstallLib $(LIBDIR) : Jambase ;
X InstallMan $(MANDIR) : jam.1 Jambase.5 Jamfile.5 ;
X}
X
END_OF_FILE
if test 866 -ne `wc -c <'Jamfile'`; then
echo shar: \"'Jamfile'\" unpacked with wrong size!
fi
# end of 'Jamfile'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(443 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile for jam
X
XCC = cc
XTARGET = -o jam0
XOPTIM = -O
X
X# Special flavors - uncomment appropriate lines
X
X# Solaris 2.0 seem not to have any identifying cpp symbol
X#CFLAGS = -Dsolaris
X
X# AIX needs -lbsd, and has no identifying cpp symbol
X#LINKLIBS = -lbsd
X#CFLAGS = -DAIX
X
X# NT (with Microsoft compiler)
X#CC = cl
X#CFLAGS = -DNT
X#TARGET = /Fejam0
X
Xinstall: jam0
X jam0 -f Jambase install
X
Xjam0:
X cc $(TARGET) $(OPTIM) $(CFLAGS) *.c $(LINKLIBS)
END_OF_FILE
if test 443 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'Porting' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Porting'\"
else
echo shar: Extracting \"'Porting'\" \(2226 characters\)
sed "s/^X//" >'Porting' <<'END_OF_FILE'
XNotes on porting Jam - revised 1/11/95
X
X1) Working out system dependencies in the Jam code.
X
X Jam's OS footprint is fairly small. For OS independent work Jam
X liberally uses standard libc functions like stdio, malloc, and
X string. The OS dependent interfaces are:
X
X From filesys.h:
X
X file_parse() - split a file name into dir/base/suffix/member
X file_build() - build a filename given dir/base/suffix/member
X file_dirscan() - scan a directory for files
X file_archscan() - scan an archive for files
X file_time() - get the timestamp of a file, if not already
X done by file_dirscan().
X
X From execcmd.h:
X
X execcmd() - execute a shell script
X execwait() - wait for any outstanding execcmd()'s.
X
X Porting to another UNIX platform rarely involves more than fixing
X file_dirscan() or, more likely, file_archscan() to work on the rogue
X directory or archive structure. Porting to another OS, such as Mac,
X DOS, etc, probably require a completely new implementation of
X fileunix.c and execunix.c.
X
X2) Defining OTHERSYMS in jam.h
X
X So that the Jambase and Jamfile know their host, Jam defines $(OS)
X to be something useful for each platform. Make sure that there is
X code in jam.h to generate a useful value for $(OS), and key it off
X the platform specific C-preprocessor symbol. If the C-preprocessor
X doesn't itself defines such a symbol, add a define to the Makefile.
X
X3) Working out system dependencies in the Jambase
X
X With the value of $(OS) available, the Jambase can be extended to
X support special variables or rules for new platforms. See the
X current support for VMS and NT.
X
X4) Yacc troubles
X
X The generated files jamgram.h and jamgram.c are distributed for the
X poor souls without yacc.
X
X5) Known problematic systems:
X
X - Solaris 2.0 sucks (still). Jam only works with the SUNWspro cc,
X because the ucb one has bogus headers for dirent.
X
X - Pyramid has no malloc.h, memory.h
X
X - Encore has no stdlib.h
X
X - Bull DPX has sys/file.h problems
X
X6) Send the results back.
X
X If you do porting work, the result can be integrated into future
X releases if you send it back to the author's adress in the README.
END_OF_FILE
if test 2226 -ne `wc -c <'Porting'`; then
echo shar: \"'Porting'\" unpacked with wrong size!
fi
# end of 'Porting'
fi
if test -f 'command.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'command.c'\"
else
echo shar: Extracting \"'command.c'\" \(1674 characters\)
sed "s/^X//" >'command.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*


X * command.c - maintain lists of commands
X *

X * Each target has a list of actions that are to be applied to it, but due
X * to modifications on the actions they do not map one-to-one to the commands
X * that are the be executed against the target. The CMD datatype holds
X * a single command that is to be executed against a target, and they can
X * chain together to represent the full collection of commands used to
X * update a target.


X *
X * External routines:

X * cmd_new() - make a new CMD and chain it
X * cmd_free() - free a CMD
X *
X * Macros:
X * cmd_next() - follow chain of CMDs

X */
X
X# include "jam.h"
X
X# include "lists.h"
X# include "parse.h"
X# include "variable.h"
X# include "rules.h"
X

X# include "command.h"
X
X/*
X * cmd_new() - make a new CMD and chain it
X */
X
XCMD *
Xcmd_new( chain, rule, targets, sources, shell )
XCMD *chain;
XRULE *rule;
XLIST *targets;
XLIST *sources;
XLIST *shell;
X{
X int len;
X
X CMD *cmd = (CMD *)malloc( sizeof( CMD ) );
X
X cmd->rule = rule;
X cmd->targets = targets;
X cmd->sources = sources;
X cmd->shell = shell;
X
X len = var_string( rule->actions, cmd->buf, targets, sources );
X
X if( len > MAXCMD )
X {
X /* Can't do much here - we just blew our buffer! */
X printf( "fatal error: command too long\n" );
X exit( EXITBAD );
X }
X
X if( !chain ) chain = cmd;
X else chain->tail->next = cmd;
X chain->tail = cmd;
X cmd->next = 0;
X
X return chain;
X}
X
X/*
X * cmd_free() - free a CMD
X */
X
Xvoid
Xcmd_free( cmd )
XCMD *cmd;
X{
X list_free( cmd->sources );
X list_free( cmd->targets );
X list_free( cmd->shell );
X
X free( (char *)cmd );
X}
END_OF_FILE
if test 1674 -ne `wc -c <'command.c'`; then
echo shar: \"'command.c'\" unpacked with wrong size!
fi
# end of 'command.c'
fi
if test -f 'command.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'command.h'\"
else
echo shar: Extracting \"'command.h'\" \(1055 characters\)
sed "s/^X//" >'command.h' <<'END_OF_FILE'
X/*
X * Copyright 1994 Christopher Seiwald.


X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * command.h - the CMD structure and routines to manipulate them
X *
X * Both ACTION and CMD contain a rule, targets, and sources. An
X * ACTION describes a rule to be applied to the given targets and
X * sources; a CMD is what actually gets executed by the shell. The
X * differences are due to:
X *
X * ACTIONS must be combined if 'actions together' is given.
X * ACTIONS must be split if 'actions piecemeal' is given.
X * ACTIONS must have current sources omitted for 'actions updated'.
X */
X
X/*
X * CMD - an action, ready to be formatted into a buffer and executed
X */
X
Xtypedef struct _cmd CMD;
X
Xstruct _cmd
X{
X CMD *next;
X CMD *tail; /* valid on in head */
X RULE *rule; /* rule->actions contains shell script */
X LIST *targets; /* LIST for $(<) */
X LIST *sources; /* LIST for $(>) */
X LIST *shell; /* $(SHELL) value */
X char buf[ MAXCMD ]; /* actual commands */
X} ;
X
XCMD *cmd_new();
Xvoid cmd_free();
X
X# define cmd_next( c ) ((c)->next)
END_OF_FILE
if test 1055 -ne `wc -c <'command.h'`; then
echo shar: \"'command.h'\" unpacked with wrong size!
fi
# end of 'command.h'
fi
if test -f 'compile.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'compile.h'\"
else
echo shar: Extracting \"'compile.h'\" \(1509 characters\)
sed "s/^X//" >'compile.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * compile.h - compile parsed jam statements
X *


X * 06/01/94 (seiwald) - new 'actions existing' does existing sources

X * 08/23/94 (seiwald) - Support for '+=' (append to variable)

X */
X
Xvoid compile_builtins();
Xvoid compile_foreach();
Xvoid compile_if();
Xvoid compile_include();
Xvoid compile_rule();
Xvoid compile_rules();
Xvoid compile_set();
Xvoid compile_setcomp();
Xvoid compile_setexec();
Xvoid compile_settings();
Xvoid compile_switch();
X
X/* Flags for compile_set(), etc */
X
X# define ASSIGN_SET 0x00 /* = assign variable */
X# define ASSIGN_APPEND 0x01 /* += append variable */
X# define ASSIGN_DEFAULT 0x02 /* set only if unset */
X
X/* Flags for compile_setexec() */
X
X# define EXEC_UPDATED 0x01 /* executes updated */
X# define EXEC_TOGETHER 0x02 /* executes together */
X# define EXEC_IGNORE 0x04 /* executes ignore */
X# define EXEC_QUIETLY 0x08 /* executes quietly */
X# define EXEC_PIECEMEAL 0x10 /* executes piecemeal */
X# define EXEC_EXISTING 0x20 /* executes existing */
X
X/* Conditions for compile_if() */
X
X# define COND_NOT 0 /* ! cond */
X# define COND_AND 1 /* cond && cond */
X# define COND_OR 2 /* cond || cond */
X
X# define COND_EXISTS 3 /* arg */
X# define COND_EQUALS 4 /* arg = arg */
X# define COND_NOTEQ 5 /* arg != arg */
X# define COND_LESS 6 /* arg < arg */
X# define COND_LESSEQ 7 /* arg <= arg */
X# define COND_MORE 8 /* arg > arg */
X# define COND_MOREEQ 9 /* arg >= arg */
END_OF_FILE
if test 1509 -ne `wc -c <'compile.h'`; then
echo shar: \"'compile.h'\" unpacked with wrong size!
fi
# end of 'compile.h'
fi
if test -f 'execcmd.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'execcmd.h'\"
else
echo shar: Extracting \"'execcmd.h'\" \(331 characters\)
sed "s/^X//" >'execcmd.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * execcmd.h - execute a shell script
X *
X * 05/04/94 (seiwald) - async multiprocess interface
X */
X
Xvoid execcmd();
Xint execwait();
X
X# define EXEC_CMD_OK 0
X# define EXEC_CMD_FAIL 1
X# define EXEC_CMD_INTR 2
END_OF_FILE
if test 331 -ne `wc -c <'execcmd.h'`; then
echo shar: \"'execcmd.h'\" unpacked with wrong size!
fi
# end of 'execcmd.h'
fi
if test -f 'execunix.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'execunix.c'\"
else
echo shar: Extracting \"'execunix.c'\" \(4275 characters\)
sed "s/^X//" >'execunix.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "execcmd.h"
X# include "lists.h"
X# include <errno.h>


X
X# ifdef unix
X

X# if defined(__sgi) || (defined (COHERENT) && defined (_I386))
X# define vfork() fork()
X# endif
X
X/*
X * execunix.c - execute a shell script on UNIX
X *
X * If $(JAMSHELL) is defined, uses that to formulate execvp().
X * The default is:
X *
X * /bin/sh -c %
X *
X * Each word must be an individual element in a jam variable value.
X *
X * In $(JAMSHELL), % expands to the command string and ! expands to
X * the slot number (starting at 1) for multiprocess (-j) invocations.
X * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
X * argument.
X *
X * Don't just set JAMSHELL to /bin/sh - it won't work!


X *
X * External routines:

X * execcmd() - launch an async command execution
X * execwait() - wait and drive at most one execution completion


X *
X * Internal routines:

X * onintr() - bump intr to note command interruption
X *


X * 04/08/94 (seiwald) - Coherent/386 support added.

X * 05/04/94 (seiwald) - async multiprocess interface
X * 01/22/95 (seiwald) - $(JAMSHELL) support
X */
X
Xstatic int intr = 0;
X
Xstatic int cmdsrunning = 0;
X
Xstatic void (*istat)();
X
Xstatic struct
X{
X int pid;
X void (*func)();
X void *closure;
X} cmdtab[ MAXJOBS ] = {0};
X
X/*
X * onintr() - bump intr to note command interruption
X */
X
Xvoid
Xonintr()
X{
X intr++;
X printf( "...interrupted\n" );
X}
X
X/*
X * execcmd() - launch an async command execution
X */
X
Xvoid
Xexeccmd( string, func, closure, shell )
Xchar *string;
Xvoid (*func)();
Xvoid *closure;
XLIST *shell;
X{
X int pid;
X int slot;
X char *argv[ MAXARGC + 1 ]; /* +1 for NULL */
X
X /* Find a slot in the running commands table for this one. */
X
X for( slot = 0; slot < MAXJOBS; slot++ )
X if( !cmdtab[ slot ].pid )
X break;
X
X if( slot == MAXJOBS )
X {
X printf( "no slots for child!\n" );
X exit( EXITBAD );
X }
X
X /* Forumulate argv */
X /* If shell was defined, be prepared for % and ! subs. */
X /* Otherwise, use stock /bin/sh. */
X
X if( shell )
X {
X int i;
X char jobno[4];
X int gotpercent = 0;
X
X sprintf( jobno, "%d", slot + 1 );
X
X for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
X {
X switch( shell->string[0] )
X {
X case '%': argv[i] = string; gotpercent++; break;
X case '!': argv[i] = jobno; break;
X default: argv[i] = shell->string;
X }
X if( DEBUG_EXECCMD )
X printf( "argv[%d] = '%s'\n", i, argv[i] );
X }
X
X if( !gotpercent )
X argv[i++] = string;
X
X argv[i] = 0;
X }
X else
X {
X argv[0] = "/bin/sh";
X argv[1] = "-c";
X argv[2] = string;
X argv[3] = 0;
X }
X
X /* Catch interrupts whenever commands are running. */
X
X if( !cmdsrunning++ )
X istat = signal( SIGINT, onintr );
X
X /* Start the command */
X
X if ((pid = vfork()) == 0)
X {
X execvp( argv[0], argv );
X _exit(127);
X }
X
X if( pid == -1 )
X {
X perror( "vfork" );
X exit( EXITBAD );
X }
X
X /* Save the operation for execwait() to find. */
X
X cmdtab[ slot ].pid = pid;
X cmdtab[ slot ].func = func;
X cmdtab[ slot ].closure = closure;
X
X /* Wait until we're under the limit of concurrent commands. */
X /* Don't trust globs.jobs alone. */
X
X while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
X if( !execwait() )
X break;
X}
X
X/*
X * execwait() - wait and drive at most one execution completion
X */
X
Xint
Xexecwait()
X{
X int i;
X int status, w;
X int rstat;
X
X /* Handle naive make1() which doesn't know if cmds are running. */
X
X if( !cmdsrunning )
X return 0;
X
X /* Pick up process pid and status */
X
X while( ( w = wait( &status ) ) == -1 && errno == EINTR )
X ;
X
X if( w == -1 )
X {
X printf( "child process(es) lost!\n" );
X perror("wait");
X exit( EXITBAD );
X }
X
X /* Find the process in the cmdtab. */
X
X for( i = 0; i < MAXJOBS; i++ )
X if( w == cmdtab[ i ].pid )
X break;
X
X if( i == MAXJOBS )
X {
X printf( "waif child found!\n" );
X exit( EXITBAD );
X }
X
X /* Drive the completion */
X
X if( !--cmdsrunning )
X signal( SIGINT, istat );
X
X if( intr )
X rstat = EXEC_CMD_INTR;
X else if( w == -1 || status != 0 )
X rstat = EXEC_CMD_FAIL;
X else
X rstat = EXEC_CMD_OK;
X
X cmdtab[ i ].pid = 0;
X
X (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat );
X
X return 1;
X}
X
X# endif /* unix */
END_OF_FILE
if test 4275 -ne `wc -c <'execunix.c'`; then
echo shar: \"'execunix.c'\" unpacked with wrong size!
fi
# end of 'execunix.c'
fi
if test -f 'execvms.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'execvms.c'\"
else
echo shar: Extracting \"'execvms.c'\" \(2071 characters\)
sed "s/^X//" >'execvms.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# ifdef VMS
X
X# include "jam.h"
X# include "execcmd.h"
X# include "lists.h"
X
X#include <stdio.h>
X#include <string.h>
X#include <stdlib.h>
X#include <iodef.h>
X#include <ssdef.h>
X#include <descrip.h>
X#include <dvidef.h>
X#include <clidef.h>
X
X/*


X * execvms.c - execute a shell script, ala VMS
X *

X * 05/04/94 (seiwald) - async multiprocess interface; noop on VMS
X */
X
X#define WRTLEN 240
X
X#define MIN( a, b ) ((a) < (b) ? (a) : (b))
X
X /* macros to allocate and initialize VMS descriptors
X */
X#define DESCALLOC( name ) struct dsc$descriptor_s \
X (name) = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_D, NULL }
X
Xvoid
Xexeccmd( string, func, closure, shell )
Xchar *string;
Xvoid (*func)();
Xvoid *closure;
XLIST *shell;
X{
X int rstat = EXEC_CMD_OK;
X
X /* Split string at newlines, and don't execute empty lines */
X /* Bail if any lines fail. */
X
X while( *string )
X {
X char *s;
X char *os = string;
X int something = 0;
X
X for( s = string; *s && *s != '\n'; s++ )
X if( !isspace( *s ) )
X something++;
X
X string = *s ? s + 1 : s ;
X
X if( something )
X {
X int status;
X int len;
X
X *s = '\0';
X
X if( ( len = strlen( os ) ) < WRTLEN )
X {
X status = system( os ) & 0x07;
X }
X else
X {
X FILE *f = fopen( "sys$scratch:jam.com", "w" );
X
X if( !f )
X {
X printf( "can't open command file\n" );
X rstat = EXEC_CMD_FAIL;
X break;
X }
X
X fputc( '$', f );
X
X while( len > 0 )
X {
X int l = MIN( len, WRTLEN );
X
X fwrite( os, l, 1, f );
X
X if( l < len )
X fputc( '-', f );
X
X fputc( '\n', f );
X
X len -= l;
X os += l;
X }
X
X fclose( f );
X
X status = system( "@sys$scratch:jam.com" ) & 0x07;
X
X unlink( "sys$scratch:jam.com" );
X
X }
X
X /* Fail for error or fatal error */
X /* OK on OK, warning, or info exit */
X
X if( status == 2 || status == 4 )
X {
X rstat = EXEC_CMD_FAIL;


X break;
X }
X }
X }
X

X (*func)( closure, rstat );
X}
X
Xint
Xexecwait()


X{
X return 0;
X}
X

X# endif /* VMS */

END_OF_FILE
if test 2071 -ne `wc -c <'execvms.c'`; then
echo shar: \"'execvms.c'\" unpacked with wrong size!
fi
# end of 'execvms.c'
fi
if test -f 'expand.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'expand.h'\"
else
echo shar: Extracting \"'expand.h'\" \(204 characters\)
sed "s/^X//" >'expand.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * expand.h - expand a buffer, given variable values
X */
X
XLIST *var_expand();
END_OF_FILE
if test 204 -ne `wc -c <'expand.h'`; then
echo shar: \"'expand.h'\" unpacked with wrong size!
fi
# end of 'expand.h'
fi
if test -f 'glob.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'glob.c'\"
else
echo shar: Extracting \"'glob.c'\" \(2338 characters\)
sed "s/^X//" >'glob.c' <<'END_OF_FILE'
X/*
X * Copyright 1994 Christopher Seiwald. All rights reserved.

X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * glob.c - match a string against a simple pattern
X *
X * Understands the following patterns:
X *
X * * any number of characters
X * ? any single character
X * [a-z] any single character in the range a-z
X * [^a-z] any single character not in the range a-z
X *
X * External functions:
X *
X * glob() - match a string against a simple pattern
X *
X * Internal functions:
X *
X * globchars() - build a bitlist to check for character group match


X */
X
X# include "jam.h"
X

X# define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
X# define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
X
Xstatic void globchars();
X
X/*
X * glob() - match a string against a simple pattern
X */
X
Xint
Xglob( c, s )
Xregister char *c;
Xregister char *s;
X{
X char bitlist[ BITLISTSIZE ];
X char *here;
X
X for( ;; )
X switch( *c++ )
X {
X case '\0':
X return *s ? -1 : 0;
X
X case '?':
X if( !*s++ )
X return 1;
X break;
X
X case '[':
X /* scan for matching ] */
X
X here = c;
X do if( !*c++ )
X return 1;
X while( here == c || *c != ']' );
X c++;
X
X /* build character class bitlist */
X
X globchars( here, c, bitlist );
X
X if( !CHECK_BIT( bitlist, *(unsigned char *)s ) )
X return 1;
X s++;
X break;
X
X case '*':
X here = s;
X
X while( *s )
X s++;
X
X /* Try to match the rest of the pattern in a recursive */
X /* call. If the match fails we'll back up chars, retrying. */
X
X while( s != here )
X {
X int r;
X
X /* A fast path for the last token in a pattern */
X
X r = *c ? glob( c, s ) : *s ? -1 : 0;
X
X if( !r )
X return 0;
X else if( r < 0 )
X return 1;
X
X --s;
X }
X break;
X
X default:
X if( *s++ != c[-1] )
X return 1;
X break;
X }
X}
X
X/*
X * globchars() - build a bitlist to check for character group match


X */
X
Xstatic void

Xglobchars( s, e, b )
Xchar *s, *e, *b;
X{
X int neg = 0;
X
X memset( b, '\0', BITLISTSIZE );
X
X if( *s == '^')
X neg++, s++;
X
X while( s < e )
X {
X int c;
X
X if( s+2 < e && s[1] == '-' )
X {
X for( c = s[0]; c <= s[2]; c++ )
X b[ c/8 ] |= (1<<(c%8));
X s += 3;
X } else {
X c = *s++;
X b[ c/8 ] |= (1<<(c%8));
X }
X }
X
X if( neg )
X {
X int i;
X for( i = 0; i < BITLISTSIZE; i++ )
X b[ i ] ^= -1;
X }
X
X /* Don't include \0 in either $[chars] or $[^chars] */
X
X b[0] &= 0376;
X}
END_OF_FILE
if test 2338 -ne `wc -c <'glob.c'`; then
echo shar: \"'glob.c'\" unpacked with wrong size!
fi
# end of 'glob.c'
fi
if test -f 'hash.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'hash.h'\"
else
echo shar: Extracting \"'hash.h'\" \(387 characters\)
sed "s/^X//" >'hash.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * hash.h - simple in-memory hashing routines
X */
X
Xtypedef struct hashdata HASHDATA;
X
Xstruct hash * hashinit();
Xint hashitem();
Xvoid hashdone();
X
X# define hashenter( hp, data ) !hashitem( hp, data, !0 )
X# define hashcheck( hp, data ) hashitem( hp, data, 0 )
END_OF_FILE
if test 387 -ne `wc -c <'hash.h'`; then
echo shar: \"'hash.h'\" unpacked with wrong size!
fi
# end of 'hash.h'
fi
if test -f 'headers.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'headers.c'\"
else
echo shar: Extracting \"'headers.c'\" \(2512 characters\)
sed "s/^X//" >'headers.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "lists.h"
X# include "parse.h"

X# include "compile.h"
X# include "rules.h"
X# include "variable.h"
X# include "regexp.h"
X# include "headers.h"


X# include "newstr.h"
X
X/*

X * headers.c - handle #includes in source files
X *
X * Using regular expressions provided as the variable $(HDRSCAN),
X * headers() searches a file for #include files and phonies up a
X * rule invocation:
X *
X * $(HDRRULE) <target> : <include files> ;
X *
X * External routines:
X * headers() - scan a target for include files and call HDRRULE


X *
X * Internal routines:

X * headers1() - using regexp, scan a file and build include LIST


X *
X * 04/13/94 (seiwald) - added shorthand L0 for null list pointer

X */
X
Xstatic LIST *headers1();
X
X/*
X * headers() - scan a target for include files and call HDRRULE
X */
X
X# define MAXINC 10
X
Xvoid
Xheaders( t )
XTARGET *t;
X{
X LIST *hdrscan;
X LIST *hdrrule;
X LIST *headlist = 0;
X PARSE p[1];
X regexp *re[ MAXINC ];
X int rec = 0;
X char *fname = t->boundname ? t->boundname : t->name;
X
X if( !( hdrscan = var_get( "HDRSCAN" ) ) ||
X !( hdrrule = var_get( "HDRRULE" ) ) )
X return;
X
X if( DEBUG_HEADER )
X printf( "header scan %s\n", t->name );
X
X /* Compile all regular expressions in HDRSCAN */
X
X while( rec < MAXINC && hdrscan )
X {
X re[rec++] = regcomp( hdrscan->string );
X hdrscan = list_next( hdrscan );
X }
X
X /* Doctor up call to HDRRULE rule */
X /* Call headers1() to get LIST of included files. */
X
X p->llist = list_new( L0, t->name );
X p->rlist = headers1( headlist, fname, rec, re );
X p->string = hdrrule->string;
X
X if( p->rlist )
X compile_rule( p, L0, L0 );
X
X /* Clean up */
X
X list_free( p->llist );
X list_free( p->rlist );
X
X while( rec )
X free( (char *)re[--rec] );
X}
X
X/*
X * headers1() - using regexp, scan a file and build include LIST


X */
X
Xstatic LIST *

Xheaders1( l, file, rec, re )
XLIST *l;
Xchar *file;
Xint rec;
Xregexp *re[];
X{
X FILE *f;
X char buf[ 1024 ];
X int i;
X
X if( !( f = fopen( file, "r" ) ) )
X return l;
X
X while( fgets( buf, sizeof( buf ), f ) )
X {
X for( i = 0; i < rec; i++ )
X if( regexec( re[i], buf ) && re[i]->startp[1] )
X {
X re[i]->endp[1][0] = '\0';
X
X if( DEBUG_HEADER )
X printf( "header found: %s\n", re[i]->startp[1] );
X
X l = list_new( l, newstr( re[i]->startp[1] ) );
X }
X }
X
X fclose( f );


X
X return l;
X}
X

Xvoid
Xregerror( s )
Xchar *s;
X{
X printf( "re error %s\n", s );
X}
END_OF_FILE
if test 2512 -ne `wc -c <'headers.c'`; then
echo shar: \"'headers.c'\" unpacked with wrong size!
fi
# end of 'headers.c'
fi
if test -f 'headers.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'headers.h'\"
else
echo shar: Extracting \"'headers.h'\" \(195 characters\)
sed "s/^X//" >'headers.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * headers.h - handle #includes in source files
X */
X
Xvoid headers();
END_OF_FILE
if test 195 -ne `wc -c <'headers.h'`; then
echo shar: \"'headers.h'\" unpacked with wrong size!
fi
# end of 'headers.h'
fi
if test -f 'jam.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jam.h'\"
else
echo shar: Extracting \"'jam.h'\" \(4415 characters\)
sed "s/^X//" >'jam.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * jam.h - includes and globals for jam
X *


X * 04/08/94 (seiwald) - Coherent/386 support added.

X * 04/21/94 (seiwald) - DGUX is __DGUX__, not just __DGUX.
X * 05/04/94 (seiwald) - new globs.jobs (-j jobs)
X * 11/01/94 (wingerd) - let us define path of Jambase at compile time.
X * 12/30/94 (wingerd) - changed command buffer size for NT (MS-DOS shell).
X * 02/22/95 (seiwald) - Jambase now in /usr/local/lib.
X */
X
X# ifdef VMS
X
X# ifdef __ALPHA
X
X# include <types.h>
X# include <file.h>
X# include <stat.h>
X# include <stdio.h>
X# include <ctype.h>
X# include <stdlib.h>
X# include <signal.h>
X# include <string.h>
X# include <time.h>
X
X# define OTHERSYMS "VMS=true","OS=OPENVMS"
X
X# else
X
X# include <types.h>
X# include <file.h>
X# include <stat.h>
X# include <stdio.h>
X# include <ctype.h>
X# include <signal.h>
X# include <string.h>
X# include <time.h>
X
X# define OTHERSYMS "VMS=true","OS=VMS"
X
X# endif
X
X# define MAXCMD 255 /* longest command - related to quotas */
X# define JAMBASE "Jambase"
X# define EXITOK 1
X# define EXITBAD 0
X
X# else


X
X# ifdef NT
X

X# include <fcntl.h>
X# include <stdlib.h>
X# include <stdio.h>
X# include <ctype.h>
X# include <malloc.h>
X# include <memory.h>
X# include <signal.h>
X# include <string.h>
X# include <time.h>
X
X# define OTHERSYMS "NT=true","OS=NT"
X# define JAMBASE "Jambase"
X# define MAXCMD 996 /* longest command */
X# define EXITOK 0
X# define EXITBAD 1
X
X# else
X
X# include <sys/types.h>
X# include <sys/file.h>
X# include <sys/stat.h>
X# include <fcntl.h>
X# ifndef ultrix
X# include <stdlib.h>
X# endif
X# include <stdio.h>
X# include <ctype.h>
X# ifndef __bsdi__
X# include <malloc.h>
X# endif
X# include <memory.h>
X# include <signal.h>
X# include <string.h>
X# include <time.h>
X
X# ifdef _AIX
X# define unix
X# define OTHERSYMS "UNIX=true","OS=AIX"
X# endif
X# ifdef __bsdi__
X# define OTHERSYMS "UNIX=true","OS=BSDI"
X# endif
X# ifdef __DGUX__
X# define OTHERSYMS "UNIX=true","OS=DGUX"
X# endif
X# ifdef __hpux
X# define OTHERSYMS "UNIX=true","OS=HPUX"
X# endif
X# ifdef __osf__
X# define OTHERSYMS "UNIX=true","OS=OSF"
X# endif
X# ifdef _SEQUENT_
X# define OTHERSYMS "UNIX=true","OS=PTX"
X# endif
X# ifdef __sgi
X# define OTHERSYMS "UNIX=true","OS=IRIX"
X# endif
X# ifdef sun
X# define OTHERSYMS "UNIX=true","OS=SUNOS"
X# endif
X# ifdef solaris
X# undef OTHERSYMS
X# define OTHERSYMS "UNIX=true","OS=SOLARIS"
X# endif
X# ifdef ultrix
X# define OTHERSYMS "UNIX=true","OS=ULTRIX"
X# endif


X# if defined (COHERENT) && defined (_I386)

X# define OTHERSYMS "UNIX=true","OS=COHERENT/386"
X# endif
X# ifndef OTHERSYMS
X# define OTHERSYMS "UNIX=true"
X# endif
X
X# ifndef JAMBASE
X# define JAMBASE "/usr/local/lib/Jambase"
X# endif
X# define MAXCMD 10240 /* longest command */
X# define EXITOK 0
X# define EXITBAD 1


X
X# endif /* NT */

X
X# endif /* UNIX */
X
X/* You probably don't need to muck with these. */
X
X# define MAXSYM 1024 /* longest symbol in the environment */
X# define MAXPATH 1024 /* longest filename */
X
X# define MAXJOBS 64 /* silently enforce -j limit */
X# define MAXARGC 32 /* words in $(JAMSHELL) */
X
X/* Jam private definitions below. */
X
Xstruct globs {
X int debug;
X int noexec;
X int jobs;
X} ;
X
Xextern struct globs globs;
X
X# define DEBUG_MAKE ( globs.debug >= 1 ) /* show actions when executed */
X# define DEBUG_MAKEQ ( globs.debug >= 2 ) /* show even quiet actions */
X# define DEBUG_EXEC ( globs.debug >= 2 ) /* show text of actons */
X# define DEBUG_MAKEPROG ( globs.debug >= 3 ) /* show progress of make0 */
X# define DEBUG_EXECCMD ( globs.debug >= 3 ) /* show execcmds()'s work */
X
X# define DEBUG_BIND ( globs.debug >= 4 ) /* show when files bound */
X# define DEBUG_COMPILE ( globs.debug >= 5 ) /* show rule invocations */
X# define DEBUG_MEM ( globs.debug >= 5 ) /* show memory use */
X# define DEBUG_HEADER ( globs.debug >= 6 ) /* show result of header scan */
X# define DEBUG_BINDSCAN ( globs.debug >= 6 ) /* show result of dir scan */
X# define DEBUG_SEARCH ( globs.debug >= 6 ) /* show attempts at binding */
X
X# define DEBUG_IF ( globs.debug >= 7 ) /* show 'if' calculations */
X# define DEBUG_VARSET ( globs.debug >= 7 ) /* show variable settings */
X# define DEBUG_VARGET ( globs.debug >= 8 ) /* show variable fetches */
X# define DEBUG_VAREXP ( globs.debug >= 8 ) /* show variable expansions */
X# define DEBUG_LISTS ( globs.debug >= 9 ) /* show list manipulation */
X# define DEBUG_SCAN ( globs.debug >= 9 ) /* show scanner tokens */
X
END_OF_FILE
if test 4415 -ne `wc -c <'jam.h'`; then
echo shar: \"'jam.h'\" unpacked with wrong size!
fi
# end of 'jam.h'
fi
if test -f 'jamgram.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jamgram.h'\"
else
echo shar: Extracting \"'jamgram.h'\" \(758 characters\)
sed "s/^X//" >'jamgram.h' <<'END_OF_FILE'

END_OF_FILE
if test 758 -ne `wc -c <'jamgram.h'`; then
echo shar: \"'jamgram.h'\" unpacked with wrong size!
fi
# end of 'jamgram.h'
fi
if test -f 'jamgramtab.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'jamgramtab.h'\"
else
echo shar: Extracting \"'jamgramtab.h'\" \(736 characters\)
sed "s/^X//" >'jamgramtab.h' <<'END_OF_FILE'
X { "!", _BANG },
X { "!=", _BANG_EQUALS },
X { "&&", _AMPERAMPER },
X { "(", _LPAREN },
X { ")", _RPAREN },
X { "+=", _PLUS_EQUALS },
X { ":", _COLON },
X { ";", _SEMIC },
X { "<", _LANGLE },
X { "<=", _LANGLE_EQUALS },
X { "=", _EQUALS },
X { ">", _RANGLE },
X { ">=", _RANGLE_EQUALS },
X { "?=", _QUESTION_EQUALS },
X { "actions", ACTIONS },
X { "case", CASE },
X { "default", DEFAULT },
X { "else", ELSE },
X { "existing", EXISTING },
X { "for", FOR },
X { "if", IF },
X { "ignore", IGNORE },
X { "in", IN },
X { "include", INCLUDE },
X { "on", ON },
X { "piecemeal", PIECEMEAL },
X { "quietly", QUIETLY },
X { "rule", RULE },
X { "switch", SWITCH },
X { "together", TOGETHER },
X { "updated", UPDATED },
X { "{", _LBRACE },
X { "||", _BARBAR },
X { "}", _RBRACE },
END_OF_FILE
if test 736 -ne `wc -c <'jamgramtab.h'`; then
echo shar: \"'jamgramtab.h'\" unpacked with wrong size!
fi
# end of 'jamgramtab.h'
fi
if test -f 'lists.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'lists.h'\"
else
echo shar: Extracting \"'lists.h'\" \(659 characters\)
sed "s/^X//" >'lists.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * lists.h - the LIST structure and routines to manipulate them


X *
X * 04/13/94 (seiwald) - added shorthand L0 for null list pointer

X * 08/23/94 (seiwald) - new list_append()
X */
X
X/*
X * LIST - list of strings
X */
X
Xtypedef struct _list LIST;
X
Xstruct _list {
X LIST *next;
X LIST *tail; /* only valid in head node */
X char *string; /* private copy */
X} ;
X
XLIST *list_append();
XLIST *list_copy();
XLIST *list_new();
Xvoid list_free();
Xvoid list_print();
XLIST *list_sublist();
X
X# define list_next( l ) ((l)->next)
X
X# define L0 ((LIST *)0)
END_OF_FILE
if test 659 -ne `wc -c <'lists.h'`; then
echo shar: \"'lists.h'\" unpacked with wrong size!
fi
# end of 'lists.h'
fi
if test -f 'make.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'make.h'\"
else
echo shar: Extracting \"'make.h'\" \(221 characters\)
sed "s/^X//" >'make.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * make.h - bring a target up to date, once rules are in place
X */
X
Xvoid make();
Xvoid make1();
END_OF_FILE
if test 221 -ne `wc -c <'make.h'`; then
echo shar: \"'make.h'\" unpacked with wrong size!
fi
# end of 'make.h'
fi
if test -f 'newstr.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'newstr.c'\"
else
echo shar: Extracting \"'newstr.c'\" \(1747 characters\)
sed "s/^X//" >'newstr.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "newstr.h"

X# include "hash.h"
X
X/*

X * newstr.c - string manipulation routines
X *
X * To minimize string copying, string creation, copying, and freeing
X * is done through newstr.
X *
X * External functions:
X *
X * newstr() - return a malloc'ed copy of a string
X * copystr() - return a copy of a string previously returned by newstr()
X * freestr() - free a string returned by newstr() or copystr()
X * donestr() - free string tables
X *
X * Once a string is passed to newstr(), the returned string is readonly.
X *
X * This implementation builds a hash table of all strings, so that multiple
X * calls of newstr() on the same string allocate memory for the string once.
X * Strings are never actually freed.
X */
X
Xtypedef char *STRING;
X
Xstatic struct hash *strhash = 0;
Xstatic int strtotal = 0;
X
X/*
X * newstr() - return a malloc'ed copy of a string
X */
X
Xchar *
Xnewstr( string )
Xchar *string;
X{
X STRING str, *s = &str;
X
X if( !strhash )
X strhash = hashinit( sizeof( STRING ), "strings" );
X
X *s = string;
X
X if( hashenter( strhash, (HASHDATA **)&s ) )
X {
X int l = strlen( string );
X char *m = (char *)malloc( l + 1 );
X
X strtotal += l + 1;
X memcpy( m, string, l + 1 );
X *s = m;
X }
X
X return *s;
X}
X
X/*
X * copystr() - return a copy of a string previously returned by newstr()
X */
X
Xchar *
Xcopystr( s )
Xchar *s;
X{
X return s;
X}
X
X/*
X * freestr() - free a string returned by newstr() or copystr()
X */
X
Xvoid
Xfreestr( s )
Xchar *s;
X{
X}
X
X/*
X * donestr() - free string tables
X */
X
Xvoid
Xdonestr()
X{
X hashdone( strhash );


X
X if( DEBUG_MEM )

X printf( "%dK in strings\n", strtotal / 1024 );
X}
END_OF_FILE
if test 1747 -ne `wc -c <'newstr.c'`; then
echo shar: \"'newstr.c'\" unpacked with wrong size!
fi
# end of 'newstr.c'
fi
if test -f 'newstr.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'newstr.h'\"
else
echo shar: Extracting \"'newstr.h'\" \(224 characters\)
sed "s/^X//" >'newstr.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * newstr.h - string manipulation routines
X */
X
Xchar *newstr();
Xchar *copystr();
Xvoid freestr();
X
END_OF_FILE
if test 224 -ne `wc -c <'newstr.h'`; then
echo shar: \"'newstr.h'\" unpacked with wrong size!
fi
# end of 'newstr.h'
fi
if test -f 'option.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'option.c'\"
else
echo shar: Extracting \"'option.c'\" \(1660 characters\)
sed "s/^X//" >'option.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "option.h"
X

X/*


X * option.c - command line option processing
X *

X * {o >o
X * \<>) "Process command line options as defined in <option.h>.
X * Return the number of argv[] elements used up by options,
X * or -1 if an invalid option flag was given or an argument
X * was supplied for an option that does not require one."
X */
X
Xint
Xgetoptions(argc, argv, opts, optv)
Xchar **argv;
Xchar *opts;
Xoption *optv;
X{
X int i;
X int optc = N_OPTS;
X
X memset( (char *)optv, '\0', sizeof( *optv ) * N_OPTS );
X
X for( i = 0; i < argc; i++ )
X {
X char *arg;
X
X if( argv[i][0] != '-' || !isalpha( argv[i][1] ) )
X break;
X
X if( !optc-- )
X {
X printf( "too many options\n" );


X return -1;
X }
X

X for( arg = &argv[i][1]; *arg; arg++ )
X {
X char *f;
X
X for( f = opts; *f; f++ )
X if( *f == *arg )
X break;
X
X if( !*f )
X {
X printf( "Invalid option: -%c\n", *arg );


X return -1;
X }
X

X optv->flag = *f;
X
X if( f[1] != ':' )
X {
X optv++->val = "true";
X }
X else if( arg[1] )
X {
X optv++->val = &arg[1];
X break;
X }
X else if( ++i < argc )
X {
X optv++->val = argv[i];
X break;
X }
X else
X {
X printf( "option: -%c needs argument\n", *f );


X return -1;
X }
X }

X }
X
X return i;
X}
X
X/*
X * Name: getoptval() - find an option given its character
X */
X
Xchar *
Xgetoptval( optv, opt, subopt )
Xoption *optv;
Xchar opt;
Xint subopt;


X{
X int i;
X

X for( i = 0; i < N_OPTS; i++, optv++ )
X if( optv->flag == opt && !subopt-- )
X return optv->val;


X
X return 0;
X}

END_OF_FILE
if test 1660 -ne `wc -c <'option.c'`; then
echo shar: \"'option.c'\" unpacked with wrong size!
fi
# end of 'option.c'
fi
if test -f 'parse.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'parse.c'\"
else
echo shar: Extracting \"'parse.c'\" \(999 characters\)
sed "s/^X//" >'parse.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "lists.h"
X# include "parse.h"

X# include "newstr.h"
X
X/*

X * parse.c - make and destroy parse trees as driven by the parser

X */
X
XPARSE *
Xparse_make( func, left, right, string, string1, llist, rlist, num )
Xvoid (*func)();
XPARSE *left;
XPARSE *right;
Xchar *string;
Xchar *string1;
XLIST *llist;
XLIST *rlist;
Xint num;
X{
X PARSE *p = (PARSE *)malloc( sizeof( PARSE ) );
X
X p->func = func;
X p->left = left;
X p->right = right;
X p->string = string;
X p->string1 = string1;
X p->llist = llist;
X p->rlist = rlist;
X p->num = num;
X
X return p;
X}
X
Xvoid
Xparse_free( p )
XPARSE *p;
X{
X if( p->string )
X freestr( p->string );
X if( p->string1 )
X freestr( p->string1 );
X if( p->llist )
X list_free( p->llist );
X if( p->rlist )
X list_free( p->rlist );
X if( p->left )
X parse_free( p->left );
X if( p->right )
X parse_free( p->right );
X
X free( (char *)p );
X}
END_OF_FILE
if test 999 -ne `wc -c <'parse.c'`; then
echo shar: \"'parse.c'\" unpacked with wrong size!
fi
# end of 'parse.c'
fi
if test -f 'parse.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'parse.h'\"
else
echo shar: Extracting \"'parse.h'\" \(430 characters\)
sed "s/^X//" >'parse.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * parse.h - make and destroy parse trees as driven by the parser
X */
X
X/*
X * parse tree node
X */
X
Xtypedef struct _PARSE PARSE;
X
Xstruct _PARSE {
X void (*func)();
X PARSE *left;
X PARSE *right;
X char *string;
X char *string1;
X LIST *llist;
X LIST *rlist;
X int num;
X} ;
X
XPARSE *parse_make();
Xvoid parse_free();
END_OF_FILE
if test 430 -ne `wc -c <'parse.h'`; then
echo shar: \"'parse.h'\" unpacked with wrong size!
fi
# end of 'parse.h'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(45 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define VERSION "2"
X#define PATCHLEVEL "0.5"
END_OF_FILE
if test 45 -ne `wc -c <'patchlevel.h'`; then
echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'regexp.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'regexp.h'\"
else
echo shar: Extracting \"'regexp.h'\" \(728 characters\)
sed "s/^X//" >'regexp.h' <<'END_OF_FILE'
X/*
X * Definitions etc. for regexp(3) routines.
X *
X * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
X * not the System V one.
X */
X#define NSUBEXP 10
Xtypedef struct regexp {
X char *startp[NSUBEXP];
X char *endp[NSUBEXP];
X char regstart; /* Internal use only. */
X char reganch; /* Internal use only. */
X char *regmust; /* Internal use only. */
X int regmlen; /* Internal use only. */
X char program[1]; /* Unwarranted chumminess with compiler. */
X} regexp;
X
Xextern regexp *regcomp();
Xextern int regexec();
Xextern void regsub();
Xextern void regerror();
X
X/*
X * The first byte of the regexp internal "program" is actually this magic
X * number; the start node begins in the second byte.
X */
X#define MAGIC 0234
END_OF_FILE
if test 728 -ne `wc -c <'regexp.h'`; then
echo shar: \"'regexp.h'\" unpacked with wrong size!
fi
# end of 'regexp.h'
fi
if test -f 'rules.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'rules.c'\"
else
echo shar: Extracting \"'rules.c'\" \(4841 characters\)
sed "s/^X//" >'rules.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "lists.h"
X# include "parse.h"
X# include "variable.h"

X# include "rules.h"
X# include "newstr.h"

X# include "hash.h"
X
X/*

X * rules.c - access to RULEs, TARGETs, and ACTIONs

X *
X * External routines:
X *

X * bindrule() - return pointer to RULE, creating it if necessary
X * bindtarget() - return pointer to TARGET, creating it if necessary
X * touchtarget() - mark a target to simulate being new
X * targetlist() - turn list of target names into a TARGET chain
X * targetentry() - add a TARGET to a chain of TARGETS
X * actionlist() - append to an ACTION chain
X * addsettings() - add a deferred "set" command to a target
X * usesettings() - set all target specific variables
X * pushsettings() - set all target specific variables
X * popsettings() - reset target specific variables to their pre-push values
X * donerules() - free RULE and TARGET tables
X *


X * 04/12/94 (seiwald) - actionlist() now just appends a single action.

X * 08/23/94 (seiwald) - Support for '+=' (append to variable)

X */
X
Xstatic struct hash *rulehash = 0;
Xstatic struct hash *targethash = 0;
X
X
X/*
X * bindrule() - return pointer to RULE, creating it if necessary
X */
X
XRULE *
Xbindrule( rulename )
Xchar *rulename;
X{
X RULE rule, *r = &rule;
X
X if( !rulehash )
X rulehash = hashinit( sizeof( RULE ), "rules" );
X
X r->name = rulename;
X
X if( hashenter( rulehash, (HASHDATA **)&r ) )
X {
X r->name = newstr( rulename ); /* never freed */
X r->procedure = (PARSE *)0;
X r->actions = (char *)0;
X r->flags = 0;
X }
X
X return r;
X}
X
X/*
X * bindtarget() - return pointer to TARGET, creating it if necessary
X */
X
XTARGET *
Xbindtarget( targetname )
Xchar *targetname;
X{
X TARGET target, *t = &target;
X
X if( !targethash )
X targethash = hashinit( sizeof( TARGET ), "targets" );
X
X t->name = targetname;
X
X if( hashenter( targethash, (HASHDATA **)&t ) )
X {
X memset( (char *)t, '\0', sizeof( *t ) );
X t->name = newstr( targetname ); /* never freed */
X }
X
X return t;
X}
X
X/*
X * touchtarget() - mark a target to simulate being new
X */
X
Xvoid
Xtouchtarget( t )
Xchar *t;
X{
X bindtarget( t )->flags |= T_FLAG_TOUCHED;
X}
X
X/*
X * targetlist() - turn list of target names into a TARGET chain
X *
X * Inputs:
X * chain existing TARGETS to append to
X * targets list of target names
X */
X
XTARGETS *
Xtargetlist( chain, targets )
XTARGETS *chain;


XLIST *targets;
X{
X for( ; targets; targets = list_next( targets ) )

X chain = targetentry( chain, bindtarget( targets->string ) );
X
X return chain;
X}
X
X/*
X * targetentry() - add a TARGET to a chain of TARGETS
X *
X * Inputs:
X * chain exisitng TARGETS to append to
X * target new target to append
X */
X
XTARGETS *
Xtargetentry( chain, target )
XTARGETS *chain;
XTARGET *target;


X{
X TARGETS *c;
X

X c = (TARGETS *)malloc( sizeof( TARGETS ) );
X c->target = target;
X
X if( !chain ) chain = c;
X else chain->tail->next = c;
X chain->tail = c;
X c->next = 0;
X
X return chain;
X}
X
X/*
X * actionlist() - append to an ACTION chain
X */
X
XACTIONS *
Xactionlist( chain, action )
XACTIONS *chain;
XACTION *action;
X{
X ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) );
X
X actions->action = action;
X
X if( !chain ) chain = actions;
X else chain->tail->next = actions;
X chain->tail = actions;
X actions->next = 0;
X
X return chain;
X}
X
X/*
X * addsettings() - add a deferred "set" command to a target
X *
X * Adds a variable setting (varname=list) onto a chain of settings
X * for a particular target. Replaces the previous previous value,
X * if any, unless 'append' says to append the new list onto the old.
X * Returns the head of the chain of settings.
X */
X
XSETTINGS *
Xaddsettings( head, append, symbol, value )
XSETTINGS *head;
Xint append;


Xchar *symbol;
XLIST *value;
X{

X SETTINGS *v;
X
X /* Look for previous setting */
X
X for( v = head; v; v = v->next )
X if( !strcmp( v->symbol, symbol ) )
X break;
X
X /* If not previously set, alloc a new. */
X /* If appending, do so. */
X /* Else free old and set new. */
X
X if( !v )
X {
X v = (SETTINGS *)malloc( sizeof( *v ) );


X v->symbol = newstr( symbol );

X v->value = value;

X v->next = head;
X head = v;
X }
X else if( append )
X {


X v->value = list_append( v->value, value );
X }

X else
X {


X list_free( v->value );
X v->value = value;
X }

X
X /* Return (new) head of list. */
X
X return head;
X}
X
X/*
X * pushsettings() - set all target specific variables
X */
X
Xvoid
Xpushsettings( v )
XSETTINGS *v;
X{
X for( ; v; v = v->next )
X v->value = var_swap( v->symbol, v->value );
X}
X
X/*
X * popsettings() - reset target specific variables to their pre-push values
X */
X
Xvoid
Xpopsettings( v )
XSETTINGS *v;
X{
X pushsettings( v ); /* just swap again */
X}
X
X/*
X * donerules() - free RULE and TARGET tables
X */
X
Xvoid
Xdonerules()
X{
X hashdone( rulehash );
X hashdone( targethash );
X}
END_OF_FILE
if test 4841 -ne `wc -c <'rules.c'`; then
echo shar: \"'rules.c'\" unpacked with wrong size!
fi
# end of 'rules.c'
fi
if test -f 'rules.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'rules.h'\"
else
echo shar: Extracting \"'rules.h'\" \(5225 characters\)
sed "s/^X//" >'rules.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * rules.h - targets, rules, and related information
X *
X * This file describes the structures holding the targets, rules, and
X * related information accumulated by interpreting the statements
X * of the jam files.
X *
X * The following are defined:
X *
X * RULE - a generic jam rule, the product of RULE and ACTIONS
X * ACTIONS - a chain of ACTIONs
X * ACTION - a RULE instance with targets and sources
X * SETTINGS - variables to set when executing a TARGET's ACTIONS
X * TARGETS - a chain of TARGETs
X * TARGET - a file or "thing" that can be built
X *


X * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.

X * 04/12/94 (seiwald) - actionlist() now just appends a single action.

X * 06/01/94 (seiwald) - new 'actions existing' does existing sources

X * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.

X * 01/19/95 (seiwald) - split DONTKNOW into CANTFIND/CANTMAKE.
X * 02/02/95 (seiwald) - new LEAVES modifier on targets.
X * 02/14/95 (seiwald) - new NOUPDATE modifier on targets.
X */
X
Xtypedef struct _rule RULE;
Xtypedef struct _target TARGET;
Xtypedef struct _targets TARGETS;
Xtypedef struct _action ACTION;
Xtypedef struct _actions ACTIONS;
Xtypedef struct _settings SETTINGS ;
X
X/* RULE - a generic jam rule, the product of RULE and ACTIONS */
X
Xstruct _rule {
X char *name;
X PARSE *procedure; /* parse tree from RULE */
X char *actions; /* command string from ACTIONS */
X int flags; /* modifiers on ACTIONS */
X
X# define RULE_NEWSRCS 0x01 /* $(>) is updated sources only */
X# define RULE_TOGETHER 0x02 /* combine actions on single target */
X# define RULE_IGNORE 0x04 /* ignore return status of executes */
X# define RULE_QUIETLY 0x08 /* don't mention it unless verbose */
X# define RULE_PIECEMEAL 0x10 /* split exec so each $(>) is small */
X# define RULE_EXISTING 0x20 /* $(>) is pre-exisitng sources only */
X
X} ;
X
X/* ACTIONS - a chain of ACTIONs */
X
Xstruct _actions {
X ACTIONS *next;
X ACTIONS *tail; /* valid only for head */


X ACTION *action;
X} ;
X

X/* ACTION - a RULE instance with targets and sources */
X
Xstruct _action {
X RULE *rule;
X TARGETS *targets;
X TARGETS *sources; /* aka $(>) */
X char progress; /* see TARGET progress */
X char status; /* see TARGET status */
X} ;
X
X/* SETTINGS - variables to set when executing a TARGET's ACTIONS */
X
Xstruct _settings {
X SETTINGS *next;
X char *symbol; /* symbol name for var_set() */
X LIST *value; /* symbol value for var_set() */
X} ;
X
X/* TARGETS - a chain of TARGETs */
X
Xstruct _targets {
X TARGETS *next;
X TARGETS *tail; /* valid only for head */
X TARGET *target;
X} ;
X
X/* TARGET - a file or "thing" that can be built */
X
Xstruct _target {
X char *name;
X char *boundname; /* if search() relocates target */
X ACTIONS *actions; /* rules to execute, if any */
X SETTINGS *settings; /* variables to define */
X
X char flags; /* status info */
X
X# define T_FLAG_TEMP 0x01 /* TEMPORARY applied */
X# define T_FLAG_NOCARE 0x02 /* NOCARE applied */
X# define T_FLAG_NOTFILE 0x04 /* NOTFILE applied */
X# define T_FLAG_TOUCHED 0x08 /* ALWAYS applied or -t target */
X# define T_FLAG_LEAVES 0x10 /* LEAVES applied */
X# define T_FLAG_NOUPDATE 0x20 /* NOUPDATE applied */
X
X char binding; /* how target relates to real file */
X
X# define T_BIND_UNBOUND 0 /* a disembodied name */
X# define T_BIND_MISSING 1 /* couldn't find real file */
X# define T_BIND_PARENTS 2 /* using parent's timestamp */
X# define T_BIND_EXISTS 3 /* real file, timestamp valid */
X
X TARGETS *deps[2]; /* dependencies */
X
X# define T_DEPS_DEPENDS 0 /* due to DEPENDS */
X# define T_DEPS_INCLUDES 1 /* due to INCLUDES */
X
X time_t time; /* update time */
X time_t leaf; /* update time of leaf sources */
X time_t htime; /* header's time */
X time_t hleaf; /* update time of leaf headers */
X
X char fate; /* make0()'s diagnosis */
X char hfate; /* collected fate for headers */
X
X# define T_FATE_INIT 0 /* nothing done to target */
X# define T_FATE_MAKING 1 /* make0(target) on stack */
X# define T_FATE_STABLE 2 /* target didn't need updating */
X# define T_FATE_TOUCHED 3 /* manually touched with -t */
X /* ...rest mean new target... */
X# define T_FATE_ISTMP 4 /* unneeded temp target oddly present */
X# define T_FATE_MISSING 5 /* is missing, needs updating */
X# define T_FATE_OUTDATED 6 /* is out of date, needs updating */
X# define T_FATE_UPDATE 7 /* deps updated, needs updating */
X# define T_FATE_CANTFIND 8 /* no rules to make missing target */
X# define T_FATE_CANTMAKE 9 /* can't find dependents */
X
X char progress; /* tracks make1() progress */
X
X# define T_MAKE_INIT 0 /* make1(target) not yet called */
X# define T_MAKE_ONSTACK 1 /* make1(target) on stack */
X# define T_MAKE_RUNNING 2 /* make1(target) in execcmd() */
X# define T_MAKE_DONE 3 /* make1(target) done */
X
X char status; /* execcmd() result */
X
X int asynccnt; /* child deps outstanding */
X TARGETS *parents; /* used by make1() for completion */
X char *cmds; /* type-punned command list */
X} ;
X
XRULE *bindrule();
XTARGET *bindtarget();
Xvoid touchtarget();
XTARGETS *targetlist();
XTARGETS *targetentry();
XACTIONS *actionlist();
XSETTINGS *addsettings();
Xvoid pushsettings();
Xvoid popsettings();
END_OF_FILE
if test 5225 -ne `wc -c <'rules.h'`; then
echo shar: \"'rules.h'\" unpacked with wrong size!
fi
# end of 'rules.h'
fi
if test -f 'scan.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'scan.c'\"
else
echo shar: Extracting \"'scan.c'\" \(5129 characters\)
sed "s/^X//" >'scan.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "jamgram.h"


X# include "lists.h"
X# include "parse.h"

X# include "scan.h"


X# include "newstr.h"
X
X/*

X * scan.c - the jam yacc scanner
X *
X * 12/26/93 (seiwald) - bump buf in yylex to 10240 - yuk.
X * 09/16/94 (seiwald) - check for overflows, unmatched {}'s, etc.
X * Also handle tokens abutting EOF by remembering
X * to return EOF now matter how many times yylex()
X * reinvokes yyline().
X * 02/11/95 (seiwald) - honor only punctuation keywords if SCAN_PUNCT.
X */
X
Xstruct keyword {
X char *word;
X int type;
X} keywords[] = {
X# include "jamgramtab.h"
X 0, 0
X} ;
X
X# define MAX_INCLUDES 10
X
Xstatic struct {
X char *string;
X FILE *file;
X char *fname;
X int line;
X char buf[ 512 ];
X} includes[ MAX_INCLUDES ] = {0}, *incp = includes;
X
Xstatic int incdepth = 0;
X
Xstatic int scanmode = SCAN_NORMAL;
X
Xstatic char *symdump();


X
X/*
X */
X

Xvoid
Xyymode( n )
Xint n;
X{
X scanmode = n;
X}
X
Xyyerror( s )
Xchar *s;
X{
X if( incdepth )
X printf( "%s: line %d: ", incp->fname, incp->line );
X
X printf( "%s at %s\n", s, symdump( &yylval ) );
X}
X
Xyyfparse( s )
Xchar *s;
X{
X FILE *f = stdin;
X
X if( incdepth == MAX_INCLUDES )
X {
X printf( "%s: too many levels of nested includes\n", s );
X return;
X }
X
X if( strcmp( s, "-" ) && !( f = fopen( s, "r" ) ) )
X perror( s );
X
X incp = &includes[ incdepth++ ];
X incp->string = "";
X incp->file = f;
X incp->fname = s;
X incp->line = 0;
X}
X
X/*
X * get character routine
X */
X
Xyyline()
X{
Xtop:
X if( incp->file )
X {
X if( fgets( incp->buf, sizeof( incp->buf ), incp->file ) )
X {
X incp->line++;
X incp->string = incp->buf;
X return *incp->string++;
X }
X
X if( incp->file != stdin )
X fclose( incp->file );
X }
X
X /* Last include file? */
X
X if( incdepth <= 1 )
X {
X /* Make sure subsequent calls get EOF, too */
X
X incdepth = 0;
X incp->string = "";
X
X return EOF;
X }
X
X /* Pop to previous include */
X
X incp = &includes[ --incdepth - 1 ];
X
X if( !*incp->string )
X goto top;
X
X return *incp->string++;
X}
X
X/*
X * yylex() - set yylval to current token; return its type
X */
X
X# define yychar() ( *incp->string ? *incp->string++ : yyline() )
X
Xyylex()
X{
X int c = *incp->string;
X char buf[10240];
X
X for( ;; )
X {
X /* Skip past the "" that yyfparse() points incp->string at. */
X
X if( !c )
X c = yychar();
X
X /* Skip past white space */
X
X while( c != EOF && isspace( c ) )
X c = yychar();
X
X /* Not a comment? Swallow up comment line. */
X
X if( c != '#' )
X break;
X while( ( c = yychar() ) != EOF && c != '\n' )
X ;
X }
X
X /* c now points to the first character of a token. */
X
X if( c == EOF )
X {
X goto eof;
X }
X else if( c == '{' && scanmode == SCAN_STRING )
X {
X /* look for closing { */
X
X char *b = buf;
X int nest = 1;
X
X while( ( c = yychar() ) != EOF && b < buf + sizeof( buf ) )
X {
X if( c == '{' )
X nest++;
X else if( c == '}' )
X nest--;
X if( !nest )
X break;
X *b++ = c;
X }
X
X /* Check obvious errors. */
X
X if( b == buf + sizeof( buf ) )
X {
X yyerror( "action block too big" );
X goto eof;
X }
X
X if( nest )
X {
X yyerror( "unmatched {} in action block" );
X goto eof;
X }
X
X *b = 0;
X yylval.type = STRING;
X yylval.string = newstr( buf );
X }
X else
X {
X /* look for white space to delimit word */
X /* "'s get stripped but preserve white space */
X
X char *b = buf;
X int inquote = 0;
X int literal = 0;
X int hasquote = 0;
X struct keyword *k;
X
X while( b < buf + sizeof( buf ) )
X {
X if( literal )
X *b++ = c, literal = 0;
X else if( c == '\\' )
X literal++;
X else if( c == '"' )
X inquote = !inquote, hasquote++;
X else
X *b++ = c;
X
X if( ( c = yychar() ) == EOF || !inquote && isspace( c ) )
X break;
X }
X
X /* Check obvious errors. */
X
X if( b == buf + sizeof( buf ) )
X {
X yyerror( "string too big" );
X goto eof;
X }
X
X if( inquote )
X {
X yyerror( "unmatched \" in string" );
X goto eof;
X }
X
X /* We looked ahead a character - back up. */
X
X incp->string--;
X
X /* scan token table */
X /* don't scan if it's "anything", $anything, */
X /* or an alphabetic when were looking for punctuation */
X
X *b = 0;
X yylval.type = ARG;
X
X if( !hasquote &&
X *buf != '$' &&
X !( isalpha( *buf ) && scanmode == SCAN_PUNCT ) )
X {
X for( k = keywords; k->word; k++ )
X if( *buf == *k->word && !strcmp( k->word, buf ) )
X {
X yylval.type = k->type;
X yylval.string = k->word; /* used by symdump */


X break;
X }
X }
X

X if( yylval.type == ARG )
X yylval.string = newstr( buf );
X }
X
X if( DEBUG_SCAN )
X printf( "scan %s\n", symdump( &yylval ) );
X
X return yylval.type;
X
Xeof:
X yylval.type = EOF;
X return yylval.type;
X}
X
Xstatic char *
Xsymdump( s )
XYYSTYPE *s;
X{
X static char buf[ 512 ];
X
X switch( s->type )
X {
X case EOF:
X sprintf( buf, "EOF" );
X break;
X case 0:
X sprintf( buf, "unknown symbol %s", s->string );
X break;
X case ARG:
X sprintf( buf, "argument %s", s->string );
X break;
X case STRING:
X sprintf( buf, "string \"%s\"", s->string );
X break;
X default:
X sprintf( buf, "keyword %s", s->string );
X break;
X }
X return buf;
X}
END_OF_FILE
if test 5129 -ne `wc -c <'scan.c'`; then
echo shar: \"'scan.c'\" unpacked with wrong size!
fi
# end of 'scan.c'
fi
if test -f 'scan.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'scan.h'\"
else
echo shar: Extracting \"'scan.h'\" \(562 characters\)
sed "s/^X//" >'scan.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * scan.h - the jam yacc scanner
X */
X
X/*
X * needed by parser, scanner
X */
X
X# define YYSTYPE YYSYMBOL
X
Xtypedef struct _YYSTYPE {
X int type;
X char *string;
X PARSE *parse;
X LIST *list;
X int number;
X} YYSTYPE;
X
Xextern YYSTYPE yylval;
X
Xvoid yymode(); /* adjust lexicon of scanner */
X
X# define SCAN_NORMAL 0 /* normal parsing */
X# define SCAN_STRING 1 /* look only for matching } */
X# define SCAN_PUNCT 2 /* only punctuation keywords */
END_OF_FILE
if test 562 -ne `wc -c <'scan.h'`; then
echo shar: \"'scan.h'\" unpacked with wrong size!
fi
# end of 'scan.h'
fi
if test -f 'search.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'search.c'\"
else
echo shar: Extracting \"'search.c'\" \(1514 characters\)
sed "s/^X//" >'search.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "lists.h"

X# include "search.h"
X# include "timestamp.h"
X# include "filesys.h"
X# include "variable.h"


X# include "newstr.h"
X
X/*

X * search.c - find a target along $(SEARCH) or $(LOCATE)

X */
X
Xchar *
Xsearch( target, time )
Xchar *target;
Xtime_t *time;
X{
X FILENAME f[1];
X LIST *varlist;


X char buf[ MAXPATH ];
X

X /* Parse the filename */
X
X file_parse( target, f );
X
X f->f_grist.ptr = 0;
X f->f_grist.len = 0;
X
X if( varlist = var_get( "LOCATE" ) )
X {
X f->f_root.ptr = varlist->string;
X f->f_root.len = strlen( varlist->string );
X
X file_build( f, buf );
X
X if( DEBUG_SEARCH )
X printf( "locate %s: %s\n", target, buf );
X
X timestamp( buf, time );
X
X return newstr( buf );
X }
X else if( varlist = var_get( "SEARCH" ) )
X {
X while( varlist )
X {
X f->f_root.ptr = varlist->string;
X f->f_root.len = strlen( varlist->string );
X
X file_build( f, buf );
X
X if( DEBUG_SEARCH )
X printf( "search %s: %s\n", target, buf );
X
X timestamp( buf, time );
X
X if( *time )
X return newstr( buf );
X
X varlist = list_next( varlist );
X }
X }
X
X /* Look for the obvious */
X /* This is a questionable move. Should we look in the */
X /* obvious place if SEARCH is set? */
X
X f->f_root.ptr = 0;
X f->f_root.len = 0;
X
X file_build( f, buf );
X
X if( DEBUG_SEARCH )
X printf( "search %s: %s\n", target, buf );
X
X timestamp( target, time );
X
X return newstr( buf );
X}
END_OF_FILE
if test 1514 -ne `wc -c <'search.c'`; then
echo shar: \"'search.c'\" unpacked with wrong size!
fi
# end of 'search.c'
fi
if test -f 'search.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'search.h'\"
else
echo shar: Extracting \"'search.h'\" \(205 characters\)
sed "s/^X//" >'search.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * search.h - find a target along $(SEARCH) or $(LOCATE)
X */
X
Xchar *search();
END_OF_FILE
if test 205 -ne `wc -c <'search.h'`; then
echo shar: \"'search.h'\" unpacked with wrong size!
fi
# end of 'search.h'
fi
if test -f 'timestamp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'timestamp.c'\"
else
echo shar: Extracting \"'timestamp.c'\" \(3478 characters\)
sed "s/^X//" >'timestamp.c' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X# include "jam.h"
X# include "hash.h"

X# include "filesys.h"
X# include "timestamp.h"


X# include "newstr.h"
X
X/*

X * timestamp.c - get the timestamp of a file or archive member

X */
X
X/*
X * BINDING - all known files
X */
X
Xtypedef struct _binding BINDING;
X
Xstruct _binding {
X char *name;
X short flags;
X
X# define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
X
X short progress;
X
X# define BIND_INIT 0 /* never seen */
X# define BIND_NOENTRY 1 /* timestamp requested but file never found */
X# define BIND_SPOTTED 2 /* file found but not timed yet */
X# define BIND_MISSING 3 /* file found but can't get timestamp */
X# define BIND_FOUND 4 /* file found and time stamped */
X
X time_t time; /* update time - 0 if not exist */
X} ;
X
Xstatic struct hash *bindhash = 0;
Xstatic void time_enter();
X
Xstatic char *time_progress[] =
X{
X "INIT",
X "NOENTRY",
X "SPOTTED",
X "MISSING",
X "FOUND"
X} ;
X
X
X/*
X * timestamp() - return timestamp on a file, if present
X */
X
Xvoid
Xtimestamp( target, time )
Xchar *target;
Xtime_t *time;
X{
X FILENAME f1, f2;
X BINDING binding, *b = &binding;


X char buf[ MAXPATH ];
X

X if( !bindhash )
X bindhash = hashinit( sizeof( BINDING ), "bindings" );
X
X /* Quick path - is it there? */
X
X b->name = target;
X b->time = b->flags = 0;
X b->progress = BIND_INIT;
X
X if( hashenter( bindhash, (HASHDATA **)&b ) )
X b->name = newstr( target ); /* never freed */
X
X if( b->progress != BIND_INIT )
X goto afterscanning;
X
X b->progress = BIND_NOENTRY;
X
X /* Not found - have to scan for it */
X
X file_parse( target, &f1 );
X memset( (char *)&f2, '\0', sizeof( f2 ) );
X
X /* Scan directory if not already done so */
X
X {
X BINDING binding, *b = &binding;
X
X f2.f_dir = f1.f_dir;
X file_build( &f2, buf );
X
X b->name = buf;
X b->time = b->flags = 0;
X b->progress = BIND_INIT;
X
X if( hashenter( bindhash, (HASHDATA **)&b ) )
X b->name = newstr( buf ); /* never freed */
X
X if( !( b->flags & BIND_SCANNED ) )
X {
X file_dirscan( buf, time_enter );
X b->flags |= BIND_SCANNED;
X }
X }
X
X /* Scan archive if not already done so */
X
X if( f1.f_member.len )
X {
X BINDING binding, *b = &binding;
X
X f2.f_base = f1.f_base;
X f2.f_suffix = f1.f_suffix;
X file_build( &f2, buf );
X
X b->name = buf;
X b->time = b->flags = 0;
X b->progress = BIND_INIT;
X
X if( hashenter( bindhash, (HASHDATA **)&b ) )
X b->name = newstr( buf ); /* never freed */
X
X if( !( b->flags & BIND_SCANNED ) )
X {
X file_archscan( buf, time_enter );
X b->flags |= BIND_SCANNED;
X }
X }
X
X afterscanning:
X
X if( b->progress == BIND_SPOTTED )
X {
X if( file_time( b->name, &b->time ) < 0 )
X b->progress = BIND_MISSING;
X else
X b->progress = BIND_FOUND;
X }
X
X *time = b->progress == BIND_FOUND ? b->time : 0;
X
X if( DEBUG_BIND && b->progress == BIND_FOUND )
X {
X printf( "time ( %s ) : %s", target, ctime( time ) );
X }
X}
X
Xstatic void
Xtime_enter( target, found, time )
Xchar *target;
Xint found;
Xtime_t time;
X{
X BINDING binding, *b = &binding;
X
X b->name = target;
X b->flags = 0;
X
X if( hashenter( bindhash, (HASHDATA **)&b ) )
X b->name = newstr( target ); /* never freed */
X
X b->time = time;
X b->progress = found ? BIND_FOUND : BIND_SPOTTED;


X
X if( DEBUG_BINDSCAN )

X printf( "time ( %s ) : %s\n", target, time_progress[b->progress] );
X}
X
X/*
X * donestamps() - free timestamp tables
X */
X
Xvoid
Xdonestamps()
X{
X hashdone( bindhash );
X}
END_OF_FILE
if test 3478 -ne `wc -c <'timestamp.c'`; then
echo shar: \"'timestamp.c'\" unpacked with wrong size!
fi
# end of 'timestamp.c'
fi
if test -f 'timestamp.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'timestamp.h'\"
else
echo shar: Extracting \"'timestamp.h'\" \(213 characters\)
sed "s/^X//" >'timestamp.h' <<'END_OF_FILE'


X/*
X * Copyright 1993, 1995 Christopher Seiwald.
X *
X * This file is part of Jam - see jam.c for Copyright information.
X */
X

X/*
X * timestamp.h - get the timestamp of a file or archive member
X */
X
Xvoid timestamp();
X
END_OF_FILE
if test 213 -ne `wc -c <'timestamp.h'`; then
echo shar: \"'timestamp.h'\" unpacked with wrong size!
fi
# end of 'timestamp.h'
fi
echo shar: End of archive 7 \(of 7\).
cp /dev/null ark7isdone

0 new messages