[BACK]Return to extend.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/extend.c, Revision 1.33

1.33    ! db          1: /*     $OpenBSD: extend.c,v 1.32 2005/03/10 16:58:57 deraadt Exp $     */
1.6       niklas      2:
1.1       deraadt     3: /*
1.5       millert     4:  *     Extended (M-X) commands, rebinding, and startup file processing.
1.1       deraadt     5:  */
1.20      vincent     6: #include "chrdef.h"
1.5       millert     7: #include "def.h"
                      8: #include "kbd.h"
1.16      art         9: #include "funmap.h"
1.1       deraadt    10:
                     11: #ifndef NO_MACRO
1.5       millert    12: #include "macro.h"
                     13: #endif /* !NO_MACRO */
1.1       deraadt    14:
                     15: #ifdef FKEYS
1.5       millert    16: #include "key.h"
1.1       deraadt    17: #ifndef        NO_STARTUP
                     18: #ifndef        BINDKEY
1.4       millert    19: #define        BINDKEY                 /* bindkey is used by FKEYS startup code */
1.5       millert    20: #endif /* !BINDKEY */
                     21: #endif /* !NO_STARTUP */
                     22: #endif /* FKEYS */
                     23:
1.21      millert    24: static int      remap(KEYMAP *, int, PF, KEYMAP *);
1.29      vincent    25: static KEYMAP  *reallocmap(KEYMAP *);
1.21      millert    26: static void     fixmap(KEYMAP *, KEYMAP *, KEYMAP *);
1.23      vincent    27: static int      dobind(KEYMAP *, const char *, int);
1.21      millert    28: static char    *skipwhite(char *);
                     29: static char    *parsetoken(char *);
1.23      vincent    30: static int      bindkey(KEYMAP **, const char *, KCHAR *, int);
1.1       deraadt    31:
1.15      mickey     32: /*
1.33    ! db         33:  * Insert a string, mainly for use from macros (created by selfinsert).
1.5       millert    34:  */
1.4       millert    35: /* ARGSUSED */
                     36: int
1.23      vincent    37: insert(int f, int n)
1.1       deraadt    38: {
1.31      vincent    39:        char     buf[128], *bufp, *cp;
1.1       deraadt    40: #ifndef NO_MACRO
1.5       millert    41:        int      count, c;
1.1       deraadt    42:
1.4       millert    43:        if (inmacro) {
                     44:                while (--n >= 0) {
                     45:                        for (count = 0; count < maclcur->l_used; count++) {
                     46:                                if ((((c = maclcur->l_text[count]) == '\n')
                     47:                                    ? lnewline() : linsert(1, c)) != TRUE)
1.33    ! db         48:                                        return (FALSE);
1.4       millert    49:                        }
                     50:                }
                     51:                maclcur = maclcur->l_fp;
1.33    ! db         52:                return (TRUE);
1.1       deraadt    53:        }
1.4       millert    54:        if (n == 1)
1.5       millert    55:                /* CFINS means selfinsert can tack on the end */
                     56:                thisflag |= CFINS;
                     57: #endif /* !NO_MACRO */
1.31      vincent    58:        if ((bufp = eread("Insert: ", buf, sizeof(buf), EFNEW)) == NULL)
1.33    ! db         59:                return (ABORT);
1.31      vincent    60:        else if (bufp[0] == '\0')
1.33    ! db         61:                return (FALSE);
1.4       millert    62:        while (--n >= 0) {
                     63:                cp = buf;
                     64:                while (*cp) {
                     65:                        if (((*cp == '\n') ? lnewline() : linsert(1, *cp))
                     66:                            != TRUE)
1.33    ! db         67:                                return (FALSE);
1.4       millert    68:                        cp++;
                     69:                }
1.1       deraadt    70:        }
1.33    ! db         71:        return (TRUE);
1.1       deraadt    72: }
                     73:
                     74: /*
                     75:  * Bind a key to a function.  Cases range from the trivial (replacing an
1.33    ! db         76:  * existing binding) to the extremely complex (creating a new prefix in a
1.1       deraadt    77:  * map_element that already has one, so the map_element must be split,
                     78:  * but the keymap doesn't have enough room for another map_element, so
                     79:  * the keymap is reallocated). No attempt is made to reclaim space no
                     80:  * longer used, if this is a problem flags must be added to indicate
                     81:  * malloced verses static storage in both keymaps and map_elements.
                     82:  * Structure assignments would come in real handy, but K&R based compilers
                     83:  * don't have them.  Care is taken so running out of memory will leave
                     84:  * the keymap in a usable state.
                     85:  */
1.4       millert    86: static int
1.23      vincent    87: remap(KEYMAP *curmap,          /* pointer to the map being changed */
1.32      deraadt    88:     int c,                     /* character being changed */
                     89:     PF funct,                  /* function being changed to */
                     90:     KEYMAP *pref_map)          /* if funct==NULL, map to bind to or NULL for new */
1.1       deraadt    91: {
1.5       millert    92:        int              i, n1, n2, nold;
1.30      vincent    93:        KEYMAP          *mp, *newmap;
1.5       millert    94:        PF              *pfp;
                     95:        MAP_ELEMENT     *mep;
1.4       millert    96:
                     97:        if (ele >= &curmap->map_element[curmap->map_num] || c < ele->k_base) {
1.7       art        98:                if (ele > &curmap->map_element[0] && (funct != NULL ||
1.5       millert    99:                    (ele - 1)->k_prefmap == NULL))
1.4       millert   100:                        n1 = c - (ele - 1)->k_num;
1.5       millert   101:                else
1.4       millert   102:                        n1 = HUGE;
                    103:                if (ele < &curmap->map_element[curmap->map_num] &&
1.7       art       104:                    (funct != NULL || ele->k_prefmap == NULL))
1.4       millert   105:                        n2 = ele->k_base - c;
1.5       millert   106:                else
1.4       millert   107:                        n2 = HUGE;
                    108:                if (n1 <= MAPELEDEF && n1 <= n2) {
                    109:                        ele--;
1.5       millert   110:                        if ((pfp = (PF *)malloc((c - ele->k_base + 1) *
1.4       millert   111:                            sizeof(PF))) == NULL) {
                    112:                                ewprintf("Out of memory");
1.33    ! db        113:                                return (FALSE);
1.4       millert   114:                        }
                    115:                        nold = ele->k_num - ele->k_base + 1;
                    116:                        for (i = 0; i < nold; i++)
                    117:                                pfp[i] = ele->k_funcp[i];
                    118:                        while (--n1)
                    119:                                pfp[i++] = curmap->map_default;
                    120:                        pfp[i] = funct;
                    121:                        ele->k_num = c;
                    122:                        ele->k_funcp = pfp;
                    123:                } else if (n2 <= MAPELEDEF) {
1.5       millert   124:                        if ((pfp = (PF *)malloc((ele->k_num - c + 1) *
                    125:                            sizeof(PF))) == NULL) {
1.4       millert   126:                                ewprintf("Out of memory");
1.33    ! db        127:                                return (FALSE);
1.4       millert   128:                        }
                    129:                        nold = ele->k_num - ele->k_base + 1;
                    130:                        for (i = 0; i < nold; i++)
                    131:                                pfp[i + n2] = ele->k_funcp[i];
                    132:                        while (--n2)
                    133:                                pfp[n2] = curmap->map_default;
                    134:                        pfp[0] = funct;
                    135:                        ele->k_base = c;
                    136:                        ele->k_funcp = pfp;
1.1       deraadt   137:                } else {
1.30      vincent   138:                        if (curmap->map_num >= curmap->map_max) {
                    139:                                if ((newmap = reallocmap(curmap)) == NULL)
1.33    ! db        140:                                        return (FALSE);
1.30      vincent   141:                                curmap = newmap;
                    142:                        }
1.13      art       143:                        if ((pfp = malloc(sizeof(PF))) == NULL) {
1.4       millert   144:                                ewprintf("Out of memory");
1.33    ! db        145:                                return (FALSE);
1.4       millert   146:                        }
                    147:                        pfp[0] = funct;
                    148:                        for (mep = &curmap->map_element[curmap->map_num];
                    149:                            mep > ele; mep--) {
                    150:                                mep->k_base = (mep - 1)->k_base;
                    151:                                mep->k_num = (mep - 1)->k_num;
                    152:                                mep->k_funcp = (mep - 1)->k_funcp;
                    153:                                mep->k_prefmap = (mep - 1)->k_prefmap;
                    154:                        }
                    155:                        ele->k_base = c;
                    156:                        ele->k_num = c;
                    157:                        ele->k_funcp = pfp;
                    158:                        ele->k_prefmap = NULL;
                    159:                        curmap->map_num++;
                    160:                }
1.7       art       161:                if (funct == NULL) {
1.29      vincent   162:                        if (pref_map != NULL)
1.4       millert   163:                                ele->k_prefmap = pref_map;
1.29      vincent   164:                        else {
                    165:                                if ((mp = (KEYMAP *)malloc(sizeof(KEYMAP) +
                    166:                                    (MAPINIT - 1) * sizeof(MAP_ELEMENT))) == NULL) {
1.4       millert   167:                                        ewprintf("Out of memory");
                    168:                                        ele->k_funcp[c - ele->k_base] =
                    169:                                            curmap->map_default;
1.33    ! db        170:                                        return (FALSE);
1.4       millert   171:                                }
                    172:                                mp->map_num = 0;
                    173:                                mp->map_max = MAPINIT;
                    174:                                mp->map_default = rescan;
                    175:                                ele->k_prefmap = mp;
                    176:                        }
1.1       deraadt   177:                }
                    178:        } else {
1.4       millert   179:                n1 = c - ele->k_base;
1.7       art       180:                if (ele->k_funcp[n1] == funct && (funct != NULL ||
1.4       millert   181:                    pref_map == NULL || pref_map == ele->k_prefmap))
1.5       millert   182:                        /* no change */
1.33    ! db        183:                        return (TRUE);
1.7       art       184:                if (funct != NULL || ele->k_prefmap == NULL) {
                    185:                        if (ele->k_funcp[n1] == NULL)
1.13      art       186:                                ele->k_prefmap = NULL;
1.5       millert   187:                        /* easy case */
                    188:                        ele->k_funcp[n1] = funct;
1.7       art       189:                        if (funct == NULL) {
1.4       millert   190:                                if (pref_map != NULL)
                    191:                                        ele->k_prefmap = pref_map;
                    192:                                else {
1.28      vincent   193:                                        if ((mp = malloc(sizeof(KEYMAP) +
1.15      mickey    194:                                            (MAPINIT - 1) *
1.28      vincent   195:                                            sizeof(MAP_ELEMENT))) == NULL) {
1.4       millert   196:                                                ewprintf("Out of memory");
                    197:                                                ele->k_funcp[c - ele->k_base] =
                    198:                                                    curmap->map_default;
1.33    ! db        199:                                                return (FALSE);
1.4       millert   200:                                        }
                    201:                                        mp->map_num = 0;
                    202:                                        mp->map_max = MAPINIT;
                    203:                                        mp->map_default = rescan;
                    204:                                        ele->k_prefmap = mp;
                    205:                                }
                    206:                        }
                    207:                } else {
                    208:                        /*
1.5       millert   209:                         * This case is the splits.
                    210:                         * Determine which side of the break c goes on
1.4       millert   211:                         * 0 = after break; 1 = before break
                    212:                         */
                    213:                        n2 = 1;
                    214:                        for (i = 0; n2 && i < n1; i++)
1.7       art       215:                                n2 &= ele->k_funcp[i] != NULL;
1.4       millert   216:                        if (curmap->map_num >= curmap->map_max &&
1.29      vincent   217:                            (curmap = reallocmap(curmap)) == NULL)
1.33    ! db        218:                                return (FALSE);
1.15      mickey    219:                        if ((pfp = malloc((ele->k_num - c + !n2) *
1.5       millert   220:                            sizeof(PF))) == NULL) {
1.4       millert   221:                                ewprintf("Out of memory");
1.33    ! db        222:                                return (FALSE);
1.4       millert   223:                        }
1.7       art       224:                        ele->k_funcp[n1] = NULL;
1.4       millert   225:                        for (i = n1 + n2; i <= ele->k_num - ele->k_base; i++)
                    226:                                pfp[i - n1 - n2] = ele->k_funcp[i];
                    227:                        for (mep = &curmap->map_element[curmap->map_num];
                    228:                            mep > ele; mep--) {
                    229:                                mep->k_base = (mep - 1)->k_base;
                    230:                                mep->k_num = (mep - 1)->k_num;
                    231:                                mep->k_funcp = (mep - 1)->k_funcp;
                    232:                                mep->k_prefmap = (mep - 1)->k_prefmap;
                    233:                        }
                    234:                        ele->k_num = c - !n2;
                    235:                        (ele + 1)->k_base = c + n2;
                    236:                        (ele + 1)->k_funcp = pfp;
                    237:                        ele += !n2;
                    238:                        ele->k_prefmap = NULL;
                    239:                        curmap->map_num++;
                    240:                        if (pref_map == NULL) {
                    241:                                if ((mp = malloc(sizeof(KEYMAP) + (MAPINIT - 1)
                    242:                                    * sizeof(MAP_ELEMENT))) == NULL) {
                    243:                                        ewprintf("Out of memory");
                    244:                                        ele->k_funcp[c - ele->k_base] =
                    245:                                            curmap->map_default;
1.33    ! db        246:                                        return (FALSE);
1.4       millert   247:                                }
                    248:                                mp->map_num = 0;
                    249:                                mp->map_max = MAPINIT;
                    250:                                mp->map_default = rescan;
                    251:                                ele->k_prefmap = mp;
                    252:                        } else
                    253:                                ele->k_prefmap = pref_map;
                    254:                }
1.1       deraadt   255:        }
1.33    ! db        256:        return (TRUE);
1.1       deraadt   257: }
                    258:
1.4       millert   259: /*
                    260:  * Reallocate a keymap, used above.
                    261:  */
                    262: static KEYMAP *
1.29      vincent   263: reallocmap(KEYMAP *curmap)
1.4       millert   264: {
1.33    ! db        265:        MAPS    *mps;
1.5       millert   266:        KEYMAP  *mp;
                    267:        int      i;
1.4       millert   268:
1.5       millert   269:        if ((mp = (KEYMAP *)malloc((unsigned)(sizeof(KEYMAP) +
1.15      mickey    270:            (curmap->map_max + (MAPGROW - 1)) *
1.5       millert   271:            sizeof(MAP_ELEMENT)))) == NULL) {
1.4       millert   272:                ewprintf("Out of memory");
1.33    ! db        273:                return (NULL);
1.4       millert   274:        }
                    275:        mp->map_num = curmap->map_num;
                    276:        mp->map_max = curmap->map_max + MAPGROW;
                    277:        mp->map_default = curmap->map_default;
                    278:        for (i = curmap->map_num; i--;) {
                    279:                mp->map_element[i].k_base = curmap->map_element[i].k_base;
                    280:                mp->map_element[i].k_num = curmap->map_element[i].k_num;
                    281:                mp->map_element[i].k_funcp = curmap->map_element[i].k_funcp;
                    282:                mp->map_element[i].k_prefmap = curmap->map_element[i].k_prefmap;
                    283:        }
1.17      art       284:        for (mps = maps; mps != NULL; mps = mps->p_next) {
                    285:                if (mps->p_map == curmap)
                    286:                        mps->p_map = mp;
1.4       millert   287:                else
1.17      art       288:                        fixmap(curmap, mp, mps->p_map);
1.4       millert   289:        }
                    290:        ele = &mp->map_element[ele - &curmap->map_element[0]];
1.33    ! db        291:        return (mp);
1.4       millert   292: }
                    293:
                    294: /*
                    295:  * Fix references to a reallocated keymap (recursive).
                    296:  */
1.12      art       297: static void
1.23      vincent   298: fixmap(KEYMAP *curmap, KEYMAP *mp, KEYMAP *mt)
1.4       millert   299: {
1.5       millert   300:        int      i;
1.4       millert   301:
                    302:        for (i = mt->map_num; i--;) {
                    303:                if (mt->map_element[i].k_prefmap != NULL) {
                    304:                        if (mt->map_element[i].k_prefmap == curmap)
                    305:                                mt->map_element[i].k_prefmap = mp;
                    306:                        else
                    307:                                fixmap(curmap, mp, mt->map_element[i].k_prefmap);
                    308:                }
1.1       deraadt   309:        }
                    310: }
                    311:
                    312: /*
1.33    ! db        313:  * Do the input for local-set-key, global-set-key  and define-key
1.1       deraadt   314:  * then call remap to do the work.
                    315:  */
1.4       millert   316: static int
1.23      vincent   317: dobind(KEYMAP *curmap, const char *p, int unbind)
1.4       millert   318: {
1.5       millert   319:        KEYMAP  *pref_map = NULL;
                    320:        PF       funct;
1.33    ! db        321:        char     prompt[80], *bufp, *pep;
1.26      vincent   322:        int      c, s, n;
1.1       deraadt   323:
                    324: #ifndef NO_MACRO
1.4       millert   325:        if (macrodef) {
                    326:                /*
                    327:                 * Keystrokes aren't collected. Not hard, but pretty useless.
                    328:                 * Would not work for function keys in any case.
                    329:                 */
                    330:                ewprintf("Can't rebind key in macro");
1.33    ! db        331:                return (FALSE);
1.1       deraadt   332:        }
                    333: #ifndef NO_STARTUP
1.4       millert   334:        if (inmacro) {
                    335:                for (s = 0; s < maclcur->l_used - 1; s++) {
1.8       art       336:                        if (doscan(curmap, c = CHARMASK(maclcur->l_text[s]), &curmap)
1.7       art       337:                            != NULL) {
1.13      art       338:                                if (remap(curmap, c, NULL, NULL)
1.4       millert   339:                                    != TRUE)
1.33    ! db        340:                                        return (FALSE);
1.4       millert   341:                        }
1.1       deraadt   342:                }
1.12      art       343:                (void)doscan(curmap, c = maclcur->l_text[s], NULL);
1.4       millert   344:                maclcur = maclcur->l_fp;
1.1       deraadt   345:        } else {
1.5       millert   346: #endif /* !NO_STARTUP */
                    347: #endif /* !NO_MACRO */
1.33    ! db        348:                n = strlcpy(prompt, p, sizeof(prompt));
        !           349:                if (n >= sizeof(prompt))
        !           350:                        n = sizeof(prompt) - 1;
1.26      vincent   351:                pep = prompt + n;
1.4       millert   352:                for (;;) {
                    353:                        ewprintf("%s", prompt);
                    354:                        pep[-1] = ' ';
1.14      mickey    355:                        pep = keyname(pep, sizeof(prompt) - (pep - prompt),
                    356:                            c = getkey(FALSE));
1.8       art       357:                        if (doscan(curmap, c, &curmap) != NULL)
1.4       millert   358:                                break;
                    359:                        *pep++ = '-';
                    360:                        *pep = '\0';
                    361:                }
1.1       deraadt   362: #ifndef NO_STARTUP
                    363:        }
1.5       millert   364: #endif /* !NO_STARTUP */
1.4       millert   365:        if (unbind)
                    366:                funct = rescan;
1.1       deraadt   367:        else {
1.31      vincent   368:                if ((bufp = eread("%s to command: ", prompt, 80, EFFUNC | EFNEW,
                    369:                    prompt)) == NULL)
1.33    ! db        370:                        return (ABORT);
1.31      vincent   371:                else if (bufp[0] == '\0')
1.33    ! db        372:                        return (FALSE);
1.7       art       373:                if (((funct = name_function(prompt)) == NULL) ?
1.4       millert   374:                    (pref_map = name_map(prompt)) == NULL : funct == NULL) {
                    375:                        ewprintf("[No match]");
1.33    ! db        376:                        return (FALSE);
1.4       millert   377:                }
1.1       deraadt   378:        }
1.33    ! db        379:        return (remap(curmap, c, funct, pref_map));
1.1       deraadt   380: }
                    381:
                    382: /*
1.15      mickey    383:  * bindkey: bind key sequence to a function in the specified map.  Used by
                    384:  * excline so it can bind function keys.  To close to release to change
                    385:  * calling sequence, should just pass KEYMAP *curmap rather than
1.5       millert   386:  * KEYMAP **mapp.
                    387:  */
1.1       deraadt   388: #ifdef BINDKEY
1.5       millert   389: static int
1.23      vincent   390: bindkey(KEYMAP **mapp, const char *fname, KCHAR *keys, int kcount)
1.5       millert   391: {
                    392:        KEYMAP  *curmap = *mapp;
                    393:        KEYMAP  *pref_map = NULL;
                    394:        PF       funct;
                    395:        int      c;
1.1       deraadt   396:
1.4       millert   397:        if (fname == NULL)
                    398:                funct = rescan;
1.7       art       399:        else if (((funct = name_function(fname)) == NULL) ?
1.5       millert   400:            (pref_map = name_map(fname)) == NULL : funct == NULL) {
1.4       millert   401:                ewprintf("[No match: %s]", fname);
1.33    ! db        402:                return (FALSE);
1.4       millert   403:        }
                    404:        while (--kcount) {
1.8       art       405:                if (doscan(curmap, c = *keys++, &curmap) != NULL) {
1.13      art       406:                        if (remap(curmap, c, NULL, NULL) != TRUE)
1.33    ! db        407:                                return (FALSE);
1.9       art       408:                        /*
                    409:                         * XXX - Bizzarreness. remap creates an empty KEYMAP
                    410:                         *       that the last key is supposed to point to.
                    411:                         */
                    412:                        curmap = ele->k_prefmap;
1.4       millert   413:                }
1.1       deraadt   414:        }
1.12      art       415:        (void)doscan(curmap, c = *keys, NULL);
1.33    ! db        416:        return (remap(curmap, c, funct, pref_map));
1.1       deraadt   417: }
1.3       millert   418:
                    419: #ifdef FKEYS
                    420: /*
                    421:  * Wrapper for bindkey() that converts escapes.
                    422:  */
                    423: int
1.23      vincent   424: dobindkey(KEYMAP *map, const char *func, const char *str)
1.3       millert   425: {
1.5       millert   426:        int      i;
1.3       millert   427:
                    428:        for (i = 0; *str && i < MAXKEY; i++) {
                    429:                /* XXX - convert numbers w/ strol()? */
                    430:                if (*str != '\\')
                    431:                        key.k_chars[i] = *str;
                    432:                else {
1.4       millert   433:                        switch (*++str) {
                    434:                        case 't':
                    435:                        case 'T':
1.3       millert   436:                                key.k_chars[i] = '\t';
                    437:                                break;
1.4       millert   438:                        case 'n':
                    439:                        case 'N':
1.3       millert   440:                                key.k_chars[i] = '\n';
                    441:                                break;
1.4       millert   442:                        case 'r':
                    443:                        case 'R':
1.3       millert   444:                                key.k_chars[i] = '\r';
                    445:                                break;
1.4       millert   446:                        case 'e':
                    447:                        case 'E':
1.3       millert   448:                                key.k_chars[i] = CCHR('[');
                    449:                                break;
                    450:                        }
                    451:                }
                    452:                str++;
                    453:        }
                    454:        key.k_count = i;
1.4       millert   455:        return (bindkey(&map, func, key.k_chars, key.k_count));
1.3       millert   456: }
1.5       millert   457: #endif /* FKEYS */
                    458: #endif /* BINDKEY */
1.1       deraadt   459:
                    460: /*
                    461:  * This function modifies the fundamental keyboard map.
                    462:  */
1.4       millert   463: /* ARGSUSED */
                    464: int
1.23      vincent   465: bindtokey(int f, int n)
1.1       deraadt   466: {
1.33    ! db        467:        return (dobind(fundamental_map, "Global set key: ", FALSE));
1.1       deraadt   468: }
                    469:
                    470: /*
                    471:  * This function modifies the current mode's keyboard map.
                    472:  */
1.4       millert   473: /* ARGSUSED */
                    474: int
1.23      vincent   475: localbind(int f, int n)
1.1       deraadt   476: {
1.33    ! db        477:        return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
        !           478:            "Local set key: ", FALSE));
1.1       deraadt   479: }
                    480:
                    481: /*
                    482:  * This function redefines a key in any keymap.
                    483:  */
1.4       millert   484: /* ARGSUSED */
                    485: int
1.19      vincent   486: define_key(int f, int n)
1.1       deraadt   487: {
1.33    ! db        488:        static char      buf[48];
        !           489:        char             tmp[32], *bufp;
        !           490:        KEYMAP          *mp;
        !           491:
        !           492:        strlcpy(buf, "Define key map: ", sizeof(buf));
        !           493:        if ((bufp = eread(buf, tmp, sizeof(tmp), EFNEW)) == NULL)
        !           494:                return (ABORT);
1.31      vincent   495:        else if (bufp[0] == '\0')
1.33    ! db        496:                return (FALSE);
        !           497:        strlcat(buf, tmp, sizeof(buf));
1.19      vincent   498:        if ((mp = name_map(tmp)) == NULL) {
                    499:                ewprintf("Unknown map %s", tmp);
1.33    ! db        500:                return (FALSE);
1.4       millert   501:        }
1.33    ! db        502:        strlcat(buf, "key: ", sizeof(buf));
1.19      vincent   503:
1.33    ! db        504:        return (dobind(mp, buf, FALSE));
1.1       deraadt   505: }
                    506:
1.4       millert   507: int
1.23      vincent   508: unbindtokey(int f, int n)
1.1       deraadt   509: {
1.33    ! db        510:        return (dobind(fundamental_map, "Global unset key: ", TRUE));
1.1       deraadt   511: }
                    512:
1.4       millert   513: int
1.27      vincent   514: localunbind(int f, int n)
1.1       deraadt   515: {
1.33    ! db        516:        return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
        !           517:            "Local unset key: ", TRUE));
1.1       deraadt   518: }
                    519:
                    520: /*
1.15      mickey    521:  * Extended command. Call the message line routine to read in the command
                    522:  * name and apply autocompletion to it. When it comes back, look the name
                    523:  * up in the symbol table and run the command if it is found.  Print an
1.5       millert   524:  * error if there is anything wrong.
1.1       deraadt   525:  */
1.4       millert   526: int
1.23      vincent   527: extend(int f, int n)
1.1       deraadt   528: {
1.5       millert   529:        PF       funct;
1.31      vincent   530:        char     xname[NXNAME], *bufp;
1.4       millert   531:
                    532:        if (!(f & FFARG))
1.31      vincent   533:                bufp = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC);
1.4       millert   534:        else
1.31      vincent   535:                bufp = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n);
                    536:        if (bufp == NULL)
1.33    ! db        537:                return (ABORT);
1.31      vincent   538:        else if (bufp[0] == '\0')
1.33    ! db        539:                return (FALSE);
1.31      vincent   540:        if ((funct = name_function(bufp)) != NULL) {
1.1       deraadt   541: #ifndef NO_MACRO
1.4       millert   542:                if (macrodef) {
1.5       millert   543:                        LINE    *lp = maclcur;
1.4       millert   544:                        macro[macrocount - 1].m_funct = funct;
                    545:                        maclcur = lp->l_bp;
                    546:                        maclcur->l_fp = lp->l_fp;
1.5       millert   547:                        free((char *)lp);
1.4       millert   548:                }
1.5       millert   549: #endif /* !NO_MACRO */
1.33    ! db        550:                return ((*funct)(f, n));
1.1       deraadt   551:        }
                    552:        ewprintf("[No match]");
1.33    ! db        553:        return (FALSE);
1.1       deraadt   554: }
                    555:
                    556: #ifndef NO_STARTUP
                    557: /*
                    558:  * Define the commands needed to do startup-file processing.
                    559:  * This code is mostly a kludge just so we can get startup-file processing.
                    560:  *
                    561:  * If you're serious about having this code, you should rewrite it.
                    562:  * To wit:
                    563:  *     It has lots of funny things in it to make the startup-file look
                    564:  *     like a GNU startup file; mostly dealing with parens and semicolons.
                    565:  *     This should all vanish.
                    566:  *
                    567:  * We define eval-expression because it's easy.         It can make
                    568:  * *-set-key or define-key set an arbitrary key sequence, so it isn't
                    569:  * useless.
                    570:  */
                    571:
                    572: /*
                    573:  * evalexpr - get one line from the user, and run it.
                    574:  */
1.4       millert   575: /* ARGSUSED */
                    576: int
1.23      vincent   577: evalexpr(int f, int n)
1.1       deraadt   578: {
1.31      vincent   579:        char     exbuf[128], *bufp;
1.1       deraadt   580:
1.31      vincent   581:        if ((bufp = ereply("Eval: ", exbuf, sizeof(exbuf))) == NULL)
1.33    ! db        582:                return (ABORT);
1.31      vincent   583:        else if (bufp[0] == '\0')
1.33    ! db        584:                return (FALSE);
        !           585:        return (excline(exbuf));
1.1       deraadt   586: }
1.4       millert   587:
1.1       deraadt   588: /*
1.15      mickey    589:  * evalbuffer - evaluate the current buffer as line commands. Useful for
1.5       millert   590:  * testing startup files.
1.1       deraadt   591:  */
1.4       millert   592: /* ARGSUSED */
                    593: int
1.23      vincent   594: evalbuffer(int f, int n)
1.1       deraadt   595: {
1.5       millert   596:        LINE            *lp;
                    597:        BUFFER          *bp = curbp;
                    598:        int              s;
                    599:        static char      excbuf[128];
1.1       deraadt   600:
                    601:        for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
1.4       millert   602:                if (llength(lp) >= 128)
1.33    ! db        603:                        return (FALSE);
1.12      art       604:                (void)strncpy(excbuf, ltext(lp), llength(lp));
1.5       millert   605:
                    606:                /* make sure it's terminated */
                    607:                excbuf[llength(lp)] = '\0';
1.4       millert   608:                if ((s = excline(excbuf)) != TRUE)
1.33    ! db        609:                        return (s);
1.1       deraadt   610:        }
1.33    ! db        611:        return (TRUE);
1.1       deraadt   612: }
1.4       millert   613:
1.1       deraadt   614: /*
                    615:  * evalfile - go get a file and evaluate it as line commands. You can
                    616:  *     go get your own startup file if need be.
                    617:  */
1.4       millert   618: /* ARGSUSED */
                    619: int
1.23      vincent   620: evalfile(int f, int n)
1.1       deraadt   621: {
1.31      vincent   622:        char     fname[NFILEN], *bufp;
1.1       deraadt   623:
1.31      vincent   624:        if ((bufp = ereply("Load file: ", fname, NFILEN)) == NULL)
1.33    ! db        625:                return (ABORT);
1.31      vincent   626:        else if (bufp[0] == '\0')
1.33    ! db        627:                return (FALSE);
        !           628:        return (load(fname));
1.1       deraadt   629: }
                    630:
                    631: /*
                    632:  * load - go load the file name we got passed.
                    633:  */
1.4       millert   634: int
1.23      vincent   635: load(const char *fname)
1.4       millert   636: {
1.25      vincent   637:        int      s = TRUE, line;
1.18      matthieu  638:        int      nbytes = 0;
1.5       millert   639:        char     excbuf[128];
1.1       deraadt   640:
                    641:        if ((fname = adjustname(fname)) == NULL)
1.5       millert   642:                /* just to be careful */
1.33    ! db        643:                return (FALSE);
1.1       deraadt   644:
1.13      art       645:        if (ffropen(fname, NULL) != FIOSUC)
1.33    ! db        646:                return (FALSE);
1.5       millert   647:
1.25      vincent   648:        line = 0;
1.4       millert   649:        while ((s = ffgetline(excbuf, sizeof(excbuf) - 1, &nbytes)) == FIOSUC) {
1.25      vincent   650:                line++;
1.1       deraadt   651:                excbuf[nbytes] = '\0';
                    652:                if (excline(excbuf) != TRUE) {
                    653:                        s = FIOERR;
1.25      vincent   654:                        ewprintf("Error loading file %s at line %d", fname, line);
1.1       deraadt   655:                        break;
                    656:                }
                    657:        }
1.13      art       658:        (void)ffclose(NULL);
1.1       deraadt   659:        excbuf[nbytes] = '\0';
1.4       millert   660:        if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE))
1.33    ! db        661:                return (FALSE);
        !           662:        return (TRUE);
1.1       deraadt   663: }
                    664:
                    665: /*
1.33    ! db        666:  * excline - run a line from a load file or eval-expression.  If FKEYS is
        !           667:  * defined, duplicate functionality of dobind so function key values don't
1.5       millert   668:  * have to fit in type char.
1.1       deraadt   669:  */
1.4       millert   670: int
1.23      vincent   671: excline(char *line)
1.1       deraadt   672: {
1.5       millert   673:        PF       fp;
                    674:        LINE    *lp, *np;
                    675:        int      status, c, f, n;
1.22      ho        676:        char    *funcp, *tmp;
1.5       millert   677:        char    *argp = NULL;
1.22      ho        678:        long     nl;
1.5       millert   679: #ifdef FKEYS
                    680:        int      bind;
                    681:        KEYMAP  *curmap;
                    682: #define BINDARG                0  /* this arg is key to bind (local/global set key) */
                    683: #define        BINDNO          1  /* not binding or non-quoted BINDARG */
                    684: #define BINDNEXT       2  /* next arg " (define-key) */
                    685: #define BINDDO         3  /* already found key to bind */
                    686: #define BINDEXT                1  /* space for trailing \0 */
                    687: #else /* FKEYS */
                    688: #define BINDEXT                0
                    689: #endif /* FKEYS */
                    690:
                    691:        lp = NULL;
1.1       deraadt   692:
1.4       millert   693:        if (macrodef || inmacro) {
1.1       deraadt   694:                ewprintf("Not now!");
1.33    ! db        695:                return (FALSE);
1.1       deraadt   696:        }
                    697:        f = 0;
                    698:        n = 1;
                    699:        funcp = skipwhite(line);
1.4       millert   700:        if (*funcp == '\0')
1.33    ! db        701:                return (TRUE);  /* No error on blank lines */
1.1       deraadt   702:        line = parsetoken(funcp);
                    703:        if (*line != '\0') {
                    704:                *line++ = '\0';
                    705:                line = skipwhite(line);
1.20      vincent   706:                if (ISDIGIT(*line) || *line == '-') {
1.1       deraadt   707:                        argp = line;
                    708:                        line = parsetoken(line);
                    709:                }
                    710:        }
                    711:        if (argp != NULL) {
                    712:                f = FFARG;
1.22      ho        713:                nl = strtol(argp, &tmp, 10);
1.20      vincent   714:                if (*tmp != '\0')
1.33    ! db        715:                        return (FALSE);
1.22      ho        716:                if (nl >= INT_MAX || nl <= INT_MIN)
1.33    ! db        717:                        return (FALSE);
1.22      ho        718:                n = (int)nl;
1.1       deraadt   719:        }
1.4       millert   720:        if ((fp = name_function(funcp)) == NULL) {
                    721:                ewprintf("Unknown function: %s", funcp);
1.33    ! db        722:                return (FALSE);
1.1       deraadt   723:        }
                    724: #ifdef FKEYS
1.4       millert   725:        if (fp == bindtokey || fp == unbindtokey) {
1.1       deraadt   726:                bind = BINDARG;
1.11      art       727:                curmap = fundamental_map;
1.4       millert   728:        } else if (fp == localbind || fp == localunbind) {
1.1       deraadt   729:                bind = BINDARG;
                    730:                curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.4       millert   731:        } else if (fp == define_key)
                    732:                bind = BINDNEXT;
                    733:        else
                    734:                bind = BINDNO;
1.5       millert   735: #endif /* FKEYS */
                    736:        /* Pack away all the args now... */
1.4       millert   737:        if ((np = lalloc(0)) == FALSE)
1.33    ! db        738:                return (FALSE);
1.1       deraadt   739:        np->l_fp = np->l_bp = maclcur = np;
                    740:        while (*line != '\0') {
                    741:                argp = skipwhite(line);
1.4       millert   742:                if (*argp == '\0')
                    743:                        break;
1.1       deraadt   744:                line = parsetoken(argp);
                    745:                if (*argp != '"') {
1.4       millert   746:                        if (*argp == '\'')
                    747:                                ++argp;
1.20      vincent   748:                        if ((lp = lalloc((int) (line - argp) + BINDEXT)) ==
                    749:                            NULL) {
1.4       millert   750:                                status = FALSE;
                    751:                                goto cleanup;
                    752:                        }
1.5       millert   753:                        bcopy(argp, ltext(lp), (int)(line - argp));
1.1       deraadt   754: #ifdef FKEYS
1.5       millert   755:                        /* don't count BINDEXT */
                    756:                        lp->l_used--;
1.4       millert   757:                        if (bind == BINDARG)
                    758:                                bind = BINDNO;
1.5       millert   759: #endif /* FKEYS */
                    760:                } else {
                    761:                        /* quoted strings are special */
1.4       millert   762:                        ++argp;
1.1       deraadt   763: #ifdef FKEYS
1.4       millert   764:                        if (bind != BINDARG) {
1.5       millert   765: #endif /* FKEYS */
                    766:                                lp = lalloc((int)(line - argp) + BINDEXT);
1.4       millert   767:                                if (lp == NULL) {
                    768:                                        status = FALSE;
                    769:                                        goto cleanup;
                    770:                                }
                    771:                                lp->l_used = 0;
1.1       deraadt   772: #ifdef FKEYS
1.33    ! db        773:                        } else
1.4       millert   774:                                key.k_count = 0;
1.5       millert   775: #endif /* FKEYS */
1.4       millert   776:                        while (*argp != '"' && *argp != '\0') {
                    777:                                if (*argp != '\\')
                    778:                                        c = *argp++;
                    779:                                else {
                    780:                                        switch (*++argp) {
                    781:                                        case 't':
                    782:                                        case 'T':
                    783:                                                c = CCHR('I');
                    784:                                                break;
                    785:                                        case 'n':
                    786:                                        case 'N':
                    787:                                                c = CCHR('J');
                    788:                                                break;
                    789:                                        case 'r':
                    790:                                        case 'R':
                    791:                                                c = CCHR('M');
                    792:                                                break;
                    793:                                        case 'e':
                    794:                                        case 'E':
                    795:                                                c = CCHR('[');
                    796:                                                break;
                    797:                                        case '^':
                    798:                                                /*
                    799:                                                 * split into two statements
                    800:                                                 * due to bug in OSK cpp
                    801:                                                 */
                    802:                                                c = CHARMASK(*++argp);
                    803:                                                c = ISLOWER(c) ?
                    804:                                                    CCHR(TOUPPER(c)) : CCHR(c);
                    805:                                                break;
                    806:                                        case '0':
                    807:                                        case '1':
                    808:                                        case '2':
                    809:                                        case '3':
                    810:                                        case '4':
                    811:                                        case '5':
                    812:                                        case '6':
                    813:                                        case '7':
                    814:                                                c = *argp - '0';
1.15      mickey    815:                                                if (argp[1] <= '7' &&
1.5       millert   816:                                                    argp[1] >= '0') {
1.4       millert   817:                                                        c <<= 3;
                    818:                                                        c += *++argp - '0';
                    819:                                                        if (argp[1] <= '7' &&
                    820:                                                            argp[1] >= '0') {
                    821:                                                                c <<= 3;
                    822:                                                                c += *++argp
                    823:                                                                    - '0';
                    824:                                                        }
                    825:                                                }
                    826:                                                break;
                    827: #ifdef FKEYS
                    828:                                        case 'f':
                    829:                                        case 'F':
                    830:                                                c = *++argp - '0';
                    831:                                                if (ISDIGIT(argp[1])) {
                    832:                                                        c *= 10;
                    833:                                                        c += *++argp - '0';
                    834:                                                }
                    835:                                                c += KFIRST;
                    836:                                                break;
1.5       millert   837: #endif /* FKEYS */
1.4       millert   838:                                        default:
                    839:                                                c = CHARMASK(*argp);
                    840:                                                break;
                    841:                                        }
                    842:                                        argp++;
                    843:                                }
1.1       deraadt   844: #ifdef FKEYS
1.4       millert   845:                                if (bind == BINDARG)
                    846:                                        key.k_chars[key.k_count++] = c;
                    847:                                else
1.5       millert   848: #endif /* FKEYS */
1.4       millert   849:                                        lp->l_text[lp->l_used++] = c;
                    850:                        }
                    851:                        if (*line)
                    852:                                line++;
1.1       deraadt   853:                }
                    854: #ifdef FKEYS
1.4       millert   855:                switch (bind) {
                    856:                case BINDARG:
1.1       deraadt   857:                        bind = BINDDO;
                    858:                        break;
1.4       millert   859:                case BINDNEXT:
1.1       deraadt   860:                        lp->l_text[lp->l_used] = '\0';
1.10      art       861:                        if ((curmap = name_map(lp->l_text)) == NULL) {
1.4       millert   862:                                ewprintf("No such mode: %s", lp->l_text);
                    863:                                status = FALSE;
1.5       millert   864:                                free((char *)lp);
1.4       millert   865:                                goto cleanup;
1.1       deraadt   866:                        }
1.5       millert   867:                        free((char *)lp);
1.1       deraadt   868:                        bind = BINDARG;
                    869:                        break;
1.4       millert   870:                default:
1.5       millert   871: #endif /* FKEYS */
1.1       deraadt   872:                        lp->l_fp = np->l_fp;
                    873:                        lp->l_bp = np;
                    874:                        np->l_fp = lp;
                    875:                        np = lp;
                    876: #ifdef FKEYS
                    877:                }
1.5       millert   878: #endif /* FKEYS */
1.1       deraadt   879:        }
                    880: #ifdef FKEYS
1.4       millert   881:        switch (bind) {
                    882:        default:
1.1       deraadt   883:                ewprintf("Bad args to set key");
                    884:                status = FALSE;
                    885:                break;
1.4       millert   886:        case BINDDO:
                    887:                if (fp != unbindtokey && fp != localunbind) {
                    888:                        lp->l_text[lp->l_used] = '\0';
                    889:                        status = bindkey(&curmap, lp->l_text, key.k_chars,
                    890:                            key.k_count);
1.33    ! db        891:                } else
1.13      art       892:                        status = bindkey(&curmap, NULL, key.k_chars,
1.4       millert   893:                            key.k_count);
1.1       deraadt   894:                break;
1.4       millert   895:        case BINDNO:
1.5       millert   896: #endif /* FKEYS */
1.1       deraadt   897:                inmacro = TRUE;
                    898:                maclcur = maclcur->l_fp;
1.5       millert   899:                status = (*fp)(f, n);
1.1       deraadt   900:                inmacro = FALSE;
                    901: #ifdef FKEYS
                    902:        }
1.5       millert   903: #endif /* FKEYS */
1.1       deraadt   904: cleanup:
                    905:        lp = maclcur->l_fp;
1.4       millert   906:        while (lp != maclcur) {
                    907:                np = lp->l_fp;
1.5       millert   908:                free((char *)lp);
1.4       millert   909:                lp = np;
1.1       deraadt   910:        }
1.5       millert   911:        free((char *)lp);
1.33    ! db        912:        return (status);
1.1       deraadt   913: }
                    914:
                    915: /*
                    916:  * a pair of utility functions for the above
                    917:  */
                    918: static char *
1.23      vincent   919: skipwhite(char *s)
1.1       deraadt   920: {
1.4       millert   921:        while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
                    922:                s++;
                    923:        if (*s == ';')
                    924:                *s = '\0';
1.33    ! db        925:        return (s);
1.1       deraadt   926: }
                    927:
                    928: static char *
1.23      vincent   929: parsetoken(char *s)
1.1       deraadt   930: {
                    931:        if (*s != '"') {
1.4       millert   932:                while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
                    933:                        s++;
                    934:                if (*s == ';')
                    935:                        *s = '\0';
1.1       deraadt   936:        } else
1.5       millert   937:                do {
1.15      mickey    938:                        /*
                    939:                         * Strings get special treatment.
                    940:                         * Beware: You can \ out the end of the string!
1.5       millert   941:                         */
1.4       millert   942:                        if (*s == '\\')
                    943:                                ++s;
                    944:                } while (*++s != '"' && *s != '\0');
1.33    ! db        945:        return (s);
1.1       deraadt   946: }
1.5       millert   947: #endif /* !NO_STARTUP */