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

1.1       root        1: /*
                      2:  * Col(1). Virtual typewriter, performs motions physical typewriters cannot,
                      3:  * like reverse line feeds. Also filters control characters.
                      4:  * Two global variables, LineNo and ColNo, have the current line and column
                      5:  * numbers. Both start at zero.
                      6:  */
                      7: #include <stdio.h>
                      8: 
                      9: #define        Unfetch(c)      Unfetched = (c)
                     10: 
                     11: #define        PAGESIZE        256     /* Default Page size. */
                     12: #define        IBUFSIZE        800     /* Number of possible columns. */
                     13: #define        EBUFSIZ         4       /* Increment size for buf in EXTRA struct. */
                     14: 
                     15: /*
                     16:  * Fetch returns the control characters \n, \b, \t, \r, HVT, VT, HLF, LF.
                     17:  * We choose HVT and HLF to make a switch statement more compact in Main().
                     18:  */
                     19: #define        OSTRK           037     /* Flag for overstruck chars. */
                     20: #define        ESC             033     /* Escape character. */
                     21: #define        SO              017     /* Shift out to alternate char set. */
                     22: #define        SI              016     /* Shift in from alternate char set. */
                     23: #define        HVT             014     /* Half vertical tab. */
                     24: #define        VT              013     /* Vertical tab, or Rev. Line Feed. */
                     25: #define        HLF             007     /* Half line feed. */
                     26: #define        LF              006     /* Line feed (but not return!). */
                     27: #define        EOT             004     /* End of line signal to InsChar. */
                     28: #define        BOT             003     /* Start of line signal to InsChar. */
                     29: 
                     30: #define        not             !
                     31: #define        or              ||
                     32: #define        and             &&
                     33: #define        TRUE            (0==0)
                     34: #define        FALSE           (not TRUE)
                     35: #define        NOTREACHED      return
                     36: 
                     37: typedef        unsigned int    uint;
                     38: typedef        unsigned char   uchar;
                     39: typedef        uchar           bool;
                     40: 
                     41: typedef struct extra {
                     42:        struct extra    *Next;
                     43:        int             Posn;
                     44:        uchar           Howmany;
                     45:        char            Ebuf[EBUFSIZ];
                     46: } EXTRA;
                     47: 
                     48: typedef struct {
                     49:        int             Len;    /* Number of valid columns in Line. */
                     50:        char            *Line;
                     51:        struct extra    *Extra;
                     52: } LINE;
                     53: 
                     54: 
                     55: /*
                     56:  * Error Messages.
                     57:  */
                     58: char   Usage[] =       "Usage: col [-bdfx] [-pnum]";
                     59: char   BackScroll[] =  "Scrolling backwards over top of page window.";
                     60: char   Confused[] =    "Seem to have lost Overstruck characters.";
                     61: 
                     62: /*
                     63:  * Flags.
                     64:  */
                     65: bool   Bflag = FALSE;          /* Command line option 'b'. */
                     66: bool   Dflag = FALSE;          /* Command line option 'd'. */
                     67: bool   Fflag = FALSE;          /* Command line option 'f'. */
                     68: bool   Pflag = FALSE;          /* Command line option 'p'. */
                     69: bool   Xflag = FALSE;          /* Command line option 'x'. */
                     70: 
                     71: /*
                     72:  * External Variables.
                     73:  */
                     74: char   Ibuf[BUFSIZ];           /* Buffer for input lines. */
                     75: 
                     76: LINE   *Page;                  /* Page window. */
                     77: LINE   *CurLine;               /* Ptr to *(Page[LineNo % PageSize]). */
                     78: 
                     79: int    PageSize = PAGESIZE;    /* Actual size of Page. */
                     80: int    Ibuflen;                /* Current length of line in Ibuf. */
                     81: int    Unfetched;              /* storage for unfetched char */
                     82: int    Top;                    /* Line number of top of Page window. */
                     83: int    Bottom;                 /* Line number of bottom of Page window. */
                     84: int    Wmark;                  /* High-water-mark of Lineno. */
                     85: int    LineNo;                 /* Current line number in Page. */
                     86: int    ColNo;                  /* Current column number. */
                     87: 
                     88: 
                     89: /*
                     90:  * Functions returning non-int.
                     91:  */
                     92: bool   Ostrikeout();
                     93: char   *realloc();
                     94: 
                     95: 
                     96: main(ac, av)
                     97: int ac;
                     98: char *av[];
                     99: {
                    100:        register int c;
                    101: 
                    102:        Aarghh(ac, av);
                    103:        Init();
                    104:        InsChar(BOT);
                    105:        while ((c = Fetch()) != EOF)
                    106:                switch (c) {
                    107:                case '\b':
                    108:                        if (ColNo > 0)
                    109:                                --ColNo;
                    110:                        break;
                    111:                case '\r':
                    112:                        ColNo = 0;
                    113:                        break;
                    114:                case '\t':
                    115:                        ColNo = (ColNo & ~07) + 8;
                    116:                        break;
                    117:                case '\n':
                    118:                        ColNo = 0;
                    119:                case VT:
                    120:                case LF:
                    121:                case HVT:
                    122:                case HLF:
                    123:                        InsChar(EOT);           /* Close current line. */
                    124:                        VertMove(c);
                    125:                        InsChar(BOT);           /* Open current line. */
                    126:                        break;
                    127:                default:
                    128:                        if (c != ' ')
                    129:                                InsChar(c);
                    130:                        ++ColNo;
                    131:                        break;
                    132:                }
                    133:        InsChar(EOT);                           /* Close current line. */
                    134:        Flush();
                    135:        return (0);
                    136: }
                    137: 
                    138: 
                    139: /*
                    140:  * Process command line arguments.
                    141:  */
                    142: Aarghh(ac, av)
                    143: int ac;
                    144: register char *av[];
                    145: {
                    146:        register char *cp;
                    147:        register int c;
                    148: 
                    149:        ac = 0;         /* To avoid "Strict" warning from compiler. */
                    150:        while ((cp = *++av) != NULL) {
                    151:                if (*cp++ != '-') {
                    152:                        Fatal(Usage);
                    153:                        NOTREACHED;
                    154:                }
                    155:                while ((c = *cp++) != '\0')
                    156:                        switch (c) {
                    157:                        case 'b':
                    158:                                Bflag = TRUE;
                    159:                                break;
                    160:                        case 'd':
                    161:                                Dflag = TRUE;
                    162:                                break;
                    163:                        case 'f':
                    164:                                Fflag = TRUE;
                    165:                                break;
                    166:                        case 'x':
                    167:                                Xflag = TRUE;
                    168:                                break;
                    169:                        case 'p':
                    170:                                Pflag = TRUE;
                    171:                                if ((PageSize = 2 * atoi(cp)) <= 0)
                    172:                                        Fatal("Bad page length");
                    173:                                break;
                    174:                        default:
                    175:                                Fatal(Usage);
                    176:                                NOTREACHED;
                    177:                        }
                    178:        }
                    179: }
                    180: 
                    181: Init()
                    182: {
                    183:        register LINE *lp;
                    184: 
                    185:        lp = CurLine = Page = (LINE *) malloc(sizeof(LINE) * PageSize);
                    186:        lp += PageSize - 1;
                    187:        while (lp-- > Page) {
                    188:                lp->Len = 0;
                    189:                lp->Line = lp->Extra = NULL;
                    190:        }
                    191:        Bottom = PageSize;
                    192:        return;
                    193: }
                    194: 
                    195: 
                    196: /*
                    197:  * Fetch grabs input characters and returns them after filtering.
                    198:  */
                    199: Fetch()
                    200: {
                    201:        static acset = 0;       /* alternate character set flag */
                    202:        register int c, c1;
                    203: 
                    204:        if ((c = Unfetched) != '\0') {
                    205:                Unfetched = '\0';
                    206:                return (c);
                    207:        }
                    208:        for(;;) {
                    209:                if ((c = getchar()) > ' '  &&  c < 0177)
                    210:                        return (acset ? c | 0200 : c);
                    211:                switch (c) {
                    212:                case ' ':
                    213:                case '\t':
                    214:                case '\n':
                    215:                case '\b':
                    216:                case '\r':
                    217:                case VT:
                    218:                case EOF:
                    219:                        return (c);
                    220:                case SO:
                    221:                        acset = 1;
                    222:                        continue;
                    223:                case SI:
                    224:                        acset = 0;
                    225:                        continue;
                    226:                case ESC:
                    227:                        switch (c1 = getchar()) {
                    228:                        case '7':
                    229:                                return (VT);
                    230:                        case '8':
                    231:                                return (HVT);
                    232:                        case '9':
                    233:                                return (HLF);
                    234:                        case 'B':
                    235:                                return (LF);
                    236:                        }
                    237:                        ungetc(c1, stdin);
                    238:                        continue;
                    239:                }
                    240:        }
                    241: }
                    242: 
                    243: 
                    244: VertMove(c)
                    245: register int c;
                    246: {
                    247:        static bool warnflag = FALSE;   /* Warn of move over top of page. */
                    248: 
                    249:        Unfetch(c);
                    250:        for (;;) {
                    251:                switch (c = Fetch()) {
                    252:                case VT:
                    253:                        LineNo -= 2;
                    254:                        break;
                    255:                case LF:
                    256:                        LineNo += 2;
                    257:                        break;
                    258:                case HVT:
                    259:                        LineNo -= 1;
                    260:                        break;
                    261:                case HLF:
                    262:                        LineNo += 1;
                    263:                        break;
                    264:                case '\n':
                    265:                        ColNo = 0;
                    266:                        LineNo += 2;
                    267:                        break;
                    268:                default:
                    269:                        Unfetch(c);
                    270:                        CurLine = Page + LineNo % PageSize;
                    271:                        return;
                    272:                }
                    273: 
                    274:                /*
                    275:                 * Have we scrolled over the top of the Page window?
                    276:                 */
                    277:                if (LineNo < Top)
                    278:                        if (not warnflag) {
                    279:                                Warning(BackScroll);
                    280:                                warnflag = TRUE;
                    281:                        }
                    282: 
                    283:                /*
                    284:                 * Update the water mark if needed.
                    285:                 */
                    286:                if (LineNo > Wmark)
                    287:                        Wmark = LineNo;
                    288: 
                    289: 
                    290:                /*
                    291:                 * If we've scrolled past the bottom of the window then we
                    292:                 * put out the Top line and move the window down.
                    293:                 */
                    294:                if (Bottom <= LineNo) {
                    295:                        PutLine(Top);
                    296:                        Top += 2;
                    297:                        Bottom += 2;
                    298:                }
                    299:        }
                    300: }
                    301: 
                    302: /*
                    303:  * Insert the character c into Ibuf at column ColNo.
                    304:  */
                    305: InsChar(c)
                    306: register int c;
                    307: {
                    308: 
                    309:        /*
                    310:         * If (c == BOT) or (c == EOT) we open or close the line in Ibuf.
                    311:         * Otherwise we are really adding a character to Ibuf.
                    312:         */
                    313:        if (c == BOT) {
                    314:                register LINE *lp = CurLine;
                    315:                if ((Ibuflen = lp->Len) != 0) {
                    316:                        strncpy(Ibuf, lp->Line, Ibuflen);
                    317:                        free(lp->Line);
                    318:                }
                    319:                return;
                    320:        }
                    321:        else if (c == EOT) {
                    322:                register LINE *lp = CurLine;
                    323:                if ((lp->Len = Ibuflen) != 0) {
                    324:                        lp->Line = malloc(Ibuflen);
                    325:                        strncpy(lp->Line, Ibuf, Ibuflen);
                    326:                }
                    327:                return;
                    328:        }
                    329: 
                    330:        /*
                    331:         * The case of appending a char to the end of Ibuf. Very common.
                    332:         * Note that in this case Ibuf[ColNo] is virgin territory.
                    333:         */
                    334:        if (ColNo == Ibuflen) {
                    335:                Ibuf[Ibuflen++] = c;
                    336:                return;
                    337:        }
                    338: 
                    339:        /*
                    340:         * The case of adding a char beyond the end of Ibuf. We must pad the
                    341:         * intervening space with spaces.
                    342:         */
                    343:        if (ColNo > Ibuflen) {
                    344:                register char *ibuf = Ibuf;
                    345:                while (Ibuflen < ColNo)
                    346:                        ibuf[Ibuflen++] = ' ';
                    347:                ibuf[Ibuflen++] = c;
                    348:                return;
                    349:        }
                    350: 
                    351: 
                    352:        /*
                    353:         * The remaining case is adding a char into the interior of Ibuf. If
                    354:         * the present char is a space or if Bflag is set we just insert c,
                    355:         * otherwise we have to overstrike.
                    356:         */
                    357:        {       register char *cp = Ibuf + ColNo;
                    358:                register int c1;
                    359: 
                    360:                if (Bflag  or  (c1 = *cp) == ' ') {
                    361:                        *cp = c;
                    362:                        return;
                    363:                }
                    364:                if (c1 != OSTRK) {
                    365:                        Overstrike(c1);
                    366:                        *cp = OSTRK;
                    367:                }
                    368:                Overstrike(c);
                    369:        }
                    370:        return;
                    371: }
                    372: 
                    373: 
                    374: /*
                    375:  * Handle overstruck characters.
                    376:  */
                    377: Overstrike(c)
                    378: int c;
                    379: {
                    380:        register EXTRA *ep;
                    381:        register EXTRA **epp;
                    382: 
                    383:        /*
                    384:         * Find the right EXTRA struct in CurLine.
                    385:         */
                    386:        epp = &CurLine->Extra;
                    387:        for (ep = *epp; ep != NULL; epp = &ep->Next, ep = *epp) {
                    388:                if (ep->Posn != ColNo) 
                    389:                        continue;
                    390:                /*
                    391:                 * We found it, check for overflow and add the char c.
                    392:                 */
                    393:                if (ep->Howmany % EBUFSIZ == 0)
                    394:                        ep = *epp = (EXTRA *) realloc((char *)ep,
                    395:                                                sizeof(EXTRA) + ep->Howmany);
                    396:                ep->Ebuf[ep->Howmany++] = c;
                    397:                return;
                    398:        }
                    399: 
                    400:        /*
                    401:         * We didn't find it, so make it, and install the char c.
                    402:         */
                    403:        ep = (EXTRA *) malloc(sizeof(EXTRA));
                    404:        ep->Howmany = 1;
                    405:        ep->Posn = ColNo;
                    406:        ep->Ebuf[0] = c;
                    407:        ep->Next = CurLine->Extra;
                    408:        CurLine->Extra = ep;
                    409:        return;
                    410: }
                    411: 
                    412: 
                    413: Flush()
                    414: {
                    415:        register int i;
                    416: 
                    417:        for (i = Top; i <= Wmark; i += 2)
                    418:                PutLine(i);
                    419:        return;
                    420: }
                    421: 
                    422: 
                    423: /*
                    424:  * Output one full line, which is possibly two half lines. All control for
                    425:  * Dflag and Fflag takes place here.
                    426:  */
                    427: PutLine(n)
                    428: int n;
                    429: {
                    430:        static char HCR[] = {'\r', ESC, '9', '\0'};     /* Half Crg. Return */
                    431:        register LINE *lp;
                    432: 
                    433:        lp = Page + n % PageSize;
                    434:        if (lp->Len != 0)
                    435:                PutHalf(lp);
                    436:        ++lp;
                    437: 
                    438:        if (lp->Len == 0) {
                    439:                if (Dflag  and  not Fflag) {
                    440:                        putchar('\n');
                    441:                        putchar('\n');
                    442:                } else
                    443:                        putchar('\n');
                    444:        } else {
                    445:                if (Fflag) {
                    446:                        fputs(HCR, stdout);
                    447:                        PutHalf(lp);
                    448:                        fputs(HCR, stdout);
                    449:                } else {
                    450:                        putchar('\n');
                    451:                        PutHalf(lp);
                    452:                        putchar('\n');
                    453:                }
                    454:        }
                    455:        return;
                    456: }
                    457: 
                    458: /*
                    459:  * PutHalf() outputs the half-line lp with no vertical motion at the end.
                    460:  * Alternate character sets are handled here. Entabbing is handled by Tab.
                    461:  * Overstrikes are handled by Ostrikeout(), which also may have to handle
                    462:  * alternate character sets.
                    463:  */
                    464: PutHalf(lp)
                    465: register LINE *lp;
                    466: {
                    467:        register int    c;
                    468:        register int    colno;
                    469:        register bool   acset = FALSE;
                    470: 
                    471:        /*
                    472:         * Note that since lp->Len is the number of valid columns, the number
                    473:         * of the last valid column is (lp->Len - 1). That's why the test is
                    474:         * "<" instead of "<=".
                    475:         */
                    476:        for (colno = 0; colno < lp->Len; ++colno) 
                    477:                switch (c = lp->Line[colno]) {
                    478:                case OSTRK:
                    479:                        acset = Ostrikeout(lp, colno, acset);
                    480:                        break;
                    481:                case ' ':
                    482:                        if (Xflag) {
                    483:                                putchar(' ');
                    484:                                break;
                    485:                        }
                    486:                        /* Entab white space. */
                    487:                        c = colno;
                    488:                        while (lp->Line[c] == ' ')
                    489:                                if (++c % 8 == 0) {
                    490:                                        putchar('\t');
                    491:                                        colno = c;
                    492:                                }
                    493:                        while (colno < c) {
                    494:                                putchar(' ');
                    495:                                ++colno;
                    496:                        }
                    497:                        --colno;
                    498:                        break;
                    499:                default:
                    500:                        if (c & 0200) {
                    501:                                if (not acset) {
                    502:                                        acset = TRUE;
                    503:                                        putchar(SO);
                    504:                                }
                    505:                                putchar(c & ~0200);
                    506:                        }
                    507:                        else {
                    508:                                if (acset) {
                    509:                                        acset = FALSE;
                    510:                                        putchar(SI);
                    511:                                }
                    512:                                putchar(c);
                    513:                        }
                    514:                        break;
                    515:                }
                    516:        if (acset)
                    517:                putchar(SI);
                    518:        free(lp->Line);
                    519:        lp->Len = 0;
                    520:        lp->Line = lp->Extra = NULL;
                    521:        return;
                    522: }
                    523: 
                    524: 
                    525: /*
                    526:  * Ostrikeout puts out all the characters overstruck in position ColNo in the
                    527:  * LINE lp. It pays attention to alternate character sets.
                    528:  */
                    529: bool
                    530: Ostrikeout(lp, col, acset)
                    531: LINE *lp;
                    532: int col;
                    533: bool acset;
                    534: {
                    535:        EXTRA   *ep;
                    536: 
                    537:        /*
                    538:         * Find the EXTRA struct for position 'col' and remove it from
                    539:         * the EXTRA list.
                    540:         */
                    541:        {       register EXTRA **epp = &lp->Extra;
                    542:                register EXTRA *e;
                    543:                register int n = col;
                    544: 
                    545:                for (e = *epp; e != NULL; epp = &e->Next, e = *epp) {
                    546:                        if (e->Posn != n)
                    547:                                continue;
                    548:                        *epp = e->Next;
                    549:                        ep = e;
                    550:                        goto FOUNDIT;
                    551:                }
                    552:                /*
                    553:                 * Didn't find it in the list.
                    554:                 */
                    555:                putchar(' ');
                    556:                Warning(Confused);
                    557:                return (acset);
                    558:        }
                    559: 
                    560:        /*
                    561:         * Now that we found it, write out all the characters in ep->Ebuf,
                    562:         * paying attention to alternate char sets, then free ep.
                    563:         */
                    564:        FOUNDIT:
                    565:        {       register int c;
                    566:                register bool ac = acset;
                    567:                register int count = ep->Howmany;
                    568:                register char *cp = ep->Ebuf;
                    569: 
                    570:                while (count-- > 0) {
                    571:                        if ((c = *cp++) & 0200) {
                    572:                                if (not ac) {
                    573:                                        ac = TRUE;
                    574:                                        putchar(SO);
                    575:                                }
                    576:                                putchar(c & ~0200);
                    577:                        }
                    578:                        else {
                    579:                                if (ac) {
                    580:                                        ac = FALSE;
                    581:                                        putchar(SI);
                    582:                                }
                    583:                                putchar(c);
                    584:                        }
                    585:                        if (count > 0)
                    586:                                putchar('\b');
                    587:                }
                    588:                free(ep);
                    589:                return (ac);
                    590:        }
                    591: }
                    592: 
                    593: 
                    594: Fatal(cp)
                    595: char *cp;
                    596: {
                    597:        Warning(cp);
                    598:        exit(1);
                    599: }
                    600: 
                    601: Warning(cp)
                    602: char *cp;
                    603: {
                    604:        fputs(cp, stderr);
                    605:        putc('\n', stderr);
                    606:        return;
                    607: }

unix.superglobalmegacorp.com

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