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 #if defined(linux)
928 const char *mach_command = NOCATGETS("/bin/uname -p");
929 #else
930 const char *mach_command = NOCATGETS("/bin/mach");
931 #endif
932
933 set_host = (get_prop(host_arch->prop, macro_prop) == NULL);
934 set_target = (get_prop(target_arch->prop, macro_prop) == NULL);
935
936 if (set_host || set_target) {
937 INIT_STRING_FROM_STACK(result_string, wc_buf);
938 append_char((int) hyphen_char, &result_string);
939
940 if ((pipe = popen(mach_command, "r")) == NULL) {
941 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 185, "Execute of %s failed"), mach_command);
942 }
943 while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
944 MBSTOWCS(wcs_buffer, mb_buf);
945 append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
946 }
947 if (pclose(pipe) != 0) {
948 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 186, "Execute of %s failed"), mach_command);
949 }
950
951 value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
952
953 #ifdef NSE
954 macro = setvar_daemon(host_arch, value, false, no_daemon, true, 0);
955 macro->body.macro.imported= true;
956 macro = setvar_daemon(target_arch, value, false, no_daemon, true, 0);
957 macro->body.macro.imported= true;
958 #else
959 if (set_host) {
960 (void) setvar_daemon(host_arch, value, false, no_daemon, true, 0);
961 }
962 if (set_target) {
963 (void) setvar_daemon(target_arch, value, false, no_daemon, true, 0);
964 }
965 #endif
966 }
967 }
968
969 /*
970 * init_mach_macros(void)
971 *
972 * Set the magic macros TARGET_MACH, HOST_MACH,
973 *
974 * Parameters:
975 *
976 * Global variables used:
977 * host_mach Property for magic macro HOST_MACH
978 * target_mach Property for magic macro TARGET_MACH
979 *
980 * Return value:
981 * The function does not return a value, but can
982 * call fatal() in case of error.
983 */
984 static void
985 init_mach_macros(void)
986 {
987 String_rec result_string;
988 wchar_t wc_buf[STRING_BUFFER_LENGTH];
989 char mb_buf[STRING_BUFFER_LENGTH];
990 FILE *pipe;
991 Name value;
992 int set_host, set_target;
993 const char *arch_command = NOCATGETS("/bin/arch");
994
995 set_host = (get_prop(host_mach->prop, macro_prop) == NULL);
996 set_target = (get_prop(target_mach->prop, macro_prop) == NULL);
997
998 if (set_host || set_target) {
999 INIT_STRING_FROM_STACK(result_string, wc_buf);
1000 append_char((int) hyphen_char, &result_string);
1001
1002 if ((pipe = popen(arch_command, "r")) == NULL) {
1003 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 183, "Execute of %s failed"), arch_command);
1004 }
1005 while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
1006 MBSTOWCS(wcs_buffer, mb_buf);
1007 append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
1008 }
1009 if (pclose(pipe) != 0) {
1010 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 184, "Execute of %s failed"), arch_command);
1011 }
1012
1013 value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
1014
1015 if (set_host) {
1016 (void) setvar_daemon(host_mach, value, false, no_daemon, true, 0);
1017 }
1018 if (set_target) {
1019 (void) setvar_daemon(target_mach, value, false, no_daemon, true, 0);
1020 }
1021 }
1022 }
1023
1024 /*
1025 * expand_value_with_daemon(name, macro, destination, cmd)
1026 *
1027 * Checks for daemons and then maybe calls expand_value().
1028 *
1029 * Parameters:
1030 * name Name of the macro (Added by the NSE)
1031 * macro The property block with the value to expand
1032 * destination Where the result should be deposited
1033 * cmd If we are evaluating a command line we
1034 * turn \ quoting off
1035 *
1036 * Global variables used:
1037 */
1038 static void
1039 #ifdef NSE
1040 expand_value_with_daemon(Name name, register Property macro, register String destination, Boolean cmd)
1041 #else
1042 expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd)
1043 #endif
1044 {
1045 register Chain chain;
1046
1047 #ifdef NSE
1048 if (reading_dependencies) {
1049 /*
1050 * Processing the dependencies themselves
1051 */
1052 depvar_dep_macro_used(name);
1053 } else {
1054 /*
1055 * Processing the rules for the targets
1056 * the nse_watch_vars flags chokes off most
1057 * checks. it is true only when processing
1058 * the output from a recursive make run
1059 * which is all we are interested in here.
1060 */
1061 if (nse_watch_vars) {
1062 depvar_rule_macro_used(name);
1063 }
1064 }
1065 #endif
1066
1067 switch (macro->body.macro.daemon) {
1068 case no_daemon:
1069 if (!svr4 && !posix) {
1070 expand_value(macro->body.macro.value, destination, cmd);
1071 } else {
1072 if (dollarless_flag && tilde_rule) {
1073 expand_value(dollarless_value, destination, cmd);
1074 dollarless_flag = false;
1075 tilde_rule = false;
1076 } else {
1077 expand_value(macro->body.macro.value, destination, cmd);
1078 }
1079 }
1080 return;
1081 case chain_daemon:
1082 /* If this is a $? value we call the daemon to translate the */
1083 /* list of names to a string */
1084 for (chain = (Chain) macro->body.macro.value;
1085 chain != NULL;
1086 chain = chain->next) {
1087 APPEND_NAME(chain->name,
1088 destination,
1089 (int) chain->name->hash.length);
1090 if (chain->next != NULL) {
1091 append_char((int) space_char, destination);
1092 }
1093 }
1094 return;
1095 }
1096 }
1097
1098 /*
1099 * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1100 */
1101 char *sunpro_dependencies_buf = NULL;
1102 char *sunpro_dependencies_oldbuf = NULL;
1103 int sunpro_dependencies_buf_size = 0;
1104
1105 /*
1106 * setvar_daemon(name, value, append, daemon, strip_trailing_spaces)
1107 *
1108 * Set a macro value, possibly supplying a daemon to be used
1109 * when referencing the value.
1110 *
1111 * Return value:
1112 * The property block with the new value
1113 *
1114 * Parameters:
1115 * name Name of the macro to set
1116 * value The value to set
1117 * append Should we reset or append to the current value?
1118 * daemon Special treatment when reading the value
1119 * strip_trailing_spaces from the end of value->string
1120 * debug_level Indicates how much tracing we should do
1121 *
1122 * Global variables used:
1123 * makefile_type Used to check if we should enforce read only
1124 * path_name The Name "PATH", compared against
1125 * virtual_root The Name "VIRTUAL_ROOT", compared against
1126 * vpath_defined Set if the macro VPATH is set
1127 * vpath_name The Name "VPATH", compared against
1128 * envvar A list of environment vars with $ in value
1129 */
1130 Property
1131 setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
1132 {
1133 register Property macro = maybe_append_prop(name, macro_prop);
1134 register Property macro_apx = get_prop(name->prop, macro_append_prop);
1135 int length = 0;
1136 String_rec destination;
1137 wchar_t buffer[STRING_BUFFER_LENGTH];
1138 register Chain chain;
1139 Name val;
1140 wchar_t *val_string = (wchar_t*)NULL;
1141 Wstring wcb;
1142
1143 #ifdef NSE
1144 macro->body.macro.imported = false;
1145 #endif
1146
1147 if ((makefile_type != reading_nothing) &&
1148 macro->body.macro.read_only) {
1149 return macro;
1150 }
1151 /* Strip spaces from the end of the value */
1152 if (daemon == no_daemon) {
1153 if(value != NULL) {
1154 wcb.init(value);
1155 length = wcb.length();
1156 val_string = wcb.get_string();
1157 }
1158 if ((length > 0) && iswspace(val_string[length-1])) {
1159 INIT_STRING_FROM_STACK(destination, buffer);
1160 buffer[0] = 0;
1161 append_string(val_string, &destination, length);
1162 if (strip_trailing_spaces) {
1163 while ((length > 0) &&
1164 iswspace(destination.buffer.start[length-1])) {
1165 destination.buffer.start[--length] = 0;
1166 }
1167 }
1168 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1169 }
1170 }
1171
1172 if(macro_apx != NULL) {
1173 val = macro_apx->body.macro_appendix.value;
1174 } else {
1175 val = macro->body.macro.value;
1176 }
1177
1178 if (append) {
1179 /*
1180 * If we are appending, we just tack the new value after
1181 * the old one with a space in between.
1182 */
1183 INIT_STRING_FROM_STACK(destination, buffer);
1184 buffer[0] = 0;
1185 if ((macro != NULL) && (val != NULL)) {
1186 APPEND_NAME(val,
1187 &destination,
1188 (int) val->hash.length);
1189 if (value != NULL) {
1190 wcb.init(value);
1191 if(wcb.length() > 0) {
1192 MBTOWC(wcs_buffer, " ");
1193 append_char(wcs_buffer[0], &destination);
1194 }
1195 }
1196 }
1197 if (value != NULL) {
1198 APPEND_NAME(value,
1199 &destination,
1200 (int) value->hash.length);
1201 }
1202 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1203 wcb.init(value);
1204 if (destination.free_after_use) {
1205 retmem(destination.buffer.start);
1206 }
1207 }
1208
1209 /* Debugging trace */
1210 if (debug_level > 1) {
1211 if (value != NULL) {
1212 switch (daemon) {
1213 case chain_daemon:
1214 (void) printf("%s =", name->string_mb);
1215 for (chain = (Chain) value;
1216 chain != NULL;
1217 chain = chain->next) {
1218 (void) printf(" %s", chain->name->string_mb);
1219 }
1220 (void) printf("\n");
1221 break;
1222 case no_daemon:
1223 (void) printf("%s= %s\n",
1224 name->string_mb,
1225 value->string_mb);
1226 break;
1227 }
1228 } else {
1229 (void) printf("%s =\n", name->string_mb);
1230 }
1231 }
1232 /* Set the new values in the macro property block */
1233 /**/
1234 if(macro_apx != NULL) {
1235 macro_apx->body.macro_appendix.value = value;
1236 INIT_STRING_FROM_STACK(destination, buffer);
1237 buffer[0] = 0;
1238 if (value != NULL) {
1239 APPEND_NAME(value,
1240 &destination,
1241 (int) value->hash.length);
1242 if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1243 MBTOWC(wcs_buffer, " ");
1244 append_char(wcs_buffer[0], &destination);
1245 }
1246 }
1247 if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1248 APPEND_NAME(macro_apx->body.macro_appendix.value_to_append,
1249 &destination,
1250 (int) macro_apx->body.macro_appendix.value_to_append->hash.length);
1251 }
1252 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1253 if (destination.free_after_use) {
1254 retmem(destination.buffer.start);
1255 }
1256 }
1257 /**/
1258 macro->body.macro.value = value;
1259 macro->body.macro.daemon = daemon;
1260 /*
1261 * If the user changes the VIRTUAL_ROOT, we need to flush
1262 * the vroot package cache.
1263 */
1264 if (name == path_name) {
1265 flush_path_cache();
1266 }
1267 if (name == virtual_root) {
1268 flush_vroot_cache();
1269 }
1270 /* If this sets the VPATH we remember that */
1271 if ((name == vpath_name) &&
1272 (value != NULL) &&
1273 (value->hash.length > 0)) {
1274 vpath_defined = true;
1275 }
1276 /*
1277 * For environment variables we also set the
1278 * environment value each time.
1279 */
1280 if (macro->body.macro.exported) {
1281 static char *env;
1282
1283 #ifdef DISTRIBUTED
1284 if (!reading_environment && (value != NULL)) {
1285 #else
1286 if (!reading_environment && (value != NULL) && value->dollar) {
1287 #endif
1288 Envvar p;
1289
1290 for (p = envvar; p != NULL; p = p->next) {
1291 if (p->name == name) {
1292 p->value = value;
1293 p->already_put = false;
1294 goto found_it;
1295 }
1296 }
1297 p = ALLOC(Envvar);
1298 p->name = name;
1299 p->value = value;
1300 p->next = envvar;
1301 p->env_string = NULL;
1302 p->already_put = false;
1303 envvar = p;
1304 found_it:;
1305 #ifdef DISTRIBUTED
1306 }
1307 if (reading_environment || (value == NULL) || !value->dollar) {
1308 #else
1309 } else {
1310 #endif
1311 length = 2 + strlen(name->string_mb);
1312 if (value != NULL) {
1313 length += strlen(value->string_mb);
1314 }
1315 Property env_prop = maybe_append_prop(name, env_mem_prop);
1316 /*
1317 * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1318 */
1319 if (!strncmp(name->string_mb, NOCATGETS("SUNPRO_DEPENDENCIES"), 19)) {
1320 if (length >= sunpro_dependencies_buf_size) {
1321 sunpro_dependencies_buf_size=length*2;
1322 if (sunpro_dependencies_buf_size < 4096)
1323 sunpro_dependencies_buf_size = 4096; // Default minimum size
1324 if (sunpro_dependencies_buf)
1325 sunpro_dependencies_oldbuf = sunpro_dependencies_buf;
1326 sunpro_dependencies_buf=getmem(sunpro_dependencies_buf_size);
1327 }
1328 env = sunpro_dependencies_buf;
1329 } else {
1330 env = getmem(length);
1331 }
1332 env_alloc_num++;
1333 env_alloc_bytes += length;
1334 (void) sprintf(env,
1335 "%s=%s",
1336 name->string_mb,
1337 value == NULL ?
1338 "" : value->string_mb);
1339 (void) putenv(env);
1340 env_prop->body.env_mem.value = env;
1341 if (sunpro_dependencies_oldbuf) {
1342 /* Return old buffer */
1343 retmem_mb(sunpro_dependencies_oldbuf);
1344 sunpro_dependencies_oldbuf = NULL;
1345 }
1346 }
1347 }
1348 if (name == target_arch) {
1349 Name ha = getvar(host_arch);
1350 Name ta = getvar(target_arch);
1351 Name vr = getvar(virtual_root);
1352 int length;
1353 wchar_t *new_value;
1354 wchar_t *old_vr;
1355 Boolean new_value_allocated = false;
1356
1357 Wstring ha_str(ha);
1358 Wstring ta_str(ta);
1359 Wstring vr_str(vr);
1360
1361 wchar_t * wcb_ha = ha_str.get_string();
1362 wchar_t * wcb_ta = ta_str.get_string();
1363 wchar_t * wcb_vr = vr_str.get_string();
1364
1365 length = 32 +
1366 wslen(wcb_ha) +
1367 wslen(wcb_ta) +
1368 wslen(wcb_vr);
1369 old_vr = wcb_vr;
1370 MBSTOWCS(wcs_buffer, NOCATGETS("/usr/arch/"));
1371 if (IS_WEQUALN(old_vr,
1372 wcs_buffer,
1373 wslen(wcs_buffer))) {
1374 old_vr = (wchar_t *) wschr(old_vr, (int) colon_char) + 1;
1375 }
1376 if ( (ha == ta) || (wslen(wcb_ta) == 0) ) {
1377 new_value = old_vr;
1378 } else {
1379 new_value = ALLOC_WC(length);
1380 new_value_allocated = true;
1381 WCSTOMBS(mbs_buffer, old_vr);
1382 #if !defined(linux)
1383 (void) wsprintf(new_value,
1384 NOCATGETS("/usr/arch/%s/%s:%s"),
1385 ha->string_mb + 1,
1386 ta->string_mb + 1,
1387 mbs_buffer);
1388 #else
1389 char * mbs_new_value = (char *)getmem(length);
1390 (void) sprintf(mbs_new_value,
1391 NOCATGETS("/usr/arch/%s/%s:%s"),
1392 ha->string_mb + 1,
1393 ta->string_mb + 1,
1394 mbs_buffer);
1395 MBSTOWCS(new_value, mbs_new_value);
1396 retmem_mb(mbs_new_value);
1397 #endif
1398 }
1399 if (new_value[0] != 0) {
1400 (void) setvar_daemon(virtual_root,
1401 GETNAME(new_value, FIND_LENGTH),
1402 false,
1403 no_daemon,
1404 true,
1405 debug_level);
1406 }
1407 if (new_value_allocated) {
1408 retmem(new_value);
1409 }
1410 }
1411 return macro;
1412 }