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

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