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