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