Annotation of researchv9/cmd/pr.c, revision 1.1.1.1

1.1       root        1: #include <stdio.h>
                      2: /*
                      3:  *     PR command (print files in pages and columns, with headings)
                      4:  *     2+head+2+page[56]+5
                      5:  */
                      6: 
                      7: #define ESC    '\033'
                      8: #define LENGTH 66
                      9: #define LINEW  72
                     10: #define NUMW   5
                     11: #define MARGIN 10
                     12: #define DEFTAB 8
                     13: 
                     14: FILE *fopen(), *mustopen();
                     15: char nulls[] = "";
                     16: typedef struct { FILE *f_f; char *f_name; int f_nextc; } FILS;
                     17: FILS *Files;
                     18: int Multi = 0, Nfiles = 0, Error = 0, Balance = 0, onintr();
                     19: 
                     20: #include <signal.h>
                     21: #include <ctype.h>
                     22: #include <sys/types.h>
                     23: #include <sys/stat.h>
                     24: typedef char CHAR;
                     25: typedef int ANY;
                     26: typedef unsigned UNS;
                     27: #define NFILES 10
                     28: int Mode;
                     29: char *ttyname(), *Ttyout, obuf[BUFSIZ];
                     30: #define istty(F)       ttyname(fileno(F))
                     31: /* ARGSUSED */
                     32: fixtty(argc, argv) char **argv;
                     33: {
                     34:        struct stat sbuf;
                     35: 
                     36:        setbuf(stdout, obuf);
                     37:        if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr);
                     38:        if (Ttyout= istty(stdout)) {
                     39:                stat(Ttyout, &sbuf);
                     40:                Mode = sbuf.st_mode&0777;
                     41:                chmod(Ttyout, 0600);
                     42:        }
                     43:        return (argc);
                     44: }
                     45: 
                     46: #define done() if (Ttyout) chmod(Ttyout, Mode)
                     47: #define INTREXIT       _exit
                     48: char *GETDATE() /* return date file was last modified */
                     49: {
                     50:        char *ctime();
                     51:        static char *now = NULL;
                     52:        static struct stat sbuf, nbuf;
                     53: 
                     54:        if (Nfiles > 1 || Files->f_name == nulls) {
                     55:                if (now == NULL)
                     56:                        { time(&nbuf.st_mtime); now = ctime(&nbuf.st_mtime); }
                     57:                return (now);
                     58:        } else {
                     59:                stat(Files->f_name, &sbuf);
                     60:                return (ctime(&sbuf.st_mtime));
                     61:        }
                     62: }
                     63: 
                     64: #define CADDID()
                     65: #define HEAD   "%12.12s %4.4s  %s Page %d\n\n\n", date+4, date+20, head, Page
                     66: #define TOLOWER(c)     (isupper(c) ? tolower(c) : c)   /* ouch! */
                     67: #define cerror(S)      fprintf(stderr, "pr: %s", S)
                     68: 
                     69: char *ffiler(s) char *s;
                     70: {
                     71:        static char buf[100];
                     72: 
                     73:        sprintf(buf, "can't open %s", s);
                     74:        return (buf);
                     75: }
                     76: 
                     77: #define STDINNAME()    nulls
                     78: #define TTY    "/dev/tty", "r"
                     79: #define PROMPT()       putc('\7', stderr) /* BEL */
                     80: #define TABS(N,C)      if ((N = intopt(argv, &C)) < 0) N = DEFTAB
                     81: #define INSTABS()      if (Itabn == 0 && Ttyout) Itabn = DEFTAB
                     82: #define ETABS  (Inpos % Etabn)
                     83: #define ITABS  (Itabn > 0 && Nspace >= (nc = Itabn - Outpos % Itabn))
                     84: #define NSEPC  '\t'
                     85: 
                     86: ANY *getspace();
                     87: 
                     88: main(argc, argv) char *argv[];
                     89: {
                     90:        FILS fstr[NFILES];
                     91:        int nfdone = 0;
                     92: 
                     93:        Files = fstr;
                     94:        for (argc = findopt(argc, argv); argc > 0; --argc, ++argv)
                     95:                if (Multi == 'm') {
                     96:                        if (Nfiles >= NFILES - 1) die("too many files");
                     97:                        if (mustopen(*argv, &Files[Nfiles++]) == NULL)
                     98:                                ++nfdone; /* suppress printing */
                     99:                } else {
                    100:                        if (print(*argv))
                    101:                                fclose(Files->f_f);
                    102:                        ++nfdone;
                    103:                }
                    104:        if (!nfdone) /* no files named, use stdin */
                    105:                print(nulls); /* on GCOS, use current file, if any */
                    106:        errprint(); /* print accumulated error reports */
                    107:        exit(Error);
                    108: }
                    109: 
                    110: 
                    111: long Lnumb = 0;
                    112: FILE *Ttyin = stdin;
                    113: int Dblspace = 1, Fpage = 1, Formfeed = 0,
                    114:        Length = LENGTH, Linew = 0, Offset = 0, Ncols = 1, Pause = 0, Sepc = 0,
                    115:        Colw, Plength, Margin = MARGIN, Numw, Nsepc = NSEPC, Report = 1,
                    116:        Etabn = 0, Etabc = '\t', Itabn = 0, Itabc = '\t';
                    117: char *Head = NULL;
                    118: CHAR *Buffer = NULL, *Bufend;
                    119: typedef struct { CHAR *c_ptr, *c_ptr0; long c_lno; } *COLP;
                    120: COLP Colpts;
                    121: 
                    122: findopt(argc, argv) char *argv[];
                    123: {
                    124:        char **eargv = argv;
                    125:        int eargc = 0, c;
                    126: 
                    127:        argc = fixtty(argc, argv);
                    128:        while (--argc > 0) {
                    129:                switch (c = **++argv) {
                    130:                case '-':
                    131:                        if ((c = *++*argv) == '\0') break;
                    132:                case '+':
                    133:                        do {
                    134:                                if (isdigit(c))
                    135:                                        { --*argv; Ncols = atoix(argv); }
                    136:                                else switch (c = TOLOWER(c)) {
                    137:                                case '+': if ((Fpage = atoix(argv)) < 1)
                    138:                                                Fpage = 1;
                    139:                                        continue;
                    140:                                case 'd': Dblspace = 2; continue;
                    141:                                case 'e': TABS(Etabn, Etabc); continue;
                    142:                                case 'f': ++Formfeed; continue;
                    143:                                case 'h': if (--argc > 0) Head = argv[1];
                    144:                                        continue;
                    145:                                case 'i': TABS(Itabn, Itabc); continue;
                    146:                                case 'l': Length = atoix(argv); continue;
                    147:                                case 'a':
                    148:                                case 'm': Multi = c; continue;
                    149:                                case 'o': Offset = atoix(argv); continue;
                    150:                                case 'p': ++Pause; continue;
                    151:                                case 'r': Report = 0; continue;
                    152:                                case 's':
                    153:                                        if ((Sepc = (*argv)[1]) != '\0') ++*argv;
                    154:                                        else Sepc = '\t';
                    155:                                        continue;
                    156:                                case 't': Margin = 0; continue;
                    157:                                case 'w': Linew = atoix(argv); continue;
                    158:                                case 'n':
                    159:                                case 'x': /* retained for historical reasons */
                    160:                                        ++Lnumb;
                    161:                                        if ((Numw = intopt(argv, &Nsepc)) <= 0)
                    162:                                                Numw = NUMW;
                    163:                                case 'b': Balance = 1; continue;
                    164:                                case 'q': /* retained for historical reasons */
                    165:                                case 'j': /* ignore GCOS jprint option */
                    166:                                        continue;
                    167:                                default : die("bad option");
                    168:                                }
                    169:                        } while ((c = *++*argv) != '\0');
                    170:                        if (Head == argv[1]) ++argv;
                    171:                        continue;
                    172:                }
                    173:                *eargv++ = *argv;
                    174:                ++eargc;
                    175:        }
                    176:        if (Length == 0) Length = LENGTH;
                    177:        if (Length <= Margin) Margin = 0;
                    178:        Plength = Length - Margin/2;
                    179:        if (Multi == 'm') Ncols = eargc;
                    180:        switch (Ncols) {
                    181:        case 0:
                    182:                Ncols = 1;
                    183:        case 1:
                    184:                break;
                    185:        default:
                    186:                if (Etabn == 0) /* respect explicit tab specification */
                    187:                        Etabn = DEFTAB;
                    188:                INSTABS();
                    189:        }
                    190:        if (Linew == 0) Linew = Ncols != 1 && Sepc == 0 ? LINEW : 512;
                    191:        if (Lnumb) Linew -= Multi == 'm' ? Numw : Numw * Ncols;
                    192:        if ((Colw = (Linew - Ncols + 1)/Ncols) < 1)
                    193:                die("width too small");
                    194:        if (Ncols != 1 && Multi == 0) {
                    195:                UNS buflen = ((UNS)(Plength/Dblspace + 1))*(Linew+1)*sizeof(CHAR);
                    196:                Buffer = (CHAR *)getspace(buflen);
                    197:                Bufend = &Buffer[buflen];
                    198:                Colpts = (COLP)getspace((UNS)((Ncols+1)*sizeof(*Colpts)));
                    199:        }
                    200:        if (Ttyout && (Pause || Formfeed) && !istty(stdin))
                    201:                Ttyin = fopen(TTY);
                    202:        return (eargc);
                    203: }
                    204: 
                    205: intopt(argv, optp) char *argv[]; int *optp;
                    206: {
                    207:        int c;
                    208: 
                    209:        if ((c = (*argv)[1]) != '\0' && !isdigit(c)) { *optp = c; ++*argv; }
                    210:        return ((c = atoix(argv)) != 0 ? c : -1);
                    211: }
                    212: 
                    213: int Page, C = '\0', Nspace, Inpos;
                    214: 
                    215: print(name) char *name;
                    216: {
                    217:        static int notfirst = 0;
                    218:        char *date = NULL, *head = NULL;
                    219:        int c;
                    220: 
                    221:        if (Multi != 'm' && mustopen(name, &Files[0]) == NULL) return (0);
                    222:        if (Buffer) ungetc(Files->f_nextc, Files->f_f);
                    223:        if (Lnumb) Lnumb = 1;
                    224:        for (Page = 0; ; putpage()) {
                    225:                if (C == EOF) break;
                    226:                if (Buffer) nexbuf();
                    227:                Inpos = 0;
                    228:                if (get(0) == EOF) break;
                    229:                fflush(stdout);
                    230:                if (++Page >= Fpage) {
                    231:                        if (Ttyout && (Pause || Formfeed && !notfirst++)) {
                    232:                                PROMPT(); /* prompt with bell and pause */
                    233:                                while ((c = getc(Ttyin)) != EOF && c != '\n') ;
                    234:                        }
                    235:                        if (Margin == 0) continue;
                    236:                        CADDID();
                    237:                        if (date == NULL) date = GETDATE();
                    238:                        if (head == NULL) head = Head != NULL ? Head :
                    239:                                Nfiles < 2 ? Files->f_name : nulls;
                    240:                        printf("\n\n");
                    241:                        Nspace = Offset;
                    242:                        putspace();
                    243:                        printf(HEAD);
                    244:                }
                    245:        }
                    246:        C = '\0';
                    247:        return (1);
                    248: }
                    249: 
                    250: int Outpos, Lcolpos, Pcolpos, Line;
                    251: 
                    252: putpage()
                    253: {
                    254:        register int colno;
                    255: 
                    256:        for (Line = Margin/2; ; get(0)) {
                    257:                for (Nspace = Offset, colno = 0, Outpos = 0; C != '\f'; ) {
                    258:                        if (Lnumb && C != EOF && (colno == 0 || Multi == 'a')) {
                    259:                                if (Page >= Fpage) {
                    260:                                        putspace();
                    261:                                        printf("%*ld", Numw, Buffer ?
                    262:                                                Colpts[colno].c_lno++ : Lnumb);
                    263:                                        Outpos += Numw;
                    264:                                        put(Nsepc);
                    265:                                }
                    266:                                ++Lnumb;
                    267:                        }
                    268:                        for (Lcolpos = 0, Pcolpos = 0;
                    269:                                C != '\n' && C != '\f' && C != EOF; get(colno))
                    270:                                        put(C);
                    271:                        if (C == EOF || ++colno == Ncols ||
                    272:                                C == '\n' && get(colno) == EOF) break;
                    273:                        if (Sepc) put(Sepc);
                    274:                        else if ((Nspace += Colw - Lcolpos + 1) < 1) Nspace = 1;
                    275:                }
                    276:        /*
                    277:                if (C == EOF) {
                    278:                        if (Margin != 0) break;
                    279:                        if (colno != 0) put('\n');
                    280:                        return;
                    281:                }
                    282:        */
                    283:                if (C == EOF && colno == 0) {
                    284:                        if (Margin != 0) break;
                    285:                        return;
                    286:                }
                    287:                if (C == '\f') break;
                    288:                put('\n');
                    289:                if (Dblspace == 2 && Line < Plength) put('\n');
                    290:                if (Line >= Plength) break;
                    291:        }
                    292:        if (Formfeed) put('\f');
                    293:        else while (Line < Length) put('\n');
                    294: }
                    295: 
                    296: nexbuf()
                    297: {
                    298:        register CHAR *s = Buffer;
                    299:        register COLP p = Colpts;
                    300:        int j, c, bline = 0;
                    301: 
                    302:        for ( ; ; ) {
                    303:                p->c_ptr0 = p->c_ptr = s;
                    304:                if (p == &Colpts[Ncols]) return;
                    305:                (p++)->c_lno = Lnumb + bline;
                    306:                for (j = (Length - Margin)/Dblspace; --j >= 0; ++bline)
                    307:                        for (Inpos = 0; ; ) {
                    308:                                if ((c = getc(Files->f_f)) == EOF) {
                    309:                                        for (*s = EOF; p <= &Colpts[Ncols]; ++p)
                    310:                                                p->c_ptr0 = p->c_ptr = s;
                    311:                                        if (Balance)
                    312:                                                balance(bline);
                    313:                                        return;
                    314:                                }
                    315:                                if (isprint(c)) ++Inpos;
                    316:                                if (Inpos <= Colw || c == '\n') {
                    317:                                        *s = c;
                    318:                                        if (++s >= Bufend)
                    319:                                                die("page-buffer overflow");
                    320:                                }
                    321:                                if (c == '\n') break;
                    322:                                switch (c) {
                    323:                                case '\b': if (Inpos == 0) --s;
                    324:                                case ESC:  if (Inpos > 0) --Inpos;
                    325:                                }
                    326:                        }
                    327:        }
                    328: }
                    329: 
                    330: balance(bline) /* line balancing for last page */
                    331: {
                    332:        register CHAR *s = Buffer;
                    333:        register COLP p = Colpts;
                    334:        int colno = 0, j, c, l;
                    335: 
                    336:        c = bline % Ncols;
                    337:        l = (bline + Ncols - 1)/Ncols;
                    338:        bline = 0;
                    339:        do {
                    340:                for (j = 0; j < l; ++j)
                    341:                        while (*s++ != '\n') ;
                    342:                (++p)->c_lno = Lnumb + (bline += l);
                    343:                p->c_ptr0 = p->c_ptr = s;
                    344:                if (++colno == c) --l;
                    345:        } while (colno < Ncols - 1);
                    346: }
                    347: 
                    348: get(colno)
                    349: {
                    350:        static int peekc = 0;
                    351:        register COLP p;
                    352:        register FILS *q;
                    353:        register int c;
                    354: 
                    355:        if (peekc)
                    356:                { peekc = 0; c = Etabc; }
                    357:        else if (Buffer) {
                    358:                p = &Colpts[colno];
                    359:                if (p->c_ptr >= (p+1)->c_ptr0) c = EOF;
                    360:                else if ((c = *p->c_ptr) != EOF) ++p->c_ptr;
                    361:        } else if ((c = 
                    362:                (q = &Files[Multi == 'a' ? 0 : colno])->f_nextc) == EOF) {
                    363:                for (q = &Files[Nfiles]; --q >= Files && q->f_nextc == EOF; ) ;
                    364:                if (q >= Files) c = '\n';
                    365:        } else
                    366:                q->f_nextc = getc(q->f_f);
                    367:        if (Etabn != 0 && c == Etabc) {
                    368:                ++Inpos;
                    369:                peekc = ETABS;
                    370:                c = ' ';
                    371:        } else if (isprint(c))
                    372:                ++Inpos;
                    373:        else
                    374:                switch (c) {
                    375:                case '\b':
                    376:                case ESC:
                    377:                        if (Inpos > 0) --Inpos;
                    378:                        break;
                    379:                case '\f':
                    380:                        if (Ncols == 1) break;
                    381:                        c = '\n';
                    382:                case '\n':
                    383:                case '\r':
                    384:                        Inpos = 0;
                    385:                }
                    386:        return (C = c);
                    387: }
                    388: 
                    389: put(c)
                    390: {
                    391:        int move;
                    392: 
                    393:        switch (c) {
                    394:        case ' ':
                    395:                ++Nspace; ++Lcolpos; return;
                    396:        case '\b':
                    397:                if (Lcolpos == 0) return;
                    398:                if (Nspace > 0) { --Nspace; --Lcolpos; return; }
                    399:                if (Lcolpos > Pcolpos) { --Lcolpos; return; }
                    400:        case ESC:
                    401:                move = -1;
                    402:                break;
                    403:        case '\n':
                    404:                ++Line;
                    405:        case '\r':
                    406:        case '\f':
                    407:                Pcolpos = 0; Lcolpos = 0; Nspace = 0; Outpos = 0;
                    408:        default:
                    409:                move = (isprint(c) != 0);
                    410:        }
                    411:        if (Page < Fpage) return;
                    412:        if (Lcolpos > 0 || move > 0) Lcolpos += move;
                    413:        if (Lcolpos <= Colw) {
                    414:                putspace();
                    415:                putchar(c);
                    416:                Pcolpos = Lcolpos;
                    417:                Outpos += move;
                    418:        }
                    419: }
                    420: 
                    421: putspace()
                    422: {
                    423:        int nc;
                    424: 
                    425:        for ( ; Nspace > 0; Outpos += nc, Nspace -= nc)
                    426:                if (ITABS)
                    427:                        putchar(Itabc);
                    428:                else {
                    429:                        nc = 1;
                    430:                        putchar(' ');
                    431:                }
                    432: }
                    433: 
                    434: atoix(p) register char **p;
                    435: {
                    436:        register int n = 0, c;
                    437: 
                    438:        while (isdigit(c = *++*p)) n = 10*n + c - '0';
                    439:        --*p;
                    440:        return (n);
                    441: }
                    442: 
                    443: /* Defer message about failure to open file to prevent messing up
                    444:    alignment of page with tear perforations or form markers.
                    445:    Treat empty file as special case and report as diagnostic.
                    446: */
                    447: #define EMPTY  14      /* length of " -- empty file" */
                    448: typedef struct err { struct err *e_nextp; char *e_mess; } ERR;
                    449: ERR *Err = NULL, *Lasterr = (ERR *)&Err;
                    450: 
                    451: FILE *mustopen(s, f) char *s; register FILS *f;
                    452: {
                    453:        if (*s == '\0') {
                    454:                f->f_name = STDINNAME();
                    455:                f->f_f = stdin;
                    456:        } else if ((f->f_f = fopen(f->f_name = s, "r")) == NULL) {
                    457:                char *strcpy();
                    458:                s = ffiler(f->f_name);
                    459:                s = strcpy((char *)getspace((UNS)(strlen(s) + 1)), s);
                    460:        }
                    461:        if (f->f_f != NULL) {
                    462:                if ((f->f_nextc = getc(f->f_f)) != EOF || Multi == 'm')
                    463:                        return (f->f_f);
                    464:                sprintf(s = (char *)getspace((UNS)(strlen(f->f_name) + 1 + EMPTY)),
                    465:                        "%s -- empty file", f->f_name);
                    466:                fclose(f->f_f);
                    467:        }
                    468:        Error = 1;
                    469:        if (Report)
                    470:                if (Ttyout) { /* accumulate error reports */
                    471:                        Lasterr = Lasterr->e_nextp = (ERR *)getspace((UNS)sizeof(ERR));
                    472:                        Lasterr->e_nextp = NULL;
                    473:                        Lasterr->e_mess = s;
                    474:                } else { /* ok to print error report now */
                    475:                        cerror(s);
                    476:                        putc('\n', stderr);
                    477:                }
                    478:        return ((FILE *)NULL);
                    479: }
                    480: 
                    481: ANY *getspace(n) UNS n;
                    482: {
                    483:        ANY *t;
                    484: 
                    485:        if ((t = (ANY *)malloc(n)) == NULL) die("out of space");
                    486:        return (t);
                    487: }
                    488: 
                    489: die(s) char *s;
                    490: {
                    491:        ++Error;
                    492:        errprint();
                    493:        cerror(s);
                    494:        putc('\n', stderr);
                    495:        exit(1);
                    496: }
                    497: 
                    498: onintr()
                    499: {
                    500:        ++Error;
                    501:        errprint();
                    502:        INTREXIT(1);
                    503: }
                    504: 
                    505: errprint() /* print accumulated error reports */
                    506: {
                    507:        fflush(stdout);
                    508:        for ( ; Err != NULL; Err = Err->e_nextp) {
                    509:                cerror(Err->e_mess);
                    510:                putc('\n', stderr);
                    511:        }
                    512:        done();
                    513: }

unix.superglobalmegacorp.com

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