1 /* $NetBSD: pr.c,v 1.16 2006/05/24 15:59:06 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.16 2006/05/24 15:59:06 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 error = 1; 513 goto out; 514 } 515 tvc = i; 516 517 for (j = 0; j < clcnt; ++j) { 518 /* 519 * determine column length 520 */ 521 if (j == mclcnt) { 522 /* 523 * last column 524 */ 525 cnt = vc[tvc].cnt; 526 if (nmwd) 527 cnt += cw; 528 } else if (sflag) { 529 /* 530 * single ch between 531 */ 532 cnt = vc[tvc].cnt + 1; 533 if (nmwd) 534 cnt += cw; 535 } else 536 cnt = fullcol; 537 if (otln(vc[tvc].pt, cnt, &ips, 538 &ops, 1)) 539 goto out; 540 tvc += pln; 541 if (tvc >= cvc) 542 break; 543 } 544 /* 545 * terminate line 546 */ 547 if (otln(buf, 0, &ips, &ops, 0)) 548 goto out; 549 } 550 /* 551 * pad to end of page 552 */ 553 if (prtail((lines - pln), 0)) 554 goto out; 555 /* 556 * done with output, go to next file 557 */ 558 break; 559 } 560 561 /* 562 * determine how many lines to output 563 */ 564 if (i > 0) 565 pln = lines; 566 else 567 pln = j; 568 569 /* 570 * print header 571 */ 572 if (pln && !nohead && prhead(hbuf, fname, pagecnt)) 573 goto out; 574 575 /* 576 * output each line 577 */ 578 for (i = 0; i < pln; ++i) { 579 ptbf = buf + lindy[i]; 580 if ((j = lstdat[i] - ptbf) <= offst) 581 break; 582 if (otln(ptbf, j, &ips, &ops, 0)) 583 goto out; 584 } 585 586 /* 587 * pad to end of page 588 */ 589 if (pln && prtail((lines - pln), 0)) 590 goto out; 591 592 /* 593 * if EOF go to next file 594 */ 595 if (cnt < 0) 596 break; 597 ++pagecnt; 598 } 599 if (inf != stdin) 600 (void)fclose(inf); 601 } 602 if (eoptind < argc) 603 goto out; 604 error = 0; 605 goto out; 606 oomem: 607 mfail(); 608 out: 609 if (buf) 610 free(buf); 611 if (hbuf) 612 free(hbuf); 613 if (vc) 614 free(vc); 615 if (lstdat) 616 free(lstdat); 617 if (indy) 618 free(lindy); 619 if (inf != NULL && inf != stdin) 620 (void)fclose(inf); 621 return error; 622 } 623 624 /* 625 * horzcol: print files with more than one column of output across a page 626 */ 627 int 628 horzcol(argc, argv) 629 int argc; 630 char *argv[]; 631 { 632 char *ptbf; 633 int pln; 634 int cnt = -1; 635 char *lstdat; 636 int col = colwd + 1; 637 int j; 638 int i; 639 int lncnt; 640 int pagecnt; 641 char *buf = NULL; 642 char *hbuf = NULL; 643 char *ohbuf; 644 char *fname; 645 FILE *inf = NULL; 646 int ips = 0; 647 int cps = 0; 648 int ops = 0; 649 int mor = 0; 650 int error = 1; 651 652 if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) 653 goto oomem; 654 655 /* 656 * page header 657 */ 658 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) 659 goto oomem; 660 ohbuf = hbuf + offst; 661 if (offst) { 662 (void)memset(buf, (int)' ', offst); 663 (void)memset(hbuf, (int)' ', offst); 664 } 665 666 /* 667 * loop by file 668 */ 669 while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 670 if (pgnm) { 671 if (inskip(inf, pgnm, lines)) 672 continue; 673 pagecnt = pgnm; 674 } else 675 pagecnt = 1; 676 lncnt = 0; 677 678 /* 679 * loop by page 680 */ 681 for(;;) { 682 /* 683 * loop by line 684 */ 685 for (i = 0; i < lines; ++i) { 686 ptbf = buf + offst; 687 lstdat = ptbf; 688 j = 0; 689 /* 690 * loop by col 691 */ 692 for(;;) { 693 if (nmwd) { 694 /* 695 * add number to column 696 */ 697 addnum(ptbf, nmwd, ++lncnt); 698 ptbf += nmwd; 699 *ptbf++ = nmchar; 700 } 701 /* 702 * input line 703 */ 704 if ((cnt = inln(inf,ptbf,colwd,&cps,1, 705 &mor)) < 0) 706 break; 707 ptbf += cnt; 708 lstdat = ptbf; 709 710 /* 711 * if last line skip padding 712 */ 713 if (++j >= clcnt) 714 break; 715 716 /* 717 * pad to end of column 718 */ 719 if (sflag) 720 *ptbf++ = schar; 721 else if ((pln = col - cnt) > 0) { 722 (void)memset(ptbf,(int)' ',pln); 723 ptbf += pln; 724 } 725 } 726 727 /* 728 * determine line length 729 */ 730 if ((j = lstdat - buf) <= offst) 731 break; 732 if (!i && !nohead && 733 prhead(hbuf, fname, pagecnt)) 734 goto out; 735 /* 736 * output line 737 */ 738 if (otln(buf, j, &ips, &ops, 0)) 739 goto out; 740 } 741 742 /* 743 * pad to end of page 744 */ 745 if (i && prtail(lines-i, 0)) 746 goto out; 747 748 /* 749 * if EOF go to next file 750 */ 751 if (cnt < 0) 752 break; 753 ++pagecnt; 754 } 755 if (inf != stdin) 756 (void)fclose(inf); 757 } 758 if (eoptind < argc) 759 goto out; 760 error = 0; 761 goto out; 762 oomem: 763 mfail(); 764 out: 765 if (buf) 766 free(buf); 767 if (hbuf) 768 free(hbuf); 769 if (inf != NULL && inf != stdin) 770 (void)fclose(inf); 771 return error; 772 } 773 774 /* 775 * mulfile: print files with more than one column of output and 776 * more than one file concurrently 777 */ 778 int 779 mulfile(argc, argv) 780 int argc; 781 char *argv[]; 782 { 783 char *ptbf; 784 int j; 785 int pln; 786 int cnt; 787 char *lstdat; 788 int i; 789 FILE **fbuf = NULL; 790 int actf; 791 int lncnt; 792 int col; 793 int pagecnt; 794 int fproc; 795 char *buf = NULL; 796 char *hbuf = NULL; 797 char *ohbuf; 798 char *fname; 799 int ips = 0; 800 int cps = 0; 801 int ops = 0; 802 int mor = 0; 803 int error = 1; 804 805 /* 806 * array of FILE *, one for each operand 807 */ 808 if ((fbuf = calloc(clcnt, sizeof(FILE *))) == NULL) 809 goto oomem; 810 811 /* 812 * page header 813 */ 814 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) 815 goto oomem; 816 ohbuf = hbuf + offst; 817 818 /* 819 * do not know how many columns yet. The number of operands provide an 820 * upper bound on the number of columns. We use the number of files 821 * we can open successfully to set the number of columns. The operation 822 * of the merge operation (-m) in relation to unsuccesful file opens 823 * is unspecified by posix. 824 */ 825 j = 0; 826 while (j < clcnt) { 827 if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL) 828 break; 829 if (pgnm && (inskip(fbuf[j], pgnm, lines))) 830 fbuf[j] = NULL; 831 ++j; 832 } 833 834 /* 835 * if no files, exit 836 */ 837 if (!j) 838 goto out; 839 840 /* 841 * calculate page boundries based on open file count 842 */ 843 clcnt = j; 844 if (nmwd) { 845 colwd = (pgwd - clcnt - nmwd)/clcnt; 846 pgwd = ((colwd + 1) * clcnt) - nmwd - 2; 847 } else { 848 colwd = (pgwd + 1 - clcnt)/clcnt; 849 pgwd = ((colwd + 1) * clcnt) - 1; 850 } 851 if (colwd < 1) { 852 (void)fprintf(err, 853 "pr: page width too small for %d columns\n", clcnt); 854 goto out; 855 } 856 actf = clcnt; 857 col = colwd + 1; 858 859 /* 860 * line buffer 861 */ 862 if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) 863 goto out; 864 if (offst) { 865 (void)memset(buf, (int)' ', offst); 866 (void)memset(hbuf, (int)' ', offst); 867 } 868 if (pgnm) 869 pagecnt = pgnm; 870 else 871 pagecnt = 1; 872 lncnt = 0; 873 874 /* 875 * continue to loop while any file still has data 876 */ 877 while (actf > 0) { 878 /* 879 * loop by line 880 */ 881 for (i = 0; i < lines; ++i) { 882 ptbf = buf + offst; 883 lstdat = ptbf; 884 if (nmwd) { 885 /* 886 * add line number to line 887 */ 888 addnum(ptbf, nmwd, ++lncnt); 889 ptbf += nmwd; 890 *ptbf++ = nmchar; 891 } 892 j = 0; 893 fproc = 0; 894 895 /* 896 * loop by column 897 */ 898 for (j = 0; j < clcnt; ++j) { 899 if (fbuf[j] == NULL) { 900 /* 901 * empty column; EOF 902 */ 903 cnt = 0; 904 } else if ((cnt = inln(fbuf[j], ptbf, colwd, 905 &cps, 1, &mor)) < 0) { 906 /* 907 * EOF hit; no data 908 */ 909 if (fbuf[j] != stdin) 910 (void)fclose(fbuf[j]); 911 fbuf[j] = NULL; 912 --actf; 913 cnt = 0; 914 } else { 915 /* 916 * process file data 917 */ 918 ptbf += cnt; 919 lstdat = ptbf; 920 fproc++; 921 } 922 923 /* 924 * if last ACTIVE column, done with line 925 */ 926 if (fproc >= actf) 927 break; 928 929 /* 930 * pad to end of column 931 */ 932 if (sflag) { 933 *ptbf++ = schar; 934 } else if ((pln = col - cnt) > 0) { 935 (void)memset(ptbf, (int)' ', pln); 936 ptbf += pln; 937 } 938 } 939 940 /* 941 * calculate data in line 942 */ 943 if ((j = lstdat - buf) <= offst) 944 break; 945 946 if (!i && !nohead && prhead(hbuf, fname, pagecnt)) 947 goto out; 948 949 /* 950 * output line 951 */ 952 if (otln(buf, j, &ips, &ops, 0)) 953 goto out; 954 955 /* 956 * if no more active files, done 957 */ 958 if (actf <= 0) { 959 ++i; 960 break; 961 } 962 } 963 964 /* 965 * pad to end of page 966 */ 967 if (i && prtail(lines-i, 0)) 968 goto out; 969 ++pagecnt; 970 } 971 if (eoptind < argc) 972 goto out; 973 error = 0; 974 goto out; 975 oomem: 976 mfail(); 977 out: 978 if (fbuf) { 979 for (j = 0; j < clcnt; j++) 980 if (fbuf[j] && fbuf[j] != stdin) 981 (void)fclose(fbuf[j]); 982 free(fbuf); 983 } 984 if (hbuf) 985 free(hbuf); 986 if (buf) 987 free(buf); 988 return error; 989 } 990 991 /* 992 * inln(): input a line of data (unlimited length lines supported) 993 * Input is optionally expanded to spaces 994 * 995 * inf: file 996 * buf: buffer 997 * lim: buffer length 998 * cps: column positon 1st char in buffer (large line support) 999 * trnc: throw away data more than lim up to \n 1000 * mor: set if more data in line (not truncated) 1001 */ 1002 int 1003 inln(inf, buf, lim, cps, trnc, mor) 1004 FILE *inf; 1005 char *buf; 1006 int lim; 1007 int *cps; 1008 int trnc; 1009 int *mor; 1010 { 1011 int col; 1012 int gap = ingap; 1013 int ch = EOF; 1014 char *ptbuf; 1015 int chk = (int)inchar; 1016 1017 ptbuf = buf; 1018 1019 if (gap) { 1020 /* 1021 * expanding input option 1022 */ 1023 while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { 1024 /* 1025 * is this the input "tab" char 1026 */ 1027 if (ch == chk) { 1028 /* 1029 * expand to number of spaces 1030 */ 1031 col = (ptbuf - buf) + *cps; 1032 col = gap - (col % gap); 1033 1034 /* 1035 * if more than this line, push back 1036 */ 1037 if ((col > lim) && (ungetc(ch, inf) == EOF)) 1038 return(1); 1039 1040 /* 1041 * expand to spaces 1042 */ 1043 while ((--col >= 0) && (--lim >= 0)) 1044 *ptbuf++ = ' '; 1045 continue; 1046 } 1047 if (ch == '\n') 1048 break; 1049 *ptbuf++ = ch; 1050 } 1051 } else { 1052 /* 1053 * no expansion 1054 */ 1055 while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { 1056 if (ch == '\n') 1057 break; 1058 *ptbuf++ = ch; 1059 } 1060 } 1061 col = ptbuf - buf; 1062 if (ch == EOF) { 1063 *mor = 0; 1064 *cps = 0; 1065 if (!col) 1066 return(-1); 1067 return(col); 1068 } 1069 if (ch == '\n') { 1070 /* 1071 * entire line processed 1072 */ 1073 *mor = 0; 1074 *cps = 0; 1075 return(col); 1076 } 1077 1078 /* 1079 * line was larger than limit 1080 */ 1081 if (trnc) { 1082 /* 1083 * throw away rest of line 1084 */ 1085 while ((ch = getc(inf)) != EOF) { 1086 if (ch == '\n') 1087 break; 1088 } 1089 *cps = 0; 1090 *mor = 0; 1091 } else { 1092 /* 1093 * save column offset if not truncated 1094 */ 1095 *cps += col; 1096 *mor = 1; 1097 } 1098 1099 return(col); 1100 } 1101 1102 /* 1103 * otln(): output a line of data. (Supports unlimited length lines) 1104 * output is optionally contracted to tabs 1105 * 1106 * buf: output buffer with data 1107 * cnt: number of chars of valid data in buf 1108 * svips: buffer input column position (for large lines) 1109 * svops: buffer output column position (for large lines) 1110 * mor: output line not complete in this buf; more data to come. 1111 * 1 is more, 0 is complete, -1 is no \n's 1112 */ 1113 int 1114 otln(buf, cnt, svips, svops, mor) 1115 char *buf; 1116 int cnt; 1117 int *svops; 1118 int *svips; 1119 int mor; 1120 { 1121 int ops; /* last col output */ 1122 int ips; /* last col in buf examined */ 1123 int gap = ogap; 1124 int tbps; 1125 char *endbuf; 1126 1127 if (ogap) { 1128 /* 1129 * contracting on output 1130 */ 1131 endbuf = buf + cnt; 1132 ops = *svops; 1133 ips = *svips; 1134 while (buf < endbuf) { 1135 /* 1136 * count number of spaces and ochar in buffer 1137 */ 1138 if (*buf == ' ') { 1139 ++ips; 1140 ++buf; 1141 continue; 1142 } 1143 1144 /* 1145 * simulate ochar processing 1146 */ 1147 if (*buf == ochar) { 1148 ips += gap - (ips % gap); 1149 ++buf; 1150 continue; 1151 } 1152 1153 /* 1154 * got a non space char; contract out spaces 1155 */ 1156 while (ops < ips) { 1157 /* 1158 * use one space if necessary 1159 */ 1160 if (ips - ops == 1) { 1161 putchar(' '); 1162 break; 1163 } 1164 /* 1165 * use as many ochar as will fit 1166 */ 1167 if ((tbps = ops + gap - (ops % gap)) > ips) 1168 break; 1169 if (putchar(ochar) == EOF) { 1170 pfail(); 1171 return(1); 1172 } 1173 ops = tbps; 1174 } 1175 1176 while (ops < ips) { 1177 /* 1178 * finish off with spaces 1179 */ 1180 if (putchar(' ') == EOF) { 1181 pfail(); 1182 return(1); 1183 } 1184 ++ops; 1185 } 1186 1187 /* 1188 * output non space char 1189 */ 1190 if (putchar(*buf++) == EOF) { 1191 pfail(); 1192 return(1); 1193 } 1194 ++ips; 1195 ++ops; 1196 } 1197 1198 if (mor > 0) { 1199 /* 1200 * if incomplete line, save position counts 1201 */ 1202 *svops = ops; 1203 *svips = ips; 1204 return(0); 1205 } 1206 1207 if (mor < 0) { 1208 while (ops < ips) { 1209 /* 1210 * use one space if necessary 1211 */ 1212 if (ips - ops == 1) { 1213 putchar(' '); 1214 break; 1215 } 1216 /* 1217 * use as many ochar as will fit 1218 */ 1219 if ((tbps = ops + gap - (ops % gap)) > ips) 1220 break; 1221 if (putchar(ochar) == EOF) { 1222 pfail(); 1223 return(1); 1224 } 1225 ops = tbps; 1226 } 1227 while (ops < ips) { 1228 /* 1229 * finish off with spaces 1230 */ 1231 if (putchar(' ') == EOF) { 1232 pfail(); 1233 return(1); 1234 } 1235 ++ops; 1236 } 1237 return(0); 1238 } 1239 } else { 1240 /* 1241 * output is not contracted 1242 */ 1243 if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) { 1244 pfail(); 1245 return(1); 1246 } 1247 if (mor != 0) 1248 return(0); 1249 } 1250 1251 /* 1252 * process line end and double space as required 1253 */ 1254 if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) { 1255 pfail(); 1256 return(1); 1257 } 1258 return(0); 1259 } 1260 1261 /* 1262 * inskip(): skip over pgcnt pages with lncnt lines per page 1263 * file is closed at EOF (if not stdin). 1264 * 1265 * inf FILE * to read from 1266 * pgcnt number of pages to skip 1267 * lncnt number of lines per page 1268 */ 1269 int 1270 inskip(inf, pgcnt, lncnt) 1271 FILE *inf; 1272 int pgcnt; 1273 int lncnt; 1274 { 1275 int c; 1276 int cnt; 1277 1278 while(--pgcnt > 0) { 1279 cnt = lncnt; 1280 while ((c = getc(inf)) != EOF) { 1281 if ((c == '\n') && (--cnt == 0)) 1282 break; 1283 } 1284 if (c == EOF) { 1285 if (inf != stdin) 1286 (void)fclose(inf); 1287 return(1); 1288 } 1289 } 1290 return(0); 1291 } 1292 1293 /* 1294 * nxtfile: returns a FILE * to next file in arg list and sets the 1295 * time field for this file (or current date). 1296 * 1297 * buf array to store proper date for the header. 1298 * dt if set skips the date processing (used with -m) 1299 */ 1300 FILE * 1301 nxtfile(argc, argv, fname, buf, dt) 1302 int argc; 1303 char **argv; 1304 char **fname; 1305 char *buf; 1306 int dt; 1307 { 1308 FILE *inf = NULL; 1309 struct timeval tv; 1310 struct timezone tz; 1311 struct tm *timeptr = NULL; 1312 struct stat statbuf; 1313 time_t curtime; 1314 static int twice = -1; 1315 1316 ++twice; 1317 if (eoptind >= argc) { 1318 /* 1319 * no file listed; default, use standard input 1320 */ 1321 if (twice) 1322 return(NULL); 1323 clearerr(stdin); 1324 inf = stdin; 1325 if (header != NULL) 1326 *fname = header; 1327 else 1328 *fname = FNAME; 1329 if (nohead) 1330 return(inf); 1331 if (gettimeofday(&tv, &tz) < 0) { 1332 ++errcnt; 1333 (void)fprintf(err, "pr: cannot get time of day, %s\n", 1334 strerror(errno)); 1335 eoptind = argc - 1; 1336 return(NULL); 1337 } 1338 curtime = tv.tv_sec; 1339 timeptr = localtime(&curtime); 1340 } 1341 for (; eoptind < argc; ++eoptind) { 1342 if (strcmp(argv[eoptind], "-") == 0) { 1343 /* 1344 * process a "-" for filename 1345 */ 1346 clearerr(stdin); 1347 inf = stdin; 1348 if (header != NULL) 1349 *fname = header; 1350 else 1351 *fname = FNAME; 1352 ++eoptind; 1353 if (nohead || (dt && twice)) 1354 return(inf); 1355 if (gettimeofday(&tv, &tz) < 0) { 1356 ++errcnt; 1357 (void)fprintf(err, 1358 "pr: cannot get time of day, %s\n", 1359 strerror(errno)); 1360 return(NULL); 1361 } 1362 curtime = tv.tv_sec; 1363 timeptr = localtime(&curtime); 1364 } else { 1365 /* 1366 * normal file processing 1367 */ 1368 if ((inf = fopen(argv[eoptind], "r")) == NULL) { 1369 ++errcnt; 1370 if (nodiag) 1371 continue; 1372 (void)fprintf(err, "pr: Cannot open %s, %s\n", 1373 argv[eoptind], strerror(errno)); 1374 continue; 1375 } 1376 if (header != NULL) 1377 *fname = header; 1378 else if (dt) 1379 *fname = FNAME; 1380 else 1381 *fname = argv[eoptind]; 1382 ++eoptind; 1383 if (nohead || (dt && twice)) 1384 return(inf); 1385 1386 if (dt) { 1387 if (gettimeofday(&tv, &tz) < 0) { 1388 ++errcnt; 1389 (void)fprintf(err, 1390 "pr: cannot get time of day, %s\n", 1391 strerror(errno)); 1392 return(NULL); 1393 } 1394 curtime = tv.tv_sec; 1395 timeptr = localtime(&curtime); 1396 } else { 1397 if (fstat(fileno(inf), &statbuf) < 0) { 1398 ++errcnt; 1399 (void)fclose(inf); 1400 (void)fprintf(err, 1401 "pr: Cannot stat %s, %s\n", 1402 argv[eoptind], strerror(errno)); 1403 return(NULL); 1404 } 1405 timeptr = localtime(&(statbuf.st_mtime)); 1406 } 1407 } 1408 break; 1409 } 1410 if (inf == NULL) 1411 return(NULL); 1412 1413 /* 1414 * set up time field used in header 1415 */ 1416 if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { 1417 ++errcnt; 1418 if (inf != stdin) 1419 (void)fclose(inf); 1420 (void)fputs("pr: time conversion failed\n", err); 1421 return(NULL); 1422 } 1423 return(inf); 1424 } 1425 1426 /* 1427 * addnum(): adds the line number to the column 1428 * Truncates from the front or pads with spaces as required. 1429 * Numbers are right justified. 1430 * 1431 * buf buffer to store the number 1432 * wdth width of buffer to fill 1433 * line line number 1434 * 1435 * NOTE: numbers occupy part of the column. The posix 1436 * spec does not specify if -i processing should or should not 1437 * occur on number padding. The spec does say it occupies 1438 * part of the column. The usage of addnum currently treats 1439 * numbers as part of the column so spaces may be replaced. 1440 */ 1441 void 1442 addnum(buf, wdth, line) 1443 char *buf; 1444 int wdth; 1445 int line; 1446 { 1447 char *pt = buf + wdth; 1448 1449 do { 1450 *--pt = digs[line % 10]; 1451 line /= 10; 1452 } while (line && (pt > buf)); 1453 1454 /* 1455 * pad with space as required 1456 */ 1457 while (pt > buf) 1458 *--pt = ' '; 1459 } 1460 1461 /* 1462 * prhead(): prints the top of page header 1463 * 1464 * buf buffer with time field (and offset) 1465 * cnt number of chars in buf 1466 * fname fname field for header 1467 * pagcnt page number 1468 */ 1469 int 1470 prhead(buf, fname, pagcnt) 1471 char *buf; 1472 char *fname; 1473 int pagcnt; 1474 { 1475 int ips = 0; 1476 int ops = 0; 1477 1478 if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { 1479 pfail(); 1480 return(1); 1481 } 1482 /* 1483 * posix is not clear if the header is subject to line length 1484 * restrictions. The specification for header line format 1485 * in the spec clearly does not limit length. No pr currently 1486 * restricts header length. However if we need to truncate in 1487 * an reasonable way, adjust the length of the printf by 1488 * changing HDFMT to allow a length max as an arguement printf. 1489 * buf (which contains the offset spaces and time field could 1490 * also be trimmed 1491 * 1492 * note only the offset (if any) is processed for tab expansion 1493 */ 1494 if (offst && otln(buf, offst, &ips, &ops, -1)) 1495 return(1); 1496 (void)printf(HDFMT,buf+offst, fname, pagcnt); 1497 return(0); 1498 } 1499 1500 /* 1501 * prtail(): pad page with empty lines (if required) and print page trailer 1502 * if requested 1503 * 1504 * cnt number of lines of padding needed 1505 * incomp was a '\n' missing from last line output 1506 */ 1507 int 1508 prtail(cnt, incomp) 1509 int cnt; 1510 int incomp; 1511 { 1512 if (nohead) { 1513 /* 1514 * only pad with no headers when incomplete last line 1515 */ 1516 if (!incomp) 1517 return(0); 1518 if ((dspace && (putchar('\n') == EOF)) || 1519 (putchar('\n') == EOF)) { 1520 pfail(); 1521 return(1); 1522 } 1523 return(0); 1524 } 1525 1526 /* 1527 * if double space output two \n 1528 */ 1529 if (dspace) 1530 cnt *= 2; 1531 1532 /* 1533 * if an odd number of lines per page, add an extra \n 1534 */ 1535 if (addone) 1536 ++cnt; 1537 1538 /* 1539 * pad page 1540 */ 1541 if (formfeed) { 1542 if ((incomp && (putchar('\n') == EOF)) || 1543 (putchar('\f') == EOF)) { 1544 pfail(); 1545 return(1); 1546 } 1547 return(0); 1548 } 1549 cnt += TAILLEN; 1550 while (--cnt >= 0) { 1551 if (putchar('\n') == EOF) { 1552 pfail(); 1553 return(1); 1554 } 1555 } 1556 return(0); 1557 } 1558 1559 /* 1560 * terminate(): when a SIGINT is recvd 1561 */ 1562 void 1563 terminate(which_sig) 1564 int which_sig; 1565 { 1566 flsh_errs(); 1567 exit(1); 1568 } 1569 1570 1571 /* 1572 * flsh_errs(): output saved up diagnostic messages after all normal 1573 * processing has completed 1574 */ 1575 void 1576 flsh_errs() 1577 { 1578 char buf[BUFSIZ]; 1579 1580 (void)fflush(stdout); 1581 (void)fflush(err); 1582 if (err == stderr) 1583 return; 1584 rewind(err); 1585 while (fgets(buf, BUFSIZ, err) != NULL) 1586 (void)fputs(buf, stderr); 1587 } 1588 1589 void 1590 mfail() 1591 { 1592 (void)fputs("pr: memory allocation failed\n", err); 1593 } 1594 1595 void 1596 pfail() 1597 { 1598 (void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); 1599 } 1600 1601 void 1602 usage() 1603 { 1604 (void)fputs( 1605 "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err); 1606 (void)fputs( 1607 " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); 1608 (void)fputs( 1609 " [-s[ch]] [-w width] [-] [file ...]\n", err); 1610 } 1611 1612 /* 1613 * setup: Validate command args, initialize and perform sanity 1614 * checks on options 1615 */ 1616 int 1617 setup(argc, argv) 1618 int argc; 1619 char **argv; 1620 { 1621 int c; 1622 int eflag = 0; 1623 int iflag = 0; 1624 int wflag = 0; 1625 int cflag = 0; 1626 1627 if (isatty(fileno(stdout))) { 1628 /* 1629 * defer diagnostics until processing is done 1630 */ 1631 if ((err = tmpfile()) == NULL) { 1632 (void)fputs("Cannot defer diagnostic messages\n",stderr); 1633 return(1); 1634 } 1635 } else 1636 err = stderr; 1637 while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?T:w:")) != -1) { 1638 switch (c) { 1639 case '+': 1640 if ((pgnm = atoi(eoptarg)) < 1) { 1641 (void)fputs("pr: +page number must be 1 or more\n", 1642 err); 1643 return(1); 1644 } 1645 break; 1646 case '-': 1647 if ((clcnt = atoi(eoptarg)) < 1) { 1648 (void)fputs("pr: -columns must be 1 or more\n",err); 1649 return(1); 1650 } 1651 if (clcnt > 1) 1652 ++cflag; 1653 break; 1654 case 'a': 1655 ++across; 1656 break; 1657 case 'd': 1658 ++dspace; 1659 break; 1660 case 'e': 1661 ++eflag; 1662 if ((eoptarg != NULL) && 1663 !isdigit((unsigned char)*eoptarg)) 1664 inchar = *eoptarg++; 1665 else 1666 inchar = INCHAR; 1667 if ((eoptarg != NULL) && 1668 isdigit((unsigned char)*eoptarg)) { 1669 if ((ingap = atoi(eoptarg)) < 0) { 1670 (void)fputs( 1671 "pr: -e gap must be 0 or more\n", err); 1672 return(1); 1673 } 1674 if (ingap == 0) 1675 ingap = INGAP; 1676 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 1677 (void)fprintf(err, 1678 "pr: invalid value for -e %s\n", eoptarg); 1679 return(1); 1680 } else 1681 ingap = INGAP; 1682 break; 1683 case 'F': 1684 ++formfeed; 1685 break; 1686 case 'h': 1687 header = eoptarg; 1688 break; 1689 case 'i': 1690 ++iflag; 1691 if ((eoptarg != NULL) && 1692 !isdigit((unsigned char)*eoptarg)) 1693 ochar = *eoptarg++; 1694 else 1695 ochar = OCHAR; 1696 if ((eoptarg != NULL) && 1697 isdigit((unsigned char)*eoptarg)) { 1698 if ((ogap = atoi(eoptarg)) < 0) { 1699 (void)fputs( 1700 "pr: -i gap must be 0 or more\n", err); 1701 return(1); 1702 } 1703 if (ogap == 0) 1704 ogap = OGAP; 1705 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 1706 (void)fprintf(err, 1707 "pr: invalid value for -i %s\n", eoptarg); 1708 return(1); 1709 } else 1710 ogap = OGAP; 1711 break; 1712 case 'l': 1713 if (!isdigit((unsigned char)*eoptarg) || 1714 ((lines=atoi(eoptarg)) < 1)) { 1715 (void)fputs( 1716 "pr: Number of lines must be 1 or more\n",err); 1717 return(1); 1718 } 1719 break; 1720 case 'm': 1721 ++merge; 1722 break; 1723 case 'n': 1724 if ((eoptarg != NULL) && 1725 !isdigit((unsigned char)*eoptarg)) 1726 nmchar = *eoptarg++; 1727 else 1728 nmchar = NMCHAR; 1729 if ((eoptarg != NULL) && 1730 isdigit((unsigned char)*eoptarg)) { 1731 if ((nmwd = atoi(eoptarg)) < 1) { 1732 (void)fputs( 1733 "pr: -n width must be 1 or more\n",err); 1734 return(1); 1735 } 1736 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 1737 (void)fprintf(err, 1738 "pr: invalid value for -n %s\n", eoptarg); 1739 return(1); 1740 } else 1741 nmwd = NMWD; 1742 break; 1743 case 'o': 1744 if (!isdigit((unsigned char)*eoptarg) || 1745 ((offst = atoi(eoptarg))< 1)){ 1746 (void)fputs("pr: -o offset must be 1 or more\n", 1747 err); 1748 return(1); 1749 } 1750 break; 1751 case 'r': 1752 ++nodiag; 1753 break; 1754 case 's': 1755 ++sflag; 1756 if (eoptarg == NULL) 1757 schar = SCHAR; 1758 else 1759 schar = *eoptarg++; 1760 if (eoptarg && *eoptarg != '\0') { 1761 (void)fprintf(err, 1762 "pr: invalid value for -s %s\n", eoptarg); 1763 return(1); 1764 } 1765 break; 1766 case 'T': 1767 timefrmt = eoptarg; 1768 break; 1769 case 't': 1770 ++nohead; 1771 break; 1772 case 'w': 1773 ++wflag; 1774 if (!isdigit((unsigned char)*eoptarg) || 1775 ((pgwd = atoi(eoptarg)) < 1)){ 1776 (void)fputs( 1777 "pr: -w width must be 1 or more \n",err); 1778 return(1); 1779 } 1780 break; 1781 case '?': 1782 default: 1783 return(1); 1784 } 1785 } 1786 1787 /* 1788 * default and sanity checks 1789 */ 1790 if (!clcnt) { 1791 if (merge) { 1792 if ((clcnt = argc - eoptind) <= 1) { 1793 clcnt = CLCNT; 1794 merge = 0; 1795 } 1796 } else 1797 clcnt = CLCNT; 1798 } 1799 if (across) { 1800 if (clcnt == 1) { 1801 (void)fputs("pr: -a flag requires multiple columns\n", 1802 err); 1803 return(1); 1804 } 1805 if (merge) { 1806 (void)fputs("pr: -m cannot be used with -a\n", err); 1807 return(1); 1808 } 1809 } 1810 if (!wflag) { 1811 if (sflag) 1812 pgwd = SPGWD; 1813 else 1814 pgwd = PGWD; 1815 } 1816 if (cflag || merge) { 1817 if (!eflag) { 1818 inchar = INCHAR; 1819 ingap = INGAP; 1820 } 1821 if (!iflag) { 1822 ochar = OCHAR; 1823 ogap = OGAP; 1824 } 1825 } 1826 if (cflag) { 1827 if (merge) { 1828 (void)fputs( 1829 "pr: -m cannot be used with multiple columns\n", err); 1830 return(1); 1831 } 1832 if (nmwd) { 1833 colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; 1834 pgwd = ((colwd + nmwd + 2) * clcnt) - 1; 1835 } else { 1836 colwd = (pgwd + 1 - clcnt)/clcnt; 1837 pgwd = ((colwd + 1) * clcnt) - 1; 1838 } 1839 if (colwd < 1) { 1840 (void)fprintf(err, 1841 "pr: page width is too small for %d columns\n",clcnt); 1842 return(1); 1843 } 1844 } 1845 if (!lines) 1846 lines = LINES; 1847 1848 /* 1849 * make sure long enough for headers. if not disable 1850 */ 1851 if (lines <= HEADLEN + TAILLEN) 1852 ++nohead; 1853 else if (!nohead) 1854 lines -= HEADLEN + TAILLEN; 1855 1856 /* 1857 * adjust for double space on odd length pages 1858 */ 1859 if (dspace) { 1860 if (lines == 1) 1861 dspace = 0; 1862 else { 1863 if (lines & 1) 1864 ++addone; 1865 lines /= 2; 1866 } 1867 } 1868 1869 return(0); 1870 } 1871