File: | dmake/rulparse.c |
Location: | line 1403, column 4 |
Description: | Access to field 'cl_next' results in a dereference of a null pointer (loaded from variable 'ln') |
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)); | |||
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 | } |