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