diff --git a/historic/jam/doc/bjam.qbk b/historic/jam/doc/bjam.qbk index 3bb9bcaef..cef647050 100644 --- a/historic/jam/doc/bjam.qbk +++ b/historic/jam/doc/bjam.qbk @@ -618,14 +618,20 @@ If you omit the list of formal arguments, all checking is bypassed as in "classi [section Dependency Building] +[section =DEPENDS= ] + [pre -DEPENDS /targets1/ : /targets2/ ; +rule DEPENDS ( /targets1/ * : /targets2/ * ) ] Builds a direct dependency: makes each of /targets1/ depend on each of /targets2/. Generally, /targets1/ will be rebuilt if /targets2/ are themselves rebuilt are or are newer than /targets1/. +[endsect] + +[section =INCLUDES= ] + [pre -INCLUDES /targets1/ : /targets2/ ; +rule INCLUDES ( /targets1/ * : /targets2/ * ) ] Builds a sibling dependency: makes any target that depends on any of /targets1/ also depend on each of /targets2/. This reflects the dependencies that arise when one source file includes another: the object built from the source file depends both on the original and included source file, but the two sources files don't depend on each other. For example: @@ -639,60 +645,96 @@ INCLUDES foo.c : foo.h ; [endsect] +[endsect] + [section Modifying Binding] The six rules =ALWAYS=, =LEAVES=, =NOCARE=, =NOTFILE=, =NOUPDATE=, and =TEMPORARY= modify the dependency graph so that =bjam= treats the targets differently during its target binding phase. See Binding above. Normally, =bjam= updates a target if it is missing, if its filesystem modification time is older than any of its dependencies (recursively), or if any of its dependencies are being updated. This basic behavior can be changed by invoking the following rules: +[section =ALWAYS= ] + [pre -ALWAYS /targets/ ; +rule ALWAYS ( /targets/ * ) ] Causes /targets/ to be rebuilt regardless of whether they are up-to-date (they must still be in the dependency graph). This is used for the clean and uninstall targets, as they have no dependencies and would otherwise appear never to need building. It is best applied to targets that are also =NOTFILE= targets, but it can also be used to force a real file to be updated as well. +[endsect] + +[section =LEAVES= ] + [pre -LEAVES /targets/ ; +rule LEAVES ( /targets/ * ) ] Makes each of /targets/ depend only on its leaf sources, and not on any intermediate targets. This makes it immune to its dependencies being updated, as the "leaf" dependencies are those without their own dependencies and without updating actions. This allows a target to be updated only if original source files change. +[endsect] + +[section =NOCARE= ] + [pre -NOCARE /targets/ ; +rule NOCARE ( /targets/ * ) ] Causes =bjam= to ignore /targets/ that neither can be found nor have updating actions to build them. Normally for such targets =bjam= issues a warning and then skips other targets that depend on these missing targets. The =HdrRule= in =Jambase= uses =NOCARE= on the header file names found during header file scanning, to let =bjam= know that the included files may not exist. For example, if an `#include` is within an `#ifdef`, the included file may not actually be around. [warning For targets with build actions: if their build actions exit with a nonzero return code, dependent targets will still be built.] +[endsect] + +[section =NOTFILE= ] + [pre -NOTFILE /targets/ ; +rule NOTFILE ( /targets/ * ) ] Marks /targets/ as pseudotargets and not real files. No timestamp is checked, and so the actions on such a target are only executed if the target's dependencies are updated, or if the target is also marked with =ALWAYS=. The default =bjam= target "=all=" is a pseudotarget. In =Jambase=, =NOTFILE= is used to define several addition convenient pseudotargets. +[endsect] + +[section =NOUPDATE= ] + [pre -NOUPDATE /targets/ ; +rule NOUPDATE ( /targets/ * ) ] Causes the timestamps on /targets/ to be ignored. This has two effects: first, once the target has been created it will never be updated; second, manually updating target will not cause other targets to be updated. In =Jambase=, for example, this rule is applied to directories by the =MkDir= rule, because =MkDir= only cares that the target directory exists, not when it has last been updated. +[endsect] + +[section =TEMPORARY= ] + [pre -TEMPORARY /targets/ ; +rule TEMPORARY ( /targets/ * ) ] Marks /targets/ as temporary, allowing them to be removed after other targets that depend upon them have been updated. If a =TEMPORARY= target is missing, =bjam= uses the timestamp of the target's parent. =Jambase= uses =TEMPORARY= to mark object files that are archived in a library after they are built, so that they can be deleted after they are archived. +[endsect] + +[section =FAIL_EXPECTED= ] + [pre -FAIL_EXPECTED /targets/ ; +rule FAIL_EXPECTED ( /targets/ * ) ] For handling targets whose build actions are expected to fail (e.g. when testing that assertions or compile-time type checkin work properly), Boost Jam supplies the =FAIL_EXPECTED= rule in the same style as =NOCARE=, et. al. During target updating, the return code of the build actions for arguments to =FAIL_EXPECTED= is inverted: if it fails, building of dependent targets continues as though it succeeded. If it succeeds, dependent targets are skipped. +[endsect] + +[section =RMOLD= ] + [pre -RMOLD /targets/ ; +rule RMOLD ( /targets/ * ) ] =BJam= removes any target files that may exist on disk when the rule used to build those targets fails. However, targets whose dependencies fail to build are not removed by default. The =RMOLD= rule causes its arguments to be removed if any of their dependencies fail to build. +[endsect] + +[section =ISFILE= ] + [pre rule ISFILE ( /targets/ * ) ] @@ -703,16 +745,24 @@ rule ISFILE ( /targets/ * ) [endsect] +[endsect] + [section Utility] The two rules =ECHO= and =EXIT= are utility rules, used only in =bjam='s parsing phase. +[section =ECHO= ] + [pre -ECHO /args/ ; +rule ECHO ( /args/ * ) ] Blurts out the message /args/ to stdout. +[endsect] + +[section =EXIT= ] + [pre rule EXIT ( /message/ * : /result-value/ ? ) ] @@ -721,30 +771,46 @@ Blurts out the /message/ to stdout and then exits with a failure status if no /r "=Echo=", "=echo=", "=Exit=", and "=exit=" are accepted as aliases for =ECHO= and =EXIT=, since it is hard to tell that these are built-in rules and not part of the language, like "=include=". +[endsect] + +[section =GLOB= ] + The =GLOB= rule does filename globbing. [pre -GLOB /directories/ : /patterns/ : /downcase-opt/ +rule GLOB ( /directories/ * : /patterns/ * : /downcase-opt/ ? ) ] Using the same wildcards as for the patterns in the switch statement. It is invoked by being used as an argument to a rule invocation inside of "=[ ]=". For example: "[^FILES = \[ GLOB dir1 dir2 : *.c *.h \]]" sets =FILES= to the list of C source and header files in =dir1= and =dir2=. The resulting filenames are the full pathnames, including the directory, but the pattern is applied only to the file name without the directory. If /downcase-opt/ is supplied, filenames are converted to all-lowercase before matching against the pattern; you can use this to do case-insensitive matching using lowercase patterns. The paths returned will still have mixed case if the OS supplies them. On Windows NT and Cygwin, filenames are always downcased before matching. +[endsect] + +[section =MATCH= ] + The =MATCH= rule does pattern matching. [pre -MATCH /regexps/ : /list/ +rule MATCH ( /regexps/ + : /list/ * ) ] Matches the =egrep=(1) style regular expressions /regexps/ against the strings in /list/. The result is the concatenation of matching =()= subexpressions for each string in /list/, and for each regular expression in /regexps/. Only useful within the "=[ ]=" construct, to change the result into a list. +[endsect] + +[section =BACKTRACE= ] + [pre rule BACKTRACE ( ) ] Returns a list of quadruples: /filename/ /line/ /module/ /rulename/..., describing each shallower level of the call stack. This rule can be used to generate useful diagnostic messages from Jam rules. +[endsect] + +[section =UPDATE= ] + [pre rule UPDATE ( /targets/ * ) ] @@ -761,6 +827,10 @@ local previous-updates = \[ UPDATE \] ; UPDATE $(previous-updates) a-new-target ; ] +[endsect] + +[section =W32_GETREG= ] + [pre rule W32_GETREG ( /path/ : /data/ ? ) ] @@ -780,6 +850,44 @@ local PSDK-location = \[ W32_GETREG HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\MicrosoftSDK\\\\Directories : "Install Dir" \] ; ] +[endsect] + +[section =W32_GETREGNAMES= ] + +[pre +rule W32_GETREGNAMES ( /path/ : /result-type/ ) +] + +Defined only for win32 platform. It reads the registry of Windows. '/path/' is the location of the information, and '/result-type/' is either '=subkeys=' or '=values='. For more information on '/path/' format and constraints, please see =W32_GETREG=. + +Depending on '/result-type/', the rule returns one of the following: + +[variablelist + [[=subkeys=] [Names of all direct subkeys of '/path/'.]] + [[=values=] [Names of values contained in registry key given by '/path/'. The "default" value of the key appears in the returned list only if its value has been set in the registry.]] +] + +If '/result-type/' is not recognized, or requested data cannot be retrieved, the rule returns an empty list. +Example: + +[pre +local key = "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\App Paths" ; +local subkeys = \[ W32_GETREGNAMES "$(key)" : subkeys \] ; +for local subkey in $(subkeys) +{ + local values = \[ W32_GETREGNAMES "$(key)\\\\$(subkey)" : values \] ; + for local value in $(values) + { + local data = \[ W32_GETREG "$(key)\\\\$(subkey)" : "$(value)" \] ; + ECHO "Registry path: " $(key)\\\\$(subkey) ":" $(value) "=" $(data) ; + } +} +] + +[endsect] + +[section =SHELL= ] + [pre rule SHELL ( /command/ : * ) ] @@ -800,6 +908,8 @@ builtin rule, =COMMAND= can be used as an alias for =SHELL= in such a case. [endsect] +[endsect] + [section Flow-of-Control] =BJam= has several simple flow-of-control statements: diff --git a/historic/jam/src/builtins.c b/historic/jam/src/builtins.c index 6be62b9d2..02ae5908d 100644 --- a/historic/jam/src/builtins.c +++ b/historic/jam/src/builtins.c @@ -53,6 +53,7 @@ # if defined( OS_NT ) || defined( OS_CYGWIN ) LIST* builtin_system_registry( PARSE *parse, FRAME *frame ); +LIST* builtin_system_registry_names( PARSE *parse, FRAME *frame ); # endif int glob( char *s, char *c ); @@ -327,6 +328,12 @@ load_builtins() bind_builtin( "W32_GETREG", builtin_system_registry, 0, args ); } + + { + char * args[] = { "key_path", ":", "result-type", 0 }; + bind_builtin( "W32_GETREGNAMES", + builtin_system_registry_names, 0, args ); + } # endif { diff --git a/historic/jam/src/w32_getreg.c b/historic/jam/src/w32_getreg.c index 506d1e20e..8da65a558 100644 --- a/historic/jam/src/w32_getreg.c +++ b/historic/jam/src/w32_getreg.c @@ -1,6 +1,8 @@ -/* Copyright Paul Lin 2003. Distributed under the Boost */ -/* Software License, Version 1.0. (See accompanying */ -/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ +/* +Copyright Paul Lin 2003. Copyright 2006 Bojan Resnik. +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ # include "jam.h" @@ -15,7 +17,9 @@ # define WIN32_LEAN_AND_MEAN # include -# define MAX_REGISTRY_DATA_LENGTH 4096 +# define MAX_REGISTRY_DATA_LENGTH 4096 +# define MAX_REGISTRY_KEYNAME_LENGTH 256 +# define MAX_REGISTRY_VALUENAME_LENGTH 16384 typedef struct { @@ -33,6 +37,26 @@ static const KeyMap dlRootKeys[] = { { 0, 0 } }; +static HKEY get_key(char const** path) +{ + const KeyMap *p; + + for (p = dlRootKeys; p->name; ++p) + { + int n = strlen(p->name); + if (!strncmp(*path,p->name,n)) + { + if ((*path)[n] == '\\' || (*path)[n] == 0) + { + *path += n + 1; + break; + } + } + } + + return p->value; +} + LIST* builtin_system_registry( PARSE *parse, @@ -40,27 +64,8 @@ builtin_system_registry( { char const* path = lol_get(frame->args, 0)->string; LIST* result = L0; - HKEY key; + HKEY key = get_key(&path); - { - const KeyMap *p; - - for (p = dlRootKeys; p->name; ++p) - { - int n = strlen(p->name); - if (!strncmp(path,p->name,n)) - { - if (path[n] == '\\' || path[n] == 0) - { - path += n + 1; - break; - } - } - } - - key = p->value; - } - if ( key != 0 && ERROR_SUCCESS == RegOpenKeyEx(key, path, 0, KEY_QUERY_VALUE, &key) @@ -125,4 +130,78 @@ builtin_system_registry( return result; } +static LIST* get_subkey_names(HKEY key, char const* path) +{ + LIST* result = 0; + + if ( ERROR_SUCCESS == + RegOpenKeyEx(key, path, 0, KEY_ENUMERATE_SUB_KEYS, &key) + ) + { + char name[MAX_REGISTRY_KEYNAME_LENGTH]; + DWORD name_size = sizeof(name); + DWORD index; + FILETIME last_write_time; + + for ( index = 0; + ERROR_SUCCESS == RegEnumKeyEx( + key, index, name, &name_size, 0, 0, 0, &last_write_time); + ++index, + name_size = sizeof(name) + ) + { + name[name_size] = 0; + result = list_append(result, list_new(0, newstr(name))); + } + + RegCloseKey(key); + } + + return result; +} + +static LIST* get_value_names(HKEY key, char const* path) +{ + LIST* result = 0; + + if ( ERROR_SUCCESS == RegOpenKeyEx(key, path, 0, KEY_QUERY_VALUE, &key) ) + { + char name[MAX_REGISTRY_VALUENAME_LENGTH]; + DWORD name_size = sizeof(name); + DWORD index; + + for ( index = 0; + ERROR_SUCCESS == RegEnumValue( + key, index, name, &name_size, 0, 0, 0, 0); + ++index, + name_size = sizeof(name) + ) + { + name[name_size] = 0; + result = list_append(result, list_new(0, newstr(name))); + } + + RegCloseKey(key); + } + + return result; +} + +LIST* +builtin_system_registry_names( + PARSE *parse, + FRAME *frame ) +{ + char const* path = lol_get(frame->args, 0)->string; + char const* result_type = lol_get(frame->args, 1)->string; + + HKEY key = get_key(&path); + + if ( !strcmp(result_type, "subkeys") ) + return get_subkey_names(key, path); + if ( !strcmp(result_type, "values") ) + return get_value_names(key, path); + return 0; +} + # endif diff --git a/historic/jam/test/builtin_w32_getregnames.jam b/historic/jam/test/builtin_w32_getregnames.jam new file mode 100644 index 000000000..fdcdde8cb --- /dev/null +++ b/historic/jam/test/builtin_w32_getregnames.jam @@ -0,0 +1,46 @@ +#~ Copyright 2006 Rene Rivera. +#~ 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) + +ECHO --- Testing W32_GETREGNAMES builtin... ; + +local result = 0 ; +local rule error ( message * ) +{ + local b = [ BACKTRACE ] ; + ECHO "$(b[9]):$(b[10]): error:" $(message) ; +} +local rule assert ( expected * : test ? : obtained * ) +{ + test ?= "(==)" ; + local r = 0 ; + if $(test) = "(==)" && $(expected) != $(obtained) + { + error [FAILED] '$(expected)' $(test) '$(obtained)' ; + r = 1 ; + } + else if $(test) = "(!=)" && $(expected) = $(obtained) + { + error [FAILED] '$(expected)' $(test) '$(obtained)' ; + r = 1 ; + } + result = [ CALC $(result) + $(r) ] ; +} + +#~ --------------------------------------------------------------------- + +if $(NT) +{ + assert "Beep" "ExtendedSounds" + : (==) : [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" : values ] ; + assert "Beep" "ExtendedSounds" + : (==) : [ W32_GETREGNAMES "HKCU\\Control Panel\\Sound" : values ] ; + assert "Control" "Enum" "Hardware Profiles" "Services" + : (==) : [ W32_GETREGNAMES "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet" : subkeys ] ; + assert "Control" "Enum" "Hardware Profiles" "Services" + : (==) : [ W32_GETREGNAMES "HKLM\\SYSTEM\\CurrentControlSet" : subkeys ] ; +} + +#~ --------------------------------------------------------------------- + +EXIT --- Complete : $(result) ; diff --git a/historic/jam/test/test.bat b/historic/jam/test/test.bat index 7a058f3d0..d30203037 100644 --- a/historic/jam/test/test.bat +++ b/historic/jam/test/test.bat @@ -9,3 +9,4 @@ set BJAM=..\src\bin.ntx86\bjam @ECHO ON %BJAM% -f builtin_shell.jam +%BJAM% -f builtin_w32_getregnames.jam