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