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