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