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