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