File: | dmake/rulparse.c |
Location: | line 1334, column 7 |
Description: | Dereference of null pointer (loaded from variable 'cp') |
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 | } |