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 2005 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Copyright 2019, Joyent, Inc. 26 */ 27 28 /* 29 * misc.cc 30 * 31 * This file contains various unclassified routines. Some main groups: 32 * getname 33 * Memory allocation 34 * String handling 35 * Property handling 36 * Error message handling 37 * Make internal state dumping 38 * main routine support 39 */ 40 41 /* 42 * Included files 43 */ 44 #include <errno.h> 45 #include <mk/defs.h> 46 #include <mksh/macro.h> /* SETVAR() */ 47 #include <mksh/misc.h> /* enable_interrupt() */ 48 #include <stdarg.h> /* va_list, va_start(), va_end() */ 49 #include <vroot/report.h> /* SUNPRO_DEPENDENCIES */ 50 #include <libintl.h> 51 52 extern void job_adjust_fini(); 53 54 /* 55 * Defined macros 56 */ 57 58 /* 59 * typedefs & structs 60 */ 61 62 /* 63 * Static variables 64 */ 65 66 /* 67 * File table of contents 68 */ 69 static void print_rule(register Name target); 70 static void print_target_n_deps(register Name target); 71 72 /***************************************** 73 * 74 * getname 75 */ 76 77 /***************************************** 78 * 79 * Memory allocation 80 */ 81 82 /* 83 * free_chain() 84 * 85 * frees a chain of Name_vector's 86 * 87 * Parameters: 88 * ptr Pointer to the first element in the chain 89 * to be freed. 90 * 91 * Global variables used: 92 */ 93 void 94 free_chain(Name_vector ptr) 95 { 96 if (ptr != NULL) { 97 if (ptr->next != NULL) { 98 free_chain(ptr->next); 99 } 100 free((char *) ptr); 101 } 102 } 103 104 /***************************************** 105 * 106 * String manipulation 107 */ 108 109 /***************************************** 110 * 111 * Nameblock property handling 112 */ 113 114 /***************************************** 115 * 116 * Error message handling 117 */ 118 119 /* 120 * fatal(format, args...) 121 * 122 * Print a message and die 123 * 124 * Parameters: 125 * format printf type format string 126 * args Arguments to match the format 127 * 128 * Global variables used: 129 * fatal_in_progress Indicates if this is a recursive call 130 * parallel_process_cnt Do we need to wait for anything? 131 * report_pwd Should we report the current path? 132 */ 133 /*VARARGS*/ 134 void 135 fatal(const char *message, ...) 136 { 137 va_list args; 138 139 va_start(args, message); 140 (void) fflush(stdout); 141 (void) fprintf(stderr, gettext("%s: Fatal error: "), getprogname()); 142 (void) vfprintf(stderr, message, args); 143 (void) fprintf(stderr, "\n"); 144 va_end(args); 145 if (report_pwd) { 146 (void) fprintf(stderr, 147 gettext("Current working directory %s\n"), 148 get_current_path()); 149 } 150 (void) fflush(stderr); 151 if (fatal_in_progress) { 152 exit_status = 1; 153 exit(1); 154 } 155 fatal_in_progress = true; 156 /* Let all parallel children finish */ 157 if ((dmake_mode_type == parallel_mode) && 158 (parallel_process_cnt > 0)) { 159 (void) fprintf(stderr, 160 gettext("Waiting for %d %s to finish\n"), 161 parallel_process_cnt, 162 parallel_process_cnt == 1 ? 163 gettext("job") : gettext("jobs")); 164 (void) fflush(stderr); 165 } 166 167 while (parallel_process_cnt > 0) { 168 await_parallel(true); 169 finish_children(false); 170 } 171 172 job_adjust_fini(); 173 174 exit_status = 1; 175 exit(1); 176 } 177 178 /* 179 * warning(format, args...) 180 * 181 * Print a message and continue. 182 * 183 * Parameters: 184 * format printf type format string 185 * args Arguments to match the format 186 * 187 * Global variables used: 188 * report_pwd Should we report the current path? 189 */ 190 /*VARARGS*/ 191 void 192 warning(char * message, ...) 193 { 194 va_list args; 195 196 va_start(args, message); 197 (void) fflush(stdout); 198 (void) fprintf(stderr, gettext("%s: Warning: "), getprogname()); 199 (void) vfprintf(stderr, message, args); 200 (void) fprintf(stderr, "\n"); 201 va_end(args); 202 if (report_pwd) { 203 (void) fprintf(stderr, 204 gettext("Current working directory %s\n"), 205 get_current_path()); 206 } 207 (void) fflush(stderr); 208 } 209 210 /* 211 * time_to_string(time) 212 * 213 * Take a numeric time value and produce 214 * a proper string representation. 215 * 216 * Return value: 217 * The string representation of the time 218 * 219 * Parameters: 220 * time The time we need to translate 221 * 222 * Global variables used: 223 */ 224 char * 225 time_to_string(const timestruc_t &time) 226 { 227 struct tm *tm; 228 char buf[128]; 229 230 if (time == file_doesnt_exist) { 231 return gettext("File does not exist"); 232 } 233 if (time == file_max_time) { 234 return gettext("Younger than any file"); 235 } 236 tm = localtime(&time.tv_sec); 237 strftime(buf, sizeof (buf), "%c %Z", tm); 238 buf[127] = (int) nul_char; 239 return strdup(buf); 240 } 241 242 /* 243 * get_current_path() 244 * 245 * Stuff current_path with the current path if it isnt there already. 246 * 247 * Parameters: 248 * 249 * Global variables used: 250 */ 251 char * 252 get_current_path(void) 253 { 254 char pwd[(MAXPATHLEN * MB_LEN_MAX)]; 255 static char *current_path = NULL; 256 257 /* 258 * When we hit this with path_reset to true, we do not free the older 259 * version of current_path at this time, as we don't have confidence 260 * that we've properly caught all users of it and they haven't cached 261 * the pointer somewhere. As such, since this is only currently set with 262 * the -C option is passed in, it seems OK to just let that bit go. 263 */ 264 if (current_path == NULL || path_reset == true) { 265 getcwd(pwd, sizeof(pwd)); 266 if (pwd[0] == (int) nul_char) { 267 pwd[0] = (int) slash_char; 268 pwd[1] = (int) nul_char; 269 } 270 current_path = strdup(pwd); 271 path_reset = false; 272 } 273 return current_path; 274 } 275 276 /***************************************** 277 * 278 * Make internal state dumping 279 * 280 * This is a set of routines for dumping the internal make state 281 * Used for the -p option 282 */ 283 284 /* 285 * dump_make_state() 286 * 287 * Dump make's internal state to stdout 288 * 289 * Parameters: 290 * 291 * Global variables used: 292 * svr4 Was ".SVR4" seen in makefile? 293 * svr4_name The Name ".SVR4", printed 294 * posix Was ".POSIX" seen in makefile? 295 * posix_name The Name ".POSIX", printed 296 * default_rule Points to the .DEFAULT rule 297 * default_rule_name The Name ".DEFAULT", printed 298 * default_target_to_build The first target to print 299 * dot_keep_state The Name ".KEEP_STATE", printed 300 * dot_keep_state_file The Name ".KEEP_STATE_FILE", printed 301 * hashtab The make hash table for Name blocks 302 * ignore_errors Was ".IGNORE" seen in makefile? 303 * ignore_name The Name ".IGNORE", printed 304 * keep_state Was ".KEEP_STATE" seen in makefile? 305 * percent_list The list of % rules 306 * precious The Name ".PRECIOUS", printed 307 * sccs_get_name The Name ".SCCS_GET", printed 308 * sccs_get_posix_name The Name ".SCCS_GET_POSIX", printed 309 * get_name The Name ".GET", printed 310 * get_posix_name The Name ".GET_POSIX", printed 311 * sccs_get_rule Points to the ".SCCS_GET" rule 312 * silent Was ".SILENT" seen in makefile? 313 * silent_name The Name ".SILENT", printed 314 * suffixes The suffix list from ".SUFFIXES" 315 * suffixes_name The Name ".SUFFIX", printed 316 */ 317 void 318 dump_make_state(void) 319 { 320 Name_set::iterator p, e; 321 register Property prop; 322 register Dependency dep; 323 register Cmd_line rule; 324 Percent percent, percent_depe; 325 326 /* Default target */ 327 if (default_target_to_build != NULL) { 328 print_rule(default_target_to_build); 329 } 330 (void) printf("\n"); 331 332 /* .POSIX */ 333 if (posix) { 334 (void) printf("%s:\n", posix_name->string_mb); 335 } 336 337 /* .DEFAULT */ 338 if (default_rule != NULL) { 339 (void) printf("%s:\n", default_rule_name->string_mb); 340 for (rule = default_rule; rule != NULL; rule = rule->next) { 341 (void) printf("\t%s\n", rule->command_line->string_mb); 342 } 343 } 344 345 /* .IGNORE */ 346 if (ignore_errors) { 347 (void) printf("%s:\n", ignore_name->string_mb); 348 } 349 350 /* .KEEP_STATE: */ 351 if (keep_state) { 352 (void) printf("%s:\n\n", dot_keep_state->string_mb); 353 } 354 355 /* .PRECIOUS */ 356 (void) printf("%s:", precious->string_mb); 357 for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) { 358 if ((p->stat.is_precious) || (all_precious)) { 359 (void) printf(" %s", p->string_mb); 360 } 361 } 362 (void) printf("\n"); 363 364 /* .SCCS_GET */ 365 if (sccs_get_rule != NULL) { 366 (void) printf("%s:\n", sccs_get_name->string_mb); 367 for (rule = sccs_get_rule; rule != NULL; rule = rule->next) { 368 (void) printf("\t%s\n", rule->command_line->string_mb); 369 } 370 } 371 372 /* .SILENT */ 373 if (silent) { 374 (void) printf("%s:\n", silent_name->string_mb); 375 } 376 377 /* .SUFFIXES: */ 378 (void) printf("%s:", suffixes_name->string_mb); 379 for (dep = suffixes; dep != NULL; dep = dep->next) { 380 (void) printf(" %s", dep->name->string_mb); 381 build_suffix_list(dep->name); 382 } 383 (void) printf("\n\n"); 384 385 /* % rules */ 386 for (percent = percent_list; 387 percent != NULL; 388 percent = percent->next) { 389 (void) printf("%s:", 390 percent->name->string_mb); 391 392 for (percent_depe = percent->dependencies; 393 percent_depe != NULL; 394 percent_depe = percent_depe->next) { 395 (void) printf(" %s", percent_depe->name->string_mb); 396 } 397 398 (void) printf("\n"); 399 400 for (rule = percent->command_template; 401 rule != NULL; 402 rule = rule->next) { 403 (void) printf("\t%s\n", rule->command_line->string_mb); 404 } 405 } 406 407 /* Suffix rules */ 408 for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) { 409 Wstring wcb(p); 410 if (wcb.get_string()[0] == (int) period_char) { 411 print_rule(p); 412 } 413 } 414 415 /* Macro assignments */ 416 for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) { 417 if (((prop = get_prop(p->prop, macro_prop)) != NULL) && 418 (prop->body.macro.value != NULL)) { 419 (void) printf("%s", p->string_mb); 420 print_value(prop->body.macro.value, 421 (Daemon) prop->body.macro.daemon); 422 } 423 } 424 (void) printf("\n"); 425 426 /* Conditional macro assignments */ 427 for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) { 428 for (prop = get_prop(p->prop, conditional_prop); 429 prop != NULL; 430 prop = get_prop(prop->next, conditional_prop)) { 431 (void) printf("%s := %s", 432 p->string_mb, 433 prop->body.conditional.name-> 434 string_mb); 435 if (prop->body.conditional.append) { 436 printf(" +"); 437 } 438 else { 439 printf(" "); 440 } 441 print_value(prop->body.conditional.value, 442 no_daemon); 443 } 444 } 445 (void) printf("\n"); 446 447 /* All other dependencies */ 448 for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) { 449 if (p->colons != no_colon) { 450 print_rule(p); 451 } 452 } 453 (void) printf("\n"); 454 } 455 456 /* 457 * print_rule(target) 458 * 459 * Print the rule for one target 460 * 461 * Parameters: 462 * target Target we print rule for 463 * 464 * Global variables used: 465 */ 466 static void 467 print_rule(register Name target) 468 { 469 register Cmd_line rule; 470 register Property line; 471 register Dependency dependency; 472 473 if (target->dependency_printed || 474 ((line = get_prop(target->prop, line_prop)) == NULL) || 475 ((line->body.line.command_template == NULL) && 476 (line->body.line.dependencies == NULL))) { 477 return; 478 } 479 target->dependency_printed = true; 480 481 (void) printf("%s:", target->string_mb); 482 483 for (dependency = line->body.line.dependencies; 484 dependency != NULL; 485 dependency = dependency->next) { 486 (void) printf(" %s", dependency->name->string_mb); 487 } 488 489 (void) printf("\n"); 490 491 for (rule = line->body.line.command_template; 492 rule != NULL; 493 rule = rule->next) { 494 (void) printf("\t%s\n", rule->command_line->string_mb); 495 } 496 } 497 498 void 499 dump_target_list(void) 500 { 501 Name_set::iterator p, e; 502 Wstring str; 503 504 for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) { 505 str.init(p); 506 wchar_t * wcb = str.get_string(); 507 if ((p->colons != no_colon) && 508 ((wcb[0] != (int) period_char) || 509 ((wcb[0] == (int) period_char) && 510 (wcschr(wcb, (int) slash_char))))) { 511 print_target_n_deps(p); 512 } 513 } 514 } 515 516 static void 517 print_target_n_deps(register Name target) 518 { 519 register Cmd_line rule; 520 register Property line; 521 register Dependency dependency; 522 523 if (target->dependency_printed) { 524 return; 525 } 526 target->dependency_printed = true; 527 528 (void) printf("%s\n", target->string_mb); 529 530 if ((line = get_prop(target->prop, line_prop)) == NULL) { 531 return; 532 } 533 for (dependency = line->body.line.dependencies; 534 dependency != NULL; 535 dependency = dependency->next) { 536 if (!dependency->automatic) { 537 print_target_n_deps(dependency->name); 538 } 539 } 540 } 541 542 /***************************************** 543 * 544 * main() support 545 */ 546 547 /* 548 * load_cached_names() 549 * 550 * Load the vector of cached names 551 * 552 * Parameters: 553 * 554 * Global variables used: 555 * Many many pointers to Name blocks. 556 */ 557 void 558 load_cached_names(void) 559 { 560 char *cp; 561 Name dollar; 562 563 /* Load the cached_names struct */ 564 MBSTOWCS(wcs_buffer, ".BUILT_LAST_MAKE_RUN"); 565 built_last_make_run = GETNAME(wcs_buffer, FIND_LENGTH); 566 MBSTOWCS(wcs_buffer, "@"); 567 c_at = GETNAME(wcs_buffer, FIND_LENGTH); 568 MBSTOWCS(wcs_buffer, " *conditionals* "); 569 conditionals = GETNAME(wcs_buffer, FIND_LENGTH); 570 /* 571 * A version of make was released with NSE 1.0 that used 572 * VERSION-1.1 but this version is identical to VERSION-1.0. 573 * The version mismatch code makes a special case for this 574 * situation. If the version number is changed from 1.0 575 * it should go to 1.2. 576 */ 577 MBSTOWCS(wcs_buffer, "VERSION-1.0"); 578 current_make_version = GETNAME(wcs_buffer, FIND_LENGTH); 579 MBSTOWCS(wcs_buffer, ".SVR4"); 580 svr4_name = GETNAME(wcs_buffer, FIND_LENGTH); 581 MBSTOWCS(wcs_buffer, ".POSIX"); 582 posix_name = GETNAME(wcs_buffer, FIND_LENGTH); 583 MBSTOWCS(wcs_buffer, ".DEFAULT"); 584 default_rule_name = GETNAME(wcs_buffer, FIND_LENGTH); 585 MBSTOWCS(wcs_buffer, "$"); 586 dollar = GETNAME(wcs_buffer, FIND_LENGTH); 587 MBSTOWCS(wcs_buffer, ".DONE"); 588 done = GETNAME(wcs_buffer, FIND_LENGTH); 589 MBSTOWCS(wcs_buffer, "."); 590 dot = GETNAME(wcs_buffer, FIND_LENGTH); 591 MBSTOWCS(wcs_buffer, ".KEEP_STATE"); 592 dot_keep_state = GETNAME(wcs_buffer, FIND_LENGTH); 593 MBSTOWCS(wcs_buffer, ".KEEP_STATE_FILE"); 594 dot_keep_state_file = GETNAME(wcs_buffer, FIND_LENGTH); 595 MBSTOWCS(wcs_buffer, ""); 596 empty_name = GETNAME(wcs_buffer, FIND_LENGTH); 597 MBSTOWCS(wcs_buffer, " FORCE"); 598 force = GETNAME(wcs_buffer, FIND_LENGTH); 599 MBSTOWCS(wcs_buffer, "HOST_ARCH"); 600 host_arch = GETNAME(wcs_buffer, FIND_LENGTH); 601 MBSTOWCS(wcs_buffer, "HOST_MACH"); 602 host_mach = GETNAME(wcs_buffer, FIND_LENGTH); 603 MBSTOWCS(wcs_buffer, ".IGNORE"); 604 ignore_name = GETNAME(wcs_buffer, FIND_LENGTH); 605 MBSTOWCS(wcs_buffer, ".INIT"); 606 init = GETNAME(wcs_buffer, FIND_LENGTH); 607 MBSTOWCS(wcs_buffer, ".LOCAL"); 608 localhost_name = GETNAME(wcs_buffer, FIND_LENGTH); 609 MBSTOWCS(wcs_buffer, ".make.state"); 610 make_state = GETNAME(wcs_buffer, FIND_LENGTH); 611 MBSTOWCS(wcs_buffer, "MAKEFLAGS"); 612 makeflags = GETNAME(wcs_buffer, FIND_LENGTH); 613 MBSTOWCS(wcs_buffer, ".MAKE_VERSION"); 614 make_version = GETNAME(wcs_buffer, FIND_LENGTH); 615 MBSTOWCS(wcs_buffer, ".NO_PARALLEL"); 616 no_parallel_name = GETNAME(wcs_buffer, FIND_LENGTH); 617 MBSTOWCS(wcs_buffer, ".NOT_AUTO"); 618 not_auto = GETNAME(wcs_buffer, FIND_LENGTH); 619 MBSTOWCS(wcs_buffer, ".PARALLEL"); 620 parallel_name = GETNAME(wcs_buffer, FIND_LENGTH); 621 MBSTOWCS(wcs_buffer, "PATH"); 622 path_name = GETNAME(wcs_buffer, FIND_LENGTH); 623 MBSTOWCS(wcs_buffer, "+"); 624 plus = GETNAME(wcs_buffer, FIND_LENGTH); 625 MBSTOWCS(wcs_buffer, ".PRECIOUS"); 626 precious = GETNAME(wcs_buffer, FIND_LENGTH); 627 MBSTOWCS(wcs_buffer, "?"); 628 query = GETNAME(wcs_buffer, FIND_LENGTH); 629 MBSTOWCS(wcs_buffer, "^"); 630 hat = GETNAME(wcs_buffer, FIND_LENGTH); 631 MBSTOWCS(wcs_buffer, ".RECURSIVE"); 632 recursive_name = GETNAME(wcs_buffer, FIND_LENGTH); 633 MBSTOWCS(wcs_buffer, ".SCCS_GET"); 634 sccs_get_name = GETNAME(wcs_buffer, FIND_LENGTH); 635 MBSTOWCS(wcs_buffer, ".SCCS_GET_POSIX"); 636 sccs_get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH); 637 MBSTOWCS(wcs_buffer, ".GET"); 638 get_name = GETNAME(wcs_buffer, FIND_LENGTH); 639 MBSTOWCS(wcs_buffer, ".GET_POSIX"); 640 get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH); 641 MBSTOWCS(wcs_buffer, "SHELL"); 642 shell_name = GETNAME(wcs_buffer, FIND_LENGTH); 643 MBSTOWCS(wcs_buffer, ".SILENT"); 644 silent_name = GETNAME(wcs_buffer, FIND_LENGTH); 645 MBSTOWCS(wcs_buffer, ".SUFFIXES"); 646 suffixes_name = GETNAME(wcs_buffer, FIND_LENGTH); 647 MBSTOWCS(wcs_buffer, SUNPRO_DEPENDENCIES); 648 sunpro_dependencies = GETNAME(wcs_buffer, FIND_LENGTH); 649 MBSTOWCS(wcs_buffer, "TARGET_ARCH"); 650 target_arch = GETNAME(wcs_buffer, FIND_LENGTH); 651 MBSTOWCS(wcs_buffer, "TARGET_MACH"); 652 target_mach = GETNAME(wcs_buffer, FIND_LENGTH); 653 MBSTOWCS(wcs_buffer, "VIRTUAL_ROOT"); 654 virtual_root = GETNAME(wcs_buffer, FIND_LENGTH); 655 MBSTOWCS(wcs_buffer, "VPATH"); 656 vpath_name = GETNAME(wcs_buffer, FIND_LENGTH); 657 MBSTOWCS(wcs_buffer, ".WAIT"); 658 wait_name = GETNAME(wcs_buffer, FIND_LENGTH); 659 660 wait_name->state = build_ok; 661 662 /* Mark special targets so that the reader treats them properly */ 663 svr4_name->special_reader = svr4_special; 664 posix_name->special_reader = posix_special; 665 built_last_make_run->special_reader = built_last_make_run_special; 666 default_rule_name->special_reader = default_special; 667 dot_keep_state->special_reader = keep_state_special; 668 dot_keep_state_file->special_reader = keep_state_file_special; 669 ignore_name->special_reader = ignore_special; 670 make_version->special_reader = make_version_special; 671 no_parallel_name->special_reader = no_parallel_special; 672 parallel_name->special_reader = parallel_special; 673 localhost_name->special_reader = localhost_special; 674 precious->special_reader = precious_special; 675 sccs_get_name->special_reader = sccs_get_special; 676 sccs_get_posix_name->special_reader = sccs_get_posix_special; 677 get_name->special_reader = get_special; 678 get_posix_name->special_reader = get_posix_special; 679 silent_name->special_reader = silent_special; 680 suffixes_name->special_reader = suffixes_special; 681 682 /* The value of $$ is $ */ 683 (void) SETVAR(dollar, dollar, false); 684 dollar->dollar = false; 685 686 /* Set the value of $(SHELL) */ 687 if (posix) { 688 MBSTOWCS(wcs_buffer, "/usr/xpg4/bin/sh"); 689 } else { 690 MBSTOWCS(wcs_buffer, "/bin/sh"); 691 } 692 (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false); 693 694 /* 695 * Use " FORCE" to simulate a FRC dependency for :: type 696 * targets with no dependencies. 697 */ 698 (void) append_prop(force, line_prop); 699 force->stat.time = file_max_time; 700 701 /* Make sure VPATH is defined before current dir is read */ 702 if ((cp = getenv(vpath_name->string_mb)) != NULL) { 703 MBSTOWCS(wcs_buffer, cp); 704 (void) SETVAR(vpath_name, 705 GETNAME(wcs_buffer, FIND_LENGTH), 706 false); 707 } 708 709 /* Check if there is NO PATH variable. If not we construct one. */ 710 if (getenv(path_name->string_mb) == NULL) { 711 vroot_path = NULL; 712 add_dir_to_path(".", &vroot_path, -1); 713 add_dir_to_path("/bin", &vroot_path, -1); 714 add_dir_to_path("/usr/bin", &vroot_path, -1); 715 } 716 } 717 718 /* 719 * iterate on list of conditional macros in np, and place them in 720 * a String_rec starting with, and separated by the '$' character. 721 */ 722 void 723 cond_macros_into_string(Name np, String_rec *buffer) 724 { 725 Macro_list macro_list; 726 727 /* 728 * Put the version number at the start of the string 729 */ 730 MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION); 731 append_string(wcs_buffer, buffer, FIND_LENGTH); 732 /* 733 * Add the rest of the conditional macros to the buffer 734 */ 735 if (np->depends_on_conditional){ 736 for (macro_list = np->conditional_macro_list; 737 macro_list != NULL; macro_list = macro_list->next){ 738 append_string(macro_list->macro_name, buffer, 739 FIND_LENGTH); 740 append_char((int) equal_char, buffer); 741 append_string(macro_list->value, buffer, FIND_LENGTH); 742 append_char((int) dollar_char, buffer); 743 } 744 } 745 } 746 747