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