xref: /minix3/usr.bin/pr/pr.c (revision e1cdaee10649323af446eb1a74571984b2ab3181)
16ea7f916SThomas Cort /*	$NetBSD: pr.c,v 1.24 2012/08/01 02:27:48 ginsbach Exp $	*/
26ea7f916SThomas Cort 
36ea7f916SThomas Cort /*-
46ea7f916SThomas Cort  * Copyright (c) 1991 Keith Muller.
56ea7f916SThomas Cort  * Copyright (c) 1993
66ea7f916SThomas Cort  *	The Regents of the University of California.  All rights reserved.
76ea7f916SThomas Cort  * Copyright (c) 2012
86ea7f916SThomas Cort  *	The NetBSD Foundation, Inc.
96ea7f916SThomas Cort  *
106ea7f916SThomas Cort  * This code is derived from software contributed to Berkeley by
116ea7f916SThomas Cort  * Keith Muller of the University of California, San Diego.
126ea7f916SThomas Cort  *
136ea7f916SThomas Cort  * Redistribution and use in source and binary forms, with or without
146ea7f916SThomas Cort  * modification, are permitted provided that the following conditions
156ea7f916SThomas Cort  * are met:
166ea7f916SThomas Cort  * 1. Redistributions of source code must retain the above copyright
176ea7f916SThomas Cort  *    notice, this list of conditions and the following disclaimer.
186ea7f916SThomas Cort  * 2. Redistributions in binary form must reproduce the above copyright
196ea7f916SThomas Cort  *    notice, this list of conditions and the following disclaimer in the
206ea7f916SThomas Cort  *    documentation and/or other materials provided with the distribution.
216ea7f916SThomas Cort  * 3. Neither the name of the University nor the names of its contributors
226ea7f916SThomas Cort  *    may be used to endorse or promote products derived from this software
236ea7f916SThomas Cort  *    without specific prior written permission.
246ea7f916SThomas Cort  *
256ea7f916SThomas Cort  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
266ea7f916SThomas Cort  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
276ea7f916SThomas Cort  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
286ea7f916SThomas Cort  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
296ea7f916SThomas Cort  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
306ea7f916SThomas Cort  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
316ea7f916SThomas Cort  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
326ea7f916SThomas Cort  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
336ea7f916SThomas Cort  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
346ea7f916SThomas Cort  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
356ea7f916SThomas Cort  * SUCH DAMAGE.
366ea7f916SThomas Cort  */
376ea7f916SThomas Cort 
386ea7f916SThomas Cort #include <sys/cdefs.h>
396ea7f916SThomas Cort #ifndef lint
406ea7f916SThomas Cort __COPYRIGHT("@(#) Copyright (c) 1993\
416ea7f916SThomas Cort  The Regents of the University of California.  All rights reserved.");
426ea7f916SThomas Cort #endif /* not lint */
436ea7f916SThomas Cort 
446ea7f916SThomas Cort #ifndef lint
456ea7f916SThomas Cort #if 0
466ea7f916SThomas Cort from: static char sccsid[] = "@(#)pr.c	8.1 (Berkeley) 6/6/93";
476ea7f916SThomas Cort #else
486ea7f916SThomas Cort __RCSID("$NetBSD: pr.c,v 1.24 2012/08/01 02:27:48 ginsbach Exp $");
496ea7f916SThomas Cort #endif
506ea7f916SThomas Cort #endif /* not lint */
516ea7f916SThomas Cort 
526ea7f916SThomas Cort #include <sys/types.h>
536ea7f916SThomas Cort #include <sys/time.h>
546ea7f916SThomas Cort #include <sys/stat.h>
556ea7f916SThomas Cort 
566ea7f916SThomas Cort #include <ctype.h>
576ea7f916SThomas Cort #include <errno.h>
586ea7f916SThomas Cort #include <signal.h>
596ea7f916SThomas Cort #include <stdio.h>
606ea7f916SThomas Cort #include <stdlib.h>
616ea7f916SThomas Cort #include <string.h>
626ea7f916SThomas Cort #include <time.h>
636ea7f916SThomas Cort #include <unistd.h>
646ea7f916SThomas Cort #include <util.h>
656ea7f916SThomas Cort 
666ea7f916SThomas Cort #include "pr.h"
676ea7f916SThomas Cort #include "extern.h"
686ea7f916SThomas Cort 
696ea7f916SThomas Cort /*
706ea7f916SThomas Cort  * pr:	a printing and pagination filter. If multiple input files
716ea7f916SThomas Cort  *	are specified, each is read, formatted, and written to standard
726ea7f916SThomas Cort  *	output. By default, input is separated into 66-line pages, each
736ea7f916SThomas Cort  *	with a header that includes the page number, date, time and the
746ea7f916SThomas Cort  *	files pathname.
756ea7f916SThomas Cort  *
766ea7f916SThomas Cort  *	Complies with posix P1003.2/D11
776ea7f916SThomas Cort  */
786ea7f916SThomas Cort 
796ea7f916SThomas Cort /*
806ea7f916SThomas Cort  * parameter variables
816ea7f916SThomas Cort  */
826ea7f916SThomas Cort static int	pgnm;			/* starting page number */
836ea7f916SThomas Cort static int	clcnt;			/* number of columns */
846ea7f916SThomas Cort static int	colwd;			/* column data width - multiple columns */
856ea7f916SThomas Cort static int	across;			/* mult col flag; write across page */
866ea7f916SThomas Cort static int	dspace;			/* double space flag */
876ea7f916SThomas Cort static char	inchar;			/* expand input char */
886ea7f916SThomas Cort static int	ingap;			/* expand input gap */
896ea7f916SThomas Cort static int	formfeed;		/* use formfeed as trailer */
906ea7f916SThomas Cort static char	*header;		/* header name instead of file name */
916ea7f916SThomas Cort static char	ochar;			/* contract output char */
926ea7f916SThomas Cort static int	ogap;			/* contract output gap */
936ea7f916SThomas Cort static int	lines;			/* number of lines per page */
946ea7f916SThomas Cort static int	merge;			/* merge multiple files in output */
956ea7f916SThomas Cort static char	nmchar;			/* line numbering append char */
966ea7f916SThomas Cort static int	nmwd;			/* width of line number field */
976ea7f916SThomas Cort static int	offst;			/* number of page offset spaces */
986ea7f916SThomas Cort static int	nodiag;			/* do not report file open errors */
996ea7f916SThomas Cort static char	schar;			/* text column separation character */
1006ea7f916SThomas Cort static int	sflag;			/* -s option for multiple columns */
1016ea7f916SThomas Cort static int	ttyout;			/* output is a tty */
1026ea7f916SThomas Cort static int	nohead;			/* do not write head and trailer */
1036ea7f916SThomas Cort static int	pgpause;		/* pause before each page */
1046ea7f916SThomas Cort static int	pgwd;			/* page width with multiple col output */
1056ea7f916SThomas Cort static const char *timefrmt = TIMEFMT;	/* time conversion string */
1066ea7f916SThomas Cort static FILE	*ttyinf;		/* input terminal for page pauses */
1076ea7f916SThomas Cort 
1086ea7f916SThomas Cort /*
1096ea7f916SThomas Cort  * misc globals
1106ea7f916SThomas Cort  */
1116ea7f916SThomas Cort static FILE	*errf;			/* error message file pointer */
1126ea7f916SThomas Cort static int	addone;			/* page length is odd with double space */
1136ea7f916SThomas Cort static int	errcnt;			/* error count on file processing */
1146ea7f916SThomas Cort static const char	digs[] = "0123456789";	/* page number translation map */
1156ea7f916SThomas Cort 
1166ea7f916SThomas Cort static void	 addnum(char *, int, int);
1176ea7f916SThomas Cort static void	 flsh_errs(void);
1186ea7f916SThomas Cort static int	 horzcol(int, char **);
1196ea7f916SThomas Cort static int	 inln(FILE *, char *, int, int *, int, int *);
1206ea7f916SThomas Cort static int	 inskip(FILE *, int, int);
1216ea7f916SThomas Cort static void	 mfail(void);
1226ea7f916SThomas Cort static int	 mulfile(int, char **);
1236ea7f916SThomas Cort static FILE	*nxtfile(int, char **, const char **, char *, int);
1246ea7f916SThomas Cort static int	 onecol(int, char **);
1256ea7f916SThomas Cort static int	 otln(char *, int, int *, int *, int);
1266ea7f916SThomas Cort static void	 pfail(void);
1276ea7f916SThomas Cort static int	 prhead(char *, const char *, int);
1286ea7f916SThomas Cort static void	 prpause(int);
1296ea7f916SThomas Cort static int	 prtail(int, int);
1306ea7f916SThomas Cort static int	 setup(int, char **);
1316ea7f916SThomas Cort __dead static void	 terminate(int);
1326ea7f916SThomas Cort static void	 usage(void);
1336ea7f916SThomas Cort static int	 vertcol(int, char **);
1346ea7f916SThomas Cort 
1356ea7f916SThomas Cort int
main(int argc,char * argv[])1366ea7f916SThomas Cort main(int argc, char *argv[])
1376ea7f916SThomas Cort {
1386ea7f916SThomas Cort 	int ret_val;
1396ea7f916SThomas Cort 
1406ea7f916SThomas Cort 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1416ea7f916SThomas Cort 		(void)signal(SIGINT, terminate);
1426ea7f916SThomas Cort 	ret_val = setup(argc, argv);
1436ea7f916SThomas Cort 	if (!ret_val) {
1446ea7f916SThomas Cort 		/*
1456ea7f916SThomas Cort 		 * select the output format based on options
1466ea7f916SThomas Cort 		 */
1476ea7f916SThomas Cort 		if (merge)
1486ea7f916SThomas Cort 			ret_val = mulfile(argc, argv);
1496ea7f916SThomas Cort 		else if (clcnt == 1)
1506ea7f916SThomas Cort 			ret_val = onecol(argc, argv);
1516ea7f916SThomas Cort 		else if (across)
1526ea7f916SThomas Cort 			ret_val = horzcol(argc, argv);
1536ea7f916SThomas Cort 		else
1546ea7f916SThomas Cort 			ret_val = vertcol(argc, argv);
1556ea7f916SThomas Cort 	} else
1566ea7f916SThomas Cort 		usage();
1576ea7f916SThomas Cort 	flsh_errs();
1586ea7f916SThomas Cort 	if (errcnt || ret_val)
1596ea7f916SThomas Cort 		exit(1);
1606ea7f916SThomas Cort 	return(0);
1616ea7f916SThomas Cort }
1626ea7f916SThomas Cort 
1636ea7f916SThomas Cort /*
1646ea7f916SThomas Cort  * onecol:	print files with only one column of output.
1656ea7f916SThomas Cort  *		Line length is unlimited.
1666ea7f916SThomas Cort  */
1676ea7f916SThomas Cort static int
onecol(int argc,char * argv[])1686ea7f916SThomas Cort onecol(int argc, char *argv[])
1696ea7f916SThomas Cort {
1706ea7f916SThomas Cort 	int cnt = -1;
1716ea7f916SThomas Cort 	int off;
1726ea7f916SThomas Cort 	int lrgln;
1736ea7f916SThomas Cort 	int linecnt;
1746ea7f916SThomas Cort 	int num;
1756ea7f916SThomas Cort 	int lncnt;
1766ea7f916SThomas Cort 	int pagecnt;
1776ea7f916SThomas Cort 	int ips;
1786ea7f916SThomas Cort 	int ops;
1796ea7f916SThomas Cort 	int cps;
1806ea7f916SThomas Cort 	char *obuf = NULL;
1816ea7f916SThomas Cort 	char *lbuf;
1826ea7f916SThomas Cort 	char *nbuf;
1836ea7f916SThomas Cort 	char *hbuf = NULL;
1846ea7f916SThomas Cort 	char *ohbuf;
1856ea7f916SThomas Cort 	FILE *inf = NULL;
1866ea7f916SThomas Cort 	const char *fname;
1876ea7f916SThomas Cort 	int mor;
1886ea7f916SThomas Cort 	int error = 1;
1896ea7f916SThomas Cort 
190*e1cdaee1SLionel Sambuc #if defined(__minix)
191*e1cdaee1SLionel Sambuc 	/* LSC: -Werror=maybe-uninitialized, when compiling with -O3 */
192*e1cdaee1SLionel Sambuc 	mor = 0;
193*e1cdaee1SLionel Sambuc #endif /* defined(__minix) */
1946ea7f916SThomas Cort 	if (nmwd)
1956ea7f916SThomas Cort 		num = nmwd + 1;
1966ea7f916SThomas Cort 	else
1976ea7f916SThomas Cort 		num = 0;
1986ea7f916SThomas Cort 	off = num + offst;
1996ea7f916SThomas Cort 
2006ea7f916SThomas Cort 	/*
2016ea7f916SThomas Cort 	 * allocate line buffer
2026ea7f916SThomas Cort 	 */
2036ea7f916SThomas Cort 	if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL)
2046ea7f916SThomas Cort 		goto oomem;
2056ea7f916SThomas Cort 	/*
2066ea7f916SThomas Cort 	 * allocate header buffer
2076ea7f916SThomas Cort 	 */
2086ea7f916SThomas Cort 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL)
2096ea7f916SThomas Cort 		goto oomem;
2106ea7f916SThomas Cort 
2116ea7f916SThomas Cort 	ohbuf = hbuf + offst;
2126ea7f916SThomas Cort 	nbuf = obuf + offst;
2136ea7f916SThomas Cort 	lbuf = nbuf + num;
2146ea7f916SThomas Cort 	if (num)
2156ea7f916SThomas Cort 		nbuf[--num] = nmchar;
2166ea7f916SThomas Cort 	if (offst) {
2176ea7f916SThomas Cort 		(void)memset(obuf, (int)' ', offst);
2186ea7f916SThomas Cort 		(void)memset(hbuf, (int)' ', offst);
2196ea7f916SThomas Cort 	}
2206ea7f916SThomas Cort 
2216ea7f916SThomas Cort 	/*
2226ea7f916SThomas Cort 	 * loop by file
2236ea7f916SThomas Cort 	 */
2246ea7f916SThomas Cort 	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
2256ea7f916SThomas Cort 		if (pgnm) {
2266ea7f916SThomas Cort 			/*
2276ea7f916SThomas Cort 			 * skip to specified page
2286ea7f916SThomas Cort 			 */
2296ea7f916SThomas Cort 			if (inskip(inf, pgnm, lines))
2306ea7f916SThomas Cort 				continue;
2316ea7f916SThomas Cort 			pagecnt = pgnm;
2326ea7f916SThomas Cort 		} else
2336ea7f916SThomas Cort 			pagecnt = 1;
2346ea7f916SThomas Cort 		lncnt = 0;
2356ea7f916SThomas Cort 
2366ea7f916SThomas Cort 		/*
2376ea7f916SThomas Cort 		 * loop by page
2386ea7f916SThomas Cort 		 */
2396ea7f916SThomas Cort 		for(;;) {
2406ea7f916SThomas Cort 			linecnt = 0;
2416ea7f916SThomas Cort 			lrgln = 0;
2426ea7f916SThomas Cort 			ops = 0;
2436ea7f916SThomas Cort 			ips = 0;
2446ea7f916SThomas Cort 			cps = 0;
2456ea7f916SThomas Cort 
2466ea7f916SThomas Cort 			/*
2476ea7f916SThomas Cort 			 * loop by line
2486ea7f916SThomas Cort 			 */
2496ea7f916SThomas Cort 			while (linecnt < lines) {
2506ea7f916SThomas Cort 				/*
2516ea7f916SThomas Cort 				 * input next line
2526ea7f916SThomas Cort 				 */
2536ea7f916SThomas Cort 				if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0)
2546ea7f916SThomas Cort 					break;
2556ea7f916SThomas Cort 				if (!linecnt) {
2566ea7f916SThomas Cort 					if (pgpause)
2576ea7f916SThomas Cort 						prpause(pagecnt);
2586ea7f916SThomas Cort 
2596ea7f916SThomas Cort 				        if (!nohead &&
2606ea7f916SThomas Cort 					    prhead(hbuf, fname, pagecnt))
2616ea7f916SThomas Cort 						goto out;
2626ea7f916SThomas Cort 				}
2636ea7f916SThomas Cort 
2646ea7f916SThomas Cort 				/*
2656ea7f916SThomas Cort 				 * start of new line.
2666ea7f916SThomas Cort 				 */
2676ea7f916SThomas Cort 				if (!lrgln) {
2686ea7f916SThomas Cort 					if (num)
2696ea7f916SThomas Cort 						addnum(nbuf, num, ++lncnt);
2706ea7f916SThomas Cort 					if (otln(obuf,cnt+off, &ips, &ops, mor))
2716ea7f916SThomas Cort 						goto out;
2726ea7f916SThomas Cort 				} else if (otln(lbuf, cnt, &ips, &ops, mor))
2736ea7f916SThomas Cort 					goto out;
2746ea7f916SThomas Cort 
2756ea7f916SThomas Cort 				/*
2766ea7f916SThomas Cort 				 * if line bigger than buffer, get more
2776ea7f916SThomas Cort 				 */
2786ea7f916SThomas Cort 				if (mor) {
2796ea7f916SThomas Cort 					lrgln = 1;
2806ea7f916SThomas Cort 					continue;
2816ea7f916SThomas Cort 				}
2826ea7f916SThomas Cort 
2836ea7f916SThomas Cort 				/*
2846ea7f916SThomas Cort 				 * whole line rcvd. reset tab proc. state
2856ea7f916SThomas Cort 				 */
2866ea7f916SThomas Cort 				++linecnt;
2876ea7f916SThomas Cort 				lrgln = 0;
2886ea7f916SThomas Cort 				ops = 0;
2896ea7f916SThomas Cort 				ips = 0;
2906ea7f916SThomas Cort 			}
2916ea7f916SThomas Cort 
2926ea7f916SThomas Cort 			/*
2936ea7f916SThomas Cort 			 * fill to end of page
2946ea7f916SThomas Cort 			 */
2956ea7f916SThomas Cort 			if (linecnt && prtail(lines-linecnt-lrgln, lrgln))
2966ea7f916SThomas Cort 				goto out;
2976ea7f916SThomas Cort 
2986ea7f916SThomas Cort 			/*
2996ea7f916SThomas Cort 			 * On EOF go to next file
3006ea7f916SThomas Cort 			 */
3016ea7f916SThomas Cort 			if (cnt < 0)
3026ea7f916SThomas Cort 				break;
3036ea7f916SThomas Cort 			++pagecnt;
3046ea7f916SThomas Cort 		}
3056ea7f916SThomas Cort 		if (inf != stdin)
3066ea7f916SThomas Cort 			(void)fclose(inf);
3076ea7f916SThomas Cort 	}
3086ea7f916SThomas Cort 	if (eoptind < argc)
3096ea7f916SThomas Cort 		goto out;
3106ea7f916SThomas Cort 	error = 0;
3116ea7f916SThomas Cort 	goto out;
3126ea7f916SThomas Cort oomem:
3136ea7f916SThomas Cort 	mfail();
3146ea7f916SThomas Cort out:
3156ea7f916SThomas Cort 	free(obuf);
3166ea7f916SThomas Cort 	free(hbuf);
3176ea7f916SThomas Cort 	if (inf != NULL && inf != stdin)
3186ea7f916SThomas Cort 		(void)fclose(inf);
3196ea7f916SThomas Cort 	return error;
3206ea7f916SThomas Cort }
3216ea7f916SThomas Cort 
3226ea7f916SThomas Cort /*
3236ea7f916SThomas Cort  * vertcol:	print files with more than one column of output down a page
3246ea7f916SThomas Cort  */
3256ea7f916SThomas Cort static int
vertcol(int argc,char * argv[])3266ea7f916SThomas Cort vertcol(int argc, char *argv[])
3276ea7f916SThomas Cort {
3286ea7f916SThomas Cort 	char *ptbf;
3296ea7f916SThomas Cort 	char **lstdat = NULL;
3306ea7f916SThomas Cort 	int i;
3316ea7f916SThomas Cort 	int j;
3326ea7f916SThomas Cort 	int cnt = -1;
3336ea7f916SThomas Cort 	int pln;
3346ea7f916SThomas Cort 	int *indy = NULL;
3356ea7f916SThomas Cort 	int cvc;
3366ea7f916SThomas Cort 	int *lindy = NULL;
3376ea7f916SThomas Cort 	int lncnt;
3386ea7f916SThomas Cort 	int stp;
3396ea7f916SThomas Cort 	int pagecnt;
3406ea7f916SThomas Cort 	int col = colwd + 1;
3416ea7f916SThomas Cort 	int mxlen = pgwd + offst + 1;
3426ea7f916SThomas Cort 	int mclcnt = clcnt - 1;
3436ea7f916SThomas Cort 	struct vcol *vc = NULL;
3446ea7f916SThomas Cort 	int mvc;
3456ea7f916SThomas Cort 	int tvc;
3466ea7f916SThomas Cort 	int cw = nmwd + 1;
3476ea7f916SThomas Cort 	int fullcol;
3486ea7f916SThomas Cort 	char *buf = NULL;
3496ea7f916SThomas Cort 	char *hbuf = NULL;
3506ea7f916SThomas Cort 	char *ohbuf;
3516ea7f916SThomas Cort 	const char *fname;
3526ea7f916SThomas Cort 	FILE *inf = NULL;
3536ea7f916SThomas Cort 	int ips = 0;
3546ea7f916SThomas Cort 	int cps = 0;
3556ea7f916SThomas Cort 	int ops = 0;
3566ea7f916SThomas Cort 	int mor = 0;
3576ea7f916SThomas Cort 	int error = 1;
3586ea7f916SThomas Cort 
3596ea7f916SThomas Cort 	/*
3606ea7f916SThomas Cort 	 * allocate page buffer
3616ea7f916SThomas Cort 	 */
3626ea7f916SThomas Cort 	if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL)
3636ea7f916SThomas Cort 		goto oomem;
3646ea7f916SThomas Cort 
3656ea7f916SThomas Cort 	/*
3666ea7f916SThomas Cort 	 * allocate page header
3676ea7f916SThomas Cort 	 */
3686ea7f916SThomas Cort 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL)
3696ea7f916SThomas Cort 		goto oomem;
3706ea7f916SThomas Cort 	ohbuf = hbuf + offst;
3716ea7f916SThomas Cort 	if (offst)
3726ea7f916SThomas Cort 		(void)memset(hbuf, (int)' ', offst);
3736ea7f916SThomas Cort 
3746ea7f916SThomas Cort 	/*
3756ea7f916SThomas Cort 	 * col pointers when no headers
3766ea7f916SThomas Cort 	 */
3776ea7f916SThomas Cort 	mvc = lines * clcnt;
3786ea7f916SThomas Cort 	if ((vc = malloc((unsigned)mvc*sizeof(struct vcol))) == NULL)
3796ea7f916SThomas Cort 		goto oomem;
3806ea7f916SThomas Cort 
3816ea7f916SThomas Cort 	/*
3826ea7f916SThomas Cort 	 * pointer into page where last data per line is located
3836ea7f916SThomas Cort 	 */
3846ea7f916SThomas Cort 	if ((lstdat = malloc((unsigned)lines*sizeof(char *))) == NULL)
3856ea7f916SThomas Cort 		goto oomem;
3866ea7f916SThomas Cort 
3876ea7f916SThomas Cort 	/*
3886ea7f916SThomas Cort 	 * fast index lookups to locate start of lines
3896ea7f916SThomas Cort 	 */
3906ea7f916SThomas Cort 	if ((indy = malloc((unsigned)lines*sizeof(int))) == NULL)
3916ea7f916SThomas Cort 		goto oomem;
3926ea7f916SThomas Cort 	if ((lindy = malloc((unsigned)lines*sizeof(int))) == NULL)
3936ea7f916SThomas Cort 		goto oomem;
3946ea7f916SThomas Cort 
3956ea7f916SThomas Cort 	if (nmwd)
3966ea7f916SThomas Cort 		fullcol = col + cw;
3976ea7f916SThomas Cort 	else
3986ea7f916SThomas Cort 		fullcol = col;
3996ea7f916SThomas Cort 
4006ea7f916SThomas Cort 	/*
4016ea7f916SThomas Cort 	 * initialize buffer lookup indexes and offset area
4026ea7f916SThomas Cort 	 */
4036ea7f916SThomas Cort 	for (j = 0; j < lines; ++j) {
4046ea7f916SThomas Cort 		lindy[j] = j * mxlen;
4056ea7f916SThomas Cort 		indy[j] = lindy[j] + offst;
4066ea7f916SThomas Cort 		if (offst) {
4076ea7f916SThomas Cort 			ptbf = buf + lindy[j];
4086ea7f916SThomas Cort 			(void)memset(ptbf, (int)' ', offst);
4096ea7f916SThomas Cort 			ptbf += offst;
4106ea7f916SThomas Cort 		} else
4116ea7f916SThomas Cort 			ptbf = buf + indy[j];
4126ea7f916SThomas Cort 		lstdat[j] = ptbf;
4136ea7f916SThomas Cort 	}
4146ea7f916SThomas Cort 
4156ea7f916SThomas Cort 	/*
4166ea7f916SThomas Cort 	 * loop by file
4176ea7f916SThomas Cort 	 */
4186ea7f916SThomas Cort 	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
4196ea7f916SThomas Cort 		if (pgnm) {
4206ea7f916SThomas Cort 			/*
4216ea7f916SThomas Cort 			 * skip to requested page
4226ea7f916SThomas Cort 			 */
4236ea7f916SThomas Cort 			if (inskip(inf, pgnm, lines))
4246ea7f916SThomas Cort 				continue;
4256ea7f916SThomas Cort 			pagecnt = pgnm;
4266ea7f916SThomas Cort 		} else
4276ea7f916SThomas Cort 			pagecnt = 1;
4286ea7f916SThomas Cort 		lncnt = 0;
4296ea7f916SThomas Cort 
4306ea7f916SThomas Cort 		/*
4316ea7f916SThomas Cort 		 * loop by page
4326ea7f916SThomas Cort 		 */
4336ea7f916SThomas Cort 		for(;;) {
4346ea7f916SThomas Cort 			/*
4356ea7f916SThomas Cort 			 * loop by column
4366ea7f916SThomas Cort 			 */
4376ea7f916SThomas Cort 			cvc = 0;
4386ea7f916SThomas Cort 			for (i = 0; i < clcnt; ++i) {
4396ea7f916SThomas Cort 				j = 0;
4406ea7f916SThomas Cort 				/*
4416ea7f916SThomas Cort 				 * if last column, do not pad
4426ea7f916SThomas Cort 				 */
4436ea7f916SThomas Cort 				if (i == mclcnt)
4446ea7f916SThomas Cort 					stp = 1;
4456ea7f916SThomas Cort 				else
4466ea7f916SThomas Cort 					stp = 0;
4476ea7f916SThomas Cort 				/*
4486ea7f916SThomas Cort 				 * loop by line
4496ea7f916SThomas Cort 				 */
4506ea7f916SThomas Cort 				for(;;) {
4516ea7f916SThomas Cort 					/*
4526ea7f916SThomas Cort 					 * is this first column
4536ea7f916SThomas Cort 					 */
4546ea7f916SThomas Cort 					if (!i) {
4556ea7f916SThomas Cort 						ptbf = buf + indy[j];
4566ea7f916SThomas Cort 						lstdat[j] = ptbf;
4576ea7f916SThomas Cort 					} else
4586ea7f916SThomas Cort 						ptbf = lstdat[j];
4596ea7f916SThomas Cort 					vc[cvc].pt = ptbf;
4606ea7f916SThomas Cort 
4616ea7f916SThomas Cort 					/*
4626ea7f916SThomas Cort 					 * add number
4636ea7f916SThomas Cort 					 */
4646ea7f916SThomas Cort 					if (nmwd) {
4656ea7f916SThomas Cort 						addnum(ptbf, nmwd, ++lncnt);
4666ea7f916SThomas Cort 						ptbf += nmwd;
4676ea7f916SThomas Cort 						*ptbf++ = nmchar;
4686ea7f916SThomas Cort 					}
4696ea7f916SThomas Cort 
4706ea7f916SThomas Cort 					/*
4716ea7f916SThomas Cort 					 * input next line
4726ea7f916SThomas Cort 					 */
4736ea7f916SThomas Cort 					cnt = inln(inf,ptbf,colwd,&cps,1,&mor);
4746ea7f916SThomas Cort 					vc[cvc++].cnt = cnt;
4756ea7f916SThomas Cort 					if (cnt < 0)
4766ea7f916SThomas Cort 						break;
4776ea7f916SThomas Cort 					ptbf += cnt;
4786ea7f916SThomas Cort 
4796ea7f916SThomas Cort 					/*
4806ea7f916SThomas Cort 					 * pad all but last column on page
4816ea7f916SThomas Cort 					 */
4826ea7f916SThomas Cort 					if (!stp) {
4836ea7f916SThomas Cort 						/*
4846ea7f916SThomas Cort 						 * pad to end of column
4856ea7f916SThomas Cort 						 */
4866ea7f916SThomas Cort 						if (sflag)
4876ea7f916SThomas Cort 							*ptbf++ = schar;
4886ea7f916SThomas Cort 						else if ((pln = col-cnt) > 0) {
4896ea7f916SThomas Cort 							(void)memset(ptbf,
4906ea7f916SThomas Cort 								(int)' ',pln);
4916ea7f916SThomas Cort 							ptbf += pln;
4926ea7f916SThomas Cort 						}
4936ea7f916SThomas Cort 					}
4946ea7f916SThomas Cort 					/*
4956ea7f916SThomas Cort 					 * remember last char in line
4966ea7f916SThomas Cort 					 */
4976ea7f916SThomas Cort 					lstdat[j] = ptbf;
4986ea7f916SThomas Cort 					if (++j >= lines)
4996ea7f916SThomas Cort 						break;
5006ea7f916SThomas Cort 				}
5016ea7f916SThomas Cort 				if (cnt < 0)
5026ea7f916SThomas Cort 					break;
5036ea7f916SThomas Cort 			}
5046ea7f916SThomas Cort 
5056ea7f916SThomas Cort 			/*
5066ea7f916SThomas Cort 			 * when -t (no header) is specified the spec requires
5076ea7f916SThomas Cort 			 * the min number of lines. The last page may not have
5086ea7f916SThomas Cort 			 * balanced length columns. To fix this we must reorder
5096ea7f916SThomas Cort 			 * the columns. This is a very slow technique so it is
5106ea7f916SThomas Cort 			 * only used under limited conditions. Without -t, the
5116ea7f916SThomas Cort 			 * balancing of text columns is unspecified. To NOT
5126ea7f916SThomas Cort 			 * balance the last page, add the global variable
5136ea7f916SThomas Cort 			 * nohead to the if statement below e.g.
5146ea7f916SThomas Cort 			 *
5156ea7f916SThomas Cort 			 * if ((cnt < 0) && nohead && cvc ......
5166ea7f916SThomas Cort 			 */
5176ea7f916SThomas Cort 			--cvc;
5186ea7f916SThomas Cort 
5196ea7f916SThomas Cort 			/*
5206ea7f916SThomas Cort 			 * check to see if last page needs to be reordered
5216ea7f916SThomas Cort 			 */
5226ea7f916SThomas Cort 			if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){
5236ea7f916SThomas Cort 				pln = cvc/clcnt;
5246ea7f916SThomas Cort 				if (cvc % clcnt)
5256ea7f916SThomas Cort 					++pln;
5266ea7f916SThomas Cort 
5276ea7f916SThomas Cort 				if (pgpause)
5286ea7f916SThomas Cort 					prpause(pagecnt);
5296ea7f916SThomas Cort 
5306ea7f916SThomas Cort 				/*
5316ea7f916SThomas Cort 				 * print header
5326ea7f916SThomas Cort 				 */
5336ea7f916SThomas Cort 				if (!nohead && prhead(hbuf, fname, pagecnt))
5346ea7f916SThomas Cort 					goto out;
5356ea7f916SThomas Cort 				for (i = 0; i < pln; ++i) {
5366ea7f916SThomas Cort 					ips = 0;
5376ea7f916SThomas Cort 					ops = 0;
5386ea7f916SThomas Cort 					if (offst&& otln(buf,offst,&ips,&ops,1)) {
5396ea7f916SThomas Cort 						error = 1;
5406ea7f916SThomas Cort 						goto out;
5416ea7f916SThomas Cort 					}
5426ea7f916SThomas Cort 					tvc = i;
5436ea7f916SThomas Cort 
5446ea7f916SThomas Cort 					for (j = 0; j < clcnt; ++j) {
5456ea7f916SThomas Cort 						/*
5466ea7f916SThomas Cort 						 * determine column length
5476ea7f916SThomas Cort 						 */
5486ea7f916SThomas Cort 						if (j == mclcnt) {
5496ea7f916SThomas Cort 							/*
5506ea7f916SThomas Cort 							 * last column
5516ea7f916SThomas Cort 							 */
5526ea7f916SThomas Cort 							cnt = vc[tvc].cnt;
5536ea7f916SThomas Cort 							if (nmwd)
5546ea7f916SThomas Cort 								cnt += cw;
5556ea7f916SThomas Cort 						} else if (sflag) {
5566ea7f916SThomas Cort 							/*
5576ea7f916SThomas Cort 							 * single ch between
5586ea7f916SThomas Cort 							 */
5596ea7f916SThomas Cort 							cnt = vc[tvc].cnt + 1;
5606ea7f916SThomas Cort 							if (nmwd)
5616ea7f916SThomas Cort 								cnt += cw;
5626ea7f916SThomas Cort 						} else
5636ea7f916SThomas Cort 							cnt = fullcol;
5646ea7f916SThomas Cort 						if (otln(vc[tvc].pt, cnt, &ips,
5656ea7f916SThomas Cort 								&ops, 1))
5666ea7f916SThomas Cort 							goto out;
5676ea7f916SThomas Cort 						tvc += pln;
5686ea7f916SThomas Cort 						if (tvc >= cvc)
5696ea7f916SThomas Cort 							break;
5706ea7f916SThomas Cort 					}
5716ea7f916SThomas Cort 					/*
5726ea7f916SThomas Cort 					 * terminate line
5736ea7f916SThomas Cort 					 */
5746ea7f916SThomas Cort 					if (otln(buf, 0, &ips, &ops, 0))
5756ea7f916SThomas Cort 						goto out;
5766ea7f916SThomas Cort 				}
5776ea7f916SThomas Cort 				/*
5786ea7f916SThomas Cort 				 * pad to end of page
5796ea7f916SThomas Cort 				 */
5806ea7f916SThomas Cort 				if (prtail((lines - pln), 0))
5816ea7f916SThomas Cort 					goto out;
5826ea7f916SThomas Cort 				/*
5836ea7f916SThomas Cort 				 * done with output, go to next file
5846ea7f916SThomas Cort 				 */
5856ea7f916SThomas Cort 				break;
5866ea7f916SThomas Cort 			}
5876ea7f916SThomas Cort 
5886ea7f916SThomas Cort 			/*
5896ea7f916SThomas Cort 			 * determine how many lines to output
5906ea7f916SThomas Cort 			 */
5916ea7f916SThomas Cort 			if (i > 0)
5926ea7f916SThomas Cort 				pln = lines;
5936ea7f916SThomas Cort 			else
5946ea7f916SThomas Cort 				pln = j;
5956ea7f916SThomas Cort 
5966ea7f916SThomas Cort 			/*
5976ea7f916SThomas Cort 			 * print header
5986ea7f916SThomas Cort 			 */
5996ea7f916SThomas Cort 			if (pln) {
6006ea7f916SThomas Cort 				if (pgpause)
6016ea7f916SThomas Cort 					prpause(pagecnt);
6026ea7f916SThomas Cort 
6036ea7f916SThomas Cort 			        if (!nohead && prhead(hbuf, fname, pagecnt))
6046ea7f916SThomas Cort 					goto out;
6056ea7f916SThomas Cort 			}
6066ea7f916SThomas Cort 
6076ea7f916SThomas Cort 			/*
6086ea7f916SThomas Cort 			 * output each line
6096ea7f916SThomas Cort 			 */
6106ea7f916SThomas Cort 			for (i = 0; i < pln; ++i) {
6116ea7f916SThomas Cort 				ptbf = buf + lindy[i];
6126ea7f916SThomas Cort 				if ((j = lstdat[i] - ptbf) <= offst)
6136ea7f916SThomas Cort 					break;
6146ea7f916SThomas Cort 				if (otln(ptbf, j, &ips, &ops, 0))
6156ea7f916SThomas Cort 					goto out;
6166ea7f916SThomas Cort 			}
6176ea7f916SThomas Cort 
6186ea7f916SThomas Cort 			/*
6196ea7f916SThomas Cort 			 * pad to end of page
6206ea7f916SThomas Cort 			 */
6216ea7f916SThomas Cort 			if (pln && prtail((lines - pln), 0))
6226ea7f916SThomas Cort 				goto out;
6236ea7f916SThomas Cort 
6246ea7f916SThomas Cort 			/*
6256ea7f916SThomas Cort 			 * if EOF go to next file
6266ea7f916SThomas Cort 			 */
6276ea7f916SThomas Cort 			if (cnt < 0)
6286ea7f916SThomas Cort 				break;
6296ea7f916SThomas Cort 			++pagecnt;
6306ea7f916SThomas Cort 		}
6316ea7f916SThomas Cort 		if (inf != stdin)
6326ea7f916SThomas Cort 			(void)fclose(inf);
6336ea7f916SThomas Cort 	}
6346ea7f916SThomas Cort 	if (eoptind < argc)
6356ea7f916SThomas Cort 		goto out;
6366ea7f916SThomas Cort 	error = 0;
6376ea7f916SThomas Cort 	goto out;
6386ea7f916SThomas Cort oomem:
6396ea7f916SThomas Cort 	mfail();
6406ea7f916SThomas Cort out:
6416ea7f916SThomas Cort 	free(buf);
6426ea7f916SThomas Cort 	free(hbuf);
6436ea7f916SThomas Cort 	free(vc);
6446ea7f916SThomas Cort 	free(lstdat);
6456ea7f916SThomas Cort 	free(lindy);
6466ea7f916SThomas Cort 	if (inf != NULL && inf != stdin)
6476ea7f916SThomas Cort 		(void)fclose(inf);
6486ea7f916SThomas Cort 	return error;
6496ea7f916SThomas Cort }
6506ea7f916SThomas Cort 
6516ea7f916SThomas Cort /*
6526ea7f916SThomas Cort  * horzcol:	print files with more than one column of output across a page
6536ea7f916SThomas Cort  */
6546ea7f916SThomas Cort static int
horzcol(int argc,char * argv[])6556ea7f916SThomas Cort horzcol(int argc, char *argv[])
6566ea7f916SThomas Cort {
6576ea7f916SThomas Cort 	char *ptbf;
6586ea7f916SThomas Cort 	int pln;
6596ea7f916SThomas Cort 	int cnt = -1;
6606ea7f916SThomas Cort 	char *lstdat;
6616ea7f916SThomas Cort 	int col = colwd + 1;
6626ea7f916SThomas Cort 	int j;
6636ea7f916SThomas Cort 	int i;
6646ea7f916SThomas Cort 	int lncnt;
6656ea7f916SThomas Cort 	int pagecnt;
6666ea7f916SThomas Cort 	char *buf = NULL;
6676ea7f916SThomas Cort 	char *hbuf = NULL;
6686ea7f916SThomas Cort 	char *ohbuf;
6696ea7f916SThomas Cort 	const char *fname;
6706ea7f916SThomas Cort 	FILE *inf = NULL;
6716ea7f916SThomas Cort 	int ips = 0;
6726ea7f916SThomas Cort 	int cps = 0;
6736ea7f916SThomas Cort 	int ops = 0;
6746ea7f916SThomas Cort 	int mor = 0;
6756ea7f916SThomas Cort 	int error = 1;
6766ea7f916SThomas Cort 
6776ea7f916SThomas Cort 	if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL)
6786ea7f916SThomas Cort 		goto oomem;
6796ea7f916SThomas Cort 
6806ea7f916SThomas Cort 	/*
6816ea7f916SThomas Cort 	 * page header
6826ea7f916SThomas Cort 	 */
6836ea7f916SThomas Cort 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL)
6846ea7f916SThomas Cort 		goto oomem;
6856ea7f916SThomas Cort 	ohbuf = hbuf + offst;
6866ea7f916SThomas Cort 	if (offst) {
6876ea7f916SThomas Cort 		(void)memset(buf, (int)' ', offst);
6886ea7f916SThomas Cort 		(void)memset(hbuf, (int)' ', offst);
6896ea7f916SThomas Cort 	}
6906ea7f916SThomas Cort 
6916ea7f916SThomas Cort 	/*
6926ea7f916SThomas Cort 	 * loop by file
6936ea7f916SThomas Cort 	 */
6946ea7f916SThomas Cort 	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
6956ea7f916SThomas Cort 		if (pgnm) {
6966ea7f916SThomas Cort 			if (inskip(inf, pgnm, lines))
6976ea7f916SThomas Cort 				continue;
6986ea7f916SThomas Cort 			pagecnt = pgnm;
6996ea7f916SThomas Cort 		} else
7006ea7f916SThomas Cort 			pagecnt = 1;
7016ea7f916SThomas Cort 		lncnt = 0;
7026ea7f916SThomas Cort 
7036ea7f916SThomas Cort 		/*
7046ea7f916SThomas Cort 		 * loop by page
7056ea7f916SThomas Cort 		 */
7066ea7f916SThomas Cort 		for(;;) {
7076ea7f916SThomas Cort 			/*
7086ea7f916SThomas Cort 			 * loop by line
7096ea7f916SThomas Cort 			 */
7106ea7f916SThomas Cort 			for (i = 0; i < lines; ++i) {
7116ea7f916SThomas Cort 				ptbf = buf + offst;
7126ea7f916SThomas Cort 				lstdat = ptbf;
7136ea7f916SThomas Cort 				j = 0;
7146ea7f916SThomas Cort 				/*
7156ea7f916SThomas Cort 				 * loop by col
7166ea7f916SThomas Cort 				 */
7176ea7f916SThomas Cort 				for(;;) {
7186ea7f916SThomas Cort 					if (nmwd) {
7196ea7f916SThomas Cort 						/*
7206ea7f916SThomas Cort 						 * add number to column
7216ea7f916SThomas Cort 						 */
7226ea7f916SThomas Cort 						addnum(ptbf, nmwd, ++lncnt);
7236ea7f916SThomas Cort 						ptbf += nmwd;
7246ea7f916SThomas Cort 						*ptbf++ = nmchar;
7256ea7f916SThomas Cort 					}
7266ea7f916SThomas Cort 					/*
7276ea7f916SThomas Cort 					 * input line
7286ea7f916SThomas Cort 					 */
7296ea7f916SThomas Cort 					if ((cnt = inln(inf,ptbf,colwd,&cps,1,
7306ea7f916SThomas Cort 							&mor)) < 0)
7316ea7f916SThomas Cort 						break;
7326ea7f916SThomas Cort 					ptbf += cnt;
7336ea7f916SThomas Cort 					lstdat = ptbf;
7346ea7f916SThomas Cort 
7356ea7f916SThomas Cort 					/*
7366ea7f916SThomas Cort 					 * if last line skip padding
7376ea7f916SThomas Cort 					 */
7386ea7f916SThomas Cort 					if (++j >= clcnt)
7396ea7f916SThomas Cort 						break;
7406ea7f916SThomas Cort 
7416ea7f916SThomas Cort 					/*
7426ea7f916SThomas Cort 					 * pad to end of column
7436ea7f916SThomas Cort 					 */
7446ea7f916SThomas Cort 					if (sflag)
7456ea7f916SThomas Cort 						*ptbf++ = schar;
7466ea7f916SThomas Cort 					else if ((pln = col - cnt) > 0) {
7476ea7f916SThomas Cort 						(void)memset(ptbf,(int)' ',pln);
7486ea7f916SThomas Cort 						ptbf += pln;
7496ea7f916SThomas Cort 					}
7506ea7f916SThomas Cort 				}
7516ea7f916SThomas Cort 
7526ea7f916SThomas Cort 				/*
7536ea7f916SThomas Cort 				 * determine line length
7546ea7f916SThomas Cort 				 */
7556ea7f916SThomas Cort 				if ((j = lstdat - buf) <= offst)
7566ea7f916SThomas Cort 					break;
7576ea7f916SThomas Cort 				if (!i) {
7586ea7f916SThomas Cort 					if (pgpause)
7596ea7f916SThomas Cort 						prpause(pagecnt);
7606ea7f916SThomas Cort 
7616ea7f916SThomas Cort 				        if (!nohead &&
7626ea7f916SThomas Cort 					    prhead(hbuf, fname, pagecnt))
7636ea7f916SThomas Cort 						goto out;
7646ea7f916SThomas Cort 				}
7656ea7f916SThomas Cort 				/*
7666ea7f916SThomas Cort 				 * output line
7676ea7f916SThomas Cort 				 */
7686ea7f916SThomas Cort 				if (otln(buf, j, &ips, &ops, 0))
7696ea7f916SThomas Cort 					goto out;
7706ea7f916SThomas Cort 			}
7716ea7f916SThomas Cort 
7726ea7f916SThomas Cort 			/*
7736ea7f916SThomas Cort 			 * pad to end of page
7746ea7f916SThomas Cort 			 */
7756ea7f916SThomas Cort 			if (i && prtail(lines-i, 0))
7766ea7f916SThomas Cort 				goto out;
7776ea7f916SThomas Cort 
7786ea7f916SThomas Cort 			/*
7796ea7f916SThomas Cort 			 * if EOF go to next file
7806ea7f916SThomas Cort 			 */
7816ea7f916SThomas Cort 			if (cnt < 0)
7826ea7f916SThomas Cort 				break;
7836ea7f916SThomas Cort 			++pagecnt;
7846ea7f916SThomas Cort 		}
7856ea7f916SThomas Cort 		if (inf != stdin)
7866ea7f916SThomas Cort 			(void)fclose(inf);
7876ea7f916SThomas Cort 	}
7886ea7f916SThomas Cort 	if (eoptind < argc)
7896ea7f916SThomas Cort 		goto out;
7906ea7f916SThomas Cort 	error = 0;
7916ea7f916SThomas Cort 	goto out;
7926ea7f916SThomas Cort oomem:
7936ea7f916SThomas Cort 	mfail();
7946ea7f916SThomas Cort out:
7956ea7f916SThomas Cort 	free(buf);
7966ea7f916SThomas Cort 	free(hbuf);
7976ea7f916SThomas Cort 	if (inf != NULL && inf != stdin)
7986ea7f916SThomas Cort 		(void)fclose(inf);
7996ea7f916SThomas Cort 	return error;
8006ea7f916SThomas Cort }
8016ea7f916SThomas Cort 
8026ea7f916SThomas Cort /*
8036ea7f916SThomas Cort  * mulfile:	print files with more than one column of output and
8046ea7f916SThomas Cort  *		more than one file concurrently
8056ea7f916SThomas Cort  */
8066ea7f916SThomas Cort static int
mulfile(int argc,char * argv[])8076ea7f916SThomas Cort mulfile(int argc, char *argv[])
8086ea7f916SThomas Cort {
8096ea7f916SThomas Cort 	char *ptbf;
8106ea7f916SThomas Cort 	int j;
8116ea7f916SThomas Cort 	int pln;
8126ea7f916SThomas Cort 	int cnt;
8136ea7f916SThomas Cort 	char *lstdat;
8146ea7f916SThomas Cort 	int i;
8156ea7f916SThomas Cort 	FILE **fbuf = NULL;
8166ea7f916SThomas Cort 	int actf;
8176ea7f916SThomas Cort 	int lncnt;
8186ea7f916SThomas Cort 	int col;
8196ea7f916SThomas Cort 	int pagecnt;
8206ea7f916SThomas Cort 	int fproc;
8216ea7f916SThomas Cort 	char *buf = NULL;
8226ea7f916SThomas Cort 	char *hbuf = NULL;
8236ea7f916SThomas Cort 	char *ohbuf;
8246ea7f916SThomas Cort 	const char *fname;
8256ea7f916SThomas Cort 	int ips = 0;
8266ea7f916SThomas Cort 	int cps = 0;
8276ea7f916SThomas Cort 	int ops = 0;
8286ea7f916SThomas Cort 	int mor = 0;
8296ea7f916SThomas Cort 	int error = 1;
8306ea7f916SThomas Cort 
8316ea7f916SThomas Cort 	/*
8326ea7f916SThomas Cort 	 * array of FILE *, one for each operand
8336ea7f916SThomas Cort 	 */
8346ea7f916SThomas Cort 	if ((fbuf = calloc(clcnt, sizeof(FILE *))) == NULL)
8356ea7f916SThomas Cort 		goto oomem;
8366ea7f916SThomas Cort 
8376ea7f916SThomas Cort 	/*
8386ea7f916SThomas Cort 	 * page header
8396ea7f916SThomas Cort 	 */
8406ea7f916SThomas Cort 	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL)
8416ea7f916SThomas Cort 		goto oomem;
8426ea7f916SThomas Cort 	ohbuf = hbuf + offst;
8436ea7f916SThomas Cort 
8446ea7f916SThomas Cort 	/*
8456ea7f916SThomas Cort 	 * do not know how many columns yet. The number of operands provide an
8466ea7f916SThomas Cort 	 * upper bound on the number of columns. We use the number of files
8476ea7f916SThomas Cort 	 * we can open successfully to set the number of columns. The operation
8486ea7f916SThomas Cort 	 * of the merge operation (-m) in relation to unsuccesful file opens
8496ea7f916SThomas Cort 	 * is unspecified by posix.
8506ea7f916SThomas Cort 	 */
8516ea7f916SThomas Cort 	j = 0;
8526ea7f916SThomas Cort 	while (j < clcnt) {
8536ea7f916SThomas Cort 		if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL)
8546ea7f916SThomas Cort 			break;
8556ea7f916SThomas Cort 		if (pgnm && (inskip(fbuf[j], pgnm, lines)))
8566ea7f916SThomas Cort 			fbuf[j] = NULL;
8576ea7f916SThomas Cort 		++j;
8586ea7f916SThomas Cort 	}
8596ea7f916SThomas Cort 
8606ea7f916SThomas Cort 	/*
8616ea7f916SThomas Cort 	 * if no files, exit
8626ea7f916SThomas Cort 	 */
8636ea7f916SThomas Cort 	if (!j)
8646ea7f916SThomas Cort 		goto out;
8656ea7f916SThomas Cort 
8666ea7f916SThomas Cort 	/*
8676ea7f916SThomas Cort 	 * calculate page boundries based on open file count
8686ea7f916SThomas Cort 	 */
8696ea7f916SThomas Cort 	clcnt = j;
8706ea7f916SThomas Cort 	if (nmwd) {
8716ea7f916SThomas Cort 		colwd = (pgwd - clcnt - nmwd)/clcnt;
8726ea7f916SThomas Cort 		pgwd = ((colwd + 1) * clcnt) - nmwd - 2;
8736ea7f916SThomas Cort 	} else {
8746ea7f916SThomas Cort 		colwd = (pgwd + 1 - clcnt)/clcnt;
8756ea7f916SThomas Cort 		pgwd = ((colwd + 1) * clcnt) - 1;
8766ea7f916SThomas Cort 	}
8776ea7f916SThomas Cort 	if (colwd < 1) {
8786ea7f916SThomas Cort 		(void)fprintf(errf,
8796ea7f916SThomas Cort 		  "pr: page width too small for %d columns\n", clcnt);
8806ea7f916SThomas Cort 		goto out;
8816ea7f916SThomas Cort 	}
8826ea7f916SThomas Cort 	actf = clcnt;
8836ea7f916SThomas Cort 	col = colwd + 1;
8846ea7f916SThomas Cort 
8856ea7f916SThomas Cort 	/*
8866ea7f916SThomas Cort 	 * line buffer
8876ea7f916SThomas Cort 	 */
8886ea7f916SThomas Cort 	if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL)
8896ea7f916SThomas Cort 		goto out;
8906ea7f916SThomas Cort 	if (offst) {
8916ea7f916SThomas Cort 		(void)memset(buf, (int)' ', offst);
8926ea7f916SThomas Cort 		(void)memset(hbuf, (int)' ', offst);
8936ea7f916SThomas Cort 	}
8946ea7f916SThomas Cort 	if (pgnm)
8956ea7f916SThomas Cort 		pagecnt = pgnm;
8966ea7f916SThomas Cort 	else
8976ea7f916SThomas Cort 		pagecnt = 1;
8986ea7f916SThomas Cort 	lncnt = 0;
8996ea7f916SThomas Cort 
9006ea7f916SThomas Cort 	/*
9016ea7f916SThomas Cort 	 * continue to loop while any file still has data
9026ea7f916SThomas Cort 	 */
9036ea7f916SThomas Cort 	while (actf > 0) {
9046ea7f916SThomas Cort 		/*
9056ea7f916SThomas Cort 		 * loop by line
9066ea7f916SThomas Cort 		 */
9076ea7f916SThomas Cort 		for (i = 0; i < lines; ++i) {
9086ea7f916SThomas Cort 			ptbf = buf + offst;
9096ea7f916SThomas Cort 			lstdat = ptbf;
9106ea7f916SThomas Cort 			if (nmwd) {
9116ea7f916SThomas Cort 				/*
9126ea7f916SThomas Cort 				 * add line number to line
9136ea7f916SThomas Cort 				 */
9146ea7f916SThomas Cort 				addnum(ptbf, nmwd, ++lncnt);
9156ea7f916SThomas Cort 				ptbf += nmwd;
9166ea7f916SThomas Cort 				*ptbf++ = nmchar;
9176ea7f916SThomas Cort 			}
9186ea7f916SThomas Cort 			j = 0;
9196ea7f916SThomas Cort 			fproc = 0;
9206ea7f916SThomas Cort 
9216ea7f916SThomas Cort 			/*
9226ea7f916SThomas Cort 			 * loop by column
9236ea7f916SThomas Cort 			 */
9246ea7f916SThomas Cort 			for (j = 0; j < clcnt; ++j) {
9256ea7f916SThomas Cort 				if (fbuf[j] == NULL) {
9266ea7f916SThomas Cort 					/*
9276ea7f916SThomas Cort 					 * empty column; EOF
9286ea7f916SThomas Cort 					 */
9296ea7f916SThomas Cort 					cnt = 0;
9306ea7f916SThomas Cort 				} else if ((cnt = inln(fbuf[j], ptbf, colwd,
9316ea7f916SThomas Cort 							&cps, 1, &mor)) < 0) {
9326ea7f916SThomas Cort 					/*
9336ea7f916SThomas Cort 					 * EOF hit; no data
9346ea7f916SThomas Cort 					 */
9356ea7f916SThomas Cort 					if (fbuf[j] != stdin)
9366ea7f916SThomas Cort 						(void)fclose(fbuf[j]);
9376ea7f916SThomas Cort 					fbuf[j] = NULL;
9386ea7f916SThomas Cort 					--actf;
9396ea7f916SThomas Cort 					cnt = 0;
9406ea7f916SThomas Cort 				} else {
9416ea7f916SThomas Cort 					/*
9426ea7f916SThomas Cort 					 * process file data
9436ea7f916SThomas Cort 					 */
9446ea7f916SThomas Cort 					ptbf += cnt;
9456ea7f916SThomas Cort 					lstdat = ptbf;
9466ea7f916SThomas Cort 					fproc++;
9476ea7f916SThomas Cort 				}
9486ea7f916SThomas Cort 
9496ea7f916SThomas Cort 				/*
9506ea7f916SThomas Cort 				 * if last ACTIVE column, done with line
9516ea7f916SThomas Cort 				 */
9526ea7f916SThomas Cort 				if (fproc >= actf)
9536ea7f916SThomas Cort 					break;
9546ea7f916SThomas Cort 
9556ea7f916SThomas Cort 				/*
9566ea7f916SThomas Cort 				 * pad to end of column
9576ea7f916SThomas Cort 				 */
9586ea7f916SThomas Cort 				if (sflag) {
9596ea7f916SThomas Cort 					*ptbf++ = schar;
9606ea7f916SThomas Cort 				} else if ((pln = col - cnt) > 0) {
9616ea7f916SThomas Cort 					(void)memset(ptbf, (int)' ', pln);
9626ea7f916SThomas Cort 					ptbf += pln;
9636ea7f916SThomas Cort 				}
9646ea7f916SThomas Cort 			}
9656ea7f916SThomas Cort 
9666ea7f916SThomas Cort 			/*
9676ea7f916SThomas Cort 			 * calculate data in line
9686ea7f916SThomas Cort 			 */
9696ea7f916SThomas Cort 			if ((j = lstdat - buf) <= offst)
9706ea7f916SThomas Cort 				break;
9716ea7f916SThomas Cort 
9726ea7f916SThomas Cort 			if (!i) {
9736ea7f916SThomas Cort 				if (pgpause)
9746ea7f916SThomas Cort 					prpause(pagecnt);
9756ea7f916SThomas Cort 
9766ea7f916SThomas Cort 			        if (!nohead && prhead(hbuf, fname, pagecnt))
9776ea7f916SThomas Cort 					goto out;
9786ea7f916SThomas Cort 			}
9796ea7f916SThomas Cort 
9806ea7f916SThomas Cort 			/*
9816ea7f916SThomas Cort 			 * output line
9826ea7f916SThomas Cort 			 */
9836ea7f916SThomas Cort 			if (otln(buf, j, &ips, &ops, 0))
9846ea7f916SThomas Cort 				goto out;
9856ea7f916SThomas Cort 
9866ea7f916SThomas Cort 			/*
9876ea7f916SThomas Cort 			 * if no more active files, done
9886ea7f916SThomas Cort 			 */
9896ea7f916SThomas Cort 			if (actf <= 0) {
9906ea7f916SThomas Cort 				++i;
9916ea7f916SThomas Cort 				break;
9926ea7f916SThomas Cort 			}
9936ea7f916SThomas Cort 		}
9946ea7f916SThomas Cort 
9956ea7f916SThomas Cort 		/*
9966ea7f916SThomas Cort 		 * pad to end of page
9976ea7f916SThomas Cort 		 */
9986ea7f916SThomas Cort 		if (i && prtail(lines-i, 0))
9996ea7f916SThomas Cort 			goto out;
10006ea7f916SThomas Cort 		++pagecnt;
10016ea7f916SThomas Cort 	}
10026ea7f916SThomas Cort 	if (eoptind < argc)
10036ea7f916SThomas Cort 		goto out;
10046ea7f916SThomas Cort 	error = 0;
10056ea7f916SThomas Cort 	goto out;
10066ea7f916SThomas Cort oomem:
10076ea7f916SThomas Cort 	mfail();
10086ea7f916SThomas Cort out:
10096ea7f916SThomas Cort 	if (fbuf) {
10106ea7f916SThomas Cort 		for (j = 0; j < clcnt; j++)
10116ea7f916SThomas Cort 			if (fbuf[j] && fbuf[j] != stdin)
10126ea7f916SThomas Cort 				(void)fclose(fbuf[j]);
10136ea7f916SThomas Cort 		free(fbuf);
10146ea7f916SThomas Cort 	}
10156ea7f916SThomas Cort 	free(hbuf);
10166ea7f916SThomas Cort 	free(buf);
10176ea7f916SThomas Cort 	return error;
10186ea7f916SThomas Cort }
10196ea7f916SThomas Cort 
10206ea7f916SThomas Cort /*
10216ea7f916SThomas Cort  * inln():	input a line of data (unlimited length lines supported)
10226ea7f916SThomas Cort  *		Input is optionally expanded to spaces
10236ea7f916SThomas Cort  *
10246ea7f916SThomas Cort  *	inf:	file
10256ea7f916SThomas Cort  *	buf:	buffer
10266ea7f916SThomas Cort  *	lim:	buffer length
10276ea7f916SThomas Cort  *	cps:	column positon 1st char in buffer (large line support)
10286ea7f916SThomas Cort  *	trnc:	throw away data more than lim up to \n
10296ea7f916SThomas Cort  *	mor:	set if more data in line (not truncated)
10306ea7f916SThomas Cort  */
10316ea7f916SThomas Cort static int
inln(FILE * inf,char * buf,int lim,int * cps,int trnc,int * mor)10326ea7f916SThomas Cort inln(FILE *inf, char *buf, int lim, int *cps, int trnc, int *mor)
10336ea7f916SThomas Cort {
10346ea7f916SThomas Cort 	int col;
10356ea7f916SThomas Cort 	int gap = ingap;
10366ea7f916SThomas Cort 	int ch = EOF;
10376ea7f916SThomas Cort 	char *ptbuf;
10386ea7f916SThomas Cort 	int chk = (int)inchar;
10396ea7f916SThomas Cort 
10406ea7f916SThomas Cort 	ptbuf = buf;
10416ea7f916SThomas Cort 
10426ea7f916SThomas Cort 	if (gap) {
10436ea7f916SThomas Cort 		/*
10446ea7f916SThomas Cort 		 * expanding input option
10456ea7f916SThomas Cort 		 */
10466ea7f916SThomas Cort 		while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
10476ea7f916SThomas Cort 			/*
10486ea7f916SThomas Cort 			 * is this the input "tab" char
10496ea7f916SThomas Cort 			 */
10506ea7f916SThomas Cort 			if (ch == chk) {
10516ea7f916SThomas Cort 				/*
10526ea7f916SThomas Cort 				 * expand to number of spaces
10536ea7f916SThomas Cort 				 */
10546ea7f916SThomas Cort 				col = (ptbuf - buf) + *cps;
10556ea7f916SThomas Cort 				col = gap - (col % gap);
10566ea7f916SThomas Cort 
10576ea7f916SThomas Cort 				/*
10586ea7f916SThomas Cort 				 * if more than this line, push back
10596ea7f916SThomas Cort 				 */
10606ea7f916SThomas Cort 				if ((col > lim) && (ungetc(ch, inf) == EOF))
10616ea7f916SThomas Cort 					return(1);
10626ea7f916SThomas Cort 
10636ea7f916SThomas Cort 				/*
10646ea7f916SThomas Cort 				 * expand to spaces
10656ea7f916SThomas Cort 				 */
10666ea7f916SThomas Cort 				while ((--col >= 0) && (--lim >= 0))
10676ea7f916SThomas Cort 					*ptbuf++ = ' ';
10686ea7f916SThomas Cort 				continue;
10696ea7f916SThomas Cort 			}
10706ea7f916SThomas Cort 			if (ch == '\n')
10716ea7f916SThomas Cort 				break;
10726ea7f916SThomas Cort 			*ptbuf++ = ch;
10736ea7f916SThomas Cort 		}
10746ea7f916SThomas Cort 	} else {
10756ea7f916SThomas Cort 		/*
10766ea7f916SThomas Cort 		 * no expansion
10776ea7f916SThomas Cort 		 */
10786ea7f916SThomas Cort 		while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
10796ea7f916SThomas Cort 			if (ch == '\n')
10806ea7f916SThomas Cort 				break;
10816ea7f916SThomas Cort 			*ptbuf++ = ch;
10826ea7f916SThomas Cort 		}
10836ea7f916SThomas Cort 	}
10846ea7f916SThomas Cort 	col = ptbuf - buf;
10856ea7f916SThomas Cort 	if (ch == EOF) {
10866ea7f916SThomas Cort 		*mor = 0;
10876ea7f916SThomas Cort 		*cps = 0;
10886ea7f916SThomas Cort 		if (!col)
10896ea7f916SThomas Cort 			return(-1);
10906ea7f916SThomas Cort 		return(col);
10916ea7f916SThomas Cort 	}
10926ea7f916SThomas Cort 	if (ch == '\n') {
10936ea7f916SThomas Cort 		/*
10946ea7f916SThomas Cort 		 * entire line processed
10956ea7f916SThomas Cort 		 */
10966ea7f916SThomas Cort 		*mor = 0;
10976ea7f916SThomas Cort 		*cps = 0;
10986ea7f916SThomas Cort 		return(col);
10996ea7f916SThomas Cort 	}
11006ea7f916SThomas Cort 
11016ea7f916SThomas Cort 	/*
11026ea7f916SThomas Cort 	 * line was larger than limit
11036ea7f916SThomas Cort 	 */
11046ea7f916SThomas Cort 	if (trnc) {
11056ea7f916SThomas Cort 		/*
11066ea7f916SThomas Cort 		 * throw away rest of line
11076ea7f916SThomas Cort 		 */
11086ea7f916SThomas Cort 		while ((ch = getc(inf)) != EOF) {
11096ea7f916SThomas Cort 			if (ch == '\n')
11106ea7f916SThomas Cort 				break;
11116ea7f916SThomas Cort 		}
11126ea7f916SThomas Cort 		*cps = 0;
11136ea7f916SThomas Cort 		*mor = 0;
11146ea7f916SThomas Cort 	} else {
11156ea7f916SThomas Cort 		/*
11166ea7f916SThomas Cort 		 * save column offset if not truncated
11176ea7f916SThomas Cort 		 */
11186ea7f916SThomas Cort 		*cps += col;
11196ea7f916SThomas Cort 		*mor = 1;
11206ea7f916SThomas Cort 	}
11216ea7f916SThomas Cort 
11226ea7f916SThomas Cort 	return(col);
11236ea7f916SThomas Cort }
11246ea7f916SThomas Cort 
11256ea7f916SThomas Cort /*
11266ea7f916SThomas Cort  * otln():	output a line of data. (Supports unlimited length lines)
11276ea7f916SThomas Cort  *		output is optionally contracted to tabs
11286ea7f916SThomas Cort  *
11296ea7f916SThomas Cort  *	buf:	output buffer with data
11306ea7f916SThomas Cort  *	cnt:	number of chars of valid data in buf
11316ea7f916SThomas Cort  *	svips:	buffer input column position (for large lines)
11326ea7f916SThomas Cort  *	svops:	buffer output column position (for large lines)
11336ea7f916SThomas Cort  *	mor:	output line not complete in this buf; more data to come.
11346ea7f916SThomas Cort  *		1 is more, 0 is complete, -1 is no \n's
11356ea7f916SThomas Cort  */
11366ea7f916SThomas Cort static int
otln(char * buf,int cnt,int * svips,int * svops,int mor)11376ea7f916SThomas Cort otln(char *buf, int cnt, int *svips, int *svops, int mor)
11386ea7f916SThomas Cort {
11396ea7f916SThomas Cort 	int ops;		/* last col output */
11406ea7f916SThomas Cort 	int ips;		/* last col in buf examined */
11416ea7f916SThomas Cort 	int gap = ogap;
11426ea7f916SThomas Cort 	int tbps;
11436ea7f916SThomas Cort 	char *endbuf;
11446ea7f916SThomas Cort 
11456ea7f916SThomas Cort 	if (ogap) {
11466ea7f916SThomas Cort 		/*
11476ea7f916SThomas Cort 		 * contracting on output
11486ea7f916SThomas Cort 		 */
11496ea7f916SThomas Cort 		endbuf = buf + cnt;
11506ea7f916SThomas Cort 		ops = *svops;
11516ea7f916SThomas Cort 		ips = *svips;
11526ea7f916SThomas Cort 		while (buf < endbuf) {
11536ea7f916SThomas Cort 			/*
11546ea7f916SThomas Cort 			 * count number of spaces and ochar in buffer
11556ea7f916SThomas Cort 			 */
11566ea7f916SThomas Cort 			if (*buf == ' ') {
11576ea7f916SThomas Cort 				++ips;
11586ea7f916SThomas Cort 				++buf;
11596ea7f916SThomas Cort 				continue;
11606ea7f916SThomas Cort 			}
11616ea7f916SThomas Cort 
11626ea7f916SThomas Cort 			/*
11636ea7f916SThomas Cort 			 * simulate ochar processing
11646ea7f916SThomas Cort 			 */
11656ea7f916SThomas Cort 			if (*buf == ochar) {
11666ea7f916SThomas Cort 				ips += gap - (ips % gap);
11676ea7f916SThomas Cort 				++buf;
11686ea7f916SThomas Cort 				continue;
11696ea7f916SThomas Cort 			}
11706ea7f916SThomas Cort 
11716ea7f916SThomas Cort 			/*
11726ea7f916SThomas Cort 			 * got a non space char; contract out spaces
11736ea7f916SThomas Cort 			 */
11746ea7f916SThomas Cort 			while (ips - ops > 1) {
11756ea7f916SThomas Cort 				/*
11766ea7f916SThomas Cort 				 * use as many ochar as will fit
11776ea7f916SThomas Cort 				 */
11786ea7f916SThomas Cort 				if ((tbps = ops + gap - (ops % gap)) > ips)
11796ea7f916SThomas Cort 					break;
11806ea7f916SThomas Cort 				if (putchar(ochar) == EOF) {
11816ea7f916SThomas Cort 					pfail();
11826ea7f916SThomas Cort 					return(1);
11836ea7f916SThomas Cort 				}
11846ea7f916SThomas Cort 				ops = tbps;
11856ea7f916SThomas Cort 			}
11866ea7f916SThomas Cort 
11876ea7f916SThomas Cort 			while (ops < ips) {
11886ea7f916SThomas Cort 				/*
11896ea7f916SThomas Cort 				 * finish off with spaces
11906ea7f916SThomas Cort 				 */
11916ea7f916SThomas Cort 				if (putchar(' ') == EOF) {
11926ea7f916SThomas Cort 					pfail();
11936ea7f916SThomas Cort 					return(1);
11946ea7f916SThomas Cort 				}
11956ea7f916SThomas Cort 				++ops;
11966ea7f916SThomas Cort 			}
11976ea7f916SThomas Cort 
11986ea7f916SThomas Cort 			/*
11996ea7f916SThomas Cort 			 * output non space char
12006ea7f916SThomas Cort 			 */
12016ea7f916SThomas Cort 			if (putchar(*buf++) == EOF) {
12026ea7f916SThomas Cort 				pfail();
12036ea7f916SThomas Cort 				return(1);
12046ea7f916SThomas Cort 			}
12056ea7f916SThomas Cort 			++ips;
12066ea7f916SThomas Cort 			++ops;
12076ea7f916SThomas Cort 		}
12086ea7f916SThomas Cort 
12096ea7f916SThomas Cort 		if (mor > 0) {
12106ea7f916SThomas Cort 			/*
12116ea7f916SThomas Cort 			 * if incomplete line, save position counts
12126ea7f916SThomas Cort 			 */
12136ea7f916SThomas Cort 			*svops = ops;
12146ea7f916SThomas Cort 			*svips = ips;
12156ea7f916SThomas Cort 			return(0);
12166ea7f916SThomas Cort 		}
12176ea7f916SThomas Cort 
12186ea7f916SThomas Cort 		if (mor < 0) {
12196ea7f916SThomas Cort 			while (ips - ops > 1) {
12206ea7f916SThomas Cort 				/*
12216ea7f916SThomas Cort 				 * use as many ochar as will fit
12226ea7f916SThomas Cort 				 */
12236ea7f916SThomas Cort 				if ((tbps = ops + gap - (ops % gap)) > ips)
12246ea7f916SThomas Cort 					break;
12256ea7f916SThomas Cort 				if (putchar(ochar) == EOF) {
12266ea7f916SThomas Cort 					pfail();
12276ea7f916SThomas Cort 					return(1);
12286ea7f916SThomas Cort 				}
12296ea7f916SThomas Cort 				ops = tbps;
12306ea7f916SThomas Cort 			}
12316ea7f916SThomas Cort 			while (ops < ips) {
12326ea7f916SThomas Cort 				/*
12336ea7f916SThomas Cort 				 * finish off with spaces
12346ea7f916SThomas Cort 				 */
12356ea7f916SThomas Cort 				if (putchar(' ') == EOF) {
12366ea7f916SThomas Cort 					pfail();
12376ea7f916SThomas Cort 					return(1);
12386ea7f916SThomas Cort 				}
12396ea7f916SThomas Cort 				++ops;
12406ea7f916SThomas Cort 			}
12416ea7f916SThomas Cort 			return(0);
12426ea7f916SThomas Cort 		}
12436ea7f916SThomas Cort 	} else {
12446ea7f916SThomas Cort 		/*
12456ea7f916SThomas Cort 		 * output is not contracted
12466ea7f916SThomas Cort 		 */
12476ea7f916SThomas Cort 		if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) {
12486ea7f916SThomas Cort 			pfail();
12496ea7f916SThomas Cort 			return(1);
12506ea7f916SThomas Cort 		}
12516ea7f916SThomas Cort 		if (mor != 0)
12526ea7f916SThomas Cort 			return(0);
12536ea7f916SThomas Cort 	}
12546ea7f916SThomas Cort 
12556ea7f916SThomas Cort 	/*
12566ea7f916SThomas Cort 	 * process line end and double space as required
12576ea7f916SThomas Cort 	 */
12586ea7f916SThomas Cort 	if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) {
12596ea7f916SThomas Cort 		pfail();
12606ea7f916SThomas Cort 		return(1);
12616ea7f916SThomas Cort 	}
12626ea7f916SThomas Cort 	return(0);
12636ea7f916SThomas Cort }
12646ea7f916SThomas Cort 
12656ea7f916SThomas Cort /*
12666ea7f916SThomas Cort  * inskip():	skip over pgcnt pages with lncnt lines per page
12676ea7f916SThomas Cort  *		file is closed at EOF (if not stdin).
12686ea7f916SThomas Cort  *
12696ea7f916SThomas Cort  *	inf	FILE * to read from
12706ea7f916SThomas Cort  *	pgcnt	number of pages to skip
12716ea7f916SThomas Cort  *	lncnt	number of lines per page
12726ea7f916SThomas Cort  */
12736ea7f916SThomas Cort static int
inskip(FILE * inf,int pgcnt,int lncnt)12746ea7f916SThomas Cort inskip(FILE *inf, int pgcnt, int lncnt)
12756ea7f916SThomas Cort {
12766ea7f916SThomas Cort 	int c;
12776ea7f916SThomas Cort 	int cnt;
12786ea7f916SThomas Cort 
12796ea7f916SThomas Cort 	while(--pgcnt > 0) {
12806ea7f916SThomas Cort 		cnt = lncnt;
12816ea7f916SThomas Cort 		while ((c = getc(inf)) != EOF) {
12826ea7f916SThomas Cort 			if ((c == '\n') && (--cnt == 0))
12836ea7f916SThomas Cort 				break;
12846ea7f916SThomas Cort 		}
12856ea7f916SThomas Cort 		if (c == EOF) {
12866ea7f916SThomas Cort 			if (inf != stdin)
12876ea7f916SThomas Cort 				(void)fclose(inf);
12886ea7f916SThomas Cort 			return(1);
12896ea7f916SThomas Cort 		}
12906ea7f916SThomas Cort 	}
12916ea7f916SThomas Cort 	return(0);
12926ea7f916SThomas Cort }
12936ea7f916SThomas Cort 
12946ea7f916SThomas Cort /*
12956ea7f916SThomas Cort  * nxtfile:	returns a FILE * to next file in arg list and sets the
12966ea7f916SThomas Cort  *		time field for this file (or current date).
12976ea7f916SThomas Cort  *
12986ea7f916SThomas Cort  *	buf	array to store proper date for the header.
12996ea7f916SThomas Cort  *	dt	if set skips the date processing (used with -m)
13006ea7f916SThomas Cort  */
13016ea7f916SThomas Cort static FILE *
nxtfile(int argc,char ** argv,const char ** fname,char * buf,int dt)13026ea7f916SThomas Cort nxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
13036ea7f916SThomas Cort {
13046ea7f916SThomas Cort 	FILE *inf = NULL;
13056ea7f916SThomas Cort 	struct timeval tv;
13066ea7f916SThomas Cort 	struct timezone tz;
13076ea7f916SThomas Cort 	struct tm *timeptr = NULL;
13086ea7f916SThomas Cort 	struct stat statbuf;
13096ea7f916SThomas Cort 	time_t curtime;
13106ea7f916SThomas Cort 	static int twice = -1;
13116ea7f916SThomas Cort 
13126ea7f916SThomas Cort 	++twice;
13136ea7f916SThomas Cort 	if (eoptind >= argc) {
13146ea7f916SThomas Cort 		/*
13156ea7f916SThomas Cort 		 * no file listed; default, use standard input
13166ea7f916SThomas Cort 		 */
13176ea7f916SThomas Cort 		if (twice)
13186ea7f916SThomas Cort 			return(NULL);
13196ea7f916SThomas Cort 		clearerr(stdin);
13206ea7f916SThomas Cort 		inf = stdin;
13216ea7f916SThomas Cort 		if (header != NULL)
13226ea7f916SThomas Cort 			*fname = header;
13236ea7f916SThomas Cort 		else
13246ea7f916SThomas Cort 			*fname = FNAME;
13256ea7f916SThomas Cort 		if (nohead)
13266ea7f916SThomas Cort 			return(inf);
13276ea7f916SThomas Cort 		if (gettimeofday(&tv, &tz) < 0) {
13286ea7f916SThomas Cort 			++errcnt;
13296ea7f916SThomas Cort 			(void)fprintf(errf, "pr: cannot get time of day, %s\n",
13306ea7f916SThomas Cort 				strerror(errno));
13316ea7f916SThomas Cort 			eoptind = argc - 1;
13326ea7f916SThomas Cort 			return(NULL);
13336ea7f916SThomas Cort 		}
13346ea7f916SThomas Cort 		curtime = tv.tv_sec;
13356ea7f916SThomas Cort 		timeptr = localtime(&curtime);
13366ea7f916SThomas Cort 	}
13376ea7f916SThomas Cort 	for (; eoptind < argc; ++eoptind) {
13386ea7f916SThomas Cort 		if (strcmp(argv[eoptind], "-") == 0) {
13396ea7f916SThomas Cort 			/*
13406ea7f916SThomas Cort 			 * process a "-" for filename
13416ea7f916SThomas Cort 			 */
13426ea7f916SThomas Cort 			clearerr(stdin);
13436ea7f916SThomas Cort 			inf = stdin;
13446ea7f916SThomas Cort 			if (header != NULL)
13456ea7f916SThomas Cort 				*fname = header;
13466ea7f916SThomas Cort 			else
13476ea7f916SThomas Cort 				*fname = FNAME;
13486ea7f916SThomas Cort 			++eoptind;
13496ea7f916SThomas Cort 			if (nohead || (dt && twice))
13506ea7f916SThomas Cort 				return(inf);
13516ea7f916SThomas Cort 			if (gettimeofday(&tv, &tz) < 0) {
13526ea7f916SThomas Cort 				++errcnt;
13536ea7f916SThomas Cort 				(void)fprintf(errf,
13546ea7f916SThomas Cort 					"pr: cannot get time of day, %s\n",
13556ea7f916SThomas Cort 					strerror(errno));
13566ea7f916SThomas Cort 				return(NULL);
13576ea7f916SThomas Cort 			}
13586ea7f916SThomas Cort 			curtime = tv.tv_sec;
13596ea7f916SThomas Cort 			timeptr = localtime(&curtime);
13606ea7f916SThomas Cort 		} else {
13616ea7f916SThomas Cort 			/*
13626ea7f916SThomas Cort 			 * normal file processing
13636ea7f916SThomas Cort 			 */
13646ea7f916SThomas Cort 			if ((inf = fopen(argv[eoptind], "r")) == NULL) {
13656ea7f916SThomas Cort 				++errcnt;
13666ea7f916SThomas Cort 				if (nodiag)
13676ea7f916SThomas Cort 					continue;
13686ea7f916SThomas Cort 				(void)fprintf(errf, "pr: Cannot open %s, %s\n",
13696ea7f916SThomas Cort 					argv[eoptind], strerror(errno));
13706ea7f916SThomas Cort 				continue;
13716ea7f916SThomas Cort 			}
13726ea7f916SThomas Cort 			if (header != NULL)
13736ea7f916SThomas Cort 				*fname = header;
13746ea7f916SThomas Cort 			else if (dt)
13756ea7f916SThomas Cort 				*fname = FNAME;
13766ea7f916SThomas Cort 			else
13776ea7f916SThomas Cort 				*fname = argv[eoptind];
13786ea7f916SThomas Cort 			++eoptind;
13796ea7f916SThomas Cort 			if (nohead || (dt && twice))
13806ea7f916SThomas Cort 				return(inf);
13816ea7f916SThomas Cort 
13826ea7f916SThomas Cort 			if (dt) {
13836ea7f916SThomas Cort 				if (gettimeofday(&tv, &tz) < 0) {
13846ea7f916SThomas Cort 					++errcnt;
13856ea7f916SThomas Cort 					(void)fprintf(errf,
13866ea7f916SThomas Cort 					     "pr: cannot get time of day, %s\n",
13876ea7f916SThomas Cort 					     strerror(errno));
13886ea7f916SThomas Cort 					return(NULL);
13896ea7f916SThomas Cort 				}
13906ea7f916SThomas Cort 				curtime = tv.tv_sec;
13916ea7f916SThomas Cort 				timeptr = localtime(&curtime);
13926ea7f916SThomas Cort 			} else {
13936ea7f916SThomas Cort 				if (fstat(fileno(inf), &statbuf) < 0) {
13946ea7f916SThomas Cort 					++errcnt;
13956ea7f916SThomas Cort 					(void)fclose(inf);
13966ea7f916SThomas Cort 					(void)fprintf(errf,
13976ea7f916SThomas Cort 						"pr: Cannot stat %s, %s\n",
13986ea7f916SThomas Cort 						argv[eoptind], strerror(errno));
13996ea7f916SThomas Cort 					return(NULL);
14006ea7f916SThomas Cort 				}
14016ea7f916SThomas Cort 				timeptr = localtime(&(statbuf.st_mtime));
14026ea7f916SThomas Cort 			}
14036ea7f916SThomas Cort 		}
14046ea7f916SThomas Cort 		break;
14056ea7f916SThomas Cort 	}
14066ea7f916SThomas Cort 	if (inf == NULL)
14076ea7f916SThomas Cort 		return(NULL);
14086ea7f916SThomas Cort 
14096ea7f916SThomas Cort 	/*
14106ea7f916SThomas Cort 	 * set up time field used in header
14116ea7f916SThomas Cort 	 */
14126ea7f916SThomas Cort 	if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) {
14136ea7f916SThomas Cort 		++errcnt;
14146ea7f916SThomas Cort 		if (inf != stdin)
14156ea7f916SThomas Cort 			(void)fclose(inf);
14166ea7f916SThomas Cort 		(void)fputs("pr: time conversion failed\n", errf);
14176ea7f916SThomas Cort 		return(NULL);
14186ea7f916SThomas Cort 	}
14196ea7f916SThomas Cort 	return(inf);
14206ea7f916SThomas Cort }
14216ea7f916SThomas Cort 
14226ea7f916SThomas Cort /*
14236ea7f916SThomas Cort  * addnum():	adds the line number to the column
14246ea7f916SThomas Cort  *		Truncates from the front or pads with spaces as required.
14256ea7f916SThomas Cort  *		Numbers are right justified.
14266ea7f916SThomas Cort  *
14276ea7f916SThomas Cort  *	buf	buffer to store the number
14286ea7f916SThomas Cort  *	wdth	width of buffer to fill
14296ea7f916SThomas Cort  *	line	line number
14306ea7f916SThomas Cort  *
14316ea7f916SThomas Cort  *		NOTE: numbers occupy part of the column. The posix
14326ea7f916SThomas Cort  *		spec does not specify if -i processing should or should not
14336ea7f916SThomas Cort  *		occur on number padding. The spec does say it occupies
14346ea7f916SThomas Cort  *		part of the column. The usage of addnum	currently treats
14356ea7f916SThomas Cort  *		numbers as part of the column so spaces may be replaced.
14366ea7f916SThomas Cort  */
14376ea7f916SThomas Cort void
addnum(char * buf,int wdth,int line)14386ea7f916SThomas Cort addnum(char *buf, int wdth, int line)
14396ea7f916SThomas Cort {
14406ea7f916SThomas Cort 	char *pt = buf + wdth;
14416ea7f916SThomas Cort 
14426ea7f916SThomas Cort 	do {
14436ea7f916SThomas Cort 		*--pt = digs[line % 10];
14446ea7f916SThomas Cort 		line /= 10;
14456ea7f916SThomas Cort 	} while (line && (pt > buf));
14466ea7f916SThomas Cort 
14476ea7f916SThomas Cort 	/*
14486ea7f916SThomas Cort 	 * pad with space as required
14496ea7f916SThomas Cort 	 */
14506ea7f916SThomas Cort 	while (pt > buf)
14516ea7f916SThomas Cort 		*--pt = ' ';
14526ea7f916SThomas Cort }
14536ea7f916SThomas Cort 
14546ea7f916SThomas Cort /*
14556ea7f916SThomas Cort  * prpause():	pause before printing each page
14566ea7f916SThomas Cort  *
14576ea7f916SThomas Cort  *	pagcnt	page number
14586ea7f916SThomas Cort  */
14596ea7f916SThomas Cort static void
prpause(int pagcnt)14606ea7f916SThomas Cort prpause(int pagcnt)
14616ea7f916SThomas Cort {
14626ea7f916SThomas Cort 
14636ea7f916SThomas Cort 	if (ttyout) {
14646ea7f916SThomas Cort 		int c;
14656ea7f916SThomas Cort 
14666ea7f916SThomas Cort 		(void)putc('\a', stderr);
14676ea7f916SThomas Cort 		(void)fflush(stderr);
14686ea7f916SThomas Cort 
14696ea7f916SThomas Cort 		while ((c = getc(ttyinf)) != '\n' && c != EOF)
14706ea7f916SThomas Cort 			;
14716ea7f916SThomas Cort 
14726ea7f916SThomas Cort 		/*
14736ea7f916SThomas Cort 		 * pause ONLY before first page of first file
14746ea7f916SThomas Cort 		 */
14756ea7f916SThomas Cort 		if (pgpause == FIRSTPAGE && pagcnt == 1)
14766ea7f916SThomas Cort 			pgpause = NO_PAUSE;
14776ea7f916SThomas Cort 	}
14786ea7f916SThomas Cort }
14796ea7f916SThomas Cort 
14806ea7f916SThomas Cort /*
14816ea7f916SThomas Cort  * prhead():	prints the top of page header
14826ea7f916SThomas Cort  *
14836ea7f916SThomas Cort  *	buf	buffer with time field (and offset)
14846ea7f916SThomas Cort  *	cnt	number of chars in buf
14856ea7f916SThomas Cort  *	fname	fname field for header
14866ea7f916SThomas Cort  *	pagcnt	page number
14876ea7f916SThomas Cort  */
14886ea7f916SThomas Cort static int
prhead(char * buf,const char * fname,int pagcnt)14896ea7f916SThomas Cort prhead(char *buf, const char *fname, int pagcnt)
14906ea7f916SThomas Cort {
14916ea7f916SThomas Cort 	int ips = 0;
14926ea7f916SThomas Cort 	int ops = 0;
14936ea7f916SThomas Cort 
14946ea7f916SThomas Cort 	if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) {
14956ea7f916SThomas Cort 		pfail();
14966ea7f916SThomas Cort 		return(1);
14976ea7f916SThomas Cort 	}
14986ea7f916SThomas Cort 	/*
14996ea7f916SThomas Cort 	 * posix is not clear if the header is subject to line length
15006ea7f916SThomas Cort 	 * restrictions. The specification for header line format
15016ea7f916SThomas Cort 	 * in the spec clearly does not limit length. No pr currently
15026ea7f916SThomas Cort 	 * restricts header length. However if we need to truncate in
15036ea7f916SThomas Cort 	 * an reasonable way, adjust the length of the printf by
15046ea7f916SThomas Cort 	 * changing HDFMT to allow a length max as an argument printf.
15056ea7f916SThomas Cort 	 * buf (which contains the offset spaces and time field could
15066ea7f916SThomas Cort 	 * also be trimmed
15076ea7f916SThomas Cort 	 *
15086ea7f916SThomas Cort 	 * note only the offset (if any) is processed for tab expansion
15096ea7f916SThomas Cort 	 */
15106ea7f916SThomas Cort 	if (offst && otln(buf, offst, &ips, &ops, -1))
15116ea7f916SThomas Cort 		return(1);
15126ea7f916SThomas Cort 	(void)printf(HDFMT,buf+offst, fname, pagcnt);
15136ea7f916SThomas Cort 	return(0);
15146ea7f916SThomas Cort }
15156ea7f916SThomas Cort 
15166ea7f916SThomas Cort /*
15176ea7f916SThomas Cort  * prtail():	pad page with empty lines (if required) and print page trailer
15186ea7f916SThomas Cort  *		if requested
15196ea7f916SThomas Cort  *
15206ea7f916SThomas Cort  *	cnt	number of lines of padding needed
15216ea7f916SThomas Cort  *	incomp	was a '\n' missing from last line output
15226ea7f916SThomas Cort  */
15236ea7f916SThomas Cort static int
prtail(int cnt,int incomp)15246ea7f916SThomas Cort prtail(int cnt, int incomp)
15256ea7f916SThomas Cort {
15266ea7f916SThomas Cort 	if (nohead) {
15276ea7f916SThomas Cort 		/*
15286ea7f916SThomas Cort 		 * only pad with no headers when incomplete last line
15296ea7f916SThomas Cort 		 */
15306ea7f916SThomas Cort 		if (!incomp)
15316ea7f916SThomas Cort 			return(0);
15326ea7f916SThomas Cort 		if ((dspace && (putchar('\n') == EOF)) ||
15336ea7f916SThomas Cort 		    (putchar('\n') == EOF)) {
15346ea7f916SThomas Cort 			pfail();
15356ea7f916SThomas Cort 			return(1);
15366ea7f916SThomas Cort 		}
15376ea7f916SThomas Cort 		return(0);
15386ea7f916SThomas Cort 	}
15396ea7f916SThomas Cort 
15406ea7f916SThomas Cort 	/*
15416ea7f916SThomas Cort 	 * if double space output two \n
15426ea7f916SThomas Cort 	 */
15436ea7f916SThomas Cort 	if (dspace)
15446ea7f916SThomas Cort 		cnt *= 2;
15456ea7f916SThomas Cort 
15466ea7f916SThomas Cort 	/*
15476ea7f916SThomas Cort 	 * if an odd number of lines per page, add an extra \n
15486ea7f916SThomas Cort 	 */
15496ea7f916SThomas Cort 	if (addone)
15506ea7f916SThomas Cort 		++cnt;
15516ea7f916SThomas Cort 
15526ea7f916SThomas Cort 	/*
15536ea7f916SThomas Cort 	 * pad page
15546ea7f916SThomas Cort 	 */
15556ea7f916SThomas Cort 	if (formfeed) {
15566ea7f916SThomas Cort 		if ((incomp && (putchar('\n') == EOF)) ||
15576ea7f916SThomas Cort 		    (putchar('\f') == EOF)) {
15586ea7f916SThomas Cort 			pfail();
15596ea7f916SThomas Cort 			return(1);
15606ea7f916SThomas Cort 		}
15616ea7f916SThomas Cort 		return(0);
15626ea7f916SThomas Cort 	}
15636ea7f916SThomas Cort 	cnt += TAILLEN;
15646ea7f916SThomas Cort 	while (--cnt >= 0) {
15656ea7f916SThomas Cort 		if (putchar('\n') == EOF) {
15666ea7f916SThomas Cort 			pfail();
15676ea7f916SThomas Cort 			return(1);
15686ea7f916SThomas Cort 		}
15696ea7f916SThomas Cort 	}
15706ea7f916SThomas Cort 	return(0);
15716ea7f916SThomas Cort }
15726ea7f916SThomas Cort 
15736ea7f916SThomas Cort /*
15746ea7f916SThomas Cort  * terminate():	when a SIGINT is recvd
15756ea7f916SThomas Cort  */
15766ea7f916SThomas Cort static void
terminate(int which_sig)15776ea7f916SThomas Cort terminate(int which_sig)
15786ea7f916SThomas Cort {
15796ea7f916SThomas Cort 	flsh_errs();
15806ea7f916SThomas Cort 	(void)raise_default_signal(which_sig);
15816ea7f916SThomas Cort 	exit(1);
15826ea7f916SThomas Cort }
15836ea7f916SThomas Cort 
15846ea7f916SThomas Cort 
15856ea7f916SThomas Cort /*
15866ea7f916SThomas Cort  * flsh_errs():	output saved up diagnostic messages after all normal
15876ea7f916SThomas Cort  *		processing has completed
15886ea7f916SThomas Cort  */
15896ea7f916SThomas Cort static void
flsh_errs(void)15906ea7f916SThomas Cort flsh_errs(void)
15916ea7f916SThomas Cort {
15926ea7f916SThomas Cort 	char buf[BUFSIZ];
15936ea7f916SThomas Cort 
15946ea7f916SThomas Cort 	(void)fflush(stdout);
15956ea7f916SThomas Cort 	(void)fflush(errf);
15966ea7f916SThomas Cort 	if (errf == stderr)
15976ea7f916SThomas Cort 		return;
15986ea7f916SThomas Cort 	rewind(errf);
15996ea7f916SThomas Cort 	while (fgets(buf, BUFSIZ, errf) != NULL)
16006ea7f916SThomas Cort 		(void)fputs(buf, stderr);
16016ea7f916SThomas Cort }
16026ea7f916SThomas Cort 
16036ea7f916SThomas Cort static void
mfail(void)16046ea7f916SThomas Cort mfail(void)
16056ea7f916SThomas Cort {
16066ea7f916SThomas Cort 	(void)fputs("pr: memory allocation failed\n", errf);
16076ea7f916SThomas Cort }
16086ea7f916SThomas Cort 
16096ea7f916SThomas Cort static void
pfail(void)16106ea7f916SThomas Cort pfail(void)
16116ea7f916SThomas Cort {
16126ea7f916SThomas Cort 	(void)fprintf(errf, "pr: write failure, %s\n", strerror(errno));
16136ea7f916SThomas Cort }
16146ea7f916SThomas Cort 
16156ea7f916SThomas Cort static void
usage(void)16166ea7f916SThomas Cort usage(void)
16176ea7f916SThomas Cort {
16186ea7f916SThomas Cort 	(void)fputs(
16196ea7f916SThomas Cort 	 "usage: pr [+page] [-col] [-adFfmprt] [-e[ch][gap]] [-h header]\n",
16206ea7f916SThomas Cort 		    errf);
16216ea7f916SThomas Cort 	(void)fputs(
16226ea7f916SThomas Cort 	 "          [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",
16236ea7f916SThomas Cort 		    errf);
16246ea7f916SThomas Cort 	(void)fputs(
16256ea7f916SThomas Cort 	 "          [-s[ch]] [-T timefmt] [-w width] [-] [file ...]\n",
16266ea7f916SThomas Cort 		    errf);
16276ea7f916SThomas Cort }
16286ea7f916SThomas Cort 
16296ea7f916SThomas Cort /*
16306ea7f916SThomas Cort  * setup:	Validate command args, initialize and perform sanity
16316ea7f916SThomas Cort  *		checks on options
16326ea7f916SThomas Cort  */
16336ea7f916SThomas Cort static int
setup(int argc,char ** argv)16346ea7f916SThomas Cort setup(int argc, char **argv)
16356ea7f916SThomas Cort {
16366ea7f916SThomas Cort 	int c;
16376ea7f916SThomas Cort 	int eflag = 0;
16386ea7f916SThomas Cort 	int iflag = 0;
16396ea7f916SThomas Cort 	int wflag = 0;
16406ea7f916SThomas Cort 	int cflag = 0;
16416ea7f916SThomas Cort 
16426ea7f916SThomas Cort 	ttyinf = stdin;
16436ea7f916SThomas Cort 
16446ea7f916SThomas Cort 	if (isatty(fileno(stdout))) {
16456ea7f916SThomas Cort 		/*
16466ea7f916SThomas Cort 		 * defer diagnostics until processing is done
16476ea7f916SThomas Cort 		 */
16486ea7f916SThomas Cort 		if ((errf = tmpfile()) == NULL) {
16496ea7f916SThomas Cort 		       (void)fputs("Cannot defer diagnostic messages\n",stderr);
16506ea7f916SThomas Cort 		       return(1);
16516ea7f916SThomas Cort 		}
16526ea7f916SThomas Cort 		ttyout = 1;
16536ea7f916SThomas Cort 	} else
16546ea7f916SThomas Cort 		errf = stderr;
16556ea7f916SThomas Cort 	while ((c = egetopt(argc, argv, "#adFfmrte?h:i?l:n?o:ps?T:w:")) != -1) {
16566ea7f916SThomas Cort 		switch (c) {
16576ea7f916SThomas Cort 		case '+':
16586ea7f916SThomas Cort 			if ((pgnm = atoi(eoptarg)) < 1) {
16596ea7f916SThomas Cort 			    (void)fputs("pr: +page number must be 1 or more\n",
16606ea7f916SThomas Cort 				errf);
16616ea7f916SThomas Cort 			    return(1);
16626ea7f916SThomas Cort 			}
16636ea7f916SThomas Cort 			break;
16646ea7f916SThomas Cort 		case '-':
16656ea7f916SThomas Cort 			if ((clcnt = atoi(eoptarg)) < 1) {
16666ea7f916SThomas Cort 			    (void)fputs("pr: -columns must be 1 or more\n",errf);
16676ea7f916SThomas Cort 			    return(1);
16686ea7f916SThomas Cort 			}
16696ea7f916SThomas Cort 			if (clcnt > 1)
16706ea7f916SThomas Cort 				++cflag;
16716ea7f916SThomas Cort 			break;
16726ea7f916SThomas Cort 		case 'a':
16736ea7f916SThomas Cort 			++across;
16746ea7f916SThomas Cort 			break;
16756ea7f916SThomas Cort 		case 'd':
16766ea7f916SThomas Cort 			++dspace;
16776ea7f916SThomas Cort 			break;
16786ea7f916SThomas Cort 		case 'e':
16796ea7f916SThomas Cort 			++eflag;
16806ea7f916SThomas Cort 			if ((eoptarg != NULL) &&
16816ea7f916SThomas Cort 			    !isdigit((unsigned char)*eoptarg))
16826ea7f916SThomas Cort 				inchar = *eoptarg++;
16836ea7f916SThomas Cort 			else
16846ea7f916SThomas Cort 				inchar = INCHAR;
16856ea7f916SThomas Cort 			if ((eoptarg != NULL) &&
16866ea7f916SThomas Cort 			    isdigit((unsigned char)*eoptarg)) {
16876ea7f916SThomas Cort 				if ((ingap = atoi(eoptarg)) < 0) {
16886ea7f916SThomas Cort 					(void)fputs(
16896ea7f916SThomas Cort 					"pr: -e gap must be 0 or more\n", errf);
16906ea7f916SThomas Cort 					return(1);
16916ea7f916SThomas Cort 				}
16926ea7f916SThomas Cort 				if (ingap == 0)
16936ea7f916SThomas Cort 					ingap = INGAP;
16946ea7f916SThomas Cort 			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
16956ea7f916SThomas Cort 				(void)fprintf(errf,
16966ea7f916SThomas Cort 				      "pr: invalid value for -e %s\n", eoptarg);
16976ea7f916SThomas Cort 				return(1);
16986ea7f916SThomas Cort 			} else
16996ea7f916SThomas Cort 				ingap = INGAP;
17006ea7f916SThomas Cort 			break;
17016ea7f916SThomas Cort 		case 'f':
17026ea7f916SThomas Cort 			pgpause |= FIRSTPAGE;
17036ea7f916SThomas Cort 			/*FALLTHROUGH*/
17046ea7f916SThomas Cort 		case 'F':
17056ea7f916SThomas Cort 			++formfeed;
17066ea7f916SThomas Cort 			break;
17076ea7f916SThomas Cort 		case 'h':
17086ea7f916SThomas Cort 			header = eoptarg;
17096ea7f916SThomas Cort 			break;
17106ea7f916SThomas Cort 		case 'i':
17116ea7f916SThomas Cort 			++iflag;
17126ea7f916SThomas Cort 			if ((eoptarg != NULL) &&
17136ea7f916SThomas Cort 			    !isdigit((unsigned char)*eoptarg))
17146ea7f916SThomas Cort 				ochar = *eoptarg++;
17156ea7f916SThomas Cort 			else
17166ea7f916SThomas Cort 				ochar = OCHAR;
17176ea7f916SThomas Cort 			if ((eoptarg != NULL) &&
17186ea7f916SThomas Cort 			    isdigit((unsigned char)*eoptarg)) {
17196ea7f916SThomas Cort 				if ((ogap = atoi(eoptarg)) < 0) {
17206ea7f916SThomas Cort 					(void)fputs(
17216ea7f916SThomas Cort 					"pr: -i gap must be 0 or more\n", errf);
17226ea7f916SThomas Cort 					return(1);
17236ea7f916SThomas Cort 				}
17246ea7f916SThomas Cort 				if (ogap == 0)
17256ea7f916SThomas Cort 					ogap = OGAP;
17266ea7f916SThomas Cort 			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
17276ea7f916SThomas Cort 				(void)fprintf(errf,
17286ea7f916SThomas Cort 				      "pr: invalid value for -i %s\n", eoptarg);
17296ea7f916SThomas Cort 				return(1);
17306ea7f916SThomas Cort 			} else
17316ea7f916SThomas Cort 				ogap = OGAP;
17326ea7f916SThomas Cort 			break;
17336ea7f916SThomas Cort 		case 'l':
17346ea7f916SThomas Cort 			if (!isdigit((unsigned char)*eoptarg) ||
17356ea7f916SThomas Cort 			    ((lines=atoi(eoptarg)) < 1)) {
17366ea7f916SThomas Cort 				(void)fputs(
17376ea7f916SThomas Cort 				 "pr: Number of lines must be 1 or more\n",errf);
17386ea7f916SThomas Cort 				return(1);
17396ea7f916SThomas Cort 			}
17406ea7f916SThomas Cort 			break;
17416ea7f916SThomas Cort 		case 'm':
17426ea7f916SThomas Cort 			++merge;
17436ea7f916SThomas Cort 			break;
17446ea7f916SThomas Cort 		case 'n':
17456ea7f916SThomas Cort 			if ((eoptarg != NULL) &&
17466ea7f916SThomas Cort 			    !isdigit((unsigned char)*eoptarg))
17476ea7f916SThomas Cort 				nmchar = *eoptarg++;
17486ea7f916SThomas Cort 			else
17496ea7f916SThomas Cort 				nmchar = NMCHAR;
17506ea7f916SThomas Cort 			if ((eoptarg != NULL) &&
17516ea7f916SThomas Cort 			    isdigit((unsigned char)*eoptarg)) {
17526ea7f916SThomas Cort 				if ((nmwd = atoi(eoptarg)) < 1) {
17536ea7f916SThomas Cort 					(void)fputs(
17546ea7f916SThomas Cort 					"pr: -n width must be 1 or more\n",errf);
17556ea7f916SThomas Cort 					return(1);
17566ea7f916SThomas Cort 				}
17576ea7f916SThomas Cort 			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
17586ea7f916SThomas Cort 				(void)fprintf(errf,
17596ea7f916SThomas Cort 				      "pr: invalid value for -n %s\n", eoptarg);
17606ea7f916SThomas Cort 				return(1);
17616ea7f916SThomas Cort 			} else
17626ea7f916SThomas Cort 				nmwd = NMWD;
17636ea7f916SThomas Cort 			break;
17646ea7f916SThomas Cort 		case 'o':
17656ea7f916SThomas Cort 			if (!isdigit((unsigned char)*eoptarg) ||
17666ea7f916SThomas Cort 			    ((offst = atoi(eoptarg))< 1)){
17676ea7f916SThomas Cort 				(void)fputs("pr: -o offset must be 1 or more\n",
17686ea7f916SThomas Cort 					errf);
17696ea7f916SThomas Cort 				return(1);
17706ea7f916SThomas Cort 			}
17716ea7f916SThomas Cort 			break;
17726ea7f916SThomas Cort 		case 'p':
17736ea7f916SThomas Cort 			pgpause |= EACHPAGE;
17746ea7f916SThomas Cort 			break;
17756ea7f916SThomas Cort 		case 'r':
17766ea7f916SThomas Cort 			++nodiag;
17776ea7f916SThomas Cort 			break;
17786ea7f916SThomas Cort 		case 's':
17796ea7f916SThomas Cort 			++sflag;
17806ea7f916SThomas Cort 			if (eoptarg == NULL)
17816ea7f916SThomas Cort 				schar = SCHAR;
17826ea7f916SThomas Cort 			else
17836ea7f916SThomas Cort 				schar = *eoptarg++;
17846ea7f916SThomas Cort 			if (eoptarg && *eoptarg != '\0') {
17856ea7f916SThomas Cort 				(void)fprintf(errf,
17866ea7f916SThomas Cort 				      "pr: invalid value for -s %s\n", eoptarg);
17876ea7f916SThomas Cort 				return(1);
17886ea7f916SThomas Cort 			}
17896ea7f916SThomas Cort 			break;
17906ea7f916SThomas Cort 		case 'T':
17916ea7f916SThomas Cort 			timefrmt = eoptarg;
17926ea7f916SThomas Cort 			break;
17936ea7f916SThomas Cort 		case 't':
17946ea7f916SThomas Cort 			++nohead;
17956ea7f916SThomas Cort 			break;
17966ea7f916SThomas Cort 		case 'w':
17976ea7f916SThomas Cort 			++wflag;
17986ea7f916SThomas Cort 			if (!isdigit((unsigned char)*eoptarg) ||
17996ea7f916SThomas Cort 			    ((pgwd = atoi(eoptarg)) < 1)){
18006ea7f916SThomas Cort 				(void)fputs(
18016ea7f916SThomas Cort 				   "pr: -w width must be 1 or more \n",errf);
18026ea7f916SThomas Cort 				return(1);
18036ea7f916SThomas Cort 			}
18046ea7f916SThomas Cort 			break;
18056ea7f916SThomas Cort 		case '?':
18066ea7f916SThomas Cort 		default:
18076ea7f916SThomas Cort 			return(1);
18086ea7f916SThomas Cort 		}
18096ea7f916SThomas Cort 	}
18106ea7f916SThomas Cort 
18116ea7f916SThomas Cort 	/*
18126ea7f916SThomas Cort 	 * default and sanity checks
18136ea7f916SThomas Cort 	 */
18146ea7f916SThomas Cort 	if (!clcnt) {
18156ea7f916SThomas Cort 		if (merge) {
18166ea7f916SThomas Cort 			if ((clcnt = argc - eoptind) <= 1) {
18176ea7f916SThomas Cort 				clcnt = CLCNT;
18186ea7f916SThomas Cort 				merge = 0;
18196ea7f916SThomas Cort 			}
18206ea7f916SThomas Cort 		} else
18216ea7f916SThomas Cort 			clcnt = CLCNT;
18226ea7f916SThomas Cort 	}
18236ea7f916SThomas Cort 	if (across) {
18246ea7f916SThomas Cort 		if (clcnt == 1) {
18256ea7f916SThomas Cort 			(void)fputs("pr: -a flag requires multiple columns\n",
18266ea7f916SThomas Cort 				errf);
18276ea7f916SThomas Cort 			return(1);
18286ea7f916SThomas Cort 		}
18296ea7f916SThomas Cort 		if (merge) {
18306ea7f916SThomas Cort 			(void)fputs("pr: -m cannot be used with -a\n", errf);
18316ea7f916SThomas Cort 			return(1);
18326ea7f916SThomas Cort 		}
18336ea7f916SThomas Cort 	}
18346ea7f916SThomas Cort 	if (!wflag) {
18356ea7f916SThomas Cort 		if (sflag)
18366ea7f916SThomas Cort 			pgwd = SPGWD;
18376ea7f916SThomas Cort 		else
18386ea7f916SThomas Cort 			pgwd = PGWD;
18396ea7f916SThomas Cort 	}
18406ea7f916SThomas Cort 	if (cflag || merge) {
18416ea7f916SThomas Cort 		if (!eflag) {
18426ea7f916SThomas Cort 			inchar = INCHAR;
18436ea7f916SThomas Cort 			ingap = INGAP;
18446ea7f916SThomas Cort 		}
18456ea7f916SThomas Cort 		if (!iflag) {
18466ea7f916SThomas Cort 			ochar = OCHAR;
18476ea7f916SThomas Cort 			ogap = OGAP;
18486ea7f916SThomas Cort 		}
18496ea7f916SThomas Cort 	}
18506ea7f916SThomas Cort 	if (cflag) {
18516ea7f916SThomas Cort 		if (merge) {
18526ea7f916SThomas Cort 			(void)fputs(
18536ea7f916SThomas Cort 			  "pr: -m cannot be used with multiple columns\n", errf);
18546ea7f916SThomas Cort 			return(1);
18556ea7f916SThomas Cort 		}
18566ea7f916SThomas Cort 		if (nmwd) {
18576ea7f916SThomas Cort 			colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt;
18586ea7f916SThomas Cort 			pgwd = ((colwd + nmwd + 2) * clcnt) - 1;
18596ea7f916SThomas Cort 		} else {
18606ea7f916SThomas Cort 			colwd = (pgwd + 1 - clcnt)/clcnt;
18616ea7f916SThomas Cort 			pgwd = ((colwd + 1) * clcnt) - 1;
18626ea7f916SThomas Cort 		}
18636ea7f916SThomas Cort 		if (colwd < 1) {
18646ea7f916SThomas Cort 			(void)fprintf(errf,
18656ea7f916SThomas Cort 			  "pr: page width is too small for %d columns\n",clcnt);
18666ea7f916SThomas Cort 			return(1);
18676ea7f916SThomas Cort 		}
18686ea7f916SThomas Cort 	}
18696ea7f916SThomas Cort 	if (!lines)
18706ea7f916SThomas Cort 		lines = LINES;
18716ea7f916SThomas Cort 
18726ea7f916SThomas Cort 	/*
18736ea7f916SThomas Cort 	 * make sure long enough for headers. if not disable
18746ea7f916SThomas Cort 	 */
18756ea7f916SThomas Cort 	if (lines <= HEADLEN + TAILLEN)
18766ea7f916SThomas Cort 		++nohead;
18776ea7f916SThomas Cort 	else if (!nohead)
18786ea7f916SThomas Cort 		lines -= HEADLEN + TAILLEN;
18796ea7f916SThomas Cort 
18806ea7f916SThomas Cort 	/*
18816ea7f916SThomas Cort 	 * adjust for double space on odd length pages
18826ea7f916SThomas Cort 	 */
18836ea7f916SThomas Cort 	if (dspace) {
18846ea7f916SThomas Cort 		if (lines == 1)
18856ea7f916SThomas Cort 			dspace = 0;
18866ea7f916SThomas Cort 		else {
18876ea7f916SThomas Cort 			if (lines & 1)
18886ea7f916SThomas Cort 				++addone;
18896ea7f916SThomas Cort 			lines /= 2;
18906ea7f916SThomas Cort 		}
18916ea7f916SThomas Cort 	}
18926ea7f916SThomas Cort 
18936ea7f916SThomas Cort 	/*
18946ea7f916SThomas Cort 	 * open /dev/tty if we are to pause before each page
18956ea7f916SThomas Cort 	 * but only if stdout is a terminal and stdin is not a terminal
18966ea7f916SThomas Cort 	 */
18976ea7f916SThomas Cort 	if (ttyout && pgpause && !isatty(fileno(stdin))) {
18986ea7f916SThomas Cort 		if ((ttyinf = fopen("/dev/tty", "r")) == NULL) {
18996ea7f916SThomas Cort 			(void)fprintf(errf, "pr: cannot open terminal\n");
19006ea7f916SThomas Cort 			return(1);
19016ea7f916SThomas Cort 		}
19026ea7f916SThomas Cort 	}
19036ea7f916SThomas Cort 
19046ea7f916SThomas Cort 	return(0);
19056ea7f916SThomas Cort }
1906