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