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