home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / DOS / PROGRAM / C / CFLOW / CFLOW.C next >
Text File  |  1993-12-01  |  27KB  |  1,205 lines

  1. /*
  2. **   CFLOW.C : find module call structure of c program
  3. **   refer to cflow.doc for how to use
  4. **
  5. **                     Mark Ellington
  6. **                    05-27-84
  7. **
  8. **   Converted to MS-DOS 2 and C86, adding the following features:
  9. **
  10. **    1.  filename wildcard support
  11. **    2.  -l flag to include line numbers in output
  12. **    3.  -f flag to include file names in output
  13. **    4.  #include support (with -h flag, same as C86 V2.20H)
  14. **    5.  -x flag to generate input for CFLOWX
  15. **    6.  #define macro() support
  16. **    7.  -t flag to change to '\t' for indentation
  17. **    8.  -s flag to allow specification of number of indentation spaces
  18. **           (default is 4 spaces)
  19. **
  20. **                    Larry Steeger
  21. **                    06-12-85
  22. */
  23.  
  24. #include <stdio.h>        /* C86 header                */
  25.  
  26. #define    VOID int
  27.  
  28. /*    external functions    */
  29.  
  30. extern    VOID abort();
  31. extern    char *alloc();
  32. extern    VOID exit();
  33. extern    int fclose();
  34. extern    unsigned char *filewdir();
  35. extern    FILE *fopen();
  36. extern    VOID fprintf();
  37. extern    int fputs();
  38. extern    VOID free();
  39. extern    int isalnum();
  40. extern    int isdigit();
  41. extern    int isspace();
  42. extern    char *lower();
  43. extern    char *makefile();
  44. extern    char *makefnam();
  45. extern    char *makepath();
  46. extern    char *realloc();
  47. extern    VOID setmem();
  48. extern    VOID sprintf();
  49. extern    char *strcat();
  50. extern    unsigned char *strchr();
  51. extern    char *strcpy();
  52. extern    unsigned strlen();
  53. extern    int strncmp();
  54. extern    char *strncpy();
  55. extern    int tolower();
  56.  
  57. #include "cflowx.h"        /* CFLOW/CFLOWX header            */
  58.  
  59. #define    VERSION    85
  60. #define    RELEASE    06
  61. #define    MODIFIC    20
  62.  
  63. #define    outinfo(S) fputs(S,stdout)
  64.  
  65. /*    display CFLOW logo                        */
  66.  
  67. outlogo()
  68. {
  69.     outinfo("\nCFLOW --> function declarations and calls in C source");
  70.     outinfo("\nby Mark Ellington");
  71.     fprintf(stdout,
  72.         "\n[V%02d.%02d.%02d for C86 by Lawrence R. Steeger]\n",
  73.         VERSION, RELEASE, MODIFIC
  74.         );
  75. }
  76.  
  77. /*    CFLOW usage help                        */
  78.  
  79. outhelp()
  80. {
  81.     outinfo("\n  usage: cflow ");
  82.     outinfo("[-[lft]|[x]] [-hsystem[,project]] ");
  83.     outinfo("[input1[..inputn]] [>output]\n");
  84.     outinfo("\n  flags: -hsystem[,project]");
  85.     outinfo("\n              #include drive/pathname specification");
  86.     outinfo("\n              (usage: C86 V2.20H)");
  87.     outinfo("\n         -l   include line numbers in output");
  88.     outinfo("\n         -f   include file names in output");
  89.     outinfo("\n         -sn  number of indentation spaces");
  90.     outinfo("\n         -t   tabs rather than spaces for indentation");
  91.     outinfo("\n         -x   generate input for CFLOWX\n");
  92.     outinfo("\ndefaults:     cflow -s4 [input] >stdout");
  93. }
  94.  
  95. typedef    struct _cflow {        /* recursive execution structure    */
  96.  
  97.     struct _cflow *_chain;    /* previous CFLOW structure        */
  98.  
  99.     int _fnmbr,        /* current file name index        */
  100.         _level,        /* level of open "{"s or #includes    */
  101.         _prevchar,        /* previous character in input buffer    */
  102.         _curchar,        /* current character in input buffer
  103.                 ** array subscript
  104.                 */
  105.         _curline,        /* current line in input dataset    */
  106.         _define,        /* #define flag                */
  107.         _defdcl;        /* name declaration offset        */
  108.  
  109.     unsigned char _delimit,    /* #include file name delimiter        */
  110.               *_defname,/* defined name buffer            */
  111.               *_name,    /* module name buffer            */
  112.               *_ins,    /* source input line buffer        */
  113.               *_fname,    /* source file name buffer        */
  114.               *_fpname;    /* source file/pathname buffer        */
  115.  
  116.     FILE *_fptr;        /* input file pointer            */
  117.  
  118.     } CFLOW;
  119.  
  120. /*    useability macros for CFLOW structure elements            */
  121.  
  122. #define    chain cflowp->_chain
  123. #define    fnmbr cflowp->_fnmbr
  124. #define    level cflowp->_level
  125. #define prevchar cflowp->_prevchar
  126. #define    curchar cflowp->_curchar
  127. #define    curline cflowp->_curline
  128. #define    define cflowp->_define
  129. #define    defdcl cflowp->_defdcl
  130. #define    delimit cflowp->_delimit
  131. #define    defname cflowp->_defname
  132. #define    name cflowp->_name
  133. #define    ins cflowp->_ins
  134. #define    fname cflowp->_fname
  135. #define    fpname cflowp->_fpname
  136. #define    fptr cflowp->_fptr
  137.  
  138. /*    runtime flags                            */
  139.  
  140. static    int hflag = FALSE,        /* -h  #include drive/pathname    */
  141.         lflag = FALSE,        /* -l  show line numbers    */
  142.         fflag = FALSE,        /* -f  show file names        */
  143.         sflag = FALSE,        /* -s  space indentation count    */
  144.         tflag = FALSE,        /* -t  tab indentation flag    */
  145.         xflag = FALSE;        /* -x  generate CFLOWX input    */
  146.  
  147. static    int fnumber = 0,        /* C source file counter    */
  148.         flevel = 0,            /* C source file level        */
  149.         mnumber = 0;        /* C source file main counter    */
  150.  
  151. static    unsigned char *filepath = NULL,    /* default file/path name    */
  152.               *hsystem = NULL,    /* -hsystem specification    */
  153.                   *hproject = NULL,    /* -h,project specification    */
  154.               *tab = "    ";    /* -t indentation        */
  155.  
  156. static    unsigned char newLine[] = {"\n"};
  157.  
  158. static    CFLOW *cflowp = NULL;        /* current CFLOW execution ptr    */
  159.  
  160. /*    mainline                            */
  161.  
  162. main(argc,argv)
  163. int argc;
  164. unsigned char * argv[];
  165. {
  166.     unsigned char *fp,
  167.               *pp;        /* temporary file/path pointer    */
  168.  
  169.     int fcount,            /* C source file counter    */
  170.         i,
  171.         j;
  172.  
  173.     if (argc < 2) {            /* display CFLOW help        */
  174.  
  175.         outlogo();
  176.         outhelp();
  177.                 exit(1);
  178.     }
  179.  
  180.     cflowp = alloc(sizeof(CFLOW));    /* 1st execution structure    */
  181.  
  182.     name = alloc(MAXBUF);        /* module name buffer        */
  183.     ins = alloc(MAXBUF);        /* input line buffer        */
  184.     fname = alloc(MAXPATH);        /* current file name        */
  185.     fpname = alloc(MAXPATH);    /* current file/path name    */
  186.  
  187.     filepath = alloc(1);        /* dummy file/path name        */
  188.     *filepath = EOS;
  189.  
  190.     for (i=1; i < argc; i++) {    /* process all flags        */
  191.         if (*argv[i] == '-') {
  192.             flags(argv[i]);
  193.             for (j = i--, --argc; j < argc; j++)
  194.                 argv[j] = argv[j+1];
  195.         }
  196.     }
  197.  
  198.     if (!xflag) outlogo();        /* display CFLOW logo        */
  199.  
  200.     if (hsystem != NULL)        /* display -h system prefix    */
  201.         if (*hsystem)
  202.             output(HDRSYST, hsystem);
  203.  
  204.     if (hproject != NULL)        /* display -h project prefix    */
  205.         if (*hproject)
  206.             output(HDRPROJ, hproject);
  207.  
  208.     for (i=1; i < argc; i++) {    /* process all files        */
  209.         if (*argv[i]) {
  210.             fnmbr = mnumber++;
  211.             strcpy(fname, argv[i]);    /* get file name    */
  212.             lower(fname);
  213.  
  214.             free(filepath);        /* get file/path name    */
  215.             filepath = makepath(fname);
  216.  
  217.             if ((strchr(fname, '*') != NULL) /* wildcards    */
  218.             ||  (strchr(fname, '?') != NULL)) {
  219.  
  220.                 /*    process all matching file names    */
  221.  
  222.                 fcount = 0;
  223.                 while ((fp = filewdir(argv[i],0x00)) != NULL) {
  224.  
  225.                     if (!fcount) {
  226.                         pp = makepath(fname);
  227.                         output(WILDPTH, pp);
  228.                         free(pp);
  229.                         pp = makefile(fname);
  230.                         output(WILDNME, pp);
  231.                         free(pp);
  232.                     }
  233.  
  234.                     ++fcount;
  235.                     lower(fp);
  236.                     strcpy(fname,fp);
  237.                     makefnam(fp, filepath, fpname);
  238.                     flevel = level = 0;
  239.                     modules();
  240.                     free(fp);
  241.                 }
  242.  
  243.                 if (!fcount) output(WILDNF, fname);
  244.             }
  245.             else {                /* no wildcards    */
  246.                 strcpy(fpname, fname);
  247.                 strcpy(fname, (pp=makefile(fname)));
  248.                 free(pp);
  249.                 flevel = level = 0;
  250.                 modules();
  251.             }
  252.         }
  253.     }
  254.     exit(0);
  255. }
  256.  
  257. /*    process command line flags                    */
  258.  
  259. int flags(flag)
  260. unsigned char *flag;
  261. {
  262.     unsigned char *hp;
  263.  
  264.     int i;
  265.  
  266.     for (i=1; i < strlen(flag); i++)
  267.         switch (tolower(flag[i])) {
  268.  
  269.         case 'h':        /* -h header specifications    */
  270.             hflag = TRUE;
  271.             i++;
  272.  
  273.             if (hsystem != NULL)
  274.                 free(hsystem);
  275.             if ((hp = strchr(&flag[i], ',')) != NULL)
  276.                 *hp++ = EOS;
  277.             hsystem = alloc((strlen(&flag[i]) + 1));
  278.             strcpy(hsystem, lower(&flag[i]));
  279.  
  280.             if (hp) {
  281.                 if (hproject != NULL)
  282.                     free(hproject);
  283.                 hproject = alloc((strlen(hp) + 1));
  284.                 strcpy(hproject, lower(hp));
  285.             }
  286.  
  287.             i=strlen(flag); /* force break in for loop    */
  288.             break;
  289.  
  290.         case 'l':        /* -l include line numbers    */
  291.             lflag = TRUE;
  292.             break;
  293.  
  294.         case 'f':        /* -f include file names    */
  295.             fflag = TRUE;
  296.             break;
  297.  
  298.         case 's':        /* -s spaces for indentation    */
  299.             if (tflag) {
  300.                 fprintf(stdout,
  301.                     "\n-s is mutually exclusive with -t");
  302.                 outhelp();
  303.                 exit(1);
  304.             }
  305.             if (!isdigit(flag[i+1])) {    /* -s only !    */
  306.  
  307.                 /*  note: -s  implies default        */
  308.  
  309.                 sflag = strlen(tab);
  310.                 break;
  311.             }
  312.             sflag = 0;
  313.             while (isdigit(flag[++i]))
  314.                 sflag = (sflag * 10) + ((int)flag[i] - '0');
  315.             --i;
  316.  
  317.             if (sflag) {
  318.                 tab = alloc(sflag + 1);
  319.                 setmem(tab, sflag, ' ');
  320.                 break;
  321.             }
  322.  
  323.         /*    note:    -s0 implies -t                */
  324.  
  325.         case 't':        /* -t tabs for indentation    */
  326.             if (sflag) {
  327.                 fprintf(stdout,
  328.                     "\n-t is mutually exclusive with -s");
  329.                 outhelp();
  330.                 exit(1);
  331.             }
  332.             tflag = TRUE;
  333.             tab = "\t";
  334.             break;
  335.  
  336.         case 'x':        /* -x generate CFLOWX file    */
  337.             xflag = TRUE;
  338.             break;
  339.  
  340.         default:
  341.             fprintf(stdout, "\nUnknown flag: \"%c\"", flag[i]);
  342.             outhelp();
  343.             exit(1);
  344.         }
  345.     flag[0] = EOS;            /* clear flag            */
  346. }
  347.  
  348. /*    find function declarations and calls                */
  349.  
  350. modules()
  351. {
  352.     int breakc,        /* comment/quotes break character    */
  353.         decl,        /* module declaration line flag        */
  354.         header,        /* in function header (before 1st '{')    */
  355.         j,            /* loop index                */
  356.         lastlin,        /* last line of file flag        */
  357.         modname();        /* module name extractor        */
  358.  
  359.     unsigned char c,        /* current input character    */
  360.               *pp;        /* temporary path name pointer    */
  361.  
  362.     fnmbr = fnumber++;    /* set & increment C source file number    */
  363.  
  364.     /*    the following switch() provides -h flag support
  365.     **    as documented for the C86 V2.20H -h flag.
  366.     */
  367.  
  368.     switch (delimit) {    /* #include/command line file opens    */
  369.  
  370.         case '"':        /* #include "filename"        */
  371.             if (*filepath) {
  372.                 fpname =
  373.                 alloc((strlen(filepath) + strlen(fname) + 1));
  374.                 strcpy(fpname, filepath);
  375.                 strcat(fpname, fname);
  376.             }
  377.             else {
  378.                 fpname = alloc((strlen(fname) + 1));
  379.                 strcpy(fpname, fname);
  380.             }
  381.             if ((fptr = fopen(fpname, "r+")) != NULL) break;
  382.             free(fpname);
  383.  
  384.         case '>':        /* #include <filename>        */
  385.             if (hproject != NULL) {
  386.                 if (*hproject) {
  387.                 fpname =
  388.                 alloc((strlen(hproject) + strlen(fname) + 1));
  389.                 strcpy(fpname, hproject);
  390.                 strcat(fpname, fname);
  391.                 if ((fptr=fopen(fpname,"r+")) != NULL) break;
  392.                 free(fpname);
  393.                 }
  394.             }
  395.  
  396.             if (hsystem != NULL) {
  397.                 if (*hsystem) {
  398.                 fpname =
  399.                 alloc((strlen(hsystem) + strlen(fname) + 1));
  400.                 strcpy(fpname, hsystem);
  401.                 strcat(fpname, fname);
  402.                 if ((fptr=fopen(fpname,"r+")) != NULL) break;
  403.                 free(fpname);
  404.                 }
  405.             }
  406.  
  407.             if (hflag || delimit != '"') {
  408.                 output(FILEERR, fname);
  409.                 return;
  410.             }
  411.  
  412.             /*    #include "filename" without -h        */
  413.  
  414.             fpname = alloc((strlen(fname) + 1));
  415.             strcpy(fpname, fname);
  416.  
  417.         default:        /* command line filename    */
  418.             if ((fptr = fopen(fpname, "r+")) == NULL) {
  419.                 output(FILEERR, fpname);
  420.                 return;
  421.             }
  422.             break;
  423.     }
  424.  
  425.     /*    initialize flags/tokens                    */
  426.  
  427.     breakc = prevchar = lastlin = header = FALSE;
  428.  
  429.     curline = 0;            /* 1st character in buffer    */
  430.  
  431.     /*    identify C source/#include file name            */
  432.  
  433.     pp = makepath(fpname);        /* get path name        */
  434.  
  435.     output(FILEPTH, pp);        /* show C source path name    */
  436.     output(FILENME, fname);        /* show C source file name    */
  437.  
  438.     free(pp);            /* free path name        */
  439.  
  440.     do {
  441.         if (lastlin = fgets())    /* read a line of source    */
  442.             ++curline;
  443.  
  444.         define = decl = FALSE;    /* assume nothing        */
  445.         curchar = 0;        /* start of line        */
  446.         defname = NULL;        /* clear defined name pointer    */
  447.  
  448.         if (prevchar != '\\')    /* reset previous if not \    */
  449.             prevchar = FALSE;
  450.  
  451.         while (ins[curchar]) {    /* process all characters    */
  452.  
  453.             if (breakc) {    /* comment/quote in progress    */
  454.                 if (skipold(&breakc))
  455.                     break;
  456.             }
  457.                 
  458.             switch (ins[curchar]) {
  459.  
  460.             case '\"':    /* start quoted string        */
  461.             case '\'':    /* start quoted constant    */
  462.             case '/' :    /* start comment ?        */
  463.                 skipnew(&breakc);
  464.                 break;
  465.  
  466.             case '#':    /* pre-processor tokens        */
  467.                 if (includes())        /* #include    */
  468.                     break;
  469.                 if (defines())        /* #define    */
  470.                     break;
  471.                 goto notsupp;        /* unsupported    */
  472.  
  473.             case '{':    /* compound statement start    */
  474.                 level++;
  475.                 header = FALSE;
  476.                 break;
  477.  
  478.             case '}':    /* compound statement end    */
  479.                 level--;
  480.                 if (level < 0) {    /* nest error    */
  481.                     output(NESTERR, fpname);
  482.                     level = 0;
  483.                 }
  484.                 break;
  485.  
  486.             case '(':    /* function/macro call/declare    */
  487.  
  488.                 if (define) {    /* #define macro()    */
  489.                     if (!lookmac(curchar))
  490.                         goto notfunc;
  491.                     macname();    /* macro name    */
  492.                     break;
  493.                 }
  494.  
  495.                 if (!lookmod(curchar))    /* module name    */
  496.                     goto notfunc;
  497.                 j = modname();
  498.  
  499.                 if (!j) goto notfunc;    /* not function    */
  500.     
  501.                 decl = TRUE;        /* function    */
  502.  
  503.                 if (j == 2)        /* declaration    */
  504.                     header = TRUE;
  505.  
  506.                 break;
  507.  
  508.             notsupp:
  509.             notfunc:
  510.               default:        /* all other characters */
  511.                 break;
  512.             }
  513.  
  514.             if (ins[curchar]) prevchar = (int)ins[curchar++];
  515.         }
  516.  
  517.         if (header && !decl && !breakc && !define) {
  518.  
  519.             /* function declaration argument declarations    */
  520.  
  521.             comout(ins);
  522.             if (ins[0]) output(FUNCARG, ins);
  523.         }
  524.  
  525.         if (defname != NULL) free(defname);
  526.  
  527.     } while (lastlin);        /* = FALSE if last line        */
  528.  
  529.     fclose(fptr);
  530.  
  531.     if (!delimit) output(NOFUNC, newLine);
  532.  
  533.     return;
  534. }
  535.  
  536. /*    process in progress comments and quoted character or strings    */
  537.  
  538. int skipold(breakc)
  539. int *breakc;
  540. {
  541.     while (ins[curchar] && *breakc) { /* !EOS & break in progress    */
  542.  
  543.         switch (ins[curchar]) {
  544.  
  545.         case '\\':            /* escape sequence    */
  546.             if (ins[(curchar+1)])
  547.                 ++curchar;    /* skip a character    */
  548.             break;
  549.  
  550.         case '\'':            /* end quoted character    */
  551.             if (*breakc != '\'') goto notbreak;
  552.             *breakc = FALSE;
  553.             break;
  554.  
  555.         case '"':            /* end quoted string    */
  556.             if (*breakc != '"') goto notbreak;
  557.             *breakc = FALSE;
  558.             break;
  559.  
  560.         case '*':            /* end comment ?    */
  561.             if (*breakc != '/') goto notbreak;
  562.             if (ins[(curchar+1)] == '/') {
  563.                 ++curchar;
  564.                 *breakc = FALSE;
  565.                 break;
  566.             }
  567.  
  568.         notbreak:
  569.         default:            /* other characters    */
  570.             break;
  571.         }
  572.  
  573.         if (ins[curchar]) prevchar = (int)ins[curchar++];
  574.     }
  575.  
  576.     return (*breakc);
  577. }
  578.  
  579. /*    start new comment or quoted character/string process        */
  580.  
  581. int skipnew(breakc)
  582. int *breakc;
  583. {
  584.     switch (ins[curchar]) {        /* not EOS            */
  585.  
  586.     case '/':            /* start comment ?        */
  587.         if (ins[++curchar] != '*') {
  588.             break;
  589.         }
  590.  
  591.         *breakc = '/';        /* comment started        */
  592.  
  593.         if (ins[curchar]) prevchar = (int)ins[curchar];
  594.         break;
  595.  
  596.     case '\'':            /* start quoted constant    */
  597.     case '"':            /* start quoted string        */
  598.         *breakc = (int)ins[curchar];
  599.         break;
  600.  
  601.     default:            /* unknown ?            */
  602.         break;
  603.     }
  604.  
  605.     return (*breakc);
  606. }
  607.  
  608. /*    process #include                        */
  609.  
  610. includes()
  611. {
  612.     unsigned char delim, *fp;
  613.     int filecur, fnamel;
  614.     CFLOW *cflows;
  615.  
  616.     filecur = curchar;
  617.  
  618.     if (strncmp("#include", &ins[filecur], 8) != 0)
  619.         return (FALSE);            /* not #include        */
  620.  
  621.     for (filecur += 8; ins[filecur]; filecur++)
  622.         if (!isspace(ins[filecur])) break;
  623.  
  624.     if (!ins[filecur]) return (FALSE);    /* #include.. only ?!    */
  625.  
  626.     delim = ins[filecur++];            /* file name delimiter    */
  627.  
  628.     if (delim != '\"' && delim != '<')
  629.         return (FALSE);            /* #include.. what ?!    */
  630.  
  631.     if (delim == '<') delim = '>';        /* #include <...>    */
  632.  
  633.     if ((fp = strchr(&ins[filecur], delim)) == NULL)
  634.         return (FALSE);            /* #include.. what ?!    */
  635.  
  636.     if ((fnamel = (fp - &ins[filecur])) == 0)
  637.         return (FALSE);            /* #include.. what ?!    */
  638.  
  639.     fp = alloc(++fnamel);
  640.     lower(strncpy(fp, &ins[filecur], (fnamel-1)));
  641.  
  642.     filecur += fnamel;        /* skip file name + 1        */
  643.  
  644.     cflows = cflowp;        /* current CFLOW ptr        */
  645.  
  646.     cflowp = alloc(sizeof(CFLOW));    /* allocate new CFLOW        */
  647.  
  648.     chain = cflows;            /* build new CFLOW        */
  649.     name = alloc(MAXBUF);
  650.     ins = alloc(MAXBUF);
  651.     fname = fp;
  652.     if ((strchr(fp, ':') != NULL)    /* no -h if drive/path used    */
  653.     ||  (strchr(fp, '\\') != NULL)) {
  654.         delimit = 1;        /* include with drive/path    */
  655.         fpname = alloc((strlen(fp) + 1));
  656.         strcpy(fpname, fp);    /* fpname = fname        */
  657.         fname = makefile(fname);
  658.         free(fp);
  659.     }
  660.     else {
  661.         delimit = delim;
  662.         fpname = NULL;        /* dynamic fpname at open    */
  663.     }
  664.     fnmbr = cflows->_fnmbr + 1;
  665.     flevel++;
  666.     level = 0;
  667.  
  668.     modules();            /* recursive call        */
  669.  
  670.     --flevel;
  671.  
  672.     cflows = chain;            /* dechain CFLOW structure    */
  673.     free(name);
  674.     free(ins);
  675.     free(fname);
  676.     if (fpname != NULL) free(fpname);
  677.     free((char *)cflowp);
  678.  
  679.     cflowp = cflows;        /* restore previous CFLOW    */
  680.  
  681.     curchar = filecur;        /* update buffer index        */
  682. }
  683.  
  684. /*    process #defines                        */
  685.  
  686. int defines()
  687. {
  688.     if (strncmp("define", &ins[(curchar+1)], 6) != 0) {
  689.         define = 0;
  690.         return (FALSE);        /* not #define            */
  691.     }
  692.  
  693.     define = 1;            /* #define 1st level        */
  694.     curchar += 6;            /* skip #define            */
  695.     return (TRUE);            /* #define found        */
  696. }
  697.  
  698. /*    look back from position n in string.  called with n indicating '('.
  699.     determine macro name.
  700. */
  701.  
  702. int lookmac(n)
  703. int n;
  704. {
  705.     int i;
  706.  
  707.     i = 0;
  708.  
  709.     if (n) {            /* ignore white space        */
  710.         --n;
  711.         while (isspace(ins[n])) --n;
  712.     }
  713.  
  714.     if (isalnum(ins[n])) {        /* find beginning of macro name */
  715.  
  716.         while (n && isalnum(ins[n-1])) --n;
  717.  
  718.         /*    save name
  719.             include definition if macro declaration
  720.         */
  721.  
  722.         if (define < 2) defdcl = n;    /* macro name offset    */
  723.  
  724.         while (isalnum(ins[n]))        /* macro definition    */
  725.             name[i++] = ins[n++];
  726.     }
  727.  
  728.     name[i] = EOS;
  729.  
  730.     if (i) {
  731.         comout(name);    /* remove any comment from name string    */
  732.         if (define < 2) {        /* save macro name    */
  733.             defname = alloc((strlen(name) + 1));
  734.             strcpy(defname, name);
  735.         }
  736.         return (TRUE);            /* macro name found    */
  737.     }
  738.     else
  739.         return (FALSE);            /* macro name not found    */
  740. }
  741.  
  742. /*    look back from position n in string.  called with n indicating '('.
  743.     determine function name.
  744. */
  745.  
  746. int lookmod(n)
  747. int n;
  748. {
  749.     int i, j, k;
  750.  
  751.     i = 0;
  752.  
  753.     if (n) {            /* ignore white space        */
  754.         --n;
  755.         while (isspace(ins[n])) --n;
  756.     }
  757.  
  758.     if (isalnum(ins[n])) {        /* find beginning of name    */
  759.  
  760.         while (n && isalnum(ins[n-1])) --n;
  761.  
  762.         /*     save name
  763.             include variable declarations if module declaration
  764.         */
  765.  
  766.         if (level == 0) {        /* function declaration */
  767.             defdcl = n;
  768.             j = 0;
  769.             while (ins[j])        /* copy full definition    */
  770.                 name[i++] = ins[j++];
  771.             defname = alloc((strlen(&ins[defdcl]) + 1));
  772.             j = defdcl;
  773.             k = 0;
  774.             while (isalnum(ins[j]))    /* copy name only    */
  775.                 defname[k++] = ins[j++];
  776.             defname[k] = EOS;
  777.         }
  778.         else                /* function call    */
  779.             while (isalnum(ins[n]))
  780.                 name[i++] = ins[n++];
  781.     }
  782.  
  783.     name[i] = EOS;
  784.  
  785.     if (i) {
  786.         comout(name);    /* remove any comment from name string    */
  787.         return (TRUE);    /* module name found            */
  788.     }
  789.     else
  790.         return (FALSE);    /* module name not found        */
  791. }
  792.  
  793. /*    terminate string at comment, stripping trailing white space    */
  794.  
  795. comout(s)
  796. unsigned char *s;
  797. {
  798.     unsigned char c;
  799.  
  800.     while (c = *s++) {
  801.         if (c == '\n') {
  802.             *--s = EOS;
  803.             break;
  804.         }
  805.         if (c == '/')
  806.             if (*s == '*') {
  807.                 *--s = EOS;
  808.                 break;
  809.             }
  810.     }
  811.     for (--s; isspace(*s);) *s-- = EOS;
  812.     if (*s == '{') {
  813.         *s = EOS;
  814.         for (--s; isspace(*s);) *s-- = EOS;
  815.     }
  816. }
  817.  
  818. /*    display macro name                        */
  819.  
  820. macname()
  821. {
  822.     char *cp;
  823.  
  824.         if (define < 2) {            /* macro start        */
  825.         define++;            /* update macro level    */
  826.     }
  827.     else {
  828.         output(MACNME, defname);    /* macro name        */
  829.         cp = alloc((strlen(&ins[defdcl]) + 1));
  830.         strcpy(cp, &ins[defdcl]);
  831.         comout(cp);
  832.         output(MACDCL, cp);        /* macro definition    */
  833.         output(MACEQU, name);        /* macro operand    */
  834.         free(cp);
  835.     }
  836. }
  837.  
  838. /*    display module name with indentation according to { level
  839.  
  840.     returns 0 if not module,
  841.         1 if call within module,
  842.         2 if module declaration
  843. */
  844.  
  845. modname()
  846. {
  847.     char *cp;
  848.     int i, result;
  849.  
  850.     if (unreserved() && !external()) { /* builtin/extern entries    */
  851.             if (level == 0) {
  852.             output(FUNCNME, defname);/* module name        */
  853.             output(FUNCDCL, name);     /* module function    */
  854.             return (2);
  855.                 }
  856.         else {
  857.             output(FUNCREF, name);     /* module reference    */
  858.             return (1);
  859.         }
  860.         }
  861.     return (0);
  862. }
  863.  
  864. /*    generate output based upon type of data and execution flags    */
  865.  
  866. output(type, string, operand)   
  867. int type;
  868. unsigned char *string, *operand;
  869. {
  870.     char *cptype;
  871.  
  872.     unsigned char outbuf[MAXBUF],
  873.               *filter();
  874.  
  875.     int j, slevel;
  876.  
  877.     slevel = level;            /* save current level        */
  878.  
  879.     switch (type) {            /* generate output strings    */
  880.  
  881.     case NOFUNC:
  882.         if (strchr(string, '%') != NULL) {
  883.             sprintf(outbuf, string, operand);
  884.             cptype = outbuf;
  885.         }
  886.         else    cptype = string;
  887.         break;
  888.  
  889.     case FUNCREF:
  890.         strcpy(outbuf, tab);
  891.         for (j=0; j < level; ++j)
  892.             strcat(outbuf, tab);
  893.         sprintf(&outbuf[strlen(outbuf)], "%s()", string);
  894.         cptype = outbuf;
  895.         break;
  896.  
  897.     case FUNCARG:
  898.         cptype = " * %s";
  899.         string = filter(string);
  900.         break;
  901.  
  902.     case FUNCDCL:
  903.         cptype = "** %s";
  904.         string = filter(string);
  905.         break;
  906.  
  907.     case MACEQU:
  908.         cptype = " = %s()";
  909.         string = filter(string);
  910.         break;
  911.  
  912.     case MACDCL:
  913.         cptype = "== %s";
  914.         string = filter(string);
  915.         break;
  916.  
  917.     case FILENME:
  918.         if (flevel) {
  919.             cptype = "           C Include: %s";
  920.             level = flevel;
  921.         }
  922.         else    cptype = "            C Source: %s";
  923.         break;
  924.  
  925.     case FILEPTH:
  926.         if (*string)
  927.             if (flevel) {
  928.                 cptype = "C Include Drive/Path: %s";
  929.                 level = flevel;
  930.             }
  931.             else    cptype = " C Source Drive/Path: %s";
  932.         else    cptype = "";
  933.         break;
  934.  
  935.     case HDRSYST:
  936.         cptype = "     C System Header: %s";
  937.         break;
  938.  
  939.     case HDRPROJ:
  940.         cptype = "    C Project Header: %s";
  941.         break;
  942.  
  943.     case WILDPTH:
  944.         if (*string)
  945.             cptype = " WildCard Drive/Path: %s";
  946.         else    cptype = "";
  947.         break;
  948.  
  949.     case WILDNME:
  950.         cptype = "      WildCard Files: %s";
  951.         break;
  952.  
  953.     case WILDNF:
  954.         cptype = "   No Files Matching: %s";
  955.         break;
  956.  
  957.     case FILEERR:
  958.         if (flevel)
  959.             cptype = "Can't Open C Include: %s";
  960.         else    cptype = " Can't Open C Source: %s";
  961.         break;
  962.  
  963.     case NESTERR:
  964.         cptype = "  {..} Nesting Error: %s";
  965.         break;
  966.  
  967.     case MACNME:
  968.     case FUNCNME:
  969.         break;
  970.  
  971.     default:
  972.         fprintf(stderr,
  973.             "\noutput(%d): internal error\n", type);
  974.         exit(1);
  975.     }
  976.  
  977.     if (!xflag) {
  978.         switch (type) {        /* perform spacing for types    */
  979.  
  980.         case FUNCDCL:        /* function declaration        */
  981.         case MACDCL:        /* macro declaration        */
  982.         case WILDPTH:        /* wildcard path name        */
  983.         case FILEPTH:        /* file pathname        */
  984.             fputs(newLine, stdout);
  985.             if (!*cptype) break;
  986.  
  987.         case WILDNME:        /* wildcard specification    */
  988.         case FILENME:        /* C source file name        */
  989.         case FUNCARG:        /* function argument        */
  990.         case FUNCREF:        /* function reference        */
  991.         case MACEQU:        /* macro equate            */
  992.         case NESTERR:        /* nesting error        */
  993.         case FILEERR:        /* file error            */
  994.         case HDRSYST:        /* -h system prefix        */
  995.         case HDRPROJ:        /* -h project prefix        */
  996.         case WILDNF:        /* no files match wildcard    */
  997.             fputs(newLine, stdout);
  998.             break;
  999.  
  1000.         case MACNME:        /* macro name            */
  1001.         case FUNCNME:        /* function name        */
  1002.             return;
  1003.  
  1004.         case NOFUNC:        /* non-function output        */
  1005.         default:
  1006.             break;
  1007.         }
  1008.  
  1009.         if (*cptype) {
  1010.             outhdr(type);        /* generate line header    */
  1011.             fprintf(stdout, cptype, string); /* output line    */
  1012.         }
  1013.     }
  1014.     else {                /* generate CFLOWX output    */
  1015.         if (type) {
  1016.             if (type == FILEERR) {
  1017.                 output(FILEPTH, "", "");
  1018.                 strcpy(outbuf, "* ");
  1019.                 strcat(outbuf, string);
  1020.                 output(FILENME, outbuf, "");
  1021.                 level = slevel;
  1022.                 return;
  1023.             }
  1024.  
  1025.             if (type == WILDNF) {
  1026.                 output(WILDPTH, "", "");
  1027.                 strcpy(outbuf, "# ");
  1028.                 strcat(outbuf, string);
  1029.                 output(WILDNME, outbuf, "");
  1030.                 level = slevel;
  1031.                 return;
  1032.             }
  1033.  
  1034.             fprintf(stdout,
  1035.                 cxref(MAXFLDS),
  1036.                 type,
  1037.                 fnmbr,
  1038.                 level,
  1039.                 curline,
  1040.                 string
  1041.                 );
  1042.         }
  1043.     }
  1044.  
  1045.     level = slevel;            /* restore current level    */
  1046. }
  1047.  
  1048. /*    output line heading                        */
  1049.  
  1050. outhdr(type)
  1051. int type;
  1052. {
  1053.     if (type && curline) {
  1054.         if (fflag) fprintf(stdout, "%s ", fpname);
  1055.         if (lflag) fprintf(stdout, "%5d: ", curline);
  1056.     }
  1057. }
  1058.  
  1059. /*    C string filter for extraneous white space            */
  1060.  
  1061. unsigned char *filter(string)
  1062. unsigned char *string;
  1063. {
  1064.     int j;
  1065.  
  1066.     while (isspace(*string)) ++string;
  1067.  
  1068.     for (j=0; string[j]; j++)
  1069.         if (isspace(string[j])) string[j] = ' ';
  1070.  
  1071.     for (j=0; string[j] && string[(j+1)] != EOS; j++) {
  1072.         if (string[j] == ' ' && string[(j+1)] == ' ') {
  1073.             strcpy(&string[j], &string[(j+1)]);
  1074.             continue;
  1075.         }
  1076.         if (string[j] == ' ' && string[(j+1)] == '(') {
  1077.             strcpy(&string[j], &string[(j+1)]);
  1078.             continue;
  1079.         }
  1080.         if (string[j] == ',' && string[(j+1)] == ' ') {
  1081.             strcpy(&string[(j+1)], &string[(j+2)]);
  1082.             continue;
  1083.         }
  1084.         if (string[j] == '*' && string[(j+1)] == ' ')
  1085.             strcpy(&string[(j+1)], &string[(j+2)]);
  1086.     }
  1087.  
  1088.     return (string);
  1089. }
  1090.  
  1091. /*    test for C reserved words                    */
  1092.  
  1093. unreserved()
  1094. {
  1095.          if (strncmp(name, "return", 6) == 0
  1096.          &&  !iscname(name[6])) return (FALSE);
  1097.     else if (strncmp(name, "if",     2) == 0
  1098.          &&  !iscname(name[2])) return (FALSE);
  1099.     else if (strncmp(name, "while",  5) == 0
  1100.          &&  !iscname(name[5])) return (FALSE);
  1101.     else if (strncmp(name, "for",    3) == 0
  1102.          &&  !iscname(name[3])) return (FALSE);
  1103.     else if (strncmp(name, "switch", 6) == 0
  1104.          &&  !iscname(name[6])) return (FALSE);
  1105.     else if (strncmp(name, "sizeof", 6) == 0
  1106.          &&  !iscname(name[6])) return (FALSE);
  1107.  
  1108.     else return (TRUE);
  1109. }
  1110.  
  1111. /*    detect "extern" function definitions outside of all functions    */
  1112.  
  1113. external()
  1114. {
  1115.     char *cp;
  1116.     int i, rc;
  1117.  
  1118.     if (level) return (FALSE);        /* within a function    */
  1119.  
  1120.     for (i=0; ins[i]; i++) if (isalnum(ins[i])) break;
  1121.  
  1122.     if (ins[i]) {        
  1123.         if (strncmp(&ins[i], "extern", 6) == 0
  1124.             &&  !iscname(ins[6])) return (TRUE);
  1125.         if (strncmp(&ins[i], "typedef", 7) == 0
  1126.         &&  !iscname(ins[7])) return (TRUE);
  1127.     }
  1128.  
  1129.     cp = alloc(strlen(ins));
  1130.     strcpy(cp, ins);
  1131.     comout(cp);
  1132.  
  1133.     if (*cp)
  1134.         if (cp[(strlen(cp)-1)] != ')') {
  1135.             free(cp);
  1136.             return (TRUE);
  1137.         }
  1138.  
  1139.     free(cp);
  1140.     return (FALSE);
  1141. }
  1142.  
  1143. /*    read a line of source                        */
  1144.  
  1145. int fgets()
  1146. {
  1147.     unsigned char *s;
  1148.     int ch, count;
  1149.  
  1150.     s = ins;
  1151.     count = 0;
  1152.  
  1153.     while ((ch = getc(fptr)) != EOF) {
  1154.  
  1155.         buflim(count, MAXBUF);
  1156.         *s++ = (unsigned char)ch;
  1157.         ++count;
  1158.  
  1159.         if (ch == '\n') {
  1160.             buflim(count, MAXBUF);
  1161.             *s = EOS;
  1162.             return (TRUE);        /* not EOF        */
  1163.         }
  1164.     }
  1165.  
  1166.     buflim(count, MAXBUF);
  1167.     *s = EOS;
  1168.     return (FALSE);                /* EOF            */
  1169. }
  1170.  
  1171. /*    test if buffer limit reached                    */
  1172.  
  1173. int buflim(current, limit)
  1174. int current, limit;
  1175. {
  1176.     if (current == limit) {
  1177.         fprintf(stderr,
  1178.             "\nfgets(): line %d in %s has more than %d characters",
  1179.             curline, fpname, MAXBUF);
  1180.         exit(1);
  1181.     }
  1182. }
  1183.  
  1184. /*    determine if character is valid in a C name or label        */
  1185.  
  1186. int iscname(c)
  1187. unsigned char c;
  1188. {
  1189.     if (isalnum(c)) return (TRUE);    /* a-z and A-Z are valid    */
  1190.  
  1191.     switch (c) {            /* plus 4 special characters    */
  1192.  
  1193.     case '_':
  1194.     case '@':
  1195.     case '$':
  1196.     case '#':
  1197.         return (TRUE);
  1198.     default:
  1199.         return (FALSE);
  1200.     }
  1201. }
  1202.  
  1203. /*    end of cflow.c            */
  1204.  
  1205. e