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