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