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: stable/11/usr.bin/pr/pr.c 317439 2017-04-26 14:44:39Z asomers $"); 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 */ 83227175Sedstatic int pgnm; /* starting page number */ 84227175Sedstatic int clcnt; /* number of columns */ 85227175Sedstatic int colwd; /* column data width - multiple columns */ 86227175Sedstatic int across; /* mult col flag; write across page */ 87227175Sedstatic int dspace; /* double space flag */ 88227175Sedstatic char inchar; /* expand input char */ 89227175Sedstatic int ingap; /* expand input gap */ 90227175Sedstatic int pausefst; /* Pause before first page */ 91227175Sedstatic int pauseall; /* Pause before each page */ 92227175Sedstatic int formfeed; /* use formfeed as trailer */ 93227175Sedstatic char *header; /* header name instead of file name */ 94227175Sedstatic char ochar; /* contract output char */ 95227175Sedstatic int ogap; /* contract output gap */ 96227175Sedstatic int lines; /* number of lines per page */ 97227175Sedstatic int merge; /* merge multiple files in output */ 98227175Sedstatic char nmchar; /* line numbering append char */ 99227175Sedstatic int nmwd; /* width of line number field */ 100227175Sedstatic int offst; /* number of page offset spaces */ 101227175Sedstatic int nodiag; /* do not report file open errors */ 102227175Sedstatic char schar; /* text column separation character */ 103227175Sedstatic int sflag; /* -s option for multiple columns */ 104227175Sedstatic int nohead; /* do not write head and trailer */ 105227175Sedstatic int pgwd; /* page width with multiple col output */ 106317439Sasomersstatic char *timefrmt; /* time conversion string */ 1071590Srgrimes 1081590Srgrimes/* 1091590Srgrimes * misc globals 1101590Srgrimes */ 111227175Sedstatic FILE *err; /* error message file pointer */ 112227175Sedstatic int addone; /* page length is odd with double space */ 113227175Sedstatic int errcnt; /* error count on file processing */ 114227175Sedstatic char digs[] = "0123456789"; /* page number translation map */ 1151590Srgrimes 116227175Sedstatic char 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); 138317439Sasomers free(timefrmt); 1391590Srgrimes } else 1401590Srgrimes usage(); 1411590Srgrimes flsh_errs(); 1421590Srgrimes if (errcnt || ret_val) 1431590Srgrimes exit(1); 1441590Srgrimes return(0); 1451590Srgrimes} 1461590Srgrimes 1471590Srgrimes/* 14893481Sjmallett * Check if we should pause and write an alert character and wait for a 14993481Sjmallett * carriage return on /dev/tty. 15093481Sjmallett */ 15198552Smarkmstatic void 15298552Smarkmttypause(int pagecnt) 15393481Sjmallett{ 15493481Sjmallett int pch; 15593481Sjmallett FILE *ttyfp; 15693481Sjmallett 15793481Sjmallett if ((pauseall || (pausefst && pagecnt == 1)) && 15893481Sjmallett isatty(STDOUT_FILENO)) { 15993481Sjmallett if ((ttyfp = fopen("/dev/tty", "r")) != NULL) { 16093481Sjmallett (void)putc('\a', stderr); 16193481Sjmallett while ((pch = getc(ttyfp)) != '\n' && pch != EOF) 16293481Sjmallett ; 16393481Sjmallett (void)fclose(ttyfp); 16493481Sjmallett } 16593481Sjmallett } 16693481Sjmallett} 16793481Sjmallett 16893481Sjmallett/* 1691590Srgrimes * onecol: print files with only one column of output. 1701590Srgrimes * Line length is unlimited. 1711590Srgrimes */ 1721590Srgrimesint 17398552Smarkmonecol(int argc, char *argv[]) 1741590Srgrimes{ 17598552Smarkm int cnt = -1; 17698552Smarkm int off; 17798552Smarkm int lrgln; 17898552Smarkm int linecnt; 17998552Smarkm int num; 1801590Srgrimes int lncnt; 1811590Srgrimes int pagecnt; 1821590Srgrimes int ips; 1831590Srgrimes int ops; 1841590Srgrimes int cps; 1851590Srgrimes char *obuf; 1861590Srgrimes char *lbuf; 1871590Srgrimes char *nbuf; 1881590Srgrimes char *hbuf; 1891590Srgrimes char *ohbuf; 1901590Srgrimes FILE *inf; 191102944Sdwmalone const char *fname; 1921590Srgrimes int mor; 1931590Srgrimes 1941590Srgrimes if (nmwd) 1951590Srgrimes num = nmwd + 1; 1961590Srgrimes else 1971590Srgrimes num = 0; 1981590Srgrimes off = num + offst; 1991590Srgrimes 2001590Srgrimes /* 2011590Srgrimes * allocate line buffer 2021590Srgrimes */ 2031590Srgrimes if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) { 2041590Srgrimes mfail(); 2051590Srgrimes return(1); 2061590Srgrimes } 2071590Srgrimes /* 2081590Srgrimes * allocate header buffer 2091590Srgrimes */ 2101590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 211317439Sasomers free(obuf); 2121590Srgrimes mfail(); 2131590Srgrimes return(1); 2141590Srgrimes } 2151590Srgrimes 2161590Srgrimes ohbuf = hbuf + offst; 2171590Srgrimes nbuf = obuf + offst; 2181590Srgrimes lbuf = nbuf + num; 2191590Srgrimes if (num) 2201590Srgrimes nbuf[--num] = nmchar; 2211590Srgrimes if (offst) { 2221590Srgrimes (void)memset(obuf, (int)' ', offst); 2231590Srgrimes (void)memset(hbuf, (int)' ', offst); 2241590Srgrimes } 2251590Srgrimes 2261590Srgrimes /* 2271590Srgrimes * loop by file 2281590Srgrimes */ 2291590Srgrimes while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 2301590Srgrimes if (pgnm) { 2311590Srgrimes /* 2321590Srgrimes * skip to specified page 2331590Srgrimes */ 2341590Srgrimes if (inskip(inf, pgnm, lines)) 2351590Srgrimes continue; 2361590Srgrimes pagecnt = pgnm; 2371590Srgrimes } else 2381590Srgrimes pagecnt = 1; 2391590Srgrimes lncnt = 0; 2401590Srgrimes 2411590Srgrimes /* 2421590Srgrimes * loop by page 2431590Srgrimes */ 2441590Srgrimes for(;;) { 2451590Srgrimes linecnt = 0; 2461590Srgrimes lrgln = 0; 2471590Srgrimes ops = 0; 2481590Srgrimes ips = 0; 2491590Srgrimes cps = 0; 2501590Srgrimes 25193481Sjmallett ttypause(pagecnt); 25293481Sjmallett 2531590Srgrimes /* 2541590Srgrimes * loop by line 2551590Srgrimes */ 2561590Srgrimes while (linecnt < lines) { 2571590Srgrimes /* 2581590Srgrimes * input next line 2591590Srgrimes */ 2601590Srgrimes if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0) 2611590Srgrimes break; 2621590Srgrimes if (!linecnt && !nohead && 2631590Srgrimes prhead(hbuf, fname, pagecnt)) 264317439Sasomers goto err; 2651590Srgrimes 2661590Srgrimes /* 2671590Srgrimes * start of new line. 2681590Srgrimes */ 2691590Srgrimes if (!lrgln) { 2701590Srgrimes if (num) 2711590Srgrimes addnum(nbuf, num, ++lncnt); 2721590Srgrimes if (otln(obuf,cnt+off, &ips, &ops, mor)) 273317439Sasomers goto err; 2741590Srgrimes } else if (otln(lbuf, cnt, &ips, &ops, mor)) 275317439Sasomers goto err; 2761590Srgrimes 2771590Srgrimes /* 2781590Srgrimes * if line bigger than buffer, get more 2791590Srgrimes */ 2801590Srgrimes if (mor) { 2811590Srgrimes lrgln = 1; 2821590Srgrimes continue; 2831590Srgrimes } 2841590Srgrimes 2851590Srgrimes /* 2861590Srgrimes * whole line rcvd. reset tab proc. state 2871590Srgrimes */ 2881590Srgrimes ++linecnt; 2891590Srgrimes lrgln = 0; 2901590Srgrimes ops = 0; 2911590Srgrimes ips = 0; 2921590Srgrimes } 2931590Srgrimes 2941590Srgrimes /* 2951590Srgrimes * fill to end of page 2961590Srgrimes */ 2971590Srgrimes if (linecnt && prtail(lines-linecnt-lrgln, lrgln)) 298317439Sasomers goto err; 2991590Srgrimes 3001590Srgrimes /* 3011590Srgrimes * On EOF go to next file 3021590Srgrimes */ 3031590Srgrimes if (cnt < 0) 3041590Srgrimes break; 3051590Srgrimes ++pagecnt; 3061590Srgrimes } 3071590Srgrimes if (inf != stdin) 3081590Srgrimes (void)fclose(inf); 3091590Srgrimes } 3101590Srgrimes if (eoptind < argc) 311317439Sasomers goto err; 312317439Sasomers free(hbuf); 313317439Sasomers free(obuf); 3141590Srgrimes return(0); 315317439Sasomerserr: 316317439Sasomers free(hbuf); 317317439Sasomers free(obuf); 318317439Sasomers return(1); 3191590Srgrimes} 3201590Srgrimes 3211590Srgrimes/* 3221590Srgrimes * vertcol: print files with more than one column of output down a page 3231590Srgrimes */ 3241590Srgrimesint 32598552Smarkmvertcol(int argc, char *argv[]) 3261590Srgrimes{ 32798552Smarkm char *ptbf; 328317439Sasomers char **lstdat = NULL; 32998552Smarkm int i; 33098552Smarkm int j; 33198552Smarkm int cnt = -1; 33298552Smarkm int pln; 333317439Sasomers int *indy = NULL; 3341590Srgrimes int cvc; 335317439Sasomers int *lindy = NULL; 3361590Srgrimes int lncnt; 3371590Srgrimes int stp; 3381590Srgrimes int pagecnt; 3391590Srgrimes int col = colwd + 1; 3401590Srgrimes int mxlen = pgwd + offst + 1; 3411590Srgrimes int mclcnt = clcnt - 1; 342317439Sasomers struct vcol *vc = NULL; 3431590Srgrimes int mvc; 3441590Srgrimes int tvc; 3451590Srgrimes int cw = nmwd + 1; 3461590Srgrimes int fullcol; 347317439Sasomers char *buf = NULL; 348317439Sasomers char *hbuf = NULL; 3491590Srgrimes char *ohbuf; 350102944Sdwmalone const char *fname; 3511590Srgrimes FILE *inf; 3521590Srgrimes int ips = 0; 3531590Srgrimes int cps = 0; 3541590Srgrimes int ops = 0; 3551590Srgrimes int mor = 0; 356317439Sasomers int retval = 1; 3571590Srgrimes 3581590Srgrimes /* 3591590Srgrimes * allocate page buffer 3601590Srgrimes */ 3611590Srgrimes if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) { 3621590Srgrimes mfail(); 3631590Srgrimes return(1); 3641590Srgrimes } 3651590Srgrimes 3661590Srgrimes /* 3671590Srgrimes * allocate page header 3681590Srgrimes */ 3691590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 3701590Srgrimes mfail(); 371317439Sasomers goto out; 3721590Srgrimes } 3731590Srgrimes ohbuf = hbuf + offst; 3741590Srgrimes if (offst) 3751590Srgrimes (void)memset(hbuf, (int)' ', offst); 3761590Srgrimes 3771590Srgrimes /* 3781590Srgrimes * col pointers when no headers 3791590Srgrimes */ 3801590Srgrimes mvc = lines * clcnt; 3811590Srgrimes if ((vc = 3821590Srgrimes (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) { 3831590Srgrimes mfail(); 384317439Sasomers goto out; 3851590Srgrimes } 3861590Srgrimes 3871590Srgrimes /* 3881590Srgrimes * pointer into page where last data per line is located 3891590Srgrimes */ 3901590Srgrimes if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){ 3911590Srgrimes mfail(); 392317439Sasomers goto out; 3931590Srgrimes } 3941590Srgrimes 3951590Srgrimes /* 3961590Srgrimes * fast index lookups to locate start of lines 3971590Srgrimes */ 3981590Srgrimes if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { 3991590Srgrimes mfail(); 400317439Sasomers goto out; 4011590Srgrimes } 4021590Srgrimes if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) { 4031590Srgrimes mfail(); 404317439Sasomers goto out; 4051590Srgrimes } 4061590Srgrimes 4071590Srgrimes if (nmwd) 4081590Srgrimes fullcol = col + cw; 4091590Srgrimes else 4101590Srgrimes fullcol = col; 4111590Srgrimes 4121590Srgrimes /* 4131590Srgrimes * initialize buffer lookup indexes and offset area 4141590Srgrimes */ 4151590Srgrimes for (j = 0; j < lines; ++j) { 4161590Srgrimes lindy[j] = j * mxlen; 4171590Srgrimes indy[j] = lindy[j] + offst; 4181590Srgrimes if (offst) { 4191590Srgrimes ptbf = buf + lindy[j]; 4201590Srgrimes (void)memset(ptbf, (int)' ', offst); 4211590Srgrimes ptbf += offst; 4221590Srgrimes } else 4231590Srgrimes ptbf = buf + indy[j]; 4241590Srgrimes lstdat[j] = ptbf; 4251590Srgrimes } 4261590Srgrimes 4271590Srgrimes /* 4281590Srgrimes * loop by file 4291590Srgrimes */ 4301590Srgrimes while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 4311590Srgrimes if (pgnm) { 4321590Srgrimes /* 4331590Srgrimes * skip to requested page 4341590Srgrimes */ 4351590Srgrimes if (inskip(inf, pgnm, lines)) 4361590Srgrimes continue; 4371590Srgrimes pagecnt = pgnm; 4381590Srgrimes } else 4391590Srgrimes pagecnt = 1; 4401590Srgrimes lncnt = 0; 4411590Srgrimes 4421590Srgrimes /* 4431590Srgrimes * loop by page 4441590Srgrimes */ 4451590Srgrimes for(;;) { 44693481Sjmallett ttypause(pagecnt); 44793481Sjmallett 4481590Srgrimes /* 4491590Srgrimes * loop by column 4501590Srgrimes */ 4511590Srgrimes cvc = 0; 4521590Srgrimes for (i = 0; i < clcnt; ++i) { 4531590Srgrimes j = 0; 4541590Srgrimes /* 4551590Srgrimes * if last column, do not pad 4561590Srgrimes */ 4571590Srgrimes if (i == mclcnt) 4581590Srgrimes stp = 1; 4591590Srgrimes else 4601590Srgrimes stp = 0; 4611590Srgrimes /* 4621590Srgrimes * loop by line 4631590Srgrimes */ 4641590Srgrimes for(;;) { 4651590Srgrimes /* 4661590Srgrimes * is this first column 4671590Srgrimes */ 4681590Srgrimes if (!i) { 4691590Srgrimes ptbf = buf + indy[j]; 4701590Srgrimes lstdat[j] = ptbf; 4718874Srgrimes } else 4721590Srgrimes ptbf = lstdat[j]; 4731590Srgrimes vc[cvc].pt = ptbf; 4741590Srgrimes 4751590Srgrimes /* 4761590Srgrimes * add number 4771590Srgrimes */ 4781590Srgrimes if (nmwd) { 4791590Srgrimes addnum(ptbf, nmwd, ++lncnt); 4801590Srgrimes ptbf += nmwd; 4811590Srgrimes *ptbf++ = nmchar; 4821590Srgrimes } 4831590Srgrimes 4841590Srgrimes /* 4851590Srgrimes * input next line 4861590Srgrimes */ 4871590Srgrimes cnt = inln(inf,ptbf,colwd,&cps,1,&mor); 4881590Srgrimes vc[cvc++].cnt = cnt; 4891590Srgrimes if (cnt < 0) 4901590Srgrimes break; 4911590Srgrimes ptbf += cnt; 4921590Srgrimes 4931590Srgrimes /* 4941590Srgrimes * pad all but last column on page 4951590Srgrimes */ 4961590Srgrimes if (!stp) { 4971590Srgrimes /* 4981590Srgrimes * pad to end of column 4991590Srgrimes */ 5001590Srgrimes if (sflag) 5011590Srgrimes *ptbf++ = schar; 5021590Srgrimes else if ((pln = col-cnt) > 0) { 5031590Srgrimes (void)memset(ptbf, 5041590Srgrimes (int)' ',pln); 5051590Srgrimes ptbf += pln; 5061590Srgrimes } 5071590Srgrimes } 5081590Srgrimes /* 5091590Srgrimes * remember last char in line 5101590Srgrimes */ 5111590Srgrimes lstdat[j] = ptbf; 5121590Srgrimes if (++j >= lines) 5131590Srgrimes break; 5141590Srgrimes } 5151590Srgrimes if (cnt < 0) 5161590Srgrimes break; 5171590Srgrimes } 5181590Srgrimes 5191590Srgrimes /* 5201590Srgrimes * when -t (no header) is specified the spec requires 5211590Srgrimes * the min number of lines. The last page may not have 5221590Srgrimes * balanced length columns. To fix this we must reorder 5231590Srgrimes * the columns. This is a very slow technique so it is 5241590Srgrimes * only used under limited conditions. Without -t, the 5251590Srgrimes * balancing of text columns is unspecified. To NOT 5261590Srgrimes * balance the last page, add the global variable 5271590Srgrimes * nohead to the if statement below e.g. 5281590Srgrimes * 5291590Srgrimes * if ((cnt < 0) && nohead && cvc ...... 5301590Srgrimes */ 5311590Srgrimes --cvc; 5321590Srgrimes 5331590Srgrimes /* 5341590Srgrimes * check to see if last page needs to be reordered 5351590Srgrimes */ 5361590Srgrimes if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){ 5371590Srgrimes pln = cvc/clcnt; 5381590Srgrimes if (cvc % clcnt) 5391590Srgrimes ++pln; 5401590Srgrimes 5411590Srgrimes /* 5421590Srgrimes * print header 5431590Srgrimes */ 5441590Srgrimes if (!nohead && prhead(hbuf, fname, pagecnt)) 545317439Sasomers goto out; 5461590Srgrimes for (i = 0; i < pln; ++i) { 5471590Srgrimes ips = 0; 5481590Srgrimes ops = 0; 549317439Sasomers if (offst && 550317439Sasomers otln(buf,offst,&ips,&ops,1)) 551317439Sasomers goto out; 5521590Srgrimes tvc = i; 5531590Srgrimes 5541590Srgrimes for (j = 0; j < clcnt; ++j) { 5551590Srgrimes /* 5561590Srgrimes * determine column length 5571590Srgrimes */ 5581590Srgrimes if (j == mclcnt) { 5591590Srgrimes /* 5601590Srgrimes * last column 5611590Srgrimes */ 5621590Srgrimes cnt = vc[tvc].cnt; 5631590Srgrimes if (nmwd) 5641590Srgrimes cnt += cw; 5651590Srgrimes } else if (sflag) { 5661590Srgrimes /* 5671590Srgrimes * single ch between 5681590Srgrimes */ 5691590Srgrimes cnt = vc[tvc].cnt + 1; 5701590Srgrimes if (nmwd) 5711590Srgrimes cnt += cw; 5721590Srgrimes } else 5731590Srgrimes cnt = fullcol; 5741590Srgrimes if (otln(vc[tvc].pt, cnt, &ips, 5751590Srgrimes &ops, 1)) 576317439Sasomers goto out; 5771590Srgrimes tvc += pln; 5781590Srgrimes if (tvc >= cvc) 5791590Srgrimes break; 5801590Srgrimes } 5811590Srgrimes /* 5821590Srgrimes * terminate line 5831590Srgrimes */ 5841590Srgrimes if (otln(buf, 0, &ips, &ops, 0)) 585317439Sasomers goto out; 5861590Srgrimes } 5871590Srgrimes /* 5881590Srgrimes * pad to end of page 5891590Srgrimes */ 5901590Srgrimes if (prtail((lines - pln), 0)) 591317439Sasomers goto out; 5921590Srgrimes /* 5931590Srgrimes * done with output, go to next file 5941590Srgrimes */ 5951590Srgrimes break; 5961590Srgrimes } 5971590Srgrimes 5981590Srgrimes /* 5991590Srgrimes * determine how many lines to output 6001590Srgrimes */ 6011590Srgrimes if (i > 0) 6021590Srgrimes pln = lines; 6031590Srgrimes else 6041590Srgrimes pln = j; 6051590Srgrimes 6061590Srgrimes /* 6071590Srgrimes * print header 6081590Srgrimes */ 6091590Srgrimes if (pln && !nohead && prhead(hbuf, fname, pagecnt)) 610317439Sasomers goto out; 6111590Srgrimes 6121590Srgrimes /* 6131590Srgrimes * output each line 6141590Srgrimes */ 6151590Srgrimes for (i = 0; i < pln; ++i) { 6161590Srgrimes ptbf = buf + lindy[i]; 6171590Srgrimes if ((j = lstdat[i] - ptbf) <= offst) 6181590Srgrimes break; 6191590Srgrimes if (otln(ptbf, j, &ips, &ops, 0)) 620317439Sasomers goto out; 6211590Srgrimes } 6221590Srgrimes 6231590Srgrimes /* 6241590Srgrimes * pad to end of page 6251590Srgrimes */ 6261590Srgrimes if (pln && prtail((lines - pln), 0)) 627317439Sasomers goto out; 6281590Srgrimes 6291590Srgrimes /* 6301590Srgrimes * if EOF go to next file 6311590Srgrimes */ 6321590Srgrimes if (cnt < 0) 6331590Srgrimes break; 6341590Srgrimes ++pagecnt; 6351590Srgrimes } 6361590Srgrimes if (inf != stdin) 6371590Srgrimes (void)fclose(inf); 6381590Srgrimes } 6391590Srgrimes if (eoptind < argc) 640317439Sasomers goto out; 641317439Sasomers retval = 0; 642317439Sasomersout: 643317439Sasomers free(lindy); 644317439Sasomers free(indy); 645317439Sasomers free(lstdat); 646317439Sasomers free(vc); 647317439Sasomers free(hbuf); 648317439Sasomers free(buf); 649317439Sasomers return(retval); 6501590Srgrimes} 6511590Srgrimes 6521590Srgrimes/* 6531590Srgrimes * horzcol: print files with more than one column of output across a page 6541590Srgrimes */ 6551590Srgrimesint 65698552Smarkmhorzcol(int argc, char *argv[]) 6571590Srgrimes{ 65898552Smarkm char *ptbf; 65998552Smarkm int pln; 66098552Smarkm int cnt = -1; 66198552Smarkm char *lstdat; 66298552Smarkm int col = colwd + 1; 66398552Smarkm int j; 66498552Smarkm int i; 6651590Srgrimes int lncnt; 6661590Srgrimes int pagecnt; 6671590Srgrimes char *buf; 6681590Srgrimes char *hbuf; 6691590Srgrimes char *ohbuf; 670102944Sdwmalone const char *fname; 6711590Srgrimes FILE *inf; 6721590Srgrimes int ips = 0; 6731590Srgrimes int cps = 0; 6741590Srgrimes int ops = 0; 6751590Srgrimes int mor = 0; 6761590Srgrimes 6771590Srgrimes if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { 6781590Srgrimes mfail(); 6791590Srgrimes return(1); 6801590Srgrimes } 6811590Srgrimes 6821590Srgrimes /* 6831590Srgrimes * page header 6841590Srgrimes */ 6851590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 686317439Sasomers free(buf); 6871590Srgrimes mfail(); 6881590Srgrimes return(1); 6891590Srgrimes } 6901590Srgrimes ohbuf = hbuf + offst; 6911590Srgrimes if (offst) { 6921590Srgrimes (void)memset(buf, (int)' ', offst); 6931590Srgrimes (void)memset(hbuf, (int)' ', offst); 6941590Srgrimes } 6951590Srgrimes 6961590Srgrimes /* 6971590Srgrimes * loop by file 6981590Srgrimes */ 6991590Srgrimes while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) { 7001590Srgrimes if (pgnm) { 7011590Srgrimes if (inskip(inf, pgnm, lines)) 7021590Srgrimes continue; 7031590Srgrimes pagecnt = pgnm; 7041590Srgrimes } else 7051590Srgrimes pagecnt = 1; 7061590Srgrimes lncnt = 0; 7071590Srgrimes 7081590Srgrimes /* 7091590Srgrimes * loop by page 7101590Srgrimes */ 7111590Srgrimes for(;;) { 71293481Sjmallett ttypause(pagecnt); 71393481Sjmallett 7141590Srgrimes /* 7151590Srgrimes * loop by line 7161590Srgrimes */ 7171590Srgrimes for (i = 0; i < lines; ++i) { 7181590Srgrimes ptbf = buf + offst; 7191590Srgrimes lstdat = ptbf; 7201590Srgrimes j = 0; 7211590Srgrimes /* 7221590Srgrimes * loop by col 7231590Srgrimes */ 7241590Srgrimes for(;;) { 7251590Srgrimes if (nmwd) { 7261590Srgrimes /* 7271590Srgrimes * add number to column 7281590Srgrimes */ 7291590Srgrimes addnum(ptbf, nmwd, ++lncnt); 7301590Srgrimes ptbf += nmwd; 7311590Srgrimes *ptbf++ = nmchar; 7321590Srgrimes } 7331590Srgrimes /* 7341590Srgrimes * input line 7351590Srgrimes */ 7361590Srgrimes if ((cnt = inln(inf,ptbf,colwd,&cps,1, 7371590Srgrimes &mor)) < 0) 7381590Srgrimes break; 7391590Srgrimes ptbf += cnt; 7401590Srgrimes lstdat = ptbf; 7411590Srgrimes 7421590Srgrimes /* 7431590Srgrimes * if last line skip padding 7441590Srgrimes */ 7451590Srgrimes if (++j >= clcnt) 7461590Srgrimes break; 7471590Srgrimes 7481590Srgrimes /* 7491590Srgrimes * pad to end of column 7501590Srgrimes */ 7511590Srgrimes if (sflag) 7521590Srgrimes *ptbf++ = schar; 7531590Srgrimes else if ((pln = col - cnt) > 0) { 7541590Srgrimes (void)memset(ptbf,(int)' ',pln); 7551590Srgrimes ptbf += pln; 7561590Srgrimes } 7571590Srgrimes } 7581590Srgrimes 7591590Srgrimes /* 7601590Srgrimes * determine line length 7611590Srgrimes */ 7621590Srgrimes if ((j = lstdat - buf) <= offst) 7631590Srgrimes break; 7641590Srgrimes if (!i && !nohead && 7651590Srgrimes prhead(hbuf, fname, pagecnt)) 766317439Sasomers goto err; 7671590Srgrimes /* 7681590Srgrimes * output line 7691590Srgrimes */ 7701590Srgrimes if (otln(buf, j, &ips, &ops, 0)) 771317439Sasomers goto err; 7721590Srgrimes } 7731590Srgrimes 7741590Srgrimes /* 7751590Srgrimes * pad to end of page 7761590Srgrimes */ 7771590Srgrimes if (i && prtail(lines-i, 0)) 778317439Sasomers goto err; 7791590Srgrimes 7801590Srgrimes /* 7811590Srgrimes * if EOF go to next file 7821590Srgrimes */ 7831590Srgrimes if (cnt < 0) 7841590Srgrimes break; 7851590Srgrimes ++pagecnt; 7861590Srgrimes } 7871590Srgrimes if (inf != stdin) 7881590Srgrimes (void)fclose(inf); 7891590Srgrimes } 7901590Srgrimes if (eoptind < argc) 791317439Sasomers goto err; 792317439Sasomers free(hbuf); 793317439Sasomers free(buf); 7941590Srgrimes return(0); 795317439Sasomerserr: 796317439Sasomers free(hbuf); 797317439Sasomers free(buf); 798317439Sasomers return(1); 7991590Srgrimes} 8001590Srgrimes 8011590Srgrimes/* 8021590Srgrimes * mulfile: print files with more than one column of output and 8031590Srgrimes * more than one file concurrently 8041590Srgrimes */ 8051590Srgrimesint 80698552Smarkmmulfile(int argc, char *argv[]) 8071590Srgrimes{ 80898552Smarkm char *ptbf; 80998552Smarkm int j; 81098552Smarkm int pln; 81198552Smarkm int cnt; 81298552Smarkm char *lstdat; 81398552Smarkm int i; 814317439Sasomers FILE **fbuf = NULL; 8151590Srgrimes int actf; 8161590Srgrimes int lncnt; 8171590Srgrimes int col; 8181590Srgrimes int pagecnt; 8191590Srgrimes int fproc; 820317439Sasomers char *buf = NULL; 821317439Sasomers char *hbuf = NULL; 8221590Srgrimes char *ohbuf; 823102944Sdwmalone const char *fname; 8241590Srgrimes int ips = 0; 8251590Srgrimes int cps = 0; 8261590Srgrimes int ops = 0; 8271590Srgrimes int mor = 0; 828317439Sasomers int retval = 1; 8291590Srgrimes 8301590Srgrimes /* 8311590Srgrimes * array of FILE *, one for each operand 8321590Srgrimes */ 8331590Srgrimes if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) { 8341590Srgrimes mfail(); 835317439Sasomers goto out; 8361590Srgrimes } 8371590Srgrimes 8381590Srgrimes /* 8391590Srgrimes * page header 8401590Srgrimes */ 8411590Srgrimes if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) { 8421590Srgrimes mfail(); 843317439Sasomers goto out; 8441590Srgrimes } 8451590Srgrimes ohbuf = hbuf + offst; 8461590Srgrimes 8471590Srgrimes /* 8481590Srgrimes * do not know how many columns yet. The number of operands provide an 8491590Srgrimes * upper bound on the number of columns. We use the number of files 8501590Srgrimes * we can open successfully to set the number of columns. The operation 851228992Suqs * of the merge operation (-m) in relation to unsuccessful file opens 8521590Srgrimes * is unspecified by posix. 8531590Srgrimes */ 8541590Srgrimes j = 0; 8551590Srgrimes while (j < clcnt) { 8561590Srgrimes if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL) 8571590Srgrimes break; 8581590Srgrimes if (pgnm && (inskip(fbuf[j], pgnm, lines))) 8591590Srgrimes fbuf[j] = NULL; 8601590Srgrimes ++j; 8611590Srgrimes } 8621590Srgrimes 8631590Srgrimes /* 8641590Srgrimes * if no files, exit 8651590Srgrimes */ 8661590Srgrimes if (!j) 867317439Sasomers goto out; 8681590Srgrimes 8691590Srgrimes /* 870228992Suqs * calculate page boundaries based on open file count 8711590Srgrimes */ 8721590Srgrimes clcnt = j; 8731590Srgrimes if (nmwd) { 8741590Srgrimes colwd = (pgwd - clcnt - nmwd)/clcnt; 8751590Srgrimes pgwd = ((colwd + 1) * clcnt) - nmwd - 2; 8761590Srgrimes } else { 8771590Srgrimes colwd = (pgwd + 1 - clcnt)/clcnt; 8781590Srgrimes pgwd = ((colwd + 1) * clcnt) - 1; 8791590Srgrimes } 8801590Srgrimes if (colwd < 1) { 8811590Srgrimes (void)fprintf(err, 8821590Srgrimes "pr: page width too small for %d columns\n", clcnt); 883317439Sasomers goto out; 8841590Srgrimes } 8851590Srgrimes actf = clcnt; 8861590Srgrimes col = colwd + 1; 8871590Srgrimes 8881590Srgrimes /* 8891590Srgrimes * line buffer 8901590Srgrimes */ 8911590Srgrimes if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) { 8921590Srgrimes mfail(); 893317439Sasomers goto out; 8941590Srgrimes } 8951590Srgrimes if (offst) { 8961590Srgrimes (void)memset(buf, (int)' ', offst); 8971590Srgrimes (void)memset(hbuf, (int)' ', offst); 8981590Srgrimes } 8991590Srgrimes if (pgnm) 9001590Srgrimes pagecnt = pgnm; 9011590Srgrimes else 9021590Srgrimes pagecnt = 1; 9031590Srgrimes lncnt = 0; 9041590Srgrimes 9051590Srgrimes /* 9061590Srgrimes * continue to loop while any file still has data 9071590Srgrimes */ 9081590Srgrimes while (actf > 0) { 90993481Sjmallett ttypause(pagecnt); 91093481Sjmallett 9111590Srgrimes /* 9121590Srgrimes * loop by line 9131590Srgrimes */ 9141590Srgrimes for (i = 0; i < lines; ++i) { 9151590Srgrimes ptbf = buf + offst; 9161590Srgrimes lstdat = ptbf; 9171590Srgrimes if (nmwd) { 9181590Srgrimes /* 9191590Srgrimes * add line number to line 9201590Srgrimes */ 9211590Srgrimes addnum(ptbf, nmwd, ++lncnt); 9221590Srgrimes ptbf += nmwd; 9231590Srgrimes *ptbf++ = nmchar; 9241590Srgrimes } 9251590Srgrimes j = 0; 9261590Srgrimes fproc = 0; 9271590Srgrimes 9281590Srgrimes /* 9291590Srgrimes * loop by column 9301590Srgrimes */ 9311590Srgrimes for (j = 0; j < clcnt; ++j) { 9321590Srgrimes if (fbuf[j] == NULL) { 9331590Srgrimes /* 9341590Srgrimes * empty column; EOF 9351590Srgrimes */ 9361590Srgrimes cnt = 0; 9371590Srgrimes } else if ((cnt = inln(fbuf[j], ptbf, colwd, 9381590Srgrimes &cps, 1, &mor)) < 0) { 9391590Srgrimes /* 9401590Srgrimes * EOF hit; no data 9411590Srgrimes */ 9421590Srgrimes if (fbuf[j] != stdin) 9431590Srgrimes (void)fclose(fbuf[j]); 9441590Srgrimes fbuf[j] = NULL; 9451590Srgrimes --actf; 9461590Srgrimes cnt = 0; 9471590Srgrimes } else { 9481590Srgrimes /* 9491590Srgrimes * process file data 9501590Srgrimes */ 9511590Srgrimes ptbf += cnt; 9521590Srgrimes lstdat = ptbf; 9531590Srgrimes fproc++; 9541590Srgrimes } 9551590Srgrimes 9561590Srgrimes /* 9571590Srgrimes * if last ACTIVE column, done with line 9581590Srgrimes */ 9591590Srgrimes if (fproc >= actf) 9601590Srgrimes break; 9611590Srgrimes 9621590Srgrimes /* 9631590Srgrimes * pad to end of column 9641590Srgrimes */ 9651590Srgrimes if (sflag) { 9661590Srgrimes *ptbf++ = schar; 9671590Srgrimes } else if ((pln = col - cnt) > 0) { 9681590Srgrimes (void)memset(ptbf, (int)' ', pln); 9691590Srgrimes ptbf += pln; 9701590Srgrimes } 9711590Srgrimes } 9721590Srgrimes 9731590Srgrimes /* 9741590Srgrimes * calculate data in line 9751590Srgrimes */ 9761590Srgrimes if ((j = lstdat - buf) <= offst) 9771590Srgrimes break; 9781590Srgrimes 9791590Srgrimes if (!i && !nohead && prhead(hbuf, fname, pagecnt)) 980317439Sasomers goto out; 9811590Srgrimes 9821590Srgrimes /* 9831590Srgrimes * output line 9841590Srgrimes */ 9851590Srgrimes if (otln(buf, j, &ips, &ops, 0)) 986317439Sasomers goto out; 9871590Srgrimes 9881590Srgrimes /* 9891590Srgrimes * if no more active files, done 9901590Srgrimes */ 9911590Srgrimes if (actf <= 0) { 9921590Srgrimes ++i; 9931590Srgrimes break; 9941590Srgrimes } 9951590Srgrimes } 9961590Srgrimes 9971590Srgrimes /* 9981590Srgrimes * pad to end of page 9991590Srgrimes */ 10001590Srgrimes if (i && prtail(lines-i, 0)) 1001317439Sasomers goto out; 10021590Srgrimes ++pagecnt; 10031590Srgrimes } 10041590Srgrimes if (eoptind < argc) 1005317439Sasomers goto out; 1006317439Sasomers retval = 0; 1007317439Sasomersout: 1008317439Sasomers free(buf); 1009317439Sasomers free(hbuf); 1010317439Sasomers free(fbuf); 1011317439Sasomers return(retval); 10121590Srgrimes} 10131590Srgrimes 10141590Srgrimes/* 10151590Srgrimes * inln(): input a line of data (unlimited length lines supported) 10161590Srgrimes * Input is optionally expanded to spaces 10171590Srgrimes * 10181590Srgrimes * inf: file 10191590Srgrimes * buf: buffer 10201590Srgrimes * lim: buffer length 1021228992Suqs * cps: column position 1st char in buffer (large line support) 10228874Srgrimes * trnc: throw away data more than lim up to \n 10231590Srgrimes * mor: set if more data in line (not truncated) 10241590Srgrimes */ 10251590Srgrimesint 102698552Smarkminln(FILE *inf, char *buf, int lim, int *cps, int trnc, int *mor) 10271590Srgrimes{ 102898552Smarkm int col; 102998552Smarkm int gap = ingap; 103098552Smarkm int ch = EOF; 103198552Smarkm char *ptbuf; 103298552Smarkm int chk = (int)inchar; 10331590Srgrimes 10341590Srgrimes ptbuf = buf; 10351590Srgrimes 10361590Srgrimes if (gap) { 10371590Srgrimes /* 10381590Srgrimes * expanding input option 10391590Srgrimes */ 10401590Srgrimes while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { 10411590Srgrimes /* 10421590Srgrimes * is this the input "tab" char 10431590Srgrimes */ 10441590Srgrimes if (ch == chk) { 10451590Srgrimes /* 10461590Srgrimes * expand to number of spaces 10471590Srgrimes */ 10481590Srgrimes col = (ptbuf - buf) + *cps; 10491590Srgrimes col = gap - (col % gap); 10501590Srgrimes 10511590Srgrimes /* 10521590Srgrimes * if more than this line, push back 10531590Srgrimes */ 10541590Srgrimes if ((col > lim) && (ungetc(ch, inf) == EOF)) 10551590Srgrimes return(1); 10561590Srgrimes 10571590Srgrimes /* 10581590Srgrimes * expand to spaces 10591590Srgrimes */ 10601590Srgrimes while ((--col >= 0) && (--lim >= 0)) 10611590Srgrimes *ptbuf++ = ' '; 10621590Srgrimes continue; 10631590Srgrimes } 10641590Srgrimes if (ch == '\n') 10651590Srgrimes break; 10661590Srgrimes *ptbuf++ = ch; 10671590Srgrimes } 10681590Srgrimes } else { 10691590Srgrimes /* 10701590Srgrimes * no expansion 10711590Srgrimes */ 10721590Srgrimes while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) { 10731590Srgrimes if (ch == '\n') 10741590Srgrimes break; 10751590Srgrimes *ptbuf++ = ch; 10761590Srgrimes } 10771590Srgrimes } 10781590Srgrimes col = ptbuf - buf; 10791590Srgrimes if (ch == EOF) { 10801590Srgrimes *mor = 0; 10811590Srgrimes *cps = 0; 10821590Srgrimes if (!col) 10831590Srgrimes return(-1); 10841590Srgrimes return(col); 10851590Srgrimes } 10861590Srgrimes if (ch == '\n') { 10871590Srgrimes /* 10881590Srgrimes * entire line processed 10891590Srgrimes */ 10901590Srgrimes *mor = 0; 10911590Srgrimes *cps = 0; 10921590Srgrimes return(col); 10931590Srgrimes } 10941590Srgrimes 10951590Srgrimes /* 10961590Srgrimes * line was larger than limit 10971590Srgrimes */ 10981590Srgrimes if (trnc) { 10991590Srgrimes /* 11001590Srgrimes * throw away rest of line 11011590Srgrimes */ 11021590Srgrimes while ((ch = getc(inf)) != EOF) { 11031590Srgrimes if (ch == '\n') 11041590Srgrimes break; 11051590Srgrimes } 11061590Srgrimes *cps = 0; 11071590Srgrimes *mor = 0; 11081590Srgrimes } else { 11091590Srgrimes /* 11101590Srgrimes * save column offset if not truncated 11111590Srgrimes */ 11121590Srgrimes *cps += col; 11131590Srgrimes *mor = 1; 11141590Srgrimes } 11151590Srgrimes 11161590Srgrimes return(col); 11171590Srgrimes} 11181590Srgrimes 11191590Srgrimes/* 11201590Srgrimes * otln(): output a line of data. (Supports unlimited length lines) 11211590Srgrimes * output is optionally contracted to tabs 11221590Srgrimes * 11231590Srgrimes * buf: output buffer with data 11241590Srgrimes * cnt: number of chars of valid data in buf 11251590Srgrimes * svips: buffer input column position (for large lines) 11261590Srgrimes * svops: buffer output column position (for large lines) 11278874Srgrimes * mor: output line not complete in this buf; more data to come. 11281590Srgrimes * 1 is more, 0 is complete, -1 is no \n's 11291590Srgrimes */ 11301590Srgrimesint 113198552Smarkmotln(char *buf, int cnt, int *svips, int *svops, int mor) 11321590Srgrimes{ 113398552Smarkm int ops; /* last col output */ 113498552Smarkm int ips; /* last col in buf examined */ 113598552Smarkm int gap = ogap; 113698552Smarkm int tbps; 113798552Smarkm char *endbuf; 11381590Srgrimes 11391590Srgrimes if (ogap) { 11401590Srgrimes /* 11411590Srgrimes * contracting on output 11421590Srgrimes */ 11431590Srgrimes endbuf = buf + cnt; 11441590Srgrimes ops = *svops; 11451590Srgrimes ips = *svips; 11461590Srgrimes while (buf < endbuf) { 11471590Srgrimes /* 11481590Srgrimes * count number of spaces and ochar in buffer 11491590Srgrimes */ 11501590Srgrimes if (*buf == ' ') { 11511590Srgrimes ++ips; 11521590Srgrimes ++buf; 11531590Srgrimes continue; 11541590Srgrimes } 11551590Srgrimes 11561590Srgrimes /* 11571590Srgrimes * simulate ochar processing 11581590Srgrimes */ 11591590Srgrimes if (*buf == ochar) { 11601590Srgrimes ips += gap - (ips % gap); 11611590Srgrimes ++buf; 11621590Srgrimes continue; 11631590Srgrimes } 11641590Srgrimes 11651590Srgrimes /* 11661590Srgrimes * got a non space char; contract out spaces 11671590Srgrimes */ 116898408Stjr while (ips - ops > 1) { 11691590Srgrimes /* 11701590Srgrimes * use as many ochar as will fit 11711590Srgrimes */ 11721590Srgrimes if ((tbps = ops + gap - (ops % gap)) > ips) 11731590Srgrimes break; 11741590Srgrimes if (putchar(ochar) == EOF) { 11751590Srgrimes pfail(); 11761590Srgrimes return(1); 11771590Srgrimes } 11781590Srgrimes ops = tbps; 11791590Srgrimes } 11801590Srgrimes 11811590Srgrimes while (ops < ips) { 11821590Srgrimes /* 11831590Srgrimes * finish off with spaces 11841590Srgrimes */ 11851590Srgrimes if (putchar(' ') == EOF) { 11861590Srgrimes pfail(); 11871590Srgrimes return(1); 11881590Srgrimes } 11891590Srgrimes ++ops; 11901590Srgrimes } 11911590Srgrimes 11921590Srgrimes /* 11931590Srgrimes * output non space char 11941590Srgrimes */ 11951590Srgrimes if (putchar(*buf++) == EOF) { 11961590Srgrimes pfail(); 11971590Srgrimes return(1); 11981590Srgrimes } 11991590Srgrimes ++ips; 12001590Srgrimes ++ops; 12011590Srgrimes } 12021590Srgrimes 12031590Srgrimes if (mor > 0) { 12041590Srgrimes /* 12051590Srgrimes * if incomplete line, save position counts 12061590Srgrimes */ 12071590Srgrimes *svops = ops; 12081590Srgrimes *svips = ips; 12091590Srgrimes return(0); 12101590Srgrimes } 12111590Srgrimes 12121590Srgrimes if (mor < 0) { 121398408Stjr while (ips - ops > 1) { 12141590Srgrimes /* 12151590Srgrimes * use as many ochar as will fit 12161590Srgrimes */ 12171590Srgrimes if ((tbps = ops + gap - (ops % gap)) > ips) 12181590Srgrimes break; 12191590Srgrimes if (putchar(ochar) == EOF) { 12201590Srgrimes pfail(); 12211590Srgrimes return(1); 12221590Srgrimes } 12231590Srgrimes ops = tbps; 12241590Srgrimes } 12251590Srgrimes while (ops < ips) { 12261590Srgrimes /* 12271590Srgrimes * finish off with spaces 12281590Srgrimes */ 12291590Srgrimes if (putchar(' ') == EOF) { 12301590Srgrimes pfail(); 12311590Srgrimes return(1); 12321590Srgrimes } 12331590Srgrimes ++ops; 12341590Srgrimes } 12351590Srgrimes return(0); 12361590Srgrimes } 12371590Srgrimes } else { 12381590Srgrimes /* 12391590Srgrimes * output is not contracted 12401590Srgrimes */ 12411590Srgrimes if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) { 12421590Srgrimes pfail(); 12431590Srgrimes return(1); 12441590Srgrimes } 12451590Srgrimes if (mor != 0) 12461590Srgrimes return(0); 12471590Srgrimes } 12481590Srgrimes 12491590Srgrimes /* 12501590Srgrimes * process line end and double space as required 12511590Srgrimes */ 12521590Srgrimes if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) { 12531590Srgrimes pfail(); 12541590Srgrimes return(1); 12551590Srgrimes } 12561590Srgrimes return(0); 12571590Srgrimes} 12581590Srgrimes 12591590Srgrimes/* 12601590Srgrimes * inskip(): skip over pgcnt pages with lncnt lines per page 12611590Srgrimes * file is closed at EOF (if not stdin). 12621590Srgrimes * 12631590Srgrimes * inf FILE * to read from 12641590Srgrimes * pgcnt number of pages to skip 12651590Srgrimes * lncnt number of lines per page 12661590Srgrimes */ 12671590Srgrimesint 126898552Smarkminskip(FILE *inf, int pgcnt, int lncnt) 12691590Srgrimes{ 127098552Smarkm int c; 127198552Smarkm int cnt; 12721590Srgrimes 12731590Srgrimes while(--pgcnt > 0) { 12741590Srgrimes cnt = lncnt; 12751590Srgrimes while ((c = getc(inf)) != EOF) { 12761590Srgrimes if ((c == '\n') && (--cnt == 0)) 12771590Srgrimes break; 12781590Srgrimes } 12791590Srgrimes if (c == EOF) { 12801590Srgrimes if (inf != stdin) 12811590Srgrimes (void)fclose(inf); 12821590Srgrimes return(1); 12831590Srgrimes } 12841590Srgrimes } 12851590Srgrimes return(0); 12861590Srgrimes} 12871590Srgrimes 12881590Srgrimes/* 12891590Srgrimes * nxtfile: returns a FILE * to next file in arg list and sets the 12901590Srgrimes * time field for this file (or current date). 12911590Srgrimes * 12921590Srgrimes * buf array to store proper date for the header. 12931590Srgrimes * dt if set skips the date processing (used with -m) 12941590Srgrimes */ 12951590SrgrimesFILE * 1296102944Sdwmalonenxtfile(int argc, char **argv, const char **fname, char *buf, int dt) 12971590Srgrimes{ 12981590Srgrimes FILE *inf = NULL; 129937262Sbde time_t tv_sec; 13001590Srgrimes struct tm *timeptr = NULL; 13011590Srgrimes struct stat statbuf; 13021590Srgrimes static int twice = -1; 13031590Srgrimes 13041590Srgrimes ++twice; 13051590Srgrimes if (eoptind >= argc) { 13061590Srgrimes /* 13071590Srgrimes * no file listed; default, use standard input 13081590Srgrimes */ 13091590Srgrimes if (twice) 13101590Srgrimes return(NULL); 13111590Srgrimes clearerr(stdin); 13121590Srgrimes inf = stdin; 13131590Srgrimes if (header != NULL) 13141590Srgrimes *fname = header; 13151590Srgrimes else 131698552Smarkm *fname = fnamedefault; 13171590Srgrimes if (nohead) 13181590Srgrimes return(inf); 1319204358Sed if ((tv_sec = time(NULL)) == -1) { 13201590Srgrimes ++errcnt; 13211590Srgrimes (void)fprintf(err, "pr: cannot get time of day, %s\n", 13221590Srgrimes strerror(errno)); 13231590Srgrimes eoptind = argc - 1; 13241590Srgrimes return(NULL); 13251590Srgrimes } 132637262Sbde timeptr = localtime(&tv_sec); 13271590Srgrimes } 13281590Srgrimes for (; eoptind < argc; ++eoptind) { 13291590Srgrimes if (strcmp(argv[eoptind], "-") == 0) { 13301590Srgrimes /* 13311590Srgrimes * process a "-" for filename 13321590Srgrimes */ 13331590Srgrimes clearerr(stdin); 13341590Srgrimes inf = stdin; 13351590Srgrimes if (header != NULL) 13361590Srgrimes *fname = header; 13371590Srgrimes else 133898552Smarkm *fname = fnamedefault; 13391590Srgrimes ++eoptind; 13401590Srgrimes if (nohead || (dt && twice)) 13411590Srgrimes return(inf); 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 /* 13521590Srgrimes * normal file processing 13531590Srgrimes */ 13541590Srgrimes if ((inf = fopen(argv[eoptind], "r")) == NULL) { 13551590Srgrimes ++errcnt; 13561590Srgrimes if (nodiag) 13571590Srgrimes continue; 1358132672Scharnier (void)fprintf(err, "pr: cannot open %s, %s\n", 13591590Srgrimes argv[eoptind], strerror(errno)); 13601590Srgrimes continue; 13611590Srgrimes } 13621590Srgrimes if (header != NULL) 13631590Srgrimes *fname = header; 13641590Srgrimes else if (dt) 136598552Smarkm *fname = fnamedefault; 13661590Srgrimes else 13671590Srgrimes *fname = argv[eoptind]; 13681590Srgrimes ++eoptind; 13691590Srgrimes if (nohead || (dt && twice)) 13701590Srgrimes return(inf); 13711590Srgrimes 13721590Srgrimes if (dt) { 1373204358Sed if ((tv_sec = time(NULL)) == -1) { 13741590Srgrimes ++errcnt; 13751590Srgrimes (void)fprintf(err, 13761590Srgrimes "pr: cannot get time of day, %s\n", 13771590Srgrimes strerror(errno)); 1378317439Sasomers fclose(inf); 13791590Srgrimes return(NULL); 13801590Srgrimes } 138137262Sbde timeptr = localtime(&tv_sec); 13821590Srgrimes } else { 13831590Srgrimes if (fstat(fileno(inf), &statbuf) < 0) { 13841590Srgrimes ++errcnt; 13851590Srgrimes (void)fclose(inf); 13868874Srgrimes (void)fprintf(err, 1387132672Scharnier "pr: cannot stat %s, %s\n", 13881590Srgrimes argv[eoptind], strerror(errno)); 13891590Srgrimes return(NULL); 13901590Srgrimes } 13911590Srgrimes timeptr = localtime(&(statbuf.st_mtime)); 13921590Srgrimes } 13931590Srgrimes } 13941590Srgrimes break; 13951590Srgrimes } 13961590Srgrimes if (inf == NULL) 13971590Srgrimes return(NULL); 13981590Srgrimes 13991590Srgrimes /* 14001590Srgrimes * set up time field used in header 14011590Srgrimes */ 14021590Srgrimes if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) { 14031590Srgrimes ++errcnt; 14041590Srgrimes if (inf != stdin) 14051590Srgrimes (void)fclose(inf); 14061590Srgrimes (void)fputs("pr: time conversion failed\n", err); 14071590Srgrimes return(NULL); 14081590Srgrimes } 14091590Srgrimes return(inf); 14101590Srgrimes} 14111590Srgrimes 14121590Srgrimes/* 14131590Srgrimes * addnum(): adds the line number to the column 14141590Srgrimes * Truncates from the front or pads with spaces as required. 14151590Srgrimes * Numbers are right justified. 14161590Srgrimes * 14171590Srgrimes * buf buffer to store the number 14181590Srgrimes * wdth width of buffer to fill 14191590Srgrimes * line line number 14201590Srgrimes * 14211590Srgrimes * NOTE: numbers occupy part of the column. The posix 14221590Srgrimes * spec does not specify if -i processing should or should not 14231590Srgrimes * occur on number padding. The spec does say it occupies 14241590Srgrimes * part of the column. The usage of addnum currently treats 14251590Srgrimes * numbers as part of the column so spaces may be replaced. 14261590Srgrimes */ 14271590Srgrimesvoid 142898552Smarkmaddnum(char *buf, int wdth, int line) 14291590Srgrimes{ 143098552Smarkm char *pt = buf + wdth; 14311590Srgrimes 14321590Srgrimes do { 14331590Srgrimes *--pt = digs[line % 10]; 14341590Srgrimes line /= 10; 14351590Srgrimes } while (line && (pt > buf)); 14361590Srgrimes 14371590Srgrimes /* 14381590Srgrimes * pad with space as required 14391590Srgrimes */ 14401590Srgrimes while (pt > buf) 14411590Srgrimes *--pt = ' '; 14421590Srgrimes} 14431590Srgrimes 14441590Srgrimes/* 14451590Srgrimes * prhead(): prints the top of page header 14461590Srgrimes * 14471590Srgrimes * buf buffer with time field (and offset) 14481590Srgrimes * cnt number of chars in buf 14491590Srgrimes * fname fname field for header 14501590Srgrimes * pagcnt page number 14511590Srgrimes */ 14521590Srgrimesint 1453102944Sdwmaloneprhead(char *buf, const char *fname, int pagcnt) 14541590Srgrimes{ 14551590Srgrimes int ips = 0; 14561590Srgrimes int ops = 0; 14571590Srgrimes 14581590Srgrimes if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) { 14591590Srgrimes pfail(); 14601590Srgrimes return(1); 14611590Srgrimes } 14621590Srgrimes /* 14631590Srgrimes * posix is not clear if the header is subject to line length 14641590Srgrimes * restrictions. The specification for header line format 14651590Srgrimes * in the spec clearly does not limit length. No pr currently 14661590Srgrimes * restricts header length. However if we need to truncate in 1467108470Sschweikh * a reasonable way, adjust the length of the printf by 1468151701Sjhb * changing HDFMT to allow a length max as an argument to printf. 14691590Srgrimes * buf (which contains the offset spaces and time field could 14701590Srgrimes * also be trimmed 14711590Srgrimes * 14721590Srgrimes * note only the offset (if any) is processed for tab expansion 14731590Srgrimes */ 14741590Srgrimes if (offst && otln(buf, offst, &ips, &ops, -1)) 14751590Srgrimes return(1); 14761590Srgrimes (void)printf(HDFMT,buf+offst, fname, pagcnt); 14771590Srgrimes return(0); 14781590Srgrimes} 14791590Srgrimes 14801590Srgrimes/* 14811590Srgrimes * prtail(): pad page with empty lines (if required) and print page trailer 14821590Srgrimes * if requested 14831590Srgrimes * 14841590Srgrimes * cnt number of lines of padding needed 14851590Srgrimes * incomp was a '\n' missing from last line output 14861590Srgrimes */ 14871590Srgrimesint 148898552Smarkmprtail(int cnt, int incomp) 14891590Srgrimes{ 14901590Srgrimes if (nohead) { 14911590Srgrimes /* 14921590Srgrimes * only pad with no headers when incomplete last line 14931590Srgrimes */ 149419092Sscrappy if (incomp && 149519092Sscrappy ((dspace && (putchar('\n') == EOF)) || 149619092Sscrappy (putchar('\n') == EOF))) { 14971590Srgrimes pfail(); 14981590Srgrimes return(1); 14991590Srgrimes } 150019092Sscrappy /* 150119092Sscrappy * but honor the formfeed request 150219092Sscrappy */ 150319092Sscrappy if (formfeed) { 150419092Sscrappy if (putchar('\f') == EOF) { 150519092Sscrappy pfail(); 150619092Sscrappy return(1); 150719092Sscrappy } 150819092Sscrappy } 15091590Srgrimes return(0); 15101590Srgrimes } 15111590Srgrimes /* 15121590Srgrimes * if double space output two \n 15131590Srgrimes */ 15141590Srgrimes if (dspace) 15151590Srgrimes cnt *= 2; 15161590Srgrimes 15171590Srgrimes /* 15181590Srgrimes * if an odd number of lines per page, add an extra \n 15191590Srgrimes */ 15201590Srgrimes if (addone) 15211590Srgrimes ++cnt; 15221590Srgrimes 15231590Srgrimes /* 15241590Srgrimes * pad page 15251590Srgrimes */ 15261590Srgrimes if (formfeed) { 15278874Srgrimes if ((incomp && (putchar('\n') == EOF)) || 15281590Srgrimes (putchar('\f') == EOF)) { 15291590Srgrimes pfail(); 15301590Srgrimes return(1); 15311590Srgrimes } 15321590Srgrimes return(0); 15338874Srgrimes } 15341590Srgrimes cnt += TAILLEN; 15351590Srgrimes while (--cnt >= 0) { 15361590Srgrimes if (putchar('\n') == EOF) { 15371590Srgrimes pfail(); 15381590Srgrimes return(1); 15391590Srgrimes } 15401590Srgrimes } 15411590Srgrimes return(0); 15421590Srgrimes} 15431590Srgrimes 15441590Srgrimes/* 15451590Srgrimes * terminate(): when a SIGINT is recvd 15461590Srgrimes */ 15471590Srgrimesvoid 154898552Smarkmterminate(int which_sig __unused) 15491590Srgrimes{ 15501590Srgrimes flsh_errs(); 15511590Srgrimes exit(1); 15521590Srgrimes} 15531590Srgrimes 15541590Srgrimes 15551590Srgrimes/* 15561590Srgrimes * flsh_errs(): output saved up diagnostic messages after all normal 15571590Srgrimes * processing has completed 15581590Srgrimes */ 15591590Srgrimesvoid 156098552Smarkmflsh_errs(void) 15611590Srgrimes{ 15621590Srgrimes char buf[BUFSIZ]; 15631590Srgrimes 15641590Srgrimes (void)fflush(stdout); 15651590Srgrimes (void)fflush(err); 15661590Srgrimes if (err == stderr) 15671590Srgrimes return; 15681590Srgrimes rewind(err); 15691590Srgrimes while (fgets(buf, BUFSIZ, err) != NULL) 15701590Srgrimes (void)fputs(buf, stderr); 15711590Srgrimes} 15721590Srgrimes 15731590Srgrimesvoid 157498552Smarkmmfail(void) 15751590Srgrimes{ 15761590Srgrimes (void)fputs("pr: memory allocation failed\n", err); 15771590Srgrimes} 15781590Srgrimes 15791590Srgrimesvoid 158098552Smarkmpfail(void) 15811590Srgrimes{ 15821590Srgrimes (void)fprintf(err, "pr: write failure, %s\n", strerror(errno)); 15831590Srgrimes} 15841590Srgrimes 15851590Srgrimesvoid 158698552Smarkmusage(void) 15871590Srgrimes{ 15881590Srgrimes (void)fputs( 158993481Sjmallett "usage: pr [+page] [-col] [-adFfmprt] [-e[ch][gap]] [-h header]\n", 159093481Sjmallett err); 15911590Srgrimes (void)fputs( 15921590Srgrimes " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err); 15931590Srgrimes (void)fputs( 159453955Sache " [-L locale] [-s[ch]] [-w width] [-] [file ...]\n", err); 15951590Srgrimes} 15961590Srgrimes 15971590Srgrimes/* 15988874Srgrimes * setup: Validate command args, initialize and perform sanity 15991590Srgrimes * checks on options 16001590Srgrimes */ 16011590Srgrimesint 160298552Smarkmsetup(int argc, char *argv[]) 16031590Srgrimes{ 160498552Smarkm int c; 160574575Sache int d_first; 16061590Srgrimes int eflag = 0; 16071590Srgrimes int iflag = 0; 16081590Srgrimes int wflag = 0; 16091590Srgrimes int cflag = 0; 161053955Sache char *Lflag = NULL; 16111590Srgrimes 16121590Srgrimes if (isatty(fileno(stdout))) { 16131590Srgrimes /* 16141590Srgrimes * defer diagnostics until processing is done 16151590Srgrimes */ 16161590Srgrimes if ((err = tmpfile()) == NULL) { 161790788Sjedgar err = stderr; 16181590Srgrimes (void)fputs("Cannot defer diagnostic messages\n",stderr); 16191590Srgrimes return(1); 16201590Srgrimes } 16211590Srgrimes } else 16221590Srgrimes err = stderr; 162393481Sjmallett while ((c = egetopt(argc, argv, "#adFfmrte?h:i?L:l:n?o:ps?w:")) != -1) { 16241590Srgrimes switch (c) { 16251590Srgrimes case '+': 16261590Srgrimes if ((pgnm = atoi(eoptarg)) < 1) { 16271590Srgrimes (void)fputs("pr: +page number must be 1 or more\n", 16281590Srgrimes err); 16291590Srgrimes return(1); 16301590Srgrimes } 16311590Srgrimes break; 16321590Srgrimes case '-': 16331590Srgrimes if ((clcnt = atoi(eoptarg)) < 1) { 16341590Srgrimes (void)fputs("pr: -columns must be 1 or more\n",err); 16351590Srgrimes return(1); 16361590Srgrimes } 16371590Srgrimes if (clcnt > 1) 16381590Srgrimes ++cflag; 16391590Srgrimes break; 16401590Srgrimes case 'a': 16411590Srgrimes ++across; 16421590Srgrimes break; 16431590Srgrimes case 'd': 16441590Srgrimes ++dspace; 16451590Srgrimes break; 16461590Srgrimes case 'e': 16471590Srgrimes ++eflag; 164853948Sache if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg)) 16491590Srgrimes inchar = *eoptarg++; 16501590Srgrimes else 16511590Srgrimes inchar = INCHAR; 165253948Sache if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) { 16531590Srgrimes if ((ingap = atoi(eoptarg)) < 0) { 16541590Srgrimes (void)fputs( 16551590Srgrimes "pr: -e gap must be 0 or more\n", err); 16561590Srgrimes return(1); 16571590Srgrimes } 16581590Srgrimes if (ingap == 0) 16591590Srgrimes ingap = INGAP; 16601590Srgrimes } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 16611590Srgrimes (void)fprintf(err, 16621590Srgrimes "pr: invalid value for -e %s\n", eoptarg); 16631590Srgrimes return(1); 16641590Srgrimes } else 16651590Srgrimes ingap = INGAP; 16661590Srgrimes break; 166793481Sjmallett case 'f': 166893481Sjmallett ++pausefst; 166993481Sjmallett /*FALLTHROUGH*/ 16701590Srgrimes case 'F': 16711590Srgrimes ++formfeed; 16721590Srgrimes break; 16731590Srgrimes case 'h': 16741590Srgrimes header = eoptarg; 16751590Srgrimes break; 16761590Srgrimes case 'i': 16771590Srgrimes ++iflag; 167853948Sache if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg)) 16791590Srgrimes ochar = *eoptarg++; 16801590Srgrimes else 16811590Srgrimes ochar = OCHAR; 168253948Sache if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) { 16831590Srgrimes if ((ogap = atoi(eoptarg)) < 0) { 16841590Srgrimes (void)fputs( 16851590Srgrimes "pr: -i gap must be 0 or more\n", err); 16861590Srgrimes return(1); 16871590Srgrimes } 16881590Srgrimes if (ogap == 0) 16891590Srgrimes ogap = OGAP; 16901590Srgrimes } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 16911590Srgrimes (void)fprintf(err, 16921590Srgrimes "pr: invalid value for -i %s\n", eoptarg); 16931590Srgrimes return(1); 16941590Srgrimes } else 16951590Srgrimes ogap = OGAP; 16961590Srgrimes break; 169753948Sache case 'L': 169853955Sache Lflag = eoptarg; 169953948Sache break; 17001590Srgrimes case 'l': 170153948Sache if (!isdigit((unsigned char)*eoptarg) || ((lines=atoi(eoptarg)) < 1)) { 17021590Srgrimes (void)fputs( 1703132672Scharnier "pr: number of lines must be 1 or more\n",err); 17041590Srgrimes return(1); 17051590Srgrimes } 17061590Srgrimes break; 17071590Srgrimes case 'm': 17081590Srgrimes ++merge; 17091590Srgrimes break; 17101590Srgrimes case 'n': 171153948Sache if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg)) 17121590Srgrimes nmchar = *eoptarg++; 17131590Srgrimes else 17141590Srgrimes nmchar = NMCHAR; 171553948Sache if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) { 17161590Srgrimes if ((nmwd = atoi(eoptarg)) < 1) { 17171590Srgrimes (void)fputs( 17181590Srgrimes "pr: -n width must be 1 or more\n",err); 17191590Srgrimes return(1); 17201590Srgrimes } 17211590Srgrimes } else if ((eoptarg != NULL) && (*eoptarg != '\0')) { 17221590Srgrimes (void)fprintf(err, 17231590Srgrimes "pr: invalid value for -n %s\n", eoptarg); 17241590Srgrimes return(1); 17251590Srgrimes } else 17261590Srgrimes nmwd = NMWD; 17271590Srgrimes break; 17281590Srgrimes case 'o': 172953948Sache if (!isdigit((unsigned char)*eoptarg) || ((offst = atoi(eoptarg))< 1)){ 17301590Srgrimes (void)fputs("pr: -o offset must be 1 or more\n", 17311590Srgrimes err); 17321590Srgrimes return(1); 17331590Srgrimes } 17341590Srgrimes break; 173593481Sjmallett case 'p': 173693481Sjmallett ++pauseall; 173793481Sjmallett break; 17381590Srgrimes case 'r': 17391590Srgrimes ++nodiag; 17401590Srgrimes break; 17411590Srgrimes case 's': 17421590Srgrimes ++sflag; 17431590Srgrimes if (eoptarg == NULL) 17441590Srgrimes schar = SCHAR; 174554114Skris else { 17461590Srgrimes schar = *eoptarg++; 174754114Skris if (*eoptarg != '\0') { 174854114Skris (void)fprintf(err, 174954114Skris "pr: invalid value for -s %s\n", 175054114Skris eoptarg); 175154114Skris return(1); 175254114Skris } 17531590Srgrimes } 17541590Srgrimes break; 17551590Srgrimes case 't': 17561590Srgrimes ++nohead; 17571590Srgrimes break; 17581590Srgrimes case 'w': 17591590Srgrimes ++wflag; 1760317439Sasomers if ((eoptarg == NULL ) || 1761317439Sasomers !isdigit((unsigned char)*eoptarg) || 1762317439Sasomers ((pgwd = atoi(eoptarg)) < 1)){ 17631590Srgrimes (void)fputs( 17641590Srgrimes "pr: -w width must be 1 or more \n",err); 17651590Srgrimes return(1); 17661590Srgrimes } 17671590Srgrimes break; 17681590Srgrimes case '?': 17691590Srgrimes default: 17701590Srgrimes return(1); 17711590Srgrimes } 17721590Srgrimes } 17731590Srgrimes 17741590Srgrimes /* 17751590Srgrimes * default and sanity checks 17761590Srgrimes */ 17771590Srgrimes if (!clcnt) { 17781590Srgrimes if (merge) { 17791590Srgrimes if ((clcnt = argc - eoptind) <= 1) { 17801590Srgrimes clcnt = CLCNT; 17811590Srgrimes merge = 0; 17821590Srgrimes } 17831590Srgrimes } else 17841590Srgrimes clcnt = CLCNT; 17851590Srgrimes } 17861590Srgrimes if (across) { 17871590Srgrimes if (clcnt == 1) { 17881590Srgrimes (void)fputs("pr: -a flag requires multiple columns\n", 17891590Srgrimes err); 17901590Srgrimes return(1); 17911590Srgrimes } 17921590Srgrimes if (merge) { 17931590Srgrimes (void)fputs("pr: -m cannot be used with -a\n", err); 17941590Srgrimes return(1); 17951590Srgrimes } 17961590Srgrimes } 17971590Srgrimes if (!wflag) { 17981590Srgrimes if (sflag) 17991590Srgrimes pgwd = SPGWD; 18001590Srgrimes else 18011590Srgrimes pgwd = PGWD; 18021590Srgrimes } 18031590Srgrimes if (cflag || merge) { 18041590Srgrimes if (!eflag) { 18051590Srgrimes inchar = INCHAR; 18061590Srgrimes ingap = INGAP; 18071590Srgrimes } 18081590Srgrimes if (!iflag) { 18091590Srgrimes ochar = OCHAR; 18101590Srgrimes ogap = OGAP; 18111590Srgrimes } 18121590Srgrimes } 18131590Srgrimes if (cflag) { 18141590Srgrimes if (merge) { 18151590Srgrimes (void)fputs( 18161590Srgrimes "pr: -m cannot be used with multiple columns\n", err); 18171590Srgrimes return(1); 18181590Srgrimes } 18191590Srgrimes if (nmwd) { 18201590Srgrimes colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt; 18211590Srgrimes pgwd = ((colwd + nmwd + 2) * clcnt) - 1; 18221590Srgrimes } else { 18231590Srgrimes colwd = (pgwd + 1 - clcnt)/clcnt; 18241590Srgrimes pgwd = ((colwd + 1) * clcnt) - 1; 18251590Srgrimes } 18261590Srgrimes if (colwd < 1) { 18271590Srgrimes (void)fprintf(err, 18281590Srgrimes "pr: page width is too small for %d columns\n",clcnt); 18291590Srgrimes return(1); 18301590Srgrimes } 18311590Srgrimes } 18321590Srgrimes if (!lines) 18331590Srgrimes lines = LINES; 18341590Srgrimes 18351590Srgrimes /* 18361590Srgrimes * make sure long enough for headers. if not disable 18371590Srgrimes */ 18381590Srgrimes if (lines <= HEADLEN + TAILLEN) 18398874Srgrimes ++nohead; 18401590Srgrimes else if (!nohead) 18411590Srgrimes lines -= HEADLEN + TAILLEN; 18421590Srgrimes 18431590Srgrimes /* 18441590Srgrimes * adjust for double space on odd length pages 18451590Srgrimes */ 18461590Srgrimes if (dspace) { 18471590Srgrimes if (lines == 1) 18481590Srgrimes dspace = 0; 18491590Srgrimes else { 18501590Srgrimes if (lines & 1) 18511590Srgrimes ++addone; 18521590Srgrimes lines /= 2; 18531590Srgrimes } 18541590Srgrimes } 18551590Srgrimes 185653955Sache (void) setlocale(LC_TIME, (Lflag != NULL) ? Lflag : ""); 185753948Sache 185874575Sache d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 185998552Smarkm timefrmt = strdup(d_first ? TIMEFMTD : TIMEFMTM); 186074575Sache 18611590Srgrimes return(0); 18621590Srgrimes} 1863