home *** CD-ROM | disk | FTP | other *** search
- /* CREF - C cross-reference utility
-
- Author: Jeff Taylor, The Toolsmith (c) copyright 1982, 1985.
- Environment: C; UNIX 4.2 BSD.
- Algorithms:
- Modified algorithm T from "The Art of Computer Programming," Vol. 1,
- p. 317, by D.E.Knuth used in tree_walk().
- History:
- 22 November 1982 - removed recursion from lookup().
- 16 December 1982 - remove recursion from tree_walk().
- 26 March 1985 - port to DECUS C.
- 27 March 1985 - line # list made a circular queue: insert(), list_file().
- reserved word search changed to binary search: keyword().
- 28 March 1985 - port to UNIX 4.2 BSD.
- */
- /* start of new comment block */
- /* MORE CODING HISTORY (and the beat goes on) */
- /* Coding History --------------------------------------------------------| */
- /* | Date | Who | What | */
- /* |==========|=====|=====================================================| */
- /* | 11/23/88 | KRG | Transcribed from Dr. Dobbs' TOOLBOOK OF C, with | */
- /* | | | minimum modifications as required for porting to | */
- /* | | | MicroSoft C 5.1 (5.0 okay, too) | */
- /* |----------|-----|-----------------------------------------------------| */
- /* | 11/25/88 | KRG | Added some formatting to output (list_file()). | */
- /* |----------|-----|-----------------------------------------------------| */
- /* | 11/26/88 | KRG | Completed slightly lacking keyword list (oops). | */
- /* |----------|-----|-----------------------------------------------------| */
- /* | / / | | | */
- /* |----------|-----|-----------------------------------------------------| */
- /* end of new comment block */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <malloc.h> /* 881123 KRG */
- #include <string.h> /* 881123 KRG */
- #include "style.h"
-
- #define lower(c) (isupper(c)? tolower(c) : (c))
- #define streq(a, b) (strcmp(a, b) == 0)
- #define WIDTH 80 /* width of output device */
-
- struct instance
- {
- struct instance *next;
- int line;
- };
-
- union ptr
- {
- struct node *files;
- struct instance *lines;
- };
-
- struct node
- {
- struct node *right, *left;
- union ptr p;
- char *name;
- };
-
- struct node *symbol_root = NULL;
- struct node *file_root= NULL;
- int line_count = 0;
-
- #define ID 'a' /* identifier */
- #define INTEGER '0' /* integer */
-
- /************************************
- * Symbol Table handling routines *
- ***********************************/
-
- /* lookup - install name at or below root */
- struct node **lookup (root, name)
- /*register*/ struct node **root;
- /*register*/ char *name;
- {
- register int cond;
-
- #ifdef RECURSIVE
- if (*root != NULL)
- {
- if ((cond = lexcmp(name, (*root)->name)) != 0)
- root = lookup((cond < 0)? &(*root)->left : &(*root)->right,
- name);
- }
- #else
- while (*root != NULL && (cond = lexcmp(name, (*root)->name)))
- root = (cond < 0)? &(*root)->left : &(*root)->right;
- #endif
-
- return(root);
- }
-
- /* add - insert entry for "name" in tree at "root" */
- struct node *add (name)
- char *name;
- {
- /* char *malloc(); */
- register struct node *r;
-
- r = (struct node *) malloc(sizeof(struct node));
- r->left = r->right = NULL;
- r->p.lines = NULL;
- r->name = name;
- return (r);
- }
-
- /* tree_walk - call 'ftn' for each node in inorder */
- void tree_walk (root, ftn)
- /*register*/ struct node *root;
- /*register*/ void (*ftn)();
- {
-
- #ifdef RECURSIVE
- if (root != NULL)
- {
- tree_walk(root->left, ftn);
- (*ftn)(root);
- tree_walk(root->right, ftn);
- }
- #else
- register struct node *stack, *tmp;
-
- stack = NULL; /* stack initially empty */
- for ( ; ; )
- {
- if (root != NULL)
- {
- tmp = root;
- root = root->left; /* move to left */
- tmp->left = stack;
- stack = tmp; /* push tmp */
- }
- else if (stack != NULL) /* stack not empty */
- {
- root = stack;
- stack = stack->left; /* pop */
- (*ftn)(root); /* visit node */
- root = root->right; /* move right */
- }
- else
- break; /* stack is empty */
- }
- #endif
- }
-
- /* insert - add 'line_no' to the circular list, 'origin' */
- struct instance *insert (origin, line_no)
- /*register*/ struct instance *origin;
- int line_no;
- {
- /* char *malloc(); */
- register struct instance *t;
-
- if (origin == NULL || origin->line != line_no)
- {
- t = (struct instance *)malloc(sizeof(struct instance));
- if (origin == NULL)
- origin = t;
- t->line = line_no;
- t->next = origin->next;
- origin->next = t;
- origin = t;
- }
- return (origin);
- }
-
- /* use - log an occurrence of "name" in "file" at "line" */
- void use (name, file, line)
- char *name, *file;
- int line;
- {
- char *newcpy();
- register struct node **ft, **nt;
-
- if (*(nt = lookup(&symbol_root, name)) == NULL)
- *nt = add(newcpy(name));
- if (*(nt = lookup(&((*nt)->p.files), file)) == NULL)
- {
- if (*(ft = lookup(&file_root, file)) == NULL)
- *ft = add(newcpy(file));
- *nt = add((*ft)->name);
- }
- (*nt)->p.lines = insert((*nt)->p.lines, line);
- }
-
- /* get_name -extract file name from line */
- void get_name (line, file)
- /*register*/ char *line;
- char *file;
- {
- void copy_until();
- register char *delim;
-
- while (*line == ' ' || *line == '\t')
- ++line;
- if (*line != '\n') /* if none, use "file" as is */
- {
- if (*line == '"')
- {
- delim = "\"\n";
- ++line;
- }
- else if (*line == '<')
- {
- delim = ">\n";
- ++line;
- }
- else
- delim = "\t\n";
- copy_until(file, line, delim);
- }
- }
-
- /* new_line - return pointer to the next line */
- char *new_line()
- {
- static char line[MAXLINE+1];
-
- ++line_count;
- return(fgets(line, MAXLINE, stdin));
- }
-
- /* white_space - tests for blanks, tabs and comments */
- /* NOTE: \n is NOT counted as 'white space' in this program; it is used as
- a token class. 881125 KRG */
-
- boolean white_space(s)
- /*register*/ char **s;
- {
-
- if (**s == ' ' || **s == '\t')
- return(TRUE);
- if (**s == '/' && *(*s+1) == '*') /* comment */
- {
- while (*++*s != '/')
- {
- while (*++*s != '*')
- {
- if (**s == EOS)
- {
- if ((*s = new_line()) != NULL)
- --*s; /* because of pre-increment of inner loop */
- else
- {
- fprintf(stderr, "unexpected EOF\n");
- return (FALSE);
- }
- }
- }
- }
- return (TRUE);
- }
- return(FALSE);
- }
-
- /* ishex - is 'c' a hexadecimal digit? */
- boolean ishex(c)
- /*register*/ char c;
- {
- return (isxdigit(c));
- }
-
- /* get_token - strip leading token from s */
- char get_token(s, t)
- /*register*/ char **s, *t;
- {
- char esc();
- register char class;
-
- while (white_space(s))
- ++*s;
- if (isalpha(**s) || **s == '_') /* identifier */
- {
- class = ID;
- do
- *t++ = *(*s)++;
- while (isdigit(**s) || isalpha(**s) || **s == '_');
- }
- else if (**s == '\"' || **s == '\'') /* string or literal */
- {
- class = **s;
- do
- {
- esc(s);
- ++*s;
- if (**s == EOS)
- {
- if ((*s = new_line()) == NULL)
- goto out; /* aaaargh! KRG */
- }
- }
- while (**s != class);
- ++*s;
- }
- else if (isdigit(**s))
- {
- do
- {
- class = *++*s;
- class = lower(class);
- }
- while (ishex(class) || class == 'x' || class == 'l' || class == '.');
- class = INTEGER;
- }
- else
- class = *(*s)++;
-
- out:
-
- *t = EOS;
- return(class);
- }
-
- static char *reserved[] =
- {
- "auto", "break", "case", "char", "const", "continue", "default", "do",
- "double", "else", "enum", "extern", "float", "for", "goto", "if", "int",
- "long", "register", "return", "short", "signed", "sizeof", "static",
- "struct", "switch", "typedef", "union", "unsigned", "void", "volatile",
- "while"
- };
-
- /* keyword - is "s" a reserved word in C */
- boolean keyword (s)
- char *s;
- {
- register int cond; /* condition code of lexcmp */
- register int mid;
- int hi, lo;
-
- /* binary search; reserved[] must be in alphabetical order */
- lo = 0; hi = sizeof(reserved) / sizeof(char *) - 1;
- while (lo <= hi)
- {
- mid = (hi + lo) / 2;
- if ((cond = lexcmp(s, reserved[mid])) == 0)
- return(TRUE);
- if (cond < 0)
- hi = mid - 1;
- else
- lo = mid + 1;
- }
- return (FALSE);
- }
-
- /* xref - cross reference */
- void xref(file)
- /*register*/ char *file;
- {
- /* int atoi(); */
- register char class;
- char *s, token[MAXLINE+1];
-
- line_count = 0;
- while ((s = new_line()) != NULL)
- {
- if ((class = get_token(&s, token)) != '#')
- {
- while (class != '\n')
- {
- if (class == ID && !keyword(token))
- use(token, file, line_count);
- class = get_token(&s, token);
- }
- }
- else if (get_token (&s, token) == ID)
- {
- if (streq(token, "include"))
- {
- get_name(s, token);
- use(token, file, line_count);
- }
- else if (streq(token, "define"))
- {
- get_token(&s, token);
- use(token, file, line_count);
- while (class != '\n') /* 881125 KRG; This is to */
- class = get_token(&s, token); /* take care of comments */
- /* starting on the same */
- /* line as a #define, */
- /* like above. */
- }
- else if (streq(token, "ifdef") || streq(token, "ifndef"))
- {
- get_token(&s, token);
- use(token, file, line_count);
- }
- else if (streq(token, "line"))
- {
- if (get_token(&s, token) == INTEGER)
- line_count = atoi(token);
- else
- fprintf(stderr, "#line %s\n", token);
- }
- else
- ; /* ignore #else, #endif, etc. */
- }
- }
- }
-
- /* putp - output a partial line to stdout */
- unsigned putp(s)
- /*register*/ char *s;
- {
- register unsigned n;
-
- for (n = 0; *s != EOS; ++n)
- putchar(*s++);
- return(n);
- }
-
- /* list_file - print lines within a file */
- #define FNAMELEN 14 /* max UNIX filename length. KRG */
- #define MAGIC 18 /* numbers are bad, but 18 = 4 + 14; 4 for left
- margin, 14 for max UNIX filename length. KRG */
-
- void list_file(ft)
- /*register*/ struct node *ft;
- {
- char *itoa();
- register unsigned b;
- register struct instance *it;
- char buf[5];
- char margin[MAGIC + 1]; /* makes it easier to prints formatted
- things with the putp() function. KRG */
-
- b = putp(" ");
- sprintf(margin,"%-*s", FNAMELEN, ft->name);
- b += putp(margin);
- /* print line numbers */
- it = ft->p.lines = ft->p.lines->next; /* move 'lines' to start */
- do
- {
- if (b == 0)
- {
- memset(margin, ' ', sizeof(margin));
- margin[MAGIC] = EOS;
- b = putp(margin);
- }
- b += putp(" ");
- /* b += itoa(it->line, buf) - buf; */ /* <- old line */
- b += strlen(itoa(it->line, buf, 10)); /* <- new line */ /* [1] */
- putp(buf);
- if (b > WIDTH - 8) /* leave margin on right */
- {
- putp("\n");
- b = 0;
- }
- it = it->next;
- }
- while (it != ft->p.lines);
- if (b > 6) /* non-blank line */
- putp("\n");
- }
-
- /* print_xref - dump cross reference table to stdout */
- void print_xref(nt)
- struct node *nt;
- {
-
- putp("\n"); putp(nt->name); putp("\n");
- tree_walk(nt->p.files, list_file);
- }
-
- main (argc, argv)
- /*register*/ int argc;
- /*register*/ char **argv;
- {
- /* FILE *freopen(); */
-
- if (argc <= 1)
- xref("<stdin>");
- else
- {
- while (--argc > 0)
- {
- if (freopen(*++argv, "r", stdin) == NULL)
- fprintf(stderr, "can't open %s\n", *argv);
- else
- xref(*argv);
- }
- }
- tree_walk(symbol_root, print_xref);
- }
-
-
- /* [1] itoa() differs from the function in strcref.c by the last parameter;
- Microsoft requires the last argument to specify the radix of the function.
- Also, Taylor's itoa returned the pointer to the END of the string, not the
- beginning, so strlen() had to come to the rescue.
- */
-