/* * l i n e p r . c * Print with line numbers. */ /*)BUILD */ #ifdef DOCUMENTATION title linepr Print files with line numbers and headers index Print files with line numbers and headers synopsis linepr [-options] [-o outfile] [file ...] description linepr prepares a listing for text files. The following options are defined: .lm +8 .s.i -8;-s Spool output to the default line printer. (On RSX modes only). .s.i -8;-o file Write output to the named file. The default is the first input file encountered with a filetype (extension) of ".x". .s.lm -8 linepr accepts wild-card file input. diagnostics .lm +8 .s.i -8;Cannot open "file" .s.i -8;Cannot open listing file "file" .s.i -8;Usage ... .lm -8 author Robert B. Denny, Martin Minow bugs #endif #include #define EOS 0 #define LWIDTH 132 /* Listing width, characters */ #define MAXLIN 57 /* Listing lines per page (w/o header) */ #ifdef vms /* * This creates files in vanilla RMS on VMS V2 */ extern FILE *fdopen(); #define CREATE(f, m) fdopen(creat(f, 0, "rat=cr", "rfm=var"), m) #else #define CREATE fopen #endif FILE *src; /* Source file pointer */ FILE *lst; /* List file pointer */ int pageno; /* Current listing page no. */ int lineno = 0; /* Current source line number */ int linpg = 0; /* Line-in-page count */ int was_lf; /* TRUE if last line ended with NL */ int ccpos; /* Where on the line */ char pghead[LWIDTH+1]; /* Page header */ char line[LWIDTH+1]; /* Source line buffer */ int time_of_day[2]; /* Time of day in seconds */ main(argc, argv) int argc; char *argv[]; { register int i; /* Arg count */ register int c; /* Switch character code */ register char *ap; /* Fast arg pointer */ char *in_file; /* Source file name string */ char *out_file; /* Cref file name string */ #ifdef rsx int splflg; /* Spool file flag */ #endif int nofiles; /* Flag "got a file" */ out_file = NULL; /* No output file yet */ #ifdef rsx splflg = 0; /* Default no spool */ #endif for (i=1; i < argc; i++) { /* For each token */ ap = argv[i]; /* ap --> i'th arg */ if (*ap++ == '-') { /* if it's an option */ while((c = *ap++) != EOS) { /* Look at each char */ switch (tolower(c)) { /* Process 'em */ case 'o': /* Output file */ if (*ap != EOS) usage("-o may not be followed by another option"); argv[i] = NULL; if (++i >= argc) usage("-o must be followed by a filename"); out_file = argv[i]; argv[i] = NULL; goto nextarg; #ifdef rsx case 's': /* Spool listing */ splflg++; break; #endif default: /* Bad option, help */ usage("Unknown option"); } } argv[i] = NULL; /* Drop this arg */ } nextarg:; } /* Done with cmd string */ nofiles = 1; for (i = 1; i < argc; i++) { if ((in_file = argv[i]) != NULL) { initinfile(in_file); while (nextinfile()) { if (nofiles) { initoutfile(out_file); nofiles = 0; } pageno = 0; lineno = 0; newpage(); while(fgets(line, LWIDTH, src) != NULL) { lstline(); } fprintf(lst, "\n"); /* Force terminal NL */ } } } if (nofiles) usage("no input files given"); #ifdef rsx if (splflg) /* If we're to spool, */ fspool(lst); /* Cross your fingers. */ #endif } /* * Listing control routines. */ newpage() /* Start new page */ { if (pageno != 0) fprintf(lst, "\n"); /* End last line */ ++pageno; linpg = 0; fprintf(lst,"%s%d\n\n", pghead, pageno); was_lf = TRUE; ccpos = 0; } lstline() /* Write out list line */ { register char *lp; register char *start; extern char *strchr(); start = line; if ((lp = strchr(line, '\f')) == NULL) { if (!was_lf) { if (length(line) >= LWIDTH) { fprintf(lst, "\n"); ccpos = 0; } fprintf(lst, "%s", line); } else { if (++linpg > MAXLIN) newpage(); fprintf(lst, "%4d:\t%s", lineno + 1, line); } } else { if (lp > line) { /* Before formfeed */ *lp = EOS; /* Eat the formfeed */ if (!was_lf) fprintf(lst, "%s\n", line); else fprintf(lst, "%4d:\t%s\n", lineno + 1, line); start = "\n"; } newpage(); if (*++lp != '\n' && *lp != EOS) { /* Stuff after formfeed */ ++linpg; fprintf(lst, "%4d:\t%s", lineno + 1, lp); start = lp; } } if (was_lf = (start[strlen(start) - 1] == '\n')) { lineno++; ccpos = 0; } else { length(start); } } int length(lp) register char *lp; /* Text pointer */ /* * Calculate new ccpos value (slightly incorrect at newline) * Returns new ccpos value. */ { register char *newlp; extern char *strchr(); while ((newlp = strchr(lp, '\t')) != NULL) { ccpos += (newlp - lp); /* Before the TAB */ ccpos = (ccpos & 7) + 8; /* The TAB itself */ lp = newlp + 1; /* Point lp after the TAB */ } ccpos += strlen(lp); /* All the rest */ } /* * Set up RSX file names, open them, and initialize the page header strings */ initinfile(in) char *in; { if ((src = fwild(in, "r")) == NULL) { perror(in); error("Cannot open %s\n", in); } if (time_of_day[0] == 0) { time(&time_of_day); } } initoutfile(out) char *out; { char wrkbuf[80]; char firstin[80]; if (out != NULL) { name(wrkbuf, out, "lst", 0); } else { fgetname(src, firstin); name(wrkbuf, firstin, "lst", 1); /* Make list file name */ } if ((lst = CREATE(wrkbuf, "w")) == NULL) { perror(wrkbuf); error("Cannot open listing file %s\n", wrkbuf); } } int nextinfile() { register char *wp; register int c; char wrkbuf[80]; char *timetemp; if (fnext(src) == NULL) return (0); fgetname(src, wrkbuf); for (wp = wrkbuf; (c = *wp++) != EOS && c != ':';) ; if (c == EOS) wp = wrkbuf; timetemp = ctime(&time_of_day); timetemp[24] = EOS; /* Trash newline */ concat(pghead, "\fListing of: ", wp, "\t", timetemp, "\tPage ", NULL); return (1); } /* * Make a file name. * The mode argument is either 0 which means use type as default extension, * or 1, which means force the extension to be type. Argument file is the * 'raw' file name, sysnam is the final filename string. All arg's except * mode are pointers, as usual. * */ name(sysnam, file, type, mode) char *sysnam; char *file; char *type; int mode; { register char *p1, *p2; /* Fast pointers */ register int c; /* Fast char. buffer */ p1 = sysnam; /* p1 --> output string */ p2 = file; /* p2 --> input string */ while ((c = *p2++) != EOS) { if (c == '[') { *p1++ = c; while ((c = *p2++) != ']' && c != EOS) *p1++ = c; } if (c == '.') break; *p1++ = c; } if (mode == 0) { /* Default extension */ if (c == '.') { /* Explicit extension */ do { /* Copy '.' + any ext. */ *p1++ = c; } while ((c = *p2++) != EOS); } else { /* Use default */ *p1++ = '.'; p2 = type; while (c = *p2++) *p1++ = c; } } else { /* Force extension */ *p1++ = '.'; p2 = type; while (c = *p2++) *p1++ = c; } *p1 = EOS; /* Terminate result */ } usage(why) char *why; /* * Give user help on program useage. */ { #ifdef vms fprintf(stderr, "linepr error: %s.\n", why); fprintf(stderr, "Usage: linepr [-o outfile] infiles\n"); #else extern int $$rsts; fprintf(stderr, "linepr error: %s.\n", why); #ifdef rt11 if ($$rsts) { fprintf(stderr, "Usage: CRUN LINEPR [-s] [-o outfile] infiles\n"); fprintf(stderr, " -s Spool output file\n"); } else { fprintf(stderr, "Usage (short): .RUN LINEPR infile\n"); fprintf(stderr, "Usage (long): .RUN LINEPR\n"); fprintf(stderr, " Argv: [-o outfile] infiles\n"); } #else fprintf(stderr, "Usage: linepr [-s] [-o outfile] infiles\n"); fprintf(stderr, " -s Spool output file\n"); #endif #endif fprintf(stderr, " -o Output to \"outfile\"\n\n"); fprintf(stderr, "Input files may have wild-card names\n"); fprintf(stderr, "Default input filetype is \".c\"\n"); fprintf(stderr, "Default output filename is \".lst\"\n"); exit(2); }