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