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

1.27    ! chl         1: /*     $OpenBSD: pr.c,v 1.26 2008/04/18 20:18:21 tobias 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.27    ! chl        44: static char *rcsid = "$OpenBSD: pr.c,v 1.26 2008/04/18 20:18:21 tobias 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:      */
1.24      deraadt   213:     if ((obuf = malloc((unsigned)LBUF + off)) == NULL) {
1.5       grr       214:        mfail();
                    215:        return(1);
                    216:     }
                    217:
                    218:     /*
                    219:      * allocate header buffer
                    220:      */
1.24      deraadt   221:     if ((hbuf = malloc((unsigned)HDBUF + offst)) == NULL) {
1.5       grr       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:      */
1.27    ! chl       379:     if ((buf = calloc((unsigned)lines, mxlen)) == NULL) {
1.5       grr       380:        mfail();
                    381:        return(1);
                    382:     }
                    383:
                    384:     /*
                    385:      * allocate page header
                    386:      */
1.24      deraadt   387:     if ((hbuf = malloc((unsigned)HDBUF + offst)) == NULL) {
1.5       grr       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;
1.24      deraadt   400:     if ((vc=(struct vcol *)calloc((unsigned)mvc, sizeof(struct vcol))) == NULL) {
1.5       grr       401:        mfail();
                    402:        return(1);
                    403:     }
                    404:
                    405:     /*
                    406:      * pointer into page where last data per line is located
                    407:      */
1.24      deraadt   408:     if ((lstdat = (char **)calloc((unsigned)lines, sizeof(char *))) == NULL){
1.5       grr       409:        mfail();
                    410:        return(1);
                    411:     }
                    412:
                    413:     /*
                    414:      * fast index lookups to locate start of lines
                    415:      */
1.24      deraadt   416:     if ((indy = (int *)calloc((unsigned)lines, sizeof(int))) == NULL) {
1.5       grr       417:        mfail();
                    418:        return(1);
                    419:     }
1.24      deraadt   420:     if ((lindy = (int *)calloc((unsigned)lines, sizeof(int))) == NULL) {
1.5       grr       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:
1.24      deraadt   691:     if ((buf = malloc((unsigned)pgwd + offst + 1)) == NULL) {
1.5       grr       692:        mfail();
                    693:        return(1);
                    694:     }
                    695:
                    696:     /*
                    697:      * page header
                    698:      */
1.24      deraadt   699:     if ((hbuf = malloc((unsigned)HDBUF + offst)) == NULL) {
1.5       grr       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:
1.26      tobias    853:        if (vasprintf(&p, fmt, ap) == -1 || (f = malloc(sizeof(*f))) == NULL) {
                    854:                flsh_errs();
                    855:                fprintf(stderr, fmt, ap);
                    856:                fputs("pr: memory allocation failed\n", stderr);
                    857:                exit(1);
                    858:        }
                    859:
1.12      deraadt   860:        f->next = NULL;
                    861:        f->buf = p;
                    862:        if (ferrhead == NULL)
                    863:            ferrhead = f;
                    864:        if (ferrtail)
                    865:                ferrtail->next = f;
                    866:        ferrtail = f;
                    867:        sigprocmask(SIG_SETMASK, &oblock, NULL);
                    868:     }
1.14      mpech     869:     va_end(ap);
1.12      deraadt   870: }
                    871:
1.1       deraadt   872: /*
1.5       grr       873:  * mulfile:    print files with more than one column of output and
                    874:  *        more than one file concurrently
1.1       deraadt   875:  */
                    876: int
1.18      deraadt   877: mulfile(int argc, char *argv[])
1.1       deraadt   878: {
1.13      mpech     879:     char *ptbf;
                    880:     int j;
                    881:     int pln;
1.5       grr       882:     int *rc;
                    883:     int cnt;
1.13      mpech     884:     char *lstdat;
                    885:     int i;
1.5       grr       886:     FILE **fbuf;
                    887:     int actf;
                    888:     int lncnt;
                    889:     int col;
                    890:     int pagecnt;
                    891:     int fproc;
                    892:     char *buf;
                    893:     char *hbuf;
                    894:     char *ohbuf;
                    895:     char *fname;
                    896:     int ips = 0;
                    897:     int cps = 0;
                    898:     int ops = 0;
                    899:     int mor = 0;
                    900:
                    901:     /*
                    902:      * array of FILE *, one for each operand
                    903:      */
1.24      deraadt   904:     if ((fbuf = (FILE **)calloc((unsigned)clcnt, sizeof(FILE *))) == NULL) {
1.5       grr       905:        mfail();
                    906:        return(1);
                    907:     }
                    908:
                    909:     /*
                    910:      * array of int *, one for each operand
                    911:      */
1.24      deraadt   912:     if ((rc = (int *)calloc((unsigned)clcnt, sizeof(int))) == NULL) {
1.5       grr       913:        mfail();
                    914:        return(1);
                    915:     }
                    916:
                    917:     /*
                    918:      * page header
                    919:      */
1.24      deraadt   920:     if ((hbuf = malloc((unsigned)HDBUF + offst)) == NULL) {
1.5       grr       921:        mfail();
                    922:        return(1);
                    923:     }
                    924:     ohbuf = hbuf + offst;
                    925:
                    926:     /*
                    927:      * do not know how many columns yet. The number of operands provide an
                    928:      * upper bound on the number of columns. We use the number of files
                    929:      * we can open successfully to set the number of columns. The operation
1.20      otto      930:      * of the merge operation (-m) in relation to unsuccessful file opens
1.5       grr       931:      * is unspecified by posix.
                    932:      *
                    933:      * XXX - this seems moderately bogus, you'd think that specifying
                    934:      * "pr -2 a b c d" would run though all the files in pairs, but
                    935:      * the existing code says up two files, or fewer if one is bogus.
                    936:      * fixing it would require modifying the looping structure, so be it.
                    937:      */
                    938:     j = 0;
                    939:     while (j < clcnt) {
                    940:        if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) != NULL) {
                    941:            rc[j] = NORMAL;
                    942:            j++;
                    943:        }
                    944:     }
                    945:
                    946:     /*
                    947:      * if no files, exit
                    948:      */
                    949:     if (j)
1.1       deraadt   950:        clcnt = j;
1.5       grr       951:     else
                    952:        return(1);
1.1       deraadt   953:
1.5       grr       954:     /*
1.20      otto      955:      * calculate page boundaries based on open file count
1.5       grr       956:      */
                    957:     if (nmwd) {
                    958:        colwd = (pgwd - clcnt - nmwd)/clcnt;
                    959:        pgwd = ((colwd + 1) * clcnt) - nmwd - 2;
                    960:     } else {
                    961:        colwd = (pgwd + 1 - clcnt)/clcnt;
                    962:        pgwd = ((colwd + 1) * clcnt) - 1;
                    963:     }
                    964:     if (colwd < 1) {
1.12      deraadt   965:        ferrout("pr: page width too small for %d columns\n", clcnt);
1.5       grr       966:        return(1);
                    967:     }
                    968:     col = colwd + 1;
                    969:
                    970:     /*
                    971:      * line buffer
                    972:      */
1.24      deraadt   973:     if ((buf = malloc((unsigned)pgwd + offst + 1)) == NULL) {
1.5       grr       974:        mfail();
                    975:        return(1);
                    976:     }
                    977:     if (offst) {
                    978:        (void)memset(buf, (int)' ', offst);
                    979:        (void)memset(hbuf, (int)' ', offst);
                    980:     }
                    981:
                    982:     pagecnt = 0;
                    983:     lncnt = 0;
                    984:     actf = clcnt;
                    985:
                    986:     /*
                    987:      * continue to loop while any file still has data
                    988:      */
                    989:     while (actf > 0) {
                    990:
                    991:        /*
                    992:         * loop on "form"
                    993:         */
                    994:        for (;;) {
                    995:
                    996:            /*
                    997:             * loop by line
                    998:             */
                    999:            for (i = 0; i < lines; ++i) {
                   1000:                ptbf = buf + offst;
                   1001:                lstdat = ptbf;
                   1002:                if (nmwd) {
                   1003:                    /*
                   1004:                     * add line number to line
                   1005:                     */
                   1006:                    addnum(ptbf, nmwd, ++lncnt);
                   1007:                    ptbf += nmwd;
                   1008:                    *ptbf++ = nmchar;
                   1009:                }
1.1       deraadt  1010:
1.5       grr      1011:                fproc = 0;
1.1       deraadt  1012:                /*
1.5       grr      1013:                 * loop by column
1.1       deraadt  1014:                 */
1.5       grr      1015:                for (j = 0; j < clcnt; ++j) {
                   1016:                    if (rc[j] == NORMAL ) {
                   1017:                        rc[j] = inln(fbuf[j], ptbf, colwd, &cnt, &cps, 1, &mor);
                   1018:                        if (cnt >= 0) {
                   1019:                            /*
                   1020:                             * process file data
                   1021:                             */
                   1022:                            ptbf += cnt;
                   1023:                            lstdat = ptbf;
                   1024:                            fproc++;
                   1025:                        } else
                   1026:                            cnt = 0;
                   1027:
                   1028:                        if (rc[j] == END) {
                   1029:                            /*
                   1030:                             * EOF close file
                   1031:                             */
                   1032:                            if (fbuf[j] != stdin)
                   1033:                                (void)fclose(fbuf[j]);
                   1034:                            --actf;
                   1035:                        }
                   1036:                    } else
                   1037:                        cnt = 0;
                   1038:
                   1039:                    /*
                   1040:                     * if last ACTIVE column, done with line
                   1041:                     */
                   1042:                    if (fproc >= actf)
                   1043:                        break;
1.1       deraadt  1044:
1.5       grr      1045:                    /*
                   1046:                     * pad to end of column
                   1047:                     */
                   1048:                    if (sflag) {
                   1049:                        *ptbf++ = schar;
                   1050:                    } else {
                   1051:                        if (cnt >= 0)
                   1052:                            pln = col - cnt;
                   1053:                        else
                   1054:                            pln = col;
                   1055:                        if (pln > 0) {
                   1056:                            (void)memset(ptbf, (int)' ', pln);
                   1057:                            ptbf += pln;
1.1       deraadt  1058:                        }
1.5       grr      1059:                    }
                   1060:                }
1.1       deraadt  1061:
1.5       grr      1062:                /*
                   1063:                 * if there was anything to do, print it
                   1064:                 */
                   1065:                if (fproc != 0) {
                   1066:                    if (!i && prhead(hbuf, fname, ++pagecnt))
                   1067:                        return(1);
1.1       deraadt  1068:
1.5       grr      1069:                    /*
                   1070:                     * output line
                   1071:                     */
                   1072:                    if (otln(buf, lstdat-buf, &ips, &ops, 0))
                   1073:                        return(1);
                   1074:                } else
                   1075:                    break;
                   1076:            }
1.1       deraadt  1077:
1.5       grr      1078:            /*
                   1079:             * pad to end of page
                   1080:             */
                   1081:            if (prtail(lines - i, 0))
                   1082:                return(1);
1.1       deraadt  1083:
1.5       grr      1084:            for (j = 0; j < clcnt; ++j)
                   1085:                if (rc[j] != END)
                   1086:                    rc[j] = NORMAL;
1.1       deraadt  1087:
1.5       grr      1088:            if (actf <= 0)
                   1089:                break;
1.1       deraadt  1090:        }
1.5       grr      1091:        if (actf <= 0)
                   1092:        break;
                   1093:     }
                   1094:     if (eoptind < argc)
                   1095:        return(1);
                   1096:     return(0);
1.1       deraadt  1097: }
                   1098:
                   1099: /*
1.5       grr      1100:  * inln():    input a line of data (unlimited length lines supported)
                   1101:  *        Input is optionally expanded to spaces
                   1102:  *        Returns 0 if normal LF, FORM on Formfeed, and END on EOF
1.1       deraadt  1103:  *
1.5       grr      1104:  *    inf:    file
                   1105:  *    buf:    buffer
                   1106:  *    lim:    buffer length
                   1107:  *    cnt:    line length or -1 if no line (EOF for example)
1.20      otto     1108:  *    cps:    column position 1st char in buffer (large line support)
1.5       grr      1109:  *    trnc:    throw away data more than lim up to \n
                   1110:  *    mor:    set if more data in line (not truncated)
1.1       deraadt  1111:  */
                   1112: int
1.18      deraadt  1113: inln(FILE *inf, char *buf, int lim, int *cnt, int *cps, int trnc, int *mor)
1.1       deraadt  1114: {
1.13      mpech    1115:     int col;
                   1116:     int gap = ingap;
                   1117:     int ch = -1;
                   1118:     char *ptbuf;
                   1119:     int chk = (int)inchar;
1.5       grr      1120:
                   1121:     ptbuf = buf;
                   1122:
                   1123:     if (gap) {
                   1124:        /*
                   1125:         * expanding input option
                   1126:         */
                   1127:        while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
                   1128:            /*
                   1129:             * is this the input "tab" char
                   1130:             */
                   1131:            if (ch == chk) {
1.1       deraadt  1132:                /*
1.5       grr      1133:                 * expand to number of spaces
1.1       deraadt  1134:                 */
1.5       grr      1135:                col = (ptbuf - buf) + *cps;
                   1136:                col = gap - (col % gap);
1.1       deraadt  1137:
                   1138:                /*
1.5       grr      1139:                 * if more than this line, push back
1.1       deraadt  1140:                 */
1.5       grr      1141:                if ((col > lim) && (ungetc(ch, inf) == EOF)) {
                   1142:                    *cnt = -1;
                   1143:                    return(END);    /* shouldn't happen */
1.1       deraadt  1144:                }
1.5       grr      1145:
1.1       deraadt  1146:                /*
1.5       grr      1147:                 * expand to spaces
1.1       deraadt  1148:                 */
1.5       grr      1149:                while ((--col >= 0) && (--lim >= 0))
                   1150:                    *ptbuf++ = ' ';
                   1151:                continue;
                   1152:            }
1.22      moritz   1153:            if (ch == '\n' || (inform && ch == INFF))
1.5       grr      1154:                break;
                   1155:            *ptbuf++ = ch;
                   1156:        }
                   1157:     } else {
                   1158:        /*
                   1159:         * no expansion
                   1160:         */
                   1161:        while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
1.22      moritz   1162:            if (ch == '\n' || (inform && ch == INFF))
1.5       grr      1163:                break;
                   1164:            *ptbuf++ = ch;
1.1       deraadt  1165:        }
1.5       grr      1166:     }
                   1167:     col = ptbuf - buf;
                   1168:     if (ch == EOF) {
                   1169:        *mor = 0;
                   1170:        *cps = 0;
                   1171:        *cnt = col ? col : -1;
                   1172:        return(END);
                   1173:     }
                   1174:     if (inform && ch == INFF) {
                   1175:        *mor = 0;
                   1176:        *cps = 0;
                   1177:        *cnt = col;
                   1178:        return(FORM);
                   1179:     }
                   1180:     if (ch == '\n') {
                   1181:        /*
                   1182:         * entire line processed
                   1183:         */
                   1184:        *mor = 0;
                   1185:        *cps = 0;
                   1186:        *cnt = col;
                   1187:        return(NORMAL);
                   1188:     }
                   1189:
                   1190:     /*
                   1191:      * line was larger than limit
                   1192:      */
                   1193:     if (trnc) {
1.1       deraadt  1194:        /*
1.5       grr      1195:         * throw away rest of line
1.1       deraadt  1196:         */
1.5       grr      1197:        while ((ch = getc(inf)) != EOF) {
                   1198:            if (ch == '\n')
                   1199:                break;
1.1       deraadt  1200:        }
1.5       grr      1201:        *cps = 0;
                   1202:        *mor = 0;
                   1203:     } else {
                   1204:        /*
                   1205:         * save column offset if not truncated
                   1206:         */
                   1207:        *cps += col;
                   1208:        *mor = 1;
                   1209:     }
1.1       deraadt  1210:
1.5       grr      1211:     *cnt = col;
                   1212:     return(NORMAL);
1.1       deraadt  1213: }
                   1214:
                   1215: /*
1.5       grr      1216:  * otln():    output a line of data. (Supports unlimited length lines)
                   1217:  *        output is optionally contracted to tabs
1.1       deraadt  1218:  *
1.5       grr      1219:  *    buf:    output buffer with data
                   1220:  *    cnt:    number of chars of valid data in buf
                   1221:  *    svips:    buffer input column position (for large lines)
                   1222:  *    svops:    buffer output column position (for large lines)
                   1223:  *    mor:    output line not complete in this buf; more data to come.
                   1224:  *        1 is more, 0 is complete, -1 is no \n's
1.1       deraadt  1225:  */
                   1226: int
1.18      deraadt  1227: otln(char *buf, int cnt, int *svips, int *svops, int mor)
1.1       deraadt  1228: {
1.13      mpech    1229:     int ops;        /* last col output */
                   1230:     int ips;        /* last col in buf examined */
                   1231:     int gap = ogap;
                   1232:     int tbps;
                   1233:     char *endbuf;
1.5       grr      1234:
                   1235:     /* skipping is only changed at header time not mid-line! */
                   1236:     if (skipping)
                   1237:        return (0);
                   1238:
                   1239:     if (ogap) {
                   1240:        /*
                   1241:         * contracting on output
                   1242:         */
                   1243:        endbuf = buf + cnt;
                   1244:        ops = *svops;
                   1245:        ips = *svips;
                   1246:        while (buf < endbuf) {
                   1247:            /*
                   1248:             * count number of spaces and ochar in buffer
                   1249:             */
                   1250:            if (*buf == ' ') {
                   1251:                ++ips;
                   1252:                ++buf;
                   1253:                continue;
                   1254:            }
                   1255:
                   1256:            /*
                   1257:             * simulate ochar processing
                   1258:             */
                   1259:            if (*buf == ochar) {
                   1260:                ips += gap - (ips % gap);
                   1261:                ++buf;
                   1262:                continue;
                   1263:            }
                   1264:
                   1265:            /*
                   1266:             * got a non space char; contract out spaces
                   1267:             */
                   1268:            while (ops < ips) {
1.1       deraadt  1269:                /*
1.10      pvalchev 1270:                 * use one space if necessary
                   1271:                 */
                   1272:                if (ips - ops == 1) {
                   1273:                        putchar(' ');
                   1274:                        break;
                   1275:                }
                   1276:                /*
1.5       grr      1277:                 * use as many ochar as will fit
1.1       deraadt  1278:                 */
1.5       grr      1279:                if ((tbps = ops + gap - (ops % gap)) > ips)
                   1280:                    break;
                   1281:                if (putchar(ochar) == EOF) {
                   1282:                    pfail();
                   1283:                    return(1);
1.1       deraadt  1284:                }
1.5       grr      1285:                ops = tbps;
                   1286:            }
1.1       deraadt  1287:
1.5       grr      1288:            while (ops < ips) {
1.1       deraadt  1289:                /*
1.5       grr      1290:                 * finish off with spaces
1.1       deraadt  1291:                 */
1.5       grr      1292:                if (putchar(' ') == EOF) {
                   1293:                    pfail();
                   1294:                    return(1);
                   1295:                }
                   1296:                ++ops;
                   1297:            }
                   1298:
                   1299:            /*
                   1300:             * output non space char
                   1301:             */
                   1302:            if (putchar(*buf++) == EOF) {
1.1       deraadt  1303:                pfail();
                   1304:                return(1);
1.5       grr      1305:            }
                   1306:            ++ips;
                   1307:            ++ops;
                   1308:        }
                   1309:
                   1310:        if (mor > 0) {
                   1311:            /*
                   1312:             * if incomplete line, save position counts
                   1313:             */
                   1314:            *svops = ops;
                   1315:            *svips = ips;
                   1316:            return(0);
1.1       deraadt  1317:        }
1.5       grr      1318:
                   1319:        if (mor < 0) {
                   1320:            while (ops < ips) {
                   1321:                /*
1.10      pvalchev 1322:                 * use one space if necessary
                   1323:                 */
                   1324:                if (ips - ops == 1) {
                   1325:                        putchar(' ');
                   1326:                        break;
                   1327:                }
                   1328:                /*
1.5       grr      1329:                 * use as many ochar as will fit
                   1330:                 */
                   1331:                if ((tbps = ops + gap - (ops % gap)) > ips)
                   1332:                    break;
                   1333:                if (putchar(ochar) == EOF) {
                   1334:                    pfail();
                   1335:                    return(1);
                   1336:                }
                   1337:                ops = tbps;
                   1338:            }
1.10      pvalchev 1339:
1.5       grr      1340:            while (ops < ips) {
                   1341:                /*
                   1342:                 * finish off with spaces
                   1343:                 */
                   1344:                if (putchar(' ') == EOF) {
                   1345:                    pfail();
                   1346:                    return(1);
                   1347:                }
                   1348:                ++ops;
                   1349:            }
                   1350:            return(0);
                   1351:        }
                   1352:     } else {
                   1353:        /*
                   1354:         * output is not contracted
                   1355:         */
1.22      moritz   1356:        if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) < cnt)) {
1.5       grr      1357:            pfail();
                   1358:            return(1);
                   1359:        }
                   1360:        if (mor != 0)
                   1361:            return(0);
                   1362:     }
                   1363:
                   1364:     /*
                   1365:      * process line end and double space as required
                   1366:      */
                   1367:     if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) {
                   1368:        pfail();
                   1369:        return(1);
                   1370:     }
                   1371:     return(0);
1.1       deraadt  1372: }
                   1373:
1.5       grr      1374: #ifdef notused
1.1       deraadt  1375: /*
1.5       grr      1376:  * inskip():    skip over pgcnt pages with lncnt lines per page
                   1377:  *        file is closed at EOF (if not stdin).
1.1       deraadt  1378:  *
1.5       grr      1379:  *    inf    FILE * to read from
                   1380:  *    pgcnt    number of pages to skip
                   1381:  *    lncnt    number of lines per page
1.1       deraadt  1382:  */
                   1383: int
1.18      deraadt  1384: inskip(FILE *inf, int pgcnt, int lncnt)
1.1       deraadt  1385: {
1.13      mpech    1386:     int c;
                   1387:     int cnt;
1.1       deraadt  1388:
1.5       grr      1389:     while(--pgcnt > 0) {
                   1390:        cnt = lncnt;
                   1391:        while ((c = getc(inf)) != EOF) {
                   1392:            if ((c == '\n') && (--cnt == 0))
                   1393:                break;
                   1394:        }
                   1395:        if (c == EOF) {
                   1396:            if (inf != stdin)
                   1397:                (void)fclose(inf);
                   1398:            return(1);
1.1       deraadt  1399:        }
1.5       grr      1400:     }
                   1401:     return(0);
1.1       deraadt  1402: }
1.5       grr      1403: #endif
1.1       deraadt  1404:
                   1405: /*
1.5       grr      1406:  * nxtfile:    returns a FILE * to next file in arg list and sets the
                   1407:  *        time field for this file (or current date).
1.1       deraadt  1408:  *
1.5       grr      1409:  *    buf    array to store proper date for the header.
                   1410:  *    dt    if set skips the date processing (used with -m)
1.1       deraadt  1411:  */
                   1412: FILE *
1.18      deraadt  1413: nxtfile(int argc, char *argv[], char **fname, char *buf, int dt)
1.1       deraadt  1414: {
1.5       grr      1415:     FILE *inf = NULL;
                   1416:     struct timeval tv;
                   1417:     struct timezone tz;
                   1418:     struct tm *timeptr = NULL;
                   1419:     struct stat statbuf;
                   1420:     time_t curtime;
                   1421:     static int twice = -1;
                   1422:
                   1423:     ++twice;
                   1424:     if (eoptind >= argc) {
                   1425:        /*
                   1426:         * no file listed; default, use standard input
                   1427:         */
                   1428:        if (twice)
                   1429:            return(NULL);
                   1430:        clearerr(stdin);
                   1431:        inf = stdin;
                   1432:        if (header != NULL)
                   1433:            *fname = header;
                   1434:        else
                   1435:            *fname = FNAME;
                   1436:        if (nohead)
                   1437:            return(inf);
                   1438:        if (gettimeofday(&tv, &tz) < 0) {
                   1439:            ++errcnt;
1.12      deraadt  1440:            ferrout("pr: cannot get time of day, %s\n",
1.5       grr      1441:                strerror(errno));
                   1442:            eoptind = argc - 1;
                   1443:            return(NULL);
                   1444:        }
                   1445:        curtime = tv.tv_sec;
                   1446:        timeptr = localtime(&curtime);
                   1447:     }
                   1448:     for (; eoptind < argc; ++eoptind) {
                   1449:        if (strcmp(argv[eoptind], "-") == 0) {
                   1450:            /*
                   1451:             * process a "-" for filename
                   1452:             */
                   1453:            clearerr(stdin);
                   1454:            inf = stdin;
                   1455:            if (header != NULL)
                   1456:                *fname = header;
                   1457:            else
                   1458:                *fname = FNAME;
                   1459:            ++eoptind;
                   1460:            if (nohead || (dt && twice))
                   1461:                return(inf);
                   1462:            if (gettimeofday(&tv, &tz) < 0) {
                   1463:                ++errcnt;
1.12      deraadt  1464:                ferrout("pr: cannot get time of day, %s\n",
1.5       grr      1465:                    strerror(errno));
                   1466:                return(NULL);
                   1467:            }
                   1468:            curtime = tv.tv_sec;
                   1469:            timeptr = localtime(&curtime);
                   1470:        } else {
                   1471:            /*
                   1472:             * normal file processing
                   1473:             */
                   1474:            if ((inf = fopen(argv[eoptind], "r")) == NULL) {
                   1475:                ++errcnt;
                   1476:                if (nodiag)
                   1477:                    continue;
1.12      deraadt  1478:                ferrout("pr: Cannot open %s, %s\n",
1.5       grr      1479:                    argv[eoptind], strerror(errno));
                   1480:                continue;
                   1481:            }
                   1482:            if (header != NULL)
                   1483:                *fname = header;
                   1484:            else if (dt)
                   1485:                *fname = FNAME;
                   1486:            else
                   1487:                *fname = argv[eoptind];
                   1488:            ++eoptind;
                   1489:            if (nohead || (dt && twice))
                   1490:                return(inf);
1.1       deraadt  1491:
1.5       grr      1492:            if (dt) {
1.1       deraadt  1493:                if (gettimeofday(&tv, &tz) < 0) {
1.5       grr      1494:                    ++errcnt;
1.12      deraadt  1495:                    ferrout("pr: cannot get time of day, %s\n",
1.5       grr      1496:                         strerror(errno));
                   1497:                    return(NULL);
1.1       deraadt  1498:                }
                   1499:                curtime = tv.tv_sec;
                   1500:                timeptr = localtime(&curtime);
1.5       grr      1501:            } else {
                   1502:                if (fstat(fileno(inf), &statbuf) < 0) {
                   1503:                    ++errcnt;
                   1504:                    (void)fclose(inf);
1.12      deraadt  1505:                    ferrout("pr: Cannot stat %s, %s\n",
1.5       grr      1506:                        argv[eoptind], strerror(errno));
                   1507:                    return(NULL);
                   1508:                }
                   1509:                timeptr = localtime(&(statbuf.st_mtime));
                   1510:            }
                   1511:        }
                   1512:        break;
                   1513:     }
                   1514:     if (inf == NULL)
                   1515:        return(NULL);
                   1516:
                   1517:     /*
                   1518:      * set up time field used in header
                   1519:      */
1.22      moritz   1520:     if (strftime(buf, HDBUF, timefrmt, timeptr) == 0) {
1.5       grr      1521:        ++errcnt;
                   1522:        if (inf != stdin)
                   1523:            (void)fclose(inf);
1.12      deraadt  1524:        ferrout("pr: time conversion failed\n");
1.5       grr      1525:        return(NULL);
                   1526:     }
                   1527:     return(inf);
1.1       deraadt  1528: }
                   1529:
                   1530: /*
1.5       grr      1531:  * addnum():    adds the line number to the column
                   1532:  *        Truncates from the front or pads with spaces as required.
                   1533:  *        Numbers are right justified.
1.1       deraadt  1534:  *
1.5       grr      1535:  *    buf    buffer to store the number
                   1536:  *    wdth    width of buffer to fill
                   1537:  *    line    line number
1.1       deraadt  1538:  *
1.5       grr      1539:  *        NOTE: numbers occupy part of the column. The posix
                   1540:  *        spec does not specify if -i processing should or should not
                   1541:  *        occur on number padding. The spec does say it occupies
                   1542:  *        part of the column. The usage of addnum    currently treats
                   1543:  *        numbers as part of the column so spaces may be replaced.
1.1       deraadt  1544:  */
                   1545: void
1.18      deraadt  1546: addnum(char *buf, int wdth, int line)
1.1       deraadt  1547: {
1.13      mpech    1548:     char *pt = buf + wdth;
1.1       deraadt  1549:
1.5       grr      1550:     do {
                   1551:        *--pt = digs[line % 10];
                   1552:        line /= 10;
                   1553:     } while (line && (pt > buf));
                   1554:
                   1555:     /*
                   1556:      * pad with space as required
                   1557:      */
                   1558:     while (pt > buf)
                   1559:        *--pt = ' ';
1.1       deraadt  1560: }
                   1561:
                   1562: /*
1.5       grr      1563:  * prhead():    prints the top of page header
1.1       deraadt  1564:  *
1.5       grr      1565:  *    buf    buffer with time field (and offset)
                   1566:  *    cnt    number of chars in buf
                   1567:  *    fname    fname field for header
                   1568:  *    pagcnt    page number
                   1569:  *
                   1570:  * prhead() should be used carefully, we don't want to print out headers
                   1571:  * for null input files or orphan headers at the end of files, and also
                   1572:  * trailer processing is typically conditional on whether you've called
1.20      otto     1573:  * prhead() at least once for a file and incremented pagecnt.  Exactly
1.5       grr      1574:  * how to determine whether to print a header is a little different in
                   1575:  * the context each output mode, but we let the caller figure that out.
1.1       deraadt  1576:  */
                   1577: int
1.18      deraadt  1578: prhead(char *buf, char *fname, int pagcnt)
1.1       deraadt  1579: {
1.5       grr      1580:     int ips = 0;
                   1581:     int ops = 0;
                   1582:
                   1583:     beheaded = 1;
1.1       deraadt  1584:
1.5       grr      1585:     if (skipping && pagcnt >= pgnm)
                   1586:        skipping = 0;
                   1587:
                   1588:     if (nohead || skipping)
                   1589:        return (0);
                   1590:
                   1591:     if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) {
                   1592:        pfail();
                   1593:        return(1);
                   1594:     }
                   1595:     /*
                   1596:      * posix is not clear if the header is subject to line length
                   1597:      * restrictions. The specification for header line format
                   1598:      * in the spec clearly does not limit length. No pr currently
                   1599:      * restricts header length. However if we need to truncate in
                   1600:      * an reasonable way, adjust the length of the printf by
1.15      deraadt  1601:      * changing HDFMT to allow a length max as an argument printf.
1.5       grr      1602:      * buf (which contains the offset spaces and time field could
                   1603:      * also be trimmed
                   1604:      *
                   1605:      * note only the offset (if any) is processed for tab expansion
                   1606:      */
                   1607:     if (offst && otln(buf, offst, &ips, &ops, -1))
                   1608:        return(1);
                   1609:     (void)printf(HDFMT,buf+offst, fname, pagcnt);
                   1610:     return(0);
1.1       deraadt  1611: }
                   1612:
                   1613: /*
1.5       grr      1614:  * prtail():    pad page with empty lines (if required) and print page trailer
                   1615:  *        if requested
                   1616:  *
                   1617:  *    cnt      number of lines of padding needed
                   1618:  *    incomp    was a '\n' missing from last line output
1.1       deraadt  1619:  *
1.5       grr      1620:  * prtail() can now be invoked unconditionally, with the notion that if
1.20      otto     1621:  * we haven't printed a header, there is no need for a trailer
1.1       deraadt  1622:  */
                   1623: int
1.18      deraadt  1624: prtail(int cnt, int incomp)
1.1       deraadt  1625: {
1.5       grr      1626:     /*
                   1627:      * if were's skipping to page N or haven't put out anything yet just exit
                   1628:      */
                   1629:     if (skipping || beheaded == 0)
                   1630:        return (0);
                   1631:     beheaded = 0;
                   1632:
                   1633:     /*
                   1634:      * if noheaders, only terminate an incomplete last line
                   1635:      */
                   1636:     if (nohead) {
                   1637:
                   1638:        if (incomp) {
                   1639:            if (dspace)
                   1640:                if (putchar('\n') == EOF) {
                   1641:                    pfail();
                   1642:                    return(1);
1.3       imp      1643:                }
1.5       grr      1644:            if (putchar('\n') == EOF) {
                   1645:                pfail();
                   1646:                return(1);
                   1647:             }
1.1       deraadt  1648:        }
1.5       grr      1649:        /*
                   1650:         * but honor the formfeed request
                   1651:         */
                   1652:        if (formfeed)
                   1653:            if (putchar(OUTFF) == EOF) {
                   1654:                pfail();
                   1655:                return(1);
                   1656:            }
                   1657:
                   1658:     } else {
1.1       deraadt  1659:
                   1660:        /*
                   1661:         * if double space output two \n
1.5       grr      1662:         *
                   1663:         * XXX this all seems bogus, why are we doing it here???
                   1664:         * page length is in terms of output lines and only the input is
                   1665:         * supposed to be double spaced...  otln() users should be doing
                   1666:         * something like linect+=(dspace ? 2:1).
1.1       deraadt  1667:         */
                   1668:        if (dspace)
1.5       grr      1669:            cnt *= 2;
1.1       deraadt  1670:
                   1671:        /*
                   1672:         * if an odd number of lines per page, add an extra \n
                   1673:         */
                   1674:        if (addone)
1.5       grr      1675:            ++cnt;
1.1       deraadt  1676:
                   1677:        /*
1.5       grr      1678:         * either put out a form-feed or pad page with blanks
1.1       deraadt  1679:         */
                   1680:        if (formfeed) {
1.5       grr      1681:            if (incomp)
                   1682:                if (putchar('\n') == EOF) {
                   1683:                    pfail();
                   1684:                    return(1);
1.1       deraadt  1685:                }
1.5       grr      1686:            if (putchar(OUTFF) == EOF) {
                   1687:                    pfail();
                   1688:                    return(1);
                   1689:            }
                   1690:
                   1691:        } else {
                   1692:
                   1693:            if (incomp)
                   1694:                cnt++;
                   1695:
                   1696:            cnt += TAILLEN;
                   1697:            while (--cnt >= 0) {
1.1       deraadt  1698:                if (putchar('\n') == EOF) {
1.5       grr      1699:                    pfail();
                   1700:                    return(1);
1.1       deraadt  1701:                }
1.5       grr      1702:            }
1.1       deraadt  1703:        }
1.5       grr      1704:     }
                   1705:
                   1706:     return(0);
1.1       deraadt  1707: }
                   1708:
                   1709: /*
1.5       grr      1710:  * terminate():    when a SIGINT is recvd
1.1       deraadt  1711:  */
1.22      moritz   1712: /*ARGSUSED*/
1.1       deraadt  1713: void
1.18      deraadt  1714: terminate(int which_sig)
1.1       deraadt  1715: {
1.12      deraadt  1716:     flsh_errs();
1.11      deraadt  1717:     _exit(1);
1.1       deraadt  1718: }
                   1719:
                   1720: void
1.18      deraadt  1721: mfail(void)
1.1       deraadt  1722: {
1.12      deraadt  1723:     ferrout("pr: memory allocation failed\n");
1.1       deraadt  1724: }
                   1725:
                   1726: void
1.18      deraadt  1727: pfail(void)
1.1       deraadt  1728: {
1.12      deraadt  1729:     ferrout("pr: write failure, %s\n", strerror(errno));
1.1       deraadt  1730: }
                   1731:
                   1732: void
1.18      deraadt  1733: usage(void)
1.1       deraadt  1734: {
1.12      deraadt  1735:     ferrout(
1.23      jmc      1736:      "usage: pr [+page] [-column] [-adFfmrt] [-e [char] [gap]] [-h header]\n");
1.12      deraadt  1737:     ferrout(
1.23      jmc      1738:      "\t[-i [char] [gap]] [-l lines] [-n [char] [width]] [-o offset]\n");
1.12      deraadt  1739:     ferrout(
1.23      jmc      1740:      "\t[-s [char]] [-w width] [-] [file ...]\n");
1.1       deraadt  1741: }
                   1742:
                   1743: /*
1.5       grr      1744:  * setup:    Validate command args, initialize and perform sanity
                   1745:  *        checks on options
1.1       deraadt  1746:  */
                   1747: int
1.18      deraadt  1748: setup(int argc, char *argv[])
1.1       deraadt  1749: {
1.13      mpech    1750:     int c;
1.5       grr      1751:     int eflag = 0;
                   1752:     int iflag = 0;
                   1753:     int wflag = 0;
                   1754:     int cflag = 0;
1.22      moritz   1755:     const char *errstr;
1.5       grr      1756:
1.12      deraadt  1757:     if (isatty(fileno(stdout)))
                   1758:        ferr = 1;
                   1759:
1.6       millert  1760:     while ((c = egetopt(argc, argv, "#adfFmrte?h:i?l:n?o:s?w:")) != -1) {
1.5       grr      1761:        switch (c) {
                   1762:        case '+':
1.22      moritz   1763:            pgnm = strtonum(eoptarg, 1, INT_MAX, &errstr);
                   1764:            if (errstr) {
                   1765:                ferrout("pr: +page number is %s: %s\n", errstr, eoptarg);
1.5       grr      1766:                return(1);
                   1767:            }
                   1768:            ++skipping;
                   1769:            break;
                   1770:        case '-':
1.22      moritz   1771:            clcnt = strtonum(eoptarg, 1, INT_MAX, &errstr);
                   1772:            if (errstr) {
                   1773:                ferrout("pr: -columns number is %s: %s\n", errstr, eoptarg);
1.5       grr      1774:                return(1);
                   1775:            }
                   1776:            if (clcnt > 1)
                   1777:                ++cflag;
                   1778:            break;
                   1779:        case 'a':
                   1780:            ++across;
                   1781:            break;
                   1782:        case 'd':
                   1783:            ++dspace;
                   1784:            break;
                   1785:        case 'e':
                   1786:            ++eflag;
                   1787:            if ((eoptarg != NULL) && !isdigit(*eoptarg))
                   1788:                inchar = *eoptarg++;
                   1789:            else
                   1790:                inchar = INCHAR;
                   1791:            if ((eoptarg != NULL) && isdigit(*eoptarg)) {
1.22      moritz   1792:                ingap = strtonum(eoptarg, 0, INT_MAX, &errstr);
                   1793:                if (errstr) {
                   1794:                    ferrout("pr: -e gap is %s: %s\n", errstr, eoptarg);
1.5       grr      1795:                    return(1);
                   1796:                }
                   1797:                if (ingap == 0)
                   1798:                    ingap = INGAP;
                   1799:            } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1.12      deraadt  1800:                ferrout("pr: invalid value for -e %s\n", eoptarg);
1.5       grr      1801:                return(1);
                   1802:            } else
                   1803:                ingap = INGAP;
                   1804:            break;
                   1805:        case 'f':
                   1806:        case 'F':
                   1807:            ++formfeed;
                   1808:            break;
                   1809:        case 'h':
                   1810:            header = eoptarg;
                   1811:            break;
                   1812:        case 'i':
                   1813:            ++iflag;
                   1814:            if ((eoptarg != NULL) && !isdigit(*eoptarg))
                   1815:                ochar = *eoptarg++;
                   1816:            else
                   1817:                ochar = OCHAR;
                   1818:            if ((eoptarg != NULL) && isdigit(*eoptarg)) {
1.22      moritz   1819:                ogap = strtonum(eoptarg, 0, INT_MAX, &errstr);
                   1820:                if (errstr) {
                   1821:                    ferrout("pr: -i gap is %s: %s\n", errstr, eoptarg);
1.5       grr      1822:                    return(1);
                   1823:                }
                   1824:                if (ogap == 0)
                   1825:                    ogap = OGAP;
                   1826:            } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1.12      deraadt  1827:                ferrout("pr: invalid value for -i %s\n", eoptarg);
1.5       grr      1828:                return(1);
                   1829:            } else
                   1830:                ogap = OGAP;
                   1831:            break;
                   1832:        case 'l':
1.22      moritz   1833:            lines = strtonum(eoptarg, 1, INT_MAX, &errstr);
                   1834:            if (errstr) {
                   1835:                ferrout("pr: number of lines is %s: %s\n", errstr, eoptarg);
1.5       grr      1836:                return(1);
                   1837:            }
                   1838:            break;
                   1839:        case 'm':
                   1840:            ++merge;
                   1841:            break;
                   1842:        case 'n':
                   1843:            if ((eoptarg != NULL) && !isdigit(*eoptarg))
                   1844:                nmchar = *eoptarg++;
                   1845:            else
                   1846:                nmchar = NMCHAR;
                   1847:            if ((eoptarg != NULL) && isdigit(*eoptarg)) {
1.22      moritz   1848:                nmwd = strtonum(eoptarg, 1, INT_MAX, &errstr);
                   1849:                if (errstr) {
                   1850:                    ferrout("pr: -n width is %s: %s\n", errstr, eoptarg);
1.5       grr      1851:                    return(1);
1.1       deraadt  1852:                }
1.5       grr      1853:            } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1.12      deraadt  1854:                ferrout("pr: invalid value for -n %s\n", eoptarg);
1.5       grr      1855:                return(1);
                   1856:            } else
                   1857:                nmwd = NMWD;
                   1858:            break;
                   1859:        case 'o':
1.22      moritz   1860:            offst = strtonum(eoptarg, 1, INT_MAX, &errstr);
                   1861:            if (errstr) {
                   1862:                ferrout("pr: -o offset is %s: %s\n", errstr, eoptarg);
1.5       grr      1863:                return(1);
                   1864:            }
                   1865:            break;
                   1866:        case 'r':
                   1867:            ++nodiag;
                   1868:            break;
                   1869:        case 's':
                   1870:            ++sflag;
                   1871:            if (eoptarg == NULL)
                   1872:                schar = SCHAR;
1.7       deraadt  1873:            else {
1.5       grr      1874:                schar = *eoptarg++;
1.7       deraadt  1875:                if (*eoptarg != '\0') {
1.12      deraadt  1876:                    ferrout("pr: invalid value for -s %s\n", eoptarg);
1.7       deraadt  1877:                    return(1);
                   1878:                }
1.5       grr      1879:            }
                   1880:            break;
                   1881:        case 't':
                   1882:            ++nohead;
                   1883:            break;
                   1884:        case 'w':
                   1885:            ++wflag;
1.22      moritz   1886:            pgwd = strtonum(eoptarg, 1, INT_MAX, &errstr);
                   1887:            if (errstr) {
                   1888:                ferrout("pr: -w width is %s: %s\n", errstr, eoptarg);
1.5       grr      1889:                return(1);
                   1890:            }
                   1891:            break;
                   1892:        default:
                   1893:            return(1);
                   1894:        }
                   1895:     }
                   1896:
                   1897:     /*
                   1898:      * default and sanity checks
                   1899:      */
                   1900:     inform++;
                   1901:
                   1902:     if (!clcnt) {
                   1903:        if (merge) {
                   1904:            if ((clcnt = argc - eoptind) <= 1) {
                   1905:                clcnt = CLCNT;
                   1906: #ifdef stupid
                   1907:                merge = 0;
                   1908: #endif
                   1909:            }
1.1       deraadt  1910:        } else
1.5       grr      1911:            clcnt = CLCNT;
                   1912:     }
                   1913:     if (across) {
                   1914:        if (clcnt == 1) {
1.12      deraadt  1915:            ferrout("pr: -a flag requires multiple columns\n");
1.5       grr      1916:            return(1);
                   1917:        }
                   1918:        if (merge) {
1.12      deraadt  1919:            ferrout("pr: -m cannot be used with -a\n");
1.5       grr      1920:            return(1);
                   1921:        }
                   1922:     }
                   1923:     if (!wflag) {
                   1924:        if (sflag)
                   1925:            pgwd = SPGWD;
                   1926:        else
                   1927:            pgwd = PGWD;
                   1928:     }
                   1929:     if (cflag || merge) {
                   1930:        if (!eflag) {
                   1931:            inchar = INCHAR;
                   1932:            ingap = INGAP;
                   1933:        }
                   1934:        if (!iflag) {
                   1935:            ochar = OCHAR;
                   1936:            ogap = OGAP;
                   1937:        }
                   1938:     }
                   1939:     if (cflag) {
                   1940:        if (merge) {
1.12      deraadt  1941:            ferrout("pr: -m cannot be used with multiple columns\n");
1.5       grr      1942:            return(1);
1.1       deraadt  1943:        }
1.5       grr      1944:        if (nmwd) {
                   1945:            colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt;
                   1946:            pgwd = ((colwd + nmwd + 2) * clcnt) - 1;
                   1947:        } else {
                   1948:            colwd = (pgwd + 1 - clcnt)/clcnt;
                   1949:            pgwd = ((colwd + 1) * clcnt) - 1;
1.1       deraadt  1950:        }
1.5       grr      1951:        if (colwd < 1) {
1.12      deraadt  1952:            ferrout("pr: page width is too small for %d columns\n",clcnt);
1.5       grr      1953:            return(1);
                   1954:        }
                   1955:     }
                   1956:     if (!lines)
                   1957:        lines = LINES;
                   1958:
                   1959:     /*
                   1960:      * make sure long enough for headers. if not disable
                   1961:      */
                   1962:     if (lines <= HEADLEN + TAILLEN)
                   1963:        ++nohead;
                   1964:     else if (!nohead)
                   1965:        lines -= HEADLEN + TAILLEN;
                   1966:
                   1967:     /*
                   1968:      * adjust for double space on odd length pages
                   1969:      */
                   1970:     if (dspace) {
                   1971:        if (lines == 1)
                   1972:            dspace = 0;
                   1973:        else {
                   1974:            if (lines & 1)
                   1975:                ++addone;
                   1976:            lines /= 2;
                   1977:        }
                   1978:     }
                   1979:
                   1980:     if ((timefrmt = getenv("LC_TIME")) == NULL)
                   1981:        timefrmt = TIMEFMT;
                   1982:     return(0);
1.1       deraadt  1983: }