Annotation of coherent/g/usr/bin/vi/tio.c, revision 1.1

1.1     ! root        1: /* tio.c */
        !             2: 
        !             3: /* Author:
        !             4:  *     Steve Kirkendall
        !             5:  *     14407 SW Teal Blvd. #C
        !             6:  *     Beaverton, OR 97005
        !             7:  *     [email protected]
        !             8:  */
        !             9: 
        !            10: 
        !            11: /* This file contains terminal I/O functions */
        !            12: 
        !            13: #include "config.h"
        !            14: #include "vi.h"
        !            15: #include "ctype.h"
        !            16: 
        !            17: static int showmsg P_((void));
        !            18: 
        !            19: /* This function reads in a line from the terminal. */
        !            20: int vgets(prompt, buf, bsize)
        !            21:        int     prompt; /* the prompt character, or '\0' for none */
        !            22:        char    *buf;   /* buffer into which the string is read */
        !            23:        int     bsize;  /* size of the buffer */
        !            24: {
        !            25:        int     len;    /* how much we've read so far */
        !            26:        int     ch;     /* a character from the user */
        !            27:        int     quoted; /* is the next char quoted? */
        !            28:        int     tab;    /* column position of cursor */
        !            29:        char    widths[132];    /* widths of characters */
        !            30:        int     word;   /* index of first letter of word */
        !            31: #ifndef NO_DIGRAPH
        !            32:        int     erased; /* 0, or first char of a digraph */
        !            33: #endif
        !            34: 
        !            35:        /* show the prompt */
        !            36:        move(LINES - 1, 0);
        !            37:        tab = 0;
        !            38:        if (prompt)
        !            39:        {
        !            40:                addch(prompt);
        !            41:                tab = 1;
        !            42:        }
        !            43:        clrtoeol();
        !            44:        refresh();
        !            45: 
        !            46:        /* read in the line */
        !            47: #ifndef NO_DIGRAPH
        !            48:        erased =
        !            49: #endif
        !            50:        quoted = len = 0;
        !            51:        for (;;)
        !            52:        {
        !            53: #ifndef NO_ABBR
        !            54:                if (quoted || mode == MODE_EX)
        !            55:                {
        !            56:                        ch = getkey(0);
        !            57:                }
        !            58:                else
        !            59:                {
        !            60:                        /* maybe expand an abbreviation while getting key */
        !            61:                        for (word = len; --word >= 0 && isalnum(buf[word]); )
        !            62:                        {
        !            63:                        }
        !            64:                        word++;
        !            65:                        ch = getabkey(WHEN_EX, &buf[word], len - word);
        !            66:                }
        !            67: #else
        !            68:                ch = getkey(0);
        !            69: #endif
        !            70: #ifndef NO_EXTENSIONS
        !            71:                if (ch == ctrl('O'))
        !            72:                {
        !            73:                        ch = getkey(quoted ? 0 : WHEN_EX);
        !            74:                }
        !            75: #endif
        !            76: 
        !            77:                /* some special conversions */
        !            78:                if (ch == ctrl('D') && len == 0)
        !            79:                        ch = ctrl('[');
        !            80: #ifndef NO_DIGRAPH
        !            81:                if (*o_digraph && erased != 0 && ch != '\b')
        !            82:                {
        !            83:                        ch = digraph(erased, ch);
        !            84:                        erased = 0;
        !            85:                }
        !            86: #endif
        !            87: 
        !            88:                /* inhibit detection of special chars (except ^J) after a ^V */
        !            89:                if (quoted && ch != '\n')
        !            90:                {
        !            91:                        ch |= 256;
        !            92:                }
        !            93: 
        !            94:                /* process the character */
        !            95:                switch(ch)
        !            96:                {
        !            97:                  case ctrl('V'):
        !            98:                        qaddch('^');
        !            99:                        qaddch('\b');
        !           100:                        quoted = TRUE;
        !           101:                        break;
        !           102: 
        !           103:                  case ctrl('['):
        !           104:                        return -1;
        !           105: 
        !           106:                  case '\n':
        !           107: #if OSK
        !           108:                  case '\l':
        !           109: #else
        !           110:                  case '\r':
        !           111: #endif
        !           112:                        clrtoeol();
        !           113:                        goto BreakBreak;
        !           114: 
        !           115:                  case '\b':
        !           116:                        if (len > 0)
        !           117:                        {
        !           118:                                len--;
        !           119: #ifndef NO_DIGRAPH
        !           120:                                erased = buf[len];
        !           121: #endif
        !           122:                                for (ch = widths[len]; ch > 0; ch--)
        !           123:                                        addch('\b');
        !           124:                                if (mode == MODE_EX)
        !           125:                                {
        !           126:                                        clrtoeol();
        !           127:                                }
        !           128:                                tab -= widths[len];
        !           129:                        }
        !           130:                        else
        !           131:                        {
        !           132:                                return -1;
        !           133:                        }
        !           134:                        break;
        !           135: 
        !           136:                  default:
        !           137:                        /* strip off quotation bit */
        !           138:                        if (ch & 256)
        !           139:                        {
        !           140:                                ch &= ~256;
        !           141:                                qaddch(' ');
        !           142:                                qaddch('\b');
        !           143:                        }
        !           144: 
        !           145:                        /* add & echo the char */
        !           146:                        if (len < bsize - 1)
        !           147:                        {
        !           148:                                if (ch == '\t' && !quoted)
        !           149:                                {
        !           150:                                        widths[len] = *o_tabstop - (tab % *o_tabstop);
        !           151:                                        addstr("        " + 8 - widths[len]);
        !           152:                                        tab += widths[len];
        !           153:                                }
        !           154:                                else if (ch > 0 && ch < ' ') /* > 0 by GB */
        !           155:                                {
        !           156:                                        addch('^');
        !           157:                                        addch(ch + '@');
        !           158:                                        widths[len] = 2;
        !           159:                                        tab += 2;
        !           160:                                }
        !           161:                                else if (ch == '\177')
        !           162:                                {
        !           163:                                        addch('^');
        !           164:                                        addch('?');
        !           165:                                        widths[len] = 2;
        !           166:                                        tab += 2;
        !           167:                                }
        !           168:                                else
        !           169:                                {
        !           170:                                        addch(ch);
        !           171:                                        widths[len] = 1;
        !           172:                                        tab++;
        !           173:                                }
        !           174:                                buf[len++] = ch;
        !           175:                        }
        !           176:                        else
        !           177:                        {
        !           178:                                beep();
        !           179:                        }
        !           180:                        quoted = FALSE;
        !           181:                }
        !           182:        }
        !           183: BreakBreak:
        !           184:        refresh();
        !           185:        buf[len] = '\0';
        !           186:        return len;
        !           187: }
        !           188: 
        !           189: 
        !           190: static int     manymsgs; /* This variable keeps msgs from overwriting each other */
        !           191: static char    pmsg[80]; /* previous message (waiting to be displayed) */
        !           192: 
        !           193: 
        !           194: static int showmsg()
        !           195: {
        !           196:        /* if there is no message to show, then don't */
        !           197:        if (!manymsgs)
        !           198:                return FALSE;
        !           199: 
        !           200:        /* display the message */
        !           201:        move(LINES - 1, 0);
        !           202:        if (*pmsg)
        !           203:        {
        !           204:                standout();
        !           205:                qaddch(' ');
        !           206:                qaddstr(pmsg);
        !           207:                qaddch(' ');
        !           208:                standend();
        !           209:        }
        !           210:        clrtoeol();
        !           211: 
        !           212:        manymsgs = FALSE;
        !           213:        return TRUE;
        !           214: }
        !           215: 
        !           216: 
        !           217: void endmsgs()
        !           218: {
        !           219:        if (manymsgs)
        !           220:        {
        !           221:                showmsg();
        !           222:                addch('\n');
        !           223:        }
        !           224: }
        !           225: 
        !           226: /* Write a message in an appropriate way.  This should really be a varargs
        !           227:  * function, but there is no such thing as vwprintw.  Hack!!!
        !           228:  *
        !           229:  * In MODE_EX or MODE_COLON, the message is written immediately, with a
        !           230:  * newline at the end.
        !           231:  *
        !           232:  * In MODE_VI, the message is stored in a character buffer.  It is not
        !           233:  * displayed until getkey() is called.  msg() will call getkey() itself,
        !           234:  * if necessary, to prevent messages from being lost.
        !           235:  *
        !           236:  * msg("")             - clears the message line
        !           237:  * msg("%s %d", ...)   - does a printf onto the message line
        !           238:  */
        !           239: #ifdef __STDC__
        !           240: void msg (char *fmt, ...)
        !           241: {
        !           242:        va_list ap;
        !           243:        va_start (ap, fmt);
        !           244: #else
        !           245: void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
        !           246:        char    *fmt;
        !           247:        long    arg1, arg2, arg3, arg4, arg5, arg6, arg7;
        !           248: {
        !           249: #endif
        !           250:        if (mode != MODE_VI)
        !           251:        {
        !           252: #ifdef __STDC__
        !           253:                vsprintf (pmsg, fmt, ap);
        !           254: #else
        !           255:                sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        !           256: #endif
        !           257:                qaddstr(pmsg);
        !           258:                addch('\n');
        !           259:                exrefresh();
        !           260:        }
        !           261:        else
        !           262:        {
        !           263:                /* wait for keypress between consecutive msgs */
        !           264:                if (manymsgs)
        !           265:                {
        !           266:                        getkey(WHEN_MSG);
        !           267:                }
        !           268: 
        !           269:                /* real message */
        !           270: #ifdef __STDC__
        !           271:                vsprintf (pmsg, fmt, ap);
        !           272: #else
        !           273:                sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
        !           274: #endif
        !           275:                if (*fmt)
        !           276:                {
        !           277:                        manymsgs = TRUE;
        !           278:                }
        !           279:        }
        !           280: #ifdef __STDC__
        !           281:        va_end (ap);
        !           282: #endif
        !           283: }
        !           284: 
        !           285: 
        !           286: /* This function calls refresh() if the option exrefresh is set */
        !           287: void exrefresh()
        !           288: {
        !           289:        char    *scan;
        !           290: 
        !           291:        /* If this ex command wrote ANYTHING set exwrote so vi's  :  command
        !           292:         * can tell that it must wait for a user keystroke before redrawing.
        !           293:         */
        !           294:        for (scan=kbuf; scan<stdscr; scan++)
        !           295:                if (*scan == '\n')
        !           296:                        exwrote = TRUE;
        !           297: 
        !           298:        /* now we do the refresh thing */
        !           299:        if (*o_exrefresh)
        !           300:        {
        !           301:                refresh();
        !           302:        }
        !           303:        else
        !           304:        {
        !           305:                wqrefresh();
        !           306:        }
        !           307:        if (mode != MODE_VI)
        !           308:        {
        !           309:                manymsgs = FALSE;
        !           310:        }
        !           311: }
        !           312: 
        !           313: 
        !           314: /* This structure is used to store maps and abbreviations.  The distinction
        !           315:  * between them is that maps are stored in the list referenced by the "maps"
        !           316:  * pointer, while abbreviations are referenced by the "abbrs" pointer.
        !           317:  */
        !           318: typedef struct _map
        !           319: {
        !           320:        struct _map     *next;  /* another abbreviation */
        !           321:        short           len;    /* length of the "rawin" characters */
        !           322:        short           flags;  /* various flags */
        !           323:        char            *label; /* label of the map/abbr, or NULL */
        !           324:        char            *rawin; /* the "rawin" characters */
        !           325:        char            *cooked;/* the "cooked" characters */
        !           326: } MAP;
        !           327: 
        !           328: static char    keybuf[KEYBUFSIZE];
        !           329: static int     cend;   /* end of input characters */
        !           330: static int     user;   /* from user through end are chars typed by user */
        !           331: static int     next;   /* index of the next character to be returned */
        !           332: static MAP     *match; /* the matching map, found by countmatch() */
        !           333: static MAP     *maps;  /* the map table */
        !           334: #ifndef NO_ABBR
        !           335: static MAP     *abbrs; /* the abbreviation table */
        !           336: #endif
        !           337: 
        !           338: 
        !           339: 
        !           340: /* ring the terminal's bell */
        !           341: void beep()
        !           342: {
        !           343:        /* do a visible/audible bell */
        !           344:        if (*o_flash)
        !           345:        {
        !           346:                do_VB();
        !           347:                refresh();
        !           348:        }
        !           349:        else if (*o_errorbells)
        !           350:        {
        !           351:                tputs("\007", 1, faddch);
        !           352:        }
        !           353: 
        !           354:        /* discard any buffered input, and abort macros */
        !           355:        next = user = cend;
        !           356: }
        !           357: 
        !           358: 
        !           359: 
        !           360: /* This function replaces a "rawin" character sequence with the "cooked" version,
        !           361:  * by modifying the internal type-ahead buffer.
        !           362:  */
        !           363: 
        !           364: void execmap(rawlen, cookedstr, visual)
        !           365:        int     rawlen;         /* length of rawin text -- string to delete */
        !           366:        char    *cookedstr;     /* the cooked text -- string to insert */
        !           367:        int     visual;         /* boolean -- chars to be executed in visual mode? */
        !           368: {
        !           369:        int     cookedlen;
        !           370:        char    *src, *dst;
        !           371:        int     i;
        !           372: 
        !           373:        /* find the length of the cooked string */
        !           374:        cookedlen = strlen(cookedstr);
        !           375: #ifndef NO_EXTENSIONS
        !           376:        if (visual)
        !           377:        {
        !           378:                cookedlen *= 2;
        !           379:        }
        !           380: #endif
        !           381: 
        !           382:        /* if too big to fit in type-ahead buffer, then don't do it */
        !           383:        if (cookedlen + (cend - next) - rawlen > KEYBUFSIZE)
        !           384:        {
        !           385:                return;
        !           386:        }
        !           387: 
        !           388:        /* shift to make room for cookedstr at the front of keybuf */
        !           389:        src = &keybuf[next + rawlen];
        !           390:        dst = &keybuf[cookedlen];
        !           391:        i = cend - (next + rawlen);
        !           392:        if (src >= dst)
        !           393:        {
        !           394:                while (i-- > 0)
        !           395:                {
        !           396:                        *dst++ = *src++;
        !           397:                }
        !           398:        }
        !           399:        else
        !           400:        {
        !           401:                src += i;
        !           402:                dst += i;
        !           403:                while (i-- > 0)
        !           404:                {
        !           405:                        *--dst = *--src;
        !           406:                }
        !           407:        }
        !           408: 
        !           409:        /* insert cookedstr, and adjust offsets */
        !           410:        cend += cookedlen - rawlen - next;
        !           411:        user += cookedlen - rawlen - next;
        !           412:        next = 0;
        !           413:        for (dst = keybuf, src = cookedstr; *src; )
        !           414:        {
        !           415: #ifndef NO_EXTENSIONS
        !           416:                if (visual)
        !           417:                {
        !           418:                        *dst++ = ctrl('O');
        !           419:                        cookedlen--;
        !           420:                }
        !           421: #endif
        !           422:                *dst++ = *src++;
        !           423:        }
        !           424: 
        !           425: #ifdef DEBUG2
        !           426:        {
        !           427: #include <stdio.h>
        !           428:                FILE    *debout;
        !           429:                int             i;
        !           430: 
        !           431:                debout = fopen("debug.out", "a");
        !           432:                fprintf(debout, "After execmap(%d, \"%s\", %d)...\n", rawlen, cookedstr, visual);
        !           433:                for (i = 0; i < cend; i++)
        !           434:                {
        !           435:                        if (i == next) fprintf(debout, "(next)");
        !           436:                        if (i == user) fprintf(debout, "(user)");
        !           437:                        if (UCHAR(keybuf[i]) < ' ')
        !           438:                                fprintf(debout, "^%c", keybuf[i] ^ '@');
        !           439:                        else
        !           440:                                fprintf(debout, "%c", keybuf[i]);
        !           441:                }
        !           442:                fprintf(debout, "(end)\n");
        !           443:                fclose(debout);
        !           444:        }
        !           445: #endif
        !           446: }
        !           447: 
        !           448: /* This function calls ttyread().  If necessary, it will also redraw the screen,
        !           449:  * change the cursor shape, display the mode, and update the ruler.  If the
        !           450:  * number of characters read is 0, and we didn't time-out, then it exits because
        !           451:  * we've apparently reached the end of an EX script.
        !           452:  */
        !           453: static int fillkeybuf(when, timeout)
        !           454:        int     when;   /* mixture of WHEN_XXX flags */
        !           455:        int     timeout;/* timeout in 1/10 second increments, or 0 */
        !           456: {
        !           457:        int     nkeys;
        !           458: #ifndef NO_SHOWMODE
        !           459:        static int      oldwhen;        /* "when" from last time */
        !           460:        static int      oldleft;
        !           461:        static long     oldtop;
        !           462:        static long     oldnlines;
        !           463:        char            *str;
        !           464: #endif
        !           465: #ifndef NO_CURSORSHAPE
        !           466:        static int      oldcurs;
        !           467: #endif
        !           468: 
        !           469: #ifdef DEBUG
        !           470:        watch();
        !           471: #endif
        !           472: 
        !           473: 
        !           474: #ifndef NO_CURSORSHAPE
        !           475:        /* make sure the cursor is the right shape */
        !           476:        if (has_CQ)
        !           477:        {
        !           478:                if (when != oldcurs)
        !           479:                {
        !           480:                        switch (when)
        !           481:                        {
        !           482:                          case WHEN_EX:         do_CX();        break;
        !           483:                          case WHEN_VICMD:      do_CV();        break;
        !           484:                          case WHEN_VIINP:      do_CI();        break;
        !           485:                          case WHEN_VIREP:      do_CR();        break;
        !           486:                        }
        !           487:                        oldcurs = when;
        !           488:                }
        !           489:        }
        !           490: #endif
        !           491: 
        !           492: #ifndef NO_SHOWMODE
        !           493:        /* if "showmode" then say which mode we're in */
        !           494:        if (*o_smd && (when & WHENMASK))
        !           495:        {
        !           496:                /* redraw the screen before we check to see whether the
        !           497:                 * "showmode" message needs to be redrawn.
        !           498:                 */
        !           499:                redraw(cursor, !(when & WHEN_VICMD));
        !           500: 
        !           501:                /* now the "topline" test should be valid */
        !           502:                if (when != oldwhen || topline != oldtop || leftcol != oldleft || nlines != oldnlines)
        !           503:                {
        !           504:                        oldwhen = when;
        !           505:                        oldtop = topline;
        !           506:                        oldleft = leftcol;
        !           507:                        oldnlines = nlines;
        !           508: 
        !           509:                        if (when & WHEN_VICMD)      str = "Command";
        !           510:                        else if (when & WHEN_VIINP) str = " Input ";
        !           511:                        else if (when & WHEN_VIREP) str = "Replace";
        !           512:                        else if (when & WHEN_REP1)  str = " Rep 1 ";
        !           513:                        else if (when & WHEN_CUT)   str = "BufName";
        !           514:                        else if (when & WHEN_MARK)  str = "Mark AZ";
        !           515:                        else if (when & WHEN_CHAR)  str = "Dest Ch";
        !           516:                        else                        str = (char *)0;
        !           517: 
        !           518:                        if (str)
        !           519:                        {
        !           520:                                move(LINES - 1, COLS - 10);
        !           521:                                standout();
        !           522:                                qaddstr(str);
        !           523:                                standend();
        !           524:                        }
        !           525:                }
        !           526:        }
        !           527: #endif
        !           528: 
        !           529: #ifndef NO_EXTENSIONS
        !           530:        /* maybe display the ruler */
        !           531:        if (*o_ruler && (when & (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)))
        !           532:        {
        !           533:                char    buf[20];
        !           534: 
        !           535:                redraw(cursor, !(when & WHEN_VICMD));
        !           536:                pfetch(markline(cursor));
        !           537:                sprintf(buf, "%7ld,%-4d", markline(cursor), 1 + idx2col(cursor, ptext, when & (WHEN_VIINP|WHEN_VIREP)));
        !           538:                move(LINES - 1, COLS - 22);
        !           539:                addstr(buf);
        !           540:        }
        !           541: #endif
        !           542: 
        !           543:        /* redraw, so the cursor is in the right place */
        !           544:        if (when & WHENMASK)
        !           545:        {
        !           546:                redraw(cursor, !(when & (WHENMASK & ~(WHEN_VIREP|WHEN_VIINP))));
        !           547:        }
        !           548: 
        !           549:        /* Okay, now we can finally read the rawin keystrokes */
        !           550:        refresh();
        !           551:        nkeys = ttyread(keybuf + cend, sizeof keybuf - cend, timeout);
        !           552: 
        !           553:        /* if nkeys == 0 then we've reached EOF of an ex script. */
        !           554:        if (nkeys == 0 && timeout == 0)
        !           555:        {
        !           556:                tmpabort(TRUE);
        !           557:                move(LINES - 1, 0);
        !           558:                clrtoeol();
        !           559:                refresh();
        !           560:                endwin();
        !           561:                exit(exitcode);
        !           562:        }
        !           563: 
        !           564:        cend += nkeys;
        !           565:        user += nkeys;
        !           566:        return nkeys;
        !           567: }
        !           568: 
        !           569: 
        !           570: /* This function counts the number of maps that could match the characters
        !           571:  * between &keybuf[next] and &keybuf[cend], including incomplete matches.
        !           572:  * The longest comlete match is remembered via the "match" variable.
        !           573:  */
        !           574: static int countmatch(when)
        !           575:        int     when;   /* mixture of WHEN_XXX flags */
        !           576: {
        !           577:        MAP     *map;
        !           578:        int     count;
        !           579: 
        !           580:        /* clear the "match" variable */
        !           581:        match = (MAP *)0;
        !           582: 
        !           583:        /* check every map */
        !           584:        for (count = 0, map = maps; map; map = map->next)
        !           585:        {
        !           586:                /* can't match if wrong mode */
        !           587:                if ((map->flags & when) == 0)
        !           588:                {
        !           589:                        continue;
        !           590:                }
        !           591: 
        !           592:                /* would this be a complete match? */
        !           593:                if (map->len <= cend - next)
        !           594:                {
        !           595:                        /* Yes, it would be.  Now does it really match? */
        !           596:                        if (!strncmp(map->rawin, &keybuf[next], map->len))
        !           597:                        {
        !           598:                                count++;
        !           599: 
        !           600:                                /* if this is the longest complete match,
        !           601:                                 * then remember it.
        !           602:                                 */
        !           603:                                if (!match || match->len < map->len)
        !           604:                                {
        !           605:                                        match = map;
        !           606:                                }
        !           607:                        }
        !           608:                }
        !           609:                else
        !           610:                {
        !           611:                        /* No, it wouldn't.  But check for partial match */
        !           612:                        if (!strncmp(map->rawin, &keybuf[next], cend - next))
        !           613:                        {
        !           614:                                count++;
        !           615:                        }
        !           616:                }
        !           617:        }
        !           618:        return count;
        !           619: }
        !           620: 
        !           621: 
        !           622: #ifndef NO_ABBR
        !           623: /* This function checks to see whether a word is an abbreviation.  If it is,
        !           624:  * then an appropriate number of backspoace characters is inserted into the
        !           625:  * type-ahead buffer, followed by the expanded form of the abbreviation.
        !           626:  */
        !           627: static void expandabbr(word, wlen)
        !           628:        char    *word;
        !           629:        int     wlen;
        !           630: {
        !           631:        MAP     *abbr;
        !           632: 
        !           633:        /* if the next character wouldn't end the word, then don't expand */
        !           634:        if (isalnum(keybuf[next]) || keybuf[next] == ctrl('V'))
        !           635:        {
        !           636:                return;
        !           637:        }
        !           638: 
        !           639:        /* find the abbreviation, if any */
        !           640:        for (abbr = abbrs;
        !           641:             abbr && (abbr->len != wlen || strncmp(abbr->rawin, word, wlen));
        !           642:             abbr = abbr->next)
        !           643:        {
        !           644:        }
        !           645: 
        !           646:        /* If an abbreviation was found, then expand it by inserting the long
        !           647:         * version into the type-ahead buffer, and then inserting (in front of
        !           648:         * the long version) enough backspaces to erase to the short version.
        !           649:         */
        !           650:        if (abbr)
        !           651:        {
        !           652:                execmap(0, abbr->cooked, FALSE);
        !           653:                while (wlen > 15)
        !           654:                {
        !           655:                        execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", FALSE);
        !           656:                        wlen -= 15;
        !           657:                }
        !           658:                if (wlen > 0)
        !           659:                {
        !           660:                        execmap(0, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" + 15 - wlen, FALSE);
        !           661:                }
        !           662:        }
        !           663: }
        !           664: #endif
        !           665: 
        !           666: 
        !           667: /* This function calls getabkey() without attempting to expand abbreviations */
        !           668: int getkey(when)
        !           669:        int     when;   /* mixture of WHEN_XXX flags */
        !           670: {
        !           671:        return getabkey(when, "", 0);
        !           672: }
        !           673: 
        !           674: 
        !           675: /* This is it.  This function returns keystrokes one-at-a-time, after mapping
        !           676:  * and abbreviations have been taken into account.
        !           677:  */
        !           678: int getabkey(when, word, wlen)
        !           679:        int     when;   /* mixture of WHEN_XXX flags */
        !           680:        char    *word;  /* a word that may need to be expanded as an abbr */
        !           681:        int     wlen;   /* length of "word" -- since "word" might not have \0 */
        !           682: {
        !           683:        int     matches;
        !           684: 
        !           685:        /* if this key is needed for delay between multiple error messages,
        !           686:         * then reset the manymsgs flag and abort any mapped key sequence.
        !           687:         */
        !           688:        if (showmsg())
        !           689:        {
        !           690:                if (when == WHEN_MSG)
        !           691:                {
        !           692: #ifndef CRUNCH
        !           693:                        if (!*o_more)
        !           694:                        {
        !           695:                                refresh();
        !           696:                                return ' ';
        !           697:                        }
        !           698: #endif
        !           699:                        qaddstr("[More...]");
        !           700:                        refresh();
        !           701:                        execmap(user, "", FALSE);
        !           702:                }
        !           703:        }
        !           704: 
        !           705: #ifdef DEBUG
        !           706:        /* periodically check for screwed up internal tables */
        !           707:        watch();
        !           708: #endif
        !           709: 
        !           710:        /* if buffer empty, read some characters without timeout */
        !           711:        if (next >= cend)
        !           712:        {
        !           713:                next = user = cend = 0;
        !           714:                fillkeybuf(when, 0);
        !           715:        }
        !           716: 
        !           717:        /* try to map the key, unless already mapped and not ":set noremap" */
        !           718:        if (next >= user || *o_remap)
        !           719:        {
        !           720:                do
        !           721:                {
        !           722:                        do
        !           723:                        {
        !           724:                                matches = countmatch(when);
        !           725:                        } while (matches > 1 && fillkeybuf(when, *o_keytime) > 0);
        !           726:                        if (matches == 1)
        !           727:                        {
        !           728:                                if (match) {
        !           729:                                        execmap(match->len, match->cooked,
        !           730:                                          (match->flags & WHEN_INMV) != 0 
        !           731:                                          && (when & (WHEN_VIINP|WHEN_VIREP)) != 0);
        !           732:                                } else
        !           733:                                        matches = 0;
        !           734:                        }
        !           735:                } while (*o_remap && matches == 1);
        !           736:        }
        !           737: 
        !           738: #ifndef NO_ABBR
        !           739:        /* try to expand an abbreviation, except in visual command mode */
        !           740:        if (wlen > 0 && (mode & (WHEN_EX|WHEN_VIINP|WHEN_VIREP)) != 0)
        !           741:        {
        !           742:                expandabbr(word, wlen);
        !           743:        }
        !           744: #endif
        !           745: 
        !           746:        /* ERASEKEY should always be mapped to '\b'. */
        !           747:        if (keybuf[next] == ERASEKEY)
        !           748:        {
        !           749:                keybuf[next] = '\b';
        !           750:        }
        !           751: 
        !           752:        /* return the next key */
        !           753:        return keybuf[next++];
        !           754: }
        !           755: 
        !           756: /* This function maps or unmaps a key */
        !           757: void mapkey(rawin, cooked, when, name)
        !           758:        char    *rawin; /* the input key sequence, before mapping */
        !           759:        char    *cooked;/* after mapping -- or NULL to remove map */
        !           760:        int     when;   /* bitmap of when mapping should happen */
        !           761:        char    *name;  /* name of the key, NULL for no name, "abbr" for abbr */
        !           762: {
        !           763:        MAP     **head; /* head of list of maps or abbreviations */
        !           764:        MAP     *scan;  /* used for scanning through the list */
        !           765:        MAP     *prev;  /* used during deletions */
        !           766: 
        !           767:        /* Is this a map or an abbreviation?  Choose the right list. */
        !           768: #ifndef NO_ABBR
        !           769:        head = ((!name || strcmp(name, "abbr")) ? &maps : &abbrs);
        !           770: #else
        !           771:        head = &maps;
        !           772: #endif
        !           773: 
        !           774:        /* try to find the map in the list */
        !           775:        for (scan = *head, prev = (MAP *)0;
        !           776:             scan && (strcmp(rawin, scan->rawin) ||
        !           777:                !(scan->flags & when & (WHEN_EX|WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)));
        !           778:             prev = scan, scan = scan->next)
        !           779:        {
        !           780:        }
        !           781: 
        !           782:        /* trying to map? (not unmap) */
        !           783:        if (cooked && *cooked)
        !           784:        {
        !           785:                /* if map starts with "visual ", then mark it as a visual map */
        !           786:                if (head == &maps && !strncmp(cooked, "visual ", 7))
        !           787:                {
        !           788:                        cooked += 7;
        !           789:                        when |= WHEN_INMV;
        !           790:                }
        !           791: 
        !           792:                /* "visual" maps always work in input mode */
        !           793:                if (when & WHEN_INMV)
        !           794:                {
        !           795:                        when |= WHEN_VIINP|WHEN_VIREP|WHEN_POPUP;
        !           796:                }
        !           797: 
        !           798:                /* if not already in the list, then allocate a new structure */
        !           799:                if (!scan)
        !           800:                {
        !           801:                        scan = (MAP *)malloc(sizeof(MAP));
        !           802:                        scan->len = strlen(rawin);
        !           803:                        scan->rawin = malloc((unsigned)(scan->len + 1));
        !           804:                        strcpy(scan->rawin, rawin);
        !           805:                        scan->flags = when;
        !           806:                        scan->label = name;
        !           807:                        if (*head)
        !           808:                        {
        !           809:                                prev->next = scan;
        !           810:                        }
        !           811:                        else
        !           812:                        {
        !           813:                                *head = scan;
        !           814:                        }
        !           815:                        scan->next = (MAP *)0;
        !           816:                }
        !           817:                else /* recycle old structure */
        !           818:                {
        !           819:                        _free_(scan->cooked);
        !           820:                }
        !           821:                scan->cooked = malloc((unsigned)(strlen(cooked) + 1));
        !           822:                strcpy(scan->cooked, cooked);
        !           823:        }
        !           824:        else /* unmapping */
        !           825:        {
        !           826:                /* if nothing to unmap, then exit silently */
        !           827:                if (!scan)
        !           828:                {
        !           829:                        return;
        !           830:                }
        !           831: 
        !           832:                /* unlink the structure from the list */
        !           833:                if (prev)
        !           834:                {
        !           835:                        prev->next = scan->next;
        !           836:                }
        !           837:                else
        !           838:                {
        !           839:                        *head = scan->next;
        !           840:                }
        !           841: 
        !           842:                /* free it, and the strings that it refers to */
        !           843:                _free_(scan->rawin);
        !           844:                _free_(scan->cooked);
        !           845:                _free_(scan);
        !           846:        }
        !           847: }
        !           848: 
        !           849: 
        !           850: /* This function returns a printable version of a string.  It uses tmpblk.c */
        !           851: char *printable(str)
        !           852:        char    *str;   /* the string to convert */
        !           853: {
        !           854:        char    *build; /* used for building the string */
        !           855: 
        !           856:        for (build = tmpblk.c; *str; str++)
        !           857:        {
        !           858: #if AMIGA
        !           859:                if (*str == '\233')
        !           860:                {
        !           861:                        *build++ = '<';
        !           862:                        *build++ = 'C';
        !           863:                        *build++ = 'S';
        !           864:                        *build++ = 'I';
        !           865:                        *build++ = '>';
        !           866:                } else 
        !           867: #endif
        !           868:                if (UCHAR(*str) < ' ' || *str == '\177')
        !           869:                {
        !           870:                        *build++ = '^';
        !           871:                        *build++ = *str ^ '@';
        !           872:                }
        !           873:                else
        !           874:                {
        !           875:                        *build++ = *str;
        !           876:                }
        !           877:        }
        !           878:        *build = '\0';
        !           879:        return tmpblk.c;
        !           880: }
        !           881: 
        !           882: /* This function displays the contents of either the map table or the
        !           883:  * abbreviation table.  User commands call this function as follows:
        !           884:  *     :map    dumpkey(WHEN_VICMD, FALSE);
        !           885:  *     :map!   dumpkey(WHEN_VIREP|WHEN_VIINP, FALSE);
        !           886:  *     :abbr   dumpkey(WHEN_VIINP|WHEN_VIREP, TRUE);
        !           887:  *     :abbr!  dumpkey(WHEN_EX|WHEN_VIINP|WHEN_VIREP, TRUE);
        !           888:  */
        !           889: void dumpkey(when, abbr)
        !           890:        int     when;   /* WHEN_XXXX of mappings to be dumped */
        !           891:        int     abbr;   /* boolean: dump abbreviations instead of maps? */
        !           892: {
        !           893:        MAP     *scan;
        !           894:        char    *str;
        !           895:        int     len;
        !           896: 
        !           897: #ifndef NO_ABBR
        !           898:        for (scan = (abbr ? abbrs : maps); scan; scan = scan->next)
        !           899: #else
        !           900:        for (scan = maps; scan; scan = scan->next)
        !           901: #endif
        !           902:        {
        !           903:                /* skip entries that don't match "when" */
        !           904:                if ((scan->flags & when) == 0)
        !           905:                {
        !           906:                        continue;
        !           907:                }
        !           908: 
        !           909:                /* dump the key label, if any */
        !           910:                if (!abbr)
        !           911:                {
        !           912:                        len = 8;
        !           913:                        if (scan->label)
        !           914:                        {
        !           915:                                qaddstr(scan->label);
        !           916:                                len -= strlen(scan->label);
        !           917:                        }
        !           918:                        do
        !           919:                        {
        !           920:                                qaddch(' ');
        !           921:                        } while (len-- > 0);
        !           922:                }
        !           923: 
        !           924:                /* dump the rawin version */
        !           925:                str = printable(scan->rawin);
        !           926:                qaddstr(str);
        !           927:                len = strlen(str);
        !           928:                do
        !           929:                {
        !           930:                        qaddch(' ');
        !           931:                } while (len++ < 8);
        !           932:                        
        !           933:                /* dump the mapped version */
        !           934: #ifndef NO_EXTENSIONS
        !           935:                if ((scan->flags & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP)))
        !           936:                {
        !           937:                        qaddstr("visual ");
        !           938:                }
        !           939: #endif
        !           940:                str = printable(scan->cooked);
        !           941:                qaddstr(str);
        !           942:                addch('\n');
        !           943:                exrefresh();
        !           944:        }
        !           945: }
        !           946: 
        !           947: #ifndef NO_MKEXRC
        !           948: 
        !           949: static void safequote(str)
        !           950:        char    *str;
        !           951: {
        !           952:        char    *build;
        !           953: 
        !           954:        build = tmpblk.c + strlen(tmpblk.c);
        !           955:        while (*str)
        !           956:        {
        !           957:                if (*str <= ' ' && *str >= 1 || *str == '|')
        !           958:                {
        !           959:                        *build++ = ctrl('V');
        !           960:                }
        !           961:                *build++ = *str++;
        !           962:        }
        !           963:        *build = '\0';
        !           964: }
        !           965: 
        !           966: /* This function saves the contents of either the map table or the
        !           967:  * abbreviation table into a file.  Both the "bang" and "no bang" versions
        !           968:  * are saved.
        !           969:  *     :map    dumpkey(WHEN_VICMD, FALSE);
        !           970:  *     :map!   dumpkey(WHEN_VIREP|WHEN_VIINP, FALSE);
        !           971:  *     :abbr   dumpkey(WHEN_VIINP|WHEN_VIREP, TRUE);
        !           972:  *     :abbr!  dumpkey(WHEN_EX|WHEN_VIINP|WHEN_VIREP, TRUE);
        !           973:  */
        !           974: void
        !           975: savemaps(fd, abbr)
        !           976:        int     fd;     /* file descriptor of an open file to write to */
        !           977:        int     abbr;   /* boolean: do abbr table? (else do map table) */
        !           978: {
        !           979:        MAP     *scan;
        !           980:        int     bang;
        !           981:        int     when;
        !           982: 
        !           983: # ifndef NO_ABBR
        !           984:        for (scan = (abbr ? abbrs : maps); scan; scan = scan->next)
        !           985: # else
        !           986:        for (scan = maps; scan; scan = scan->next)
        !           987: # endif
        !           988:        {
        !           989:                /* skip maps that have labels, except for function keys */
        !           990:                if (scan->label && *scan->label != '#')
        !           991:                {
        !           992:                        continue;
        !           993:                }
        !           994: 
        !           995:                for (bang = 0; bang < 2; bang++)
        !           996:                {
        !           997:                        /* decide which "when" flags we want */
        !           998: # ifndef NO_ABBR
        !           999:                        if (abbr)
        !          1000:                                when = (bang ? WHEN_EX|WHEN_VIINP|WHEN_VIREP : WHEN_VIINP|WHEN_VIREP);
        !          1001:                        else
        !          1002: # endif
        !          1003:                                when = (bang ? WHEN_VIREP|WHEN_VIINP : WHEN_VICMD);
        !          1004: 
        !          1005:                        /* skip entries that don't match "when" */
        !          1006:                        if ((scan->flags & when) == 0)
        !          1007:                        {
        !          1008:                                continue;
        !          1009:                        }
        !          1010: 
        !          1011:                        /* write a "map" or "abbr" command name */
        !          1012: # ifndef NO_ABBR
        !          1013:                        if (abbr)
        !          1014:                                strcpy(tmpblk.c, "abbr");
        !          1015:                        else
        !          1016: # endif
        !          1017:                                strcpy(tmpblk.c, "map");
        !          1018: 
        !          1019:                        /* maybe write a bang.  Definitely write a space */
        !          1020:                        if (bang)
        !          1021:                                strcat(tmpblk.c, "! ");
        !          1022:                        else
        !          1023:                                strcat(tmpblk.c, " ");
        !          1024: 
        !          1025:                        /* write the rawin version */
        !          1026: # ifndef NO_FKEY
        !          1027:                        if (scan->label)
        !          1028:                                strcat(tmpblk.c, scan->label);
        !          1029:                        else
        !          1030: # endif
        !          1031:                                safequote(scan->rawin);
        !          1032:                        strcat(tmpblk.c, " ");
        !          1033:                                
        !          1034:                        /* dump the mapped version */
        !          1035: # ifndef NO_EXTENSIONS
        !          1036:                        if ((scan->flags & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP)))
        !          1037:                        {
        !          1038:                                strcat(tmpblk.c, "visual ");
        !          1039:                        }
        !          1040: # endif
        !          1041:                        safequote(scan->cooked);
        !          1042:                        strcat(tmpblk.c, "\n");
        !          1043:                        twrite(fd, tmpblk.c, strlen(tmpblk.c));
        !          1044:                }
        !          1045:        }
        !          1046: }
        !          1047: #endif

unix.superglobalmegacorp.com

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