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