1 /* $NetBSD: pr.c,v 1.20 2009/04/13 00:37:05 lukem 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\ 39 The Regents of the University of California. All rights reserved."); 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.20 2009/04/13 00:37:05 lukem 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 #include <util.h> 63 64 #include "pr.h" 65 #include "extern.h" 66 67 /* 68 * pr: a printing and pagination filter. If multiple input files 69 * are specified, each is read, formatted, and written to standard 70 * output. By default, input is separated into 66-line pages, each 71 * with a header that includes the page number, date, time and the 72 * files pathname. 73 * 74 * Complies with posix P1003.2/D11 75 */ 76 77 /* 78 * parameter variables 79 */ 80 int pgnm; /* starting page number */ 81 int clcnt; /* number of columns */ 82 int colwd; /* column data width - multiple columns */ 83 int across; /* mult col flag; write across page */ 84 int dspace; /* double space flag */ 85 char inchar; /* expand input char */ 86 int ingap; /* expand input gap */ 87 int formfeed; /* use formfeed as trailer */ 88 char *header; /* header name instead of file name */ 89 char ochar; /* contract output char */ 90 int ogap; /* contract output gap */ 91 int lines; /* number of lines per page */ 92 int merge; /* merge multiple files in output */ 93 char nmchar; /* line numbering append char */ 94 int nmwd; /* width of line number field */ 95 int offst; /* number of page offset spaces */ 96 int nodiag; /* do not report file open errors */ 97 char schar; /* text column separation character */ 98 int sflag; /* -s option for multiple columns */ 99 int nohead; /* do not write head and trailer */ 100 int pgwd; /* page width with multiple col output */ 101 const char *timefrmt = TIMEFMT; /* time conversion string */ 102 103 /* 104 * misc globals 105 */ 106 FILE *err; /* error message file pointer */ 107 int addone; /* page length is odd with double space */ 108 int errcnt; /* error count on file processing */ 109 char digs[] = "0123456789"; /* page number translation map */ 110 111 int main __P((int, char **)); 112 113 int 114 main(argc, argv) 115 int argc; 116 char *argv[]; 117 { 118 int ret_val; 119 120 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 121 (void)signal(SIGINT, terminate); 122 ret_val = setup(argc, argv); 123 if (!ret_val) { 124 /* 125 * select the output format based on options 126 */ 127 if (merge) 128 ret_val = mulfile(argc, argv); 129 else if (clcnt == 1) 130 ret_val = onecol(argc, argv); 131 else if (across) 132 ret_val = horzcol(argc, argv); 133 else 134 ret_val = vertcol(argc, argv); 135 } else 136 usage(); 137 flsh_errs(); 138 if (errcnt || ret_val) 139 exit(1); 140 return(0); 141 } 142 143 /* 144 * onecol: print files with only one column of output. 145 * Line length is unlimited. 146 */ 147 int 148 onecol(argc, argv) 149 int argc; 150 char *argv[]; 151 { 152 int cnt = -1; 153 int off; 154 int lrgln; 155 int linecnt; 156 int num; 157 int lncnt; 158 int pagecnt; 159 int ips; 160 int ops; 161 int cps; 162 char *obuf = NULL; 163 char *lbuf; 164 char *nbuf; 165 char *hbuf = NULL; 166 char *ohbuf; 167 FILE *inf = NULL; 168 const char *fname; 169 int mor; 170 int error = 1; 171 172 if (nmwd) 173 num = nmwd + 1; 174 else 175 num = 0; 176 off = num + offst; 177 178 /* 179 * allocate line buffer 180 */ 181 if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) 182 goto oomem; 183 /* 184 * allocate header buffer 185 */ 186 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) 187 goto oomem; 188 189 ohbuf = hbuf + offst; 190 nbuf = obuf + offst; 191 lbuf = nbuf + num; 192 if (num) 193 nbuf[--num] = nmchar; 194 if (offst) { 195 (void)memset(obuf, (int)' ', offst); 196 (void)memset(hbuf, (int)' ', offst); 197 } 198 199 /* 200 * loop by file 201 */ 202 while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 203 if (pgnm) { 204 /* 205 * skip to specified page 206 */ 207 if (inskip(inf, pgnm, lines)) 208 continue; 209 pagecnt = pgnm; 210 } else 211 pagecnt = 1; 212 lncnt = 0; 213 214 /* 215 * loop by page 216 */ 217 for(;;) { 218 linecnt = 0; 219 lrgln = 0; 220 ops = 0; 221 ips = 0; 222 cps = 0; 223 224 /* 225 * loop by line 226 */ 227 while (linecnt < lines) { 228 /* 229 * input next line 230 */ 231 if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0) 232 break; 233 if (!linecnt && !nohead && 234 prhead(hbuf, fname, pagecnt)) 235 goto out; 236 237 /* 238 * start of new line. 239 */ 240 if (!lrgln) { 241 if (num) 242 addnum(nbuf, num, ++lncnt); 243 if (otln(obuf,cnt+off, &ips, &ops, mor)) 244 goto out; 245 } else if (otln(lbuf, cnt, &ips, &ops, mor)) 246 goto out; 247 248 /* 249 * if line bigger than buffer, get more 250 */ 251 if (mor) { 252 lrgln = 1; 253 continue; 254 } 255 256 /* 257 * whole line rcvd. reset tab proc. state 258 */ 259 ++linecnt; 260 lrgln = 0; 261 ops = 0; 262 ips = 0; 263 } 264 265 /* 266 * fill to end of page 267 */ 268 if (linecnt && prtail(lines-linecnt-lrgln, lrgln)) 269 goto out; 270 271 /* 272 * On EOF go to next file 273 */ 274 if (cnt < 0) 275 break; 276 ++pagecnt; 277 } 278 if (inf != stdin) 279 (void)fclose(inf); 280 } 281 if (eoptind < argc) 282 goto out; 283 error = 0; 284 goto out; 285 oomem: 286 mfail(); 287 out: 288 if (obuf) 289 free(obuf); 290 if (hbuf) 291 free(hbuf); 292 if (inf != NULL && inf != stdin) 293 (void)fclose(inf); 294 return error; 295 } 296 297 /* 298 * vertcol: print files with more than one column of output down a page 299 */ 300 int 301 vertcol(argc, argv) 302 int argc; 303 char *argv[]; 304 { 305 char *ptbf; 306 char **lstdat = NULL; 307 int i; 308 int j; 309 int cnt = -1; 310 int pln; 311 int *indy = NULL; 312 int cvc; 313 int *lindy = NULL; 314 int lncnt; 315 int stp; 316 int pagecnt; 317 int col = colwd + 1; 318 int mxlen = pgwd + offst + 1; 319 int mclcnt = clcnt - 1; 320 struct vcol *vc = NULL; 321 int mvc; 322 int tvc; 323 int cw = nmwd + 1; 324 int fullcol; 325 char *buf = NULL; 326 char *hbuf = NULL; 327 char *ohbuf; 328 const char *fname; 329 FILE *inf = NULL; 330 int ips = 0; 331 int cps = 0; 332 int ops = 0; 333 int mor = 0; 334 int error = 1; 335 336 /* 337 * allocate page buffer 338 */ 339 if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) 340 goto oomem; 341 342 /* 343 * allocate page header 344 */ 345 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) 346 goto oomem; 347 ohbuf = hbuf + offst; 348 if (offst) 349 (void)memset(hbuf, (int)' ', offst); 350 351 /* 352 * col pointers when no headers 353 */ 354 mvc = lines * clcnt; 355 if ((vc = malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) 356 goto oomem; 357 358 /* 359 * pointer into page where last data per line is located 360 */ 361 if ((lstdat = malloc((unsigned)lines*sizeof(char *))) == NULL) 362 goto oomem; 363 364 /* 365 * fast index lookups to locate start of lines 366 */ 367 if ((indy = malloc((unsigned)lines*sizeof(int))) == NULL) 368 goto oomem; 369 if ((lindy = malloc((unsigned)lines*sizeof(int))) == NULL) 370 goto oomem; 371 372 if (nmwd) 373 fullcol = col + cw; 374 else 375 fullcol = col; 376 377 /* 378 * initialize buffer lookup indexes and offset area 379 */ 380 for (j = 0; j < lines; ++j) { 381 lindy[j] = j * mxlen; 382 indy[j] = lindy[j] + offst; 383 if (offst) { 384 ptbf = buf + lindy[j]; 385 (void)memset(ptbf, (int)' ', offst); 386 ptbf += offst; 387 } else 388 ptbf = buf + indy[j]; 389 lstdat[j] = ptbf; 390 } 391 392 /* 393 * loop by file 394 */ 395 while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 396 if (pgnm) { 397 /* 398 * skip to requested page 399 */ 400 if (inskip(inf, pgnm, lines)) 401 continue; 402 pagecnt = pgnm; 403 } else 404 pagecnt = 1; 405 lncnt = 0; 406 407 /* 408 * loop by page 409 */ 410 for(;;) { 411 /* 412 * loop by column 413 */ 414 cvc = 0; 415 for (i = 0; i < clcnt; ++i) { 416 j = 0; 417 /* 418 * if last column, do not pad 419 */ 420 if (i == mclcnt) 421 stp = 1; 422 else 423 stp = 0; 424 /* 425 * loop by line 426 */ 427 for(;;) { 428 /* 429 * is this first column 430 */ 431 if (!i) { 432 ptbf = buf + indy[j]; 433 lstdat[j] = ptbf; 434 } else 435 ptbf = lstdat[j]; 436 vc[cvc].pt = ptbf; 437 438 /* 439 * add number 440 */ 441 if (nmwd) { 442 addnum(ptbf, nmwd, ++lncnt); 443 ptbf += nmwd; 444 *ptbf++ = nmchar; 445 } 446 447 /* 448 * input next line 449 */ 450 cnt = inln(inf,ptbf,colwd,&cps,1,&mor); 451 vc[cvc++].cnt = cnt; 452 if (cnt < 0) 453 break; 454 ptbf += cnt; 455 456 /* 457 * pad all but last column on page 458 */ 459 if (!stp) { 460 /* 461 * pad to end of column 462 */ 463 if (sflag) 464 *ptbf++ = schar; 465 else if ((pln = col-cnt) > 0) { 466 (void)memset(ptbf, 467 (int)' ',pln); 468 ptbf += pln; 469 } 470 } 471 /* 472 * remember last char in line 473 */ 474 lstdat[j] = ptbf; 475 if (++j >= lines) 476 break; 477 } 478 if (cnt < 0) 479 break; 480 } 481 482 /* 483 * when -t (no header) is specified the spec requires 484 * the min number of lines. The last page may not have 485 * balanced length columns. To fix this we must reorder 486 * the columns. This is a very slow technique so it is 487 * only used under limited conditions. Without -t, the 488 * balancing of text columns is unspecified. To NOT 489 * balance the last page, add the global variable 490 * nohead to the if statement below e.g. 491 * 492 * if ((cnt < 0) && nohead && cvc ...... 493 */ 494 --cvc; 495 496 /* 497 * check to see if last page needs to be reordered 498 */ 499 if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){ 500 pln = cvc/clcnt; 501 if (cvc % clcnt) 502 ++pln; 503 504 /* 505 * print header 506 */ 507 if (!nohead && prhead(hbuf, fname, pagecnt)) 508 goto out; 509 for (i = 0; i < pln; ++i) { 510 ips = 0; 511 ops = 0; 512 if (offst&& otln(buf,offst,&ips,&ops,1)) { 513 error = 1; 514 goto out; 515 } 516 tvc = i; 517 518 for (j = 0; j < clcnt; ++j) { 519 /* 520 * determine column length 521 */ 522 if (j == mclcnt) { 523 /* 524 * last column 525 */ 526 cnt = vc[tvc].cnt; 527 if (nmwd) 528 cnt += cw; 529 } else if (sflag) { 530 /* 531 * single ch between 532 */ 533 cnt = vc[tvc].cnt + 1; 534 if (nmwd) 535 cnt += cw; 536 } else 537 cnt = fullcol; 538 if (otln(vc[tvc].pt, cnt, &ips, 539 &ops, 1)) 540 goto out; 541 tvc += pln; 542 if (tvc >= cvc) 543 break; 544 } 545 /* 546 * terminate line 547 */ 548 if (otln(buf, 0, &ips, &ops, 0)) 549 goto out; 550 } 551 /* 552 * pad to end of page 553 */ 554 if (prtail((lines - pln), 0)) 555 goto out; 556 /* 557 * done with output, go to next file 558 */ 559 break; 560 } 561 562 /* 563 * determine how many lines to output 564 */ 565 if (i > 0) 566 pln = lines; 567 else 568 pln = j; 569 570 /* 571 * print header 572 */ 573 if (pln && !nohead && prhead(hbuf, fname, pagecnt)) 574 goto out; 575 576 /* 577 * output each line 578 */ 579 for (i = 0; i < pln; ++i) { 580 ptbf = buf + lindy[i]; 581 if ((j = lstdat[i] - ptbf) <= offst) 582 break; 583 if (otln(ptbf, j, &ips, &ops, 0)) 584 goto out; 585 } 586 587 /* 588 * pad to end of page 589 */ 590 if (pln && prtail((lines - pln), 0)) 591 goto out; 592 593 /* 594 * if EOF go to next file 595 */ 596 if (cnt < 0) 597 break; 598 ++pagecnt; 599 } 600 if (inf != stdin) 601 (void)fclose(inf); 602 } 603 if (eoptind < argc) 604 goto out; 605 error = 0; 606 goto out; 607 oomem: 608 mfail(); 609 out: 610 if (buf) 611 free(buf); 612 if (hbuf) 613 free(hbuf); 614 if (vc) 615 free(vc); 616 if (lstdat) 617 free(lstdat); 618 if (indy) 619 free(lindy); 620 if (inf != NULL && inf != stdin) 621 (void)fclose(inf); 622 return error; 623 } 624 625 /* 626 * horzcol: print files with more than one column of output across a page 627 */ 628 int 629 horzcol(argc, argv) 630 int argc; 631 char *argv[]; 632 { 633 char *ptbf; 634 int pln; 635 int cnt = -1; 636 char *lstdat; 637 int col = colwd + 1; 638 int j; 639 int i; 640 int lncnt; 641 int pagecnt; 642 char *buf = NULL; 643 char *hbuf = NULL; 644 char *ohbuf; 645 const char *fname; 646 FILE *inf = NULL; 647 int ips = 0; 648 int cps = 0; 649 int ops = 0; 650 int mor = 0; 651 int error = 1; 652 653 if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) 654 goto oomem; 655 656 /* 657 * page header 658 */ 659 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) 660 goto oomem; 661 ohbuf = hbuf + offst; 662 if (offst) { 663 (void)memset(buf, (int)' ', offst); 664 (void)memset(hbuf, (int)' ', offst); 665 } 666 667 /* 668 * loop by file 669 */ 670 while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 671 if (pgnm) { 672 if (inskip(inf, pgnm, lines)) 673 continue; 674 pagecnt = pgnm; 675 } else 676 pagecnt = 1; 677 lncnt = 0; 678 679 /* 680 * loop by page 681 */ 682 for(;;) { 683 /* 684 * loop by line 685 */ 686 for (i = 0; i < lines; ++i) { 687 ptbf = buf + offst; 688 lstdat = ptbf; 689 j = 0; 690 /* 691 * loop by col 692 */ 693 for(;;) { 694 if (nmwd) { 695 /* 696 * add number to column 697 */ 698 addnum(ptbf, nmwd, ++lncnt); 699 ptbf += nmwd; 700 *ptbf++ = nmchar; 701 } 702 /* 703 * input line 704 */ 705 if ((cnt = inln(inf,ptbf,colwd,&cps,1, 706 &mor)) < 0) 707 break; 708 ptbf += cnt; 709 lstdat = ptbf; 710 711 /* 712 * if last line skip padding 713 */ 714 if (++j >= clcnt) 715 break; 716 717 /* 718 * pad to end of column 719 */ 720 if (sflag) 721 *ptbf++ = schar; 722 else if ((pln = col - cnt) > 0) { 723 (void)memset(ptbf,(int)' ',pln); 724 ptbf += pln; 725 } 726 } 727 728 /* 729 * determine line length 730 */ 731 if ((j = lstdat - buf) <= offst) 732 break; 733 if (!i && !nohead && 734 prhead(hbuf, fname, pagecnt)) 735 goto out; 736 /* 737 * output line 738 */ 739 if (otln(buf, j, &ips, &ops, 0)) 740 goto out; 741 } 742 743 /* 744 * pad to end of page 745 */ 746 if (i && prtail(lines-i, 0)) 747 goto out; 748 749 /* 750 * if EOF go to next file 751 */ 752 if (cnt < 0) 753 break; 754 ++pagecnt; 755 } 756 if (inf != stdin) 757 (void)fclose(inf); 758 } 759 if (eoptind < argc) 760 goto out; 761 error = 0; 762 goto out; 763 oomem: 764 mfail(); 765 out: 766 if (buf) 767 free(buf); 768 if (hbuf) 769 free(hbuf); 770 if (inf != NULL && inf != stdin) 771 (void)fclose(inf); 772 return error; 773 } 774 775 /* 776 * mulfile: print files with more than one column of output and 777 * more than one file concurrently 778 */ 779 int 780 mulfile(argc, argv) 781 int argc; 782 char *argv[]; 783 { 784 char *ptbf; 785 int j; 786 int pln; 787 int cnt; 788 char *lstdat; 789 int i; 790 FILE **fbuf = NULL; 791 int actf; 792 int lncnt; 793 int col; 794 int pagecnt; 795 int fproc; 796 char *buf = NULL; 797 char *hbuf = NULL; 798 char *ohbuf; 799 const char *fname; 800 int ips = 0; 801 int cps = 0; 802 int ops = 0; 803 int mor = 0; 804 int error = 1; 805 806 /* 807 * array of FILE *, one for each operand 808 */ 809 if ((fbuf = calloc(clcnt, sizeof(FILE *))) == NULL) 810 goto oomem; 811 812 /* 813 * page header 814 */ 815 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) 816 goto oomem; 817 ohbuf = hbuf + offst; 818 819 /* 820 * do not know how many columns yet. The number of operands provide an 821 * upper bound on the number of columns. We use the number of files 822 * we can open successfully to set the number of columns. The operation 823 * of the merge operation (-m) in relation to unsuccesful file opens 824 * is unspecified by posix. 825 */ 826 j = 0; 827 while (j < clcnt) { 828 if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL) 829 break; 830 if (pgnm && (inskip(fbuf[j], pgnm, lines))) 831 fbuf[j] = NULL; 832 ++j; 833 } 834 835 /* 836 * if no files, exit 837 */ 838 if (!j) 839 goto out; 840 841 /* 842 * calculate page boundries based on open file count 843 */ 844 clcnt = j; 845 if (nmwd) { 846 colwd = (pgwd - clcnt - nmwd)/clcnt; 847 pgwd = ((colwd + 1) * clcnt) - nmwd - 2; 848 } else { 849 colwd = (pgwd + 1 - clcnt)/clcnt; 850 pgwd = ((colwd + 1) * clcnt) - 1; 851 } 852 if (colwd < 1) { 853 (void)fprintf(err, 854 "pr: page width too small for %d columns\n", clcnt); 855 goto out; 856 } 857 actf = clcnt; 858 col = colwd + 1; 859 860 /* 861 * line buffer 862 */ 863 if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) 864 goto out; 865 if (offst) { 866 (void)memset(buf, (int)' ', offst); 867 (void)memset(hbuf, (int)' ', offst); 868 } 869 if (pgnm) 870 pagecnt = pgnm; 871 else 872 pagecnt = 1; 873 lncnt = 0; 874 875 /* 876 * continue to loop while any file still has data 877 */ 878 while (actf > 0) { 879 /* 880 * loop by line 881 */ 882 for (i = 0; i < lines; ++i) { 883 ptbf = buf + offst; 884 lstdat = ptbf; 885 if (nmwd) { 886 /* 887 * add line number to line 888 */ 889 addnum(ptbf, nmwd, ++lncnt); 890 ptbf += nmwd; 891 *ptbf++ = nmchar; 892 } 893 j = 0; 894 fproc = 0; 895 896 /* 897 * loop by column 898 */ 899 for (j = 0; j < clcnt; ++j) { 900 if (fbuf[j] == NULL) { 901 /* 902 * empty column; EOF 903 */ 904 cnt = 0; 905 } else if ((cnt = inln(fbuf[j], ptbf, colwd, 906 &cps, 1, &mor)) < 0) { 907 /* 908 * EOF hit; no data 909 */ 910 if (fbuf[j] != stdin) 911 (void)fclose(fbuf[j]); 912 fbuf[j] = NULL; 913 --actf; 914 cnt = 0; 915 } else { 916 /* 917 * process file data 918 */ 919 ptbf += cnt; 920 lstdat = ptbf; 921 fproc++; 922 } 923 924 /* 925 * if last ACTIVE column, done with line 926 */ 927 if (fproc >= actf) 928 break; 929 930 /* 931 * pad to end of column 932 */ 933 if (sflag) { 934 *ptbf++ = schar; 935 } else if ((pln = col - cnt) > 0) { 936 (void)memset(ptbf, (int)' ', pln); 937 ptbf += pln; 938 } 939 } 940 941 /* 942 * calculate data in line 943 */ 944 if ((j = lstdat - buf) <= offst) 945 break; 946 947 if (!i && !nohead && prhead(hbuf, fname, pagecnt)) 948 goto out; 949 950 /* 951 * output line 952 */ 953 if (otln(buf, j, &ips, &ops, 0)) 954 goto out; 955 956 /* 957 * if no more active files, done 958 */ 959 if (actf <= 0) { 960 ++i; 961 break; 962 } 963 } 964 965 /* 966 * pad to end of page 967 */ 968 if (i && prtail(lines-i, 0)) 969 goto out; 970 ++pagecnt; 971 } 972 if (eoptind < argc) 973 goto out; 974 error = 0; 975 goto out; 976 oomem: 977 mfail(); 978 out: 979 if (fbuf) { 980 for (j = 0; j < clcnt; j++) 981 if (fbuf[j] && fbuf[j] != stdin) 982 (void)fclose(fbuf[j]); 983 free(fbuf); 984 } 985 if (hbuf) 986 free(hbuf); 987 if (buf) 988 free(buf); 989 return error; 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 const 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 const 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 argument 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 (void)raise_default_signal(which_sig); 1569 exit(1); 1570 } 1571 1572 1573 /* 1574 * flsh_errs(): output saved up diagnostic messages after all normal 1575 * processing has completed 1576 */ 1577 void 1578 flsh_errs() 1579 { 1580 char buf[BUFSIZ]; 1581 1582 (void)fflush(stdout); 1583 (void)fflush(err); 1584 if (err == stderr) 1585 return; 1586 rewind(err); 1587 while (fgets(buf, BUFSIZ, err) != NULL) 1588 (void)fputs(buf, stderr); 1589 } 1590 1591 void 1592 mfail() 1593 { 1594 (void)fputs("pr: memory allocation failed\n", err); 1595 } 1596 1597 void 1598 pfail() 1599 { 1600 (void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); 1601 } 1602 1603 void 1604 usage() 1605 { 1606 (void)fputs( 1607 "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err); 1608 (void)fputs( 1609 " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); 1610 (void)fputs( 1611 " [-s[ch]] [-w width] [-] [file ...]\n", err); 1612 } 1613 1614 /* 1615 * setup: Validate command args, initialize and perform sanity 1616 * checks on options 1617 */ 1618 int 1619 setup(argc, argv) 1620 int argc; 1621 char **argv; 1622 { 1623 int c; 1624 int eflag = 0; 1625 int iflag = 0; 1626 int wflag = 0; 1627 int cflag = 0; 1628 1629 if (isatty(fileno(stdout))) { 1630 /* 1631 * defer diagnostics until processing is done 1632 */ 1633 if ((err = tmpfile()) == NULL) { 1634 (void)fputs("Cannot defer diagnostic messages\n",stderr); 1635 return(1); 1636 } 1637 } else 1638 err = stderr; 1639 while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?T:w:")) != -1) { 1640 switch (c) { 1641 case '+': 1642 if ((pgnm = atoi(eoptarg)) < 1) { 1643 (void)fputs("pr: +page number must be 1 or more\n", 1644 err); 1645 return(1); 1646 } 1647 break; 1648 case '-': 1649 if ((clcnt = atoi(eoptarg)) < 1) { 1650 (void)fputs("pr: -columns must be 1 or more\n",err); 1651 return(1); 1652 } 1653 if (clcnt > 1) 1654 ++cflag; 1655 break; 1656 case 'a': 1657 ++across; 1658 break; 1659 case 'd': 1660 ++dspace; 1661 break; 1662 case 'e': 1663 ++eflag; 1664 if ((eoptarg != NULL) && 1665 !isdigit((unsigned char)*eoptarg)) 1666 inchar = *eoptarg++; 1667 else 1668 inchar = INCHAR; 1669 if ((eoptarg != NULL) && 1670 isdigit((unsigned char)*eoptarg)) { 1671 if ((ingap = atoi(eoptarg)) < 0) { 1672 (void)fputs( 1673 "pr: -e gap must be 0 or more\n", err); 1674 return(1); 1675 } 1676 if (ingap == 0) 1677 ingap = INGAP; 1678 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 1679 (void)fprintf(err, 1680 "pr: invalid value for -e %s\n", eoptarg); 1681 return(1); 1682 } else 1683 ingap = INGAP; 1684 break; 1685 case 'F': 1686 ++formfeed; 1687 break; 1688 case 'h': 1689 header = eoptarg; 1690 break; 1691 case 'i': 1692 ++iflag; 1693 if ((eoptarg != NULL) && 1694 !isdigit((unsigned char)*eoptarg)) 1695 ochar = *eoptarg++; 1696 else 1697 ochar = OCHAR; 1698 if ((eoptarg != NULL) && 1699 isdigit((unsigned char)*eoptarg)) { 1700 if ((ogap = atoi(eoptarg)) < 0) { 1701 (void)fputs( 1702 "pr: -i gap must be 0 or more\n", err); 1703 return(1); 1704 } 1705 if (ogap == 0) 1706 ogap = OGAP; 1707 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 1708 (void)fprintf(err, 1709 "pr: invalid value for -i %s\n", eoptarg); 1710 return(1); 1711 } else 1712 ogap = OGAP; 1713 break; 1714 case 'l': 1715 if (!isdigit((unsigned char)*eoptarg) || 1716 ((lines=atoi(eoptarg)) < 1)) { 1717 (void)fputs( 1718 "pr: Number of lines must be 1 or more\n",err); 1719 return(1); 1720 } 1721 break; 1722 case 'm': 1723 ++merge; 1724 break; 1725 case 'n': 1726 if ((eoptarg != NULL) && 1727 !isdigit((unsigned char)*eoptarg)) 1728 nmchar = *eoptarg++; 1729 else 1730 nmchar = NMCHAR; 1731 if ((eoptarg != NULL) && 1732 isdigit((unsigned char)*eoptarg)) { 1733 if ((nmwd = atoi(eoptarg)) < 1) { 1734 (void)fputs( 1735 "pr: -n width must be 1 or more\n",err); 1736 return(1); 1737 } 1738 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 1739 (void)fprintf(err, 1740 "pr: invalid value for -n %s\n", eoptarg); 1741 return(1); 1742 } else 1743 nmwd = NMWD; 1744 break; 1745 case 'o': 1746 if (!isdigit((unsigned char)*eoptarg) || 1747 ((offst = atoi(eoptarg))< 1)){ 1748 (void)fputs("pr: -o offset must be 1 or more\n", 1749 err); 1750 return(1); 1751 } 1752 break; 1753 case 'r': 1754 ++nodiag; 1755 break; 1756 case 's': 1757 ++sflag; 1758 if (eoptarg == NULL) 1759 schar = SCHAR; 1760 else 1761 schar = *eoptarg++; 1762 if (eoptarg && *eoptarg != '\0') { 1763 (void)fprintf(err, 1764 "pr: invalid value for -s %s\n", eoptarg); 1765 return(1); 1766 } 1767 break; 1768 case 'T': 1769 timefrmt = eoptarg; 1770 break; 1771 case 't': 1772 ++nohead; 1773 break; 1774 case 'w': 1775 ++wflag; 1776 if (!isdigit((unsigned char)*eoptarg) || 1777 ((pgwd = atoi(eoptarg)) < 1)){ 1778 (void)fputs( 1779 "pr: -w width must be 1 or more \n",err); 1780 return(1); 1781 } 1782 break; 1783 case '?': 1784 default: 1785 return(1); 1786 } 1787 } 1788 1789 /* 1790 * default and sanity checks 1791 */ 1792 if (!clcnt) { 1793 if (merge) { 1794 if ((clcnt = argc - eoptind) <= 1) { 1795 clcnt = CLCNT; 1796 merge = 0; 1797 } 1798 } else 1799 clcnt = CLCNT; 1800 } 1801 if (across) { 1802 if (clcnt == 1) { 1803 (void)fputs("pr: -a flag requires multiple columns\n", 1804 err); 1805 return(1); 1806 } 1807 if (merge) { 1808 (void)fputs("pr: -m cannot be used with -a\n", err); 1809 return(1); 1810 } 1811 } 1812 if (!wflag) { 1813 if (sflag) 1814 pgwd = SPGWD; 1815 else 1816 pgwd = PGWD; 1817 } 1818 if (cflag || merge) { 1819 if (!eflag) { 1820 inchar = INCHAR; 1821 ingap = INGAP; 1822 } 1823 if (!iflag) { 1824 ochar = OCHAR; 1825 ogap = OGAP; 1826 } 1827 } 1828 if (cflag) { 1829 if (merge) { 1830 (void)fputs( 1831 "pr: -m cannot be used with multiple columns\n", err); 1832 return(1); 1833 } 1834 if (nmwd) { 1835 colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; 1836 pgwd = ((colwd + nmwd + 2) * clcnt) - 1; 1837 } else { 1838 colwd = (pgwd + 1 - clcnt)/clcnt; 1839 pgwd = ((colwd + 1) * clcnt) - 1; 1840 } 1841 if (colwd < 1) { 1842 (void)fprintf(err, 1843 "pr: page width is too small for %d columns\n",clcnt); 1844 return(1); 1845 } 1846 } 1847 if (!lines) 1848 lines = LINES; 1849 1850 /* 1851 * make sure long enough for headers. if not disable 1852 */ 1853 if (lines <= HEADLEN + TAILLEN) 1854 ++nohead; 1855 else if (!nohead) 1856 lines -= HEADLEN + TAILLEN; 1857 1858 /* 1859 * adjust for double space on odd length pages 1860 */ 1861 if (dspace) { 1862 if (lines == 1) 1863 dspace = 0; 1864 else { 1865 if (lines & 1) 1866 ++addone; 1867 lines /= 2; 1868 } 1869 } 1870 1871 return(0); 1872 } 1873