Annotation of coherent/d/bin/pr.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * pr -- print files
                      3:  *
                      4:  * All references to page length exclude possible margin lines.
                      5:  */
                      6: 
                      7: #include       <stdio.h>
                      8: 
                      9: #ifdef COHERENT
                     10: #include       <sys/types.h>
                     11: #include       <errno.h>
                     12: #endif
                     13: 
                     14: #ifdef MSDOS
                     15: #include <sys/timeb.h>                 /* typedef long time_t; */
                     16: #endif
                     17: 
                     18: #define        LSIZE   256                     /* line size */
                     19: #define        LENGTH  (66-MARGIN)             /* default page length */
                     20: #define        WIDTH   80                      /* default page width */
                     21: #define        TMAR    5                       /* five lines of top margin */
                     22: #define        BMAR    5                       /* five lines of bottom margin */
                     23: #define        HEADER  2                       /* line # where header appears */
                     24: 
                     25: #define        MARGIN  (TMAR+BMAR)
                     26: 
                     27: 
                     28: /*
                     29:  * info on input file streams
                     30:  * Unless -m is in effect, only f[0] is used.
                     31:  */
                     32: struct f {
                     33:        int     f_ff;           /* '\f' received */
                     34:        FILE    *f_stream;      /* input stream */
                     35: };
                     36: 
                     37: 
                     38: int    ncol    = 1,                    /* # of columns */
                     39:        nskip,                          /* # pages to skip of each file */
                     40:        length  = LENGTH,               /* page length */
                     41:        width   = WIDTH,                /* page width */
                     42:        lno,                            /* current input line # */
                     43:        fwidth;                         /* field width */
                     44: char   schar,                          /* separator char */
                     45:        tflag,                          /* -t: no header or margins */
                     46:        mflag,                          /* -m: multiple file output */
                     47:        nflag,                          /* -n: line number output */
                     48:        *date,                          /* date string */
                     49:        *header,                        /* -h: header text */
                     50:        **lines;                        /* buffer addr for multicolumn */
                     51: 
                     52: struct f       f[20];                  /* input file info */
                     53: 
                     54: char   **init( ),
                     55:        *malloc( ),
                     56:        *ctime( );
                     57: int    page1( ), page2( ),
                     58:        putl( ), nop( );
                     59: FILE   *openf( );
                     60: 
                     61: int    (*page)( )      = page1;
                     62: 
                     63: 
                     64: /*
                     65:  * paginate files to standard output
                     66:  * If no files are given, use standard input.  The file name "-" also
                     67:  * means standard input.
                     68:  */
                     69: main( argc, argv)
                     70: char   **argv;
                     71: {
                     72: #ifdef MSDOS
                     73:        msdoscvt("pr", &argc, &argv);
                     74: #endif
                     75:        argv = init( argc, argv);
                     76: 
                     77:        if (*argv)
                     78:                while (*argv) {
                     79:                        f[0].f_stream = openf( *argv);
                     80:                        print( *argv++);
                     81:                        fclose( f[0].f_stream);
                     82:                }
                     83:        else
                     84:                print( "");
                     85: 
                     86:        return (0);
                     87: }
                     88: 
                     89: 
                     90: /*
                     91:  * initialize & get options
                     92:  * Flags are recognized up to the first file name.  If multi-column (-N),
                     93:  * allocate line array.  If printing multiple files (-m), open all files.
                     94:  * There are two paging algorithms: one file per column (page1), and
                     95:  * many columns per file (page2).  The latter requires page buffering.
                     96:  * init( ) makes this selection.
                     97:  */
                     98: char   **
                     99: init( ac, av)
                    100: register char  **av;
                    101: {
                    102:        register        mar     = MARGIN;
                    103:        static char     obuf[BUFSIZ];
                    104:        time_t          tvec;
                    105: 
                    106:        setbuf( stdout, obuf);
                    107: 
                    108:        while (++av, --ac) {
                    109:                if (av[0][0] == '+')
                    110:                        if ((nskip=atoi( &av[0][1])) <= 0)
                    111:                                fatal( "bad skip");
                    112:                        else
                    113:                                continue;
                    114:                if (av[0][0] != '-')
                    115:                        break;
                    116:                switch (av[0][1]) {
                    117:                case '\0':
                    118:                        break;
                    119:                case 'l':
                    120:                        length = atoi( &av[0][2]) - mar;
                    121:                        continue;
                    122:                case 'w':
                    123:                        width = atoi( &av[0][2]);
                    124:                        continue;
                    125:                case 'h':
                    126:                        if (av[0][2])
                    127:                                header = &av[0][2];
                    128:                        else {
                    129:                                if (--ac <= 0)
                    130:                                        fatal( "missing header arg");
                    131:                                header = (++av)[0];
                    132:                        }
                    133:                        continue;
                    134:                case 's':
                    135:                        if ((schar=av[0][2]) == '\0')
                    136:                                schar = '\t';
                    137:                        continue;
                    138:                case 'm':
                    139:                        ++mflag;
                    140:                        continue;
                    141:                case 't':
                    142:                        ++tflag;
                    143:                        length += mar;
                    144:                        mar = 0;
                    145:                        continue;
                    146:                case 'n':
                    147:                        ++nflag;
                    148:                        continue;
                    149:                default:
                    150:                        if ('0'<=av[0][1] && av[0][1]<='9')
                    151:                                ncol = atoi( &av[0][1]);
                    152:                        else
                    153:                                fatal( "no such switch %s", av[0]);
                    154:                        continue;
                    155:                }
                    156:                break;
                    157: 
                    158:        }
                    159: 
                    160:        f[0].f_stream = stdin;
                    161:        if (mflag && av[0]) {
                    162:                ncol = 0;
                    163:                do {
                    164:                        f[ncol++].f_stream = openf( av++[0]);
                    165:                } while (av[0]);
                    166:        }
                    167: 
                    168:        /*
                    169:         * check that all options jive
                    170:         */
                    171:        if (length <= 0)
                    172:                if (length == -mar) {   /* gunja artifice */
                    173:                        length = 1;
                    174:                        ++tflag;
                    175:                }
                    176:                else
                    177:                        fatal( "length too small");
                    178:        fwidth = width / ncol;
                    179:        if (schar)
                    180:                --fwidth;
                    181:        if (fwidth <= 0 || (nflag && fwidth < 10))
                    182:                fatal( "width too small");
                    183:        if (fwidth >= LSIZE-1)
                    184:                fatal( "too wide");
                    185:        if (ncol>1 && mflag==0) {
                    186:                if ((lines=malloc( (ncol-1)*length*sizeof( char *))) == NULL)
                    187:                        fatal( "insufficient core");
                    188:                page = page2;
                    189:        }
                    190: 
                    191:        time( &tvec);
                    192:        date = ctime( &tvec);
                    193: 
                    194:        return (av);
                    195: }
                    196: 
                    197: 
                    198: /*
                    199:  * open input file
                    200:  * Failure to open is fatal.  openf( "-") returns stdin.
                    201:  */
                    202: FILE   *
                    203: openf( file)
                    204: register char  *file;
                    205: {
                    206:        register FILE   *stream;
                    207: 
                    208:        lno = 0;
                    209:        if (file[0]=='-' && file[1]=='\0')
                    210:                return (stdin);
                    211:        if ((stream=fopen( file, "r")) == NULL)
                    212: #ifdef COHERENT
                    213:                if (errno == EMFILE)
                    214:                        fatal( "too many files for -m");
                    215:                else
                    216: #endif
                    217:                        fatal( "can't open %s", file);
                    218:        return (stream);
                    219: }
                    220: 
                    221: 
                    222: /*
                    223:  * print from open input streams
                    224:  * Control output of pages, perhaps provide header/footer margins and title.
                    225:  * The paging routine is expected to give an eof warning on the last page.
                    226:  */
                    227: print( file)
                    228: char   *file;
                    229: {
                    230:        register        i,
                    231:                        pg,
                    232:                        eof;
                    233: 
                    234:        for (pg=1; pg<=nskip; ++pg)
                    235:                if ((*page)( nop))
                    236:                        return;
                    237: 
                    238:        do {
                    239:                if (tflag == 0)
                    240:                        for (i=0; i<TMAR; ++i) {
                    241:                                if (i != HEADER) {
                    242:                                        putchar( '\n');
                    243:                                        continue;
                    244:                                }
                    245:                                printf( "%.12s%.5s  %s  Page %d, line %ld\n",
                    246:                                        date+4, date+19,
                    247:                                        header? header: file,
                    248:                                        pg,
                    249:                                        (long)(pg-1)*(mflag?1:ncol)*length+1);
                    250:                        }
                    251:                eof = (*page)( putl);
                    252:                if (tflag == 0)
                    253:                        for (i=0; i<BMAR; ++i)
                    254:                                putchar( '\n');
                    255:        } while (++pg, eof==0);
                    256: }
                    257: 
                    258: 
                    259: /*
                    260:  * page one stream per column
                    261:  * This handles all cases of one column per page.
                    262:  * Formfeed advances output of that stream to the next page.
                    263:  * Eof is only indicated when all streams give this condition.
                    264:  */
                    265: page1( putline)
                    266: int    (*putline)( );
                    267: {
                    268:        register        i,
                    269:                        j;
                    270:        char    lbuf[LSIZE];
                    271: 
                    272:        for (i=0; i<length; ++i) {
                    273:                for (j=0; j<ncol; ++j) {
                    274:                        getline( &f[j], lbuf);
                    275:                        (*putline)( lbuf, j<ncol-1? schar: 0);
                    276:                }
                    277:                (*putline)( (char *)0);
                    278:        }
                    279: 
                    280:        i = 0;
                    281:        for (j=0; j<ncol; ++j) {
                    282:                f[j].f_ff = 0;
                    283:                if (feof( f[j].f_stream))
                    284:                        ++i;
                    285:                else if (ungetc( getc( f[j].f_stream), f[j].f_stream) == EOF)
                    286:                        ++i;
                    287:        }
                    288:        return (i == j);
                    289: }
                    290: 
                    291: 
                    292: /*
                    293:  * page one stream across multiple columns
                    294:  * The first `ncol'-1 columns of text are buffered; the last is simply
                    295:  * read as needed.  Formfeeds advance output to the next column.
                    296:  */
                    297: page2( putline)
                    298: int    (*putline)( );
                    299: {
                    300:        register        i,
                    301:                        j,
                    302:                        k;
                    303:        char    lbuf[LSIZE];
                    304: 
                    305:        for (i=0; i<(ncol-1)*length; ++i) {
                    306:                if ((i%length) == 0)
                    307:                        f[0].f_ff = 0;
                    308:                if (k = getline( &f[0], lbuf)) {
                    309:                        if ((lines[i]=malloc( k+1)) == NULL)
                    310:                                fatal( "out of core");
                    311:                        strcpy( lines[i], lbuf);
                    312:                }
                    313:                else
                    314:                        lines[i] = NULL;
                    315:        }
                    316:        f[0].f_ff = 0;
                    317: 
                    318:        for (i=0; i<length; ++i) {
                    319:                for (j=0; j<ncol-1; ++j) {
                    320:                        k = j*length + i;
                    321:                        if (lines[k]) {
                    322:                                (*putline)( lines[k], schar);
                    323:                                free( lines[k]);
                    324:                        }
                    325:                        else
                    326:                                (*putline)( "", schar);
                    327:                }
                    328:                getline( &f[0], lbuf);
                    329:                (*putline)( lbuf, 0);
                    330:                (*putline)( (char *)0);
                    331:        }
                    332: 
                    333:        if (feof( f[0].f_stream))
                    334:                return (1);
                    335:        if (ungetc( getc( f[0].f_stream), f[0].f_stream) == EOF)
                    336:                return (1);
                    337:        return (0);
                    338: }
                    339: 
                    340: 
                    341: /*
                    342:  * read a line
                    343:  * Simple char processing is done, including tab expansion.  getline( )
                    344:  * will return an empty line if f_ff is set.  Lines are truncated to
                    345:  * fit the field width.
                    346:  */
                    347: getline( fp, lbuf)
                    348: register struct f      *fp;
                    349: char   *lbuf;
                    350: {
                    351:        register        col;
                    352:        register char   *p;
                    353:        char            c;
                    354: 
                    355:        col = 0;
                    356:        p = lbuf;
                    357:        if (feof( fp->f_stream)==0 && fp->f_ff==0) {
                    358:                if (nflag) {
                    359:                        sprintf(p, "%4d: ", ++lno);
                    360:                        p += 6;
                    361:                }
                    362:                for (; ; ) {
                    363:                        switch (c = getc(fp->f_stream)) {
                    364:                        case '\f':
                    365:                                ++fp->f_ff;
                    366:                        case EOF:
                    367:                                if (nflag && (p == &lbuf[6]))
                    368:                                        p = lbuf;
                    369:                                break;
                    370:                        case '\n':
                    371:                                break;
                    372:                        case '\r':
                    373:                                continue;
                    374:                        case '\t':
                    375:                                do {
                    376:                                        if (p<&lbuf[LSIZE-1] && col<fwidth)
                    377:                                                *p++ = ' ';
                    378:                                } while (++col & 7);
                    379:                                continue;
                    380:                        case '\b':
                    381:                                if (col) {
                    382:                                        --col;
                    383:                                        if (p<&lbuf[LSIZE-1] && col<fwidth)
                    384:                                                *p++ = c;
                    385:                                }
                    386:                                continue;
                    387:                        default:
                    388:                                if (p<&lbuf[LSIZE-1] && col<fwidth)
                    389:                                        *p++ = c;
                    390:                                ++col;
                    391:                                continue;
                    392:                        }
                    393:                        break;
                    394:                }
                    395: 
                    396:        }
                    397:        *p = '\0';
                    398:        return (p - lbuf);
                    399: }
                    400: 
                    401: 
                    402: /*
                    403:  * write a line, incrementally
                    404:  * A line of output can be built by successive calls to putl( ).  A line
                    405:  * address of 0 puts the newline.  Simple char processing is done,
                    406:  * including tab optimization.  Each line segment is padded to the
                    407:  * field width, unless a there is a field separator char.
                    408:  */
                    409: putl( lbuf, schr)
                    410: char   *lbuf;
                    411: {
                    412:        register char   *p;
                    413:        register        c,
                    414:                        nextxcol;
                    415:        static          col,
                    416:                        xcol;
                    417: 
                    418:        if ((p=lbuf) == NULL) {
                    419:                col = 0;
                    420:                xcol = 0;
                    421:                putchar( '\n');
                    422:                return;
                    423:        }
                    424:        nextxcol = xcol + fwidth;
                    425: 
                    426:        for (; ; ) {
                    427:                if ((c= *p++) == '\0') {
                    428:                        if ((c=schr) == '\0')
                    429:                                break;
                    430:                        schr = 0;
                    431:                        --p;
                    432:                        nextxcol = xcol + 1;
                    433:                }
                    434:                if (c == ' ') {
                    435:                        ++xcol;
                    436:                        continue;
                    437:                }
                    438:                if (c == '\b') {
                    439:                        --xcol;
                    440:                        continue;
                    441:                }
                    442:                while ((col|7)+1 <= xcol) {
                    443:                        col = (col|7) + 1;
                    444:                        putchar( '\t');
                    445:                }
                    446:                while (col < xcol) {
                    447:                        ++col;
                    448:                        putchar( ' ');
                    449:                }
                    450:                while (col > xcol) {
                    451:                        --col;
                    452:                        putchar( '\b');
                    453:                }
                    454:                putchar( c);
                    455:                xcol = ++col;
                    456:        }
                    457: 
                    458:        xcol = nextxcol;
                    459: }
                    460: 
                    461: 
                    462: /*
                    463:  * throw away output line
                    464:  * Used when skipping the first pages of input.
                    465:  */
                    466: nop( )
                    467: {
                    468: 
                    469: }
                    470: 
                    471: 
                    472: /*
                    473:  * print error message, exit
                    474:  */
                    475: fatal( arg0)
                    476: {
                    477: 
                    478:        fflush( stdout);
                    479:        fprintf( stderr, "pr: %r\n", &arg0);
                    480:        exit (1);
                    481: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.