Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/jam/src/builtins.c @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

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