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