/* * Extended (M-X) commands. */ #include "def.h" /* * This function modifies the keyboard * binding table, by adjusting the entries in the * big "bindings" array. Most of the grief deals with the * prompting for additional arguments. */ extern KEY *kbdnext ; /*ARGSUSED*/ bindtokey(f, n, k) { register int s; register SYMBOL *sp; int c; char xname[NXNAME]; if (kbdmop == NULL) ewprintf("Set key globally: ") ; c = (int) getkey(0); if ((s=eread("Set key %c to command: ", xname, NXNAME, EFNEW|EFFUNC, #ifdef VARARGS c #else (char *) &c, (char *) NULL #endif )) != TRUE) return (s); if ((sp=symlookup(xname)) == NULL) { ewprintf("[No match]"); return (FALSE); } binding[(KEY) c] = sp; /* rebind new. */ return (TRUE); } /* * User function to unbind keys. Just call the unbind we already have. */ /*ARGSUSED*/ unsetkey(f, n, k) { register KEY key; if (kbdmop == NULL) ewprintf("Unset key globally: ") ; key = getkey(0); if (key == (KCTRL|'G') || key == (KCTLX|KCTRL|'G') || key == (KMETA|KCTRL|'G')) { (VOID) ctrlg(FALSE, 1, KRANDOM); return ABORT; } binding[key] = NULL; return TRUE; } /* * Extended command. Call the message line * routine to read in the command name and apply autocompletion * to it. When it comes back, look the name up in the symbol table * and run the command if it is found and has the right type. * Print an error if there is anything wrong. */ /*ARGSUSED*/ extend(f, n, k) { register SYMBOL *sp; register int s; char xname[NXNAME]; if (f == FALSE) s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC #ifndef VARARGS , (char *) NULL #endif ) ; else s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC, #ifdef VARARGS n #else (char *) &n, (char *) NULL #endif ) ; if (s != TRUE) return (s); if ((sp=symlookup(xname)) != NULL) return ((*sp->s_funcp)(f, n, KRANDOM)); ewprintf("[No match]"); return FALSE; } /* * Read a key from the keyboard, and look it * up in the binding table. Display the name of the function * currently bound to the key. Say that the key is not bound * if it is indeed not bound, or if the type is not a * "builtin". This is a bit of overkill, because this is the * only kind of function there is. */ /*ARGSUSED*/ desckey(f, n, k) { register SYMBOL *sp; register KEY c; if (kbdmop == NULL) ewprintf("Describe key briefly: "); c = getkey(0); if (kbdmop != NULL) return TRUE; if ((sp=binding[c]) == NULL) ewprintf("%c is undefined", (int) c); else ewprintf("%c runs the command %s", (int) c, sp->s_name); return (TRUE); } /* * This function creates a table, listing all * of the command keys and their current bindings, and stores * the table in the standard pop-op buffer (the one used by the * directory list command, the buffer list command, etc.). This * lets MicroEMACS produce it's own wall chart. The bindings to * "ins-self" are only displayed if there is an argument. */ /*ARGSUSED*/ wallchart(f, n, k) { register int key; register SYMBOL *sp; register char *cp1; register char *cp2; BUFFER *bp; char buf[64]; bp = bfind("*Help*", TRUE); if (bclear(bp) != TRUE) /* Clear it out. */ return TRUE; for (key=0; keys_name, "self-insert-command")!=0)) { keyname(buf, key); cp1 = &buf[0]; /* Find end. */ while (*cp1 != 0) ++cp1; while (cp1 < &buf[32]) /* Goto column 32. */ *cp1++ = ' '; cp2 = sp->s_name; /* Add function name. */ while (*cp1++ = *cp2++) ; if (addline(bp, buf) == FALSE) return (FALSE); } } return popbuf(bp) == NULL ? FALSE : TRUE; } #ifdef STARTUP /* * Define the commands needed to do startup-file processing. * This code is mostly a kludge just so we can get startup-file processing. * * If you're serious about having this code, you should rewrite it. * To wit: * It has lots of funny things in it to make the startup-file look * like a GNU startup file; mostly dealing with parens and semicolons. * This should all vanish. * * It uses the same buffer as keyboard macros. The fix is easy (make * a new function "execmacro" that takes a pointer to char and * does what ctlxe does on it. Make ctlxe and excline both call it.) * but would slow down the non-micro version. * * We define eval-expression because it's easy. It's pretty useless, * since it duplicates the functionality of execute-extended-command. * All of this is just to support startup files, and should be turned * off for micros. */ /* * evalexpr - get one line from the user, and run it. Identical in function * to extend, but easy. */ /*ARGSUSED*/ evalexpr(f, n, k) { register int s; char exbuf[NKBDM]; if ((s = ereply("Eval: ", exbuf, NKBDM)) != TRUE) return s; return excline(exbuf); } /* * evalbuffer - evaluate the current buffer as line commands. Useful * for testing startup files. */ /*ARGSUSED*/ evalbuffer(f, n, k) { register LINE *lp; register BUFFER *bp = curbp; register int s; static char excbuf[NKBDM]; char *strncpy(); for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) { if (llength(lp) >= NKBDM + 1) return FALSE ; (VOID) strncpy(excbuf, ltext(lp), NKBDM); if ((s = excline(excbuf)) != TRUE) return s; } return TRUE; } /* * evalfile - go get a file and evaluate it as line commands. You can * go get your own startup file if need be. */ /*ARGSUSED*/ evalfile(f, n, k) { register int s; char fname[NFILEN]; if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE) return s; return load(fname); } /* * load - go load the file name we got passed. */ load(fname) char *fname; { register int s; char excbuf[NKBDM]; if (((s = ffropen(fname)) == FIOERR) || (s == FIOFNF)) return FALSE; while ((s = ffgetline(excbuf, NKBDM)) == FIOSUC) if (excline(excbuf) != TRUE) break; (VOID) ffclose(); return s == FIOEOF; } int myupper(c) int c ; { if ('a'<=c&&c<='z') return(c - ('a'-'A')) ; else return(c) ; } char *skipwhite(s) char *s ; { while (*s && *s <= ' ') s++ ; return(s) ; } /* * excline - run a line from a load file or eval-expression. * Now broken into two pieces; the piece which gets the * line into the macro buffer starting at kbdnext, and the * part which decides what to do with it. * * This has been rewritten considerably. Now, everything * must be typed explicitly, just as if it were coming in * from the keyboard. Thus, you might have: * * ^U 10 $X 'kill-line' * * Anything in quotes is taken verbatim, including spaces. * A ^ is combined with the preceding character into a control * character. A \nnn is turned into that character. White * space is ignored outside of quotes. A \" gets turned into * a single quote. $ gets turned into a meta. Note that * we currently allow macros to be defined by this. The end of * a ' string gets turned into a null, as it is then an argument * to something. */ /* Don't want to get the objects in isdigit.c just for this */ #define isdigit(c) (((c) >= '0') && ((c) <= '9')) excline(line) register char *line; { register char *funcp, *argp = NULL; int status; KEY *kbdst, *p ; int inquote ; int buckies ; int c ; long param ; if (kbdmip > kbdnext) kbdnext = kbdmip + 1 ; kbdst = kbdnext + 10 ; inquote = 0 ; param = 0 ; for (funcp = line; *funcp !=0 && kbdst < &kbdm[NKBDM-6]; funcp++) { buckies = 0 ; floop: if (!inquote) funcp = skipwhite(funcp) ; if (*funcp != 0) { while (*funcp == '^' || *funcp == '$') { if (*funcp == '^') buckies |= KCTRL ; else buckies |= KMETA ; funcp++ ; if (!inquote) funcp = skipwhite(funcp) ; if ((c=myupper(*funcp))=='X' && (buckies & KCTRL)) { buckies = KCTLX ; funcp++ ; } } gloop: if (buckies) { if (!inquote) funcp = skipwhite(funcp) ; if ((c = myupper(*funcp))) { if (c=='U' && (buckies & KCTRL)) { if (param == 0) param = 4 ; else param <<= 2 ; } else { if (param != 0) { *kbdst++ = (KCTRL | 'U') ; *kbdst++ = param ; param = 0 ; } *kbdst++ = buckies | c ; } funcp++ ; buckies = 0 ; goto floop ; } else { ewprintf("Need alpha after $ or ^") ; return(FALSE) ; } } if (param != 0) { if (!inquote) funcp = skipwhite(funcp) ; if (isdigit(*funcp)) { param = 0 ; while (isdigit(*funcp)) { param = param * 10 + *funcp++ - '0' ; } } *kbdst++ = (KCTRL | 'U') ; *kbdst++ = param ; param = 0 ; buckies = 0 ; goto floop ; } if (*funcp == '"' || *funcp == '\'') { if (*funcp == inquote) { if (inquote == '\'') *kbdst++ = 0 ; inquote = 0 ; } else if (inquote == 0) { inquote = *funcp ; } else { *kbdst++ = *funcp ; } } else if (*funcp == '\\') { funcp++ ; if (*funcp == 'F' || *funcp == 'f') { funcp++ ; c = 0 ; while (isdigit(*funcp)) c = 10 * c + *funcp++ - '0' ; c += KFIRST ; if (c > KLAST) c = KFIRST ; *kbdst++ = c ; } else if ('0' <= *funcp && *funcp <= '7') { c = 0 ; while (isdigit(*funcp)) c = 10 * c + *funcp++ - '0' ; *kbdst++ = c ; } else { *kbdst++ = *funcp ; } } else { *kbdst++ = *funcp ; } } if (*funcp == 0) break ; } if (*funcp != 0) return(FALSE) ; *kbdst++ = (KEY) (KCTLX|')'); *kbdst++ = (KEY) (KCTLX|')'); *kbdst++ = '\0'; status = ctlxe(FALSE, 1, KMACCUR); return status; } #endif STARTUP