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