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