Annotation of coherent/d/bin/col.c, revision 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.