allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (11/27/89)
Posting-number: Volume 9, Issue 10 Submitted-by: dmt@pegasus.ATT.COM (Dave Tutelman) Archive-name: cpr_dt : This is a shar archive. Extract with sh, not csh. : The rest of this file will extract: : readme cpr.c parsargs.c list.c fold.c report.c wildfile.c cpr.h makefile echo extracting - readme sed 's/^X//' > readme << '!EOR!' X X README FILE FOR CPR X ^^^^^^^^^^^^^^^^^^^ X XOK, we gotta have a README file, so you can tell what this does and Xwhere it came from. Well, I pulled it off the net myself early this Xyear (1989), and found it sort of useful. It's a pretty-printer for XC programs. X XWHAT IT DOES: X - Paginates, with meaningful page headers. X - Makes a table of contents for files and functions. X - Won't start a function at the bottom of a page. (In fact, X has an option to print only one function per page.) X XWHAT IT DOESN'T DO: X - Indent. X - Put brackets on separate lines. X - Other stuff that "C beautifiers" do. X XWhen I inherited a couple of pretty big C programs to maintain, the Xfirst thing I did was to try to get a bunch of listings with CPR. I Xfound that CPR as I received it wasn't up to the job. It certainly Xwas after I added a few enhancements. Here's the enhanced version, Xcast back upon the waters of the net. The enhancements are: X X - Any arguments can appear in a file rather than on the command X line, and in pretty free form. (As received, you could only have X filename arguments in a file, one name per line.) X - The table of contents can contain a single sorted index of X all functions across all files. X - The option "-?" will give a help screen for the options X (more like the PC idiom than the usual UNIX utility). X - Lines can be "intelligently" folded if they go beyond the X width of a page. (You wouldn't believe this program I X inherited, and its 160-column lines.) X XThis remains public domain, which is as I found it. (It's free, and Xworth every penny :-) X X Dave Tutelman XPHYSICAL: 16 Tilton Drive AT&T Bell Labs X Wayside, NJ 07712 Lincroft, NJ 07738 XAUDIBLE: (201) 922-9576 (201) 576-2194 XLOGICAL: att!pegasus!dmt X XContributors to the code include: X * Written by: X * Paul Breslin X * Human Computing Resources Corp. X * 10 St. Mary St. X * Toronto, Ontario X * Canada, M4Y 1P9 X * X * -- ...!decvax!utcsrgv!hcr!phb X * X * Sorting and standard input reading from: X * Rick Wise, CALCULON Corp., Rockville, MD. X * -- ...!decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise X * X * File modified time, X * numbered output, X * optional white space, X * improved function start tests from: X * David Wasley, U.C.Berkeley X * -- ...!ucbvax!topaz.dlw X * X * Modified the -r to leave variable amounts of space X * Patrick Powell, U. Waterloo X * X * Changed handling of form feeds to start a new page AND print heading: X * Terry Doner, U of Waterloo X * X * Fixed up to locate more functions, and added -p option X * Dennis Vadura, U of Waterloo X * X * It will find things like struct foo *f()... X * but not things like int X * f X * ()... X * ie. the constraint is that the () must appear on the same line X * as the function name. X * X * Clean up a bit for 80286 machines (lints a bit cleaner, too) X * Dan Frank, Prairie Computing X * X * Fixed a whole bunch of stuff and added lots of new flags. X * -S sort and be case insensitive. X * -N start numbering pages at 1 for each new file X * -T title cat the file title before the table of contents. X * -C print only the table of contents X * -c only try to look for function names in files whose suffix ends X * in .c X * -f file to handle file containing list of files to print. (for MSDOS) X * Dennis Vadura X * X * Set to work better in MS-DOS (and Turbo C). X * Ported to Turbo C on MS-DOS. X * Enabled wildcard expansion for systems that don't support it. X * Broke BIG source file into several C files plus header. X * Fixed argument parsing to be more forgiving. X * Changed -f option to handle all args in a free-form file, X * not just filenames. X * Added options: X * -? Help screen. X * -x,-X Sort TOC across files, giving function index (xref-like?). X * -w (n) Fold lines to a page width (fairly good-looking line folding). X * Dave Tutelman - att!pegasus!dmt - 10/89 X X !EOR! echo extracting - cpr.c sed 's/^X//' > cpr.c << '!EOR!' X/* CPR - Pretty-Printer for C programs X * X * This program prints the files named in its argument list, preceding X * the output with a table of contents. Each file is assumed to be C X * source code (but doesn't have to be) in that the program searches X * for the beginning and end of functions. Function names are added to X * the table of contents, provided the name starts at the beginning of X * a line. The function name in the output is double striken. X * X * PAGE SIZE X * The option "-l" indicates that the following argument is to be X * the page length used for output (changing the page length hasn't been X * tested much). X * The option "-w" indicates that the following argument is to be X * the page width (and lines are folded to that width, using a X * reasonably aesthetic folding algorithm). The default, in the X * absence of "-w" is not to fold lines. X * X * NUMBERING OF LINES & PAGES X * The option "-n" indicates that output lines should be numbered with X * the corresponding line number from the input file. X * The option "-N" indicates that page numbers start at 1 within each X * file. X * X * FORMATTING THE PROGRAM X * The option "-p" indicates what proportion of the page in steps of 16 X * should be used for deciding if a new function needs a new page. X * That is -p12 (the default) indicates that if a function starts X * within the top 12/16 (3/4) of the page then do it, otherwise put it X * on a new page. Thus the higher the number (upto 16) the closer to X * the bottom of the page will functions be started. -p0 says put each X * func on a new page. X * X * By default blank space is inserted after every closing '}' X * character. Thus functions and structure declarations are nicely X * isolated in the output. The only drawback to this is that structure X * initialization tables sometimes produce lots of white space. X * The "-r" option removes this space, or changes it to the indicated X * length. X * X * TABLE OF CONTENTS OPTIONS X * The option "-s" indicates that the table of contents should be sorted X * by function name within each file. X * The option "-S" also calls for a sorted table of contents, but with X * a case-insensitive sort. X * The option "-x" indicates that the table of contents should include X * a sorted index of functions across all files. X * The option "-X" also calls for a sorted index of functions, but with X * a case-insensitive sort. X * X * The option "-C" indicates that ONLY the table of contents is to X * be printed, not the source files themselves. X * X * The option "-c" indicates that only files with the extension ".c" X * should be examined for files to list in the table of contents. X * X * The option "-T" indicates that the following argument is a file X * name; the contents of that file is to be printed verbatim in the X * output before the table of contents, as a Title Paragraph. X * X * MISCELLANEOUS OPTIONS X * The option "-?" indicates that a help screen for CPR be sent X * to stderr (generally the screen), but no processing done. X * The help screen is more verbose than the usage message that's X * printed on error, and summarizes all options of CPR. X * X * The option "-f" indicates that the following argument is a file X * name; the contents of that file are to be treated just as command X * line arguments. (Thus you can, for example, make a ".cprrc" file X * with the right options and source files, in each of your X * source directories.) X * X * HISTORY X * X * Written by: X * Paul Breslin X * Human Computing Resources Corp. X * 10 St. Mary St. X * Toronto, Ontario X * Canada, M4Y 1P9 X * X * -- ...!decvax!utcsrgv!hcr!phb X * X * Sorting and standard input reading from: X * Rick Wise, CALCULON Corp., Rockville, MD. X * -- ...!decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise X * X * File modified time, X * numbered output, X * optional white space, X * improved function start tests from: X * David Wasley, U.C.Berkeley X * -- ...!ucbvax!topaz.dlw X * Modified the -r to leave variable amounts of space X * Patrick Powell, U. Waterloo X * X * Changed handling of form feeds to start a new page AND print heading: X * Terry Doner, U of Waterloo X * X * Fixed up to locate more functions, and added -p option X * Dennis Vadura, U of Waterloo X * X * It will find things like struct foo *f()... X * but not things like int X * f X * ()... X * ie. the constraint is that the () must appear on the same line X * as the function name. X * X * Clean up a bit for 80286 machines (lints a bit cleaner, too) X * Dan Frank, Prairie Computing X * X * Fixed a whole bunch of stuff and added lots of new flags. X * -S sort and be case insensitive. X * -N start numbering pages at 1 for each new file X * -T title cat the file title before the table of contents. X * -C print only the table of contents X * -c only try to look for function names in files whose suffix ends X * in .c X * -f file to handle file containing list of files to print. (for MSDOS) X * Dennis Vadura X * X * Set to work better in MS-DOS (and Turbo C). X * Ported to Turbo C on MS-DOS. X * Enabled wildcard expansion for systems that don't support it. X * Broke BIG source file into several C files plus header. X * Fixed argument parsing to be more forgiving. X * Changed -f option to handle all args in a free-form file, X * not just filenames. X * Added options: X * -? Help screen. X * -x,-X Sort TOC across files, giving function index (xref-like?). X * -w (n) Fold lines to a page width (fairly good-looking line folding). X * Dave Tutelman - att!pegasus!dmt - 10/89 X */ X X#include <sys/types.h> X#include <ctype.h> X#include <stdio.h> X#include <signal.h> X#include <string.h> X Xchar *synopsis [] = { X"OPTIONS:", X"-c Look for functions only if file is a '.c' file.", X"-C Produce ONLY table of contents, no listing.", X"-n Number lines in the listing.", X"-N Start each file listing on page 1.", X"-s Sort table of contents by function name (in each file).", X"-S Like -s, but case-insensitive.", X"-x,-X Like -s, -S, but sorts across files (Xref-like function index).", X"-l n Page length. (Default = 66)", X"-w n Page width, at which to fold lines. (Default = don't fold lines)", X"-p n How many 16ths of a page can be used, and still start a new function", X" on this page? (-p0 puts a new function on each page. Default = 12)", X"-r n How many blank lines to leave after a '}'. (Default = 5)", X"-t n Width of a tab stop. (Default = 8)", X"-T title Print contents of file 'title' before table of contents.", X"-f argfile Take next few arguments from file 'argfile'.", X"- File name for the Standard Input.", X'\0' X}; X X#define MAIN X#include "cpr.h" X X/* Some macros for parsing parameters from the argument list */ X#define NEXPARM NexParm (&i,&parm, argc,argv) X#define NUMPARM NumParm (&i,&parm, argc,argv) X#define STRPARM StrParm (&i,&parm, argc,argv) X X#ifdef NOWILD Xint NextName=0; /* Use next_file function to expand wildcard */ Xchar *first_file(), *next_file(); X#endif X Xchar *GetProgName(); Xchar *StrParm(); X Xmain(argc, argv) Xchar **argv; X{ X int i; X char *ctime(); X time_t thetime, time(); X char *parm; /* points to next thing to do in an arg */ X int num; X int FirstFile=1; X X ProgName = GetProgName (argv[0]); X thetime = time((time_t *)0); X strcpy(Today,ctime(&thetime)); X X if (argc < 2) Synop(); X X i = 0; X while ((i = NEXPARM) >0) /* get next argument if there is one */ X { X if( arg[0] == '?' X && arg[1] == '\0' ) Synop(); X X if( arg[0] != '-' || arg[1] == '\0' ) { /* file name */ X parm--; /* back off to get whole name */ X Name = STRPARM; X if (NULLSTR( Name )) Usage(); X if (FirstFile) { X FirstFile=0; X StartTempFile(); X } X DoFile (Name); X } X X else { /* this arg is options */ X switch( *parm ) { X case '-': X break; /* skip. just leading - for options */ X X case '\0': /* check for end of this argument */ X case ' ': /* just for safety. */ X case '\t': X case '\n': X case '\r': X break; X X case '?': Synop(); X X case 'f': /* get next args from a file */ X listn = STRPARM; /* get next string parameter */ X if (NULLSTR( listn )) Usage(); X if ((listf = fopen (listn, "r")) == NULL) { X fprintf(stderr,"%s: list file '%s' not found\n", X ProgName, listn); X exit (1); X } X InArgFile = 1; X break; X X case 't': X TabWidth = NUMPARM; X if( TabWidth == -1) TabWidth = 0; X if( TabWidth < 0 ) TabWidth = 0; X break; X X case 'T': X TitleFile = STRPARM; X if (NULLSTR( TitleFile )) Usage(); X if ((Tfile = fopen (TitleFile, "r")) == NULL) { X fprintf(stderr,"%s: title file '%s' not found\n", X ProgName, TitleFile); X exit (1); X } X ++Title; X break; X X case 'l': X PageLength = NUMPARM; X if( PageLength == -1) Usage(); X if( PageLength < 10) PageLength = 10; X PageEnd = PageLength - ((PageLength > 30) ? 7 : 1); X break; X X case 'w': X PageWidth = NUMPARM; X if( PageWidth == -1 ) Usage(); X if( PageWidth < 0 ) PageWidth = 0; X break; X X case 'S': X ++CaseInsensitive; X case 's': X ++SortFlag; X break; X X case 'X': X ++CaseInsensitive; X case 'x': X ++SortFlag; X ++XrefFlag; X if (ResetPage) { X fprintf(stderr,"%s: options -X and -N are incompatible\n", X ProgName); X exit (1); X } X break; X X case 'C': X ++ContentsOnly; X break; X X case 'c': X ++OnlyCFiles; X break; X X case 'n': X ++NumberFlag; X FirstCol = FORMATWIDTH; /* leave room for line numbering */ X break; X X case 'N': X ++ResetPage; X if (XrefFlag) { X fprintf(stderr,"%s: options -X and -N are incompatible\n", X ProgName); X exit (1); X } X break; X X case 'r': X Space_to_leave = NUMPARM; X if (Space_to_leave == -1) Space_to_leave = 0; X if (Space_to_leave < 0) Space_to_leave = 0; X break; X X case 'p': X PagePart = NUMPARM; X if ( PagePart == -1) Usage(); X if ( PagePart < 0) PagePart = 0; X if ( PagePart > 16) PagePart = 16; X break; X X default: X Usage(); X break; X } /* end 'switch' */ X } /* end 'else' */ X } /* end 'while' */ X X /* All files processed. Print the listings. */ X if( PageNumber > 1 || LineNumber > 0 ) X putchar(BP); X EndTempFile(); X X DumpTableOfContents(); X DumpTempFiles(); X Done(); X} X XUsage() X{ X fprintf(stderr, "%s: Problem with argument %s", ProgName, arg); X if (InArgFile) fprintf(stderr, " in argument file\n"); X else fprintf(stderr, "\n"); /* yeah, I know ... */ X fprintf(stderr, "Usage: %s [-?cCnNsSxX] [-t tabwidth] [-l pagelength] ",ProgName); X fprintf(stderr, "[-w pagewidth]\n\t[-p[num]] [-r[num]] [-T title] [[-f] file] ..."); X exit(1); X} X XSynop() X{ X int i; X X fprintf(stderr,"Synopsis:\n%s [options] [filenames]\n\n", ProgName); X for (i=0; *synopsis[i] != '\0'; i++) X fprintf (stderr,"%s\n",synopsis[i]); X exit(1); X} X Xchar * XGetProgName (s) /* We need to strip off path information, if there */ Xchar *s; X{ X char *p; X X for (p=s; *p!='\0'; p++); /* get end of string */ X while (--p >= s) { X#ifdef MSDOS X if (*p == '.') X *p='\0'; /* strip off .EXE extension */ X#endif X if ((*p=='/') || (*p=='\\')) X break; X } X return (++p); X} X X X/* Do the processing necessary to format one file */ XDoFile (fname) X char *fname; X{ X if (*fname=='-' && *(fname+1)=='\0') { X File = stdin; X Name = "Standard Input"; X List(); X return; X } X#ifndef NOWILD X if( (File = fopen( fname, "r" )) == NULL ) X { X fprintf(stderr,"%s: Can't open file '%s': %s\n", X ProgName, Name, sys_errlist[errno] ); X } X List(); X fclose(File); X X#else /* expand wildcards explicitly */ X Name = first_file (fname); X while ((Name != NULL) && (*Name != '\0')) { X if( (File = fopen( Name, "r" )) == NULL ) X { X fprintf(stderr,"%s: Can't open file '%s': %s\n", X ProgName, Name, sys_errlist[errno] ); X continue; X } X List(); X fclose(File); X X Name = next_file (); X } X#endif X} X X Xint SaveOut; Xchar *TempName; Xchar *Temp2Name; X XStartTempFile() X{ X int Done(); X extern char *mktemp(); X X CatchSignalsPlease(Done); X X SaveOut = dup(1); X#ifdef MSDOS X TempName = "cpr0001.tmp"; X#else X TempName = mktemp("/tmp/cprXXXXXX"); X#endif X if( freopen(TempName, "w", stdout) == NULL ) X { X fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName, X TempName, sys_errlist[errno]); X exit(1); X } X} X XEndTempFile() X{ X#ifdef MSDOS X Temp2Name = "cpr0002.tmp"; X#else X Temp2Name = mktemp("/tmp/cprXXXXXX"); X#endif X if( freopen(Temp2Name, "w", stdout) == NULL ) X { X fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName, X Temp2Name, sys_errlist[errno]); X exit(1); X } X} X XDumpTempFiles() X{ X FILE *f; X char b[256]; X register int pid, w; X X fclose(stdout); X X#ifndef MSDOS X dup(SaveOut); X while( (pid = fork()) < 0 ) sleep(1); X if( pid ) X while ((w = wait((int *)0)) != pid && w != -1); X else X { X CatchSignalsPlease(SIG_DFL); X X if( ContentsOnly ) X execl( "/bin/cat", "cat", Temp2Name, (char *)0 ); X else X execl( "/bin/cat", "cat", Temp2Name, TempName, (char *)0 ); X fprintf(stderr, "%s: exec of /bin/cat failed: %s\n", ProgName, X sys_errlist[errno]); X exit(0); X } X#else X CatchSignalsPlease(SIG_DFL); X if( (f=fopen(Temp2Name,"r")) == NULL ) X fprintf(stderr,"%s: Can't open file '%s': %s\n", X ProgName, TitleFile, sys_errlist[errno] ); X else X { X while( fgets(b, 256, f) != NULL ) X write(SaveOut,b,strlen(b)); X X fclose(f); X } X X if( !ContentsOnly ) X if( (f=fopen(TempName,"r")) == NULL ) X fprintf(stderr,"%s: Can't open file '%s': %s\n", X ProgName, TitleFile, sys_errlist[errno] ); X else X { X while( fgets(b, 256, f) != NULL ) X write(SaveOut,b,strlen(b)); X X fclose(f); X } X#endif X} X XDone() X{ X CatchSignalsPlease(SIG_DFL); X X fclose( stdout ); X if( TempName ) unlink( TempName ); X if( Temp2Name ) unlink( Temp2Name ); X X exit(0); X} X XCatchSignalsPlease(action) Xvoid (*action)(); X{ X#ifndef TURBOC X if( signal(SIGINT, SIG_IGN) != SIG_IGN ) signal(SIGINT, action); X#else /* TURBOC */ X signal (SIGINT, action); X#endif X#ifndef MSDOS X if( signal(SIGQUIT, SIG_IGN) != SIG_IGN ) signal(SIGQUIT, action); X if( signal(SIGHUP, SIG_IGN) != SIG_IGN ) signal(SIGHUP, action); X#endif X} X !EOR! echo extracting - parsargs.c sed 's/^X//' > parsargs.c << '!EOR!' X/* PARSARGS X * X * Functions to get parameters from: X * - The command line. X * - The argument file (if -f option is used). X */ X X#include <stdio.h> X#include <ctype.h> X#include "cpr.h" X X X/* Get the next parameter, and point to it with *pp. X * Return current index into argv[], or -1 if no more parameters. X * Put NEW argument into arg[], but just bump *pp if there's still X * more to do in arg[]. X * Get NEW argument from argv[] or list file, depending on InArgFile. X */ X Xint XNexParm (ip,pp, argc,argv) X int *ip; /* pointer to arg[] index */ X char **pp; /* pointer to parm, which is (char *) */ X int argc; X char *argv[]; X{ X int i = *ip; X char *p = *pp; X int c; X int InArg = 0; /* state variable */ X int GotArg = 0; X X if (i==0) { /* need to initialize */ X strcpy (arg, argv[1]); X *pp = arg; X *ip = 1; X return (1); X } X X p++; /* bump the parameter pointer */ X X if (WHITESPACE( *p )) { /* need a new arg */ X arg[0] = '\0'; /* blank the beginning of the arg[] array */ X if (InArgFile) { /* get the new arg from listf */ X p = arg; X while (!GotArg) { X c=getc (listf); X if (!InArg) { X if (c == EOF) { /* no more in listf */ X InArgFile = 0; X GotArg++; X } X else if (!WHITESPACE( (char)c )) InArg++; X } X if (InArg) { X if (WHITESPACE( (char)c ) || c==EOF) { X *p = '\0'; X GotArg++; X } X else if (!WHITESPACE( (char)c )) *p++ = c; X } X } /* end while (!GotArg) */ X } /* end if (InArgFile) */ X X if (arg[0]=='\0') { /* get the new arg from command line */ X if (++i >= argc) return (-1); X strcpy (arg, argv[i]); X *ip = i; X GotArg++; X } X *pp = arg; X } /* end of "need new arg" */ X X else if (!GotArg) /* not a new arg, just bump pointer */ X *pp = p; X X return ( i ); X} X Xint XNumParm (ip, pp, argc,argv) /* Returns next parameter as an integer if it X * is a number. Otherwise returns -1. */ X int *ip; /* pointer to argument counter in main program */ X char **pp; /* pointer to "parm" pointer in main program */ X int argc; X char *argv[]; X{ X int num=0; /* number accumulator */ X int i; X char *p; X X /* Bump to next parm, if there is one */ X i = NexParm( ip, pp, argc, argv ); X if (i <= 0) return (-1); X X p = *pp; /* use updated parm pointer */ X X /* is there at least one digit? */ X if (!isdigit( *p )) { X *pp = p-1; /* back off to previous position */ X return (-1); X } X X /* accumulate a decimal number */ X while (isdigit( *p )) X num = 10*num + (int)(*p++ - '0'); X X /* fix up pointers before returning */ X *pp = p-1; /* back off to end of number */ X return (num); X} X X Xchar * XStrParm (ip, pp, argc,argv) /* Returns next string parameter if there X * is one. Otherwise returns -1. */ X int *ip; /* pointer to argument counter in main program */ X char **pp; /* pointer to "parm" pointer in main program */ X int argc; X char *argv[]; X{ X int i; X char *p, *s; X X /* Bump to next parm, if there is one */ X i = NexParm( ip, pp, argc, argv ); X if (i <= 0) return (NULL); X X s = p = *pp; /* use updated parm pointer */ X if (WHITESPACE( *p )) return (NULL); X X /* Find end of string and null it out */ X while (! WHITESPACE( *p )) p++; X *p = '\0'; /* now null-terminate the string */ X X /* fix up pointers before returning */ X *pp = p-1; /* back off to end of string */ X return (s); X} X !EOR! echo extracting - list.c sed 's/^X//' > list.c << '!EOR!' X/* LIST.C X * X * Functions that go through the .C files, X * parse them, and make entries in Table of Contents. X */ X X#include <stdio.h> X#include <ctype.h> X#include <string.h> X#include "cpr.h" X Xint SawFunction; Xint Braces; X X XList() X{ X register int bp; X register char *bufp; X char buffer[256]; X X NewFile(); X bp = Braces = 0; X InString = InComment = 0; /* reset for new file -DV */ X SawFunction = 0; X bufp = buffer; X while( fgets(bufp, sizeof(buffer), File) != NULL ) X { X ++FileLineNumber; X if( bp ) NewFunction(); X X if( ++LineNumber >= PageEnd ) NewPage(); X X if( bufp[0] == '\f' X && bufp[1] == '\n' X && bufp[2] == '\0' ) X { X NewPage(); /* was strcpy(bufp, "^L\n");*/ X continue; X } X X if( NumberFlag ) X { X if( *bufp == '\n' ) X printf(BLANKFORMAT); X else X printf(NUMFORMAT, FileLineNumber); X } X if( (Braces == 0) && LooksLikeFunction(bufp) ) X AddToTableOfContents(NEWFUNCTION); X X bp = ScanLine(buffer); X } X} X XScanLine(l) Xregister char *l; X{ X extern char *EndComment(); X extern char *EndString(); X register char c; X int bp; X char *save; X X /* initialize line-checking variables */ X bp = 0; X X /* Now scan the line */ X for( save = l; c = *l; ++l ) X if( InComment ) X l = EndComment(l); X else if( InString ) X l = EndString(l); X else X switch(c) X { X case '{': X ++Braces; X break; X X case '}': X if( --Braces == 0 ) X bp = 1; X break; X X case '\'': X for( ++l; *l && *l != '\''; ++l ) X if( *l == '\\' && *(l+1) ) ++l; X break; X X case '"': X InString = 1; X break; X X case '/': X if( *(l+1) == '*' ) X { X InComment = 1; X ++l; X } X break; X } X if (PageWidth) FoldLine( save ); X OutputLine( save ); X return(bp); X} X Xchar * XEndComment(p) Xregister char *p; X{ X register char c; X X /* X * Always return pointer to last non-null char looked at. X */ X while( c = *p++ ) { X if( c == '*' && *p == '/' ) X { X InComment = 0; X return(p); X } X } X return(p-2); X} X Xchar * XEndString(p) Xregister char *p; X{ X register char c; X X /* X * Always return pointer to last non-null char looked at. X */ X while( c = *p++ ) { X if( c == '\\' && *p ) X { X ++p; X continue; X } X else if( c == '"' ) X { X InString = 0; X return(p-1); X } X } X return(p-2); X} X XNewFunction() X{ X register int i; X X if( Space_to_leave <= 0 || !SawFunction ) return; X if( LineNumber + Space_to_leave > (PageLength * PagePart /16) ) X NewPage(); X else X { X for( i=0; i < (Space_to_leave); ++i ) putchar('\n'); X LineNumber += Space_to_leave; X } X X SawFunction = 0; X} X X#define isidchr(c) (isalnum(c) || (c == '_')) X X/* This used to incorrectly identify a declaration such as X * int (*name[])() = { initializers ... } X * as a function. It also picked up this in an assembler file: X * #define MACRO(x) stuff X * MACRO(x): X * Fixed both of these. -IAN! X */ XLooksLikeFunction(s) Xregister char *s; X{ X register char *p; X register int i; X char *save; X int t = TabWidth; X X if( InComment || InString ) return(0); X if( OnlyCFiles ) X { X char *e = Name+strlen(Name)-1; X if(( *e != 'c' X#ifdef MSDOS X && *e != 'C' X#endif X ) || e[-1] != '.' ) return(0); X } X X if( !t ) t = 8; X save = s; X X i = 0; X do X { X p = FunctionName; X X while( *s && (*s == ' ') || (*s == '\t') ) ++s; X if( *s == '*' ) ++s; X if( *s && (*s == ' ') || (*s == '\t') ) continue; X if( !*s || ((*s != '_') && !isalpha(*s)) ) return(0); X X while( isidchr(*s) ) X *p++ = *s++; X *p = '\0'; X X while( *s && (*s == ' ') || (*s == '\t') ) ++s; X i++; X } X while ( *s && *s != '(' && i < 4 ); X X if( *s != '(' || *(s+1) == '*' ) return(0); X X for (i = 0; *s; s++) X { X switch( *s ) X { X case '(': X ++i; X continue; X X case ')': X --i; X break; X X default: X break; X } X if( i == 0 ) break; X } X if( !*s ) return(0); X X while( *s ) X { X if( *s == '{') break; X if( *s == ';' || *s == ':' ) return(0); X ++s; X } X X /* X * This will cause the function name part of the line to X * be double striken. Note that this assumes the name and the opening X * parentheses are on the same line... X */ X X if( p = strchr( save, '(' ) ) X { X p--; X while( p != save && isidchr( *(p-1) ) ) p--; X for( i=0; save != p; save++ ) X if( *save == '\t' ) X { X putchar('\t'); X i = ((i+t)/t)*t; X } X else X { X putchar(' '); X i++; X } X X for( ; *p != '('; p++ ) X if( *p == '\t' ) X { X putchar('\t'); X i = ((i+t)/t)*t; X } X else X { X putchar(*p); X i++; X } X } X else X for( i=0; *save && (*save == '*' || isidchr(*save)); ++save) X if( *save == '*' ) X { X putchar(' '); X i++; X } X else X { X if( *save == '\t' ) X i = ((i+t)/t)*t; X else X i++; X putchar(*save); X } X X while( i --> 0 ) putchar('\b'); X X SawFunction = 1; X return(1); X} !EOR! echo extracting - fold.c sed 's/^X//' > fold.c << '!EOR!' X/* FOLD X * X * Functions to fold an output line. X */ X X#include <stdio.h> X#include <string.h> X#include "cpr.h" X X/* The criteria for folding a line are, in order of aethetic desirability: */ X#define COMMENT 0 /* Comment starts here */ X#define BRACKET 1 /* Curly open bracket */ X#define SEMICOLON 2 /* First non-blank after semicolon */ X#define BLANK 3 /* First non-blank after whitespace */ X#define PAREN 4 /* Open parenthesis */ X#define N_CRIT 5 /* Number of criteria for folding a line */ X#define CLEAR_CRIT { int i; for(i=0;i<N_CRIT;i++) crit[i]=NULL; } X Xint NeedFold = 0; /* Number of folds needed for this line */ Xint FoldCol = -1; /* Proposed left edge of folded line */ Xchar *folds [64]; /* Places to fold the current line */ X Xchar *FoldHeuristic (); X X XFoldLine (s) /* Put Fold Marks in the right place in the line */ X char *s; X{ X char *p; X int i; X int col = 0; /* Current column in output line */ X char *NonBlank = NULL; /* First non-blank character */ X int CantFold = 0; /* Set it if we have trouble folding */ X X /* Set up array of pointers into the line of possible places to fold, X * in order of aesthetic desirability. */ X char *crit [N_CRIT]; X char *SemiWait = NULL, *BlankWait = NULL; X X CLEAR_CRIT; X FoldCol = -1; X NeedFold = 0; /* assume we won't need to fold line */ X X if (! PageWidth) return; /* Don't bother folding lines */ X X /* Step through line, looking for good places to fold */ X for (p=s; *p; p++) { X switch (*p) { X case '\n': /* ignore */ X break; X X case ' ': /* Whitespace is harmless */ X col++; X BlankWait = p; /* remember we've seen a blank */ X break; X X case '\t': /* Space out a tab's worth */ X while ((++col) % TabWidth); X col++; X BlankWait = p; /* remember we've seen a blank */ X break; X X case '/': X if (*(p+1) == '*') /* beginning of a comment */ X crit [COMMENT] = p; X col++; X break; X X case '{': X if (*(p-1) != '\'') X crit [BRACKET] = p; X col++; X break; X X case ';': /* Remember we've seen a semicolon */ X col++; X if (*(p-1) != '\'') X SemiWait = p; X break; X X case '(': X if (*(p-1) != '\'') X crit [PAREN] = p; X col++; X break; X X default: X col++; X break; X } X X /* If non-blank, do a few housekeeping things */ X if (*p!=' ' && *p!='\t' && *p!='\n') { X if (FoldCol == -1) { X NonBlank = p; X FoldCol = col + 1; X } X if (BlankWait) { /* waiting after blank */ X crit [BLANK] = p; X BlankWait = 0; X } X if (SemiWait && SemiWait!=p) { X crit [SEMICOLON] = p; X if (*p!=';') SemiWait = 0; X } X } X X /* Do we need to fold yet ? */ X if (col+FirstCol >= PageWidth && *p!=' ' && *p!='\t') { X /* Can we fold? We can tell by checking our pointers X * in order of decreasing aesthetic result of fold. X */ X char *FoldHere; X X FoldHere = FoldHeuristic (s, NonBlank, crit); X if (FoldHere) X folds [NeedFold++] = FoldHere; X else X CantFold++; X X /* Do some cleaning up after folding */ X if (FoldHere) { X col = FoldCol; X p = FoldHere; X X CLEAR_CRIT; X BlankWait = SemiWait = NULL; X } X } X } X if (CantFold) /* complain, but print anyway and continue */ X fprintf(stderr,"%s: trouble folding line %ld of file %s\n", X ProgName, FileLineNumber, Name); X} X X/* Output the line, folding where indicated in folds[] */ X XOutputLine (p) X char *p; X{ X int i = 0; X X if (! NeedFold) /* don't bother folding lines */ X printf ("%s",p); X X else { /* gotta fold lines */ X for (; *p; p++) { X if (p==folds[i] && i<NeedFold) { /* fold to a new line */ X putchar ('\n'); X if (++LineNumber >= PageEnd) NewPage(); X if (NumberFlag) X printf (BLANKFORMAT); X GoToColumn (FirstCol, FoldCol+FirstCol); X i++; X } X putchar (*p); X } X } X} X X/* Heuristic for determining where to fold */ X X#define MAX( x, y ) ((x) > (y)) ? x : y X#define MIN( x, y ) ((x) < (y)) ? x : y X#define MAXC( c, j ) for(i=j=0;i<N_CRIT;i++) if(c[i]>c[j]) j=i X Xchar * XFoldHeuristic (s, NonBlank, crit) X char *s; /* pointer to line */ X char *NonBlank; /* pointer to first non-blank character */ X char *crit[]; /* pointers to likely places to fold, based on X * aesthetic criteria */ X{ X int i,j; X int score [N_CRIT]; /* keep some "scores" here */ X int credit; /* score value increments (in columns) */ X char *lptr; /* points to start of partial line */ X char *p; X X /* For each crit[] pointer, it's worthless as a folding point if it's X * the first non-blank in the line. */ X for (i=0; i<N_CRIT; i++) X if (crit[i]==NonBlank) crit[i] = NULL; X X /* Fold on a comment, if we've got one */ X if (crit [COMMENT]) return (crit [COMMENT]); X X /* For the rest, we'll compute some heuristic "scores". X * Start by seeing how much of the partial line each crit picks up. */ X score [COMMENT] = 0; X if (NeedFold) /* line already folded */ X lptr = folds [NeedFold-1]; X else X lptr = NonBlank; X for (i=1; i<N_CRIT; i++) X if (crit [i]) X score [i] = crit [i] - lptr; X else score [i] = 0; X X /* Adjust the scores according to some "feel for aesthetics". X * Start by giving each criterion credit for its order in the array; X * "credit" is measured by the number of columns it's worth. X * We'll estimate a unit of "credit" as a fraction of the line X * that we're trying to fill. X */ X X credit = PageWidth - (lptr - s); /* width of current partial */ X credit = credit / 10; /* "arbitrary" fraction of line */ X for (i=1; i<N_CRIT; i++) X if (score [i]) X score [i] += (N_CRIT - i - 1) * credit; X X /* Next, see how "valuable" a paren is from its context. */ X if (p = crit [PAREN]) { X char *pp; X pp = p-1; X if (*pp==' ' || *pp=='\t') X score[PAREN] += 2 * credit; X else if (*pp=='(') { X /* Find the left edge of string of parens */ X while (--pp) { X if (pp < lptr) { X /* Parens all the way left. Quit */ X score[PAREN] -= credit; X break; X } X else if (*pp==' ' || *pp=='\t') { X /* Isolated! Point to it & give bonus */ X crit [PAREN] = pp+1; X score[PAREN] = (pp - lptr) + 1 + 2*credit; X break; X } X else if (*pp!='(') { X /* Nothing special. Point & give small bonus */ X crit [PAREN] = pp+1; X score[PAREN] = (pp - lptr) + credit; X break; X } X /* If we got here, keep searching */ X } X } X else /* Nothing special. Small bonus */ X score [PAREN] += credit - 1; X } X X /* Now, just return the highest score. */ X MAXC( score, j ); X return ( crit[j] ); X} X !EOR! echo extracting - report.c sed 's/^X//' > report.c << '!EOR!' X/* REPORT.C X * X * Prints out the table of contents and listed .C files. X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include <ctype.h> X#include <string.h> X X#include "cpr.h" X X#define HEADER_SIZE 3 X#define TOC_SIZE 4096 X Xstatic char *Toc[TOC_SIZE]; /* array of pointers to malloc-ed TOC strings */ Xstatic int TocPages[TOC_SIZE]; /* page on which the item occurs */ Xstatic int TocCount; /* how many TOC lines so far */ X Xchar FileDate[24]; /* Last modified time of file */ X X XNewPage() X /* Note that PageNumber is -1 during TableOfCont processing */ X{ X static int CountNewPage=0; /* suppress blank pre-page */ X X if( PageNumber >= 0 ) { X ++PageNumber; X putchar(BP); X } X else /* we're doing TOC */ X if( CountNewPage++ ) putchar(BP); /* don't put first BP */ X LineNumber = 0; X X PutHeader(); X} X XPutHeader() X{ X register int i, l, j; X X putchar('\n'); X ++LineNumber; X l = strlen(Name); X for( j=0; j < l; ++j ) X printf("%c\b%c\b%c", Name[j], Name[j], Name[j]); X X if( PageNumber > 0 ) X { X printf(" %.17s", FileDate); X GoToColumn(l+19, 70); X printf("Page:%4d\n\n", PageNumber); X ++LineNumber; X ++LineNumber; X } X else X { X GoToColumn(l, 55); X printf("%s\n\n", Today); X ++LineNumber; X ++LineNumber; X } X} X XGoToColumn(from, to) Xregister int from, to; X{ X if( from < to) X { X if( TabWidth > 0 ){ X from &= ~(TabWidth-1); X for( ; (from + TabWidth) <= to; from += TabWidth ) X putchar('\t'); X } X for( ; from < to; from++ ) X putchar(' '); X } X} X X XAddToTableOfContents(type) X{ X if( TocCount > TOC_SIZE ) X return; X if( TocCount == TOC_SIZE ) X { X fprintf(stderr, "%s: More than %d Table of contents entries; others ignored.\n", X ProgName, TOC_SIZE); X ++TocCount; X return; X } X X if( type == NEWFILE ) X AddFile(); X else X AddFunction(); X} X XAddFunction() X{ X register int l; X register char *p; X X /* This heuristic stops multiple occurrences of a function, X * selected by #ifdefs, to all end up many times over in the X * Table of Contents. One only needs to see it once. -IAN! X */ X if( TocCount > 0 && TocPages[TocCount-1] == PageNumber X && strcmp(Toc[TocCount-1],FunctionName) == 0 ) X return; X l = strlen(FunctionName); X p = Toc[TocCount] = (char *)malloc(l+1); X strcpy(p, FunctionName); X TocPages[TocCount] = PageNumber; X ++TocCount; X} X XAddFile() X{ X register int i, l; X register int len; X char temp[20]; X X len = strlen(Name) + 20; X len = (len < 130) ? 130 : len; X Toc[TocCount] = (char *)malloc(len); X sprintf(Toc[TocCount], "\n File: %s ", Name); X l = strlen(Toc[TocCount]); X if( l < 64 ) X { X if( TabWidth > 0 ){ X i = ((64 - l) /TabWidth) + 1; X while( i-- > 0 ) X Toc[TocCount][l++] = '\t'; X } X else{ X while( l < 64 ) X Toc[TocCount][l++] = ' '; X } X Toc[TocCount][l++] = '\0'; X } X sprintf(temp, " Page %4d\n", PageNumber); X strcat(Toc[TocCount], temp); X ++TocCount; X} X XNewFile() X{ X GetFileTime(); X if( ResetPage ) PageNumber=0; X NewPage(); X AddToTableOfContents(NEWFILE); X FileLineNumber = 0; X} X XGetFileTime() X{ X struct stat st; X extern char *ctime(); X X if( File == stdin ) X strncpy(FileDate, &Today[4], 20); X else X { X fstat(fileno(File), &st); X strncpy(FileDate, ctime((time_t *)&st.st_mtime) + 4, 20); X } X strncpy(&FileDate[12], &FileDate[15], 5); X FileDate[18] = '\0'; X} X XDumpTableOfContents() X{ X register int i, j; X int TocIncr = 0; X int index[TOC_SIZE]; X int Files = 0; /* How many files reported so far */ X int Functions = 0; /* How many functions reported so far? */ X int EveryFourth; X X if( TocCount == 0 ) return; X X for (i = 0; i < TocCount; i++) index[i] = i; X X if( XrefFlag ) { /* XREF - put files as first entries. X * SortTable() will do the rest. */ X FilesFirst (); X TocIncr = 1; /* start printing AFTER the \n */ X } X X if( SortFlag ) X SortTable(index); X X Name = "Table of Contents"; X X PageNumber = -1; X LineNumber = 0; X X if( Title ) X { X FILE *f; X int n; X char b[256]; X X if( (f=fopen(TitleFile,"r")) == NULL ) X fprintf(stderr,"%s: Can't open file '%s': %s\n", X ProgName, TitleFile, sys_errlist[errno] ); X else X { X while( fgets(b, 256, f) != NULL ) X { X if( strlen(b) ) b[strlen(b)-1]=0; X puts(b); X LineNumber++; X if( ++LineNumber >= PageEnd ) NewPage(); X } X X fclose(f); X } X } X else X NewPage(); X X for( i=0; i < TocCount; ++i ) X { X if( Toc[index[i]][0] == '\n' ) /* File entry */ X { X if( (LineNumber + 5) >= PageEnd ) NewPage(); X X /* Play with the leading \n in file entry */ X EveryFourth = ( !(Files++ & 3) && XrefFlag ); X printf("%s", Toc[index[i]]+TocIncr-EveryFourth); X LineNumber += 2 - TocIncr + EveryFourth; X continue; X } X else /* Function entry */ X { X if (! Functions++ && XrefFlag) { X printf( "\nFunction Index:\n"); X LineNumber += 2; X } X } X if( ++LineNumber >= PageEnd ) NewPage(); X X printf(" %s ", Toc[index[i]]); X for( j=strlen(Toc[index[i]]); j < 48; ++j ) putchar('.'); X printf(" %4d\n", TocPages[index[i]]); X } X X if( ContentsOnly ) NewPage(); X} X XFilesFirst () X{ X int i; X int FirstNonFile = 0; X char *Ctemp; X int Itemp; X X for (i=0; i<TocCount; i++) X if (Toc [i][0] == '\n') { /* swap file entry down */ X Ctemp = Toc [i]; X Toc [i] = Toc [FirstNonFile]; X Toc [FirstNonFile] = Ctemp; X X Itemp = TocPages [i]; X TocPages [i] = TocPages [FirstNonFile]; X TocPages [FirstNonFile] = Itemp; X X FirstNonFile++; X } X} X XSortTable(index) Xregister int *index; X{ X register int i, temp, flag; X char name1[256]; X char name2[256]; X X do { X flag = 0; X for (i = 0; i < TocCount - 1; i++) X { X if( Toc[index[i]][0] == '\n' || Toc[index[i+1]][0] == '\n' ) X continue; /* don't sort across file names */ X strcpy( name1, Toc[index[i]] ); X strcpy( name2, Toc[index[i+1]] ); X X if( CaseInsensitive ) X { X char *p; X char c; X for(p=name1; c=*p; p++ ) X if( islower(c) ) *p=toupper(c); X for(p=name2; c=*p; p++ ) X if( islower(c) ) *p=toupper(c); X } X X if( strcmp(name1, name2) > 0) X { X temp = index[i]; X index[i] = index[i+1]; X index[i+1] = temp; X flag = 1; X } X } X } X while( flag ); X} X !EOR! echo extracting - wildfile.c sed 's/^X//' > wildfile.c << '!EOR!' X/* Expand wildcards (e.g., for MSDOS, which doesn't do it for you). X * Note that the MSDOS wildcard conventions are used, not the X * UNIX conventions. X * X * The following code is a prototype of the use of these functions, X * if 'fname' points to the [wildcarded] name of the file: X * X * #ifdef NOWILD X * strncpy (fname, first_file (fname), MAXNAME); X * while ((fname!=NULL) && (*fname!='\0')) { X * process_file (fname); X * strncpy (fname, next_file (fname), MAXNAME); X * } X * #else X * process_file (fname); X * #endif X * X * This file is an example of these functions for Turbo C. X * (It isn't needed for Turbo C 2.0, but may be for earlier ones.) X */ X X#include <stdio.h> X X#ifdef NOWILD X#ifdef TURBOC X X#include <dos.h> X#include <dir.h> X Xstruct ffblk fb; Xchar fullname[MAXPATH]; Xint dirlen; X X/* Find the first file meeting the wildcard spec, and return its name */ Xchar * Xfirst_file (fn) X char *fn; /* filename (perhaps complete pathname */ X{ X int ffflag; X int splitflag; X char drive[MAXDRIVE], dir[MAXDIR], X name[MAXFILE], ext[MAXEXT]; X X /* Get path part, if any */ X splitflag = fnsplit (fn, drive, dir, name, ext); X strcpy (fullname, drive); X strcat (fullname, dir); X dirlen = strlen (fullname); X X ffflag = findfirst (fn, &fb, FA_RDONLY+FA_ARCH); X if (ffflag) { /* No files match */ X if (splitflag & WILDCARDS) /* done if wildcard */ X return (NULL); X else /* complain if not wild */ X return (fn); X } X else { X if (dirlen) { X strcpy (fullname+dirlen, fb.ff_name); X return (fullname); X } X else X return (fb.ff_name); X } X} X X/* Find the next file meeting the wildcard spec, and return its name */ Xchar * Xnext_file () X{ X int ffflag; X X ffflag = findnext (&fb); X if (ffflag) /* No more matching files */ X return (NULL); X else { X if (dirlen) { X strcpy (fullname+dirlen, fb.ff_name); X return (fullname); X } X else X return (fb.ff_name); X } X} X X#endif X#endif !EOR! echo extracting - cpr.h sed 's/^X//' > cpr.h << '!EOR!' X/************** Header File For CPR ************************/ X X#ifdef MAIN X# define EXTERN X# define INIT(x) =x X#else X# define EXTERN extern X# define INIT(x) X#endif X Xextern int errno; /* system error number */ Xextern char *sys_errlist[]; /* error message */ Xextern char *malloc() ; /* important for 8086-like systems */ X X#define BP 0xC /* Form feed */ X X#define NEWFILE 1 X#define NEWFUNCTION 2 X X/* Define formats for beginning of line */ X#define NUMFORMAT "%6ld " X#define BLANKFORMAT " " X#define FORMATWIDTH 8 X X#define NULLSTR( x ) ((x == NULL) || (*x == '\0')) X#define WHITESPACE(x) (strchr (" \n\r\t", x)) X X/* Option flag variables */ XEXTERN int PageLength INIT( 66 ); /* -l, <len> Page length */ XEXTERN int PageWidth INIT( 0 ); /* -w, page width for line folding */ XEXTERN int PagePart INIT( 12 ); /* -p, Decision on paging for new fn*/ XEXTERN int PageEnd INIT( 59 ); /* Accounts for space at bottom (7 lines) */ XEXTERN int Title INIT( 0 ); /* -T, print a title file */ XEXTERN int ResetPage INIT( 0 ); /* -N, each file resets page # */ XEXTERN int ContentsOnly INIT( 0 ); /* -C, only ToC, no listings */ XEXTERN int SortFlag INIT( 0 ); /* -s, sort table of contents */ XEXTERN int CaseInsensitive INIT( 0 ); /* -S, case-insens sort */ XEXTERN int XrefFlag INIT( 0 ); /* -x, cross-reference */ XEXTERN int NumberFlag INIT( 0 ); /* -n, line numbers in output */ XEXTERN int FirstCol INIT( 0 ); /* starting column for listing (-n) */ XEXTERN int Space_to_leave INIT( 5 ); /* -r<number> space to leave */ XEXTERN int TabWidth INIT( 8 ); /* -t <number> width of tabs */ XEXTERN int OnlyCFiles INIT( 0 ); /* -c, only look in C files */ X X/* State variables for the program */ XEXTERN long FileLineNumber; /* Input file line number */ XEXTERN int LineNumber; /* Output line on this page */ XEXTERN int PageNumber INIT( 0 ); /* You figure this one out */ XEXTERN int InComment; XEXTERN int InString; X XEXTERN char *TitleFile; XEXTERN char *ProgName; XEXTERN char Today[30]; XEXTERN char *Name; /* Current file name */ XEXTERN char FunctionName[80]; X X/* Help with parsing the command line and argument file */ XEXTERN int InArgFile INIT( 0 ); XEXTERN char arg[1024]; /* buffer for current argument */ XEXTERN char *listn; /* argument file name */ XEXTERN FILE *listf; /* argument file */ XEXTERN FILE *File; XEXTERN FILE *Tfile; /* title file */ X !EOR! echo extracting - makefile sed 's/^X//' > makefile << '!EOR!' X# MAKEFILES FOR CPR: X# Pick out your system, extract the sub-makefile, and go. X# Note: this makefile is untested, and probably won't work as is; X# use it as a guide. X X# For UNIX System V. XSRC=cpr.c parsargs.c list.c fold.c report.c XOBJ=cpr.o parsargs.o list.o fold.o report.o XHDR=cpr.h XTARGET=cpr XCC=cc -c -O XLINK=cc -o cpr X X# For MSDOS using Turbo C 2.0 or later XSRC=cpr.c parsargs.c list.c fold.c report.c XOBJ=cpr.obj parsargs.obj list.obj fold.obj report.obj \tc\lib\wildargs.obj XHDR=cpr.h XTARGET=cpr.exe XCC=tcc -O -DMSDOS -DTURBOC XLINK=tcc X X# For MSDOS using Microsoft C 5.0 or later X# (Note: in the "rules" section, end each command line with ';') XSRC=cpr.c parsargs.c list.c fold.c report.c XOBJ=cpr.obj parsargs.obj list.obj fold.obj report.obj \msc\lib\setargv.obj XHDR=cpr.h XTARGET=CPR.EXE XCC=msc -O -DMSDOS XLINK=link X X# For systems that don't expand wildcards on command line X# (including earlier MS C and Turbo C), X# replace the "special" .obj with "wildfile.obj", which you will write X# yourself. A sample wildfile.c is given for early Turbo C. X# Also, compile with the additional flag NOWILD. X X# Generic Makefile section X X.c.o: X $(CC) $*.c X X$(TARGET) : $(OBJ) X $(LINK) $(OBJ) X X$(OBJ) : $(HDR) X X# Make a listing using cpr. This "bootstraps" from a good cpr. Xlisting : cpr.cpr Xcpr.cpr : $(SRC) $(HDR) X cpr -Xp9w83 $(SRC) $(HDR) > cpr.cpr X !EOR!