home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / calls.new < prev    next >
Text File  |  1986-11-30  |  26KB  |  1,050 lines

  1. /* Written  8:23 pm  Jun 16, 1986 by sources-request@mirror.UUCP in mirror:mod.sources */
  2. /* ---------- "v06i003:  new calls; shows function" ---------- */
  3. Submitted by: Wombat <cca!caip!pur-ee!pucc-j.Purdue.EDU!rsk>
  4. Mod.sources: Volume 6, Issue 3
  5. Archive-name: calls.new
  6.  
  7. [ I collapsed the handling of the -D -I and -U flags, and changed the
  8.   lines that used sprintf's return value.  Other than index/strchr, it
  9.   should work on any Unix.  --R$]
  10.  
  11. This is a massively revised, bug-fixed, and hacked version of "calls",
  12. which has been bouncing around the net for some time.  Comments and
  13. bugs and whatnot to Kevin Braunsdorf at pucc-j!ksb or ksb@j.cc.purdue.edu.
  14.  
  15. It's also available via anonymous ftp on j.cc.purdue.edu.
  16.  
  17. -- 
  18. Rich Kulawiec, pucc-j!rsk, rsk@j.cc.purdue.edu
  19.  
  20. #    This is a shell archive.
  21. #    Remove everything above and including the cut line.
  22. #    Then run the rest of the file through sh.
  23. #----cut here-----cut here-----cut here-----cut here----#
  24. #!/bin/sh
  25. # shar:    Shell Archiver
  26. #    Run the following text with /bin/sh to create:
  27. #    README
  28. #    Makefile
  29. #    calls.1u
  30. #    getopt.h
  31. #    main.h
  32. #    scan.h
  33. #    getopt.c
  34. #    main.c
  35. #    scan.c
  36. # This archive created: Thu Jun 12 22:46:39 1986
  37. # By:    Wombat (Purdue University)
  38. cat << \SHAR_EOF > README
  39. Calls is a program I use a lot.  It came off the net last year;
  40. since then I have been beefing it up to take on bigger and better
  41. things (static functions are the biggest).  The only thing calls
  42. would like to know to run okay is if calloc() really does zero out
  43. all of the memory it returns: if not, use the -DBADCALLOC in the
  44. Makefile.
  45.  
  46.                     Kevin S Braunsdorf
  47.                     ksb@j.cc.purdue.edu
  48.  
  49. P.S. to see the neat stuff you might try
  50.     ./calls -v -F newHASH/scan.c -f level1 -f dostdin *.c
  51. SHAR_EOF
  52. cat << \SHAR_EOF > Makefile
  53. # Makefile for calls, Kevin Braunsdorf PUCC
  54.  
  55. BIN =    /usr/local/bin
  56. #DEFS= -DBADCALLOC
  57. DEFS=
  58. CFLAGS = -g ${DEFS}
  59.  
  60. SRCm=    Makefile
  61. HDR =    main.h getopt.h scan.h
  62. SRCc=    main.c getopt.c scan.c
  63. OBJ =    main.o getopt.o scan.o
  64. SRC =    ${SRCm} ${HDR} ${SRCc}
  65.  
  66. all: calls
  67.  
  68. calls: ${OBJ}
  69.     ${CC} ${CFLAGS} ${OBJ} -o $@
  70.  
  71. install: calls
  72.     install -s -m 751 -o binary -g system calls ${BIN}
  73.  
  74. list:
  75.     lpr ${SRC}
  76.  
  77. lint:
  78.     lint -hnx ${SRCc}
  79.  
  80. clean:
  81.     rm -f ${OBJ}
  82.  
  83. spotless: clean
  84.     ci ${SRC}
  85.  
  86. ${SRC}:
  87.     co -l $@
  88.  
  89. depend: ${SRCc}
  90.     maketd ${SRCc}
  91.  
  92. # DO NOT DELETE THIS LINE - make depend DEPENDS ON IT
  93.  
  94. main.o: getopt.h main.c main.h scan.h
  95.  
  96. getopt.o: getopt.c getopt.h
  97.  
  98. scan.o: main.h scan.c scan.h
  99.  
  100. # *** Do not add anything here - It will go away. ***
  101. SHAR_EOF
  102. cat << \SHAR_EOF > calls.1u
  103. .TH CALLS 1 UNSUP
  104. .SH NAME
  105. calls \- print out calling pattern of a C program
  106. .SH SYNOPSIS
  107. calls [-aeitv] [-w n] [-f function] [-F function[/file.c]] [-D name[=def]] [-U name] [-I dir] [filenames]
  108. .SH DESCRIPTION
  109. .I Calls
  110. is intended to help analyze the flow of a program by laying out the
  111. functions called in a hierarchical manner.
  112. .I Calls
  113. invokes the C preprocessor on the named C source files, and outputs
  114. the analyzed calling pattern to standard output.
  115. All filenames given will have their calling sequences combined into
  116. one hierarchy.
  117. If a filename of \- is seen, standard input will be read.
  118. .P
  119. Functions called but not defined within the source file are shown as:
  120. .br
  121. .RS
  122. function
  123. .RE
  124. .P
  125. While functions defined in the source files are listed with the file they
  126. are declared in in brackets, as shown:
  127. .br
  128. .RS
  129. function [main.c] , or
  130. .br
  131. function [static in main.c]
  132. .RE
  133. or if the function is not being described
  134. .RS
  135. function [see also %d] , or
  136. .br
  137. function [see below]
  138. .RE
  139. .P
  140. Recursive references are shown as:
  141. .br
  142. .RS
  143. function <<< recursive >>>
  144. .RE
  145. .P
  146. For example, given the file
  147. .B prog.c
  148. .br
  149. .RS
  150. .nf
  151. main() {
  152.     abc();
  153.     def();
  154. }
  155. abc() {
  156.     ghi();
  157.     jkl();
  158. }
  159. static mno() { }
  160. ghi() {
  161.     abc();
  162.     def();
  163.     mno();
  164. }
  165. .fi
  166. .RE
  167. .sp
  168. Executing "calls prog.c" will produce:
  169. .sp
  170. .RS
  171. .nf
  172.     1    main [prog.c]
  173.     2        abc [prog.c]
  174.     3            ghi [prog.c]
  175.     4                abc <<< recursive >>>
  176.     5                def
  177.     6                mno [static in prog.c]
  178.     7            jkl
  179.     8        def
  180. .fi
  181. .RE
  182. .SH FLAGS
  183. .TP
  184. .BI -a
  185. Normally only the first call to a function is recorded for any
  186. given function, under this option all calls are recorded. This may
  187. make the output for some large programs very verbose and these are
  188. normally not needed to show the calling structure of a program.
  189. .TP
  190. .BI -e
  191. Normally an index listing (-i below) does not contain the external
  192. functions called in the program, under this option these are also listed.
  193. Note this option also turns on the indexing option, -i.
  194. .TP
  195. .BI -f function
  196. The named function will be printed as the root of a calling tree.
  197. .TP
  198. .BI -F function\[/file\]
  199. The named static function (in the given file) is used as the base of a
  200. calling tree, as above.  This allows closer examination of sources such
  201. as that of dbx(1) that have many functions with the same name.
  202. .TP
  203. .BI -h
  204. Display a brief help message.
  205. .TP
  206. .BI -i
  207. This option produces an index of all the functions declared in the
  208. processed files. Optionally all functions mentioned can be output;
  209. see -e above.
  210. .TP
  211. .BI -t
  212. This option instructs
  213. .I calls
  214. not to display calling trees that were
  215. not explicitly asked for on the command line. Using this option as
  216. well as the index option one can produce just a list of the functions
  217. declared in a file.
  218. .TP
  219. .BI -v
  220. Be less verbose in the index output, do not output any defined functions
  221. that were not present in any of the output trees.
  222. Note this also turns on the index option.
  223. For a list of all functions called
  224. by 'missle' one might examine the index output of "calls -vt -f missle *.c".
  225. .TP
  226. .BI -w n
  227. Set the max indentation width to n.  The default is 96 columns.
  228. .TP
  229. .BI -D name
  230. .TP
  231. .BI -D name=def
  232. Define the
  233. .I name
  234. for the preprocessor, as if by #define.
  235. If no definition is given, the name is defined as 1.
  236. .TP
  237. .BI -U name
  238. Remove any initial definition of
  239. .I name
  240. in the preprocessor.
  241. .TP
  242. .BI -I dir
  243. Change the path for searching for #include files whose names do not
  244. begin with / to look in
  245. .I dir
  246. before looking in the directories on the standard list.
  247. .br
  248. .RE
  249. .SH BUGS
  250. Static functions must be declared (in full) 
  251. .I before
  252. used to work properly.
  253. .br
  254. Output width checking is only done on the first character on a new line.
  255. .SH AUTHOR
  256. Originally from the net. Major revisions by Kevin Braunsdorf, PUCC.
  257. .SH SEE ALSO
  258. cpp(1), cc(1), ctags(1)
  259. SHAR_EOF
  260. cat << \SHAR_EOF > getopt.h
  261. /*
  262.  * get option letter from argument vector
  263.  */
  264. extern int
  265.     optind,            /* index into parent argv vector */
  266.     optopt;            /* character checked for validity */
  267. extern char
  268.     *optarg;        /* argument associated with option */
  269.  
  270. #define BADCH    ((int)'?')
  271. #define EMSG    ""
  272. #define tell(s)    {fputs(*nargv,stderr);fputs((s),stderr); \
  273.         fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);}
  274.  
  275. extern int getopt(), getarg();
  276. SHAR_EOF
  277. cat << \SHAR_EOF > main.h
  278. /*
  279.  * calls   -- print out the calling struture of a C program.
  280.  *
  281.  *  takes these options:
  282.  *    -a        show all calls (even duplicates)
  283.  *    -e        include externals in index
  284.  *    -i        normal index
  285.  *    -t        terse form, no extra trees output
  286.  *    -v        less verbose index
  287.  *    -w nn        paper width  (default 96)
  288.  *    -f name        function to start printing from
  289.  *    -F name[/file]    static function to start printing from
  290.  *
  291.  *  arguments passed on to CPP:
  292.  *    -D name        #define def
  293.  *    -U name        #undef def
  294.  *    -I file        #include path modifier
  295.  */
  296.  
  297. #define MAXDEPTH    99        /* max output depth level    */
  298. #define PAPERWIDTH    96        /* limits tabbing        */
  299. #define TABWIDTH    8        /* width of a \t        */
  300.  
  301. typedef struct CLnode {
  302.     struct CLnode *pCLnext;
  303.     struct HTnode *pHTlist;
  304. } LIST;
  305. #define nilCL    ((LIST *) 0)
  306. #define newCL()    ((LIST *)malloc(sizeof(LIST)))
  307.  
  308. extern char sbCmd[];
  309. extern int Allp;
  310. SHAR_EOF
  311. cat << \SHAR_EOF > scan.h
  312. /*
  313.  * scan.h -- scanner for calls
  314.  *    <stdio> must be included before this file, and
  315.  *    "main.h" is assumed the main.h defines BUCKET, also included before
  316.  */
  317.  
  318. #define LCURLY      '{'            /*}*/    /* messes with vi's mind     */
  319. #define RCURLY     /*{*/           '}'    /* to have curly in text    */
  320. #define LPAREN      '('        /*)*/    /* same mess            */
  321. #define RPAREN   /*(*/         ')'    /* as above            */
  322. #define LBRACK      '['        /*]*/    /* more mess implies        */
  323. #define RBRACK     /*[*/         ']'    /* more mass            */
  324. #define BUCKET        100        /* number of objects to alloc    */
  325. #define MAXCHARS    80        /* max number of chars in ident    */
  326.  
  327. typedef struct INnode {
  328.     struct HTnode *pHTname;        /* namep;            */
  329.     struct INnode *pINnext;        /* pnext            */
  330. } INST;
  331. #define nilINST    ((INST *) 0)
  332.  
  333. typedef struct HTnode {
  334.     char *pchname, *pchfile;    /* name & file declared        */
  335.     struct HTnode *pHTnext;        /* next in table (list)        */
  336.     struct INnode *pINcalls;    /* list of calls        */
  337.     short int
  338.         listp,            /* 0 = don't, 1 = do, 2 = done    */
  339.         calledp,        /* have we ever been called    */
  340.         iline,            /* line output on        */
  341.         localp;            /* crude static function flag    */
  342. } HASH, *PHT;
  343. #define nilHASH    ((HASH *) 0)
  344.  
  345. extern void level1();
  346. extern FILE *input;
  347. extern HASH *newHASH(), *search(), *pHTRoot[2];
  348. extern INST *newINST();
  349. SHAR_EOF
  350. cat << \SHAR_EOF > getopt.c
  351. /* @(#)getopt.c */
  352.  
  353. #include <stdio.h>
  354.  
  355. #include "getopt.h"
  356.  
  357. /*
  358.  * get option letter from argument vector
  359.  */
  360. int
  361.     optind = 1,        /* index into parent argv vector */
  362.     optopt;            /* character checked for validity */
  363. char    *optarg;        /* argument associated with option */
  364.  
  365. int
  366. getopt(nargc, nargv, ostr)
  367. int nargc;
  368. char **nargv, *ostr;
  369. {
  370.     extern char    *index();
  371.     register char    *oli;        /* option letter list index */
  372.     static char    *place = EMSG;    /* option letter processing */
  373.  
  374.     if(!*place) {            /* update scanning pointer */
  375.         if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  376.         if (*place == '-') {    /* found "--" */
  377.             ++optind;
  378.             return EOF;
  379.         }
  380.     }                /* option letter okay? */
  381.     if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
  382.         if(!*place) ++optind;
  383.         tell(": illegal option -- ");
  384.     }
  385.     if (*++oli != ':') {        /* don't need argument */
  386.         optarg = NULL;
  387.         if (!*place)
  388.             ++optind;
  389.     } else {                /* need an argument */
  390.         if (*place) {            /* no white space */
  391.             optarg = place;
  392.         } else if (nargc <= ++optind) {    /* no arg */
  393.             place = EMSG;
  394.             tell(": option requires an argument -- ");
  395.         } else {
  396.             optarg = nargv[optind];    /* white space */
  397.         }
  398.         place = EMSG;
  399.         ++optind;
  400.     }
  401.     return optopt;            /* dump back option letter */
  402. }
  403.  
  404. int
  405. getarg(nargc, nargv)
  406. int nargc;
  407. char **nargv;
  408. {
  409.     if (nargc <= optind) {
  410.         optarg = (char *) 0;
  411.         return EOF;
  412.     } else {
  413.         optarg = nargv[optind++];
  414.         return 0;
  415.     }
  416. }
  417. SHAR_EOF
  418. cat << \SHAR_EOF > main.c
  419. /*
  420.  * main.c -- calls mainline, trace calling sequences of C programs
  421.  */
  422.  
  423. #include <stdio.h>
  424. #include <ctype.h>
  425. #include <errno.h>
  426. #include <strings.h>
  427.  
  428. #include "scan.h"
  429. #include "getopt.h"
  430. #include "main.h"
  431.  
  432. /* globals */
  433. char
  434.     sbCmd[] = "cmd line";    /* kludge to notify user of error    */
  435. int
  436.     Allp = 0,        /* flag to show *all* function calls    */
  437.     Tersep = 0,        /* only requested trees            */
  438.     Externp = 0,        /* include externs in index        */
  439.     Indexp = 0,        /* output functions index        */
  440.     Verbosep = 1;        /* index functions not output        */
  441.  
  442. /* locals */
  443. static int
  444.     linect = 0,        /* line number                */
  445.     activep = 0,        /* current function being output    */
  446.     iWidth = PAPERWIDTH;    /* default paper width            */
  447. static char
  448.     *pchProg,        /* argv[0]                */
  449.     cppcommand[1024] =    /* cpp command string            */
  450.         "/lib/cpp -P ";
  451. static HASH
  452.     *activelist[MAXDEPTH];    /* list of current output names        */
  453.  
  454.  
  455. char *
  456. syserrlist()    /*  the routine returns a string for a system error    */
  457. {
  458.     extern char *sys_errlist[];
  459.     extern int sys_nerr;
  460.     extern int errno;
  461.     register char *pchErr =
  462.         errno == 0 ? "errno = 0" :
  463.         errno < sys_nerr ? sys_errlist[errno] : "errno out of range";
  464.  
  465.     errno = 0;
  466.     return pchErr;
  467. }
  468.  
  469. void
  470. process(filename, outname)    /* invoke cpp on file, call level1    */
  471. register char *filename, *outname;
  472. {
  473.     extern FILE *popen();
  474.     register char *sbNull;
  475.     register int ret;
  476.  
  477.     if (access(filename, 04) != 0) {
  478.         (void) fprintf(stderr, "%s: cannot open file '%s' (%s).\n", pchProg, filename, syserrlist());
  479.         return;
  480.     }
  481.     sbNull = cppcommand + strlen(cppcommand);
  482.     strcpy(sbNull, filename);
  483.     if (NULL == (input = popen(cppcommand, "r"))) {
  484.         (void) fprintf(stderr, "%s: fork of CPP command '%s' failed on file '%s' (%s).\n", pchProg, cppcommand, filename, syserrlist());
  485.     } else {
  486.         level1(outname);
  487.         if (0 != (ret = pclose(input)))
  488.             (void) fprintf(stderr, "%s: CPP command '%s' failed on file '%s' with return code %d.\n", pchProg, cppcommand, filename, ret);
  489.     }
  490.     *sbNull = '\0';
  491.     return;
  492. }
  493.  
  494. void
  495. dostdin()    /* copy stdin to temp file, call process on file    */
  496. {
  497.     extern char *mktemp();
  498.     register int cc;
  499.     register char *filename = mktemp("/tmp/callsXXXXXX");
  500.     register FILE *ofileptr = fopen(filename, "w");
  501.     register char *sbNull;
  502.  
  503.     if (NULL == ofileptr) {
  504.         (void) fprintf(stderr, "%s: cannot open tempfile '%s' for writing (%s).\n", pchProg, filename, syserrlist());
  505.     } else {
  506.         while (EOF != (cc = getchar()))
  507.             putc(cc, ofileptr);
  508.         fclose(ofileptr);
  509.         sbNull = cppcommand + strlen(cppcommand);
  510.         strcpy(sbNull, "-I. ");
  511.         process(filename, "stdin");
  512.         *sbNull = '\000';
  513.         unlink(filename);
  514.     }
  515. }
  516.  
  517. int
  518. active(func)    /* check for recursive calls, prevents endless output    */
  519. register HASH *func;
  520. {
  521.     register int i;
  522.  
  523.     for (i = 0; i < activep-1; i++)
  524.         if (func == activelist[i])
  525.             return 1;
  526.     return 0;
  527. }
  528.  
  529. void
  530. output(pHTFunc, tabc)    /* output a (sub)tree in pretty form        */
  531. register HASH *pHTFunc;
  532. register int tabc;
  533. {
  534.     static char dashes[] = "\n----------";
  535.     register INST *pINTemp;
  536.     register int i;
  537.  
  538.     ++linect;
  539.     (void) printf("\n%5d\t", linect);
  540.     if (activep < MAXDEPTH) {
  541.         activelist[activep++] = pHTFunc;
  542.     } else {
  543.         (void) printf("   * nesting is too deep");
  544.         return;
  545.     }
  546.  
  547.     for (i = 0; i < tabc; i++ )
  548.         putchar('\t');
  549.     printf("%s", pHTFunc->pchname);
  550.  
  551.     if (active(pHTFunc)) {
  552.         (void) printf(" <<< recursive >>>");
  553.     } else if (pHTFunc->pchfile) {
  554.         pINTemp = pHTFunc->pINcalls;
  555.         if (pHTFunc->listp && tabc && 0 == pHTFunc->iline) {
  556.             (void) printf(" [%s] [see below]", pHTFunc->pchfile);
  557.         } else if (! pHTFunc->iline) {
  558.             (void) printf(pHTFunc->localp ? " [static in %s]" : " [%s]", pHTFunc->pchfile);
  559.             pHTFunc->iline = linect;
  560.             if ((++tabc) * TABWIDTH >= iWidth) {
  561.                 (void) printf(dashes);
  562.                 tabc = 0;
  563.             }
  564.             while (pINTemp) {
  565.                 output(pINTemp->pHTname, tabc);
  566.                 pINTemp = pINTemp->pINnext;
  567.             }
  568.             if (! tabc)
  569.                 (void) printf(dashes);
  570.         } else if (pINTemp || pHTFunc->localp) {
  571.             (void) printf(" [see line %d]", pHTFunc->iline);
  572.         }
  573.     }
  574.     activelist[activep--] = nilHASH;
  575. }
  576.  
  577. int
  578. main(argc, argv)    /* parse args, add files, call output        */
  579. int argc;
  580. char *argv[];
  581. {
  582.     extern int atoi();
  583.     extern char *index();
  584.     static char sbOpts[] = "aehitvw:D:f:F:U:I:"; /* valid options    */
  585.     static char sbTemp[200];
  586.     static LIST *pCLRoot;
  587.     register HASH *pHTList;
  588.     register int cOption;
  589.     register LIST **ppCL;
  590.     register char *pchSplit;
  591.  
  592.     pchProg = argv[0];
  593.     ppCL = & pCLRoot;
  594.  
  595.     while (EOF != (cOption = getopt(argc, argv, sbOpts))) {
  596.         switch (cOption) {
  597.         case 'a':
  598.             Allp = 1;
  599.             break;
  600.         case 'e':
  601.             Externp = 1;
  602.             Indexp = 1;
  603.             break;
  604.         case 'F':
  605.             if (0 != (pchSplit = index(optarg, '/'))) {
  606.                 *pchSplit++ = '\000';
  607.             } else {
  608.         case 'f':    
  609.                 pchSplit = sbCmd;
  610.             }
  611.             pHTList = search(optarg, 'F' == cOption, pchSplit);
  612.             pHTList->listp = 1;
  613.             pHTList->pchfile = pchSplit;
  614.             *ppCL = newCL();
  615.             (*ppCL)->pCLnext = pCLRoot;
  616.             (*ppCL)->pHTlist = pHTList;
  617.             ppCL = & (*ppCL)->pCLnext;
  618.             break;
  619.         case 't':    
  620.             Tersep = 1;
  621.             break;
  622.         case 'v':
  623.             Verbosep = 0;
  624.             /*fallthrough*/
  625.         case 'i':
  626.             Indexp = 1;
  627.             break;
  628.         case 'w':
  629.             if (0 >= (iWidth = atoi(optarg)))
  630.                 iWidth = PAPERWIDTH;
  631.             break;
  632.         case 'D':
  633.         case 'I':
  634.         case 'U':
  635.             sprintf(sbTemp, "-%c%s ", cOption, optarg));
  636.             strcat(cppcommand, sbTemp);
  637.             break;
  638.         case '?':
  639.         case 'h':
  640.             (void) fprintf(stderr, "usage: %s [-aehitv] [-f function] [-F function[/file.c]] [-w width]\n\
  641.     [-D define] [-U undefine] [-I include-dir] [filename|-]*\n\
  642. \ta\tprint all calls in every function body\n\
  643. \te\tindex external functions too\n\
  644. \tf,F\tstart calling trace at given function\n\
  645. \th\tprint this message\n\
  646. \ti\tprint an index of defined functions\n\
  647. \tv\tlist only called functions in index output\n\
  648. \tt\tterse, list only trees that are requested\n\
  649. \tw\tset ouptut width\n\
  650. \tD,U,I\tas in cpp\n", pchProg);
  651.             exit('h' != cOption);
  652.         }
  653.     }
  654.     *ppCL = nilCL;
  655.  
  656.     while (EOF != getarg(argc, argv)) {
  657.         if ('-' == optarg[0] && '\000' == optarg[1])
  658.             dostdin();
  659.         else
  660.             process(optarg, optarg);
  661.     }
  662.  
  663.     while (pCLRoot) {        /* print requested trees    */
  664.         output(pCLRoot->pHTlist, 0);
  665.         putchar('\n');
  666.         pCLRoot = pCLRoot->pCLnext;
  667.     }
  668.  
  669.     if (!Tersep) {            /* print other trees        */
  670.         for (cOption = 0; cOption < 2; ++cOption) {
  671.             for (pHTList = pHTRoot[cOption]; pHTList; pHTList = pHTList->pHTnext) {
  672.                 if (!pHTList->calledp && NULL != pHTList->pchfile) {
  673.                     output(pHTList, 0);
  674.                     putchar('\n');
  675.                 }
  676.             }
  677.         }
  678.     }
  679.  
  680.     if (Indexp) {            /* print index            */
  681.         printf("\fIndex:\n");
  682.         while (nilHASH != pHTRoot[0] || nilHASH != pHTRoot[1]) {
  683.             
  684.             if (nilHASH == pHTRoot[0] || (nilHASH != pHTRoot[1] && strcmp(pHTRoot[0]->pchname, pHTRoot[1]->pchname) >= 0)) {
  685.                 pHTList = pHTRoot[1];
  686.                 pHTRoot[1] = pHTRoot[1]->pHTnext;
  687.             } else {
  688.                 pHTList = pHTRoot[0];
  689.                 pHTRoot[0] = pHTRoot[0]->pHTnext;
  690.             }
  691.             if (!Externp && NULL == pHTList->pchfile)
  692.                 continue;
  693.             if (!Verbosep && 0 == pHTList->iline)
  694.                 continue;
  695.             putchar('\t');
  696.             fputs(pHTList->pchname, stdout);
  697.             if (pHTList->localp) {
  698.                 printf(" [static in %s]", pHTList->pchfile);
  699.             } else if (((char *) 0) != pHTList->pchfile) {
  700.                 printf(" [%s]", pHTList->pchfile);
  701.             }
  702.             if (0 != pHTList->iline) {
  703.                 printf(" [see line %d]", pHTList->iline);
  704.             }
  705.             putchar('\n');
  706.         }
  707.     }
  708.     exit(0);
  709. }
  710. SHAR_EOF
  711. cat << \SHAR_EOF > scan.c
  712. /*
  713.  * scan.c -- a simple scanner for C, pulls out the function
  714.  *    calling pattern    (all by KSB)
  715.  */
  716.  
  717. #include <ctype.h>
  718. #include <stdio.h>
  719. #include <strings.h>
  720. #define strsave(X)    strcpy((char *)malloc(strlen((X))+1), (X))
  721.  
  722. #include "scan.h"
  723. #include "main.h"
  724.  
  725. int c;                /* parser look ahead            */
  726. FILE *input;            /* our input file pointer        */
  727. HASH *pHTRoot[2] =         /* our list of idents            */
  728.     {nilHASH, nilHASH};
  729. static char 
  730.     AUTO[] = "auto",    BREAK[] = "break",    CASE[] = "case",
  731.     CHAR[] = "char",    CONTINUE[] = "continue",DEFAULT[] = "default",
  732.     DO[] = "do",        DOUBLE[] = "double",    ELSE[] = "else",
  733.     ENUM[] = "enum",    EXTERN[] = "extern",    FLOAT[] = "float",
  734.     FOR[] = "for",        FORTRAN[] = "fortran",    GOTO[] = "goto",
  735.     IF[] = "if",        INT[] = "int",        LONG[] = "long",
  736.     REGISTER[] = "register",RETURN[] = "return",    SHORT[] = "short",
  737.     SIZEOF[] = "sizeof",    STATIC[] = "static",    STRUCT[] = "struct",
  738.     SWITCH[] = "switch",    TYPEDEF[] = "typedef",    UNION[] = "union",
  739.     UNSIGNED[] = "unsigned",VOID[] = "void",    WHILE[] = "while";
  740.  
  741. static HASH *
  742. newHASH()    /* get a new hash node                    */
  743. {
  744.     extern char *calloc();
  745.     register HASH *pHTRet;
  746.     static HASH *pHTQueue = nilHASH;
  747.  
  748.     if (nilHASH == pHTQueue) {
  749.         if (!(pHTRet = (HASH *)calloc(BUCKET, sizeof(HASH)))) {
  750.             (void) fprintf(stderr, "out of mem\n");
  751.             exit(2);
  752.         }
  753.         pHTQueue = (pHTRet+(BUCKET-1))->pHTnext = pHTRet;
  754.     }
  755.     pHTRet = pHTQueue;
  756.     pHTQueue = pHTRet->pHTnext ? nilHASH : pHTRet+1;
  757.     return pHTRet;
  758. }
  759.  
  760. HASH *
  761. search(name, Localp, pchFile)    /* translate name to hash node        */
  762. register char *name;
  763. int Localp;            /* -> trying to make a local def    */
  764. char *pchFile;
  765. {
  766.     register HASH **ppHT, *pHT;
  767.     register int i = 1;
  768.  
  769.     ppHT = & pHTRoot[1];    /* first search statics    */
  770.     while((pHT = *ppHT) && (i = strcmp(pHT->pchname, name)) <= 0) {
  771.         if (0 == i && 0 == strcmp(pchFile, pHT->pchfile))
  772.             break;    /* found a visible static function    */
  773.         ppHT = & pHT->pHTnext;
  774.         i = 1;
  775.     }
  776.  
  777.     if (0 != i && ! Localp) {
  778.         ppHT = & pHTRoot[0];
  779.         while((pHT = *ppHT) && (i = strcmp(pHT->pchname, name)) < 0)
  780.             ppHT = & pHT->pHTnext;
  781.     }
  782.  
  783.     if (0 != i) {
  784.         pHT = newHASH();
  785.         pHT->pchname = strsave(name);
  786. #ifdef BADCALLOC        /* calloc does not zero mem?        */
  787.         pHT->pchfile = (char *) 0;
  788.         pHT->listp = 0;
  789.         pHT->calledp = 0;
  790.         pHT->pINcalls = nilINST;
  791. #endif BADCALLOC
  792.         pHT->localp = Localp;
  793.         pHT->pHTnext = *ppHT;
  794.         *ppHT = pHT;
  795.     }
  796.     return pHT;
  797. }
  798.  
  799. /*
  800.  * here we don't assume that cpp takes out comments, really
  801.  * paranoid of us, but I think that way
  802.  * f is a flag we use to make the look ahead come out right
  803.  * in all cases
  804.  */
  805. void
  806. eatwhite(f)    /* skip blanks, comments, "strings", 'chars' in input    */
  807. register int f;
  808. {
  809.     if (f)
  810.         c = getc(input);
  811.     for(/* void */; /* c != EOF */; c = getc(input)) {
  812.         if (isspace(c) || c == '\b') {
  813.             continue;
  814.         } else if ('/' == c) {        /* start of comment? */
  815.             if ('*' == (c = getc(input))) {
  816.                 c = getc(input);    /* eat comment */
  817.                 for(;;) {
  818.                     while (c != '*')
  819.                         c = getc(input);
  820.                     if ('/' == (c = getc(input)))
  821.                         break;
  822.                 }
  823.             } else {
  824.                 ungetc(c, input);
  825.                 c = '/';
  826.                 break;
  827.             }
  828.         } else if ('\'' == c || '"' == c) {
  829.             while(c != (f = getc(input))) {
  830.                 if ('\\' == f)
  831.                     getc(input);
  832.             }
  833.         } else if ('#' == c) {
  834.             while ('\n' != getc(input))
  835.                 /* void */;
  836.         } else {
  837.             break;
  838.         }
  839.     }
  840. }
  841.  
  842. void
  843. balance(l, r)    /* find balancing character                */
  844. register int l, r;
  845. {
  846.     register int brace = 1;
  847.  
  848.     do
  849.         eatwhite(1);
  850.     while (brace += (l == c) - (r == c));
  851. }
  852.  
  853. int
  854. getid(sb, ppchToken)    /* return 0 = var, 1 == func, 2 == keyword    */
  855. register char *sb;
  856. char **ppchToken;
  857. {
  858.     static char *keywords[] = {
  859.         AUTO, BREAK, CASE, CHAR, CONTINUE, DEFAULT,
  860.         DO, DOUBLE, ELSE, ENUM, EXTERN, FLOAT, FOR,
  861.         FORTRAN, GOTO, IF, INT, LONG, REGISTER,
  862.         RETURN, SHORT, SIZEOF, STATIC, STRUCT, SWITCH,
  863.         TYPEDEF, UNION, UNSIGNED, VOID, WHILE, (char *)0
  864.     };
  865.     register int i = 0;
  866.     register char **psbKey = keywords;
  867.  
  868.     do {
  869.         if (i < MAXCHARS)
  870.             sb[i++] = c;
  871.         c = getc(input);
  872.     } while (isalpha(c) || isdigit(c) || '_' == c);
  873.     sb[i] = '\000';        /* buffer really goes to MAXCHARS+1    */
  874.     eatwhite(0);    /* c == next char after id */
  875.  
  876.     while (*psbKey && 0 != strcmp(*psbKey, sb))
  877.         ++psbKey;
  878.  
  879.     if (*psbKey) {
  880.         *ppchToken = *psbKey;
  881.         return 2;
  882.     }
  883.  
  884.     return LPAREN == c;
  885. }
  886.  
  887. void
  888. eatdecl(sb)    /* eat anything that starts with any keyword listed    */
  889. register char *sb;
  890. {
  891.     static char *which[] = {    /* keywords mark a declaration    */
  892.         AUTO, CHAR, STATIC, DOUBLE, ENUM, EXTERN, FLOAT, INT,
  893.         LONG, REGISTER, SHORT, STATIC, STRUCT, TYPEDEF, UNION,
  894.         UNSIGNED, VOID, (char *) 0};
  895.     register char **psb = which;
  896.  
  897.     while(*psb)
  898.         if (*psb++ == sb)
  899.             break;
  900.     if (*psb) {
  901.         while ('=' != c && ';' != c && RPAREN != c) {
  902.             if (LCURLY == c)
  903.                 balance(LCURLY, RCURLY);
  904.             else if (LPAREN == c) {
  905.                 balance(LPAREN, RPAREN);
  906.             }
  907.             eatwhite(1);
  908.         }
  909.     }
  910. }
  911.  
  912. INST *
  913. newINST()    /* get a new instaniation  node                */
  914. {
  915.     extern char *calloc();
  916.     register INST *pINRet;
  917.     static INST *pINQueue = nilINST;
  918.  
  919.     if (nilINST == pINQueue) {
  920.         if (!(pINRet = (INST *)calloc(BUCKET, sizeof(INST)))) {
  921.             (void) fprintf(stderr, "out of mem\n");
  922.             exit(2);
  923.         }
  924.         pINQueue = (pINRet+(BUCKET-1))->pINnext = pINRet;
  925.     }
  926.     pINRet = pINQueue;
  927.     pINQueue = pINRet->pINnext ? nilINST : pINRet+1;
  928.     return pINRet;
  929. }
  930.  
  931. void
  932. level2(pHTCaller, pchFile)    /* inside a function looking for calls    */
  933. HASH *pHTCaller;
  934. char *pchFile;
  935. {
  936.     static char buffer[MAXCHARS+1];
  937.     register struct INnode *pINLoop;
  938.     register int brace = 0;
  939.     register HASH *pHTFound;
  940.     register struct INnode **ppIN = & (pHTCaller->pINcalls);
  941.     register int declp = 1;        /* eating declarations        */
  942.     auto char *pchToken;
  943.  
  944.     while (brace || declp) {
  945.         if (isalpha(c) || '_' == c) {
  946.             switch (getid(buffer, & pchToken)) {
  947.             case 1:
  948.                 pHTFound = search(buffer, 0, pchFile);
  949.                 if (Allp)
  950.                     goto regardless;
  951.                 for(pINLoop = pHTCaller->pINcalls;
  952.                     pINLoop;
  953.                     pINLoop = pINLoop->pINnext)
  954.                     if (pHTFound == pINLoop->pHTname)
  955.                         break;
  956.                 if (! pINLoop) {
  957.             regardless:
  958.                     pINLoop = *ppIN = newINST();
  959.                     pINLoop->pHTname = pHTFound;
  960.                     ppIN = & pINLoop->pINnext;
  961.                 }
  962.                 ++pHTFound->calledp;
  963.                 break;
  964.             case 2:
  965.                 eatdecl(pchToken);
  966.                 /* fall through */
  967.             case 0:
  968.                 break;
  969.             }
  970.         } else {
  971.             if (LCURLY == c)
  972.                 declp = 0, ++brace;
  973.             else if (RCURLY == c)
  974.                 --brace;
  975.             eatwhite(1);
  976.         }
  977.     }
  978.     *ppIN = nilINST;
  979. }
  980.  
  981. void
  982. level1(filename)    /* in a C source program, looking for fnx(){..}    */
  983. register char *filename;
  984. {
  985.     static char buffer[MAXCHARS+1];
  986.     static char *pchToken;
  987.     register HASH *pHTTemp;
  988.     register int parens = 0;
  989.     register int Localp = 0;
  990.  
  991.     c = ' ';
  992.  
  993.     do {        /* looking to a function decl    */
  994.         if (isalpha(c) || '_' == c) {
  995.             switch (getid(buffer, & pchToken)) {
  996.             case 1:
  997.                 while (parens += (LPAREN == c) - (RPAREN == c))
  998.                     eatwhite(1);
  999.                 for (;;) {    /* eat complex stuff    */
  1000.                     eatwhite(1);
  1001.                     if (LPAREN == c) {
  1002.                         balance(LPAREN, RPAREN);
  1003.                         continue;
  1004.                     } else if (LBRACK == c) {
  1005.                         balance(LBRACK, RBRACK);
  1006.                         continue;
  1007.                     } else {
  1008.                         break;
  1009.                     }
  1010.                 }
  1011.                 pHTTemp = search(buffer, Localp, filename);
  1012.                 if (',' == c || ';' == c) {
  1013.                     Localp = 0;
  1014.                     break;
  1015.                 }
  1016.                 if (pHTTemp->pchfile && pHTTemp->pchfile != sbCmd &&
  1017.                     (pHTTemp->pchfile == filename ||
  1018.                     0 != strcmp(pHTTemp->pchfile, filename))) {
  1019.                     fprintf(stderr, "%s is multiply defined [%s, %s]\n", pHTTemp->pchname, pHTTemp->pchfile, filename);
  1020.                     exit(5);
  1021.                 } else {
  1022.                     pHTTemp->pchfile = filename;
  1023.                     Localp = 0;
  1024.                     level2(pHTTemp, filename);
  1025.                 }
  1026.                 continue;
  1027.             case 2:
  1028.                 if (STATIC == pchToken)
  1029.                     Localp = 1;
  1030.             case 0:
  1031.                 continue;
  1032.             }
  1033.         } else if (LCURLY == c) {
  1034.             balance(LCURLY, RCURLY);
  1035.         } else if (LPAREN == c) {
  1036.             ++parens;
  1037.         } else if (RPAREN == c) {
  1038.             --parens;
  1039.         } else if ('*' != c) {
  1040.             Localp = 0;
  1041.         }
  1042.         eatwhite(1);
  1043.     } while (EOF != c);
  1044. }
  1045. SHAR_EOF
  1046. #    End of shell archive
  1047. exit 0
  1048.  
  1049. /* End of text from mirror:mod.sources */
  1050.