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