home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 344_01 / cflow.c < prev    next >
C/C++ Source or Header  |  1990-12-05  |  15KB  |  516 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. #include <dos.h>
  75. #include <dir.h>
  76. #endif
  77.  
  78. /*  Portability Note:  A few compilers don't know the additional type
  79.     void.  If yours is one of these, uncomment the following #define.   */
  80.  
  81. /* #define      void            int                                     */
  82.  
  83. #ifndef TRUE
  84. #define TRUE    1
  85. #endif
  86.  
  87. #ifndef FALSE
  88. #define FALSE   0
  89. #endif
  90.  
  91. #ifndef EOF
  92. #define EOF     -1
  93. #endif
  94.  
  95. #define LINE_LENGTH     256     /* Max line length program can handle.  */
  96. #define PAGE_LENGTH     55      /* lines per page                       */
  97.  
  98. FILE *fptr;                     /* input file pointer                   */
  99. int level;                      /* keep track of level of open "{"s     */
  100. char name[LINE_LENGTH];         /* module name buffer                   */
  101. char ins[LINE_LENGTH];          /* source input line buffer             */
  102. int curchar;                    /* current character in input line
  103.                                         buffer array subscript          */
  104. unsigned short int linenum;     /* current line number                  */
  105. unsigned short int linecnt;     /* hidden line number                   */
  106. int function = FALSE;           /* flag for level zero only             */
  107. char filename[128];             /* holder for filename                  */
  108. short int lpp;                  /* holder for lines per page            */
  109. struct date today;              /* structure for todays date            */
  110. struct time now;                /* structure for current time           */
  111. short int pageno;               /* holder for page number               */
  112. struct ffblk ffblk;             /* holder for file structure            */
  113.  
  114. /*  Fixed bug that makes _ characters lop off the beginning of function
  115.     names.  WCC3.                                                       */
  116.  
  117. /**********************************************************************/
  118.  
  119. int main(argc,argv)
  120. int argc;
  121. char *argv[];
  122. {
  123.    void modules(), prt_hdr();
  124.    int i, done, filenum;
  125.    unsigned long int ttllines;
  126.  
  127.    if (argc < 2) {
  128.       fprintf(stderr,"\nUsage: cflow infilename.ext [-f] ");
  129.       return TRUE;
  130.    }
  131.  
  132.    if (done = findfirst(argv[1], &ffblk, 0)) {
  133.       fprintf(stderr,"\nCan't open %s\n",argv[1]);
  134.       return TRUE;
  135.    }
  136.  
  137.    if (argc > 2)
  138.       if (argv[2][0] == '-' && (argv[2][1] == 'f' || argv[2][1] == 'F'))
  139.          function = TRUE;
  140.       else {
  141.          fprintf(stderr,"Second parameter is either '-f' or '-F'.");
  142.          return TRUE;
  143.       }
  144.  
  145.    getdate(&today);
  146.    gettime(&now);
  147.    filenum = 0;
  148.    ttllines = 0;
  149.  
  150.    while (!done) {
  151.       for (i = 0; ffblk.ff_name[i]; i++)
  152.          filename[i] = toupper(ffblk.ff_name[i]);
  153.       filename[i] = NULL;
  154.  
  155.       if (!(fptr = fopen(filename,"r")))
  156.          break;
  157.  
  158.       if (!function) {
  159.          pageno = 0;
  160.          prt_hdr();
  161.       } 
  162.       else
  163.          fprintf(stderr,"File: %s\n", filename);
  164.  
  165.       if (filenum++ > 1)
  166.          ttllines += linenum;
  167.       linenum = linecnt = 0;
  168.  
  169.       modules();
  170.  
  171.       fclose(fptr);
  172.  
  173.       done = findnext(&ffblk);
  174.    }
  175.    if (filenum > 1)
  176.       fprintf(stderr, "Processed %d files, %u lines\n", filenum, ttllines);
  177.  
  178.    return FALSE;
  179.  
  180. }
  181.  
  182. /**********************************************************************/
  183.  
  184. void modules()          /* find function declarations and calls         */
  185. {
  186.    char c;
  187.    int i, dquote, defcont;
  188.    int incom;      /* comment flag                                 */
  189.    int decl;       /* module declaration line flag                 */
  190.    int quoted;     /* within " quotes "                            */
  191.    int header;     /* within function header (before 1st '{')      */
  192.    int lookbak();
  193.    void comout(), modname(), prt_hdr();
  194.  
  195.    incom = quoted = header = defcont = dquote = FALSE;
  196.    level = 0;
  197.  
  198.    while (fgets(ins, LINE_LENGTH, fptr)) { /* read a line of source */
  199.       linenum++;
  200.       decl = FALSE;           /* assume nothing               */
  201.       curchar = 0;
  202.  
  203.       while (ins[curchar]) {  /* read for significant characters */
  204.  
  205. comment:
  206.          if (ins[curchar] == '/' && (!quoted)) /* comments ? */
  207.             if (incom) {
  208.                if (curchar && (ins[curchar-1] == '*')) {
  209.                   incom = FALSE;
  210.                   curchar++;
  211.                }
  212.             } 
  213.             else
  214.                if (ins[curchar+1] == '*') {
  215.                   incom = TRUE;
  216.                   curchar += 2;
  217.                   if (ins[curchar] == '/')
  218.                      curchar++;
  219.                }
  220.  
  221.          if (!incom) {
  222.             if (defcont) { /* delete preprocessor continued lines */
  223. def_cont:
  224.                defcont = TRUE;
  225.                for (i = curchar; ins[i]; i++)
  226.                   switch (ins[i]) {
  227.  
  228.                   case '\\':
  229.                      i++;
  230.                      break;
  231.  
  232.                   case '\'':
  233.                      if (!dquote) {
  234.                         if (ins[++i] == '\\')
  235.                            i++;
  236.                         i++;
  237.                      }
  238.                      break;
  239.  
  240.                   case '"':
  241.                      dquote = !dquote;
  242.                      break;
  243.  
  244.                   case '/':
  245.                      if (!dquote)
  246.                         if (ins[i+1] == '*') {
  247.                            curchar = i;
  248.                            goto comment;
  249.                         }
  250.                      break;
  251.  
  252.                   } /* end switch */
  253.  
  254.                if (ins[i-2] != '\\' || ins[i-1] != '\n')
  255.                   defcont = dquote = FALSE;
  256.                break;
  257.             }
  258.  
  259.             if (ins[curchar] == '\\') {
  260.                curchar += 2;
  261.                if (!ins[curchar])
  262.                   break;
  263.                continue;
  264.             }
  265.  
  266.             /* skip double quoted strings */
  267.             if ((c  = ins[curchar]) == '"')
  268.                quoted = !quoted;
  269.  
  270.             if (!quoted) {
  271.                if (ins[curchar] == '#') {
  272.                   for (i = curchar - 1; i >= 0; i-- )
  273.                      if (!isspace(ins[i]))
  274.                         break;
  275.                   if (i < 0)
  276.                      goto def_cont;
  277.                }
  278.  
  279.                switch(c) {
  280.  
  281.                case '\'':
  282.                   if (ins[++curchar] == '\\')
  283.                      curchar++;
  284.                   curchar++;
  285.                   break;
  286.  
  287.                case '{':  
  288.                   level++;
  289.                   header = FALSE;
  290.                   break;
  291.  
  292.                case '}':  
  293.                   level--;
  294.                   break;
  295.  
  296.                   /* "(" always follows function call */
  297.                   /* or declaration */
  298.  
  299.                case '(':
  300.                   if ((function && level) || header || !lookbak(curchar)) {
  301.                      linenum += linecnt;
  302.                      linecnt = 0;
  303.                      break;
  304.                   }
  305.                   modname();
  306.                   decl = TRUE;
  307.                   header = !level;
  308.                   linenum += linecnt;
  309.                   linecnt = 0;
  310.                   break;
  311.  
  312.                } /* End switch */
  313.             } /* End if */
  314.          } /* End if */
  315.          curchar++;
  316.       } /* End while */
  317.  
  318.       if (defcont && (!incom))
  319.          continue;
  320.  
  321.       /* display argument declarations */
  322.  
  323.       if (header && !decl && !function) {
  324.          comout(ins);
  325.          printf("%s",ins);
  326.          if ((lpp++) >= PAGE_LENGTH)
  327.             prt_hdr();
  328.       }
  329.    }  /* end while */
  330.    if (!function)
  331.       printf("\n\n >>> End CFLOW of %s <<<\f", filename);
  332. }
  333.  
  334. /**********************************************************************/
  335.  
  336. /* look back from position n in string.  called with n indicating '('.
  337.    determine function name                                              */
  338.  
  339. int lookbak(n)
  340. int n;
  341. {
  342.    int i, j, parens;
  343.    char lins[LINE_LENGTH];
  344.    void comout();
  345.  
  346.    while (isspace(ins[--n]));
  347.    if (!(isalnum(ins[n]) || (ins[n] == '_')))
  348.       return FALSE;
  349.  
  350.    /* find leading blank */
  351.    while ((isalnum(ins[n-1]) || (ins[n-1] == '_')) && n)
  352.       --n;
  353.  
  354.    /* save name */
  355.    /* include variable declarations if module declaration */
  356.  
  357.  
  358.    if (!level) {                /* full line if declaration     */
  359.       for (j = n, parens = 1; ins[j++] != '(';);
  360.  
  361.       while (ins[j] != ';' && ins[j] && parens) {
  362.          if (ins[j] == '(')
  363.             parens++;
  364.          if (ins[j] == ')')
  365.             parens--;
  366.          j++;
  367.       }
  368.  
  369.       while (isspace(ins[j]))
  370.          j++;
  371.  
  372.       if (parens && ins[j] != ';')           /* parens are unbalanced */
  373.          /* get following lines to make determination */
  374.          while (fgets(lins, LINE_LENGTH, fptr)) {
  375.             linecnt++;
  376.             i = 0;
  377.             while (lins[i] != ';' && lins[i] && parens) {
  378.                if (lins[i] == '(')
  379.                   parens++;
  380.                if (lins[i] == ')')
  381.                   parens--;
  382.                i++;
  383.             }     
  384.             if (!parens || lins[i] == ';') {
  385.                while (isspace(lins[i]))
  386.                   i++;
  387.                break;
  388.             }
  389.          }
  390.  
  391.       if (parens)
  392.          return FALSE;
  393.  
  394.       if (!linecnt) {
  395.          if (ins[j] == ',' || ins[j] == ';')        /* extern or prototype */
  396.             return FALSE;
  397.       } 
  398.       else
  399.          if (lins[i] == ',' || lins[i] == ';')     /* extern or prototype */
  400.             return FALSE;
  401.  
  402.       i = 0;    
  403.       while (ins[n])
  404.          name[i++] = ins[n++];
  405.    } 
  406.    else {
  407.       i = 0;                     /* function call within function */
  408.       while (isalnum(ins[n]) || (ins[n] == '_'))
  409.          name[i++] = ins[n++];
  410.    }
  411.    name[i] = NULL;
  412.    comout(name);   /* remove comment from name string */
  413.    if (strcmp(name,"if") && strcmp(name,"for") &&
  414.        strcmp(name,"while") && strcmp(name,"switch") &&
  415.        strcmp(name,"return"))
  416.       return TRUE;
  417.  
  418.    return FALSE;
  419. }
  420.  
  421. /**********************************************************************/
  422.  
  423. /* terminate string at comment */
  424.  
  425. void comout(s)
  426. char *s;
  427. {
  428.    char c;
  429.  
  430.    while (c = *s++)
  431.       if (c == '/')
  432.          if (*s == '*') {
  433.             *(s - 1) = '\n';
  434.             *s = NULL;
  435.             break;
  436.          }
  437. }
  438.  
  439. /**********************************************************************/
  440.  
  441. /* display module name with indentation according to { level */
  442.  
  443. void modname()
  444. {
  445.    int i, j, k;
  446.    char temps[255], final[255];
  447.    char sep[] =
  448.        "********************************************************************";
  449.    void comout(), prt_hdr();
  450.  
  451.    if (!level) {
  452.       comout(ins);
  453.       if (function) {
  454.          sprintf(temps, "%-12s :%4u: %-s", filename, linenum, ins);
  455.          for (i = 0; i < 20; i++)
  456.             final[i] = temps[i];
  457.          j = i;
  458.          while (isspace(temps[i]))
  459.             i++;
  460.          k = i;
  461.          while (temps[k] && temps[k] != '(' && temps[k] != '*') {
  462.             while (temps[k])
  463.                if (!isspace(temps[k]) && (temps [k] != '('))
  464.                   k++;
  465.                else
  466.                   break;
  467.             while (isspace(temps[k]))
  468.                k++;
  469.             if (temps[k] != '(' )
  470.                i = k;
  471.          }
  472.          if (temps[k] == '*')
  473.             j--;
  474.          while (temps[i])
  475.             final[j++] =temps[i++];
  476.          final[j] = NULL;
  477.          printf("%s",final);
  478.       } 
  479.       else {
  480.          printf("\n\n");
  481.          if ((lpp += 2) >= PAGE_LENGTH)
  482.             prt_hdr();
  483.          printf("%s\n\n %4u: %s", sep, linenum, ins);
  484.          if ((lpp += 3) >= PAGE_LENGTH)
  485.             prt_hdr();
  486.       }
  487.    } 
  488.    else {
  489.       printf("\n %4u: ", linenum);
  490.       for (j=0; j < level; ++j)
  491.          printf("|  ");
  492.       printf("%s()",name);
  493.       if ((lpp++) >= PAGE_LENGTH)
  494.          prt_hdr();
  495.    }
  496.  
  497. }
  498.  
  499. /**********************************************************************/
  500.  
  501. /* print page header */
  502.  
  503. void prt_hdr(void)
  504.  
  505. {
  506.    if (pageno++)
  507.       printf("\f");
  508.    printf("CFLOW of: %s                    ", filename);
  509.    printf(" Date:%d/%d/%02d %02d:%02d:%02d", today.da_mon, today.da_day,
  510.    today.da_year, now.ti_hour, now.ti_min, now.ti_sec);
  511.    printf(" Page: %d\n\n", pageno);
  512.    lpp = 2;
  513. }
  514.  
  515. /**********************************************************************/
  516.