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