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