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