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 2005 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      misc.cc
  28  *
  29  *      This file contains various unclassified routines. Some main groups:
  30  *              getname
  31  *              Memory allocation
  32  *              String handling
  33  *              Property handling
  34  *              Error message handling
  35  *              Make internal state dumping
  36  *              main routine support
  37  */
  38 
  39 /*
  40  * Included files
  41  */
  42 #include <errno.h>
  43 #include <mk/defs.h>
  44 #include <mksh/macro.h>           /* SETVAR() */
  45 #include <mksh/misc.h>            /* enable_interrupt() */
  46 #include <stdarg.h>               /* va_list, va_start(), va_end() */
  47 #include <vroot/report.h> /* SUNPRO_DEPENDENCIES */
  48 
  49 #if defined(HP_UX) || defined(linux)
  50 #include <unistd.h>
  51 #endif
  52 
  53 #ifdef TEAMWARE_MAKE_CMN
  54 #define MAXJOBS_ADJUST_RFE4694000
  55 
  56 #ifdef MAXJOBS_ADJUST_RFE4694000
  57 extern void job_adjust_fini();
  58 #endif /* MAXJOBS_ADJUST_RFE4694000 */
  59 #endif /* TEAMWARE_MAKE_CMN */
  60 
  61 #if defined(linux)
  62 #include <time.h>         /* localtime() */
  63 #endif
  64 
  65 /*
  66  * Defined macros
  67  */
  68 
  69 /*
  70  * typedefs & structs
  71  */
  72 
  73 /*
  74  * Static variables
  75  */
  76 
  77 /*
  78  * File table of contents
  79  */
  80 static  void            print_rule(register Name target);
  81 static  void            print_target_n_deps(register Name target);
  82 
  83 /*****************************************
  84  *
  85  *      getname
  86  */
  87 
  88 /*****************************************
  89  *
  90  *      Memory allocation
  91  */
  92 
  93 /*
  94  *      free_chain()
  95  *
  96  *      frees a chain of Name_vector's
  97  *
  98  *      Parameters:
  99  *              ptr             Pointer to the first element in the chain
 100  *                              to be freed.
 101  *
 102  *      Global variables used:
 103  */
 104 void 
 105 free_chain(Name_vector ptr)
 106 {
 107         if (ptr != NULL) {
 108                 if (ptr->next != NULL) {
 109                         free_chain(ptr->next);
 110                 }
 111                 free((char *) ptr);
 112         }
 113 }
 114 
 115 /*****************************************
 116  *
 117  *      String manipulation
 118  */
 119 
 120 /*****************************************
 121  *
 122  *      Nameblock property handling
 123  */
 124 
 125 /*****************************************
 126  *
 127  *      Error message handling
 128  */
 129 
 130 /*
 131  *      fatal(format, args...)
 132  *
 133  *      Print a message and die
 134  *
 135  *      Parameters:
 136  *              format          printf type format string
 137  *              args            Arguments to match the format
 138  *
 139  *      Global variables used:
 140  *              fatal_in_progress Indicates if this is a recursive call
 141  *              parallel_process_cnt Do we need to wait for anything?
 142  *              report_pwd      Should we report the current path?
 143  */
 144 /*VARARGS*/
 145 void
 146 fatal(char * message, ...)
 147 {
 148         va_list args;
 149 
 150         va_start(args, message);
 151         (void) fflush(stdout);
 152 #ifdef DISTRIBUTED
 153         (void) fprintf(stderr, catgets(catd, 1, 262, "dmake: Fatal error: "));
 154 #else
 155         (void) fprintf(stderr, catgets(catd, 1, 263, "make: Fatal error: "));
 156 #endif
 157         (void) vfprintf(stderr, message, args);
 158         (void) fprintf(stderr, "\n");
 159         va_end(args);
 160         if (report_pwd) {
 161                 (void) fprintf(stderr,
 162                                catgets(catd, 1, 156, "Current working directory %s\n"),
 163                                get_current_path());
 164         }
 165         (void) fflush(stderr);
 166         if (fatal_in_progress) {
 167 #if defined(SUN5_0) || defined(HP_UX) || defined(linux)
 168                 exit_status = 1;
 169 #endif
 170                 exit(1);
 171         }
 172         fatal_in_progress = true;
 173 #ifdef TEAMWARE_MAKE_CMN
 174         /* Let all parallel children finish */
 175         if ((dmake_mode_type == parallel_mode) &&
 176             (parallel_process_cnt > 0)) {
 177                 (void) fprintf(stderr,
 178                                catgets(catd, 1, 157, "Waiting for %d %s to finish\n"),
 179                                parallel_process_cnt,
 180                                parallel_process_cnt == 1 ?
 181                                catgets(catd, 1, 158, "job") : catgets(catd, 1, 159, "jobs"));
 182                 (void) fflush(stderr);
 183         }
 184 
 185         while (parallel_process_cnt > 0) {
 186 #ifdef DISTRIBUTED
 187                 if (dmake_mode_type == distributed_mode) {
 188                         (void) await_dist(false);
 189                 } else {
 190                         await_parallel(true);
 191                 }
 192 #else
 193                 await_parallel(true);
 194 #endif
 195                 finish_children(false);
 196         }
 197 #endif
 198 
 199 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
 200         job_adjust_fini();
 201 #endif
 202 
 203 #if defined(SUN5_0) || defined(HP_UX) || defined(linux)
 204         exit_status = 1;
 205 #endif
 206         exit(1);
 207 }
 208 
 209 /*
 210  *      warning(format, args...)
 211  *
 212  *      Print a message and continue.
 213  *
 214  *      Parameters:
 215  *              format          printf type format string
 216  *              args            Arguments to match the format
 217  *
 218  *      Global variables used:
 219  *              report_pwd      Should we report the current path?
 220  */
 221 /*VARARGS*/
 222 void
 223 warning(char * message, ...)
 224 {
 225         va_list args;
 226 
 227         va_start(args, message);
 228         (void) fflush(stdout);
 229 #ifdef DISTRIBUTED
 230         (void) fprintf(stderr, catgets(catd, 1, 264, "dmake: Warning: "));
 231 #else
 232         (void) fprintf(stderr, catgets(catd, 1, 265, "make: Warning: "));
 233 #endif
 234         (void) vfprintf(stderr, message, args);
 235         (void) fprintf(stderr, "\n");
 236         va_end(args);
 237         if (report_pwd) {
 238                 (void) fprintf(stderr,
 239                                catgets(catd, 1, 161, "Current working directory %s\n"),
 240                                get_current_path());
 241         }
 242         (void) fflush(stderr);
 243 }
 244 
 245 /*
 246  *      time_to_string(time)
 247  *
 248  *      Take a numeric time value and produce
 249  *      a proper string representation.
 250  *
 251  *      Return value:
 252  *                              The string representation of the time
 253  *
 254  *      Parameters:
 255  *              time            The time we need to translate
 256  *
 257  *      Global variables used:
 258  */
 259 char *
 260 time_to_string(const timestruc_t &time)
 261 {
 262         struct tm               *tm;
 263         char                    buf[128];
 264 
 265         if (time == file_doesnt_exist) {
 266                 return catgets(catd, 1, 163, "File does not exist");
 267         }
 268         if (time == file_max_time) {
 269                 return catgets(catd, 1, 164, "Younger than any file");
 270         }
 271         tm = localtime(&time.tv_sec);
 272         strftime(buf, sizeof (buf), NOCATGETS("%c %Z"), tm);
 273         buf[127] = (int) nul_char;
 274         return strdup(buf);
 275 }
 276 
 277 /*
 278  *      get_current_path()
 279  *
 280  *      Stuff current_path with the current path if it isnt there already.
 281  *
 282  *      Parameters:
 283  *
 284  *      Global variables used:
 285  */
 286 char *
 287 get_current_path(void)
 288 {
 289         char                    pwd[(MAXPATHLEN * MB_LEN_MAX)];
 290         static char             *current_path;
 291 
 292         if (current_path == NULL) {
 293 #if defined(SUN5_0) || defined(HP_UX) || defined(linux)
 294                 getcwd(pwd, sizeof(pwd));
 295 #else
 296                 (void) getwd(pwd);
 297 #endif
 298                 if (pwd[0] == (int) nul_char) {
 299                         pwd[0] = (int) slash_char;
 300                         pwd[1] = (int) nul_char;
 301 #ifdef DISTRIBUTED
 302                         current_path = strdup(pwd);
 303                 } else if (IS_EQUALN(pwd, NOCATGETS("/tmp_mnt"), 8)) {
 304                         current_path = strdup(pwd + 8);
 305                 } else {
 306                         current_path = strdup(pwd);
 307                 }
 308 #else
 309                 }
 310                 current_path = strdup(pwd);
 311 #endif
 312         }
 313         return current_path;
 314 }
 315 
 316 /*****************************************
 317  *
 318  *      Make internal state dumping
 319  *
 320  *      This is a set  of routines for dumping the internal make state
 321  *      Used for the -p option
 322  */
 323 
 324 /*
 325  *      dump_make_state()
 326  *
 327  *      Dump make's internal state to stdout
 328  *
 329  *      Parameters:
 330  *
 331  *      Global variables used:
 332  *              svr4                    Was ".SVR4" seen in makefile?
 333  *              svr4_name               The Name ".SVR4", printed
 334  *              posix                   Was ".POSIX" seen in makefile?
 335  *              posix_name              The Name ".POSIX", printed
 336  *              default_rule            Points to the .DEFAULT rule
 337  *              default_rule_name       The Name ".DEFAULT", printed
 338  *              default_target_to_build The first target to print
 339  *              dot_keep_state          The Name ".KEEP_STATE", printed
 340  *              dot_keep_state_file     The Name ".KEEP_STATE_FILE", printed
 341  *              hashtab                 The make hash table for Name blocks
 342  *              ignore_errors           Was ".IGNORE" seen in makefile?
 343  *              ignore_name             The Name ".IGNORE", printed
 344  *              keep_state              Was ".KEEP_STATE" seen in makefile?
 345  *              percent_list            The list of % rules
 346  *              precious                The Name ".PRECIOUS", printed
 347  *              sccs_get_name           The Name ".SCCS_GET", printed
 348  *              sccs_get_posix_name     The Name ".SCCS_GET_POSIX", printed
 349  *              get_name                The Name ".GET", printed
 350  *              get_posix_name          The Name ".GET_POSIX", printed
 351  *              sccs_get_rule           Points to the ".SCCS_GET" rule
 352  *              silent                  Was ".SILENT" seen in makefile?
 353  *              silent_name             The Name ".SILENT", printed
 354  *              suffixes                The suffix list from ".SUFFIXES"
 355  *              suffixes_name           The Name ".SUFFIX", printed
 356  */
 357 void
 358 dump_make_state(void)
 359 {
 360         Name_set::iterator      p, e;
 361         register Property       prop;
 362         register Dependency     dep;
 363         register Cmd_line       rule;
 364         Percent                 percent, percent_depe;
 365 
 366         /* Default target */
 367         if (default_target_to_build != NULL) {
 368                 print_rule(default_target_to_build);
 369         }
 370         (void) printf("\n");
 371 
 372         /* .POSIX */
 373         if (posix) {
 374                 (void) printf("%s:\n", posix_name->string_mb);
 375         }
 376 
 377         /* .DEFAULT */
 378         if (default_rule != NULL) {
 379                 (void) printf("%s:\n", default_rule_name->string_mb);
 380                 for (rule = default_rule; rule != NULL; rule = rule->next) {
 381                         (void) printf("\t%s\n", rule->command_line->string_mb);
 382                 }
 383         }
 384 
 385         /* .IGNORE */
 386         if (ignore_errors) {
 387                 (void) printf("%s:\n", ignore_name->string_mb);
 388         }
 389 
 390         /* .KEEP_STATE: */
 391         if (keep_state) {
 392                 (void) printf("%s:\n\n", dot_keep_state->string_mb);
 393         }
 394 
 395         /* .PRECIOUS */
 396         (void) printf("%s:", precious->string_mb);
 397         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 398                         if ((p->stat.is_precious) || (all_precious)) {
 399                                 (void) printf(" %s", p->string_mb);
 400                         }
 401         }
 402         (void) printf("\n");
 403 
 404         /* .SCCS_GET */
 405         if (sccs_get_rule != NULL) {
 406                 (void) printf("%s:\n", sccs_get_name->string_mb);
 407                 for (rule = sccs_get_rule; rule != NULL; rule = rule->next) {
 408                         (void) printf("\t%s\n", rule->command_line->string_mb);
 409                 }
 410         }
 411 
 412         /* .SILENT */
 413         if (silent) {
 414                 (void) printf("%s:\n", silent_name->string_mb);
 415         }
 416 
 417         /* .SUFFIXES: */
 418         (void) printf("%s:", suffixes_name->string_mb);
 419         for (dep = suffixes; dep != NULL; dep = dep->next) {
 420                 (void) printf(" %s", dep->name->string_mb);
 421                 build_suffix_list(dep->name);
 422         }
 423         (void) printf("\n\n");
 424 
 425         /* % rules */
 426         for (percent = percent_list;
 427              percent != NULL;
 428              percent = percent->next) {
 429                 (void) printf("%s:",
 430                               percent->name->string_mb);
 431                 
 432                 for (percent_depe = percent->dependencies;
 433                      percent_depe != NULL;
 434                      percent_depe = percent_depe->next) {
 435                         (void) printf(" %s", percent_depe->name->string_mb);
 436                 }
 437                 
 438                 (void) printf("\n");
 439 
 440                 for (rule = percent->command_template;
 441                      rule != NULL;
 442                      rule = rule->next) {
 443                         (void) printf("\t%s\n", rule->command_line->string_mb);
 444                 }
 445         }
 446 
 447         /* Suffix rules */
 448         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 449                         Wstring wcb(p);
 450                         if (wcb.get_string()[0] == (int) period_char) {
 451                                 print_rule(p);
 452                         }
 453         }
 454 
 455         /* Macro assignments */
 456         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 457                         if (((prop = get_prop(p->prop, macro_prop)) != NULL) &&
 458                             (prop->body.macro.value != NULL)) {
 459                                 (void) printf("%s", p->string_mb);
 460                                 print_value(prop->body.macro.value,
 461                                             (Daemon) prop->body.macro.daemon);
 462                         }
 463         }
 464         (void) printf("\n");
 465 
 466         /* Conditional macro assignments */
 467         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 468                         for (prop = get_prop(p->prop, conditional_prop);
 469                              prop != NULL;
 470                              prop = get_prop(prop->next, conditional_prop)) {
 471                                 (void) printf("%s := %s",
 472                                               p->string_mb,
 473                                               prop->body.conditional.name->
 474                                               string_mb);
 475                                 if (prop->body.conditional.append) {
 476                                         printf(" +");
 477                                 }
 478                                 else {
 479                                         printf(" ");
 480                                 }
 481                                 print_value(prop->body.conditional.value,
 482                                             no_daemon);
 483                         }
 484         }
 485         (void) printf("\n");
 486 
 487         /* All other dependencies */
 488         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 489                         if (p->colons != no_colon) {
 490                                 print_rule(p);
 491                         }
 492         }
 493         (void) printf("\n");
 494 }
 495 
 496 /*
 497  *      print_rule(target)
 498  *
 499  *      Print the rule for one target
 500  *
 501  *      Parameters:
 502  *              target          Target we print rule for
 503  *
 504  *      Global variables used:
 505  */
 506 static void
 507 print_rule(register Name target)
 508 {
 509         register Cmd_line       rule;
 510         register Property       line;
 511         register Dependency     dependency;
 512 
 513         if (target->dependency_printed ||
 514             ((line = get_prop(target->prop, line_prop)) == NULL) ||
 515             ((line->body.line.command_template == NULL) &&
 516              (line->body.line.dependencies == NULL))) {
 517                 return;
 518         }
 519         target->dependency_printed = true;
 520 
 521         (void) printf("%s:", target->string_mb);
 522 
 523         for (dependency = line->body.line.dependencies;
 524              dependency != NULL;
 525              dependency = dependency->next) {
 526                 (void) printf(" %s", dependency->name->string_mb);
 527         }
 528 
 529         (void) printf("\n");
 530 
 531         for (rule = line->body.line.command_template;
 532              rule != NULL;
 533              rule = rule->next) {
 534                 (void) printf("\t%s\n", rule->command_line->string_mb);
 535         }
 536 }
 537 
 538 void
 539 dump_target_list(void)
 540 {
 541         Name_set::iterator      p, e;
 542         Wstring str;
 543 
 544         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 545                         str.init(p);
 546                         wchar_t * wcb = str.get_string();
 547                         if ((p->colons != no_colon) &&
 548                             ((wcb[0] != (int) period_char) ||
 549                              ((wcb[0] == (int) period_char) &&
 550                               (wschr(wcb, (int) slash_char))))) {
 551                                 print_target_n_deps(p);
 552                         }
 553         }
 554 }
 555 
 556 static void
 557 print_target_n_deps(register Name target)
 558 {
 559         register Cmd_line       rule;
 560         register Property       line;
 561         register Dependency     dependency;
 562 
 563         if (target->dependency_printed) {
 564                 return;
 565         }
 566         target->dependency_printed = true;
 567 
 568         (void) printf("%s\n", target->string_mb);
 569 
 570         if ((line = get_prop(target->prop, line_prop)) == NULL) {
 571                 return;
 572         }
 573         for (dependency = line->body.line.dependencies;
 574              dependency != NULL;
 575              dependency = dependency->next) {
 576                 if (!dependency->automatic) {
 577                         print_target_n_deps(dependency->name);
 578                 }
 579         }
 580 }
 581 
 582 /*****************************************
 583  *
 584  *      main() support
 585  */
 586 
 587 /*
 588  *      load_cached_names()
 589  *
 590  *      Load the vector of cached names
 591  *
 592  *      Parameters:
 593  *
 594  *      Global variables used:
 595  *              Many many pointers to Name blocks.
 596  */
 597 void
 598 load_cached_names(void)
 599 {
 600         char            *cp;
 601         Name            dollar;
 602 
 603         /* Load the cached_names struct */
 604         MBSTOWCS(wcs_buffer, NOCATGETS(".BUILT_LAST_MAKE_RUN"));
 605         built_last_make_run = GETNAME(wcs_buffer, FIND_LENGTH);
 606         MBSTOWCS(wcs_buffer, NOCATGETS("@"));
 607         c_at = GETNAME(wcs_buffer, FIND_LENGTH);
 608         MBSTOWCS(wcs_buffer, NOCATGETS(" *conditionals* "));
 609         conditionals = GETNAME(wcs_buffer, FIND_LENGTH);
 610         /*
 611          * A version of make was released with NSE 1.0 that used
 612          * VERSION-1.1 but this version is identical to VERSION-1.0.
 613          * The version mismatch code makes a special case for this
 614          * situation.  If the version number is changed from 1.0
 615          * it should go to 1.2.
 616          */
 617         MBSTOWCS(wcs_buffer, NOCATGETS("VERSION-1.0"));
 618         current_make_version = GETNAME(wcs_buffer, FIND_LENGTH);
 619         MBSTOWCS(wcs_buffer, NOCATGETS(".SVR4"));
 620         svr4_name = GETNAME(wcs_buffer, FIND_LENGTH);
 621         MBSTOWCS(wcs_buffer, NOCATGETS(".POSIX"));
 622         posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 623         MBSTOWCS(wcs_buffer, NOCATGETS(".DEFAULT"));
 624         default_rule_name = GETNAME(wcs_buffer, FIND_LENGTH);
 625 #ifdef NSE
 626         MBSTOWCS(wcs_buffer, NOCATGETS(".DERIVED_SRC"));
 627         derived_src= GETNAME(wcs_buffer, FIND_LENGTH);
 628 #endif
 629         MBSTOWCS(wcs_buffer, NOCATGETS("$"));
 630         dollar = GETNAME(wcs_buffer, FIND_LENGTH);
 631         MBSTOWCS(wcs_buffer, NOCATGETS(".DONE"));
 632         done = GETNAME(wcs_buffer, FIND_LENGTH);
 633         MBSTOWCS(wcs_buffer, NOCATGETS("."));
 634         dot = GETNAME(wcs_buffer, FIND_LENGTH);
 635         MBSTOWCS(wcs_buffer, NOCATGETS(".KEEP_STATE"));
 636         dot_keep_state = GETNAME(wcs_buffer, FIND_LENGTH);
 637         MBSTOWCS(wcs_buffer, NOCATGETS(".KEEP_STATE_FILE"));
 638         dot_keep_state_file = GETNAME(wcs_buffer, FIND_LENGTH);
 639         MBSTOWCS(wcs_buffer, NOCATGETS(""));
 640         empty_name = GETNAME(wcs_buffer, FIND_LENGTH);
 641         MBSTOWCS(wcs_buffer, NOCATGETS(" FORCE"));
 642         force = GETNAME(wcs_buffer, FIND_LENGTH);
 643         MBSTOWCS(wcs_buffer, NOCATGETS("HOST_ARCH"));
 644         host_arch = GETNAME(wcs_buffer, FIND_LENGTH);
 645         MBSTOWCS(wcs_buffer, NOCATGETS("HOST_MACH"));
 646         host_mach = GETNAME(wcs_buffer, FIND_LENGTH);
 647         MBSTOWCS(wcs_buffer, NOCATGETS(".IGNORE"));
 648         ignore_name = GETNAME(wcs_buffer, FIND_LENGTH);
 649         MBSTOWCS(wcs_buffer, NOCATGETS(".INIT"));
 650         init = GETNAME(wcs_buffer, FIND_LENGTH);
 651         MBSTOWCS(wcs_buffer, NOCATGETS(".LOCAL"));
 652         localhost_name = GETNAME(wcs_buffer, FIND_LENGTH);
 653         MBSTOWCS(wcs_buffer, NOCATGETS(".make.state"));
 654         make_state = GETNAME(wcs_buffer, FIND_LENGTH);
 655         MBSTOWCS(wcs_buffer, NOCATGETS("MAKEFLAGS"));
 656         makeflags = GETNAME(wcs_buffer, FIND_LENGTH);
 657         MBSTOWCS(wcs_buffer, NOCATGETS(".MAKE_VERSION"));
 658         make_version = GETNAME(wcs_buffer, FIND_LENGTH);
 659         MBSTOWCS(wcs_buffer, NOCATGETS(".NO_PARALLEL"));
 660         no_parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
 661         MBSTOWCS(wcs_buffer, NOCATGETS(".NOT_AUTO"));
 662         not_auto = GETNAME(wcs_buffer, FIND_LENGTH);
 663         MBSTOWCS(wcs_buffer, NOCATGETS(".PARALLEL"));
 664         parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
 665         MBSTOWCS(wcs_buffer, NOCATGETS("PATH"));
 666         path_name = GETNAME(wcs_buffer, FIND_LENGTH);
 667         MBSTOWCS(wcs_buffer, NOCATGETS("+"));
 668         plus = GETNAME(wcs_buffer, FIND_LENGTH);
 669         MBSTOWCS(wcs_buffer, NOCATGETS(".PRECIOUS"));
 670         precious = GETNAME(wcs_buffer, FIND_LENGTH);
 671         MBSTOWCS(wcs_buffer, NOCATGETS("?"));
 672         query = GETNAME(wcs_buffer, FIND_LENGTH);
 673         MBSTOWCS(wcs_buffer, NOCATGETS("^"));
 674         hat = GETNAME(wcs_buffer, FIND_LENGTH);
 675         MBSTOWCS(wcs_buffer, NOCATGETS(".RECURSIVE"));
 676         recursive_name = GETNAME(wcs_buffer, FIND_LENGTH);
 677         MBSTOWCS(wcs_buffer, NOCATGETS(".SCCS_GET"));
 678         sccs_get_name = GETNAME(wcs_buffer, FIND_LENGTH);
 679         MBSTOWCS(wcs_buffer, NOCATGETS(".SCCS_GET_POSIX"));
 680         sccs_get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 681         MBSTOWCS(wcs_buffer, NOCATGETS(".GET"));
 682         get_name = GETNAME(wcs_buffer, FIND_LENGTH);
 683         MBSTOWCS(wcs_buffer, NOCATGETS(".GET_POSIX"));
 684         get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 685         MBSTOWCS(wcs_buffer, NOCATGETS("SHELL"));
 686         shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
 687         MBSTOWCS(wcs_buffer, NOCATGETS(".SILENT"));
 688         silent_name = GETNAME(wcs_buffer, FIND_LENGTH);
 689         MBSTOWCS(wcs_buffer, NOCATGETS(".SUFFIXES"));
 690         suffixes_name = GETNAME(wcs_buffer, FIND_LENGTH);
 691         MBSTOWCS(wcs_buffer, SUNPRO_DEPENDENCIES);
 692         sunpro_dependencies = GETNAME(wcs_buffer, FIND_LENGTH);
 693         MBSTOWCS(wcs_buffer, NOCATGETS("TARGET_ARCH"));
 694         target_arch = GETNAME(wcs_buffer, FIND_LENGTH);
 695         MBSTOWCS(wcs_buffer, NOCATGETS("TARGET_MACH"));
 696         target_mach = GETNAME(wcs_buffer, FIND_LENGTH);
 697         MBSTOWCS(wcs_buffer, NOCATGETS("VIRTUAL_ROOT"));
 698         virtual_root = GETNAME(wcs_buffer, FIND_LENGTH);
 699         MBSTOWCS(wcs_buffer, NOCATGETS("VPATH"));
 700         vpath_name = GETNAME(wcs_buffer, FIND_LENGTH);
 701         MBSTOWCS(wcs_buffer, NOCATGETS(".WAIT"));
 702         wait_name = GETNAME(wcs_buffer, FIND_LENGTH);
 703 
 704         wait_name->state = build_ok;
 705 
 706         /* Mark special targets so that the reader treats them properly */
 707         svr4_name->special_reader = svr4_special;
 708         posix_name->special_reader = posix_special;
 709         built_last_make_run->special_reader = built_last_make_run_special;
 710         default_rule_name->special_reader = default_special;
 711 #ifdef NSE
 712         derived_src->special_reader= derived_src_special;
 713 #endif
 714         dot_keep_state->special_reader = keep_state_special;
 715         dot_keep_state_file->special_reader = keep_state_file_special;
 716         ignore_name->special_reader = ignore_special;
 717         make_version->special_reader = make_version_special;
 718         no_parallel_name->special_reader = no_parallel_special;
 719         parallel_name->special_reader = parallel_special;
 720         localhost_name->special_reader = localhost_special;
 721         precious->special_reader = precious_special;
 722         sccs_get_name->special_reader = sccs_get_special;
 723         sccs_get_posix_name->special_reader = sccs_get_posix_special;
 724         get_name->special_reader = get_special;
 725         get_posix_name->special_reader = get_posix_special;
 726         silent_name->special_reader = silent_special;
 727         suffixes_name->special_reader = suffixes_special;
 728 
 729         /* The value of $$ is $ */
 730         (void) SETVAR(dollar, dollar, false);
 731         dollar->dollar = false;
 732 
 733         /* Set the value of $(SHELL) */
 734         #ifdef HP_UX
 735         MBSTOWCS(wcs_buffer, NOCATGETS("/bin/posix/sh"));
 736         #else
 737         #if defined(SUN5_0)
 738         if (posix) {
 739           MBSTOWCS(wcs_buffer, NOCATGETS("/usr/xpg4/bin/sh"));
 740         } else {
 741           MBSTOWCS(wcs_buffer, NOCATGETS("/bin/sh"));
 742         }
 743         #else  /* ^SUN5_0 */
 744         MBSTOWCS(wcs_buffer, NOCATGETS("/bin/sh"));
 745         #endif /* ^SUN5_0 */
 746         #endif
 747         (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
 748 
 749         /*
 750          * Use " FORCE" to simulate a FRC dependency for :: type
 751          * targets with no dependencies.
 752          */
 753         (void) append_prop(force, line_prop);
 754         force->stat.time = file_max_time;
 755 
 756         /* Make sure VPATH is defined before current dir is read */
 757         if ((cp = getenv(vpath_name->string_mb)) != NULL) {
 758                 MBSTOWCS(wcs_buffer, cp);
 759                 (void) SETVAR(vpath_name,
 760                               GETNAME(wcs_buffer, FIND_LENGTH),
 761                               false);
 762         }
 763 
 764         /* Check if there is NO PATH variable. If not we construct one. */
 765         if (getenv(path_name->string_mb) == NULL) {
 766                 vroot_path = NULL;
 767                 add_dir_to_path(NOCATGETS("."), &vroot_path, -1);
 768                 add_dir_to_path(NOCATGETS("/bin"), &vroot_path, -1);
 769                 add_dir_to_path(NOCATGETS("/usr/bin"), &vroot_path, -1);
 770         }
 771 }
 772 
 773 /* 
 774  * iterate on list of conditional macros in np, and place them in 
 775  * a String_rec starting with, and separated by the '$' character.
 776  */
 777 void
 778 cond_macros_into_string(Name np, String_rec *buffer)
 779 {
 780         Macro_list      macro_list;
 781 
 782         /* 
 783          * Put the version number at the start of the string
 784          */
 785         MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
 786         append_string(wcs_buffer, buffer, FIND_LENGTH);
 787         /* 
 788          * Add the rest of the conditional macros to the buffer
 789          */
 790         if (np->depends_on_conditional){
 791                 for (macro_list = np->conditional_macro_list; 
 792                      macro_list != NULL; macro_list = macro_list->next){
 793                         append_string(macro_list->macro_name, buffer, 
 794                                 FIND_LENGTH);
 795                         append_char((int) equal_char, buffer);
 796                         append_string(macro_list->value, buffer, FIND_LENGTH);
 797                         append_char((int) dollar_char, buffer);
 798                 }
 799         }
 800 }
 801 /*
 802  *      Copyright (c) 1987-1992 Sun Microsystems, Inc.  All Rights Reserved.
 803  *      Sun considers its source code as an unpublished, proprietary
 804  *      trade secret, and it is available only under strict license
 805  *      provisions.  This copyright notice is placed here only to protect
 806  *      Sun in the event the source is deemed a published work.  Dissassembly,
 807  *      decompilation, or other means of reducing the object code to human
 808  *      readable form is prohibited by the license agreement under which
 809  *      this code is provided to the user or company in possession of this
 810  *      copy.
 811  *      RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the
 812  *      Government is subject to restrictions as set forth in subparagraph
 813  *      (c)(1)(ii) of the Rights in Technical Data and Computer Software
 814  *      clause at DFARS 52.227-7013 and in similar clauses in the FAR and
 815  *      NASA FAR Supplement.
 816  *
 817  * 1.3 91/09/30
 818  */
 819 
 820 
 821 /* Some includes are commented because of the includes at the beginning */
 822 /* #include <signal.h> */
 823 #include <sys/types.h>
 824 #include <sys/stat.h>
 825 #include <sys/param.h>
 826 /* #include <string.h> */
 827 #include <unistd.h>
 828 #include <stdlib.h>
 829 /* #include <stdio.h> */
 830 /* #include <avo/find_dir.h> */
 831 /* #ifndef TEAMWARE_MAKE_CMN
 832 #include <avo/find_dir.h>
 833 #endif */
 834 
 835 /* Routines to find the base directory name from which the various components
 836  * -executables, *crt* libraries etc will be accessed
 837  */
 838 
 839 /* This routine checks to see if a given filename is an executable or not.
 840    Logically similar to the csh statement : if  ( -x $i && ! -d $i )
 841  */
 842 
 843 static int
 844 check_if_exec(char *file)
 845 {
 846         struct stat stb;
 847         if (stat(file, &stb) < 0) {
 848                 return ( -1);
 849         }
 850         if (S_ISDIR(stb.st_mode)) {
 851                 return (-1);
 852         }
 853         if (!(stb.st_mode & S_IEXEC)) {
 854                 return ( -1);
 855         }
 856         return (0);
 857 }
 858 
 859 /* resolve - check for specified file in specified directory
 860  *      sets up dir, following symlinks.
 861  *      returns zero for success, or
 862  *      -1 for error (with errno set properly)
 863  */
 864 static int
 865 resolve (char   *indir, /* search directory */
 866          char   *cmd,   /* search for name */
 867          char   *dir,   /* directory buffer */
 868          char   **run)  /* resultion name ptr ptr */
 869 {
 870     char               *p;
 871     int                 rv = -1;
 872     int                 sll;
 873     char                symlink[MAXPATHLEN + 1];
 874 
 875     do {
 876         errno = ENAMETOOLONG;
 877         if ((strlen (indir) + strlen (cmd) + 2) > (size_t) MAXPATHLEN)
 878             break;
 879 
 880         sprintf(dir, "%s/%s", indir, cmd);
 881         if (check_if_exec(dir) != 0)  /* check if dir is an executable */
 882         {
 883                 break;          /* Not an executable program */
 884         }
 885 
 886         /* follow symbolic links */
 887         while ((sll = readlink (dir, symlink, MAXPATHLEN)) >= 0) {
 888             symlink[sll] = 0;
 889             if (*symlink == '/')
 890                 strcpy (dir, symlink);
 891             else
 892                 sprintf (strrchr (dir, '/'), "/%s", symlink);
 893         }
 894         if (errno != EINVAL)
 895             break;
 896 
 897         p = strrchr (dir, '/');
 898         *p++ = 0;
 899         if (run)                /* user wants resolution name */
 900             *run = p;
 901         rv = 0;                 /* complete, with success! */
 902 
 903     } while (0);
 904 
 905     return rv;
 906 }
 907 
 908 /* 
 909  *find_run_directory - find executable file in PATH
 910  *
 911  * PARAMETERS:
 912  *      cmd     filename as typed by user (argv[0])
 913  *      cwd     buffer from which is read the working directory
 914  *               if first character is '/' or into which is
 915  *               copied working directory name otherwise
 916  *      dir     buffer into which is copied program's directory
 917  *      pgm     where to return pointer to tail of cmd (may be NULL
 918  *               if not wanted) 
 919  *      run     where to return pointer to tail of final resolved
 920  *               name ( dir/run is the program) (may be NULL
 921  *               if not wanted)
 922  *      path    user's path from environment
 923  *
 924  * Note: run and pgm will agree except when symbolic links have
 925  *      renamed files
 926  *
 927  * RETURNS:
 928  *      returns zero for success,
 929  *      -1 for error (with errno set properly).
 930  *
 931  * EXAMPLE:
 932  *      find_run_directory (argv[0], ".", &charray1, (char **) 0, (char **) 0,
 933  *                          getenv(NOGETTEXT("PATH")));
 934  */
 935 extern int
 936 find_run_directory (char        *cmd,
 937                     char        *cwd,
 938                     char        *dir,
 939                     char        **pgm,
 940                     char        **run,
 941                     char        *path)
 942 {
 943     int                 rv = 0;
 944     char                *f, *s;
 945     int                 i;
 946     char                tmp_path[MAXPATHLEN];
 947 
 948     if (!cmd || !*cmd || !cwd || !dir) {
 949         errno = EINVAL;         /* stupid arguments! */
 950         return -1;
 951     }
 952 
 953     if (*cwd != '/')
 954         if (!(getcwd (cwd, MAXPATHLEN)))
 955             return -1;          /* can not get working directory */
 956 
 957     f = strrchr (cmd, '/');
 958     if (pgm)                    /* user wants program name */
 959         *pgm = f ? f + 1 : cmd;
 960 
 961     /* get program directory */
 962     rv = -1;
 963     if (*cmd == '/')    /* absname given */
 964         rv = resolve ("", cmd + 1, dir, run);
 965     else if (f)         /* relname given */
 966         rv = resolve (cwd, cmd, dir, run);
 967     else {  /* from searchpath */
 968             if (!path || !*path) {      /* if missing or null path */
 969                     tmp_path[0] = '.';  /* assume sanity */
 970                     tmp_path[1] = '\0';
 971             } else {
 972                     strcpy(tmp_path, path);
 973             }
 974         f = tmp_path;
 975         rv = -1;
 976         errno = ENOENT; /* errno gets this if path empty */
 977         while (*f && (rv < 0)) {
 978             s = f;
 979             while (*f && (*f != ':'))
 980                 ++f;
 981             if (*f)
 982                 *f++ = 0;
 983             if (*s == '/')
 984                 rv = resolve (s, cmd, dir, run);
 985             else {
 986                 char                abuf[MAXPATHLEN];
 987 
 988                 sprintf (abuf, "%s/%s", cwd, s);
 989                 rv = resolve (abuf, cmd, dir, run);
 990             }
 991         }
 992     }
 993 
 994     /* Remove any trailing /. */
 995     i = strlen(dir);
 996     if ( dir[i-2] == '/' && dir[i-1] == '.') {
 997             dir[i-2] = '\0';
 998     }
 999 
1000     return rv;
1001 }
1002