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

1.24    ! vincent     1: /*     $OpenBSD: extend.c,v 1.23 2002/03/11 13:02:56 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;
                    322:        int      c, s;
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.14      mickey    348:                pep = prompt + strlcpy(prompt, p, sizeof(prompt));
1.4       millert   349:                for (;;) {
                    350:                        ewprintf("%s", prompt);
                    351:                        pep[-1] = ' ';
1.14      mickey    352:                        pep = keyname(pep, sizeof(prompt) - (pep - prompt),
                    353:                            c = getkey(FALSE));
1.8       art       354:                        if (doscan(curmap, c, &curmap) != NULL)
1.4       millert   355:                                break;
                    356:                        *pep++ = '-';
                    357:                        *pep = '\0';
                    358:                }
1.1       deraadt   359: #ifndef NO_STARTUP
                    360:        }
1.5       millert   361: #endif /* !NO_STARTUP */
1.4       millert   362:        if (unbind)
                    363:                funct = rescan;
1.1       deraadt   364:        else {
1.4       millert   365:                if ((s = eread("%s to command: ", prompt, 80, EFFUNC | EFNEW,
                    366:                    prompt)) != TRUE)
                    367:                        return s;
1.7       art       368:                if (((funct = name_function(prompt)) == NULL) ?
1.4       millert   369:                    (pref_map = name_map(prompt)) == NULL : funct == NULL) {
                    370:                        ewprintf("[No match]");
                    371:                        return FALSE;
                    372:                }
1.1       deraadt   373:        }
                    374:        return remap(curmap, c, funct, pref_map);
                    375: }
                    376:
                    377: /*
1.15      mickey    378:  * bindkey: bind key sequence to a function in the specified map.  Used by
                    379:  * excline so it can bind function keys.  To close to release to change
                    380:  * calling sequence, should just pass KEYMAP *curmap rather than
1.5       millert   381:  * KEYMAP **mapp.
                    382:  */
1.1       deraadt   383: #ifdef BINDKEY
1.5       millert   384: static int
1.23      vincent   385: bindkey(KEYMAP **mapp, const char *fname, KCHAR *keys, int kcount)
1.5       millert   386: {
                    387:        KEYMAP  *curmap = *mapp;
                    388:        KEYMAP  *pref_map = NULL;
                    389:        PF       funct;
                    390:        int      c;
1.1       deraadt   391:
1.4       millert   392:        if (fname == NULL)
                    393:                funct = rescan;
1.7       art       394:        else if (((funct = name_function(fname)) == NULL) ?
1.5       millert   395:            (pref_map = name_map(fname)) == NULL : funct == NULL) {
1.4       millert   396:                ewprintf("[No match: %s]", fname);
                    397:                return FALSE;
                    398:        }
                    399:        while (--kcount) {
1.8       art       400:                if (doscan(curmap, c = *keys++, &curmap) != NULL) {
1.13      art       401:                        if (remap(curmap, c, NULL, NULL) != TRUE)
1.4       millert   402:                                return FALSE;
1.9       art       403:                        /*
                    404:                         * XXX - Bizzarreness. remap creates an empty KEYMAP
                    405:                         *       that the last key is supposed to point to.
                    406:                         */
                    407:                        curmap = ele->k_prefmap;
1.4       millert   408:                }
1.1       deraadt   409:        }
1.12      art       410:        (void)doscan(curmap, c = *keys, NULL);
1.1       deraadt   411:        return remap(curmap, c, funct, pref_map);
                    412: }
1.3       millert   413:
                    414: #ifdef FKEYS
                    415: /*
                    416:  * Wrapper for bindkey() that converts escapes.
                    417:  */
                    418: int
1.23      vincent   419: dobindkey(KEYMAP *map, const char *func, const char *str)
1.3       millert   420: {
1.5       millert   421:        int      i;
1.3       millert   422:
                    423:        for (i = 0; *str && i < MAXKEY; i++) {
                    424:                /* XXX - convert numbers w/ strol()? */
                    425:                if (*str != '\\')
                    426:                        key.k_chars[i] = *str;
                    427:                else {
1.4       millert   428:                        switch (*++str) {
                    429:                        case 't':
                    430:                        case 'T':
1.3       millert   431:                                key.k_chars[i] = '\t';
                    432:                                break;
1.4       millert   433:                        case 'n':
                    434:                        case 'N':
1.3       millert   435:                                key.k_chars[i] = '\n';
                    436:                                break;
1.4       millert   437:                        case 'r':
                    438:                        case 'R':
1.3       millert   439:                                key.k_chars[i] = '\r';
                    440:                                break;
1.4       millert   441:                        case 'e':
                    442:                        case 'E':
1.3       millert   443:                                key.k_chars[i] = CCHR('[');
                    444:                                break;
                    445:                        }
                    446:                }
                    447:                str++;
                    448:        }
                    449:        key.k_count = i;
1.4       millert   450:        return (bindkey(&map, func, key.k_chars, key.k_count));
1.3       millert   451: }
1.5       millert   452: #endif /* FKEYS */
                    453: #endif /* BINDKEY */
1.1       deraadt   454:
                    455: /*
                    456:  * This function modifies the fundamental keyboard map.
                    457:  */
1.4       millert   458: /* ARGSUSED */
                    459: int
1.23      vincent   460: bindtokey(int f, int n)
1.1       deraadt   461: {
1.11      art       462:        return dobind(fundamental_map, "Global set key: ", FALSE);
1.1       deraadt   463: }
                    464:
                    465: /*
                    466:  * This function modifies the current mode's keyboard map.
                    467:  */
1.4       millert   468: /* ARGSUSED */
                    469: int
1.23      vincent   470: localbind(int f, int n)
1.1       deraadt   471: {
1.15      mickey    472:        return dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
1.5       millert   473:            "Local set key: ", FALSE);
1.1       deraadt   474: }
                    475:
                    476: /*
                    477:  * This function redefines a key in any keymap.
                    478:  */
1.4       millert   479: /* ARGSUSED */
                    480: int
1.19      vincent   481: define_key(int f, int n)
1.1       deraadt   482: {
1.19      vincent   483:        static char buf[48];
                    484:        char tmp[32];
                    485:        KEYMAP *mp;
1.4       millert   486:
1.19      vincent   487:        strlcpy(buf, "Define key map: ", sizeof buf);
                    488:        if (eread(buf, tmp, sizeof tmp, EFNEW) != TRUE)
1.4       millert   489:                return FALSE;
1.19      vincent   490:        strlcat(buf, tmp, sizeof buf);
                    491:        if ((mp = name_map(tmp)) == NULL) {
                    492:                ewprintf("Unknown map %s", tmp);
1.4       millert   493:                return FALSE;
                    494:        }
1.19      vincent   495:        strlcat(buf, "key: ", sizeof buf);
                    496:
1.10      art       497:        return dobind(mp, buf, FALSE);
1.1       deraadt   498: }
                    499:
1.4       millert   500: int
1.23      vincent   501: unbindtokey(int f, int n)
1.1       deraadt   502: {
1.11      art       503:        return dobind(fundamental_map, "Global unset key: ", TRUE);
1.1       deraadt   504: }
                    505:
1.4       millert   506: int
1.1       deraadt   507: localunbind(f, n)
1.4       millert   508:        int f, n;
1.1       deraadt   509: {
1.4       millert   510:        return dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
                    511:            "Local unset key: ", TRUE);
1.1       deraadt   512: }
                    513:
                    514: /*
1.15      mickey    515:  * Extended command. Call the message line routine to read in the command
                    516:  * name and apply autocompletion to it. When it comes back, look the name
                    517:  * up in the symbol table and run the command if it is found.  Print an
1.5       millert   518:  * error if there is anything wrong.
1.1       deraadt   519:  */
1.4       millert   520: int
1.23      vincent   521: extend(int f, int n)
1.1       deraadt   522: {
1.5       millert   523:        PF       funct;
                    524:        int      s;
                    525:        char     xname[NXNAME];
1.4       millert   526:
                    527:        if (!(f & FFARG))
                    528:                s = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC);
                    529:        else
                    530:                s = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n);
                    531:        if (s != TRUE)
                    532:                return s;
                    533:        if ((funct = name_function(xname)) != NULL) {
1.1       deraadt   534: #ifndef NO_MACRO
1.4       millert   535:                if (macrodef) {
1.5       millert   536:                        LINE    *lp = maclcur;
1.4       millert   537:                        macro[macrocount - 1].m_funct = funct;
                    538:                        maclcur = lp->l_bp;
                    539:                        maclcur->l_fp = lp->l_fp;
1.5       millert   540:                        free((char *)lp);
1.4       millert   541:                }
1.5       millert   542: #endif /* !NO_MACRO */
                    543:                return (*funct)(f, n);
1.1       deraadt   544:        }
                    545:        ewprintf("[No match]");
                    546:        return FALSE;
                    547: }
                    548:
                    549: #ifndef NO_STARTUP
                    550: /*
                    551:  * Define the commands needed to do startup-file processing.
                    552:  * This code is mostly a kludge just so we can get startup-file processing.
                    553:  *
                    554:  * If you're serious about having this code, you should rewrite it.
                    555:  * To wit:
                    556:  *     It has lots of funny things in it to make the startup-file look
                    557:  *     like a GNU startup file; mostly dealing with parens and semicolons.
                    558:  *     This should all vanish.
                    559:  *
                    560:  * We define eval-expression because it's easy.         It can make
                    561:  * *-set-key or define-key set an arbitrary key sequence, so it isn't
                    562:  * useless.
                    563:  */
                    564:
                    565: /*
                    566:  * evalexpr - get one line from the user, and run it.
                    567:  */
1.4       millert   568: /* ARGSUSED */
                    569: int
1.23      vincent   570: evalexpr(int f, int n)
1.1       deraadt   571: {
1.5       millert   572:        int      s;
                    573:        char     exbuf[128];
1.1       deraadt   574:
                    575:        if ((s = ereply("Eval: ", exbuf, 128)) != TRUE)
                    576:                return s;
                    577:        return excline(exbuf);
                    578: }
1.4       millert   579:
1.1       deraadt   580: /*
1.15      mickey    581:  * evalbuffer - evaluate the current buffer as line commands. Useful for
1.5       millert   582:  * testing startup files.
1.1       deraadt   583:  */
1.4       millert   584: /* ARGSUSED */
                    585: int
1.23      vincent   586: evalbuffer(int f, int n)
1.1       deraadt   587: {
1.5       millert   588:        LINE            *lp;
                    589:        BUFFER          *bp = curbp;
                    590:        int              s;
                    591:        static char      excbuf[128];
1.1       deraadt   592:
                    593:        for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
1.4       millert   594:                if (llength(lp) >= 128)
                    595:                        return FALSE;
1.12      art       596:                (void)strncpy(excbuf, ltext(lp), llength(lp));
1.5       millert   597:
                    598:                /* make sure it's terminated */
                    599:                excbuf[llength(lp)] = '\0';
1.4       millert   600:                if ((s = excline(excbuf)) != TRUE)
                    601:                        return s;
1.1       deraadt   602:        }
                    603:        return TRUE;
                    604: }
1.4       millert   605:
1.1       deraadt   606: /*
                    607:  * evalfile - go get a file and evaluate it as line commands. You can
                    608:  *     go get your own startup file if need be.
                    609:  */
1.4       millert   610: /* ARGSUSED */
                    611: int
1.23      vincent   612: evalfile(int f, int n)
1.1       deraadt   613: {
1.5       millert   614:        int      s;
                    615:        char     fname[NFILEN];
1.1       deraadt   616:
                    617:        if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
                    618:                return s;
                    619:        return load(fname);
                    620: }
                    621:
                    622: /*
                    623:  * load - go load the file name we got passed.
                    624:  */
1.4       millert   625: int
1.23      vincent   626: load(const char *fname)
1.4       millert   627: {
1.5       millert   628:        int      s = TRUE;
1.18      matthieu  629:        int      nbytes = 0;
1.5       millert   630:        char     excbuf[128];
1.1       deraadt   631:
                    632:        if ((fname = adjustname(fname)) == NULL)
1.5       millert   633:                /* just to be careful */
                    634:                return FALSE;
1.1       deraadt   635:
1.13      art       636:        if (ffropen(fname, NULL) != FIOSUC)
1.4       millert   637:                return FALSE;
1.5       millert   638:
1.4       millert   639:        while ((s = ffgetline(excbuf, sizeof(excbuf) - 1, &nbytes)) == FIOSUC) {
1.1       deraadt   640:                excbuf[nbytes] = '\0';
                    641:                if (excline(excbuf) != TRUE) {
                    642:                        s = FIOERR;
                    643:                        ewprintf("Error loading file %s", fname);
                    644:                        break;
                    645:                }
                    646:        }
1.13      art       647:        (void)ffclose(NULL);
1.1       deraadt   648:        excbuf[nbytes] = '\0';
1.4       millert   649:        if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE))
1.1       deraadt   650:                return FALSE;
                    651:        return TRUE;
                    652: }
                    653:
                    654: /*
1.15      mickey    655:  * excline - run a line from a load file or eval-expression.  if FKEYS is
                    656:  * defined, duplicate functionallity of dobind so function key values don't
1.5       millert   657:  * have to fit in type char.
1.1       deraadt   658:  */
1.4       millert   659: int
1.23      vincent   660: excline(char *line)
1.1       deraadt   661: {
1.5       millert   662:        PF       fp;
                    663:        LINE    *lp, *np;
                    664:        int      status, c, f, n;
1.22      ho        665:        char    *funcp, *tmp;
1.5       millert   666:        char    *argp = NULL;
1.22      ho        667:        long     nl;
1.5       millert   668: #ifdef FKEYS
                    669:        int      bind;
                    670:        KEYMAP  *curmap;
                    671: #define BINDARG                0  /* this arg is key to bind (local/global set key) */
                    672: #define        BINDNO          1  /* not binding or non-quoted BINDARG */
                    673: #define BINDNEXT       2  /* next arg " (define-key) */
                    674: #define BINDDO         3  /* already found key to bind */
                    675: #define BINDEXT                1  /* space for trailing \0 */
                    676: #else /* FKEYS */
                    677: #define BINDEXT                0
                    678: #endif /* FKEYS */
                    679:
                    680:        lp = NULL;
1.1       deraadt   681:
1.4       millert   682:        if (macrodef || inmacro) {
1.1       deraadt   683:                ewprintf("Not now!");
                    684:                return FALSE;
                    685:        }
                    686:        f = 0;
                    687:        n = 1;
                    688:        funcp = skipwhite(line);
1.4       millert   689:        if (*funcp == '\0')
                    690:                return TRUE;    /* No error on blank lines */
1.1       deraadt   691:        line = parsetoken(funcp);
                    692:        if (*line != '\0') {
                    693:                *line++ = '\0';
                    694:                line = skipwhite(line);
1.20      vincent   695:                if (ISDIGIT(*line) || *line == '-') {
1.1       deraadt   696:                        argp = line;
                    697:                        line = parsetoken(line);
                    698:                }
                    699:        }
                    700:        if (argp != NULL) {
                    701:                f = FFARG;
1.22      ho        702:                nl = strtol(argp, &tmp, 10);
1.20      vincent   703:                if (*tmp != '\0')
                    704:                        return FALSE;
1.22      ho        705:                if (nl >= INT_MAX || nl <= INT_MIN)
1.20      vincent   706:                        return FALSE;
1.22      ho        707:                n = (int)nl;
1.1       deraadt   708:        }
1.4       millert   709:        if ((fp = name_function(funcp)) == NULL) {
                    710:                ewprintf("Unknown function: %s", funcp);
                    711:                return FALSE;
1.1       deraadt   712:        }
                    713: #ifdef FKEYS
1.4       millert   714:        if (fp == bindtokey || fp == unbindtokey) {
1.1       deraadt   715:                bind = BINDARG;
1.11      art       716:                curmap = fundamental_map;
1.4       millert   717:        } else if (fp == localbind || fp == localunbind) {
1.1       deraadt   718:                bind = BINDARG;
                    719:                curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.4       millert   720:        } else if (fp == define_key)
                    721:                bind = BINDNEXT;
                    722:        else
                    723:                bind = BINDNO;
1.5       millert   724: #endif /* FKEYS */
                    725:        /* Pack away all the args now... */
1.4       millert   726:        if ((np = lalloc(0)) == FALSE)
                    727:                return FALSE;
1.1       deraadt   728:        np->l_fp = np->l_bp = maclcur = np;
                    729:        while (*line != '\0') {
                    730:                argp = skipwhite(line);
1.4       millert   731:                if (*argp == '\0')
                    732:                        break;
1.1       deraadt   733:                line = parsetoken(argp);
                    734:                if (*argp != '"') {
1.4       millert   735:                        if (*argp == '\'')
                    736:                                ++argp;
1.20      vincent   737:                        if ((lp = lalloc((int) (line - argp) + BINDEXT)) ==
                    738:                            NULL) {
1.4       millert   739:                                status = FALSE;
                    740:                                goto cleanup;
                    741:                        }
1.5       millert   742:                        bcopy(argp, ltext(lp), (int)(line - argp));
1.1       deraadt   743: #ifdef FKEYS
1.5       millert   744:                        /* don't count BINDEXT */
                    745:                        lp->l_used--;
1.4       millert   746:                        if (bind == BINDARG)
                    747:                                bind = BINDNO;
1.5       millert   748: #endif /* FKEYS */
                    749:                } else {
                    750:                        /* quoted strings are special */
1.4       millert   751:                        ++argp;
1.1       deraadt   752: #ifdef FKEYS
1.4       millert   753:                        if (bind != BINDARG) {
1.5       millert   754: #endif /* FKEYS */
                    755:                                lp = lalloc((int)(line - argp) + BINDEXT);
1.4       millert   756:                                if (lp == NULL) {
                    757:                                        status = FALSE;
                    758:                                        goto cleanup;
                    759:                                }
                    760:                                lp->l_used = 0;
1.1       deraadt   761: #ifdef FKEYS
1.4       millert   762:                        } else {
                    763:                                key.k_count = 0;
1.1       deraadt   764:                        }
1.5       millert   765: #endif /* FKEYS */
1.4       millert   766:                        while (*argp != '"' && *argp != '\0') {
                    767:                                if (*argp != '\\')
                    768:                                        c = *argp++;
                    769:                                else {
                    770:                                        switch (*++argp) {
                    771:                                        case 't':
                    772:                                        case 'T':
                    773:                                                c = CCHR('I');
                    774:                                                break;
                    775:                                        case 'n':
                    776:                                        case 'N':
                    777:                                                c = CCHR('J');
                    778:                                                break;
                    779:                                        case 'r':
                    780:                                        case 'R':
                    781:                                                c = CCHR('M');
                    782:                                                break;
                    783:                                        case 'e':
                    784:                                        case 'E':
                    785:                                                c = CCHR('[');
                    786:                                                break;
                    787:                                        case '^':
                    788:                                                /*
                    789:                                                 * split into two statements
                    790:                                                 * due to bug in OSK cpp
                    791:                                                 */
                    792:                                                c = CHARMASK(*++argp);
                    793:                                                c = ISLOWER(c) ?
                    794:                                                    CCHR(TOUPPER(c)) : CCHR(c);
                    795:                                                break;
                    796:                                        case '0':
                    797:                                        case '1':
                    798:                                        case '2':
                    799:                                        case '3':
                    800:                                        case '4':
                    801:                                        case '5':
                    802:                                        case '6':
                    803:                                        case '7':
                    804:                                                c = *argp - '0';
1.15      mickey    805:                                                if (argp[1] <= '7' &&
1.5       millert   806:                                                    argp[1] >= '0') {
1.4       millert   807:                                                        c <<= 3;
                    808:                                                        c += *++argp - '0';
                    809:                                                        if (argp[1] <= '7' &&
                    810:                                                            argp[1] >= '0') {
                    811:                                                                c <<= 3;
                    812:                                                                c += *++argp
                    813:                                                                    - '0';
                    814:                                                        }
                    815:                                                }
                    816:                                                break;
                    817: #ifdef FKEYS
                    818:                                        case 'f':
                    819:                                        case 'F':
                    820:                                                c = *++argp - '0';
                    821:                                                if (ISDIGIT(argp[1])) {
                    822:                                                        c *= 10;
                    823:                                                        c += *++argp - '0';
                    824:                                                }
                    825:                                                c += KFIRST;
                    826:                                                break;
1.5       millert   827: #endif /* FKEYS */
1.4       millert   828:                                        default:
                    829:                                                c = CHARMASK(*argp);
                    830:                                                break;
                    831:                                        }
                    832:                                        argp++;
                    833:                                }
1.1       deraadt   834: #ifdef FKEYS
1.4       millert   835:                                if (bind == BINDARG)
                    836:                                        key.k_chars[key.k_count++] = c;
                    837:                                else
1.5       millert   838: #endif /* FKEYS */
1.4       millert   839:                                        lp->l_text[lp->l_used++] = c;
                    840:                        }
                    841:                        if (*line)
                    842:                                line++;
1.1       deraadt   843:                }
                    844: #ifdef FKEYS
1.4       millert   845:                switch (bind) {
                    846:                case BINDARG:
1.1       deraadt   847:                        bind = BINDDO;
                    848:                        break;
1.4       millert   849:                case BINDNEXT:
1.1       deraadt   850:                        lp->l_text[lp->l_used] = '\0';
1.10      art       851:                        if ((curmap = name_map(lp->l_text)) == NULL) {
1.4       millert   852:                                ewprintf("No such mode: %s", lp->l_text);
                    853:                                status = FALSE;
1.5       millert   854:                                free((char *)lp);
1.4       millert   855:                                goto cleanup;
1.1       deraadt   856:                        }
1.5       millert   857:                        free((char *)lp);
1.1       deraadt   858:                        bind = BINDARG;
                    859:                        break;
1.4       millert   860:                default:
1.5       millert   861: #endif /* FKEYS */
1.1       deraadt   862:                        lp->l_fp = np->l_fp;
                    863:                        lp->l_bp = np;
                    864:                        np->l_fp = lp;
                    865:                        np = lp;
                    866: #ifdef FKEYS
                    867:                }
1.5       millert   868: #endif /* FKEYS */
1.1       deraadt   869:        }
                    870: #ifdef FKEYS
1.4       millert   871:        switch (bind) {
                    872:        default:
1.1       deraadt   873:                ewprintf("Bad args to set key");
                    874:                status = FALSE;
                    875:                break;
1.4       millert   876:        case BINDDO:
                    877:                if (fp != unbindtokey && fp != localunbind) {
                    878:                        lp->l_text[lp->l_used] = '\0';
                    879:                        status = bindkey(&curmap, lp->l_text, key.k_chars,
                    880:                            key.k_count);
1.13      art       881:                } else {
                    882:                        status = bindkey(&curmap, NULL, key.k_chars,
1.4       millert   883:                            key.k_count);
1.13      art       884:                }
1.1       deraadt   885:                break;
1.4       millert   886:        case BINDNO:
1.5       millert   887: #endif /* FKEYS */
1.1       deraadt   888:                inmacro = TRUE;
                    889:                maclcur = maclcur->l_fp;
1.5       millert   890:                status = (*fp)(f, n);
1.1       deraadt   891:                inmacro = FALSE;
                    892: #ifdef FKEYS
                    893:        }
1.5       millert   894: #endif /* FKEYS */
1.1       deraadt   895: cleanup:
                    896:        lp = maclcur->l_fp;
1.4       millert   897:        while (lp != maclcur) {
                    898:                np = lp->l_fp;
1.5       millert   899:                free((char *)lp);
1.4       millert   900:                lp = np;
1.1       deraadt   901:        }
1.5       millert   902:        free((char *)lp);
1.1       deraadt   903:        return status;
                    904: }
                    905:
                    906: /*
                    907:  * a pair of utility functions for the above
                    908:  */
                    909: static char *
1.23      vincent   910: skipwhite(char *s)
1.1       deraadt   911: {
1.4       millert   912:        while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
                    913:                s++;
                    914:        if (*s == ';')
                    915:                *s = '\0';
1.1       deraadt   916:        return s;
                    917: }
                    918:
                    919: static char *
1.23      vincent   920: parsetoken(char *s)
1.1       deraadt   921: {
                    922:        if (*s != '"') {
1.4       millert   923:                while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
                    924:                        s++;
                    925:                if (*s == ';')
                    926:                        *s = '\0';
1.1       deraadt   927:        } else
1.5       millert   928:                do {
1.15      mickey    929:                        /*
                    930:                         * Strings get special treatment.
                    931:                         * Beware: You can \ out the end of the string!
1.5       millert   932:                         */
1.4       millert   933:                        if (*s == '\\')
                    934:                                ++s;
                    935:                } while (*++s != '"' && *s != '\0');
1.1       deraadt   936:        return s;
                    937: }
1.5       millert   938: #endif /* !NO_STARTUP */