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