[BACK]Return to pr.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / pr

Annotation of src/usr.bin/pr/pr.c, Revision 1.37

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