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