1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1984-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * make variable routines
26 */
27
28 #include "make.h"
29 #include "options.h"
30
31 #define BINDING(r,f) (((f)&VAL_UNBOUND)?unbound(r):state.localview?localview(r):(r)->name)
32
33 /*
34 * generator for genprereqs()
35 * sp!=0 is the first pass that sets M_generate
36 * sp==0 is the second pass that clears M_generate
37 */
38
39 static int
scanprereqs(register Sfio_t * sp,Rule_t * r,int dostate,int all,int top,int sep,int op)40 scanprereqs(register Sfio_t* sp, Rule_t* r, int dostate, int all, int top, int sep, int op)
41 {
42 register int i;
43 register List_t* p;
44 register Rule_t* x;
45 Rule_t* y;
46 Rule_t* z;
47 List_t* prereqs[4];
48 List_t t;
49
50 i = 0;
51 if (r->scan == SCAN_IGNORE && !(state.questionable & 0x02000000))
52 top = -1;
53 else if ((x = staterule(PREREQS, r, NiL, 0)) && (x->property & P_implicit))
54 prereqs[i++] = x->prereqs;
55 else
56 top = 1;
57 if (top)
58 {
59 if ((x = staterule(RULE, r, NiL, 0)) && x->prereqs != r->prereqs)
60 prereqs[i++] = x->prereqs;
61 prereqs[i++] = r->prereqs;
62 }
63 if (r->active && r->active->primary)
64 {
65 t.rule = makerule(r->active->primary);
66 t.next = 0;
67 prereqs[i++] = &t;
68 }
69 while (--i >= 0)
70 for (p = prereqs[i]; p; p = p->next)
71 {
72 x = p->rule;
73 do
74 {
75 if (!(x->dynamic & D_alias))
76 z = 0;
77 else if (!(z = getrule(x->name)))
78 break;
79 if (x->mark & M_generate)
80 {
81 if (!sp)
82 {
83 x->mark &= ~M_generate;
84 if (top >= 0)
85 scanprereqs(sp, x, dostate, all, 0, sep, op);
86 }
87 }
88 else if (sp && (all || ((x->property & P_state) || x->scan || (y = staterule(PREREQS, x, NiL, 0)) && y->scan || !r->scan) && !(x->property & (P_use|P_virtual)) && (!(x->property & P_ignore) || (x->property & P_parameter)) && (!(x->property & P_dontcare) || x->time)))
89 {
90 x->mark |= M_generate;
91 if (all || ((x->property & P_state) != 0) == dostate)
92 {
93 if (sep)
94 sfputc(sp, ' ');
95 else
96 sep = 1;
97 sfputr(sp, (op & VAL_UNBOUND) ? unbound(x) : state.localview ? localview(x) : ((x->dynamic & D_alias) ? x->uname : x->name), -1);
98 }
99 if (top >= 0)
100 sep = scanprereqs(sp, x, dostate, all, 0, sep, op);
101 }
102 } while (x = z);
103 }
104 return sep;
105 }
106
107 /*
108 * generate the list of source|explicit prerequisites in sp
109 * if sep!=0 then ' ' separation needed
110 * new value of sep is returned
111 */
112
113 static int
genprereqs(Sfio_t * sp,Rule_t * r,int dostate,int all,int sep,int op)114 genprereqs(Sfio_t* sp, Rule_t* r, int dostate, int all, int sep, int op)
115 {
116 state.val++;
117 sep = scanprereqs(sp, r, dostate, all, 1, sep, op);
118 scanprereqs(NiL, r, dostate, all, 1, sep, op);
119 state.val--;
120 return sep;
121 }
122
123 /*
124 * return the value of a variable given its name
125 * the internal automatic variables are (lazily) expanded here
126 * op: VAL_PRIMARY|VAL_AUXILIARY|VAL_UNBOUND
127 */
128
129 char*
getval(register char * s,int op)130 getval(register char* s, int op)
131 {
132 register List_t* p;
133 register Rule_t* r;
134 Rule_t* x;
135 Rule_t* z;
136 Var_t* v;
137 Var_t* a;
138 char* t;
139 char* o;
140 char* val;
141 char* next;
142 int c;
143 int n;
144 int var;
145 int tokens;
146 int pop;
147 int sep;
148 Time_t e;
149 char** ap;
150 char* arg[16];
151
152 if (!*s)
153 return null;
154 else if (isstatevar(s))
155 {
156 if (!(r = getrule(s)))
157 return null;
158 if ((r->property & (P_functional|P_virtual)) && r->status != UPDATE)
159 maketop(r, 0, NiL);
160 return r->statedata ? r->statedata : null;
161 }
162 else if (!istype(*s, C_VARIABLE1|C_ID1|C_ID2))
163 {
164 sep = 0;
165
166 /*
167 * some internal vars have no associated rule
168 */
169
170 switch (var = *s)
171 {
172
173 #if __OBSOLETE__ < 20100101
174 case '+': /* 20051122 restore for backwards compatibility -- shoulda thunk it */
175 #if __OBSOLETE__ > 20070101
176 error(1, "$(%s): obsolete -- use $(-...)", var);
177 #endif
178 s--;
179 /*FALLTHROUGH*/
180 #endif
181 case '-': /* option settings suitable for command line */
182 /*
183 * -name option value if set
184 * --name option name and value for subsequent set
185 * -+name option value
186 * -?name 1 if option value was set/unset
187 * - non-default settings
188 * -+ non-default internal settings
189 * -- all settings
190 * -? := default settings
191 * -[^:alnum:] defined by genop()/listops()
192 */
193
194 if (c = *++s)
195 {
196 if (isalnum(c))
197 c = 0;
198 else
199 s++;
200 }
201 if (*s)
202 {
203 getop(internal.val, s, c);
204 return sfstruse(internal.val);
205 }
206 if (state.mam.statix && (state.never || state.frame->target && !(state.frame->target->property & P_always)))
207 return "${NMAKEFLAGS}";
208 listops(internal.val, c);
209 if (c == '-')
210 for (p = internal.preprocess->prereqs; p; p = p->next)
211 sfprintf(internal.val, " %s", p->rule->name);
212 return sfstruse(internal.val);
213
214 case '=': /* command line script args and export vars */
215 for (n = 1; n < state.argc; n++)
216 if (state.argf[n] & (ARG_ASSIGN|ARG_SCRIPT))
217 {
218 if (sep)
219 sfputc(internal.val, ' ');
220 else
221 sep = 1;
222 shquote(internal.val, state.argv[n]);
223 }
224 for (p = internal.script->prereqs; p; p = p->next)
225 if (v = getvar(p->rule->name))
226 {
227 if (sep)
228 sfputc(internal.val, ' ');
229 else
230 sep = 1;
231 sfprintf(internal.val, "%s=%s", v->name, (v->property & V_scan) ? "=" : null);
232 shquote(internal.val, v->value);
233 }
234 else if (strchr(p->rule->name, '='))
235 {
236 if (sep)
237 sfputc(internal.val, ' ');
238 else
239 sep = 1;
240 shquote(internal.val, p->rule->name);
241 }
242 return sfstruse(internal.val);
243 }
244 for (pop = -1; *s == var; s++, pop++);
245 next = 0;
246 tokens = 0;
247 for (;;)
248 {
249 val = null;
250 while (*s == ' ')
251 s++;
252 if (!*s)
253 {
254 if (tokens)
255 goto done;
256 r = state.frame->target;
257 }
258 else
259 {
260 if (next = strchr(s, ' '))
261 {
262 *next = 0;
263 if (!tokens++)
264 state.val++;
265 }
266 if (*s == MARK_CONTEXT)
267 {
268 if (!(t = next))
269 t = s + strlen(s);
270 if (*--t == MARK_CONTEXT)
271 {
272 *t = 0;
273 s++;
274 }
275 else
276 t = 0;
277 }
278 else
279 t = 0;
280 if (!(r = getrule(s)))
281 switch (var)
282 {
283 case '!':
284 case '&':
285 case '?':
286 if (staterule(RULE, NiL, s, -1) || staterule(PREREQS, NiL, s, -1))
287 r = makerule(s);
288 break;
289 }
290 if (t)
291 *t = MARK_CONTEXT;
292 if (!r)
293 goto done;
294 s = r->name;
295 if (*s == ATTRNAME && !r->active && !(r->dynamic & D_cached) && strmatch(s, internal.issource))
296 r = source(r);
297 }
298 for (n = pop; n > 0; n--)
299 {
300 if (!r->active)
301 goto done;
302 r = r->active->parent->target;
303 }
304 switch (c = var)
305 {
306
307 case '#': /* local arg count */
308 val = 0;
309 argcount();
310 break;
311
312 case ';': /* target data */
313 if (r->property & P_statevar)
314 r = bind(r);
315 if (r->statedata && !(r->property & P_staterule))
316 val = r->statedata;
317 break;
318
319 case '<': /* target name */
320 if ((r->property & (P_joint|P_target)) != (P_joint|P_target))
321 {
322 val = BINDING(r, op);
323 break;
324 }
325 r = r->prereqs->rule;
326 c = '~';
327 /*FALLTHROUGH*/
328
329 case '>': /* updated target file prerequisites */
330 case '*': /* all target file prerequisites */
331 case '~': /* all target prerequisites */
332 n = 0;
333 if (r->active && (t = r->active->primary))
334 {
335 x = makerule(t);
336 t = BINDING(x, op);
337 if (c == '>')
338 {
339 val = t;
340 break;
341 }
342 sfputr(internal.val, t, -1);
343 n = 1;
344 }
345 else
346 {
347 x = 0;
348 n = 0;
349 }
350 val = 0;
351 e = (c == '>' && !(state.questionable & 0x01000000) && (z = staterule(RULE, r, NiL, -1))) ? z->time : r->time;
352 for (p = r->prereqs; p; p = p->next)
353 {
354 if (p->rule != x && (c == '~' && (!(op & VAL_FILE) || !notfile(p->rule) || (op & VAL_BRACE) && (*p->rule->name == '{' || *p->rule->name == '}') && !*(p->rule->name + 1)) || !notfile(p->rule) &&
355 (c != '>' || !(p->rule->dynamic & D_same) &&
356 (!(r->property & P_archive) && (p->rule->time >= state.start || p->rule->time > e || !(z = staterule(RULE, p->rule, NiL, -1)) || !z->time || !(state.questionable & 0x01000000) && z->time > e) ||
357 (r->property & P_archive) && !(p->rule->dynamic & D_member) && p->rule->time))))
358 {
359 t = BINDING(p->rule, op);
360 if (n)
361 sfputc(internal.val, ' ');
362 else
363 {
364 if (!p->next)
365 {
366 val = t;
367 break;
368 }
369 else
370 n = 1;
371 if (sep)
372 sfputc(internal.val, ' ');
373 else
374 sep = 1;
375 }
376 sfputr(internal.val, t, -1);
377 }
378 }
379 break;
380
381 case '@': /* target action */
382 if (r->action)
383 val = r->action;
384 break;
385
386 case '%': /* target stem or functional args */
387 if (r->active && r->active->stem)
388 {
389 val = r->active->stem;
390 if (state.context && (t = strrchr(val, '/')))
391 val = t + 1;
392 }
393 else
394 val = unbound(r);
395 break;
396
397 case '!': /* explicit and generated file prerequisites */
398 case '&': /* explicit and generated state prerequisites */
399 case '?': /* all explicit and generated prerequisites */
400 sep = genprereqs(internal.val, r, c == '&', c == '?', sep, op);
401 val = 0;
402 break;
403
404 case '^': /* original bound name */
405 if (!r->active)
406 break;
407 if ((r->property & (P_joint|P_target)) != (P_joint|P_target))
408 {
409 if (r->active->original && !streq(r->active->original, r->name))
410 val = state.localview ? localview(makerule(r->active->original)) : r->active->original;
411 break;
412 }
413 for (p = r->prereqs->rule->prereqs; p; p = p->next)
414 if (p->rule->active && (t = p->rule->active->original))
415 {
416 if (sep)
417 sfputc(internal.val, ' ');
418 else
419 sep = 1;
420 sfputr(internal.val, state.localview ? localview(makerule(t)) : t, -1);
421 }
422 val = 0;
423 break;
424
425 default:
426 #if DEBUG
427 error(1, "%c: invalid internal variable name", c);
428 #endif
429 return null;
430 }
431 done:
432 if (tokens)
433 {
434 if (val && *val)
435 {
436 if (sep)
437 sfputc(internal.val, ' ');
438 else
439 sep = 1;
440 sfputr(internal.val, val, -1);
441 }
442 if (!next)
443 {
444 state.val--;
445 return sfstruse(internal.val);
446 }
447 *next++ = ' ';
448 s = next;
449 }
450 else if (val)
451 return val;
452 else
453 return sfstruse(internal.val);
454 }
455 }
456 else if ((v = getvar(s)) || (t = strchr(s, ' ')))
457 {
458 if (v)
459 {
460 t = 0;
461 if (!(v->property & V_functional) || (r = getrule(v->name)) && !(r->property & P_functional))
462 r = 0;
463 }
464 else
465 {
466 /*
467 * functional var with args
468 */
469
470 *t = 0;
471 if (!(v = getvar(s)) || !v->builtin)
472 {
473 if (!(r = getrule(s)) || !(r->property & P_functional))
474 r = catrule(".", s, ".", 0);
475 if (!r || !(r->property & P_functional))
476 {
477 *t++ = ' ';
478 return null;
479 }
480 if (v = getvar(r->name))
481 v->property |= V_functional;
482 else
483 v = setvar(r->name, NiL, V_functional);
484 }
485 *t++ = ' ';
486 }
487 if (v->builtin)
488 {
489 ap = arg;
490 if (t)
491 {
492 for (;;)
493 {
494 while (isspace(*t))
495 t++;
496 if (!*t)
497 break;
498 *ap++ = t;
499 if (ap >= &arg[elementsof(arg) - 1])
500 break;
501 while (*t && !isspace(*t))
502 t++;
503 if (*t == '"' || *t == '\'')
504 {
505 o = t;
506 n = *t++;
507 while (*t && (n || !isspace(*t)))
508 {
509 if (*t == n)
510 n = 0;
511 else if (!n && (*t == '"' || *t == '\''))
512 n = *t;
513 else
514 *o++ = *t;
515 t++;
516 }
517 *o = 0;
518 }
519 if (!*t)
520 break;
521 *t++ = 0;
522 }
523 }
524 *ap = 0;
525 return (t = (*v->builtin)(arg)) ? t : null;
526 }
527 if (r)
528 maketop(r, 0, t ? t : null);
529 if (state.reading && !state.global)
530 {
531 v->property &= ~V_compiled;
532 if (istype(*s, C_ID1))
533 v->property |= V_frozen;
534 }
535 if (state.mam.regress && state.user > 1 && (v->property & (V_import|V_local_E)) == V_import)
536 {
537 v->property |= V_local_E;
538 dumpregress(state.mam.out, "setv", v->name, v->value);
539 }
540 t = (op & VAL_PRIMARY) ? v->value : null;
541 if ((v->property & V_auxiliary) && (op & VAL_AUXILIARY) && (a = auxiliary(v->name, 0)) && *a->value)
542 {
543 if (!*t)
544 return a->value;
545 sfprintf(internal.val, "%s %s", t, a->value);
546 t = sfstruse(internal.val);
547 }
548 return t;
549 }
550 if (state.reading && !state.global && istype(*s, C_ID1) && (v = setvar(s, null, 0)))
551 v->property |= V_frozen;
552 return null;
553 }
554
555 /*
556 * reset variable p value to v
557 * append!=0 if v is from append
558 */
559
560 static void
resetvar(register Var_t * p,char * v,int append)561 resetvar(register Var_t* p, char* v, int append)
562 {
563 register int n;
564
565 n = strlen(v);
566 if (!p->value || (p->property & V_import) || n > p->length)
567 {
568 if (append)
569 n = (n + 1023) & ~1023;
570 if (n < MINVALUE)
571 n = MINVALUE;
572 if (!(p->property & V_free))
573 {
574 p->property |= V_free;
575 p->value = 0;
576 }
577 p->value = newof(p->value, char, n + 1, 0);
578 p->length = n;
579 }
580 strcpy(p->value, v);
581 }
582
583 /*
584 * set the value of a variable
585 */
586
587 Var_t*
setvar(char * s,char * v,int flags)588 setvar(char* s, char* v, int flags)
589 {
590 register char* t;
591 register Var_t* p;
592 register int n;
593 int isid;
594 int undefined;
595
596 if (!v)
597 v = null;
598
599 /*
600 * the name determines the variable type
601 */
602
603 n = nametype(s, NiL);
604 if (n & NAME_statevar)
605 {
606 bindstate(makerule(s), v);
607 return 0;
608 }
609 if (!(isid = !!(n & NAME_identifier)) && !(n & (NAME_variable|NAME_intvar)) && !istype(*s, C_VARIABLE1|C_ID1|C_ID2) && *s != '(')
610 {
611 if (flags & V_retain)
612 return 0;
613 error(2, "%s: invalid variable name", s);
614 }
615
616 /*
617 * check for a previous definition
618 */
619
620 if (undefined = !(p = getvar(s)))
621 {
622 newvar(p);
623 if (p->property & V_import)
624 {
625 p->property &= ~V_import;
626 p->value = 0;
627 }
628 else if (p->value)
629 *p->value = 0;
630 p->name = putvar(0, p);
631 p->builtin = 0;
632 }
633
634 /*
635 * check the variable attributes for precedence
636 */
637
638 if (flags & V_auxiliary)
639 {
640 if (!p->value)
641 {
642 p->value = null;
643 p->property |= V_import;
644 }
645 p->property |= V_auxiliary;
646 p = auxiliary(s, 1);
647 }
648 p->property |= flags & (V_builtin|V_functional);
649 if (state.user || state.readonly || undefined || !(p->property & V_readonly) && (!state.pushed && !(p->property & V_import) || state.global != 1 || (flags & V_import) || state.base && !state.init))
650 {
651 if (flags & V_import)
652 {
653 if (p->property & V_free)
654 {
655 p->property &= ~V_free;
656 free(p->value);
657 }
658 p->value = v;
659 }
660 else
661 {
662 t = v;
663 if (state.user)
664 p->property &= ~V_append;
665 if (n = (flags & V_append))
666 {
667 if (state.reading && !state.global && isid)
668 p->property |= V_frozen;
669 if (p->value && *p->value)
670 {
671 if (*v)
672 {
673 sfprintf(internal.nam, "%s %s", p->value, v);
674 t = sfstruse(internal.nam);
675 }
676 else
677 t = p->value;
678 }
679 }
680 resetvar(p, t, n);
681 }
682 if (flags & V_import)
683 p->property |= V_import;
684 else
685 p->property &= ~V_import;
686 if (state.readonly)
687 {
688 p->property |= V_readonly;
689 if (flags & V_append)
690 p->property |= V_append;
691 }
692 else if (state.init)
693 p->property |= V_compiled;
694 else
695 p->property &= ~V_compiled;
696 if ((flags & V_scan) && !(p->property & V_scan))
697 {
698 if (isid && state.user <= 1)
699 {
700 p->property |= V_scan;
701 staterule(VAR, NiL, p->name, -1);
702 }
703 else
704 error(1, "%s: not marked as candidate state variable", p->name);
705 }
706 if (state.vardump && !(p->property & V_import))
707 dumpvar(sfstdout, p);
708 }
709 else if (state.reading)
710 {
711 if (p->property & V_readonly)
712 {
713 /*
714 * save old value for makefile compiler
715 */
716
717 s = (p->property & V_oldvalue) ? getold(p->name) : (char*)0;
718 t = v;
719 if (flags & V_append)
720 {
721 if (state.reading && !state.global && isid)
722 p->property |= V_frozen;
723 if (s && *s)
724 {
725 if (*v)
726 {
727 sfprintf(internal.nam, "%s %s", s, v);
728 t = sfstruse(internal.nam);
729 }
730 else
731 t = s;
732 }
733 }
734 putold(p->name, strdup(t));
735 p->property |= V_oldvalue;
736 if ((p->property & V_append) && p->value && *p->value)
737 {
738 sfprintf(internal.nam, "%s %s", t, p->value + (s ? strlen(s) + 1 : 0));
739 resetvar(p, sfstruse(internal.nam), 1);
740 }
741 }
742 if (isid && (flags & V_scan) && state.makefile)
743 {
744 p->property |= V_scan;
745 staterule(VAR, NiL, p->name, -1);
746 }
747 }
748 if (!p->value)
749 {
750 p->value = strdup(null);
751 p->property |= V_free;
752 }
753 return p;
754 }
755
756 /*
757 * translate ':' in s's expanded value to del in sp for list generators
758 * 0 returned if s empty
759 */
760
761 char*
colonlist(register Sfio_t * sp,register char * s,int exp,register int del)762 colonlist(register Sfio_t* sp, register char* s, int exp, register int del)
763 {
764 register char* p;
765 Var_t* v;
766
767 if (exp)
768 {
769 if (!(v = getvar(s)))
770 return 0;
771 s = v->value;
772 }
773 expand(sp, s);
774 for (p = sfstruse(sp); isspace(*p); p++);
775 if (!*(s = p))
776 return 0;
777 for (;;)
778 switch (*p++)
779 {
780 case ':':
781 if (*(p - 1) = del)
782 break;
783 /*FALLTHROUGH*/
784 case 0:
785 return s;
786 }
787 }
788
789 /*
790 * copy variable reference into sp
791 */
792
793 void
localvar(Sfio_t * sp,register Var_t * v,char * value,int property)794 localvar(Sfio_t* sp, register Var_t* v, char* value, int property)
795 {
796 register char* s;
797 register int c;
798 char* prefix;
799 char* t;
800 Var_t* x;
801
802 prefix = (property & V_local_D) ? null : "_";
803 if (state.mam.out && (!(v->property & property) || !sp))
804 {
805 v->property |= property;
806 sfprintf(state.mam.out, "%ssetv %s%s ", state.mam.label, prefix, v->name);
807 if (*(s = value))
808 {
809 sfprintf(state.mam.out, "%s%s", (property & V_local_D) ? "-D" : null, v->name);
810 if (!(property & V_local_D) || *s != '1' || *(s + 1))
811 {
812 sfputc(state.mam.out, '=');
813 sfputc(state.mam.out, '"');
814
815 /*
816 * this quoting allows simple parameterization
817 */
818
819 while (c = *s++)
820 {
821 switch (c)
822 {
823 case '$':
824 if (istype(*s, C_ID1))
825 {
826 for (t = s; istype(*t, C_ID1|C_ID2); t++);
827 c = *t;
828 *t = 0;
829 x = getvar(s);
830 *t = c;
831 c = '$';
832 if (x)
833 break;
834 }
835 else if (*s == '{')
836 break;
837 /*FALLTHROUGH*/
838 case '\\':
839 case '"':
840 case '`':
841 sfputc(state.mam.out, '\\');
842 break;
843 }
844 sfputc(state.mam.out, c);
845 }
846 sfputc(state.mam.out, '"');
847 }
848 }
849 else if (property & V_local_D)
850 sfprintf(state.mam.out, "-U%s%s", prefix, v->name);
851 sfputc(state.mam.out, '\n');
852 }
853 if (sp)
854 sfprintf(sp, "\"${%s%s}\"", prefix, v->name);
855 }
856
857 /*
858 * read the environment and set internal variables with setvar()
859 * complicated by those who pollute the environment
860 */
861
862 void
readenv(void)863 readenv(void)
864 {
865 register char** e;
866 register char* t;
867
868 for (e = environ; t = *e; e++)
869 if (istype(*t, C_ID1))
870 {
871 while (istype(*t, C_ID2))
872 sfputc(internal.nam, *t++);
873 if (*t++ == '=')
874 setvar(sfstruse(internal.nam), t, V_import);
875 else
876 sfstrseek(internal.nam, 0, SEEK_SET);
877 }
878 }
879