ahh@j.cc.purdue.edu (Brent L. Woods) (02/27/88)
Program Name: pr Submitted By: Jim Levie REMTECH Inc Huntsville, Al Summary: A file printer program like the UNIX program of the same name. Poster Boy: Brent Woods (ahh@j.cc.purdue.edu) Tested. NOTES: We were able to test the epson version (worked fine, too), but, not having access to a laserjet printer, we weren't able to test that one. Other than that, no problems at all. Brent Woods, Co-Moderator, comp.{sources,binaries}.amiga USENET: ...!j.cc.purdue.edu!ahh ARPANET: ahh@j.cc.purdue.edu BITNET: PODUM@PURCCVM PHONE: +1 (317) 743-8421 USNAIL: 320 Brown St., #406 / West Lafayette, IN 47906 ================================================================ # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # author # README.pr # makefile # getopt.c # pr.epson.c # pr.laserjet.c # This archive created: Sat Feb 27 01:10:30 1988 # By: Brent L. Woods (Co-Moderators Unlimited.) cat << \SHAR_EOF > author Seeing the requests for 2-up laser printed docs made me think of posting this to the archive. It's a Unix like 'pr' utility for the Amiga that can, amoung other things, do 2-up printing on a Laserjet. I have provided Laserjet and Epson variants of 'pr', though the Epson variety cannot do 2-up printing in landscape mode. =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ Jim Levie REMTECH Inc Huntsville, Al The opinions expressed above are just that. Ph. (205) 536-8581 email: uunet!ingr!b11!jim SHAR_EOF cat << \SHAR_EOF > README.pr This is my attempt at a Unix like pr utility. Actually I wrote this originally for a Xerox 4045 printer on a Unix system 'cause I wanted to print 2-up in landscape mode and pr didn't know how to do that automatically. Since then I improved the code and made variants for Epson and Laserjet printers, and modified the code to work on the Amiga. The Laserjet variant automagically shifts to landscape mode for multi-column output, for obvious reasons the Epson variety doesn't. Also since I have only narrow carriage printers the margins built in to the code don't use more than 8.5in of with, it's easy to change. The utility can be built with Manx C V3.4b, I have the printer codes hard coded into the source so that I can use the same basic code on several machines. Since most people only have one printer the makefile just makes 'pr' from the source specified ('make pr-epson' or 'make pr-lj'). This code is freely redistributible, I only ask that you not remove the author credit. MANIFEST: makefile - makefile to build either variant pr.epson.c - source for Epson variant pr.lasetjet.c - source for Laserjet variant getopt.c - source for getopt pr-epson - executable Epson variant pr-lj - executable Laserjet variant =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ Jim Levie REMTECH Inc Huntsville, Al The opinions expressed above are just that. Ph. (205) 536-8581 email: uunet!ingr!b11!jim SHAR_EOF cat << \SHAR_EOF > makefile # # Makefile for pr using Manx C # pr-epson: pr.epson.o getopt.o ln -o pr pr.epson.o getopt.o -lc pr-lj: pr.lj.o getopt.o ln -o pr pr.lj.o getopt.o -lc pr.epson.o: pr.epson.c cc pr.epson.c pr.lj.o: pr.laserjet.c cc -o pr.lj.o pr.laserjet.c getopt.o: getopt.c cc getopt.c clean: delete #?.o delete pr install: copy pr sys:utilities SHAR_EOF cat << \SHAR_EOF > getopt.c /* * GETOPT.C * * SYNOPSIS * int getopt(argc, argv, optstring) * int args; * char **argv; * char *optstring; * * extern char *optarg; * extern int optind, opterr; * * DESCRIPTION * getopt returns the next option letter in argv that matches a * letter in optstring. optstring is a string of recognized * option letters; if a letter is followed by a colon, the * option is expected to have an argument that may or may not * be separated from it by white space. optarg is set to point * to the start of the option argument on return from getopt. * * getopt places in optind the argv index of the next argument * to be processed. Because optind is external, it is normally * initialized to zero automatically before the first call to * getopt. * * When all options have been processed (i.e., up to the first * non-option argument), getopt returns EOF. The special option * -- may be used to delimit the end of the options; EOF will * be returned, and -- will be skipped. * * DIAGNOSTICS * getopt prints an error message on stderr and returns a ques- * tion mark (?) when it encounters an option letter not * included in optstring. This error message may be disabled * by setting opterr to zero. * */ /*LINTLIBRARY*/ #define NULL 0 #define EOF (-1) #define ERR(s, c) if(opterr){\ extern int strlen(), write();\ char errbuf[2];\ errbuf[0] = c; errbuf[1] = '\n';\ (void) write(2, argv[0], (unsigned)strlen(argv[0]));\ (void) write(2, s, (unsigned)strlen(s));\ (void) write(2, errbuf, 2);} extern int strcmp(); extern char *strchr(); int opterr=1; int optind=1; int optopt; char *optarg; int getopt(argc, argv, opts) int argc; char **argv, *opts; { static int sp = 1; register int c; register char *cp; if(sp==1) { if(optind>=argc || argv[optind][0]!='-' || argv[optind][1]=='\0') { return(EOF); } else if(strcmp(argv[optind], "--")==NULL) { optind++; return(EOF); } } optopt=c=argv[optind][sp]; if(c==':' || (cp=strchr(opts, c))==NULL) { ERR(": illegal option -- ", c); if(argv[optind][++sp]=='\0') { optind++; sp=1; } return('?'); } if(*++cp==':') { if(argv[optind][sp+1]!='\0') optarg=&argv[optind++][sp+1]; else if(++optind>=argc) { ERR(": option requires an argument -- ", c); sp=1; return('?'); } else optarg=argv[optind++]; sp=1; } else { if(argv[optind][++sp]=='\0') { sp=1; optind++; } optarg=NULL; } return(c); } SHAR_EOF cat << \SHAR_EOF > pr.epson.c /* * PR.LASERJET.C - HP Laserjet Series II printer driver * * pr - prepare file(s) for printing, perhaps in multiple columns * * SYNOPSIS: * pr [-n] [+n] [-h string] [-wn] [-ln] [-t] [file] ... * * DESCRIPTION: * pr prepares one or more files for printing. By default the output is * separated into pages headed by the date, the name of the file, and page * number. pr processes standard input if no input file is specified, and * sends output to standard out. Formfeed characters in the input cause * page breaks as expected and tabs are expanded. * * OPTIONS: * -n Produce n-column output. Column width is calculated as * (page width-(n-1)*3)/n. Columns are separated by 3 spaces. * * +n Begin printing at page n. * * -h string Use string instead of the file name in the page header. * * -wn Use n for the page width rather than the defaults. Pr * normally uses 80 for single column output and 160 for * multicolumn output. * * -ln Take the length of the page to be n lines rather than the * default of 60. * * -t Do not print the header at the top of the page. * * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= * * This utility writes directly to the printer connected to the par: device. * It does not use the prt: device or codes. I did it this way to be able * to use the same basic code on the Amiga and Unix. To use on Unix the * freopen of stdout has to be removed. * * Author: James K. Levie III * * Version 1.0 05-Oct-1987 - Initial version * Version 1.1 17-Oct-1987 - Fixed bug that failed to close file just printed. * Version 1.2 13-Nov-1987 - By popular demand changed the separation between * columns from 5 to 3. */ #include <stdio.h> extern char *fgets(); extern char *malloc(); extern int errno; extern long time(); extern char *ctime(); extern char *optarg; extern int optind, opterr; /* * Local definitions */ #define MAX_WIDTH 124 #define MAX_LENGTH 66 #define DEF_WIDTH 86 #define DEF_LENGTH 60 #define WIDTH_80 94 #define TRUE 1 #define FALSE 0 /* * Allocate storage for global variables */ char loctim[27]; /* buffer to hold current time */ char *title=NULL; /* title used in page header */ int length; /* length of page in lines */ int width; /* width of column in characters */ int columns=1; /* number of columns on a page */ int header=3; /* flag and size of headers */ int page_start=1; /* starting page number */ page_width; /* printable page width */ page_length; /* printable page length */ char *pagebuf; /* ptr to page buffer (malloc'd) */ char *pageptr[MAX_LENGTH*2]; /* ptr's to lines in buffer */ int cur_page; /* current page number */ int cur_line; /* current line on page */ int cur_char; /* current character in current line */ /* * Printer specific stuff. This really should be done in a printer * independent manner, but can't think of one that will work on all systems * * Codes for HP Laserjet Series II */ char Reset[]="\033@"; char Margin_80[]="\033l\010\033Q\136"; char Margin_132[]="\033l\014\033Q\210"; char *Margins; char Font_80[]="\033!\001"; char Font_132[]="\033!\004"; char *Font; char Bold[]="\033E"; char unBold[]="\033F"; FILE *in; FILE *sfp, *freopen(); /* a kludge 'cause no real pipes in */ /* Amiga shell, should fix that */ ^L /* * The main for pr. This module examines the command line for options * and files and dispatches the printing module. */ main(argc, argv) int argc; char *argv[]; { char *cp, *ct, **myargv, c; register int i; int myargc, look_again, looking, user_width=0, user_length=0; long tim; /* * Some setup stuff, get the system time and * format it the way we want to print it. */ tim=time(NULL); /* get system time */ cp=ctime(&tim); /* convert to ascii time */ ct=loctim; for(i=8; i<11; i++) *ct++=cp[i]; /* load day */ for(i=4; i<8; i++) *ct++=cp[i]; /* load month */ for(i=20; i<24; i++) *ct++=cp[i]; /* load year */ *ct++=' '; for(i=10; i<16; i++) *ct++=cp[i]; /* and finally time */ *ct='\0'; /* * Begin the main loop. Each time we will need to check for options * since we allow options to be reset between files. To do this we * will have to diddle the arguments and internal variables of getopt(). * Accordingly this program should always use the version of getopt() * supplied, rather than the library version. */ opterr=0; /* disable error messages from getopt */ myargv=argv; /* we'll need to be able to ... */ myargc=argc; /* ... diddle argc and argv to getopt() */ /* * Until we get real pipes on the Amiga I think I'll close sdtout and * write directly to the par: device. */ if((sfp=freopen("par:", "w", stdout))==NULL) { fprintf("Can't reopen stdout\n"); exit(20); } do { looking=TRUE; while(looking) { c=getopt(myargc, myargv, "12h:w:l:t"); switch(c) { case '1': columns=1; break; case '2': columns=2; break; case 'h': title=optarg; break; case 'w': user_width=atoi(optarg); if(user_width<1 || user_width>MAX_WIDTH) { user_width=DEF_WIDTH; fprintf(stderr, "%s: error in width, reset to %d", argv[0], DEF_WIDTH); } break; case 'l': user_length=atoi(optarg); if(user_length<1) { user_length=DEF_LENGTH; fprintf(stderr, "%s: error in length, reset to %d", argv[0], DEF_LENGTH); } break; case 't': header=0; break; case EOF: if(optind<myargc && myargv[optind][0]=='+') { if(myargv[optind][1]=='\0') { page_start=atoi(myargv[optind+1]); optind+=2; } else { page_start=atoi(&myargv[optind][1]); optind++; } /* * Now see if there might be more options on the command * line following the '+n' option. We are going to * going to diddle the getopt stuff to get it to keep on * searching. Since we will not have a program name in * argv[0] we want to set optind to 0 rather than 1. */ myargc-=optind; myargv= &myargv[optind]; optind=0; } else looking=FALSE; } /* end of switch(c) */ } /* end of while(looking) */ /* * Now we should either have a file or stdin for input. If it is * stdin we don't want to look again. */ if(user_width) page_width=user_width; else page_width=(columns>1)? MAX_WIDTH:DEF_WIDTH; width=(page_width-(columns-1)*3)/columns; if(user_length) page_length=user_length; else page_length=DEF_LENGTH; length=(page_length-header)*columns+header; Margins=(page_width>WIDTH_80)? Margin_132:Margin_80; Font=(page_width>WIDTH_80)? Font_132:Font_80; look_again=FALSE; /* assume we won't look anymore */ if(optind<myargc) { while(optind<myargc && myargv[optind][0]!='-' && myargv[optind][0]!= '+') { if(title==NULL) title=myargv[optind]; if((in=fopen(myargv[optind], "r"))==NULL) printf("%s: Failed to open %s\n", argv[0], myargv[optind]); else { prt_file(); fclose(in); } title=NULL; optind++; } if(optind<myargc) look_again=TRUE;/* we can look again, not stdin */ } else { in=stdin; /* no file, use stdin */ prt_file(); } }while(look_again); /* end of do ... while(look_again) */ } prt_file() { char *bp, *rp, buffer[512]; int i, ii, nchars; /* * Check the size of the page buffer and adjust if necessary. The * number of bytes for a line must allow for the null byte. */ if(pagebuf==NULL) { if((pagebuf=malloc((page_width+1)*page_length))==NULL) { fprintf(stderr, "Failed to allocate page buffer\n"); exit(20); } } else { if(sizeof(pagebuf)<((page_width+1)*page_length)) { free(pagebuf); if((pagebuf=malloc(page_width*page_length))==NULL) { fprintf(stderr, "Failed to allocate page buffer\n"); exit(20); } } } /* * Set up the pointers to the virtual lines. */ for(i=0; i<page_length; i++) pageptr[i]=pagebuf+i*(page_width+1); /* * Set up the pointers to the second or more columns. * If we are doing multicolumn stuff we have to allow for the * whitespace that separates each column. Two column output is not * a problem since the space is in the page width, three or more * is. */ if(columns>1) { ii=page_length; while(ii<length) { for(i=header; i<page_length; i++,ii++) { pageptr[ii]=pageptr[i]+width+(columns-2)*3; } } } /* * Initialize some variables, remember that line and character references * are from zero. */ printf("%s%s%s", Reset, Font, Margins); cur_page=1; cur_line=0; cur_char=0; /* * Process the input stream. */ if(header) mak_hdr(); bp=pageptr[cur_line++]; *bp='\0'; while((nchars=fread(buffer, sizeof(*buffer), 512, in))>0) { rp=buffer; while(nchars>0) { if(cur_page<page_start) { switch(*rp) { case '\f': cur_page++; cur_line=0; if(header) mak_hdr(); break; case '\n': cur_line++; if(cur_line>=length) { cur_page++; cur_line=0; if(header) mak_hdr(); } break; default: break; } } else { switch(*rp) { case '\f': /* * This gets a little tricky. When we are doing * multicolumns we only want a formfeed to eject the * page if we are on the last column. For the other columns * we want to fill out the rest of the column with spaces * and start at the top of the next column. */ if(columns>1 && (length-cur_line)>=(page_length-header)) { /* * Well we weren't on the last column. Do we need to * space fill the rest of this line?. */ if(cur_char!=0) { /* * Yep, do it */ while(cur_char<width) { *bp++=' '; cur_char++; } *bp='\0'; /* * Okay, point to the next line. */ bp=pageptr[cur_line++]; *bp='\0'; cur_char=0; } /* * Now we need to space fill the rest of this column */ i=(page_length-header) -((cur_line-header)%(page_length-header)); while(i>0) { ii=(cur_line>page_length)? 3:0; for(cur_char=0; cur_char<(width+ii); cur_char++) *bp++=' '; *bp='\0'; bp=pageptr[cur_line++]; *bp='\0'; cur_char=0; i--; } } else { dump_buffer(); cur_page++; cur_char=0; cur_line=0; if(header) mak_hdr(); bp=pageptr[cur_line++]; *bp='\0'; } break; case '\t': ii=8-(cur_char)%8; while(ii>0 && cur_char<width) { *bp++=' '; cur_char++; *bp='\0'; ii--; } break; case '\n': /* * Did we just finish the last line on this physical * page? */ if(cur_line>=length) { dump_buffer(); cur_page++; cur_line=0; cur_char=0; if(header) mak_hdr(); bp=pageptr[cur_line++]; *bp='\0'; } /* * Should we space fill the remainder of this line? * We only need to if there are more columns to follow. */ if(columns>1 && cur_char<width && (length-cur_line)>=(page_length-header)) { while(cur_char<width) { *bp++=' '; cur_char++; } *bp='\0'; } /* * Columns 2, 3, and so on need withspace at the beginning * that is not actually a part of the line to separate * the columns. */ bp=pageptr[cur_line++]; if(columns>1 && cur_line>page_length) for(i=0; i<3; i++) *bp++=' '; *bp=0; cur_char=0; break; default: if(cur_char<width) { *bp++= *rp; cur_char++; *bp='\0'; } } } /* end of if(cur_page< ... */ rp++; nchars--; } } if((header && cur_line>3) || (!header && cur_line>0)) dump_buffer(); return(0); } /* * MAK_HDR * * This module takes the local time, title, and page number and forms * the header line that is printed at the top of each page. The local time * is justified against the left margin and the title and page number is * justified against the right margin as determined by "width". The header * is always printed in bold type. There are two blank lines following the * header. * */ mak_hdr() { char *bp, tmp[MAX_WIDTH]; int i, ii, iii; /* * Put the header into buffer */ bp=pageptr[cur_line++]; strcpy(bp, loctim); /* * Now get the page number string into buf */ sprintf(tmp, "%s Page %d", title, cur_page); ii=strlen(bp); bp=bp+ii; iii=strlen(tmp); for(i=ii; i<(page_width-iii); i++) *bp++=' '; for(i=0; i<iii; i++) *bp++=tmp[i]; *bp++='\0'; *pageptr[cur_line++]='\0'; *pageptr[cur_line++]='\0'; } /* * dump_buffer() * * This module dumps the virtual page. */ dump_buffer() { int i, ii; /* * Decide how much to print. We need to print all of the lines * that were actually used, but no more. When we are doing * multicolumn we only want to index on the left most column. */ ii=(cur_line>page_length)? page_length:cur_line; for(i=0; i<ii; i++) { if(header && i==0) printf("%s%s%s\r\n", Bold, pageptr[i], unBold); else printf("%s\r\n", pageptr[i]); } printf("\r\f"); fflush(stdout); } SHAR_EOF cat << \SHAR_EOF > pr.laserjet.c /* * PR.C - prepare file(s) for printing, perhaps in multiple columns * * SYNOPSIS: * pr [-n] [+n] [-h string] [-wn] [-ln] [-t] [file] ... * * DESCRIPTION: * pr prepares one or more files for printing. By default the output is * separated into pages headed by the date, the name of the file, and page * number. pr processes standard input if no input file is specified, and * sends output to standard out. Formfeed characters in the input cause * page breaks as expected and tabs are expanded. * * OPTIONS: * -n Produce n-column output. Column width is calculated as * (page width-(n-1)*3)/n. Columns are separated by 3 spaces. * * +n Begin printing at page n. * * -h string Use string instead of the file name in the page header. * * -wn Use n for the page width rather than the defaults. Pr * normally uses 80 for single column output and 160 for * multicolumn output. * * -ln Take the length of the page to be n lines rather than the * default of 60. * * -t Do not print the header at the top of the page. * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= * * This utility writes directly to the printer connected to the par: device. * It does not use the prt: device or codes. I did it this way to be able * to use the same basic code on the Amiga and Unix. To use on Unix the * freopen of stdout has to be removed. * * Author: James K. Levie III * * Version 1.0 05-Oct-1987 - Initial version * Version 1.1 17-Oct-1987 - Fixed bug that failed to close file just printed. * Version 1.2 13-Nov-1987 - By popular demand changed the separation between * columns from 5 to 3. */ #include <stdio.h> /*#include <prcodes.h>*/ extern char *fgets(); extern char *malloc(); extern int errno; extern long time(); extern char *ctime(); extern char *optarg; extern int optind, opterr; /* * Local definitions */ #define MAX_WIDTH 167 #define MAX_LENGTH 84 #define DEF_WIDTH 75 #define DEF_LENGTH 60 #define TRUE 1 #define FALSE 0 /* * Allocate storage for global variables */ char loctim[27]; /* buffer to hold current time */ char *title=NULL; /* title used in page header */ int length; /* length of page in lines */ int width; /* width of column in characters */ int columns=1; /* number of columns on a page */ int header=3; /* flag and size of headers */ int page_start=1; /* starting page number */ page_width; /* printable page width */ page_length; /* printable page length */ char *pagebuf; /* ptr to page buffer (malloc'd) */ char *pageptr[MAX_LENGTH*2]; /* ptr's to lines in buffer */ int cur_page; /* current page number */ int cur_line; /* current line on page */ int cur_char; /* current character in current line */ /* * Xerox 4045 specific stuff, this will be replaced later with termcap * stuff. */ char Reset[]="\033E\033&k0G"; char Margin_80[]="\033&l0O\033&l2E\033&l61F\033&a5L\033&a83M"; char Margin_132[]="\033&l1O\033&l8D\033&l6E\033&l61F\033&a3L\033&a167M"; char *Margins; char Font_80[]="\033(s10H"; char Font_132[]="\033(s16.66H"; char *Font; char Bold[]="\033(s3B"; char unBold[]="\033(s0B"; FILE *in; FILE *sfp, *freopen(); /* a kludge 'cause no real pipes in shell */ ^L /* * The main for pr. This module examines the command line for options * and files and dispatches the printing module. */ main(argc, argv) int argc; char *argv[]; { char *cp, *ct, **myargv, c; register int i; int myargc, look_again, looking, user_width=0, user_length=0; long tim; /* * Some setup stuff, get the system time and * format it the way we want to print it. */ tim=time(NULL); /* get system time */ cp=ctime(&tim); /* convert to ascii time */ ct=loctim; for(i=8; i<11; i++) *ct++=cp[i]; /* load day */ for(i=4; i<8; i++) *ct++=cp[i]; /* load month */ for(i=20; i<24; i++) *ct++=cp[i]; /* load year */ *ct++=' '; for(i=10; i<16; i++) *ct++=cp[i]; /* and finally time */ *ct='\0'; /* * Begin the main loop. Each time we will need to check for options * since we allow options to be reset between files. To do this we * will have to diddle the arguments and internal variables of getopt(). * Accordingly this program should always use the version of getopt() * supplied, rather than the library version. */ opterr=0; /* disable error messages from getopt */ myargv=argv; /* we'll need to be able to ... */ myargc=argc; /* ... diddle argc and argv to getopt() */ /* * Until we get real pipes on the Amiga I think I'll close sdtout and * write directly to the par: device. */ if((sfp=freopen("par:", "w", stdout))==NULL) { fprintf("Can't reopen stdout\n"); exit(20); } do { looking=TRUE; while(looking) { c=getopt(myargc, myargv, "12h:w:l:t"); switch(c) { case '1': columns=1; break; case '2': columns=2; break; case 'h': title=optarg; break; case 'w': user_width=atoi(optarg); if(user_width<1 || user_width>MAX_WIDTH) { user_width=DEF_WIDTH; fprintf(stderr, "%s: error in width, reset to %d", argv[0], DEF_WIDTH); } break; case 'l': user_length=atoi(optarg); if(user_length<1) { user_length=DEF_LENGTH; fprintf(stderr, "%s: error in length, reset to %d", argv[0], DEF_LENGTH); } break; case 't': header=0; break; case EOF: if(optind<myargc && myargv[optind][0]=='+') { if(myargv[optind][1]=='\0') { page_start=atoi(myargv[optind+1]); optind+=2; } else { page_start=atoi(&myargv[optind][1]); optind++; } /* * Now see if there might be more options on the command * line following the '+n' option. We are going to * going to diddle the getopt stuff to get it to keep on * searching. Since we will not have a program name in * argv[0] we want to set optind to 0 rather than 1. */ myargc-=optind; myargv= &myargv[optind]; optind=0; } else looking=FALSE; } /* end of switch(c) */ } /* end of while(looking) */ /* * Now we should either have a file or stdin for input. If it is * stdin we don't want to look again. */ if(user_width) page_width=user_width; else page_width=(columns>1)? MAX_WIDTH:DEF_WIDTH; width=(page_width-(columns-1)*3)/columns; if(user_length) page_length=user_length; else page_length=DEF_LENGTH; length=(page_length-header)*columns+header; Margins=(page_width>80)? Margin_132:Margin_80; Font=(page_width>80)? Font_132:Font_80; look_again=FALSE; /* assume we won't look anymore */ if(optind<myargc) { while(optind<myargc && myargv[optind][0]!='-' && myargv[optind][0]!= '+') { if(title==NULL) title=myargv[optind]; if((in=fopen(myargv[optind], "r"))==NULL) printf("%s: Failed to open %s\n", argv[0], myargv[optind]); else { prt_file(); fclose(in); } title=NULL; optind++; } if(optind<myargc) look_again=TRUE;/* we can look again, not stdin */ } else { in=stdin; /* no file, use stdin */ prt_file(); } }while(look_again); /* end of do ... while(look_again) */ } prt_file() { char *bp, *rp, buffer[512]; int i, ii, nchars; /* * Check the size of the page buffer and adjust if necessary. The * number of bytes for a line must allow for the null byte. */ if(pagebuf==NULL) { if((pagebuf=malloc((page_width+1)*page_length))==NULL) { fprintf(stderr, "Failed to allocate page buffer\n"); exit(20); } } else { if(sizeof(pagebuf)<((page_width+1)*page_length)) { free(pagebuf); if((pagebuf=malloc(page_width*page_length))==NULL) { fprintf(stderr, "Failed to allocate page buffer\n"); exit(20); } } } /* * Set up the pointers to the virtual lines. */ for(i=0; i<page_length; i++) pageptr[i]=pagebuf+i*(page_width+1); /* * Set up the pointers to the second or more columns. * If we are doing multicolumn stuff we have to allow for the * whitespace that separates each column. Two column output is not * a problem since the space is in the page width, three or more * is. */ if(columns>1) { ii=page_length; while(ii<length) { for(i=header; i<page_length; i++,ii++) { pageptr[ii]=pageptr[i]+width+(columns-2)*3; } } } /* * Initialize some variables, remember that line and character references * are from zero. */ printf("%s%s%s", Reset, Margins, Font); cur_page=1; cur_line=0; cur_char=0; /* * Process the input stream. */ if(header) mak_hdr(); bp=pageptr[cur_line++]; *bp='\0'; while((nchars=fread(buffer, sizeof(*buffer), 512, in))>0) { rp=buffer; while(nchars>0) { if(cur_page<page_start) { switch(*rp) { case '\f': cur_page++; cur_line=0; if(header) mak_hdr(); break; case '\n': cur_line++; if(cur_line>=length) { cur_page++; cur_line=0; if(header) mak_hdr(); } break; default: break; } } else { switch(*rp) { case '\f': /* * This gets a little tricky. When we are doing * multicolumns we only want a formfeed to eject the * page if we are on the last column. For the other columns * we want to fill out the rest of the column with spaces * and start at the top of the next column. */ if(columns>1 && (length-cur_line)>=(page_length-header)) { /* * Well we weren't on the last column. Do we need to * space fill the rest of this line?. */ if(cur_char!=0) { /* * Yep, do it */ while(cur_char<width) { *bp++=' '; cur_char++; } *bp='\0'; /* * Okay, point to the next line. */ bp=pageptr[cur_line++]; *bp='\0'; cur_char=0; } /* * Now we need to space fill the rest of this column */ i=(page_length-header) -((cur_line-header)%(page_length-header)); while(i>0) { ii=(cur_line>page_length)? 3:0; for(cur_char=0; cur_char<(width+ii); cur_char++) *bp++=' '; *bp='\0'; bp=pageptr[cur_line++]; *bp='\0'; cur_char=0; i--; } } else { dump_buffer(); cur_page++; cur_char=0; cur_line=0; if(header) mak_hdr(); bp=pageptr[cur_line++]; *bp='\0'; } break; case '\t': ii=8-(cur_char)%8; while(ii>0 && cur_char<width) { *bp++=' '; cur_char++; *bp='\0'; ii--; } break; case '\n': /* * Did we just finish the last line on this physical * page? */ if(cur_line>=length) { dump_buffer(); cur_page++; cur_line=0; cur_char=0; if(header) mak_hdr(); bp=pageptr[cur_line++]; *bp='\0'; } /* * Should we space fill the remainder of this line? * We only need to if there are more columns to follow. */ if(columns>1 && cur_char<width && (length-cur_line)>=(page_length-header)) { while(cur_char<width) { *bp++=' '; cur_char++; } *bp='\0'; } /* * Columns 2, 3, and so on need withspace at the beginning * that is not actually a part of the line to separate * the columns. */ bp=pageptr[cur_line++]; if(columns>1 && cur_line>page_length) for(i=0; i<3; i++) *bp++=' '; *bp=0; cur_char=0; break; default: if(cur_char<width) { *bp++= *rp; cur_char++; *bp='\0'; } } } /* end of if(cur_page< ... */ rp++; nchars--; } } if((header && cur_line>3) || (!header && cur_line>0)) dump_buffer(); return(0); } /* * MAK_HDR * * This module takes the local time, title, and page number and forms * the header line that is printed at the top of each page. The local time * is justified against the left margin and the title and page number is * justified against the right margin as determined by "width". The header * is always printed in bold type. There are two blank lines following the * header. * */ mak_hdr() { char *bp, tmp[MAX_WIDTH]; int i, ii, iii; /* * Put the header into buffer */ bp=pageptr[cur_line++]; strcpy(bp, loctim); /* * Now get the page number string into buf */ sprintf(tmp, "%s Page %d", title, cur_page); ii=strlen(bp); bp=bp+ii; iii=strlen(tmp); for(i=ii; i<(page_width-iii); i++) *bp++=' '; for(i=0; i<iii; i++) *bp++=tmp[i]; *bp++='\0'; *pageptr[cur_line++]='\0'; *pageptr[cur_line++]='\0'; } /* * dump_buffer() * * This module dumps the virtual page. */ dump_buffer() { int i, ii; /* * Decide how much to print. We need to print all of the lines * that were actually used, but no more. When we are doing * multicolumn we only want to index on the left most column. */ ii=(cur_line>page_length)? page_length:cur_line; for(i=0; i<ii; i++) { if(header && i==0) printf("%s%s%s\r\n", Bold, pageptr[i], unBold); else printf("%s\r\n", pageptr[i]); } printf("\r\f"); fflush(stdout); } SHAR_EOF # End of shell archive exit 0