summaryrefslogtreecommitdiff
path: root/tools/build/v2/engine
diff options
context:
space:
mode:
Diffstat (limited to 'tools/build/v2/engine')
-rw-r--r--tools/build/v2/engine/build.bat42
-rw-r--r--tools/build/v2/engine/build.jam109
-rwxr-xr-xtools/build/v2/engine/build.sh6
-rw-r--r--tools/build/v2/engine/build_vms.com105
-rw-r--r--tools/build/v2/engine/builtins.c924
-rw-r--r--tools/build/v2/engine/builtins.h81
-rw-r--r--tools/build/v2/engine/class.c96
-rw-r--r--tools/build/v2/engine/class.h3
-rw-r--r--tools/build/v2/engine/command.c34
-rw-r--r--tools/build/v2/engine/command.h11
-rw-r--r--tools/build/v2/engine/compile.c1163
-rw-r--r--tools/build/v2/engine/compile.h29
-rw-r--r--tools/build/v2/engine/constants.c183
-rw-r--r--tools/build/v2/engine/constants.h72
-rw-r--r--tools/build/v2/engine/debug.c35
-rw-r--r--tools/build/v2/engine/debug.h9
-rw-r--r--tools/build/v2/engine/execcmd.h10
-rw-r--r--tools/build/v2/engine/execmac.c69
-rw-r--r--tools/build/v2/engine/execnt.c65
-rw-r--r--tools/build/v2/engine/execunix.c34
-rw-r--r--tools/build/v2/engine/execvms.c161
-rw-r--r--tools/build/v2/engine/expand.c733
-rw-r--r--tools/build/v2/engine/expand.h14
-rw-r--r--tools/build/v2/engine/filemac.c175
-rw-r--r--tools/build/v2/engine/filent.c96
-rw-r--r--tools/build/v2/engine/fileos2.c138
-rw-r--r--tools/build/v2/engine/filesys.c52
-rw-r--r--tools/build/v2/engine/filesys.h21
-rw-r--r--tools/build/v2/engine/fileunix.c84
-rw-r--r--tools/build/v2/engine/filevms.c327
-rw-r--r--tools/build/v2/engine/frames.c3
-rw-r--r--tools/build/v2/engine/frames.h14
-rw-r--r--tools/build/v2/engine/function.c4553
-rw-r--r--tools/build/v2/engine/function.h46
-rw-r--r--tools/build/v2/engine/glob.c10
-rw-r--r--tools/build/v2/engine/hash.c333
-rw-r--r--tools/build/v2/engine/hash.h65
-rw-r--r--tools/build/v2/engine/hcache.c334
-rw-r--r--tools/build/v2/engine/hcache.h6
-rw-r--r--tools/build/v2/engine/hdrmacro.c49
-rw-r--r--tools/build/v2/engine/hdrmacro.h7
-rw-r--r--tools/build/v2/engine/headers.c61
-rw-r--r--tools/build/v2/engine/headers.h13
-rw-r--r--tools/build/v2/engine/jam.c182
-rw-r--r--tools/build/v2/engine/jam.h83
-rw-r--r--tools/build/v2/engine/jamgram.c1687
-rw-r--r--tools/build/v2/engine/jamgram.h47
-rw-r--r--tools/build/v2/engine/jamgram.y52
-rw-r--r--tools/build/v2/engine/jamgram.yy50
-rw-r--r--tools/build/v2/engine/lists.c397
-rw-r--r--tools/build/v2/engine/lists.h50
-rw-r--r--tools/build/v2/engine/make.c95
-rw-r--r--tools/build/v2/engine/make.h14
-rw-r--r--tools/build/v2/engine/make1.c249
-rw-r--r--tools/build/v2/engine/modules.c394
-rw-r--r--tools/build/v2/engine/modules.h42
-rw-r--r--tools/build/v2/engine/modules/order.c41
-rw-r--r--tools/build/v2/engine/modules/path.c10
-rw-r--r--tools/build/v2/engine/modules/property-set.c39
-rw-r--r--tools/build/v2/engine/modules/regex.c24
-rw-r--r--tools/build/v2/engine/modules/sequence.c23
-rw-r--r--tools/build/v2/engine/modules/set.c14
-rw-r--r--tools/build/v2/engine/native.c47
-rw-r--r--tools/build/v2/engine/native.h13
-rw-r--r--tools/build/v2/engine/newstr.c174
-rw-r--r--tools/build/v2/engine/newstr.h14
-rw-r--r--tools/build/v2/engine/object.c379
-rw-r--r--tools/build/v2/engine/object.h43
-rw-r--r--tools/build/v2/engine/output.c14
-rw-r--r--tools/build/v2/engine/output.h7
-rw-r--r--tools/build/v2/engine/parse.c44
-rw-r--r--tools/build/v2/engine/parse.h47
-rw-r--r--tools/build/v2/engine/patchlevel.h8
-rw-r--r--tools/build/v2/engine/pathmac.c252
-rw-r--r--tools/build/v2/engine/pathsys.h34
-rw-r--r--tools/build/v2/engine/pathunix.c338
-rw-r--r--tools/build/v2/engine/pathvms.c406
-rw-r--r--tools/build/v2/engine/pwd.c20
-rw-r--r--tools/build/v2/engine/pwd.h3
-rw-r--r--tools/build/v2/engine/regexp.c32
-rw-r--r--tools/build/v2/engine/regexp.h10
-rw-r--r--tools/build/v2/engine/rules.c350
-rw-r--r--tools/build/v2/engine/rules.h67
-rw-r--r--tools/build/v2/engine/scan.c41
-rw-r--r--tools/build/v2/engine/scan.h21
-rw-r--r--tools/build/v2/engine/search.c145
-rw-r--r--tools/build/v2/engine/search.h11
-rw-r--r--tools/build/v2/engine/subst.c57
-rw-r--r--tools/build/v2/engine/timestamp.c141
-rw-r--r--tools/build/v2/engine/timestamp.h10
-rw-r--r--tools/build/v2/engine/variable.c460
-rw-r--r--tools/build/v2/engine/variable.h23
-rw-r--r--tools/build/v2/engine/w32_getreg.c34
93 files changed, 9878 insertions, 7235 deletions
diff --git a/tools/build/v2/engine/build.bat b/tools/build/v2/engine/build.bat
index f927b7697c..2982fb9c93 100644
--- a/tools/build/v2/engine/build.bat
+++ b/tools/build/v2/engine/build.bat
@@ -28,7 +28,7 @@ ECHO ### You can specify the toolset as the argument, i.e.:
ECHO ### .\build.bat msvc
ECHO ###
ECHO ### Toolsets supported by this script are: borland, como, gcc, gcc-nocygwin,
-ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10
+ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10, vc11
ECHO ###
call :Set_Error
endlocal
@@ -101,6 +101,16 @@ call :Test_Empty %ProgramFiles%
if not errorlevel 1 set ProgramFiles=C:\Program Files
call :Clear_Error
+if NOT "_%VS110COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET=vc11"
+ set "BOOST_JAM_TOOLSET_ROOT=%VS110COMNTOOLS%..\..\VC\"
+ goto :eof)
+call :Clear_Error
+if EXIST "%ProgramFiles%\Microsoft Visual Studio 11.0\VC\VCVARSALL.BAT" (
+ set "BOOST_JAM_TOOLSET=vc11"
+ set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio 11.0\VC\"
+ goto :eof)
+call :Clear_Error
if NOT "_%VS100COMNTOOLS%_" == "__" (
set "BOOST_JAM_TOOLSET=vc10"
set "BOOST_JAM_TOOLSET_ROOT=%VS100COMNTOOLS%..\..\VC\"
@@ -371,6 +381,21 @@ set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0"
set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
set "_known_=1"
:Skip_VC10
+if NOT "_%BOOST_JAM_TOOLSET%_" == "_vc11_" goto Skip_VC11
+if NOT "_%VS110COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET_ROOT=%VS110COMNTOOLS%..\..\VC\"
+ )
+if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%VCVARSALL.BAT" %BOOST_JAM_ARGS%
+if NOT "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
+ if "_%VCINSTALLDIR%_" == "__" (
+ set "PATH=%BOOST_JAM_TOOLSET_ROOT%bin;%PATH%"
+ ) )
+set "BOOST_JAM_CC=cl /nologo /RTC1 /Zi /MTd /Fobootstrap/ /Fdbootstrap/ -DNT -DYYDEBUG -wd4996 kernel32.lib advapi32.lib user32.lib"
+set "BOOST_JAM_OPT_JAM=/Febootstrap\jam0"
+set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0"
+set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
+set "_known_=1"
+:Skip_VC11
if NOT "_%BOOST_JAM_TOOLSET%_" == "_borland_" goto Skip_BORLAND
if "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
call :Test_Path bcc32.exe )
@@ -438,9 +463,9 @@ echo ###
set YYACC_SOURCES=yyacc.c
set MKJAMBASE_SOURCES=mkjambase.c
set BJAM_SOURCES=
-set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c debug.c execnt.c expand.c filent.c glob.c hash.c
+set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c constants.c debug.c execnt.c filent.c function.c glob.c hash.c
set BJAM_SOURCES=%BJAM_SOURCES% hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c
-set BJAM_SOURCES=%BJAM_SOURCES% newstr.c option.c output.c parse.c pathunix.c regexp.c
+set BJAM_SOURCES=%BJAM_SOURCES% object.c option.c output.c parse.c pathunix.c regexp.c
set BJAM_SOURCES=%BJAM_SOURCES% rules.c scan.c search.c subst.c timestamp.c variable.c modules.c
set BJAM_SOURCES=%BJAM_SOURCES% strings.c filesys.c builtins.c md5.c pwd.c class.c w32_getreg.c native.c
set BJAM_SOURCES=%BJAM_SOURCES% modules/set.c modules/path.c modules/regex.c
@@ -457,10 +482,13 @@ set test=###%test%###
set test=%test:"###=%
set test=%test:###"=%
set test=%test:###=%
-if "%test%" == "--update" set BJAM_UPDATE=update
+if "%test%" == "--update" goto Found_Update
endlocal
shift
if not "_%BJAM_UPDATE%_" == "_update_" goto Check_Update
+:Found_Update
+endlocal
+set BJAM_UPDATE=update
:Check_Update_End
if "_%BJAM_UPDATE%_" == "_update_" (
if not exist ".\bootstrap\jam0.exe" (
@@ -506,9 +534,6 @@ rename y.tab.h jamgram.h
%BOOST_JAM_CC% %BOOST_JAM_OPT_JAM% %BJAM_SOURCES%
:Skip_Bootstrap
@if not exist ".\bootstrap\jam0.exe" goto Skip_Jam
-@if "_%BJAM_UPDATE%_" == "_update_" goto Skip_Clean
-.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " clean
-:Skip_Clean
@set args=%*
@echo OFF
:Set_Args
@@ -526,6 +551,9 @@ set args=%args:~1%
goto Set_Args
:Set_Args_End
@echo ON
+@if "_%BJAM_UPDATE%_" == "_update_" goto Skip_Clean
+.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " %args% clean
+:Skip_Clean
.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " %args%
:Skip_Jam
diff --git a/tools/build/v2/engine/build.jam b/tools/build/v2/engine/build.jam
index 266b07a17d..1efc3f1f0b 100644
--- a/tools/build/v2/engine/build.jam
+++ b/tools/build/v2/engine/build.jam
@@ -18,12 +18,9 @@ for local v in ARGV CC CFLAGS LIBS
# Platform related specifics.
if $(OS) = NT { rule .path { return "$(<:J=\\)" ; } ./ = "/" ; }
-else if $(OS) = OS2 { rule .path { return "$(<:J=\\)" ; } ./ = "/" ; }
-else if $(OS) = VMS { rule .path { return "[.$(<:J=/)]" ; } }
-else if $(OS) = MAC { rule .path { return ":$(<:J=\:)" ; } }
else { rule .path { return "$(<:J=/)" ; } }
-if $(OS) = VMS { . = "_" ; }
-else { . = "." ; }
+
+. = "." ;
./ ?= "" ;
# Info about what we are building.
@@ -71,7 +68,7 @@ if $(with-python)
{
--python-include = [ .path $(python-location) include ] ;
--python-lib = ;
- for local v in 26 25 24 23 22
+ for local v in 27 26 25 24 23 22
{
--python-lib ?=
[ GLOB [ .path $(python-location) libs ] : "python$(v).lib" ]
@@ -94,7 +91,7 @@ if $(with-python)
{
--python-include = ;
--python-lib = ;
- for local v in 2.6 2.5 2.4 2.3 2.2
+ for local v in 2.7 2.6 2.5 2.4 2.3 2.2
{
local inc = [ GLOB [ .path $(python-location) include ] : python$(v) ] ;
local lib = [ GLOB [ .path $(python-location) lib ] : libpython$(v)* ] ;
@@ -214,6 +211,7 @@ toolset gcc gcc : "-o " : -D
: -pedantic -fno-strict-aliasing
[ opt --release : [ opt --symbols : -g : -s ] -O3 ]
[ opt --debug : -g -O0 -fno-inline ]
+ [ opt --profile : -O3 -g -pg ]
-I$(--python-include) -I$(--extra-include) -Wno-long-long
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
## GCC 2.x, 3.x on CYGWIN but without cygwin1.dll
@@ -319,14 +317,14 @@ toolset pgi pgcc : "-o " : -D
## Sun Workshop 6 C++
toolset sun cc : "-o " : -D
:
- [ opt --release : -s -fast -xO4 ]
+ [ opt --release : -s -xO3 ]
[ opt --debug : -g ]
-I$(--python-include) -I$(--extra-include)
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
## Sun Workshop 6 C++ (old alias)
toolset sunpro cc : "-o " : -D
:
- [ opt --release : -s -fast -xO4 ]
+ [ opt --release : -s -xO3 ]
[ opt --debug : -g ]
-I$(--python-include) -I$(--extra-include)
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
@@ -372,18 +370,13 @@ toolset vc10 cl : /Fe /Fe /Fd /Fo : -D
[ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
-I$(--python-include) -I$(--extra-include)
: kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
-## VMS/OpenVMS DEC C
-toolset vmsdecc cc : /OBJECT= : "/DEFINES=(" "," ")"
- : /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
- [ opt --release : /OPTIMIZE /NODEBUG ]
- [ opt --debug : /NOOPTIMIZE /DEBUG ]
- ;
-toolset vmsdecc link .link : /EXECUTABLE= :
- : /NOMAP
- [ opt --release : /NODEBUG ]
- [ opt --debug : /DEBUG ]
- ;
-
+toolset vc11 cl : /Fe /Fe /Fd /Fo : -D
+ : /nologo
+ [ opt --release : /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ]
+ [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
+ -I$(--python-include) -I$(--extra-include)
+ : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
+
# First set the build commands and options according to the
# preset toolset.
toolset = [ MATCH --toolset=(.*) : $(ARGV) ] ;
@@ -454,17 +447,7 @@ if $(tool.$(toolset).link.cc)
# Put executables in platform-specific subdirectory.
locate-target = $(LOCATE_TARGET) ;
-if $(OS) = VMS
-{
- locate-target ?= bin$(.)vms ;
- platform = vms ;
-}
-else if $(OS) = MAC
-{
- locate-target ?= bin$(.)$(OS:L)$(OSPLAT:L) ;
- platform = $(OS:L)$(OSPLAT:L) ;
-}
-else if $(OSPLAT)
+if $(OSPLAT)
{
locate-target ?= bin$(.)$(OS:L)$(OSPLAT:L) ;
platform = $(OS:L)$(OSPLAT:L) ;
@@ -492,12 +475,12 @@ if --show-locate-target in $(ARGV)
ECHO $(locate-target) ;
}
-# We have some different files for UNIX, VMS, and NT.
+# We have some different files for UNIX, and NT.
jam.source =
- command.c compile.c debug.c expand.c glob.c
+ command.c compile.c constants.c debug.c function.c glob.c
hash.c hcache.c headers.c hdrmacro.c
jam.c jambase.c jamgram.c
- lists.c make.c make1.c mem.c newstr.c
+ lists.c make.c make1.c mem.c object.c
option.c output.c parse.c regexp.c rules.c
scan.c search.c subst.c w32_getreg.c
timestamp.c variable.c modules.c strings.c filesys.c
@@ -509,18 +492,6 @@ if $(OS) = NT
{
jam.source += execnt.c filent.c pathunix.c ;
}
-else if $(OS) = OS2
-{
- jam.source += execunix.c fileos2.c pathunix.c ;
-}
-else if $(OS) = VMS
-{
- jam.source += execvms.c filevms.c pathvms.c ;
-}
-else if $(OS) = MAC
-{
- jam.source += execmac.c filemac.c pathmac.c ;
-}
else
{
jam.source += execunix.c fileunix.c pathunix.c ;
@@ -565,10 +536,6 @@ if ( $(OS) = NT ) && ! NT in $(--defs)
{
--defs += NT ;
}
-if $(OS) = VMS
-{
- --defs += VMS ;
-}
--defs += YYSTACKSIZE=5000 ;
if $(with-python)
@@ -597,18 +564,12 @@ if $(OS) = NT { actions piecemeal together existing [DELETE] {
if $(UNIX) = true { actions piecemeal together existing [DELETE] {
rm -f "$(>)"
} }
-if $(OS) = VMS { actions piecemeal together existing [DELETE] {
- DELETE $(>[--2]:J=";*, ") $(>[-1]);*
-} }
if $(OS) = NT {
--chmod+w = "attrib -r " ;
}
if $(UNIX) = true {
--chmod+w = "chmod +w " ;
}
-if $(OS) = VMS {
- --chmod+w = "SET FILE/PROT=(S:RWED) " ;
-}
rule .mkdir
{
@@ -622,14 +583,11 @@ if $(OS) = NT { actions [MKDIR] {
if $(UNIX) = true { actions [MKDIR] {
mkdir "$(<)"
} }
-if $(OS) = VMS { actions [MKDIR] {
- CREATE/DIR $(<J=", ")
-} }
rule .exe
{
local exe = $(<) ;
- if $(OS) = NT || ( $(UNIX) = true && $(OS) = CYGWIN ) || $(OS) = VMS { exe = $(exe:S=.exe) ; }
+ if $(OS) = NT || ( $(UNIX) = true && $(OS) = CYGWIN ) { exe = $(exe:S=.exe) ; }
LOCATE on $(exe) = $(locate-target) ;
DEPENDS all : $(exe) ;
.mkdir $(locate-target) ;
@@ -665,18 +623,16 @@ rule .exe
return $(exe) ;
}
if ! $(--def[2]) { actions [COMPILE] {
- "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def)$(--defs)" "$(--flags)" "$(--libs)" "$(>)"
+ "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def)$(--defs)" "$(--flags)" "$(>)" "$(--libs)"
} }
else { actions [COMPILE] {
- "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def[1])$(--defs:J=$(--def[2]))$(--def[3])" "$(--flags)" "$(--libs)" "$(>)"
-} }
-if $(OS) = VMS { actions [COMPILE.LINK] {
- "$(--link)" $(--link-bin)$(<:D=) $(--link-dir)$(<:D)$(./) $(--link-out)$(<) $(--link-def)$(--link-defs) $(--link-flags) "$(--link-libs)" $(>J=", ")
-} }
-else { actions [COMPILE.LINK] {
- "$(--link)" "$(--link-bin)$(<:D=)" "$(--link-dir)$(<:D)$(./)" "$(--link-out)$(<)" "$(--link-def)$(--link-defs)" "$(--link-flags)" "$(--link-libs)" "$(>)"
+ "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def[1])$(--defs:J=$(--def[2]))$(--def[3])" "$(--flags)" "$(>)" "$(--libs)"
} }
+actions [COMPILE.LINK] {
+ "$(--link)" "$(--link-bin)$(<:D=)" "$(--link-dir)$(<:D)$(./)" "$(--link-out)$(<)" "$(--link-def)$(--link-defs)" "$(--link-flags)" "$(>)" "$(--link-libs)"
+}
+
rule .link
{
DEPENDS all : $(<) ;
@@ -690,9 +646,6 @@ if $(OS) = NT { actions [LINK] {
if $(UNIX) = true { actions [LINK] {
ln -fs "$(>)" "$(<)"
} }
-if $(OS) = VMS { actions [LINK] {
- COPY/REPLACE $(>) $(<)
-} }
rule .copy
{
@@ -720,9 +673,6 @@ if $(OS) = NT { actions [MOVE] {
if $(UNIX) = true { actions [MOVE] {
mv -f "$(>)" "$(<)"
} }
-if $(OS) = VMS { actions [MOVE] {
- RENAME "$(>)" "$(<)"
-} }
# Generate the grammar tokens table, and the real yacc grammar.
rule .yyacc
@@ -796,13 +746,6 @@ if $(UNIX) = true { actions [YACC] {
exit 1
fi
} }
-if $(OS) = VMS { actions [YACC] {
- IF "$(yacc)" $(>)
- THEN
- RENAME y_tab$(<[1]:S) $(<[1])
- RENAME y_tab$(<[2]:S) $(<[2])
- ENDIF
-} }
if $(grammar) && ! $(yacc)
{
EXIT "Could not find the 'yacc' tool, and therefore can not build the grammar." ;
@@ -888,7 +831,7 @@ dist.source =
dist.source = $(dist.source:D=)
$(dist.license[1])
$(dist.docs)
- build.jam build.bat build.sh build_vms.com
+ build.jam build.bat build.sh
Jambase
jamgram.y jamgram.yy
[ .path modules set.c ]
diff --git a/tools/build/v2/engine/build.sh b/tools/build/v2/engine/build.sh
index f1fb806d3c..e3a4498b7a 100755
--- a/tools/build/v2/engine/build.sh
+++ b/tools/build/v2/engine/build.sh
@@ -245,9 +245,9 @@ echo "###"
YYACC_SOURCES="yyacc.c"
MKJAMBASE_SOURCES="mkjambase.c"
BJAM_SOURCES="\
- command.c compile.c debug.c expand.c glob.c hash.c\
+ command.c compile.c constants.c debug.c function.c glob.c hash.c\
hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c\
- newstr.c option.c output.c parse.c pathunix.c pathvms.c regexp.c\
+ object.c option.c output.c parse.c pathunix.c regexp.c\
rules.c scan.c search.c subst.c timestamp.c variable.c modules.c\
strings.c filesys.c builtins.c pwd.c class.c native.c md5.c w32_getreg.c\
modules/set.c modules/path.c modules/regex.c modules/property-set.c\
@@ -297,7 +297,7 @@ if test "${BJAM_UPDATE}" != "update" ; then
fi
if test -x "./bootstrap/jam0" ; then
if test "${BJAM_UPDATE}" != "update" ; then
- echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" clean
+ echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" "$@" clean
fi
echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" "$@"
fi
diff --git a/tools/build/v2/engine/build_vms.com b/tools/build/v2/engine/build_vms.com
deleted file mode 100644
index 965b634247..0000000000
--- a/tools/build/v2/engine/build_vms.com
+++ /dev/null
@@ -1,105 +0,0 @@
-$ ! Copyright 2002-2003 Rene Rivera, Johan Nilsson.
-$ ! Distributed under the Boost Software License, Version 1.0.
-$ ! (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-$ !
-$ ! bootstrap build script for Jam
-$ !
-$ SAY :== WRITE SYS$OUTPUT
-$ !
-$ ON WARNING THEN CONTINUE
-$ !
-$ IF "" .NES. F$SEARCH("[.bootstrap_vms]*.*")
-$ THEN
-$ SAY "Cleaning previous boostrap files..."
-$ !
-$ SET FILE/PROTECTION=(S:RWED) [.bootstrap_vms]*.*;*
-$ DELETE [.bootstrap_vms]*.*;*
-$ ENDIF
-$ !
-$ IF "" .NES. F$SEARCH("bootstrap_vms.dir")
-$ THEN
-$ SAY "Removing previous boostrap directory..."
-$ !
-$ SET FILE/PROT=(S:RWED) bootstrap_vms.dir
-$ DELETE bootstrap_vms.dir;
-$ ENDIF
-$ !
-$ SAY "Creating boostrap directory..."
-$ !
-$ CREATE/DIR [.bootstrap_vms]
-$ !
-$ SAY "Building bootstrap jam..."
-$ !
-$ CC_FLAGS = "/DEFINE=VMS /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES "
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]builtins.obj builtins.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]command.obj command.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]compile.obj compile.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]execvms.obj execvms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]expand.obj expand.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]filesys.obj filesys.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]filevms.obj filevms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]glob.obj glob.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]hash.obj hash.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]hdrmacro.obj hdrmacro.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]headers.obj headers.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jam.obj jam.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jambase.obj jambase.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jamgram.obj jamgram.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]lists.obj lists.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]make.obj make.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]make1.obj make1.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]modules.obj modules.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]newstr.obj newstr.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]option.obj option.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]parse.obj parse.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]pathvms.obj pathvms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]pwd.obj pwd.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]regexp.obj regexp.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]rules.obj rules.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]scan.obj scan.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]search.obj search.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]strings.obj strings.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]subst.obj subst.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]timestamp.obj timestamp.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]variable.obj variable.c
-$ link -
- /EXECUTABLE=[.bootstrap_vms]jam0.exe -
- [.bootstrap_vms]builtins.obj, -
- [.bootstrap_vms]command.obj, -
- [.bootstrap_vms]compile.obj, -
- [.bootstrap_vms]execvms.obj, -
- [.bootstrap_vms]expand.obj, -
- [.bootstrap_vms]filesys.obj, -
- [.bootstrap_vms]filevms.obj, -
- [.bootstrap_vms]glob.obj, -
- [.bootstrap_vms]hash.obj, -
- [.bootstrap_vms]hdrmacro.obj, -
- [.bootstrap_vms]headers.obj, -
- [.bootstrap_vms]jam.obj, -
- [.bootstrap_vms]jambase.obj, -
- [.bootstrap_vms]jamgram.obj, -
- [.bootstrap_vms]lists.obj, -
- [.bootstrap_vms]make.obj, -
- [.bootstrap_vms]make1.obj, -
- [.bootstrap_vms]modules.obj, -
- [.bootstrap_vms]newstr.obj, -
- [.bootstrap_vms]option.obj, -
- [.bootstrap_vms]parse.obj, -
- [.bootstrap_vms]pathvms.obj, -
- [.bootstrap_vms]pwd.obj, -
- [.bootstrap_vms]regexp.obj, -
- [.bootstrap_vms]rules.obj, -
- [.bootstrap_vms]scan.obj, -
- [.bootstrap_vms]search.obj, -
- [.bootstrap_vms]strings.obj, -
- [.bootstrap_vms]subst.obj, -
- [.bootstrap_vms]timestamp.obj, -
- [.bootstrap_vms]variable.obj
-$ !
-$ SAY "Cleaning any previous build..."
-$ !
-$ MCR [.bootstrap_vms]jam0.exe -f build.jam --toolset=vmsdecc clean
-$ !
-$ SAY "Building Boost.Jam..."
-$ !
-$ MCR [.bootstrap_vms]jam0.exe -f build.jam --toolset=vmsdecc
diff --git a/tools/build/v2/engine/builtins.c b/tools/build/v2/engine/builtins.c
index b28a484ec4..07eaa1534a 100644
--- a/tools/build/v2/engine/builtins.c
+++ b/tools/build/v2/engine/builtins.c
@@ -11,7 +11,7 @@
#include "builtins.h"
#include "rules.h"
#include "filesys.h"
-#include "newstr.h"
+#include "object.h"
#include "regexp.h"
#include "frames.h"
#include "hash.h"
@@ -25,6 +25,7 @@
#include "variable.h"
#include "timestamp.h"
#include "md5.h"
+#include "constants.h"
#include <ctype.h>
#if defined(USE_EXECUNIX)
@@ -65,38 +66,44 @@
*/
#define P0 (PARSE *)0
-#define C0 (char *)0
+#define C0 (OBJECT *)0
#if defined( OS_NT ) || defined( OS_CYGWIN )
- LIST * builtin_system_registry ( PARSE *, FRAME * );
- LIST * builtin_system_registry_names( PARSE *, FRAME * );
+ LIST * builtin_system_registry ( FRAME *, int );
+ LIST * builtin_system_registry_names( FRAME *, int );
#endif
-int glob( char * s, char * c );
+int glob( const char * s, const char * c );
void backtrace ( FRAME * );
void backtrace_line ( FRAME * );
-void print_source_line( PARSE * );
+void print_source_line( FRAME * );
-RULE * bind_builtin( char * name, LIST * (* f)( PARSE *, FRAME * ), int flags, char * * args )
+RULE * bind_builtin( const char * name_, LIST * (* f)( FRAME *, int flags ), int flags, const char * * args )
{
- argument_list* arg_list = 0;
+ FUNCTION * func;
+ RULE * result;
+ OBJECT * name = object_new( name_ );
- if ( args )
- {
- arg_list = args_new();
- lol_build( arg_list->data, args );
- }
+ func = function_builtin( f, flags, args );
+
+ result = new_rule_body( root_module(), name, func, 1 );
+
+ function_free( func );
+
+ object_free( name );
- return new_rule_body( root_module(), name, arg_list,
- parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
+ return result;
}
-RULE * duplicate_rule( char * name, RULE * other )
+RULE * duplicate_rule( const char * name_, RULE * other )
{
- return import_rule( other, root_module(), name );
+ OBJECT * name = object_new( name_ );
+ RULE * result = import_rule( other, root_module(), name );
+ object_free( name );
+ return result;
}
@@ -116,7 +123,7 @@ void load_builtins()
builtin_echo, 0, 0 ) ) );
{
- char * args[] = { "message", "*", ":", "result-value", "?", 0 };
+ const char * args[] = { "message", "*", ":", "result-value", "?", 0 };
duplicate_rule( "exit",
duplicate_rule( "Exit",
bind_builtin( "EXIT",
@@ -124,13 +131,13 @@ void load_builtins()
}
{
- char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
+ const char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
duplicate_rule( "Glob",
bind_builtin( "GLOB", builtin_glob, 0, args ) );
}
{
- char * args[] = { "patterns", "*", 0 };
+ const char * args[] = { "patterns", "*", 0 };
bind_builtin( "GLOB-RECURSIVELY",
builtin_glob_recursive, 0, args );
}
@@ -140,7 +147,7 @@ void load_builtins()
builtin_depends, 1, 0 ) );
{
- char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
+ const char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
bind_builtin( "REBUILDS",
builtin_rebuilds, 0, args );
}
@@ -154,7 +161,7 @@ void load_builtins()
builtin_match, 0, 0 ) );
{
- char * args[] = { "string", ":", "delimiters" };
+ const char * args[] = { "string", ":", "delimiters" };
bind_builtin( "SPLIT_BY_CHARACTERS",
builtin_split_by_characters, 0, 0 );
}
@@ -194,13 +201,13 @@ void load_builtins()
builtin_flags, T_FLAG_RMOLD, 0 );
{
- char * args[] = { "targets", "*", 0 };
+ const char * args[] = { "targets", "*", 0 };
bind_builtin( "UPDATE",
builtin_update, 0, args );
}
{
- char * args[] = { "targets", "*",
+ const char * args[] = { "targets", "*",
":", "log", "?",
":", "ignore-minus-n", "?",
":", "ignore-minus-q", "?", 0 };
@@ -209,33 +216,33 @@ void load_builtins()
}
{
- char * args[] = { "string", "pattern", "replacements", "+", 0 };
+ const char * args[] = { "string", "pattern", "replacements", "+", 0 };
duplicate_rule( "subst",
bind_builtin( "SUBST",
builtin_subst, 0, args ) );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "RULENAMES",
builtin_rulenames, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "VARNAMES",
builtin_varnames, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "DELETE_MODULE",
builtin_delete_module, 0, args );
}
{
- char * args[] = { "source_module", "?",
+ const char * args[] = { "source_module", "?",
":", "source_rules", "*",
":", "target_module", "?",
":", "target_rules", "*",
@@ -245,104 +252,98 @@ void load_builtins()
}
{
- char * args[] = { "module", "?", ":", "rules", "*", 0 };
+ const char * args[] = { "module", "?", ":", "rules", "*", 0 };
bind_builtin( "EXPORT",
builtin_export, 0, args );
}
{
- char * args[] = { "levels", "?", 0 };
+ const char * args[] = { "levels", "?", 0 };
bind_builtin( "CALLER_MODULE",
builtin_caller_module, 0, args );
}
{
- char * args[] = { "levels", "?", 0 };
+ const char * args[] = { "levels", "?", 0 };
bind_builtin( "BACKTRACE",
builtin_backtrace, 0, args );
}
{
- char * args[] = { 0 };
+ const char * args[] = { 0 };
bind_builtin( "PWD",
builtin_pwd, 0, args );
}
{
- char * args[] = { "target", "*", ":", "path", "*", 0 };
- bind_builtin( "SEARCH_FOR_TARGET",
- builtin_search_for_target, 0, args );
- }
-
- {
- char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
+ const char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
bind_builtin( "IMPORT_MODULE",
builtin_import_module, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "IMPORTED_MODULES",
builtin_imported_modules, 0, args );
}
{
- char * args[] = { "instance_module", ":", "class_module", 0 };
+ const char * args[] = { "instance_module", ":", "class_module", 0 };
bind_builtin( "INSTANCE",
builtin_instance, 0, args );
}
{
- char * args[] = { "sequence", "*", 0 };
+ const char * args[] = { "sequence", "*", 0 };
bind_builtin( "SORT",
builtin_sort, 0, args );
}
{
- char * args[] = { "path_parts", "*", 0 };
+ const char * args[] = { "path_parts", "*", 0 };
bind_builtin( "NORMALIZE_PATH",
builtin_normalize_path, 0, args );
}
{
- char * args[] = { "args", "*", 0 };
+ const char * args[] = { "args", "*", 0 };
bind_builtin( "CALC",
builtin_calc, 0, args );
}
{
- char * args[] = { "module", ":", "rule", 0 };
+ const char * args[] = { "module", ":", "rule", 0 };
bind_builtin( "NATIVE_RULE",
builtin_native_rule, 0, args );
}
{
- char * args[] = { "module", ":", "rule", ":", "version", 0 };
+ const char * args[] = { "module", ":", "rule", ":", "version", 0 };
bind_builtin( "HAS_NATIVE_RULE",
builtin_has_native_rule, 0, args );
}
{
- char * args[] = { "module", "*", 0 };
+ const char * args[] = { "module", "*", 0 };
bind_builtin( "USER_MODULE",
builtin_user_module, 0, args );
}
{
- char * args[] = { 0 };
+ const char * args[] = { 0 };
bind_builtin( "NEAREST_USER_LOCATION",
builtin_nearest_user_location, 0, args );
}
{
- char * args[] = { "file", 0 };
+ const char * args[] = { "file", 0 };
bind_builtin( "CHECK_IF_FILE",
builtin_check_if_file, 0, args );
}
#ifdef HAVE_PYTHON
{
- char * args[] = { "python-module", ":", "function", ":",
+ const char * args[] = { "python-module", ":", "function", ":",
"jam-module", ":", "rule-name", 0 };
bind_builtin( "PYTHON_IMPORT_RULE",
builtin_python_import_rule, 0, args );
@@ -351,56 +352,56 @@ void load_builtins()
# if defined( OS_NT ) || defined( OS_CYGWIN )
{
- char * args[] = { "key_path", ":", "data", "?", 0 };
+ const char * args[] = { "key_path", ":", "data", "?", 0 };
bind_builtin( "W32_GETREG",
builtin_system_registry, 0, args );
}
{
- char * args[] = { "key_path", ":", "result-type", 0 };
+ const char * args[] = { "key_path", ":", "result-type", 0 };
bind_builtin( "W32_GETREGNAMES",
builtin_system_registry_names, 0, args );
}
# endif
{
- char * args[] = { "command", ":", "*", 0 };
+ const char * args[] = { "command", ":", "*", 0 };
duplicate_rule( "SHELL",
bind_builtin( "COMMAND",
builtin_shell, 0, args ) );
}
{
- char * args[] = { "string", 0 };
+ const char * args[] = { "string", 0 };
bind_builtin( "MD5",
builtin_md5, 0, args ) ;
}
{
- char * args[] = { "name", ":", "mode", 0 };
+ const char * args[] = { "name", ":", "mode", 0 };
bind_builtin( "FILE_OPEN",
builtin_file_open, 0, args );
}
{
- char * args[] = { "string", ":", "width", 0 };
+ const char * args[] = { "string", ":", "width", 0 };
bind_builtin( "PAD",
builtin_pad, 0, args );
}
{
- char * args[] = { "targets", "*", 0 };
+ const char * args[] = { "targets", "*", 0 };
bind_builtin( "PRECIOUS",
builtin_precious, 0, args );
}
{
- char * args [] = { 0 };
+ const char * args [] = { 0 };
bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
}
{
- char * args [] = { "path", 0 };
+ const char * args [] = { "path", 0 };
bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
}
@@ -420,11 +421,11 @@ void load_builtins()
* The CALC rule performs simple mathematical operations on two arguments.
*/
-LIST * builtin_calc( PARSE * parse, FRAME * frame )
+LIST * builtin_calc( FRAME * frame, int flags )
{
LIST * arg = lol_get( frame->args, 0 );
- LIST * result = 0;
+ LIST * result = L0;
long lhs_value;
long rhs_value;
long result_value;
@@ -432,17 +433,18 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
char const * lhs;
char const * op;
char const * rhs;
+ LISTITER iter = list_begin( arg ), end = list_end( arg );
- if ( arg == 0 ) return L0;
- lhs = arg->string;
+ if ( iter == end ) return L0;
+ lhs = object_str( list_item( iter ) );
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- op = arg->string;
+ iter = list_next( iter );
+ if ( iter == end ) return L0;
+ op = object_str( list_item( iter ) );
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- rhs = arg->string;
+ iter = list_next( iter );
+ if ( iter == end ) return L0;
+ rhs = object_str( list_item( iter ) );
lhs_value = atoi( lhs );
rhs_value = atoi( rhs );
@@ -461,7 +463,7 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
}
sprintf( buffer, "%ld", result_value );
- result = list_new( result, newstr( buffer ) );
+ result = list_push_back( result, object_new( buffer ) );
return result;
}
@@ -474,21 +476,22 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
* targets and sources as TARGETs.
*/
-LIST * builtin_depends( PARSE * parse, FRAME * frame )
+LIST * builtin_depends( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * sources = lol_get( frame->args, 1 );
- LIST * l;
-
- for ( l = targets; l; l = list_next( l ) )
+ LISTITER iter, end;
+
+ iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* If doing INCLUDES, switch to the TARGET's include */
/* TARGET, creating it if needed. The internal include */
/* TARGET shares the name of its parent. */
- if ( parse->num )
+ if ( flags )
{
if ( !t->includes )
{
@@ -502,9 +505,10 @@ LIST * builtin_depends( PARSE * parse, FRAME * frame )
}
/* Enter reverse links */
- for ( l = sources; l; l = list_next( l ) )
+ iter = list_begin( sources ), end = list_end( sources );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * s = bindtarget( l->string );
+ TARGET * s = bindtarget( list_item( iter ) );
s->dependants = targetlist( s->dependants, targets );
}
@@ -520,15 +524,15 @@ LIST * builtin_depends( PARSE * parse, FRAME * frame )
* argument.
*/
-LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
+LIST * builtin_rebuilds( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * rebuilds = lol_get( frame->args, 1 );
- LIST * l;
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
- for ( l = targets; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
t->rebuilds = targetlist( t->rebuilds, rebuilds );
}
@@ -543,7 +547,7 @@ LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
* taken.
*/
-LIST * builtin_echo( PARSE * parse, FRAME * frame )
+LIST * builtin_echo( FRAME * frame, int flags )
{
list_print( lol_get( frame->args, 0 ) );
printf( "\n" );
@@ -559,13 +563,14 @@ LIST * builtin_echo( PARSE * parse, FRAME * frame )
* with a failure status.
*/
-LIST * builtin_exit( PARSE * parse, FRAME * frame )
+LIST * builtin_exit( FRAME * frame, int flags )
{
+ LIST * code = lol_get( frame->args, 1 );
list_print( lol_get( frame->args, 0 ) );
printf( "\n" );
- if ( lol_get( frame->args, 1 ) )
+ if ( !list_empty( code ) )
{
- exit( atoi( lol_get( frame->args, 1 )->string ) );
+ exit( atoi( object_str( list_front( code ) ) ) );
}
else
{
@@ -582,11 +587,12 @@ LIST * builtin_exit( PARSE * parse, FRAME * frame )
* It binds each target as a TARGET.
*/
-LIST * builtin_flags( PARSE * parse, FRAME * frame )
+LIST * builtin_flags( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = list_next( l ) )
- bindtarget( l->string )->flags |= parse->num;
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ bindtarget( list_item( iter ) )->flags |= flags;
return L0;
}
@@ -612,10 +618,10 @@ static void downcase_inplace( char * p )
static void builtin_glob_back
(
- void * closure,
- char * file,
- int status,
- time_t time
+ void * closure,
+ OBJECT * file,
+ int status,
+ time_t time
)
{
PROFILE_ENTER( BUILTIN_GLOB_BACK );
@@ -624,15 +630,16 @@ static void builtin_glob_back
LIST * l;
PATHNAME f;
string buf[ 1 ];
+ LISTITER iter, end;
/* Null out directory for matching. We wish we had file_dirscan() pass up a
* PATHNAME.
*/
- path_parse( file, &f );
+ path_parse( object_str( file ), &f );
f.f_dir.len = 0;
/* For globbing, we unconditionally ignore current and parent directory
- * items. Since they items always exist, there is no reason why caller of
+ * items. Since these items always exist, there is no reason why caller of
* GLOB would want to see them. We could also change file_dirscan(), but
* then paths with embedded "." and ".." would not work anywhere.
*/
@@ -648,11 +655,12 @@ static void builtin_glob_back
if ( globbing->case_insensitive )
downcase_inplace( buf->value );
- for ( l = globbing->patterns; l; l = l->next )
+ iter = list_begin( globbing->patterns ), end = list_end( globbing->patterns );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- if ( !glob( l->string, buf->value ) )
+ if ( !glob( object_str( list_item( iter ) ), buf->value ) )
{
- globbing->results = list_new( globbing->results, newstr( file ) );
+ globbing->results = list_push_back( globbing->results, object_copy( file ) );
break;
}
}
@@ -665,17 +673,18 @@ static void builtin_glob_back
static LIST * downcase_list( LIST * in )
{
- LIST * result = 0;
+ LIST * result = L0;
+ LISTITER iter = list_begin( in ), end = list_end( in );
string s[ 1 ];
string_new( s );
- while ( in )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- string_copy( s, in->string );
+ string_append( s, object_str( list_item( iter ) ) );
downcase_inplace( s->value );
- result = list_append( result, list_new( 0, newstr( s->value ) ) );
- in = in->next;
+ result = list_push_back( result, object_new( s->value ) );
+ string_truncate( s, 0 );
}
string_free( s );
@@ -683,11 +692,12 @@ static LIST * downcase_list( LIST * in )
}
-LIST * builtin_glob( PARSE * parse, FRAME * frame )
+LIST * builtin_glob( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
LIST * r = lol_get( frame->args, 1 );
+ LISTITER iter, end;
struct globbing globbing;
globbing.results = L0;
@@ -703,8 +713,9 @@ LIST * builtin_glob( PARSE * parse, FRAME * frame )
if ( globbing.case_insensitive )
globbing.patterns = downcase_list( r );
- for ( ; l; l = list_next( l ) )
- file_dirscan( l->string, builtin_glob_back, &globbing );
+ iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ file_dirscan( list_item( iter ), builtin_glob_back, &globbing );
if ( globbing.case_insensitive )
list_free( globbing.patterns );
@@ -724,19 +735,19 @@ static int has_wildcards( char const * str )
* If 'file' exists, append 'file' to 'list'. Returns 'list'.
*/
-static LIST * append_if_exists( LIST * list, char * file )
+static LIST * append_if_exists( LIST * list, OBJECT * file )
{
time_t time;
timestamp( file, &time );
return time > 0
- ? list_new( list, newstr( file ) )
+ ? list_push_back( list, object_copy( file ) )
: list;
}
-LIST * glob1( char * dirname, char * pattern )
+LIST * glob1( OBJECT * dirname, OBJECT * pattern )
{
- LIST * plist = list_new( L0, pattern );
+ LIST * plist = list_new( object_copy(pattern) );
struct globbing globbing;
globbing.results = L0;
@@ -763,7 +774,7 @@ LIST * glob1( char * dirname, char * pattern )
}
-LIST * glob_recursive( char * pattern )
+LIST * glob_recursive( const char * pattern )
{
LIST * result = L0;
@@ -771,7 +782,9 @@ LIST * glob_recursive( char * pattern )
if ( !has_wildcards( pattern ) )
{
/* No metacharacters. Check if the path exists. */
- result = append_if_exists(result, pattern);
+ OBJECT * p = object_new( pattern );
+ result = append_if_exists( result, p );
+ object_free( p );
}
else
{
@@ -798,27 +811,35 @@ LIST * glob_recursive( char * pattern )
dirs = has_wildcards( dirname->value )
? glob_recursive( dirname->value )
- : list_new( dirs, dirname->value );
+ : list_push_back( dirs, object_new( dirname->value ) );
if ( has_wildcards( basename->value ) )
{
- for ( ; dirs; dirs = dirs->next )
- result = list_append( result, glob1( dirs->string,
- basename->value ) );
+ OBJECT * b = object_new( basename->value );
+ LISTITER iter = list_begin( dirs ), end = list_end( dirs );
+ for ( ; iter != end; iter = list_next( iter ) )
+ result = list_append( result, glob1( list_item( iter ), b ) );
+ object_free( b );
}
else
{
+ LISTITER iter = list_begin( dirs ), end = list_end( dirs );
string file_string[ 1 ];
string_new( file_string );
/* No wildcard in basename. */
- for ( ; dirs; dirs = dirs->next )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- path->f_dir.ptr = dirs->string;
- path->f_dir.len = strlen( dirs->string );
+ OBJECT * p;
+ path->f_dir.ptr = object_str( list_item( iter ) );
+ path->f_dir.len = strlen( object_str( list_item( iter ) ) );
path_build( path, file_string, 0 );
- result = append_if_exists( result, file_string->value );
+ p = object_new( file_string->value );
+
+ result = append_if_exists( result, p );
+
+ object_free( p );
string_truncate( file_string, 0 );
}
@@ -828,11 +849,15 @@ LIST * glob_recursive( char * pattern )
string_free( dirname );
string_free( basename );
+
+ list_free( dirs );
}
else
{
/** No directory, just a pattern. */
- result = list_append( result, glob1( ".", pattern ) );
+ OBJECT * p = object_new( pattern );
+ result = list_append( result, glob1( constant_dot, p ) );
+ object_free( p );
}
}
@@ -840,12 +865,13 @@ LIST * glob_recursive( char * pattern )
}
-LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
+LIST * builtin_glob_recursive( FRAME * frame, int flags )
{
LIST * result = L0;
LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = l->next )
- result = list_append( result, glob_recursive( l->string ) );
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ result = list_append( result, glob_recursive( object_str( list_item( iter ) ) ) );
return result;
}
@@ -854,26 +880,31 @@ LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
* builtin_match() - MATCH rule, regexp matching.
*/
-LIST * builtin_match( PARSE * parse, FRAME * frame )
+LIST * builtin_match( FRAME * frame, int flags )
{
LIST * l;
LIST * r;
- LIST * result = 0;
+ LIST * result = L0;
+ LISTITER l_iter, l_end, r_iter, r_end;
string buf[ 1 ];
string_new( buf );
/* For each pattern */
- for ( l = lol_get( frame->args, 0 ); l; l = l->next )
+ l = lol_get( frame->args, 0 );
+ l_iter = list_begin( l ), l_end = list_end( l );
+ for (; l_iter != l_end; l_iter = list_next( l_iter ) )
{
/* Result is cached and intentionally never freed. */
- regexp * re = regex_compile( l->string );
+ regexp * re = regex_compile( list_item( l_iter ) );
/* For each string to match against. */
- for ( r = lol_get( frame->args, 1 ); r; r = r->next )
+ r = lol_get( frame->args, 1 );
+ r_iter = list_begin( r ), r_end = list_end( r );
+ for ( ; r_iter != r_end; r_iter = list_next( r_iter ) )
{
- if ( regexec( re, r->string ) )
+ if ( regexec( re, object_str( list_item( r_iter ) ) ) )
{
int i;
int top;
@@ -889,7 +920,7 @@ LIST * builtin_match( PARSE * parse, FRAME * frame )
for ( i = 1; i <= top; ++i )
{
string_append_range( buf, re->startp[ i ], re->endp[ i ] );
- result = list_new( result, newstr( buf->value ) );
+ result = list_push_back( result, object_new( buf->value ) );
string_truncate( buf, 0 );
}
}
@@ -900,41 +931,45 @@ LIST * builtin_match( PARSE * parse, FRAME * frame )
return result;
}
-LIST * builtin_split_by_characters( PARSE * parse, FRAME * frame )
+LIST * builtin_split_by_characters( FRAME * frame, int flags )
{
LIST * l1 = lol_get( frame->args, 0 );
LIST * l2 = lol_get( frame->args, 1 );
- LIST * result = 0;
+ LIST * result = L0;
+
+ string buf[ 1 ];
- char* s = strdup (l1->string);
- char* delimiters = l2->string;
- char* t;
+ const char * delimiters = object_str( list_front( l2 ) );
+ char * t;
- t = strtok (s, delimiters);
- while (t)
+ string_copy( buf, object_str( list_front( l1 ) ) );
+
+ t = strtok( buf->value, delimiters) ;
+ while ( t )
{
- result = list_new(result, newstr(t));
- t = strtok (NULL, delimiters);
+ result = list_push_back( result, object_new( t ) );
+ t = strtok( NULL, delimiters );
}
- free (s);
+ string_free( buf );
return result;
}
-LIST * builtin_hdrmacro( PARSE * parse, FRAME * frame )
+LIST * builtin_hdrmacro( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for ( ; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* Scan file for header filename macro definitions. */
if ( DEBUG_HEADER )
printf( "scanning '%s' for header file macro definitions\n",
- l->string );
+ object_str( list_item( iter ) ) );
macro_headers( t );
}
@@ -955,15 +990,15 @@ static void add_rule_name( void * r_, void * result_ )
RULE * r = (RULE *)r_;
LIST * * result = (LIST * *)result_;
if ( r->exported )
- *result = list_new( *result, copystr( r->name ) );
+ *result = list_push_back( *result, object_copy( r->name ) );
}
-LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
+LIST * builtin_rulenames( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 );
if ( source_module->rules )
hashenumerate( source_module->rules, add_rule_name, &result );
@@ -984,36 +1019,17 @@ LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
static void add_hash_key( void * np, void * result_ )
{
LIST * * result = (LIST * *)result_;
- *result = list_new( *result, copystr( *(char * *)np ) );
+ *result = list_push_back( *result, object_copy( *(OBJECT * *)np ) );
}
-static struct hash * get_running_module_vars()
-{
- struct hash * dummy;
- struct hash * vars = NULL;
- /* Get the global variables pointer (that of the currently running module).
- */
- var_hash_swap( &vars );
- dummy = vars;
- /* Put the global variables pointer in its right place. */
- var_hash_swap( &dummy );
- return vars;
-}
-
-
-LIST * builtin_varnames( PARSE * parse, FRAME * frame )
+LIST * builtin_varnames( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
- /* The running module _always_ has its 'variables' member set to NULL due to
- * the way enter_module() and var_hash_swap() work.
- */
- struct hash * vars = source_module == frame->module
- ? get_running_module_vars()
- : source_module->variables;
+ struct hash * vars = source_module->variables;
if ( vars )
hashenumerate( vars, add_hash_key, &result );
@@ -1027,20 +1043,28 @@ LIST * builtin_varnames( PARSE * parse, FRAME * frame )
* Clears all rules and variables from the given module.
*/
-LIST * builtin_delete_module( PARSE * parse, FRAME * frame )
+LIST * builtin_delete_module( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
delete_module( source_module );
return result;
}
-static void unknown_rule( FRAME * frame, char * key, char * module_name, char * rule_name )
+static void unknown_rule( FRAME * frame, const char * key, module_t * module, OBJECT * rule_name )
{
+ const char * module_name = module->name ? object_str( module->name ) : "";
backtrace_line( frame->prev );
- printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
+ if ( module->name )
+ {
+ printf( "%s error: rule \"%s\" unknown in module \"%s.\"\n", key, object_str( rule_name ), object_str( module->name ) );
+ }
+ else
+ {
+ printf( "%s error: rule \"%s\" unknown in module \"\"\n", key, object_str( rule_name ) );
+ }
backtrace( frame->prev );
exit( 1 );
}
@@ -1067,7 +1091,7 @@ static void unknown_rule( FRAME * frame, char * key, char * module_name, char *
* variables.
*/
-LIST * builtin_import( PARSE * parse, FRAME * frame )
+LIST * builtin_import( FRAME * frame, int flags )
{
LIST * source_module_list = lol_get( frame->args, 0 );
LIST * source_rules = lol_get( frame->args, 1 );
@@ -1076,37 +1100,35 @@ LIST * builtin_import( PARSE * parse, FRAME * frame )
LIST * localize = lol_get( frame->args, 4 );
module_t * target_module =
- bindmodule( target_module_list ? target_module_list->string : 0 );
+ bindmodule( !list_empty( target_module_list ) ? list_front( target_module_list ) : 0 );
module_t * source_module =
- bindmodule( source_module_list ? source_module_list->string : 0 );
+ bindmodule( !list_empty( source_module_list ) ? list_front( source_module_list ) : 0 );
- LIST * source_name;
- LIST * target_name;
+ LISTITER source_iter = list_begin( source_rules ), source_end = list_end( source_rules );
+ LISTITER target_iter = list_begin( target_rules ), target_end = list_end( target_rules );
- for ( source_name = source_rules, target_name = target_rules;
- source_name && target_name;
- source_name = list_next( source_name ),
- target_name = list_next( target_name ) )
+ for ( ;
+ source_iter != source_end && target_iter != target_end;
+ source_iter = list_next( source_iter ),
+ target_iter = list_next( target_iter ) )
{
- RULE r_;
- RULE * r = &r_;
+ RULE * r;
RULE * imported;
- r_.name = source_name->string;
if ( !source_module->rules ||
- !hashcheck( source_module->rules, (HASHDATA * *)&r ) )
- unknown_rule( frame, "IMPORT", source_module->name, r_.name );
+ !(r = (RULE *)hash_find( source_module->rules, list_item( source_iter ) ) ) )
+ unknown_rule( frame, "IMPORT", source_module, list_item( source_iter ) );
- imported = import_rule( r, target_module, target_name->string );
- if ( localize )
- imported->module = target_module;
+ imported = import_rule( r, target_module, list_item( target_iter ) );
+ if ( !list_empty( localize ) )
+ rule_localize( imported, target_module );
/* This rule is really part of some other module. Just refer to it here,
* but do not let it out.
*/
imported->exported = 0;
}
- if ( source_name || target_name )
+ if ( source_iter != source_end || target_iter != target_end )
{
backtrace_line( frame->prev );
printf( "import error: length of source and target rule name lists don't match!\n" );
@@ -1131,20 +1153,19 @@ LIST * builtin_import( PARSE * parse, FRAME * frame )
* is issued.
*/
-LIST * builtin_export( PARSE * parse, FRAME * frame )
+LIST * builtin_export( FRAME * frame, int flags )
{
LIST * module_list = lol_get( frame->args, 0 );
LIST * rules = lol_get( frame->args, 1 );
- module_t * m = bindmodule( module_list ? module_list->string : 0 );
+ module_t * m = bindmodule( !list_empty( module_list ) ? list_front( module_list ) : 0 );
- for ( ; rules; rules = list_next( rules ) )
+ LISTITER iter = list_begin( rules ), end = list_end( rules );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- RULE r_;
- RULE * r = &r_;
- r_.name = rules->string;
+ RULE * r;
- if ( !m->rules || !hashcheck( m->rules, (HASHDATA * *)&r ) )
- unknown_rule( frame, "EXPORT", m->name, r_.name );
+ if ( !m->rules || !(r = (RULE *)hash_find( m->rules, list_item( iter ) ) ) )
+ unknown_rule( frame, "EXPORT", m, list_item( iter ) );
r->exported = 1;
}
@@ -1157,12 +1178,12 @@ LIST * builtin_export( PARSE * parse, FRAME * frame )
* indicated for a given procedure in debug output or an error backtrace.
*/
-static void get_source_line( PARSE * procedure, char * * file, int * line )
+static void get_source_line( FRAME * frame, const char * * file, int * line )
{
- if ( procedure )
+ if ( frame->file )
{
- char * f = procedure->file;
- int l = procedure->line;
+ const char * f = object_str( frame->file );
+ int l = frame->line;
if ( !strcmp( f, "+" ) )
{
f = "jambase.c";
@@ -1179,12 +1200,12 @@ static void get_source_line( PARSE * procedure, char * * file, int * line )
}
-void print_source_line( PARSE * p )
+void print_source_line( FRAME * frame )
{
- char * file;
+ const char * file;
int line;
- get_source_line( p, &file, &line );
+ get_source_line( frame, &file, &line );
if ( line < 0 )
printf( "(builtin):" );
else
@@ -1205,7 +1226,7 @@ void backtrace_line( FRAME * frame )
}
else
{
- print_source_line( frame->procedure );
+ print_source_line( frame );
printf( " in %s\n", frame->rulename );
}
}
@@ -1231,23 +1252,31 @@ void backtrace( FRAME * frame )
* period.
*/
-LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
+LIST * builtin_backtrace( FRAME * frame, int flags )
{
LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : ( (unsigned int)(-1) >> 1 ) ;
+ int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : (int)( (unsigned int)(-1) >> 1 ) ;
LIST * result = L0;
for ( ; ( frame = frame->prev ) && levels ; --levels )
{
- char * file;
+ const char * file;
int line;
char buf[32];
- get_source_line( frame->procedure, &file, &line );
+ string module_name[1];
+ get_source_line( frame, &file, &line );
sprintf( buf, "%d", line );
- result = list_new( result, newstr( file ) );
- result = list_new( result, newstr( buf ) );
- result = list_new( result, newstr( frame->module->name ) );
- result = list_new( result, newstr( frame->rulename ) );
+ string_new( module_name );
+ if ( frame->module->name )
+ {
+ string_append( module_name, object_str( frame->module->name ) );
+ string_append( module_name, "." );
+ }
+ result = list_push_back( result, object_new( file ) );
+ result = list_push_back( result, object_new( buf ) );
+ result = list_push_back( result, object_new( module_name->value ) );
+ result = list_push_back( result, object_new( frame->rulename ) );
+ string_free( module_name );
}
return result;
}
@@ -1265,10 +1294,10 @@ LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
* behavior.
*/
-LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
+LIST * builtin_caller_module( FRAME * frame, int flags )
{
LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : 0 ;
+ int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : 0 ;
int i;
for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
@@ -1276,16 +1305,8 @@ LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
if ( frame->module == root_module() )
return L0;
-
- {
- LIST * result;
- string name;
- string_copy( &name, frame->module->name );
- string_pop_back( &name );
- result = list_new( L0, newstr(name.value) );
- string_free( &name );
- return result;
- }
+ else
+ return list_new( object_copy( frame->module->name ) );
}
@@ -1295,7 +1316,7 @@ LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
* Usage: pwd = [ PWD ] ;
*/
-LIST * builtin_pwd( PARSE * parse, FRAME * frame )
+LIST * builtin_pwd( FRAME * frame, int flags )
{
return pwd();
}
@@ -1305,13 +1326,14 @@ LIST * builtin_pwd( PARSE * parse, FRAME * frame )
* Adds targets to the list of target that jam will attempt to update.
*/
-LIST * builtin_update( PARSE * parse, FRAME * frame )
+LIST * builtin_update( FRAME * frame, int flags )
{
- LIST * result = list_copy( L0, targets_to_update() );
+ LIST * result = list_copy( targets_to_update() );
LIST * arg1 = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
clear_targets_to_update();
- for ( ; arg1; arg1 = list_next( arg1 ) )
- mark_target_for_updating( newstr( arg1->string ) );
+ for ( ; iter != end; iter = list_next( iter ) )
+ mark_target_for_updating( object_copy( list_item( iter ) ) );
return result;
}
@@ -1325,34 +1347,30 @@ int last_update_now_status;
Third parameter, if non-empty, specifies that the -n option should have
no effect -- that is, all out-of-date targets should be rebuild.
*/
-LIST * builtin_update_now( PARSE * parse, FRAME * frame )
+LIST * builtin_update_now( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * log = lol_get( frame->args, 1 );
- LIST * force = lol_get (frame->args, 2);
- LIST * continue_ = lol_get(frame->args, 3);
- int status = 0;
- int original_stdout;
- int original_stderr;
- int n;
- int targets_count;
- const char** targets2;
- int i;
- int original_noexec;
- int original_quitquick;
+ LIST * force = lol_get( frame->args, 2 );
+ LIST * continue_ = lol_get( frame->args, 3 );
+ int status;
+ int original_stdout = 0;
+ int original_stderr = 0;
+ int original_noexec = 0;
+ int original_quitquick = 0;
- if (log)
+ if ( !list_empty( log ) )
{
- int fd = atoi(log->string);
+ int fd = atoi( object_str( list_front( log ) ) );
/* Redirect stdout and stderr, temporary, to the log file. */
- original_stdout = dup (0);
- original_stderr = dup (1);
- dup2 (fd, 0);
- dup2 (fd, 1);
+ original_stdout = dup( 0 );
+ original_stderr = dup( 1 );
+ dup2 ( fd, 0 );
+ dup2 ( fd, 1 );
}
- if (force)
+ if ( !list_empty( force ) )
{
original_noexec = globs.noexec;
globs.noexec = 0;
@@ -1360,95 +1378,83 @@ LIST * builtin_update_now( PARSE * parse, FRAME * frame )
globs.quitquick = 0;
}
- if (continue_)
+ if ( !list_empty( continue_ ) )
{
original_quitquick = globs.quitquick;
globs.quitquick = 0;
}
- targets_count = list_length( targets );
- targets2 = (const char * *)BJAM_MALLOC( targets_count * sizeof( char * ) );
- for (i = 0 ; targets; targets = list_next( targets ) )
- targets2[ i++ ] = targets->string;
- status |= make( targets_count, targets2, anyhow);
- free( targets );
+ status = make( targets, anyhow );
- if (force)
+ if ( !list_empty( force ) )
{
globs.noexec = original_noexec;
globs.quitquick = original_quitquick;
}
- if (continue_)
+ if ( !list_empty( continue_ ) )
{
globs.quitquick = original_quitquick;
}
- if (log)
+ if ( !list_empty( log ) )
{
/* Flush whatever stdio might have buffered, while descriptions
0 and 1 still refer to the log file. */
- fflush (stdout);
- fflush (stderr);
- dup2 (original_stdout, 0);
- dup2 (original_stderr, 1);
- close (original_stdout);
- close (original_stderr);
+ fflush( stdout );
+ fflush( stderr );
+ dup2( original_stdout, 0 );
+ dup2( original_stderr, 1 );
+ close( original_stdout );
+ close( original_stderr );
}
last_update_now_status = status;
- if (status == 0)
- return list_new (L0, newstr ("ok"));
+ if ( status == 0 )
+ return list_new( object_copy( constant_ok ) );
else
return L0;
}
-LIST * builtin_search_for_target( PARSE * parse, FRAME * frame )
-{
- LIST * arg1 = lol_get( frame->args, 0 );
- LIST * arg2 = lol_get( frame->args, 1 );
- TARGET * t = search_for_target( arg1->string, arg2 );
- return list_new( L0, t->name );
-}
-
-LIST * builtin_import_module( PARSE * parse, FRAME * frame )
+LIST * builtin_import_module( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
LIST * arg2 = lol_get( frame->args, 1 );
- module_t * m = arg2 ? bindmodule( arg2->string ) : root_module();
+ module_t * m = !list_empty( arg2 ) ? bindmodule( list_front( arg2 ) ) : root_module();
import_module( arg1, m );
return L0;
}
-LIST * builtin_imported_modules( PARSE * parse, FRAME * frame )
+LIST * builtin_imported_modules( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
- return imported_modules( bindmodule( arg0 ? arg0->string : 0 ) );
+ return imported_modules( bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 ) );
}
-LIST * builtin_instance( PARSE * parse, FRAME * frame )
+LIST * builtin_instance( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
LIST * arg2 = lol_get( frame->args, 1 );
- module_t * const instance = bindmodule( arg1->string );
- module_t * const class_module = bindmodule( arg2->string );
+ module_t * const instance = bindmodule( list_front( arg1 ) );
+ module_t * const class_module = bindmodule( list_front( arg2 ) );
instance->class_module = class_module;
+ module_set_fixed_variables( instance, class_module->num_fixed_variables );
return L0;
}
-LIST * builtin_sort( PARSE * parse, FRAME * frame )
+LIST * builtin_sort( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
return list_sort( arg1 );
}
-LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
+LIST * builtin_normalize_path( FRAME * frame, int flags )
{
LIST * arg = lol_get( frame->args, 0 );
@@ -1468,7 +1474,8 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
/* Number of '..' elements seen and not processed yet. */
int dotdots = 0;
int rooted = 0;
- char * result = 0;
+ OBJECT * result = 0;
+ LISTITER arg_iter = list_begin( arg ), arg_end = list_end( arg );
/* Make a copy of input: we should not change it. Prepend a '/' before it as
* a guard for the algorithm later on and remember whether it was originally
@@ -1476,16 +1483,16 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
*/
string_new( in );
string_push_back( in, '/' );
- for ( ; arg; arg = list_next( arg ) )
+ for ( ; arg_iter != arg_end; arg_iter = list_next( arg_iter ) )
{
- if ( arg->string[ 0 ] != '\0' )
+ if ( object_str( list_item( arg_iter ) )[ 0 ] != '\0' )
{
if ( in->size == 1 )
- rooted = ( ( arg->string[ 0 ] == '/' ) ||
- ( arg->string[ 0 ] == '\\' ) );
+ rooted = ( ( object_str( list_item( arg_iter ) )[ 0 ] == '/' ) ||
+ ( object_str( list_item( arg_iter ) )[ 0 ] == '\\' ) );
else
string_append( in, "/" );
- string_append( in, arg->string );
+ string_append( in, object_str( list_item( arg_iter ) ) );
}
}
@@ -1544,7 +1551,12 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
*/
if ( dotdots )
{
- if ( rooted ) return L0;
+ if ( rooted )
+ {
+ string_free( out );
+ string_free( in );
+ return L0;
+ }
do
string_append( out, "/.." );
while ( --dotdots );
@@ -1561,34 +1573,32 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
* the original path was rooted and we have an empty path we need to add
* back the '/'.
*/
- result = newstr( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
+ result = object_new( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
string_free( out );
string_free( in );
- return list_new( 0, result );
+ return list_new( result );
}
-LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_native_rule( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
LIST * rule_name = lol_get( frame->args, 1 );
- module_t * module = bindmodule( module_name->string );
+ module_t * module = bindmodule( list_front( module_name ) );
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+ native_rule_t * np;
+ if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
{
- new_rule_body( module, np->name, np->arguments, np->procedure, 1 );
+ new_rule_body( module, np->name, np->procedure, 1 );
}
else
{
backtrace_line( frame->prev );
- printf( "error: no native rule \"%s\" defined in module \"%s\"\n",
- n.name, module->name );
+ printf( "error: no native rule \"%s\" defined in module \"%s.\"\n",
+ object_str( list_front( rule_name ) ), object_str( module->name ) );
backtrace( frame->prev );
exit( 1 );
}
@@ -1596,40 +1606,39 @@ LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
}
-LIST * builtin_has_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_has_native_rule( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
LIST * rule_name = lol_get( frame->args, 1 );
LIST * version = lol_get( frame->args, 2 );
- module_t * module = bindmodule( module_name->string );
+ module_t * module = bindmodule( list_front( module_name ) );
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+ native_rule_t * np;
+ if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
{
- int expected_version = atoi( version->string );
+ int expected_version = atoi( object_str( list_front( version ) ) );
if ( np->version == expected_version )
- return list_new( 0, newstr( "true" ) );
+ return list_new( object_copy( constant_true ) );
}
return L0;
}
-LIST * builtin_user_module( PARSE * parse, FRAME * frame )
+LIST * builtin_user_module( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
- for ( ; module_name; module_name = module_name->next )
+ LISTITER iter = list_begin( module_name ), end = list_end( module_name );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- module_t * m = bindmodule( module_name->string );
+ module_t * m = bindmodule( list_item( iter ) );
m->user_module = 1;
}
return L0;
}
-LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
+LIST * builtin_nearest_user_location( FRAME * frame, int flags )
{
FRAME * nearest_user_frame =
frame->module->user_module ? frame : frame->prev_user;
@@ -1637,33 +1646,33 @@ LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
return L0;
{
- LIST * result = 0;
- char * file;
+ LIST * result = L0;
+ const char * file;
int line;
char buf[32];
- get_source_line( nearest_user_frame->procedure, &file, &line );
+ get_source_line( nearest_user_frame, &file, &line );
sprintf( buf, "%d", line );
- result = list_new( result, newstr( file ) );
- result = list_new( result, newstr( buf ) );
+ result = list_push_back( result, object_new( file ) );
+ result = list_push_back( result, object_new( buf ) );
return result;
}
}
-LIST * builtin_check_if_file( PARSE * parse, FRAME * frame )
+LIST * builtin_check_if_file( FRAME * frame, int flags )
{
LIST * name = lol_get( frame->args, 0 );
- return file_is_file( name->string ) == 1
- ? list_new( 0, newstr( "true" ) )
+ return file_is_file( list_front( name ) ) == 1
+ ? list_new( object_copy( constant_true ) )
: L0 ;
}
-LIST * builtin_md5( PARSE * parse, FRAME * frame )
+LIST * builtin_md5( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
- char* s = l->string;
+ const char* s = object_str( list_front( l ) );
md5_state_t state;
md5_byte_t digest[16];
@@ -1671,36 +1680,36 @@ LIST * builtin_md5( PARSE * parse, FRAME * frame )
int di;
- md5_init(&state);
- md5_append(&state, (const md5_byte_t *)s, strlen(s));
- md5_finish(&state, digest);
+ md5_init( &state );
+ md5_append( &state, (const md5_byte_t *)s, strlen(s) );
+ md5_finish( &state, digest );
for (di = 0; di < 16; ++di)
- sprintf(hex_output + di * 2, "%02x", digest[di]);
+ sprintf( hex_output + di * 2, "%02x", digest[di] );
- return list_new (0, newstr(hex_output));
+ return list_new( object_new( hex_output ) );
}
-LIST *builtin_file_open( PARSE *parse, FRAME *frame )
+LIST *builtin_file_open( FRAME * frame, int flags )
{
- char* name = lol_get(frame->args, 0)->string;
- char* mode = lol_get(frame->args, 1)->string;
+ const char * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
+ const char * mode = object_str( list_front( lol_get( frame->args, 1 ) ) );
int fd;
char buffer[sizeof("4294967295")];
- if (strcmp(mode, "w") == 0)
+ if ( strcmp(mode, "w") == 0 )
{
- fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ fd = open( name, O_WRONLY|O_CREAT|O_TRUNC, 0666 );
}
else
{
- fd = open(name, O_RDONLY);
+ fd = open( name, O_RDONLY );
}
if (fd != -1)
{
- sprintf(buffer, "%d", fd);
- return list_new(L0, newstr(buffer));
+ sprintf( buffer, "%d", fd );
+ return list_new( object_new( buffer ) );
}
else
{
@@ -1708,52 +1717,53 @@ LIST *builtin_file_open( PARSE *parse, FRAME *frame )
}
}
-LIST *builtin_pad( PARSE *parse, FRAME *frame )
+LIST *builtin_pad( FRAME * frame, int flags )
{
- char *string = lol_get(frame->args, 0)->string;
- char *width_s = lol_get(frame->args, 1)->string;
+ OBJECT * string = list_front( lol_get( frame->args, 0 ) );
+ const char * width_s = object_str( list_front( lol_get( frame->args, 1 ) ) );
- int current = strlen (string);
- int desired = atoi(width_s);
+ int current = strlen( object_str( string ) );
+ int desired = atoi( width_s );
if (current >= desired)
- return list_new (L0, string);
+ return list_new( object_copy( string ) );
else
{
- char *buffer = malloc (desired + 1);
+ char * buffer = BJAM_MALLOC( desired + 1 );
int i;
- LIST *result;
+ LIST * result;
- strcpy (buffer, string);
- for (i = current; i < desired; ++i)
+ strcpy( buffer, object_str( string ) );
+ for ( i = current; i < desired; ++i )
buffer[i] = ' ';
buffer[desired] = '\0';
- result = list_new (L0, newstr (buffer));
- free (buffer);
+ result = list_new( object_new( buffer ) );
+ BJAM_FREE( buffer );
return result;
}
}
-LIST *builtin_precious( PARSE *parse, FRAME *frame )
+LIST *builtin_precious( FRAME * frame, int flags )
{
- LIST* targets = lol_get(frame->args, 0);
+ LIST * targets = lol_get(frame->args, 0);
- for ( ; targets; targets = list_next( targets ) )
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET* t = bindtarget (targets->string);
+ TARGET* t = bindtarget( list_item( iter ) );
t->flags |= T_FLAG_PRECIOUS;
}
return L0;
}
-LIST *builtin_self_path( PARSE *parse, FRAME *frame )
+LIST *builtin_self_path( FRAME * frame, int flags )
{
- extern char *saved_argv0;
- char *p = executable_path (saved_argv0);
- if (p)
+ extern const char * saved_argv0;
+ char * p = executable_path( saved_argv0 );
+ if ( p )
{
- LIST* result = list_new (0, newstr (p));
- free(p);
+ LIST* result = list_new( object_new( p ) );
+ free( p );
return result;
}
else
@@ -1762,13 +1772,13 @@ LIST *builtin_self_path( PARSE *parse, FRAME *frame )
}
}
-LIST *builtin_makedir( PARSE *parse, FRAME *frame )
+LIST *builtin_makedir( FRAME * frame, int flags )
{
- LIST *path = lol_get(frame->args, 0);
+ LIST * path = lol_get( frame->args, 0 );
- if (file_mkdir(path->string) == 0)
+ if ( file_mkdir( object_str( list_front( path ) ) ) == 0 )
{
- LIST *result = list_new (0, newstr(path->string));
+ LIST * result = list_new( object_copy( list_front( path ) ) );
return result;
}
else
@@ -1779,13 +1789,13 @@ LIST *builtin_makedir( PARSE *parse, FRAME *frame )
#ifdef HAVE_PYTHON
-LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_python_import_rule( FRAME * frame, int flags )
{
static int first_time = 1;
- char * python_module = lol_get( frame->args, 0 )->string;
- char * python_function = lol_get( frame->args, 1 )->string;
- char * jam_module = lol_get( frame->args, 2 )->string;
- char * jam_rule = lol_get( frame->args, 3 )->string;
+ const char * python_module = object_str( list_front( lol_get( frame->args, 0 ) ) );
+ const char * python_function = object_str( list_front( lol_get( frame->args, 1 ) ) );
+ OBJECT * jam_module = list_front( lol_get( frame->args, 2 ) );
+ OBJECT * jam_rule = list_front( lol_get( frame->args, 3 ) );
PyObject * pName;
PyObject * pModule;
@@ -1799,29 +1809,19 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
*/
LIST * extra = 0;
module_t * outer_module = frame->module;
+ LISTITER iter, end;
first_time = 0;
- if ( outer_module != root_module() )
- {
- exit_module( outer_module );
- enter_module( root_module() );
- }
-
- extra = var_get( "EXTRA_PYTHONPATH" );
-
- if ( outer_module != root_module() )
- {
- exit_module( root_module() );
- enter_module( outer_module );
- }
+ extra = var_get( root_module(), constant_extra_pythonpath );
- for ( ; extra; extra = extra->next )
+ iter = list_begin( extra ), end = list_end( extra );
+ for ( ; iter != end; iter = list_next( iter ) )
{
string buf[ 1 ];
string_new( buf );
string_append( buf, "import sys\nsys.path.append(\"" );
- string_append( buf, extra->string );
+ string_append( buf, object_str( list_item( iter ) ) );
string_append( buf, "\")\n" );
PyRun_SimpleString( buf->value );
string_free( buf );
@@ -1840,12 +1840,7 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
if ( pFunc && PyCallable_Check( pFunc ) )
{
module_t * m = bindmodule( jam_module );
- RULE * r = bindrule( jam_rule, m );
-
- /* Make pFunc owned. */
- Py_INCREF( pFunc );
-
- r->python_function = pFunc;
+ new_rule_body( m, jam_rule, function_python( pFunc, 0 ), 0 );
}
else
{
@@ -1866,7 +1861,7 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
#endif
-void lol_build( LOL * lol, char * * elements )
+void lol_build( LOL * lol, const char * * elements )
{
LIST * l = L0;
lol_init( lol );
@@ -1880,7 +1875,7 @@ void lol_build( LOL * lol, char * * elements )
}
else
{
- l = list_new( l, newstr( *elements ) );
+ l = list_push_back( l, object_new( *elements ) );
}
++elements;
}
@@ -1900,22 +1895,21 @@ void lol_build( LOL * lol, char * * elements )
PyObject* bjam_call( PyObject * self, PyObject * args )
{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
- char * rulename;
+ FRAME inner[ 1 ];
+ LIST * result;
+ PARSE * p;
+ OBJECT * rulename;
/* Build up the list of arg lists. */
frame_init( inner );
inner->prev = 0;
inner->prev_user = 0;
- inner->module = bindmodule( "python_interface" );
- inner->procedure = 0;
+ inner->module = bindmodule( constant_python_interface );
/* Extract the rule name and arguments from 'args'. */
/* PyTuple_GetItem returns borrowed reference. */
- rulename = PyString_AsString( PyTuple_GetItem( args, 0 ) );
+ rulename = object_new( PyString_AsString( PyTuple_GetItem( args, 0 ) ) );
{
int i = 1;
int size = PyTuple_Size( args );
@@ -1924,7 +1918,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
PyObject * a = PyTuple_GetItem( args, i );
if ( PyString_Check( a ) )
{
- lol_add( inner->args, list_new( 0, newstr(
+ lol_add( inner->args, list_new( object_new(
PyString_AsString( a ) ) ) );
}
else if ( PySequence_Check( a ) )
@@ -1942,7 +1936,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
printf( "Invalid parameter type passed from Python\n" );
exit( 1 );
}
- l = list_new( l, newstr( s ) );
+ l = list_push_back( l, object_new( s ) );
Py_DECREF( e );
}
lol_add( inner->args, l );
@@ -1951,6 +1945,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
}
result = evaluate_rule( rulename, inner );
+ object_free( rulename );
frame_free( inner );
@@ -1958,10 +1953,10 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
{
PyObject * pyResult = PyList_New( list_length( result ) );
int i = 0;
- while ( result )
+ LISTITER iter = list_begin( result ), end = list_end( result );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- PyList_SetItem( pyResult, i, PyString_FromString( result->string ) );
- result = list_next( result );
+ PyList_SetItem( pyResult, i, PyString_FromString( object_str( list_item( iter ) ) ) );
i += 1;
}
list_free( result );
@@ -1988,6 +1983,8 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args )
PyObject * bjam_signature = NULL;
module_t * m;
RULE * r;
+ OBJECT * module_name;
+ OBJECT * rule_name;
if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
&module, &rule, &func, &bjam_signature ) )
@@ -2000,29 +1997,15 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args )
return NULL;
}
- m = bindmodule( *module ? module : 0 );
- r = bindrule( rule, m );
-
- /* Make pFunc owned. */
- Py_INCREF( func );
-
- r->python_function = func;
- r->arguments = 0;
-
- if (bjam_signature)
+ module_name = *module ? object_new( module ) : 0;
+ m = bindmodule( module_name );
+ if( module_name )
{
- argument_list * arg_list = args_new();
- Py_ssize_t i;
-
- Py_ssize_t s = PySequence_Size (bjam_signature);
- for (i = 0; i < s; ++i)
- {
- PyObject* v = PySequence_GetItem (bjam_signature, i);
- lol_add(arg_list->data, list_from_python (v));
- Py_DECREF(v);
- }
- r->arguments = arg_list;
+ object_free( module_name );
}
+ rule_name = object_new( rule );
+ new_rule_body( m, rule_name, function_python( func, bjam_signature ), 0 );
+ object_free( rule_name );
Py_INCREF( Py_None );
return Py_None;
@@ -2048,6 +2031,8 @@ PyObject * bjam_define_action( PyObject * self, PyObject * args )
LIST * bindlist = L0;
int n;
int i;
+ OBJECT * name_str;
+ FUNCTION * body_func;
if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
&PyList_Type, &bindlist_python, &flags ) )
@@ -2063,10 +2048,14 @@ PyObject * bjam_define_action( PyObject * self, PyObject * args )
"bind list has non-string type" );
return NULL;
}
- bindlist = list_new( bindlist, PyString_AsString( next ) );
+ bindlist = list_push_back( bindlist, object_new( PyString_AsString( next ) ) );
}
- new_rule_actions( root_module(), name, newstr( body ), bindlist, flags );
+ name_str = object_new( name );
+ body_func = function_compile_actions( body, constant_builtin, -1 );
+ new_rule_actions( root_module(), name_str, body_func, bindlist, flags );
+ function_free( body_func );
+ object_free( name_str );
Py_INCREF( Py_None );
return Py_None;
@@ -2083,17 +2072,20 @@ PyObject * bjam_variable( PyObject * self, PyObject * args )
LIST * value;
PyObject * result;
int i;
+ OBJECT * varname;
+ LISTITER iter, end;
if ( !PyArg_ParseTuple( args, "s", &name ) )
return NULL;
- enter_module( root_module() );
- value = var_get( name );
- exit_module( root_module() );
+ varname = object_new( name );
+ value = var_get( root_module(), varname );
+ object_free( varname );
+ iter = list_begin( value ), end = list_end( value );
result = PyList_New( list_length( value ) );
- for ( i = 0; value; value = list_next( value ), ++i )
- PyList_SetItem( result, i, PyString_FromString( value->string ) );
+ for ( i = 0; iter != end; iter = list_next( iter ), ++i )
+ PyList_SetItem( result, i, PyString_FromString( object_str( list_item( iter ) ) ) );
return result;
}
@@ -2106,19 +2098,28 @@ PyObject * bjam_backtrace( PyObject * self, PyObject * args )
for ( ; f = f->prev; )
{
- PyObject * tuple = PyTuple_New( 4 );
- char * file;
- int line;
- char buf[ 32 ];
+ PyObject * tuple = PyTuple_New( 4 );
+ const char * file;
+ int line;
+ char buf[ 32 ];
+ string module_name[1];
- get_source_line( f->procedure, &file, &line );
+ get_source_line( f, &file, &line );
sprintf( buf, "%d", line );
+ string_new( module_name );
+ if ( f->module->name )
+ {
+ string_append( module_name, object_str( f->module->name ) );
+ string_append( module_name, "." );
+ }
/* PyTuple_SetItem steals reference. */
PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
- PyTuple_SetItem( tuple, 2, PyString_FromString( f->module->name ) );
- PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
+ PyTuple_SetItem( tuple, 2, PyString_FromString( module_name->value ) );
+ PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
+
+ string_free( module_name );
PyList_Append( result, tuple );
Py_DECREF( tuple );
@@ -2128,9 +2129,10 @@ PyObject * bjam_backtrace( PyObject * self, PyObject * args )
PyObject * bjam_caller( PyObject * self, PyObject * args )
{
- PyObject *result = PyString_FromString(
- frame_before_python_call->prev->module->name);
- return result;
+ const char * s = frame_before_python_call->prev->module->name ?
+ object_str( frame_before_python_call->prev->module->name ) :
+ "";
+ return PyString_FromString( s );
}
#endif /* #ifdef HAVE_PYTHON */
@@ -2189,7 +2191,7 @@ PyObject * bjam_caller( PyObject * self, PyObject * args )
* should Windows ever 'fix' this feature.
* (03.06.2008.) (Jurko)
*/
- static FILE * windows_popen_wrapper( char * command, char * mode )
+ static FILE * windows_popen_wrapper( const char * command, const char * mode )
{
int extra_command_quotes_needed = ( strchr( command, '"' ) != 0 );
string quoted_command;
@@ -2214,18 +2216,18 @@ PyObject * bjam_caller( PyObject * self, PyObject * args )
#endif
-static char * rtrim(char *s)
+static char * rtrim( char * s )
{
- char *p = s;
- while(*p) ++p;
- for(--p; p >= s && isspace(*p); *p-- = 0);
+ char * p = s;
+ while ( *p ) ++p;
+ for ( --p; p >= s && isspace( *p ); *p-- = 0 );
return s;
}
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
{
LIST * command = lol_get( frame->args, 0 );
- LIST * result = 0;
+ LIST * result = L0;
string s;
int ret;
char buffer[ 1024 ];
@@ -2239,17 +2241,17 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
{
int a = 1;
LIST * arg = lol_get( frame->args, a );
- while ( arg )
+ while ( !list_empty( arg ) )
{
- if ( strcmp( "exit-status", arg->string ) == 0 )
+ if ( strcmp( "exit-status", object_str( list_front( arg ) ) ) == 0 )
{
exit_status_opt = 1;
}
- else if ( strcmp( "no-output", arg->string ) == 0 )
+ else if ( strcmp( "no-output", object_str( list_front( arg ) ) ) == 0 )
{
no_output_opt = 1;
}
- else if ( strcmp("strip-eol", arg->string) == 0 )
+ else if ( strcmp("strip-eol", object_str( list_front( arg ) ) ) == 0 )
{
strip_eol_opt = 1;
}
@@ -2263,7 +2265,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
*/
fflush( NULL );
- p = popen( command->string, "r" );
+ p = popen( object_str( list_front( command ) ), "r" );
if ( p == NULL )
return L0;
@@ -2283,7 +2285,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
exit_status = pclose( p );
/* The command output is returned first. */
- result = list_new( L0, newstr( s.value ) );
+ result = list_new( object_new( s.value ) );
string_free( &s );
/* The command exit result next. */
@@ -2294,7 +2296,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
else
exit_status = -1;
sprintf( buffer, "%d", exit_status );
- result = list_new( result, newstr( buffer ) );
+ result = list_push_back( result, object_new( buffer ) );
}
return result;
@@ -2302,7 +2304,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
#else /* #ifdef HAVE_POPEN */
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
{
return L0;
}
diff --git a/tools/build/v2/engine/builtins.h b/tools/build/v2/engine/builtins.h
index 5fed07c968..b8c086fb4f 100644
--- a/tools/build/v2/engine/builtins.h
+++ b/tools/build/v2/engine/builtins.h
@@ -21,47 +21,46 @@ void init_property_set();
void init_sequence();
void init_order();
-LIST *builtin_calc( PARSE *parse, FRAME *args );
-LIST *builtin_depends( PARSE *parse, FRAME *args );
-LIST *builtin_rebuilds( PARSE *parse, FRAME *args );
-LIST *builtin_echo( PARSE *parse, FRAME *args );
-LIST *builtin_exit( PARSE *parse, FRAME *args );
-LIST *builtin_flags( PARSE *parse, FRAME *args );
-LIST *builtin_glob( PARSE *parse, FRAME *args );
-LIST *builtin_glob_recursive( PARSE *parse, FRAME *frame );
-LIST *builtin_subst( PARSE *parse, FRAME *args );
-LIST *builtin_match( PARSE *parse, FRAME *args );
-LIST *builtin_split_by_characters( PARSE *parse, FRAME *args );
-LIST *builtin_hdrmacro( PARSE *parse, FRAME *args );
-LIST *builtin_rulenames( PARSE *parse, FRAME *args );
-LIST *builtin_varnames( PARSE *parse, FRAME *args );
-LIST *builtin_delete_module( PARSE *parse, FRAME *args );
-LIST *builtin_import( PARSE *parse, FRAME *args );
-LIST *builtin_export( PARSE *parse, FRAME *args );
-LIST *builtin_caller_module( PARSE *parse, FRAME *args );
-LIST *builtin_backtrace( PARSE *parse, FRAME *args );
-LIST *builtin_pwd( PARSE *parse, FRAME *args );
-LIST *builtin_update( PARSE *parse, FRAME *args );
-LIST *builtin_update_now( PARSE *parse, FRAME *args );
-LIST *builtin_search_for_target( PARSE *parse, FRAME *args );
-LIST *builtin_import_module( PARSE *parse, FRAME *args );
-LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
-LIST *builtin_instance( PARSE *parse, FRAME *frame );
-LIST *builtin_sort( PARSE *parse, FRAME *frame );
-LIST *builtin_normalize_path( PARSE *parse, FRAME *frame );
-LIST *builtin_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_has_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_user_module( PARSE *parse, FRAME *frame );
-LIST *builtin_nearest_user_location( PARSE *parse, FRAME *frame );
-LIST *builtin_check_if_file( PARSE *parse, FRAME *frame );
-LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_shell( PARSE *parse, FRAME *frame );
-LIST *builtin_md5( PARSE *parse, FRAME *frame );
-LIST *builtin_file_open( PARSE *parse, FRAME *frame );
-LIST *builtin_pad( PARSE *parse, FRAME *frame );
-LIST *builtin_precious( PARSE *parse, FRAME *frame );
-LIST *builtin_self_path( PARSE *parse, FRAME *frame );
-LIST *builtin_makedir( PARSE *parse, FRAME *frame );
+LIST *builtin_calc( FRAME * frame, int flags );
+LIST *builtin_depends( FRAME * frame, int flags );
+LIST *builtin_rebuilds( FRAME * frame, int flags );
+LIST *builtin_echo( FRAME * frame, int flags );
+LIST *builtin_exit( FRAME * frame, int flags );
+LIST *builtin_flags( FRAME * frame, int flags );
+LIST *builtin_glob( FRAME * frame, int flags );
+LIST *builtin_glob_recursive( FRAME * frame, int flags );
+LIST *builtin_subst( FRAME * frame, int flags );
+LIST *builtin_match( FRAME * frame, int flags );
+LIST *builtin_split_by_characters( FRAME * frame, int flags );
+LIST *builtin_hdrmacro( FRAME * frame, int flags );
+LIST *builtin_rulenames( FRAME * frame, int flags );
+LIST *builtin_varnames( FRAME * frame, int flags );
+LIST *builtin_delete_module( FRAME * frame, int flags );
+LIST *builtin_import( FRAME * frame, int flags );
+LIST *builtin_export( FRAME * frame, int flags );
+LIST *builtin_caller_module( FRAME * frame, int flags );
+LIST *builtin_backtrace( FRAME * frame, int flags );
+LIST *builtin_pwd( FRAME * frame, int flags );
+LIST *builtin_update( FRAME * frame, int flags );
+LIST *builtin_update_now( FRAME * frame, int flags );
+LIST *builtin_import_module( FRAME * frame, int flags );
+LIST *builtin_imported_modules( FRAME * frame, int flags );
+LIST *builtin_instance( FRAME * frame, int flags );
+LIST *builtin_sort( FRAME * frame, int flags );
+LIST *builtin_normalize_path( FRAME * frame, int flags );
+LIST *builtin_native_rule( FRAME * frame, int flags );
+LIST *builtin_has_native_rule( FRAME * frame, int flags );
+LIST *builtin_user_module( FRAME * frame, int flags );
+LIST *builtin_nearest_user_location( FRAME * frame, int flags );
+LIST *builtin_check_if_file( FRAME * frame, int flags );
+LIST *builtin_python_import_rule( FRAME * frame, int flags );
+LIST *builtin_shell( FRAME * frame, int flags );
+LIST *builtin_md5( FRAME * frame, int flags );
+LIST *builtin_file_open( FRAME * frame, int flags );
+LIST *builtin_pad( FRAME * frame, int flags );
+LIST *builtin_precious( FRAME * frame, int flags );
+LIST *builtin_self_path( FRAME * frame, int flags );
+LIST *builtin_makedir( FRAME * frame, int flags );
void backtrace( FRAME *frame );
extern int last_update_now_status;
diff --git a/tools/build/v2/engine/class.c b/tools/build/v2/engine/class.c
index ff4ec56807..8871d1113b 100644
--- a/tools/build/v2/engine/class.c
+++ b/tools/build/v2/engine/class.c
@@ -7,7 +7,7 @@
#include "variable.h"
#include "frames.h"
#include "rules.h"
-#include "newstr.h"
+#include "object.h"
#include "hash.h"
@@ -17,28 +17,28 @@ static struct hash * classes = 0;
static void check_defined( LIST * class_names )
{
- for ( ; class_names; class_names = class_names->next )
+ LISTITER iter = list_begin( class_names ), end = list_end( class_names );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- char * * p = &class_names->string;
- if ( !hashcheck( classes, (HASHDATA * *)&p ) )
+ if ( !hash_find( classes, list_item( iter ) ) )
{
- printf( "Class %s is not defined\n", class_names->string );
+ printf( "Class %s is not defined\n", object_str( list_item( iter ) ) );
abort();
}
}
}
-static char * class_module_name( char * declared_name )
+static OBJECT * class_module_name( OBJECT * declared_name )
{
string name[ 1 ];
- char * result;
+ OBJECT * result;
string_new( name );
string_append( name, "class@" );
- string_append( name, declared_name );
+ string_append( name, object_str( declared_name ) );
- result = newstr( name->value );
+ result = object_new( name->value );
string_free( name );
return result;
@@ -47,7 +47,7 @@ static char * class_module_name( char * declared_name )
struct import_base_data
{
- char * base_name;
+ OBJECT * base_name;
module_t * base_module;
module_t * class_module;
};
@@ -60,14 +60,19 @@ static void import_base_rule( void * r_, void * d_ )
RULE * ir2;
struct import_base_data * d = (struct import_base_data *)d_;
string qualified_name[ 1 ];
+ OBJECT * qname;
string_new ( qualified_name );
- string_append ( qualified_name, d->base_name );
+ string_append ( qualified_name, object_str( d->base_name ) );
string_push_back( qualified_name, '.' );
- string_append ( qualified_name, r->name );
+ string_append ( qualified_name, object_str( r->name ) );
+
+ qname = object_new( qualified_name->value );
ir1 = import_rule( r, d->class_module, r->name );
- ir2 = import_rule( r, d->class_module, qualified_name->value );
+ ir2 = import_rule( r, d->class_module, qname );
+
+ object_free( qname );
/* Copy 'exported' flag. */
ir1->exported = ir2->exported = r->exported;
@@ -75,7 +80,10 @@ static void import_base_rule( void * r_, void * d_ )
/* If we are importing a class method, localize it. */
if ( ( r->module == d->base_module ) || ( r->module->class_module &&
( r->module->class_module == d->base_module ) ) )
- ir1->module = ir2->module = d->class_module;
+ {
+ rule_localize( ir1, d->class_module );
+ rule_localize( ir2, d->class_module );
+ }
string_free( qualified_name );
}
@@ -87,55 +95,73 @@ static void import_base_rule( void * r_, void * d_ )
* marked as exported.
*/
-static void import_base_rules( module_t * class, char * base )
+static void import_base_rules( module_t * class_, OBJECT * base )
{
- module_t * base_module = bindmodule( class_module_name( base ) );
+ OBJECT * module_name = class_module_name( base );
+ module_t * base_module = bindmodule( module_name );
+ LIST * imported;
struct import_base_data d;
d.base_name = base;
d.base_module = base_module;
- d.class_module = class;
+ d.class_module = class_;
+ object_free( module_name );
if ( base_module->rules )
hashenumerate( base_module->rules, import_base_rule, &d );
- import_module( imported_modules( base_module ), class );
+ imported = imported_modules( base_module );
+ import_module( imported, class_ );
+ list_free( imported );
}
-char * make_class_module( LIST * xname, LIST * bases, FRAME * frame )
+OBJECT * make_class_module( LIST * xname, LIST * bases, FRAME * frame )
{
- char * name = class_module_name( xname->string );
- char * * pp = &xname->string;
+ OBJECT * name = class_module_name( list_front( xname ) );
+ OBJECT * * pp;
module_t * class_module = 0;
module_t * outer_module = frame->module;
+ int found;
+ LISTITER iter, end;
if ( !classes )
- classes = hashinit( sizeof( char * ), "classes" );
+ classes = hashinit( sizeof( OBJECT * ), "classes" );
- if ( hashcheck( classes, (HASHDATA * *)&pp ) )
+ pp = (OBJECT * *)hash_insert( classes, list_front( xname ), &found );
+ if ( !found )
{
- printf( "Class %s already defined\n", xname->string );
- abort();
+ *pp = object_copy( list_front( xname ) );
}
else
{
- hashenter( classes, (HASHDATA * *)&pp );
+ printf( "Class %s already defined\n", object_str( list_front( xname ) ) );
+ abort();
}
check_defined( bases );
class_module = bindmodule( name );
- exit_module( outer_module );
- enter_module( class_module );
+ var_set( class_module, constant_name, xname, VAR_SET );
+ var_set( class_module, constant_bases, bases, VAR_SET );
- var_set( "__name__", xname, VAR_SET );
- var_set( "__bases__", bases, VAR_SET );
+ iter = list_begin( bases ), end = list_end( bases );
+ for ( ; iter != end; iter = list_next( iter ) )
+ import_base_rules( class_module, list_item( iter ) );
- exit_module( class_module );
- enter_module( outer_module );
+ return name;
+}
- for ( ; bases; bases = bases->next )
- import_base_rules( class_module, bases->string );
+static void free_class( void * xclass, void * data )
+{
+ object_free( *(OBJECT * *)xclass );
+}
- return name;
+void class_done( void )
+{
+ if( classes )
+ {
+ hashenumerate( classes, free_class, (void *)0 );
+ hashdone( classes );
+ classes = 0;
+ }
}
diff --git a/tools/build/v2/engine/class.h b/tools/build/v2/engine/class.h
index f7faeff62e..256d298b53 100644
--- a/tools/build/v2/engine/class.h
+++ b/tools/build/v2/engine/class.h
@@ -8,6 +8,7 @@
#include "lists.h"
#include "frames.h"
-char* make_class_module(LIST* xname, LIST* bases, FRAME* frame);
+OBJECT * make_class_module( LIST * xname, LIST * bases, FRAME * frame );
+void class_done( void );
#endif
diff --git a/tools/build/v2/engine/command.c b/tools/build/v2/engine/command.c
index d2ea068149..8161014c05 100644
--- a/tools/build/v2/engine/command.c
+++ b/tools/build/v2/engine/command.c
@@ -33,10 +33,11 @@
CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
{
CMD * cmd = (CMD *)BJAM_MALLOC( sizeof( CMD ) );
+ LISTITER iter = list_begin( shell ), end = list_end( shell );
/* Lift line-length limitation entirely when JAMSHELL is just "%". */
- int no_limit = ( shell && !strcmp(shell->string,"%") && !list_next(shell) );
+ int no_limit = ( iter != end && !strcmp( object_str( list_item( iter ) ), "%") && list_next( iter ) == end );
int max_line = MAXLINE;
- int allocated = -1;
+ FRAME frame[1];
cmd->rule = rule;
cmd->shell = shell;
@@ -45,27 +46,20 @@ CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
lol_init( &cmd->args );
lol_add( &cmd->args, targets );
lol_add( &cmd->args, sources );
- cmd->buf = 0;
+ string_new( cmd->buf );
- do
- {
- BJAM_FREE( cmd->buf ); /* free any buffer from previous iteration */
-
- cmd->buf = (char*)BJAM_MALLOC_ATOMIC( max_line + 1 );
-
- if ( cmd->buf == 0 )
- break;
-
- allocated = var_string( rule->actions->command, cmd->buf, max_line, &cmd->args );
-
- max_line = max_line * 2;
- }
- while ( ( allocated < 0 ) && ( max_line < INT_MAX / 2 ) );
+ frame_init( frame );
+ frame->module = rule->module;
+ lol_init( frame->args );
+ lol_add( frame->args, list_copy( targets ) );
+ lol_add( frame->args, list_copy( sources ) );
+ function_run_actions( rule->actions->command, frame, stack_global(), cmd->buf );
+ frame_free( frame );
if ( !no_limit )
{
/* Bail if the result will not fit in MAXLINE. */
- char * s = cmd->buf;
+ char * s = cmd->buf->value;
while ( *s )
{
size_t l = strcspn( s, "\n" );
@@ -95,6 +89,6 @@ void cmd_free( CMD * cmd )
{
lol_free( &cmd->args );
list_free( cmd->shell );
- BJAM_FREE( cmd->buf );
- BJAM_FREE( (char *)cmd );
+ string_free( cmd->buf );
+ BJAM_FREE( (void *)cmd );
}
diff --git a/tools/build/v2/engine/command.h b/tools/build/v2/engine/command.h
index ddd38e6897..4dad9e254c 100644
--- a/tools/build/v2/engine/command.h
+++ b/tools/build/v2/engine/command.h
@@ -36,6 +36,13 @@
* CMD - an action, ready to be formatted into a buffer and executed.
*/
+#ifndef COMMAND_SW20111118_H
+#define COMMAND_SW20111118_H
+
+#include "lists.h"
+#include "rules.h"
+#include "strings.h"
+
typedef struct _cmd CMD;
struct _cmd
@@ -45,7 +52,7 @@ struct _cmd
RULE * rule; /* rule->actions contains shell script */
LIST * shell; /* $(SHELL) value */
LOL args; /* LISTs for $(<), $(>) */
- char * buf; /* actual commands */
+ string buf[1]; /* actual commands */
};
CMD * cmd_new
@@ -59,3 +66,5 @@ CMD * cmd_new
void cmd_free( CMD * );
#define cmd_next( c ) ( ( c )->next )
+
+#endif
diff --git a/tools/build/v2/engine/compile.c b/tools/build/v2/engine/compile.c
index 2c049aae59..cb08e24c95 100644
--- a/tools/build/v2/engine/compile.c
+++ b/tools/build/v2/engine/compile.c
@@ -16,9 +16,8 @@
# include "parse.h"
# include "compile.h"
# include "variable.h"
-# include "expand.h"
# include "rules.h"
-# include "newstr.h"
+# include "object.h"
# include "make.h"
# include "search.h"
# include "hdrmacro.h"
@@ -27,6 +26,7 @@
# include "strings.h"
# include "builtins.h"
# include "class.h"
+# include "constants.h"
# include <assert.h>
# include <string.h>
@@ -86,15 +86,17 @@
* 01/10/00 (seiwald) - built-ins split out to builtin.c.
*/
-static void debug_compile( int which, char *s, FRAME* frame );
-int glob( char *s, char *c );
+static void debug_compile( int which, const char * s, FRAME * frame );
+int glob( const char * s, const char * c );
/* Internal functions from builtins.c */
-void backtrace( FRAME *frame );
-void backtrace_line( FRAME *frame );
-void print_source_line( PARSE* p );
+void backtrace( FRAME * frame );
+void backtrace_line( FRAME * frame );
+void print_source_line( FRAME * frame );
struct frame * frame_before_python_call;
+static OBJECT * module_scope;
+
void frame_init( FRAME* frame )
{
frame->prev = 0;
@@ -102,7 +104,8 @@ void frame_init( FRAME* frame )
lol_init(frame->args);
frame->module = root_module();
frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
}
@@ -113,907 +116,39 @@ void frame_free( FRAME* frame )
/*
- * compile_append() - append list results of two statements
- *
- * parse->left more compile_append() by left-recursion
- * parse->right single rule
- */
-
-LIST * compile_append( PARSE * parse, FRAME * frame )
-{
- /* Append right to left. */
- return list_append(
- parse_evaluate( parse->left, frame ),
- parse_evaluate( parse->right, frame ) );
-}
-
-
-/*
- * compile_eval() - evaluate if to determine which leg to compile
- *
- * Returns:
- * list if expression true - compile 'then' clause
- * L0 if expression false - compile 'else' clause
- */
-
-static int lcmp( LIST * t, LIST * s )
-{
- int status = 0;
-
- while ( !status && ( t || s ) )
- {
- char *st = t ? t->string : "";
- char *ss = s ? s->string : "";
-
- status = strcmp( st, ss );
-
- t = t ? list_next( t ) : t;
- s = s ? list_next( s ) : s;
- }
-
- return status;
-}
-
-LIST * compile_eval( PARSE * parse, FRAME * frame )
-{
- LIST * ll;
- LIST * lr;
- LIST * s;
- LIST * t;
- int status = 0;
-
- /* Short circuit lr eval for &&, ||, and 'in'. */
-
- ll = parse_evaluate( parse->left, frame );
- lr = 0;
-
- switch ( parse->num )
- {
- case EXPR_AND:
- case EXPR_IN : if ( ll ) goto eval; break;
- case EXPR_OR : if ( !ll ) goto eval; break;
- default: eval: lr = parse_evaluate( parse->right, frame );
- }
-
- /* Now eval. */
- switch ( parse->num )
- {
- case EXPR_NOT: if ( !ll ) status = 1; break;
- case EXPR_AND: if ( ll && lr ) status = 1; break;
- case EXPR_OR : if ( ll || lr ) status = 1; break;
-
- case EXPR_IN:
- /* "a in b": make sure each of ll is equal to something in lr. */
- for ( t = ll; t; t = list_next( t ) )
- {
- for ( s = lr; s; s = list_next( s ) )
- if ( !strcmp( t->string, s->string ) )
- break;
- if ( !s ) break;
- }
- /* No more ll? Success. */
- if ( !t ) status = 1;
- break;
-
- case EXPR_EXISTS: if ( lcmp( ll, L0 ) != 0 ) status = 1; break;
- case EXPR_EQUALS: if ( lcmp( ll, lr ) == 0 ) status = 1; break;
- case EXPR_NOTEQ : if ( lcmp( ll, lr ) != 0 ) status = 1; break;
- case EXPR_LESS : if ( lcmp( ll, lr ) < 0 ) status = 1; break;
- case EXPR_LESSEQ: if ( lcmp( ll, lr ) <= 0 ) status = 1; break;
- case EXPR_MORE : if ( lcmp( ll, lr ) > 0 ) status = 1; break;
- case EXPR_MOREEQ: if ( lcmp( ll, lr ) >= 0 ) status = 1; break;
- }
-
- if ( DEBUG_IF )
- {
- debug_compile( 0, "if", frame );
- list_print( ll );
- printf( "(%d) ", status );
- list_print( lr );
- printf( "\n" );
- }
-
- /* Find something to return. */
- /* In odd circumstances (like "" = "") */
- /* we'll have to return a new string. */
-
- if ( !status ) t = 0;
- else if ( ll ) t = ll, ll = 0;
- else if ( lr ) t = lr, lr = 0;
- else t = list_new( L0, newstr( "1" ) );
-
- if ( ll ) list_free( ll );
- if ( lr ) list_free( lr );
- return t;
-}
-
-
-/*
- * compile_foreach() - compile the "for x in y" statement
- *
- * Compile_foreach() resets the given variable name to each specified
- * value, executing the commands enclosed in braces for each iteration.
- *
- * parse->string index variable
- * parse->left variable values
- * parse->right rule to compile
- */
-
-LIST * compile_foreach( PARSE * parse, FRAME * frame )
-{
- LIST * nv = parse_evaluate( parse->left, frame );
- LIST * l;
- SETTINGS * s = 0;
-
- if ( parse->num )
- {
- s = addsettings( s, VAR_SET, parse->string, L0 );
- pushsettings( s );
- }
-
- /* Call var_set to reset $(parse->string) for each val. */
-
- for ( l = nv; l; l = list_next( l ) )
- {
- LIST * val = list_new( L0, copystr( l->string ) );
- var_set( parse->string, val, VAR_SET );
- list_free( parse_evaluate( parse->right, frame ) );
- }
-
- if ( parse->num )
- {
- popsettings( s );
- freesettings( s );
- }
-
- list_free( nv );
-
- return L0;
-}
-
-/*
- * compile_if() - compile 'if' rule
- *
- * parse->left condition tree
- * parse->right then tree
- * parse->third else tree
- */
-
-LIST * compile_if( PARSE * p, FRAME * frame )
-{
- LIST * l = parse_evaluate( p->left, frame );
- if ( l )
- {
- list_free( l );
- return parse_evaluate( p->right, frame );
- }
- return parse_evaluate( p->third, frame );
-}
-
-
-LIST * compile_while( PARSE * p, FRAME * frame )
-{
- LIST * r = 0;
- LIST * l;
- while ( ( l = parse_evaluate( p->left, frame ) ) )
- {
- list_free( l );
- if ( r ) list_free( r );
- r = parse_evaluate( p->right, frame );
- }
- return r;
-}
-
-
-/*
- * compile_include() - support for 'include' - call include() on file
- *
- * parse->left list of files to include (can only do 1)
- */
-
-LIST * compile_include( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "include", frame);
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->string );
-
- /* DWA 2001/10/22 - Perforce Jam cleared the arguments here, which
- * prevents an included file from being treated as part of the body of a
- * rule. I did not see any reason to do that, so I lifted the
- * restriction.
- */
-
- /* Bind the include file under the influence of */
- /* "on-target" variables. Though they are targets, */
- /* include files are not built with make(). */
-
- pushsettings( t->settings );
- /* We don't expect that file to be included is generated by some
- action. Therefore, pass 0 as third argument.
- If the name resolves to directory, let it error out. */
- t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
-
- parse_file( t->boundname, frame );
- }
-
- list_free( nt );
-
- return L0;
-}
-
-static LIST* evaluate_in_module ( char* module_name, PARSE * p, FRAME* frame)
-{
- LIST* result;
-
- module_t* outer_module = frame->module;
- frame->module = module_name ? bindmodule( module_name ) : root_module();
-
- if ( outer_module != frame->module )
- {
- exit_module( outer_module );
- enter_module( frame->module );
- }
-
- result = parse_evaluate( p, frame );
-
- if ( outer_module != frame->module )
- {
- exit_module( frame->module );
- enter_module( outer_module );
- frame->module = outer_module;
- }
-
- return result;
-}
-
-
-LIST * compile_module( PARSE * p, FRAME * frame )
-{
- /* Here we are entering a module declaration block. */
- LIST * module_name = parse_evaluate( p->left, frame );
- LIST * result = evaluate_in_module( module_name ? module_name->string : 0,
- p->right, frame );
- list_free( module_name );
- return result;
-}
-
-
-LIST * compile_class( PARSE * p, FRAME * frame )
-{
- /** Todo: check for empty class name.
- Check for class redeclaration. */
-
- char * class_module = 0;
-
- LIST * name = parse_evaluate( p->left->right, frame );
- LIST * bases = 0;
-
- if ( p->left->left )
- bases = parse_evaluate( p->left->left->right, frame );
-
- class_module = make_class_module( name, bases, frame );
- evaluate_in_module( class_module, p->right, frame );
-
- return L0;
-}
-
-
-/*
- * compile_list() - expand and return a list.
- *
- * parse->string - character string to expand.
- */
-
-LIST * compile_list( PARSE * parse, FRAME * frame )
-{
- /* s is a copyable string */
- char * s = parse->string;
- return var_expand( L0, s, s + strlen( s ), frame->args, 1 );
-}
-
-
-/*
- * compile_local() - declare (and set) local variables.
- *
- * parse->left list of variables
- * parse->right list of values
- * parse->third rules to execute
- */
-
-LIST * compile_local( PARSE * parse, FRAME * frame )
-{
- LIST * l;
- SETTINGS * s = 0;
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * result;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "local", frame );
- list_print( nt );
- printf( " = " );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Initial value is ns. */
- for ( l = nt; l; l = list_next( l ) )
- s = addsettings( s, VAR_SET, l->string, list_copy( (LIST *)0, ns ) );
-
- list_free( ns );
- list_free( nt );
-
- /* Note that callees of the current context get this "local" variable,
- * making it not so much local as layered.
- */
-
- pushsettings( s );
- result = parse_evaluate( parse->third, frame );
- popsettings( s );
-
- freesettings( s );
-
- return result;
-}
-
-
-/*
- * compile_null() - do nothing -- a stub for parsing.
- */
-
-LIST * compile_null( PARSE * parse, FRAME * frame )
-{
- return L0;
-}
-
-
-/*
- * compile_on() - run rule under influence of on-target variables
- *
- * parse->left list of files to include (can only do 1).
- * parse->right rule to run.
- *
- * EXPERIMENTAL!
- */
-
-LIST * compile_on( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "on", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->string );
- pushsettings( t->settings );
- result = parse_evaluate( parse->right, frame );
- popsettings( t->settings );
- }
-
- list_free( nt );
-
- return result;
-}
-
-
-/*
- * compile_rule() - compile a single user defined rule.
- *
- * parse->string name of user defined rule.
- * parse->left parameters (list of lists) to rule, recursing left.
- *
- * Wrapped around evaluate_rule() so that headers() can share it.
- */
-
-LIST * compile_rule( PARSE * parse, FRAME * frame )
-{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
-
- /* Build up the list of arg lists. */
- frame_init( inner );
- inner->prev = frame;
- inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
- inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */
- inner->procedure = parse;
- /* Special-case LOL of length 1 where the first list is totally empty.
- This is created when calling functions with no parameters, due to
- the way jam grammar is written. This is OK when one jam function
- calls another, but really not good when Jam function calls Python. */
- if ( parse->left->left == NULL && parse->left->right->func == compile_null)
- ;
- else
- for ( p = parse->left; p; p = p->left )
- lol_add( inner->args, parse_evaluate( p->right, frame ) );
-
- /* And invoke the rule. */
- result = evaluate_rule( parse->string, inner );
- frame_free( inner );
- return result;
-}
-
-
-static void argument_error( char * message, RULE * rule, FRAME * frame, LIST* arg )
-{
- LOL * actual = frame->args;
- assert( frame->procedure != 0 );
- backtrace_line( frame->prev );
- printf( "*** argument error\n* rule %s ( ", frame->rulename );
- lol_print( rule->arguments->data );
- printf( " )\n* called with: ( " );
- lol_print( actual );
- printf( " )\n* %s %s\n", message, arg ? arg->string : "" );
- print_source_line( rule->procedure );
- printf( "see definition of rule '%s' being called\n", rule->name );
- backtrace( frame->prev );
- exit( 1 );
-}
-
-
-/* Define delimiters for type check elements in argument lists (and return type
- * specifications, eventually).
- */
-# define TYPE_OPEN_DELIM '['
-# define TYPE_CLOSE_DELIM ']'
-
-/*
- * is_type_name() - true iff the given string represents a type check
- * specification.
- */
-
-static int is_type_name( char * s )
-{
- return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
- ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
-}
-
-
-/*
- * arg_modifier - if the next element of formal is a single character, return
- * that; return 0 otherwise. Used to extract "*+?" modifiers * from argument
- * lists.
- */
-
-static char arg_modifier( LIST * formal )
-{
- if ( formal->next )
- {
- char * next = formal->next->string;
- if ( next && ( next[ 0 ] != 0 ) && ( next[ 1 ] == 0 ) )
- return next[ 0 ];
- }
- return 0;
-}
-
-
-/*
- * type_check() - checks that each element of values satisfies the requirements
- * of type_name.
- *
- * caller - the frame of the rule calling the rule whose arguments are
- * being checked
- *
- * called - the rule being called
- *
- * arg_name - a list element containing the name of the argument being
- * checked
- */
-
-static void type_check
-(
- char * type_name,
- LIST * values,
- FRAME * caller,
- RULE * called,
- LIST * arg_name
-)
-{
- static module_t * typecheck = 0;
-
- /* If nothing to check, bail now. */
- if ( !values || !type_name )
- return;
-
- if ( !typecheck )
- typecheck = bindmodule( ".typecheck" );
-
- /* If the checking rule can not be found, also bail. */
- {
- RULE checker_, *checker = &checker_;
-
- checker->name = type_name;
- if ( !typecheck->rules || !hashcheck( typecheck->rules, (HASHDATA * *)&checker ) )
- return;
- }
-
- exit_module( caller->module );
-
- while ( values != 0 )
- {
- LIST *error;
- FRAME frame[1];
- frame_init( frame );
- frame->module = typecheck;
- frame->prev = caller;
- frame->prev_user = caller->module->user_module ? caller : caller->prev_user;
-
- enter_module( typecheck );
- /* Prepare the argument list */
- lol_add( frame->args, list_new( L0, values->string ) );
- error = evaluate_rule( type_name, frame );
-
- exit_module( typecheck );
-
- if ( error )
- argument_error( error->string, called, caller, arg_name );
-
- frame_free( frame );
- values = values->next;
- }
-
- enter_module( caller->module );
-}
-
-/*
- * collect_arguments() - local argument checking and collection
- */
-static SETTINGS *
-collect_arguments( RULE* rule, FRAME* frame )
-{
- SETTINGS *locals = 0;
-
- LOL * all_actual = frame->args;
- LOL * all_formal = rule->arguments ? rule->arguments->data : 0;
- if ( all_formal ) /* Nothing to set; nothing to check */
- {
- int max = all_formal->count > all_actual->count
- ? all_formal->count
- : all_actual->count;
-
- int n;
- for ( n = 0; n < max ; ++n )
- {
- LIST *actual = lol_get( all_actual, n );
- char *type_name = 0;
-
- LIST *formal;
- for ( formal = lol_get( all_formal, n ); formal; formal = formal->next )
- {
- char* name = formal->string;
-
- if ( is_type_name(name) )
- {
- if ( type_name )
- argument_error( "missing argument name before type name:", rule, frame, formal );
-
- if ( !formal->next )
- argument_error( "missing argument name after type name:", rule, frame, formal );
-
- type_name = formal->string;
- }
- else
- {
- LIST* value = 0;
- char modifier;
- LIST* arg_name = formal; /* hold the argument name for type checking */
- int multiple = 0;
-
- /* Stop now if a variable number of arguments are specified */
- if ( name[0] == '*' && name[1] == 0 )
- return locals;
-
- modifier = arg_modifier( formal );
-
- if ( !actual && modifier != '?' && modifier != '*' )
- argument_error( "missing argument", rule, frame, formal );
-
- switch ( modifier )
- {
- case '+':
- case '*':
- value = list_copy( 0, actual );
- multiple = 1;
- actual = 0;
- /* skip an extra element for the modifier */
- formal = formal->next;
- break;
- case '?':
- /* skip an extra element for the modifier */
- formal = formal->next;
- /* fall through */
- default:
- if ( actual ) /* in case actual is missing */
- {
- value = list_new( 0, actual->string );
- actual = actual->next;
- }
- }
-
- locals = addsettings(locals, VAR_SET, name, value);
- locals->multiple = multiple;
- type_check( type_name, value, frame, rule, arg_name );
- type_name = 0;
- }
- }
-
- if ( actual )
- {
- argument_error( "extra argument", rule, frame, actual );
- }
- }
- }
- return locals;
-}
-
-RULE *
-enter_rule( char *rulename, module_t *target_module );
-
-#ifdef HAVE_PYTHON
-
-static int python_instance_number = 0;
-
-
-/* Given a Python object, return a string to use in Jam
- code instead of said object.
- If the object is string, use the string value
- If the object implemenets __jam_repr__ method, use that.
- Otherwise return 0.
-
- The result value is newstr-ed. */
-char *python_to_string(PyObject* value)
-{
- if (PyString_Check(value))
- {
- return newstr(PyString_AsString(value));
- }
- else
- {
- /* See if this is an instance that defines special __jam_repr__
- method. */
- if (PyInstance_Check(value)
- && PyObject_HasAttrString(value, "__jam_repr__"))
- {
- PyObject* repr = PyObject_GetAttrString(value, "__jam_repr__");
- if (repr)
- {
- PyObject* arguments2 = PyTuple_New(0);
- PyObject* value2 = PyObject_Call(repr, arguments2, 0);
- Py_DECREF(repr);
- Py_DECREF(arguments2);
- if (PyString_Check(value2))
- {
- return newstr(PyString_AsString(value2));
- }
- Py_DECREF(value2);
- }
- }
- return 0;
- }
-}
-
-static LIST*
-call_python_function(RULE* r, FRAME* frame)
-{
- LIST * result = 0;
- PyObject * arguments = 0;
- PyObject * kw = NULL;
- int i ;
- PyObject * py_result;
-
- if (r->arguments)
- {
- SETTINGS * args;
-
- arguments = PyTuple_New(0);
- kw = PyDict_New();
-
- for (args = collect_arguments(r, frame); args; args = args->next)
- {
- PyObject *key = PyString_FromString(args->symbol);
- PyObject *value = 0;
- if (args->multiple)
- value = list_to_python(args->value);
- else {
- if (args->value)
- value = PyString_FromString(args->value->string);
- }
-
- if (value)
- PyDict_SetItem(kw, key, value);
- Py_DECREF(key);
- Py_XDECREF(value);
- }
- }
- else
- {
- arguments = PyTuple_New( frame->args->count );
- for ( i = 0; i < frame->args->count; ++i )
- {
- PyObject * arg = PyList_New(0);
- LIST* l = lol_get( frame->args, i);
-
- for ( ; l; l = l->next )
- {
- PyObject * v = PyString_FromString(l->string);
- PyList_Append( arg, v );
- Py_DECREF(v);
- }
- /* Steals reference to 'arg' */
- PyTuple_SetItem( arguments, i, arg );
- }
- }
-
- frame_before_python_call = frame;
- py_result = PyObject_Call( r->python_function, arguments, kw );
- Py_DECREF(arguments);
- Py_XDECREF(kw);
- if ( py_result != NULL )
- {
- if ( PyList_Check( py_result ) )
- {
- int size = PyList_Size( py_result );
- int i;
- for ( i = 0; i < size; ++i )
- {
- PyObject * item = PyList_GetItem( py_result, i );
- char *s = python_to_string (item);
- if (!s) {
- fprintf( stderr, "Non-string object returned by Python call.\n" );
- } else {
- result = list_new (result, s);
- }
- }
- }
- else if ( py_result == Py_None )
- {
- result = L0;
- }
- else
- {
- char *s = python_to_string(py_result);
- if (s)
- result = list_new(0, s);
- else
- /* We have tried all we could. Return empty list. There are
- cases, e.g. feature.feature function that should return
- value for the benefit of Python code and which also can be
- called by Jam code, where no sensible value can be
- returned. We cannot even emit a warning, since there will
- be a pile of them. */
- result = L0;
- }
-
- Py_DECREF( py_result );
- }
- else
- {
- PyErr_Print();
- fprintf(stderr,"Call failed\n");
- }
-
- return result;
-}
-
-
-module_t * python_module()
-{
- static module_t * python = 0;
- if ( !python )
- python = bindmodule("__python__");
- return python;
-}
-
-#endif
-
-
-/*
* evaluate_rule() - execute a rule invocation.
*/
LIST *
evaluate_rule(
- char * rulename,
- FRAME * frame )
+ OBJECT * rulename,
+ FRAME * frame )
{
LIST * result = L0;
RULE * rule;
profile_frame prof[1];
module_t * prev_module = frame->module;
- LIST * l;
- {
- LOL arg_context_, * arg_context = &arg_context_;
- if ( !frame->prev )
- lol_init(arg_context);
- else
- arg_context = frame->prev->args;
- l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 );
- }
-
- if ( !l )
- {
- backtrace_line( frame->prev );
- printf( "warning: rulename %s expands to empty string\n", rulename );
- backtrace( frame->prev );
- return result;
- }
-
- rulename = l->string;
- rule = bindrule( l->string, frame->module );
-
-#ifdef HAVE_PYTHON
- if ( rule->python_function )
- {
- /* The below messing with modules is due to the way modules are
- * implemented in Jam. Suppose we are in module M1 now. The global
- * variable map actually holds 'M1' variables, and M1->variables hold
- * global variables.
- *
- * If we call Python right away, Python calls back Jam and then Jam
- * does 'module M1 { }' then Jam will try to swap the current global
- * variables with M1->variables. The result will be that global
- * variables map will hold global variables, and any variable settings
- * we do will go to the global module, not M1.
- *
- * By restoring basic state, where the global variable map holds global
- * variable, we make sure any future 'module M1' entry will work OK.
- */
-
- LIST * result;
- module_t * m = python_module();
-
- frame->module = m;
-
- exit_module( prev_module );
- enter_module( m );
-
- result = call_python_function( rule, frame );
-
- exit_module( m );
- enter_module ( prev_module );
-
- return result;
- }
-#endif
-
- /* Drop the rule name. */
- l = list_pop_front( l );
-
- /* Tack the rest of the expansion onto the front of the first argument. */
- frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) );
+ rule = bindrule( rulename, frame->module );
if ( DEBUG_COMPILE )
{
/* Try hard to indicate in which module the rule is going to execute. */
if ( rule->module != frame->module
- && rule->procedure != 0 && strcmp( rulename, rule->procedure->rulename ) )
+ && rule->procedure != 0 && !object_equal( rulename, function_rulename( rule->procedure ) ) )
{
char buf[256] = "";
- strncat( buf, rule->module->name, sizeof( buf ) - 1 );
- strncat( buf, rule->name, sizeof( buf ) - 1 );
+ if ( rule->module->name )
+ {
+ strncat( buf, object_str( rule->module->name ), sizeof( buf ) - 1 );
+ strncat( buf, ".", sizeof( buf ) - 1 );
+ }
+ strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 );
debug_compile( 1, buf, frame );
}
else
{
- debug_compile( 1, rulename, frame );
+ debug_compile( 1, object_str( rulename ), frame );
}
lol_print( frame->args );
@@ -1024,26 +159,29 @@ evaluate_rule(
{
/* Propagate current module to nested rule invocations. */
frame->module = rule->module;
-
- /* Swap variables. */
- exit_module( prev_module );
- enter_module( rule->module );
}
/* Record current rule name in frame. */
if ( rule->procedure )
{
- frame->rulename = rulename;
+ frame->rulename = object_str( rulename );
/* And enter record profile info. */
if ( DEBUG_PROFILE )
- profile_enter( rule->procedure->rulename, prof );
+ profile_enter( function_rulename( rule->procedure ), prof );
}
/* Check traditional targets $(<) and sources $(>). */
if ( !rule->actions && !rule->procedure )
{
backtrace_line( frame->prev );
- printf( "rule %s unknown in module %s\n", rule->name, frame->module->name );
+ if ( frame->module->name )
+ {
+ printf( "rule %s unknown in module %s\n", object_str( rule->name ), object_str( frame->module->name ) );
+ }
+ else
+ {
+ printf( "rule %s unknown in module \n", object_str( rule->name ) );
+ }
backtrace( frame->prev );
exit( 1 );
}
@@ -1063,6 +201,7 @@ evaluate_rule(
action->rule = rule;
action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) );
action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) );
+ action->refs = 1;
/* If we have a group of targets all being built using the same action
* then we must not allow any of them to be used as sources unless they
@@ -1109,30 +248,21 @@ evaluate_rule(
/* Append this action to the actions of each target. */
for ( t = action->targets; t; t = t->next )
t->target->actions = actionlist( t->target->actions, action );
+
+ action_free( action );
}
/* Now recursively compile any parse tree associated with this rule.
- * parse_refer()/parse_free() call pair added to ensure rule not freed
+ * function_refer()/function_free() call pair added to ensure rule not freed
* during use.
*/
if ( rule->procedure )
{
- SETTINGS * local_args = collect_arguments( rule, frame );
- PARSE * parse = rule->procedure;
- parse_refer( parse );
-
- pushsettings( local_args );
- result = parse_evaluate( parse, frame );
- popsettings( local_args );
- freesettings( local_args );
+ FUNCTION * function = rule->procedure;
- parse_free( parse );
- }
-
- if ( frame->module != prev_module )
- {
- exit_module( frame->module );
- enter_module( prev_module );
+ function_refer( function );
+ result = function_run( function, frame, stack_global() );
+ function_free( function );
}
if ( DEBUG_PROFILE && rule->procedure )
@@ -1154,7 +284,7 @@ evaluate_rule(
* which might be implemented in Jam.
*/
-LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
+LIST * call_rule( OBJECT * rulename, FRAME * caller_frame, ... )
{
va_list va;
LIST * result;
@@ -1165,7 +295,6 @@ LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
inner->prev_user = caller_frame->module->user_module ?
caller_frame : caller_frame->prev_user;
inner->module = caller_frame->module;
- inner->procedure = 0;
va_start( va, caller_frame );
for ( ; ; )
@@ -1185,218 +314,12 @@ LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
}
-/*
- * compile_rules() - compile a chain of rules
- *
- * parse->left single rule
- * parse->right more compile_rules() by right-recursion
- */
-
-LIST * compile_rules( PARSE * parse, FRAME * frame )
-{
- /* Ignore result from first statement; return the 2nd. */
- /* Optimize recursion on the right by looping. */
- do list_free( parse_evaluate( parse->left, frame ) );
- while ( ( parse = parse->right )->func == compile_rules );
- return parse_evaluate( parse, frame );
-}
-
-
-/*
- * assign_var_mode() - convert ASSIGN_XXX compilation flag into corresponding
- * VAR_XXX variable set flag.
- */
-
-static int assign_var_mode( int parsenum, char const * * tracetext )
-{
- char const * trace;
- int setflag;
- switch ( parsenum )
- {
- case ASSIGN_SET : setflag = VAR_SET ; trace = "=" ; break;
- case ASSIGN_APPEND : setflag = VAR_APPEND ; trace = "+="; break;
- case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break;
- default: setflag = VAR_SET ; trace = "" ; break;
- }
- if ( tracetext )
- *tracetext = trace ;
- return setflag;
-}
-
-/*
- * compile_set() - compile the "set variable" statement
- *
- * parse->left variable names
- * parse->right variable values
- * parse->num ASSIGN_SET/APPEND/DEFAULT
- */
-
-LIST * compile_set( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * l;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call var_set to set variable. var_set keeps ns, so need to copy it. */
- for ( l = nt; l; l = list_next( l ) )
- var_set( l->string, list_copy( L0, ns ), setflag );
- list_free( nt );
- return ns;
-}
-
-
-/*
- * compile_setcomp() - support for `rule` - save parse tree.
- *
- * parse->string rule name
- * parse->left rules for rule
- * parse->right optional list-of-lists describing arguments
- */
-
-LIST * compile_setcomp( PARSE * parse, FRAME * frame )
-{
- argument_list * arg_list = 0;
-
- /* Create new LOL describing argument requirements if supplied. */
- if ( parse->right )
- {
- PARSE * p;
- arg_list = args_new();
- for ( p = parse->right; p; p = p->left )
- lol_add( arg_list->data, parse_evaluate( p->right, frame ) );
- }
-
- new_rule_body( frame->module, parse->string, arg_list, parse->left, !parse->num );
- return L0;
-}
-
-
-/*
- * compile_setexec() - support for `actions` - save execution string.
- *
- * parse->string rule name
- * parse->string1 OS command string
- * parse->num flags
- * parse->left `bind` variables
- *
- * Note that the parse flags (as defined in compile.h) are transferred directly
- * to the rule flags (as defined in rules.h).
- */
-
-LIST * compile_setexec( PARSE * parse, FRAME * frame )
-{
- LIST * bindlist = parse_evaluate( parse->left, frame );
- new_rule_actions( frame->module, parse->string, parse->string1, bindlist, parse->num );
- return L0;
-}
-
-
-/*
- * compile_settings() - compile the "on =" (set variable on exec) statement.
- *
- * parse->left variable names
- * parse->right target name
- * parse->third variable value
- * parse->num ASSIGN_SET/APPEND
- */
-
-LIST * compile_settings( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->third, frame );
- LIST * targets = parse_evaluate( parse->right, frame );
- LIST * ts;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " on " );
- list_print( targets );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call addsettings() to save variable setting. addsettings() keeps ns, so
- * need to copy it. Pass append flag to addsettings().
- */
- for ( ts = targets; ts; ts = list_next( ts ) )
- {
- TARGET * t = bindtarget( ts->string );
- LIST * l;
-
- for ( l = nt; l; l = list_next( l ) )
- t->settings = addsettings( t->settings, setflag, l->string,
- list_copy( (LIST *)0, ns ) );
- }
-
- list_free( nt );
- list_free( targets );
- return ns;
-}
-
-
-/*
- * compile_switch() - compile 'switch' rule.
- *
- * parse->left switch value (only 1st used)
- * parse->right cases
- *
- * cases->left 1st case
- * cases->right next cases
- *
- * case->string argument to match
- * case->left parse tree to execute
- */
-
-LIST * compile_switch( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "switch", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- /* Step through cases. */
- for ( parse = parse->right; parse; parse = parse->right )
- {
- if ( !glob( parse->left->string, nt ? nt->string : "" ) )
- {
- /* Get & exec parse tree for this case. */
- parse = parse->left->left;
- result = parse_evaluate( parse, frame );
- break;
- }
- }
-
- list_free( nt );
- return result;
-}
-
/*
* debug_compile() - printf with indent to show rule expansion.
*/
-static void debug_compile( int which, char * s, FRAME * frame )
+static void debug_compile( int which, const char * s, FRAME * frame )
{
static int level = 0;
static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
@@ -1405,7 +328,7 @@ static void debug_compile( int which, char * s, FRAME * frame )
{
int i;
- print_source_line( frame->procedure );
+ print_source_line( frame );
i = ( level + 1 ) * 2;
while ( i > 35 )
diff --git a/tools/build/v2/engine/compile.h b/tools/build/v2/engine/compile.h
index 7d5191f0e1..1c002d90fa 100644
--- a/tools/build/v2/engine/compile.h
+++ b/tools/build/v2/engine/compile.h
@@ -16,6 +16,7 @@
# include "frames.h"
# include "parse.h"
# include "regexp.h"
+# include "object.h"
/*
* compile.h - compile parsed jam statements
@@ -23,30 +24,10 @@
void compile_builtins();
-LIST *compile_append( PARSE *parse, FRAME *frame );
-LIST *compile_foreach( PARSE *parse, FRAME *frame );
-LIST *compile_if( PARSE *parse, FRAME *frame );
-LIST *compile_eval( PARSE *parse, FRAME *args );
-LIST *compile_include( PARSE *parse, FRAME *frame );
-LIST *compile_list( PARSE *parse, FRAME *frame );
-LIST *compile_local( PARSE *parse, FRAME *frame );
-LIST *compile_module( PARSE *parse, FRAME *frame );
-LIST *compile_class( PARSE *parse, FRAME *frame );
-LIST *compile_null( PARSE *parse, FRAME *frame );
-LIST *compile_on( PARSE *parse, FRAME *frame );
-LIST *compile_rule( PARSE *parse, FRAME *frame );
-LIST *compile_rules( PARSE *parse, FRAME *frame );
-LIST *compile_set( PARSE *parse, FRAME *frame );
-LIST *compile_setcomp( PARSE *parse, FRAME *frame );
-LIST *compile_setexec( PARSE *parse, FRAME *frame );
-LIST *compile_settings( PARSE *parse, FRAME *frame );
-LIST *compile_switch( PARSE *parse, FRAME *frame );
-LIST *compile_while( PARSE *parse, FRAME *frame );
-
-LIST *evaluate_rule( char *rulename, FRAME *frame );
-LIST *call_rule( char *rulename, FRAME* caller_frame, ...);
-
-regexp* regex_compile( const char* pattern );
+LIST *evaluate_rule( OBJECT * rulename, FRAME * frame );
+LIST *call_rule( OBJECT * rulename, FRAME * caller_frame, ...);
+
+regexp* regex_compile( OBJECT * pattern );
/* Flags for compile_set(), etc */
diff --git a/tools/build/v2/engine/constants.c b/tools/build/v2/engine/constants.c
new file mode 100644
index 0000000000..3ad534ed75
--- /dev/null
+++ b/tools/build/v2/engine/constants.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "constants.h"
+# include "object.h"
+
+/*
+ * constants.c - constant objects
+ *
+ * External functions:
+ *
+ * constants_init() - initialize constants
+ * constants_done() - free constants
+ *
+ */
+
+void constants_init( void )
+{
+ constant_empty = object_new( "" );
+ constant_dot = object_new( "." );
+ constant_percent = object_new( "%" );
+ constant_plus = object_new( "+" );
+ constant_star = object_new( "*" );
+ constant_question_mark = object_new( "?" );
+ constant_ok = object_new( "ok" );
+ constant_true = object_new( "true" );
+ constant_name = object_new( "__name__" );
+ constant_bases = object_new( "__bases__" );
+ constant_typecheck = object_new( ".typecheck" );
+ constant_builtin = object_new( "(builtin)" );
+ constant_HCACHEFILE = object_new( "HCACHEFILE" );
+ constant_HCACHEMAXAGE = object_new( "HCACHEMAXAGE" );
+ constant_HDRSCAN = object_new( "HDRSCAN" );
+ constant_HDRRULE = object_new( "HDRRULE" );
+ constant_BINDRULE = object_new( "BINDRULE" );
+ constant_LOCATE = object_new( "LOCATE" );
+ constant_SEARCH = object_new( "SEARCH" );
+ constant_JAM_SEMAPHORE = object_new( "JAM_SEMAPHORE" );
+ constant_TIMING_RULE = object_new( "__TIMING_RULE__" );
+ constant_ACTION_RULE = object_new( "__ACTION_RULE__" );
+ constant_JAMSHELL = object_new( "JAMSHELL" );
+ constant_TMPDIR = object_new( "TMPDIR" );
+ constant_TMPNAME = object_new( "TMPNAME" );
+ constant_TMPFILE = object_new( "TMPFILE" );
+ constant_STDOUT = object_new( "STDOUT" );
+ constant_STDERR = object_new( "STDERR" );
+ constant_JAMDATE = object_new( "JAMDATE" );
+ constant_JAM_VERSION = object_new( "JAM_VERSION" );
+ constant_JAMUNAME = object_new( "JAMUNAME" );
+ constant_ENVIRON = object_new( ".ENVIRON" );
+ constant_ARGV = object_new( "ARGV" );
+ constant_all = object_new( "all" );
+ constant_PARALLELISM = object_new( "PARALLELISM" );
+ constant_KEEP_GOING = object_new( "KEEP_GOING" );
+ constant_other = object_new( "[OTHER]" );
+ constant_total = object_new( "[TOTAL]" );
+ constant_FILE_DIRSCAN = object_new( "FILE_DIRSCAN" );
+ constant_MAIN = object_new( "MAIN" );
+ constant_MAIN_MAKE = object_new( "MAIN_MAKE" );
+ constant_MAKE_MAKE0 = object_new( "MAKE_MAKE0" );
+ constant_MAKE_MAKE1 = object_new( "MAKE_MAKE1" );
+ constant_MAKE_MAKE0SORT = object_new( "MAKE_MAKE0SORT" );
+ constant_BINDMODULE = object_new( "BINDMODULE" );
+ constant_IMPORT_MODULE = object_new( "IMPORT_MODULE" );
+ constant_BUILTIN_GLOB_BACK = object_new( "BUILTIN_GLOB_BACK" );
+ constant_timestamp = object_new( "timestamp" );
+ constant_python = object_new("__python__");
+ constant_python_interface = object_new( "python_interface" );
+ constant_extra_pythonpath = object_new( "EXTRA_PYTHONPATH" );
+ constant_MAIN_PYTHON = object_new( "MAIN_PYTHON" );
+}
+
+void constants_done( void )
+{
+ object_free( constant_empty );
+ object_free( constant_dot );
+ object_free( constant_percent );
+ object_free( constant_plus );
+ object_free( constant_star );
+ object_free( constant_question_mark );
+ object_free( constant_ok );
+ object_free( constant_true );
+ object_free( constant_name );
+ object_free( constant_bases );
+ object_free( constant_typecheck );
+ object_free( constant_builtin );
+ object_free( constant_HCACHEFILE );
+ object_free( constant_HCACHEMAXAGE );
+ object_free( constant_HDRSCAN );
+ object_free( constant_HDRRULE );
+ object_free( constant_BINDRULE );
+ object_free( constant_LOCATE );
+ object_free( constant_SEARCH );
+ object_free( constant_JAM_SEMAPHORE );
+ object_free( constant_TIMING_RULE );
+ object_free( constant_ACTION_RULE );
+ object_free( constant_JAMSHELL );
+ object_free( constant_TMPDIR );
+ object_free( constant_TMPNAME );
+ object_free( constant_TMPFILE );
+ object_free( constant_STDOUT );
+ object_free( constant_STDERR );
+ object_free( constant_JAMDATE );
+ object_free( constant_JAM_VERSION );
+ object_free( constant_JAMUNAME );
+ object_free( constant_ENVIRON );
+ object_free( constant_ARGV );
+ object_free( constant_all );
+ object_free( constant_PARALLELISM );
+ object_free( constant_KEEP_GOING );
+ object_free( constant_other );
+ object_free( constant_total );
+ object_free( constant_FILE_DIRSCAN );
+ object_free( constant_MAIN );
+ object_free( constant_MAIN_MAKE );
+ object_free( constant_MAKE_MAKE0 );
+ object_free( constant_MAKE_MAKE1 );
+ object_free( constant_MAKE_MAKE0SORT );
+ object_free( constant_BINDMODULE );
+ object_free( constant_IMPORT_MODULE );
+ object_free( constant_BUILTIN_GLOB_BACK );
+ object_free( constant_timestamp );
+ object_free( constant_python );
+ object_free( constant_python_interface );
+ object_free( constant_extra_pythonpath );
+ object_free( constant_MAIN_PYTHON );
+}
+
+OBJECT * constant_empty;
+OBJECT * constant_dot;
+OBJECT * constant_percent;
+OBJECT * constant_plus;
+OBJECT * constant_star;
+OBJECT * constant_question_mark;
+OBJECT * constant_ok;
+OBJECT * constant_true;
+OBJECT * constant_name;
+OBJECT * constant_bases;
+OBJECT * constant_typecheck;
+OBJECT * constant_builtin;
+OBJECT * constant_HCACHEFILE;
+OBJECT * constant_HCACHEMAXAGE;
+OBJECT * constant_HDRSCAN;
+OBJECT * constant_HDRRULE;
+OBJECT * constant_BINDRULE;
+OBJECT * constant_LOCATE;
+OBJECT * constant_SEARCH;
+OBJECT * constant_JAM_SEMAPHORE;
+OBJECT * constant_TIMING_RULE;
+OBJECT * constant_ACTION_RULE;
+OBJECT * constant_JAMSHELL;
+OBJECT * constant_TMPDIR;
+OBJECT * constant_TMPNAME;
+OBJECT * constant_TMPFILE;
+OBJECT * constant_STDOUT;
+OBJECT * constant_STDERR;
+OBJECT * constant_JAMDATE;
+OBJECT * constant_JAM_VERSION;
+OBJECT * constant_JAMUNAME;
+OBJECT * constant_ENVIRON;
+OBJECT * constant_ARGV;
+OBJECT * constant_all;
+OBJECT * constant_PARALLELISM;
+OBJECT * constant_KEEP_GOING;
+OBJECT * constant_other;
+OBJECT * constant_total;
+OBJECT * constant_FILE_DIRSCAN;
+OBJECT * constant_MAIN;
+OBJECT * constant_MAIN_MAKE;
+OBJECT * constant_MAKE_MAKE0;
+OBJECT * constant_MAKE_MAKE1;
+OBJECT * constant_MAKE_MAKE0SORT;
+OBJECT * constant_BINDMODULE;
+OBJECT * constant_IMPORT_MODULE;
+OBJECT * constant_BUILTIN_GLOB_BACK;
+OBJECT * constant_timestamp;
+OBJECT * constant_python;
+OBJECT * constant_python_interface;
+OBJECT * constant_extra_pythonpath;
+OBJECT * constant_MAIN_PYTHON;
diff --git a/tools/build/v2/engine/constants.h b/tools/build/v2/engine/constants.h
new file mode 100644
index 0000000000..2ec27e800f
--- /dev/null
+++ b/tools/build/v2/engine/constants.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * constants.h - constant objects
+ */
+
+#ifndef BOOST_JAM_CONSTANTS_H
+#define BOOST_JAM_CONSTANTS_H
+
+#include "object.h"
+
+void constants_init( void );
+void constants_done( void );
+
+extern OBJECT * constant_empty; /* "" */
+extern OBJECT * constant_dot; /* "." */
+extern OBJECT * constant_percent; /* "%" */
+extern OBJECT * constant_plus; /* "+" */
+extern OBJECT * constant_star; /* "*" */
+extern OBJECT * constant_question_mark; /* "?" */
+extern OBJECT * constant_ok; /* "ok" */
+extern OBJECT * constant_true; /* "true" */
+extern OBJECT * constant_name; /* "__name__" */
+extern OBJECT * constant_bases; /* "__bases__" */
+extern OBJECT * constant_typecheck; /* ".typecheck" */
+extern OBJECT * constant_builtin; /* "(builtin)" */
+extern OBJECT * constant_HCACHEFILE; /* "HCACHEFILE" */
+extern OBJECT * constant_HCACHEMAXAGE; /* "HCACHEMAXAGE" */
+extern OBJECT * constant_HDRSCAN; /* "HDRSCAN" */
+extern OBJECT * constant_HDRRULE; /* "HDRRULE" */
+extern OBJECT * constant_BINDRULE; /* "BINDRULE" */
+extern OBJECT * constant_LOCATE; /* "LOCATE" */
+extern OBJECT * constant_SEARCH; /* "SEARCH" */
+extern OBJECT * constant_JAM_SEMAPHORE; /* "JAM_SEMAPHORE" */
+extern OBJECT * constant_TIMING_RULE; /* "__TIMING_RULE__" */
+extern OBJECT * constant_ACTION_RULE; /* "__ACTION_RULE__" */
+extern OBJECT * constant_JAMSHELL; /* "JAMSHELL" */
+extern OBJECT * constant_TMPDIR; /* "TMPDIR" */
+extern OBJECT * constant_TMPNAME; /* "TMPNAME" */
+extern OBJECT * constant_TMPFILE; /* "TMPFILE" */
+extern OBJECT * constant_STDOUT; /* "STDOUT" */
+extern OBJECT * constant_STDERR; /* "STDERR" */
+extern OBJECT * constant_JAMDATE; /* "JAMDATE" */
+extern OBJECT * constant_JAM_VERSION; /* "JAM_VERSION" */
+extern OBJECT * constant_JAMUNAME; /* "JAMUNAME" */
+extern OBJECT * constant_ENVIRON; /* ".ENVIRON" */
+extern OBJECT * constant_ARGV; /* "ARGV" */
+extern OBJECT * constant_all; /* "all" */
+extern OBJECT * constant_PARALLELISM; /* "PARALLELISM" */
+extern OBJECT * constant_KEEP_GOING; /* "KEEP_GOING" */
+extern OBJECT * constant_other; /* "[OTHER]" */
+extern OBJECT * constant_total; /* "[TOTAL]" */
+extern OBJECT * constant_FILE_DIRSCAN; /* "FILE_DIRSCAN" */
+extern OBJECT * constant_MAIN; /* "MAIN" */
+extern OBJECT * constant_MAIN_MAKE; /* "MAIN_MAKE" */
+extern OBJECT * constant_MAKE_MAKE0; /* "MAKE_MAKE0" */
+extern OBJECT * constant_MAKE_MAKE1; /* "MAKE_MAKE1" */
+extern OBJECT * constant_MAKE_MAKE0SORT; /* "MAKE_MAKE0SORT" */
+extern OBJECT * constant_BINDMODULE; /* "BINDMODULE" */
+extern OBJECT * constant_IMPORT_MODULE; /* "IMPORT_MODULE" */
+extern OBJECT * constant_BUILTIN_GLOB_BACK; /* "BUILTIN_GLOB_BACK" */
+extern OBJECT * constant_timestamp; /* "timestamp" */
+extern OBJECT * constant_python; /* "__python__" */
+extern OBJECT * constant_python_interface; /* "python_interface" */
+extern OBJECT * constant_extra_pythonpath; /* "EXTRA_PYTHONPATH" */
+extern OBJECT * constant_MAIN_PYTHON; /* "MAIN_PYTHON" */
+
+#endif
diff --git a/tools/build/v2/engine/debug.c b/tools/build/v2/engine/debug.c
index 7290555a74..827356bb83 100644
--- a/tools/build/v2/engine/debug.c
+++ b/tools/build/v2/engine/debug.c
@@ -14,34 +14,41 @@
static profile_frame * profile_stack = 0;
static struct hash * profile_hash = 0;
-static profile_info profile_other = { "[OTHER]", 0, 0, 0, 0, 0 };
-static profile_info profile_total = { "[TOTAL]", 0, 0, 0, 0, 0 };
+static profile_info profile_other = { 0, 0, 0, 0, 0, 0 };
+static profile_info profile_total = { 0, 0, 0, 0, 0, 0 };
-profile_frame * profile_init( char * rulename, profile_frame * frame )
+profile_frame * profile_init( OBJECT * rulename, profile_frame * frame )
{
if ( DEBUG_PROFILE ) profile_enter( rulename, frame );
return frame;
}
-void profile_enter( char * rulename, profile_frame * frame )
+void profile_enter( OBJECT * rulename, profile_frame * frame )
{
if ( DEBUG_PROFILE )
{
clock_t start = clock();
- profile_info info;
- profile_info * p = &info;
-
- if ( !rulename ) p = &profile_other;
+ profile_info * p;
if ( !profile_hash && rulename )
profile_hash = hashinit( sizeof( profile_info ), "profile" );
- info.name = rulename;
-
- if ( rulename && hashenter( profile_hash, (HASHDATA * *)&p ) )
- p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+ if ( rulename )
+ {
+ int found;
+ p = (profile_info *)hash_insert( profile_hash, rulename, &found );
+ if ( !found )
+ {
+ p->name = rulename;
+ p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+ }
+ }
+ else
+ {
+ p = &profile_other;
+ }
++p->num_entries;
++p->stack_count;
@@ -115,7 +122,7 @@ static void dump_profile_entry( void * p_, void * ignored )
profile_total.memory += p->memory;
}
printf( "%10ld %12.6f %12.6f %12.8f %10ld %10ld %s\n", p->num_entries,
- cumulative, net, q, p->memory, mem_each, p->name );
+ cumulative, net, q, p->memory, mem_each, object_str( p->name ) );
}
@@ -126,7 +133,9 @@ void profile_dump()
printf( "%10s %12s %12s %12s %10s %10s %s\n", "--count--", "--gross--",
"--net--", "--each--", "--mem--", "--each--", "--name--" );
hashenumerate( profile_hash, dump_profile_entry, 0 );
+ profile_other.name = constant_other;
dump_profile_entry( &profile_other, 0 );
+ profile_total.name = constant_total;
dump_profile_entry( &profile_total, (void *)1 );
}
}
diff --git a/tools/build/v2/engine/debug.h b/tools/build/v2/engine/debug.h
index 115a88735b..baad262a00 100644
--- a/tools/build/v2/engine/debug.h
+++ b/tools/build/v2/engine/debug.h
@@ -6,6 +6,7 @@
#ifndef BJAM_DEBUG_H
#define BJAM_DEBUG_H
+#include "constants.h"
#include "jam.h"
#include <time.h>
@@ -13,7 +14,7 @@
struct profile_info
{
/* name of rule being called */
- char* name;
+ OBJECT * name;
/* cumulative time spent in rule */
clock_t cumulative;
/* time spent in rule proper */
@@ -42,13 +43,13 @@ struct profile_frame
};
typedef struct profile_frame profile_frame;
-profile_frame * profile_init( char * rulename, profile_frame * frame );
-void profile_enter( char* rulename, profile_frame * frame );
+profile_frame * profile_init( OBJECT * rulename, profile_frame * frame );
+void profile_enter( OBJECT * rulename, profile_frame * frame );
void profile_memory( long mem );
void profile_exit( profile_frame * frame );
void profile_dump();
-#define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( #scope, &PROF_ ## scope )
+#define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( constant_ ## scope, &PROF_ ## scope )
#define PROFILE_EXIT( scope ) profile_exit( PROF_ ## scope ## _p )
#endif
diff --git a/tools/build/v2/engine/execcmd.h b/tools/build/v2/engine/execcmd.h
index 67f2b839c6..9d3cff35b2 100644
--- a/tools/build/v2/engine/execcmd.h
+++ b/tools/build/v2/engine/execcmd.h
@@ -28,16 +28,18 @@ typedef struct timing_info
void exec_cmd
(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
+ const char * string,
+ void (* func)( void * closure, int status, timing_info *, const char *, const char * ),
void * closure,
LIST * shell,
- char * action,
- char * target
+ const char * action,
+ const char * target
);
int exec_wait();
+void exec_done( void );
+
#define EXEC_CMD_OK 0
#define EXEC_CMD_FAIL 1
#define EXEC_CMD_INTR 2
diff --git a/tools/build/v2/engine/execmac.c b/tools/build/v2/engine/execmac.c
deleted file mode 100644
index 2ddddedd15..0000000000
--- a/tools/build/v2/engine/execmac.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-#include "jam.h"
-#include "lists.h"
-#include "execcmd.h"
-#include <errno.h>
-
-#ifdef OS_MAC
-
-/*
- * execunix.c - execute a shell script on UNIX
- *
- * If $(JAMSHELL) is defined, uses that to formulate execvp().
- * The default is:
- *
- * /bin/sh -c %
- *
- * Each word must be an individual element in a jam variable value.
- *
- * In $(JAMSHELL), % expands to the command string and ! expands to
- * the slot number (starting at 1) for multiprocess (-j) invocations.
- * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
- * argument.
- *
- * Don't just set JAMSHELL to /bin/sh - it won't work!
- *
- * External routines:
- * exec_cmd() - launch an async command execution.
- * exec_wait() - wait and drive at most one execution completion.
- *
- * Internal routines:
- * onintr() - bump intr to note command interruption.
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 05/04/94 (seiwald) - async multiprocess interface
- * 01/22/95 (seiwald) - $(JAMSHELL) support
- */
-
-
-/*
- * exec_cmd() - launch an async command execution.
- */
-
-void exec_cmd
-(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
- void * closure,
- LIST * shell
-)
-{
- printf( "%s", string );
- (*func)( closure, EXEC_CMD_OK );
-}
-
-/*
- * exec_wait() - wait and drive at most one execution completion.
- */
-
-int exec_wait()
-{
- return 0;
-}
-
-#endif /* OS_MAC */
diff --git a/tools/build/v2/engine/execnt.c b/tools/build/v2/engine/execnt.c
index 7642045180..f34b378549 100644
--- a/tools/build/v2/engine/execnt.c
+++ b/tools/build/v2/engine/execnt.c
@@ -65,13 +65,13 @@
int maxline();
/* delete and argv list */
-static void free_argv(char**);
+static void free_argv(const char * *);
/* Convert a command string into arguments for spawnvp. */
-static char** string_to_args(const char*);
+static const char** string_to_args(const char*);
/* bump intr to note command interruption */
static void onintr(int);
/* If the command is suitable for execution via spawnvp */
-long can_spawn(char*);
+long can_spawn(const char*);
/* Add two 64-bit unsigned numbers, h1l1 and h2l2 */
static FILETIME add_64(
unsigned long h1, unsigned long l1,
@@ -135,7 +135,7 @@ static struct
int exit_reason; /* reason why a command completed */
/* Function called when the command completes. */
- void (* func)( void * closure, int status, timing_info *, char *, char * );
+ void (* func)( void * closure, int status, timing_info *, const char *, const char * );
/* Opaque data passed back to the 'func' callback called when the command
* completes.
@@ -184,7 +184,7 @@ void execnt_unit_test()
/* Work around vc6 bug; it doesn't like escaped string
* literals inside assert
*/
- char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
+ const char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
char const expected[] = "-c -I\"Foobar\"";
assert( !strcmp( argv[ 0 ], "g++" ) );
@@ -201,26 +201,26 @@ void execnt_unit_test()
void exec_cmd
(
- char * command,
- void (* func)( void * closure, int status, timing_info *, char * invoked_command, char * command_output ),
- void * closure,
- LIST * shell,
- char * action,
- char * target
+ const char * command,
+ void (* func)( void * closure, int status, timing_info *, const char * invoked_command, const char * command_output ),
+ void * closure,
+ LIST * shell,
+ const char * action,
+ const char * target
)
{
int slot;
int raw_cmd = 0 ;
- char * argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
- char * * argv = argv_static;
+ const char * argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
+ const char * * argv = argv_static;
char * p;
- char * command_orig = command;
+ const char * command_orig = command;
/* Check to see if we need to hack around the line-length limitation. Look
* for a JAMSHELL setting of "%", indicating that the command should be
* invoked directly.
*/
- if ( shell && !strcmp( shell->string, "%" ) && !list_next( shell ) )
+ if ( !list_empty( shell ) && !strcmp( object_str( list_front( shell ) ), "%" ) && list_next( list_begin( shell ) ) == list_end( shell ) )
{
raw_cmd = 1;
shell = 0;
@@ -290,8 +290,8 @@ void exec_cmd
if ( DEBUG_EXECCMD )
{
- if ( shell )
- printf( "using user-specified shell: %s", shell->string );
+ if ( !list_empty( shell ) )
+ printf( "using user-specified shell: %s", object_str( list_front( shell ) ) );
else
printf( "Executing through .bat file\n" );
}
@@ -305,16 +305,17 @@ void exec_cmd
int i;
char jobno[ 4 ];
int gotpercent = 0;
+ LISTITER shell_iter = list_begin( shell ), shell_end = list_end( shell );
sprintf( jobno, "%d", slot + 1 );
- for ( i = 0; shell && ( i < MAXARGC ); ++i, shell = list_next( shell ) )
+ for ( i = 0; shell_iter != shell_end && ( i < MAXARGC ); ++i, shell_iter = list_next( shell_iter ) )
{
- switch ( shell->string[ 0 ] )
+ switch ( object_str( list_item( shell_iter ) )[ 0 ] )
{
case '%': argv[ i ] = command; ++gotpercent; break;
case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = shell->string;
+ default : argv[ i ] = object_str( list_item( shell_iter ) );
}
if ( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[ i ] );
@@ -425,7 +426,7 @@ void exec_cmd
/* Put together the command we run. */
{
- char * * argp = argv;
+ const char * * argp = argv;
string_new( &cmd );
string_copy( &cmd, *(argp++) );
while ( *argp )
@@ -577,10 +578,10 @@ int exec_wait()
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-static void free_argv( char * * args )
+static void free_argv( const char * * args )
{
- BJAM_FREE( args[ 0 ] );
- BJAM_FREE( args );
+ BJAM_FREE( (void *)args[ 0 ] );
+ BJAM_FREE( (void *)args );
}
@@ -613,14 +614,14 @@ int maxline()
* New strategy: break the string in at most one place.
*/
-static char * * string_to_args( char const * string )
+static const char * * string_to_args( char const * string )
{
int src_len;
int in_quote;
char * line;
char const * src;
char * dst;
- char * * argv;
+ const char * * argv;
/* Drop leading and trailing whitespace if any. */
while ( isspace( *string ) )
@@ -640,7 +641,7 @@ static char * * string_to_args( char const * string )
* element 1: stores the command-line arguments to the executable
* element 2: NULL terminator
*/
- argv = (char * *)BJAM_MALLOC( 3 * sizeof( char * ) );
+ argv = (const char * *)BJAM_MALLOC( 3 * sizeof( const char * ) );
if ( !argv )
{
BJAM_FREE( line );
@@ -697,9 +698,9 @@ static void onintr( int disp )
* Otherwise, return zero.
*/
-long can_spawn( char * command )
+long can_spawn( const char * command )
{
- char * p;
+ const char * p;
char inquote = 0;
/* Move to the first non-whitespace. */
@@ -1293,4 +1294,10 @@ static void close_alert( HANDLE process )
}
}
+
+void exec_done( void )
+{
+}
+
+
#endif /* USE_EXECNT */
diff --git a/tools/build/v2/engine/execunix.c b/tools/build/v2/engine/execunix.c
index ef9dba0037..147d051cd5 100644
--- a/tools/build/v2/engine/execunix.c
+++ b/tools/build/v2/engine/execunix.c
@@ -88,7 +88,7 @@ static struct
char *target; /* buffer to hold action and target invoked */
char *command; /* buffer to hold command being invoked */
char *buffer[2]; /* buffer to hold stdout and stderr, if any */
- void (*func)( void *closure, int status, timing_info*, char *, char * );
+ void (*func)( void *closure, int status, timing_info*, const char *, const char * );
void *closure;
time_t start_dt; /* start of command timestamp */
} cmdtab[ MAXJOBS ] = {{0}};
@@ -110,12 +110,12 @@ void onintr( int disp )
void exec_cmd
(
- char * string,
- void (*func)( void *closure, int status, timing_info*, char *, char * ),
+ const char * string,
+ void (*func)( void *closure, int status, timing_info*, const char *, const char * ),
void * closure,
LIST * shell,
- char * action,
- char * target
+ const char * action,
+ const char * target
)
{
static int initialized = 0;
@@ -123,7 +123,7 @@ void exec_cmd
int err[2];
int slot;
int len;
- char * argv[ MAXARGC + 1 ]; /* +1 for NULL */
+ const char * argv[ MAXARGC + 1 ]; /* +1 for NULL */
/* Find a slot in the running commands table for this one. */
for ( slot = 0; slot < MAXJOBS; ++slot )
@@ -139,21 +139,22 @@ void exec_cmd
/* Forumulate argv. If shell was defined, be prepared for % and ! subs.
* Otherwise, use stock /bin/sh on unix or cmd.exe on NT.
*/
- if ( shell )
+ if ( !list_empty( shell ) )
{
int i;
char jobno[4];
int gotpercent = 0;
+ LISTITER iter = list_begin( shell ), end = list_end( shell );
sprintf( jobno, "%d", slot + 1 );
- for ( i = 0; shell && i < MAXARGC; ++i, shell = list_next( shell ) )
+ for ( i = 0; iter != end && i < MAXARGC; ++i, iter = list_next( iter ) )
{
- switch ( shell->string[0] )
+ switch ( object_str( list_item( iter ) )[0] )
{
case '%': argv[ i ] = string; ++gotpercent; break;
case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = shell->string;
+ default : argv[ i ] = object_str( list_item( iter ) );
}
if ( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[ i ] );
@@ -242,7 +243,7 @@ void exec_cmd
setrlimit( RLIMIT_CPU, &r_limit );
}
setpgid( pid,pid );
- execvp( argv[0], argv );
+ execvp( argv[0], (char * *)argv );
perror( "execvp" );
_exit( 127 );
}
@@ -566,4 +567,15 @@ int exec_wait()
return 1;
}
+void exec_done( void )
+{
+ int i;
+ for( i = 0; i < MAXJOBS; ++i )
+ {
+ if( ! cmdtab[i].action ) break;
+ BJAM_FREE( cmdtab[i].action );
+ BJAM_FREE( cmdtab[i].target );
+ }
+}
+
# endif /* USE_EXECUNIX */
diff --git a/tools/build/v2/engine/execvms.c b/tools/build/v2/engine/execvms.c
deleted file mode 100644
index 729917d356..0000000000
--- a/tools/build/v2/engine/execvms.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-#include "jam.h"
-#include "lists.h"
-#include "execcmd.h"
-
-#ifdef OS_VMS
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <iodef.h>
-#include <ssdef.h>
-#include <descrip.h>
-#include <dvidef.h>
-#include <clidef.h>
-
-/*
- * execvms.c - execute a shell script, ala VMS.
- *
- * The approach is this:
- *
- * If the command is a single line, and shorter than WRTLEN (what we believe to
- * be the maximum line length), we just system() it.
- *
- * If the command is multi-line, or longer than WRTLEN, we write the command
- * block to a temp file, splitting long lines (using "-" at the end of the line
- * to indicate contiuation), and then source that temp file. We use special
- * logic to make sure we do not continue in the middle of a quoted string.
- *
- * 05/04/94 (seiwald) - async multiprocess interface; noop on VMS
- * 12/20/96 (seiwald) - rewritten to handle multi-line commands well
- * 01/14/96 (seiwald) - do not put -'s between "'s
- */
-
-#define WRTLEN 240
-
-#define MIN( a, b ) ((a) < (b) ? (a) : (b))
-
-/* 1 for the @ and 4 for the .com */
-
-char tempnambuf[ L_tmpnam + 1 + 4 ] = { 0 };
-
-
-void exec_cmd
-(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
- void * closure,
- LIST * shell,
- char * rule_name,
- char * target
-)
-{
- char * s;
- char * e;
- cahr * p;
- int rstat = EXEC_CMD_OK;
- int status;
-
- /* See if string is more than one line discounting leading/trailing white
- * space.
- */
- for ( s = string; *s && isspace( *s ); ++s );
-
- e = p = strchr( s, '\n' );
-
- while ( p && isspace( *p ) )
- ++p;
-
- /* If multi line or long, write to com file. Otherwise, exec directly. */
- if ( ( p && *p ) || ( e - s > WRTLEN ) )
- {
- FILE * f;
-
- /* Create temp file invocation "@sys$scratch:tempfile.com". */
- if ( !*tempnambuf )
- {
- tempnambuf[0] = '@';
- (void)tmpnam( tempnambuf + 1 );
- strcat( tempnambuf, ".com" );
- }
-
- /* Open tempfile. */
- if ( !( f = fopen( tempnambuf + 1, "w" ) ) )
- {
- printf( "can't open command file\n" );
- (*func)( closure, EXEC_CMD_FAIL );
- return;
- }
-
- /* For each line of the string. */
- while ( *string )
- {
- char * s = strchr( string, '\n' );
- int len = s ? s + 1 - string : strlen( string );
-
- fputc( '$', f );
-
- /* For each chunk of a line that needs to be split. */
- while ( len > 0 )
- {
- char * q = string;
- char * qe = string + MIN( len, WRTLEN );
- char * qq = q;
- int quote = 0;
-
- /* Look for matching "s. */
- for ( ; q < qe; ++q )
- if ( ( *q == '"' ) && ( quote = !quote ) )
- qq = q;
-
- /* Back up to opening quote, if in one. */
- if ( quote )
- q = qq;
-
- fwrite( string, ( q - string ), 1, f );
-
- len -= ( q - string );
- string = q;
-
- if ( len )
- {
- fputc( '-', f );
- fputc( '\n', f );
- }
- }
- }
-
- fclose( f );
-
- status = system( tempnambuf ) & 0x07;
-
- unlink( tempnambuf + 1 );
- }
- else
- {
- /* Execute single line command. Strip trailing newline before execing.
- */
- if ( e ) *e = 0;
- status = system( s ) & 0x07;
- }
-
- /* Fail for error or fatal error. OK on OK, warning or info exit. */
- if ( ( status == 2 ) || ( status == 4 ) )
- rstat = EXEC_CMD_FAIL;
-
- (*func)( closure, rstat );
-}
-
-
-int exec_wait()
-{
- return 0;
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/expand.c b/tools/build/v2/engine/expand.c
deleted file mode 100644
index d8e58827c6..0000000000
--- a/tools/build/v2/engine/expand.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-# include "jam.h"
-# include "lists.h"
-# include "variable.h"
-# include "expand.h"
-# include "pathsys.h"
-# include "newstr.h"
-# include <assert.h>
-# include <stdlib.h>
-# include <limits.h>
-
-# ifdef OS_CYGWIN
-# include <sys/cygwin.h>
-# include <windows.h>
-# endif
-
-/*
- * expand.c - expand a buffer, given variable values
- *
- * External routines:
- *
- * var_expand() - variable-expand input string into list of strings
- *
- * Internal routines:
- *
- * var_edit_parse() - parse : modifiers into PATHNAME structure.
- * var_edit_file() - copy input target name to output, modifying filename.
- * var_edit_shift() - do upshift/downshift mods.
- *
- * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval
- */
-
-typedef struct
-{
- PATHNAME f; /* :GDBSMR -- pieces */
- char parent; /* :P -- go to parent directory */
- char filemods; /* one of the above applied */
- char downshift; /* :L -- downshift result */
- char upshift; /* :U -- upshift result */
- char to_slashes; /* :T -- convert "\" to "/" */
- char to_windows; /* :W -- convert cygwin to native paths */
- PATHPART empty; /* :E -- default for empties */
- PATHPART join; /* :J -- join list with char */
-} VAR_EDITS ;
-
-static void var_edit_parse( char * mods, VAR_EDITS * edits );
-static void var_edit_file ( char * in, string * out, VAR_EDITS * edits );
-static void var_edit_shift( string * out, VAR_EDITS * edits );
-
-#define MAGIC_COLON '\001'
-#define MAGIC_LEFT '\002'
-#define MAGIC_RIGHT '\003'
-
-
-/*
- * var_expand() - variable-expand input string into list of strings.
- *
- * Would just copy input to output, performing variable expansion, except that
- * since variables can contain multiple values the result of variable expansion
- * may contain multiple values (a list). Properly performs "product" operations
- * that occur in "$(var1)xxx$(var2)" or even "$($(var2))".
- *
- * Returns a newly created list.
- */
-
-LIST * var_expand( LIST * l, char * in, char * end, LOL * lol, int cancopyin )
-{
- char out_buf[ MAXSYM ];
- string buf[ 1 ];
- string out1[ 1 ]; /* temporary buffer */
- size_t prefix_length;
- char * out;
- char * inp = in;
- char * ov; /* for temp copy of variable in outbuf */
- int depth;
-
- if ( DEBUG_VAREXP )
- printf( "expand '%.*s'\n", end - in, in );
-
- /* This gets a lot of cases: $(<) and $(>). */
- if
- (
- ( in[ 0 ] == '$' ) &&
- ( in[ 1 ] == '(' ) &&
- ( in[ 3 ] == ')' ) &&
- ( in[ 4 ] == '\0' )
- )
- {
- switch ( in[ 2 ] )
- {
- case '<': return list_copy( l, lol_get( lol, 0 ) );
- case '>': return list_copy( l, lol_get( lol, 1 ) );
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return list_copy( l, lol_get( lol, in[ 2 ] - '1' ) );
- }
- }
- else if ( in[0] == '$' && in[1] == '(' && in[2] == '1' && in[4] == ')' &&
- in[5] == '\0') {
-
- switch( in[3] )
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return list_copy( l, lol_get( lol, in[3]-'0'+10-1 ) );
- }
- }
-
- /* Expand @() files, to single item plus accompanying file. */
- if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) && ( *( end - 1 ) == ')' ) )
- {
- /* We try the expansion until it fits within the propective output
- * buffer.
- */
- char * at_buf = 0;
- int at_size = MAXJPATH;
- int at_len = 0;
- do
- {
- BJAM_FREE( at_buf );
- at_buf = (char *)BJAM_MALLOC_ATOMIC( at_size + 1 );
- at_len = var_string( in, at_buf, at_size, lol );
- at_size *= 2;
- }
- while ( ( at_len < 0 ) && ( at_size < INT_MAX / 2 ) );
- /* Return the result as a single item list. */
- if ( at_len > 0 )
- {
- LIST * r;
- string_copy( buf, at_buf );
- r = list_new( l, newstr( buf->value ) );
- string_free( buf );
- BJAM_FREE( at_buf );
- return r;
- }
- BJAM_FREE( at_buf );
- }
-
- /* Just try simple copy of in to out. */
- while ( in < end )
- if ( ( *in++ == '$' ) && ( *in == '(' ) )
- goto expand;
-
- /* No variables expanded - just add copy of input string to list. */
-
- /* 'cancopyin' is an optimization: if the input was already a list item, we
- * can use copystr() to put it on the new list. Otherwise, we use the slower
- * newstr().
- */
- if ( cancopyin )
- return list_new( l, copystr( inp ) );
-
- {
- LIST * r;
- string_new( buf );
- string_append_range( buf, inp, end );
- r = list_new( l, newstr( buf->value ) );
- string_free( buf );
- return r;
- }
-
-expand:
- string_new( buf );
- string_append_range( buf, inp, in - 1 ); /* Copy the part before '$'. */
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^
- * in end
- * Output so far:
- *
- * stuff-in-outbuf $
- * ^ ^
- * out_buf out
- *
- *
- * We just copied the $ of $(...), so back up one on the output. We now find
- * the matching close paren, copying the variable and modifiers between the
- * $( and ) temporarily into out_buf, so that we can replace :'s with
- * MAGIC_COLON. This is necessary to avoid being confused by modifier values
- * that are variables containing :'s. Ugly.
- */
-
- depth = 1;
- inp = ++in; /* Skip over the '('. */
-
- while ( ( in < end ) && depth )
- {
- switch ( *in++ )
- {
- case '(': ++depth; break;
- case ')': --depth; break;
- }
- }
-
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^ ^
- * inp in end
- */
- prefix_length = buf->size;
- string_append_range( buf, inp, in - 1 );
-
- out = buf->value + prefix_length;
- for ( ov = out; ov < buf->value + buf->size; ++ov )
- {
- switch ( *ov )
- {
- case ':': *ov = MAGIC_COLON; break;
- case '[': *ov = MAGIC_LEFT ; break;
- case ']': *ov = MAGIC_RIGHT; break;
- }
- }
-
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^
- * in end
- * Output so far:
- *
- * stuff-in-outbuf variable
- * ^ ^ ^
- * out_buf out ov
- *
- * Later we will overwrite 'variable' in out_buf, but we will be done with
- * it by then. 'variable' may be a multi-element list, so may each value for
- * '$(variable element)', and so may 'remainder'. Thus we produce a product
- * of three lists.
- */
- {
- LIST * variables = 0;
- LIST * remainder = 0;
- LIST * vars;
-
- /* Recursively expand variable name & rest of input. */
- if ( out < ov ) variables = var_expand( L0, out, ov, lol, 0 );
- if ( in < end ) remainder = var_expand( L0, in, end, lol, 0 );
-
- /* Now produce the result chain. */
-
- /* For each variable name. */
- for ( vars = variables; vars; vars = list_next( vars ) )
- {
- LIST * value = 0;
- LIST * evalue = 0;
- char * colon;
- char * bracket;
- string variable[1];
- char * varname;
- int sub1 = 0;
- int sub2 = -1;
- VAR_EDITS edits;
-
- /* Look for a : modifier in the variable name. Must copy into
- * varname so we can modify it.
- */
- string_copy( variable, vars->string );
- varname = variable->value;
-
- if ( ( colon = strchr( varname, MAGIC_COLON ) ) )
- {
- string_truncate( variable, colon - varname );
- var_edit_parse( colon + 1, &edits );
- }
-
- /* Look for [x-y] subscripting. sub1 and sub2 are x and y. */
- if ( ( bracket = strchr( varname, MAGIC_LEFT ) ) )
- {
- /* Make all syntax errors in [] subscripting result in the same
- * behavior: silenty return an empty expansion (by setting sub2
- * = 0). Brute force parsing; May get moved into yacc someday.
- */
-
- char * s = bracket + 1;
-
- string_truncate( variable, bracket - varname );
-
- do /* so we can use "break" */
- {
- /* Allow negative indexes. */
- if ( !isdigit( *s ) && ( *s != '-' ) )
- {
- sub2 = 0;
- break;
- }
- sub1 = atoi( s );
-
- /* Skip over the first symbol, which is either a digit or dash. */
- ++s;
- while ( isdigit( *s ) ) ++s;
-
- if ( *s == MAGIC_RIGHT )
- {
- sub2 = sub1;
- break;
- }
-
- if ( *s != '-' )
- {
- sub2 = 0;
- break;
- }
-
- ++s;
-
- if ( *s == MAGIC_RIGHT )
- {
- sub2 = -1;
- break;
- }
-
- if ( !isdigit( *s ) && ( *s != '-' ) )
- {
- sub2 = 0;
- break;
- }
-
- /* First, compute the index of the last element. */
- sub2 = atoi( s );
- while ( isdigit( *++s ) );
-
- if ( *s != MAGIC_RIGHT )
- sub2 = 0;
-
- } while ( 0 );
-
- /* Anything but the end of the string, or the colon introducing
- * a modifier is a syntax error.
- */
- ++s;
- if ( *s && ( *s != MAGIC_COLON ) )
- sub2 = 0;
-
- *bracket = '\0';
- }
-
- /* Get variable value, with special handling for $(<), $(>), $(n).
- */
- if ( !varname[1] )
- {
- if ( varname[0] == '<' )
- value = lol_get( lol, 0 );
- else if ( varname[0] == '>' )
- value = lol_get( lol, 1 );
- else if ( ( varname[0] >= '1' ) && ( varname[0] <= '9' ) )
- value = lol_get( lol, varname[0] - '1' );
- else if( varname[0] == '1' && varname[1] >= '0' &&
- varname[1] <= '9' && !varname[2] )
- value = lol_get( lol, varname[1] - '0' + 10 - 1 );
- }
-
- if ( !value )
- value = var_get( varname );
-
- /* Handle negitive indexes: part two. */
- {
- int length = list_length( value );
-
- if ( sub1 < 0 )
- sub1 = length + sub1;
- else
- sub1 -= 1;
-
- if ( sub2 < 0 )
- sub2 = length + 1 + sub2 - sub1;
- else
- sub2 -= sub1;
- /* The "sub2 < 0" test handles the semantic error of sub2 <
- * sub1.
- */
- if ( sub2 < 0 )
- sub2 = 0;
- }
-
- /* The fast path: $(x) - just copy the variable value. This is only
- * an optimization.
- */
- if ( ( out == out_buf ) && !bracket && !colon && ( in == end ) )
- {
- string_free( variable );
- l = list_copy( l, value );
- continue;
- }
-
- /* Handle start subscript. */
- while ( ( sub1 > 0 ) && value )
- --sub1, value = list_next( value );
-
- /* Empty w/ :E=default?. */
- if ( !value && colon && edits.empty.ptr )
- evalue = value = list_new( L0, newstr( edits.empty.ptr ) );
-
- /* For each variable value. */
- string_new( out1 );
- for ( ; value; value = list_next( value ) )
- {
- LIST * rem;
- size_t postfix_start;
-
- /* Handle end subscript (length actually). */
-
- if ( sub2 >= 0 && --sub2 < 0 )
- break;
-
- string_truncate( buf, prefix_length );
-
- /* Apply : mods, if present */
-
- if ( colon && edits.filemods )
- var_edit_file( value->string, out1, &edits );
- else
- string_append( out1, value->string );
-
- if ( colon && ( edits.upshift || edits.downshift || edits.to_slashes || edits.to_windows ) )
- var_edit_shift( out1, &edits );
-
- /* Handle :J=joinval */
- /* If we have more values for this var, just keep appending them
- * (using the join value) rather than creating separate LIST
- * elements.
- */
- if ( colon && edits.join.ptr &&
- ( list_next( value ) || list_next( vars ) ) )
- {
- string_append( out1, edits.join.ptr );
- continue;
- }
-
- string_append( buf, out1->value );
- string_free( out1 );
- string_new( out1 );
-
- /* If no remainder, append result to output chain. */
- if ( in == end )
- {
- l = list_new( l, newstr( buf->value ) );
- continue;
- }
-
- /* For each remainder, append the complete string to the output
- * chain. Remember the end of the variable expansion so we can
- * just tack on each instance of 'remainder'.
- */
- postfix_start = buf->size;
- for ( rem = remainder; rem; rem = list_next( rem ) )
- {
- string_truncate( buf, postfix_start );
- string_append( buf, rem->string );
- l = list_new( l, newstr( buf->value ) );
- }
- }
- string_free( out1 );
-
- /* Toss used empty. */
- if ( evalue )
- list_free( evalue );
-
- string_free( variable );
- }
-
- /* variables & remainder were gifts from var_expand and must be freed. */
- if ( variables ) list_free( variables );
- if ( remainder ) list_free( remainder );
-
- if ( DEBUG_VAREXP )
- {
- printf( "expanded to " );
- list_print( l );
- printf( "\n" );
- }
-
- string_free( buf );
- return l;
- }
-}
-
-
-/*
- * var_edit_parse() - parse : modifiers into PATHNAME structure
- *
- * The : modifiers in a $(varname:modifier) currently support replacing or
- * omitting elements of a filename, and so they are parsed into a PATHNAME
- * structure (which contains pointers into the original string).
- *
- * Modifiers of the form "X=value" replace the component X with the given value.
- * Modifiers without the "=value" cause everything but the component X to be
- * omitted. X is one of:
- *
- * G <grist>
- * D directory name
- * B base name
- * S .suffix
- * M (member)
- * R root directory - prepended to whole path
- *
- * This routine sets:
- *
- * f->f_xxx.ptr = 0
- * f->f_xxx.len = 0
- * -> leave the original component xxx
- *
- * f->f_xxx.ptr = string
- * f->f_xxx.len = strlen( string )
- * -> replace component xxx with string
- *
- * f->f_xxx.ptr = ""
- * f->f_xxx.len = 0
- * -> omit component xxx
- *
- * var_edit_file() below and path_build() obligingly follow this convention.
- */
-
-static void var_edit_parse( char * mods, VAR_EDITS * edits )
-{
- int havezeroed = 0;
- memset( (char *)edits, 0, sizeof( *edits ) );
-
- while ( *mods )
- {
- char * p;
- PATHPART * fp;
-
- switch ( *mods++ )
- {
- case 'L': edits->downshift = 1; continue;
- case 'U': edits->upshift = 1; continue;
- case 'P': edits->parent = edits->filemods = 1; continue;
- case 'E': fp = &edits->empty; goto strval;
- case 'J': fp = &edits->join; goto strval;
- case 'G': fp = &edits->f.f_grist; goto fileval;
- case 'R': fp = &edits->f.f_root; goto fileval;
- case 'D': fp = &edits->f.f_dir; goto fileval;
- case 'B': fp = &edits->f.f_base; goto fileval;
- case 'S': fp = &edits->f.f_suffix; goto fileval;
- case 'M': fp = &edits->f.f_member; goto fileval;
- case 'T': edits->to_slashes = 1; continue;
- case 'W': edits->to_windows = 1; continue;
- default:
- return; /* Should complain, but so what... */
- }
-
- fileval:
- /* Handle :CHARS, where each char (without a following =) selects a
- * particular file path element. On the first such char, we deselect all
- * others (by setting ptr = "", len = 0) and for each char we select
- * that element (by setting ptr = 0).
- */
- edits->filemods = 1;
-
- if ( *mods != '=' )
- {
- if ( !havezeroed++ )
- {
- int i;
- for ( i = 0; i < 6; ++i )
- {
- edits->f.part[ i ].len = 0;
- edits->f.part[ i ].ptr = "";
- }
- }
-
- fp->ptr = 0;
- continue;
- }
-
- strval:
- /* Handle :X=value, or :X */
- if ( *mods != '=' )
- {
- fp->ptr = "";
- fp->len = 0;
- }
- else if ( ( p = strchr( mods, MAGIC_COLON ) ) )
- {
- *p = 0;
- fp->ptr = ++mods;
- fp->len = p - mods;
- mods = p + 1;
- }
- else
- {
- fp->ptr = ++mods;
- fp->len = strlen( mods );
- mods += fp->len;
- }
- }
-}
-
-
-/*
- * var_edit_file() - copy input target name to output, modifying filename.
- */
-
-static void var_edit_file( char * in, string * out, VAR_EDITS * edits )
-{
- PATHNAME pathname;
-
- /* Parse apart original filename, putting parts into "pathname". */
- path_parse( in, &pathname );
-
- /* Replace any pathname with edits->f */
- if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
- if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
- if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
- if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
- if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
- if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
-
- /* If requested, modify pathname to point to parent. */
- if ( edits->parent )
- path_parent( &pathname );
-
- /* Put filename back together. */
- path_build( &pathname, out, 0 );
-}
-
-
-/*
- * var_edit_shift() - do upshift/downshift mods.
- */
-
-static void var_edit_shift( string * out, VAR_EDITS * edits )
-{
- /* Handle upshifting, downshifting and slash translation now. */
- char * p;
- for ( p = out->value; *p; ++p)
- {
- if ( edits->upshift )
- *p = toupper( *p );
- else if ( edits->downshift )
- *p = tolower( *p );
- if ( edits->to_slashes && ( *p == '\\' ) )
- *p = '/';
-# ifdef OS_CYGWIN
- if ( edits->to_windows )
- {
- char result[ MAX_PATH + 1 ];
- cygwin_conv_to_win32_path( out->value, result );
- assert( strlen( result ) <= MAX_PATH );
- string_free( out );
- string_copy( out, result );
- }
-# endif
- }
- out->size = p - out->value;
-}
-
-
-#ifndef NDEBUG
-void var_expand_unit_test()
-{
- LOL lol[ 1 ];
- LIST * l;
- LIST * l2;
- LIST * expected = list_new( list_new( L0, newstr( "axb" ) ), newstr( "ayb" ) );
- LIST * e2;
- char axyb[] = "a$(xy)b";
- char azb[] = "a$($(z))b";
- char path[] = "$(p:W)";
-
-# ifdef OS_CYGWIN
- char cygpath[ 256 ];
- cygwin_conv_to_posix_path( "c:\\foo\\bar", cygpath );
-# else
- char cygpath[] = "/cygdrive/c/foo/bar";
-# endif
-
- lol_init(lol);
- var_set( "xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET );
- var_set( "z", list_new( L0, newstr( "xy" ) ), VAR_SET );
- var_set( "p", list_new( L0, newstr( cygpath ) ), VAR_SET );
-
- l = var_expand( 0, axyb, axyb + sizeof( axyb ) - 1, lol, 0 );
- for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next( l2 ), e2 = list_next( e2 ) )
- assert( !strcmp( e2->string, l2->string ) );
- assert( l2 == 0 );
- assert( e2 == 0 );
- list_free( l );
-
- l = var_expand( 0, azb, azb + sizeof( azb ) - 1, lol, 0 );
- for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next( l2 ), e2 = list_next( e2 ) )
- assert( !strcmp( e2->string, l2->string ) );
- assert( l2 == 0 );
- assert( e2 == 0 );
- list_free( l );
-
- l = var_expand( 0, path, path + sizeof( path ) - 1, lol, 0 );
- assert( l != 0 );
- assert( list_next( l ) == 0 );
-# ifdef OS_CYGWIN
- /* On some installations of cygwin the drive letter is expanded to other
- * case. This has been reported to be the case if cygwin has been installed
- * to C:\ as opposed to C:\cygwin. Since case of the drive letter will not
- * matter, we allow for both.
- */
- assert( !strcmp( l->string, "c:\\foo\\bar" ) ||
- !strcmp( l->string, "C:\\foo\\bar" ) );
-# else
- assert( !strcmp( l->string, cygpath ) );
-# endif
- list_free( l );
- list_free( expected );
- lol_free( lol );
-}
-#endif
diff --git a/tools/build/v2/engine/expand.h b/tools/build/v2/engine/expand.h
deleted file mode 100644
index cc25d19090..0000000000
--- a/tools/build/v2/engine/expand.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/*
- * expand.h - expand a buffer, given variable values
- */
-
-#include "lists.h"
-
-LIST *var_expand( LIST *l, char *in, char *end, LOL *lol, int cancopyin );
-void var_expand_unit_test();
diff --git a/tools/build/v2/engine/filemac.c b/tools/build/v2/engine/filemac.c
deleted file mode 100644
index e69aa648f3..0000000000
--- a/tools/build/v2/engine/filemac.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-# ifdef OS_MAC
-
-#include <Files.h>
-#include <Folders.h>
-
-# include <:sys:stat.h>
-
-/*
- * filemac.c - manipulate file names and scan directories on macintosh
- *
- * External routines:
- *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 12/19/94 (mikem) - solaris string table insanity support
- * 02/14/95 (seiwald) - parse and build /xxx properly
- * 05/03/96 (seiwald) - split into pathunix.c
- * 11/21/96 (peterk) - BEOS does not have Unix-style archives
- */
-
-
-void CopyC2PStr( char const * cstr, StringPtr pstr )
-{
- int len;
- for ( len = 0; *cstr && ( len < 255 ); pstr[ ++len ] = *cstr++ );
- pstr[ 0 ] = len;
-}
-
-
-/*
- * file_dirscan() - scan a directory for files.
- */
-
-void file_dirscan( char * dir, scanback func, void * closure )
-{
- PATHNAME f;
- string filename[ 1 ];
- unsigned char fullPath[ 512 ];
-
- FSSpec spec;
- WDPBRec vol;
- Str63 volName;
- CInfoPBRec lastInfo;
- int index = 1;
-
- /* First enter directory itself. */
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
-
- /* Special case ":" - enter it */
-
- if ( ( f.f_dir.len == 1 ) && ( f.f_dir.ptr[0] == ':' ) )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
-
- /* Now enter contents of directory */
-
- vol.ioNamePtr = volName;
-
- if ( PBHGetVolSync( &vol ) )
- return;
-
- CopyC2PStr( dir, fullPath );
-
- if ( FSMakeFSSpec( vol.ioWDVRefNum, vol.ioWDDirID, fullPath, &spec ) )
- return;
-
- lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
- lastInfo.dirInfo.ioDrDirID = spec.parID;
- lastInfo.dirInfo.ioNamePtr = spec.name;
- lastInfo.dirInfo.ioFDirIndex = 0;
- lastInfo.dirInfo.ioACUser = 0;
-
- if ( PBGetCatInfoSync( &lastInfo ) )
- return;
-
- if ( !( lastInfo.dirInfo.ioFlAttrib & 0x10 ) )
- return;
-
- /* ioDrDirID must be reset each time. */
- spec.parID = lastInfo.dirInfo.ioDrDirID;
-
- string_new( filename );
- for ( ; ; )
- {
- lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
- lastInfo.dirInfo.ioDrDirID = spec.parID;
- lastInfo.dirInfo.ioNamePtr = fullPath;
- lastInfo.dirInfo.ioFDirIndex = index++;
-
- if ( PBGetCatInfoSync( &lastInfo ) )
- return;
-
- f.f_base.ptr = (char *)fullPath + 1;
- f.f_base.len = *fullPath;
-
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
- (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 );
- }
- string_free( filename );
-}
-
-
-/*
- * file_time() - get timestamp of file, if not done by file_dirscan().
- */
-
-int file_time( char * filename, time_t * time )
-{
- struct stat statbuf;
-
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
-
- *time = statbuf.st_mtime;
-
- return 0;
-}
-
-
-int file_is_file( char * filename )
-{
- struct stat statbuf;
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
- return S_ISREG( statbuf.st_mode ) ? 1 : 0;
-}
-
-int file_mkdir(char *pathname)
-{
- return mkdir(pathname, 0766);
-}
-
-
-/*
- * file_archscan() - scan an archive for files.
- */
-
-void file_archscan( char * archive, scanback func, void * closure )
-{
-}
-
-
-# endif /* macintosh */
diff --git a/tools/build/v2/engine/filent.c b/tools/build/v2/engine/filent.c
index ab18957677..b448cd03f7 100644
--- a/tools/build/v2/engine/filent.c
+++ b/tools/build/v2/engine/filent.c
@@ -16,7 +16,7 @@
# include "filesys.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# ifdef OS_NT
@@ -57,20 +57,19 @@
* file_dirscan() - scan a directory for files
*/
-void file_dirscan( char * dir, scanback func, void * closure )
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
{
PROFILE_ENTER( FILE_DIRSCAN );
file_info_t * d = 0;
- dir = short_path_to_long_path( dir );
-
/* First enter directory itself */
d = file_query( dir );
if ( !d || !d->is_dir )
{
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -84,11 +83,15 @@ void file_dirscan( char * dir, scanback func, void * closure )
int ret;
struct _finddata_t finfo[ 1 ];
LIST * files = L0;
- int d_length = strlen( d->name );
+ int d_length;
+
+ dir = short_path_to_long_path( dir );
+
+ d_length = strlen( object_str( dir ) );
memset( (char *)&f, '\0', sizeof( f ) );
- f.f_dir.ptr = d->name;
+ f.f_dir.ptr = object_str( dir );
f.f_dir.len = d_length;
/* Now enter contents of directory */
@@ -103,8 +106,8 @@ void file_dirscan( char * dir, scanback func, void * closure )
* its trailing path separator or otherwise we would not support the
* Windows root folder specified without its drive letter, i.e. '\'.
*/
- char trailingChar = d->name[ d_length - 1 ] ;
- string_copy( filespec, d->name );
+ char trailingChar = object_str( dir )[ d_length - 1 ] ;
+ string_copy( filespec, object_str( dir ) );
if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
string_append( filespec, "\\" );
string_append( filespec, "*" );
@@ -117,6 +120,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
{
string_free( filespec );
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -132,7 +136,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename );
- files = list_new( files, newstr(filename->value) );
+ files = list_push_back( files, object_new(filename->value) );
ff = file_info( filename->value );
ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0;
@@ -147,6 +151,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
if ( ret = ( handle < 0L ) )
{
string_free( filespec );
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -154,6 +159,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_new( filename );
while ( !ret )
{
+ OBJECT * filename_obj;
file_info_t * ff = 0;
f.f_base.ptr = finfo->name;
@@ -162,8 +168,10 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename, 0 );
- files = list_new( files, newstr( filename->value ) );
- ff = file_info( filename->value );
+ filename_obj = object_new( filename->value );
+ path_add_key( filename_obj );
+ files = list_push_back( files, filename_obj );
+ ff = file_info( filename_obj );
ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0;
ff->size = finfo->size;
@@ -176,17 +184,26 @@ void file_dirscan( char * dir, scanback func, void * closure )
# endif
string_free( filename );
string_free( filespec );
+ object_free( dir );
d->files = files;
}
/* Special case \ or d:\ : enter it */
{
- unsigned long len = strlen(d->name);
- if ( len == 1 && d->name[0] == '\\' )
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
- else if ( len == 3 && d->name[1] == ':' ) {
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
+ unsigned long len = strlen( object_str( d->name ) );
+ if ( len == 1 && object_str( d->name )[0] == '\\' )
+ {
+ OBJECT * dir = short_path_to_long_path( d->name );
+ (*func)( closure, dir, 1 /* stat()'ed */, d->time );
+ object_free( dir );
+ }
+ else if ( len == 3 && object_str( d->name )[1] == ':' )
+ {
+ char buf[4];
+ OBJECT * dir1 = short_path_to_long_path( d->name );
+ OBJECT * dir2;
+ (*func)( closure, dir1, 1 /* stat()'ed */, d->time );
/* We've just entered 3-letter drive name spelling (with trailing
slash), into the hash table. Now enter two-letter variant,
without trailing slash, so that if we try to check whether
@@ -199,34 +216,38 @@ void file_dirscan( char * dir, scanback func, void * closure )
There will be no trailing slash in $(p), but there will be one
in $(p2). But, that seems rather fragile.
*/
- d->name[2] = 0;
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
+ strcpy( buf, object_str( dir1 ) );
+ buf[2] = 0;
+ dir2 = object_new( buf );
+ (*func)( closure, dir2, 1 /* stat()'ed */, d->time );
+ object_free( dir2 );
+ object_free( dir1 );
}
}
/* Now enter contents of directory */
- if ( d->files )
+ if ( !list_empty( d->files ) )
{
LIST * files = d->files;
- while ( files )
+ LISTITER iter = list_begin( files ), end = list_end( files );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- file_info_t * ff = file_info( files->string );
- (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
- files = list_next( files );
+ file_info_t * ff = file_info( list_item( iter ) );
+ (*func)( closure, list_item( iter ), 1 /* stat()'ed */, ff->time );
}
}
PROFILE_EXIT( FILE_DIRSCAN );
}
-file_info_t * file_query( char * filename )
+file_info_t * file_query( OBJECT * filename )
{
file_info_t * ff = file_info( filename );
if ( ! ff->time )
{
struct stat statbuf;
- if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
+ if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
return 0;
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
@@ -243,8 +264,8 @@ file_info_t * file_query( char * filename )
int
file_time(
- char *filename,
- time_t *time )
+ OBJECT * filename,
+ time_t * time )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
@@ -252,14 +273,14 @@ file_time(
return 0;
}
-int file_is_file(char* filename)
+int file_is_file( OBJECT * filename )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
return ff->is_file;
}
-int file_mkdir(char *pathname)
+int file_mkdir( const char * pathname )
{
return _mkdir(pathname);
}
@@ -290,9 +311,9 @@ struct ar_hdr {
void
file_archscan(
- char *archive,
- scanback func,
- void *closure )
+ const char * archive,
+ scanback func,
+ void * closure )
{
struct ar_hdr ar_hdr;
char *string_table = 0;
@@ -320,9 +341,10 @@ file_archscan(
{
long lar_date;
long lar_size;
- char *name = 0;
- char *endname;
- char *c;
+ char * name = 0;
+ char * endname;
+ char * c;
+ OBJECT * member;
sscanf( ar_hdr.ar_date, "%ld", &lar_date );
sscanf( ar_hdr.ar_size, "%ld", &lar_size );
@@ -375,7 +397,9 @@ file_archscan(
name = c + 1;
sprintf( buf, "%s(%.*s)", archive, endname - name, name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
offset += SARHDR + lar_size;
lseek( fd, offset, 0 );
diff --git a/tools/build/v2/engine/fileos2.c b/tools/build/v2/engine/fileos2.c
deleted file mode 100644
index af2373ea83..0000000000
--- a/tools/build/v2/engine/fileos2.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-/* note that we use "fileunix.c" when compiling with EMX on OS/2 */
-# if defined(OS_OS2) && !defined(__EMX__)
-
-# include <io.h>
-# include <dos.h>
-
-/*
- * fileos2.c - scan directories and archives on NT
- *
- * External routines:
- *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 07/10/95 (taylor) Findfirst() returns the first file on NT.
- * 05/03/96 (seiwald) split apart into pathnt.c
- * 09/22/00 (seiwald) handle \ and c:\ specially: don't add extra /
- */
-
-/*
- * file_dirscan() - scan a directory for files
- */
-
-void
-file_dirscan(
- char *dir,
- scanback func,
- void *closure )
-{
- PATHNAME f;
- string filespec[1];
- long handle;
- int ret;
- struct _find_t finfo[1];
-
- /* First enter directory itself */
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
-
- dir = *dir ? dir : ".";
-
- /* Special case \ or d:\ : enter it */
- string_copy( filespec, dir );
-
- if ( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
- else if ( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
- else
- string_push_back( filespec, '/' );
-
- string_push_back( filespec, '*' );
-
- /* Now enter contents of directory */
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", filespec->value );
-
- /* Time info in dos find_t is not very useful. It consists */
- /* of a separate date and time, and putting them together is */
- /* not easy. So we leave that to a later stat() call. */
-
- if ( !_dos_findfirst( filespec->value, _A_NORMAL|_A_RDONLY|_A_SUBDIR, finfo ) )
- {
- string filename[1];
- string_new( filename );
- do
- {
- f.f_base.ptr = finfo->name;
- f.f_base.len = strlen( finfo->name );
-
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
- (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 );
- }
- while ( !_dos_findnext( finfo ) );
- string_free( filename );
- }
-}
-
-/*
- * file_time() - get timestamp of file, if not done by file_dirscan()
- */
-
-int
-file_time(
- char *filename,
- time_t *time )
-{
- /* This is called on OS2, not NT. */
- /* NT fills in the time in the dirscan. */
-
- struct stat statbuf;
-
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
-
- *time = statbuf.st_mtime;
-
- return 0;
-}
-
-void
-file_archscan(
- char *archive,
- scanback func,
- void *closure )
-{
-}
-
-# endif /* OS2 && !__EMX__ */
-
diff --git a/tools/build/v2/engine/filesys.c b/tools/build/v2/engine/filesys.c
index eb62ed4060..8d174cfd8b 100644
--- a/tools/build/v2/engine/filesys.c
+++ b/tools/build/v2/engine/filesys.c
@@ -1,7 +1,7 @@
# include "jam.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# include "filesys.h"
# include "lists.h"
@@ -36,25 +36,30 @@ void file_build1( PATHNAME * f, string * file )
static struct hash * filecache_hash = 0;
static file_info_t filecache_finfo;
-file_info_t * file_info(char * filename)
+file_info_t * file_info( OBJECT * filename )
{
file_info_t *finfo = &filecache_finfo;
+ int found;
if ( !filecache_hash )
filecache_hash = hashinit( sizeof( file_info_t ), "file_info" );
- finfo->name = filename;
- finfo->is_file = 0;
- finfo->is_dir = 0;
- finfo->size = 0;
- finfo->time = 0;
- finfo->files = 0;
- if ( hashenter( filecache_hash, (HASHDATA**)&finfo ) )
+ filename = path_as_key( filename );
+
+ finfo = (file_info_t *)hash_insert( filecache_hash, filename, &found );
+ if ( !found )
{
/* printf( "file_info: %s\n", filename ); */
- finfo->name = newstr( finfo->name );
+ finfo->name = object_copy( filename );
+ finfo->is_file = 0;
+ finfo->is_dir = 0;
+ finfo->size = 0;
+ finfo->time = 0;
+ finfo->files = L0;
}
+ object_free( filename );
+
return finfo;
}
@@ -62,22 +67,33 @@ static LIST * files_to_remove = L0;
static void remove_files_atexit(void)
{
- /* we do pop front in case this exit function is called
- more than once */
- while ( files_to_remove )
+ LISTITER iter = list_begin( files_to_remove ), end = list_end( files_to_remove );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- remove( files_to_remove->string );
- files_to_remove = list_pop_front( files_to_remove );
+ remove( object_str( list_item( iter ) ) );
}
+ list_free( files_to_remove );
+ files_to_remove = L0;
+}
+
+static void free_file_info ( void * xfile, void * data )
+{
+ file_info_t * file = (file_info_t *)xfile;
+ object_free( file->name );
+ list_free( file->files );
}
void file_done()
{
remove_files_atexit();
- hashdone( filecache_hash );
+ if ( filecache_hash )
+ {
+ hashenumerate( filecache_hash, free_file_info, (void *)0 );
+ hashdone( filecache_hash );
+ }
}
-void file_remove_atexit( const char * path )
+void file_remove_atexit( OBJECT * path )
{
- files_to_remove = list_new( files_to_remove, newstr((char*)path) );
+ files_to_remove = list_push_back( files_to_remove, object_copy( path ) );
}
diff --git a/tools/build/v2/engine/filesys.h b/tools/build/v2/engine/filesys.h
index efc081d120..d32805126e 100644
--- a/tools/build/v2/engine/filesys.h
+++ b/tools/build/v2/engine/filesys.h
@@ -20,22 +20,23 @@
# include "pathsys.h"
#include "hash.h"
#include "lists.h"
+#include "object.h"
-typedef void (*scanback)( void *closure, char *file, int found, time_t t );
+typedef void (*scanback)( void *closure, OBJECT * file, int found, time_t t );
-void file_dirscan( char *dir, scanback func, void *closure );
-void file_archscan( char *arch, scanback func, void *closure );
+void file_dirscan( OBJECT * dir, scanback func, void * closure );
+void file_archscan( const char * arch, scanback func, void * closure );
-int file_time( char *filename, time_t *time );
+int file_time( OBJECT * filename, time_t * time );
void file_build1(PATHNAME *f, string* file) ;
-int file_is_file(char* filename);
-int file_mkdir(char *pathname);
+int file_is_file( OBJECT * filename );
+int file_mkdir( const char * pathname );
typedef struct file_info_t file_info_t ;
struct file_info_t
{
- char * name;
+ OBJECT * name;
short is_file;
short is_dir;
unsigned long size;
@@ -47,14 +48,14 @@ struct file_info_t
/* Creates a pointer to information about file 'filename', creating it as
* necessary. If created, the structure will be default initialized.
*/
-file_info_t * file_info( char * filename );
+file_info_t * file_info( OBJECT * filename );
/* Returns information about a file, queries the OS if needed. */
-file_info_t * file_query( char * filename );
+file_info_t * file_query( OBJECT * filename );
void file_done();
/* Marks a path/file to be removed when jam exits. */
-void file_remove_atexit( const char * path );
+void file_remove_atexit( OBJECT * path );
#endif
diff --git a/tools/build/v2/engine/fileunix.c b/tools/build/v2/engine/fileunix.c
index 680c3f5394..d8b458c9ba 100644
--- a/tools/build/v2/engine/fileunix.c
+++ b/tools/build/v2/engine/fileunix.c
@@ -15,7 +15,7 @@
# include "filesys.h"
# include "strings.h"
# include "pathsys.h"
-# include "newstr.h"
+# include "object.h"
# include <stdio.h>
# include <sys/stat.h>
@@ -125,7 +125,7 @@ struct ar_hdr /* archive file member header - printable ascii */
* file_dirscan() - scan a directory for files.
*/
-void file_dirscan( char * dir, scanback func, void * closure )
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
{
PROFILE_ENTER( FILE_DIRSCAN );
@@ -139,37 +139,39 @@ void file_dirscan( char * dir, scanback func, void * closure )
return;
}
- if ( ! d->files )
+ if ( list_empty( d->files ) )
{
LIST* files = L0;
PATHNAME f;
DIR *dd;
STRUCT_DIRENT *dirent;
string filename[1];
+ const char * dirstr = object_str( dir );
/* First enter directory itself */
memset( (char *)&f, '\0', sizeof( f ) );
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
+ f.f_dir.ptr = dirstr;
+ f.f_dir.len = strlen( dirstr );
- dir = *dir ? dir : ".";
+ dirstr = *dirstr ? dirstr : ".";
/* Now enter contents of directory. */
- if ( !( dd = opendir( dir ) ) )
+ if ( !( dd = opendir( dirstr ) ) )
{
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
+ printf( "scan directory %s\n", dirstr );
string_new( filename );
while ( ( dirent = readdir( dd ) ) )
{
+ OBJECT * filename_obj;
# ifdef old_sinix
/* Broken structure definition on sinix. */
f.f_base.ptr = dirent->d_name - 2;
@@ -181,8 +183,9 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename, 0 );
- files = list_new( files, newstr(filename->value) );
- file_query( filename->value );
+ filename_obj = object_new( filename->value );
+ files = list_push_back( files, filename_obj );
+ file_query( filename_obj );
}
string_free( filename );
@@ -193,18 +196,18 @@ void file_dirscan( char * dir, scanback func, void * closure )
/* Special case / : enter it */
{
- unsigned long len = strlen(d->name);
- if ( ( len == 1 ) && ( d->name[0] == '/' ) )
+ if ( strcmp( object_str( d->name ), "/" ) == 0 )
(*func)( closure, d->name, 1 /* stat()'ed */, d->time );
}
/* Now enter contents of directory */
- if ( d->files )
+ if ( !list_empty( d->files ) )
{
LIST * files = d->files;
- while ( files )
+ LISTITER iter = list_begin( files ), end = list_end( files );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- file_info_t * ff = file_info( files->string );
+ file_info_t * ff = file_info( list_item( iter ) );
(*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
files = list_next( files );
}
@@ -214,14 +217,14 @@ void file_dirscan( char * dir, scanback func, void * closure )
}
-file_info_t * file_query( char * filename )
+file_info_t * file_query( OBJECT * filename )
{
file_info_t * ff = file_info( filename );
if ( ! ff->time )
{
struct stat statbuf;
- if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
+ if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
return 0;
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
@@ -238,8 +241,8 @@ file_info_t * file_query( char * filename )
int
file_time(
- char *filename,
- time_t *time )
+ OBJECT * filename,
+ time_t * time )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
@@ -247,16 +250,16 @@ file_time(
return 0;
}
-int file_is_file(char* filename)
+int file_is_file( OBJECT * filename )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
return ff->is_file;
}
-int file_mkdir(char* pathname)
+int file_mkdir( const char * pathname )
{
- return mkdir(pathname, 0766);
+ return mkdir( pathname, 0766 );
}
/*
@@ -270,9 +273,9 @@ int file_mkdir(char* pathname)
void
file_archscan(
- char *archive,
+ const char * archive,
scanback func,
- void *closure )
+ void * closure )
{
# ifndef NO_AR
struct ar_hdr ar_hdr;
@@ -312,6 +315,7 @@ file_archscan(
char * c;
char * src;
char * dest;
+ OBJECT * member;
strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
@@ -356,14 +360,16 @@ file_archscan(
sprintf( buf, "%s(%s)", archive, lar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
lseek( fd, offset, 0 );
}
- if (string_table)
- BJAM_FREE(string_table);
+ if ( string_table )
+ BJAM_FREE( string_table );
close( fd );
@@ -396,10 +402,11 @@ static void file_archscan_small(
while ( ( offset > 0 )
&& ( lseek( fd, offset, 0 ) >= 0 )
- && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) )
+ && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) ) )
{
long lar_date;
int lar_namlen;
+ OBJECT * member;
sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
sscanf( ar_hdr.hdr.ar_date , "%ld", &lar_date );
@@ -412,7 +419,9 @@ static void file_archscan_small(
sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
}
}
@@ -446,6 +455,7 @@ static void file_archscan_big(
{
long lar_date;
int lar_namlen;
+ OBJECT * member;
sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
sscanf( ar_hdr.hdr.ar_date , "%ld" , &lar_date );
@@ -458,19 +468,21 @@ static void file_archscan_big(
sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
}
}
#endif /* AR_HSZ_BIG */
-void file_archscan(char *archive, scanback func, void *closure)
+void file_archscan( const char * archive, scanback func, void *closure)
{
int fd;
char fl_magic[SAIAMAG];
- if (( fd = open(archive, O_RDONLY, 0)) < 0)
+ if (( fd = open( archive, O_RDONLY, 0)) < 0)
return;
if (read( fd, fl_magic, SAIAMAG) != SAIAMAG
@@ -480,16 +492,16 @@ void file_archscan(char *archive, scanback func, void *closure)
return;
}
- if (strncmp(AIAMAG, fl_magic, SAIAMAG) == 0)
+ if ( strncmp( AIAMAG, fl_magic, SAIAMAG ) == 0 )
{
/* read small variant */
- file_archscan_small(fd, archive, func, closure);
+ file_archscan_small( fd, archive, func, closure );
}
#ifdef AR_HSZ_BIG
- else if (strncmp(AIAMAGBIG, fl_magic, SAIAMAG) == 0)
+ else if ( strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) == 0 )
{
/* read big variant */
- file_archscan_big(fd, archive, func, closure);
+ file_archscan_big( fd, archive, func, closure );
}
#endif
diff --git a/tools/build/v2/engine/filevms.c b/tools/build/v2/engine/filevms.c
deleted file mode 100644
index d2ab2047f0..0000000000
--- a/tools/build/v2/engine/filevms.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-# ifdef OS_VMS
-
-/*
- * filevms.c - scan directories and libaries on VMS
- *
- * External routines:
- *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
- * 05/03/96 (seiwald) - split into pathvms.c
- */
-
-# include <rms.h>
-# include <iodef.h>
-# include <ssdef.h>
-# include <string.h>
-# include <stdlib.h>
-# include <stdio.h>
-# include <descrip.h>
-
-#include <lbrdef.h>
-#include <credef.h>
-#include <mhddef.h>
-#include <lhidef.h>
-#include <lib$routines.h>
-#include <starlet.h>
-
-/* Supply missing prototypes for lbr$-routines*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-int lbr$set_module(
- void **,
- unsigned long *,
- struct dsc$descriptor_s *,
- unsigned short *,
- void * );
-
-int lbr$open( void **,
- struct dsc$descriptor_s *,
- void *,
- void *,
- void *,
- void *,
- void * );
-
-int lbr$ini_control(
- void **,
- unsigned long *,
- unsigned long *,
- void * );
-
-int lbr$get_index(
- void **,
- unsigned long *,
- int (*func)( struct dsc$descriptor_s *, unsigned long *),
- void * );
-
-int lbr$close(
- void ** );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-static void
-file_cvttime(
- unsigned int *curtime,
- time_t *unixtime )
-{
- static const size_t divisor = 10000000;
- static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
- int delta[2], remainder;
-
- lib$subx( curtime, bastim, delta );
- lib$ediv( &divisor, delta, unixtime, &remainder );
-}
-
-# define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
-
-# define min( a,b ) ((a)<(b)?(a):(b))
-
-void
-file_dirscan(
- char *dir,
- scanback func,
- void *closure )
-{
-
- struct FAB xfab;
- struct NAM xnam;
- struct XABDAT xab;
- char esa[256];
- char filename[256];
- string filename2[1];
- char dirname[256];
- register int status;
- PATHNAME f;
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_root.ptr = dir;
- f.f_root.len = strlen( dir );
-
- /* get the input file specification
- */
- xnam = cc$rms_nam;
- xnam.nam$l_esa = esa;
- xnam.nam$b_ess = sizeof( esa ) - 1;
- xnam.nam$l_rsa = filename;
- xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS );
-
- xab = cc$rms_xabdat; /* initialize extended attributes */
- xab.xab$b_cod = XAB$C_DAT; /* ask for date */
- xab.xab$l_nxt = NULL; /* terminate XAB chain */
-
- xfab = cc$rms_fab;
- xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION;
- xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1;
- xfab.fab$l_fop = FAB$M_NAM;
- xfab.fab$l_fna = dir; /* address of file name */
- xfab.fab$b_fns = strlen( dir ); /* length of file name */
- xfab.fab$l_nam = &xnam; /* address of NAB block */
- xfab.fab$l_xab = (char *)&xab; /* address of XAB block */
-
-
- status = sys$parse( &xfab );
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
-
- if ( !( status & 1 ) )
- return;
-
-
-
- /* Add bogus directory for [000000] */
-
- if ( !strcmp( dir, "[000000]" ) )
- {
- (*func)( closure, "[000000]", 1 /* time valid */, 1 /* old but true */ );
- }
-
- /* Add bogus directory for [] */
-
- if ( !strcmp( dir, "[]" ) )
- {
- (*func)( closure, "[]", 1 /* time valid */, 1 /* old but true */ );
- (*func)( closure, "[-]", 1 /* time valid */, 1 /* old but true */ );
- }
-
- string_new( filename2 );
- while ( (status = sys$search( &xfab )) & 1 )
- {
- char *s;
- time_t time;
-
- /* "I think that might work" - eml */
-
- sys$open( &xfab );
- sys$close( &xfab );
-
- file_cvttime( (unsigned int *)&xab.xab$q_rdt, &time );
-
- filename[xnam.nam$b_rsl] = '\0';
-
- /* What we do with the name depends on the suffix: */
- /* .dir is a directory */
- /* .xxx is a file with a suffix */
- /* . is no suffix at all */
-
- if ( xnam.nam$b_type == 4 && !strncmp( xnam.nam$l_type, ".DIR", 4 ) )
- {
- /* directory */
- sprintf( dirname, "[.%.*s]", xnam.nam$b_name, xnam.nam$l_name );
- f.f_dir.ptr = dirname;
- f.f_dir.len = strlen( dirname );
- f.f_base.ptr = 0;
- f.f_base.len = 0;
- f.f_suffix.ptr = 0;
- f.f_suffix.len = 0;
- }
- else
- {
- /* normal file with a suffix */
- f.f_dir.ptr = 0;
- f.f_dir.len = 0;
- f.f_base.ptr = xnam.nam$l_name;
- f.f_base.len = xnam.nam$b_name;
- f.f_suffix.ptr = xnam.nam$l_type;
- f.f_suffix.len = xnam.nam$b_type;
- }
-
- string_truncate( filename2, 0 );
- path_build( &f, filename2, 0 );
-
- /*
- if ( DEBUG_SEARCH )
- printf("root '%s' base %.*s suf %.*s = %s\n",
- dir,
- xnam.nam$b_name, xnam.nam$l_name,
- xnam.nam$b_type, xnam.nam$l_type,
- filename2 );
- */
-
- (*func)( closure, filename2->value, 1 /* time valid */, time );
- }
- string_free( filename2 );
-}
-
-int
-file_time(
- char *filename,
- time_t *time )
-{
- /* This should never be called, as all files are */
- /* timestampped in file_dirscan() and file_archscan() */
- return -1;
-}
-
-static char *VMS_archive = 0;
-static scanback VMS_func;
-static void *VMS_closure;
-static void *context;
-
-static int
-file_archmember(
- struct dsc$descriptor_s *module,
- unsigned long *rfa )
-{
- static struct dsc$descriptor_s bufdsc =
- {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
-
- struct mhddef *mhd;
- char filename[128];
- char buf[ MAXJPATH ];
-
- int status;
- time_t library_date;
-
- register int i;
- register char *p;
-
- bufdsc.dsc$a_pointer = filename;
- bufdsc.dsc$w_length = sizeof( filename );
- status = lbr$set_module( &context, rfa, &bufdsc,
- &bufdsc.dsc$w_length, NULL );
-
- if ( !(status & 1) )
- return ( 1 );
-
- mhd = (struct mhddef *)filename;
-
- file_cvttime( &mhd->mhd$l_datim, &library_date );
-
- for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; ++i, ++p )
- filename[ i ] = *p;
-
- filename[ i ] = '\0';
-
- sprintf( buf, "%s(%s.obj)", VMS_archive, filename );
-
- (*VMS_func)( VMS_closure, buf, 1 /* time valid */, (time_t)library_date );
-
- return ( 1 );
-}
-
-
-void file_archscan( char * archive, scanback func, void * closure )
-{
- static struct dsc$descriptor_s library =
- {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
-
- unsigned long lfunc = LBR$C_READ;
- unsigned long typ = LBR$C_TYP_UNK;
- unsigned long index = 1;
-
- register int status;
-
- VMS_archive = archive;
- VMS_func = func;
- VMS_closure = closure;
-
- status = lbr$ini_control( &context, &lfunc, &typ, NULL );
- if ( !( status & 1 ) )
- return;
-
- library.dsc$a_pointer = archive;
- library.dsc$w_length = strlen( archive );
-
- status = lbr$open( &context, &library, NULL, NULL, NULL, NULL, NULL );
- if ( !( status & 1 ) )
- return;
-
- (void) lbr$get_index( &context, &index, file_archmember, NULL );
-
- (void) lbr$close( &context );
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/frames.c b/tools/build/v2/engine/frames.c
index 84889f09e7..29f7f03cde 100644
--- a/tools/build/v2/engine/frames.c
+++ b/tools/build/v2/engine/frames.c
@@ -13,7 +13,8 @@ void frame_init( FRAME* frame )
lol_init(frame->args);
frame->module = root_module();
frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
}
void frame_free( FRAME* frame )
diff --git a/tools/build/v2/engine/frames.h b/tools/build/v2/engine/frames.h
index 693d77fa0a..1e2040d14f 100644
--- a/tools/build/v2/engine/frames.h
+++ b/tools/build/v2/engine/frames.h
@@ -7,6 +7,7 @@
#define FRAMES_DWA20011021_H
#include "lists.h"
+#include "object.h"
#include "modules.h"
typedef struct _PARSE PARSE;
@@ -14,13 +15,14 @@ typedef struct frame FRAME;
struct frame
{
- FRAME * prev;
+ FRAME * prev;
/* The nearest enclosing frame for which module->user_module is true. */
- FRAME * prev_user;
- LOL args[ 1 ];
- module_t * module;
- PARSE * procedure;
- char * rulename;
+ FRAME * prev_user;
+ LOL args[ 1 ];
+ module_t * module;
+ OBJECT * file;
+ int line;
+ const char * rulename;
};
diff --git a/tools/build/v2/engine/function.c b/tools/build/v2/engine/function.c
new file mode 100644
index 0000000000..1688eba4e8
--- /dev/null
+++ b/tools/build/v2/engine/function.c
@@ -0,0 +1,4553 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#include "lists.h"
+#include "pathsys.h"
+#include "mem.h"
+#include "constants.h"
+#include "jam.h"
+#include "frames.h"
+#include "function.h"
+#include "rules.h"
+#include "variable.h"
+#include "compile.h"
+#include "search.h"
+#include "class.h"
+#include "pathsys.h"
+#include "filesys.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+# ifdef OS_CYGWIN
+# include <sys/cygwin.h>
+# include <windows.h>
+# endif
+
+int glob( const char * s, const char * c );
+void backtrace( FRAME * frame );
+void backtrace_line( FRAME * frame );
+
+#define INSTR_PUSH_EMPTY 0
+#define INSTR_PUSH_CONSTANT 1
+#define INSTR_PUSH_ARG 2
+#define INSTR_PUSH_VAR 3
+#define INSTR_PUSH_VAR_FIXED 57
+#define INSTR_PUSH_GROUP 4
+#define INSTR_PUSH_RESULT 5
+#define INSTR_PUSH_APPEND 6
+#define INSTR_SWAP 7
+
+#define INSTR_JUMP_EMPTY 8
+#define INSTR_JUMP_NOT_EMPTY 9
+
+#define INSTR_JUMP 10
+#define INSTR_JUMP_LT 11
+#define INSTR_JUMP_LE 12
+#define INSTR_JUMP_GT 13
+#define INSTR_JUMP_GE 14
+#define INSTR_JUMP_EQ 15
+#define INSTR_JUMP_NE 16
+#define INSTR_JUMP_IN 17
+#define INSTR_JUMP_NOT_IN 18
+
+#define INSTR_JUMP_NOT_GLOB 19
+
+#define INSTR_FOR_INIT 56
+#define INSTR_FOR_LOOP 20
+
+#define INSTR_SET_RESULT 21
+#define INSTR_RETURN 22
+#define INSTR_POP 23
+
+#define INSTR_PUSH_LOCAL 24
+#define INSTR_POP_LOCAL 25
+#define INSTR_SET 26
+#define INSTR_APPEND 27
+#define INSTR_DEFAULT 28
+
+#define INSTR_PUSH_LOCAL_FIXED 58
+#define INSTR_POP_LOCAL_FIXED 59
+#define INSTR_SET_FIXED 60
+#define INSTR_APPEND_FIXED 61
+#define INSTR_DEFAULT_FIXED 62
+
+#define INSTR_PUSH_LOCAL_GROUP 29
+#define INSTR_POP_LOCAL_GROUP 30
+#define INSTR_SET_GROUP 31
+#define INSTR_APPEND_GROUP 32
+#define INSTR_DEFAULT_GROUP 33
+
+#define INSTR_PUSH_ON 34
+#define INSTR_POP_ON 35
+#define INSTR_SET_ON 36
+#define INSTR_APPEND_ON 37
+#define INSTR_DEFAULT_ON 38
+
+#define INSTR_CALL_RULE 39
+
+#define INSTR_APPLY_MODIFIERS 40
+#define INSTR_APPLY_INDEX 41
+#define INSTR_APPLY_INDEX_MODIFIERS 42
+#define INSTR_APPLY_MODIFIERS_GROUP 43
+#define INSTR_APPLY_INDEX_GROUP 44
+#define INSTR_APPLY_INDEX_MODIFIERS_GROUP 45
+#define INSTR_COMBINE_STRINGS 46
+
+#define INSTR_INCLUDE 47
+#define INSTR_RULE 48
+#define INSTR_ACTIONS 49
+#define INSTR_PUSH_MODULE 50
+#define INSTR_POP_MODULE 51
+#define INSTR_CLASS 52
+#define INSTR_BIND_MODULE_VARIABLES 63
+
+#define INSTR_APPEND_STRINGS 53
+#define INSTR_WRITE_FILE 54
+#define INSTR_OUTPUT_STRINGS 55
+
+typedef struct instruction
+{
+ unsigned int op_code;
+ int arg;
+} instruction;
+
+typedef struct _subfunction
+{
+ OBJECT * name;
+ FUNCTION * code;
+ int local;
+} SUBFUNCTION;
+
+typedef struct _subaction
+{
+ OBJECT * name;
+ FUNCTION * command;
+ int flags;
+} SUBACTION;
+
+#define FUNCTION_BUILTIN 0
+#define FUNCTION_JAM 1
+
+struct argument {
+ int flags;
+#define ARG_ONE 0
+#define ARG_OPTIONAL 1
+#define ARG_PLUS 2
+#define ARG_STAR 3
+#define ARG_VARIADIC 4
+ OBJECT * type_name;
+ OBJECT * arg_name;
+ int index;
+};
+
+struct arg_list {
+ int size;
+ struct argument * args;
+};
+
+struct _function
+{
+ int type;
+ int reference_count;
+ OBJECT * rulename;
+ struct arg_list * formal_arguments;
+ int num_formal_arguments;
+};
+
+typedef struct _builtin_function
+{
+ FUNCTION base;
+ LIST * ( * func )( FRAME *, int flags );
+ int flags;
+} BUILTIN_FUNCTION;
+
+typedef struct _jam_function
+{
+ FUNCTION base;
+ int code_size;
+ instruction * code;
+ int num_constants;
+ OBJECT * * constants;
+ int num_subfunctions;
+ SUBFUNCTION * functions;
+ int num_subactions;
+ SUBACTION * actions;
+ FUNCTION * generic;
+ OBJECT * file;
+ int line;
+} JAM_FUNCTION;
+
+
+#ifdef HAVE_PYTHON
+
+#define FUNCTION_PYTHON 2
+
+typedef struct _python_function
+{
+ FUNCTION base;
+ PyObject * python_function;
+} PYTHON_FUNCTION;
+
+static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame );
+
+#endif
+
+
+struct _stack
+{
+ void * data;
+};
+
+static void * stack;
+
+STACK * stack_global()
+{
+ static STACK result;
+ if ( !stack )
+ {
+ int size = 1 << 21;
+ stack = BJAM_MALLOC( size );
+ result.data = (char *)stack + size;
+ }
+ return &result;
+}
+
+static void check_alignment( STACK * s )
+{
+ assert( (unsigned long)s->data % sizeof( LIST * ) == 0 );
+}
+
+void * stack_allocate( STACK * s, int size )
+{
+ check_alignment( s );
+ s->data = (char *)s->data - size;
+ check_alignment( s );
+ return s->data;
+}
+
+void stack_deallocate( STACK * s, int size )
+{
+ check_alignment( s );
+ s->data = (char *)s->data + size;
+ check_alignment( s );
+}
+
+void stack_push( STACK * s, LIST * l )
+{
+ *(LIST * *)stack_allocate( s, sizeof( LIST * ) ) = l;
+}
+
+LIST * stack_pop( STACK * s )
+{
+ LIST * result = *(LIST * *)s->data;
+ stack_deallocate( s, sizeof( LIST * ) );
+ return result;
+}
+
+LIST * stack_top(STACK * s)
+{
+ check_alignment( s );
+ return *(LIST * *)s->data;
+}
+
+LIST * stack_at( STACK * s, int n )
+{
+ check_alignment( s );
+ return *((LIST * *)s->data + n);
+}
+
+void stack_set( STACK * s, int n, LIST * value )
+{
+ check_alignment( s );
+ *((LIST * *)s->data + n) = value;
+}
+
+void * stack_get( STACK * s )
+{
+ check_alignment( s );
+ return (LIST * *)s->data;
+}
+
+LIST * frame_get_local( FRAME * frame, int idx )
+{
+ /* The only local variables are the arguments */
+ return list_copy( lol_get( frame->args, idx ) );
+}
+
+static OBJECT * function_get_constant( JAM_FUNCTION * function, int idx )
+{
+ return function->constants[ idx ];
+}
+
+static LIST * function_get_variable( JAM_FUNCTION * function, FRAME * frame, int idx )
+{
+ return list_copy( var_get( frame->module, function->constants[idx] ) );
+}
+
+static void function_set_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_SET );
+}
+
+static LIST * function_swap_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ return var_swap( frame->module, function->constants[idx], value );
+}
+
+static void function_append_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_APPEND );
+}
+
+static void function_default_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_DEFAULT );
+}
+
+static void function_set_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+{
+ SUBFUNCTION * sub = function->functions + idx;
+ new_rule_body( frame->module, sub->name, sub->code, !sub->local );
+}
+
+static void function_set_actions( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+{
+ SUBACTION * sub = function->actions + idx;
+ LIST * bindlist = stack_pop( s );
+
+ new_rule_actions( frame->module, sub->name, sub->command, bindlist, sub->flags );
+}
+
+/*
+ * returns the index if name is "<", ">", "1", "2", ... or "19"
+ * otherwise returns -1.
+ */
+
+static int get_argument_index( const char * s )
+{
+ if( s[ 0 ] != '\0')
+ {
+ if( s[ 1 ] == '\0' )
+ {
+ switch ( s[ 0 ] )
+ {
+ case '<': return 0;
+ case '>': return 1;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 0 ] - '1';
+ }
+ }
+ else if ( s[ 0 ] == '1' && s[ 2 ] == '\0' )
+ {
+ switch( s[ 1 ] )
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 1 ] - '0' + 10 - 1;
+ }
+ }
+ }
+ return -1;
+}
+
+static LIST * function_get_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name )
+{
+ int idx = get_argument_index( object_str( name ) );
+ if( idx != -1 )
+ {
+ return list_copy( lol_get( frame->args, idx ) );
+ }
+ else
+ {
+ return list_copy( var_get( frame->module, name ) );
+ }
+}
+
+static void function_set_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+{
+ var_set( frame->module, name, value, VAR_SET );
+}
+
+static LIST * function_swap_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+{
+ return var_swap( frame->module, name, value );
+}
+
+static void function_append_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+{
+ var_set( frame->module, name, value, VAR_APPEND );
+}
+
+static void function_default_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+{
+ var_set( frame->module, name, value, VAR_DEFAULT );
+}
+
+static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int n_args, const char * unexpanded, OBJECT * file, int line )
+{
+ FRAME inner[ 1 ];
+ int i;
+ LIST * first = stack_pop( s );
+ LIST * result = L0;
+ OBJECT * rulename;
+ LIST * trailing;
+
+ frame->file = file;
+ frame->line = line;
+
+ if ( list_empty( first ) )
+ {
+ backtrace_line( frame );
+ printf( "warning: rulename %s expands to empty string\n", unexpanded );
+ backtrace( frame );
+
+ list_free( first );
+
+ for( i = 0; i < n_args; ++i )
+ {
+ list_free( stack_pop( s ) );
+ }
+
+ return result;
+ }
+
+ rulename = object_copy( list_front( first ) );
+
+ frame_init( inner );
+
+ inner->prev = frame;
+ inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
+ inner->module = frame->module; /* This gets fixed up in evaluate_rule(), below. */
+
+ for( i = 0; i < n_args; ++i )
+ {
+ lol_add( inner->args, stack_at( s, n_args - i - 1 ) );
+ }
+
+ for( i = 0; i < n_args; ++i )
+ {
+ stack_pop( s );
+ }
+
+ trailing = list_pop_front( first );
+ if ( trailing )
+ {
+ if ( inner->args->count == 0 )
+ {
+ lol_add( inner->args, trailing );
+ }
+ else
+ {
+ LIST * * l = &inner->args->list[0];
+ *l = list_append( trailing, *l );
+ }
+ }
+
+ result = evaluate_rule( rulename, inner );
+ frame_free( inner );
+ object_free( rulename );
+ return result;
+}
+
+/* Variable expansion */
+
+typedef struct
+{
+ int sub1;
+ int sub2;
+} subscript_t;
+
+typedef struct
+{
+ PATHNAME f; /* :GDBSMR -- pieces */
+ char parent; /* :P -- go to parent directory */
+ char filemods; /* one of the above applied */
+ char downshift; /* :L -- downshift result */
+ char upshift; /* :U -- upshift result */
+ char to_slashes; /* :T -- convert "\" to "/" */
+ char to_windows; /* :W -- convert cygwin to native paths */
+ PATHPART empty; /* :E -- default for empties */
+ PATHPART join; /* :J -- join list with char */
+} VAR_EDITS;
+
+static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER iter, LISTITER end );
+static void get_iters( subscript_t subscript, LISTITER * first, LISTITER * last, int length );
+static void var_edit_file( const char * in, string * out, VAR_EDITS * edits );
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits );
+static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed );
+
+
+/*
+ * var_edit_parse() - parse : modifiers into PATHNAME structure
+ *
+ * The : modifiers in a $(varname:modifier) currently support replacing or
+ * omitting elements of a filename, and so they are parsed into a PATHNAME
+ * structure (which contains pointers into the original string).
+ *
+ * Modifiers of the form "X=value" replace the component X with the given value.
+ * Modifiers without the "=value" cause everything but the component X to be
+ * omitted. X is one of:
+ *
+ * G <grist>
+ * D directory name
+ * B base name
+ * S .suffix
+ * M (member)
+ * R root directory - prepended to whole path
+ *
+ * This routine sets:
+ *
+ * f->f_xxx.ptr = 0
+ * f->f_xxx.len = 0
+ * -> leave the original component xxx
+ *
+ * f->f_xxx.ptr = string
+ * f->f_xxx.len = strlen( string )
+ * -> replace component xxx with string
+ *
+ * f->f_xxx.ptr = ""
+ * f->f_xxx.len = 0
+ * -> omit component xxx
+ *
+ * var_edit_file() below and path_build() obligingly follow this convention.
+ */
+
+static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed )
+{
+ while ( *mods )
+ {
+ PATHPART * fp;
+
+ switch ( *mods++ )
+ {
+ case 'L': edits->downshift = 1; continue;
+ case 'U': edits->upshift = 1; continue;
+ case 'P': edits->parent = edits->filemods = 1; continue;
+ case 'E': fp = &edits->empty; goto strval;
+ case 'J': fp = &edits->join; goto strval;
+ case 'G': fp = &edits->f.f_grist; goto fileval;
+ case 'R': fp = &edits->f.f_root; goto fileval;
+ case 'D': fp = &edits->f.f_dir; goto fileval;
+ case 'B': fp = &edits->f.f_base; goto fileval;
+ case 'S': fp = &edits->f.f_suffix; goto fileval;
+ case 'M': fp = &edits->f.f_member; goto fileval;
+ case 'T': edits->to_slashes = 1; continue;
+ case 'W': edits->to_windows = 1; continue;
+ default:
+ continue; /* Should complain, but so what... */
+ }
+
+ fileval:
+ /* Handle :CHARS, where each char (without a following =) selects a
+ * particular file path element. On the first such char, we deselect all
+ * others (by setting ptr = "", len = 0) and for each char we select
+ * that element (by setting ptr = 0).
+ */
+ edits->filemods = 1;
+
+ if ( *mods != '=' )
+ {
+ if ( !havezeroed++ )
+ {
+ int i;
+ for ( i = 0; i < 6; ++i )
+ {
+ edits->f.part[ i ].len = 0;
+ edits->f.part[ i ].ptr = "";
+ }
+ }
+
+ fp->ptr = 0;
+ continue;
+ }
+
+ strval:
+ /* Handle :X=value, or :X */
+ if ( *mods != '=' )
+ {
+ fp->ptr = "";
+ fp->len = 0;
+ }
+ else
+ {
+ fp->ptr = ++mods;
+ fp->len = strlen( mods );
+ mods += fp->len;
+ }
+ }
+
+ return havezeroed;
+}
+
+/*
+ * var_edit_file() - copy input target name to output, modifying filename.
+ */
+
+static void var_edit_file( const char * in, string * out, VAR_EDITS * edits )
+{
+ if ( edits->filemods )
+ {
+ PATHNAME pathname;
+
+ /* Parse apart original filename, putting parts into "pathname". */
+ path_parse( in, &pathname );
+
+ /* Replace any pathname with edits->f */
+ if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
+ if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
+ if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
+ if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
+ if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
+ if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
+
+ /* If requested, modify pathname to point to parent. */
+ if ( edits->parent )
+ path_parent( &pathname );
+
+ /* Put filename back together. */
+ path_build( &pathname, out, 0 );
+ }
+ else
+ {
+ string_append( out, in );
+ }
+}
+
+/*
+ * var_edit_shift() - do upshift/downshift mods.
+ */
+
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits )
+{
+ if ( edits->upshift || edits->downshift || edits->to_windows || edits->to_slashes )
+ {
+ /* Handle upshifting, downshifting and slash translation now. */
+ char * p;
+# ifdef OS_CYGWIN
+ if ( edits->to_windows )
+ {
+ /* FIXME: skip grist */
+ char result[ MAX_PATH + 1 ];
+ cygwin_conv_to_win32_path( out->value + pos, result );
+ assert( strlen( result ) <= MAX_PATH );
+ string_truncate( out, pos );
+ string_append( out, result );
+ edits->to_slashes = 0;
+ }
+# endif
+ for ( p = out->value + pos; *p; ++p)
+ {
+ if ( edits->upshift )
+ *p = toupper( *p );
+ else if ( edits->downshift )
+ *p = tolower( *p );
+ if ( edits->to_slashes && ( *p == '\\' ) )
+ *p = '/';
+ }
+ }
+}
+
+/*
+ * Reads n LISTs from the top of the STACK and
+ * combines them to form VAR_EDITS.
+ *
+ * returns the number of VAR_EDITS pushed onto
+ * the STACK.
+ */
+
+static int expand_modifiers( STACK * s, int n )
+{
+ int i;
+ int total = 1;
+ LIST * * args = stack_get( s );
+ for( i = 0; i < n; ++i)
+ total *= list_length( args[i] );
+
+ if ( total != 0 )
+ {
+ VAR_EDITS * out = stack_allocate( s, total * sizeof(VAR_EDITS) );
+ LISTITER * iter = stack_allocate( s, n * sizeof(LIST *) );
+ for (i = 0; i < n; ++i )
+ {
+ iter[i] = list_begin( args[i] );
+ }
+ i = 0;
+ {
+ int havezeroed;
+ loop:
+ memset( out, 0, sizeof( *out ) );
+ havezeroed = 0;
+ for (i = 0; i < n; ++i )
+ {
+ havezeroed = var_edit_parse( object_str( list_item( iter[i] ) ), out, havezeroed );
+ }
+ ++out;
+ while ( --i >= 0 )
+ {
+ if ( list_next( iter[i] ) != list_end( args[i] ) )
+ {
+ iter[i] = list_next( iter[i] );
+ goto loop;
+ }
+ else
+ {
+ iter[i] = list_begin( args[i] );
+ }
+ }
+ }
+ stack_deallocate( s, n * sizeof( LIST * ) );
+ }
+ return total;
+}
+
+static LIST * apply_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * result = L0;
+ VAR_EDITS * edits = (VAR_EDITS *)( (LIST * *)stack_get( s ) + 1 );
+ string buf[1];
+ string_new( buf );
+ result = apply_modifiers_impl( result, buf, edits, n, list_begin( value ), list_end( value ) );
+ string_free( buf );
+ return result;
+}
+
+/*
+ * Parse a string of the form "1-2", "-2--1", "2-"
+ * and return the two subscripts.
+ */
+
+subscript_t parse_subscript( const char * s )
+{
+ subscript_t result;
+ result.sub1 = 0;
+ result.sub2 = 0;
+ do /* so we can use "break" */
+ {
+ /* Allow negative subscripts. */
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+ result.sub1 = atoi( s );
+
+ /* Skip over the first symbol, which is either a digit or dash. */
+ ++s;
+ while ( isdigit( *s ) ) ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = result.sub1;
+ break;
+ }
+
+ if ( *s != '-' )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = -1;
+ break;
+ }
+
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ /* First, compute the index of the last element. */
+ result.sub2 = atoi( s );
+ while ( isdigit( *++s ) );
+
+ if ( *s != '\0' )
+ result.sub2 = 0;
+
+ } while ( 0 );
+ return result;
+}
+
+static LIST * apply_subscript( STACK * s )
+{
+ LIST * value = stack_top( s );
+ LIST * indices = stack_at( s, 1 );
+ LIST * result = L0;
+ int length = list_length( value );
+ string buf[1];
+ LISTITER indices_iter = list_begin( indices ), indices_end = list_end( indices );
+ string_new( buf );
+ for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter ) )
+ {
+ LISTITER iter = list_begin( value );
+ LISTITER end = list_end( value );
+ subscript_t subscript = parse_subscript( object_str( list_item( indices_iter ) ) );
+ get_iters( subscript, &iter, &end, length );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ result = list_push_back( result, object_copy( list_item( iter ) ) );
+ }
+ }
+ string_free( buf );
+ return result;
+}
+
+/*
+ * Reads the LIST from first and applies subscript to it.
+ * The results are written to *first and *last.
+ */
+
+static void get_iters( subscript_t subscript, LISTITER * first, LISTITER * last, int length )
+{
+ int start;
+ int size;
+ LISTITER iter;
+ LISTITER end;
+ {
+
+ if ( subscript.sub1 < 0 )
+ start = length + subscript.sub1;
+ else if( subscript.sub1 > length )
+ start = length;
+ else
+ start = subscript.sub1 - 1;
+
+ if ( subscript.sub2 < 0 )
+ size = length + 1 + subscript.sub2 - start;
+ else
+ size = subscript.sub2 - start;
+
+ /*
+ * HACK: When the first subscript is before the start of the
+ * list, it magically becomes the beginning of the list.
+ * This is inconsistent, but needed for backwards
+ * compatibility.
+ */
+ if ( start < 0 )
+ start = 0;
+
+ /* The "sub2 < 0" test handles the semantic error of sub2 <
+ * sub1.
+ */
+ if ( size < 0 )
+ size = 0;
+
+ if ( start + size > length )
+ size = length - start;
+ }
+
+ iter = *first;
+ while ( start-- > 0 )
+ iter = list_next( iter );
+
+ end = iter;
+ while ( size-- > 0 )
+ end = list_next( end );
+
+ *first = iter;
+ *last = end;
+}
+
+static LIST * apply_modifiers_empty( LIST * result, string * buf, VAR_EDITS * edits, int n)
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ {
+ if ( edits[i].empty.ptr )
+ {
+ /** FIXME: is empty.ptr always null-terminated? */
+ var_edit_file( edits[i].empty.ptr, buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ result = list_push_back( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ return result;
+}
+
+static LIST * apply_modifiers_non_empty( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER begin, LISTITER end )
+{
+ int i;
+ LISTITER iter;
+ for ( i = 0; i < n; ++i )
+ {
+ if ( edits[i].join.ptr )
+ {
+ var_edit_file( object_str( list_item( begin ) ), buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ for ( iter = list_next( begin ); iter != end; iter = list_next( iter ) )
+ {
+ size_t size;
+ string_append( buf, edits[i].join.ptr );
+ size = buf->size;
+ var_edit_file( object_str( list_item( iter ) ), buf, edits + i );
+ var_edit_shift( buf, size, edits + i );
+ }
+ result = list_push_back( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ else
+ {
+ for ( iter = begin; iter != end; iter = list_next( iter ) )
+ {
+ var_edit_file( object_str( list_item( iter ) ), buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ result = list_push_back( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ }
+ return result;
+}
+
+static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER iter, LISTITER end )
+{
+ if ( iter != end )
+ {
+ return apply_modifiers_non_empty( result, buf, edits, n, iter, end );
+ }
+ else
+ {
+ return apply_modifiers_empty( result, buf, edits, n );
+ }
+}
+
+static LIST * apply_subscript_and_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * indices = stack_at( s, 1 );
+ LIST * result = L0;
+ VAR_EDITS * edits = (VAR_EDITS *)((LIST * *)stack_get( s ) + 2);
+ int length = list_length( value );
+ string buf[1];
+ LISTITER indices_iter = list_begin( indices ), indices_end = list_end( indices );
+ string_new( buf );
+ for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter ) )
+ {
+ LISTITER iter = list_begin( value );
+ LISTITER end = list_end( value );
+ subscript_t sub = parse_subscript( object_str( list_item( indices_iter ) ) );
+ get_iters( sub, &iter, &end, length );
+ result = apply_modifiers_impl( result, buf, edits, n, iter, end );
+ }
+ string_free( buf );
+ return result;
+}
+
+typedef struct expansion_item
+{
+ LISTITER elem;
+ LIST * saved;
+ int size;
+} expansion_item;
+
+static LIST * expand( expansion_item * elem, int length )
+{
+ LIST * result = L0;
+ string buf[1];
+ int size = 0;
+ int i;
+ assert( length > 0 );
+ for ( i = 0; i < length; ++i )
+ {
+ int max = 0;
+ LISTITER iter = elem[i].elem, end = list_end( elem[i].saved );
+ if ( iter == end ) return result;
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ int len = strlen( object_str( list_item( iter ) ) );
+ if ( len > max ) max = len;
+ }
+ size += max;
+ }
+ string_new( buf );
+ string_reserve( buf, size );
+ i = 0;
+ {
+ loop:
+ for ( ; i < length; ++i )
+ {
+ elem[i].size = buf->size;
+ string_append( buf, object_str( list_item( elem[i].elem ) ) );
+ }
+ result = list_push_back( result, object_new( buf->value ) );
+ while ( --i >= 0 )
+ {
+ if( list_next( elem[i].elem ) != list_end( elem[i].saved ) )
+ {
+ elem[i].elem = list_next( elem[i].elem );
+ string_truncate( buf, elem[i].size );
+ goto loop;
+ }
+ else
+ {
+ elem[i].elem = list_begin( elem[i].saved );
+ }
+ }
+ }
+ string_free( buf );
+ return result;
+}
+
+static void combine_strings( STACK * s, int n, string * out )
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ {
+ LIST * values = stack_pop( s );
+ LISTITER iter = list_begin( values ), end = list_end( values );
+ if ( iter != end )
+ {
+ string_append( out, object_str( list_item( iter ) ) );
+ for ( iter = list_next( iter ); iter != end; iter = list_next( iter ) )
+ {
+ string_push_back( out, ' ' );
+ string_append( out, object_str( list_item( iter ) ) );
+ }
+ list_free( values );
+ }
+ }
+}
+
+struct dynamic_array
+{
+ int size;
+ int capacity;
+ void * data;
+};
+
+static void dynamic_array_init( struct dynamic_array * array )
+{
+ array->size = 0;
+ array->capacity = 0;
+ array->data = 0;
+}
+
+static void dynamic_array_free( struct dynamic_array * array )
+{
+ BJAM_FREE( array->data );
+}
+
+static void dynamic_array_push_impl( struct dynamic_array * array, void * value, int unit_size )
+{
+ if ( array->capacity == 0 )
+ {
+ array->capacity = 2;
+ array->data = BJAM_MALLOC( array->capacity * unit_size );
+ }
+ else if ( array->capacity == array->size )
+ {
+ void * new_data;
+ array->capacity *= 2;
+ new_data = BJAM_MALLOC( array->capacity * unit_size );
+ memcpy( new_data, array->data, array->size * unit_size );
+ BJAM_FREE( array->data );
+ array->data = new_data;
+ }
+ memcpy( (char *)array->data + array->size * unit_size, value, unit_size );
+ ++array->size;
+}
+
+#define dynamic_array_push( array, value ) ( dynamic_array_push_impl( array, &value, sizeof(value) ) )
+#define dynamic_array_at( type, array, idx ) (((type *)(array)->data)[idx])
+
+/*
+ * struct compiler
+ */
+
+struct label_info
+{
+ int absolute_position;
+ struct dynamic_array uses[1];
+};
+
+struct stored_rule
+{
+ OBJECT * name;
+ PARSE * parse;
+ int num_arguments;
+ struct arg_list * arguments;
+ int local;
+};
+
+typedef struct compiler
+{
+ struct dynamic_array code[1];
+ struct dynamic_array constants[1];
+ struct dynamic_array labels[1];
+ struct dynamic_array rules[1];
+ struct dynamic_array actions[1];
+} compiler;
+
+static void compiler_init( compiler * c )
+{
+ dynamic_array_init( c->code );
+ dynamic_array_init( c->constants );
+ dynamic_array_init( c->labels );
+ dynamic_array_init( c->rules );
+ dynamic_array_init( c->actions );
+}
+
+static void compiler_free( compiler * c )
+{
+ int i;
+ dynamic_array_free( c->actions );
+ dynamic_array_free( c->rules );
+ for ( i = 0; i < c->labels->size; ++i )
+ {
+ dynamic_array_free( dynamic_array_at( struct label_info, c->labels, i ).uses );
+ }
+ dynamic_array_free( c->labels );
+ dynamic_array_free( c->constants );
+ dynamic_array_free( c->code );
+}
+
+static void compile_emit_instruction( compiler * c, instruction instr )
+{
+ dynamic_array_push( c->code, instr );
+}
+
+static int compile_new_label( compiler * c )
+{
+ int result = c->labels->size;
+ struct label_info info;
+ info.absolute_position = -1;
+ dynamic_array_init( info.uses );
+ dynamic_array_push( c->labels, info );
+ return result;
+}
+
+static void compile_set_label( compiler * c, int label )
+{
+ struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
+ int pos = c->code->size;
+ int i;
+ assert( l->absolute_position == -1 );
+ l->absolute_position = pos;
+ for ( i = 0; i < l->uses->size; ++i )
+ {
+ int id = dynamic_array_at( int, l->uses, i );
+ int offset = (int)(pos - id - 1);
+ dynamic_array_at( instruction, c->code, id ).arg = offset;
+ }
+}
+
+static void compile_emit( compiler * c, unsigned int op_code, int arg )
+{
+ instruction instr;
+ instr.op_code = op_code;
+ instr.arg = arg;
+ compile_emit_instruction( c, instr );
+}
+
+static void compile_emit_branch( compiler * c, unsigned int op_code, int label )
+{
+ struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
+ int pos = c->code->size;
+ instruction instr;
+ instr.op_code = op_code;
+ if ( l->absolute_position == -1 )
+ {
+ instr.arg = 0;
+ dynamic_array_push( l->uses, pos );
+ }
+ else
+ {
+ instr.arg = (int)( l->absolute_position - pos - 1 );
+ }
+ compile_emit_instruction( c, instr );
+}
+
+static int compile_emit_constant( compiler * c, OBJECT * value )
+{
+ OBJECT * copy = object_copy( value );
+ dynamic_array_push( c->constants, copy );
+ return c->constants->size - 1;
+}
+
+static int compile_emit_rule( compiler * c, OBJECT * name, PARSE * parse, int num_arguments, struct arg_list * arguments, int local )
+{
+ struct stored_rule rule;
+ rule.name = object_copy( name );
+ rule.parse = parse;
+ rule.num_arguments = num_arguments;
+ rule.arguments = arguments;
+ rule.local = local;
+ dynamic_array_push( c->rules, rule );
+ return (int)( c->rules->size - 1 );
+}
+
+static int compile_emit_actions( compiler * c, PARSE * parse )
+{
+ SUBACTION a;
+ a.name = object_copy( parse->string );
+ a.command = function_compile_actions( object_str( parse->string1 ), parse->file, parse->line );
+ a.flags = parse->num;
+ dynamic_array_push( c->actions, a );
+ return (int)( c->actions->size - 1 );
+}
+
+static JAM_FUNCTION * compile_to_function( compiler * c )
+{
+ JAM_FUNCTION * result = BJAM_MALLOC( sizeof(JAM_FUNCTION) );
+ int i;
+ result->base.type = FUNCTION_JAM;
+ result->base.reference_count = 1;
+ result->base.formal_arguments = 0;
+ result->base.num_formal_arguments = 0;
+
+ result->base.rulename = 0;
+
+ result->code_size = c->code->size;
+ result->code = BJAM_MALLOC( c->code->size * sizeof(instruction) );
+ memcpy( result->code, c->code->data, c->code->size * sizeof(instruction) );
+
+ result->constants = BJAM_MALLOC( c->constants->size * sizeof(OBJECT *) );
+ memcpy( result->constants, c->constants->data, c->constants->size * sizeof(OBJECT *) );
+ result->num_constants = c->constants->size;
+
+ result->num_subfunctions = c->rules->size;
+ result->functions = BJAM_MALLOC( c->rules->size * sizeof(SUBFUNCTION) );
+ for ( i = 0; i < c->rules->size; ++i )
+ {
+ struct stored_rule * rule = &dynamic_array_at( struct stored_rule, c->rules, i );
+ result->functions[i].name = rule->name;
+ result->functions[i].code = function_compile( rule->parse );
+ result->functions[i].code->num_formal_arguments = rule->num_arguments;
+ result->functions[i].code->formal_arguments = rule->arguments;
+ result->functions[i].local = rule->local;
+ }
+
+ result->actions = BJAM_MALLOC( c->actions->size * sizeof(SUBACTION) );
+ memcpy( result->actions, c->actions->data, c->actions->size * sizeof(SUBACTION) );
+ result->num_subactions = c->actions->size;
+
+ result->generic = 0;
+
+ result->file = 0;
+ result->line = -1;
+
+ return result;
+}
+
+/*
+ * Parsing of variable expansions
+ */
+
+typedef struct VAR_PARSE_GROUP
+{
+ struct dynamic_array elems[1];
+} VAR_PARSE_GROUP;
+
+typedef struct VAR_PARSE_ACTIONS
+{
+ struct dynamic_array elems[1];
+} VAR_PARSE_ACTIONS;
+
+#define VAR_PARSE_TYPE_VAR 0
+#define VAR_PARSE_TYPE_STRING 1
+#define VAR_PARSE_TYPE_FILE 2
+
+typedef struct _var_parse
+{
+ int type; /* string or variable */
+} VAR_PARSE;
+
+typedef struct
+{
+ VAR_PARSE base;
+ VAR_PARSE_GROUP * name;
+ VAR_PARSE_GROUP * subscript;
+ struct dynamic_array modifiers[1];
+} VAR_PARSE_VAR;
+
+typedef struct
+{
+ VAR_PARSE base;
+ OBJECT * s;
+} VAR_PARSE_STRING;
+
+typedef struct
+{
+ VAR_PARSE base;
+ struct dynamic_array filename[1];
+ struct dynamic_array contents[1];
+} VAR_PARSE_FILE;
+
+static void var_parse_free( VAR_PARSE * );
+
+/*
+ * VAR_PARSE_GROUP
+ */
+
+static VAR_PARSE_GROUP * var_parse_group_new()
+{
+ VAR_PARSE_GROUP * result = BJAM_MALLOC( sizeof( VAR_PARSE_GROUP ) );
+ dynamic_array_init( result->elems );
+ return result;
+}
+
+static void var_parse_group_free( VAR_PARSE_GROUP * group )
+{
+ int i;
+ for ( i = 0; i < group->elems->size; ++i )
+ {
+ var_parse_free( dynamic_array_at( VAR_PARSE *, group->elems, i ) );
+ }
+ dynamic_array_free( group->elems );
+ BJAM_FREE( group );
+}
+
+static void var_parse_group_add( VAR_PARSE_GROUP * group, VAR_PARSE * elem )
+{
+ dynamic_array_push( group->elems, elem );
+}
+
+static void var_parse_group_maybe_add_constant( VAR_PARSE_GROUP * group, const char * start, const char * end )
+{
+ if ( start != end )
+ {
+ string buf[1];
+ VAR_PARSE_STRING * value = (VAR_PARSE_STRING *)BJAM_MALLOC( sizeof(VAR_PARSE_STRING) );
+ value->base.type = VAR_PARSE_TYPE_STRING;
+ string_new( buf );
+ string_append_range( buf, start, end );
+ value->s = object_new( buf->value );
+ string_free( buf );
+ var_parse_group_add( group, (VAR_PARSE *)value );
+ }
+}
+
+VAR_PARSE_STRING * var_parse_group_as_literal( VAR_PARSE_GROUP * group )
+{
+ if ( group->elems->size == 1 )
+ {
+ VAR_PARSE * result = dynamic_array_at( VAR_PARSE *, group->elems, 0 );
+ if ( result->type == VAR_PARSE_TYPE_STRING )
+ {
+ return (VAR_PARSE_STRING *)result;
+ }
+ }
+ return 0;
+}
+
+/*
+ * VAR_PARSE_ACTIONS
+ */
+
+static VAR_PARSE_ACTIONS * var_parse_actions_new()
+{
+ VAR_PARSE_ACTIONS * result = (VAR_PARSE_ACTIONS *)BJAM_MALLOC( sizeof(VAR_PARSE_ACTIONS) );
+ dynamic_array_init( result->elems );
+ return result;
+}
+
+static void var_parse_actions_free( VAR_PARSE_ACTIONS * actions )
+{
+ int i;
+ for ( i = 0; i < actions->elems->size; ++i )
+ {
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, actions->elems, i ) );
+ }
+ dynamic_array_free( actions->elems );
+ BJAM_FREE( actions );
+}
+
+/*
+ * VAR_PARSE_VAR
+ */
+
+static VAR_PARSE_VAR * var_parse_var_new()
+{
+ VAR_PARSE_VAR * result = BJAM_MALLOC( sizeof( VAR_PARSE_VAR ) );
+ result->base.type = VAR_PARSE_TYPE_VAR;
+ result->name = var_parse_group_new();
+ result->subscript = 0;
+ dynamic_array_init( result->modifiers );
+ return result;
+}
+
+static void var_parse_var_free( VAR_PARSE_VAR * var )
+{
+ int i;
+ var_parse_group_free( var->name );
+ if ( var->subscript )
+ var_parse_group_free( var->subscript );
+ for( i = 0; i < var->modifiers->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, var->modifiers, i ) );
+ dynamic_array_free( var->modifiers );
+ BJAM_FREE( var );
+}
+
+static VAR_PARSE_GROUP * var_parse_var_new_modifier( VAR_PARSE_VAR * var )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ dynamic_array_push( var->modifiers, result );
+ return result;
+}
+
+/*
+ * VAR_PARSE_STRING
+ */
+
+static void var_parse_string_free( VAR_PARSE_STRING * string )
+{
+ object_free( string->s );
+ BJAM_FREE( string );
+}
+
+/*
+ * VAR_PARSE_FILE
+ */
+
+static VAR_PARSE_FILE * var_parse_file_new( void )
+{
+ VAR_PARSE_FILE * result = (VAR_PARSE_FILE *)BJAM_MALLOC( sizeof( VAR_PARSE_FILE ) );
+ result->base.type = VAR_PARSE_TYPE_FILE;
+ dynamic_array_init( result->filename );
+ dynamic_array_init( result->contents );
+ return result;
+}
+
+static void var_parse_file_free( VAR_PARSE_FILE * file )
+{
+ int i;
+ for( i = 0; i < file->filename->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, file->filename, i ) );
+ dynamic_array_free( file->filename );
+ for( i = 0; i < file->contents->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, file->contents, i ) );
+ dynamic_array_free( file->contents );
+ BJAM_FREE( file );
+}
+
+/*
+ * VAR_PARSE
+ */
+
+static void var_parse_free( VAR_PARSE * parse )
+{
+ if ( parse->type == VAR_PARSE_TYPE_VAR )
+ {
+ var_parse_var_free( (VAR_PARSE_VAR *)parse );
+ }
+ else if ( parse->type == VAR_PARSE_TYPE_STRING )
+ {
+ var_parse_string_free( (VAR_PARSE_STRING *)parse );
+ }
+ else if ( parse->type == VAR_PARSE_TYPE_FILE )
+ {
+ var_parse_file_free( (VAR_PARSE_FILE *)parse );
+ }
+ else
+ {
+ assert(!"Invalid type");
+ }
+}
+
+/*
+ * Compile VAR_PARSE
+ */
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c );
+
+static void var_parse_var_compile( const VAR_PARSE_VAR * parse, compiler * c )
+{
+ int expand_name = 0;
+ /* If there are modifiers, emit them in reverse order. */
+ if ( parse->modifiers->size > 0 )
+ {
+ int i;
+ for ( i = 0; i < parse->modifiers->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, parse->modifiers->size - i - 1 ), c );
+ }
+ }
+
+ /* If there's a subscript, emit it. */
+ if ( parse->subscript )
+ {
+ var_parse_group_compile( parse->subscript, c );
+ }
+
+ /* If the variable name is empty, look it up. */
+ if ( parse->name->elems->size == 0 )
+ {
+ compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, constant_empty ) );
+ }
+ /* If the variable name doesn't need to be expanded, look it up. */
+ else if ( parse->name->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ OBJECT * name = ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 ) )->s;
+ int idx = get_argument_index( object_str( name ) );
+ if ( idx != -1 )
+ {
+ compile_emit( c, INSTR_PUSH_ARG, idx );
+ }
+ else
+ {
+ compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, name ) );
+ }
+ }
+ /* Otherwise, push the var names and use the group instruction. */
+ else
+ {
+ var_parse_group_compile( parse->name, c );
+ expand_name = 1;
+ }
+
+ /** Select the instruction for expanding the variable. */
+ if ( !parse->modifiers->size && !parse->subscript && !expand_name )
+ {
+ /* Nothing to do */
+ }
+ else if ( !parse->modifiers->size && !parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_PUSH_GROUP, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_GROUP, 0 );
+ }
+ if ( parse->modifiers->size && !parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && !parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+}
+
+static void var_parse_string_compile( const VAR_PARSE_STRING * parse, compiler * c )
+{
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, parse->s ) );
+}
+
+static void var_parse_file_compile( const VAR_PARSE_FILE * parse, compiler * c )
+{
+ int i;
+ for ( i = 0; i < parse->filename->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->filename, parse->filename->size - i - 1 ), c );
+ }
+ compile_emit( c, INSTR_APPEND_STRINGS, parse->filename->size );
+ for ( i = 0; i < parse->contents->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->contents, parse->contents->size - i - 1 ), c );
+ }
+ compile_emit( c, INSTR_WRITE_FILE, parse->contents->size );
+}
+
+static void var_parse_compile( const VAR_PARSE * parse, compiler * c )
+{
+ if( parse->type == VAR_PARSE_TYPE_VAR )
+ {
+ var_parse_var_compile( (const VAR_PARSE_VAR *)parse, c );
+ }
+ else if( parse->type == VAR_PARSE_TYPE_STRING )
+ {
+ var_parse_string_compile( (const VAR_PARSE_STRING *)parse, c );
+ }
+ else if( parse->type == VAR_PARSE_TYPE_FILE )
+ {
+ var_parse_file_compile( (const VAR_PARSE_FILE *)parse, c );
+ }
+ else
+ {
+ assert( !"Unknown var parse type." );
+ }
+}
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c )
+{
+ /* Emit the elements in reverse order. */
+ int i;
+ for( i = 0; i < parse->elems->size; ++i)
+ {
+ var_parse_compile( dynamic_array_at( VAR_PARSE *, parse->elems, parse->elems->size - i - 1 ), c );
+ }
+ /* If there're no elements, emit an empty string. */
+ if ( parse->elems->size == 0 )
+ {
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, constant_empty ) );
+ }
+ /* If there's more than one element, combine them. */
+ if ( parse->elems->size > 1 )
+ {
+ compile_emit( c, INSTR_COMBINE_STRINGS, parse->elems->size );
+ }
+}
+
+static void var_parse_actions_compile( const VAR_PARSE_ACTIONS * actions, compiler * c )
+{
+ int i;
+ for ( i = 0; i < actions->elems->size; ++i )
+ {
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, actions->elems, actions->elems->size - i - 1 ), c );
+ }
+ compile_emit( c, INSTR_OUTPUT_STRINGS, actions->elems->size );
+}
+
+/*
+ * Parse VAR_PARSE_VAR
+ */
+
+static VAR_PARSE * parse_at_file( const char * start, const char * mid, const char * end );
+static VAR_PARSE * parse_variable( const char * * string );
+static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
+static void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
+static void parse_var_string( const char * first, const char * last, struct dynamic_array * out );
+
+/*
+ * Parses a string that can contain variables to expand.
+ */
+
+static VAR_PARSE_GROUP * parse_expansion( const char * * string )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ const char * s = *string;
+ for (;;)
+ {
+ if(try_parse_variable( &s, string, result )) {}
+ else if(s[0] == '\0')
+ {
+ var_parse_group_maybe_add_constant( result, *string, s );
+ return result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+}
+
+static VAR_PARSE_ACTIONS * parse_actions( const char * string )
+{
+ VAR_PARSE_ACTIONS * result = var_parse_actions_new();
+ parse_var_string( string, string + strlen( string ), result->elems );
+ return result;
+}
+
+/*
+ * Checks whether the string a *s_ starts with
+ * a variable expansion "$(". *string should point
+ * to the first unemitted character before *s.
+ * If *s_ starts with variable expansion, appends
+ * elements to out up to the closing ")", and
+ * adjusts *s_ and *string to point to next character.
+ * Returns 1 if s_ starts with a variable, 0 otherwise.
+ */
+
+static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ const char * s = *s_;
+ if(s[0] == '$' && s[1] == '(')
+ {
+ var_parse_group_maybe_add_constant( out, *string, s );
+ s += 2;
+ var_parse_group_add( out, parse_variable( &s ) );
+ *string = s;
+ *s_ = s;
+ return 1;
+ }
+ else if(s[0] == '@' && s[1] == '(')
+ {
+ int depth = 1;
+ const char * ine;
+ const char * split = 0;
+ var_parse_group_maybe_add_constant( out, *string, s );
+ s += 2;
+ ine = s;
+
+ /* Scan the content of the response file @() section. */
+ while ( *ine && ( depth > 0 ) )
+ {
+ switch ( *ine )
+ {
+ case '(': ++depth; break;
+ case ')': --depth; break;
+ case ':':
+ if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
+ split = ine;
+ break;
+ }
+ ++ine;
+ }
+
+ if ( !split || depth != 0 )
+ {
+ return 0;
+ }
+
+ var_parse_group_add( out, parse_at_file( s, split, ine - 1 ) );
+ *string = ine;
+ *s_ = ine;
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static const char * current_file = "";
+static int current_line;
+
+static void parse_error( const char * message )
+{
+ printf( "%s:%d: %s\n", current_file, current_line, message );
+}
+
+/*
+ * Parses a single variable up to the closing ")" and
+ * adjusts *string to point to the next character. *string
+ * should point to the character immediately after
+ * the initial "$("
+ */
+
+static VAR_PARSE * parse_variable( const char * * string )
+{
+ VAR_PARSE_VAR * result = var_parse_var_new();
+ VAR_PARSE_GROUP * name = result->name;
+ const char * s = *string;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, name ) ) {}
+ else if ( s[0] == ':' )
+ {
+ VAR_PARSE_GROUP * mod;
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, mod ) ) {}
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, mod );
+ }
+ else if ( s[0] == ':' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ }
+ else if ( s[0] == '[' )
+ {
+ parse_error("unexpected subscript");
+ ++s;
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ }
+ else if ( s[0] == '[' )
+ {
+ VAR_PARSE_GROUP * subscript = var_parse_group_new();
+ result->subscript = subscript;
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, subscript ) ) {}
+ else if ( s[0] == ']' )
+ {
+ var_parse_group_maybe_add_constant( subscript, *string, s );
+ ++s;
+ *string = s;
+ if ( s[0] == ')' || s[0] == ':' || s[0] == '\0')
+ {
+ break;
+ }
+ else
+ {
+ parse_error( "unexpected text following []" );
+ break;
+ }
+ }
+ else if ( isdigit( s[0] ) || s[0] == '-' )
+ {
+ ++s;
+ }
+ else if( s[0] == '\0' )
+ {
+ parse_error( "malformed subscript" );
+ break;
+ }
+ else
+ {
+ parse_error( "malformed subscript" );
+ ++s;
+ }
+ }
+ }
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, name );
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ var_parse_group_maybe_add_constant( name, *string, s );
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+}
+
+static void parse_var_string( const char * first, const char * last, struct dynamic_array * out )
+{
+ const char * saved = first;
+ for ( ; ; )
+ {
+ /* Handle whitespace */
+ for ( ; first != last; ++first ) if ( !isspace(*first) ) break;
+ if ( saved != first )
+ {
+ VAR_PARSE_GROUP * group = var_parse_group_new();
+ var_parse_group_maybe_add_constant( group, saved, first );
+ saved = first;
+ dynamic_array_push( out, group );
+ }
+
+ if ( first == last ) break;
+
+ /* Handle non-whitespace */
+
+ {
+ VAR_PARSE_GROUP * group = var_parse_group_new();
+ for ( ; ; )
+ {
+
+ if( first == last || isspace( *first ) )
+ {
+ var_parse_group_maybe_add_constant( group, saved, first );
+ saved = first;
+ break;
+ }
+ else if ( try_parse_variable( &first, &saved, group ) )
+ {
+ assert( first <= last );
+ }
+ else
+ {
+ ++first;
+ }
+ }
+ dynamic_array_push( out, group );
+ }
+ if ( first == last ) break;
+ }
+}
+
+/*
+ * start should point to the character immediately following the
+ * opening "@(", mid should point to the ":E=", and end should
+ * point to the closing ")".
+ */
+
+static VAR_PARSE * parse_at_file( const char * start, const char * mid, const char * end )
+{
+ VAR_PARSE_FILE * result = var_parse_file_new();
+ parse_var_string( start, mid, result->filename );
+ parse_var_string( mid + 3, end, result->contents );
+ return (VAR_PARSE *)result;
+}
+
+/*
+ * Given that *s_ points to the character after a "(",
+ * parses up to the matching ")". *string should
+ * point to the first unemitted character before *s_.
+ *
+ * When the function returns, *s_ will point to the character
+ * after the ")", and *string will point to the first
+ * unemitted character before *s_. The range from *string
+ * to *s_ does not contain any variables that need to be
+ * expanded.
+ */
+
+void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ int depth = 1;
+ const char * s = *s_;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, out ) ) { }
+ else if(s[0] == ':' || s[0] == '[')
+ {
+ parse_error( "unbalanced parentheses" );
+ ++s;
+ }
+ else if(s[0] == '\0')
+ {
+ parse_error( "unbalanced parentheses" );
+ break;
+ }
+ else if(s[0] == ')')
+ {
+ ++s;
+ if(--depth == 0) break;
+ }
+ else if(s[0] == '(')
+ {
+ ++depth;
+ ++s;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ *s_ = s;
+}
+
+/*
+ * Main compile
+ */
+
+#define RESULT_STACK 0
+#define RESULT_RETURN 1
+#define RESULT_NONE 2
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location );
+static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments );
+
+static void compile_condition( PARSE * parse, compiler * c, int branch_true, int label )
+{
+ assert( parse->type == PARSE_EVAL );
+ switch ( parse->num )
+ {
+ case EXPR_EXISTS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_NOT_EMPTY, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_EMPTY, label );
+ break;
+ }
+ case EXPR_EQUALS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ break;
+ }
+ case EXPR_NOTEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ break;
+ }
+ case EXPR_LESS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ break;
+ }
+ case EXPR_LESSEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ break;
+ }
+ case EXPR_MORE:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ break;
+ }
+ case EXPR_MOREEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ break;
+ }
+ case EXPR_IN:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_IN, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NOT_IN, label );
+ break;
+ }
+ case EXPR_AND:
+ {
+ if ( branch_true )
+ {
+ int f = compile_new_label( c );
+ compile_condition( parse->left, c, 0, f );
+ compile_condition( parse->right, c, 1, label );
+ compile_set_label( c, f );
+ }
+ else
+ {
+ compile_condition( parse->left, c, 0, label );
+ compile_condition( parse->right, c, 0, label );
+ }
+ break;
+ }
+ case EXPR_OR:
+ {
+ if ( branch_true )
+ {
+ compile_condition( parse->left, c, 1, label );
+ compile_condition( parse->right, c, 1, label );
+ }
+ else
+ {
+ int t = compile_new_label( c );
+ compile_condition( parse->left, c, 1, t );
+ compile_condition( parse->right, c, 0, label );
+ compile_set_label( c, t );
+ }
+ break;
+ }
+ case EXPR_NOT:
+ {
+ compile_condition( parse->left, c, !branch_true, label );
+ break;
+ }
+ }
+}
+
+static void adjust_result( compiler * c, int actual_location, int desired_location )
+{
+ if ( actual_location == desired_location )
+ ;
+ else if ( actual_location == RESULT_STACK && desired_location == RESULT_RETURN )
+ compile_emit( c, INSTR_SET_RESULT, 0 );
+ else if( actual_location == RESULT_STACK && desired_location == RESULT_NONE )
+ compile_emit( c, INSTR_POP, 0 );
+ else if( actual_location == RESULT_RETURN && desired_location == RESULT_STACK )
+ compile_emit( c, INSTR_PUSH_RESULT, 0 );
+ else if ( actual_location == RESULT_RETURN && desired_location == RESULT_NONE )
+ ;
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_STACK )
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_RETURN )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_SET_RESULT, 0 );
+ }
+ else
+ {
+ assert( !"invalid result location" );
+ }
+}
+
+static const char * parse_type( PARSE * parse )
+{
+ switch ( parse->type )
+ {
+ case PARSE_APPEND: return "append";
+ case PARSE_EVAL: return "eval";
+ case PARSE_RULES: return "rules";
+ default: return "unknown";
+ }
+}
+
+static void compile_append_chain( PARSE * parse, compiler * c )
+{
+ assert( parse->type == PARSE_APPEND );
+ if ( parse->left->type == PARSE_NULL )
+ {
+ compile_parse( parse->right, c, RESULT_STACK );
+ }
+ else
+ {
+ if ( parse->left->type == PARSE_APPEND )
+ compile_append_chain( parse->left, c );
+ else
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_APPEND, 0 );
+ }
+}
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location )
+{
+ if ( parse->type == PARSE_APPEND )
+ {
+ compile_append_chain( parse, c );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_EVAL )
+ {
+ /* FIXME: This is only needed because of the bizarre parsing of conditions. */
+ if ( parse->num == EXPR_EXISTS )
+ {
+ compile_parse( parse->left, c, result_location );
+ }
+ else
+ {
+ int f = compile_new_label( c );
+ int end = compile_new_label( c );
+
+ printf( "%s:%d: Conditional used as list (check operator precedence).\n", object_str(parse->file), parse->line );
+
+ /* Emit the condition */
+ compile_condition( parse, c, 0, f );
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, constant_true ) );
+ compile_emit_branch( c, INSTR_JUMP, end );
+ compile_set_label( c, f );
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_set_label( c, end );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ }
+ else if ( parse->type == PARSE_FOREACH )
+ {
+ int var = compile_emit_constant( c, parse->string );
+ int top = compile_new_label( c );
+ int end = compile_new_label( c );
+
+ /*
+ * Evaluate the list.
+ */
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ /* Localize the loop variable */
+ if ( parse->num )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_PUSH_LOCAL, var );
+ compile_emit( c, INSTR_SWAP, 1 );
+ }
+
+ compile_emit( c, INSTR_FOR_INIT, 0 );
+ compile_set_label( c, top );
+ compile_emit_branch( c, INSTR_FOR_LOOP, end );
+ compile_emit( c, INSTR_SET, var );
+ compile_emit( c, INSTR_POP, 0 );
+
+ /* Run the loop body */
+ compile_parse( parse->right, c, RESULT_NONE );
+
+ compile_emit_branch( c, INSTR_JUMP, top );
+ compile_set_label( c, end );
+
+ if ( parse->num )
+ {
+ compile_emit( c, INSTR_POP_LOCAL, var );
+ }
+
+ adjust_result( c, RESULT_NONE, result_location);
+ }
+ else if( parse->type == PARSE_IF )
+ {
+ int f = compile_new_label( c );
+ /* Emit the condition */
+ compile_condition( parse->left, c, 0, f );
+ /* Emit the if block */
+ compile_parse( parse->right, c, result_location );
+ if ( parse->third->type != PARSE_NULL || result_location != RESULT_NONE )
+ {
+ /* Emit the else block */
+ int end = compile_new_label( c );
+ compile_emit_branch( c, INSTR_JUMP, end );
+ compile_set_label( c, f );
+ compile_parse( parse->third, c, result_location );
+ compile_set_label( c, end );
+ }
+ else
+ {
+ compile_set_label( c, f );
+ }
+
+ }
+ else if( parse->type == PARSE_WHILE )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ int test = compile_new_label( c );
+ int top = compile_new_label( c );
+ /* Make sure that we return an empty list if the loop runs zero times. */
+ adjust_result( c, RESULT_NONE, nested_result );
+ /* Jump to the loop test */
+ compile_emit_branch( c, INSTR_JUMP, test );
+ compile_set_label( c, top );
+ /* Emit the loop body */
+ compile_parse( parse->right, c, nested_result );
+ /* Emit the condition */
+ compile_set_label( c, test );
+ compile_condition( parse->left, c, 1, top );
+
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_INCLUDE )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_INCLUDE, 0 );
+ compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_MODULE )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_MODULE, 0 );
+ compile_parse( parse->right, c, nested_result );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_CLASS )
+ {
+ /* Evaluate the class name. */
+ compile_parse( parse->left->right, c, RESULT_STACK );
+ /* Evaluate the base classes. */
+ if ( parse->left->left )
+ {
+ compile_parse( parse->left->left->right, c, RESULT_STACK );
+ }
+ else
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ }
+ compile_emit( c, INSTR_CLASS, 0 );
+ compile_parse( parse->right, c, RESULT_NONE );
+ compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_LIST )
+ {
+ OBJECT * o = parse->string;
+ const char * s = object_str( o );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_LOCAL )
+ {
+ int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ /*
+ * This should be left recursive group of compile_appends
+ */
+ PARSE * vars = parse->left;
+
+ /* Special case an empty list of vars */
+ if ( vars->type == PARSE_NULL )
+ {
+ compile_parse( parse->right, c, RESULT_NONE );
+ compile_parse( parse->third, c, result_location );
+ nested_result = result_location;
+ }
+ /*
+ * Check whether there is exactly one variable
+ * with a constant name
+ */
+ else if ( vars->left->type == PARSE_NULL &&
+ vars->right->type == PARSE_LIST )
+ {
+ const char * s = object_str( vars->right->string );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ if ( group->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL, name );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_ON )
+ {
+ int end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit_branch( c, INSTR_PUSH_ON, end );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_POP_ON, 0 );
+ compile_set_label( c, end );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULE )
+ {
+ PARSE * p;
+ int n = 0;
+ VAR_PARSE_GROUP * group;
+ const char * s = object_str( parse->string );
+
+ if ( parse->left->left == NULL && parse->left->right->type == PARSE_NULL )
+ ;
+ else
+ for ( p = parse->left; p; p = p->left )
+ {
+ compile_parse( p->right, c, RESULT_STACK );
+ ++n;
+ }
+
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_emit( c, INSTR_CALL_RULE, n );
+ compile_emit( c, compile_emit_constant( c, parse->string ), parse->line );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULES )
+ {
+ do compile_parse( parse->left, c, RESULT_NONE );
+ while ( ( parse = parse->right )->type == PARSE_RULES );
+ compile_parse( parse, c, result_location );
+ }
+ else if ( parse->type == PARSE_SET )
+ {
+ PARSE * vars = parse->left;
+ unsigned int op_code;
+ unsigned int op_code_group;
+
+ switch ( parse->num )
+ {
+ case ASSIGN_SET: default: op_code = INSTR_SET; op_code_group = INSTR_SET_GROUP; break;
+ case ASSIGN_APPEND: op_code = INSTR_APPEND; op_code_group = INSTR_APPEND_GROUP; break;
+ case ASSIGN_DEFAULT: op_code = INSTR_DEFAULT; op_code_group = INSTR_DEFAULT_GROUP; break;
+ }
+
+ /*
+ * Check whether there is exactly one variable
+ * with a constant name
+ */
+ if ( vars->type == PARSE_LIST )
+ {
+ const char * s = object_str( vars->string );
+ VAR_PARSE_GROUP * group;
+ current_file = object_str( parse->file );
+ current_line = parse->line;
+ group = parse_expansion( &s );
+ if ( group->elems->size == 1 &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_SETCOMP )
+ {
+ int n_args;
+ struct arg_list * args = arg_list_compile( parse->right, &n_args );
+
+ int rule_id = compile_emit_rule( c, parse->string, parse->left, n_args, args, parse->num );
+
+ compile_emit( c, INSTR_RULE, rule_id );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_SETEXEC )
+ {
+ int actions_id = compile_emit_actions( c, parse );
+
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ compile_emit( c, INSTR_ACTIONS, actions_id );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_SETTINGS )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->third, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+
+ switch ( parse->num )
+ {
+ case ASSIGN_SET: default: compile_emit( c, INSTR_SET_ON, 0 ); break;
+ case ASSIGN_APPEND: compile_emit( c, INSTR_APPEND_ON, 0 ); break;
+ case ASSIGN_DEFAULT: compile_emit( c, INSTR_DEFAULT_ON, 0 ); break;
+ }
+
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_SWITCH )
+ {
+ int switch_end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ for ( parse = parse->right; parse; parse = parse->right )
+ {
+ int id = compile_emit_constant( c, parse->left->string );
+ int next_case = compile_new_label( c );
+ compile_emit( c, INSTR_PUSH_CONSTANT, id );
+ compile_emit_branch( c, INSTR_JUMP_NOT_GLOB, next_case );
+ compile_parse( parse->left->left, c, result_location );
+ compile_emit_branch( c, INSTR_JUMP, switch_end );
+ compile_set_label( c, next_case );
+ }
+ compile_emit( c, INSTR_POP, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ compile_set_label( c, switch_end );
+ }
+ else if ( parse->type == PARSE_NULL )
+ {
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else
+ {
+ assert( !"unknown PARSE type." );
+ }
+}
+
+OBJECT * function_rulename( FUNCTION * function )
+{
+ return function->rulename;
+}
+
+void function_set_rulename( FUNCTION * function, OBJECT * rulename )
+{
+ function->rulename = rulename;
+}
+
+void function_location( FUNCTION * function_, OBJECT * * file, int * line )
+{
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+#ifdef HAVE_PYTHON
+ if ( function_->type == FUNCTION_PYTHON )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+#endif
+ else
+ {
+ JAM_FUNCTION * function = (JAM_FUNCTION *)function_;
+ assert( function_->type == FUNCTION_JAM );
+ *file = function->file;
+ *line = function->line;
+ }
+}
+
+static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments );
+
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags, const char * * args )
+{
+ BUILTIN_FUNCTION * result = BJAM_MALLOC( sizeof( BUILTIN_FUNCTION ) );
+ result->base.type = FUNCTION_BUILTIN;
+ result->base.reference_count = 1;
+ result->base.rulename = 0;
+ result->base.formal_arguments = arg_list_compile_builtin( args, &result->base.num_formal_arguments );
+ result->func = func;
+ result->flags = flags;
+ return (FUNCTION *)result;
+}
+
+FUNCTION * function_compile( PARSE * parse )
+{
+ compiler c[1];
+ JAM_FUNCTION * result;
+ compiler_init( c );
+ compile_parse( parse, c, RESULT_RETURN );
+ compile_emit( c, INSTR_RETURN, 0 );
+ result = compile_to_function( c );
+ compiler_free( c );
+ result->file = object_copy( parse->file );
+ result->line = parse->line;
+ return (FUNCTION *)result;
+}
+
+FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line )
+{
+ compiler c[1];
+ JAM_FUNCTION * result;
+ VAR_PARSE_ACTIONS * parse;
+ current_file = object_str( file );
+ current_line = line;
+ parse = parse_actions( actions );
+ compiler_init( c );
+ var_parse_actions_compile( parse, c );
+ var_parse_actions_free( parse );
+ compile_emit( c, INSTR_RETURN, 0 );
+ result = compile_to_function( c );
+ compiler_free( c );
+ result->file = object_copy( file );
+ result->line = line;
+ return (FUNCTION *)result;
+}
+
+static void argument_list_print( struct arg_list * args, int num_args );
+
+
+/* Define delimiters for type check elements in argument lists (and return type
+ * specifications, eventually).
+ */
+# define TYPE_OPEN_DELIM '['
+# define TYPE_CLOSE_DELIM ']'
+
+/*
+ * is_type_name() - true iff the given string represents a type check
+ * specification.
+ */
+
+int is_type_name( const char * s )
+{
+ return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
+ ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
+}
+
+static void argument_error( const char * message, FUNCTION * procedure, FRAME * frame, OBJECT * arg )
+{ extern void print_source_line( FRAME * );
+ LOL * actual = frame->args;
+ backtrace_line( frame->prev );
+ printf( "*** argument error\n* rule %s ( ", frame->rulename );
+ argument_list_print( procedure->formal_arguments, procedure->num_formal_arguments );
+ printf( " )\n* called with: ( " );
+ lol_print( actual );
+ printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" );
+ function_location( procedure, &frame->file, &frame->line );
+ print_source_line( frame );
+ printf( "see definition of rule '%s' being called\n", frame->rulename );
+ backtrace( frame->prev );
+ exit( 1 );
+}
+
+static void type_check_range
+(
+ OBJECT * type_name,
+ LISTITER iter,
+ LISTITER end,
+ FRAME * caller,
+ FUNCTION * called,
+ OBJECT * arg_name
+)
+{
+ static module_t * typecheck = 0;
+
+ /* If nothing to check, bail now. */
+ if ( iter == end || !type_name )
+ return;
+
+ if ( !typecheck )
+ {
+ typecheck = bindmodule( constant_typecheck );
+ }
+
+ /* If the checking rule can not be found, also bail. */
+ if ( !typecheck->rules || !hash_find( typecheck->rules, type_name ) )
+ return;
+
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ LIST *error;
+ FRAME frame[1];
+ frame_init( frame );
+ frame->module = typecheck;
+ frame->prev = caller;
+ frame->prev_user = caller->module->user_module ? caller : caller->prev_user;
+
+ /* Prepare the argument list */
+ lol_add( frame->args, list_new( object_copy( list_item( iter ) ) ) );
+ error = evaluate_rule( type_name, frame );
+
+ if ( !list_empty( error ) )
+ argument_error( object_str( list_front( error ) ), called, caller, arg_name );
+
+ frame_free( frame );
+ }
+}
+
+static void type_check
+(
+ OBJECT * type_name,
+ LIST * values,
+ FRAME * caller,
+ FUNCTION * called,
+ OBJECT * arg_name
+)
+{
+ type_check_range( type_name, list_begin( values ), list_end( values ), caller, called, arg_name );
+}
+
+void argument_list_check( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ LIST * value;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, function, formal_arg->arg_name );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", function, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", function, frame, list_front( actual ) );
+ }
+ }
+}
+
+void argument_list_push( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame, STACK * s )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ LIST * value;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ value = list_new( object_copy( list_item( actual_iter ) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ value = list_new( object_copy( list_item( actual_iter ) ) );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ value = list_copy_range( actual, actual_iter, actual_end );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ type_check( formal_arg->type_name, value, frame, function, formal_arg->arg_name );
+
+ if ( formal_arg->index != -1 )
+ {
+ LIST * * old = &frame->module->fixed_variables[ formal_arg->index ];
+ stack_push( s, *old );
+ *old = value;
+ }
+ else
+ {
+ stack_push( s, var_swap( frame->module, formal_arg->arg_name, value ) );
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", function, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", function, frame, list_front( actual ) );
+ }
+ }
+}
+
+void argument_list_pop( struct arg_list * formal, int formal_count, FRAME * frame, STACK * s )
+{
+ int i, j;
+
+ for ( i = formal_count - 1; i >= 0; --i )
+ {
+ for ( j = formal[i].size - 1; j >= 0 ; --j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+
+ if ( formal_arg->flags == ARG_VARIADIC )
+ {
+ continue;
+ }
+ else if ( formal_arg->index != -1 )
+ {
+ LIST * old = stack_pop( s );
+ LIST * * pos = &frame->module->fixed_variables[ formal_arg->index ];
+ list_free( *pos );
+ *pos = old;
+ }
+ else
+ {
+ var_set( frame->module, formal_arg->arg_name, stack_pop( s ), VAR_SET );
+ }
+ }
+ }
+}
+
+
+struct argument_compiler
+{
+ struct dynamic_array args[ 1 ];
+ struct argument arg;
+ int state;
+#define ARGUMENT_COMPILER_START 0
+#define ARGUMENT_COMPILER_FOUND_TYPE 1
+#define ARGUMENT_COMPILER_FOUND_OBJECT 2
+#define ARGUMENT_COMPILER_DONE 3
+};
+
+
+static void argument_compiler_init( struct argument_compiler * c )
+{
+ dynamic_array_init( c->args );
+ c->state = ARGUMENT_COMPILER_START;
+}
+
+static void argument_compiler_free( struct argument_compiler * c )
+{
+ dynamic_array_free( c->args );
+}
+
+static void argument_compiler_add( struct argument_compiler * c, OBJECT * arg, OBJECT * file, int line )
+{
+ switch ( c->state )
+ {
+ case ARGUMENT_COMPILER_FOUND_OBJECT:
+
+ if ( object_equal( arg, constant_question_mark ) )
+ {
+ c->arg.flags = ARG_OPTIONAL;
+ }
+ else if ( object_equal( arg, constant_plus ) )
+ {
+ c->arg.flags = ARG_PLUS;
+ }
+ else if ( object_equal( arg, constant_star ) )
+ {
+ c->arg.flags = ARG_STAR;
+ }
+
+ dynamic_array_push( c->args, c->arg );
+ c->state = ARGUMENT_COMPILER_START;
+
+ if ( c->arg.flags != ARG_ONE )
+ break;
+ /* fall-through */
+
+ case ARGUMENT_COMPILER_START:
+
+ c->arg.type_name = 0;
+ c->arg.index = -1;
+ c->arg.flags = ARG_ONE;
+
+ if ( is_type_name( object_str( arg ) ) )
+ {
+ c->arg.type_name = object_copy( arg );
+ c->state = ARGUMENT_COMPILER_FOUND_TYPE;
+ break;
+ }
+ /* fall-through */
+
+ case ARGUMENT_COMPILER_FOUND_TYPE:
+
+ if ( is_type_name( object_str( arg ) ) )
+ {
+ printf( "%s:%d: missing argument name before type name: %s\n", object_str( file ), line, object_str( arg ) );
+ exit( 1 );
+ }
+
+ c->arg.arg_name = object_copy( arg );
+ if ( object_equal( arg, constant_star ) )
+ {
+ c->arg.flags = ARG_VARIADIC;
+ dynamic_array_push( c->args, c->arg );
+ c->state = ARGUMENT_COMPILER_DONE;
+ }
+ else
+ {
+ c->state = ARGUMENT_COMPILER_FOUND_OBJECT;
+ }
+ break;
+
+ case ARGUMENT_COMPILER_DONE:
+ break;
+ }
+}
+
+static void argument_compiler_recurse( struct argument_compiler * c, PARSE * parse )
+{
+ if ( parse->type == PARSE_APPEND )
+ {
+ argument_compiler_recurse( c, parse->left );
+ argument_compiler_recurse( c, parse->right );
+ }
+ else if ( parse->type != PARSE_NULL )
+ {
+ assert( parse->type == PARSE_LIST );
+ argument_compiler_add( c, parse->string, parse->file, parse->line );
+ }
+}
+
+static struct arg_list arg_compile_impl( struct argument_compiler * c, OBJECT * file, int line )
+{
+ struct arg_list result;
+ switch ( c->state )
+ {
+ case ARGUMENT_COMPILER_START:
+ case ARGUMENT_COMPILER_DONE:
+ break;
+ case ARGUMENT_COMPILER_FOUND_TYPE:
+ printf( "%s:%d: missing argument name after type name: %s\n", object_str( file ), line, object_str( c->arg.type_name ) );
+ exit( 1 );
+ case ARGUMENT_COMPILER_FOUND_OBJECT:
+ dynamic_array_push( c->args, c->arg );
+ break;
+ }
+ result.size = c->args->size;
+ result.args = BJAM_MALLOC( c->args->size * sizeof( struct argument ) );
+ memcpy( result.args, c->args->data, c->args->size * sizeof( struct argument ) );
+ return result;
+}
+
+static struct arg_list arg_compile( PARSE * parse )
+{
+ struct argument_compiler c[ 1 ];
+ struct arg_list result;
+ argument_compiler_init( c );
+ argument_compiler_recurse( c, parse );
+ result = arg_compile_impl( c, parse->file, parse->line );
+ argument_compiler_free( c );
+ return result;
+}
+
+struct argument_list_compiler
+{
+ struct dynamic_array args[ 1 ];
+};
+
+static void argument_list_compiler_init( struct argument_list_compiler * c )
+{
+ dynamic_array_init( c->args );
+}
+
+static void argument_list_compiler_free( struct argument_list_compiler * c )
+{
+ dynamic_array_free( c->args );
+}
+
+static void argument_list_compiler_add( struct argument_list_compiler * c, PARSE * parse )
+{
+ struct arg_list args = arg_compile( parse );
+ dynamic_array_push( c->args, args );
+}
+
+static void argument_list_compiler_recurse( struct argument_list_compiler * c, PARSE * parse )
+{
+ if ( parse )
+ {
+ argument_list_compiler_add( c, parse->right );
+ argument_list_compiler_recurse( c, parse->left );
+ }
+}
+
+static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments )
+{
+ if ( parse )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ argument_list_compiler_init( c );
+ argument_list_compiler_recurse( c, parse );
+ *num_arguments = c->args->size;
+ result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments )
+{
+ if ( args )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ argument_list_compiler_init( c );
+ while ( *args )
+ {
+ struct argument_compiler arg_comp[ 1 ];
+ struct arg_list arg;
+ argument_compiler_init( arg_comp );
+ for ( ; *args; ++args )
+ {
+ OBJECT * token;
+ if ( strcmp( *args, ":" ) == 0 )
+ {
+ ++args;
+ break;
+ }
+ token = object_new( *args );
+ argument_compiler_add( arg_comp, token, constant_builtin, -1 );
+ object_free( token );
+ }
+ arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
+ dynamic_array_push( c->args, arg );
+ argument_compiler_free( arg_comp );
+ }
+ *num_arguments = c->args->size;
+ result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+static void argument_list_print( struct arg_list * args, int num_args )
+{
+ if ( args )
+ {
+ int i, j;
+ for ( i = 0; i < num_args; ++i )
+ {
+ if ( i ) printf(" : ");
+ for ( j = 0; j < args[ i ].size; ++j )
+ {
+ struct argument * formal_arg = &args[ i ].args[ j ];
+ if ( j ) printf( " " );
+ if ( formal_arg->type_name ) printf( "%s ", object_str( formal_arg->type_name ) );
+ printf( "%s", formal_arg->arg_name );
+ switch( formal_arg->flags )
+ {
+ case ARG_OPTIONAL: printf( " ?" ); break;
+ case ARG_PLUS: printf( " +" ); break;
+ case ARG_STAR: printf( " *" ); break;
+ }
+ }
+ }
+ }
+}
+
+
+struct arg_list * argument_list_bind_variables( struct arg_list * formal, int formal_count, module_t * module, int * counter )
+{
+ if ( formal )
+ {
+ struct arg_list * result = (struct arg_list *)BJAM_MALLOC( sizeof( struct arg_list ) * formal_count );
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ struct argument * args = (struct argument *)BJAM_MALLOC( sizeof( struct argument ) * formal[ i ].size );
+ for ( j = 0; j < formal[ i ].size; ++j )
+ {
+ args[ j ] = formal[ i ].args[ j ];
+ if ( args[ j ].type_name )
+ args[ j ].type_name = object_copy( args[ j ].type_name );
+ args[ j ].arg_name = object_copy( args[ j ].arg_name );
+ if ( args[ j ].flags != ARG_VARIADIC )
+ {
+ args[ j ].index = module_add_fixed_var( module, args[ j ].arg_name, counter );
+ }
+ }
+ result[ i ].args = args;
+ result[ i ].size = formal[ i ].size;
+ }
+
+ return result;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+void argument_list_free( struct arg_list * args, int args_count )
+{
+ int i, j;
+ for ( i = 0; i < args_count; ++i )
+ {
+ for ( j = 0; j < args[ i ].size; ++j )
+ {
+ if ( args[ i ].args[ j ].type_name )
+ object_free( args[ i ].args[ j ].type_name );
+ object_free( args[ i ].args[ j ].arg_name );
+ }
+ BJAM_FREE( args[ i ].args );
+ }
+ BJAM_FREE( args );
+}
+
+
+FUNCTION * function_unbind_variables( FUNCTION * f )
+{
+ if ( f->type == FUNCTION_JAM )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ if ( func->generic )
+ return func->generic;
+ else
+ return (FUNCTION *)func;
+ }
+#ifdef HAVE_PYTHON
+ else if ( f->type == FUNCTION_PYTHON )
+ {
+ return f;
+ }
+#endif
+ else
+ {
+ assert( f->type == FUNCTION_BUILTIN );
+ return f;
+ }
+}
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter )
+{
+ if ( f->type == FUNCTION_BUILTIN )
+ {
+ return f;
+ }
+#ifdef HAVE_PYTHON
+ else if ( f->type == FUNCTION_PYTHON )
+ {
+ return f;
+ }
+#endif
+ else
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ JAM_FUNCTION * new_func = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
+ instruction * code;
+ int i;
+ assert( f->type == FUNCTION_JAM );
+ memcpy( new_func, func, sizeof( JAM_FUNCTION ) );
+ new_func->base.reference_count = 1;
+ new_func->base.formal_arguments = argument_list_bind_variables( f->formal_arguments, f->num_formal_arguments, module, counter );
+ new_func->code = BJAM_MALLOC( func->code_size * sizeof( instruction ) );
+ memcpy( new_func->code, func->code, func->code_size * sizeof( instruction ) );
+ new_func->generic = (FUNCTION *)func;
+ func = new_func;
+ for ( i = 0; ; ++i )
+ {
+ OBJECT * key;
+ int op_code;
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_VAR: op_code = INSTR_PUSH_VAR_FIXED; break;
+ case INSTR_PUSH_LOCAL: op_code = INSTR_PUSH_LOCAL_FIXED; break;
+ case INSTR_POP_LOCAL: op_code = INSTR_POP_LOCAL_FIXED; break;
+ case INSTR_SET: op_code = INSTR_SET_FIXED; break;
+ case INSTR_APPEND: op_code = INSTR_APPEND_FIXED; break;
+ case INSTR_DEFAULT: op_code = INSTR_DEFAULT_FIXED; break;
+ case INSTR_RETURN: return (FUNCTION *)new_func;
+ case INSTR_CALL_RULE: ++i; continue;
+ case INSTR_PUSH_MODULE:
+ {
+ int depth = 1;
+ ++i;
+ while ( depth > 0 )
+ {
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_MODULE:
+ case INSTR_CLASS:
+ ++depth;
+ break;
+ case INSTR_POP_MODULE:
+ --depth;
+ break;
+ case INSTR_CALL_RULE:
+ ++i;
+ break;
+ }
+ ++i;
+ }
+ --i;
+ }
+ default: continue;
+ }
+ key = func->constants[ code->arg ];
+ if ( !( object_equal( key, constant_TMPDIR ) ||
+ object_equal( key, constant_TMPNAME ) ||
+ object_equal( key, constant_TMPFILE ) ||
+ object_equal( key, constant_STDOUT ) ||
+ object_equal( key, constant_STDERR ) ) )
+ {
+ code->op_code = op_code;
+ code->arg = module_add_fixed_var( module, key, counter );
+ }
+ }
+ }
+}
+
+void function_refer( FUNCTION * func )
+{
+ ++func->reference_count;
+}
+
+void function_free( FUNCTION * function_ )
+{
+ int i;
+
+ if ( --function_->reference_count != 0 ) return;
+
+ if ( function_->formal_arguments ) argument_list_free( function_->formal_arguments, function_->num_formal_arguments );
+
+ if ( function_->type == FUNCTION_JAM )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)function_;
+
+ BJAM_FREE( func->code );
+
+ if ( func->generic )
+ function_free( func->generic );
+ else
+ {
+ if ( function_->rulename ) object_free( function_->rulename );
+
+ for ( i = 0; i < func->num_constants; ++i )
+ {
+ object_free( func->constants[i] );
+ }
+ BJAM_FREE( func->constants );
+
+ for ( i = 0; i < func->num_subfunctions; ++i )
+ {
+ object_free( func->functions[i].name );
+ function_free( func->functions[i].code );
+ }
+ BJAM_FREE( func->functions );
+
+ for ( i = 0; i < func->num_subactions; ++i )
+ {
+ object_free( func->actions[i].name );
+ function_free( func->actions[i].command );
+ }
+ BJAM_FREE( func->actions );
+
+ object_free( func->file );
+ }
+ }
+#ifdef HAVE_PYTHON
+ else if ( function_->type == FUNCTION_PYTHON )
+ {
+ PYTHON_FUNCTION * func = (PYTHON_FUNCTION *)function_;
+ Py_DECREF( func->python_function );
+ if ( function_->rulename ) object_free( function_->rulename );
+ }
+#endif
+ else
+ {
+ assert( function_->type == FUNCTION_BUILTIN );
+ if ( function_->rulename ) object_free( function_->rulename );
+ }
+
+ BJAM_FREE( function_ );
+}
+
+
+/* Alignment check for stack */
+
+struct align_var_edits
+{
+ char ch;
+ VAR_EDITS e;
+};
+
+struct align_expansion_item
+{
+ char ch;
+ expansion_item e;
+};
+
+static char check_align_var_edits[ sizeof(struct align_var_edits) <= sizeof(VAR_EDITS) + sizeof(void *) ? 1 : -1 ];
+static char check_align_expansion_item[ sizeof(struct align_expansion_item) <= sizeof(expansion_item) + sizeof(void *) ? 1 : -1 ];
+
+static char check_ptr_size1[ sizeof(LIST *) <= sizeof(void *) ? 1 : -1 ];
+static char check_ptr_size2[ sizeof(char *) <= sizeof(void *) ? 1 : -1 ];
+
+void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string * out )
+{
+ *(string * *)stack_allocate( s, sizeof( string * ) ) = out;
+ list_free( function_run( function, frame, s ) );
+ stack_deallocate( s, sizeof( string * ) );
+}
+
+/*
+ * WARNING: The instruction set is tuned for Jam and
+ * is not really generic. Be especially careful about
+ * stack push/pop.
+ */
+
+LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s )
+{
+ JAM_FUNCTION * function;
+ instruction * code;
+ LIST * l;
+ LIST * r;
+ LIST * result = L0;
+ void * saved_stack = s->data;
+
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
+ if ( function_->formal_arguments )
+ argument_list_check( function_->formal_arguments, function_->num_formal_arguments, function_, frame );
+ return f->func( frame, f->flags );
+ }
+
+#ifdef HAVE_PYTHON
+
+ else if ( function_->type == FUNCTION_PYTHON )
+ {
+ PYTHON_FUNCTION * f = (PYTHON_FUNCTION *)function_;
+ return call_python_function( f, frame );
+ }
+
+#endif
+
+ assert( function_->type == FUNCTION_JAM );
+
+ if ( function_->formal_arguments )
+ argument_list_push( function_->formal_arguments, function_->num_formal_arguments, function_, frame, s );
+
+ function = (JAM_FUNCTION *)function_;
+ code = function->code;
+ for ( ; ; )
+ {
+ switch ( code->op_code )
+ {
+
+ /*
+ * Basic stack manipulation
+ */
+
+ case INSTR_PUSH_EMPTY:
+ {
+ stack_push( s, L0 );
+ break;
+ }
+
+ case INSTR_PUSH_CONSTANT:
+ {
+ OBJECT * value = function_get_constant( function, code->arg );
+ stack_push( s, list_new( object_copy( value ) ) );
+ break;
+ }
+
+ case INSTR_PUSH_ARG:
+ {
+ stack_push( s, frame_get_local( frame, code->arg ) );
+ break;
+ }
+
+ case INSTR_PUSH_VAR:
+ {
+ stack_push( s, function_get_variable( function, frame, code->arg ) );
+ break;
+ }
+
+ case INSTR_PUSH_VAR_FIXED:
+ {
+ stack_push( s, list_copy( frame->module->fixed_variables[ code->arg ] ) );
+ break;
+ }
+
+ case INSTR_PUSH_GROUP:
+ {
+ LIST * value = L0;
+ LISTITER iter, end;
+ l = stack_pop( s );
+ for ( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
+ {
+ LIST * one = function_get_named_variable( function, frame, list_item( iter ) );
+ value = list_append( value, one );
+ }
+ list_free( l );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_PUSH_APPEND:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ stack_push( s, list_append( l, r ) );
+ break;
+ }
+
+ case INSTR_SWAP:
+ {
+ l = stack_top( s );
+ stack_set( s, 0, stack_at( s, code->arg ) );
+ stack_set( s, code->arg, l );
+ break;
+ }
+
+ case INSTR_POP:
+ {
+ list_free( stack_pop( s ) );
+ break;
+ }
+
+ /*
+ * Branch instructions
+ */
+
+ case INSTR_JUMP:
+ {
+ code += code->arg;
+ break;
+ }
+
+ case INSTR_JUMP_EMPTY:
+ {
+ l = stack_pop( s );
+ if ( !list_cmp( l, L0 ) ) { code += code->arg; }
+ list_free( l );
+ break;
+ }
+
+ case INSTR_JUMP_NOT_EMPTY:
+ {
+ l = stack_pop( s );
+ if( list_cmp( l, L0 ) ) { code += code->arg; }
+ list_free( l );
+ break;
+ }
+
+ case INSTR_JUMP_LT:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) < 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_LE:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) <= 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_GT:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) > 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_GE:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if ( list_cmp( l, r ) >= 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_EQ:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if( list_cmp( l, r ) == 0 ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ case INSTR_JUMP_NE:
+ {
+ r = stack_pop(s);
+ l = stack_pop(s);
+ if( list_cmp(l, r) != 0 ) { code += code->arg; }
+ list_free(l);
+ list_free(r);
+ break;
+ }
+
+ case INSTR_JUMP_IN:
+ {
+ r = stack_pop(s);
+ l = stack_pop(s);
+ if ( list_is_sublist( l, r ) ) { code += code->arg; }
+ list_free(l);
+ list_free(r);
+ break;
+ }
+
+ case INSTR_JUMP_NOT_IN:
+ {
+ r = stack_pop( s );
+ l = stack_pop( s );
+ if( !list_is_sublist( l, r ) ) { code += code->arg; }
+ list_free( l );
+ list_free( r );
+ break;
+ }
+
+ /*
+ * For
+ */
+
+ case INSTR_FOR_INIT:
+ {
+ l = stack_top( s );
+ *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) =
+ list_begin( l );
+ break;
+ }
+
+ case INSTR_FOR_LOOP:
+ {
+ LISTITER iter = *(LISTITER *)stack_get( s );
+ stack_deallocate( s, sizeof( LISTITER ) );
+ l = stack_top( s );
+ if( iter == list_end( l ) )
+ {
+ list_free( stack_pop( s ) );
+ code += code->arg;
+ }
+ else
+ {
+ r = list_new( object_copy( list_item( iter ) ) );
+ iter = list_next( iter );
+ *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) = iter;
+ stack_push( s, r );
+ }
+ break;
+ }
+
+ /*
+ * Switch
+ */
+
+ case INSTR_JUMP_NOT_GLOB:
+ {
+ const char * pattern;
+ const char * match;
+ l = stack_pop( s );
+ r = stack_top( s );
+ pattern = !list_empty( l ) ? object_str( list_front( l ) ) : "";
+ match = !list_empty( r ) ? object_str( list_front( r ) ) : "";
+ if( glob( pattern, match ) )
+ {
+ code += code->arg;
+ }
+ else
+ {
+ list_free( stack_pop( s ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * Return
+ */
+
+ case INSTR_SET_RESULT:
+ {
+ list_free( result );
+ result = stack_pop( s );
+ break;
+ }
+
+ case INSTR_PUSH_RESULT:
+ {
+ stack_push( s, result );
+ result = L0;
+ break;
+ }
+
+ case INSTR_RETURN:
+ {
+ if ( function_->formal_arguments )
+ argument_list_pop( function_->formal_arguments, function_->num_formal_arguments, frame, s );
+#ifndef NDEBUG
+
+ if ( !( saved_stack == s->data ) )
+ {
+ frame->file = function->file;
+ frame->line = function->line;
+ backtrace_line( frame );
+ printf( "error: stack check failed.\n" );
+ backtrace( frame );
+ assert( saved_stack == s->data );
+ }
+#endif
+ assert( saved_stack == s->data );
+ return result;
+ }
+
+ /*
+ * Local variables
+ */
+
+ case INSTR_PUSH_LOCAL:
+ {
+ LIST * value = stack_pop( s );
+ stack_push( s, function_swap_variable( function, frame, code->arg, value ) );
+ break;
+ }
+
+ case INSTR_POP_LOCAL:
+ {
+ function_set_variable( function, frame, code->arg, stack_pop( s ) );
+ break;
+ }
+
+ case INSTR_PUSH_LOCAL_FIXED:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ stack_push( s, *ptr );
+ *ptr = value;
+ break;
+ }
+
+ case INSTR_POP_LOCAL_FIXED:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ list_free( *ptr );
+ *ptr = value;
+ break;
+ }
+
+ case INSTR_PUSH_LOCAL_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LISTITER iter, end;
+ l = stack_pop( s );
+ for( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
+ {
+ LIST * saved = function_swap_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ stack_push( s, saved );
+ }
+ list_free( value );
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_POP_LOCAL_GROUP:
+ {
+ LISTITER iter, end;
+ r = stack_pop( s );
+ l = list_reverse( r );
+ list_free( r );
+ for( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
+ {
+ function_set_named_variable( function, frame, list_item( iter ), stack_pop( s ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * on $(TARGET) variables
+ */
+
+ case INSTR_PUSH_ON:
+ {
+ LIST * targets = stack_top( s );
+ if ( !list_empty( targets ) )
+ {
+ /*
+ * FIXME: push the state onto the stack instead of
+ * using pushsettings.
+ */
+ TARGET * t = bindtarget( list_front( targets ) );
+ pushsettings( frame->module, t->settings );
+ }
+ else
+ {
+ /*
+ * [ on $(TARGET) ... ] is ignored if $(TARGET) is empty.
+ */
+ list_free( stack_pop( s ) );
+ stack_push( s, L0 );
+ code += code->arg;
+ }
+ break;
+ }
+
+ case INSTR_POP_ON:
+ {
+ LIST * result = stack_pop( s );
+ LIST * targets = stack_pop( s );
+ if ( !list_empty( targets ) )
+ {
+ TARGET * t = bindtarget( list_front( targets ) );
+ popsettings( frame->module, t->settings );
+ }
+ list_free( targets );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_SET_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
+ t->settings = addsettings( t->settings, VAR_SET, list_item( vars_iter ),
+ list_copy( value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
+ t->settings = addsettings( t->settings, VAR_APPEND, list_item( vars_iter ),
+ list_copy( value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
+ t->settings = addsettings( t->settings, VAR_DEFAULT, list_item( vars_iter ),
+ list_copy( value ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Variable setting
+ */
+
+ case INSTR_SET:
+ {
+ function_set_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_APPEND:
+ {
+ function_append_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_DEFAULT:
+ {
+ function_default_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_SET_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ list_free( *ptr );
+ *ptr = list_copy( stack_top( s ) );
+ break;
+ }
+
+ case INSTR_APPEND_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ *ptr = list_append( *ptr, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_DEFAULT_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ if ( list_empty( *ptr ) )
+ *ptr = list_copy( stack_top( s ) );
+ break;
+ }
+
+ case INSTR_SET_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ function_set_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ function_append_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ function_default_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Rules
+ */
+
+ case INSTR_CALL_RULE:
+ {
+ const char * unexpanded =
+ object_str( function_get_constant( function, code[1].op_code ) );
+ LIST * result = function_call_rule( function, frame, s, code->arg, unexpanded, function->file, code[1].arg );
+ stack_push( s, result );
+ ++code;
+ break;
+ }
+
+ case INSTR_RULE:
+ {
+ function_set_rule( function, frame, s, code->arg );
+ break;
+ }
+
+ case INSTR_ACTIONS:
+ {
+ function_set_actions( function, frame, s, code->arg );
+ break;
+ }
+
+ /*
+ * Variable expansion
+ */
+
+ case INSTR_APPLY_MODIFIERS:
+ {
+ int n;
+ int i;
+ l = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, l );
+ l = apply_modifiers( s, n );
+ list_free( stack_pop( s ) );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX:
+ {
+ l = apply_subscript( s );
+ list_free( stack_pop( s ) );
+ list_free( stack_pop( s ) );
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_MODIFIERS:
+ {
+ int i;
+ int n;
+ l = stack_pop( s );
+ r = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, r );
+ stack_push( s, l );
+ l = apply_subscript_and_modifiers( s, n );
+ list_free( stack_pop( s ) );
+ list_free( stack_pop( s ) );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_MODIFIERS_GROUP:
+ {
+ int i;
+ LIST * vars = stack_pop( s );
+ int n = expand_modifiers( s, code->arg );
+ LIST * result = L0;
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ result = list_append( result, apply_modifiers( s, n ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( vars );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_GROUP:
+ {
+ LIST * vars = stack_pop( s );
+ LIST * result = L0;
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ for( ; iter != end; iter = list_next( iter ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ result = list_append( result, apply_subscript( s ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( vars );
+ list_free( stack_pop( s ) );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_APPLY_INDEX_MODIFIERS_GROUP:
+ {
+ int i;
+ LIST * vars = stack_pop( s );
+ LIST * r = stack_pop( s );
+ int n = expand_modifiers( s, code->arg );
+ LIST * result = L0;
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ stack_push( s, r );
+ for( ; iter != end; iter = list_next( iter ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ result = list_append( result, apply_subscript_and_modifiers( s, n ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( stack_pop( s ) );
+ list_free( vars );
+ stack_deallocate( s, n * sizeof( VAR_EDITS ) );
+ for ( i = 0; i < code->arg; ++i )
+ list_free( stack_pop( s ) ); /* pop modifiers */
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_COMBINE_STRINGS:
+ {
+ LIST * result;
+ size_t buffer_size = code->arg * sizeof( expansion_item );
+ LIST * * stack_pos = stack_get( s );
+ expansion_item * items = stack_allocate( s, buffer_size );
+ int i;
+ for( i = 0; i < code->arg; ++i )
+ {
+ items[i].saved = stack_pos[i];
+ items[i].elem = list_begin( items[i].saved );
+ }
+ result = expand( items, code->arg );
+ stack_deallocate( s, buffer_size );
+ for( i = 0; i < code->arg; ++i )
+ {
+ list_free( stack_pop( s ) );
+ }
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_INCLUDE:
+ {
+ LIST * nt = stack_pop( s );
+
+ if ( !list_empty( nt ) )
+ {
+ TARGET * t = bindtarget( list_front( nt ) );
+ list_free( nt );
+
+ /* DWA 2001/10/22 - Perforce Jam cleared the arguments here, which
+ * prevents an included file from being treated as part of the body of a
+ * rule. I did not see any reason to do that, so I lifted the
+ * restriction.
+ */
+
+ /* Bind the include file under the influence of */
+ /* "on-target" variables. Though they are targets, */
+ /* include files are not built with make(). */
+
+ pushsettings( root_module(), t->settings );
+ /* We don't expect that file to be included is generated by some
+ action. Therefore, pass 0 as third argument.
+ If the name resolves to directory, let it error out. */
+ object_free( t->boundname );
+ t->boundname = search( t->name, &t->time, 0, 0 );
+ popsettings( root_module(), t->settings );
+
+ parse_file( t->boundname, frame );
+ }
+
+ break;
+ }
+
+ /*
+ * Classes and modules
+ */
+
+ case INSTR_PUSH_MODULE:
+ {
+ LIST * module_name = stack_pop( s );
+
+ module_t * outer_module = frame->module;
+ frame->module = !list_empty( module_name ) ? bindmodule( list_front( module_name ) ) : root_module();
+
+ list_free( module_name );
+
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
+
+ break;
+ }
+
+ case INSTR_POP_MODULE:
+ {
+ module_t * outer_module = *(module_t * *)stack_get( s );
+ stack_deallocate( s, sizeof( module_t * ) );
+ frame->module = outer_module;
+ break;
+ }
+
+ case INSTR_CLASS:
+ {
+ LIST * bases = stack_pop( s );
+ LIST * name = stack_pop( s );
+ OBJECT * class_module = make_class_module( name, bases, frame );
+
+ module_t * outer_module = frame->module;
+ frame->module = bindmodule( class_module );
+ object_free( class_module );
+
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
+
+ break;
+ }
+
+ case INSTR_BIND_MODULE_VARIABLES:
+ {
+ module_bind_variables( frame->module );
+ break;
+ }
+
+ case INSTR_APPEND_STRINGS:
+ {
+ string buf[1];
+ string_new( buf );
+ combine_strings( s, code->arg, buf );
+ stack_push( s, list_new( object_new( buf->value ) ) );
+ string_free( buf );
+ break;
+ }
+
+ case INSTR_WRITE_FILE:
+ {
+ string buf[1];
+ const char * out;
+ OBJECT * tmp_filename = 0;
+ int out_debug = DEBUG_EXEC ? 1 : 0;
+ FILE * out_file = 0;
+ string_new( buf );
+ combine_strings( s, code->arg, buf );
+ out = object_str( list_front( stack_top( s ) ) );
+
+ /* For stdout/stderr we will create a temp file and generate
+ * a command that outputs the content as needed.
+ */
+ if ( ( strcmp( "STDOUT", out ) == 0 ) ||
+ ( strcmp( "STDERR", out ) == 0 ) )
+ {
+ int err_redir = strcmp( "STDERR", out ) == 0;
+ string result[1];
+ tmp_filename = path_tmpfile();
+ string_new( result );
+
+ #ifdef OS_NT
+ string_append( result, "type \"" );
+ #else
+ string_append( result, "cat \"" );
+ #endif
+ string_append( result, object_str( tmp_filename ) );
+ string_push_back( result, '\"' );
+ if ( err_redir )
+ string_append( result, " 1>&2" );
+
+ /* Replace STDXXX with the temporary file. */
+ list_free( stack_pop( s ) );
+ stack_push( s, list_new( object_new( result->value ) ) );
+ out = object_str( tmp_filename );
+
+ string_free( result );
+
+ /* We also make sure that the temp files created by this
+ * get nuked eventually.
+ */
+ file_remove_atexit( tmp_filename );
+ }
+
+ if ( !globs.noexec )
+ {
+ string out_name[1];
+ /* Handle "path to file" filenames. */
+ if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) )
+ {
+ string_copy( out_name, out + 1 );
+ string_truncate( out_name, out_name->size - 1 );
+ }
+ else
+ {
+ string_copy( out_name, out );
+ }
+ out_file = fopen( out_name->value, "w" );
+
+ if ( !out_file )
+ {
+ printf( "failed to write output file '%s'!\n", out_name->value );
+ exit( EXITBAD );
+ }
+ string_free( out_name );
+ }
+
+ if ( out_debug ) printf( "\nfile %s\n", out );
+
+ if ( out_file ) fputs( buf->value, out_file );
+ if ( out_debug ) fputs( buf->value, stdout );
+
+ if ( out_file )
+ {
+ fflush( out_file );
+ fclose( out_file );
+ }
+ string_free( buf );
+ if ( tmp_filename )
+ object_free( tmp_filename );
+
+ if ( out_debug ) fputc( '\n', stdout );
+
+ break;
+ }
+
+ case INSTR_OUTPUT_STRINGS:
+ {
+ string * buf = *(string * *)( (char *)stack_get( s ) + ( code->arg * sizeof( LIST * ) ) );
+ combine_strings( s, code->arg, buf );
+ break;
+ }
+
+ }
+ ++code;
+ }
+}
+
+
+#ifdef HAVE_PYTHON
+
+static struct arg_list * arg_list_compile_python( PyObject * bjam_signature, int * num_arguments )
+{
+ if ( bjam_signature )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ Py_ssize_t s, i, j, inner;
+ argument_list_compiler_init( c );
+
+ s = PySequence_Size( bjam_signature );
+ for ( i = 0; i < s; ++i )
+ {
+ struct argument_compiler arg_comp[ 1 ];
+ struct arg_list arg;
+ PyObject * v = PySequence_GetItem( bjam_signature, i );
+ argument_compiler_init( arg_comp );
+
+ inner = PySequence_Size( v );
+ for ( j = 0; j < inner; ++j )
+ {
+ PyObject * x = PySequence_GetItem( v, j );
+ argument_compiler_add( arg_comp, object_new( PyString_AsString( x ) ), constant_builtin, -1 );
+ }
+
+ arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
+ dynamic_array_push( c->args, arg );
+ argument_compiler_free( arg_comp );
+ Py_DECREF( v );
+ }
+
+ *num_arguments = c->args->size;
+ result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+FUNCTION * function_python( PyObject * function, PyObject * bjam_signature )
+{
+ PYTHON_FUNCTION * result = BJAM_MALLOC( sizeof( PYTHON_FUNCTION ) );
+
+ result->base.type = FUNCTION_PYTHON;
+ result->base.reference_count = 1;
+ result->base.rulename = 0;
+ result->base.formal_arguments = arg_list_compile_python( bjam_signature, &result->base.num_formal_arguments );
+ Py_INCREF( function );
+ result->python_function = function;
+
+ return (FUNCTION *)result;
+}
+
+static void argument_list_to_python( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame, PyObject * kw )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ LIST *actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
+ for ( j = 0; j < formal[i].size; ++j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ PyObject * value;
+ LIST * l;
+
+ switch ( formal_arg->flags )
+ {
+ case ARG_ONE:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = 0;
+ else
+ {
+ type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ actual_iter = list_next( actual_iter );
+ }
+ break;
+ case ARG_PLUS:
+ if ( actual_iter == actual_end )
+ argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ /* fallthrough */
+ case ARG_STAR:
+ type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, function, formal_arg->arg_name );
+ l = list_copy_range( actual, actual_iter, actual_end );
+ value = list_to_python( l );
+ list_free( l );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ if (value)
+ {
+ PyObject * key = PyString_FromString( object_str( formal_arg->arg_name ) );
+ PyDict_SetItem( kw, key, value );
+ Py_DECREF( key );
+ Py_DECREF( value );
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ argument_error( "extra argument", function, frame, list_item( actual_iter ) );
+ }
+ }
+
+ for ( ; i < all_actual->count; ++i )
+ {
+ LIST * actual = lol_get( all_actual, i );
+ if ( !list_empty( actual ) )
+ {
+ argument_error( "extra argument", function, frame, list_front( actual ) );
+ }
+ }
+}
+
+/* Given a Python object, return a string to use in Jam
+ code instead of said object.
+ If the object is string, use the string value
+ If the object implemenets __jam_repr__ method, use that.
+ Otherwise return 0. */
+OBJECT * python_to_string( PyObject * value )
+{
+ if ( PyString_Check( value ) )
+ {
+ return object_new( PyString_AsString( value ) );
+ }
+ else
+ {
+ /* See if this is an instance that defines special __jam_repr__
+ method. */
+ if ( PyInstance_Check( value )
+ && PyObject_HasAttrString( value, "__jam_repr__" ) )
+ {
+ PyObject* repr = PyObject_GetAttrString( value, "__jam_repr__" );
+ if ( repr )
+ {
+ PyObject * arguments2 = PyTuple_New( 0 );
+ PyObject * value2 = PyObject_Call( repr, arguments2, 0 );
+ Py_DECREF( repr );
+ Py_DECREF( arguments2 );
+ if ( PyString_Check( value2 ) )
+ {
+ return object_new( PyString_AsString( value2 ) );
+ }
+ Py_DECREF( value2 );
+ }
+ }
+ return 0;
+ }
+}
+
+static module_t * python_module()
+{
+ static module_t * python = 0;
+ if ( !python )
+ python = bindmodule(constant_python);
+ return python;
+}
+
+static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame )
+{
+ LIST * result = 0;
+ PyObject * arguments = 0;
+ PyObject * kw = NULL;
+ int i ;
+ PyObject * py_result;
+ FRAME * prev_frame_before_python_call;
+
+ if ( function->base.formal_arguments )
+ {
+ arguments = PyTuple_New(0);
+ kw = PyDict_New();
+
+ argument_list_to_python( function->base.formal_arguments, function->base.num_formal_arguments, &function->base, frame, kw );
+ }
+ else
+ {
+ arguments = PyTuple_New( frame->args->count );
+ for ( i = 0; i < frame->args->count; ++i )
+ {
+ PyTuple_SetItem( arguments, i, list_to_python( lol_get( frame->args, i ) ) );
+ }
+ }
+
+ frame->module = python_module();
+
+ prev_frame_before_python_call = frame_before_python_call;
+ frame_before_python_call = frame;
+ py_result = PyObject_Call( function->python_function, arguments, kw );
+ frame_before_python_call = prev_frame_before_python_call;
+ Py_DECREF( arguments );
+ Py_XDECREF( kw );
+ if ( py_result != NULL )
+ {
+ if ( PyList_Check( py_result ) )
+ {
+ int size = PyList_Size( py_result );
+ int i;
+ for ( i = 0; i < size; ++i )
+ {
+ PyObject * item = PyList_GetItem( py_result, i );
+ OBJECT *s = python_to_string( item );
+ if ( !s ) {
+ fprintf( stderr, "Non-string object returned by Python call.\n" );
+ } else {
+ result = list_push_back( result, s );
+ }
+ }
+ }
+ else if ( py_result == Py_None )
+ {
+ result = L0;
+ }
+ else
+ {
+ OBJECT *s = python_to_string( py_result );
+ if (s)
+ result = list_new( s );
+ else
+ /* We have tried all we could. Return empty list. There are
+ cases, e.g. feature.feature function that should return
+ value for the benefit of Python code and which also can be
+ called by Jam code, where no sensible value can be
+ returned. We cannot even emit a warning, since there will
+ be a pile of them. */
+ result = L0;
+ }
+
+ Py_DECREF( py_result );
+ }
+ else
+ {
+ PyErr_Print();
+ fprintf( stderr,"Call failed\n" );
+ }
+
+ return result;
+}
+
+#endif
+
+
+void function_done( void )
+{
+ BJAM_FREE( stack );
+}
diff --git a/tools/build/v2/engine/function.h b/tools/build/v2/engine/function.h
new file mode 100644
index 0000000000..64f26b3cf7
--- /dev/null
+++ b/tools/build/v2/engine/function.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#ifndef FUNCTION_SW20111123_H
+#define FUNCTION_SW20111123_H
+
+#include "object.h"
+#include "frames.h"
+#include "lists.h"
+#include "parse.h"
+#include "strings.h"
+
+typedef struct _function FUNCTION;
+typedef struct _stack STACK;
+
+STACK * stack_global( void );
+void stack_push( STACK * s, LIST * l );
+LIST * stack_pop( STACK * s );
+
+FUNCTION * function_compile( PARSE * parse );
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags, const char * * args );
+void function_refer( FUNCTION * );
+void function_free( FUNCTION * );
+OBJECT * function_rulename( FUNCTION * );
+void function_set_rulename( FUNCTION *, OBJECT * );
+void function_location( FUNCTION *, OBJECT * *, int * );
+LIST * function_run( FUNCTION * function, FRAME * frame, STACK * s );
+
+FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line );
+void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string * out );
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
+void function_done( void );
+
+#ifdef HAVE_PYTHON
+
+FUNCTION * function_python( PyObject * function, PyObject * bjam_signature );
+
+#endif
+
+#endif
diff --git a/tools/build/v2/engine/glob.c b/tools/build/v2/engine/glob.c
index 527d6c8088..bec00ee562 100644
--- a/tools/build/v2/engine/glob.c
+++ b/tools/build/v2/engine/glob.c
@@ -29,17 +29,17 @@
# define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
# define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
-static void globchars( char * s, char * e, char * b );
+static void globchars( const char * s, const char * e, char * b );
/*
* glob() - match a string against a simple pattern.
*/
-int glob( char * c, char * s )
+int glob( const char * c, const char * s )
{
char bitlist[ BITLISTSIZE ];
- char * here;
+ const char * here;
for ( ; ; )
switch ( *c++ )
@@ -64,7 +64,7 @@ int glob( char * c, char * s )
globchars( here, c, bitlist );
- if ( !CHECK_BIT( bitlist, *(unsigned char *)s ) )
+ if ( !CHECK_BIT( bitlist, *(const unsigned char *)s ) )
return 1;
++s;
break;
@@ -111,7 +111,7 @@ int glob( char * c, char * s )
* globchars() - build a bitlist to check for character group match.
*/
-static void globchars( char * s, char * e, char * b )
+static void globchars( const char * s, const char * e, char * b )
{
int neg = 0;
diff --git a/tools/build/v2/engine/hash.c b/tools/build/v2/engine/hash.c
index fbd1a8993d..6e748ab4d0 100644
--- a/tools/build/v2/engine/hash.c
+++ b/tools/build/v2/engine/hash.c
@@ -7,6 +7,7 @@
# include "jam.h"
# include "hash.h"
# include "compile.h"
+# include "object.h"
# include <assert.h>
/*
@@ -29,30 +30,16 @@
#define HASH_DEBUG_PROFILE 1
/* */
-char *hashsccssid="@(#)hash.c 1.14 () 6/20/88";
-
/* Header attached to all data items entered into a hash table. */
struct hashhdr
{
struct item * next;
- unsigned int keyval; /* for quick comparisons */
-};
-
-/* This structure overlays the one handed to hashenter(). Its actual size is
- * given to hashinit().
- */
-
-struct hashdata
-{
- char * key;
- /* rest of user data */
};
typedef struct item
{
struct hashhdr hdr;
- struct hashdata data;
} ITEM ;
# define MAX_LISTS 32
@@ -78,7 +65,6 @@ struct hash
int more; /* how many more ITEMs fit in lists[ list ] */
ITEM *free; /* free list of items */
char *next; /* where to put more ITEMs in lists[ list ] */
- int datalen; /* length of records in this hash table */
int size; /* sizeof( ITEM ) + aligned datalen */
int nel; /* total ITEMs held by all lists[] */
int list; /* index into lists[] */
@@ -89,54 +75,23 @@ struct hash
} lists[ MAX_LISTS ];
} items;
- char * name; /* just for hashstats() */
+ const char * name; /* just for hashstats() */
};
static void hashrehash( struct hash *hp );
static void hashstat( struct hash *hp );
-static void * hash_mem_alloc(size_t datalen, size_t size);
-static void hash_mem_free(size_t datalen, void * data);
-#ifdef OPT_BOEHM_GC
-static void hash_mem_finalizer(char * key, struct hash * hp);
-#endif
-
-static unsigned int jenkins_one_at_a_time_hash(const unsigned char *key)
-{
- unsigned int hash = 0;
-
- while ( *key )
- {
- hash += *key++;
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
- hash += (hash << 3);
- hash ^= (hash >> 11);
- hash += (hash << 15);
-
- return hash;
-}
-
-/*
-static unsigned int knuth_hash(const unsigned char *key)
-{
- unsigned int keyval = *key;
- while ( *key )
- keyval = keyval * 2147059363 + *key++;
- return keyval;
-}
-*/
-static unsigned int hash_keyval( const char * key_ )
+static unsigned int hash_keyval( OBJECT * key )
{
- /*
- return knuth_hash((const unsigned char *)key_);
- */
- return jenkins_one_at_a_time_hash((const unsigned char *)key_);
+ return object_hash( key );
}
#define hash_bucket(hp,keyval) ((hp)->tab.base + ( (keyval) % (hp)->tab.nel ))
+#define hash_data_key(data) (*(OBJECT * *)(data))
+#define hash_item_data(item) ((HASHDATA *)((char *)item + sizeof(struct hashhdr)))
+#define hash_item_key(item) (hash_data_key(hash_item_data(item)))
+
/* Find the hash item for the given data. Returns pointer to the
item and if given a pointer to the item before the found item.
If it's the first item in a bucket, there is no previous item,
@@ -145,7 +100,7 @@ static unsigned int hash_keyval( const char * key_ )
static ITEM * hash_search(
struct hash *hp,
unsigned int keyval,
- const char * keydata,
+ OBJECT * keydata,
ITEM * * previous )
{
ITEM * i = *hash_bucket(hp,keyval);
@@ -153,8 +108,7 @@ static ITEM * hash_search(
for ( ; i; i = i->hdr.next )
{
- if ( ( keyval == i->hdr.keyval ) &&
- !strcmp( i->data.key, keydata ) )
+ if ( object_equal( hash_item_key( i ), keydata ) )
{
if (previous)
{
@@ -169,52 +123,13 @@ static ITEM * hash_search(
}
/*
- * hash_free() - remove the given item from the table if it's there.
- * Returns 1 if found, 0 otherwise.
- *
- * NOTE: 2nd argument is HASHDATA*, not HASHDATA** as elsewhere.
- */
-int
-hash_free(
- register struct hash *hp,
- HASHDATA *data)
-{
- ITEM * i = 0;
- ITEM * prev = 0;
- unsigned int keyval = hash_keyval(data->key);
-
- i = hash_search( hp, keyval, data->key, &prev );
- if (i)
- {
- /* mark it free so we skip it during enumeration */
- i->data.key = 0;
- /* unlink the record from the hash chain */
- if (prev) prev->hdr.next = i->hdr.next;
- else *hash_bucket(hp,keyval) = i->hdr.next;
- /* link it into the freelist */
- i->hdr.next = hp->items.free;
- hp->items.free = i;
- /* we have another item */
- hp->items.more++;
-
- return 1;
- }
- return 0;
-}
-
-/*
- * hashitem() - find a record in the table, and optionally enter a new one
+ * hash_insert() - insert a record in the table or return the existing one
*/
-int
-hashitem(
- register struct hash *hp,
- HASHDATA **data,
- int enter )
+HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
{
- register ITEM *i;
- char *b = (*data)->key;
- unsigned int keyval = hash_keyval(b);
+ ITEM * i;
+ unsigned int keyval = hash_keyval( key );
#ifdef HASH_DEBUG_PROFILE
profile_frame prof[1];
@@ -222,38 +137,24 @@ hashitem(
profile_enter( 0, prof );
#endif
- if ( enter && !hp->items.more )
+ if ( !hp->items.more )
hashrehash( hp );
- if ( !enter && !hp->items.nel )
+ i = hash_search( hp, keyval, key, 0 );
+ if ( i )
{
- #ifdef HASH_DEBUG_PROFILE
- if ( DEBUG_PROFILE )
- profile_exit( prof );
- #endif
- return 0;
+ *found = 1;
}
-
- i = hash_search( hp, keyval, (*data)->key, 0 );
- if (i)
- {
- *data = &i->data;
- #ifdef HASH_DEBUG_PROFILE
- if ( DEBUG_PROFILE ) profile_exit( prof );
- #endif
- return !0;
- }
-
- if ( enter )
+ else
{
- ITEM * * base = hash_bucket(hp,keyval);
+ ITEM * * base = hash_bucket( hp, keyval );
/* try to grab one from the free list */
if ( hp->items.free )
{
i = hp->items.free;
hp->items.free = i->hdr.next;
- assert( i->data.key == 0 );
+ assert( hash_item_key( i ) == 0 );
}
else
{
@@ -261,24 +162,58 @@ hashitem(
hp->items.next += hp->items.size;
}
hp->items.more--;
- memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
- i->hdr.keyval = keyval;
i->hdr.next = *base;
*base = i;
- *data = &i->data;
- #ifdef OPT_BOEHM_GC
- if (sizeof(HASHDATA) == hp->items.datalen)
- {
- GC_REGISTER_FINALIZER(i->data.key,&hash_mem_finalizer,hp,0,0);
- }
+ *found = 0;
+ }
+
+ #ifdef HASH_DEBUG_PROFILE
+ if ( DEBUG_PROFILE )
+ profile_exit( prof );
+ #endif
+
+ return hash_item_data( i );
+}
+
+/*
+ * hash_find() - find a record in the table or NULL if none exists
+ */
+
+HASHDATA * hash_find( struct hash *hp, OBJECT *key )
+{
+ ITEM *i;
+ unsigned int keyval = hash_keyval(key);
+
+ #ifdef HASH_DEBUG_PROFILE
+ profile_frame prof[1];
+ if ( DEBUG_PROFILE )
+ profile_enter( 0, prof );
+ #endif
+
+ if ( !hp->items.nel )
+ {
+ #ifdef HASH_DEBUG_PROFILE
+ if ( DEBUG_PROFILE )
+ profile_exit( prof );
#endif
+ return 0;
}
+ i = hash_search( hp, keyval, key, 0 );
+
#ifdef HASH_DEBUG_PROFILE
if ( DEBUG_PROFILE )
profile_exit( prof );
#endif
- return 0;
+
+ if (i)
+ {
+ return hash_item_data( i );
+ }
+ else
+ {
+ return 0;
+ }
}
/*
@@ -289,7 +224,7 @@ static void hashrehash( register struct hash *hp )
{
int i = ++hp->items.list;
hp->items.more = i ? 2 * hp->items.nel : hp->inel;
- hp->items.next = (char *)hash_mem_alloc( hp->items.datalen, hp->items.more * hp->items.size );
+ hp->items.next = (char *)BJAM_MALLOC( hp->items.more * hp->items.size );
hp->items.free = 0;
hp->items.lists[i].nel = hp->items.more;
@@ -297,10 +232,10 @@ static void hashrehash( register struct hash *hp )
hp->items.nel += hp->items.more;
if ( hp->tab.base )
- hash_mem_free( hp->items.datalen, (char *)hp->tab.base );
+ BJAM_FREE( (char *)hp->tab.base );
hp->tab.nel = hp->items.nel * hp->bloat;
- hp->tab.base = (ITEM **)hash_mem_alloc( hp->items.datalen, hp->tab.nel * sizeof(ITEM **) );
+ hp->tab.base = (ITEM **)BJAM_MALLOC( hp->tab.nel * sizeof(ITEM **) );
memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
@@ -312,9 +247,9 @@ static void hashrehash( register struct hash *hp )
for ( ; nel--; next += hp->items.size )
{
register ITEM *i = (ITEM *)next;
- ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
+ ITEM **ip = hp->tab.base + object_hash( hash_item_key( i ) ) % hp->tab.nel;
/* code currently assumes rehashing only when there are no free items */
- assert( i->data.key != 0 );
+ assert( hash_item_key( i ) != 0 );
i->hdr.next = *ip;
*ip = i;
@@ -335,8 +270,8 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
for ( ; nel--; next += hp->items.size )
{
ITEM * i = (ITEM *)next;
- if ( i->data.key != 0 ) /* DO not enumerate freed items. */
- f( &i->data, data );
+ if ( hash_item_key( i ) != 0 ) /* DO not enumerate freed items. */
+ f( hash_item_data( i ), data );
}
}
}
@@ -352,16 +287,15 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
struct hash *
hashinit(
int datalen,
- char *name )
+ const char *name )
{
- struct hash *hp = (struct hash *)hash_mem_alloc( datalen, sizeof( *hp ) );
+ struct hash *hp = (struct hash *)BJAM_MALLOC( sizeof( *hp ) );
hp->bloat = 3;
hp->tab.nel = 0;
hp->tab.base = (ITEM **)0;
hp->items.more = 0;
hp->items.free = 0;
- hp->items.datalen = datalen;
hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
hp->items.list = -1;
hp->items.nel = 0;
@@ -371,89 +305,92 @@ hashinit(
return hp;
}
+void hashdone( struct hash * hp )
+{
+ if ( !hp )
+ return;
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ hashstat( hp );
+ hash_free( hp );
+}
+
/*
- * hashdone() - free a hash table, given its handle
+ * hash_free() - free a hash table, given its handle
*/
void
-hashdone( struct hash *hp )
+hash_free( struct hash * hp )
{
int i;
if ( !hp )
return;
- if ( DEBUG_MEM || DEBUG_PROFILE )
- hashstat( hp );
-
if ( hp->tab.base )
- hash_mem_free( hp->items.datalen, (char *)hp->tab.base );
+ BJAM_FREE( (char *)hp->tab.base );
for ( i = 0; i <= hp->items.list; ++i )
- hash_mem_free( hp->items.datalen, hp->items.lists[i].base );
- hash_mem_free( hp->items.datalen, (char *)hp );
+ BJAM_FREE( hp->items.lists[i].base );
+ BJAM_FREE( (char *)hp );
}
-static void * hash_mem_alloc(size_t datalen, size_t size)
-{
- if (sizeof(HASHDATA) == datalen)
- {
- return BJAM_MALLOC_RAW(size);
- }
- else
- {
- return BJAM_MALLOC(size);
- }
-}
-static void hash_mem_free(size_t datalen, void * data)
+/* ---- */
+
+static void hashstat( struct hash * hp )
{
- if (sizeof(HASHDATA) == datalen)
- {
- BJAM_FREE_RAW(data);
- }
- else
- {
- BJAM_FREE(data);
- }
+ struct hashstats stats[ 1 ];
+ hashstats_init( stats );
+ hashstats_add( stats, hp );
+ hashstats_print( stats, hp->name );
}
-#ifdef OPT_BOEHM_GC
-static void hash_mem_finalizer(char * key, struct hash * hp)
+void hashstats_init( struct hashstats * stats )
{
- HASHDATA d;
- d.key = key;
- hash_free(hp,&d);
+ stats->count = 0;
+ stats->num_items = 0;
+ stats->tab_size = 0;
+ stats->item_size = 0;
+ stats->sets = 0;
}
-#endif
-
-/* ---- */
-
-static void hashstat( struct hash * hp )
+void hashstats_add( struct hashstats * stats, struct hash * hp )
{
- ITEM * * tab = hp->tab.base;
- int nel = hp->tab.nel;
- int count = 0;
- int sets = 0;
- int run = ( tab[ nel - 1 ] != (ITEM *)0 );
- int i;
- int here;
-
- for ( i = nel; i > 0; --i )
+ if ( hp )
{
- if ( ( here = ( *tab++ != (ITEM *)0 ) ) )
- count++;
- if ( here && !run )
- sets++;
- run = here;
+ ITEM * * tab = hp->tab.base;
+ int nel = hp->tab.nel;
+ int count = 0;
+ int sets = 0;
+ int i;
+
+ for ( i = 0; i < nel; ++i )
+ {
+ ITEM * item;
+ int here = 0;
+ for ( item = tab[ i ]; item != 0; item = item->hdr.next )
+ ++here;
+
+ count += here;
+ if ( here > 0 )
+ ++sets;
+ }
+
+ stats->count += count;
+ stats->sets += sets;
+ stats->num_items += hp->items.nel;
+ stats->tab_size += hp->tab.nel;
+ stats->item_size = hp->items.size;
}
+}
+void hashstats_print( struct hashstats * stats, const char * name )
+{
printf( "%s table: %d+%d+%d (%dK+%luK) items+table+hash, %f density\n",
- hp->name,
- count,
- hp->items.nel,
- hp->tab.nel,
- hp->items.nel * hp->items.size / 1024,
- (long unsigned)hp->tab.nel * sizeof( ITEM ** ) / 1024,
- (float)count / (float)sets );
+ name,
+ stats->count,
+ stats->num_items,
+ stats->tab_size,
+ stats->num_items * stats->item_size / 1024,
+ (long unsigned)stats->tab_size * sizeof( ITEM ** ) / 1024,
+ (float)stats->count / (float)stats->sets );
}
diff --git a/tools/build/v2/engine/hash.h b/tools/build/v2/engine/hash.h
index 7195b4146f..65db56c1c5 100644
--- a/tools/build/v2/engine/hash.h
+++ b/tools/build/v2/engine/hash.h
@@ -11,15 +11,68 @@
#ifndef BOOST_JAM_HASH_H
#define BOOST_JAM_HASH_H
+/*
+ * An opaque struct representing an item in the
+ * hash table. The first element of every struct
+ * stored in the table must be an OBJECT * which
+ * is treated as the key.
+ */
typedef struct hashdata HASHDATA;
-struct hash * hashinit ( int datalen, char * name );
-int hashitem ( struct hash * hp, HASHDATA * * data, int enter );
-void hashdone ( struct hash * hp );
+/*
+ * hashinit() - initialize a hash table, returning a handle.
+ * datalen is the size of the items. name is used for debugging.
+ */
+struct hash * hashinit ( int datalen, const char * name );
+
+/*
+ * hash_free() - free a hash table, given its handle
+ */
+void hash_free( struct hash * hp );
+void hashdone( struct hash * hp );
+
+/*
+ * hashenumerate() - call f(i, data) on each item, i in the hash
+ * table. The order of the items is unspecified.
+ */
void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data );
-int hash_free ( struct hash * hp, HASHDATA * data);
-#define hashenter( hp, data ) ( !hashitem( hp, data, !0 ) )
-#define hashcheck( hp, data ) hashitem( hp, data, 0 )
+/*
+ * hash_insert() - insert a new item in a hash table, or return an
+ * existing one.
+ *
+ * Preconditions:
+ * - hp must be a hash table created by hashinit
+ * - key must be an object created by object_new
+ *
+ * Postconditions:
+ * - if the key does not already exist in the hash
+ * table, *found == 0 and the result will be a
+ * pointer to an uninitialized item. The key
+ * of the new item must be set to a value equal to
+ * key before any further operations on the
+ * hash table except hashdone.
+ * - if the key is present then *found == 1 and
+ * the result is a pointer to the existing
+ * record.
+ */
+HASHDATA * hash_insert ( struct hash * hp, OBJECT * key, int * found );
+
+/*
+ * hash_find() - find a record in the table or NULL if none exists
+ */
+HASHDATA * hash_find ( struct hash * hp, OBJECT * key );
+
+struct hashstats {
+ int count;
+ int num_items;
+ int tab_size;
+ int item_size;
+ int sets;
+};
+
+void hashstats_init( struct hashstats * stats );
+void hashstats_add( struct hashstats * stats, struct hash * hp );
+void hashstats_print( struct hashstats * stats, const char * name );
#endif
diff --git a/tools/build/v2/engine/hcache.c b/tools/build/v2/engine/hcache.c
index 70bb798cc9..9e7a0343ed 100644
--- a/tools/build/v2/engine/hcache.c
+++ b/tools/build/v2/engine/hcache.c
@@ -8,11 +8,12 @@
# include "rules.h"
# include "regexp.h"
# include "headers.h"
-# include "newstr.h"
+# include "object.h"
# include "hash.h"
# include "hcache.h"
# include "variable.h"
# include "search.h"
+# include "modules.h"
#ifdef OPT_HEADER_CACHE_EXT
@@ -43,7 +44,7 @@ typedef struct hcachedata HCACHEDATA ;
struct hcachedata
{
- char * boundname;
+ OBJECT * boundname;
time_t time;
LIST * includes;
LIST * hdrscan; /* the HDRSCAN value for this target */
@@ -70,30 +71,30 @@ static int hits = 0;
* the result so the user can not change the cache file during header scanning.
*/
-static char * cache_name( void )
+static const char * cache_name( void )
{
- static char * name = 0;
+ static OBJECT * name = 0;
if ( !name )
{
- LIST * hcachevar = var_get( "HCACHEFILE" );
+ LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE );
- if ( hcachevar )
+ if ( !list_empty( hcachevar ) )
{
- TARGET * t = bindtarget( hcachevar->string );
+ TARGET * t = bindtarget( list_front( hcachevar ) );
- pushsettings( t->settings );
+ pushsettings( root_module(), t->settings );
/* Do not expect the cache file to be generated, so pass 0 as the
* third argument to search. Expect the location to be specified via
* LOCATE, so pass 0 as the fourth arugment.
*/
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
- if ( hcachevar )
- name = copystr( t->boundname );
+ name = object_copy( t->boundname );
}
}
- return name;
+ return name ? object_str( name ) : 0;
}
@@ -105,10 +106,10 @@ static char * cache_name( void )
static int cache_maxage( void )
{
int age = 100;
- LIST * var = var_get( "HCACHEMAXAGE" );
- if ( var )
+ LIST * var = var_get( root_module(), constant_HCACHEMAXAGE );
+ if ( !list_empty( var ) )
{
- age = atoi( var->string );
+ age = atoi( object_str( list_front( var ) ) );
if ( age < 0 )
age = 0;
}
@@ -118,10 +119,10 @@ static int cache_maxage( void )
/*
* Read a netstring. The caveat is that the string can not contain ASCII 0. The
- * returned value is as returned by newstr(), so it need not be freed.
+ * returned value is as returned by object_new().
*/
-char * read_netstring( FILE * f )
+OBJECT * read_netstring( FILE * f )
{
unsigned long len;
static char * buf = NULL;
@@ -154,7 +155,7 @@ char * read_netstring( FILE * f )
return NULL;
buf[ len ] = 0;
- return newstr( buf );
+ return object_new( buf );
}
@@ -172,12 +173,13 @@ void write_netstring( FILE * f, char const * s )
void hcache_init()
{
- HCACHEDATA cachedata;
- HCACHEDATA * c;
FILE * f;
- char * version;
+ OBJECT * version = 0;
int header_count = 0;
- char * hcachename;
+ const char * hcachename;
+
+ if ( hcachehash )
+ return;
hcachehash = hashinit( sizeof( HCACHEDATA ), "hcache" );
@@ -188,105 +190,144 @@ void hcache_init()
return;
version = read_netstring( f );
- if ( !version || strcmp( version, CACHE_FILE_VERSION ) )
- {
- fclose( f );
- return;
- }
+
+ if ( !version || strcmp( object_str( version ), CACHE_FILE_VERSION ) )
+ goto bail;
while ( 1 )
{
- char * record_type;
- char * time_str;
- char * age_str;
- char * includes_count_str;
- char * hdrscan_count_str;
- int i;
- int count;
- LIST * l;
+ HCACHEDATA cachedata;
+ HCACHEDATA * c;
+ OBJECT * record_type = 0;
+ OBJECT * time_str = 0;
+ OBJECT * age_str = 0;
+ OBJECT * includes_count_str = 0;
+ OBJECT * hdrscan_count_str = 0;
+ int i;
+ int count;
+ LIST * l;
+ int found;
+
+ cachedata.boundname = 0;
+ cachedata.includes = 0;
+ cachedata.hdrscan = 0;
record_type = read_netstring( f );
if ( !record_type )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- if ( !strcmp( record_type, CACHE_RECORD_END ) )
+ if ( !strcmp( object_str( record_type ), CACHE_RECORD_END ) )
+ {
+ object_free( record_type );
break;
- if ( strcmp( record_type, CACHE_RECORD_HEADER ) )
+ }
+ if ( strcmp( object_str( record_type ), CACHE_RECORD_HEADER ) )
{
fprintf( stderr, "invalid %s with record separator <%s>\n",
- hcachename, record_type ? record_type : "<null>" );
- goto bail;
+ hcachename, record_type ? object_str( record_type ) : "<null>" );
+ goto cleanup;
}
- c = &cachedata;
-
- c->boundname = read_netstring( f );
- time_str = read_netstring( f );
- age_str = read_netstring( f );
- includes_count_str = read_netstring( f );
+ cachedata.boundname = read_netstring( f );
+ time_str = read_netstring( f );
+ age_str = read_netstring( f );
+ includes_count_str = read_netstring( f );
- if ( !c->boundname || !time_str || !age_str || !includes_count_str )
+ if ( !cachedata.boundname || !time_str || !age_str || !includes_count_str )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- c->time = atoi( time_str );
- c->age = atoi( age_str ) + 1;
+ cachedata.time = atoi( object_str( time_str ) );
+ cachedata.age = atoi( object_str( age_str ) ) + 1;
- count = atoi( includes_count_str );
- for ( l = 0, i = 0; i < count; ++i )
+ count = atoi( object_str( includes_count_str ) );
+ for ( l = L0, i = 0; i < count; ++i )
{
- char * s = read_netstring( f );
+ OBJECT * s = read_netstring( f );
if ( !s )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ list_free( l );
+ goto cleanup;
}
- l = list_new( l, s );
+ l = list_push_back( l, s );
}
- c->includes = l;
+ cachedata.includes = l;
hdrscan_count_str = read_netstring( f );
- if ( !includes_count_str )
+ if ( !hdrscan_count_str )
{
- list_free( c->includes );
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- count = atoi( hdrscan_count_str );
- for ( l = 0, i = 0; i < count; ++i )
+ count = atoi( object_str( hdrscan_count_str ) );
+ for ( l = L0, i = 0; i < count; ++i )
{
- char * s = read_netstring( f );
+ OBJECT * s = read_netstring( f );
if ( !s )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ list_free( l );
+ goto cleanup;
}
- l = list_new( l, s );
+ l = list_push_back( l, s );
}
- c->hdrscan = l;
+ cachedata.hdrscan = l;
- if ( !hashenter( hcachehash, (HASHDATA * *)&c ) )
+ c = (HCACHEDATA *)hash_insert( hcachehash, cachedata.boundname, &found );
+ if ( !found )
+ {
+ c->boundname = cachedata.boundname;
+ c->time = cachedata.time;
+ c->includes = cachedata.includes;
+ c->hdrscan = cachedata.hdrscan;
+ c->age = cachedata.age;
+ }
+ else
{
fprintf( stderr, "can't insert header cache item, bailing on %s\n",
hcachename );
- goto bail;
+ goto cleanup;
}
c->next = hcachelist;
hcachelist = c;
++header_count;
+
+ object_free( record_type );
+ object_free( time_str );
+ object_free( age_str );
+ object_free( includes_count_str );
+ object_free( hdrscan_count_str );
+ continue;
+
+cleanup:
+
+ if ( record_type ) object_free( record_type );
+ if ( time_str ) object_free( time_str );
+ if ( age_str ) object_free( age_str );
+ if ( includes_count_str ) object_free( includes_count_str );
+ if ( hdrscan_count_str ) object_free( hdrscan_count_str );
+
+ if ( cachedata.boundname ) object_free( cachedata.boundname );
+ if ( cachedata.includes ) list_free( cachedata.includes );
+ if ( cachedata.hdrscan ) list_free( cachedata.hdrscan );
+
+ goto bail;
}
if ( DEBUG_HEADER )
printf( "hcache read from file %s\n", hcachename );
- bail:
+bail:
+ if ( version )
+ object_free( version );
fclose( f );
}
@@ -296,17 +337,17 @@ void hcache_done()
FILE * f;
HCACHEDATA * c;
int header_count = 0;
- char * hcachename;
+ const char * hcachename;
int maxage;
if ( !hcachehash )
return;
if ( !( hcachename = cache_name() ) )
- return;
+ goto cleanup;
if ( !( f = fopen( hcachename, "wb" ) ) )
- return;
+ goto cleanup;
maxage = cache_maxage();
@@ -316,7 +357,7 @@ void hcache_done()
c = hcachelist;
for ( c = hcachelist; c; c = c->next )
{
- LIST * l;
+ LISTITER iter, end;
char time_str[ 30 ];
char age_str[ 30 ];
char includes_count_str[ 30 ];
@@ -333,15 +374,17 @@ void hcache_done()
sprintf( age_str, "%lu", (long unsigned) c->age );
write_netstring( f, CACHE_RECORD_HEADER );
- write_netstring( f, c->boundname );
+ write_netstring( f, object_str( c->boundname ) );
write_netstring( f, time_str );
write_netstring( f, age_str );
write_netstring( f, includes_count_str );
- for ( l = c->includes; l; l = list_next( l ) )
- write_netstring( f, l->string );
+ for ( iter = list_begin( c->includes ), end = list_end( c->includes );
+ iter != end; iter = list_next( iter ) )
+ write_netstring( f, object_str( list_item( iter ) ) );
write_netstring( f, hdrscan_count_str );
- for ( l = c->hdrscan; l; l = list_next( l ) )
- write_netstring( f, l->string );
+ for ( iter = list_begin( c->hdrscan ), end = list_end( c->hdrscan );
+ iter != end; iter = list_next( iter ) )
+ write_netstring( f, object_str( list_item( iter ) ) );
fputs( "\n", f );
++header_count;
}
@@ -352,81 +395,110 @@ void hcache_done()
hcachename, header_count, queries ? 100.0 * hits / queries : 0 );
fclose ( f );
+
+cleanup:
+ for ( c = hcachelist; c; c = c->next )
+ {
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ object_free( c->boundname );
+ }
+
+ hcachelist = 0;
+ if ( hcachehash )
+ hashdone( hcachehash );
+ hcachehash = 0;
}
LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
{
- HCACHEDATA cachedata;
- HCACHEDATA * c = &cachedata;
+ HCACHEDATA * c;
LIST * l = 0;
++queries;
- c->boundname = t->boundname;
-
- if (hashcheck (hcachehash, (HASHDATA **) &c))
- {
- if (c->time == t->time)
+ if ( ( c = (HCACHEDATA *)hash_find( hcachehash, t->boundname ) ) )
{
- LIST *l1 = hdrscan, *l2 = c->hdrscan;
- while (l1 && l2) {
- if (l1->string != l2->string) {
- l1 = NULL;
- } else {
- l1 = list_next(l1);
- l2 = list_next(l2);
- }
+ if ( c->time == t->time )
+ {
+ LIST *l1 = hdrscan, *l2 = c->hdrscan;
+ LISTITER iter1 = list_begin( l1 ), end1 = list_end( l1 ),
+ iter2 = list_begin( l2 ), end2 = list_end( l2 );
+ while ( iter1 != end1 && iter2 != end2 )
+ {
+ if ( !object_equal( list_item( iter1 ), list_item( iter2 ) ) )
+ {
+ iter1 = end1;
+ }
+ else
+ {
+ iter1 = list_next( iter1 );
+ iter2 = list_next( iter2 );
+ }
+ }
+ if ( iter1 != end1 || iter2 != end2 )
+ {
+ if (DEBUG_HEADER)
+ printf( "HDRSCAN out of date in cache for %s\n",
+ object_str( t->boundname ) );
+
+ printf( "HDRSCAN out of date for %s\n",
+ object_str( t->boundname ) );
+ printf(" real : ");
+ list_print( hdrscan );
+ printf( "\n cached: " );
+ list_print( c->hdrscan );
+ printf( "\n" );
+
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ c->includes = L0;
+ c->hdrscan = L0;
+ }
+ else
+ {
+ if (DEBUG_HEADER)
+ printf( "using header cache for %s\n",
+ object_str( t->boundname ) );
+ c->age = 0;
+ ++hits;
+ l = list_copy( c->includes );
+ return l;
+ }
}
- if (l1 || l2) {
- if (DEBUG_HEADER)
- printf("HDRSCAN out of date in cache for %s\n",
- t->boundname);
-
- printf("HDRSCAN out of date for %s\n", t->boundname);
- printf(" real : ");
- list_print(hdrscan);
- printf("\n cached: ");
- list_print(c->hdrscan);
- printf("\n");
-
- list_free(c->includes);
- list_free(c->hdrscan);
- c->includes = 0;
- c->hdrscan = 0;
- } else {
- if (DEBUG_HEADER)
- printf ("using header cache for %s\n", t->boundname);
- c->age = 0;
- ++hits;
- l = list_copy (0, c->includes);
- return l;
+ else
+ {
+ if (DEBUG_HEADER)
+ printf ("header cache out of date for %s\n",
+ object_str( t->boundname ) );
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ c->includes = L0;
+ c->hdrscan = L0;
}
- } else {
- if (DEBUG_HEADER)
- printf ("header cache out of date for %s\n", t->boundname);
- list_free (c->includes);
- list_free(c->hdrscan);
- c->includes = 0;
- c->hdrscan = 0;
- }
- } else {
- if (hashenter (hcachehash, (HASHDATA **)&c)) {
- c->boundname = newstr (c->boundname);
- c->next = hcachelist;
- hcachelist = c;
}
+ else
+ {
+ int found;
+ c = (HCACHEDATA *)hash_insert( hcachehash, t->boundname, &found );
+ if ( !found )
+ {
+ c->boundname = object_copy( t->boundname );
+ c->next = hcachelist;
+ hcachelist = c;
+ }
}
/* 'c' points at the cache entry. Its out of date. */
- l = headers1 (0, t->boundname, rec, re);
+ l = headers1( L0, t->boundname, rec, re );
c->time = t->time;
c->age = 0;
- c->includes = list_copy (0, l);
- c->hdrscan = list_copy(0, hdrscan);
+ c->includes = list_copy( l );
+ c->hdrscan = list_copy( hdrscan );
return l;
}
diff --git a/tools/build/v2/engine/hcache.h b/tools/build/v2/engine/hcache.h
index c316e3bcad..2aa2394939 100644
--- a/tools/build/v2/engine/hcache.h
+++ b/tools/build/v2/engine/hcache.h
@@ -11,8 +11,8 @@
# include "regexp.h"
# include "lists.h"
-void hcache_init(void);
-void hcache_done(void);
-LIST *hcache(TARGET *t, int rec, regexp *re[], LIST *hdrscan);
+void hcache_init( void );
+void hcache_done( void );
+LIST * hcache( TARGET *t, int rec, regexp * re[], LIST * hdrscan );
#endif
diff --git a/tools/build/v2/engine/hdrmacro.c b/tools/build/v2/engine/hdrmacro.c
index 43031d48ff..6ef2a131c9 100644
--- a/tools/build/v2/engine/hdrmacro.c
+++ b/tools/build/v2/engine/hdrmacro.c
@@ -19,7 +19,7 @@
# include "regexp.h"
# include "hdrmacro.h"
# include "hash.h"
-# include "newstr.h"
+# include "object.h"
# include "strings.h"
/*
@@ -49,8 +49,8 @@
/* this type is used to store a dictionary of file header macros */
typedef struct header_macro
{
- char * symbol;
- char * filename; /* we could maybe use a LIST here ?? */
+ OBJECT * symbol;
+ OBJECT * filename; /* we could maybe use a LIST here ?? */
} HEADER_MACRO;
static struct hash * header_macros_hash = 0;
@@ -63,26 +63,28 @@ static struct hash * header_macros_hash = 0;
# define MAXINC 10
void
-macro_headers( TARGET *t )
+macro_headers( TARGET * t )
{
static regexp *re = 0;
FILE *f;
char buf[ 1024 ];
if ( DEBUG_HEADER )
- printf( "macro header scan for %s\n", t->name );
+ printf( "macro header scan for %s\n", object_str( t->name ) );
/* this regexp is used to detect lines of the form */
/* "#define MACRO <....>" or "#define MACRO "....." */
/* in the header macro files.. */
if ( re == 0 )
{
- re = regex_compile(
+ OBJECT * re_str = object_new(
"^[ ]*#[ ]*define[ ]*([A-Za-z][A-Za-z0-9_]*)[ ]*"
"[<\"]([^\">]*)[\">].*$" );
+ re = regex_compile( re_str );
+ object_free( re_str );
}
- if ( !( f = fopen( t->boundname, "r" ) ) )
+ if ( !( f = fopen( object_str( t->boundname ), "r" ) ) )
return;
while ( fgets( buf, sizeof( buf ), f ) )
@@ -92,24 +94,30 @@ macro_headers( TARGET *t )
if ( regexec( re, buf ) && re->startp[1] )
{
+ OBJECT * symbol;
+ int found;
/* we detected a line that looks like "#define MACRO filename */
- re->endp[1][0] = '\0';
- re->endp[2][0] = '\0';
+ ((char *)re->endp[1])[0] = '\0';
+ ((char *)re->endp[2])[0] = '\0';
if ( DEBUG_HEADER )
printf( "macro '%s' used to define filename '%s' in '%s'\n",
- re->startp[1], re->startp[2], t->boundname );
+ re->startp[1], re->startp[2], object_str( t->boundname ) );
/* add macro definition to hash table */
if ( !header_macros_hash )
header_macros_hash = hashinit( sizeof( HEADER_MACRO ), "hdrmacros" );
- v->symbol = re->startp[1];
- v->filename = 0;
- if ( hashenter( header_macros_hash, (HASHDATA **)&v ) )
+ symbol = object_new( re->startp[1] );
+ v = (HEADER_MACRO *)hash_insert( header_macros_hash, symbol, &found );
+ if ( !found )
{
- v->symbol = newstr( re->startp[1] ); /* never freed */
- v->filename = newstr( re->startp[2] ); /* never freed */
+ v->symbol = symbol;
+ v->filename = object_new( re->startp[2] ); /* never freed */
+ }
+ else
+ {
+ object_free( symbol );
}
/* XXXX: FOR NOW, WE IGNORE MULTIPLE MACRO DEFINITIONS !! */
/* WE MIGHT AS WELL USE A LIST TO STORE THEM.. */
@@ -120,17 +128,14 @@ macro_headers( TARGET *t )
}
-char * macro_header_get( const char * macro_name )
+OBJECT * macro_header_get( OBJECT * macro_name )
{
- HEADER_MACRO var;
- HEADER_MACRO * v = &var;
-
- v->symbol = (char* )macro_name;
+ HEADER_MACRO * v;
- if ( header_macros_hash && hashcheck( header_macros_hash, (HASHDATA **)&v ) )
+ if ( header_macros_hash && ( v = (HEADER_MACRO *)hash_find( header_macros_hash, macro_name ) ) )
{
if ( DEBUG_HEADER )
- printf( "### macro '%s' evaluated to '%s'\n", macro_name, v->filename );
+ printf( "### macro '%s' evaluated to '%s'\n", object_str( macro_name ), object_str( v->filename ) );
return v->filename;
}
return 0;
diff --git a/tools/build/v2/engine/hdrmacro.h b/tools/build/v2/engine/hdrmacro.h
index 08cc111600..ddfa6eeac2 100644
--- a/tools/build/v2/engine/hdrmacro.h
+++ b/tools/build/v2/engine/hdrmacro.h
@@ -9,6 +9,11 @@
* #define MACRO "filename" definitions
*/
+#ifndef HDRMACRO_SW20111118_H
+#define HDRMACRO_SW20111118_H
+
void macro_headers( TARGET *t );
-char* macro_header_get( const char* macro_name );
+OBJECT * macro_header_get( OBJECT * macro_name );
+
+#endif
diff --git a/tools/build/v2/engine/headers.c b/tools/build/v2/engine/headers.c
index b9d8f6370d..7e01440169 100644
--- a/tools/build/v2/engine/headers.c
+++ b/tools/build/v2/engine/headers.c
@@ -14,11 +14,12 @@
# include "parse.h"
# include "compile.h"
# include "rules.h"
+# include "modules.h"
# include "variable.h"
# include "regexp.h"
# include "headers.h"
# include "hdrmacro.h"
-# include "newstr.h"
+# include "object.h"
#ifdef OPT_HEADER_CACHE_EXT
# include "hcache.h"
@@ -46,7 +47,7 @@
*/
#ifndef OPT_HEADER_CACHE_EXT
-static LIST *headers1( LIST *l, char *file, int rec, regexp *re[]);
+static LIST * headers1( LIST * l, OBJECT * file, int rec, regexp * re[]);
#endif
/*
@@ -56,28 +57,33 @@ static LIST *headers1( LIST *l, char *file, int rec, regexp *re[]);
# define MAXINC 10
void
-headers( TARGET *t )
+headers( TARGET * t )
{
LIST * hdrscan;
LIST * hdrrule;
#ifndef OPT_HEADER_CACHE_EXT
- LIST * headlist = 0;
+ LIST * headlist = L0;
#endif
regexp * re[ MAXINC ];
int rec = 0;
+ LISTITER iter, end;
- if ( !( hdrscan = var_get( "HDRSCAN" ) ) ||
- !( hdrrule = var_get( "HDRRULE" ) ) )
+ hdrscan = var_get( root_module(), constant_HDRSCAN );
+ if ( list_empty( hdrscan ) )
+ return;
+
+ hdrrule = var_get( root_module(), constant_HDRRULE );
+ if ( list_empty( hdrrule ) )
return;
if ( DEBUG_HEADER )
- printf( "header scan %s\n", t->name );
+ printf( "header scan %s\n", object_str( t->name ) );
/* Compile all regular expressions in HDRSCAN */
- while ( ( rec < MAXINC ) && hdrscan )
+ iter = list_begin( hdrscan ), end = list_end( hdrscan );
+ for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) )
{
- re[ rec++ ] = regex_compile( hdrscan->string );
- hdrscan = list_next( hdrscan );
+ re[ rec++ ] = regex_compile( list_item( iter ) );
}
/* Doctor up call to HDRRULE rule */
@@ -85,7 +91,7 @@ headers( TARGET *t )
{
FRAME frame[1];
frame_init( frame );
- lol_add( frame->args, list_new( L0, t->name ) );
+ lol_add( frame->args, list_new( object_copy( t->name ) ) );
#ifdef OPT_HEADER_CACHE_EXT
lol_add( frame->args, hcache( t, rec, re, hdrscan ) );
#else
@@ -96,9 +102,9 @@ headers( TARGET *t )
{
/* The third argument to HDRRULE is the bound name of
* $(<) */
- lol_add( frame->args, list_new( L0, t->boundname ) );
+ lol_add( frame->args, list_new( object_copy( t->boundname ) ) );
- list_free( evaluate_rule( hdrrule->string, frame ) );
+ list_free( evaluate_rule( list_front( hdrrule ), frame ) );
}
/* Clean up. */
@@ -118,7 +124,7 @@ static LIST *
#endif
headers1(
LIST * l,
- char * file,
+ OBJECT * file,
int rec,
regexp * re[] )
{
@@ -137,10 +143,14 @@ headers1(
/* the following regexp is used to detect cases where a */
/* file is included through a line line "#include MACRO" */
if ( re_macros == 0 )
- re_macros = regex_compile(
+ {
+ OBJECT * re_str = object_new(
"^[ ]*#[ ]*include[ ]*([A-Za-z][A-Za-z0-9_]*).*$" );
+ re_macros = regex_compile( re_str );
+ object_free( re_str );
+ }
- if ( !( f = fopen( file, "r" ) ) )
+ if ( !( f = fopen( object_str( file ), "r" ) ) )
return l;
while ( fgets( buf, sizeof( buf ), f ) )
@@ -158,30 +168,33 @@ headers1(
for ( i = 0; i < rec; ++i )
if ( regexec( re[i], buf ) && re[i]->startp[1] )
{
- re[i]->endp[1][0] = '\0';
+ ((char *)re[i]->endp[1])[0] = '\0';
if ( DEBUG_HEADER )
printf( "header found: %s\n", re[i]->startp[1] );
- l = list_new( l, newstr( re[i]->startp[1] ) );
+ l = list_push_back( l, object_new( re[i]->startp[1] ) );
}
/* special treatment for #include MACRO */
if ( regexec( re_macros, buf ) && re_macros->startp[1] )
{
- char* header_filename;
+ OBJECT * header_filename;
+ OBJECT * macro_name;
- re_macros->endp[1][0] = '\0';
+ ((char *)re_macros->endp[1])[0] = '\0';
if ( DEBUG_HEADER )
printf( "macro header found: %s", re_macros->startp[1] );
- header_filename = macro_header_get( re_macros->startp[1] );
+ macro_name = object_new( re_macros->startp[1] );
+ header_filename = macro_header_get( macro_name );
+ object_free( macro_name );
if ( header_filename )
{
if ( DEBUG_HEADER )
- printf( " resolved to '%s'\n", header_filename );
- l = list_new( l, newstr( header_filename ) );
+ printf( " resolved to '%s'\n", object_str( header_filename ) );
+ l = list_push_back( l, object_copy( header_filename ) );
}
else
{
@@ -197,7 +210,7 @@ headers1(
}
-void regerror( char * s )
+void regerror( const char * s )
{
printf( "re error %s\n", s );
}
diff --git a/tools/build/v2/engine/headers.h b/tools/build/v2/engine/headers.h
index 624475fe7d..1c0a642df8 100644
--- a/tools/build/v2/engine/headers.h
+++ b/tools/build/v2/engine/headers.h
@@ -8,9 +8,18 @@
* headers.h - handle #includes in source files
*/
-void headers( TARGET *t );
+#ifndef HEADERS_SW20111118_H
+#define HEADERS_SW20111118_H
+
+#include "object.h"
+#include "rules.h"
+#include "regexp.h"
+
+void headers( TARGET * t );
#ifdef OPT_HEADER_CACHE_EXT
struct regexp;
-LIST *headers1( LIST *l, char *file, int rec, struct regexp *re[] );
+LIST * headers1( LIST *l, OBJECT * file, int rec, struct regexp *re[] );
+#endif
+
#endif
diff --git a/tools/build/v2/engine/jam.c b/tools/build/v2/engine/jam.c
index e11d082bca..09faf85225 100644
--- a/tools/build/v2/engine/jam.c
+++ b/tools/build/v2/engine/jam.c
@@ -54,18 +54,18 @@
* are layered thus:
*
* variable|expand
- * / | | |
- * / | | |
- * / | | |
- * lists | | pathsys
- * \ | |
- * \ | |
- * \ | |
- * newstr |
+ * / | |
+ * / | |
+ * / | |
+ * lists | pathsys
+ * \ |
+ * \ hash
+ * \ |
+ * \ |
* \ |
* \ |
* \ |
- * hash
+ * object
*
* Roughly, the modules are:
*
@@ -73,8 +73,6 @@
* command.c - maintain lists of commands
* compile.c - compile parsed jam statements
* execunix.c - execute a shell script on UNIX
- * execvms.c - execute a shell script, ala VMS
- * expand.c - expand a buffer, given variable values
* file*.c - scan directories and archives on *
* hash.c - simple in-memory hashing routines
* hdrmacro.c - handle header file parsing for filename macro definitions
@@ -84,7 +82,7 @@
* lists.c - maintain lists of strings
* make.c - bring a target up to date, once rules are in place
* make1.c - execute command to bring targets up to date
- * newstr.c - string manipulation routines
+ * object.c - string manipulation routines
* option.c - command line option processing
* parse.c - make and destroy parse trees as driven by the parser
* path*.c - manipulate file names on *
@@ -115,14 +113,20 @@
#include "compile.h"
#include "builtins.h"
#include "rules.h"
-#include "newstr.h"
+#include "object.h"
#include "scan.h"
#include "timestamp.h"
#include "make.h"
#include "strings.h"
-#include "expand.h"
#include "filesys.h"
#include "output.h"
+#include "search.h"
+#include "class.h"
+#include "execcmd.h"
+#include "constants.h"
+#include "function.h"
+#include "pwd.h"
+#include "hcache.h"
/* Macintosh is "special" */
#ifdef OS_MAC
@@ -196,7 +200,6 @@ static void run_unit_tests()
execnt_unit_test();
#endif
string_unit_test();
- var_expand_unit_test();
}
#endif
@@ -211,7 +214,9 @@ int anyhow = 0;
extern PyObject * bjam_caller ( PyObject * self, PyObject * args );
#endif
-char *saved_argv0;
+void regex_done();
+
+const char *saved_argv0;
int main( int argc, char * * argv, char * * arg_environ )
{
@@ -223,6 +228,7 @@ int main( int argc, char * * argv, char * * arg_environ )
int arg_c = argc;
char * * arg_v = argv;
char const * progname = argv[0];
+ module_t * environ_module;
saved_argv0 = argv[0];
@@ -338,6 +344,8 @@ int main( int argc, char * * argv, char * * arg_environ )
globs.debug[i--] = 1;
}
+ constants_init();
+
{
PROFILE_ENTER( MAIN );
@@ -377,14 +385,14 @@ int main( int argc, char * * argv, char * * arg_environ )
#endif
/* Set JAMDATE. */
- var_set( "JAMDATE", list_new( L0, outf_time(time(0)) ), VAR_SET );
+ var_set( root_module(), constant_JAMDATE, list_new( outf_time(time(0)) ), VAR_SET );
/* Set JAM_VERSION. */
- var_set( "JAM_VERSION",
- list_new( list_new( list_new( L0,
- newstr( VERSION_MAJOR_SYM ) ),
- newstr( VERSION_MINOR_SYM ) ),
- newstr( VERSION_PATCH_SYM ) ),
+ var_set( root_module(), constant_JAM_VERSION,
+ list_push_back( list_push_back( list_new(
+ object_new( VERSION_MAJOR_SYM ) ),
+ object_new( VERSION_MINOR_SYM ) ),
+ object_new( VERSION_PATCH_SYM ) ),
VAR_SET );
/* Set JAMUNAME. */
@@ -394,17 +402,17 @@ int main( int argc, char * * argv, char * * arg_environ )
if ( uname( &u ) >= 0 )
{
- var_set( "JAMUNAME",
- list_new(
- list_new(
- list_new(
- list_new(
- list_new( L0,
- newstr( u.sysname ) ),
- newstr( u.nodename ) ),
- newstr( u.release ) ),
- newstr( u.version ) ),
- newstr( u.machine ) ), VAR_SET );
+ var_set( root_module(), constant_JAMUNAME,
+ list_push_back(
+ list_push_back(
+ list_push_back(
+ list_push_back(
+ list_new(
+ object_new( u.sysname ) ),
+ object_new( u.nodename ) ),
+ object_new( u.release ) ),
+ object_new( u.version ) ),
+ object_new( u.machine ) ), VAR_SET );
}
}
#endif /* unix */
@@ -414,19 +422,18 @@ int main( int argc, char * * argv, char * * arg_environ )
/* First into the global module, with splitting, for backward
* compatibility.
*/
- var_defines( use_environ, 1 );
+ var_defines( root_module(), use_environ, 1 );
+ environ_module = bindmodule( constant_ENVIRON );
/* Then into .ENVIRON, without splitting. */
- enter_module( bindmodule(".ENVIRON") );
- var_defines( use_environ, 0 );
- exit_module( bindmodule(".ENVIRON") );
+ var_defines( environ_module, use_environ, 0 );
/*
* Jam defined variables OS & OSPLAT. We load them after environment, so
* that setting OS in environment does not change Jam's notion of the
* current platform.
*/
- var_defines( othersyms, 1 );
+ var_defines( root_module(), othersyms, 1 );
/* Load up variables set on command line. */
for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n )
@@ -434,16 +441,16 @@ int main( int argc, char * * argv, char * * arg_environ )
char *symv[2];
symv[ 0 ] = s;
symv[ 1 ] = 0;
- var_defines( symv, 1 );
- enter_module( bindmodule(".ENVIRON") );
- var_defines( symv, 0 );
- exit_module( bindmodule(".ENVIRON") );
+ var_defines( root_module(), symv, 1 );
+ var_defines( environ_module, symv, 0 );
}
/* Set the ARGV to reflect the complete list of arguments of invocation.
*/
for ( n = 0; n < arg_c; ++n )
- var_set( "ARGV", list_new( L0, newstr( arg_v[n] ) ), VAR_APPEND );
+ {
+ var_set( root_module(), constant_ARGV, list_new( object_new( arg_v[n] ) ), VAR_APPEND );
+ }
/* Initialize built-in rules. */
load_builtins();
@@ -459,29 +466,43 @@ int main( int argc, char * * argv, char * * arg_environ )
}
else
{
- mark_target_for_updating( arg_v[ n ] );
+ OBJECT * target = object_new( arg_v[ n ] );
+ mark_target_for_updating( target );
+ object_free( target );
}
}
- if (!targets_to_update())
- mark_target_for_updating("all");
+ if ( list_empty( targets_to_update() ) )
+ {
+ mark_target_for_updating( constant_all );
+ }
/* Parse ruleset. */
{
FRAME frame[ 1 ];
frame_init( frame );
for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n )
- parse_file( s, frame );
+ {
+ OBJECT * filename = object_new( s );
+ parse_file( filename, frame );
+ object_free( filename );
+ }
if ( !n )
- parse_file( "+", frame );
+ {
+ parse_file( constant_plus, frame );
+ }
}
status = yyanyerrors();
/* Manually touch -t targets. */
for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n )
- touch_target( s );
+ {
+ OBJECT * target = object_new( s );
+ touch_target( target );
+ object_free( target );
+ }
/* If an output file is specified, set globs.cmdout to that. */
if ( ( s = getoptval( optv, 'o', 0 ) ) )
@@ -498,13 +519,13 @@ int main( int argc, char * * argv, char * * arg_environ )
options. */
{
LIST *p = L0;
- p = var_get ("PARALLELISM");
- if (p)
+ p = var_get ( root_module(), constant_PARALLELISM );
+ if ( !list_empty( p ) )
{
- int j = atoi (p->string);
- if (j == -1)
+ int j = atoi( object_str( list_front( p ) ) );
+ if ( j == -1 )
{
- printf( "Invalid value of PARALLELISM: %s\n", p->string);
+ printf( "Invalid value of PARALLELISM: %s\n", object_str( list_front( p ) ) );
}
else
{
@@ -516,11 +537,11 @@ int main( int argc, char * * argv, char * * arg_environ )
/* KEEP_GOING overrides -q option. */
{
LIST *p = L0;
- p = var_get ("KEEP_GOING");
- if (p)
+ p = var_get( root_module(), constant_KEEP_GOING );
+ if ( !list_empty( p ) )
{
- int v = atoi (p->string);
- if (v == 0)
+ int v = atoi( object_str( list_front( p ) ) );
+ if ( v == 0 )
globs.quitquick = 1;
else
globs.quitquick = 0;
@@ -532,16 +553,9 @@ int main( int argc, char * * argv, char * * arg_environ )
PROFILE_ENTER( MAIN_MAKE );
LIST * targets = targets_to_update();
- if (targets)
+ if ( !list_empty( targets ) )
{
- int targets_count = list_length( targets );
- const char * * targets2 = (const char * *)
- BJAM_MALLOC( targets_count * sizeof( char * ) );
- int n = 0;
- for ( ; targets; targets = list_next( targets ) )
- targets2[ n++ ] = targets->string;
- status |= make( targets_count, targets2, anyhow );
- free( targets );
+ status |= make( targets, anyhow );
}
else
{
@@ -557,12 +571,28 @@ int main( int argc, char * * argv, char * * arg_environ )
if ( DEBUG_PROFILE )
profile_dump();
+
+#ifdef OPT_HEADER_CACHE_EXT
+ hcache_done();
+#endif
+
+ clear_targets_to_update();
+
/* Widely scattered cleanup. */
- var_done();
file_done();
rules_done();
stamps_done();
- str_done();
+ search_done();
+ class_done();
+ modules_done();
+ regex_done();
+ exec_done();
+ pwd_done();
+ path_done();
+ function_done();
+ list_done();
+ constants_done();
+ object_done();
/* Close cmdout. */
if ( globs.cmdout )
@@ -579,7 +609,7 @@ int main( int argc, char * * argv, char * * arg_environ )
#if defined(_WIN32)
#include <windows.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf));
if (ret == 0 || ret == sizeof(buf)) return NULL;
@@ -587,7 +617,7 @@ char *executable_path(char *argv0) {
}
#elif defined(__APPLE__) /* Not tested */
#include <mach-o/dyld.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
uint32_t size = sizeof(buf);
int ret = _NSGetExecutablePath(buf, &size);
@@ -597,12 +627,12 @@ char *executable_path(char *argv0) {
#elif defined(sun) || defined(__sun) /* Not tested */
#include <stdlib.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
return strdup(getexecname());
}
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
@@ -616,16 +646,16 @@ char *executable_path(char *argv0) {
}
#elif defined(__linux__)
#include <unistd.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf));
if (ret == 0 || ret == sizeof(buf)) return NULL;
return strndup(buf, ret);
}
#else
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
/* If argv0 is absolute path, assume it's the right absolute path. */
- if (argv0[0] == "/")
+ if (argv0[0] == '/')
return strdup(argv0);
return NULL;
}
diff --git a/tools/build/v2/engine/jam.h b/tools/build/v2/engine/jam.h
index 73a7a04c58..26b94a7f7e 100644
--- a/tools/build/v2/engine/jam.h
+++ b/tools/build/v2/engine/jam.h
@@ -46,40 +46,6 @@
#define HAVE_POPEN 1
/*
- * VMS, OPENVMS
- */
-
-#ifdef VMS
-
-#include <types.h>
-#include <file.h>
-#include <stat.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <unixlib.h>
-
-#define OSMINOR "OS=VMS"
-#define OSMAJOR "VMS=true"
-#define OS_VMS
-#define MAXLINE 1024 /* longest 'together' actions */
-#define SPLITPATH ','
-#define EXITOK 1
-#define EXITBAD 0
-#define DOWNSHIFT_PATHS
-
-/* This may be inaccurate. */
-#ifndef __DECC
-#define OSPLAT "OSPLAT=VAX"
-#endif
-
-#endif
-
-/*
* Windows NT
*/
@@ -157,55 +123,6 @@
#endif
/*
- * OS2
- */
-
-#ifdef __OS2__
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <malloc.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-
-#define OSMAJOR "OS2=true"
-#define OSMINOR "OS=OS2"
-#define OS_OS2
-#define SPLITPATH ';'
-#define MAXLINE 996 /* longest 'together' actions */
-#define USE_EXECUNIX
-#define USE_PATHUNIX
-#define PATH_DELIM '\\'
-#define DOWNSHIFT_PATHS
-
-#ifdef __EMX__
- #define USE_FILEUNIX
-#endif
-
-#endif
-
-/*
- * Macintosh MPW
- */
-
-#ifdef macintosh
-
-#include <time.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#define OSMAJOR "MAC=true"
-#define OSMINOR "OS=MAC"
-#define OS_MAC
-#define SPLITPATH ','
-
-#endif
-
-/*
* God fearing UNIX.
*/
diff --git a/tools/build/v2/engine/jamgram.c b/tools/build/v2/engine/jamgram.c
index b1fa0835df..48c85228e8 100644
--- a/tools/build/v2/engine/jamgram.c
+++ b/tools/build/v2/engine/jamgram.c
@@ -1,30 +1,38 @@
-/* A Bison parser, made by GNU Bison 1.875. */
-
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
+/* A Bison parser, made by GNU Bison 2.4.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* Written by Richard Stallman by simplifying the original so called
- ``semantic'' parser. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
/* All symbols defined below should begin with yy or YY, to avoid
infringing on user name space. This should be done even for local
@@ -36,17 +44,93 @@
/* Identify Bison output. */
#define YYBISON 1
+/* Bison version. */
+#define YYBISON_VERSION "2.4.3"
+
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
/* Pure parsers. */
#define YYPURE 0
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
/* Using locations. */
#define YYLSP_NEEDED 0
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 96 "jamgram.y"
+
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "object.h"
+#include "rules.h"
+
+# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
+
+# define F0 -1
+# define P0 (PARSE *)0
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+
+
+/* Line 189 of yacc.c */
+#line 114 "y.tab.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -101,6 +185,7 @@
STRING = 303
};
#endif
+/* Tokens. */
#define _BANG_t 258
#define _BANG_EQUALS_t 259
#define _AMPER_t 260
@@ -151,119 +236,184 @@
-/* Copy the first part of user declarations. */
-#line 96 "jamgram.y"
-
-#include "jam.h"
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
-#include "lists.h"
-#include "parse.h"
-#include "scan.h"
-#include "compile.h"
-#include "newstr.h"
-#include "rules.h"
-# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
+/* Copy the second part of user declarations. */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
-# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
-# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
-# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+/* Line 264 of yacc.c */
+#line 252 "y.tab.c"
+#ifdef short
+# undef short
+#endif
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
#endif
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
#else
-# define YYERROR_VERBOSE 0
+typedef unsigned short int yytype_uint16;
#endif
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-typedef int YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
#endif
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-/* Copy the second part of user declarations. */
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
-/* Line 214 of yacc.c. */
-#line 223 "y.tab.c"
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
-#if ! defined (yyoverflow) || YYERROR_VERBOSE
+#if ! defined yyoverflow || YYERROR_VERBOSE
/* The parser invokes alloca or malloc; define the necessary symbols. */
-# if YYSTACK_USE_ALLOCA
-# define YYSTACK_ALLOC alloca
-# else
-# ifndef YYSTACK_USE_ALLOCA
-# if defined (alloca) || defined (_ALLOCA_H)
-# define YYSTACK_ALLOC alloca
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
# else
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
# endif
# endif
# endif
# endif
# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
# else
-# if defined (__STDC__) || defined (__cplusplus)
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
# endif
-# define YYSTACK_ALLOC malloc
-# define YYSTACK_FREE free
# endif
-#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-#if (! defined (yyoverflow) \
- && (! defined (__cplusplus) \
- || (YYSTYPE_IS_TRIVIAL)))
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- short yyss;
- YYSTYPE yyvs;
- };
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -271,24 +421,24 @@ union yyalloc
/* The size of an array large to enough to hold all stacks, each with
N elements. */
# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
-# if 1 < __GNUC__
+# if defined __GNUC__ && 1 < __GNUC__
# define YYCOPY(To, From, Count) \
__builtin_memcpy (To, From, (Count) * sizeof (*(From)))
# else
# define YYCOPY(To, From, Count) \
do \
{ \
- register YYSIZE_T yyi; \
+ YYSIZE_T yyi; \
for (yyi = 0; yyi < (Count); yyi++) \
(To)[yyi] = (From)[yyi]; \
} \
- while (0)
+ while (YYID (0))
# endif
# endif
@@ -297,48 +447,42 @@ union yyalloc
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
-# define YYSTACK_RELOCATE(Stack) \
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
do \
{ \
YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / sizeof (*yyptr); \
} \
- while (0)
-
-#endif
+ while (YYID (0))
-#if defined (__STDC__) || defined (__cplusplus)
- typedef signed char yysigned_char;
-#else
- typedef short yysigned_char;
#endif
-/* YYFINAL -- State number of the termination state. */
+/* YYFINAL -- State number of the termination state. */
#define YYFINAL 43
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 261
+#define YYLAST 243
-/* YYNTOKENS -- Number of terminals. */
+/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 49
-/* YYNNTS -- Number of nonterminals. */
+/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 24
-/* YYNRULES -- Number of rules. */
+/* YYNRULES -- Number of rules. */
#define YYNRULES 75
-/* YYNRULES -- Number of states. */
+/* YYNRULES -- Number of states. */
#define YYNSTATES 159
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
#define YYMAXUTOK 303
-#define YYTRANSLATE(YYX) \
+#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const unsigned char yytranslate[] =
+static const yytype_uint8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -376,7 +520,7 @@ static const unsigned char yytranslate[] =
#if YYDEBUG
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
YYRHS. */
-static const unsigned char yyprhs[] =
+static const yytype_uint8 yyprhs[] =
{
0, 0, 3, 4, 6, 8, 10, 12, 15, 21,
22, 25, 27, 31, 32, 34, 35, 39, 43, 47,
@@ -388,8 +532,8 @@ static const unsigned char yyprhs[] =
244, 246, 248, 250, 252, 253
};
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yysigned_char yyrhs[] =
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
{
50, 0, -1, -1, 52, -1, 53, -1, 52, -1,
57, -1, 57, 52, -1, 32, 65, 54, 11, 51,
@@ -413,14 +557,14 @@ static const yysigned_char yyrhs[] =
7, 61, 8, -1, -1, 63, 62, -1, 22, 47,
10, 51, -1, 65, -1, 65, 10, 64, -1, 66,
-1, -1, 66, 67, -1, 47, -1, -1, 18, 68,
- 69, 19, -1, 67, 64, -1, 34, 67, 67, 64,
+ 69, 19, -1, 47, 64, -1, 34, 67, 47, 64,
-1, 34, 67, 37, 65, -1, -1, 70, 71, -1,
41, -1, 40, -1, 29, -1, 36, -1, 35, -1,
26, -1, -1, 21, 65, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const unsigned short yyrline[] =
+static const yytype_uint16 yyrline[] =
{
0, 139, 139, 141, 152, 154, 158, 160, 162, 167,
170, 172, 176, 179, 182, 185, 188, 190, 192, 194,
@@ -433,9 +577,9 @@ static const unsigned short yyrline[] =
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE
-/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
{
"$end", "error", "$undefined", "_BANG_t", "_BANG_EQUALS_t", "_AMPER_t",
@@ -448,15 +592,15 @@ static const char *const yytname[] =
"RULE_t", "SWITCH_t", "TOGETHER_t", "UPDATED_t", "WHILE_t", "_LBRACE_t",
"_BAR_t", "_BARBAR_t", "_RBRACE_t", "ARG", "STRING", "$accept", "run",
"block", "rules", "null", "assign_list_opt", "arglist_opt", "local_opt",
- "rule", "@1", "@2", "assign", "expr", "cases", "case", "lol", "list",
- "listp", "arg", "@3", "func", "eflags", "eflag", "bindlist", 0
+ "rule", "$@1", "$@2", "assign", "expr", "cases", "case", "lol", "list",
+ "listp", "arg", "$@3", "func", "eflags", "eflag", "bindlist", 0
};
#endif
# ifdef YYPRINT
/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
token YYLEX-NUM. */
-static const unsigned short yytoknum[] =
+static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
@@ -467,7 +611,7 @@ static const unsigned short yytoknum[] =
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const unsigned char yyr1[] =
+static const yytype_uint8 yyr1[] =
{
0, 49, 50, 50, 51, 51, 52, 52, 52, 53,
54, 54, 55, 55, 56, 56, 57, 57, 57, 57,
@@ -480,7 +624,7 @@ static const unsigned char yyr1[] =
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const unsigned char yyr2[] =
+static const yytype_uint8 yyr2[] =
{
0, 2, 0, 1, 1, 1, 1, 2, 5, 0,
2, 1, 3, 0, 1, 0, 3, 3, 3, 4,
@@ -495,7 +639,7 @@ static const unsigned char yyr2[] =
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
-static const unsigned char yydefact[] =
+static const yytype_uint8 yydefact[] =
{
2, 61, 66, 58, 15, 0, 58, 58, 58, 0,
58, 58, 0, 9, 60, 0, 3, 0, 6, 0,
@@ -515,8 +659,8 @@ static const unsigned char yydefact[] =
12, 20, 32, 0, 28, 54, 0, 22, 33
};
-/* YYDEFGOTO[NTERM-NUM]. */
-static const short yydefgoto[] =
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
{
-1, 15, 39, 40, 41, 84, 125, 17, 18, 146,
156, 51, 30, 121, 122, 22, 23, 24, 31, 20,
@@ -526,31 +670,31 @@ static const short yydefgoto[] =
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
#define YYPACT_NINF -48
-static const short yypact[] =
+static const yytype_int16 yypact[] =
{
- 179, -48, -48, -48, -15, 7, -48, -16, -48, 3,
- -48, -48, 7, 179, 1, 27, -48, -9, 179, 19,
- -3, 33, -11, 24, 3, -48, -10, 7, 7, -48,
- 138, 9, 30, 35, 13, 205, 53, 22, 151, 20,
- -48, -48, 56, -48, 23, -48, -48, -48, -48, 61,
- -48, -48, 3, -48, 62, -48, -48, -48, -48, -48,
- -48, 58, -48, 179, -48, -48, 52, -48, 164, 7,
- 7, 7, 7, 7, 7, 7, 7, 179, 7, 7,
- -48, -48, -48, -48, 72, 179, -48, -48, 68, 179,
- -48, -48, 85, -48, 77, 73, 8, -48, -48, -48,
- 50, 57, -48, -48, -48, 45, 93, 93, -48, -48,
- 45, -48, -48, 64, 245, 245, -48, -48, 179, 66,
- 67, 69, 68, 71, -48, 205, -48, -48, -48, -48,
- -48, -48, -48, 70, 79, -48, -48, 109, -48, -48,
- -48, 112, -48, 115, -48, -48, 75, 179, 205, 179,
- -48, -48, -48, 81, -48, -48, 82, -48, -48
+ 170, -48, -48, -48, -12, 7, -48, -17, -48, -3,
+ -48, -48, 7, 170, 1, 22, -48, -9, 170, 19,
+ -2, 79, -6, 29, -3, -48, 2, 7, 7, -48,
+ 138, 20, 44, 45, 18, 196, 51, 26, 151, 24,
+ -48, -48, 62, -48, 27, -48, -48, -48, -48, 61,
+ -48, -48, -3, -48, 67, -48, -48, -48, -48, -48,
+ -48, 58, -48, 170, -48, -48, 50, -48, 52, 7,
+ 7, 7, 7, 7, 7, 7, 7, 170, 7, 7,
+ -48, -48, -48, -48, 70, 170, -48, -48, 87, 170,
+ -48, -48, 94, -48, 17, 99, -20, -48, -48, -48,
+ 69, 71, -48, -48, -48, 91, 156, 156, -48, -48,
+ 91, -48, -48, 77, 78, 78, -48, -48, 170, 81,
+ 66, 82, 87, 95, -48, 196, -48, -48, -48, -48,
+ -48, -48, -48, 97, 112, -48, -48, 135, -48, -48,
+ -48, 150, -48, 148, -48, -48, 98, 170, 196, 170,
+ -48, -48, -48, 115, -48, -48, 116, -48, -48
};
/* YYPGOTO[NTERM-NUM]. */
-static const short yypgoto[] =
+static const yytype_int16 yypgoto[] =
{
- -48, -48, -47, 5, 104, -48, -48, 136, -27, -48,
- -48, 47, 60, 36, -48, -13, -4, -48, 0, -48,
+ -48, -48, -47, 5, 140, -48, -48, 171, -27, -48,
+ -48, 80, 60, 54, -48, -13, -4, -48, 0, -48,
-48, -48, -48, -48
};
@@ -559,106 +703,86 @@ static const short yypgoto[] =
number is the opposite. If zero, do what YYDEFACT says.
If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -59
-static const short yytable[] =
+static const yytype_int16 yytable[] =
{
19, 42, 32, 33, 34, 16, 36, 37, 86, 35,
- 27, -58, -58, 19, 28, 1, 101, 25, 19, -58,
- 53, 1, -14, 45, 65, 1, 1, 43, 46, 44,
- 113, 52, 63, 47, 64, 19, 48, 66, 119, 80,
- 97, 81, 123, 49, 29, 128, 94, 95, -58, 82,
- 29, 102, 96, 50, 29, 29, 85, 72, 73, 55,
- 75, 76, 56, 19, 87, 88, 90, 91, 57, 58,
- 92, 135, 38, 59, 60, 93, 116, 19, 117, 99,
- 61, 98, 103, 118, 127, 19, 46, 67, 68, 19,
- 120, 47, 124, 131, 48, 130, 129, 69, 142, 133,
- 153, 49, 155, 132, 148, 72, 73, 74, 75, 76,
- 134, 141, 136, 147, 137, 138, 145, 140, 19, 149,
- 150, 154, 143, 152, 144, 19, 151, 157, 158, 105,
- 106, 107, 108, 109, 110, 111, 112, 83, 114, 115,
- 26, 126, 69, 70, 71, 0, 0, 19, 19, 19,
- 72, 73, 74, 75, 76, 69, 70, 71, 139, 0,
- 0, 0, 0, 72, 73, 74, 75, 76, 69, 70,
- 71, 0, 104, 0, 0, 0, 72, 73, 74, 75,
- 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 89, 78, 79, 1, 0, 2,
- 0, 0, 3, 0, 0, 0, 4, 5, 78, 79,
- 6, 7, 8, 9, 0, 0, 10, -15, 11, 0,
- 0, 12, 13, 1, 0, 2, 14, 0, 3, 0,
- 0, 0, 4, 5, 0, 0, 6, 25, 8, 9,
- 0, 0, 10, 0, 11, 0, 0, 12, 13, 69,
- 70, 71, 14, 0, 0, 0, 0, 72, 73, 74,
- 75, 76
+ 27, -58, -58, 19, 28, 1, 101, 128, 19, -58,
+ 25, -14, 43, 45, 65, 1, 46, 129, 46, 44,
+ 113, 47, 52, 47, 48, 19, 48, 63, 119, 64,
+ 97, 49, 123, 49, 29, 53, 94, 95, -58, 66,
+ 80, 102, 96, 50, 29, 81, 69, 70, 71, 82,
+ 104, 85, 87, 19, 72, 73, 74, 75, 76, 88,
+ 90, 135, 38, 91, 92, 93, 116, 19, 117, 99,
+ 103, 118, 69, 70, 71, 19, 98, 67, 68, 19,
+ 72, 73, 74, 75, 76, 130, 78, 79, 142, 133,
+ 153, 124, 155, 72, 73, 55, 75, 76, 56, 120,
+ 127, 141, 131, 137, 57, 58, 145, 132, 19, 59,
+ 60, 154, 143, 134, 144, 19, 61, 136, 138, 105,
+ 106, 107, 108, 109, 110, 111, 112, 148, 114, 115,
+ 147, 140, 69, 70, 71, 149, 152, 19, 19, 19,
+ 72, 73, 74, 75, 76, 69, 70, 71, 150, 151,
+ 69, 157, 158, 72, 73, 74, 75, 76, 72, 73,
+ 74, 75, 76, 83, 126, 26, 139, 0, 0, 0,
+ 0, 77, 78, 79, 0, 0, 0, 0, 1, 0,
+ 2, 0, 0, 3, 89, 78, 79, 4, 5, 0,
+ 0, 6, 7, 8, 9, 0, 0, 10, -15, 11,
+ 0, 0, 12, 13, 1, 0, 2, 14, 0, 3,
+ 0, 0, 0, 4, 5, 0, 0, 6, 25, 8,
+ 9, 0, 0, 10, 0, 11, 0, 0, 12, 13,
+ 0, 0, 0, 14
};
-static const short yycheck[] =
+static const yytype_int16 yycheck[] =
{
0, 14, 6, 7, 8, 0, 10, 11, 35, 9,
- 3, 10, 11, 13, 7, 18, 63, 32, 18, 18,
- 20, 18, 38, 18, 24, 18, 18, 0, 9, 38,
- 77, 34, 43, 14, 10, 35, 17, 47, 85, 30,
- 53, 11, 89, 24, 47, 37, 50, 51, 47, 14,
- 47, 64, 52, 34, 47, 47, 43, 12, 13, 26,
- 15, 16, 29, 63, 11, 43, 46, 11, 35, 36,
- 47, 118, 12, 40, 41, 14, 80, 77, 82, 21,
- 47, 19, 30, 11, 11, 85, 9, 27, 28, 89,
- 22, 14, 7, 43, 17, 99, 96, 4, 125, 103,
- 147, 24, 149, 46, 25, 12, 13, 14, 15, 16,
- 46, 124, 46, 43, 47, 46, 129, 46, 118, 10,
- 8, 148, 126, 48, 128, 125, 11, 46, 46, 69,
- 70, 71, 72, 73, 74, 75, 76, 33, 78, 79,
- 4, 94, 4, 5, 6, -1, -1, 147, 148, 149,
- 12, 13, 14, 15, 16, 4, 5, 6, 122, -1,
- -1, -1, -1, 12, 13, 14, 15, 16, 4, 5,
- 6, -1, 8, -1, -1, -1, 12, 13, 14, 15,
- 16, 43, 44, 45, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 43, 44, 45, 18, -1, 20,
- -1, -1, 23, -1, -1, -1, 27, 28, 44, 45,
- 31, 32, 33, 34, -1, -1, 37, 38, 39, -1,
- -1, 42, 43, 18, -1, 20, 47, -1, 23, -1,
- -1, -1, 27, 28, -1, -1, 31, 32, 33, 34,
- -1, -1, 37, -1, 39, -1, -1, 42, 43, 4,
- 5, 6, 47, -1, -1, -1, -1, 12, 13, 14,
- 15, 16
+ 3, 10, 11, 13, 7, 18, 63, 37, 18, 18,
+ 32, 38, 0, 18, 24, 18, 9, 47, 9, 38,
+ 77, 14, 34, 14, 17, 35, 17, 43, 85, 10,
+ 53, 24, 89, 24, 47, 47, 50, 51, 47, 47,
+ 30, 64, 52, 34, 47, 11, 4, 5, 6, 14,
+ 8, 43, 11, 63, 12, 13, 14, 15, 16, 43,
+ 46, 118, 12, 11, 47, 14, 80, 77, 82, 21,
+ 30, 11, 4, 5, 6, 85, 19, 27, 28, 89,
+ 12, 13, 14, 15, 16, 99, 44, 45, 125, 103,
+ 147, 7, 149, 12, 13, 26, 15, 16, 29, 22,
+ 11, 124, 43, 47, 35, 36, 129, 46, 118, 40,
+ 41, 148, 126, 46, 128, 125, 47, 46, 46, 69,
+ 70, 71, 72, 73, 74, 75, 76, 25, 78, 79,
+ 43, 46, 4, 5, 6, 10, 48, 147, 148, 149,
+ 12, 13, 14, 15, 16, 4, 5, 6, 8, 11,
+ 4, 46, 46, 12, 13, 14, 15, 16, 12, 13,
+ 14, 15, 16, 33, 94, 4, 122, -1, -1, -1,
+ -1, 43, 44, 45, -1, -1, -1, -1, 18, -1,
+ 20, -1, -1, 23, 43, 44, 45, 27, 28, -1,
+ -1, 31, 32, 33, 34, -1, -1, 37, 38, 39,
+ -1, -1, 42, 43, 18, -1, 20, 47, -1, 23,
+ -1, -1, -1, 27, 28, -1, -1, 31, 32, 33,
+ 34, -1, -1, 37, -1, 39, -1, -1, 42, 43,
+ -1, -1, -1, 47
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
-static const unsigned char yystos[] =
+static const yytype_uint8 yystos[] =
{
0, 18, 20, 23, 27, 28, 31, 32, 33, 34,
37, 39, 42, 43, 47, 50, 52, 56, 57, 67,
68, 70, 64, 65, 66, 32, 56, 3, 7, 47,
61, 67, 65, 65, 65, 67, 65, 65, 61, 51,
52, 53, 64, 0, 38, 52, 9, 14, 17, 24,
- 34, 60, 34, 67, 69, 26, 29, 35, 36, 40,
+ 34, 60, 34, 47, 69, 26, 29, 35, 36, 40,
41, 47, 71, 43, 10, 67, 47, 61, 61, 4,
5, 6, 12, 13, 14, 15, 16, 43, 44, 45,
30, 11, 14, 53, 54, 43, 57, 11, 43, 43,
46, 11, 47, 14, 65, 65, 67, 64, 19, 21,
72, 51, 64, 30, 8, 61, 61, 61, 61, 61,
61, 61, 61, 51, 61, 61, 65, 65, 11, 51,
- 22, 62, 63, 51, 7, 55, 60, 11, 37, 67,
+ 22, 62, 63, 51, 7, 55, 60, 11, 37, 47,
65, 43, 46, 65, 46, 51, 46, 47, 46, 62,
46, 64, 57, 65, 65, 64, 58, 43, 25, 10,
8, 11, 48, 51, 57, 51, 59, 46, 46
};
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
#define YYEMPTY (-2)
@@ -666,13 +790,23 @@ static const unsigned char yystos[] =
#define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrlab1
+#define YYERROR goto yyerrorlab
+
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -683,30 +817,63 @@ do \
yychar = (Token); \
yylval = (Value); \
yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK; \
+ YYPOPSTACK (1); \
goto yybackup; \
} \
else \
- { \
- yyerror ("syntax error: cannot back up");\
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
-while (0)
+while (YYID (0))
+
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
- are run). */
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- Current.first_line = Rhs[1].first_line; \
- Current.first_column = Rhs[1].first_column; \
- Current.last_line = Rhs[N].last_line; \
- Current.last_column = Rhs[N].last_column;
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
#endif
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
/* YYLEX -- calling `yylex' with the right arguments. */
#ifdef YYLEX_PARAM
@@ -727,43 +894,100 @@ while (0)
do { \
if (yydebug) \
YYFPRINTF Args; \
-} while (0)
+} while (YYID (0))
-# define YYDSYMPRINT(Args) \
-do { \
- if (yydebug) \
- yysymprint Args; \
-} while (0)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
-# define YYDSYMPRINTF(Title, Token, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yysymprint (stderr, \
- Token, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (0)
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
/*------------------------------------------------------------------.
| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (cinluded). |
+| TOP (included). |
`------------------------------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (short *bottom, short *top)
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
#else
static void
-yy_stack_print (bottom, top)
- short *bottom;
- short *top;
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (/* Nothing. */; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
YYFPRINTF (stderr, "\n");
}
@@ -771,45 +995,52 @@ yy_stack_print (bottom, top)
do { \
if (yydebug) \
yy_stack_print ((Bottom), (Top)); \
-} while (0)
+} while (YYID (0))
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yy_reduce_print (int yyrule)
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
#else
static void
-yy_reduce_print (yyrule)
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
int yyrule;
#endif
{
+ int yynrhs = yyr2[yyrule];
int yyi;
- unsigned int yylineno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
- yyrule - 1, yylineno);
- /* Print the symbols being reduced, and their result. */
- for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
- YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
- YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
}
# define YY_REDUCE_PRINT(Rule) \
do { \
if (yydebug) \
- yy_reduce_print (Rule); \
-} while (0)
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
int yydebug;
#else /* !YYDEBUG */
# define YYDPRINTF(Args)
-# define YYDSYMPRINT(Args)
-# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
# define YY_STACK_PRINT(Bottom, Top)
# define YY_REDUCE_PRINT(Rule)
#endif /* !YYDEBUG */
@@ -824,13 +1055,9 @@ int yydebug;
if the built-in stack extension method is used).
Do not make this value too large; the results are undefined if
- SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
evaluated with infinite-precision integer arithmetic. */
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
#ifndef YYMAXDEPTH
# define YYMAXDEPTH 10000
#endif
@@ -840,45 +1067,47 @@ int yydebug;
#if YYERROR_VERBOSE
# ifndef yystrlen
-# if defined (__GLIBC__) && defined (_STRING_H)
+# if defined __GLIBC__ && defined _STRING_H
# define yystrlen strlen
# else
/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static YYSIZE_T
-# if defined (__STDC__) || defined (__cplusplus)
yystrlen (const char *yystr)
-# else
+#else
+static YYSIZE_T
yystrlen (yystr)
- const char *yystr;
-# endif
+ const char *yystr;
+#endif
{
- register const char *yys = yystr;
-
- while (*yys++ != '\0')
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
continue;
-
- return yys - yystr - 1;
+ return yylen;
}
# endif
# endif
# ifndef yystpcpy
-# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
# define yystpcpy stpcpy
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static char *
-# if defined (__STDC__) || defined (__cplusplus)
yystpcpy (char *yydest, const char *yysrc)
-# else
+#else
+static char *
yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-# endif
+ char *yydest;
+ const char *yysrc;
+#endif
{
- register char *yyd = yydest;
- register const char *yys = yysrc;
+ char *yyd = yydest;
+ const char *yys = yysrc;
while ((*yyd++ = *yys++) != '\0')
continue;
@@ -888,84 +1117,204 @@ yystpcpy (yydest, yysrc)
# endif
# endif
-#endif /* !YYERROR_VERBOSE */
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
-
+ if (! yyres)
+ return yystrlen (yystr);
-#if YYDEBUG
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
-#if defined (__STDC__) || defined (__cplusplus)
-static void
-yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yysymprint (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- /* Pacify ``unused variable'' warnings. */
- (void) yyvaluep;
+ int yyn = yypact[yystate];
- if (yytype < YYNTOKENS)
- {
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-# ifdef YYPRINT
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# endif
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- switch (yytype)
{
- default:
- break;
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
}
- YYFPRINTF (yyoutput, ")");
}
+#endif /* YYERROR_VERBOSE */
+
-#endif /* ! YYDEBUG */
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yydestruct (int yytype, YYSTYPE *yyvaluep)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
#else
static void
-yydestruct (yytype, yyvaluep)
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
int yytype;
YYSTYPE *yyvaluep;
#endif
{
- /* Pacify ``unused variable'' warnings. */
- (void) yyvaluep;
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
switch (yytype)
{
default:
- break;
+ break;
}
}
-
/* Prevent warnings from -Wmissing-prototypes. */
-
#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
+#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
-# else
+#else
int yyparse ();
-# endif
+#endif
#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
+#if defined __STDC__ || defined __cplusplus
int yyparse (void);
#else
int yyparse ();
@@ -973,7 +1322,6 @@ int yyparse ();
#endif /* ! YYPARSE_PARAM */
-
/* The lookahead symbol. */
int yychar;
@@ -985,19 +1333,23 @@ int yynerrs;
-/*----------.
-| yyparse. |
-`----------*/
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
-int yyparse (void *YYPARSE_PARAM)
-# else
-int yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-# endif
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
int
yyparse (void)
#else
@@ -1008,59 +1360,67 @@ yyparse ()
#endif
{
- register int yystate;
- register int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken = 0;
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
- /* The state stack. */
- short yyssa[YYINITDEPTH];
- short *yyss = yyssa;
- register short *yyssp;
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- register YYSTYPE *yyvsp;
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
-#define YYPOPSTACK (yyvsp--, yyssp--)
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
- YYSIZE_T yystacksize = YYINITDEPTH;
+ YYSIZE_T yystacksize;
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
- /* When reducing, the number of symbols on the RHS of the reduced
- rule. */
- int yylen;
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
-
yyssp = yyss;
yyvsp = yyvs;
@@ -1071,8 +1431,7 @@ yyparse ()
`------------------------------------------------------------*/
yynewstate:
/* In all cases, when you get here, the value and location stacks
- have just been pushed. so pushing a state here evens the stacks.
- */
+ have just been pushed. So pushing a state here evens the stacks. */
yyssp++;
yysetstate:
@@ -1085,21 +1444,19 @@ yyparse ()
#ifdef yyoverflow
{
- /* Give user a chance to reallocate the stack. Use copies of
+ /* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
YYSTYPE *yyvs1 = yyvs;
- short *yyss1 = yyss;
-
+ yytype_int16 *yyss1 = yyss;
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
be undefined if yyoverflow is a macro. */
- yyoverflow ("parser stack overflow",
+ yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
-
&yystacksize);
yyss = yyss1;
@@ -1107,24 +1464,23 @@ yyparse ()
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
- goto yyoverflowlab;
+ goto yyexhaustedlab;
# else
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
- goto yyoverflowlab;
+ goto yyexhaustedlab;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
{
- short *yyss1 = yyss;
+ yytype_int16 *yyss1 = yyss;
union yyalloc *yyptr =
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
- goto yyoverflowlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -1135,7 +1491,6 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
-
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -1145,6 +1500,9 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
goto yybackup;
/*-----------.
@@ -1152,12 +1510,10 @@ yyparse ()
`-----------*/
yybackup:
-/* Do appropriate processing given the current state. */
-/* Read a lookahead token if we need one and don't already have one. */
-/* yyresume: */
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
/* First try to decide what to do without reference to lookahead token. */
-
yyn = yypact[yystate];
if (yyn == YYPACT_NINF)
goto yydefault;
@@ -1179,7 +1535,7 @@ yybackup:
else
{
yytoken = YYTRANSLATE (yychar);
- YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
}
/* If the proper action on seeing token YYTOKEN is to reduce or to
@@ -1196,25 +1552,20 @@ yybackup:
goto yyreduce;
}
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Shift the lookahead token. */
- YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
-
- /* Discard the token being shifted unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- *++yyvsp = yylval;
-
-
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
yystate = yyn;
+ *++yyvsp = yylval;
+
goto yynewstate;
@@ -1250,385 +1601,530 @@ yyreduce:
switch (yyn)
{
case 3:
+
+/* Line 1464 of yacc.c */
#line 142 "jamgram.y"
- { parse_save( yyvsp[0].parse ); }
+ { parse_save( (yyvsp[(1) - (1)]).parse ); }
break;
case 4:
+
+/* Line 1464 of yacc.c */
#line 153 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 5:
+
+/* Line 1464 of yacc.c */
#line 155 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 6:
+
+/* Line 1464 of yacc.c */
#line 159 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 7:
+
+/* Line 1464 of yacc.c */
#line 161 "jamgram.y"
- { yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = prules( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 8:
+
+/* Line 1464 of yacc.c */
#line 163 "jamgram.y"
- { yyval.parse = plocal( yyvsp[-3].parse, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = plocal( (yyvsp[(2) - (5)]).parse, (yyvsp[(3) - (5)]).parse, (yyvsp[(5) - (5)]).parse ); }
break;
case 9:
+
+/* Line 1464 of yacc.c */
#line 167 "jamgram.y"
- { yyval.parse = pnull(); }
+ { (yyval).parse = pnull(); }
break;
case 10:
+
+/* Line 1464 of yacc.c */
#line 171 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_SET; }
+ { (yyval).parse = (yyvsp[(2) - (2)]).parse; (yyval).number = ASSIGN_SET; }
break;
case 11:
+
+/* Line 1464 of yacc.c */
#line 173 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_APPEND; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; (yyval).number = ASSIGN_APPEND; }
break;
case 12:
+
+/* Line 1464 of yacc.c */
#line 177 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 13:
+
+/* Line 1464 of yacc.c */
#line 179 "jamgram.y"
- { yyval.parse = P0; }
+ { (yyval).parse = P0; }
break;
case 14:
+
+/* Line 1464 of yacc.c */
#line 183 "jamgram.y"
- { yyval.number = 1; }
+ { (yyval).number = 1; }
break;
case 15:
+
+/* Line 1464 of yacc.c */
#line 185 "jamgram.y"
- { yyval.number = 0; }
+ { (yyval).number = 0; }
break;
case 16:
+
+/* Line 1464 of yacc.c */
#line 189 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 17:
+
+/* Line 1464 of yacc.c */
#line 191 "jamgram.y"
- { yyval.parse = pincl( yyvsp[-1].parse ); }
+ { (yyval).parse = pincl( (yyvsp[(2) - (3)]).parse ); }
break;
case 18:
+
+/* Line 1464 of yacc.c */
#line 193 "jamgram.y"
- { yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); }
+ { (yyval).parse = prule( (yyvsp[(1) - (3)]).string, (yyvsp[(2) - (3)]).parse ); }
break;
case 19:
+
+/* Line 1464 of yacc.c */
#line 195 "jamgram.y"
- { yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
+ { (yyval).parse = pset( (yyvsp[(1) - (4)]).parse, (yyvsp[(3) - (4)]).parse, (yyvsp[(2) - (4)]).number ); }
break;
case 20:
+
+/* Line 1464 of yacc.c */
#line 197 "jamgram.y"
- { yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
+ { (yyval).parse = pset1( (yyvsp[(1) - (6)]).parse, (yyvsp[(3) - (6)]).parse, (yyvsp[(5) - (6)]).parse, (yyvsp[(4) - (6)]).number ); }
break;
case 21:
+
+/* Line 1464 of yacc.c */
#line 199 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 22:
+
+/* Line 1464 of yacc.c */
#line 201 "jamgram.y"
- { yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-6].number ); }
+ { (yyval).parse = pfor( (yyvsp[(3) - (8)]).string, (yyvsp[(5) - (8)]).parse, (yyvsp[(7) - (8)]).parse, (yyvsp[(2) - (8)]).number ); }
break;
case 23:
+
+/* Line 1464 of yacc.c */
#line 203 "jamgram.y"
- { yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pswitch( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 24:
+
+/* Line 1464 of yacc.c */
#line 205 "jamgram.y"
- { yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); }
+ { (yyval).parse = pif( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse, pnull() ); }
break;
case 25:
+
+/* Line 1464 of yacc.c */
#line 207 "jamgram.y"
- { yyval.parse = pmodule( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pmodule( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 26:
+
+/* Line 1464 of yacc.c */
#line 209 "jamgram.y"
- { yyval.parse = pclass( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pclass( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 27:
+
+/* Line 1464 of yacc.c */
#line 211 "jamgram.y"
- { yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pwhile( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 28:
+
+/* Line 1464 of yacc.c */
#line 213 "jamgram.y"
- { yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pif( (yyvsp[(2) - (7)]).parse, (yyvsp[(4) - (7)]).parse, (yyvsp[(7) - (7)]).parse ); }
break;
case 29:
+
+/* Line 1464 of yacc.c */
#line 215 "jamgram.y"
- { yyval.parse = psetc( yyvsp[-2].string, yyvsp[0].parse, yyvsp[-1].parse, yyvsp[-4].number ); }
+ { (yyval).parse = psetc( (yyvsp[(3) - (5)]).string, (yyvsp[(5) - (5)]).parse, (yyvsp[(4) - (5)]).parse, (yyvsp[(1) - (5)]).number ); }
break;
case 30:
+
+/* Line 1464 of yacc.c */
#line 217 "jamgram.y"
- { yyval.parse = pon( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 31:
+
+/* Line 1464 of yacc.c */
#line 219 "jamgram.y"
{ yymode( SCAN_STRING ); }
break;
case 32:
+
+/* Line 1464 of yacc.c */
#line 221 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 33:
+
+/* Line 1464 of yacc.c */
#line 223 "jamgram.y"
- { yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); }
+ { (yyval).parse = psete( (yyvsp[(3) - (9)]).string,(yyvsp[(4) - (9)]).parse,(yyvsp[(7) - (9)]).string,(yyvsp[(2) - (9)]).number ); }
break;
case 34:
+
+/* Line 1464 of yacc.c */
#line 231 "jamgram.y"
- { yyval.number = ASSIGN_SET; }
+ { (yyval).number = ASSIGN_SET; }
break;
case 35:
+
+/* Line 1464 of yacc.c */
#line 233 "jamgram.y"
- { yyval.number = ASSIGN_APPEND; }
+ { (yyval).number = ASSIGN_APPEND; }
break;
case 36:
+
+/* Line 1464 of yacc.c */
#line 235 "jamgram.y"
- { yyval.number = ASSIGN_DEFAULT; }
+ { (yyval).number = ASSIGN_DEFAULT; }
break;
case 37:
+
+/* Line 1464 of yacc.c */
#line 237 "jamgram.y"
- { yyval.number = ASSIGN_DEFAULT; }
+ { (yyval).number = ASSIGN_DEFAULT; }
break;
case 38:
+
+/* Line 1464 of yacc.c */
#line 244 "jamgram.y"
- { yyval.parse = peval( EXPR_EXISTS, yyvsp[0].parse, pnull() ); }
+ { (yyval).parse = peval( EXPR_EXISTS, (yyvsp[(1) - (1)]).parse, pnull() ); }
break;
case 39:
+
+/* Line 1464 of yacc.c */
#line 246 "jamgram.y"
- { yyval.parse = peval( EXPR_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_EQUALS, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 40:
+
+/* Line 1464 of yacc.c */
#line 248 "jamgram.y"
- { yyval.parse = peval( EXPR_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_NOTEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 41:
+
+/* Line 1464 of yacc.c */
#line 250 "jamgram.y"
- { yyval.parse = peval( EXPR_LESS, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_LESS, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 42:
+
+/* Line 1464 of yacc.c */
#line 252 "jamgram.y"
- { yyval.parse = peval( EXPR_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_LESSEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 43:
+
+/* Line 1464 of yacc.c */
#line 254 "jamgram.y"
- { yyval.parse = peval( EXPR_MORE, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_MORE, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 44:
+
+/* Line 1464 of yacc.c */
#line 256 "jamgram.y"
- { yyval.parse = peval( EXPR_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_MOREEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 45:
+
+/* Line 1464 of yacc.c */
#line 258 "jamgram.y"
- { yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_AND, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 46:
+
+/* Line 1464 of yacc.c */
#line 260 "jamgram.y"
- { yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_AND, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 47:
+
+/* Line 1464 of yacc.c */
#line 262 "jamgram.y"
- { yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_OR, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 48:
+
+/* Line 1464 of yacc.c */
#line 264 "jamgram.y"
- { yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_OR, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 49:
+
+/* Line 1464 of yacc.c */
#line 266 "jamgram.y"
- { yyval.parse = peval( EXPR_IN, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_IN, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 50:
+
+/* Line 1464 of yacc.c */
#line 268 "jamgram.y"
- { yyval.parse = peval( EXPR_NOT, yyvsp[0].parse, pnull() ); }
+ { (yyval).parse = peval( EXPR_NOT, (yyvsp[(2) - (2)]).parse, pnull() ); }
break;
case 51:
+
+/* Line 1464 of yacc.c */
#line 270 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 52:
+
+/* Line 1464 of yacc.c */
#line 281 "jamgram.y"
- { yyval.parse = P0; }
+ { (yyval).parse = P0; }
break;
case 53:
+
+/* Line 1464 of yacc.c */
#line 283 "jamgram.y"
- { yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pnode( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 54:
+
+/* Line 1464 of yacc.c */
#line 287 "jamgram.y"
- { yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); }
+ { (yyval).parse = psnode( (yyvsp[(2) - (4)]).string, (yyvsp[(4) - (4)]).parse ); }
break;
case 55:
+
+/* Line 1464 of yacc.c */
#line 296 "jamgram.y"
- { yyval.parse = pnode( P0, yyvsp[0].parse ); }
+ { (yyval).parse = pnode( P0, (yyvsp[(1) - (1)]).parse ); }
break;
case 56:
+
+/* Line 1464 of yacc.c */
#line 298 "jamgram.y"
- { yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); }
+ { (yyval).parse = pnode( (yyvsp[(3) - (3)]).parse, (yyvsp[(1) - (3)]).parse ); }
break;
case 57:
+
+/* Line 1464 of yacc.c */
#line 308 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; yymode( SCAN_NORMAL ); }
break;
case 58:
+
+/* Line 1464 of yacc.c */
#line 312 "jamgram.y"
- { yyval.parse = pnull(); yymode( SCAN_PUNCT ); }
+ { (yyval).parse = pnull(); yymode( SCAN_PUNCT ); }
break;
case 59:
+
+/* Line 1464 of yacc.c */
#line 314 "jamgram.y"
- { yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pappend( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 60:
+
+/* Line 1464 of yacc.c */
#line 318 "jamgram.y"
- { yyval.parse = plist( yyvsp[0].string ); }
+ { (yyval).parse = plist( (yyvsp[(1) - (1)]).string ); }
break;
case 61:
+
+/* Line 1464 of yacc.c */
#line 319 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 62:
+
+/* Line 1464 of yacc.c */
#line 320 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(3) - (4)]).parse; }
break;
case 63:
+
+/* Line 1464 of yacc.c */
#line 329 "jamgram.y"
- { yyval.parse = prule( yyvsp[-1].string, yyvsp[0].parse ); }
+ { (yyval).parse = prule( (yyvsp[(1) - (2)]).string, (yyvsp[(2) - (2)]).parse ); }
break;
case 64:
+
+/* Line 1464 of yacc.c */
#line 331 "jamgram.y"
- { yyval.parse = pon( yyvsp[-2].parse, prule( yyvsp[-1].string, yyvsp[0].parse ) ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (4)]).parse, prule( (yyvsp[(3) - (4)]).string, (yyvsp[(4) - (4)]).parse ) ); }
break;
case 65:
+
+/* Line 1464 of yacc.c */
#line 333 "jamgram.y"
- { yyval.parse = pon( yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (4)]).parse, (yyvsp[(4) - (4)]).parse ); }
break;
case 66:
+
+/* Line 1464 of yacc.c */
#line 343 "jamgram.y"
- { yyval.number = 0; }
+ { (yyval).number = 0; }
break;
case 67:
+
+/* Line 1464 of yacc.c */
#line 345 "jamgram.y"
- { yyval.number = yyvsp[-1].number | yyvsp[0].number; }
+ { (yyval).number = (yyvsp[(1) - (2)]).number | (yyvsp[(2) - (2)]).number; }
break;
case 68:
+
+/* Line 1464 of yacc.c */
#line 349 "jamgram.y"
- { yyval.number = EXEC_UPDATED; }
+ { (yyval).number = EXEC_UPDATED; }
break;
case 69:
+
+/* Line 1464 of yacc.c */
#line 351 "jamgram.y"
- { yyval.number = EXEC_TOGETHER; }
+ { (yyval).number = EXEC_TOGETHER; }
break;
case 70:
+
+/* Line 1464 of yacc.c */
#line 353 "jamgram.y"
- { yyval.number = EXEC_IGNORE; }
+ { (yyval).number = EXEC_IGNORE; }
break;
case 71:
+
+/* Line 1464 of yacc.c */
#line 355 "jamgram.y"
- { yyval.number = EXEC_QUIETLY; }
+ { (yyval).number = EXEC_QUIETLY; }
break;
case 72:
+
+/* Line 1464 of yacc.c */
#line 357 "jamgram.y"
- { yyval.number = EXEC_PIECEMEAL; }
+ { (yyval).number = EXEC_PIECEMEAL; }
break;
case 73:
+
+/* Line 1464 of yacc.c */
#line 359 "jamgram.y"
- { yyval.number = EXEC_EXISTING; }
+ { (yyval).number = EXEC_EXISTING; }
break;
case 74:
+
+/* Line 1464 of yacc.c */
#line 368 "jamgram.y"
- { yyval.parse = pnull(); }
+ { (yyval).parse = pnull(); }
break;
case 75:
+
+/* Line 1464 of yacc.c */
#line 370 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(2) - (2)]).parse; }
break;
- }
-
-/* Line 991 of yacc.c. */
-#line 1621 "y.tab.c"
-
- yyvsp -= yylen;
- yyssp -= yylen;
+/* Line 1464 of yacc.c */
+#line 2118 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+ YYPOPSTACK (yylen);
+ yylen = 0;
YY_STACK_PRINT (yyss, yyssp);
*++yyvsp = yyval;
-
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -1652,54 +2148,41 @@ yyerrlab:
if (!yyerrstatus)
{
++yynerrs;
-#if YYERROR_VERBOSE
- yyn = yypact[yystate];
-
- if (YYPACT_NINF < yyn && yyn < YYLAST)
- {
- YYSIZE_T yysize = 0;
- int yytype = YYTRANSLATE (yychar);
- char *yymsg;
- int yyx, yycount;
-
- yycount = 0;
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- yysize += yystrlen (yytname[yyx]) + 15, yycount++;
- yysize += yystrlen ("syntax error, unexpected ") + 1;
- yysize += yystrlen (yytname[yytype]);
- yymsg = (char *) YYSTACK_ALLOC (yysize);
- if (yymsg != 0)
- {
- char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
- yyp = yystpcpy (yyp, yytname[yytype]);
-
- if (yycount < 5)
- {
- yycount = 0;
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *));
- yyx++)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- const char *yyq = ! yycount ? ", expecting " : " or ";
- yyp = yystpcpy (yyp, yyq);
- yyp = yystpcpy (yyp, yytname[yyx]);
- yycount++;
- }
- }
- yyerror (yymsg);
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
- }
- else
- yyerror ("syntax error; also virtual memory exhausted");
- }
- else
-#endif /* YYERROR_VERBOSE */
- yyerror ("syntax error");
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
}
@@ -1709,51 +2192,49 @@ yyerrlab:
/* If just tried and failed to reuse lookahead token after an
error, discard it. */
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- {
- /* Pop the error token. */
- YYPOPSTACK;
- /* Pop the rest of the stack. */
- while (yyss < yyssp)
- {
- YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
- yydestruct (yystos[*yyssp], yyvsp);
- YYPOPSTACK;
- }
- YYABORT;
- }
-
- YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
- yydestruct (yytoken, &yylval);
- yychar = YYEMPTY;
-
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
}
/* Else will try to reuse lookahead token after shifting the error
token. */
- goto yyerrlab2;
+ goto yyerrlab1;
-/*----------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action. |
-`----------------------------------------------------*/
-yyerrlab1:
-
- /* Suppress GCC warning that yyerrlab1 is unused when no action
- invokes YYERROR. */
-#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
- __attribute__ ((__unused__))
-#endif
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
- goto yyerrlab2;
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
-/*---------------------------------------------------------------.
-| yyerrlab2 -- pop states until the error token can be shifted. |
-`---------------------------------------------------------------*/
-yyerrlab2:
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
yyerrstatus = 3; /* Each real token shifted decrements this. */
for (;;)
@@ -1774,22 +2255,20 @@ yyerrlab2:
if (yyssp == yyss)
YYABORT;
- YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
- yydestruct (yystos[yystate], yyvsp);
- yyvsp--;
- yystate = *--yyssp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
}
- if (yyn == YYFINAL)
- YYACCEPT;
-
- YYDPRINTF ((stderr, "Shifting error token, "));
-
*++yyvsp = yylval;
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
yystate = yyn;
goto yynewstate;
@@ -1808,22 +2287,40 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#ifndef yyoverflow
-/*----------------------------------------------.
-| yyoverflowlab -- parser overflow comes here. |
-`----------------------------------------------*/
-yyoverflowlab:
- yyerror ("parser stack overflow");
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
yyresult = 2;
/* Fall through. */
#endif
yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
#ifndef yyoverflow
if (yyss != yyssa)
YYSTACK_FREE (yyss);
#endif
- return yyresult;
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
}
diff --git a/tools/build/v2/engine/jamgram.h b/tools/build/v2/engine/jamgram.h
index 3cb7656417..97f117535d 100644
--- a/tools/build/v2/engine/jamgram.h
+++ b/tools/build/v2/engine/jamgram.h
@@ -1,27 +1,36 @@
-/* A Bison parser, made by GNU Bison 1.875. */
+/* A Bison parser, made by GNU Bison 2.4.3. */
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -77,6 +86,7 @@
STRING = 303
};
#endif
+/* Tokens. */
#define _BANG_t 258
#define _BANG_EQUALS_t 259
#define _AMPER_t 260
@@ -127,14 +137,13 @@
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-
diff --git a/tools/build/v2/engine/jamgram.y b/tools/build/v2/engine/jamgram.y
index c26b1e1b6b..543f1561a4 100644
--- a/tools/build/v2/engine/jamgram.y
+++ b/tools/build/v2/engine/jamgram.y
@@ -100,34 +100,34 @@
#include "parse.h"
#include "scan.h"
#include "compile.h"
-#include "newstr.h"
+#include "object.h"
#include "rules.h"
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
@@ -325,9 +325,9 @@ arg : ARG
* This needs to be split cleanly out of 'rule'
*/
-func : arg lol
+func : ARG lol
{ $$.parse = prule( $1.string, $2.parse ); }
- | ON_t arg arg lol
+ | ON_t arg ARG lol
{ $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); }
| ON_t arg RETURN_t list
{ $$.parse = pon( $2.parse, $4.parse ); }
@@ -369,3 +369,5 @@ bindlist : /* empty */
| BIND_t list
{ $$.parse = $2.parse; }
;
+
+
diff --git a/tools/build/v2/engine/jamgram.yy b/tools/build/v2/engine/jamgram.yy
index 1524348710..8d20e3896e 100644
--- a/tools/build/v2/engine/jamgram.yy
+++ b/tools/build/v2/engine/jamgram.yy
@@ -56,34 +56,34 @@
#include "parse.h"
#include "scan.h"
#include "compile.h"
-#include "newstr.h"
+#include "object.h"
#include "rules.h"
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
@@ -281,9 +281,9 @@ arg : ARG
* This needs to be split cleanly out of 'rule'
*/
-func : arg lol
+func : ARG lol
{ $$.parse = prule( $1.string, $2.parse ); }
- | `on` arg arg lol
+ | `on` arg ARG lol
{ $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); }
| `on` arg `return` list
{ $$.parse = pon( $2.parse, $4.parse ); }
diff --git a/tools/build/v2/engine/lists.c b/tools/build/v2/engine/lists.c
index ebabb63e90..c93fd7c090 100644
--- a/tools/build/v2/engine/lists.c
+++ b/tools/build/v2/engine/lists.c
@@ -5,27 +5,65 @@
*/
# include "jam.h"
-# include "newstr.h"
+# include "object.h"
# include "lists.h"
+# include "assert.h"
/*
- * lists.c - maintain lists of strings
- *
- * This implementation essentially uses a singly linked list, but
- * guarantees that the head element of every list has a valid pointer
- * to the tail of the list, so the new elements can efficiently and
- * properly be appended to the end of a list.
- *
- * To avoid massive allocation, list_free() just tacks the whole freed
- * chain onto freelist and list_new() looks on freelist first for an
- * available list struct. list_free() does not free the strings in the
- * chain: it lazily lets list_new() do so.
+ * lists.c - maintain lists of objects
*
* 08/23/94 (seiwald) - new list_append()
* 09/07/00 (seiwald) - documented lol_*() functions
*/
-static LIST *freelist = 0; /* junkpile for list_free() */
+struct freelist_node { struct freelist_node *next; };
+
+static struct freelist_node *freelist[32]; /* junkpile for list_free() */
+
+static unsigned get_bucket( unsigned size )
+{
+ unsigned bucket = 0;
+ while ( size > ( 1u << bucket ) ) ++bucket;
+ return bucket;
+}
+
+static LIST * list_alloc( unsigned size )
+{
+ unsigned bucket = get_bucket( size );
+ if ( freelist[ bucket ] )
+ {
+ struct freelist_node * result = freelist[ bucket ];
+ freelist[ bucket ] = result->next;
+ return (LIST *)result;
+ }
+ else
+ {
+ return (LIST *)BJAM_MALLOC( sizeof( LIST ) + ( 1u << bucket ) * sizeof( OBJECT * ) );
+ }
+}
+
+static void list_dealloc( LIST * l )
+{
+ unsigned size = list_length( l );
+ unsigned bucket;
+ struct freelist_node * node = (struct freelist_node *)l;
+
+ if ( size == 0 ) return;
+
+ bucket = get_bucket( size );;
+
+#ifdef BJAM_NO_MEM_CACHE
+
+ BJAM_FREE( node );
+
+#else
+
+ node->next = freelist[ bucket ];
+ freelist[ bucket ] = node;
+
+#endif
+
+}
/*
* list_append() - append a list onto another one, returning total
@@ -33,60 +71,104 @@ static LIST *freelist = 0; /* junkpile for list_free() */
LIST * list_append( LIST * l, LIST * nl )
{
- if ( !nl )
+ if ( list_empty( nl ) )
{
/* Just return l */
}
- else if ( !l )
+ else if ( list_empty( l ) )
{
l = nl;
}
else
{
- /* Graft two non-empty lists. */
- l->tail->next = nl;
- l->tail = nl->tail;
+ int l_size = list_length( l );
+ int nl_size = list_length( nl );
+ int size = l_size + nl_size;
+ unsigned bucket;
+ int i;
+
+ bucket = get_bucket( size );
+ /* Do we need to reallocate? */
+ if ( l_size <= ( 1u << (bucket - 1) ) )
+ {
+ LIST * result = list_alloc( size );
+ memcpy( list_begin( result ), list_begin( l ), l_size * sizeof( OBJECT * ) );
+ list_dealloc( l );
+ l = result;
+ }
+
+ l->impl.size = size;
+ memcpy( list_begin( l ) + l_size, list_begin( nl ), nl_size * sizeof( OBJECT * ) );
+ list_dealloc( nl );
+ return l;
}
return l;
}
+LISTITER list_begin( LIST * l )
+{
+ if ( l )
+ return (LISTITER)( (char *)l + sizeof(LIST) );
+ else
+ return 0;
+}
+
+LISTITER list_end( LIST * l )
+{
+ if ( l )
+ return list_begin( l ) + l->impl.size;
+ else
+ return 0;
+}
+
+LIST * list_new( OBJECT * value )
+{
+ LIST * head;
+ if ( freelist[ 0 ] )
+ {
+ struct freelist_node * result = freelist[ 0 ];
+ freelist[ 0 ] = result->next;
+ head = (LIST *)result;
+ }
+ else
+ {
+ head = BJAM_MALLOC( sizeof( LIST * ) + sizeof( OBJECT * ) );
+ }
+
+ head->impl.size = 1;
+ list_begin( head )[ 0 ] = value;
+
+ return head;
+}
+
/*
- * list_new() - tack a string onto the end of a list of strings
+ * list_push_back() - tack a string onto the end of a list of strings
*/
-LIST * list_new( LIST * head, char * string )
+LIST * list_push_back( LIST * head, OBJECT * value )
{
- LIST * l;
+ unsigned int size = list_length( head );
+ unsigned int i;
if ( DEBUG_LISTS )
- printf( "list > %s <\n", string );
+ printf( "list > %s <\n", object_str( value ) );
- /* Get list struct from freelist, if one available. */
- /* Otherwise allocate. */
- /* If from freelist, must free string first */
-
- if ( freelist )
+ /* If the size is a power of 2, reallocate. */
+ if ( size == 0 )
{
- l = freelist;
- freestr( l->string );
- freelist = freelist->next;
+ head = list_alloc( 1 );
}
- else
+ else if ( ( ( size - 1 ) & size ) == 0 )
{
- l = (LIST *)BJAM_MALLOC( sizeof( LIST ) );
+ LIST * l = list_alloc( size + 1 );
+ memcpy( l, head, sizeof( LIST ) + size * sizeof( OBJECT * ) );
+ list_dealloc( head );
+ head = l;
}
- /* If first on chain, head points here. */
- /* If adding to chain, tack us on. */
- /* Tail must point to this new, last element. */
-
- if ( !head ) head = l;
- else head->tail->next = l;
- head->tail = l;
- l->next = 0;
-
- l->string = string;
+ list_begin( head )[ size ] = value;
+ head->impl.size = size + 1;
return head;
}
@@ -96,11 +178,42 @@ LIST * list_new( LIST * head, char * string )
* list_copy() - copy a whole list of strings (nl) onto end of another (l).
*/
-LIST * list_copy( LIST * l, LIST * nl )
+LIST * list_copy( LIST * l )
{
- for ( ; nl; nl = list_next( nl ) )
- l = list_new( l, copystr( nl->string ) );
- return l;
+ int size = list_length( l );
+ int i;
+ LIST * result;
+
+ if ( size == 0 ) return L0;
+
+ result = list_alloc( size );
+ result->impl.size = size;
+ for ( i = 0; i < size; ++i )
+ {
+ list_begin( result )[ i ] = object_copy( list_begin( l )[ i ] );
+ }
+ return result;
+}
+
+
+LIST * list_copy_range( LIST *l, LISTITER first, LISTITER last )
+{
+ if ( first == last )
+ {
+ return L0;
+ }
+ else
+ {
+ int size = last - first;
+ LIST * result = list_alloc( size );
+ LISTITER dest = list_begin( result );
+ result->impl.size = size;
+ for ( ; first != last; ++first, ++dest )
+ {
+ *dest = object_copy( *first );
+ }
+ return result;
+ }
}
@@ -110,19 +223,19 @@ LIST * list_copy( LIST * l, LIST * nl )
LIST * list_sublist( LIST * l, int start, int count )
{
- LIST * nl = 0;
- for ( ; l && start--; l = list_next( l ) );
- for ( ; l && count--; l = list_next( l ) )
- nl = list_new( nl, copystr( l->string ) );
- return nl;
+ int end = start + count;
+ int size = list_length( l );
+ if ( start >= size ) return L0;
+ if ( end > size ) end = size;
+ return list_copy_range( l, list_begin( l ) + start, list_begin( l ) + end );
}
static int str_ptr_compare( void const * va, void const * vb )
{
- char * a = *( (char * *)va );
- char * b = *( (char * *)vb );
- return strcmp(a, b);
+ OBJECT * a = *( (OBJECT * *)va );
+ OBJECT * b = *( (OBJECT * *)vb );
+ return strcmp(object_str(a), object_str(b));
}
@@ -130,29 +243,15 @@ LIST * list_sort( LIST * l )
{
int len;
int ii;
- char * * strings;
- LIST * listp;
- LIST * result = 0;
+ LIST * result;
if ( !l )
return L0;
len = list_length( l );
- strings = (char * *)BJAM_MALLOC( len * sizeof(char*) );
-
- listp = l;
- for ( ii = 0; ii < len; ++ii )
- {
- strings[ ii ] = listp->string;
- listp = listp->next;
- }
-
- qsort( strings, len, sizeof( char * ), str_ptr_compare );
+ result = list_copy( l );
- for ( ii = 0; ii < len; ++ii )
- result = list_append( result, list_new( 0, strings[ ii ] ) );
-
- BJAM_FREE( strings );
+ qsort( list_begin( result ), len, sizeof( OBJECT * ), str_ptr_compare );
return result;
}
@@ -164,11 +263,14 @@ LIST * list_sort( LIST * l )
void list_free( LIST * head )
{
- /* Just tack onto freelist. */
- if ( head )
+ if ( !list_empty( head ) )
{
- head->tail->next = freelist;
- freelist = head;
+ LISTITER iter = list_begin( head ), end = list_end( head );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ object_free( list_item( iter ) );
+ }
+ list_dealloc( head );
}
}
@@ -179,17 +281,79 @@ void list_free( LIST * head )
LIST * list_pop_front( LIST * l )
{
- LIST * result = l->next;
- if ( result )
+ unsigned size = list_length( l );
+ assert( size != 0 );
+ --size;
+ object_free( list_front( l ) );
+
+ if ( size == 0 )
{
- result->tail = l->tail;
- l->next = L0;
- l->tail = l;
+ list_dealloc( l );
+ return L0;
+ }
+ else if ( ( ( size - 1 ) & size ) == 0 )
+ {
+ LIST * nl = list_alloc( size );
+ nl->impl.size = size;
+ memcpy( list_begin( nl ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
+ list_dealloc( l );
+ return nl;
+ }
+ else
+ {
+ l->impl.size = size;
+ memmove( list_begin( l ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
+ return l;
+ }
+}
+
+LIST * list_reverse( LIST * l )
+{
+ int size = list_length( l );
+ if ( size == 0 ) return L0;
+ else
+ {
+ LIST * result = list_alloc( size );
+ int i;
+ result->impl.size = size;
+ for ( i = 0; i < size; ++i )
+ {
+ list_begin( result )[ i ] = object_copy( list_begin( l )[ size - i - 1 ] );
+ }
+ return result;
}
- list_free( l );
- return result;
}
+int list_cmp( LIST * t, LIST * s )
+{
+ int status = 0;
+ LISTITER t_it = list_begin( t ), t_end = list_end( t );
+ LISTITER s_it = list_begin( s ), s_end = list_end( s );
+
+ while ( !status && ( t_it != t_end || s_it != s_end ) )
+ {
+ const char *st = t_it != t_end ? object_str( list_item( t_it ) ) : "";
+ const char *ss = s_it != s_end ? object_str( list_item( s_it ) ) : "";
+
+ status = strcmp( st, ss );
+
+ t_it = t_it != t_end ? list_next( t_it ) : t_it;
+ s_it = s_it != s_end ? list_next( s_it ) : s_it;
+ }
+
+ return status;
+}
+
+int list_is_sublist( LIST * sub, LIST * l )
+{
+ LISTITER iter = list_begin( sub ), end = list_end( sub );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ if ( !list_in( l, list_item( iter ) ) )
+ return 0;
+ }
+ return 1;
+}
/*
* list_print() - print a list of strings to stdout
@@ -197,12 +361,14 @@ LIST * list_pop_front( LIST * l )
void list_print( LIST * l )
{
- LIST * p = 0;
- for ( ; l; p = l, l = list_next( l ) )
- if ( p )
- printf( "%s ", p->string );
- if ( p )
- printf( "%s", p->string );
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ if ( iter != end )
+ {
+ printf( "%s", object_str( list_item( iter ) ) );
+ iter = list_next( iter );
+ for ( ; iter != end; iter = list_next( iter ) )
+ printf( " %s", object_str( list_item( iter ) ) );
+ }
}
@@ -212,16 +378,18 @@ void list_print( LIST * l )
int list_length( LIST * l )
{
- int n = 0;
- for ( ; l; l = list_next( l ), ++n );
- return n;
+ if ( l )
+ return l->impl.size;
+ else
+ return 0;
}
-int list_in( LIST * l, char * value )
+int list_in( LIST * l, OBJECT * value )
{
- for ( ; l; l = l->next )
- if ( strcmp( l->string, value ) == 0 )
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ if ( object_equal( list_item( iter ), value ) )
return 1;
return 0;
}
@@ -229,20 +397,38 @@ int list_in( LIST * l, char * value )
LIST * list_unique( LIST * sorted_list )
{
- LIST * result = 0;
- LIST * last_added = 0;
+ LIST * result = L0;
+ OBJECT * last_added = 0;
- for ( ; sorted_list; sorted_list = sorted_list->next )
+ LISTITER iter = list_begin( sorted_list ), end = list_end( sorted_list );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- if ( !last_added || strcmp( sorted_list->string, last_added->string ) != 0 )
+ if ( !last_added || !object_equal( list_item( iter ), last_added ) )
{
- result = list_new( result, sorted_list->string );
- last_added = sorted_list;
+ result = list_push_back( result, object_copy( list_item( iter ) ) );
+ last_added = list_item( iter );
}
}
return result;
}
+void list_done()
+{
+ int i;
+ int total = 0;
+ for ( i = 0; i < sizeof( freelist ) / sizeof( freelist[ 0 ] ); ++i )
+ {
+ struct freelist_node *l, *tmp;
+ int bytes;
+ for( l = freelist[ i ]; l; )
+ {
+ tmp = l;
+ l = l->next;
+ BJAM_FREE( tmp );
+ }
+ }
+}
+
/*
* lol_init() - initialize a LOL (list of lists).
@@ -284,7 +470,7 @@ void lol_free( LOL * lol )
LIST * lol_get( LOL * lol, int i )
{
- return i < lol->count ? lol->list[ i ] : 0;
+ return i < lol->count ? lol->list[ i ] : L0;
}
@@ -309,10 +495,11 @@ void lol_print( LOL * lol )
PyObject *list_to_python(LIST *l)
{
PyObject *result = PyList_New(0);
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for (; l; l = l->next)
+ for (; iter != end; iter = list_next( iter ) )
{
- PyObject* s = PyString_FromString(l->string);
+ PyObject* s = PyString_FromString(object_str(list_item(iter)));
PyList_Append(result, s);
Py_DECREF(s);
}
@@ -322,14 +509,14 @@ PyObject *list_to_python(LIST *l)
LIST *list_from_python(PyObject *l)
{
- LIST * result = 0;
+ LIST * result = L0;
Py_ssize_t i, n;
n = PySequence_Size(l);
for (i = 0; i < n; ++i)
{
PyObject *v = PySequence_GetItem(l, i);
- result = list_new (result, newstr (PyString_AsString(v)));
+ result = list_push_back(result, object_new (PyString_AsString(v)));
Py_DECREF(v);
}
diff --git a/tools/build/v2/engine/lists.h b/tools/build/v2/engine/lists.h
index 1dc598274d..bc97261e57 100644
--- a/tools/build/v2/engine/lists.h
+++ b/tools/build/v2/engine/lists.h
@@ -13,23 +13,23 @@
/*
* lists.h - the LIST structure and routines to manipulate them
*
- * The whole of jam relies on lists of strings as a datatype. This
- * module, in conjunction with newstr.c, handles these relatively
+ * The whole of jam relies on lists of objects as a datatype. This
+ * module, in conjunction with object.c, handles these relatively
* efficiently.
*
* Structures defined:
*
- * LIST - list of strings
+ * LIST - list of OBJECTs
* LOL - list of LISTs
*
* External routines:
*
* list_append() - append a list onto another one, returning total
- * list_new() - tack a string onto the end of a list of strings
- * list_copy() - copy a whole list of strings
- * list_sublist() - copy a subset of a list of strings
- * list_free() - free a list of strings
- * list_print() - print a list of strings to stdout
+ * list_new() - tack an object onto the end of a list of objects
+ * list_copy() - copy a whole list of objects
+ * list_sublist() - copy a subset of a list of objects
+ * list_free() - free a list of objects
+ * list_print() - print a list of objects to stdout
* list_length() - return the number of items in the list
*
* lol_init() - initialize a LOL (list of lists)
@@ -45,6 +45,8 @@
#ifndef LISTS_DWA20011022_H
# define LISTS_DWA20011022_H
+#include "object.h"
+
#ifdef HAVE_PYTHON
#include <Python.h>
#endif
@@ -56,11 +58,14 @@
typedef struct _list LIST;
struct _list {
- LIST *next;
- LIST *tail; /* only valid in head node */
- char *string; /* private copy */
+ union {
+ int size;
+ OBJECT *align;
+ } impl;
};
+typedef OBJECT * * LISTITER;
+
/*
* LOL - list of LISTs
*/
@@ -74,19 +79,30 @@ struct _lol {
LIST *list[ LOL_MAX ];
};
+LIST * list_new( OBJECT * value );
LIST * list_append( LIST *l, LIST *nl );
-LIST * list_copy( LIST *l, LIST *nl );
+LIST * list_copy( LIST *l );
+LIST * list_copy_range( LIST *l, LISTITER first, LISTITER last );
void list_free( LIST *head );
-LIST * list_new( LIST *head, char *string );
+LIST * list_push_back( LIST *head, OBJECT *string );
void list_print( LIST *l );
int list_length( LIST *l );
LIST * list_sublist( LIST *l, int start, int count );
LIST * list_pop_front( LIST *l );
LIST * list_sort( LIST *l);
LIST * list_unique( LIST *sorted_list);
-int list_in(LIST* l, char* value);
-
-# define list_next( l ) ((l)->next)
+int list_in(LIST* l, OBJECT* value);
+LIST * list_reverse( LIST * );
+int list_cmp( LIST * lhs, LIST * rhs );
+int list_is_sublist( LIST * sub, LIST * l );
+void list_done();
+
+LISTITER list_begin( LIST * );
+LISTITER list_end( LIST * );
+# define list_next( it ) ((it) + 1)
+# define list_item( it ) (*(it))
+# define list_empty( l ) ( (l) == L0 )
+# define list_front( l ) list_item( list_begin( l ) )
# define L0 ((LIST *)0)
@@ -95,7 +111,7 @@ void lol_init( LOL *lol );
void lol_free( LOL *lol );
LIST * lol_get( LOL *lol, int i );
void lol_print( LOL *lol );
-void lol_build( LOL* lol, char** elements );
+void lol_build( LOL* lol, const char** elements );
#ifdef HAVE_PYTHON
diff --git a/tools/build/v2/engine/make.c b/tools/build/v2/engine/make.c
index c871f0be2d..96416cbd52 100644
--- a/tools/build/v2/engine/make.c
+++ b/tools/build/v2/engine/make.c
@@ -58,7 +58,7 @@
#endif
#include "search.h"
-#include "newstr.h"
+#include "object.h"
#include "make.h"
#include "headers.h"
#include "command.h"
@@ -106,9 +106,8 @@ static const char * target_bind[] =
* make() - make a target, given its name.
*/
-int make( int n_targets, char const * * targets, int anyhow )
+int make( LIST * targets, int anyhow )
{
- int i;
COUNTS counts[ 1 ];
int status = 0; /* 1 if anything fails */
@@ -124,16 +123,24 @@ int make( int n_targets, char const * * targets, int anyhow )
bind_explicitly_located_targets();
{
+ LISTITER iter, end;
PROFILE_ENTER( MAKE_MAKE0 );
- for ( i = 0; i < n_targets; ++i )
- make0( bindtarget( targets[ i ] ), 0, 0, counts, anyhow );
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ if ( t->fate == T_FATE_INIT )
+ make0( t, 0, 0, counts, anyhow );
+ }
PROFILE_EXIT( MAKE_MAKE0 );
}
#ifdef OPT_GRAPH_DEBUG_EXT
if ( DEBUG_GRAPH )
- for ( i = 0; i < n_targets; ++i )
- dependGraphOutput( bindtarget( targets[ i ] ), 0 );
+ {
+ LISTITER iter, end;
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ dependGraphOutput( bindtarget( list_item( iter ) ), 0 );
+ }
#endif
if ( DEBUG_MAKE )
@@ -155,16 +162,13 @@ int make( int n_targets, char const * * targets, int anyhow )
counts->cantmake > 1 ? "s" : "" );
}
-#ifdef OPT_HEADER_CACHE_EXT
- hcache_done();
-#endif
-
status = counts->cantfind || counts->cantmake;
{
+ LISTITER iter, end;
PROFILE_ENTER( MAKE_MAKE1 );
- for ( i = 0; i < n_targets; ++i )
- status |= make1( bindtarget( targets[ i ] ) );
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ status |= make1( bindtarget( list_item( iter ) ) );
PROFILE_EXIT( MAKE_MAKE1 );
}
@@ -195,7 +199,7 @@ static void update_dependants( TARGET * t )
if ( DEBUG_FATE )
{
printf( "fate change %s from %s to %s (as dependant of %s)\n",
- p->name, target_fate[ (int) fate0 ], target_fate[ (int) p->fate ], t->name );
+ object_str( p->name ), target_fate[ (int) fate0 ], target_fate[ (int) p->fate ], object_str( t->name ) );
}
/* If we are done visiting it, go back and make sure its dependants
@@ -224,7 +228,7 @@ static void force_rebuilds( TARGET * t )
{
if ( DEBUG_FATE )
printf( "fate change %s from %s to %s (by rebuild)\n",
- r->name, target_fate[ (int) r->fate ], target_fate[ T_FATE_REBUILD ] );
+ object_str( r->name ), target_fate[ (int) r->fate ], target_fate[ T_FATE_REBUILD ] );
/* Force rebuild it. */
r->fate = T_FATE_REBUILD;
@@ -266,14 +270,14 @@ void make0
#endif
if ( DEBUG_MAKEPROG )
- printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+ printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
/*
* Step 1: initialize
*/
if ( DEBUG_MAKEPROG )
- printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+ printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
t->fate = T_FATE_MAKING;
@@ -284,12 +288,13 @@ void make0
/* Step 2a: set "on target" variables. */
s = copysettings( t->settings );
- pushsettings( s );
+ pushsettings( root_module(), s );
/* Step 2b: find and timestamp the target file (if it is a file). */
if ( ( t->binding == T_BIND_UNBOUND ) && !( t->flags & T_FLAG_NOTFILE ) )
{
- char * another_target;
+ OBJECT * another_target;
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, &another_target,
t->flags & T_FLAG_ISFILE );
/* If it was detected that this target refers to an already existing and
@@ -317,10 +322,10 @@ void make0
#ifdef OPT_SEMAPHORE
{
- LIST * var = var_get( "JAM_SEMAPHORE" );
- if ( var )
+ LIST * var = var_get( root_module(), constant_JAM_SEMAPHORE );
+ if ( !list_empty( var ) )
{
- TARGET * semaphore = bindtarget( var->string );
+ TARGET * semaphore = bindtarget( list_front( var ) );
semaphore->progress = T_MAKE_SEMAPHORE;
t->semaphore = semaphore;
}
@@ -332,7 +337,7 @@ void make0
headers( t );
/* Step 2d: reset "on target" variables. */
- popsettings( s );
+ popsettings( root_module(), s );
freesettings( s );
/*
@@ -341,9 +346,9 @@ void make0
if ( DEBUG_BIND )
{
- if ( strcmp( t->name, t->boundname ) )
+ if ( ! object_equal( t->name, t->boundname ) )
printf( "bind\t--\t%s%s: %s\n",
- spaces( depth ), t->name, t->boundname );
+ spaces( depth ), object_str( t->name ), object_str( t->boundname ) );
switch ( t->binding )
{
@@ -351,12 +356,12 @@ void make0
case T_BIND_MISSING:
case T_BIND_PARENTS:
printf( "time\t--\t%s%s: %s\n",
- spaces( depth ), t->name, target_bind[ (int) t->binding ] );
+ spaces( depth ), object_str( t->name ), target_bind[ (int) t->binding ] );
break;
case T_BIND_EXISTS:
printf( "time\t--\t%s%s: %s",
- spaces( depth ), t->name, ctime( &t->time ) );
+ spaces( depth ), object_str( t->name ), ctime( &t->time ) );
break;
}
}
@@ -376,7 +381,7 @@ void make0
if ( c->target->fate == T_FATE_INIT )
make0( c->target, ptime, depth + 1, counts, anyhow );
else if ( c->target->fate == T_FATE_MAKING && !internal )
- printf( "warning: %s depends on itself\n", c->target->name );
+ printf( "warning: %s depends on itself\n", object_str( c->target->name ) );
}
/* Step 3b: recursively make0() internal includes node. */
@@ -420,8 +425,8 @@ void make0
if ( DEBUG_FATE )
if ( fate < c->target->fate )
printf( "fate change %s from %s to %s by dependency %s\n",
- t->name, target_fate[(int) fate], target_fate[(int) c->target->fate],
- c->target->name );
+ object_str( t->name ), target_fate[(int) fate], target_fate[(int) c->target->fate],
+ object_str( c->target->name ) );
#endif
}
@@ -445,8 +450,8 @@ void make0
#ifdef OPT_GRAPH_DEBUG_EXT
if ( DEBUG_FATE )
if ( fate != T_FATE_STABLE )
- printf( "fate change %s back to stable, NOUPDATE.\n", t->name
- );
+ printf( "fate change %s back to stable, NOUPDATE.\n",
+ object_str( t->name ) );
#endif
last = 0;
@@ -541,10 +546,10 @@ void make0
if ( DEBUG_FATE && ( fate != savedFate ) )
{
if ( savedFate == T_FATE_STABLE )
- printf( "fate change %s set to %s%s\n", t->name,
+ printf( "fate change %s set to %s%s\n", object_str( t->name ),
target_fate[ fate ], oldTimeStamp ? " (by timestamp)" : "" );
else
- printf( "fate change %s from %s to %s%s\n", t->name,
+ printf( "fate change %s from %s to %s%s\n", object_str( t->name ),
target_fate[ savedFate ], target_fate[ fate ],
oldTimeStamp ? " (by timestamp)" : "" );
}
@@ -564,13 +569,13 @@ void make0
if ( DEBUG_FATE )
printf( "fate change %s to STABLE from %s, "
"no actions, no dependencies and do not care\n",
- t->name, target_fate[ fate ] );
+ object_str( t->name ), target_fate[ fate ] );
#endif
fate = T_FATE_STABLE;
}
else
{
- printf( "don't know how to make %s\n", t->name );
+ printf( "don't know how to make %s\n", object_str( t->name ) );
fate = T_FATE_CANTFIND;
}
}
@@ -637,7 +642,7 @@ void make0
if ( DEBUG_MAKEPROG )
printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int) t->fate ],
- spaces( depth ), t->name );
+ spaces( depth ), object_str( t->name ) );
}
@@ -648,10 +653,10 @@ static const char * target_name( TARGET * t )
static char buf[ 1000 ];
if ( t->flags & T_FLAG_INTERNAL )
{
- sprintf( buf, "%s (internal node)", t->name );
+ sprintf( buf, "%s (internal node)", object_str( t->name ) );
return buf;
}
- return t->name;
+ return object_str( t->name );
}
@@ -681,8 +686,8 @@ static void dependGraphOutput( TARGET * t, int depth )
break;
}
- if ( strcmp( t->name, t->boundname ) )
- printf( " %s Loc: %s\n", spaces( depth ), t->boundname );
+ if ( ! object_equal( t->name, t->boundname ) )
+ printf( " %s Loc: %s\n", spaces( depth ), object_str( t->boundname ) );
switch ( t->fate )
{
@@ -792,12 +797,12 @@ static TARGETS * make0sort( TARGETS * chain )
}
-static LIST * targets_to_update_ = 0;
+static LIST * targets_to_update_ = L0;
-void mark_target_for_updating( char * target )
+void mark_target_for_updating( OBJECT * target )
{
- targets_to_update_ = list_new( targets_to_update_, target );
+ targets_to_update_ = list_push_back( targets_to_update_, object_copy( target ) );
}
@@ -810,5 +815,5 @@ LIST * targets_to_update()
void clear_targets_to_update()
{
list_free( targets_to_update_ );
- targets_to_update_ = 0;
+ targets_to_update_ = L0;
}
diff --git a/tools/build/v2/engine/make.h b/tools/build/v2/engine/make.h
index b372263e19..e0c7906583 100644
--- a/tools/build/v2/engine/make.h
+++ b/tools/build/v2/engine/make.h
@@ -8,10 +8,14 @@
* make.h - bring a target up to date, once rules are in place
*/
+#ifndef MAKE_SW20111118_H
+#define MAKE_SW20111118_H
+
#include "lists.h"
+#include "object.h"
-int make( int n_targets, const char **targets, int anyhow );
-int make1( TARGET *t );
+int make( LIST * targets, int anyhow );
+int make1( TARGET * t );
typedef struct {
int temp;
@@ -30,12 +34,14 @@ void make0( TARGET *t, TARGET *p, int depth,
/*
* Specifies that the target should be updated.
*/
-void mark_target_for_updating(char *target);
+void mark_target_for_updating( OBJECT * target );
/*
* Returns the list of all the target previously passed to 'mark_target_for_updating'.
*/
-LIST *targets_to_update();
+LIST * targets_to_update();
/*
* Cleasr/unmarks all targets that are currently marked for update.
*/
void clear_targets_to_update();
+
+#endif
diff --git a/tools/build/v2/engine/make1.c b/tools/build/v2/engine/make1.c
index 8001f33390..47132419a8 100644
--- a/tools/build/v2/engine/make1.c
+++ b/tools/build/v2/engine/make1.c
@@ -57,7 +57,7 @@
#include "headers.h"
#include "search.h"
-#include "newstr.h"
+#include "object.h"
#include "make.h"
#include "command.h"
#include "execcmd.h"
@@ -72,7 +72,7 @@
static CMD * make1cmds ( TARGET * );
static LIST * make1list ( LIST *, TARGETS *, int flags );
-static SETTINGS * make1settings( LIST * vars );
+static SETTINGS * make1settings( struct module_t * module, LIST * vars );
static void make1bind ( TARGET * );
/* Ugly static - it is too hard to carry it through the callbacks. */
@@ -107,7 +107,7 @@ static void make1atail ( state * );
static void make1b ( state * );
static void make1c ( state * );
static void make1d ( state * );
-static void make_closure( void * closure, int status, timing_info *, char *, char * );
+static void make_closure( void * closure, int status, timing_info *, const char *, const char * );
typedef struct _stack
{
@@ -281,6 +281,15 @@ static void make1a( state * pState )
++pState->parent->asynccnt;
}
+ /*
+ * If the target has been previously updated with -n in
+ * effect, and we're ignoring -n, update it for real.
+ */
+ if ( !globs.noexec && pState->t->progress == T_MAKE_NOEXEC_DONE )
+ {
+ pState->t->progress = T_MAKE_INIT;
+ }
+
/* If this target is already being processed then do nothing. There is no
* need to start processing the same target all over again.
*/
@@ -350,10 +359,10 @@ static void make1atail( state * pState )
static void make1b( state * pState )
{
- TARGET * t = pState->t;
- TARGETS * c;
- TARGET * failed = 0;
- char * failed_name = "dependencies";
+ TARGET * t = pState->t;
+ TARGETS * c;
+ TARGET * failed = 0;
+ const char * failed_name = "dependencies";
/* If any dependencies are still outstanding, wait until they call make1b()
* to signal their completion.
@@ -376,7 +385,7 @@ static void make1b( state * pState )
if ( DEBUG_EXECCMD )
printf( "SEM: %s is busy, delaying launch of %s\n",
- t->semaphore->name, t->name );
+ object_str( t->semaphore->name ), object_str( t->name ) );
pop_state( &state_stack );
return;
}
@@ -384,13 +393,21 @@ static void make1b( state * pState )
/* Now ready to build target 't', if dependencies built OK. */
- /* Collect status from dependencies. */
- for ( c = t->depends; c; c = c->next )
- if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
- {
- failed = c->target;
- pState->t->status = c->target->status;
- }
+ /* Collect status from dependencies. If -n was passed then
+ * act as though all dependencies built correctly. The only
+ * way they can fail is if UPDATE_NOW was called. If
+ * the dependencies can't be found or we got an interrupt,
+ * we can't get here.
+ */
+ if ( !globs.noexec )
+ {
+ for ( c = t->depends; c; c = c->next )
+ if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
+ {
+ failed = c->target;
+ pState->t->status = c->target->status;
+ }
+ }
/* If an internal header node failed to build, we want to output the target
* that it failed on.
*/
@@ -398,7 +415,7 @@ static void make1b( state * pState )
{
failed_name = failed->flags & T_FLAG_INTERNAL
? failed->failed
- : failed->name;
+ : object_str( failed->name );
}
t->failed = failed_name;
@@ -410,11 +427,11 @@ static void make1b( state * pState )
++counts->skipped;
if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
{
- if ( !unlink( pState->t->boundname ) )
- printf( "...removing outdated %s\n", pState->t->boundname );
+ if ( !unlink( object_str( pState->t->boundname ) ) )
+ printf( "...removing outdated %s\n", object_str( pState->t->boundname ) );
}
else
- printf( "...skipped %s for lack of %s...\n", pState->t->name, failed_name );
+ printf( "...skipped %s for lack of %s...\n", object_str( pState->t->name ), failed_name );
}
if ( pState->t->status == EXEC_CMD_OK )
@@ -436,7 +453,7 @@ static void make1b( state * pState )
case T_FATE_ISTMP:
if ( DEBUG_MAKE )
- printf( "...using %s...\n", pState->t->name );
+ printf( "...using %s...\n", object_str( pState->t->name ) );
break;
case T_FATE_TOUCHED:
@@ -467,7 +484,7 @@ static void make1b( state * pState )
/* All possible fates should have been accounted for by now. */
default:
- printf( "ERROR: %s has bad fate %d", pState->t->name,
+ printf( "ERROR: %s has bad fate %d", object_str( pState->t->name ),
pState->t->fate );
abort();
}
@@ -484,8 +501,8 @@ static void make1b( state * pState )
{
++pState->t->semaphore->asynccnt;
if ( DEBUG_EXECCMD )
- printf( "SEM: %s now used by %s\n", pState->t->semaphore->name,
- pState->t->name );
+ printf( "SEM: %s now used by %s\n", object_str( pState->t->semaphore->name ),
+ object_str( pState->t->name ) );
}
#endif
@@ -508,16 +525,16 @@ static void make1c( state * pState )
if ( cmd && ( pState->t->status == EXEC_CMD_OK ) )
{
- char * rule_name = 0;
- char * target = 0;
+ const char * rule_name = 0;
+ const char * target = 0;
if ( DEBUG_MAKEQ ||
( !( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE ) )
{
- rule_name = cmd->rule->name;
- target = lol_get( &cmd->args, 0 )->string;
+ rule_name = object_str( cmd->rule->name );
+ target = object_str( list_front( lol_get( &cmd->args, 0 ) ) );
if ( globs.noexec )
- out_action( rule_name, target, cmd->buf, "", "", EXIT_OK );
+ out_action( rule_name, target, cmd->buf->value, "", "", EXIT_OK );
}
if ( globs.noexec )
@@ -529,7 +546,7 @@ static void make1c( state * pState )
{
/* Pop state first because exec_cmd() could push state. */
pop_state( &state_stack );
- exec_cmd( cmd->buf, make_closure, pState->t, cmd->shell, rule_name,
+ exec_cmd( cmd->buf->value, make_closure, pState->t, cmd->shell, rule_name,
target );
}
}
@@ -560,13 +577,17 @@ static void make1c( state * pState )
TARGET * t = pState->t;
TARGET * additional_includes = NULL;
- t->progress = T_MAKE_DONE;
+ if ( globs.noexec )
+ t->progress = T_MAKE_NOEXEC_DONE;
+ else
+ t->progress = T_MAKE_DONE;
/* Target has been updated so rescan it for dependencies. */
if ( ( t->fate >= T_FATE_MISSING ) &&
( t->status == EXEC_CMD_OK ) &&
!t->rescanned )
{
+ TARGET * saved_includes;
TARGET * target_to_rescan = t;
SETTINGS * s;
@@ -576,16 +597,21 @@ static void make1c( state * pState )
target_to_rescan = t->original_target;
/* Clean current includes. */
+ saved_includes = target_to_rescan->includes;
target_to_rescan->includes = 0;
s = copysettings( target_to_rescan->settings );
- pushsettings( s );
+ pushsettings( root_module(), s );
headers( target_to_rescan );
- popsettings( s );
+ popsettings( root_module(), s );
freesettings( s );
if ( target_to_rescan->includes )
{
+ /* Link the old includes on to make sure that it gets
+ * cleaned up correctly.
+ */
+ target_to_rescan->includes->includes = saved_includes;
target_to_rescan->includes->rescanned = 1;
/* Tricky. The parents have already been processed, but they
* have not seen the internal node, because it was just
@@ -604,6 +630,10 @@ static void make1c( state * pState )
/* Will be processed below. */
additional_includes = target_to_rescan->includes;
}
+ else
+ {
+ target_to_rescan->includes = saved_includes;
+ }
}
if ( additional_includes )
@@ -621,7 +651,7 @@ static void make1c( state * pState )
--t->semaphore->asynccnt;
if ( DEBUG_EXECCMD )
- printf( "SEM: %s is now free\n", t->semaphore->name );
+ printf( "SEM: %s is now free\n", object_str( t->semaphore->name ) );
/* If anything is waiting, notify the next target. There is no
* point in notifying waiting targets, since they will be
@@ -635,7 +665,7 @@ static void make1c( state * pState )
t->semaphore->parents = first->next;
if ( DEBUG_EXECCMD )
- printf( "SEM: placing %s on stack\n", first->target->name );
+ printf( "SEM: placing %s on stack\n", object_str( first->target->name ) );
push_state( &temp_stack, first->target, NULL, T_STATE_MAKE1B );
BJAM_FREE( first );
}
@@ -662,11 +692,11 @@ static void call_timing_rule( TARGET * target, timing_info * time )
{
LIST * timing_rule;
- pushsettings( target->settings );
- timing_rule = var_get( "__TIMING_RULE__" );
- popsettings( target->settings );
+ pushsettings( root_module(), target->settings );
+ timing_rule = var_get( root_module(), constant_TIMING_RULE );
+ popsettings( root_module(), target->settings );
- if ( timing_rule )
+ if ( !list_empty( timing_rule ) )
{
/* rule timing-rule ( args * : target : start end user system ) */
@@ -675,20 +705,20 @@ static void call_timing_rule( TARGET * target, timing_info * time )
frame_init( frame );
/* args * :: $(__TIMING_RULE__[2-]) */
- lol_add( frame->args, list_copy( L0, timing_rule->next ) );
+ lol_add( frame->args, list_copy_range( timing_rule, list_next( list_begin( timing_rule ) ), list_end( timing_rule ) ) );
/* target :: the name of the target */
- lol_add( frame->args, list_new( L0, target->name ) );
+ lol_add( frame->args, list_new( object_copy( target->name ) ) );
/* start end user system :: info about the action command */
- lol_add( frame->args, list_new( list_new( list_new( list_new( L0,
+ lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_new(
outf_time ( time->start ) ),
outf_time ( time->end ) ),
outf_double( time->user ) ),
outf_double( time->system ) ) );
/* Call the rule. */
- evaluate_rule( timing_rule->string, frame );
+ evaluate_rule( list_front( timing_rule ), frame );
/* Clean up. */
frame_free( frame );
@@ -707,17 +737,17 @@ static void call_action_rule
TARGET * target,
int status,
timing_info * time,
- char * executed_command,
- char * command_output
+ const char * executed_command,
+ const char * command_output
)
{
- LIST * action_rule;
+ LIST * action_rule;
- pushsettings( target->settings );
- action_rule = var_get( "__ACTION_RULE__" );
- popsettings( target->settings );
+ pushsettings( root_module(), target->settings );
+ action_rule = var_get( root_module(), constant_ACTION_RULE );
+ popsettings( root_module(), target->settings );
- if ( action_rule )
+ if ( !list_empty( action_rule ) )
{
/* rule action-rule (
args * :
@@ -730,15 +760,15 @@ static void call_action_rule
frame_init( frame );
/* args * :: $(__ACTION_RULE__[2-]) */
- lol_add( frame->args, list_copy( L0, action_rule->next ) );
+ lol_add( frame->args, list_copy_range( action_rule, list_next( list_begin( action_rule ) ), list_end( action_rule ) ) );
/* target :: the name of the target */
- lol_add( frame->args, list_new( L0, target->name ) );
+ lol_add( frame->args, list_new( object_copy( target->name ) ) );
/* command status start end user system :: info about the action command */
lol_add( frame->args,
- list_new( list_new( list_new( list_new( list_new( list_new( L0,
- newstr( executed_command ) ),
+ list_push_back( list_push_back( list_push_back( list_push_back( list_push_back( list_new(
+ object_new( executed_command ) ),
outf_int( status ) ),
outf_time( time->start ) ),
outf_time( time->end ) ),
@@ -747,12 +777,12 @@ static void call_action_rule
/* output ? :: the output of the action command */
if ( command_output )
- lol_add( frame->args, list_new( L0, newstr( command_output ) ) );
+ lol_add( frame->args, list_new( object_new( command_output ) ) );
else
lol_add( frame->args, L0 );
/* Call the rule. */
- evaluate_rule( action_rule->string, frame );
+ evaluate_rule( list_front( action_rule ), frame );
/* Clean up. */
frame_free( frame );
@@ -770,8 +800,8 @@ static void make_closure
void * closure,
int status,
timing_info * time,
- char * executed_command,
- char * command_output
+ const char * executed_command,
+ const char * command_output
)
{
TARGET * built = (TARGET *)closure;
@@ -801,7 +831,7 @@ static void make1d( state * pState )
CMD * cmd = (CMD *)t->cmds;
int status = pState->status;
- if ( t->flags & T_FLAG_FAIL_EXPECTED )
+ if ( t->flags & T_FLAG_FAIL_EXPECTED && !globs.noexec )
{
/* Invert execution result when FAIL_EXPECTED has been applied. */
switch ( status )
@@ -823,9 +853,9 @@ static void make1d( state * pState )
if ( ( status == EXEC_CMD_FAIL ) && DEBUG_MAKE )
{
if ( !DEBUG_EXEC )
- printf( "%s\n", cmd->buf );
+ printf( "%s\n", cmd->buf->value );
- printf( "...failed %s ", cmd->rule->name );
+ printf( "...failed %s ", object_str( cmd->rule->name ) );
list_print( lol_get( &cmd->args, 0 ) );
printf( "...\n" );
}
@@ -842,16 +872,17 @@ static void make1d( state * pState )
if (status != EXEC_CMD_OK)
{
LIST * targets = lol_get( &cmd->args, 0 );
- for ( ; targets; targets = list_next( targets ) )
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
int need_unlink = 1;
- TARGET* t = bindtarget ( targets->string );
+ TARGET* t = bindtarget ( list_item( iter ) );
if (t->flags & T_FLAG_PRECIOUS)
{
need_unlink = 0;
}
- if (need_unlink && !unlink( targets->string ) )
- printf( "...removing %s\n", targets->string );
+ if (need_unlink && !unlink( object_str( list_item( iter ) ) ) )
+ printf( "...removing %s\n", object_str( list_item( iter ) ) );
}
}
@@ -878,29 +909,17 @@ static void swap_settings
TARGET * new_target
)
{
- if ( new_module == root_module() )
- new_module = 0;
-
if ( ( new_target == *current_target ) && ( new_module == *current_module ) )
return;
if ( *current_target )
- popsettings( (*current_target)->settings );
-
- if ( new_module != *current_module )
- {
- if ( *current_module )
- exit_module( *current_module );
+ popsettings( *current_module, (*current_target)->settings );
- *current_module = new_module;
-
- if ( new_module )
- enter_module( new_module );
- }
+ if ( new_target )
+ pushsettings( new_module, new_target->settings );
+ *current_module = new_module;
*current_target = new_target;
- if ( new_target )
- pushsettings( new_target->settings );
}
@@ -916,10 +935,11 @@ static void swap_settings
static CMD * make1cmds( TARGET * t )
{
CMD * cmds = 0;
- LIST * shell = 0;
+ LIST * shell = L0;
module_t * settings_module = 0;
TARGET * settings_target = 0;
ACTIONS * a0;
+ int running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING;
/* Step through actions. Actions may be shared with other targets or grouped
* using RULE_TOGETHER, so actions already seen are skipped.
@@ -939,10 +959,10 @@ static CMD * make1cmds( TARGET * t )
/* Only do rules with commands to execute. If this action has already
* been executed, use saved status.
*/
- if ( !actions || a0->action->running )
+ if ( !actions || a0->action->running >= running_flag )
continue;
- a0->action->running = 1;
+ a0->action->running = running_flag;
/* Make LISTS of targets and sources. If `execute together` has been
* specified for this rule, tack on sources from each instance of this
@@ -952,28 +972,30 @@ static CMD * make1cmds( TARGET * t )
ns = make1list( L0, a0->action->sources, actions->flags );
if ( actions->flags & RULE_TOGETHER )
for ( a1 = a0->next; a1; a1 = a1->next )
- if ( a1->action->rule == rule && !a1->action->running )
+ if ( a1->action->rule == rule && a1->action->running < running_flag )
{
ns = make1list( ns, a1->action->sources, actions->flags );
- a1->action->running = 1;
+ a1->action->running = running_flag;
}
/* If doing only updated (or existing) sources, but none have been
* updated (or exist), skip this action.
*/
- if ( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
+ if ( list_empty( ns ) && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
{
list_free( nt );
continue;
}
swap_settings( &settings_module, &settings_target, rule->module, t );
- if ( !shell )
- shell = var_get( "JAMSHELL" ); /* shell is per-target */
+ if ( list_empty( shell ) )
+ {
+ shell = var_get( rule->module, constant_JAMSHELL ); /* shell is per-target */
+ }
/* If we had 'actions xxx bind vars' we bind the vars now. */
- boundvars = make1settings( actions->bindlist );
- pushsettings( boundvars );
+ boundvars = make1settings( rule->module, actions->bindlist );
+ pushsettings( rule->module, boundvars );
/*
* Build command, starting with all source args.
@@ -998,9 +1020,9 @@ static CMD * make1cmds( TARGET * t )
{
/* Build cmd: cmd_new consumes its lists. */
CMD * cmd = cmd_new( rule,
- list_copy( L0, nt ),
+ list_copy( nt ),
list_sublist( ns, start, chunk ),
- list_copy( L0, shell ) );
+ list_copy( shell ) );
if ( cmd )
{
@@ -1018,14 +1040,14 @@ static CMD * make1cmds( TARGET * t )
else
{
/* Too long and not splittable. */
- printf( "%s actions too long (max %d):\n", rule->name, MAXLINE
+ printf( "%s actions too long (max %d):\n", object_str( rule->name ), MAXLINE
);
/* Tell the user what didn't fit. */
- cmd = cmd_new( rule, list_copy( L0, nt ),
+ cmd = cmd_new( rule, list_copy( nt ),
list_sublist( ns, start, chunk ),
- list_new( L0, newstr( "%" ) ) );
- fputs( cmd->buf, stdout );
+ list_new( object_copy( constant_percent ) ) );
+ fputs( cmd->buf->value, stdout );
exit( EXITBAD );
}
}
@@ -1038,7 +1060,7 @@ static CMD * make1cmds( TARGET * t )
/* Free the variables whose values were bound by 'actions xxx bind
* vars'.
*/
- popsettings( boundvars );
+ popsettings( rule->module, boundvars );
freesettings( boundvars );
}
@@ -1077,16 +1099,16 @@ static LIST * make1list( LIST * l, TARGETS * targets, int flags )
/* Prohibit duplicates for RULE_TOGETHER. */
if ( flags & RULE_TOGETHER )
{
- LIST * m;
- for ( m = l; m; m = m->next )
- if ( !strcmp( m->string, t->boundname ) )
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ if ( object_equal( list_item( iter ), t->boundname ) )
break;
- if ( m )
+ if ( iter != end )
continue;
}
/* Build new list. */
- l = list_new( l, copystr( t->boundname ) );
+ l = list_push_back( l, object_copy( t->boundname ) );
}
return l;
@@ -1097,29 +1119,31 @@ static LIST * make1list( LIST * l, TARGETS * targets, int flags )
* make1settings() - for vars that get bound values, build up replacement lists.
*/
-static SETTINGS * make1settings( LIST * vars )
+static SETTINGS * make1settings( struct module_t * module, LIST * vars )
{
SETTINGS * settings = 0;
- for ( ; vars; vars = list_next( vars ) )
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
{
- LIST * l = var_get( vars->string );
- LIST * nl = 0;
+ LIST * l = var_get( module, list_item( vars_iter ) );
+ LIST * nl = L0;
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for ( ; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* Make sure the target is bound. */
if ( t->binding == T_BIND_UNBOUND )
make1bind( t );
/* Build a new list. */
- nl = list_new( nl, copystr( t->boundname ) );
+ nl = list_push_back( nl, object_copy( t->boundname ) );
}
/* Add to settings chain. */
- settings = addsettings( settings, VAR_SET, vars->string, nl );
+ settings = addsettings( settings, VAR_SET, list_item( vars_iter ), nl );
}
return settings;
@@ -1138,8 +1162,9 @@ static void make1bind( TARGET * t )
if ( t->flags & T_FLAG_NOTFILE )
return;
- pushsettings( t->settings );
+ pushsettings( root_module(), t->settings );
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, 0, ( t->flags & T_FLAG_ISFILE ) );
t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
}
diff --git a/tools/build/v2/engine/modules.c b/tools/build/v2/engine/modules.c
index 7295259415..8898d18bb0 100644
--- a/tools/build/v2/engine/modules.c
+++ b/tools/build/v2/engine/modules.c
@@ -8,64 +8,54 @@
#include "modules.h"
#include "string.h"
#include "hash.h"
-#include "newstr.h"
+#include "object.h"
#include "lists.h"
#include "parse.h"
#include "rules.h"
#include "variable.h"
#include "strings.h"
+#include "native.h"
#include <assert.h>
static struct hash * module_hash = 0;
+static module_t root;
-
-static char * new_module_str( module_t * m, char * suffix )
-{
- char * result;
- string s;
- string_copy( &s, m->name );
- string_append( &s, suffix );
- result = newstr( s.value );
- string_free( &s );
- return result;
-}
-
-
-module_t * bindmodule( char * name )
+module_t * bindmodule( OBJECT * name )
{
- PROFILE_ENTER( BINDMODULE );
-
- string s;
- module_t m_;
- module_t * m = &m_;
-
- if ( !module_hash )
- module_hash = hashinit( sizeof( module_t ), "modules" );
- string_new( &s );
- if ( name )
+ if ( !name )
{
- string_append( &s, name );
- string_push_back( &s, '.' );
+ return &root;
}
-
- m->name = s.value;
-
- if ( hashenter( module_hash, (HASHDATA * *)&m ) )
+ else
{
- m->name = newstr( m->name );
- m->variables = 0;
- m->rules = 0;
- m->imported_modules = 0;
- m->class_module = 0;
- m->native_rules = 0;
- m->user_module = 0;
+ PROFILE_ENTER( BINDMODULE );
+
+ module_t * m;
+ int found;
+
+ if ( !module_hash )
+ module_hash = hashinit( sizeof( module_t ), "modules" );
+
+ m = (module_t *)hash_insert( module_hash, name, &found );
+ if ( !found )
+ {
+ m->name = object_copy( name );
+ m->variables = 0;
+ m->variable_indices = 0;
+ m->num_fixed_variables = 0;
+ m->fixed_variables = 0;
+ m->rules = 0;
+ m->imported_modules = 0;
+ m->class_module = 0;
+ m->native_rules = 0;
+ m->user_module = 0;
+ }
+
+ PROFILE_EXIT( BINDMODULE );
+
+ return m;
}
- string_free( &s );
-
- PROFILE_EXIT( BINDMODULE );
-
- return m;
}
/*
@@ -74,7 +64,7 @@ module_t * bindmodule( char * name )
struct hash * demand_rules( module_t * m )
{
if ( !m->rules )
- m->rules = hashinit( sizeof( RULE ), new_module_str( m, "rules" ) );
+ m->rules = hashinit( sizeof( RULE ), "rules" );
return m->rules;
}
@@ -89,43 +79,194 @@ static void delete_rule_( void * xrule, void * data )
}
+static void delete_native_rule( void * xrule, void * data )
+{
+ native_rule_t * rule = (native_rule_t *)xrule;
+ object_free( rule->name );
+ if ( rule->procedure )
+ function_free( rule->procedure );
+}
+
+
+static void delete_imported_modules( void * xmodule_name, void * data )
+{
+ object_free( *(OBJECT * *)xmodule_name );
+}
+
+static void free_fixed_variable( void * xvar, void * data );
+
void delete_module( module_t * m )
{
/* Clear out all the rules. */
if ( m->rules )
{
hashenumerate( m->rules, delete_rule_, (void *)0 );
- hashdone( m->rules );
+ hash_free( m->rules );
m->rules = 0;
}
+ if ( m->native_rules )
+ {
+ hashenumerate( m->native_rules, delete_native_rule, (void *)0 );
+ hash_free( m->native_rules );
+ m->native_rules = 0;
+ }
+
if ( m->variables )
{
- var_hash_swap( &m->variables );
- var_done();
- var_hash_swap( &m->variables );
+ var_done( m );
m->variables = 0;
}
+
+ if ( m->fixed_variables )
+ {
+ int i;
+ for ( i = 0; i < m->num_fixed_variables; ++i )
+ {
+ list_free( m->fixed_variables[ i ] );
+ }
+ BJAM_FREE( m->fixed_variables );
+ m->fixed_variables = 0;
+ }
+
+ if ( m->variable_indices )
+ {
+ hashenumerate( m->variable_indices, &free_fixed_variable, (void *)0 );
+ hash_free( m->variable_indices );
+ m->variable_indices = 0;
+ }
+
+ if ( m->imported_modules )
+ {
+ hashenumerate( m->imported_modules, delete_imported_modules, (void *)0 );
+ hash_free( m->imported_modules );
+ m->imported_modules = 0;
+ }
}
-module_t * root_module()
+struct module_stats
+{
+ OBJECT * module_name;
+ struct hashstats rules_stats[ 1 ];
+ struct hashstats variables_stats[ 1 ];
+ struct hashstats variable_indices_stats[ 1 ];
+ struct hashstats imported_modules_stats[ 1 ];
+};
+
+
+static void module_stat( struct hash * hp, OBJECT * module, const char * name )
+{
+ if ( hp )
+ {
+ struct hashstats stats[ 1 ];
+ string id[ 1 ];
+ hashstats_init( stats );
+ string_new( id );
+ string_append( id, object_str( module ) );
+ string_push_back( id, ' ' );
+ string_append( id, name );
+
+ hashstats_add( stats, hp );
+ hashstats_print( stats, id->value );
+
+ string_free( id );
+ }
+}
+
+
+static void class_module_stat( struct hashstats * stats, OBJECT * module, const char * name )
+{
+ if ( stats->item_size )
+ {
+ string id[ 1 ];
+ string_new( id );
+ string_append( id, object_str( module ) );
+ string_append( id, " object " );
+ string_append( id, name );
+
+ hashstats_print( stats, id->value );
+
+ string_free( id );
+ }
+}
+
+
+static void stat_module( void * xmodule, void * data )
+{
+ module_t *m = (module_t *)xmodule;
+
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ {
+ struct hash * class_info = (struct hash *)data;
+ if ( m->class_module )
+ {
+ int found;
+ struct module_stats * ms = (struct module_stats *)hash_insert( class_info, m->class_module->name, &found );
+ if ( !found )
+ {
+ ms->module_name = m->class_module->name;
+ hashstats_init( ms->rules_stats );
+ hashstats_init( ms->variables_stats );
+ hashstats_init( ms->variable_indices_stats );
+ hashstats_init( ms->imported_modules_stats );
+ }
+
+ hashstats_add( ms->rules_stats, m->rules );
+ hashstats_add( ms->variables_stats, m->variables );
+ hashstats_add( ms->variable_indices_stats, m->variable_indices );
+ hashstats_add( ms->imported_modules_stats, m->imported_modules );
+ }
+ else
+ {
+ module_stat( m->rules, m->name, "rules" );
+ module_stat( m->variables, m->name, "variables" );
+ module_stat( m->variable_indices, m->name, "fixed variables" );
+ module_stat( m->imported_modules, m->name, "imported modules" );
+ }
+ }
+
+ delete_module( m );
+ object_free( m->name );
+}
+
+static void print_class_stats( void * xstats, void * data )
{
- static module_t * root = 0;
- if ( !root )
- root = bindmodule( 0 );
- return root;
+ struct module_stats * stats = (struct module_stats *)xstats;
+ class_module_stat( stats->rules_stats, stats->module_name, "rules" );
+ class_module_stat( stats->variables_stats, stats->module_name, "variables" );
+ class_module_stat( stats->variable_indices_stats, stats->module_name, "fixed variables" );
+ class_module_stat( stats->imported_modules_stats, stats->module_name, "imported modules" );
}
-void enter_module( module_t * m )
+
+static void delete_module_( void * xmodule, void * data )
{
- var_hash_swap( &m->variables );
+ module_t *m = (module_t *)xmodule;
+
+ delete_module( m );
+ object_free( m->name );
}
-void exit_module( module_t * m )
+void modules_done()
+{
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ {
+ struct hash * class_hash = hashinit( sizeof( struct module_stats ), "object info" );
+ hashenumerate( module_hash, stat_module, (void *)class_hash );
+ hashenumerate( class_hash, print_class_stats, (void *)0 );
+ hash_free( class_hash );
+ }
+ hashenumerate( module_hash, delete_module_, (void *)0 );
+ hashdone( module_hash );
+ module_hash = 0;
+ delete_module( &root );
+}
+
+module_t * root_module()
{
- var_hash_swap( &m->variables );
+ return &root;
}
@@ -134,16 +275,22 @@ void import_module( LIST * module_names, module_t * target_module )
PROFILE_ENTER( IMPORT_MODULE );
struct hash * h;
+ LISTITER iter, end;
if ( !target_module->imported_modules )
target_module->imported_modules = hashinit( sizeof( char * ), "imported" );
h = target_module->imported_modules;
- for ( ; module_names; module_names = module_names->next )
+ iter = list_begin( module_names ), end = list_end( module_names );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- char * s = module_names->string;
- char * * ss = &s;
- hashenter( h, (HASHDATA * *)&ss );
+ int found;
+ OBJECT * s = list_item( iter );
+ OBJECT * * ss = (OBJECT * *)hash_insert( h, s, &found );
+ if( !found )
+ {
+ *ss = object_copy( s );
+ }
}
PROFILE_EXIT( IMPORT_MODULE );
@@ -152,10 +299,10 @@ void import_module( LIST * module_names, module_t * target_module )
static void add_module_name( void * r_, void * result_ )
{
- char * * r = (char * *)r_;
+ OBJECT * * r = (OBJECT * *)r_;
LIST * * result = (LIST * *)result_;
- *result = list_new( *result, copystr( *r ) );
+ *result = list_push_back( *result, object_copy( *r ) );
}
@@ -166,3 +313,124 @@ LIST * imported_modules( module_t * module )
hashenumerate( module->imported_modules, add_module_name, &result );
return result;
}
+
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
+struct fixed_variable
+{
+ OBJECT * key;
+ int n;
+};
+
+struct bind_vars_t
+{
+ module_t * module;
+ int counter;
+};
+
+static void free_fixed_variable( void * xvar, void * data )
+{
+ object_free( ( (struct fixed_variable *)xvar )->key );
+}
+
+static void bind_variables_for_rule( void * xrule, void * xdata )
+{
+ RULE * rule = (RULE *)xrule;
+ struct bind_vars_t * data = (struct bind_vars_t *)xdata;
+ if ( rule->procedure && rule->module == data->module )
+ rule->procedure = function_bind_variables( rule->procedure, data->module, &data->counter );
+}
+
+void module_bind_variables( struct module_t * m )
+{
+ if ( m != root_module() && m->rules )
+ {
+ struct bind_vars_t data;
+ data.module = m;
+ data.counter = m->num_fixed_variables;
+ hashenumerate( m->rules, &bind_variables_for_rule, &data );
+ module_set_fixed_variables( m, data.counter );
+ }
+}
+
+int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter )
+{
+ struct fixed_variable * v;
+ int found;
+
+ assert( !m->class_module );
+
+ if ( !m->variable_indices )
+ m->variable_indices = hashinit( sizeof( struct fixed_variable ), "variable index table" );
+
+ v = (struct fixed_variable *)hash_insert( m->variable_indices, name, &found );
+ if ( !found )
+ {
+ v->key = object_copy( name );
+ v->n = (*counter)++;
+ }
+
+ return v->n;
+}
+
+LIST * var_get_and_clear_raw( module_t * m, OBJECT * name );
+
+static void load_fixed_variable( void * xvar, void * data )
+{
+ struct fixed_variable * var = (struct fixed_variable *)xvar;
+ struct module_t * m = (struct module_t *)data;
+ if ( var->n >= m->num_fixed_variables )
+ {
+ m->fixed_variables[ var->n ] = var_get_and_clear_raw( m, var->key );
+ }
+}
+
+void module_set_fixed_variables( struct module_t * m, int n_variables )
+{
+ /* Reallocate */
+ struct hash * variable_indices;
+ LIST * * fixed_variables = BJAM_MALLOC( n_variables * sizeof( LIST * ) );
+ if ( m->fixed_variables )
+ {
+ memcpy( fixed_variables, m->fixed_variables, n_variables * sizeof( LIST * ) );
+ BJAM_FREE( m->fixed_variables );
+ }
+ m->fixed_variables = fixed_variables;
+ if ( m->class_module )
+ {
+ variable_indices = m->class_module->variable_indices;
+ }
+ else
+ {
+ variable_indices = m->variable_indices;
+ }
+ if ( variable_indices )
+ hashenumerate( variable_indices, &load_fixed_variable, m );
+ m->num_fixed_variables = n_variables;
+}
+
+int module_get_fixed_var( struct module_t * m_, OBJECT * name )
+{
+ struct fixed_variable * v;
+ struct module_t * m = m_;
+
+ if ( m->class_module )
+ {
+ m = m->class_module;
+ }
+
+ if ( !m->variable_indices )
+ return -1;
+
+ v = (struct fixed_variable *)hash_find( m->variable_indices, name );
+ if ( v && v->n < m_->num_fixed_variables )
+ {
+ return v->n;
+ }
+ else
+ {
+ return -1;
+ }
+}
diff --git a/tools/build/v2/engine/modules.h b/tools/build/v2/engine/modules.h
index 60053a239f..a7d9752b8c 100644
--- a/tools/build/v2/engine/modules.h
+++ b/tools/build/v2/engine/modules.h
@@ -10,28 +10,44 @@
struct module_t
{
- char* name;
- struct hash* rules;
- struct hash* variables;
- struct hash* imported_modules;
- struct module_t* class_module;
- struct hash* native_rules;
+ OBJECT * name;
+ struct hash * rules;
+ struct hash * variables;
+ struct hash * variable_indices;
+ int num_fixed_variables;
+ LIST * * fixed_variables;
+ struct hash * imported_modules;
+ struct module_t * class_module;
+ struct hash * native_rules;
int user_module;
};
typedef struct module_t module_t ; /* MSVC debugger gets confused unless this is provided */
-module_t* bindmodule( char* name );
-module_t* root_module();
-void enter_module( module_t* );
-void exit_module( module_t* );
-void delete_module( module_t* );
+module_t * bindmodule( OBJECT * name );
+module_t * root_module();
+void delete_module( module_t * );
-void import_module(LIST* module_names, module_t* target_module);
+void import_module( LIST * module_names, module_t * target_module );
LIST* imported_modules(module_t* module);
-struct hash* demand_rules( module_t* );
+struct hash * demand_rules( module_t * );
+void module_bind_variables( struct module_t * m );
+
+/*
+ * After calling module_add_fixed_var, module_set_fixed_variables
+ * must be called before accessing any variables in the module.
+ */
+int module_add_fixed_var( struct module_t * m, OBJECT * name, int * n );
+void module_set_fixed_variables( struct module_t * m, int n );
+
+/*
+ * Returns the index of the variable or -1 if none exists.
+ */
+int module_get_fixed_var( struct module_t * m, OBJECT * name );
+
+void modules_done();
#endif
diff --git a/tools/build/v2/engine/modules/order.c b/tools/build/v2/engine/modules/order.c
index d77943a79c..ed632be3ac 100644
--- a/tools/build/v2/engine/modules/order.c
+++ b/tools/build/v2/engine/modules/order.c
@@ -5,18 +5,19 @@
#include "../native.h"
#include "../lists.h"
#include "../strings.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../variable.h"
/* Use quite klugy approach: when we add order dependency from 'a' to 'b',
just append 'b' to of value of variable 'a'.
*/
-LIST *add_pair( PARSE *parse, FRAME *frame )
+LIST *add_pair( FRAME *frame, int flags )
{
LIST* arg = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg ), end = list_end( arg );
- var_set(arg->string, list_copy(0, arg->next), VAR_APPEND);
+ var_set( frame->module, list_item( iter ), list_copy_range( arg, list_next( iter ), end ), VAR_APPEND );
return L0;
}
@@ -24,11 +25,12 @@ LIST *add_pair( PARSE *parse, FRAME *frame )
/** Given a list and a value, returns position of that value in
the list, or -1 if not found.
*/
-int list_index(LIST* list, const char* value)
+int list_index(LIST* list, OBJECT* value)
{
int result = 0;
- for(; list; list = list->next, ++result) {
- if (strcmp(list->string, value) == 0)
+ LISTITER iter = list_begin(list), end = list_end(list);
+ for(; iter != end; iter = list_next(iter), ++result) {
+ if (object_equal(list_item(iter), value))
return result;
}
return -1;
@@ -74,12 +76,12 @@ void topological_sort(int** graph, int num_vertices, int* result)
BJAM_FREE(colors);
}
-LIST *order( PARSE *parse, FRAME *frame )
+LIST *order( FRAME *frame, int flags )
{
- LIST* arg = lol_get( frame->args, 0 );
- LIST* tmp;
- LIST* result = 0;
+ LIST* arg = lol_get( frame->args, 0 );
+ LIST* result = L0;
int src;
+ LISTITER iter = list_begin(arg), end = list_end(arg);
/* We need to create a graph of order dependencies between
the passed objects. We assume that there are no duplicates
@@ -89,15 +91,16 @@ LIST *order( PARSE *parse, FRAME *frame )
int** graph = (int**)BJAM_CALLOC(length, sizeof(int*));
int* order = (int*)BJAM_MALLOC((length+1)*sizeof(int));
- for(tmp = arg, src = 0; tmp; tmp = tmp->next, ++src) {
+ for(src = 0; iter != end; iter = list_next(iter), ++src) {
/* For all object this one depend upon, add elements
to 'graph' */
- LIST* dependencies = var_get(tmp->string);
+ LIST* dependencies = var_get(frame->module, list_item(iter));
int index = 0;
+ LISTITER dep_iter = list_begin(dependencies), dep_end = list_end(dependencies);
graph[src] = (int*)BJAM_CALLOC(list_length(dependencies)+1, sizeof(int));
- for(; dependencies; dependencies = dependencies->next) {
- int dst = list_index(arg, dependencies->string);
+ for(; dep_iter != dep_end; dep_iter = list_next(dep_iter)) {
+ int dst = list_index(arg, list_item(dep_iter));
if (dst != -1)
graph[src][index++] = dst;
}
@@ -110,9 +113,9 @@ LIST *order( PARSE *parse, FRAME *frame )
int index = length-1;
for(; index >= 0; --index) {
int i;
- tmp = arg;
- for (i = 0; i < order[index]; ++i, tmp = tmp->next);
- result = list_new(result, tmp->string);
+ iter = list_begin(arg), end = list_end(arg);
+ for (i = 0; i < order[index]; ++i, iter = list_next(iter));
+ result = list_push_back(result, object_copy(list_item(iter)));
}
}
@@ -131,12 +134,12 @@ LIST *order( PARSE *parse, FRAME *frame )
void init_order()
{
{
- char* args[] = { "first", "second", 0 };
+ const char* args[] = { "first", "second", 0 };
declare_native_rule("class@order", "add-pair", args, add_pair, 1);
}
{
- char* args[] = { "objects", "*", 0 };
+ const char* args[] = { "objects", "*", 0 };
declare_native_rule("class@order", "order", args, order, 1);
}
diff --git a/tools/build/v2/engine/modules/path.c b/tools/build/v2/engine/modules/path.c
index f5d0962246..ca243f03d6 100644
--- a/tools/build/v2/engine/modules/path.c
+++ b/tools/build/v2/engine/modules/path.c
@@ -4,17 +4,17 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
-LIST *path_exists( PARSE *parse, FRAME *frame )
+LIST *path_exists( FRAME *frame, int flags )
{
LIST* l = lol_get( frame->args, 0 );
time_t time;
- timestamp(l->string, &time);
+ timestamp(list_front(l), &time);
if (time != 0)
{
- return list_new(0, newstr("true"));
+ return list_new(object_new("true"));
}
else
{
@@ -25,7 +25,7 @@ LIST *path_exists( PARSE *parse, FRAME *frame )
void init_path()
{
{
- char* args[] = { "location", 0 };
+ const char* args[] = { "location", 0 };
declare_native_rule("path", "exists", args, path_exists, 1);
}
diff --git a/tools/build/v2/engine/modules/property-set.c b/tools/build/v2/engine/modules/property-set.c
index 2b0fb5d97b..9d0c5cf633 100644
--- a/tools/build/v2/engine/modules/property-set.c
+++ b/tools/build/v2/engine/modules/property-set.c
@@ -4,7 +4,7 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../strings.h"
#include "../lists.h"
#include "../variable.h"
@@ -19,7 +19,7 @@ LIST* get_grist(char* f)
string_new(s);
string_append_range(s, f, end+1);
- result = list_new(0, newstr(s->value));
+ result = list_new(object_new(s->value));
string_free(s);
return result;
@@ -41,17 +41,18 @@ rule create ( raw-properties * )
}
*/
-LIST *property_set_create( PARSE *parse, FRAME *frame )
+LIST *property_set_create( FRAME *frame, int flags )
{
LIST* properties = lol_get( frame->args, 0 );
- LIST* sorted = 0;
+ LIST* sorted = L0;
#if 0
LIST* order_sensitive = 0;
#endif
LIST* unique;
- LIST* tmp;
LIST* val;
string var[1];
+ OBJECT* name;
+ LISTITER iter, end;
#if 0
/* Sort all properties which are not order sensitive */
@@ -59,9 +60,9 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
LIST* g = get_grist(tmp->string);
LIST* att = call_rule("feature.attributes", frame, g, 0);
if (list_in(att, "order-sensitive")) {
- order_sensitive = list_new( order_sensitive, tmp->string);
+ order_sensitive = list_new( order_sensitive, copystr(tmp->string));
} else {
- sorted = list_new( sorted, tmp->string);
+ sorted = list_new( sorted, copystr(tmp->string));
}
list_free(att);
}
@@ -76,22 +77,28 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
string_new(var);
string_append(var, ".ps.");
- for(tmp = unique; tmp; tmp = tmp->next) {
- string_append(var, tmp->string);
+ iter = list_begin( unique ), end = list_end( unique );
+ for( ; iter != end; iter = list_next( iter ) ) {
+ string_append(var, object_str( list_item( iter ) ));
string_push_back(var, '-');
}
- val = var_get(var->value);
- if (val == 0)
+ name = object_new(var->value);
+ val = var_get(frame->module, name);
+ if (list_empty(val))
{
- val = call_rule("new", frame,
- list_append(list_new(0, "property-set"), unique), 0);
+ OBJECT* rulename = object_new("new");
+ val = call_rule(rulename, frame,
+ list_append(list_new(object_new("property-set")), unique), 0);
+ object_free(rulename);
- var_set(newstr(var->value), list_copy(0, val), VAR_SET);
+ var_set(frame->module, name, list_copy(val), VAR_SET);
}
else
{
- val = list_copy(0, val);
+ list_free(unique);
+ val = list_copy(val);
}
+ object_free(name);
string_free(var);
/* The 'unique' variable is freed in 'call_rule'. */
@@ -104,7 +111,7 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
void init_property_set()
{
{
- char* args[] = { "raw-properties", "*", 0 };
+ const char* args[] = { "raw-properties", "*", 0 };
declare_native_rule("property-set", "create", args, property_set_create, 1);
}
}
diff --git a/tools/build/v2/engine/modules/regex.c b/tools/build/v2/engine/modules/regex.c
index d048ba1de4..9002f4bad3 100644
--- a/tools/build/v2/engine/modules/regex.c
+++ b/tools/build/v2/engine/modules/regex.c
@@ -4,7 +4,7 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../strings.h"
#include "../regexp.h"
#include "../compile.h"
@@ -25,7 +25,7 @@ rule transform ( list * : pattern : indices * )
return $(result) ;
}
*/
-LIST *regex_transform( PARSE *parse, FRAME *frame )
+LIST *regex_transform( FRAME *frame, int flags )
{
LIST* l = lol_get( frame->args, 0 );
LIST* pattern = lol_get( frame->args, 1 );
@@ -33,18 +33,19 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
int* indices = 0;
int size;
int* p;
- LIST* result = 0;
+ LIST* result = L0;
string buf[1];
string_new(buf);
- if (indices_list)
+ if (!list_empty(indices_list))
{
+ LISTITER iter = list_begin(indices_list), end = list_end(indices_list);
size = list_length(indices_list);
indices = (int*)BJAM_MALLOC(size*sizeof(int));
- for(p = indices; indices_list; indices_list = indices_list->next)
+ for(p = indices; iter != end; iter = list_next(iter))
{
- *p++ = atoi(indices_list->string);
+ *p++ = atoi(object_str(list_item(iter)));
}
}
else
@@ -56,11 +57,12 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
{
/* Result is cached and intentionally never freed */
- regexp *re = regex_compile( pattern->string );
+ regexp *re = regex_compile( list_front( pattern ) );
- for(; l; l = l->next)
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for( ; iter != end; iter = list_next( iter ) )
{
- if( regexec( re, l->string ) )
+ if( regexec( re, object_str( list_item( iter ) ) ) )
{
int i = 0;
for(; i < size; ++i)
@@ -73,7 +75,7 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
if (re->startp[index] != re->endp[index])
{
string_append_range( buf, re->startp[index], re->endp[index] );
- result = list_new( result, newstr( buf->value ) );
+ result = list_push_back( result, object_new( buf->value ) );
string_truncate( buf, 0 );
}
}
@@ -90,7 +92,7 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
void init_regex()
{
{
- char* args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
+ const char* args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
declare_native_rule("regex", "transform", args, regex_transform, 2);
}
}
diff --git a/tools/build/v2/engine/modules/sequence.c b/tools/build/v2/engine/modules/sequence.c
index bda80d94c4..2b539966de 100644
--- a/tools/build/v2/engine/modules/sequence.c
+++ b/tools/build/v2/engine/modules/sequence.c
@@ -3,30 +3,35 @@
/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
#include "../native.h"
+#include "../object.h"
# ifndef max
# define max( a,b ) ((a)>(b)?(a):(b))
# endif
-LIST *sequence_select_highest_ranked( PARSE *parse, FRAME *frame )
+LIST *sequence_select_highest_ranked( FRAME *frame, int flags )
{
/* Returns all of 'elements' for which corresponding element in parallel */
/* list 'rank' is equal to the maximum value in 'rank'. */
LIST* elements = lol_get( frame->args, 0 );
LIST* rank = lol_get( frame->args, 1 );
+ LISTITER iter, end, elements_iter, elements_end;
- LIST* result = 0;
+ LIST* result = L0;
LIST* tmp;
int highest_rank = -1;
- for (tmp = rank; tmp; tmp = tmp->next)
- highest_rank = max(highest_rank, atoi(tmp->string));
-
- for (; rank; rank = rank->next, elements = elements->next)
- if (atoi(rank->string) == highest_rank)
- result = list_new(result, elements->string);
+ iter = list_begin(rank), end = list_end(rank);
+ for (; iter != end; iter = list_next(iter))
+ highest_rank = max(highest_rank, atoi(object_str(list_item(iter))));
+
+ iter = list_begin(rank), end = list_end(rank);
+ elements_iter = list_begin(elements), elements_end = list_end(elements);
+ for (; iter != end; iter = list_next(iter), elements_iter = list_next(elements_iter))
+ if (atoi(object_str(list_item(iter))) == highest_rank)
+ result = list_push_back(result, object_copy(list_item(elements_iter)));
return result;
}
@@ -34,7 +39,7 @@ LIST *sequence_select_highest_ranked( PARSE *parse, FRAME *frame )
void init_sequence()
{
{
- char* args[] = { "elements", "*", ":", "rank", "*", 0 };
+ const char* args[] = { "elements", "*", ":", "rank", "*", 0 };
declare_native_rule("sequence", "select-highest-ranked", args,
sequence_select_highest_ranked, 1);
}
diff --git a/tools/build/v2/engine/modules/set.c b/tools/build/v2/engine/modules/set.c
index f8219403c5..77a314d57d 100644
--- a/tools/build/v2/engine/modules/set.c
+++ b/tools/build/v2/engine/modules/set.c
@@ -3,6 +3,7 @@
/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
#include "../native.h"
+#include "../object.h"
/*
local result = ;
@@ -16,17 +17,18 @@
}
return $(result) ;
*/
-LIST *set_difference( PARSE *parse, FRAME *frame )
+LIST *set_difference( FRAME *frame, int flags )
{
LIST* b = lol_get( frame->args, 0 );
LIST* a = lol_get( frame->args, 1 );
- LIST* result = 0;
- for(; b; b = b->next)
+ LIST* result = L0;
+ LISTITER iter = list_begin( b ), end = list_end( b );
+ for( ; iter != end; iter = list_next( iter ) )
{
- if (!list_in(a, b->string))
- result = list_new(result, b->string);
+ if (!list_in(a, list_item(iter)))
+ result = list_push_back(result, object_copy(list_item(iter)));
}
return result;
}
@@ -34,7 +36,7 @@ LIST *set_difference( PARSE *parse, FRAME *frame )
void init_set()
{
{
- char* args[] = { "B", "*", ":", "A", "*", 0 };
+ const char* args[] = { "B", "*", ":", "A", "*", 0 };
declare_native_rule("set", "difference", args, set_difference, 1);
}
diff --git a/tools/build/v2/engine/native.c b/tools/build/v2/engine/native.c
index 4c2899595e..b1d4278313 100644
--- a/tools/build/v2/engine/native.c
+++ b/tools/build/v2/engine/native.c
@@ -4,33 +4,36 @@
#include "native.h"
#include "hash.h"
+#include "object.h"
+#include "assert.h"
-# define P0 (PARSE *)0
-# define C0 (char *)0
-
-
-void declare_native_rule(char* module, char* rule, char** args,
- LIST*(*f)(PARSE*, FRAME*), int version)
+void declare_native_rule( const char * module, const char * rule, const char * * args,
+ LIST * (*f)( FRAME *, int ), int version )
{
- module_t* m = bindmodule(module);
- if (m->native_rules == 0) {
+ OBJECT * module_obj = 0;
+ module_t * m;
+ if ( module )
+ {
+ module_obj = object_new( module );
+ }
+ m = bindmodule( module_obj );
+ if ( module_obj )
+ {
+ object_free( module_obj );
+ }
+ if (m->native_rules == 0)
+ {
m->native_rules = hashinit( sizeof( native_rule_t ), "native rules");
}
{
- native_rule_t n, *np = &n;
- n.name = rule;
- if (args)
- {
- n.arguments = args_new();
- lol_build( n.arguments->data, args );
- }
- else
- {
- n.arguments = 0;
- }
- n.procedure = parse_make( f, P0, P0, P0, C0, C0, 0 );
- n.version = version;
- hashenter(m->native_rules, (HASHDATA**)&np);
+ native_rule_t *np;
+ OBJECT * name = object_new( rule );
+ int found;
+ np = (native_rule_t *)hash_insert( m->native_rules, name, &found );
+ np->name = name;
+ assert( !found );
+ np->procedure = function_builtin( f, 0, args );
+ np->version = version;
}
}
diff --git a/tools/build/v2/engine/native.h b/tools/build/v2/engine/native.h
index 3fc710b9c6..cdd63c844b 100644
--- a/tools/build/v2/engine/native.h
+++ b/tools/build/v2/engine/native.h
@@ -5,13 +5,16 @@
#ifndef NATIVE_H_VP_2003_12_09
#define NATIVE_H_VP_2003_12_09
+#include "lists.h"
+#include "object.h"
+#include "frames.h"
+#include "function.h"
#include "rules.h"
struct native_rule_t
{
- char* name;
- argument_list* arguments;
- PARSE* procedure;
+ OBJECT * name;
+ FUNCTION * procedure;
/* Version of the interface that the native rule provides.
It's possible that we want to change the set parameter
for existing native rule. In that case, version number
@@ -26,8 +29,8 @@ struct native_rule_t
/* MSVC debugger gets confused unless this is provided */
typedef struct native_rule_t native_rule_t ;
-void declare_native_rule(char* module, char* rule, char** args,
- LIST*(*f)(PARSE*, FRAME*), int version);
+void declare_native_rule( const char * module, const char * rule, const char * * args,
+ LIST * (*f)( FRAME *, int ), int version );
diff --git a/tools/build/v2/engine/newstr.c b/tools/build/v2/engine/newstr.c
deleted file mode 100644
index 6a229eb216..0000000000
--- a/tools/build/v2/engine/newstr.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-# include "jam.h"
-# include "newstr.h"
-# include "hash.h"
-# include "compile.h"
-# include <stddef.h>
-# include <stdlib.h>
-
-/*
- * newstr.c - string manipulation routines
- *
- * To minimize string copying, string creation, copying, and freeing
- * is done through newstr.
- *
- * External functions:
- *
- * newstr() - return a dynamically allocated copy of a string
- * copystr() - return a copy of a string previously returned by newstr()
- * freestr() - free a string returned by newstr() or copystr()
- * str_done() - free string tables
- *
- * Once a string is passed to newstr(), the returned string is readonly.
- *
- * This implementation builds a hash table of all strings, so that multiple
- * calls of newstr() on the same string allocate memory for the string once.
- * Strings are never actually freed.
- */
-
-typedef char * STRING;
-
-static struct hash * strhash = 0;
-static int strtotal = 0;
-static int strcount_in = 0;
-static int strcount_out = 0;
-
-
-/*
- * Immortal string allocator implementation speeds string allocation and cuts
- * down on internal fragmentation.
- */
-
-# define STRING_BLOCK 4096
-typedef struct strblock
-{
- struct strblock * next;
- char data[STRING_BLOCK];
-} strblock;
-
-static strblock * strblock_chain = 0;
-
-/* Storage remaining in the current strblock */
-static char * storage_start = 0;
-static char * storage_finish = 0;
-
-
-/*
- * allocate() - Allocate n bytes of immortal string storage.
- */
-
-static char * allocate( size_t const n )
-{
-#ifdef BJAM_NEWSTR_NO_ALLOCATE
- return (char*)BJAM_MALLOC_ATOMIC(n);
-#else
- /* See if we can grab storage from an existing block. */
- size_t remaining = storage_finish - storage_start;
- if ( remaining >= n )
- {
- char * result = storage_start;
- storage_start += n;
- return result;
- }
- else /* Must allocate a new block. */
- {
- strblock * new_block;
- size_t nalloc = n;
- if ( nalloc < STRING_BLOCK )
- nalloc = STRING_BLOCK;
-
- /* Allocate a new block and link into the chain. */
- new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[0] ) + nalloc * sizeof( new_block->data[0] ) );
- if ( new_block == 0 )
- return 0;
- new_block->next = strblock_chain;
- strblock_chain = new_block;
-
- /* Take future allocations out of the larger remaining space. */
- if ( remaining < nalloc - n )
- {
- storage_start = new_block->data + n;
- storage_finish = new_block->data + nalloc;
- }
- return new_block->data;
- }
-#endif
-}
-
-
-/*
- * newstr() - return a dynamically allocated copy of a string.
- */
-
-char * newstr( char * string )
-{
- STRING str;
- STRING * s = &str;
-
- if ( !strhash )
- strhash = hashinit( sizeof( STRING ), "strings" );
-
- *s = string;
-
- if ( hashenter( strhash, (HASHDATA **)&s ) )
- {
- int l = strlen( string );
- char * m = (char *)allocate( l + 1 );
-
- strtotal += l + 1;
- memcpy( m, string, l + 1 );
- *s = m;
- }
-
- strcount_in += 1;
- return *s;
-}
-
-
-/*
- * copystr() - return a copy of a string previously returned by newstr()
- */
-
-char * copystr( char * s )
-{
- strcount_in += 1;
- return s;
-}
-
-
-/*
- * freestr() - free a string returned by newstr() or copystr()
- */
-
-void freestr( char * s )
-{
- strcount_out += 1;
-}
-
-
-/*
- * str_done() - free string tables.
- */
-
-void str_done()
-{
- /* Reclaim string blocks. */
- while ( strblock_chain != 0 )
- {
- strblock * n = strblock_chain->next;
- BJAM_FREE(strblock_chain);
- strblock_chain = n;
- }
-
- hashdone( strhash );
-
- if ( DEBUG_MEM )
- printf( "%dK in strings\n", strtotal / 1024 );
-
- /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
-}
diff --git a/tools/build/v2/engine/newstr.h b/tools/build/v2/engine/newstr.h
deleted file mode 100644
index 84a4d7b6da..0000000000
--- a/tools/build/v2/engine/newstr.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/*
- * newstr.h - string manipulation routines
- */
-
-char * copystr ( char * );
-void freestr ( char * );
-char * newstr ( char * );
-void str_done();
diff --git a/tools/build/v2/engine/object.c b/tools/build/v2/engine/object.c
new file mode 100644
index 0000000000..399f04ae84
--- /dev/null
+++ b/tools/build/v2/engine/object.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "jam.h"
+# include "object.h"
+# include <stddef.h>
+# include <stdlib.h>
+# include <assert.h>
+
+/*
+ * object.c - object manipulation routines
+ *
+ * External functions:
+ *
+ * object_new() - create an object from a string
+ * object_copy() - return a copy of an object
+ * object_free() - free an object
+ * object_str() - get the string value of an object
+ * object_done() - free string tables
+ *
+ * This implementation builds a hash table of all strings, so that multiple
+ * calls of object_new() on the same string allocate memory for the string once.
+ * Strings are never actually freed.
+ */
+
+#define OBJECT_MAGIC 0xa762e0e3u
+
+#ifndef object_copy
+
+struct hash_header
+{
+#ifndef NDEBUG
+ unsigned int magic;
+#endif
+ unsigned int hash;
+ struct hash_item * next;
+};
+
+#endif
+
+struct hash_item
+{
+ struct hash_header header;
+ char data[1];
+};
+
+#define ALLOC_ALIGNMENT ( sizeof( struct hash_item ) - sizeof( struct hash_header ) )
+
+typedef struct string_set
+{
+ unsigned int num;
+ unsigned int size;
+ struct hash_item * * data;
+} string_set;
+
+static string_set strhash;
+static int strtotal = 0;
+static int strcount_in = 0;
+static int strcount_out = 0;
+
+
+/*
+ * Immortal string allocator implementation speeds string allocation and cuts
+ * down on internal fragmentation.
+ */
+
+# define STRING_BLOCK 4096
+typedef struct strblock
+{
+ struct strblock * next;
+ char data[STRING_BLOCK];
+} strblock;
+
+static strblock * strblock_chain = 0;
+
+/* Storage remaining in the current strblock */
+static char * storage_start = 0;
+static char * storage_finish = 0;
+
+
+/*
+ * allocate() - Allocate n bytes of immortal string storage.
+ */
+
+static char * allocate( size_t n )
+{
+#ifdef BJAM_NEWSTR_NO_ALLOCATE
+ return (char*)BJAM_MALLOC(n);
+#else
+ /* See if we can grab storage from an existing block. */
+ size_t remaining = storage_finish - storage_start;
+ n = ((n + ALLOC_ALIGNMENT - 1) / ALLOC_ALIGNMENT) * ALLOC_ALIGNMENT;
+ if ( remaining >= n )
+ {
+ char * result = storage_start;
+ storage_start += n;
+ return result;
+ }
+ else /* Must allocate a new block. */
+ {
+ strblock * new_block;
+ size_t nalloc = n;
+ if ( nalloc < STRING_BLOCK )
+ nalloc = STRING_BLOCK;
+
+ /* Allocate a new block and link into the chain. */
+ new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[0] ) + nalloc * sizeof( new_block->data[0] ) );
+ if ( new_block == 0 )
+ return 0;
+ new_block->next = strblock_chain;
+ strblock_chain = new_block;
+
+ /* Take future allocations out of the larger remaining space. */
+ if ( remaining < nalloc - n )
+ {
+ storage_start = new_block->data + n;
+ storage_finish = new_block->data + nalloc;
+ }
+ return new_block->data;
+ }
+#endif
+}
+
+static unsigned int hash_keyval( const char * key )
+{
+ unsigned int hash = 0;
+ unsigned i;
+ unsigned int len = strlen( key );
+
+ for ( i = 0; i < len / sizeof( unsigned int ); ++i )
+ {
+ unsigned int val;
+ memcpy( &val, key, sizeof( unsigned int ) );
+ hash = hash * 2147059363 + val;
+ key += sizeof( unsigned int );
+ }
+
+ {
+ unsigned int val = 0;
+ memcpy( &val, key, len % sizeof( unsigned int ) );
+ hash = hash * 2147059363 + val;
+ }
+
+ hash += (hash >> 17);
+
+ return hash;
+}
+
+static void string_set_init(string_set * set)
+{
+ set->size = 0;
+ set->num = 4;
+ set->data = (struct hash_item * *)BJAM_MALLOC( set->num * sizeof( struct hash_item * ) );
+ memset( set->data, 0, set->num * sizeof( struct hash_item * ) );
+}
+
+static void string_set_done(string_set * set)
+{
+ BJAM_FREE( set->data );
+}
+
+static void string_set_resize(string_set *set)
+{
+ unsigned i;
+ string_set new_set;
+ new_set.num = set->num * 2;
+ new_set.size = set->size;
+ new_set.data = (struct hash_item * *)BJAM_MALLOC( sizeof( struct hash_item * ) * new_set.num );
+ memset(new_set.data, 0, sizeof(struct hash_item *) * new_set.num);
+ for ( i = 0; i < set->num; ++i )
+ {
+ while ( set->data[i] )
+ {
+ struct hash_item * temp = set->data[i];
+ unsigned pos = temp->header.hash % new_set.num;
+ set->data[i] = temp->header.next;
+ temp->header.next = new_set.data[pos];
+ new_set.data[pos] = temp;
+ }
+ }
+ BJAM_FREE( set->data );
+ *set = new_set;
+}
+
+static const char * string_set_insert ( string_set * set, const char * string )
+{
+ unsigned hash = hash_keyval( string );
+ unsigned pos = hash % set->num;
+ unsigned l;
+
+ struct hash_item * result;
+
+ for ( result = set->data[pos]; result; result = result->header.next )
+ {
+ if ( strcmp( result->data, string ) == 0 )
+ {
+ return result->data;
+ }
+ }
+
+ if( set->size >= set->num )
+ {
+ string_set_resize( set );
+ pos = hash % set->num;
+ }
+
+ l = strlen( string );
+ result = (struct hash_item *)allocate( sizeof( struct hash_header ) + l + 1 );
+ result->header.hash = hash;
+ result->header.next = set->data[pos];
+#ifndef NDEBUG
+ result->header.magic = OBJECT_MAGIC;
+#endif
+ memcpy( result->data, string, l + 1 );
+ assert( hash_keyval( result->data ) == result->header.hash );
+ set->data[pos] = result;
+ strtotal += l + 1;
+ ++set->size;
+
+ return result->data;
+}
+
+
+static struct hash_item * object_get_item( OBJECT * obj )
+{
+ return (struct hash_item *)( (char *)obj - offsetof( struct hash_item, data ) );
+}
+
+
+static void object_validate( OBJECT * obj )
+{
+ assert( object_get_item( obj )->header.magic == OBJECT_MAGIC );
+}
+
+
+/*
+ * object_new() - create an object from a string.
+ */
+
+OBJECT * object_new( const char * string )
+{
+#ifdef BJAM_NO_MEM_CACHE
+ int l = strlen( string );
+ struct hash_item * m = (struct hash_item *)BJAM_MALLOC( sizeof(struct hash_header) + l + 1 );
+
+ strtotal += l + 1;
+ memcpy( m->data, string, l + 1 );
+ m->header.magic = OBJECT_MAGIC;
+ return (OBJECT *)m->data;
+#else
+ if ( ! strhash.data )
+ string_set_init( &strhash );
+
+ strcount_in += 1;
+
+ return (OBJECT *)string_set_insert( &strhash, string );
+#endif
+}
+
+#ifndef object_copy
+
+/*
+ * object_copy() - return a copy of an object
+ */
+
+OBJECT * object_copy( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ return object_new( object_str( obj ) );
+#else
+ strcount_in += 1;
+ return obj;
+#endif
+}
+
+
+/*
+ * object_free() - free an object
+ */
+
+void object_free( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ BJAM_FREE( object_get_item( obj ) );
+#endif
+ strcount_out += 1;
+}
+
+
+/*
+ * object_str() - return the
+ */
+
+const char * object_str( OBJECT * obj )
+{
+ object_validate( obj );
+ return (const char *)obj;
+}
+
+
+/*
+ * object_equal() - compare two objects
+ */
+
+int object_equal( OBJECT * lhs, OBJECT * rhs )
+{
+ object_validate( lhs );
+ object_validate( rhs );
+#ifdef BJAM_NO_MEM_CACHE
+ return strcmp(object_str(lhs), object_str(rhs)) == 0;
+#else
+ assert( (lhs == rhs) == ( strcmp(object_str(lhs), object_str(rhs)) == 0 ) );
+ return lhs == rhs;
+#endif
+}
+
+
+/*
+ * object_hash() - returns the hash value of an object
+ */
+
+unsigned int object_hash( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ return hash_keyval( object_str( obj ) );
+#else
+ return object_get_item( obj )->header.hash;
+#endif
+}
+
+#endif
+
+/*
+ * object_done() - free string tables.
+ */
+
+void object_done()
+{
+
+#ifdef BJAM_NEWSTR_NO_ALLOCATE
+
+ unsigned i;
+
+ for ( i = 0; i < strhash.num; ++i )
+ {
+ while ( strhash.data[i] )
+ {
+ struct hash_item * item = strhash.data[i];
+ strhash.data[i] = item->header.next;
+ BJAM_FREE( item );
+ }
+ }
+
+#else
+
+ /* Reclaim string blocks. */
+ while ( strblock_chain != 0 )
+ {
+ strblock * n = strblock_chain->next;
+ BJAM_FREE(strblock_chain);
+ strblock_chain = n;
+ }
+
+#endif
+
+ string_set_done( &strhash );
+
+ if ( DEBUG_MEM )
+ printf( "%dK in strings\n", strtotal / 1024 );
+
+ /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
+}
diff --git a/tools/build/v2/engine/object.h b/tools/build/v2/engine/object.h
new file mode 100644
index 0000000000..1c123f8b0f
--- /dev/null
+++ b/tools/build/v2/engine/object.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * object.h - object manipulation routines
+ */
+
+#ifndef BOOST_JAM_OBJECT_H
+#define BOOST_JAM_OBJECT_H
+
+typedef struct _object OBJECT;
+
+OBJECT * object_new ( const char * );
+void object_done ( void );
+
+#if defined(NDEBUG) && !defined(BJAM_NO_MEM_CACHE)
+
+struct hash_header
+{
+ unsigned int hash;
+ struct hash_item * next;
+};
+
+#define object_str( obj ) ( (const char *)( obj ) )
+#define object_copy( obj ) ( obj )
+#define object_free( obj ) ( (void)0 )
+#define object_equal( lhs, rhs ) ( ( lhs ) == ( rhs ) )
+#define object_hash( obj ) ( ((struct hash_header *)( (char *)( obj ) - sizeof(struct hash_header) ))->hash )
+
+#else
+
+const char * object_str ( OBJECT * );
+OBJECT * object_copy ( OBJECT * );
+void object_free ( OBJECT * );
+int object_equal ( OBJECT *, OBJECT * );
+unsigned int object_hash ( OBJECT * );
+
+#endif
+
+#endif
diff --git a/tools/build/v2/engine/output.c b/tools/build/v2/engine/output.c
index 483c6ca9e6..a0154c6ea3 100644
--- a/tools/build/v2/engine/output.c
+++ b/tools/build/v2/engine/output.c
@@ -6,7 +6,7 @@
#include "jam.h"
#include "output.h"
-#include "newstr.h"
+#include "object.h"
#include <stdio.h>
#define bjam_out (stdout)
@@ -101,25 +101,25 @@ void out_action
}
-char * outf_int( int value )
+OBJECT * outf_int( int value )
{
char buffer[50];
sprintf( buffer, "%i", value );
- return newstr( buffer );
+ return object_new( buffer );
}
-char * outf_double( double value )
+OBJECT * outf_double( double value )
{
char buffer[50];
sprintf( buffer, "%f", value );
- return newstr( buffer );
+ return object_new( buffer );
}
-char * outf_time( time_t value )
+OBJECT * outf_time( time_t value )
{
char buffer[50];
strftime( buffer, 49, "%Y-%m-%d %H:%M:%SZ", gmtime( &value ) );
- return newstr( buffer );
+ return object_new( buffer );
}
diff --git a/tools/build/v2/engine/output.h b/tools/build/v2/engine/output.h
index 9e9876cfc5..64175e67ef 100644
--- a/tools/build/v2/engine/output.h
+++ b/tools/build/v2/engine/output.h
@@ -7,6 +7,7 @@
#ifndef BJAM_OUTPUT_H
#define BJAM_OUTPUT_H
+#include "object.h"
#include <time.h>
#define EXIT_OK 0
@@ -22,8 +23,8 @@ void out_action(
int exit_reason
);
-char * outf_int( int value );
-char * outf_double( double value );
-char * outf_time( time_t value );
+OBJECT * outf_int( int value );
+OBJECT * outf_double( double value );
+OBJECT * outf_time( time_t value );
#endif
diff --git a/tools/build/v2/engine/parse.c b/tools/build/v2/engine/parse.c
index 9114fa057a..167ad1745a 100644
--- a/tools/build/v2/engine/parse.c
+++ b/tools/build/v2/engine/parse.c
@@ -14,9 +14,10 @@
#include "lists.h"
#include "parse.h"
#include "scan.h"
-#include "newstr.h"
+#include "object.h"
#include "modules.h"
#include "frames.h"
+#include "function.h"
/*
* parse.c - make and destroy parse trees as driven by the parser
@@ -29,7 +30,7 @@
static PARSE * yypsave;
-void parse_file( char * f, FRAME * frame )
+void parse_file( OBJECT * f, FRAME * frame )
{
/* Suspend scan of current file and push this new file in the stream. */
yyfparse( f );
@@ -41,6 +42,7 @@ void parse_file( char * f, FRAME * frame )
for ( ; ; )
{
PARSE * p;
+ FUNCTION * func;
/* Filled by yyparse() calling parse_save(). */
yypsave = 0;
@@ -50,8 +52,10 @@ void parse_file( char * f, FRAME * frame )
break;
/* Run the parse tree. */
- parse_evaluate( p, frame );
+ func = function_compile( p );
parse_free( p );
+ list_free( function_run( func, frame, stack_global() ) );
+ function_free( func );
}
}
@@ -63,17 +67,17 @@ void parse_save( PARSE * p )
PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
- PARSE * left,
- PARSE * right,
- PARSE * third,
- char * string,
- char * string1,
- int num )
+ int type,
+ PARSE * left,
+ PARSE * right,
+ PARSE * third,
+ OBJECT * string,
+ OBJECT * string1,
+ int num )
{
PARSE * p = (PARSE *)BJAM_MALLOC( sizeof( PARSE ) );
- p->func = func;
+ p->type = type;
p->left = left;
p->right = right;
p->third = third;
@@ -85,12 +89,13 @@ PARSE * parse_make(
if ( left )
{
- p->file = left->file;
+ p->file = object_copy( left->file );
p->line = left->line;
}
else
{
yyinput_stream( &p->file, &p->line );
+ p->file = object_copy( p->file );
}
return p;
@@ -109,9 +114,9 @@ void parse_free( PARSE * p )
return;
if ( p->string )
- freestr( p->string );
+ object_free( p->string );
if ( p->string1 )
- freestr( p->string1 );
+ object_free( p->string1 );
if ( p->left )
parse_free( p->left );
if ( p->right )
@@ -119,14 +124,9 @@ void parse_free( PARSE * p )
if ( p->third )
parse_free( p->third );
if ( p->rulename )
- freestr( p->rulename );
+ object_free( p->rulename );
+ if ( p->file )
+ object_free( p->file );
BJAM_FREE( (char *)p );
}
-
-
-LIST * parse_evaluate( PARSE * p, FRAME * frame )
-{
- frame->procedure = p;
- return (*p->func)( p, frame );
-}
diff --git a/tools/build/v2/engine/parse.h b/tools/build/v2/engine/parse.h
index e324972f7b..882a029f42 100644
--- a/tools/build/v2/engine/parse.h
+++ b/tools/build/v2/engine/parse.h
@@ -21,36 +21,55 @@
* parse.h - make and destroy parse trees as driven by the parser.
*/
+#define PARSE_APPEND 0
+#define PARSE_FOREACH 1
+#define PARSE_IF 2
+#define PARSE_EVAL 3
+#define PARSE_INCLUDE 4
+#define PARSE_LIST 5
+#define PARSE_LOCAL 6
+#define PARSE_MODULE 7
+#define PARSE_CLASS 8
+#define PARSE_NULL 9
+#define PARSE_ON 10
+#define PARSE_RULE 11
+#define PARSE_RULES 12
+#define PARSE_SET 13
+#define PARSE_SETCOMP 14
+#define PARSE_SETEXEC 15
+#define PARSE_SETTINGS 16
+#define PARSE_SWITCH 17
+#define PARSE_WHILE 18
+
/*
* Parse tree node.
*/
struct _PARSE {
- LIST * (* func)( PARSE *, FRAME * );
+ int type;
PARSE * left;
PARSE * right;
PARSE * third;
- char * string;
- char * string1;
+ OBJECT * string;
+ OBJECT * string1;
int num;
int refs;
-/* module * module; */
- char * rulename;
- char * file;
+ OBJECT * rulename;
+ OBJECT * file;
int line;
};
-void parse_file( char *, FRAME * );
+void parse_file( OBJECT *, FRAME * );
void parse_save( PARSE * );
PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
- PARSE * left,
- PARSE * right,
- PARSE * third,
- char * string,
- char * string1,
- int num );
+ int type,
+ PARSE * left,
+ PARSE * right,
+ PARSE * third,
+ OBJECT * string,
+ OBJECT * string1,
+ int num );
void parse_refer ( PARSE * );
void parse_free ( PARSE * );
diff --git a/tools/build/v2/engine/patchlevel.h b/tools/build/v2/engine/patchlevel.h
index 699efd84ba..18224c1c31 100644
--- a/tools/build/v2/engine/patchlevel.h
+++ b/tools/build/v2/engine/patchlevel.h
@@ -8,10 +8,10 @@
/* It can be accessed as $(JAMVERSION) in the Jamfile. */
#define VERSION_MAJOR 2011
-#define VERSION_MINOR 04
+#define VERSION_MINOR 12
#define VERSION_PATCH 0
#define VERSION_MAJOR_SYM "2011"
-#define VERSION_MINOR_SYM "04"
+#define VERSION_MINOR_SYM "12"
#define VERSION_PATCH_SYM "00"
-#define VERSION "2011.4"
-#define JAMVERSYM "JAMVERSION=2011.4"
+#define VERSION "2011.12"
+#define JAMVERSYM "JAMVERSION=2011.12"
diff --git a/tools/build/v2/engine/pathmac.c b/tools/build/v2/engine/pathmac.c
deleted file mode 100644
index e2c250e338..0000000000
--- a/tools/build/v2/engine/pathmac.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "pathsys.h"
-
-# ifdef OS_MAC
-
-# define DELIM ':'
-
-/*
- * pathunix.c - manipulate file names on UNIX, NT, OS2
- *
- * External routines:
- *
- * path_parse() - split a file name into dir/base/suffix/member
- * path_build() - build a filename given dir/base/suffix/member
- * path_parent() - make a PATHNAME point to its parent dir
- *
- * File_parse() and path_build() just manipuate a string and a structure;
- * they do not make system calls.
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
- * 12/19/94 (mikem) - solaris string table insanity support
- * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
- * 02/14/95 (seiwald) - parse and build /xxx properly
- * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
- * should expect hdr searches to come up with strings
- * like "thing/thing.h". So we need to test for "/" as
- * well as "\" when parsing pathnames.
- * 03/16/95 (seiwald) - fixed accursed typo on line 69.
- * 05/03/96 (seiwald) - split from filent.c, fileunix.c
- * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
- * don't include the archive member name.
- * 01/10/01 (seiwald) - path_parse now strips the trailing : from the
- * directory name, unless the directory name is all
- * :'s, so that $(d:P) works.
- */
-
-/*
- * path_parse() - split a file name into dir/base/suffix/member
- */
-
-void
-path_parse(
- char *file,
- PATHNAME *f )
-{
- char *p, *q;
- char *end;
-
- memset( (char *)f, 0, sizeof( *f ) );
-
- /* Look for <grist> */
-
- if ( file[0] == '<' && ( p = strchr( file, '>' ) ) )
- {
- f->f_grist.ptr = file;
- f->f_grist.len = p - file;
- file = p + 1;
- }
-
- /* Look for dir: */
-
- if ( p = strrchr( file, DELIM ) )
- {
- f->f_dir.ptr = file;
- f->f_dir.len = p - file;
- file = p + 1;
-
- /* All :'s? Include last : as part of directory name */
-
- while ( ( p > f->f_dir.ptr ) && ( *--p == DELIM ) );
-
- if ( p == f->f_dir.ptr )
- ++f->f_dir.len;
- }
-
- end = file + strlen( file );
-
- /* Look for (member). */
-
- if ( ( p = strchr( file, '(' ) ) && ( end[-1] == ')' ) )
- {
- f->f_member.ptr = p + 1;
- f->f_member.len = end - p - 2;
- end = p;
- }
-
- /* Look for .suffix */
- /* This would be memrchr() */
-
- p = 0;
- q = file;
-
- while ( q = memchr( q, '.', end - q ) )
- p = q++;
-
- if ( p )
- {
- f->f_suffix.ptr = p;
- f->f_suffix.len = end - p;
- end = p;
- }
-
- /* Leaves base */
-
- f->f_base.ptr = file;
- f->f_base.len = end - file;
-}
-
-/*
- * path_build() - build a filename given dir/base/suffix/member.
- */
-
-# define DIR_EMPTY 0 /* "" */
-# define DIR_DOT 1 /* : */
-# define DIR_DOTDOT 2 /* :: */
-# define DIR_ABS 3 /* dira:dirb: */
-# define DIR_REL 4 /* :dira:dirb: */
-
-# define G_DIR 0 /* take dir */
-# define G_ROOT 1 /* take root */
-# define G_CAT 2 /* prepend root to dir */
-# define G_DTDR 3 /* :: of rel dir */
-# define G_DDDD 4 /* make it ::: (../..) */
-# define G_MT 5 /* leave it empty */
-
-char grid[5][5] = {
-/* EMPTY DOT DOTDOT ABS REL */
-/* EMPTY */ { G_MT, G_DIR, G_DIR, G_DIR, G_DIR },
-/* DOT */ { G_ROOT, G_DIR, G_DIR, G_DIR, G_DIR },
-/* DOTDOT */ { G_ROOT, G_ROOT, G_DDDD, G_DIR, G_DTDR },
-/* ABS */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT },
-/* REL */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT }
-};
-
-static int file_flags( char * ptr, int len )
-{
- if ( !len )
- return DIR_EMPTY;
- if ( ( len == 1 ) && ( ptr[0] == DELIM ) )
- return DIR_DOT;
- if ( ( len == 2 ) && ( ptr[0] == DELIM ) && ( ptr[1] == DELIM ) )
- return DIR_DOTDOT;
- if ( ptr[0] == DELIM )
- return DIR_REL;
- return DIR_ABS;
-}
-
-
-void path_build( PATHNAME * f, string * file, int binding )
-{
- int dflag;
- int rflag;
- int act;
-
- file_build1( f, file );
-
- /* Combine root & directory, according to the grid. */
-
- dflag = file_flags( f->f_dir.ptr, f->f_dir.len );
- rflag = file_flags( f->f_root.ptr, f->f_root.len );
-
- switch ( act = grid[ rflag ][ dflag ] )
- {
- case G_DTDR:
- {
- /* :: of rel dir */
- string_push_back( file, DELIM );
- }
- /* fall through */
-
- case G_DIR:
- /* take dir */
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_ROOT:
- /* take root */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- break;
-
- case G_CAT:
- /* prepend root to dir */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- if ( file->value[ file->size - 1 ] == DELIM )
- string_pop_back( file );
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_DDDD:
- /* make it ::: (../..) */
- string_append( file, ":::" );
- break;
- }
-
- /* Put : between dir and file (if none already). */
-
- if ( ( act != G_MT ) &&
- ( file->value[ file->size - 1 ] != DELIM ) &&
- ( f->f_base.len || f->f_suffix.len ) )
- {
- string_push_back( file, DELIM );
- }
-
- if ( f->f_base.len )
- string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
-
- if ( f->f_suffix.len )
- string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
-
- if ( f->f_member.len )
- {
- string_push_back( file, '(' );
- string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
- string_push_back( file, ')' );
- }
-
- if ( DEBUG_SEARCH )
- printf( " -> '%s'\n", file->value );
-}
-
-
-/*
- * path_parent() - make a PATHNAME point to its parent dir
- */
-
-void path_parent( PATHNAME * f )
-{
- /* Just set everything else to nothing. */
-
- f->f_base.ptr =
- f->f_suffix.ptr =
- f->f_member.ptr = "";
-
- f->f_base.len =
- f->f_suffix.len =
- f->f_member.len = 0;
-}
-
-# endif /* OS_MAC */
diff --git a/tools/build/v2/engine/pathsys.h b/tools/build/v2/engine/pathsys.h
index 737758105f..978dbf4a7a 100644
--- a/tools/build/v2/engine/pathsys.h
+++ b/tools/build/v2/engine/pathsys.h
@@ -15,31 +15,27 @@
* have the same name: it never appears in the bound name of a target.
* (member) is an archive member name: the syntax is arbitrary, but must
* agree in path_parse(), path_build() and the Jambase.
- *
- * On VMS, we keep track of whether the original path was a directory
- * (without a file), so that $(VAR:D) can climb to the parent.
*/
#ifndef PATHSYS_VP_20020211_H
# define PATHSYS_VP_20020211_H
+#include "jam.h"
#include "strings.h"
+#include "object.h"
typedef struct _pathname PATHNAME;
typedef struct _pathpart PATHPART;
struct _pathpart
{
- char * ptr;
- int len;
+ const char * ptr;
+ int len;
};
struct _pathname
{
PATHPART part[6];
-#ifdef OS_VMS
- int parent;
-#endif
#define f_grist part[0]
#define f_root part[1]
@@ -52,18 +48,26 @@ struct _pathname
void path_build( PATHNAME * f, string * file, int binding );
void path_build1( PATHNAME * f, string * file );
-void path_parse( char * file, PATHNAME * f );
+void path_parse( const char * file, PATHNAME * f );
void path_parent( PATHNAME * f );
#ifdef NT
-/** Returns newstr-allocated string with long equivivalent of 'short_name'.
+/** Returns object_new-allocated string with long equivivalent of 'short_name'.
If none exists -- i.e. 'short_path' is already long path, it's returned
unaltered. */
-char * short_path_to_long_path( char * short_path );
+OBJECT * short_path_to_long_path( OBJECT * short_path );
#endif
+/** Given a path, returns an object that can be
+ used as a unique key for that path. Equivalent
+ paths such as a/b, A\B, and a\B on NT all yield the
+ same key.
+ */
+OBJECT * path_as_key( OBJECT * path );
+void path_add_key( OBJECT * path );
+
#ifdef USE_PATHUNIX
/** Returns a static pointer to the system dependent path to the temporary
directory. NOTE: *without* a trailing path separator.
@@ -72,11 +76,11 @@ const char * path_tmpdir( void );
/** Returns a new temporary name.
*/
-const char * path_tmpnam( void );
+OBJECT * path_tmpnam( void );
/** Returns a new temporary path.
*/
-const char * path_tmpfile( void );
+OBJECT * path_tmpfile( void );
#endif
/** Give the first argument to 'main', return a full path to
@@ -86,6 +90,8 @@ const char * path_tmpfile( void );
Implemented in jam.c
*/
-char * executable_path (char *argv0);
+char * executable_path (const char *argv0);
+
+void path_done( void );
#endif
diff --git a/tools/build/v2/engine/pathunix.c b/tools/build/v2/engine/pathunix.c
index 2daad14b72..a8428df8d6 100644
--- a/tools/build/v2/engine/pathunix.c
+++ b/tools/build/v2/engine/pathunix.c
@@ -14,10 +14,11 @@
# include "jam.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# include "filesys.h"
# include <time.h>
# include <stdlib.h>
+# include <assert.h>
# ifndef OS_NT
# include <unistd.h>
# endif
@@ -56,11 +57,11 @@
* path_parse() - split a file name into dir/base/suffix/member
*/
-void path_parse( char * file, PATHNAME * f )
+void path_parse( const char * file, PATHNAME * f )
{
- char * p;
- char * q;
- char * end;
+ const char * p;
+ const char * q;
+ const char * end;
memset( (char *)f, 0, sizeof( *f ) );
@@ -273,124 +274,250 @@ path_parent( PATHNAME *f )
#ifdef NT
#include <windows.h>
-#include <tchar.h>
/* The definition of this in winnt.h is not ANSI-C compatible. */
#undef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+OBJECT * path_as_key( OBJECT * path );
+static void path_write_key( char * path_, string * out );
-DWORD ShortPathToLongPath(LPCTSTR lpszShortPath,LPTSTR lpszLongPath,DWORD
- cchBuffer)
+void ShortPathToLongPath( char * short_path, string * out )
{
- LONG i=0;
- TCHAR path[_MAX_PATH]={0};
- TCHAR ret[_MAX_PATH]={0};
- LONG pos=0, prev_pos=0;
- LONG len=_tcslen(lpszShortPath);
-
- /* Is the string valid? */
- if (!lpszShortPath) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
+ const char * new_element;
+ unsigned long saved_size;
+ char * p;
+
+ if ( short_path[0] == '\0' )
+ {
+ return;
+ }
+
+ if ( short_path[0] == '\\' && short_path[1] == '\0')
+ {
+ string_push_back( out, '\\' );
+ return;
+ }
+
+ if ( short_path[1] == ':' &&
+ ( short_path[2] == '\0' ||
+ ( short_path[2] == '\\' && short_path[3] == '\0' ) ) )
+ {
+ string_push_back( out, toupper( short_path[0] ) );
+ string_push_back( out, ':' );
+ string_push_back( out, '\\' );
+ return;
+ }
+
+ /* '/' already handled. */
+ if ( ( p = strrchr( short_path, '\\' ) ) )
+ {
+ char saved;
+ new_element = p + 1;
+
+ /* special case \ */
+ if ( p == short_path )
+ ++p;
+
+ /* special case D:\ */
+ if ( p == short_path + 2 && short_path[1] == ':' )
+ ++p;
+
+ saved = *p;
+ *p = '\0';
+ path_write_key( short_path, out );
+ *p = saved;
+ }
+ else
+ {
+ new_element = short_path;
+ }
+
+ if ( out->size && out->value[ out->size - 1 ] != '\\' )
+ {
+ string_push_back( out, '\\' );
+ }
+
+ saved_size = out->size;
+ string_append( out, new_element );
+
+ if ( ! ( new_element[0] == '.' && new_element[1] == '\0' ||
+ new_element[0] == '.' && new_element[1] == '.'
+ && new_element[2] == '\0' ) )
+ {
+ WIN32_FIND_DATA fd;
+ HANDLE hf = 0;
+ hf = FindFirstFile( out->value, &fd );
+
+ /* If the file exists, replace the name. */
+ if ( hf != INVALID_HANDLE_VALUE )
+ {
+ string_truncate( out, saved_size );
+ string_append( out, fd.cFileName );
+ FindClose( hf );
+ }
}
+}
- /* Is the path valid? */
- if (GetFileAttributes(lpszShortPath)==INVALID_FILE_ATTRIBUTES)
- return 0;
+OBJECT * short_path_to_long_path( OBJECT * short_path )
+{
+ return path_as_key( short_path );
+}
- /* Convert "/" to "\" */
- for (i=0;i<len;++i) {
- if (lpszShortPath[i]==_T('/'))
- path[i]=_T('\\');
+struct path_key_entry
+{
+ OBJECT * path;
+ OBJECT * key;
+};
+
+static struct hash * path_key_cache;
+
+static void path_write_key( char * path_, string * out )
+{
+ struct path_key_entry * result;
+ OBJECT * path = object_new( path_ );
+ int found;
+
+ /* This is only called by path_as_key, which initializes the cache. */
+ assert( path_key_cache );
+
+ result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+ if ( !found )
+ {
+ /* path_ is already normalized. */
+ result->path = path;
+ ShortPathToLongPath( path_, out );
+ result->key = object_new( out->value );
+ }
+ else
+ {
+ object_free( path );
+ string_append( out, object_str( result->key ) );
+ }
+
+}
+
+static void normalize_path( string * path )
+{
+ char * s;
+ for ( s = path->value; s < path->value + path->size; ++s )
+ {
+ if ( *s == '/' )
+ *s = '\\';
else
- path[i]=lpszShortPath[i];
+ *s = tolower( *s );
+ }
+ /* Strip trailing "/" */
+ if ( path->size != 0 && path->size != 3 && path->value[ path->size - 1 ] == '\\' )
+ {
+ string_pop_back( path );
}
+}
- /* UNC path? */
- if (path[0]==_T('\\') && path[1]==_T('\\')) {
- pos=2;
- for (i=0;i<2;++i) {
- while (path[pos]!=_T('\\') && path[pos]!=_T('\0'))
- ++pos;
- ++pos;
+void path_add_key( OBJECT * path )
+{
+ struct path_key_entry * result;
+ int found;
+
+ if ( ! path_key_cache )
+ path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
+
+ result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+ if ( !found )
+ {
+ string buf[1];
+ OBJECT * normalized;
+ struct path_key_entry * nresult;
+ result->path = path;
+ string_copy( buf, object_str( path ) );
+ normalize_path( buf );
+ normalized = object_new( buf->value );
+ string_free( buf );
+ nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
+ if ( !found || nresult == result )
+ {
+ nresult->path = object_copy( normalized );
+ nresult->key = object_copy( path );
}
- _tcsncpy(ret,path,pos-1);
- } /* Drive letter? */
- else if (path[1]==_T(':')) {
- if (path[2]==_T('\\'))
- pos=3;
- if (len==3) {
- if (cchBuffer>3)
- _tcscpy(lpszLongPath,lpszShortPath);
- return len;
+ object_free( normalized );
+ if ( nresult != result )
+ {
+ result->path = object_copy( path );
+ result->key = object_copy( nresult->key );
}
- _tcsncpy(ret,path,2);
}
+}
+
+OBJECT * path_as_key( OBJECT * path )
+{
+ struct path_key_entry * result;
+ int found;
+
+ if ( ! path_key_cache )
+ path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
- /* Expand the path for each subpath, and strip trailing backslashes */
- for (prev_pos = pos-1;pos<=len;++pos) {
- if (path[pos]==_T('\\') || (path[pos]==_T('\0') &&
- path[pos-1]!=_T('\\'))) {
- WIN32_FIND_DATA fd;
- HANDLE hf=0;
- TCHAR c=path[pos];
- char* new_element;
- path[pos]=_T('\0');
-
- /* the path[prev_pos+1]... path[pos] range is the part of
- path we're handling right now. We need to find long
- name for that element and add it. */
- new_element = path + prev_pos + 1;
-
- /* First add separator, but only if there's something in result already. */
- if (ret[0] != _T('\0'))
- {
- _tcscat(ret,_T("\\"));
- }
-
- /* If it's ".." element, we need to append it, not
- the name in parent that FindFirstFile will return.
- Same goes for "." */
-
- if (new_element[0] == _T('.') && new_element[1] == _T('\0') ||
- new_element[0] == _T('.') && new_element[1] == _T('.')
- && new_element[2] == _T('\0'))
- {
- _tcscat(ret, new_element);
- }
- else
- {
- hf=FindFirstFile(path, &fd);
- if (hf==INVALID_HANDLE_VALUE)
- return 0;
-
- _tcscat(ret,fd.cFileName);
- FindClose(hf);
- }
-
- path[pos]=c;
-
- prev_pos = pos;
+ result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+ if ( !found )
+ {
+ string buf[1];
+ OBJECT * normalized;
+ struct path_key_entry * nresult;
+ result->path = path;
+ string_copy( buf, object_str( path ) );
+ normalize_path( buf );
+ normalized = object_new( buf->value );
+ nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
+ if ( !found || nresult == result )
+ {
+ string long_path[1];
+ nresult->path = normalized;
+ string_new( long_path );
+ ShortPathToLongPath( buf->value, long_path );
+ nresult->path = object_copy( normalized );
+ nresult->key = object_new( long_path->value );
+ string_free( long_path );
}
+ string_free( buf );
+ object_free( normalized );
+ if ( nresult != result )
+ {
+ result->path = object_copy( path );
+ result->key = object_copy( nresult->key );
+ }
+ }
+
+ return object_copy( result->key );
+}
+
+static void free_path_key_entry( void * xentry, void * data )
+{
+ struct path_key_entry * entry = (struct path_key_entry *)xentry;
+ object_free( entry->path );
+ object_free( entry->key );
+}
+
+void path_done( void )
+{
+ if ( path_key_cache )
+ {
+ hashenumerate( path_key_cache, &free_path_key_entry, (void *)0 );
+ hashdone( path_key_cache );
}
+}
- len=_tcslen(ret)+1;
- if (cchBuffer>=len)
- _tcscpy(lpszLongPath,ret);
+#else
- return len;
+void path_add_key( OBJECT * path )
+{
}
-char* short_path_to_long_path(char* short_path)
+OBJECT * path_as_key( OBJECT * path )
{
- char buffer2[_MAX_PATH];
- int ret = ShortPathToLongPath(short_path, buffer2, _MAX_PATH);
+ return object_copy( path );
+}
- if (ret)
- return newstr(buffer2);
- else
- return newstr(short_path);
+void path_done( void )
+{
}
#endif
@@ -424,7 +551,7 @@ const char * path_tmpdir()
return path_tmpdir_result;
}
-const char * path_tmpnam(void)
+OBJECT * path_tmpnam(void)
{
char name_buffer[64];
# ifdef OS_NT
@@ -436,18 +563,21 @@ const char * path_tmpnam(void)
if (0 == c1) c1 = time(0)&0xffff;
c1 += 1;
sprintf(name_buffer,"jam%lx%lx.000",c0,c1);
- return newstr(name_buffer);
+ return object_new(name_buffer);
}
-const char * path_tmpfile(void)
+OBJECT * path_tmpfile(void)
{
- const char * result = 0;
+ OBJECT * result = 0;
+ OBJECT * tmpnam;
string file_path;
string_copy(&file_path,path_tmpdir());
string_push_back(&file_path,PATH_DELIM);
- string_append(&file_path,path_tmpnam());
- result = newstr(file_path.value);
+ tmpnam = path_tmpnam();
+ string_append(&file_path,object_str(tmpnam));
+ object_free(tmpnam);
+ result = object_new(file_path.value);
string_free(&file_path);
return result;
diff --git a/tools/build/v2/engine/pathvms.c b/tools/build/v2/engine/pathvms.c
deleted file mode 100644
index 975fe5a579..0000000000
--- a/tools/build/v2/engine/pathvms.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- */
-
-# include "jam.h"
-# include "pathsys.h"
-
-# ifdef OS_VMS
-
-# define DEBUG
-
-/*
- * pathvms.c - manipulate file names on VMS
- *
- * External routines:
- *
- * path_parse() - split a file name into dir/base/suffix/member
- * path_build() - build a filename given dir/base/suffix/member
- * path_parent() - make a PATHNAME point to its parent dir
- *
- * File_parse() and path_build() just manipuate a string and a structure;
- * they do not make system calls.
- *
- * WARNING! This file contains voodoo logic, as black magic is
- * necessary for wrangling with VMS file name. Woe be to people
- * who mess with this code.
- *
- * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
- * 05/03/96 (seiwald) - split from filevms.c
- */
-
-/*
- * path_parse() - split a file name into dir/base/suffix/member.
- */
-
-void path_parse( char * file, PATHNAME * f )
-{
- char * p;
- char * q;
- char * end;
-
- memset( (char *)f, 0, sizeof( *f ) );
-
- /* Look for <grist> */
-
- if ( ( file[0] == '<' ) && ( p = strchr( file, '>' ) ) )
- {
- f->f_grist.ptr = file;
- f->f_grist.len = p - file;
- file = p + 1;
- }
-
- /* Look for dev:[dir] or dev: */
-
- if ( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) )
- {
- f->f_dir.ptr = file;
- f->f_dir.len = p + 1 - file;
- file = p + 1;
- }
-
- end = file + strlen( file );
-
- /* Look for (member). */
-
- if ( ( p = strchr( file, '(' ) ) && ( end[ -1 ] == ')' ) )
- {
- f->f_member.ptr = p + 1;
- f->f_member.len = end - p - 2;
- end = p;
- }
-
- /* Look for .suffix */
- /* This would be memrchr(). */
-
- p = 0;
- q = file;
-
- while ( q = (char *)memchr( q, '.', end - q ) )
- p = q++;
-
- if ( p )
- {
- f->f_suffix.ptr = p;
- f->f_suffix.len = end - p;
- end = p;
- }
-
- /* Leaves base. */
- f->f_base.ptr = file;
- f->f_base.len = end - file;
-
- /* Is this a directory without a file spec? */
- f->parent = 0;
-}
-
-/*
- * dir mods result
- * --- --- ------
- * Rerooting:
- *
- * (none) :R=dev: dev:
- * devd: :R=dev: devd:
- * devd:[dir] :R=dev: devd:[dir]
- * [.dir] :R=dev: dev:[dir] questionable
- * [dir] :R=dev: dev:[dir]
- *
- * (none) :R=[rdir] [rdir] questionable
- * devd: :R=[rdir] devd:
- * devd:[dir] :R=[rdir] devd:[dir]
- * [.dir] :R=[rdir] [rdir.dir] questionable
- * [dir] :R=[rdir] [rdir]
- *
- * (none) :R=dev:[root] dev:[root]
- * devd: :R=dev:[root] devd:
- * devd:[dir] :R=dev:[root] devd:[dir]
- * [.dir] :R=dev:[root] dev:[root.dir]
- * [dir] :R=dev:[root] [dir]
- *
- * Climbing to parent:
- *
- */
-
-# define DIR_EMPTY 0 /* empty string */
-# define DIR_DEV 1 /* dev: */
-# define DIR_DEVDIR 2 /* dev:[dir] */
-# define DIR_DOTDIR 3 /* [.dir] */
-# define DIR_DASHDIR 4 /* [-] or [-.dir] */
-# define DIR_ABSDIR 5 /* [dir] */
-# define DIR_ROOT 6 /* [000000] or dev:[000000] */
-
-# define G_DIR 0 /* take just dir */
-# define G_ROOT 1 /* take just root */
-# define G_VAD 2 /* root's dev: + [abs] */
-# define G_DRD 3 /* root's dev:[dir] + [.rel] */
-# define G_VRD 4 /* root's dev: + [.rel] made [abs] */
-# define G_DDD 5 /* root's dev:[dir] + . + [dir] */
-
-static int grid[7][7] = {
-
-/* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */
-/* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR,
-/* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD,
-/* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD,
-/* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
-/* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR,
-/* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
-/* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR,
-
-};
-
-struct dirinf
-{
- int flags;
-
- struct
- {
- char * ptr;
- int len;
- } dev, dir;
-};
-
-static char * strnchr( char * buf, int c, int len )
-{
- while ( len-- )
- if ( *buf && ( *buf++ == c ) )
- return buf - 1;
- return 0;
-}
-
-
-static void dir_flags( char * buf, int len, struct dirinf * i )
-{
- char * p;
-
- if ( !buf || !len )
- {
- i->flags = DIR_EMPTY;
- i->dev.ptr =
- i->dir.ptr = 0;
- i->dev.len =
- i->dir.len = 0;
- }
- else if ( p = strnchr( buf, ':', len ) )
- {
- i->dev.ptr = buf;
- i->dev.len = p + 1 - buf;
- i->dir.ptr = buf + i->dev.len;
- i->dir.len = len - i->dev.len;
- i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV;
- }
- else
- {
- i->dev.ptr = buf;
- i->dev.len = 0;
- i->dir.ptr = buf;
- i->dir.len = len;
-
- if ( ( *buf == '[' ) && ( buf[1] == ']' ) )
- i->flags = DIR_EMPTY;
- else if ( ( *buf == '[' ) && ( buf[1] == '.' ) )
- i->flags = DIR_DOTDIR;
- else if ( ( *buf == '[' ) && ( buf[1] == '-' ) )
- i->flags = DIR_DASHDIR;
- else
- i->flags = DIR_ABSDIR;
- }
-
- /* But if its rooted in any way. */
-
- if ( ( i->dir.len == 8 ) && !strncmp( i->dir.ptr, "[000000]", 8 ) )
- i->flags = DIR_ROOT;
-}
-
-
-/*
- * path_build() - build a filename given dir/base/suffix/member
- */
-
-void path_build( PATHNAME * f, string * file, int binding )
-{
- struct dirinf root;
- struct dirinf dir;
- int g;
-
- file_build1( f, file );
-
- /* Get info on root and dir for combining. */
- dir_flags( f->f_root.ptr, f->f_root.len, &root );
- dir_flags( f->f_dir.ptr, f->f_dir.len, &dir );
-
- /* Combine. */
- switch ( g = grid[ root.flags ][ dir.flags ] )
- {
- case G_DIR:
- /* take dir */
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_ROOT:
- /* take root */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- break;
-
- case G_VAD:
- /* root's dev + abs directory */
- string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
- string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len );
- break;
-
- case G_DRD:
- case G_DDD:
- /* root's dev:[dir] + rel directory */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
-
- /* sanity checks: root ends with ] */
-
- if ( file->value[file->size - 1] == ']' )
- string_pop_back( file );
-
- /* Add . if separating two -'s */
-
- if ( g == G_DDD )
- string_push_back( file, '.' );
-
- /* skip [ of dir */
- string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1 );
- break;
-
- case G_VRD:
- /* root's dev + rel directory made abs */
- string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
- string_push_back( file, '[' );
- /* skip [. of rel dir */
- string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2 );
- break;
- }
-
-# ifdef DEBUG
- if ( DEBUG_SEARCH && ( root.flags || dir.flags ) )
- printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
- grid[ root.flags ][ dir.flags ], file->value );
-# endif
-
- /*
- * Now do the special :P modifier when no file was present.
- * (none) (none)
- * [dir1.dir2] [dir1]
- * [dir] [000000]
- * [.dir] (none)
- * [] []
- */
-
- if ( ( file->value[ file->size - 1 ] == ']' ) && f->parent )
- {
- char * p = file->value + file->size;
- while ( p-- > file->value )
- {
- if ( *p == '.' )
- {
- /* If we've truncated everything and left with '[',
- return empty string. */
- if ( p == file->value + 1 )
- string_truncate( file, 0 );
- else
- {
- string_truncate( file, p - file->value );
- string_push_back( file, ']' );
- }
- break;
- }
-
- if ( *p == '-' )
- {
- /* handle .- or - */
- if ( ( p > file->value ) && ( p[ -1 ] == '.' ) )
- --p;
-
- *p++ = ']';
- break;
- }
-
- if ( *p == '[' )
- {
- if ( p[ 1 ] == ']' )
- {
- /* CONSIDER: I don't see any use of this code. We immediately
- break, and 'p' is a local variable. */
- p += 2;
- }
- else
- {
- string_truncate( file, p - file->value );
- string_append( file, "[000000]" );
- }
- break;
- }
- }
- }
-
- /* Now copy the file pieces. */
- if ( f->f_base.len )
- {
- string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
- }
-
- /* If there is no suffix, we append a "." onto all generated names. This
- * keeps VMS from appending its own (wrong) idea of what the suffix should
- * be.
- */
- if ( f->f_suffix.len )
- string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
- else if ( binding && f->f_base.len )
- string_push_back( file, '.' );
-
- if ( f->f_member.len )
- {
- string_push_back( file, '(' );
- string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
- string_push_back( file, ')' );
- }
-
-# ifdef DEBUG
- if ( DEBUG_SEARCH )
- printf( "built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n",
- f->f_root.len, f->f_root.ptr,
- f->f_dir.len, f->f_dir.ptr,
- f->f_base.len, f->f_base.ptr,
- f->f_suffix.len, f->f_suffix.ptr,
- f->f_member.len, f->f_member.ptr,
- file->value );
-# endif
-}
-
-
-/*
- * path_parent() - make a PATHNAME point to its parent dir
- */
-
-void path_parent( PATHNAME * f )
-{
- if ( f->f_base.len )
- {
- f->f_base.ptr =
- f->f_suffix.ptr =
- f->f_member.ptr = "";
-
- f->f_base.len =
- f->f_suffix.len =
- f->f_member.len = 0;
- }
- else
- {
- f->parent = 1;
- }
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/pwd.c b/tools/build/v2/engine/pwd.c
index 90c8eb175d..93d8126032 100644
--- a/tools/build/v2/engine/pwd.c
+++ b/tools/build/v2/engine/pwd.c
@@ -4,7 +4,7 @@
#include "jam.h"
#include "lists.h"
-#include "newstr.h"
+#include "object.h"
#include "pathsys.h"
#include "mem.h"
@@ -29,7 +29,7 @@
/* The current directory can't change in bjam, so optimize this to cache
** the result.
*/
-static char * pwd_result = NULL;
+static OBJECT * pwd_result = NULL;
LIST*
@@ -46,9 +46,11 @@ pwd(void)
if (result_buffer)
{
#ifdef NT
- pwd_result = short_path_to_long_path(result_buffer);
+ OBJECT * result = object_new(result_buffer);
+ pwd_result = short_path_to_long_path(result);
+ object_free( result );
#else
- pwd_result = newstr(result_buffer);
+ pwd_result = object_new(result_buffer);
#endif
}
buffer_size *= 2;
@@ -62,5 +64,13 @@ pwd(void)
return L0;
}
}
- return list_new(L0, pwd_result);
+ return list_new( object_copy( pwd_result ) );
+}
+
+void pwd_done( void )
+{
+ if( pwd_result )
+ {
+ object_free( pwd_result );
+ }
}
diff --git a/tools/build/v2/engine/pwd.h b/tools/build/v2/engine/pwd.h
index 37cb531e4f..e6ed268bb2 100644
--- a/tools/build/v2/engine/pwd.h
+++ b/tools/build/v2/engine/pwd.h
@@ -5,6 +5,7 @@
#ifndef PWD_H
#define PWD_H
-LIST* pwd(void);
+LIST * pwd( void );
+void pwd_done( void );
#endif
diff --git a/tools/build/v2/engine/regexp.c b/tools/build/v2/engine/regexp.c
index 30197a2feb..b51b85b09c 100644
--- a/tools/build/v2/engine/regexp.c
+++ b/tools/build/v2/engine/regexp.c
@@ -152,7 +152,7 @@
* Utility definitions.
*/
#ifndef CHARBITS
-#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#define UCHARAT(p) ((int)*(const unsigned char *)(p))
#else
#define UCHARAT(p) ((int)*(p)&CHARBITS)
#endif
@@ -213,7 +213,7 @@ STATIC int strcspn();
* of the structure of the compiled regexp.
*/
regexp *
-regcomp( char *exp )
+regcomp( const char *exp )
{
register regexp *r;
register char *scan;
@@ -770,15 +770,15 @@ regoptail(
/*
* Global work variables for regexec().
*/
-static char *reginput; /* String-input pointer. */
-static char *regbol; /* Beginning of input, for ^ check. */
-static char **regstartp; /* Pointer to startp array. */
-static char **regendp; /* Ditto for endp. */
+static const char *reginput; /* String-input pointer. */
+static const char *regbol; /* Beginning of input, for ^ check. */
+static const char **regstartp; /* Pointer to startp array. */
+static const char **regendp; /* Ditto for endp. */
/*
* Forwards.
*/
-STATIC int regtry( regexp *prog, char *string );
+STATIC int regtry( regexp *prog, const char *string );
STATIC int regmatch( char *prog );
STATIC int regrepeat( char *p );
@@ -794,7 +794,7 @@ STATIC char *regprop();
int
regexec(
register regexp *prog,
- register char *string )
+ register const char *string )
{
register char *s;
@@ -859,11 +859,11 @@ regexec(
static int /* 0 failure, 1 success */
regtry(
regexp *prog,
- char *string )
+ const char *string )
{
register int i;
- register char * * sp;
- register char * * ep;
+ register const char * * sp;
+ register const char * * ep;
reginput = string;
regstartp = prog->startp;
@@ -982,7 +982,7 @@ regmatch( char * prog )
case OPEN+8:
case OPEN+9: {
register int no;
- register char *save;
+ register const char *save;
no = OP(scan) - OPEN;
save = reginput;
@@ -1010,7 +1010,7 @@ regmatch( char * prog )
case CLOSE+8:
case CLOSE+9: {
register int no;
- register char *save;
+ register const char *save;
no = OP(scan) - CLOSE;
save = reginput;
@@ -1029,7 +1029,7 @@ regmatch( char * prog )
}
break;
case BRANCH: {
- register char *save;
+ register const char *save;
if (OP(next) != BRANCH) /* No choice. */
next = OPERAND(scan); /* Avoid recursion. */
@@ -1050,7 +1050,7 @@ regmatch( char * prog )
case PLUS: {
register char nextch;
register int no;
- register char *save;
+ register const char *save;
register int min;
/*
@@ -1102,7 +1102,7 @@ static int
regrepeat( char *p )
{
register int count = 0;
- register char *scan;
+ register const char *scan;
register char *opnd;
scan = reginput;
diff --git a/tools/build/v2/engine/regexp.h b/tools/build/v2/engine/regexp.h
index 9d4604f60a..fccfb7dff8 100644
--- a/tools/build/v2/engine/regexp.h
+++ b/tools/build/v2/engine/regexp.h
@@ -9,8 +9,8 @@
#define NSUBEXP 10
typedef struct regexp {
- char *startp[NSUBEXP];
- char *endp[NSUBEXP];
+ const char *startp[NSUBEXP];
+ const char *endp[NSUBEXP];
char regstart; /* Internal use only. */
char reganch; /* Internal use only. */
char *regmust; /* Internal use only. */
@@ -18,9 +18,9 @@ typedef struct regexp {
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
-regexp *regcomp( char *exp );
-int regexec( regexp *prog, char *string );
-void regerror( char *s );
+regexp *regcomp( const char *exp );
+int regexec( regexp *prog, const char *string );
+void regerror( const char *s );
/*
* The first byte of the regexp internal "program" is actually this magic
diff --git a/tools/build/v2/engine/rules.c b/tools/build/v2/engine/rules.c
index a0be1d3400..b9ff6191f5 100644
--- a/tools/build/v2/engine/rules.c
+++ b/tools/build/v2/engine/rules.c
@@ -9,7 +9,7 @@
# include "parse.h"
# include "variable.h"
# include "rules.h"
-# include "newstr.h"
+# include "object.h"
# include "hash.h"
# include "modules.h"
# include "search.h"
@@ -45,19 +45,10 @@
*/
static void set_rule_actions( RULE *, rule_actions * );
-static void set_rule_body ( RULE *, argument_list *, PARSE * procedure );
+static void set_rule_body ( RULE *, FUNCTION * procedure );
static struct hash * targethash = 0;
-struct _located_target
-{
- char * file_name;
- TARGET * target;
-};
-typedef struct _located_target LOCATED_TARGET ;
-
-static struct hash * located_targets = 0;
-
/*
* target_include() - adds the 'included' TARGET to the list of targets included
@@ -83,25 +74,20 @@ void target_include( TARGET * including, TARGET * included )
* target_module.
*/
-static RULE * enter_rule( char * rulename, module_t * target_module )
+static RULE * enter_rule( OBJECT * rulename, module_t * target_module )
{
- RULE rule;
- RULE * r = &rule;
+ int found;
+ RULE * r;
- r->name = rulename;
-
- if ( hashenter( demand_rules( target_module ), (HASHDATA * *)&r ) )
+ r = (RULE *)hash_insert( demand_rules(target_module), rulename, &found );
+ if ( !found )
{
- r->name = newstr( rulename ); /* never freed */
- r->procedure = (PARSE *)0;
+ r->name = object_copy( rulename );
+ r->procedure = 0;
r->module = 0;
r->actions = 0;
- r->arguments = 0;
r->exported = 0;
r->module = target_module;
-#ifdef HAVE_PYTHON
- r->python_function = 0;
-#endif
}
return r;
}
@@ -116,14 +102,14 @@ static RULE * enter_rule( char * rulename, module_t * target_module )
static RULE * define_rule
(
module_t * src_module,
- char * rulename,
+ OBJECT * rulename,
module_t * target_module
)
{
RULE * r = enter_rule( rulename, target_module );
if ( r->module != src_module ) /* if the rule was imported from elsewhere, clear it now */
{
- set_rule_body( r, 0, 0 );
+ set_rule_body( r, 0 );
set_rule_actions( r, 0 );
r->module = src_module; /* r will be executed in the source module */
}
@@ -133,13 +119,11 @@ static RULE * define_rule
void rule_free( RULE * r )
{
- freestr( r->name );
- r->name = "";
- parse_free( r->procedure );
+ object_free( r->name );
+ r->name = 0;
+ if ( r->procedure )
+ function_free( r->procedure );
r->procedure = 0;
- if ( r->arguments )
- args_free( r->arguments );
- r->arguments = 0;
if ( r->actions )
actions_free( r->actions );
r->actions = 0;
@@ -150,25 +134,20 @@ void rule_free( RULE * r )
* bindtarget() - return pointer to TARGET, creating it if necessary.
*/
-TARGET * bindtarget( char const * target_name )
+TARGET * bindtarget( OBJECT * target_name )
{
- TARGET target;
- TARGET * t = &target;
+ int found;
+ TARGET * t;
if ( !targethash )
targethash = hashinit( sizeof( TARGET ), "targets" );
- /* Perforce added const everywhere. No time to merge that change. */
-#ifdef NT
- target_name = short_path_to_long_path( (char *)target_name );
-#endif
- t->name = (char *)target_name;
-
- if ( hashenter( targethash, (HASHDATA * *)&t ) )
+ t = (TARGET *)hash_insert( targethash, target_name, &found );
+ if ( !found )
{
memset( (char *)t, '\0', sizeof( *t ) );
- t->name = newstr( (char *)target_name ); /* never freed */
- t->boundname = t->name; /* default for T_FLAG_NOTFILE */
+ t->name = object_copy( target_name );
+ t->boundname = object_copy( t->name ); /* default for T_FLAG_NOTFILE */
}
return t;
@@ -184,14 +163,15 @@ static void bind_explicitly_located_target( void * xtarget, void * data )
SETTINGS * s = t->settings;
for ( ; s ; s = s->next )
{
- if ( strcmp( s->symbol, "LOCATE" ) == 0 )
+ if ( strcmp( object_str( s->symbol ), "LOCATE" ) == 0 )
{
- pushsettings( t->settings );
+ pushsettings( root_module(), t->settings );
/* We are binding a target with explicit LOCATE. So third
* argument is of no use: nothing will be returned through it.
*/
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
break;
}
}
@@ -206,81 +186,6 @@ void bind_explicitly_located_targets()
}
-/* TODO: It is probably not a good idea to use functions in other modules like
- this. */
-void call_bind_rule( char * target, char * boundname );
-
-
-TARGET * search_for_target ( char * name, LIST * search_path )
-{
- PATHNAME f[1];
- string buf[1];
- LOCATED_TARGET lt;
- LOCATED_TARGET * lta = &lt;
- time_t time;
- int found = 0;
- TARGET * result;
-
- string_new( buf );
-
- path_parse( name, f );
-
- f->f_grist.ptr = 0;
- f->f_grist.len = 0;
-
- while ( search_path )
- {
- f->f_root.ptr = search_path->string;
- f->f_root.len = strlen( search_path->string );
-
- string_truncate( buf, 0 );
- path_build( f, buf, 1 );
-
- lt.file_name = buf->value ;
-
- if ( !located_targets )
- located_targets = hashinit( sizeof(LOCATED_TARGET),
- "located targets" );
-
- if ( hashcheck( located_targets, (HASHDATA * *)&lta ) )
- {
- return lta->target;
- }
-
- timestamp( buf->value, &time );
- if ( time )
- {
- found = 1;
- break;
- }
-
- search_path = list_next( search_path );
- }
-
- if ( !found )
- {
- f->f_root.ptr = 0;
- f->f_root.len = 0;
-
- string_truncate( buf, 0 );
- path_build( f, buf, 1 );
-
- timestamp( buf->value, &time );
- }
-
- result = bindtarget( name );
- result->boundname = newstr( buf->value );
- result->time = time;
- result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
-
- call_bind_rule( result->name, result->boundname );
-
- string_free( buf );
-
- return result;
-}
-
-
/*
* copytarget() - make a new target with the old target's name.
*
@@ -291,8 +196,8 @@ TARGET * copytarget( const TARGET * ot )
{
TARGET * t = (TARGET *)BJAM_MALLOC( sizeof( *t ) );
memset( (char *)t, '\0', sizeof( *t ) );
- t->name = copystr( ot->name );
- t->boundname = t->name;
+ t->name = object_copy( ot->name );
+ t->boundname = object_copy( t->name );
t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
@@ -304,7 +209,7 @@ TARGET * copytarget( const TARGET * ot )
* touch_target() - mark a target to simulate being new.
*/
-void touch_target( char * t )
+void touch_target( OBJECT * t )
{
bindtarget( t )->flags |= T_FLAG_TOUCHED;
}
@@ -320,8 +225,9 @@ void touch_target( char * t )
TARGETS * targetlist( TARGETS * chain, LIST * target_names )
{
- for ( ; target_names; target_names = list_next( target_names ) )
- chain = targetentry( chain, bindtarget( target_names->string ) );
+ LISTITER iter = list_begin( target_names ), end = list_end( target_names );
+ for ( ; iter != end; iter = list_next( iter ) )
+ chain = targetentry( chain, bindtarget( list_item( iter ) ) );
return chain;
}
@@ -368,6 +274,21 @@ TARGETS * targetchain( TARGETS * chain, TARGETS * targets )
}
/*
+ * action_free - decrement the ACTIONs refrence count
+ * and (maybe) free it.
+ */
+
+void action_free ( ACTION * action )
+{
+ if ( --action->refs == 0 )
+ {
+ freetargets( action->targets );
+ freetargets( action->sources );
+ BJAM_FREE( action );
+ }
+}
+
+/*
* actionlist() - append to an ACTION chain.
*/
@@ -377,6 +298,7 @@ ACTIONS * actionlist( ACTIONS * chain, ACTION * action )
actions->action = action;
+ ++action->refs;
if ( !chain ) chain = actions;
else chain->tail->next = actions;
chain->tail = actions;
@@ -397,13 +319,13 @@ static SETTINGS * settings_freelist;
* the head of the settings chain.
*/
-SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
+SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol, LIST * value )
{
SETTINGS * v;
/* Look for previous settings. */
for ( v = head; v; v = v->next )
- if ( !strcmp( v->symbol, symbol ) )
+ if ( object_equal( v->symbol, symbol ) )
break;
/* If not previously set, alloc a new. */
@@ -418,10 +340,9 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
else
v = (SETTINGS *)BJAM_MALLOC( sizeof( *v ) );
- v->symbol = newstr( symbol );
+ v->symbol = object_copy( symbol );
v->value = value;
v->next = head;
- v->multiple = 0;
head = v;
}
else if ( flag == VAR_APPEND )
@@ -445,10 +366,10 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
* pushsettings() - set all target specific variables.
*/
-void pushsettings( SETTINGS * v )
+void pushsettings( struct module_t * module, SETTINGS * v )
{
for ( ; v; v = v->next )
- v->value = var_swap( v->symbol, v->value );
+ v->value = var_swap( module, v->symbol, v->value );
}
@@ -456,9 +377,9 @@ void pushsettings( SETTINGS * v )
* popsettings() - reset target specific variables to their pre-push values.
*/
-void popsettings( SETTINGS * v )
+void popsettings( struct module_t * module, SETTINGS * v )
{
- pushsettings( v ); /* just swap again */
+ pushsettings( module, v ); /* just swap again */
}
@@ -471,7 +392,7 @@ SETTINGS * copysettings( SETTINGS * head )
SETTINGS * copy = 0;
SETTINGS * v;
for ( v = head; v; v = v->next )
- copy = addsettings( copy, VAR_SET, v->symbol, list_copy( 0, v->value ) );
+ copy = addsettings( copy, VAR_SET, v->symbol, list_copy( v->value ) );
return copy;
}
@@ -500,6 +421,7 @@ void freeactions( ACTIONS * chain )
while ( chain )
{
ACTIONS * n = chain->next;
+ action_free( chain->action );
BJAM_FREE( chain );
chain = n;
}
@@ -515,7 +437,7 @@ void freesettings( SETTINGS * v )
while ( v )
{
SETTINGS * n = v->next;
- freestr( v->symbol );
+ object_free( v->symbol );
list_free( v->value );
v->next = settings_freelist;
settings_freelist = v;
@@ -527,10 +449,19 @@ void freesettings( SETTINGS * v )
static void freetarget( void * xt, void * data )
{
TARGET * t = (TARGET *)xt;
- if ( t->settings ) freesettings( t->settings );
- if ( t->depends ) freetargets ( t->depends );
- if ( t->includes ) freetarget ( t->includes, (void *)0 );
- if ( t->actions ) freeactions ( t->actions );
+ if ( t->name ) object_free ( t->name );
+ if ( t->boundname ) object_free ( t->boundname );
+ if ( t->settings ) freesettings( t->settings );
+ if ( t->depends ) freetargets ( t->depends );
+ if ( t->dependants ) freetargets ( t->dependants );
+ if ( t->parents ) freetargets ( t->parents );
+ if ( t->actions ) freeactions ( t->actions );
+
+ if ( t->includes )
+ {
+ freetarget( t->includes, (void *)0 );
+ BJAM_FREE( t->includes );
+ }
}
@@ -540,8 +471,11 @@ static void freetarget( void * xt, void * data )
void rules_done()
{
- hashenumerate( targethash, freetarget, 0 );
- hashdone( targethash );
+ if ( targethash )
+ {
+ hashenumerate( targethash, freetarget, 0 );
+ hashdone( targethash );
+ }
while ( settings_freelist )
{
SETTINGS * n = settings_freelist->next;
@@ -552,43 +486,6 @@ void rules_done()
/*
- * args_new() - make a new reference-counted argument list.
- */
-
-argument_list * args_new()
-{
- argument_list * r = (argument_list *)BJAM_MALLOC( sizeof(argument_list) );
- r->reference_count = 0;
- lol_init( r->data );
- return r;
-}
-
-
-/*
- * args_refer() - add a new reference to the given argument list.
- */
-
-void args_refer( argument_list * a )
-{
- ++a->reference_count;
-}
-
-
-/*
- * args_free() - release a reference to the given argument list.
- */
-
-void args_free( argument_list * a )
-{
- if ( --a->reference_count <= 0 )
- {
- lol_free( a->data );
- BJAM_FREE( a );
- }
-}
-
-
-/*
* actions_refer() - add a new reference to the given actions.
*/
@@ -606,29 +503,22 @@ void actions_free( rule_actions * a )
{
if ( --a->reference_count <= 0 )
{
- freestr( a->command );
+ function_free( a->command );
list_free( a->bindlist );
BJAM_FREE( a );
}
}
-
/*
* set_rule_body() - set the argument list and procedure of the given rule.
*/
-static void set_rule_body( RULE * rule, argument_list * args, PARSE * procedure )
+static void set_rule_body( RULE * rule, FUNCTION * procedure )
{
- if ( args )
- args_refer( args );
- if ( rule->arguments )
- args_free( rule->arguments );
- rule->arguments = args;
-
if ( procedure )
- parse_refer( procedure );
+ function_refer( procedure );
if ( rule->procedure )
- parse_free( rule->procedure );
+ function_free( rule->procedure );
rule->procedure = procedure;
}
@@ -638,16 +528,20 @@ static void set_rule_body( RULE * rule, argument_list * args, PARSE * procedure
* global module.
*/
-static char * global_rule_name( RULE * r )
+static OBJECT * global_rule_name( RULE * r )
{
if ( r->module == root_module() )
- return r->name;
+ return object_copy( r->name );
{
char name[4096] = "";
- strncat( name, r->module->name, sizeof( name ) - 1 );
- strncat( name, r->name, sizeof( name ) - 1 );
- return newstr( name);
+ if ( r->module->name )
+ {
+ strncat( name, object_str( r->module->name ), sizeof( name ) - 1 );
+ strncat( name, ".", sizeof( name ) - 1 );
+ }
+ strncat( name, object_str( r->name ), sizeof( name ) - 1 );
+ return object_new( name );
}
}
@@ -663,9 +557,9 @@ static RULE * global_rule( RULE * r )
return r;
{
- char * name = global_rule_name( r );
+ OBJECT * name = global_rule_name( r );
RULE * result = define_rule( r->module, name, root_module() );
- freestr( name );
+ object_free( name );
return result;
}
}
@@ -677,19 +571,19 @@ static RULE * global_rule( RULE * r )
* exported to the global module as modulename.rulename.
*/
-RULE * new_rule_body( module_t * m, char * rulename, argument_list * args, PARSE * procedure, int exported )
+RULE * new_rule_body( module_t * m, OBJECT * rulename, FUNCTION * procedure, int exported )
{
RULE * local = define_rule( m, rulename, m );
local->exported = exported;
- set_rule_body( local, args, procedure );
+ set_rule_body( local, procedure );
/* Mark the procedure with the global rule name, regardless of whether the
* rule is exported. That gives us something reasonably identifiable that we
* can use, e.g. in profiling output. Only do this once, since this could be
* called multiple times with the same procedure.
*/
- if ( procedure->rulename == 0 )
- procedure->rulename = global_rule_name( local );
+ if ( function_rulename( procedure ) == 0 )
+ function_set_rulename( procedure, global_rule_name( local ) );
return local;
}
@@ -705,10 +599,11 @@ static void set_rule_actions( RULE * rule, rule_actions * actions )
}
-static rule_actions * actions_new( char * command, LIST * bindlist, int flags )
+static rule_actions * actions_new( FUNCTION * command, LIST * bindlist, int flags )
{
rule_actions * result = (rule_actions *)BJAM_MALLOC( sizeof( rule_actions ) );
- result->command = copystr( command );
+ function_refer( command );
+ result->command = command;
result->bindlist = bindlist;
result->flags = flags;
result->reference_count = 0;
@@ -716,7 +611,7 @@ static rule_actions * actions_new( char * command, LIST * bindlist, int flags )
}
-RULE * new_rule_actions( module_t * m, char * rulename, char * command, LIST * bindlist, int flags )
+RULE * new_rule_actions( module_t * m, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags )
{
RULE * local = define_rule( m, rulename, m );
RULE * global = global_rule( local );
@@ -733,32 +628,37 @@ RULE * new_rule_actions( module_t * m, char * rulename, char * command, LIST * b
* modules, look in module 'name1' for rule 'name2'.
*/
-RULE * lookup_rule( char * rulename, module_t * m, int local_only )
+RULE * lookup_rule( OBJECT * rulename, module_t * m, int local_only )
{
- RULE rule;
- RULE * r = &rule;
+ RULE * r;
RULE * result = 0;
module_t * original_module = m;
- r->name = rulename;
-
if ( m->class_module )
m = m->class_module;
- if ( m->rules && hashcheck( m->rules, (HASHDATA * *)&r ) )
+ if ( m->rules && ( r = (RULE *)hash_find( m->rules, rulename ) ) )
result = r;
else if ( !local_only && m->imported_modules )
{
/* Try splitting the name into module and rule. */
- char *p = strchr( r->name, '.' ) ;
+ char *p = strchr( object_str( rulename ), '.' ) ;
if ( p )
{
- *p = '\0';
+ string buf[1];
+ OBJECT * module_part;
+ OBJECT * rule_part;
+ string_new( buf );
+ string_append_range( buf, object_str( rulename ), p );
+ module_part = object_new( buf->value );
+ rule_part = object_new( p + 1 );
/* Now, r->name keeps the module name, and p+1 keeps the rule name.
*/
- if ( hashcheck( m->imported_modules, (HASHDATA * *)&r ) )
- result = lookup_rule( p + 1, bindmodule( rulename ), 1 );
- *p = '.';
+ if ( hash_find( m->imported_modules, module_part ) )
+ result = lookup_rule( rule_part, bindmodule( module_part ), 1 );
+ object_free( rule_part );
+ object_free( module_part );
+ string_free( buf );
}
}
@@ -786,7 +686,7 @@ RULE * lookup_rule( char * rulename, module_t * m, int local_only )
}
-RULE * bindrule( char * rulename, module_t * m )
+RULE * bindrule( OBJECT * rulename, module_t * m )
{
RULE * result = lookup_rule( rulename, m, 0 );
if ( !result )
@@ -801,10 +701,24 @@ RULE * bindrule( char * rulename, module_t * m )
}
-RULE * import_rule( RULE * source, module_t * m, char * name )
+RULE * import_rule( RULE * source, module_t * m, OBJECT * name )
{
RULE * dest = define_rule( source->module, name, m );
- set_rule_body( dest, source->arguments, source->procedure );
+ set_rule_body( dest, source->procedure );
set_rule_actions( dest, source->actions );
return dest;
}
+
+
+void rule_localize( RULE * rule, module_t * m )
+{
+ rule->module = m;
+ if ( rule->procedure )
+ {
+ FUNCTION * procedure = function_unbind_variables( rule->procedure );
+ function_refer( procedure );
+ function_free( rule->procedure );
+ rule->procedure = procedure;
+ }
+}
+
diff --git a/tools/build/v2/engine/rules.h b/tools/build/v2/engine/rules.h
index 806a1469c0..823fbd1f55 100644
--- a/tools/build/v2/engine/rules.h
+++ b/tools/build/v2/engine/rules.h
@@ -15,7 +15,7 @@
#include "modules.h"
#include "jam.h"
-#include "parse.h"
+#include "function.h"
/*
@@ -52,20 +52,13 @@ typedef struct _settings SETTINGS ;
/* RULE - a generic jam rule, the product of RULE and ACTIONS. */
-/* A rule's argument list. */
-struct argument_list
-{
- int reference_count;
- LOL data[1];
-};
-
/* Build actions corresponding to a rule. */
struct rule_actions
{
- int reference_count;
- char * command; /* command string from ACTIONS */
- LIST * bindlist;
- int flags; /* modifiers on ACTIONS */
+ int reference_count;
+ FUNCTION * command; /* command string from ACTIONS */
+ LIST * bindlist;
+ int flags; /* modifiers on ACTIONS */
#define RULE_NEWSRCS 0x01 /* $(>) is updated sources only */
#define RULE_TOGETHER 0x02 /* combine actions on single target */
@@ -80,19 +73,14 @@ typedef struct argument_list argument_list;
struct _rule
{
- char * name;
- PARSE * procedure; /* parse tree from RULE */
- argument_list * arguments; /* argument checking info, or NULL for unchecked
- */
+ OBJECT * name;
+ FUNCTION * procedure;
rule_actions * actions; /* build actions, or NULL for no actions */
module_t * module; /* module in which this rule is executed */
int exported; /* nonzero if this rule is supposed to appear in
* the global module and be automatically
* imported into other modules
*/
-#ifdef HAVE_PYTHON
- PyObject * python_function;
-#endif
};
/* ACTIONS - a chain of ACTIONs. */
@@ -110,16 +98,19 @@ struct _action
TARGETS * targets;
TARGETS * sources; /* aka $(>) */
char running; /* has been started */
+#define A_INIT 0
+#define A_RUNNING_NOEXEC 1
+#define A_RUNNING 2
char status; /* see TARGET status */
+ int refs;
};
/* SETTINGS - variables to set when executing a TARGET's ACTIONS. */
struct _settings
{
SETTINGS * next;
- char * symbol; /* symbol name for var_set() */
+ OBJECT * symbol; /* symbol name for var_set() */
LIST * value; /* symbol value for var_set() */
- int multiple;
};
/* TARGETS - a chain of TARGETs. */
@@ -133,8 +124,8 @@ struct _targets
/* TARGET - an entity (e.g. a file) that can be built. */
struct _target
{
- char * name;
- char * boundname; /* if search() relocates target */
+ OBJECT * name;
+ OBJECT * boundname; /* if search() relocates target */
ACTIONS * actions; /* rules to execute, if any */
SETTINGS * settings; /* variables to define */
@@ -220,6 +211,7 @@ struct _target
#define T_MAKE_ACTIVE 2 /* make1(target) in make1b() */
#define T_MAKE_RUNNING 3 /* make1(target) running commands */
#define T_MAKE_DONE 4 /* make1(target) done */
+#define T_MAKE_NOEXEC_DONE 5 /* make1(target) done with -n in effect */
#ifdef OPT_SEMAPHORE
#define T_MAKE_SEMAPHORE 5 /* Special target type for semaphores */
@@ -235,44 +227,41 @@ struct _target
TARGETS * parents; /* used by make1() for completion */
char * cmds; /* type-punned command list */
- char * failed;
+ const char * failed;
};
/* Action related functions. */
+void action_free ( ACTION * );
ACTIONS * actionlist ( ACTIONS *, ACTION * );
void freeactions ( ACTIONS * );
-SETTINGS * addsettings ( SETTINGS *, int flag, char * symbol, LIST * value );
-void pushsettings ( SETTINGS * );
-void popsettings ( SETTINGS * );
+SETTINGS * addsettings ( SETTINGS *, int flag, OBJECT * symbol, LIST * value );
+void pushsettings ( struct module_t * module, SETTINGS * );
+void popsettings ( struct module_t * module, SETTINGS * );
SETTINGS * copysettings ( SETTINGS * );
void freesettings ( SETTINGS * );
void actions_refer( rule_actions * );
void actions_free ( rule_actions * );
-/* Argument list related functions. */
-void args_free ( argument_list * );
-argument_list * args_new ();
-void args_refer( argument_list * );
-
/* Rule related functions. */
-RULE * bindrule ( char * rulename, module_t * );
-RULE * import_rule ( RULE * source, module_t *, char * name );
-RULE * new_rule_body ( module_t *, char * rulename, argument_list *, PARSE * procedure, int exprt );
-RULE * new_rule_actions( module_t *, char * rulename, char * command, LIST * bindlist, int flags );
+RULE * bindrule ( OBJECT * rulename, module_t * );
+RULE * import_rule ( RULE * source, module_t *, OBJECT * name );
+void rule_localize ( RULE * rule, module_t * module );
+RULE * new_rule_body ( module_t *, OBJECT * rulename, FUNCTION * func, int exprt );
+RULE * new_rule_actions( module_t *, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags );
void rule_free ( RULE * );
/* Target related functions. */
void bind_explicitly_located_targets();
-TARGET * bindtarget ( char const * target_name );
+TARGET * bindtarget ( OBJECT * target_name );
TARGET * copytarget ( TARGET const * t );
void freetargets ( TARGETS * );
-TARGET * search_for_target ( char * name, LIST * search_path );
TARGETS * targetchain ( TARGETS * chain, TARGETS * );
TARGETS * targetentry ( TARGETS * chain, TARGET * );
void target_include ( TARGET * including, TARGET * included );
TARGETS * targetlist ( TARGETS * chain, LIST * target_names );
-void touch_target ( char * t );
+void touch_target ( OBJECT * t );
+void clear_includes ( TARGET * );
/* Final module cleanup. */
void rules_done();
diff --git a/tools/build/v2/engine/scan.c b/tools/build/v2/engine/scan.c
index 11c44c0e21..915ec21f44 100644
--- a/tools/build/v2/engine/scan.c
+++ b/tools/build/v2/engine/scan.c
@@ -10,7 +10,8 @@
#include "scan.h"
#include "jamgram.h"
#include "jambase.h"
-#include "newstr.h"
+#include "object.h"
+#include "constants.h"
/*
* scan.c - the jam yacc scanner
@@ -41,7 +42,7 @@ struct include
char * string; /* pointer into current line */
char * * strings; /* for yyfparse() -- text to parse */
FILE * file; /* for yyfparse() -- file being read */
- char * fname; /* for yyfparse() -- file name */
+ OBJECT * fname; /* for yyfparse() -- file name */
int line; /* line counter for error messages */
char buf[ 512 ]; /* for yyfparse() -- line buffer */
};
@@ -67,7 +68,7 @@ void yymode( int n )
}
-void yyerror( char * s )
+void yyerror( const char * s )
{
/* We use yylval instead of incp to access the error location information as
* the incp pointer will already be reset to 0 in case the error occurred at
@@ -82,7 +83,7 @@ void yyerror( char * s )
* TODO: Test the theory about when yylval and incp location information are
* the same and when they differ.
*/
- printf( "%s:%d: %s at %s\n", yylval.file, yylval.line, s, symdump( &yylval ) );
+ printf( "%s:%d: %s at %s\n", object_str( yylval.file ), yylval.line, s, symdump( &yylval ) );
++anyerrors;
}
@@ -93,7 +94,7 @@ int yyanyerrors()
}
-void yyfparse( char * s )
+void yyfparse( OBJECT * s )
{
struct include * i = (struct include *)BJAM_MALLOC( sizeof( *i ) );
@@ -101,13 +102,13 @@ void yyfparse( char * s )
i->string = "";
i->strings = 0;
i->file = 0;
- i->fname = copystr( s );
+ i->fname = object_copy( s );
i->line = 0;
i->next = incp;
incp = i;
/* If the filename is "+", it means use the internal jambase. */
- if ( !strcmp( s, "+" ) )
+ if ( !strcmp( object_str( s ), "+" ) )
i->strings = jambase;
}
@@ -151,8 +152,8 @@ int yyline()
if ( !i->file )
{
FILE * f = stdin;
- if ( strcmp( i->fname, "-" ) && !( f = fopen( i->fname, "r" ) ) )
- perror( i->fname );
+ if ( strcmp( object_str( i->fname ), "-" ) && !( f = fopen( object_str( i->fname ), "r" ) ) )
+ perror( object_str( i->fname ) );
i->file = f;
}
@@ -174,7 +175,7 @@ int yyline()
/* Close file, free name. */
if ( i->file && ( i->file != stdin ) )
fclose( i->file );
- freestr( i->fname );
+ object_free( i->fname );
BJAM_FREE( (char *)i );
return EOF;
@@ -252,7 +253,7 @@ int yylex()
*b = 0;
yylval.type = STRING;
- yylval.string = newstr( buf );
+ yylval.string = object_new( buf );
yylval.file = incp->fname;
yylval.line = incp->line;
}
@@ -361,12 +362,12 @@ int yylex()
if ( ( *buf == *k->word ) && !strcmp( k->word, buf ) )
{
yylval.type = k->type;
- yylval.string = k->word; /* used by symdump */
+ yylval.keyword = k->word; /* used by symdump */
break;
}
if ( yylval.type == ARG )
- yylval.string = newstr( buf );
+ yylval.string = object_new( buf );
}
if ( DEBUG_SCAN )
@@ -388,11 +389,11 @@ static char * symdump( YYSTYPE * s )
static char buf[ BIGGEST_TOKEN + 20 ];
switch ( s->type )
{
- case EOF : sprintf( buf, "EOF" ); break;
- case 0 : sprintf( buf, "unknown symbol %s", s->string ); break;
- case ARG : sprintf( buf, "argument %s" , s->string ); break;
- case STRING: sprintf( buf, "string \"%s\"" , s->string ); break;
- default : sprintf( buf, "keyword %s" , s->string ); break;
+ case EOF : sprintf( buf, "EOF" ); break;
+ case 0 : sprintf( buf, "unknown symbol %s", object_str( s->string ) ); break;
+ case ARG : sprintf( buf, "argument %s" , object_str( s->string ) ); break;
+ case STRING: sprintf( buf, "string \"%s\"" , object_str( s->string ) ); break;
+ default : sprintf( buf, "keyword %s" , s->keyword ); break;
}
return buf;
}
@@ -403,7 +404,7 @@ static char * symdump( YYSTYPE * s )
* transitions that produce a parse.
*/
-void yyinput_stream( char * * name, int * line )
+void yyinput_stream( OBJECT * * name, int * line )
{
if ( incp )
{
@@ -412,7 +413,7 @@ void yyinput_stream( char * * name, int * line )
}
else
{
- *name = "(builtin)";
+ *name = constant_builtin;
*line = -1;
}
}
diff --git a/tools/build/v2/engine/scan.h b/tools/build/v2/engine/scan.h
index 3fad1c24cf..b672d00262 100644
--- a/tools/build/v2/engine/scan.h
+++ b/tools/build/v2/engine/scan.h
@@ -31,25 +31,26 @@
typedef struct _YYSTYPE
{
- int type;
- char * string;
- PARSE * parse;
- LIST * list;
- int number;
- char * file;
- int line;
+ int type;
+ OBJECT * string;
+ PARSE * parse;
+ LIST * list;
+ int number;
+ OBJECT * file;
+ int line;
+ const char * keyword;
} YYSTYPE;
extern YYSTYPE yylval;
void yymode( int n );
-void yyerror( char * s );
+void yyerror( const char * s );
int yyanyerrors();
-void yyfparse( char * s );
+void yyfparse( OBJECT * s );
int yyline();
int yylex();
int yyparse();
-void yyinput_stream( char * * name, int * line );
+void yyinput_stream( OBJECT * * name, int * line );
# define SCAN_NORMAL 0 /* normal parsing */
# define SCAN_STRING 1 /* look only for matching } */
diff --git a/tools/build/v2/engine/search.c b/tools/build/v2/engine/search.c
index 6c23d97a14..e3d287a679 100644
--- a/tools/build/v2/engine/search.c
+++ b/tools/build/v2/engine/search.c
@@ -16,7 +16,7 @@
#include "timestamp.h"
#include "pathsys.h"
#include "variable.h"
-#include "newstr.h"
+#include "object.h"
#include "compile.h"
#include "strings.h"
#include "hash.h"
@@ -26,8 +26,8 @@
typedef struct _binding
{
- char * binding;
- char * target;
+ OBJECT * binding;
+ OBJECT * target;
} BINDING;
static struct hash *explicit_bindings = 0;
@@ -35,22 +35,15 @@ static struct hash *explicit_bindings = 0;
void call_bind_rule
(
- char * target_,
- char * boundname_
+ OBJECT * target_,
+ OBJECT * boundname_
)
{
- LIST * bind_rule = var_get( "BINDRULE" );
- if ( bind_rule )
+ LIST * bind_rule = var_get( root_module(), constant_BINDRULE );
+ if ( !list_empty( bind_rule ) )
{
- /* No guarantee that the target is an allocated string, so be on the
- * safe side.
- */
- char * target = copystr( target_ );
-
- /* Likewise, do not rely on implementation details of newstr.c: allocate
- * a copy of boundname.
- */
- char * boundname = copystr( boundname_ );
+ OBJECT * target = object_copy( target_ );
+ OBJECT * boundname = object_copy( boundname_ );
if ( boundname && target )
{
/* Prepare the argument list. */
@@ -58,11 +51,11 @@ void call_bind_rule
frame_init( frame );
/* First argument is the target name. */
- lol_add( frame->args, list_new( L0, target ) );
+ lol_add( frame->args, list_new( target ) );
- lol_add( frame->args, list_new( L0, boundname ) );
+ lol_add( frame->args, list_new( boundname ) );
if ( lol_get( frame->args, 1 ) )
- evaluate_rule( bind_rule->string, frame );
+ list_free( evaluate_rule( list_front( bind_rule ), frame ) );
/* Clean up */
frame_free( frame );
@@ -70,9 +63,9 @@ void call_bind_rule
else
{
if ( boundname )
- freestr( boundname );
+ object_free( boundname );
if ( target )
- freestr( target );
+ object_free( target );
}
}
}
@@ -93,21 +86,21 @@ void call_bind_rule
* the third argument.
*/
-char *
+OBJECT *
search(
- char *target,
+ OBJECT * target,
time_t *time,
- char **another_target,
+ OBJECT * * another_target,
int file
)
{
PATHNAME f[1];
- LIST *varlist;
- string buf[1];
- int found = 0;
+ LIST * varlist;
+ string buf[1];
+ int found = 0;
/* Will be set to 1 if target location is specified via LOCATE. */
- int explicitly_located = 0;
- char *boundname = 0;
+ int explicitly_located = 0;
+ OBJECT * boundname = 0;
if ( another_target )
*another_target = 0;
@@ -119,55 +112,64 @@ search(
string_new( buf );
/* Parse the filename */
- path_parse( target, f );
+ path_parse( object_str( target ), f );
f->f_grist.ptr = 0;
f->f_grist.len = 0;
- if ( ( varlist = var_get( "LOCATE" ) ) )
- {
- f->f_root.ptr = varlist->string;
- f->f_root.len = strlen( varlist->string );
+ varlist = var_get( root_module(), constant_LOCATE );
+ if ( !list_empty( varlist ) )
+ {
+ OBJECT * key;
+ f->f_root.ptr = object_str( list_front( varlist ) );
+ f->f_root.len = strlen( object_str( list_front( varlist ) ) );
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "locate %s: %s\n", target, buf->value );
+ printf( "locate %s: %s\n", object_str( target ), buf->value );
explicitly_located = 1;
- timestamp( buf->value, time );
+ key = object_new( buf->value );
+ timestamp( key, time );
+ object_free( key );
found = 1;
}
- else if ( ( varlist = var_get( "SEARCH" ) ) )
+ else if ( varlist = var_get( root_module(), constant_SEARCH ), !list_empty( varlist ) )
{
- while ( varlist )
+ LISTITER iter = list_begin( varlist ), end = list_end( varlist );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- BINDING b, *ba = &b;
+ BINDING * ba;
file_info_t *ff;
+ OBJECT * key;
+ OBJECT * test_path;
- f->f_root.ptr = varlist->string;
- f->f_root.len = strlen( varlist->string );
+ f->f_root.ptr = object_str( list_item( iter ) );
+ f->f_root.len = strlen( object_str( list_item( iter ) ) );
string_truncate( buf, 0 );
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "search %s: %s\n", target, buf->value );
-
- ff = file_query(buf->value);
- timestamp( buf->value, time );
+ printf( "search %s: %s\n", object_str( target ), buf->value );
- b.binding = buf->value;
+ test_path = object_new( buf->value );
+ key = path_as_key( test_path );
+ object_free( test_path );
+ ff = file_query( key );
+ timestamp( key, time );
- if ( hashcheck( explicit_bindings, (HASHDATA**)&ba ) )
+ if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
{
if ( DEBUG_SEARCH )
printf(" search %s: found explicitly located target %s\n",
- target, ba->target);
+ object_str( target ), object_str( ba->target ) );
if ( another_target )
*another_target = ba->target;
found = 1;
+ object_free( key );
break;
}
else if ( ff && ff->time )
@@ -175,11 +177,11 @@ search(
if ( !file || ff->is_file )
{
found = 1;
+ object_free( key );
break;
}
}
-
- varlist = list_next( varlist );
+ object_free( key );
}
}
@@ -188,6 +190,7 @@ search(
/* Look for the obvious */
/* This is a questionable move. Should we look in the */
/* obvious place if SEARCH is set? */
+ OBJECT * key;
f->f_root.ptr = 0;
f->f_root.len = 0;
@@ -196,24 +199,34 @@ search(
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "search %s: %s\n", target, buf->value );
+ printf( "search %s: %s\n", object_str( target ), buf->value );
- timestamp( buf->value, time );
+ key = object_new( buf->value );
+ timestamp( key, time );
+ object_free( key );
}
- boundname = newstr( buf->value );
+ boundname = object_new( buf->value );
string_free( buf );
if ( explicitly_located )
{
- BINDING b;
- BINDING * ba = &b;
- b.binding = boundname;
- b.target = target;
+ int found;
+ BINDING * ba;
+ OBJECT * key = path_as_key( boundname );
/* CONSIDER: we probably should issue a warning is another file
is explicitly bound to the same location. This might break
compatibility, though. */
- hashenter( explicit_bindings, (HASHDATA * *)&ba );
+ ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
+ if ( !found )
+ {
+ ba->binding = key;
+ ba->target = target;
+ }
+ else
+ {
+ object_free( key );
+ }
}
/* prepare a call to BINDRULE if the variable is set */
@@ -221,3 +234,19 @@ search(
return boundname;
}
+
+
+static void free_binding( void * xbinding, void * data )
+{
+ BINDING * binding = (BINDING *)xbinding;
+ object_free( binding->binding );
+}
+
+void search_done( void )
+{
+ if ( explicit_bindings )
+ {
+ hashenumerate( explicit_bindings, free_binding, (void *)0 );
+ hashdone( explicit_bindings );
+ }
+}
diff --git a/tools/build/v2/engine/search.h b/tools/build/v2/engine/search.h
index c364cac03b..0b6583996b 100644
--- a/tools/build/v2/engine/search.h
+++ b/tools/build/v2/engine/search.h
@@ -8,4 +8,13 @@
* search.h - find a target along $(SEARCH) or $(LOCATE)
*/
-char *search( char *target, time_t *time, char **another_target, int file );
+#ifndef SEARCH_SW20111118_H
+#define SEARCH_SW20111118_H
+
+#include "object.h"
+#include <time.h>
+
+OBJECT * search( OBJECT * target, time_t * time, OBJECT * * another_target, int file );
+void search_done( void );
+
+#endif
diff --git a/tools/build/v2/engine/subst.c b/tools/build/v2/engine/subst.c
index 75524ecc12..156670f1e9 100644
--- a/tools/build/v2/engine/subst.c
+++ b/tools/build/v2/engine/subst.c
@@ -3,62 +3,64 @@
#include "regexp.h"
#include "hash.h"
-#include "newstr.h"
+#include "object.h"
#include "lists.h"
-#include "parse.h"
#include "compile.h"
#include "frames.h"
+#include "builtins.h"
struct regex_entry
{
- const char* pattern;
+ OBJECT* pattern;
regexp* regex;
};
typedef struct regex_entry regex_entry;
static struct hash* regex_hash;
-regexp* regex_compile( const char* pattern )
+regexp* regex_compile( OBJECT* pattern )
{
- regex_entry entry, *e = &entry;
- entry.pattern = pattern;
+ int found;
+ regex_entry * e ;
if ( !regex_hash )
regex_hash = hashinit(sizeof(regex_entry), "regex");
- if ( hashenter( regex_hash, (HASHDATA **)&e ) )
+ e = (regex_entry *)hash_insert( regex_hash, pattern, &found );
+ if ( !found )
+ {
+ e->pattern = object_copy( pattern );
e->regex = regcomp( (char*)pattern );
+ }
return e->regex;
}
-LIST*
-builtin_subst(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_subst( FRAME * frame, int flags )
{
LIST* result = L0;
LIST* arg1 = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
- if ( arg1 && list_next(arg1) && list_next(list_next(arg1)) )
+ if ( iter != end && list_next( iter ) != end && list_next( list_next( iter ) ) != end )
{
- const char* source = arg1->string;
- const char* pattern = list_next(arg1)->string;
+ const char* source = object_str( list_item( iter ) );
+ OBJECT * pattern = list_item( list_next( iter ) );
regexp* repat = regex_compile( pattern );
if ( regexec( repat, (char*)source) )
{
- LIST* subst = list_next(arg1);
+ LISTITER subst = list_next( iter );
- while ((subst = list_next(subst)) != L0)
+ while ( ( subst = list_next( subst ) ) != end )
{
# define BUFLEN 4096
char buf[BUFLEN + 1];
- const char* in = subst->string;
+ const char* in = object_str( list_item( subst ) );
char* out = buf;
- for ( in = subst->string; *in && out < buf + BUFLEN; ++in )
+ for ( ; *in && out < buf + BUFLEN; ++in )
{
if ( *in == '\\' || *in == '$' )
{
@@ -83,7 +85,7 @@ builtin_subst(
}
*out = 0;
- result = list_new( result, newstr( buf ) );
+ result = list_push_back( result, object_new( buf ) );
#undef BUFLEN
}
}
@@ -92,3 +94,20 @@ builtin_subst(
return result;
}
+
+static void free_regex( void * xregex, void * data )
+{
+ regex_entry * regex = (regex_entry *)xregex;
+ object_free( regex->pattern );
+ BJAM_FREE( regex->regex );
+}
+
+
+void regex_done()
+{
+ if ( regex_hash )
+ {
+ hashenumerate( regex_hash, free_regex, (void *)0 );
+ hashdone( regex_hash );
+ }
+}
diff --git a/tools/build/v2/engine/timestamp.c b/tools/build/v2/engine/timestamp.c
index 8a59c8c0e0..6e4ed7326a 100644
--- a/tools/build/v2/engine/timestamp.c
+++ b/tools/build/v2/engine/timestamp.c
@@ -16,7 +16,7 @@
# include "filesys.h"
# include "pathsys.h"
# include "timestamp.h"
-# include "newstr.h"
+# include "object.h"
# include "strings.h"
/*
@@ -32,12 +32,12 @@
typedef struct _binding BINDING;
struct _binding {
- char *name;
- short flags;
+ OBJECT * name;
+ short flags;
# define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
- short progress;
+ short progress;
# define BIND_INIT 0 /* never seen */
# define BIND_NOENTRY 1 /* timestamp requested but file never found */
@@ -45,11 +45,11 @@ struct _binding {
# define BIND_MISSING 3 /* file found but can't get timestamp */
# define BIND_FOUND 4 /* file found and time stamped */
- time_t time; /* update time - 0 if not exist */
+ time_t time; /* update time - 0 if not exist */
};
static struct hash * bindhash = 0;
-static void time_enter( void *, char *, int, time_t );
+static void time_enter( void *, OBJECT *, int, time_t );
static char * time_progress[] =
{
@@ -65,49 +65,32 @@ static char * time_progress[] =
* timestamp() - return timestamp on a file, if present.
*/
-void timestamp( char * target, time_t * time )
+void timestamp( OBJECT * target, time_t * time )
{
PROFILE_ENTER( timestamp );
PATHNAME f1;
PATHNAME f2;
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
string buf[ 1 ];
-#ifdef DOWNSHIFT_PATHS
- string path;
- char * p;
-#endif
-#ifdef DOWNSHIFT_PATHS
- string_copy( &path, target );
- p = path.value;
+ target = path_as_key( target );
- do
- {
- *p = tolower( *p );
-#ifdef NT
- /* On NT, we must use backslashes or the file will not be found. */
- if ( *p == '/' )
- *p = PATH_DELIM;
-#endif
- }
- while ( *p++ );
-
- target = path.value;
-#endif /* #ifdef DOWNSHIFT_PATHS */
string_new( buf );
if ( !bindhash )
bindhash = hashinit( sizeof( BINDING ), "bindings" );
/* Quick path - is it there? */
- b->name = target;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( target ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, target, &found );
+ if ( !found )
+ {
+ b->name = object_copy( target ); /* never freed */
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+ }
if ( b->progress != BIND_INIT )
goto afterscanning;
@@ -115,37 +98,44 @@ void timestamp( char * target, time_t * time )
b->progress = BIND_NOENTRY;
/* Not found - have to scan for it. */
- path_parse( target, &f1 );
+ path_parse( object_str( target ), &f1 );
/* Scan directory if not already done so. */
{
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
+ OBJECT * name;
f2 = f1;
f2.f_grist.len = 0;
path_parent( &f2 );
path_build( &f2, buf, 0 );
- b->name = buf->value;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
+ name = object_new( buf->value );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( buf->value ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, name, &found );
+ if ( !found )
+ {
+ b->name = object_copy( name );
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+ }
if ( !( b->flags & BIND_SCANNED ) )
{
- file_dirscan( buf->value, time_enter, bindhash );
+ file_dirscan( name, time_enter, bindhash );
b->flags |= BIND_SCANNED;
}
+
+ object_free( name );
}
/* Scan archive if not already done so. */
if ( f1.f_member.len )
{
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
+ OBJECT * name;
f2 = f1;
f2.f_grist.len = 0;
@@ -153,18 +143,23 @@ void timestamp( char * target, time_t * time )
string_truncate( buf, 0 );
path_build( &f2, buf, 0 );
- b->name = buf->value;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
+ name = object_new( buf->value );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( buf->value ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, name, &found );
+ if ( !found )
+ {
+ b->name = object_copy( name );
+ b->time = b->flags = 0;
+ b->progress = BIND_INIT;
+ }
if ( !( b->flags & BIND_SCANNED ) )
{
file_archscan( buf->value, time_enter, bindhash );
b->flags |= BIND_SCANNED;
}
+
+ object_free( name );
}
afterscanning:
@@ -178,43 +173,41 @@ void timestamp( char * target, time_t * time )
*time = b->progress == BIND_FOUND ? b->time : 0;
string_free( buf );
-#ifdef DOWNSHIFT_PATHS
- string_free( &path );
-#endif
+
+ object_free( target );
PROFILE_EXIT( timestamp );
}
-static void time_enter( void * closure, char * target, int found, time_t time )
+static void time_enter( void * closure, OBJECT * target, int found, time_t time )
{
- BINDING binding;
- BINDING * b = &binding;
+ int item_found;
+ BINDING * b;
struct hash * bindhash = (struct hash *)closure;
-#ifdef DOWNSHIFT_PATHS
- char path[ MAXJPATH ];
- char * p = path;
-
- do *p++ = tolower( *target );
- while ( *target++ );
-
- target = path;
-#endif
-
- b->name = target;
- b->flags = 0;
+ target = path_as_key( target );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( target ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, target, &item_found );
+ if ( !item_found )
+ {
+ b->name = object_copy( target );
+ b->flags = 0;
+ }
b->time = time;
b->progress = found ? BIND_FOUND : BIND_SPOTTED;
if ( DEBUG_BINDSCAN )
- printf( "time ( %s ) : %s\n", target, time_progress[ b->progress ] );
+ printf( "time ( %s ) : %s\n", object_str( target ), time_progress[ b->progress ] );
+
+ object_free( target );
}
+static void free_timestamps ( void * xbinding, void * data )
+{
+ object_free( ((BINDING *)xbinding)->name );
+}
/*
* stamps_done() - free timestamp tables.
@@ -222,5 +215,9 @@ static void time_enter( void * closure, char * target, int found, time_t time )
void stamps_done()
{
- hashdone( bindhash );
+ if ( bindhash )
+ {
+ hashenumerate( bindhash, free_timestamps, (void *)0 );
+ hashdone( bindhash );
+ }
}
diff --git a/tools/build/v2/engine/timestamp.h b/tools/build/v2/engine/timestamp.h
index f575276393..26b7e8d1c9 100644
--- a/tools/build/v2/engine/timestamp.h
+++ b/tools/build/v2/engine/timestamp.h
@@ -8,5 +8,13 @@
* timestamp.h - get the timestamp of a file or archive member
*/
-void timestamp( char * target, time_t * time );
+#ifndef TIMESTAMP_H_SW_2011_11_18
+#define TIMESTAMP_H_SW_2011_11_18
+
+#include "object.h"
+#include "time.h"
+
+void timestamp( OBJECT * target, time_t * time );
void stamps_done();
+
+#endif
diff --git a/tools/build/v2/engine/variable.c b/tools/build/v2/engine/variable.c
index 795f345846..21eedf395a 100644
--- a/tools/build/v2/engine/variable.c
+++ b/tools/build/v2/engine/variable.c
@@ -16,12 +16,12 @@
#include "lists.h"
#include "parse.h"
#include "variable.h"
-#include "expand.h"
#include "hash.h"
#include "filesys.h"
-#include "newstr.h"
+#include "object.h"
#include "strings.h"
#include "pathsys.h"
+#include "modules.h"
#include <stdlib.h>
#include <stdio.h>
@@ -49,8 +49,6 @@
* 09/11/00 (seiwald) - defunct var_list() removed
*/
-static struct hash *varhash = 0;
-
/*
* VARIABLE - a user defined multi-value variable
*/
@@ -59,26 +57,12 @@ typedef struct _variable VARIABLE ;
struct _variable
{
- char * symbol;
- LIST * value;
+ OBJECT * symbol;
+ LIST * value;
};
-static VARIABLE * var_enter( char * symbol );
-static void var_dump( char * symbol, LIST * value, char * what );
-
-
-/*
- * var_hash_swap() - swap all variable settings with those passed
- *
- * Used to implement separate settings spaces for modules
- */
-
-void var_hash_swap( struct hash * * new_vars )
-{
- struct hash * old = varhash;
- varhash = *new_vars;
- *new_vars = old;
-}
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol );
+static void var_dump( OBJECT * symbol, LIST * value, char * what );
/*
@@ -94,7 +78,7 @@ void var_hash_swap( struct hash * * new_vars )
* Otherwise, split the value at blanks.
*/
-void var_defines( char * const * e, int preprocess )
+void var_defines( struct module_t * module, char * const * e, int preprocess )
{
string buf[1];
@@ -103,6 +87,7 @@ void var_defines( char * const * e, int preprocess )
for ( ; *e; ++e )
{
char * val;
+ OBJECT * varname;
# ifdef OS_MAC
/* On the mac (MPW), the var=val is actually var\0val */
@@ -133,7 +118,7 @@ void var_defines( char * const * e, int preprocess )
if ( quoted && preprocess )
{
string_append_range( buf, val + 2, val + len );
- l = list_new( l, newstr( buf->value ) );
+ l = list_push_back( l, object_new( buf->value ) );
string_truncate( buf, 0 );
}
else
@@ -156,16 +141,18 @@ void var_defines( char * const * e, int preprocess )
)
{
string_append_range( buf, pp, p );
- l = list_new( l, newstr( buf->value ) );
+ l = list_push_back( l, object_new( buf->value ) );
string_truncate( buf, 0 );
}
- l = list_new( l, newstr( pp ) );
+ l = list_push_back( l, object_new( pp ) );
}
/* Get name. */
string_append_range( buf, *e, val );
- var_set( buf->value, l, VAR_SET );
+ varname = object_new( buf->value );
+ var_set( module, varname, l, VAR_SET );
+ object_free( varname );
string_truncate( buf, 0 );
}
}
@@ -173,304 +160,7 @@ void var_defines( char * const * e, int preprocess )
}
-/*
- * var_string() - expand a string with variables in it
- *
- * Copies in to out; doesn't modify targets & sources.
- */
-
-int var_string( char * in, char * out, int outsize, LOL * lol )
-{
- char * out0 = out;
- char * oute = out + outsize - 1;
-
- while ( *in )
- {
- char * lastword;
- int dollar = 0;
-
- /* Copy white space. */
- while ( isspace( *in ) )
- {
- if ( out >= oute )
- return -1;
- *out++ = *in++;
- }
-
- lastword = out;
-
- /* Copy non-white space, watching for variables. */
- while ( *in && !isspace( *in ) )
- {
- if ( out >= oute )
- return -1;
-
- if ( ( in[ 0 ] == '$' ) && ( in[ 1 ] == '(' ) )
- {
- ++dollar;
- *out++ = *in++;
- }
- #ifdef OPT_AT_FILES
- else if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) )
- {
- int depth = 1;
- char * ine = in + 2;
- char * split = 0;
-
- /* Scan the content of the response file @() section. */
- while ( *ine && ( depth > 0 ) )
- {
- switch ( *ine )
- {
- case '(': ++depth; break;
- case ')': --depth; break;
- case ':':
- if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
- split = ine;
- break;
- }
- ++ine;
- }
-
- if ( !split )
- {
- /* the @() reference doesn't match the @(foo:E=bar) format.
- hence we leave it alone by copying directly to output. */
- int l = 0;
- if ( out + 2 >= oute ) return -1;
- *( out++ ) = '@';
- *( out++ ) = '(';
- l = var_string( in + 2, out, oute - out, lol );
- if ( l < 0 ) return -1;
- out += l;
- if ( out + 1 >= oute ) return -1;
- *( out++ ) = ')';
- }
- else if ( depth == 0 )
- {
- string file_name_v;
- int file_name_l = 0;
- const char * file_name_s = 0;
-
- /* Expand the temporary file name var inline. */
- #if 0
- string_copy( &file_name_v, "$(" );
- string_append_range( &file_name_v, in + 2, split );
- string_push_back( &file_name_v, ')' );
- #else
- string_new( &file_name_v );
- string_append_range( &file_name_v, in + 2, split );
- #endif
- file_name_l = var_string( file_name_v.value, out, oute - out + 1, lol );
- string_free( &file_name_v );
- if ( file_name_l < 0 ) return -1;
- file_name_s = out;
-
- /* For stdout/stderr we will create a temp file and generate
- * a command that outputs the content as needed.
- */
- if ( ( strcmp( "STDOUT", out ) == 0 ) ||
- ( strcmp( "STDERR", out ) == 0 ) )
- {
- int err_redir = strcmp( "STDERR", out ) == 0;
- out[ 0 ] = '\0';
- file_name_s = path_tmpfile();
- file_name_l = strlen(file_name_s);
- #ifdef OS_NT
- if ( ( out + 7 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
- return -1;
- sprintf( out,"type \"%s\"%s", file_name_s,
- err_redir ? " 1>&2" : "" );
- #else
- if ( ( out + 6 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
- return -1;
- sprintf( out,"cat \"%s\"%s", file_name_s,
- err_redir ? " 1>&2" : "" );
- #endif
- /* We also make sure that the temp files created by this
- * get nuked eventually.
- */
- file_remove_atexit( file_name_s );
- }
-
- /* Expand the file value into the file reference. */
- var_string_to_file( split + 3, ine - split - 4, file_name_s,
- lol );
-
- /* Continue on with the expansion. */
- out += strlen( out );
- }
-
- /* And continue with the parsing just past the @() reference. */
- in = ine;
- }
- #endif
- else
- {
- *out++ = *in++;
- }
- }
-
- /* Add zero to 'out' so that 'lastword' is correctly zero-terminated. */
- if ( out >= oute )
- return -1;
- /* Do not increment, intentionally. */
- *out = '\0';
-
- /* If a variable encountered, expand it and and embed the
- * space-separated members of the list in the output.
- */
- if ( dollar )
- {
- LIST * l = var_expand( L0, lastword, out, lol, 0 );
-
- out = lastword;
-
- while ( l )
- {
- int so = strlen( l->string );
-
- if ( out + so >= oute )
- return -1;
-
- strcpy( out, l->string );
- out += so;
- l = list_next( l );
- if ( l ) *out++ = ' ';
- }
-
- list_free( l );
- }
- }
-
- if ( out >= oute )
- return -1;
-
- *out++ = '\0';
-
- return out - out0;
-}
-
-
-void var_string_to_file( const char * in, int insize, const char * out, LOL * lol )
-{
- char const * ine = in + insize;
- FILE * out_file = 0;
- int out_debug = DEBUG_EXEC ? 1 : 0;
- if ( globs.noexec )
- {
- /* out_debug = 1; */
- }
- else if ( strcmp( out, "STDOUT" ) == 0 )
- {
- out_file = stdout;
- }
- else if ( strcmp( out, "STDERR" ) == 0 )
- {
- out_file = stderr;
- }
- else
- {
- /* Handle "path to file" filenames. */
- string out_name;
- if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) )
- {
- string_copy( &out_name, out + 1 );
- string_truncate( &out_name, out_name.size - 1 );
- }
- else
- {
- string_copy( &out_name,out );
- }
- out_file = fopen( out_name.value, "w" );
- if ( !out_file )
- {
- printf( "failed to write output file '%s'!\n", out_name.value );
- exit( EXITBAD );
- }
- string_free( &out_name );
- }
-
- if ( out_debug ) printf( "\nfile %s\n", out );
-
- while ( *in && ( in < ine ) )
- {
- int dollar = 0;
- const char * output_0 = in;
- const char * output_1 = in;
-
- /* Copy white space. */
- while ( ( output_1 < ine ) && isspace( *output_1 ) )
- ++output_1;
-
- if ( output_0 < output_1 )
- {
- if ( out_file ) fwrite( output_0, output_1 - output_0, 1, out_file );
- if ( out_debug ) fwrite( output_0, output_1 - output_0, 1, stdout );
- }
- output_0 = output_1;
-
- /* Copy non-white space, watching for variables. */
- while ( ( output_1 < ine ) && *output_1 && !isspace( *output_1 ) )
- {
- if ( ( output_1[ 0 ] == '$' ) && ( output_1[ 1 ] == '(' ) )
- ++dollar;
- ++output_1;
- }
-
- /* If a variable encountered, expand it and embed the space-separated
- * members of the list in the output.
- */
- if ( dollar )
- {
- LIST * l = var_expand( L0, (char *)output_0, (char *)output_1, lol, 0 );
-
- while ( l )
- {
- if ( out_file ) fputs( l->string, out_file );
- if ( out_debug ) puts( l->string );
- l = list_next( l );
- if ( l )
- {
- if ( out_file ) fputc( ' ', out_file );
- if ( out_debug ) fputc( ' ', stdout );
- }
- }
-
- list_free( l );
- }
- else if ( output_0 < output_1 )
- {
- if ( out_file )
- {
- const char * output_n = output_0;
- while ( output_n < output_1 )
- {
- output_n += fwrite( output_n, 1, output_1-output_n, out_file );
- }
- }
- if ( out_debug )
- {
- const char * output_n = output_0;
- while ( output_n < output_1 )
- {
- output_n += fwrite( output_n, 1, output_1-output_n, stdout );
- }
- }
- }
-
- in = output_1;
- }
-
- if ( out_file && ( out_file != stdout ) && ( out_file != stderr ) )
- {
- fflush( out_file );
- fclose( out_file );
- }
-
- if ( out_debug ) fputc( '\n', stdout );
-}
-
+static LIST * saved_var = L0;
/*
* var_get() - get value of a user defined symbol.
@@ -478,40 +168,49 @@ void var_string_to_file( const char * in, int insize, const char * out, LOL * lo
* Returns NULL if symbol unset.
*/
-LIST * var_get( char * symbol )
+LIST * var_get( struct module_t * module, OBJECT * symbol )
{
- LIST * result = 0;
+ LIST * result = L0;
#ifdef OPT_AT_FILES
/* Some "fixed" variables... */
- if ( strcmp( "TMPDIR", symbol ) == 0 )
+ if ( object_equal( symbol, constant_TMPDIR ) )
{
- result = list_new( L0, newstr( (char *)path_tmpdir() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_new( path_tmpdir() ) );
}
- else if ( strcmp( "TMPNAME", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_TMPNAME ) )
{
- result = list_new( L0, newstr( (char *)path_tmpnam() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( path_tmpnam() );
}
- else if ( strcmp( "TMPFILE", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_TMPFILE ) )
{
- result = list_new( L0, newstr( (char *)path_tmpfile() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( path_tmpfile() );
}
- else if ( strcmp( "STDOUT", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_STDOUT ) )
{
- result = list_new( L0, newstr( "STDOUT" ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_copy( constant_STDOUT ) );
}
- else if ( strcmp( "STDERR", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_STDERR ) )
{
- result = list_new( L0, newstr( "STDERR" ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_copy( constant_STDERR ) );
}
else
#endif
{
- VARIABLE var;
- VARIABLE * v = &var;
+ VARIABLE * v;
+ int n;
- v->symbol = symbol;
-
- if ( varhash && hashcheck( varhash, (HASHDATA * *)&v ) )
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ if ( DEBUG_VARGET )
+ var_dump( symbol, module->fixed_variables[ n ], "get" );
+ result = module->fixed_variables[ n ];
+ }
+ else if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
{
if ( DEBUG_VARGET )
var_dump( v->symbol, v->value, "get" );
@@ -522,6 +221,20 @@ LIST * var_get( char * symbol )
}
+LIST * var_get_and_clear_raw( module_t * module, OBJECT * symbol )
+{
+ LIST * result = L0;
+ VARIABLE * v;
+
+ if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
+ {
+ result = v->value;
+ v->value = L0;
+ }
+
+ return result;
+}
+
/*
* var_set() - set a variable in Jam's user defined symbol table.
*
@@ -532,9 +245,9 @@ LIST * var_get( char * symbol )
* Copies symbol. Takes ownership of value.
*/
-void var_set( char * symbol, LIST * value, int flag )
+void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag )
{
- VARIABLE * v = var_enter( symbol );
+ LIST * * v = var_enter( module, symbol );
if ( DEBUG_VARSET )
var_dump( symbol, value, "set" );
@@ -543,19 +256,19 @@ void var_set( char * symbol, LIST * value, int flag )
{
case VAR_SET:
/* Replace value */
- list_free( v->value );
- v->value = value;
+ list_free( *v );
+ *v = value;
break;
case VAR_APPEND:
/* Append value */
- v->value = list_append( v->value, value );
+ *v = list_append( *v, value );
break;
case VAR_DEFAULT:
/* Set only if unset */
- if ( !v->value )
- v->value = value;
+ if ( list_empty( *v ) )
+ *v = value;
else
list_free( value );
break;
@@ -567,13 +280,13 @@ void var_set( char * symbol, LIST * value, int flag )
* var_swap() - swap a variable's value with the given one.
*/
-LIST * var_swap( char * symbol, LIST * value )
+LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value )
{
- VARIABLE * v = var_enter( symbol );
- LIST * oldvalue = v->value;
+ LIST * * v = var_enter( module, symbol );
+ LIST * oldvalue = *v;
if ( DEBUG_VARSET )
var_dump( symbol, value, "set" );
- v->value = value;
+ *v = value;
return oldvalue;
}
@@ -582,21 +295,28 @@ LIST * var_swap( char * symbol, LIST * value )
* var_enter() - make new var symbol table entry, returning var ptr.
*/
-static VARIABLE * var_enter( char * symbol )
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol )
{
- VARIABLE var;
- VARIABLE * v = &var;
+ int found;
+ VARIABLE * v;
+ int n;
- if ( !varhash )
- varhash = hashinit( sizeof( VARIABLE ), "variables" );
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ return &module->fixed_variables[ n ];
+ }
- v->symbol = symbol;
- v->value = 0;
+ if ( !module->variables )
+ module->variables = hashinit( sizeof( VARIABLE ), "variables" );
- if ( hashenter( varhash, (HASHDATA * *)&v ) )
- v->symbol = newstr( symbol ); /* never freed */
+ v = (VARIABLE *)hash_insert( module->variables, symbol, &found );
+ if ( !found )
+ {
+ v->symbol = object_copy( symbol );
+ v->value = L0;
+ }
- return v;
+ return &v->value;
}
@@ -604,9 +324,9 @@ static VARIABLE * var_enter( char * symbol )
* var_dump() - dump a variable to stdout.
*/
-static void var_dump( char * symbol, LIST * value, char * what )
+static void var_dump( OBJECT * symbol, LIST * value, char * what )
{
- printf( "%s %s = ", what, symbol );
+ printf( "%s %s = ", what, object_str( symbol ) );
list_print( value );
printf( "\n" );
}
@@ -619,13 +339,15 @@ static void var_dump( char * symbol, LIST * value, char * what )
static void delete_var_( void * xvar, void * data )
{
VARIABLE * v = (VARIABLE *)xvar;
- freestr( v->symbol );
+ object_free( v->symbol );
list_free( v-> value );
}
-void var_done()
+void var_done( struct module_t * module )
{
- hashenumerate( varhash, delete_var_, (void *)0 );
- hashdone( varhash );
+ list_free( saved_var );
+ saved_var = L0;
+ hashenumerate( module->variables, delete_var_, (void *)0 );
+ hash_free( module->variables );
}
diff --git a/tools/build/v2/engine/variable.h b/tools/build/v2/engine/variable.h
index 5c49e3ca55..aa27d56d6b 100644
--- a/tools/build/v2/engine/variable.h
+++ b/tools/build/v2/engine/variable.h
@@ -8,22 +8,16 @@
* variable.h - handle jam multi-element variables
*/
-struct hash;
+#ifndef VARIABLE_SW20111119_H
+#define VARIABLE_SW20111119_H
-void var_defines( char* const *e, int preprocess );
-int var_string( char *in, char *out, int outsize, LOL *lol );
-LIST * var_get( char *symbol );
-void var_set( char *symbol, LIST *value, int flag );
-LIST * var_swap( char *symbol, LIST *value );
-void var_done();
-void var_hash_swap( struct hash** );
+struct module_t;
-/** Expands the "in" expression directly into the "out" file.
- The file can be one of: a path, STDOUT, or STDERR to send
- the output to a file overwriting previous content, to
- the console, or to the error output respectively.
-*/
-void var_string_to_file( const char * in, int insize, const char * out, LOL * lol );
+void var_defines( struct module_t * module, char * const * e, int preprocess );
+LIST * var_get( struct module_t * module, OBJECT * symbol );
+void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag );
+LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value );
+void var_done( struct module_t * module );
/*
* Defines for var_set().
@@ -33,3 +27,4 @@ void var_string_to_file( const char * in, int insize, const char * out, LOL * lo
# define VAR_APPEND 1 /* append to previous value */
# define VAR_DEFAULT 2 /* set only if no previous value */
+#endif
diff --git a/tools/build/v2/engine/w32_getreg.c b/tools/build/v2/engine/w32_getreg.c
index 5a06f43e92..dd2d0fc70c 100644
--- a/tools/build/v2/engine/w32_getreg.c
+++ b/tools/build/v2/engine/w32_getreg.c
@@ -9,7 +9,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
# if defined( OS_NT ) || defined( OS_CYGWIN )
# include "lists.h"
-# include "newstr.h"
+# include "object.h"
# include "parse.h"
# include "frames.h"
# include "strings.h"
@@ -57,12 +57,9 @@ static HKEY get_key(char const** path)
return p->value;
}
-LIST*
-builtin_system_registry(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry( FRAME * frame, int flags )
{
- char const* path = lol_get(frame->args, 0)->string;
+ char const* path = object_str( list_front( lol_get(frame->args, 0) ) );
LIST* result = L0;
HKEY key = get_key(&path);
@@ -74,10 +71,10 @@ builtin_system_registry(
DWORD type;
BYTE data[MAX_REGISTRY_DATA_LENGTH];
DWORD len = sizeof(data);
- LIST const* const field = lol_get(frame->args, 1);
+ LIST * const field = lol_get(frame->args, 1);
if ( ERROR_SUCCESS ==
- RegQueryValueEx(key, field ? field->string : 0, 0, &type, data, &len) )
+ RegQueryValueEx(key, field ? object_str( list_front( field ) ) : 0, 0, &type, data, &len) )
{
switch (type)
{
@@ -97,7 +94,7 @@ builtin_system_registry(
expanded->size = len - 1;
- result = list_new( result, newstr(expanded->value) );
+ result = list_push_back( result, object_new(expanded->value) );
string_free( expanded );
}
break;
@@ -107,7 +104,7 @@ builtin_system_registry(
char* s;
for (s = (char*)data; *s; s += strlen(s) + 1)
- result = list_new( result, newstr(s) );
+ result = list_push_back( result, object_new(s) );
}
break;
@@ -116,12 +113,12 @@ builtin_system_registry(
{
char buf[100];
sprintf( buf, "%u", *(PDWORD)data );
- result = list_new( result, newstr(buf) );
+ result = list_push_back( result, object_new(buf) );
}
break;
case REG_SZ:
- result = list_new( result, newstr((char*)data) );
+ result = list_push_back( result, object_new( (const char *)data ) );
break;
}
}
@@ -151,7 +148,7 @@ static LIST* get_subkey_names(HKEY key, char const* path)
)
{
name[name_size] = 0;
- result = list_append(result, list_new(0, newstr(name)));
+ result = list_append(result, list_new(object_new(name)));
}
RegCloseKey(key);
@@ -178,7 +175,7 @@ static LIST* get_value_names(HKEY key, char const* path)
)
{
name[name_size] = 0;
- result = list_append(result, list_new(0, newstr(name)));
+ result = list_append(result, list_new(object_new(name)));
}
RegCloseKey(key);
@@ -187,13 +184,10 @@ static LIST* get_value_names(HKEY key, char const* path)
return result;
}
-LIST*
-builtin_system_registry_names(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry_names( FRAME * frame, int flags )
{
- char const* path = lol_get(frame->args, 0)->string;
- char const* result_type = lol_get(frame->args, 1)->string;
+ char const* path = object_str( list_front( lol_get(frame->args, 0) ) );
+ char const* result_type = object_str( list_front( lol_get(frame->args, 1) ) );
HKEY key = get_key(&path);