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