pr.c revision 204358
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1991 Keith Muller. 31590Srgrimes * Copyright (c) 1993 41590Srgrimes * The Regents of the University of California. All rights reserved. 51590Srgrimes * 61590Srgrimes * This code is derived from software contributed to Berkeley by 71590Srgrimes * Keith Muller of the University of California, San Diego. 81590Srgrimes * 91590Srgrimes * Redistribution and use in source and binary forms, with or without 101590Srgrimes * modification, are permitted provided that the following conditions 111590Srgrimes * are met: 121590Srgrimes * 1. Redistributions of source code must retain the above copyright 131590Srgrimes * notice, this list of conditions and the following disclaimer. 141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer in the 161590Srgrimes * documentation and/or other materials provided with the distribution. 171590Srgrimes * 3. All advertising materials mentioning features or use of this software 181590Srgrimes * must display the following acknowledgement: 191590Srgrimes * This product includes software developed by the University of 201590Srgrimes * California, Berkeley and its contributors. 211590Srgrimes * 4. Neither the name of the University nor the names of its contributors 221590Srgrimes * may be used to endorse or promote products derived from this software 231590Srgrimes * without specific prior written permission. 241590Srgrimes * 251590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351590Srgrimes * SUCH DAMAGE. 361590Srgrimes */ 371590Srgrimes 381590Srgrimes#ifndef lint 3998552Smarkmstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 4498552Smarkm#if 0 451590Srgrimes#ifndef lint 461590Srgrimesstatic char sccsid[] = "@(#)pr.c 8.2 (Berkeley) 4/16/94"; 471590Srgrimes#endif /* not lint */ 4898552Smarkm#endif 491590Srgrimes 5098552Smarkm#include <sys/cdefs.h> 5198552Smarkm__FBSDID("$FreeBSD: head/usr.bin/pr/pr.c 204358 2010-02-26 13:47:51Z ed $"); 5298552Smarkm 531590Srgrimes#include <sys/types.h> 541590Srgrimes#include <sys/time.h> 551590Srgrimes#include <sys/stat.h> 561590Srgrimes 571590Srgrimes#include <ctype.h> 581590Srgrimes#include <errno.h> 5974575Sache#include <langinfo.h> 6053948Sache#include <locale.h> 611590Srgrimes#include <signal.h> 621590Srgrimes#include <stdio.h> 631590Srgrimes#include <stdlib.h> 641590Srgrimes#include <string.h> 651590Srgrimes#include <unistd.h> 661590Srgrimes 671590Srgrimes#include "pr.h" 681590Srgrimes#include "extern.h" 691590Srgrimes 701590Srgrimes/* 711590Srgrimes * pr: a printing and pagination filter. If multiple input files 721590Srgrimes * are specified, each is read, formatted, and written to standard 7372091Sasmodai * output. By default, input is separated into 66-line pages, each 741590Srgrimes * with a header that includes the page number, date, time and the 751590Srgrimes * files pathname. 761590Srgrimes * 771590Srgrimes * Complies with posix P1003.2/D11 781590Srgrimes */ 791590Srgrimes 801590Srgrimes/* 811590Srgrimes * parameter variables 821590Srgrimes */ 831590Srgrimesint pgnm; /* starting page number */ 841590Srgrimesint clcnt; /* number of columns */ 851590Srgrimesint colwd; /* column data width - multiple columns */ 861590Srgrimesint across; /* mult col flag; write across page */ 871590Srgrimesint dspace; /* double space flag */ 881590Srgrimeschar inchar; /* expand input char */ 891590Srgrimesint ingap; /* expand input gap */ 9093481Sjmallettint pausefst; /* Pause before first page */ 9193481Sjmallettint pauseall; /* Pause before each page */ 921590Srgrimesint formfeed; /* use formfeed as trailer */ 931590Srgrimeschar *header; /* header name instead of file name */ 941590Srgrimeschar ochar; /* contract output char */ 951590Srgrimesint ogap; /* contract output gap */ 961590Srgrimesint lines; /* number of lines per page */ 971590Srgrimesint merge; /* merge multiple files in output */ 981590Srgrimeschar nmchar; /* line numbering append char */ 991590Srgrimesint nmwd; /* width of line number field */ 1001590Srgrimesint offst; /* number of page offset spaces */ 1011590Srgrimesint nodiag; /* do not report file open errors */ 1021590Srgrimeschar schar; /* text column separation character */ 1031590Srgrimesint sflag; /* -s option for multiple columns */ 1041590Srgrimesint nohead; /* do not write head and trailer */ 1051590Srgrimesint pgwd; /* page width with multiple col output */ 106102944Sdwmaloneconst char *timefrmt; /* time conversion string */ 1071590Srgrimes 1081590Srgrimes/* 1091590Srgrimes * misc globals 1101590Srgrimes */ 1111590SrgrimesFILE *err; /* error message file pointer */ 1121590Srgrimesint addone; /* page length is odd with double space */ 1131590Srgrimesint errcnt; /* error count on file processing */ 1141590Srgrimeschar digs[] = "0123456789"; /* page number translation map */ 1151590Srgrimes 11698552Smarkmchar fnamedefault[] = FNAME; 11798552Smarkm 1181590Srgrimesint 11998552Smarkmmain(int argc, char *argv[]) 1201590Srgrimes{ 1211590Srgrimes int ret_val; 1221590Srgrimes 1231590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1241590Srgrimes (void)signal(SIGINT, terminate); 1251590Srgrimes ret_val = setup(argc, argv); 1261590Srgrimes if (!ret_val) { 1271590Srgrimes /* 1281590Srgrimes * select the output format based on options 1291590Srgrimes */ 1301590Srgrimes if (merge) 1311590Srgrimes ret_val = mulfile(argc, argv); 1321590Srgrimes else if (clcnt == 1) 1331590Srgrimes ret_val = onecol(argc, argv); 1341590Srgrimes else if (across) 1351590Srgrimes ret_val = horzcol(argc, argv); 1361590Srgrimes else 1371590Srgrimes ret_val = vertcol(argc, argv); 1381590Srgrimes } else 1391590Srgrimes usage(); 1401590Srgrimes flsh_errs(); 1411590Srgrimes if (errcnt || ret_val) 1421590Srgrimes exit(1); 1431590Srgrimes return(0); 1441590Srgrimes} 1451590Srgrimes 1461590Srgrimes/* 14793481Sjmallett * Check if we should pause and write an alert character and wait for a 14893481Sjmallett * carriage return on /dev/tty. 14993481Sjmallett */ 15098552Smarkmstatic void 15198552Smarkmttypause(int pagecnt) 15293481Sjmallett{ 15393481Sjmallett int pch; 15493481Sjmallett FILE *ttyfp; 15593481Sjmallett 15693481Sjmallett if ((pauseall || (pausefst && pagecnt == 1)) && 15793481Sjmallett isatty(STDOUT_FILENO)) { 15893481Sjmallett if ((ttyfp = fopen("/dev/tty", "r")) != NULL) { 15993481Sjmallett (void)putc('\a', stderr); 16093481Sjmallett while ((pch = getc(ttyfp)) != '\n' && pch != EOF) 16193481Sjmallett ; 16293481Sjmallett (void)fclose(ttyfp); 16393481Sjmallett } 16493481Sjmallett } 16593481Sjmallett} 16693481Sjmallett 16793481Sjmallett/* 1681590Srgrimes * onecol: print files with only one column of output. 1691590Srgrimes * Line length is unlimited. 1701590Srgrimes */ 1711590Srgrimesint 17298552Smarkmonecol(int argc, char *argv[]) 1731590Srgrimes{ 17498552Smarkm int cnt = -1; 17598552Smarkm int off; 17698552Smarkm int lrgln; 17798552Smarkm int linecnt; 17898552Smarkm int num; 1791590Srgrimes int lncnt; 1801590Srgrimes int pagecnt; 1811590Srgrimes int ips; 1821590Srgrimes int ops; 1831590Srgrimes int cps; 1841590Srgrimes char *obuf; 1851590Srgrimes char *lbuf; 1861590Srgrimes char *nbuf; 1871590Srgrimes char *hbuf; 1881590Srgrimes char *ohbuf; 1891590Srgrimes FILE *inf; 190102944Sdwmalone const char *fname; 1911590Srgrimes int mor; 1921590Srgrimes 1931590Srgrimes if (nmwd) 1941590Srgrimes num = nmwd + 1; 1951590Srgrimes else 1961590Srgrimes num = 0; 1971590Srgrimes off = num + offst; 1981590Srgrimes 1991590Srgrimes /* 2001590Srgrimes * allocate line buffer 2011590Srgrimes */ 2021590Srgrimes if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) { 2031590Srgrimes mfail(); 2041590Srgrimes return(1); 2051590Srgrimes } 2061590Srgrimes /* 2071590Srgrimes * allocate header buffer 2081590Srgrimes */ 2091590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 2101590Srgrimes mfail(); 2111590Srgrimes return(1); 2121590Srgrimes } 2131590Srgrimes 2141590Srgrimes ohbuf = hbuf + offst; 2151590Srgrimes nbuf = obuf + offst; 2161590Srgrimes lbuf = nbuf + num; 2171590Srgrimes if (num) 2181590Srgrimes nbuf[--num] = nmchar; 2191590Srgrimes if (offst) { 2201590Srgrimes (void)memset(obuf, (int)' ', offst); 2211590Srgrimes (void)memset(hbuf, (int)' ', offst); 2221590Srgrimes } 2231590Srgrimes 2241590Srgrimes /* 2251590Srgrimes * loop by file 2261590Srgrimes */ 2271590Srgrimes while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 2281590Srgrimes if (pgnm) { 2291590Srgrimes /* 2301590Srgrimes * skip to specified page 2311590Srgrimes */ 2321590Srgrimes if (inskip(inf, pgnm, lines)) 2331590Srgrimes continue; 2341590Srgrimes pagecnt = pgnm; 2351590Srgrimes } else 2361590Srgrimes pagecnt = 1; 2371590Srgrimes lncnt = 0; 2381590Srgrimes 2391590Srgrimes /* 2401590Srgrimes * loop by page 2411590Srgrimes */ 2421590Srgrimes for(;;) { 2431590Srgrimes linecnt = 0; 2441590Srgrimes lrgln = 0; 2451590Srgrimes ops = 0; 2461590Srgrimes ips = 0; 2471590Srgrimes cps = 0; 2481590Srgrimes 24993481Sjmallett ttypause(pagecnt); 25093481Sjmallett 2511590Srgrimes /* 2521590Srgrimes * loop by line 2531590Srgrimes */ 2541590Srgrimes while (linecnt < lines) { 2551590Srgrimes /* 2561590Srgrimes * input next line 2571590Srgrimes */ 2581590Srgrimes if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0) 2591590Srgrimes break; 2601590Srgrimes if (!linecnt && !nohead && 2611590Srgrimes prhead(hbuf, fname, pagecnt)) 2621590Srgrimes return(1); 2631590Srgrimes 2641590Srgrimes /* 2651590Srgrimes * start of new line. 2661590Srgrimes */ 2671590Srgrimes if (!lrgln) { 2681590Srgrimes if (num) 2691590Srgrimes addnum(nbuf, num, ++lncnt); 2701590Srgrimes if (otln(obuf,cnt+off, &ips, &ops, mor)) 2711590Srgrimes return(1); 2721590Srgrimes } else if (otln(lbuf, cnt, &ips, &ops, mor)) 2731590Srgrimes return(1); 2741590Srgrimes 2751590Srgrimes /* 2761590Srgrimes * if line bigger than buffer, get more 2771590Srgrimes */ 2781590Srgrimes if (mor) { 2791590Srgrimes lrgln = 1; 2801590Srgrimes continue; 2811590Srgrimes } 2821590Srgrimes 2831590Srgrimes /* 2841590Srgrimes * whole line rcvd. reset tab proc. state 2851590Srgrimes */ 2861590Srgrimes ++linecnt; 2871590Srgrimes lrgln = 0; 2881590Srgrimes ops = 0; 2891590Srgrimes ips = 0; 2901590Srgrimes } 2911590Srgrimes 2921590Srgrimes /* 2931590Srgrimes * fill to end of page 2941590Srgrimes */ 2951590Srgrimes if (linecnt && prtail(lines-linecnt-lrgln, lrgln)) 2961590Srgrimes return(1); 2971590Srgrimes 2981590Srgrimes /* 2991590Srgrimes * On EOF go to next file 3001590Srgrimes */ 3011590Srgrimes if (cnt < 0) 3021590Srgrimes break; 3031590Srgrimes ++pagecnt; 3041590Srgrimes } 3051590Srgrimes if (inf != stdin) 3061590Srgrimes (void)fclose(inf); 3071590Srgrimes } 3081590Srgrimes if (eoptind < argc) 3091590Srgrimes return(1); 3101590Srgrimes return(0); 3111590Srgrimes} 3121590Srgrimes 3131590Srgrimes/* 3141590Srgrimes * vertcol: print files with more than one column of output down a page 3151590Srgrimes */ 3161590Srgrimesint 31798552Smarkmvertcol(int argc, char *argv[]) 3181590Srgrimes{ 31998552Smarkm char *ptbf; 32098552Smarkm char **lstdat; 32198552Smarkm int i; 32298552Smarkm int j; 32398552Smarkm int cnt = -1; 32498552Smarkm int pln; 32598552Smarkm int *indy; 3261590Srgrimes int cvc; 3271590Srgrimes int *lindy; 3281590Srgrimes int lncnt; 3291590Srgrimes int stp; 3301590Srgrimes int pagecnt; 3311590Srgrimes int col = colwd + 1; 3321590Srgrimes int mxlen = pgwd + offst + 1; 3331590Srgrimes int mclcnt = clcnt - 1; 3341590Srgrimes struct vcol *vc; 3351590Srgrimes int mvc; 3361590Srgrimes int tvc; 3371590Srgrimes int cw = nmwd + 1; 3381590Srgrimes int fullcol; 3391590Srgrimes char *buf; 3401590Srgrimes char *hbuf; 3411590Srgrimes char *ohbuf; 342102944Sdwmalone const char *fname; 3431590Srgrimes FILE *inf; 3441590Srgrimes int ips = 0; 3451590Srgrimes int cps = 0; 3461590Srgrimes int ops = 0; 3471590Srgrimes int mor = 0; 3481590Srgrimes 3491590Srgrimes /* 3501590Srgrimes * allocate page buffer 3511590Srgrimes */ 3521590Srgrimes if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) { 3531590Srgrimes mfail(); 3541590Srgrimes return(1); 3551590Srgrimes } 3561590Srgrimes 3571590Srgrimes /* 3581590Srgrimes * allocate page header 3591590Srgrimes */ 3601590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 3611590Srgrimes mfail(); 3621590Srgrimes return(1); 3631590Srgrimes } 3641590Srgrimes ohbuf = hbuf + offst; 3651590Srgrimes if (offst) 3661590Srgrimes (void)memset(hbuf, (int)' ', offst); 3671590Srgrimes 3681590Srgrimes /* 3691590Srgrimes * col pointers when no headers 3701590Srgrimes */ 3711590Srgrimes mvc = lines * clcnt; 3721590Srgrimes if ((vc = 3731590Srgrimes (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) { 3741590Srgrimes mfail(); 3751590Srgrimes return(1); 3761590Srgrimes } 3771590Srgrimes 3781590Srgrimes /* 3791590Srgrimes * pointer into page where last data per line is located 3801590Srgrimes */ 3811590Srgrimes if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){ 3821590Srgrimes mfail(); 3831590Srgrimes return(1); 3841590Srgrimes } 3851590Srgrimes 3861590Srgrimes /* 3871590Srgrimes * fast index lookups to locate start of lines 3881590Srgrimes */ 3891590Srgrimes if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { 3901590Srgrimes mfail(); 3911590Srgrimes return(1); 3921590Srgrimes } 3931590Srgrimes if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { 3941590Srgrimes mfail(); 3951590Srgrimes return(1); 3961590Srgrimes } 3971590Srgrimes 3981590Srgrimes if (nmwd) 3991590Srgrimes fullcol = col + cw; 4001590Srgrimes else 4011590Srgrimes fullcol = col; 4021590Srgrimes 4031590Srgrimes /* 4041590Srgrimes * initialize buffer lookup indexes and offset area 4051590Srgrimes */ 4061590Srgrimes for (j = 0; j < lines; ++j) { 4071590Srgrimes lindy[j] = j * mxlen; 4081590Srgrimes indy[j] = lindy[j] + offst; 4091590Srgrimes if (offst) { 4101590Srgrimes ptbf = buf + lindy[j]; 4111590Srgrimes (void)memset(ptbf, (int)' ', offst); 4121590Srgrimes ptbf += offst; 4131590Srgrimes } else 4141590Srgrimes ptbf = buf + indy[j]; 4151590Srgrimes lstdat[j] = ptbf; 4161590Srgrimes } 4171590Srgrimes 4181590Srgrimes /* 4191590Srgrimes * loop by file 4201590Srgrimes */ 4211590Srgrimes while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 4221590Srgrimes if (pgnm) { 4231590Srgrimes /* 4241590Srgrimes * skip to requested page 4251590Srgrimes */ 4261590Srgrimes if (inskip(inf, pgnm, lines)) 4271590Srgrimes continue; 4281590Srgrimes pagecnt = pgnm; 4291590Srgrimes } else 4301590Srgrimes pagecnt = 1; 4311590Srgrimes lncnt = 0; 4321590Srgrimes 4331590Srgrimes /* 4341590Srgrimes * loop by page 4351590Srgrimes */ 4361590Srgrimes for(;;) { 43793481Sjmallett ttypause(pagecnt); 43893481Sjmallett 4391590Srgrimes /* 4401590Srgrimes * loop by column 4411590Srgrimes */ 4421590Srgrimes cvc = 0; 4431590Srgrimes for (i = 0; i < clcnt; ++i) { 4441590Srgrimes j = 0; 4451590Srgrimes /* 4461590Srgrimes * if last column, do not pad 4471590Srgrimes */ 4481590Srgrimes if (i == mclcnt) 4491590Srgrimes stp = 1; 4501590Srgrimes else 4511590Srgrimes stp = 0; 4521590Srgrimes /* 4531590Srgrimes * loop by line 4541590Srgrimes */ 4551590Srgrimes for(;;) { 4561590Srgrimes /* 4571590Srgrimes * is this first column 4581590Srgrimes */ 4591590Srgrimes if (!i) { 4601590Srgrimes ptbf = buf + indy[j]; 4611590Srgrimes lstdat[j] = ptbf; 4628874Srgrimes } else 4631590Srgrimes ptbf = lstdat[j]; 4641590Srgrimes vc[cvc].pt = ptbf; 4651590Srgrimes 4661590Srgrimes /* 4671590Srgrimes * add number 4681590Srgrimes */ 4691590Srgrimes if (nmwd) { 4701590Srgrimes addnum(ptbf, nmwd, ++lncnt); 4711590Srgrimes ptbf += nmwd; 4721590Srgrimes *ptbf++ = nmchar; 4731590Srgrimes } 4741590Srgrimes 4751590Srgrimes /* 4761590Srgrimes * input next line 4771590Srgrimes */ 4781590Srgrimes cnt = inln(inf,ptbf,colwd,&cps,1,&mor); 4791590Srgrimes vc[cvc++].cnt = cnt; 4801590Srgrimes if (cnt < 0) 4811590Srgrimes break; 4821590Srgrimes ptbf += cnt; 4831590Srgrimes 4841590Srgrimes /* 4851590Srgrimes * pad all but last column on page 4861590Srgrimes */ 4871590Srgrimes if (!stp) { 4881590Srgrimes /* 4891590Srgrimes * pad to end of column 4901590Srgrimes */ 4911590Srgrimes if (sflag) 4921590Srgrimes *ptbf++ = schar; 4931590Srgrimes else if ((pln = col-cnt) > 0) { 4941590Srgrimes (void)memset(ptbf, 4951590Srgrimes (int)' ',pln); 4961590Srgrimes ptbf += pln; 4971590Srgrimes } 4981590Srgrimes } 4991590Srgrimes /* 5001590Srgrimes * remember last char in line 5011590Srgrimes */ 5021590Srgrimes lstdat[j] = ptbf; 5031590Srgrimes if (++j >= lines) 5041590Srgrimes break; 5051590Srgrimes } 5061590Srgrimes if (cnt < 0) 5071590Srgrimes break; 5081590Srgrimes } 5091590Srgrimes 5101590Srgrimes /* 5111590Srgrimes * when -t (no header) is specified the spec requires 5121590Srgrimes * the min number of lines. The last page may not have 5131590Srgrimes * balanced length columns. To fix this we must reorder 5141590Srgrimes * the columns. This is a very slow technique so it is 5151590Srgrimes * only used under limited conditions. Without -t, the 5161590Srgrimes * balancing of text columns is unspecified. To NOT 5171590Srgrimes * balance the last page, add the global variable 5181590Srgrimes * nohead to the if statement below e.g. 5191590Srgrimes * 5201590Srgrimes * if ((cnt < 0) && nohead && cvc ...... 5211590Srgrimes */ 5221590Srgrimes --cvc; 5231590Srgrimes 5241590Srgrimes /* 5251590Srgrimes * check to see if last page needs to be reordered 5261590Srgrimes */ 5271590Srgrimes if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){ 5281590Srgrimes pln = cvc/clcnt; 5291590Srgrimes if (cvc % clcnt) 5301590Srgrimes ++pln; 5311590Srgrimes 5321590Srgrimes /* 5331590Srgrimes * print header 5341590Srgrimes */ 5351590Srgrimes if (!nohead && prhead(hbuf, fname, pagecnt)) 5361590Srgrimes return(1); 5371590Srgrimes for (i = 0; i < pln; ++i) { 5381590Srgrimes ips = 0; 5391590Srgrimes ops = 0; 5401590Srgrimes if (offst&& otln(buf,offst,&ips,&ops,1)) 5411590Srgrimes return(1); 5421590Srgrimes tvc = i; 5431590Srgrimes 5441590Srgrimes for (j = 0; j < clcnt; ++j) { 5451590Srgrimes /* 5461590Srgrimes * determine column length 5471590Srgrimes */ 5481590Srgrimes if (j == mclcnt) { 5491590Srgrimes /* 5501590Srgrimes * last column 5511590Srgrimes */ 5521590Srgrimes cnt = vc[tvc].cnt; 5531590Srgrimes if (nmwd) 5541590Srgrimes cnt += cw; 5551590Srgrimes } else if (sflag) { 5561590Srgrimes /* 5571590Srgrimes * single ch between 5581590Srgrimes */ 5591590Srgrimes cnt = vc[tvc].cnt + 1; 5601590Srgrimes if (nmwd) 5611590Srgrimes cnt += cw; 5621590Srgrimes } else 5631590Srgrimes cnt = fullcol; 5641590Srgrimes if (otln(vc[tvc].pt, cnt, &ips, 5651590Srgrimes &ops, 1)) 5661590Srgrimes return(1); 5671590Srgrimes tvc += pln; 5681590Srgrimes if (tvc >= cvc) 5691590Srgrimes break; 5701590Srgrimes } 5711590Srgrimes /* 5721590Srgrimes * terminate line 5731590Srgrimes */ 5741590Srgrimes if (otln(buf, 0, &ips, &ops, 0)) 5751590Srgrimes return(1); 5761590Srgrimes } 5771590Srgrimes /* 5781590Srgrimes * pad to end of page 5791590Srgrimes */ 5801590Srgrimes if (prtail((lines - pln), 0)) 5811590Srgrimes return(1); 5821590Srgrimes /* 5831590Srgrimes * done with output, go to next file 5841590Srgrimes */ 5851590Srgrimes break; 5861590Srgrimes } 5871590Srgrimes 5881590Srgrimes /* 5891590Srgrimes * determine how many lines to output 5901590Srgrimes */ 5911590Srgrimes if (i > 0) 5921590Srgrimes pln = lines; 5931590Srgrimes else 5941590Srgrimes pln = j; 5951590Srgrimes 5961590Srgrimes /* 5971590Srgrimes * print header 5981590Srgrimes */ 5991590Srgrimes if (pln && !nohead && prhead(hbuf, fname, pagecnt)) 6001590Srgrimes return(1); 6011590Srgrimes 6021590Srgrimes /* 6031590Srgrimes * output each line 6041590Srgrimes */ 6051590Srgrimes for (i = 0; i < pln; ++i) { 6061590Srgrimes ptbf = buf + lindy[i]; 6071590Srgrimes if ((j = lstdat[i] - ptbf) <= offst) 6081590Srgrimes break; 6091590Srgrimes if (otln(ptbf, j, &ips, &ops, 0)) 6101590Srgrimes return(1); 6111590Srgrimes } 6121590Srgrimes 6131590Srgrimes /* 6141590Srgrimes * pad to end of page 6151590Srgrimes */ 6161590Srgrimes if (pln && prtail((lines - pln), 0)) 6171590Srgrimes return(1); 6181590Srgrimes 6191590Srgrimes /* 6201590Srgrimes * if EOF go to next file 6211590Srgrimes */ 6221590Srgrimes if (cnt < 0) 6231590Srgrimes break; 6241590Srgrimes ++pagecnt; 6251590Srgrimes } 6261590Srgrimes if (inf != stdin) 6271590Srgrimes (void)fclose(inf); 6281590Srgrimes } 6291590Srgrimes if (eoptind < argc) 6301590Srgrimes return(1); 6311590Srgrimes return(0); 6321590Srgrimes} 6331590Srgrimes 6341590Srgrimes/* 6351590Srgrimes * horzcol: print files with more than one column of output across a page 6361590Srgrimes */ 6371590Srgrimesint 63898552Smarkmhorzcol(int argc, char *argv[]) 6391590Srgrimes{ 64098552Smarkm char *ptbf; 64198552Smarkm int pln; 64298552Smarkm int cnt = -1; 64398552Smarkm char *lstdat; 64498552Smarkm int col = colwd + 1; 64598552Smarkm int j; 64698552Smarkm int i; 6471590Srgrimes int lncnt; 6481590Srgrimes int pagecnt; 6491590Srgrimes char *buf; 6501590Srgrimes char *hbuf; 6511590Srgrimes char *ohbuf; 652102944Sdwmalone const char *fname; 6531590Srgrimes FILE *inf; 6541590Srgrimes int ips = 0; 6551590Srgrimes int cps = 0; 6561590Srgrimes int ops = 0; 6571590Srgrimes int mor = 0; 6581590Srgrimes 6591590Srgrimes if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { 6601590Srgrimes mfail(); 6611590Srgrimes return(1); 6621590Srgrimes } 6631590Srgrimes 6641590Srgrimes /* 6651590Srgrimes * page header 6661590Srgrimes */ 6671590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 6681590Srgrimes mfail(); 6691590Srgrimes return(1); 6701590Srgrimes } 6711590Srgrimes ohbuf = hbuf + offst; 6721590Srgrimes if (offst) { 6731590Srgrimes (void)memset(buf, (int)' ', offst); 6741590Srgrimes (void)memset(hbuf, (int)' ', offst); 6751590Srgrimes } 6761590Srgrimes 6771590Srgrimes /* 6781590Srgrimes * loop by file 6791590Srgrimes */ 6801590Srgrimes while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 6811590Srgrimes if (pgnm) { 6821590Srgrimes if (inskip(inf, pgnm, lines)) 6831590Srgrimes continue; 6841590Srgrimes pagecnt = pgnm; 6851590Srgrimes } else 6861590Srgrimes pagecnt = 1; 6871590Srgrimes lncnt = 0; 6881590Srgrimes 6891590Srgrimes /* 6901590Srgrimes * loop by page 6911590Srgrimes */ 6921590Srgrimes for(;;) { 69393481Sjmallett ttypause(pagecnt); 69493481Sjmallett 6951590Srgrimes /* 6961590Srgrimes * loop by line 6971590Srgrimes */ 6981590Srgrimes for (i = 0; i < lines; ++i) { 6991590Srgrimes ptbf = buf + offst; 7001590Srgrimes lstdat = ptbf; 7011590Srgrimes j = 0; 7021590Srgrimes /* 7031590Srgrimes * loop by col 7041590Srgrimes */ 7051590Srgrimes for(;;) { 7061590Srgrimes if (nmwd) { 7071590Srgrimes /* 7081590Srgrimes * add number to column 7091590Srgrimes */ 7101590Srgrimes addnum(ptbf, nmwd, ++lncnt); 7111590Srgrimes ptbf += nmwd; 7121590Srgrimes *ptbf++ = nmchar; 7131590Srgrimes } 7141590Srgrimes /* 7151590Srgrimes * input line 7161590Srgrimes */ 7171590Srgrimes if ((cnt = inln(inf,ptbf,colwd,&cps,1, 7181590Srgrimes &mor)) < 0) 7191590Srgrimes break; 7201590Srgrimes ptbf += cnt; 7211590Srgrimes lstdat = ptbf; 7221590Srgrimes 7231590Srgrimes /* 7241590Srgrimes * if last line skip padding 7251590Srgrimes */ 7261590Srgrimes if (++j >= clcnt) 7271590Srgrimes break; 7281590Srgrimes 7291590Srgrimes /* 7301590Srgrimes * pad to end of column 7311590Srgrimes */ 7321590Srgrimes if (sflag) 7331590Srgrimes *ptbf++ = schar; 7341590Srgrimes else if ((pln = col - cnt) > 0) { 7351590Srgrimes (void)memset(ptbf,(int)' ',pln); 7361590Srgrimes ptbf += pln; 7371590Srgrimes } 7381590Srgrimes } 7391590Srgrimes 7401590Srgrimes /* 7411590Srgrimes * determine line length 7421590Srgrimes */ 7431590Srgrimes if ((j = lstdat - buf) <= offst) 7441590Srgrimes break; 7451590Srgrimes if (!i && !nohead && 7461590Srgrimes prhead(hbuf, fname, pagecnt)) 7471590Srgrimes return(1); 7481590Srgrimes /* 7491590Srgrimes * output line 7501590Srgrimes */ 7511590Srgrimes if (otln(buf, j, &ips, &ops, 0)) 7521590Srgrimes return(1); 7531590Srgrimes } 7541590Srgrimes 7551590Srgrimes /* 7561590Srgrimes * pad to end of page 7571590Srgrimes */ 7581590Srgrimes if (i && prtail(lines-i, 0)) 7591590Srgrimes return(1); 7601590Srgrimes 7611590Srgrimes /* 7621590Srgrimes * if EOF go to next file 7631590Srgrimes */ 7641590Srgrimes if (cnt < 0) 7651590Srgrimes break; 7661590Srgrimes ++pagecnt; 7671590Srgrimes } 7681590Srgrimes if (inf != stdin) 7691590Srgrimes (void)fclose(inf); 7701590Srgrimes } 7711590Srgrimes if (eoptind < argc) 7721590Srgrimes return(1); 7731590Srgrimes return(0); 7741590Srgrimes} 7751590Srgrimes 7761590Srgrimes/* 7771590Srgrimes * mulfile: print files with more than one column of output and 7781590Srgrimes * more than one file concurrently 7791590Srgrimes */ 7801590Srgrimesint 78198552Smarkmmulfile(int argc, char *argv[]) 7821590Srgrimes{ 78398552Smarkm char *ptbf; 78498552Smarkm int j; 78598552Smarkm int pln; 78698552Smarkm int cnt; 78798552Smarkm char *lstdat; 78898552Smarkm int i; 7891590Srgrimes FILE **fbuf; 7901590Srgrimes int actf; 7911590Srgrimes int lncnt; 7921590Srgrimes int col; 7931590Srgrimes int pagecnt; 7941590Srgrimes int fproc; 7951590Srgrimes char *buf; 7961590Srgrimes char *hbuf; 7971590Srgrimes char *ohbuf; 798102944Sdwmalone const char *fname; 7991590Srgrimes int ips = 0; 8001590Srgrimes int cps = 0; 8011590Srgrimes int ops = 0; 8021590Srgrimes int mor = 0; 8031590Srgrimes 8041590Srgrimes /* 8051590Srgrimes * array of FILE *, one for each operand 8061590Srgrimes */ 8071590Srgrimes if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) { 8081590Srgrimes mfail(); 8091590Srgrimes return(1); 8101590Srgrimes } 8111590Srgrimes 8121590Srgrimes /* 8131590Srgrimes * page header 8141590Srgrimes */ 8151590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 8161590Srgrimes mfail(); 8171590Srgrimes return(1); 8181590Srgrimes } 8191590Srgrimes ohbuf = hbuf + offst; 8201590Srgrimes 8211590Srgrimes /* 8221590Srgrimes * do not know how many columns yet. The number of operands provide an 8231590Srgrimes * upper bound on the number of columns. We use the number of files 8241590Srgrimes * we can open successfully to set the number of columns. The operation 8251590Srgrimes * of the merge operation (-m) in relation to unsuccesful file opens 8261590Srgrimes * is unspecified by posix. 8271590Srgrimes */ 8281590Srgrimes j = 0; 8291590Srgrimes while (j < clcnt) { 8301590Srgrimes if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL) 8311590Srgrimes break; 8321590Srgrimes if (pgnm && (inskip(fbuf[j], pgnm, lines))) 8331590Srgrimes fbuf[j] = NULL; 8341590Srgrimes ++j; 8351590Srgrimes } 8361590Srgrimes 8371590Srgrimes /* 8381590Srgrimes * if no files, exit 8391590Srgrimes */ 8401590Srgrimes if (!j) 8411590Srgrimes return(1); 8421590Srgrimes 8431590Srgrimes /* 8441590Srgrimes * calculate page boundries based on open file count 8451590Srgrimes */ 8461590Srgrimes clcnt = j; 8471590Srgrimes if (nmwd) { 8481590Srgrimes colwd = (pgwd - clcnt - nmwd)/clcnt; 8491590Srgrimes pgwd = ((colwd + 1) * clcnt) - nmwd - 2; 8501590Srgrimes } else { 8511590Srgrimes colwd = (pgwd + 1 - clcnt)/clcnt; 8521590Srgrimes pgwd = ((colwd + 1) * clcnt) - 1; 8531590Srgrimes } 8541590Srgrimes if (colwd < 1) { 8551590Srgrimes (void)fprintf(err, 8561590Srgrimes "pr: page width too small for %d columns\n", clcnt); 8571590Srgrimes return(1); 8581590Srgrimes } 8591590Srgrimes actf = clcnt; 8601590Srgrimes col = colwd + 1; 8611590Srgrimes 8621590Srgrimes /* 8631590Srgrimes * line buffer 8641590Srgrimes */ 8651590Srgrimes if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { 8661590Srgrimes mfail(); 8671590Srgrimes return(1); 8681590Srgrimes } 8691590Srgrimes if (offst) { 8701590Srgrimes (void)memset(buf, (int)' ', offst); 8711590Srgrimes (void)memset(hbuf, (int)' ', offst); 8721590Srgrimes } 8731590Srgrimes if (pgnm) 8741590Srgrimes pagecnt = pgnm; 8751590Srgrimes else 8761590Srgrimes pagecnt = 1; 8771590Srgrimes lncnt = 0; 8781590Srgrimes 8791590Srgrimes /* 8801590Srgrimes * continue to loop while any file still has data 8811590Srgrimes */ 8821590Srgrimes while (actf > 0) { 88393481Sjmallett ttypause(pagecnt); 88493481Sjmallett 8851590Srgrimes /* 8861590Srgrimes * loop by line 8871590Srgrimes */ 8881590Srgrimes for (i = 0; i < lines; ++i) { 8891590Srgrimes ptbf = buf + offst; 8901590Srgrimes lstdat = ptbf; 8911590Srgrimes if (nmwd) { 8921590Srgrimes /* 8931590Srgrimes * add line number to line 8941590Srgrimes */ 8951590Srgrimes addnum(ptbf, nmwd, ++lncnt); 8961590Srgrimes ptbf += nmwd; 8971590Srgrimes *ptbf++ = nmchar; 8981590Srgrimes } 8991590Srgrimes j = 0; 9001590Srgrimes fproc = 0; 9011590Srgrimes 9021590Srgrimes /* 9031590Srgrimes * loop by column 9041590Srgrimes */ 9051590Srgrimes for (j = 0; j < clcnt; ++j) { 9061590Srgrimes if (fbuf[j] == NULL) { 9071590Srgrimes /* 9081590Srgrimes * empty column; EOF 9091590Srgrimes */ 9101590Srgrimes cnt = 0; 9111590Srgrimes } else if ((cnt = inln(fbuf[j], ptbf, colwd, 9121590Srgrimes &cps, 1, &mor)) < 0) { 9131590Srgrimes /* 9141590Srgrimes * EOF hit; no data 9151590Srgrimes */ 9161590Srgrimes if (fbuf[j] != stdin) 9171590Srgrimes (void)fclose(fbuf[j]); 9181590Srgrimes fbuf[j] = NULL; 9191590Srgrimes --actf; 9201590Srgrimes cnt = 0; 9211590Srgrimes } else { 9221590Srgrimes /* 9231590Srgrimes * process file data 9241590Srgrimes */ 9251590Srgrimes ptbf += cnt; 9261590Srgrimes lstdat = ptbf; 9271590Srgrimes fproc++; 9281590Srgrimes } 9291590Srgrimes 9301590Srgrimes /* 9311590Srgrimes * if last ACTIVE column, done with line 9321590Srgrimes */ 9331590Srgrimes if (fproc >= actf) 9341590Srgrimes break; 9351590Srgrimes 9361590Srgrimes /* 9371590Srgrimes * pad to end of column 9381590Srgrimes */ 9391590Srgrimes if (sflag) { 9401590Srgrimes *ptbf++ = schar; 9411590Srgrimes } else if ((pln = col - cnt) > 0) { 9421590Srgrimes (void)memset(ptbf, (int)' ', pln); 9431590Srgrimes ptbf += pln; 9441590Srgrimes } 9451590Srgrimes } 9461590Srgrimes 9471590Srgrimes /* 9481590Srgrimes * calculate data in line 9491590Srgrimes */ 9501590Srgrimes if ((j = lstdat - buf) <= offst) 9511590Srgrimes break; 9521590Srgrimes 9531590Srgrimes if (!i && !nohead && prhead(hbuf, fname, pagecnt)) 9541590Srgrimes return(1); 9551590Srgrimes 9561590Srgrimes /* 9571590Srgrimes * output line 9581590Srgrimes */ 9591590Srgrimes if (otln(buf, j, &ips, &ops, 0)) 9601590Srgrimes return(1); 9611590Srgrimes 9621590Srgrimes /* 9631590Srgrimes * if no more active files, done 9641590Srgrimes */ 9651590Srgrimes if (actf <= 0) { 9661590Srgrimes ++i; 9671590Srgrimes break; 9681590Srgrimes } 9691590Srgrimes } 9701590Srgrimes 9711590Srgrimes /* 9721590Srgrimes * pad to end of page 9731590Srgrimes */ 9741590Srgrimes if (i && prtail(lines-i, 0)) 9751590Srgrimes return(1); 9761590Srgrimes ++pagecnt; 9771590Srgrimes } 9781590Srgrimes if (eoptind < argc) 9791590Srgrimes return(1); 9801590Srgrimes return(0); 9811590Srgrimes} 9821590Srgrimes 9831590Srgrimes/* 9841590Srgrimes * inln(): input a line of data (unlimited length lines supported) 9851590Srgrimes * Input is optionally expanded to spaces 9861590Srgrimes * 9871590Srgrimes * inf: file 9881590Srgrimes * buf: buffer 9891590Srgrimes * lim: buffer length 9901590Srgrimes * cps: column positon 1st char in buffer (large line support) 9918874Srgrimes * trnc: throw away data more than lim up to \n 9921590Srgrimes * mor: set if more data in line (not truncated) 9931590Srgrimes */ 9941590Srgrimesint 99598552Smarkminln(FILE *inf, char *buf, int lim, int *cps, int trnc, int *mor) 9961590Srgrimes{ 99798552Smarkm int col; 99898552Smarkm int gap = ingap; 99998552Smarkm int ch = EOF; 100098552Smarkm char *ptbuf; 100198552Smarkm int chk = (int)inchar; 10021590Srgrimes 10031590Srgrimes ptbuf = buf; 10041590Srgrimes 10051590Srgrimes if (gap) { 10061590Srgrimes /* 10071590Srgrimes * expanding input option 10081590Srgrimes */ 10091590Srgrimes while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { 10101590Srgrimes /* 10111590Srgrimes * is this the input "tab" char 10121590Srgrimes */ 10131590Srgrimes if (ch == chk) { 10141590Srgrimes /* 10151590Srgrimes * expand to number of spaces 10161590Srgrimes */ 10171590Srgrimes col = (ptbuf - buf) + *cps; 10181590Srgrimes col = gap - (col % gap); 10191590Srgrimes 10201590Srgrimes /* 10211590Srgrimes * if more than this line, push back 10221590Srgrimes */ 10231590Srgrimes if ((col > lim) && (ungetc(ch, inf) == EOF)) 10241590Srgrimes return(1); 10251590Srgrimes 10261590Srgrimes /* 10271590Srgrimes * expand to spaces 10281590Srgrimes */ 10291590Srgrimes while ((--col >= 0) && (--lim >= 0)) 10301590Srgrimes *ptbuf++ = ' '; 10311590Srgrimes continue; 10321590Srgrimes } 10331590Srgrimes if (ch == '\n') 10341590Srgrimes break; 10351590Srgrimes *ptbuf++ = ch; 10361590Srgrimes } 10371590Srgrimes } else { 10381590Srgrimes /* 10391590Srgrimes * no expansion 10401590Srgrimes */ 10411590Srgrimes while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { 10421590Srgrimes if (ch == '\n') 10431590Srgrimes break; 10441590Srgrimes *ptbuf++ = ch; 10451590Srgrimes } 10461590Srgrimes } 10471590Srgrimes col = ptbuf - buf; 10481590Srgrimes if (ch == EOF) { 10491590Srgrimes *mor = 0; 10501590Srgrimes *cps = 0; 10511590Srgrimes if (!col) 10521590Srgrimes return(-1); 10531590Srgrimes return(col); 10541590Srgrimes } 10551590Srgrimes if (ch == '\n') { 10561590Srgrimes /* 10571590Srgrimes * entire line processed 10581590Srgrimes */ 10591590Srgrimes *mor = 0; 10601590Srgrimes *cps = 0; 10611590Srgrimes return(col); 10621590Srgrimes } 10631590Srgrimes 10641590Srgrimes /* 10651590Srgrimes * line was larger than limit 10661590Srgrimes */ 10671590Srgrimes if (trnc) { 10681590Srgrimes /* 10691590Srgrimes * throw away rest of line 10701590Srgrimes */ 10711590Srgrimes while ((ch = getc(inf)) != EOF) { 10721590Srgrimes if (ch == '\n') 10731590Srgrimes break; 10741590Srgrimes } 10751590Srgrimes *cps = 0; 10761590Srgrimes *mor = 0; 10771590Srgrimes } else { 10781590Srgrimes /* 10791590Srgrimes * save column offset if not truncated 10801590Srgrimes */ 10811590Srgrimes *cps += col; 10821590Srgrimes *mor = 1; 10831590Srgrimes } 10841590Srgrimes 10851590Srgrimes return(col); 10861590Srgrimes} 10871590Srgrimes 10881590Srgrimes/* 10891590Srgrimes * otln(): output a line of data. (Supports unlimited length lines) 10901590Srgrimes * output is optionally contracted to tabs 10911590Srgrimes * 10921590Srgrimes * buf: output buffer with data 10931590Srgrimes * cnt: number of chars of valid data in buf 10941590Srgrimes * svips: buffer input column position (for large lines) 10951590Srgrimes * svops: buffer output column position (for large lines) 10968874Srgrimes * mor: output line not complete in this buf; more data to come. 10971590Srgrimes * 1 is more, 0 is complete, -1 is no \n's 10981590Srgrimes */ 10991590Srgrimesint 110098552Smarkmotln(char *buf, int cnt, int *svips, int *svops, int mor) 11011590Srgrimes{ 110298552Smarkm int ops; /* last col output */ 110398552Smarkm int ips; /* last col in buf examined */ 110498552Smarkm int gap = ogap; 110598552Smarkm int tbps; 110698552Smarkm char *endbuf; 11071590Srgrimes 11081590Srgrimes if (ogap) { 11091590Srgrimes /* 11101590Srgrimes * contracting on output 11111590Srgrimes */ 11121590Srgrimes endbuf = buf + cnt; 11131590Srgrimes ops = *svops; 11141590Srgrimes ips = *svips; 11151590Srgrimes while (buf < endbuf) { 11161590Srgrimes /* 11171590Srgrimes * count number of spaces and ochar in buffer 11181590Srgrimes */ 11191590Srgrimes if (*buf == ' ') { 11201590Srgrimes ++ips; 11211590Srgrimes ++buf; 11221590Srgrimes continue; 11231590Srgrimes } 11241590Srgrimes 11251590Srgrimes /* 11261590Srgrimes * simulate ochar processing 11271590Srgrimes */ 11281590Srgrimes if (*buf == ochar) { 11291590Srgrimes ips += gap - (ips % gap); 11301590Srgrimes ++buf; 11311590Srgrimes continue; 11321590Srgrimes } 11331590Srgrimes 11341590Srgrimes /* 11351590Srgrimes * got a non space char; contract out spaces 11361590Srgrimes */ 113798408Stjr while (ips - ops > 1) { 11381590Srgrimes /* 11391590Srgrimes * use as many ochar as will fit 11401590Srgrimes */ 11411590Srgrimes if ((tbps = ops + gap - (ops % gap)) > ips) 11421590Srgrimes break; 11431590Srgrimes if (putchar(ochar) == EOF) { 11441590Srgrimes pfail(); 11451590Srgrimes return(1); 11461590Srgrimes } 11471590Srgrimes ops = tbps; 11481590Srgrimes } 11491590Srgrimes 11501590Srgrimes while (ops < ips) { 11511590Srgrimes /* 11521590Srgrimes * finish off with spaces 11531590Srgrimes */ 11541590Srgrimes if (putchar(' ') == EOF) { 11551590Srgrimes pfail(); 11561590Srgrimes return(1); 11571590Srgrimes } 11581590Srgrimes ++ops; 11591590Srgrimes } 11601590Srgrimes 11611590Srgrimes /* 11621590Srgrimes * output non space char 11631590Srgrimes */ 11641590Srgrimes if (putchar(*buf++) == EOF) { 11651590Srgrimes pfail(); 11661590Srgrimes return(1); 11671590Srgrimes } 11681590Srgrimes ++ips; 11691590Srgrimes ++ops; 11701590Srgrimes } 11711590Srgrimes 11721590Srgrimes if (mor > 0) { 11731590Srgrimes /* 11741590Srgrimes * if incomplete line, save position counts 11751590Srgrimes */ 11761590Srgrimes *svops = ops; 11771590Srgrimes *svips = ips; 11781590Srgrimes return(0); 11791590Srgrimes } 11801590Srgrimes 11811590Srgrimes if (mor < 0) { 118298408Stjr while (ips - ops > 1) { 11831590Srgrimes /* 11841590Srgrimes * use as many ochar as will fit 11851590Srgrimes */ 11861590Srgrimes if ((tbps = ops + gap - (ops % gap)) > ips) 11871590Srgrimes break; 11881590Srgrimes if (putchar(ochar) == EOF) { 11891590Srgrimes pfail(); 11901590Srgrimes return(1); 11911590Srgrimes } 11921590Srgrimes ops = tbps; 11931590Srgrimes } 11941590Srgrimes while (ops < ips) { 11951590Srgrimes /* 11961590Srgrimes * finish off with spaces 11971590Srgrimes */ 11981590Srgrimes if (putchar(' ') == EOF) { 11991590Srgrimes pfail(); 12001590Srgrimes return(1); 12011590Srgrimes } 12021590Srgrimes ++ops; 12031590Srgrimes } 12041590Srgrimes return(0); 12051590Srgrimes } 12061590Srgrimes } else { 12071590Srgrimes /* 12081590Srgrimes * output is not contracted 12091590Srgrimes */ 12101590Srgrimes if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) { 12111590Srgrimes pfail(); 12121590Srgrimes return(1); 12131590Srgrimes } 12141590Srgrimes if (mor != 0) 12151590Srgrimes return(0); 12161590Srgrimes } 12171590Srgrimes 12181590Srgrimes /* 12191590Srgrimes * process line end and double space as required 12201590Srgrimes */ 12211590Srgrimes if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) { 12221590Srgrimes pfail(); 12231590Srgrimes return(1); 12241590Srgrimes } 12251590Srgrimes return(0); 12261590Srgrimes} 12271590Srgrimes 12281590Srgrimes/* 12291590Srgrimes * inskip(): skip over pgcnt pages with lncnt lines per page 12301590Srgrimes * file is closed at EOF (if not stdin). 12311590Srgrimes * 12321590Srgrimes * inf FILE * to read from 12331590Srgrimes * pgcnt number of pages to skip 12341590Srgrimes * lncnt number of lines per page 12351590Srgrimes */ 12361590Srgrimesint 123798552Smarkminskip(FILE *inf, int pgcnt, int lncnt) 12381590Srgrimes{ 123998552Smarkm int c; 124098552Smarkm int cnt; 12411590Srgrimes 12421590Srgrimes while(--pgcnt > 0) { 12431590Srgrimes cnt = lncnt; 12441590Srgrimes while ((c = getc(inf)) != EOF) { 12451590Srgrimes if ((c == '\n') && (--cnt == 0)) 12461590Srgrimes break; 12471590Srgrimes } 12481590Srgrimes if (c == EOF) { 12491590Srgrimes if (inf != stdin) 12501590Srgrimes (void)fclose(inf); 12511590Srgrimes return(1); 12521590Srgrimes } 12531590Srgrimes } 12541590Srgrimes return(0); 12551590Srgrimes} 12561590Srgrimes 12571590Srgrimes/* 12581590Srgrimes * nxtfile: returns a FILE * to next file in arg list and sets the 12591590Srgrimes * time field for this file (or current date). 12601590Srgrimes * 12611590Srgrimes * buf array to store proper date for the header. 12621590Srgrimes * dt if set skips the date processing (used with -m) 12631590Srgrimes */ 12641590SrgrimesFILE * 1265102944Sdwmalonenxtfile(int argc, char **argv, const char **fname, char *buf, int dt) 12661590Srgrimes{ 12671590Srgrimes FILE *inf = NULL; 126837262Sbde time_t tv_sec; 12691590Srgrimes struct tm *timeptr = NULL; 12701590Srgrimes struct stat statbuf; 12711590Srgrimes static int twice = -1; 12721590Srgrimes 12731590Srgrimes ++twice; 12741590Srgrimes if (eoptind >= argc) { 12751590Srgrimes /* 12761590Srgrimes * no file listed; default, use standard input 12771590Srgrimes */ 12781590Srgrimes if (twice) 12791590Srgrimes return(NULL); 12801590Srgrimes clearerr(stdin); 12811590Srgrimes inf = stdin; 12821590Srgrimes if (header != NULL) 12831590Srgrimes *fname = header; 12841590Srgrimes else 128598552Smarkm *fname = fnamedefault; 12861590Srgrimes if (nohead) 12871590Srgrimes return(inf); 1288204358Sed if ((tv_sec = time(NULL)) == -1) { 12891590Srgrimes ++errcnt; 12901590Srgrimes (void)fprintf(err, "pr: cannot get time of day, %s\n", 12911590Srgrimes strerror(errno)); 12921590Srgrimes eoptind = argc - 1; 12931590Srgrimes return(NULL); 12941590Srgrimes } 129537262Sbde timeptr = localtime(&tv_sec); 12961590Srgrimes } 12971590Srgrimes for (; eoptind < argc; ++eoptind) { 12981590Srgrimes if (strcmp(argv[eoptind], "-") == 0) { 12991590Srgrimes /* 13001590Srgrimes * process a "-" for filename 13011590Srgrimes */ 13021590Srgrimes clearerr(stdin); 13031590Srgrimes inf = stdin; 13041590Srgrimes if (header != NULL) 13051590Srgrimes *fname = header; 13061590Srgrimes else 130798552Smarkm *fname = fnamedefault; 13081590Srgrimes ++eoptind; 13091590Srgrimes if (nohead || (dt && twice)) 13101590Srgrimes return(inf); 1311204358Sed if ((tv_sec = time(NULL)) == -1) { 13121590Srgrimes ++errcnt; 13131590Srgrimes (void)fprintf(err, 13141590Srgrimes "pr: cannot get time of day, %s\n", 13151590Srgrimes strerror(errno)); 13161590Srgrimes return(NULL); 13171590Srgrimes } 131837262Sbde timeptr = localtime(&tv_sec); 13191590Srgrimes } else { 13201590Srgrimes /* 13211590Srgrimes * normal file processing 13221590Srgrimes */ 13231590Srgrimes if ((inf = fopen(argv[eoptind], "r")) == NULL) { 13241590Srgrimes ++errcnt; 13251590Srgrimes if (nodiag) 13261590Srgrimes continue; 1327132672Scharnier (void)fprintf(err, "pr: cannot open %s, %s\n", 13281590Srgrimes argv[eoptind], strerror(errno)); 13291590Srgrimes continue; 13301590Srgrimes } 13311590Srgrimes if (header != NULL) 13321590Srgrimes *fname = header; 13331590Srgrimes else if (dt) 133498552Smarkm *fname = fnamedefault; 13351590Srgrimes else 13361590Srgrimes *fname = argv[eoptind]; 13371590Srgrimes ++eoptind; 13381590Srgrimes if (nohead || (dt && twice)) 13391590Srgrimes return(inf); 13401590Srgrimes 13411590Srgrimes if (dt) { 1342204358Sed if ((tv_sec = time(NULL)) == -1) { 13431590Srgrimes ++errcnt; 13441590Srgrimes (void)fprintf(err, 13451590Srgrimes "pr: cannot get time of day, %s\n", 13461590Srgrimes strerror(errno)); 13471590Srgrimes return(NULL); 13481590Srgrimes } 134937262Sbde timeptr = localtime(&tv_sec); 13501590Srgrimes } else { 13511590Srgrimes if (fstat(fileno(inf), &statbuf) < 0) { 13521590Srgrimes ++errcnt; 13531590Srgrimes (void)fclose(inf); 13548874Srgrimes (void)fprintf(err, 1355132672Scharnier "pr: cannot stat %s, %s\n", 13561590Srgrimes argv[eoptind], strerror(errno)); 13571590Srgrimes return(NULL); 13581590Srgrimes } 13591590Srgrimes timeptr = localtime(&(statbuf.st_mtime)); 13601590Srgrimes } 13611590Srgrimes } 13621590Srgrimes break; 13631590Srgrimes } 13641590Srgrimes if (inf == NULL) 13651590Srgrimes return(NULL); 13661590Srgrimes 13671590Srgrimes /* 13681590Srgrimes * set up time field used in header 13691590Srgrimes */ 13701590Srgrimes if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { 13711590Srgrimes ++errcnt; 13721590Srgrimes if (inf != stdin) 13731590Srgrimes (void)fclose(inf); 13741590Srgrimes (void)fputs("pr: time conversion failed\n", err); 13751590Srgrimes return(NULL); 13761590Srgrimes } 13771590Srgrimes return(inf); 13781590Srgrimes} 13791590Srgrimes 13801590Srgrimes/* 13811590Srgrimes * addnum(): adds the line number to the column 13821590Srgrimes * Truncates from the front or pads with spaces as required. 13831590Srgrimes * Numbers are right justified. 13841590Srgrimes * 13851590Srgrimes * buf buffer to store the number 13861590Srgrimes * wdth width of buffer to fill 13871590Srgrimes * line line number 13881590Srgrimes * 13891590Srgrimes * NOTE: numbers occupy part of the column. The posix 13901590Srgrimes * spec does not specify if -i processing should or should not 13911590Srgrimes * occur on number padding. The spec does say it occupies 13921590Srgrimes * part of the column. The usage of addnum currently treats 13931590Srgrimes * numbers as part of the column so spaces may be replaced. 13941590Srgrimes */ 13951590Srgrimesvoid 139698552Smarkmaddnum(char *buf, int wdth, int line) 13971590Srgrimes{ 139898552Smarkm char *pt = buf + wdth; 13991590Srgrimes 14001590Srgrimes do { 14011590Srgrimes *--pt = digs[line % 10]; 14021590Srgrimes line /= 10; 14031590Srgrimes } while (line && (pt > buf)); 14041590Srgrimes 14051590Srgrimes /* 14061590Srgrimes * pad with space as required 14071590Srgrimes */ 14081590Srgrimes while (pt > buf) 14091590Srgrimes *--pt = ' '; 14101590Srgrimes} 14111590Srgrimes 14121590Srgrimes/* 14131590Srgrimes * prhead(): prints the top of page header 14141590Srgrimes * 14151590Srgrimes * buf buffer with time field (and offset) 14161590Srgrimes * cnt number of chars in buf 14171590Srgrimes * fname fname field for header 14181590Srgrimes * pagcnt page number 14191590Srgrimes */ 14201590Srgrimesint 1421102944Sdwmaloneprhead(char *buf, const char *fname, int pagcnt) 14221590Srgrimes{ 14231590Srgrimes int ips = 0; 14241590Srgrimes int ops = 0; 14251590Srgrimes 14261590Srgrimes if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { 14271590Srgrimes pfail(); 14281590Srgrimes return(1); 14291590Srgrimes } 14301590Srgrimes /* 14311590Srgrimes * posix is not clear if the header is subject to line length 14321590Srgrimes * restrictions. The specification for header line format 14331590Srgrimes * in the spec clearly does not limit length. No pr currently 14341590Srgrimes * restricts header length. However if we need to truncate in 1435108470Sschweikh * a reasonable way, adjust the length of the printf by 1436151701Sjhb * changing HDFMT to allow a length max as an argument to printf. 14371590Srgrimes * buf (which contains the offset spaces and time field could 14381590Srgrimes * also be trimmed 14391590Srgrimes * 14401590Srgrimes * note only the offset (if any) is processed for tab expansion 14411590Srgrimes */ 14421590Srgrimes if (offst && otln(buf, offst, &ips, &ops, -1)) 14431590Srgrimes return(1); 14441590Srgrimes (void)printf(HDFMT,buf+offst, fname, pagcnt); 14451590Srgrimes return(0); 14461590Srgrimes} 14471590Srgrimes 14481590Srgrimes/* 14491590Srgrimes * prtail(): pad page with empty lines (if required) and print page trailer 14501590Srgrimes * if requested 14511590Srgrimes * 14521590Srgrimes * cnt number of lines of padding needed 14531590Srgrimes * incomp was a '\n' missing from last line output 14541590Srgrimes */ 14551590Srgrimesint 145698552Smarkmprtail(int cnt, int incomp) 14571590Srgrimes{ 14581590Srgrimes if (nohead) { 14591590Srgrimes /* 14601590Srgrimes * only pad with no headers when incomplete last line 14611590Srgrimes */ 146219092Sscrappy if (incomp && 146319092Sscrappy ((dspace && (putchar('\n') == EOF)) || 146419092Sscrappy (putchar('\n') == EOF))) { 14651590Srgrimes pfail(); 14661590Srgrimes return(1); 14671590Srgrimes } 146819092Sscrappy /* 146919092Sscrappy * but honor the formfeed request 147019092Sscrappy */ 147119092Sscrappy if (formfeed) { 147219092Sscrappy if (putchar('\f') == EOF) { 147319092Sscrappy pfail(); 147419092Sscrappy return(1); 147519092Sscrappy } 147619092Sscrappy } 14771590Srgrimes return(0); 14781590Srgrimes } 14791590Srgrimes /* 14801590Srgrimes * if double space output two \n 14811590Srgrimes */ 14821590Srgrimes if (dspace) 14831590Srgrimes cnt *= 2; 14841590Srgrimes 14851590Srgrimes /* 14861590Srgrimes * if an odd number of lines per page, add an extra \n 14871590Srgrimes */ 14881590Srgrimes if (addone) 14891590Srgrimes ++cnt; 14901590Srgrimes 14911590Srgrimes /* 14921590Srgrimes * pad page 14931590Srgrimes */ 14941590Srgrimes if (formfeed) { 14958874Srgrimes if ((incomp && (putchar('\n') == EOF)) || 14961590Srgrimes (putchar('\f') == EOF)) { 14971590Srgrimes pfail(); 14981590Srgrimes return(1); 14991590Srgrimes } 15001590Srgrimes return(0); 15018874Srgrimes } 15021590Srgrimes cnt += TAILLEN; 15031590Srgrimes while (--cnt >= 0) { 15041590Srgrimes if (putchar('\n') == EOF) { 15051590Srgrimes pfail(); 15061590Srgrimes return(1); 15071590Srgrimes } 15081590Srgrimes } 15091590Srgrimes return(0); 15101590Srgrimes} 15111590Srgrimes 15121590Srgrimes/* 15131590Srgrimes * terminate(): when a SIGINT is recvd 15141590Srgrimes */ 15151590Srgrimesvoid 151698552Smarkmterminate(int which_sig __unused) 15171590Srgrimes{ 15181590Srgrimes flsh_errs(); 15191590Srgrimes exit(1); 15201590Srgrimes} 15211590Srgrimes 15221590Srgrimes 15231590Srgrimes/* 15241590Srgrimes * flsh_errs(): output saved up diagnostic messages after all normal 15251590Srgrimes * processing has completed 15261590Srgrimes */ 15271590Srgrimesvoid 152898552Smarkmflsh_errs(void) 15291590Srgrimes{ 15301590Srgrimes char buf[BUFSIZ]; 15311590Srgrimes 15321590Srgrimes (void)fflush(stdout); 15331590Srgrimes (void)fflush(err); 15341590Srgrimes if (err == stderr) 15351590Srgrimes return; 15361590Srgrimes rewind(err); 15371590Srgrimes while (fgets(buf, BUFSIZ, err) != NULL) 15381590Srgrimes (void)fputs(buf, stderr); 15391590Srgrimes} 15401590Srgrimes 15411590Srgrimesvoid 154298552Smarkmmfail(void) 15431590Srgrimes{ 15441590Srgrimes (void)fputs("pr: memory allocation failed\n", err); 15451590Srgrimes} 15461590Srgrimes 15471590Srgrimesvoid 154898552Smarkmpfail(void) 15491590Srgrimes{ 15501590Srgrimes (void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); 15511590Srgrimes} 15521590Srgrimes 15531590Srgrimesvoid 155498552Smarkmusage(void) 15551590Srgrimes{ 15561590Srgrimes (void)fputs( 155793481Sjmallett "usage: pr [+page] [-col] [-adFfmprt] [-e[ch][gap]] [-h header]\n", 155893481Sjmallett err); 15591590Srgrimes (void)fputs( 15601590Srgrimes " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); 15611590Srgrimes (void)fputs( 156253955Sache " [-L locale] [-s[ch]] [-w width] [-] [file ...]\n", err); 15631590Srgrimes} 15641590Srgrimes 15651590Srgrimes/* 15668874Srgrimes * setup: Validate command args, initialize and perform sanity 15671590Srgrimes * checks on options 15681590Srgrimes */ 15691590Srgrimesint 157098552Smarkmsetup(int argc, char *argv[]) 15711590Srgrimes{ 157298552Smarkm int c; 157374575Sache int d_first; 15741590Srgrimes int eflag = 0; 15751590Srgrimes int iflag = 0; 15761590Srgrimes int wflag = 0; 15771590Srgrimes int cflag = 0; 157853955Sache char *Lflag = NULL; 15791590Srgrimes 15801590Srgrimes if (isatty(fileno(stdout))) { 15811590Srgrimes /* 15821590Srgrimes * defer diagnostics until processing is done 15831590Srgrimes */ 15841590Srgrimes if ((err = tmpfile()) == NULL) { 158590788Sjedgar err = stderr; 15861590Srgrimes (void)fputs("Cannot defer diagnostic messages\n",stderr); 15871590Srgrimes return(1); 15881590Srgrimes } 15891590Srgrimes } else 15901590Srgrimes err = stderr; 159193481Sjmallett while ((c = egetopt(argc, argv, "#adFfmrte?h:i?L:l:n?o:ps?w:")) != -1) { 15921590Srgrimes switch (c) { 15931590Srgrimes case '+': 15941590Srgrimes if ((pgnm = atoi(eoptarg)) < 1) { 15951590Srgrimes (void)fputs("pr: +page number must be 1 or more\n", 15961590Srgrimes err); 15971590Srgrimes return(1); 15981590Srgrimes } 15991590Srgrimes break; 16001590Srgrimes case '-': 16011590Srgrimes if ((clcnt = atoi(eoptarg)) < 1) { 16021590Srgrimes (void)fputs("pr: -columns must be 1 or more\n",err); 16031590Srgrimes return(1); 16041590Srgrimes } 16051590Srgrimes if (clcnt > 1) 16061590Srgrimes ++cflag; 16071590Srgrimes break; 16081590Srgrimes case 'a': 16091590Srgrimes ++across; 16101590Srgrimes break; 16111590Srgrimes case 'd': 16121590Srgrimes ++dspace; 16131590Srgrimes break; 16141590Srgrimes case 'e': 16151590Srgrimes ++eflag; 161653948Sache if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg)) 16171590Srgrimes inchar = *eoptarg++; 16181590Srgrimes else 16191590Srgrimes inchar = INCHAR; 162053948Sache if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) { 16211590Srgrimes if ((ingap = atoi(eoptarg)) < 0) { 16221590Srgrimes (void)fputs( 16231590Srgrimes "pr: -e gap must be 0 or more\n", err); 16241590Srgrimes return(1); 16251590Srgrimes } 16261590Srgrimes if (ingap == 0) 16271590Srgrimes ingap = INGAP; 16281590Srgrimes } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 16291590Srgrimes (void)fprintf(err, 16301590Srgrimes "pr: invalid value for -e %s\n", eoptarg); 16311590Srgrimes return(1); 16321590Srgrimes } else 16331590Srgrimes ingap = INGAP; 16341590Srgrimes break; 163593481Sjmallett case 'f': 163693481Sjmallett ++pausefst; 163793481Sjmallett /*FALLTHROUGH*/ 16381590Srgrimes case 'F': 16391590Srgrimes ++formfeed; 16401590Srgrimes break; 16411590Srgrimes case 'h': 16421590Srgrimes header = eoptarg; 16431590Srgrimes break; 16441590Srgrimes case 'i': 16451590Srgrimes ++iflag; 164653948Sache if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg)) 16471590Srgrimes ochar = *eoptarg++; 16481590Srgrimes else 16491590Srgrimes ochar = OCHAR; 165053948Sache if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) { 16511590Srgrimes if ((ogap = atoi(eoptarg)) < 0) { 16521590Srgrimes (void)fputs( 16531590Srgrimes "pr: -i gap must be 0 or more\n", err); 16541590Srgrimes return(1); 16551590Srgrimes } 16561590Srgrimes if (ogap == 0) 16571590Srgrimes ogap = OGAP; 16581590Srgrimes } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 16591590Srgrimes (void)fprintf(err, 16601590Srgrimes "pr: invalid value for -i %s\n", eoptarg); 16611590Srgrimes return(1); 16621590Srgrimes } else 16631590Srgrimes ogap = OGAP; 16641590Srgrimes break; 166553948Sache case 'L': 166653955Sache Lflag = eoptarg; 166753948Sache break; 16681590Srgrimes case 'l': 166953948Sache if (!isdigit((unsigned char)*eoptarg) || ((lines=atoi(eoptarg)) < 1)) { 16701590Srgrimes (void)fputs( 1671132672Scharnier "pr: number of lines must be 1 or more\n",err); 16721590Srgrimes return(1); 16731590Srgrimes } 16741590Srgrimes break; 16751590Srgrimes case 'm': 16761590Srgrimes ++merge; 16771590Srgrimes break; 16781590Srgrimes case 'n': 167953948Sache if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg)) 16801590Srgrimes nmchar = *eoptarg++; 16811590Srgrimes else 16821590Srgrimes nmchar = NMCHAR; 168353948Sache if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) { 16841590Srgrimes if ((nmwd = atoi(eoptarg)) < 1) { 16851590Srgrimes (void)fputs( 16861590Srgrimes "pr: -n width must be 1 or more\n",err); 16871590Srgrimes return(1); 16881590Srgrimes } 16891590Srgrimes } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 16901590Srgrimes (void)fprintf(err, 16911590Srgrimes "pr: invalid value for -n %s\n", eoptarg); 16921590Srgrimes return(1); 16931590Srgrimes } else 16941590Srgrimes nmwd = NMWD; 16951590Srgrimes break; 16961590Srgrimes case 'o': 169753948Sache if (!isdigit((unsigned char)*eoptarg) || ((offst = atoi(eoptarg))< 1)){ 16981590Srgrimes (void)fputs("pr: -o offset must be 1 or more\n", 16991590Srgrimes err); 17001590Srgrimes return(1); 17011590Srgrimes } 17021590Srgrimes break; 170393481Sjmallett case 'p': 170493481Sjmallett ++pauseall; 170593481Sjmallett break; 17061590Srgrimes case 'r': 17071590Srgrimes ++nodiag; 17081590Srgrimes break; 17091590Srgrimes case 's': 17101590Srgrimes ++sflag; 17111590Srgrimes if (eoptarg == NULL) 17121590Srgrimes schar = SCHAR; 171354114Skris else { 17141590Srgrimes schar = *eoptarg++; 171554114Skris if (*eoptarg != '\0') { 171654114Skris (void)fprintf(err, 171754114Skris "pr: invalid value for -s %s\n", 171854114Skris eoptarg); 171954114Skris return(1); 172054114Skris } 17211590Srgrimes } 17221590Srgrimes break; 17231590Srgrimes case 't': 17241590Srgrimes ++nohead; 17251590Srgrimes break; 17261590Srgrimes case 'w': 17271590Srgrimes ++wflag; 172853948Sache if (!isdigit((unsigned char)*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){ 17291590Srgrimes (void)fputs( 17301590Srgrimes "pr: -w width must be 1 or more \n",err); 17311590Srgrimes return(1); 17321590Srgrimes } 17331590Srgrimes break; 17341590Srgrimes case '?': 17351590Srgrimes default: 17361590Srgrimes return(1); 17371590Srgrimes } 17381590Srgrimes } 17391590Srgrimes 17401590Srgrimes /* 17411590Srgrimes * default and sanity checks 17421590Srgrimes */ 17431590Srgrimes if (!clcnt) { 17441590Srgrimes if (merge) { 17451590Srgrimes if ((clcnt = argc - eoptind) <= 1) { 17461590Srgrimes clcnt = CLCNT; 17471590Srgrimes merge = 0; 17481590Srgrimes } 17491590Srgrimes } else 17501590Srgrimes clcnt = CLCNT; 17511590Srgrimes } 17521590Srgrimes if (across) { 17531590Srgrimes if (clcnt == 1) { 17541590Srgrimes (void)fputs("pr: -a flag requires multiple columns\n", 17551590Srgrimes err); 17561590Srgrimes return(1); 17571590Srgrimes } 17581590Srgrimes if (merge) { 17591590Srgrimes (void)fputs("pr: -m cannot be used with -a\n", err); 17601590Srgrimes return(1); 17611590Srgrimes } 17621590Srgrimes } 17631590Srgrimes if (!wflag) { 17641590Srgrimes if (sflag) 17651590Srgrimes pgwd = SPGWD; 17661590Srgrimes else 17671590Srgrimes pgwd = PGWD; 17681590Srgrimes } 17691590Srgrimes if (cflag || merge) { 17701590Srgrimes if (!eflag) { 17711590Srgrimes inchar = INCHAR; 17721590Srgrimes ingap = INGAP; 17731590Srgrimes } 17741590Srgrimes if (!iflag) { 17751590Srgrimes ochar = OCHAR; 17761590Srgrimes ogap = OGAP; 17771590Srgrimes } 17781590Srgrimes } 17791590Srgrimes if (cflag) { 17801590Srgrimes if (merge) { 17811590Srgrimes (void)fputs( 17821590Srgrimes "pr: -m cannot be used with multiple columns\n", err); 17831590Srgrimes return(1); 17841590Srgrimes } 17851590Srgrimes if (nmwd) { 17861590Srgrimes colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; 17871590Srgrimes pgwd = ((colwd + nmwd + 2) * clcnt) - 1; 17881590Srgrimes } else { 17891590Srgrimes colwd = (pgwd + 1 - clcnt)/clcnt; 17901590Srgrimes pgwd = ((colwd + 1) * clcnt) - 1; 17911590Srgrimes } 17921590Srgrimes if (colwd < 1) { 17931590Srgrimes (void)fprintf(err, 17941590Srgrimes "pr: page width is too small for %d columns\n",clcnt); 17951590Srgrimes return(1); 17961590Srgrimes } 17971590Srgrimes } 17981590Srgrimes if (!lines) 17991590Srgrimes lines = LINES; 18001590Srgrimes 18011590Srgrimes /* 18021590Srgrimes * make sure long enough for headers. if not disable 18031590Srgrimes */ 18041590Srgrimes if (lines <= HEADLEN + TAILLEN) 18058874Srgrimes ++nohead; 18061590Srgrimes else if (!nohead) 18071590Srgrimes lines -= HEADLEN + TAILLEN; 18081590Srgrimes 18091590Srgrimes /* 18101590Srgrimes * adjust for double space on odd length pages 18111590Srgrimes */ 18121590Srgrimes if (dspace) { 18131590Srgrimes if (lines == 1) 18141590Srgrimes dspace = 0; 18151590Srgrimes else { 18161590Srgrimes if (lines & 1) 18171590Srgrimes ++addone; 18181590Srgrimes lines /= 2; 18191590Srgrimes } 18201590Srgrimes } 18211590Srgrimes 182253955Sache (void) setlocale(LC_TIME, (Lflag != NULL) ? Lflag : ""); 182353948Sache 182474575Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 182598552Smarkm timefrmt = strdup(d_first ? TIMEFMTD : TIMEFMTM); 182674575Sache 18271590Srgrimes return(0); 18281590Srgrimes} 1829