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