Home | History | Annotate | Line # | Download | only in pr
pr.c revision 1.6
      1 /*	$NetBSD: pr.c,v 1.6 1998/04/02 10:42:51 kleink Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1991 Keith Muller.
      5  * Copyright (c) 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * Keith Muller of the University of California, San Diego.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the University of
     22  *	California, Berkeley and its contributors.
     23  * 4. Neither the name of the University nor the names of its contributors
     24  *    may be used to endorse or promote products derived from this software
     25  *    without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     37  * SUCH DAMAGE.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 #ifndef lint
     42 __COPYRIGHT("@(#) Copyright (c) 1993\n\
     43 	The Regents of the University of California.  All rights reserved.\n");
     44 #endif /* not lint */
     45 
     46 #ifndef lint
     47 #if 0
     48 from: static char sccsid[] = "@(#)pr.c	8.1 (Berkeley) 6/6/93";
     49 #else
     50 __RCSID("$NetBSD: pr.c,v 1.6 1998/04/02 10:42:51 kleink Exp $");
     51 #endif
     52 #endif /* not lint */
     53 
     54 #include <sys/types.h>
     55 #include <sys/time.h>
     56 #include <sys/stat.h>
     57 
     58 #include <ctype.h>
     59 #include <errno.h>
     60 #include <signal.h>
     61 #include <stdio.h>
     62 #include <stdlib.h>
     63 #include <string.h>
     64 #include <time.h>
     65 #include <unistd.h>
     66 
     67 #include "pr.h"
     68 #include "extern.h"
     69 
     70 /*
     71  * pr:	a printing and pagination filter. If multiple input files
     72  *	are specified, each is read, formatted, and written to standard
     73  *	output. By default, input is seperated into 66-line pages, each
     74  *	with a header that includes the page number, date, time and the
     75  *	files pathname.
     76  *
     77  *	Complies with posix P1003.2/D11
     78  */
     79 
     80 /*
     81  * parameter variables
     82  */
     83 int	pgnm;			/* starting page number */
     84 int	clcnt;			/* number of columns */
     85 int	colwd;			/* column data width - multiple columns */
     86 int	across;			/* mult col flag; write across page */
     87 int	dspace;			/* double space flag */
     88 char	inchar;			/* expand input char */
     89 int	ingap;			/* expand input gap */
     90 int	formfeed;		/* use formfeed as trailer */
     91 char	*header;		/* header name instead of file name */
     92 char	ochar;			/* contract output char */
     93 int	ogap;			/* contract output gap */
     94 int	lines;			/* number of lines per page */
     95 int	merge;			/* merge multiple files in output */
     96 char	nmchar;			/* line numbering append char */
     97 int	nmwd;			/* width of line number field */
     98 int	offst;			/* number of page offset spaces */
     99 int	nodiag;			/* do not report file open errors */
    100 char	schar;			/* text column separation character */
    101 int	sflag;			/* -s option for multiple columns */
    102 int	nohead;			/* do not write head and trailer */
    103 int	pgwd;			/* page width with multiple col output */
    104 char	*timefrmt;		/* time conversion string */
    105 
    106 /*
    107  * misc globals
    108  */
    109 FILE	*err;			/* error message file pointer */
    110 int	addone;			/* page length is odd with double space */
    111 int	errcnt;			/* error count on file processing */
    112 char	digs[] = "0123456789";	/* page number translation map */
    113 
    114 int	main __P((int, char **));
    115 
    116 int
    117 main(argc, argv)
    118         int argc;
    119         char *argv[];
    120 {
    121 	int ret_val;
    122 
    123 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
    124 		(void)signal(SIGINT, terminate);
    125 	ret_val = setup(argc, argv);
    126 	if (!ret_val) {
    127 		/*
    128 		 * select the output format based on options
    129 		 */
    130 		if (merge)
    131 			ret_val = mulfile(argc, argv);
    132 		else if (clcnt == 1)
    133 			ret_val = onecol(argc, argv);
    134 		else if (across)
    135 			ret_val = horzcol(argc, argv);
    136 		else
    137 			ret_val = vertcol(argc, argv);
    138 	} else
    139 		usage();
    140 	flsh_errs();
    141 	if (errcnt || ret_val)
    142 		exit(1);
    143 	return(0);
    144 }
    145 
    146 /*
    147  * onecol:	print files with only one column of output.
    148  *		Line length is unlimited.
    149  */
    150 int
    151 onecol(argc, argv)
    152         int argc;
    153         char *argv[];
    154 {
    155 	int cnt = -1;
    156 	int off;
    157 	int lrgln;
    158 	int linecnt;
    159 	int num;
    160 	int lncnt;
    161 	int pagecnt;
    162 	int ips;
    163 	int ops;
    164 	int cps;
    165 	char *obuf;
    166 	char *lbuf;
    167 	char *nbuf;
    168 	char *hbuf;
    169 	char *ohbuf;
    170 	FILE *inf;
    171 	char *fname;
    172 	int mor;
    173 
    174 	if (nmwd)
    175 		num = nmwd + 1;
    176 	else
    177 		num = 0;
    178 	off = num + offst;
    179 
    180 	/*
    181 	 * allocate line buffer
    182 	 */
    183 	if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) {
    184 		mfail();
    185 		return(1);
    186 	}
    187 	/*
    188 	 * allocate header buffer
    189 	 */
    190 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
    191 		mfail();
    192 		return(1);
    193 	}
    194 
    195 	ohbuf = hbuf + offst;
    196 	nbuf = obuf + offst;
    197 	lbuf = nbuf + num;
    198 	if (num)
    199 		nbuf[--num] = nmchar;
    200 	if (offst) {
    201 		(void)memset(obuf, (int)' ', offst);
    202 		(void)memset(hbuf, (int)' ', offst);
    203 	}
    204 
    205 	/*
    206 	 * loop by file
    207 	 */
    208 	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
    209 		if (pgnm) {
    210 			/*
    211 			 * skip to specified page
    212 			 */
    213 			if (inskip(inf, pgnm, lines))
    214 				continue;
    215 			pagecnt = pgnm;
    216 		} else
    217 			pagecnt = 1;
    218 		lncnt = 0;
    219 
    220 		/*
    221 		 * loop by page
    222 		 */
    223 		for(;;) {
    224 			linecnt = 0;
    225 			lrgln = 0;
    226 			ops = 0;
    227 			ips = 0;
    228 			cps = 0;
    229 
    230 			/*
    231 			 * loop by line
    232 			 */
    233 			while (linecnt < lines) {
    234 				/*
    235 				 * input next line
    236 				 */
    237 				if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0)
    238 					break;
    239 				if (!linecnt && !nohead &&
    240 					prhead(hbuf, fname, pagecnt))
    241 					return(1);
    242 
    243 				/*
    244 				 * start of new line.
    245 				 */
    246 				if (!lrgln) {
    247 					if (num)
    248 						addnum(nbuf, num, ++lncnt);
    249 					if (otln(obuf,cnt+off, &ips, &ops, mor))
    250 						return(1);
    251 				} else if (otln(lbuf, cnt, &ips, &ops, mor))
    252 					return(1);
    253 
    254 				/*
    255 				 * if line bigger than buffer, get more
    256 				 */
    257 				if (mor) {
    258 					lrgln = 1;
    259 					continue;
    260 				}
    261 
    262 				/*
    263 				 * whole line rcvd. reset tab proc. state
    264 				 */
    265 				++linecnt;
    266 				lrgln = 0;
    267 				ops = 0;
    268 				ips = 0;
    269 			}
    270 
    271 			/*
    272 			 * fill to end of page
    273 			 */
    274 			if (linecnt && prtail(lines-linecnt-lrgln, lrgln))
    275 				return(1);
    276 
    277 			/*
    278 			 * On EOF go to next file
    279 			 */
    280 			if (cnt < 0)
    281 				break;
    282 			++pagecnt;
    283 		}
    284 		if (inf != stdin)
    285 			(void)fclose(inf);
    286 	}
    287 	if (eoptind < argc)
    288 		return(1);
    289 	return(0);
    290 }
    291 
    292 /*
    293  * vertcol:	print files with more than one column of output down a page
    294  */
    295 int
    296 vertcol(argc, argv)
    297         int argc;
    298         char *argv[];
    299 {
    300 	char *ptbf;
    301 	char **lstdat;
    302 	int i;
    303 	int j;
    304 	int cnt = -1;
    305 	int pln;
    306 	int *indy;
    307 	int cvc;
    308 	int *lindy;
    309 	int lncnt;
    310 	int stp;
    311 	int pagecnt;
    312 	int col = colwd + 1;
    313 	int mxlen = pgwd + offst + 1;
    314 	int mclcnt = clcnt - 1;
    315 	struct vcol *vc;
    316 	int mvc;
    317 	int tvc;
    318 	int cw = nmwd + 1;
    319 	int fullcol;
    320 	char *buf;
    321 	char *hbuf;
    322 	char *ohbuf;
    323 	char *fname;
    324 	FILE *inf;
    325 	int ips = 0;
    326 	int cps = 0;
    327 	int ops = 0;
    328 	int mor = 0;
    329 
    330 	/*
    331 	 * allocate page buffer
    332 	 */
    333 	if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) {
    334 		mfail();
    335 		return(1);
    336 	}
    337 
    338 	/*
    339 	 * allocate page header
    340 	 */
    341 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
    342 		mfail();
    343 		return(1);
    344 	}
    345 	ohbuf = hbuf + offst;
    346 	if (offst)
    347 		(void)memset(hbuf, (int)' ', offst);
    348 
    349 	/*
    350 	 * col pointers when no headers
    351 	 */
    352 	mvc = lines * clcnt;
    353 	if ((vc =
    354 	    (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) {
    355 		mfail();
    356 		return(1);
    357 	}
    358 
    359 	/*
    360 	 * pointer into page where last data per line is located
    361 	 */
    362 	if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){
    363 		mfail();
    364 		return(1);
    365 	}
    366 
    367 	/*
    368 	 * fast index lookups to locate start of lines
    369 	 */
    370 	if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
    371 		mfail();
    372 		return(1);
    373 	}
    374 	if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
    375 		mfail();
    376 		return(1);
    377 	}
    378 
    379 	if (nmwd)
    380 		fullcol = col + cw;
    381 	else
    382 		fullcol = col;
    383 
    384 	/*
    385 	 * initialize buffer lookup indexes and offset area
    386 	 */
    387 	for (j = 0; j < lines; ++j) {
    388 		lindy[j] = j * mxlen;
    389 		indy[j] = lindy[j] + offst;
    390 		if (offst) {
    391 			ptbf = buf + lindy[j];
    392 			(void)memset(ptbf, (int)' ', offst);
    393 			ptbf += offst;
    394 		} else
    395 			ptbf = buf + indy[j];
    396 		lstdat[j] = ptbf;
    397 	}
    398 
    399 	/*
    400 	 * loop by file
    401 	 */
    402 	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
    403 		if (pgnm) {
    404 			/*
    405 			 * skip to requested page
    406 			 */
    407 			if (inskip(inf, pgnm, lines))
    408 				continue;
    409 			pagecnt = pgnm;
    410 		} else
    411 			pagecnt = 1;
    412 		lncnt = 0;
    413 
    414 		/*
    415 		 * loop by page
    416 		 */
    417 		for(;;) {
    418 			/*
    419 			 * loop by column
    420 			 */
    421 			cvc = 0;
    422 			for (i = 0; i < clcnt; ++i) {
    423 				j = 0;
    424 				/*
    425 				 * if last column, do not pad
    426 				 */
    427 				if (i == mclcnt)
    428 					stp = 1;
    429 				else
    430 					stp = 0;
    431 				/*
    432 				 * loop by line
    433 				 */
    434 				for(;;) {
    435 					/*
    436 					 * is this first column
    437 					 */
    438 					if (!i) {
    439 						ptbf = buf + indy[j];
    440 						lstdat[j] = ptbf;
    441 					} else
    442 						ptbf = lstdat[j];
    443 					vc[cvc].pt = ptbf;
    444 
    445 					/*
    446 					 * add number
    447 					 */
    448 					if (nmwd) {
    449 						addnum(ptbf, nmwd, ++lncnt);
    450 						ptbf += nmwd;
    451 						*ptbf++ = nmchar;
    452 					}
    453 
    454 					/*
    455 					 * input next line
    456 					 */
    457 					cnt = inln(inf,ptbf,colwd,&cps,1,&mor);
    458 					vc[cvc++].cnt = cnt;
    459 					if (cnt < 0)
    460 						break;
    461 					ptbf += cnt;
    462 
    463 					/*
    464 					 * pad all but last column on page
    465 					 */
    466 					if (!stp) {
    467 						/*
    468 						 * pad to end of column
    469 						 */
    470 						if (sflag)
    471 							*ptbf++ = schar;
    472 						else if ((pln = col-cnt) > 0) {
    473 							(void)memset(ptbf,
    474 								(int)' ',pln);
    475 							ptbf += pln;
    476 						}
    477 					}
    478 					/*
    479 					 * remember last char in line
    480 					 */
    481 					lstdat[j] = ptbf;
    482 					if (++j >= lines)
    483 						break;
    484 				}
    485 				if (cnt < 0)
    486 					break;
    487 			}
    488 
    489 			/*
    490 			 * when -t (no header) is specified the spec requires
    491 			 * the min number of lines. The last page may not have
    492 			 * balanced length columns. To fix this we must reorder
    493 			 * the columns. This is a very slow technique so it is
    494 			 * only used under limited conditions. Without -t, the
    495 			 * balancing of text columns is unspecified. To NOT
    496 			 * balance the last page, add the global variable
    497 			 * nohead to the if statement below e.g.
    498 			 *
    499 			 * if ((cnt < 0) && nohead && cvc ......
    500 			 */
    501 			--cvc;
    502 
    503 			/*
    504 			 * check to see if last page needs to be reordered
    505 			 */
    506 			if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){
    507 				pln = cvc/clcnt;
    508 				if (cvc % clcnt)
    509 					++pln;
    510 
    511 				/*
    512 				 * print header
    513 				 */
    514 				if (!nohead && prhead(hbuf, fname, pagecnt))
    515 					return(1);
    516 				for (i = 0; i < pln; ++i) {
    517 					ips = 0;
    518 					ops = 0;
    519 					if (offst&& otln(buf,offst,&ips,&ops,1))
    520 						return(1);
    521 					tvc = i;
    522 
    523 					for (j = 0; j < clcnt; ++j) {
    524 						/*
    525 						 * determine column length
    526 						 */
    527 						if (j == mclcnt) {
    528 							/*
    529 							 * last column
    530 							 */
    531 							cnt = vc[tvc].cnt;
    532 							if (nmwd)
    533 								cnt += cw;
    534 						} else if (sflag) {
    535 							/*
    536 							 * single ch between
    537 							 */
    538 							cnt = vc[tvc].cnt + 1;
    539 							if (nmwd)
    540 								cnt += cw;
    541 						} else
    542 							cnt = fullcol;
    543 						if (otln(vc[tvc].pt, cnt, &ips,
    544 								&ops, 1))
    545 							return(1);
    546 						tvc += pln;
    547 						if (tvc >= cvc)
    548 							break;
    549 					}
    550 					/*
    551 					 * terminate line
    552 					 */
    553 					if (otln(buf, 0, &ips, &ops, 0))
    554 						return(1);
    555 				}
    556 				/*
    557 				 * pad to end of page
    558 				 */
    559 				if (prtail((lines - pln), 0))
    560 					return(1);
    561 				/*
    562 				 * done with output, go to next file
    563 				 */
    564 				break;
    565 			}
    566 
    567 			/*
    568 			 * determine how many lines to output
    569 			 */
    570 			if (i > 0)
    571 				pln = lines;
    572 			else
    573 				pln = j;
    574 
    575 			/*
    576 			 * print header
    577 			 */
    578 			if (pln && !nohead && prhead(hbuf, fname, pagecnt))
    579 				return(1);
    580 
    581 			/*
    582 			 * output each line
    583 			 */
    584 			for (i = 0; i < pln; ++i) {
    585 				ptbf = buf + lindy[i];
    586 				if ((j = lstdat[i] - ptbf) <= offst)
    587 					break;
    588 				if (otln(ptbf, j, &ips, &ops, 0))
    589 					return(1);
    590 			}
    591 
    592 			/*
    593 			 * pad to end of page
    594 			 */
    595 			if (pln && prtail((lines - pln), 0))
    596 				return(1);
    597 
    598 			/*
    599 			 * if EOF go to next file
    600 			 */
    601 			if (cnt < 0)
    602 				break;
    603 			++pagecnt;
    604 		}
    605 		if (inf != stdin)
    606 			(void)fclose(inf);
    607 	}
    608 	if (eoptind < argc)
    609 		return(1);
    610 	return(0);
    611 }
    612 
    613 /*
    614  * horzcol:	print files with more than one column of output across a page
    615  */
    616 int
    617 horzcol(argc, argv)
    618         int argc;
    619         char *argv[];
    620 {
    621 	char *ptbf;
    622 	int pln;
    623 	int cnt = -1;
    624 	char *lstdat;
    625 	int col = colwd + 1;
    626 	int j;
    627 	int i;
    628 	int lncnt;
    629 	int pagecnt;
    630 	char *buf;
    631 	char *hbuf;
    632 	char *ohbuf;
    633 	char *fname;
    634 	FILE *inf;
    635 	int ips = 0;
    636 	int cps = 0;
    637 	int ops = 0;
    638 	int mor = 0;
    639 
    640 	if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
    641 		mfail();
    642 		return(1);
    643 	}
    644 
    645 	/*
    646 	 * page header
    647 	 */
    648 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
    649 		mfail();
    650 		return(1);
    651 	}
    652 	ohbuf = hbuf + offst;
    653 	if (offst) {
    654 		(void)memset(buf, (int)' ', offst);
    655 		(void)memset(hbuf, (int)' ', offst);
    656 	}
    657 
    658 	/*
    659 	 * loop by file
    660 	 */
    661 	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
    662 		if (pgnm) {
    663 			if (inskip(inf, pgnm, lines))
    664 				continue;
    665 			pagecnt = pgnm;
    666 		} else
    667 			pagecnt = 1;
    668 		lncnt = 0;
    669 
    670 		/*
    671 		 * loop by page
    672 		 */
    673 		for(;;) {
    674 			/*
    675 			 * loop by line
    676 			 */
    677 			for (i = 0; i < lines; ++i) {
    678 				ptbf = buf + offst;
    679 				lstdat = ptbf;
    680 				j = 0;
    681 				/*
    682 				 * loop by col
    683 				 */
    684 				for(;;) {
    685 					if (nmwd) {
    686 						/*
    687 						 * add number to column
    688 						 */
    689 						addnum(ptbf, nmwd, ++lncnt);
    690 						ptbf += nmwd;
    691 						*ptbf++ = nmchar;
    692 					}
    693 					/*
    694 					 * input line
    695 					 */
    696 					if ((cnt = inln(inf,ptbf,colwd,&cps,1,
    697 							&mor)) < 0)
    698 						break;
    699 					ptbf += cnt;
    700 					lstdat = ptbf;
    701 
    702 					/*
    703 					 * if last line skip padding
    704 					 */
    705 					if (++j >= clcnt)
    706 						break;
    707 
    708 					/*
    709 					 * pad to end of column
    710 					 */
    711 					if (sflag)
    712 						*ptbf++ = schar;
    713 					else if ((pln = col - cnt) > 0) {
    714 						(void)memset(ptbf,(int)' ',pln);
    715 						ptbf += pln;
    716 					}
    717 				}
    718 
    719 				/*
    720 				 * determine line length
    721 				 */
    722 				if ((j = lstdat - buf) <= offst)
    723 					break;
    724 				if (!i && !nohead &&
    725 					prhead(hbuf, fname, pagecnt))
    726 					return(1);
    727 				/*
    728 				 * output line
    729 				 */
    730 				if (otln(buf, j, &ips, &ops, 0))
    731 					return(1);
    732 			}
    733 
    734 			/*
    735 			 * pad to end of page
    736 			 */
    737 			if (i && prtail(lines-i, 0))
    738 				return(1);
    739 
    740 			/*
    741 			 * if EOF go to next file
    742 			 */
    743 			if (cnt < 0)
    744 				break;
    745 			++pagecnt;
    746 		}
    747 		if (inf != stdin)
    748 			(void)fclose(inf);
    749 	}
    750 	if (eoptind < argc)
    751 		return(1);
    752 	return(0);
    753 }
    754 
    755 /*
    756  * mulfile:	print files with more than one column of output and
    757  *		more than one file concurrently
    758  */
    759 int
    760 mulfile(argc, argv)
    761         int argc;
    762         char *argv[];
    763 {
    764 	char *ptbf;
    765 	int j;
    766 	int pln;
    767 	int cnt;
    768 	char *lstdat;
    769 	int i;
    770 	FILE **fbuf;
    771 	int actf;
    772 	int lncnt;
    773 	int col;
    774 	int pagecnt;
    775 	int fproc;
    776 	char *buf;
    777 	char *hbuf;
    778 	char *ohbuf;
    779 	char *fname;
    780 	int ips = 0;
    781 	int cps = 0;
    782 	int ops = 0;
    783 	int mor = 0;
    784 
    785 	/*
    786 	 * array of FILE *, one for each operand
    787 	 */
    788 	if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) {
    789 		mfail();
    790 		return(1);
    791 	}
    792 
    793 	/*
    794 	 * page header
    795 	 */
    796 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
    797 		mfail();
    798 		return(1);
    799 	}
    800 	ohbuf = hbuf + offst;
    801 
    802 	/*
    803 	 * do not know how many columns yet. The number of operands provide an
    804 	 * upper bound on the number of columns. We use the number of files
    805 	 * we can open successfully to set the number of columns. The operation
    806 	 * of the merge operation (-m) in relation to unsuccesful file opens
    807 	 * is unspecified by posix.
    808 	 */
    809 	j = 0;
    810 	while (j < clcnt) {
    811 		if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL)
    812 			break;
    813 		if (pgnm && (inskip(fbuf[j], pgnm, lines)))
    814 			fbuf[j] = NULL;
    815 		++j;
    816 	}
    817 
    818 	/*
    819 	 * if no files, exit
    820 	 */
    821 	if (!j)
    822 		return(1);
    823 
    824 	/*
    825 	 * calculate page boundries based on open file count
    826 	 */
    827 	clcnt = j;
    828 	if (nmwd) {
    829 		colwd = (pgwd - clcnt - nmwd)/clcnt;
    830 		pgwd = ((colwd + 1) * clcnt) - nmwd - 2;
    831 	} else {
    832 		colwd = (pgwd + 1 - clcnt)/clcnt;
    833 		pgwd = ((colwd + 1) * clcnt) - 1;
    834 	}
    835 	if (colwd < 1) {
    836 		(void)fprintf(err,
    837 		  "pr: page width too small for %d columns\n", clcnt);
    838 		return(1);
    839 	}
    840 	actf = clcnt;
    841 	col = colwd + 1;
    842 
    843 	/*
    844 	 * line buffer
    845 	 */
    846 	if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
    847 		mfail();
    848 		return(1);
    849 	}
    850 	if (offst) {
    851 		(void)memset(buf, (int)' ', offst);
    852 		(void)memset(hbuf, (int)' ', offst);
    853 	}
    854 	if (pgnm)
    855 		pagecnt = pgnm;
    856 	else
    857 		pagecnt = 1;
    858 	lncnt = 0;
    859 
    860 	/*
    861 	 * continue to loop while any file still has data
    862 	 */
    863 	while (actf > 0) {
    864 		/*
    865 		 * loop by line
    866 		 */
    867 		for (i = 0; i < lines; ++i) {
    868 			ptbf = buf + offst;
    869 			lstdat = ptbf;
    870 			if (nmwd) {
    871 				/*
    872 				 * add line number to line
    873 				 */
    874 				addnum(ptbf, nmwd, ++lncnt);
    875 				ptbf += nmwd;
    876 				*ptbf++ = nmchar;
    877 			}
    878 			j = 0;
    879 			fproc = 0;
    880 
    881 			/*
    882 			 * loop by column
    883 			 */
    884 			for (j = 0; j < clcnt; ++j) {
    885 				if (fbuf[j] == NULL) {
    886 					/*
    887 					 * empty column; EOF
    888 					 */
    889 					cnt = 0;
    890 				} else if ((cnt = inln(fbuf[j], ptbf, colwd,
    891 							&cps, 1, &mor)) < 0) {
    892 					/*
    893 					 * EOF hit; no data
    894 					 */
    895 					if (fbuf[j] != stdin)
    896 						(void)fclose(fbuf[j]);
    897 					fbuf[j] = NULL;
    898 					--actf;
    899 					cnt = 0;
    900 				} else {
    901 					/*
    902 					 * process file data
    903 					 */
    904 					ptbf += cnt;
    905 					lstdat = ptbf;
    906 					fproc++;
    907 				}
    908 
    909 				/*
    910 				 * if last ACTIVE column, done with line
    911 				 */
    912 				if (fproc >= actf)
    913 					break;
    914 
    915 				/*
    916 				 * pad to end of column
    917 				 */
    918 				if (sflag) {
    919 					*ptbf++ = schar;
    920 				} else if ((pln = col - cnt) > 0) {
    921 					(void)memset(ptbf, (int)' ', pln);
    922 					ptbf += pln;
    923 				}
    924 			}
    925 
    926 			/*
    927 			 * calculate data in line
    928 			 */
    929 			if ((j = lstdat - buf) <= offst)
    930 				break;
    931 
    932 			if (!i && !nohead && prhead(hbuf, fname, pagecnt))
    933 				return(1);
    934 
    935 			/*
    936 			 * output line
    937 			 */
    938 			if (otln(buf, j, &ips, &ops, 0))
    939 				return(1);
    940 
    941 			/*
    942 			 * if no more active files, done
    943 			 */
    944 			if (actf <= 0) {
    945 				++i;
    946 				break;
    947 			}
    948 		}
    949 
    950 		/*
    951 		 * pad to end of page
    952 		 */
    953 		if (i && prtail(lines-i, 0))
    954 			return(1);
    955 		++pagecnt;
    956 	}
    957 	if (eoptind < argc)
    958 		return(1);
    959 	return(0);
    960 }
    961 
    962 /*
    963  * inln():	input a line of data (unlimited length lines supported)
    964  *		Input is optionally expanded to spaces
    965  *
    966  *	inf:	file
    967  *	buf:	buffer
    968  *	lim:	buffer length
    969  *	cps:	column positon 1st char in buffer (large line support)
    970  *	trnc:	throw away data more than lim up to \n
    971  *	mor:	set if more data in line (not truncated)
    972  */
    973 int
    974 inln(inf, buf, lim, cps, trnc, mor)
    975 	FILE *inf;
    976 	char *buf;
    977 	int lim;
    978 	int *cps;
    979 	int trnc;
    980 	int *mor;
    981 {
    982 	int col;
    983 	int gap = ingap;
    984 	int ch = EOF;
    985 	char *ptbuf;
    986 	int chk = (int)inchar;
    987 
    988 	ptbuf = buf;
    989 
    990 	if (gap) {
    991 		/*
    992 		 * expanding input option
    993 		 */
    994 		while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
    995 			/*
    996 			 * is this the input "tab" char
    997 			 */
    998 			if (ch == chk) {
    999 				/*
   1000 				 * expand to number of spaces
   1001 				 */
   1002 				col = (ptbuf - buf) + *cps;
   1003 				col = gap - (col % gap);
   1004 
   1005 				/*
   1006 				 * if more than this line, push back
   1007 				 */
   1008 				if ((col > lim) && (ungetc(ch, inf) == EOF))
   1009 					return(1);
   1010 
   1011 				/*
   1012 				 * expand to spaces
   1013 				 */
   1014 				while ((--col >= 0) && (--lim >= 0))
   1015 					*ptbuf++ = ' ';
   1016 				continue;
   1017 			}
   1018 			if (ch == '\n')
   1019 				break;
   1020 			*ptbuf++ = ch;
   1021 		}
   1022 	} else {
   1023 		/*
   1024 		 * no expansion
   1025 		 */
   1026 		while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
   1027 			if (ch == '\n')
   1028 				break;
   1029 			*ptbuf++ = ch;
   1030 		}
   1031 	}
   1032 	col = ptbuf - buf;
   1033 	if (ch == EOF) {
   1034 		*mor = 0;
   1035 		*cps = 0;
   1036 		if (!col)
   1037 			return(-1);
   1038 		return(col);
   1039 	}
   1040 	if (ch == '\n') {
   1041 		/*
   1042 		 * entire line processed
   1043 		 */
   1044 		*mor = 0;
   1045 		*cps = 0;
   1046 		return(col);
   1047 	}
   1048 
   1049 	/*
   1050 	 * line was larger than limit
   1051 	 */
   1052 	if (trnc) {
   1053 		/*
   1054 		 * throw away rest of line
   1055 		 */
   1056 		while ((ch = getc(inf)) != EOF) {
   1057 			if (ch == '\n')
   1058 				break;
   1059 		}
   1060 		*cps = 0;
   1061 		*mor = 0;
   1062 	} else {
   1063 		/*
   1064 		 * save column offset if not truncated
   1065 		 */
   1066 		*cps += col;
   1067 		*mor = 1;
   1068 	}
   1069 
   1070 	return(col);
   1071 }
   1072 
   1073 /*
   1074  * otln():	output a line of data. (Supports unlimited length lines)
   1075  *		output is optionally contracted to tabs
   1076  *
   1077  *	buf:	output buffer with data
   1078  *	cnt:	number of chars of valid data in buf
   1079  *	svips:	buffer input column position (for large lines)
   1080  *	svops:	buffer output column position (for large lines)
   1081  *	mor:	output line not complete in this buf; more data to come.
   1082  *		1 is more, 0 is complete, -1 is no \n's
   1083  */
   1084 int
   1085 otln(buf, cnt, svips, svops, mor)
   1086 	char *buf;
   1087 	int cnt;
   1088 	int *svops;
   1089 	int *svips;
   1090 	int mor;
   1091 {
   1092 	int ops;		/* last col output */
   1093 	int ips;		/* last col in buf examined */
   1094 	int gap = ogap;
   1095 	int tbps;
   1096 	char *endbuf;
   1097 
   1098 	if (ogap) {
   1099 		/*
   1100 		 * contracting on output
   1101 		 */
   1102 		endbuf = buf + cnt;
   1103 		ops = *svops;
   1104 		ips = *svips;
   1105 		while (buf < endbuf) {
   1106 			/*
   1107 			 * count number of spaces and ochar in buffer
   1108 			 */
   1109 			if (*buf == ' ') {
   1110 				++ips;
   1111 				++buf;
   1112 				continue;
   1113 			}
   1114 
   1115 			/*
   1116 			 * simulate ochar processing
   1117 			 */
   1118 			if (*buf == ochar) {
   1119 				ips += gap - (ips % gap);
   1120 				++buf;
   1121 				continue;
   1122 			}
   1123 
   1124 			/*
   1125 			 * got a non space char; contract out spaces
   1126 			 */
   1127 			while (ops < ips) {
   1128 				/*
   1129 				 * use as many ochar as will fit
   1130 				 */
   1131 				if ((tbps = ops + gap - (ops % gap)) > ips)
   1132 					break;
   1133 				if (putchar(ochar) == EOF) {
   1134 					pfail();
   1135 					return(1);
   1136 				}
   1137 				ops = tbps;
   1138 			}
   1139 
   1140 			while (ops < ips) {
   1141 				/*
   1142 				 * finish off with spaces
   1143 				 */
   1144 				if (putchar(' ') == EOF) {
   1145 					pfail();
   1146 					return(1);
   1147 				}
   1148 				++ops;
   1149 			}
   1150 
   1151 			/*
   1152 			 * output non space char
   1153 			 */
   1154 			if (putchar(*buf++) == EOF) {
   1155 				pfail();
   1156 				return(1);
   1157 			}
   1158 			++ips;
   1159 			++ops;
   1160 		}
   1161 
   1162 		if (mor > 0) {
   1163 			/*
   1164 			 * if incomplete line, save position counts
   1165 			 */
   1166 			*svops = ops;
   1167 			*svips = ips;
   1168 			return(0);
   1169 		}
   1170 
   1171 		if (mor < 0) {
   1172 			while (ops < ips) {
   1173 				/*
   1174 				 * use as many ochar as will fit
   1175 				 */
   1176 				if ((tbps = ops + gap - (ops % gap)) > ips)
   1177 					break;
   1178 				if (putchar(ochar) == EOF) {
   1179 					pfail();
   1180 					return(1);
   1181 				}
   1182 				ops = tbps;
   1183 			}
   1184 			while (ops < ips) {
   1185 				/*
   1186 				 * finish off with spaces
   1187 				 */
   1188 				if (putchar(' ') == EOF) {
   1189 					pfail();
   1190 					return(1);
   1191 				}
   1192 				++ops;
   1193 			}
   1194 			return(0);
   1195 		}
   1196 	} else {
   1197 		/*
   1198 		 * output is not contracted
   1199 		 */
   1200 		if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) {
   1201 			pfail();
   1202 			return(1);
   1203 		}
   1204 		if (mor != 0)
   1205 			return(0);
   1206 	}
   1207 
   1208 	/*
   1209 	 * process line end and double space as required
   1210 	 */
   1211 	if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) {
   1212 		pfail();
   1213 		return(1);
   1214 	}
   1215 	return(0);
   1216 }
   1217 
   1218 /*
   1219  * inskip():	skip over pgcnt pages with lncnt lines per page
   1220  *		file is closed at EOF (if not stdin).
   1221  *
   1222  *	inf	FILE * to read from
   1223  *	pgcnt	number of pages to skip
   1224  *	lncnt	number of lines per page
   1225  */
   1226 int
   1227 inskip(inf, pgcnt, lncnt)
   1228 	FILE *inf;
   1229 	int pgcnt;
   1230 	int lncnt;
   1231 {
   1232 	int c;
   1233 	int cnt;
   1234 
   1235 	while(--pgcnt > 0) {
   1236 		cnt = lncnt;
   1237 		while ((c = getc(inf)) != EOF) {
   1238 			if ((c == '\n') && (--cnt == 0))
   1239 				break;
   1240 		}
   1241 		if (c == EOF) {
   1242 			if (inf != stdin)
   1243 				(void)fclose(inf);
   1244 			return(1);
   1245 		}
   1246 	}
   1247 	return(0);
   1248 }
   1249 
   1250 /*
   1251  * nxtfile:	returns a FILE * to next file in arg list and sets the
   1252  *		time field for this file (or current date).
   1253  *
   1254  *	buf	array to store proper date for the header.
   1255  *	dt	if set skips the date processing (used with -m)
   1256  */
   1257 FILE *
   1258 nxtfile(argc, argv, fname, buf, dt)
   1259 	int argc;
   1260 	char **argv;
   1261 	char **fname;
   1262 	char *buf;
   1263 	int dt;
   1264 {
   1265 	FILE *inf = NULL;
   1266 	struct timeval tv;
   1267 	struct timezone tz;
   1268 	struct tm *timeptr = NULL;
   1269 	struct stat statbuf;
   1270 	time_t curtime;
   1271 	static int twice = -1;
   1272 
   1273 	++twice;
   1274 	if (eoptind >= argc) {
   1275 		/*
   1276 		 * no file listed; default, use standard input
   1277 		 */
   1278 		if (twice)
   1279 			return(NULL);
   1280 		clearerr(stdin);
   1281 		inf = stdin;
   1282 		if (header != NULL)
   1283 			*fname = header;
   1284 		else
   1285 			*fname = FNAME;
   1286 		if (nohead)
   1287 			return(inf);
   1288 		if (gettimeofday(&tv, &tz) < 0) {
   1289 			++errcnt;
   1290 			(void)fprintf(err, "pr: cannot get time of day, %s\n",
   1291 				strerror(errno));
   1292 			eoptind = argc - 1;
   1293 			return(NULL);
   1294 		}
   1295 		curtime = tv.tv_sec;
   1296 		timeptr = localtime(&curtime);
   1297 	}
   1298 	for (; eoptind < argc; ++eoptind) {
   1299 		if (strcmp(argv[eoptind], "-") == 0) {
   1300 			/*
   1301 			 * process a "-" for filename
   1302 			 */
   1303 			clearerr(stdin);
   1304 			inf = stdin;
   1305 			if (header != NULL)
   1306 				*fname = header;
   1307 			else
   1308 				*fname = FNAME;
   1309 			++eoptind;
   1310 			if (nohead || (dt && twice))
   1311 				return(inf);
   1312 			if (gettimeofday(&tv, &tz) < 0) {
   1313 				++errcnt;
   1314 				(void)fprintf(err,
   1315 					"pr: cannot get time of day, %s\n",
   1316 					strerror(errno));
   1317 				return(NULL);
   1318 			}
   1319 			curtime = tv.tv_sec;
   1320 			timeptr = localtime(&curtime);
   1321 		} else {
   1322 			/*
   1323 			 * normal file processing
   1324 			 */
   1325 			if ((inf = fopen(argv[eoptind], "r")) == NULL) {
   1326 				++errcnt;
   1327 				if (nodiag)
   1328 					continue;
   1329 				(void)fprintf(err, "pr: Cannot open %s, %s\n",
   1330 					argv[eoptind], strerror(errno));
   1331 				continue;
   1332 			}
   1333 			if (header != NULL)
   1334 				*fname = header;
   1335 			else if (dt)
   1336 				*fname = FNAME;
   1337 			else
   1338 				*fname = argv[eoptind];
   1339 			++eoptind;
   1340 			if (nohead || (dt && twice))
   1341 				return(inf);
   1342 
   1343 			if (dt) {
   1344 				if (gettimeofday(&tv, &tz) < 0) {
   1345 					++errcnt;
   1346 					(void)fprintf(err,
   1347 					     "pr: cannot get time of day, %s\n",
   1348 					     strerror(errno));
   1349 					return(NULL);
   1350 				}
   1351 				curtime = tv.tv_sec;
   1352 				timeptr = localtime(&curtime);
   1353 			} else {
   1354 				if (fstat(fileno(inf), &statbuf) < 0) {
   1355 					++errcnt;
   1356 					(void)fclose(inf);
   1357 					(void)fprintf(err,
   1358 						"pr: Cannot stat %s, %s\n",
   1359 						argv[eoptind], strerror(errno));
   1360 					return(NULL);
   1361 				}
   1362 				timeptr = localtime(&(statbuf.st_mtime));
   1363 			}
   1364 		}
   1365 		break;
   1366 	}
   1367 	if (inf == NULL)
   1368 		return(NULL);
   1369 
   1370 	/*
   1371 	 * set up time field used in header
   1372 	 */
   1373 	if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) {
   1374 		++errcnt;
   1375 		if (inf != stdin)
   1376 			(void)fclose(inf);
   1377 		(void)fputs("pr: time conversion failed\n", err);
   1378 		return(NULL);
   1379 	}
   1380 	return(inf);
   1381 }
   1382 
   1383 /*
   1384  * addnum():	adds the line number to the column
   1385  *		Truncates from the front or pads with spaces as required.
   1386  *		Numbers are right justified.
   1387  *
   1388  *	buf	buffer to store the number
   1389  *	wdth	width of buffer to fill
   1390  *	line	line number
   1391  *
   1392  *		NOTE: numbers occupy part of the column. The posix
   1393  *		spec does not specify if -i processing should or should not
   1394  *		occur on number padding. The spec does say it occupies
   1395  *		part of the column. The usage of addnum	currently treats
   1396  *		numbers as part of the column so spaces may be replaced.
   1397  */
   1398 void
   1399 addnum(buf, wdth, line)
   1400 	char *buf;
   1401 	int wdth;
   1402 	int line;
   1403 {
   1404 	char *pt = buf + wdth;
   1405 
   1406 	do {
   1407 		*--pt = digs[line % 10];
   1408 		line /= 10;
   1409 	} while (line && (pt > buf));
   1410 
   1411 	/*
   1412 	 * pad with space as required
   1413 	 */
   1414 	while (pt > buf)
   1415 		*--pt = ' ';
   1416 }
   1417 
   1418 /*
   1419  * prhead():	prints the top of page header
   1420  *
   1421  *	buf	buffer with time field (and offset)
   1422  *	cnt	number of chars in buf
   1423  *	fname	fname field for header
   1424  *	pagcnt	page number
   1425  */
   1426 int
   1427 prhead(buf, fname, pagcnt)
   1428 	char *buf;
   1429 	char *fname;
   1430 	int pagcnt;
   1431 {
   1432 	int ips = 0;
   1433 	int ops = 0;
   1434 
   1435 	if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) {
   1436 		pfail();
   1437 		return(1);
   1438 	}
   1439 	/*
   1440 	 * posix is not clear if the header is subject to line length
   1441 	 * restrictions. The specification for header line format
   1442 	 * in the spec clearly does not limit length. No pr currently
   1443 	 * restricts header length. However if we need to truncate in
   1444 	 * an reasonable way, adjust the length of the printf by
   1445 	 * changing HDFMT to allow a length max as an arguement printf.
   1446 	 * buf (which contains the offset spaces and time field could
   1447 	 * also be trimmed
   1448 	 *
   1449 	 * note only the offset (if any) is processed for tab expansion
   1450 	 */
   1451 	if (offst && otln(buf, offst, &ips, &ops, -1))
   1452 		return(1);
   1453 	(void)printf(HDFMT,buf+offst, fname, pagcnt);
   1454 	return(0);
   1455 }
   1456 
   1457 /*
   1458  * prtail():	pad page with empty lines (if required) and print page trailer
   1459  *		if requested
   1460  *
   1461  *	cnt	number of lines of padding needed
   1462  *	incomp	was a '\n' missing from last line output
   1463  */
   1464 int
   1465 prtail(cnt, incomp)
   1466 	int cnt;
   1467 	int incomp;
   1468 {
   1469 	if (nohead) {
   1470 		/*
   1471 		 * only pad with no headers when incomplete last line
   1472 		 */
   1473 		if (!incomp)
   1474 			return(0);
   1475 		if ((dspace && (putchar('\n') == EOF)) ||
   1476 		    (putchar('\n') == EOF)) {
   1477 			pfail();
   1478 			return(1);
   1479 		}
   1480 		return(0);
   1481 	}
   1482 
   1483 	/*
   1484 	 * if double space output two \n
   1485 	 */
   1486 	if (dspace)
   1487 		cnt *= 2;
   1488 
   1489 	/*
   1490 	 * if an odd number of lines per page, add an extra \n
   1491 	 */
   1492 	if (addone)
   1493 		++cnt;
   1494 
   1495 	/*
   1496 	 * pad page
   1497 	 */
   1498 	if (formfeed) {
   1499 		if ((incomp && (putchar('\n') == EOF)) ||
   1500 		    (putchar('\f') == EOF)) {
   1501 			pfail();
   1502 			return(1);
   1503 		}
   1504 		return(0);
   1505 	}
   1506 	cnt += TAILLEN;
   1507 	while (--cnt >= 0) {
   1508 		if (putchar('\n') == EOF) {
   1509 			pfail();
   1510 			return(1);
   1511 		}
   1512 	}
   1513 	return(0);
   1514 }
   1515 
   1516 /*
   1517  * terminate():	when a SIGINT is recvd
   1518  */
   1519 void
   1520 terminate(which_sig)
   1521 	int which_sig;
   1522 {
   1523 	flsh_errs();
   1524 	exit(1);
   1525 }
   1526 
   1527 
   1528 /*
   1529  * flsh_errs():	output saved up diagnostic messages after all normal
   1530  *		processing has completed
   1531  */
   1532 void
   1533 flsh_errs()
   1534 {
   1535 	char buf[BUFSIZ];
   1536 
   1537 	(void)fflush(stdout);
   1538 	(void)fflush(err);
   1539 	if (err == stderr)
   1540 		return;
   1541 	rewind(err);
   1542 	while (fgets(buf, BUFSIZ, err) != NULL)
   1543 		(void)fputs(buf, stderr);
   1544 }
   1545 
   1546 void
   1547 mfail()
   1548 {
   1549 	(void)fputs("pr: memory allocation failed\n", err);
   1550 }
   1551 
   1552 void
   1553 pfail()
   1554 {
   1555 	(void)fprintf(err, "pr: write failure, %s\n", strerror(errno));
   1556 }
   1557 
   1558 void
   1559 usage()
   1560 {
   1561 	(void)fputs(
   1562 	 "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err);
   1563 	(void)fputs(
   1564 	 "          [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err);
   1565 	(void)fputs(
   1566 	 "          [-s[ch]] [-w width] [-] [file ...]\n", err);
   1567 }
   1568 
   1569 /*
   1570  * setup:	Validate command args, initialize and perform sanity
   1571  *		checks on options
   1572  */
   1573 int
   1574 setup(argc, argv)
   1575 	int argc;
   1576 	char **argv;
   1577 {
   1578 	int c;
   1579 	int eflag = 0;
   1580 	int iflag = 0;
   1581 	int wflag = 0;
   1582 	int cflag = 0;
   1583 
   1584 	if (isatty(fileno(stdout))) {
   1585 		/*
   1586 		 * defer diagnostics until processing is done
   1587 		 */
   1588 		if ((err = tmpfile()) == NULL) {
   1589 		       (void)fputs("Cannot defer diagnostic messages\n",stderr);
   1590 		       return(1);
   1591 		}
   1592 	} else
   1593 		err = stderr;
   1594 	while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?w:")) != -1) {
   1595 		switch (c) {
   1596 		case '+':
   1597 			if ((pgnm = atoi(eoptarg)) < 1) {
   1598 			    (void)fputs("pr: +page number must be 1 or more\n",
   1599 				err);
   1600 			    return(1);
   1601 			}
   1602 			break;
   1603 		case '-':
   1604 			if ((clcnt = atoi(eoptarg)) < 1) {
   1605 			    (void)fputs("pr: -columns must be 1 or more\n",err);
   1606 			    return(1);
   1607 			}
   1608 			if (clcnt > 1)
   1609 				++cflag;
   1610 			break;
   1611 		case 'a':
   1612 			++across;
   1613 			break;
   1614 		case 'd':
   1615 			++dspace;
   1616 			break;
   1617 		case 'e':
   1618 			++eflag;
   1619 			if ((eoptarg != NULL) && !isdigit(*eoptarg))
   1620 				inchar = *eoptarg++;
   1621 			else
   1622 				inchar = INCHAR;
   1623 			if ((eoptarg != NULL) && isdigit(*eoptarg)) {
   1624 				if ((ingap = atoi(eoptarg)) < 0) {
   1625 					(void)fputs(
   1626 					"pr: -e gap must be 0 or more\n", err);
   1627 					return(1);
   1628 				}
   1629 				if (ingap == 0)
   1630 					ingap = INGAP;
   1631 			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
   1632 				(void)fprintf(err,
   1633 				      "pr: invalid value for -e %s\n", eoptarg);
   1634 				return(1);
   1635 			} else
   1636 				ingap = INGAP;
   1637 			break;
   1638 		case 'F':
   1639 			++formfeed;
   1640 			break;
   1641 		case 'h':
   1642 			header = eoptarg;
   1643 			break;
   1644 		case 'i':
   1645 			++iflag;
   1646 			if ((eoptarg != NULL) && !isdigit(*eoptarg))
   1647 				ochar = *eoptarg++;
   1648 			else
   1649 				ochar = OCHAR;
   1650 			if ((eoptarg != NULL) && isdigit(*eoptarg)) {
   1651 				if ((ogap = atoi(eoptarg)) < 0) {
   1652 					(void)fputs(
   1653 					"pr: -i gap must be 0 or more\n", err);
   1654 					return(1);
   1655 				}
   1656 				if (ogap == 0)
   1657 					ogap = OGAP;
   1658 			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
   1659 				(void)fprintf(err,
   1660 				      "pr: invalid value for -i %s\n", eoptarg);
   1661 				return(1);
   1662 			} else
   1663 				ogap = OGAP;
   1664 			break;
   1665 		case 'l':
   1666 			if (!isdigit(*eoptarg) || ((lines=atoi(eoptarg)) < 1)) {
   1667 				(void)fputs(
   1668 				 "pr: Number of lines must be 1 or more\n",err);
   1669 				return(1);
   1670 			}
   1671 			break;
   1672 		case 'm':
   1673 			++merge;
   1674 			break;
   1675 		case 'n':
   1676 			if ((eoptarg != NULL) && !isdigit(*eoptarg))
   1677 				nmchar = *eoptarg++;
   1678 			else
   1679 				nmchar = NMCHAR;
   1680 			if ((eoptarg != NULL) && isdigit(*eoptarg)) {
   1681 				if ((nmwd = atoi(eoptarg)) < 1) {
   1682 					(void)fputs(
   1683 					"pr: -n width must be 1 or more\n",err);
   1684 					return(1);
   1685 				}
   1686 			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
   1687 				(void)fprintf(err,
   1688 				      "pr: invalid value for -n %s\n", eoptarg);
   1689 				return(1);
   1690 			} else
   1691 				nmwd = NMWD;
   1692 			break;
   1693 		case 'o':
   1694 			if (!isdigit(*eoptarg) || ((offst = atoi(eoptarg))< 1)){
   1695 				(void)fputs("pr: -o offset must be 1 or more\n",
   1696 					err);
   1697 				return(1);
   1698 			}
   1699 			break;
   1700 		case 'r':
   1701 			++nodiag;
   1702 			break;
   1703 		case 's':
   1704 			++sflag;
   1705 			if (eoptarg == NULL)
   1706 				schar = SCHAR;
   1707 			else
   1708 				schar = *eoptarg++;
   1709 			if (*eoptarg != '\0') {
   1710 				(void)fprintf(err,
   1711 				      "pr: invalid value for -s %s\n", eoptarg);
   1712 				return(1);
   1713 			}
   1714 			break;
   1715 		case 't':
   1716 			++nohead;
   1717 			break;
   1718 		case 'w':
   1719 			++wflag;
   1720 			if (!isdigit(*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){
   1721 				(void)fputs(
   1722 				   "pr: -w width must be 1 or more \n",err);
   1723 				return(1);
   1724 			}
   1725 			break;
   1726 		case '?':
   1727 		default:
   1728 			return(1);
   1729 		}
   1730 	}
   1731 
   1732 	/*
   1733 	 * default and sanity checks
   1734 	 */
   1735 	if (!clcnt) {
   1736 		if (merge) {
   1737 			if ((clcnt = argc - eoptind) <= 1) {
   1738 				clcnt = CLCNT;
   1739 				merge = 0;
   1740 			}
   1741 		} else
   1742 			clcnt = CLCNT;
   1743 	}
   1744 	if (across) {
   1745 		if (clcnt == 1) {
   1746 			(void)fputs("pr: -a flag requires multiple columns\n",
   1747 				err);
   1748 			return(1);
   1749 		}
   1750 		if (merge) {
   1751 			(void)fputs("pr: -m cannot be used with -a\n", err);
   1752 			return(1);
   1753 		}
   1754 	}
   1755 	if (!wflag) {
   1756 		if (sflag)
   1757 			pgwd = SPGWD;
   1758 		else
   1759 			pgwd = PGWD;
   1760 	}
   1761 	if (cflag || merge) {
   1762 		if (!eflag) {
   1763 			inchar = INCHAR;
   1764 			ingap = INGAP;
   1765 		}
   1766 		if (!iflag) {
   1767 			ochar = OCHAR;
   1768 			ogap = OGAP;
   1769 		}
   1770 	}
   1771 	if (cflag) {
   1772 		if (merge) {
   1773 			(void)fputs(
   1774 			  "pr: -m cannot be used with multiple columns\n", err);
   1775 			return(1);
   1776 		}
   1777 		if (nmwd) {
   1778 			colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt;
   1779 			pgwd = ((colwd + nmwd + 2) * clcnt) - 1;
   1780 		} else {
   1781 			colwd = (pgwd + 1 - clcnt)/clcnt;
   1782 			pgwd = ((colwd + 1) * clcnt) - 1;
   1783 		}
   1784 		if (colwd < 1) {
   1785 			(void)fprintf(err,
   1786 			  "pr: page width is too small for %d columns\n",clcnt);
   1787 			return(1);
   1788 		}
   1789 	}
   1790 	if (!lines)
   1791 		lines = LINES;
   1792 
   1793 	/*
   1794 	 * make sure long enough for headers. if not disable
   1795 	 */
   1796 	if (lines <= HEADLEN + TAILLEN)
   1797 		++nohead;
   1798 	else if (!nohead)
   1799 		lines -= HEADLEN + TAILLEN;
   1800 
   1801 	/*
   1802 	 * adjust for double space on odd length pages
   1803 	 */
   1804 	if (dspace) {
   1805 		if (lines == 1)
   1806 			dspace = 0;
   1807 		else {
   1808 			if (lines & 1)
   1809 				++addone;
   1810 			lines /= 2;
   1811 		}
   1812 	}
   1813 
   1814 	if ((timefrmt = getenv("LC_TIME")) == NULL)
   1815 		timefrmt = TIMEFMT;
   1816 	return(0);
   1817 }
   1818