2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
26 #include "timestamp.h"
30 #if defined(USE_EXECUNIX)
31 # include <sys/types.h>
32 # include <sys/wait.h>
35 NT does not have wait() and associated macros, it uses the return value
36 of system() instead. Status code group are documented at
37 http://msdn.microsoft.com/en-gb/library/ff565436.aspx
39 # define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0)
40 # define WEXITSTATUS(w)(w)
44 * builtins.c - builtin jam rules
48 * load_builtin() - define builtin rules
52 * builtin_depends() - DEPENDS/INCLUDES rule.
53 * builtin_echo() - ECHO rule.
54 * builtin_exit() - EXIT rule.
55 * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule.
56 * builtin_glob() - GLOB rule.
57 * builtin_match() - MATCH rule.
59 * 01/10/01 (seiwald) - split from compile.c
64 * compile_builtin() - define builtin rules
70 #if defined( OS_NT ) || defined( OS_CYGWIN )
71 LIST * builtin_system_registry ( PARSE *, FRAME * );
72 LIST * builtin_system_registry_names( PARSE *, FRAME * );
75 int glob( char * s, char * c );
77 void backtrace ( FRAME * );
78 void backtrace_line ( FRAME * );
79 void print_source_line( PARSE * );
82 RULE * bind_builtin( char * name, LIST * (* f)( PARSE *, FRAME * ), int flags, char * * args )
84 argument_list* arg_list = 0;
88 arg_list = args_new();
89 lol_build( arg_list->data, args );
92 return new_rule_body( root_module(), name, arg_list,
93 parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
97 RULE * duplicate_rule( char * name, RULE * other )
99 return import_rule( other, root_module(), name );
105 duplicate_rule( "Always",
106 bind_builtin( "ALWAYS",
107 builtin_flags, T_FLAG_TOUCHED, 0 ) );
109 duplicate_rule( "Depends",
110 bind_builtin( "DEPENDS",
111 builtin_depends, 0, 0 ) );
113 duplicate_rule( "echo",
114 duplicate_rule( "Echo",
115 bind_builtin( "ECHO",
116 builtin_echo, 0, 0 ) ) );
119 char * args[] = { "message", "*", ":", "result-value", "?", 0 };
120 duplicate_rule( "exit",
121 duplicate_rule( "Exit",
122 bind_builtin( "EXIT",
123 builtin_exit, 0, args ) ) );
127 char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
128 duplicate_rule( "Glob",
129 bind_builtin( "GLOB", builtin_glob, 0, args ) );
133 char * args[] = { "patterns", "*", 0 };
134 bind_builtin( "GLOB-RECURSIVELY",
135 builtin_glob_recursive, 0, args );
138 duplicate_rule( "Includes",
139 bind_builtin( "INCLUDES",
140 builtin_depends, 1, 0 ) );
143 char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
144 bind_builtin( "REBUILDS",
145 builtin_rebuilds, 0, args );
148 duplicate_rule( "Leaves",
149 bind_builtin( "LEAVES",
150 builtin_flags, T_FLAG_LEAVES, 0 ) );
152 duplicate_rule( "Match",
153 bind_builtin( "MATCH",
154 builtin_match, 0, 0 ) );
157 char * args[] = { "string", ":", "delimiters" };
158 bind_builtin( "SPLIT_BY_CHARACTERS",
159 builtin_split_by_characters, 0, 0 );
162 duplicate_rule( "NoCare",
163 bind_builtin( "NOCARE",
164 builtin_flags, T_FLAG_NOCARE, 0 ) );
166 duplicate_rule( "NOTIME",
167 duplicate_rule( "NotFile",
168 bind_builtin( "NOTFILE",
169 builtin_flags, T_FLAG_NOTFILE, 0 ) ) );
171 duplicate_rule( "NoUpdate",
172 bind_builtin( "NOUPDATE",
173 builtin_flags, T_FLAG_NOUPDATE, 0 ) );
175 duplicate_rule( "Temporary",
176 bind_builtin( "TEMPORARY",
177 builtin_flags, T_FLAG_TEMP, 0 ) );
179 bind_builtin( "ISFILE",
180 builtin_flags, T_FLAG_ISFILE, 0 );
182 duplicate_rule( "HdrMacro",
183 bind_builtin( "HDRMACRO",
184 builtin_hdrmacro, 0, 0 ) );
186 /* FAIL_EXPECTED is used to indicate that the result of a target build
187 * action should be inverted (ok <=> fail) this can be useful when
188 * performing test runs from Jamfiles.
190 bind_builtin( "FAIL_EXPECTED",
191 builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
193 bind_builtin( "RMOLD",
194 builtin_flags, T_FLAG_RMOLD, 0 );
197 char * args[] = { "targets", "*", 0 };
198 bind_builtin( "UPDATE",
199 builtin_update, 0, args );
203 char * args[] = { "targets", "*",
205 ":", "ignore-minus-n", "?",
206 ":", "ignore-minus-q", "?", 0 };
207 bind_builtin( "UPDATE_NOW",
208 builtin_update_now, 0, args );
212 char * args[] = { "string", "pattern", "replacements", "+", 0 };
213 duplicate_rule( "subst",
214 bind_builtin( "SUBST",
215 builtin_subst, 0, args ) );
219 char * args[] = { "module", "?", 0 };
220 bind_builtin( "RULENAMES",
221 builtin_rulenames, 0, args );
226 char * args[] = { "module", "?", 0 };
227 bind_builtin( "VARNAMES",
228 builtin_varnames, 0, args );
232 char * args[] = { "module", "?", 0 };
233 bind_builtin( "DELETE_MODULE",
234 builtin_delete_module, 0, args );
238 char * args[] = { "source_module", "?",
239 ":", "source_rules", "*",
240 ":", "target_module", "?",
241 ":", "target_rules", "*",
242 ":", "localize", "?", 0 };
243 bind_builtin( "IMPORT",
244 builtin_import, 0, args );
248 char * args[] = { "module", "?", ":", "rules", "*", 0 };
249 bind_builtin( "EXPORT",
250 builtin_export, 0, args );
254 char * args[] = { "levels", "?", 0 };
255 bind_builtin( "CALLER_MODULE",
256 builtin_caller_module, 0, args );
260 char * args[] = { "levels", "?", 0 };
261 bind_builtin( "BACKTRACE",
262 builtin_backtrace, 0, args );
266 char * args[] = { 0 };
268 builtin_pwd, 0, args );
272 char * args[] = { "target", "*", ":", "path", "*", 0 };
273 bind_builtin( "SEARCH_FOR_TARGET",
274 builtin_search_for_target, 0, args );
278 char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
279 bind_builtin( "IMPORT_MODULE",
280 builtin_import_module, 0, args );
284 char * args[] = { "module", "?", 0 };
285 bind_builtin( "IMPORTED_MODULES",
286 builtin_imported_modules, 0, args );
290 char * args[] = { "instance_module", ":", "class_module", 0 };
291 bind_builtin( "INSTANCE",
292 builtin_instance, 0, args );
296 char * args[] = { "sequence", "*", 0 };
297 bind_builtin( "SORT",
298 builtin_sort, 0, args );
302 char * args[] = { "path_parts", "*", 0 };
303 bind_builtin( "NORMALIZE_PATH",
304 builtin_normalize_path, 0, args );
308 char * args[] = { "args", "*", 0 };
309 bind_builtin( "CALC",
310 builtin_calc, 0, args );
314 char * args[] = { "module", ":", "rule", 0 };
315 bind_builtin( "NATIVE_RULE",
316 builtin_native_rule, 0, args );
320 char * args[] = { "module", ":", "rule", ":", "version", 0 };
321 bind_builtin( "HAS_NATIVE_RULE",
322 builtin_has_native_rule, 0, args );
326 char * args[] = { "module", "*", 0 };
327 bind_builtin( "USER_MODULE",
328 builtin_user_module, 0, args );
332 char * args[] = { 0 };
333 bind_builtin( "NEAREST_USER_LOCATION",
334 builtin_nearest_user_location, 0, args );
338 char * args[] = { "file", 0 };
339 bind_builtin( "CHECK_IF_FILE",
340 builtin_check_if_file, 0, args );
345 char * args[] = { "python-module", ":", "function", ":",
346 "jam-module", ":", "rule-name", 0 };
347 bind_builtin( "PYTHON_IMPORT_RULE",
348 builtin_python_import_rule, 0, args );
352 # if defined( OS_NT ) || defined( OS_CYGWIN )
354 char * args[] = { "key_path", ":", "data", "?", 0 };
355 bind_builtin( "W32_GETREG",
356 builtin_system_registry, 0, args );
360 char * args[] = { "key_path", ":", "result-type", 0 };
361 bind_builtin( "W32_GETREGNAMES",
362 builtin_system_registry_names, 0, args );
367 char * args[] = { "command", ":", "*", 0 };
368 duplicate_rule( "SHELL",
369 bind_builtin( "COMMAND",
370 builtin_shell, 0, args ) );
374 char * args[] = { "string", 0 };
376 builtin_md5, 0, args ) ;
380 char * args[] = { "name", ":", "mode", 0 };
381 bind_builtin( "FILE_OPEN",
382 builtin_file_open, 0, args );
386 char * args[] = { "string", ":", "width", 0 };
388 builtin_pad, 0, args );
392 char * args[] = { "targets", "*", 0 };
393 bind_builtin( "PRECIOUS",
394 builtin_precious, 0, args );
398 char * args [] = { 0 };
399 bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
403 char * args [] = { "path", 0 };
404 bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
407 /* Initialize builtin modules. */
418 * builtin_calc() - CALC rule.
420 * The CALC rule performs simple mathematical operations on two arguments.
423 LIST * builtin_calc( PARSE * parse, FRAME * frame )
425 LIST * arg = lol_get( frame->args, 0 );
436 if ( arg == 0 ) return L0;
439 arg = list_next( arg );
440 if ( arg == 0 ) return L0;
443 arg = list_next( arg );
444 if ( arg == 0 ) return L0;
447 lhs_value = atoi( lhs );
448 rhs_value = atoi( rhs );
450 if ( strcmp( "+", op ) == 0 )
452 result_value = lhs_value + rhs_value;
454 else if ( strcmp( "-", op ) == 0 )
456 result_value = lhs_value - rhs_value;
463 sprintf( buffer, "%ld", result_value );
464 result = list_new( result, newstr( buffer ) );
470 * builtin_depends() - DEPENDS/INCLUDES rule.
472 * The DEPENDS/INCLUDES builtin rule appends each of the listed sources on the
473 * dependency/includes list of each of the listed targets. It binds both the
474 * targets and sources as TARGETs.
477 LIST * builtin_depends( PARSE * parse, FRAME * frame )
479 LIST * targets = lol_get( frame->args, 0 );
480 LIST * sources = lol_get( frame->args, 1 );
483 for ( l = targets; l; l = list_next( l ) )
485 TARGET * t = bindtarget( l->string );
487 /* If doing INCLUDES, switch to the TARGET's include */
488 /* TARGET, creating it if needed. The internal include */
489 /* TARGET shares the name of its parent. */
495 t->includes = copytarget( t );
496 t->includes->original_target = t;
501 t->depends = targetlist( t->depends, sources );
504 /* Enter reverse links */
505 for ( l = sources; l; l = list_next( l ) )
507 TARGET * s = bindtarget( l->string );
508 s->dependants = targetlist( s->dependants, targets );
516 * builtin_rebuilds() - REBUILDS rule.
518 * The REBUILDS builtin rule appends each of the listed rebuild-targets in its
519 * 2nd argument on the rebuilds list of each of the listed targets in its first
523 LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
525 LIST * targets = lol_get( frame->args, 0 );
526 LIST * rebuilds = lol_get( frame->args, 1 );
529 for ( l = targets; l; l = list_next( l ) )
531 TARGET * t = bindtarget( l->string );
532 t->rebuilds = targetlist( t->rebuilds, rebuilds );
540 * builtin_echo() - ECHO rule.
542 * The ECHO builtin rule echoes the targets to the user. No other actions are
546 LIST * builtin_echo( PARSE * parse, FRAME * frame )
548 list_print( lol_get( frame->args, 0 ) );
556 * builtin_exit() - EXIT rule.
558 * The EXIT builtin rule echoes the targets to the user and exits the program
559 * with a failure status.
562 LIST * builtin_exit( PARSE * parse, FRAME * frame )
564 list_print( lol_get( frame->args, 0 ) );
566 if ( lol_get( frame->args, 1 ) )
568 exit( atoi( lol_get( frame->args, 1 )->string ) );
572 exit( EXITBAD ); /* yeech */
579 * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule.
581 * Builtin_flags() marks the target with the appropriate flag, for use by make0().
582 * It binds each target as a TARGET.
585 LIST * builtin_flags( PARSE * parse, FRAME * frame )
587 LIST * l = lol_get( frame->args, 0 );
588 for ( ; l; l = list_next( l ) )
589 bindtarget( l->string )->flags |= parse->num;
595 * builtin_globbing() - GLOB rule.
602 LIST * case_insensitive;
606 static void downcase_inplace( char * p )
613 static void builtin_glob_back
621 PROFILE_ENTER( BUILTIN_GLOB_BACK );
623 struct globbing * globbing = (struct globbing *)closure;
628 /* Null out directory for matching. We wish we had file_dirscan() pass up a
631 path_parse( file, &f );
634 /* For globbing, we unconditionally ignore current and parent directory
635 * items. Since they items always exist, there is no reason why caller of
636 * GLOB would want to see them. We could also change file_dirscan(), but
637 * then paths with embedded "." and ".." would not work anywhere.
639 if ( !strcmp( f.f_base.ptr, "." ) || !strcmp( f.f_base.ptr, ".." ) )
641 PROFILE_EXIT( BUILTIN_GLOB_BACK );
646 path_build( &f, buf, 0 );
648 if ( globbing->case_insensitive )
649 downcase_inplace( buf->value );
651 for ( l = globbing->patterns; l; l = l->next )
653 if ( !glob( l->string, buf->value ) )
655 globbing->results = list_new( globbing->results, newstr( file ) );
662 PROFILE_EXIT( BUILTIN_GLOB_BACK );
666 static LIST * downcase_list( LIST * in )
675 string_copy( s, in->string );
676 downcase_inplace( s->value );
677 result = list_append( result, list_new( 0, newstr( s->value ) ) );
686 LIST * builtin_glob( PARSE * parse, FRAME * frame )
688 LIST * l = lol_get( frame->args, 0 );
689 LIST * r = lol_get( frame->args, 1 );
691 struct globbing globbing;
693 globbing.results = L0;
694 globbing.patterns = r;
696 globbing.case_insensitive
697 # if defined( OS_NT ) || defined( OS_CYGWIN )
698 = l; /* Always case-insensitive if any files can be found. */
700 = lol_get( frame->args, 2 );
703 if ( globbing.case_insensitive )
704 globbing.patterns = downcase_list( r );
706 for ( ; l; l = list_next( l ) )
707 file_dirscan( l->string, builtin_glob_back, &globbing );
709 if ( globbing.case_insensitive )
710 list_free( globbing.patterns );
712 return globbing.results;
716 static int has_wildcards( char const * str )
718 size_t const index = strcspn( str, "[]*?" );
719 return str[ index ] == '\0' ? 0 : 1;
724 * If 'file' exists, append 'file' to 'list'. Returns 'list'.
727 static LIST * append_if_exists( LIST * list, char * file )
730 timestamp( file, &time );
732 ? list_new( list, newstr( file ) )
737 LIST * glob1( char * dirname, char * pattern )
739 LIST * plist = list_new( L0, pattern );
740 struct globbing globbing;
742 globbing.results = L0;
743 globbing.patterns = plist;
745 globbing.case_insensitive
746 # if defined( OS_NT ) || defined( OS_CYGWIN )
747 = plist; /* always case-insensitive if any files can be found */
752 if ( globbing.case_insensitive )
753 globbing.patterns = downcase_list( plist );
755 file_dirscan( dirname, builtin_glob_back, &globbing );
757 if ( globbing.case_insensitive )
758 list_free( globbing.patterns );
762 return globbing.results;
766 LIST * glob_recursive( char * pattern )
770 /* Check if there's metacharacters in pattern */
771 if ( !has_wildcards( pattern ) )
773 /* No metacharacters. Check if the path exists. */
774 result = append_if_exists(result, pattern);
778 /* Have metacharacters in the pattern. Split into dir/name. */
780 path_parse( pattern, path );
782 if ( path->f_dir.ptr )
786 string basename[ 1 ];
787 string_new( dirname );
788 string_new( basename );
790 string_append_range( dirname, path->f_dir.ptr,
791 path->f_dir.ptr + path->f_dir.len );
793 path->f_grist.ptr = 0;
794 path->f_grist.len = 0;
797 path_build( path, basename, 0 );
799 dirs = has_wildcards( dirname->value )
800 ? glob_recursive( dirname->value )
801 : list_new( dirs, dirname->value );
803 if ( has_wildcards( basename->value ) )
805 for ( ; dirs; dirs = dirs->next )
806 result = list_append( result, glob1( dirs->string,
811 string file_string[ 1 ];
812 string_new( file_string );
814 /* No wildcard in basename. */
815 for ( ; dirs; dirs = dirs->next )
817 path->f_dir.ptr = dirs->string;
818 path->f_dir.len = strlen( dirs->string );
819 path_build( path, file_string, 0 );
821 result = append_if_exists( result, file_string->value );
823 string_truncate( file_string, 0 );
826 string_free( file_string );
829 string_free( dirname );
830 string_free( basename );
834 /** No directory, just a pattern. */
835 result = list_append( result, glob1( ".", pattern ) );
843 LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
846 LIST * l = lol_get( frame->args, 0 );
847 for ( ; l; l = l->next )
848 result = list_append( result, glob_recursive( l->string ) );
854 * builtin_match() - MATCH rule, regexp matching.
857 LIST * builtin_match( PARSE * parse, FRAME * frame )
866 /* For each pattern */
868 for ( l = lol_get( frame->args, 0 ); l; l = l->next )
870 /* Result is cached and intentionally never freed. */
871 regexp * re = regex_compile( l->string );
873 /* For each string to match against. */
874 for ( r = lol_get( frame->args, 1 ); r; r = r->next )
876 if ( regexec( re, r->string ) )
881 /* Find highest parameter */
883 for ( top = NSUBEXP; top-- > 1; )
884 if ( re->startp[ top ] )
887 /* And add all parameters up to highest onto list. */
888 /* Must have parameters to have results! */
889 for ( i = 1; i <= top; ++i )
891 string_append_range( buf, re->startp[ i ], re->endp[ i ] );
892 result = list_new( result, newstr( buf->value ) );
893 string_truncate( buf, 0 );
903 LIST * builtin_split_by_characters( PARSE * parse, FRAME * frame )
905 LIST * l1 = lol_get( frame->args, 0 );
906 LIST * l2 = lol_get( frame->args, 1 );
910 char* s = strdup (l1->string);
911 char* delimiters = l2->string;
914 t = strtok (s, delimiters);
917 result = list_new(result, newstr(t));
918 t = strtok (NULL, delimiters);
926 LIST * builtin_hdrmacro( PARSE * parse, FRAME * frame )
928 LIST * l = lol_get( frame->args, 0 );
930 for ( ; l; l = list_next( l ) )
932 TARGET * t = bindtarget( l->string );
934 /* Scan file for header filename macro definitions. */
936 printf( "scanning '%s' for header file macro definitions\n",
947 * builtin_rulenames() - RULENAMES ( MODULE ? ).
949 * Returns a list of the non-local rule names in the given MODULE. If MODULE is
950 * not supplied, returns the list of rule names in the global module.
953 static void add_rule_name( void * r_, void * result_ )
955 RULE * r = (RULE *)r_;
956 LIST * * result = (LIST * *)result_;
958 *result = list_new( *result, copystr( r->name ) );
962 LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
964 LIST * arg0 = lol_get( frame->args, 0 );
966 module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
968 if ( source_module->rules )
969 hashenumerate( source_module->rules, add_rule_name, &result );
975 * builtin_varnames() - VARNAMES ( MODULE ? ).
977 * Returns a list of the variable names in the given MODULE. If MODULE is not
978 * supplied, returns the list of variable names in the global module.
981 /* helper function for builtin_varnames(), below. Used with hashenumerate, will
982 * prepend the key of each element to the list
984 static void add_hash_key( void * np, void * result_ )
986 LIST * * result = (LIST * *)result_;
987 *result = list_new( *result, copystr( *(char * *)np ) );
991 static struct hash * get_running_module_vars()
994 struct hash * vars = NULL;
995 /* Get the global variables pointer (that of the currently running module).
997 var_hash_swap( &vars );
999 /* Put the global variables pointer in its right place. */
1000 var_hash_swap( &dummy );
1005 LIST * builtin_varnames( PARSE * parse, FRAME * frame )
1007 LIST * arg0 = lol_get( frame->args, 0 );
1009 module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
1011 /* The running module _always_ has its 'variables' member set to NULL due to
1012 * the way enter_module() and var_hash_swap() work.
1014 struct hash * vars = source_module == frame->module
1015 ? get_running_module_vars()
1016 : source_module->variables;
1019 hashenumerate( vars, add_hash_key, &result );
1025 * builtin_delete_module() - MODULE ?.
1027 * Clears all rules and variables from the given module.
1030 LIST * builtin_delete_module( PARSE * parse, FRAME * frame )
1032 LIST * arg0 = lol_get( frame->args, 0 );
1034 module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
1035 delete_module( source_module );
1040 static void unknown_rule( FRAME * frame, char * key, char * module_name, char * rule_name )
1042 backtrace_line( frame->prev );
1043 printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
1044 backtrace( frame->prev );
1050 * builtin_import() - IMPORT
1059 * The IMPORT rule imports rules from the SOURCE_MODULE into the TARGET_MODULE
1060 * as local rules. If either SOURCE_MODULE or TARGET_MODULE is not supplied, it
1061 * refers to the global module. SOURCE_RULES specifies which rules from the
1062 * SOURCE_MODULE to import; TARGET_RULES specifies the names to give those rules
1063 * in TARGET_MODULE. If SOURCE_RULES contains a name which doesn't correspond to
1064 * a rule in SOURCE_MODULE, or if it contains a different number of items than
1065 * TARGET_RULES, an error is issued. If LOCALIZE is specified, the rules will be
1066 * executed in TARGET_MODULE, with corresponding access to its module local
1070 LIST * builtin_import( PARSE * parse, FRAME * frame )
1072 LIST * source_module_list = lol_get( frame->args, 0 );
1073 LIST * source_rules = lol_get( frame->args, 1 );
1074 LIST * target_module_list = lol_get( frame->args, 2 );
1075 LIST * target_rules = lol_get( frame->args, 3 );
1076 LIST * localize = lol_get( frame->args, 4 );
1078 module_t * target_module =
1079 bindmodule( target_module_list ? target_module_list->string : 0 );
1080 module_t * source_module =
1081 bindmodule( source_module_list ? source_module_list->string : 0 );
1086 for ( source_name = source_rules, target_name = target_rules;
1087 source_name && target_name;
1088 source_name = list_next( source_name ),
1089 target_name = list_next( target_name ) )
1094 r_.name = source_name->string;
1096 if ( !source_module->rules ||
1097 !hashcheck( source_module->rules, (HASHDATA * *)&r ) )
1098 unknown_rule( frame, "IMPORT", source_module->name, r_.name );
1100 imported = import_rule( r, target_module, target_name->string );
1102 imported->module = target_module;
1103 /* This rule is really part of some other module. Just refer to it here,
1104 * but do not let it out.
1106 imported->exported = 0;
1109 if ( source_name || target_name )
1111 backtrace_line( frame->prev );
1112 printf( "import error: length of source and target rule name lists don't match!\n" );
1113 printf( " source: " );
1114 list_print( source_rules );
1115 printf( "\n target: " );
1116 list_print( target_rules );
1118 backtrace( frame->prev );
1127 * builtin_export() - EXPORT ( MODULE ? : RULES * ).
1129 * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local (and thus
1130 * exportable). If an element of RULES does not name a rule in MODULE, an error
1134 LIST * builtin_export( PARSE * parse, FRAME * frame )
1136 LIST * module_list = lol_get( frame->args, 0 );
1137 LIST * rules = lol_get( frame->args, 1 );
1138 module_t * m = bindmodule( module_list ? module_list->string : 0 );
1140 for ( ; rules; rules = list_next( rules ) )
1144 r_.name = rules->string;
1146 if ( !m->rules || !hashcheck( m->rules, (HASHDATA * *)&r ) )
1147 unknown_rule( frame, "EXPORT", m->name, r_.name );
1156 * get_source_line() - Retrieve the file and line number that should be
1157 * indicated for a given procedure in debug output or an error backtrace.
1160 static void get_source_line( PARSE * procedure, char * * file, int * line )
1164 char * f = procedure->file;
1165 int l = procedure->line;
1166 if ( !strcmp( f, "+" ) )
1176 *file = "(builtin)";
1182 void print_source_line( PARSE * p )
1187 get_source_line( p, &file, &line );
1189 printf( "(builtin):" );
1191 printf( "%s:%d:", file, line );
1196 * backtrace_line() - print a single line of error backtrace for the given
1200 void backtrace_line( FRAME * frame )
1204 printf( "(no frame):" );
1208 print_source_line( frame->procedure );
1209 printf( " in %s\n", frame->rulename );
1215 * backtrace() - Print the entire backtrace from the given frame to the Jambase
1219 void backtrace( FRAME * frame )
1221 if ( !frame ) return;
1222 while ( ( frame = frame->prev ) )
1223 backtrace_line( frame );
1228 * builtin_backtrace() - A Jam version of the backtrace function, taking no
1229 * arguments and returning a list of quadruples: FILENAME LINE MODULE. RULENAME
1230 * describing each frame. Note that the module-name is always followed by a
1234 LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
1236 LIST * levels_arg = lol_get( frame->args, 0 );
1237 int levels = levels_arg ? atoi( levels_arg->string ) : ( (unsigned int)(-1) >> 1 ) ;
1240 for ( ; ( frame = frame->prev ) && levels ; --levels )
1245 get_source_line( frame->procedure, &file, &line );
1246 sprintf( buf, "%d", line );
1247 result = list_new( result, newstr( file ) );
1248 result = list_new( result, newstr( buf ) );
1249 result = list_new( result, newstr( frame->module->name ) );
1250 result = list_new( result, newstr( frame->rulename ) );
1257 * builtin_caller_module() - CALLER_MODULE ( levels ? )
1259 * If levels is not supplied, returns the name of the module of the rule which
1260 * called the one calling this one. If levels is supplied, it is interpreted as
1261 * an integer specifying a number of additional levels of call stack to traverse
1262 * in order to locate the module in question. If no such module exists, returns
1263 * the empty list. Also returns the empty list when the module in question is
1264 * the global module. This rule is needed for implementing module import
1268 LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
1270 LIST * levels_arg = lol_get( frame->args, 0 );
1271 int levels = levels_arg ? atoi( levels_arg->string ) : 0 ;
1274 for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
1275 frame = frame->prev;
1277 if ( frame->module == root_module() )
1283 string_copy( &name, frame->module->name );
1284 string_pop_back( &name );
1285 result = list_new( L0, newstr(name.value) );
1286 string_free( &name );
1293 * Return the current working directory.
1295 * Usage: pwd = [ PWD ] ;
1298 LIST * builtin_pwd( PARSE * parse, FRAME * frame )
1305 * Adds targets to the list of target that jam will attempt to update.
1308 LIST * builtin_update( PARSE * parse, FRAME * frame )
1310 LIST * result = list_copy( L0, targets_to_update() );
1311 LIST * arg1 = lol_get( frame->args, 0 );
1312 clear_targets_to_update();
1313 for ( ; arg1; arg1 = list_next( arg1 ) )
1314 mark_target_for_updating( newstr( arg1->string ) );
1319 int last_update_now_status;
1321 /* Takes a list of target names as first argument, and immediately
1323 Second parameter, if specified, if the descriptor (converted to a string)
1324 of a log file where all build output is redirected.
1325 Third parameter, if non-empty, specifies that the -n option should have
1326 no effect -- that is, all out-of-date targets should be rebuild.
1328 LIST * builtin_update_now( PARSE * parse, FRAME * frame )
1330 LIST * targets = lol_get( frame->args, 0 );
1331 LIST * log = lol_get( frame->args, 1 );
1332 LIST * force = lol_get (frame->args, 2);
1333 LIST * continue_ = lol_get(frame->args, 3);
1335 int original_stdout;
1336 int original_stderr;
1339 const char** targets2;
1341 int original_noexec;
1342 int original_quitquick;
1347 int fd = atoi(log->string);
1348 /* Redirect stdout and stderr, temporary, to the log file. */
1349 original_stdout = dup (0);
1350 original_stderr = dup (1);
1357 original_noexec = globs.noexec;
1359 original_quitquick = globs.quitquick;
1360 globs.quitquick = 0;
1365 original_quitquick = globs.quitquick;
1366 globs.quitquick = 0;
1369 targets_count = list_length( targets );
1370 targets2 = (const char * *)BJAM_MALLOC( targets_count * sizeof( char * ) );
1371 for (i = 0 ; targets; targets = list_next( targets ) )
1372 targets2[ i++ ] = targets->string;
1373 status |= make( targets_count, targets2, anyhow);
1378 globs.noexec = original_noexec;
1379 globs.quitquick = original_quitquick;
1384 globs.quitquick = original_quitquick;
1389 /* Flush whatever stdio might have buffered, while descriptions
1390 0 and 1 still refer to the log file. */
1393 dup2 (original_stdout, 0);
1394 dup2 (original_stderr, 1);
1395 close (original_stdout);
1396 close (original_stderr);
1399 last_update_now_status = status;
1402 return list_new (L0, newstr ("ok"));
1407 LIST * builtin_search_for_target( PARSE * parse, FRAME * frame )
1409 LIST * arg1 = lol_get( frame->args, 0 );
1410 LIST * arg2 = lol_get( frame->args, 1 );
1411 TARGET * t = search_for_target( arg1->string, arg2 );
1412 return list_new( L0, t->name );
1416 LIST * builtin_import_module( PARSE * parse, FRAME * frame )
1418 LIST * arg1 = lol_get( frame->args, 0 );
1419 LIST * arg2 = lol_get( frame->args, 1 );
1420 module_t * m = arg2 ? bindmodule( arg2->string ) : root_module();
1421 import_module( arg1, m );
1426 LIST * builtin_imported_modules( PARSE * parse, FRAME * frame )
1428 LIST * arg0 = lol_get( frame->args, 0 );
1429 return imported_modules( bindmodule( arg0 ? arg0->string : 0 ) );
1433 LIST * builtin_instance( PARSE * parse, FRAME * frame )
1435 LIST * arg1 = lol_get( frame->args, 0 );
1436 LIST * arg2 = lol_get( frame->args, 1 );
1437 module_t * const instance = bindmodule( arg1->string );
1438 module_t * const class_module = bindmodule( arg2->string );
1439 instance->class_module = class_module;
1444 LIST * builtin_sort( PARSE * parse, FRAME * frame )
1446 LIST * arg1 = lol_get( frame->args, 0 );
1447 return list_sort( arg1 );
1451 LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
1453 LIST * arg = lol_get( frame->args, 0 );
1455 /* First, we iterate over all '/'-separated elements, starting from the end
1456 * of string. If we see a '..', we remove a previous path elements. If we
1457 * see '.', we remove it. The removal is done by overwriting data using '\1'
1458 * in the string. After the whole string has been processed, we do a second
1459 * pass, removing all the entered '\1' characters.
1464 /* Last character of the part of string still to be processed. */
1466 /* Working pointer. */
1468 /* Number of '..' elements seen and not processed yet. */
1473 /* Make a copy of input: we should not change it. Prepend a '/' before it as
1474 * a guard for the algorithm later on and remember whether it was originally
1478 string_push_back( in, '/' );
1479 for ( ; arg; arg = list_next( arg ) )
1481 if ( arg->string[ 0 ] != '\0' )
1483 if ( in->size == 1 )
1484 rooted = ( ( arg->string[ 0 ] == '/' ) ||
1485 ( arg->string[ 0 ] == '\\' ) );
1487 string_append( in, "/" );
1488 string_append( in, arg->string );
1492 /* Convert \ into /. On Windows, paths using / and \ are equivalent, and we
1493 * want this function to obtain a canonic representation.
1495 for ( current = in->value, end = in->value + in->size;
1496 current < end; ++current )
1497 if ( *current == '\\' )
1500 /* Now we remove any extra path elements by overwriting them with '\1'
1501 * characters and cound how many more unused '..' path elements there are
1502 * remaining. Note that each remaining path element with always starts with
1505 for ( end = in->value + in->size - 1; end >= in->value; )
1507 /* Set 'current' to the next occurence of '/', which always exists. */
1508 for ( current = end; *current != '/'; --current );
1510 if ( current == end )
1512 /* Found a trailing or duplicate '/'. Remove it. */
1515 else if ( ( end - current == 1 ) && ( *(current + 1) == '.' ) )
1517 /* Found '/.'. Remove them all. */
1519 *(current + 1) = '\1';
1521 else if ( ( end - current == 2 ) && ( *(current + 1) == '.' ) && ( *(current + 2) == '.' ) )
1523 /* Found '/..'. Remove them all. */
1525 *(current + 1) = '\1';
1526 *(current + 2) = '\1';
1531 memset( current, '\1', end - current + 1 );
1539 /* Now we know that we need to add exactly dotdots '..' path elements to the
1540 * front and that our string is either empty or has a '/' as its first
1541 * significant character. If we have any dotdots remaining then the passed
1542 * path must not have been rooted or else it is invalid we return an empty
1547 if ( rooted ) return L0;
1549 string_append( out, "/.." );
1550 while ( --dotdots );
1553 /* Now we actually remove all the path characters marked for removal. */
1554 for ( current = in->value; *current; ++current )
1555 if ( *current != '\1' )
1556 string_push_back( out, *current );
1558 /* Here we know that our string contains no '\1' characters and is either
1559 * empty or has a '/' as its initial character. If the original path was not
1560 * rooted and we have a non-empty path we need to drop the initial '/'. If
1561 * the original path was rooted and we have an empty path we need to add
1564 result = newstr( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
1569 return list_new( 0, result );
1573 LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
1575 LIST * module_name = lol_get( frame->args, 0 );
1576 LIST * rule_name = lol_get( frame->args, 1 );
1578 module_t * module = bindmodule( module_name->string );
1581 native_rule_t * np = &n;
1582 n.name = rule_name->string;
1583 if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
1585 new_rule_body( module, np->name, np->arguments, np->procedure, 1 );
1589 backtrace_line( frame->prev );
1590 printf( "error: no native rule \"%s\" defined in module \"%s\"\n",
1591 n.name, module->name );
1592 backtrace( frame->prev );
1599 LIST * builtin_has_native_rule( PARSE * parse, FRAME * frame )
1601 LIST * module_name = lol_get( frame->args, 0 );
1602 LIST * rule_name = lol_get( frame->args, 1 );
1603 LIST * version = lol_get( frame->args, 2 );
1605 module_t * module = bindmodule( module_name->string );
1608 native_rule_t * np = &n;
1609 n.name = rule_name->string;
1610 if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
1612 int expected_version = atoi( version->string );
1613 if ( np->version == expected_version )
1614 return list_new( 0, newstr( "true" ) );
1620 LIST * builtin_user_module( PARSE * parse, FRAME * frame )
1622 LIST * module_name = lol_get( frame->args, 0 );
1623 for ( ; module_name; module_name = module_name->next )
1625 module_t * m = bindmodule( module_name->string );
1632 LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
1634 FRAME * nearest_user_frame =
1635 frame->module->user_module ? frame : frame->prev_user;
1636 if ( !nearest_user_frame )
1645 get_source_line( nearest_user_frame->procedure, &file, &line );
1646 sprintf( buf, "%d", line );
1647 result = list_new( result, newstr( file ) );
1648 result = list_new( result, newstr( buf ) );
1654 LIST * builtin_check_if_file( PARSE * parse, FRAME * frame )
1656 LIST * name = lol_get( frame->args, 0 );
1657 return file_is_file( name->string ) == 1
1658 ? list_new( 0, newstr( "true" ) )
1663 LIST * builtin_md5( PARSE * parse, FRAME * frame )
1665 LIST * l = lol_get( frame->args, 0 );
1666 char* s = l->string;
1669 md5_byte_t digest[16];
1670 char hex_output[16*2 + 1];
1675 md5_append(&state, (const md5_byte_t *)s, strlen(s));
1676 md5_finish(&state, digest);
1678 for (di = 0; di < 16; ++di)
1679 sprintf(hex_output + di * 2, "%02x", digest[di]);
1681 return list_new (0, newstr(hex_output));
1684 LIST *builtin_file_open( PARSE *parse, FRAME *frame )
1686 char* name = lol_get(frame->args, 0)->string;
1687 char* mode = lol_get(frame->args, 1)->string;
1689 char buffer[sizeof("4294967295")];
1691 if (strcmp(mode, "w") == 0)
1693 fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1697 fd = open(name, O_RDONLY);
1702 sprintf(buffer, "%d", fd);
1703 return list_new(L0, newstr(buffer));
1711 LIST *builtin_pad( PARSE *parse, FRAME *frame )
1713 char *string = lol_get(frame->args, 0)->string;
1714 char *width_s = lol_get(frame->args, 1)->string;
1716 int current = strlen (string);
1717 int desired = atoi(width_s);
1718 if (current >= desired)
1719 return list_new (L0, string);
1722 char *buffer = malloc (desired + 1);
1726 strcpy (buffer, string);
1727 for (i = current; i < desired; ++i)
1729 buffer[desired] = '\0';
1730 result = list_new (L0, newstr (buffer));
1736 LIST *builtin_precious( PARSE *parse, FRAME *frame )
1738 LIST* targets = lol_get(frame->args, 0);
1740 for ( ; targets; targets = list_next( targets ) )
1742 TARGET* t = bindtarget (targets->string);
1743 t->flags |= T_FLAG_PRECIOUS;
1749 LIST *builtin_self_path( PARSE *parse, FRAME *frame )
1751 extern char *saved_argv0;
1752 char *p = executable_path (saved_argv0);
1755 LIST* result = list_new (0, newstr (p));
1765 LIST *builtin_makedir( PARSE *parse, FRAME *frame )
1767 LIST *path = lol_get(frame->args, 0);
1769 if (file_mkdir(path->string) == 0)
1771 LIST *result = list_new (0, newstr(path->string));
1782 LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
1784 static int first_time = 1;
1785 char * python_module = lol_get( frame->args, 0 )->string;
1786 char * python_function = lol_get( frame->args, 1 )->string;
1787 char * jam_module = lol_get( frame->args, 2 )->string;
1788 char * jam_rule = lol_get( frame->args, 3 )->string;
1797 /* At the first invocation, we add the value of the global
1798 * EXTRA_PYTHONPATH to the sys.path Python variable.
1801 module_t * outer_module = frame->module;
1805 if ( outer_module != root_module() )
1807 exit_module( outer_module );
1808 enter_module( root_module() );
1811 extra = var_get( "EXTRA_PYTHONPATH" );
1813 if ( outer_module != root_module() )
1815 exit_module( root_module() );
1816 enter_module( outer_module );
1819 for ( ; extra; extra = extra->next )
1823 string_append( buf, "import sys\nsys.path.append(\"" );
1824 string_append( buf, extra->string );
1825 string_append( buf, "\")\n" );
1826 PyRun_SimpleString( buf->value );
1831 pName = PyString_FromString( python_module );
1832 pModule = PyImport_Import( pName );
1835 if ( pModule != NULL )
1837 pDict = PyModule_GetDict( pModule );
1838 pFunc = PyDict_GetItemString( pDict, python_function );
1840 if ( pFunc && PyCallable_Check( pFunc ) )
1842 module_t * m = bindmodule( jam_module );
1843 RULE * r = bindrule( jam_rule, m );
1845 /* Make pFunc owned. */
1848 r->python_function = pFunc;
1852 if ( PyErr_Occurred() )
1854 fprintf( stderr, "Cannot find function \"%s\"\n", python_function );
1856 Py_DECREF( pModule );
1861 fprintf( stderr, "Failed to load \"%s\"\n", python_module );
1869 void lol_build( LOL * lol, char * * elements )
1874 while ( elements && *elements )
1876 if ( !strcmp( *elements, ":" ) )
1883 l = list_new( l, newstr( *elements ) );
1896 * Calls the bjam rule specified by name passed in 'args'. The name is looked up
1897 * in the context of bjam's 'python_interface' module. Returns the list of
1898 * string retured by the rule.
1901 PyObject* bjam_call( PyObject * self, PyObject * args )
1908 /* Build up the list of arg lists. */
1909 frame_init( inner );
1911 inner->prev_user = 0;
1912 inner->module = bindmodule( "python_interface" );
1913 inner->procedure = 0;
1915 /* Extract the rule name and arguments from 'args'. */
1917 /* PyTuple_GetItem returns borrowed reference. */
1918 rulename = PyString_AsString( PyTuple_GetItem( args, 0 ) );
1921 int size = PyTuple_Size( args );
1922 for ( ; i < size; ++i )
1924 PyObject * a = PyTuple_GetItem( args, i );
1925 if ( PyString_Check( a ) )
1927 lol_add( inner->args, list_new( 0, newstr(
1928 PyString_AsString( a ) ) ) );
1930 else if ( PySequence_Check( a ) )
1933 int s = PySequence_Size( a );
1935 for ( ; i < s; ++i )
1937 /* PySequence_GetItem returns new reference. */
1938 PyObject * e = PySequence_GetItem( a, i );
1939 char * s = PyString_AsString( e );
1942 printf( "Invalid parameter type passed from Python\n" );
1945 l = list_new( l, newstr( s ) );
1948 lol_add( inner->args, l );
1953 result = evaluate_rule( rulename, inner );
1955 frame_free( inner );
1957 /* Convert the bjam list into a Python list result. */
1959 PyObject * pyResult = PyList_New( list_length( result ) );
1963 PyList_SetItem( pyResult, i, PyString_FromString( result->string ) );
1964 result = list_next( result );
1967 list_free( result );
1974 * Accepts four arguments:
1977 * - Python callable.
1978 * - (optional) bjam language function signature.
1979 * Creates a bjam rule with the specified name in the specified module, which will
1980 * invoke the Python callable.
1983 PyObject * bjam_import_rule( PyObject * self, PyObject * args )
1988 PyObject * bjam_signature = NULL;
1992 if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
1993 &module, &rule, &func, &bjam_signature ) )
1996 if ( !PyCallable_Check( func ) )
1998 PyErr_SetString( PyExc_RuntimeError,
1999 "Non-callable object passed to bjam.import_rule" );
2003 m = bindmodule( *module ? module : 0 );
2004 r = bindrule( rule, m );
2006 /* Make pFunc owned. */
2009 r->python_function = func;
2014 argument_list * arg_list = args_new();
2017 Py_ssize_t s = PySequence_Size (bjam_signature);
2018 for (i = 0; i < s; ++i)
2020 PyObject* v = PySequence_GetItem (bjam_signature, i);
2021 lol_add(arg_list->data, list_from_python (v));
2024 r->arguments = arg_list;
2027 Py_INCREF( Py_None );
2033 * Accepts four arguments:
2036 * - a list of variable that will be bound inside the action
2038 * Defines an action on bjam side.
2041 PyObject * bjam_define_action( PyObject * self, PyObject * args )
2046 PyObject * bindlist_python;
2048 LIST * bindlist = L0;
2052 if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
2053 &PyList_Type, &bindlist_python, &flags ) )
2056 n = PyList_Size( bindlist_python );
2057 for ( i = 0; i < n; ++i )
2059 PyObject * next = PyList_GetItem( bindlist_python, i );
2060 if ( !PyString_Check( next ) )
2062 PyErr_SetString( PyExc_RuntimeError,
2063 "bind list has non-string type" );
2066 bindlist = list_new( bindlist, PyString_AsString( next ) );
2069 new_rule_actions( root_module(), name, newstr( body ), bindlist, flags );
2071 Py_INCREF( Py_None );
2077 * Returns the value of a variable in root Jam module.
2080 PyObject * bjam_variable( PyObject * self, PyObject * args )
2087 if ( !PyArg_ParseTuple( args, "s", &name ) )
2090 enter_module( root_module() );
2091 value = var_get( name );
2092 exit_module( root_module() );
2094 result = PyList_New( list_length( value ) );
2095 for ( i = 0; value; value = list_next( value ), ++i )
2096 PyList_SetItem( result, i, PyString_FromString( value->string ) );
2102 PyObject * bjam_backtrace( PyObject * self, PyObject * args )
2104 PyObject * result = PyList_New( 0 );
2105 struct frame * f = frame_before_python_call;
2107 for ( ; f = f->prev; )
2109 PyObject * tuple = PyTuple_New( 4 );
2114 get_source_line( f->procedure, &file, &line );
2115 sprintf( buf, "%d", line );
2117 /* PyTuple_SetItem steals reference. */
2118 PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
2119 PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
2120 PyTuple_SetItem( tuple, 2, PyString_FromString( f->module->name ) );
2121 PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
2123 PyList_Append( result, tuple );
2129 PyObject * bjam_caller( PyObject * self, PyObject * args )
2131 PyObject *result = PyString_FromString(
2132 frame_before_python_call->prev->module->name);
2136 #endif /* #ifdef HAVE_PYTHON */
2141 #if defined(_MSC_VER) || defined(__BORLANDC__)
2142 #define popen windows_popen_wrapper
2143 #define pclose _pclose
2146 * This wrapper is a workaround for a funny _popen() feature on Windows
2147 * where it eats external quotes in some cases. The bug seems to be related
2148 * to the quote stripping functionality used by the Windows cmd.exe
2149 * interpreter when its /S is not specified.
2151 * Cleaned up quote from the cmd.exe help screen as displayed on Windows XP
2154 * 1. If all of the following conditions are met, then quote characters on
2155 * the command line are preserved:
2158 * - exactly two quote characters
2159 * - no special characters between the two quote characters, where
2160 * special is one of: &<>()@^|
2161 * - there are one or more whitespace characters between the two quote
2163 * - the string between the two quote characters is the name of an
2166 * 2. Otherwise, old behavior is to see if the first character is a quote
2167 * character and if so, strip the leading character and remove the last
2168 * quote character on the command line, preserving any text after the
2169 * last quote character.
2171 * This causes some commands containing quotes not to be executed correctly.
2174 * "\Long folder name\aaa.exe" --name="Jurko" --no-surname
2176 * would get its outermost quotes stripped and would be executed as:
2178 * \Long folder name\aaa.exe" --name="Jurko --no-surname
2180 * which would report an error about '\Long' not being a valid command.
2182 * cmd.exe help seems to indicate it would be enough to add an extra space
2183 * character in front of the command to avoid this but this does not work,
2184 * most likely due to the shell first stripping all leading whitespace
2185 * characters from the command.
2187 * Solution implemented here is to quote the whole command in case it
2188 * contains any quote characters. Note thought this will not work correctly
2189 * should Windows ever 'fix' this feature.
2190 * (03.06.2008.) (Jurko)
2192 static FILE * windows_popen_wrapper( char * command, char * mode )
2194 int extra_command_quotes_needed = ( strchr( command, '"' ) != 0 );
2195 string quoted_command;
2198 if ( extra_command_quotes_needed )
2200 string_new( "ed_command );
2201 string_append( "ed_command, "\"" );
2202 string_append( "ed_command, command );
2203 string_append( "ed_command, "\"" );
2204 command = quoted_command.value;
2207 result = _popen( command, "r" );
2209 if ( extra_command_quotes_needed )
2210 string_free( "ed_command );
2217 static char * rtrim(char *s)
2221 for(--p; p >= s && isspace(*p); *p-- = 0);
2225 LIST * builtin_shell( PARSE * parse, FRAME * frame )
2227 LIST * command = lol_get( frame->args, 0 );
2231 char buffer[ 1024 ];
2233 int exit_status = -1;
2234 int exit_status_opt = 0;
2235 int no_output_opt = 0;
2236 int strip_eol_opt = 0;
2238 /* Process the variable args options. */
2241 LIST * arg = lol_get( frame->args, a );
2244 if ( strcmp( "exit-status", arg->string ) == 0 )
2246 exit_status_opt = 1;
2248 else if ( strcmp( "no-output", arg->string ) == 0 )
2252 else if ( strcmp("strip-eol", arg->string) == 0 )
2256 arg = lol_get( frame->args, ++a );
2260 /* The following fflush() call seems to be indicated as a workaround for a
2261 * popen() bug on POSIX implementations related to synhronizing input
2262 * stream positions for the called and the calling process.
2266 p = popen( command->string, "r" );
2272 while ( ( ret = fread( buffer, sizeof( char ), sizeof( buffer ) - 1, p ) ) > 0 )
2275 if ( !no_output_opt )
2277 if ( strip_eol_opt )
2279 string_append( &s, buffer );
2283 exit_status = pclose( p );
2285 /* The command output is returned first. */
2286 result = list_new( L0, newstr( s.value ) );
2289 /* The command exit result next. */
2290 if ( exit_status_opt )
2292 if ( WIFEXITED(exit_status) )
2293 exit_status = WEXITSTATUS(exit_status);
2296 sprintf( buffer, "%d", exit_status );
2297 result = list_new( result, newstr( buffer ) );
2303 #else /* #ifdef HAVE_POPEN */
2305 LIST * builtin_shell( PARSE * parse, FRAME * frame )
2310 #endif /* #ifdef HAVE_POPEN */