181bcec06SDavid du Colombier /*
281bcec06SDavid du Colombier * calls - print a paragraphed list of who calls whom within a body of C source
381bcec06SDavid du Colombier *
481bcec06SDavid du Colombier * Author: M.M. Taylor, DCIEM, Toronto, Canada.
581bcec06SDavid du Colombier * Modified by Alexis Kwan (HCR at DCIEM),
681bcec06SDavid du Colombier * Kevin Szabo (watmath!wateng!ksbszabo, Elec Eng, U of Waterloo),
781bcec06SDavid du Colombier * Tony Hansen, AT&T-IS, pegasus!hansen.
881bcec06SDavid du Colombier */
981bcec06SDavid du Colombier
1081bcec06SDavid du Colombier #include <u.h>
1181bcec06SDavid du Colombier #include <libc.h>
1281bcec06SDavid du Colombier #include <ctype.h>
1381bcec06SDavid du Colombier #include <bio.h>
1481bcec06SDavid du Colombier #include <String.h>
1581bcec06SDavid du Colombier
1681bcec06SDavid du Colombier #define CPP "cpp -+"
1781bcec06SDavid du Colombier #define RINSTERR ((Rinst *)-1) /* ugly; error but keep going */
1881bcec06SDavid du Colombier
1981bcec06SDavid du Colombier #define STREQ(a, b) (*(a) == *(b) && strcmp(a, b) == 0)
2081bcec06SDavid du Colombier #define OTHER(rdwr) ((rdwr) == Rd? Wr: Rd)
2181bcec06SDavid du Colombier /* per 8c, all multibyte runes are considered alphabetic */
2281bcec06SDavid du Colombier #define ISIDENT(r) (isascii(r) && isalnum(r) || (r) == '_' || (r) >= Runeself)
2381bcec06SDavid du Colombier
2481bcec06SDavid du Colombier /* safe macros */
2581bcec06SDavid du Colombier #define checksys(atom) strbsearch(atom, sysword, nelem(sysword))
2681bcec06SDavid du Colombier
2781bcec06SDavid du Colombier enum {
2881bcec06SDavid du Colombier Printstats = 0, /* flag */
29*0b04b1f8SDavid du Colombier Maxseen = 4000, /* # of instances w/in a function */
3081bcec06SDavid du Colombier Maxdepth = 300, /* max func call tree depth */
3181bcec06SDavid du Colombier Hashsize = 2048,
3281bcec06SDavid du Colombier
3381bcec06SDavid du Colombier Maxid = 256 + UTFmax, /* max size of name */
3481bcec06SDavid du Colombier Tabwidth = 8,
3581bcec06SDavid du Colombier Maxwidth = 132, /* limits tabbing */
3681bcec06SDavid du Colombier Defwidth = 80, /* limits tabbing */
3781bcec06SDavid du Colombier
3881bcec06SDavid du Colombier Backslash = '\\',
3981bcec06SDavid du Colombier Quote = '\'',
4081bcec06SDavid du Colombier
4181bcec06SDavid du Colombier Rd = 0, /* pipe indices */
4281bcec06SDavid du Colombier Wr,
4381bcec06SDavid du Colombier
4481bcec06SDavid du Colombier Stdin = 0,
4581bcec06SDavid du Colombier Stdout,
4681bcec06SDavid du Colombier Stderr,
4781bcec06SDavid du Colombier
4881bcec06SDavid du Colombier Defn = 0,
4981bcec06SDavid du Colombier Decl,
5081bcec06SDavid du Colombier Call,
5181bcec06SDavid du Colombier
5281bcec06SDavid du Colombier Nomore = -1,
5381bcec06SDavid du Colombier Added,
5481bcec06SDavid du Colombier Found,
5581bcec06SDavid du Colombier };
5681bcec06SDavid du Colombier
5781bcec06SDavid du Colombier typedef struct Pushstate Pushstate;
5881bcec06SDavid du Colombier typedef struct Rinst Rinst;
5981bcec06SDavid du Colombier typedef struct Root Root;
6081bcec06SDavid du Colombier typedef struct Rname Rname;
6181bcec06SDavid du Colombier typedef struct Rnamehash Rnamehash;
6281bcec06SDavid du Colombier
6381bcec06SDavid du Colombier struct Pushstate {
6481bcec06SDavid du Colombier int kid;
6581bcec06SDavid du Colombier int fd; /* original fd */
6681bcec06SDavid du Colombier int rfd; /* replacement fd */
6781bcec06SDavid du Colombier int input;
6881bcec06SDavid du Colombier int open;
6981bcec06SDavid du Colombier };
7081bcec06SDavid du Colombier
7181bcec06SDavid du Colombier struct Rname {
7281bcec06SDavid du Colombier Rinst *dlistp;
7381bcec06SDavid du Colombier int rnameout;
7481bcec06SDavid du Colombier char rnamecalled;
7581bcec06SDavid du Colombier char rnamedefined;
7681bcec06SDavid du Colombier char *namer;
7781bcec06SDavid du Colombier Rname *next; /* next in hash chain */
7881bcec06SDavid du Colombier };
7981bcec06SDavid du Colombier
8081bcec06SDavid du Colombier struct Rnamehash {
8181bcec06SDavid du Colombier Rname *head;
8281bcec06SDavid du Colombier };
8381bcec06SDavid du Colombier
8481bcec06SDavid du Colombier /* list of calling instances of those names */
8581bcec06SDavid du Colombier struct Rinst {
8681bcec06SDavid du Colombier Rname *namep;
8781bcec06SDavid du Colombier Rinst *calls;
8881bcec06SDavid du Colombier Rinst *calledby;
8981bcec06SDavid du Colombier };
9081bcec06SDavid du Colombier
9181bcec06SDavid du Colombier struct Root {
9281bcec06SDavid du Colombier char *func;
9381bcec06SDavid du Colombier Root *next;
9481bcec06SDavid du Colombier };
9581bcec06SDavid du Colombier
9681bcec06SDavid du Colombier char *aseen[Maxseen]; /* names being gathered within a function */
97*0b04b1f8SDavid du Colombier Rnamehash nameshash[Hashsize]; /* names being tracked */
9881bcec06SDavid du Colombier Rname *activelist[Maxdepth]; /* names being output */
9981bcec06SDavid du Colombier String *cppopt;
10081bcec06SDavid du Colombier Root *roots;
10181bcec06SDavid du Colombier
10281bcec06SDavid du Colombier static struct stats {
10381bcec06SDavid du Colombier long highestseen; /* aseen high water mark */
10481bcec06SDavid du Colombier long highestname; /* namelist high water mark */
10581bcec06SDavid du Colombier long highestact; /* activelist high water mark */
10681bcec06SDavid du Colombier long highgetfree; /* getfrees high water mark */
10781bcec06SDavid du Colombier } stats;
10881bcec06SDavid du Colombier
10981bcec06SDavid du Colombier static long getfrees = 0;
11081bcec06SDavid du Colombier
111c3617180SDavid du Colombier int bracket = 0; /* curly brace count in input */
112c3617180SDavid du Colombier int linect = 0; /* line number in output */
11381bcec06SDavid du Colombier int activep = 0; /* current function being output */
11481bcec06SDavid du Colombier
115c3617180SDavid du Colombier char *infile;
116c3617180SDavid du Colombier int lineno = 1; /* line number of input */
117500d234bSDavid du Colombier int prevc = '\n', thisc = '\n';
118c3617180SDavid du Colombier
11981bcec06SDavid du Colombier /* options */
12081bcec06SDavid du Colombier int terse = 1; /* track functions only once */
12181bcec06SDavid du Colombier int ntabs = (Maxwidth - 20) / Tabwidth; /* how wide to go */
12281bcec06SDavid du Colombier
12381bcec06SDavid du Colombier char *dashes; /* separators for deep nestings */
12481bcec06SDavid du Colombier
12581bcec06SDavid du Colombier /*
12681bcec06SDavid du Colombier * These are C tokens after which a parenthesis is valid which would
12781bcec06SDavid du Colombier * otherwise be tagged as function names. The reserved words which are not
12881bcec06SDavid du Colombier * listed are break, const, continue, default, goto and volatile.
12981bcec06SDavid du Colombier */
13081bcec06SDavid du Colombier char *sysword[] = {
13181bcec06SDavid du Colombier "auto", "case", "char", "do", "double", "else", "enum",
13281bcec06SDavid du Colombier "extern", "float", "for", "if", "int", "long", "register",
13381bcec06SDavid du Colombier "return", "short", "sizeof", "static", "struct", "switch",
13481bcec06SDavid du Colombier "typedef", "union", "unsigned", "void", "while",
13581bcec06SDavid du Colombier };
13681bcec06SDavid du Colombier
13781bcec06SDavid du Colombier /*
13881bcec06SDavid du Colombier * warning - print best error message possible
13981bcec06SDavid du Colombier */
14081bcec06SDavid du Colombier void
warning(char * s1,char * s2)14181bcec06SDavid du Colombier warning(char *s1, char *s2)
14281bcec06SDavid du Colombier {
14381bcec06SDavid du Colombier fprint(2, "%s: ", argv0);
14481bcec06SDavid du Colombier fprint(2, s1, s2);
14581bcec06SDavid du Colombier fprint(2, "\n");
14681bcec06SDavid du Colombier }
14781bcec06SDavid du Colombier
14881bcec06SDavid du Colombier /*
14981bcec06SDavid du Colombier * safe malloc() code. Does the checking for nil returns from malloc()
15081bcec06SDavid du Colombier */
15181bcec06SDavid du Colombier void *
emalloc(int size)15281bcec06SDavid du Colombier emalloc(int size)
15381bcec06SDavid du Colombier {
15481bcec06SDavid du Colombier void *f = mallocz(size, 1);
15581bcec06SDavid du Colombier
15681bcec06SDavid du Colombier if (f == nil)
15781bcec06SDavid du Colombier sysfatal("cannot allocate memory");
15881bcec06SDavid du Colombier return f;
15981bcec06SDavid du Colombier }
16081bcec06SDavid du Colombier
16181bcec06SDavid du Colombier unsigned
hash(char * s)16281bcec06SDavid du Colombier hash(char *s)
16381bcec06SDavid du Colombier {
16481bcec06SDavid du Colombier unsigned h;
16581bcec06SDavid du Colombier unsigned char *cp;
16681bcec06SDavid du Colombier
16781bcec06SDavid du Colombier h = 0;
16881bcec06SDavid du Colombier for(cp = (unsigned char *)s; *cp; h += *cp++)
16981bcec06SDavid du Colombier h *= 1119;
17081bcec06SDavid du Colombier return h;
17181bcec06SDavid du Colombier }
17281bcec06SDavid du Colombier
173500d234bSDavid du Colombier int
nextc(Biobuf * in)174500d234bSDavid du Colombier nextc(Biobuf *in)
175500d234bSDavid du Colombier {
176500d234bSDavid du Colombier prevc = thisc;
177500d234bSDavid du Colombier thisc = Bgetrune(in);
178500d234bSDavid du Colombier return thisc;
179500d234bSDavid du Colombier }
180500d234bSDavid du Colombier
181500d234bSDavid du Colombier int
ungetc(Biobuf * in)182500d234bSDavid du Colombier ungetc(Biobuf *in)
183500d234bSDavid du Colombier {
184500d234bSDavid du Colombier prevc = thisc;
185500d234bSDavid du Colombier return Bungetrune(in);
186500d234bSDavid du Colombier }
187500d234bSDavid du Colombier
188500d234bSDavid du Colombier int
newatom(Biobuf * in,char * atom)189500d234bSDavid du Colombier newatom(Biobuf *in, char *atom)
190500d234bSDavid du Colombier {
191500d234bSDavid du Colombier atom[0] = '\0';
192500d234bSDavid du Colombier return nextc(in);
193500d234bSDavid du Colombier }
194500d234bSDavid du Colombier
19581bcec06SDavid du Colombier /*
19681bcec06SDavid du Colombier * lookup (name) accepts a pointer to a name and sees if the name is on the
19781bcec06SDavid du Colombier * namelist. If so, it returns a pointer to the nameblock. Otherwise it
19881bcec06SDavid du Colombier * returns nil.
19981bcec06SDavid du Colombier */
20081bcec06SDavid du Colombier Rname *
lookfor(char * name)20181bcec06SDavid du Colombier lookfor(char *name)
20281bcec06SDavid du Colombier {
20381bcec06SDavid du Colombier int i;
20481bcec06SDavid du Colombier unsigned buck;
20581bcec06SDavid du Colombier Rname *np;
20681bcec06SDavid du Colombier Rnamehash *hp;
20781bcec06SDavid du Colombier
20881bcec06SDavid du Colombier buck = hash(name) % Hashsize;
20981bcec06SDavid du Colombier hp = &nameshash[buck];
21081bcec06SDavid du Colombier i = 0;
21181bcec06SDavid du Colombier for (np = hp->head; np != nil; np = np->next, i++)
21281bcec06SDavid du Colombier if (STREQ(name, np->namer))
21381bcec06SDavid du Colombier return np;
21481bcec06SDavid du Colombier
21581bcec06SDavid du Colombier if (i > stats.highestname)
21681bcec06SDavid du Colombier stats.highestname = i;
21781bcec06SDavid du Colombier return nil;
21881bcec06SDavid du Colombier }
21981bcec06SDavid du Colombier
22081bcec06SDavid du Colombier /*
22181bcec06SDavid du Colombier * place() returns a pointer to the name on the namelist. If the name was
22281bcec06SDavid du Colombier * not in the namelist, place adds it.
22381bcec06SDavid du Colombier */
22481bcec06SDavid du Colombier Rname *
place(char name[])22581bcec06SDavid du Colombier place(char name[])
22681bcec06SDavid du Colombier {
22781bcec06SDavid du Colombier unsigned buck;
22881bcec06SDavid du Colombier Rname *np;
22981bcec06SDavid du Colombier Rnamehash *hp;
23081bcec06SDavid du Colombier
23181bcec06SDavid du Colombier np = lookfor(name);
23281bcec06SDavid du Colombier if (np != nil)
23381bcec06SDavid du Colombier return np;
23481bcec06SDavid du Colombier
23581bcec06SDavid du Colombier buck = hash(name) % Hashsize;
23681bcec06SDavid du Colombier hp = &nameshash[buck];
23781bcec06SDavid du Colombier np = emalloc(sizeof *np);
23881bcec06SDavid du Colombier np->namer = strdup(name);
23981bcec06SDavid du Colombier np->next = hp->head;
24081bcec06SDavid du Colombier hp->head = np;
24181bcec06SDavid du Colombier return np;
24281bcec06SDavid du Colombier }
24381bcec06SDavid du Colombier
24481bcec06SDavid du Colombier /*
24581bcec06SDavid du Colombier * getfree returns a pointer to the next free instance block on the list
24681bcec06SDavid du Colombier */
24781bcec06SDavid du Colombier Rinst *
getfree(void)24881bcec06SDavid du Colombier getfree(void)
24981bcec06SDavid du Colombier {
25081bcec06SDavid du Colombier Rinst *ret, *new;
25181bcec06SDavid du Colombier static Rinst *prev;
25281bcec06SDavid du Colombier
25381bcec06SDavid du Colombier ++getfrees;
25481bcec06SDavid du Colombier if (getfrees > stats.highgetfree)
25581bcec06SDavid du Colombier stats.highgetfree = getfrees;
25681bcec06SDavid du Colombier
25781bcec06SDavid du Colombier if (prev == nil)
25881bcec06SDavid du Colombier prev = emalloc(sizeof *prev);
25981bcec06SDavid du Colombier new = emalloc(sizeof *new);
26081bcec06SDavid du Colombier
26181bcec06SDavid du Colombier prev->calls = new; /* also serves as next pointer */
26281bcec06SDavid du Colombier new->calledby = prev;
26381bcec06SDavid du Colombier
26481bcec06SDavid du Colombier ret = prev;
26581bcec06SDavid du Colombier prev = new;
26681bcec06SDavid du Colombier return ret;
26781bcec06SDavid du Colombier }
26881bcec06SDavid du Colombier
26981bcec06SDavid du Colombier /*
27081bcec06SDavid du Colombier * install(np, rp) puts a new instance of a function into the linked list.
27181bcec06SDavid du Colombier * It puts a pointer (np) to its own name (returned by place) into its
27281bcec06SDavid du Colombier * namepointer, a pointer to the calling routine (rp) into its called-by
27381bcec06SDavid du Colombier * pointer, and zero into the calls pointer. It then puts a pointer to
27481bcec06SDavid du Colombier * itself into the last function in the chain.
27581bcec06SDavid du Colombier */
27681bcec06SDavid du Colombier Rinst *
install(Rname * np,Rinst * rp)27781bcec06SDavid du Colombier install(Rname *np, Rinst *rp)
27881bcec06SDavid du Colombier {
27981bcec06SDavid du Colombier Rinst *newp;
28081bcec06SDavid du Colombier
28181bcec06SDavid du Colombier if (np == nil)
28281bcec06SDavid du Colombier return RINSTERR;
28381bcec06SDavid du Colombier if ((newp = getfree()) == nil)
28481bcec06SDavid du Colombier return nil;
28581bcec06SDavid du Colombier newp->namep = np;
28681bcec06SDavid du Colombier newp->calls = 0;
28781bcec06SDavid du Colombier if (rp) {
28881bcec06SDavid du Colombier while (rp->calls)
28981bcec06SDavid du Colombier rp = rp->calls;
29081bcec06SDavid du Colombier newp->calledby = rp->calledby;
29181bcec06SDavid du Colombier rp->calls = newp;
29281bcec06SDavid du Colombier } else {
29381bcec06SDavid du Colombier newp->calledby = (Rinst *)np;
29481bcec06SDavid du Colombier np->dlistp = newp;
29581bcec06SDavid du Colombier }
29681bcec06SDavid du Colombier return newp;
29781bcec06SDavid du Colombier }
29881bcec06SDavid du Colombier
29981bcec06SDavid du Colombier /*
30081bcec06SDavid du Colombier * When scanning the text, each function instance is inserted into a
30181bcec06SDavid du Colombier * linear list of names, using the Rname structure, when it is first
30281bcec06SDavid du Colombier * encountered. It is also inserted into the linked list using the Rinst
30381bcec06SDavid du Colombier * structure. The entry into the name list has a pointer to the defining
30481bcec06SDavid du Colombier * instance in the linked list, and each entry in the linked list has a
30581bcec06SDavid du Colombier * pointer back to the relevant name. Newproc makes an entry in the
30681bcec06SDavid du Colombier * defining list, which is distinguished from the called list only
30781bcec06SDavid du Colombier * because it has no calledby link (value=0). Add2proc enters into the
30881bcec06SDavid du Colombier * called list, by inserting a link to the new instance in the calls
30981bcec06SDavid du Colombier * pointer of the last entry (may be a defining instance, or a function
31081bcec06SDavid du Colombier * called by that defining instance), and points back to the defining
31181bcec06SDavid du Colombier * instance of the caller in its called-by pointer.
31281bcec06SDavid du Colombier */
31381bcec06SDavid du Colombier Rinst *
newproc(char * name)31481bcec06SDavid du Colombier newproc(char *name)
31581bcec06SDavid du Colombier {
31681bcec06SDavid du Colombier int i;
31781bcec06SDavid du Colombier Rname *rp;
31881bcec06SDavid du Colombier
31981bcec06SDavid du Colombier for (i = 0; i < Maxseen; i++)
32081bcec06SDavid du Colombier if (aseen[i] != nil) {
32181bcec06SDavid du Colombier free(aseen[i]);
32281bcec06SDavid du Colombier aseen[i] = nil;
32381bcec06SDavid du Colombier }
32481bcec06SDavid du Colombier rp = place(name);
32581bcec06SDavid du Colombier if (rp == nil)
32681bcec06SDavid du Colombier return RINSTERR;
327*0b04b1f8SDavid du Colombier /* declaration in a header file is enough to cause this. */
32881bcec06SDavid du Colombier if (0 && rp->rnamedefined)
329*0b04b1f8SDavid du Colombier warning("function `%s' redeclared", name);
33081bcec06SDavid du Colombier rp->rnamedefined = 1;
33181bcec06SDavid du Colombier return install(rp, nil);
33281bcec06SDavid du Colombier }
33381bcec06SDavid du Colombier
33481bcec06SDavid du Colombier /*
33581bcec06SDavid du Colombier * add the function name to the calling stack of the current function.
33681bcec06SDavid du Colombier */
33781bcec06SDavid du Colombier int
add2call(char name[],Rinst * curp)33881bcec06SDavid du Colombier add2call(char name[], Rinst *curp)
33981bcec06SDavid du Colombier {
34081bcec06SDavid du Colombier Rname *p = place(name);
34181bcec06SDavid du Colombier Rinst *ip = install(p, curp);
34281bcec06SDavid du Colombier
34381bcec06SDavid du Colombier if (p != nil && curp != nil && curp->namep != nil &&
34481bcec06SDavid du Colombier !STREQ(p->namer, curp->namep->namer))
34581bcec06SDavid du Colombier p->rnamecalled = 1;
34681bcec06SDavid du Colombier return ip != nil;
34781bcec06SDavid du Colombier }
34881bcec06SDavid du Colombier
34981bcec06SDavid du Colombier /*
35081bcec06SDavid du Colombier * backup removes an item from the active stack
35181bcec06SDavid du Colombier */
35281bcec06SDavid du Colombier void
backup(void)35381bcec06SDavid du Colombier backup(void)
35481bcec06SDavid du Colombier {
35581bcec06SDavid du Colombier if (activep > 0)
35681bcec06SDavid du Colombier activelist[--activep] = nil;
35781bcec06SDavid du Colombier }
35881bcec06SDavid du Colombier
35981bcec06SDavid du Colombier /*
36081bcec06SDavid du Colombier * makeactive simply puts a pointer to the nameblock into a stack with
36181bcec06SDavid du Colombier * maximum depth Maxdepth. the error return only happens for stack
36281bcec06SDavid du Colombier * overflow.
36381bcec06SDavid du Colombier */
36481bcec06SDavid du Colombier int
makeactive(Rname * func)36581bcec06SDavid du Colombier makeactive(Rname *func)
36681bcec06SDavid du Colombier {
36781bcec06SDavid du Colombier if (activep < Maxdepth) {
36881bcec06SDavid du Colombier if (activep > stats.highestact)
36981bcec06SDavid du Colombier stats.highestact = activep;
37081bcec06SDavid du Colombier activelist[activep++] = func;
37181bcec06SDavid du Colombier return 1;
37281bcec06SDavid du Colombier }
37381bcec06SDavid du Colombier return 0;
37481bcec06SDavid du Colombier }
37581bcec06SDavid du Colombier
37681bcec06SDavid du Colombier /*
37781bcec06SDavid du Colombier * active checks whether the pointer which is its argument has already
37881bcec06SDavid du Colombier * occurred on the active list, and returns 1 if so.
37981bcec06SDavid du Colombier */
38081bcec06SDavid du Colombier int
active(Rname * func)38181bcec06SDavid du Colombier active(Rname *func)
38281bcec06SDavid du Colombier {
38381bcec06SDavid du Colombier int i;
38481bcec06SDavid du Colombier
38581bcec06SDavid du Colombier for (i = 0; i < activep - 1; i++)
38681bcec06SDavid du Colombier if (func == activelist[i])
38781bcec06SDavid du Colombier return 1;
38881bcec06SDavid du Colombier return 0;
38981bcec06SDavid du Colombier }
39081bcec06SDavid du Colombier
39181bcec06SDavid du Colombier /*
39281bcec06SDavid du Colombier * output is a recursive routine to print one tab for each level of
39381bcec06SDavid du Colombier * recursion, then the name of the function called, followed by the next
39481bcec06SDavid du Colombier * function called by the same higher level routine. In doing this, it
39581bcec06SDavid du Colombier * calls itself to output the name of the first function called by the
39681bcec06SDavid du Colombier * function whose name it is printing. It maintains an active list of
39781bcec06SDavid du Colombier * functions currently being printed by the different levels of
39881bcec06SDavid du Colombier * recursion, and if it finds itself asked to print one which is already
39981bcec06SDavid du Colombier * active, it terminates, marking that call with a '*'.
40081bcec06SDavid du Colombier */
40181bcec06SDavid du Colombier void
output(Rname * func,int tabc)40281bcec06SDavid du Colombier output(Rname *func, int tabc)
40381bcec06SDavid du Colombier {
40481bcec06SDavid du Colombier int i, tabd, tabstar, tflag;
40581bcec06SDavid du Colombier Rinst *nextp;
40681bcec06SDavid du Colombier
40781bcec06SDavid du Colombier ++linect;
40881bcec06SDavid du Colombier print("\n%d", linect);
40981bcec06SDavid du Colombier if (!makeactive(func)) {
41081bcec06SDavid du Colombier print(" * nesting is too deep");
41181bcec06SDavid du Colombier return;
41281bcec06SDavid du Colombier }
41381bcec06SDavid du Colombier tabstar = 0;
41481bcec06SDavid du Colombier tabd = tabc;
41581bcec06SDavid du Colombier for (; tabd > ntabs; tabstar++)
41681bcec06SDavid du Colombier tabd -= ntabs;
41781bcec06SDavid du Colombier if (tabstar > 0) {
41881bcec06SDavid du Colombier print(" ");
41981bcec06SDavid du Colombier for (i = 0; i < tabstar; i++)
42081bcec06SDavid du Colombier print("<");
42181bcec06SDavid du Colombier }
42281bcec06SDavid du Colombier if (tabd == 0)
42381bcec06SDavid du Colombier print(" ");
42481bcec06SDavid du Colombier else
42581bcec06SDavid du Colombier for (i = 0; i < tabd; i++)
42681bcec06SDavid du Colombier print("\t");
42781bcec06SDavid du Colombier if (active(func))
42881bcec06SDavid du Colombier print("<<< %s", func->namer); /* recursive call */
42981bcec06SDavid du Colombier else if (func->dlistp == nil)
43081bcec06SDavid du Colombier print("%s [external]", func->namer);
43181bcec06SDavid du Colombier else {
43281bcec06SDavid du Colombier print("%s", func->namer);
43381bcec06SDavid du Colombier nextp = func->dlistp->calls;
43481bcec06SDavid du Colombier if (!terse || !func->rnameout) {
43581bcec06SDavid du Colombier ++tabc;
43681bcec06SDavid du Colombier if (!func->rnameout)
43781bcec06SDavid du Colombier func->rnameout = linect;
43881bcec06SDavid du Colombier if (tabc > ntabs && tabc%ntabs == 1 && nextp) {
43981bcec06SDavid du Colombier print("\n%s", dashes);
44081bcec06SDavid du Colombier tflag = 1;
44181bcec06SDavid du Colombier } else
44281bcec06SDavid du Colombier tflag = 0;
44381bcec06SDavid du Colombier for (; nextp; nextp = nextp->calls)
44481bcec06SDavid du Colombier output(nextp->namep, tabc);
44581bcec06SDavid du Colombier if (tflag) {
44681bcec06SDavid du Colombier print("\n%s", dashes);
44781bcec06SDavid du Colombier tflag = 0;
44881bcec06SDavid du Colombier USED(tflag);
44981bcec06SDavid du Colombier }
45081bcec06SDavid du Colombier } else if (nextp != nil) /* not a leaf */
45181bcec06SDavid du Colombier print(" ... [see line %d]", func->rnameout);
45281bcec06SDavid du Colombier }
45381bcec06SDavid du Colombier backup();
45481bcec06SDavid du Colombier }
45581bcec06SDavid du Colombier
45681bcec06SDavid du Colombier /*
45781bcec06SDavid du Colombier * Dumptree() lists out the calling stacks. All names will be listed out
45881bcec06SDavid du Colombier * unless some function names are specified in -f options.
45981bcec06SDavid du Colombier */
46081bcec06SDavid du Colombier void
dumptree(void)46181bcec06SDavid du Colombier dumptree(void)
46281bcec06SDavid du Colombier {
46381bcec06SDavid du Colombier unsigned buck;
46481bcec06SDavid du Colombier Root *rp;
46581bcec06SDavid du Colombier Rname *np;
46681bcec06SDavid du Colombier
46781bcec06SDavid du Colombier if (roots != nil)
46881bcec06SDavid du Colombier for (rp = roots; rp != nil; rp = rp->next)
46981bcec06SDavid du Colombier if ((np = lookfor(rp->func)) != nil) {
47081bcec06SDavid du Colombier output(np, 0);
47181bcec06SDavid du Colombier print("\n\n");
47281bcec06SDavid du Colombier } else
47381bcec06SDavid du Colombier fprint(2, "%s: function '%s' not found\n",
47481bcec06SDavid du Colombier argv0, rp->func);
47581bcec06SDavid du Colombier else
47681bcec06SDavid du Colombier /* print everything */
47781bcec06SDavid du Colombier for (buck = 0; buck < Hashsize; buck++)
47881bcec06SDavid du Colombier for (np = nameshash[buck].head; np != nil; np = np->next)
47981bcec06SDavid du Colombier if (!np->rnamecalled) {
48081bcec06SDavid du Colombier output(np, 0);
48181bcec06SDavid du Colombier print("\n\n");
48281bcec06SDavid du Colombier }
48381bcec06SDavid du Colombier }
48481bcec06SDavid du Colombier
48581bcec06SDavid du Colombier /*
48681bcec06SDavid du Colombier * Skipcomments() skips past any blanks and comments in the input stream.
48781bcec06SDavid du Colombier */
48881bcec06SDavid du Colombier int
skipcomments(Biobuf * in,int firstc)48981bcec06SDavid du Colombier skipcomments(Biobuf *in, int firstc)
49081bcec06SDavid du Colombier {
49181bcec06SDavid du Colombier int c;
49281bcec06SDavid du Colombier
493500d234bSDavid du Colombier for (c = firstc; isascii(c) && isspace(c) || c == '/'; c = nextc(in)) {
494c3617180SDavid du Colombier if (c == '\n')
495c3617180SDavid du Colombier lineno++;
49681bcec06SDavid du Colombier if (c != '/')
49781bcec06SDavid du Colombier continue;
498500d234bSDavid du Colombier c = nextc(in); /* read ahead */
49981bcec06SDavid du Colombier if (c == Beof)
50081bcec06SDavid du Colombier break;
50181bcec06SDavid du Colombier if (c != '*' && c != '/') { /* not comment start? */
502500d234bSDavid du Colombier ungetc(in); /* push back readahead */
50381bcec06SDavid du Colombier return '/';
50481bcec06SDavid du Colombier }
50581bcec06SDavid du Colombier if (c == '/') { /* c++ style */
506500d234bSDavid du Colombier while ((c = nextc(in)) != '\n' && c != Beof)
50781bcec06SDavid du Colombier ;
508c3617180SDavid du Colombier if (c == '\n')
509c3617180SDavid du Colombier lineno++;
51081bcec06SDavid du Colombier continue;
51181bcec06SDavid du Colombier }
51281bcec06SDavid du Colombier for (;;) {
51381bcec06SDavid du Colombier /* skip to possible closing delimiter */
514500d234bSDavid du Colombier while ((c = nextc(in)) != '*' && c != Beof)
515c3617180SDavid du Colombier if (c == '\n')
516c3617180SDavid du Colombier lineno++;
51781bcec06SDavid du Colombier if (c == Beof)
51881bcec06SDavid du Colombier break;
51981bcec06SDavid du Colombier /* else c == '*' */
520500d234bSDavid du Colombier c = nextc(in); /* read ahead */
52181bcec06SDavid du Colombier if (c == Beof || c == '/') /* comment end? */
52281bcec06SDavid du Colombier break;
523500d234bSDavid du Colombier ungetc(in); /* push back readahead */
52481bcec06SDavid du Colombier }
52581bcec06SDavid du Colombier }
52681bcec06SDavid du Colombier return c;
52781bcec06SDavid du Colombier }
52881bcec06SDavid du Colombier
52981bcec06SDavid du Colombier /*
53081bcec06SDavid du Colombier * isfndefn differentiates between an external declaration and a real
53181bcec06SDavid du Colombier * function definition. For instance, between:
53281bcec06SDavid du Colombier *
53381bcec06SDavid du Colombier * extern char *getenv(char *), *strcmp(char *, char *);
53481bcec06SDavid du Colombier * and
53581bcec06SDavid du Colombier * char *getenv(char *name)
53681bcec06SDavid du Colombier * {}
53781bcec06SDavid du Colombier *
53881bcec06SDavid du Colombier * It does so by making the observation that nothing (except blanks and
53981bcec06SDavid du Colombier * comments) can be between the right parenthesis and the semi-colon or
54081bcec06SDavid du Colombier * comma following the extern declaration.
54181bcec06SDavid du Colombier */
54281bcec06SDavid du Colombier int
isfndefn(Biobuf * in)54381bcec06SDavid du Colombier isfndefn(Biobuf *in)
54481bcec06SDavid du Colombier {
54581bcec06SDavid du Colombier int c;
54681bcec06SDavid du Colombier
547500d234bSDavid du Colombier c = skipcomments(in, nextc(in));
54881bcec06SDavid du Colombier while (c != ')' && c != Beof) /* consume arg. decl.s */
549500d234bSDavid du Colombier c = nextc(in);
55081bcec06SDavid du Colombier if (c == Beof)
55181bcec06SDavid du Colombier return 1; /* definition at Beof */
552500d234bSDavid du Colombier c = skipcomments(in, nextc(in)); /* skip blanks between ) and ; */
55381bcec06SDavid du Colombier
55481bcec06SDavid du Colombier if (c == ';' || c == ',')
55581bcec06SDavid du Colombier return 0; /* an extern declaration */
55681bcec06SDavid du Colombier if (c != Beof)
557500d234bSDavid du Colombier ungetc(in);
55881bcec06SDavid du Colombier return 1; /* a definition */
55981bcec06SDavid du Colombier }
56081bcec06SDavid du Colombier
56181bcec06SDavid du Colombier /*
56281bcec06SDavid du Colombier * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
56381bcec06SDavid du Colombier * is WAY faster than the generic bsearch().
56481bcec06SDavid du Colombier */
56581bcec06SDavid du Colombier int
strbsearch(char * key,char ** base,unsigned nel)56681bcec06SDavid du Colombier strbsearch(char *key, char **base, unsigned nel)
56781bcec06SDavid du Colombier {
56881bcec06SDavid du Colombier int cmp;
56981bcec06SDavid du Colombier char **last = base + nel - 1, **pos;
57081bcec06SDavid du Colombier
57181bcec06SDavid du Colombier while (last >= base) {
57281bcec06SDavid du Colombier pos = base + ((last - base) >> 1);
57381bcec06SDavid du Colombier cmp = key[0] - (*pos)[0];
57481bcec06SDavid du Colombier if (cmp == 0) {
57581bcec06SDavid du Colombier /* there are no empty strings in the table */
57681bcec06SDavid du Colombier cmp = strcmp(key, *pos);
57781bcec06SDavid du Colombier if (cmp == 0)
57881bcec06SDavid du Colombier return 1;
57981bcec06SDavid du Colombier }
58081bcec06SDavid du Colombier if (cmp < 0)
58181bcec06SDavid du Colombier last = pos - 1;
58281bcec06SDavid du Colombier else
58381bcec06SDavid du Colombier base = pos + 1;
58481bcec06SDavid du Colombier }
58581bcec06SDavid du Colombier return 0;
58681bcec06SDavid du Colombier }
58781bcec06SDavid du Colombier
58881bcec06SDavid du Colombier /*
58981bcec06SDavid du Colombier * see if we have seen this function within this process
59081bcec06SDavid du Colombier */
59181bcec06SDavid du Colombier int
seen(char * atom)59281bcec06SDavid du Colombier seen(char *atom)
59381bcec06SDavid du Colombier {
59481bcec06SDavid du Colombier int i;
59581bcec06SDavid du Colombier
59681bcec06SDavid du Colombier for (i = 0; aseen[i] != nil && i < Maxseen-1; i++)
59781bcec06SDavid du Colombier if (STREQ(atom, aseen[i]))
59881bcec06SDavid du Colombier return Found;
59981bcec06SDavid du Colombier if (i >= Maxseen-1)
60081bcec06SDavid du Colombier return Nomore;
60181bcec06SDavid du Colombier aseen[i] = strdup(atom);
60281bcec06SDavid du Colombier if (i > stats.highestseen)
60381bcec06SDavid du Colombier stats.highestseen = i;
60481bcec06SDavid du Colombier return Added;
60581bcec06SDavid du Colombier }
60681bcec06SDavid du Colombier
60781bcec06SDavid du Colombier /*
60881bcec06SDavid du Colombier * getfunc returns the name of a function in atom and Defn for a definition,
60981bcec06SDavid du Colombier * Call for an internal call, or Beof.
61081bcec06SDavid du Colombier */
61181bcec06SDavid du Colombier int
getfunc(Biobuf * in,char * atom)61281bcec06SDavid du Colombier getfunc(Biobuf *in, char *atom)
61381bcec06SDavid du Colombier {
614500d234bSDavid du Colombier int c, nf, last, ss, quote;
615500d234bSDavid du Colombier char *ln, *nm, *ap, *ep = &atom[Maxid-1-UTFmax];
616500d234bSDavid du Colombier char *flds[4];
61781bcec06SDavid du Colombier Rune r;
61881bcec06SDavid du Colombier
619500d234bSDavid du Colombier c = nextc(in);
62081bcec06SDavid du Colombier while (c != Beof) {
62181bcec06SDavid du Colombier if (ISIDENT(c)) {
62281bcec06SDavid du Colombier ap = atom;
62381bcec06SDavid du Colombier do {
62481bcec06SDavid du Colombier if (isascii(c))
62581bcec06SDavid du Colombier *ap++ = c;
62681bcec06SDavid du Colombier else {
62781bcec06SDavid du Colombier r = c;
62881bcec06SDavid du Colombier ap += runetochar(ap, &r);
62981bcec06SDavid du Colombier }
630500d234bSDavid du Colombier c = nextc(in);
63181bcec06SDavid du Colombier } while(ap < ep && ISIDENT(c));
63281bcec06SDavid du Colombier *ap = '\0';
63381bcec06SDavid du Colombier if (ap >= ep) { /* uncommon case: id won't fit */
63481bcec06SDavid du Colombier /* consume remainder of too-long id */
63581bcec06SDavid du Colombier while (ISIDENT(c))
636500d234bSDavid du Colombier c = nextc(in);
63781bcec06SDavid du Colombier }
63881bcec06SDavid du Colombier }
63981bcec06SDavid du Colombier
64081bcec06SDavid du Colombier switch (c) {
64181bcec06SDavid du Colombier case Beof:
64281bcec06SDavid du Colombier return Beof;
643c3617180SDavid du Colombier case '\n':
644c3617180SDavid du Colombier lineno++;
645c3617180SDavid du Colombier /* fall through */
64681bcec06SDavid du Colombier case '\t': /* ignore white space */
64781bcec06SDavid du Colombier case ' ':
64881bcec06SDavid du Colombier case '\f':
64981bcec06SDavid du Colombier case '\r':
65081bcec06SDavid du Colombier case '/': /* potential comment? */
651500d234bSDavid du Colombier c = skipcomments(in, nextc(in));
65281bcec06SDavid du Colombier break;
65381bcec06SDavid du Colombier case Backslash: /* consume a newline or something */
65481bcec06SDavid du Colombier case ')': /* end of parameter list */
65581bcec06SDavid du Colombier default:
65681bcec06SDavid du Colombier c = newatom(in, atom);
65781bcec06SDavid du Colombier break;
658500d234bSDavid du Colombier case '#':
659500d234bSDavid du Colombier if (prevc != '\n') { /* cpp # or ## operator? */
660500d234bSDavid du Colombier c = nextc(in); /* read ahead */
661500d234bSDavid du Colombier break;
662500d234bSDavid du Colombier }
663500d234bSDavid du Colombier /* it's a cpp directive */
664500d234bSDavid du Colombier ln = Brdline(in, '\n');
665500d234bSDavid du Colombier if (ln == nil)
666500d234bSDavid du Colombier thisc = c = Beof;
667500d234bSDavid du Colombier else {
668500d234bSDavid du Colombier nf = tokenize(ln, flds, nelem(flds));
669500d234bSDavid du Colombier if (nf >= 3 && strcmp(flds[0], "line") == 0) {
670500d234bSDavid du Colombier lineno = atoi(flds[1]);
671500d234bSDavid du Colombier free(infile);
672500d234bSDavid du Colombier nm = flds[2];
673500d234bSDavid du Colombier if (nm[0] == '"')
674500d234bSDavid du Colombier nm++;
675500d234bSDavid du Colombier last = strlen(nm) - 1;
676500d234bSDavid du Colombier if (nm[last] == '"')
677500d234bSDavid du Colombier nm[last] = '\0';
678500d234bSDavid du Colombier infile = strdup(nm);
679500d234bSDavid du Colombier } else
680c3617180SDavid du Colombier lineno++;
681500d234bSDavid du Colombier c = nextc(in); /* read ahead */
682c3617180SDavid du Colombier }
68381bcec06SDavid du Colombier break;
68481bcec06SDavid du Colombier case Quote: /* character constant */
68581bcec06SDavid du Colombier case '\"': /* string constant */
68681bcec06SDavid du Colombier quote = c;
68781bcec06SDavid du Colombier atom[0] = '\0';
688500d234bSDavid du Colombier while ((c = nextc(in)) != quote && c != Beof)
68981bcec06SDavid du Colombier if (c == Backslash)
690500d234bSDavid du Colombier nextc(in);
69181bcec06SDavid du Colombier if (c == quote)
692500d234bSDavid du Colombier c = nextc(in);
69381bcec06SDavid du Colombier break;
69481bcec06SDavid du Colombier case '{': /* start of a block */
69581bcec06SDavid du Colombier bracket++;
69681bcec06SDavid du Colombier c = newatom(in, atom);
69781bcec06SDavid du Colombier break;
69881bcec06SDavid du Colombier case '}': /* end of a block */
699c3617180SDavid du Colombier if (bracket < 1)
700c3617180SDavid du Colombier fprint(2, "%s: %s:%d: too many closing braces; "
701c3617180SDavid du Colombier "previous open brace missing\n",
702c3617180SDavid du Colombier argv0, infile, lineno);
703c3617180SDavid du Colombier else
70481bcec06SDavid du Colombier --bracket;
70581bcec06SDavid du Colombier c = newatom(in, atom);
70681bcec06SDavid du Colombier break;
70781bcec06SDavid du Colombier case '(': /* parameter list for function? */
70881bcec06SDavid du Colombier if (atom[0] != '\0' && !checksys(atom)) {
70981bcec06SDavid du Colombier if (bracket == 0)
71081bcec06SDavid du Colombier if (isfndefn(in))
71181bcec06SDavid du Colombier return Defn;
71281bcec06SDavid du Colombier else {
713500d234bSDavid du Colombier c = nextc(in);
71481bcec06SDavid du Colombier break; /* ext. decl. */
71581bcec06SDavid du Colombier }
71681bcec06SDavid du Colombier ss = seen(atom);
71781bcec06SDavid du Colombier if (ss == Nomore)
718c3617180SDavid du Colombier fprint(2, "%s: %s:%d: more than %d "
719c3617180SDavid du Colombier "identifiers in a function\n",
720c3617180SDavid du Colombier argv0, infile, lineno, Maxseen);
72181bcec06SDavid du Colombier if (bracket > 0 && ss == Added)
72281bcec06SDavid du Colombier return Call;
72381bcec06SDavid du Colombier }
72481bcec06SDavid du Colombier c = newatom(in, atom);
72581bcec06SDavid du Colombier break;
72681bcec06SDavid du Colombier }
72781bcec06SDavid du Colombier }
72881bcec06SDavid du Colombier return Beof;
72981bcec06SDavid du Colombier }
73081bcec06SDavid du Colombier
73181bcec06SDavid du Colombier /*
73281bcec06SDavid du Colombier * addfuncs() scans the input file for function names and adds them to the
73381bcec06SDavid du Colombier * calling list.
73481bcec06SDavid du Colombier */
73581bcec06SDavid du Colombier void
addfuncs(int infd)73681bcec06SDavid du Colombier addfuncs(int infd)
73781bcec06SDavid du Colombier {
73881bcec06SDavid du Colombier int intern;
73981bcec06SDavid du Colombier uintptr ok = 1;
74081bcec06SDavid du Colombier char atom[Maxid];
74181bcec06SDavid du Colombier Biobuf inbb;
74281bcec06SDavid du Colombier Biobuf *in;
74381bcec06SDavid du Colombier Rinst *curproc = nil;
74481bcec06SDavid du Colombier
74581bcec06SDavid du Colombier in = &inbb;
74681bcec06SDavid du Colombier Binit(in, infd, OREAD);
74781bcec06SDavid du Colombier atom[0] = '\0';
74881bcec06SDavid du Colombier while ((intern = getfunc(in, atom)) != Beof && ok)
74981bcec06SDavid du Colombier if (intern == Call)
75081bcec06SDavid du Colombier ok = add2call(atom, curproc); /* function call */
75181bcec06SDavid du Colombier else
75281bcec06SDavid du Colombier ok = (uintptr)(curproc = newproc(atom)); /* fn def'n */
75381bcec06SDavid du Colombier Bterm(in);
75481bcec06SDavid du Colombier }
75581bcec06SDavid du Colombier
75681bcec06SDavid du Colombier /*
75781bcec06SDavid du Colombier * push a filter, cmd, onto fd. if input, it's an input descriptor.
75881bcec06SDavid du Colombier * returns a descriptor to replace fd, or -1 on error.
75981bcec06SDavid du Colombier */
76081bcec06SDavid du Colombier static int
push(int fd,char * cmd,int input,Pushstate * ps)76181bcec06SDavid du Colombier push(int fd, char *cmd, int input, Pushstate *ps)
76281bcec06SDavid du Colombier {
76381bcec06SDavid du Colombier int nfd, pifds[2];
76481bcec06SDavid du Colombier String *s;
76581bcec06SDavid du Colombier
76681bcec06SDavid du Colombier ps->open = 0;
76781bcec06SDavid du Colombier ps->fd = fd;
76881bcec06SDavid du Colombier ps->input = input;
76981bcec06SDavid du Colombier if (fd < 0 || pipe(pifds) < 0)
77081bcec06SDavid du Colombier return -1;
77181bcec06SDavid du Colombier ps->kid = fork();
77281bcec06SDavid du Colombier switch (ps->kid) {
77381bcec06SDavid du Colombier case -1:
77481bcec06SDavid du Colombier return -1;
77581bcec06SDavid du Colombier case 0:
77681bcec06SDavid du Colombier if (input)
77781bcec06SDavid du Colombier dup(pifds[Wr], Stdout);
77881bcec06SDavid du Colombier else
77981bcec06SDavid du Colombier dup(pifds[Rd], Stdin);
78081bcec06SDavid du Colombier close(pifds[input? Rd: Wr]);
78181bcec06SDavid du Colombier dup(fd, (input? Stdin: Stdout));
78281bcec06SDavid du Colombier
78381bcec06SDavid du Colombier s = s_new();
78481bcec06SDavid du Colombier if (cmd[0] != '/')
78581bcec06SDavid du Colombier s_append(s, "/bin/");
78681bcec06SDavid du Colombier s_append(s, cmd);
78781bcec06SDavid du Colombier execl(s_to_c(s), cmd, nil);
78881bcec06SDavid du Colombier execl("/bin/rc", "rc", "-c", cmd, nil);
78981bcec06SDavid du Colombier sysfatal("can't exec %s: %r", cmd);
79081bcec06SDavid du Colombier default:
79181bcec06SDavid du Colombier nfd = pifds[input? Rd: Wr];
79281bcec06SDavid du Colombier close(pifds[input? Wr: Rd]);
79381bcec06SDavid du Colombier break;
79481bcec06SDavid du Colombier }
79581bcec06SDavid du Colombier ps->rfd = nfd;
79681bcec06SDavid du Colombier ps->open = 1;
79781bcec06SDavid du Colombier return nfd;
79881bcec06SDavid du Colombier }
79981bcec06SDavid du Colombier
80081bcec06SDavid du Colombier static char *
pushclose(Pushstate * ps)80181bcec06SDavid du Colombier pushclose(Pushstate *ps)
80281bcec06SDavid du Colombier {
80381bcec06SDavid du Colombier Waitmsg *wm;
80481bcec06SDavid du Colombier
80581bcec06SDavid du Colombier if (ps->fd < 0 || ps->rfd < 0 || !ps->open)
80681bcec06SDavid du Colombier return "not open";
80781bcec06SDavid du Colombier close(ps->rfd);
80881bcec06SDavid du Colombier ps->rfd = -1;
80981bcec06SDavid du Colombier ps->open = 0;
81081bcec06SDavid du Colombier while ((wm = wait()) != nil && wm->pid != ps->kid)
81181bcec06SDavid du Colombier continue;
81281bcec06SDavid du Colombier return wm? wm->msg: nil;
81381bcec06SDavid du Colombier }
81481bcec06SDavid du Colombier
81581bcec06SDavid du Colombier /*
81681bcec06SDavid du Colombier * invoke the C preprocessor on the named files so that its
81781bcec06SDavid du Colombier * output can be read.
81881bcec06SDavid du Colombier *
81981bcec06SDavid du Colombier * must fork/exec cpp for each input file.
82081bcec06SDavid du Colombier * otherwise we get macro redefinitions and other problems.
821*0b04b1f8SDavid du Colombier * also plan 9's cpp can only process one input file per invocation.
82281bcec06SDavid du Colombier */
82381bcec06SDavid du Colombier void
scanfiles(int argc,char ** argv)82481bcec06SDavid du Colombier scanfiles(int argc, char **argv)
82581bcec06SDavid du Colombier {
82681bcec06SDavid du Colombier int i, infd;
82781bcec06SDavid du Colombier char *sts;
82881bcec06SDavid du Colombier Pushstate ps;
82981bcec06SDavid du Colombier String *cmd;
83081bcec06SDavid du Colombier
83181bcec06SDavid du Colombier cmd = s_new();
83281bcec06SDavid du Colombier for (i = 0; i < argc; i++) {
83381bcec06SDavid du Colombier s_reset(cmd);
83481bcec06SDavid du Colombier s_append(cmd, s_to_c(cppopt));
83581bcec06SDavid du Colombier s_append(cmd, " ");
83681bcec06SDavid du Colombier s_append(cmd, argv[i]);
83781bcec06SDavid du Colombier
83881bcec06SDavid du Colombier infd = push(Stdin, s_to_c(cmd), Rd, &ps);
83981bcec06SDavid du Colombier if (infd < 0) {
84081bcec06SDavid du Colombier warning("can't execute cmd `%s'", s_to_c(cmd));
84181bcec06SDavid du Colombier return;
84281bcec06SDavid du Colombier }
84381bcec06SDavid du Colombier
844500d234bSDavid du Colombier free(infile);
845500d234bSDavid du Colombier infile = strdup(argv[i]);
846c3617180SDavid du Colombier lineno = 1;
84781bcec06SDavid du Colombier addfuncs(infd);
84881bcec06SDavid du Colombier
84981bcec06SDavid du Colombier sts = pushclose(&ps);
85081bcec06SDavid du Colombier if (sts != nil && sts[0] != '\0') {
85181bcec06SDavid du Colombier warning("cmd `%s' failed", s_to_c(cmd));
85281bcec06SDavid du Colombier fprint(2, "exit status %s\n", sts);
85381bcec06SDavid du Colombier }
85481bcec06SDavid du Colombier }
85581bcec06SDavid du Colombier s_free(cmd);
85681bcec06SDavid du Colombier }
85781bcec06SDavid du Colombier
85881bcec06SDavid du Colombier static void
usage(void)85981bcec06SDavid du Colombier usage(void)
86081bcec06SDavid du Colombier {
86181bcec06SDavid du Colombier fprint(2, "usage: %s [-ptv] [-f func] [-w width] [-D define] [-U undef]"
86281bcec06SDavid du Colombier " [-I dir] [file...]\n", argv0);
86381bcec06SDavid du Colombier exits("usage");
86481bcec06SDavid du Colombier }
86581bcec06SDavid du Colombier
86681bcec06SDavid du Colombier void
main(int argc,char ** argv)86781bcec06SDavid du Colombier main(int argc, char **argv)
86881bcec06SDavid du Colombier {
86981bcec06SDavid du Colombier int i, width = Defwidth;
87081bcec06SDavid du Colombier char _dashes[1024];
87181bcec06SDavid du Colombier Root *rp;
87281bcec06SDavid du Colombier
87381bcec06SDavid du Colombier cppopt = s_copy(CPP);
87481bcec06SDavid du Colombier ARGBEGIN{
87581bcec06SDavid du Colombier case 'f': /* start from function arg. */
87681bcec06SDavid du Colombier rp = emalloc(sizeof *rp);
87781bcec06SDavid du Colombier rp->func = EARGF(usage());
87881bcec06SDavid du Colombier rp->next = roots;
87981bcec06SDavid du Colombier roots = rp;
88081bcec06SDavid du Colombier break;
88181bcec06SDavid du Colombier case 'p': /* ape includes */
88281bcec06SDavid du Colombier s_append(cppopt, " -I /sys/include/ape");
88381bcec06SDavid du Colombier s_append(cppopt, " -I /");
88481bcec06SDavid du Colombier s_append(cppopt, getenv("objtype"));
88581bcec06SDavid du Colombier s_append(cppopt, "/include/ape");
88681bcec06SDavid du Colombier break;
88781bcec06SDavid du Colombier case 't': /* terse (default) */
88881bcec06SDavid du Colombier terse = 1;
88981bcec06SDavid du Colombier break;
89081bcec06SDavid du Colombier case 'v':
89181bcec06SDavid du Colombier terse = 0;
89281bcec06SDavid du Colombier break;
89381bcec06SDavid du Colombier case 'w': /* output width */
89481bcec06SDavid du Colombier width = atoi(EARGF(usage()));
89581bcec06SDavid du Colombier if (width <= 0)
89681bcec06SDavid du Colombier width = Defwidth;
89781bcec06SDavid du Colombier break;
89881bcec06SDavid du Colombier case 'D':
89981bcec06SDavid du Colombier case 'I':
90081bcec06SDavid du Colombier case 'U':
90181bcec06SDavid du Colombier s_append(cppopt, " -");
90281bcec06SDavid du Colombier s_putc(cppopt, ARGC());
90381bcec06SDavid du Colombier s_append(cppopt, EARGF(usage()));
90481bcec06SDavid du Colombier break;
90581bcec06SDavid du Colombier default:
90681bcec06SDavid du Colombier usage();
90781bcec06SDavid du Colombier }ARGEND
90881bcec06SDavid du Colombier
90981bcec06SDavid du Colombier /* initialize the dashed separator list for deep nesting */
91081bcec06SDavid du Colombier ntabs = (width - 20) / Tabwidth;
91181bcec06SDavid du Colombier for (i = 0; i < width && i+1 < sizeof dashes; i += 2) {
91281bcec06SDavid du Colombier _dashes[i] = '-';
91381bcec06SDavid du Colombier _dashes[i+1] = ' ';
91481bcec06SDavid du Colombier }
91581bcec06SDavid du Colombier if (i < sizeof dashes)
91681bcec06SDavid du Colombier _dashes[i] = '\0';
91781bcec06SDavid du Colombier else
91881bcec06SDavid du Colombier _dashes[sizeof dashes - 1] = '\0';
91981bcec06SDavid du Colombier dashes = _dashes;
92081bcec06SDavid du Colombier
92181bcec06SDavid du Colombier scanfiles(argc, argv);
92281bcec06SDavid du Colombier dumptree();
92381bcec06SDavid du Colombier
92481bcec06SDavid du Colombier if (Printstats) {
92581bcec06SDavid du Colombier fprint(2, "%ld/%d aseen entries\n", stats.highestseen, Maxseen);
92681bcec06SDavid du Colombier fprint(2, "%ld longest namelist hash chain\n", stats.highestname);
92781bcec06SDavid du Colombier fprint(2, "%ld/%d activelist high water mark\n",
92881bcec06SDavid du Colombier stats.highestact, Maxdepth);
92981bcec06SDavid du Colombier fprint(2, "%ld dlist high water mark\n", stats.highgetfree);
93081bcec06SDavid du Colombier }
93181bcec06SDavid du Colombier exits(0);
93281bcec06SDavid du Colombier }
933