diff options
Diffstat (limited to 'tools/build/v2/engine')
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 = ⌖ + 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 = < - 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 * *)<a ) ) - { - 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); |