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

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