| File: | dmake/rulparse.c |
| Location: | line 293, column 40 |
| Description: | Value stored to 'result' is never read |
| 1 | /* |
| 2 | -- |
| 3 | -- SYNOPSIS |
| 4 | -- Perform semantic analysis on input |
| 5 | -- |
| 6 | -- DESCRIPTION |
| 7 | -- This code performs semantic analysis on the input, and builds |
| 8 | -- the complex internal datastructure that is used to represent |
| 9 | -- the user makefile. |
| 10 | -- |
| 11 | -- AUTHOR |
| 12 | -- Dennis Vadura, dvadura@dmake.wticorp.com |
| 13 | -- |
| 14 | -- WWW |
| 15 | -- http://dmake.wticorp.com/ |
| 16 | -- |
| 17 | -- COPYRIGHT |
| 18 | -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved. |
| 19 | -- |
| 20 | -- This program is NOT free software; you can redistribute it and/or |
| 21 | -- modify it under the terms of the Software License Agreement Provided |
| 22 | -- in the file <distribution-root>/readme/license.txt. |
| 23 | -- |
| 24 | -- LOG |
| 25 | -- Use cvs log to obtain detailed change logs. |
| 26 | */ |
| 27 | |
| 28 | #include "extern.h" |
| 29 | |
| 30 | /* prototypes for local functions */ |
| 31 | static void _add_indirect_prereq ANSI((CELLPTR))(CELLPTR); |
| 32 | static int _add_root ANSI((CELLPTR))(CELLPTR); |
| 33 | static CELLPTR _build_graph ANSI((int, CELLPTR, CELLPTR))(int, CELLPTR, CELLPTR); |
| 34 | static char* _build_meta ANSI((char*))(char*); |
| 35 | static int _do_magic ANSI((int, char*, CELLPTR, CELLPTR, t_attr, char*))(int, char*, CELLPTR, CELLPTR, t_attr, char*); |
| 36 | static void _do_special ANSI((int, int, t_attr,char*,CELLPTR,CELLPTR,int*))(int, int, t_attr,char*,CELLPTR,CELLPTR,int*); |
| 37 | static int _do_targets ANSI((int, t_attr, char*, CELLPTR, CELLPTR))(int, t_attr, char*, CELLPTR, CELLPTR); |
| 38 | static t_attr _is_attribute ANSI((char*))(char*); |
| 39 | static int _is_special ANSI((char*))(char*); |
| 40 | static char* _is_magic ANSI((char*))(char*); |
| 41 | static int _is_percent ANSI((char*))(char*); |
| 42 | static CELLPTR _make_multi ANSI((CELLPTR))(CELLPTR); |
| 43 | static CELLPTR _replace_cell ANSI((CELLPTR,CELLPTR,CELLPTR))(CELLPTR,CELLPTR,CELLPTR); |
| 44 | static void _set_attributes ANSI((t_attr, char*, CELLPTR ))(t_attr, char*, CELLPTR ); |
| 45 | static void _stick_at_head ANSI((CELLPTR, CELLPTR))(CELLPTR, CELLPTR); |
| 46 | static void _set_global_attr ANSI((t_attr))(t_attr); |
| 47 | |
| 48 | |
| 49 | /* static variables that must persist across invocation of Parse_rule_def */ |
| 50 | static CELLPTR _sv_targets = NIL(CELL)((CELL*)((void*)0)); |
| 51 | static STRINGPTR _sv_rules = NIL(STRING)((STRING*)((void*)0)); /* first recipe element. */ |
| 52 | static STRINGPTR _sv_crule = NIL(STRING)((STRING*)((void*)0)); /* current/last recipe element. */ |
| 53 | static CELLPTR _sv_edgel = NIL(CELL)((CELL*)((void*)0)); |
| 54 | static LINKPTR _sv_ind_prq = NIL(LINK)((LINK*)((void*)0)); /* indirect prerequisites for % cell */ |
| 55 | static int _sp_target = FALSE0; |
| 56 | static t_attr _sv_attr; |
| 57 | static int _sv_flag; |
| 58 | static int _sv_op; |
| 59 | static char *_sv_setdir; |
| 60 | static char _sv_globprq_only = 0; |
| 61 | |
| 62 | /* Define for global attribute mask (A_SWAP == A_WINPATH) */ |
| 63 | #define A_GLOB(0x00001 | 0x00002 | 0x00020 | 0x00008 | 0x01000 | 0x00800 | 0x00010 | 0x00080 | 0x00200 | 0x02000 ) (A_PRECIOUS0x00001 | A_SILENT0x00002 | A_IGNORE0x00020 | A_EPILOG0x00008 | A_SWAP0x01000 |\ |
| 64 | A_SHELL0x00800 | A_PROLOG0x00010 | A_NOINFER0x00080 | A_SEQ0x00200 | A_MKSARGS0x02000 ) |
| 65 | |
| 66 | |
| 67 | PUBLIC int |
| 68 | Parse_rule_def( state )/* |
| 69 | ========================= |
| 70 | Parse the rule definition contained in Buffer, and modify the state |
| 71 | if appropriate. The function returns 0, if the definition is found to |
| 72 | be an illegal rule definition, and it returns 1 if it is a rule definition. |
| 73 | */ |
| 74 | int *state; |
| 75 | { |
| 76 | TKSTR input; /* input string struct for token search */ |
| 77 | CELLPTR targets; /* list of targets if any */ |
| 78 | CELLPTR prereq; /* list of prereq if any */ |
| 79 | CELLPTR prereqtail; /* tail of prerequisite list */ |
| 80 | CELLPTR cp; /* temporary cell pointer for list making */ |
| 81 | char *result; /* temporary storage for result */ |
| 82 | char *tok; /* temporary pointer for tokens */ |
| 83 | char *set_dir; /* value of setdir attribute */ |
| 84 | char *brk; /* break char list for Get_token */ |
| 85 | char *firstrcp; /* first recipe line, from ; in rule line */ |
| 86 | t_attr attr; /* sum of attribute flags for current tgts*/ |
| 87 | t_attr at; /* temp place to keep an attribute code */ |
| 88 | int op; /* rule operator */ |
| 89 | int special; /* indicate special targets in rule */ |
| 90 | int augmeta; /* indicate .<suffix> like target */ |
| 91 | int percent; /* indicate percent rule target */ |
| 92 | int percent_prq; /* indicate mixed %-rule prereq possible */ |
| 93 | |
| 94 | DB_ENTER( "Parse_rule_def" ); |
| 95 | |
| 96 | op = 0; |
| 97 | attr = 0; |
| 98 | special = 0; |
| 99 | augmeta = 0; |
| 100 | percent = 0; |
| 101 | set_dir = NIL( char )((char*)((void*)0)); |
| 102 | targets = NIL(CELL)((CELL*)((void*)0)); |
| 103 | prereq = NIL(CELL)((CELL*)((void*)0)); |
| 104 | prereqtail = NIL(CELL)((CELL*)((void*)0)); |
| 105 | percent_prq = 0; |
| 106 | |
| 107 | /* Check to see if the line is of the form: |
| 108 | * targets : prerequisites; first recipe line |
| 109 | * If so remember the first_recipe part of the line. */ |
| 110 | |
| 111 | firstrcp = strchr( Buffer, ';' ); |
| 112 | if( firstrcp != NIL( char )((char*)((void*)0)) ) { |
| 113 | *firstrcp++ = 0; |
| 114 | firstrcp = DmStrSpn( firstrcp, " \t" ); |
| 115 | } |
| 116 | |
| 117 | result = Expand( Buffer ); |
| 118 | /* Remove CONTINUATION_CHAR, keep the <nl> */ |
| 119 | for( brk=strchr(result,CONTINUATION_CHAR'\\'); brk != NIL(char)((char*)((void*)0)); brk=strchr(brk,CONTINUATION_CHAR'\\') ) |
| 120 | if( brk[1] == '\n' ) |
| 121 | *brk = ' '; |
| 122 | else |
| 123 | brk++; |
| 124 | |
| 125 | DB_PRINT( "par", ("Scanning: [%s]", result) ); |
| 126 | |
| 127 | SET_TOKEN( &input, result )(&input)->tk_str = (result); (&input)->tk_cchar = *(result); (&input)->tk_quote = 1;; |
| 128 | brk = ":-^!|"; |
| 129 | Def_targets = TRUE1; |
| 130 | |
| 131 | /* Scan the input rule line collecting targets, the operator, and any |
| 132 | * prerequisites. Stop when we run out of targets and prerequisites. */ |
| 133 | |
| 134 | while( *(tok = Get_token( &input, brk, TRUE1 )) != '\0' ) |
| 135 | if( !op ) { |
| 136 | /* we are scanning targets and attributes |
| 137 | * check to see if token is an operator. */ |
| 138 | |
| 139 | op = Rule_op( tok ); |
| 140 | |
| 141 | if( !op ) { |
| 142 | /* Define a new cell, or get pointer to pre-existing cell. */ |
| 143 | /* Do we need cells for attributes? If not move the definition |
| 144 | * to the target part. */ |
| 145 | cp = Def_cell( tok ); |
| 146 | /* A $ character indicates either a literal $ in the pathname (this |
| 147 | * was broken before) or a dynamic macro (this is a syntax error). |
| 148 | * FIXME: Here would be the place to add a sanity check. */ |
| 149 | DB_PRINT( "par", ("tg_cell [%s]", tok) ); |
| 150 | |
| 151 | if( (at = _is_attribute(tok)) != 0 ) { |
| 152 | /* Ignore .SILENT when -vr is active. */ |
| 153 | if( (Verbose & V_FORCEECHO0x80) && (at == A_SILENT0x00002) ) |
| 154 | at = 0; |
| 155 | |
| 156 | /* Logically OR the attributes specified into one main |
| 157 | * ATTRIBUTE mask. */ |
| 158 | |
| 159 | if( at == A_SETDIR0x00400 ) { |
| 160 | if( set_dir != NIL( char )((char*)((void*)0)) ) |
| 161 | Warning( "Multiple .SETDIR attribute ignored" ); |
| 162 | else |
| 163 | set_dir = DmStrDup( tok ); |
| 164 | } |
| 165 | |
| 166 | attr |= at; |
| 167 | } |
| 168 | else { |
| 169 | /* Not an attribute, this must be a target. */ |
| 170 | int tmp; |
| 171 | |
| 172 | tmp = _is_special( tok ); |
| 173 | |
| 174 | if( _is_percent( tok ) ) { |
| 175 | /* First %-target checks if there were non-%-targets before. */ |
| 176 | if( !percent && targets != NIL(CELL)((CELL*)((void*)0)) ) |
| 177 | Fatal( "A %%-target must not be mixed with non-%%-targets, offending target [%s]", tok ); |
| 178 | |
| 179 | percent++; |
| 180 | cp->ce_flag |= F_PERCENT0x0800; |
| 181 | } else { |
| 182 | if( percent ) |
| 183 | Fatal( "A non-%%-target must not be mixed with %%-targets, offending target [%s]", tok ); |
| 184 | } |
| 185 | |
| 186 | if( _is_magic( tok ) ) { |
| 187 | /* Check that AUGMAKE targets are not mixed with other |
| 188 | * targets. The return value of _is_magic() is discarded and |
| 189 | * calculated again in _do_targets() if this rule definition |
| 190 | * really is a .<suffix> like target. |
| 191 | * If we would allow only one target per line we could easily |
| 192 | * store the result for later, but for multiple .<suffix> |
| 193 | * targets this creates too much overhead. |
| 194 | * These targets should be rare (obsolete?) anyway. */ |
| 195 | if( !augmeta && targets != NIL(CELL)((CELL*)((void*)0)) ) |
| 196 | Fatal( "An AUGMAKE meta target must not be mixed with non AUGMAKE meta targets, offending target [%s]", tok ); |
| 197 | |
| 198 | augmeta++; |
| 199 | cp->ce_flag |= F_MAGIC0x2000; /* do_magic will also add F_PERCENT later. */ |
| 200 | } else { |
| 201 | if( augmeta ) |
| 202 | Fatal( "A non AUGMAKE meta target must not be mixed with AUGMAKE meta targets, offending target [%s]", tok ); |
| 203 | } |
| 204 | |
| 205 | if( special ) |
| 206 | Fatal( "Special target must appear alone, found [%s]", tok ); |
| 207 | else if( !(cp->ce_flag & F_MARK0x0001) ) { |
| 208 | /* Targets are kept in this list in lexically sorted order. |
| 209 | * This allows for easy equality comparison of target |
| 210 | * sets.*/ |
| 211 | CELLPTR prev,cur; |
| 212 | for(prev=NIL(CELL)((CELL*)((void*)0)),cur=targets;cur;prev=cur,cur=cur->ce_link) |
| 213 | if(strcmp(cur->CE_NAMEce_name->ht_name,cp->CE_NAMEce_name->ht_name) > 0) |
| 214 | break; |
| 215 | |
| 216 | cp->ce_link = cur; |
| 217 | |
| 218 | if (!prev) |
| 219 | targets = cp; |
| 220 | else |
| 221 | prev->ce_link = cp; |
| 222 | |
| 223 | cp->ce_flag |= F_MARK0x0001 | F_EXPLICIT0x0400; |
| 224 | special = tmp; |
| 225 | } |
| 226 | else |
| 227 | Warning( "Duplicate target [%s]", cp->CE_NAMEce_name->ht_name ); |
| 228 | } |
| 229 | } |
| 230 | else { |
| 231 | /* found an operator so empty out break list and clear mark |
| 232 | * bits on target list, setting them all to F_VISITED*/ |
| 233 | |
| 234 | brk = ""; |
| 235 | for( cp=targets; cp != NIL(CELL)((CELL*)((void*)0)); cp=cp->ce_link ) { |
| 236 | cp->ce_flag ^= F_MARK0x0001; |
| 237 | cp->ce_flag |= F_VISITED0x0080; |
| 238 | } |
| 239 | |
| 240 | Def_targets = FALSE0; |
| 241 | } |
| 242 | } |
| 243 | else { |
| 244 | /* Scanning prerequisites so build the prerequisite list. We use |
| 245 | * F_MARK flag to make certain we have only a single copy of the |
| 246 | * prerequisite in the list */ |
| 247 | |
| 248 | cp = Def_cell( tok ); |
| 249 | |
| 250 | /* %-prerequisits require eiter a %-target or this might be a rule of |
| 251 | * the "ATTRIBUTE_LIST : targets" form. */ |
| 252 | if( _is_percent( tok ) ) { |
| 253 | if( percent || ((targets == NIL(CELL)((CELL*)((void*)0))) && attr) ) |
| 254 | percent_prq = 1; |
| 255 | else |
| 256 | Fatal( "Syntax error in %% rule, missing %% target"); |
| 257 | } |
| 258 | |
| 259 | if( cp->ce_flag & F_VISITED0x0080 ) { |
| 260 | if( cp->ce_attr & A_COMPOSITE0x200000 ) |
| 261 | continue; |
| 262 | else |
| 263 | Fatal( "Detected circular dependency in graph at [%s]", |
| 264 | cp->CE_NAMEce_name->ht_name ); |
| 265 | } |
| 266 | else if( !(cp->ce_flag & F_MARK0x0001) ) { |
| 267 | DB_PRINT( "par", ("pq_cell [%s]", tok) ); |
| 268 | cp->ce_flag |= F_MARK0x0001; |
| 269 | |
| 270 | if( prereqtail == NIL(CELL)((CELL*)((void*)0)) ) /* keep prereq's in order */ |
| 271 | prereq = cp; |
| 272 | else |
| 273 | prereqtail->ce_link = cp; |
| 274 | |
| 275 | prereqtail = cp; |
| 276 | cp->ce_link = NIL(CELL)((CELL*)((void*)0)); |
| 277 | } |
| 278 | else if( !(cp->ce_attr & A_LIBRARY0x00004) && (Verbose & V_WARNALL0x40)) |
| 279 | Warning("Duplicate entry [%s] in prerequisite list",cp->CE_NAMEce_name->ht_name); |
| 280 | } |
| 281 | |
| 282 | /* Check to see if we have a percent rule that has only global |
| 283 | * prerequisites, i.e. they are of the form: "%.a : foo". |
| 284 | * If so then set the flag so that later on, we don't issue |
| 285 | * an error if such targets supply an empty set of rules. */ |
| 286 | |
| 287 | if( percent && !percent_prq && (prereq != NIL(CELL)((CELL*)((void*)0))) ) |
| 288 | _sv_globprq_only = 1; |
| 289 | |
| 290 | /* It's ok to have targets with attributes, and no prerequisites, but it's |
| 291 | * not ok to have no targets and no attributes, or no operator */ |
| 292 | |
| 293 | CLEAR_TOKEN( &input )*(&input)->tk_str = (&input)->tk_cchar; FREE(result)free((char*)(result)); result = NIL(char)((char*)((void*)0)); |
Value stored to 'result' is never read | |
| 294 | if( !op ) { |
| 295 | DB_PRINT( "par", ("Not a rule [%s]", Buffer) ); |
| 296 | DB_RETURN( 0 )return (0); |
| 297 | } |
| 298 | |
| 299 | /* More than one percent target didn't work with prior versions. */ |
| 300 | #if 0 |
| 301 | if( (percent > 1) && !(op & R_OP_OR32) ) |
| 302 | Warning( "Prior to dmake 4.5 only one\n" |
| 303 | "%%-target per target-definition worked reliably. Check your makefiles.\n" ); |
| 304 | #endif |
| 305 | |
| 306 | if( !attr && targets == NIL(CELL)((CELL*)((void*)0)) ) { |
| 307 | Fatal( "Missing targets or attributes in rule" ); |
| 308 | if( set_dir != NIL( char )((char*)((void*)0))) FREE( set_dir )free((char*)(set_dir)); |
| 309 | DB_RETURN( 0 )return (0); |
| 310 | } |
| 311 | |
| 312 | /* We have established we have a legal rules line, so we must process it. |
| 313 | * In doing so we must handle any special targets. Special targets must |
| 314 | * appear alone possibly accompanied by attributes. |
| 315 | * NOTE: special != 0 ==> targets != NIL(CELL) */ |
| 316 | |
| 317 | if( prereqtail != NIL(CELL)((CELL*)((void*)0)) ) prereqtail->ce_link = NIL(CELL)((CELL*)((void*)0)); |
| 318 | |
| 319 | /* Clear out MARK bits used in duplicate checking. I originally wanted |
| 320 | * to do this as the lists get processed but that got too error prone |
| 321 | * so I bit the bullit and added these two loops. */ |
| 322 | |
| 323 | for( cp=prereq; cp != NIL(CELL)((CELL*)((void*)0)); cp=cp->ce_link ) cp->ce_flag &= ~F_MARK0x0001; |
| 324 | for( cp=targets; cp != NIL(CELL)((CELL*)((void*)0)); cp=cp->ce_link ) cp->ce_flag &= ~F_VISITED0x0080; |
| 325 | |
| 326 | /* Check to see if the previous recipe was bound, if not the call |
| 327 | * Bind_rules_to_targets() to bind the recipe (_sv_rules) to the |
| 328 | * target(s) (_sv_targets). */ |
| 329 | /* was: if( _sv_rules != NIL(STRING) ) Bind_rules_to_targets( F_DEFAULT );*/ |
| 330 | /* Only Add_recipe_to_list() sets _sv_rules and Bind_rules_to_targets() |
| 331 | * clears the (static) variables again. Bind_rules_to_targets() is |
| 332 | * (should be) called after State is leaving RULE_SCAN in Parse(). |
| 333 | * Abort if there are unbound recipes. FIXME: Remove this paragraph |
| 334 | * if this never occurs. */ |
| 335 | if( _sv_rules != NIL(STRING)((STRING*)((void*)0)) ) |
| 336 | Fatal( "Internal Error: _sv_rules not empty." ); |
| 337 | |
| 338 | /* Add the first recipe line to the list */ |
| 339 | if( firstrcp != NIL( char )((char*)((void*)0)) ) |
| 340 | Add_recipe_to_list( firstrcp, TRUE1, FALSE0 ); |
| 341 | |
| 342 | /* Save these prior to calling _do_targets, since _build_graph needs the |
| 343 | * _sv_setdir value for matching edges. */ |
| 344 | _sv_op = op; |
| 345 | _sv_setdir = set_dir; |
| 346 | |
| 347 | if( special ) |
| 348 | /* _do_special() can alter *state */ |
| 349 | _do_special( special, op, attr, set_dir, targets, prereq, state ); |
| 350 | else |
| 351 | *state = _do_targets( op, attr, set_dir, targets, prereq ); |
| 352 | |
| 353 | if( (*state != RULE_SCAN1) && (_sv_rules != NIL(STRING)((STRING*)((void*)0))) ) |
| 354 | Fatal( "Unexpected recipe found." ); |
| 355 | |
| 356 | DB_RETURN( 1 )return (1); |
| 357 | } |
| 358 | |
| 359 | |
| 360 | PUBLIC int |
| 361 | Rule_op( op )/* |
| 362 | ================ |
| 363 | Check the passed in op string and map it to one of the rule operators */ |
| 364 | char *op; |
| 365 | { |
| 366 | int ret = 0; |
| 367 | |
| 368 | DB_ENTER( "rule_op" ); |
| 369 | |
| 370 | if( *op == TGT_DEP_SEP':' ) { |
| 371 | ret = R_OP_CL1; |
| 372 | op++; |
| 373 | |
| 374 | /* All rule operations begin with a :, but may include any one of the |
| 375 | * four modifiers. In order for the rule to be properly mapped we must |
| 376 | * check for each of the modifiers in turn, building up our return bit |
| 377 | * string. */ |
| 378 | |
| 379 | while( *op && ret ) |
| 380 | switch( *op ) { |
| 381 | case ':': ret |= R_OP_DCL2; op++; break; |
| 382 | case '!': ret |= R_OP_BG4; op++; break; |
| 383 | case '^': ret |= R_OP_UP8; op++; break; |
| 384 | case '-': ret |= R_OP_MI16; op++; break; |
| 385 | case '|': ret |= R_OP_OR32; op++; break; |
| 386 | |
| 387 | default : ret = 0; /* an invalid modifier, chuck whole string */ |
| 388 | } |
| 389 | |
| 390 | if( *op != '\0' ) ret = 0; |
| 391 | } |
| 392 | |
| 393 | DB_RETURN( ret )return (ret); |
| 394 | } |
| 395 | |
| 396 | |
| 397 | PUBLIC void |
| 398 | Add_recipe_to_list( rule, white_too, no_check )/* |
| 399 | ================================================= |
| 400 | Take the provided string and add it to the list of recipe lines |
| 401 | we are saving to be added to the list of targets we have built |
| 402 | previously. If white_too == TRUE add the rule EVEN IF it contains only |
| 403 | an empty string (whitespace is handled by Def_recipe()). */ |
| 404 | char *rule; |
| 405 | int white_too; |
| 406 | int no_check; |
| 407 | { |
| 408 | DB_ENTER( "Add_recipe_to_list" ); |
| 409 | |
| 410 | if( rule != NIL( char )((char*)((void*)0)) && (*rule != '\0' || white_too) ) { |
| 411 | DB_PRINT( "par", ("Adding recipe [%s]", rule) ); |
| 412 | _sv_crule = Def_recipe( rule, _sv_crule, white_too, no_check ); |
| 413 | |
| 414 | /* If _sv_rules is not yet set this must be the first recipe line, |
| 415 | * remember it. */ |
| 416 | if( _sv_rules == NIL(STRING)((STRING*)((void*)0)) ) |
| 417 | _sv_rules = _sv_crule; |
| 418 | } |
| 419 | |
| 420 | DB_VOID_RETURNreturn; |
| 421 | } |
| 422 | |
| 423 | |
| 424 | PUBLIC void |
| 425 | Bind_rules_to_targets( flag )/* |
| 426 | =============================== |
| 427 | Take the recipe lines we have defined and bind them with proper attributes |
| 428 | to the targets that were previously defined in the parse. The |
| 429 | attributes that get passed here are merged with those that are were |
| 430 | previously defined. (namely attribute F_SINGLE) */ |
| 431 | int flag; |
| 432 | { |
| 433 | CELLPTR tg; /* pointer to current target in list */ |
| 434 | LINKPTR lp; /* pointer to link cell */ |
| 435 | int magic; /* TRUE if target of % or .xxx.yyy form */ |
| 436 | int tflag; /* TRUE if we assigned targets here */ |
| 437 | |
| 438 | DB_ENTER( "Bind_rules_to_targets" ); |
| 439 | |
| 440 | /* This line is needed since Parse may call us twice when the last |
| 441 | * GROUP rule appears at the end of file. In this case the rules |
| 442 | * have already been bound and we want to ignore them. */ |
| 443 | |
| 444 | if( _sv_targets == NIL(CELL)((CELL*)((void*)0)) ) { DB_VOID_RETURNreturn; } |
| 445 | |
| 446 | tflag = FALSE0; |
| 447 | flag |= (_sv_flag & F_SINGLE0x0004); |
| 448 | flag |= ((_sv_attr & A_GROUP0x02000000) ? F_GROUP0x0020 : 0); |
| 449 | |
| 450 | for( tg = _sv_targets; tg != NIL(CELL)((CELL*)((void*)0)); tg = tg->ce_link ) { |
| 451 | DB_PRINT( "par", ("Binding to %s, %04x", tg->CE_NAME, tg->ce_flag) ); |
| 452 | magic = tg->ce_flag & F_PERCENT0x0800; |
| 453 | |
| 454 | |
| 455 | /* NOTE: For targets that are magic or special we ignore any |
| 456 | * previously defined rules, ie. We throw away the old definition |
| 457 | * and use the new, otherwise we complain. */ |
| 458 | if( !(tg->ce_flag & F_MULTI0x0002) && !magic && (tg->CE_RECIPEce_recipe != NIL(STRING)((STRING*)((void*)0))) |
| 459 | && !_sp_target && (_sv_rules != NIL(STRING)((STRING*)((void*)0))) ) |
| 460 | Fatal( "Multiply defined recipe for target %s", tg->CE_NAMEce_name->ht_name ); |
| 461 | |
| 462 | if( (magic || _sp_target) && (_sv_rules == NIL(STRING)((STRING*)((void*)0))) && |
| 463 | !(tg->ce_flag & F_SPECIAL0x0100) && !_sv_globprq_only ) |
| 464 | Warning( "Empty recipe for special or meta target %s", tg->CE_NAMEce_name->ht_name ); |
| 465 | |
| 466 | if( magic ) { |
| 467 | CELLPTR ep; |
| 468 | |
| 469 | for( ep=_sv_edgel; ep != NIL(CELL)((CELL*)((void*)0)); ep=ep->ce_link ) { |
| 470 | DB_PRINT( "par", ("ep address: %#x", ep) ); |
| 471 | /* %.xx :| '%.yy' abc xx '%.tt' ; touch $@ |
| 472 | * loops here ... */ |
| 473 | _set_attributes( _sv_attr, _sv_setdir, ep ); |
| 474 | ep->ce_flag |= (F_TARGET0x0008|flag); |
| 475 | |
| 476 | if( _sv_rules != NIL(STRING)((STRING*)((void*)0)) ) { |
| 477 | ep->ce_recipe = _sv_rules; |
| 478 | ep->ce_indprq = _sv_ind_prq; |
| 479 | } |
| 480 | } |
| 481 | } |
| 482 | else { |
| 483 | tg->ce_attr |= _sv_attr; |
| 484 | tg->ce_flag |= flag; |
| 485 | |
| 486 | if( _sv_rules != NIL(STRING)((STRING*)((void*)0)) ) { |
| 487 | tg->ce_recipe = _sv_rules; |
| 488 | tg->ce_flag |= F_RULES0x0010 | F_TARGET0x0008; |
| 489 | |
| 490 | /* Bind the current set of prerequisites as belonging to the |
| 491 | * original recipe given for the target */ |
| 492 | for( lp=tg->ce_prq; lp != NIL(LINK)((LINK*)((void*)0)); lp = lp->cl_next ) |
| 493 | if( !(lp->cl_flag & F_VISITED0x0080) ) lp->cl_flag |= F_TARGET0x0008; |
| 494 | } |
| 495 | else for( lp=tg->ce_prq; lp != NIL(LINK)((LINK*)((void*)0)); lp = lp->cl_next ) |
| 496 | lp->cl_flag |= F_VISITED0x0080; |
| 497 | } |
| 498 | |
| 499 | tflag |= _add_root(tg); |
| 500 | } |
| 501 | |
| 502 | if( tflag ) Target = TRUE1; |
| 503 | if( _sv_setdir ) FREE(_sv_setdir)free((char*)(_sv_setdir)); |
| 504 | _sv_rules = NIL(STRING)((STRING*)((void*)0)); |
| 505 | _sv_crule = NIL(STRING)((STRING*)((void*)0)); |
| 506 | _sv_targets = NIL(CELL)((CELL*)((void*)0)); |
| 507 | _sv_ind_prq = NIL(LINK)((LINK*)((void*)0)); |
| 508 | _sv_edgel = NIL(CELL)((CELL*)((void*)0)); |
| 509 | _sp_target = FALSE0; |
| 510 | _sv_globprq_only = 0; |
| 511 | |
| 512 | DB_VOID_RETURNreturn; |
| 513 | } |
| 514 | |
| 515 | |
| 516 | |
| 517 | PUBLIC int |
| 518 | Set_group_attributes( list )/* |
| 519 | ============================== |
| 520 | Scan list looking for the standard @,-,% and + (as in recipe line |
| 521 | defs) (+ is set but ignored for group recipes) |
| 522 | and set the flags accordingly so that they apply when we bind the |
| 523 | rules to the appropriate targets. |
| 524 | Return TRUE if group recipe start '[' was found, otherwise FALSE. */ |
| 525 | char *list; |
| 526 | { |
| 527 | int res = FALSE0; |
| 528 | char *s; |
| 529 | |
| 530 | if ( !((_sv_attr|Glob_attr)&A_IGNOREGROUP0x10000) ) { |
| 531 | s = DmStrSpn(list,"@-%+ \t"); |
| 532 | res = (*s == '['); |
| 533 | if( res ) { |
| 534 | /* Check for non-white space characters after the [. */ |
| 535 | for( s++; *s && iswhite(*s)((*s == ' ') || (*s == '\t')) ; s++ ) |
| 536 | ; |
| 537 | if( *s ) |
| 538 | Warning("Found non-white space character after '[' in [%s].", list); |
| 539 | |
| 540 | _sv_attr |= Rcp_attribute(list); |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | return(res); |
| 545 | } |
| 546 | |
| 547 | |
| 548 | static void |
| 549 | _do_special( special, op, attr, set_dir, target, prereq, state )/* |
| 550 | ================================================================== |
| 551 | Process a special target (always only a single target). So far the only |
| 552 | special targets we have are those recognized by the _is_special function. |
| 553 | Some of the special targets can take recipes, they call _do_targets() |
| 554 | and (implicitly) set *state to to RULE_SCAN. Otherwise *state remains |
| 555 | unaffected, i.e. NORMAL_SCAN. |
| 556 | |
| 557 | target is always only a single special target. |
| 558 | |
| 559 | NOTE: For the cases of .IMPORT, and .INCLUDE, the cells created by the |
| 560 | parser are never freed. This is due to the fact that it is too much |
| 561 | trouble to get them out of the hash table once they are defined, and |
| 562 | if they are per chance used again it will be ok, anyway, since the |
| 563 | cell is not really used by the code below. */ |
| 564 | |
| 565 | int special; |
| 566 | int op; |
| 567 | t_attr attr; |
| 568 | char *set_dir; |
| 569 | CELLPTR target; |
| 570 | CELLPTR prereq; |
| 571 | int *state; |
| 572 | { |
| 573 | HASHPTR hp; /* pointer to macro def cell */ |
| 574 | CELLPTR cp; /* temporary pointer into cells list */ |
| 575 | CELLPTR dp; /* pointer to directory dir cell */ |
| 576 | LINKPTR lp; /* pointer at prerequisite list */ |
| 577 | char *dir; /* current dir to prepend */ |
| 578 | char *path; /* resulting path to try to read */ |
| 579 | char *name; /* File name for processing a .INCLUDE */ |
| 580 | char *tmp; /* temporary string pointer */ |
| 581 | FILE *fil; /* File descriptor returned by Openfile */ |
| 582 | |
| 583 | DB_ENTER( "_do_special" ); |
| 584 | |
| 585 | target->ce_flag = F_SPECIAL0x0100; /* mark the target as special */ |
| 586 | |
| 587 | switch( special ) { |
| 588 | case ST_EXPORT8: |
| 589 | for( ; prereq != NIL(CELL)((CELL*)((void*)0)); prereq = prereq->ce_link ) { |
| 590 | DB_PRINT( "par", ("Exporting [%s]", prereq->CE_NAME) ); |
| 591 | hp = GET_MACRO( prereq->CE_NAME )Get_name(prereq->ce_name->ht_name, Macs, 0); |
| 592 | |
| 593 | if( hp != NIL(HASH)((HASH*)((void*)0)) ) { |
| 594 | char *tmpstr = hp->ht_value; |
| 595 | |
| 596 | if( tmpstr == NIL(char)((char*)((void*)0)) ) tmpstr = ""; |
| 597 | |
| 598 | if( Write_env_string( prereq->CE_NAMEce_name->ht_name, tmpstr ) != 0 ) |
| 599 | Warning( "Could not export %s", prereq->CE_NAMEce_name->ht_name ); |
| 600 | } |
| 601 | } |
| 602 | break; |
| 603 | |
| 604 | /* Simply cause the parser to fail on the next input read */ |
| 605 | case ST_EXIT12: |
| 606 | Skip_to_eof = TRUE1; |
| 607 | break; |
| 608 | |
| 609 | case ST_IMPORT9: |
| 610 | for( ; prereq != NIL(CELL)((CELL*)((void*)0)); prereq = prereq->ce_link ) { |
| 611 | char *tmpstr; |
| 612 | |
| 613 | DB_PRINT( "par", ("Importing [%s]", prereq->CE_NAME) ); |
| 614 | |
| 615 | if( strcmp(prereq->CE_NAMEce_name->ht_name, ".EVERYTHING") == 0 ) { |
| 616 | t_attr sattr = Glob_attr; |
| 617 | Glob_attr |= A_SILENT0x00002; |
| 618 | |
| 619 | ReadEnvironment(); |
| 620 | |
| 621 | Glob_attr = sattr; |
| 622 | } |
| 623 | else { |
| 624 | tmpstr = Read_env_string( prereq->CE_NAMEce_name->ht_name ); |
| 625 | |
| 626 | if( tmpstr != NIL(char)((char*)((void*)0)) ) |
| 627 | Def_macro(prereq->CE_NAMEce_name->ht_name, tmpstr, M_EXPANDED0x0008|M_LITERAL0x0020); |
| 628 | else |
| 629 | if( !((Glob_attr | attr) & A_IGNORE0x00020) ) |
| 630 | Fatal("Imported macro `%s' not found",prereq->CE_NAMEce_name->ht_name); |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | attr &= ~A_IGNORE0x00020; |
| 635 | break; |
| 636 | |
| 637 | case ST_INCLUDE5: |
| 638 | { |
| 639 | int pushed = FALSE0; |
| 640 | int first = (attr & A_FIRST0x20000000); |
| 641 | int ignore = (((Glob_attr | attr) & A_IGNORE0x00020) != 0); |
| 642 | int found = FALSE0; |
| 643 | int noinf = (attr & A_NOINFER0x00080); |
| 644 | LINKPTR prqlnk = NIL(LINK)((LINK*)((void*)0)); |
| 645 | LINKPTR prqlst = NIL(LINK)((LINK*)((void*)0)); |
| 646 | |
| 647 | if( prereq == NIL(CELL)((CELL*)((void*)0)) ) Fatal( "No .INCLUDE file(s) specified" ); |
| 648 | |
| 649 | dp = Def_cell( ".INCLUDEDIRS" ); |
| 650 | |
| 651 | if( (attr & A_SETDIR0x00400) && *(dir = strchr(set_dir, '=')+1) ) |
| 652 | pushed = Push_dir( dir, ".INCLUDE", ignore ); |
| 653 | |
| 654 | for( cp=prereq; cp != NIL(CELL)((CELL*)((void*)0)); cp = cp->ce_link ) { |
| 655 | LINKPTR ltmp; |
| 656 | TALLOC(ltmp, 1, LINK)if ((ltmp = (LINK*) calloc((unsigned int)(1), (size_t)sizeof( LINK))) == (LINK*)0) {No_ram();}; |
| 657 | ltmp->cl_prq = cp; |
| 658 | |
| 659 | if( prqlnk == NIL(LINK)((LINK*)((void*)0)) ) |
| 660 | prqlst = ltmp; |
| 661 | else |
| 662 | prqlnk->cl_next = ltmp; |
| 663 | |
| 664 | prqlnk = ltmp; |
| 665 | } |
| 666 | |
| 667 | for( ; prqlst != NIL(LINK)((LINK*)((void*)0)); FREE(prqlst)free((char*)(prqlst)), prqlst=prqlnk ) { |
| 668 | prqlnk = prqlst->cl_next; |
| 669 | cp = prqlst->cl_prq; |
| 670 | name = cp->CE_NAMEce_name->ht_name; |
| 671 | |
| 672 | /* Leave this here, it ensures that prqlst gets propely free'd */ |
| 673 | if ( first && found ) |
| 674 | continue; |
| 675 | |
| 676 | if( *name == '<' ) { |
| 677 | /* We have a file name enclosed in <....> |
| 678 | * so get rid of the <> arround the file name */ |
| 679 | |
| 680 | name++; |
| 681 | if( (tmp = strrchr( name, '>' )) != NIL( char )((char*)((void*)0)) ) |
| 682 | *tmp = 0; |
| 683 | |
| 684 | if( If_root_path( name ) ) |
| 685 | fil = Openfile( name, FALSE0, FALSE0 ); |
| 686 | else |
| 687 | fil = NIL(FILE)((FILE*)((void*)0)); |
| 688 | } |
| 689 | else |
| 690 | fil = Openfile( name, FALSE0, FALSE0 ); |
| 691 | |
| 692 | if( fil == NIL(FILE)((FILE*)((void*)0)) && !If_root_path( name ) ) { /*if true ==> not found in current dir*/ |
| 693 | |
| 694 | /* Now we must scan the list of prerequisites for .INCLUDEDIRS |
| 695 | * looking for the file in each of the specified directories. |
| 696 | * if we don't find it then we issue an error. The error |
| 697 | * message is suppressed if the .IGNORE attribute of attr is |
| 698 | * set. If a file is found we call Parse on the file to |
| 699 | * perform the parse and then continue on from where we left |
| 700 | * off. */ |
| 701 | |
| 702 | for(lp=dp->CE_PRQce_prq; lp && fil == NIL(FILE)((FILE*)((void*)0)); lp=lp->cl_next) { |
| 703 | dir = lp->cl_prq->CE_NAMEce_name->ht_name; |
| 704 | if( strchr(dir, '$') ) dir = Expand(dir); |
| 705 | path = Build_path( dir, name ); |
| 706 | |
| 707 | DB_PRINT( "par", ("Trying to include [%s]", path) ); |
| 708 | |
| 709 | fil = Openfile( path, FALSE0, FALSE0 ); |
| 710 | if( dir != lp->cl_prq->CE_NAMEce_name->ht_name ) FREE(dir)free((char*)(dir)); |
| 711 | } |
| 712 | } |
| 713 | |
| 714 | if (!noinf && fil == NIL(FILE)((FILE*)((void*)0))) { |
| 715 | t_attr glob = Glob_attr; |
| 716 | t_attr cattr = prqlst->cl_prq->ce_attr; |
| 717 | |
| 718 | prqlst->cl_next = NIL(LINK)((LINK*)((void*)0)); |
| 719 | Glob_attr |= (attr&A_IGNORE0x00020); |
| 720 | prqlst->cl_prq->ce_attr &= ~A_FRINGE0x100000; |
| 721 | |
| 722 | if( Verbose & V_FILE_IO0x20 ) |
| 723 | printf( "%s: Inferring include file [%s].\n", |
| 724 | Pname, name ); |
| 725 | fil = TryFiles(prqlst); |
| 726 | |
| 727 | Glob_attr = glob; |
| 728 | prqlst->cl_prq->ce_attr |= (cattr & A_FRINGE0x100000); |
| 729 | } |
| 730 | |
| 731 | if( fil != NIL(FILE)((FILE*)((void*)0)) ) { |
| 732 | if( Verbose & V_FILE_IO0x20 ) |
| 733 | printf( "%s: Parsing include file [%s].\n", |
| 734 | Pname, name ); |
| 735 | Parse( fil ); |
| 736 | found = TRUE1; |
| 737 | } |
| 738 | else if( !(ignore || first) ) |
| 739 | Fatal( "Include file %s, not found", name ); |
| 740 | else if( Verbose & V_FILE_IO0x20 ) |
| 741 | printf( "%s: Include file [%s] was not found.\n", |
| 742 | Pname, name ); |
| 743 | } |
| 744 | |
| 745 | if ( !ignore && first && !found ) |
| 746 | Fatal( "No include file was found" ); |
| 747 | |
| 748 | if( pushed ) Pop_dir(FALSE0); |
| 749 | attr &= ~(A_IGNORE0x00020|A_SETDIR0x00400|A_FIRST0x20000000|A_NOINFER0x00080); |
| 750 | } |
| 751 | break; |
| 752 | |
| 753 | case ST_SOURCE7: |
| 754 | if( prereq != NIL(CELL)((CELL*)((void*)0)) ) |
| 755 | _do_targets( op & (R_OP_CL1 | R_OP_MI16 | R_OP_UP8), attr, set_dir, |
| 756 | target, prereq ); |
| 757 | else { |
| 758 | /* The old semantics of .SOURCE were that an empty list of |
| 759 | * prerequisites clears the .SOURCE list. So we must implement |
| 760 | * that here as a clearout prerequisite operation. Since this is |
| 761 | * a standard operation with the :- opcode we can simply call the |
| 762 | * proper routine with the target cell and it should do the trick |
| 763 | */ |
| 764 | |
| 765 | if( op == R_OP_CL1 || (op & R_OP_MI16) ) |
| 766 | Clear_prerequisites( target ); |
| 767 | } |
| 768 | |
| 769 | op &= ~(R_OP_MI16 | R_OP_UP8); |
| 770 | break; |
| 771 | |
| 772 | case ST_KEEP11: |
| 773 | if( Keep_state != NIL(char)((char*)((void*)0)) ) break; |
| 774 | Def_macro( ".KEEP_STATE", "_state.mk", M_EXPANDED0x0008 ); |
| 775 | break; |
| 776 | |
| 777 | case ST_REST4: |
| 778 | /* The rest of the special targets can all take recipes, as such they |
| 779 | * must be able to affect the state of the parser. */ |
| 780 | |
| 781 | { |
| 782 | int s_targ = Target; |
| 783 | |
| 784 | Target = TRUE1; |
| 785 | _sp_target = TRUE1; |
| 786 | *state = _do_targets( op, attr, set_dir, target, prereq ); |
| 787 | Target = s_targ; |
| 788 | |
| 789 | target->ce_flag |= F_TARGET0x0008; |
| 790 | |
| 791 | attr = A_DEFAULT0x00000; |
| 792 | op = R_OP_CL1; |
| 793 | } |
| 794 | break; |
| 795 | |
| 796 | default:break; |
| 797 | } |
| 798 | |
| 799 | if( op != R_OP_CL1 ) Warning( "Modifier(s) for operator ignored" ); |
| 800 | if( attr != A_DEFAULT0x00000 ) Warning( "Extra attributes ignored" ); |
| 801 | |
| 802 | DB_VOID_RETURNreturn; |
| 803 | } |
| 804 | |
| 805 | |
| 806 | static int |
| 807 | _do_targets( op, attr, set_dir, targets, prereq )/* |
| 808 | =================================================== |
| 809 | Evaluate the values derived from the current target definition |
| 810 | line. Helper functions _build_graph(), _do_magic(), _make_multi(), |
| 811 | _add_root(), _replace_cell(), _set_attributes(), Clear_prerequisites() |
| 812 | _stick_at_head(), Add_prerequisite() and _set_global_attr() are used. |
| 813 | If successfull "_sv_targets" is set to "targets". |
| 814 | Return RULE_SCAN if a recipe is expected to follow, otherwise |
| 815 | NORMAL_SCAN. */ |
| 816 | int op; /* rule operator */ |
| 817 | t_attr attr; /* attribute flags for current targets */ |
| 818 | char *set_dir; /* value of setdir attribute */ |
| 819 | CELLPTR targets; /* list of targets (each cell maybe already |
| 820 | * defined by a previous target definition |
| 821 | * line. */ |
| 822 | CELLPTR prereq; /* list of prerequisites */ |
| 823 | { |
| 824 | CELLPTR tg1; /* temporary target pointer */ |
| 825 | CELLPTR tp1; /* temporary prerequisite pointer */ |
| 826 | LINKPTR prev_cell; /* pointer for .UPDATEALL processing */ |
| 827 | char *p; /* temporary char pointer */ |
| 828 | int tflag = FALSE0; /* set to TRUE if we add target to root */ |
| 829 | int ret_state = RULE_SCAN1; /* Return state */ |
| 830 | |
| 831 | DB_ENTER( "_do_targets" ); |
| 832 | |
| 833 | /* If .UPDATEALL is set sort the target list that was temporary linked |
| 834 | * with ce_link into a list using ce_link with ce_set pointing to the first |
| 835 | * element. */ |
| 836 | /* FIXME: Check that .UPDATEALL and %-targets on one line work together. */ |
| 837 | if( attr & A_UPDATEALL0x00100 ) { |
| 838 | if( targets == NIL(CELL)((CELL*)((void*)0)) ) |
| 839 | Fatal( ".UPDATEALL attribute requires non-empty list of targets" ); |
| 840 | |
| 841 | if (targets->ce_set == NIL(CELL)((CELL*)((void*)0))) { |
| 842 | for( |
| 843 | prev_cell=CeMeToo(targets)&((targets)->ce_all),tg1=targets->ce_link; |
| 844 | tg1 != NIL(CELL)((CELL*)((void*)0)); |
| 845 | tg1=tg1->ce_link |
| 846 | ) { |
| 847 | if (tg1->ce_set) |
| 848 | Fatal( "Target [%s] appears on multiple .UPDATEALL lists", |
| 849 | tg1->CE_NAMEce_name->ht_name); |
| 850 | tg1->ce_set = targets; |
| 851 | TALLOC(prev_cell->cl_next, 1, LINK)if ((prev_cell->cl_next = (LINK*) calloc((unsigned int)(1) , (size_t)sizeof(LINK))) == (LINK*)0) {No_ram();}; |
| 852 | prev_cell = prev_cell->cl_next; |
| 853 | prev_cell->cl_prq = tg1; |
| 854 | } |
| 855 | targets->ce_set = targets; |
| 856 | } |
| 857 | else { |
| 858 | LINKPTR ap; |
| 859 | CELLPTR tp; |
| 860 | |
| 861 | tp = targets; |
| 862 | ap = CeMeToo(targets)&((targets)->ce_all); |
| 863 | while (ap && tp && ap->cl_prq == tp && tp->ce_set == targets) { |
| 864 | ap = ap->cl_next; |
| 865 | tp = tp->ce_link; |
| 866 | } |
| 867 | if (ap || tp) |
| 868 | Fatal("Inconsistent .UPDATEALL lists for target [%s]", |
| 869 | targets->CE_NAMEce_name->ht_name); |
| 870 | } |
| 871 | targets->ce_link = NIL(CELL)((CELL*)((void*)0)); |
| 872 | } |
| 873 | |
| 874 | for( tg1 = targets; tg1 != NIL(CELL)((CELL*)((void*)0)); tg1 = tg1->ce_link ) { |
| 875 | /* Check if tg1 is already marked as a %-target, but not a magic |
| 876 | * (.xxx.yyy) target. */ |
| 877 | int purepercent = (tg1->ce_flag & F_PERCENT0x0800) && !(tg1->ce_flag & F_MAGIC0x2000); |
| 878 | |
| 879 | /* Check each target. Check for inconsistencies between :: and : rule |
| 880 | * sets. :: may follow either : or :: but not the reverse. |
| 881 | * |
| 882 | * Any F_MULTI target (contains :: rules) is represented by a prerequisite |
| 883 | * list hanging off the main target cell where each of the prerequisites |
| 884 | * is a copy of the target cell but is not entered into the hash table. |
| 885 | */ |
| 886 | if( !(op & R_OP_DCL2 ) && (tg1->ce_flag & F_MULTI0x0002) && !purepercent ) |
| 887 | Fatal( "':' vs '::' inconsistency in rules for %s", tg1->CE_NAMEce_name->ht_name ); |
| 888 | |
| 889 | if( purepercent ) { |
| 890 | /* Handle %-targets. */ |
| 891 | CELLPTR cur; |
| 892 | CELLPTR tpq = NIL(CELL)((CELL*)((void*)0)); |
| 893 | CELLPTR nprq = NULL((void*)0); |
| 894 | |
| 895 | #ifdef DBUG |
| 896 | DB_PRINT( "%", ("Handling %%-target [%s : : <prerequisites follow, maybe empty>]", |
| 897 | tg1->CE_NAME) ); |
| 898 | for(cur=prereq;cur;cur=cur->ce_link) { |
| 899 | DB_PRINT( "%", (" %%-prerequisites : %s ", |
| 900 | cur->CE_NAME ? cur->CE_NAME : "<empty>") ); |
| 901 | } |
| 902 | #endif |
| 903 | |
| 904 | /* Handle indirect (global) prerequisites first. */ |
| 905 | for(cur=prereq;cur;cur=cur->ce_link) { |
| 906 | char *name = cur->CE_NAMEce_name->ht_name; |
| 907 | int len = strlen(name); |
| 908 | |
| 909 | if( *name == '\'' && name[len-1]=='\'' ){ |
| 910 | name[len-1] = '\0'; |
| 911 | len = strlen(name+1)+1; |
| 912 | memmove(name,name+1,len); |
| 913 | /* add indirect prerequisite */ |
| 914 | _add_indirect_prereq( cur ); |
| 915 | } |
| 916 | else { |
| 917 | /* Sort all "other" prerequisits into tpq, with nprq |
| 918 | * pointing to the first element. */ |
| 919 | if (tpq) |
| 920 | tpq->ce_link = cur; |
| 921 | else |
| 922 | nprq = cur; |
| 923 | tpq = cur; |
| 924 | } |
| 925 | } |
| 926 | /* Mark the last element of nprq. */ |
| 927 | if(tpq) |
| 928 | tpq->ce_link=NIL(CELL)((CELL*)((void*)0)); |
| 929 | else |
| 930 | nprq = NIL(CELL)((CELL*)((void*)0)); |
| 931 | |
| 932 | /* Handle "normal" prerequisites now. */ |
| 933 | |
| 934 | if ( op & R_OP_OR32 ) { |
| 935 | /* for op == ':|' transform: |
| 936 | * <%-target> :| <prereq_1> ... <prereq_n> ; <recipe> |
| 937 | * into: |
| 938 | * <%-target> : <prereq_1> ; <recipe> |
| 939 | * .. |
| 940 | * <%-target> : <prereq_n> ; <recipe> |
| 941 | */ |
| 942 | for(tp1=nprq; tp1; tp1=tp1->ce_link) { |
| 943 | CELLPTR tmpcell = tp1->ce_link; |
| 944 | tp1->ce_link = NIL(CELL)((CELL*)((void*)0)); |
| 945 | _build_graph(op,tg1,tp1); |
| 946 | tp1->ce_link = tmpcell; |
| 947 | } |
| 948 | } |
| 949 | else { |
| 950 | /* The inference mechanism for %-targets limits the number of |
| 951 | * (non-indirect) prerequisite to one, but an unlimited number |
| 952 | * of indirect prerequisites is possible. */ |
| 953 | if ( nprq && nprq->ce_link && !(op & R_OP_OR32)) |
| 954 | Warning("More than one prerequisite\n" |
| 955 | "for %%-target. Use :| ruleop or indirect prerequisites."); |
| 956 | |
| 957 | _build_graph(op,tg1,nprq); |
| 958 | } |
| 959 | } |
| 960 | else if( tg1->ce_flag & F_MAGIC0x2000 && |
| 961 | (p = _is_magic( tg1->CE_NAMEce_name->ht_name )) != NIL(char)((char*)((void*)0)) && |
| 962 | _do_magic( op, p, tg1, prereq, attr, set_dir ) ) |
| 963 | ; /* _do_magic() does all that is needed (if return value is TRUE). */ |
| 964 | else if( op & R_OP_DCL2 ) { /* op == :: */ |
| 965 | CELLPTR tmp_cell = _make_multi(tg1); |
| 966 | |
| 967 | /* Add the F_MULTI master to .TARGETS (If not set already). |
| 968 | * Do this here so that the member cell is not added instead |
| 969 | * when the recipies are bound in Bind_rules_to_targets(). */ |
| 970 | tflag |= _add_root(tg1); |
| 971 | |
| 972 | /* Replace the F_MULTI master with the member cell. */ |
| 973 | targets = _replace_cell( targets, tg1, tmp_cell ); |
| 974 | |
| 975 | /* We have to set (add) the attributes also for the F_MULTI master |
| 976 | * target cell. As there is no recipe the setdir value is not |
| 977 | * needed. _set_attributes() that follows in approx. 8 lines |
| 978 | * will set the attributes for the F_MULTI member cell. */ |
| 979 | tg1->ce_attr |= (attr & ~A_SETDIR0x00400); |
| 980 | |
| 981 | /* Now switch tg1 to the current (F_MULTI prereq.) target. |
| 982 | * All recipes have to be added to that cell and not to the |
| 983 | * F_MULTI master. */ |
| 984 | tg1 = tmp_cell; |
| 985 | } |
| 986 | |
| 987 | if( !purepercent ) _set_attributes( attr, set_dir, tg1 ); |
| 988 | |
| 989 | /* Build the proper prerequisite list of the target. If the `-', |
| 990 | * modifier was used clear the prerequisite list before adding any |
| 991 | * new prerequisites. Else add them to the head/tail as appropriate. |
| 992 | * |
| 993 | * If the target has F_PERCENT set then no prerequisites are used. */ |
| 994 | |
| 995 | if( !(tg1->ce_flag & F_PERCENT0x0800) ) { |
| 996 | if( op & R_OP_MI16 ) Clear_prerequisites( tg1 ); /* op == :- */ |
| 997 | |
| 998 | if( (op & R_OP_UP8) && (tg1->ce_prq != NIL(LINK)((LINK*)((void*)0))) ) /* op == :^ */ |
| 999 | _stick_at_head( tg1, prereq ); |
| 1000 | else for( tp1=prereq; tp1 != NIL(CELL)((CELL*)((void*)0)); tp1 = tp1->ce_link ) |
| 1001 | Add_prerequisite( tg1, tp1, FALSE0, FALSE0 ); |
| 1002 | } |
| 1003 | else if( op & (R_OP_MI16 | R_OP_UP8) ) |
| 1004 | Warning( "Modifier(s) `^-' for %-meta target ignored" ); |
| 1005 | } |
| 1006 | |
| 1007 | /* In case a F_MULTI member that was the first prerequisite of .TARGETS */ |
| 1008 | if(tflag) |
| 1009 | Target = TRUE1; |
| 1010 | |
| 1011 | /* Check to see if we have NO targets but some attributes, i.e. an |
| 1012 | * Attribute-Definition. If so then apply all of the attributes to the |
| 1013 | * complete list of prerequisites. No recipes are allowed to follow. */ |
| 1014 | |
| 1015 | if( (targets == NIL(CELL)((CELL*)((void*)0))) && attr ) { |
| 1016 | ret_state = NORMAL_SCAN0; |
| 1017 | if( prereq != NIL(CELL)((CELL*)((void*)0)) ) |
| 1018 | for( tp1=prereq; tp1 != NIL(CELL)((CELL*)((void*)0)); tp1 = tp1->ce_link ) |
| 1019 | _set_attributes( attr, set_dir, tp1 ); |
| 1020 | else |
| 1021 | _set_global_attr( attr ); |
| 1022 | } |
| 1023 | |
| 1024 | /* Now that we have built the lists of targets, the parser must parse the |
| 1025 | * recipes if there are any. However we must start the recipe list with the |
| 1026 | * recipe specified as via the ; kludge, if there is one */ |
| 1027 | _sv_targets = targets; |
| 1028 | _sv_attr = attr; |
| 1029 | _sv_flag = ((op & R_OP_BG4) ? F_SINGLE0x0004 : F_DEFAULT0x0000); |
| 1030 | |
| 1031 | DB_RETURN( ret_state )return (ret_state); |
| 1032 | } |
| 1033 | |
| 1034 | |
| 1035 | static int |
| 1036 | _do_magic( op, dot, target, prereq, attr, set_dir )/* |
| 1037 | ===================================================== |
| 1038 | This function investigates dot for being a magic target of the form |
| 1039 | .<chars>.<chars> or .<chars> and creates the appropriate % rules for |
| 1040 | that target. |
| 1041 | If the target is given with an undefined syntax, i.e. with prerequisites, |
| 1042 | then this function terminates early without creating % rules and |
| 1043 | returns 0. |
| 1044 | If successful the function returns 1. |
| 1045 | |
| 1046 | The function builds the % rule, `%.o : %.c' from .c.o, and |
| 1047 | `% : %.a' from .a */ |
| 1048 | |
| 1049 | int op; |
| 1050 | char *dot; |
| 1051 | CELLPTR target; |
| 1052 | CELLPTR prereq; |
| 1053 | t_attr attr; |
| 1054 | char *set_dir; |
| 1055 | { |
| 1056 | CELLPTR tg; |
| 1057 | CELLPTR prq; |
| 1058 | char *tmp, *tmp2; |
| 1059 | |
| 1060 | DB_ENTER( "_do_magic" ); |
| 1061 | |
| 1062 | DB_PRINT("%", ("Analysing magic target [%s]", target->CE_NAME)); |
| 1063 | |
| 1064 | if( prereq != NIL(CELL)((CELL*)((void*)0)) ) { |
| 1065 | Warning( "Ignoring AUGMAKE meta-target [%s] because prerequisites are present.", target->CE_NAMEce_name->ht_name ); |
| 1066 | DB_RETURN(0)return (0); |
| 1067 | } |
| 1068 | |
| 1069 | if( dot == target->CE_NAMEce_name->ht_name ) { /* its of the form .a */ |
| 1070 | tg = Def_cell( "%" ); |
| 1071 | tmp = _build_meta( target->CE_NAMEce_name->ht_name ); |
| 1072 | prq = Def_cell( tmp ); |
| 1073 | FREE( tmp )free((char*)(tmp)); |
| 1074 | |
| 1075 | _build_graph( op, tg, prq ); |
| 1076 | } |
| 1077 | else { |
| 1078 | tmp = _build_meta( dot ); |
| 1079 | tg = Def_cell( tmp ); |
| 1080 | FREE( tmp )free((char*)(tmp)); |
| 1081 | |
| 1082 | tmp = _build_meta( tmp2 = DmSubStr( target->CE_NAMEce_name->ht_name, dot ) ); |
| 1083 | prq = Def_cell( tmp ); |
| 1084 | FREE( tmp )free((char*)(tmp)); |
| 1085 | FREE( tmp2 )free((char*)(tmp2)); |
| 1086 | |
| 1087 | _build_graph( op, tg, prq ); |
| 1088 | } |
| 1089 | |
| 1090 | tg->ce_flag |= F_PERCENT0x0800; |
| 1091 | target->ce_flag |= (F_MAGIC0x2000|F_PERCENT0x0800); |
| 1092 | |
| 1093 | _set_attributes( attr, set_dir, tg ); |
| 1094 | |
| 1095 | DB_RETURN(1)return (1); |
| 1096 | } |
| 1097 | |
| 1098 | |
| 1099 | static CELLPTR |
| 1100 | _replace_cell( lst, cell, rep )/* |
| 1101 | ================================= |
| 1102 | Replace cell with rep in lst. Note if cell is not part of lst we are in |
| 1103 | real trouble. */ |
| 1104 | CELLPTR lst; |
| 1105 | CELLPTR cell; |
| 1106 | CELLPTR rep; |
| 1107 | { |
| 1108 | register CELLPTR tp; |
| 1109 | |
| 1110 | if( lst == cell ) { |
| 1111 | rep->ce_link = lst->ce_link; |
| 1112 | lst = rep; |
| 1113 | } |
| 1114 | else { |
| 1115 | for( tp=lst; tp->ce_link != cell && tp ; tp=tp->ce_link ); |
| 1116 | if( !tp ) |
| 1117 | Fatal( "Internal Error: cell not part of lst." ); |
| 1118 | rep->ce_link = tp->ce_link->ce_link; |
| 1119 | tp->ce_link = rep; |
| 1120 | } |
| 1121 | |
| 1122 | return(lst); |
| 1123 | } |
| 1124 | |
| 1125 | |
| 1126 | static char * |
| 1127 | _build_meta( name )/* |
| 1128 | ===================== |
| 1129 | Check to see if the name is of the form .c~ if so and if Augmake |
| 1130 | translation is enabled then return s.%.c, else return %.suff, where if the |
| 1131 | suffix ends in '~' then leave it be.*/ |
| 1132 | char *name; |
| 1133 | { |
| 1134 | char *tmp; |
| 1135 | int test = (STOBOOL(Augmake)(Augmake && ((*Augmake | 0x20) == 'y')) ? name[strlen(name)-1] == '~' : 0); |
| 1136 | |
| 1137 | tmp = DmStrJoin( test ? "s.%" : "%", name, -1, FALSE0); |
| 1138 | if( test ) tmp[ strlen(tmp)-1 ] = '\0'; |
| 1139 | |
| 1140 | return(tmp); |
| 1141 | } |
| 1142 | |
| 1143 | |
| 1144 | static CELLPTR |
| 1145 | _build_graph( op, target, prereq )/* |
| 1146 | ==================================== |
| 1147 | This function is called to build the graph for the % rule given by |
| 1148 | target : prereq cell combination. This function assumes that target |
| 1149 | is a % target and that prereq is one or multiple non-indirect prerequisite. |
| 1150 | It also assumes that target cell has F_PERCENT set already. |
| 1151 | |
| 1152 | NOTE: If more than one prerequisite is present this function handles them |
| 1153 | correctly but the lookup still only uses the first (BUG!). |
| 1154 | |
| 1155 | R_OP_CL (:) rules replace existing rules if any, %.o :: %.c is meaningless. |
| 1156 | |
| 1157 | The function always returns NIL(CELL). */ |
| 1158 | int op; |
| 1159 | CELLPTR target; |
| 1160 | CELLPTR prereq; |
| 1161 | { |
| 1162 | LINKPTR edl; |
| 1163 | CELLPTR edge = 0; |
| 1164 | CELLPTR tpq,cur; |
| 1165 | int match; |
| 1166 | |
| 1167 | #ifdef DBUG |
| 1168 | DB_ENTER( "_build_graph" ); |
| 1169 | DB_PRINT( "%", ("Building graph for [%s : <prerequisites follow, maybe empty>]", |
| 1170 | target->CE_NAME) ); |
| 1171 | for(tpq=prereq;tpq;tpq=tpq->ce_link) { |
| 1172 | DB_PRINT( "%", (" %%-prerequisites : %s ", |
| 1173 | tpq->CE_NAME ? tpq->CE_NAME : "<empty>") ); |
| 1174 | } |
| 1175 | #endif |
| 1176 | |
| 1177 | /* Currently multiple prerequisites are not (yet) handled correctly. |
| 1178 | * We already issue a warning in _do_targets(), don't issue it here |
| 1179 | * again. |
| 1180 | if ( prereq && prereq->ce_link ) |
| 1181 | Warning( "Internal Error: more than one prerequisite in _build_graph." ); |
| 1182 | */ |
| 1183 | |
| 1184 | /* There cannot be more than one target name ( linked with |
| 1185 | * (CeMeToo(target))->cl_next ) per %-target master. |
| 1186 | * FIXME: remove this check after verifying that it never triggers. */ |
| 1187 | if ( (CeMeToo(target)&((target)->ce_all))->cl_next ) |
| 1188 | Fatal( "Internal Error: more than one target name in _build_graph." ); |
| 1189 | |
| 1190 | /* Search the list of prerequisites for the current target and see if |
| 1191 | * any of them match the current %-meta's : prereq's pair. NOTE that |
| 1192 | * %-metas are built as if they were F_MULTI targets, i.e. the target |
| 1193 | * definitions for the %-target members are stored in the prerequisites |
| 1194 | * list of the master target. */ |
| 1195 | /* This relies on target->ce_prq being NULL if this is the first |
| 1196 | * occurrence of this %-target and therefore not yet having a %-target |
| 1197 | * master. */ |
| 1198 | match = FALSE0; |
| 1199 | for(edl=target->ce_prq; !match && edl != NIL(LINK)((LINK*)((void*)0)); edl=edl->cl_next) { |
| 1200 | LINKPTR l1,l2; |
| 1201 | edge = edl->cl_prq; |
| 1202 | |
| 1203 | DB_PRINT("%", ("Trying to match [%s]",edge?edge->CE_NAME:"(nil)")); |
| 1204 | |
| 1205 | /* First we match the target sets, if this fails then we don't have to |
| 1206 | * bother with the prerequisite sets. The targets sets are sorted. |
| 1207 | * this makes life very simple. */ |
| 1208 | /* ce_dir is handled per member target, no check needed for the |
| 1209 | * master target. */ |
| 1210 | |
| 1211 | /* FIXME: We already checked above that there is only one target |
| 1212 | * name. Remove the comparisons for following names. */ |
| 1213 | l1 = CeMeToo(target)&((target)->ce_all); /* Used by .UPDATEALL !!! */ |
| 1214 | l2 = CeMeToo(edge)&((edge)->ce_all); |
| 1215 | while(l1 && l2 && l1->cl_prq == l2->cl_prq) { |
| 1216 | l1=l1->cl_next; |
| 1217 | l2=l2->cl_next; |
| 1218 | } |
| 1219 | /* If both l1 and l2 are NULL we had a match. */ |
| 1220 | if (l1 || l2) |
| 1221 | continue; |
| 1222 | |
| 1223 | /* target sets match, so check prerequisites. */ |
| 1224 | if( (!edge->ce_prq && !prereq) /* matches both empty - separate this. */ |
| 1225 | || ( edge->ce_prq |
| 1226 | && ( edge->ce_dir == _sv_setdir |
| 1227 | || ( edge->ce_dir |
| 1228 | && _sv_setdir |
| 1229 | && !strcmp(edge->ce_dir,strchr(_sv_setdir,'=')+1) |
| 1230 | ) |
| 1231 | ) |
| 1232 | ) |
| 1233 | ) { |
| 1234 | LINKPTR prql; |
| 1235 | |
| 1236 | /* this is a really gross way to compare two sets, it's n^2 but |
| 1237 | * since the sets are assumed to always be tiny, it should be ok. */ |
| 1238 | for(tpq=prereq; tpq; tpq=tpq->ce_link) { |
| 1239 | for(prql=edge->ce_prq;prql;prql=prql->cl_next) |
| 1240 | if (prql->cl_prq == tpq) |
| 1241 | break; |
| 1242 | |
| 1243 | if(prql == NIL(LINK)((LINK*)((void*)0))) |
| 1244 | break; |
| 1245 | |
| 1246 | prql->cl_prq->ce_flag |= F_MARK0x0001; |
| 1247 | } |
| 1248 | |
| 1249 | if (tpq == NIL(CELL)((CELL*)((void*)0))) { |
| 1250 | for(prql=edge->ce_prq;prql;prql=prql->cl_next) |
| 1251 | if(!(prql->cl_prq->ce_flag & F_MARK0x0001)) |
| 1252 | break; |
| 1253 | |
| 1254 | if(prql == NIL(LINK)((LINK*)((void*)0))) |
| 1255 | match = TRUE1; |
| 1256 | } |
| 1257 | |
| 1258 | /* clean up the mark bits. */ |
| 1259 | for(prql=edge->ce_prq;prql;prql=prql->cl_next) |
| 1260 | prql->cl_prq->ce_flag &= ~F_MARK0x0001; |
| 1261 | } |
| 1262 | } |
| 1263 | |
| 1264 | if( match ) { |
| 1265 | /* match is TRUE hence, we found an edge joining the target and the |
| 1266 | * prerequisite so reset the new edge so that new values replace it. */ |
| 1267 | DB_PRINT( "%", ("It's an old edge") ); |
| 1268 | |
| 1269 | edge->ce_dir = NIL(char)((char*)((void*)0)); |
| 1270 | edge->ce_flag &= (F_PERCENT0x0800|F_MAGIC0x2000|F_DFA0x0200); |
| 1271 | edge->ce_attr &= A_NOINFER0x00080; |
| 1272 | } |
| 1273 | else { |
| 1274 | DB_PRINT( "%", ("Adding a new edge") ); |
| 1275 | |
| 1276 | edge = _make_multi(target); |
| 1277 | |
| 1278 | /* FIXME: There can be only one %-target. */ |
| 1279 | for(edl=CeMeToo(target)&((target)->ce_all);edl;edl=edl->cl_next) { |
| 1280 | if( !((tpq=edl->cl_prq)->ce_flag & F_DFA0x0200) ) { |
| 1281 | Add_nfa( tpq->CE_NAMEce_name->ht_name ); |
| 1282 | tpq->ce_flag |= F_DFA0x0200; |
| 1283 | } |
| 1284 | |
| 1285 | edl->cl_prq->ce_set = edge; |
| 1286 | } |
| 1287 | |
| 1288 | edge->ce_all = target->ce_all; |
| 1289 | target->ce_all.cl_next = NIL(LINK)((LINK*)((void*)0)); |
| 1290 | target->ce_set = NIL(CELL)((CELL*)((void*)0)); |
| 1291 | |
| 1292 | /* Add all prerequisites to edge. */ |
| 1293 | for(tpq=prereq; tpq; tpq=tpq->ce_link) |
| 1294 | Add_prerequisite(edge, tpq, FALSE0, TRUE1); |
| 1295 | } |
| 1296 | |
| 1297 | if( op & R_OP_DCL2 ) |
| 1298 | Warning("'::' operator for meta-target '%s' ignored, ':' operator assumed.", |
| 1299 | target->CE_NAMEce_name->ht_name ); |
| 1300 | |
| 1301 | /* If edge was already added we're in BIG trouble. */ |
| 1302 | /* Re-use cur as temporary variable. */ |
| 1303 | for( cur=_sv_edgel; cur != NIL(CELL)((CELL*)((void*)0)); cur=cur->ce_link ) { |
| 1304 | if( cur == edge ) |
| 1305 | Fatal( "Internal Error: edge already in _sv_edgel." ); |
| 1306 | } |
| 1307 | |
| 1308 | edge->ce_link = _sv_edgel; |
| 1309 | _sv_edgel = edge; |
| 1310 | _sv_globprq_only = 0; |
| 1311 | |
| 1312 | DB_RETURN(NIL(CELL))return (((CELL*)((void*)0))); |
| 1313 | } |
| 1314 | |
| 1315 | |
| 1316 | static CELLPTR |
| 1317 | _make_multi( tg )/* |
| 1318 | =================== |
| 1319 | This function is called to convert tg into an F_MULTI target. |
| 1320 | Return a pointer to the new member cell. |
| 1321 | I don't know what the author intended but the ce_index entry is only |
| 1322 | used in this function (set to 0 for added targets) and undefined otherwise! |
| 1323 | The undefined value is hopefully set to 0 by the C compiler as each added |
| 1324 | target sets its ce_count to ++ce_index (==1). (FIXME) */ |
| 1325 | CELLPTR tg; |
| 1326 | { |
| 1327 | CELLPTR cp; |
| 1328 | |
| 1329 | /* This creates a new master F_MULTI target if tg existed before as a normal |
| 1330 | * target with prerequisites or recipes. */ |
| 1331 | if( !(tg->ce_flag & F_MULTI0x0002) && (tg->ce_prq || tg->ce_recipe) ) { |
| 1332 | /* Allocate a new master cell. */ |
| 1333 | TALLOC(cp, 1, CELL)if ((cp = (CELL*) calloc((unsigned int)(1), (size_t)sizeof(CELL ))) == (CELL*)0) {No_ram();}; |
| 1334 | *cp = *tg; |
| 1335 | |
| 1336 | /* F_MULTI master */ |
| 1337 | tg->ce_prq = NIL(LINK)((LINK*)((void*)0)); |
| 1338 | tg->ce_flag |= F_RULES0x0010|F_MULTI0x0002|F_TARGET0x0008; |
| 1339 | tg->ce_attr |= A_SEQ0x00200; |
| 1340 | tg->ce_recipe = NIL(STRING)((STRING*)((void*)0)); |
| 1341 | tg->ce_dir = NIL(char)((char*)((void*)0)); |
| 1342 | |
| 1343 | /* F_MULTI member for preexisting elements */ |
| 1344 | cp->ce_count = ++tg->ce_index; |
| 1345 | cp->ce_cond = NIL(STRING)((STRING*)((void*)0)); |
| 1346 | cp->ce_set = NIL(CELL)((CELL*)((void*)0)); |
| 1347 | cp->ce_all.cl_prq = cp; |
| 1348 | CeNotMe(cp)(cp)->ce_all.cl_next = NIL(LINK)((LINK*)((void*)0)); |
| 1349 | |
| 1350 | Add_prerequisite(tg, cp, FALSE0, TRUE1); |
| 1351 | } |
| 1352 | |
| 1353 | /* Alocate memory for new member of F_MULTI target */ |
| 1354 | TALLOC(cp, 1, CELL)if ((cp = (CELL*) calloc((unsigned int)(1), (size_t)sizeof(CELL ))) == (CELL*)0) {No_ram();}; |
| 1355 | *cp = *tg; |
| 1356 | |
| 1357 | /* This is reached if the target already exists, but without having |
| 1358 | * prerequisites or recepies. Morph it into a F_MULTI master cell. */ |
| 1359 | if( !(tg->ce_flag & F_MULTI0x0002) ) { |
| 1360 | tg->ce_prq = NIL(LINK)((LINK*)((void*)0)); |
| 1361 | tg->ce_flag |= F_RULES0x0010|F_MULTI0x0002|F_TARGET0x0008; |
| 1362 | tg->ce_attr |= A_SEQ0x00200; |
| 1363 | tg->ce_recipe = NIL(STRING)((STRING*)((void*)0)); |
| 1364 | tg->ce_dir = NIL(char)((char*)((void*)0)); |
| 1365 | cp->ce_cond = NIL(STRING)((STRING*)((void*)0)); |
| 1366 | } |
| 1367 | /* This handles the case of adding an additional target as a |
| 1368 | * prerequisite to a F_MULTI target. */ |
| 1369 | else { |
| 1370 | cp->ce_flag &= ~(F_RULES0x0010|F_MULTI0x0002); |
| 1371 | cp->ce_attr &= ~A_SEQ0x00200; |
| 1372 | cp->ce_prq = NIL(LINK)((LINK*)((void*)0)); |
| 1373 | cp->ce_index = 0; |
| 1374 | cp->ce_cond = NIL(STRING)((STRING*)((void*)0)); |
| 1375 | } |
| 1376 | cp->ce_count = ++tg->ce_index; |
| 1377 | cp->ce_flag |= F_TARGET0x0008; |
| 1378 | cp->ce_set = NIL(CELL)((CELL*)((void*)0)); |
| 1379 | cp->ce_all.cl_prq = cp; |
| 1380 | CeNotMe(cp)(cp)->ce_all.cl_next = NIL(LINK)((LINK*)((void*)0)); |
| 1381 | |
| 1382 | Add_prerequisite(tg, cp, FALSE0, TRUE1); |
| 1383 | return(cp); |
| 1384 | } |
| 1385 | |
| 1386 | |
| 1387 | static void |
| 1388 | _add_indirect_prereq( pq )/* |
| 1389 | ========================== |
| 1390 | Prerequisite is an indirect prerequisite for a %-target, add it to |
| 1391 | the target's list of indirect prerequsites to add on match. */ |
| 1392 | CELLPTR pq; |
| 1393 | { |
| 1394 | register LINKPTR ln; |
| 1395 | |
| 1396 | /* Only add to list of indirect prerequsites if it is not in already. */ |
| 1397 | for(ln=_sv_ind_prq; ln; ln=ln->cl_next) |
| 1398 | if(strcmp(ln->cl_prq->CE_NAMEce_name->ht_name,pq->CE_NAMEce_name->ht_name) == 0) |
| 1399 | return; |
| 1400 | |
| 1401 | /* Not in, add it. */ |
| 1402 | TALLOC( ln, 1, LINK )if ((ln = (LINK*) calloc((unsigned int)(1), (size_t)sizeof(LINK ))) == (LINK*)0) {No_ram();}; |
| 1403 | ln->cl_next = _sv_ind_prq; |
| 1404 | ln->cl_prq = pq; |
| 1405 | _sv_ind_prq = ln; |
| 1406 | } |
| 1407 | |
| 1408 | |
| 1409 | |
| 1410 | static void |
| 1411 | _set_attributes( attr, set_dir, cp )/* |
| 1412 | ====================================== |
| 1413 | Set the appropriate attributes for a cell */ |
| 1414 | t_attr attr; |
| 1415 | char *set_dir; |
| 1416 | CELLPTR cp; |
| 1417 | { |
| 1418 | char *dir = 0; |
| 1419 | |
| 1420 | DB_ENTER( "_set_attributes" ); |
| 1421 | |
| 1422 | /* If .SETDIR attribute is set then we have at least .SETDIR= in the |
| 1423 | * set_dir string. So go and fishout what is at the end of the =. |
| 1424 | * If not set and not NULL then propagate it to the target cell. */ |
| 1425 | |
| 1426 | if( attr & A_SETDIR0x00400 ) { |
| 1427 | char *p; |
| 1428 | if( (p = strchr( set_dir, '=' )) != NULL((void*)0) ) |
| 1429 | dir = p + 1; |
| 1430 | |
| 1431 | if( cp->ce_dir ) |
| 1432 | Warning( "Multiple .SETDIR for %s ignored", cp->CE_NAMEce_name->ht_name ); |
| 1433 | else if( *dir ) |
| 1434 | cp->ce_dir = DmStrDup(dir); |
| 1435 | } |
| 1436 | cp->ce_attr |= attr; /* set rest of attributes for target */ |
| 1437 | |
| 1438 | DB_VOID_RETURNreturn; |
| 1439 | } |
| 1440 | |
| 1441 | |
| 1442 | |
| 1443 | static void |
| 1444 | _set_global_attr( attr )/* |
| 1445 | ========================== |
| 1446 | Handle the setting of the global attribute functions based on |
| 1447 | The attribute flags set in attr. */ |
| 1448 | t_attr attr; |
| 1449 | { |
| 1450 | t_attr flag; |
| 1451 | |
| 1452 | /* Some compilers can't handle a switch on a long, and t_attr is now a long |
| 1453 | * integer on some systems. foey! */ |
| 1454 | for( flag = MAX_ATTR0x40000; flag; flag >>= 1 ) |
| 1455 | if( flag & attr ) { |
| 1456 | if( flag == A_PRECIOUS0x00001) Def_macro(".PRECIOUS", "y", M_EXPANDED0x0008); |
| 1457 | else if( flag == A_SILENT0x00002) Def_macro(".SILENT", "y", M_EXPANDED0x0008); |
| 1458 | else if( flag == A_IGNORE0x00020 ) Def_macro(".IGNORE", "y", M_EXPANDED0x0008); |
| 1459 | else if( flag == A_EPILOG0x00008 ) Def_macro(".EPILOG", "y", M_EXPANDED0x0008); |
| 1460 | else if( flag == A_PROLOG0x00010 ) Def_macro(".PROLOG", "y", M_EXPANDED0x0008); |
| 1461 | else if( flag == A_NOINFER0x00080 ) Def_macro(".NOINFER", "y", M_EXPANDED0x0008); |
| 1462 | else if( flag == A_SEQ0x00200 ) Def_macro(".SEQUENTIAL","y", M_EXPANDED0x0008); |
| 1463 | else if( flag == A_SHELL0x00800 ) Def_macro(".USESHELL", "y", M_EXPANDED0x0008); |
| 1464 | else if( flag == A_MKSARGS0x02000 ) Def_macro(".MKSARGS", "y", M_EXPANDED0x0008); |
| 1465 | #if !defined(__CYGWIN__) |
| 1466 | else if( flag == A_SWAP0x01000 ) Def_macro(".SWAP", "y", M_EXPANDED0x0008); |
| 1467 | #else |
| 1468 | else if( flag == A_WINPATH0x01000 ) Def_macro(".WINPATH", "y", M_EXPANDED0x0008); |
| 1469 | #endif |
| 1470 | } |
| 1471 | |
| 1472 | attr &= ~A_GLOB(0x00001 | 0x00002 | 0x00020 | 0x00008 | 0x01000 | 0x00800 | 0x00010 | 0x00080 | 0x00200 | 0x02000 ); |
| 1473 | if( attr ) Warning( "Non global attribute(s) ignored" ); |
| 1474 | } |
| 1475 | |
| 1476 | |
| 1477 | |
| 1478 | static void |
| 1479 | _stick_at_head( cp, pq )/* |
| 1480 | ========================== |
| 1481 | Add the prerequisite list to the head of the existing prerequisite |
| 1482 | list */ |
| 1483 | |
| 1484 | CELLPTR cp; /* cell for target node */ |
| 1485 | CELLPTR pq; /* list of prerequisites to add */ |
| 1486 | { |
| 1487 | DB_ENTER( "_stick_at_head" ); |
| 1488 | |
| 1489 | if( pq->ce_link != NIL(CELL)((CELL*)((void*)0)) ) _stick_at_head( cp, pq->ce_link ); |
| 1490 | Add_prerequisite( cp, pq, TRUE1, FALSE0 ); |
| 1491 | |
| 1492 | DB_VOID_RETURNreturn; |
| 1493 | } |
| 1494 | |
| 1495 | |
| 1496 | |
| 1497 | static t_attr |
| 1498 | _is_attribute( name )/* |
| 1499 | ======================= |
| 1500 | Check the passed name against the list of valid attributes and return the |
| 1501 | attribute index if it is, else return 0, indicating the name is not a valid |
| 1502 | attribute. The present attributes are defined in dmake.h as A_xxx #defines, |
| 1503 | with the corresponding makefile specification: (note they must be named |
| 1504 | exactly as defined below) |
| 1505 | |
| 1506 | Valid attributes are: .IGNORE, .SETDIR=, .SILENT, .PRECIOUS, .LIBRARY, |
| 1507 | .EPILOG, .PROLOG, .LIBRARYM, .SYMBOL, .UPDATEALL, |
| 1508 | .USESHELL, .NOINFER, .PHONY, .SWAP/.WINPATH, .SEQUENTIAL |
| 1509 | .NOSTATE, .MKSARGS, .IGNOREGROUP, .GROUP, .FIRST |
| 1510 | .EXECUTE, .ERRREMOVE |
| 1511 | |
| 1512 | NOTE: The strcmp's are OK since at most three are ever executed for any |
| 1513 | one attribute check, and that happens only when we can be fairly |
| 1514 | certain we have an attribute. */ |
| 1515 | char *name; |
| 1516 | { |
| 1517 | t_attr attr = 0; |
| 1518 | |
| 1519 | DB_ENTER( "_is_attribute" ); |
| 1520 | |
| 1521 | if( *name++ == '.' ) |
| 1522 | switch( *name ) |
| 1523 | { |
| 1524 | case 'E': |
| 1525 | if( !strcmp(name, "EPILOG") ) attr = A_EPILOG0x00008; |
| 1526 | else if( !strcmp(name, "EXECUTE")) attr = A_EXECUTE0x20000; |
| 1527 | else if( !strcmp(name, "ERRREMOVE")) attr = A_ERRREMOVE0x40000; |
| 1528 | else attr = 0; |
| 1529 | break; |
| 1530 | |
| 1531 | /* A_FIRST implies A_IGNORE, handled in ST_INCLUDE */ |
| 1532 | case 'F': |
| 1533 | attr = (strcmp(name, "FIRST")) ? 0 : A_FIRST0x20000000; |
| 1534 | break; |
| 1535 | |
| 1536 | case 'G': attr = (strcmp(name, "GROUP")) ? 0 : A_GROUP0x02000000; break; |
| 1537 | case 'L': attr = (strcmp(name, "LIBRARY")) ? 0 : A_LIBRARY0x00004; break; |
| 1538 | case 'M': attr = (strcmp(name, "MKSARGS")) ? 0 : A_MKSARGS0x02000; break; |
| 1539 | |
| 1540 | case 'I': |
| 1541 | if( !strcmp(name, "IGNORE") ) attr = A_IGNORE0x00020; |
| 1542 | else if( !strcmp(name, "IGNOREGROUP")) attr = A_IGNOREGROUP0x10000; |
| 1543 | else attr = 0; |
| 1544 | break; |
| 1545 | |
| 1546 | case 'N': |
| 1547 | if( !strcmp(name, "NOINFER") ) attr = A_NOINFER0x00080; |
| 1548 | else if( !strcmp(name, "NOSTATE")) attr = A_NOSTATE0x08000; |
| 1549 | else attr = 0; |
| 1550 | break; |
| 1551 | |
| 1552 | case 'U': |
| 1553 | if( !strcmp(name, "UPDATEALL") ) attr = A_UPDATEALL0x00100; |
| 1554 | else if( !strcmp(name, "USESHELL")) attr = A_SHELL0x00800; |
| 1555 | else attr = 0; |
| 1556 | break; |
| 1557 | |
| 1558 | case 'P': |
| 1559 | if( !strcmp(name, "PRECIOUS") ) attr = A_PRECIOUS0x00001; |
| 1560 | else if( !strcmp(name, "PROLOG") ) attr = A_PROLOG0x00010; |
| 1561 | else if( !strcmp(name, "PHONY") ) attr = A_PHONY0x04000; |
| 1562 | else attr = 0; |
| 1563 | break; |
| 1564 | |
| 1565 | case 'S': |
| 1566 | if( !strncmp(name, "SETDIR=", 7) ) attr = A_SETDIR0x00400; |
| 1567 | else if( !strcmp(name, "SILENT") ) attr = A_SILENT0x00002; |
| 1568 | else if( !strcmp(name, "SYMBOL") ) attr = A_SYMBOL0x00040; |
| 1569 | else if( !strcmp(name, "SEQUENTIAL")) attr = A_SEQ0x00200; |
| 1570 | /* A_SWAP has no meaning except for MSDOS. */ |
| 1571 | else if( !strcmp(name, "SWAP")) attr = A_SWAP0x01000; |
| 1572 | else attr = 0; |
| 1573 | break; |
| 1574 | |
| 1575 | case 'W': attr = (strcmp(name, "WINPATH")) ? 0 : A_WINPATH0x01000; break; |
| 1576 | } |
| 1577 | |
| 1578 | DB_RETURN( attr )return (attr); |
| 1579 | } |
| 1580 | |
| 1581 | |
| 1582 | |
| 1583 | static int |
| 1584 | _is_special( tg )/* |
| 1585 | =================== |
| 1586 | This function returns TRUE if the name passed in represents a special |
| 1587 | target, otherwise it returns false. A special target is one that has |
| 1588 | a special meaning to dmake, and may require processing at the time that |
| 1589 | it is parsed. |
| 1590 | |
| 1591 | Current Special targets are: |
| 1592 | .GROUPPROLOG .GROUPEPILOG .INCLUDE .IMPORT |
| 1593 | .EXPORT .SOURCE .SUFFIXES .ERROR .EXIT |
| 1594 | .INCLUDEDIRS .MAKEFILES .REMOVE .KEEP_STATE |
| 1595 | .TARGETS .ROOT |
| 1596 | */ |
| 1597 | char *tg; |
| 1598 | { |
| 1599 | DB_ENTER( "_is_special" ); |
| 1600 | |
| 1601 | if( *tg++ != '.' ) DB_RETURN( 0 )return (0); |
| 1602 | |
| 1603 | switch( *tg ) |
| 1604 | { |
| 1605 | case 'E': |
| 1606 | if( !strcmp( tg, "ERROR" ) ) DB_RETURN( ST_REST )return (4); |
| 1607 | else if( !strcmp( tg, "EXPORT" ) ) DB_RETURN( ST_EXPORT )return (8); |
| 1608 | else if( !strcmp( tg, "EXIT" ) ) DB_RETURN( ST_EXIT )return (12); |
| 1609 | break; |
| 1610 | |
| 1611 | case 'G': |
| 1612 | if( !strcmp( tg, "GROUPPROLOG" )) DB_RETURN( ST_REST )return (4); |
| 1613 | else if( !strcmp( tg, "GROUPEPILOG" )) DB_RETURN( ST_REST )return (4); |
| 1614 | break; |
| 1615 | |
| 1616 | case 'I': |
| 1617 | if( !strcmp( tg, "IMPORT" ) ) DB_RETURN( ST_IMPORT )return (9); |
| 1618 | else if( !strcmp( tg, "INCLUDE" ) ) DB_RETURN( ST_INCLUDE )return (5); |
| 1619 | else if( !strcmp( tg, "INCLUDEDIRS" )) DB_RETURN( ST_REST )return (4); |
| 1620 | break; |
| 1621 | |
| 1622 | case 'K': |
| 1623 | if( !strcmp( tg, "KEEP_STATE" ) ) DB_RETURN( ST_KEEP )return (11); |
| 1624 | break; |
| 1625 | |
| 1626 | case 'M': |
| 1627 | if( !strcmp( tg, "MAKEFILES" ) ) DB_RETURN( ST_REST )return (4); |
| 1628 | break; |
| 1629 | |
| 1630 | case 'R': |
| 1631 | if( !strcmp( tg, "REMOVE" ) ) DB_RETURN( ST_REST )return (4); |
| 1632 | else if( !strcmp( tg, "ROOT" ) ) DB_RETURN( ST_REST )return (4); |
| 1633 | break; |
| 1634 | |
| 1635 | case 'S': |
| 1636 | if( !strncmp( tg, "SOURCE", 6 ) ) DB_RETURN( ST_SOURCE )return (7); |
| 1637 | else if( !strncmp(tg, "SUFFIXES", 8 )) { |
| 1638 | if (Verbose & V_WARNALL0x40) |
| 1639 | Warning( "The .SUFFIXES target has no special meaning and is deprecated." ); |
| 1640 | DB_RETURN( ST_SOURCE )return (7); |
| 1641 | } |
| 1642 | break; |
| 1643 | |
| 1644 | case 'T': |
| 1645 | if( !strcmp( tg, "TARGETS" ) ) DB_RETURN( ST_REST )return (4); |
| 1646 | break; |
| 1647 | } |
| 1648 | |
| 1649 | DB_RETURN( 0 )return (0); |
| 1650 | } |
| 1651 | |
| 1652 | |
| 1653 | |
| 1654 | static int |
| 1655 | _is_percent( np )/* |
| 1656 | =================== |
| 1657 | return TRUE if np points at a string containing a % sign */ |
| 1658 | char *np; |
| 1659 | { |
| 1660 | return( (strchr(np,'%') && (*np != '\'' && np[strlen(np)-1] != '\'')) ? |
| 1661 | TRUE1 : FALSE0 ); |
| 1662 | } |
| 1663 | |
| 1664 | |
| 1665 | static char * |
| 1666 | _is_magic( np )/* |
| 1667 | ================= |
| 1668 | return NULL if np does not points at a string of the form |
| 1669 | .<chars>.<chars> or .<chars> |
| 1670 | where chars are "visible characters" for the current locale. If np is of the |
| 1671 | first form we return a pointer to the second '.' and for the second form we |
| 1672 | return a pointer to the '.'. |
| 1673 | |
| 1674 | NOTE: reject target if it contains / or begins with .. |
| 1675 | reject also .INIT and .DONE because they are mentioned in the |
| 1676 | man page. */ |
| 1677 | char *np; |
| 1678 | { |
| 1679 | register char *n; |
| 1680 | |
| 1681 | n = np; |
| 1682 | if( *n != '.' ) return( NIL(char)((char*)((void*)0)) ); |
| 1683 | if (strchr(DirBrkStr, *(n+1))!=NULL((void*)0) || *(n+1) == '.' ) |
| 1684 | return (NIL(char)((char*)((void*)0))); |
| 1685 | if( !strcmp( n+1, "INIT" ) || !strcmp( n+1, "DONE" ) ) |
| 1686 | return (NIL(char)((char*)((void*)0))); |
| 1687 | |
| 1688 | for( n++; isgraph(*n)((*__ctype_b_loc ())[(int) ((*n))] & (unsigned short int) _ISgraph) && (*n != '.'); n++ ); |
| 1689 | |
| 1690 | if( *n != '\0' ) { |
| 1691 | if( *n != '.' ) return( NIL(char)((char*)((void*)0)) ); |
| 1692 | for( np = n++; isgraph( *n )((*__ctype_b_loc ())[(int) ((*n))] & (unsigned short int) _ISgraph) && (*n != '.'); n++ ); |
| 1693 | if( *n != '\0' ) return( NIL(char)((char*)((void*)0)) ); |
| 1694 | } |
| 1695 | /* Until dmake 4.5 a .<suffix> target was ignored when AUGMAKE was |
| 1696 | * set and evaluated as a meta target if unset (also for -A). |
| 1697 | * To keep maximum compatibility accept this regardles of the AUGMAKE |
| 1698 | * status. */ |
| 1699 | |
| 1700 | /* np points at the second . of .<chars>.<chars> string. |
| 1701 | * if the special target is of the form .<chars> then np points at the |
| 1702 | * first . in the token. */ |
| 1703 | |
| 1704 | return( np ); |
| 1705 | } |
| 1706 | |
| 1707 | |
| 1708 | static int |
| 1709 | _add_root(tg)/* |
| 1710 | =============== |
| 1711 | Adds "tg" to the prerequisits list of "Targets" if "Target" is not TRUE, |
| 1712 | i.e. to the list of targets that are to be build. |
| 1713 | Instead io setting "Target" to TRUE, TRUE is returned as more targets |
| 1714 | might be defined in the current makefile line and they all have to be |
| 1715 | add to "Targets" in this case. */ |
| 1716 | |
| 1717 | CELLPTR tg; |
| 1718 | { |
| 1719 | int res = FALSE0; |
| 1720 | |
| 1721 | if(tg == Targets) |
| 1722 | return(TRUE1); |
| 1723 | |
| 1724 | if( !Target && !(tg->ce_flag & (F_SPECIAL0x0100|F_PERCENT0x0800)) ) { |
| 1725 | Add_prerequisite(Targets, tg, FALSE0, TRUE1); |
| 1726 | |
| 1727 | tg->ce_flag |= F_TARGET0x0008; |
| 1728 | tg->ce_attr |= A_FRINGE0x100000; |
| 1729 | res = TRUE1; |
| 1730 | } |
| 1731 | |
| 1732 | return(res); |
| 1733 | } |