1*18cc0328Sespie /* $OpenBSD: dump.c,v 1.12 2020/01/26 12:41:21 espie Exp $ */
2a6b963c8Sespie /*
3a6b963c8Sespie * Copyright (c) 2012 Marc Espie.
4a6b963c8Sespie *
5a6b963c8Sespie * Redistribution and use in source and binary forms, with or without
6a6b963c8Sespie * modification, are permitted provided that the following conditions
7a6b963c8Sespie * are met:
8a6b963c8Sespie * 1. Redistributions of source code must retain the above copyright
9a6b963c8Sespie * notice, this list of conditions and the following disclaimer.
10a6b963c8Sespie * 2. Redistributions in binary form must reproduce the above copyright
11a6b963c8Sespie * notice, this list of conditions and the following disclaimer in the
12a6b963c8Sespie * documentation and/or other materials provided with the distribution.
13a6b963c8Sespie *
14a6b963c8Sespie * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
15a6b963c8Sespie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16a6b963c8Sespie * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17a6b963c8Sespie * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
18a6b963c8Sespie * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19a6b963c8Sespie * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20a6b963c8Sespie * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21a6b963c8Sespie * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22a6b963c8Sespie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23a6b963c8Sespie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24a6b963c8Sespie * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25a6b963c8Sespie */
261bae8e1fSespie #include <limits.h>
271f89b472Sespie #include <stddef.h>
281f89b472Sespie #include <stdint.h>
291f89b472Sespie #include <stdio.h>
301f89b472Sespie #include <stdlib.h>
311f89b472Sespie #include <string.h>
321f89b472Sespie #include <ohash.h>
33a6b963c8Sespie #include "defines.h"
341bae8e1fSespie #include "gnode.h"
35a6b963c8Sespie #include "dump.h"
36a6b963c8Sespie #include "targ.h"
371bae8e1fSespie #include "var.h"
381bae8e1fSespie #include "memory.h"
391bae8e1fSespie #include "suff.h"
401bae8e1fSespie #include "lst.h"
411bae8e1fSespie #include "timestamp.h"
421bae8e1fSespie #include "dir.h"
431bae8e1fSespie
441bae8e1fSespie /* since qsort doesn't have user data, this needs to be a global... */
451bae8e1fSespie static ptrdiff_t cmp_offset;
461bae8e1fSespie static void targ_dump(bool);
471bae8e1fSespie
481bae8e1fSespie static int
compare_names(const void * a,const void * b)491bae8e1fSespie compare_names(const void *a, const void *b)
501bae8e1fSespie {
511bae8e1fSespie const char **pa = (const char **)a;
521bae8e1fSespie const char **pb = (const char **)b;
531bae8e1fSespie return strcmp((*pa) + cmp_offset, (*pb) + cmp_offset);
541bae8e1fSespie }
551bae8e1fSespie
561bae8e1fSespie void *
sort_ohash_by_name(struct ohash * h)571bae8e1fSespie sort_ohash_by_name(struct ohash *h)
581bae8e1fSespie {
591bae8e1fSespie cmp_offset = h->info.key_offset;
601bae8e1fSespie
611bae8e1fSespie return sort_ohash(h, compare_names);
621bae8e1fSespie }
631bae8e1fSespie
641bae8e1fSespie void *
sort_ohash(struct ohash * h,int (* comparison)(const void *,const void *))651bae8e1fSespie sort_ohash(struct ohash *h, int (*comparison)(const void *, const void *))
661bae8e1fSespie {
671bae8e1fSespie unsigned int i, j;
681bae8e1fSespie void *e;
691bae8e1fSespie size_t n = ohash_entries(h);
7077c73da2Sespie void **t = ereallocarray(NULL, n+1, sizeof(void *));
711bae8e1fSespie cmp_offset = h->info.key_offset;
721bae8e1fSespie
731bae8e1fSespie for (i = 0, e = ohash_first(h, &j); e != NULL; e = ohash_next(h, &j))
741bae8e1fSespie t[i++] = e;
751bae8e1fSespie qsort(t, n, sizeof(void *), comparison);
761bae8e1fSespie /* add an extra entry to be able to figure out the end without needing
771bae8e1fSespie * to keep a counter */
781bae8e1fSespie t[n] = NULL;
791bae8e1fSespie return t;
801bae8e1fSespie }
811bae8e1fSespie
821bae8e1fSespie static void
TargPrintName(void * gnp)831bae8e1fSespie TargPrintName(void *gnp)
841bae8e1fSespie {
856eef43d0Sespie const GNode *gn = gnp;
861bae8e1fSespie printf("%s ", gn->name);
871bae8e1fSespie }
881bae8e1fSespie
891bae8e1fSespie static void
TargPrintOnlySrc(GNode * gn)901bae8e1fSespie TargPrintOnlySrc(GNode *gn)
911bae8e1fSespie {
921bae8e1fSespie if (OP_NOP(gn->type) && gn->special == SPECIAL_NONE &&
931bae8e1fSespie !(gn->type & OP_DUMMY)) {
941bae8e1fSespie if (gn->path != NULL)
951bae8e1fSespie printf("#\t%s [%s]\n", gn->name,
961bae8e1fSespie strcmp(gn->path, gn->name) == 0 ? "=" : gn->path);
971bae8e1fSespie else
981bae8e1fSespie printf("#\t%s\n", gn->name);
991bae8e1fSespie }
1001bae8e1fSespie }
1011bae8e1fSespie
1021bae8e1fSespie static void
TargPrintNode(GNode * gn,bool full)1031bae8e1fSespie TargPrintNode(GNode *gn, bool full)
1041bae8e1fSespie {
1051bae8e1fSespie if (OP_NOP(gn->type))
1061bae8e1fSespie return;
1071471c3c2Sespie switch(gn->special) {
1081bae8e1fSespie case SPECIAL_SUFFIXES:
1091bae8e1fSespie case SPECIAL_PHONY:
1101bae8e1fSespie case SPECIAL_ORDER:
11129936c8aSespie case SPECIAL_NOTHING:
1121bae8e1fSespie case SPECIAL_MAIN:
1131bae8e1fSespie case SPECIAL_IGNORE:
1141bae8e1fSespie return;
1151bae8e1fSespie default:
1161bae8e1fSespie break;
1171bae8e1fSespie }
1181bae8e1fSespie if (full) {
119194f6eccSespie printf("# %d unmade prerequisites\n", gn->children_left);
120*18cc0328Sespie if (! (gn->type & OP_USE)) {
1211bae8e1fSespie if (!is_out_of_date(gn->mtime)) {
1221bae8e1fSespie printf("# last modified %s: %s\n",
1234c9de429Sespie time_to_string(&gn->mtime),
1241bae8e1fSespie status_to_string(gn));
1251bae8e1fSespie } else if (gn->built_status != UNKNOWN) {
1261bae8e1fSespie printf("# non-existent (maybe): %s\n",
1271bae8e1fSespie status_to_string(gn));
1281bae8e1fSespie } else {
1291bae8e1fSespie printf("# unmade\n");
1301bae8e1fSespie }
1311bae8e1fSespie }
1321bae8e1fSespie }
1331bae8e1fSespie if (!Lst_IsEmpty(&gn->parents)) {
1341bae8e1fSespie printf("# parent targets: ");
1351bae8e1fSespie Lst_Every(&gn->parents, TargPrintName);
1361bae8e1fSespie fputc('\n', stdout);
1371bae8e1fSespie }
1381bae8e1fSespie if (gn->impliedsrc)
1391bae8e1fSespie printf("# implied prerequisite: %s\n", gn->impliedsrc->name);
1401bae8e1fSespie
1411bae8e1fSespie printf("%-16s", gn->name);
1421bae8e1fSespie switch (gn->type & OP_OPMASK) {
1431bae8e1fSespie case OP_DEPENDS:
1441bae8e1fSespie printf(": "); break;
1451bae8e1fSespie case OP_FORCE:
1461bae8e1fSespie printf("! "); break;
1471bae8e1fSespie case OP_DOUBLEDEP:
1481bae8e1fSespie printf(":: "); break;
1491bae8e1fSespie }
1501bae8e1fSespie Targ_PrintType(gn->type);
1511bae8e1fSespie Lst_Every(&gn->children, TargPrintName);
1521bae8e1fSespie fputc('\n', stdout);
1531bae8e1fSespie Lst_Every(&gn->commands, Targ_PrintCmd);
1541bae8e1fSespie printf("\n\n");
1551bae8e1fSespie if (gn->type & OP_DOUBLEDEP) {
1561bae8e1fSespie LstNode ln;
1571bae8e1fSespie
1581bae8e1fSespie for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
159568f6c05Sespie TargPrintNode(Lst_Datum(ln), full);
1601bae8e1fSespie }
1611bae8e1fSespie }
1621bae8e1fSespie
1631bae8e1fSespie static void
dump_special(GNode ** t,const char * name,int prop)1641bae8e1fSespie dump_special(GNode **t, const char *name, int prop)
1651bae8e1fSespie {
1661bae8e1fSespie unsigned int i;
1671bae8e1fSespie bool first = true;
1681bae8e1fSespie
1691bae8e1fSespie for (i = 0; t[i] != NULL; i++)
1701bae8e1fSespie if (t[i]->type & prop) {
1711bae8e1fSespie if (first) {
1721bae8e1fSespie printf("%s:", name);
1731bae8e1fSespie first = false;
1741bae8e1fSespie }
1751bae8e1fSespie printf(" %s", t[i]->name);
1761bae8e1fSespie }
1771bae8e1fSespie if (!first)
1781bae8e1fSespie printf("\n\n");
1791bae8e1fSespie }
1801bae8e1fSespie
1811bae8e1fSespie static void
targ_dump(bool full)1821bae8e1fSespie targ_dump(bool full)
1831bae8e1fSespie {
1841bae8e1fSespie GNode **t = sort_ohash_by_name(targets_hash());
1851bae8e1fSespie unsigned int i;
1861bae8e1fSespie
1871bae8e1fSespie printf("# Input graph:\n");
1881bae8e1fSespie for (i = 0; t[i] != NULL; i++)
1891bae8e1fSespie TargPrintNode(t[i], full);
1901bae8e1fSespie printf("\n\n");
1911bae8e1fSespie
1921bae8e1fSespie dump_special(t, ".PHONY", OP_PHONY);
1931bae8e1fSespie dump_special(t, ".PRECIOUS", OP_PRECIOUS);
1941bae8e1fSespie dump_special(t, ".SILENT", OP_SILENT);
1951bae8e1fSespie dump_special(t, ".IGNORE", OP_IGNORE);
1961bae8e1fSespie printf("# Other target names:\n");
1971bae8e1fSespie for (i = 0; t[i] != NULL; i++)
1981bae8e1fSespie TargPrintOnlySrc(t[i]);
1991bae8e1fSespie printf("\n");
2001bae8e1fSespie free(t);
2011bae8e1fSespie }
2021bae8e1fSespie
2031bae8e1fSespie static bool dumped_once = false;
204a6b963c8Sespie
205a6b963c8Sespie void
dump_data(void)206a6b963c8Sespie dump_data(void)
207a6b963c8Sespie {
2081bae8e1fSespie Var_Dump();
2091bae8e1fSespie Suff_PrintAll();
2101bae8e1fSespie targ_dump(false);
2111bae8e1fSespie dumped_once = true;
2121bae8e1fSespie }
2131bae8e1fSespie
2141bae8e1fSespie void
post_mortem(void)2151bae8e1fSespie post_mortem(void)
2161bae8e1fSespie {
2171bae8e1fSespie if (!dumped_once) {
2181bae8e1fSespie Var_Dump();
2191bae8e1fSespie Suff_PrintAll();
2201bae8e1fSespie }
2211bae8e1fSespie targ_dump(true);
222a6b963c8Sespie }
223