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