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