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