[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.22

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