root/usr/src/cmd/make/bin/doname.cc
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * Use is subject to license terms.
 *
 * Copyright (c) 2016 by Delphix. All rights reserved.
 * Copyright 2019 RackTop Systems.
 */

/*
 *      doname.c
 *
 *      Figure out which targets are out of date and rebuild them
 */

/*
 * Included files
 */
#include <alloca.h>             /* alloca() */
#include <fcntl.h>
#include <mk/defs.h>
#include <mksh/i18n.h>          /* get_char_semantics_value() */
#include <mksh/macro.h>         /* getvar(), expand_value() */
#include <mksh/misc.h>          /* getmem() */
#include <poll.h>
#include <libintl.h>
#include <signal.h>
#include <stropts.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>        /* uname() */
#include <sys/wait.h>
#include <unistd.h>             /* close() */

/*
 * Defined macros
 */
#       define LOCALHOST "localhost"

#define MAXRULES 100

// Sleep for .1 seconds between stat()'s
const int       STAT_RETRY_SLEEP_TIME = 100000;

/*
 * typedefs & structs
 */

/*
 * Static variables
 */
static char     hostName[MAXNAMELEN] = "";
static char     userName[MAXNAMELEN] = "";


static int      second_pass = 0;

/*
 * File table of contents
 */
extern  Doname          doname_check(Name target, Boolean do_get, Boolean implicit, Boolean automatic);
extern  Doname          doname(Name target, Boolean do_get, Boolean implicit, Boolean automatic);
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);
void            dynamic_dependencies(Name target);
static  Doname          run_command(Property line, Boolean print_machine);
extern  Doname          execute_serial(Property line);
extern  Name            vpath_translation(Name cmd);
extern  void            check_state(Name temp_file_name);
static  void            read_dependency_file(Name filename);
static  void            check_read_state_file(void);
static  void            do_assign(Name line, Name target);
static  void            build_command_strings(Name target, Property line);
static  Doname          touch_command(Property line, Name target, Doname result);
extern  void            update_target(Property line, Doname result);
static  Doname          sccs_get(Name target, Property *command);
extern  void            read_directory_of_file(Name file);
static  void            add_pattern_conditionals(Name target);
extern  void            set_locals(Name target, Property old_locals);
extern  void            reset_locals(Name target, Property old_locals, Property conditional, int index);
extern  Boolean         check_auto_dependencies(Name target, int auto_count, Name *automatics);
static  void            delete_query_chain(Chain ch);

// From read2.cc
extern  Name            normalize_name(wchar_t *name_string, int length);



/*
 * DONE.
 *
 *      doname_check(target, do_get, implicit, automatic)
 *
 *      Will call doname() and then inspect the return value
 *
 *      Return value:
 *                              Indication if the build failed or not
 *
 *      Parameters:
 *              target          The target to build
 *              do_get          Passed thru to doname()
 *              implicit        Passed thru to doname()
 *              automatic       Are we building a hidden dependency?
 *
 *      Global variables used:
 *              build_failed_seen       Set if -k is on and error occurs
 *              continue_after_error    Indicates that -k is on
 *              report_dependencies     No error msg if -P is on
 */
Doname
doname_check(Name target, Boolean do_get, Boolean implicit, Boolean automatic)
{
        int first_time = 1;
        Doname rv = build_failed;

        (void) fflush(stdout);
try_again:
        switch (doname(target, do_get, implicit, automatic)) {
        case build_ok:
                second_pass = 0;
                rv = build_ok;
                break;
        case build_running:
                second_pass = 0;
                rv = build_running;
                break;
        case build_failed:
                if (!continue_after_error) {
                        fatal(
                            gettext("Target `%s' not remade because of errors"),
                            target->string_mb);
                }
                build_failed_seen = true;
                second_pass = 0;
                rv = build_failed;
                break;
        case build_dont_know:
                /*
                 * If we can't figure out how to build an automatic
                 * (hidden) dependency, we just ignore it.
                 * We later declare the target to be out of date just in
                 * case something changed.
                 * Also, don't complain if just reporting the dependencies
                 * and not building anything.
                 */
                if (automatic || (report_dependencies_level > 0)) {
                        second_pass = 0;
                        rv = build_dont_know;
                        break;
                }
                if(first_time) {
                        first_time = 0;
                        second_pass = 1;
                        goto try_again;
                }
                second_pass = 0;
                if (continue_after_error && !svr4) {
                        warning(gettext("Don't know how to make target `%s'"),
                                target->string_mb);
                        build_failed_seen = true;
                        rv = build_failed;
                        break;
                }
                fatal(gettext("Don't know how to make target `%s'"),
                    target->string_mb);
                break;
        }
        return (rv);
}


void
enter_explicit_rule_from_dynamic_rule(Name target, Name source)
{
        Property line, source_line;
        Dependency dependency;

        source_line = get_prop(source->prop, line_prop);
        line = maybe_append_prop(target, line_prop);
        line->body.line.sccs_command = false;
        line->body.line.target = target;
        if (line->body.line.command_template == NULL) {
                line->body.line.command_template = source_line->body.line.command_template;
                for (dependency = source_line->body.line.dependencies;
                     dependency != NULL;
                     dependency = dependency->next) {
                        enter_dependency(line, dependency->name, false);
                }
                line->body.line.less = target;
        }
        line->body.line.percent = NULL;
}



Name
find_dyntarget(Name target)
{
        Dyntarget               p;
        int                     i;
        String_rec              string;
        wchar_t                 buffer[STRING_BUFFER_LENGTH];
        wchar_t                 *pp, * bufend;
        wchar_t                 tbuffer[MAXPATHLEN];
        Wstring                 wcb(target);

        for (p = dyntarget_list; p != NULL; p = p->next) {
                INIT_STRING_FROM_STACK(string, buffer);
                expand_value(p->name, &string, false);
                i = 0;
                pp = string.buffer.start;
                bufend = pp + STRING_BUFFER_LENGTH;
                while((*pp != nul_char) && (pp < bufend)) {
                        if(iswspace(*pp)) {
                                tbuffer[i] = nul_char;
                                if(i > 0) {
                                        if (wcb.equal(tbuffer)) {
                                                enter_explicit_rule_from_dynamic_rule(target, p->name);
                                                return(target);
                                        }
                                }
                                pp++;
                                i = 0;
                                continue;
                        }
                        tbuffer[i] = *pp;
                        i++;
                        pp++;
                        if(*pp == nul_char) {
                                tbuffer[i] = nul_char;
                                if(i > 0) {
                                        if (wcb.equal(tbuffer)) {
                                                enter_explicit_rule_from_dynamic_rule(target, p->name);
                                                return(target);
                                        }
                                }
                                break;
                        }
                }
        }
        return(NULL);
}

/*
 * DONE.
 *
 *      doname(target, do_get, implicit)
 *
 *      Chases all files the target depends on and builds any that
 *      are out of date. If the target is out of date it is then rebuilt.
 *
 *      Return value:
 *                              Indiates if build failed or nt
 *
 *      Parameters:
 *              target          Target to build
 *              do_get          Run sccs get is nessecary
 *              implicit        doname is trying to find an implicit rule
 *
 *      Global variables used:
 *              assign_done     True if command line assgnment has happened
 *              commands_done   Preserved for the case that we need local value
 *              debug_level     Should we trace make's actions?
 *              default_rule    The rule for ".DEFAULT", used as last resort
 *              empty_name      The Name "", used when looking for single sfx
 *              keep_state      Indicates that .KEEP_STATE is on
 *              parallel        True if building in parallel
 *              recursion_level Used for tracing
 *              report_dependencies make -P is on
 */
Doname
doname(Name target, Boolean do_get, Boolean implicit, Boolean automatic)
{
        Doname                  result = build_dont_know;
        Chain                   out_of_date_list = NULL;
        Chain                   target_group;
        Property                old_locals = NULL;
        Property        line;
        Property                command = NULL;
        Dependency      dependency;
        Name                    less = NULL;
        Name                    true_target = target;
        Name                    *automatics = NULL;
        int             auto_count;
        Boolean                 rechecking_target = false;
        Boolean                 saved_commands_done;
        Boolean                 restart = false;
        Boolean                 save_parallel = parallel;
        Boolean                 doing_subtree = false;

        Boolean                 recheck_conditionals = false;

        if (target->state == build_running) {
                return build_running;
        }
        line = get_prop(target->prop, line_prop);
        if (line != NULL) {
                /*
                 * If this target is a member of target group and one of the
                 * other members of the group is running, mark this target
                 * as running.
                 */
                for (target_group = line->body.line.target_group;
                     target_group != NULL;
                     target_group = target_group->next) {
                        if (is_running(target_group->name)) {
                                target->state = build_running;
                                add_pending(target,
                                            recursion_level,
                                            do_get,
                                            implicit,
                                            false);
                                return build_running;
                        }
                }
        }
        /*
         * If the target is a constructed one for a "::" target,
         * we need to consider that.
         */
        if (target->has_target_prop) {
                true_target = get_prop(target->prop,
                                       target_prop)->body.target.target;
                if (true_target->colon_splits > 0) {
                        /* Make sure we have a valid time for :: targets */
                        Property        time;

                        time = get_prop(true_target->prop, time_prop);
                        if (time != NULL) {
                                true_target->stat.time = time->body.time.time;
                        }
                }
        }
        (void) exists(true_target);
        /*
         * If the target has been processed, we don't need to do it again,
         * unless it depends on conditional macros or a delayed assignment,
         * or it has been done when KEEP_STATE is on.
         */
        if (target->state == build_ok) {
                if((!keep_state || (!target->depends_on_conditional && !assign_done))) {
                        return build_ok;
                } else {
                        recheck_conditionals = true;
                }
        }
        if (target->state == build_subtree) {
                /* A dynamic macro subtree is being built */
                target->state = build_dont_know;
                doing_subtree = true;
                if (!target->checking_subtree) {
                        /*
                         * This target has been started before and therefore
                         * not all dependencies have to be built.
                         */
                        restart = true;
                }
        } else if (target->state == build_pending) {
                target->state = build_dont_know;
                restart = true;
/*
        } else if (parallel &&
                   keep_state &&
                   (target->conditional_cnt > 0)) {
            if (!parallel_ok(target, false)) {
                add_subtree(target, recursion_level, do_get, implicit);
                target->state = build_running;
                return build_running;
            }
 */
        }
        /*
         * If KEEP_STATE is on, we have to rebuild the target if the
         * building of it caused new automatic dependencies to be reported.
         * This is where we restart the build.
         */
        if (line != NULL) {
                line->body.line.percent = NULL;
        }
recheck_target:
        /* Init all local variables */
        result = build_dont_know;
        out_of_date_list = NULL;
        command = NULL;
        less = NULL;
        auto_count = 0;
        if (!restart && line != NULL) {
                /*
                 * If this target has never been built before, mark all
                 * of the dependencies as never built.
                 */
                for (dependency = line->body.line.dependencies;
                     dependency != NULL;
                     dependency = dependency->next) {
                        dependency->built = false;
                }
        }
        /* Save the set of automatic depes defined for this target */
        if (keep_state &&
            (line != NULL) &&
            (line->body.line.dependencies != NULL)) {
                Name *p;

                /*
                 * First run thru the dependency list to see how many
                 * autos there are.
                 */
                for (dependency = line->body.line.dependencies;
                     dependency != NULL;
                     dependency = dependency->next) {
                        if (dependency->automatic && !dependency->stale) {
                                auto_count++;
                        }
                }
                /* Create vector to hold the current autos */
                automatics =
                  (Name *) alloca((int) (auto_count * sizeof (Name)));
                /* Copy them */
                for (p = automatics, dependency = line->body.line.dependencies;
                     dependency != NULL;
                     dependency = dependency->next) {
                        if (dependency->automatic && !dependency->stale) {
                                *p++ = dependency->name;
                        }
                }
        }
        if (debug_level > 1) {
                (void) printf("%*sdoname(%s)\n",
                              recursion_level,
                              "",
                              target->string_mb);
        }
        recursion_level++;
        /* Avoid infinite loops */
        if (target->state == build_in_progress) {
                warning(gettext("Infinite loop: Target `%s' depends on itself"),
                        target->string_mb);
                return build_ok;
        }
        target->state = build_in_progress;

        /* Activate conditional macros for the target */
        if (!target->added_pattern_conditionals) {
                add_pattern_conditionals(target);
                target->added_pattern_conditionals = true;
        }
        if (target->conditional_cnt > 0) {
                old_locals = (Property) alloca(target->conditional_cnt *
                                               sizeof (Property_rec));
                set_locals(target, old_locals);
        }

/*
 * after making the call to dynamic_dependecies unconditional we can handle
 * target names that are same as file name. In this case $$@ in the
 * dependencies did not mean anything. WIth this change it expands it
 * as expected.
 */
        if (!target->has_depe_list_expanded)
        {
                dynamic_dependencies(target);
        }

/*
 *      FIRST SECTION -- GO THROUGH DEPENDENCIES AND COLLECT EXPLICIT
 *      COMMANDS TO RUN
 */
        if ((line = get_prop(target->prop, line_prop)) != NULL) {
                if (check_dependencies(&result,
                                       line,
                                       do_get,
                                       target,
                                       true_target,
                                       doing_subtree,
                                       &out_of_date_list,
                                       old_locals,
                                       implicit,
                                       &command,
                                       less,
                                       rechecking_target,
                                       recheck_conditionals)) {
                        return build_running;
                }
                if (line->body.line.query != NULL) {
                        delete_query_chain(line->body.line.query);
                }
                line->body.line.query = out_of_date_list;
        }


/*
 * If the target is a :: type, do not try to find the rule for the target,
 * all actions will be taken by separate branches.
 * Else, we try to find an implicit rule using various methods,
 * we quit as soon as one is found.
 *
 * [tolik, 12 Sep 2002] Do not try to find implicit rule for the target
 * being rechecked - the target is being rechecked means that it already
 * has explicit dependencies derived from an implicit rule found
 * in previous step.
 */
        if (target->colon_splits == 0 && !rechecking_target) {
                /* Look for percent matched rule */
                if ((result == build_dont_know) &&
                    (command == NULL)) {
                        switch (find_percent_rule(
                                        target,
                                        &command,
                                        recheck_conditionals)) {
                        case build_failed:
                                result = build_failed;
                                break;
                        case build_running:
                                target->state = build_running;
                                add_pending(target,
                                            --recursion_level,
                                            do_get,
                                            implicit,
                                            false);
                                if (target->conditional_cnt > 0) {
                                        reset_locals(target,
                                                     old_locals,
                                                     get_prop(target->prop,
                                                             conditional_prop),
                                                     0);
                                }
                                return build_running;
                        case build_ok:
                                result = build_ok;
                                break;
                        }
                }
                /* Look for double suffix rule */
                if (result == build_dont_know) {
                        Property member;

                        if (target->is_member &&
                            ((member = get_prop(target->prop, member_prop)) !=
                             NULL)) {
                                switch (find_ar_suffix_rule(target,
                                                member->body.
                                                member.member,
                                                &command,
                                                recheck_conditionals)) {
                                case build_failed:
                                        result = build_failed;
                                        break;
                                case build_running:
                                        target->state = build_running;
                                        add_pending(target,
                                                    --recursion_level,
                                                    do_get,
                                                    implicit,
                                                    false);
                                    if (target->conditional_cnt > 0) {
                                            reset_locals(target,
                                                         old_locals,
                                                         get_prop(target->prop,
                                                             conditional_prop),
                                                         0);
                                    }
                                        return build_running;
                                default:
                                        /* ALWAYS bind $% for old style */
                                        /* ar rules */
                                        if (line == NULL) {
                                                line =
                                                  maybe_append_prop(target,
                                                                    line_prop);
                                        }
                                        line->body.line.percent =
                                          member->body.member.member;
                                        break;
                                }
                        } else {
                                switch (find_double_suffix_rule(target,
                                                &command,
                                                recheck_conditionals)) {
                                case build_failed:
                                        result = build_failed;
                                        break;
                                case build_running:
                                        target->state = build_running;
                                        add_pending(target,
                                                    --recursion_level,
                                                    do_get,
                                                    implicit,
                                                    false);
                                        if (target->conditional_cnt > 0) {
                                                reset_locals(target,
                                                             old_locals,
                                                             get_prop(target->
                                                                      prop,
                                                                      conditional_prop),
                                                             0);
                                        }
                                        return build_running;
                                }
                        }
                }
                /* Look for single suffix rule */

/* /tolik/
 * I commented !implicit to fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
 * This caused problem with SVR4 tilde rules (infinite recursion). So I made some changes in "implicit.cc"
 */
/* /tolik, 06.21.96/
 * Regression! See BugId 1255360
 * If more than one percent rules are defined for the same target then
 * the behaviour of 'make' with my previous fix may be different from one
 * of the 'old make'.
 * The global variable second_pass (maybe it should be an argument to doname())
 * is intended to avoid this regression. It is set in doname_check().
 * First, 'make' will work as it worked before. Only when it is
 * going to say "don't know how to make target" it sets second_pass to true and
 * run 'doname' again but now trying to use Single Suffix Rules.
 */
                if ((result == build_dont_know) && !automatic && (!implicit || second_pass) &&
                    ((line == NULL) ||
                     ((line->body.line.target != NULL) &&
                      !line->body.line.target->has_regular_dependency))) {
                        switch (find_suffix_rule(target,
                                                 target,
                                                 empty_name,
                                                 &command,
                                                 recheck_conditionals)) {
                        case build_failed:
                                result = build_failed;
                                break;
                        case build_running:
                                target->state = build_running;
                                add_pending(target,
                                            --recursion_level,
                                            do_get,
                                            implicit,
                                            false);
                                if (target->conditional_cnt > 0) {
                                        reset_locals(target,
                                                     old_locals,
                                                     get_prop(target->prop,
                                                             conditional_prop),
                                                     0);
                                }
                                return build_running;
                        }
                }
                /* Try to sccs get */
                if ((command == NULL) &&
                    (result == build_dont_know) &&
                    do_get) {
                        result = sccs_get(target, &command);
                }

                /* Use .DEFAULT rule if it is defined. */
                if ((command == NULL) &&
                    (result == build_dont_know) &&
                    (true_target->colons == no_colon) &&
                    default_rule &&
                    !implicit) {
                        /* Make sure we have a line prop */
                        line = maybe_append_prop(target, line_prop);
                        command = line;
                        Boolean out_of_date;
                        if (true_target->is_member) {
                                out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
                                                                        line->body.line.dependency_time);
                        } else {
                                out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
                                                                    line->body.line.dependency_time);
                        }
                        if (build_unconditional || out_of_date) {
                                line->body.line.is_out_of_date = true;
                                if (debug_level > 0) {
                                        (void) printf(gettext("%*sBuilding %s using .DEFAULT because it is out of date\n"),
                                                      recursion_level,
                                                      "",
                                                      true_target->string_mb);
                                }
                        }
                        line->body.line.sccs_command = false;
                        line->body.line.command_template = default_rule;
                        line->body.line.target = true_target;
                        line->body.line.star = NULL;
                        line->body.line.less = true_target;
                        line->body.line.percent = NULL;
                }
        }

        /* We say "target up to date" if no cmd were executed for the target */
        if (!target->is_double_colon_parent) {
                commands_done = false;
        }

        silent = silent_all;
        ignore_errors = ignore_errors_all;
        if  (posix)
        {
          if  (!silent)
          {
            silent = (Boolean) target->silent_mode;
          }
          if  (!ignore_errors)
          {
            ignore_errors = (Boolean) target->ignore_error_mode;
          }
        }

        int doname_dyntarget = 0;
r_command:
        /* Run commands if any. */
        if ((command != NULL) &&
            (command->body.line.command_template != NULL)) {
                if (result != build_failed) {
                        result = run_command(command,
                                             (Boolean) ((parallel || save_parallel) && !silent));
                }
                switch (result) {
                case build_running:
                        add_running(target,
                                    true_target,
                                    command,
                                    --recursion_level,
                                    auto_count,
                                    automatics,
                                    do_get,
                                    implicit);
                        target->state = build_running;
                        if ((line = get_prop(target->prop,
                                             line_prop)) != NULL) {
                                if (line->body.line.query != NULL) {
                                        delete_query_chain(line->body.line.query);
                                }
                                line->body.line.query = NULL;
                        }
                        if (target->conditional_cnt > 0) {
                                reset_locals(target,
                                             old_locals,
                                             get_prop(target->prop,
                                                     conditional_prop),
                                             0);
                        }
                        return build_running;
                case build_serial:
                        add_serial(target,
                                   --recursion_level,
                                   do_get,
                                   implicit);
                        target->state = build_running;
                        line = get_prop(target->prop, line_prop);
                        if (line != NULL) {
                                if (line->body.line.query != NULL) {
                                        delete_query_chain(line->body.line.query);
                                }
                                line->body.line.query = NULL;
                        }
                        if (target->conditional_cnt > 0) {
                                reset_locals(target,
                                             old_locals,
                                             get_prop(target->prop,
                                                     conditional_prop),
                                             0);
                        }
                        return build_running;
                case build_ok:
                        /* If all went OK set a nice timestamp */
                        if (true_target->stat.time == file_doesnt_exist) {
                                true_target->stat.time = file_max_time;
                        }
                        break;
                }
        } else {
                /*
                 * If no command was found for the target, and it doesn't
                 * exist, and it is mentioned as a target in the makefile,
                 * we say it is extremely new and that it is OK.
                 */
                if (target->colons != no_colon) {
                        if (true_target->stat.time == file_doesnt_exist){
                                true_target->stat.time = file_max_time;
                        }
                        result = build_ok;
                }
                /*
                 * Trying dynamic targets.
                 */
                if(!doname_dyntarget) {
                        doname_dyntarget = 1;
                        Name dtarg = find_dyntarget(target);
                        if(dtarg!=NULL) {
                                if (!target->has_depe_list_expanded) {
                                        dynamic_dependencies(target);
                                }
                                if ((line = get_prop(target->prop, line_prop)) != NULL) {
                                        if (check_dependencies(&result,
                                                               line,
                                                               do_get,
                                                               target,
                                                               true_target,
                                                               doing_subtree,
                                                               &out_of_date_list,
                                                               old_locals,
                                                               implicit,
                                                               &command,
                                                               less,
                                                               rechecking_target,
                                                               recheck_conditionals))
                                        {
                                                return build_running;
                                        }
                                        if (line->body.line.query != NULL) {
                                                delete_query_chain(line->body.line.query);
                                        }
                                        line->body.line.query = out_of_date_list;
                                }
                                goto r_command;
                        }
                }
                /*
                 * If the file exists, it is OK that we couldnt figure
                 * out how to build it.
                 */
                (void) exists(target);
                if ((target->stat.time != file_doesnt_exist) &&
                    (result == build_dont_know)) {
                        result = build_ok;
                }
        }

        /*
         * Some of the following is duplicated in the function finish_doname.
         * If anything is changed here, check to see if it needs to be
         * changed there.
         */
        if ((line = get_prop(target->prop, line_prop)) != NULL) {
                if (line->body.line.query != NULL) {
                        delete_query_chain(line->body.line.query);
                }
                line->body.line.query = NULL;
        }
        target->state = result;
        parallel = save_parallel;
        if (target->conditional_cnt > 0) {
                reset_locals(target,
                             old_locals,
                             get_prop(target->prop, conditional_prop),
                             0);
        }
        recursion_level--;
        if (target->is_member) {
                Property member;

                /* Propagate the timestamp from the member file to the member*/
                if ((target->stat.time != file_max_time) &&
                    ((member = get_prop(target->prop, member_prop)) != NULL) &&
                    (exists(member->body.member.member) > file_doesnt_exist)) {
                        target->stat.time =
                          member->body.member.member->stat.time;
                }
        }
        /*
         * Check if we found any new auto dependencies when we
         * built the target.
         */
        if ((result == build_ok) && check_auto_dependencies(target,
                                                            auto_count,
                                                            automatics)) {
                if (debug_level > 0) {
                        (void) printf(gettext("%*sTarget `%s' acquired new dependencies from build, rechecking all dependencies\n"),
                                      recursion_level,
                                      "",
                                      true_target->string_mb);
                }
                rechecking_target = true;
                saved_commands_done = commands_done;
                goto recheck_target;
        }

        if (rechecking_target && !commands_done) {
                commands_done = saved_commands_done;
        }

        return result;
}

/*
 * DONE.
 *
 *      check_dependencies(result, line, do_get,
 *                      target, true_target, doing_subtree, out_of_date_tail,
 *                      old_locals, implicit, command, less, rechecking_target)
 *
 *      Return value:
 *                              True returned if some dependencies left running
 *
 *      Parameters:
 *              result          Pointer to cell we update if build failed
 *              line            We get the dependencies from here
 *              do_get          Allow use of sccs get in recursive doname()
 *              target          The target to chase dependencies for
 *              true_target     The real one for :: and lib(member)
 *              doing_subtree   True if building a conditional macro subtree
 *              out_of_date_tail Used to set the $? list
 *              old_locals      Used for resetting the local macros
 *              implicit        Called when scanning for implicit rules?
 *              command         Place to stuff command
 *              less            Set to $< value
 *
 *      Global variables used:
 *              command_changed Set if we suspect .make.state needs rewrite
 *              debug_level     Should we trace actions?
 *              force           The Name " FORCE", compared against
 *              recursion_level Used for tracing
 *              rewrite_statefile Set if .make.state needs rewriting
 *              wait_name       The Name ".WAIT", compared against
 */
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)
{
        Boolean                 dependencies_running;
        Dependency      dependency;
        Doname                  dep_result;
        Boolean                 dependency_changed = false;

        line->body.line.dependency_time = file_doesnt_exist;
        if (line->body.line.query != NULL) {
                delete_query_chain(line->body.line.query);
        }
        line->body.line.query = NULL;
        line->body.line.is_out_of_date = false;
        dependencies_running = false;
        /*
         * Run thru all the dependencies and call doname() recursively
         * on each of them.
         */
        for (dependency = line->body.line.dependencies;
             dependency != NULL;
             dependency = dependency->next) {
                Boolean this_dependency_changed = false;

                if (!dependency->automatic &&
                    (rechecking_target || target->rechecking_target)) {
                        /*
                         * We only bother with the autos when rechecking
                         */
                        continue;
                }

                if (dependency->name == wait_name) {
                        /*
                         * The special target .WAIT means finish all of
                         * the prior dependencies before continuing.
                         */
                        if (dependencies_running) {
                                break;
                        }
                } else if ((!parallel_ok(dependency->name, false)) &&
                           (dependencies_running)) {
                        /*
                         * If we can't execute the current dependency in
                         * parallel, hold off the dependency processing
                         * to preserve the order of the dependencies.
                         */
                        break;
                } else {
                        timestruc_t     depe_time = file_doesnt_exist;


                        if (true_target->is_member) {
                                depe_time = exists(dependency->name);
                        }
                        if (dependency->built ||
                            (dependency->name->state == build_failed)) {
                                dep_result = (Doname) dependency->name->state;
                        } else {
                                dep_result = doname_check(dependency->name,
                                                          do_get,
                                                          false,
                                                          (Boolean) dependency->automatic);
                        }
                        if (true_target->is_member || dependency->name->is_member) {
                                /* should compare only secs, cause lib members does not have nsec time resolution */
                                if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
                                        this_dependency_changed =
                                          dependency_changed =
                                            true;
                                }
                        } else {
                                if (depe_time != dependency->name->stat.time) {
                                        this_dependency_changed =
                                          dependency_changed =
                                            true;
                                }
                        }
                        dependency->built = true;
                        switch (dep_result) {
                        case build_running:
                                dependencies_running = true;
                                continue;
                        case build_failed:
                                *result = build_failed;
                                break;
                        case build_dont_know:
/*
 * If make can't figure out how to make a dependency, maybe the dependency
 * is out of date. In this case, we just declare the target out of date
 * and go on. If we really need the dependency, the make'ing of the target
 * will fail. This will only happen for automatic (hidden) dependencies.
 */
                                if(!recheck_conditionals) {
                                        line->body.line.is_out_of_date = true;
                                }
                                /*
                                 * Make sure the dependency is not saved
                                 * in the state file.
                                 */
                                dependency->stale = true;
                                rewrite_statefile =
                                  command_changed =
                                    true;
                                if (debug_level > 0) {
                                        (void) printf(gettext("Target %s rebuilt because dependency %s does not exist\n"),
                                                     true_target->string_mb,
                                                     dependency->name->string_mb);
                                }
                                break;
                        }
                        if (dependency->name->depends_on_conditional) {
                                target->depends_on_conditional = true;
                        }
                        if (dependency->name == force) {
                                target->stat.time =
                                  dependency->name->stat.time;
                        }
                        /*
                         * Propagate new timestamp from "member" to
                         * "lib.a(member)".
                         */
                        (void) exists(dependency->name);

                        /* Collect the timestamp of the youngest dependency */
                        line->body.line.dependency_time =
                          MAX(dependency->name->stat.time,
                              line->body.line.dependency_time);

                        /* Correction: do not consider nanosecs for members */
                        if(true_target->is_member || dependency->name->is_member) {
                                line->body.line.dependency_time.tv_nsec = 0;
                        }

                        if (debug_level > 1) {
                                (void) printf(gettext("%*sDate(%s)=%s \n"),
                                              recursion_level,
                                              "",
                                              dependency->name->string_mb,
                                              time_to_string(dependency->name->
                                                             stat.time));
                                if (dependency->name->stat.time > line->body.line.dependency_time) {
                                        (void) printf(gettext("%*sDate-dependencies(%s) set to %s\n"),
                                                      recursion_level,
                                                      "",
                                                      true_target->string_mb,
                                                      time_to_string(line->body.line.
                                                                     dependency_time));
                                }
                        }

                        /* Build the $? list */
                        if (true_target->is_member) {
                                if (this_dependency_changed == true) {
                                        true_target->stat.time = dependency->name->stat.time;
                                        true_target->stat.time.tv_sec--;
                                } else {
                                        /* Dina:
                                         * The next statement is commented
                                         * out as a fix for bug #1051032.
                                         * if dependency hasn't changed
                                         * then there's no need to invalidate
                                         * true_target. This statemnt causes
                                         * make to take much longer to process
                                         * an already-built archive. Soren
                                         * said it was a quick fix for some
                                         * problem he doesn't remember.
                                        true_target->stat.time = file_no_time;
                                         */
                                        (void) exists(true_target);
                                }
                        } else {
                                (void) exists(true_target);
                        }
                        Boolean out_of_date;
                        if (true_target->is_member || dependency->name->is_member) {
                                out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
                                                                        dependency->name->stat.time);
                        } else {
                                out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
                                                                    dependency->name->stat.time);
                        }
                        if ((build_unconditional || out_of_date) &&
                            (dependency->name != force) &&
                            (dependency->stale == false)) {
                                *out_of_date_tail = ALLOC(Chain);
                                if (dependency->name->is_member &&
                                    (get_prop(dependency->name->prop,
                                              member_prop) != NULL)) {
                                        (*out_of_date_tail)->name =
                                          get_prop(dependency->name->prop,
                                                   member_prop)->
                                                     body.member.member;
                                } else {
                                        (*out_of_date_tail)->name =
                                          dependency->name;
                                }
                                (*out_of_date_tail)->next = NULL;
                                out_of_date_tail = &(*out_of_date_tail)->next;
                                if (debug_level > 0) {
                                        if (dependency->name->stat.time == file_max_time) {
                                                (void) printf(gettext("%*sBuilding %s because %s does not exist\n"),
                                                              recursion_level,
                                                              "",
                                                              true_target->string_mb,
                                                              dependency->name->string_mb);
                                        } else {
                                                (void) printf(gettext("%*sBuilding %s because it is out of date relative to %s\n"),
                                                              recursion_level,
                                                              "",
                                                              true_target->string_mb,
                                                              dependency->name->string_mb);
                                        }
                                }
                        }
                        if (dependency->name == force) {
                                force->stat.time =
                                  file_max_time;
                                force->state = build_dont_know;
                        }
                }
        }
        if (dependencies_running) {
                if (doing_subtree) {
                        if (target->conditional_cnt > 0) {
                                reset_locals(target,
                                             old_locals,
                                             get_prop(target->prop,
                                                      conditional_prop),
                                             0);
                        }
                        return true;
                } else {
                        target->state = build_running;
                        add_pending(target,
                                    --recursion_level,
                                    do_get,
                                    implicit,
                                    false);
                        if (target->conditional_cnt > 0) {
                                reset_locals(target,
                                             old_locals,
                                             get_prop(target->prop,
                                                      conditional_prop),
                                             0);
                        }
                        return true;
                }
        }
        /*
         * Collect the timestamp of the youngest double colon target
         * dependency.
         */
        if (target->is_double_colon_parent) {
                for (dependency = line->body.line.dependencies;
                     dependency != NULL;
                     dependency = dependency->next) {
                        Property        tmp_line;

                        if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) {
                                if(tmp_line->body.line.dependency_time != file_max_time) {
                                        target->stat.time =
                                          MAX(tmp_line->body.line.dependency_time,
                                              target->stat.time);
                                }
                        }
                }
        }
        if ((true_target->is_member) && (dependency_changed == true)) {
                true_target->stat.time = file_no_time;
        }
        /*
         * After scanning all the dependencies, we check the rule
         * if we found one.
         */
        if (line->body.line.command_template != NULL) {
                if (line->body.line.command_template_redefined) {
                        warning(gettext("Too many rules defined for target %s"),
                                target->string_mb);
                }
                *command = line;
                /* Check if the target is out of date */
                Boolean out_of_date;
                if (true_target->is_member) {
                        out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
                                                                line->body.line.dependency_time);
                } else {
                        out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
                                                            line->body.line.dependency_time);
                }
                if (build_unconditional || out_of_date){
                        if(!recheck_conditionals) {
                                line->body.line.is_out_of_date = true;
                        }
                }
                line->body.line.sccs_command = false;
                line->body.line.target = true_target;
                if(gnu_style) {

                        // set $< for explicit rule
                        if(line->body.line.dependencies != NULL) {
                                less = line->body.line.dependencies->name;
                        }

                        // set $* for explicit rule
                        Name                    target_body;
                        Name                    tt = true_target;
                        Property                member;
                        wchar_t *target_end;
                        Dependency      suffix;
                        int             suffix_length;
                        Wstring                 targ_string;
                        Wstring                 suf_string;

                        if (true_target->is_member &&
                            ((member = get_prop(target->prop, member_prop)) !=
                             NULL)) {
                                tt = member->body.member.member;
                        }
                        targ_string.init(tt);
                        target_end = targ_string.get_string() + tt->hash.length;
                        for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
                                suffix_length = suffix->name->hash.length;
                                suf_string.init(suffix->name);
                                if (tt->hash.length < suffix_length) {
                                        continue;
                                } else if (!IS_WEQUALN(suf_string.get_string(),
                                                (target_end - suffix_length),
                                                suffix_length)) {
                                        continue;
                                }
                                target_body = GETNAME(
                                        targ_string.get_string(),
                                        (int)(tt->hash.length - suffix_length)
                                );
                                line->body.line.star = target_body;
                        }

                        // set result = build_ok so that implicit rules are not used.
                        if(*result == build_dont_know) {
                                *result = build_ok;
                        }
                }
                if (less != NULL) {
                        line->body.line.less = less;
                }
        }

        return false;
}

/*
 *      dynamic_dependencies(target)
 *
 *      Checks if any dependency contains a macro ref
 *      If so, it replaces the dependency with the expanded version.
 *      Here, "$@" gets translated to target->string. That is
 *      the current name on the left of the colon in the
 *      makefile.  Thus,
 *              xyz:    s.$@.c
 *      translates into
 *              xyz:    s.xyz.c
 *
 *      Also, "$(@F)" translates to the same thing without a preceeding
 *      directory path (if one exists).
 *      Note, to enter "$@" on a dependency line in a makefile
 *      "$$@" must be typed. This is because make expands
 *      macros in dependency lists upon reading them.
 *      dynamic_dependencies() also expands file wildcards.
 *      If there are any Shell meta characters in the name,
 *      search the directory, and replace the dependency
 *      with the set of files the pattern matches
 *
 *      Parameters:
 *              target          Target to sanitize dependencies for
 *
 *      Global variables used:
 *              c_at            The Name "@", used to set macro value
 *              debug_level     Should we trace actions?
 *              dot             The Name ".", used to read directory
 *              recursion_level Used for tracing
 */
void
dynamic_dependencies(Name target)
{
        wchar_t                 pattern[MAXPATHLEN];
        wchar_t *p;
        Property                line;
        Dependency      dependency;
        Dependency      *remove;
        String_rec              string;
        wchar_t                 buffer[MAXPATHLEN];
        Boolean set_at = false;
        wchar_t *start;
        Dependency              new_depe;
        Boolean reuse_cell;
        Dependency              first_member;
        Name                    directory;
        Name                    lib;
        Name                    member;
        Property                prop;
        Name                    true_target = target;
        wchar_t                 *library;

        if ((line = get_prop(target->prop, line_prop)) == NULL) {
                return;
        }
        /* If the target is constructed from a "::" target we consider that */
        if (target->has_target_prop) {
                true_target = get_prop(target->prop,
                                       target_prop)->body.target.target;
        }
        /* Scan all dependencies and process the ones that contain "$" chars */
        for (dependency = line->body.line.dependencies;
             dependency != NULL;
             dependency = dependency->next) {
                if (!dependency->name->dollar) {
                        continue;
                }
                target->has_depe_list_expanded = true;

                /* The make macro $@ is bound to the target name once per */
                /* invocation of dynamic_dependencies() */
                if (!set_at) {
                        (void) SETVAR(c_at, true_target, false);
                        set_at = true;
                }
                /* Expand this dependency string */
                INIT_STRING_FROM_STACK(string, buffer);
                expand_value(dependency->name, &string, false);
                /* Scan the expanded string. It could contain whitespace */
                /* which mean it expands to several dependencies */
                start = string.buffer.start;
                while (iswspace(*start)) {
                        start++;
                }
                /* Remove the cell (later) if the macro was empty */
                if (start[0] == (int) nul_char) {
                        dependency->name = NULL;
                }

/* azv 10/26/95 to fix bug BID_1170218 */
                if ((start[0] == (int) period_char) &&
                    (start[1] == (int) slash_char)) {
                        start += 2;
                }
/* azv */

                first_member = NULL;
                /* We use the original dependency cell for the first */
                /* dependency from the expansion */
                reuse_cell = true;
                /* We also have to deal with dependencies that expand to */
                /* lib.a(members) notation */
                for (p = start; *p != (int) nul_char; p++) {
                        if ((*p == (int) parenleft_char)) {
                                lib = GETNAME(start, p - start);
                                lib->is_member = true;
                                first_member = dependency;
                                start = p + 1;
                                while (iswspace(*start)) {
                                        start++;
                                }
                                break;
                        }
                }
                do {
                    /* First skip whitespace */
                        for (p = start; *p != (int) nul_char; p++) {
                                if ((*p == (int) nul_char) ||
                                    iswspace(*p) ||
                                    (*p == (int) parenright_char)) {
                                        break;
                                }
                        }
                        /* Enter dependency from expansion */
                        if (p != start) {
                                /* Create new dependency cell if */
                                /* this is not the first dependency */
                                /* picked from the expansion */
                                if (!reuse_cell) {
                                        new_depe = ALLOC(Dependency);
                                        new_depe->next = dependency->next;
                                        new_depe->automatic = false;
                                        new_depe->stale = false;
                                        new_depe->built = false;
                                        dependency->next = new_depe;
                                        dependency = new_depe;
                                }
                                reuse_cell = false;
                                /* Internalize the dependency name */
                                // tolik. Fix for bug 4110429: inconsistent expansion for macros that
                                // include "//" and "/./"
                                //dependency->name = GETNAME(start, p - start);
                                dependency->name = normalize_name(start, p - start);
                                if ((debug_level > 0) &&
                                    (first_member == NULL)) {
                                        (void) printf(gettext("%*sDynamic dependency `%s' for target `%s'\n"),
                                                      recursion_level,
                                                      "",
                                                      dependency->name->string_mb,
                                                      true_target->string_mb);
                                }
                                for (start = p; iswspace(*start); start++);
                                p = start;
                        }
                } while ((*p != (int) nul_char) &&
                         (*p != (int) parenright_char));
                /* If the expansion was of lib.a(members) format we now */
                /* enter the proper member cells */
                if (first_member != NULL) {
                        /* Scan the new dependencies and transform them from */
                        /* "foo" to "lib.a(foo)" */
                        for (; 1; first_member = first_member->next) {
                                /* Build "lib.a(foo)" name */
                                INIT_STRING_FROM_STACK(string, buffer);
                                APPEND_NAME(lib,
                                              &string,
                                              (int) lib->hash.length);
                                append_char((int) parenleft_char, &string);
                                APPEND_NAME(first_member->name,
                                              &string,
                                              FIND_LENGTH);
                                append_char((int) parenright_char, &string);
                                member = first_member->name;
                                /* Replace "foo" with "lib.a(foo)" */
                                first_member->name =
                                  GETNAME(string.buffer.start, FIND_LENGTH);
                                if (string.free_after_use) {
                                        retmem(string.buffer.start);
                                }
                                if (debug_level > 0) {
                                        (void) printf(gettext("%*sDynamic dependency `%s' for target `%s'\n"),
                                                      recursion_level,
                                                      "",
                                                      first_member->name->
                                                      string_mb,
                                                      true_target->string_mb);
                                }
                                first_member->name->is_member = lib->is_member;
                                /* Add member property to member */
                                prop = maybe_append_prop(first_member->name,
                                                         member_prop);
                                prop->body.member.library = lib;
                                prop->body.member.entry = NULL;
                                prop->body.member.member = member;
                                if (first_member == dependency) {
                                        break;
                                }
                        }
                }
        }
        Wstring wcb;
        /* Then scan all the dependencies again. This time we want to expand */
        /* shell file wildcards */
        for (remove = &line->body.line.dependencies, dependency = *remove;
             dependency != NULL;
             dependency = *remove) {
                if (dependency->name == NULL) {
                        dependency = *remove = (*remove)->next;
                        continue;
                }
                /* If dependency name string contains shell wildcards */
                /* replace the name with the expansion */
                if (dependency->name->wildcard) {
                        wcb.init(dependency->name);
                        if ((start = (wchar_t *) wcschr(wcb.get_string(),
                                           (int) parenleft_char)) != NULL) {
                                /* lib(*) type pattern */
                                library = buffer;
                                (void) wcsncpy(buffer,
                                              wcb.get_string(),
                                              start - wcb.get_string());
                                buffer[start-wcb.get_string()] =
                                  (int) nul_char;
                                (void) wcsncpy(pattern,
                                              start + 1,
(int) (dependency->name->hash.length-(start-wcb.get_string())-2));
                                pattern[dependency->name->hash.length -
                                        (start-wcb.get_string()) - 2] =
                                          (int) nul_char;
                        } else {
                                library = NULL;
                                (void) wcsncpy(pattern,
                                              wcb.get_string(),
                                              (int) dependency->name->hash.length);
                                pattern[dependency->name->hash.length] =
                                  (int) nul_char;
                        }
                        start = (wchar_t *) wcsrchr(pattern, (int) slash_char);
                        if (start == NULL) {
                                directory = dot;
                                p = pattern;
                        } else {
                                directory = GETNAME(pattern, start-pattern);
                                p = start+1;
                        }
                        /* The expansion is handled by the read_dir() routine*/
                        if (read_dir(directory, p, line, library)) {
                                *remove = (*remove)->next;
                        } else {
                                remove = &dependency->next;
                        }
                } else {
                        remove = &dependency->next;
                }
        }

        /* Then unbind $@ */
        (void) SETVAR(c_at, (Name) NULL, false);
}

/*
 * DONE.
 *
 *      run_command(line)
 *
 *      Takes one Cmd_line and runs the commands from it.
 *
 *      Return value:
 *                              Indicates if the command failed or not
 *
 *      Parameters:
 *              line            The command line to run
 *
 *      Global variables used:
 *              commands_done   Set if we do run command
 *              current_line    Set to the line we run a command from
 *              current_target  Set to the target we run a command for
 *              file_number     Used to form temp file name
 *              keep_state      Indicates that .KEEP_STATE is on
 *              make_state      The Name ".make.state", used to check timestamp
 *              parallel        True if currently building in parallel
 *              parallel_process_cnt Count of parallel processes running
 *              quest           Indicates that make -q is on
 *              rewrite_statefile Set if we do run a command
 *              sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value
 *              temp_file_directory Used to form temp fie name
 *              temp_file_name  Set to the name of the temp file
 *              touch           Indicates that make -t is on
 */
static Doname
run_command(Property line, Boolean)
{
        Doname          result = build_ok;
        Boolean remember_only = false;
        Name            target = line->body.line.target;
        wchar_t                 *string;
        char                    tmp_file_path[MAXPATHLEN];

        if (!line->body.line.is_out_of_date && target->rechecking_target) {
                target->rechecking_target = false;
                return build_ok;
        }

        /*
         * Build the command if we know the target is out of date,
         * or if we want to check cmd consistency.
         */
        if (line->body.line.is_out_of_date || keep_state) {
                /* Hack for handling conditional macros in DMake. */
                if (!line->body.line.dont_rebuild_command_used) {
                        build_command_strings(target, line);
                }
        }
        /* Never mind */
        if (!line->body.line.is_out_of_date) {
                return build_ok;
        }
        /* If quest, then exit(1) because the target is out of date */
        if (quest) {
                if (posix) {
                        result = execute_parallel(line, true);
                }
                exit_status = 1;
                exit(1);
        }
        /* We actually had to do something this time */
        rewrite_statefile = commands_done = true;
        /*
         * If this is an sccs command, we have to do some extra checking
         * and possibly complain. If the file can't be gotten because it's
         * checked out, we complain and behave as if the command was
         * executed eventhough we ignored the command.
         */
        if (!touch &&
            line->body.line.sccs_command &&
            (target->stat.time != file_doesnt_exist) &&
            ((target->stat.mode & 0222) != 0)) {
                fatal(gettext("%s is writable so it cannot be sccs gotten"),
                      target->string_mb);
                target->has_complained = remember_only = true;
        }
        /*
         * If KEEP_STATE is on, we make sure we have the timestamp for
         * .make.state. If .make.state changes during the command run,
         * we reread .make.state after the command. We also setup the
         * environment variable that asks utilities to report dependencies.
         */
        if (!touch &&
            keep_state &&
            !remember_only) {
                (void) exists(make_state);
                if((strlen(temp_file_directory) == 1) &&
                        (temp_file_directory[0] == '/')) {
                   tmp_file_path[0] = '\0';
                } else {
                   strcpy(tmp_file_path, temp_file_directory);
                }
                sprintf(mbs_buffer,
                                "%s/.make.dependency.%08x.%d.%d",
                                tmp_file_path,
                                hostid,
                                getpid(),
                                file_number++);
                MBSTOWCS(wcs_buffer, mbs_buffer);
                Boolean fnd;
                temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd);
                temp_file_name->stat.is_file = true;
                int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2;
                wchar_t *to = string = ALLOC_WC(len);
                for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) {
                        if (*from == (int) space_char) {
                                *to++ = (int) backslash_char;
                        }
                        *to++ = *from++;
                }
                *to++ = (int) space_char;
                MBSTOWCS(to, target->string_mb);
                Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd);
                (void) SETVAR(sunpro_dependencies,
                              sprodep_name,
                              false);
                retmem(string);
        } else {
                temp_file_name = NULL;
        }

        /*
         * In case we are interrupted, we need to know what was going on.
         */
        current_target = target;
        /*
         * We also need to be able to save an empty command instead of the
         * interrupted one in .make.state.
         */
        current_line = line;
        if (remember_only) {
                /* Empty block!!! */
        } else if (touch) {
                result = touch_command(line, target, result);
                if (posix) {
                        result = execute_parallel(line, true);
                }
        } else {
                /*
                 * If this is not a touch run, we need to execute the
                 * proper command(s) for the target.
                 */
                if (parallel) {
                        if (!parallel_ok(target, true)) {
                                /*
                                 * We are building in parallel, but
                                 * this target must be built in serial.
                                 */
                                /*
                                 * If nothing else is building,
                                 * do this one, else wait.
                                 */
                                if (parallel_process_cnt == 0) {
                                        result = execute_parallel(line, true, target->localhost);
                                } else {
                                        current_target = NULL;
                                        current_line = NULL;
/*
                                        line->body.line.command_used = NULL;
 */
                                        line->body.line.dont_rebuild_command_used = true;
                                        return build_serial;
                                }
                        } else {
                                result = execute_parallel(line, false);
                                switch (result) {
                                case build_running:
                                        return build_running;
                                case build_serial:
                                        if (parallel_process_cnt == 0) {
                                                result = execute_parallel(line, true, target->localhost);
                                        } else {
                                                current_target = NULL;
                                                current_line = NULL;
                                                target->parallel = false;
                                                line->body.line.command_used =
                                                    NULL;
                                                return build_serial;
                                        }
                                }
                        }
                } else {
                        result = execute_parallel(line, true, target->localhost);
                }
        }
        temp_file_name = NULL;
        if (report_dependencies_level == 0){
                update_target(line, result);
        }
        current_target = NULL;
        current_line = NULL;
        return result;
}

/*
 *      execute_serial(line)
 *
 *      Runs thru the command line for the target and
 *      executes the rules one by one.
 *
 *      Return value:
 *                              The result of the command build
 *
 *      Parameters:
 *              line            The command to execute
 *
 *      Static variables used:
 *
 *      Global variables used:
 *              continue_after_error -k flag
 *              do_not_exec_rule -n flag
 *              report_dependencies -P flag
 *              silent          Don't echo commands before executing
 *              temp_file_name  Temp file for auto dependencies
 *              vpath_defined   If true, translate path for command
 */
Doname
execute_serial(Property line)
{
        int                     child_pid = 0;
        Boolean                 printed_serial;
        Doname                  result = build_ok;
        Cmd_line                rule, cmd_tail, command = NULL;
        char                    mbstring[MAXPATHLEN];
        int                     filed;
        Name                    target = line->body.line.target;

        target->has_recursive_dependency = false;
        // We have to create a copy of the rules chain for processing because
        // the original one can be destroyed during .make.state file rereading.
        for (rule = line->body.line.command_used;
             rule != NULL;
             rule = rule->next) {
                if (command == NULL) {
                        command = cmd_tail = ALLOC(Cmd_line);
                } else {
                        cmd_tail->next = ALLOC(Cmd_line);
                        cmd_tail = cmd_tail->next;
                }
                *cmd_tail = *rule;
        }
        if (command) {
                cmd_tail->next = NULL;
        }
        for (rule = command; rule != NULL; rule = rule->next) {
                if (posix && (touch || quest) && !rule->always_exec) {
                        continue;
                }
                if (vpath_defined) {
                        rule->command_line =
                          vpath_translation(rule->command_line);
                }
                /* Echo command line, maybe. */
                if ((rule->command_line->hash.length > 0) &&
                    !silent &&
                    (!rule->silent || do_not_exec_rule) &&
                    (report_dependencies_level == 0)) {
                        (void) printf("%s\n", rule->command_line->string_mb);
                }
                if (rule->command_line->hash.length > 0) {
                        /* Do assignment if command line prefixed with "=" */
                        if (rule->assign) {
                                result = build_ok;
                                do_assign(rule->command_line, target);
                        } else if (report_dependencies_level == 0) {
                                /* Execute command line. */
                                setvar_envvar();
                                result = dosys(rule->command_line,
                                               (Boolean) rule->ignore_error,
                                               (Boolean) rule->make_refd,
                                               /* ds 98.04.23 bug #4085164. make should always show error messages */
                                               false,
                                               /* BOOLEAN(rule->silent &&
                                                       rule->ignore_error), */
                                               (Boolean) rule->always_exec,
                                               target);
                                check_state(temp_file_name);
                        }
                } else {
                        result = build_ok;
                }
                if (result == build_failed) {
                        if (silent || rule->silent) {
                                (void) printf(gettext("The following command caused the error:\n%s\n"),
                                              rule->command_line->string_mb);
                        }
                        if (!rule->ignore_error && !ignore_errors) {
                                if (!continue_after_error) {
                                        fatal(gettext("Command failed for target `%s'"),
                                              target->string_mb);
                                }
                                /*
                                 * Make sure a failing command is not
                                 * saved in .make.state.
                                 */
                                line->body.line.command_used = NULL;
                                break;
                        } else {
                                result = build_ok;
                        }
                }
        }
        for (rule = command; rule != NULL; rule = cmd_tail) {
                cmd_tail = rule->next;
                free(rule);
        }
        command = NULL;
        if (temp_file_name != NULL) {
                free_name(temp_file_name);
        }
        temp_file_name = NULL;

        Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
        if(spro != NULL) {
                Name val = spro->body.macro.value;
                if(val != NULL) {
                        free_name(val);
                        spro->body.macro.value = NULL;
                }
        }
        spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
        if(spro) {
                char *val = spro->body.env_mem.value;
                if(val != NULL) {
                        /*
                         * Do not return memory allocated for SUNPRO_DEPENDENCIES
                         * It will be returned in setvar_daemon() in macro.cc
                         */
                        //      retmem_mb(val);
                        spro->body.env_mem.value = NULL;
                }
        }

        return result;
}



/*
 *      vpath_translation(cmd)
 *
 *      Translates one command line by
 *      checking each word. If the word has an alias it is translated.
 *
 *      Return value:
 *                              The translated command
 *
 *      Parameters:
 *              cmd             Command to translate
 *
 *      Global variables used:
 */
Name
vpath_translation(Name cmd)
{
        wchar_t                 buffer[STRING_BUFFER_LENGTH];
        String_rec              new_cmd;
        wchar_t                 *p;
        wchar_t                 *start;

        if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) {
                return cmd;
        }
        INIT_STRING_FROM_STACK(new_cmd, buffer);

        Wstring wcb(cmd);
        p = wcb.get_string();

        while (*p != (int) nul_char) {
                while (iswspace(*p) && (*p != (int) nul_char)) {
                        append_char(*p++, &new_cmd);
                }
                start = p;
                while (!iswspace(*p) && (*p != (int) nul_char)) {
                        p++;
                }
                cmd = GETNAME(start, p - start);
                if (cmd->has_vpath_alias_prop) {
                        cmd = get_prop(cmd->prop, vpath_alias_prop)->
                                                body.vpath_alias.alias;
                        APPEND_NAME(cmd,
                                      &new_cmd,
                                      (int) cmd->hash.length);
                } else {
                        append_string(start, &new_cmd, p - start);
                }
        }
        cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH);
        if (new_cmd.free_after_use) {
                retmem(new_cmd.buffer.start);
        }
        return cmd;
}

/*
 *      check_state(temp_file_name)
 *
 *      Reads and checks the state changed by the previously executed command.
 *
 *      Parameters:
 *              temp_file_name  The auto dependency temp file
 *
 *      Global variables used:
 */
void
check_state(Name temp_file_name)
{
        if (!keep_state) {
                return;
        }

        /*
         * Then read the temp file that now might
         * contain dependency reports from utilities
         */
        read_dependency_file(temp_file_name);

        /*
         * And reread .make.state if it
         * changed (the command ran recursive makes)
         */
        check_read_state_file();
        if (temp_file_name != NULL) {
                (void) unlink(temp_file_name->string_mb);
        }
}

/*
 *      read_dependency_file(filename)
 *
 *      Read the temp file used for reporting dependencies to make
 *
 *      Parameters:
 *              filename        The name of the file with the state info
 *
 *      Global variables used:
 *              makefile_type   The type of makefile being read
 *              read_trace_level Debug flag
 *              temp_file_number The always increasing number for unique files
 *              trace_reader    Debug flag
 */
static void
read_dependency_file(Name filename)
{
        Makefile_type   save_makefile_type;

        if (filename == NULL) {
                return;
        }
        filename->stat.time = file_no_time;
        if (exists(filename) > file_doesnt_exist) {
                save_makefile_type = makefile_type;
                makefile_type = reading_cpp_file;
                if (read_trace_level > 1) {
                        trace_reader = true;
                }
                temp_file_number++;
                (void) read_simple_file(filename,
                                        false,
                                        false,
                                        false,
                                        false,
                                        false,
                                        false);
                trace_reader = false;
                makefile_type = save_makefile_type;
        }
}

/*
 *      check_read_state_file()
 *
 *      Check if .make.state has changed
 *      If it has we reread it
 *
 *      Parameters:
 *
 *      Global variables used:
 *              make_state      Make state file name
 *              makefile_type   Type of makefile being read
 *              read_trace_level Debug flag
 *              trace_reader    Debug flag
 */
static void
check_read_state_file(void)
{
        timestruc_t             previous = make_state->stat.time;
        Makefile_type   save_makefile_type;
        Property        makefile;

        make_state->stat.time = file_no_time;
        if ((exists(make_state) == file_doesnt_exist) ||
            (make_state->stat.time == previous)) {
                return;
        }
        save_makefile_type = makefile_type;
        makefile_type = rereading_statefile;
        /* Make sure we clear the old cached contents of .make.state */
        makefile = maybe_append_prop(make_state, makefile_prop);
        if (makefile->body.makefile.contents != NULL) {
                retmem(makefile->body.makefile.contents);
                makefile->body.makefile.contents = NULL;
        }
        if (read_trace_level > 1) {
                trace_reader = true;
        }
        temp_file_number++;
        (void) read_simple_file(make_state,
                                false,
                                false,
                                false,
                                false,
                                false,
                                true);
        trace_reader = false;
        makefile_type = save_makefile_type;
}

/*
 *      do_assign(line, target)
 *
 *      Handles runtime assignments for command lines prefixed with "=".
 *
 *      Parameters:
 *              line            The command that contains an assignment
 *              target          The Name of the target, used for error reports
 *
 *      Global variables used:
 *              assign_done     Set to indicate doname needs to reprocess
 */
static void
do_assign(Name line, Name target)
{
        Wstring wcb(line);
        wchar_t *string = wcb.get_string();
        wchar_t *equal;
        Name            name;
        Boolean append = false;

        /*
         * If any runtime assignments are done, doname() must reprocess all
         * targets in the future since the macro values used to build the
         * command lines for the targets might have changed.
         */
        assign_done = true;
        /* Skip white space. */
        while (iswspace(*string)) {
                string++;
        }
        equal = string;
        /* Find "+=" or "=". */
        while (!iswspace(*equal) &&
               (*equal != (int) plus_char) &&
               (*equal != (int) equal_char)) {
                equal++;
        }
        /* Internalize macro name. */
        name = GETNAME(string, equal - string);
        /* Skip over "+=" "=". */
        while (!((*equal == (int) nul_char) ||
                 (*equal == (int) equal_char) ||
                 (*equal == (int) plus_char))) {
                equal++;
        }
        switch (*equal) {
        case nul_char:
                fatal(gettext("= expected in rule `%s' for target `%s'"),
                      line->string_mb,
                      target->string_mb);
        case plus_char:
                append = true;
                equal++;
                break;
        }
        equal++;
        /* Skip over whitespace in front of value. */
        while (iswspace(*equal)) {
                equal++;
        }
        /* Enter new macro value. */
        enter_equal(name,
                    GETNAME(equal, wcb.get_string() + line->hash.length - equal),
                    append);
}

/*
 *      build_command_strings(target, line)
 *
 *      Builds the command string to used when
 *      building a target. If the string is different from the previous one
 *      is_out_of_date is set.
 *
 *      Parameters:
 *              target          Target to build commands for
 *              line            Where to stuff result
 *
 *      Global variables used:
 *              c_at            The Name "@", used to set macro value
 *              command_changed Set if command is different from old
 *              debug_level     Should we trace activities?
 *              do_not_exec_rule Always echo when running -n
 *              empty_name      The Name "", used for empty rule
 *              funny           Semantics of characters
 *              ignore_errors   Used to init field for line
 *              is_conditional  Set to false befor evaling macro, checked
 *                              after expanding macros
 *              keep_state      Indicates that .KEEP_STATE is on
 *              make_word_mentioned Set by macro eval, inits field for cmd
 *              query           The Name "?", used to set macro value
 *              query_mentioned Set by macro eval, inits field for cmd
 *              recursion_level Used for tracing
 *              silent          Used to init field for line
 */
static void
build_command_strings(Name target, Property line)
{
        String_rec              command_line;
        Cmd_line        command_template = line->body.line.command_template;
        Cmd_line        *insert = &line->body.line.command_used;
        Cmd_line        used = *insert;
        wchar_t                 buffer[STRING_BUFFER_LENGTH];
        wchar_t                 *start;
        Name                    new_command_line;
        Boolean new_command_longer = false;
        Boolean ignore_all_command_dependency = true;
        Property                member;
        static Name             less_name;
        static Name             percent_name;
        static Name             star;
        Name                    tmp_name;

        if (less_name == NULL) {
                MBSTOWCS(wcs_buffer, "<");
                less_name = GETNAME(wcs_buffer, FIND_LENGTH);
                MBSTOWCS(wcs_buffer, "%");
                percent_name = GETNAME(wcs_buffer, FIND_LENGTH);
                MBSTOWCS(wcs_buffer, "*");
                star = GETNAME(wcs_buffer, FIND_LENGTH);
        }

        /* We have to check if a target depends on conditional macros */
        /* Targets that do must be reprocessed by doname() each time around */
        /* since the macro values used when building the target might have */
        /* changed */
        conditional_macro_used = false;
        /* If we are building a lib.a(member) target $@ should be bound */
        /* to lib.a */
        if (target->is_member &&
            ((member = get_prop(target->prop, member_prop)) != NULL)) {
                target = member->body.member.library;
        }
        /* If we are building a "::" help target $@ should be bound to */
        /* the real target name */
        /* A lib.a(member) target is never :: */
        if (target->has_target_prop) {
                target = get_prop(target->prop, target_prop)->
                  body.target.target;
        }
        /* Bind the magic macros that make supplies */
        tmp_name = target;
        if(tmp_name != NULL) {
                if (tmp_name->has_vpath_alias_prop) {
                        tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
                                        body.vpath_alias.alias;
                }
        }
        (void) SETVAR(c_at, tmp_name, false);

        tmp_name = line->body.line.star;
        if(tmp_name != NULL) {
                if (tmp_name->has_vpath_alias_prop) {
                        tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
                                        body.vpath_alias.alias;
                }
        }
        (void) SETVAR(star, tmp_name, false);

        tmp_name = line->body.line.less;
        if(tmp_name != NULL) {
                if (tmp_name->has_vpath_alias_prop) {
                        tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
                                        body.vpath_alias.alias;
                }
        }
        (void) SETVAR(less_name, tmp_name, false);

        tmp_name = line->body.line.percent;
        if(tmp_name != NULL) {
                if (tmp_name->has_vpath_alias_prop) {
                        tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
                                        body.vpath_alias.alias;
                }
        }
        (void) SETVAR(percent_name, tmp_name, false);

        /* $? is seldom used and it is expensive to build */
        /* so we store the list form and build the string on demand */
        Chain query_list = NULL;
        Chain *query_list_tail = &query_list;

        for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) {
                *query_list_tail = ALLOC(Chain);
                (*query_list_tail)->name = ch->name;
                if ((*query_list_tail)->name->has_vpath_alias_prop) {
                        (*query_list_tail)->name =
                                get_prop((*query_list_tail)->name->prop,
                                        vpath_alias_prop)->body.vpath_alias.alias;
                }
                (*query_list_tail)->next = NULL;
                query_list_tail = &(*query_list_tail)->next;
        }
        (void) setvar_daemon(query,
                             (Name) query_list,
                             false,
                             chain_daemon,
                             false,
                             debug_level);

        /* build $^ */
        Chain hat_list = NULL;
        Chain *hat_list_tail = &hat_list;

        for (Dependency dependency = line->body.line.dependencies;
                dependency != NULL;
                dependency = dependency->next) {
                /* skip automatic dependencies */
                if (!dependency->automatic) {
                        if ((dependency->name != force) &&
                                (dependency->stale == false)) {
                                *hat_list_tail = ALLOC(Chain);

                                if (dependency->name->is_member &&
                                        (get_prop(dependency->name->prop, member_prop) != NULL)) {
                                        (*hat_list_tail)->name =
                                                        get_prop(dependency->name->prop,
                                                                member_prop)->body.member.member;
                                } else {
                                        (*hat_list_tail)->name = dependency->name;
                                }

                                if((*hat_list_tail)->name != NULL) {
                                        if ((*hat_list_tail)->name->has_vpath_alias_prop) {
                                                (*hat_list_tail)->name =
                                                        get_prop((*hat_list_tail)->name->prop,
                                                                vpath_alias_prop)->body.vpath_alias.alias;
                                        }
                                }

                                (*hat_list_tail)->next = NULL;
                                hat_list_tail = &(*hat_list_tail)->next;
                        }
                }
        }
        (void) setvar_daemon(hat,
                             (Name) hat_list,
                             false,
                             chain_daemon,
                             false,
                             debug_level);

/* We have two command sequences we need to handle */
/* The old one that we probably read from .make.state */
/* and the new one we are building that will replace the old one */
/* Even when KEEP_STATE is not on we build a new command sequence and store */
/* it in the line prop. This command sequence is then executed by */
/* run_command(). If KEEP_STATE is on it is also later written to */
/* .make.state. The routine replaces the old command line by line with the */
/* new one trying to reuse Cmd_lines */

        /* If there is no old command_used we have to start creating */
        /* Cmd_lines to keep the new cmd in */
        if (used == NULL) {
                new_command_longer = true;
                *insert = used = ALLOC(Cmd_line);
                used->next = NULL;
                used->command_line = NULL;
                insert = &used->next;
        }
        /* Run thru the template for the new command and build the expanded */
        /* new command lines */
        for (;
             command_template != NULL;
             command_template = command_template->next, insert = &used->next, used = *insert) {
                /* If there is no old command_used Cmd_line we need to */
                /* create one and say that cmd consistency failed */
                if (used == NULL) {
                        new_command_longer = true;
                        *insert = used = ALLOC(Cmd_line);
                        used->next = NULL;
                        used->command_line = empty_name;
                }
                /* Prepare the Cmd_line for the processing */
                /* The command line prefixes "@-=?" are stripped and that */
                /* information is saved in the Cmd_line */
                used->assign = false;
                used->ignore_error = ignore_errors;
                used->silent = silent;
                used->always_exec = false;
                /* Expand the macros in the command line */
                INIT_STRING_FROM_STACK(command_line, buffer);
                make_word_mentioned =
                  query_mentioned =
                    false;
                expand_value(command_template->command_line, &command_line, true);
                /* If the macro $(MAKE) is mentioned in the command */
                /* "make -n" runs actually execute the command */
                used->make_refd = make_word_mentioned;
                used->ignore_command_dependency = query_mentioned;
                /* Strip the prefixes */
                start = command_line.buffer.start;
                for (;
                     iswspace(*start) ||
                     (get_char_semantics_value(*start) & (int) command_prefix_sem);
                     start++) {
                        switch (*start) {
                        case question_char:
                                used->ignore_command_dependency = true;
                                break;
                        case exclam_char:
                                used->ignore_command_dependency = false;
                                break;
                        case equal_char:
                                used->assign = true;
                                break;
                        case hyphen_char:
                                used->ignore_error = true;
                                break;
                        case at_char:
                                if (!do_not_exec_rule) {
                                        used->silent = true;
                                }
                                break;
                        case plus_char:
                                if(posix) {
                                  used->always_exec  = true;
                                }
                                break;
                        }
                }
                /* If all command lines of the template are prefixed with "?"*/
                /* the VIRTUAL_ROOT is not used for cmd consistency checks */
                if (!used->ignore_command_dependency) {
                        ignore_all_command_dependency = false;
                }
                /* Internalize the expanded and stripped command line */
                new_command_line = GETNAME(start, FIND_LENGTH);
                if ((used->command_line == NULL) &&
                    (line->body.line.sccs_command)) {
                        used->command_line = new_command_line;
                        new_command_longer = false;
                }
                /* Compare it with the old one for command consistency */
                if (used->command_line != new_command_line) {
                        Name vpath_translated = vpath_translation(new_command_line);
                        if (keep_state &&
                            !used->ignore_command_dependency && (vpath_translated != used->command_line)) {
                                if (debug_level > 0) {
                                        if (used->command_line != NULL
                                            && *used->command_line->string_mb !=
                                            '\0') {
                                                (void) printf(gettext("%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"),
                                                              recursion_level,
                                                              "",
                                                              target->string_mb,
                                                              vpath_translated->string_mb,
                                                              recursion_level,
                                                              "",
                                                              used->
                                                              command_line->
                                                              string_mb);
                                        } else {
                                                (void) printf(gettext("%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"),
                                                              recursion_level,
                                                              "",
                                                              target->string_mb,
                                                              vpath_translated->string_mb,
                                                              recursion_level,
                                                              "");
                                        }
                                }
                                command_changed = true;
                                line->body.line.is_out_of_date = true;
                        }
                        used->command_line = new_command_line;
                }
                if (command_line.free_after_use) {
                        retmem(command_line.buffer.start);
                }
        }
        /* Check if the old command is longer than the new for */
        /* command consistency */
        if (used != NULL) {
                *insert = NULL;
                if (keep_state &&
                    !ignore_all_command_dependency) {
                        if (debug_level > 0) {
                                (void) printf(gettext("%*sBuilding %s because new command shorter than old\n"),
                                              recursion_level,
                                              "",
                                              target->string_mb);
                        }
                        command_changed = true;
                        line->body.line.is_out_of_date = true;
                }
        }
        /* Check if the new command is longer than the old command for */
        /* command consistency */
        if (new_command_longer &&
            !ignore_all_command_dependency &&
            keep_state) {
                if (debug_level > 0) {
                        (void) printf(gettext("%*sBuilding %s because new command longer than old\n"),
                                      recursion_level,
                                      "",
                                      target->string_mb);
                }
                command_changed = true;
                line->body.line.is_out_of_date = true;
        }
        /* Unbind the magic macros */
        (void) SETVAR(c_at, (Name) NULL, false);
        (void) SETVAR(star, (Name) NULL, false);
        (void) SETVAR(less_name, (Name) NULL, false);
        (void) SETVAR(percent_name, (Name) NULL, false);
        (void) SETVAR(query, (Name) NULL, false);
        if (query_list != NULL) {
                delete_query_chain(query_list);
        }
        (void) SETVAR(hat, (Name) NULL, false);
        if (hat_list != NULL) {
                delete_query_chain(hat_list);
        }

        if (conditional_macro_used) {
                target->conditional_macro_list = cond_macro_list;
                cond_macro_list = NULL;
                target->depends_on_conditional = true;
        }
}

/*
 *      touch_command(line, target, result)
 *
 *      If this is an "make -t" run we do this.
 *      We touch all targets in the target group ("foo + fie:") if any.
 *
 *      Return value:
 *                              Indicates if the command failed or not
 *
 *      Parameters:
 *              line            The command line to update
 *              target          The target we are touching
 *              result          Initial value for the result we return
 *
 *      Global variables used:
 *              do_not_exec_rule Indicates that -n is on
 *              silent          Do not echo commands
 */
static Doname
touch_command(Property line, Name target, Doname result)
{
        Name                    name;
        Chain           target_group;
        String_rec              touch_string;
        wchar_t                 buffer[MAXPATHLEN];
        Name                    touch_cmd;
        Cmd_line                rule;

        for (name = target, target_group = NULL; name != NULL;) {
                if (!name->is_member) {
                        /*
                         * Build a touch command that can be passed
                         * to dosys(). If KEEP_STATE is on, "make -t"
                         * will save the proper command, not the
                         * "touch" in .make.state.
                         */
                        INIT_STRING_FROM_STACK(touch_string, buffer);
                        MBSTOWCS(wcs_buffer, "touch ");
                        append_string(wcs_buffer, &touch_string, FIND_LENGTH);
                        touch_cmd = name;
                        if (name->has_vpath_alias_prop) {
                                touch_cmd = get_prop(name->prop,
                                                 vpath_alias_prop)->
                                                   body.vpath_alias.alias;
                        }
                        APPEND_NAME(touch_cmd,
                                      &touch_string,
                                      FIND_LENGTH);
                        touch_cmd = GETNAME(touch_string.buffer.start,
                                            FIND_LENGTH);
                        if (touch_string.free_after_use) {
                                retmem(touch_string.buffer.start);
                        }
                        if (!silent ||
                            do_not_exec_rule &&
                            (target_group == NULL)) {
                                (void) printf("%s\n", touch_cmd->string_mb);
                        }
                        /* Run the touch command, or simulate it */
                        if (!do_not_exec_rule) {
                                result = dosys(touch_cmd,
                                               false,
                                               false,
                                               false,
                                               false,
                                               name);
                        } else {
                                result = build_ok;
                        }
                } else {
                        result = build_ok;
                }
                if (target_group == NULL) {
                        target_group = line->body.line.target_group;
                } else {
                        target_group = target_group->next;
                }
                if (target_group != NULL) {
                        name = target_group->name;
                } else {
                        name = NULL;
                }
        }
        return result;
}

/*
 *      update_target(line, result)
 *
 *      updates the status of a target after executing its commands.
 *
 *      Parameters:
 *              line            The command line block to update
 *              result          Indicates that build is OK so can update
 *
 *      Global variables used:
 *              do_not_exec_rule Indicates that -n is on
 *              touch           Fake the new timestamp if we are just touching
 */
void
update_target(Property line, Doname result)
{
        Name                    target;
        Chain                   target_group;
        Property                line2;
        timestruc_t             old_stat_time;
        Property                member;

        /*
         * [tolik] Additional fix for bug 1063790. It was fixed
         * for serial make long ago, but DMake dumps core when
         * target is a symlink and sccs file is newer then target.
         * In this case, finish_children() calls update_target()
         * with line==NULL.
         */
        if(line == NULL) {
                /* XXX. Should we do anything here? */
                return;
        }

        target = line->body.line.target;

        if ((result == build_ok) && (line->body.line.command_used != NULL)) {
                if (do_not_exec_rule ||
                    touch ||
                    (target->is_member &&
                     (line->body.line.command_template != NULL) &&
                     (line->body.line.command_template->command_line->string_mb[0] == 0) &&
                     (line->body.line.command_template->next == NULL))) {
                        /* If we are simulating execution we need to fake a */
                        /* new timestamp for the target we didnt build */
                        target->stat.time = file_max_time;
                } else {
                        /*
                         * If we really built the target we read the new
                         * timestamp.
                         * Fix for bug #1110906: if .c file is newer than
                         * the corresponding .o file which is in an archive
                         * file, make will compile the .c file but it won't
                         * update the object in the .a file.
                         */
                        old_stat_time = target->stat.time;
                        target->stat.time = file_no_time;
                        (void) exists(target);
                        if ((target->is_member) &&
                            (target->stat.time == old_stat_time)) {
                                member = get_prop(target->prop, member_prop);
                                if (member != NULL) {
                                        target->stat.time = member->body.member.library->stat.time;
                                        target->stat.time.tv_sec++;
                                }
                        }
                }
                /* If the target is part of a group we need to propagate the */
                /* result of the run to all members */
                for (target_group = line->body.line.target_group;
                     target_group != NULL;
                     target_group = target_group->next) {
                        target_group->name->stat.time = target->stat.time;
                        line2 = maybe_append_prop(target_group->name,
                                                  line_prop);
                        line2->body.line.command_used =
                          line->body.line.command_used;
                        line2->body.line.target = target_group->name;
                }
        }
        target->has_built = true;
}

/*
 *      sccs_get(target, command)
 *
 *      Figures out if it possible to sccs get a file
 *      and builds the command to do it if it is.
 *
 *      Return value:
 *                              Indicates if sccs get failed or not
 *
 *      Parameters:
 *              target          Target to get
 *              command         Where to deposit command to use
 *
 *      Global variables used:
 *              debug_level     Should we trace activities?
 *              recursion_level Used for tracing
 *              sccs_get_rule   The rule to used for sccs getting
 */
static Doname
sccs_get(Name target, Property *command)
{
        int             result;
        char                    link[MAXPATHLEN];
        String_rec              string;
        wchar_t                 name[MAXPATHLEN];
        wchar_t *p;
        timestruc_t             sccs_time;
        Property        line;
        int                     sym_link_depth = 0;

        /* For sccs, we need to chase symlinks. */
        while (target->stat.is_sym_link) {
                if (sym_link_depth++ > 90) {
                        fatal(gettext("Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."),
                              target->string_mb);
                }
                /* Read the value of the link. */
                result = readlink_vroot(target->string_mb,
                                        link,
                                        sizeof(link),
                                        NULL,
                                        VROOT_DEFAULT);
                if (result == -1) {
                        fatal(gettext("Can't read symbolic link `%s': %s"),
                              target->string_mb, errmsg(errno));
                }
                link[result] = 0;
                /* Use the value to build the proper filename. */
                INIT_STRING_FROM_STACK(string, name);

                Wstring wcb(target);
                if ((link[0] != slash_char) &&
                    ((p = (wchar_t *) wcsrchr(wcb.get_string(), slash_char)) != NULL)) {
                        append_string(wcb.get_string(), &string, p - wcb.get_string() + 1);
                }
                append_string(link, &string, result);
                /* Replace the old name with the translated name. */
                target = normalize_name(string.buffer.start, string.text.p - string.buffer.start);
                (void) exists(target);
                if (string.free_after_use) {
                        retmem(string.buffer.start);
                }
        }

        /*
         * read_dir() also reads the ?/SCCS dir and saves information
         * about which files have SCSC/s. files.
         */
        if (target->stat.has_sccs == DONT_KNOW_SCCS) {
                read_directory_of_file(target);
        }
        switch (target->stat.has_sccs) {
        case DONT_KNOW_SCCS:
                /* We dont know by now there is no SCCS/s.* */
                target->stat.has_sccs = NO_SCCS;
                /* FALLTHROUGH */
        case NO_SCCS:
                /*
                 * If there is no SCCS/s.* but the plain file exists,
                 * we say things are OK.
                 */
                if (target->stat.time > file_doesnt_exist) {
                        return build_ok;
                }
                /* If we cant find the plain file, we give up. */
                return build_dont_know;
        case HAS_SCCS:
                /*
                 * Pay dirt. We now need to figure out if the plain file
                 * is out of date relative to the SCCS/s.* file.
                 */
                sccs_time = exists(get_prop(target->prop,
                                            sccs_prop)->body.sccs.file);
                break;
        }

        if ((!target->has_complained &&
            (sccs_time != file_doesnt_exist) &&
            (sccs_get_rule != NULL))) {
                /* only checking */
                if (command == NULL) {
                        return build_ok;
                }
                /*
                 * We provide a command line for the target. The line is a
                 * "sccs get" command from default.mk.
                 */
                line = maybe_append_prop(target, line_prop);
                *command = line;
                if (sccs_time > target->stat.time) {
                        /*
                         * And only if the plain file is out of date do we
                         * request execution of the command.
                         */
                        line->body.line.is_out_of_date = true;
                        if (debug_level > 0) {
                                (void) printf(gettext("%*sSccs getting %s because s. file is younger than source file\n"),
                                              recursion_level,
                                              "",
                                              target->string_mb);
                        }
                }
                line->body.line.sccs_command = true;
                line->body.line.command_template = sccs_get_rule;
                if(!svr4 && (!allrules_read || posix)) {
                   if((target->prop) &&
                      (target->prop->body.sccs.file) &&
                      (target->prop->body.sccs.file->string_mb)) {
                      if((strlen(target->prop->body.sccs.file->string_mb) ==
                        strlen(target->string_mb) + 2) &&
                        (target->prop->body.sccs.file->string_mb[0] == 's') &&
                        (target->prop->body.sccs.file->string_mb[1] == '.')) {

                         line->body.line.command_template = get_posix_rule;
                      }
                   }
                }
                line->body.line.target = target;
                /*
                 * Also make sure the rule is build with $* and $<
                 * bound properly.
                 */
                line->body.line.star = NULL;
                line->body.line.less = NULL;
                line->body.line.percent = NULL;
                return build_ok;
        }
        return build_dont_know;
}

/*
 *      read_directory_of_file(file)
 *
 *      Reads the directory the specified file lives in.
 *
 *      Parameters:
 *              file            The file we need to read dir for
 *
 *      Global variables used:
 *              dot             The Name ".", used as the default dir
 */
void
read_directory_of_file(Name file)
{

        Wstring file_string(file);
        wchar_t * wcb = file_string.get_string();
        wchar_t usr_include_buf[MAXPATHLEN];
        wchar_t usr_include_sys_buf[MAXPATHLEN];

        Name            directory = dot;
        wchar_t *p = (wchar_t *) wcsrchr(wcb,
                                                        (int) slash_char);
        int             length = p - wcb;
        static Name             usr_include;
        static Name             usr_include_sys;

        if (usr_include == NULL) {
                MBSTOWCS(usr_include_buf, "/usr/include");
                usr_include = GETNAME(usr_include_buf, FIND_LENGTH);
                MBSTOWCS(usr_include_sys_buf, "/usr/include/sys");
                usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH);
        }

        /*
         * If the filename contains a "/" we have to extract the path
         * Else the path defaults to ".".
         */
        if (p != NULL) {
                /*
                 * Check some popular directories first to possibly
                 * save time. Compare string length first to gain speed.
                 */
                if ((usr_include->hash.length == length) &&
                    IS_WEQUALN(usr_include_buf,
                               wcb,
                               length)) {
                        directory = usr_include;
                } else if ((usr_include_sys->hash.length == length) &&
                           IS_WEQUALN(usr_include_sys_buf,
                                      wcb,
                                      length)) {
                        directory = usr_include_sys;
                } else {
                        directory = GETNAME(wcb, length);
                }
        }
        (void) read_dir(directory,
                        (wchar_t *) NULL,
                        (Property) NULL,
                        (wchar_t *) NULL);
}

/*
 *      add_pattern_conditionals(target)
 *
 *      Scan the list of conditionals defined for pattern targets and add any
 *      that match this target to its list of conditionals.
 *
 *      Parameters:
 *              target          The target we should add conditionals for
 *
 *      Global variables used:
 *              conditionals    The list of pattern conditionals
 */
static void
add_pattern_conditionals(Name target)
{
        Property        conditional;
        Property                new_prop;
        Property                *previous;
        Name_rec                dummy;
        wchar_t                 *pattern;
        wchar_t                 *percent;
        int                     length;

        Wstring wcb(target);
        Wstring wcb1;

        for (conditional = get_prop(conditionals->prop, conditional_prop);
             conditional != NULL;
             conditional = get_prop(conditional->next, conditional_prop)) {
                wcb1.init(conditional->body.conditional.target);
                pattern = wcb1.get_string();
                if (pattern[1] != 0) {
                        percent = (wchar_t *) wcschr(pattern, (int) percent_char);
                        /* Check for possible buffer under-read */
                        if ((length = wcb.length()-wcslen(percent+1)) <= 0) {
                                continue;
                        }
                        if (!wcb.equaln(pattern, percent-pattern) ||
                            !IS_WEQUAL(wcb.get_string(length), percent+1)) {
                                continue;
                        }
                }
                for (previous = &target->prop;
                     *previous != NULL;
                     previous = &(*previous)->next) {
                        if (((*previous)->type == conditional_prop) &&
                            ((*previous)->body.conditional.sequence >
                             conditional->body.conditional.sequence)) {
                                break;
                        }
                }
                if (*previous == NULL) {
                        new_prop = append_prop(target, conditional_prop);
                } else {
                        dummy.prop = NULL;
                        new_prop = append_prop(&dummy, conditional_prop);
                        new_prop->next = *previous;
                        *previous = new_prop;
                }
                target->conditional_cnt++;
                new_prop->body.conditional = conditional->body.conditional;
        }
}

/*
 *      set_locals(target, old_locals)
 *
 *      Sets any conditional macros for the target.
 *      Each target carries a possibly empty set of conditional properties.
 *
 *      Parameters:
 *              target          The target to set conditional macros for
 *              old_locals      Space to store old values in
 *
 *      Global variables used:
 *              debug_level     Should we trace activity?
 *              is_conditional  We need to preserve this value
 *              recursion_level Used for tracing
 */
void
set_locals(Name target, Property old_locals)
{
        Property        conditional;
        int             i;
        Boolean saved_conditional_macro_used;
        Chain                   cond_name;
        Chain                   cond_chain;

        if (target->dont_activate_cond_values) {
                return;
        }

        saved_conditional_macro_used = conditional_macro_used;

        /* Scan the list of conditional properties and apply each one */
        for (conditional = get_prop(target->prop, conditional_prop), i = 0;
             conditional != NULL;
             conditional = get_prop(conditional->next, conditional_prop),
             i++) {
                /* Save the old value */
                old_locals[i].body.macro =
                  maybe_append_prop(conditional->body.conditional.name,
                                    macro_prop)->body.macro;
                if (debug_level > 1) {
                        (void) printf(gettext("%*sActivating conditional value: "),
                                      recursion_level,
                                      "");
                }
                /* Set the conditional value. Macros are expanded when the */
                /* macro is refd as usual */
                if ((conditional->body.conditional.name != virtual_root) ||
                    (conditional->body.conditional.value != virtual_root)) {
                        (void) SETVAR(conditional->body.conditional.name,
                                      conditional->body.conditional.value,
                                      (Boolean) conditional->body.conditional.append);
                }
                cond_name = ALLOC(Chain);
                cond_name->name = conditional->body.conditional.name;
        }
        /* Put this target on the front of the chain of conditional targets */
        cond_chain = ALLOC(Chain);
        cond_chain->name = target;
        cond_chain->next = conditional_targets;
        conditional_targets = cond_chain;
        conditional_macro_used = saved_conditional_macro_used;
}

/*
 *      reset_locals(target, old_locals, conditional, index)
 *
 *      Removes any conditional macros for the target.
 *
 *      Parameters:
 *              target          The target we are retoring values for
 *              old_locals      The values to restore
 *              conditional     The first conditional block for the target
 *              index           into the old_locals vector
 *      Global variables used:
 *              debug_level     Should we trace activities?
 *              recursion_level Used for tracing
 */
void
reset_locals(Name target, Property old_locals, Property conditional, int index)
{
        Property        this_conditional;
        Chain                   cond_chain;

        if (target->dont_activate_cond_values) {
                return;
        }

        /* Scan the list of conditional properties and restore the old value */
        /* to each one Reverse the order relative to when we assigned macros */
        this_conditional = get_prop(conditional->next, conditional_prop);
        if (this_conditional != NULL) {
                reset_locals(target, old_locals, this_conditional, index+1);
        } else {
                /* Remove conditional target from chain */
                if (conditional_targets == NULL ||
                    conditional_targets->name != target) {
                        warning(gettext("Internal error: reset target not at head of condtional_targets chain"));
                } else {
                        cond_chain = conditional_targets->next;
                        retmem_mb((caddr_t) conditional_targets);
                        conditional_targets = cond_chain;
                }
        }
        get_prop(conditional->body.conditional.name->prop,
                 macro_prop)->body.macro = old_locals[index].body.macro;
        if (conditional->body.conditional.name == virtual_root) {
                (void) SETVAR(virtual_root, getvar(virtual_root), false);
        }
        if (debug_level > 1) {
                if (old_locals[index].body.macro.value != NULL) {
                        (void) printf(gettext("%*sdeactivating conditional value: %s= %s\n"),
                                      recursion_level,
                                      "",
                                      conditional->body.conditional.name->
                                      string_mb,
                                      old_locals[index].body.macro.value->
                                      string_mb);
                } else {
                        (void) printf(gettext("%*sdeactivating conditional value: %s =\n"),
                                      recursion_level,
                                      "",
                                      conditional->body.conditional.name->
                                      string_mb);
                }
        }
}

/*
 *      check_auto_dependencies(target, auto_count, automatics)
 *
 *      Returns true if the target now has a dependency
 *      it didn't previously have (saved on automatics).
 *
 *      Return value:
 *                              true if new dependency found
 *
 *      Parameters:
 *              target          Target we check
 *              auto_count      Number of old automatic vars
 *              automatics      Saved old automatics
 *
 *      Global variables used:
 *              keep_state      Indicates that .KEEP_STATE is on
 */
Boolean
check_auto_dependencies(Name target, int auto_count, Name *automatics)
{
        Name            *p;
        int             n;
        Property        line;
        Dependency      dependency;

        if (keep_state) {
                if ((line = get_prop(target->prop, line_prop)) == NULL) {
                        return false;
                }
                /* Go thru new list of automatic depes */
                for (dependency = line->body.line.dependencies;
                     dependency != NULL;
                     dependency = dependency->next) {
                        /* And make sure that each one existed before we */
                        /* built the target */
                        if (dependency->automatic && !dependency->stale) {
                                for (n = auto_count, p = automatics;
                                     n > 0;
                                     n--) {
                                        if (*p++ == dependency->name) {
                                                /* If we can find it on the */
                                                /* saved list of autos we */
                                                /* are OK  */
                                                goto not_new;
                                        }
                                }
                                /* But if we scan over the old list */
                                /* of auto. without finding it it is */
                                /* new and we must check it */
                                return true;
                        }
                not_new:;
                }
                return false;
        } else {
                return false;
        }
}


// Recursively delete each of the Chain struct on the chain.

static void
delete_query_chain(Chain ch)
{
        if (ch == NULL) {
                return;
        } else {
                delete_query_chain(ch->next);
                retmem_mb((char *) ch);
        }
}

Doname
target_can_be_built(Name target) {
        Doname          result = build_dont_know;
        Name            true_target = target;
        Property        line;

        if (target == wait_name) {
                return(build_ok);
        }
        /*
         * If the target is a constructed one for a "::" target,
         * we need to consider that.
         */
        if (target->has_target_prop) {
                true_target = get_prop(target->prop,
                                       target_prop)->body.target.target;
        }

        (void) exists(true_target);

        if (true_target->state == build_running) {
                return(build_running);
        }
        if (true_target->stat.time != file_doesnt_exist) {
                result = build_ok;
        }

        /* get line property for the target */
        line = get_prop(true_target->prop, line_prop);

        /* first check for explicit rule */
        if (line != NULL && line->body.line.command_template != NULL) {
                result = build_ok;
        }
        /* try to find pattern rule */
        if (result == build_dont_know) {
                result = find_percent_rule(target, NULL, false);
        }

        /* try to find double suffix rule */
        if (result == build_dont_know) {
                if (target->is_member) {
                        Property member = get_prop(target->prop, member_prop);
                        if (member != NULL && member->body.member.member != NULL) {
                                result = find_ar_suffix_rule(target, member->body.member.member, NULL, false);
                        } else {
                                result = find_double_suffix_rule(target, NULL, false);
                        }
                } else {
                        result = find_double_suffix_rule(target, NULL, false);
                }
        }

        /* try to find suffix rule */
        if ((result == build_dont_know) && second_pass) {
                result = find_suffix_rule(target, target, empty_name, NULL, false);
        }

        /* check for sccs */
        if (result == build_dont_know) {
                result = sccs_get(target, NULL);
        }

        /* try to find dyn target */
        if (result == build_dont_know) {
                Name dtarg = find_dyntarget(target);
                if (dtarg != NULL) {
                        result = target_can_be_built(dtarg);
                }
        }

        /* check whether target was mentioned in makefile */
        if (result == build_dont_know) {
                if (target->colons != no_colon) {
                        result = build_ok;
                }
        }

        /* result */
        return result;
}