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