Annotation of researchv10no/cmd/tabs.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *     tabs [tabspec] [+mn] [-Ttype]
                      3:  *     set tabs (and margin, if +mn), for terminal type
                      4:  */
                      5: 
                      6: static char tabsvers[] = "@(#)tabs.c   1.1";
                      7: 
                      8: #include <stdio.h>
                      9: #include <signal.h>
                     10: #include <sys/types.h>
                     11: #include <sys/stat.h>
                     12: #include <sys/ttyio.h>
                     13: #define EQ(a,b)        (strcmp(a, b) == 0)
                     14: /*     max # columns used (needed for GSI) */
                     15: #define NCOLS  158
                     16: #define NTABS  41      /* max # tabs +1 (to be set) */
                     17: #define        NTABSCL 21      /* max # tabs + 1 that will be cleared */
                     18: #define ESC    033
                     19: #define CLEAR  '2'
                     20: #define SET    '1'
                     21: #define TAB    '\t'
                     22: #define CR     '\r'
                     23: #define NMG    0       /* no margin setting */
                     24: #define GMG    1       /* DTC300s margin */
                     25: #define TMG    2       /* TERMINET margin */
                     26: #define DMG    3       /* DASI450 margin */
                     27: #define FMG    4       /* TTY 43 margin */
                     28: #define TRMG   5       /* Trendata 4000a */
                     29: 
                     30: #define TCLRLN 0       /* long, repetitive, general tab clear */
                     31: 
                     32: char   tclrhp[] = {ESC,'3',CR,0};      /* short for HP44,45,etc */
                     33: char   tclrsh[] = {ESC,CLEAR,CR,0};    /* short sequence for many terminals */
                     34: char   tclrgs[] = {ESC,TAB,CR,0};      /* short, for 300s */
                     35: char   tclr40[] = {ESC,'R',CR,0};      /* TTY 40/2 */
                     36: 
                     37: struct ttab {
                     38:        char *ttype;    /* -Tttype */
                     39:        char *tclr;     /* char sequence to clear tabs and return carriage */
                     40:        int tmaxtab;    /* maximum allowed position */
                     41:        int tmarg;      /* type of margin setting allowed */
                     42: } *tt;
                     43: 
                     44: struct ttab termtab[] = {
                     45:        "",             tclrsh, 132,    NMG,
                     46:        "1620",         tclrsh, 132,    DMG,
                     47:        "1620-12",      tclrsh, 158,    DMG,
                     48:        "1620-12-8",    tclrsh, 158,    DMG,
                     49:        "1700",         tclrsh, 132,    DMG,
                     50:        "1700-12",      tclrsh, 132,    DMG,
                     51:        "1700-12-8",    tclrsh, 158,    DMG,
                     52:        "2640",         TCLRLN,  80,    NMG,    /* hp 2640a & b */
                     53:        "2645",         tclrhp,  80,    NMG,    /* all hp 40 series except 2640's */
                     54:        "2621",         tclrhp,  80,    NMG,    /*  hp2621a and p */
                     55:        "hp",           tclrhp,  80,    NMG,    /*  hp default */
                     56:        "300",          TCLRLN, 132,    NMG,
                     57:        "300-12",       TCLRLN, 158,    NMG,
                     58:        "300s",         tclrgs, 132,    GMG,
                     59:        "300s-12",      tclrgs, 158,    GMG,
                     60:        "40-2",         tclr40,  80,    NMG,
                     61:        "4000a",        tclrsh, 132,    TRMG,
                     62:        "4000a-12",     tclrsh, 158,    TRMG,
                     63:        "43",           "",     0,      FMG,
                     64:        "450",          tclrsh, 132,    DMG,
                     65:        "450-12",       tclrsh, 158,    DMG,
                     66:        "450-12-8",     tclrsh, 158,    DMG,
                     67:        "tn1200",       tclrsh, 118,    TMG,
                     68:        "tn300",        tclrsh, 118,    TMG,
                     69:        "1520",         "",     0,      NMG,
                     70:        "3045",         "",     0,      NMG,
                     71:        0
                     72: };
                     73: 
                     74: 
                     75: int    maxtab;         /* max tab for repetitive spec */
                     76: int    margin; 
                     77: int    margflg;        /* >0 ==> +m option used, 0 ==> not */
                     78: char   *terminal = "";
                     79: char   *tabspec = "-8";        /* default tab specification */
                     80: 
                     81: struct sgttyb ttyold;  /* tty table */
                     82: int    ttysave;        /* save for modes */
                     83: int    istty;          /* 1 ==> is actual tty */
                     84: 
                     85: struct stat    statbuf;
                     86: char   *devtty;
                     87: 
                     88: int    endup();
                     89: char   *getenv();
                     90: struct ttab *termadj();
                     91: 
                     92: main(argc, argv)
                     93: char **argv;
                     94: {
                     95:        int tabvect[NTABS];     /* build tab list here */
                     96:        char *ttyname();
                     97:        char *scan;     /* scan pointer to next char */
                     98:        int endup();
                     99: 
                    100:        signal(SIGINT, endup);
                    101:        if (ioctl(1, TIOCGETP, &ttyold) == 0) {
                    102:                ttysave = ttyold.sg_flags;
                    103:                fstat(1, &statbuf);
                    104:                devtty = ttyname(1);
                    105:                if (devtty && *devtty)
                    106:                        chmod(devtty, 0000);    /* nobody, not even us */
                    107:                istty++;
                    108:        }
                    109:        tabvect[0] = 0; /* mark as not yet filled in */
                    110:        while (--argc > 0) {
                    111:                scan = *++argv;
                    112:                if (*scan == '+')
                    113:                        switch (*++scan) {
                    114:                        case 'm':
                    115:                                margflg++;
                    116:                                if (*++scan)
                    117:                                        margin = getnum(&scan);
                    118:                                else
                    119:                                        margin = 10;
                    120:                                break;
                    121:                        }
                    122:                else if (*scan == '-' && *(scan+1) == 'T')
                    123:                        terminal = scan+2;
                    124:                else
                    125:                        tabspec = scan;         /* save tab specification */
                    126:        }
                    127:        if (*terminal == '\0') {
                    128:                terminal = getenv("TERM");
                    129:                if (terminal == NULL)
                    130:                        terminal = "";
                    131:        }
                    132:        tt = termadj();
                    133:        maxtab = tt->tmaxtab;
                    134:        scantab(tabspec,tabvect,0);
                    135:        if (!tabvect[0])
                    136:                repetab("8",tabvect);
                    137:        settabs(tabvect);
                    138:        endup();
                    139:        exit(0);
                    140: }
                    141: 
                    142: /*     scantab: scan 1 tabspec & return tab list for it */
                    143: 
                    144: scantab(scan,tabvect,level)
                    145: char *scan;
                    146: int tabvect[NTABS], level;
                    147: {
                    148:        register char c;
                    149:        if (*scan == '-')
                    150:                if ((c = *++scan) == '-')
                    151:                        filetab(++scan,tabvect,level);
                    152:                else if (c >= '0' && c <= '9')
                    153:                        repetab(scan,tabvect);
                    154:                else if (stdtab(scan,tabvect))
                    155:                        error("unknown tab code");
                    156:                else;
                    157:        else
                    158:                arbitab(scan,tabvect);
                    159: }
                    160: 
                    161: /*     repetab: scan and set repetitve tabs, 1+n, 1+2*n, etc */
                    162: 
                    163: repetab(scan,tabvect)
                    164: char *scan;
                    165: int tabvect[NTABS];
                    166: {
                    167:        register incr, i, tabn;
                    168:        int limit;
                    169:        incr = getnum(&scan);
                    170:        tabn = 1;
                    171:        limit = (maxtab-1)/(incr?incr:1)-1; /* # last actual tab */
                    172:        if (limit>NTABS-2)
                    173:                limit = NTABS-2;
                    174:        for (i = 0; i<=limit; i++)
                    175:                tabvect[i] = tabn += incr;
                    176:        tabvect[i] = 0;
                    177: }
                    178: 
                    179: /*     arbitab: handle list of arbitrary tabs */
                    180: 
                    181: arbitab(scan,tabvect)
                    182: char *scan;
                    183: int tabvect[NTABS];
                    184: {
                    185:        register i, t, last;
                    186:        last = 0;
                    187:        for (i = 0; i<NTABS-1;) {
                    188:                if (*scan == '+') {
                    189:                        scan++;         /* +n ==> increment, not absolute */
                    190:                        if (t = getnum(&scan))
                    191:                                tabvect[i++] = last += t;
                    192:                        else error("illegal increment");
                    193:                }
                    194:                else {
                    195:                        if ((t = getnum(&scan)) > last)
                    196:                                tabvect[i++] = last = t;
                    197:                        else error("illegal tabs");
                    198:                }
                    199:                if (*scan++ != ',') break;
                    200:        }
                    201:        if (last > NCOLS)
                    202:                error("illegal tabs");
                    203:        tabvect[i] = 0;
                    204: }
                    205: 
                    206: /*     filetab: copy tabspec from existing file */
                    207: #define CARDSIZ        132
                    208: filetab(scan,tabvect,level)
                    209: char *scan;
                    210: int tabvect[NTABS];
                    211: {
                    212:        register length, i;
                    213:        register char c;
                    214:        int fildes;
                    215:        char card[CARDSIZ];     /* buffer area for 1st card in file */
                    216:        char state, found;
                    217:        char *temp;
                    218:        if (level)
                    219:                error("file indirection");
                    220:        if ((fildes = open(scan,0)) < 0)
                    221:                error("can't open");
                    222:        length = read(fildes,card,CARDSIZ);
                    223:        close(fildes);
                    224:        found = state = 0;
                    225:        scan = 0;
                    226:        for (i = 0; i<length && (c = card[i]) != '\n'; i++) {
                    227:                switch (state) {
                    228:                case 0:
                    229:                        state = (c == '<'); break;
                    230:                case 1:
                    231:                        state = (c == ':')?2:0; break;
                    232:                case 2:
                    233:                        if (c == 't')
                    234:                                state = 3;
                    235:                        else if (c == ':')
                    236:                                state = 6;
                    237:                        else if (c != ' ')
                    238:                                state = 5;
                    239:                        break;
                    240:                case 3:
                    241:                        if (c == ' ')
                    242:                                state = 2;
                    243:                        else {
                    244:                                scan = &card[i];
                    245:                                state = 4;
                    246:                        }
                    247:                        break;
                    248:                case 4:
                    249:                        if (c == ' ') {
                    250:                                card[i] = '\0';
                    251:                                state = 5;
                    252:                        }
                    253:                        else if (c == ':') {
                    254:                                card[i] = '\0';
                    255:                                state = 6;
                    256:                        }
                    257:                        break;
                    258:                case 5:
                    259:                        if (c == ' ')
                    260:                                state = 2;
                    261:                        else if (c == ':')
                    262:                                state = 6;
                    263:                        break;
                    264:                case 6:
                    265:                        if (c == '>') {
                    266:                                found = 1;
                    267:                                goto done;
                    268:                        }
                    269:                        else state = 5;
                    270:                        break;
                    271:                }
                    272:        }
                    273: done:
                    274:        if (found && scan != 0) {
                    275:                scantab(scan,tabvect,1);
                    276:                temp = scan;
                    277:                while (*++temp);
                    278:                *temp = '\n';
                    279:        }
                    280:        else scantab("-8",tabvect,1);
                    281: }
                    282: 
                    283: struct ttab *
                    284: termadj()
                    285: {
                    286:        register struct ttab *t;
                    287: 
                    288:        for (t = termtab; t->ttype; t++) {
                    289:                if (EQ(terminal, t->ttype))
                    290:                        return(t);
                    291:        }
                    292: /* should have message */
                    293:        return(termtab);
                    294: }
                    295: 
                    296: char   *cleartabs();
                    297: /*     settabs: set actual tabs at terminal */
                    298: /*     note: this code caters to necessities of handling GSI and
                    299:        other terminals in a consistent way. */
                    300: 
                    301: settabs(tabvect)
                    302: int tabvect[NTABS];
                    303: {
                    304:        char setbuf[400];       /* 2+3*NTABS+2+NCOLS+NTABS (+ some extra) */
                    305:        register char *p;               /* ptr for assembly in setbuf */
                    306:        register *curtab;               /* ptr to tabvect item */
                    307:        int i, previous, nblanks;
                    308:        if (istty) {
                    309:                ttyold.sg_flags &= ~(CRMOD);
                    310:                ioctl(1, TIOCSETN, &ttyold);    /* turn off cr-lf map */
                    311:        }
                    312:        p = setbuf;
                    313:        *p++ = CR;
                    314:        p = cleartabs(p, tt->tclr);
                    315: 
                    316:        if (margflg)
                    317:                switch(tt->tmarg) {
                    318:                case GMG:       /* GSI300S */
                    319:                /* NOTE: the 300S appears somewhat odd, in that there is
                    320:                a column 0, but there is no way to do a direct tab to it.
                    321:                The sequence ESC 'T' '\0' jumps to column 27 and prints
                    322:                a '0', without changing the margin. */
                    323:                        *p++ = ESC;
                    324:                        *p++ = 'T';     /* setup for direct tab */
                    325:                        if (margin &= 0177)     /* normal case */
                    326:                                *p++ = margin;
                    327:                        else {                  /* +m0 case */
                    328:                                *p++ = 1;       /* column 1 */
                    329:                                *p++ = '\b';    /* column 0 */
                    330:                        }
                    331:                        *p++ = margin;  /* direct horizontal tab */
                    332:                        *p++ = ESC;
                    333:                        *p++ = '0';     /* actual margin set */
                    334:                        break;
                    335:                case TMG:       /* TERMINET 300 & 1200 */
                    336:                        while (margin--)
                    337:                                *p++ = ' ';
                    338:                        break;
                    339:                case DMG:       /* DASI450/DIABLO 1620 */
                    340:                        *p++ = ESC;     /* direct tab ignores margin */
                    341:                        *p++ = '\t';
                    342:                        if (margin == 3){
                    343:                                *p++ = (margin & 0177);
                    344:                                *p++ = ' ';
                    345:                        }
                    346:                        else
                    347:                                *p++ = (margin & 0177) + 1;
                    348:                        *p++ = ESC;
                    349:                        *p++ = '9';
                    350:                        break;
                    351:                case FMG:       /* TTY 43 */
                    352:                        p--;
                    353:                        *p++ = ESC;
                    354:                        *p++ = 'x';
                    355:                        *p++ = CR;
                    356:                        while (margin--)
                    357:                                *p++ = ' ';
                    358:                        *p++ = ESC;
                    359:                        *p++ = 'l';
                    360:                        *p++ = CR;
                    361:                        write(1, setbuf, p - setbuf);
                    362:                        return;
                    363:                case TRMG:
                    364:                        p--;
                    365:                        *p++ = ESC;
                    366:                        *p++ = 'N';
                    367:                        while (margin--)
                    368:                                *p++ = ' ';
                    369:                        *p++ = ESC;
                    370:                        *p++ = 'F';
                    371:                        break;
                    372:                }
                    373: 
                    374: /*
                    375:  *     actual setting: at least terminals do this consistently!
                    376:  */
                    377:        previous = 1; curtab = tabvect;
                    378:        while ((nblanks = *curtab-previous) >= 0 &&
                    379:                previous + nblanks <= maxtab) {
                    380:                for (i = 1; i <= nblanks; i++) *p++ = ' ';
                    381:                previous = *curtab++;
                    382:                *p++ =ESC;
                    383:                *p++ = SET;
                    384:        }
                    385:        *p++ = CR;
                    386:        if (tt->tclr && EQ(tt->tclr, tclr40))
                    387:                *p++ = '\n';    /* TTY40/2 needs LF, not just CR */
                    388:        write(1, setbuf, p - setbuf);
                    389: }
                    390: 
                    391: /*     cleartabs(pointer to buffer, pointer to clear sequence */
                    392: char *cleartabs(p, qq)
                    393: register char *p;
                    394: char *qq;
                    395: {
                    396:        register i;
                    397:        register char *q;
                    398:        q = qq;
                    399:         if (q == TCLRLN) {      /* if repetitive sequence */
                    400:                *p++ = CR;
                    401:                for(i = 0; i < NTABSCL - 1; i++) {
                    402:                        *p++ = TAB;
                    403:                        *p++ = ESC;
                    404:                        *p++ = CLEAR;
                    405:                }
                    406:                *p++ = CR;
                    407:        }
                    408:        else {
                    409:                while(*p++ = *q++);     /* copy table sequence */
                    410:                p--;                    /* adjust for null */
                    411:                if (qq == tclr40) {     /* TTY40 extra delays needed */
                    412:                        *p++ = '\0';
                    413:                        *p++ = '\0';
                    414:                        *p++ = '\0';
                    415:                        *p++ = '\0';
                    416:                }
                    417:        }
                    418:        return(p);
                    419: }
                    420: /*     getnum: scan and convert number, return zero if none found */
                    421: /*     set scan ptr to addr of ending delimeter */
                    422: getnum(scan1)
                    423: char **scan1;
                    424: {
                    425:        register n;
                    426:        register char c, *scan;
                    427:        n = 0;
                    428:        scan = *scan1;
                    429:        while ((c = *scan++) >= '0' && c <= '9') n = n * 10 + c -'0';
                    430:        *scan1 = --scan;
                    431:        return(n);
                    432: }
                    433: 
                    434: /*     error: terminate processing with message to terminal */
                    435: error(arg)
                    436: char *arg;
                    437: {
                    438:        register char *temp;
                    439:        temp = arg;
                    440:        while (*++temp);        /* get length */
                    441:        *temp = '\n';
                    442:        endup();
                    443:        write(2, arg, temp+1-arg);
                    444:        exit(1);
                    445: }
                    446: 
                    447: /*     endup: make sure tty mode reset & exit */
                    448: endup()
                    449: {
                    450:        if (istty) {
                    451:                ttyold.sg_flags = ttysave;
                    452:                ioctl(1, TIOCSETN, &ttyold);    /* reset cr-lf to previous */
                    453:                if (devtty && *devtty)
                    454:                        chmod(devtty, statbuf.st_mode & 0777);
                    455:        }
                    456: }
                    457: 
                    458: /*     stdtabs: standard tabs table
                    459:        format: option code letter(s), null, tabs, null */
                    460: char stdtabs[] = {
                    461: 'a',   0,1,10,16,36,72,0,                      /* IBM 370 Assembler */
                    462: 'a','2',0,1,10,16,40,72,0,                     /* IBM Assembler alternative*/
                    463: 'c',   0,1,8,12,16,20,55,0,                    /* COBOL, normal */
                    464: 'c','2',0,1,6,10,14,49,0,                      /* COBOL, crunched*/
                    465: 'c','3',0,1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67,0,
                    466:                                                /* crunched COBOL, many tabs */
                    467: 'f',   0,1,7,11,15,19,23,0,                    /* FORTRAN */
                    468: 'p',   0,1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,0, /* PL/I */
                    469: 's',   0,1,10,55,0,                            /* SNOBOL */
                    470: 'u',   0,1,12,20,44,0,                         /* UNIVAC ASM */
                    471: 0};
                    472: 
                    473: /*     stdtab: return tab list for any "canned" tab option.
                    474:        entry: option points to null-terminated option string
                    475:                tabvect points to vector to be filled in
                    476:        exit: return(0) if legal, tabvect filled, ending with zero
                    477:                return(-1) if unknown option
                    478: */
                    479: stdtab(option,tabvect)
                    480: char option[];
                    481: int tabvect[];
                    482: {
                    483:        register char *sp;
                    484:        tabvect[0] = 0;
                    485:        sp = stdtabs;
                    486:        while (*sp) {
                    487:                if (EQ(option,sp)) {
                    488:                        while (*sp++);          /* skip to 1st tab value */
                    489:                        while (*tabvect++ = *sp++);     /* copy, make int */
                    490:                        return(0);
                    491:                }
                    492:                while(*sp++);   /* skip to 1st tab value */
                    493:                while(*sp++);           /* skip over tab list */
                    494:        }
                    495:        return(-1);
                    496: }

unix.superglobalmegacorp.com

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