]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/pr/pr.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 static int      pgnm;           /* starting page number */
84 static int      clcnt;          /* number of columns */
85 static int      colwd;          /* column data width - multiple columns */
86 static int      across;         /* mult col flag; write across page */
87 static int      dspace;         /* double space flag */
88 static char     inchar;         /* expand input char */
89 static int      ingap;          /* expand input gap */
90 static int      pausefst;       /* Pause before first page */
91 static int      pauseall;       /* Pause before each page */
92 static int      formfeed;       /* use formfeed as trailer */
93 static char     *header;        /* header name instead of file name */
94 static char     ochar;          /* contract output char */
95 static int      ogap;           /* contract output gap */
96 static int      lines;          /* number of lines per page */
97 static int      merge;          /* merge multiple files in output */
98 static char     nmchar;         /* line numbering append char */
99 static int      nmwd;           /* width of line number field */
100 static int      offst;          /* number of page offset spaces */
101 static int      nodiag;         /* do not report file open errors */
102 static char     schar;          /* text column separation character */
103 static int      sflag;          /* -s option for multiple columns */
104 static int      nohead;         /* do not write head and trailer */
105 static int      pgwd;           /* page width with multiple col output */
106 static const char *timefrmt;    /* time conversion string */
107
108 /*
109  * misc globals
110  */
111 static FILE     *err;           /* error message file pointer */
112 static int      addone;         /* page length is odd with double space */
113 static int      errcnt;         /* error count on file processing */
114 static char     digs[] = "0123456789"; /* page number translation map */
115
116 static 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 unsuccessful 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 boundaries 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 position 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         time_t tv_sec;
1269         struct tm *timeptr = NULL;
1270         struct stat statbuf;
1271         static int twice = -1;
1272
1273         ++twice;
1274         if (eoptind >= argc) {
1275                 /*
1276                  * no file listed; default, use standard input
1277                  */
1278                 if (twice)
1279                         return(NULL);
1280                 clearerr(stdin);
1281                 inf = stdin;
1282                 if (header != NULL)
1283                         *fname = header;
1284                 else
1285                         *fname = fnamedefault;
1286                 if (nohead)
1287                         return(inf);
1288                 if ((tv_sec = time(NULL)) == -1) {
1289                         ++errcnt;
1290                         (void)fprintf(err, "pr: cannot get time of day, %s\n",
1291                                 strerror(errno));
1292                         eoptind = argc - 1;
1293                         return(NULL);
1294                 }
1295                 timeptr = localtime(&tv_sec);
1296         }
1297         for (; eoptind < argc; ++eoptind) {
1298                 if (strcmp(argv[eoptind], "-") == 0) {
1299                         /*
1300                          * process a "-" for filename
1301                          */
1302                         clearerr(stdin);
1303                         inf = stdin;
1304                         if (header != NULL)
1305                                 *fname = header;
1306                         else
1307                                 *fname = fnamedefault;
1308                         ++eoptind;
1309                         if (nohead || (dt && twice))
1310                                 return(inf);
1311                         if ((tv_sec = time(NULL)) == -1) {
1312                                 ++errcnt;
1313                                 (void)fprintf(err,
1314                                         "pr: cannot get time of day, %s\n",
1315                                         strerror(errno));
1316                                 return(NULL);
1317                         }
1318                         timeptr = localtime(&tv_sec);
1319                 } else {
1320                         /*
1321                          * normal file processing
1322                          */
1323                         if ((inf = fopen(argv[eoptind], "r")) == NULL) {
1324                                 ++errcnt;
1325                                 if (nodiag)
1326                                         continue;
1327                                 (void)fprintf(err, "pr: cannot open %s, %s\n",
1328                                         argv[eoptind], strerror(errno));
1329                                 continue;
1330                         }
1331                         if (header != NULL)
1332                                 *fname = header;
1333                         else if (dt)
1334                                 *fname = fnamedefault;
1335                         else
1336                                 *fname = argv[eoptind];
1337                         ++eoptind;
1338                         if (nohead || (dt && twice))
1339                                 return(inf);
1340
1341                         if (dt) {
1342                                 if ((tv_sec = time(NULL)) == -1) {
1343                                         ++errcnt;
1344                                         (void)fprintf(err,
1345                                              "pr: cannot get time of day, %s\n",
1346                                              strerror(errno));
1347                                         return(NULL);
1348                                 }
1349                                 timeptr = localtime(&tv_sec);
1350                         } else {
1351                                 if (fstat(fileno(inf), &statbuf) < 0) {
1352                                         ++errcnt;
1353                                         (void)fclose(inf);
1354                                         (void)fprintf(err,
1355                                                 "pr: cannot stat %s, %s\n",
1356                                                 argv[eoptind], strerror(errno));
1357                                         return(NULL);
1358                                 }
1359                                 timeptr = localtime(&(statbuf.st_mtime));
1360                         }
1361                 }
1362                 break;
1363         }
1364         if (inf == NULL)
1365                 return(NULL);
1366
1367         /*
1368          * set up time field used in header
1369          */
1370         if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) {
1371                 ++errcnt;
1372                 if (inf != stdin)
1373                         (void)fclose(inf);
1374                 (void)fputs("pr: time conversion failed\n", err);
1375                 return(NULL);
1376         }
1377         return(inf);
1378 }
1379
1380 /*
1381  * addnum():    adds the line number to the column
1382  *              Truncates from the front or pads with spaces as required.
1383  *              Numbers are right justified.
1384  *
1385  *      buf     buffer to store the number
1386  *      wdth    width of buffer to fill
1387  *      line    line number
1388  *
1389  *              NOTE: numbers occupy part of the column. The posix
1390  *              spec does not specify if -i processing should or should not
1391  *              occur on number padding. The spec does say it occupies
1392  *              part of the column. The usage of addnum currently treats
1393  *              numbers as part of the column so spaces may be replaced.
1394  */
1395 void
1396 addnum(char *buf, int wdth, int line)
1397 {
1398         char *pt = buf + wdth;
1399
1400         do {
1401                 *--pt = digs[line % 10];
1402                 line /= 10;
1403         } while (line && (pt > buf));
1404
1405         /*
1406          * pad with space as required
1407          */
1408         while (pt > buf)
1409                 *--pt = ' ';
1410 }
1411
1412 /*
1413  * prhead():    prints the top of page header
1414  *
1415  *      buf     buffer with time field (and offset)
1416  *      cnt     number of chars in buf
1417  *      fname   fname field for header
1418  *      pagcnt  page number
1419  */
1420 int
1421 prhead(char *buf, const char *fname, int pagcnt)
1422 {
1423         int ips = 0;
1424         int ops = 0;
1425
1426         if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) {
1427                 pfail();
1428                 return(1);
1429         }
1430         /*
1431          * posix is not clear if the header is subject to line length
1432          * restrictions. The specification for header line format
1433          * in the spec clearly does not limit length. No pr currently
1434          * restricts header length. However if we need to truncate in
1435          * a reasonable way, adjust the length of the printf by
1436          * changing HDFMT to allow a length max as an argument to printf.
1437          * buf (which contains the offset spaces and time field could
1438          * also be trimmed
1439          *
1440          * note only the offset (if any) is processed for tab expansion
1441          */
1442         if (offst && otln(buf, offst, &ips, &ops, -1))
1443                 return(1);
1444         (void)printf(HDFMT,buf+offst, fname, pagcnt);
1445         return(0);
1446 }
1447
1448 /*
1449  * prtail():    pad page with empty lines (if required) and print page trailer
1450  *              if requested
1451  *
1452  *      cnt     number of lines of padding needed
1453  *      incomp  was a '\n' missing from last line output
1454  */
1455 int
1456 prtail(int cnt, int incomp)
1457 {
1458         if (nohead) {
1459                 /*
1460                  * only pad with no headers when incomplete last line
1461                  */
1462                 if (incomp &&
1463                     ((dspace && (putchar('\n') == EOF)) ||
1464                      (putchar('\n') == EOF))) {
1465                         pfail();
1466                         return(1);
1467                 }
1468                 /*
1469                  * but honor the formfeed request
1470                  */
1471                 if (formfeed) {
1472                         if (putchar('\f') == EOF) {
1473                                 pfail();
1474                                 return(1);
1475                         }
1476                 }
1477                 return(0);
1478         }
1479         /*
1480          * if double space output two \n
1481          */
1482         if (dspace)
1483                 cnt *= 2;
1484
1485         /*
1486          * if an odd number of lines per page, add an extra \n
1487          */
1488         if (addone)
1489                 ++cnt;
1490
1491         /*
1492          * pad page
1493          */
1494         if (formfeed) {
1495                 if ((incomp && (putchar('\n') == EOF)) ||
1496                     (putchar('\f') == EOF)) {
1497                         pfail();
1498                         return(1);
1499                 }
1500                 return(0);
1501         }
1502         cnt += TAILLEN;
1503         while (--cnt >= 0) {
1504                 if (putchar('\n') == EOF) {
1505                         pfail();
1506                         return(1);
1507                 }
1508         }
1509         return(0);
1510 }
1511
1512 /*
1513  * terminate(): when a SIGINT is recvd
1514  */
1515 void
1516 terminate(int which_sig __unused)
1517 {
1518         flsh_errs();
1519         exit(1);
1520 }
1521
1522
1523 /*
1524  * flsh_errs(): output saved up diagnostic messages after all normal
1525  *              processing has completed
1526  */
1527 void
1528 flsh_errs(void)
1529 {
1530         char buf[BUFSIZ];
1531
1532         (void)fflush(stdout);
1533         (void)fflush(err);
1534         if (err == stderr)
1535                 return;
1536         rewind(err);
1537         while (fgets(buf, BUFSIZ, err) != NULL)
1538                 (void)fputs(buf, stderr);
1539 }
1540
1541 void
1542 mfail(void)
1543 {
1544         (void)fputs("pr: memory allocation failed\n", err);
1545 }
1546
1547 void
1548 pfail(void)
1549 {
1550         (void)fprintf(err, "pr: write failure, %s\n", strerror(errno));
1551 }
1552
1553 void
1554 usage(void)
1555 {
1556         (void)fputs(
1557          "usage: pr [+page] [-col] [-adFfmprt] [-e[ch][gap]] [-h header]\n",
1558          err);
1559         (void)fputs(
1560          "          [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err);
1561         (void)fputs(
1562          "          [-L locale] [-s[ch]] [-w width] [-] [file ...]\n", err);
1563 }
1564
1565 /*
1566  * setup:       Validate command args, initialize and perform sanity
1567  *              checks on options
1568  */
1569 int
1570 setup(int argc, char *argv[])
1571 {
1572         int c;
1573         int d_first;
1574         int eflag = 0;
1575         int iflag = 0;
1576         int wflag = 0;
1577         int cflag = 0;
1578         char *Lflag = NULL;
1579
1580         if (isatty(fileno(stdout))) {
1581                 /*
1582                  * defer diagnostics until processing is done
1583                  */
1584                 if ((err = tmpfile()) == NULL) {
1585                        err = stderr;
1586                        (void)fputs("Cannot defer diagnostic messages\n",stderr);
1587                        return(1);
1588                 }
1589         } else
1590                 err = stderr;
1591         while ((c = egetopt(argc, argv, "#adFfmrte?h:i?L:l:n?o:ps?w:")) != -1) {
1592                 switch (c) {
1593                 case '+':
1594                         if ((pgnm = atoi(eoptarg)) < 1) {
1595                             (void)fputs("pr: +page number must be 1 or more\n",
1596                                 err);
1597                             return(1);
1598                         }
1599                         break;
1600                 case '-':
1601                         if ((clcnt = atoi(eoptarg)) < 1) {
1602                             (void)fputs("pr: -columns must be 1 or more\n",err);
1603                             return(1);
1604                         }
1605                         if (clcnt > 1)
1606                                 ++cflag;
1607                         break;
1608                 case 'a':
1609                         ++across;
1610                         break;
1611                 case 'd':
1612                         ++dspace;
1613                         break;
1614                 case 'e':
1615                         ++eflag;
1616                         if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
1617                                 inchar = *eoptarg++;
1618                         else
1619                                 inchar = INCHAR;
1620                         if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
1621                                 if ((ingap = atoi(eoptarg)) < 0) {
1622                                         (void)fputs(
1623                                         "pr: -e gap must be 0 or more\n", err);
1624                                         return(1);
1625                                 }
1626                                 if (ingap == 0)
1627                                         ingap = INGAP;
1628                         } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1629                                 (void)fprintf(err,
1630                                       "pr: invalid value for -e %s\n", eoptarg);
1631                                 return(1);
1632                         } else
1633                                 ingap = INGAP;
1634                         break;
1635                 case 'f':
1636                         ++pausefst;
1637                         /*FALLTHROUGH*/
1638                 case 'F':
1639                         ++formfeed;
1640                         break;
1641                 case 'h':
1642                         header = eoptarg;
1643                         break;
1644                 case 'i':
1645                         ++iflag;
1646                         if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
1647                                 ochar = *eoptarg++;
1648                         else
1649                                 ochar = OCHAR;
1650                         if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
1651                                 if ((ogap = atoi(eoptarg)) < 0) {
1652                                         (void)fputs(
1653                                         "pr: -i gap must be 0 or more\n", err);
1654                                         return(1);
1655                                 }
1656                                 if (ogap == 0)
1657                                         ogap = OGAP;
1658                         } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1659                                 (void)fprintf(err,
1660                                       "pr: invalid value for -i %s\n", eoptarg);
1661                                 return(1);
1662                         } else
1663                                 ogap = OGAP;
1664                         break;
1665                 case 'L':
1666                         Lflag = eoptarg;
1667                         break;
1668                 case 'l':
1669                         if (!isdigit((unsigned char)*eoptarg) || ((lines=atoi(eoptarg)) < 1)) {
1670                                 (void)fputs(
1671                                  "pr: number of lines must be 1 or more\n",err);
1672                                 return(1);
1673                         }
1674                         break;
1675                 case 'm':
1676                         ++merge;
1677                         break;
1678                 case 'n':
1679                         if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
1680                                 nmchar = *eoptarg++;
1681                         else
1682                                 nmchar = NMCHAR;
1683                         if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
1684                                 if ((nmwd = atoi(eoptarg)) < 1) {
1685                                         (void)fputs(
1686                                         "pr: -n width must be 1 or more\n",err);
1687                                         return(1);
1688                                 }
1689                         } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1690                                 (void)fprintf(err,
1691                                       "pr: invalid value for -n %s\n", eoptarg);
1692                                 return(1);
1693                         } else
1694                                 nmwd = NMWD;
1695                         break;
1696                 case 'o':
1697                         if (!isdigit((unsigned char)*eoptarg) || ((offst = atoi(eoptarg))< 1)){
1698                                 (void)fputs("pr: -o offset must be 1 or more\n",
1699                                         err);
1700                                 return(1);
1701                         }
1702                         break;
1703                 case 'p':
1704                         ++pauseall;
1705                         break;
1706                 case 'r':
1707                         ++nodiag;
1708                         break;
1709                 case 's':
1710                         ++sflag;
1711                         if (eoptarg == NULL)
1712                                 schar = SCHAR;
1713                         else {
1714                                 schar = *eoptarg++;
1715                                 if (*eoptarg != '\0') {
1716                                         (void)fprintf(err,
1717                                             "pr: invalid value for -s %s\n",
1718                                             eoptarg);
1719                                         return(1);
1720                                 }
1721                         }
1722                         break;
1723                 case 't':
1724                         ++nohead;
1725                         break;
1726                 case 'w':
1727                         ++wflag;
1728                         if (!isdigit((unsigned char)*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){
1729                                 (void)fputs(
1730                                    "pr: -w width must be 1 or more \n",err);
1731                                 return(1);
1732                         }
1733                         break;
1734                 case '?':
1735                 default:
1736                         return(1);
1737                 }
1738         }
1739
1740         /*
1741          * default and sanity checks
1742          */
1743         if (!clcnt) {
1744                 if (merge) {
1745                         if ((clcnt = argc - eoptind) <= 1) {
1746                                 clcnt = CLCNT;
1747                                 merge = 0;
1748                         }
1749                 } else
1750                         clcnt = CLCNT;
1751         }
1752         if (across) {
1753                 if (clcnt == 1) {
1754                         (void)fputs("pr: -a flag requires multiple columns\n",
1755                                 err);
1756                         return(1);
1757                 }
1758                 if (merge) {
1759                         (void)fputs("pr: -m cannot be used with -a\n", err);
1760                         return(1);
1761                 }
1762         }
1763         if (!wflag) {
1764                 if (sflag)
1765                         pgwd = SPGWD;
1766                 else
1767                         pgwd = PGWD;
1768         }
1769         if (cflag || merge) {
1770                 if (!eflag) {
1771                         inchar = INCHAR;
1772                         ingap = INGAP;
1773                 }
1774                 if (!iflag) {
1775                         ochar = OCHAR;
1776                         ogap = OGAP;
1777                 }
1778         }
1779         if (cflag) {
1780                 if (merge) {
1781                         (void)fputs(
1782                           "pr: -m cannot be used with multiple columns\n", err);
1783                         return(1);
1784                 }
1785                 if (nmwd) {
1786                         colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt;
1787                         pgwd = ((colwd + nmwd + 2) * clcnt) - 1;
1788                 } else {
1789                         colwd = (pgwd + 1 - clcnt)/clcnt;
1790                         pgwd = ((colwd + 1) * clcnt) - 1;
1791                 }
1792                 if (colwd < 1) {
1793                         (void)fprintf(err,
1794                           "pr: page width is too small for %d columns\n",clcnt);
1795                         return(1);
1796                 }
1797         }
1798         if (!lines)
1799                 lines = LINES;
1800
1801         /*
1802          * make sure long enough for headers. if not disable
1803          */
1804         if (lines <= HEADLEN + TAILLEN)
1805                 ++nohead;
1806         else if (!nohead)
1807                 lines -= HEADLEN + TAILLEN;
1808
1809         /*
1810          * adjust for double space on odd length pages
1811          */
1812         if (dspace) {
1813                 if (lines == 1)
1814                         dspace = 0;
1815                 else {
1816                         if (lines & 1)
1817                                 ++addone;
1818                         lines /= 2;
1819                 }
1820         }
1821
1822         (void) setlocale(LC_TIME, (Lflag != NULL) ? Lflag : "");
1823
1824         d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
1825         timefrmt = strdup(d_first ? TIMEFMTD : TIMEFMTM);
1826
1827         return(0);
1828 }