Annotation of researchv9/cmd/pr.c, revision 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.