11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1991 Keith Muller.
31590Srgrimes * Copyright (c) 1993
41590Srgrimes *	The Regents of the University of California.  All rights reserved.
51590Srgrimes *
61590Srgrimes * This code is derived from software contributed to Berkeley by
71590Srgrimes * Keith Muller of the University of California, San Diego.
81590Srgrimes *
91590Srgrimes * Redistribution and use in source and binary forms, with or without
101590Srgrimes * modification, are permitted provided that the following conditions
111590Srgrimes * are met:
121590Srgrimes * 1. Redistributions of source code must retain the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer.
141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer in the
161590Srgrimes *    documentation and/or other materials provided with the distribution.
171590Srgrimes * 3. All advertising materials mentioning features or use of this software
181590Srgrimes *    must display the following acknowledgement:
191590Srgrimes *	This product includes software developed by the University of
201590Srgrimes *	California, Berkeley and its contributors.
211590Srgrimes * 4. Neither the name of the University nor the names of its contributors
221590Srgrimes *    may be used to endorse or promote products derived from this software
231590Srgrimes *    without specific prior written permission.
241590Srgrimes *
251590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351590Srgrimes * SUCH DAMAGE.
361590Srgrimes */
371590Srgrimes
381590Srgrimes#ifndef lint
3998552Smarkmstatic const char copyright[] =
401590Srgrimes"@(#) Copyright (c) 1993\n\
411590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
421590Srgrimes#endif /* not lint */
431590Srgrimes
4498552Smarkm#if 0
451590Srgrimes#ifndef lint
461590Srgrimesstatic char sccsid[] = "@(#)pr.c	8.2 (Berkeley) 4/16/94";
471590Srgrimes#endif /* not lint */
4898552Smarkm#endif
491590Srgrimes
5098552Smarkm#include <sys/cdefs.h>
5198552Smarkm__FBSDID("$FreeBSD: stable/11/usr.bin/pr/pr.c 317439 2017-04-26 14:44:39Z asomers $");
5298552Smarkm
531590Srgrimes#include <sys/types.h>
541590Srgrimes#include <sys/time.h>
551590Srgrimes#include <sys/stat.h>
561590Srgrimes
571590Srgrimes#include <ctype.h>
581590Srgrimes#include <errno.h>
5974575Sache#include <langinfo.h>
6053948Sache#include <locale.h>
611590Srgrimes#include <signal.h>
621590Srgrimes#include <stdio.h>
631590Srgrimes#include <stdlib.h>
641590Srgrimes#include <string.h>
651590Srgrimes#include <unistd.h>
661590Srgrimes
671590Srgrimes#include "pr.h"
681590Srgrimes#include "extern.h"
691590Srgrimes
701590Srgrimes/*
711590Srgrimes * pr:	a printing and pagination filter. If multiple input files
721590Srgrimes *	are specified, each is read, formatted, and written to standard
7372091Sasmodai *	output. By default, input is separated into 66-line pages, each
741590Srgrimes *	with a header that includes the page number, date, time and the
751590Srgrimes *	files pathname.
761590Srgrimes *
771590Srgrimes *	Complies with posix P1003.2/D11
781590Srgrimes */
791590Srgrimes
801590Srgrimes/*
811590Srgrimes * parameter variables
821590Srgrimes */
83227175Sedstatic int	pgnm;		/* starting page number */
84227175Sedstatic int	clcnt;		/* number of columns */
85227175Sedstatic int	colwd;		/* column data width - multiple columns */
86227175Sedstatic int	across;		/* mult col flag; write across page */
87227175Sedstatic int	dspace;		/* double space flag */
88227175Sedstatic char	inchar;		/* expand input char */
89227175Sedstatic int	ingap;		/* expand input gap */
90227175Sedstatic int	pausefst;	/* Pause before first page */
91227175Sedstatic int	pauseall;	/* Pause before each page */
92227175Sedstatic int	formfeed;	/* use formfeed as trailer */
93227175Sedstatic char	*header;	/* header name instead of file name */
94227175Sedstatic char	ochar;		/* contract output char */
95227175Sedstatic int	ogap;		/* contract output gap */
96227175Sedstatic int	lines;		/* number of lines per page */
97227175Sedstatic int	merge;		/* merge multiple files in output */
98227175Sedstatic char	nmchar;		/* line numbering append char */
99227175Sedstatic int	nmwd;		/* width of line number field */
100227175Sedstatic int	offst;		/* number of page offset spaces */
101227175Sedstatic int	nodiag;		/* do not report file open errors */
102227175Sedstatic char	schar;		/* text column separation character */
103227175Sedstatic int	sflag;		/* -s option for multiple columns */
104227175Sedstatic int	nohead;		/* do not write head and trailer */
105227175Sedstatic int	pgwd;		/* page width with multiple col output */
106317439Sasomersstatic char	*timefrmt;	/* time conversion string */
1071590Srgrimes
1081590Srgrimes/*
1091590Srgrimes * misc globals
1101590Srgrimes */
111227175Sedstatic FILE	*err;		/* error message file pointer */
112227175Sedstatic int	addone;		/* page length is odd with double space */
113227175Sedstatic int	errcnt;		/* error count on file processing */
114227175Sedstatic char	digs[] = "0123456789"; /* page number translation map */
1151590Srgrimes
116227175Sedstatic char	fnamedefault[] = FNAME;
11798552Smarkm
1181590Srgrimesint
11998552Smarkmmain(int argc, char *argv[])
1201590Srgrimes{
1211590Srgrimes	int ret_val;
1221590Srgrimes
1231590Srgrimes	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1241590Srgrimes		(void)signal(SIGINT, terminate);
1251590Srgrimes	ret_val = setup(argc, argv);
1261590Srgrimes	if (!ret_val) {
1271590Srgrimes		/*
1281590Srgrimes		 * select the output format based on options
1291590Srgrimes		 */
1301590Srgrimes		if (merge)
1311590Srgrimes			ret_val = mulfile(argc, argv);
1321590Srgrimes		else if (clcnt == 1)
1331590Srgrimes			ret_val = onecol(argc, argv);
1341590Srgrimes		else if (across)
1351590Srgrimes			ret_val = horzcol(argc, argv);
1361590Srgrimes		else
1371590Srgrimes			ret_val = vertcol(argc, argv);
138317439Sasomers		free(timefrmt);
1391590Srgrimes	} else
1401590Srgrimes		usage();
1411590Srgrimes	flsh_errs();
1421590Srgrimes	if (errcnt || ret_val)
1431590Srgrimes		exit(1);
1441590Srgrimes	return(0);
1451590Srgrimes}
1461590Srgrimes
1471590Srgrimes/*
14893481Sjmallett * Check if we should pause and write an alert character and wait for a
14993481Sjmallett * carriage return on /dev/tty.
15093481Sjmallett */
15198552Smarkmstatic void
15298552Smarkmttypause(int pagecnt)
15393481Sjmallett{
15493481Sjmallett	int pch;
15593481Sjmallett	FILE *ttyfp;
15693481Sjmallett
15793481Sjmallett	if ((pauseall || (pausefst && pagecnt == 1)) &&
15893481Sjmallett	    isatty(STDOUT_FILENO)) {
15993481Sjmallett		if ((ttyfp = fopen("/dev/tty", "r")) != NULL) {
16093481Sjmallett			(void)putc('\a', stderr);
16193481Sjmallett			while ((pch = getc(ttyfp)) != '\n' && pch != EOF)
16293481Sjmallett				;
16393481Sjmallett			(void)fclose(ttyfp);
16493481Sjmallett		}
16593481Sjmallett	}
16693481Sjmallett}
16793481Sjmallett
16893481Sjmallett/*
1691590Srgrimes * onecol:	print files with only one column of output.
1701590Srgrimes *		Line length is unlimited.
1711590Srgrimes */
1721590Srgrimesint
17398552Smarkmonecol(int argc, char *argv[])
1741590Srgrimes{
17598552Smarkm	int cnt = -1;
17698552Smarkm	int off;
17798552Smarkm	int lrgln;
17898552Smarkm	int linecnt;
17998552Smarkm	int num;
1801590Srgrimes	int lncnt;
1811590Srgrimes	int pagecnt;
1821590Srgrimes	int ips;
1831590Srgrimes	int ops;
1841590Srgrimes	int cps;
1851590Srgrimes	char *obuf;
1861590Srgrimes	char *lbuf;
1871590Srgrimes	char *nbuf;
1881590Srgrimes	char *hbuf;
1891590Srgrimes	char *ohbuf;
1901590Srgrimes	FILE *inf;
191102944Sdwmalone	const char *fname;
1921590Srgrimes	int mor;
1931590Srgrimes
1941590Srgrimes	if (nmwd)
1951590Srgrimes		num = nmwd + 1;
1961590Srgrimes	else
1971590Srgrimes		num = 0;
1981590Srgrimes	off = num + offst;
1991590Srgrimes
2001590Srgrimes	/*
2011590Srgrimes	 * allocate line buffer
2021590Srgrimes	 */
2031590Srgrimes	if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) {
2041590Srgrimes		mfail();
2051590Srgrimes		return(1);
2061590Srgrimes	}
2071590Srgrimes	/*
2081590Srgrimes	 * allocate header buffer
2091590Srgrimes	 */
2101590Srgrimes	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
211317439Sasomers		free(obuf);
2121590Srgrimes		mfail();
2131590Srgrimes		return(1);
2141590Srgrimes	}
2151590Srgrimes
2161590Srgrimes	ohbuf = hbuf + offst;
2171590Srgrimes	nbuf = obuf + offst;
2181590Srgrimes	lbuf = nbuf + num;
2191590Srgrimes	if (num)
2201590Srgrimes		nbuf[--num] = nmchar;
2211590Srgrimes	if (offst) {
2221590Srgrimes		(void)memset(obuf, (int)' ', offst);
2231590Srgrimes		(void)memset(hbuf, (int)' ', offst);
2241590Srgrimes	}
2251590Srgrimes
2261590Srgrimes	/*
2271590Srgrimes	 * loop by file
2281590Srgrimes	 */
2291590Srgrimes	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
2301590Srgrimes		if (pgnm) {
2311590Srgrimes			/*
2321590Srgrimes			 * skip to specified page
2331590Srgrimes			 */
2341590Srgrimes			if (inskip(inf, pgnm, lines))
2351590Srgrimes				continue;
2361590Srgrimes			pagecnt = pgnm;
2371590Srgrimes		} else
2381590Srgrimes			pagecnt = 1;
2391590Srgrimes		lncnt = 0;
2401590Srgrimes
2411590Srgrimes		/*
2421590Srgrimes		 * loop by page
2431590Srgrimes		 */
2441590Srgrimes		for(;;) {
2451590Srgrimes			linecnt = 0;
2461590Srgrimes			lrgln = 0;
2471590Srgrimes			ops = 0;
2481590Srgrimes			ips = 0;
2491590Srgrimes			cps = 0;
2501590Srgrimes
25193481Sjmallett			ttypause(pagecnt);
25293481Sjmallett
2531590Srgrimes			/*
2541590Srgrimes			 * loop by line
2551590Srgrimes			 */
2561590Srgrimes			while (linecnt < lines) {
2571590Srgrimes				/*
2581590Srgrimes				 * input next line
2591590Srgrimes				 */
2601590Srgrimes				if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0)
2611590Srgrimes					break;
2621590Srgrimes				if (!linecnt && !nohead &&
2631590Srgrimes					prhead(hbuf, fname, pagecnt))
264317439Sasomers					goto err;
2651590Srgrimes
2661590Srgrimes				/*
2671590Srgrimes				 * start of new line.
2681590Srgrimes				 */
2691590Srgrimes				if (!lrgln) {
2701590Srgrimes					if (num)
2711590Srgrimes						addnum(nbuf, num, ++lncnt);
2721590Srgrimes					if (otln(obuf,cnt+off, &ips, &ops, mor))
273317439Sasomers						goto err;
2741590Srgrimes				} else if (otln(lbuf, cnt, &ips, &ops, mor))
275317439Sasomers					goto err;
2761590Srgrimes
2771590Srgrimes				/*
2781590Srgrimes				 * if line bigger than buffer, get more
2791590Srgrimes				 */
2801590Srgrimes				if (mor) {
2811590Srgrimes					lrgln = 1;
2821590Srgrimes					continue;
2831590Srgrimes				}
2841590Srgrimes
2851590Srgrimes				/*
2861590Srgrimes				 * whole line rcvd. reset tab proc. state
2871590Srgrimes				 */
2881590Srgrimes				++linecnt;
2891590Srgrimes				lrgln = 0;
2901590Srgrimes				ops = 0;
2911590Srgrimes				ips = 0;
2921590Srgrimes			}
2931590Srgrimes
2941590Srgrimes			/*
2951590Srgrimes			 * fill to end of page
2961590Srgrimes			 */
2971590Srgrimes			if (linecnt && prtail(lines-linecnt-lrgln, lrgln))
298317439Sasomers				goto err;
2991590Srgrimes
3001590Srgrimes			/*
3011590Srgrimes			 * On EOF go to next file
3021590Srgrimes			 */
3031590Srgrimes			if (cnt < 0)
3041590Srgrimes				break;
3051590Srgrimes			++pagecnt;
3061590Srgrimes		}
3071590Srgrimes		if (inf != stdin)
3081590Srgrimes			(void)fclose(inf);
3091590Srgrimes	}
3101590Srgrimes	if (eoptind < argc)
311317439Sasomers		goto err;
312317439Sasomers	free(hbuf);
313317439Sasomers	free(obuf);
3141590Srgrimes	return(0);
315317439Sasomerserr:
316317439Sasomers	free(hbuf);
317317439Sasomers	free(obuf);
318317439Sasomers	return(1);
3191590Srgrimes}
3201590Srgrimes
3211590Srgrimes/*
3221590Srgrimes * vertcol:	print files with more than one column of output down a page
3231590Srgrimes */
3241590Srgrimesint
32598552Smarkmvertcol(int argc, char *argv[])
3261590Srgrimes{
32798552Smarkm	char *ptbf;
328317439Sasomers	char **lstdat = NULL;
32998552Smarkm	int i;
33098552Smarkm	int j;
33198552Smarkm	int cnt = -1;
33298552Smarkm	int pln;
333317439Sasomers	int *indy = NULL;
3341590Srgrimes	int cvc;
335317439Sasomers	int *lindy = NULL;
3361590Srgrimes	int lncnt;
3371590Srgrimes	int stp;
3381590Srgrimes	int pagecnt;
3391590Srgrimes	int col = colwd + 1;
3401590Srgrimes	int mxlen = pgwd + offst + 1;
3411590Srgrimes	int mclcnt = clcnt - 1;
342317439Sasomers	struct vcol *vc = NULL;
3431590Srgrimes	int mvc;
3441590Srgrimes	int tvc;
3451590Srgrimes	int cw = nmwd + 1;
3461590Srgrimes	int fullcol;
347317439Sasomers	char *buf = NULL;
348317439Sasomers	char *hbuf = NULL;
3491590Srgrimes	char *ohbuf;
350102944Sdwmalone	const char *fname;
3511590Srgrimes	FILE *inf;
3521590Srgrimes	int ips = 0;
3531590Srgrimes	int cps = 0;
3541590Srgrimes	int ops = 0;
3551590Srgrimes	int mor = 0;
356317439Sasomers	int retval = 1;
3571590Srgrimes
3581590Srgrimes	/*
3591590Srgrimes	 * allocate page buffer
3601590Srgrimes	 */
3611590Srgrimes	if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) {
3621590Srgrimes		mfail();
3631590Srgrimes		return(1);
3641590Srgrimes	}
3651590Srgrimes
3661590Srgrimes	/*
3671590Srgrimes	 * allocate page header
3681590Srgrimes	 */
3691590Srgrimes	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
3701590Srgrimes		mfail();
371317439Sasomers		goto out;
3721590Srgrimes	}
3731590Srgrimes	ohbuf = hbuf + offst;
3741590Srgrimes	if (offst)
3751590Srgrimes		(void)memset(hbuf, (int)' ', offst);
3761590Srgrimes
3771590Srgrimes	/*
3781590Srgrimes	 * col pointers when no headers
3791590Srgrimes	 */
3801590Srgrimes	mvc = lines * clcnt;
3811590Srgrimes	if ((vc =
3821590Srgrimes	    (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) {
3831590Srgrimes		mfail();
384317439Sasomers		goto out;
3851590Srgrimes	}
3861590Srgrimes
3871590Srgrimes	/*
3881590Srgrimes	 * pointer into page where last data per line is located
3891590Srgrimes	 */
3901590Srgrimes	if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){
3911590Srgrimes		mfail();
392317439Sasomers		goto out;
3931590Srgrimes	}
3941590Srgrimes
3951590Srgrimes	/*
3961590Srgrimes	 * fast index lookups to locate start of lines
3971590Srgrimes	 */
3981590Srgrimes	if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
3991590Srgrimes		mfail();
400317439Sasomers		goto out;
4011590Srgrimes	}
4021590Srgrimes	if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
4031590Srgrimes		mfail();
404317439Sasomers		goto out;
4051590Srgrimes	}
4061590Srgrimes
4071590Srgrimes	if (nmwd)
4081590Srgrimes		fullcol = col + cw;
4091590Srgrimes	else
4101590Srgrimes		fullcol = col;
4111590Srgrimes
4121590Srgrimes	/*
4131590Srgrimes	 * initialize buffer lookup indexes and offset area
4141590Srgrimes	 */
4151590Srgrimes	for (j = 0; j < lines; ++j) {
4161590Srgrimes		lindy[j] = j * mxlen;
4171590Srgrimes		indy[j] = lindy[j] + offst;
4181590Srgrimes		if (offst) {
4191590Srgrimes			ptbf = buf + lindy[j];
4201590Srgrimes			(void)memset(ptbf, (int)' ', offst);
4211590Srgrimes			ptbf += offst;
4221590Srgrimes		} else
4231590Srgrimes			ptbf = buf + indy[j];
4241590Srgrimes		lstdat[j] = ptbf;
4251590Srgrimes	}
4261590Srgrimes
4271590Srgrimes	/*
4281590Srgrimes	 * loop by file
4291590Srgrimes	 */
4301590Srgrimes	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
4311590Srgrimes		if (pgnm) {
4321590Srgrimes			/*
4331590Srgrimes			 * skip to requested page
4341590Srgrimes			 */
4351590Srgrimes			if (inskip(inf, pgnm, lines))
4361590Srgrimes				continue;
4371590Srgrimes			pagecnt = pgnm;
4381590Srgrimes		} else
4391590Srgrimes			pagecnt = 1;
4401590Srgrimes		lncnt = 0;
4411590Srgrimes
4421590Srgrimes		/*
4431590Srgrimes		 * loop by page
4441590Srgrimes		 */
4451590Srgrimes		for(;;) {
44693481Sjmallett			ttypause(pagecnt);
44793481Sjmallett
4481590Srgrimes			/*
4491590Srgrimes			 * loop by column
4501590Srgrimes			 */
4511590Srgrimes			cvc = 0;
4521590Srgrimes			for (i = 0; i < clcnt; ++i) {
4531590Srgrimes				j = 0;
4541590Srgrimes				/*
4551590Srgrimes				 * if last column, do not pad
4561590Srgrimes				 */
4571590Srgrimes				if (i == mclcnt)
4581590Srgrimes					stp = 1;
4591590Srgrimes				else
4601590Srgrimes					stp = 0;
4611590Srgrimes				/*
4621590Srgrimes				 * loop by line
4631590Srgrimes				 */
4641590Srgrimes				for(;;) {
4651590Srgrimes					/*
4661590Srgrimes					 * is this first column
4671590Srgrimes					 */
4681590Srgrimes					if (!i) {
4691590Srgrimes						ptbf = buf + indy[j];
4701590Srgrimes						lstdat[j] = ptbf;
4718874Srgrimes					} else
4721590Srgrimes						ptbf = lstdat[j];
4731590Srgrimes					vc[cvc].pt = ptbf;
4741590Srgrimes
4751590Srgrimes					/*
4761590Srgrimes					 * add number
4771590Srgrimes					 */
4781590Srgrimes					if (nmwd) {
4791590Srgrimes						addnum(ptbf, nmwd, ++lncnt);
4801590Srgrimes						ptbf += nmwd;
4811590Srgrimes						*ptbf++ = nmchar;
4821590Srgrimes					}
4831590Srgrimes
4841590Srgrimes					/*
4851590Srgrimes					 * input next line
4861590Srgrimes					 */
4871590Srgrimes					cnt = inln(inf,ptbf,colwd,&cps,1,&mor);
4881590Srgrimes					vc[cvc++].cnt = cnt;
4891590Srgrimes					if (cnt < 0)
4901590Srgrimes						break;
4911590Srgrimes					ptbf += cnt;
4921590Srgrimes
4931590Srgrimes					/*
4941590Srgrimes					 * pad all but last column on page
4951590Srgrimes					 */
4961590Srgrimes					if (!stp) {
4971590Srgrimes						/*
4981590Srgrimes						 * pad to end of column
4991590Srgrimes						 */
5001590Srgrimes						if (sflag)
5011590Srgrimes							*ptbf++ = schar;
5021590Srgrimes						else if ((pln = col-cnt) > 0) {
5031590Srgrimes							(void)memset(ptbf,
5041590Srgrimes								(int)' ',pln);
5051590Srgrimes							ptbf += pln;
5061590Srgrimes						}
5071590Srgrimes					}
5081590Srgrimes					/*
5091590Srgrimes					 * remember last char in line
5101590Srgrimes					 */
5111590Srgrimes					lstdat[j] = ptbf;
5121590Srgrimes					if (++j >= lines)
5131590Srgrimes						break;
5141590Srgrimes				}
5151590Srgrimes				if (cnt < 0)
5161590Srgrimes					break;
5171590Srgrimes			}
5181590Srgrimes
5191590Srgrimes			/*
5201590Srgrimes			 * when -t (no header) is specified the spec requires
5211590Srgrimes			 * the min number of lines. The last page may not have
5221590Srgrimes			 * balanced length columns. To fix this we must reorder
5231590Srgrimes			 * the columns. This is a very slow technique so it is
5241590Srgrimes			 * only used under limited conditions. Without -t, the
5251590Srgrimes			 * balancing of text columns is unspecified. To NOT
5261590Srgrimes			 * balance the last page, add the global variable
5271590Srgrimes			 * nohead to the if statement below e.g.
5281590Srgrimes			 *
5291590Srgrimes			 * if ((cnt < 0) && nohead && cvc ......
5301590Srgrimes			 */
5311590Srgrimes			--cvc;
5321590Srgrimes
5331590Srgrimes			/*
5341590Srgrimes			 * check to see if last page needs to be reordered
5351590Srgrimes			 */
5361590Srgrimes			if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){
5371590Srgrimes				pln = cvc/clcnt;
5381590Srgrimes				if (cvc % clcnt)
5391590Srgrimes					++pln;
5401590Srgrimes
5411590Srgrimes				/*
5421590Srgrimes				 * print header
5431590Srgrimes				 */
5441590Srgrimes				if (!nohead && prhead(hbuf, fname, pagecnt))
545317439Sasomers					goto out;
5461590Srgrimes				for (i = 0; i < pln; ++i) {
5471590Srgrimes					ips = 0;
5481590Srgrimes					ops = 0;
549317439Sasomers					if (offst &&
550317439Sasomers					    otln(buf,offst,&ips,&ops,1))
551317439Sasomers						goto out;
5521590Srgrimes					tvc = i;
5531590Srgrimes
5541590Srgrimes					for (j = 0; j < clcnt; ++j) {
5551590Srgrimes						/*
5561590Srgrimes						 * determine column length
5571590Srgrimes						 */
5581590Srgrimes						if (j == mclcnt) {
5591590Srgrimes							/*
5601590Srgrimes							 * last column
5611590Srgrimes							 */
5621590Srgrimes							cnt = vc[tvc].cnt;
5631590Srgrimes							if (nmwd)
5641590Srgrimes								cnt += cw;
5651590Srgrimes						} else if (sflag) {
5661590Srgrimes							/*
5671590Srgrimes							 * single ch between
5681590Srgrimes							 */
5691590Srgrimes							cnt = vc[tvc].cnt + 1;
5701590Srgrimes							if (nmwd)
5711590Srgrimes								cnt += cw;
5721590Srgrimes						} else
5731590Srgrimes							cnt = fullcol;
5741590Srgrimes						if (otln(vc[tvc].pt, cnt, &ips,
5751590Srgrimes								&ops, 1))
576317439Sasomers							goto out;
5771590Srgrimes						tvc += pln;
5781590Srgrimes						if (tvc >= cvc)
5791590Srgrimes							break;
5801590Srgrimes					}
5811590Srgrimes					/*
5821590Srgrimes					 * terminate line
5831590Srgrimes					 */
5841590Srgrimes					if (otln(buf, 0, &ips, &ops, 0))
585317439Sasomers						goto out;
5861590Srgrimes				}
5871590Srgrimes				/*
5881590Srgrimes				 * pad to end of page
5891590Srgrimes				 */
5901590Srgrimes				if (prtail((lines - pln), 0))
591317439Sasomers					goto out;
5921590Srgrimes				/*
5931590Srgrimes				 * done with output, go to next file
5941590Srgrimes				 */
5951590Srgrimes				break;
5961590Srgrimes			}
5971590Srgrimes
5981590Srgrimes			/*
5991590Srgrimes			 * determine how many lines to output
6001590Srgrimes			 */
6011590Srgrimes			if (i > 0)
6021590Srgrimes				pln = lines;
6031590Srgrimes			else
6041590Srgrimes				pln = j;
6051590Srgrimes
6061590Srgrimes			/*
6071590Srgrimes			 * print header
6081590Srgrimes			 */
6091590Srgrimes			if (pln && !nohead && prhead(hbuf, fname, pagecnt))
610317439Sasomers				goto out;
6111590Srgrimes
6121590Srgrimes			/*
6131590Srgrimes			 * output each line
6141590Srgrimes			 */
6151590Srgrimes			for (i = 0; i < pln; ++i) {
6161590Srgrimes				ptbf = buf + lindy[i];
6171590Srgrimes				if ((j = lstdat[i] - ptbf) <= offst)
6181590Srgrimes					break;
6191590Srgrimes				if (otln(ptbf, j, &ips, &ops, 0))
620317439Sasomers					goto out;
6211590Srgrimes			}
6221590Srgrimes
6231590Srgrimes			/*
6241590Srgrimes			 * pad to end of page
6251590Srgrimes			 */
6261590Srgrimes			if (pln && prtail((lines - pln), 0))
627317439Sasomers				goto out;
6281590Srgrimes
6291590Srgrimes			/*
6301590Srgrimes			 * if EOF go to next file
6311590Srgrimes			 */
6321590Srgrimes			if (cnt < 0)
6331590Srgrimes				break;
6341590Srgrimes			++pagecnt;
6351590Srgrimes		}
6361590Srgrimes		if (inf != stdin)
6371590Srgrimes			(void)fclose(inf);
6381590Srgrimes	}
6391590Srgrimes	if (eoptind < argc)
640317439Sasomers		goto out;
641317439Sasomers	retval = 0;
642317439Sasomersout:
643317439Sasomers	free(lindy);
644317439Sasomers	free(indy);
645317439Sasomers	free(lstdat);
646317439Sasomers	free(vc);
647317439Sasomers	free(hbuf);
648317439Sasomers	free(buf);
649317439Sasomers	return(retval);
6501590Srgrimes}
6511590Srgrimes
6521590Srgrimes/*
6531590Srgrimes * horzcol:	print files with more than one column of output across a page
6541590Srgrimes */
6551590Srgrimesint
65698552Smarkmhorzcol(int argc, char *argv[])
6571590Srgrimes{
65898552Smarkm	char *ptbf;
65998552Smarkm	int pln;
66098552Smarkm	int cnt = -1;
66198552Smarkm	char *lstdat;
66298552Smarkm	int col = colwd + 1;
66398552Smarkm	int j;
66498552Smarkm	int i;
6651590Srgrimes	int lncnt;
6661590Srgrimes	int pagecnt;
6671590Srgrimes	char *buf;
6681590Srgrimes	char *hbuf;
6691590Srgrimes	char *ohbuf;
670102944Sdwmalone	const char *fname;
6711590Srgrimes	FILE *inf;
6721590Srgrimes	int ips = 0;
6731590Srgrimes	int cps = 0;
6741590Srgrimes	int ops = 0;
6751590Srgrimes	int mor = 0;
6761590Srgrimes
6771590Srgrimes	if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
6781590Srgrimes		mfail();
6791590Srgrimes		return(1);
6801590Srgrimes	}
6811590Srgrimes
6821590Srgrimes	/*
6831590Srgrimes	 * page header
6841590Srgrimes	 */
6851590Srgrimes	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
686317439Sasomers		free(buf);
6871590Srgrimes		mfail();
6881590Srgrimes		return(1);
6891590Srgrimes	}
6901590Srgrimes	ohbuf = hbuf + offst;
6911590Srgrimes	if (offst) {
6921590Srgrimes		(void)memset(buf, (int)' ', offst);
6931590Srgrimes		(void)memset(hbuf, (int)' ', offst);
6941590Srgrimes	}
6951590Srgrimes
6961590Srgrimes	/*
6971590Srgrimes	 * loop by file
6981590Srgrimes	 */
6991590Srgrimes	while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
7001590Srgrimes		if (pgnm) {
7011590Srgrimes			if (inskip(inf, pgnm, lines))
7021590Srgrimes				continue;
7031590Srgrimes			pagecnt = pgnm;
7041590Srgrimes		} else
7051590Srgrimes			pagecnt = 1;
7061590Srgrimes		lncnt = 0;
7071590Srgrimes
7081590Srgrimes		/*
7091590Srgrimes		 * loop by page
7101590Srgrimes		 */
7111590Srgrimes		for(;;) {
71293481Sjmallett			ttypause(pagecnt);
71393481Sjmallett
7141590Srgrimes			/*
7151590Srgrimes			 * loop by line
7161590Srgrimes			 */
7171590Srgrimes			for (i = 0; i < lines; ++i) {
7181590Srgrimes				ptbf = buf + offst;
7191590Srgrimes				lstdat = ptbf;
7201590Srgrimes				j = 0;
7211590Srgrimes				/*
7221590Srgrimes				 * loop by col
7231590Srgrimes				 */
7241590Srgrimes				for(;;) {
7251590Srgrimes					if (nmwd) {
7261590Srgrimes						/*
7271590Srgrimes						 * add number to column
7281590Srgrimes						 */
7291590Srgrimes						addnum(ptbf, nmwd, ++lncnt);
7301590Srgrimes						ptbf += nmwd;
7311590Srgrimes						*ptbf++ = nmchar;
7321590Srgrimes					}
7331590Srgrimes					/*
7341590Srgrimes					 * input line
7351590Srgrimes					 */
7361590Srgrimes					if ((cnt = inln(inf,ptbf,colwd,&cps,1,
7371590Srgrimes							&mor)) < 0)
7381590Srgrimes						break;
7391590Srgrimes					ptbf += cnt;
7401590Srgrimes					lstdat = ptbf;
7411590Srgrimes
7421590Srgrimes					/*
7431590Srgrimes					 * if last line skip padding
7441590Srgrimes					 */
7451590Srgrimes					if (++j >= clcnt)
7461590Srgrimes						break;
7471590Srgrimes
7481590Srgrimes					/*
7491590Srgrimes					 * pad to end of column
7501590Srgrimes					 */
7511590Srgrimes					if (sflag)
7521590Srgrimes						*ptbf++ = schar;
7531590Srgrimes					else if ((pln = col - cnt) > 0) {
7541590Srgrimes						(void)memset(ptbf,(int)' ',pln);
7551590Srgrimes						ptbf += pln;
7561590Srgrimes					}
7571590Srgrimes				}
7581590Srgrimes
7591590Srgrimes				/*
7601590Srgrimes				 * determine line length
7611590Srgrimes				 */
7621590Srgrimes				if ((j = lstdat - buf) <= offst)
7631590Srgrimes					break;
7641590Srgrimes				if (!i && !nohead &&
7651590Srgrimes					prhead(hbuf, fname, pagecnt))
766317439Sasomers					goto err;
7671590Srgrimes				/*
7681590Srgrimes				 * output line
7691590Srgrimes				 */
7701590Srgrimes				if (otln(buf, j, &ips, &ops, 0))
771317439Sasomers					goto err;
7721590Srgrimes			}
7731590Srgrimes
7741590Srgrimes			/*
7751590Srgrimes			 * pad to end of page
7761590Srgrimes			 */
7771590Srgrimes			if (i && prtail(lines-i, 0))
778317439Sasomers				goto err;
7791590Srgrimes
7801590Srgrimes			/*
7811590Srgrimes			 * if EOF go to next file
7821590Srgrimes			 */
7831590Srgrimes			if (cnt < 0)
7841590Srgrimes				break;
7851590Srgrimes			++pagecnt;
7861590Srgrimes		}
7871590Srgrimes		if (inf != stdin)
7881590Srgrimes			(void)fclose(inf);
7891590Srgrimes	}
7901590Srgrimes	if (eoptind < argc)
791317439Sasomers		goto err;
792317439Sasomers	free(hbuf);
793317439Sasomers	free(buf);
7941590Srgrimes	return(0);
795317439Sasomerserr:
796317439Sasomers	free(hbuf);
797317439Sasomers	free(buf);
798317439Sasomers	return(1);
7991590Srgrimes}
8001590Srgrimes
8011590Srgrimes/*
8021590Srgrimes * mulfile:	print files with more than one column of output and
8031590Srgrimes *		more than one file concurrently
8041590Srgrimes */
8051590Srgrimesint
80698552Smarkmmulfile(int argc, char *argv[])
8071590Srgrimes{
80898552Smarkm	char *ptbf;
80998552Smarkm	int j;
81098552Smarkm	int pln;
81198552Smarkm	int cnt;
81298552Smarkm	char *lstdat;
81398552Smarkm	int i;
814317439Sasomers	FILE **fbuf = NULL;
8151590Srgrimes	int actf;
8161590Srgrimes	int lncnt;
8171590Srgrimes	int col;
8181590Srgrimes	int pagecnt;
8191590Srgrimes	int fproc;
820317439Sasomers	char *buf = NULL;
821317439Sasomers	char *hbuf = NULL;
8221590Srgrimes	char *ohbuf;
823102944Sdwmalone	const char *fname;
8241590Srgrimes	int ips = 0;
8251590Srgrimes	int cps = 0;
8261590Srgrimes	int ops = 0;
8271590Srgrimes	int mor = 0;
828317439Sasomers	int retval = 1;
8291590Srgrimes
8301590Srgrimes	/*
8311590Srgrimes	 * array of FILE *, one for each operand
8321590Srgrimes	 */
8331590Srgrimes	if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) {
8341590Srgrimes		mfail();
835317439Sasomers		goto out;
8361590Srgrimes	}
8371590Srgrimes
8381590Srgrimes	/*
8391590Srgrimes	 * page header
8401590Srgrimes	 */
8411590Srgrimes	if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
8421590Srgrimes		mfail();
843317439Sasomers		goto out;
8441590Srgrimes	}
8451590Srgrimes	ohbuf = hbuf + offst;
8461590Srgrimes
8471590Srgrimes	/*
8481590Srgrimes	 * do not know how many columns yet. The number of operands provide an
8491590Srgrimes	 * upper bound on the number of columns. We use the number of files
8501590Srgrimes	 * we can open successfully to set the number of columns. The operation
851228992Suqs	 * of the merge operation (-m) in relation to unsuccessful file opens
8521590Srgrimes	 * is unspecified by posix.
8531590Srgrimes	 */
8541590Srgrimes	j = 0;
8551590Srgrimes	while (j < clcnt) {
8561590Srgrimes		if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL)
8571590Srgrimes			break;
8581590Srgrimes		if (pgnm && (inskip(fbuf[j], pgnm, lines)))
8591590Srgrimes			fbuf[j] = NULL;
8601590Srgrimes		++j;
8611590Srgrimes	}
8621590Srgrimes
8631590Srgrimes	/*
8641590Srgrimes	 * if no files, exit
8651590Srgrimes	 */
8661590Srgrimes	if (!j)
867317439Sasomers		goto out;
8681590Srgrimes
8691590Srgrimes	/*
870228992Suqs	 * calculate page boundaries based on open file count
8711590Srgrimes	 */
8721590Srgrimes	clcnt = j;
8731590Srgrimes	if (nmwd) {
8741590Srgrimes		colwd = (pgwd - clcnt - nmwd)/clcnt;
8751590Srgrimes		pgwd = ((colwd + 1) * clcnt) - nmwd - 2;
8761590Srgrimes	} else {
8771590Srgrimes		colwd = (pgwd + 1 - clcnt)/clcnt;
8781590Srgrimes		pgwd = ((colwd + 1) * clcnt) - 1;
8791590Srgrimes	}
8801590Srgrimes	if (colwd < 1) {
8811590Srgrimes		(void)fprintf(err,
8821590Srgrimes		  "pr: page width too small for %d columns\n", clcnt);
883317439Sasomers		goto out;
8841590Srgrimes	}
8851590Srgrimes	actf = clcnt;
8861590Srgrimes	col = colwd + 1;
8871590Srgrimes
8881590Srgrimes	/*
8891590Srgrimes	 * line buffer
8901590Srgrimes	 */
8911590Srgrimes	if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
8921590Srgrimes		mfail();
893317439Sasomers		goto out;
8941590Srgrimes	}
8951590Srgrimes	if (offst) {
8961590Srgrimes		(void)memset(buf, (int)' ', offst);
8971590Srgrimes		(void)memset(hbuf, (int)' ', offst);
8981590Srgrimes	}
8991590Srgrimes	if (pgnm)
9001590Srgrimes		pagecnt = pgnm;
9011590Srgrimes	else
9021590Srgrimes		pagecnt = 1;
9031590Srgrimes	lncnt = 0;
9041590Srgrimes
9051590Srgrimes	/*
9061590Srgrimes	 * continue to loop while any file still has data
9071590Srgrimes	 */
9081590Srgrimes	while (actf > 0) {
90993481Sjmallett		ttypause(pagecnt);
91093481Sjmallett
9111590Srgrimes		/*
9121590Srgrimes		 * loop by line
9131590Srgrimes		 */
9141590Srgrimes		for (i = 0; i < lines; ++i) {
9151590Srgrimes			ptbf = buf + offst;
9161590Srgrimes			lstdat = ptbf;
9171590Srgrimes			if (nmwd) {
9181590Srgrimes				/*
9191590Srgrimes				 * add line number to line
9201590Srgrimes				 */
9211590Srgrimes				addnum(ptbf, nmwd, ++lncnt);
9221590Srgrimes				ptbf += nmwd;
9231590Srgrimes				*ptbf++ = nmchar;
9241590Srgrimes			}
9251590Srgrimes			j = 0;
9261590Srgrimes			fproc = 0;
9271590Srgrimes
9281590Srgrimes			/*
9291590Srgrimes			 * loop by column
9301590Srgrimes			 */
9311590Srgrimes			for (j = 0; j < clcnt; ++j) {
9321590Srgrimes				if (fbuf[j] == NULL) {
9331590Srgrimes					/*
9341590Srgrimes					 * empty column; EOF
9351590Srgrimes					 */
9361590Srgrimes					cnt = 0;
9371590Srgrimes				} else if ((cnt = inln(fbuf[j], ptbf, colwd,
9381590Srgrimes							&cps, 1, &mor)) < 0) {
9391590Srgrimes					/*
9401590Srgrimes					 * EOF hit; no data
9411590Srgrimes					 */
9421590Srgrimes					if (fbuf[j] != stdin)
9431590Srgrimes						(void)fclose(fbuf[j]);
9441590Srgrimes					fbuf[j] = NULL;
9451590Srgrimes					--actf;
9461590Srgrimes					cnt = 0;
9471590Srgrimes				} else {
9481590Srgrimes					/*
9491590Srgrimes					 * process file data
9501590Srgrimes					 */
9511590Srgrimes					ptbf += cnt;
9521590Srgrimes					lstdat = ptbf;
9531590Srgrimes					fproc++;
9541590Srgrimes				}
9551590Srgrimes
9561590Srgrimes				/*
9571590Srgrimes				 * if last ACTIVE column, done with line
9581590Srgrimes				 */
9591590Srgrimes				if (fproc >= actf)
9601590Srgrimes					break;
9611590Srgrimes
9621590Srgrimes				/*
9631590Srgrimes				 * pad to end of column
9641590Srgrimes				 */
9651590Srgrimes				if (sflag) {
9661590Srgrimes					*ptbf++ = schar;
9671590Srgrimes				} else if ((pln = col - cnt) > 0) {
9681590Srgrimes					(void)memset(ptbf, (int)' ', pln);
9691590Srgrimes					ptbf += pln;
9701590Srgrimes				}
9711590Srgrimes			}
9721590Srgrimes
9731590Srgrimes			/*
9741590Srgrimes			 * calculate data in line
9751590Srgrimes			 */
9761590Srgrimes			if ((j = lstdat - buf) <= offst)
9771590Srgrimes				break;
9781590Srgrimes
9791590Srgrimes			if (!i && !nohead && prhead(hbuf, fname, pagecnt))
980317439Sasomers				goto out;
9811590Srgrimes
9821590Srgrimes			/*
9831590Srgrimes			 * output line
9841590Srgrimes			 */
9851590Srgrimes			if (otln(buf, j, &ips, &ops, 0))
986317439Sasomers				goto out;
9871590Srgrimes
9881590Srgrimes			/*
9891590Srgrimes			 * if no more active files, done
9901590Srgrimes			 */
9911590Srgrimes			if (actf <= 0) {
9921590Srgrimes				++i;
9931590Srgrimes				break;
9941590Srgrimes			}
9951590Srgrimes		}
9961590Srgrimes
9971590Srgrimes		/*
9981590Srgrimes		 * pad to end of page
9991590Srgrimes		 */
10001590Srgrimes		if (i && prtail(lines-i, 0))
1001317439Sasomers			goto out;
10021590Srgrimes		++pagecnt;
10031590Srgrimes	}
10041590Srgrimes	if (eoptind < argc)
1005317439Sasomers		goto out;
1006317439Sasomers	retval = 0;
1007317439Sasomersout:
1008317439Sasomers	free(buf);
1009317439Sasomers	free(hbuf);
1010317439Sasomers	free(fbuf);
1011317439Sasomers	return(retval);
10121590Srgrimes}
10131590Srgrimes
10141590Srgrimes/*
10151590Srgrimes * inln():	input a line of data (unlimited length lines supported)
10161590Srgrimes *		Input is optionally expanded to spaces
10171590Srgrimes *
10181590Srgrimes *	inf:	file
10191590Srgrimes *	buf:	buffer
10201590Srgrimes *	lim:	buffer length
1021228992Suqs *	cps:	column position 1st char in buffer (large line support)
10228874Srgrimes *	trnc:	throw away data more than lim up to \n
10231590Srgrimes *	mor:	set if more data in line (not truncated)
10241590Srgrimes */
10251590Srgrimesint
102698552Smarkminln(FILE *inf, char *buf, int lim, int *cps, int trnc, int *mor)
10271590Srgrimes{
102898552Smarkm	int col;
102998552Smarkm	int gap = ingap;
103098552Smarkm	int ch = EOF;
103198552Smarkm	char *ptbuf;
103298552Smarkm	int chk = (int)inchar;
10331590Srgrimes
10341590Srgrimes	ptbuf = buf;
10351590Srgrimes
10361590Srgrimes	if (gap) {
10371590Srgrimes		/*
10381590Srgrimes		 * expanding input option
10391590Srgrimes		 */
10401590Srgrimes		while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
10411590Srgrimes			/*
10421590Srgrimes			 * is this the input "tab" char
10431590Srgrimes			 */
10441590Srgrimes			if (ch == chk) {
10451590Srgrimes				/*
10461590Srgrimes				 * expand to number of spaces
10471590Srgrimes				 */
10481590Srgrimes				col = (ptbuf - buf) + *cps;
10491590Srgrimes				col = gap - (col % gap);
10501590Srgrimes
10511590Srgrimes				/*
10521590Srgrimes				 * if more than this line, push back
10531590Srgrimes				 */
10541590Srgrimes				if ((col > lim) && (ungetc(ch, inf) == EOF))
10551590Srgrimes					return(1);
10561590Srgrimes
10571590Srgrimes				/*
10581590Srgrimes				 * expand to spaces
10591590Srgrimes				 */
10601590Srgrimes				while ((--col >= 0) && (--lim >= 0))
10611590Srgrimes					*ptbuf++ = ' ';
10621590Srgrimes				continue;
10631590Srgrimes			}
10641590Srgrimes			if (ch == '\n')
10651590Srgrimes				break;
10661590Srgrimes			*ptbuf++ = ch;
10671590Srgrimes		}
10681590Srgrimes	} else {
10691590Srgrimes		/*
10701590Srgrimes		 * no expansion
10711590Srgrimes		 */
10721590Srgrimes		while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
10731590Srgrimes			if (ch == '\n')
10741590Srgrimes				break;
10751590Srgrimes			*ptbuf++ = ch;
10761590Srgrimes		}
10771590Srgrimes	}
10781590Srgrimes	col = ptbuf - buf;
10791590Srgrimes	if (ch == EOF) {
10801590Srgrimes		*mor = 0;
10811590Srgrimes		*cps = 0;
10821590Srgrimes		if (!col)
10831590Srgrimes			return(-1);
10841590Srgrimes		return(col);
10851590Srgrimes	}
10861590Srgrimes	if (ch == '\n') {
10871590Srgrimes		/*
10881590Srgrimes		 * entire line processed
10891590Srgrimes		 */
10901590Srgrimes		*mor = 0;
10911590Srgrimes		*cps = 0;
10921590Srgrimes		return(col);
10931590Srgrimes	}
10941590Srgrimes
10951590Srgrimes	/*
10961590Srgrimes	 * line was larger than limit
10971590Srgrimes	 */
10981590Srgrimes	if (trnc) {
10991590Srgrimes		/*
11001590Srgrimes		 * throw away rest of line
11011590Srgrimes		 */
11021590Srgrimes		while ((ch = getc(inf)) != EOF) {
11031590Srgrimes			if (ch == '\n')
11041590Srgrimes				break;
11051590Srgrimes		}
11061590Srgrimes		*cps = 0;
11071590Srgrimes		*mor = 0;
11081590Srgrimes	} else {
11091590Srgrimes		/*
11101590Srgrimes		 * save column offset if not truncated
11111590Srgrimes		 */
11121590Srgrimes		*cps += col;
11131590Srgrimes		*mor = 1;
11141590Srgrimes	}
11151590Srgrimes
11161590Srgrimes	return(col);
11171590Srgrimes}
11181590Srgrimes
11191590Srgrimes/*
11201590Srgrimes * otln():	output a line of data. (Supports unlimited length lines)
11211590Srgrimes *		output is optionally contracted to tabs
11221590Srgrimes *
11231590Srgrimes *	buf:	output buffer with data
11241590Srgrimes *	cnt:	number of chars of valid data in buf
11251590Srgrimes *	svips:	buffer input column position (for large lines)
11261590Srgrimes *	svops:	buffer output column position (for large lines)
11278874Srgrimes *	mor:	output line not complete in this buf; more data to come.
11281590Srgrimes *		1 is more, 0 is complete, -1 is no \n's
11291590Srgrimes */
11301590Srgrimesint
113198552Smarkmotln(char *buf, int cnt, int *svips, int *svops, int mor)
11321590Srgrimes{
113398552Smarkm	int ops;		/* last col output */
113498552Smarkm	int ips;		/* last col in buf examined */
113598552Smarkm	int gap = ogap;
113698552Smarkm	int tbps;
113798552Smarkm	char *endbuf;
11381590Srgrimes
11391590Srgrimes	if (ogap) {
11401590Srgrimes		/*
11411590Srgrimes		 * contracting on output
11421590Srgrimes		 */
11431590Srgrimes		endbuf = buf + cnt;
11441590Srgrimes		ops = *svops;
11451590Srgrimes		ips = *svips;
11461590Srgrimes		while (buf < endbuf) {
11471590Srgrimes			/*
11481590Srgrimes			 * count number of spaces and ochar in buffer
11491590Srgrimes			 */
11501590Srgrimes			if (*buf == ' ') {
11511590Srgrimes				++ips;
11521590Srgrimes				++buf;
11531590Srgrimes				continue;
11541590Srgrimes			}
11551590Srgrimes
11561590Srgrimes			/*
11571590Srgrimes			 * simulate ochar processing
11581590Srgrimes			 */
11591590Srgrimes			if (*buf == ochar) {
11601590Srgrimes				ips += gap - (ips % gap);
11611590Srgrimes				++buf;
11621590Srgrimes				continue;
11631590Srgrimes			}
11641590Srgrimes
11651590Srgrimes			/*
11661590Srgrimes			 * got a non space char; contract out spaces
11671590Srgrimes			 */
116898408Stjr			while (ips - ops > 1) {
11691590Srgrimes				/*
11701590Srgrimes				 * use as many ochar as will fit
11711590Srgrimes				 */
11721590Srgrimes				if ((tbps = ops + gap - (ops % gap)) > ips)
11731590Srgrimes					break;
11741590Srgrimes				if (putchar(ochar) == EOF) {
11751590Srgrimes					pfail();
11761590Srgrimes					return(1);
11771590Srgrimes				}
11781590Srgrimes				ops = tbps;
11791590Srgrimes			}
11801590Srgrimes
11811590Srgrimes			while (ops < ips) {
11821590Srgrimes				/*
11831590Srgrimes				 * finish off with spaces
11841590Srgrimes				 */
11851590Srgrimes				if (putchar(' ') == EOF) {
11861590Srgrimes					pfail();
11871590Srgrimes					return(1);
11881590Srgrimes				}
11891590Srgrimes				++ops;
11901590Srgrimes			}
11911590Srgrimes
11921590Srgrimes			/*
11931590Srgrimes			 * output non space char
11941590Srgrimes			 */
11951590Srgrimes			if (putchar(*buf++) == EOF) {
11961590Srgrimes				pfail();
11971590Srgrimes				return(1);
11981590Srgrimes			}
11991590Srgrimes			++ips;
12001590Srgrimes			++ops;
12011590Srgrimes		}
12021590Srgrimes
12031590Srgrimes		if (mor > 0) {
12041590Srgrimes			/*
12051590Srgrimes			 * if incomplete line, save position counts
12061590Srgrimes			 */
12071590Srgrimes			*svops = ops;
12081590Srgrimes			*svips = ips;
12091590Srgrimes			return(0);
12101590Srgrimes		}
12111590Srgrimes
12121590Srgrimes		if (mor < 0) {
121398408Stjr			while (ips - ops > 1) {
12141590Srgrimes				/*
12151590Srgrimes				 * use as many ochar as will fit
12161590Srgrimes				 */
12171590Srgrimes				if ((tbps = ops + gap - (ops % gap)) > ips)
12181590Srgrimes					break;
12191590Srgrimes				if (putchar(ochar) == EOF) {
12201590Srgrimes					pfail();
12211590Srgrimes					return(1);
12221590Srgrimes				}
12231590Srgrimes				ops = tbps;
12241590Srgrimes			}
12251590Srgrimes			while (ops < ips) {
12261590Srgrimes				/*
12271590Srgrimes				 * finish off with spaces
12281590Srgrimes				 */
12291590Srgrimes				if (putchar(' ') == EOF) {
12301590Srgrimes					pfail();
12311590Srgrimes					return(1);
12321590Srgrimes				}
12331590Srgrimes				++ops;
12341590Srgrimes			}
12351590Srgrimes			return(0);
12361590Srgrimes		}
12371590Srgrimes	} else {
12381590Srgrimes		/*
12391590Srgrimes		 * output is not contracted
12401590Srgrimes		 */
12411590Srgrimes		if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) {
12421590Srgrimes			pfail();
12431590Srgrimes			return(1);
12441590Srgrimes		}
12451590Srgrimes		if (mor != 0)
12461590Srgrimes			return(0);
12471590Srgrimes	}
12481590Srgrimes
12491590Srgrimes	/*
12501590Srgrimes	 * process line end and double space as required
12511590Srgrimes	 */
12521590Srgrimes	if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) {
12531590Srgrimes		pfail();
12541590Srgrimes		return(1);
12551590Srgrimes	}
12561590Srgrimes	return(0);
12571590Srgrimes}
12581590Srgrimes
12591590Srgrimes/*
12601590Srgrimes * inskip():	skip over pgcnt pages with lncnt lines per page
12611590Srgrimes *		file is closed at EOF (if not stdin).
12621590Srgrimes *
12631590Srgrimes *	inf	FILE * to read from
12641590Srgrimes *	pgcnt	number of pages to skip
12651590Srgrimes *	lncnt	number of lines per page
12661590Srgrimes */
12671590Srgrimesint
126898552Smarkminskip(FILE *inf, int pgcnt, int lncnt)
12691590Srgrimes{
127098552Smarkm	int c;
127198552Smarkm	int cnt;
12721590Srgrimes
12731590Srgrimes	while(--pgcnt > 0) {
12741590Srgrimes		cnt = lncnt;
12751590Srgrimes		while ((c = getc(inf)) != EOF) {
12761590Srgrimes			if ((c == '\n') && (--cnt == 0))
12771590Srgrimes				break;
12781590Srgrimes		}
12791590Srgrimes		if (c == EOF) {
12801590Srgrimes			if (inf != stdin)
12811590Srgrimes				(void)fclose(inf);
12821590Srgrimes			return(1);
12831590Srgrimes		}
12841590Srgrimes	}
12851590Srgrimes	return(0);
12861590Srgrimes}
12871590Srgrimes
12881590Srgrimes/*
12891590Srgrimes * nxtfile:	returns a FILE * to next file in arg list and sets the
12901590Srgrimes *		time field for this file (or current date).
12911590Srgrimes *
12921590Srgrimes *	buf	array to store proper date for the header.
12931590Srgrimes *	dt	if set skips the date processing (used with -m)
12941590Srgrimes */
12951590SrgrimesFILE *
1296102944Sdwmalonenxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
12971590Srgrimes{
12981590Srgrimes	FILE *inf = NULL;
129937262Sbde	time_t tv_sec;
13001590Srgrimes	struct tm *timeptr = NULL;
13011590Srgrimes	struct stat statbuf;
13021590Srgrimes	static int twice = -1;
13031590Srgrimes
13041590Srgrimes	++twice;
13051590Srgrimes	if (eoptind >= argc) {
13061590Srgrimes		/*
13071590Srgrimes		 * no file listed; default, use standard input
13081590Srgrimes		 */
13091590Srgrimes		if (twice)
13101590Srgrimes			return(NULL);
13111590Srgrimes		clearerr(stdin);
13121590Srgrimes		inf = stdin;
13131590Srgrimes		if (header != NULL)
13141590Srgrimes			*fname = header;
13151590Srgrimes		else
131698552Smarkm			*fname = fnamedefault;
13171590Srgrimes		if (nohead)
13181590Srgrimes			return(inf);
1319204358Sed		if ((tv_sec = time(NULL)) == -1) {
13201590Srgrimes			++errcnt;
13211590Srgrimes			(void)fprintf(err, "pr: cannot get time of day, %s\n",
13221590Srgrimes				strerror(errno));
13231590Srgrimes			eoptind = argc - 1;
13241590Srgrimes			return(NULL);
13251590Srgrimes		}
132637262Sbde		timeptr = localtime(&tv_sec);
13271590Srgrimes	}
13281590Srgrimes	for (; eoptind < argc; ++eoptind) {
13291590Srgrimes		if (strcmp(argv[eoptind], "-") == 0) {
13301590Srgrimes			/*
13311590Srgrimes			 * process a "-" for filename
13321590Srgrimes			 */
13331590Srgrimes			clearerr(stdin);
13341590Srgrimes			inf = stdin;
13351590Srgrimes			if (header != NULL)
13361590Srgrimes				*fname = header;
13371590Srgrimes			else
133898552Smarkm				*fname = fnamedefault;
13391590Srgrimes			++eoptind;
13401590Srgrimes			if (nohead || (dt && twice))
13411590Srgrimes				return(inf);
1342204358Sed			if ((tv_sec = time(NULL)) == -1) {
13431590Srgrimes				++errcnt;
13441590Srgrimes				(void)fprintf(err,
13451590Srgrimes					"pr: cannot get time of day, %s\n",
13461590Srgrimes					strerror(errno));
13471590Srgrimes				return(NULL);
13481590Srgrimes			}
134937262Sbde			timeptr = localtime(&tv_sec);
13501590Srgrimes		} else {
13511590Srgrimes			/*
13521590Srgrimes			 * normal file processing
13531590Srgrimes			 */
13541590Srgrimes			if ((inf = fopen(argv[eoptind], "r")) == NULL) {
13551590Srgrimes				++errcnt;
13561590Srgrimes				if (nodiag)
13571590Srgrimes					continue;
1358132672Scharnier				(void)fprintf(err, "pr: cannot open %s, %s\n",
13591590Srgrimes					argv[eoptind], strerror(errno));
13601590Srgrimes				continue;
13611590Srgrimes			}
13621590Srgrimes			if (header != NULL)
13631590Srgrimes				*fname = header;
13641590Srgrimes			else if (dt)
136598552Smarkm				*fname = fnamedefault;
13661590Srgrimes			else
13671590Srgrimes				*fname = argv[eoptind];
13681590Srgrimes			++eoptind;
13691590Srgrimes			if (nohead || (dt && twice))
13701590Srgrimes				return(inf);
13711590Srgrimes
13721590Srgrimes			if (dt) {
1373204358Sed				if ((tv_sec = time(NULL)) == -1) {
13741590Srgrimes					++errcnt;
13751590Srgrimes					(void)fprintf(err,
13761590Srgrimes					     "pr: cannot get time of day, %s\n",
13771590Srgrimes					     strerror(errno));
1378317439Sasomers					fclose(inf);
13791590Srgrimes					return(NULL);
13801590Srgrimes				}
138137262Sbde				timeptr = localtime(&tv_sec);
13821590Srgrimes			} else {
13831590Srgrimes				if (fstat(fileno(inf), &statbuf) < 0) {
13841590Srgrimes					++errcnt;
13851590Srgrimes					(void)fclose(inf);
13868874Srgrimes					(void)fprintf(err,
1387132672Scharnier						"pr: cannot stat %s, %s\n",
13881590Srgrimes						argv[eoptind], strerror(errno));
13891590Srgrimes					return(NULL);
13901590Srgrimes				}
13911590Srgrimes				timeptr = localtime(&(statbuf.st_mtime));
13921590Srgrimes			}
13931590Srgrimes		}
13941590Srgrimes		break;
13951590Srgrimes	}
13961590Srgrimes	if (inf == NULL)
13971590Srgrimes		return(NULL);
13981590Srgrimes
13991590Srgrimes	/*
14001590Srgrimes	 * set up time field used in header
14011590Srgrimes	 */
14021590Srgrimes	if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) {
14031590Srgrimes		++errcnt;
14041590Srgrimes		if (inf != stdin)
14051590Srgrimes			(void)fclose(inf);
14061590Srgrimes		(void)fputs("pr: time conversion failed\n", err);
14071590Srgrimes		return(NULL);
14081590Srgrimes	}
14091590Srgrimes	return(inf);
14101590Srgrimes}
14111590Srgrimes
14121590Srgrimes/*
14131590Srgrimes * addnum():	adds the line number to the column
14141590Srgrimes *		Truncates from the front or pads with spaces as required.
14151590Srgrimes *		Numbers are right justified.
14161590Srgrimes *
14171590Srgrimes *	buf	buffer to store the number
14181590Srgrimes *	wdth	width of buffer to fill
14191590Srgrimes *	line	line number
14201590Srgrimes *
14211590Srgrimes *		NOTE: numbers occupy part of the column. The posix
14221590Srgrimes *		spec does not specify if -i processing should or should not
14231590Srgrimes *		occur on number padding. The spec does say it occupies
14241590Srgrimes *		part of the column. The usage of addnum	currently treats
14251590Srgrimes *		numbers as part of the column so spaces may be replaced.
14261590Srgrimes */
14271590Srgrimesvoid
142898552Smarkmaddnum(char *buf, int wdth, int line)
14291590Srgrimes{
143098552Smarkm	char *pt = buf + wdth;
14311590Srgrimes
14321590Srgrimes	do {
14331590Srgrimes		*--pt = digs[line % 10];
14341590Srgrimes		line /= 10;
14351590Srgrimes	} while (line && (pt > buf));
14361590Srgrimes
14371590Srgrimes	/*
14381590Srgrimes	 * pad with space as required
14391590Srgrimes	 */
14401590Srgrimes	while (pt > buf)
14411590Srgrimes		*--pt = ' ';
14421590Srgrimes}
14431590Srgrimes
14441590Srgrimes/*
14451590Srgrimes * prhead():	prints the top of page header
14461590Srgrimes *
14471590Srgrimes *	buf	buffer with time field (and offset)
14481590Srgrimes *	cnt	number of chars in buf
14491590Srgrimes *	fname	fname field for header
14501590Srgrimes *	pagcnt	page number
14511590Srgrimes */
14521590Srgrimesint
1453102944Sdwmaloneprhead(char *buf, const char *fname, int pagcnt)
14541590Srgrimes{
14551590Srgrimes	int ips = 0;
14561590Srgrimes	int ops = 0;
14571590Srgrimes
14581590Srgrimes	if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) {
14591590Srgrimes		pfail();
14601590Srgrimes		return(1);
14611590Srgrimes	}
14621590Srgrimes	/*
14631590Srgrimes	 * posix is not clear if the header is subject to line length
14641590Srgrimes	 * restrictions. The specification for header line format
14651590Srgrimes	 * in the spec clearly does not limit length. No pr currently
14661590Srgrimes	 * restricts header length. However if we need to truncate in
1467108470Sschweikh	 * a reasonable way, adjust the length of the printf by
1468151701Sjhb	 * changing HDFMT to allow a length max as an argument to printf.
14691590Srgrimes	 * buf (which contains the offset spaces and time field could
14701590Srgrimes	 * also be trimmed
14711590Srgrimes	 *
14721590Srgrimes	 * note only the offset (if any) is processed for tab expansion
14731590Srgrimes	 */
14741590Srgrimes	if (offst && otln(buf, offst, &ips, &ops, -1))
14751590Srgrimes		return(1);
14761590Srgrimes	(void)printf(HDFMT,buf+offst, fname, pagcnt);
14771590Srgrimes	return(0);
14781590Srgrimes}
14791590Srgrimes
14801590Srgrimes/*
14811590Srgrimes * prtail():	pad page with empty lines (if required) and print page trailer
14821590Srgrimes *		if requested
14831590Srgrimes *
14841590Srgrimes *	cnt	number of lines of padding needed
14851590Srgrimes *	incomp	was a '\n' missing from last line output
14861590Srgrimes */
14871590Srgrimesint
148898552Smarkmprtail(int cnt, int incomp)
14891590Srgrimes{
14901590Srgrimes	if (nohead) {
14911590Srgrimes		/*
14921590Srgrimes		 * only pad with no headers when incomplete last line
14931590Srgrimes		 */
149419092Sscrappy		if (incomp &&
149519092Sscrappy		    ((dspace && (putchar('\n') == EOF)) ||
149619092Sscrappy		     (putchar('\n') == EOF))) {
14971590Srgrimes			pfail();
14981590Srgrimes			return(1);
14991590Srgrimes		}
150019092Sscrappy		/*
150119092Sscrappy		 * but honor the formfeed request
150219092Sscrappy		 */
150319092Sscrappy		if (formfeed) {
150419092Sscrappy			if (putchar('\f') == EOF) {
150519092Sscrappy				pfail();
150619092Sscrappy				return(1);
150719092Sscrappy			}
150819092Sscrappy		}
15091590Srgrimes		return(0);
15101590Srgrimes	}
15111590Srgrimes	/*
15121590Srgrimes	 * if double space output two \n
15131590Srgrimes	 */
15141590Srgrimes	if (dspace)
15151590Srgrimes		cnt *= 2;
15161590Srgrimes
15171590Srgrimes	/*
15181590Srgrimes	 * if an odd number of lines per page, add an extra \n
15191590Srgrimes	 */
15201590Srgrimes	if (addone)
15211590Srgrimes		++cnt;
15221590Srgrimes
15231590Srgrimes	/*
15241590Srgrimes	 * pad page
15251590Srgrimes	 */
15261590Srgrimes	if (formfeed) {
15278874Srgrimes		if ((incomp && (putchar('\n') == EOF)) ||
15281590Srgrimes		    (putchar('\f') == EOF)) {
15291590Srgrimes			pfail();
15301590Srgrimes			return(1);
15311590Srgrimes		}
15321590Srgrimes		return(0);
15338874Srgrimes	}
15341590Srgrimes	cnt += TAILLEN;
15351590Srgrimes	while (--cnt >= 0) {
15361590Srgrimes		if (putchar('\n') == EOF) {
15371590Srgrimes			pfail();
15381590Srgrimes			return(1);
15391590Srgrimes		}
15401590Srgrimes	}
15411590Srgrimes	return(0);
15421590Srgrimes}
15431590Srgrimes
15441590Srgrimes/*
15451590Srgrimes * terminate():	when a SIGINT is recvd
15461590Srgrimes */
15471590Srgrimesvoid
154898552Smarkmterminate(int which_sig __unused)
15491590Srgrimes{
15501590Srgrimes	flsh_errs();
15511590Srgrimes	exit(1);
15521590Srgrimes}
15531590Srgrimes
15541590Srgrimes
15551590Srgrimes/*
15561590Srgrimes * flsh_errs():	output saved up diagnostic messages after all normal
15571590Srgrimes *		processing has completed
15581590Srgrimes */
15591590Srgrimesvoid
156098552Smarkmflsh_errs(void)
15611590Srgrimes{
15621590Srgrimes	char buf[BUFSIZ];
15631590Srgrimes
15641590Srgrimes	(void)fflush(stdout);
15651590Srgrimes	(void)fflush(err);
15661590Srgrimes	if (err == stderr)
15671590Srgrimes		return;
15681590Srgrimes	rewind(err);
15691590Srgrimes	while (fgets(buf, BUFSIZ, err) != NULL)
15701590Srgrimes		(void)fputs(buf, stderr);
15711590Srgrimes}
15721590Srgrimes
15731590Srgrimesvoid
157498552Smarkmmfail(void)
15751590Srgrimes{
15761590Srgrimes	(void)fputs("pr: memory allocation failed\n", err);
15771590Srgrimes}
15781590Srgrimes
15791590Srgrimesvoid
158098552Smarkmpfail(void)
15811590Srgrimes{
15821590Srgrimes	(void)fprintf(err, "pr: write failure, %s\n", strerror(errno));
15831590Srgrimes}
15841590Srgrimes
15851590Srgrimesvoid
158698552Smarkmusage(void)
15871590Srgrimes{
15881590Srgrimes	(void)fputs(
158993481Sjmallett	 "usage: pr [+page] [-col] [-adFfmprt] [-e[ch][gap]] [-h header]\n",
159093481Sjmallett	 err);
15911590Srgrimes	(void)fputs(
15921590Srgrimes	 "          [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err);
15931590Srgrimes	(void)fputs(
159453955Sache	 "          [-L locale] [-s[ch]] [-w width] [-] [file ...]\n", err);
15951590Srgrimes}
15961590Srgrimes
15971590Srgrimes/*
15988874Srgrimes * setup:	Validate command args, initialize and perform sanity
15991590Srgrimes *		checks on options
16001590Srgrimes */
16011590Srgrimesint
160298552Smarkmsetup(int argc, char *argv[])
16031590Srgrimes{
160498552Smarkm	int c;
160574575Sache	int d_first;
16061590Srgrimes	int eflag = 0;
16071590Srgrimes	int iflag = 0;
16081590Srgrimes	int wflag = 0;
16091590Srgrimes	int cflag = 0;
161053955Sache	char *Lflag = NULL;
16111590Srgrimes
16121590Srgrimes	if (isatty(fileno(stdout))) {
16131590Srgrimes		/*
16141590Srgrimes		 * defer diagnostics until processing is done
16151590Srgrimes		 */
16161590Srgrimes		if ((err = tmpfile()) == NULL) {
161790788Sjedgar		       err = stderr;
16181590Srgrimes		       (void)fputs("Cannot defer diagnostic messages\n",stderr);
16191590Srgrimes		       return(1);
16201590Srgrimes		}
16211590Srgrimes	} else
16221590Srgrimes		err = stderr;
162393481Sjmallett	while ((c = egetopt(argc, argv, "#adFfmrte?h:i?L:l:n?o:ps?w:")) != -1) {
16241590Srgrimes		switch (c) {
16251590Srgrimes		case '+':
16261590Srgrimes			if ((pgnm = atoi(eoptarg)) < 1) {
16271590Srgrimes			    (void)fputs("pr: +page number must be 1 or more\n",
16281590Srgrimes				err);
16291590Srgrimes			    return(1);
16301590Srgrimes			}
16311590Srgrimes			break;
16321590Srgrimes		case '-':
16331590Srgrimes			if ((clcnt = atoi(eoptarg)) < 1) {
16341590Srgrimes			    (void)fputs("pr: -columns must be 1 or more\n",err);
16351590Srgrimes			    return(1);
16361590Srgrimes			}
16371590Srgrimes			if (clcnt > 1)
16381590Srgrimes				++cflag;
16391590Srgrimes			break;
16401590Srgrimes		case 'a':
16411590Srgrimes			++across;
16421590Srgrimes			break;
16431590Srgrimes		case 'd':
16441590Srgrimes			++dspace;
16451590Srgrimes			break;
16461590Srgrimes		case 'e':
16471590Srgrimes			++eflag;
164853948Sache			if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
16491590Srgrimes				inchar = *eoptarg++;
16501590Srgrimes			else
16511590Srgrimes				inchar = INCHAR;
165253948Sache			if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
16531590Srgrimes				if ((ingap = atoi(eoptarg)) < 0) {
16541590Srgrimes					(void)fputs(
16551590Srgrimes					"pr: -e gap must be 0 or more\n", err);
16561590Srgrimes					return(1);
16571590Srgrimes				}
16581590Srgrimes				if (ingap == 0)
16591590Srgrimes					ingap = INGAP;
16601590Srgrimes			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
16611590Srgrimes				(void)fprintf(err,
16621590Srgrimes				      "pr: invalid value for -e %s\n", eoptarg);
16631590Srgrimes				return(1);
16641590Srgrimes			} else
16651590Srgrimes				ingap = INGAP;
16661590Srgrimes			break;
166793481Sjmallett		case 'f':
166893481Sjmallett			++pausefst;
166993481Sjmallett			/*FALLTHROUGH*/
16701590Srgrimes		case 'F':
16711590Srgrimes			++formfeed;
16721590Srgrimes			break;
16731590Srgrimes		case 'h':
16741590Srgrimes			header = eoptarg;
16751590Srgrimes			break;
16761590Srgrimes		case 'i':
16771590Srgrimes			++iflag;
167853948Sache			if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
16791590Srgrimes				ochar = *eoptarg++;
16801590Srgrimes			else
16811590Srgrimes				ochar = OCHAR;
168253948Sache			if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
16831590Srgrimes				if ((ogap = atoi(eoptarg)) < 0) {
16841590Srgrimes					(void)fputs(
16851590Srgrimes					"pr: -i gap must be 0 or more\n", err);
16861590Srgrimes					return(1);
16871590Srgrimes				}
16881590Srgrimes				if (ogap == 0)
16891590Srgrimes					ogap = OGAP;
16901590Srgrimes			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
16911590Srgrimes				(void)fprintf(err,
16921590Srgrimes				      "pr: invalid value for -i %s\n", eoptarg);
16931590Srgrimes				return(1);
16941590Srgrimes			} else
16951590Srgrimes				ogap = OGAP;
16961590Srgrimes			break;
169753948Sache		case 'L':
169853955Sache			Lflag = eoptarg;
169953948Sache			break;
17001590Srgrimes		case 'l':
170153948Sache			if (!isdigit((unsigned char)*eoptarg) || ((lines=atoi(eoptarg)) < 1)) {
17021590Srgrimes				(void)fputs(
1703132672Scharnier				 "pr: number of lines must be 1 or more\n",err);
17041590Srgrimes				return(1);
17051590Srgrimes			}
17061590Srgrimes			break;
17071590Srgrimes		case 'm':
17081590Srgrimes			++merge;
17091590Srgrimes			break;
17101590Srgrimes		case 'n':
171153948Sache			if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
17121590Srgrimes				nmchar = *eoptarg++;
17131590Srgrimes			else
17141590Srgrimes				nmchar = NMCHAR;
171553948Sache			if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
17161590Srgrimes				if ((nmwd = atoi(eoptarg)) < 1) {
17171590Srgrimes					(void)fputs(
17181590Srgrimes					"pr: -n width must be 1 or more\n",err);
17191590Srgrimes					return(1);
17201590Srgrimes				}
17211590Srgrimes			} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
17221590Srgrimes				(void)fprintf(err,
17231590Srgrimes				      "pr: invalid value for -n %s\n", eoptarg);
17241590Srgrimes				return(1);
17251590Srgrimes			} else
17261590Srgrimes				nmwd = NMWD;
17271590Srgrimes			break;
17281590Srgrimes		case 'o':
172953948Sache			if (!isdigit((unsigned char)*eoptarg) || ((offst = atoi(eoptarg))< 1)){
17301590Srgrimes				(void)fputs("pr: -o offset must be 1 or more\n",
17311590Srgrimes					err);
17321590Srgrimes				return(1);
17331590Srgrimes			}
17341590Srgrimes			break;
173593481Sjmallett		case 'p':
173693481Sjmallett			++pauseall;
173793481Sjmallett			break;
17381590Srgrimes		case 'r':
17391590Srgrimes			++nodiag;
17401590Srgrimes			break;
17411590Srgrimes		case 's':
17421590Srgrimes			++sflag;
17431590Srgrimes			if (eoptarg == NULL)
17441590Srgrimes				schar = SCHAR;
174554114Skris			else {
17461590Srgrimes				schar = *eoptarg++;
174754114Skris				if (*eoptarg != '\0') {
174854114Skris					(void)fprintf(err,
174954114Skris					    "pr: invalid value for -s %s\n",
175054114Skris					    eoptarg);
175154114Skris					return(1);
175254114Skris				}
17531590Srgrimes			}
17541590Srgrimes			break;
17551590Srgrimes		case 't':
17561590Srgrimes			++nohead;
17571590Srgrimes			break;
17581590Srgrimes		case 'w':
17591590Srgrimes			++wflag;
1760317439Sasomers			if ((eoptarg == NULL ) ||
1761317439Sasomers			    !isdigit((unsigned char)*eoptarg) ||
1762317439Sasomers			    ((pgwd = atoi(eoptarg)) < 1)){
17631590Srgrimes				(void)fputs(
17641590Srgrimes				   "pr: -w width must be 1 or more \n",err);
17651590Srgrimes				return(1);
17661590Srgrimes			}
17671590Srgrimes			break;
17681590Srgrimes		case '?':
17691590Srgrimes		default:
17701590Srgrimes			return(1);
17711590Srgrimes		}
17721590Srgrimes	}
17731590Srgrimes
17741590Srgrimes	/*
17751590Srgrimes	 * default and sanity checks
17761590Srgrimes	 */
17771590Srgrimes	if (!clcnt) {
17781590Srgrimes		if (merge) {
17791590Srgrimes			if ((clcnt = argc - eoptind) <= 1) {
17801590Srgrimes				clcnt = CLCNT;
17811590Srgrimes				merge = 0;
17821590Srgrimes			}
17831590Srgrimes		} else
17841590Srgrimes			clcnt = CLCNT;
17851590Srgrimes	}
17861590Srgrimes	if (across) {
17871590Srgrimes		if (clcnt == 1) {
17881590Srgrimes			(void)fputs("pr: -a flag requires multiple columns\n",
17891590Srgrimes				err);
17901590Srgrimes			return(1);
17911590Srgrimes		}
17921590Srgrimes		if (merge) {
17931590Srgrimes			(void)fputs("pr: -m cannot be used with -a\n", err);
17941590Srgrimes			return(1);
17951590Srgrimes		}
17961590Srgrimes	}
17971590Srgrimes	if (!wflag) {
17981590Srgrimes		if (sflag)
17991590Srgrimes			pgwd = SPGWD;
18001590Srgrimes		else
18011590Srgrimes			pgwd = PGWD;
18021590Srgrimes	}
18031590Srgrimes	if (cflag || merge) {
18041590Srgrimes		if (!eflag) {
18051590Srgrimes			inchar = INCHAR;
18061590Srgrimes			ingap = INGAP;
18071590Srgrimes		}
18081590Srgrimes		if (!iflag) {
18091590Srgrimes			ochar = OCHAR;
18101590Srgrimes			ogap = OGAP;
18111590Srgrimes		}
18121590Srgrimes	}
18131590Srgrimes	if (cflag) {
18141590Srgrimes		if (merge) {
18151590Srgrimes			(void)fputs(
18161590Srgrimes			  "pr: -m cannot be used with multiple columns\n", err);
18171590Srgrimes			return(1);
18181590Srgrimes		}
18191590Srgrimes		if (nmwd) {
18201590Srgrimes			colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt;
18211590Srgrimes			pgwd = ((colwd + nmwd + 2) * clcnt) - 1;
18221590Srgrimes		} else {
18231590Srgrimes			colwd = (pgwd + 1 - clcnt)/clcnt;
18241590Srgrimes			pgwd = ((colwd + 1) * clcnt) - 1;
18251590Srgrimes		}
18261590Srgrimes		if (colwd < 1) {
18271590Srgrimes			(void)fprintf(err,
18281590Srgrimes			  "pr: page width is too small for %d columns\n",clcnt);
18291590Srgrimes			return(1);
18301590Srgrimes		}
18311590Srgrimes	}
18321590Srgrimes	if (!lines)
18331590Srgrimes		lines = LINES;
18341590Srgrimes
18351590Srgrimes	/*
18361590Srgrimes	 * make sure long enough for headers. if not disable
18371590Srgrimes	 */
18381590Srgrimes	if (lines <= HEADLEN + TAILLEN)
18398874Srgrimes		++nohead;
18401590Srgrimes	else if (!nohead)
18411590Srgrimes		lines -= HEADLEN + TAILLEN;
18421590Srgrimes
18431590Srgrimes	/*
18441590Srgrimes	 * adjust for double space on odd length pages
18451590Srgrimes	 */
18461590Srgrimes	if (dspace) {
18471590Srgrimes		if (lines == 1)
18481590Srgrimes			dspace = 0;
18491590Srgrimes		else {
18501590Srgrimes			if (lines & 1)
18511590Srgrimes				++addone;
18521590Srgrimes			lines /= 2;
18531590Srgrimes		}
18541590Srgrimes	}
18551590Srgrimes
185653955Sache	(void) setlocale(LC_TIME, (Lflag != NULL) ? Lflag : "");
185753948Sache
185874575Sache	d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
185998552Smarkm	timefrmt = strdup(d_first ? TIMEFMTD : TIMEFMTM);
186074575Sache
18611590Srgrimes	return(0);
18621590Srgrimes}
1863