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