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