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