home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / tools / formatte / cpg / cpg.c next >
Text File  |  1987-04-19  |  25KB  |  887 lines

  1. /*Tcpg - c program source listing formatter */
  2. /*F cpg.c **********************************************************
  3.  *
  4.  *                           cpg.c
  5.  *
  6.  *    DESCRIPTION OF FILE CONTENTS:
  7.  *      C source program listing formatter source.
  8.  *
  9.  *  Cpg provides the facility to print out a C language source file
  10.  *  with headers, nesting level indicators, and table of contents.
  11.  *  It makes use of "triggers" for page headings, titles and
  12.  *  subtitles, and pagination.  It also recognizes function
  13.  *    declarations and form feeds and treats them appropriately.
  14.  *
  15.  *  (c) 1985  Steven List
  16.  *            Benetics Corporation
  17.  *            Mountain View, CA
  18.  *            {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
  19.  *
  20.  *******************************************************************/
  21. /*E*/
  22. /*S includes, defines, and globals */
  23. /*P*/
  24. #include <stdio.h>
  25. #include    <ctype.h>
  26. #include    <time.h>
  27.  
  28. #define EQ ==
  29. #define NE !=
  30. #define GT >
  31. #define GE >=
  32. #define LT <
  33. #define LE <=
  34. #define OR ||
  35. #define AND &&
  36.  
  37. #define TRUE 1
  38. #define FALSE 0
  39. #define YES 1
  40. #define NO 0
  41.  
  42. #define SPACE ' '
  43. #define NUL '\0'
  44.  
  45. typedef short   BOOL;
  46.  
  47. #define INULL -32768
  48. #define LNULL -2147483648
  49.  
  50. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  51. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  52. #define ABS(a) ((a) >= 0 ? (a) : -(a))
  53.  
  54. #define LINESINHEAD 6
  55. #define LPP 60
  56. #define MAXWIDTH    130
  57.  
  58. #define notend(ll) ((ll[0] EQ SLASH AND ll[1] EQ STAR AND ll[2] EQ 'E') ? FALSE : TRUE)
  59. #define SLASH   '/'
  60. #define STAR    '*'
  61. #define DQUOTE '"'
  62. #define SQUOTE '\''
  63. #define BSLASH '\\'
  64.  
  65. char    tim_lin[40];
  66. char    *file_name;
  67. char    fh_name[50] = "";
  68. char    fnc_name[40] = "";
  69. char    subttl[70] = "";
  70. char    title[70] = "";
  71. char    tocname[] = "/tmp/toc_XXXXXX";
  72.  
  73. int     nlvl = 0;
  74.  
  75. int     page_line = LPP+1;
  76. int     pageno = 1;
  77.  
  78. int     tabstop = 8;
  79.  
  80. int        infunc = FALSE;
  81. int     logging = 0;
  82.  
  83. int     incomment = FALSE;
  84. int     insquote = FALSE;
  85. int     indquote = FALSE;
  86.  
  87. char    specline = FALSE;
  88.  
  89. FILE    *tocfile;
  90. FILE    *fd;
  91.  
  92. char    *pgm;
  93.  
  94. char    *ReservedWord[]  = { 
  95.      "auto", "bool", "break", "case", "char", "continue",
  96.      "default", "do", "double", "else", "entry", "enum",
  97.      "extern", "float", "for", "goto", "if",
  98.      "int", "long", "register", "return", "short",
  99.      "sizeof", "static", "struct", "switch",
  100.      "typedef", "union", "unsigned", "void", "while",
  101.      NULL };
  102.  
  103. /*S main function */
  104. /*Hmain */
  105. /*E*/
  106.  
  107. main (ac, av)
  108. int     ac;
  109. char    **av;
  110. {
  111.     char    *std_input = "standard input";    /* input file name        */
  112.  
  113.     long    cur_time;                /* place for current raw time    */
  114.  
  115.     long    *time();                /* return raw time from system    */
  116.  
  117.     register int i;                    /* temporary for indexes, etc.    */
  118.  
  119.     struct tm *tim;                    /* return from localtime        */
  120.     struct tm *localtime ();
  121.  
  122.     char    cmdbuf[40];                /* place to format sort command    */
  123.  
  124.     char    *strrchr ();            /* find char from end - rindex    */
  125.  
  126.     extern char *optarg;            /* option argument pointer        */
  127.     extern int   optind;            /* option index                    */
  128.  
  129.     if (pgm = strrchr (pgm, "/")) pgm++;    /* set program name        */
  130.     else pgm = pgm;
  131.  
  132.     while ((i = getopt (ac, av, "l:t:")) NE EOF)
  133.     {
  134.         switch (i)
  135.         {
  136.             case    'l':
  137.                 logging = atoi (optarg);
  138.                 break;
  139.             case    't':
  140.                 tabstop = atoi (optarg);
  141.                 break;
  142.             default:
  143.                 fprintf (stderr,
  144.                     "usage: %s [ -t <tabstop> ] [ files... ]\n",
  145.                         pgm);
  146.         }
  147.     }
  148.  
  149.     /* ------------------------------------------------------------ */
  150.     /* set up the date/time portion of page headings                */
  151.     /* ------------------------------------------------------------ */
  152.  
  153.     time(&cur_time);
  154.  
  155.     tim = localtime (&cur_time);
  156.     sprintf (tim_lin, "Printed: %02d/%02d/%02d at %2d:%02d %s",
  157.         tim->tm_mon + 1, tim->tm_mday, tim->tm_year,
  158.         tim->tm_hour GT 12 ? tim->tm_hour - 12 : tim->tm_hour,
  159.         tim->tm_min,
  160.         tim->tm_hour GE 12 ? "PM" : "AM" );
  161.  
  162.     /* ------------------------------------------------------------ */
  163.     /* create the temporary file for the table of contents          */
  164.     /*   don't bother if output is to a terminal                    */
  165.     /* ------------------------------------------------------------ */
  166.  
  167.     mktemp (tocname);
  168.     if (!isatty (1))
  169.     {
  170.         tocfile = fopen (tocname, "w");
  171.         if (!tocfile)
  172.         {
  173.             fprintf (stderr, "%s: unable to create tocfile %s\n",
  174.                 pgm, tocname);
  175.             exit (2);
  176.         }
  177.     }
  178.  
  179.     /* ------------------------------------------------------------ */
  180.     /* if no file names, read standard input                        */
  181.     /* ------------------------------------------------------------ */
  182.  
  183.     if (optind EQ ac)
  184.     {
  185.         fd = stdin;
  186.         file_name = std_input;
  187.         dofile (fd);
  188.     }
  189.     else
  190.     {
  191.     /* ------------------------------------------------------------ */
  192.     /* process each file named on the command line                  */
  193.     /* ------------------------------------------------------------ */
  194.  
  195.         for (i = optind; i LT ac; i++)
  196.         {
  197.     /* ------------------------------------------------------------ */
  198.     /* special file name `-' is standard input                      */
  199.     /* ------------------------------------------------------------ */
  200.  
  201.             if (strcmp (av[i], "-") EQ 0)
  202.             {
  203.                 fd = stdin;
  204.                 file_name = std_input;
  205.             }
  206.             else
  207.             {
  208.                 fd = fopen (av[i], "r");
  209.                 if (fd EQ NULL)
  210.                 {
  211.                     fprintf (stderr,
  212.                         "cpg: unable to open %s\n", av[i]);
  213.                 }
  214.             }
  215.             if (fd NE NULL)
  216.             {
  217.                 strcpy (fh_name, av[i]);
  218.                 file_name = av[i];
  219.                 dofile (fd);
  220.                 fclose (fd);
  221.             }
  222.         }
  223.     }
  224.  
  225.     fflush (stdout);
  226.  
  227.     /* ------------------------------------------------------------ */
  228.     /* sort and print the table of contents - straight alpha order  */
  229.     /* on function and file name                                    */
  230.     /* ------------------------------------------------------------ */
  231.  
  232.     if (!isatty (1))
  233.     {
  234.         fclose (tocfile);
  235.         sprintf (cmdbuf, "sort +1 -2 +0 -1 -u -o %s %s", tocname, tocname);
  236.         system (cmdbuf);
  237.         tocfile = fopen (tocname, "r");
  238.         if (!tocfile)
  239.         {
  240.             fprintf (stderr, "%s: unable to read tocfile\n", pgm);
  241.             exit (2);
  242.         }
  243.         else
  244.         {
  245.             tocout (tocfile);
  246.             fclose (tocfile);
  247.             if (!logging) unlink (tocname);
  248.         }
  249.     }
  250.  
  251.     fprintf (stdout, "\f");
  252.  
  253.     exit (0);
  254. }
  255. /*Sdofile - process an input file */
  256. /*Hdofile*/
  257. /*E*/
  258. dofile (fd)
  259. FILE    *fd;
  260. {
  261.     register int i;                    /* temporary                    */
  262.  
  263.     int     lineno = 1;                /* line number in current file    */
  264.  
  265.     register char *line;            /* current line pointer            */
  266.  
  267.     char    ibuf[MAXWIDTH];            /* original input line            */
  268.     char    ebuf[MAXWIDTH];            /* line with tabs expanded        */
  269.  
  270.     char    *strrchr ();            /* find char from start - index    */
  271.  
  272.     register char *p;                /* temporary char pointer        */
  273.  
  274.     /* ------------------------------------------------------------ */
  275.     /* initialize the function name to `.' - unknown                */
  276.     /* retrieve the basename portion of the file name               */
  277.     /* ------------------------------------------------------------ */
  278.  
  279.     strcpy (fnc_name, ".");
  280.     if (p = strrchr (fh_name, '/')) p++;
  281.     else p = fh_name;
  282.  
  283.     /* ------------------------------------------------------------ */
  284.     /* if building TOC, add this entry                              */
  285.     /* ------------------------------------------------------------ */
  286.  
  287.     if (!isatty (1))
  288.         fprintf (tocfile,
  289.             "%s %s %d %d\n", p, fnc_name, pageno, lineno);
  290.  
  291.     /* ------------------------------------------------------------ */
  292.     /* if tabs are to be expanded, use the expansion buffer         */
  293.     /* ------------------------------------------------------------ */
  294.  
  295.     if (tabstop) line = ebuf;
  296.     else         line = ibuf;
  297.  
  298.     /* ------------------------------------------------------------ */
  299.     /* process each line in the file, looking for triggers          */
  300.     /* ------------------------------------------------------------ */
  301.  
  302.     while (fgets (ibuf, MAXWIDTH, fd) NE NULL)
  303.     {
  304.         if (logging GE 9) fprintf (stderr, "%s: LOG: %s", pgm, line);
  305.     /* ------------------------------------------------------------ */
  306.     /* expand the input line                                        */
  307.     /* ------------------------------------------------------------ */
  308.  
  309.         expand (ebuf, ibuf);
  310.  
  311.         if (line[0] EQ SLASH AND line[1] EQ STAR)
  312.         {
  313.     /* ------------------------------------------------------------ */
  314.     /* comment found - could be a trigger                           */
  315.     /* ------------------------------------------------------------ */
  316.  
  317.             switch (line[2])
  318.             {
  319.                 case 'F':
  320.                 case 'H':
  321.                 {
  322.                     if (logging GE 9) fprintf (stderr, "F/H header\n");
  323.                     header (&lineno, line, fd);
  324.                     break;
  325.                 }
  326.                 case 'P':
  327.                 {
  328.                     if (logging GE 9) fprintf (stderr, "page break\n");
  329.                     print_head ();
  330.                     lineno++;
  331.                     break;
  332.                 }
  333.                 case 'S':
  334.                 {
  335.                     if (logging GE 9) fprintf (stderr, "subtitle\n");
  336.                     getname (line, subttl);
  337.                     lineno++;
  338.                     break;
  339.                 }
  340.                 case 'T':
  341.                 {
  342.                     if (logging GE 9) fprintf (stderr, "title\n");
  343.                     getname (line, title);
  344.                     /* print_head (); */
  345.                     lineno++;
  346.                     break;
  347.                 }
  348.                 default:
  349.                 {
  350.                     if (logging GE 9) fprintf (stderr, "other comment\n");
  351.                     print (&lineno, line);
  352.                     break;
  353.                 }
  354.             }
  355.         }
  356.         else
  357.         {
  358.     /* ------------------------------------------------------------ */
  359.     /* not a comment - check for function declaration               */
  360.     /* if a form feed is found, start a new page with header        */
  361.     /* ------------------------------------------------------------ */
  362.  
  363.             if (logging GE 9) fprintf (stderr, "not a comment\n");
  364.             if (!nlvl AND !isatty (1)) infunc = ckfunc (lineno, line);
  365.             if (*line EQ '\f') print_head ();
  366.             else print (&lineno, line);
  367.         }
  368.     }
  369.  
  370.     page_line = LPP+1;        /* force new page after file            */
  371.     title[0] = NUL;            /* clear title and subtitle                */
  372.     subttl[0] = NUL;
  373.  
  374.     return;
  375. }
  376. /*Sheader - construct and print header box */
  377. /*Hheader*/
  378. /*E*/
  379. header  (lineno, line, fd)
  380. register int     *lineno;
  381. register char    *line;
  382. register FILE    *fd;
  383. {
  384.     register char *p;
  385.  
  386.     char    *strrchr ();
  387.  
  388.     if (line[2] EQ 'F')
  389.     {
  390.         getname (line, fh_name);
  391.         strcpy (fnc_name, ".");
  392.     }
  393.     else if (line[2] EQ 'H')
  394.     {
  395.         getname (line, fnc_name);
  396.     }
  397.  
  398.     if (p = strrchr (fh_name, '/')) p++;
  399.     else p = fh_name;
  400.     if (!isatty (1))
  401.         fprintf (tocfile,
  402.             "%s %s %d %d\n", p, fnc_name, pageno, *lineno);
  403.  
  404.     print_head ();
  405.  
  406.     print (lineno, line);
  407.  
  408.     while (fgets (line, MAXWIDTH, fd) NE NULL AND
  409.             notend (line))
  410.     {
  411.         if (line[0] EQ SLASH AND line[1] EQ STAR AND line[2] EQ 'P')
  412.         {
  413.             print_head ();
  414.             (*lineno)++;
  415.         }
  416.         else
  417.         {
  418.             print (lineno, line);
  419.         }
  420.     }
  421.  
  422.     print (lineno, line);
  423.  
  424.     return;
  425. }
  426. /*Sgetname - get a string from a signal line */
  427. /*Hgetname */
  428. /*E*/
  429. getname (line, name)
  430. register char    *line;
  431. register char    *name;
  432. {
  433.     register int     i;
  434.     register int     j;
  435.  
  436.     /* ------------------------------------------------------------ */
  437.     /* skip leading spaces in the trigger line                      */
  438.     /* copy up to trailing asterisk or end-of-line                  */
  439.     /* strip trailing spaces                                        */
  440.     /* ------------------------------------------------------------ */
  441.  
  442.     for (i = 3; isspace(line[i]) AND i LT MAXWIDTH; i++);
  443.  
  444.     for (j = 0; line[i] AND line[i] NE '*'; i++, j++)
  445.     {
  446.         name[j] = line[i];
  447.     }
  448.  
  449.     while (j-- GT 0 AND isspace (name[j]));
  450.  
  451.     name[++j] = NUL;
  452.  
  453.     return;
  454. }
  455. /*Sprint - print a line with line number */
  456. /*Hprint */
  457. /*E*/
  458. print (lineno, line)
  459. register int     *lineno;
  460. register char    *line;
  461. {
  462.     register int llen = strlen (line);
  463.     register int i;
  464.  
  465.     register char sc = specline ? '*' : ' ';
  466.  
  467.     int     j = 0;
  468.  
  469.     register char    dc = NUL;
  470.     char    *strchr();
  471.  
  472.     /* ------------------------------------------------------------ */
  473.     /* new page with header if page length is exceeded              */
  474.     /* ------------------------------------------------------------ */
  475.  
  476.     if (page_line GT LPP)
  477.     {
  478.         print_head ();
  479.     }
  480.  
  481.     /* ------------------------------------------------------------ */
  482.     /* if brace(s) found,                                           */
  483.     /*   modify the nesting level by the net nesting delta          */
  484.     /*   select the indicator according to the net delta            */
  485.     /*   if nexting is back to zero (none), clear function name     */
  486.     /* ------------------------------------------------------------ */
  487.  
  488.     if (fnd (line, &j))
  489.     {
  490.         nlvl += j;
  491.  
  492.         if (j LT 0) dc = '<';
  493.         else if (j EQ 0) dc = '*';
  494.         else dc = '>';
  495.  
  496.         i = nlvl;
  497.         if (j LT 0) i++;
  498.         fprintf (stdout, "%4d%c%2d%c ",
  499.             (*lineno)++, sc, i, dc);
  500.         if (nlvl EQ 0) strcpy (fnc_name, ".");
  501.     }
  502.     else
  503.     {
  504.         fprintf (stdout, "%4d%c    ", (*lineno)++, sc);
  505.     }
  506.  
  507.     /* ------------------------------------------------------------ */
  508.     /* break up long lines by finding the first space form the end  */
  509.     /* ------------------------------------------------------------ */
  510.  
  511.     if (llen GT 71)
  512.     {
  513.         for (i = 70; i GE 0; i--)
  514.         {
  515.             if (line[i] EQ SPACE)
  516.             {
  517.                 fprintf (stdout, "%*.*s \\\n", i, i, line);
  518.                 page_line++;
  519.                 break;
  520.             }
  521.         }
  522.  
  523.         j = 79 - (llen - i);
  524.  
  525.         for (j; j GE 0; j--) putc (SPACE, stdout);
  526.  
  527.         fprintf (stdout, "%s", &line[i+1]);
  528.     }
  529.     else
  530.     {
  531.         fprintf (stdout, "%s", line);
  532.     }
  533.  
  534.     page_line++;
  535.  
  536.     specline = FALSE;        /* true if function declaration        */
  537.  
  538.     return;
  539. }
  540. /*Sprint_head - print the page heading with page number */
  541. /*Hprint_head */
  542. /*E*/
  543. print_head ()
  544. {
  545.     char    headbuf[80];
  546.     register int len;
  547.  
  548.     sprintf (headbuf, "[ %s | %s <- %s",
  549.         tim_lin, fh_name, fnc_name);
  550.  
  551.     for (len = strlen (headbuf); len LT 68; len++) headbuf[len] = SPACE;
  552.  
  553.     sprintf (&headbuf[68], "Page %-4d ]", pageno++);
  554.     fprintf (stdout, "\f\n");
  555.     if (!isatty (1))
  556.         fprintf (stdout, "_______________________________________\
  557. ________________________________________");
  558.     fprintf (stdout, "\n%s\n", headbuf);
  559.     fprintf (stdout, "[-------------------------------+------\
  560. ---------------------------------------]\n");
  561.  
  562.     if (*title)
  563.     {
  564.         sprintf (headbuf, "[    %s", title);
  565.     }
  566.     else
  567.     {
  568.         sprintf (headbuf, "[    %s", fh_name);
  569.     }
  570.     for (len = strlen (headbuf); len LT 78; len++) headbuf[len] = SPACE;
  571.     headbuf[78] = ']';
  572.     fprintf (stdout, "%s\n", headbuf);
  573.  
  574.     if (*subttl)
  575.     {
  576.         sprintf (headbuf, "[    %s", subttl);
  577.     }
  578.     else
  579.     {
  580.         sprintf (headbuf, "[    %s", fnc_name);
  581.     }
  582.     for (len = strlen (headbuf); len LT 78; len++) headbuf[len] = SPACE;
  583.     headbuf[78] = ']';
  584.     fprintf (stdout, "%s", headbuf);
  585.  
  586.     if (!isatty (1))
  587.         fprintf (stdout, "\r_______________________________________\
  588. ________________________________________");
  589.     fprintf (stdout, "\n\n");
  590.  
  591.     page_line = LINESINHEAD;
  592.  
  593.     return;
  594. }
  595. /*S fnd - return true if a brace is found */
  596. /*H fnd */
  597. /*E*/
  598. fnd (in, nchg)
  599. register char *in;
  600. register int    *nchg;
  601. {
  602. #   define LBRACE   '{'
  603. #   define RBRACE   '}'
  604. #   define SHARP    '#'
  605. #   define COLON    ':'
  606.  
  607.     register found = FALSE;            /* true if keyword found        */
  608.  
  609.     register char blank = TRUE;        /* used to check for shell/make    */
  610.                                     /* comments beginning with #/:    */
  611.     register int inshcomment = FALSE;    /* true if in shell comment    */
  612.  
  613.     *nchg = 0;                /* initialize net change to zero        */
  614.  
  615.     /* ------------------------------------------------------------ */
  616.     /* check each character of the line                             */
  617.     /* ------------------------------------------------------------ */
  618.  
  619.     for (in; *in; in++)
  620.     {
  621.         if (!incomment AND !inshcomment AND !indquote AND !insquote)
  622.         {
  623.             if (logging GE 9) fprintf (stderr, "not in comment or quote\n");
  624.             if (*in EQ SLASH AND *(in+1) EQ STAR)
  625.             {
  626.                 incomment = TRUE;
  627.                 blank = FALSE;
  628.                 if (logging GE 9) fprintf (stderr, "new comment\n");
  629.             }
  630.             else if (blank AND
  631.                      ((*in EQ SHARP OR *in EQ COLON) AND
  632.                      (*(in+1) NE LBRACE AND *(in+1) NE RBRACE))
  633.                     )
  634.             {
  635.                 inshcomment = TRUE;
  636.                 blank = FALSE;
  637.                 if (logging GE 9) fprintf (stderr, "new shell comment\n");
  638.             }
  639.             else if (*in EQ DQUOTE AND
  640.                     (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  641.             {
  642.                 indquote = TRUE;
  643.                 blank = FALSE;
  644.                 if (logging GE 9) fprintf (stderr, "new dquote\n");
  645.             }
  646.             else if (*in EQ SQUOTE AND
  647.                     (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  648.             {
  649.                 insquote = TRUE;
  650.                 blank = FALSE;
  651.                 if (logging GE 9) fprintf (stderr, "new squote\n");
  652.             }
  653.             else if (*in EQ LBRACE)
  654.             {
  655.                 (*nchg)++;
  656.                 found = TRUE;
  657.                 blank = FALSE;
  658.                 if (logging GE 9) fprintf (stderr, "nest in\n");
  659.             }
  660.             else if (*in EQ RBRACE)
  661.             {
  662.                 (*nchg)--;
  663.                 found = TRUE;
  664.                 blank = FALSE;
  665.                 if (logging GE 9) fprintf (stderr, "nest out\n");
  666.             }
  667.             else if (!isspace (*in))
  668.             {
  669.                 blank = FALSE;
  670.             }
  671.         }
  672.         else if (incomment AND *in EQ STAR AND *(in+1) EQ SLASH)
  673.         {
  674.             incomment = FALSE;
  675.             if (logging GE 9) fprintf (stderr, "end comment\n");
  676.         }
  677.         else if (indquote AND *in EQ DQUOTE AND
  678.                 (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  679.         {
  680.             indquote = FALSE;
  681.             if (logging GE 9) fprintf (stderr, "end dquote\n");
  682.         }
  683.         else if (insquote AND *in EQ SQUOTE AND
  684.                 (*(in-1) NE BSLASH OR *(in-2) EQ BSLASH))
  685.         {
  686.             insquote = FALSE;
  687.             if (logging GE 9) fprintf (stderr, "end squote\n");
  688.         }
  689.     }
  690.     
  691.     return found;
  692. }
  693. /*Stocout - print out the table of contents */
  694. /*Htocout */
  695. /*E*/
  696. tocout (toc)
  697. FILE    *toc;
  698. {
  699.     char    buf[80];
  700.     char    filenam[80];
  701.     char    fncnam[80];
  702.     int     page;
  703.     int     line;
  704.  
  705.     char    outline[80];
  706.  
  707.     register int toclines = 99;
  708.  
  709.     while (fscanf (toc, "%s%s%d%d", filenam, fncnam, &page, &line) EQ 4)
  710.     {
  711.         if (toclines GT 54)
  712.         {
  713.             printf ("\f\n\
  714.                              _____________________\n\
  715.                              [ TABLE OF CONTENTS ]\r\
  716.                              _____________________\n\n\
  717.                 File -> Function                     Page    Line\r\
  718. ________________________________________\
  719. ________________________________________\n\n");
  720.             toclines = 0;
  721.         }
  722.  
  723.         toclines++;
  724.  
  725.         printf ("\
  726.     %16s -> %-16.16s ............ %3d   %5d\n",
  727.             filenam, *fncnam EQ '.' ? "START" : fncnam, page, line);
  728.     }
  729.     return;
  730. }
  731. /*S expand - expand tabs to tabstop */
  732. /*H expand */
  733. /*E*/
  734. expand (to, from)
  735. register char *to;
  736. register char *from;
  737. {
  738.     register int i;
  739.     register int tofill;
  740.  
  741. #   define BACKSPACE '\b'
  742. #   define FORMFEED '\f'
  743. #   define NEWLINE '\n'
  744. #   define RETURN '\r'
  745. #   define TAB '\t'
  746.     
  747.     i = 0;
  748.  
  749.     while (*from)
  750.     {
  751.         switch (*from)
  752.         {
  753.             case    TAB:
  754.                 tofill = tabstop - (i % tabstop);
  755.                 i += tofill;
  756.                 while (tofill--) *(to++) = SPACE;
  757.                 break;
  758.             case    NEWLINE:
  759.             case    RETURN:
  760.                 i = 0;
  761.             case    FORMFEED:
  762.                 *(to++) = *from;
  763.                 break;
  764.             case    BACKSPACE:
  765.                 i--;
  766.                 *(to++) = *from;
  767.                 break;
  768.             default:
  769.                 i++;
  770.                 *(to++) = *from;
  771.                 break;
  772.         }
  773.  
  774.         from++;
  775.     }
  776.  
  777.     *to = NUL;
  778.  
  779.     return;
  780. }
  781. /*S ckfunc - check line for function declaration */
  782. /*H ckfunc */
  783. /*E*/
  784.  
  785. #define isidchr(c) (isalnum(c) || (c == '_'))
  786.  
  787. ckfunc (lineno, s)
  788. register int lineno;
  789. register char   *s;
  790. {
  791.     register char *p;
  792.     register int  Cnt;
  793.     register int  i;
  794.     register int  result;
  795.     register char found = FALSE;
  796.  
  797.     static char *_fnm = "ckfunc";
  798.  
  799.     char FunctionName[40];
  800.  
  801.     if (logging GE 3)
  802.     {
  803.         fprintf (stderr,
  804.             "%s<%s>: LOG: ckfunc called - line = %s",
  805.             pgm, _fnm, s);
  806.     }
  807.  
  808.     if(!strcmp (fnc_name, ".") AND !incomment && !indquote && !insquote)
  809.     {
  810.         found = TRUE;
  811.  
  812.         while (found)
  813.         {
  814.             found = FALSE;
  815.             p = FunctionName;
  816.             for (s; isascii (*s) && isspace (*s) && *s; s++);
  817.             if( *s == '*' )
  818.             {
  819.                 for (++s; isascii (*s) && isspace (*s) && *s; s++);
  820.             }
  821.  
  822.             if ((*s == '_') || isalpha(*s))
  823.             {
  824.                 while (isidchr (*s)) *p++ = *s++;
  825.  
  826.                 *p = '\0';
  827.  
  828.                 for (found = FALSE, i = 0;
  829.                      !found AND ReservedWord[i]; i++)
  830.                 {
  831.                     if (!(result = strcmp (FunctionName, ReservedWord[i])))
  832.                         found = TRUE;
  833.  
  834.                     if  (result < 0) break;
  835.                 }
  836.  
  837.                 if (logging GE 3 AND found)
  838.                 {
  839.                     fprintf (stderr,
  840.                         "%s<%s>: LOG: reserved word = %s\n",
  841.                         pgm, _fnm, FunctionName);
  842.                 }
  843.             }
  844.         }
  845.  
  846.         if (logging GE 3)
  847.         {
  848.             fprintf (stderr,
  849.                 "%s<%s>: LOG: last word = %s\n",
  850.                 pgm, _fnm, FunctionName);
  851.         }
  852.         
  853.         for (s; isascii (*s) && isspace (*s) && *s; s++);
  854.  
  855.         if (*s EQ '(')
  856.         {
  857.             for (found = FALSE; *s AND !found; s++)
  858.                 found = *s EQ ')';
  859.             
  860.             if (found)
  861.             {
  862.                 for (; *s AND isspace (*s); s++);
  863.  
  864.                 found = *s NE ';';
  865.                 
  866.                 if (found)
  867.                 {
  868.                     strcpy (fnc_name, FunctionName);
  869.                     fprintf (tocfile,
  870.                         "%s %s %d %d\n",
  871.                         fh_name, fnc_name, pageno-1, lineno);
  872.                     specline = TRUE;
  873.                 }
  874.             }
  875.         }
  876.     }
  877.  
  878.     if (logging GE 3)
  879.     {
  880.         fprintf (stderr,
  881.     "%s<%s>: LOG: this line does%s contain a function declaration\n",
  882.             pgm, _fnm, found ? "" : " not");
  883.     }
  884.  
  885.     return found;
  886. }
  887.