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