add UNLEASHED_OBJ to unleashed.mk
[unleashed/tickless.git] / usr / src / cmd / make / lib / mksh / macro.cc
blobb3d8f7b86473db945c0aefcbe813e279bccd4680
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * macro.cc
30 * Handle expansion of make macros
34 * Included files
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 #include <sys/utsname.h>
42 #include <sys/systeminfo.h>
44 #include <libintl.h>
47 * File table of contents
49 static void add_macro_to_global_list(Name macro_to_add);
50 static void expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd);
52 static void init_arch_macros(void);
53 static void init_mach_macros(void);
54 static Boolean init_arch_done = false;
55 static Boolean init_mach_done = false;
58 long env_alloc_num = 0;
59 long env_alloc_bytes = 0;
62 * getvar(name)
64 * Return expanded value of macro.
66 * Return value:
67 * The expanded value of the macro
69 * Parameters:
70 * name The name of the macro we want the value for
72 * Global variables used:
74 Name
75 getvar(register Name name)
77 String_rec destination;
78 wchar_t buffer[STRING_BUFFER_LENGTH];
79 register Name result;
81 if ((name == host_arch) || (name == target_arch)) {
82 if (!init_arch_done) {
83 init_arch_done = true;
84 init_arch_macros();
87 if ((name == host_mach) || (name == target_mach)) {
88 if (!init_mach_done) {
89 init_mach_done = true;
90 init_mach_macros();
94 INIT_STRING_FROM_STACK(destination, buffer);
95 expand_value(maybe_append_prop(name, macro_prop)->body.macro.value,
96 &destination,
97 false);
98 result = GETNAME(destination.buffer.start, FIND_LENGTH);
99 if (destination.free_after_use) {
100 retmem(destination.buffer.start);
102 return result;
106 * expand_value(value, destination, cmd)
108 * Recursively expands all macros in the string value.
109 * destination is where the expanded value should be appended.
111 * Parameters:
112 * value The value we are expanding
113 * destination Where to deposit the expansion
114 * cmd If we are evaluating a command line we
115 * turn \ quoting off
117 * Global variables used:
119 void
120 expand_value(Name value, register String destination, Boolean cmd)
122 Source_rec sourceb;
123 register Source source = &sourceb;
124 register wchar_t *source_p = NULL;
125 register wchar_t *source_end = NULL;
126 wchar_t *block_start = NULL;
127 int quote_seen = 0;
129 if (value == NULL) {
131 * Make sure to get a string allocated even if it
132 * will be empty.
134 MBSTOWCS(wcs_buffer, "");
135 append_string(wcs_buffer, destination, FIND_LENGTH);
136 destination->text.end = destination->text.p;
137 return;
139 if (!value->dollar) {
141 * If the value we are expanding does not contain
142 * any $, we don't have to parse it.
144 APPEND_NAME(value,
145 destination,
146 (int) value->hash.length
148 destination->text.end = destination->text.p;
149 return;
152 if (value->being_expanded) {
153 fatal_reader_mksh(gettext("Loop detected when expanding macro value `%s'"),
154 value->string_mb);
156 value->being_expanded = true;
157 /* Setup the structure we read from */
158 Wstring vals(value);
159 sourceb.string.text.p = sourceb.string.buffer.start = wcsdup(vals.get_string());
160 sourceb.string.free_after_use = true;
161 sourceb.string.text.end =
162 sourceb.string.buffer.end =
163 sourceb.string.text.p + value->hash.length;
164 sourceb.previous = NULL;
165 sourceb.fd = -1;
166 sourceb.inp_buf =
167 sourceb.inp_buf_ptr =
168 sourceb.inp_buf_end = NULL;
169 sourceb.error_converting = false;
170 /* Lift some pointers from the struct to local register variables */
171 CACHE_SOURCE(0);
172 /* We parse the string in segments */
173 /* We read chars until we find a $, then we append what we have read so far */
174 /* (since last $ processing) to the destination. When we find a $ we call */
175 /* expand_macro() and let it expand that particular $ reference into dest */
176 block_start = source_p;
177 quote_seen = 0;
178 for (; 1; source_p++) {
179 switch (GET_CHAR()) {
180 case backslash_char:
181 /* Quote $ in macro value */
182 if (!cmd) {
183 quote_seen = ~quote_seen;
185 continue;
186 case dollar_char:
187 /* Save the plain string we found since */
188 /* start of string or previous $ */
189 if (quote_seen) {
190 append_string(block_start,
191 destination,
192 source_p - block_start - 1);
193 block_start = source_p;
194 break;
196 append_string(block_start,
197 destination,
198 source_p - block_start);
199 source->string.text.p = ++source_p;
200 UNCACHE_SOURCE();
201 /* Go expand the macro reference */
202 expand_macro(source, destination, sourceb.string.buffer.start, cmd);
203 CACHE_SOURCE(1);
204 block_start = source_p + 1;
205 break;
206 case nul_char:
207 /* The string ran out. Get some more */
208 append_string(block_start,
209 destination,
210 source_p - block_start);
211 GET_NEXT_BLOCK_NOCHK(source);
212 if (source == NULL) {
213 destination->text.end = destination->text.p;
214 value->being_expanded = false;
215 return;
217 if (source->error_converting) {
218 fatal_reader_mksh("Internal error: Invalid byte sequence in expand_value()");
220 block_start = source_p;
221 source_p--;
222 continue;
224 quote_seen = 0;
226 retmem(sourceb.string.buffer.start);
230 * expand_macro(source, destination, current_string, cmd)
232 * Should be called with source->string.text.p pointing to
233 * the first char after the $ that starts a macro reference.
234 * source->string.text.p is returned pointing to the first char after
235 * the macro name.
236 * It will read the macro name, expanding any macros in it,
237 * and get the value. The value is then expanded.
238 * destination is a String that is filled in with the expanded macro.
239 * It may be passed in referencing a buffer to expand the macro into.
240 * Note that most expansions are done on demand, e.g. right
241 * before the command is executed and not while the file is
242 * being parsed.
244 * Parameters:
245 * source The source block that references the string
246 * to expand
247 * destination Where to put the result
248 * current_string The string we are expanding, for error msg
249 * cmd If we are evaluating a command line we
250 * turn \ quoting off
252 * Global variables used:
253 * funny Vector of semantic tags for characters
254 * is_conditional Set if a conditional macro is refd
255 * make_word_mentioned Set if the word "MAKE" is mentioned
256 * makefile_type We deliver extra msg when reading makefiles
257 * query The Name "?", compared against
258 * query_mentioned Set if the word "?" is mentioned
260 void
261 expand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd)
263 static Name make = (Name)NULL;
264 static wchar_t colon_sh[4];
265 static wchar_t colon_shell[7];
266 String_rec string;
267 wchar_t buffer[STRING_BUFFER_LENGTH];
268 register wchar_t *source_p = source->string.text.p;
269 register wchar_t *source_end = source->string.text.end;
270 register int closer = 0;
271 wchar_t *block_start = (wchar_t *)NULL;
272 int quote_seen = 0;
273 register int closer_level = 1;
274 Name name = (Name)NULL;
275 wchar_t *colon = (wchar_t *)NULL;
276 wchar_t *percent = (wchar_t *)NULL;
277 wchar_t *eq = (wchar_t *) NULL;
278 Property macro = NULL;
279 wchar_t *p = (wchar_t*)NULL;
280 String_rec extracted;
281 wchar_t extracted_string[MAXPATHLEN];
282 wchar_t *left_head = NULL;
283 wchar_t *left_tail = NULL;
284 wchar_t *right_tail = NULL;
285 int left_head_len = 0;
286 int left_tail_len = 0;
287 int tmp_len = 0;
288 wchar_t *right_hand[128];
289 int i = 0;
290 enum {
291 no_extract,
292 dir_extract,
293 file_extract
294 } extraction = no_extract;
295 enum {
296 no_replace,
297 suffix_replace,
298 pattern_replace,
299 sh_replace
300 } replacement = no_replace;
302 if (make == NULL) {
303 MBSTOWCS(wcs_buffer, "MAKE");
304 make = GETNAME(wcs_buffer, FIND_LENGTH);
306 MBSTOWCS(colon_sh, ":sh");
307 MBSTOWCS(colon_shell, ":shell");
310 right_hand[0] = NULL;
312 /* First copy the (macro-expanded) macro name into string. */
313 INIT_STRING_FROM_STACK(string, buffer);
314 recheck_first_char:
315 /* Check the first char of the macro name to figure out what to do. */
316 switch (GET_CHAR()) {
317 case nul_char:
318 GET_NEXT_BLOCK_NOCHK(source);
319 if (source == NULL) {
320 WCSTOMBS(mbs_buffer, current_string);
321 fatal_reader_mksh(gettext("'$' at end of string `%s'"),
322 mbs_buffer);
324 if (source->error_converting) {
325 fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
327 goto recheck_first_char;
328 case parenleft_char:
329 /* Multi char name. */
330 closer = (int) parenright_char;
331 break;
332 case braceleft_char:
333 /* Multi char name. */
334 closer = (int) braceright_char;
335 break;
336 case newline_char:
337 fatal_reader_mksh(gettext("'$' at end of line"));
338 default:
339 /* Single char macro name. Just suck it up */
340 append_char(*source_p, &string);
341 source->string.text.p = source_p + 1;
342 goto get_macro_value;
345 /* Handle multi-char macro names */
346 block_start = ++source_p;
347 quote_seen = 0;
348 for (; 1; source_p++) {
349 switch (GET_CHAR()) {
350 case nul_char:
351 append_string(block_start,
352 &string,
353 source_p - block_start);
354 GET_NEXT_BLOCK_NOCHK(source);
355 if (source == NULL) {
356 if (current_string != NULL) {
357 WCSTOMBS(mbs_buffer, current_string);
358 fatal_reader_mksh(gettext("Unmatched `%c' in string `%s'"),
359 closer ==
360 (int) braceright_char ?
361 (int) braceleft_char :
362 (int) parenleft_char,
363 mbs_buffer);
364 } else {
365 fatal_reader_mksh(gettext("Premature EOF"));
368 if (source->error_converting) {
369 fatal_reader_mksh("Internal error: Invalid byte sequence in expand_macro()");
371 block_start = source_p;
372 source_p--;
373 continue;
374 case newline_char:
375 fatal_reader_mksh(gettext("Unmatched `%c' on line"),
376 closer == (int) braceright_char ?
377 (int) braceleft_char :
378 (int) parenleft_char);
379 case backslash_char:
380 /* Quote dollar in macro value. */
381 if (!cmd) {
382 quote_seen = ~quote_seen;
384 continue;
385 case dollar_char:
387 * Macro names may reference macros.
388 * This expands the value of such macros into the
389 * macro name string.
391 if (quote_seen) {
392 append_string(block_start,
393 &string,
394 source_p - block_start - 1);
395 block_start = source_p;
396 break;
398 append_string(block_start,
399 &string,
400 source_p - block_start);
401 source->string.text.p = ++source_p;
402 UNCACHE_SOURCE();
403 expand_macro(source, &string, current_string, cmd);
404 CACHE_SOURCE(0);
405 block_start = source_p;
406 source_p--;
407 break;
408 case parenleft_char:
409 /* Allow nested pairs of () in the macro name. */
410 if (closer == (int) parenright_char) {
411 closer_level++;
413 break;
414 case braceleft_char:
415 /* Allow nested pairs of {} in the macro name. */
416 if (closer == (int) braceright_char) {
417 closer_level++;
419 break;
420 case parenright_char:
421 case braceright_char:
423 * End of the name. Save the string in the macro
424 * name string.
426 if ((*source_p == closer) && (--closer_level <= 0)) {
427 source->string.text.p = source_p + 1;
428 append_string(block_start,
429 &string,
430 source_p - block_start);
431 goto get_macro_value;
433 break;
435 quote_seen = 0;
438 * We got the macro name. We now inspect it to see if it
439 * specifies any translations of the value.
441 get_macro_value:
442 name = NULL;
443 /* First check if we have a $(@D) type translation. */
444 if ((get_char_semantics_value(string.buffer.start[0]) &
445 (int) special_macro_sem) &&
446 (string.text.p - string.buffer.start >= 2) &&
447 ((string.buffer.start[1] == 'D') ||
448 (string.buffer.start[1] == 'F'))) {
449 switch (string.buffer.start[1]) {
450 case 'D':
451 extraction = dir_extract;
452 break;
453 case 'F':
454 extraction = file_extract;
455 break;
456 default:
457 WCSTOMBS(mbs_buffer, string.buffer.start);
458 fatal_reader_mksh(gettext("Illegal macro reference `%s'"),
459 mbs_buffer);
461 /* Internalize the macro name using the first char only. */
462 name = GETNAME(string.buffer.start, 1);
463 (void) wcscpy(string.buffer.start, string.buffer.start + 2);
465 /* Check for other kinds of translations. */
466 if ((colon = (wchar_t *) wcschr(string.buffer.start,
467 (int) colon_char)) != NULL) {
469 * We have a $(FOO:.c=.o) type translation.
470 * Get the name of the macro proper.
472 if (name == NULL) {
473 name = GETNAME(string.buffer.start,
474 colon - string.buffer.start);
476 /* Pickup all the translations. */
477 if (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell)) {
478 replacement = sh_replace;
479 } else if ((svr4) ||
480 ((percent = (wchar_t *) wcschr(colon + 1,
481 (int) percent_char)) == NULL)) {
482 while (colon != NULL) {
483 if ((eq = (wchar_t *) wcschr(colon + 1,
484 (int) equal_char)) == NULL) {
485 fatal_reader_mksh(gettext("= missing from replacement macro reference"));
487 left_tail_len = eq - colon - 1;
488 if(left_tail) {
489 retmem(left_tail);
491 left_tail = ALLOC_WC(left_tail_len + 1);
492 (void) wcsncpy(left_tail,
493 colon + 1,
494 eq - colon - 1);
495 left_tail[eq - colon - 1] = (int) nul_char;
496 replacement = suffix_replace;
497 if ((colon = (wchar_t *) wcschr(eq + 1,
498 (int) colon_char)) != NULL) {
499 tmp_len = colon - eq;
500 if(right_tail) {
501 retmem(right_tail);
503 right_tail = ALLOC_WC(tmp_len);
504 (void) wcsncpy(right_tail,
505 eq + 1,
506 colon - eq - 1);
507 right_tail[colon - eq - 1] =
508 (int) nul_char;
509 } else {
510 if(right_tail) {
511 retmem(right_tail);
513 right_tail = ALLOC_WC(wcslen(eq) + 1);
514 (void) wcscpy(right_tail, eq + 1);
517 } else {
518 if ((eq = (wchar_t *) wcschr(colon + 1,
519 (int) equal_char)) == NULL) {
520 fatal_reader_mksh(gettext("= missing from replacement macro reference"));
522 if ((percent = (wchar_t *) wcschr(colon + 1,
523 (int) percent_char)) == NULL) {
524 fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
526 if (eq < percent) {
527 fatal_reader_mksh(gettext("%% missing from replacement macro reference"));
530 if (percent > (colon + 1)) {
531 tmp_len = percent - colon;
532 if(left_head) {
533 retmem(left_head);
535 left_head = ALLOC_WC(tmp_len);
536 (void) wcsncpy(left_head,
537 colon + 1,
538 percent - colon - 1);
539 left_head[percent-colon-1] = (int) nul_char;
540 left_head_len = percent-colon-1;
541 } else {
542 left_head = NULL;
543 left_head_len = 0;
546 if (eq > percent+1) {
547 tmp_len = eq - percent;
548 if(left_tail) {
549 retmem(left_tail);
551 left_tail = ALLOC_WC(tmp_len);
552 (void) wcsncpy(left_tail,
553 percent + 1,
554 eq - percent - 1);
555 left_tail[eq-percent-1] = (int) nul_char;
556 left_tail_len = eq-percent-1;
557 } else {
558 left_tail = NULL;
559 left_tail_len = 0;
562 if ((percent = (wchar_t *) wcschr(++eq,
563 (int) percent_char)) == NULL) {
565 right_hand[0] = ALLOC_WC(wcslen(eq) + 1);
566 right_hand[1] = NULL;
567 (void) wcscpy(right_hand[0], eq);
568 } else {
569 i = 0;
570 do {
571 right_hand[i] = ALLOC_WC(percent-eq+1);
572 (void) wcsncpy(right_hand[i],
574 percent - eq);
575 right_hand[i][percent-eq] =
576 (int) nul_char;
577 if (i++ >= VSIZEOF(right_hand)) {
578 fatal_mksh(gettext("Too many %% in pattern"));
580 eq = percent + 1;
581 if (eq[0] == (int) nul_char) {
582 MBSTOWCS(wcs_buffer, "");
583 right_hand[i] = (wchar_t *) wcsdup(wcs_buffer);
584 i++;
585 break;
587 } while ((percent = (wchar_t *) wcschr(eq, (int) percent_char)) != NULL);
588 if (eq[0] != (int) nul_char) {
589 right_hand[i] = ALLOC_WC(wcslen(eq) + 1);
590 (void) wcscpy(right_hand[i], eq);
591 i++;
593 right_hand[i] = NULL;
595 replacement = pattern_replace;
598 if (name == NULL) {
600 * No translations found.
601 * Use the whole string as the macro name.
603 name = GETNAME(string.buffer.start,
604 string.text.p - string.buffer.start);
606 if (string.free_after_use) {
607 retmem(string.buffer.start);
609 if (name == make) {
610 make_word_mentioned = true;
612 if (name == query) {
613 query_mentioned = true;
615 if ((name == host_arch) || (name == target_arch)) {
616 if (!init_arch_done) {
617 init_arch_done = true;
618 init_arch_macros();
621 if ((name == host_mach) || (name == target_mach)) {
622 if (!init_mach_done) {
623 init_mach_done = true;
624 init_mach_macros();
627 /* Get the macro value. */
628 macro = get_prop(name->prop, macro_prop);
629 if ((macro != NULL) && macro->body.macro.is_conditional) {
630 conditional_macro_used = true;
632 * Add this conditional macro to the beginning of the
633 * global list.
635 add_macro_to_global_list(name);
636 if (makefile_type == reading_makefile) {
637 warning_mksh(gettext("Conditional macro `%s' referenced in file `%ws', line %d"),
638 name->string_mb, file_being_read, line_number);
641 /* Macro name read and parsed. Expand the value. */
642 if ((macro == NULL) || (macro->body.macro.value == NULL)) {
643 /* If the value is empty, we just get out of here. */
644 goto exit;
646 if (replacement == sh_replace) {
647 /* If we should do a :sh transform, we expand the command
648 * and process it.
650 INIT_STRING_FROM_STACK(string, buffer);
651 /* Expand the value into a local string buffer and run cmd. */
652 expand_value_with_daemon(name, macro, &string, cmd);
653 sh_command2string(&string, destination);
654 } else if ((replacement != no_replace) || (extraction != no_extract)) {
656 * If there were any transforms specified in the macro
657 * name, we deal with them here.
659 INIT_STRING_FROM_STACK(string, buffer);
660 /* Expand the value into a local string buffer. */
661 expand_value_with_daemon(name, macro, &string, cmd);
662 /* Scan the expanded string. */
663 p = string.buffer.start;
664 while (*p != (int) nul_char) {
665 wchar_t chr;
668 * First skip over any white space and append
669 * that to the destination string.
671 block_start = p;
672 while ((*p != (int) nul_char) && iswspace(*p)) {
673 p++;
675 append_string(block_start,
676 destination,
677 p - block_start);
678 /* Then find the end of the next word. */
679 block_start = p;
680 while ((*p != (int) nul_char) && !iswspace(*p)) {
681 p++;
683 /* If we cant find another word we are done */
684 if (block_start == p) {
685 break;
687 /* Then apply the transforms to the word */
688 INIT_STRING_FROM_STACK(extracted, extracted_string);
689 switch (extraction) {
690 case dir_extract:
692 * $(@D) type transform. Extract the
693 * path from the word. Deliver "." if
694 * none is found.
696 if (p != NULL) {
697 chr = *p;
698 *p = (int) nul_char;
700 eq = (wchar_t *) wcsrchr(block_start, (int) slash_char);
701 if (p != NULL) {
702 *p = chr;
704 if ((eq == NULL) || (eq > p)) {
705 MBSTOWCS(wcs_buffer, ".");
706 append_string(wcs_buffer, &extracted, 1);
707 } else {
708 append_string(block_start,
709 &extracted,
710 eq - block_start);
712 break;
713 case file_extract:
715 * $(@F) type transform. Remove the path
716 * from the word if any.
718 if (p != NULL) {
719 chr = *p;
720 *p = (int) nul_char;
722 eq = (wchar_t *) wcsrchr(block_start, (int) slash_char);
723 if (p != NULL) {
724 *p = chr;
726 if ((eq == NULL) || (eq > p)) {
727 append_string(block_start,
728 &extracted,
729 p - block_start);
730 } else {
731 append_string(eq + 1,
732 &extracted,
733 p - eq - 1);
735 break;
736 case no_extract:
737 append_string(block_start,
738 &extracted,
739 p - block_start);
740 break;
742 switch (replacement) {
743 case suffix_replace:
745 * $(FOO:.o=.c) type transform.
746 * Maybe replace the tail of the word.
748 if (((extracted.text.p -
749 extracted.buffer.start) >=
750 left_tail_len) &&
751 IS_WEQUALN(extracted.text.p - left_tail_len,
752 left_tail,
753 left_tail_len)) {
754 append_string(extracted.buffer.start,
755 destination,
756 (extracted.text.p -
757 extracted.buffer.start)
758 - left_tail_len);
759 append_string(right_tail,
760 destination,
761 FIND_LENGTH);
762 } else {
763 append_string(extracted.buffer.start,
764 destination,
765 FIND_LENGTH);
767 break;
768 case pattern_replace:
769 /* $(X:a%b=c%d) type transform. */
770 if (((extracted.text.p -
771 extracted.buffer.start) >=
772 left_head_len+left_tail_len) &&
773 IS_WEQUALN(left_head,
774 extracted.buffer.start,
775 left_head_len) &&
776 IS_WEQUALN(left_tail,
777 extracted.text.p - left_tail_len,
778 left_tail_len)) {
779 i = 0;
780 while (right_hand[i] != NULL) {
781 append_string(right_hand[i],
782 destination,
783 FIND_LENGTH);
784 i++;
785 if (right_hand[i] != NULL) {
786 append_string(extracted.buffer.
787 start +
788 left_head_len,
789 destination,
790 (extracted.text.p - extracted.buffer.start)-left_head_len-left_tail_len);
793 } else {
794 append_string(extracted.buffer.start,
795 destination,
796 FIND_LENGTH);
798 break;
799 case no_replace:
800 append_string(extracted.buffer.start,
801 destination,
802 FIND_LENGTH);
803 break;
804 case sh_replace:
805 break;
808 if (string.free_after_use) {
809 retmem(string.buffer.start);
811 } else {
813 * This is for the case when the macro name did not
814 * specify transforms.
816 if (!strncmp(name->string_mb, "GET", 3)) {
817 dollarget_seen = true;
819 dollarless_flag = false;
820 if (!strncmp(name->string_mb, "<", 1) &&
821 dollarget_seen) {
822 dollarless_flag = true;
823 dollarget_seen = false;
825 expand_value_with_daemon(name, macro, destination, cmd);
827 exit:
828 if(left_tail) {
829 retmem(left_tail);
831 if(right_tail) {
832 retmem(right_tail);
834 if(left_head) {
835 retmem(left_head);
837 i = 0;
838 while (right_hand[i] != NULL) {
839 retmem(right_hand[i]);
840 i++;
842 *destination->text.p = (int) nul_char;
843 destination->text.end = destination->text.p;
846 static void
847 add_macro_to_global_list(Name macro_to_add)
849 Macro_list new_macro;
850 Macro_list macro_on_list;
851 char *name_on_list = NULL;
852 char *name_to_add = macro_to_add->string_mb;
853 char *value_on_list = NULL;
854 const char *value_to_add = NULL;
856 if (macro_to_add->prop->body.macro.value != NULL) {
857 value_to_add = macro_to_add->prop->body.macro.value->string_mb;
858 } else {
859 value_to_add = "";
863 * Check if this macro is already on list, if so, do nothing
865 for (macro_on_list = cond_macro_list;
866 macro_on_list != NULL;
867 macro_on_list = macro_on_list->next) {
869 name_on_list = macro_on_list->macro_name;
870 value_on_list = macro_on_list->value;
872 if (IS_EQUAL(name_on_list, name_to_add)) {
873 if (IS_EQUAL(value_on_list, value_to_add)) {
874 return;
878 new_macro = (Macro_list) malloc(sizeof(Macro_list_rec));
879 new_macro->macro_name = strdup(name_to_add);
880 new_macro->value = strdup(value_to_add);
881 new_macro->next = cond_macro_list;
882 cond_macro_list = new_macro;
886 * init_arch_macros(void)
888 * Set the magic macros TARGET_ARCH, HOST_ARCH,
890 * Parameters:
892 * Global variables used:
893 * host_arch Property for magic macro HOST_ARCH
894 * target_arch Property for magic macro TARGET_ARCH
896 * Return value:
897 * The function does not return a value, but can
898 * call fatal() in case of error.
900 static void
901 init_arch_macros(void)
903 String_rec result_string;
904 wchar_t wc_buf[STRING_BUFFER_LENGTH];
905 char mb_buf[STRING_BUFFER_LENGTH];
906 FILE *pipe;
907 Name value;
908 int set_host, set_target;
910 set_host = (get_prop(host_arch->prop, macro_prop) == NULL);
911 set_target = (get_prop(target_arch->prop, macro_prop) == NULL);
913 if (set_host || set_target) {
914 INIT_STRING_FROM_STACK(result_string, wc_buf);
915 append_char((int) hyphen_char, &result_string);
916 if (sysinfo(SI_PLATFORM, mb_buf, sizeof (mb_buf)) < 0)
917 fatal_mksh(gettext("sysinfo() failed"));
918 MBSTOWCS(wcs_buffer, mb_buf);
919 append_string(wcs_buffer, &result_string, wcslen(wcs_buffer));
921 value = GETNAME(result_string.buffer.start, wcslen(result_string.buffer.start));
923 if (set_host) {
924 (void) setvar_daemon(host_arch, value, false, no_daemon, true, 0);
926 if (set_target) {
927 (void) setvar_daemon(target_arch, value, false, no_daemon, true, 0);
933 * init_mach_macros(void)
935 * Set the magic macros TARGET_MACH, HOST_MACH,
937 * Parameters:
939 * Global variables used:
940 * host_mach Property for magic macro HOST_MACH
941 * target_mach Property for magic macro TARGET_MACH
943 * Return value:
944 * The function does not return a value, but can
945 * call fatal() in case of error.
947 static void
948 init_mach_macros(void)
950 String_rec result_string;
951 wchar_t wc_buf[STRING_BUFFER_LENGTH];
952 FILE *pipe;
953 Name value;
954 int set_host, set_target;
955 struct utsname uts;
957 set_host = (get_prop(host_mach->prop, macro_prop) == NULL);
958 set_target = (get_prop(target_mach->prop, macro_prop) == NULL);
960 if (set_host || set_target) {
961 INIT_STRING_FROM_STACK(result_string, wc_buf);
962 append_char((int) hyphen_char, &result_string);
963 if (uname(&uts) < 0)
964 fatal_mksh(gettext("uname() failed"));
965 MBSTOWCS(wcs_buffer, uts.machine);
966 append_string(wcs_buffer, &result_string, wcslen(wcs_buffer));
968 value = GETNAME(result_string.buffer.start, wcslen(result_string.buffer.start));
970 if (set_host) {
971 (void) setvar_daemon(host_mach, value, false, no_daemon, true, 0);
973 if (set_target) {
974 (void) setvar_daemon(target_mach, value, false, no_daemon, true, 0);
980 * expand_value_with_daemon(name, macro, destination, cmd)
982 * Checks for daemons and then maybe calls expand_value().
984 * Parameters:
985 * name Name of the macro (Added by the NSE)
986 * macro The property block with the value to expand
987 * destination Where the result should be deposited
988 * cmd If we are evaluating a command line we
989 * turn \ quoting off
991 * Global variables used:
993 static void
994 expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd)
996 register Chain chain;
999 switch (macro->body.macro.daemon) {
1000 case no_daemon:
1001 if (!svr4 && !posix) {
1002 expand_value(macro->body.macro.value, destination, cmd);
1003 } else {
1004 if (dollarless_flag && tilde_rule) {
1005 expand_value(dollarless_value, destination, cmd);
1006 dollarless_flag = false;
1007 tilde_rule = false;
1008 } else {
1009 expand_value(macro->body.macro.value, destination, cmd);
1012 return;
1013 case chain_daemon:
1014 /* If this is a $? value we call the daemon to translate the */
1015 /* list of names to a string */
1016 for (chain = (Chain) macro->body.macro.value;
1017 chain != NULL;
1018 chain = chain->next) {
1019 APPEND_NAME(chain->name,
1020 destination,
1021 (int) chain->name->hash.length);
1022 if (chain->next != NULL) {
1023 append_char((int) space_char, destination);
1026 return;
1031 * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1033 char *sunpro_dependencies_buf = NULL;
1034 char *sunpro_dependencies_oldbuf = NULL;
1035 int sunpro_dependencies_buf_size = 0;
1038 * setvar_daemon(name, value, append, daemon, strip_trailing_spaces)
1040 * Set a macro value, possibly supplying a daemon to be used
1041 * when referencing the value.
1043 * Return value:
1044 * The property block with the new value
1046 * Parameters:
1047 * name Name of the macro to set
1048 * value The value to set
1049 * append Should we reset or append to the current value?
1050 * daemon Special treatment when reading the value
1051 * strip_trailing_spaces from the end of value->string
1052 * debug_level Indicates how much tracing we should do
1054 * Global variables used:
1055 * makefile_type Used to check if we should enforce read only
1056 * path_name The Name "PATH", compared against
1057 * virtual_root The Name "VIRTUAL_ROOT", compared against
1058 * vpath_defined Set if the macro VPATH is set
1059 * vpath_name The Name "VPATH", compared against
1060 * envvar A list of environment vars with $ in value
1062 Property
1063 setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
1065 register Property macro = maybe_append_prop(name, macro_prop);
1066 register Property macro_apx = get_prop(name->prop, macro_append_prop);
1067 int length = 0;
1068 String_rec destination;
1069 wchar_t buffer[STRING_BUFFER_LENGTH];
1070 register Chain chain;
1071 Name val;
1072 wchar_t *val_string = (wchar_t*)NULL;
1073 Wstring wcb;
1076 if ((makefile_type != reading_nothing) &&
1077 macro->body.macro.read_only) {
1078 return macro;
1080 /* Strip spaces from the end of the value */
1081 if (daemon == no_daemon) {
1082 if(value != NULL) {
1083 wcb.init(value);
1084 length = wcb.length();
1085 val_string = wcb.get_string();
1087 if ((length > 0) && iswspace(val_string[length-1])) {
1088 INIT_STRING_FROM_STACK(destination, buffer);
1089 buffer[0] = 0;
1090 append_string(val_string, &destination, length);
1091 if (strip_trailing_spaces) {
1092 while ((length > 0) &&
1093 iswspace(destination.buffer.start[length-1])) {
1094 destination.buffer.start[--length] = 0;
1097 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1101 if(macro_apx != NULL) {
1102 val = macro_apx->body.macro_appendix.value;
1103 } else {
1104 val = macro->body.macro.value;
1107 if (append) {
1109 * If we are appending, we just tack the new value after
1110 * the old one with a space in between.
1112 INIT_STRING_FROM_STACK(destination, buffer);
1113 buffer[0] = 0;
1114 if ((macro != NULL) && (val != NULL)) {
1115 APPEND_NAME(val,
1116 &destination,
1117 (int) val->hash.length);
1118 if (value != NULL) {
1119 wcb.init(value);
1120 if(wcb.length() > 0) {
1121 MBTOWC(wcs_buffer, " ");
1122 append_char(wcs_buffer[0], &destination);
1126 if (value != NULL) {
1127 APPEND_NAME(value,
1128 &destination,
1129 (int) value->hash.length);
1131 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1132 wcb.init(value);
1133 if (destination.free_after_use) {
1134 retmem(destination.buffer.start);
1138 /* Debugging trace */
1139 if (debug_level > 1) {
1140 if (value != NULL) {
1141 switch (daemon) {
1142 case chain_daemon:
1143 (void) printf("%s =", name->string_mb);
1144 for (chain = (Chain) value;
1145 chain != NULL;
1146 chain = chain->next) {
1147 (void) printf(" %s", chain->name->string_mb);
1149 (void) printf("\n");
1150 break;
1151 case no_daemon:
1152 (void) printf("%s= %s\n",
1153 name->string_mb,
1154 value->string_mb);
1155 break;
1157 } else {
1158 (void) printf("%s =\n", name->string_mb);
1161 /* Set the new values in the macro property block */
1162 /**/
1163 if(macro_apx != NULL) {
1164 macro_apx->body.macro_appendix.value = value;
1165 INIT_STRING_FROM_STACK(destination, buffer);
1166 buffer[0] = 0;
1167 if (value != NULL) {
1168 APPEND_NAME(value,
1169 &destination,
1170 (int) value->hash.length);
1171 if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1172 MBTOWC(wcs_buffer, " ");
1173 append_char(wcs_buffer[0], &destination);
1176 if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1177 APPEND_NAME(macro_apx->body.macro_appendix.value_to_append,
1178 &destination,
1179 (int) macro_apx->body.macro_appendix.value_to_append->hash.length);
1181 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1182 if (destination.free_after_use) {
1183 retmem(destination.buffer.start);
1186 /**/
1187 macro->body.macro.value = value;
1188 macro->body.macro.daemon = daemon;
1190 * If the user changes the VIRTUAL_ROOT, we need to flush
1191 * the vroot package cache.
1193 if (name == path_name) {
1194 flush_path_cache();
1196 if (name == virtual_root) {
1197 flush_vroot_cache();
1199 /* If this sets the VPATH we remember that */
1200 if ((name == vpath_name) &&
1201 (value != NULL) &&
1202 (value->hash.length > 0)) {
1203 vpath_defined = true;
1206 * For environment variables we also set the
1207 * environment value each time.
1209 if (macro->body.macro.exported) {
1210 static char *env;
1212 if (!reading_environment && (value != NULL)) {
1213 Envvar p;
1215 for (p = envvar; p != NULL; p = p->next) {
1216 if (p->name == name) {
1217 p->value = value;
1218 p->already_put = false;
1219 goto found_it;
1222 p = ALLOC(Envvar);
1223 p->name = name;
1224 p->value = value;
1225 p->next = envvar;
1226 p->env_string = NULL;
1227 p->already_put = false;
1228 envvar = p;
1229 found_it:;
1230 } if (reading_environment || (value == NULL) || !value->dollar) {
1231 length = 2 + strlen(name->string_mb);
1232 if (value != NULL) {
1233 length += strlen(value->string_mb);
1235 Property env_prop = maybe_append_prop(name, env_mem_prop);
1237 * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1239 if (!strncmp(name->string_mb, "SUNPRO_DEPENDENCIES", 19)) {
1240 if (length >= sunpro_dependencies_buf_size) {
1241 sunpro_dependencies_buf_size=length*2;
1242 if (sunpro_dependencies_buf_size < 4096)
1243 sunpro_dependencies_buf_size = 4096; // Default minimum size
1244 if (sunpro_dependencies_buf)
1245 sunpro_dependencies_oldbuf = sunpro_dependencies_buf;
1246 sunpro_dependencies_buf=getmem(sunpro_dependencies_buf_size);
1248 env = sunpro_dependencies_buf;
1249 } else {
1250 env = getmem(length);
1252 env_alloc_num++;
1253 env_alloc_bytes += length;
1254 (void) sprintf(env,
1255 "%s=%s",
1256 name->string_mb,
1257 value == NULL ?
1258 "" : value->string_mb);
1259 (void) putenv(env);
1260 env_prop->body.env_mem.value = env;
1261 if (sunpro_dependencies_oldbuf) {
1262 /* Return old buffer */
1263 retmem_mb(sunpro_dependencies_oldbuf);
1264 sunpro_dependencies_oldbuf = NULL;
1268 if (name == target_arch) {
1269 Name ha = getvar(host_arch);
1270 Name ta = getvar(target_arch);
1271 Name vr = getvar(virtual_root);
1272 int length;
1273 wchar_t *new_value;
1274 wchar_t *old_vr;
1275 Boolean new_value_allocated = false;
1277 Wstring ha_str(ha);
1278 Wstring ta_str(ta);
1279 Wstring vr_str(vr);
1281 wchar_t * wcb_ha = ha_str.get_string();
1282 wchar_t * wcb_ta = ta_str.get_string();
1283 wchar_t * wcb_vr = vr_str.get_string();
1285 length = 32 +
1286 wcslen(wcb_ha) +
1287 wcslen(wcb_ta) +
1288 wcslen(wcb_vr);
1289 old_vr = wcb_vr;
1290 MBSTOWCS(wcs_buffer, "/usr/arch/");
1291 if (IS_WEQUALN(old_vr,
1292 wcs_buffer,
1293 wcslen(wcs_buffer))) {
1294 old_vr = (wchar_t *) wcschr(old_vr, (int) colon_char) + 1;
1296 if ( (ha == ta) || (wcslen(wcb_ta) == 0) ) {
1297 new_value = old_vr;
1298 } else {
1299 new_value = ALLOC_WC(length);
1300 new_value_allocated = true;
1301 WCSTOMBS(mbs_buffer, old_vr);
1302 (void) swprintf(new_value, length * SIZEOFWCHAR_T,
1303 L"/usr/arch/%s/%s:%s",
1304 ha->string_mb + 1,
1305 ta->string_mb + 1,
1306 mbs_buffer);
1308 if (new_value[0] != 0) {
1309 (void) setvar_daemon(virtual_root,
1310 GETNAME(new_value, FIND_LENGTH),
1311 false,
1312 no_daemon,
1313 true,
1314 debug_level);
1316 if (new_value_allocated) {
1317 retmem(new_value);
1320 return macro;