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