home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-09-11 | 24.9 KB | 1,050 lines |
- /* Written 8:23 pm Jun 16, 1986 by sources-request@mirror.UUCP in mirror:mod.sources */
- /* ---------- "v06i003: new calls; shows function" ---------- */
- Submitted by: Wombat <cca!caip!pur-ee!pucc-j.Purdue.EDU!rsk>
- Mod.sources: Volume 6, Issue 3
- Archive-name: calls.new
-
- [ I collapsed the handling of the -D -I and -U flags, and changed the
- lines that used sprintf's return value. Other than index/strchr, it
- should work on any Unix. --R$]
-
- This is a massively revised, bug-fixed, and hacked version of "calls",
- which has been bouncing around the net for some time. Comments and
- bugs and whatnot to Kevin Braunsdorf at pucc-j!ksb or ksb@j.cc.purdue.edu.
-
- It's also available via anonymous ftp on j.cc.purdue.edu.
-
- --
- Rich Kulawiec, pucc-j!rsk, rsk@j.cc.purdue.edu
-
- # This is a shell archive.
- # Remove everything above and including the cut line.
- # Then run the rest of the file through sh.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # README
- # Makefile
- # calls.1u
- # getopt.h
- # main.h
- # scan.h
- # getopt.c
- # main.c
- # scan.c
- # This archive created: Thu Jun 12 22:46:39 1986
- # By: Wombat (Purdue University)
- cat << \SHAR_EOF > README
- Calls is a program I use a lot. It came off the net last year;
- since then I have been beefing it up to take on bigger and better
- things (static functions are the biggest). The only thing calls
- would like to know to run okay is if calloc() really does zero out
- all of the memory it returns: if not, use the -DBADCALLOC in the
- Makefile.
-
- Kevin S Braunsdorf
- ksb@j.cc.purdue.edu
-
- P.S. to see the neat stuff you might try
- ./calls -v -F newHASH/scan.c -f level1 -f dostdin *.c
- SHAR_EOF
- cat << \SHAR_EOF > Makefile
- # Makefile for calls, Kevin Braunsdorf PUCC
-
- BIN = /usr/local/bin
- #DEFS= -DBADCALLOC
- DEFS=
- CFLAGS = -g ${DEFS}
-
- SRCm= Makefile
- HDR = main.h getopt.h scan.h
- SRCc= main.c getopt.c scan.c
- OBJ = main.o getopt.o scan.o
- SRC = ${SRCm} ${HDR} ${SRCc}
-
- all: calls
-
- calls: ${OBJ}
- ${CC} ${CFLAGS} ${OBJ} -o $@
-
- install: calls
- install -s -m 751 -o binary -g system calls ${BIN}
-
- list:
- lpr ${SRC}
-
- lint:
- lint -hnx ${SRCc}
-
- clean:
- rm -f ${OBJ}
-
- spotless: clean
- ci ${SRC}
-
- ${SRC}:
- co -l $@
-
- depend: ${SRCc}
- maketd ${SRCc}
-
- # DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
-
- main.o: getopt.h main.c main.h scan.h
-
- getopt.o: getopt.c getopt.h
-
- scan.o: main.h scan.c scan.h
-
- # *** Do not add anything here - It will go away. ***
- SHAR_EOF
- cat << \SHAR_EOF > calls.1u
- .TH CALLS 1 UNSUP
- .SH NAME
- calls \- print out calling pattern of a C program
- .SH SYNOPSIS
- calls [-aeitv] [-w n] [-f function] [-F function[/file.c]] [-D name[=def]] [-U name] [-I dir] [filenames]
- .SH DESCRIPTION
- .I Calls
- is intended to help analyze the flow of a program by laying out the
- functions called in a hierarchical manner.
- .I Calls
- invokes the C preprocessor on the named C source files, and outputs
- the analyzed calling pattern to standard output.
- All filenames given will have their calling sequences combined into
- one hierarchy.
- If a filename of \- is seen, standard input will be read.
- .P
- Functions called but not defined within the source file are shown as:
- .br
- .RS
- function
- .RE
- .P
- While functions defined in the source files are listed with the file they
- are declared in in brackets, as shown:
- .br
- .RS
- function [main.c] , or
- .br
- function [static in main.c]
- .RE
- or if the function is not being described
- .RS
- function [see also %d] , or
- .br
- function [see below]
- .RE
- .P
- Recursive references are shown as:
- .br
- .RS
- function <<< recursive >>>
- .RE
- .P
- For example, given the file
- .B prog.c
- .br
- .RS
- .nf
- main() {
- abc();
- def();
- }
- abc() {
- ghi();
- jkl();
- }
- static mno() { }
- ghi() {
- abc();
- def();
- mno();
- }
- .fi
- .RE
- .sp
- Executing "calls prog.c" will produce:
- .sp
- .RS
- .nf
- 1 main [prog.c]
- 2 abc [prog.c]
- 3 ghi [prog.c]
- 4 abc <<< recursive >>>
- 5 def
- 6 mno [static in prog.c]
- 7 jkl
- 8 def
- .fi
- .RE
- .SH FLAGS
- .TP
- .BI -a
- Normally only the first call to a function is recorded for any
- given function, under this option all calls are recorded. This may
- make the output for some large programs very verbose and these are
- normally not needed to show the calling structure of a program.
- .TP
- .BI -e
- Normally an index listing (-i below) does not contain the external
- functions called in the program, under this option these are also listed.
- Note this option also turns on the indexing option, -i.
- .TP
- .BI -f function
- The named function will be printed as the root of a calling tree.
- .TP
- .BI -F function\[/file\]
- The named static function (in the given file) is used as the base of a
- calling tree, as above. This allows closer examination of sources such
- as that of dbx(1) that have many functions with the same name.
- .TP
- .BI -h
- Display a brief help message.
- .TP
- .BI -i
- This option produces an index of all the functions declared in the
- processed files. Optionally all functions mentioned can be output;
- see -e above.
- .TP
- .BI -t
- This option instructs
- .I calls
- not to display calling trees that were
- not explicitly asked for on the command line. Using this option as
- well as the index option one can produce just a list of the functions
- declared in a file.
- .TP
- .BI -v
- Be less verbose in the index output, do not output any defined functions
- that were not present in any of the output trees.
- Note this also turns on the index option.
- For a list of all functions called
- by 'missle' one might examine the index output of "calls -vt -f missle *.c".
- .TP
- .BI -w n
- Set the max indentation width to n. The default is 96 columns.
- .TP
- .BI -D name
- .TP
- .BI -D name=def
- Define the
- .I name
- for the preprocessor, as if by #define.
- If no definition is given, the name is defined as 1.
- .TP
- .BI -U name
- Remove any initial definition of
- .I name
- in the preprocessor.
- .TP
- .BI -I dir
- Change the path for searching for #include files whose names do not
- begin with / to look in
- .I dir
- before looking in the directories on the standard list.
- .br
- .RE
- .SH BUGS
- Static functions must be declared (in full)
- .I before
- used to work properly.
- .br
- Output width checking is only done on the first character on a new line.
- .SH AUTHOR
- Originally from the net. Major revisions by Kevin Braunsdorf, PUCC.
- .SH SEE ALSO
- cpp(1), cc(1), ctags(1)
- SHAR_EOF
- cat << \SHAR_EOF > getopt.h
- /*
- * get option letter from argument vector
- */
- extern int
- optind, /* index into parent argv vector */
- optopt; /* character checked for validity */
- extern char
- *optarg; /* argument associated with option */
-
- #define BADCH ((int)'?')
- #define EMSG ""
- #define tell(s) {fputs(*nargv,stderr);fputs((s),stderr); \
- fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
-
- extern int getopt(), getarg();
- SHAR_EOF
- cat << \SHAR_EOF > main.h
- /*
- * calls -- print out the calling struture of a C program.
- *
- * takes these options:
- * -a show all calls (even duplicates)
- * -e include externals in index
- * -i normal index
- * -t terse form, no extra trees output
- * -v less verbose index
- * -w nn paper width (default 96)
- * -f name function to start printing from
- * -F name[/file] static function to start printing from
- *
- * arguments passed on to CPP:
- * -D name #define def
- * -U name #undef def
- * -I file #include path modifier
- */
-
- #define MAXDEPTH 99 /* max output depth level */
- #define PAPERWIDTH 96 /* limits tabbing */
- #define TABWIDTH 8 /* width of a \t */
-
- typedef struct CLnode {
- struct CLnode *pCLnext;
- struct HTnode *pHTlist;
- } LIST;
- #define nilCL ((LIST *) 0)
- #define newCL() ((LIST *)malloc(sizeof(LIST)))
-
- extern char sbCmd[];
- extern int Allp;
- SHAR_EOF
- cat << \SHAR_EOF > scan.h
- /*
- * scan.h -- scanner for calls
- * <stdio> must be included before this file, and
- * "main.h" is assumed the main.h defines BUCKET, also included before
- */
-
- #define LCURLY '{' /*}*/ /* messes with vi's mind */
- #define RCURLY /*{*/ '}' /* to have curly in text */
- #define LPAREN '(' /*)*/ /* same mess */
- #define RPAREN /*(*/ ')' /* as above */
- #define LBRACK '[' /*]*/ /* more mess implies */
- #define RBRACK /*[*/ ']' /* more mass */
- #define BUCKET 100 /* number of objects to alloc */
- #define MAXCHARS 80 /* max number of chars in ident */
-
- typedef struct INnode {
- struct HTnode *pHTname; /* namep; */
- struct INnode *pINnext; /* pnext */
- } INST;
- #define nilINST ((INST *) 0)
-
- typedef struct HTnode {
- char *pchname, *pchfile; /* name & file declared */
- struct HTnode *pHTnext; /* next in table (list) */
- struct INnode *pINcalls; /* list of calls */
- short int
- listp, /* 0 = don't, 1 = do, 2 = done */
- calledp, /* have we ever been called */
- iline, /* line output on */
- localp; /* crude static function flag */
- } HASH, *PHT;
- #define nilHASH ((HASH *) 0)
-
- extern void level1();
- extern FILE *input;
- extern HASH *newHASH(), *search(), *pHTRoot[2];
- extern INST *newINST();
- SHAR_EOF
- cat << \SHAR_EOF > getopt.c
- /* @(#)getopt.c */
-
- #include <stdio.h>
-
- #include "getopt.h"
-
- /*
- * get option letter from argument vector
- */
- int
- optind = 1, /* index into parent argv vector */
- optopt; /* character checked for validity */
- char *optarg; /* argument associated with option */
-
- int
- getopt(nargc, nargv, ostr)
- int nargc;
- char **nargv, *ostr;
- {
- extern char *index();
- register char *oli; /* option letter list index */
- static char *place = EMSG; /* option letter processing */
-
- if(!*place) { /* update scanning pointer */
- if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
- if (*place == '-') { /* found "--" */
- ++optind;
- return EOF;
- }
- } /* option letter okay? */
- if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
- if(!*place) ++optind;
- tell(": illegal option -- ");
- }
- if (*++oli != ':') { /* don't need argument */
- optarg = NULL;
- if (!*place)
- ++optind;
- } else { /* need an argument */
- if (*place) { /* no white space */
- optarg = place;
- } else if (nargc <= ++optind) { /* no arg */
- place = EMSG;
- tell(": option requires an argument -- ");
- } else {
- optarg = nargv[optind]; /* white space */
- }
- place = EMSG;
- ++optind;
- }
- return optopt; /* dump back option letter */
- }
-
- int
- getarg(nargc, nargv)
- int nargc;
- char **nargv;
- {
- if (nargc <= optind) {
- optarg = (char *) 0;
- return EOF;
- } else {
- optarg = nargv[optind++];
- return 0;
- }
- }
- SHAR_EOF
- cat << \SHAR_EOF > main.c
- /*
- * main.c -- calls mainline, trace calling sequences of C programs
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <errno.h>
- #include <strings.h>
-
- #include "scan.h"
- #include "getopt.h"
- #include "main.h"
-
- /* globals */
- char
- sbCmd[] = "cmd line"; /* kludge to notify user of error */
- int
- Allp = 0, /* flag to show *all* function calls */
- Tersep = 0, /* only requested trees */
- Externp = 0, /* include externs in index */
- Indexp = 0, /* output functions index */
- Verbosep = 1; /* index functions not output */
-
- /* locals */
- static int
- linect = 0, /* line number */
- activep = 0, /* current function being output */
- iWidth = PAPERWIDTH; /* default paper width */
- static char
- *pchProg, /* argv[0] */
- cppcommand[1024] = /* cpp command string */
- "/lib/cpp -P ";
- static HASH
- *activelist[MAXDEPTH]; /* list of current output names */
-
-
- char *
- syserrlist() /* the routine returns a string for a system error */
- {
- extern char *sys_errlist[];
- extern int sys_nerr;
- extern int errno;
- register char *pchErr =
- errno == 0 ? "errno = 0" :
- errno < sys_nerr ? sys_errlist[errno] : "errno out of range";
-
- errno = 0;
- return pchErr;
- }
-
- void
- process(filename, outname) /* invoke cpp on file, call level1 */
- register char *filename, *outname;
- {
- extern FILE *popen();
- register char *sbNull;
- register int ret;
-
- if (access(filename, 04) != 0) {
- (void) fprintf(stderr, "%s: cannot open file '%s' (%s).\n", pchProg, filename, syserrlist());
- return;
- }
- sbNull = cppcommand + strlen(cppcommand);
- strcpy(sbNull, filename);
- if (NULL == (input = popen(cppcommand, "r"))) {
- (void) fprintf(stderr, "%s: fork of CPP command '%s' failed on file '%s' (%s).\n", pchProg, cppcommand, filename, syserrlist());
- } else {
- level1(outname);
- if (0 != (ret = pclose(input)))
- (void) fprintf(stderr, "%s: CPP command '%s' failed on file '%s' with return code %d.\n", pchProg, cppcommand, filename, ret);
- }
- *sbNull = '\0';
- return;
- }
-
- void
- dostdin() /* copy stdin to temp file, call process on file */
- {
- extern char *mktemp();
- register int cc;
- register char *filename = mktemp("/tmp/callsXXXXXX");
- register FILE *ofileptr = fopen(filename, "w");
- register char *sbNull;
-
- if (NULL == ofileptr) {
- (void) fprintf(stderr, "%s: cannot open tempfile '%s' for writing (%s).\n", pchProg, filename, syserrlist());
- } else {
- while (EOF != (cc = getchar()))
- putc(cc, ofileptr);
- fclose(ofileptr);
- sbNull = cppcommand + strlen(cppcommand);
- strcpy(sbNull, "-I. ");
- process(filename, "stdin");
- *sbNull = '\000';
- unlink(filename);
- }
- }
-
- int
- active(func) /* check for recursive calls, prevents endless output */
- register HASH *func;
- {
- register int i;
-
- for (i = 0; i < activep-1; i++)
- if (func == activelist[i])
- return 1;
- return 0;
- }
-
- void
- output(pHTFunc, tabc) /* output a (sub)tree in pretty form */
- register HASH *pHTFunc;
- register int tabc;
- {
- static char dashes[] = "\n----------";
- register INST *pINTemp;
- register int i;
-
- ++linect;
- (void) printf("\n%5d\t", linect);
- if (activep < MAXDEPTH) {
- activelist[activep++] = pHTFunc;
- } else {
- (void) printf(" * nesting is too deep");
- return;
- }
-
- for (i = 0; i < tabc; i++ )
- putchar('\t');
- printf("%s", pHTFunc->pchname);
-
- if (active(pHTFunc)) {
- (void) printf(" <<< recursive >>>");
- } else if (pHTFunc->pchfile) {
- pINTemp = pHTFunc->pINcalls;
- if (pHTFunc->listp && tabc && 0 == pHTFunc->iline) {
- (void) printf(" [%s] [see below]", pHTFunc->pchfile);
- } else if (! pHTFunc->iline) {
- (void) printf(pHTFunc->localp ? " [static in %s]" : " [%s]", pHTFunc->pchfile);
- pHTFunc->iline = linect;
- if ((++tabc) * TABWIDTH >= iWidth) {
- (void) printf(dashes);
- tabc = 0;
- }
- while (pINTemp) {
- output(pINTemp->pHTname, tabc);
- pINTemp = pINTemp->pINnext;
- }
- if (! tabc)
- (void) printf(dashes);
- } else if (pINTemp || pHTFunc->localp) {
- (void) printf(" [see line %d]", pHTFunc->iline);
- }
- }
- activelist[activep--] = nilHASH;
- }
-
- int
- main(argc, argv) /* parse args, add files, call output */
- int argc;
- char *argv[];
- {
- extern int atoi();
- extern char *index();
- static char sbOpts[] = "aehitvw:D:f:F:U:I:"; /* valid options */
- static char sbTemp[200];
- static LIST *pCLRoot;
- register HASH *pHTList;
- register int cOption;
- register LIST **ppCL;
- register char *pchSplit;
-
- pchProg = argv[0];
- ppCL = & pCLRoot;
-
- while (EOF != (cOption = getopt(argc, argv, sbOpts))) {
- switch (cOption) {
- case 'a':
- Allp = 1;
- break;
- case 'e':
- Externp = 1;
- Indexp = 1;
- break;
- case 'F':
- if (0 != (pchSplit = index(optarg, '/'))) {
- *pchSplit++ = '\000';
- } else {
- case 'f':
- pchSplit = sbCmd;
- }
- pHTList = search(optarg, 'F' == cOption, pchSplit);
- pHTList->listp = 1;
- pHTList->pchfile = pchSplit;
- *ppCL = newCL();
- (*ppCL)->pCLnext = pCLRoot;
- (*ppCL)->pHTlist = pHTList;
- ppCL = & (*ppCL)->pCLnext;
- break;
- case 't':
- Tersep = 1;
- break;
- case 'v':
- Verbosep = 0;
- /*fallthrough*/
- case 'i':
- Indexp = 1;
- break;
- case 'w':
- if (0 >= (iWidth = atoi(optarg)))
- iWidth = PAPERWIDTH;
- break;
- case 'D':
- case 'I':
- case 'U':
- sprintf(sbTemp, "-%c%s ", cOption, optarg));
- strcat(cppcommand, sbTemp);
- break;
- case '?':
- case 'h':
- (void) fprintf(stderr, "usage: %s [-aehitv] [-f function] [-F function[/file.c]] [-w width]\n\
- [-D define] [-U undefine] [-I include-dir] [filename|-]*\n\
- \ta\tprint all calls in every function body\n\
- \te\tindex external functions too\n\
- \tf,F\tstart calling trace at given function\n\
- \th\tprint this message\n\
- \ti\tprint an index of defined functions\n\
- \tv\tlist only called functions in index output\n\
- \tt\tterse, list only trees that are requested\n\
- \tw\tset ouptut width\n\
- \tD,U,I\tas in cpp\n", pchProg);
- exit('h' != cOption);
- }
- }
- *ppCL = nilCL;
-
- while (EOF != getarg(argc, argv)) {
- if ('-' == optarg[0] && '\000' == optarg[1])
- dostdin();
- else
- process(optarg, optarg);
- }
-
- while (pCLRoot) { /* print requested trees */
- output(pCLRoot->pHTlist, 0);
- putchar('\n');
- pCLRoot = pCLRoot->pCLnext;
- }
-
- if (!Tersep) { /* print other trees */
- for (cOption = 0; cOption < 2; ++cOption) {
- for (pHTList = pHTRoot[cOption]; pHTList; pHTList = pHTList->pHTnext) {
- if (!pHTList->calledp && NULL != pHTList->pchfile) {
- output(pHTList, 0);
- putchar('\n');
- }
- }
- }
- }
-
- if (Indexp) { /* print index */
- printf("\fIndex:\n");
- while (nilHASH != pHTRoot[0] || nilHASH != pHTRoot[1]) {
-
- if (nilHASH == pHTRoot[0] || (nilHASH != pHTRoot[1] && strcmp(pHTRoot[0]->pchname, pHTRoot[1]->pchname) >= 0)) {
- pHTList = pHTRoot[1];
- pHTRoot[1] = pHTRoot[1]->pHTnext;
- } else {
- pHTList = pHTRoot[0];
- pHTRoot[0] = pHTRoot[0]->pHTnext;
- }
- if (!Externp && NULL == pHTList->pchfile)
- continue;
- if (!Verbosep && 0 == pHTList->iline)
- continue;
- putchar('\t');
- fputs(pHTList->pchname, stdout);
- if (pHTList->localp) {
- printf(" [static in %s]", pHTList->pchfile);
- } else if (((char *) 0) != pHTList->pchfile) {
- printf(" [%s]", pHTList->pchfile);
- }
- if (0 != pHTList->iline) {
- printf(" [see line %d]", pHTList->iline);
- }
- putchar('\n');
- }
- }
- exit(0);
- }
- SHAR_EOF
- cat << \SHAR_EOF > scan.c
- /*
- * scan.c -- a simple scanner for C, pulls out the function
- * calling pattern (all by KSB)
- */
-
- #include <ctype.h>
- #include <stdio.h>
- #include <strings.h>
- #define strsave(X) strcpy((char *)malloc(strlen((X))+1), (X))
-
- #include "scan.h"
- #include "main.h"
-
- int c; /* parser look ahead */
- FILE *input; /* our input file pointer */
- HASH *pHTRoot[2] = /* our list of idents */
- {nilHASH, nilHASH};
- static char
- AUTO[] = "auto", BREAK[] = "break", CASE[] = "case",
- CHAR[] = "char", CONTINUE[] = "continue",DEFAULT[] = "default",
- DO[] = "do", DOUBLE[] = "double", ELSE[] = "else",
- ENUM[] = "enum", EXTERN[] = "extern", FLOAT[] = "float",
- FOR[] = "for", FORTRAN[] = "fortran", GOTO[] = "goto",
- IF[] = "if", INT[] = "int", LONG[] = "long",
- REGISTER[] = "register",RETURN[] = "return", SHORT[] = "short",
- SIZEOF[] = "sizeof", STATIC[] = "static", STRUCT[] = "struct",
- SWITCH[] = "switch", TYPEDEF[] = "typedef", UNION[] = "union",
- UNSIGNED[] = "unsigned",VOID[] = "void", WHILE[] = "while";
-
- static HASH *
- newHASH() /* get a new hash node */
- {
- extern char *calloc();
- register HASH *pHTRet;
- static HASH *pHTQueue = nilHASH;
-
- if (nilHASH == pHTQueue) {
- if (!(pHTRet = (HASH *)calloc(BUCKET, sizeof(HASH)))) {
- (void) fprintf(stderr, "out of mem\n");
- exit(2);
- }
- pHTQueue = (pHTRet+(BUCKET-1))->pHTnext = pHTRet;
- }
- pHTRet = pHTQueue;
- pHTQueue = pHTRet->pHTnext ? nilHASH : pHTRet+1;
- return pHTRet;
- }
-
- HASH *
- search(name, Localp, pchFile) /* translate name to hash node */
- register char *name;
- int Localp; /* -> trying to make a local def */
- char *pchFile;
- {
- register HASH **ppHT, *pHT;
- register int i = 1;
-
- ppHT = & pHTRoot[1]; /* first search statics */
- while((pHT = *ppHT) && (i = strcmp(pHT->pchname, name)) <= 0) {
- if (0 == i && 0 == strcmp(pchFile, pHT->pchfile))
- break; /* found a visible static function */
- ppHT = & pHT->pHTnext;
- i = 1;
- }
-
- if (0 != i && ! Localp) {
- ppHT = & pHTRoot[0];
- while((pHT = *ppHT) && (i = strcmp(pHT->pchname, name)) < 0)
- ppHT = & pHT->pHTnext;
- }
-
- if (0 != i) {
- pHT = newHASH();
- pHT->pchname = strsave(name);
- #ifdef BADCALLOC /* calloc does not zero mem? */
- pHT->pchfile = (char *) 0;
- pHT->listp = 0;
- pHT->calledp = 0;
- pHT->pINcalls = nilINST;
- #endif BADCALLOC
- pHT->localp = Localp;
- pHT->pHTnext = *ppHT;
- *ppHT = pHT;
- }
- return pHT;
- }
-
- /*
- * here we don't assume that cpp takes out comments, really
- * paranoid of us, but I think that way
- * f is a flag we use to make the look ahead come out right
- * in all cases
- */
- void
- eatwhite(f) /* skip blanks, comments, "strings", 'chars' in input */
- register int f;
- {
- if (f)
- c = getc(input);
- for(/* void */; /* c != EOF */; c = getc(input)) {
- if (isspace(c) || c == '\b') {
- continue;
- } else if ('/' == c) { /* start of comment? */
- if ('*' == (c = getc(input))) {
- c = getc(input); /* eat comment */
- for(;;) {
- while (c != '*')
- c = getc(input);
- if ('/' == (c = getc(input)))
- break;
- }
- } else {
- ungetc(c, input);
- c = '/';
- break;
- }
- } else if ('\'' == c || '"' == c) {
- while(c != (f = getc(input))) {
- if ('\\' == f)
- getc(input);
- }
- } else if ('#' == c) {
- while ('\n' != getc(input))
- /* void */;
- } else {
- break;
- }
- }
- }
-
- void
- balance(l, r) /* find balancing character */
- register int l, r;
- {
- register int brace = 1;
-
- do
- eatwhite(1);
- while (brace += (l == c) - (r == c));
- }
-
- int
- getid(sb, ppchToken) /* return 0 = var, 1 == func, 2 == keyword */
- register char *sb;
- char **ppchToken;
- {
- static char *keywords[] = {
- AUTO, BREAK, CASE, CHAR, CONTINUE, DEFAULT,
- DO, DOUBLE, ELSE, ENUM, EXTERN, FLOAT, FOR,
- FORTRAN, GOTO, IF, INT, LONG, REGISTER,
- RETURN, SHORT, SIZEOF, STATIC, STRUCT, SWITCH,
- TYPEDEF, UNION, UNSIGNED, VOID, WHILE, (char *)0
- };
- register int i = 0;
- register char **psbKey = keywords;
-
- do {
- if (i < MAXCHARS)
- sb[i++] = c;
- c = getc(input);
- } while (isalpha(c) || isdigit(c) || '_' == c);
- sb[i] = '\000'; /* buffer really goes to MAXCHARS+1 */
- eatwhite(0); /* c == next char after id */
-
- while (*psbKey && 0 != strcmp(*psbKey, sb))
- ++psbKey;
-
- if (*psbKey) {
- *ppchToken = *psbKey;
- return 2;
- }
-
- return LPAREN == c;
- }
-
- void
- eatdecl(sb) /* eat anything that starts with any keyword listed */
- register char *sb;
- {
- static char *which[] = { /* keywords mark a declaration */
- AUTO, CHAR, STATIC, DOUBLE, ENUM, EXTERN, FLOAT, INT,
- LONG, REGISTER, SHORT, STATIC, STRUCT, TYPEDEF, UNION,
- UNSIGNED, VOID, (char *) 0};
- register char **psb = which;
-
- while(*psb)
- if (*psb++ == sb)
- break;
- if (*psb) {
- while ('=' != c && ';' != c && RPAREN != c) {
- if (LCURLY == c)
- balance(LCURLY, RCURLY);
- else if (LPAREN == c) {
- balance(LPAREN, RPAREN);
- }
- eatwhite(1);
- }
- }
- }
-
- INST *
- newINST() /* get a new instaniation node */
- {
- extern char *calloc();
- register INST *pINRet;
- static INST *pINQueue = nilINST;
-
- if (nilINST == pINQueue) {
- if (!(pINRet = (INST *)calloc(BUCKET, sizeof(INST)))) {
- (void) fprintf(stderr, "out of mem\n");
- exit(2);
- }
- pINQueue = (pINRet+(BUCKET-1))->pINnext = pINRet;
- }
- pINRet = pINQueue;
- pINQueue = pINRet->pINnext ? nilINST : pINRet+1;
- return pINRet;
- }
-
- void
- level2(pHTCaller, pchFile) /* inside a function looking for calls */
- HASH *pHTCaller;
- char *pchFile;
- {
- static char buffer[MAXCHARS+1];
- register struct INnode *pINLoop;
- register int brace = 0;
- register HASH *pHTFound;
- register struct INnode **ppIN = & (pHTCaller->pINcalls);
- register int declp = 1; /* eating declarations */
- auto char *pchToken;
-
- while (brace || declp) {
- if (isalpha(c) || '_' == c) {
- switch (getid(buffer, & pchToken)) {
- case 1:
- pHTFound = search(buffer, 0, pchFile);
- if (Allp)
- goto regardless;
- for(pINLoop = pHTCaller->pINcalls;
- pINLoop;
- pINLoop = pINLoop->pINnext)
- if (pHTFound == pINLoop->pHTname)
- break;
- if (! pINLoop) {
- regardless:
- pINLoop = *ppIN = newINST();
- pINLoop->pHTname = pHTFound;
- ppIN = & pINLoop->pINnext;
- }
- ++pHTFound->calledp;
- break;
- case 2:
- eatdecl(pchToken);
- /* fall through */
- case 0:
- break;
- }
- } else {
- if (LCURLY == c)
- declp = 0, ++brace;
- else if (RCURLY == c)
- --brace;
- eatwhite(1);
- }
- }
- *ppIN = nilINST;
- }
-
- void
- level1(filename) /* in a C source program, looking for fnx(){..} */
- register char *filename;
- {
- static char buffer[MAXCHARS+1];
- static char *pchToken;
- register HASH *pHTTemp;
- register int parens = 0;
- register int Localp = 0;
-
- c = ' ';
-
- do { /* looking to a function decl */
- if (isalpha(c) || '_' == c) {
- switch (getid(buffer, & pchToken)) {
- case 1:
- while (parens += (LPAREN == c) - (RPAREN == c))
- eatwhite(1);
- for (;;) { /* eat complex stuff */
- eatwhite(1);
- if (LPAREN == c) {
- balance(LPAREN, RPAREN);
- continue;
- } else if (LBRACK == c) {
- balance(LBRACK, RBRACK);
- continue;
- } else {
- break;
- }
- }
- pHTTemp = search(buffer, Localp, filename);
- if (',' == c || ';' == c) {
- Localp = 0;
- break;
- }
- if (pHTTemp->pchfile && pHTTemp->pchfile != sbCmd &&
- (pHTTemp->pchfile == filename ||
- 0 != strcmp(pHTTemp->pchfile, filename))) {
- fprintf(stderr, "%s is multiply defined [%s, %s]\n", pHTTemp->pchname, pHTTemp->pchfile, filename);
- exit(5);
- } else {
- pHTTemp->pchfile = filename;
- Localp = 0;
- level2(pHTTemp, filename);
- }
- continue;
- case 2:
- if (STATIC == pchToken)
- Localp = 1;
- case 0:
- continue;
- }
- } else if (LCURLY == c) {
- balance(LCURLY, RCURLY);
- } else if (LPAREN == c) {
- ++parens;
- } else if (RPAREN == c) {
- --parens;
- } else if ('*' != c) {
- Localp = 0;
- }
- eatwhite(1);
- } while (EOF != c);
- }
- SHAR_EOF
- # End of shell archive
- exit 0
-
- /* End of text from mirror:mod.sources */
-