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