Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/tools/build/jam_src/builtins.c @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

File size: 40.7 KB
Line 
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
9# include "lists.h"
10# include "parse.h"
11# include "builtins.h"
12# include "rules.h"
13# include "filesys.h"
14# include "newstr.h"
15# include "regexp.h"
16# include "frames.h"
17# include "hash.h"
18# include "strings.h"
19# include "pwd.h"
20# include "pathsys.h"
21# include "make.h"
22# include "hdrmacro.h"
23# include "compile.h"
24# include "native.h"
25# include "variable.h"
26# include <ctype.h>
27
28/*
29 * builtins.c - builtin jam rules
30 *
31 * External routines:
32 *
33 *      load_builtin() - define builtin rules
34 *
35 * Internal routines:
36 *
37 *      builtin_depends() - DEPENDS/INCLUDES rule
38 *      builtin_echo() - ECHO rule
39 *      builtin_exit() - EXIT rule
40 *      builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
41 *      builtin_glob() - GLOB rule
42 *      builtin_match() - MATCH rule
43 *
44 * 01/10/01 (seiwald) - split from compile.c
45 */
46
47/*
48 * compile_builtin() - define builtin rules
49 */
50
51# define P0 (PARSE *)0
52# define C0 (char *)0
53
54# ifdef OS_NT
55LIST* builtin_system_registry( PARSE *parse, FRAME *frame );
56# endif
57
58int glob( char *s, char *c );
59
60void lol_build( LOL* lol, char** elements );
61void backtrace( FRAME *frame );
62void backtrace_line( FRAME *frame );
63void print_source_line( PARSE* p );
64
65RULE* bind_builtin( char* name, LIST*(*f)(PARSE*, FRAME*), int flags, char** args )
66{
67    argument_list* arg_list = 0;
68   
69    if ( args )
70    {
71        arg_list = args_new();
72        lol_build( arg_list->data, args );
73    }
74
75    return new_rule_body( root_module(), name, arg_list,
76                          parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
77}
78
79RULE* duplicate_rule( char* name, RULE* other )
80{
81    return import_rule( other, root_module(), name );
82}
83
84void
85load_builtins()
86{
87    duplicate_rule( "Always" ,
88      bind_builtin( "ALWAYS" ,
89                    builtin_flags, T_FLAG_TOUCHED, 0 ) );
90
91    duplicate_rule( "Depends" ,
92      bind_builtin( "DEPENDS" ,
93                    builtin_depends, 0, 0 ) );
94
95    duplicate_rule( "echo" ,
96    duplicate_rule( "Echo" ,
97      bind_builtin( "ECHO" ,
98                    builtin_echo, 0, 0 ) ) );
99
100    duplicate_rule( "exit" ,
101    duplicate_rule( "Exit" ,
102      bind_builtin( "EXIT" ,
103                    builtin_exit, 0, 0 ) ) );
104
105    {
106        char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
107        duplicate_rule(
108            "Glob" ,
109            bind_builtin( "GLOB" , builtin_glob, 0, args )
110            );
111    }
112
113    {
114        char * args[] = { "patterns", "*", 0 };
115        bind_builtin( "GLOB-RECURSIVELY" , builtin_glob_recursive, 0, args );
116    }
117
118
119    duplicate_rule( "Includes" ,
120      bind_builtin( "INCLUDES" ,
121                    builtin_depends, 1, 0 ) );
122
123    {
124        char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
125        bind_builtin( "REBUILDS" ,
126                      builtin_rebuilds, 0, args );
127    }
128   
129    duplicate_rule( "Leaves" ,
130      bind_builtin( "LEAVES" ,
131                    builtin_flags, T_FLAG_LEAVES, 0 ) );
132
133    duplicate_rule( "Match" ,
134      bind_builtin( "MATCH" ,
135                    builtin_match, 0, 0 ) );
136
137    duplicate_rule( "NoCare" ,
138      bind_builtin( "NOCARE" ,
139                    builtin_flags, T_FLAG_NOCARE, 0 ) );
140
141    duplicate_rule( "NOTIME" ,
142    duplicate_rule( "NotFile" ,
143      bind_builtin( "NOTFILE" ,
144                    builtin_flags, T_FLAG_NOTFILE, 0 ) ) );
145
146    duplicate_rule( "NoUpdate" ,
147      bind_builtin( "NOUPDATE" ,
148                    builtin_flags, T_FLAG_NOUPDATE, 0 ) );
149
150    duplicate_rule( "Temporary" ,
151      bind_builtin( "TEMPORARY" ,
152                    builtin_flags, T_FLAG_TEMP, 0 ) );
153
154    {
155        char * args[] = { "targets", "*", 0 };
156        bind_builtin(
157            "ISFILE",
158            builtin_flags, T_FLAG_ISFILE, 0 );
159    }
160
161    duplicate_rule( "HdrMacro" ,
162      bind_builtin( "HDRMACRO" ,
163                    builtin_hdrmacro, 0, 0 ) );
164
165    /* FAIL_EXPECTED is used to indicate that the result of a target build */
166    /* action should be inverted (ok <=> fail) this can be useful when     */
167    /* performing test runs from Jamfiles..                                */
168      bind_builtin( "FAIL_EXPECTED" ,
169                    builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
170
171      bind_builtin( "RMOLD" , builtin_flags, T_FLAG_RMOLD, 0 );
172     
173      {
174          char * args[] = { "targets", "*", 0 };
175          bind_builtin( "UPDATE", builtin_update, 0, args );
176      }
177
178      {
179          char * args[] = { "string", "pattern", "replacements", "+", 0 };
180          duplicate_rule( "subst" ,
181            bind_builtin( "SUBST" ,
182                          builtin_subst, 0, args ) );
183      }
184
185      {
186          char * args[] = { "module", "?", 0 };
187          bind_builtin( "RULENAMES" ,
188                         builtin_rulenames, 0, args );
189      }
190
191
192      {
193          char * args[] = { "module", "?", 0 };
194          bind_builtin( "VARNAMES" ,
195                         builtin_varnames, 0, args );
196      }
197
198      {
199          char * args[] = { "module", "?", 0 };
200          bind_builtin( "DELETE_MODULE" ,
201                         builtin_delete_module, 0, args );
202      }
203
204      {
205           char * args[] = { "source_module", "?",
206                             ":", "source_rules", "*",
207                             ":", "target_module", "?",
208                             ":", "target_rules", "*",
209                             ":", "localize", "?", 0 };
210           bind_builtin( "IMPORT" ,
211                         builtin_import, 0, args );
212      }
213
214      {
215          char * args[] = { "module", "?", ":", "rules", "*", 0 };
216          bind_builtin( "EXPORT" ,
217                        builtin_export, 0, args );
218      }
219
220      {
221          char * args[] = { "levels", "?", 0 };
222          bind_builtin( "CALLER_MODULE" ,
223                         builtin_caller_module, 0, args );
224      }
225
226      {
227          char * args[] = { "levels", "?", 0 };
228          bind_builtin( "BACKTRACE" ,
229                        builtin_backtrace, 0, args );
230      }
231
232      {
233          char * args[] = { 0 };
234          bind_builtin( "PWD" ,
235                        builtin_pwd, 0, args );
236      }
237
238      {
239          char * args[] = { "target", "*", ":", "path", "*", 0 };
240          bind_builtin( "SEARCH_FOR_TARGET",
241                        builtin_search_for_target, 0, args );
242      }
243
244      {
245          char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
246          bind_builtin( "IMPORT_MODULE",
247                        builtin_import_module, 0, args );
248      }
249
250      {
251          char * args[] = { "module", "?", 0 };
252          bind_builtin( "IMPORTED_MODULES",
253                        builtin_imported_modules, 0, args );
254      }
255
256      {
257          char * args[] = { "instance_module", ":", "class_module", 0 };
258          bind_builtin( "INSTANCE",
259                        builtin_instance, 0, args );
260      }
261
262      {
263          char * args[] = { "sequence", "*", 0 };
264          bind_builtin( "SORT",
265                        builtin_sort, 0, args );
266      }
267
268      {
269          char * args[] = { "path", 0 };
270          bind_builtin( "NORMALIZE_PATH",
271              builtin_normalize_path, 0, args );
272      }
273
274      {
275          char * args[] = { "args", "*", 0 };
276          bind_builtin( "CALC",
277              builtin_calc, 0, args );
278      }
279
280      {
281          char * args[] = { "module", ":", "rule", 0 };
282          bind_builtin( "NATIVE_RULE",
283              builtin_native_rule, 0, args );
284      }
285
286      {
287          char * args[] = { "module", "*", 0 };
288          bind_builtin( "USER_MODULE",
289              builtin_user_module, 0, args );
290      }
291
292      {
293          char * args[] = { 0 };
294          bind_builtin( "NEAREST_USER_LOCATION",
295              builtin_nearest_user_location, 0, args );
296      }
297
298      {
299          char * args[] = { "file", 0 };
300          bind_builtin( "CHECK_IF_FILE",
301                        builtin_check_if_file, 0, args );
302      }
303
304#ifdef HAVE_PYTHON
305      {
306          char * args[] = { "python-module", ":", "function", ":", 
307                            "jam-module", ":", "rule-name", 0 };
308          bind_builtin( "PYTHON_IMPORT_RULE",
309              builtin_python_import_rule, 0, args );
310      }
311#endif
312
313# ifdef OS_NT
314      {
315          char * args[] = { "key_path", ":", "data", "?", 0 };
316          bind_builtin( "W32_GETREG",
317              builtin_system_registry, 0, args );
318      }
319# endif
320
321      {
322          char * args[] = { "command", 0 };
323          bind_builtin( "SHELL",
324              builtin_shell, 0, args );
325      }
326
327      /* Initialize builtin modules */
328      init_set();
329      init_path();
330      init_regex();
331      init_property_set();
332      init_sequence();
333      init_order();
334}
335
336/*
337* builtin_calc() - CALC rule
338*
339* The CALC rule performs simple mathematical operations on two arguments.
340*/
341
342LIST *
343builtin_calc(
344    PARSE *parse,
345    FRAME *frame )
346{
347    LIST *arg = lol_get( frame->args, 0 );
348
349    LIST *result = 0;
350    long lhs_value;
351    long rhs_value;
352    long result_value;
353    char buffer [16];
354    const char* lhs;
355    const char* op;
356    const char* rhs;
357
358    if (arg == 0) return L0;
359    lhs = arg->string;
360
361    arg = list_next( arg );
362    if (arg == 0) return L0;
363    op = arg->string;
364
365    arg = list_next( arg );
366    if (arg == 0) return L0;
367    rhs = arg->string;
368
369    lhs_value = atoi (lhs);
370    rhs_value = atoi (rhs);
371
372    if (strcmp ("+", op) == 0)
373    {
374        result_value = lhs_value + rhs_value;
375    }
376    else if (strcmp ("-", op) == 0)
377    {
378        result_value = lhs_value - rhs_value;
379    }
380    else
381    {
382        return L0;
383    }
384
385    sprintf (buffer, "%ld", result_value);
386    result = list_new( result, newstr( buffer ) );
387    return result;
388}
389
390/*
391 * builtin_depends() - DEPENDS/INCLUDES rule
392 *
393 * The DEPENDS builtin rule appends each of the listed sources on the
394 * dependency list of each of the listed targets.  It binds both the
395 * targets and sources as TARGETs.
396 */
397
398LIST *
399builtin_depends(
400        PARSE   *parse,
401        FRAME *frame )
402{
403        LIST *targets = lol_get( frame->args, 0 );
404        LIST *sources = lol_get( frame->args, 1 );
405        LIST *l;
406
407        for( l = targets; l; l = list_next( l ) )
408        {
409            TARGET *t = bindtarget( l->string );
410
411            /* If doing INCLUDES, switch to the TARGET's include */
412            /* TARGET, creating it if needed.  The internal include */
413            /* TARGET shares the name of its parent. */
414
415            if( parse->num )
416            {
417            if( !t->includes ) {
418                t->includes = copytarget( t );
419                t->includes->original_target = t;
420            }
421            t = t->includes;
422            }
423
424            t->depends = targetlist( t->depends, sources );
425        }
426
427    /* Enter reverse links */
428        for( l = sources; l; l = list_next( l ) )
429        {
430            TARGET *s = bindtarget( l->string );
431        s->dependents = targetlist( s->dependents, targets );
432    }
433
434        return L0;
435}
436
437/*
438 * builtin_rebuilds() - REBUILDS rule
439 *
440 * The REBUILDS builtin rule appends each of the listed
441 * rebuild-targets in its 2nd argument on the rebuilds list of each of
442 * the listed targets in its first argument.
443 */
444
445LIST *
446builtin_rebuilds(
447        PARSE   *parse,
448        FRAME *frame )
449{
450        LIST *targets = lol_get( frame->args, 0 );
451        LIST *rebuilds = lol_get( frame->args, 1 );
452        LIST *l;
453
454        for( l = targets; l; l = list_next( l ) )
455        {
456            TARGET *t = bindtarget( l->string );
457            t->rebuilds = targetlist( t->rebuilds, rebuilds );
458        }
459
460        return L0;
461}
462
463/*
464 * builtin_echo() - ECHO rule
465 *
466 * The ECHO builtin rule echoes the targets to the user.  No other
467 * actions are taken.
468 */
469
470LIST *
471builtin_echo(
472        PARSE   *parse,
473        FRAME *frame )
474{
475        list_print( lol_get( frame->args, 0 ) );
476        printf( "\n" );
477        return L0;
478}
479
480/*
481 * builtin_exit() - EXIT rule
482 *
483 * The EXIT builtin rule echoes the targets to the user and exits
484 * the program with a failure status.
485 */
486
487LIST *
488builtin_exit(
489        PARSE   *parse,
490        FRAME *frame )
491{
492        list_print( lol_get( frame->args, 0 ) );
493        printf( "\n" );
494        exit( EXITBAD ); /* yeech */
495        return L0;
496}
497
498/*
499 * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
500 *
501 * Builtin_flags() marks the target with the appropriate flag, for use
502 * by make0().  It binds each target as a TARGET.
503 */
504
505LIST *
506builtin_flags(
507        PARSE   *parse,
508        FRAME *frame )
509{
510        LIST *l = lol_get( frame->args, 0 );
511
512        for( ; l; l = list_next( l ) )
513            bindtarget( l->string )->flags |= parse->num;
514
515        return L0;
516}
517
518/*
519 * builtin_globbing() - GLOB rule
520 */
521
522struct globbing {
523    LIST    *patterns;
524    LIST    *results;
525    LIST    *case_insensitive;
526} ;
527
528static void downcase_inplace( char* p )
529{
530    for ( ; *p; ++p )
531    {
532        *p = tolower(*p);
533    }
534}
535   
536static void
537builtin_glob_back(
538    void    *closure,
539    char    *file,
540    int status,
541    time_t  time )
542{
543    struct globbing *globbing = (struct globbing *)closure;
544    LIST        *l;
545    PATHNAME    f;
546    string          buf[1];
547
548    /* Null out directory for matching. */
549    /* We wish we had file_dirscan() pass up a PATHNAME. */
550
551    path_parse( file, &f );
552    f.f_dir.len = 0;
553
554    /* For globbing, we unconditionally ignore current and parent
555       directory items. Since they items always exist, there's not
556       reason why caller of GLOB would want to see them.
557       We could also change file_dirscan, but then paths with embedded
558       "." and ".." won't work anywhere.
559    */
560    if (strcmp(f.f_base.ptr, ".") == 0 || strcmp(f.f_base.ptr, "..") == 0)
561        return;
562
563    string_new( buf );
564    path_build( &f, buf, 0 );
565
566    if (globbing->case_insensitive) {
567        downcase_inplace( buf->value );
568    }
569
570    for( l = globbing->patterns; l; l = l->next )
571    {
572        if( !glob( l->string, buf->value ) )
573        {
574            globbing->results = list_new( globbing->results, newstr( file ) );
575            break;
576        }
577    }
578   
579    string_free( buf );
580}
581
582static LIST* downcase_list( LIST *in )
583{
584    LIST* result = 0;
585   
586    string s[1];
587    string_new( s );
588       
589    while (in)
590    {
591        string_copy( s, in->string );
592        downcase_inplace( s->value );
593        result = list_append( result, list_new( 0, newstr( s->value ) ) );
594        in = in->next;
595    }
596   
597    string_free( s );
598    return result;
599}
600
601LIST *
602builtin_glob(
603    PARSE   *parse,
604    FRAME *frame )
605{
606    LIST *l = lol_get( frame->args, 0 );
607    LIST *r = lol_get( frame->args, 1 );
608   
609    struct globbing globbing;
610
611    globbing.results = L0;
612    globbing.patterns = r;
613   
614    globbing.case_insensitive
615# if defined( OS_NT ) || defined( OS_CYGWIN )
616       = l;  /* always case-insensitive if any files can be found */
617# else
618       = lol_get( frame->args, 2 );
619# endif
620
621    if ( globbing.case_insensitive )
622    {
623        globbing.patterns = downcase_list( r );
624    }
625   
626    for( ; l; l = list_next( l ) )
627        file_dirscan( l->string, builtin_glob_back, &globbing );
628
629    if ( globbing.case_insensitive )
630    {
631        list_free( globbing.patterns );
632    }
633    return globbing.results;
634}
635
636static int has_wildcards(const char* str)
637{
638    size_t index = strcspn(str, "[]*?");
639    if (str[index] == '\0')
640        return 0;
641    else
642        return 1;
643}
644
645/** If 'file' exists, append 'file' to 'list'.
646    Returns 'list'.
647*/
648static LIST* append_if_exists(LIST* list, char* file)
649{
650    time_t time;
651    timestamp(file, &time);
652    if (time > 0)
653        return list_new(list, newstr(file));
654    else
655        return list;       
656}
657
658LIST* glob1(char* dirname, char* pattern)
659{
660    LIST* plist = list_new(L0, pattern);
661    struct globbing globbing;
662
663    globbing.results = L0;
664    globbing.patterns = plist;
665   
666    globbing.case_insensitive
667# if defined( OS_NT ) || defined( OS_CYGWIN )
668       = plist;  /* always case-insensitive if any files can be found */
669# else
670       = L0;
671# endif
672
673    if ( globbing.case_insensitive )
674    {
675        globbing.patterns = downcase_list( plist );
676    }
677   
678    file_dirscan( dirname, builtin_glob_back, &globbing );
679
680    if ( globbing.case_insensitive )
681    {
682        list_free( globbing.patterns );
683    }
684
685    list_free(plist);
686
687    return globbing.results;
688}
689
690
691LIST* glob_recursive(char* pattern)
692{
693    LIST* result = L0;
694
695    /* Check if there's metacharacters in pattern */
696    if (!has_wildcards(pattern))
697    {
698        /* No metacharacters. Check if the path exists. */
699        result = append_if_exists(result, pattern);
700    }       
701    else
702    {
703        /* Have metacharacters in the pattern. Split into dir/name */
704        PATHNAME path[1];
705        path_parse(pattern, path);           
706       
707        if (path->f_dir.ptr)
708        {
709            LIST* dirs = L0;
710            string dirname[1];
711            string basename[1];
712            string_new(dirname);
713            string_new(basename);
714
715            string_append_range(dirname, path->f_dir.ptr, 
716                                path->f_dir.ptr + path->f_dir.len);
717
718            path->f_grist.ptr = 0;
719            path->f_grist.len = 0;
720            path->f_dir.ptr = 0;
721            path->f_dir.len = 0;
722            path_build(path, basename, 0);
723
724            if (has_wildcards(dirname->value))
725            {
726                dirs = glob_recursive(dirname->value);
727            }
728            else
729            {
730                dirs = list_new(dirs, dirname->value);
731            }
732           
733            if (has_wildcards(basename->value))
734            {
735                for(; dirs; dirs = dirs->next)
736                {
737                    result = list_append(result, 
738                                         glob1(dirs->string, basename->value));
739                }
740            }
741            else
742            {
743                string file_string[1];
744                string_new(file_string);
745
746                /** No wildcard in basename. */
747                for(; dirs; dirs = dirs->next)
748                {                                     
749                    path->f_dir.ptr = dirs->string;
750                    path->f_dir.len = strlen(dirs->string);                   
751                    path_build(path, file_string, 0);
752
753                    result = append_if_exists(result, file_string->value);
754
755                    string_truncate(file_string, 0);
756                }
757
758                string_free(file_string);
759            }
760
761            string_free(dirname);
762            string_free(basename);
763        }
764        else
765        {
766            /** No directory, just a pattern. */
767            result = list_append(result, glob1(".", pattern));
768        }
769    }
770
771    return result;
772}
773
774LIST *
775builtin_glob_recursive(
776    PARSE   *parse,
777    FRAME *frame )
778{
779    LIST* result = L0;
780    LIST* l = lol_get( frame->args, 0 );
781
782    for(; l; l = l->next)
783    {
784        result = list_append(result, glob_recursive(l->string));
785    }
786
787    return result;
788}
789
790/*
791 * builtin_match() - MATCH rule, regexp matching
792 */
793
794LIST *
795builtin_match(
796        PARSE   *parse,
797        FRAME   *frame )
798{
799        LIST *l, *r;
800        LIST *result = 0;
801       
802        string buf[1];
803        string_new(buf);
804
805        /* For each pattern */
806
807        for( l = lol_get( frame->args, 0 ); l; l = l->next )
808        {
809            /* Result is cached and intentionally never freed */
810            regexp *re = regex_compile( l->string );
811
812            /* For each string to match against */
813            for( r = lol_get( frame->args, 1 ); r; r = r->next )
814            {
815                if( regexec( re, r->string ) )
816                {
817                    int i, top;
818
819                    /* Find highest parameter */
820
821                    for( top = NSUBEXP; top-- > 1; )
822                        if( re->startp[top] )
823                            break;
824
825                    /* And add all parameters up to highest onto list. */
826                    /* Must have parameters to have results! */
827
828                    for( i = 1; i <= top; i++ )
829                    {
830                        string_append_range( buf, re->startp[i], re->endp[i] );
831                        result = list_new( result, newstr( buf->value ) );
832                        string_truncate( buf, 0 );
833                    }
834                }
835            }
836        }
837
838        string_free( buf );
839        return result;
840}
841
842LIST *
843builtin_hdrmacro(
844    PARSE    *parse,
845    FRAME *frame )
846{
847  LIST*  l = lol_get( frame->args, 0 );
848 
849  for ( ; l; l = list_next(l) )
850  {
851    TARGET*  t = bindtarget( l->string );
852
853    /* scan file for header filename macro definitions */   
854    if ( DEBUG_HEADER )
855      printf( "scanning '%s' for header file macro definitions\n",
856              l->string );
857
858    macro_headers( t );
859  }
860 
861  return L0;
862}
863
864/*  builtin_rulenames() - RULENAMES ( MODULE ? )
865 *
866 *  Returns a list of the non-local rule names in the given MODULE. If
867 *  MODULE is not supplied, returns the list of rule names in the
868 *  global module.
869 */
870
871/* helper function for builtin_rulenames(), below */
872static void add_rule_name( void* r_, void* result_ )
873{
874    RULE* r = (RULE*)r_;
875    LIST** result = (LIST**)result_;
876
877    if ( r->exported )
878        *result = list_new( *result, copystr( r->name ) );
879}
880
881LIST *
882builtin_rulenames(
883    PARSE   *parse,
884    FRAME *frame )
885{
886    LIST *arg0 = lol_get( frame->args, 0 );
887    LIST *result = L0;
888    module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
889
890    if ( source_module->rules )
891        hashenumerate( source_module->rules, add_rule_name, &result );
892    return result;
893}
894
895/*  builtin_varnames() - VARNAMES ( MODULE ? )
896 *
897 *  Returns a list of the variable names in the given MODULE. If
898 *  MODULE is not supplied, returns the list of variable names in the
899 *  global module.
900 */
901
902/* helper function for builtin_varnames(), below.  Used with
903 * hashenumerate, will prepend the key of each element to a list
904 */
905static void add_hash_key( void* np, void* result_ )
906{
907    LIST** result = (LIST**)result_;
908
909    *result = list_new( *result, copystr( *(char**)np ) );
910}
911
912LIST *
913builtin_varnames(
914    PARSE   *parse,
915    FRAME *frame )
916{
917    LIST *arg0 = lol_get( frame->args, 0 );
918    LIST *result = L0;
919    module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
920
921    if ( source_module->variables )
922        hashenumerate( source_module->variables, add_hash_key, &result );
923    return result;
924}
925
926/*
927 * builtin_delete_module() - MODULE ?
928 *
929 * Clears all rules and variables from the given module.
930 */
931LIST *
932builtin_delete_module(
933    PARSE   *parse,
934    FRAME *frame )
935{
936    LIST *arg0 = lol_get( frame->args, 0 );
937    LIST *result = L0;
938    module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
939
940    delete_module( source_module );
941    return result;
942}
943
944static void unknown_rule( FRAME *frame, char* key, char *module_name, char *rule_name )
945{
946    backtrace_line( frame->prev );
947    printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
948    backtrace( frame->prev );
949    exit(1);
950   
951}
952
953/*
954 * builtin_import() - IMPORT ( SOURCE_MODULE ? : SOURCE_RULES * : TARGET_MODULE ? : TARGET_RULES * : LOCALIZE ? )
955 *
956 * The IMPORT rule imports rules from the SOURCE_MODULE into the
957 * TARGET_MODULE as local rules. If either SOURCE_MODULE or
958 * TARGET_MODULE is not supplied, it refers to the global
959 * module. SOURCE_RULES specifies which rules from the SOURCE_MODULE
960 * to import; TARGET_RULES specifies the names to give those rules in
961 * TARGET_MODULE. If SOURCE_RULES contains a name which doesn't
962 * correspond to a rule in SOURCE_MODULE, or if it contains a
963 * different number of items than TARGET_RULES, an error is issued.
964 * if LOCALIZE is specified, the rules will be executed in
965 * TARGET_MODULE, with corresponding access to its module local
966 * variables.
967 */
968LIST *
969builtin_import(
970    PARSE *parse,
971    FRAME *frame )
972{
973    LIST *source_module_list = lol_get( frame->args, 0 );
974    LIST *source_rules = lol_get( frame->args, 1 );
975    LIST *target_module_list = lol_get( frame->args, 2 );
976    LIST *target_rules = lol_get( frame->args, 3 );
977    LIST *localize = lol_get( frame->args, 4 );
978
979    module_t* target_module = bindmodule( target_module_list ? target_module_list->string : 0 );
980    module_t* source_module = bindmodule( source_module_list ? source_module_list->string : 0 );
981   
982    LIST *source_name, *target_name;
983           
984    for ( source_name = source_rules, target_name = target_rules;
985          source_name && target_name;
986          source_name = list_next( source_name )
987          , target_name = list_next( target_name ) )
988    {
989        RULE r_, *r = &r_, *imported;
990        r_.name = source_name->string;
991               
992        if ( !source_module->rules
993             || !hashcheck( source_module->rules, (HASHDATA**)&r )
994            )
995        {
996            unknown_rule( frame, "IMPORT", source_module->name, r_.name );
997        }
998       
999        imported = import_rule( r, target_module, target_name->string );
1000        if ( localize )
1001            imported->module = target_module;
1002        imported->exported = 0; /* this rule is really part of some other module; just refer to it here, but don't let it out */
1003    }
1004   
1005    if ( source_name || target_name )
1006    {
1007        backtrace_line( frame->prev );
1008        printf( "import error: length of source and target rule name lists don't match!\n" );
1009        printf( "    source: " );
1010        list_print( source_rules );
1011        printf( "\n    target: " );
1012        list_print( target_rules );
1013        printf( "\n" );
1014        backtrace( frame->prev );
1015        exit(1);
1016    }
1017
1018    return L0;
1019}
1020
1021
1022/*
1023 * builtin_export() - EXPORT ( MODULE ? : RULES * )
1024 *
1025 * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local
1026 * (and thus exportable). If an element of RULES does not name a rule
1027 * in MODULE, an error is issued.
1028 */
1029LIST *
1030builtin_export(
1031    PARSE *parse,
1032    FRAME *frame )
1033{
1034    LIST *module_list = lol_get( frame->args, 0 );
1035    LIST *rules = lol_get( frame->args, 1 );
1036
1037    module_t* m = bindmodule( module_list ? module_list->string : 0 );
1038   
1039           
1040    for ( ; rules; rules = list_next( rules ) )
1041    {
1042        RULE r_, *r = &r_;
1043        r_.name = rules->string;
1044               
1045        if ( !m->rules || !hashcheck( m->rules, (HASHDATA**)&r ) )
1046            unknown_rule( frame, "EXPORT", m->name, r_.name );
1047       
1048        r->exported = 1;
1049    }
1050    return L0;
1051}
1052
1053/*  Retrieve the file and line number that should be indicated for a
1054 *  given procedure in debug output or an error backtrace
1055 */
1056static void get_source_line( PARSE* procedure, char** file, int* line )
1057{
1058    if ( procedure )
1059    {
1060        char* f = procedure->file;
1061        int l = procedure->line;
1062        if ( !strcmp( f, "+" ) )
1063        {
1064            f = "jambase.c";
1065            l += 3;
1066        }
1067        *file = f;
1068        *line = l;
1069    }
1070    else
1071    {
1072        *file = "(builtin)";
1073        *line = -1;
1074    }
1075}
1076
1077void print_source_line( PARSE* p )
1078{
1079    char* file;
1080    int line;
1081
1082    get_source_line( p, &file, &line );
1083    if ( line < 0 )
1084        printf( "(builtin):" );
1085    else
1086        printf( "%s:%d:", file, line);
1087}
1088
1089/* Print a single line of error backtrace for the given frame */
1090void backtrace_line( FRAME *frame )
1091{
1092    if ( frame == 0 )
1093    {
1094        printf( "(no frame):" );
1095    }
1096    else
1097    {
1098        print_source_line( frame->procedure );
1099        printf( " in %s\n", frame->rulename );
1100    }
1101}
1102
1103/*  Print the entire backtrace from the given frame to the Jambase
1104 *  which invoked it.
1105 */
1106void backtrace( FRAME *frame )
1107{
1108        if ( !frame ) return;
1109    while ( frame = frame->prev )
1110    {
1111        backtrace_line( frame );
1112    }
1113}
1114
1115/*  A Jam version of the backtrace function, taking no arguments and
1116 *  returning a list of quadruples: FILENAME LINE MODULE. RULENAME
1117 *  describing each frame. Note that the module-name is always
1118 *  followed by a period.
1119 */
1120LIST *builtin_backtrace( PARSE *parse, FRAME *frame )
1121{
1122    LIST* levels_arg = lol_get( frame->args, 0 );
1123    int levels = levels_arg ? atoi( levels_arg->string ) : ((unsigned int)(-1) >> 1) ;
1124
1125    LIST* result = L0;
1126    for(; (frame = frame->prev) && levels ; --levels )
1127    {
1128        char* file;
1129        int line;
1130        char buf[32];
1131        get_source_line( frame->procedure, &file, &line );
1132        sprintf( buf, "%d", line );
1133        result = list_new( result, newstr( file ) );
1134        result = list_new( result, newstr( buf ) );
1135        result = list_new( result, newstr( frame->module->name ) );
1136        result = list_new( result, newstr( frame->rulename ) );
1137    }
1138    return result;
1139}
1140
1141/*
1142 * builtin_caller_module() - CALLER_MODULE ( levels ? )
1143 *
1144 * If levels is not supplied, returns the name of the module of the rule which
1145 * called the one calling this one. If levels is supplied, it is interpreted as
1146 * an integer specifying a number of additional levels of call stack to traverse
1147 * in order to locate the module in question. If no such module exists,
1148 * returns the empty list. Also returns the empty list when the module in
1149 * question is the global module. This rule is needed for implementing module
1150 * import behavior.
1151 */
1152LIST *builtin_caller_module( PARSE *parse, FRAME *frame )
1153{
1154    LIST* levels_arg = lol_get( frame->args, 0 );
1155    int levels = levels_arg ? atoi( levels_arg->string ) : 0 ;
1156
1157    int i;
1158    for (i = 0; i < levels + 2 && frame->prev; ++i)
1159        frame = frame->prev;
1160
1161    if ( frame->module == root_module() )
1162    {
1163        return L0;
1164    }
1165    else
1166    {
1167        LIST* result;
1168       
1169        string name;
1170        string_copy( &name, frame->module->name );
1171        string_pop_back( &name );
1172
1173        result = list_new( L0, newstr(name.value) );
1174       
1175        string_free( &name );
1176       
1177        return result;
1178    }
1179}
1180
1181/*
1182 * Return the current working directory.
1183 *
1184 * Usage: pwd = [ PWD ] ;
1185 */
1186LIST*
1187builtin_pwd( PARSE *parse, FRAME *frame )
1188{
1189    return pwd();
1190}
1191
1192/*
1193 * Adds targets to the list of target that jam will attempt to update.
1194 */
1195LIST* 
1196builtin_update( PARSE *parse, FRAME *frame)
1197{
1198    LIST* result = list_copy( L0, targets_to_update() );
1199    LIST* arg1 = lol_get( frame->args, 0 );
1200    clear_targets_to_update();
1201    for ( ; arg1; arg1 = list_next( arg1 ) )
1202        mark_target_for_updating( newstr(arg1->string) );
1203    return result;
1204}
1205
1206LIST*
1207builtin_search_for_target( PARSE *parse, FRAME *frame )
1208{
1209    LIST* arg1 = lol_get( frame->args, 0 );
1210    LIST* arg2 = lol_get( frame->args, 1 );
1211
1212    TARGET* t = search_for_target( arg1->string, arg2 );
1213    return list_new( L0, t->name );
1214}
1215
1216LIST *builtin_import_module( PARSE *parse, FRAME *frame )
1217{
1218    LIST* arg1 = lol_get( frame->args, 0 );
1219    LIST* arg2 = lol_get( frame->args, 1 );
1220
1221    module_t* m = arg2 ? bindmodule(arg2->string) : root_module();
1222
1223    import_module(arg1, m);
1224
1225    return L0;
1226}
1227
1228
1229LIST *builtin_imported_modules( PARSE *parse, FRAME *frame )
1230{
1231    LIST *arg0 = lol_get( frame->args, 0 );
1232    module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
1233
1234    return imported_modules(source_module);
1235}
1236
1237LIST *builtin_instance( PARSE *parse, FRAME *frame )
1238{
1239    LIST* arg1 = lol_get( frame->args, 0 );
1240    LIST* arg2 = lol_get( frame->args, 1 );
1241
1242    module_t* instance = bindmodule( arg1->string );
1243    module_t* class_module = bindmodule( arg2->string );
1244    instance->class_module = class_module;
1245
1246    return L0;
1247}
1248
1249LIST*
1250builtin_sort( PARSE *parse, FRAME *frame )
1251{
1252    LIST* arg1 = lol_get( frame->args, 0 );
1253
1254    return list_sort(arg1);
1255}
1256
1257LIST *builtin_normalize_path( PARSE *parse, FRAME *frame )
1258{
1259    LIST* arg1 = lol_get( frame->args, 0 );
1260
1261    /* First, we iterate over all '/'-separated elements, starting from
1262       the end of string. If we see '..', we remove previous path elements.
1263       If we see '.', we remove it.
1264       The removal is done by putting '\1' in the string. After all the string
1265       is processed, we do a second pass, removing '\1' characters.
1266    */
1267   
1268    string in[1], out[1], tmp[1];
1269    char* end;      /* Last character of the part of string still to be processed. */
1270    char* current;  /* Working pointer. */ 
1271    int dotdots = 0; /* Number of '..' elements seen and not processed yet. */
1272    int rooted = arg1->string[0] == '/';
1273    char* result;
1274
1275    /* Make a copy of input: we should not change it. */
1276    string_new(in);
1277    if (!rooted)
1278        string_push_back(in, '/');
1279    string_append(in, arg1->string);
1280   
1281
1282    end = in->value + in->size - 1;
1283    current = end;
1284   
1285    for(;end >= in->value;) {
1286        /* Set 'current' to the next occurence of '/', which always exists. */
1287        for(current = end; *current != '/'; --current)
1288            ;
1289       
1290        if (current == end && current != in->value) {
1291            /* Found a trailing slash. Remove it. */
1292            *current = '\1';
1293        } else if (current == end && *(current+1) == '/') {
1294            /* Found duplicated slash. Remove it. */
1295            *current = '\1';
1296        } else if (end - current == 1 && strncmp(current, "/.", 2) == 0) {
1297            /* Found '/.'. Drop them all. */
1298            *current = '\1';
1299            *(current+1) = '\1';                   
1300        } else if (end - current == 2 && strncmp(current, "/..", 3) == 0) {
1301            /* Found '/..' */               
1302            *current = '\1';
1303            *(current+1) = '\1';                   
1304            *(current+2) = '\1';                   
1305            ++dotdots;
1306        } else if (dotdots) {
1307            char* p = current;
1308            memset(current, '\1', end-current+1);
1309            --dotdots;
1310        }                 
1311        end = current-1;
1312    }
1313
1314
1315    string_new(tmp);
1316    while(dotdots--)
1317        string_append(tmp, "/..");
1318    string_append(tmp, in->value);
1319    string_copy(in, tmp->value);
1320    string_free(tmp);
1321       
1322       
1323    string_new(out);
1324    /* The resulting path is either empty or has '/' as the first significant
1325       element. If the original path was not rooted, we need to drop first '/'.
1326       If the original path was rooted, and we've got empty path, need to add '/'
1327    */
1328    if (!rooted) {
1329        current = strchr(in->value, '/');
1330        if (current)
1331            *current = '\1';
1332    } 
1333       
1334    for (current = in->value; *current; ++current)
1335        if (*current != '\1')
1336            string_push_back(out, *current);
1337
1338   
1339    result = newstr(out->size ? out->value : (rooted ? "/" : "."));
1340    string_free(in);
1341    string_free(out);
1342
1343    return list_new(0, result);
1344
1345}
1346
1347LIST *builtin_native_rule( PARSE *parse, FRAME *frame )
1348{
1349    LIST* module_name = lol_get( frame->args, 0 );   
1350    LIST* rule_name = lol_get( frame->args, 1 );   
1351
1352    module_t* module = bindmodule(module_name->string);
1353
1354    native_rule_t n, *np = &n;
1355    n.name = rule_name->string;
1356    if (module->native_rules && hashcheck(module->native_rules, (HASHDATA**)&np))
1357    {
1358        new_rule_body(module, np->name, np->arguments, np->procedure, 1);
1359    }
1360    else
1361    {
1362        backtrace_line( frame->prev );
1363        printf( "error: no native rule \"%s\" defined in module \"%s\"\n", 
1364                n.name, module->name);
1365        backtrace( frame->prev );
1366        exit(1);
1367    }
1368    return L0;   
1369}
1370
1371LIST *builtin_user_module( PARSE *parse, FRAME *frame )
1372{
1373    LIST* module_name = lol_get( frame->args, 0 );   
1374    for(; module_name; module_name = module_name->next) 
1375    {
1376        module_t* m = bindmodule( module_name->string);
1377        m->user_module = 1;
1378    }
1379    return L0;
1380}
1381
1382LIST *builtin_nearest_user_location( PARSE *parse, FRAME *frame )
1383{
1384    LIST* result = 0;
1385    FRAME* nearest_user_frame = 
1386        frame->module->user_module ? frame : frame->prev_user;
1387
1388    if (nearest_user_frame)
1389    {
1390        char* file;
1391        int line;
1392        char buf[32];
1393        get_source_line( nearest_user_frame->procedure, &file, &line );
1394        sprintf( buf, "%d", line );
1395        result = list_new( result, newstr( file ) );
1396        result = list_new( result, newstr( buf ) );
1397        return result;
1398    }
1399    else
1400    {
1401        return L0;
1402    }
1403}
1404
1405LIST *builtin_check_if_file( PARSE *parse, FRAME *frame )
1406{
1407    LIST* name = lol_get( frame->args, 0 );
1408    if (file_is_file(name->string) == 1) {
1409        return list_new(0, newstr("true"));
1410    } else {
1411        return L0;
1412    }
1413}
1414
1415
1416#ifdef HAVE_PYTHON
1417
1418LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame )
1419{
1420    static int first_time = 1;
1421   char* python_module = lol_get( frame->args, 0 )->string;       
1422   char* python_function = lol_get( frame->args, 1 )->string;       
1423   char* jam_module = lol_get( frame->args, 2 )->string;       
1424   char* jam_rule = lol_get( frame->args, 3 )->string;       
1425
1426   PyObject *pName, *pModule, *pDict, *pFunc;
1427
1428   if (first_time)
1429   {
1430       /* At the first invocation, we add the value of the
1431          global EXTRA_PYTHONPATH to the sys.path Python
1432          variable.
1433       */
1434       LIST* extra = 0;
1435       module_t* outer_module = frame->module;
1436
1437       first_time = 0;
1438
1439       if ( outer_module != root_module())
1440       {
1441           exit_module( outer_module );
1442           enter_module( root_module());
1443       }
1444   
1445       extra = var_get("EXTRA_PYTHONPATH");
1446   
1447       if ( outer_module != root_module())
1448       {
1449            exit_module( root_module());
1450            enter_module( outer_module );
1451       }
1452
1453       for(; extra; extra = extra->next)
1454       {
1455           string buf[1];
1456           string_new(buf);
1457           string_append(buf, "import sys\nsys.path.append(\"");
1458           string_append(buf, extra->string);
1459           string_append(buf, "\")\n");
1460           PyRun_SimpleString(buf->value);   
1461           string_free(buf);               
1462       }       
1463   }
1464
1465
1466   pName = PyString_FromString(python_module);
1467   
1468   pModule = PyImport_Import(pName);
1469   Py_DECREF(pName);
1470
1471   if (pModule != NULL) {
1472        pDict = PyModule_GetDict(pModule);
1473        pFunc = PyDict_GetItemString(pDict, python_function);
1474
1475        if (pFunc && PyCallable_Check(pFunc)) {
1476
1477            module_t* m = bindmodule(jam_module);
1478            RULE* r = bindrule( jam_rule, m );
1479
1480            /* Make pFunc owned */
1481            Py_INCREF(pFunc);
1482
1483            r->python_function = pFunc;
1484        }
1485        else {
1486            if (PyErr_Occurred())
1487                PyErr_Print();
1488            fprintf(stderr, "Cannot find function \"%s\"\n", python_function);
1489        }
1490        Py_DECREF(pModule);
1491    }
1492    else {
1493        PyErr_Print();
1494        fprintf(stderr, "Failed to load \"%s\"\n", python_module);
1495    }
1496   return L0;
1497
1498}
1499
1500#endif
1501
1502void lol_build( LOL* lol, char** elements )
1503{
1504    LIST* l = L0;
1505    lol_init( lol );
1506   
1507    while ( elements && *elements )
1508    {
1509        if ( !strcmp( *elements, ":" ) )
1510        {
1511            lol_add( lol, l );
1512            l = L0 ;
1513        }
1514        else
1515        {
1516            l = list_new( l, newstr( *elements ) );
1517        }
1518        ++elements;
1519    }
1520   
1521    if ( l != L0 )
1522        lol_add( lol, l );
1523}
1524
1525#ifdef HAVE_PYTHON
1526
1527/** Calls the bjam rule specified by name passed in 'args'.
1528    The name is looked up in context of bjam's 'python_interface'
1529    module. Returns the list of string retured by the rule.
1530*/
1531PyObject*
1532bjam_call(PyObject* self, PyObject* args)
1533{
1534    FRAME       inner[1];
1535    LIST    *result;
1536    PARSE   *p;
1537    char*  rulename;
1538   
1539    /* Build up the list of arg lists */
1540
1541    frame_init( inner );
1542    inner->prev = 0;
1543    inner->prev_user = 0;
1544    inner->module = bindmodule("python_interface");
1545    inner->procedure = 0;
1546
1547    /* Extract the rule name and arguments from 'args' */
1548
1549    /* PyTuple_GetItem returns borrowed reference */
1550    rulename = PyString_AsString(PyTuple_GetItem(args, 0));
1551    {
1552        int i = 1;
1553        int size = PyTuple_Size(args);
1554        for( ; i < size; ++i) {
1555            PyObject* a = PyTuple_GetItem(args, i);
1556            if (PyString_Check(a))
1557            {
1558                lol_add(inner->args, 
1559                        list_new(0, newstr(PyString_AsString(a))));
1560            }
1561            else if (PySequence_Check(a))
1562            {
1563                LIST* l = 0;
1564                int s = PySequence_Size(a);
1565                int i = 0;
1566                for(; i < s; ++i)
1567                {
1568                    /* PySequence_GetItem returns new reference. */
1569                    PyObject* e = PySequence_GetItem(a, i);
1570                    l = list_new(l, newstr(PyString_AsString(e)));
1571                    Py_DECREF(e);
1572                }
1573                lol_add(inner->args, l);
1574            }               
1575        }
1576    }
1577
1578    result = evaluate_rule( rulename, inner );
1579
1580    frame_free( inner );
1581}
1582
1583/** Accepts three arguments: module name, rule name and Python callable.
1584
1585    Creates bjam rule with the specified name in the specified module,
1586    which will invoke the Python callable.
1587*/
1588PyObject*
1589bjam_import_rule(PyObject* self, PyObject* args)
1590{
1591    char* module;
1592    char* rule;
1593    PyObject* func;
1594    module_t* m;
1595    RULE* r;
1596
1597    if (!PyArg_ParseTuple(args, "ssO:import_rule", &module, &rule, &func))
1598        return NULL;
1599   
1600    if (!PyCallable_Check(func))
1601        return NULL;
1602   
1603    m = bindmodule(module);
1604    r = bindrule(rule, m);
1605
1606    /* Make pFunc owned */
1607    Py_INCREF(func);
1608
1609    r->python_function = func;
1610    return Py_None;
1611}
1612
1613#endif
1614
1615#ifdef HAVE_POPEN
1616#if defined(_MSC_VER) || defined(__BORLANDC__)
1617    #define popen _popen
1618    #define pclose _pclose
1619#endif
1620
1621LIST *builtin_shell( PARSE *parse, FRAME *frame )
1622{
1623    LIST* arg = lol_get( frame->args, 0 );
1624    LIST* result = 0; 
1625    string s;
1626    int ret;
1627    char buffer[1024];
1628    FILE *p = NULL;
1629
1630    string_new( &s );
1631
1632    fflush(NULL);
1633
1634    p = popen(arg->string, "r");
1635    if ( p == NULL )
1636        return L0;
1637
1638    while ( (ret = fread(buffer, sizeof(char), sizeof(buffer)-1, p)) > 0 )
1639    {
1640        buffer[ret+1] = 0;
1641        string_append( &s, buffer );
1642    }
1643
1644    pclose(p);
1645
1646    result = list_new( L0, newstr(s.value) );
1647    string_free(&s);
1648    return result;
1649}
1650
1651#else
1652
1653LIST *builtin_shell( PARSE *parse, FRAME *frame )
1654{
1655    return L0;
1656}
1657
1658#endif
Note: See TracBrowser for help on using the repository browser.