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