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