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