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