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