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