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

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