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

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