summaryrefslogtreecommitdiff
path: root/jam-files/engine/builtins.c
diff options
context:
space:
mode:
authorChris Dyer <cdyer@cs.cmu.edu>2012-10-11 14:06:32 -0400
committerChris Dyer <cdyer@cs.cmu.edu>2012-10-11 14:06:32 -0400
commit9339c80d465545aec5a6dccfef7c83ca715bf11f (patch)
tree64c56d558331edad1db3832018c80e799551c39a /jam-files/engine/builtins.c
parent438dac41810b7c69fa10203ac5130d20efa2da9f (diff)
parentafd7da3b2338661657ad0c4e9eec681e014d37bf (diff)
Merge branch 'master' of https://github.com/redpony/cdec
Diffstat (limited to 'jam-files/engine/builtins.c')
-rw-r--r--jam-files/engine/builtins.c2310
1 files changed, 0 insertions, 2310 deletions
diff --git a/jam-files/engine/builtins.c b/jam-files/engine/builtins.c
deleted file mode 100644
index b28a484e..00000000
--- a/jam-files/engine/builtins.c
+++ /dev/null
@@ -1,2310 +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 "parse.h"
-#include "builtins.h"
-#include "rules.h"
-#include "filesys.h"
-#include "newstr.h"
-#include "regexp.h"
-#include "frames.h"
-#include "hash.h"
-#include "strings.h"
-#include "pwd.h"
-#include "pathsys.h"
-#include "make.h"
-#include "hdrmacro.h"
-#include "compile.h"
-#include "native.h"
-#include "variable.h"
-#include "timestamp.h"
-#include "md5.h"
-#include <ctype.h>
-
-#if defined(USE_EXECUNIX)
-# include <sys/types.h>
-# include <sys/wait.h>
-#else
-/*
- NT does not have wait() and associated macros, it uses the return value
- of system() instead. Status code group are documented at
- http://msdn.microsoft.com/en-gb/library/ff565436.aspx
-*/
-# define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0)
-# define WEXITSTATUS(w)(w)
-#endif
-
-/*
- * builtins.c - builtin jam rules
- *
- * External routines:
- *
- * load_builtin() - define builtin rules
- *
- * Internal routines:
- *
- * builtin_depends() - DEPENDS/INCLUDES rule.
- * builtin_echo() - ECHO rule.
- * builtin_exit() - EXIT rule.
- * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule.
- * builtin_glob() - GLOB rule.
- * builtin_match() - MATCH rule.
- *
- * 01/10/01 (seiwald) - split from compile.c
- */
-
-
-/*
- * compile_builtin() - define builtin rules
- */
-
-#define P0 (PARSE *)0
-#define C0 (char *)0
-
-#if defined( OS_NT ) || defined( OS_CYGWIN )
- LIST * builtin_system_registry ( PARSE *, FRAME * );
- LIST * builtin_system_registry_names( PARSE *, FRAME * );
-#endif
-
-int glob( char * s, char * c );
-
-void backtrace ( FRAME * );
-void backtrace_line ( FRAME * );
-void print_source_line( PARSE * );
-
-
-RULE * bind_builtin( char * name, LIST * (* f)( PARSE *, FRAME * ), int flags, char * * args )
-{
- argument_list* arg_list = 0;
-
- if ( args )
- {
- arg_list = args_new();
- lol_build( arg_list->data, args );
- }
-
- return new_rule_body( root_module(), name, arg_list,
- parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
-}
-
-
-RULE * duplicate_rule( char * name, RULE * other )
-{
- return import_rule( other, root_module(), name );
-}
-
-
-void load_builtins()
-{
- duplicate_rule( "Always",
- bind_builtin( "ALWAYS",
- builtin_flags, T_FLAG_TOUCHED, 0 ) );
-
- duplicate_rule( "Depends",
- bind_builtin( "DEPENDS",
- builtin_depends, 0, 0 ) );
-
- duplicate_rule( "echo",
- duplicate_rule( "Echo",
- bind_builtin( "ECHO",
- builtin_echo, 0, 0 ) ) );
-
- {
- char * args[] = { "message", "*", ":", "result-value", "?", 0 };
- duplicate_rule( "exit",
- duplicate_rule( "Exit",
- bind_builtin( "EXIT",
- builtin_exit, 0, args ) ) );
- }
-
- {
- char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
- duplicate_rule( "Glob",
- bind_builtin( "GLOB", builtin_glob, 0, args ) );
- }
-
- {
- char * args[] = { "patterns", "*", 0 };
- bind_builtin( "GLOB-RECURSIVELY",
- builtin_glob_recursive, 0, args );
- }
-
- duplicate_rule( "Includes",
- bind_builtin( "INCLUDES",
- builtin_depends, 1, 0 ) );
-
- {
- char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
- bind_builtin( "REBUILDS",
- builtin_rebuilds, 0, args );
- }
-
- duplicate_rule( "Leaves",
- bind_builtin( "LEAVES",
- builtin_flags, T_FLAG_LEAVES, 0 ) );
-
- duplicate_rule( "Match",
- bind_builtin( "MATCH",
- builtin_match, 0, 0 ) );
-
- {
- char * args[] = { "string", ":", "delimiters" };
- bind_builtin( "SPLIT_BY_CHARACTERS",
- builtin_split_by_characters, 0, 0 );
- }
-
- duplicate_rule( "NoCare",
- bind_builtin( "NOCARE",
- builtin_flags, T_FLAG_NOCARE, 0 ) );
-
- duplicate_rule( "NOTIME",
- duplicate_rule( "NotFile",
- bind_builtin( "NOTFILE",
- builtin_flags, T_FLAG_NOTFILE, 0 ) ) );
-
- duplicate_rule( "NoUpdate",
- bind_builtin( "NOUPDATE",
- builtin_flags, T_FLAG_NOUPDATE, 0 ) );
-
- duplicate_rule( "Temporary",
- bind_builtin( "TEMPORARY",
- builtin_flags, T_FLAG_TEMP, 0 ) );
-
- bind_builtin( "ISFILE",
- builtin_flags, T_FLAG_ISFILE, 0 );
-
- duplicate_rule( "HdrMacro",
- bind_builtin( "HDRMACRO",
- builtin_hdrmacro, 0, 0 ) );
-
- /* FAIL_EXPECTED is used to indicate that the result of a target build
- * action should be inverted (ok <=> fail) this can be useful when
- * performing test runs from Jamfiles.
- */
- bind_builtin( "FAIL_EXPECTED",
- builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
-
- bind_builtin( "RMOLD",
- builtin_flags, T_FLAG_RMOLD, 0 );
-
- {
- char * args[] = { "targets", "*", 0 };
- bind_builtin( "UPDATE",
- builtin_update, 0, args );
- }
-
- {
- char * args[] = { "targets", "*",
- ":", "log", "?",
- ":", "ignore-minus-n", "?",
- ":", "ignore-minus-q", "?", 0 };
- bind_builtin( "UPDATE_NOW",
- builtin_update_now, 0, args );
- }
-
- {
- char * args[] = { "string", "pattern", "replacements", "+", 0 };
- duplicate_rule( "subst",
- bind_builtin( "SUBST",
- builtin_subst, 0, args ) );
- }
-
- {
- char * args[] = { "module", "?", 0 };
- bind_builtin( "RULENAMES",
- builtin_rulenames, 0, args );
- }
-
-
- {
- char * args[] = { "module", "?", 0 };
- bind_builtin( "VARNAMES",
- builtin_varnames, 0, args );
- }
-
- {
- char * args[] = { "module", "?", 0 };
- bind_builtin( "DELETE_MODULE",
- builtin_delete_module, 0, args );
- }
-
- {
- char * args[] = { "source_module", "?",
- ":", "source_rules", "*",
- ":", "target_module", "?",
- ":", "target_rules", "*",
- ":", "localize", "?", 0 };
- bind_builtin( "IMPORT",
- builtin_import, 0, args );
- }
-
- {
- char * args[] = { "module", "?", ":", "rules", "*", 0 };
- bind_builtin( "EXPORT",
- builtin_export, 0, args );
- }
-
- {
- char * args[] = { "levels", "?", 0 };
- bind_builtin( "CALLER_MODULE",
- builtin_caller_module, 0, args );
- }
-
- {
- char * args[] = { "levels", "?", 0 };
- bind_builtin( "BACKTRACE",
- builtin_backtrace, 0, args );
- }
-
- {
- 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 };
- bind_builtin( "IMPORT_MODULE",
- builtin_import_module, 0, args );
- }
-
- {
- char * args[] = { "module", "?", 0 };
- bind_builtin( "IMPORTED_MODULES",
- builtin_imported_modules, 0, args );
- }
-
- {
- char * args[] = { "instance_module", ":", "class_module", 0 };
- bind_builtin( "INSTANCE",
- builtin_instance, 0, args );
- }
-
- {
- char * args[] = { "sequence", "*", 0 };
- bind_builtin( "SORT",
- builtin_sort, 0, args );
- }
-
- {
- char * args[] = { "path_parts", "*", 0 };
- bind_builtin( "NORMALIZE_PATH",
- builtin_normalize_path, 0, args );
- }
-
- {
- char * args[] = { "args", "*", 0 };
- bind_builtin( "CALC",
- builtin_calc, 0, args );
- }
-
- {
- char * args[] = { "module", ":", "rule", 0 };
- bind_builtin( "NATIVE_RULE",
- builtin_native_rule, 0, args );
- }
-
- {
- char * args[] = { "module", ":", "rule", ":", "version", 0 };
- bind_builtin( "HAS_NATIVE_RULE",
- builtin_has_native_rule, 0, args );
- }
-
- {
- char * args[] = { "module", "*", 0 };
- bind_builtin( "USER_MODULE",
- builtin_user_module, 0, args );
- }
-
- {
- char * args[] = { 0 };
- bind_builtin( "NEAREST_USER_LOCATION",
- builtin_nearest_user_location, 0, args );
- }
-
- {
- char * args[] = { "file", 0 };
- bind_builtin( "CHECK_IF_FILE",
- builtin_check_if_file, 0, args );
- }
-
-#ifdef HAVE_PYTHON
- {
- char * args[] = { "python-module", ":", "function", ":",
- "jam-module", ":", "rule-name", 0 };
- bind_builtin( "PYTHON_IMPORT_RULE",
- builtin_python_import_rule, 0, args );
- }
-#endif
-
-# if defined( OS_NT ) || defined( OS_CYGWIN )
- {
- char * args[] = { "key_path", ":", "data", "?", 0 };
- 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
-
- {
- char * args[] = { "command", ":", "*", 0 };
- duplicate_rule( "SHELL",
- bind_builtin( "COMMAND",
- builtin_shell, 0, args ) );
- }
-
- {
- char * args[] = { "string", 0 };
- bind_builtin( "MD5",
- builtin_md5, 0, args ) ;
- }
-
- {
- char * args[] = { "name", ":", "mode", 0 };
- bind_builtin( "FILE_OPEN",
- builtin_file_open, 0, args );
- }
-
- {
- char * args[] = { "string", ":", "width", 0 };
- bind_builtin( "PAD",
- builtin_pad, 0, args );
- }
-
- {
- char * args[] = { "targets", "*", 0 };
- bind_builtin( "PRECIOUS",
- builtin_precious, 0, args );
- }
-
- {
- char * args [] = { 0 };
- bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
- }
-
- {
- char * args [] = { "path", 0 };
- bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
- }
-
- /* Initialize builtin modules. */
- init_set();
- init_path();
- init_regex();
- init_property_set();
- init_sequence();
- init_order();
-}
-
-
-/*
- * builtin_calc() - CALC rule.
- *
- * The CALC rule performs simple mathematical operations on two arguments.
- */
-
-LIST * builtin_calc( PARSE * parse, FRAME * frame )
-{
- LIST * arg = lol_get( frame->args, 0 );
-
- LIST * result = 0;
- long lhs_value;
- long rhs_value;
- long result_value;
- char buffer [ 16 ];
- char const * lhs;
- char const * op;
- char const * rhs;
-
- if ( arg == 0 ) return L0;
- lhs = arg->string;
-
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- op = arg->string;
-
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- rhs = arg->string;
-
- lhs_value = atoi( lhs );
- rhs_value = atoi( rhs );
-
- if ( strcmp( "+", op ) == 0 )
- {
- result_value = lhs_value + rhs_value;
- }
- else if ( strcmp( "-", op ) == 0 )
- {
- result_value = lhs_value - rhs_value;
- }
- else
- {
- return L0;
- }
-
- sprintf( buffer, "%ld", result_value );
- result = list_new( result, newstr( buffer ) );
- return result;
-}
-
-
-/*
- * builtin_depends() - DEPENDS/INCLUDES rule.
- *
- * The DEPENDS/INCLUDES builtin rule appends each of the listed sources on the
- * dependency/includes list of each of the listed targets. It binds both the
- * targets and sources as TARGETs.
- */
-
-LIST * builtin_depends( PARSE * parse, FRAME * frame )
-{
- LIST * targets = lol_get( frame->args, 0 );
- LIST * sources = lol_get( frame->args, 1 );
- LIST * l;
-
- for ( l = targets; l; l = list_next( l ) )
- {
- TARGET * t = bindtarget( l->string );
-
- /* If doing INCLUDES, switch to the TARGET's include */
- /* TARGET, creating it if needed. The internal include */
- /* TARGET shares the name of its parent. */
-
- if ( parse->num )
- {
- if ( !t->includes )
- {
- t->includes = copytarget( t );
- t->includes->original_target = t;
- }
- t = t->includes;
- }
-
- t->depends = targetlist( t->depends, sources );
- }
-
- /* Enter reverse links */
- for ( l = sources; l; l = list_next( l ) )
- {
- TARGET * s = bindtarget( l->string );
- s->dependants = targetlist( s->dependants, targets );
- }
-
- return L0;
-}
-
-
-/*
- * builtin_rebuilds() - REBUILDS rule.
- *
- * The REBUILDS builtin rule appends each of the listed rebuild-targets in its
- * 2nd argument on the rebuilds list of each of the listed targets in its first
- * argument.
- */
-
-LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
-{
- LIST * targets = lol_get( frame->args, 0 );
- LIST * rebuilds = lol_get( frame->args, 1 );
- LIST * l;
-
- for ( l = targets; l; l = list_next( l ) )
- {
- TARGET * t = bindtarget( l->string );
- t->rebuilds = targetlist( t->rebuilds, rebuilds );
- }
-
- return L0;
-}
-
-
-/*
- * builtin_echo() - ECHO rule.
- *
- * The ECHO builtin rule echoes the targets to the user. No other actions are
- * taken.
- */
-
-LIST * builtin_echo( PARSE * parse, FRAME * frame )
-{
- list_print( lol_get( frame->args, 0 ) );
- printf( "\n" );
- fflush( stdout );
- return L0;
-}
-
-
-/*
- * builtin_exit() - EXIT rule.
- *
- * The EXIT builtin rule echoes the targets to the user and exits the program
- * with a failure status.
- */
-
-LIST * builtin_exit( PARSE * parse, FRAME * frame )
-{
- list_print( lol_get( frame->args, 0 ) );
- printf( "\n" );
- if ( lol_get( frame->args, 1 ) )
- {
- exit( atoi( lol_get( frame->args, 1 )->string ) );
- }
- else
- {
- exit( EXITBAD ); /* yeech */
- }
- return L0;
-}
-
-
-/*
- * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule.
- *
- * Builtin_flags() marks the target with the appropriate flag, for use by make0().
- * It binds each target as a TARGET.
- */
-
-LIST * builtin_flags( PARSE * parse, FRAME * frame )
-{
- LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = list_next( l ) )
- bindtarget( l->string )->flags |= parse->num;
- return L0;
-}
-
-
-/*
- * builtin_globbing() - GLOB rule.
- */
-
-struct globbing
-{
- LIST * patterns;
- LIST * results;
- LIST * case_insensitive;
-};
-
-
-static void downcase_inplace( char * p )
-{
- for ( ; *p; ++p )
- *p = tolower( *p );
-}
-
-
-static void builtin_glob_back
-(
- void * closure,
- char * file,
- int status,
- time_t time
-)
-{
- PROFILE_ENTER( BUILTIN_GLOB_BACK );
-
- struct globbing * globbing = (struct globbing *)closure;
- LIST * l;
- PATHNAME f;
- string buf[ 1 ];
-
- /* Null out directory for matching. We wish we had file_dirscan() pass up a
- * PATHNAME.
- */
- path_parse( 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
- * GLOB would want to see them. We could also change file_dirscan(), but
- * then paths with embedded "." and ".." would not work anywhere.
- */
- if ( !strcmp( f.f_base.ptr, "." ) || !strcmp( f.f_base.ptr, ".." ) )
- {
- PROFILE_EXIT( BUILTIN_GLOB_BACK );
- return;
- }
-
- string_new( buf );
- path_build( &f, buf, 0 );
-
- if ( globbing->case_insensitive )
- downcase_inplace( buf->value );
-
- for ( l = globbing->patterns; l; l = l->next )
- {
- if ( !glob( l->string, buf->value ) )
- {
- globbing->results = list_new( globbing->results, newstr( file ) );
- break;
- }
- }
-
- string_free( buf );
-
- PROFILE_EXIT( BUILTIN_GLOB_BACK );
-}
-
-
-static LIST * downcase_list( LIST * in )
-{
- LIST * result = 0;
-
- string s[ 1 ];
- string_new( s );
-
- while ( in )
- {
- string_copy( s, in->string );
- downcase_inplace( s->value );
- result = list_append( result, list_new( 0, newstr( s->value ) ) );
- in = in->next;
- }
-
- string_free( s );
- return result;
-}
-
-
-LIST * builtin_glob( PARSE * parse, FRAME * frame )
-{
- LIST * l = lol_get( frame->args, 0 );
- LIST * r = lol_get( frame->args, 1 );
-
- struct globbing globbing;
-
- globbing.results = L0;
- globbing.patterns = r;
-
- globbing.case_insensitive
-# if defined( OS_NT ) || defined( OS_CYGWIN )
- = l; /* Always case-insensitive if any files can be found. */
-# else
- = lol_get( frame->args, 2 );
-# endif
-
- if ( globbing.case_insensitive )
- globbing.patterns = downcase_list( r );
-
- for ( ; l; l = list_next( l ) )
- file_dirscan( l->string, builtin_glob_back, &globbing );
-
- if ( globbing.case_insensitive )
- list_free( globbing.patterns );
-
- return globbing.results;
-}
-
-
-static int has_wildcards( char const * str )
-{
- size_t const index = strcspn( str, "[]*?" );
- return str[ index ] == '\0' ? 0 : 1;
-}
-
-
-/*
- * If 'file' exists, append 'file' to 'list'. Returns 'list'.
- */
-
-static LIST * append_if_exists( LIST * list, char * file )
-{
- time_t time;
- timestamp( file, &time );
- return time > 0
- ? list_new( list, newstr( file ) )
- : list;
-}
-
-
-LIST * glob1( char * dirname, char * pattern )
-{
- LIST * plist = list_new( L0, pattern );
- struct globbing globbing;
-
- globbing.results = L0;
- globbing.patterns = plist;
-
- globbing.case_insensitive
-# if defined( OS_NT ) || defined( OS_CYGWIN )
- = plist; /* always case-insensitive if any files can be found */
-# else
- = L0;
-# endif
-
- if ( globbing.case_insensitive )
- globbing.patterns = downcase_list( plist );
-
- file_dirscan( dirname, builtin_glob_back, &globbing );
-
- if ( globbing.case_insensitive )
- list_free( globbing.patterns );
-
- list_free( plist );
-
- return globbing.results;
-}
-
-
-LIST * glob_recursive( char * pattern )
-{
- LIST * result = L0;
-
- /* Check if there's metacharacters in pattern */
- if ( !has_wildcards( pattern ) )
- {
- /* No metacharacters. Check if the path exists. */
- result = append_if_exists(result, pattern);
- }
- else
- {
- /* Have metacharacters in the pattern. Split into dir/name. */
- PATHNAME path[ 1 ];
- path_parse( pattern, path );
-
- if ( path->f_dir.ptr )
- {
- LIST * dirs = L0;
- string dirname[ 1 ];
- string basename[ 1 ];
- string_new( dirname );
- string_new( basename );
-
- string_append_range( dirname, path->f_dir.ptr,
- path->f_dir.ptr + path->f_dir.len );
-
- path->f_grist.ptr = 0;
- path->f_grist.len = 0;
- path->f_dir.ptr = 0;
- path->f_dir.len = 0;
- path_build( path, basename, 0 );
-
- dirs = has_wildcards( dirname->value )
- ? glob_recursive( dirname->value )
- : list_new( dirs, dirname->value );
-
- if ( has_wildcards( basename->value ) )
- {
- for ( ; dirs; dirs = dirs->next )
- result = list_append( result, glob1( dirs->string,
- basename->value ) );
- }
- else
- {
- string file_string[ 1 ];
- string_new( file_string );
-
- /* No wildcard in basename. */
- for ( ; dirs; dirs = dirs->next )
- {
- path->f_dir.ptr = dirs->string;
- path->f_dir.len = strlen( dirs->string );
- path_build( path, file_string, 0 );
-
- result = append_if_exists( result, file_string->value );
-
- string_truncate( file_string, 0 );
- }
-
- string_free( file_string );
- }
-
- string_free( dirname );
- string_free( basename );
- }
- else
- {
- /** No directory, just a pattern. */
- result = list_append( result, glob1( ".", pattern ) );
- }
- }
-
- return result;
-}
-
-
-LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
-{
- LIST * result = L0;
- LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = l->next )
- result = list_append( result, glob_recursive( l->string ) );
- return result;
-}
-
-
-/*
- * builtin_match() - MATCH rule, regexp matching.
- */
-
-LIST * builtin_match( PARSE * parse, FRAME * frame )
-{
- LIST * l;
- LIST * r;
- LIST * result = 0;
-
- string buf[ 1 ];
- string_new( buf );
-
- /* For each pattern */
-
- for ( l = lol_get( frame->args, 0 ); l; l = l->next )
- {
- /* Result is cached and intentionally never freed. */
- regexp * re = regex_compile( l->string );
-
- /* For each string to match against. */
- for ( r = lol_get( frame->args, 1 ); r; r = r->next )
- {
- if ( regexec( re, r->string ) )
- {
- int i;
- int top;
-
- /* Find highest parameter */
-
- for ( top = NSUBEXP; top-- > 1; )
- if ( re->startp[ top ] )
- break;
-
- /* And add all parameters up to highest onto list. */
- /* Must have parameters to have results! */
- for ( i = 1; i <= top; ++i )
- {
- string_append_range( buf, re->startp[ i ], re->endp[ i ] );
- result = list_new( result, newstr( buf->value ) );
- string_truncate( buf, 0 );
- }
- }
- }
- }
-
- string_free( buf );
- return result;
-}
-
-LIST * builtin_split_by_characters( PARSE * parse, FRAME * frame )
-{
- LIST * l1 = lol_get( frame->args, 0 );
- LIST * l2 = lol_get( frame->args, 1 );
-
- LIST * result = 0;
-
- char* s = strdup (l1->string);
- char* delimiters = l2->string;
- char* t;
-
- t = strtok (s, delimiters);
- while (t)
- {
- result = list_new(result, newstr(t));
- t = strtok (NULL, delimiters);
- }
-
- free (s);
-
- return result;
-}
-
-LIST * builtin_hdrmacro( PARSE * parse, FRAME * frame )
-{
- LIST * l = lol_get( frame->args, 0 );
-
- for ( ; l; l = list_next( l ) )
- {
- TARGET * t = bindtarget( l->string );
-
- /* Scan file for header filename macro definitions. */
- if ( DEBUG_HEADER )
- printf( "scanning '%s' for header file macro definitions\n",
- l->string );
-
- macro_headers( t );
- }
-
- return L0;
-}
-
-
-/*
- * builtin_rulenames() - RULENAMES ( MODULE ? ).
- *
- * Returns a list of the non-local rule names in the given MODULE. If MODULE is
- * not supplied, returns the list of rule names in the global module.
- */
-
-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 ) );
-}
-
-
-LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
-{
- LIST * arg0 = lol_get( frame->args, 0 );
- LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
-
- if ( source_module->rules )
- hashenumerate( source_module->rules, add_rule_name, &result );
- return result;
-}
-
-
-/*
- * builtin_varnames() - VARNAMES ( MODULE ? ).
- *
- * Returns a list of the variable names in the given MODULE. If MODULE is not
- * supplied, returns the list of variable names in the global module.
- */
-
-/* helper function for builtin_varnames(), below. Used with hashenumerate, will
- * prepend the key of each element to the list
- */
-static void add_hash_key( void * np, void * result_ )
-{
- LIST * * result = (LIST * *)result_;
- *result = list_new( *result, copystr( *(char * *)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 * arg0 = lol_get( frame->args, 0 );
- LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 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;
-
- if ( vars )
- hashenumerate( vars, add_hash_key, &result );
- return result;
-}
-
-
-/*
- * builtin_delete_module() - MODULE ?.
- *
- * Clears all rules and variables from the given module.
- */
-
-LIST * builtin_delete_module( PARSE * parse, FRAME * frame )
-{
- LIST * arg0 = lol_get( frame->args, 0 );
- LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
- delete_module( source_module );
- return result;
-}
-
-
-static void unknown_rule( FRAME * frame, char * key, char * module_name, char * rule_name )
-{
- backtrace_line( frame->prev );
- printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
- backtrace( frame->prev );
- exit( 1 );
-}
-
-
-/*
- * builtin_import() - IMPORT
- * (
- * SOURCE_MODULE ? :
- * SOURCE_RULES * :
- * TARGET_MODULE ? :
- * TARGET_RULES * :
- * LOCALIZE ?
- * )
- *
- * The IMPORT rule imports rules from the SOURCE_MODULE into the TARGET_MODULE
- * as local rules. If either SOURCE_MODULE or TARGET_MODULE is not supplied, it
- * refers to the global module. SOURCE_RULES specifies which rules from the
- * SOURCE_MODULE to import; TARGET_RULES specifies the names to give those rules
- * in TARGET_MODULE. If SOURCE_RULES contains a name which doesn't correspond to
- * a rule in SOURCE_MODULE, or if it contains a different number of items than
- * TARGET_RULES, an error is issued. If LOCALIZE is specified, the rules will be
- * executed in TARGET_MODULE, with corresponding access to its module local
- * variables.
- */
-
-LIST * builtin_import( PARSE * parse, FRAME * frame )
-{
- LIST * source_module_list = lol_get( frame->args, 0 );
- LIST * source_rules = lol_get( frame->args, 1 );
- LIST * target_module_list = lol_get( frame->args, 2 );
- LIST * target_rules = lol_get( frame->args, 3 );
- LIST * localize = lol_get( frame->args, 4 );
-
- module_t * target_module =
- bindmodule( target_module_list ? target_module_list->string : 0 );
- module_t * source_module =
- bindmodule( source_module_list ? source_module_list->string : 0 );
-
- LIST * source_name;
- LIST * target_name;
-
- 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 ) )
- {
- RULE r_;
- RULE * r = &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 );
-
- imported = import_rule( r, target_module, target_name->string );
- if ( localize )
- imported->module = 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 )
- {
- backtrace_line( frame->prev );
- printf( "import error: length of source and target rule name lists don't match!\n" );
- printf( " source: " );
- list_print( source_rules );
- printf( "\n target: " );
- list_print( target_rules );
- printf( "\n" );
- backtrace( frame->prev );
- exit( 1 );
- }
-
- return L0;
-}
-
-
-/*
- * builtin_export() - EXPORT ( MODULE ? : RULES * ).
- *
- * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local (and thus
- * exportable). If an element of RULES does not name a rule in MODULE, an error
- * is issued.
- */
-
-LIST * builtin_export( PARSE * parse, FRAME * frame )
-{
- 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 );
-
- for ( ; rules; rules = list_next( rules ) )
- {
- RULE r_;
- RULE * r = &r_;
- r_.name = rules->string;
-
- if ( !m->rules || !hashcheck( m->rules, (HASHDATA * *)&r ) )
- unknown_rule( frame, "EXPORT", m->name, r_.name );
-
- r->exported = 1;
- }
- return L0;
-}
-
-
-/*
- * get_source_line() - Retrieve the file and line number that should be
- * indicated for a given procedure in debug output or an error backtrace.
- */
-
-static void get_source_line( PARSE * procedure, char * * file, int * line )
-{
- if ( procedure )
- {
- char * f = procedure->file;
- int l = procedure->line;
- if ( !strcmp( f, "+" ) )
- {
- f = "jambase.c";
- l += 3;
- }
- *file = f;
- *line = l;
- }
- else
- {
- *file = "(builtin)";
- *line = -1;
- }
-}
-
-
-void print_source_line( PARSE * p )
-{
- char * file;
- int line;
-
- get_source_line( p, &file, &line );
- if ( line < 0 )
- printf( "(builtin):" );
- else
- printf( "%s:%d:", file, line );
-}
-
-
-/*
- * backtrace_line() - print a single line of error backtrace for the given
- * frame.
- */
-
-void backtrace_line( FRAME * frame )
-{
- if ( frame == 0 )
- {
- printf( "(no frame):" );
- }
- else
- {
- print_source_line( frame->procedure );
- printf( " in %s\n", frame->rulename );
- }
-}
-
-
-/*
- * backtrace() - Print the entire backtrace from the given frame to the Jambase
- * which invoked it.
- */
-
-void backtrace( FRAME * frame )
-{
- if ( !frame ) return;
- while ( ( frame = frame->prev ) )
- backtrace_line( frame );
-}
-
-
-/*
- * builtin_backtrace() - A Jam version of the backtrace function, taking no
- * arguments and returning a list of quadruples: FILENAME LINE MODULE. RULENAME
- * describing each frame. Note that the module-name is always followed by a
- * period.
- */
-
-LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
-{
- LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : ( (unsigned int)(-1) >> 1 ) ;
-
- LIST * result = L0;
- for ( ; ( frame = frame->prev ) && levels ; --levels )
- {
- char * file;
- int line;
- char buf[32];
- get_source_line( frame->procedure, &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 ) );
- }
- return result;
-}
-
-
-/*
- * builtin_caller_module() - CALLER_MODULE ( levels ? )
- *
- * If levels is not supplied, returns the name of the module of the rule which
- * called the one calling this one. If levels is supplied, it is interpreted as
- * an integer specifying a number of additional levels of call stack to traverse
- * in order to locate the module in question. If no such module exists, returns
- * the empty list. Also returns the empty list when the module in question is
- * the global module. This rule is needed for implementing module import
- * behavior.
- */
-
-LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
-{
- LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : 0 ;
-
- int i;
- for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
- frame = frame->prev;
-
- 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;
- }
-}
-
-
-/*
- * Return the current working directory.
- *
- * Usage: pwd = [ PWD ] ;
- */
-
-LIST * builtin_pwd( PARSE * parse, FRAME * frame )
-{
- return pwd();
-}
-
-
-/*
- * Adds targets to the list of target that jam will attempt to update.
- */
-
-LIST * builtin_update( PARSE * parse, FRAME * frame )
-{
- LIST * result = list_copy( L0, targets_to_update() );
- LIST * arg1 = lol_get( frame->args, 0 );
- clear_targets_to_update();
- for ( ; arg1; arg1 = list_next( arg1 ) )
- mark_target_for_updating( newstr( arg1->string ) );
- return result;
-}
-
-extern int anyhow;
-int last_update_now_status;
-
-/* Takes a list of target names as first argument, and immediately
- updates them.
- Second parameter, if specified, if the descriptor (converted to a string)
- of a log file where all build output is redirected.
- 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 * 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;
-
-
- if (log)
- {
- int fd = atoi(log->string);
- /* Redirect stdout and stderr, temporary, to the log file. */
- original_stdout = dup (0);
- original_stderr = dup (1);
- dup2 (fd, 0);
- dup2 (fd, 1);
- }
-
- if (force)
- {
- original_noexec = globs.noexec;
- globs.noexec = 0;
- original_quitquick = globs.quitquick;
- globs.quitquick = 0;
- }
-
- if (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 );
-
- if (force)
- {
- globs.noexec = original_noexec;
- globs.quitquick = original_quitquick;
- }
-
- if (continue_)
- {
- globs.quitquick = original_quitquick;
- }
-
- if (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);
- }
-
- last_update_now_status = status;
-
- if (status == 0)
- return list_new (L0, newstr ("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 * arg1 = lol_get( frame->args, 0 );
- LIST * arg2 = lol_get( frame->args, 1 );
- module_t * m = arg2 ? bindmodule( arg2->string ) : root_module();
- import_module( arg1, m );
- return L0;
-}
-
-
-LIST * builtin_imported_modules( PARSE * parse, FRAME * frame )
-{
- LIST * arg0 = lol_get( frame->args, 0 );
- return imported_modules( bindmodule( arg0 ? arg0->string : 0 ) );
-}
-
-
-LIST * builtin_instance( PARSE * parse, FRAME * frame )
-{
- 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 );
- instance->class_module = class_module;
- return L0;
-}
-
-
-LIST * builtin_sort( PARSE * parse, FRAME * frame )
-{
- LIST * arg1 = lol_get( frame->args, 0 );
- return list_sort( arg1 );
-}
-
-
-LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
-{
- LIST * arg = lol_get( frame->args, 0 );
-
- /* First, we iterate over all '/'-separated elements, starting from the end
- * of string. If we see a '..', we remove a previous path elements. If we
- * see '.', we remove it. The removal is done by overwriting data using '\1'
- * in the string. After the whole string has been processed, we do a second
- * pass, removing all the entered '\1' characters.
- */
-
- string in[ 1 ];
- string out[ 1 ];
- /* Last character of the part of string still to be processed. */
- char * end;
- /* Working pointer. */
- char * current;
- /* Number of '..' elements seen and not processed yet. */
- int dotdots = 0;
- int rooted = 0;
- char * result = 0;
-
- /* 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
- * rooted or not.
- */
- string_new( in );
- string_push_back( in, '/' );
- for ( ; arg; arg = list_next( arg ) )
- {
- if ( arg->string[ 0 ] != '\0' )
- {
- if ( in->size == 1 )
- rooted = ( ( arg->string[ 0 ] == '/' ) ||
- ( arg->string[ 0 ] == '\\' ) );
- else
- string_append( in, "/" );
- string_append( in, arg->string );
- }
- }
-
- /* Convert \ into /. On Windows, paths using / and \ are equivalent, and we
- * want this function to obtain a canonic representation.
- */
- for ( current = in->value, end = in->value + in->size;
- current < end; ++current )
- if ( *current == '\\' )
- *current = '/';
-
- /* Now we remove any extra path elements by overwriting them with '\1'
- * characters and cound how many more unused '..' path elements there are
- * remaining. Note that each remaining path element with always starts with
- * a '/' character.
- */
- for ( end = in->value + in->size - 1; end >= in->value; )
- {
- /* Set 'current' to the next occurence of '/', which always exists. */
- for ( current = end; *current != '/'; --current );
-
- if ( current == end )
- {
- /* Found a trailing or duplicate '/'. Remove it. */
- *current = '\1';
- }
- else if ( ( end - current == 1 ) && ( *(current + 1) == '.' ) )
- {
- /* Found '/.'. Remove them all. */
- *current = '\1';
- *(current + 1) = '\1';
- }
- else if ( ( end - current == 2 ) && ( *(current + 1) == '.' ) && ( *(current + 2) == '.' ) )
- {
- /* Found '/..'. Remove them all. */
- *current = '\1';
- *(current + 1) = '\1';
- *(current + 2) = '\1';
- ++dotdots;
- }
- else if ( dotdots )
- {
- memset( current, '\1', end - current + 1 );
- --dotdots;
- }
- end = current - 1;
- }
-
- string_new( out );
-
- /* Now we know that we need to add exactly dotdots '..' path elements to the
- * front and that our string is either empty or has a '/' as its first
- * significant character. If we have any dotdots remaining then the passed
- * path must not have been rooted or else it is invalid we return an empty
- * list.
- */
- if ( dotdots )
- {
- if ( rooted ) return L0;
- do
- string_append( out, "/.." );
- while ( --dotdots );
- }
-
- /* Now we actually remove all the path characters marked for removal. */
- for ( current = in->value; *current; ++current )
- if ( *current != '\1' )
- string_push_back( out, *current );
-
- /* Here we know that our string contains no '\1' characters and is either
- * empty or has a '/' as its initial character. If the original path was not
- * rooted and we have a non-empty path we need to drop the initial '/'. If
- * 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 ? "/" : "." ) );
-
- string_free( out );
- string_free( in );
-
- return list_new( 0, result );
-}
-
-
-LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
-{
- LIST * module_name = lol_get( frame->args, 0 );
- LIST * rule_name = lol_get( frame->args, 1 );
-
- module_t * module = bindmodule( module_name->string );
-
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
- {
- new_rule_body( module, np->name, np->arguments, np->procedure, 1 );
- }
- else
- {
- backtrace_line( frame->prev );
- printf( "error: no native rule \"%s\" defined in module \"%s\"\n",
- n.name, module->name );
- backtrace( frame->prev );
- exit( 1 );
- }
- return L0;
-}
-
-
-LIST * builtin_has_native_rule( PARSE * parse, FRAME * frame )
-{
- 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 );
-
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
- {
- int expected_version = atoi( version->string );
- if ( np->version == expected_version )
- return list_new( 0, newstr( "true" ) );
- }
- return L0;
-}
-
-
-LIST * builtin_user_module( PARSE * parse, FRAME * frame )
-{
- LIST * module_name = lol_get( frame->args, 0 );
- for ( ; module_name; module_name = module_name->next )
- {
- module_t * m = bindmodule( module_name->string );
- m->user_module = 1;
- }
- return L0;
-}
-
-
-LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
-{
- FRAME * nearest_user_frame =
- frame->module->user_module ? frame : frame->prev_user;
- if ( !nearest_user_frame )
- return L0;
-
- {
- LIST * result = 0;
- char * file;
- int line;
- char buf[32];
-
- get_source_line( nearest_user_frame->procedure, &file, &line );
- sprintf( buf, "%d", line );
- result = list_new( result, newstr( file ) );
- result = list_new( result, newstr( buf ) );
- return result;
- }
-}
-
-
-LIST * builtin_check_if_file( PARSE * parse, FRAME * frame )
-{
- LIST * name = lol_get( frame->args, 0 );
- return file_is_file( name->string ) == 1
- ? list_new( 0, newstr( "true" ) )
- : L0 ;
-}
-
-
-LIST * builtin_md5( PARSE * parse, FRAME * frame )
-{
- LIST * l = lol_get( frame->args, 0 );
- char* s = l->string;
-
- md5_state_t state;
- md5_byte_t digest[16];
- char hex_output[16*2 + 1];
-
- int di;
-
- 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]);
-
- return list_new (0, newstr(hex_output));
-}
-
-LIST *builtin_file_open( PARSE *parse, FRAME *frame )
-{
- char* name = lol_get(frame->args, 0)->string;
- char* mode = lol_get(frame->args, 1)->string;
- int fd;
- char buffer[sizeof("4294967295")];
-
- if (strcmp(mode, "w") == 0)
- {
- fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
- }
- else
- {
- fd = open(name, O_RDONLY);
- }
-
- if (fd != -1)
- {
- sprintf(buffer, "%d", fd);
- return list_new(L0, newstr(buffer));
- }
- else
- {
- return L0;
- }
-}
-
-LIST *builtin_pad( PARSE *parse, FRAME *frame )
-{
- char *string = lol_get(frame->args, 0)->string;
- char *width_s = lol_get(frame->args, 1)->string;
-
- int current = strlen (string);
- int desired = atoi(width_s);
- if (current >= desired)
- return list_new (L0, string);
- else
- {
- char *buffer = malloc (desired + 1);
- int i;
- LIST *result;
-
- strcpy (buffer, string);
- for (i = current; i < desired; ++i)
- buffer[i] = ' ';
- buffer[desired] = '\0';
- result = list_new (L0, newstr (buffer));
- free (buffer);
- return result;
- }
-}
-
-LIST *builtin_precious( PARSE *parse, FRAME *frame )
-{
- LIST* targets = lol_get(frame->args, 0);
-
- for ( ; targets; targets = list_next( targets ) )
- {
- TARGET* t = bindtarget (targets->string);
- t->flags |= T_FLAG_PRECIOUS;
- }
-
- return L0;
-}
-
-LIST *builtin_self_path( PARSE *parse, FRAME *frame )
-{
- extern char *saved_argv0;
- char *p = executable_path (saved_argv0);
- if (p)
- {
- LIST* result = list_new (0, newstr (p));
- free(p);
- return result;
- }
- else
- {
- return L0;
- }
-}
-
-LIST *builtin_makedir( PARSE *parse, FRAME *frame )
-{
- LIST *path = lol_get(frame->args, 0);
-
- if (file_mkdir(path->string) == 0)
- {
- LIST *result = list_new (0, newstr(path->string));
- return result;
- }
- else
- {
- return L0;
- }
-}
-
-#ifdef HAVE_PYTHON
-
-LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
-{
- 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;
-
- PyObject * pName;
- PyObject * pModule;
- PyObject * pDict;
- PyObject * pFunc;
-
- if ( first_time )
- {
- /* At the first invocation, we add the value of the global
- * EXTRA_PYTHONPATH to the sys.path Python variable.
- */
- LIST * extra = 0;
- module_t * outer_module = frame->module;
-
- 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 );
- }
-
- for ( ; extra; extra = extra->next )
- {
- string buf[ 1 ];
- string_new( buf );
- string_append( buf, "import sys\nsys.path.append(\"" );
- string_append( buf, extra->string );
- string_append( buf, "\")\n" );
- PyRun_SimpleString( buf->value );
- string_free( buf );
- }
- }
-
- pName = PyString_FromString( python_module );
- pModule = PyImport_Import( pName );
- Py_DECREF( pName );
-
- if ( pModule != NULL )
- {
- pDict = PyModule_GetDict( pModule );
- pFunc = PyDict_GetItemString( pDict, python_function );
-
- 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;
- }
- else
- {
- if ( PyErr_Occurred() )
- PyErr_Print();
- fprintf( stderr, "Cannot find function \"%s\"\n", python_function );
- }
- Py_DECREF( pModule );
- }
- else
- {
- PyErr_Print();
- fprintf( stderr, "Failed to load \"%s\"\n", python_module );
- }
- return L0;
-
-}
-
-#endif
-
-void lol_build( LOL * lol, char * * elements )
-{
- LIST * l = L0;
- lol_init( lol );
-
- while ( elements && *elements )
- {
- if ( !strcmp( *elements, ":" ) )
- {
- lol_add( lol, l );
- l = L0 ;
- }
- else
- {
- l = list_new( l, newstr( *elements ) );
- }
- ++elements;
- }
-
- if ( l != L0 )
- lol_add( lol, l );
-}
-
-
-#ifdef HAVE_PYTHON
-
-/*
- * Calls the bjam rule specified by name passed in 'args'. The name is looked up
- * in the context of bjam's 'python_interface' module. Returns the list of
- * string retured by the rule.
- */
-
-PyObject* bjam_call( PyObject * self, PyObject * args )
-{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
- char * 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;
-
- /* Extract the rule name and arguments from 'args'. */
-
- /* PyTuple_GetItem returns borrowed reference. */
- rulename = PyString_AsString( PyTuple_GetItem( args, 0 ) );
- {
- int i = 1;
- int size = PyTuple_Size( args );
- for ( ; i < size; ++i )
- {
- PyObject * a = PyTuple_GetItem( args, i );
- if ( PyString_Check( a ) )
- {
- lol_add( inner->args, list_new( 0, newstr(
- PyString_AsString( a ) ) ) );
- }
- else if ( PySequence_Check( a ) )
- {
- LIST * l = 0;
- int s = PySequence_Size( a );
- int i = 0;
- for ( ; i < s; ++i )
- {
- /* PySequence_GetItem returns new reference. */
- PyObject * e = PySequence_GetItem( a, i );
- char * s = PyString_AsString( e );
- if ( !s )
- {
- printf( "Invalid parameter type passed from Python\n" );
- exit( 1 );
- }
- l = list_new( l, newstr( s ) );
- Py_DECREF( e );
- }
- lol_add( inner->args, l );
- }
- }
- }
-
- result = evaluate_rule( rulename, inner );
-
- frame_free( inner );
-
- /* Convert the bjam list into a Python list result. */
- {
- PyObject * pyResult = PyList_New( list_length( result ) );
- int i = 0;
- while ( result )
- {
- PyList_SetItem( pyResult, i, PyString_FromString( result->string ) );
- result = list_next( result );
- i += 1;
- }
- list_free( result );
- return pyResult;
- }
-}
-
-
-/*
- * Accepts four arguments:
- * - module name
- * - rule name,
- * - Python callable.
- * - (optional) bjam language function signature.
- * Creates a bjam rule with the specified name in the specified module, which will
- * invoke the Python callable.
- */
-
-PyObject * bjam_import_rule( PyObject * self, PyObject * args )
-{
- char * module;
- char * rule;
- PyObject * func;
- PyObject * bjam_signature = NULL;
- module_t * m;
- RULE * r;
-
- if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
- &module, &rule, &func, &bjam_signature ) )
- return NULL;
-
- if ( !PyCallable_Check( func ) )
- {
- PyErr_SetString( PyExc_RuntimeError,
- "Non-callable object passed to bjam.import_rule" );
- 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)
- {
- 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;
- }
-
- Py_INCREF( Py_None );
- return Py_None;
-}
-
-
-/*
- * Accepts four arguments:
- * - an action name
- * - an action body
- * - a list of variable that will be bound inside the action
- * - integer flags.
- * Defines an action on bjam side.
- */
-
-PyObject * bjam_define_action( PyObject * self, PyObject * args )
-{
- char * name;
- char * body;
- module_t * m;
- PyObject * bindlist_python;
- int flags;
- LIST * bindlist = L0;
- int n;
- int i;
-
- if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
- &PyList_Type, &bindlist_python, &flags ) )
- return NULL;
-
- n = PyList_Size( bindlist_python );
- for ( i = 0; i < n; ++i )
- {
- PyObject * next = PyList_GetItem( bindlist_python, i );
- if ( !PyString_Check( next ) )
- {
- PyErr_SetString( PyExc_RuntimeError,
- "bind list has non-string type" );
- return NULL;
- }
- bindlist = list_new( bindlist, PyString_AsString( next ) );
- }
-
- new_rule_actions( root_module(), name, newstr( body ), bindlist, flags );
-
- Py_INCREF( Py_None );
- return Py_None;
-}
-
-
-/*
- * Returns the value of a variable in root Jam module.
- */
-
-PyObject * bjam_variable( PyObject * self, PyObject * args )
-{
- char * name;
- LIST * value;
- PyObject * result;
- int i;
-
- if ( !PyArg_ParseTuple( args, "s", &name ) )
- return NULL;
-
- enter_module( root_module() );
- value = var_get( name );
- exit_module( root_module() );
-
- result = PyList_New( list_length( value ) );
- for ( i = 0; value; value = list_next( value ), ++i )
- PyList_SetItem( result, i, PyString_FromString( value->string ) );
-
- return result;
-}
-
-
-PyObject * bjam_backtrace( PyObject * self, PyObject * args )
-{
- PyObject * result = PyList_New( 0 );
- struct frame * f = frame_before_python_call;
-
- for ( ; f = f->prev; )
- {
- PyObject * tuple = PyTuple_New( 4 );
- char * file;
- int line;
- char buf[ 32 ];
-
- get_source_line( f->procedure, &file, &line );
- sprintf( buf, "%d", line );
-
- /* 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 ) );
-
- PyList_Append( result, tuple );
- Py_DECREF( tuple );
- }
- return result;
-}
-
-PyObject * bjam_caller( PyObject * self, PyObject * args )
-{
- PyObject *result = PyString_FromString(
- frame_before_python_call->prev->module->name);
- return result;
-}
-
-#endif /* #ifdef HAVE_PYTHON */
-
-
-#ifdef HAVE_POPEN
-
-#if defined(_MSC_VER) || defined(__BORLANDC__)
- #define popen windows_popen_wrapper
- #define pclose _pclose
-
- /*
- * This wrapper is a workaround for a funny _popen() feature on Windows
- * where it eats external quotes in some cases. The bug seems to be related
- * to the quote stripping functionality used by the Windows cmd.exe
- * interpreter when its /S is not specified.
- *
- * Cleaned up quote from the cmd.exe help screen as displayed on Windows XP
- * SP3:
- *
- * 1. If all of the following conditions are met, then quote characters on
- * the command line are preserved:
- *
- * - no /S switch
- * - exactly two quote characters
- * - no special characters between the two quote characters, where
- * special is one of: &<>()@^|
- * - there are one or more whitespace characters between the two quote
- * characters
- * - the string between the two quote characters is the name of an
- * executable file.
- *
- * 2. Otherwise, old behavior is to see if the first character is a quote
- * character and if so, strip the leading character and remove the last
- * quote character on the command line, preserving any text after the
- * last quote character.
- *
- * This causes some commands containing quotes not to be executed correctly.
- * For example:
- *
- * "\Long folder name\aaa.exe" --name="Jurko" --no-surname
- *
- * would get its outermost quotes stripped and would be executed as:
- *
- * \Long folder name\aaa.exe" --name="Jurko --no-surname
- *
- * which would report an error about '\Long' not being a valid command.
- *
- * cmd.exe help seems to indicate it would be enough to add an extra space
- * character in front of the command to avoid this but this does not work,
- * most likely due to the shell first stripping all leading whitespace
- * characters from the command.
- *
- * Solution implemented here is to quote the whole command in case it
- * contains any quote characters. Note thought this will not work correctly
- * should Windows ever 'fix' this feature.
- * (03.06.2008.) (Jurko)
- */
- static FILE * windows_popen_wrapper( char * command, char * mode )
- {
- int extra_command_quotes_needed = ( strchr( command, '"' ) != 0 );
- string quoted_command;
- FILE * result;
-
- if ( extra_command_quotes_needed )
- {
- string_new( &quoted_command );
- string_append( &quoted_command, "\"" );
- string_append( &quoted_command, command );
- string_append( &quoted_command, "\"" );
- command = quoted_command.value;
- }
-
- result = _popen( command, "r" );
-
- if ( extra_command_quotes_needed )
- string_free( &quoted_command );
-
- return result;
- }
-#endif
-
-
-static char * rtrim(char *s)
-{
- char *p = s;
- while(*p) ++p;
- for(--p; p >= s && isspace(*p); *p-- = 0);
- return s;
-}
-
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
-{
- LIST * command = lol_get( frame->args, 0 );
- LIST * result = 0;
- string s;
- int ret;
- char buffer[ 1024 ];
- FILE * p = NULL;
- int exit_status = -1;
- int exit_status_opt = 0;
- int no_output_opt = 0;
- int strip_eol_opt = 0;
-
- /* Process the variable args options. */
- {
- int a = 1;
- LIST * arg = lol_get( frame->args, a );
- while ( arg )
- {
- if ( strcmp( "exit-status", arg->string ) == 0 )
- {
- exit_status_opt = 1;
- }
- else if ( strcmp( "no-output", arg->string ) == 0 )
- {
- no_output_opt = 1;
- }
- else if ( strcmp("strip-eol", arg->string) == 0 )
- {
- strip_eol_opt = 1;
- }
- arg = lol_get( frame->args, ++a );
- }
- }
-
- /* The following fflush() call seems to be indicated as a workaround for a
- * popen() bug on POSIX implementations related to synhronizing input
- * stream positions for the called and the calling process.
- */
- fflush( NULL );
-
- p = popen( command->string, "r" );
- if ( p == NULL )
- return L0;
-
- string_new( &s );
-
- while ( ( ret = fread( buffer, sizeof( char ), sizeof( buffer ) - 1, p ) ) > 0 )
- {
- buffer[ret] = 0;
- if ( !no_output_opt )
- {
- if ( strip_eol_opt )
- rtrim(buffer);
- string_append( &s, buffer );
- }
- }
-
- exit_status = pclose( p );
-
- /* The command output is returned first. */
- result = list_new( L0, newstr( s.value ) );
- string_free( &s );
-
- /* The command exit result next. */
- if ( exit_status_opt )
- {
- if ( WIFEXITED(exit_status) )
- exit_status = WEXITSTATUS(exit_status);
- else
- exit_status = -1;
- sprintf( buffer, "%d", exit_status );
- result = list_new( result, newstr( buffer ) );
- }
-
- return result;
-}
-
-#else /* #ifdef HAVE_POPEN */
-
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
-{
- return L0;
-}
-
-#endif /* #ifdef HAVE_POPEN */