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