• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3  *
4  * This file is part of Jam - see jam.c for Copyright information.
5  */
6 
7 #include "jam.h"
8 #include "builtins.h"
9 
10 #include "compile.h"
11 #include "constants.h"
12 #include "cwd.h"
13 #include "debugger.h"
14 #include "filesys.h"
15 #include "frames.h"
16 #include "hash.h"
17 #include "hdrmacro.h"
18 #include "lists.h"
19 #include "make.h"
20 #include "md5.h"
21 #include "native.h"
22 #include "object.h"
23 #include "parse.h"
24 #include "pathsys.h"
25 #include "rules.h"
26 #include "jam_strings.h"
27 #include "subst.h"
28 #include "timestamp.h"
29 #include "variable.h"
30 #include "output.h"
31 
32 #include <ctype.h>
33 
34 #ifdef OS_NT
35 #include <windows.h>
36 #ifndef FSCTL_GET_REPARSE_POINT
37 /* MinGW's version of windows.h is missing this, so we need
38  * to include winioctl.h directly
39  */
40 #include <winioctl.h>
41 #endif
42 
43 /* With VC8 (VS2005) these are not defined:
44  *   FSCTL_GET_REPARSE_POINT  (expects WINVER >= 0x0500 _WIN32_WINNT >= 0x0500 )
45  *   IO_REPARSE_TAG_SYMLINK   (is part of a separate Driver SDK)
46  * So define them explicitly to their expected values.
47  */
48 #ifndef FSCTL_GET_REPARSE_POINT
49 # define FSCTL_GET_REPARSE_POINT 0x000900a8
50 #endif
51 #ifndef IO_REPARSE_TAG_SYMLINK
52 # define IO_REPARSE_TAG_SYMLINK	(0xA000000CL)
53 #endif
54 
55 #include <io.h>
56 #if !defined(__BORLANDC__)
57 #define dup _dup
58 #define dup2 _dup2
59 #define open _open
60 #define close _close
61 #endif /* __BORLANDC__ */
62 #endif /* OS_NT */
63 
64 #if defined(USE_EXECUNIX)
65 # include <sys/types.h>
66 # include <sys/wait.h>
67 #elif defined(OS_VMS)
68 # include <wait.h>
69 #else
70 /*
71  * NT does not have wait() and associated macros and uses the system() return
72  * value instead. Status code group are documented at:
73  * http://msdn.microsoft.com/en-gb/library/ff565436.aspx
74  */
75 # define WIFEXITED(w)  (((w) & 0XFFFFFF00) == 0)
76 # define WEXITSTATUS(w)(w)
77 #endif
78 
79 /*
80  * builtins.c - builtin jam rules
81  *
82  * External routines:
83  *  load_builtins()               - define builtin rules
84  *  unknown_rule()                - reports an unknown rule occurrence to the
85  *                                  user and exits
86  *
87  * Internal routines:
88  *  append_if_exists()            - if file exists, append it to the list
89  *  builtin_calc()                - CALC rule
90  *  builtin_delete_module()       - DELETE_MODULE ( MODULE ? )
91  *  builtin_depends()             - DEPENDS/INCLUDES rule
92  *  builtin_echo()                - ECHO rule
93  *  builtin_exit()                - EXIT rule
94  *  builtin_export()              - EXPORT ( MODULE ? : RULES * )
95  *  builtin_flags()               - NOCARE, NOTFILE, TEMPORARY rule
96  *  builtin_glob()                - GLOB rule
97  *  builtin_glob_recursive()      - ???
98  *  builtin_hdrmacro()            - ???
99  *  builtin_import()              - IMPORT rule
100  *  builtin_match()               - MATCH rule, regexp matching
101  *  builtin_rebuilds()            - REBUILDS rule
102  *  builtin_rulenames()           - RULENAMES ( MODULE ? )
103  *  builtin_split_by_characters() - splits the given string into tokens
104  *  builtin_varnames()            - VARNAMES ( MODULE ? )
105  *  get_source_line()             - get a frame's file and line number
106  *                                  information
107  */
108 
109 
110 /*
111  * compile_builtin() - define builtin rules
112  */
113 
114 #define P0 (PARSE *)0
115 #define C0 (OBJECT *)0
116 
117 #if defined( OS_NT ) || defined( OS_CYGWIN )
118     LIST * builtin_system_registry      ( FRAME *, int );
119     LIST * builtin_system_registry_names( FRAME *, int );
120 #endif
121 
122 int glob( char const * s, char const * c );
123 
124 void backtrace        ( FRAME * );
125 void backtrace_line   ( FRAME * );
126 void print_source_line( FRAME * );
127 
128 
bind_builtin(char const * name_,LIST * (* f)(FRAME *,int flags),int flags,char const ** args)129 RULE * bind_builtin( char const * name_, LIST * (* f)( FRAME *, int flags ),
130     int flags, char const * * args )
131 {
132     FUNCTION * func;
133     RULE * result;
134     OBJECT * name = object_new( name_ );
135 
136     func = function_builtin( f, flags, args );
137 
138     result = new_rule_body( root_module(), name, func, 1 );
139 
140     function_free( func );
141 
142     object_free( name );
143 
144     return result;
145 }
146 
147 
duplicate_rule(char const * name_,RULE * other)148 RULE * duplicate_rule( char const * name_, RULE * other )
149 {
150     OBJECT * name = object_new( name_ );
151     RULE * result = import_rule( other, root_module(), name );
152     object_free( name );
153     return result;
154 }
155 
156 
157 /*
158  *  load_builtins() - define builtin rules
159  */
160 
load_builtins()161 void load_builtins()
162 {
163     duplicate_rule( "Always",
164       bind_builtin( "ALWAYS",
165                     builtin_flags, T_FLAG_TOUCHED, 0 ) );
166 
167     duplicate_rule( "Depends",
168       bind_builtin( "DEPENDS",
169                     builtin_depends, 0, 0 ) );
170 
171     duplicate_rule( "echo",
172     duplicate_rule( "Echo",
173       bind_builtin( "ECHO",
174                     builtin_echo, 0, 0 ) ) );
175 
176     {
177         char const * args[] = { "message", "*", ":", "result-value", "?", 0 };
178         duplicate_rule( "exit",
179         duplicate_rule( "Exit",
180           bind_builtin( "EXIT",
181                         builtin_exit, 0, args ) ) );
182     }
183 
184     {
185         char const * args[] = { "directories", "*", ":", "patterns", "*", ":",
186             "case-insensitive", "?", 0 };
187         duplicate_rule( "Glob",
188                         bind_builtin( "GLOB", builtin_glob, 0, args ) );
189     }
190 
191     {
192         char const * args[] = { "patterns", "*", 0 };
193         bind_builtin( "GLOB-RECURSIVELY",
194                       builtin_glob_recursive, 0, args );
195     }
196 
197     duplicate_rule( "Includes",
198       bind_builtin( "INCLUDES",
199                     builtin_depends, 1, 0 ) );
200 
201     {
202         char const * args[] = { "targets", "*", ":", "targets-to-rebuild", "*",
203             0 };
204         bind_builtin( "REBUILDS",
205                       builtin_rebuilds, 0, args );
206     }
207 
208     duplicate_rule( "Leaves",
209       bind_builtin( "LEAVES",
210                     builtin_flags, T_FLAG_LEAVES, 0 ) );
211 
212     duplicate_rule( "Match",
213       bind_builtin( "MATCH",
214                     builtin_match, 0, 0 ) );
215 
216     {
217         char const * args[] = { "string", ":", "delimiters", 0 };
218         bind_builtin( "SPLIT_BY_CHARACTERS",
219                       builtin_split_by_characters, 0, args );
220     }
221 
222     duplicate_rule( "NoCare",
223       bind_builtin( "NOCARE",
224                     builtin_flags, T_FLAG_NOCARE, 0 ) );
225 
226     duplicate_rule( "NOTIME",
227     duplicate_rule( "NotFile",
228       bind_builtin( "NOTFILE",
229                     builtin_flags, T_FLAG_NOTFILE, 0 ) ) );
230 
231     duplicate_rule( "NoUpdate",
232       bind_builtin( "NOUPDATE",
233                     builtin_flags, T_FLAG_NOUPDATE, 0 ) );
234 
235     duplicate_rule( "Temporary",
236       bind_builtin( "TEMPORARY",
237                     builtin_flags, T_FLAG_TEMP, 0 ) );
238 
239       bind_builtin( "ISFILE",
240                     builtin_flags, T_FLAG_ISFILE, 0 );
241 
242     duplicate_rule( "HdrMacro",
243       bind_builtin( "HDRMACRO",
244                     builtin_hdrmacro, 0, 0 ) );
245 
246     /* FAIL_EXPECTED is used to indicate that the result of a target build
247      * action should be inverted (ok <=> fail) this can be useful when
248      * performing test runs from Jamfiles.
249      */
250     bind_builtin( "FAIL_EXPECTED",
251                   builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
252 
253     bind_builtin( "RMOLD",
254                   builtin_flags, T_FLAG_RMOLD, 0 );
255 
256     {
257         char const * args[] = { "targets", "*", 0 };
258         bind_builtin( "UPDATE",
259                       builtin_update, 0, args );
260     }
261 
262     {
263         char const * args[] = { "targets", "*",
264                             ":", "log", "?",
265                             ":", "ignore-minus-n", "?",
266                             ":", "ignore-minus-q", "?", 0 };
267         bind_builtin( "UPDATE_NOW",
268                       builtin_update_now, 0, args );
269     }
270 
271     {
272         char const * args[] = { "string", "pattern", "replacements", "+", 0 };
273         duplicate_rule( "subst",
274           bind_builtin( "SUBST",
275                         builtin_subst, 0, args ) );
276     }
277 
278     {
279         char const * args[] = { "module", "?", 0 };
280         bind_builtin( "RULENAMES",
281                        builtin_rulenames, 0, args );
282     }
283 
284     {
285         char const * args[] = { "module", "?", 0 };
286         bind_builtin( "VARNAMES",
287                        builtin_varnames, 0, args );
288     }
289 
290     {
291         char const * args[] = { "module", "?", 0 };
292         bind_builtin( "DELETE_MODULE",
293                        builtin_delete_module, 0, args );
294     }
295 
296     {
297         char const * args[] = { "source_module", "?",
298                             ":", "source_rules", "*",
299                             ":", "target_module", "?",
300                             ":", "target_rules", "*",
301                             ":", "localize", "?", 0 };
302         bind_builtin( "IMPORT",
303                       builtin_import, 0, args );
304     }
305 
306     {
307         char const * args[] = { "module", "?", ":", "rules", "*", 0 };
308         bind_builtin( "EXPORT",
309                       builtin_export, 0, args );
310     }
311 
312     {
313         char const * args[] = { "levels", "?", 0 };
314         bind_builtin( "CALLER_MODULE",
315                        builtin_caller_module, 0, args );
316     }
317 
318     {
319         char const * args[] = { "levels", "?", 0 };
320         bind_builtin( "BACKTRACE",
321                       builtin_backtrace, 0, args );
322     }
323 
324     {
325         char const * args[] = { 0 };
326         bind_builtin( "PWD",
327                       builtin_pwd, 0, args );
328     }
329 
330     {
331         char const * args[] = { "modules_to_import", "+",
332                             ":", "target_module", "?", 0 };
333         bind_builtin( "IMPORT_MODULE",
334                       builtin_import_module, 0, args );
335     }
336 
337     {
338         char const * args[] = { "module", "?", 0 };
339         bind_builtin( "IMPORTED_MODULES",
340                       builtin_imported_modules, 0, args );
341     }
342 
343     {
344         char const * args[] = { "instance_module", ":", "class_module", 0 };
345         bind_builtin( "INSTANCE",
346                       builtin_instance, 0, args );
347     }
348 
349     {
350         char const * args[] = { "sequence", "*", 0 };
351         bind_builtin( "SORT",
352                       builtin_sort, 0, args );
353     }
354 
355     {
356         char const * args[] = { "path_parts", "*", 0 };
357         bind_builtin( "NORMALIZE_PATH",
358                       builtin_normalize_path, 0, args );
359     }
360 
361     {
362         char const * args[] = { "args", "*", 0 };
363         bind_builtin( "CALC",
364                       builtin_calc, 0, args );
365     }
366 
367     {
368         char const * args[] = { "module", ":", "rule", 0 };
369         bind_builtin( "NATIVE_RULE",
370                       builtin_native_rule, 0, args );
371     }
372 
373     {
374         char const * args[] = { "module", ":", "rule", ":", "version", 0 };
375         bind_builtin( "HAS_NATIVE_RULE",
376                       builtin_has_native_rule, 0, args );
377     }
378 
379     {
380         char const * args[] = { "module", "*", 0 };
381         bind_builtin( "USER_MODULE",
382                       builtin_user_module, 0, args );
383     }
384 
385     {
386         char const * args[] = { 0 };
387         bind_builtin( "NEAREST_USER_LOCATION",
388                       builtin_nearest_user_location, 0, args );
389     }
390 
391     {
392         char const * args[] = { "file", 0 };
393         bind_builtin( "CHECK_IF_FILE",
394                       builtin_check_if_file, 0, args );
395     }
396 
397 #ifdef HAVE_PYTHON
398     {
399         char const * args[] = { "python-module",
400                             ":", "function",
401                             ":", "jam-module",
402                             ":", "rule-name", 0 };
403         bind_builtin( "PYTHON_IMPORT_RULE",
404                       builtin_python_import_rule, 0, args );
405     }
406 #endif
407 
408 # if defined( OS_NT ) || defined( OS_CYGWIN )
409     {
410         char const * args[] = { "key_path", ":", "data", "?", 0 };
411         bind_builtin( "W32_GETREG",
412                       builtin_system_registry, 0, args );
413     }
414 
415     {
416         char const * args[] = { "key_path", ":", "result-type", 0 };
417         bind_builtin( "W32_GETREGNAMES",
418                       builtin_system_registry_names, 0, args );
419     }
420 # endif
421 
422     {
423         char const * args[] = { "command", ":", "*", 0 };
424         duplicate_rule( "SHELL",
425           bind_builtin( "COMMAND",
426                         builtin_shell, 0, args ) );
427     }
428 
429     {
430         char const * args[] = { "string", 0 };
431         bind_builtin( "MD5",
432                       builtin_md5, 0, args );
433     }
434 
435     {
436         char const * args[] = { "name", ":", "mode", 0 };
437         bind_builtin( "FILE_OPEN",
438                       builtin_file_open, 0, args );
439     }
440 
441     {
442         char const * args[] = { "string", ":", "width", 0 };
443         bind_builtin( "PAD",
444                       builtin_pad, 0, args );
445     }
446 
447     {
448         char const * args[] = { "targets", "*", 0 };
449         bind_builtin( "PRECIOUS",
450                       builtin_precious, 0, args );
451     }
452 
453     {
454         char const * args [] = { 0 };
455         bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
456     }
457 
458     {
459         char const * args [] = { "path", 0 };
460         bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
461     }
462 
463     {
464         const char * args [] = { "path", 0 };
465         bind_builtin( "READLINK", builtin_readlink, 0, args );
466     }
467 
468     {
469         char const * args[] = { "archives", "*",
470                                 ":", "member-patterns", "*",
471                                 ":", "case-insensitive", "?",
472                                 ":", "symbol-patterns", "*", 0 };
473         bind_builtin( "GLOB_ARCHIVE", builtin_glob_archive, 0, args );
474     }
475 
476 #ifdef JAM_DEBUGGER
477 
478 	{
479 		const char * args[] = { "list", "*", 0 };
480 		bind_builtin("__DEBUG_PRINT_HELPER__", builtin_debug_print_helper, 0, args);
481 	}
482 
483 #endif
484 
485     /* Initialize builtin modules. */
486     init_set();
487     init_path();
488     init_regex();
489     init_property_set();
490     init_sequence();
491     init_order();
492 }
493 
494 
495 /*
496  * builtin_calc() - CALC rule
497  *
498  * Performs simple mathematical operations on two arguments.
499  */
500 
builtin_calc(FRAME * frame,int flags)501 LIST * builtin_calc( FRAME * frame, int flags )
502 {
503     LIST * arg = lol_get( frame->args, 0 );
504 
505     LIST * result = L0;
506     long lhs_value;
507     long rhs_value;
508     long result_value;
509     char buffer[ 16 ];
510     char const * lhs;
511     char const * op;
512     char const * rhs;
513     LISTITER iter = list_begin( arg );
514     LISTITER const end = list_end( arg );
515 
516     if ( iter == end ) return L0;
517     lhs = object_str( list_item( iter ) );
518 
519     iter = list_next( iter );
520     if ( iter == end ) return L0;
521     op = object_str( list_item( iter ) );
522 
523     iter = list_next( iter );
524     if ( iter == end ) return L0;
525     rhs = object_str( list_item( iter ) );
526 
527     lhs_value = atoi( lhs );
528     rhs_value = atoi( rhs );
529 
530     if ( !strcmp( "+", op ) )
531         result_value = lhs_value + rhs_value;
532     else if ( !strcmp( "-", op ) )
533         result_value = lhs_value - rhs_value;
534     else
535         return L0;
536 
537     sprintf( buffer, "%ld", result_value );
538     result = list_push_back( result, object_new( buffer ) );
539     return result;
540 }
541 
542 
543 /*
544  * builtin_depends() - DEPENDS/INCLUDES rule
545  *
546  * The DEPENDS/INCLUDES builtin rule appends each of the listed sources on the
547  * dependency/includes list of each of the listed targets. It binds both the
548  * targets and sources as TARGETs.
549  */
550 
builtin_depends(FRAME * frame,int flags)551 LIST * builtin_depends( FRAME * frame, int flags )
552 {
553     LIST * const targets = lol_get( frame->args, 0 );
554     LIST * const sources = lol_get( frame->args, 1 );
555 
556     LISTITER iter = list_begin( targets );
557     LISTITER end = list_end( targets );
558     for ( ; iter != end; iter = list_next( iter ) )
559     {
560         TARGET * const t = bindtarget( list_item( iter ) );
561 
562         if ( flags )
563             target_include_many( t, sources );
564         else
565             t->depends = targetlist( t->depends, sources );
566     }
567 
568     /* Enter reverse links */
569     iter = list_begin( sources );
570     end = list_end( sources );
571     for ( ; iter != end; iter = list_next( iter ) )
572     {
573         TARGET * const s = bindtarget( list_item( iter ) );
574         if ( flags )
575         {
576             LISTITER t_iter = list_begin( targets );
577             LISTITER const t_end = list_end( targets );
578             for ( ; t_iter != t_end; t_iter = list_next( t_iter ) )
579                 s->dependants = targetentry( s->dependants, bindtarget(
580                     list_item( t_iter ) )->includes );
581         }
582         else
583             s->dependants = targetlist( s->dependants, targets );
584     }
585 
586     return L0;
587 }
588 
589 
590 /*
591  * builtin_rebuilds() - REBUILDS rule
592  *
593  * Appends each of the rebuild-targets listed in its second argument to the
594  * rebuilds list for each of the targets listed in its first argument.
595  */
596 
builtin_rebuilds(FRAME * frame,int flags)597 LIST * builtin_rebuilds( FRAME * frame, int flags )
598 {
599     LIST * targets = lol_get( frame->args, 0 );
600     LIST * rebuilds = lol_get( frame->args, 1 );
601     LISTITER iter = list_begin( targets );
602     LISTITER const end = list_end( targets );
603     for ( ; iter != end; iter = list_next( iter ) )
604     {
605         TARGET * const t = bindtarget( list_item( iter ) );
606         t->rebuilds = targetlist( t->rebuilds, rebuilds );
607     }
608     return L0;
609 }
610 
611 
612 /*
613  * builtin_echo() - ECHO rule
614  *
615  * Echoes the targets to the user. No other actions are taken.
616  */
617 
builtin_echo(FRAME * frame,int flags)618 LIST * builtin_echo( FRAME * frame, int flags )
619 {
620     list_print( lol_get( frame->args, 0 ) );
621     out_printf( "\n" );
622     out_flush();
623     return L0;
624 }
625 
626 
627 /*
628  * builtin_exit() - EXIT rule
629  *
630  * Echoes the targets to the user and exits the program with a failure status.
631  */
632 
builtin_exit(FRAME * frame,int flags)633 LIST * builtin_exit( FRAME * frame, int flags )
634 {
635     LIST * const code = lol_get( frame->args, 1 );
636     list_print( lol_get( frame->args, 0 ) );
637     out_printf( "\n" );
638     if ( !list_empty( code ) )
639     {
640         int status = atoi( object_str( list_front( code ) ) );
641 #ifdef OS_VMS
642         switch( status )
643         {
644         case 0:
645             status = EXITOK;
646             break;
647         case 1:
648             status = EXITBAD;
649             break;
650         }
651 #endif
652         exit( status );
653     }
654     else
655         exit( EXITBAD );  /* yeech */
656     return L0;
657 }
658 
659 
660 /*
661  * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
662  *
663  * Marks the target with the appropriate flag, for use by make0(). It binds each
664  * target as a TARGET.
665  */
666 
builtin_flags(FRAME * frame,int flags)667 LIST * builtin_flags( FRAME * frame, int flags )
668 {
669     LIST * const targets = lol_get( frame->args, 0 );
670     LISTITER iter = list_begin( targets );
671     LISTITER const end = list_end( targets );
672     for ( ; iter != end; iter = list_next( iter ) )
673         bindtarget( list_item( iter ) )->flags |= flags;
674     return L0;
675 }
676 
677 
678 /*
679  * builtin_glob() - GLOB rule
680  */
681 
682 struct globbing
683 {
684     LIST * patterns;
685     LIST * results;
686     LIST * case_insensitive;
687 };
688 
689 
downcase_inplace(char * p)690 static void downcase_inplace( char * p )
691 {
692     for ( ; *p; ++p )
693         *p = tolower( *p );
694 }
695 
696 
builtin_glob_back(void * closure,OBJECT * file,int status,timestamp const * const time)697 static void builtin_glob_back( void * closure, OBJECT * file, int status,
698     timestamp const * const time )
699 {
700     PROFILE_ENTER( BUILTIN_GLOB_BACK );
701 
702     struct globbing * const globbing = (struct globbing *)closure;
703     PATHNAME f;
704     string buf[ 1 ];
705     LISTITER iter;
706     LISTITER end;
707 
708     /* Null out directory for matching. We wish we had file_dirscan() pass up a
709      * PATHNAME.
710      */
711     path_parse( object_str( file ), &f );
712     f.f_dir.len = 0;
713 
714     /* For globbing, we unconditionally ignore current and parent directory
715      * items. Since these items always exist, there is no reason why caller of
716      * GLOB would want to see them. We could also change file_dirscan(), but
717      * then paths with embedded "." and ".." would not work anywhere.
718     */
719     if ( !strcmp( f.f_base.ptr, "." ) || !strcmp( f.f_base.ptr, ".." ) )
720     {
721         PROFILE_EXIT( BUILTIN_GLOB_BACK );
722         return;
723     }
724 
725     string_new( buf );
726     path_build( &f, buf );
727 
728     if ( globbing->case_insensitive )
729         downcase_inplace( buf->value );
730 
731     iter = list_begin( globbing->patterns );
732     end = list_end( globbing->patterns );
733     for ( ; iter != end; iter = list_next( iter ) )
734     {
735         if ( !glob( object_str( list_item( iter ) ), buf->value ) )
736         {
737             globbing->results = list_push_back( globbing->results, object_copy(
738                 file ) );
739             break;
740         }
741     }
742 
743     string_free( buf );
744 
745     PROFILE_EXIT( BUILTIN_GLOB_BACK );
746 }
747 
748 
downcase_list(LIST * in)749 static LIST * downcase_list( LIST * in )
750 {
751     LIST * result = L0;
752     LISTITER iter = list_begin( in );
753     LISTITER const end = list_end( in );
754 
755     string s[ 1 ];
756     string_new( s );
757 
758     for ( ; iter != end; iter = list_next( iter ) )
759     {
760         string_append( s, object_str( list_item( iter ) ) );
761         downcase_inplace( s->value );
762         result = list_push_back( result, object_new( s->value ) );
763         string_truncate( s, 0 );
764     }
765 
766     string_free( s );
767     return result;
768 }
769 
770 
builtin_glob(FRAME * frame,int flags)771 LIST * builtin_glob( FRAME * frame, int flags )
772 {
773     LIST * const l = lol_get( frame->args, 0 );
774     LIST * const r = lol_get( frame->args, 1 );
775 
776     LISTITER iter;
777     LISTITER end;
778     struct globbing globbing;
779 
780     globbing.results = L0;
781     globbing.patterns = r;
782 
783     globbing.case_insensitive =
784 # if defined( OS_NT ) || defined( OS_CYGWIN ) || defined( OS_VMS )
785        l;  /* Always case-insensitive if any files can be found. */
786 # else
787        lol_get( frame->args, 2 );
788 # endif
789 
790     if ( globbing.case_insensitive )
791         globbing.patterns = downcase_list( r );
792 
793     iter = list_begin( l );
794     end = list_end( l );
795     for ( ; iter != end; iter = list_next( iter ) )
796         file_dirscan( list_item( iter ), builtin_glob_back, &globbing );
797 
798     if ( globbing.case_insensitive )
799         list_free( globbing.patterns );
800 
801     return globbing.results;
802 }
803 
804 
has_wildcards(char const * const str)805 static int has_wildcards( char const * const str )
806 {
807     return str[ strcspn( str, "[]*?" ) ] ? 1 : 0;
808 }
809 
810 
811 /*
812  * append_if_exists() - if file exists, append it to the list
813  */
814 
append_if_exists(LIST * list,OBJECT * file)815 static LIST * append_if_exists( LIST * list, OBJECT * file )
816 {
817     file_info_t * info = file_query( file );
818     return info
819         ? list_push_back( list, object_copy( info->name ) )
820         : list ;
821 }
822 
823 
glob1(OBJECT * dirname,OBJECT * pattern)824 LIST * glob1( OBJECT * dirname, OBJECT * pattern )
825 {
826     LIST * const plist = list_new( object_copy( pattern ) );
827     struct globbing globbing;
828 
829     globbing.results = L0;
830     globbing.patterns = plist;
831 
832     globbing.case_insensitive
833 # if defined( OS_NT ) || defined( OS_CYGWIN ) || defined( OS_VMS )
834        = plist;  /* always case-insensitive if any files can be found */
835 # else
836        = L0;
837 # endif
838 
839     if ( globbing.case_insensitive )
840         globbing.patterns = downcase_list( plist );
841 
842     file_dirscan( dirname, builtin_glob_back, &globbing );
843 
844     if ( globbing.case_insensitive )
845         list_free( globbing.patterns );
846 
847     list_free( plist );
848 
849     return globbing.results;
850 }
851 
852 
glob_recursive(char const * pattern)853 LIST * glob_recursive( char const * pattern )
854 {
855     LIST * result = L0;
856 
857     /* Check if there's metacharacters in pattern */
858     if ( !has_wildcards( pattern ) )
859     {
860         /* No metacharacters. Check if the path exists. */
861         OBJECT * const p = object_new( pattern );
862         result = append_if_exists( result, p );
863         object_free( p );
864     }
865     else
866     {
867         /* Have metacharacters in the pattern. Split into dir/name. */
868         PATHNAME path[ 1 ];
869         path_parse( pattern, path );
870 
871         if ( path->f_dir.ptr )
872         {
873             LIST * dirs = L0;
874             string dirname[ 1 ];
875             string basename[ 1 ];
876             string_new( dirname );
877             string_new( basename );
878 
879             string_append_range( dirname, path->f_dir.ptr,
880                                 path->f_dir.ptr + path->f_dir.len );
881 
882             path->f_grist.ptr = 0;
883             path->f_grist.len = 0;
884             path->f_dir.ptr = 0;
885             path->f_dir.len = 0;
886             path_build( path, basename );
887 
888             dirs =  has_wildcards( dirname->value )
889                 ? glob_recursive( dirname->value )
890                 : list_push_back( dirs, object_new( dirname->value ) );
891 
892             if ( has_wildcards( basename->value ) )
893             {
894                 OBJECT * const b = object_new( basename->value );
895                 LISTITER iter = list_begin( dirs );
896                 LISTITER const end = list_end( dirs );
897                 for ( ; iter != end; iter = list_next( iter ) )
898                     result = list_append( result, glob1( list_item( iter ), b )
899                         );
900                 object_free( b );
901             }
902             else
903             {
904                 LISTITER iter = list_begin( dirs );
905                 LISTITER const end = list_end( dirs );
906                 string file_string[ 1 ];
907                 string_new( file_string );
908 
909                 /* No wildcard in basename. */
910                 for ( ; iter != end; iter = list_next( iter ) )
911                 {
912                     OBJECT * p;
913                     path->f_dir.ptr = object_str( list_item( iter ) );
914                     path->f_dir.len = strlen( object_str( list_item( iter ) ) );
915                     path_build( path, file_string );
916 
917                     p = object_new( file_string->value );
918 
919                     result = append_if_exists( result, p );
920 
921                     object_free( p );
922 
923                     string_truncate( file_string, 0 );
924                 }
925 
926                 string_free( file_string );
927             }
928 
929             string_free( dirname );
930             string_free( basename );
931 
932             list_free( dirs );
933         }
934         else
935         {
936             /* No directory, just a pattern. */
937             OBJECT * const p = object_new( pattern );
938             result = list_append( result, glob1( constant_dot, p ) );
939             object_free( p );
940         }
941     }
942 
943     return result;
944 }
945 
946 
947 /*
948  * builtin_glob_recursive() - ???
949  */
950 
builtin_glob_recursive(FRAME * frame,int flags)951 LIST * builtin_glob_recursive( FRAME * frame, int flags )
952 {
953     LIST * result = L0;
954     LIST * const l = lol_get( frame->args, 0 );
955     LISTITER iter = list_begin( l );
956     LISTITER const end = list_end( l );
957     for ( ; iter != end; iter = list_next( iter ) )
958         result = list_append( result, glob_recursive( object_str( list_item(
959             iter ) ) ) );
960     return result;
961 }
962 
963 
964 /*
965  * builtin_match() - MATCH rule, regexp matching
966  */
967 
builtin_match(FRAME * frame,int flags)968 LIST * builtin_match( FRAME * frame, int flags )
969 {
970     LIST * l;
971     LIST * r;
972     LIST * result = L0;
973     LISTITER l_iter;
974     LISTITER l_end;
975     LISTITER r_iter;
976     LISTITER r_end;
977 
978     string buf[ 1 ];
979     string_new( buf );
980 
981     /* For each pattern */
982 
983     l = lol_get( frame->args, 0 );
984     l_iter = list_begin( l );
985     l_end = list_end( l );
986     for ( ; l_iter != l_end; l_iter = list_next( l_iter ) )
987     {
988         /* Result is cached and intentionally never freed. */
989         regexp * re = regex_compile( list_item( l_iter ) );
990 
991         /* For each string to match against. */
992         r = lol_get( frame->args, 1 );
993         r_iter = list_begin( r );
994         r_end = list_end( r );
995         for ( ; r_iter != r_end; r_iter = list_next( r_iter ) )
996         {
997             if ( regexec( re, object_str( list_item( r_iter ) ) ) )
998             {
999                 int i;
1000                 int top;
1001 
1002                 /* Find highest parameter */
1003 
1004                 for ( top = NSUBEXP; top-- > 1; )
1005                     if ( re->startp[ top ] )
1006                         break;
1007 
1008                 /* And add all parameters up to highest onto list. */
1009                 /* Must have parameters to have results! */
1010                 for ( i = 1; i <= top; ++i )
1011                 {
1012                     string_append_range( buf, re->startp[ i ], re->endp[ i ] );
1013                     result = list_push_back( result, object_new( buf->value ) );
1014                     string_truncate( buf, 0 );
1015                 }
1016             }
1017         }
1018     }
1019 
1020     string_free( buf );
1021     return result;
1022 }
1023 
1024 
1025 /*
1026  * builtin_split_by_characters() - splits the given string into tokens
1027  */
1028 
builtin_split_by_characters(FRAME * frame,int flags)1029 LIST * builtin_split_by_characters( FRAME * frame, int flags )
1030 {
1031     LIST * l1 = lol_get( frame->args, 0 );
1032     LIST * l2 = lol_get( frame->args, 1 );
1033 
1034     LIST * result = L0;
1035 
1036     string buf[ 1 ];
1037 
1038     char const * delimiters = object_str( list_front( l2 ) );
1039     char * t;
1040 
1041     string_copy( buf, object_str( list_front( l1 ) ) );
1042 
1043     t = strtok( buf->value, delimiters );
1044     while ( t )
1045     {
1046         result = list_push_back( result, object_new( t ) );
1047         t = strtok( NULL, delimiters );
1048     }
1049 
1050     string_free( buf );
1051 
1052     return result;
1053 }
1054 
1055 
1056 /*
1057  * builtin_hdrmacro() - ???
1058  */
1059 
builtin_hdrmacro(FRAME * frame,int flags)1060 LIST * builtin_hdrmacro( FRAME * frame, int flags )
1061 {
1062     LIST * const l = lol_get( frame->args, 0 );
1063     LISTITER iter = list_begin( l );
1064     LISTITER const end = list_end( l );
1065 
1066     for ( ; iter != end; iter = list_next( iter ) )
1067     {
1068         TARGET * const t = bindtarget( list_item( iter ) );
1069 
1070         /* Scan file for header filename macro definitions. */
1071         if ( DEBUG_HEADER )
1072             out_printf( "scanning '%s' for header file macro definitions\n",
1073                 object_str( list_item( iter ) ) );
1074 
1075         macro_headers( t );
1076     }
1077 
1078     return L0;
1079 }
1080 
1081 
1082 /*
1083  * builtin_rulenames() - RULENAMES ( MODULE ? )
1084  *
1085  * Returns a list of the non-local rule names in the given MODULE. If MODULE is
1086  * not supplied, returns the list of rule names in the global module.
1087  */
1088 
add_rule_name(void * r_,void * result_)1089 static void add_rule_name( void * r_, void * result_ )
1090 {
1091     RULE * const r = (RULE *)r_;
1092     LIST * * const result = (LIST * *)result_;
1093     if ( r->exported )
1094         *result = list_push_back( *result, object_copy( r->name ) );
1095 }
1096 
1097 
builtin_rulenames(FRAME * frame,int flags)1098 LIST * builtin_rulenames( FRAME * frame, int flags )
1099 {
1100     LIST * arg0 = lol_get( frame->args, 0 );
1101     LIST * result = L0;
1102     module_t * const source_module = bindmodule( list_empty( arg0 )
1103         ? 0
1104         : list_front( arg0 ) );
1105 
1106     if ( source_module->rules )
1107         hashenumerate( source_module->rules, add_rule_name, &result );
1108     return result;
1109 }
1110 
1111 
1112 /*
1113  * builtin_varnames() - VARNAMES ( MODULE ? )
1114  *
1115  * Returns a list of the variable names in the given MODULE. If MODULE is not
1116  * supplied, returns the list of variable names in the global module.
1117  */
1118 
1119 /* helper function for builtin_varnames(), below. Used with hashenumerate, will
1120  * prepend the key of each element to the list
1121  */
add_hash_key(void * np,void * result_)1122 static void add_hash_key( void * np, void * result_ )
1123 {
1124     LIST * * result = (LIST * *)result_;
1125     *result = list_push_back( *result, object_copy( *(OBJECT * *)np ) );
1126 }
1127 
1128 
builtin_varnames(FRAME * frame,int flags)1129 LIST * builtin_varnames( FRAME * frame, int flags )
1130 {
1131     LIST * arg0 = lol_get( frame->args, 0 );
1132     LIST * result = L0;
1133     module_t * source_module = bindmodule( list_empty( arg0 )
1134         ? 0
1135         : list_front( arg0 ) );
1136 
1137     struct hash * const vars = source_module->variables;
1138     if ( vars )
1139         hashenumerate( vars, add_hash_key, &result );
1140     return result;
1141 }
1142 
1143 
1144 /*
1145  * builtin_delete_module() - DELETE_MODULE ( MODULE ? )
1146  *
1147  * Clears all rules and variables from the given module.
1148  */
1149 
builtin_delete_module(FRAME * frame,int flags)1150 LIST * builtin_delete_module( FRAME * frame, int flags )
1151 {
1152     LIST * const arg0 = lol_get( frame->args, 0 );
1153     module_t * const source_module = bindmodule( list_empty( arg0 ) ? 0 :
1154         list_front( arg0 ) );
1155     delete_module( source_module );
1156     return L0;
1157 }
1158 
1159 
1160 /*
1161  * unknown_rule() - reports an unknown rule occurrence to the user and exits
1162  */
1163 
unknown_rule(FRAME * frame,char const * key,module_t * module,OBJECT * rule_name)1164 void unknown_rule( FRAME * frame, char const * key, module_t * module,
1165     OBJECT * rule_name )
1166 {
1167     backtrace_line( frame->prev );
1168     if ( key )
1169         out_printf("%s error", key);
1170     else
1171         out_printf("ERROR");
1172     out_printf( ": rule \"%s\" unknown in ", object_str( rule_name ) );
1173     if ( module->name )
1174         out_printf( "module \"%s\".\n", object_str( module->name ) );
1175     else
1176         out_printf( "root module.\n" );
1177     backtrace( frame->prev );
1178     exit( EXITBAD );
1179 }
1180 
1181 
1182 /*
1183  * builtin_import() - IMPORT rule
1184  *
1185  * IMPORT
1186  * (
1187  *     SOURCE_MODULE ? :
1188  *     SOURCE_RULES  * :
1189  *     TARGET_MODULE ? :
1190  *     TARGET_RULES  * :
1191  *     LOCALIZE      ?
1192  * )
1193  *
1194  * Imports rules from the SOURCE_MODULE into the TARGET_MODULE as local rules.
1195  * If either SOURCE_MODULE or TARGET_MODULE is not supplied, it refers to the
1196  * global module. SOURCE_RULES specifies which rules from the SOURCE_MODULE to
1197  * import; TARGET_RULES specifies the names to give those rules in
1198  * TARGET_MODULE. If SOURCE_RULES contains a name that does not correspond to
1199  * a rule in SOURCE_MODULE, or if it contains a different number of items than
1200  * TARGET_RULES, an error is issued. If LOCALIZE is specified, the rules will be
1201  * executed in TARGET_MODULE, with corresponding access to its module local
1202  * variables.
1203  */
1204 
builtin_import(FRAME * frame,int flags)1205 LIST * builtin_import( FRAME * frame, int flags )
1206 {
1207     LIST * source_module_list = lol_get( frame->args, 0 );
1208     LIST * source_rules       = lol_get( frame->args, 1 );
1209     LIST * target_module_list = lol_get( frame->args, 2 );
1210     LIST * target_rules       = lol_get( frame->args, 3 );
1211     LIST * localize           = lol_get( frame->args, 4 );
1212 
1213     module_t * target_module = bindmodule( list_empty( target_module_list )
1214         ? 0
1215         : list_front( target_module_list ) );
1216     module_t * source_module = bindmodule( list_empty( source_module_list )
1217         ? 0
1218         : list_front( source_module_list ) );
1219 
1220     LISTITER source_iter = list_begin( source_rules );
1221     LISTITER const source_end = list_end( source_rules );
1222     LISTITER target_iter = list_begin( target_rules );
1223     LISTITER const target_end = list_end( target_rules );
1224 
1225     for ( ;
1226           source_iter != source_end && target_iter != target_end;
1227           source_iter = list_next( source_iter ),
1228           target_iter = list_next( target_iter ) )
1229     {
1230         RULE * r = nullptr;
1231         RULE * imported = nullptr;
1232 
1233         if ( !source_module->rules || !(r = (RULE *)hash_find(
1234             source_module->rules, list_item( source_iter ) ) ) )
1235         {
1236             unknown_rule( frame, "IMPORT", source_module, list_item( source_iter
1237                 ) );
1238         }
1239 
1240         imported = import_rule( r, target_module, list_item( target_iter ) );
1241         if ( !list_empty( localize ) )
1242             rule_localize( imported, target_module );
1243         /* This rule is really part of some other module. Just refer to it here,
1244          * but do not let it out.
1245          */
1246         imported->exported = 0;
1247     }
1248 
1249     if ( source_iter != source_end || target_iter != target_end )
1250     {
1251         backtrace_line( frame->prev );
1252         out_printf( "import error: length of source and target rule name lists "
1253             "don't match!\n" );
1254         out_printf( "    source: " );
1255         list_print( source_rules );
1256         out_printf( "\n    target: " );
1257         list_print( target_rules );
1258         out_printf( "\n" );
1259         backtrace( frame->prev );
1260         exit( EXITBAD );
1261     }
1262 
1263     return L0;
1264 }
1265 
1266 
1267 /*
1268  * builtin_export() - EXPORT ( MODULE ? : RULES * )
1269  *
1270  * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local (and thus
1271  * exportable). If an element of RULES does not name a rule in MODULE, an error
1272  * is issued.
1273  */
1274 
builtin_export(FRAME * frame,int flags)1275 LIST * builtin_export( FRAME * frame, int flags )
1276 {
1277     LIST * const module_list = lol_get( frame->args, 0 );
1278     LIST * const rules = lol_get( frame->args, 1 );
1279     module_t * const m = bindmodule( list_empty( module_list ) ? 0 : list_front(
1280         module_list ) );
1281 
1282     LISTITER iter = list_begin( rules );
1283     LISTITER const end = list_end( rules );
1284     for ( ; iter != end; iter = list_next( iter ) )
1285     {
1286         RULE * r = nullptr;
1287         if ( !m->rules || !( r = (RULE *)hash_find( m->rules, list_item( iter )
1288             ) ) )
1289         {
1290             unknown_rule( frame, "EXPORT", m, list_item( iter ) );
1291         }
1292         r->exported = 1;
1293     }
1294     return L0;
1295 }
1296 
1297 
1298 /*
1299  * get_source_line() - get a frame's file and line number information
1300  *
1301  * This is the execution traceback information to be indicated for in debug
1302  * output or an error backtrace.
1303  */
1304 
get_source_line(FRAME * frame,char const ** file,int * line)1305 static void get_source_line( FRAME * frame, char const * * file, int * line )
1306 {
1307     if ( frame->file )
1308     {
1309         char const * f = object_str( frame->file );
1310         int l = frame->line;
1311         *file = f;
1312         *line = l;
1313     }
1314     else
1315     {
1316         *file = "(builtin)";
1317         *line = -1;
1318     }
1319 }
1320 
1321 
print_source_line(FRAME * frame)1322 void print_source_line( FRAME * frame )
1323 {
1324     char const * file;
1325     int line;
1326     get_source_line( frame, &file, &line );
1327     if ( line < 0 )
1328         out_printf( "(builtin):" );
1329     else
1330         out_printf( "%s:%d:", file, line );
1331 }
1332 
1333 
1334 /*
1335  * backtrace_line() - print a single line of error backtrace for the given
1336  * frame.
1337  */
1338 
backtrace_line(FRAME * frame)1339 void backtrace_line( FRAME * frame )
1340 {
1341     if ( frame == 0 )
1342     {
1343         out_printf( "(no frame):" );
1344     }
1345     else
1346     {
1347         print_source_line( frame );
1348         out_printf( " in %s\n", frame->rulename );
1349     }
1350 }
1351 
1352 
1353 /*
1354  * backtrace() - Print the entire backtrace from the given frame to the Jambase
1355  * which invoked it.
1356  */
1357 
backtrace(FRAME * frame)1358 void backtrace( FRAME * frame )
1359 {
1360     if ( !frame ) return;
1361     while ( ( frame = frame->prev ) )
1362         backtrace_line( frame );
1363 }
1364 
1365 
1366 /*
1367  * builtin_backtrace() - A Jam version of the backtrace function, taking no
1368  * arguments and returning a list of quadruples: FILENAME LINE MODULE. RULENAME
1369  * describing each frame. Note that the module-name is always followed by a
1370  * period.
1371  */
1372 
builtin_backtrace(FRAME * frame,int flags)1373 LIST * builtin_backtrace( FRAME * frame, int flags )
1374 {
1375     LIST * const levels_arg = lol_get( frame->args, 0 );
1376     int levels = list_empty( levels_arg )
1377         ? (int)( (unsigned int)(-1) >> 1 )
1378         : atoi( object_str( list_front( levels_arg ) ) );
1379 
1380     LIST * result = L0;
1381     for ( ; ( frame = frame->prev ) && levels; --levels )
1382     {
1383         char const * file;
1384         int line;
1385         char buf[ 32 ];
1386         string module_name[ 1 ];
1387         get_source_line( frame, &file, &line );
1388         sprintf( buf, "%d", line );
1389         string_new( module_name );
1390         if ( frame->module->name )
1391         {
1392             string_append( module_name, object_str( frame->module->name ) );
1393             string_append( module_name, "." );
1394         }
1395         result = list_push_back( result, object_new( file ) );
1396         result = list_push_back( result, object_new( buf ) );
1397         result = list_push_back( result, object_new( module_name->value ) );
1398         result = list_push_back( result, object_new( frame->rulename ) );
1399         string_free( module_name );
1400     }
1401     return result;
1402 }
1403 
1404 
1405 /*
1406  * builtin_caller_module() - CALLER_MODULE ( levels ? )
1407  *
1408  * If levels is not supplied, returns the name of the module of the rule which
1409  * called the one calling this one. If levels is supplied, it is interpreted as
1410  * an integer specifying a number of additional levels of call stack to traverse
1411  * in order to locate the module in question. If no such module exists, returns
1412  * the empty list. Also returns the empty list when the module in question is
1413  * the global module. This rule is needed for implementing module import
1414  * behavior.
1415  */
1416 
builtin_caller_module(FRAME * frame,int flags)1417 LIST * builtin_caller_module( FRAME * frame, int flags )
1418 {
1419     LIST * const levels_arg = lol_get( frame->args, 0 );
1420     int const levels = list_empty( levels_arg )
1421         ? 0
1422         : atoi( object_str( list_front( levels_arg ) ) );
1423 
1424     int i;
1425     for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
1426         frame = frame->prev;
1427 
1428     return frame->module == root_module()
1429         ? L0
1430         : list_new( object_copy( frame->module->name ) );
1431 }
1432 
1433 
1434 /*
1435  * Return the current working directory.
1436  *
1437  * Usage: pwd = [ PWD ] ;
1438  */
1439 
builtin_pwd(FRAME * frame,int flags)1440 LIST * builtin_pwd( FRAME * frame, int flags )
1441 {
1442     return list_new( object_copy( cwd() ) );
1443 }
1444 
1445 
1446 /*
1447  * Adds targets to the list of target that jam will attempt to update.
1448  */
1449 
builtin_update(FRAME * frame,int flags)1450 LIST * builtin_update( FRAME * frame, int flags )
1451 {
1452     LIST * result = list_copy( targets_to_update() );
1453     LIST * arg1 = lol_get( frame->args, 0 );
1454     LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
1455     clear_targets_to_update();
1456     for ( ; iter != end; iter = list_next( iter ) )
1457         mark_target_for_updating( object_copy( list_item( iter ) ) );
1458     return result;
1459 }
1460 
1461 extern int anyhow;
1462 int last_update_now_status;
1463 
1464 /* Takes a list of target names and immediately updates them.
1465  *
1466  * Parameters:
1467  *  1. Target list.
1468  *  2. Optional file descriptor (converted to a string) for a log file where all
1469  *     the related build output should be redirected.
1470  *  3. If specified, makes the build temporarily disable the -n option, i.e.
1471  *     forces all needed out-of-date targets to be rebuilt.
1472  *  4. If specified, makes the build temporarily disable the -q option, i.e.
1473  *     forces the build to continue even if one of the targets fails to build.
1474  */
builtin_update_now(FRAME * frame,int flags)1475 LIST * builtin_update_now( FRAME * frame, int flags )
1476 {
1477     LIST * targets = lol_get( frame->args, 0 );
1478     LIST * log = lol_get( frame->args, 1 );
1479     LIST * force = lol_get( frame->args, 2 );
1480     LIST * continue_ = lol_get( frame->args, 3 );
1481     int status;
1482     int original_stdout = 0;
1483     int original_stderr = 0;
1484     int original_noexec = 0;
1485     int original_quitquick = 0;
1486 
1487     if ( !list_empty( log ) )
1488     {
1489         /* Temporarily redirect stdout and stderr to the given log file. */
1490         int const fd = atoi( object_str( list_front( log ) ) );
1491         original_stdout = dup( 0 );
1492         original_stderr = dup( 1 );
1493         dup2( fd, 0 );
1494         dup2( fd, 1 );
1495     }
1496 
1497     if ( !list_empty( force ) )
1498     {
1499         original_noexec = globs.noexec;
1500         globs.noexec = 0;
1501     }
1502 
1503     if ( !list_empty( continue_ ) )
1504     {
1505         original_quitquick = globs.quitquick;
1506         globs.quitquick = 0;
1507     }
1508 
1509     status = make( targets, anyhow );
1510 
1511     if ( !list_empty( force ) )
1512     {
1513         globs.noexec = original_noexec;
1514     }
1515 
1516     if ( !list_empty( continue_ ) )
1517     {
1518         globs.quitquick = original_quitquick;
1519     }
1520 
1521     if ( !list_empty( log ) )
1522     {
1523         /* Flush whatever stdio might have buffered, while descriptions 0 and 1
1524          * still refer to the log file.
1525          */
1526         out_flush( );
1527         err_flush( );
1528         dup2( original_stdout, 0 );
1529         dup2( original_stderr, 1 );
1530         close( original_stdout );
1531         close( original_stderr );
1532     }
1533 
1534     last_update_now_status = status;
1535 
1536     return status ? L0 : list_new( object_copy( constant_ok ) );
1537 }
1538 
1539 
builtin_import_module(FRAME * frame,int flags)1540 LIST * builtin_import_module( FRAME * frame, int flags )
1541 {
1542     LIST * const arg1 = lol_get( frame->args, 0 );
1543     LIST * const arg2 = lol_get( frame->args, 1 );
1544     module_t * const m = list_empty( arg2 )
1545         ? root_module()
1546         : bindmodule( list_front( arg2 ) );
1547     import_module( arg1, m );
1548     return L0;
1549 }
1550 
1551 
builtin_imported_modules(FRAME * frame,int flags)1552 LIST * builtin_imported_modules( FRAME * frame, int flags )
1553 {
1554     LIST * const arg0 = lol_get( frame->args, 0 );
1555     OBJECT * const module = list_empty( arg0 ) ? 0 : list_front( arg0 );
1556     return imported_modules( bindmodule( module ) );
1557 }
1558 
1559 
builtin_instance(FRAME * frame,int flags)1560 LIST * builtin_instance( FRAME * frame, int flags )
1561 {
1562     LIST * arg1 = lol_get( frame->args, 0 );
1563     LIST * arg2 = lol_get( frame->args, 1 );
1564     module_t * const instance     = bindmodule( list_front( arg1 ) );
1565     module_t * const class_module = bindmodule( list_front( arg2 ) );
1566     instance->class_module = class_module;
1567     module_set_fixed_variables( instance, class_module->num_fixed_variables );
1568     return L0;
1569 }
1570 
1571 
builtin_sort(FRAME * frame,int flags)1572 LIST * builtin_sort( FRAME * frame, int flags )
1573 {
1574     return list_sort( lol_get( frame->args, 0 ) );
1575 }
1576 
1577 
1578 namespace
1579 {
1580     template <class S>
replace_all(S & str,const S & from,const S & to)1581     void replace_all(S &str, const S &from, const S &to)
1582     {
1583         const auto from_len = from.length();
1584         const auto to_len = to.length();
1585         auto pos = str.find(from, 0);
1586         while (pos != S::npos)
1587         {
1588             str.replace(pos, from_len, to);
1589             pos += to_len;
1590             pos = str.find(from, pos);
1591         }
1592     }
1593 }
1594 
1595 
builtin_normalize_path(FRAME * frame,int flags)1596 LIST * builtin_normalize_path( FRAME * frame, int flags )
1597 {
1598     LIST * arg = lol_get( frame->args, 0 );
1599     LISTITER arg_iter = list_begin( arg );
1600     LISTITER arg_end = list_end( arg );
1601     std::string in;
1602     for ( ; arg_iter != arg_end; arg_iter = list_next( arg_iter ) )
1603     {
1604         auto arg_str = object_str( list_item( arg_iter ) );
1605         if (arg_str[ 0 ] == '\0') continue;
1606         if (!in.empty()) in += "/";
1607         in += arg_str;
1608     }
1609     std::string out = b2::paths::normalize(in);
1610 
1611     if (out.empty()) return L0;
1612     else return list_new(object_new(out.c_str()));
1613 }
1614 
1615 
builtin_native_rule(FRAME * frame,int flags)1616 LIST * builtin_native_rule( FRAME * frame, int flags )
1617 {
1618     LIST * module_name = lol_get( frame->args, 0 );
1619     LIST * rule_name = lol_get( frame->args, 1 );
1620 
1621     module_t * module = bindmodule( list_front( module_name ) );
1622 
1623     native_rule_t * np;
1624     if ( module->native_rules && (np = (native_rule_t *)hash_find(
1625         module->native_rules, list_front( rule_name ) ) ) )
1626     {
1627         new_rule_body( module, np->name, np->procedure, 1 );
1628     }
1629     else
1630     {
1631         backtrace_line( frame->prev );
1632         out_printf( "error: no native rule \"%s\" defined in module \"%s.\"\n",
1633             object_str( list_front( rule_name ) ), object_str( module->name ) );
1634         backtrace( frame->prev );
1635         exit( EXITBAD );
1636     }
1637     return L0;
1638 }
1639 
1640 
builtin_has_native_rule(FRAME * frame,int flags)1641 LIST * builtin_has_native_rule( FRAME * frame, int flags )
1642 {
1643     LIST * module_name = lol_get( frame->args, 0 );
1644     LIST * rule_name   = lol_get( frame->args, 1 );
1645     LIST * version     = lol_get( frame->args, 2 );
1646 
1647     module_t * module = bindmodule( list_front( module_name ) );
1648 
1649     native_rule_t * np;
1650     if ( module->native_rules && (np = (native_rule_t *)hash_find(
1651         module->native_rules, list_front( rule_name ) ) ) )
1652     {
1653         int expected_version = atoi( object_str( list_front( version ) ) );
1654         if ( np->version == expected_version )
1655             return list_new( object_copy( constant_true ) );
1656     }
1657     return L0;
1658 }
1659 
1660 
builtin_user_module(FRAME * frame,int flags)1661 LIST * builtin_user_module( FRAME * frame, int flags )
1662 {
1663     LIST * const module_name = lol_get( frame->args, 0 );
1664     LISTITER iter = list_begin( module_name );
1665     LISTITER const end = list_end( module_name );
1666     for ( ; iter != end; iter = list_next( iter ) )
1667         bindmodule( list_item( iter ) )->user_module = 1;
1668     return L0;
1669 }
1670 
1671 
builtin_nearest_user_location(FRAME * frame,int flags)1672 LIST * builtin_nearest_user_location( FRAME * frame, int flags )
1673 {
1674     FRAME * const nearest_user_frame = frame->module->user_module
1675         ? frame
1676         : frame->prev_user;
1677     if ( !nearest_user_frame )
1678         return L0;
1679 
1680     {
1681         LIST * result = L0;
1682         char const * file;
1683         int line;
1684         char buf[ 32 ];
1685 
1686         get_source_line( nearest_user_frame, &file, &line );
1687         sprintf( buf, "%d", line );
1688         result = list_push_back( result, object_new( file ) );
1689         result = list_push_back( result, object_new( buf ) );
1690         return result;
1691     }
1692 }
1693 
1694 
builtin_check_if_file(FRAME * frame,int flags)1695 LIST * builtin_check_if_file( FRAME * frame, int flags )
1696 {
1697     LIST * const name = lol_get( frame->args, 0 );
1698     return file_is_file( list_front( name ) ) == 1
1699         ? list_new( object_copy( constant_true ) )
1700         : L0;
1701 }
1702 
1703 
builtin_md5(FRAME * frame,int flags)1704 LIST * builtin_md5( FRAME * frame, int flags )
1705 {
1706     LIST * l = lol_get( frame->args, 0 );
1707     char const * s = object_str( list_front( l ) );
1708 
1709     md5_state_t state;
1710     md5_byte_t digest[ 16 ];
1711     char hex_output[ 16 * 2 + 1 ];
1712 
1713     int di;
1714 
1715     md5_init( &state );
1716     md5_append( &state, (md5_byte_t const *)s, strlen( s ) );
1717     md5_finish( &state, digest );
1718 
1719     for ( di = 0; di < 16; ++di )
1720         sprintf( hex_output + di * 2, "%02x", digest[ di ] );
1721 
1722     return list_new( object_new( hex_output ) );
1723 }
1724 
1725 
builtin_file_open(FRAME * frame,int flags)1726 LIST * builtin_file_open( FRAME * frame, int flags )
1727 {
1728     char const * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
1729     char const * mode = object_str( list_front( lol_get( frame->args, 1 ) ) );
1730     int fd;
1731     char buffer[ sizeof( "4294967295" ) ];
1732 
1733     if ( strcmp(mode, "w") == 0 )
1734         fd = open( name, O_WRONLY|O_CREAT|O_TRUNC, 0666 );
1735     else
1736         fd = open( name, O_RDONLY );
1737 
1738     if ( fd != -1 )
1739     {
1740         sprintf( buffer, "%d", fd );
1741         return list_new( object_new( buffer ) );
1742     }
1743     return L0;
1744 }
1745 
1746 
builtin_pad(FRAME * frame,int flags)1747 LIST * builtin_pad( FRAME * frame, int flags )
1748 {
1749     OBJECT * string = list_front( lol_get( frame->args, 0 ) );
1750     char const * width_s = object_str( list_front( lol_get( frame->args, 1 ) ) );
1751 
1752     int current = strlen( object_str( string ) );
1753     int desired = atoi( width_s );
1754     if ( current >= desired )
1755         return list_new( object_copy( string ) );
1756     else
1757     {
1758         char * buffer = (char *)BJAM_MALLOC( desired + 1 );
1759         int i;
1760         LIST * result;
1761 
1762         strcpy( buffer, object_str( string ) );
1763         for ( i = current; i < desired; ++i )
1764             buffer[ i ] = ' ';
1765         buffer[ desired ] = '\0';
1766         result = list_new( object_new( buffer ) );
1767         BJAM_FREE( buffer );
1768         return result;
1769     }
1770 }
1771 
1772 
builtin_precious(FRAME * frame,int flags)1773 LIST * builtin_precious( FRAME * frame, int flags )
1774 {
1775     LIST * targets = lol_get( frame->args, 0 );
1776     LISTITER iter = list_begin( targets );
1777     LISTITER const end = list_end( targets );
1778     for ( ; iter != end; iter = list_next( iter ) )
1779         bindtarget( list_item( iter ) )->flags |= T_FLAG_PRECIOUS;
1780     return L0;
1781 }
1782 
1783 
builtin_self_path(FRAME * frame,int flags)1784 LIST * builtin_self_path( FRAME * frame, int flags )
1785 {
1786     extern char const * saved_argv0;
1787     char * p = executable_path( saved_argv0 );
1788     if ( p )
1789     {
1790         LIST * const result = list_new( object_new( p ) );
1791         free( p );
1792         return result;
1793     }
1794     return L0;
1795 }
1796 
1797 
builtin_makedir(FRAME * frame,int flags)1798 LIST * builtin_makedir( FRAME * frame, int flags )
1799 {
1800     LIST * const path = lol_get( frame->args, 0 );
1801     return file_mkdir( object_str( list_front( path ) ) )
1802         ? L0
1803         : list_new( object_copy( list_front( path ) ) );
1804 }
1805 
builtin_readlink(FRAME * frame,int flags)1806 LIST *builtin_readlink( FRAME * frame, int flags )
1807 {
1808     const char * path = object_str( list_front( lol_get( frame->args, 0 ) ) );
1809 #ifdef OS_NT
1810 
1811     /* This struct is declared in ntifs.h which is
1812      * part of the Windows Driver Kit.
1813      */
1814     typedef struct _REPARSE_DATA_BUFFER {
1815         ULONG ReparseTag;
1816         USHORT ReparseDataLength;
1817         USHORT Reserved;
1818         union {
1819             struct {
1820                 USHORT SubstituteNameOffset;
1821                 USHORT SubstituteNameLength;
1822                 USHORT PrintNameOffset;
1823                 USHORT PrintNameLength;
1824                 ULONG Flags;
1825                 WCHAR PathBuffer[ 1 ];
1826             } SymbolicLinkReparseBuffer;
1827             struct {
1828                 USHORT SubstituteNameOffset;
1829                 USHORT SubstituteNameLength;
1830                 USHORT PrintNameOffset;
1831                 USHORT PrintNameLength;
1832                 WCHAR PathBuffer[ 1 ];
1833             } MountPointReparseBuffer;
1834             struct {
1835                 UCHAR DataBuffer[ 1 ];
1836             } GenericReparseBuffer;
1837         };
1838     } REPARSE_DATA_BUFFER;
1839 
1840     HANDLE hLink = CreateFileA( path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL );
1841     DWORD n;
1842     union {
1843         REPARSE_DATA_BUFFER reparse;
1844         char data[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1845     } buf;
1846     int okay = DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, &buf, sizeof(buf), &n, NULL);
1847 
1848     CloseHandle( hLink );
1849 
1850     if (okay && buf.reparse.ReparseTag == IO_REPARSE_TAG_SYMLINK )
1851     {
1852         int index = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameOffset / 2;
1853         int length = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameLength / 2;
1854         char cbuf[MAX_PATH + 1];
1855         int numchars = WideCharToMultiByte( CP_ACP, 0, buf.reparse.SymbolicLinkReparseBuffer.PathBuffer + index, length, cbuf, sizeof(cbuf), NULL, NULL );
1856         if( numchars >= int(sizeof(cbuf)) )
1857         {
1858             return 0;
1859         }
1860         cbuf[numchars] = '\0';
1861         return list_new( object_new( cbuf ) );
1862     }
1863     else if( okay && buf.reparse.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT )
1864     {
1865         int index = buf.reparse.MountPointReparseBuffer.SubstituteNameOffset / 2;
1866         int length = buf.reparse.MountPointReparseBuffer.SubstituteNameLength / 2;
1867         char cbuf[MAX_PATH + 1];
1868         const char * result;
1869         int numchars = WideCharToMultiByte( CP_ACP, 0, buf.reparse.MountPointReparseBuffer.PathBuffer + index, length, cbuf, sizeof(cbuf), NULL, NULL );
1870         if( numchars >= int(sizeof(cbuf)) )
1871         {
1872             return 0;
1873         }
1874         cbuf[numchars] = '\0';
1875         /* strip off the leading "\??\" */
1876         result = cbuf;
1877         if ( cbuf[ 0 ] == '\\' && cbuf[ 1 ] == '?' &&
1878             cbuf[ 2 ] == '?' && cbuf[ 3 ] == '\\' &&
1879             cbuf[ 4 ] != '\0' && cbuf[ 5 ] == ':' )
1880         {
1881             result += 4;
1882         }
1883         return list_new( object_new( result ) );
1884     }
1885     return 0;
1886 #else
1887     char static_buf[256];
1888     char * buf = static_buf;
1889     size_t bufsize = 256;
1890     LIST * result = 0;
1891     while (1) {
1892         ssize_t len = readlink( path, buf, bufsize );
1893         if ( len < 0 )
1894         {
1895             break;
1896         }
1897         else if ( size_t(len) < bufsize )
1898         {
1899             buf[ len ] = '\0';
1900             result = list_new( object_new( buf ) );
1901             break;
1902         }
1903         if ( buf != static_buf )
1904             BJAM_FREE( buf );
1905         bufsize *= 2;
1906         buf = (char *)BJAM_MALLOC( bufsize );
1907     }
1908 
1909     if ( buf != static_buf )
1910         BJAM_FREE( buf );
1911 
1912     return result;
1913 #endif
1914 }
1915 
1916 #ifdef JAM_DEBUGGER
1917 
builtin_debug_print_helper(FRAME * frame,int flags)1918 LIST *builtin_debug_print_helper( FRAME * frame, int flags )
1919 {
1920     debug_print_result = list_copy( lol_get( frame->args, 0 ) );
1921     return L0;
1922 }
1923 
1924 #endif
1925 
1926 #ifdef HAVE_PYTHON
1927 
builtin_python_import_rule(FRAME * frame,int flags)1928 LIST * builtin_python_import_rule( FRAME * frame, int flags )
1929 {
1930     static int first_time = 1;
1931     char const * python_module   = object_str( list_front( lol_get( frame->args,
1932         0 ) ) );
1933     char const * python_function = object_str( list_front( lol_get( frame->args,
1934         1 ) ) );
1935     OBJECT     * jam_module      = list_front( lol_get( frame->args, 2 ) );
1936     OBJECT     * jam_rule        = list_front( lol_get( frame->args, 3 ) );
1937 
1938     PyObject * pName;
1939     PyObject * pModule;
1940     PyObject * pDict;
1941     PyObject * pFunc;
1942 
1943     if ( first_time )
1944     {
1945         /* At the first invocation, we add the value of the global
1946          * EXTRA_PYTHONPATH to the sys.path Python variable.
1947          */
1948         LIST * extra = 0;
1949         module_t * outer_module = frame->module;
1950         LISTITER iter, end;
1951 
1952         first_time = 0;
1953 
1954         extra = var_get( root_module(), constant_extra_pythonpath );
1955 
1956         iter = list_begin( extra ), end = list_end( extra );
1957         for ( ; iter != end; iter = list_next( iter ) )
1958         {
1959             string buf[ 1 ];
1960             string_new( buf );
1961             string_append( buf, "import sys\nsys.path.append(\"" );
1962             string_append( buf, object_str( list_item( iter ) ) );
1963             string_append( buf, "\")\n" );
1964             PyRun_SimpleString( buf->value );
1965             string_free( buf );
1966         }
1967     }
1968 
1969     pName   = PyString_FromString( python_module );
1970     pModule = PyImport_Import( pName );
1971     Py_DECREF( pName );
1972 
1973     if ( pModule != NULL )
1974     {
1975         pDict = PyModule_GetDict( pModule );
1976         pFunc = PyDict_GetItemString( pDict, python_function );
1977 
1978         if ( pFunc && PyCallable_Check( pFunc ) )
1979         {
1980             module_t * m = bindmodule( jam_module );
1981             new_rule_body( m, jam_rule, function_python( pFunc, 0 ), 0 );
1982         }
1983         else
1984         {
1985             if ( PyErr_Occurred() )
1986                 PyErr_Print();
1987             err_printf( "Cannot find function \"%s\"\n", python_function );
1988         }
1989         Py_DECREF( pModule );
1990     }
1991     else
1992     {
1993         PyErr_Print();
1994         err_printf( "Failed to load \"%s\"\n", python_module );
1995     }
1996     return L0;
1997 
1998 }
1999 
2000 #endif  /* #ifdef HAVE_PYTHON */
2001 
2002 
lol_build(LOL * lol,char const ** elements)2003 void lol_build( LOL * lol, char const * * elements )
2004 {
2005     LIST * l = L0;
2006     lol_init( lol );
2007 
2008     while ( elements && *elements )
2009     {
2010         if ( !strcmp( *elements, ":" ) )
2011         {
2012             lol_add( lol, l );
2013             l = L0;
2014         }
2015         else
2016         {
2017             l = list_push_back( l, object_new( *elements ) );
2018         }
2019         ++elements;
2020     }
2021 
2022     if ( l != L0 )
2023         lol_add( lol, l );
2024 }
2025 
2026 
2027 #ifdef HAVE_PYTHON
2028 
jam_list_from_string(PyObject * a)2029 static LIST *jam_list_from_string(PyObject *a)
2030 {
2031     return list_new( object_new( PyString_AsString( a ) ) );
2032 }
2033 
jam_list_from_sequence(PyObject * a)2034 static LIST *jam_list_from_sequence(PyObject *a)
2035 {
2036     LIST * l = 0;
2037 
2038     int i = 0;
2039     int s = PySequence_Size( a );
2040 
2041     for ( ; i < s; ++i )
2042     {
2043         /* PySequence_GetItem returns new reference. */
2044         PyObject * e = PySequence_GetItem( a, i );
2045         char * s = PyString_AsString( e );
2046         if ( !s )
2047         {
2048             /* try to get the repr() on the object */
2049             PyObject *repr = PyObject_Repr(e);
2050             if (repr)
2051             {
2052                 const char *str = PyString_AsString(repr);
2053                 PyErr_Format(PyExc_TypeError, "expecting type <str> got %s", str);
2054             }
2055             /* fall back to a dumb error */
2056             else
2057             {
2058                 PyErr_BadArgument();
2059             }
2060             return NULL;
2061         }
2062         l = list_push_back( l, object_new( s ) );
2063         Py_DECREF( e );
2064     }
2065 
2066     return l;
2067 }
2068 
make_jam_arguments_from_python(FRAME * inner,PyObject * args)2069 static void make_jam_arguments_from_python(FRAME* inner, PyObject *args)
2070 {
2071     int i;
2072     int size;
2073 
2074     /* Build up the list of arg lists. */
2075     frame_init( inner );
2076     inner->prev = 0;
2077     inner->prev_user = 0;
2078     inner->module = bindmodule( constant_python_interface );
2079 
2080     size = PyTuple_Size( args );
2081     for (i = 0 ; i < size; ++i)
2082     {
2083         PyObject * a = PyTuple_GetItem( args, i );
2084         if ( PyString_Check( a ) )
2085         {
2086             lol_add( inner->args, jam_list_from_string(a) );
2087         }
2088         else if ( PySequence_Check( a ) )
2089         {
2090             lol_add( inner->args, jam_list_from_sequence(a) );
2091         }
2092     }
2093 }
2094 
2095 
2096 /*
2097  * Calls the bjam rule specified by name passed in 'args'. The name is looked up
2098  * in the context of bjam's 'python_interface' module. Returns the list of
2099  * strings returned by the rule.
2100  */
2101 
bjam_call(PyObject * self,PyObject * args)2102 PyObject * bjam_call( PyObject * self, PyObject * args )
2103 {
2104     FRAME    inner[ 1 ];
2105     LIST   * result;
2106     PARSE  * p;
2107     OBJECT * rulename;
2108     PyObject *args_proper;
2109 
2110     /* PyTuple_GetItem returns borrowed reference. */
2111     rulename = object_new( PyString_AsString( PyTuple_GetItem( args, 0 ) ) );
2112 
2113     args_proper = PyTuple_GetSlice(args, 1, PyTuple_Size(args));
2114     make_jam_arguments_from_python (inner, args_proper);
2115     if ( PyErr_Occurred() )
2116     {
2117         return NULL;
2118     }
2119     Py_DECREF(args_proper);
2120 
2121     result = evaluate_rule( bindrule( rulename, inner->module), rulename, inner );
2122     object_free( rulename );
2123 
2124     frame_free( inner );
2125 
2126     /* Convert the bjam list into a Python list result. */
2127     {
2128         PyObject * const pyResult = PyList_New( list_length( result ) );
2129         int i = 0;
2130         LISTITER iter = list_begin( result );
2131         LISTITER const end = list_end( result );
2132         for ( ; iter != end; iter = list_next( iter ) )
2133         {
2134             PyList_SetItem( pyResult, i, PyString_FromString( object_str(
2135                 list_item( iter ) ) ) );
2136             i += 1;
2137         }
2138         list_free( result );
2139         return pyResult;
2140     }
2141 }
2142 
2143 
2144 /*
2145  * Accepts four arguments:
2146  * - module name
2147  * - rule name,
2148  * - Python callable.
2149  * - (optional) bjam language function signature.
2150  * Creates a bjam rule with the specified name in the specified module, which
2151  * will invoke the Python callable.
2152  */
2153 
bjam_import_rule(PyObject * self,PyObject * args)2154 PyObject * bjam_import_rule( PyObject * self, PyObject * args )
2155 {
2156     char     * module;
2157     char     * rule;
2158     PyObject * func;
2159     PyObject * bjam_signature = NULL;
2160     module_t * m;
2161     RULE     * r;
2162     OBJECT   * module_name;
2163     OBJECT   * rule_name;
2164 
2165     if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
2166                             &module, &rule, &func, &bjam_signature ) )
2167         return NULL;
2168 
2169     if ( !PyCallable_Check( func ) )
2170     {
2171         PyErr_SetString( PyExc_RuntimeError, "Non-callable object passed to "
2172             "bjam.import_rule" );
2173         return NULL;
2174     }
2175 
2176     module_name = *module ? object_new( module ) : 0;
2177     m = bindmodule( module_name );
2178     if ( module_name )
2179         object_free( module_name );
2180     rule_name = object_new( rule );
2181     new_rule_body( m, rule_name, function_python( func, bjam_signature ), 0 );
2182     object_free( rule_name );
2183 
2184     Py_INCREF( Py_None );
2185     return Py_None;
2186 }
2187 
2188 
2189 /*
2190  * Accepts four arguments:
2191  *  - an action name
2192  *  - an action body
2193  *  - a list of variable that will be bound inside the action
2194  *  - integer flags.
2195  *  Defines an action on bjam side.
2196  */
2197 
bjam_define_action(PyObject * self,PyObject * args)2198 PyObject * bjam_define_action( PyObject * self, PyObject * args )
2199 {
2200     char     * name;
2201     char     * body;
2202     module_t * m;
2203     PyObject * bindlist_python;
2204     int        flags;
2205     LIST     * bindlist = L0;
2206     int        n;
2207     int        i;
2208     OBJECT   * name_str;
2209     FUNCTION * body_func;
2210 
2211     if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
2212         &PyList_Type, &bindlist_python, &flags ) )
2213         return NULL;
2214 
2215     n = PyList_Size( bindlist_python );
2216     for ( i = 0; i < n; ++i )
2217     {
2218         PyObject * next = PyList_GetItem( bindlist_python, i );
2219         if ( !PyString_Check( next ) )
2220         {
2221             PyErr_SetString( PyExc_RuntimeError, "bind list has non-string "
2222                 "type" );
2223             return NULL;
2224         }
2225         bindlist = list_push_back( bindlist, object_new( PyString_AsString( next
2226             ) ) );
2227     }
2228 
2229     name_str = object_new( name );
2230     body_func = function_compile_actions( body, constant_builtin, -1 );
2231     new_rule_actions( root_module(), name_str, body_func, bindlist, flags );
2232     function_free( body_func );
2233     object_free( name_str );
2234 
2235     Py_INCREF( Py_None );
2236     return Py_None;
2237 }
2238 
2239 
2240 /*
2241  * Returns the value of a variable in root Jam module.
2242  */
2243 
bjam_variable(PyObject * self,PyObject * args)2244 PyObject * bjam_variable( PyObject * self, PyObject * args )
2245 {
2246     char     * name;
2247     LIST     * value;
2248     PyObject * result;
2249     int        i;
2250     OBJECT   * varname;
2251     LISTITER   iter;
2252     LISTITER   end;
2253 
2254     if ( !PyArg_ParseTuple( args, "s", &name ) )
2255         return NULL;
2256 
2257     varname = object_new( name );
2258     value = var_get( root_module(), varname );
2259     object_free( varname );
2260     iter = list_begin( value );
2261     end = list_end( value );
2262 
2263     result = PyList_New( list_length( value ) );
2264     for ( i = 0; iter != end; iter = list_next( iter ), ++i )
2265         PyList_SetItem( result, i, PyString_FromString( object_str( list_item(
2266             iter ) ) ) );
2267 
2268     return result;
2269 }
2270 
2271 
bjam_backtrace(PyObject * self,PyObject * args)2272 PyObject * bjam_backtrace( PyObject * self, PyObject * args )
2273 {
2274     PyObject     * result = PyList_New( 0 );
2275     struct frame * f = frame_before_python_call;
2276 
2277     for ( ; (f = f->prev); )
2278     {
2279         PyObject   * tuple = PyTuple_New( 4 );
2280         char const * file;
2281         int          line;
2282         char         buf[ 32 ];
2283         string module_name[ 1 ];
2284 
2285         get_source_line( f, &file, &line );
2286         sprintf( buf, "%d", line );
2287         string_new( module_name );
2288         if ( f->module->name )
2289         {
2290             string_append( module_name, object_str( f->module->name ) );
2291             string_append( module_name, "." );
2292         }
2293 
2294         /* PyTuple_SetItem steals reference. */
2295         PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
2296         PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
2297         PyTuple_SetItem( tuple, 2, PyString_FromString( module_name->value ) );
2298         PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
2299 
2300         string_free( module_name );
2301 
2302         PyList_Append( result, tuple );
2303         Py_DECREF( tuple );
2304     }
2305     return result;
2306 }
2307 
bjam_caller(PyObject * self,PyObject * args)2308 PyObject * bjam_caller( PyObject * self, PyObject * args )
2309 {
2310     return PyString_FromString( frame_before_python_call->prev->module->name ?
2311         object_str( frame_before_python_call->prev->module->name ) : "" );
2312 }
2313 
2314 #endif  /* #ifdef HAVE_PYTHON */
2315 
2316 
2317 #ifdef HAVE_POPEN
2318 
2319 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW64__) || defined(__MINGW32__)
2320     #undef popen
2321     #define popen windows_popen_wrapper
2322     #undef pclose
2323     #define pclose _pclose
2324 
2325     /*
2326      * This wrapper is a workaround for a funny _popen() feature on Windows
2327      * where it eats external quotes in some cases. The bug seems to be related
2328      * to the quote stripping functionality used by the Windows cmd.exe
2329      * interpreter when its /S is not specified.
2330      *
2331      * Cleaned up quote from the cmd.exe help screen as displayed on Windows XP
2332      * SP3:
2333      *
2334      *   1. If all of the following conditions are met, then quote characters on
2335      *      the command line are preserved:
2336      *
2337      *       - no /S switch
2338      *       - exactly two quote characters
2339      *       - no special characters between the two quote characters, where
2340      *         special is one of: &<>()@^|
2341      *       - there are one or more whitespace characters between the two quote
2342      *         characters
2343      *       - the string between the two quote characters is the name of an
2344      *         executable file.
2345      *
2346      *   2. Otherwise, old behavior is to see if the first character is a quote
2347      *      character and if so, strip the leading character and remove the last
2348      *      quote character on the command line, preserving any text after the
2349      *      last quote character.
2350      *
2351      * This causes some commands containing quotes not to be executed correctly.
2352      * For example:
2353      *
2354      *   "\Long folder name\aaa.exe" --name="Jurko" --no-surname
2355      *
2356      * would get its outermost quotes stripped and would be executed as:
2357      *
2358      *   \Long folder name\aaa.exe" --name="Jurko --no-surname
2359      *
2360      * which would report an error about '\Long' not being a valid command.
2361      *
2362      * cmd.exe help seems to indicate it would be enough to add an extra space
2363      * character in front of the command to avoid this but this does not work,
2364      * most likely due to the shell first stripping all leading whitespace
2365      * characters from the command.
2366      *
2367      * Solution implemented here is to quote the whole command in case it
2368      * contains any quote characters. Note thought this will not work correctly
2369      * should Windows ever 'fix' this feature.
2370      *                                               (03.06.2008.) (Jurko)
2371      */
windows_popen_wrapper(char const * command,char const * mode)2372     static FILE * windows_popen_wrapper( char const * command,
2373         char const * mode )
2374     {
2375         int const extra_command_quotes_needed = !!strchr( command, '"' );
2376         string quoted_command;
2377         FILE * result;
2378 
2379         if ( extra_command_quotes_needed )
2380         {
2381             string_new( &quoted_command );
2382             string_append( &quoted_command, "\"" );
2383             string_append( &quoted_command, command );
2384             string_append( &quoted_command, "\"" );
2385             command = quoted_command.value;
2386         }
2387 
2388         result = _popen( command, "r" );
2389 
2390         if ( extra_command_quotes_needed )
2391             string_free( &quoted_command );
2392 
2393         return result;
2394     }
2395 #endif  /* defined(_MSC_VER) || defined(__BORLANDC__) */
2396 
2397 
builtin_shell(FRAME * frame,int flags)2398 LIST * builtin_shell( FRAME * frame, int flags )
2399 {
2400     LIST   * command = lol_get( frame->args, 0 );
2401     LIST   * result = L0;
2402     string   s;
2403     int      ret;
2404     char     buffer[ 1024 ];
2405     FILE   * p = NULL;
2406     int      exit_status = -1;
2407     int      exit_status_opt = 0;
2408     int      no_output_opt = 0;
2409     int      strip_eol_opt = 0;
2410 
2411     /* Process the variable args options. */
2412     {
2413         int a = 1;
2414         LIST * arg = lol_get( frame->args, a );
2415         for ( ; !list_empty( arg ); arg = lol_get( frame->args, ++a ) )
2416         {
2417             if ( !strcmp( "exit-status", object_str( list_front( arg ) ) ) )
2418                 exit_status_opt = 1;
2419             else if ( !strcmp( "no-output", object_str( list_front( arg ) ) ) )
2420                 no_output_opt = 1;
2421             else if ( !strcmp("strip-eol", object_str( list_front( arg ) ) ) )
2422                 strip_eol_opt = 1;
2423         }
2424     }
2425 
2426     /* The following fflush() call seems to be indicated as a workaround for a
2427      * popen() bug on POSIX implementations related to synhronizing input
2428      * stream positions for the called and the calling process.
2429      */
2430     fflush( NULL );
2431 
2432     p = popen( object_str( list_front( command ) ), "r" );
2433     if ( p == NULL )
2434         return L0;
2435 
2436     string_new( &s );
2437 
2438     while ( ( ret = fread( buffer, sizeof( char ), sizeof( buffer ) - 1, p ) ) >
2439         0 )
2440     {
2441         buffer[ ret ] = 0;
2442         if ( !no_output_opt )
2443         {
2444             string_append( &s, buffer );
2445         }
2446 
2447         /* Explicit EOF check for systems with broken fread */
2448         if ( feof( p ) ) break;
2449     }
2450 
2451     if ( strip_eol_opt )
2452         string_rtrim( &s );
2453 
2454     exit_status = pclose( p );
2455 
2456     /* The command output is returned first. */
2457     result = list_new( object_new( s.value ) );
2458     string_free( &s );
2459 
2460     /* The command exit result next. */
2461     if ( exit_status_opt )
2462     {
2463         if ( WIFEXITED( exit_status ) )
2464             exit_status = WEXITSTATUS( exit_status );
2465         else
2466             exit_status = -1;
2467 
2468 #ifdef OS_VMS
2469         /* Harmonize VMS success status with POSIX */
2470         if ( exit_status == 1 ) exit_status = EXIT_SUCCESS;
2471 #endif
2472         sprintf( buffer, "%d", exit_status );
2473         result = list_push_back( result, object_new( buffer ) );
2474     }
2475 
2476     return result;
2477 }
2478 
2479 #else  /* #ifdef HAVE_POPEN */
2480 
builtin_shell(FRAME * frame,int flags)2481 LIST * builtin_shell( FRAME * frame, int flags )
2482 {
2483     return L0;
2484 }
2485 
2486 #endif  /* #ifdef HAVE_POPEN */
2487 
2488 
2489 /*
2490  * builtin_glob_archive() - GLOB_ARCHIVE rule
2491  */
2492 
2493 struct globbing2
2494 {
2495     LIST * patterns[ 2 ];
2496     LIST * results;
2497     LIST * case_insensitive;
2498 };
2499 
2500 
builtin_glob_archive_back(void * closure,OBJECT * member,LIST * symbols,int status,timestamp const * const time)2501 static void builtin_glob_archive_back( void * closure, OBJECT * member,
2502     LIST * symbols, int status, timestamp const * const time )
2503 {
2504     PROFILE_ENTER( BUILTIN_GLOB_ARCHIVE_BACK );
2505 
2506     struct globbing2 * const globbing = (struct globbing2 *)closure;
2507     PATHNAME f;
2508     string buf[ 1 ];
2509     LISTITER iter;
2510     LISTITER end;
2511     LISTITER iter_symbols;
2512     LISTITER end_symbols;
2513     int matched = 0;
2514 
2515     /* Match member name.
2516      */
2517     path_parse( object_str( member ), &f );
2518 
2519     if ( !strcmp( f.f_member.ptr, "" ) )
2520     {
2521         PROFILE_EXIT( BUILTIN_GLOB_ARCHIVE_BACK );
2522         return;
2523     }
2524 
2525     string_new( buf );
2526     string_append_range( buf, f.f_member.ptr, f.f_member.ptr + f.f_member.len );
2527 
2528     if ( globbing->case_insensitive )
2529         downcase_inplace( buf->value );
2530 
2531     /* Glob with member patterns. If not matched, then match symbols.
2532      */
2533     matched = 0;
2534     iter = list_begin( globbing->patterns[ 0 ] );
2535     end = list_end( globbing->patterns[ 0 ] );
2536     for ( ; !matched && iter != end;
2537             iter = list_next( iter ) )
2538     {
2539         const char * pattern = object_str( list_item( iter ) );
2540         int match_exact = ( !has_wildcards( pattern ) );
2541         matched = ( match_exact ?
2542             ( !strcmp( pattern, buf->value ) ) :
2543             ( !glob( pattern, buf->value ) ) );
2544     }
2545 
2546 
2547     /* Glob with symbol patterns, if requested.
2548      */
2549     iter = list_begin( globbing->patterns[ 1 ] );
2550     end = list_end( globbing->patterns[ 1 ] );
2551 
2552     if ( iter != end ) matched = 0;
2553 
2554     for ( ; !matched && iter != end;
2555             iter = list_next( iter ) )
2556     {
2557         const char * pattern = object_str( list_item( iter ) );
2558         int match_exact = ( !has_wildcards( pattern ) );
2559 
2560         iter_symbols = list_begin( symbols );
2561         end_symbols = list_end( symbols );
2562 
2563         for ( ; !matched && iter_symbols != end_symbols;
2564                 iter_symbols = list_next( iter_symbols ) )
2565         {
2566             const char * symbol = object_str( list_item( iter_symbols ) );
2567 
2568             string_copy( buf, symbol );
2569             if ( globbing->case_insensitive )
2570                 downcase_inplace( buf->value );
2571 
2572             matched = ( match_exact ?
2573                 ( !strcmp( pattern, buf->value ) ) :
2574                 ( !glob( pattern, buf->value ) ) );
2575         }
2576     }
2577 
2578     if ( matched )
2579     {
2580         globbing->results = list_push_back( globbing->results,
2581             object_copy( member ) );
2582     }
2583 
2584     string_free( buf );
2585 
2586     PROFILE_EXIT( BUILTIN_GLOB_ARCHIVE_BACK );
2587 }
2588 
2589 
builtin_glob_archive(FRAME * frame,int flags)2590 LIST * builtin_glob_archive( FRAME * frame, int flags )
2591 {
2592     LIST * const l = lol_get( frame->args, 0 );
2593     LIST * const r1 = lol_get( frame->args, 1 );
2594     LIST * const r3 = lol_get( frame->args, 3 );
2595 
2596     LISTITER iter;
2597     LISTITER end;
2598     struct globbing2 globbing;
2599 
2600     globbing.results = L0;
2601     globbing.patterns[ 0 ] = r1;
2602     globbing.patterns[ 1 ] = r3;
2603 
2604     globbing.case_insensitive =
2605 # if defined( OS_NT ) || defined( OS_CYGWIN ) || defined( OS_VMS )
2606        l;  /* Always case-insensitive. */
2607 # else
2608        lol_get( frame->args, 2 ); // r2
2609 # endif
2610 
2611     if ( globbing.case_insensitive )
2612     {
2613         globbing.patterns[ 0 ] = downcase_list( globbing.patterns[ 0 ] );
2614         globbing.patterns[ 1 ] = downcase_list( globbing.patterns[ 1 ] );
2615     }
2616 
2617     iter = list_begin( l );
2618     end = list_end( l );
2619     for ( ; iter != end; iter = list_next( iter ) )
2620         file_archivescan( list_item( iter ), builtin_glob_archive_back, &globbing );
2621 
2622     if ( globbing.case_insensitive )
2623     {
2624         list_free( globbing.patterns[ 0 ] );
2625         list_free( globbing.patterns[ 1 ] );
2626     }
2627 
2628     return globbing.results;
2629 }
2630