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