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