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