Line data Source code
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));
32 : static int _add_root ANSI((CELLPTR));
33 : static CELLPTR _build_graph ANSI((int, CELLPTR, CELLPTR));
34 : static char* _build_meta ANSI((char*));
35 : static int _do_magic ANSI((int, char*, CELLPTR, CELLPTR, t_attr, char*));
36 : static void _do_special ANSI((int, int, t_attr,char*,CELLPTR,CELLPTR,int*));
37 : static int _do_targets ANSI((int, t_attr, char*, CELLPTR, CELLPTR));
38 : static t_attr _is_attribute ANSI((char*));
39 : static int _is_special ANSI((char*));
40 : static char* _is_magic ANSI((char*));
41 : static int _is_percent ANSI((char*));
42 : static CELLPTR _make_multi ANSI((CELLPTR));
43 : static CELLPTR _replace_cell ANSI((CELLPTR,CELLPTR,CELLPTR));
44 : static void _set_attributes ANSI((t_attr, char*, CELLPTR ));
45 : static void _stick_at_head ANSI((CELLPTR, CELLPTR));
46 : static void _set_global_attr ANSI((t_attr));
47 :
48 :
49 : /* static variables that must persist across invocation of Parse_rule_def */
50 : static CELLPTR _sv_targets = NIL(CELL);
51 : static STRINGPTR _sv_rules = NIL(STRING); /* first recipe element. */
52 : static STRINGPTR _sv_crule = NIL(STRING); /* current/last recipe element. */
53 : static CELLPTR _sv_edgel = NIL(CELL);
54 : static LINKPTR _sv_ind_prq = NIL(LINK); /* indirect prerequisites for % cell */
55 : static int _sp_target = FALSE;
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 (A_PRECIOUS | A_SILENT | A_IGNORE | A_EPILOG | A_SWAP |\
64 : A_SHELL | A_PROLOG | A_NOINFER | A_SEQ | A_MKSARGS )
65 :
66 :
67 : PUBLIC int
68 27336 : 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 27336 : op = 0;
97 27336 : attr = 0;
98 27336 : special = 0;
99 27336 : augmeta = 0;
100 27336 : percent = 0;
101 27336 : set_dir = NIL( char );
102 27336 : targets = NIL(CELL);
103 27336 : prereq = NIL(CELL);
104 27336 : prereqtail = NIL(CELL);
105 27336 : 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 27336 : firstrcp = strchr( Buffer, ';' );
112 27336 : if( firstrcp != NIL( char ) ) {
113 3312 : *firstrcp++ = 0;
114 3312 : firstrcp = DmStrSpn( firstrcp, " \t" );
115 : }
116 :
117 27336 : result = Expand( Buffer );
118 : /* Remove CONTINUATION_CHAR, keep the <nl> */
119 51868 : for( brk=strchr(result,CONTINUATION_CHAR); brk != NIL(char); brk=strchr(brk,CONTINUATION_CHAR) )
120 24532 : if( brk[1] == '\n' )
121 24532 : *brk = ' ';
122 : else
123 0 : brk++;
124 :
125 : DB_PRINT( "par", ("Scanning: [%s]", result) );
126 :
127 27336 : SET_TOKEN( &input, result );
128 27336 : brk = ":-^!|";
129 27336 : Def_targets = TRUE;
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 169588 : while( *(tok = Get_token( &input, brk, TRUE )) != '\0' )
135 114916 : if( !op ) {
136 : /* we are scanning targets and attributes
137 : * check to see if token is an operator. */
138 :
139 59940 : op = Rule_op( tok );
140 :
141 59940 : 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 33646 : 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 33646 : if( (at = _is_attribute(tok)) != 0 ) {
152 : /* Ignore .SILENT when -vr is active. */
153 2592 : if( (Verbose & V_FORCEECHO) && (at == A_SILENT) )
154 0 : at = 0;
155 :
156 : /* Logically OR the attributes specified into one main
157 : * ATTRIBUTE mask. */
158 :
159 2592 : if( at == A_SETDIR ) {
160 0 : if( set_dir != NIL( char ) )
161 0 : Warning( "Multiple .SETDIR attribute ignored" );
162 : else
163 0 : set_dir = DmStrDup( tok );
164 : }
165 :
166 2592 : attr |= at;
167 : }
168 : else {
169 : /* Not an attribute, this must be a target. */
170 : int tmp;
171 :
172 31054 : tmp = _is_special( tok );
173 :
174 31054 : if( _is_percent( tok ) ) {
175 : /* First %-target checks if there were non-%-targets before. */
176 11512 : if( !percent && targets != NIL(CELL) )
177 0 : Fatal( "A %%-target must not be mixed with non-%%-targets, offending target [%s]", tok );
178 :
179 11512 : percent++;
180 11512 : cp->ce_flag |= F_PERCENT;
181 : } else {
182 19542 : if( percent )
183 0 : Fatal( "A non-%%-target must not be mixed with %%-targets, offending target [%s]", tok );
184 : }
185 :
186 31054 : 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 8830 : if( !augmeta && targets != NIL(CELL) )
196 0 : Fatal( "An AUGMAKE meta target must not be mixed with non AUGMAKE meta targets, offending target [%s]", tok );
197 :
198 8830 : augmeta++;
199 8830 : cp->ce_flag |= F_MAGIC; /* do_magic will also add F_PERCENT later. */
200 : } else {
201 22224 : if( augmeta )
202 0 : Fatal( "A non AUGMAKE meta target must not be mixed with AUGMAKE meta targets, offending target [%s]", tok );
203 : }
204 :
205 31054 : if( special )
206 0 : Fatal( "Special target must appear alone, found [%s]", tok );
207 31054 : else if( !(cp->ce_flag & F_MARK) ) {
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 358136 : for(prev=NIL(CELL),cur=targets;cur;prev=cur,cur=cur->ce_link)
213 327304 : if(strcmp(cur->CE_NAME,cp->CE_NAME) > 0)
214 222 : break;
215 :
216 31054 : cp->ce_link = cur;
217 :
218 31054 : if (!prev)
219 26492 : targets = cp;
220 : else
221 4562 : prev->ce_link = cp;
222 :
223 31054 : cp->ce_flag |= F_MARK | F_EXPLICIT;
224 31054 : special = tmp;
225 : }
226 : else
227 0 : Warning( "Duplicate target [%s]", cp->CE_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 26294 : brk = "";
235 57348 : for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) {
236 31054 : cp->ce_flag ^= F_MARK;
237 31054 : cp->ce_flag |= F_VISITED;
238 : }
239 :
240 26294 : Def_targets = FALSE;
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 54976 : 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 54976 : if( _is_percent( tok ) ) {
253 9162 : if( percent || ((targets == NIL(CELL)) && attr) )
254 9162 : percent_prq = 1;
255 : else
256 0 : Fatal( "Syntax error in %% rule, missing %% target");
257 : }
258 :
259 54976 : if( cp->ce_flag & F_VISITED ) {
260 0 : if( cp->ce_attr & A_COMPOSITE )
261 0 : continue;
262 : else
263 0 : Fatal( "Detected circular dependency in graph at [%s]",
264 0 : cp->CE_NAME );
265 : }
266 54976 : else if( !(cp->ce_flag & F_MARK) ) {
267 : DB_PRINT( "par", ("pq_cell [%s]", tok) );
268 54976 : cp->ce_flag |= F_MARK;
269 :
270 54976 : if( prereqtail == NIL(CELL) ) /* keep prereq's in order */
271 20320 : prereq = cp;
272 : else
273 34656 : prereqtail->ce_link = cp;
274 :
275 54976 : prereqtail = cp;
276 54976 : cp->ce_link = NIL(CELL);
277 : }
278 0 : else if( !(cp->ce_attr & A_LIBRARY) && (Verbose & V_WARNALL))
279 0 : Warning("Duplicate entry [%s] in prerequisite list",cp->CE_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 27336 : if( percent && !percent_prq && (prereq != NIL(CELL)) )
288 730 : _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 27336 : CLEAR_TOKEN( &input ); FREE(result); result = NIL(char);
294 27336 : if( !op ) {
295 : DB_PRINT( "par", ("Not a rule [%s]", Buffer) );
296 1042 : DB_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_OR) )
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 26294 : if( !attr && targets == NIL(CELL) ) {
307 0 : Fatal( "Missing targets or attributes in rule" );
308 0 : if( set_dir != NIL( char )) FREE( set_dir );
309 0 : DB_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 26294 : if( prereqtail != NIL(CELL) ) prereqtail->ce_link = NIL(CELL);
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 26294 : for( cp=prereq; cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_MARK;
324 26294 : for( cp=targets; cp != NIL(CELL); cp=cp->ce_link ) cp->ce_flag &= ~F_VISITED;
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 26294 : if( _sv_rules != NIL(STRING) )
336 0 : Fatal( "Internal Error: _sv_rules not empty." );
337 :
338 : /* Add the first recipe line to the list */
339 26294 : if( firstrcp != NIL( char ) )
340 3312 : Add_recipe_to_list( firstrcp, TRUE, FALSE );
341 :
342 : /* Save these prior to calling _do_targets, since _build_graph needs the
343 : * _sv_setdir value for matching edges. */
344 26294 : _sv_op = op;
345 26294 : _sv_setdir = set_dir;
346 :
347 26294 : if( special )
348 : /* _do_special() can alter *state */
349 8830 : _do_special( special, op, attr, set_dir, targets, prereq, state );
350 : else
351 17464 : *state = _do_targets( op, attr, set_dir, targets, prereq );
352 :
353 26294 : if( (*state != RULE_SCAN) && (_sv_rules != NIL(STRING)) )
354 0 : Fatal( "Unexpected recipe found." );
355 :
356 26294 : DB_RETURN( 1 );
357 : }
358 :
359 :
360 : PUBLIC int
361 59940 : 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 59940 : int ret = 0;
367 :
368 : DB_ENTER( "rule_op" );
369 :
370 59940 : if( *op == TGT_DEP_SEP ) {
371 26294 : ret = R_OP_CL;
372 26294 : 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 53060 : while( *op && ret )
380 472 : switch( *op ) {
381 0 : case ':': ret |= R_OP_DCL; op++; break;
382 0 : case '!': ret |= R_OP_BG; op++; break;
383 0 : case '^': ret |= R_OP_UP; op++; break;
384 368 : case '-': ret |= R_OP_MI; op++; break;
385 104 : case '|': ret |= R_OP_OR; op++; break;
386 :
387 0 : default : ret = 0; /* an invalid modifier, chuck whole string */
388 : }
389 :
390 26294 : if( *op != '\0' ) ret = 0;
391 : }
392 :
393 59940 : DB_RETURN( ret );
394 : }
395 :
396 :
397 : PUBLIC void
398 44922 : 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 44922 : if( rule != NIL( char ) && (*rule != '\0' || white_too) ) {
411 : DB_PRINT( "par", ("Adding recipe [%s]", rule) );
412 44922 : _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 44922 : if( _sv_rules == NIL(STRING) )
417 15920 : _sv_rules = _sv_crule;
418 : }
419 :
420 44922 : DB_VOID_RETURN;
421 : }
422 :
423 :
424 : PUBLIC void
425 18878 : 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 18878 : if( _sv_targets == NIL(CELL) ) { DB_VOID_RETURN; }
445 :
446 18566 : tflag = FALSE;
447 18566 : flag |= (_sv_flag & F_SINGLE);
448 18566 : flag |= ((_sv_attr & A_GROUP) ? F_GROUP : 0);
449 :
450 41894 : for( tg = _sv_targets; tg != NIL(CELL); tg = tg->ce_link ) {
451 : DB_PRINT( "par", ("Binding to %s, %04x", tg->CE_NAME, tg->ce_flag) );
452 23328 : magic = tg->ce_flag & F_PERCENT;
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 23328 : if( !(tg->ce_flag & F_MULTI) && !magic && (tg->CE_RECIPE != NIL(STRING))
459 314 : && !_sp_target && (_sv_rules != NIL(STRING)) )
460 0 : Fatal( "Multiply defined recipe for target %s", tg->CE_NAME );
461 :
462 23880 : if( (magic || _sp_target) && (_sv_rules == NIL(STRING)) &&
463 552 : !(tg->ce_flag & F_SPECIAL) && !_sv_globprq_only )
464 0 : Warning( "Empty recipe for special or meta target %s", tg->CE_NAME );
465 :
466 23328 : if( magic ) {
467 : CELLPTR ep;
468 :
469 23032 : for( ep=_sv_edgel; ep != NIL(CELL); ep=ep->ce_link ) {
470 : DB_PRINT( "par", ("ep address: %#x", ep) );
471 : /* %.xx :| '%.yy' abc xx '%.tt' ; touch $@
472 : * loops here ... */
473 11520 : _set_attributes( _sv_attr, _sv_setdir, ep );
474 11520 : ep->ce_flag |= (F_TARGET|flag);
475 :
476 11520 : if( _sv_rules != NIL(STRING) ) {
477 11520 : ep->ce_recipe = _sv_rules;
478 11520 : ep->ce_indprq = _sv_ind_prq;
479 : }
480 : }
481 : }
482 : else {
483 11816 : tg->ce_attr |= _sv_attr;
484 11816 : tg->ce_flag |= flag;
485 :
486 11816 : if( _sv_rules != NIL(STRING) ) {
487 4664 : tg->ce_recipe = _sv_rules;
488 4664 : tg->ce_flag |= F_RULES | F_TARGET;
489 :
490 : /* Bind the current set of prerequisites as belonging to the
491 : * original recipe given for the target */
492 35466 : for( lp=tg->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
493 30802 : if( !(lp->cl_flag & F_VISITED) ) lp->cl_flag |= F_TARGET;
494 : }
495 25906 : else for( lp=tg->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
496 18754 : lp->cl_flag |= F_VISITED;
497 : }
498 :
499 23328 : tflag |= _add_root(tg);
500 : }
501 :
502 18566 : if( tflag ) Target = TRUE;
503 18566 : if( _sv_setdir ) FREE(_sv_setdir);
504 18566 : _sv_rules = NIL(STRING);
505 18566 : _sv_crule = NIL(STRING);
506 18566 : _sv_targets = NIL(CELL);
507 18566 : _sv_ind_prq = NIL(LINK);
508 18566 : _sv_edgel = NIL(CELL);
509 18566 : _sp_target = FALSE;
510 18566 : _sv_globprq_only = 0;
511 :
512 18566 : DB_VOID_RETURN;
513 : }
514 :
515 :
516 :
517 : PUBLIC int
518 88910 : 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 88910 : int res = FALSE;
528 : char *s;
529 :
530 88910 : if ( !((_sv_attr|Glob_attr)&A_IGNOREGROUP) ) {
531 88910 : s = DmStrSpn(list,"@-%+ \t");
532 88910 : res = (*s == '[');
533 88910 : if( res ) {
534 : /* Check for non-white space characters after the [. */
535 0 : for( s++; *s && iswhite(*s) ; s++ )
536 : ;
537 0 : if( *s )
538 0 : Warning("Found non-white space character after '[' in [%s].", list);
539 :
540 0 : _sv_attr |= Rcp_attribute(list);
541 : }
542 : }
543 :
544 88910 : return(res);
545 : }
546 :
547 :
548 : static void
549 8830 : _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 8830 : target->ce_flag = F_SPECIAL; /* mark the target as special */
586 :
587 8830 : switch( special ) {
588 : case ST_EXPORT:
589 4984 : for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
590 : DB_PRINT( "par", ("Exporting [%s]", prereq->CE_NAME) );
591 2774 : hp = GET_MACRO( prereq->CE_NAME );
592 :
593 2774 : if( hp != NIL(HASH) ) {
594 2600 : char *tmpstr = hp->ht_value;
595 :
596 2600 : if( tmpstr == NIL(char) ) tmpstr = "";
597 :
598 2600 : if( Write_env_string( prereq->CE_NAME, tmpstr ) != 0 )
599 0 : Warning( "Could not export %s", prereq->CE_NAME );
600 : }
601 : }
602 2210 : break;
603 :
604 : /* Simply cause the parser to fail on the next input read */
605 : case ST_EXIT:
606 0 : Skip_to_eof = TRUE;
607 0 : break;
608 :
609 : case ST_IMPORT:
610 736 : for( ; prereq != NIL(CELL); prereq = prereq->ce_link ) {
611 : char *tmpstr;
612 :
613 : DB_PRINT( "par", ("Importing [%s]", prereq->CE_NAME) );
614 :
615 368 : if( strcmp(prereq->CE_NAME, ".EVERYTHING") == 0 ) {
616 184 : t_attr sattr = Glob_attr;
617 184 : Glob_attr |= A_SILENT;
618 :
619 184 : ReadEnvironment();
620 :
621 184 : Glob_attr = sattr;
622 : }
623 : else {
624 184 : tmpstr = Read_env_string( prereq->CE_NAME );
625 :
626 184 : if( tmpstr != NIL(char) )
627 184 : Def_macro(prereq->CE_NAME, tmpstr, M_EXPANDED|M_LITERAL);
628 : else
629 0 : if( !((Glob_attr | attr) & A_IGNORE) )
630 0 : Fatal("Imported macro `%s' not found",prereq->CE_NAME);
631 : }
632 : }
633 :
634 368 : attr &= ~A_IGNORE;
635 368 : break;
636 :
637 : case ST_INCLUDE:
638 : {
639 4964 : int pushed = FALSE;
640 4964 : int first = (attr & A_FIRST);
641 4964 : int ignore = (((Glob_attr | attr) & A_IGNORE) != 0);
642 4964 : int found = FALSE;
643 4964 : int noinf = (attr & A_NOINFER);
644 4964 : LINKPTR prqlnk = NIL(LINK);
645 4964 : LINKPTR prqlst = NIL(LINK);
646 :
647 4964 : if( prereq == NIL(CELL) ) Fatal( "No .INCLUDE file(s) specified" );
648 :
649 4964 : dp = Def_cell( ".INCLUDEDIRS" );
650 :
651 4964 : if( (attr & A_SETDIR) && *(dir = strchr(set_dir, '=')+1) )
652 0 : pushed = Push_dir( dir, ".INCLUDE", ignore );
653 :
654 9928 : for( cp=prereq; cp != NIL(CELL); cp = cp->ce_link ) {
655 : LINKPTR ltmp;
656 4964 : TALLOC(ltmp, 1, LINK);
657 4964 : ltmp->cl_prq = cp;
658 :
659 4964 : if( prqlnk == NIL(LINK) )
660 4964 : prqlst = ltmp;
661 : else
662 0 : prqlnk->cl_next = ltmp;
663 :
664 4964 : prqlnk = ltmp;
665 : }
666 :
667 9928 : for( ; prqlst != NIL(LINK); FREE(prqlst), prqlst=prqlnk ) {
668 4964 : prqlnk = prqlst->cl_next;
669 4964 : cp = prqlst->cl_prq;
670 4964 : name = cp->CE_NAME;
671 :
672 : /* Leave this here, it ensures that prqlst gets propely free'd */
673 4964 : if ( first && found )
674 0 : continue;
675 :
676 4964 : if( *name == '<' ) {
677 : /* We have a file name enclosed in <....>
678 : * so get rid of the <> arround the file name */
679 :
680 0 : name++;
681 0 : if( (tmp = strrchr( name, '>' )) != NIL( char ) )
682 0 : *tmp = 0;
683 :
684 0 : if( If_root_path( name ) )
685 0 : fil = Openfile( name, FALSE, FALSE );
686 : else
687 0 : fil = NIL(FILE);
688 : }
689 : else
690 4964 : fil = Openfile( name, FALSE, FALSE );
691 :
692 4964 : if( fil == NIL(FILE) && !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 11934 : for(lp=dp->CE_PRQ; lp && fil == NIL(FILE); lp=lp->cl_next) {
703 7956 : dir = lp->cl_prq->CE_NAME;
704 7956 : if( strchr(dir, '$') ) dir = Expand(dir);
705 7956 : path = Build_path( dir, name );
706 :
707 : DB_PRINT( "par", ("Trying to include [%s]", path) );
708 :
709 7956 : fil = Openfile( path, FALSE, FALSE );
710 7956 : if( dir != lp->cl_prq->CE_NAME ) FREE(dir);
711 : }
712 : }
713 :
714 4964 : if (!noinf && fil == NIL(FILE)) {
715 556 : t_attr glob = Glob_attr;
716 556 : t_attr cattr = prqlst->cl_prq->ce_attr;
717 :
718 556 : prqlst->cl_next = NIL(LINK);
719 556 : Glob_attr |= (attr&A_IGNORE);
720 556 : prqlst->cl_prq->ce_attr &= ~A_FRINGE;
721 :
722 556 : if( Verbose & V_FILE_IO )
723 0 : printf( "%s: Inferring include file [%s].\n",
724 : Pname, name );
725 556 : fil = TryFiles(prqlst);
726 :
727 556 : Glob_attr = glob;
728 556 : prqlst->cl_prq->ce_attr |= (cattr & A_FRINGE);
729 : }
730 :
731 4964 : if( fil != NIL(FILE) ) {
732 4224 : if( Verbose & V_FILE_IO )
733 0 : printf( "%s: Parsing include file [%s].\n",
734 : Pname, name );
735 4224 : Parse( fil );
736 4224 : found = TRUE;
737 : }
738 740 : else if( !(ignore || first) )
739 0 : Fatal( "Include file %s, not found", name );
740 740 : else if( Verbose & V_FILE_IO )
741 0 : printf( "%s: Include file [%s] was not found.\n",
742 : Pname, name );
743 : }
744 :
745 4964 : if ( !ignore && first && !found )
746 0 : Fatal( "No include file was found" );
747 :
748 4964 : if( pushed ) Pop_dir(FALSE);
749 4964 : attr &= ~(A_IGNORE|A_SETDIR|A_FIRST|A_NOINFER);
750 : }
751 4964 : break;
752 :
753 : case ST_SOURCE:
754 184 : if( prereq != NIL(CELL) )
755 184 : _do_targets( op & (R_OP_CL | R_OP_MI | R_OP_UP), 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 0 : if( op == R_OP_CL || (op & R_OP_MI) )
766 0 : Clear_prerequisites( target );
767 : }
768 :
769 184 : op &= ~(R_OP_MI | R_OP_UP);
770 184 : break;
771 :
772 : case ST_KEEP:
773 0 : if( Keep_state != NIL(char) ) break;
774 0 : Def_macro( ".KEEP_STATE", "_state.mk", M_EXPANDED );
775 0 : break;
776 :
777 : case ST_REST:
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 1104 : int s_targ = Target;
783 :
784 1104 : Target = TRUE;
785 1104 : _sp_target = TRUE;
786 1104 : *state = _do_targets( op, attr, set_dir, target, prereq );
787 1104 : Target = s_targ;
788 :
789 1104 : target->ce_flag |= F_TARGET;
790 :
791 1104 : attr = A_DEFAULT;
792 1104 : op = R_OP_CL;
793 : }
794 1104 : break;
795 :
796 0 : default:break;
797 : }
798 :
799 8830 : if( op != R_OP_CL ) Warning( "Modifier(s) for operator ignored" );
800 8830 : if( attr != A_DEFAULT ) Warning( "Extra attributes ignored" );
801 :
802 8830 : DB_VOID_RETURN;
803 : }
804 :
805 :
806 : static int
807 18752 : _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 18752 : int tflag = FALSE; /* set to TRUE if we add target to root */
829 18752 : int ret_state = RULE_SCAN; /* 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 18752 : if( attr & A_UPDATEALL ) {
838 0 : if( targets == NIL(CELL) )
839 0 : Fatal( ".UPDATEALL attribute requires non-empty list of targets" );
840 :
841 0 : if (targets->ce_set == NIL(CELL)) {
842 0 : for(
843 0 : prev_cell=CeMeToo(targets),tg1=targets->ce_link;
844 : tg1 != NIL(CELL);
845 0 : tg1=tg1->ce_link
846 : ) {
847 0 : if (tg1->ce_set)
848 0 : Fatal( "Target [%s] appears on multiple .UPDATEALL lists",
849 0 : tg1->CE_NAME);
850 0 : tg1->ce_set = targets;
851 0 : TALLOC(prev_cell->cl_next, 1, LINK);
852 0 : prev_cell = prev_cell->cl_next;
853 0 : prev_cell->cl_prq = tg1;
854 : }
855 0 : targets->ce_set = targets;
856 : }
857 : else {
858 : LINKPTR ap;
859 : CELLPTR tp;
860 :
861 0 : tp = targets;
862 0 : ap = CeMeToo(targets);
863 0 : while (ap && tp && ap->cl_prq == tp && tp->ce_set == targets) {
864 0 : ap = ap->cl_next;
865 0 : tp = tp->ce_link;
866 : }
867 0 : if (ap || tp)
868 0 : Fatal("Inconsistent .UPDATEALL lists for target [%s]",
869 0 : targets->CE_NAME);
870 : }
871 0 : targets->ce_link = NIL(CELL);
872 : }
873 :
874 42264 : for( tg1 = targets; tg1 != NIL(CELL); tg1 = tg1->ce_link ) {
875 : /* Check if tg1 is already marked as a %-target, but not a magic
876 : * (.xxx.yyy) target. */
877 23512 : int purepercent = (tg1->ce_flag & F_PERCENT) && !(tg1->ce_flag & F_MAGIC);
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 23512 : if( !(op & R_OP_DCL ) && (tg1->ce_flag & F_MULTI) && !purepercent )
887 0 : Fatal( "':' vs '::' inconsistency in rules for %s", tg1->CE_NAME );
888 :
889 23512 : if( purepercent ) {
890 : /* Handle %-targets. */
891 : CELLPTR cur;
892 11512 : CELLPTR tpq = NIL(CELL);
893 11512 : CELLPTR nprq = NULL;
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 21404 : for(cur=prereq;cur;cur=cur->ce_link) {
906 9892 : char *name = cur->CE_NAME;
907 9892 : int len = strlen(name);
908 :
909 9892 : if( *name == '\'' && name[len-1]=='\'' ){
910 0 : name[len-1] = '\0';
911 0 : len = strlen(name+1)+1;
912 0 : memmove(name,name+1,len);
913 : /* add indirect prerequisite */
914 0 : _add_indirect_prereq( cur );
915 : }
916 : else {
917 : /* Sort all "other" prerequisits into tpq, with nprq
918 : * pointing to the first element. */
919 9892 : if (tpq)
920 0 : tpq->ce_link = cur;
921 : else
922 9892 : nprq = cur;
923 9892 : tpq = cur;
924 : }
925 : }
926 : /* Mark the last element of nprq. */
927 11512 : if(tpq)
928 9892 : tpq->ce_link=NIL(CELL);
929 : else
930 1620 : nprq = NIL(CELL);
931 :
932 : /* Handle "normal" prerequisites now. */
933 :
934 11512 : if ( op & R_OP_OR ) {
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 208 : for(tp1=nprq; tp1; tp1=tp1->ce_link) {
943 104 : CELLPTR tmpcell = tp1->ce_link;
944 104 : tp1->ce_link = NIL(CELL);
945 104 : _build_graph(op,tg1,tp1);
946 104 : 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 11408 : if ( nprq && nprq->ce_link && !(op & R_OP_OR))
954 0 : Warning("More than one prerequisite\n"
955 : "for %%-target. Use :| ruleop or indirect prerequisites.");
956 :
957 11408 : _build_graph(op,tg1,nprq);
958 : }
959 : }
960 12000 : else if( tg1->ce_flag & F_MAGIC &&
961 0 : (p = _is_magic( tg1->CE_NAME )) != NIL(char) &&
962 0 : _do_magic( op, p, tg1, prereq, attr, set_dir ) )
963 : ; /* _do_magic() does all that is needed (if return value is TRUE). */
964 12000 : else if( op & R_OP_DCL ) { /* op == :: */
965 0 : 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 0 : tflag |= _add_root(tg1);
971 :
972 : /* Replace the F_MULTI master with the member cell. */
973 0 : 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 0 : tg1->ce_attr |= (attr & ~A_SETDIR);
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 0 : tg1 = tmp_cell;
985 : }
986 :
987 23512 : 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 23512 : if( !(tg1->ce_flag & F_PERCENT) ) {
996 12000 : if( op & R_OP_MI ) Clear_prerequisites( tg1 ); /* op == :- */
997 :
998 12000 : if( (op & R_OP_UP) && (tg1->ce_prq != NIL(LINK)) ) /* op == :^ */
999 0 : _stick_at_head( tg1, prereq );
1000 55146 : else for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link )
1001 43146 : Add_prerequisite( tg1, tp1, FALSE, FALSE );
1002 : }
1003 11512 : else if( op & (R_OP_MI | R_OP_UP) )
1004 0 : Warning( "Modifier(s) `^-' for %-meta target ignored" );
1005 : }
1006 :
1007 : /* In case a F_MULTI member that was the first prerequisite of .TARGETS */
1008 18752 : if(tflag)
1009 0 : Target = TRUE;
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 18752 : if( (targets == NIL(CELL)) && attr ) {
1016 2 : ret_state = NORMAL_SCAN;
1017 2 : if( prereq != NIL(CELL) )
1018 4 : for( tp1=prereq; tp1 != NIL(CELL); tp1 = tp1->ce_link )
1019 2 : _set_attributes( attr, set_dir, tp1 );
1020 : else
1021 0 : _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 18752 : _sv_targets = targets;
1028 18752 : _sv_attr = attr;
1029 18752 : _sv_flag = ((op & R_OP_BG) ? F_SINGLE : F_DEFAULT);
1030 :
1031 18752 : DB_RETURN( ret_state );
1032 : }
1033 :
1034 :
1035 : static int
1036 0 : _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 0 : if( prereq != NIL(CELL) ) {
1065 0 : Warning( "Ignoring AUGMAKE meta-target [%s] because prerequisites are present.", target->CE_NAME );
1066 0 : DB_RETURN(0);
1067 : }
1068 :
1069 0 : if( dot == target->CE_NAME ) { /* its of the form .a */
1070 0 : tg = Def_cell( "%" );
1071 0 : tmp = _build_meta( target->CE_NAME );
1072 0 : prq = Def_cell( tmp );
1073 0 : FREE( tmp );
1074 :
1075 0 : _build_graph( op, tg, prq );
1076 : }
1077 : else {
1078 0 : tmp = _build_meta( dot );
1079 0 : tg = Def_cell( tmp );
1080 0 : FREE( tmp );
1081 :
1082 0 : tmp = _build_meta( tmp2 = DmSubStr( target->CE_NAME, dot ) );
1083 0 : prq = Def_cell( tmp );
1084 0 : FREE( tmp );
1085 0 : FREE( tmp2 );
1086 :
1087 0 : _build_graph( op, tg, prq );
1088 : }
1089 :
1090 0 : tg->ce_flag |= F_PERCENT;
1091 0 : target->ce_flag |= (F_MAGIC|F_PERCENT);
1092 :
1093 0 : _set_attributes( attr, set_dir, tg );
1094 :
1095 0 : DB_RETURN(1);
1096 : }
1097 :
1098 :
1099 : static CELLPTR
1100 0 : _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 0 : if( lst == cell ) {
1111 0 : rep->ce_link = lst->ce_link;
1112 0 : lst = rep;
1113 : }
1114 : else {
1115 0 : for( tp=lst; tp->ce_link != cell && tp ; tp=tp->ce_link );
1116 0 : if( !tp )
1117 0 : Fatal( "Internal Error: cell not part of lst." );
1118 0 : rep->ce_link = tp->ce_link->ce_link;
1119 0 : tp->ce_link = rep;
1120 : }
1121 :
1122 0 : return(lst);
1123 : }
1124 :
1125 :
1126 : static char *
1127 0 : _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 0 : int test = (STOBOOL(Augmake) ? name[strlen(name)-1] == '~' : 0);
1136 :
1137 0 : tmp = DmStrJoin( test ? "s.%" : "%", name, -1, FALSE);
1138 0 : if( test ) tmp[ strlen(tmp)-1 ] = '\0';
1139 :
1140 0 : return(tmp);
1141 : }
1142 :
1143 :
1144 : static CELLPTR
1145 11512 : _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 11512 : 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 11512 : if ( (CeMeToo(target))->cl_next )
1188 0 : 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 11512 : match = FALSE;
1199 41280 : for(edl=target->ce_prq; !match && edl != NIL(LINK); edl=edl->cl_next) {
1200 : LINKPTR l1,l2;
1201 29768 : 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 29768 : l1 = CeMeToo(target); /* Used by .UPDATEALL !!! */
1214 29768 : l2 = CeMeToo(edge);
1215 89304 : while(l1 && l2 && l1->cl_prq == l2->cl_prq) {
1216 29768 : l1=l1->cl_next;
1217 29768 : l2=l2->cl_next;
1218 : }
1219 : /* If both l1 and l2 are NULL we had a match. */
1220 29768 : if (l1 || l2)
1221 0 : continue;
1222 :
1223 : /* target sets match, so check prerequisites. */
1224 29768 : if( (!edge->ce_prq && !prereq) /* matches both empty - separate this. */
1225 29768 : || ( edge->ce_prq
1226 29768 : && ( edge->ce_dir == _sv_setdir
1227 0 : || ( edge->ce_dir
1228 0 : && _sv_setdir
1229 0 : && !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 29768 : for(tpq=prereq; tpq; tpq=tpq->ce_link) {
1239 59536 : for(prql=edge->ce_prq;prql;prql=prql->cl_next)
1240 29768 : if (prql->cl_prq == tpq)
1241 0 : break;
1242 :
1243 29768 : if(prql == NIL(LINK))
1244 29768 : break;
1245 :
1246 0 : prql->cl_prq->ce_flag |= F_MARK;
1247 : }
1248 :
1249 29768 : if (tpq == NIL(CELL)) {
1250 0 : for(prql=edge->ce_prq;prql;prql=prql->cl_next)
1251 0 : if(!(prql->cl_prq->ce_flag & F_MARK))
1252 0 : break;
1253 :
1254 0 : if(prql == NIL(LINK))
1255 0 : match = TRUE;
1256 : }
1257 :
1258 : /* clean up the mark bits. */
1259 59536 : for(prql=edge->ce_prq;prql;prql=prql->cl_next)
1260 29768 : prql->cl_prq->ce_flag &= ~F_MARK;
1261 : }
1262 : }
1263 :
1264 11512 : 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 0 : edge->ce_dir = NIL(char);
1270 0 : edge->ce_flag &= (F_PERCENT|F_MAGIC|F_DFA);
1271 0 : edge->ce_attr &= A_NOINFER;
1272 : }
1273 : else {
1274 : DB_PRINT( "%", ("Adding a new edge") );
1275 :
1276 11512 : edge = _make_multi(target);
1277 :
1278 : /* FIXME: There can be only one %-target. */
1279 23024 : for(edl=CeMeToo(target);edl;edl=edl->cl_next) {
1280 11512 : if( !((tpq=edl->cl_prq)->ce_flag & F_DFA) ) {
1281 4672 : Add_nfa( tpq->CE_NAME );
1282 4672 : tpq->ce_flag |= F_DFA;
1283 : }
1284 :
1285 11512 : edl->cl_prq->ce_set = edge;
1286 : }
1287 :
1288 11512 : edge->ce_all = target->ce_all;
1289 11512 : target->ce_all.cl_next = NIL(LINK);
1290 11512 : target->ce_set = NIL(CELL);
1291 :
1292 : /* Add all prerequisites to edge. */
1293 21404 : for(tpq=prereq; tpq; tpq=tpq->ce_link)
1294 9892 : Add_prerequisite(edge, tpq, FALSE, TRUE);
1295 : }
1296 :
1297 11512 : if( op & R_OP_DCL )
1298 0 : Warning("'::' operator for meta-target '%s' ignored, ':' operator assumed.",
1299 0 : target->CE_NAME );
1300 :
1301 : /* If edge was already added we're in BIG trouble. */
1302 : /* Re-use cur as temporary variable. */
1303 11516 : for( cur=_sv_edgel; cur != NIL(CELL); cur=cur->ce_link ) {
1304 4 : if( cur == edge )
1305 0 : Fatal( "Internal Error: edge already in _sv_edgel." );
1306 : }
1307 :
1308 11512 : edge->ce_link = _sv_edgel;
1309 11512 : _sv_edgel = edge;
1310 11512 : _sv_globprq_only = 0;
1311 :
1312 11512 : DB_RETURN(NIL(CELL));
1313 : }
1314 :
1315 :
1316 : static CELLPTR
1317 11512 : _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 11512 : if( !(tg->ce_flag & F_MULTI) && (tg->ce_prq || tg->ce_recipe) ) {
1332 : /* Allocate a new master cell. */
1333 0 : TALLOC(cp, 1, CELL);
1334 0 : *cp = *tg;
1335 :
1336 : /* F_MULTI master */
1337 0 : tg->ce_prq = NIL(LINK);
1338 0 : tg->ce_flag |= F_RULES|F_MULTI|F_TARGET;
1339 0 : tg->ce_attr |= A_SEQ;
1340 0 : tg->ce_recipe = NIL(STRING);
1341 0 : tg->ce_dir = NIL(char);
1342 :
1343 : /* F_MULTI member for preexisting elements */
1344 0 : cp->ce_count = ++tg->ce_index;
1345 0 : cp->ce_cond = NIL(STRING);
1346 0 : cp->ce_set = NIL(CELL);
1347 0 : cp->ce_all.cl_prq = cp;
1348 0 : CeNotMe(cp) = NIL(LINK);
1349 :
1350 0 : Add_prerequisite(tg, cp, FALSE, TRUE);
1351 : }
1352 :
1353 : /* Alocate memory for new member of F_MULTI target */
1354 11512 : TALLOC(cp, 1, CELL);
1355 11512 : *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 11512 : if( !(tg->ce_flag & F_MULTI) ) {
1360 4672 : tg->ce_prq = NIL(LINK);
1361 4672 : tg->ce_flag |= F_RULES|F_MULTI|F_TARGET;
1362 4672 : tg->ce_attr |= A_SEQ;
1363 4672 : tg->ce_recipe = NIL(STRING);
1364 4672 : tg->ce_dir = NIL(char);
1365 4672 : cp->ce_cond = NIL(STRING);
1366 : }
1367 : /* This handles the case of adding an additional target as a
1368 : * prerequisite to a F_MULTI target. */
1369 : else {
1370 6840 : cp->ce_flag &= ~(F_RULES|F_MULTI);
1371 6840 : cp->ce_attr &= ~A_SEQ;
1372 6840 : cp->ce_prq = NIL(LINK);
1373 6840 : cp->ce_index = 0;
1374 6840 : cp->ce_cond = NIL(STRING);
1375 : }
1376 11512 : cp->ce_count = ++tg->ce_index;
1377 11512 : cp->ce_flag |= F_TARGET;
1378 11512 : cp->ce_set = NIL(CELL);
1379 11512 : cp->ce_all.cl_prq = cp;
1380 11512 : CeNotMe(cp) = NIL(LINK);
1381 :
1382 11512 : Add_prerequisite(tg, cp, FALSE, TRUE);
1383 11512 : return(cp);
1384 : }
1385 :
1386 :
1387 : static void
1388 0 : _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 0 : for(ln=_sv_ind_prq; ln; ln=ln->cl_next)
1398 0 : if(strcmp(ln->cl_prq->CE_NAME,pq->CE_NAME) == 0)
1399 0 : return;
1400 :
1401 : /* Not in, add it. */
1402 0 : TALLOC( ln, 1, LINK );
1403 0 : ln->cl_next = _sv_ind_prq;
1404 0 : ln->cl_prq = pq;
1405 0 : _sv_ind_prq = ln;
1406 : }
1407 :
1408 :
1409 :
1410 : static void
1411 23522 : _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 23522 : 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 23522 : if( attr & A_SETDIR ) {
1427 : char *p;
1428 0 : if( (p = strchr( set_dir, '=' )) != NULL )
1429 0 : dir = p + 1;
1430 :
1431 0 : if( cp->ce_dir )
1432 0 : Warning( "Multiple .SETDIR for %s ignored", cp->CE_NAME );
1433 0 : else if( *dir )
1434 0 : cp->ce_dir = DmStrDup(dir);
1435 : }
1436 23522 : cp->ce_attr |= attr; /* set rest of attributes for target */
1437 :
1438 23522 : DB_VOID_RETURN;
1439 : }
1440 :
1441 :
1442 :
1443 : static void
1444 0 : _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 0 : for( flag = MAX_ATTR; flag; flag >>= 1 )
1455 0 : if( flag & attr ) {
1456 0 : if( flag == A_PRECIOUS) Def_macro(".PRECIOUS", "y", M_EXPANDED);
1457 0 : else if( flag == A_SILENT) Def_macro(".SILENT", "y", M_EXPANDED);
1458 0 : else if( flag == A_IGNORE ) Def_macro(".IGNORE", "y", M_EXPANDED);
1459 0 : else if( flag == A_EPILOG ) Def_macro(".EPILOG", "y", M_EXPANDED);
1460 0 : else if( flag == A_PROLOG ) Def_macro(".PROLOG", "y", M_EXPANDED);
1461 0 : else if( flag == A_NOINFER ) Def_macro(".NOINFER", "y", M_EXPANDED);
1462 0 : else if( flag == A_SEQ ) Def_macro(".SEQUENTIAL","y", M_EXPANDED);
1463 0 : else if( flag == A_SHELL ) Def_macro(".USESHELL", "y", M_EXPANDED);
1464 0 : else if( flag == A_MKSARGS ) Def_macro(".MKSARGS", "y", M_EXPANDED);
1465 : #if !defined(__CYGWIN__)
1466 0 : else if( flag == A_SWAP ) Def_macro(".SWAP", "y", M_EXPANDED);
1467 : #else
1468 : else if( flag == A_WINPATH ) Def_macro(".WINPATH", "y", M_EXPANDED);
1469 : #endif
1470 : }
1471 :
1472 0 : attr &= ~A_GLOB;
1473 0 : if( attr ) Warning( "Non global attribute(s) ignored" );
1474 0 : }
1475 :
1476 :
1477 :
1478 : static void
1479 0 : _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 0 : if( pq->ce_link != NIL(CELL) ) _stick_at_head( cp, pq->ce_link );
1490 0 : Add_prerequisite( cp, pq, TRUE, FALSE );
1491 :
1492 0 : DB_VOID_RETURN;
1493 : }
1494 :
1495 :
1496 :
1497 : static t_attr
1498 33646 : _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 33646 : t_attr attr = 0;
1518 :
1519 : DB_ENTER( "_is_attribute" );
1520 :
1521 33646 : if( *name++ == '.' )
1522 26300 : switch( *name )
1523 : {
1524 : case 'E':
1525 2404 : if( !strcmp(name, "EPILOG") ) attr = A_EPILOG;
1526 2404 : else if( !strcmp(name, "EXECUTE")) attr = A_EXECUTE;
1527 2404 : else if( !strcmp(name, "ERRREMOVE")) attr = A_ERRREMOVE;
1528 2394 : else attr = 0;
1529 2404 : break;
1530 :
1531 : /* A_FIRST implies A_IGNORE, handled in ST_INCLUDE */
1532 : case 'F':
1533 0 : attr = (strcmp(name, "FIRST")) ? 0 : A_FIRST;
1534 0 : break;
1535 :
1536 0 : case 'G': attr = (strcmp(name, "GROUP")) ? 0 : A_GROUP; break;
1537 0 : case 'L': attr = (strcmp(name, "LIBRARY")) ? 0 : A_LIBRARY; break;
1538 368 : case 'M': attr = (strcmp(name, "MKSARGS")) ? 0 : A_MKSARGS; break;
1539 :
1540 : case 'I':
1541 7164 : if( !strcmp(name, "IGNORE") ) attr = A_IGNORE;
1542 5872 : else if( !strcmp(name, "IGNOREGROUP")) attr = A_IGNOREGROUP;
1543 5872 : else attr = 0;
1544 7164 : break;
1545 :
1546 : case 'N':
1547 368 : if( !strcmp(name, "NOINFER") ) attr = A_NOINFER;
1548 184 : else if( !strcmp(name, "NOSTATE")) attr = A_NOSTATE;
1549 0 : else attr = 0;
1550 368 : break;
1551 :
1552 : case 'U':
1553 0 : if( !strcmp(name, "UPDATEALL") ) attr = A_UPDATEALL;
1554 0 : else if( !strcmp(name, "USESHELL")) attr = A_SHELL;
1555 0 : else attr = 0;
1556 0 : break;
1557 :
1558 : case 'P':
1559 566 : if( !strcmp(name, "PRECIOUS") ) attr = A_PRECIOUS;
1560 566 : else if( !strcmp(name, "PROLOG") ) attr = A_PROLOG;
1561 566 : else if( !strcmp(name, "PHONY") ) attr = A_PHONY;
1562 0 : else attr = 0;
1563 566 : break;
1564 :
1565 : case 'S':
1566 540 : if( !strncmp(name, "SETDIR=", 7) ) attr = A_SETDIR;
1567 540 : else if( !strcmp(name, "SILENT") ) attr = A_SILENT;
1568 540 : else if( !strcmp(name, "SYMBOL") ) attr = A_SYMBOL;
1569 540 : else if( !strcmp(name, "SEQUENTIAL")) attr = A_SEQ;
1570 : /* A_SWAP has no meaning except for MSDOS. */
1571 184 : else if( !strcmp(name, "SWAP")) attr = A_SWAP;
1572 184 : else attr = 0;
1573 540 : break;
1574 :
1575 0 : case 'W': attr = (strcmp(name, "WINPATH")) ? 0 : A_WINPATH; break;
1576 : }
1577 :
1578 33646 : DB_RETURN( attr );
1579 : }
1580 :
1581 :
1582 :
1583 : static int
1584 31054 : _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 31054 : if( *tg++ != '.' ) DB_RETURN( 0 );
1602 :
1603 23708 : switch( *tg )
1604 : {
1605 : case 'E':
1606 2394 : if( !strcmp( tg, "ERROR" ) ) DB_RETURN( ST_REST );
1607 2210 : else if( !strcmp( tg, "EXPORT" ) ) DB_RETURN( ST_EXPORT );
1608 0 : else if( !strcmp( tg, "EXIT" ) ) DB_RETURN( ST_EXIT );
1609 0 : break;
1610 :
1611 : case 'G':
1612 0 : if( !strcmp( tg, "GROUPPROLOG" )) DB_RETURN( ST_REST );
1613 0 : else if( !strcmp( tg, "GROUPEPILOG" )) DB_RETURN( ST_REST );
1614 0 : break;
1615 :
1616 : case 'I':
1617 5872 : if( !strcmp( tg, "IMPORT" ) ) DB_RETURN( ST_IMPORT );
1618 5504 : else if( !strcmp( tg, "INCLUDE" ) ) DB_RETURN( ST_INCLUDE );
1619 540 : else if( !strcmp( tg, "INCLUDEDIRS" )) DB_RETURN( ST_REST );
1620 356 : break;
1621 :
1622 : case 'K':
1623 0 : if( !strcmp( tg, "KEEP_STATE" ) ) DB_RETURN( ST_KEEP );
1624 0 : break;
1625 :
1626 : case 'M':
1627 368 : if( !strcmp( tg, "MAKEFILES" ) ) DB_RETURN( ST_REST );
1628 0 : break;
1629 :
1630 : case 'R':
1631 368 : if( !strcmp( tg, "REMOVE" ) ) DB_RETURN( ST_REST );
1632 184 : else if( !strcmp( tg, "ROOT" ) ) DB_RETURN( ST_REST );
1633 0 : break;
1634 :
1635 : case 'S':
1636 184 : if( !strncmp( tg, "SOURCE", 6 ) ) DB_RETURN( ST_SOURCE );
1637 0 : else if( !strncmp(tg, "SUFFIXES", 8 )) {
1638 0 : if (Verbose & V_WARNALL)
1639 0 : Warning( "The .SUFFIXES target has no special meaning and is deprecated." );
1640 0 : DB_RETURN( ST_SOURCE );
1641 : }
1642 0 : break;
1643 :
1644 : case 'T':
1645 0 : if( !strcmp( tg, "TARGETS" ) ) DB_RETURN( ST_REST );
1646 0 : break;
1647 : }
1648 :
1649 14878 : DB_RETURN( 0 );
1650 : }
1651 :
1652 :
1653 :
1654 : static int
1655 86030 : _is_percent( np )/*
1656 : ===================
1657 : return TRUE if np points at a string containing a % sign */
1658 : char *np;
1659 : {
1660 213408 : return( (strchr(np,'%') && (*np != '\'' && np[strlen(np)-1] != '\'')) ?
1661 127378 : TRUE : FALSE );
1662 : }
1663 :
1664 :
1665 : static char *
1666 31054 : _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 31054 : n = np;
1682 31054 : if( *n != '.' ) return( NIL(char) );
1683 23708 : if (strchr(DirBrkStr, *(n+1))!=NULL || *(n+1) == '.' )
1684 14338 : return (NIL(char));
1685 9370 : if( !strcmp( n+1, "INIT" ) || !strcmp( n+1, "DONE" ) )
1686 540 : return (NIL(char));
1687 :
1688 8830 : for( n++; isgraph(*n) && (*n != '.'); n++ );
1689 :
1690 8830 : if( *n != '\0' ) {
1691 0 : if( *n != '.' ) return( NIL(char) );
1692 0 : for( np = n++; isgraph( *n ) && (*n != '.'); n++ );
1693 0 : if( *n != '\0' ) return( NIL(char) );
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 8830 : return( np );
1705 : }
1706 :
1707 :
1708 : static int
1709 23328 : _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 23328 : int res = FALSE;
1720 :
1721 23328 : if(tg == Targets)
1722 0 : return(TRUE);
1723 :
1724 23328 : if( !Target && !(tg->ce_flag & (F_SPECIAL|F_PERCENT)) ) {
1725 184 : Add_prerequisite(Targets, tg, FALSE, TRUE);
1726 :
1727 184 : tg->ce_flag |= F_TARGET;
1728 184 : tg->ce_attr |= A_FRINGE;
1729 184 : res = TRUE;
1730 : }
1731 :
1732 23328 : return(res);
1733 : }
|