home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / cpr < prev    next >
Text File  |  1989-03-20  |  32KB  |  1,319 lines

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