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  *      doname.c
  28  *
  29  *      Figure out which targets are out of date and rebuild them
  30  */
  31 
  32 /*
  33  * Included files
  34  */
  35 #include <alloca.h>               /* alloca() */
  36 
  37 
  38 #include <fcntl.h>
  39 #include <mk/defs.h>
  40 #include <mksh/i18n.h>            /* get_char_semantics_value() */
  41 #include <mksh/macro.h>           /* getvar(), expand_value() */
  42 #include <mksh/misc.h>            /* getmem() */
  43 #include <poll.h>
  44 
  45 
  46 #include <signal.h>
  47 
  48 #       include <stropts.h>
  49 
  50 #include <sys/errno.h>
  51 #include <sys/stat.h>
  52 #include <sys/types.h>
  53 #include <sys/utsname.h>  /* uname() */
  54 #include <sys/wait.h>
  55 #include <unistd.h>               /* close() */
  56 
  57 /*
  58  * Defined macros
  59  */
  60 #       define LOCALHOST "localhost"
  61 
  62 #define MAXRULES 100
  63 
  64 #define SEND_MTOOL_MSG(cmds) 
  65 
  66 // Sleep for .1 seconds between stat()'s
  67 const int       STAT_RETRY_SLEEP_TIME = 100000;
  68 
  69 /*
  70  * typedefs & structs
  71  */
  72 
  73 /*
  74  * Static variables
  75  */
  76 static char     hostName[MAXNAMELEN] = "";
  77 static char     userName[MAXNAMELEN] = "";
  78 
  79 
  80 static int      second_pass = 0;
  81 
  82 /*
  83  * File table of contents
  84  */
  85 extern  Doname          doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
  86 extern  Doname          doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
  87 static  Boolean         check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
  88 void            dynamic_dependencies(Name target);
  89 static  Doname          run_command(register Property line, Boolean print_machine);
  90 extern  Doname          execute_serial(Property line);
  91 extern  Name            vpath_translation(register Name cmd);
  92 extern  void            check_state(Name temp_file_name);
  93 static  void            read_dependency_file(register Name filename);
  94 static  void            check_read_state_file(void);
  95 static  void            do_assign(register Name line, register Name target);
  96 static  void            build_command_strings(Name target, register Property line);
  97 static  Doname          touch_command(register Property line, register Name target, Doname result);
  98 extern  void            update_target(Property line, Doname result);
  99 static  Doname          sccs_get(register Name target, register Property *command);
 100 extern  void            read_directory_of_file(register Name file);
 101 static  void            add_pattern_conditionals(register Name target);
 102 extern  void            set_locals(register Name target, register Property old_locals);
 103 extern  void            reset_locals(register Name target, register Property old_locals, register Property conditional, register int index);
 104 extern  Boolean         check_auto_dependencies(Name target, int auto_count, Name *automatics);
 105 static  void            delete_query_chain(Chain ch);
 106 
 107 // From read2.cc
 108 extern  Name            normalize_name(register wchar_t *name_string, register int length);
 109 
 110 
 111 
 112 /*
 113  * DONE.
 114  *
 115  *      doname_check(target, do_get, implicit, automatic)
 116  *
 117  *      Will call doname() and then inspect the return value
 118  *
 119  *      Return value:
 120  *                              Indication if the build failed or not
 121  *
 122  *      Parameters:
 123  *              target          The target to build
 124  *              do_get          Passed thru to doname()
 125  *              implicit        Passed thru to doname()
 126  *              automatic       Are we building a hidden dependency?
 127  *
 128  *      Global variables used:
 129  *              build_failed_seen       Set if -k is on and error occurs
 130  *              continue_after_error    Indicates that -k is on
 131  *              report_dependencies     No error msg if -P is on
 132  */
 133 Doname
 134 doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
 135 {
 136         int first_time = 1;
 137         (void) fflush(stdout);
 138 try_again:
 139         switch (doname(target, do_get, implicit, automatic)) {
 140         case build_ok:
 141                 second_pass = 0;
 142                 return build_ok;
 143         case build_running:
 144                 second_pass = 0;
 145                 return build_running;
 146         case build_failed:
 147                 if (!continue_after_error) {
 148                         fatal(catgets(catd, 1, 13, "Target `%s' not remade because of errors"),
 149                               target->string_mb);
 150                 }
 151                 build_failed_seen = true;
 152                 second_pass = 0;
 153                 return build_failed;
 154         case build_dont_know:
 155                 /*
 156                  * If we can't figure out how to build an automatic
 157                  * (hidden) dependency, we just ignore it.
 158                  * We later declare the target to be out of date just in
 159                  * case something changed.
 160                  * Also, don't complain if just reporting the dependencies
 161                  * and not building anything.
 162                  */
 163                 if (automatic || (report_dependencies_level > 0)) {
 164                         second_pass = 0;
 165                         return build_dont_know;
 166                 }
 167                 if(first_time) {
 168                         first_time = 0;
 169                         second_pass = 1;
 170                         goto try_again;
 171                 }
 172                 second_pass = 0;
 173                 if (continue_after_error && !svr4) {
 174                         warning(catgets(catd, 1, 14, "Don't know how to make target `%s'"),
 175                                 target->string_mb);
 176                         build_failed_seen = true;
 177                         return build_failed;
 178                 }
 179                 fatal(catgets(catd, 1, 15, "Don't know how to make target `%s'"), target->string_mb);
 180                 break;
 181         }
 182 #ifdef lint
 183         return build_failed;
 184 #endif
 185 }
 186 
 187 
 188 void
 189 enter_explicit_rule_from_dynamic_rule(Name target, Name source)
 190 {
 191         Property line, source_line;
 192         Dependency dependency;
 193 
 194         source_line = get_prop(source->prop, line_prop);
 195         line = maybe_append_prop(target, line_prop);
 196         line->body.line.sccs_command = false;
 197         line->body.line.target = target;
 198         if (line->body.line.command_template == NULL) {
 199                 line->body.line.command_template = source_line->body.line.command_template;
 200                 for (dependency = source_line->body.line.dependencies;
 201                      dependency != NULL;
 202                      dependency = dependency->next) {
 203                         enter_dependency(line, dependency->name, false);
 204                 }
 205                 line->body.line.less = target;
 206         }
 207         line->body.line.percent = NULL;
 208 }
 209 
 210 
 211 
 212 Name
 213 find_dyntarget(Name target)
 214 {
 215         Dyntarget               p;
 216         int                     i;
 217         String_rec              string;
 218         wchar_t                 buffer[STRING_BUFFER_LENGTH];
 219         wchar_t                 *pp, * bufend;
 220         wchar_t                 tbuffer[MAXPATHLEN];
 221         Wstring                 wcb(target);
 222 
 223         for (p = dyntarget_list; p != NULL; p = p->next) {
 224                 INIT_STRING_FROM_STACK(string, buffer);
 225                 expand_value(p->name, &string, false);
 226                 i = 0;
 227                 pp = string.buffer.start;
 228                 bufend = pp + STRING_BUFFER_LENGTH;
 229                 while((*pp != nul_char) && (pp < bufend)) {
 230                         if(iswspace(*pp)) {
 231                                 tbuffer[i] = nul_char;
 232                                 if(i > 0) {
 233                                         if (wcb.equal(tbuffer)) {
 234                                                 enter_explicit_rule_from_dynamic_rule(target, p->name);
 235                                                 return(target);
 236                                         }
 237                                 }
 238                                 pp++;
 239                                 i = 0;
 240                                 continue;
 241                         }
 242                         tbuffer[i] = *pp;
 243                         i++;
 244                         pp++;
 245                         if(*pp == nul_char) {
 246                                 tbuffer[i] = nul_char;
 247                                 if(i > 0) {
 248                                         if (wcb.equal(tbuffer)) {
 249                                                 enter_explicit_rule_from_dynamic_rule(target, p->name);
 250                                                 return(target);
 251                                         }
 252                                 }
 253                                 break;
 254                         }
 255                 }
 256         }
 257         return(NULL);
 258 }
 259 
 260 /*
 261  * DONE.
 262  *
 263  *      doname(target, do_get, implicit)
 264  *
 265  *      Chases all files the target depends on and builds any that
 266  *      are out of date. If the target is out of date it is then rebuilt.
 267  *
 268  *      Return value:
 269  *                              Indiates if build failed or nt
 270  *
 271  *      Parameters:
 272  *              target          Target to build
 273  *              do_get          Run sccs get is nessecary
 274  *              implicit        doname is trying to find an implicit rule
 275  *
 276  *      Global variables used:
 277  *              assign_done     True if command line assgnment has happened
 278  *              commands_done   Preserved for the case that we need local value
 279  *              debug_level     Should we trace make's actions?
 280  *              default_rule    The rule for ".DEFAULT", used as last resort
 281  *              empty_name      The Name "", used when looking for single sfx
 282  *              keep_state      Indicates that .KEEP_STATE is on
 283  *              parallel        True if building in parallel
 284  *              recursion_level Used for tracing
 285  *              report_dependencies make -P is on
 286  */
 287 Doname
 288 doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
 289 {
 290         Doname                  result = build_dont_know;
 291         Chain                   out_of_date_list = NULL;
 292 #ifdef TEAMWARE_MAKE_CMN
 293         Chain                   target_group;
 294 #endif
 295         Property                old_locals = NULL;
 296         register Property       line;
 297         Property                command = NULL;
 298         register Dependency     dependency;
 299         Name                    less = NULL;
 300         Name                    true_target = target;
 301         Name                    *automatics = NULL;
 302         register int            auto_count;
 303         Boolean                 rechecking_target = false;
 304         Boolean                 saved_commands_done;
 305         Boolean                 restart = false;
 306         Boolean                 save_parallel = parallel;
 307         Boolean                 doing_subtree = false;
 308 
 309         Boolean                 recheck_conditionals = false;
 310 
 311         if (target->state == build_running) {
 312                 return build_running;
 313         }
 314         line = get_prop(target->prop, line_prop);
 315 #ifdef TEAMWARE_MAKE_CMN
 316         if (line != NULL) {
 317                 /*
 318                  * If this target is a member of target group and one of the
 319                  * other members of the group is running, mark this target
 320                  * as running.
 321                  */
 322                 for (target_group = line->body.line.target_group;
 323                      target_group != NULL;
 324                      target_group = target_group->next) {
 325                         if (is_running(target_group->name)) {
 326                                 target->state = build_running;
 327                                 add_pending(target,
 328                                             recursion_level,
 329                                             do_get,
 330                                             implicit,
 331                                             false);
 332                                 return build_running;
 333                         }
 334                 }
 335         }
 336 #endif
 337         /*
 338          * If the target is a constructed one for a "::" target,
 339          * we need to consider that.
 340          */
 341         if (target->has_target_prop) {
 342                 true_target = get_prop(target->prop,
 343                                        target_prop)->body.target.target;
 344                 if (true_target->colon_splits > 0) {
 345                         /* Make sure we have a valid time for :: targets */
 346                         Property        time;
 347 
 348                         time = get_prop(true_target->prop, time_prop);
 349                         if (time != NULL) {
 350                                 true_target->stat.time = time->body.time.time;
 351                         }
 352                 }
 353         }
 354         (void) exists(true_target);
 355         /*
 356          * If the target has been processed, we don't need to do it again,
 357          * unless it depends on conditional macros or a delayed assignment,
 358          * or it has been done when KEEP_STATE is on.
 359          */
 360         if (target->state == build_ok) {
 361                 if((!keep_state || (!target->depends_on_conditional && !assign_done))) {
 362                         return build_ok;
 363                 } else {
 364                         recheck_conditionals = true;
 365                 }
 366         }
 367         if (target->state == build_subtree) {
 368                 /* A dynamic macro subtree is being built */
 369                 target->state = build_dont_know;
 370                 doing_subtree = true;
 371                 if (!target->checking_subtree) {
 372                         /*
 373                          * This target has been started before and therefore
 374                          * not all dependencies have to be built.
 375                          */
 376                         restart = true;
 377                 }
 378         } else if (target->state == build_pending) {
 379                 target->state = build_dont_know;
 380                 restart = true;
 381 /*
 382 #ifdef TEAMWARE_MAKE_CMN
 383         } else if (parallel &&
 384                    keep_state &&
 385                    (target->conditional_cnt > 0)) {
 386             if (!parallel_ok(target, false)) {
 387                 add_subtree(target, recursion_level, do_get, implicit);
 388                 target->state = build_running;
 389                 return build_running;
 390             }
 391 #endif
 392  */
 393         }
 394         /*
 395          * If KEEP_STATE is on, we have to rebuild the target if the
 396          * building of it caused new automatic dependencies to be reported.
 397          * This is where we restart the build.
 398          */
 399         if (line != NULL) {
 400                 line->body.line.percent = NULL;
 401         }
 402 recheck_target:
 403         /* Init all local variables */
 404         result = build_dont_know;
 405         out_of_date_list = NULL;
 406         command = NULL;
 407         less = NULL;
 408         auto_count = 0;
 409         if (!restart && line != NULL) {
 410                 /*
 411                  * If this target has never been built before, mark all
 412                  * of the dependencies as never built.
 413                  */
 414                 for (dependency = line->body.line.dependencies;
 415                      dependency != NULL;
 416                      dependency = dependency->next) {
 417                         dependency->built = false;
 418                 }
 419         }
 420         /* Save the set of automatic depes defined for this target */
 421         if (keep_state &&
 422             (line != NULL) &&
 423             (line->body.line.dependencies != NULL)) {
 424                 Name *p;
 425 
 426                 /*
 427                  * First run thru the dependency list to see how many
 428                  * autos there are.
 429                  */
 430                 for (dependency = line->body.line.dependencies;
 431                      dependency != NULL;
 432                      dependency = dependency->next) {
 433                         if (dependency->automatic && !dependency->stale) {
 434                                 auto_count++;
 435                         }
 436                 }
 437                 /* Create vector to hold the current autos */
 438                 automatics =
 439                   (Name *) alloca((int) (auto_count * sizeof (Name)));
 440                 /* Copy them */
 441                 for (p = automatics, dependency = line->body.line.dependencies;
 442                      dependency != NULL;
 443                      dependency = dependency->next) {
 444                         if (dependency->automatic && !dependency->stale) {
 445                                 *p++ = dependency->name;
 446                         }
 447                 }
 448         }
 449         if (debug_level > 1) {
 450                 (void) printf(NOCATGETS("%*sdoname(%s)\n"),
 451                               recursion_level,
 452                               "",
 453                               target->string_mb);
 454         }
 455         recursion_level++;
 456         /* Avoid infinite loops */
 457         if (target->state == build_in_progress) {
 458                 warning(catgets(catd, 1, 16, "Infinite loop: Target `%s' depends on itself"),
 459                         target->string_mb);
 460                 return build_ok;
 461         }
 462         target->state = build_in_progress;
 463 
 464         /* Activate conditional macros for the target */
 465         if (!target->added_pattern_conditionals) {
 466                 add_pattern_conditionals(target);
 467                 target->added_pattern_conditionals = true;
 468         }
 469         if (target->conditional_cnt > 0) {
 470                 old_locals = (Property) alloca(target->conditional_cnt *
 471                                                sizeof (Property_rec));
 472                 set_locals(target, old_locals);
 473         }
 474 
 475 /*
 476  * after making the call to dynamic_dependecies unconditional we can handle
 477  * target names that are same as file name. In this case $$@ in the 
 478  * dependencies did not mean anything. WIth this change it expands it
 479  * as expected.
 480  */
 481         if (!target->has_depe_list_expanded)
 482         {
 483                 dynamic_dependencies(target);
 484         }
 485 
 486 /*
 487  *      FIRST SECTION -- GO THROUGH DEPENDENCIES AND COLLECT EXPLICIT
 488  *      COMMANDS TO RUN
 489  */
 490         if ((line = get_prop(target->prop, line_prop)) != NULL) {
 491                 if (check_dependencies(&result,
 492                                        line,
 493                                        do_get,
 494                                        target,
 495                                        true_target,
 496                                        doing_subtree,
 497                                        &out_of_date_list,
 498                                        old_locals,
 499                                        implicit,
 500                                        &command,
 501                                        less,
 502                                        rechecking_target,
 503                                        recheck_conditionals)) {
 504                         return build_running;
 505                 }
 506                 if (line->body.line.query != NULL) {
 507                         delete_query_chain(line->body.line.query);
 508                 }
 509                 line->body.line.query = out_of_date_list;
 510         }
 511 
 512 
 513 /*
 514  * If the target is a :: type, do not try to find the rule for the target,
 515  * all actions will be taken by separate branches.
 516  * Else, we try to find an implicit rule using various methods,
 517  * we quit as soon as one is found.
 518  *
 519  * [tolik, 12 Sep 2002] Do not try to find implicit rule for the target
 520  * being rechecked - the target is being rechecked means that it already
 521  * has explicit dependencies derived from an implicit rule found
 522  * in previous step.
 523  */
 524         if (target->colon_splits == 0 && !rechecking_target) {
 525                 /* Look for percent matched rule */
 526                 if ((result == build_dont_know) &&
 527                     (command == NULL)) {
 528                         switch (find_percent_rule(
 529                                         target,
 530                                         &command,
 531                                         recheck_conditionals)) {
 532                         case build_failed:
 533                                 result = build_failed;
 534                                 break;
 535 #ifdef TEAMWARE_MAKE_CMN
 536                         case build_running:
 537                                 target->state = build_running;
 538                                 add_pending(target,
 539                                             --recursion_level,
 540                                             do_get,
 541                                             implicit,
 542                                             false);
 543                                 if (target->conditional_cnt > 0) {
 544                                         reset_locals(target,
 545                                                      old_locals,
 546                                                      get_prop(target->prop,
 547                                                              conditional_prop),
 548                                                      0);
 549                                 }
 550                                 return build_running;
 551 #endif
 552                         case build_ok:
 553                                 result = build_ok;
 554                                 break;
 555                         }
 556                 }
 557                 /* Look for double suffix rule */
 558                 if (result == build_dont_know) {
 559                         Property member;
 560 
 561                         if (target->is_member &&
 562                             ((member = get_prop(target->prop, member_prop)) !=
 563                              NULL)) {
 564                                 switch (find_ar_suffix_rule(target,
 565                                                 member->body.
 566                                                 member.member,
 567                                                 &command,
 568                                                 recheck_conditionals)) {
 569                                 case build_failed:
 570                                         result = build_failed;
 571                                         break;
 572 #ifdef TEAMWARE_MAKE_CMN
 573                                 case build_running:
 574                                         target->state = build_running;
 575                                         add_pending(target,
 576                                                     --recursion_level,
 577                                                     do_get,
 578                                                     implicit,
 579                                                     false);
 580                                     if (target->conditional_cnt > 0) {
 581                                             reset_locals(target,
 582                                                          old_locals,
 583                                                          get_prop(target->prop,
 584                                                              conditional_prop),
 585                                                          0);
 586                                     }
 587                                         return build_running;
 588 #endif
 589                                 default:
 590                                         /* ALWAYS bind $% for old style */
 591                                         /* ar rules */
 592                                         if (line == NULL) {
 593                                                 line =
 594                                                   maybe_append_prop(target,
 595                                                                     line_prop);
 596                                         }
 597                                         line->body.line.percent =
 598                                           member->body.member.member;
 599                                         break;
 600                                 }
 601                         } else {
 602                                 switch (find_double_suffix_rule(target,
 603                                                 &command,
 604                                                 recheck_conditionals)) {
 605                                 case build_failed:
 606                                         result = build_failed;
 607                                         break;
 608 #ifdef TEAMWARE_MAKE_CMN
 609                                 case build_running:
 610                                         target->state = build_running;
 611                                         add_pending(target,
 612                                                     --recursion_level,
 613                                                     do_get,
 614                                                     implicit,
 615                                                     false);
 616                                         if (target->conditional_cnt > 0) {
 617                                                 reset_locals(target,
 618                                                              old_locals,
 619                                                              get_prop(target->
 620                                                                       prop,
 621                                                                       conditional_prop),
 622                                                              0);
 623                                         }
 624                                         return build_running;
 625 #endif
 626                                 }
 627                         }
 628                 }
 629                 /* Look for single suffix rule */
 630 
 631 /* /tolik/
 632  * I commented !implicit to fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
 633  * This caused problem with SVR4 tilde rules (infinite recursion). So I made some changes in "implicit.cc"
 634  */
 635 /* /tolik, 06.21.96/
 636  * Regression! See BugId 1255360
 637  * If more than one percent rules are defined for the same target then
 638  * the behaviour of 'make' with my previous fix may be different from one
 639  * of the 'old make'. 
 640  * The global variable second_pass (maybe it should be an argument to doname())
 641  * is intended to avoid this regression. It is set in doname_check().
 642  * First, 'make' will work as it worked before. Only when it is
 643  * going to say "don't know how to make target" it sets second_pass to true and
 644  * run 'doname' again but now trying to use Single Suffix Rules.
 645  */
 646                 if ((result == build_dont_know) && !automatic && (!implicit || second_pass) &&
 647                     ((line == NULL) ||
 648                      ((line->body.line.target != NULL) &&
 649                       !line->body.line.target->has_regular_dependency))) {
 650                         switch (find_suffix_rule(target,
 651                                                  target,
 652                                                  empty_name,
 653                                                  &command,
 654                                                  recheck_conditionals)) {
 655                         case build_failed:
 656                                 result = build_failed;
 657                                 break;
 658 #ifdef TEAMWARE_MAKE_CMN
 659                         case build_running:
 660                                 target->state = build_running;
 661                                 add_pending(target,
 662                                             --recursion_level,
 663                                             do_get,
 664                                             implicit,
 665                                             false);
 666                                 if (target->conditional_cnt > 0) {
 667                                         reset_locals(target,
 668                                                      old_locals,
 669                                                      get_prop(target->prop,
 670                                                              conditional_prop),
 671                                                      0);
 672                                 }
 673                                 return build_running;
 674 #endif
 675                         }
 676                 }
 677                 /* Try to sccs get */
 678                 if ((command == NULL) &&
 679                     (result == build_dont_know) &&
 680                     do_get) {
 681                         result = sccs_get(target, &command);
 682                 }
 683 
 684                 /* Use .DEFAULT rule if it is defined. */
 685                 if ((command == NULL) &&
 686                     (result == build_dont_know) &&
 687                     (true_target->colons == no_colon) &&
 688                     default_rule &&
 689                     !implicit) {
 690                         /* Make sure we have a line prop */
 691                         line = maybe_append_prop(target, line_prop);
 692                         command = line;
 693                         Boolean out_of_date;
 694                         if (true_target->is_member) {
 695                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
 696                                                                         line->body.line.dependency_time);
 697                         } else {
 698                                 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
 699                                                                     line->body.line.dependency_time);
 700                         }
 701                         if (build_unconditional || out_of_date) {
 702                                 line->body.line.is_out_of_date = true;
 703                                 if (debug_level > 0) {
 704                                         (void) printf(catgets(catd, 1, 17, "%*sBuilding %s using .DEFAULT because it is out of date\n"),
 705                                                       recursion_level,
 706                                                       "",
 707                                                       true_target->string_mb);
 708                                 }
 709                         }
 710                         line->body.line.sccs_command = false;
 711                         line->body.line.command_template = default_rule;
 712                         line->body.line.target = true_target;
 713                         line->body.line.star = NULL;
 714                         line->body.line.less = true_target;
 715                         line->body.line.percent = NULL;
 716                 }
 717         }
 718 
 719         /* We say "target up to date" if no cmd were executed for the target */
 720         if (!target->is_double_colon_parent) {
 721                 commands_done = false;
 722         }
 723 
 724         silent = silent_all;
 725         ignore_errors = ignore_errors_all;
 726         if  (posix)
 727         {
 728           if  (!silent)
 729           {
 730             silent = (Boolean) target->silent_mode;
 731           }
 732           if  (!ignore_errors)
 733           {
 734             ignore_errors = (Boolean) target->ignore_error_mode;
 735           }
 736         }
 737 
 738         int doname_dyntarget = 0;
 739 r_command:
 740         /* Run commands if any. */
 741         if ((command != NULL) &&
 742             (command->body.line.command_template != NULL)) {
 743                 if (result != build_failed) {
 744                         result = run_command(command, 
 745                                              (Boolean) ((parallel || save_parallel) && !silent));
 746                 }
 747                 switch (result) {
 748 #ifdef TEAMWARE_MAKE_CMN
 749                 case build_running:
 750                         add_running(target,
 751                                     true_target,
 752                                     command,
 753                                     --recursion_level,
 754                                     auto_count,
 755                                     automatics,
 756                                     do_get,
 757                                     implicit);
 758                         target->state = build_running;
 759                         if ((line = get_prop(target->prop,
 760                                              line_prop)) != NULL) {
 761                                 if (line->body.line.query != NULL) {
 762                                         delete_query_chain(line->body.line.query);
 763                                 }
 764                                 line->body.line.query = NULL;
 765                         }
 766                         if (target->conditional_cnt > 0) {
 767                                 reset_locals(target,
 768                                              old_locals,
 769                                              get_prop(target->prop,
 770                                                      conditional_prop),
 771                                              0);
 772                         }
 773                         return build_running;
 774                 case build_serial:
 775                         add_serial(target,
 776                                    --recursion_level,
 777                                    do_get,
 778                                    implicit);
 779                         target->state = build_running;
 780                         line = get_prop(target->prop, line_prop);
 781                         if (line != NULL) {
 782                                 if (line->body.line.query != NULL) {
 783                                         delete_query_chain(line->body.line.query);
 784                                 }
 785                                 line->body.line.query = NULL;
 786                         }
 787                         if (target->conditional_cnt > 0) {
 788                                 reset_locals(target,
 789                                              old_locals,
 790                                              get_prop(target->prop,
 791                                                      conditional_prop),
 792                                              0);
 793                         }
 794                         return build_running;
 795 #endif
 796                 case build_ok:
 797                         /* If all went OK set a nice timestamp */
 798                         if (true_target->stat.time == file_doesnt_exist) {
 799                                 true_target->stat.time = file_max_time;
 800                         }
 801                         break;
 802                 }
 803         } else {
 804                 /*
 805                  * If no command was found for the target, and it doesn't
 806                  * exist, and it is mentioned as a target in the makefile,
 807                  * we say it is extremely new and that it is OK.
 808                  */
 809                 if (target->colons != no_colon) {
 810                         if (true_target->stat.time == file_doesnt_exist){
 811                                 true_target->stat.time = file_max_time;
 812                         }
 813                         result = build_ok;
 814                 }
 815                 /*
 816                  * Trying dynamic targets.
 817                  */
 818                 if(!doname_dyntarget) {
 819                         doname_dyntarget = 1;
 820                         Name dtarg = find_dyntarget(target);
 821                         if(dtarg!=NULL) {
 822                                 if (!target->has_depe_list_expanded) {
 823                                         dynamic_dependencies(target);
 824                                 }
 825                                 if ((line = get_prop(target->prop, line_prop)) != NULL) {
 826                                         if (check_dependencies(&result,
 827                                                                line,
 828                                                                do_get,
 829                                                                target,
 830                                                                true_target,
 831                                                                doing_subtree,
 832                                                                &out_of_date_list,
 833                                                                old_locals,
 834                                                                implicit,
 835                                                                &command,
 836                                                                less,
 837                                                                rechecking_target,
 838                                                                recheck_conditionals))
 839                                         {
 840                                                 return build_running;
 841                                         }
 842                                         if (line->body.line.query != NULL) {
 843                                                 delete_query_chain(line->body.line.query);
 844                                         }
 845                                         line->body.line.query = out_of_date_list;
 846                                 }
 847                                 goto r_command;
 848                         }
 849                 }
 850                 /*
 851                  * If the file exists, it is OK that we couldnt figure
 852                  * out how to build it.
 853                  */
 854                 (void) exists(target);
 855                 if ((target->stat.time != file_doesnt_exist) &&
 856                     (result == build_dont_know)) {
 857                         result = build_ok;
 858                 }
 859         }
 860 
 861         /*
 862          * Some of the following is duplicated in the function finish_doname.
 863          * If anything is changed here, check to see if it needs to be
 864          * changed there.
 865          */
 866         if ((line = get_prop(target->prop, line_prop)) != NULL) {
 867                 if (line->body.line.query != NULL) {
 868                         delete_query_chain(line->body.line.query);
 869                 }
 870                 line->body.line.query = NULL;
 871         }
 872         target->state = result;
 873         parallel = save_parallel;
 874         if (target->conditional_cnt > 0) {
 875                 reset_locals(target,
 876                              old_locals,
 877                              get_prop(target->prop, conditional_prop),
 878                              0);
 879         }
 880         recursion_level--;
 881         if (target->is_member) {
 882                 Property member;
 883 
 884                 /* Propagate the timestamp from the member file to the member*/
 885                 if ((target->stat.time != file_max_time) &&
 886                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
 887                     (exists(member->body.member.member) > file_doesnt_exist)) {
 888                         target->stat.time =
 889                           member->body.member.member->stat.time;
 890                 }
 891         }
 892         /*
 893          * Check if we found any new auto dependencies when we
 894          * built the target.
 895          */
 896         if ((result == build_ok) && check_auto_dependencies(target,
 897                                                             auto_count,
 898                                                             automatics)) {
 899                 if (debug_level > 0) {
 900                         (void) printf(catgets(catd, 1, 18, "%*sTarget `%s' acquired new dependencies from build, rechecking all dependencies\n"),
 901                                       recursion_level,
 902                                       "",
 903                                       true_target->string_mb);
 904                 }
 905                 rechecking_target = true;
 906                 saved_commands_done = commands_done;
 907                 goto recheck_target;
 908         }
 909 
 910         if (rechecking_target && !commands_done) {
 911                 commands_done = saved_commands_done;
 912         }
 913 
 914         return result;
 915 }
 916 
 917 /*
 918  * DONE.
 919  *
 920  *      check_dependencies(result, line, do_get,
 921  *                      target, true_target, doing_subtree, out_of_date_tail,
 922  *                      old_locals, implicit, command, less, rechecking_target)
 923  *
 924  *      Return value:
 925  *                              True returned if some dependencies left running
 926  *                              
 927  *      Parameters:
 928  *              result          Pointer to cell we update if build failed
 929  *              line            We get the dependencies from here
 930  *              do_get          Allow use of sccs get in recursive doname()
 931  *              target          The target to chase dependencies for
 932  *              true_target     The real one for :: and lib(member)
 933  *              doing_subtree   True if building a conditional macro subtree
 934  *              out_of_date_tail Used to set the $? list
 935  *              old_locals      Used for resetting the local macros
 936  *              implicit        Called when scanning for implicit rules?
 937  *              command         Place to stuff command
 938  *              less            Set to $< value
 939  *
 940  *      Global variables used:
 941  *              command_changed Set if we suspect .make.state needs rewrite
 942  *              debug_level     Should we trace actions?
 943  *              force           The Name " FORCE", compared against
 944  *              recursion_level Used for tracing
 945  *              rewrite_statefile Set if .make.state needs rewriting
 946  *              wait_name       The Name ".WAIT", compared against
 947  */
 948 static Boolean
 949 #ifdef TEAMWARE_MAKE_CMN
 950 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
 951 #else
 952 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean, Chain *out_of_date_tail, Property, Boolean, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
 953 #endif
 954 {
 955         Boolean                 dependencies_running;
 956         register Dependency     dependency;
 957         Doname                  dep_result;
 958         Boolean                 dependency_changed = false;
 959 
 960         line->body.line.dependency_time = file_doesnt_exist;
 961         if (line->body.line.query != NULL) {
 962                 delete_query_chain(line->body.line.query);
 963         }
 964         line->body.line.query = NULL;
 965         line->body.line.is_out_of_date = false;
 966         dependencies_running = false;
 967         /*
 968          * Run thru all the dependencies and call doname() recursively
 969          * on each of them.
 970          */
 971         for (dependency = line->body.line.dependencies;
 972              dependency != NULL;
 973              dependency = dependency->next) {
 974                 Boolean this_dependency_changed = false;
 975 
 976                 if (!dependency->automatic &&
 977                     (rechecking_target || target->rechecking_target)) {
 978                         /*
 979                          * We only bother with the autos when rechecking
 980                          */
 981                         continue;
 982                 }
 983 
 984                 if (dependency->name == wait_name) {
 985                         /*
 986                          * The special target .WAIT means finish all of
 987                          * the prior dependencies before continuing.
 988                          */
 989                         if (dependencies_running) {
 990                                 break;
 991                         }
 992                 } else {
 993                         timestruc_t     depe_time = file_doesnt_exist;
 994 
 995 
 996                         if (true_target->is_member) {
 997                                 depe_time = exists(dependency->name);
 998                         }
 999                         if (dependency->built ||
1000                             (dependency->name->state == build_failed)) {
1001                                 dep_result = (Doname) dependency->name->state;
1002                         } else {
1003                                 dep_result = doname_check(dependency->name,
1004                                                           do_get,
1005                                                           false,
1006                                                           (Boolean) dependency->automatic);
1007                         }
1008                         if (true_target->is_member || dependency->name->is_member) {
1009                                 /* should compare only secs, cause lib members does not have nsec time resolution */
1010                                 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
1011                                         this_dependency_changed =
1012                                           dependency_changed =
1013                                             true;
1014                                 }
1015                         } else {
1016                                 if (depe_time != dependency->name->stat.time) {
1017                                         this_dependency_changed =
1018                                           dependency_changed =
1019                                             true;
1020                                 }
1021                         }
1022                         dependency->built = true;
1023                         switch (dep_result) {
1024                         case build_running:
1025                                 dependencies_running = true;
1026                                 continue;
1027                         case build_failed:
1028                                 *result = build_failed;
1029                                 break;
1030                         case build_dont_know:
1031 /*
1032  * If make can't figure out how to make a dependency, maybe the dependency
1033  * is out of date. In this case, we just declare the target out of date
1034  * and go on. If we really need the dependency, the make'ing of the target
1035  * will fail. This will only happen for automatic (hidden) dependencies.
1036  */
1037                                 if(!recheck_conditionals) {
1038                                         line->body.line.is_out_of_date = true;
1039                                 }
1040                                 /*
1041                                  * Make sure the dependency is not saved
1042                                  * in the state file.
1043                                  */
1044                                 dependency->stale = true;
1045                                 rewrite_statefile =
1046                                   command_changed =
1047                                     true;
1048                                 if (debug_level > 0) {
1049                                         (void) printf(catgets(catd, 1, 19, "Target %s rebuilt because dependency %s does not exist\n"),
1050                                                      true_target->string_mb,
1051                                                      dependency->name->string_mb);
1052                                 }
1053                                 break;
1054                         }
1055                         if (dependency->name->depends_on_conditional) {
1056                                 target->depends_on_conditional = true;
1057                         }
1058                         if (dependency->name == force) {
1059                                 target->stat.time =
1060                                   dependency->name->stat.time;
1061                         }
1062                         /*
1063                          * Propagate new timestamp from "member" to
1064                          * "lib.a(member)".
1065                          */
1066                         (void) exists(dependency->name);
1067 
1068                         /* Collect the timestamp of the youngest dependency */
1069                         line->body.line.dependency_time =
1070                           MAX(dependency->name->stat.time,
1071                               line->body.line.dependency_time);
1072 
1073                         /* Correction: do not consider nanosecs for members */
1074                         if(true_target->is_member || dependency->name->is_member) {
1075                                 line->body.line.dependency_time.tv_nsec = 0;
1076                         }
1077 
1078                         if (debug_level > 1) {
1079                                 (void) printf(catgets(catd, 1, 20, "%*sDate(%s)=%s \n"),
1080                                               recursion_level,
1081                                               "",
1082                                               dependency->name->string_mb,
1083                                               time_to_string(dependency->name->
1084                                                              stat.time));
1085                                 if (dependency->name->stat.time > line->body.line.dependency_time) {
1086                                         (void) printf(catgets(catd, 1, 21, "%*sDate-dependencies(%s) set to %s\n"),
1087                                                       recursion_level,
1088                                                       "",
1089                                                       true_target->string_mb,
1090                                                       time_to_string(line->body.line.
1091                                                                      dependency_time));
1092                                 }
1093                         }
1094 
1095                         /* Build the $? list */
1096                         if (true_target->is_member) {
1097                                 if (this_dependency_changed == true) {
1098                                         true_target->stat.time = dependency->name->stat.time;
1099                                         true_target->stat.time.tv_sec--;
1100                                 } else {
1101                                         /* Dina: 
1102                                          * The next statement is commented
1103                                          * out as a fix for bug #1051032.
1104                                          * if dependency hasn't changed
1105                                          * then there's no need to invalidate
1106                                          * true_target. This statemnt causes
1107                                          * make to take much longer to process
1108                                          * an already-built archive. Soren
1109                                          * said it was a quick fix for some
1110                                          * problem he doesn't remember.
1111                                         true_target->stat.time = file_no_time;
1112                                          */
1113                                         (void) exists(true_target);
1114                                 }
1115                         } else {
1116                                 (void) exists(true_target);
1117                         }
1118                         Boolean out_of_date;
1119                         if (true_target->is_member || dependency->name->is_member) {
1120                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1121                                                                         dependency->name->stat.time);
1122                         } else {
1123                                 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1124                                                                     dependency->name->stat.time);
1125                         }
1126                         if ((build_unconditional || out_of_date) &&
1127                             (dependency->name != force) &&
1128                             (dependency->stale == false)) {
1129                                 *out_of_date_tail = ALLOC(Chain);
1130                                 if (dependency->name->is_member &&
1131                                     (get_prop(dependency->name->prop,
1132                                               member_prop) != NULL)) {
1133                                         (*out_of_date_tail)->name =
1134                                           get_prop(dependency->name->prop,
1135                                                    member_prop)->
1136                                                      body.member.member;
1137                                 } else {
1138                                         (*out_of_date_tail)->name =
1139                                           dependency->name;
1140                                 }
1141                                 (*out_of_date_tail)->next = NULL;
1142                                 out_of_date_tail = &(*out_of_date_tail)->next;
1143                                 if (debug_level > 0) {
1144                                         if (dependency->name->stat.time == file_max_time) {
1145                                                 (void) printf(catgets(catd, 1, 22, "%*sBuilding %s because %s does not exist\n"),
1146                                                               recursion_level,
1147                                                               "",
1148                                                               true_target->string_mb,
1149                                                               dependency->name->string_mb);
1150                                         } else {
1151                                                 (void) printf(catgets(catd, 1, 23, "%*sBuilding %s because it is out of date relative to %s\n"),
1152                                                               recursion_level,
1153                                                               "",
1154                                                               true_target->string_mb,
1155                                                               dependency->name->string_mb);
1156                                         }
1157                                 }
1158                         }
1159                         if (dependency->name == force) {
1160                                 force->stat.time =
1161                                   file_max_time;
1162                                 force->state = build_dont_know;
1163                         }
1164                 }
1165         }
1166 #ifdef TEAMWARE_MAKE_CMN
1167         if (dependencies_running) {
1168                 if (doing_subtree) {
1169                         if (target->conditional_cnt > 0) {
1170                                 reset_locals(target,
1171                                              old_locals,
1172                                              get_prop(target->prop,
1173                                                       conditional_prop),
1174                                              0);
1175                         }
1176                         return true;
1177                 } else {
1178                         target->state = build_running;
1179                         add_pending(target,
1180                                     --recursion_level,
1181                                     do_get,
1182                                     implicit,
1183                                     false);
1184                         if (target->conditional_cnt > 0) {
1185                                 reset_locals(target,
1186                                              old_locals,
1187                                              get_prop(target->prop,
1188                                                       conditional_prop),
1189                                              0);
1190                         }
1191                         return true;
1192                 }
1193         }
1194 #endif
1195         /*
1196          * Collect the timestamp of the youngest double colon target
1197          * dependency.
1198          */
1199         if (target->is_double_colon_parent) {
1200                 for (dependency = line->body.line.dependencies;
1201                      dependency != NULL;
1202                      dependency = dependency->next) {
1203                         Property        tmp_line;
1204 
1205                         if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) {
1206                                 if(tmp_line->body.line.dependency_time != file_max_time) {
1207                                         target->stat.time =
1208                                           MAX(tmp_line->body.line.dependency_time,
1209                                               target->stat.time);
1210                                 }
1211                         }
1212                 }
1213         }
1214         if ((true_target->is_member) && (dependency_changed == true)) {
1215                 true_target->stat.time = file_no_time;
1216         }
1217         /*
1218          * After scanning all the dependencies, we check the rule
1219          * if we found one.
1220          */
1221         if (line->body.line.command_template != NULL) {
1222                 if (line->body.line.command_template_redefined) {
1223                         warning(catgets(catd, 1, 24, "Too many rules defined for target %s"),
1224                                 target->string_mb);
1225                 }
1226                 *command = line;
1227                 /* Check if the target is out of date */
1228                 Boolean out_of_date;
1229                 if (true_target->is_member) {
1230                         out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1231                                                                 line->body.line.dependency_time);
1232                 } else {
1233                         out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1234                                                             line->body.line.dependency_time);
1235                 }
1236                 if (build_unconditional || out_of_date){
1237                         if(!recheck_conditionals) {
1238                                 line->body.line.is_out_of_date = true;
1239                         }
1240                 }
1241                 line->body.line.sccs_command = false;
1242                 line->body.line.target = true_target;
1243                 if(gnu_style) {
1244 
1245                         // set $< for explicit rule
1246                         if(line->body.line.dependencies != NULL) {
1247                                 less = line->body.line.dependencies->name;
1248                         }
1249 
1250                         // set $* for explicit rule
1251                         Name                    target_body;
1252                         Name                    tt = true_target;
1253                         Property                member;
1254                         register wchar_t        *target_end;
1255                         register Dependency     suffix;
1256                         register int            suffix_length;
1257                         Wstring                 targ_string;
1258                         Wstring                 suf_string;
1259 
1260                         if (true_target->is_member &&
1261                             ((member = get_prop(target->prop, member_prop)) !=
1262                              NULL)) {
1263                                 tt = member->body.member.member;
1264                         }
1265                         targ_string.init(tt);
1266                         target_end = targ_string.get_string() + tt->hash.length;
1267                         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
1268                                 suffix_length = suffix->name->hash.length;
1269                                 suf_string.init(suffix->name);
1270                                 if (tt->hash.length < suffix_length) {
1271                                         continue;
1272                                 } else if (!IS_WEQUALN(suf_string.get_string(),
1273                                                 (target_end - suffix_length),
1274                                                 suffix_length)) {
1275                                         continue;
1276                                 }
1277                                 target_body = GETNAME(
1278                                         targ_string.get_string(),
1279                                         (int)(tt->hash.length - suffix_length)
1280                                 );
1281                                 line->body.line.star = target_body;
1282                         }
1283 
1284                         // set result = build_ok so that implicit rules are not used.
1285                         if(*result == build_dont_know) {
1286                                 *result = build_ok;
1287                         }
1288                 }
1289                 if (less != NULL) {
1290                         line->body.line.less = less;
1291                 }
1292         }
1293 
1294         return false;
1295 }
1296 
1297 /*
1298  *      dynamic_dependencies(target)
1299  *
1300  *      Checks if any dependency contains a macro ref
1301  *      If so, it replaces the dependency with the expanded version.
1302  *      Here, "$@" gets translated to target->string. That is
1303  *      the current name on the left of the colon in the
1304  *      makefile.  Thus,
1305  *              xyz:    s.$@.c
1306  *      translates into
1307  *              xyz:    s.xyz.c
1308  *
1309  *      Also, "$(@F)" translates to the same thing without a preceeding
1310  *      directory path (if one exists).
1311  *      Note, to enter "$@" on a dependency line in a makefile
1312  *      "$$@" must be typed. This is because make expands
1313  *      macros in dependency lists upon reading them.
1314  *      dynamic_dependencies() also expands file wildcards.
1315  *      If there are any Shell meta characters in the name,
1316  *      search the directory, and replace the dependency
1317  *      with the set of files the pattern matches
1318  *
1319  *      Parameters:
1320  *              target          Target to sanitize dependencies for
1321  *
1322  *      Global variables used:
1323  *              c_at            The Name "@", used to set macro value
1324  *              debug_level     Should we trace actions?
1325  *              dot             The Name ".", used to read directory
1326  *              recursion_level Used for tracing
1327  */
1328 void
1329 dynamic_dependencies(Name target)
1330 {
1331         wchar_t                 pattern[MAXPATHLEN];
1332         register wchar_t        *p;
1333         Property                line;
1334         register Dependency     dependency;
1335         register Dependency     *remove;
1336         String_rec              string;
1337         wchar_t                 buffer[MAXPATHLEN];
1338         register Boolean        set_at = false;
1339         register wchar_t        *start;
1340         Dependency              new_depe;
1341         register Boolean        reuse_cell;
1342         Dependency              first_member;
1343         Name                    directory;
1344         Name                    lib;
1345         Name                    member;
1346         Property                prop;
1347         Name                    true_target = target;
1348         wchar_t                 *library;
1349 
1350         if ((line = get_prop(target->prop, line_prop)) == NULL) {
1351                 return;
1352         }
1353         /* If the target is constructed from a "::" target we consider that */
1354         if (target->has_target_prop) {
1355                 true_target = get_prop(target->prop,
1356                                        target_prop)->body.target.target;
1357         }
1358         /* Scan all dependencies and process the ones that contain "$" chars */
1359         for (dependency = line->body.line.dependencies;
1360              dependency != NULL;
1361              dependency = dependency->next) {
1362                 if (!dependency->name->dollar) {
1363                         continue;
1364                 }
1365                 target->has_depe_list_expanded = true;
1366 
1367                 /* The make macro $@ is bound to the target name once per */
1368                 /* invocation of dynamic_dependencies() */
1369                 if (!set_at) {
1370                         (void) SETVAR(c_at, true_target, false);
1371                         set_at = true;
1372                 }
1373                 /* Expand this dependency string */
1374                 INIT_STRING_FROM_STACK(string, buffer);
1375                 expand_value(dependency->name, &string, false);
1376                 /* Scan the expanded string. It could contain whitespace */
1377                 /* which mean it expands to several dependencies */
1378                 start = string.buffer.start;
1379                 while (iswspace(*start)) {
1380                         start++;
1381                 }
1382                 /* Remove the cell (later) if the macro was empty */
1383                 if (start[0] == (int) nul_char) {
1384                         dependency->name = NULL;
1385                 }
1386 
1387 /* azv 10/26/95 to fix bug BID_1170218 */
1388                 if ((start[0] == (int) period_char) &&
1389                     (start[1] == (int) slash_char)) {
1390                         start += 2;
1391                 }
1392 /* azv */
1393 
1394                 first_member = NULL;
1395                 /* We use the original dependency cell for the first */
1396                 /* dependency from the expansion */
1397                 reuse_cell = true;
1398                 /* We also have to deal with dependencies that expand to */
1399                 /* lib.a(members) notation */
1400                 for (p = start; *p != (int) nul_char; p++) {
1401                         if ((*p == (int) parenleft_char)) {
1402                                 lib = GETNAME(start, p - start);
1403                                 lib->is_member = true;
1404                                 first_member = dependency;
1405                                 start = p + 1;
1406                                 while (iswspace(*start)) {
1407                                         start++;
1408                                 }
1409                                 break;
1410                         }
1411                 }
1412                 do {
1413                     /* First skip whitespace */
1414                         for (p = start; *p != (int) nul_char; p++) {
1415                                 if ((*p == (int) nul_char) ||
1416                                     iswspace(*p) ||
1417                                     (*p == (int) parenright_char)) {
1418                                         break;
1419                                 }
1420                         }
1421                         /* Enter dependency from expansion */
1422                         if (p != start) {
1423                                 /* Create new dependency cell if */
1424                                 /* this is not the first dependency */
1425                                 /* picked from the expansion */
1426                                 if (!reuse_cell) {
1427                                         new_depe = ALLOC(Dependency);
1428                                         new_depe->next = dependency->next;
1429                                         new_depe->automatic = false;
1430                                         new_depe->stale = false;
1431                                         new_depe->built = false;
1432                                         dependency->next = new_depe;
1433                                         dependency = new_depe;
1434                                 }
1435                                 reuse_cell = false;
1436                                 /* Internalize the dependency name */
1437                                 // tolik. Fix for bug 4110429: inconsistent expansion for macros that
1438                                 // include "//" and "/./"
1439                                 //dependency->name = GETNAME(start, p - start);
1440                                 dependency->name = normalize_name(start, p - start);
1441                                 if ((debug_level > 0) &&
1442                                     (first_member == NULL)) {
1443                                         (void) printf(catgets(catd, 1, 25, "%*sDynamic dependency `%s' for target `%s'\n"),
1444                                                       recursion_level,
1445                                                       "",
1446                                                       dependency->name->string_mb,
1447                                                       true_target->string_mb);
1448                                 }
1449                                 for (start = p; iswspace(*start); start++);
1450                                 p = start;
1451                         }
1452                 } while ((*p != (int) nul_char) &&
1453                          (*p != (int) parenright_char));
1454                 /* If the expansion was of lib.a(members) format we now */
1455                 /* enter the proper member cells */
1456                 if (first_member != NULL) {
1457                         /* Scan the new dependencies and transform them from */
1458                         /* "foo" to "lib.a(foo)" */
1459                         for (; 1; first_member = first_member->next) {
1460                                 /* Build "lib.a(foo)" name */
1461                                 INIT_STRING_FROM_STACK(string, buffer);
1462                                 APPEND_NAME(lib,
1463                                               &string,
1464                                               (int) lib->hash.length);
1465                                 append_char((int) parenleft_char, &string);
1466                                 APPEND_NAME(first_member->name,
1467                                               &string,
1468                                               FIND_LENGTH);
1469                                 append_char((int) parenright_char, &string);
1470                                 member = first_member->name;
1471                                 /* Replace "foo" with "lib.a(foo)" */
1472                                 first_member->name =
1473                                   GETNAME(string.buffer.start, FIND_LENGTH);
1474                                 if (string.free_after_use) {
1475                                         retmem(string.buffer.start);
1476                                 }
1477                                 if (debug_level > 0) {
1478                                         (void) printf(catgets(catd, 1, 26, "%*sDynamic dependency `%s' for target `%s'\n"),
1479                                                       recursion_level,
1480                                                       "",
1481                                                       first_member->name->
1482                                                       string_mb,
1483                                                       true_target->string_mb);
1484                                 }
1485                                 first_member->name->is_member = lib->is_member;
1486                                 /* Add member property to member */
1487                                 prop = maybe_append_prop(first_member->name,
1488                                                          member_prop);
1489                                 prop->body.member.library = lib;
1490                                 prop->body.member.entry = NULL;
1491                                 prop->body.member.member = member;
1492                                 if (first_member == dependency) {
1493                                         break;
1494                                 }
1495                         }
1496                 }
1497         }
1498         Wstring wcb;
1499         /* Then scan all the dependencies again. This time we want to expand */
1500         /* shell file wildcards */
1501         for (remove = &line->body.line.dependencies, dependency = *remove;
1502              dependency != NULL;
1503              dependency = *remove) {
1504                 if (dependency->name == NULL) {
1505                         dependency = *remove = (*remove)->next;
1506                         continue;
1507                 }
1508                 /* If dependency name string contains shell wildcards */
1509                 /* replace the name with the expansion */
1510                 if (dependency->name->wildcard) {
1511                         wcb.init(dependency->name);
1512                         if ((start = (wchar_t *) wschr(wcb.get_string(),
1513                                            (int) parenleft_char)) != NULL) {
1514                                 /* lib(*) type pattern */
1515                                 library = buffer;
1516                                 (void) wsncpy(buffer,
1517                                               wcb.get_string(),
1518                                               start - wcb.get_string());
1519                                 buffer[start-wcb.get_string()] =
1520                                   (int) nul_char;
1521                                 (void) wsncpy(pattern,
1522                                               start + 1,
1523 (int) (dependency->name->hash.length-(start-wcb.get_string())-2));
1524                                 pattern[dependency->name->hash.length -
1525                                         (start-wcb.get_string()) - 2] =
1526                                           (int) nul_char;
1527                         } else {
1528                                 library = NULL;
1529                                 (void) wsncpy(pattern,
1530                                               wcb.get_string(),
1531                                               (int) dependency->name->hash.length);
1532                                 pattern[dependency->name->hash.length] =
1533                                   (int) nul_char;
1534                         }
1535                         start = (wchar_t *) wsrchr(pattern, (int) slash_char);
1536                         if (start == NULL) {
1537                                 directory = dot;
1538                                 p = pattern;
1539                         } else {
1540                                 directory = GETNAME(pattern, start-pattern);
1541                                 p = start+1;
1542                         }
1543                         /* The expansion is handled by the read_dir() routine*/
1544                         if (read_dir(directory, p, line, library)) {
1545                                 *remove = (*remove)->next;
1546                         } else {
1547                                 remove = &dependency->next;
1548                         }
1549                 } else {
1550                         remove = &dependency->next;
1551                 }
1552         }
1553 
1554         /* Then unbind $@ */
1555         (void) SETVAR(c_at, (Name) NULL, false);
1556 }
1557 
1558 /*
1559  * DONE.
1560  *
1561  *      run_command(line)
1562  *
1563  *      Takes one Cmd_line and runs the commands from it.
1564  *
1565  *      Return value:
1566  *                              Indicates if the command failed or not
1567  *
1568  *      Parameters:
1569  *              line            The command line to run
1570  *
1571  *      Global variables used:
1572  *              commands_done   Set if we do run command
1573  *              current_line    Set to the line we run a command from
1574  *              current_target  Set to the target we run a command for
1575  *              file_number     Used to form temp file name
1576  *              keep_state      Indicates that .KEEP_STATE is on
1577  *              make_state      The Name ".make.state", used to check timestamp
1578  *              parallel        True if currently building in parallel
1579  *              parallel_process_cnt Count of parallel processes running
1580  *              quest           Indicates that make -q is on
1581  *              rewrite_statefile Set if we do run a command
1582  *              sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value
1583  *              temp_file_directory Used to form temp fie name
1584  *              temp_file_name  Set to the name of the temp file
1585  *              touch           Indicates that make -t is on
1586  */
1587 static Doname
1588 run_command(register Property line, Boolean)
1589 {
1590         register Doname         result = build_ok;
1591         register Boolean        remember_only = false;
1592         register Name           target = line->body.line.target;
1593         wchar_t                 *string;
1594         char                    tmp_file_path[MAXPATHLEN];
1595 
1596         if (!line->body.line.is_out_of_date && target->rechecking_target) {
1597                 target->rechecking_target = false;
1598                 return build_ok;
1599         }
1600 
1601         /*
1602          * Build the command if we know the target is out of date,
1603          * or if we want to check cmd consistency.
1604          */
1605         if (line->body.line.is_out_of_date || keep_state) {
1606                 /* Hack for handling conditional macros in DMake. */
1607                 if (!line->body.line.dont_rebuild_command_used) {
1608                         build_command_strings(target, line);
1609                 }
1610         }
1611         /* Never mind */
1612         if (!line->body.line.is_out_of_date) {
1613                 return build_ok;
1614         }
1615         /* If quest, then exit(1) because the target is out of date */
1616         if (quest) {
1617                 if (posix) {
1618 #ifdef TEAMWARE_MAKE_CMN
1619                         result = execute_parallel(line, true);
1620 #else
1621                         result = execute_serial(line);
1622 #endif
1623                 }
1624                 exit_status = 1;
1625                 exit(1);
1626         }
1627         /* We actually had to do something this time */
1628         rewrite_statefile = commands_done = true;
1629         /*
1630          * If this is an sccs command, we have to do some extra checking
1631          * and possibly complain. If the file can't be gotten because it's
1632          * checked out, we complain and behave as if the command was
1633          * executed eventhough we ignored the command.
1634          */
1635         if (!touch &&
1636             line->body.line.sccs_command &&
1637             (target->stat.time != file_doesnt_exist) &&
1638             ((target->stat.mode & 0222) != 0)) {
1639                 fatal(catgets(catd, 1, 27, "%s is writable so it cannot be sccs gotten"),
1640                       target->string_mb);
1641                 target->has_complained = remember_only = true;
1642         }
1643         /*
1644          * If KEEP_STATE is on, we make sure we have the timestamp for
1645          * .make.state. If .make.state changes during the command run,
1646          * we reread .make.state after the command. We also setup the
1647          * environment variable that asks utilities to report dependencies.
1648          */
1649         if (!touch &&
1650             keep_state &&
1651             !remember_only) {
1652                 (void) exists(make_state);
1653                 if((strlen(temp_file_directory) == 1) && 
1654                         (temp_file_directory[0] == '/')) {
1655                    tmp_file_path[0] = '\0';
1656                 } else {
1657                    strcpy(tmp_file_path, temp_file_directory);
1658                 }
1659                 sprintf(mbs_buffer,
1660                                 NOCATGETS("%s/.make.dependency.%08x.%d.%d"),
1661                                 tmp_file_path,
1662                                 hostid,
1663                                 getpid(),
1664                                 file_number++);
1665                 MBSTOWCS(wcs_buffer, mbs_buffer);
1666                 Boolean fnd;
1667                 temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd);
1668                 temp_file_name->stat.is_file = true;
1669                 int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2;
1670                 wchar_t *to = string = ALLOC_WC(len);
1671                 for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) {
1672                         if (*from == (int) space_char) {
1673                                 *to++ = (int) backslash_char;
1674                         }
1675                         *to++ = *from++;
1676                 }
1677                 *to++ = (int) space_char;
1678                 MBSTOWCS(to, target->string_mb);
1679                 Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd);
1680                 (void) SETVAR(sunpro_dependencies,
1681                               sprodep_name,
1682                               false);
1683                 retmem(string);
1684         } else {
1685                 temp_file_name = NULL;
1686         }
1687 
1688         /*
1689          * In case we are interrupted, we need to know what was going on.
1690          */
1691         current_target = target;
1692         /*
1693          * We also need to be able to save an empty command instead of the
1694          * interrupted one in .make.state.
1695          */
1696         current_line = line;
1697         if (remember_only) {
1698                 /* Empty block!!! */
1699         } else if (touch) {
1700                 result = touch_command(line, target, result);
1701                 if (posix) {
1702 #ifdef TEAMWARE_MAKE_CMN
1703                         result = execute_parallel(line, true);
1704 #else
1705                         result = execute_serial(line);
1706 #endif
1707                 }
1708         } else {
1709                 /*
1710                  * If this is not a touch run, we need to execute the
1711                  * proper command(s) for the target.
1712                  */
1713 #ifdef TEAMWARE_MAKE_CMN
1714                 if (parallel) {
1715                         if (!parallel_ok(target, true)) {
1716                                 /*
1717                                  * We are building in parallel, but
1718                                  * this target must be built in serial.
1719                                  */
1720                                 /*
1721                                  * If nothing else is building,
1722                                  * do this one, else wait.
1723                                  */
1724                                 if (parallel_process_cnt == 0) {
1725 #ifdef TEAMWARE_MAKE_CMN
1726                                         result = execute_parallel(line, true, target->localhost);
1727 #else
1728                                         result = execute_serial(line);
1729 #endif
1730                                 } else {
1731                                         current_target = NULL;
1732                                         current_line = NULL;
1733 /*
1734                                         line->body.line.command_used = NULL;
1735  */
1736                                         line->body.line.dont_rebuild_command_used = true;
1737                                         return build_serial;
1738                                 }
1739                         } else {
1740                                 result = execute_parallel(line, false);
1741                                 switch (result) {
1742                                 case build_running:
1743                                         return build_running;
1744                                 case build_serial:
1745                                         if (parallel_process_cnt == 0) {
1746 #ifdef TEAMWARE_MAKE_CMN
1747                                                 result = execute_parallel(line, true, target->localhost);
1748 #else
1749                                                 result = execute_serial(line);
1750 #endif
1751                                         } else {
1752                                                 current_target = NULL;
1753                                                 current_line = NULL;
1754                                                 target->parallel = false;
1755                                                 line->body.line.command_used =
1756                                                                         NULL;
1757                                                 return build_serial;
1758                                         }
1759                                 }
1760                         }
1761                 } else {
1762 #endif
1763 #ifdef TEAMWARE_MAKE_CMN
1764                         result = execute_parallel(line, true, target->localhost);
1765 #else
1766                         result = execute_serial(line);
1767 #endif
1768 #ifdef TEAMWARE_MAKE_CMN
1769                 }
1770 #endif
1771         }
1772         temp_file_name = NULL;
1773         if (report_dependencies_level == 0){
1774                 update_target(line, result);
1775         }
1776         current_target = NULL;
1777         current_line = NULL;
1778         return result;
1779 }
1780 
1781 /*
1782  *      execute_serial(line)
1783  *
1784  *      Runs thru the command line for the target and
1785  *      executes the rules one by one.
1786  *
1787  *      Return value:
1788  *                              The result of the command build
1789  *
1790  *      Parameters:     
1791  *              line            The command to execute
1792  *
1793  *      Static variables used:
1794  *
1795  *      Global variables used:
1796  *              continue_after_error -k flag
1797  *              do_not_exec_rule -n flag
1798  *              report_dependencies -P flag
1799  *              silent          Don't echo commands before executing
1800  *              temp_file_name  Temp file for auto dependencies
1801  *              vpath_defined   If true, translate path for command
1802  */
1803 Doname
1804 execute_serial(Property line)
1805 {
1806         int                     child_pid = 0;
1807         Boolean                 printed_serial;
1808         Doname                  result = build_ok;
1809         Cmd_line                rule, cmd_tail, command = NULL;
1810         char                    mbstring[MAXPATHLEN];
1811         int                     filed;
1812         Name                    target = line->body.line.target;
1813 
1814         SEND_MTOOL_MSG(
1815                 if (!sent_rsrc_info_msg) {
1816                         if (userName[0] == '\0') {
1817                                 avo_get_user(userName, NULL);
1818                         }
1819                         if (hostName[0] == '\0') {
1820                                 strcpy(hostName, avo_hostname());
1821                         }
1822                         send_rsrc_info_msg(1, hostName, userName);
1823                         sent_rsrc_info_msg = 1;
1824                 }
1825                 send_job_start_msg(line);
1826                 job_result_msg = new Avo_MToolJobResultMsg();
1827         );
1828 
1829         target->has_recursive_dependency = false;
1830         // We have to create a copy of the rules chain for processing because
1831         // the original one can be destroyed during .make.state file rereading.
1832         for (rule = line->body.line.command_used;
1833              rule != NULL;
1834              rule = rule->next) {
1835                 if (command == NULL) {
1836                         command = cmd_tail = ALLOC(Cmd_line);
1837                 } else {
1838                         cmd_tail->next = ALLOC(Cmd_line);
1839                         cmd_tail = cmd_tail->next;
1840                 }
1841                 *cmd_tail = *rule;
1842         }
1843         if (command) {
1844                 cmd_tail->next = NULL;
1845         }
1846         for (rule = command; rule != NULL; rule = rule->next) {
1847                 if (posix && (touch || quest) && !rule->always_exec) {
1848                         continue;
1849                 }
1850                 if (vpath_defined) {
1851                         rule->command_line =
1852                           vpath_translation(rule->command_line);
1853                 }
1854                 /* Echo command line, maybe. */
1855                 if ((rule->command_line->hash.length > 0) &&
1856                     !silent &&
1857                     (!rule->silent || do_not_exec_rule) &&
1858                     (report_dependencies_level == 0)) {
1859                         (void) printf("%s\n", rule->command_line->string_mb);
1860                         SEND_MTOOL_MSG(
1861                                 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
1862                         );
1863                 }
1864                 if (rule->command_line->hash.length > 0) {
1865                         SEND_MTOOL_MSG(
1866                                 (void) sprintf(mbstring,
1867                                                 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
1868                                                 tmpdir,
1869                                                 getpid(),
1870                                                 file_number++);
1871 
1872                                 int tmp_fd = mkstemp(mbstring);
1873                                 if(tmp_fd) {
1874                                         (void) close(tmp_fd);
1875                                 }
1876 
1877                                 stdout_file = strdup(mbstring);
1878                                 stderr_file = NULL;
1879                                 child_pid = pollResults(stdout_file,
1880                                                         (char *)NULL,
1881                                                         (char *)NULL);
1882                         );
1883                         /* Do assignment if command line prefixed with "=" */
1884                         if (rule->assign) {
1885                                 result = build_ok;
1886                                 do_assign(rule->command_line, target);
1887                         } else if (report_dependencies_level == 0) {
1888                                 /* Execute command line. */
1889                                 setvar_envvar();
1890                                 result = dosys(rule->command_line,
1891                                                (Boolean) rule->ignore_error,
1892                                                (Boolean) rule->make_refd,
1893                                                /* ds 98.04.23 bug #4085164. make should always show error messages */
1894                                                false,
1895                                                /* BOOLEAN(rule->silent &&
1896                                                        rule->ignore_error), */
1897                                                (Boolean) rule->always_exec,
1898                                                target,
1899                                                send_mtool_msgs);
1900                                 check_state(temp_file_name);
1901                         }
1902                         SEND_MTOOL_MSG(
1903                                 append_job_result_msg(job_result_msg);
1904                                 if (child_pid > 0) {
1905                                         kill(child_pid, SIGUSR1);
1906                                         while (!((waitpid(child_pid, 0, 0) == -1)
1907                                                 && (errno == ECHILD)));
1908                                 }
1909                                 child_pid = 0;
1910                                 (void) unlink(stdout_file);
1911                                 retmem_mb(stdout_file);
1912                                 stdout_file = NULL;
1913                         );
1914                 } else {
1915                         result = build_ok;
1916                 }
1917                 if (result == build_failed) {
1918                         if (silent || rule->silent) {
1919                                 (void) printf(catgets(catd, 1, 242, "The following command caused the error:\n%s\n"),
1920                                               rule->command_line->string_mb);
1921                                 SEND_MTOOL_MSG(
1922                                         job_result_msg->appendOutput(AVO_STRDUP(catgets(catd, 1, 243, "The following command caused the error:")));
1923                                         job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
1924                                 );
1925                         }
1926                         if (!rule->ignore_error && !ignore_errors) {
1927                                 if (!continue_after_error) {
1928                                         SEND_MTOOL_MSG(
1929                                                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
1930                                                 xdr_msg = (RWCollectable*)
1931                                                         job_result_msg;
1932                                                 xdr(&xdrs, xdr_msg);
1933                                                 (void) fflush(mtool_msgs_fp);
1934                                                 delete job_result_msg;
1935                                         );
1936                                         fatal(catgets(catd, 1, 244, "Command failed for target `%s'"),
1937                                               target->string_mb);
1938                                 }
1939                                 /*
1940                                  * Make sure a failing command is not
1941                                  * saved in .make.state.
1942                                  */
1943                                 line->body.line.command_used = NULL;
1944                                 break;
1945                         } else {
1946                                 result = build_ok;
1947                         }
1948                 }
1949         }
1950         for (rule = command; rule != NULL; rule = cmd_tail) {
1951                 cmd_tail = rule->next;
1952                 free(rule);
1953         }
1954         command = NULL;
1955         SEND_MTOOL_MSG(
1956                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
1957                 xdr_msg = (RWCollectable*) job_result_msg;
1958                 xdr(&xdrs, xdr_msg);
1959                 (void) fflush(mtool_msgs_fp);
1960 
1961                 delete job_result_msg;
1962         );
1963         if (temp_file_name != NULL) {
1964                 free_name(temp_file_name);
1965         }
1966         temp_file_name = NULL;
1967 
1968         Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
1969         if(spro != NULL) {
1970                 Name val = spro->body.macro.value;
1971                 if(val != NULL) {
1972                         free_name(val);
1973                         spro->body.macro.value = NULL;
1974                 }
1975         }
1976         spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
1977         if(spro) {
1978                 char *val = spro->body.env_mem.value;
1979                 if(val != NULL) {
1980                         /* 
1981                          * Do not return memory allocated for SUNPRO_DEPENDENCIES
1982                          * It will be returned in setvar_daemon() in macro.cc 
1983                          */
1984                         //      retmem_mb(val);
1985                         spro->body.env_mem.value = NULL;
1986                 }
1987         }
1988         
1989         return result;
1990 }
1991 
1992 
1993 
1994 /*
1995  *      vpath_translation(cmd)
1996  *
1997  *      Translates one command line by
1998  *      checking each word. If the word has an alias it is translated.
1999  *
2000  *      Return value:
2001  *                              The translated command
2002  *
2003  *      Parameters:
2004  *              cmd             Command to translate
2005  *
2006  *      Global variables used:
2007  */
2008 Name
2009 vpath_translation(register Name cmd)
2010 {
2011         wchar_t                 buffer[STRING_BUFFER_LENGTH];
2012         String_rec              new_cmd;
2013         wchar_t                 *p;
2014         wchar_t                 *start;
2015 
2016         if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) {
2017                 return cmd;
2018         }
2019         INIT_STRING_FROM_STACK(new_cmd, buffer);
2020 
2021         Wstring wcb(cmd);
2022         p = wcb.get_string();
2023 
2024         while (*p != (int) nul_char) {
2025                 while (iswspace(*p) && (*p != (int) nul_char)) {
2026                         append_char(*p++, &new_cmd);
2027                 }
2028                 start = p;
2029                 while (!iswspace(*p) && (*p != (int) nul_char)) {
2030                         p++;
2031                 }
2032                 cmd = GETNAME(start, p - start);
2033                 if (cmd->has_vpath_alias_prop) {
2034                         cmd = get_prop(cmd->prop, vpath_alias_prop)->
2035                                                 body.vpath_alias.alias;
2036                         APPEND_NAME(cmd,
2037                                       &new_cmd,
2038                                       (int) cmd->hash.length);
2039                 } else {
2040                         append_string(start, &new_cmd, p - start);
2041                 }
2042         }
2043         cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH);
2044         if (new_cmd.free_after_use) {
2045                 retmem(new_cmd.buffer.start);
2046         }
2047         return cmd;
2048 }
2049 
2050 /*
2051  *      check_state(temp_file_name)
2052  *
2053  *      Reads and checks the state changed by the previously executed command.
2054  *
2055  *      Parameters:
2056  *              temp_file_name  The auto dependency temp file
2057  *
2058  *      Global variables used:
2059  */
2060 void
2061 check_state(Name temp_file_name)
2062 {
2063         if (!keep_state) {
2064                 return;
2065         }
2066 
2067         /*
2068          * Then read the temp file that now might 
2069          * contain dependency reports from utilities 
2070          */
2071         read_dependency_file(temp_file_name);
2072 
2073         /*
2074          * And reread .make.state if it
2075          * changed (the command ran recursive makes) 
2076          */
2077         check_read_state_file();
2078         if (temp_file_name != NULL) {
2079                 (void) unlink(temp_file_name->string_mb);
2080         }
2081 }
2082 
2083 /*
2084  *      read_dependency_file(filename)
2085  *
2086  *      Read the temp file used for reporting dependencies to make
2087  *
2088  *      Parameters:
2089  *              filename        The name of the file with the state info
2090  *
2091  *      Global variables used:
2092  *              makefile_type   The type of makefile being read
2093  *              read_trace_level Debug flag
2094  *              temp_file_number The always increasing number for unique files
2095  *              trace_reader    Debug flag
2096  */
2097 static void
2098 read_dependency_file(register Name filename)
2099 {
2100         register Makefile_type  save_makefile_type;
2101 
2102         if (filename == NULL) {
2103                 return;
2104         }
2105         filename->stat.time = file_no_time;
2106         if (exists(filename) > file_doesnt_exist) {
2107                 save_makefile_type = makefile_type;
2108                 makefile_type = reading_cpp_file;
2109                 if (read_trace_level > 1) {
2110                         trace_reader = true;
2111                 }
2112                 temp_file_number++;
2113                 (void) read_simple_file(filename,
2114                                         false,
2115                                         false,
2116                                         false,
2117                                         false,
2118                                         false,
2119                                         false);
2120                 trace_reader = false;
2121                 makefile_type = save_makefile_type;
2122         }
2123 }
2124 
2125 /*
2126  *      check_read_state_file()
2127  *
2128  *      Check if .make.state has changed
2129  *      If it has we reread it
2130  *
2131  *      Parameters:
2132  *
2133  *      Global variables used:
2134  *              make_state      Make state file name
2135  *              makefile_type   Type of makefile being read
2136  *              read_trace_level Debug flag
2137  *              trace_reader    Debug flag
2138  */
2139 static void
2140 check_read_state_file(void)
2141 {
2142         timestruc_t             previous = make_state->stat.time;
2143         register Makefile_type  save_makefile_type;
2144         register Property       makefile;
2145 
2146         make_state->stat.time = file_no_time;
2147         if ((exists(make_state) == file_doesnt_exist) ||
2148             (make_state->stat.time == previous)) {
2149                 return;
2150         }
2151         save_makefile_type = makefile_type;
2152         makefile_type = rereading_statefile;
2153         /* Make sure we clear the old cached contents of .make.state */
2154         makefile = maybe_append_prop(make_state, makefile_prop);
2155         if (makefile->body.makefile.contents != NULL) {
2156                 retmem(makefile->body.makefile.contents);
2157                 makefile->body.makefile.contents = NULL;
2158         }
2159         if (read_trace_level > 1) {
2160                 trace_reader = true;
2161         }
2162         temp_file_number++;
2163         (void) read_simple_file(make_state,
2164                                 false,
2165                                 false,
2166                                 false,
2167                                 false,
2168                                 false,
2169                                 true);
2170         trace_reader = false;
2171         makefile_type = save_makefile_type;
2172 }
2173 
2174 /*
2175  *      do_assign(line, target)
2176  *
2177  *      Handles runtime assignments for command lines prefixed with "=".
2178  *
2179  *      Parameters:
2180  *              line            The command that contains an assignment
2181  *              target          The Name of the target, used for error reports
2182  *
2183  *      Global variables used:
2184  *              assign_done     Set to indicate doname needs to reprocess
2185  */
2186 static void
2187 do_assign(register Name line, register Name target)
2188 {
2189         Wstring wcb(line);
2190         register wchar_t        *string = wcb.get_string();
2191         register wchar_t        *equal;
2192         register Name           name;
2193         register Boolean        append = false;
2194 
2195         /*
2196          * If any runtime assignments are done, doname() must reprocess all
2197          * targets in the future since the macro values used to build the
2198          * command lines for the targets might have changed.
2199          */
2200         assign_done = true;
2201         /* Skip white space. */
2202         while (iswspace(*string)) {
2203                 string++;
2204         }
2205         equal = string;
2206         /* Find "+=" or "=". */
2207         while (!iswspace(*equal) &&
2208                (*equal != (int) plus_char) &&
2209                (*equal != (int) equal_char)) {
2210                 equal++;
2211         }
2212         /* Internalize macro name. */
2213         name = GETNAME(string, equal - string);
2214         /* Skip over "+=" "=". */
2215         while (!((*equal == (int) nul_char) ||
2216                  (*equal == (int) equal_char) ||
2217                  (*equal == (int) plus_char))) {
2218                 equal++;
2219         }
2220         switch (*equal) {
2221         case nul_char:
2222                 fatal(catgets(catd, 1, 31, "= expected in rule `%s' for target `%s'"),
2223                       line->string_mb,
2224                       target->string_mb);
2225         case plus_char:
2226                 append = true;
2227                 equal++;
2228                 break;
2229         }
2230         equal++;
2231         /* Skip over whitespace in front of value. */
2232         while (iswspace(*equal)) {
2233                 equal++;
2234         }
2235         /* Enter new macro value. */
2236         enter_equal(name,
2237                     GETNAME(equal, wcb.get_string() + line->hash.length - equal),
2238                     append);
2239 }
2240 
2241 /*
2242  *      build_command_strings(target, line)
2243  *
2244  *      Builds the command string to used when
2245  *      building a target. If the string is different from the previous one
2246  *      is_out_of_date is set.
2247  *
2248  *      Parameters:
2249  *              target          Target to build commands for
2250  *              line            Where to stuff result
2251  *
2252  *      Global variables used:
2253  *              c_at            The Name "@", used to set macro value
2254  *              command_changed Set if command is different from old
2255  *              debug_level     Should we trace activities?
2256  *              do_not_exec_rule Always echo when running -n
2257  *              empty_name      The Name "", used for empty rule
2258  *              funny           Semantics of characters
2259  *              ignore_errors   Used to init field for line
2260  *              is_conditional  Set to false befor evaling macro, checked
2261  *                              after expanding macros
2262  *              keep_state      Indicates that .KEEP_STATE is on
2263  *              make_word_mentioned Set by macro eval, inits field for cmd
2264  *              query           The Name "?", used to set macro value
2265  *              query_mentioned Set by macro eval, inits field for cmd
2266  *              recursion_level Used for tracing
2267  *              silent          Used to init field for line
2268  */
2269 static void
2270 build_command_strings(Name target, register Property line)
2271 {
2272         String_rec              command_line;
2273         register Cmd_line       command_template = line->body.line.command_template;
2274         register Cmd_line       *insert = &line->body.line.command_used;
2275         register Cmd_line       used = *insert;
2276         wchar_t                 buffer[STRING_BUFFER_LENGTH];
2277         wchar_t                 *start;
2278         Name                    new_command_line;
2279         register Boolean        new_command_longer = false;
2280         register Boolean        ignore_all_command_dependency = true;
2281         Property                member;
2282         static Name             less_name;
2283         static Name             percent_name;
2284         static Name             star;
2285         Name                    tmp_name;
2286 
2287         if (less_name == NULL) {
2288                 MBSTOWCS(wcs_buffer, "<");
2289                 less_name = GETNAME(wcs_buffer, FIND_LENGTH);
2290                 MBSTOWCS(wcs_buffer, "%");
2291                 percent_name = GETNAME(wcs_buffer, FIND_LENGTH);
2292                 MBSTOWCS(wcs_buffer, "*");
2293                 star = GETNAME(wcs_buffer, FIND_LENGTH);
2294         }
2295 
2296         /* We have to check if a target depends on conditional macros */
2297         /* Targets that do must be reprocessed by doname() each time around */
2298         /* since the macro values used when building the target might have */
2299         /* changed */
2300         conditional_macro_used = false;
2301         /* If we are building a lib.a(member) target $@ should be bound */
2302         /* to lib.a */
2303         if (target->is_member &&
2304             ((member = get_prop(target->prop, member_prop)) != NULL)) {
2305                 target = member->body.member.library;
2306         }
2307         /* If we are building a "::" help target $@ should be bound to */
2308         /* the real target name */
2309         /* A lib.a(member) target is never :: */
2310         if (target->has_target_prop) {
2311                 target = get_prop(target->prop, target_prop)->
2312                   body.target.target;
2313         }
2314         /* Bind the magic macros that make supplies */
2315         tmp_name = target;
2316         if(tmp_name != NULL) {
2317                 if (tmp_name->has_vpath_alias_prop) {
2318                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2319                                         body.vpath_alias.alias;
2320                 }
2321         }
2322         (void) SETVAR(c_at, tmp_name, false);
2323 
2324         tmp_name = line->body.line.star;
2325         if(tmp_name != NULL) {
2326                 if (tmp_name->has_vpath_alias_prop) {
2327                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2328                                         body.vpath_alias.alias;
2329                 }
2330         }
2331         (void) SETVAR(star, tmp_name, false);
2332 
2333         tmp_name = line->body.line.less;
2334         if(tmp_name != NULL) {
2335                 if (tmp_name->has_vpath_alias_prop) {
2336                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2337                                         body.vpath_alias.alias;
2338                 }
2339         }
2340         (void) SETVAR(less_name, tmp_name, false);
2341 
2342         tmp_name = line->body.line.percent;
2343         if(tmp_name != NULL) {
2344                 if (tmp_name->has_vpath_alias_prop) {
2345                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2346                                         body.vpath_alias.alias;
2347                 }
2348         }
2349         (void) SETVAR(percent_name, tmp_name, false);
2350 
2351         /* $? is seldom used and it is expensive to build */
2352         /* so we store the list form and build the string on demand */
2353         Chain query_list = NULL;
2354         Chain *query_list_tail = &query_list;
2355 
2356         for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) {
2357                 *query_list_tail = ALLOC(Chain);
2358                 (*query_list_tail)->name = ch->name;
2359                 if ((*query_list_tail)->name->has_vpath_alias_prop) {
2360                         (*query_list_tail)->name =
2361                                 get_prop((*query_list_tail)->name->prop,
2362                                         vpath_alias_prop)->body.vpath_alias.alias;
2363                 }
2364                 (*query_list_tail)->next = NULL;
2365                 query_list_tail = &(*query_list_tail)->next;
2366         }
2367         (void) setvar_daemon(query,
2368                              (Name) query_list,
2369                              false,
2370                              chain_daemon,
2371                              false,
2372                              debug_level);
2373 
2374         /* build $^ */
2375         Chain hat_list = NULL;
2376         Chain *hat_list_tail = &hat_list;
2377 
2378         for (Dependency dependency = line->body.line.dependencies; 
2379                 dependency != NULL;
2380                 dependency = dependency->next) {
2381                 /* skip automatic dependencies */
2382                 if (!dependency->automatic) {
2383                         if ((dependency->name != force) &&
2384                                 (dependency->stale == false)) {
2385                                 *hat_list_tail = ALLOC(Chain);
2386                         
2387                                 if (dependency->name->is_member &&
2388                                         (get_prop(dependency->name->prop, member_prop) != NULL)) {
2389                                         (*hat_list_tail)->name = 
2390                                                         get_prop(dependency->name->prop,
2391                                                                 member_prop)->body.member.member;
2392                                 } else {
2393                                         (*hat_list_tail)->name = dependency->name;
2394                                 }
2395 
2396                                 if((*hat_list_tail)->name != NULL) {
2397                                         if ((*hat_list_tail)->name->has_vpath_alias_prop) {
2398                                                 (*hat_list_tail)->name =
2399                                                         get_prop((*hat_list_tail)->name->prop,
2400                                                                 vpath_alias_prop)->body.vpath_alias.alias;
2401                                         }
2402                                 }
2403 
2404                                 (*hat_list_tail)->next = NULL;
2405                                 hat_list_tail = &(*hat_list_tail)->next;
2406                         }
2407                 }
2408         }
2409         (void) setvar_daemon(hat,
2410                              (Name) hat_list,
2411                              false,
2412                              chain_daemon,
2413                              false,
2414                              debug_level);
2415 
2416 /* We have two command sequences we need to handle */
2417 /* The old one that we probably read from .make.state */
2418 /* and the new one we are building that will replace the old one */
2419 /* Even when KEEP_STATE is not on we build a new command sequence and store */
2420 /* it in the line prop. This command sequence is then executed by */
2421 /* run_command(). If KEEP_STATE is on it is also later written to */
2422 /* .make.state. The routine replaces the old command line by line with the */
2423 /* new one trying to reuse Cmd_lines */
2424 
2425         /* If there is no old command_used we have to start creating */
2426         /* Cmd_lines to keep the new cmd in */
2427         if (used == NULL) {
2428                 new_command_longer = true;
2429                 *insert = used = ALLOC(Cmd_line);
2430                 used->next = NULL;
2431                 used->command_line = NULL;
2432                 insert = &used->next;
2433         }
2434         /* Run thru the template for the new command and build the expanded */
2435         /* new command lines */
2436         for (;
2437              command_template != NULL;
2438              command_template = command_template->next, insert = &used->next, used = *insert) {
2439                 /* If there is no old command_used Cmd_line we need to */
2440                 /* create one and say that cmd consistency failed */
2441                 if (used == NULL) {
2442                         new_command_longer = true;
2443                         *insert = used = ALLOC(Cmd_line);
2444                         used->next = NULL;
2445                         used->command_line = empty_name;
2446                 }
2447                 /* Prepare the Cmd_line for the processing */
2448                 /* The command line prefixes "@-=?" are stripped and that */
2449                 /* information is saved in the Cmd_line */
2450                 used->assign = false;
2451                 used->ignore_error = ignore_errors;
2452                 used->silent = silent;
2453                 used->always_exec = false;
2454                 /* Expand the macros in the command line */
2455                 INIT_STRING_FROM_STACK(command_line, buffer);
2456                 make_word_mentioned =
2457                   query_mentioned =
2458                     false;
2459                 expand_value(command_template->command_line, &command_line, true);
2460                 /* If the macro $(MAKE) is mentioned in the command */
2461                 /* "make -n" runs actually execute the command */
2462                 used->make_refd = make_word_mentioned;
2463                 used->ignore_command_dependency = query_mentioned;
2464                 /* Strip the prefixes */
2465                 start = command_line.buffer.start;
2466                 for (;
2467                      iswspace(*start) ||
2468                      (get_char_semantics_value(*start) & (int) command_prefix_sem);
2469                      start++) {
2470                         switch (*start) {
2471                         case question_char:
2472                                 used->ignore_command_dependency = true;
2473                                 break;
2474                         case exclam_char:
2475                                 used->ignore_command_dependency = false;
2476                                 break;
2477                         case equal_char:
2478                                 used->assign = true;
2479                                 break;
2480                         case hyphen_char:
2481                                 used->ignore_error = true;
2482                                 break;
2483                         case at_char:
2484                                 if (!do_not_exec_rule) {
2485                                         used->silent = true;
2486                                 }
2487                                 break;
2488                         case plus_char:
2489                                 if(posix) {
2490                                   used->always_exec  = true;
2491                                 }
2492                                 break;
2493                         }
2494                 }
2495                 /* If all command lines of the template are prefixed with "?"*/
2496                 /* the VIRTUAL_ROOT is not used for cmd consistency checks */
2497                 if (!used->ignore_command_dependency) {
2498                         ignore_all_command_dependency = false;
2499                 }
2500                 /* Internalize the expanded and stripped command line */
2501                 new_command_line = GETNAME(start, FIND_LENGTH);
2502                 if ((used->command_line == NULL) &&
2503                     (line->body.line.sccs_command)) {
2504                         used->command_line = new_command_line;
2505                         new_command_longer = false;
2506                 }
2507                 /* Compare it with the old one for command consistency */
2508                 if (used->command_line != new_command_line) {
2509                         Name vpath_translated = vpath_translation(new_command_line);
2510                         if (keep_state &&
2511                             !used->ignore_command_dependency && (vpath_translated != used->command_line)) {
2512                                 if (debug_level > 0) {
2513                                         if (used->command_line != NULL
2514                                             && *used->command_line->string_mb !=
2515                                             '\0') {
2516                                                 (void) printf(catgets(catd, 1, 32, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"),
2517                                                               recursion_level,
2518                                                               "",
2519                                                               target->string_mb,
2520                                                               vpath_translated->string_mb,
2521                                                               recursion_level,
2522                                                               "",
2523                                                               used->
2524                                                               command_line->
2525                                                               string_mb);
2526                                         } else {
2527                                                 (void) printf(catgets(catd, 1, 33, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"),
2528                                                               recursion_level,
2529                                                               "",
2530                                                               target->string_mb,
2531                                                               vpath_translated->string_mb,
2532                                                               recursion_level,
2533                                                               "");
2534                                         }
2535                                 }
2536                                 command_changed = true;
2537                                 line->body.line.is_out_of_date = true;
2538                         }
2539                         used->command_line = new_command_line;
2540                 }
2541                 if (command_line.free_after_use) {
2542                         retmem(command_line.buffer.start);
2543                 }
2544         }
2545         /* Check if the old command is longer than the new for */
2546         /* command consistency */
2547         if (used != NULL) {
2548                 *insert = NULL;
2549                 if (keep_state &&
2550                     !ignore_all_command_dependency) {
2551                         if (debug_level > 0) {
2552                                 (void) printf(catgets(catd, 1, 34, "%*sBuilding %s because new command shorter than old\n"),
2553                                               recursion_level,
2554                                               "",
2555                                               target->string_mb);
2556                         }
2557                         command_changed = true;
2558                         line->body.line.is_out_of_date = true;
2559                 }
2560         }
2561         /* Check if the new command is longer than the old command for */
2562         /* command consistency */
2563         if (new_command_longer &&
2564             !ignore_all_command_dependency &&
2565             keep_state) {
2566                 if (debug_level > 0) {
2567                         (void) printf(catgets(catd, 1, 35, "%*sBuilding %s because new command longer than old\n"),
2568                                       recursion_level,
2569                                       "",
2570                                       target->string_mb);
2571                 }
2572                 command_changed = true;
2573                 line->body.line.is_out_of_date = true;
2574         }
2575         /* Unbind the magic macros */
2576         (void) SETVAR(c_at, (Name) NULL, false);
2577         (void) SETVAR(star, (Name) NULL, false);
2578         (void) SETVAR(less_name, (Name) NULL, false);
2579         (void) SETVAR(percent_name, (Name) NULL, false);
2580         (void) SETVAR(query, (Name) NULL, false);
2581         if (query_list != NULL) {
2582                 delete_query_chain(query_list);
2583         }
2584         (void) SETVAR(hat, (Name) NULL, false);
2585         if (hat_list != NULL) {
2586                 delete_query_chain(hat_list);
2587         }
2588 
2589         if (conditional_macro_used) {
2590                 target->conditional_macro_list = cond_macro_list;
2591                 cond_macro_list = NULL;
2592                 target->depends_on_conditional = true;
2593         }
2594 }
2595 
2596 /*
2597  *      touch_command(line, target, result)
2598  *
2599  *      If this is an "make -t" run we do this.
2600  *      We touch all targets in the target group ("foo + fie:") if any.
2601  *
2602  *      Return value:
2603  *                              Indicates if the command failed or not
2604  *
2605  *      Parameters:
2606  *              line            The command line to update
2607  *              target          The target we are touching
2608  *              result          Initial value for the result we return
2609  *
2610  *      Global variables used:
2611  *              do_not_exec_rule Indicates that -n is on
2612  *              silent          Do not echo commands
2613  */
2614 static Doname
2615 touch_command(register Property line, register Name target, Doname result)
2616 {
2617         Name                    name;
2618         register Chain          target_group;
2619         String_rec              touch_string;
2620         wchar_t                 buffer[MAXPATHLEN];
2621         Name                    touch_cmd;
2622         Cmd_line                rule;
2623 
2624 
2625         SEND_MTOOL_MSG(
2626                 if (!sent_rsrc_info_msg) {
2627                         if (userName[0] == '\0') {
2628                                 avo_get_user(userName, NULL);
2629                         }
2630                         if (hostName[0] == '\0') {
2631                                 strcpy(hostName, avo_hostname());
2632                         }
2633                         send_rsrc_info_msg(1, hostName, userName);
2634                         sent_rsrc_info_msg = 1;
2635                 }
2636                 send_job_start_msg(line);
2637                 job_result_msg = new Avo_MToolJobResultMsg();
2638         );
2639         for (name = target, target_group = NULL; name != NULL;) {
2640                 if (!name->is_member) {
2641                         /*
2642                          * Build a touch command that can be passed
2643                          * to dosys(). If KEEP_STATE is on, "make -t"
2644                          * will save the proper command, not the
2645                          * "touch" in .make.state.
2646                          */
2647                         INIT_STRING_FROM_STACK(touch_string, buffer);
2648                         MBSTOWCS(wcs_buffer, NOCATGETS("touch "));
2649                         append_string(wcs_buffer, &touch_string, FIND_LENGTH);
2650                         touch_cmd = name;
2651                         if (name->has_vpath_alias_prop) {
2652                                 touch_cmd = get_prop(name->prop,
2653                                                  vpath_alias_prop)->
2654                                                    body.vpath_alias.alias;
2655                         }
2656                         APPEND_NAME(touch_cmd,
2657                                       &touch_string,
2658                                       FIND_LENGTH);
2659                         touch_cmd = GETNAME(touch_string.buffer.start,
2660                                             FIND_LENGTH);
2661                         if (touch_string.free_after_use) {
2662                                 retmem(touch_string.buffer.start);
2663                         }
2664                         if (!silent ||
2665                             do_not_exec_rule &&
2666                             (target_group == NULL)) {
2667                                 (void) printf("%s\n", touch_cmd->string_mb);
2668                                 SEND_MTOOL_MSG(
2669                                         job_result_msg->appendOutput(AVO_STRDUP(touch_cmd->string_mb));
2670                                 );
2671                         }
2672                         /* Run the touch command, or simulate it */
2673                         if (!do_not_exec_rule) {
2674 
2675                                 SEND_MTOOL_MSG(
2676                                         (void) sprintf(mbstring,
2677                                                         NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
2678                                                         tmpdir,
2679                                                         getpid(),
2680                                                         file_number++);
2681                                 
2682                                         int tmp_fd = mkstemp(mbstring);
2683                                         if(tmp_fd) {
2684                                                 (void) close(tmp_fd);
2685                                         }
2686 
2687                                         stdout_file = strdup(mbstring);
2688                                         stderr_file = NULL;
2689                                         child_pid = pollResults(stdout_file,
2690                                                                 (char *)NULL,
2691                                                                 (char *)NULL);
2692                                 );
2693 
2694                                 result = dosys(touch_cmd,
2695                                                false,
2696                                                false,
2697                                                false,
2698                                                false,
2699                                                name,
2700                                                send_mtool_msgs);
2701 
2702                                 SEND_MTOOL_MSG(
2703                                         append_job_result_msg(job_result_msg);
2704                                         if (child_pid > 0) {
2705                                                 kill(child_pid, SIGUSR1);
2706                                                 while (!((waitpid(child_pid, 0, 0) == -1)
2707                                                         && (errno == ECHILD)));
2708                                         }
2709                                         child_pid = 0;
2710                                         (void) unlink(stdout_file);
2711                                         retmem_mb(stdout_file);
2712                                         stdout_file = NULL;
2713                                 );
2714 
2715                         } else {
2716                                 result = build_ok;
2717                         }
2718                 } else {
2719                         result = build_ok;
2720                 }
2721                 if (target_group == NULL) {
2722                         target_group = line->body.line.target_group;
2723                 } else {
2724                         target_group = target_group->next;
2725                 }
2726                 if (target_group != NULL) {
2727                         name = target_group->name;
2728                 } else {
2729                         name = NULL;
2730                 }
2731         }
2732         SEND_MTOOL_MSG(
2733                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2734                 xdr_msg = (RWCollectable*) job_result_msg;
2735                 xdr(&xdrs, xdr_msg);
2736                 (void) fflush(mtool_msgs_fp);
2737                 delete job_result_msg;
2738         );
2739         return result;
2740 }
2741 
2742 /*
2743  *      update_target(line, result)
2744  *
2745  *      updates the status of a target after executing its commands.
2746  *
2747  *      Parameters:
2748  *              line            The command line block to update
2749  *              result          Indicates that build is OK so can update
2750  *
2751  *      Global variables used:
2752  *              do_not_exec_rule Indicates that -n is on
2753  *              touch           Fake the new timestamp if we are just touching
2754  */
2755 void
2756 update_target(Property line, Doname result)
2757 {
2758         Name                    target;
2759         Chain                   target_group;
2760         Property                line2;
2761         timestruc_t             old_stat_time;
2762         Property                member;
2763 
2764         /*
2765          * [tolik] Additional fix for bug 1063790. It was fixed
2766          * for serial make long ago, but DMake dumps core when
2767          * target is a symlink and sccs file is newer then target. 
2768          * In this case, finish_children() calls update_target()
2769          * with line==NULL.
2770          */
2771         if(line == NULL) {
2772                 /* XXX. Should we do anything here? */
2773                 return;
2774         }       
2775 
2776         target = line->body.line.target;
2777 
2778         if ((result == build_ok) && (line->body.line.command_used != NULL)) {
2779                 if (do_not_exec_rule ||
2780                     touch ||
2781                     (target->is_member &&
2782                      (line->body.line.command_template != NULL) &&
2783                      (line->body.line.command_template->command_line->string_mb[0] == 0) &&
2784                      (line->body.line.command_template->next == NULL))) {
2785                         /* If we are simulating execution we need to fake a */
2786                         /* new timestamp for the target we didnt build */
2787                         target->stat.time = file_max_time;
2788                 } else {
2789                         /*
2790                          * If we really built the target we read the new
2791                          * timestamp.
2792                          * Fix for bug #1110906: if .c file is newer than
2793                          * the corresponding .o file which is in an archive
2794                          * file, make will compile the .c file but it won't
2795                          * update the object in the .a file.
2796                          */
2797                         old_stat_time = target->stat.time;
2798                         target->stat.time = file_no_time;
2799                         (void) exists(target);
2800                         if ((target->is_member) &&
2801                             (target->stat.time == old_stat_time)) {
2802                                 member = get_prop(target->prop, member_prop);
2803                                 if (member != NULL) {
2804                                         target->stat.time = member->body.member.library->stat.time;
2805                                         target->stat.time.tv_sec++;
2806                                 }
2807                         }
2808                 }
2809                 /* If the target is part of a group we need to propagate the */
2810                 /* result of the run to all members */
2811                 for (target_group = line->body.line.target_group;
2812                      target_group != NULL;
2813                      target_group = target_group->next) {
2814                         target_group->name->stat.time = target->stat.time;
2815                         line2 = maybe_append_prop(target_group->name,
2816                                                   line_prop);
2817                         line2->body.line.command_used =
2818                           line->body.line.command_used;
2819                         line2->body.line.target = target_group->name;
2820                 }
2821         }
2822         target->has_built = true;
2823 }
2824 
2825 /*
2826  *      sccs_get(target, command)
2827  *
2828  *      Figures out if it possible to sccs get a file
2829  *      and builds the command to do it if it is.
2830  *
2831  *      Return value:
2832  *                              Indicates if sccs get failed or not
2833  *
2834  *      Parameters:
2835  *              target          Target to get
2836  *              command         Where to deposit command to use
2837  *
2838  *      Global variables used:
2839  *              debug_level     Should we trace activities?
2840  *              recursion_level Used for tracing
2841  *              sccs_get_rule   The rule to used for sccs getting
2842  */
2843 static Doname
2844 sccs_get(register Name target, register Property *command)
2845 {
2846         register int            result;
2847         char                    link[MAXPATHLEN];
2848         String_rec              string;
2849         wchar_t                 name[MAXPATHLEN];
2850         register wchar_t        *p;
2851         timestruc_t             sccs_time;
2852         register Property       line;
2853         int                     sym_link_depth = 0;
2854 
2855         /* For sccs, we need to chase symlinks. */
2856         while (target->stat.is_sym_link) {
2857                 if (sym_link_depth++ > 90) {
2858                         fatal(catgets(catd, 1, 95, "Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."),
2859                               target->string_mb);
2860                 }
2861                 /* Read the value of the link. */
2862                 result = readlink_vroot(target->string_mb,
2863                                         link,
2864                                         sizeof(link),
2865                                         NULL,
2866                                         VROOT_DEFAULT);
2867                 if (result == -1) {
2868                         fatal(catgets(catd, 1, 36, "Can't read symbolic link `%s': %s"),
2869                               target->string_mb, errmsg(errno));
2870                 }
2871                 link[result] = 0;
2872                 /* Use the value to build the proper filename. */
2873                 INIT_STRING_FROM_STACK(string, name);
2874 
2875                 Wstring wcb(target);
2876                 if ((link[0] != slash_char) &&
2877                     ((p = (wchar_t *) wsrchr(wcb.get_string(), slash_char)) != NULL)) {
2878                         append_string(wcb.get_string(), &string, p - wcb.get_string() + 1);
2879                 }
2880                 append_string(link, &string, result);
2881                 /* Replace the old name with the translated name. */
2882                 target = normalize_name(string.buffer.start, string.text.p - string.buffer.start);
2883                 (void) exists(target);
2884                 if (string.free_after_use) {
2885                         retmem(string.buffer.start);
2886                 }
2887         }
2888 
2889         /*
2890          * read_dir() also reads the ?/SCCS dir and saves information
2891          * about which files have SCSC/s. files.
2892          */
2893         if (target->stat.has_sccs == DONT_KNOW_SCCS) {
2894                 read_directory_of_file(target);
2895         }
2896         switch (target->stat.has_sccs) {
2897         case DONT_KNOW_SCCS:
2898                 /* We dont know by now there is no SCCS/s.* */
2899                 target->stat.has_sccs = NO_SCCS;
2900         case NO_SCCS:
2901                 /*
2902                  * If there is no SCCS/s.* but the plain file exists,
2903                  * we say things are OK.
2904                  */
2905                 if (target->stat.time > file_doesnt_exist) {
2906                         return build_ok;
2907                 }
2908                 /* If we cant find the plain file, we give up. */
2909                 return build_dont_know;
2910         case HAS_SCCS:
2911                 /*
2912                  * Pay dirt. We now need to figure out if the plain file
2913                  * is out of date relative to the SCCS/s.* file.
2914                  */
2915                 sccs_time = exists(get_prop(target->prop,
2916                                             sccs_prop)->body.sccs.file);
2917                 break;
2918         }
2919 
2920         if ((!target->has_complained &&
2921             (sccs_time != file_doesnt_exist) &&
2922             (sccs_get_rule != NULL))) {
2923                 /* only checking */
2924                 if (command == NULL) {
2925                         return build_ok;
2926                 }
2927                 /*
2928                  * We provide a command line for the target. The line is a
2929                  * "sccs get" command from default.mk.
2930                  */
2931                 line = maybe_append_prop(target, line_prop);
2932                 *command = line;
2933                 if (sccs_time > target->stat.time) {
2934                         /*
2935                          * And only if the plain file is out of date do we
2936                          * request execution of the command.
2937                          */
2938                         line->body.line.is_out_of_date = true;
2939                         if (debug_level > 0) {
2940                                 (void) printf(catgets(catd, 1, 37, "%*sSccs getting %s because s. file is younger than source file\n"),
2941                                               recursion_level,
2942                                               "",
2943                                               target->string_mb);
2944                         }
2945                 }
2946                 line->body.line.sccs_command = true;
2947                 line->body.line.command_template = sccs_get_rule;
2948                 if(!svr4 && (!allrules_read || posix)) {
2949                    if((target->prop) &&
2950                       (target->prop->body.sccs.file) &&
2951                       (target->prop->body.sccs.file->string_mb)) {
2952                       if((strlen(target->prop->body.sccs.file->string_mb) ==
2953                         strlen(target->string_mb) + 2) && 
2954                         (target->prop->body.sccs.file->string_mb[0] == 's') &&
2955                         (target->prop->body.sccs.file->string_mb[1] == '.')) {
2956 
2957                          line->body.line.command_template = get_posix_rule;
2958                       }
2959                    }
2960                 }
2961                 line->body.line.target = target;
2962                 /*
2963                  * Also make sure the rule is build with $* and $<
2964                  * bound properly.
2965                  */
2966                 line->body.line.star = NULL;
2967                 line->body.line.less = NULL;
2968                 line->body.line.percent = NULL;
2969                 return build_ok;
2970         }
2971         return build_dont_know;
2972 }
2973 
2974 /*
2975  *      read_directory_of_file(file)
2976  *
2977  *      Reads the directory the specified file lives in.
2978  *
2979  *      Parameters:
2980  *              file            The file we need to read dir for
2981  *
2982  *      Global variables used:
2983  *              dot             The Name ".", used as the default dir
2984  */
2985 void
2986 read_directory_of_file(register Name file)
2987 {
2988 
2989         Wstring file_string(file);
2990         wchar_t * wcb = file_string.get_string();
2991         wchar_t usr_include_buf[MAXPATHLEN];
2992         wchar_t usr_include_sys_buf[MAXPATHLEN];
2993 
2994         register Name           directory = dot;
2995         register wchar_t        *p = (wchar_t *) wsrchr(wcb,
2996                                                         (int) slash_char);
2997         register int            length = p - wcb;
2998         static Name             usr_include;
2999         static Name             usr_include_sys;
3000 
3001         if (usr_include == NULL) {
3002                 MBSTOWCS(usr_include_buf, NOCATGETS("/usr/include"));
3003                 usr_include = GETNAME(usr_include_buf, FIND_LENGTH);
3004                 MBSTOWCS(usr_include_sys_buf, NOCATGETS("/usr/include/sys"));
3005                 usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH);
3006         }
3007 
3008         /*
3009          * If the filename contains a "/" we have to extract the path
3010          * Else the path defaults to ".".
3011          */
3012         if (p != NULL) {
3013                 /*
3014                  * Check some popular directories first to possibly
3015                  * save time. Compare string length first to gain speed.
3016                  */
3017                 if ((usr_include->hash.length == length) &&
3018                     IS_WEQUALN(usr_include_buf,
3019                                wcb,
3020                                length)) {
3021                         directory = usr_include;
3022                 } else if ((usr_include_sys->hash.length == length) &&
3023                            IS_WEQUALN(usr_include_sys_buf,
3024                                       wcb,
3025                                       length)) {
3026                         directory = usr_include_sys;
3027                 } else {
3028                         directory = GETNAME(wcb, length);
3029                 }
3030         }
3031         (void) read_dir(directory,
3032                         (wchar_t *) NULL,
3033                         (Property) NULL,
3034                         (wchar_t *) NULL);
3035 }
3036 
3037 /*
3038  *      add_pattern_conditionals(target)
3039  *
3040  *      Scan the list of conditionals defined for pattern targets and add any
3041  *      that match this target to its list of conditionals.
3042  *
3043  *      Parameters:
3044  *              target          The target we should add conditionals for
3045  *
3046  *      Global variables used:
3047  *              conditionals    The list of pattern conditionals
3048  */
3049 static void
3050 add_pattern_conditionals(register Name target)
3051 {
3052         register Property       conditional;
3053         Property                new_prop;
3054         Property                *previous;
3055         Name_rec                dummy;
3056         wchar_t                 *pattern;
3057         wchar_t                 *percent;
3058         int                     length;
3059 
3060         Wstring wcb(target);
3061         Wstring wcb1;
3062 
3063         for (conditional = get_prop(conditionals->prop, conditional_prop);
3064              conditional != NULL;
3065              conditional = get_prop(conditional->next, conditional_prop)) {
3066                 wcb1.init(conditional->body.conditional.target);
3067                 pattern = wcb1.get_string();
3068                 if (pattern[1] != 0) {
3069                         percent = (wchar_t *) wschr(pattern, (int) percent_char);
3070                         if (!wcb.equaln(pattern, percent-pattern) ||
3071                             !IS_WEQUAL(wcb.get_string(wcb.length()-wslen(percent+1)), percent+1)) {
3072                                 continue;
3073                         }
3074                 }
3075                 for (previous = &target->prop;
3076                      *previous != NULL;
3077                      previous = &(*previous)->next) {
3078                         if (((*previous)->type == conditional_prop) &&
3079                             ((*previous)->body.conditional.sequence >
3080                              conditional->body.conditional.sequence)) {
3081                                 break;
3082                         }
3083                 }
3084                 if (*previous == NULL) {
3085                         new_prop = append_prop(target, conditional_prop);
3086                 } else {
3087                         dummy.prop = NULL;
3088                         new_prop = append_prop(&dummy, conditional_prop);
3089                         new_prop->next = *previous;
3090                         *previous = new_prop;
3091                 }
3092                 target->conditional_cnt++;
3093                 new_prop->body.conditional = conditional->body.conditional;
3094         }
3095 }
3096 
3097 /*
3098  *      set_locals(target, old_locals)
3099  *
3100  *      Sets any conditional macros for the target.
3101  *      Each target carries a possibly empty set of conditional properties.
3102  *
3103  *      Parameters:
3104  *              target          The target to set conditional macros for
3105  *              old_locals      Space to store old values in
3106  *
3107  *      Global variables used:
3108  *              debug_level     Should we trace activity?
3109  *              is_conditional  We need to preserve this value
3110  *              recursion_level Used for tracing
3111  */
3112 void
3113 set_locals(register Name target, register Property old_locals)
3114 {
3115         register Property       conditional;
3116         register int            i;
3117         register Boolean        saved_conditional_macro_used;
3118         Chain                   cond_name;
3119         Chain                   cond_chain;
3120 
3121         if (target->dont_activate_cond_values) {
3122                 return;
3123         }
3124 
3125         saved_conditional_macro_used = conditional_macro_used;
3126 
3127         /* Scan the list of conditional properties and apply each one */
3128         for (conditional = get_prop(target->prop, conditional_prop), i = 0;
3129              conditional != NULL;
3130              conditional = get_prop(conditional->next, conditional_prop),
3131              i++) {
3132                 /* Save the old value */
3133                 old_locals[i].body.macro =
3134                   maybe_append_prop(conditional->body.conditional.name,
3135                                     macro_prop)->body.macro;
3136                 if (debug_level > 1) {
3137                         (void) printf(catgets(catd, 1, 38, "%*sActivating conditional value: "),
3138                                       recursion_level,
3139                                       "");
3140                 }
3141                 /* Set the conditional value. Macros are expanded when the */
3142                 /* macro is refd as usual */
3143                 if ((conditional->body.conditional.name != virtual_root) ||
3144                     (conditional->body.conditional.value != virtual_root)) {
3145                         (void) SETVAR(conditional->body.conditional.name,
3146                                       conditional->body.conditional.value,
3147                                       (Boolean) conditional->body.conditional.append);
3148                 }
3149                 cond_name = ALLOC(Chain);
3150                 cond_name->name = conditional->body.conditional.name;
3151         }
3152         /* Put this target on the front of the chain of conditional targets */
3153         cond_chain = ALLOC(Chain);
3154         cond_chain->name = target;
3155         cond_chain->next = conditional_targets;
3156         conditional_targets = cond_chain;
3157         conditional_macro_used = saved_conditional_macro_used;
3158 }
3159 
3160 /*
3161  *      reset_locals(target, old_locals, conditional, index)
3162  *
3163  *      Removes any conditional macros for the target.
3164  *
3165  *      Parameters:
3166  *              target          The target we are retoring values for
3167  *              old_locals      The values to restore
3168  *              conditional     The first conditional block for the target
3169  *              index           into the old_locals vector
3170  *      Global variables used:
3171  *              debug_level     Should we trace activities?
3172  *              recursion_level Used for tracing
3173  */
3174 void
3175 reset_locals(register Name target, register Property old_locals, register Property conditional, register int index)
3176 {
3177         register Property       this_conditional;
3178         Chain                   cond_chain;
3179 
3180         if (target->dont_activate_cond_values) {
3181                 return;
3182         }
3183 
3184         /* Scan the list of conditional properties and restore the old value */
3185         /* to each one Reverse the order relative to when we assigned macros */
3186         this_conditional = get_prop(conditional->next, conditional_prop);
3187         if (this_conditional != NULL) {
3188                 reset_locals(target, old_locals, this_conditional, index+1);
3189         } else {
3190                 /* Remove conditional target from chain */
3191                 if (conditional_targets == NULL ||
3192                     conditional_targets->name != target) {
3193                         warning(catgets(catd, 1, 39, "Internal error: reset target not at head of condtional_targets chain"));
3194                 } else {
3195                         cond_chain = conditional_targets->next;
3196                         retmem_mb((caddr_t) conditional_targets);
3197                         conditional_targets = cond_chain;
3198                 }
3199         }
3200         get_prop(conditional->body.conditional.name->prop,
3201                  macro_prop)->body.macro = old_locals[index].body.macro;
3202         if (conditional->body.conditional.name == virtual_root) {
3203                 (void) SETVAR(virtual_root, getvar(virtual_root), false);
3204         }
3205         if (debug_level > 1) {
3206                 if (old_locals[index].body.macro.value != NULL) {
3207                         (void) printf(catgets(catd, 1, 40, "%*sdeactivating conditional value: %s= %s\n"),
3208                                       recursion_level,
3209                                       "",
3210                                       conditional->body.conditional.name->
3211                                       string_mb,
3212                                       old_locals[index].body.macro.value->
3213                                       string_mb);
3214                 } else {
3215                         (void) printf(catgets(catd, 1, 41, "%*sdeactivating conditional value: %s =\n"),
3216                                       recursion_level,
3217                                       "",
3218                                       conditional->body.conditional.name->
3219                                       string_mb);
3220                 }
3221         }
3222 }
3223 
3224 /*
3225  *      check_auto_dependencies(target, auto_count, automatics)
3226  *
3227  *      Returns true if the target now has a dependency
3228  *      it didn't previously have (saved on automatics).
3229  *
3230  *      Return value:
3231  *                              true if new dependency found
3232  *
3233  *      Parameters:
3234  *              target          Target we check
3235  *              auto_count      Number of old automatic vars
3236  *              automatics      Saved old automatics
3237  *
3238  *      Global variables used:
3239  *              keep_state      Indicates that .KEEP_STATE is on
3240  */
3241 Boolean
3242 check_auto_dependencies(Name target, int auto_count, Name *automatics)
3243 {
3244         Name            *p;
3245         int             n;
3246         Property        line;
3247         Dependency      dependency;
3248 
3249         if (keep_state) {
3250                 if ((line = get_prop(target->prop, line_prop)) == NULL) {
3251                         return false;
3252                 }
3253                 /* Go thru new list of automatic depes */
3254                 for (dependency = line->body.line.dependencies;
3255                      dependency != NULL;
3256                      dependency = dependency->next) {
3257                         /* And make sure that each one existed before we */
3258                         /* built the target */
3259                         if (dependency->automatic && !dependency->stale) {
3260                                 for (n = auto_count, p = automatics;
3261                                      n > 0;
3262                                      n--) {
3263                                         if (*p++ == dependency->name) {
3264                                                 /* If we can find it on the */
3265                                                 /* saved list of autos we */
3266                                                 /* are OK  */
3267                                                 goto not_new;
3268                                         }
3269                                 }
3270                                 /* But if we scan over the old list */
3271                                 /* of auto. without finding it it is */
3272                                 /* new and we must check it */
3273                                 return true;
3274                         }
3275                 not_new:;
3276                 }
3277                 return false;
3278         } else {
3279                 return false;
3280         }
3281 }
3282 
3283 
3284 // Recursively delete each of the Chain struct on the chain.
3285 
3286 static void
3287 delete_query_chain(Chain ch)
3288 {
3289         if (ch == NULL) {
3290                 return;
3291         } else {
3292                 delete_query_chain(ch->next);
3293                 retmem_mb((char *) ch);
3294         }
3295 }
3296 
3297 Doname
3298 target_can_be_built(register Name target) {
3299         Doname          result = build_dont_know;
3300         Name            true_target = target;
3301         Property        line;
3302 
3303         if (target == wait_name) {
3304                 return(build_ok);
3305         }
3306         /*
3307          * If the target is a constructed one for a "::" target,
3308          * we need to consider that.
3309          */
3310         if (target->has_target_prop) {
3311                 true_target = get_prop(target->prop,
3312                                        target_prop)->body.target.target;
3313         }
3314 
3315         (void) exists(true_target);
3316 
3317         if (true_target->state == build_running) {
3318                 return(build_running);
3319         }
3320         if (true_target->stat.time != file_doesnt_exist) {
3321                 result = build_ok;
3322         }
3323 
3324         /* get line property for the target */
3325         line = get_prop(true_target->prop, line_prop);
3326 
3327         /* first check for explicit rule */
3328         if (line != NULL && line->body.line.command_template != NULL) {
3329                 result = build_ok;
3330         }
3331         /* try to find pattern rule */
3332         if (result == build_dont_know) {
3333                 result = find_percent_rule(target, NULL, false);
3334         }
3335         
3336         /* try to find double suffix rule */
3337         if (result == build_dont_know) {
3338                 if (target->is_member) {
3339                         Property member = get_prop(target->prop, member_prop);
3340                         if (member != NULL && member->body.member.member != NULL) {
3341                                 result = find_ar_suffix_rule(target, member->body.member.member, NULL, false);
3342                         } else {
3343                                 result = find_double_suffix_rule(target, NULL, false);
3344                         }
3345                 } else {
3346                         result = find_double_suffix_rule(target, NULL, false);
3347                 }
3348         }
3349         
3350         /* try to find suffix rule */
3351         if ((result == build_dont_know) && second_pass) {
3352                 result = find_suffix_rule(target, target, empty_name, NULL, false);
3353         }
3354         
3355         /* check for sccs */
3356         if (result == build_dont_know) {
3357                 result = sccs_get(target, NULL);
3358         }
3359         
3360         /* try to find dyn target */
3361         if (result == build_dont_know) {
3362                 Name dtarg = find_dyntarget(target);
3363                 if (dtarg != NULL) {
3364                         result = target_can_be_built(dtarg);
3365                 }
3366         }
3367         
3368         /* check whether target was mentioned in makefile */
3369         if (result == build_dont_know) {
3370                 if (target->colons != no_colon) {
3371                         result = build_ok;
3372                 }
3373         }
3374 
3375         /* result */
3376         return result;
3377 }