[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.36

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