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