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 "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;
1231         RULE * imported;
1232 
1233         if ( !source_module->rules || !(r = (RULE *)hash_find(
1234             source_module->rules, list_item( source_iter ) ) ) )
1235             unknown_rule( frame, "IMPORT", source_module, list_item( source_iter
1236                 ) );
1237 
1238         imported = import_rule( r, target_module, list_item( target_iter ) );
1239         if ( !list_empty( localize ) )
1240             rule_localize( imported, target_module );
1241         /* This rule is really part of some other module. Just refer to it here,
1242          * but do not let it out.
1243          */
1244         imported->exported = 0;
1245     }
1246 
1247     if ( source_iter != source_end || target_iter != target_end )
1248     {
1249         backtrace_line( frame->prev );
1250         out_printf( "import error: length of source and target rule name lists "
1251             "don't match!\n" );
1252         out_printf( "    source: " );
1253         list_print( source_rules );
1254         out_printf( "\n    target: " );
1255         list_print( target_rules );
1256         out_printf( "\n" );
1257         backtrace( frame->prev );
1258         exit( EXITBAD );
1259     }
1260 
1261     return L0;
1262 }
1263 
1264 
1265 /*
1266  * builtin_export() - EXPORT ( MODULE ? : RULES * )
1267  *
1268  * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local (and thus
1269  * exportable). If an element of RULES does not name a rule in MODULE, an error
1270  * is issued.
1271  */
1272 
builtin_export(FRAME * frame,int flags)1273 LIST * builtin_export( FRAME * frame, int flags )
1274 {
1275     LIST * const module_list = lol_get( frame->args, 0 );
1276     LIST * const rules = lol_get( frame->args, 1 );
1277     module_t * const m = bindmodule( list_empty( module_list ) ? 0 : list_front(
1278         module_list ) );
1279 
1280     LISTITER iter = list_begin( rules );
1281     LISTITER const end = list_end( rules );
1282     for ( ; iter != end; iter = list_next( iter ) )
1283     {
1284         RULE * r;
1285         if ( !m->rules || !( r = (RULE *)hash_find( m->rules, list_item( iter )
1286             ) ) )
1287             unknown_rule( frame, "EXPORT", m, list_item( iter ) );
1288         r->exported = 1;
1289     }
1290     return L0;
1291 }
1292 
1293 
1294 /*
1295  * get_source_line() - get a frame's file and line number information
1296  *
1297  * This is the execution traceback information to be indicated for in debug
1298  * output or an error backtrace.
1299  */
1300 
get_source_line(FRAME * frame,char const ** file,int * line)1301 static void get_source_line( FRAME * frame, char const * * file, int * line )
1302 {
1303     if ( frame->file )
1304     {
1305         char const * f = object_str( frame->file );
1306         int l = frame->line;
1307         if ( !strcmp( f, "+" ) )
1308         {
1309             f = "jambase.c";
1310             l += 3;
1311         }
1312         *file = f;
1313         *line = l;
1314     }
1315     else
1316     {
1317         *file = "(builtin)";
1318         *line = -1;
1319     }
1320 }
1321 
1322 
print_source_line(FRAME * frame)1323 void print_source_line( FRAME * frame )
1324 {
1325     char const * file;
1326     int line;
1327     get_source_line( frame, &file, &line );
1328     if ( line < 0 )
1329         out_printf( "(builtin):" );
1330     else
1331         out_printf( "%s:%d:", file, line );
1332 }
1333 
1334 
1335 /*
1336  * backtrace_line() - print a single line of error backtrace for the given
1337  * frame.
1338  */
1339 
backtrace_line(FRAME * frame)1340 void backtrace_line( FRAME * frame )
1341 {
1342     if ( frame == 0 )
1343     {
1344         out_printf( "(no frame):" );
1345     }
1346     else
1347     {
1348         print_source_line( frame );
1349         out_printf( " in %s\n", frame->rulename );
1350     }
1351 }
1352 
1353 
1354 /*
1355  * backtrace() - Print the entire backtrace from the given frame to the Jambase
1356  * which invoked it.
1357  */
1358 
backtrace(FRAME * frame)1359 void backtrace( FRAME * frame )
1360 {
1361     if ( !frame ) return;
1362     while ( ( frame = frame->prev ) )
1363         backtrace_line( frame );
1364 }
1365 
1366 
1367 /*
1368  * builtin_backtrace() - A Jam version of the backtrace function, taking no
1369  * arguments and returning a list of quadruples: FILENAME LINE MODULE. RULENAME
1370  * describing each frame. Note that the module-name is always followed by a
1371  * period.
1372  */
1373 
builtin_backtrace(FRAME * frame,int flags)1374 LIST * builtin_backtrace( FRAME * frame, int flags )
1375 {
1376     LIST * const levels_arg = lol_get( frame->args, 0 );
1377     int levels = list_empty( levels_arg )
1378         ? (int)( (unsigned int)(-1) >> 1 )
1379         : atoi( object_str( list_front( levels_arg ) ) );
1380 
1381     LIST * result = L0;
1382     for ( ; ( frame = frame->prev ) && levels; --levels )
1383     {
1384         char const * file;
1385         int line;
1386         char buf[ 32 ];
1387         string module_name[ 1 ];
1388         get_source_line( frame, &file, &line );
1389         sprintf( buf, "%d", line );
1390         string_new( module_name );
1391         if ( frame->module->name )
1392         {
1393             string_append( module_name, object_str( frame->module->name ) );
1394             string_append( module_name, "." );
1395         }
1396         result = list_push_back( result, object_new( file ) );
1397         result = list_push_back( result, object_new( buf ) );
1398         result = list_push_back( result, object_new( module_name->value ) );
1399         result = list_push_back( result, object_new( frame->rulename ) );
1400         string_free( module_name );
1401     }
1402     return result;
1403 }
1404 
1405 
1406 /*
1407  * builtin_caller_module() - CALLER_MODULE ( levels ? )
1408  *
1409  * If levels is not supplied, returns the name of the module of the rule which
1410  * called the one calling this one. If levels is supplied, it is interpreted as
1411  * an integer specifying a number of additional levels of call stack to traverse
1412  * in order to locate the module in question. If no such module exists, returns
1413  * the empty list. Also returns the empty list when the module in question is
1414  * the global module. This rule is needed for implementing module import
1415  * behavior.
1416  */
1417 
builtin_caller_module(FRAME * frame,int flags)1418 LIST * builtin_caller_module( FRAME * frame, int flags )
1419 {
1420     LIST * const levels_arg = lol_get( frame->args, 0 );
1421     int const levels = list_empty( levels_arg )
1422         ? 0
1423         : atoi( object_str( list_front( levels_arg ) ) );
1424 
1425     int i;
1426     for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
1427         frame = frame->prev;
1428 
1429     return frame->module == root_module()
1430         ? L0
1431         : list_new( object_copy( frame->module->name ) );
1432 }
1433 
1434 
1435 /*
1436  * Return the current working directory.
1437  *
1438  * Usage: pwd = [ PWD ] ;
1439  */
1440 
builtin_pwd(FRAME * frame,int flags)1441 LIST * builtin_pwd( FRAME * frame, int flags )
1442 {
1443     return list_new( object_copy( cwd() ) );
1444 }
1445 
1446 
1447 /*
1448  * Adds targets to the list of target that jam will attempt to update.
1449  */
1450 
builtin_update(FRAME * frame,int flags)1451 LIST * builtin_update( FRAME * frame, int flags )
1452 {
1453     LIST * result = list_copy( targets_to_update() );
1454     LIST * arg1 = lol_get( frame->args, 0 );
1455     LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
1456     clear_targets_to_update();
1457     for ( ; iter != end; iter = list_next( iter ) )
1458         mark_target_for_updating( object_copy( list_item( iter ) ) );
1459     return result;
1460 }
1461 
1462 extern int anyhow;
1463 int last_update_now_status;
1464 
1465 /* Takes a list of target names and immediately updates them.
1466  *
1467  * Parameters:
1468  *  1. Target list.
1469  *  2. Optional file descriptor (converted to a string) for a log file where all
1470  *     the related build output should be redirected.
1471  *  3. If specified, makes the build temporarily disable the -n option, i.e.
1472  *     forces all needed out-of-date targets to be rebuilt.
1473  *  4. If specified, makes the build temporarily disable the -q option, i.e.
1474  *     forces the build to continue even if one of the targets fails to build.
1475  */
builtin_update_now(FRAME * frame,int flags)1476 LIST * builtin_update_now( FRAME * frame, int flags )
1477 {
1478     LIST * targets = lol_get( frame->args, 0 );
1479     LIST * log = lol_get( frame->args, 1 );
1480     LIST * force = lol_get( frame->args, 2 );
1481     LIST * continue_ = lol_get( frame->args, 3 );
1482     int status;
1483     int original_stdout = 0;
1484     int original_stderr = 0;
1485     int original_noexec = 0;
1486     int original_quitquick = 0;
1487 
1488     if ( !list_empty( log ) )
1489     {
1490         /* Temporarily redirect stdout and stderr to the given log file. */
1491         int const fd = atoi( object_str( list_front( log ) ) );
1492         original_stdout = dup( 0 );
1493         original_stderr = dup( 1 );
1494         dup2( fd, 0 );
1495         dup2( fd, 1 );
1496     }
1497 
1498     if ( !list_empty( force ) )
1499     {
1500         original_noexec = globs.noexec;
1501         globs.noexec = 0;
1502     }
1503 
1504     if ( !list_empty( continue_ ) )
1505     {
1506         original_quitquick = globs.quitquick;
1507         globs.quitquick = 0;
1508     }
1509 
1510     status = make( targets, anyhow );
1511 
1512     if ( !list_empty( force ) )
1513     {
1514         globs.noexec = original_noexec;
1515     }
1516 
1517     if ( !list_empty( continue_ ) )
1518     {
1519         globs.quitquick = original_quitquick;
1520     }
1521 
1522     if ( !list_empty( log ) )
1523     {
1524         /* Flush whatever stdio might have buffered, while descriptions 0 and 1
1525          * still refer to the log file.
1526          */
1527         out_flush( );
1528         err_flush( );
1529         dup2( original_stdout, 0 );
1530         dup2( original_stderr, 1 );
1531         close( original_stdout );
1532         close( original_stderr );
1533     }
1534 
1535     last_update_now_status = status;
1536 
1537     return status ? L0 : list_new( object_copy( constant_ok ) );
1538 }
1539 
1540 
builtin_import_module(FRAME * frame,int flags)1541 LIST * builtin_import_module( FRAME * frame, int flags )
1542 {
1543     LIST * const arg1 = lol_get( frame->args, 0 );
1544     LIST * const arg2 = lol_get( frame->args, 1 );
1545     module_t * const m = list_empty( arg2 )
1546         ? root_module()
1547         : bindmodule( list_front( arg2 ) );
1548     import_module( arg1, m );
1549     return L0;
1550 }
1551 
1552 
builtin_imported_modules(FRAME * frame,int flags)1553 LIST * builtin_imported_modules( FRAME * frame, int flags )
1554 {
1555     LIST * const arg0 = lol_get( frame->args, 0 );
1556     OBJECT * const module = list_empty( arg0 ) ? 0 : list_front( arg0 );
1557     return imported_modules( bindmodule( module ) );
1558 }
1559 
1560 
builtin_instance(FRAME * frame,int flags)1561 LIST * builtin_instance( FRAME * frame, int flags )
1562 {
1563     LIST * arg1 = lol_get( frame->args, 0 );
1564     LIST * arg2 = lol_get( frame->args, 1 );
1565     module_t * const instance     = bindmodule( list_front( arg1 ) );
1566     module_t * const class_module = bindmodule( list_front( arg2 ) );
1567     instance->class_module = class_module;
1568     module_set_fixed_variables( instance, class_module->num_fixed_variables );
1569     return L0;
1570 }
1571 
1572 
builtin_sort(FRAME * frame,int flags)1573 LIST * builtin_sort( FRAME * frame, int flags )
1574 {
1575     return list_sort( lol_get( frame->args, 0 ) );
1576 }
1577 
1578 
builtin_normalize_path(FRAME * frame,int flags)1579 LIST * builtin_normalize_path( FRAME * frame, int flags )
1580 {
1581     LIST * arg = lol_get( frame->args, 0 );
1582 
1583     /* First, we iterate over all '/'-separated elements, starting from the end
1584      * of string. If we see a '..', we remove a preceding path element. If we
1585      * see '.', we remove it. Removal is done by overwriting data using '\1'
1586      * characters. After the whole string has been processed, we do a second
1587      * pass, removing any entered '\1' characters.
1588      */
1589 
1590     string   in[ 1 ];
1591     string   out[ 1 ];
1592     /* Last character of the part of string still to be processed. */
1593     char   * end;
1594     /* Working pointer. */
1595     char   * current;
1596     /* Number of '..' elements seen and not processed yet. */
1597     int      dotdots = 0;
1598     int      rooted  = 0;
1599     OBJECT * result  = 0;
1600     LISTITER arg_iter = list_begin( arg );
1601     LISTITER arg_end = list_end( arg );
1602 
1603     /* Make a copy of input: we should not change it. Prepend a '/' before it as
1604      * a guard for the algorithm later on and remember whether it was originally
1605      * rooted or not.
1606      */
1607     string_new( in );
1608     string_push_back( in, '/' );
1609     for ( ; arg_iter != arg_end; arg_iter = list_next( arg_iter ) )
1610     {
1611         if ( object_str( list_item( arg_iter ) )[ 0 ] != '\0' )
1612         {
1613             if ( in->size == 1 )
1614                 rooted = ( object_str( list_item( arg_iter ) )[ 0 ] == '/'  ) ||
1615                          ( object_str( list_item( arg_iter ) )[ 0 ] == '\\' );
1616             else
1617                 string_append( in, "/" );
1618             string_append( in, object_str( list_item( arg_iter ) ) );
1619         }
1620     }
1621 
1622     /* Convert \ into /. On Windows, paths using / and \ are equivalent, and we
1623      * want this function to obtain a canonic representation.
1624      */
1625     for ( current = in->value, end = in->value + in->size;
1626         current < end; ++current )
1627         if ( *current == '\\' )
1628             *current = '/';
1629 
1630     /* Now we remove any extra path elements by overwriting them with '\1'
1631      * characters and count how many more unused '..' path elements there are
1632      * remaining. Note that each remaining path element with always starts with
1633      * a '/' character.
1634      */
1635     for ( end = in->value + in->size - 1; end >= in->value; )
1636     {
1637         /* Set 'current' to the next occurrence of '/', which always exists. */
1638         for ( current = end; *current != '/'; --current );
1639 
1640         if ( current == end )
1641         {
1642             /* Found a trailing or duplicate '/'. Remove it. */
1643             *current = '\1';
1644         }
1645         else if ( ( end - current == 1 ) && ( *( current + 1 ) == '.' ) )
1646         {
1647             /* Found '/.'. Remove them all. */
1648             *current = '\1';
1649             *(current + 1) = '\1';
1650         }
1651         else if ( ( end - current == 2 ) && ( *( current + 1 ) == '.' ) &&
1652             ( *( current + 2 ) == '.' ) )
1653         {
1654             /* Found '/..'. Remove them all. */
1655             *current = '\1';
1656             *(current + 1) = '\1';
1657             *(current + 2) = '\1';
1658             ++dotdots;
1659         }
1660         else if ( dotdots )
1661         {
1662             memset( current, '\1', end - current + 1 );
1663             --dotdots;
1664         }
1665         end = current - 1;
1666     }
1667 
1668     string_new( out );
1669 
1670     /* Now we know that we need to add exactly dotdots '..' path elements to the
1671      * front and that our string is either empty or has a '/' as its first
1672      * significant character. If we have any dotdots remaining then the passed
1673      * path must not have been rooted or else it is invalid we return an empty
1674      * list.
1675      */
1676     if ( dotdots )
1677     {
1678         if ( rooted )
1679         {
1680             string_free( out );
1681             string_free( in );
1682             return L0;
1683         }
1684         do
1685             string_append( out, "/.." );
1686         while ( --dotdots );
1687     }
1688 
1689     /* Now we actually remove all the path characters marked for removal. */
1690     for ( current = in->value; *current; ++current )
1691         if ( *current != '\1' )
1692             string_push_back( out, *current );
1693 
1694     /* Here we know that our string contains no '\1' characters and is either
1695      * empty or has a '/' as its initial character. If the original path was not
1696      * rooted and we have a non-empty path we need to drop the initial '/'. If
1697      * the original path was rooted and we have an empty path we need to add
1698      * back the '/'.
1699      */
1700     result = object_new( out->size
1701         ? out->value + !rooted
1702         : ( rooted ? "/" : "." ) );
1703 
1704     string_free( out );
1705     string_free( in );
1706 
1707     return list_new( result );
1708 }
1709 
1710 
builtin_native_rule(FRAME * frame,int flags)1711 LIST * builtin_native_rule( FRAME * frame, int flags )
1712 {
1713     LIST * module_name = lol_get( frame->args, 0 );
1714     LIST * rule_name = lol_get( frame->args, 1 );
1715 
1716     module_t * module = bindmodule( list_front( module_name ) );
1717 
1718     native_rule_t * np;
1719     if ( module->native_rules && (np = (native_rule_t *)hash_find(
1720         module->native_rules, list_front( rule_name ) ) ) )
1721     {
1722         new_rule_body( module, np->name, np->procedure, 1 );
1723     }
1724     else
1725     {
1726         backtrace_line( frame->prev );
1727         out_printf( "error: no native rule \"%s\" defined in module \"%s.\"\n",
1728             object_str( list_front( rule_name ) ), object_str( module->name ) );
1729         backtrace( frame->prev );
1730         exit( EXITBAD );
1731     }
1732     return L0;
1733 }
1734 
1735 
builtin_has_native_rule(FRAME * frame,int flags)1736 LIST * builtin_has_native_rule( FRAME * frame, int flags )
1737 {
1738     LIST * module_name = lol_get( frame->args, 0 );
1739     LIST * rule_name   = lol_get( frame->args, 1 );
1740     LIST * version     = lol_get( frame->args, 2 );
1741 
1742     module_t * module = bindmodule( list_front( module_name ) );
1743 
1744     native_rule_t * np;
1745     if ( module->native_rules && (np = (native_rule_t *)hash_find(
1746         module->native_rules, list_front( rule_name ) ) ) )
1747     {
1748         int expected_version = atoi( object_str( list_front( version ) ) );
1749         if ( np->version == expected_version )
1750             return list_new( object_copy( constant_true ) );
1751     }
1752     return L0;
1753 }
1754 
1755 
builtin_user_module(FRAME * frame,int flags)1756 LIST * builtin_user_module( FRAME * frame, int flags )
1757 {
1758     LIST * const module_name = lol_get( frame->args, 0 );
1759     LISTITER iter = list_begin( module_name );
1760     LISTITER const end = list_end( module_name );
1761     for ( ; iter != end; iter = list_next( iter ) )
1762         bindmodule( list_item( iter ) )->user_module = 1;
1763     return L0;
1764 }
1765 
1766 
builtin_nearest_user_location(FRAME * frame,int flags)1767 LIST * builtin_nearest_user_location( FRAME * frame, int flags )
1768 {
1769     FRAME * const nearest_user_frame = frame->module->user_module
1770         ? frame
1771         : frame->prev_user;
1772     if ( !nearest_user_frame )
1773         return L0;
1774 
1775     {
1776         LIST * result = L0;
1777         char const * file;
1778         int line;
1779         char buf[ 32 ];
1780 
1781         get_source_line( nearest_user_frame, &file, &line );
1782         sprintf( buf, "%d", line );
1783         result = list_push_back( result, object_new( file ) );
1784         result = list_push_back( result, object_new( buf ) );
1785         return result;
1786     }
1787 }
1788 
1789 
builtin_check_if_file(FRAME * frame,int flags)1790 LIST * builtin_check_if_file( FRAME * frame, int flags )
1791 {
1792     LIST * const name = lol_get( frame->args, 0 );
1793     return file_is_file( list_front( name ) ) == 1
1794         ? list_new( object_copy( constant_true ) )
1795         : L0;
1796 }
1797 
1798 
builtin_md5(FRAME * frame,int flags)1799 LIST * builtin_md5( FRAME * frame, int flags )
1800 {
1801     LIST * l = lol_get( frame->args, 0 );
1802     char const * s = object_str( list_front( l ) );
1803 
1804     md5_state_t state;
1805     md5_byte_t digest[ 16 ];
1806     char hex_output[ 16 * 2 + 1 ];
1807 
1808     int di;
1809 
1810     md5_init( &state );
1811     md5_append( &state, (md5_byte_t const *)s, strlen( s ) );
1812     md5_finish( &state, digest );
1813 
1814     for ( di = 0; di < 16; ++di )
1815         sprintf( hex_output + di * 2, "%02x", digest[ di ] );
1816 
1817     return list_new( object_new( hex_output ) );
1818 }
1819 
1820 
builtin_file_open(FRAME * frame,int flags)1821 LIST * builtin_file_open( FRAME * frame, int flags )
1822 {
1823     char const * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
1824     char const * mode = object_str( list_front( lol_get( frame->args, 1 ) ) );
1825     int fd;
1826     char buffer[ sizeof( "4294967295" ) ];
1827 
1828     if ( strcmp(mode, "w") == 0 )
1829         fd = open( name, O_WRONLY|O_CREAT|O_TRUNC, 0666 );
1830     else
1831         fd = open( name, O_RDONLY );
1832 
1833     if ( fd != -1 )
1834     {
1835         sprintf( buffer, "%d", fd );
1836         return list_new( object_new( buffer ) );
1837     }
1838     return L0;
1839 }
1840 
1841 
builtin_pad(FRAME * frame,int flags)1842 LIST * builtin_pad( FRAME * frame, int flags )
1843 {
1844     OBJECT * string = list_front( lol_get( frame->args, 0 ) );
1845     char const * width_s = object_str( list_front( lol_get( frame->args, 1 ) ) );
1846 
1847     int current = strlen( object_str( string ) );
1848     int desired = atoi( width_s );
1849     if ( current >= desired )
1850         return list_new( object_copy( string ) );
1851     else
1852     {
1853         char * buffer = (char *)BJAM_MALLOC( desired + 1 );
1854         int i;
1855         LIST * result;
1856 
1857         strcpy( buffer, object_str( string ) );
1858         for ( i = current; i < desired; ++i )
1859             buffer[ i ] = ' ';
1860         buffer[ desired ] = '\0';
1861         result = list_new( object_new( buffer ) );
1862         BJAM_FREE( buffer );
1863         return result;
1864     }
1865 }
1866 
1867 
builtin_precious(FRAME * frame,int flags)1868 LIST * builtin_precious( FRAME * frame, int flags )
1869 {
1870     LIST * targets = lol_get( frame->args, 0 );
1871     LISTITER iter = list_begin( targets );
1872     LISTITER const end = list_end( targets );
1873     for ( ; iter != end; iter = list_next( iter ) )
1874         bindtarget( list_item( iter ) )->flags |= T_FLAG_PRECIOUS;
1875     return L0;
1876 }
1877 
1878 
builtin_self_path(FRAME * frame,int flags)1879 LIST * builtin_self_path( FRAME * frame, int flags )
1880 {
1881     extern char const * saved_argv0;
1882     char * p = executable_path( saved_argv0 );
1883     if ( p )
1884     {
1885         LIST * const result = list_new( object_new( p ) );
1886         free( p );
1887         return result;
1888     }
1889     return L0;
1890 }
1891 
1892 
builtin_makedir(FRAME * frame,int flags)1893 LIST * builtin_makedir( FRAME * frame, int flags )
1894 {
1895     LIST * const path = lol_get( frame->args, 0 );
1896     return file_mkdir( object_str( list_front( path ) ) )
1897         ? L0
1898         : list_new( object_copy( list_front( path ) ) );
1899 }
1900 
builtin_readlink(FRAME * frame,int flags)1901 LIST *builtin_readlink( FRAME * frame, int flags )
1902 {
1903     const char * path = object_str( list_front( lol_get( frame->args, 0 ) ) );
1904 #ifdef OS_NT
1905 
1906     /* This struct is declared in ntifs.h which is
1907      * part of the Windows Driver Kit.
1908      */
1909     typedef struct _REPARSE_DATA_BUFFER {
1910         ULONG ReparseTag;
1911         USHORT ReparseDataLength;
1912         USHORT Reserved;
1913         union {
1914             struct {
1915                 USHORT SubstituteNameOffset;
1916                 USHORT SubstituteNameLength;
1917                 USHORT PrintNameOffset;
1918                 USHORT PrintNameLength;
1919                 ULONG Flags;
1920                 WCHAR PathBuffer[ 1 ];
1921             } SymbolicLinkReparseBuffer;
1922             struct {
1923                 USHORT SubstituteNameOffset;
1924                 USHORT SubstituteNameLength;
1925                 USHORT PrintNameOffset;
1926                 USHORT PrintNameLength;
1927                 WCHAR PathBuffer[ 1 ];
1928             } MountPointReparseBuffer;
1929             struct {
1930                 UCHAR DataBuffer[ 1 ];
1931             } GenericReparseBuffer;
1932         };
1933     } REPARSE_DATA_BUFFER;
1934 
1935     HANDLE hLink = CreateFileA( path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL );
1936     DWORD n;
1937     union {
1938         REPARSE_DATA_BUFFER reparse;
1939         char data[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
1940     } buf;
1941     int okay = DeviceIoControl(hLink, FSCTL_GET_REPARSE_POINT, NULL, 0, &buf, sizeof(buf), &n, NULL);
1942 
1943     CloseHandle( hLink );
1944 
1945     if (okay && buf.reparse.ReparseTag == IO_REPARSE_TAG_SYMLINK )
1946     {
1947         int index = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameOffset / 2;
1948         int length = buf.reparse.SymbolicLinkReparseBuffer.SubstituteNameLength / 2;
1949         char cbuf[MAX_PATH + 1];
1950         int numchars = WideCharToMultiByte( CP_ACP, 0, buf.reparse.SymbolicLinkReparseBuffer.PathBuffer + index, length, cbuf, sizeof(cbuf), NULL, NULL );
1951         if( numchars >= sizeof(cbuf) )
1952         {
1953             return 0;
1954         }
1955         cbuf[numchars] = '\0';
1956         return list_new( object_new( cbuf ) );
1957     }
1958     else if( okay && buf.reparse.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT )
1959     {
1960         int index = buf.reparse.MountPointReparseBuffer.SubstituteNameOffset / 2;
1961         int length = buf.reparse.MountPointReparseBuffer.SubstituteNameLength / 2;
1962         char cbuf[MAX_PATH + 1];
1963         const char * result;
1964         int numchars = WideCharToMultiByte( CP_ACP, 0, buf.reparse.MountPointReparseBuffer.PathBuffer + index, length, cbuf, sizeof(cbuf), NULL, NULL );
1965         if( numchars >= sizeof(cbuf) )
1966         {
1967             return 0;
1968         }
1969         cbuf[numchars] = '\0';
1970         /* strip off the leading "\??\" */
1971         result = cbuf;
1972         if ( cbuf[ 0 ] == '\\' && cbuf[ 1 ] == '?' &&
1973             cbuf[ 2 ] == '?' && cbuf[ 3 ] == '\\' &&
1974             cbuf[ 4 ] != '\0' && cbuf[ 5 ] == ':' )
1975         {
1976             result += 4;
1977         }
1978         return list_new( object_new( result ) );
1979     }
1980     return 0;
1981 #else
1982     char static_buf[256];
1983     char * buf = static_buf;
1984     size_t bufsize = 256;
1985     LIST * result = 0;
1986     while (1) {
1987         ssize_t len = readlink( path, buf, bufsize );
1988         if ( len < 0 )
1989         {
1990             break;
1991         }
1992         else if ( len < bufsize )
1993         {
1994             buf[ len ] = '\0';
1995             result = list_new( object_new( buf ) );
1996             break;
1997         }
1998         if ( buf != static_buf )
1999             BJAM_FREE( buf );
2000         bufsize *= 2;
2001         buf = (char *)BJAM_MALLOC( bufsize );
2002     }
2003 
2004     if ( buf != static_buf )
2005         BJAM_FREE( buf );
2006 
2007     return result;
2008 #endif
2009 }
2010 
2011 #ifdef JAM_DEBUGGER
2012 
builtin_debug_print_helper(FRAME * frame,int flags)2013 LIST *builtin_debug_print_helper( FRAME * frame, int flags )
2014 {
2015     debug_print_result = list_copy( lol_get( frame->args, 0 ) );
2016     return L0;
2017 }
2018 
2019 #endif
2020 
2021 #ifdef HAVE_PYTHON
2022 
builtin_python_import_rule(FRAME * frame,int flags)2023 LIST * builtin_python_import_rule( FRAME * frame, int flags )
2024 {
2025     static int first_time = 1;
2026     char const * python_module   = object_str( list_front( lol_get( frame->args,
2027         0 ) ) );
2028     char const * python_function = object_str( list_front( lol_get( frame->args,
2029         1 ) ) );
2030     OBJECT     * jam_module      = list_front( lol_get( frame->args, 2 ) );
2031     OBJECT     * jam_rule        = list_front( lol_get( frame->args, 3 ) );
2032 
2033     PyObject * pName;
2034     PyObject * pModule;
2035     PyObject * pDict;
2036     PyObject * pFunc;
2037 
2038     if ( first_time )
2039     {
2040         /* At the first invocation, we add the value of the global
2041          * EXTRA_PYTHONPATH to the sys.path Python variable.
2042          */
2043         LIST * extra = 0;
2044         module_t * outer_module = frame->module;
2045         LISTITER iter, end;
2046 
2047         first_time = 0;
2048 
2049         extra = var_get( root_module(), constant_extra_pythonpath );
2050 
2051         iter = list_begin( extra ), end = list_end( extra );
2052         for ( ; iter != end; iter = list_next( iter ) )
2053         {
2054             string buf[ 1 ];
2055             string_new( buf );
2056             string_append( buf, "import sys\nsys.path.append(\"" );
2057             string_append( buf, object_str( list_item( iter ) ) );
2058             string_append( buf, "\")\n" );
2059             PyRun_SimpleString( buf->value );
2060             string_free( buf );
2061         }
2062     }
2063 
2064     pName   = PyString_FromString( python_module );
2065     pModule = PyImport_Import( pName );
2066     Py_DECREF( pName );
2067 
2068     if ( pModule != NULL )
2069     {
2070         pDict = PyModule_GetDict( pModule );
2071         pFunc = PyDict_GetItemString( pDict, python_function );
2072 
2073         if ( pFunc && PyCallable_Check( pFunc ) )
2074         {
2075             module_t * m = bindmodule( jam_module );
2076             new_rule_body( m, jam_rule, function_python( pFunc, 0 ), 0 );
2077         }
2078         else
2079         {
2080             if ( PyErr_Occurred() )
2081                 PyErr_Print();
2082             err_printf( "Cannot find function \"%s\"\n", python_function );
2083         }
2084         Py_DECREF( pModule );
2085     }
2086     else
2087     {
2088         PyErr_Print();
2089         err_printf( "Failed to load \"%s\"\n", python_module );
2090     }
2091     return L0;
2092 
2093 }
2094 
2095 #endif  /* #ifdef HAVE_PYTHON */
2096 
2097 
lol_build(LOL * lol,char const ** elements)2098 void lol_build( LOL * lol, char const * * elements )
2099 {
2100     LIST * l = L0;
2101     lol_init( lol );
2102 
2103     while ( elements && *elements )
2104     {
2105         if ( !strcmp( *elements, ":" ) )
2106         {
2107             lol_add( lol, l );
2108             l = L0;
2109         }
2110         else
2111         {
2112             l = list_push_back( l, object_new( *elements ) );
2113         }
2114         ++elements;
2115     }
2116 
2117     if ( l != L0 )
2118         lol_add( lol, l );
2119 }
2120 
2121 
2122 #ifdef HAVE_PYTHON
2123 
jam_list_from_string(PyObject * a)2124 static LIST *jam_list_from_string(PyObject *a)
2125 {
2126     return list_new( object_new( PyString_AsString( a ) ) );
2127 }
2128 
jam_list_from_sequence(PyObject * a)2129 static LIST *jam_list_from_sequence(PyObject *a)
2130 {
2131     LIST * l = 0;
2132 
2133     int i = 0;
2134     int s = PySequence_Size( a );
2135 
2136     for ( ; i < s; ++i )
2137     {
2138         /* PySequence_GetItem returns new reference. */
2139         PyObject * e = PySequence_GetItem( a, i );
2140         char * s = PyString_AsString( e );
2141         if ( !s )
2142         {
2143             /* try to get the repr() on the object */
2144             PyObject *repr = PyObject_Repr(e);
2145             if (repr)
2146             {
2147                 const char *str = PyString_AsString(repr);
2148                 PyErr_Format(PyExc_TypeError, "expecting type <str> got %s", str);
2149             }
2150             /* fall back to a dumb error */
2151             else
2152             {
2153                 PyErr_BadArgument();
2154             }
2155             return NULL;
2156         }
2157         l = list_push_back( l, object_new( s ) );
2158         Py_DECREF( e );
2159     }
2160 
2161     return l;
2162 }
2163 
make_jam_arguments_from_python(FRAME * inner,PyObject * args)2164 static void make_jam_arguments_from_python(FRAME* inner, PyObject *args)
2165 {
2166     int i;
2167     int size;
2168 
2169     /* Build up the list of arg lists. */
2170     frame_init( inner );
2171     inner->prev = 0;
2172     inner->prev_user = 0;
2173     inner->module = bindmodule( constant_python_interface );
2174 
2175     size = PyTuple_Size( args );
2176     for (i = 0 ; i < size; ++i)
2177     {
2178         PyObject * a = PyTuple_GetItem( args, i );
2179         if ( PyString_Check( a ) )
2180         {
2181             lol_add( inner->args, jam_list_from_string(a) );
2182         }
2183         else if ( PySequence_Check( a ) )
2184         {
2185             lol_add( inner->args, jam_list_from_sequence(a) );
2186         }
2187     }
2188 }
2189 
2190 
2191 /*
2192  * Calls the bjam rule specified by name passed in 'args'. The name is looked up
2193  * in the context of bjam's 'python_interface' module. Returns the list of
2194  * strings returned by the rule.
2195  */
2196 
bjam_call(PyObject * self,PyObject * args)2197 PyObject * bjam_call( PyObject * self, PyObject * args )
2198 {
2199     FRAME    inner[ 1 ];
2200     LIST   * result;
2201     PARSE  * p;
2202     OBJECT * rulename;
2203     PyObject *args_proper;
2204 
2205     /* PyTuple_GetItem returns borrowed reference. */
2206     rulename = object_new( PyString_AsString( PyTuple_GetItem( args, 0 ) ) );
2207 
2208     args_proper = PyTuple_GetSlice(args, 1, PyTuple_Size(args));
2209     make_jam_arguments_from_python (inner, args_proper);
2210     if ( PyErr_Occurred() )
2211     {
2212         return NULL;
2213     }
2214     Py_DECREF(args_proper);
2215 
2216     result = evaluate_rule( bindrule( rulename, inner->module), rulename, inner );
2217     object_free( rulename );
2218 
2219     frame_free( inner );
2220 
2221     /* Convert the bjam list into a Python list result. */
2222     {
2223         PyObject * const pyResult = PyList_New( list_length( result ) );
2224         int i = 0;
2225         LISTITER iter = list_begin( result );
2226         LISTITER const end = list_end( result );
2227         for ( ; iter != end; iter = list_next( iter ) )
2228         {
2229             PyList_SetItem( pyResult, i, PyString_FromString( object_str(
2230                 list_item( iter ) ) ) );
2231             i += 1;
2232         }
2233         list_free( result );
2234         return pyResult;
2235     }
2236 }
2237 
2238 
2239 /*
2240  * Accepts four arguments:
2241  * - module name
2242  * - rule name,
2243  * - Python callable.
2244  * - (optional) bjam language function signature.
2245  * Creates a bjam rule with the specified name in the specified module, which
2246  * will invoke the Python callable.
2247  */
2248 
bjam_import_rule(PyObject * self,PyObject * args)2249 PyObject * bjam_import_rule( PyObject * self, PyObject * args )
2250 {
2251     char     * module;
2252     char     * rule;
2253     PyObject * func;
2254     PyObject * bjam_signature = NULL;
2255     module_t * m;
2256     RULE     * r;
2257     OBJECT   * module_name;
2258     OBJECT   * rule_name;
2259 
2260     if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
2261                             &module, &rule, &func, &bjam_signature ) )
2262         return NULL;
2263 
2264     if ( !PyCallable_Check( func ) )
2265     {
2266         PyErr_SetString( PyExc_RuntimeError, "Non-callable object passed to "
2267             "bjam.import_rule" );
2268         return NULL;
2269     }
2270 
2271     module_name = *module ? object_new( module ) : 0;
2272     m = bindmodule( module_name );
2273     if ( module_name )
2274         object_free( module_name );
2275     rule_name = object_new( rule );
2276     new_rule_body( m, rule_name, function_python( func, bjam_signature ), 0 );
2277     object_free( rule_name );
2278 
2279     Py_INCREF( Py_None );
2280     return Py_None;
2281 }
2282 
2283 
2284 /*
2285  * Accepts four arguments:
2286  *  - an action name
2287  *  - an action body
2288  *  - a list of variable that will be bound inside the action
2289  *  - integer flags.
2290  *  Defines an action on bjam side.
2291  */
2292 
bjam_define_action(PyObject * self,PyObject * args)2293 PyObject * bjam_define_action( PyObject * self, PyObject * args )
2294 {
2295     char     * name;
2296     char     * body;
2297     module_t * m;
2298     PyObject * bindlist_python;
2299     int        flags;
2300     LIST     * bindlist = L0;
2301     int        n;
2302     int        i;
2303     OBJECT   * name_str;
2304     FUNCTION * body_func;
2305 
2306     if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
2307         &PyList_Type, &bindlist_python, &flags ) )
2308         return NULL;
2309 
2310     n = PyList_Size( bindlist_python );
2311     for ( i = 0; i < n; ++i )
2312     {
2313         PyObject * next = PyList_GetItem( bindlist_python, i );
2314         if ( !PyString_Check( next ) )
2315         {
2316             PyErr_SetString( PyExc_RuntimeError, "bind list has non-string "
2317                 "type" );
2318             return NULL;
2319         }
2320         bindlist = list_push_back( bindlist, object_new( PyString_AsString( next
2321             ) ) );
2322     }
2323 
2324     name_str = object_new( name );
2325     body_func = function_compile_actions( body, constant_builtin, -1 );
2326     new_rule_actions( root_module(), name_str, body_func, bindlist, flags );
2327     function_free( body_func );
2328     object_free( name_str );
2329 
2330     Py_INCREF( Py_None );
2331     return Py_None;
2332 }
2333 
2334 
2335 /*
2336  * Returns the value of a variable in root Jam module.
2337  */
2338 
bjam_variable(PyObject * self,PyObject * args)2339 PyObject * bjam_variable( PyObject * self, PyObject * args )
2340 {
2341     char     * name;
2342     LIST     * value;
2343     PyObject * result;
2344     int        i;
2345     OBJECT   * varname;
2346     LISTITER   iter;
2347     LISTITER   end;
2348 
2349     if ( !PyArg_ParseTuple( args, "s", &name ) )
2350         return NULL;
2351 
2352     varname = object_new( name );
2353     value = var_get( root_module(), varname );
2354     object_free( varname );
2355     iter = list_begin( value );
2356     end = list_end( value );
2357 
2358     result = PyList_New( list_length( value ) );
2359     for ( i = 0; iter != end; iter = list_next( iter ), ++i )
2360         PyList_SetItem( result, i, PyString_FromString( object_str( list_item(
2361             iter ) ) ) );
2362 
2363     return result;
2364 }
2365 
2366 
bjam_backtrace(PyObject * self,PyObject * args)2367 PyObject * bjam_backtrace( PyObject * self, PyObject * args )
2368 {
2369     PyObject     * result = PyList_New( 0 );
2370     struct frame * f = frame_before_python_call;
2371 
2372     for ( ; (f = f->prev); )
2373     {
2374         PyObject   * tuple = PyTuple_New( 4 );
2375         char const * file;
2376         int          line;
2377         char         buf[ 32 ];
2378         string module_name[ 1 ];
2379 
2380         get_source_line( f, &file, &line );
2381         sprintf( buf, "%d", line );
2382         string_new( module_name );
2383         if ( f->module->name )
2384         {
2385             string_append( module_name, object_str( f->module->name ) );
2386             string_append( module_name, "." );
2387         }
2388 
2389         /* PyTuple_SetItem steals reference. */
2390         PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
2391         PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
2392         PyTuple_SetItem( tuple, 2, PyString_FromString( module_name->value ) );
2393         PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
2394 
2395         string_free( module_name );
2396 
2397         PyList_Append( result, tuple );
2398         Py_DECREF( tuple );
2399     }
2400     return result;
2401 }
2402 
bjam_caller(PyObject * self,PyObject * args)2403 PyObject * bjam_caller( PyObject * self, PyObject * args )
2404 {
2405     return PyString_FromString( frame_before_python_call->prev->module->name ?
2406         object_str( frame_before_python_call->prev->module->name ) : "" );
2407 }
2408 
2409 #endif  /* #ifdef HAVE_PYTHON */
2410 
2411 
2412 #ifdef HAVE_POPEN
2413 
2414 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW64__) || defined(__MINGW32__)
2415     #undef popen
2416     #define popen windows_popen_wrapper
2417     #undef pclose
2418     #define pclose _pclose
2419 
2420     /*
2421      * This wrapper is a workaround for a funny _popen() feature on Windows
2422      * where it eats external quotes in some cases. The bug seems to be related
2423      * to the quote stripping functionality used by the Windows cmd.exe
2424      * interpreter when its /S is not specified.
2425      *
2426      * Cleaned up quote from the cmd.exe help screen as displayed on Windows XP
2427      * SP3:
2428      *
2429      *   1. If all of the following conditions are met, then quote characters on
2430      *      the command line are preserved:
2431      *
2432      *       - no /S switch
2433      *       - exactly two quote characters
2434      *       - no special characters between the two quote characters, where
2435      *         special is one of: &<>()@^|
2436      *       - there are one or more whitespace characters between the two quote
2437      *         characters
2438      *       - the string between the two quote characters is the name of an
2439      *         executable file.
2440      *
2441      *   2. Otherwise, old behavior is to see if the first character is a quote
2442      *      character and if so, strip the leading character and remove the last
2443      *      quote character on the command line, preserving any text after the
2444      *      last quote character.
2445      *
2446      * This causes some commands containing quotes not to be executed correctly.
2447      * For example:
2448      *
2449      *   "\Long folder name\aaa.exe" --name="Jurko" --no-surname
2450      *
2451      * would get its outermost quotes stripped and would be executed as:
2452      *
2453      *   \Long folder name\aaa.exe" --name="Jurko --no-surname
2454      *
2455      * which would report an error about '\Long' not being a valid command.
2456      *
2457      * cmd.exe help seems to indicate it would be enough to add an extra space
2458      * character in front of the command to avoid this but this does not work,
2459      * most likely due to the shell first stripping all leading whitespace
2460      * characters from the command.
2461      *
2462      * Solution implemented here is to quote the whole command in case it
2463      * contains any quote characters. Note thought this will not work correctly
2464      * should Windows ever 'fix' this feature.
2465      *                                               (03.06.2008.) (Jurko)
2466      */
windows_popen_wrapper(char const * command,char const * mode)2467     static FILE * windows_popen_wrapper( char const * command,
2468         char const * mode )
2469     {
2470         int const extra_command_quotes_needed = !!strchr( command, '"' );
2471         string quoted_command;
2472         FILE * result;
2473 
2474         if ( extra_command_quotes_needed )
2475         {
2476             string_new( &quoted_command );
2477             string_append( &quoted_command, "\"" );
2478             string_append( &quoted_command, command );
2479             string_append( &quoted_command, "\"" );
2480             command = quoted_command.value;
2481         }
2482 
2483         result = _popen( command, "r" );
2484 
2485         if ( extra_command_quotes_needed )
2486             string_free( &quoted_command );
2487 
2488         return result;
2489     }
2490 #endif  /* defined(_MSC_VER) || defined(__BORLANDC__) */
2491 
2492 
builtin_shell(FRAME * frame,int flags)2493 LIST * builtin_shell( FRAME * frame, int flags )
2494 {
2495     LIST   * command = lol_get( frame->args, 0 );
2496     LIST   * result = L0;
2497     string   s;
2498     int      ret;
2499     char     buffer[ 1024 ];
2500     FILE   * p = NULL;
2501     int      exit_status = -1;
2502     int      exit_status_opt = 0;
2503     int      no_output_opt = 0;
2504     int      strip_eol_opt = 0;
2505 
2506     /* Process the variable args options. */
2507     {
2508         int a = 1;
2509         LIST * arg = lol_get( frame->args, a );
2510         for ( ; !list_empty( arg ); arg = lol_get( frame->args, ++a ) )
2511         {
2512             if ( !strcmp( "exit-status", object_str( list_front( arg ) ) ) )
2513                 exit_status_opt = 1;
2514             else if ( !strcmp( "no-output", object_str( list_front( arg ) ) ) )
2515                 no_output_opt = 1;
2516             else if ( !strcmp("strip-eol", object_str( list_front( arg ) ) ) )
2517                 strip_eol_opt = 1;
2518         }
2519     }
2520 
2521     /* The following fflush() call seems to be indicated as a workaround for a
2522      * popen() bug on POSIX implementations related to synhronizing input
2523      * stream positions for the called and the calling process.
2524      */
2525     fflush( NULL );
2526 
2527     p = popen( object_str( list_front( command ) ), "r" );
2528     if ( p == NULL )
2529         return L0;
2530 
2531     string_new( &s );
2532 
2533     while ( ( ret = fread( buffer, sizeof( char ), sizeof( buffer ) - 1, p ) ) >
2534         0 )
2535     {
2536         buffer[ ret ] = 0;
2537         if ( !no_output_opt )
2538         {
2539             string_append( &s, buffer );
2540         }
2541 
2542         /* Explicit EOF check for systems with broken fread */
2543         if ( feof( p ) ) break;
2544     }
2545 
2546     if ( strip_eol_opt )
2547         string_rtrim( &s );
2548 
2549     exit_status = pclose( p );
2550 
2551     /* The command output is returned first. */
2552     result = list_new( object_new( s.value ) );
2553     string_free( &s );
2554 
2555     /* The command exit result next. */
2556     if ( exit_status_opt )
2557     {
2558         if ( WIFEXITED( exit_status ) )
2559             exit_status = WEXITSTATUS( exit_status );
2560         else
2561             exit_status = -1;
2562 
2563 #ifdef OS_VMS
2564         /* Harmonize VMS success status with POSIX */
2565         if ( exit_status == 1 ) exit_status = EXIT_SUCCESS;
2566 #endif
2567         sprintf( buffer, "%d", exit_status );
2568         result = list_push_back( result, object_new( buffer ) );
2569     }
2570 
2571     return result;
2572 }
2573 
2574 #else  /* #ifdef HAVE_POPEN */
2575 
builtin_shell(FRAME * frame,int flags)2576 LIST * builtin_shell( FRAME * frame, int flags )
2577 {
2578     return L0;
2579 }
2580 
2581 #endif  /* #ifdef HAVE_POPEN */
2582 
2583 
2584 /*
2585  * builtin_glob_archive() - GLOB_ARCHIVE rule
2586  */
2587 
2588 struct globbing2
2589 {
2590     LIST * patterns[ 2 ];
2591     LIST * results;
2592     LIST * case_insensitive;
2593 };
2594 
2595 
builtin_glob_archive_back(void * closure,OBJECT * member,LIST * symbols,int status,timestamp const * const time)2596 static void builtin_glob_archive_back( void * closure, OBJECT * member,
2597     LIST * symbols, int status, timestamp const * const time )
2598 {
2599     PROFILE_ENTER( BUILTIN_GLOB_ARCHIVE_BACK );
2600 
2601     struct globbing2 * const globbing = (struct globbing2 *)closure;
2602     PATHNAME f;
2603     string buf[ 1 ];
2604     LISTITER iter;
2605     LISTITER end;
2606     LISTITER iter_symbols;
2607     LISTITER end_symbols;
2608     int matched = 0;
2609 
2610     /* Match member name.
2611      */
2612     path_parse( object_str( member ), &f );
2613 
2614     if ( !strcmp( f.f_member.ptr, "" ) )
2615     {
2616         PROFILE_EXIT( BUILTIN_GLOB_ARCHIVE_BACK );
2617         return;
2618     }
2619 
2620     string_new( buf );
2621     string_append_range( buf, f.f_member.ptr, f.f_member.ptr + f.f_member.len );
2622 
2623     if ( globbing->case_insensitive )
2624         downcase_inplace( buf->value );
2625 
2626     /* Glob with member patterns. If not matched, then match symbols.
2627      */
2628     matched = 0;
2629     iter = list_begin( globbing->patterns[ 0 ] );
2630     end = list_end( globbing->patterns[ 0 ] );
2631     for ( ; !matched && iter != end;
2632             iter = list_next( iter ) )
2633     {
2634         const char * pattern = object_str( list_item( iter ) );
2635         int match_exact = ( !has_wildcards( pattern ) );
2636         matched = ( match_exact ?
2637             ( !strcmp( pattern, buf->value ) ) :
2638             ( !glob( pattern, buf->value ) ) );
2639     }
2640 
2641 
2642     /* Glob with symbol patterns, if requested.
2643      */
2644     iter = list_begin( globbing->patterns[ 1 ] );
2645     end = list_end( globbing->patterns[ 1 ] );
2646 
2647     if ( iter != end ) matched = 0;
2648 
2649     for ( ; !matched && iter != end;
2650             iter = list_next( iter ) )
2651     {
2652         const char * pattern = object_str( list_item( iter ) );
2653         int match_exact = ( !has_wildcards( pattern ) );
2654 
2655         iter_symbols = list_begin( symbols );
2656         end_symbols = list_end( symbols );
2657 
2658         for ( ; !matched && iter_symbols != end_symbols;
2659                 iter_symbols = list_next( iter_symbols ) )
2660         {
2661             const char * symbol = object_str( list_item( iter_symbols ) );
2662 
2663             string_copy( buf, symbol );
2664             if ( globbing->case_insensitive )
2665                 downcase_inplace( buf->value );
2666 
2667             matched = ( match_exact ?
2668                 ( !strcmp( pattern, buf->value ) ) :
2669                 ( !glob( pattern, buf->value ) ) );
2670         }
2671     }
2672 
2673     if ( matched )
2674     {
2675         globbing->results = list_push_back( globbing->results,
2676             object_copy( member ) );
2677     }
2678 
2679     string_free( buf );
2680 
2681     PROFILE_EXIT( BUILTIN_GLOB_ARCHIVE_BACK );
2682 }
2683 
2684 
builtin_glob_archive(FRAME * frame,int flags)2685 LIST * builtin_glob_archive( FRAME * frame, int flags )
2686 {
2687     LIST * const l = lol_get( frame->args, 0 );
2688     LIST * const r1 = lol_get( frame->args, 1 );
2689     LIST * const r2 = lol_get( frame->args, 2 );
2690     LIST * const r3 = lol_get( frame->args, 3 );
2691 
2692     LISTITER iter;
2693     LISTITER end;
2694     struct globbing2 globbing;
2695 
2696     globbing.results = L0;
2697     globbing.patterns[ 0 ] = r1;
2698     globbing.patterns[ 1 ] = r3;
2699 
2700     globbing.case_insensitive =
2701 # if defined( OS_NT ) || defined( OS_CYGWIN ) || defined( OS_VMS )
2702        l;  /* Always case-insensitive. */
2703 # else
2704        r2;
2705 # endif
2706 
2707     if ( globbing.case_insensitive )
2708     {
2709         globbing.patterns[ 0 ] = downcase_list( globbing.patterns[ 0 ] );
2710         globbing.patterns[ 1 ] = downcase_list( globbing.patterns[ 1 ] );
2711     }
2712 
2713     iter = list_begin( l );
2714     end = list_end( l );
2715     for ( ; iter != end; iter = list_next( iter ) )
2716         file_archivescan( list_item( iter ), builtin_glob_archive_back, &globbing );
2717 
2718     if ( globbing.case_insensitive )
2719     {
2720         list_free( globbing.patterns[ 0 ] );
2721         list_free( globbing.patterns[ 1 ] );
2722     }
2723 
2724     return globbing.results;
2725 }
2726