=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/pr/pr.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- src/usr.bin/pr/pr.c 1997/01/15 23:43:00 1.4 +++ src/usr.bin/pr/pr.c 1997/04/23 08:08:28 1.5 @@ -1,4 +1,4 @@ -/* $OpenBSD: pr.c,v 1.4 1997/01/15 23:43:00 millert Exp $ */ +/* $OpenBSD: pr.c,v 1.5 1997/04/23 08:08:28 grr Exp $ */ /*- * Copyright (c) 1991 Keith Muller. @@ -45,7 +45,7 @@ #ifndef lint /* from: static char sccsid[] = "@(#)pr.c 8.1 (Berkeley) 6/6/93"; */ -static char *rcsid = "$OpenBSD: pr.c,v 1.4 1997/01/15 23:43:00 millert Exp $"; +static char *rcsid = "$OpenBSD: pr.c,v 1.5 1997/04/23 08:08:28 grr Exp $"; #endif /* not lint */ #include @@ -74,1746 +74,1916 @@ */ /* + * pr: more boundary conditions than a four-legged porcupine + * + * the original version didn't support form-feeds, while many of the ad-hoc + * pr implementations out there do. Addding this and making it work reasonably + * in all four output modes required quite a bit of hacking and a few minor + * bugs were noted and fixed in the processs. Some implementations have this + * as the as -f, some as -F so we accept either. + * + * The impelmentation of form feeds on top of the existing I/O structure is + * a bit ideosyncratic. Basically they are treated as temporary end-of-file + * conditions and an additional level of "loop on form feed" is added to each + * of the output modes to continue after such a transient end-of-file's. This + * has the general benefit of making the existing header/trailer logic work + * and provides a usable framework for rational behavior in multi-column modes. + * + * The orginal "efficient" implementation of the "skip to page N" option was + * bogus and I substituted the basic inhibit printing until page N approach. + * This is still fairly bogus vis-a-vis numbering pages on multiple files + * restarting at one, but at least lets you consistantly reprint some large + * document starting in the middle, in any of the output modes. + * + * Additional support for overprinting via or would + * be nice, but is not trivial across tab interpretation, output formatting + * and the different operating modes. Support for line-wrapping, either + * strict or word-wrapped would be really useful and not all that hard to + * kludge into the inln() implementation. The general notion is that -wc n + * would specify width and wrapping with a marker character c and -Wc n + * would add word wrapping with a minimum width n and delimiters c, defaulting + * to tab, blank, and -, and column width. Word wrapping always involves + * painful policy questions which are difficult to specify unless you just + * hardwire in some fixed rules. Think quotes, punctuation and white-space + * elimination and whether you'd do the same thing with a C program and + * something like columninated newspaper text. + * + * George Robbins 4/22/97. + */ + +/* * parameter variables */ -int pgnm; /* starting page number */ -int clcnt; /* number of columns */ -int colwd; /* column data width - multiple columns */ -int across; /* mult col flag; write across page */ -int dspace; /* double space flag */ -char inchar; /* expand input char */ -int ingap; /* expand input gap */ -int formfeed; /* use formfeed as trailer */ -char *header; /* header name instead of file name */ -char ochar; /* contract output char */ -int ogap; /* contract output gap */ -int lines; /* number of lines per page */ -int merge; /* merge multiple files in output */ -char nmchar; /* line numbering append char */ -int nmwd; /* width of line number field */ -int offst; /* number of page offset spaces */ -int nodiag; /* do not report file open errors */ -char schar; /* text column separation character */ -int sflag; /* -s option for multiple columns */ -int nohead; /* do not write head and trailer */ -int pgwd; /* page width with multiple col output */ -char *timefrmt; /* time conversion string */ +int pgnm; /* starting page number */ +int skipping; /* we're skipping to page pgnum */ +int clcnt; /* number of columns */ +int colwd; /* column data width - multiple columns */ +int across; /* mult col flag; write across page */ +int dspace; /* double space flag */ +char inchar; /* expand input char */ +int ingap; /* expand input gap */ +int formfeed; /* use formfeed as trailer */ +int inform; /* grok formfeeds in input */ +char *header; /* header name instead of file name */ +char ochar; /* contract output char */ +int ogap; /* contract output gap */ +int lines; /* number of lines per page */ +int merge; /* merge multiple files in output */ +char nmchar; /* line numbering append char */ +int nmwd; /* width of line number field */ +int offst; /* number of page offset spaces */ +int nodiag; /* do not report file open errors */ +char schar; /* text column separation character */ +int sflag; /* -s option for multiple columns */ +int nohead; /* do not write head and trailer */ +int pgwd; /* page width with multiple col output */ +char *timefrmt; /* time conversion string */ /* * misc globals */ -FILE *err; /* error message file pointer */ -int addone; /* page length is odd with double space */ -int errcnt; /* error count on file processing */ +FILE *err; /* error message file pointer */ +int addone = 0; /* page length is odd with double space */ +int errcnt = 0; /* error count on file processing */ +int beheaded = 0; /* header / trailer link */ char digs[] = "0123456789"; /* page number translation map */ int main(argc, argv) - int argc; - char *argv[]; + int argc; + char *argv[]; { - int ret_val; + int ret_val; - if (signal(SIGINT, SIG_IGN) != SIG_IGN) - (void)signal(SIGINT, terminate); - ret_val = setup(argc, argv); - if (!ret_val) { - /* - * select the output format based on options - */ - if (merge) - ret_val = mulfile(argc, argv); - else if (clcnt == 1) - ret_val = onecol(argc, argv); - else if (across) - ret_val = horzcol(argc, argv); - else - ret_val = vertcol(argc, argv); - } else - usage(); - flsh_errs(); - if (errcnt || ret_val) - exit(1); - return(0); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + (void)signal(SIGINT, terminate); + ret_val = setup(argc, argv); + if (!ret_val) { + /* + * select the output format based on options + */ + if (merge) + ret_val = mulfile(argc, argv); + else if (clcnt == 1) + ret_val = onecol(argc, argv); + else if (across) + ret_val = horzcol(argc, argv); + else + ret_val = vertcol(argc, argv); + } else + usage(); + flsh_errs(); + if (errcnt || ret_val) + exit(1); + return(0); } /* - * onecol: print files with only one column of output. - * Line length is unlimited. + * onecol: print files with only one column of output. + * Line length is unlimited. */ int onecol(argc, argv) - int argc; - char *argv[]; + int argc; + char *argv[]; { - register int cnt = -1; - register int off; - register int lrgln; - register int linecnt; - register int num; - int lncnt; - int pagecnt; - int ips; - int ops; - int cps; - char *obuf; - char *lbuf; - char *nbuf; - char *hbuf; - char *ohbuf; - FILE *inf; - char *fname; - int mor; + register int off; + register int lrgln; + register int linecnt; + register int num; + int cnt; + int rc; + int lncnt; + int pagecnt; + int ips; + int ops; + int cps; + char *obuf; + char *lbuf; + char *nbuf; + char *hbuf; + char *ohbuf; + FILE *inf; + char *fname; + int mor; - if (nmwd) - num = nmwd + 1; - else - num = 0; - off = num + offst; + if (nmwd) + num = nmwd + 1; + else + num = 0; + off = num + offst; - /* - * allocate line buffer - */ - if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) { - mfail(); - return(1); - } - /* - * allocate header buffer - */ - if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { - mfail(); - return(1); - } + /* + * allocate line buffer + */ + if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) { + mfail(); + return(1); + } - ohbuf = hbuf + offst; - nbuf = obuf + offst; - lbuf = nbuf + num; - if (num) - nbuf[--num] = nmchar; - if (offst) { - (void)memset(obuf, (int)' ', offst); - (void)memset(hbuf, (int)' ', offst); - } + /* + * allocate header buffer + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + ohbuf = hbuf + offst; + nbuf = obuf + offst; + lbuf = nbuf + num; + + if (num) + nbuf[--num] = nmchar; + + if (offst) { + (void)memset(obuf, (int)' ', offst); + (void)memset(hbuf, (int)' ', offst); + } + + /* + * loop by file + */ + while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { + pagecnt = 0; + lncnt = 0; + /* - * loop by file + * loop by "form" */ - while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { - if (pgnm) { - /* - * skip to specified page - */ - if (inskip(inf, pgnm, lines)) - continue; - pagecnt = pgnm; - } else - pagecnt = 1; - lncnt = 0; + for(;;) { + /* + * loop by page + */ + for(;;) { + linecnt = 0; + lrgln = 0; + ops = 0; + ips = 0; + cps = 0; + /* - * loop by page + * loop by line */ - for(;;) { - linecnt = 0; - lrgln = 0; - ops = 0; - ips = 0; - cps = 0; + while (linecnt < lines) { - /* - * loop by line - */ - while (linecnt < lines) { - /* - * input next line - */ - if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0) - break; - if (!linecnt && !nohead && - prhead(hbuf, fname, pagecnt)) - return(1); + /* + * input next line + */ + rc = inln(inf,lbuf,LBUF,&cnt,&cps,0,&mor); + if (cnt >= 0) { + if (!lrgln) + if (!linecnt && prhead(hbuf, fname, ++pagecnt)) + return(1); - /* - * start of new line. - */ - if (!lrgln) { - if (num) - addnum(nbuf, num, ++lncnt); - if (otln(obuf,cnt+off, &ips, &ops, mor)) - return(1); - } else if (otln(lbuf, cnt, &ips, &ops, mor)) - return(1); - - /* - * if line bigger than buffer, get more - */ - if (mor) { - lrgln = 1; - continue; - } - - /* - * whole line rcvd. reset tab proc. state - */ - ++linecnt; - lrgln = 0; - ops = 0; - ips = 0; - } - /* - * fill to end of page + * start new line or continue a long one */ - if (linecnt && prtail(lines-linecnt-lrgln, lrgln)) + if (!lrgln) { + if (num) + addnum(nbuf, num, ++lncnt); + if (otln(obuf,cnt+off, &ips, &ops, mor)) return(1); + } else + if (otln(lbuf, cnt, &ips, &ops, mor)) + return(1); /* - * On EOF go to next file + * if line bigger than buffer, get more */ - if (cnt < 0) - break; - ++pagecnt; + if (mor) { + lrgln = 1; + } else { + /* + * whole line rcvd. reset tab proc. state + */ + ++linecnt; + lrgln = 0; + ops = 0; + ips = 0; + } + } + + if (rc != NORMAL) + break; } - if (inf != stdin) - (void)fclose(inf); + + /* + * fill to end of page + */ + if (prtail(lines - linecnt, lrgln)) + return(1); + + /* + * unless END continue + */ + if (rc == END) + break; + } + + /* + * On EOF go to next file + */ + if (rc == END) + break; } - if (eoptind < argc) - return(1); + + if (inf != stdin) + (void)fclose(inf); + } + /* + * If we didn't process all the files, return error + */ + if (eoptind < argc) + return(1); + else return(0); } /* * vertcol: print files with more than one column of output down a page + * the general approach is to buffer a page of data, then print */ int vertcol(argc, argv) - int argc; - char *argv[]; + int argc; + char *argv[]; { - register char *ptbf; - register char **lstdat; - register int i; - register int j; - register int cnt = -1; - register int pln; - register int *indy; - int cvc; - int *lindy; - int lncnt; - int stp; - int pagecnt; - int col = colwd + 1; - int mxlen = pgwd + offst + 1; - int mclcnt = clcnt - 1; - struct vcol *vc; - int mvc; - int tvc; - int cw = nmwd + 1; - int fullcol; - char *buf; - char *hbuf; - char *ohbuf; - char *fname; - FILE *inf; - int ips = 0; - int cps = 0; - int ops = 0; - int mor = 0; + register char *ptbf; + register char **lstdat; + register int i; + register int j; + register int pln; + register int *indy; + int cnt; + int rc; + int cvc; + int *lindy; + int lncnt; + int stp; + int pagecnt; + int col = colwd + 1; + int mxlen = pgwd + offst + 1; + int mclcnt = clcnt - 1; + struct vcol *vc; + int mvc; + int tvc; + int cw = nmwd + 1; + int fullcol; + char *buf; + char *hbuf; + char *ohbuf; + char *fname; + FILE *inf; + int ips = 0; + int cps = 0; + int ops = 0; + int mor = 0; - /* - * allocate page buffer - */ - if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) { - mfail(); - return(1); - } + /* + * allocate page buffer + */ + if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) { + mfail(); + return(1); + } - /* - * allocate page header - */ - if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { - mfail(); - return(1); - } - ohbuf = hbuf + offst; - if (offst) - (void)memset(hbuf, (int)' ', offst); + /* + * allocate page header + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } - /* - * col pointers when no headers - */ - mvc = lines * clcnt; - if ((vc = - (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) { - mfail(); - return(1); - } + ohbuf = hbuf + offst; + if (offst) + (void)memset(hbuf, (int)' ', offst); - /* - * pointer into page where last data per line is located - */ - if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){ - mfail(); - return(1); - } + /* + * col pointers when no headers + */ + mvc = lines * clcnt; + if ((vc=(struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) { + mfail(); + return(1); + } - /* - * fast index lookups to locate start of lines - */ - if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { - mfail(); - return(1); - } - if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { - mfail(); - return(1); - } + /* + * pointer into page where last data per line is located + */ + if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){ + mfail(); + return(1); + } - if (nmwd) - fullcol = col + cw; - else - fullcol = col; + /* + * fast index lookups to locate start of lines + */ + if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { + mfail(); + return(1); + } + if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { + mfail(); + return(1); + } - /* - * initialize buffer lookup indexes and offset area - */ - for (j = 0; j < lines; ++j) { - lindy[j] = j * mxlen; - indy[j] = lindy[j] + offst; - if (offst) { - ptbf = buf + lindy[j]; - (void)memset(ptbf, (int)' ', offst); - ptbf += offst; - } else - ptbf = buf + indy[j]; - lstdat[j] = ptbf; - } + if (nmwd) + fullcol = col + cw; + else + fullcol = col; + /* + * initialize buffer lookup indexes and offset area + */ + for (j = 0; j < lines; ++j) { + lindy[j] = j * mxlen; + indy[j] = lindy[j] + offst; + if (offst) { + ptbf = buf + lindy[j]; + (void)memset(ptbf, (int)' ', offst); + ptbf += offst; + } else + ptbf = buf + indy[j]; + lstdat[j] = ptbf; + } + + /* + * loop by file + */ + while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { + pagecnt = 0; + lncnt = 0; + /* - * loop by file + * loop by "form" */ - while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { - if (pgnm) { - /* - * skip to requested page - */ - if (inskip(inf, pgnm, lines)) - continue; - pagecnt = pgnm; - } else - pagecnt = 1; - lncnt = 0; + for (;;) { + /* + * loop by page + */ + for(;;) { + /* - * loop by page + * loop by column */ - for(;;) { + cvc = 0; + for (i = 0; i < clcnt; ++i) { + j = 0; + /* + * if last column, do not pad + */ + if (i == mclcnt) + stp = 1; + else + stp = 0; + + /* + * loop by line + */ + for(;;) { /* - * loop by column + * is this first column */ - cvc = 0; - for (i = 0; i < clcnt; ++i) { - j = 0; - /* - * if last column, do not pad - */ - if (i == mclcnt) - stp = 1; - else - stp = 0; - /* - * loop by line - */ - for(;;) { - /* - * is this first column - */ - if (!i) { - ptbf = buf + indy[j]; - lstdat[j] = ptbf; - } else - ptbf = lstdat[j]; - vc[cvc].pt = ptbf; + if (!i) { + ptbf = buf + indy[j]; + lstdat[j] = ptbf; + } else + ptbf = lstdat[j]; + vc[cvc].pt = ptbf; - /* - * add number - */ - if (nmwd) { - addnum(ptbf, nmwd, ++lncnt); - ptbf += nmwd; - *ptbf++ = nmchar; - } - - /* - * input next line - */ - cnt = inln(inf,ptbf,colwd,&cps,1,&mor); - vc[cvc++].cnt = cnt; - if (cnt < 0) - break; - ptbf += cnt; - - /* - * pad all but last column on page - */ - if (!stp) { - /* - * pad to end of column - */ - if (sflag) - *ptbf++ = schar; - else if ((pln = col-cnt) > 0) { - (void)memset(ptbf, - (int)' ',pln); - ptbf += pln; - } - } - /* - * remember last char in line - */ - lstdat[j] = ptbf; - if (++j >= lines) - break; - } - if (cnt < 0) - break; - } - /* - * when -t (no header) is specified the spec requires - * the min number of lines. The last page may not have - * balanced length columns. To fix this we must reorder - * the columns. This is a very slow technique so it is - * only used under limited conditions. Without -t, the - * balancing of text columns is unspecified. To NOT - * balance the last page, add the global variable - * nohead to the if statement below e.g. - * - * if ((cnt < 0) && nohead && cvc ...... + * add number */ - --cvc; + if (nmwd) { + addnum(ptbf, nmwd, ++lncnt); + ptbf += nmwd; + *ptbf++ = nmchar; + } /* - * check to see if last page needs to be reordered + * input next line */ - if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){ - pln = cvc/clcnt; - if (cvc % clcnt) - ++pln; + rc = inln(inf,ptbf,colwd,&cnt,&cps,1,&mor); + vc[cvc++].cnt = cnt; + if (cnt >= 0) { + ptbf += cnt; + /* + * pad all but last column on page + */ + if (!stp) { /* - * print header + * pad to end of column */ - if (!nohead && prhead(hbuf, fname, pagecnt)) - return(1); - for (i = 0; i < pln; ++i) { - ips = 0; - ops = 0; - if (offst&& otln(buf,offst,&ips,&ops,1)) - return(1); - tvc = i; - - for (j = 0; j < clcnt; ++j) { - /* - * determine column length - */ - if (j == mclcnt) { - /* - * last column - */ - cnt = vc[tvc].cnt; - if (nmwd) - cnt += cw; - } else if (sflag) { - /* - * single ch between - */ - cnt = vc[tvc].cnt + 1; - if (nmwd) - cnt += cw; - } else - cnt = fullcol; - if (otln(vc[tvc].pt, cnt, &ips, - &ops, 1)) - return(1); - tvc += pln; - if (tvc >= cvc) - break; - } - /* - * terminate line - */ - if (otln(buf, 0, &ips, &ops, 0)) - return(1); + if (sflag) + *ptbf++ = schar; + else if ((pln = col-cnt) > 0) { + (void)memset(ptbf, + (int)' ',pln); + ptbf += pln; } + } + + /* + * remember last char in line + */ + lstdat[j] = ptbf; + if (++j >= lines) + break; + } /* end of if cnt >= 0 */ + + if (rc != NORMAL) + break; + } /* end of for line */ + + if (rc != NORMAL) + break; + } /* end of for column */ + + /* + * when -t (no header) is specified the spec requires + * the min number of lines. The last page may not have + * balanced length columns. To fix this we must reorder + * the columns. This is a very slow technique so it is + * only used under limited conditions. Without -t, the + * balancing of text columns is unspecified. To NOT + * balance the last page, add the global variable + * nohead to the if statement below e.g. + */ + + /* + * print header iff we got anything on the first read + */ + if (vc[0].cnt >= 0) { + if (prhead(hbuf, fname, ++pagecnt)) + return(1); + + /* + * check to see if "last" page needs to be reordered + */ + --cvc; + if ((rc != NORMAL) && cvc && ((mvc-cvc) >= clcnt)){ + pln = cvc/clcnt; + if (cvc % clcnt) + ++pln; + + for (i = 0; i < pln; ++i) { + ips = 0; + ops = 0; + if (offst && otln(buf,offst,&ips,&ops,1)) + return(1); + tvc = i; + + for (j = 0; j < clcnt; ++j) { /* - * pad to end of page + * determine column length */ - if (prtail((lines - pln), 0)) - return(1); - /* - * done with output, go to next file - */ - break; + if (j == mclcnt) { + /* + * last column + */ + cnt = vc[tvc].cnt; + if (nmwd) + cnt += cw; + } else if (sflag) { + /* + * single ch between + */ + cnt = vc[tvc].cnt + 1; + if (nmwd) + cnt += cw; + } else + cnt = fullcol; + + if (otln(vc[tvc].pt, cnt, &ips, &ops, 1)) + return(1); + tvc += pln; + if (tvc > cvc) + break; + } + /* + * terminate line + */ + if (otln(buf, 0, &ips, &ops, 0)) + return(1); } + } else { + /* + * just a normal page... * determine how many lines to output */ if (i > 0) - pln = lines; + pln = lines; else - pln = j; + pln = j; /* - * print header - */ - if (pln && !nohead && prhead(hbuf, fname, pagecnt)) - return(1); - - /* * output each line */ for (i = 0; i < pln; ++i) { - ptbf = buf + lindy[i]; - if ((j = lstdat[i] - ptbf) <= offst) - break; + ptbf = buf + lindy[i]; + if ((j = lstdat[i] - ptbf) <= offst) + break; + else { + ips = 0; + ops = 0; if (otln(ptbf, j, &ips, &ops, 0)) - return(1); + return(1); + } } + } + } - /* - * pad to end of page - */ - if (pln && prtail((lines - pln), 0)) - return(1); + /* + * pad to end of page + */ + if (prtail((lines - pln), 0)) + return(1); - /* - * if EOF go to next file - */ - if (cnt < 0) - break; - ++pagecnt; - } - if (inf != stdin) - (void)fclose(inf); + /* + * if FORM continue + */ + if (rc != NORMAL) + break; + } + + /* + * if EOF go to next file + */ + if (rc == END) + break; } - if (eoptind < argc) - return(1); + + if (inf != stdin) + (void)fclose(inf); + } + + if (eoptind < argc) + return(1); + else return(0); } /* - * horzcol: print files with more than one column of output across a page + * horzcol: print files with more than one column of output across a page */ int horzcol(argc, argv) - int argc; - char *argv[]; + int argc; + char *argv[]; { - register char *ptbf; - register int pln; - register int cnt = -1; - register char *lstdat; - register int col = colwd + 1; - register int j; - register int i; - int lncnt; - int pagecnt; - char *buf; - char *hbuf; - char *ohbuf; - char *fname; - FILE *inf; - int ips = 0; - int cps = 0; - int ops = 0; - int mor = 0; + register char *ptbf; + register int pln; + register char *lstdat; + register int col = colwd + 1; + register int j; + register int i; + int cnt; + int rc; + int lncnt; + int pagecnt; + char *buf; + char *hbuf; + char *ohbuf; + char *fname; + FILE *inf; + int cps = 0; + int mor = 0; + int ips = 0; + int ops = 0; - if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { - mfail(); - return(1); - } + if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { + mfail(); + return(1); + } - /* - * page header - */ - if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { - mfail(); - return(1); - } - ohbuf = hbuf + offst; - if (offst) { - (void)memset(buf, (int)' ', offst); - (void)memset(hbuf, (int)' ', offst); - } + /* + * page header + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + ohbuf = hbuf + offst; + if (offst) { + (void)memset(buf, (int)' ', offst); + (void)memset(hbuf, (int)' ', offst); + } + + /* + * loop by file + */ + while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { + pagecnt = 0; + lncnt = 0; + /* - * loop by file + * loop by form */ - while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { - if (pgnm) { - if (inskip(inf, pgnm, lines)) - continue; - pagecnt = pgnm; - } else - pagecnt = 1; - lncnt = 0; + for (;;) { + /* + * loop by page + */ + for(;;) { + /* - * loop by page + * loop by line */ - for(;;) { + for (i = 0; i < lines; ++i) { + ptbf = buf + offst; + lstdat = ptbf; + j = 0; + + /* + * loop by col + */ + for(;;) { + if (nmwd) { + /* + * add number to column + */ + addnum(ptbf, nmwd, ++lncnt); + ptbf += nmwd; + *ptbf++ = nmchar; + } /* - * loop by line + * input line */ - for (i = 0; i < lines; ++i) { - ptbf = buf + offst; - lstdat = ptbf; - j = 0; - /* - * loop by col - */ - for(;;) { - if (nmwd) { - /* - * add number to column - */ - addnum(ptbf, nmwd, ++lncnt); - ptbf += nmwd; - *ptbf++ = nmchar; - } - /* - * input line - */ - if ((cnt = inln(inf,ptbf,colwd,&cps,1, - &mor)) < 0) - break; - ptbf += cnt; - lstdat = ptbf; + rc = inln(inf,ptbf,colwd,&cnt,&cps,1, &mor); + if (cnt >= 0) { + if (!i && !j && prhead(hbuf, fname, ++pagecnt)) + return(1); - /* - * if last line skip padding - */ - if (++j >= clcnt) - break; + ptbf += cnt; + lstdat = ptbf; - /* - * pad to end of column - */ - if (sflag) - *ptbf++ = schar; - else if ((pln = col - cnt) > 0) { - (void)memset(ptbf,(int)' ',pln); - ptbf += pln; - } - } + /* + * if last line skip padding + */ + if (++j >= clcnt) + break; - /* - * determine line length - */ - if ((j = lstdat - buf) <= offst) - break; - if (!i && !nohead && - prhead(hbuf, fname, pagecnt)) - return(1); - /* - * output line - */ - if (otln(buf, j, &ips, &ops, 0)) - return(1); + /* + * pad to end of column + */ + if (sflag) + *ptbf++ = schar; + else if ((pln = col - cnt) > 0) { + (void)memset(ptbf,(int)' ',pln); + ptbf += pln; + } } + if (rc != NORMAL) + break; + } - /* - * pad to end of page - */ - if (i && prtail(lines-i, 0)) - return(1); + /* + * output line if any columns on it + */ + if (j) { + if (otln(buf, lstdat-buf, &ips, &ops, 0)) + return(1); + } - /* - * if EOF go to next file - */ - if (cnt < 0) - break; - ++pagecnt; + if (rc != NORMAL) + break; } - if (inf != stdin) - (void)fclose(inf); + + /* + * pad to end of page + */ + if (prtail(lines - i, 0)) + return(1); + + /* + * if FORM continue + */ + if (rc == END) + break; + } + /* + * if EOF go to next file + */ + if (rc == END) + break; } - if (eoptind < argc) - return(1); - return(0); + if (inf != stdin) + (void)fclose(inf); + } + if (eoptind < argc) + return(1); + return(0); } /* - * mulfile: print files with more than one column of output and - * more than one file concurrently + * mulfile: print files with more than one column of output and + * more than one file concurrently */ int mulfile(argc, argv) - int argc; - char *argv[]; + int argc; + char *argv[]; { - register char *ptbf; - register int j; - register int pln; - register int cnt; - register char *lstdat; - register int i; - FILE **fbuf; - int actf; - int lncnt; - int col; - int pagecnt; - int fproc; - char *buf; - char *hbuf; - char *ohbuf; - char *fname; - int ips = 0; - int cps = 0; - int ops = 0; - int mor = 0; + register char *ptbf; + register int j; + register int pln; + int *rc; + int cnt; + register char *lstdat; + register int i; + FILE **fbuf; + int actf; + int lncnt; + int col; + int pagecnt; + int fproc; + char *buf; + char *hbuf; + char *ohbuf; + char *fname; + int ips = 0; + int cps = 0; + int ops = 0; + int mor = 0; - /* - * array of FILE *, one for each operand - */ - if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) { - mfail(); - return(1); - } + /* + * array of FILE *, one for each operand + */ + if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) { + mfail(); + return(1); + } - /* - * page header - */ - if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { - mfail(); - return(1); - } - ohbuf = hbuf + offst; + /* + * array of int *, one for each operand + */ + if ((rc = (int *)malloc((unsigned)clcnt*sizeof(int))) == NULL) { + mfail(); + return(1); + } - /* - * do not know how many columns yet. The number of operands provide an - * upper bound on the number of columns. We use the number of files - * we can open successfully to set the number of columns. The operation - * of the merge operation (-m) in relation to unsuccesful file opens - * is unspecified by posix. - */ - j = 0; - while (j < clcnt) { - if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL) - break; - if (pgnm && (inskip(fbuf[j], pgnm, lines))) - fbuf[j] = NULL; - ++j; + /* + * page header + */ + if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + ohbuf = hbuf + offst; + + /* + * do not know how many columns yet. The number of operands provide an + * upper bound on the number of columns. We use the number of files + * we can open successfully to set the number of columns. The operation + * of the merge operation (-m) in relation to unsuccesful file opens + * is unspecified by posix. + * + * XXX - this seems moderately bogus, you'd think that specifying + * "pr -2 a b c d" would run though all the files in pairs, but + * the existing code says up two files, or fewer if one is bogus. + * fixing it would require modifying the looping structure, so be it. + */ + j = 0; + while (j < clcnt) { + if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) != NULL) { + rc[j] = NORMAL; + j++; } + } - /* - * if no files, exit - */ - if (!j) - return(1); - - /* - * calculate page boundries based on open file count - */ + /* + * if no files, exit + */ + if (j) clcnt = j; - if (nmwd) { - colwd = (pgwd - clcnt - nmwd)/clcnt; - pgwd = ((colwd + 1) * clcnt) - nmwd - 2; - } else { - colwd = (pgwd + 1 - clcnt)/clcnt; - pgwd = ((colwd + 1) * clcnt) - 1; - } - if (colwd < 1) { - (void)fprintf(err, - "pr: page width too small for %d columns\n", clcnt); - return(1); - } - actf = clcnt; - col = colwd + 1; + else + return(1); - /* - * line buffer - */ - if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { - mfail(); - return(1); - } - if (offst) { - (void)memset(buf, (int)' ', offst); - (void)memset(hbuf, (int)' ', offst); - } - if (pgnm) - pagecnt = pgnm; - else - pagecnt = 1; - lncnt = 0; + /* + * calculate page boundries based on open file count + */ + if (nmwd) { + colwd = (pgwd - clcnt - nmwd)/clcnt; + pgwd = ((colwd + 1) * clcnt) - nmwd - 2; + } else { + colwd = (pgwd + 1 - clcnt)/clcnt; + pgwd = ((colwd + 1) * clcnt) - 1; + } + if (colwd < 1) { + (void)fprintf(err, + "pr: page width too small for %d columns\n", clcnt); + return(1); + } + col = colwd + 1; + /* + * line buffer + */ + if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { + mfail(); + return(1); + } + if (offst) { + (void)memset(buf, (int)' ', offst); + (void)memset(hbuf, (int)' ', offst); + } + + pagecnt = 0; + lncnt = 0; + actf = clcnt; + + /* + * continue to loop while any file still has data + */ + while (actf > 0) { + /* - * continue to loop while any file still has data + * loop on "form" */ - while (actf > 0) { + for (;;) { + + /* + * loop by line + */ + for (i = 0; i < lines; ++i) { + ptbf = buf + offst; + lstdat = ptbf; + if (nmwd) { + /* + * add line number to line + */ + addnum(ptbf, nmwd, ++lncnt); + ptbf += nmwd; + *ptbf++ = nmchar; + } + + fproc = 0; /* - * loop by line + * loop by column */ - for (i = 0; i < lines; ++i) { - ptbf = buf + offst; - lstdat = ptbf; - if (nmwd) { - /* - * add line number to line - */ - addnum(ptbf, nmwd, ++lncnt); - ptbf += nmwd; - *ptbf++ = nmchar; + for (j = 0; j < clcnt; ++j) { + if (rc[j] == NORMAL ) { + rc[j] = inln(fbuf[j], ptbf, colwd, &cnt, &cps, 1, &mor); + if (cnt >= 0) { + /* + * process file data + */ + ptbf += cnt; + lstdat = ptbf; + fproc++; + } else + cnt = 0; + + if (rc[j] == END) { + /* + * EOF close file + */ + if (fbuf[j] != stdin) + (void)fclose(fbuf[j]); + --actf; } - j = 0; - fproc = 0; + } else + cnt = 0; - /* - * loop by column - */ - for (j = 0; j < clcnt; ++j) { - if (fbuf[j] == NULL) { - /* - * empty column; EOF - */ - cnt = 0; - } else if ((cnt = inln(fbuf[j], ptbf, colwd, - &cps, 1, &mor)) < 0) { - /* - * EOF hit; no data - */ - if (fbuf[j] != stdin) - (void)fclose(fbuf[j]); - fbuf[j] = NULL; - --actf; - cnt = 0; - } else { - /* - * process file data - */ - ptbf += cnt; - lstdat = ptbf; - fproc++; - } + /* + * if last ACTIVE column, done with line + */ + if (fproc >= actf) + break; - /* - * if last ACTIVE column, done with line - */ - if (fproc >= actf) - break; - - /* - * pad to end of column - */ - if (sflag) { - *ptbf++ = schar; - } else if ((pln = col - cnt) > 0) { - (void)memset(ptbf, (int)' ', pln); - ptbf += pln; - } + /* + * pad to end of column + */ + if (sflag) { + *ptbf++ = schar; + } else { + if (cnt >= 0) + pln = col - cnt; + else + pln = col; + if (pln > 0) { + (void)memset(ptbf, (int)' ', pln); + ptbf += pln; } - - /* - * calculate data in line - */ - if ((j = lstdat - buf) <= offst) - break; - - if (!i && !nohead && prhead(hbuf, fname, pagecnt)) - return(1); - - /* - * output line - */ - if (otln(buf, j, &ips, &ops, 0)) - return(1); - - /* - * if no more active files, done - */ - if (actf <= 0) { - ++i; - break; - } + } } /* - * pad to end of page + * if there was anything to do, print it */ - if (i && prtail(lines-i, 0)) + if (fproc != 0) { + if (!i && prhead(hbuf, fname, ++pagecnt)) return(1); - ++pagecnt; - } - if (eoptind < argc) + + /* + * output line + */ + if (otln(buf, lstdat-buf, &ips, &ops, 0)) + return(1); + } else + break; + } + + /* + * pad to end of page + */ + if (prtail(lines - i, 0)) return(1); - return(0); + + for (j = 0; j < clcnt; ++j) + if (rc[j] != END) + rc[j] = NORMAL; + + if (actf <= 0) + break; + } + if (actf <= 0) + break; + } + if (eoptind < argc) + return(1); + return(0); } /* - * inln(): input a line of data (unlimited length lines supported) - * Input is optionally expanded to spaces + * inln(): input a line of data (unlimited length lines supported) + * Input is optionally expanded to spaces + * Returns 0 if normal LF, FORM on Formfeed, and END on EOF * - * inf: file - * buf: buffer - * lim: buffer length - * cps: column positon 1st char in buffer (large line support) - * trnc: throw away data more than lim up to \n - * mor: set if more data in line (not truncated) + * inf: file + * buf: buffer + * lim: buffer length + * cnt: line length or -1 if no line (EOF for example) + * cps: column positon 1st char in buffer (large line support) + * trnc: throw away data more than lim up to \n + * mor: set if more data in line (not truncated) */ int -inln(inf, buf, lim, cps, trnc, mor) - FILE *inf; - char *buf; - register int lim; - int *cps; - int trnc; - int *mor; +inln(inf, buf, lim, cnt, cps, trnc, mor) + FILE *inf; + char *buf; + register int lim; + int *cnt; + int *cps; + int trnc; + int *mor; { - register int col; - register int gap = ingap; - register int ch = EOF; - register char *ptbuf; - register int chk = (int)inchar; + register int col; + register int gap = ingap; + register int ch = EOF; + register char *ptbuf; + register int chk = (int)inchar; - ptbuf = buf; + ptbuf = buf; - if (gap) { + if (gap) { + /* + * expanding input option + */ + while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { + /* + * is this the input "tab" char + */ + if (ch == chk) { /* - * expanding input option + * expand to number of spaces */ - while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { - /* - * is this the input "tab" char - */ - if (ch == chk) { - /* - * expand to number of spaces - */ - col = (ptbuf - buf) + *cps; - col = gap - (col % gap); + col = (ptbuf - buf) + *cps; + col = gap - (col % gap); - /* - * if more than this line, push back - */ - if ((col > lim) && (ungetc(ch, inf) == EOF)) - return(1); - - /* - * expand to spaces - */ - while ((--col >= 0) && (--lim >= 0)) - *ptbuf++ = ' '; - continue; - } - if (ch == '\n') - break; - *ptbuf++ = ch; - } - } else { /* - * no expansion + * if more than this line, push back */ - while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { - if (ch == '\n') - break; - *ptbuf++ = ch; + if ((col > lim) && (ungetc(ch, inf) == EOF)) { + *cnt = -1; + return(END); /* shouldn't happen */ } - } - col = ptbuf - buf; - if (ch == EOF) { - *mor = 0; - *cps = 0; - if (!col) - return(-1); - return(col); - } - if (ch == '\n') { + /* - * entire line processed + * expand to spaces */ - *mor = 0; - *cps = 0; - return(col); + while ((--col >= 0) && (--lim >= 0)) + *ptbuf++ = ' '; + continue; + } + if (ch == '\n' || inform && ch == INFF) + break; + *ptbuf++ = ch; } + } else { + /* + * no expansion + */ + while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { + if (ch == '\n' || inform && ch == INFF) + break; + *ptbuf++ = ch; + } + } + col = ptbuf - buf; + if (ch == EOF) { + *mor = 0; + *cps = 0; + *cnt = col ? col : -1; + return(END); + } + if (inform && ch == INFF) { + *mor = 0; + *cps = 0; + *cnt = col; + return(FORM); + } + if (ch == '\n') { + /* + * entire line processed + */ + *mor = 0; + *cps = 0; + *cnt = col; + return(NORMAL); + } + /* + * line was larger than limit + */ + if (trnc) { /* - * line was larger than limit + * throw away rest of line */ - if (trnc) { - /* - * throw away rest of line - */ - while ((ch = getc(inf)) != EOF) { - if (ch == '\n') - break; - } - *cps = 0; - *mor = 0; - } else { - /* - * save column offset if not truncated - */ - *cps += col; - *mor = 1; + while ((ch = getc(inf)) != EOF) { + if (ch == '\n') + break; } + *cps = 0; + *mor = 0; + } else { + /* + * save column offset if not truncated + */ + *cps += col; + *mor = 1; + } - return(col); + *cnt = col; + return(NORMAL); } /* - * otln(): output a line of data. (Supports unlimited length lines) - * output is optionally contracted to tabs + * otln(): output a line of data. (Supports unlimited length lines) + * output is optionally contracted to tabs * - * buf: output buffer with data - * cnt: number of chars of valid data in buf - * svips: buffer input column position (for large lines) - * svops: buffer output column position (for large lines) - * mor: output line not complete in this buf; more data to come. - * 1 is more, 0 is complete, -1 is no \n's + * buf: output buffer with data + * cnt: number of chars of valid data in buf + * svips: buffer input column position (for large lines) + * svops: buffer output column position (for large lines) + * mor: output line not complete in this buf; more data to come. + * 1 is more, 0 is complete, -1 is no \n's */ int otln(buf, cnt, svips, svops, mor) - register char *buf; - int cnt; - int *svops; - int *svips; - int mor; + register char *buf; + int cnt; + int *svops; + int *svips; + int mor; { - register int ops; /* last col output */ - register int ips; /* last col in buf examined */ - register int gap = ogap; - register int tbps; - register char *endbuf; + register int ops; /* last col output */ + register int ips; /* last col in buf examined */ + register int gap = ogap; + register int tbps; + register char *endbuf; - if (ogap) { - /* - * contracting on output - */ - endbuf = buf + cnt; - ops = *svops; - ips = *svips; - while (buf < endbuf) { - /* - * count number of spaces and ochar in buffer - */ - if (*buf == ' ') { - ++ips; - ++buf; - continue; - } + /* skipping is only changed at header time not mid-line! */ + if (skipping) + return (0); - /* - * simulate ochar processing - */ - if (*buf == ochar) { - ips += gap - (ips % gap); - ++buf; - continue; - } + if (ogap) { + /* + * contracting on output + */ + endbuf = buf + cnt; + ops = *svops; + ips = *svips; + while (buf < endbuf) { + /* + * count number of spaces and ochar in buffer + */ + if (*buf == ' ') { + ++ips; + ++buf; + continue; + } - /* - * got a non space char; contract out spaces - */ - while (ops < ips) { - /* - * use as many ochar as will fit - */ - if ((tbps = ops + gap - (ops % gap)) > ips) - break; - if (putchar(ochar) == EOF) { - pfail(); - return(1); - } - ops = tbps; - } + /* + * simulate ochar processing + */ + if (*buf == ochar) { + ips += gap - (ips % gap); + ++buf; + continue; + } - while (ops < ips) { - /* - * finish off with spaces - */ - if (putchar(' ') == EOF) { - pfail(); - return(1); - } - ++ops; - } - - /* - * output non space char - */ - if (putchar(*buf++) == EOF) { - pfail(); - return(1); - } - ++ips; - ++ops; + /* + * got a non space char; contract out spaces + */ + while (ops < ips) { + /* + * use as many ochar as will fit + */ + if ((tbps = ops + gap - (ops % gap)) > ips) + break; + if (putchar(ochar) == EOF) { + pfail(); + return(1); } + ops = tbps; + } - if (mor > 0) { - /* - * if incomplete line, save position counts - */ - *svops = ops; - *svips = ips; - return(0); + while (ops < ips) { + /* + * finish off with spaces + */ + if (putchar(' ') == EOF) { + pfail(); + return(1); } + ++ops; + } - if (mor < 0) { - while (ops < ips) { - /* - * use as many ochar as will fit - */ - if ((tbps = ops + gap - (ops % gap)) > ips) - break; - if (putchar(ochar) == EOF) { - pfail(); - return(1); - } - ops = tbps; - } - while (ops < ips) { - /* - * finish off with spaces - */ - if (putchar(' ') == EOF) { - pfail(); - return(1); - } - ++ops; - } - return(0); + /* + * output non space char + */ + if (putchar(*buf++) == EOF) { + pfail(); + return(1); + } + ++ips; + ++ops; + } + + if (mor > 0) { + /* + * if incomplete line, save position counts + */ + *svops = ops; + *svips = ips; + return(0); + } + + if (mor < 0) { + while (ops < ips) { + /* + * use as many ochar as will fit + */ + if ((tbps = ops + gap - (ops % gap)) > ips) + break; + if (putchar(ochar) == EOF) { + pfail(); + return(1); } - } else { + ops = tbps; + } + while (ops < ips) { /* - * output is not contracted + * finish off with spaces */ - if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) { - pfail(); - return(1); + if (putchar(' ') == EOF) { + pfail(); + return(1); } - if (mor != 0) - return(0); + ++ops; + } + return(0); } - + } else { /* - * process line end and double space as required + * output is not contracted */ - if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) { - pfail(); - return(1); + if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) { + pfail(); + return(1); } - return(0); + if (mor != 0) + return(0); + } + + /* + * process line end and double space as required + */ + if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) { + pfail(); + return(1); + } + return(0); } +#ifdef notused /* - * inskip(): skip over pgcnt pages with lncnt lines per page - * file is closed at EOF (if not stdin). + * inskip(): skip over pgcnt pages with lncnt lines per page + * file is closed at EOF (if not stdin). * - * inf FILE * to read from - * pgcnt number of pages to skip - * lncnt number of lines per page + * inf FILE * to read from + * pgcnt number of pages to skip + * lncnt number of lines per page */ int inskip(inf, pgcnt, lncnt) - FILE *inf; - register int pgcnt; - register int lncnt; + FILE *inf; + register int pgcnt; + register int lncnt; { - register int c; - register int cnt; + register int c; + register int cnt; - while(--pgcnt > 0) { - cnt = lncnt; - while ((c = getc(inf)) != EOF) { - if ((c == '\n') && (--cnt == 0)) - break; - } - if (c == EOF) { - if (inf != stdin) - (void)fclose(inf); - return(1); - } + while(--pgcnt > 0) { + cnt = lncnt; + while ((c = getc(inf)) != EOF) { + if ((c == '\n') && (--cnt == 0)) + break; } - return(0); + if (c == EOF) { + if (inf != stdin) + (void)fclose(inf); + return(1); + } + } + return(0); } +#endif /* - * nxtfile: returns a FILE * to next file in arg list and sets the - * time field for this file (or current date). + * nxtfile: returns a FILE * to next file in arg list and sets the + * time field for this file (or current date). * - * buf array to store proper date for the header. - * dt if set skips the date processing (used with -m) + * buf array to store proper date for the header. + * dt if set skips the date processing (used with -m) */ FILE * nxtfile(argc, argv, fname, buf, dt) - int argc; - char **argv; - char **fname; - char *buf; - int dt; + int argc; + char **argv; + char **fname; + char *buf; + int dt; { - FILE *inf = NULL; - struct timeval tv; - struct timezone tz; - struct tm *timeptr = NULL; - struct stat statbuf; - time_t curtime; - static int twice = -1; + FILE *inf = NULL; + struct timeval tv; + struct timezone tz; + struct tm *timeptr = NULL; + struct stat statbuf; + time_t curtime; + static int twice = -1; - ++twice; - if (eoptind >= argc) { - /* - * no file listed; default, use standard input - */ - if (twice) - return(NULL); - clearerr(stdin); - inf = stdin; - if (header != NULL) - *fname = header; - else - *fname = FNAME; - if (nohead) - return(inf); + ++twice; + if (eoptind >= argc) { + /* + * no file listed; default, use standard input + */ + if (twice) + return(NULL); + clearerr(stdin); + inf = stdin; + if (header != NULL) + *fname = header; + else + *fname = FNAME; + if (nohead) + return(inf); + if (gettimeofday(&tv, &tz) < 0) { + ++errcnt; + (void)fprintf(err, "pr: cannot get time of day, %s\n", + strerror(errno)); + eoptind = argc - 1; + return(NULL); + } + curtime = tv.tv_sec; + timeptr = localtime(&curtime); + } + for (; eoptind < argc; ++eoptind) { + if (strcmp(argv[eoptind], "-") == 0) { + /* + * process a "-" for filename + */ + clearerr(stdin); + inf = stdin; + if (header != NULL) + *fname = header; + else + *fname = FNAME; + ++eoptind; + if (nohead || (dt && twice)) + return(inf); + if (gettimeofday(&tv, &tz) < 0) { + ++errcnt; + (void)fprintf(err, + "pr: cannot get time of day, %s\n", + strerror(errno)); + return(NULL); + } + curtime = tv.tv_sec; + timeptr = localtime(&curtime); + } else { + /* + * normal file processing + */ + if ((inf = fopen(argv[eoptind], "r")) == NULL) { + ++errcnt; + if (nodiag) + continue; + (void)fprintf(err, "pr: Cannot open %s, %s\n", + argv[eoptind], strerror(errno)); + continue; + } + if (header != NULL) + *fname = header; + else if (dt) + *fname = FNAME; + else + *fname = argv[eoptind]; + ++eoptind; + if (nohead || (dt && twice)) + return(inf); + + if (dt) { if (gettimeofday(&tv, &tz) < 0) { - ++errcnt; - (void)fprintf(err, "pr: cannot get time of day, %s\n", - strerror(errno)); - eoptind = argc - 1; - return(NULL); + ++errcnt; + (void)fprintf(err, + "pr: cannot get time of day, %s\n", + strerror(errno)); + return(NULL); } curtime = tv.tv_sec; timeptr = localtime(&curtime); - } - for (; eoptind < argc; ++eoptind) { - if (strcmp(argv[eoptind], "-") == 0) { - /* - * process a "-" for filename - */ - clearerr(stdin); - inf = stdin; - if (header != NULL) - *fname = header; - else - *fname = FNAME; - ++eoptind; - if (nohead || (dt && twice)) - return(inf); - if (gettimeofday(&tv, &tz) < 0) { - ++errcnt; - (void)fprintf(err, - "pr: cannot get time of day, %s\n", - strerror(errno)); - return(NULL); - } - curtime = tv.tv_sec; - timeptr = localtime(&curtime); - } else { - /* - * normal file processing - */ - if ((inf = fopen(argv[eoptind], "r")) == NULL) { - ++errcnt; - if (nodiag) - continue; - (void)fprintf(err, "pr: Cannot open %s, %s\n", - argv[eoptind], strerror(errno)); - continue; - } - if (header != NULL) - *fname = header; - else if (dt) - *fname = FNAME; - else - *fname = argv[eoptind]; - ++eoptind; - if (nohead || (dt && twice)) - return(inf); - - if (dt) { - if (gettimeofday(&tv, &tz) < 0) { - ++errcnt; - (void)fprintf(err, - "pr: cannot get time of day, %s\n", - strerror(errno)); - return(NULL); - } - curtime = tv.tv_sec; - timeptr = localtime(&curtime); - } else { - if (fstat(fileno(inf), &statbuf) < 0) { - ++errcnt; - (void)fclose(inf); - (void)fprintf(err, - "pr: Cannot stat %s, %s\n", - argv[eoptind], strerror(errno)); - return(NULL); - } - timeptr = localtime(&(statbuf.st_mtime)); - } + } else { + if (fstat(fileno(inf), &statbuf) < 0) { + ++errcnt; + (void)fclose(inf); + (void)fprintf(err, + "pr: Cannot stat %s, %s\n", + argv[eoptind], strerror(errno)); + return(NULL); } - break; + timeptr = localtime(&(statbuf.st_mtime)); + } } - if (inf == NULL) - return(NULL); + break; + } + if (inf == NULL) + return(NULL); - /* - * set up time field used in header - */ - if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { - ++errcnt; - if (inf != stdin) - (void)fclose(inf); - (void)fputs("pr: time conversion failed\n", err); - return(NULL); - } - return(inf); + /* + * set up time field used in header + */ + if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { + ++errcnt; + if (inf != stdin) + (void)fclose(inf); + (void)fputs("pr: time conversion failed\n", err); + return(NULL); + } + return(inf); } /* - * addnum(): adds the line number to the column - * Truncates from the front or pads with spaces as required. - * Numbers are right justified. + * addnum(): adds the line number to the column + * Truncates from the front or pads with spaces as required. + * Numbers are right justified. * - * buf buffer to store the number - * wdth width of buffer to fill - * line line number + * buf buffer to store the number + * wdth width of buffer to fill + * line line number * - * NOTE: numbers occupy part of the column. The posix - * spec does not specify if -i processing should or should not - * occur on number padding. The spec does say it occupies - * part of the column. The usage of addnum currently treats - * numbers as part of the column so spaces may be replaced. + * NOTE: numbers occupy part of the column. The posix + * spec does not specify if -i processing should or should not + * occur on number padding. The spec does say it occupies + * part of the column. The usage of addnum currently treats + * numbers as part of the column so spaces may be replaced. */ void addnum(buf, wdth, line) - register char *buf; - register int wdth; - register int line; + register char *buf; + register int wdth; + register int line; { - register char *pt = buf + wdth; + register char *pt = buf + wdth; - do { - *--pt = digs[line % 10]; - line /= 10; - } while (line && (pt > buf)); + do { + *--pt = digs[line % 10]; + line /= 10; + } while (line && (pt > buf)); - /* - * pad with space as required - */ - while (pt > buf) - *--pt = ' '; + /* + * pad with space as required + */ + while (pt > buf) + *--pt = ' '; } /* - * prhead(): prints the top of page header + * prhead(): prints the top of page header * - * buf buffer with time field (and offset) - * cnt number of chars in buf - * fname fname field for header - * pagcnt page number + * buf buffer with time field (and offset) + * cnt number of chars in buf + * fname fname field for header + * pagcnt page number + * + * prhead() should be used carefully, we don't want to print out headers + * for null input files or orphan headers at the end of files, and also + * trailer processing is typically conditional on whether you've called + * prhead() at least once for a file and incremented pagecnt.. Exactly + * how to determine whether to print a header is a little different in + * the context each output mode, but we let the caller figure that out. */ int prhead(buf, fname, pagcnt) - char *buf; - char *fname; - int pagcnt; + char *buf; + char *fname; + int pagcnt; { - int ips = 0; - int ops = 0; + int ips = 0; + int ops = 0; - if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { - pfail(); - return(1); - } - /* - * posix is not clear if the header is subject to line length - * restrictions. The specification for header line format - * in the spec clearly does not limit length. No pr currently - * restricts header length. However if we need to truncate in - * an reasonable way, adjust the length of the printf by - * changing HDFMT to allow a length max as an arguement printf. - * buf (which contains the offset spaces and time field could - * also be trimmed - * - * note only the offset (if any) is processed for tab expansion - */ - if (offst && otln(buf, offst, &ips, &ops, -1)) - return(1); - (void)printf(HDFMT,buf+offst, fname, pagcnt); - return(0); + beheaded = 1; + + if (skipping && pagcnt >= pgnm) + skipping = 0; + + if (nohead || skipping) + return (0); + + if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { + pfail(); + return(1); + } + /* + * posix is not clear if the header is subject to line length + * restrictions. The specification for header line format + * in the spec clearly does not limit length. No pr currently + * restricts header length. However if we need to truncate in + * an reasonable way, adjust the length of the printf by + * changing HDFMT to allow a length max as an arguement printf. + * buf (which contains the offset spaces and time field could + * also be trimmed + * + * note only the offset (if any) is processed for tab expansion + */ + if (offst && otln(buf, offst, &ips, &ops, -1)) + return(1); + (void)printf(HDFMT,buf+offst, fname, pagcnt); + return(0); } /* - * prtail(): pad page with empty lines (if required) and print page trailer - * if requested + * prtail(): pad page with empty lines (if required) and print page trailer + * if requested * - * cnt number of lines of padding needed - * incomp was a '\n' missing from last line output + * cnt number of lines of padding needed + * incomp was a '\n' missing from last line output + * + * prtail() can now be invoked unconditionally, with the notion that if + * we haven't printed a hearder, these no need for a trailer */ int prtail(cnt, incomp) - register int cnt; - int incomp; + register int cnt; + int incomp; { - if (nohead) { - /* - * only pad with no headers when incomplete last line - */ - if (incomp && - ((dspace && (putchar('\n') == EOF)) || - (putchar('\n') == EOF))) { - pfail(); - return(1); + /* + * if were's skipping to page N or haven't put out anything yet just exit + */ + if (skipping || beheaded == 0) + return (0); + beheaded = 0; + + /* + * if noheaders, only terminate an incomplete last line + */ + if (nohead) { + + if (incomp) { + if (dspace) + if (putchar('\n') == EOF) { + pfail(); + return(1); } - /* - * but honor the formfeed request - */ - if (formfeed) { - if (putchar('\f') == EOF) { - pfail(); - return(1); - } - } - return(0); + if (putchar('\n') == EOF) { + pfail(); + return(1); + } } + /* + * but honor the formfeed request + */ + if (formfeed) + if (putchar(OUTFF) == EOF) { + pfail(); + return(1); + } + } else { + /* * if double space output two \n + * + * XXX this all seems bogus, why are we doing it here??? + * page length is in terms of output lines and only the input is + * supposed to be double spaced... otln() users should be doing + * something like linect+=(dspace ? 2:1). */ if (dspace) - cnt *= 2; + cnt *= 2; /* * if an odd number of lines per page, add an extra \n */ if (addone) - ++cnt; + ++cnt; /* - * pad page + * either put out a form-feed or pad page with blanks */ if (formfeed) { - if ((incomp && (putchar('\n') == EOF)) || - (putchar('\f') == EOF)) { - pfail(); - return(1); + if (incomp) + if (putchar('\n') == EOF) { + pfail(); + return(1); } - return(0); - } - cnt += TAILLEN; - while (--cnt >= 0) { + if (putchar(OUTFF) == EOF) { + pfail(); + return(1); + } + + } else { + + if (incomp) + cnt++; + + cnt += TAILLEN; + while (--cnt >= 0) { if (putchar('\n') == EOF) { - pfail(); - return(1); + pfail(); + return(1); } + } } - return(0); + } + + return(0); } /* - * terminate(): when a SIGINT is recvd + * terminate(): when a SIGINT is recvd */ void terminate(which_sig) - int which_sig; + int which_sig; { - flsh_errs(); - exit(1); + flsh_errs(); + exit(1); } /* - * flsh_errs(): output saved up diagnostic messages after all normal - * processing has completed + * flsh_errs(): output saved up diagnostic messages after all normal + * processing has completed */ void flsh_errs() { - char buf[BUFSIZ]; + char buf[BUFSIZ]; - (void)fflush(stdout); - (void)fflush(err); - if (err == stderr) - return; - rewind(err); - while (fgets(buf, BUFSIZ, err) != NULL) - (void)fputs(buf, stderr); + (void)fflush(stdout); + (void)fflush(err); + if (err == stderr) + return; + rewind(err); + while (fgets(buf, BUFSIZ, err) != NULL) + (void)fputs(buf, stderr); } void mfail() { - (void)fputs("pr: memory allocation failed\n", err); + (void)fputs("pr: memory allocation failed\n", err); } void pfail() { - (void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); + (void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); } void usage() { - (void)fputs( - "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err); - (void)fputs( - " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); - (void)fputs( - " [-s[ch]] [-w width] [-] [file ...]\n", err); + (void)fputs( + "usage: pr [+page] [-col] [-adfFmrt] [-e[ch][gap]] [-h header]\n",err); + (void)fputs( + " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); + (void)fputs( + " [-s[ch]] [-w width] [-] [file ...]\n", err); } /* - * setup: Validate command args, initialize and perform sanity - * checks on options + * setup: Validate command args, initialize and perform sanity + * checks on options */ int setup(argc, argv) - register int argc; - register char **argv; + register int argc; + register char **argv; { - register int c; - int eflag = 0; - int iflag = 0; - int wflag = 0; - int cflag = 0; + register int c; + int eflag = 0; + int iflag = 0; + int wflag = 0; + int cflag = 0; - if (isatty(fileno(stdout))) { - /* - * defer diagnostics until processing is done - */ - if ((err = tmpfile()) == NULL) { - (void)fputs("Cannot defer diagnostic messages\n",stderr); - return(1); - } - } else - err = stderr; - while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?w:")) != -1) { - switch (c) { - case '+': - if ((pgnm = atoi(eoptarg)) < 1) { - (void)fputs("pr: +page number must be 1 or more\n", - err); - return(1); - } - break; - case '-': - if ((clcnt = atoi(eoptarg)) < 1) { - (void)fputs("pr: -columns must be 1 or more\n",err); - return(1); - } - if (clcnt > 1) - ++cflag; - break; - case 'a': - ++across; - break; - case 'd': - ++dspace; - break; - case 'e': - ++eflag; - if ((eoptarg != NULL) && !isdigit(*eoptarg)) - inchar = *eoptarg++; - else - inchar = INCHAR; - if ((eoptarg != NULL) && isdigit(*eoptarg)) { - if ((ingap = atoi(eoptarg)) < 0) { - (void)fputs( - "pr: -e gap must be 0 or more\n", err); - return(1); - } - if (ingap == 0) - ingap = INGAP; - } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { - (void)fprintf(err, - "pr: invalid value for -e %s\n", eoptarg); - return(1); - } else - ingap = INGAP; - break; - case 'F': - ++formfeed; - break; - case 'h': - header = eoptarg; - break; - case 'i': - ++iflag; - if ((eoptarg != NULL) && !isdigit(*eoptarg)) - ochar = *eoptarg++; - else - ochar = OCHAR; - if ((eoptarg != NULL) && isdigit(*eoptarg)) { - if ((ogap = atoi(eoptarg)) < 0) { - (void)fputs( - "pr: -i gap must be 0 or more\n", err); - return(1); - } - if (ogap == 0) - ogap = OGAP; - } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { - (void)fprintf(err, - "pr: invalid value for -i %s\n", eoptarg); - return(1); - } else - ogap = OGAP; - break; - case 'l': - if (!isdigit(*eoptarg) || ((lines=atoi(eoptarg)) < 1)) { - (void)fputs( - "pr: Number of lines must be 1 or more\n",err); - return(1); - } - break; - case 'm': - ++merge; - break; - case 'n': - if ((eoptarg != NULL) && !isdigit(*eoptarg)) - nmchar = *eoptarg++; - else - nmchar = NMCHAR; - if ((eoptarg != NULL) && isdigit(*eoptarg)) { - if ((nmwd = atoi(eoptarg)) < 1) { - (void)fputs( - "pr: -n width must be 1 or more\n",err); - return(1); - } - } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { - (void)fprintf(err, - "pr: invalid value for -n %s\n", eoptarg); - return(1); - } else - nmwd = NMWD; - break; - case 'o': - if (!isdigit(*eoptarg) || ((offst = atoi(eoptarg))< 1)){ - (void)fputs("pr: -o offset must be 1 or more\n", - err); - return(1); - } - break; - case 'r': - ++nodiag; - break; - case 's': - ++sflag; - if (eoptarg == NULL) - schar = SCHAR; - else - schar = *eoptarg++; - if (*eoptarg != '\0') { - (void)fprintf(err, - "pr: invalid value for -s %s\n", eoptarg); - return(1); - } - break; - case 't': - ++nohead; - break; - case 'w': - ++wflag; - if (!isdigit(*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){ - (void)fputs( - "pr: -w width must be 1 or more \n",err); - return(1); - } - break; - case '?': - default: - return(1); - } - } - + if (isatty(fileno(stdout))) { /* - * default and sanity checks + * defer diagnostics until processing is done */ - if (!clcnt) { - if (merge) { - if ((clcnt = argc - eoptind) <= 1) { - clcnt = CLCNT; - merge = 0; - } - } else - clcnt = CLCNT; + if ((err = tmpfile()) == NULL) { + (void)fputs("Cannot defer diagnostic messages\n",stderr); + return(1); } - if (across) { - if (clcnt == 1) { - (void)fputs("pr: -a flag requires multiple columns\n", - err); - return(1); + } else + err = stderr; + while ((c = egetopt(argc, argv, "#adfFmrte?h:i?l:n?o:s?w:")) != EOF) { + switch (c) { + case '+': + if ((pgnm = atoi(eoptarg)) < 1) { + (void)fputs("pr: +page number must be 1 or more\n", + err); + return(1); + } + ++skipping; + break; + case '-': + if ((clcnt = atoi(eoptarg)) < 1) { + (void)fputs("pr: -columns must be 1 or more\n",err); + return(1); + } + if (clcnt > 1) + ++cflag; + break; + case 'a': + ++across; + break; + case 'd': + ++dspace; + break; + case 'e': + ++eflag; + if ((eoptarg != NULL) && !isdigit(*eoptarg)) + inchar = *eoptarg++; + else + inchar = INCHAR; + if ((eoptarg != NULL) && isdigit(*eoptarg)) { + if ((ingap = atoi(eoptarg)) < 0) { + (void)fputs( + "pr: -e gap must be 0 or more\n", err); + return(1); } - if (merge) { - (void)fputs("pr: -m cannot be used with -a\n", err); - return(1); + if (ingap == 0) + ingap = INGAP; + } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { + (void)fprintf(err, + "pr: invalid value for -e %s\n", eoptarg); + return(1); + } else + ingap = INGAP; + break; + case 'f': + case 'F': + ++formfeed; + break; + case 'h': + header = eoptarg; + break; + case 'i': + ++iflag; + if ((eoptarg != NULL) && !isdigit(*eoptarg)) + ochar = *eoptarg++; + else + ochar = OCHAR; + if ((eoptarg != NULL) && isdigit(*eoptarg)) { + if ((ogap = atoi(eoptarg)) < 0) { + (void)fputs( + "pr: -i gap must be 0 or more\n", err); + return(1); } + if (ogap == 0) + ogap = OGAP; + } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { + (void)fprintf(err, + "pr: invalid value for -i %s\n", eoptarg); + return(1); + } else + ogap = OGAP; + break; + case 'l': + if (!isdigit(*eoptarg) || ((lines=atoi(eoptarg)) < 1)) { + (void)fputs( + "pr: Number of lines must be 1 or more\n",err); + return(1); + } + break; + case 'm': + ++merge; + break; + case 'n': + if ((eoptarg != NULL) && !isdigit(*eoptarg)) + nmchar = *eoptarg++; + else + nmchar = NMCHAR; + if ((eoptarg != NULL) && isdigit(*eoptarg)) { + if ((nmwd = atoi(eoptarg)) < 1) { + (void)fputs( + "pr: -n width must be 1 or more\n",err); + return(1); + } + } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { + (void)fprintf(err, + "pr: invalid value for -n %s\n", eoptarg); + return(1); + } else + nmwd = NMWD; + break; + case 'o': + if (!isdigit(*eoptarg) || ((offst = atoi(eoptarg))< 1)){ + (void)fputs("pr: -o offset must be 1 or more\n", + err); + return(1); + } + break; + case 'r': + ++nodiag; + break; + case 's': + ++sflag; + if (eoptarg == NULL) + schar = SCHAR; + else + schar = *eoptarg++; + if (*eoptarg != '\0') { + (void)fprintf(err, + "pr: invalid value for -s %s\n", eoptarg); + return(1); + } + break; + case 't': + ++nohead; + break; + case 'w': + ++wflag; + if (!isdigit(*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){ + (void)fputs( + "pr: -w width must be 1 or more \n",err); + return(1); + } + break; + case '?': + default: + return(1); } - if (!wflag) { - if (sflag) - pgwd = SPGWD; - else - pgwd = PGWD; + } + + /* + * default and sanity checks + */ + inform++; + + if (!clcnt) { + if (merge) { + if ((clcnt = argc - eoptind) <= 1) { + clcnt = CLCNT; +#ifdef stupid + merge = 0; +#endif + } + } else + clcnt = CLCNT; + } + if (across) { + if (clcnt == 1) { + (void)fputs("pr: -a flag requires multiple columns\n", + err); + return(1); } - if (cflag || merge) { - if (!eflag) { - inchar = INCHAR; - ingap = INGAP; - } - if (!iflag) { - ochar = OCHAR; - ogap = OGAP; - } + if (merge) { + (void)fputs("pr: -m cannot be used with -a\n", err); + return(1); } - if (cflag) { - if (merge) { - (void)fputs( - "pr: -m cannot be used with multiple columns\n", err); - return(1); - } - if (nmwd) { - colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; - pgwd = ((colwd + nmwd + 2) * clcnt) - 1; - } else { - colwd = (pgwd + 1 - clcnt)/clcnt; - pgwd = ((colwd + 1) * clcnt) - 1; - } - if (colwd < 1) { - (void)fprintf(err, - "pr: page width is too small for %d columns\n",clcnt); - return(1); - } + } + if (!wflag) { + if (sflag) + pgwd = SPGWD; + else + pgwd = PGWD; + } + if (cflag || merge) { + if (!eflag) { + inchar = INCHAR; + ingap = INGAP; } - if (!lines) - lines = LINES; + if (!iflag) { + ochar = OCHAR; + ogap = OGAP; + } + } + if (cflag) { + if (merge) { + (void)fputs( + "pr: -m cannot be used with multiple columns\n", err); + return(1); + } + if (nmwd) { + colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; + pgwd = ((colwd + nmwd + 2) * clcnt) - 1; + } else { + colwd = (pgwd + 1 - clcnt)/clcnt; + pgwd = ((colwd + 1) * clcnt) - 1; + } + if (colwd < 1) { + (void)fprintf(err, + "pr: page width is too small for %d columns\n",clcnt); + return(1); + } + } + if (!lines) + lines = LINES; - /* - * make sure long enough for headers. if not disable - */ - if (lines <= HEADLEN + TAILLEN) - ++nohead; - else if (!nohead) - lines -= HEADLEN + TAILLEN; + /* + * make sure long enough for headers. if not disable + */ + if (lines <= HEADLEN + TAILLEN) + ++nohead; + else if (!nohead) + lines -= HEADLEN + TAILLEN; - /* - * adjust for double space on odd length pages - */ - if (dspace) { - if (lines == 1) - dspace = 0; - else { - if (lines & 1) - ++addone; - lines /= 2; - } + /* + * adjust for double space on odd length pages + */ + if (dspace) { + if (lines == 1) + dspace = 0; + else { + if (lines & 1) + ++addone; + lines /= 2; } + } - if ((timefrmt = getenv("LC_TIME")) == NULL) - timefrmt = TIMEFMT; - return(0); + if ((timefrmt = getenv("LC_TIME")) == NULL) + timefrmt = TIMEFMT; + return(0); }