home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 236_01 / cflow.c < prev    next >
Text File  |  1989-06-07  |  8KB  |  347 lines

  1. /*
  2.     HEADER:        CUG236;
  3.     TITLE:        Function Abstractor;
  4.     DATE:        04/19/1987;
  5.     DESCRIPTION:    "Abstracts C function calls and declarations from a C
  6.             source and produces a listing of the program's calling
  7.             hierarchy."
  8.     VERSION:    3.0;
  9.     KEYWORDS:    Flow Analysis, Flow Analyzer;
  10.     FILENAME:    CFLOW.C;
  11.     SEE-ALSO:    CFLOW.DOC;
  12.     COMPILERS:    vanilla;
  13.     AUTHORS:    W. C. Colley III, Mark Ellington;
  14. */
  15.  
  16. /*
  17. **   CFLOW.C : find module call structure of c program
  18. **   refer to cflow.doc for how to use
  19. **                    Mark Ellington
  20. **                    05-27-84
  21. **
  22. **   Ported to portable C.  Required the following changes:
  23. **
  24. **    1)  Stripped BDS C hooks.
  25. **    2)  Stripped C/80 hooks.
  26. **    3)  Allowed for presence/absence of header files "ctype.h"
  27. **        and "string.h".
  28. **    4)  Allowed for possible pre-definition of constants TRUE,
  29. **        FALSE, and EOF.
  30. **    5)  Made variable fptr type FILE * instead of int.
  31. **    6)  Added a #define for the max line length.
  32. **    7)  Made preprocessor directive rejection logic smarter.
  33. **    8)  Removed name conflict between our fgets() and the std
  34. **        library fgets() by changing ours to get_source_line().
  35. **                    William C. Colley, III
  36. **                    04-19-87
  37. */
  38.  
  39. #include <stdio.h>
  40.  
  41. /*
  42.  * Portability Note:  The AZTEC C compilers handle the binary/text file
  43.  * dichotomy differently from most other compilers.  Uncomment the following
  44.  * pair of #defines if you are running AZTEC C:
  45.  */
  46.  
  47. /*
  48. #define getc(f)        agetc(f)
  49. #define putc(c,f)    aputc(c,f)
  50. */
  51.  
  52. /*  Portability Note:  If you do not have a header file "ctype.h",
  53.     uncomment the following #define so that the program will look for
  54.     library support.                            */
  55.  
  56. /* #define    NO_CTYPE_H                        */
  57.  
  58. #ifdef    NO_CTYPE_H
  59. extern int isalnum();
  60. #else
  61. #include <ctype.h>
  62. #endif
  63.  
  64. /*  Portability Note:  If you do not have a header file "string.h",
  65.     uncomment the following #define so that the program will look for
  66.     library support.                            */
  67.  
  68. /* #define    NO_STRING_H                        */
  69.  
  70. #ifdef    NO_STRING_H
  71. extern int strcmp();
  72. #else
  73. #include <string.h>
  74. #endif
  75.  
  76. /*  Portability Note:  A few compilers don't know the additional type
  77.     void.  If yours is one of these, uncomment the following #define.    */
  78.  
  79. /* #define    void        int                    */
  80.  
  81. #ifndef TRUE
  82. #define TRUE    1
  83. #endif
  84.  
  85. #ifndef FALSE
  86. #define FALSE    0
  87. #endif
  88.  
  89. #ifndef EOF
  90. #define EOF    -1
  91. #endif
  92.  
  93. #define LINE_LENGTH    256    /* Max line length program can handle.    */
  94.  
  95. FILE *fptr;            /* input file pointer            */
  96. int level;            /* keep track of level of open "{"s    */
  97. char name[LINE_LENGTH];        /* module name buffer            */
  98. char ins[LINE_LENGTH];        /* source input line buffer        */
  99. int curchar;            /* current character in input line
  100.                     buffer array subscript        */
  101.  
  102. /*  Fixed bug that makes _ characters lop off the beginning of function
  103.     names.  WCC3.                            */
  104.  
  105. int isal_num(c)
  106. int c;
  107. {
  108.     return isalnum(c) || c == '_';
  109. }
  110.  
  111. int main(argc,argv)
  112. int argc;
  113. char *argv[];
  114. {
  115.     void modules();
  116.  
  117.     printf("\nCFLOW --> function declarations and calls in C source");
  118.     printf("\n by Mark Ellington");
  119.  
  120.     if (argc != 2) {
  121.         printf("\nUsage: cflow [infilename.ext] ");
  122.         return TRUE;
  123.     }
  124.  
  125.     if (!(fptr = fopen(argv[1],"r"))) {
  126.         printf("\nCan't open %s\n",argv[1]);
  127.         return TRUE;
  128.     }
  129.     printf("\nSource file: %s",argv[1]);
  130.  
  131.     modules();
  132.  
  133.     fclose(fptr);  return FALSE;
  134. }
  135.  
  136.  
  137. void modules()        /* find function declarations and calls        */
  138. {
  139.     int j;
  140.     char c;
  141.     int incom;    /* comment flag                    */
  142.     int decl;    /* module declaration line flag            */
  143.     int lastlin;    /* last line of file flag            */
  144.     int quoted;    /* within " quotes                */
  145.     int header;    /* within function header (before 1st '{')    */
  146.     int comment(), get_source_line(), modname(), skipline();
  147.     void comout(), lookbak(), quotes();
  148.  
  149.     incom = lastlin = quoted  = header = FALSE;  level = 0;
  150.  
  151.     do {
  152.         lastlin = get_source_line();    /* read a line of source */
  153.         decl = FALSE;        /* assume nothing        */
  154.         curchar = 0;
  155.                     /* read for significant characters */
  156.         while (curchar < LINE_LENGTH) {
  157.             if (skipline()) break;
  158.             quotes();    /* skip single quoted character */
  159.             incom = comment(incom); /* true if in comment    */
  160.             c = ins[curchar];
  161.             /* read for significant characters */
  162.             if (!incom) {
  163.                 /* skip double quoted strings */
  164.                 if (c == '"') quoted = !quoted;
  165.                 if (!quoted)
  166.                 switch(c) {
  167.                     case '{' :    level++;  header = FALSE;
  168.                         break;
  169.  
  170.                     case '}' :    level--;
  171.                         break;
  172.  
  173.                 /* "(" always follows function call */
  174.                     /* or declaration */
  175.  
  176.                     case '(' :    if (!isalnum(ins[curchar-1]))
  177.                             break;
  178.                         lookbak(curchar);
  179.                         if (!(j = modname())) break;
  180.                         else decl = TRUE;
  181.                         if (j == 2) header = TRUE;
  182.                         break;
  183.  
  184.                     default :    break;
  185.                 }
  186.             }
  187.             ++curchar;     /* next character */
  188.         }
  189.         /* display argument declarations */
  190.         comout(ins);
  191.         if (header && !decl) printf("%s",ins);
  192.     } while (lastlin);    /*  = 0 if last line */
  193. }
  194.  
  195. /* skip this line ? */
  196.  
  197. int skipline()
  198. {
  199.     char c;
  200.     int i;
  201.  
  202.     if (!(c = ins[curchar])) return TRUE;    /* end of line        */
  203.     if (c == '#') {            /* skip preprocessor directives */
  204.         for (i = curchar; i--; )
  205.             if (ins[i] != ' ' && ins[i] != '\t') return FALSE;
  206.         return TRUE;
  207.     }
  208.     return FALSE;                /* don't skip        */
  209. }
  210.  
  211.  
  212. /* skip characters quoted (for instance '}' would throw off level count) */
  213.  
  214. void quotes()
  215. {
  216.     int flowchar();
  217.  
  218.     if (flowchar(ins[curchar]) &&        /* test critical chars only */
  219.         ins[curchar+1] == '\'' &&        /* next char single quote? */
  220.         curchar+2 < LINE_LENGTH)        /* don't pass end of string */
  221.         curchar = curchar + 2;        /* skip past quote    */
  222. }
  223.  
  224.  
  225. /* return TRUE if entering comment, FALSE if exiting */
  226.  
  227. int comment(incom)
  228. int incom;
  229. {
  230.     if (ins[curchar] == '/') {
  231.         if (ins[curchar+1] == '*') return TRUE;
  232.         if (curchar > 0 && ins[curchar-1] == '*') return FALSE;
  233.     }
  234.     return incom;                /* unchanged        */
  235. }
  236.  
  237.  
  238. /* look back from position n in string.     called with n indicating '('.
  239.    determine function name                        */
  240.  
  241. void lookbak(n)
  242. int n;
  243. {
  244.     int i;
  245.     void comout();
  246.  
  247.     while (!isal_num(ins[n]) && n) --n;
  248.  
  249.     /* find leading blank */
  250.     while (isal_num(ins[n-1]) && n) --n;
  251.  
  252.     /* save name */
  253.     /* include variable declarations if module declaration */
  254.  
  255.     i = 0;
  256.     if (level == 0)            /* full line if declaration    */
  257.         while (ins[n]) name[i++] = ins[n++];
  258.     else                /* function call within function */
  259.         while (isal_num(ins[n])) name[i++] = ins[n++];
  260.     name[i] = '\0';
  261.     comout(name);    /* remove comment from name string */
  262. }
  263.  
  264.  
  265. /* terminate string at comment */
  266.  
  267. void comout(s)
  268. char *s;
  269. {
  270.     char c;
  271.  
  272.     while (c = *s++)
  273.         if (c == '/')
  274.             if (*s == '*') {
  275.                 *(s - 1) = '\n';
  276.                 *s = '\0';
  277.                 break;
  278.             }
  279. }
  280.  
  281.  
  282.  
  283. /* display module name with indentation according to { level */
  284. /* returns 0 if not module, 1 if call within module, 2 if    */
  285. /* module declaration  */
  286.  
  287. int modname()
  288. {
  289.     int j, unreserved();
  290.     void comout();
  291.  
  292.     if (unreserved()) {        /* test if builtin like while */
  293.         if (level == 0) {
  294.             comout(ins);
  295.             printf("\n\n\n**\n%s",ins);
  296.             return 2;
  297.         }
  298.         else {
  299.             printf("\n");
  300.             for (j=0; j < level; ++j)
  301.                 putchar('\t');
  302.             printf("%s()",name);
  303.             return 1;
  304.         }
  305.     }
  306.     return 0;
  307. }
  308.  
  309. /* test for names that are operators not functions */
  310.  
  311. int unreserved()
  312. {
  313.     return    strcmp(name,"return") &&
  314.         strcmp(name,"if") &&
  315.         strcmp(name,"while") &&
  316.         strcmp(name,"for") &&
  317.         strcmp(name,"switch");
  318. }
  319.  
  320.  
  321. /* test if character is one that program tracks */
  322.  
  323. int flowchar(c)
  324. char c;
  325. {
  326.     return c == '{' || c == '}' || c == '\"';
  327. }
  328.  
  329.  
  330. /* read a line of source */
  331.  
  332. int get_source_line()
  333. {
  334.     char *s;
  335.     int ch;
  336.  
  337.     s = ins;
  338.     while ((ch = getc(fptr)) != EOF) {
  339.         if ((*s++ = ch) == '\n') {
  340.             *s = '\0';
  341.             return TRUE;
  342.         }
  343.     }
  344.     *s = '\0';
  345.     return FALSE;
  346. }
  347.