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