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 2006 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      main.cc
  28  *
  29  *      make program main routine plus some helper routines
  30  */
  31  
  32 /*
  33  * Included files
  34  */
  35 #include <bsd/bsd.h>              /* bsd_signal() */
  36 
  37 
  38 #include <locale.h>               /* setlocale() */
  39 #include <libgen.h>
  40 #include <mk/defs.h>
  41 #include <mksh/macro.h>           /* getvar() */
  42 #include <mksh/misc.h>            /* getmem(), setup_char_semantics() */
  43 
  44 #include <pwd.h>          /* getpwnam() */
  45 #include <setjmp.h>
  46 #include <signal.h>
  47 #include <stdlib.h>
  48 #include <sys/errno.h>            /* ENOENT */
  49 #include <sys/stat.h>             /* fstat() */
  50 #include <fcntl.h>                /* open() */
  51 
  52 #       include <sys/systeminfo.h>        /* sysinfo() */
  53 
  54 #include <sys/types.h>            /* stat() */
  55 #include <sys/wait.h>             /* wait() */
  56 #include <unistd.h>               /* execv(), unlink(), access() */
  57 #include <vroot/report.h> /* report_dependency(), get_report_file() */
  58 
  59 // From read2.cc
  60 extern  Name            normalize_name(register wchar_t *name_string, register int length);
  61 
  62 extern void job_adjust_fini();
  63 
  64 
  65 /*
  66  * Defined macros
  67  */
  68 #define LD_SUPPORT_ENV_VAR      "SGS_SUPPORT_32"
  69 #define LD_SUPPORT_ENV_VAR_32   "SGS_SUPPORT_32"
  70 #define LD_SUPPORT_ENV_VAR_64   "SGS_SUPPORT_64"
  71 #define LD_SUPPORT_MAKE_LIB     "libmakestate.so.1"
  72 #ifdef __i386
  73 #define LD_SUPPORT_MAKE_ARCH    "i386"
  74 #elif __sparc
  75 #define LD_SUPPORT_MAKE_ARCH    "sparc"
  76 #else
  77 #error "Unsupported architecture"
  78 #endif
  79 
  80 /*
  81  * typedefs & structs
  82  */
  83 
  84 /*
  85  * Static variables
  86  */
  87 static  char            *argv_zero_string;
  88 static  Boolean         build_failed_ever_seen;
  89 static  Boolean         continue_after_error_ever_seen; /* `-k' */
  90 static  Boolean         dmake_group_specified;          /* `-g' */
  91 static  Boolean         dmake_max_jobs_specified;       /* `-j' */
  92 static  Boolean         dmake_mode_specified;           /* `-m' */
  93 static  Boolean         dmake_add_mode_specified;       /* `-x' */
  94 static  Boolean         dmake_output_mode_specified;    /* `-x DMAKE_OUTPUT_MODE=' */
  95 static  Boolean         dmake_compat_mode_specified;    /* `-x SUN_MAKE_COMPAT_MODE=' */
  96 static  Boolean         dmake_odir_specified;           /* `-o' */
  97 static  Boolean         dmake_rcfile_specified;         /* `-c' */
  98 static  Boolean         env_wins;                       /* `-e' */
  99 static  Boolean         ignore_default_mk;              /* `-r' */
 100 static  Boolean         list_all_targets;               /* `-T' */
 101 static  int             mf_argc;
 102 static  char            **mf_argv;
 103 static  Dependency_rec  not_auto_depen_struct;
 104 static  Dependency      not_auto_depen = &not_auto_depen_struct;
 105 static  Boolean         pmake_cap_r_specified;          /* `-R' */
 106 static  Boolean         pmake_machinesfile_specified;   /* `-M' */
 107 static  Boolean         stop_after_error_ever_seen;     /* `-S' */
 108 static  Boolean         trace_status;                   /* `-p' */
 109 
 110 #ifdef DMAKE_STATISTICS
 111 static  Boolean         getname_stat = false;
 112 #endif
 113 
 114         static  time_t          start_time;
 115         static  int             g_argc;
 116         static  char            **g_argv;
 117 
 118 /*
 119  * File table of contents
 120  */
 121         extern "C" void         cleanup_after_exit(void);
 122 
 123 extern "C" {
 124         extern  void            dmake_exit_callback(void);
 125         extern  void            dmake_message_callback(char *);
 126 }
 127 
 128 extern  Name            normalize_name(register wchar_t *name_string, register int length);
 129 
 130 extern  int             main(int, char * []);
 131 
 132 static  void            append_makeflags_string(Name, String);
 133 static  void            doalarm(int);
 134 static  void            enter_argv_values(int , char **, ASCII_Dyn_Array *);
 135 static  void            make_targets(int, char **, Boolean);
 136 static  int             parse_command_option(char);
 137 static  void            read_command_options(int, char **);
 138 static  void            read_environment(Boolean);
 139 static  void            read_files_and_state(int, char **);
 140 static  Boolean         read_makefile(Name, Boolean, Boolean, Boolean);
 141 static  void            report_recursion(Name);
 142 static  void            set_sgs_support(void);
 143 static  void            setup_for_projectdir(void);
 144 static  void            setup_makeflags_argv(void);
 145 static  void            report_dir_enter_leave(Boolean entering);
 146 
 147 extern void expand_value(Name, register String , Boolean);
 148 
 149 static const char       verstring[] = "illumos make";
 150 
 151 jmp_buf jmpbuffer;
 152 
 153 /*
 154  *      main(argc, argv)
 155  *
 156  *      Parameters:
 157  *              argc                    You know what this is
 158  *              argv                    You know what this is
 159  *
 160  *      Static variables used:
 161  *              list_all_targets        make -T seen
 162  *              trace_status            make -p seen
 163  *
 164  *      Global variables used:
 165  *              debug_level             Should we trace make actions?
 166  *              keep_state              Set if .KEEP_STATE seen
 167  *              makeflags               The Name "MAKEFLAGS", used to get macro
 168  *              remote_command_name     Name of remote invocation cmd ("on")
 169  *              running_list            List of parallel running processes
 170  *              stdout_stderr_same      true if stdout and stderr are the same
 171  *              auto_dependencies       The Name "SUNPRO_DEPENDENCIES"
 172  *              temp_file_directory     Set to the dir where we create tmp file
 173  *              trace_reader            Set to reflect tracing status
 174  *              working_on_targets      Set when building user targets
 175  */
 176 int
 177 main(int argc, char *argv[])
 178 {
 179         /*
 180          * cp is a -> to the value of the MAKEFLAGS env var,
 181          * which has to be regular chars.
 182          */
 183         register char           *cp;
 184         char                    make_state_dir[MAXPATHLEN];
 185         Boolean                 parallel_flag = false;
 186         char                    *prognameptr;
 187         char                    *slash_ptr;
 188         mode_t                  um;
 189         int                     i;
 190         struct itimerval        value;
 191         char                    def_dmakerc_path[MAXPATHLEN];
 192         Name                    dmake_name, dmake_name2;
 193         Name                    dmake_value, dmake_value2;
 194         Property                prop, prop2;
 195         struct stat             statbuf;
 196         int                     statval;
 197 
 198         struct stat             out_stat, err_stat;
 199         hostid = gethostid();
 200         bsd_signals();
 201 
 202         (void) setlocale(LC_ALL, "");
 203 
 204 
 205 #ifdef DMAKE_STATISTICS
 206         if (getenv("DMAKE_STATISTICS")) {
 207                 getname_stat = true;
 208         }
 209 #endif
 210 
 211 #ifndef TEXT_DOMAIN
 212 #define TEXT_DOMAIN     "SYS_TEST"      
 213 #endif
 214         textdomain(TEXT_DOMAIN);
 215 
 216         g_argc = argc;
 217         g_argv = (char **) malloc((g_argc + 1) * sizeof(char *));
 218         for (i = 0; i < argc; i++) {
 219                 g_argv[i] = argv[i];
 220         }
 221         g_argv[i] = NULL;
 222 
 223         /*
 224          * Set argv_zero_string to some form of argv[0] for
 225          * recursive MAKE builds.
 226          */
 227 
 228         if (*argv[0] == (int) slash_char) {
 229                 /* argv[0] starts with a slash */
 230                 argv_zero_string = strdup(argv[0]);
 231         } else if (strchr(argv[0], (int) slash_char) == NULL) {
 232                 /* argv[0] contains no slashes */
 233                 argv_zero_string = strdup(argv[0]);
 234         } else {
 235                 /*
 236                  * argv[0] contains at least one slash,
 237                  * but doesn't start with a slash
 238                  */
 239                 char    *tmp_current_path;
 240                 char    *tmp_string;
 241 
 242                 tmp_current_path = get_current_path();
 243                 tmp_string = getmem(strlen(tmp_current_path) + 1 +
 244                                     strlen(argv[0]) + 1);
 245                 (void) sprintf(tmp_string,
 246                                "%s/%s",
 247                                tmp_current_path,
 248                                argv[0]);
 249                 argv_zero_string = strdup(tmp_string);
 250                 retmem_mb(tmp_string);
 251         }
 252 
 253         /* 
 254          * The following flags are reset if we don't have the 
 255          * (.nse_depinfo or .make.state) files locked and only set 
 256          * AFTER the file has been locked. This ensures that if the user
 257          * interrupts the program while file_lock() is waiting to lock
 258          * the file, the interrupt handler doesn't remove a lock 
 259          * that doesn't belong to us.
 260          */
 261         make_state_lockfile = NULL;
 262         make_state_locked = false;
 263 
 264 
 265         /*
 266          * look for last slash char in the path to look at the binary 
 267          * name. This is to resolve the hard link and invoke make
 268          * in svr4 mode.
 269          */
 270 
 271         /* Sun OS make standart */
 272         svr4 = false;  
 273         posix = false;
 274         if(!strcmp(argv_zero_string, "/usr/xpg4/bin/make")) {
 275                 svr4 = false;
 276                 posix = true;
 277         } else {
 278                 prognameptr = strrchr(argv[0], '/');
 279                 if(prognameptr) {
 280                         prognameptr++;
 281                 } else {
 282                         prognameptr = argv[0];
 283                 }
 284                 if(!strcmp(prognameptr, "svr4.make")) {
 285                         svr4 = true;
 286                         posix = false;
 287                 }
 288         }
 289         if (getenv(USE_SVR4_MAKE) || getenv("USE_SVID")){
 290            svr4 = true;
 291            posix = false;
 292         }
 293 
 294         /*
 295          * Find the dmake_compat_mode: posix, sun, svr4, or gnu_style, .
 296          */
 297         char * dmake_compat_mode_var = getenv("SUN_MAKE_COMPAT_MODE");
 298         if (dmake_compat_mode_var != NULL) {
 299                 if (0 == strcasecmp(dmake_compat_mode_var, "GNU")) {
 300                         gnu_style = true;
 301                 }
 302                 //svr4 = false;
 303                 //posix = false;
 304         }
 305 
 306         /*
 307          * Temporary directory set up.
 308          */
 309         char * tmpdir_var = getenv("TMPDIR");
 310         if (tmpdir_var != NULL && *tmpdir_var == '/' && strlen(tmpdir_var) < MAXPATHLEN) {
 311                 strcpy(mbs_buffer, tmpdir_var);
 312                 for (tmpdir_var = mbs_buffer+strlen(mbs_buffer);
 313                         *(--tmpdir_var) == '/' && tmpdir_var > mbs_buffer;
 314                         *tmpdir_var = '\0');
 315                 if (strlen(mbs_buffer) + 32 < MAXPATHLEN) { /* 32 = strlen("/dmake.stdout.%d.%d.XXXXXX") */
 316                         sprintf(mbs_buffer2, "%s/dmake.tst.%d.XXXXXX",
 317                                 mbs_buffer, getpid());
 318                         int fd = mkstemp(mbs_buffer2);
 319                         if (fd >= 0) {
 320                                 close(fd);
 321                                 unlink(mbs_buffer2);
 322                                 tmpdir = strdup(mbs_buffer);
 323                         }
 324                 }
 325         }
 326 
 327         /* find out if stdout and stderr point to the same place */
 328         if (fstat(1, &out_stat) < 0) {
 329                 fatal(gettext("fstat of standard out failed: %s"), errmsg(errno));
 330         }
 331         if (fstat(2, &err_stat) < 0) {
 332                 fatal(gettext("fstat of standard error failed: %s"), errmsg(errno));
 333         }
 334         if ((out_stat.st_dev == err_stat.st_dev) &&
 335             (out_stat.st_ino == err_stat.st_ino)) {
 336                 stdout_stderr_same = true;
 337         } else {
 338                 stdout_stderr_same = false;
 339         }
 340         /* Make the vroot package scan the path using shell semantics */
 341         set_path_style(0);
 342 
 343         setup_char_semantics();
 344 
 345         setup_for_projectdir();
 346 
 347         /*
 348          * If running with .KEEP_STATE, curdir will be set with
 349          * the connected directory.
 350          */
 351         (void) atexit(cleanup_after_exit);
 352 
 353         load_cached_names();
 354 
 355 /*
 356  *      Set command line flags
 357  */
 358         setup_makeflags_argv();
 359         read_command_options(mf_argc, mf_argv);
 360         read_command_options(argc, argv);
 361         if (debug_level > 0) {
 362                 cp = getenv(makeflags->string_mb);
 363                 (void) printf(gettext("MAKEFLAGS value: %s\n"), cp == NULL ? "" : cp);
 364         }
 365 
 366         setup_interrupt(handle_interrupt);
 367 
 368         read_files_and_state(argc, argv);
 369 
 370         /*
 371          * Find the dmake_output_mode: TXT1, TXT2 or HTML1.
 372          */
 373         MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
 374         dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH);
 375         prop2 = get_prop(dmake_name2->prop, macro_prop);
 376         if (prop2 == NULL) {
 377                 /* DMAKE_OUTPUT_MODE not defined, default to TXT1 mode */
 378                 output_mode = txt1_mode;
 379         } else {
 380                 dmake_value2 = prop2->body.macro.value;
 381                 if ((dmake_value2 == NULL) ||
 382                     (IS_EQUAL(dmake_value2->string_mb, "TXT1"))) {
 383                         output_mode = txt1_mode;
 384                 } else if (IS_EQUAL(dmake_value2->string_mb, "TXT2")) {
 385                         output_mode = txt2_mode;
 386                 } else if (IS_EQUAL(dmake_value2->string_mb, "HTML1")) {
 387                         output_mode = html1_mode;
 388                 } else {
 389                         warning(gettext("Unsupported value `%s' for DMAKE_OUTPUT_MODE after -x flag (ignored)"),
 390                               dmake_value2->string_mb);
 391                 }
 392         }
 393         /*
 394          * Find the dmake_mode: parallel, or serial.
 395          */
 396     if ((!pmake_cap_r_specified) &&
 397         (!pmake_machinesfile_specified)) {
 398         char *s, *b;
 399 
 400         if ((s = strdup(argv[0])) == NULL)
 401                 fatal(gettext("Out of memory"));
 402 
 403         b = basename(s);
 404 
 405         MBSTOWCS(wcs_buffer, "DMAKE_MODE");
 406         dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH);
 407         prop2 = get_prop(dmake_name2->prop, macro_prop);
 408         // If we're invoked as 'make' run serially, regardless of DMAKE_MODE
 409         // If we're invoked as 'make' but passed -j, run parallel
 410         // If we're invoked as 'dmake', without DMAKE_MODE, default parallel
 411         // If we're invoked as 'dmake' and DMAKE_MODE is set, honour it.
 412         if ((strcmp(b, "make") == 0) &&
 413             !dmake_max_jobs_specified) {
 414                 dmake_mode_type = serial_mode;
 415                 no_parallel = true;
 416         } else if (prop2 == NULL) {
 417                 /* DMAKE_MODE not defined, default based on our name */
 418                 if (strcmp(b, "dmake") == 0) {
 419                         dmake_mode_type = parallel_mode;
 420                         no_parallel = false;
 421                 }
 422         } else {
 423                 dmake_value2 = prop2->body.macro.value;
 424                 if (IS_EQUAL(dmake_value2->string_mb, "parallel")) {
 425                         dmake_mode_type = parallel_mode;
 426                         no_parallel = false;
 427                 } else if (IS_EQUAL(dmake_value2->string_mb, "serial")) {
 428                         dmake_mode_type = serial_mode;
 429                         no_parallel = true;
 430                 } else {
 431                         fatal(gettext("Unknown dmake mode argument `%s' after -m flag"), dmake_value2->string_mb);
 432                 }
 433         }
 434         free(s);
 435     }
 436 
 437         parallel_flag = true;
 438         putenv(strdup("DMAKE_CHILD=TRUE"));
 439 
 440 //
 441 // If dmake is running with -t option, set dmake_mode_type to serial.
 442 // This is done because doname() calls touch_command() that runs serially.
 443 // If we do not do that, maketool will have problems. 
 444 //
 445         if(touch) {
 446                 dmake_mode_type = serial_mode;
 447                 no_parallel = true;
 448         }
 449 
 450         /*
 451          * Check whether stdout and stderr are physically same.
 452          * This is in order to decide whether we need to redirect
 453          * stderr separately from stdout.
 454          * This check is performed only if __DMAKE_SEPARATE_STDERR
 455          * is not set. This variable may be used in order to preserve
 456          * the 'old' behaviour.
 457          */
 458         out_err_same = true;
 459         char * dmake_sep_var = getenv("__DMAKE_SEPARATE_STDERR");
 460         if (dmake_sep_var == NULL || (0 != strcasecmp(dmake_sep_var, "NO"))) {
 461                 struct stat stdout_stat;
 462                 struct stat stderr_stat;
 463                 if( (fstat(1, &stdout_stat) == 0)
 464                  && (fstat(2, &stderr_stat) == 0) )
 465                 {
 466                         if( (stdout_stat.st_dev != stderr_stat.st_dev)
 467                          || (stdout_stat.st_ino != stderr_stat.st_ino) )
 468                         {
 469                                 out_err_same = false;
 470                         }
 471                 }
 472         }
 473 
 474                 
 475 /*
 476  *      Enable interrupt handler for alarms
 477  */
 478         (void) bsd_signal(SIGALRM, (SIG_PF)doalarm);
 479 
 480 /*
 481  *      Check if make should report
 482  */
 483         if (getenv(sunpro_dependencies->string_mb) != NULL) {
 484                 FILE    *report_file;
 485 
 486                 report_dependency("");
 487                 report_file = get_report_file();
 488                 if ((report_file != NULL) && (report_file != (FILE*)-1)) {
 489                         (void) fprintf(report_file, "\n");
 490                 }
 491         }
 492 
 493 /*
 494  *      Make sure SUNPRO_DEPENDENCIES is exported (or not) properly.
 495  */
 496         if (keep_state) {
 497                 maybe_append_prop(sunpro_dependencies, macro_prop)->
 498                   body.macro.exported = true;
 499         } else {
 500                 maybe_append_prop(sunpro_dependencies, macro_prop)->
 501                   body.macro.exported = false;
 502         }
 503 
 504         working_on_targets = true;
 505         if (trace_status) {
 506                 dump_make_state();
 507                 fclose(stdout);
 508                 fclose(stderr);
 509                 exit_status = 0;
 510                 exit(0);
 511         }
 512         if (list_all_targets) {
 513                 dump_target_list();
 514                 fclose(stdout);
 515                 fclose(stderr);
 516                 exit_status = 0;
 517                 exit(0);
 518         }
 519         trace_reader = false;
 520 
 521         /*
 522          * Set temp_file_directory to the directory the .make.state
 523          * file is written to.
 524          */
 525         if ((slash_ptr = strrchr(make_state->string_mb, (int) slash_char)) == NULL) {
 526                 temp_file_directory = strdup(get_current_path());
 527         } else {
 528                 *slash_ptr = (int) nul_char;
 529                 (void) strcpy(make_state_dir, make_state->string_mb);
 530                 *slash_ptr = (int) slash_char;
 531                    /* when there is only one slash and it's the first
 532                    ** character, make_state_dir should point to '/'.
 533                    */
 534                 if(make_state_dir[0] == '\0') {
 535                    make_state_dir[0] = '/';
 536                    make_state_dir[1] = '\0';
 537                 }
 538                 if (make_state_dir[0] == (int) slash_char) {
 539                         temp_file_directory = strdup(make_state_dir);
 540                 } else {
 541                         char    tmp_current_path2[MAXPATHLEN];
 542  
 543                         (void) sprintf(tmp_current_path2,
 544                                        "%s/%s",
 545                                        get_current_path(),
 546                                        make_state_dir);
 547                         temp_file_directory = strdup(tmp_current_path2);
 548                 }
 549         }
 550 
 551 
 552         report_dir_enter_leave(true);
 553 
 554         make_targets(argc, argv, parallel_flag);
 555 
 556         report_dir_enter_leave(false);
 557 
 558         if (build_failed_ever_seen) {
 559                 if (posix) {
 560                         exit_status = 1;
 561                 }
 562                 exit(1);
 563         }
 564         exit_status = 0;
 565         exit(0);
 566         /* NOTREACHED */
 567 }
 568 
 569 /*
 570  *      cleanup_after_exit()
 571  *
 572  *      Called from exit(), performs cleanup actions.
 573  *
 574  *      Parameters:
 575  *              status          The argument exit() was called with
 576  *              arg             Address of an argument vector to
 577  *                              cleanup_after_exit()
 578  *
 579  *      Global variables used:
 580  *              command_changed Set if we think .make.state should be rewritten
 581  *              current_line    Is set we set commands_changed
 582  *              do_not_exec_rule
 583  *                              True if -n flag on
 584  *              done            The Name ".DONE", rule we run
 585  *              keep_state      Set if .KEEP_STATE seen
 586  *              parallel        True if building in parallel
 587  *              quest           If -q is on we do not run .DONE
 588  *              report_dependencies
 589  *                              True if -P flag on
 590  *              running_list    List of parallel running processes
 591  *              temp_file_name  The temp file is removed, if any
 592  */
 593 extern "C" void
 594 cleanup_after_exit(void)
 595 {
 596         Running         rp;
 597 
 598 extern long     getname_bytes_count;
 599 extern long     getname_names_count;
 600 extern long     getname_struct_count;
 601 extern long     freename_bytes_count;
 602 extern long     freename_names_count;
 603 extern long     freename_struct_count;
 604 extern long     other_alloc;
 605 
 606 extern long     env_alloc_num;
 607 extern long     env_alloc_bytes;
 608 
 609 
 610 #ifdef DMAKE_STATISTICS
 611 if(getname_stat) {
 612         printf(">>> Getname statistics:\n");
 613         printf("  Allocated:\n");
 614         printf("        Names: %ld\n", getname_names_count);
 615         printf("      Strings: %ld Kb (%ld bytes)\n", getname_bytes_count/1000, getname_bytes_count);
 616         printf("      Structs: %ld Kb (%ld bytes)\n", getname_struct_count/1000, getname_struct_count);
 617         printf("  Total bytes: %ld Kb (%ld bytes)\n", getname_struct_count/1000 + getname_bytes_count/1000, getname_struct_count + getname_bytes_count);
 618 
 619         printf("\n  Unallocated: %ld\n", freename_names_count);
 620         printf("        Names: %ld\n", freename_names_count);
 621         printf("      Strings: %ld Kb (%ld bytes)\n", freename_bytes_count/1000, freename_bytes_count);
 622         printf("      Structs: %ld Kb (%ld bytes)\n", freename_struct_count/1000, freename_struct_count);
 623         printf("  Total bytes: %ld Kb (%ld bytes)\n", freename_struct_count/1000 + freename_bytes_count/1000, freename_struct_count + freename_bytes_count);
 624 
 625         printf("\n  Total used: %ld Kb (%ld bytes)\n", (getname_struct_count/1000 + getname_bytes_count/1000) - (freename_struct_count/1000 + freename_bytes_count/1000), (getname_struct_count + getname_bytes_count) - (freename_struct_count + freename_bytes_count));
 626 
 627         printf("\n>>> Other:\n");
 628         printf(
 629                 "       Env (%ld): %ld Kb (%ld bytes)\n",
 630                 env_alloc_num,
 631                 env_alloc_bytes/1000,
 632                 env_alloc_bytes
 633         );
 634 
 635 }
 636 #endif
 637 
 638         parallel = false;
 639         /* If we used the SVR4_MAKE, don't build .DONE or .FAILED */
 640         if (!getenv(USE_SVR4_MAKE)){
 641             /* Build the target .DONE or .FAILED if we caught an error */
 642             if (!quest && !list_all_targets) {
 643                 Name            failed_name;
 644 
 645                 MBSTOWCS(wcs_buffer, ".FAILED");
 646                 failed_name = GETNAME(wcs_buffer, FIND_LENGTH);
 647                 if ((exit_status != 0) && (failed_name->prop != NULL)) {
 648                         /*
 649                          * [tolik] switch DMake to serial mode
 650                          */
 651                         dmake_mode_type = serial_mode;
 652                         no_parallel = true;
 653                         (void) doname(failed_name, false, true);
 654                 } else {
 655                     if (!trace_status) {
 656                         /*
 657                          * Switch DMake to serial mode
 658                          */
 659                         dmake_mode_type = serial_mode;
 660                         no_parallel = true;
 661                         (void) doname(done, false, true);
 662                     }
 663                 }
 664             }
 665         }
 666         /*
 667          * Remove the temp file utilities report dependencies thru if it
 668          * is still around
 669          */
 670         if (temp_file_name != NULL) {
 671                 (void) unlink(temp_file_name->string_mb);
 672         }
 673         /*
 674          * Do not save the current command in .make.state if make
 675          * was interrupted.
 676          */
 677         if (current_line != NULL) {
 678                 command_changed = true;
 679                 current_line->body.line.command_used = NULL;
 680         }
 681         /*
 682          * For each parallel build process running, remove the temp files
 683          * and zap the command line so it won't be put in .make.state
 684          */
 685         for (rp = running_list; rp != NULL; rp = rp->next) {
 686                 if (rp->temp_file != NULL) {
 687                         (void) unlink(rp->temp_file->string_mb);
 688                 }
 689                 if (rp->stdout_file != NULL) {
 690                         (void) unlink(rp->stdout_file);
 691                         retmem_mb(rp->stdout_file);
 692                         rp->stdout_file = NULL;
 693                 }
 694                 if (rp->stderr_file != NULL) {
 695                         (void) unlink(rp->stderr_file);
 696                         retmem_mb(rp->stderr_file);
 697                         rp->stderr_file = NULL;
 698                 }
 699                 command_changed = true;
 700 /*
 701                 line = get_prop(rp->target->prop, line_prop);
 702                 if (line != NULL) {
 703                         line->body.line.command_used = NULL;
 704                 }
 705  */
 706         }
 707         /* Remove the statefile lock file if the file has been locked */
 708         if ((make_state_lockfile != NULL) && (make_state_locked)) {
 709                 (void) unlink(make_state_lockfile);
 710                 make_state_lockfile = NULL;
 711                 make_state_locked = false;
 712         }
 713         /* Write .make.state */
 714         write_state_file(1, (Boolean) 1);
 715 
 716         job_adjust_fini();
 717 }
 718 
 719 /*
 720  *      handle_interrupt()
 721  *
 722  *      This is where C-C traps are caught.
 723  *
 724  *      Parameters:
 725  *
 726  *      Global variables used (except DMake 1.0):
 727  *              current_target          Sometimes the current target is removed
 728  *              do_not_exec_rule        But not if -n is on
 729  *              quest                   or -q
 730  *              running_list            List of parallel running processes
 731  *              touch                   Current target is not removed if -t on
 732  */
 733 void
 734 handle_interrupt(int)
 735 {
 736         Property                member;
 737         Running                 rp;
 738 
 739         (void) fflush(stdout);
 740         if (childPid > 0) {
 741                 kill(childPid, SIGTERM);
 742                 childPid = -1;
 743         }
 744         for (rp = running_list; rp != NULL; rp = rp->next) {
 745                 if (rp->state != build_running) {
 746                         continue;
 747                 }
 748                 if (rp->pid > 0) {
 749                         kill(rp->pid, SIGTERM);
 750                         rp->pid = -1;
 751                 }
 752         }
 753         if (getpid() == getpgrp()) {
 754                 bsd_signal(SIGTERM, SIG_IGN);
 755                 kill (-getpid(), SIGTERM);
 756         }
 757         /* Clean up all parallel children already finished */
 758         finish_children(false);
 759 
 760         /* Make sure the processes running under us terminate first */
 761 
 762         while (wait((int *) NULL) != -1);
 763         /* Delete the current targets unless they are precious */
 764         if ((current_target != NULL) &&
 765             current_target->is_member &&
 766             ((member = get_prop(current_target->prop, member_prop)) != NULL)) {
 767                 current_target = member->body.member.library;
 768         }
 769         if (!do_not_exec_rule &&
 770             !touch &&
 771             !quest &&
 772             (current_target != NULL) &&
 773             !(current_target->stat.is_precious || all_precious)) {
 774 
 775 /* BID_1030811 */
 776 /* azv 16 Oct 95 */
 777                 current_target->stat.time = file_no_time; 
 778 
 779                 if (exists(current_target) != file_doesnt_exist) {
 780                         (void) fprintf(stderr,
 781                                        "\n*** %s ",
 782                                        current_target->string_mb);
 783                         if (current_target->stat.is_dir) {
 784                                 (void) fprintf(stderr,
 785                                                gettext("not removed.\n"),
 786                                                current_target->string_mb);
 787                         } else if (unlink(current_target->string_mb) == 0) {
 788                                 (void) fprintf(stderr,
 789                                                gettext("removed.\n"),
 790                                                current_target->string_mb);
 791                         } else {
 792                                 (void) fprintf(stderr,
 793                                                gettext("could not be removed: %s.\n"),
 794                                                current_target->string_mb,
 795                                                errmsg(errno));
 796                         }
 797                 }
 798         }
 799         for (rp = running_list; rp != NULL; rp = rp->next) {
 800                 if (rp->state != build_running) {
 801                         continue;
 802                 }
 803                 if (rp->target->is_member &&
 804                     ((member = get_prop(rp->target->prop, member_prop)) !=
 805                      NULL)) {
 806                         rp->target = member->body.member.library;
 807                 }
 808                 if (!do_not_exec_rule &&
 809                     !touch &&
 810                     !quest &&
 811                     !(rp->target->stat.is_precious || all_precious)) {
 812 
 813                         rp->target->stat.time = file_no_time; 
 814                         if (exists(rp->target) != file_doesnt_exist) {
 815                                 (void) fprintf(stderr,
 816                                                "\n*** %s ",
 817                                                rp->target->string_mb);
 818                                 if (rp->target->stat.is_dir) {
 819                                         (void) fprintf(stderr,
 820                                                        gettext("not removed.\n"),
 821                                                        rp->target->string_mb);
 822                                 } else if (unlink(rp->target->string_mb) == 0) {
 823                                         (void) fprintf(stderr,
 824                                                        gettext("removed.\n"),
 825                                                        rp->target->string_mb);
 826                                 } else {
 827                                         (void) fprintf(stderr,
 828                                                        gettext("could not be removed: %s.\n"),
 829                                                        rp->target->string_mb,
 830                                                        errmsg(errno));
 831                                 }
 832                         }
 833                 }
 834         }
 835 
 836 
 837         /* Have we locked .make.state or .nse_depinfo? */
 838         if ((make_state_lockfile != NULL) && (make_state_locked)) {
 839                 unlink(make_state_lockfile);
 840                 make_state_lockfile = NULL;
 841                 make_state_locked = false;
 842         }
 843         /*
 844          * Re-read .make.state file (it might be changed by recursive make)
 845          */
 846         check_state(NULL);
 847 
 848         report_dir_enter_leave(false);
 849 
 850         exit_status = 2;
 851         exit(2);
 852 }
 853 
 854 /*
 855  *      doalarm(sig, ...)
 856  *
 857  *      Handle the alarm interrupt but do nothing.  Side effect is to
 858  *      cause return from wait3.
 859  *
 860  *      Parameters:
 861  *              sig
 862  *
 863  *      Global variables used:
 864  */
 865 /*ARGSUSED*/
 866 static void
 867 doalarm(int)
 868 {
 869         return;
 870 }
 871 
 872 
 873 /*
 874  *      read_command_options(argc, argv)
 875  *
 876  *      Scan the cmd line options and process the ones that start with "-"
 877  *
 878  *      Return value:
 879  *                              -M argument, if any
 880  *
 881  *      Parameters:
 882  *              argc            You know what this is
 883  *              argv            You know what this is
 884  *
 885  *      Global variables used:
 886  */
 887 static void
 888 read_command_options(register int argc, register char **argv)
 889 {
 890         register int            ch;
 891         int                     current_optind = 1;
 892         int                     last_optind_with_double_hyphen = 0;
 893         int                     last_optind;
 894         int                     last_current_optind;
 895         register int            i;
 896         register int            j;
 897         register int            k;
 898         register int            makefile_next = 0; /*
 899                                                     * flag to note options:
 900                                                     * -c, f, g, j, m, o
 901                                                     */
 902         const char              *tptr;
 903         const char              *CMD_OPTS;
 904 
 905         extern char             *optarg;
 906         extern int              optind, opterr, optopt;
 907 
 908 #define SUNPRO_CMD_OPTS "-~Bbc:Ddef:g:ij:K:kM:m:NnO:o:PpqRrSsTtuVvwx:"
 909 
 910 #       define SVR4_CMD_OPTS   "-c:ef:g:ij:km:nO:o:pqrsTtVv"
 911 
 912         /*
 913          * Added V in SVR4_CMD_OPTS also, which is going to be a hidden
 914          * option, just to make sure that the getopt doesn't fail when some
 915          * users leave their USE_SVR4_MAKE set and try to use the makefiles
 916          * that are designed to issue commands like $(MAKE) -V. Anyway it
 917          * sets the same flag but ensures that getopt doesn't fail.
 918          */
 919 
 920         opterr = 0;
 921         optind = 1;
 922         while (1) {
 923                 last_optind=optind;                     /* Save optind and current_optind values */
 924                 last_current_optind=current_optind;     /* in case we have to repeat this round. */
 925                 if (svr4) {
 926                         CMD_OPTS=SVR4_CMD_OPTS;
 927                         ch = getopt(argc, argv, SVR4_CMD_OPTS);
 928                 } else {
 929                         CMD_OPTS=SUNPRO_CMD_OPTS;
 930                         ch = getopt(argc, argv, SUNPRO_CMD_OPTS);
 931                 }
 932                 if (ch == EOF) {
 933                         if(optind < argc) {
 934                                 /*
 935                                  * Fixing bug 4102537:
 936                                  *    Strange behaviour of command make using -- option.
 937                                  * Not all argv have been processed
 938                                  * Skip non-flag argv and continue processing.
 939                                  */
 940                                 optind++;
 941                                 current_optind++;
 942                                 continue;
 943                         } else {
 944                                 break;
 945                         }
 946 
 947                 }
 948                 if (ch == '?') {
 949                         if (optopt == '-') {
 950                                 /* Bug 5060758: getopt() changed behavior (s10_60),
 951                                  * and now we have to deal with cases when options
 952                                  * with double hyphen appear here, from -$(MAKEFLAGS)
 953                                  */
 954                                 i = current_optind;
 955                                 if (argv[i][0] == '-') {
 956                                   if (argv[i][1] == '-') {
 957                                     if (argv[i][2] != '\0') {
 958                                       /* Check if this option is allowed */
 959                                       tptr = strchr(CMD_OPTS, argv[i][2]);
 960                                       if (tptr) {
 961                                         if (last_optind_with_double_hyphen != current_optind) {
 962                                           /* This is first time we are trying to fix "--"
 963                                            * problem with this option. If we come here second 
 964                                            * time, we will go to fatal error.
 965                                            */
 966                                           last_optind_with_double_hyphen = current_optind;
 967                                           
 968                                           /* Eliminate first hyphen character */
 969                                           for (j=0; argv[i][j] != '\0'; j++) {
 970                                             argv[i][j] = argv[i][j+1];
 971                                           }
 972                                           
 973                                           /* Repeat the processing of this argument */
 974                                           optind=last_optind;
 975                                           current_optind=last_current_optind;
 976                                           continue;
 977                                         }
 978                                       }
 979                                     }
 980                                   }
 981                                 }
 982                         }
 983                 }
 984 
 985                 if (ch == '?') {
 986                         if (svr4) {
 987                                 fprintf(stderr,
 988                                         gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ]\n"));
 989                                 fprintf(stderr,
 990                                         gettext("              [ -j dmake_max_jobs ][ -m dmake_mode ][ -o dmake_odir ]...\n"));
 991                                 fprintf(stderr,
 992                                         gettext("              [ -e ][ -i ][ -k ][ -n ][ -p ][ -q ][ -r ][ -s ][ -t ][ -v ]\n"));
 993                                 tptr = strchr(SVR4_CMD_OPTS, optopt);
 994                         } else {
 995                                 fprintf(stderr,
 996                                         gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ]\n"));
 997                                 fprintf(stderr,
 998                                         gettext("              [ -j dmake_max_jobs ][ -K statefile ][ -m dmake_mode ][ -x MODE_NAME=VALUE ][ -o dmake_odir ]...\n"));
 999                                 fprintf(stderr,
1000                                         gettext("              [ -d ][ -dd ][ -D ][ -DD ][ -e ][ -i ][ -k ][ -n ][ -p ][ -P ][ -u ][ -w ]\n"));
1001                                 fprintf(stderr,
1002                                         gettext("              [ -q ][ -r ][ -s ][ -S ][ -t ][ -v ][ -V ][ target... ][ macro=value... ][ \"macro +=value\"... ]\n"));
1003                                 tptr = strchr(SUNPRO_CMD_OPTS, optopt);
1004                         }
1005                         if (!tptr) {
1006                                 fatal(gettext("Unknown option `-%c'"), optopt);
1007                         } else {
1008                                 fatal(gettext("Missing argument after `-%c'"), optopt);
1009                         }
1010                 }
1011 
1012 
1013 
1014                 makefile_next |= parse_command_option(ch);
1015                 /*
1016                  * If we're done processing all of the options of
1017                  * ONE argument string...
1018                  */
1019                 if (current_optind < optind) {
1020                         i = current_optind;
1021                         k = 0;
1022                         /* If there's an argument for an option... */
1023                         if ((optind - current_optind) > 1) {
1024                                 k = i + 1;
1025                         }
1026                         switch (makefile_next) {
1027                         case 0:
1028                                 argv[i] = NULL;
1029                                 /* This shouldn't happen */
1030                                 if (k) {
1031                                         argv[k] = NULL;
1032                                 }
1033                                 break;
1034                         case 1: /* -f seen */
1035                                 argv[i] = (char *)"-f";
1036                                 break;
1037                         case 2: /* -c seen */
1038                                 argv[i] = (char *)"-c";
1039                                 break;
1040                         case 4: /* -g seen */
1041                                 argv[i] = (char *)"-g";
1042                                 break;
1043                         case 8: /* -j seen */
1044                                 argv[i] = (char *)"-j";
1045                                 break;
1046                         case 16: /* -M seen */
1047                                 argv[i] = (char *)"-M";
1048                                 break;
1049                         case 32: /* -m seen */
1050                                 argv[i] = (char *)"-m";
1051                                 break;
1052                         case 128: /* -O seen */
1053                                 argv[i] = (char *)"-O";
1054                                 break;
1055                         case 256: /* -K seen */
1056                                 argv[i] = (char *)"-K";
1057                                 break;
1058                         case 512:       /* -o seen */
1059                                 argv[i] = (char *)"-o";
1060                                 break;
1061                         case 1024: /* -x seen */
1062                                 argv[i] = (char *)"-x";
1063                                 break;
1064                         default: /* > 1 of -c, f, g, j, K, M, m, O, o, x seen */
1065                                 fatal(gettext("Illegal command line. More than one option requiring\nan argument given in the same argument group"));
1066                         }
1067 
1068                         makefile_next = 0;
1069                         current_optind = optind;
1070                 }
1071         }
1072 }
1073 
1074 static void
1075 quote_str(char *str, char *qstr)
1076 {
1077         char            *to;
1078         char            *from;
1079 
1080         to = qstr;
1081         for (from = str; *from; from++) {
1082                 switch (*from) {
1083                 case ';':       /* End of command */
1084                 case '(':       /* Start group */
1085                 case ')':       /* End group */
1086                 case '{':       /* Start group */
1087                 case '}':       /* End group */
1088                 case '[':       /* Reg expr - any of a set of chars */
1089                 case ']':       /* End of set of chars */
1090                 case '|':       /* Pipe or logical-or */
1091                 case '^':       /* Old-fashioned pipe */
1092                 case '&':   /* Background or logical-and */
1093                 case '<':    /* Redirect stdin */
1094                 case '>':    /* Redirect stdout */
1095                 case '*':       /* Reg expr - any sequence of chars */
1096                 case '?':       /* Reg expr - any single char */
1097                 case '$':       /* Variable substitution */
1098                 case '\'':      /* Singe quote - turn off all magic */
1099                 case '"':       /* Double quote - span whitespace */
1100                 case '`':       /* Backquote - run a command */
1101                 case '#':       /* Comment */
1102                 case ' ':       /* Space (for MACRO=value1 value2  */
1103                 case '\\':      /* Escape char - turn off magic of next char */
1104                         *to++ = '\\';
1105                         break;
1106 
1107                 default:
1108                         break;
1109                 }
1110                 *to++ = *from;
1111         }
1112         *to = '\0';
1113 }
1114 
1115 static void
1116 unquote_str(char *str, char *qstr)
1117 {
1118         char            *to;
1119         char            *from;
1120 
1121         to = qstr;
1122         for (from = str; *from; from++) {
1123                 if (*from == '\\') {
1124                         from++;
1125                 }
1126                 *to++ = *from;
1127         }
1128         *to = '\0';
1129 }
1130 
1131 /*
1132  * Convert the MAKEFLAGS string value into a vector of char *, similar
1133  * to argv.
1134  */
1135 static void
1136 setup_makeflags_argv()
1137 {
1138         char            *cp;
1139         char            *cp1;
1140         char            *cp2;
1141         char            *cp3;
1142         char            *cp_orig;
1143         Boolean         add_hyphen;
1144         int             i;
1145         char            tmp_char;
1146 
1147         mf_argc = 1;
1148         cp = getenv(makeflags->string_mb);
1149         cp_orig = cp;
1150 
1151         if (cp) {
1152                 /*
1153                  * If new MAKEFLAGS format, no need to add hyphen.
1154                  * If old MAKEFLAGS format, add hyphen before flags.
1155                  */
1156 
1157                 if ((strchr(cp, (int) hyphen_char) != NULL) ||
1158                     (strchr(cp, (int) equal_char) != NULL)) {
1159 
1160                         /* New MAKEFLAGS format */
1161 
1162                         add_hyphen = false;
1163 
1164                         /* Check if MAKEFLAGS value begins with multiple
1165                          * hyphen characters, and remove all duplicates.
1166                          * Usually it happens when the next command is
1167                          * used: $(MAKE) -$(MAKEFLAGS)
1168                          * 
1169                          * This was a workaround for BugID 5060758, but
1170                          * appears to have survived as a fix in make.
1171                          */
1172                         while (*cp) {
1173                                 if (*cp != (int) hyphen_char) {
1174                                         break;
1175                                 }
1176                                 cp++;
1177                                 if (*cp == (int) hyphen_char) {
1178                                         /* There are two hyphens. Skip one */
1179                                         cp_orig = cp;
1180                                         cp++;
1181                                 }
1182                                 if (!(*cp)) {
1183                                         /* There are hyphens only. Skip all */
1184                                         cp_orig = cp;
1185                                         break;
1186                                 }
1187                         }
1188                 } else {
1189 
1190                         /* Old MAKEFLAGS format */
1191 
1192                         add_hyphen = true;
1193                 }
1194         }
1195 
1196         /* Find the number of arguments in MAKEFLAGS */
1197         while (cp && *cp) {
1198                 /* Skip white spaces */
1199                 while (cp && *cp && isspace(*cp)) {
1200                         cp++;
1201                 }
1202                 if (cp && *cp) {
1203                         /* Increment arg count */
1204                         mf_argc++;
1205                         /* Go to next white space */
1206                         while (cp && *cp && !isspace(*cp)) {
1207                                 if(*cp == (int) backslash_char) {
1208                                         cp++;
1209                                 }
1210                                 cp++;
1211                         }
1212                 }
1213         }
1214         /* Allocate memory for the new MAKEFLAGS argv */
1215         mf_argv = (char **) malloc((mf_argc + 1) * sizeof(char *));
1216         mf_argv[0] = (char *)"MAKEFLAGS";
1217         /*
1218          * Convert the MAKEFLAGS string value into a vector of char *,
1219          * similar to argv.
1220          */
1221         cp = cp_orig;
1222         for (i = 1; i < mf_argc; i++) {
1223                 /* Skip white spaces */
1224                 while (cp && *cp && isspace(*cp)) {
1225                         cp++;
1226                 }
1227                 if (cp && *cp) {
1228                         cp_orig = cp;
1229                         /* Go to next white space */
1230                         while (cp && *cp && !isspace(*cp)) {
1231                                 if(*cp == (int) backslash_char) {
1232                                         cp++;
1233                                 }
1234                                 cp++;
1235                         }
1236                         tmp_char = *cp;
1237                         *cp = (int) nul_char;
1238                         if (add_hyphen) {
1239                                 mf_argv[i] = getmem(2 + strlen(cp_orig));
1240                                 mf_argv[i][0] = '\0';
1241                                 (void) strcat(mf_argv[i], "-");
1242                                 // (void) strcat(mf_argv[i], cp_orig);
1243                                 unquote_str(cp_orig, mf_argv[i]+1);
1244                         } else {
1245                                 mf_argv[i] = getmem(2 + strlen(cp_orig));
1246                                 //mf_argv[i] = strdup(cp_orig);
1247                                 unquote_str(cp_orig, mf_argv[i]);
1248                         }
1249                         *cp = tmp_char;
1250                 }
1251         }
1252         mf_argv[i] = NULL;
1253 }
1254 
1255 /*
1256  *      parse_command_option(ch)
1257  *
1258  *      Parse make command line options.
1259  *
1260  *      Return value:
1261  *                              Indicates if any -f -c or -M were seen
1262  *
1263  *      Parameters:
1264  *              ch              The character to parse
1265  *
1266  *      Static variables used:
1267  *              dmake_group_specified   Set for make -g
1268  *              dmake_max_jobs_specified        Set for make -j
1269  *              dmake_mode_specified    Set for make -m
1270  *              dmake_add_mode_specified        Set for make -x
1271  *              dmake_compat_mode_specified     Set for make -x SUN_MAKE_COMPAT_MODE=
1272  *              dmake_output_mode_specified     Set for make -x DMAKE_OUTPUT_MODE=
1273  *              dmake_odir_specified    Set for make -o
1274  *              dmake_rcfile_specified  Set for make -c
1275  *              env_wins                Set for make -e
1276  *              ignore_default_mk       Set for make -r
1277  *              trace_status            Set for make -p
1278  *
1279  *      Global variables used:
1280  *              .make.state path & name set for make -K
1281  *              continue_after_error    Set for make -k
1282  *              debug_level             Set for make -d
1283  *              do_not_exec_rule        Set for make -n
1284  *              filter_stderr           Set for make -X
1285  *              ignore_errors_all       Set for make -i
1286  *              no_parallel             Set for make -R
1287  *              quest                   Set for make -q
1288  *              read_trace_level        Set for make -D
1289  *              report_dependencies     Set for make -P
1290  *              silent_all              Set for make -s
1291  *              touch                   Set for make -t
1292  */
1293 static int
1294 parse_command_option(register char ch)
1295 {
1296         static int              invert_next = 0;
1297         int                     invert_this = invert_next;
1298 
1299         invert_next = 0;
1300         switch (ch) {
1301         case '-':                        /* Ignore "--" */
1302                 return 0;
1303         case '~':                        /* Invert next option */
1304                 invert_next = 1;
1305                 return 0;
1306         case 'B':                        /* Obsolete */
1307                 return 0;
1308         case 'b':                        /* Obsolete */
1309                 return 0;
1310         case 'c':                        /* Read alternative dmakerc file */
1311                 if (invert_this) {
1312                         dmake_rcfile_specified = false;
1313                 } else {
1314                         dmake_rcfile_specified = true;
1315                 }
1316                 return 2;
1317         case 'D':                        /* Show lines read */
1318                 if (invert_this) {
1319                         read_trace_level--;
1320                 } else {
1321                         read_trace_level++;
1322                 }
1323                 return 0;
1324         case 'd':                        /* Debug flag */
1325                 if (invert_this) {
1326                         debug_level--;
1327                 } else {
1328                         debug_level++;
1329                 }
1330                 return 0;
1331         case 'e':                        /* Environment override flag */
1332                 if (invert_this) {
1333                         env_wins = false;
1334                 } else {
1335                         env_wins = true;
1336                 }
1337                 return 0;
1338         case 'f':                        /* Read alternative makefile(s) */
1339                 return 1;
1340         case 'g':                        /* Use alternative DMake group */
1341                 if (invert_this) {
1342                         dmake_group_specified = false;
1343                 } else {
1344                         dmake_group_specified = true;
1345                 }
1346                 return 4;
1347         case 'i':                        /* Ignore errors */
1348                 if (invert_this) {
1349                         ignore_errors_all = false;
1350                 } else {
1351                         ignore_errors_all = true;
1352                 }
1353                 return 0;
1354         case 'j':                        /* Use alternative DMake max jobs */
1355                 if (invert_this) {
1356                         dmake_max_jobs_specified = false;
1357                 } else {
1358                         dmake_mode_type = parallel_mode;
1359                         no_parallel = false;
1360                         dmake_max_jobs_specified = true;
1361                 }
1362                 return 8;
1363         case 'K':                        /* Read alternative .make.state */
1364                 return 256;
1365         case 'k':                        /* Keep making even after errors */
1366                 if (invert_this) {
1367                         continue_after_error = false;
1368                 } else {
1369                         continue_after_error = true;
1370                         continue_after_error_ever_seen = true;
1371                 }
1372                 return 0;
1373         case 'M':                        /* Read alternative make.machines file */
1374                 if (invert_this) {
1375                         pmake_machinesfile_specified = false;
1376                 } else {
1377                         pmake_machinesfile_specified = true;
1378                         dmake_mode_type = parallel_mode;
1379                         no_parallel = false;
1380                 }
1381                 return 16;
1382         case 'm':                        /* Use alternative DMake build mode */
1383                 if (invert_this) {
1384                         dmake_mode_specified = false;
1385                 } else {
1386                         dmake_mode_specified = true;
1387                 }
1388                 return 32;
1389         case 'x':                        /* Use alternative DMake mode */
1390                 if (invert_this) {
1391                         dmake_add_mode_specified = false;
1392                 } else {
1393                         dmake_add_mode_specified = true;
1394                 }
1395                 return 1024;
1396         case 'N':                        /* Reverse -n */
1397                 if (invert_this) {
1398                         do_not_exec_rule = true;
1399                 } else {
1400                         do_not_exec_rule = false;
1401                 }
1402                 return 0;
1403         case 'n':                        /* Print, not exec commands */
1404                 if (invert_this) {
1405                         do_not_exec_rule = false;
1406                 } else {
1407                         do_not_exec_rule = true;
1408                 }
1409                 return 0;
1410         case 'O':                        /* Integrate with maketool, obsolete */
1411                 return 0;
1412         case 'o':                        /* Use alternative dmake output dir */
1413                 if (invert_this) {
1414                         dmake_odir_specified = false;
1415                 } else {
1416                         dmake_odir_specified = true;
1417                 }
1418                 return 512;
1419         case 'P':                        /* Print for selected targets */
1420                 if (invert_this) {
1421                         report_dependencies_level--;
1422                 } else {
1423                         report_dependencies_level++;
1424                 }
1425                 return 0;
1426         case 'p':                        /* Print description */
1427                 if (invert_this) {
1428                         trace_status = false;
1429                         do_not_exec_rule = false;
1430                 } else {
1431                         trace_status = true;
1432                         do_not_exec_rule = true;
1433                 }
1434                 return 0;
1435         case 'q':                        /* Question flag */
1436                 if (invert_this) {
1437                         quest = false;
1438                 } else {
1439                         quest = true;
1440                 }
1441                 return 0;
1442         case 'R':                        /* Don't run in parallel */
1443                 if (invert_this) {
1444                         pmake_cap_r_specified = false;
1445                         no_parallel = false;
1446                 } else {
1447                         pmake_cap_r_specified = true;
1448                         dmake_mode_type = serial_mode;
1449                         no_parallel = true;
1450                 }
1451                 return 0;
1452         case 'r':                        /* Turn off internal rules */
1453                 if (invert_this) {
1454                         ignore_default_mk = false;
1455                 } else {
1456                         ignore_default_mk = true;
1457                 }
1458                 return 0;
1459         case 'S':                        /* Reverse -k */
1460                 if (invert_this) {
1461                         continue_after_error = true;
1462                 } else {
1463                         continue_after_error = false;
1464                         stop_after_error_ever_seen = true;
1465                 }
1466                 return 0;
1467         case 's':                        /* Silent flag */
1468                 if (invert_this) {
1469                         silent_all = false;
1470                 } else {
1471                         silent_all = true;
1472                 }
1473                 return 0;
1474         case 'T':                        /* Print target list */
1475                 if (invert_this) {
1476                         list_all_targets = false;
1477                         do_not_exec_rule = false;
1478                 } else {
1479                         list_all_targets = true;
1480                         do_not_exec_rule = true;
1481                 }
1482                 return 0;
1483         case 't':                        /* Touch flag */
1484                 if (invert_this) {
1485                         touch = false;
1486                 } else {
1487                         touch = true;
1488                 }
1489                 return 0;
1490         case 'u':                        /* Unconditional flag */
1491                 if (invert_this) {
1492                         build_unconditional = false;
1493                 } else {
1494                         build_unconditional = true;
1495                 }
1496                 return 0;
1497         case 'V':                       /* SVR4 mode */
1498                 svr4 = true;
1499                 return 0;
1500         case 'v':                       /* Version flag */
1501                 if (invert_this) {
1502                 } else {
1503                         fprintf(stdout, "%s: %s\n", getprogname(), verstring);
1504                         exit_status = 0;
1505                         exit(0);
1506                 }
1507                 return 0;
1508         case 'w':                        /* Unconditional flag */
1509                 if (invert_this) {
1510                         report_cwd = false;
1511                 } else {
1512                         report_cwd = true;
1513                 }
1514                 return 0;
1515 #if 0
1516         case 'X':                       /* Filter stdout */
1517                 if (invert_this) {
1518                         filter_stderr = false;
1519                 } else {
1520                         filter_stderr = true;
1521                 }
1522                 return 0;
1523 #endif
1524         default:
1525                 break;
1526         }
1527         return 0;
1528 }
1529 
1530 /*
1531  *      setup_for_projectdir()
1532  *
1533  *      Read the PROJECTDIR variable, if defined, and set the sccs path
1534  *
1535  *      Parameters:
1536  *
1537  *      Global variables used:
1538  *              sccs_dir_path   Set to point to SCCS dir to use
1539  */
1540 static void
1541 setup_for_projectdir(void)
1542 {
1543 static char     path[MAXPATHLEN];
1544 char            cwdpath[MAXPATHLEN];
1545 uid_t uid;
1546 int   done=0;
1547 
1548         /* Check if we should use PROJECTDIR when reading the SCCS dir. */
1549         sccs_dir_path = getenv("PROJECTDIR");
1550         if ((sccs_dir_path != NULL) &&
1551             (sccs_dir_path[0] != (int) slash_char)) {
1552                 struct passwd *pwent;
1553 
1554              {
1555                 uid = getuid();
1556                 pwent = getpwuid(uid);
1557                 if (pwent == NULL) {
1558                    fatal(gettext("Bogus USERID "));
1559                 }
1560                 if ((pwent = getpwnam(sccs_dir_path)) == NULL) {
1561                         /*empty block : it'll go & check cwd  */
1562                 }
1563                 else {
1564                   (void) sprintf(path, "%s/src", pwent->pw_dir);
1565                   if (access(path, F_OK) == 0) {
1566                         sccs_dir_path = path;
1567                         done = 1;
1568                   } else {
1569                         (void) sprintf(path, "%s/source", pwent->pw_dir);
1570                         if (access(path, F_OK) == 0) {
1571                                 sccs_dir_path = path;
1572                                 done = 1;
1573                         }
1574                      }
1575                 }
1576                 if (!done) {
1577                     if (getcwd(cwdpath, MAXPATHLEN - 1 )) {
1578 
1579                        (void) sprintf(path, "%s/%s", cwdpath,sccs_dir_path);
1580                        if (access(path, F_OK) == 0) {
1581                                 sccs_dir_path = path;
1582                                 done = 1;
1583                         } else {
1584                                 fatal(gettext("Bogus PROJECTDIR '%s'"), sccs_dir_path);
1585                         }
1586                     }
1587                 }
1588            }
1589         }
1590 }
1591 
1592 char *
1593 make_install_prefix(void)
1594 {
1595         int ret;
1596         char origin[PATH_MAX];
1597         char *dir;
1598 
1599         if ((ret = readlink("/proc/self/path/a.out", origin,
1600             PATH_MAX - 1)) < 0)
1601                 fatal("failed to read origin from /proc\n");
1602 
1603         
1604         origin[ret] = '\0';
1605         return strdup(dirname(origin));
1606 }
1607 
1608 static char *
1609 add_to_env(const char *var, const char *value, const char *fallback)
1610 {
1611         const char *oldpath;
1612         char *newpath;
1613 
1614         oldpath = getenv(var);
1615         if (oldpath == NULL) {
1616                 if (value != NULL) {
1617                         asprintf(&newpath, "%s=%s",
1618                             var, value);
1619                 } else {
1620                         asprintf(&newpath, "%s=%s",
1621                             var, fallback);
1622                 }
1623         } else {
1624                 if (value != NULL) {
1625                         asprintf(&newpath, "%s=%s:%s",
1626                             var, oldpath, value);
1627                 } else {
1628                         asprintf(&newpath, "%s=%s:%s",
1629                             var, oldpath, fallback);                    
1630                 }
1631         }
1632 
1633         return (newpath);
1634 }
1635 
1636 /*
1637  *      set_sgs_support()
1638  *
1639  *      Add the libmakestate.so.1 lib to the env var SGS_SUPPORT
1640  *        if it's not already in there.
1641  *      The SGS_SUPPORT env var and libmakestate.so.1 is used by
1642  *        the linker ld to report .make.state info back to make.
1643  *
1644  * In the new world we always will set the 32-bit and 64-bit versions of this
1645  * variable explicitly so that we can take into account the correct isa and our
1646  * prefix. So say that the prefix was /opt/local. Then we would want to search
1647  * /opt/local/lib/libmakestate.so.1:libmakestate.so.1. We still want to search
1648  * the original location just as a safety measure.
1649  */
1650 static void
1651 set_sgs_support()
1652 {
1653         int             len;
1654         char            *newpath, *newpath64;
1655         char            *lib32, *lib64;
1656         static char     *prev_path, *prev_path64;
1657         char            *origin = make_install_prefix();
1658         struct stat st;
1659 
1660         asprintf(&lib32, "%s/%s/%s", origin, "../lib",
1661             LD_SUPPORT_MAKE_LIB);
1662 
1663         if (stat(lib32, &st) != 0) {
1664                 free(lib32);
1665                 // Try the tools path
1666                 asprintf(&lib32, "%s/%s/%s/%s", origin, "../../lib/",
1667                     LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB);
1668 
1669                 if (stat(lib32, &st) != 0) {
1670                         free(lib32);
1671                         lib32 = NULL;
1672                 }
1673         }
1674 
1675         asprintf(&lib64, "%s/%s/64/%s", origin, "../lib",
1676             LD_SUPPORT_MAKE_LIB);
1677 
1678         if (stat(lib64, &st) != 0) {
1679                 free(lib64);
1680                 // Try the tools path
1681                 asprintf(&lib64, "%s/%s/%s/64/%s", origin, "../../lib/",
1682                     LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB);
1683 
1684                 if (stat(lib64, &st) != 0) {
1685                         free(lib64);
1686                         lib64 = NULL;
1687                 }
1688         }
1689 
1690         newpath = add_to_env(LD_SUPPORT_ENV_VAR_32, lib32, LD_SUPPORT_MAKE_LIB);
1691         newpath64 = add_to_env(LD_SUPPORT_ENV_VAR_64, lib64, LD_SUPPORT_MAKE_LIB);
1692 
1693         putenv(newpath);
1694         if (prev_path) {
1695                 free(prev_path);
1696         }
1697         prev_path = newpath;
1698 
1699         putenv(newpath64);
1700         if (prev_path64) {
1701                 free(prev_path64);
1702         }
1703         prev_path64 = newpath64;
1704         free(lib32);
1705         free(lib64);
1706         free(origin);
1707 }
1708 
1709 /*
1710  *      read_files_and_state(argc, argv)
1711  *
1712  *      Read the makefiles we care about and the environment
1713  *      Also read the = style command line options
1714  *
1715  *      Parameters:
1716  *              argc            You know what this is
1717  *              argv            You know what this is
1718  *
1719  *      Static variables used:
1720  *              env_wins        make -e, determines if env vars are RO
1721  *              ignore_default_mk make -r, determines if make.rules is read
1722  *              not_auto_depen  dwight
1723  *
1724  *      Global variables used:
1725  *              default_target_to_build Set to first proper target from file
1726  *              do_not_exec_rule Set to false when makfile is made
1727  *              dot             The Name ".", used to read current dir
1728  *              empty_name      The Name "", use as macro value
1729  *              keep_state      Set if KEEP_STATE is in environment
1730  *              make_state      The Name ".make.state", used to read file
1731  *              makefile_type   Set to type of file being read
1732  *              makeflags       The Name "MAKEFLAGS", used to set macro value
1733  *              not_auto        dwight
1734  *              read_trace_level Checked to se if the reader should trace
1735  *              report_dependencies If -P is on we do not read .make.state
1736  *              trace_reader    Set if reader should trace
1737  *              virtual_root    The Name "VIRTUAL_ROOT", used to check value
1738  */
1739 static void
1740 read_files_and_state(int argc, char **argv)
1741 {
1742         wchar_t                 buffer[1000];
1743         wchar_t                 buffer_posix[1000];
1744         register char           ch;
1745         register char           *cp;
1746         Property                def_make_macro = NULL;
1747         Name                    def_make_name;
1748         Name                    default_makefile;
1749         String_rec              dest;
1750         wchar_t                 destbuffer[STRING_BUFFER_LENGTH];
1751         register int            i;
1752         register int            j;
1753         Name                    keep_state_name;
1754         int                     length;
1755         Name                    Makefile;
1756         register Property       macro;
1757         struct stat             make_state_stat;
1758         Name                    makefile_name;
1759         register int            makefile_next = 0;
1760         register Boolean        makefile_read = false;
1761         String_rec              makeflags_string;
1762         String_rec              makeflags_string_posix;
1763         String_rec *            makeflags_string_current;
1764         Name                    makeflags_value_saved;
1765         register Name           name;
1766         Name                    new_make_value;
1767         Boolean                 save_do_not_exec_rule;
1768         Name                    sdotMakefile;
1769         Name                    sdotmakefile_name;
1770         static wchar_t          state_file_str;
1771         static char             state_file_str_mb[MAXPATHLEN];
1772         static struct _Name     state_filename;
1773         Boolean                 temp;
1774         char                    tmp_char;
1775         wchar_t                 *tmp_wcs_buffer;
1776         register Name           value;
1777         ASCII_Dyn_Array         makeflags_and_macro;
1778         Boolean                 is_xpg4;
1779 
1780 /*
1781  *      Remember current mode. It may be changed after reading makefile
1782  *      and we will have to correct MAKEFLAGS variable.
1783  */
1784         is_xpg4 = posix;
1785 
1786         MBSTOWCS(wcs_buffer, "KEEP_STATE");
1787         keep_state_name = GETNAME(wcs_buffer, FIND_LENGTH);
1788         MBSTOWCS(wcs_buffer, "Makefile");
1789         Makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1790         MBSTOWCS(wcs_buffer, "makefile");
1791         makefile_name = GETNAME(wcs_buffer, FIND_LENGTH);
1792         MBSTOWCS(wcs_buffer, "s.makefile");
1793         sdotmakefile_name = GETNAME(wcs_buffer, FIND_LENGTH);
1794         MBSTOWCS(wcs_buffer, "s.Makefile");
1795         sdotMakefile = GETNAME(wcs_buffer, FIND_LENGTH);
1796 
1797 /*
1798  *      initialize global dependency entry for .NOT_AUTO
1799  */
1800         not_auto_depen->next = NULL;
1801         not_auto_depen->name = not_auto;
1802         not_auto_depen->automatic = not_auto_depen->stale = false;
1803 
1804 /*
1805  *      Read internal definitions and rules.
1806  */
1807         if (read_trace_level > 1) {
1808                 trace_reader = true;
1809         }
1810         if (!ignore_default_mk) {
1811                 if (svr4) {
1812                         MBSTOWCS(wcs_buffer, "svr4.make.rules");
1813                         default_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1814                 } else {
1815                         MBSTOWCS(wcs_buffer, "make.rules");
1816                         default_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1817                 }
1818                 default_makefile->stat.is_file = true;
1819 
1820                 (void) read_makefile(default_makefile,
1821                                      true,
1822                                      false,
1823                                      true);
1824         }
1825 
1826         /*
1827          * If the user did not redefine the MAKE macro in the
1828          * default makefile (make.rules), then we'd like to
1829          * change the macro value of MAKE to be some form
1830          * of argv[0] for recursive MAKE builds.
1831          */
1832         MBSTOWCS(wcs_buffer, "MAKE");
1833         def_make_name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
1834         def_make_macro = get_prop(def_make_name->prop, macro_prop);
1835         if ((def_make_macro != NULL) &&
1836             (IS_EQUAL(def_make_macro->body.macro.value->string_mb,
1837                       "make"))) {
1838                 MBSTOWCS(wcs_buffer, argv_zero_string);
1839                 new_make_value = GETNAME(wcs_buffer, wcslen(wcs_buffer));
1840                 (void) SETVAR(def_make_name,
1841                               new_make_value,
1842                               false);
1843         }
1844 
1845         default_target_to_build = NULL;
1846         trace_reader = false;
1847 
1848 /*
1849  *      Read environment args. Let file args which follow override unless
1850  *      -e option seen. If -e option is not mentioned.
1851  */
1852         read_environment(env_wins);
1853         if (getvar(virtual_root)->hash.length == 0) {
1854                 maybe_append_prop(virtual_root, macro_prop)
1855                   ->body.macro.exported = true;
1856                 MBSTOWCS(wcs_buffer, "/");
1857                 (void) SETVAR(virtual_root,
1858                               GETNAME(wcs_buffer, FIND_LENGTH),
1859                               false);
1860         }
1861 
1862 /*
1863  * We now scan mf_argv and argv to see if we need to set
1864  * any of the DMake-added options/variables in MAKEFLAGS.
1865  */
1866 
1867         makeflags_and_macro.start = 0;
1868         makeflags_and_macro.size = 0;
1869         enter_argv_values(mf_argc, mf_argv, &makeflags_and_macro);
1870         enter_argv_values(argc, argv, &makeflags_and_macro);
1871 
1872 /*
1873  *      Set MFLAGS and MAKEFLAGS
1874  *      
1875  *      Before reading makefile we do not know exactly which mode
1876  *      (posix or not) is used. So prepare two MAKEFLAGS strings
1877  *      for both posix and solaris modes because they are different.
1878  */
1879         INIT_STRING_FROM_STACK(makeflags_string, buffer);
1880         INIT_STRING_FROM_STACK(makeflags_string_posix, buffer_posix);
1881         append_char((int) hyphen_char, &makeflags_string);
1882         append_char((int) hyphen_char, &makeflags_string_posix);
1883 
1884         switch (read_trace_level) {
1885         case 2:
1886                 append_char('D', &makeflags_string);
1887                 append_char('D', &makeflags_string_posix);
1888         case 1:
1889                 append_char('D', &makeflags_string);
1890                 append_char('D', &makeflags_string_posix);
1891         }
1892         switch (debug_level) {
1893         case 2:
1894                 append_char('d', &makeflags_string);
1895                 append_char('d', &makeflags_string_posix);
1896         case 1:
1897                 append_char('d', &makeflags_string);
1898                 append_char('d', &makeflags_string_posix);
1899         }
1900         if (env_wins) {
1901                 append_char('e', &makeflags_string);
1902                 append_char('e', &makeflags_string_posix);
1903         }
1904         if (ignore_errors_all) {
1905                 append_char('i', &makeflags_string);
1906                 append_char('i', &makeflags_string_posix);
1907         }
1908         if (continue_after_error) {
1909                 if (stop_after_error_ever_seen) {
1910                         append_char('S', &makeflags_string_posix);
1911                         append_char((int) space_char, &makeflags_string_posix);
1912                         append_char((int) hyphen_char, &makeflags_string_posix);
1913                 }
1914                 append_char('k', &makeflags_string);
1915                 append_char('k', &makeflags_string_posix);
1916         } else {
1917                 if (stop_after_error_ever_seen 
1918                     && continue_after_error_ever_seen) {
1919                         append_char('k', &makeflags_string_posix);
1920                         append_char((int) space_char, &makeflags_string_posix);
1921                         append_char((int) hyphen_char, &makeflags_string_posix);
1922                         append_char('S', &makeflags_string_posix);
1923                 }
1924         }
1925         if (do_not_exec_rule) {
1926                 append_char('n', &makeflags_string);
1927                 append_char('n', &makeflags_string_posix);
1928         }
1929         switch (report_dependencies_level) {
1930         case 4:
1931                 append_char('P', &makeflags_string);
1932                 append_char('P', &makeflags_string_posix);
1933         case 3:
1934                 append_char('P', &makeflags_string);
1935                 append_char('P', &makeflags_string_posix);
1936         case 2:
1937                 append_char('P', &makeflags_string);
1938                 append_char('P', &makeflags_string_posix);
1939         case 1:
1940                 append_char('P', &makeflags_string);
1941                 append_char('P', &makeflags_string_posix);
1942         }
1943         if (trace_status) {
1944                 append_char('p', &makeflags_string);
1945                 append_char('p', &makeflags_string_posix);
1946         }
1947         if (quest) {
1948                 append_char('q', &makeflags_string);
1949                 append_char('q', &makeflags_string_posix);
1950         }
1951         if (silent_all) {
1952                 append_char('s', &makeflags_string);
1953                 append_char('s', &makeflags_string_posix);
1954         }
1955         if (touch) {
1956                 append_char('t', &makeflags_string);
1957                 append_char('t', &makeflags_string_posix);
1958         }
1959         if (build_unconditional) {
1960                 append_char('u', &makeflags_string);
1961                 append_char('u', &makeflags_string_posix);
1962         }
1963         if (report_cwd) {
1964                 append_char('w', &makeflags_string);
1965                 append_char('w', &makeflags_string_posix);
1966         }
1967         /* -c dmake_rcfile */
1968         if (dmake_rcfile_specified) {
1969                 MBSTOWCS(wcs_buffer, "DMAKE_RCFILE");
1970                 dmake_rcfile = GETNAME(wcs_buffer, FIND_LENGTH);
1971                 append_makeflags_string(dmake_rcfile, &makeflags_string);
1972                 append_makeflags_string(dmake_rcfile, &makeflags_string_posix);
1973         }
1974         /* -g dmake_group */
1975         if (dmake_group_specified) {
1976                 MBSTOWCS(wcs_buffer, "DMAKE_GROUP");
1977                 dmake_group = GETNAME(wcs_buffer, FIND_LENGTH);
1978                 append_makeflags_string(dmake_group, &makeflags_string);
1979                 append_makeflags_string(dmake_group, &makeflags_string_posix);
1980         }
1981         /* -j dmake_max_jobs */
1982         if (dmake_max_jobs_specified) {
1983                 MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
1984                 dmake_max_jobs = GETNAME(wcs_buffer, FIND_LENGTH);
1985                 append_makeflags_string(dmake_max_jobs, &makeflags_string);
1986                 append_makeflags_string(dmake_max_jobs, &makeflags_string_posix);
1987         }
1988         /* -m dmake_mode */
1989         if (dmake_mode_specified) {
1990                 MBSTOWCS(wcs_buffer, "DMAKE_MODE");
1991                 dmake_mode = GETNAME(wcs_buffer, FIND_LENGTH);
1992                 append_makeflags_string(dmake_mode, &makeflags_string);
1993                 append_makeflags_string(dmake_mode, &makeflags_string_posix);
1994         }
1995         /* -x dmake_compat_mode */
1996 //      if (dmake_compat_mode_specified) {
1997 //              MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE");
1998 //              dmake_compat_mode = GETNAME(wcs_buffer, FIND_LENGTH);
1999 //              append_makeflags_string(dmake_compat_mode, &makeflags_string);
2000 //              append_makeflags_string(dmake_compat_mode, &makeflags_string_posix);
2001 //      }
2002         /* -x dmake_output_mode */
2003         if (dmake_output_mode_specified) {
2004                 MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
2005                 dmake_output_mode = GETNAME(wcs_buffer, FIND_LENGTH);
2006                 append_makeflags_string(dmake_output_mode, &makeflags_string);
2007                 append_makeflags_string(dmake_output_mode, &makeflags_string_posix);
2008         }
2009         /* -o dmake_odir */
2010         if (dmake_odir_specified) {
2011                 MBSTOWCS(wcs_buffer, "DMAKE_ODIR");
2012                 dmake_odir = GETNAME(wcs_buffer, FIND_LENGTH);
2013                 append_makeflags_string(dmake_odir, &makeflags_string);
2014                 append_makeflags_string(dmake_odir, &makeflags_string_posix);
2015         }
2016         /* -M pmake_machinesfile */
2017         if (pmake_machinesfile_specified) {
2018                 MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
2019                 pmake_machinesfile = GETNAME(wcs_buffer, FIND_LENGTH);
2020                 append_makeflags_string(pmake_machinesfile, &makeflags_string);
2021                 append_makeflags_string(pmake_machinesfile, &makeflags_string_posix);
2022         }
2023         /* -R */
2024         if (pmake_cap_r_specified) {
2025                 append_char((int) space_char, &makeflags_string);
2026                 append_char((int) hyphen_char, &makeflags_string);
2027                 append_char('R', &makeflags_string);
2028                 append_char((int) space_char, &makeflags_string_posix);
2029                 append_char((int) hyphen_char, &makeflags_string_posix);
2030                 append_char('R', &makeflags_string_posix);
2031         }
2032 
2033 /*
2034  *      Make sure MAKEFLAGS is exported
2035  */
2036         maybe_append_prop(makeflags, macro_prop)->
2037           body.macro.exported = true;
2038 
2039         if (makeflags_string.buffer.start[1] != (int) nul_char) {
2040                 if (makeflags_string.buffer.start[1] != (int) space_char) {
2041                         MBSTOWCS(wcs_buffer, "MFLAGS");
2042                         (void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH),
2043                                       GETNAME(makeflags_string.buffer.start,
2044                                               FIND_LENGTH),
2045                                       false);
2046                 } else {
2047                         MBSTOWCS(wcs_buffer, "MFLAGS");
2048                         (void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH),
2049                                       GETNAME(makeflags_string.buffer.start + 2,
2050                                               FIND_LENGTH),
2051                                       false);
2052                 }
2053         }
2054 
2055 /* 
2056  *      Add command line macro to POSIX makeflags_string  
2057  */
2058         if (makeflags_and_macro.start) {
2059                 tmp_char = (char) space_char;
2060                 cp = makeflags_and_macro.start;
2061                 do {
2062                         append_char(tmp_char, &makeflags_string_posix);
2063                 } while ( tmp_char = *cp++ ); 
2064                 retmem_mb(makeflags_and_macro.start);
2065         }
2066 
2067 /*
2068  *      Now set the value of MAKEFLAGS macro in accordance
2069  *      with current mode.
2070  */
2071         macro = maybe_append_prop(makeflags, macro_prop);
2072         temp = (Boolean) macro->body.macro.read_only;
2073         macro->body.macro.read_only = false;
2074         if(posix || gnu_style) {
2075                 makeflags_string_current = &makeflags_string_posix;
2076         } else {
2077                 makeflags_string_current = &makeflags_string;
2078         }
2079         if (makeflags_string_current->buffer.start[1] == (int) nul_char) {
2080                 makeflags_value_saved =
2081                         GETNAME( makeflags_string_current->buffer.start + 1
2082                                , FIND_LENGTH
2083                                );
2084         } else {
2085                 if (makeflags_string_current->buffer.start[1] != (int) space_char) {
2086                         makeflags_value_saved =
2087                                 GETNAME( makeflags_string_current->buffer.start
2088                                        , FIND_LENGTH
2089                                        );
2090                 } else {
2091                         makeflags_value_saved =
2092                                 GETNAME( makeflags_string_current->buffer.start + 2
2093                                        , FIND_LENGTH
2094                                        );
2095                 }
2096         }
2097         (void) SETVAR( makeflags
2098                      , makeflags_value_saved
2099                      , false
2100                      );
2101         macro->body.macro.read_only = temp;
2102 
2103 /*
2104  *      Read command line "-f" arguments and ignore -c, g, j, K, M, m, O and o args.
2105  */
2106         save_do_not_exec_rule = do_not_exec_rule;
2107         do_not_exec_rule = false;
2108         if (read_trace_level > 0) {
2109                 trace_reader = true;
2110         }
2111 
2112         for (i = 1; i < argc; i++) {
2113                 if (argv[i] &&
2114                     (argv[i][0] == (int) hyphen_char) &&
2115                     (argv[i][1] == 'f') &&
2116                     (argv[i][2] == (int) nul_char)) {
2117                         argv[i] = NULL;         /* Remove -f */
2118                         if (i >= argc - 1) {
2119                                 fatal(gettext("No filename argument after -f flag"));
2120                         }
2121                         MBSTOWCS(wcs_buffer, argv[++i]);
2122                         primary_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
2123                         (void) read_makefile(primary_makefile, true, true, true);
2124                         argv[i] = NULL;         /* Remove filename */
2125                         makefile_read = true;
2126                 } else if (argv[i] &&
2127                            (argv[i][0] == (int) hyphen_char) &&
2128                            (argv[i][1] == 'c' ||
2129                             argv[i][1] == 'g' ||
2130                             argv[i][1] == 'j' ||
2131                             argv[i][1] == 'K' ||
2132                             argv[i][1] == 'M' ||
2133                             argv[i][1] == 'm' ||
2134                             argv[i][1] == 'O' ||
2135                             argv[i][1] == 'o') &&
2136                            (argv[i][2] == (int) nul_char)) {
2137                         argv[i] = NULL;
2138                         argv[++i] = NULL;
2139                 }
2140         }
2141 
2142 /*
2143  *      If no command line "-f" args then look for "makefile", and then for
2144  *      "Makefile" if "makefile" isn't found.
2145  */
2146         if (!makefile_read) {
2147                 (void) read_dir(dot,
2148                                 (wchar_t *) NULL,
2149                                 (Property) NULL,
2150                                 (wchar_t *) NULL);
2151             if (!posix) {
2152                 if (makefile_name->stat.is_file) {
2153                         if (Makefile->stat.is_file) {
2154                                 warning(gettext("Both `makefile' and `Makefile' exist"));
2155                         }
2156                         primary_makefile = makefile_name;
2157                         makefile_read = read_makefile(makefile_name,
2158                                                       false,
2159                                                       false,
2160                                                       true);
2161                 }
2162                 if (!makefile_read &&
2163                     Makefile->stat.is_file) {
2164                         primary_makefile = Makefile;
2165                         makefile_read = read_makefile(Makefile,
2166                                                       false,
2167                                                       false,
2168                                                       true);
2169                 }
2170             } else {
2171 
2172                 enum sccs_stat save_m_has_sccs = NO_SCCS;
2173                 enum sccs_stat save_M_has_sccs = NO_SCCS;
2174 
2175                 if (makefile_name->stat.is_file) {
2176                         if (Makefile->stat.is_file) {
2177                                 warning(gettext("Both `makefile' and `Makefile' exist"));
2178                         }
2179                 }
2180                 if (makefile_name->stat.is_file) {
2181                         if (makefile_name->stat.has_sccs == NO_SCCS) {
2182                            primary_makefile = makefile_name;
2183                            makefile_read = read_makefile(makefile_name,
2184                                                       false,
2185                                                       false,
2186                                                       true);
2187                         } else {
2188                           save_m_has_sccs = makefile_name->stat.has_sccs;
2189                           makefile_name->stat.has_sccs = NO_SCCS;
2190                           primary_makefile = makefile_name;
2191                           makefile_read = read_makefile(makefile_name,
2192                                                       false,
2193                                                       false,
2194                                                       true);
2195                         }
2196                 }
2197                 if (!makefile_read &&
2198                     Makefile->stat.is_file) {
2199                         if (Makefile->stat.has_sccs == NO_SCCS) {
2200                            primary_makefile = Makefile;
2201                            makefile_read = read_makefile(Makefile,
2202                                                       false,
2203                                                       false,
2204                                                       true);
2205                         } else {
2206                           save_M_has_sccs = Makefile->stat.has_sccs;
2207                           Makefile->stat.has_sccs = NO_SCCS;
2208                           primary_makefile = Makefile;
2209                           makefile_read = read_makefile(Makefile,
2210                                                       false,
2211                                                       false,
2212                                                       true);
2213                         }
2214                 }
2215                 if (!makefile_read &&
2216                         makefile_name->stat.is_file) {
2217                            makefile_name->stat.has_sccs = save_m_has_sccs;
2218                            primary_makefile = makefile_name;
2219                            makefile_read = read_makefile(makefile_name,
2220                                                       false,
2221                                                       false,
2222                                                       true);
2223                 }
2224                 if (!makefile_read &&
2225                     Makefile->stat.is_file) {
2226                            Makefile->stat.has_sccs = save_M_has_sccs;
2227                            primary_makefile = Makefile;
2228                            makefile_read = read_makefile(Makefile,
2229                                                       false,
2230                                                       false,
2231                                                       true);
2232                 }
2233             }
2234         }
2235         do_not_exec_rule = save_do_not_exec_rule;
2236         allrules_read = makefile_read;
2237         trace_reader = false;
2238 
2239 /*
2240  *      Now get current value of MAKEFLAGS and compare it with
2241  *      the saved value we set before reading makefile.
2242  *      If they are different then MAKEFLAGS is subsequently set by
2243  *      makefile, just leave it there. Otherwise, if make mode
2244  *      is changed by using .POSIX target in makefile we need
2245  *      to correct MAKEFLAGS value.
2246  */
2247         Name mf_val = getvar(makeflags);
2248         if( (posix != is_xpg4)
2249          && (!strcmp(mf_val->string_mb, makeflags_value_saved->string_mb)))
2250         {
2251                 if (makeflags_string_posix.buffer.start[1] == (int) nul_char) {
2252                         (void) SETVAR(makeflags,
2253                                       GETNAME(makeflags_string_posix.buffer.start + 1,
2254                                               FIND_LENGTH),
2255                                       false);
2256                 } else {
2257                         if (makeflags_string_posix.buffer.start[1] != (int) space_char) {
2258                                 (void) SETVAR(makeflags,
2259                                               GETNAME(makeflags_string_posix.buffer.start,
2260                                                       FIND_LENGTH),
2261                                               false);
2262                         } else {
2263                                 (void) SETVAR(makeflags,
2264                                               GETNAME(makeflags_string_posix.buffer.start + 2,
2265                                                       FIND_LENGTH),
2266                                               false);
2267                         }
2268                 }
2269         }
2270 
2271         if (makeflags_string.free_after_use) {
2272                 retmem(makeflags_string.buffer.start);
2273         }
2274         if (makeflags_string_posix.free_after_use) {
2275                 retmem(makeflags_string_posix.buffer.start);
2276         }
2277         makeflags_string.buffer.start = NULL;
2278         makeflags_string_posix.buffer.start = NULL;
2279 
2280         if (posix) {
2281                 /*
2282                  * If the user did not redefine the ARFLAGS macro in the
2283                  * default makefile (make.rules), then we'd like to
2284                  * change the macro value of ARFLAGS to be in accordance
2285                  * with "POSIX" requirements.
2286                  */
2287                 MBSTOWCS(wcs_buffer, "ARFLAGS");
2288                 name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2289                 macro = get_prop(name->prop, macro_prop);
2290                 if ((macro != NULL) && /* Maybe (macro == NULL) || ? */
2291                     (IS_EQUAL(macro->body.macro.value->string_mb,
2292                               "rv"))) {
2293                         MBSTOWCS(wcs_buffer, "-rv");
2294                         value = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2295                         (void) SETVAR(name,
2296                                       value,
2297                                       false);
2298                 }
2299         }
2300 
2301         if (!posix && !svr4) {
2302                 set_sgs_support();
2303         }
2304 
2305 
2306 /*
2307  *      Make sure KEEP_STATE is in the environment if KEEP_STATE is on.
2308  */
2309         macro = get_prop(keep_state_name->prop, macro_prop);
2310         if ((macro != NULL) &&
2311             macro->body.macro.exported) {
2312                 keep_state = true;
2313         }
2314         if (keep_state) {
2315                 if (macro == NULL) {
2316                         macro = maybe_append_prop(keep_state_name,
2317                                                   macro_prop);
2318                 }
2319                 macro->body.macro.exported = true;
2320                 (void) SETVAR(keep_state_name,
2321                               empty_name,
2322                               false);
2323 
2324                 /*
2325                  *      Read state file
2326                  */
2327 
2328                 /* Before we read state, let's make sure we have
2329                 ** right state file.
2330                 */
2331                 /* just in case macro references are used in make_state file
2332                 ** name, we better expand them at this stage using expand_value.
2333                 */
2334                 INIT_STRING_FROM_STACK(dest, destbuffer);
2335                 expand_value(make_state, &dest, false);
2336 
2337                 make_state = GETNAME(dest.buffer.start, FIND_LENGTH);
2338 
2339                 if(!stat(make_state->string_mb, &make_state_stat)) {
2340                    if(!(make_state_stat.st_mode & S_IFREG) ) {
2341                         /* copy the make_state structure to the other
2342                         ** and then let make_state point to the new
2343                         ** one.
2344                         */
2345                       memcpy(&state_filename, make_state,sizeof(state_filename));
2346                       state_filename.string_mb = state_file_str_mb;
2347                 /* Just a kludge to avoid two slashes back to back */                   
2348                       if((make_state->hash.length == 1)&&
2349                                 (make_state->string_mb[0] == '/')) {
2350                          make_state->hash.length = 0;
2351                          make_state->string_mb[0] = '\0';
2352                       }
2353                       sprintf(state_file_str_mb,"%s%s",
2354                        make_state->string_mb,"/.make.state");
2355                       make_state = &state_filename;
2356                         /* adjust the length to reflect the appended string */
2357                       make_state->hash.length += 12;
2358                    }
2359                 } else { /* the file doesn't exist or no permission */
2360                    char tmp_path[MAXPATHLEN];
2361                    char *slashp;
2362 
2363                    if (slashp = strrchr(make_state->string_mb, '/')) {
2364                       strncpy(tmp_path, make_state->string_mb, 
2365                                 (slashp - make_state->string_mb));
2366                         tmp_path[slashp - make_state->string_mb]=0;
2367                       if(strlen(tmp_path)) {
2368                         if(stat(tmp_path, &make_state_stat)) {
2369                           warning(gettext("directory %s for .KEEP_STATE_FILE does not exist"),tmp_path);
2370                         }
2371                         if (access(tmp_path, F_OK) != 0) {
2372                           warning(gettext("can't access dir %s"),tmp_path);
2373                         }
2374                       }
2375                    }
2376                 }
2377                 if (report_dependencies_level != 1) {
2378                         Makefile_type   makefile_type_temp = makefile_type;
2379                         makefile_type = reading_statefile;
2380                         if (read_trace_level > 1) {
2381                                 trace_reader = true;
2382                         }
2383                         (void) read_simple_file(make_state,
2384                                                 false,
2385                                                 false,
2386                                                 false,
2387                                                 false,
2388                                                 false,
2389                                                 true);
2390                         trace_reader = false;
2391                         makefile_type = makefile_type_temp;
2392                 }
2393         }
2394 }
2395 
2396 /*
2397  * Scan the argv for options and "=" type args and make them readonly.
2398  */
2399 static void
2400 enter_argv_values(int argc, char *argv[], ASCII_Dyn_Array *makeflags_and_macro)
2401 {
2402         register char           *cp;
2403         register int            i;
2404         int                     length;
2405         register Name           name;
2406         int                     opt_separator = argc; 
2407         char                    tmp_char;
2408         wchar_t                 *tmp_wcs_buffer;
2409         register Name           value;
2410         Boolean                 append = false;
2411         Property                macro;
2412         struct stat             statbuf;
2413 
2414 
2415         /* Read argv options and "=" type args and make them readonly. */
2416         makefile_type = reading_nothing;
2417         for (i = 1; i < argc; ++i) {
2418                 append = false;
2419                 if (argv[i] == NULL) {
2420                         continue;
2421                 } else if (((argv[i][0] == '-') && (argv[i][1] == '-')) ||
2422                            ((argv[i][0] == (int) ' ') &&
2423                             (argv[i][1] == (int) '-') &&
2424                             (argv[i][2] == (int) ' ') &&
2425                             (argv[i][3] == (int) '-'))) {
2426                         argv[i] = NULL;
2427                         opt_separator = i;
2428                         continue;
2429                 } else if ((i < opt_separator) && (argv[i][0] == (int) hyphen_char)) {
2430                         switch (parse_command_option(argv[i][1])) {
2431                         case 1: /* -f seen */
2432                                 ++i;
2433                                 continue;
2434                         case 2: /* -c seen */
2435                                 if (argv[i+1] == NULL) {
2436                                         fatal(gettext("No dmake rcfile argument after -c flag"));
2437                                 }
2438                                 MBSTOWCS(wcs_buffer, "DMAKE_RCFILE");
2439                                 name = GETNAME(wcs_buffer, FIND_LENGTH);
2440                                 break;
2441                         case 4: /* -g seen */
2442                                 if (argv[i+1] == NULL) {
2443                                         fatal(gettext("No dmake group argument after -g flag"));
2444                                 }
2445                                 MBSTOWCS(wcs_buffer, "DMAKE_GROUP");
2446                                 name = GETNAME(wcs_buffer, FIND_LENGTH);
2447                                 break;
2448                         case 8: /* -j seen */
2449                                 if (argv[i+1] == NULL) {
2450                                         fatal(gettext("No dmake max jobs argument after -j flag"));
2451                                 }
2452                                 MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
2453                                 name = GETNAME(wcs_buffer, FIND_LENGTH);
2454                                 break;
2455                         case 16: /* -M seen */
2456                                 if (argv[i+1] == NULL) {
2457                                         fatal(gettext("No pmake machinesfile argument after -M flag"));
2458                                 }
2459                                 MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
2460                                 name = GETNAME(wcs_buffer, FIND_LENGTH);
2461                                 break;
2462                         case 32: /* -m seen */
2463                                 if (argv[i+1] == NULL) {
2464                                         fatal(gettext("No dmake mode argument after -m flag"));
2465                                 }
2466                                 MBSTOWCS(wcs_buffer, "DMAKE_MODE");
2467                                 name = GETNAME(wcs_buffer, FIND_LENGTH);
2468                                 break;
2469                         case 256: /* -K seen */
2470                                 if (argv[i+1] == NULL) {
2471                                         fatal(gettext("No makestate filename argument after -K flag"));
2472                                 }
2473                                 MBSTOWCS(wcs_buffer, argv[i+1]);
2474                                 make_state = GETNAME(wcs_buffer, FIND_LENGTH);
2475                                 keep_state = true;
2476                                 argv[i] = NULL;
2477                                 argv[i+1] = NULL;
2478                                 continue;
2479                         case 512:       /* -o seen */
2480                                 if (argv[i+1] == NULL) {
2481                                         fatal(gettext("No dmake output dir argument after -o flag"));
2482                                 }
2483                                 MBSTOWCS(wcs_buffer, "DMAKE_ODIR");
2484                                 name = GETNAME(wcs_buffer, FIND_LENGTH);
2485                                 break;
2486                         case 1024: /* -x seen */
2487                                 if (argv[i+1] == NULL) {
2488                                         fatal(gettext("No argument after -x flag"));
2489                                 }
2490                                 length = strlen( "SUN_MAKE_COMPAT_MODE=");
2491                                 if (strncmp(argv[i+1], "SUN_MAKE_COMPAT_MODE=", length) == 0) {
2492                                         argv[i+1] = &argv[i+1][length];
2493                                         MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE");
2494                                         name = GETNAME(wcs_buffer, FIND_LENGTH);
2495                                         dmake_compat_mode_specified = dmake_add_mode_specified;
2496                                         break;
2497                                 }
2498                                 length = strlen( "DMAKE_OUTPUT_MODE=");
2499                                 if (strncmp(argv[i+1], "DMAKE_OUTPUT_MODE=", length) == 0) {
2500                                         argv[i+1] = &argv[i+1][length];
2501                                         MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
2502                                         name = GETNAME(wcs_buffer, FIND_LENGTH);
2503                                         dmake_output_mode_specified = dmake_add_mode_specified;
2504                                 } else {
2505                                         warning(gettext("Unknown argument `%s' after -x flag (ignored)"),
2506                                               argv[i+1]);
2507                                         argv[i] = argv[i + 1] = NULL;
2508                                         continue;
2509                                 }
2510                                 break;
2511                         default: /* Shouldn't reach here */
2512                                 argv[i] = NULL;
2513                                 continue;
2514                         }
2515                         argv[i] = NULL;
2516                         if (i == (argc - 1)) {
2517                                 break;
2518                         }
2519                         if ((length = strlen(argv[i+1])) >= MAXPATHLEN) {
2520                                 tmp_wcs_buffer = ALLOC_WC(length + 1);
2521                                 (void) mbstowcs(tmp_wcs_buffer, argv[i+1], length + 1);
2522                                 value = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
2523                                 retmem(tmp_wcs_buffer);
2524                         } else {
2525                                 MBSTOWCS(wcs_buffer, argv[i+1]);
2526                                 value = GETNAME(wcs_buffer, FIND_LENGTH);
2527                         }
2528                         argv[i+1] = NULL;
2529                 } else if ((cp = strchr(argv[i], (int) equal_char)) != NULL) {
2530 /* 
2531  * Combine all macro in dynamic array
2532  */
2533                         if(*(cp-1) == (int) plus_char)
2534                         {
2535                                 if(isspace(*(cp-2))) {
2536                                         append = true;
2537                                         cp--;
2538                                 }
2539                         }
2540                         if(!append)
2541                                 append_or_replace_macro_in_dyn_array(makeflags_and_macro, argv[i]);
2542 
2543                         while (isspace(*(cp-1))) {
2544                                 cp--;
2545                         }
2546                         tmp_char = *cp;
2547                         *cp = (int) nul_char;
2548                         MBSTOWCS(wcs_buffer, argv[i]);
2549                         *cp = tmp_char;
2550                         name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2551                         while (*cp != (int) equal_char) {
2552                                 cp++;
2553                         }
2554                         cp++;
2555                         while (isspace(*cp) && (*cp != (int) nul_char)) {
2556                                 cp++;
2557                         }
2558                         if ((length = strlen(cp)) >= MAXPATHLEN) {
2559                                 tmp_wcs_buffer = ALLOC_WC(length + 1);
2560                                 (void) mbstowcs(tmp_wcs_buffer, cp, length + 1);
2561                                 value = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
2562                                 retmem(tmp_wcs_buffer);
2563                         } else {
2564                                 MBSTOWCS(wcs_buffer, cp);
2565                                 value = GETNAME(wcs_buffer, FIND_LENGTH);
2566                         }
2567                         argv[i] = NULL;
2568                 } else {
2569                         /* Illegal MAKEFLAGS argument */
2570                         continue;
2571                 }
2572                 if(append) {
2573                         setvar_append(name, value);
2574                         append = false;
2575                 } else {
2576                         macro = maybe_append_prop(name, macro_prop);
2577                         macro->body.macro.exported = true;
2578                         SETVAR(name, value, false)->body.macro.read_only = true;
2579                 }
2580         }
2581 }
2582 
2583 /*
2584  * Append the DMake option and value to the MAKEFLAGS string.
2585  */
2586 static void
2587 append_makeflags_string(Name name, register String makeflags_string)
2588 {
2589         const char      *option;
2590 
2591         if (strcmp(name->string_mb, "DMAKE_GROUP") == 0) {
2592                 option = " -g ";
2593         } else if (strcmp(name->string_mb, "DMAKE_MAX_JOBS") == 0) {
2594                 option = " -j ";
2595         } else if (strcmp(name->string_mb, "DMAKE_MODE") == 0) {
2596                 option = " -m ";
2597         } else if (strcmp(name->string_mb, "DMAKE_ODIR") == 0) {
2598                 option = " -o ";
2599         } else if (strcmp(name->string_mb, "DMAKE_RCFILE") == 0) {
2600                 option = " -c ";
2601         } else if (strcmp(name->string_mb, "PMAKE_MACHINESFILE") == 0) {
2602                 option = " -M ";
2603         } else if (strcmp(name->string_mb, "DMAKE_OUTPUT_MODE") == 0) {
2604                 option = " -x DMAKE_OUTPUT_MODE=";
2605         } else if (strcmp(name->string_mb, "SUN_MAKE_COMPAT_MODE") == 0) {
2606                 option = " -x SUN_MAKE_COMPAT_MODE=";
2607         } else {
2608                 fatal(gettext("Internal error: name not recognized in append_makeflags_string()"));
2609         }
2610         Property prop = maybe_append_prop(name, macro_prop);
2611         if( prop == 0 || prop->body.macro.value == 0 ||
2612             prop->body.macro.value->string_mb == 0 ) {
2613                 return;
2614         }
2615         char mbs_value[MAXPATHLEN + 100];
2616         strcpy(mbs_value, option);
2617         strcat(mbs_value, prop->body.macro.value->string_mb);
2618         MBSTOWCS(wcs_buffer, mbs_value);
2619         append_string(wcs_buffer, makeflags_string, FIND_LENGTH);
2620 }
2621 
2622 /*
2623  *      read_environment(read_only)
2624  *
2625  *      This routine reads the process environment when make starts and enters
2626  *      it as make macros. The environment variable SHELL is ignored.
2627  *
2628  *      Parameters:
2629  *              read_only       Should we make env vars read only?
2630  *
2631  *      Global variables used:
2632  *              report_pwd      Set if this make was started by other make
2633  */
2634 static void
2635 read_environment(Boolean read_only)
2636 {
2637         register char           **environment;
2638         int                     length;
2639         wchar_t                 *tmp_wcs_buffer;
2640         Boolean                 alloced_tmp_wcs_buffer = false;
2641         register wchar_t        *name;
2642         register wchar_t        *value;
2643         register Name           macro;
2644         Property                val;
2645         Boolean                 read_only_saved;
2646 
2647         reading_environment = true;
2648         environment = environ;
2649         for (; *environment; environment++) {
2650                 read_only_saved = read_only;
2651                 if ((length = strlen(*environment)) >= MAXPATHLEN) {
2652                         tmp_wcs_buffer = ALLOC_WC(length + 1);
2653                         alloced_tmp_wcs_buffer = true;
2654                         (void) mbstowcs(tmp_wcs_buffer, *environment, length + 1);
2655                         name = tmp_wcs_buffer;
2656                 } else {
2657                         MBSTOWCS(wcs_buffer, *environment);
2658                         name = wcs_buffer;
2659                 }
2660                 value = (wchar_t *) wcschr(name, (int) equal_char);
2661 
2662                 /*
2663                  * Looks like there's a bug in the system, but sometimes
2664                  * you can get blank lines in *environment.
2665                  */
2666                 if (!value) {
2667                         continue;
2668                 }
2669                 MBSTOWCS(wcs_buffer2, "SHELL=");
2670                 if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2671                         continue;
2672                 }
2673                 MBSTOWCS(wcs_buffer2, "MAKEFLAGS=");
2674                 if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2675                         report_pwd = true;
2676                         /*
2677                          * In POSIX mode we do not want MAKEFLAGS to be readonly.
2678                          * If the MAKEFLAGS macro is subsequently set by the makefile,
2679                          * it replaces the MAKEFLAGS variable currently found in the
2680                          * environment.
2681                          * See Assertion 50 in section 6.2.5.3 of standard P1003.3.2/D8.
2682                          */
2683                         if(posix) {
2684                                 read_only_saved = false;
2685                         }
2686                 }
2687 
2688                 /*
2689                  * We ignore SUNPRO_DEPENDENCIES. This environment variable is
2690                  * set by make and read by cpp which then writes info to
2691                  * .make.dependency.xxx.  When make is invoked by another make
2692                  * (recursive make), we don't want to read this because then
2693                  * the child make will end up writing to the parent
2694                  * directory's .make.state and clobbering them.
2695                  */
2696                 MBSTOWCS(wcs_buffer2, "SUNPRO_DEPENDENCIES");
2697                 if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2698                         continue;
2699                 }
2700 
2701                 macro = GETNAME(name, value - name);
2702                 maybe_append_prop(macro, macro_prop)->body.macro.exported =
2703                   true;
2704                 if ((value == NULL) || ((value + 1)[0] == (int) nul_char)) {
2705                         val = setvar_daemon(macro,
2706                                             (Name) NULL,
2707                                             false, no_daemon, false, debug_level);
2708                 } else {
2709                         val = setvar_daemon(macro,
2710                                             GETNAME(value + 1, FIND_LENGTH),
2711                                             false, no_daemon, false, debug_level);
2712                 }
2713                 val->body.macro.read_only = read_only_saved;
2714                 if (alloced_tmp_wcs_buffer) {
2715                         retmem(tmp_wcs_buffer);
2716                         alloced_tmp_wcs_buffer = false;
2717                 }
2718         }
2719         reading_environment = false;
2720 }
2721 
2722 /*
2723  *      read_makefile(makefile, complain, must_exist, report_file)
2724  *
2725  *      Read one makefile and check the result
2726  *
2727  *      Return value:
2728  *                              false is the read failed
2729  *
2730  *      Parameters:
2731  *              makefile        The file to read
2732  *              complain        Passed thru to read_simple_file()
2733  *              must_exist      Passed thru to read_simple_file()
2734  *              report_file     Passed thru to read_simple_file()
2735  *
2736  *      Global variables used:
2737  *              makefile_type   Set to indicate we are reading main file
2738  *              recursion_level Initialized
2739  */
2740 static Boolean
2741 read_makefile(register Name makefile, Boolean complain, Boolean must_exist, Boolean report_file)
2742 {
2743         Boolean                 b;
2744         
2745         makefile_type = reading_makefile;
2746         recursion_level = 0;
2747         reading_dependencies = true;
2748         b = read_simple_file(makefile, true, true, complain,
2749                              must_exist, report_file, false);
2750         reading_dependencies = false;
2751         return b;
2752 }
2753 
2754 /*
2755  *      make_targets(argc, argv, parallel_flag)
2756  *
2757  *      Call doname on the specified targets
2758  *
2759  *      Parameters:
2760  *              argc            You know what this is
2761  *              argv            You know what this is
2762  *              parallel_flag   True if building in parallel
2763  *
2764  *      Global variables used:
2765  *              build_failed_seen Used to generated message after failed -k
2766  *              commands_done   Used to generate message "Up to date"
2767  *              default_target_to_build First proper target in makefile
2768  *              init            The Name ".INIT", use to run command
2769  *              parallel        Global parallel building flag
2770  *              quest           make -q, suppresses messages
2771  *              recursion_level Initialized, used for tracing
2772  *              report_dependencies make -P, regroves whole process
2773  */
2774 static void
2775 make_targets(int argc, char **argv, Boolean parallel_flag)
2776 {
2777         int                     i;
2778         char                    *cp;
2779         Doname                  result;
2780         register Boolean        target_to_make_found = false;
2781 
2782         (void) doname(init, true, true);
2783         recursion_level = 1;
2784         parallel = parallel_flag;
2785 /*
2786  *      make remaining args
2787  */
2788 /*
2789         if ((report_dependencies_level == 0) && parallel) {
2790  */
2791         if (parallel) {
2792                 /*
2793                  * If building targets in parallel, start all of the
2794                  * remaining args to build in parallel.
2795                  */
2796                 for (i = 1; i < argc; i++) {
2797                         if ((cp = argv[i]) != NULL) {
2798                                 commands_done = false;
2799                                 if ((cp[0] == (int) period_char) &&
2800                                     (cp[1] == (int) slash_char)) {
2801                                         cp += 2;
2802                                 }
2803                                  if((cp[0] == (int) ' ') &&
2804                                     (cp[1] == (int) '-') &&
2805                                     (cp[2] == (int) ' ') &&
2806                                     (cp[3] == (int) '-')) {
2807                                     argv[i] = NULL;
2808                                         continue;
2809                                 }
2810                                 MBSTOWCS(wcs_buffer, cp);
2811                                 //default_target_to_build = GETNAME(wcs_buffer,
2812                                 //                                FIND_LENGTH);
2813                                 default_target_to_build = normalize_name(wcs_buffer,
2814                                                                   wcslen(wcs_buffer));
2815                                 if (default_target_to_build == wait_name) {
2816                                         if (parallel_process_cnt > 0) {
2817                                                 finish_running();
2818                                         }
2819                                         continue;
2820                                 }
2821                                 top_level_target = get_wstring(default_target_to_build->string_mb);
2822                                 /*
2823                                  * If we can't execute the current target in
2824                                  * parallel, hold off the target processing
2825                                  * to preserve the order of the targets as they appeared
2826                                  * in command line.
2827                                  */
2828                                 if (!parallel_ok(default_target_to_build, false)
2829                                                 && parallel_process_cnt > 0) {
2830                                         finish_running();
2831                                 }
2832                                 result = doname_check(default_target_to_build,
2833                                                       true,
2834                                                       false,
2835                                                       false);
2836                                 gather_recursive_deps();
2837                                 if (/* !commands_done && */
2838                                     (result == build_ok) &&
2839                                     !quest &&
2840                                     (report_dependencies_level == 0) /*  &&
2841                                     (exists(default_target_to_build) > file_doesnt_exist)  */) {
2842                                         if (posix) {
2843                                                 if (!commands_done) {
2844                                                         (void) printf(gettext("`%s' is updated.\n"),
2845                                                                       default_target_to_build->string_mb);
2846                                                 } else {
2847                                                         if (no_action_was_taken) {
2848                                                                 (void) printf(gettext("`%s': no action was taken.\n"),
2849                                                                               default_target_to_build->string_mb);
2850                                                         }
2851                                                 }
2852                                         } else {
2853                                                 default_target_to_build->stat.time = file_no_time;
2854                                                 if (!commands_done &&
2855                                                     (exists(default_target_to_build) > file_doesnt_exist)) {
2856                                                         (void) printf(gettext("`%s' is up to date.\n"),
2857                                                                       default_target_to_build->string_mb);
2858                                                 }
2859                                         }
2860                                 }
2861                         }
2862                 }
2863                 /* Now wait for all of the targets to finish running */
2864                 finish_running();
2865                 //              setjmp(jmpbuffer);
2866                 
2867         }
2868         for (i = 1; i < argc; i++) {
2869                 if ((cp = argv[i]) != NULL) {
2870                         target_to_make_found = true;
2871                         if ((cp[0] == (int) period_char) &&
2872                             (cp[1] == (int) slash_char)) {
2873                                 cp += 2;
2874                         }
2875                                  if((cp[0] == (int) ' ') &&
2876                                     (cp[1] == (int) '-') &&
2877                                     (cp[2] == (int) ' ') &&
2878                                     (cp[3] == (int) '-')) {
2879                                     argv[i] = NULL;
2880                                         continue;
2881                                 }
2882                         MBSTOWCS(wcs_buffer, cp);
2883                         default_target_to_build = normalize_name(wcs_buffer, wcslen(wcs_buffer));
2884                         top_level_target = get_wstring(default_target_to_build->string_mb);
2885                         report_recursion(default_target_to_build);
2886                         commands_done = false;
2887                         if (parallel) {
2888                                 result = (Doname) default_target_to_build->state;
2889                         } else {
2890                                 result = doname_check(default_target_to_build,
2891                                                       true,
2892                                                       false,
2893                                                       false);
2894                         }
2895                         gather_recursive_deps();
2896                         if (build_failed_seen) {
2897                                 build_failed_ever_seen = true;
2898                                 warning(gettext("Target `%s' not remade because of errors"),
2899                                         default_target_to_build->string_mb);
2900                         }
2901                         build_failed_seen = false;
2902                         if (report_dependencies_level > 0) {
2903                                 print_dependencies(default_target_to_build,
2904                                                    get_prop(default_target_to_build->prop,
2905                                                             line_prop));
2906                         }
2907                         default_target_to_build->stat.time =
2908                           file_no_time;
2909                         if (default_target_to_build->colon_splits > 0) {
2910                                 default_target_to_build->state =
2911                                   build_dont_know;
2912                         }
2913                         if (!parallel &&
2914                             /* !commands_done && */
2915                             (result == build_ok) &&
2916                             !quest &&
2917                             (report_dependencies_level == 0) /*  &&
2918                             (exists(default_target_to_build) > file_doesnt_exist)  */) {
2919                                 if (posix) {
2920                                         if (!commands_done) {
2921                                                 (void) printf(gettext("`%s' is updated.\n"),
2922                                                               default_target_to_build->string_mb);
2923                                         } else {
2924                                                 if (no_action_was_taken) {
2925                                                         (void) printf(gettext("`%s': no action was taken.\n"),
2926                                                                       default_target_to_build->string_mb);
2927                                                 }
2928                                         }
2929                                 } else {
2930                                         if (!commands_done &&
2931                                             (exists(default_target_to_build) > file_doesnt_exist)) {
2932                                                 (void) printf(gettext("`%s' is up to date.\n"),
2933                                                               default_target_to_build->string_mb);
2934                                         }
2935                                 }
2936                         }
2937                 }
2938         }
2939 
2940 /*
2941  *      If no file arguments have been encountered,
2942  *      make the first name encountered that doesnt start with a dot
2943  */
2944         if (!target_to_make_found) {
2945                 if (default_target_to_build == NULL) {
2946                         fatal(gettext("No arguments to build"));
2947                 }
2948                 commands_done = false;
2949                 top_level_target = get_wstring(default_target_to_build->string_mb);
2950                 report_recursion(default_target_to_build);
2951 
2952 
2953                 if (getenv("SPRO_EXPAND_ERRORS")){
2954                         (void) printf("::(%s)\n",
2955                                       default_target_to_build->string_mb);
2956                 }
2957 
2958 
2959                 result = doname_parallel(default_target_to_build, true, false);
2960                 gather_recursive_deps();
2961                 if (build_failed_seen) {
2962                         build_failed_ever_seen = true;
2963                         warning(gettext("Target `%s' not remade because of errors"),
2964                                 default_target_to_build->string_mb);
2965                 }
2966                 build_failed_seen = false;
2967                 if (report_dependencies_level > 0) {
2968                         print_dependencies(default_target_to_build,
2969                                            get_prop(default_target_to_build->
2970                                                     prop,
2971                                                     line_prop));
2972                 }
2973                 default_target_to_build->stat.time = file_no_time;
2974                 if (default_target_to_build->colon_splits > 0) {
2975                         default_target_to_build->state = build_dont_know;
2976                 }
2977                 if (/* !commands_done && */
2978                     (result == build_ok) &&
2979                     !quest &&
2980                     (report_dependencies_level == 0) /*  &&
2981                     (exists(default_target_to_build) > file_doesnt_exist)  */) {
2982                         if (posix) {
2983                                 if (!commands_done) {
2984                                         (void) printf(gettext("`%s' is updated.\n"),
2985                                                       default_target_to_build->string_mb);
2986                                 } else {
2987                                         if (no_action_was_taken) {
2988                                                 (void) printf(gettext("`%s': no action was taken.\n"),
2989                                                               default_target_to_build->string_mb);
2990                                         }
2991                                 }
2992                         } else {
2993                                 if (!commands_done &&
2994                                     (exists(default_target_to_build) > file_doesnt_exist)) {
2995                                         (void) printf(gettext("`%s' is up to date.\n"),
2996                                                       default_target_to_build->string_mb);
2997                                 }
2998                         }
2999                 }
3000         }
3001 }
3002 
3003 /*
3004  *      report_recursion(target)
3005  *
3006  *      If this is a recursive make and the parent make has KEEP_STATE on
3007  *      this routine reports the dependency to the parent make
3008  *
3009  *      Parameters:
3010  *              target          Target to report
3011  *
3012  *      Global variables used:
3013  *              makefiles_used          List of makefiles read
3014  *              recursive_name          The Name ".RECURSIVE", printed
3015  *              report_dependency       dwight
3016  */
3017 static void
3018 report_recursion(register Name target)
3019 {
3020         register FILE           *report_file = get_report_file();
3021 
3022         if ((report_file == NULL) || (report_file == (FILE*)-1)) {
3023                 return;
3024         }
3025         if (primary_makefile == NULL) {
3026                 /*
3027                  * This can happen when there is no makefile and
3028                  * only implicit rules are being used.
3029                  */
3030                 return;
3031         }
3032         (void) fprintf(report_file,
3033                        "%s: %s ",
3034                        get_target_being_reported_for(),
3035                        recursive_name->string_mb);
3036         report_dependency(get_current_path());
3037         report_dependency(target->string_mb);
3038         report_dependency(primary_makefile->string_mb);
3039         (void) fprintf(report_file, "\n");
3040 }
3041 
3042 /* Next function "append_or_replace_macro_in_dyn_array" must be in "misc.cc". */
3043 /* NIKMOL */
3044 extern void
3045 append_or_replace_macro_in_dyn_array(ASCII_Dyn_Array *Ar, char *macro)
3046 {
3047         register char   *cp0;   /* work pointer in macro */
3048         register char   *cp1;   /* work pointer in array */
3049         register char   *cp2;   /* work pointer in array */
3050         register char   *cp3;   /* work pointer in array */
3051         register char   *name;  /* macro name */
3052         register char   *value; /* macro value */
3053         register int    len_array;
3054         register int    len_macro;
3055 
3056         char * esc_value = NULL;
3057         int esc_len;
3058 
3059         if (!(len_macro = strlen(macro))) return;
3060         name = macro;
3061         while (isspace(*(name))) {
3062                 name++;
3063         }
3064         if (!(value = strchr(name, (int) equal_char))) {
3065                 /* no '=' in macro */
3066                 goto ERROR_MACRO;
3067         }
3068         cp0 = value;
3069         value++;
3070         while (isspace(*(value))) {
3071                 value++;
3072         }
3073         while (isspace(*(cp0-1))) {
3074                 cp0--;
3075         }
3076         if (cp0 <= name) goto ERROR_MACRO; /* no name */
3077         if (!(Ar->size)) goto ALLOC_ARRAY;
3078         cp1 = Ar->start;
3079 
3080 LOOK_FOR_NAME:
3081         if (!(cp1 = strchr(cp1, name[0]))) goto APPEND_MACRO;
3082         if (!(cp2 = strchr(cp1, (int) equal_char))) goto APPEND_MACRO;
3083         if (strncmp(cp1, name, (size_t)(cp0-name))) {
3084                 /* another name */
3085                 cp1++;
3086                 goto LOOK_FOR_NAME;
3087         }
3088         if (cp1 != Ar->start) {
3089                 if (!isspace(*(cp1-1))) {
3090                         /* another name */
3091                         cp1++;
3092                         goto LOOK_FOR_NAME;
3093                 }
3094         }
3095         for (cp3 = cp1 + (cp0-name); cp3 < cp2; cp3++) {
3096                 if (isspace(*cp3)) continue;
3097                 /* else: another name */
3098                 cp1++;
3099                 goto LOOK_FOR_NAME;
3100         }
3101         /* Look for the next macro name in array */
3102         cp3 = cp2+1;
3103         if (*cp3 != (int) doublequote_char) {
3104                 /* internal error */
3105                 goto ERROR_MACRO;
3106         }
3107         if (!(cp3 = strchr(cp3+1, (int) doublequote_char))) {
3108                 /* internal error */
3109                 goto ERROR_MACRO;
3110         }
3111         cp3++;
3112         while (isspace(*cp3)) {
3113                 cp3++;
3114         }
3115         
3116         cp2 = cp1;  /* remove old macro */
3117         if ((*cp3) && (cp3 < Ar->start + Ar->size)) {
3118                 for (; cp3 < Ar->start + Ar->size; cp3++) {
3119                         *cp2++ = *cp3;
3120                 }
3121         } 
3122         for (; cp2 < Ar->start + Ar->size; cp2++) {
3123                 *cp2 = 0;
3124         }
3125         if (*cp1) {
3126                 /* check next name */
3127                 goto LOOK_FOR_NAME;
3128         }
3129         goto APPEND_MACRO;
3130 
3131 ALLOC_ARRAY:
3132         if (Ar->size) {
3133                 cp1 = Ar->start;
3134         } else {
3135                 cp1 = 0;
3136         }
3137         Ar->size += 128;
3138         Ar->start = getmem(Ar->size);
3139         for (len_array=0; len_array < Ar->size; len_array++) {
3140                 Ar->start[len_array] = 0;
3141         }
3142         if (cp1) {
3143                 strcpy(Ar->start, cp1);
3144                 retmem((wchar_t *) cp1);
3145         }
3146 
3147 APPEND_MACRO:
3148         len_array = strlen(Ar->start);
3149         esc_value = (char*)malloc(strlen(value)*2 + 1);
3150         quote_str(value, esc_value);
3151         esc_len = strlen(esc_value) - strlen(value);
3152         if (len_array + len_macro + esc_len + 5 >= Ar->size) goto  ALLOC_ARRAY;
3153         strcat(Ar->start, " ");
3154         strncat(Ar->start, name, cp0-name);
3155         strcat(Ar->start, "=");
3156         strncat(Ar->start, esc_value, strlen(esc_value));
3157         free(esc_value);
3158         return;
3159 ERROR_MACRO:    
3160         /* Macro without '=' or with invalid left/right part */
3161         return;
3162 }
3163 
3164 static void
3165 report_dir_enter_leave(Boolean entering)
3166 {
3167         char    rcwd[MAXPATHLEN];
3168 static  char *  mlev = NULL;
3169         char *  make_level_str = NULL;
3170         int     make_level_val = 0;
3171 
3172         make_level_str = getenv("MAKELEVEL");
3173         if(make_level_str) {
3174                 make_level_val = atoi(make_level_str);
3175         }
3176         if(mlev == NULL) {
3177                 mlev = (char*) malloc(MAXPATHLEN);
3178         }
3179         if(entering) {
3180                 sprintf(mlev, "MAKELEVEL=%d", make_level_val + 1);
3181         } else {
3182                 make_level_val--;
3183                 sprintf(mlev, "MAKELEVEL=%d", make_level_val);
3184         }
3185         putenv(mlev);
3186 
3187         if(report_cwd) {
3188                 if(make_level_val <= 0) {
3189                         if(entering) {
3190                                 sprintf(rcwd,
3191                                     gettext("%s: Entering directory `%s'\n"),
3192                                     getprogname(),
3193                                     get_current_path());
3194                         } else {
3195                                 sprintf(rcwd,
3196                                     gettext("%s: Leaving directory `%s'\n"),
3197                                     getprogname(),
3198                                     get_current_path());
3199                         }
3200                 } else {
3201                         if(entering) {
3202                                 sprintf(rcwd,
3203                                     gettext("%s[%d]: Entering directory `%s'\n"),
3204                                     getprogname(),
3205                                     make_level_val, get_current_path());
3206                         } else {
3207                                 sprintf(rcwd,
3208                                     gettext("%s[%d]: Leaving directory `%s'\n"),
3209                                     getprogname(),
3210                                     make_level_val, get_current_path());
3211                         }
3212                 }
3213                 printf("%s", rcwd);
3214         }
3215 }