version 1.4, 1997/01/15 23:43:00 |
version 1.5, 1997/04/23 08:08:28 |
|
|
*/ |
*/ |
|
|
/* |
/* |
|
* 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 <back-space> or <return> 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 <grr@tharsis.com> 4/22/97. |
|
*/ |
|
|
|
/* |
* parameter variables |
* parameter variables |
*/ |
*/ |
int pgnm; /* starting page number */ |
int pgnm; /* starting page number */ |
int clcnt; /* number of columns */ |
int skipping; /* we're skipping to page pgnum */ |
int colwd; /* column data width - multiple columns */ |
int clcnt; /* number of columns */ |
int across; /* mult col flag; write across page */ |
int colwd; /* column data width - multiple columns */ |
int dspace; /* double space flag */ |
int across; /* mult col flag; write across page */ |
char inchar; /* expand input char */ |
int dspace; /* double space flag */ |
int ingap; /* expand input gap */ |
char inchar; /* expand input char */ |
int formfeed; /* use formfeed as trailer */ |
int ingap; /* expand input gap */ |
char *header; /* header name instead of file name */ |
int formfeed; /* use formfeed as trailer */ |
char ochar; /* contract output char */ |
int inform; /* grok formfeeds in input */ |
int ogap; /* contract output gap */ |
char *header; /* header name instead of file name */ |
int lines; /* number of lines per page */ |
char ochar; /* contract output char */ |
int merge; /* merge multiple files in output */ |
int ogap; /* contract output gap */ |
char nmchar; /* line numbering append char */ |
int lines; /* number of lines per page */ |
int nmwd; /* width of line number field */ |
int merge; /* merge multiple files in output */ |
int offst; /* number of page offset spaces */ |
char nmchar; /* line numbering append char */ |
int nodiag; /* do not report file open errors */ |
int nmwd; /* width of line number field */ |
char schar; /* text column separation character */ |
int offst; /* number of page offset spaces */ |
int sflag; /* -s option for multiple columns */ |
int nodiag; /* do not report file open errors */ |
int nohead; /* do not write head and trailer */ |
char schar; /* text column separation character */ |
int pgwd; /* page width with multiple col output */ |
int sflag; /* -s option for multiple columns */ |
char *timefrmt; /* time conversion string */ |
int nohead; /* do not write head and trailer */ |
|
int pgwd; /* page width with multiple col output */ |
|
char *timefrmt; /* time conversion string */ |
|
|
/* |
/* |
* misc globals |
* misc globals |
*/ |
*/ |
FILE *err; /* error message file pointer */ |
FILE *err; /* error message file pointer */ |
int addone; /* page length is odd with double space */ |
int addone = 0; /* page length is odd with double space */ |
int errcnt; /* error count on file processing */ |
int errcnt = 0; /* error count on file processing */ |
|
int beheaded = 0; /* header / trailer link */ |
char digs[] = "0123456789"; /* page number translation map */ |
char digs[] = "0123456789"; /* page number translation map */ |
|
|
int |
int |
main(argc, argv) |
main(argc, argv) |
int argc; |
int argc; |
char *argv[]; |
char *argv[]; |
{ |
{ |
int ret_val; |
int ret_val; |
|
|
if (signal(SIGINT, SIG_IGN) != SIG_IGN) |
if (signal(SIGINT, SIG_IGN) != SIG_IGN) |
(void)signal(SIGINT, terminate); |
(void)signal(SIGINT, terminate); |
ret_val = setup(argc, argv); |
ret_val = setup(argc, argv); |
if (!ret_val) { |
if (!ret_val) { |
/* |
/* |
* select the output format based on options |
* select the output format based on options |
*/ |
*/ |
if (merge) |
if (merge) |
ret_val = mulfile(argc, argv); |
ret_val = mulfile(argc, argv); |
else if (clcnt == 1) |
else if (clcnt == 1) |
ret_val = onecol(argc, argv); |
ret_val = onecol(argc, argv); |
else if (across) |
else if (across) |
ret_val = horzcol(argc, argv); |
ret_val = horzcol(argc, argv); |
else |
else |
ret_val = vertcol(argc, argv); |
ret_val = vertcol(argc, argv); |
} else |
} else |
usage(); |
usage(); |
flsh_errs(); |
flsh_errs(); |
if (errcnt || ret_val) |
if (errcnt || ret_val) |
exit(1); |
exit(1); |
return(0); |
return(0); |
} |
} |
|
|
/* |
/* |
* onecol: print files with only one column of output. |
* onecol: print files with only one column of output. |
* Line length is unlimited. |
* Line length is unlimited. |
*/ |
*/ |
int |
int |
onecol(argc, argv) |
onecol(argc, argv) |
int argc; |
int argc; |
char *argv[]; |
char *argv[]; |
{ |
{ |
register int cnt = -1; |
register int off; |
register int off; |
register int lrgln; |
register int lrgln; |
register int linecnt; |
register int linecnt; |
register int num; |
register int num; |
int cnt; |
int lncnt; |
int rc; |
int pagecnt; |
int lncnt; |
int ips; |
int pagecnt; |
int ops; |
int ips; |
int cps; |
int ops; |
char *obuf; |
int cps; |
char *lbuf; |
char *obuf; |
char *nbuf; |
char *lbuf; |
char *hbuf; |
char *nbuf; |
char *ohbuf; |
char *hbuf; |
FILE *inf; |
char *ohbuf; |
char *fname; |
FILE *inf; |
int mor; |
char *fname; |
|
int mor; |
|
|
if (nmwd) |
if (nmwd) |
num = nmwd + 1; |
num = nmwd + 1; |
else |
else |
num = 0; |
num = 0; |
off = num + offst; |
off = num + offst; |
|
|
/* |
/* |
* allocate line buffer |
* allocate line buffer |
*/ |
*/ |
if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) { |
if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) { |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
/* |
|
* allocate header buffer |
|
*/ |
|
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
|
mfail(); |
|
return(1); |
|
} |
|
|
|
ohbuf = hbuf + offst; |
/* |
nbuf = obuf + offst; |
* allocate header buffer |
lbuf = nbuf + num; |
*/ |
if (num) |
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
nbuf[--num] = nmchar; |
mfail(); |
if (offst) { |
return(1); |
(void)memset(obuf, (int)' ', offst); |
} |
(void)memset(hbuf, (int)' ', offst); |
|
} |
|
|
|
|
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) { |
for(;;) { |
if (pgnm) { |
|
/* |
|
* skip to specified page |
|
*/ |
|
if (inskip(inf, pgnm, lines)) |
|
continue; |
|
pagecnt = pgnm; |
|
} else |
|
pagecnt = 1; |
|
lncnt = 0; |
|
|
|
|
/* |
|
* loop by page |
|
*/ |
|
for(;;) { |
|
linecnt = 0; |
|
lrgln = 0; |
|
ops = 0; |
|
ips = 0; |
|
cps = 0; |
|
|
/* |
/* |
* loop by page |
* loop by line |
*/ |
*/ |
for(;;) { |
while (linecnt < lines) { |
linecnt = 0; |
|
lrgln = 0; |
|
ops = 0; |
|
ips = 0; |
|
cps = 0; |
|
|
|
/* |
/* |
* loop by line |
* input next line |
*/ |
*/ |
while (linecnt < lines) { |
rc = inln(inf,lbuf,LBUF,&cnt,&cps,0,&mor); |
/* |
if (cnt >= 0) { |
* input next line |
if (!lrgln) |
*/ |
if (!linecnt && prhead(hbuf, fname, ++pagecnt)) |
if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0) |
return(1); |
break; |
|
if (!linecnt && !nohead && |
|
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); |
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) |
if (mor) { |
break; |
lrgln = 1; |
++pagecnt; |
} 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); |
return(0); |
} |
} |
|
|
/* |
/* |
* vertcol: print files with more than one column of output down a page |
* 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 |
int |
vertcol(argc, argv) |
vertcol(argc, argv) |
int argc; |
int argc; |
char *argv[]; |
char *argv[]; |
{ |
{ |
register char *ptbf; |
register char *ptbf; |
register char **lstdat; |
register char **lstdat; |
register int i; |
register int i; |
register int j; |
register int j; |
register int cnt = -1; |
register int pln; |
register int pln; |
register int *indy; |
register int *indy; |
int cnt; |
int cvc; |
int rc; |
int *lindy; |
int cvc; |
int lncnt; |
int *lindy; |
int stp; |
int lncnt; |
int pagecnt; |
int stp; |
int col = colwd + 1; |
int pagecnt; |
int mxlen = pgwd + offst + 1; |
int col = colwd + 1; |
int mclcnt = clcnt - 1; |
int mxlen = pgwd + offst + 1; |
struct vcol *vc; |
int mclcnt = clcnt - 1; |
int mvc; |
struct vcol *vc; |
int tvc; |
int mvc; |
int cw = nmwd + 1; |
int tvc; |
int fullcol; |
int cw = nmwd + 1; |
char *buf; |
int fullcol; |
char *hbuf; |
char *buf; |
char *ohbuf; |
char *hbuf; |
char *fname; |
char *ohbuf; |
FILE *inf; |
char *fname; |
int ips = 0; |
FILE *inf; |
int cps = 0; |
int ips = 0; |
int ops = 0; |
int cps = 0; |
int mor = 0; |
int ops = 0; |
|
int mor = 0; |
|
|
/* |
/* |
* allocate page buffer |
* allocate page buffer |
*/ |
*/ |
if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) { |
if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) { |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
|
|
/* |
/* |
* allocate page header |
* allocate page header |
*/ |
*/ |
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
ohbuf = hbuf + offst; |
|
if (offst) |
|
(void)memset(hbuf, (int)' ', offst); |
|
|
|
/* |
ohbuf = hbuf + offst; |
* col pointers when no headers |
if (offst) |
*/ |
(void)memset(hbuf, (int)' ', offst); |
mvc = lines * clcnt; |
|
if ((vc = |
|
(struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) { |
|
mfail(); |
|
return(1); |
|
} |
|
|
|
/* |
/* |
* pointer into page where last data per line is located |
* col pointers when no headers |
*/ |
*/ |
if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){ |
mvc = lines * clcnt; |
mfail(); |
if ((vc=(struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) { |
return(1); |
mfail(); |
} |
return(1); |
|
} |
|
|
/* |
/* |
* fast index lookups to locate start of lines |
* pointer into page where last data per line is located |
*/ |
*/ |
if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { |
if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){ |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { |
|
mfail(); |
|
return(1); |
|
} |
|
|
|
if (nmwd) |
/* |
fullcol = col + cw; |
* fast index lookups to locate start of lines |
else |
*/ |
fullcol = col; |
if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { |
|
mfail(); |
|
return(1); |
|
} |
|
if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { |
|
mfail(); |
|
return(1); |
|
} |
|
|
/* |
if (nmwd) |
* initialize buffer lookup indexes and offset area |
fullcol = col + cw; |
*/ |
else |
for (j = 0; j < lines; ++j) { |
fullcol = col; |
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; |
|
} |
|
|
|
|
/* |
|
* 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) { |
for (;;) { |
if (pgnm) { |
|
/* |
|
* skip to requested page |
|
*/ |
|
if (inskip(inf, pgnm, lines)) |
|
continue; |
|
pagecnt = pgnm; |
|
} else |
|
pagecnt = 1; |
|
lncnt = 0; |
|
|
|
|
/* |
|
* 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; |
if (!i) { |
for (i = 0; i < clcnt; ++i) { |
ptbf = buf + indy[j]; |
j = 0; |
lstdat[j] = ptbf; |
/* |
} else |
* if last column, do not pad |
ptbf = lstdat[j]; |
*/ |
vc[cvc].pt = ptbf; |
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; |
|
|
|
/* |
|
* 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 |
* add number |
* 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 ...... |
|
*/ |
*/ |
--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)){ |
rc = inln(inf,ptbf,colwd,&cnt,&cps,1,&mor); |
pln = cvc/clcnt; |
vc[cvc++].cnt = cnt; |
if (cvc % clcnt) |
if (cnt >= 0) { |
++pln; |
ptbf += cnt; |
|
|
|
/* |
|
* pad all but last column on page |
|
*/ |
|
if (!stp) { |
/* |
/* |
* print header |
* pad to end of column |
*/ |
*/ |
if (!nohead && prhead(hbuf, fname, pagecnt)) |
if (sflag) |
return(1); |
*ptbf++ = schar; |
for (i = 0; i < pln; ++i) { |
else if ((pln = col-cnt) > 0) { |
ips = 0; |
(void)memset(ptbf, |
ops = 0; |
(int)' ',pln); |
if (offst&& otln(buf,offst,&ips,&ops,1)) |
ptbf += pln; |
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); |
|
} |
} |
|
} |
|
|
|
/* |
|
* 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)) |
if (j == mclcnt) { |
return(1); |
/* |
/* |
* last column |
* done with output, go to next file |
*/ |
*/ |
cnt = vc[tvc].cnt; |
break; |
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 |
* determine how many lines to output |
*/ |
*/ |
if (i > 0) |
if (i > 0) |
pln = lines; |
pln = lines; |
else |
else |
pln = j; |
pln = j; |
|
|
/* |
/* |
* print header |
|
*/ |
|
if (pln && !nohead && prhead(hbuf, fname, pagecnt)) |
|
return(1); |
|
|
|
/* |
|
* output each line |
* output each line |
*/ |
*/ |
for (i = 0; i < pln; ++i) { |
for (i = 0; i < pln; ++i) { |
ptbf = buf + lindy[i]; |
ptbf = buf + lindy[i]; |
if ((j = lstdat[i] - ptbf) <= offst) |
if ((j = lstdat[i] - ptbf) <= offst) |
break; |
break; |
|
else { |
|
ips = 0; |
|
ops = 0; |
if (otln(ptbf, j, &ips, &ops, 0)) |
if (otln(ptbf, j, &ips, &ops, 0)) |
return(1); |
return(1); |
|
} |
} |
} |
|
} |
|
} |
|
|
/* |
/* |
* pad to end of page |
* pad to end of page |
*/ |
*/ |
if (pln && prtail((lines - pln), 0)) |
if (prtail((lines - pln), 0)) |
return(1); |
return(1); |
|
|
/* |
/* |
* if EOF go to next file |
* if FORM continue |
*/ |
*/ |
if (cnt < 0) |
if (rc != NORMAL) |
break; |
break; |
++pagecnt; |
} |
} |
|
if (inf != stdin) |
/* |
(void)fclose(inf); |
* 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); |
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 |
int |
horzcol(argc, argv) |
horzcol(argc, argv) |
int argc; |
int argc; |
char *argv[]; |
char *argv[]; |
{ |
{ |
register char *ptbf; |
register char *ptbf; |
register int pln; |
register int pln; |
register int cnt = -1; |
register char *lstdat; |
register char *lstdat; |
register int col = colwd + 1; |
register int col = colwd + 1; |
register int j; |
register int j; |
register int i; |
register int i; |
int cnt; |
int lncnt; |
int rc; |
int pagecnt; |
int lncnt; |
char *buf; |
int pagecnt; |
char *hbuf; |
char *buf; |
char *ohbuf; |
char *hbuf; |
char *fname; |
char *ohbuf; |
FILE *inf; |
char *fname; |
int ips = 0; |
FILE *inf; |
int cps = 0; |
int cps = 0; |
int ops = 0; |
int mor = 0; |
int mor = 0; |
int ips = 0; |
|
int ops = 0; |
|
|
if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { |
if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
|
|
/* |
/* |
* page header |
* page header |
*/ |
*/ |
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
ohbuf = hbuf + offst; |
|
if (offst) { |
|
(void)memset(buf, (int)' ', offst); |
|
(void)memset(hbuf, (int)' ', offst); |
|
} |
|
|
|
|
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) { |
for (;;) { |
if (pgnm) { |
|
if (inskip(inf, pgnm, lines)) |
|
continue; |
|
pagecnt = pgnm; |
|
} else |
|
pagecnt = 1; |
|
lncnt = 0; |
|
|
|
|
/* |
|
* 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) { |
rc = inln(inf,ptbf,colwd,&cnt,&cps,1, &mor); |
ptbf = buf + offst; |
if (cnt >= 0) { |
lstdat = ptbf; |
if (!i && !j && prhead(hbuf, fname, ++pagecnt)) |
j = 0; |
return(1); |
/* |
|
* 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; |
|
|
|
/* |
ptbf += cnt; |
* if last line skip padding |
lstdat = ptbf; |
*/ |
|
if (++j >= clcnt) |
|
break; |
|
|
|
/* |
/* |
* pad to end of column |
* if last line skip padding |
*/ |
*/ |
if (sflag) |
if (++j >= clcnt) |
*ptbf++ = schar; |
break; |
else if ((pln = col - cnt) > 0) { |
|
(void)memset(ptbf,(int)' ',pln); |
|
ptbf += pln; |
|
} |
|
} |
|
|
|
/* |
/* |
* determine line length |
* pad to end of column |
*/ |
*/ |
if ((j = lstdat - buf) <= offst) |
if (sflag) |
break; |
*ptbf++ = schar; |
if (!i && !nohead && |
else if ((pln = col - cnt) > 0) { |
prhead(hbuf, fname, pagecnt)) |
(void)memset(ptbf,(int)' ',pln); |
return(1); |
ptbf += pln; |
/* |
} |
* output line |
|
*/ |
|
if (otln(buf, j, &ips, &ops, 0)) |
|
return(1); |
|
} |
} |
|
if (rc != NORMAL) |
|
break; |
|
} |
|
|
/* |
/* |
* pad to end of page |
* output line if any columns on it |
*/ |
*/ |
if (i && prtail(lines-i, 0)) |
if (j) { |
return(1); |
if (otln(buf, lstdat-buf, &ips, &ops, 0)) |
|
return(1); |
|
} |
|
|
/* |
if (rc != NORMAL) |
* if EOF go to next file |
break; |
*/ |
|
if (cnt < 0) |
|
break; |
|
++pagecnt; |
|
} |
} |
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) |
if (inf != stdin) |
return(1); |
(void)fclose(inf); |
return(0); |
} |
|
if (eoptind < argc) |
|
return(1); |
|
return(0); |
} |
} |
|
|
/* |
/* |
* mulfile: print files with more than one column of output and |
* mulfile: print files with more than one column of output and |
* more than one file concurrently |
* more than one file concurrently |
*/ |
*/ |
int |
int |
mulfile(argc, argv) |
mulfile(argc, argv) |
int argc; |
int argc; |
char *argv[]; |
char *argv[]; |
{ |
{ |
register char *ptbf; |
register char *ptbf; |
register int j; |
register int j; |
register int pln; |
register int pln; |
register int cnt; |
int *rc; |
register char *lstdat; |
int cnt; |
register int i; |
register char *lstdat; |
FILE **fbuf; |
register int i; |
int actf; |
FILE **fbuf; |
int lncnt; |
int actf; |
int col; |
int lncnt; |
int pagecnt; |
int col; |
int fproc; |
int pagecnt; |
char *buf; |
int fproc; |
char *hbuf; |
char *buf; |
char *ohbuf; |
char *hbuf; |
char *fname; |
char *ohbuf; |
int ips = 0; |
char *fname; |
int cps = 0; |
int ips = 0; |
int ops = 0; |
int cps = 0; |
int mor = 0; |
int ops = 0; |
|
int mor = 0; |
|
|
/* |
/* |
* array of FILE *, one for each operand |
* array of FILE *, one for each operand |
*/ |
*/ |
if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) { |
if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) { |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
|
|
/* |
/* |
* page header |
* array of int *, one for each operand |
*/ |
*/ |
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
if ((rc = (int *)malloc((unsigned)clcnt*sizeof(int))) == NULL) { |
mfail(); |
mfail(); |
return(1); |
return(1); |
} |
} |
ohbuf = hbuf + offst; |
|
|
|
/* |
/* |
* do not know how many columns yet. The number of operands provide an |
* page header |
* 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 |
if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { |
* of the merge operation (-m) in relation to unsuccesful file opens |
mfail(); |
* is unspecified by posix. |
return(1); |
*/ |
} |
j = 0; |
ohbuf = hbuf + offst; |
while (j < clcnt) { |
|
if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL) |
/* |
break; |
* do not know how many columns yet. The number of operands provide an |
if (pgnm && (inskip(fbuf[j], pgnm, lines))) |
* upper bound on the number of columns. We use the number of files |
fbuf[j] = NULL; |
* we can open successfully to set the number of columns. The operation |
++j; |
* 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 no files, exit |
*/ |
*/ |
if (!j) |
if (j) |
return(1); |
|
|
|
/* |
|
* calculate page boundries based on open file count |
|
*/ |
|
clcnt = j; |
clcnt = j; |
if (nmwd) { |
else |
colwd = (pgwd - clcnt - nmwd)/clcnt; |
return(1); |
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; |
|
|
|
/* |
/* |
* line buffer |
* calculate page boundries based on open file count |
*/ |
*/ |
if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { |
if (nmwd) { |
mfail(); |
colwd = (pgwd - clcnt - nmwd)/clcnt; |
return(1); |
pgwd = ((colwd + 1) * clcnt) - nmwd - 2; |
} |
} else { |
if (offst) { |
colwd = (pgwd + 1 - clcnt)/clcnt; |
(void)memset(buf, (int)' ', offst); |
pgwd = ((colwd + 1) * clcnt) - 1; |
(void)memset(hbuf, (int)' ', offst); |
} |
} |
if (colwd < 1) { |
if (pgnm) |
(void)fprintf(err, |
pagecnt = pgnm; |
"pr: page width too small for %d columns\n", clcnt); |
else |
return(1); |
pagecnt = 1; |
} |
lncnt = 0; |
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) { |
for (j = 0; j < clcnt; ++j) { |
ptbf = buf + offst; |
if (rc[j] == NORMAL ) { |
lstdat = ptbf; |
rc[j] = inln(fbuf[j], ptbf, colwd, &cnt, &cps, 1, &mor); |
if (nmwd) { |
if (cnt >= 0) { |
/* |
/* |
* add line number to line |
* process file data |
*/ |
*/ |
addnum(ptbf, nmwd, ++lncnt); |
ptbf += cnt; |
ptbf += nmwd; |
lstdat = ptbf; |
*ptbf++ = nmchar; |
fproc++; |
|
} else |
|
cnt = 0; |
|
|
|
if (rc[j] == END) { |
|
/* |
|
* EOF close file |
|
*/ |
|
if (fbuf[j] != stdin) |
|
(void)fclose(fbuf[j]); |
|
--actf; |
} |
} |
j = 0; |
} else |
fproc = 0; |
cnt = 0; |
|
|
/* |
/* |
* loop by column |
* if last ACTIVE column, done with line |
*/ |
*/ |
for (j = 0; j < clcnt; ++j) { |
if (fproc >= actf) |
if (fbuf[j] == NULL) { |
break; |
/* |
|
* 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 |
* pad to end of column |
*/ |
*/ |
if (fproc >= actf) |
if (sflag) { |
break; |
*ptbf++ = schar; |
|
} else { |
/* |
if (cnt >= 0) |
* pad to end of column |
pln = col - cnt; |
*/ |
else |
if (sflag) { |
pln = col; |
*ptbf++ = schar; |
if (pln > 0) { |
} else if ((pln = col - cnt) > 0) { |
(void)memset(ptbf, (int)' ', pln); |
(void)memset(ptbf, (int)' ', pln); |
ptbf += 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); |
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(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) |
* inln(): input a line of data (unlimited length lines supported) |
* Input is optionally expanded to spaces |
* Input is optionally expanded to spaces |
|
* Returns 0 if normal LF, FORM on Formfeed, and END on EOF |
* |
* |
* inf: file |
* inf: file |
* buf: buffer |
* buf: buffer |
* lim: buffer length |
* lim: buffer length |
* cps: column positon 1st char in buffer (large line support) |
* cnt: line length or -1 if no line (EOF for example) |
* trnc: throw away data more than lim up to \n |
* cps: column positon 1st char in buffer (large line support) |
* mor: set if more data in line (not truncated) |
* trnc: throw away data more than lim up to \n |
|
* mor: set if more data in line (not truncated) |
*/ |
*/ |
int |
int |
inln(inf, buf, lim, cps, trnc, mor) |
inln(inf, buf, lim, cnt, cps, trnc, mor) |
FILE *inf; |
FILE *inf; |
char *buf; |
char *buf; |
register int lim; |
register int lim; |
int *cps; |
int *cnt; |
int trnc; |
int *cps; |
int *mor; |
int trnc; |
|
int *mor; |
{ |
{ |
register int col; |
register int col; |
register int gap = ingap; |
register int gap = ingap; |
register int ch = EOF; |
register int ch = EOF; |
register char *ptbuf; |
register char *ptbuf; |
register int chk = (int)inchar; |
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)) { |
col = (ptbuf - buf) + *cps; |
/* |
col = gap - (col % gap); |
* is this the input "tab" char |
|
*/ |
|
if (ch == chk) { |
|
/* |
|
* expand to number of spaces |
|
*/ |
|
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 ((col > lim) && (ungetc(ch, inf) == EOF)) { |
if (ch == '\n') |
*cnt = -1; |
break; |
return(END); /* shouldn't happen */ |
*ptbuf++ = ch; |
|
} |
} |
} |
|
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; |
while ((--col >= 0) && (--lim >= 0)) |
*cps = 0; |
*ptbuf++ = ' '; |
return(col); |
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) { |
while ((ch = getc(inf)) != EOF) { |
/* |
if (ch == '\n') |
* throw away rest of line |
break; |
*/ |
|
while ((ch = getc(inf)) != EOF) { |
|
if (ch == '\n') |
|
break; |
|
} |
|
*cps = 0; |
|
*mor = 0; |
|
} else { |
|
/* |
|
* save column offset if not truncated |
|
*/ |
|
*cps += col; |
|
*mor = 1; |
|
} |
} |
|
*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) |
* otln(): output a line of data. (Supports unlimited length lines) |
* output is optionally contracted to tabs |
* output is optionally contracted to tabs |
* |
* |
* buf: output buffer with data |
* buf: output buffer with data |
* cnt: number of chars of valid data in buf |
* cnt: number of chars of valid data in buf |
* svips: buffer input column position (for large lines) |
* svips: buffer input column position (for large lines) |
* svops: buffer output 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. |
* mor: output line not complete in this buf; more data to come. |
* 1 is more, 0 is complete, -1 is no \n's |
* 1 is more, 0 is complete, -1 is no \n's |
*/ |
*/ |
int |
int |
otln(buf, cnt, svips, svops, mor) |
otln(buf, cnt, svips, svops, mor) |
register char *buf; |
register char *buf; |
int cnt; |
int cnt; |
int *svops; |
int *svops; |
int *svips; |
int *svips; |
int mor; |
int mor; |
{ |
{ |
register int ops; /* last col output */ |
register int ops; /* last col output */ |
register int ips; /* last col in buf examined */ |
register int ips; /* last col in buf examined */ |
register int gap = ogap; |
register int gap = ogap; |
register int tbps; |
register int tbps; |
register char *endbuf; |
register char *endbuf; |
|
|
if (ogap) { |
/* skipping is only changed at header time not mid-line! */ |
/* |
if (skipping) |
* contracting on output |
return (0); |
*/ |
|
endbuf = buf + cnt; |
|
ops = *svops; |
|
ips = *svips; |
|
while (buf < endbuf) { |
|
/* |
|
* count number of spaces and ochar in buffer |
|
*/ |
|
if (*buf == ' ') { |
|
++ips; |
|
++buf; |
|
continue; |
|
} |
|
|
|
/* |
if (ogap) { |
* simulate ochar processing |
/* |
*/ |
* contracting on output |
if (*buf == ochar) { |
*/ |
ips += gap - (ips % gap); |
endbuf = buf + cnt; |
++buf; |
ops = *svops; |
continue; |
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 |
* simulate ochar processing |
*/ |
*/ |
while (ops < ips) { |
if (*buf == ochar) { |
/* |
ips += gap - (ips % gap); |
* use as many ochar as will fit |
++buf; |
*/ |
continue; |
if ((tbps = ops + gap - (ops % gap)) > ips) |
} |
break; |
|
if (putchar(ochar) == EOF) { |
|
pfail(); |
|
return(1); |
|
} |
|
ops = tbps; |
|
} |
|
|
|
while (ops < ips) { |
/* |
/* |
* got a non space char; contract out spaces |
* finish off with spaces |
*/ |
*/ |
while (ops < ips) { |
if (putchar(' ') == EOF) { |
/* |
pfail(); |
* use as many ochar as will fit |
return(1); |
*/ |
} |
if ((tbps = ops + gap - (ops % gap)) > ips) |
++ops; |
break; |
} |
if (putchar(ochar) == EOF) { |
|
pfail(); |
/* |
return(1); |
* output non space char |
|
*/ |
|
if (putchar(*buf++) == EOF) { |
|
pfail(); |
|
return(1); |
|
} |
|
++ips; |
|
++ops; |
|
} |
} |
|
ops = tbps; |
|
} |
|
|
if (mor > 0) { |
while (ops < ips) { |
/* |
/* |
* if incomplete line, save position counts |
* finish off with spaces |
*/ |
*/ |
*svops = ops; |
if (putchar(' ') == EOF) { |
*svips = ips; |
pfail(); |
return(0); |
return(1); |
} |
} |
|
++ops; |
|
} |
|
|
if (mor < 0) { |
/* |
while (ops < ips) { |
* output non space char |
/* |
*/ |
* use as many ochar as will fit |
if (putchar(*buf++) == EOF) { |
*/ |
pfail(); |
if ((tbps = ops + gap - (ops % gap)) > ips) |
return(1); |
break; |
} |
if (putchar(ochar) == EOF) { |
++ips; |
pfail(); |
++ops; |
return(1); |
} |
} |
|
ops = tbps; |
if (mor > 0) { |
} |
/* |
while (ops < ips) { |
* if incomplete line, save position counts |
/* |
*/ |
* finish off with spaces |
*svops = ops; |
*/ |
*svips = ips; |
if (putchar(' ') == EOF) { |
return(0); |
pfail(); |
} |
return(1); |
|
} |
if (mor < 0) { |
++ops; |
while (ops < ips) { |
} |
/* |
return(0); |
* 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)) { |
if (putchar(' ') == EOF) { |
pfail(); |
pfail(); |
return(1); |
return(1); |
} |
} |
if (mor != 0) |
++ops; |
return(0); |
} |
|
return(0); |
} |
} |
|
} else { |
/* |
/* |
* process line end and double space as required |
* output is not contracted |
*/ |
*/ |
if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) { |
if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) { |
pfail(); |
pfail(); |
return(1); |
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 |
* inskip(): skip over pgcnt pages with lncnt lines per page |
* file is closed at EOF (if not stdin). |
* file is closed at EOF (if not stdin). |
* |
* |
* inf FILE * to read from |
* inf FILE * to read from |
* pgcnt number of pages to skip |
* pgcnt number of pages to skip |
* lncnt number of lines per page |
* lncnt number of lines per page |
*/ |
*/ |
int |
int |
inskip(inf, pgcnt, lncnt) |
inskip(inf, pgcnt, lncnt) |
FILE *inf; |
FILE *inf; |
register int pgcnt; |
register int pgcnt; |
register int lncnt; |
register int lncnt; |
{ |
{ |
register int c; |
register int c; |
register int cnt; |
register int cnt; |
|
|
while(--pgcnt > 0) { |
while(--pgcnt > 0) { |
cnt = lncnt; |
cnt = lncnt; |
while ((c = getc(inf)) != EOF) { |
while ((c = getc(inf)) != EOF) { |
if ((c == '\n') && (--cnt == 0)) |
if ((c == '\n') && (--cnt == 0)) |
break; |
break; |
} |
|
if (c == EOF) { |
|
if (inf != stdin) |
|
(void)fclose(inf); |
|
return(1); |
|
} |
|
} |
} |
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 |
* nxtfile: returns a FILE * to next file in arg list and sets the |
* time field for this file (or current date). |
* time field for this file (or current date). |
* |
* |
* buf array to store proper date for the header. |
* buf array to store proper date for the header. |
* dt if set skips the date processing (used with -m) |
* dt if set skips the date processing (used with -m) |
*/ |
*/ |
FILE * |
FILE * |
nxtfile(argc, argv, fname, buf, dt) |
nxtfile(argc, argv, fname, buf, dt) |
int argc; |
int argc; |
char **argv; |
char **argv; |
char **fname; |
char **fname; |
char *buf; |
char *buf; |
int dt; |
int dt; |
{ |
{ |
FILE *inf = NULL; |
FILE *inf = NULL; |
struct timeval tv; |
struct timeval tv; |
struct timezone tz; |
struct timezone tz; |
struct tm *timeptr = NULL; |
struct tm *timeptr = NULL; |
struct stat statbuf; |
struct stat statbuf; |
time_t curtime; |
time_t curtime; |
static int twice = -1; |
static int twice = -1; |
|
|
++twice; |
++twice; |
if (eoptind >= argc) { |
if (eoptind >= argc) { |
/* |
/* |
* no file listed; default, use standard input |
* no file listed; default, use standard input |
*/ |
*/ |
if (twice) |
if (twice) |
return(NULL); |
return(NULL); |
clearerr(stdin); |
clearerr(stdin); |
inf = stdin; |
inf = stdin; |
if (header != NULL) |
if (header != NULL) |
*fname = header; |
*fname = header; |
else |
else |
*fname = FNAME; |
*fname = FNAME; |
if (nohead) |
if (nohead) |
return(inf); |
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) { |
if (gettimeofday(&tv, &tz) < 0) { |
++errcnt; |
++errcnt; |
(void)fprintf(err, "pr: cannot get time of day, %s\n", |
(void)fprintf(err, |
strerror(errno)); |
"pr: cannot get time of day, %s\n", |
eoptind = argc - 1; |
strerror(errno)); |
return(NULL); |
return(NULL); |
} |
} |
curtime = tv.tv_sec; |
curtime = tv.tv_sec; |
timeptr = localtime(&curtime); |
timeptr = localtime(&curtime); |
} |
} else { |
for (; eoptind < argc; ++eoptind) { |
if (fstat(fileno(inf), &statbuf) < 0) { |
if (strcmp(argv[eoptind], "-") == 0) { |
++errcnt; |
/* |
(void)fclose(inf); |
* process a "-" for filename |
(void)fprintf(err, |
*/ |
"pr: Cannot stat %s, %s\n", |
clearerr(stdin); |
argv[eoptind], strerror(errno)); |
inf = stdin; |
return(NULL); |
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)); |
|
} |
|
} |
} |
break; |
timeptr = localtime(&(statbuf.st_mtime)); |
|
} |
} |
} |
if (inf == NULL) |
break; |
return(NULL); |
} |
|
if (inf == NULL) |
|
return(NULL); |
|
|
/* |
/* |
* set up time field used in header |
* set up time field used in header |
*/ |
*/ |
if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { |
if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { |
++errcnt; |
++errcnt; |
if (inf != stdin) |
if (inf != stdin) |
(void)fclose(inf); |
(void)fclose(inf); |
(void)fputs("pr: time conversion failed\n", err); |
(void)fputs("pr: time conversion failed\n", err); |
return(NULL); |
return(NULL); |
} |
} |
return(inf); |
return(inf); |
} |
} |
|
|
/* |
/* |
* addnum(): adds the line number to the column |
* addnum(): adds the line number to the column |
* Truncates from the front or pads with spaces as required. |
* Truncates from the front or pads with spaces as required. |
* Numbers are right justified. |
* Numbers are right justified. |
* |
* |
* buf buffer to store the number |
* buf buffer to store the number |
* wdth width of buffer to fill |
* wdth width of buffer to fill |
* line line number |
* line line number |
* |
* |
* NOTE: numbers occupy part of the column. The posix |
* NOTE: numbers occupy part of the column. The posix |
* spec does not specify if -i processing should or should not |
* spec does not specify if -i processing should or should not |
* occur on number padding. The spec does say it occupies |
* occur on number padding. The spec does say it occupies |
* part of the column. The usage of addnum currently treats |
* part of the column. The usage of addnum currently treats |
* numbers as part of the column so spaces may be replaced. |
* numbers as part of the column so spaces may be replaced. |
*/ |
*/ |
void |
void |
addnum(buf, wdth, line) |
addnum(buf, wdth, line) |
register char *buf; |
register char *buf; |
register int wdth; |
register int wdth; |
register int line; |
register int line; |
{ |
{ |
register char *pt = buf + wdth; |
register char *pt = buf + wdth; |
|
|
do { |
do { |
*--pt = digs[line % 10]; |
*--pt = digs[line % 10]; |
line /= 10; |
line /= 10; |
} while (line && (pt > buf)); |
} while (line && (pt > buf)); |
|
|
/* |
/* |
* pad with space as required |
* pad with space as required |
*/ |
*/ |
while (pt > buf) |
while (pt > buf) |
*--pt = ' '; |
*--pt = ' '; |
} |
} |
|
|
/* |
/* |
* prhead(): prints the top of page header |
* prhead(): prints the top of page header |
* |
* |
* buf buffer with time field (and offset) |
* buf buffer with time field (and offset) |
* cnt number of chars in buf |
* cnt number of chars in buf |
* fname fname field for header |
* fname fname field for header |
* pagcnt page number |
* 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 |
int |
prhead(buf, fname, pagcnt) |
prhead(buf, fname, pagcnt) |
char *buf; |
char *buf; |
char *fname; |
char *fname; |
int pagcnt; |
int pagcnt; |
{ |
{ |
int ips = 0; |
int ips = 0; |
int ops = 0; |
int ops = 0; |
|
|
if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { |
beheaded = 1; |
pfail(); |
|
return(1); |
if (skipping && pagcnt >= pgnm) |
} |
skipping = 0; |
/* |
|
* posix is not clear if the header is subject to line length |
if (nohead || skipping) |
* restrictions. The specification for header line format |
return (0); |
* in the spec clearly does not limit length. No pr currently |
|
* restricts header length. However if we need to truncate in |
if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { |
* an reasonable way, adjust the length of the printf by |
pfail(); |
* changing HDFMT to allow a length max as an arguement printf. |
return(1); |
* buf (which contains the offset spaces and time field could |
} |
* also be trimmed |
/* |
* |
* posix is not clear if the header is subject to line length |
* note only the offset (if any) is processed for tab expansion |
* restrictions. The specification for header line format |
*/ |
* in the spec clearly does not limit length. No pr currently |
if (offst && otln(buf, offst, &ips, &ops, -1)) |
* restricts header length. However if we need to truncate in |
return(1); |
* an reasonable way, adjust the length of the printf by |
(void)printf(HDFMT,buf+offst, fname, pagcnt); |
* changing HDFMT to allow a length max as an arguement printf. |
return(0); |
* 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 |
* prtail(): pad page with empty lines (if required) and print page trailer |
* if requested |
* if requested |
* |
* |
* cnt number of lines of padding needed |
* cnt number of lines of padding needed |
* incomp was a '\n' missing from last line output |
* 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 |
int |
prtail(cnt, incomp) |
prtail(cnt, incomp) |
register int cnt; |
register int cnt; |
int incomp; |
int incomp; |
{ |
{ |
if (nohead) { |
/* |
/* |
* if were's skipping to page N or haven't put out anything yet just exit |
* only pad with no headers when incomplete last line |
*/ |
*/ |
if (skipping || beheaded == 0) |
if (incomp && |
return (0); |
((dspace && (putchar('\n') == EOF)) || |
beheaded = 0; |
(putchar('\n') == EOF))) { |
|
pfail(); |
/* |
return(1); |
* if noheaders, only terminate an incomplete last line |
|
*/ |
|
if (nohead) { |
|
|
|
if (incomp) { |
|
if (dspace) |
|
if (putchar('\n') == EOF) { |
|
pfail(); |
|
return(1); |
} |
} |
/* |
if (putchar('\n') == EOF) { |
* but honor the formfeed request |
pfail(); |
*/ |
return(1); |
if (formfeed) { |
} |
if (putchar('\f') == EOF) { |
|
pfail(); |
|
return(1); |
|
} |
|
} |
|
return(0); |
|
} |
} |
|
/* |
|
* but honor the formfeed request |
|
*/ |
|
if (formfeed) |
|
if (putchar(OUTFF) == EOF) { |
|
pfail(); |
|
return(1); |
|
} |
|
|
|
} else { |
|
|
/* |
/* |
* if double space output two \n |
* 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) |
if (dspace) |
cnt *= 2; |
cnt *= 2; |
|
|
/* |
/* |
* if an odd number of lines per page, add an extra \n |
* if an odd number of lines per page, add an extra \n |
*/ |
*/ |
if (addone) |
if (addone) |
++cnt; |
++cnt; |
|
|
/* |
/* |
* pad page |
* either put out a form-feed or pad page with blanks |
*/ |
*/ |
if (formfeed) { |
if (formfeed) { |
if ((incomp && (putchar('\n') == EOF)) || |
if (incomp) |
(putchar('\f') == EOF)) { |
if (putchar('\n') == EOF) { |
pfail(); |
pfail(); |
return(1); |
return(1); |
} |
} |
return(0); |
if (putchar(OUTFF) == EOF) { |
} |
pfail(); |
cnt += TAILLEN; |
return(1); |
while (--cnt >= 0) { |
} |
|
|
|
} else { |
|
|
|
if (incomp) |
|
cnt++; |
|
|
|
cnt += TAILLEN; |
|
while (--cnt >= 0) { |
if (putchar('\n') == EOF) { |
if (putchar('\n') == EOF) { |
pfail(); |
pfail(); |
return(1); |
return(1); |
} |
} |
|
} |
} |
} |
return(0); |
} |
|
|
|
return(0); |
} |
} |
|
|
/* |
/* |
* terminate(): when a SIGINT is recvd |
* terminate(): when a SIGINT is recvd |
*/ |
*/ |
void |
void |
terminate(which_sig) |
terminate(which_sig) |
int which_sig; |
int which_sig; |
{ |
{ |
flsh_errs(); |
flsh_errs(); |
exit(1); |
exit(1); |
} |
} |
|
|
|
|
/* |
/* |
* flsh_errs(): output saved up diagnostic messages after all normal |
* flsh_errs(): output saved up diagnostic messages after all normal |
* processing has completed |
* processing has completed |
*/ |
*/ |
void |
void |
flsh_errs() |
flsh_errs() |
{ |
{ |
char buf[BUFSIZ]; |
char buf[BUFSIZ]; |
|
|
(void)fflush(stdout); |
(void)fflush(stdout); |
(void)fflush(err); |
(void)fflush(err); |
if (err == stderr) |
if (err == stderr) |
return; |
return; |
rewind(err); |
rewind(err); |
while (fgets(buf, BUFSIZ, err) != NULL) |
while (fgets(buf, BUFSIZ, err) != NULL) |
(void)fputs(buf, stderr); |
(void)fputs(buf, stderr); |
} |
} |
|
|
void |
void |
mfail() |
mfail() |
{ |
{ |
(void)fputs("pr: memory allocation failed\n", err); |
(void)fputs("pr: memory allocation failed\n", err); |
} |
} |
|
|
void |
void |
pfail() |
pfail() |
{ |
{ |
(void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); |
(void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); |
} |
} |
|
|
void |
void |
usage() |
usage() |
{ |
{ |
(void)fputs( |
(void)fputs( |
"usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err); |
"usage: pr [+page] [-col] [-adfFmrt] [-e[ch][gap]] [-h header]\n",err); |
(void)fputs( |
(void)fputs( |
" [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); |
" [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); |
(void)fputs( |
(void)fputs( |
" [-s[ch]] [-w width] [-] [file ...]\n", err); |
" [-s[ch]] [-w width] [-] [file ...]\n", err); |
} |
} |
|
|
/* |
/* |
* setup: Validate command args, initialize and perform sanity |
* setup: Validate command args, initialize and perform sanity |
* checks on options |
* checks on options |
*/ |
*/ |
int |
int |
setup(argc, argv) |
setup(argc, argv) |
register int argc; |
register int argc; |
register char **argv; |
register char **argv; |
{ |
{ |
register int c; |
register int c; |
int eflag = 0; |
int eflag = 0; |
int iflag = 0; |
int iflag = 0; |
int wflag = 0; |
int wflag = 0; |
int cflag = 0; |
int cflag = 0; |
|
|
if (isatty(fileno(stdout))) { |
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); |
|
} |
|
} |
|
|
|
/* |
/* |
* default and sanity checks |
* defer diagnostics until processing is done |
*/ |
*/ |
if (!clcnt) { |
if ((err = tmpfile()) == NULL) { |
if (merge) { |
(void)fputs("Cannot defer diagnostic messages\n",stderr); |
if ((clcnt = argc - eoptind) <= 1) { |
return(1); |
clcnt = CLCNT; |
|
merge = 0; |
|
} |
|
} else |
|
clcnt = CLCNT; |
|
} |
} |
if (across) { |
} else |
if (clcnt == 1) { |
err = stderr; |
(void)fputs("pr: -a flag requires multiple columns\n", |
while ((c = egetopt(argc, argv, "#adfFmrte?h:i?l:n?o:s?w:")) != EOF) { |
err); |
switch (c) { |
return(1); |
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) { |
if (ingap == 0) |
(void)fputs("pr: -m cannot be used with -a\n", err); |
ingap = INGAP; |
return(1); |
} 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 |
* default and sanity checks |
pgwd = PGWD; |
*/ |
|
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 (merge) { |
if (!eflag) { |
(void)fputs("pr: -m cannot be used with -a\n", err); |
inchar = INCHAR; |
return(1); |
ingap = INGAP; |
|
} |
|
if (!iflag) { |
|
ochar = OCHAR; |
|
ogap = OGAP; |
|
} |
|
} |
} |
if (cflag) { |
} |
if (merge) { |
if (!wflag) { |
(void)fputs( |
if (sflag) |
"pr: -m cannot be used with multiple columns\n", err); |
pgwd = SPGWD; |
return(1); |
else |
} |
pgwd = PGWD; |
if (nmwd) { |
} |
colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; |
if (cflag || merge) { |
pgwd = ((colwd + nmwd + 2) * clcnt) - 1; |
if (!eflag) { |
} else { |
inchar = INCHAR; |
colwd = (pgwd + 1 - clcnt)/clcnt; |
ingap = INGAP; |
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) |
if (!iflag) { |
lines = LINES; |
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 |
* make sure long enough for headers. if not disable |
*/ |
*/ |
if (lines <= HEADLEN + TAILLEN) |
if (lines <= HEADLEN + TAILLEN) |
++nohead; |
++nohead; |
else if (!nohead) |
else if (!nohead) |
lines -= HEADLEN + TAILLEN; |
lines -= HEADLEN + TAILLEN; |
|
|
/* |
/* |
* adjust for double space on odd length pages |
* adjust for double space on odd length pages |
*/ |
*/ |
if (dspace) { |
if (dspace) { |
if (lines == 1) |
if (lines == 1) |
dspace = 0; |
dspace = 0; |
else { |
else { |
if (lines & 1) |
if (lines & 1) |
++addone; |
++addone; |
lines /= 2; |
lines /= 2; |
} |
|
} |
} |
|
} |
|
|
if ((timefrmt = getenv("LC_TIME")) == NULL) |
if ((timefrmt = getenv("LC_TIME")) == NULL) |
timefrmt = TIMEFMT; |
timefrmt = TIMEFMT; |
return(0); |
return(0); |
} |
} |