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

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