Annotation of coherent/g/usr/bin/vi/tio.c, revision 1.1.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.