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