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