"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/sunpro/Make/bin/make/common/doname.cc" (16 Aug 2021, 108710 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


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