Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added boost

File size: 17.5 KB
Line 
1/*
2 * Copyright 1993, 1995 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7# include "jam.h"
8# include "lists.h"
9# include "parse.h"
10# include "variable.h"
11# include "rules.h"
12# include "newstr.h"
13# include "hash.h"
14# include "modules.h"
15# include "search.h"
16# include "lists.h"
17# include "pathsys.h"
18# include "timestamp.h"
19
20/*  This file is ALSO:
21 *  Copyright 2001-2004 David Abrahams.
22 *  Distributed under the Boost Software License, Version 1.0.
23 *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
24 */
25
26/*
27 * rules.c - access to RULEs, TARGETs, and ACTIONs
28 *
29 * External routines:
30 *
31 *    bindrule() - return pointer to RULE, creating it if necessary
32 *    bindtarget() - return pointer to TARGET, creating it if necessary
33 *    touchtarget() - mark a target to simulate being new
34 *    targetlist() - turn list of target names into a TARGET chain
35 *    targetentry() - add a TARGET to a chain of TARGETS
36 *    actionlist() - append to an ACTION chain
37 *    addsettings() - add a deferred "set" command to a target
38#ifndef OPT_FIX_TARGET_VARIABLES_EXT
39 *    usesettings() - set all target specific variables
40#endif
41 *    pushsettings() - set all target specific variables
42 *    popsettings() - reset target specific variables to their pre-push values
43 *    freesettings() - delete a settings list
44 *    donerules() - free RULE and TARGET tables
45 *
46 * 04/12/94 (seiwald) - actionlist() now just appends a single action.
47 * 08/23/94 (seiwald) - Support for '+=' (append to variable)
48 */
49
50static void set_rule_actions( RULE* rule, rule_actions* actions );
51static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure );
52static struct hash *targethash = 0;
53
54typedef struct _located_target LOCATED_TARGET ;
55
56struct _located_target {
57    char* file_name;
58    TARGET* target;
59};
60static struct hash *located_targets = 0;
61
62
63
64
65/*
66 * enter_rule() - return pointer to RULE, creating it if necessary in
67 * target_module.
68 */
69static RULE *
70enter_rule( char *rulename, module_t *target_module )
71{
72    RULE rule, *r = &rule;
73
74    r->name = rulename;
75
76    if ( hashenter( demand_rules( target_module ), (HASHDATA **)&r ) )
77    {
78        r->name = newstr( rulename );   /* never freed */
79        r->procedure = (PARSE *)0;
80        r->module = 0;
81        r->actions = 0;
82        r->arguments = 0;
83        r->exported = 0;
84        r->module = target_module;
85#ifdef HAVE_PYTHON
86        r->python_function = 0;
87#endif
88    }
89    return r;
90}
91
92/*
93 * define_rule() - return pointer to RULE, creating it if necessary in
94 * target_module. Prepare it to accept a body or action originating in
95 * src_module.
96 */
97static RULE *
98define_rule( module_t *src_module, char *rulename, module_t *target_module )
99{
100    RULE *r = enter_rule( rulename, target_module );
101
102    if ( r->module != src_module ) /* if the rule was imported from elsewhere, clear it now */
103    {
104        set_rule_body( r, 0, 0 ); 
105        set_rule_actions( r, 0 );
106        r->module = src_module; /* r will be executed in the source module */
107    }
108
109    return r;
110}
111
112void
113rule_free( RULE* r )
114{
115    freestr( r->name );
116    r->name = "";
117    parse_free( r->procedure );
118    r->procedure = 0;
119        if ( r->arguments )
120            args_free( r->arguments );
121    r->arguments = 0;
122    if ( r->actions )
123                actions_free( r->actions );
124    r->actions = 0;
125}
126
127/*
128 * bindtarget() - return pointer to TARGET, creating it if necessary
129 */
130
131TARGET *
132bindtarget( const char *targetname )
133{
134        TARGET target, *t = ⌖
135
136        if( !targethash )
137            targethash = hashinit( sizeof( TARGET ), "targets" );
138
139    /* Perforce added const everywhere. No time to merge that change. */
140        t->name = (char*)targetname;
141
142        if( hashenter( targethash, (HASHDATA **)&t ) )
143        {
144            memset( (char *)t, '\0', sizeof( *t ) );
145            t->name = newstr( (char*)targetname );      /* never freed */
146            t->boundname = t->name;             /* default for T_FLAG_NOTFILE */
147        }
148
149        return t;
150}
151
152
153static void bind_explicitly_located_target(void* xtarget, void* data)
154{
155    TARGET* t = (TARGET*)xtarget;
156    if (! (t->flags & T_FLAG_NOTFILE) )
157    {
158        /* Check if there's a setting for LOCATE */
159        SETTINGS* s = t->settings;
160        for(; s ; s = s->next)
161        {           
162            if (strcmp(s->symbol, "LOCATE") == 0) 
163            {
164                pushsettings(t->settings);
165                /* We're binding a target with explicit LOCATE. So
166                   third argument is of now use: nothing will be returned
167                   through it. */
168                t->boundname = search( t->name, &t->time, 0 );
169                popsettings(t->settings);
170                break;
171            }
172        }
173    }
174}
175
176void bind_explicitly_located_targets()
177{
178    if (targethash)
179        hashenumerate(targethash, bind_explicitly_located_target, (void*)0);
180}
181
182/* TODO: this is probably not a good idea to use functions in other modules like
183  that. */
184void call_bind_rule(char* target, char* boundname);
185
186TARGET* search_for_target ( char * name, LIST* search_path )
187{
188    PATHNAME f[1];
189    string buf[1];
190    LOCATED_TARGET lt, *lta = <
191    time_t time;
192    int found = 0;
193    TARGET* result;
194
195    string_new( buf );
196
197        path_parse( name, f );
198
199    f->f_grist.ptr = 0;
200    f->f_grist.len = 0;
201
202    while( search_path )
203    {
204        f->f_root.ptr = search_path->string;
205        f->f_root.len = strlen( search_path->string );
206
207        string_truncate( buf, 0 );
208        path_build( f, buf, 1 );
209
210        lt.file_name = buf->value ;
211
212        if (! located_targets )
213            located_targets = hashinit( sizeof(LOCATED_TARGET),
214                                        "located targets" );
215
216
217        if ( hashcheck( located_targets, (HASHDATA **)&lta ) )
218        {
219            return lta->target;
220        }
221
222        timestamp( buf->value, &time );
223        if (time)
224        {
225            found = 1;
226            break;
227        }
228
229        search_path = list_next( search_path );
230    }
231
232    if ( ! found )
233    {
234        f->f_root.ptr = 0;
235        f->f_root.len = 0;
236
237        string_truncate( buf, 0 );
238        path_build( f, buf, 1 );
239
240        timestamp( buf->value, &time );       
241    }
242
243    result = bindtarget( name );
244    result->boundname = newstr( buf->value );
245    result->time = time;
246    result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
247
248    call_bind_rule( result->name, result->boundname );
249   
250    string_free( buf );
251
252    return result;
253
254}
255
256/*
257 * copytarget() - make a new target with the old target's name
258 *
259 * Not entered into hash table -- for internal nodes.
260 */
261
262TARGET *
263copytarget( const TARGET *ot )
264{
265        TARGET *t;
266
267        t = (TARGET *)malloc( sizeof( *t ) );
268        memset( (char *)t, '\0', sizeof( *t ) );
269        t->name = copystr( ot->name );
270        t->boundname = t->name;
271
272        t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
273
274        return t;
275}
276
277/*
278 * touchtarget() - mark a target to simulate being new
279 */
280
281void
282touchtarget( char *t )
283{
284        bindtarget( t )->flags |= T_FLAG_TOUCHED;
285}
286
287/*
288 * targetlist() - turn list of target names into a TARGET chain
289 *
290 * Inputs:
291 *      chain   existing TARGETS to append to
292 *      targets list of target names
293 */
294
295TARGETS *
296targetlist( 
297        TARGETS *chain,
298        LIST    *targets )
299{
300        for( ; targets; targets = list_next( targets ) )
301            chain = targetentry( chain, bindtarget( targets->string ) );
302
303        return chain;
304}
305
306/*
307 * targetentry() - add a TARGET to a chain of TARGETS
308 *
309 * Inputs:
310 *      chain   exisitng TARGETS to append to
311 *      target  new target to append
312 */
313
314TARGETS *
315targetentry( 
316        TARGETS *chain,
317        TARGET  *target )
318{
319        TARGETS *c;
320
321        c = (TARGETS *)malloc( sizeof( TARGETS ) );
322        c->target = target;
323
324        if( !chain ) chain = c;
325        else chain->tail->next = c;
326        chain->tail = c;
327        c->next = 0;
328
329        return chain;
330}
331
332/*
333 * targetchain() - append two TARGET chains
334 *
335 * Inputs:
336 *      chain   exisitng TARGETS to append to
337 *      target  new target to append
338 */
339
340TARGETS *
341targetchain( 
342        TARGETS *chain,
343        TARGETS *targets )
344{
345        TARGETS *c;
346
347        if( !targets )
348            return chain;
349        else if( !chain )
350            return targets;
351
352        chain->tail->next = targets;
353        chain->tail = targets->tail;
354
355        return chain;
356}
357
358/*
359 * actionlist() - append to an ACTION chain
360 */
361
362ACTIONS *
363actionlist(
364        ACTIONS *chain,
365        ACTION  *action )
366{
367        ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) );
368
369        actions->action = action;
370
371        if( !chain ) chain = actions;
372        else chain->tail->next = actions;
373        chain->tail = actions;
374        actions->next = 0;
375
376        return chain;
377}
378
379static SETTINGS* settings_freelist;
380
381/*
382 * addsettings() - add a deferred "set" command to a target
383 *
384 * Adds a variable setting (varname=list) onto a chain of settings
385 * for a particular target.  Replaces the previous previous value,
386 * if any, unless 'append' says to append the new list onto the old.
387 * Returns the head of the chain of settings.
388 */
389
390SETTINGS *
391addsettings(
392        SETTINGS *head,
393        int     append,
394        char    *symbol,
395        LIST    *value )
396{
397        SETTINGS *v;
398       
399        /* Look for previous setting */
400
401        for( v = head; v; v = v->next )
402            if( !strcmp( v->symbol, symbol ) )
403                break;
404
405        /* If not previously set, alloc a new. */
406        /* If appending, do so. */
407        /* Else free old and set new. */
408
409        if( !v )
410        {
411        v = settings_freelist;
412       
413        if ( v )
414            settings_freelist = v->next;
415        else
416            v = (SETTINGS *)malloc( sizeof( *v ) );
417       
418            v->symbol = newstr( symbol );
419            v->value = value;
420            v->next = head;
421            head = v;
422        }
423        else if( append )
424        {
425            v->value = list_append( v->value, value );
426        }
427        else
428        {
429            list_free( v->value );
430            v->value = value;
431        } 
432
433        /* Return (new) head of list. */
434
435        return head;
436}
437
438/*
439 * pushsettings() - set all target specific variables
440 */
441
442void
443pushsettings( SETTINGS *v )
444{
445        for( ; v; v = v->next )
446            v->value = var_swap( v->symbol, v->value );
447}
448
449/*
450 * popsettings() - reset target specific variables to their pre-push values
451 */
452
453void
454popsettings( SETTINGS *v )
455{
456        pushsettings( v );      /* just swap again */
457}
458
459/*
460 * copysettings() - duplicate a settings list, returning the new copy
461 */
462SETTINGS*
463copysettings( SETTINGS *head )
464{
465    SETTINGS *copy = 0, *v;
466
467    for (v = head; v; v = v->next)
468        copy = addsettings(copy, 0, v->symbol, list_copy(0, v->value));
469
470    return copy;
471}
472
473/*
474 *    freetargets() - delete a targets list
475 */
476void freetargets( TARGETS *chain )
477{
478    while( chain )
479    {
480        TARGETS* n = chain->next;
481        free( chain );
482        chain = n;
483    }
484}
485
486/*
487 *    freeactions() - delete an action list
488 */
489void freeactions( ACTIONS *chain )
490{
491    while( chain )
492    {
493        ACTIONS* n = chain->next;
494        free( chain );
495        chain = n;
496    }
497}
498
499
500/*
501 *    freesettings() - delete a settings list
502 */
503
504void
505freesettings( SETTINGS *v )
506{
507        while( v )
508        {
509            SETTINGS *n = v->next;
510
511            freestr( v->symbol );
512            list_free( v->value );
513        v->next = settings_freelist;
514        settings_freelist = v;
515
516            v = n;
517        }
518}
519
520static void freetarget( void *xt, void *data )
521{
522    TARGET* t = (TARGET *)xt;
523    if ( t->settings )
524        freesettings( t->settings );
525    if ( t->depends )
526        freetargets( t->depends );
527    if ( t->includes )
528        freetarget( t->includes, (void*)0);
529    if ( t->actions )
530        freeactions( t->actions );
531}
532
533/*
534 * donerules() - free TARGET tables
535 */
536
537void
538donerules()
539{
540     hashenumerate( targethash, freetarget, 0 );
541        hashdone( targethash );
542    while ( settings_freelist )
543    {
544        SETTINGS* n = settings_freelist->next;
545        free( settings_freelist );
546        settings_freelist = n;
547    }
548}
549
550/*
551 * args_new() - make a new reference-counted argument list
552 */
553argument_list* args_new()
554{
555    argument_list* r = (argument_list*)malloc( sizeof(argument_list) );
556    r->reference_count = 0;
557    lol_init(r->data);
558    return r;
559}
560
561/*
562 * args_refer() - add a new reference to the given argument list
563 */
564void args_refer( argument_list* a )
565{
566    ++a->reference_count;
567}
568
569/*
570 * args_free() - release a reference to the given argument list
571 */
572void args_free( argument_list* a )
573{
574    if (--a->reference_count <= 0)
575    {
576        lol_free(a->data);
577        free(a);
578    }
579}
580
581/*
582 * actions_refer() - add a new reference to the given actions
583 */
584void actions_refer(rule_actions* a)
585{
586    ++a->reference_count;
587}
588
589/*
590 * actions_free() - release a reference to the given actions
591 */
592void actions_free(rule_actions* a)
593{
594    if (--a->reference_count <= 0)
595    {
596        freestr(a->command);
597        list_free(a->bindlist);
598        free(a);
599    }
600}
601
602/*
603 * set_rule_body() - set the argument list and procedure of the given rule
604 */
605static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure )
606{
607    if ( args )
608        args_refer( args );
609    if ( rule->arguments )
610        args_free( rule->arguments );
611    rule->arguments = args;
612   
613    if ( procedure )
614        parse_refer( procedure );
615    if ( rule->procedure )
616        parse_free( rule->procedure );
617    rule->procedure = procedure;
618}
619
620/*
621 * global_name() - given a rule, return the name for a corresponding rule in the global module
622 */
623static char* global_rule_name( RULE* r )
624{
625    if ( r->module == root_module() )
626    {
627        return r->name;
628    }
629    else
630    {
631        char name[4096] = "";
632        strncat(name, r->module->name, sizeof(name) - 1);
633        strncat(name, r->name, sizeof(name) - 1 );
634        return newstr(name);
635    }
636}
637
638/*
639 * global_rule() - given a rule, produce the corresponding entry in the global module
640 */
641static RULE* global_rule( RULE* r )
642{
643    if ( r->module == root_module() )
644    {
645        return r;
646    }
647    else
648    {
649        char* name = global_rule_name( r );
650        RULE* result = define_rule( r->module, name, root_module() );
651        freestr(name);
652        return result;
653    }
654}
655
656/*
657 * new_rule_body() - make a new rule named rulename in the given
658 * module, with the given argument list and procedure. If exported is
659 * true, the rule is exported to the global module as
660 * modulename.rulename.
661 */
662RULE* new_rule_body( module_t* m, char* rulename, argument_list* args, PARSE* procedure, int exported )
663{
664    RULE* local = define_rule( m, rulename, m );
665    local->exported = exported;
666    set_rule_body( local, args, procedure );
667   
668    /* Mark the procedure with the global rule name, regardless of
669     * whether the rule is exported. That gives us something
670     * reasonably identifiable that we can use, e.g. in profiling
671     * output. Only do this once, since this could be called multiple
672     * times with the same procedure.
673     */
674    if ( procedure->rulename == 0 )
675        procedure->rulename = global_rule_name( local );
676
677    return local;
678}
679
680static void set_rule_actions( RULE* rule, rule_actions* actions )
681{
682    if ( actions )
683        actions_refer( actions );
684    if ( rule->actions )
685        actions_free( rule->actions );
686    rule->actions = actions;
687   
688}
689
690static rule_actions* actions_new( char* command, LIST* bindlist, int flags )
691{
692    rule_actions* result = (rule_actions*)malloc(sizeof(rule_actions));
693    result->command = copystr( command );
694    result->bindlist = bindlist;
695    result->flags = flags;
696    result->reference_count = 0;
697    return result;
698}
699
700RULE* new_rule_actions( module_t* m, char* rulename, char* command, LIST* bindlist, int flags )
701{
702    RULE* local = define_rule( m, rulename, m );
703    RULE* global = global_rule( local );
704    set_rule_actions( local, actions_new( command, bindlist, flags ) );
705    set_rule_actions( global, local->actions );
706    return local;
707}
708
709/* Looks for a rule in the specified module, and returns it, if found.
710   First checks if the rule is present in the module's rule table.
711   Second, if name of the rule is in the form name1.name2 and name1 is in
712   the list of imported modules, look in module 'name1' for rule 'name2'.
713*/
714RULE *lookup_rule( char *rulename, module_t *m, int local_only )
715{
716    RULE rule, *r = &rule, *result = 0;
717    module_t* original_module = m;
718    r->name = rulename;
719
720    if (m->class_module)
721        m = m->class_module;
722
723    if (m->rules && hashcheck( m->rules, (HASHDATA **)&r ) )
724        result = r;
725    else if (!local_only && m->imported_modules) {
726        /* Try splitting the name into module and rule. */
727        char *p = strchr(r->name, '.') ;
728        if (p) {
729            *p = '\0';
730            /* Now, r->name keeps the module name, and p+1 keeps the rule name. */
731            if (hashcheck( m->imported_modules, (HASHDATA **)&r))
732            {
733                result = lookup_rule(p+1, bindmodule(rulename), 1);
734            }
735            *p = '.';
736        }       
737    }
738
739    if (result)
740    {
741        if (local_only && !result->exported)
742            result = 0;
743        else
744        {
745            /* Lookup started in class module. We've found a rule in class module,
746               which is marked for execution in that module, or in some instances.
747               Mark it for execution in the instance where we've started lookup.
748            */
749            int execute_in_class = (result->module == m);
750            int execute_in_some_instance = 
751            (result->module->class_module && result->module->class_module == m);
752            if (original_module != m && (execute_in_class || execute_in_some_instance))
753                result->module = original_module;           
754        }
755    }
756
757    return result;
758       
759}
760
761
762RULE *bindrule( char *rulename, module_t* m)
763{
764    RULE *result;
765
766    result = lookup_rule(rulename, m, 0);
767    if (!result)
768        result = lookup_rule(rulename, root_module(), 0);
769    /* We've only one caller, 'evaluate_rule', which will complain about
770       calling underfined rule. We could issue the error
771       here, but we don't have necessary information, such as frame.
772    */
773    if (!result)
774        result = enter_rule( rulename, m );
775
776    return result;
777}
778
779RULE* import_rule( RULE* source, module_t* m, char* name )
780{
781    RULE* dest = define_rule( source->module, name, m );
782    set_rule_body( dest, source->arguments, source->procedure );
783    set_rule_actions( dest, source->actions );
784    return dest;
785}
Note: See TracBrowser for help on using the repository browser.