/* * Copyright 1993, 1995 Christopher Seiwald. * * This file is part of Jam - see jam.c for Copyright information. */ /* * rules.c - access to RULEs, TARGETs, and ACTIONs * * External routines: * * bindrule() - return pointer to RULE, creating it if necessary * bindtarget() - return pointer to TARGET, creating it if necessary * copytarget() - make a new target with the old target's name * touchtarget() - mark a target to simulate being new * targetlist() - turn list of target names into a TARGET chain * targetentry() - add a TARGET to a chain of TARGETS * targetchain() - append two TARGET chains * actionlist() - append to an ACTION chain * addsettings() - add a deferred "set" command to a target * copysettings() - copy a settings list for temp use * pushsettings() - set all target specific variables * popsettings() - reset target specific variables to their pre-push values * freesettings() - delete a settings list * donerules() - free RULE and TARGET tables * * 04/12/94 (seiwald) - actionlist() now just appends a single action. * 08/23/94 (seiwald) - Support for '+=' (append to variable) * 06/21/02 (seiwald) - support for named parameters * 11/04/02 (seiwald) - const-ing for string literals * 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends * 12/17/02 (seiwald) - new copysettings() to protect target-specific vars * 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET */ # include "jam.h" # include "lists.h" # include "parse.h" # include "variable.h" # include "rules.h" # include "newstr.h" # include "hash.h" static struct hash *rulehash = 0; static struct hash *targethash = 0; # ifdef OPT_RULE_PROFILING_EXT static RULE *profiling_rule_list = 0; # endif /* * bindrule() - return pointer to RULE, creating it if necessary */ RULE * bindrule( const char *rulename ) { RULE rule, *r = &rule; if( !rulehash ) rulehash = hashinit( sizeof( RULE ), "rules" ); r->name = rulename; if( hashenter( rulehash, (HASHDATA **)&r ) ) { r->name = newstr( rulename ); /* never freed */ r->procedure = (PARSE *)0; r->actions = (char *)0; r->bindlist = L0; r->params = L0; r->flags = 0; # ifdef OPT_RULE_PROFILING_EXT if ( DEBUG_PROFILE_RULES ) { r->invocations = 0; r->invocation_time = 0; r->next_profiling_rule = profiling_rule_list; profiling_rule_list = r; } # endif } return r; } /* * bindtarget() - return pointer to TARGET, creating it if necessary */ TARGET * bindtarget( const char *targetname ) { TARGET target, *t = ⌖ if( !targethash ) targethash = hashinit( sizeof( TARGET ), "targets" ); t->name = targetname; if( hashenter( targethash, (HASHDATA **)&t ) ) { memset( (char *)t, '\0', sizeof( *t ) ); t->name = newstr( targetname ); /* never freed */ t->boundname = t->name; /* default for T_FLAG_NOTFILE */ } return t; } /* * copytarget() - make a new target with the old target's name * * Not entered into hash table -- for internal nodes. */ TARGET * copytarget( const TARGET *ot ) { TARGET *t; t = (TARGET *)malloc( sizeof( *t ) ); memset( (char *)t, '\0', sizeof( *t ) ); t->name = copystr( ot->name ); t->boundname = t->name; t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL; return t; } /* * touchtarget() - mark a target to simulate being new */ void touchtarget( const char *t ) { bindtarget( t )->flags |= T_FLAG_TOUCHED; } /* * targetlist() - turn list of target names into a TARGET chain * * Inputs: * chain existing TARGETS to append to * targets list of target names */ TARGETS * targetlist( TARGETS *chain, LIST *targets ) { for( ; targets; targets = list_next( targets ) ) chain = targetentry( chain, bindtarget( targets->string ) ); return chain; } /* * targetentry() - add a TARGET to a chain of TARGETS * * Inputs: * chain exisitng TARGETS to append to * target new target to append */ TARGETS * targetentry( TARGETS *chain, TARGET *target ) { TARGETS *c; c = (TARGETS *)malloc( sizeof( TARGETS ) ); c->target = target; if( !chain ) chain = c; else chain->tail->next = c; chain->tail = c; c->next = 0; return chain; } /* * targetchain() - append two TARGET chains * * Inputs: * chain exisitng TARGETS to append to * target new target to append */ TARGETS * targetchain( TARGETS *chain, TARGETS *targets ) { TARGETS *c; if( !targets ) return chain; else if( !chain ) return targets; chain->tail->next = targets; chain->tail = targets->tail; return chain; } /* * actionlist() - append to an ACTION chain */ ACTIONS * actionlist( ACTIONS *chain, ACTION *action ) { ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) ); actions->action = action; if( !chain ) chain = actions; else chain->tail->next = actions; chain->tail = actions; actions->next = 0; return chain; } /* * addsettings() - add a deferred "set" command to a target * * Adds a variable setting (varname=list) onto a chain of settings * for a particular target. Replaces the previous previous value, * if any, unless 'append' says to append the new list onto the old. * Returns the head of the chain of settings. */ SETTINGS * addsettings( SETTINGS *head, int setflag, const char *symbol, LIST *value ) { SETTINGS *v; /* Look for previous setting */ for( v = head; v; v = v->next ) if( !strcmp( v->symbol, symbol ) ) break; /* If not previously set, alloc a new. */ /* If appending, do so. */ /* Else free old and set new. */ if( !v ) { v = (SETTINGS *)malloc( sizeof( *v ) ); v->symbol = newstr( symbol ); v->value = value; v->next = head; head = v; } else switch( setflag ) { case VAR_SET: /* Toss old, set new */ list_free( v->value ); v->value = value; break; case VAR_APPEND: /* Append new to old */ v->value = list_append( v->value, value ); break; case VAR_DEFAULT: /* Toss new, old already set */ list_free( value ); break; } /* Return (new) head of list. */ return head; } /* * copysettings() - copy a settings list for temp use * * When target-specific variables are pushed into place with pushsettings(), * any global variables with the same name are swapped onto the target's * SETTINGS chain. If that chain gets modified (by using the "on target" * syntax), popsettings() would wrongly swap those modified values back * as the new global values. * * copysettings() protects the target's SETTINGS chain by providing a * copy of the chain to pass to pushsettings() and popsettings(), so that * the target's original SETTINGS chain can be modified using the usual * "on target" syntax. */ SETTINGS * copysettings( SETTINGS *from ) { SETTINGS *head = 0, *v; for( ; from; from = from->next ) { SETTINGS *v = (SETTINGS *)malloc( sizeof( *v ) ); v->symbol = copystr( from->symbol ); v->value = list_copy( 0, from->value ); v->next = head; head = v; } return head; } /* * pushsettings() - set all target specific variables */ void pushsettings( SETTINGS *v ) { for( ; v; v = v->next ) v->value = var_swap( v->symbol, v->value ); } /* * popsettings() - reset target specific variables to their pre-push values */ void popsettings( SETTINGS *v ) { pushsettings( v ); /* just swap again */ } /* * freesettings() - delete a settings list */ void freesettings( SETTINGS *v ) { while( v ) { SETTINGS *n = v->next; freestr( v->symbol ); list_free( v->value ); free( (char *)v ); v = n; } } /* * donerules() - free RULE and TARGET tables */ void donerules() { # ifdef OPT_RULE_PROFILING_EXT if ( DEBUG_PROFILE_RULES ) { RULE *rule; printf("# invoked total time (us) rule\n"); printf("--------- --------------- " "------------------------------------\n"); for (rule = profiling_rule_list; rule; rule = rule->next_profiling_rule) { printf("%9d %15lld %s\n", rule->invocations, (long long)rule->invocation_time, rule->name); } } # endif hashdone( rulehash ); hashdone( targethash ); }