home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume06 / cpr < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  32.1 KB

  1. From decwrl!purdue!mailrus!tut.cis.ohio-state.edu!ucbvax!agate!helios.ee.lbl.gov!ncis.llnl.gov!lll-winken!uunet!allbery Fri Mar 24 22:25:59 PST 1989
  2. Article 834 of comp.sources.misc:
  3. Path: decwrl!purdue!mailrus!tut.cis.ohio-state.edu!ucbvax!agate!helios.ee.lbl.gov!ncis.llnl.gov!lll-winken!uunet!allbery
  4. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Newsgroups: comp.sources.misc
  6. Subject: v06i067: CPR a pretty printer for lots of C sources
  7. Message-ID: <51318@uunet.UU.NET>
  8. Date: 21 Mar 89 01:45:17 GMT
  9. Sender: allbery@uunet.UU.NET
  10. Reply-To: Dennis Vadura <dvadura@watdragon.waterloo.edu>
  11. Organization: Computer Science Dept., University of Waterloo
  12. Lines: 1310
  13. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  14.  
  15. Posting-number: Volume 6, Issue 67
  16. Submitted-by: dvadura@watdragon.waterloo.edu (Dennis Vadura)
  17. Archive-name: cpr
  18.  
  19.  
  20. # This is a listing program for C sources, but handles other stuff as well.  It
  21. # pretty prints the specified files, and creates a table of contents.
  22. # We use it arround here a lot.
  23. #
  24. # I posted this program to comp.sources about 3 years ago and it was quite
  25. # popular.  I have since improved the function finding ability, fixed up the
  26. # handling of tabs and added a bunch of new features.  So I decided to submit
  27. # it again.  It now compiles under DOS as well.  There is no makefile, but
  28. # the first two lines of cpr.c give the command lines to use for compiling it.
  29. #
  30. #    This shar file contains:
  31. #        cpr.c        - the C source for cpr
  32. #        cpr.t         - the troff source for the man page
  33. #        cpr.p        - preformatted version of the manpage.
  34. #------------------------------------------------------------------------------
  35. # This is a shell archive.  Remove anything before this line,
  36. # then unpack it by saving it in a file and typing "sh file".
  37. #
  38. # Wrapped by watdragon!dvadura on Tue Feb  7 17:05:23 EST 1989
  39. # Contents:  cpr.c cpr.p cpr.t
  40.  
  41. echo x - cpr.c
  42. sed 's/^@//' > "cpr.c" <<'@//E*O*F cpr.c//'
  43. /*    if UNIX:    cc -O cpr.c
  44.  *    if MSDOS:    cc -O -DMSDOS cpr.c
  45.  *
  46.  *    This program prints the files named in its argument list, preceding
  47.  *    the output with a table of contents. Each file is assumed to be C
  48.  *    source code (but doesn't have to be) in that the program searches
  49.  *    for the beginning and end of functions. Function names are added to
  50.  *    the table of contents, provided the name starts at the beginning of
  51.  *    a line. The function name in the output is double striken.
  52.  *
  53.  *    By default blank space is inserted after every closing '}'
  54.  *    character. Thus functions and structure declarations are nicely
  55.  *    isolated in the output. The only drawback to this is that structure
  56.  *    initialization tables sometimes produce lots of white space.
  57.  *    The "-r" option removes this space, or changes it to the indicated
  58.  *    length.
  59.  *
  60.  *    The option "-l" indicates that the following argument is to be
  61.  *    the page length used for output (changing the page length hasn't been
  62.  *    tested much).
  63.  *
  64.  *    The option "-s" indicates that the table of contents should be sorted
  65.  *    by function name within each file.
  66.  *
  67.  *    The option "-n" indicates that output lines should be numbered with
  68.  *    the corresponding line number from the input file.
  69.  *
  70.  *    The option "-p" indicates what proportion of the page in steps of 16
  71.  *    should be used for deciding if a new function needs a new page.
  72.  *    That is -p12 (the default) indicates that if a function starts
  73.  *    within the top 12/16 (3/4) of the page then do it, otherwise put it
  74.  *    on a new page.  Thus the higher the number (upto 16) the closer to
  75.  *    the bottom of the page will functions be started. -p0 says put each
  76.  *    func on a new page.
  77.  *
  78.  *    Try it! You'll like it. (I call it cpr.c)
  79.  *
  80.  *    Written by:
  81.  *        Paul Breslin
  82.  *        Human Computing Resources Corp.
  83.  *        10 St. Mary St.
  84.  *        Toronto, Ontario
  85.  *        Canada, M4Y 1P9
  86.  *
  87.  *        -- ...!decvax!utcsrgv!hcr!phb
  88.  *
  89.  *      Sorting and standard input reading from:
  90.  *        Rick Wise, CALCULON Corp., Rockville, MD.
  91.  *        -- ...!decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise
  92.  *
  93.  *    File modified time,
  94.  *    numbered output,
  95.  *    optional white space,
  96.  *    improved function start tests from:
  97.  *        David Wasley, U.C.Berkeley
  98.  *        -- ...!ucbvax!topaz.dlw
  99.  *    Modified the -r to leave variable amounts of space
  100.  *        Patrick Powell, U. Waterloo
  101.  *
  102.  *      Changed handling of form feeds to start a new page AND print heading:
  103.  *        Terry Doner, U of Waterloo
  104.  *
  105.  *    Fixed up to locate more functions, and added -p option
  106.  *        Dennis Vadura, U of Waterloo
  107.  *
  108.  *        It will find things like  struct foo *f()...
  109.  *        but not things like     int
  110.  *                    f
  111.  *                    ()...
  112.  *        ie. the constraint is that the () must appear on the same line
  113.  *        as the function name.
  114.  *
  115.  *  Clean up a bit for 80286 machines (lints a bit cleaner, too) 
  116.  *      Dan Frank, Prairie Computing
  117.  *
  118.  *  Fixed a whole bunch of stuff and added lots of new flags.
  119.  *      -S       sort and be case insensitive.
  120.  *      -N       start numbering pages at 1 for each new file
  121.  *      -T title cat the file title before the table of contents.
  122.  *      -C       print only the table of contents
  123.  *      -c       only try to look for function names in files whose suffix ends
  124.  *             in .c
  125.  *      -f file  to handle file containing list of files to print. (for MSDOS)
  126.  *      Dennis Vadura
  127.  */
  128. #include <sys/types.h>
  129. #include <sys/stat.h>
  130. #include <stdio.h>
  131. #include <ctype.h>
  132. #include <signal.h>
  133. #include <string.h>
  134. extern int errno; /* system error number */
  135. extern char *sys_errlist[]; /* error message */
  136. extern char *malloc() ; /* important for 8086-like systems */
  137.  
  138. #define BP        0xC        /* Form feed            */
  139.  
  140. #define TOC_SIZE    4096
  141.  
  142. #define    NEWFILE        1
  143. #define NEWFUNCTION    2
  144.  
  145. FILE *File;
  146.  
  147. int Braces; /* Keeps track of brace depth    */
  148. int LineNumber; /* Count output lines        */
  149. int PageNumber = 0; /* You figure this one out    */
  150. int PageLength = 66; /* -l <len> Normal paper length    */
  151. int PagePart = 12; /* Decision on paging for new fn*/
  152. int PageEnd; /* Accounts for space at bottom    */
  153. int SawFunction;
  154. int InComment;
  155. int InString;
  156. int Title=0;
  157. int ResetPage=0;
  158. int ContentsOnly=0;
  159. int CaseInsensitive=0;
  160. int OnlyCFiles=0;
  161.  
  162. long FileLineNumber; /* Input file line number    */
  163.  
  164. char *TitleFile;
  165. char *ProgName;
  166. char Today[30];
  167. char *Name; /* Current file name        */
  168.  
  169. char FunctionName[80];
  170. char FileDate[24]; /* Last modified time of file    */
  171.  
  172. char SortFlag; /* -s == sort table of contents    */
  173. char NumberFlag; /* -n == output line numbers    */
  174. int Space_to_leave = 5; /* -r<number> space to leave    */
  175. int TabWidth = 0; /* -t <number> width of tabs     */
  176.  
  177. main(argc, argv)
  178. char **argv;
  179. {
  180.    register int i;
  181.    char *ctime();
  182.    time_t thetime, time();
  183.    char *parm;
  184.    int c;
  185.  
  186.    ProgName = argv[0];
  187.    thetime = time((time_t *)0);
  188.    strcpy(Today,ctime(&thetime));
  189.  
  190.    for( i=1; argc > i; ++i )
  191.    {
  192.       if( argv[i][0] != '-' 
  193.          || argv[i][1] == '\0' ) break;
  194.  
  195.       parm = argv[i];
  196.       while( c = *++parm ) switch( c ){
  197.       case 'f': goto endofoptions;
  198.       case 't':
  199.          if( argc < 3 ) Usage();
  200.          TabWidth = atoi(argv[++i]);
  201.          if( TabWidth < 0 )
  202.             TabWidth = 0;
  203.          break;
  204.  
  205.       case 'T':
  206.          if( argc < 3 ) Usage();
  207.          TitleFile = argv[++i];
  208.          ++Title;
  209.          break;
  210.  
  211.       case 'l':
  212.          if( argc < 3 ) Usage();
  213.          PageLength = atoi(argv[++i]);
  214.          if( PageLength < 10) PageLength = 10;
  215.          break;
  216.  
  217.       case 'S':
  218.          ++CaseInsensitive;
  219.       case 's':
  220.          ++SortFlag;
  221.          break;
  222.  
  223.       case 'C':
  224.          ++ContentsOnly;
  225.          break;
  226.  
  227.       case 'c':
  228.          ++OnlyCFiles;
  229.          break;
  230.  
  231.       case 'n':
  232.          ++NumberFlag;
  233.          break;
  234.  
  235.       case 'N':
  236.          ++ResetPage;
  237.          break;
  238.  
  239.       case 'r':
  240.          if( (c = parm[1]) && isdigit( c )
  241.             &&( c = atoi( parm+1 )) > 0 ){
  242.             Space_to_leave = c;
  243.          }
  244.          else {
  245.             Space_to_leave = 0;
  246.          }
  247.          while( *parm ){
  248.             ++parm;
  249.          }
  250.          --parm;
  251.          break;
  252.  
  253.       case 'p':
  254.          if( (c = parm[1]) && isdigit( c )
  255.             &&( c = atoi( parm+1 )) >= 0 ){
  256.             PagePart = (c <= 16) ? c: 16;
  257.          }
  258.          while( *parm ){
  259.             ++parm;
  260.          }
  261.          --parm;
  262.          break;
  263.  
  264.       default:
  265.          Usage();
  266.          break;
  267.       }
  268.    }
  269.  
  270. endofoptions:
  271.    PageEnd = PageLength - ((PageLength > 30) ? 7 : 1);
  272.  
  273.    StartTempFile();
  274.  
  275.    if( i == argc )
  276.    { /* no file names */
  277.       File = stdin;
  278.       Name = "Standard Input";
  279.       List();
  280.    }
  281.  
  282.    for(; i < argc; ++i )
  283.    {
  284.       if( strcmp(argv[i], "-") == 0 )
  285.       {
  286.          File = stdin;
  287.          Name = "Standard Input";
  288.          List();
  289.       }
  290.       else if( strcmp(argv[i], "-f") == 0 )
  291.       {
  292.          char b[1024];
  293.      FILE *listf;
  294.  
  295.      i++;
  296.      if( i == argc )
  297.      {
  298.         fprintf(stderr,"%s: missing file name for -f option\n", ProgName );
  299.         exit(1);
  300.      }
  301.  
  302.      if( (listf = fopen( argv[i], "r" )) == NULL )
  303.      {
  304.         fprintf(stderr,"%s: list file '%s', not found\n", ProgName,
  305.             argv[i] );
  306.         exit(1);
  307.      }
  308.  
  309.          while( fgets(b, 1024, listf) != NULL )
  310.          {
  311.             if( strlen(b) ) b[strlen(b)-1]=0;
  312.  
  313.         if( strcmp(b, "-") != 0 )
  314.         {
  315.            if( (File = fopen( Name = b, "r" )) == NULL )
  316.            {
  317.           fprintf(stderr,"%s: Can't open file '%s': %s\n",
  318.           ProgName, Name, sys_errlist[errno] );
  319.           continue;
  320.            }
  321.         }
  322.         else
  323.            File = stdin;
  324.  
  325.             List();
  326.             if( File != stdin ) fclose(File);
  327.          }
  328.       }
  329.       else {
  330.          if( (File = fopen( Name = argv[i], "r" )) == NULL )
  331.          {
  332.             fprintf(stderr,"%s: Can't open file '%s': %s\n",
  333.             ProgName, Name, sys_errlist[errno] );
  334.             continue;
  335.          }
  336.          List();
  337.          if( File != stdin ) fclose(File);
  338.       }
  339.    }
  340.  
  341.    if( PageNumber > 1 || LineNumber > 0 )
  342.       putchar(BP);
  343.    EndTempFile();
  344.  
  345.    DumpTableOfContents();
  346.    DumpTempFiles();
  347.    Done();
  348. }
  349.  
  350. Usage()
  351. {
  352.    fprintf(stderr, "Usage: %s [-cCnNsS] [-T title] [-t tabwidth] [-p[num]] [-r[num]] [-l pagelength] [[-f] file] ...\n",
  353.    ProgName);
  354.    exit(1);
  355. }
  356.  
  357. int SaveOut;
  358. char *TempName;
  359. char *Temp2Name;
  360.  
  361. StartTempFile()
  362. {
  363.    int Done();
  364.    extern char *mktemp();
  365.  
  366.    CatchSignalsPlease(Done);
  367.  
  368.    SaveOut = dup(1);
  369. #ifdef MSDOS
  370.    TempName = "cpr0001.tmp";
  371. #else
  372.    TempName = mktemp("/tmp/cprXXXXXX");
  373. #endif
  374.    if( freopen(TempName, "w", stdout) == NULL )
  375.    {
  376.       fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
  377.       TempName, sys_errlist[errno]);
  378.       exit(1);
  379.    }
  380. }
  381.  
  382. EndTempFile()
  383. {
  384. #ifdef MSDOS
  385.    Temp2Name = "cpr0002.tmp";
  386. #else
  387.    Temp2Name = mktemp("/tmp/cprXXXXXX");
  388. #endif
  389.    if( freopen(Temp2Name, "w", stdout) == NULL )
  390.    {
  391.       fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
  392.       Temp2Name, sys_errlist[errno]);
  393.       exit(1);
  394.    }
  395. }
  396.  
  397. DumpTempFiles()
  398. {
  399.    FILE *f;
  400.    char b[256];
  401.    register int pid, w;
  402.  
  403.    fclose(stdout);
  404.  
  405. #ifndef MSDOS
  406.    dup(SaveOut);
  407.    while( (pid = fork()) < 0 ) sleep(1);
  408.    if( pid )
  409.       while ((w = wait((int *)0)) != pid && w != -1);
  410.    else
  411.       {
  412.       CatchSignalsPlease(SIG_DFL);
  413.  
  414.       if( ContentsOnly )
  415.          execl( "/bin/cat", "cat", Temp2Name, (char *)0 );
  416.       else
  417.          execl( "/bin/cat", "cat", Temp2Name, TempName, (char *)0 );
  418.       fprintf(stderr, "%s: exec of /bin/cat failed: %s\n", ProgName,
  419.       sys_errlist[errno]);
  420.       exit(0);
  421.    }
  422. #else
  423.    CatchSignalsPlease(SIG_DFL);
  424.    if( (f=fopen(Temp2Name,"r")) == NULL )
  425.       fprintf(stderr,"%s: Can't open file '%s': %s\n",
  426.       ProgName, TitleFile, sys_errlist[errno] );
  427.    else
  428.    {
  429.       while( fgets(b, 256, f) != NULL )
  430.          write(SaveOut,b,strlen(b));
  431.  
  432.       fclose(f);
  433.    }
  434.  
  435.    if( !ContentsOnly )
  436.       if( (f=fopen(TempName,"r")) == NULL )
  437.          fprintf(stderr,"%s: Can't open file '%s': %s\n",
  438.          ProgName, TitleFile, sys_errlist[errno] );
  439.       else
  440.       {
  441.          while( fgets(b, 256, f) != NULL )
  442.             write(SaveOut,b,strlen(b));
  443.  
  444.          fclose(f);
  445.       }
  446. #endif
  447. }
  448.  
  449. Done()
  450. {
  451.    CatchSignalsPlease(SIG_DFL);
  452.  
  453.    fclose( stdout );
  454.    if( TempName ) unlink( TempName );
  455.    if( Temp2Name ) unlink( Temp2Name );
  456.  
  457.    exit(0);
  458. }
  459.  
  460. CatchSignalsPlease(action)
  461. int (*action)();
  462. {
  463.    if( signal(SIGINT, SIG_IGN) != SIG_IGN ) signal(SIGINT, action);
  464. #ifndef MSDOS
  465.    if( signal(SIGQUIT, SIG_IGN) != SIG_IGN ) signal(SIGQUIT, action);
  466.    if( signal(SIGHUP, SIG_IGN) != SIG_IGN ) signal(SIGHUP, action);
  467. #endif
  468. }
  469.  
  470. List()
  471. {
  472.    register int bp;
  473.    register char *bufp;
  474.    char buffer[256];
  475.  
  476.    NewFile();
  477.    bp = Braces = 0;
  478.    InString = InComment = 0; /* reset for new file -DV */
  479.    SawFunction = 0;
  480.    bufp = buffer;
  481.    while( fgets(bufp, sizeof(buffer), File) != NULL )
  482.    {
  483.       ++FileLineNumber;
  484.       if( bp ) NewFunction();
  485.  
  486.       if( ++LineNumber >= PageEnd ) NewPage();
  487.  
  488.       if( bufp[0] == '\f'
  489.          && bufp[1] == '\n'
  490.          && bufp[2] == '\0' )
  491.       {
  492.          NewPage(); /* was strcpy(bufp, "^L\n");*/
  493.          continue;
  494.       }
  495.  
  496.       if( NumberFlag )
  497.       {
  498.          if( *bufp == '\n' )
  499.             printf("        ");
  500.          else
  501.             printf("%6ld  ", FileLineNumber);
  502.       }
  503.       if( (Braces == 0) && LooksLikeFunction(bufp) )
  504.          AddToTableOfContents(NEWFUNCTION);
  505.  
  506.       bp = PutLine(buffer);
  507.    }
  508. }
  509.  
  510. PutLine(l)
  511. register char *l;
  512. {
  513.    extern char *EndComment();
  514.    extern char *EndString();
  515.    register char c;
  516.    int bp;
  517.    char *save;
  518.  
  519.    bp = 0;
  520.    for( save = l; c = *l; ++l )
  521.       if( InComment ) 
  522.          l = EndComment(l);
  523.       else if( InString )
  524.          l = EndString(l);
  525.       else
  526.          switch(c)
  527.          {
  528.          case '{':
  529.             ++Braces;
  530.             break;
  531.  
  532.          case '}':
  533.             if( --Braces == 0 )
  534.                bp = 1;
  535.             break;
  536.  
  537.          case '\'':
  538.             for( ++l; *l && *l != '\''; ++l )
  539.                if( *l == '\\' && *(l+1) ) ++l;
  540.             break;
  541.  
  542.          case '"':
  543.             InString = 1;
  544.             break;
  545.  
  546.          case '/':
  547.             if( *(l+1) == '*' )
  548.             {
  549.                InComment = 1;
  550.                ++l;
  551.             }
  552.             break;
  553.          }
  554.    printf("%s", save);
  555.    return(bp);
  556. }
  557.  
  558. char *
  559. EndComment(p)
  560. register char *p;
  561. {
  562.    register char c;
  563.  
  564.    /*
  565.             * Always return pointer to last non-null char looked at.
  566.             */
  567.    while( c = *p++ )
  568.       if( c == '*' && *p == '/' )
  569.       {
  570.          InComment = 0;
  571.          return(p);
  572.       }
  573.    return(p-2);
  574. }
  575.  
  576. char *
  577. EndString(p)
  578. register char *p;
  579. {
  580.    register char c;
  581.  
  582.    /*
  583.             * Always return pointer to last non-null char looked at.
  584.             */
  585.    while( c = *p++ )
  586.       if( c == '\\' && *p )
  587.       {
  588.          ++p;
  589.          continue;
  590.       }
  591.       else if( c == '"' )
  592.       {
  593.          InString = 0;
  594.          return(p-1);
  595.       }
  596.    return(p-2);
  597. }
  598.  
  599. NewFunction()
  600. {
  601.    register int i;
  602.  
  603.    if( Space_to_leave <= 0 || !SawFunction ) return;
  604.    if( LineNumber + Space_to_leave > (PageLength * PagePart /16) )
  605.       NewPage();
  606.    else
  607.       {
  608.       for( i=0; i < (Space_to_leave); ++i ) putchar('\n');
  609.       LineNumber += Space_to_leave;
  610.    }
  611.  
  612.    SawFunction = 0;
  613. }
  614.  
  615. #define HEADER_SIZE 3
  616.  
  617. NewPage()
  618. {
  619.    if( PageNumber >= 0 ) ++PageNumber;
  620.    putchar(BP);
  621.    LineNumber = 0;
  622.  
  623.    PutHeader();
  624. }
  625.  
  626. PutHeader()
  627. {
  628.    register int i, l, j;
  629.  
  630.    putchar('\n');
  631.    ++LineNumber;
  632.    l = strlen(Name);
  633.    for( j=0; j < l; ++j )
  634.       printf("%c\b%c\b%c", Name[j], Name[j], Name[j]);
  635.  
  636.    if( PageNumber > 0 )
  637.    {
  638.       printf("  %.17s", FileDate);
  639.       GoToColumn(l+19, 70);
  640.       printf("Page:%4d\n\n", PageNumber);
  641.       ++LineNumber;
  642.       ++LineNumber;
  643.    }
  644.    else
  645.       {
  646.       GoToColumn(l, 55);
  647.       printf("%s\n\n", Today);
  648.       ++LineNumber;
  649.       ++LineNumber;
  650.    }
  651. }
  652.  
  653. GoToColumn(from, to)
  654. register int from, to;
  655. {
  656.    if( from < to)
  657.    {
  658.       if( TabWidth > 0 ){
  659.          from &= ~(TabWidth-1);
  660.          for( ; (from + TabWidth) <= to; from += TabWidth )
  661.             putchar('\t');
  662.       }
  663.       for( ; from < to; from++ )
  664.          putchar(' ');
  665.    }
  666. }
  667.  
  668. #define isidchr(c)    (isalnum(c) || (c == '_'))
  669.  
  670. /* This used to incorrectly identify a declaration such as
  671.  *     int (*name[])() = { initializers ... }
  672.  * as a function.  It also picked up this in an assembler file:
  673.  *     #define MACRO(x) stuff
  674.  *     MACRO(x):
  675.  * Fixed both of these.   -IAN!
  676.  */
  677. LooksLikeFunction(s)
  678. register char *s;
  679. {
  680.    register char *p;
  681.    register int i;
  682.    char *save;
  683.    int t = TabWidth;
  684.  
  685.    if( InComment || InString ) return(0);
  686.    if( OnlyCFiles )
  687.    {
  688.       char *e = Name+strlen(Name)-1;
  689.       if( *e != 'c' || e[-1] != '.' ) return(0);
  690.    }
  691.  
  692.    if( !t ) t = 8;
  693.    save = s;
  694.  
  695.    i = 0;
  696.    do
  697.       {
  698.       p = FunctionName;
  699.  
  700.       while( *s && (*s == ' ') || (*s == '\t') ) ++s;
  701.       if( *s == '*' ) ++s;
  702.       if( *s && (*s == ' ') || (*s == '\t') ) continue;
  703.       if( !*s || ((*s != '_') && !isalpha(*s)) ) return(0);
  704.  
  705.       while( isidchr(*s) )
  706.          *p++ = *s++;
  707.       *p = '\0';
  708.  
  709.       while( *s && (*s == ' ') || (*s == '\t') ) ++s;
  710.       i++;
  711.    }
  712.    while ( *s && *s != '(' && i < 4 );
  713.  
  714.    if( *s != '(' || *(s+1) == '*' ) return(0);
  715.  
  716.    for (i = 0; *s; s++)
  717.    {
  718.       switch( *s )
  719.       {
  720.       case '(':
  721.          ++i;
  722.          continue;
  723.  
  724.       case ')':
  725.          --i;
  726.          break;
  727.  
  728.       default:
  729.          break;
  730.       }
  731.       if( i == 0 ) break;
  732.    }
  733.    if( !*s ) return(0);
  734.  
  735.    while( *s )
  736.    {
  737.       if( *s == '{') break;
  738.       if( *s == ';' || *s == ':' ) return(0);
  739.       ++s;
  740.    }
  741.  
  742.    /*
  743.             * This will cause the function name part of the line to
  744.             * be double striken.  Note that this assumes the name and the opening
  745.             * parentheses are on the same line...
  746.             */
  747.  
  748.    if( p = strchr( save, '(' ) )
  749.    {
  750.       p--;
  751.       while( p != save && isidchr( *(p-1) ) ) p--;
  752.       for( i=0; save != p; save++ )
  753.          if( *save == '\t' )
  754.          {
  755.             putchar('\t');
  756.             i = ((i+t)/t)*t;
  757.          }
  758.          else
  759.          {
  760.             putchar(' ');
  761.             i++;
  762.          }
  763.  
  764.       for( ; *p != '('; p++ )
  765.          if( *p == '\t' )
  766.          {
  767.             putchar('\t');
  768.             i = ((i+t)/t)*t;
  769.          }
  770.          else
  771.          {
  772.             putchar(*p);
  773.             i++;
  774.          }
  775.    }
  776.    else
  777.       for( i=0; *save && (*save == '*' || isidchr(*save)); ++save)
  778.          if( *save == '*' )
  779.          {
  780.             putchar(' ');
  781.             i++;
  782.          }
  783.          else
  784.          {
  785.             if( *save == '\t' )
  786.                i = ((i+t)/t)*t;
  787.             else
  788.                i++;
  789.             putchar(*save);
  790.          }
  791.  
  792.    while( i --> 0 ) putchar('\b');
  793.  
  794.    SawFunction = 1;
  795.    return(1);
  796. }
  797.  
  798. static char *Toc[TOC_SIZE];
  799. static int TocPages[TOC_SIZE];
  800. static int TocCount;
  801.  
  802. AddToTableOfContents(type)
  803. {
  804.    if( TocCount > TOC_SIZE )
  805.       return;
  806.    if( TocCount == TOC_SIZE )
  807.    {
  808.       fprintf(stderr, "%s: More than %d Table of contents entries; others ignored.\n",
  809.       ProgName, TOC_SIZE);
  810.       ++TocCount;
  811.       return;
  812.    }
  813.  
  814.    if( type == NEWFILE )
  815.       AddFile();
  816.    else
  817.       AddFunction();
  818. }
  819.  
  820. AddFunction()
  821. {
  822.    register int l;
  823.    register char *p;
  824.  
  825.    /* This heuristic stops multiple occurrences of a function,
  826.             * selected by #ifdefs, to all end up many times over in the
  827.             * Table of Contents.  One only needs to see it once.  -IAN!
  828.             */
  829.    if( TocCount > 0 && TocPages[TocCount-1] == PageNumber
  830.       && strcmp(Toc[TocCount-1],FunctionName) == 0 )
  831.       return;
  832.    l = strlen(FunctionName);
  833.    p = Toc[TocCount] = (char *)malloc(l+1);
  834.    strcpy(p, FunctionName);
  835.    TocPages[TocCount] = PageNumber;
  836.    ++TocCount;
  837. }
  838.  
  839. AddFile()
  840. {
  841.    register int i, l;
  842.    register int len;
  843.    char temp[20];
  844.  
  845.    len = strlen(Name) + 20;
  846.    len = (len < 130) ? 130 : len;
  847.    Toc[TocCount] = (char *)malloc(len);
  848.    sprintf(Toc[TocCount], "\n    File: %s ", Name);
  849.    l = strlen(Toc[TocCount]);
  850.    if( l < 64 )
  851.    {
  852.       if( TabWidth > 0 ){
  853.          i = ((64 - l) /TabWidth) + 1;
  854.          while( i-- > 0 )
  855.             Toc[TocCount][l++] = '\t';
  856.       }
  857.       else{
  858.          while( l < 64 )
  859.             Toc[TocCount][l++] = ' ';
  860.       }
  861.       Toc[TocCount][l++] = '\0';
  862.    }
  863.    sprintf(temp, "  Page %4d\n", PageNumber);
  864.    strcat(Toc[TocCount], temp);
  865.    ++TocCount;
  866. }
  867.  
  868. NewFile()
  869. {
  870.    GetFileTime();
  871.    if( ResetPage ) PageNumber=0;
  872.    NewPage();
  873.    AddToTableOfContents(NEWFILE);
  874.    FileLineNumber = 0;
  875. }
  876.  
  877. GetFileTime()
  878. {
  879.    struct stat st;
  880.    extern char *ctime();
  881.  
  882.    if( File == stdin )
  883.       strncpy(FileDate, &Today[4], 20);
  884.    else
  885.       {
  886.       fstat(fileno(File), &st);
  887.       strncpy(FileDate, ctime((time_t *)&st.st_mtime) + 4, 20);
  888.    }
  889.    strncpy(&FileDate[12], &FileDate[15], 5);
  890.    FileDate[18] = '\0';
  891. }
  892.  
  893. DumpTableOfContents()
  894. {
  895.    register int i, j;
  896.    int index[TOC_SIZE];
  897.  
  898.    if( TocCount == 0 ) return;
  899.  
  900.    for (i = 0; i < TocCount; i++) index[i] = i;
  901.    if( SortFlag )
  902.       SortTable(index);
  903.  
  904.    Name = "Table of  Contents";
  905.  
  906.    PageNumber = -1;
  907.    LineNumber = 0;
  908.  
  909.    if( Title )
  910.    {
  911.       FILE *f;
  912.       int n;
  913.       char b[256];
  914.  
  915.       if( (f=fopen(TitleFile,"r")) == NULL )
  916.          fprintf(stderr,"%s: Can't open file '%s': %s\n",
  917.          ProgName, TitleFile, sys_errlist[errno] );
  918.       else
  919.       {
  920.          while( fgets(b, 256, f) != NULL )
  921.          {
  922.             if( strlen(b) ) b[strlen(b)-1]=0;
  923.             puts(b);
  924.             LineNumber++;
  925.             if( ++LineNumber >= PageEnd ) NewPage();
  926.          }
  927.  
  928.          fclose(f);
  929.       }
  930.    }
  931.    else
  932.       NewPage();
  933.  
  934.    for( i=0; i < TocCount; ++i )
  935.    {
  936.       if( Toc[index[i]][0] == '\n' )
  937.       {
  938.          if( (LineNumber + 5) >= PageEnd ) NewPage();
  939.  
  940.          printf("%s", Toc[index[i]]);
  941.          LineNumber += 2;
  942.          continue;
  943.       }
  944.       if( ++LineNumber >= PageEnd ) NewPage();
  945.  
  946.       printf("        %s ", Toc[index[i]]);
  947.       for( j=strlen(Toc[index[i]]); j < 48; ++j ) putchar('.');
  948.       printf(" %4d\n", TocPages[index[i]]);
  949.    }
  950.  
  951.    if( ContentsOnly ) NewPage();
  952. }
  953.  
  954. SortTable(index)
  955. register int *index;
  956. {
  957.    register int i, temp, flag;
  958.    char name1[256];
  959.    char name2[256];
  960.  
  961.    do {
  962.       flag = 0;
  963.       for (i = 0; i < TocCount - 1; i++)
  964.       {
  965.          if( Toc[index[i]][0] == '\n' || Toc[index[i+1]][0] == '\n' )
  966.             continue; /* don't sort across file names */
  967.          strcpy( name1, Toc[index[i]] );
  968.          strcpy( name2, Toc[index[i+1]] );
  969.  
  970.          if( CaseInsensitive )
  971.          {
  972.             char *p;
  973.             char c;
  974.             for(p=name1; c=*p; p++ )
  975.                if( islower(c) ) *p=toupper(c);
  976.             for(p=name2; c=*p; p++ )
  977.                if( islower(c) ) *p=toupper(c);
  978.          }
  979.  
  980.          if( strcmp(name1, name2) > 0)
  981.          {
  982.             temp = index[i];
  983.             index[i] = index[i+1];
  984.             index[i+1] = temp;
  985.             flag = 1;
  986.          }
  987.       }
  988.    }
  989.    while( flag );
  990. }
  991. @//E*O*F cpr.c//
  992. chmod u=rw,g=,o= cpr.c
  993.  
  994. echo x - cpr.p
  995. sed 's/^@//' > "cpr.p" <<'@//E*O*F cpr.p//'
  996.  
  997.  
  998.  
  999.  
  1000. CPR(P)                 Unsupported Software                 CPR(P)
  1001.  
  1002.  
  1003.  
  1004. NNAAMMEE
  1005.      cpr  -  print 'C' files
  1006.  
  1007. SSYYNNOOPPSSIISS
  1008.      ppuubblliicc ccpprr [-cCnNsS] [-T title] [-t tabwidth] [-p[num]]
  1009.      [-r[num]] [-l pagelength] [[-f] file] ...
  1010.  
  1011. DDEESSCCRRIIPPTTIIOONN
  1012.      _c_p_r prints the files named in its argument list, preceding
  1013.      the output with a table of contents.  If a filename is pre-
  1014.      ceded by --ff then the specified file is assumed to contain a
  1015.      list of files to be printed.  The filename "-" specifies
  1016.      standard input.  Each file printed is assumed to be C source
  1017.      code (but doesn't have to be see -c option below) in that
  1018.      the program searches for the beginning and end of functions.
  1019.      Function names are added to the table of contents, provided
  1020.      the name starts at the beginning of a line. The function
  1021.      name in the output is double struck.
  1022.  
  1023.      By default, blank lines are inserted after every closing '}'
  1024.      character. Thus functions and structure declarations are
  1025.      nicely isolated in the output. The only drawback to this is
  1026.      that structure initialization tables sometimes produce lots
  1027.      of white space.  The --rr[n] option changes the space left to
  1028.      the specified number of lines.  If no number is specified,
  1029.      no space is left.
  1030.  
  1031.      The option --ll indicates that the following argument is to be
  1032.      the page length used for output, rather than the default 66
  1033.      lines.
  1034.  
  1035.      The option --cc forces cpr to "look" for functions only in
  1036.      files whose suffix ends in '.c'.
  1037.  
  1038.      The option --CC forces cpr to produce only a table of con-
  1039.      tents, the file contents themselves are not printed.
  1040.  
  1041.      The option --TT ttiittllee causes cpr to print the contents of the
  1042.      file ttiittllee before printing the table of contents.
  1043.  
  1044.      The option --ss indicates that the table of contents should be
  1045.      sorted by function name within each file.  Specifying --SS
  1046.      performs the sort in a case-insensitive manner.
  1047.  
  1048.      The option --nn indicates that output lines should be numbered
  1049.      with the corresponding line number from the input file.
  1050.  
  1051.      The option --NN forces page numbering to start with page 1 for
  1052.      each file processed.
  1053.  
  1054.      The option --tt _t_a_b_w_i_d_t_h causes output to be produced that
  1055.      will look correct with tabs expanded every _t_a_b_w_i_d_t_h columns.
  1056.  
  1057.  
  1058.  
  1059. Formatted 89/02/07              UW                              1
  1060.  
  1061.  
  1062.  
  1063.  
  1064. CPR(P)                 Unsupported Software                 CPR(P)
  1065.  
  1066.  
  1067.  
  1068.      (The default is every 8 columns.) A _t_a_b_w_i_d_t_h of zero
  1069.      suppresses use of tabs; all output will be spaced using
  1070.      blanks.
  1071.  
  1072.      The option --pp pprrooppoorrttiioonn indicates what proportion of the
  1073.      page in steps of 16 should be used for deciding if a new
  1074.      function needs a new page.  That is -p12 (the default) indi-
  1075.      cates that if a function starts within the top 12/16 (3/4)
  1076.      of the page then do it, otherwise put it on a new page.
  1077.      Thus the higher the number (up to 16) the closer to the bot-
  1078.      tom of the page will functions be started.  --pp00 says put
  1079.      each function on a new page.
  1080.  
  1081. FFIILLEESS
  1082.      /tmp/cpr$$          - temp files holding text
  1083.  
  1084. SSEEEE AALLSSOO
  1085.      cb(1), cat(1), fold(1), num(1), pr(1)
  1086.  
  1087. DDIIAAGGNNOOSSTTIICCSS
  1088.      Various messages about being unable to open files.  Self
  1089.      explanatory.
  1090.  
  1091. BBUUGGSS
  1092.      This program sometimes thinks some declarations are func-
  1093.      tions.  Functions declarations whose opening ( is not found
  1094.      on the same line as the function name will not be recognized
  1095.      as functions.  Use of macros to define functions will also
  1096.      confuse it.  Comments are not recognized, and #ifdef's are
  1097.      not processed, so stuff inside them gets interpreted.  If
  1098.      the same function definition appears multiple times on the
  1099.      same page, only one entry is made in the table of contents,
  1100.      to reduce the number of redundant entries.
  1101.  
  1102. AAUUTTHHOORR
  1103.      Paul Breslin        original, Human Computing Resources
  1104.                          Corp.
  1105.  
  1106.      Rick Wise           sorting and use of standard input, CAL-
  1107.                          CULON Corp.
  1108.  
  1109.      David Wasley        numbering, times, etc., U. C. Berkley.
  1110.  
  1111.      Patrick Powell      variable number of lines between func-
  1112.                          tions, University of Waterloo
  1113.  
  1114.      Ian! D. Allen       variable tabs; redundant TOC suppres-
  1115.                          sion, University of Waterloo
  1116.  
  1117.      Dennis Vadura       more options; better function recogni-
  1118.                          tion, University of Waterloo
  1119.  
  1120.  
  1121.  
  1122.  
  1123. Formatted 89/02/07              UW                              2
  1124.  
  1125.  
  1126.  
  1127.  
  1128. CPR(P)                 Unsupported Software                 CPR(P)
  1129.  
  1130.  
  1131.  
  1132. SSUUPPPPOORRTT
  1133.      This software is _n_o_t supported by MFCF.
  1134.  
  1135.      Send complaints or suggestions to dvadura@dragon.
  1136.  
  1137.  
  1138.  
  1139.  
  1140.  
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.  
  1150.  
  1151.  
  1152.  
  1153.  
  1154.  
  1155.  
  1156.  
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187. Formatted 89/02/07              UW                              3
  1188. @//E*O*F cpr.p//
  1189. chmod u=rw,g=,o= cpr.p
  1190.  
  1191. echo x - cpr.t
  1192. sed 's/^@//' > "cpr.t" <<'@//E*O*F cpr.t//'
  1193. @.\" to produce the man page.
  1194. @.\" troff -man -Tdumb cpr.tf | ddumb >cpr.p
  1195. @.\"
  1196. @.TH CPR P UW 
  1197. @.SH "NAME"
  1198. cpr  \-  print 'C' files
  1199. @.SH "SYNOPSIS"
  1200. @.B public cpr
  1201. [-cCnNsS] [-T title] [-t tabwidth] [-p[num]] [-r[num]] [-l pagelength]
  1202. [[-f] file] ...
  1203. @.SH "DESCRIPTION"
  1204. @.I cpr
  1205. prints the files named in its argument list, preceding
  1206. the output with a table of contents.
  1207. If a filename is preceded by
  1208. @.B -f
  1209. then the specified file is assumed to contain a list of files to be
  1210. printed.  The filename "-" specifies standard input.
  1211. Each file printed is assumed to be C
  1212. source code (but doesn't have to be see -c option below)
  1213. in that the program searches
  1214. for the beginning and end of functions.
  1215. Function names are added to
  1216. the table of contents, provided the name starts at the beginning of
  1217. a line. The function name in the output is double struck.
  1218. @.PP
  1219. By default, blank lines are inserted after every closing '}'
  1220. character. Thus functions and structure declarations are nicely
  1221. isolated in the output. The only drawback to this is that structure
  1222. initialization tables sometimes produce lots of white space.
  1223. The \fB\-r\fP[n] option changes the space left to the specified
  1224. number of lines.  If no number is specified, no space is left.
  1225. @.PP
  1226. The option \fB\-l\fP indicates that the following argument is to be
  1227. the page length used for output, rather
  1228. than the default 66 lines.
  1229. @.PP
  1230. The option \fB\-c\fP forces cpr to "look" for functions only in files
  1231. whose suffix ends in '.c'.
  1232. @.PP
  1233. The option \fB\-C\fP forces cpr to produce only a table of contents, the
  1234. file contents themselves are not printed.
  1235. @.PP
  1236. The option \fB\-T title\fP causes cpr to print the contents of the file
  1237. @.B title
  1238. before printing the table of contents.
  1239. @.PP
  1240. The option \fB\-s\fP indicates that the table of contents should be sorted
  1241. by function name within each file.
  1242. Specifying \fB\-S\fP performs the sort in a case-insensitive manner.
  1243. @.PP
  1244. The option \fB\-n\fP indicates that output lines should be numbered with
  1245. the corresponding line number from the input file.
  1246. @.PP
  1247. The option \fB\-N\fP forces page numbering to start with page 1 for each
  1248. file processed.
  1249. @.PP
  1250. The option \fB\-t\fI\ tabwidth\fR
  1251. causes output to be produced that will look correct with tabs expanded every
  1252. @.I tabwidth
  1253. columns.
  1254. (The default is every 8 columns.)
  1255. A
  1256. @.I tabwidth
  1257. of zero suppresses use of tabs; all output will be spaced using blanks.
  1258. @.PP
  1259. The option
  1260. @.B -p proportion
  1261. indicates what proportion of the page in steps of 16
  1262. should be used for deciding if a new function needs a new page.
  1263. That is -p12 (the default) indicates that if a function starts
  1264. within the top 12/16 (3/4) of the page then do it, otherwise put it
  1265. on a new page.
  1266. Thus the higher the number (up to 16) the closer to
  1267. the bottom of the page will functions be started.
  1268. @.B -p0
  1269. says put each function on a new page.
  1270. @.SH "FILES"
  1271. @.nf
  1272. /tmp/cpr$$        \- temp files holding text
  1273. @.fi
  1274. @.SH "SEE ALSO"
  1275. cb(1), cat(1), fold(1), num(1), pr(1)
  1276. @.SH "DIAGNOSTICS"
  1277. Various messages about being unable to open files.
  1278. Self explanatory.
  1279. @.SH "BUGS"
  1280. This program sometimes thinks some declarations are functions.
  1281. Functions declarations whose opening ( is not found on the same line
  1282. as the function name will not be recognized as functions.
  1283. Use of macros to define functions will also confuse it.
  1284. Comments are not recognized, and #ifdef's are not processed,
  1285. so stuff inside them gets interpreted.
  1286. If the same function definition appears multiple times on the same page,
  1287. only one entry is made in the table of contents, to reduce the number
  1288. of redundant entries.
  1289. @.SH "AUTHOR"
  1290. @.IP "Paul Breslin" 2.0i
  1291. original, Human Computing Resources Corp.
  1292. @.IP "Rick Wise" 2.0i
  1293. sorting and use of standard input, CALCULON Corp.
  1294. @.IP "David Wasley" 2.0i
  1295. numbering, times, etc., U. C. Berkley.
  1296. @.IP "Patrick Powell" 2.0i
  1297. variable number of lines between functions, University of Waterloo
  1298. @.IP "Ian! D. Allen" 2.0i
  1299. variable tabs; redundant TOC suppression, University of Waterloo
  1300. @.IP "Dennis Vadura" 2.0i
  1301. more options; better function recognition,
  1302. University of Waterloo
  1303. @.SH SUPPORT
  1304. This software is
  1305. @.I not
  1306. supported by
  1307. @.SM MFCF.
  1308. @.PP
  1309. Send complaints or suggestions to dvadura@dragon.
  1310. @//E*O*F cpr.t//
  1311. chmod u=rw,g=,o= cpr.t
  1312.  
  1313. exit 0
  1314. -- 
  1315. --------------------------------------------------------------------------------
  1316. Dennis Vadura, Computer Science Dept.,          UUCP,BITNET:    dvadura@water
  1317. University of Waterloo, Waterloo, Ont.            EDU,CDN,CSNET:  dvadura@waterloo
  1318. ================================================================================
  1319.  
  1320. -- 
  1321. --------------------------------------------------------------------------------
  1322. Dennis Vadura, Computer Science Dept.,          UUCP,BITNET:    dvadura@water
  1323. University of Waterloo, Waterloo, Ont.            EDU,CDN,CSNET:  dvadura@waterloo
  1324. ================================================================================
  1325.  
  1326.  
  1327.