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