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