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