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 | } |