1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 * macro.cc
29 *
30 * Handle expansion of make macros
31 */
32
33 /*
34 * Included files
35 */
36 #include <mksh/dosys.h> /* sh_command2string() */
37 #include <mksh/i18n.h> /* get_char_semantics_value() */
38 #include <mksh/macro.h>
39 #include <mksh/misc.h> /* retmem() */
40 #include <mksh/read.h> /* get_next_block_fn() */
41
42 #include <widec.h>
43 #include <libintl.h>
44
45 /*
46 * File table of contents
47 */
48 static void add_macro_to_global_list(Name macro_to_add);
49 static void expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd);
50
51 static void init_arch_macros(void);
52 static void init_mach_macros(void);
53 static Boolean init_arch_done = false;
54 static Boolean init_mach_done = false;
55
56
57 long env_alloc_num = 0;
58 long env_alloc_bytes = 0;
59
60 /*
61 * getvar(name)
62 *
63 * Return expanded value of macro.
64 *
65 * Return value:
66 * The expanded value of the macro
67 *
68 * Parameters:
69 * name The name of the macro we want the value for
70 *
71 * Global variables used:
72 */
73 Name
74 getvar(register Name name)
75 {
76 String_rec destination;
77 wchar_t buffer[STRING_BUFFER_LENGTH];
78 register Name result;
79
80 if ((name == host_arch) || (name == target_arch)) {
81 if (!init_arch_done) {
82 init_arch_done = true;
83 init_arch_macros();
84 }
85 }
86 if ((name == host_mach) || (name == target_mach)) {
87 if (!init_mach_done) {
88 init_mach_done = true;
89 init_mach_macros();
90 }
91 }
92
93 INIT_STRING_FROM_STACK(destination, buffer);
94 expand_value(maybe_append_prop(name, macro_prop)->body.macro.value,
95 &destination,
96 false);
97 result = GETNAME(destination.buffer.start, FIND_LENGTH);
98 if (destination.free_after_use) {
99 retmem(destination.buffer.start);
100 }
101 return result;
102 }
103
104 /*
105 * expand_value(value, destination, cmd)
106 *
107 * Recursively expands all macros in the string value.
108 * destination is where the expanded value should be appended.
109 *
110 * Parameters:
111 * value The value we are expanding
112 * destination Where to deposit the expansion
113 * cmd If we are evaluating a command line we
114 * turn \ quoting off
115 *
116 * Global variables used:
117 */
118 void
119 expand_value(Name value, register String destination, Boolean cmd)
120 {
121 Source_rec sourceb;
122 register Source source = &sourceb;
123 register wchar_t *source_p = NULL;
124 register wchar_t *source_end = NULL;
125 wchar_t *block_start = NULL;
126 int quote_seen = 0;
127
128 if (value == NULL) {
129 /*
130 * Make sure to get a string allocated even if it
131 * will be empty.
132 */
133 MBSTOWCS(wcs_buffer, "");
134 append_string(wcs_buffer, destination, FIND_LENGTH);
135 destination->text.end = destination->text.p;
136 return;
137 }
138 if (!value->dollar) {
139 /*
140 * If the value we are expanding does not contain
141 * any $, we don't have to parse it.
142 */
143 APPEND_NAME(value,
144 destination,
145 (int) value->hash.length
146 );
147 destination->text.end = destination->text.p;
148 return;
149 }
150
151 if (value->being_expanded) {
152 fatal_reader_mksh(gettext("Loop detected when expanding macro value `%s'"),
153 value->string_mb);
154 }
155 value->being_expanded = true;
156 /* Setup the structure we read from */
157 Wstring vals(value);
158 sourceb.string.text.p = sourceb.string.buffer.start = wsdup(vals.get_string());
159 sourceb.string.free_after_use = true;
160 sourceb.string.text.end =
161 sourceb.string.buffer.end =
162 sourceb.string.text.p + value->hash.length;
163 sourceb.previous = NULL;
164 sourceb.fd = -1;
165 sourceb.inp_buf =
166 sourceb.inp_buf_ptr =
167 sourceb.inp_buf_end = NULL;
168 sourceb.error_converting = false;
169 /* Lift some pointers from the struct to local register variables */
170 CACHE_SOURCE(0);
171 /* We parse the string in segments */
172 /* We read chars until we find a $, then we append what we have read so far */
173 /* (since last $ processing) to the destination. When we find a $ we call */
174 /* expand_macro() and let it expand that particular $ reference into dest */
175 block_start = source_p;
176 quote_seen = 0;
177 for (; 1; source_p++) {
178 switch (GET_CHAR()) {
179 case backslash_char:
180 /* Quote $ in macro value */
181 if (!cmd) {
182 quote_seen = ~quote_seen;
183 }
184 continue;
185 case dollar_char:
186 /* Save the plain string we found since */
187 /* start of string or previous $ */
188 if (quote_seen) {
189 append_string(block_start,
190 destination,
191 source_p - block_start - 1);
192 block_start = source_p;
193 break;
194 }
195 append_string(block_start,
196 destination,
197 source_p - block_start);
198 source->string.text.p = ++source_p;
199 UNCACHE_SOURCE();
200 /* Go expand the macro reference */
201 expand_macro(source, destination, sourceb.string.buffer.start, cmd);
202 CACHE_SOURCE(1);
203 block_start = source_p + 1;
204 break;
205 case nul_char:
206 /* The string ran out. Get some more */
207 append_string(block_start,
208 destination,
209 source_p - block_start);
210 GET_NEXT_BLOCK_NOCHK(source);
211 if (source == NULL) {
212 destination->text.end = destination->text.p;
213 value->being_expanded = false;
214 return;
215 }
216 if (source->error_converting) {
217 fatal_reader_mksh("Internal error: Invalid byte sequence in expand_value()");
218 }
219 block_start = source_p;
220 source_p--;
221 continue;
222 }
223 quote_seen = 0;
224 }
225 retmem(sourceb.string.buffer.start);
226 }
227
228 /*
229 * expand_macro(source, destination, current_string, cmd)
230 *
231 * Should be called with source->string.text.p pointing to
232 * the first char after the $ that starts a macro reference.
233 * source->string.text.p is returned pointing to the first char after
234 * the macro name.
235 * It will read the macro name, expanding any macros in it,
236 * and get the value. The value is then expanded.
237 * destination is a String that is filled in with the expanded macro.
238 * It may be passed in referencing a buffer to expand the macro into.
239 * Note that most expansions are done on demand, e.g. right
240 * before the command is executed and not while the file is
241 * being parsed.
242 *
243 * Parameters:
244 * source The source block that references the string
245 * to expand
246 * destination Where to put the result
247 * current_string The string we are expanding, for error msg
248 * cmd If we are evaluating a command line we
249 * turn \ quoting off
250 *
251 * Global variables used:
252 * funny Vector of semantic tags for characters
253 * is_conditional Set if a conditional macro is refd
254 * make_word_mentioned Set if the word "MAKE" is mentioned
255 * makefile_type We deliver extra msg when reading makefiles
256 * query The Name "?", compared against
257 * query_mentioned Set if the word "?" is mentioned
258 */
259 void
260 expand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd)
261 {
262 static Name make = (Name)NULL;
263 static wchar_t colon_sh[4];
264 static wchar_t colon_shell[7];
265 String_rec string;
266 wchar_t buffer[STRING_BUFFER_LENGTH];
267 register wchar_t *source_p = source->string.text.p;
268 register wchar_t *source_end = source->string.text.end;
269 register int closer = 0;
270 wchar_t *block_start = (wchar_t *)NULL;
271 int quote_seen = 0;
272 register int closer_level = 1;
273 Name name = (Name)NULL;
274 wchar_t *colon = (wchar_t *)NULL;
275 wchar_t *percent = (wchar_t *)NULL;
276 wchar_t *eq = (wchar_t *) NULL;
277 Property macro = NULL;
278 wchar_t *p = (wchar_t*)NULL;
279 String_rec extracted;
280 wchar_t extracted_string[MAXPATHLEN];
281 wchar_t *left_head = NULL;
282 wchar_t *left_tail = NULL;
283 wchar_t *right_tail = NULL;
284 int left_head_len = 0;
285 int left_tail_len = 0;
286 int tmp_len = 0;
287 wchar_t *right_hand[128];
288 int i = 0;
289 enum {
290 no_extract,
291 dir_extract,
292 file_extract
293 } extraction = no_extract;
294 enum {
295 no_replace,
296 suffix_replace,
297 pattern_replace,
298 sh_replace
299 } replacement = no_replace;
300
301 if (make == NULL) {
302 MBSTOWCS(wcs_buffer, "MAKE");
303 make = GETNAME(wcs_buffer, FIND_LENGTH);
304
305 MBSTOWCS(colon_sh, ":sh");
306 MBSTOWCS(colon_shell, ":shell");
307 }
308
309 right_hand[0] = NULL;
310
311 /* First copy the (macro-expanded) macro name into string. */
312 INIT_STRING_FROM_STACK(string, buffer);
313 recheck_first_char:
314 /* Check the first char of the macro name to figure out what to do. */
315 switch (GET_CHAR()) {
316 case nul_char:
317 GET_NEXT_BLOCK_NOCHK(source);
318 if (source == NULL) {
319 WCSTOMBS(mbs_buffer, current_string);
320 fatal_reader_mksh(gettext("'$' at end of string `%s'"),
321 mbs_buffer);
322 }
323 if (source->error_converting) {
324 fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
325 }
326 goto recheck_first_char;
327 case parenleft_char:
328 /* Multi char name. */
329 closer = (int) parenright_char;
330 break;
331 case braceleft_char:
332 /* Multi char name. */
333 closer = (int) braceright_char;
334 break;
335 case newline_char:
336 fatal_reader_mksh(gettext("'$' at end of line"));
337 default:
338 /* Single char macro name. Just suck it up */
339 append_char(*source_p, &string);
340 source->string.text.p = source_p + 1;
341 goto get_macro_value;
342 }
343
344 /* Handle multi-char macro names */
345 block_start = ++source_p;
346 quote_seen = 0;
347 for (; 1; source_p++) {
348 switch (GET_CHAR()) {
349 case nul_char:
350 append_string(block_start,
351 &string,
352 source_p - block_start);
353 GET_NEXT_BLOCK_NOCHK(source);
354 if (source == NULL) {
355 if (current_string != NULL) {
356 WCSTOMBS(mbs_buffer, current_string);
357 fatal_reader_mksh(gettext("Unmatched `%c' in string `%s'"),
358 closer ==
359 (int) braceright_char ?
360 (int) braceleft_char :
361 (int) parenleft_char,
362 mbs_buffer);
363 } else {
364 fatal_reader_mksh(gettext("Premature EOF"));
365 }
366 }
367 if (source->error_converting) {
368 fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
369 }
370 block_start = source_p;
371 source_p--;
372 continue;
373 case newline_char:
374 fatal_reader_mksh(gettext("Unmatched `%c' on line"),
375 closer == (int) braceright_char ?
376 (int) braceleft_char :
377 (int) parenleft_char);
378 case backslash_char:
379 /* Quote dollar in macro value. */
380 if (!cmd) {
381 quote_seen = ~quote_seen;
382 }
383 continue;
384 case dollar_char:
385 /*
386 * Macro names may reference macros.
387 * This expands the value of such macros into the
388 * macro name string.
389 */
390 if (quote_seen) {
391 append_string(block_start,
392 &string,
393 source_p - block_start - 1);
394 block_start = source_p;
395 break;
396 }
397 append_string(block_start,
398 &string,
399 source_p - block_start);
400 source->string.text.p = ++source_p;
401 UNCACHE_SOURCE();
402 expand_macro(source, &string, current_string, cmd);
403 CACHE_SOURCE(0);
404 block_start = source_p;
405 source_p--;
406 break;
407 case parenleft_char:
408 /* Allow nested pairs of () in the macro name. */
409 if (closer == (int) parenright_char) {
410 closer_level++;
411 }
412 break;
413 case braceleft_char:
414 /* Allow nested pairs of {} in the macro name. */
415 if (closer == (int) braceright_char) {
416 closer_level++;
417 }
418 break;
419 case parenright_char:
420 case braceright_char:
421 /*
422 * End of the name. Save the string in the macro
423 * name string.
424 */
425 if ((*source_p == closer) && (--closer_level <= 0)) {
426 source->string.text.p = source_p + 1;
427 append_string(block_start,
428 &string,
429 source_p - block_start);
430 goto get_macro_value;
431 }
432 break;
433 }
434 quote_seen = 0;
435 }
436 /*
437 * We got the macro name. We now inspect it to see if it
438 * specifies any translations of the value.
439 */
440 get_macro_value:
441 name = NULL;
442 /* First check if we have a $(@D) type translation. */
443 if ((get_char_semantics_value(string.buffer.start[0]) &
444 (int) special_macro_sem) &&
445 (string.text.p - string.buffer.start >= 2) &&
446 ((string.buffer.start[1] == 'D') ||
447 (string.buffer.start[1] == 'F'))) {
448 switch (string.buffer.start[1]) {
449 case 'D':
450 extraction = dir_extract;
451 break;
452 case 'F':
453 extraction = file_extract;
454 break;
455 default:
456 WCSTOMBS(mbs_buffer, string.buffer.start);
457 fatal_reader_mksh(gettext("Illegal macro reference `%s'"),
458 mbs_buffer);
459 }
460 /* Internalize the macro name using the first char only. */
461 name = GETNAME(string.buffer.start, 1);
462 (void) wscpy(string.buffer.start, string.buffer.start + 2);
463 }
464 /* Check for other kinds of translations. */
465 if ((colon = (wchar_t *) wschr(string.buffer.start,
466 (int) colon_char)) != NULL) {
467 /*
468 * We have a $(FOO:.c=.o) type translation.
469 * Get the name of the macro proper.
470 */
471 if (name == NULL) {
472 name = GETNAME(string.buffer.start,
473 colon - string.buffer.start);
474 }
475 /* Pickup all the translations. */
476 if (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell)) {
477 replacement = sh_replace;
478 } else if ((svr4) ||
479 ((percent = (wchar_t *) wschr(colon + 1,
480 (int) percent_char)) == NULL)) {
481 while (colon != NULL) {
482 if ((eq = (wchar_t *) wschr(colon + 1,
483 (int) equal_char)) == NULL) {
484 fatal_reader_mksh(gettext("= missing from replacement macro reference"));
485 }
486 left_tail_len = eq - colon - 1;
487 if(left_tail) {
488 retmem(left_tail);
489 }
490 left_tail = ALLOC_WC(left_tail_len + 1);
491 (void) wsncpy(left_tail,
492 colon + 1,
493 eq - colon - 1);
494 left_tail[eq - colon - 1] = (int) nul_char;
495 replacement = suffix_replace;
496 if ((colon = (wchar_t *) wschr(eq + 1,
497 (int) colon_char)) != NULL) {
498 tmp_len = colon - eq;
499 if(right_tail) {
500 retmem(right_tail);
501 }
502 right_tail = ALLOC_WC(tmp_len);
503 (void) wsncpy(right_tail,
504 eq + 1,
505 colon - eq - 1);
506 right_tail[colon - eq - 1] =
507 (int) nul_char;
508 } else {
509 if(right_tail) {
510 retmem(right_tail);
511 }
512 right_tail = ALLOC_WC(wslen(eq) + 1);
513 (void) wscpy(right_tail, eq + 1);
514 }
515 }
516 } else {
517 if ((eq = (wchar_t *) wschr(colon + 1,
518 (int) equal_char)) == NULL) {
519 fatal_reader_mksh(gettext("= missing from replacement macro reference"));
520 }
521 if ((percent = (wchar_t *) wschr(colon + 1,
522 (int) percent_char)) == NULL) {
523 fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
524 }
525 if (eq < percent) {
526 fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
527 }
528
529 if (percent > (colon + 1)) {
530 tmp_len = percent - colon;
531 if(left_head) {
532 retmem(left_head);
533 }
534 left_head = ALLOC_WC(tmp_len);
535 (void) wsncpy(left_head,
536 colon + 1,
537 percent - colon - 1);
538 left_head[percent-colon-1] = (int) nul_char;
539 left_head_len = percent-colon-1;
540 } else {
541 left_head = NULL;
542 left_head_len = 0;
543 }
544
545 if (eq > percent+1) {
546 tmp_len = eq - percent;
547 if(left_tail) {
548 retmem(left_tail);
549 }
550 left_tail = ALLOC_WC(tmp_len);
551 (void) wsncpy(left_tail,
552 percent + 1,
553 eq - percent - 1);
554 left_tail[eq-percent-1] = (int) nul_char;
555 left_tail_len = eq-percent-1;
556 } else {
557 left_tail = NULL;
558 left_tail_len = 0;
559 }
560
561 if ((percent = (wchar_t *) wschr(++eq,
562 (int) percent_char)) == NULL) {
563
564 right_hand[0] = ALLOC_WC(wslen(eq) + 1);
565 right_hand[1] = NULL;
566 (void) wscpy(right_hand[0], eq);
567 } else {
568 i = 0;
569 do {
570 right_hand[i] = ALLOC_WC(percent-eq+1);
571 (void) wsncpy(right_hand[i],
572 eq,
573 percent - eq);
574 right_hand[i][percent-eq] =
575 (int) nul_char;
576 if (i++ >= VSIZEOF(right_hand)) {
577 fatal_mksh(gettext("Too many %% in pattern"));
578 }
579 eq = percent + 1;
580 if (eq[0] == (int) nul_char) {
581 MBSTOWCS(wcs_buffer, "");
582 right_hand[i] = (wchar_t *) wsdup(wcs_buffer);
583 i++;
584 break;
585 }
586 } while ((percent = (wchar_t *) wschr(eq, (int) percent_char)) != NULL);
587 if (eq[0] != (int) nul_char) {
588 right_hand[i] = ALLOC_WC(wslen(eq) + 1);
589 (void) wscpy(right_hand[i], eq);
590 i++;
591 }
592 right_hand[i] = NULL;
593 }
594 replacement = pattern_replace;
595 }
596 }
597 if (name == NULL) {
598 /*
599 * No translations found.
600 * Use the whole string as the macro name.
601 */
602 name = GETNAME(string.buffer.start,
603 string.text.p - string.buffer.start);
604 }
605 if (string.free_after_use) {
606 retmem(string.buffer.start);
607 }
608 if (name == make) {
609 make_word_mentioned = true;
610 }
611 if (name == query) {
612 query_mentioned = true;
613 }
614 if ((name == host_arch) || (name == target_arch)) {
615 if (!init_arch_done) {
616 init_arch_done = true;
617 init_arch_macros();
618 }
619 }
620 if ((name == host_mach) || (name == target_mach)) {
621 if (!init_mach_done) {
622 init_mach_done = true;
623 init_mach_macros();
624 }
625 }
626 /* Get the macro value. */
627 macro = get_prop(name->prop, macro_prop);
628 if ((macro != NULL) && macro->body.macro.is_conditional) {
629 conditional_macro_used = true;
630 /*
631 * Add this conditional macro to the beginning of the
632 * global list.
633 */
634 add_macro_to_global_list(name);
635 if (makefile_type == reading_makefile) {
636 warning_mksh(gettext("Conditional macro `%s' referenced in file `%ws', line %d"),
637 name->string_mb, file_being_read, line_number);
638 }
639 }
640 /* Macro name read and parsed. Expand the value. */
641 if ((macro == NULL) || (macro->body.macro.value == NULL)) {
642 /* If the value is empty, we just get out of here. */
643 goto exit;
644 }
645 if (replacement == sh_replace) {
646 /* If we should do a :sh transform, we expand the command
647 * and process it.
648 */
649 INIT_STRING_FROM_STACK(string, buffer);
650 /* Expand the value into a local string buffer and run cmd. */
651 expand_value_with_daemon(name, macro, &string, cmd);
652 sh_command2string(&string, destination);
653 } else if ((replacement != no_replace) || (extraction != no_extract)) {
654 /*
655 * If there were any transforms specified in the macro
656 * name, we deal with them here.
657 */
658 INIT_STRING_FROM_STACK(string, buffer);
659 /* Expand the value into a local string buffer. */
660 expand_value_with_daemon(name, macro, &string, cmd);
661 /* Scan the expanded string. */
662 p = string.buffer.start;
663 while (*p != (int) nul_char) {
664 wchar_t chr;
665
666 /*
667 * First skip over any white space and append
668 * that to the destination string.
669 */
670 block_start = p;
671 while ((*p != (int) nul_char) && iswspace(*p)) {
672 p++;
673 }
674 append_string(block_start,
675 destination,
676 p - block_start);
677 /* Then find the end of the next word. */
678 block_start = p;
679 while ((*p != (int) nul_char) && !iswspace(*p)) {
680 p++;
681 }
682 /* If we cant find another word we are done */
683 if (block_start == p) {
684 break;
685 }
686 /* Then apply the transforms to the word */
687 INIT_STRING_FROM_STACK(extracted, extracted_string);
688 switch (extraction) {
689 case dir_extract:
690 /*
691 * $(@D) type transform. Extract the
692 * path from the word. Deliver "." if
693 * none is found.
694 */
695 if (p != NULL) {
696 chr = *p;
697 *p = (int) nul_char;
698 }
699 eq = (wchar_t *) wsrchr(block_start, (int) slash_char);
700 if (p != NULL) {
701 *p = chr;
702 }
703 if ((eq == NULL) || (eq > p)) {
704 MBSTOWCS(wcs_buffer, ".");
705 append_string(wcs_buffer, &extracted, 1);
706 } else {
707 append_string(block_start,
708 &extracted,
709 eq - block_start);
710 }
711 break;
712 case file_extract:
713 /*
714 * $(@F) type transform. Remove the path
715 * from the word if any.
716 */
717 if (p != NULL) {
718 chr = *p;
719 *p = (int) nul_char;
720 }
721 eq = (wchar_t *) wsrchr(block_start, (int) slash_char);
722 if (p != NULL) {
723 *p = chr;
724 }
725 if ((eq == NULL) || (eq > p)) {
726 append_string(block_start,
727 &extracted,
728 p - block_start);
729 } else {
730 append_string(eq + 1,
731 &extracted,
732 p - eq - 1);
733 }
734 break;
735 case no_extract:
736 append_string(block_start,
737 &extracted,
738 p - block_start);
739 break;
740 }
741 switch (replacement) {
742 case suffix_replace:
743 /*
744 * $(FOO:.o=.c) type transform.
745 * Maybe replace the tail of the word.
746 */
747 if (((extracted.text.p -
748 extracted.buffer.start) >=
749 left_tail_len) &&
750 IS_WEQUALN(extracted.text.p - left_tail_len,
751 left_tail,
752 left_tail_len)) {
753 append_string(extracted.buffer.start,
754 destination,
755 (extracted.text.p -
756 extracted.buffer.start)
757 - left_tail_len);
758 append_string(right_tail,
759 destination,
760 FIND_LENGTH);
761 } else {
762 append_string(extracted.buffer.start,
763 destination,
764 FIND_LENGTH);
765 }
766 break;
767 case pattern_replace:
768 /* $(X:a%b=c%d) type transform. */
769 if (((extracted.text.p -
770 extracted.buffer.start) >=
771 left_head_len+left_tail_len) &&
772 IS_WEQUALN(left_head,
773 extracted.buffer.start,
774 left_head_len) &&
775 IS_WEQUALN(left_tail,
776 extracted.text.p - left_tail_len,
777 left_tail_len)) {
778 i = 0;
779 while (right_hand[i] != NULL) {
780 append_string(right_hand[i],
781 destination,
782 FIND_LENGTH);
783 i++;
784 if (right_hand[i] != NULL) {
785 append_string(extracted.buffer.
786 start +
787 left_head_len,
788 destination,
789 (extracted.text.p - extracted.buffer.start)-left_head_len-left_tail_len);
790 }
791 }
792 } else {
793 append_string(extracted.buffer.start,
794 destination,
795 FIND_LENGTH);
796 }
797 break;
798 case no_replace:
799 append_string(extracted.buffer.start,
800 destination,
801 FIND_LENGTH);
802 break;
803 case sh_replace:
804 break;
805 }
806 }
807 if (string.free_after_use) {
808 retmem(string.buffer.start);
809 }
810 } else {
811 /*
812 * This is for the case when the macro name did not
813 * specify transforms.
814 */
815 if (!strncmp(name->string_mb, "GET", 3)) {
816 dollarget_seen = true;
817 }
818 dollarless_flag = false;
819 if (!strncmp(name->string_mb, "<", 1) &&
820 dollarget_seen) {
821 dollarless_flag = true;
822 dollarget_seen = false;
823 }
824 expand_value_with_daemon(name, macro, destination, cmd);
825 }
826 exit:
827 if(left_tail) {
828 retmem(left_tail);
829 }
830 if(right_tail) {
831 retmem(right_tail);
832 }
833 if(left_head) {
834 retmem(left_head);
835 }
836 i = 0;
837 while (right_hand[i] != NULL) {
838 retmem(right_hand[i]);
839 i++;
840 }
841 *destination->text.p = (int) nul_char;
842 destination->text.end = destination->text.p;
843 }
844
845 static void
846 add_macro_to_global_list(Name macro_to_add)
847 {
848 Macro_list new_macro;
849 Macro_list macro_on_list;
850 char *name_on_list = (char*)NULL;
851 char *name_to_add = macro_to_add->string_mb;
852 char *value_on_list = (char*)NULL;
853 const char *value_to_add = (char*)NULL;
854
855 if (macro_to_add->prop->body.macro.value != NULL) {
856 value_to_add = macro_to_add->prop->body.macro.value->string_mb;
857 } else {
858 value_to_add = "";
859 }
860
861 /*
862 * Check if this macro is already on list, if so, do nothing
863 */
864 for (macro_on_list = cond_macro_list;
865 macro_on_list != NULL;
866 macro_on_list = macro_on_list->next) {
867
868 name_on_list = macro_on_list->macro_name;
869 value_on_list = macro_on_list->value;
870
871 if (IS_EQUAL(name_on_list, name_to_add)) {
872 if (IS_EQUAL(value_on_list, value_to_add)) {
873 return;
874 }
875 }
876 }
877 new_macro = (Macro_list) malloc(sizeof(Macro_list_rec));
878 new_macro->macro_name = strdup(name_to_add);
879 new_macro->value = strdup(value_to_add);
880 new_macro->next = cond_macro_list;
881 cond_macro_list = new_macro;
882 }
883
884 /*
885 * init_arch_macros(void)
886 *
887 * Set the magic macros TARGET_ARCH, HOST_ARCH,
888 *
889 * Parameters:
890 *
891 * Global variables used:
892 * host_arch Property for magic macro HOST_ARCH
893 * target_arch Property for magic macro TARGET_ARCH
894 *
895 * Return value:
896 * The function does not return a value, but can
897 * call fatal() in case of error.
898 */
899 static void
900 init_arch_macros(void)
901 {
902 String_rec result_string;
903 wchar_t wc_buf[STRING_BUFFER_LENGTH];
904 char mb_buf[STRING_BUFFER_LENGTH];
905 FILE *pipe;
906 Name value;
907 int set_host, set_target;
908 const char *mach_command = "/bin/mach";
909
910 set_host = (get_prop(host_arch->prop, macro_prop) == NULL);
911 set_target = (get_prop(target_arch->prop, macro_prop) == NULL);
912
913 if (set_host || set_target) {
914 INIT_STRING_FROM_STACK(result_string, wc_buf);
915 append_char((int) hyphen_char, &result_string);
916
917 if ((pipe = popen(mach_command, "r")) == NULL) {
918 fatal_mksh(gettext("Execute of %s failed"), mach_command);
919 }
920 while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
921 MBSTOWCS(wcs_buffer, mb_buf);
922 append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
923 }
924 if (pclose(pipe) != 0) {
925 fatal_mksh(gettext("Execute of %s failed"), mach_command);
926 }
927
928 value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
929
930 if (set_host) {
931 (void) setvar_daemon(host_arch, value, false, no_daemon, true, 0);
932 }
933 if (set_target) {
934 (void) setvar_daemon(target_arch, value, false, no_daemon, true, 0);
935 }
936 }
937 }
938
939 /*
940 * init_mach_macros(void)
941 *
942 * Set the magic macros TARGET_MACH, HOST_MACH,
943 *
944 * Parameters:
945 *
946 * Global variables used:
947 * host_mach Property for magic macro HOST_MACH
948 * target_mach Property for magic macro TARGET_MACH
949 *
950 * Return value:
951 * The function does not return a value, but can
952 * call fatal() in case of error.
953 */
954 static void
955 init_mach_macros(void)
956 {
957 String_rec result_string;
958 wchar_t wc_buf[STRING_BUFFER_LENGTH];
959 char mb_buf[STRING_BUFFER_LENGTH];
960 FILE *pipe;
961 Name value;
962 int set_host, set_target;
963 const char *arch_command = "/bin/arch";
964
965 set_host = (get_prop(host_mach->prop, macro_prop) == NULL);
966 set_target = (get_prop(target_mach->prop, macro_prop) == NULL);
967
968 if (set_host || set_target) {
969 INIT_STRING_FROM_STACK(result_string, wc_buf);
970 append_char((int) hyphen_char, &result_string);
971
972 if ((pipe = popen(arch_command, "r")) == NULL) {
973 fatal_mksh(gettext("Execute of %s failed"), arch_command);
974 }
975 while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
976 MBSTOWCS(wcs_buffer, mb_buf);
977 append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
978 }
979 if (pclose(pipe) != 0) {
980 fatal_mksh(gettext("Execute of %s failed"), arch_command);
981 }
982
983 value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
984
985 if (set_host) {
986 (void) setvar_daemon(host_mach, value, false, no_daemon, true, 0);
987 }
988 if (set_target) {
989 (void) setvar_daemon(target_mach, value, false, no_daemon, true, 0);
990 }
991 }
992 }
993
994 /*
995 * expand_value_with_daemon(name, macro, destination, cmd)
996 *
997 * Checks for daemons and then maybe calls expand_value().
998 *
999 * Parameters:
1000 * name Name of the macro (Added by the NSE)
1001 * macro The property block with the value to expand
1002 * destination Where the result should be deposited
1003 * cmd If we are evaluating a command line we
1004 * turn \ quoting off
1005 *
1006 * Global variables used:
1007 */
1008 static void
1009 expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd)
1010 {
1011 register Chain chain;
1012
1013
1014 switch (macro->body.macro.daemon) {
1015 case no_daemon:
1016 if (!svr4 && !posix) {
1017 expand_value(macro->body.macro.value, destination, cmd);
1018 } else {
1019 if (dollarless_flag && tilde_rule) {
1020 expand_value(dollarless_value, destination, cmd);
1021 dollarless_flag = false;
1022 tilde_rule = false;
1023 } else {
1024 expand_value(macro->body.macro.value, destination, cmd);
1025 }
1026 }
1027 return;
1028 case chain_daemon:
1029 /* If this is a $? value we call the daemon to translate the */
1030 /* list of names to a string */
1031 for (chain = (Chain) macro->body.macro.value;
1032 chain != NULL;
1033 chain = chain->next) {
1034 APPEND_NAME(chain->name,
1035 destination,
1036 (int) chain->name->hash.length);
1037 if (chain->next != NULL) {
1038 append_char((int) space_char, destination);
1039 }
1040 }
1041 return;
1042 }
1043 }
1044
1045 /*
1046 * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1047 */
1048 char *sunpro_dependencies_buf = NULL;
1049 char *sunpro_dependencies_oldbuf = NULL;
1050 int sunpro_dependencies_buf_size = 0;
1051
1052 /*
1053 * setvar_daemon(name, value, append, daemon, strip_trailing_spaces)
1054 *
1055 * Set a macro value, possibly supplying a daemon to be used
1056 * when referencing the value.
1057 *
1058 * Return value:
1059 * The property block with the new value
1060 *
1061 * Parameters:
1062 * name Name of the macro to set
1063 * value The value to set
1064 * append Should we reset or append to the current value?
1065 * daemon Special treatment when reading the value
1066 * strip_trailing_spaces from the end of value->string
1067 * debug_level Indicates how much tracing we should do
1068 *
1069 * Global variables used:
1070 * makefile_type Used to check if we should enforce read only
1071 * path_name The Name "PATH", compared against
1072 * virtual_root The Name "VIRTUAL_ROOT", compared against
1073 * vpath_defined Set if the macro VPATH is set
1074 * vpath_name The Name "VPATH", compared against
1075 * envvar A list of environment vars with $ in value
1076 */
1077 Property
1078 setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
1079 {
1080 register Property macro = maybe_append_prop(name, macro_prop);
1081 register Property macro_apx = get_prop(name->prop, macro_append_prop);
1082 int length = 0;
1083 String_rec destination;
1084 wchar_t buffer[STRING_BUFFER_LENGTH];
1085 register Chain chain;
1086 Name val;
1087 wchar_t *val_string = (wchar_t*)NULL;
1088 Wstring wcb;
1089
1090
1091 if ((makefile_type != reading_nothing) &&
1092 macro->body.macro.read_only) {
1093 return macro;
1094 }
1095 /* Strip spaces from the end of the value */
1096 if (daemon == no_daemon) {
1097 if(value != NULL) {
1098 wcb.init(value);
1099 length = wcb.length();
1100 val_string = wcb.get_string();
1101 }
1102 if ((length > 0) && iswspace(val_string[length-1])) {
1103 INIT_STRING_FROM_STACK(destination, buffer);
1104 buffer[0] = 0;
1105 append_string(val_string, &destination, length);
1106 if (strip_trailing_spaces) {
1107 while ((length > 0) &&
1108 iswspace(destination.buffer.start[length-1])) {
1109 destination.buffer.start[--length] = 0;
1110 }
1111 }
1112 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1113 }
1114 }
1115
1116 if(macro_apx != NULL) {
1117 val = macro_apx->body.macro_appendix.value;
1118 } else {
1119 val = macro->body.macro.value;
1120 }
1121
1122 if (append) {
1123 /*
1124 * If we are appending, we just tack the new value after
1125 * the old one with a space in between.
1126 */
1127 INIT_STRING_FROM_STACK(destination, buffer);
1128 buffer[0] = 0;
1129 if ((macro != NULL) && (val != NULL)) {
1130 APPEND_NAME(val,
1131 &destination,
1132 (int) val->hash.length);
1133 if (value != NULL) {
1134 wcb.init(value);
1135 if(wcb.length() > 0) {
1136 MBTOWC(wcs_buffer, " ");
1137 append_char(wcs_buffer[0], &destination);
1138 }
1139 }
1140 }
1141 if (value != NULL) {
1142 APPEND_NAME(value,
1143 &destination,
1144 (int) value->hash.length);
1145 }
1146 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1147 wcb.init(value);
1148 if (destination.free_after_use) {
1149 retmem(destination.buffer.start);
1150 }
1151 }
1152
1153 /* Debugging trace */
1154 if (debug_level > 1) {
1155 if (value != NULL) {
1156 switch (daemon) {
1157 case chain_daemon:
1158 (void) printf("%s =", name->string_mb);
1159 for (chain = (Chain) value;
1160 chain != NULL;
1161 chain = chain->next) {
1162 (void) printf(" %s", chain->name->string_mb);
1163 }
1164 (void) printf("\n");
1165 break;
1166 case no_daemon:
1167 (void) printf("%s= %s\n",
1168 name->string_mb,
1169 value->string_mb);
1170 break;
1171 }
1172 } else {
1173 (void) printf("%s =\n", name->string_mb);
1174 }
1175 }
1176 /* Set the new values in the macro property block */
1177 /**/
1178 if(macro_apx != NULL) {
1179 macro_apx->body.macro_appendix.value = value;
1180 INIT_STRING_FROM_STACK(destination, buffer);
1181 buffer[0] = 0;
1182 if (value != NULL) {
1183 APPEND_NAME(value,
1184 &destination,
1185 (int) value->hash.length);
1186 if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1187 MBTOWC(wcs_buffer, " ");
1188 append_char(wcs_buffer[0], &destination);
1189 }
1190 }
1191 if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1192 APPEND_NAME(macro_apx->body.macro_appendix.value_to_append,
1193 &destination,
1194 (int) macro_apx->body.macro_appendix.value_to_append->hash.length);
1195 }
1196 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1197 if (destination.free_after_use) {
1198 retmem(destination.buffer.start);
1199 }
1200 }
1201 /**/
1202 macro->body.macro.value = value;
1203 macro->body.macro.daemon = daemon;
1204 /*
1205 * If the user changes the VIRTUAL_ROOT, we need to flush
1206 * the vroot package cache.
1207 */
1208 if (name == path_name) {
1209 flush_path_cache();
1210 }
1211 if (name == virtual_root) {
1212 flush_vroot_cache();
1213 }
1214 /* If this sets the VPATH we remember that */
1215 if ((name == vpath_name) &&
1216 (value != NULL) &&
1217 (value->hash.length > 0)) {
1218 vpath_defined = true;
1219 }
1220 /*
1221 * For environment variables we also set the
1222 * environment value each time.
1223 */
1224 if (macro->body.macro.exported) {
1225 static char *env;
1226
1227 if (!reading_environment && (value != NULL)) {
1228 Envvar p;
1229
1230 for (p = envvar; p != NULL; p = p->next) {
1231 if (p->name == name) {
1232 p->value = value;
1233 p->already_put = false;
1234 goto found_it;
1235 }
1236 }
1237 p = ALLOC(Envvar);
1238 p->name = name;
1239 p->value = value;
1240 p->next = envvar;
1241 p->env_string = NULL;
1242 p->already_put = false;
1243 envvar = p;
1244 found_it:;
1245 } if (reading_environment || (value == NULL) || !value->dollar) {
1246 length = 2 + strlen(name->string_mb);
1247 if (value != NULL) {
1248 length += strlen(value->string_mb);
1249 }
1250 Property env_prop = maybe_append_prop(name, env_mem_prop);
1251 /*
1252 * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1253 */
1254 if (!strncmp(name->string_mb, "SUNPRO_DEPENDENCIES", 19)) {
1255 if (length >= sunpro_dependencies_buf_size) {
1256 sunpro_dependencies_buf_size=length*2;
1257 if (sunpro_dependencies_buf_size < 4096)
1258 sunpro_dependencies_buf_size = 4096; // Default minimum size
1259 if (sunpro_dependencies_buf)
1260 sunpro_dependencies_oldbuf = sunpro_dependencies_buf;
1261 sunpro_dependencies_buf=getmem(sunpro_dependencies_buf_size);
1262 }
1263 env = sunpro_dependencies_buf;
1264 } else {
1265 env = getmem(length);
1266 }
1267 env_alloc_num++;
1268 env_alloc_bytes += length;
1269 (void) sprintf(env,
1270 "%s=%s",
1271 name->string_mb,
1272 value == NULL ?
1273 "" : value->string_mb);
1274 (void) putenv(env);
1275 env_prop->body.env_mem.value = env;
1276 if (sunpro_dependencies_oldbuf) {
1277 /* Return old buffer */
1278 retmem_mb(sunpro_dependencies_oldbuf);
1279 sunpro_dependencies_oldbuf = NULL;
1280 }
1281 }
1282 }
1283 if (name == target_arch) {
1284 Name ha = getvar(host_arch);
1285 Name ta = getvar(target_arch);
1286 Name vr = getvar(virtual_root);
1287 int length;
1288 wchar_t *new_value;
1289 wchar_t *old_vr;
1290 Boolean new_value_allocated = false;
1291
1292 Wstring ha_str(ha);
1293 Wstring ta_str(ta);
1294 Wstring vr_str(vr);
1295
1296 wchar_t * wcb_ha = ha_str.get_string();
1297 wchar_t * wcb_ta = ta_str.get_string();
1298 wchar_t * wcb_vr = vr_str.get_string();
1299
1300 length = 32 +
1301 wslen(wcb_ha) +
1302 wslen(wcb_ta) +
1303 wslen(wcb_vr);
1304 old_vr = wcb_vr;
1305 MBSTOWCS(wcs_buffer, "/usr/arch/");
1306 if (IS_WEQUALN(old_vr,
1307 wcs_buffer,
1308 wslen(wcs_buffer))) {
1309 old_vr = (wchar_t *) wschr(old_vr, (int) colon_char) + 1;
1310 }
1311 if ( (ha == ta) || (wslen(wcb_ta) == 0) ) {
1312 new_value = old_vr;
1313 } else {
1314 new_value = ALLOC_WC(length);
1315 new_value_allocated = true;
1316 WCSTOMBS(mbs_buffer, old_vr);
1317 (void) wsprintf(new_value,
1318 "/usr/arch/%s/%s:%s",
1319 ha->string_mb + 1,
1320 ta->string_mb + 1,
1321 mbs_buffer);
1322 }
1323 if (new_value[0] != 0) {
1324 (void) setvar_daemon(virtual_root,
1325 GETNAME(new_value, FIND_LENGTH),
1326 false,
1327 no_daemon,
1328 true,
1329 debug_level);
1330 }
1331 if (new_value_allocated) {
1332 retmem(new_value);
1333 }
1334 }
1335 return macro;
1336 }