The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

builtins.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
00003  *
00004  * This file is part of Jam - see jam.c for Copyright information.
00005  */
00006 
00007 # include "jam.h"
00008 
00009 # include "lists.h"
00010 # include "parse.h"
00011 # include "builtins.h"
00012 # include "rules.h"
00013 # include "filesys.h"
00014 # include "newstr.h"
00015 # include "regexp.h"
00016 # include "frames.h"
00017 # include "hash.h"
00018 # include "strings.h"
00019 # include "pwd.h"
00020 # include "pathsys.h"
00021 # include "make.h"
00022 # include "hdrmacro.h"
00023 # include "compile.h"
00024 # include <ctype.h>
00025 
00026 /*
00027  * builtins.c - builtin jam rules
00028  *
00029  * External routines:
00030  *
00031  *      load_builtin() - define builtin rules
00032  *
00033  * Internal routines:
00034  *
00035  *      builtin_depends() - DEPENDS/INCLUDES rule
00036  *      builtin_echo() - ECHO rule
00037  *      builtin_exit() - EXIT rule
00038  *      builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
00039  *      builtin_glob() - GLOB rule
00040  *      builtin_match() - MATCH rule
00041  *
00042  * 01/10/01 (seiwald) - split from compile.c
00043  */
00044 
00045 /*
00046  * compile_builtin() - define builtin rules
00047  */
00048 
00049 # define P0 (PARSE *)0
00050 # define C0 (char *)0
00051 
00052 int glob( char *s, char *c );
00053 
00054 static void lol_build( LOL* lol, char** elements );
00055 void backtrace( FRAME *frame );
00056 void backtrace_line( FRAME *frame );
00057 void print_source_line( PARSE* p );
00058 
00059 RULE* bind_builtin( char* name, LIST*(*f)(PARSE*, FRAME*), int flags, char** args )
00060 {
00061     argument_list* arg_list = 0;
00062     
00063     if ( args )
00064     {
00065         arg_list = args_new();
00066         lol_build( arg_list->data, args );
00067     }
00068 
00069     return new_rule_body( root_module(), name, arg_list,
00070                           parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
00071 }
00072 
00073 RULE* duplicate_rule( char* name, RULE* other )
00074 {
00075     return import_rule( other, root_module(), name );
00076 }
00077 
00078 void
00079 load_builtins()
00080 {
00081     duplicate_rule( "Always" ,
00082       bind_builtin( "ALWAYS" ,
00083                     builtin_flags, T_FLAG_TOUCHED, 0 ) );
00084 
00085     duplicate_rule( "Depends" ,
00086       bind_builtin( "DEPENDS" ,
00087                     builtin_depends, 0, 0 ) );
00088 
00089     duplicate_rule( "echo" ,
00090     duplicate_rule( "Echo" ,
00091       bind_builtin( "ECHO" ,
00092                     builtin_echo, 0, 0 ) ) );
00093 
00094     duplicate_rule( "exit" ,
00095     duplicate_rule( "Exit" ,
00096       bind_builtin( "EXIT" ,
00097                     builtin_exit, 0, 0 ) ) );
00098 
00099     {
00100         char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
00101         duplicate_rule(
00102             "Glob" ,
00103             bind_builtin( "GLOB" , builtin_glob, 0, args )
00104             );
00105     }
00106 
00107     duplicate_rule( "Includes" ,
00108       bind_builtin( "INCLUDES" ,
00109                     builtin_depends, 1, 0 ) );
00110 
00111     duplicate_rule( "Leaves" ,
00112       bind_builtin( "LEAVES" ,
00113                     builtin_flags, T_FLAG_LEAVES, 0 ) );
00114 
00115     duplicate_rule( "Match" ,
00116       bind_builtin( "MATCH" ,
00117                     builtin_match, 0, 0 ) );
00118 
00119     duplicate_rule( "NoCare" ,
00120       bind_builtin( "NOCARE" ,
00121                     builtin_flags, T_FLAG_NOCARE, 0 ) );
00122 
00123     duplicate_rule( "NOTIME" ,
00124     duplicate_rule( "NotFile" ,
00125       bind_builtin( "NOTFILE" ,
00126                     builtin_flags, T_FLAG_NOTFILE, 0 ) ) );
00127 
00128     duplicate_rule( "NoUpdate" ,
00129       bind_builtin( "NOUPDATE" ,
00130                     builtin_flags, T_FLAG_NOUPDATE, 0 ) );
00131 
00132     duplicate_rule( "Temporary" ,
00133       bind_builtin( "TEMPORARY" ,
00134                     builtin_flags, T_FLAG_TEMP, 0 ) );
00135 
00136     duplicate_rule( "HdrMacro" ,
00137       bind_builtin( "HDRMACRO" ,
00138                     builtin_hdrmacro, 0, 0 ) );
00139 
00140     /* FAIL_EXPECTED is used to indicate that the result of a target build */
00141     /* action should be inverted (ok <=> fail) this can be useful when     */
00142     /* performing test runs from Jamfiles..                                */
00143       bind_builtin( "FAIL_EXPECTED" ,
00144                     builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
00145 
00146       bind_builtin( "RMOLD" , builtin_flags, T_FLAG_RMOLD, 0 );
00147       
00148       {
00149           char * args[] = { "targets", "*", 0 };
00150           bind_builtin( "UPDATE", builtin_update, 0, args );
00151       }
00152 
00153       {
00154           char * args[] = { "string", "pattern", "replacements", "+", 0 };
00155           duplicate_rule( "subst" ,
00156             bind_builtin( "SUBST" ,
00157                           builtin_subst, 0, args ) );
00158       }
00159 
00160       {
00161           char * args[] = { "module", "?", 0 };
00162           bind_builtin( "RULENAMES" ,
00163                          builtin_rulenames, 0, args );
00164       }
00165 
00166 
00167       {
00168           char * args[] = { "module", "?", 0 };
00169           bind_builtin( "VARNAMES" ,
00170                          builtin_varnames, 0, args );
00171       }
00172 
00173       {
00174           char * args[] = { "module", "?", 0 };
00175           bind_builtin( "DELETE_MODULE" ,
00176                          builtin_delete_module, 0, args );
00177       }
00178 
00179       {
00180            char * args[] = { "source_module", "?",
00181                              ":", "source_rules", "*",
00182                              ":", "target_module", "?",
00183                              ":", "target_rules", "*",
00184                              ":", "localize", "?", 0 };
00185            bind_builtin( "IMPORT" ,
00186                          builtin_import, 0, args );
00187       }
00188 
00189       {
00190           char * args[] = { "module", "?", ":", "rules", "*", 0 };
00191           bind_builtin( "EXPORT" ,
00192                         builtin_export, 0, args );
00193       }
00194 
00195       {
00196           char * args[] = { "levels", "?", 0 };
00197           bind_builtin( "CALLER_MODULE" ,
00198                          builtin_caller_module, 0, args );
00199       }
00200 
00201       {
00202           char * args[] = { "levels", "?", 0 };
00203           bind_builtin( "BACKTRACE" ,
00204                         builtin_backtrace, 0, args );
00205       }
00206 
00207       {
00208           char * args[] = { 0 };
00209           bind_builtin( "PWD" ,
00210                         builtin_pwd, 0, args );
00211       }
00212 
00213       {
00214           char * args[] = { "target", "*", ":", "path", "*", 0 };
00215           bind_builtin( "SEARCH_FOR_TARGET",
00216                         builtin_search_for_target, 0, args );
00217       }
00218 
00219       {
00220           char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
00221           bind_builtin( "IMPORT_MODULE",
00222                         builtin_import_module, 0, args );
00223       }
00224 
00225       {
00226           char * args[] = { "module", "?", 0 };
00227           bind_builtin( "IMPORTED_MODULES",
00228                         builtin_imported_modules, 0, args );
00229       }
00230 
00231       {
00232           char * args[] = { "instance_module", ":", "class_module", 0 };
00233           bind_builtin( "INSTANCE",
00234                         builtin_instance, 0, args );
00235       }
00236 
00237       {
00238           char * args[] = { "sequence", "*", 0 };
00239           bind_builtin( "SORT",
00240                         builtin_sort, 0, args );
00241       }
00242 
00243       {
00244           char * args[] = { "path", 0 };
00245           bind_builtin( "NORMALIZE_PATH",
00246               builtin_normalize_path, 0, args );
00247       }
00248 
00249       {
00250           char * args[] = { "args", "*", 0 };
00251           bind_builtin( "CALC",
00252               builtin_calc, 0, args );
00253       }
00254 }
00255 
00256 /*
00257 * builtin_calc() - CALC rule
00258 *
00259 * The CALC rule performs simple mathematical operations on two arguments.
00260 */
00261 
00262 LIST *
00263 builtin_calc(
00264     PARSE *parse,
00265     FRAME *frame )
00266 {
00267     LIST *arg = lol_get( frame->args, 0 );
00268 
00269     LIST *result = 0;
00270     long lhs_value;
00271     long rhs_value;
00272     long result_value;
00273     char buffer [16];
00274     const char* lhs;
00275     const char* op;
00276     const char* rhs;
00277 
00278     if (arg == 0) return L0;
00279     lhs = arg->string;
00280 
00281     arg = list_next( arg );
00282     if (arg == 0) return L0;
00283     op = arg->string;
00284 
00285     arg = list_next( arg );
00286     if (arg == 0) return L0;
00287     rhs = arg->string;
00288 
00289     lhs_value = atoi (lhs);
00290     rhs_value = atoi (rhs);
00291 
00292     if (strcmp ("+", op) == 0)
00293     {
00294         result_value = lhs_value + rhs_value;
00295     }
00296     else if (strcmp ("-", op) == 0)
00297     {
00298         result_value = lhs_value - rhs_value;
00299     }
00300     else
00301     {
00302         return L0;
00303     }
00304 
00305     sprintf (buffer, "%ld", result_value);
00306     result = list_new( result, newstr( buffer ) );
00307     return result;
00308 }
00309 
00310 /*
00311  * builtin_depends() - DEPENDS/INCLUDES rule
00312  *
00313  * The DEPENDS builtin rule appends each of the listed sources on the 
00314  * dependency list of each of the listed targets.  It binds both the 
00315  * targets and sources as TARGETs.
00316  */
00317 
00318 LIST *
00319 builtin_depends(
00320         PARSE   *parse,
00321         FRAME *frame )
00322 {
00323         LIST *targets = lol_get( frame->args, 0 );
00324         LIST *sources = lol_get( frame->args, 1 );
00325         int which = parse->num;
00326         LIST *l;
00327 
00328         for( l = targets; l; l = list_next( l ) )
00329         {
00330             TARGET *t = bindtarget( l->string );
00331 
00332             /* If doing INCLUDES, switch to the TARGET's include */
00333             /* TARGET, creating it if needed.  The internal include */
00334             /* TARGET shares the name of its parent. */
00335 
00336             if( parse->num )
00337             {
00338             if( !t->includes ) {
00339                 t->includes = copytarget( t );
00340                 t->includes->original_target = t;
00341             }
00342             t = t->includes;
00343             }
00344 
00345             t->depends = targetlist( t->depends, sources );
00346         }
00347 
00348         return L0;
00349 }
00350 
00351 /*
00352  * builtin_echo() - ECHO rule
00353  *
00354  * The ECHO builtin rule echoes the targets to the user.  No other 
00355  * actions are taken.
00356  */
00357 
00358 LIST *
00359 builtin_echo(
00360         PARSE   *parse,
00361         FRAME *frame )
00362 {
00363         list_print( lol_get( frame->args, 0 ) );
00364         printf( "\n" );
00365         return L0;
00366 }
00367 
00368 /*
00369  * builtin_exit() - EXIT rule
00370  *
00371  * The EXIT builtin rule echoes the targets to the user and exits
00372  * the program with a failure status.
00373  */
00374 
00375 LIST *
00376 builtin_exit(
00377         PARSE   *parse,
00378         FRAME *frame )
00379 {
00380         list_print( lol_get( frame->args, 0 ) );
00381         printf( "\n" );
00382         exit( EXITBAD ); /* yeech */
00383         return L0;
00384 }
00385 
00386 /*
00387  * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
00388  *
00389  * Builtin_flags() marks the target with the appropriate flag, for use
00390  * by make0().  It binds each target as a TARGET.
00391  */
00392 
00393 LIST *
00394 builtin_flags(
00395         PARSE   *parse,
00396         FRAME *frame )
00397 {
00398         LIST *l = lol_get( frame->args, 0 );
00399 
00400         for( ; l; l = list_next( l ) )
00401             bindtarget( l->string )->flags |= parse->num;
00402 
00403         return L0;
00404 }
00405 
00406 /*
00407  * builtin_globbing() - GLOB rule
00408  */
00409 
00410 struct globbing {
00411     LIST    *patterns;
00412     LIST    *results;
00413     LIST    *case_insensitive;
00414 } ;
00415 
00416 static void downcase_inplace( char* p )
00417 {
00418     for ( ; *p; ++p )
00419     {
00420         *p = tolower(*p);
00421     }
00422 }
00423     
00424 static void
00425 builtin_glob_back(
00426     void    *closure,
00427     char    *file,
00428     int status,
00429     time_t  time )
00430 {
00431     struct globbing *globbing = (struct globbing *)closure;
00432     LIST        *l;
00433     PATHNAME    f;
00434     string          buf[1];
00435 
00436     /* Null out directory for matching. */
00437     /* We wish we had file_dirscan() pass up a PATHNAME. */
00438 
00439     path_parse( file, &f );
00440     f.f_dir.len = 0;
00441     string_new( buf );
00442     path_build( &f, buf, 0 );
00443 
00444     if (globbing->case_insensitive)
00445         downcase_inplace( buf->value );
00446 
00447     for( l = globbing->patterns; l; l = l->next )
00448     {
00449         if( !glob( l->string, buf->value ) )
00450         {
00451             globbing->results = list_new( globbing->results, newstr( file ) );
00452             break;
00453         }
00454     }
00455     
00456     string_free( buf );
00457 }
00458 
00459 static LIST* downcase_list( LIST *in )
00460 {
00461     LIST* result = 0;
00462     
00463     string s[1];
00464     string_new( s );
00465         
00466     while (in)
00467     {
00468         string_copy( s, in->string );
00469         downcase_inplace( s->value );
00470         result = list_append( result, list_new( 0, newstr( s->value ) ) );
00471         in = in->next;
00472     }
00473     
00474     string_free( s );
00475     return result;
00476 }
00477 
00478 LIST *
00479 builtin_glob(
00480     PARSE   *parse,
00481     FRAME *frame )
00482 {
00483     LIST *l = lol_get( frame->args, 0 );
00484     LIST *r = lol_get( frame->args, 1 );
00485     
00486     struct globbing globbing;
00487 
00488     globbing.results = L0;
00489     globbing.patterns = r;
00490     
00491     globbing.case_insensitive
00492 # if defined( OS_NT ) || defined( OS_CYGWIN )
00493        = l;  /* always case-insensitive if any files can be found */
00494 # else 
00495        = lol_get( frame->args, 2 );
00496 # endif
00497 
00498     if ( globbing.case_insensitive )
00499     {
00500         globbing.patterns = downcase_list( r );
00501     }
00502     
00503     for( ; l; l = list_next( l ) )
00504         file_dirscan( l->string, builtin_glob_back, &globbing );
00505 
00506     if ( globbing.case_insensitive )
00507     {
00508         list_free( globbing.patterns );
00509     }
00510     return globbing.results;
00511 }
00512 
00513 /*
00514  * builtin_match() - MATCH rule, regexp matching
00515  */
00516 
00517 LIST *
00518 builtin_match(
00519         PARSE   *parse,
00520         FRAME   *frame )
00521 {
00522         LIST *l, *r;
00523         LIST *result = 0;
00524         
00525         string buf[1];
00526         string_new(buf);
00527 
00528         /* For each pattern */
00529 
00530         for( l = lol_get( frame->args, 0 ); l; l = l->next )
00531         {
00532             /* Result is cached and intentionally never freed */
00533             regexp *re = regex_compile( l->string );
00534 
00535             /* For each string to match against */
00536             for( r = lol_get( frame->args, 1 ); r; r = r->next )
00537             {
00538                 if( regexec( re, r->string ) )
00539                 {
00540                     int i, top;
00541 
00542                     /* Find highest parameter */
00543 
00544                     for( top = NSUBEXP; top-- > 1; )
00545                         if( re->startp[top] )
00546                             break;
00547 
00548                     /* And add all parameters up to highest onto list. */
00549                     /* Must have parameters to have results! */
00550 
00551                     for( i = 1; i <= top; i++ )
00552                     {
00553                         string_append_range( buf, re->startp[i], re->endp[i] );
00554                         result = list_new( result, newstr( buf->value ) );
00555                         string_truncate( buf, 0 );
00556                     }
00557                 }
00558             }
00559         }
00560 
00561         string_free( buf );
00562         return result;
00563 }
00564 
00565 LIST *
00566 builtin_hdrmacro(
00567     PARSE    *parse,
00568     FRAME *frame )
00569 {
00570   LIST*  l = lol_get( frame->args, 0 );
00571   
00572   for ( ; l; l = list_next(l) )
00573   {
00574     TARGET*  t = bindtarget( l->string );
00575 
00576     /* scan file for header filename macro definitions */    
00577     if ( DEBUG_HEADER )
00578       printf( "scanning '%s' for header file macro definitions\n",
00579               l->string );
00580 
00581     macro_headers( t );
00582   }
00583   
00584   return L0;
00585 }
00586 
00587 /*  builtin_rulenames() - RULENAMES ( MODULE ? )
00588  *
00589  *  Returns a list of the non-local rule names in the given MODULE. If
00590  *  MODULE is not supplied, returns the list of rule names in the
00591  *  global module.
00592  */
00593 
00594 /* helper function for builtin_rulenames(), below */
00595 static void add_rule_name( void* r_, void* result_ )
00596 {
00597     RULE* r = (RULE*)r_;
00598     LIST** result = (LIST**)result_;
00599 
00600     if ( r->exported )
00601         *result = list_new( *result, copystr( r->name ) );
00602 }
00603 
00604 LIST *
00605 builtin_rulenames(
00606     PARSE   *parse,
00607     FRAME *frame )
00608 {
00609     LIST *arg0 = lol_get( frame->args, 0 );
00610     LIST *result = L0;
00611     module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
00612 
00613     if ( source_module->rules )
00614         hashenumerate( source_module->rules, add_rule_name, &result );
00615     return result;
00616 }
00617 
00618 /*  builtin_varnames() - VARNAMES ( MODULE ? )
00619  *
00620  *  Returns a list of the variable names in the given MODULE. If
00621  *  MODULE is not supplied, returns the list of variable names in the
00622  *  global module.
00623  */
00624 
00625 /* helper function for builtin_varnames(), below.  Used with
00626  * hashenumerate, will prepend the key of each element to a list
00627  */
00628 static void add_hash_key( void* np, void* result_ )
00629 {
00630     LIST** result = (LIST**)result_;
00631 
00632     *result = list_new( *result, copystr( *(char**)np ) );
00633 }
00634 
00635 LIST *
00636 builtin_varnames(
00637     PARSE   *parse,
00638     FRAME *frame )
00639 {
00640     LIST *arg0 = lol_get( frame->args, 0 );
00641     LIST *result = L0;
00642     module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
00643 
00644     if ( source_module->variables )
00645         hashenumerate( source_module->variables, add_hash_key, &result );
00646     return result;
00647 }
00648 
00649 /*
00650  * builtin_delete_module() - MODULE ?
00651  *
00652  * Clears all rules and variables from the given module.
00653  */
00654 LIST *
00655 builtin_delete_module(
00656     PARSE   *parse,
00657     FRAME *frame )
00658 {
00659     LIST *arg0 = lol_get( frame->args, 0 );
00660     LIST *result = L0;
00661     module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
00662 
00663     delete_module( source_module );
00664     return result;
00665 }
00666 
00667 static void unknown_rule( FRAME *frame, char* key, char *module_name, char *rule_name )
00668 {
00669     backtrace_line( frame->prev );
00670     printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
00671     backtrace( frame->prev );
00672     exit(1);
00673     
00674 }
00675 
00676 /*
00677  * builtin_import() - IMPORT ( SOURCE_MODULE ? : SOURCE_RULES * : TARGET_MODULE ? : TARGET_RULES * : LOCALIZE ? )
00678  *
00679  * The IMPORT rule imports rules from the SOURCE_MODULE into the
00680  * TARGET_MODULE as local rules. If either SOURCE_MODULE or
00681  * TARGET_MODULE is not supplied, it refers to the global
00682  * module. SOURCE_RULES specifies which rules from the SOURCE_MODULE
00683  * to import; TARGET_RULES specifies the names to give those rules in
00684  * TARGET_MODULE. If SOURCE_RULES contains a name which doesn't
00685  * correspond to a rule in SOURCE_MODULE, or if it contains a
00686  * different number of items than TARGET_RULES, an error is issued.
00687  * if LOCALIZE is specified, the rules will be executed in
00688  * TARGET_MODULE, with corresponding access to its module local
00689  * variables.
00690  */
00691 LIST *
00692 builtin_import(
00693     PARSE *parse,
00694     FRAME *frame )
00695 {
00696     LIST *source_module_list = lol_get( frame->args, 0 );
00697     LIST *source_rules = lol_get( frame->args, 1 );
00698     LIST *target_module_list = lol_get( frame->args, 2 );
00699     LIST *target_rules = lol_get( frame->args, 3 );
00700     LIST *localize = lol_get( frame->args, 4 );
00701 
00702     module_t* target_module = bindmodule( target_module_list ? target_module_list->string : 0 );
00703     module_t* source_module = bindmodule( source_module_list ? source_module_list->string : 0 );
00704     
00705     LIST *source_name, *target_name;
00706             
00707     for ( source_name = source_rules, target_name = target_rules;
00708           source_name && target_name;
00709           source_name = list_next( source_name )
00710           , target_name = list_next( target_name ) )
00711     {
00712         RULE r_, *r = &r_, *imported;
00713         r_.name = source_name->string;
00714                 
00715         if ( !source_module->rules
00716              || !hashcheck( source_module->rules, (HASHDATA**)&r )
00717             )
00718         {
00719             unknown_rule( frame, "IMPORT", source_module->name, r_.name );
00720         }
00721         
00722         imported = import_rule( r, target_module, target_name->string );
00723         if ( localize )
00724             imported->module = target_module;
00725         imported->exported = 0; /* this rule is really part of some other module; just refer to it here, but don't let it out */
00726     }
00727     
00728     if ( source_name || target_name )
00729     {
00730         backtrace_line( frame->prev );
00731         printf( "import error: length of source and target rule name lists don't match!\n" );
00732         printf( "    source: " );
00733         list_print( source_rules );
00734         printf( "\n    target: " );
00735         list_print( target_rules );
00736         printf( "\n" );
00737         backtrace( frame->prev );
00738         exit(1);
00739     }
00740 
00741     return L0;
00742 }
00743 
00744 
00745 /*
00746  * builtin_export() - EXPORT ( MODULE ? : RULES * )
00747  *
00748  * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local
00749  * (and thus exportable). If an element of RULES does not name a rule
00750  * in MODULE, an error is issued.
00751  */
00752 LIST *
00753 builtin_export(
00754     PARSE *parse,
00755     FRAME *frame )
00756 {
00757     LIST *module_list = lol_get( frame->args, 0 );
00758     LIST *rules = lol_get( frame->args, 1 );
00759 
00760     module_t* m = bindmodule( module_list ? module_list->string : 0 );
00761     
00762             
00763     for ( ; rules; rules = list_next( rules ) )
00764     {
00765         RULE r_, *r = &r_;
00766         r_.name = rules->string;
00767                 
00768         if ( !m->rules || !hashcheck( m->rules, (HASHDATA**)&r ) )
00769             unknown_rule( frame, "EXPORT", m->name, r_.name );
00770         
00771         r->exported = 1;
00772     }
00773     return L0;
00774 }
00775 
00776 /*  Retrieve the file and line number that should be indicated for a
00777  *  given procedure in debug output or an error backtrace
00778  */
00779 static void get_source_line( PARSE* procedure, char** file, int* line )
00780 {
00781     if ( procedure )
00782     {
00783         char* f = procedure->file;
00784         int l = procedure->line;
00785         if ( !strcmp( f, "+" ) )
00786         {
00787             f = "jambase.c";
00788             l += 3;
00789         }
00790         *file = f;
00791         *line = l;
00792     }
00793     else
00794     {
00795         *file = "(builtin)";
00796         *line = -1;
00797     }
00798 }
00799 
00800 void print_source_line( PARSE* p )
00801 {
00802     char* file;
00803     int line;
00804 
00805     get_source_line( p, &file, &line );
00806     if ( line < 0 )
00807         printf( "(builtin):" );
00808     else
00809         printf( "%s:%d:", file, line);
00810 }
00811 
00812 /* Print a single line of error backtrace for the given frame */
00813 void backtrace_line( FRAME *frame )
00814 {
00815     if ( frame == 0 )
00816     {
00817         printf( "(no frame):" );
00818     }
00819     else
00820     {
00821         print_source_line( frame->procedure );
00822         printf( " in %s\n", frame->rulename );
00823     }
00824 }
00825 
00826 /*  Print the entire backtrace from the given frame to the Jambase
00827  *  which invoked it.
00828  */
00829 void backtrace( FRAME *frame )
00830 {
00831         if ( !frame ) return;
00832     while ( frame = frame->prev )
00833     {
00834         backtrace_line( frame );
00835     }
00836 }
00837 
00838 /*  A Jam version of the backtrace function, taking no arguments and
00839  *  returning a list of quadruples: FILENAME LINE MODULE. RULENAME
00840  *  describing each frame. Note that the module-name is always
00841  *  followed by a period.
00842  */
00843 LIST *builtin_backtrace( PARSE *parse, FRAME *frame )
00844 {
00845     LIST* levels_arg = lol_get( frame->args, 0 );
00846     int levels = levels_arg ? atoi( levels_arg->string ) : ((unsigned int)(-1) >> 1) ;
00847 
00848     LIST* result = L0;
00849     for(; (frame = frame->prev) && levels ; --levels )
00850     {
00851         char* file;
00852         int line;
00853         char buf[32];
00854         get_source_line( frame->procedure, &file, &line );
00855         sprintf( buf, "%d", line );
00856         result = list_new( result, newstr( file ) );
00857         result = list_new( result, newstr( buf ) );
00858         result = list_new( result, newstr( frame->module->name ) );
00859         result = list_new( result, newstr( frame->rulename ) );
00860     }
00861     return result;
00862 }
00863 
00864 /*
00865  * builtin_caller_module() - CALLER_MODULE ( levels ? )
00866  *
00867  * If levels is not supplied, returns the name of the module of the rule which
00868  * called the one calling this one. If levels is supplied, it is interpreted as
00869  * an integer specifying a number of additional levels of call stack to traverse
00870  * in order to locate the module in question. If no such module exists,
00871  * returns the empty list. Also returns the empty list when the module in
00872  * question is the global module. This rule is needed for implementing module
00873  * import behavior.
00874  */
00875 LIST *builtin_caller_module( PARSE *parse, FRAME *frame )
00876 {
00877     LIST* levels_arg = lol_get( frame->args, 0 );
00878     int levels = levels_arg ? atoi( levels_arg->string ) : 0 ;
00879 
00880     int i;
00881     for (i = 0; i < levels + 2 && frame->prev; ++i)
00882         frame = frame->prev;
00883 
00884     if ( frame->module == root_module() )
00885     {
00886         return L0;
00887     }
00888     else
00889     {
00890         LIST* result;
00891         
00892         string name;
00893         string_copy( &name, frame->module->name );
00894         string_pop_back( &name );
00895 
00896         result = list_new( L0, newstr(name.value) );
00897         
00898         string_free( &name );
00899         
00900         return result;
00901     }
00902 }
00903 
00904 /*
00905  * Return the current working directory.
00906  *
00907  * Usage: pwd = [ PWD ] ;
00908  */
00909 LIST*
00910 builtin_pwd( PARSE *parse, FRAME *frame )
00911 {
00912     return pwd();
00913 }
00914 
00915 /*
00916  * Adds targets to the list of target that jam will attempt to update.
00917  */
00918 LIST* 
00919 builtin_update( PARSE *parse, FRAME *frame)
00920 {
00921     LIST* result = list_copy( L0, targets_to_update() );
00922     LIST* arg1 = lol_get( frame->args, 0 );
00923     clear_targets_to_update();
00924     for ( ; arg1; arg1 = list_next( arg1 ) )
00925         mark_target_for_updating( newstr(arg1->string) );
00926     return result;
00927 }
00928 
00929 LIST*
00930 builtin_search_for_target( PARSE *parse, FRAME *frame )
00931 {
00932     LIST* arg1 = lol_get( frame->args, 0 );
00933     LIST* arg2 = lol_get( frame->args, 1 );
00934 
00935     TARGET* t = search_for_target( arg1->string, arg2 );
00936     return list_new( L0, t->name );
00937 }
00938 
00939 LIST *builtin_import_module( PARSE *parse, FRAME *frame )
00940 {
00941     LIST* arg1 = lol_get( frame->args, 0 );
00942     LIST* arg2 = lol_get( frame->args, 1 );
00943 
00944     module_t* m = arg2 ? bindmodule(arg2->string) : root_module();
00945 
00946     import_module(arg1, m);
00947 
00948     return L0;
00949 }
00950 
00951 
00952 LIST *builtin_imported_modules( PARSE *parse, FRAME *frame )
00953 {
00954     LIST *arg0 = lol_get( frame->args, 0 );
00955     module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
00956 
00957     return imported_modules(source_module);
00958 }
00959 
00960 LIST *builtin_instance( PARSE *parse, FRAME *frame )
00961 {
00962     LIST* arg1 = lol_get( frame->args, 0 );
00963     LIST* arg2 = lol_get( frame->args, 1 );
00964 
00965     module_t* instance = bindmodule( arg1->string );
00966     module_t* class_module = bindmodule( arg2->string );
00967     instance->class_module = class_module;
00968 
00969     return L0;
00970 }
00971 
00972 LIST*
00973 builtin_sort( PARSE *parse, FRAME *frame )
00974 {
00975     LIST* arg1 = lol_get( frame->args, 0 );
00976 
00977     return list_sort(arg1);
00978 }
00979 
00980 LIST *builtin_normalize_path( PARSE *parse, FRAME *frame )
00981 {
00982     LIST* arg1 = lol_get( frame->args, 0 );
00983 
00984     /* First, we iterate over all '/'-separated elements, starting from
00985        the end of string. If we see '..', we remove previous path elements.
00986        If we see '.', we remove it.
00987        The removal is done by putting '\1' in the string. After all the string
00988        is processed, we do a second pass, removing '\1' characters.
00989     */
00990     
00991     string in[1], out[1], tmp[1];
00992     char* end;      /* Last character of the part of string still to be processed. */
00993     char* current;  /* Working pointer. */  
00994     int dotdots = 0; /* Number of '..' elements seen and not processed yet. */
00995     int rooted = arg1->string[0] == '/';
00996     char* result;
00997 
00998     /* Make a copy of input: we should not change it. */
00999     string_new(in);
01000     if (!rooted)
01001         string_push_back(in, '/');
01002     string_append(in, arg1->string);
01003     
01004 
01005     end = in->value + in->size - 1;
01006     current = end;
01007     
01008     for(;end >= in->value;) {
01009         /* Set 'current' to the next occurence of '/', which always exists. */
01010         for(current = end; *current != '/'; --current)
01011             ;
01012         
01013         if (current == end && current != in->value) {
01014             /* Found a trailing slash. Remove it. */
01015             *current = '\1';
01016         } else if (current == end && *(current+1) == '/') {
01017             /* Found duplicated slash. Remove it. */
01018             *current = '\1';
01019         } else if (end - current == 1 && strncmp(current, "/.", 2) == 0) {
01020             /* Found '/.'. Drop them all. */
01021             *current = '\1';
01022             *(current+1) = '\1';                   
01023         } else if (end - current == 2 && strncmp(current, "/..", 3) == 0) {
01024             /* Found '/..' */                
01025             *current = '\1';
01026             *(current+1) = '\1';                   
01027             *(current+2) = '\1';                   
01028             ++dotdots;
01029         } else if (dotdots) {
01030             char* p = current;
01031             memset(current, '\1', end-current+1);
01032             --dotdots;
01033         }                 
01034         end = current-1;
01035     }
01036 
01037 
01038     string_new(tmp);
01039     while(dotdots--)
01040         string_append(tmp, "/..");
01041     string_append(tmp, in->value);
01042     string_copy(in, tmp->value);
01043     string_free(tmp);
01044         
01045        
01046     string_new(out);
01047     /* The resulting path is either empty or has '/' as the first significant
01048        element. If the original path was not rooted, we need to drop first '/'. 
01049        If the original path was rooted, and we've got empty path, need to add '/'
01050     */
01051     if (!rooted) {
01052         current = strchr(in->value, '/');
01053         if (current)
01054             *current = '\1';
01055     } 
01056        
01057     for (current = in->value; *current; ++current)
01058         if (*current != '\1')
01059             string_push_back(out, *current);
01060 
01061     
01062     result = newstr(out->size ? out->value : (rooted ? "/" : "."));
01063     string_free(in);
01064     string_free(out);
01065 
01066     return list_new(0, result);
01067 
01068 }
01069 
01070 
01071 
01072 static void lol_build( LOL* lol, char** elements )
01073 {
01074     LIST* l = L0;
01075     lol_init( lol );
01076     
01077     while ( elements && *elements )
01078     {
01079         if ( !strcmp( *elements, ":" ) )
01080         {
01081             lol_add( lol, l );
01082             l = L0 ;
01083         }
01084         else
01085         {
01086             l = list_new( l, newstr( *elements ) );
01087         }
01088         ++elements;
01089     }
01090     
01091     if ( l != L0 )
01092         lol_add( lol, l );
01093 }
01094 

Generated on Mon Nov 8 17:07:31 2004 for MPT by  doxygen 1.3.9.1