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

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