root/usr/src/cmd/make/bin/nse_printdep.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 2003 Sun Microsystems, Inc. All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Included files
 */
#include <mk/defs.h>
#include <mksh/misc.h>          /* get_prop() */

/*
 * File table of contents
 */
void   print_dependencies(Name target, Property line);
static void     print_deps(Name target, Property line);
static void     print_more_deps(Name target, Name name);
static void     print_filename(Name name);
static Boolean  should_print_dep(Property line);
static void     print_forest(Name target);
static void     print_deplist(Dependency head);
void            print_value(Name value, Daemon daemon);
static void     print_rule(Name target);
static  void    print_rec_info(Name target);
static Boolean  is_out_of_date(Property line);
extern void depvar_print_results (void);

/*
 *      print_dependencies(target, line)
 *
 *      Print all the dependencies of a target. First print all the Makefiles.
 *      Then print all the dependencies. Finally, print all the .INIT
 *      dependencies.
 *
 *      Parameters:
 *              target          The target we print dependencies for
 *              line            We get the dependency list from here
 *
 *      Global variables used:
 *              done            The Name ".DONE"
 *              init            The Name ".INIT"
 *              makefiles_used  List of all makefiles read
 */
void
print_dependencies(Name target, Property line)
{
        Dependency      dp;
        static Boolean  makefiles_printed = false;

        if (target_variants) {
                depvar_print_results();
        }

        if (!makefiles_printed) {
                /*
                 * Search the makefile list for the primary makefile,
                 * then print it and its inclusions.  After that go back
                 * and print the default.mk file and its inclusions.
                 */
                for (dp = makefiles_used; dp != NULL; dp = dp->next) {
                        if (dp->name == primary_makefile) {
                                break;
                        }
                }
                if (dp) {
                        print_deplist(dp);
                        for (dp = makefiles_used; dp != NULL; dp = dp->next) {
                                if (dp->name == primary_makefile) {
                                        break;
                                }
                                (void)printf(" %s", dp->name->string_mb);
                        }
                }
                (void) printf("\n");
                makefiles_printed = true;
        }
        print_deps(target, line);
/*
        print_more_deps(target, init);
        print_more_deps(target, done);
 */
        if (target_variants) {
                print_forest(target);
        }
}

/*
 *      print_more_deps(target, name)
 *
 *      Print some special dependencies.
 *      These are the dependencies for the .INIT and .DONE targets.
 *
 *      Parameters:
 *              target          Target built during make run
 *              name            Special target to print dependencies for
 *
 *      Global variables used:
 */
static void
print_more_deps(Name target, Name name)
{
        Property        line;
        Dependency      dependencies;

        line = get_prop(name->prop, line_prop);
        if (line != NULL && line->body.line.dependencies != NULL) {
                (void) printf("%s:\t", target->string_mb);
                print_deplist(line->body.line.dependencies);
                (void) printf("\n");
                for (dependencies= line->body.line.dependencies;
                     dependencies != NULL;
                     dependencies= dependencies->next) {
                         print_deps(dependencies->name,
                                 get_prop(dependencies->name->prop, line_prop));
                }
        }
}

/*
 *      print_deps(target, line, go_recursive)
 *
 *      Print a regular dependency list.  Append to this information which
 *      indicates whether or not the target is recursive.
 *
 *      Parameters:
 *              target          target to print dependencies for
 *              line            We get the dependency list from here
 *              go_recursive    Should we show all dependencies recursively?
 *
 *      Global variables used:
 *              recursive_name  The Name ".RECURSIVE", printed
 */
static void
print_deps(Name target, Property line)
{
        Dependency      dep;

        if ((target->dependency_printed) ||
            (target == force)) {
                return;
        }
        target->dependency_printed = true;

        /* only print entries that are actually derived and are not leaf
         * files and are not the result of sccs get.
         */
        if (should_print_dep(line)) {
                if ((report_dependencies_level == 2) ||
                    (report_dependencies_level == 4)) {
                        if (is_out_of_date(line)) {
                                (void) printf("1 ");
                        } else {
                                (void) printf("0 ");
                        }
                }
                print_filename(target);
                (void) printf(":\t");
                print_deplist(line->body.line.dependencies);
                print_rec_info(target);
                (void) printf("\n");
                for (dep = line->body.line.dependencies;
                     dep != NULL;
                     dep = dep->next) {
                        print_deps(dep->name,
                                   get_prop(dep->name->prop, line_prop));
                }
        }
}

static Boolean
is_out_of_date(Property line)
{
        Dependency      dep;
        Property        line2;

        if (line == NULL) {
                return false;
        }
        if (line->body.line.is_out_of_date) {
                return true;
        }
        for (dep = line->body.line.dependencies;
             dep != NULL;
             dep = dep->next) {
                line2 = get_prop(dep->name->prop, line_prop);
                if (is_out_of_date(line2)) {
                        line->body.line.is_out_of_date = true;
                        return true;
                }
        }
        return false;
}

/*
 * Given a dependency print it and all its siblings.
 */
static void
print_deplist(Dependency head)
{
        Dependency      dp;

        for (dp = head; dp != NULL; dp = dp->next) {
                if ((report_dependencies_level != 2) ||
                    ((!dp->automatic) ||
                     (dp->name->is_double_colon))) {
                        if (dp->name != force) {
                                putwchar(' ');
                                print_filename(dp->name);
                        }
                }
        }
}

/*
 * Print the name of a file for the -P option.
 * If the file is a directory put on a trailing slash.
 */
static void
print_filename(Name name)
{
        (void) printf("%s", name->string_mb);
/*
        if (name->stat.is_dir) {
                putwchar('/');
        }
 */
}

/*
 *      should_print_dep(line)
 *
 *      Test if we should print the dependencies of this target.
 *      The line must exist and either have children dependencies
 *      or have a command that is not an SCCS command.
 *
 *      Return value:
 *                              true if the dependencies should be printed
 *
 *      Parameters:
 *              line            We get the dependency list from here
 *
 *      Global variables used:
 */
static Boolean
should_print_dep(Property line)
{
        if (line == NULL) {
                return false;
        }
        if (line->body.line.dependencies != NULL) {
                return true;
        }
        if (line->body.line.sccs_command) {
                return false;
        }
        return true;
}

/*
 * Print out the root nodes of all the dependency trees
 * in this makefile.
 */
static void
print_forest(Name target)
{
        Name_set::iterator np, e;
        Property        line;

        for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
                        if (np->is_target && !np->has_parent && np != target) {
                                (void) doname_check(np, true, false, false);
                                line = get_prop(np->prop, line_prop);
                                printf("-\n");
                                print_deps(np, line);
                        }
        }
}


/*
 *      This is a set  of routines for dumping the internal make state
 *      Used for the -p option
 */
void
print_value(Name value, Daemon daemon)
{
        Chain                   cp;

        if (value == NULL)
                (void)printf("=\n");
        else
                switch (daemon) {
                    case no_daemon:
                        (void)printf("= %s\n", value->string_mb);
                        break;
                    case chain_daemon:
                        for (cp= (Chain) value; cp != NULL; cp= cp->next)
                                (void)printf(cp->next == NULL ? "%s" : "%s ",
                                        cp->name->string_mb);
                        (void)printf("\n");
                        break;
                };
}

static void
print_rule(Name target)
{
        Cmd_line        rule;
        Property        line;

        if (((line= get_prop(target->prop, line_prop)) == NULL) ||
            ((line->body.line.command_template == NULL) &&
             (line->body.line.dependencies == NULL)))
                return;
        print_dependencies(target, line);
        for (rule= line->body.line.command_template; rule != NULL; rule= rule->next)
                (void)printf("\t%s\n", rule->command_line->string_mb);
}


/*
 *  If target is recursive,  print the following to standard out:
 *      .RECURSIVE subdir targ Makefile
 */
static void
print_rec_info(Name target)
{
        Recursive_make  rp;
        wchar_t         *colon;

        report_recursive_init();

        rp = find_recursive_target(target);

        if (rp) {
                /*
                 * if found,  print starting with the space after the ':'
                 */
                colon = (wchar_t *) wcschr(rp->oldline, (int) colon_char);
                (void) printf("%s", colon + 1);
        }
}