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

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