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