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