1/* 2 * Copyright 1993, 1995 Christopher Seiwald. 3 * 4 * This file is part of Jam - see jam.c for Copyright information. 5 */ 6 7/* 8 * rules.c - access to RULEs, TARGETs, and ACTIONs 9 * 10 * External routines: 11 * 12 * bindrule() - return pointer to RULE, creating it if necessary 13 * bindtarget() - return pointer to TARGET, creating it if necessary 14 * copytarget() - make a new target with the old target's name 15 * touchtarget() - mark a target to simulate being new 16 * targetlist() - turn list of target names into a TARGET chain 17 * targetentry() - add a TARGET to a chain of TARGETS 18 * targetchain() - append two TARGET chains 19 * actionlist() - append to an ACTION chain 20 * addsettings() - add a deferred "set" command to a target 21 * copysettings() - copy a settings list for temp use 22 * pushsettings() - set all target specific variables 23 * popsettings() - reset target specific variables to their pre-push values 24 * freesettings() - delete a settings list 25 * donerules() - free RULE and TARGET tables 26 * 27 * 04/12/94 (seiwald) - actionlist() now just appends a single action. 28 * 08/23/94 (seiwald) - Support for '+=' (append to variable) 29 * 06/21/02 (seiwald) - support for named parameters 30 * 11/04/02 (seiwald) - const-ing for string literals 31 * 12/03/02 (seiwald) - fix odd includes support by grafting them onto depends 32 * 12/17/02 (seiwald) - new copysettings() to protect target-specific vars 33 * 01/14/03 (seiwald) - fix includes fix with new internal includes TARGET 34 */ 35 36# include "jam.h" 37# include "lists.h" 38# include "parse.h" 39# include "variable.h" 40# include "rules.h" 41# include "newstr.h" 42# include "hash.h" 43 44static struct hash *rulehash = 0; 45static struct hash *targethash = 0; 46 47# ifdef OPT_RULE_PROFILING_EXT 48static RULE *profiling_rule_list = 0; 49# endif 50 51 52/* 53 * bindrule() - return pointer to RULE, creating it if necessary 54 */ 55 56RULE * 57bindrule( const char *rulename ) 58{ 59 RULE rule, *r = &rule; 60 61 if( !rulehash ) 62 rulehash = hashinit( sizeof( RULE ), "rules" ); 63 64 r->name = rulename; 65 66 if( hashenter( rulehash, (HASHDATA **)&r ) ) 67 { 68 r->name = newstr( rulename ); /* never freed */ 69 r->procedure = (PARSE *)0; 70 r->actions = (char *)0; 71 r->bindlist = L0; 72 r->params = L0; 73 r->flags = 0; 74 75# ifdef OPT_RULE_PROFILING_EXT 76 if ( DEBUG_PROFILE_RULES ) 77 { 78 r->invocations = 0; 79 r->invocation_time = 0; 80 r->next_profiling_rule = profiling_rule_list; 81 profiling_rule_list = r; 82 } 83# endif 84 } 85 86 return r; 87} 88 89/* 90 * bindtarget() - return pointer to TARGET, creating it if necessary 91 */ 92 93TARGET * 94bindtarget( const char *targetname ) 95{ 96 TARGET target, *t = ⌖ 97 98 if( !targethash ) 99 targethash = hashinit( sizeof( TARGET ), "targets" ); 100 101 t->name = targetname; 102 103 if( hashenter( targethash, (HASHDATA **)&t ) ) 104 { 105 memset( (char *)t, '\0', sizeof( *t ) ); 106 t->name = newstr( targetname ); /* never freed */ 107 t->boundname = t->name; /* default for T_FLAG_NOTFILE */ 108 } 109 110 return t; 111} 112 113/* 114 * copytarget() - make a new target with the old target's name 115 * 116 * Not entered into hash table -- for internal nodes. 117 */ 118 119TARGET * 120copytarget( const TARGET *ot ) 121{ 122 TARGET *t; 123 124 t = (TARGET *)malloc( sizeof( *t ) ); 125 memset( (char *)t, '\0', sizeof( *t ) ); 126 t->name = copystr( ot->name ); 127 t->boundname = t->name; 128 129 t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL; 130 131 return t; 132} 133 134/* 135 * touchtarget() - mark a target to simulate being new 136 */ 137 138void 139touchtarget( const char *t ) 140{ 141 bindtarget( t )->flags |= T_FLAG_TOUCHED; 142} 143 144/* 145 * targetlist() - turn list of target names into a TARGET chain 146 * 147 * Inputs: 148 * chain existing TARGETS to append to 149 * targets list of target names 150 */ 151 152TARGETS * 153targetlist( 154 TARGETS *chain, 155 LIST *targets ) 156{ 157 for( ; targets; targets = list_next( targets ) ) 158 chain = targetentry( chain, bindtarget( targets->string ) ); 159 160 return chain; 161} 162 163/* 164 * targetentry() - add a TARGET to a chain of TARGETS 165 * 166 * Inputs: 167 * chain exisitng TARGETS to append to 168 * target new target to append 169 */ 170 171TARGETS * 172targetentry( 173 TARGETS *chain, 174 TARGET *target ) 175{ 176 TARGETS *c; 177 178 c = (TARGETS *)malloc( sizeof( TARGETS ) ); 179 c->target = target; 180 181 if( !chain ) chain = c; 182 else chain->tail->next = c; 183 chain->tail = c; 184 c->next = 0; 185 186 return chain; 187} 188 189/* 190 * targetchain() - append two TARGET chains 191 * 192 * Inputs: 193 * chain exisitng TARGETS to append to 194 * target new target to append 195 */ 196 197TARGETS * 198targetchain( 199 TARGETS *chain, 200 TARGETS *targets ) 201{ 202 TARGETS *c; 203 204 if( !targets ) 205 return chain; 206 else if( !chain ) 207 return targets; 208 209 chain->tail->next = targets; 210 chain->tail = targets->tail; 211 212 return chain; 213} 214 215/* 216 * actionlist() - append to an ACTION chain 217 */ 218 219ACTIONS * 220actionlist( 221 ACTIONS *chain, 222 ACTION *action ) 223{ 224 ACTIONS *actions = (ACTIONS *)malloc( sizeof( ACTIONS ) ); 225 226 actions->action = action; 227 228 if( !chain ) chain = actions; 229 else chain->tail->next = actions; 230 chain->tail = actions; 231 actions->next = 0; 232 233 return chain; 234} 235 236/* 237 * addsettings() - add a deferred "set" command to a target 238 * 239 * Adds a variable setting (varname=list) onto a chain of settings 240 * for a particular target. Replaces the previous previous value, 241 * if any, unless 'append' says to append the new list onto the old. 242 * Returns the head of the chain of settings. 243 */ 244 245SETTINGS * 246addsettings( 247 SETTINGS *head, 248 int setflag, 249 const char *symbol, 250 LIST *value ) 251{ 252 SETTINGS *v; 253 254 /* Look for previous setting */ 255 256 for( v = head; v; v = v->next ) 257 if( !strcmp( v->symbol, symbol ) ) 258 break; 259 260 /* If not previously set, alloc a new. */ 261 /* If appending, do so. */ 262 /* Else free old and set new. */ 263 264 if( !v ) 265 { 266 v = (SETTINGS *)malloc( sizeof( *v ) ); 267 v->symbol = newstr( symbol ); 268 v->value = value; 269 v->next = head; 270 head = v; 271 } 272 else switch( setflag ) 273 { 274 case VAR_SET: 275 /* Toss old, set new */ 276 list_free( v->value ); 277 v->value = value; 278 break; 279 280 case VAR_APPEND: 281 /* Append new to old */ 282 v->value = list_append( v->value, value ); 283 break; 284 285 case VAR_DEFAULT: 286 /* Toss new, old already set */ 287 list_free( value ); 288 break; 289 } 290 291 /* Return (new) head of list. */ 292 293 return head; 294} 295 296/* 297 * copysettings() - copy a settings list for temp use 298 * 299 * When target-specific variables are pushed into place with pushsettings(), 300 * any global variables with the same name are swapped onto the target's 301 * SETTINGS chain. If that chain gets modified (by using the "on target" 302 * syntax), popsettings() would wrongly swap those modified values back 303 * as the new global values. 304 * 305 * copysettings() protects the target's SETTINGS chain by providing a 306 * copy of the chain to pass to pushsettings() and popsettings(), so that 307 * the target's original SETTINGS chain can be modified using the usual 308 * "on target" syntax. 309 */ 310 311SETTINGS * 312copysettings( SETTINGS *from ) 313{ 314 SETTINGS *head = 0, *v; 315 316 for( ; from; from = from->next ) 317 { 318 SETTINGS *v = (SETTINGS *)malloc( sizeof( *v ) ); 319 v->symbol = copystr( from->symbol ); 320 v->value = list_copy( 0, from->value ); 321 v->next = head; 322 head = v; 323 } 324 325 return head; 326} 327 328/* 329 * pushsettings() - set all target specific variables 330 */ 331 332void 333pushsettings( SETTINGS *v ) 334{ 335 for( ; v; v = v->next ) 336 v->value = var_swap( v->symbol, v->value ); 337} 338 339/* 340 * popsettings() - reset target specific variables to their pre-push values 341 */ 342 343void 344popsettings( SETTINGS *v ) 345{ 346 pushsettings( v ); /* just swap again */ 347} 348 349/* 350 * freesettings() - delete a settings list 351 */ 352 353void 354freesettings( SETTINGS *v ) 355{ 356 while( v ) 357 { 358 SETTINGS *n = v->next; 359 360 freestr( v->symbol ); 361 list_free( v->value ); 362 free( (char *)v ); 363 364 v = n; 365 } 366} 367 368/* 369 * donerules() - free RULE and TARGET tables 370 */ 371 372void 373donerules() 374{ 375# ifdef OPT_RULE_PROFILING_EXT 376 if ( DEBUG_PROFILE_RULES ) 377 { 378 RULE *rule; 379 380 printf("# invoked total time (us) rule\n"); 381 printf("--------- --------------- " 382 "------------------------------------\n"); 383 384 for (rule = profiling_rule_list; 385 rule; 386 rule = rule->next_profiling_rule) 387 { 388 printf("%9d %15lld %s\n", rule->invocations, 389 (long long)rule->invocation_time, rule->name); 390 } 391 } 392# endif 393 394 hashdone( rulehash ); 395 hashdone( targethash ); 396} 397