This is bind.c in view mode; [Download] [Up]
/* This file is for functions having to do with key bindings, descriptions, help commands and startup file. written 11-feb-86 by Daniel Lawrence */ #include <stdio.h> #include "estruct.h" #include "etype.h" #include "edef.h" #include "elang.h" #include "epath.h" PASCAL NEAR help(f, n) /* give me some help!!!! bring up a fake buffer and read the help file into it with view mode */ { register BUFFER *bp; /* buffer pointer to help */ char *fname; /* file name of help file */ /* first check if we are already here */ bp = bfind("emacs.hlp", FALSE, BFINVS); if (bp == NULL) { #if SHARED strcpy(tname, pathname[1]); fname = flook(tname, FALSE); #else fname = flook(pathname[1], FALSE); #endif if (fname == NULL) { mlwrite(TEXT12); /* "[Help file is not online]" */ return(FALSE); } } /* split the current window to make room for the help stuff */ if (splitwind(FALSE, 1) == FALSE) return(FALSE); if (bp == NULL) { /* and read the stuff in */ if (getfile(fname, FALSE) == FALSE) return(FALSE); } else swbuffer(bp); /* make this window in VIEW mode, update all mode lines */ curwp->w_bufp->b_mode |= MDVIEW; curwp->w_bufp->b_flag |= BFINVS; upmode(); return(TRUE); } PASCAL NEAR deskey(f, n) /* describe the command for a certain key */ { register int c; /* key to describe */ register char *ptr; /* string pointer to scan output strings */ char outseq[NSTRING]; /* output buffer for command sequence */ /* prompt the user to type us a key to describe */ mlwrite(TEXT13); /* ": describe-key " */ /* get the command sequence to describe change it to something we can print as well */ cmdstr(c = getckey(FALSE), &outseq[0]); /* and dump it out */ ostring(outseq); ostring(" "); /* find the right ->function */ if ((ptr = getfname(getbind(c))) == NULL) ptr = "Not Bound"; /* output the command sequence */ ostring(ptr); } /* bindtokey: add a new key to the key binding table */ PASCAL NEAR bindtokey(f, n) int f, n; /* command arguments [IGNORED] */ { register unsigned int c;/* command key to bind */ register int (PASCAL NEAR *kfunc)();/* ptr to the requested function to bind to */ register KEYTAB *ktp; /* pointer into the command table */ register int found; /* matched command flag */ char outseq[80]; /* output buffer for keystroke sequence */ /* prompt the user to type in a key to bind */ /* get the function name to bind it to */ kfunc = getname(TEXT15); /* ": bind-to-key " */ if (kfunc == NULL) { mlwrite(TEXT16); /* "[No such function]" */ return(FALSE); } ostring(" "); TTflush(); /* get the command sequence to bind */ c = getckey((kfunc == meta) || (kfunc == cex) || (kfunc == unarg) || (kfunc == ctrlg)); /* change it to something we can print as well */ cmdstr(c, &outseq[0]); /* and dump it out */ ostring(outseq); /* if the function is a unique prefix key */ if (kfunc == unarg || kfunc == ctrlg) { /* search for an existing binding for the prefix key */ ktp = &keytab[0]; while (ktp->k_ptr.fp != NULL) { if (ktp->k_ptr.fp == kfunc) unbindchar(ktp->k_code); ++ktp; } /* reset the appropriate global prefix variable */ if (kfunc == unarg) reptc = c; if (kfunc == ctrlg) abortc = c; } /* search the table to see if it exists */ ktp = &keytab[0]; found = FALSE; while (ktp->k_ptr.fp != NULL) { if (ktp->k_code == c) { found = TRUE; break; } ++ktp; } if (found) { /* it exists, just change it then */ ktp->k_ptr.fp = kfunc; ktp->k_type = BINDFNC; } else { /* otherwise we need to add it to the end */ /* if we run out of binding room, bitch */ if (ktp >= &keytab[NBINDS]) { mlwrite(TEXT17); /* "Binding table FULL!" */ return(FALSE); } ktp->k_code = c; /* add keycode */ ktp->k_ptr.fp = kfunc; /* and the function pointer */ ktp->k_type = BINDFNC; /* and the binding type */ ++ktp; /* and make sure the next is null */ ktp->k_code = 0; ktp->k_type = BINDNUL; ktp->k_ptr.fp = NULL; } /* if we have rebound the meta key, make the search terminator follow it */ if (kfunc == meta) sterm = c; return(TRUE); } /* macrotokey: Bind a key to a macro in the key binding table */ PASCAL NEAR macrotokey(f, n) int f, n; /* command arguments [IGNORED] */ { register unsigned int c;/* command key to bind */ register BUFFER *kmacro;/* ptr to buffer of macro to bind to key */ register KEYTAB *ktp; /* pointer into the command table */ register int found; /* matched command flag */ register int status; /* error return */ char outseq[80]; /* output buffer for keystroke sequence */ char bufn[NBUFN]; /* buffer to hold macro name */ /* get the buffer name to use */ if ((status=mlreply(TEXT215, &bufn[1], NBUFN-2)) != TRUE) /* ": macro-to-key " */ return(status); /* build the responce string for later */ strcpy(outseq, TEXT215); /* ": macro-to-key " */ strcat(outseq, &bufn[1]); /* translate it to a buffer pointer */ bufn[0] = '['; strcat(bufn, "]"); if ((kmacro=bfind(bufn, FALSE, 0)) == NULL) { mlwrite(TEXT130); /* "Macro not defined"*/ return(FALSE); } strcat(outseq, " "); mlwrite(outseq); /* get the command sequence to bind */ c = getckey(FALSE); /* change it to something we can print as well */ cmdstr(c, &outseq[0]); /* and dump it out */ ostring(outseq); /* search the table to see if it exists */ ktp = &keytab[0]; found = FALSE; while (ktp->k_type != BINDNUL) { if (ktp->k_code == c) { found = TRUE; break; } ++ktp; } if (found) { /* it exists, just change it then */ ktp->k_ptr.buf = kmacro; ktp->k_type = BINDBUF; } else { /* otherwise we need to add it to the end */ /* if we run out of binding room, bitch */ if (ktp >= &keytab[NBINDS]) { mlwrite(TEXT17); /* "Binding table FULL!" */ return(FALSE); } ktp->k_code = c; /* add keycode */ ktp->k_ptr.buf = kmacro; /* and the function pointer */ ktp->k_type = BINDBUF; /* and the binding type */ ++ktp; /* and make sure the next is null */ ktp->k_code = 0; ktp->k_type = BINDNUL; ktp->k_ptr.fp = NULL; } return(TRUE); } /* unbindkey: delete a key from the key binding table */ PASCAL NEAR unbindkey(f, n) int f, n; /* command arguments [IGNORED] */ { register int c; /* command key to unbind */ char outseq[80]; /* output buffer for keystroke sequence */ /* prompt the user to type in a key to unbind */ mlwrite(TEXT18); /* ": unbind-key " */ /* get the command sequence to unbind */ c = getckey(FALSE); /* get a command sequence */ /* change it to something we can print as well */ cmdstr(c, &outseq[0]); /* and dump it out */ ostring(outseq); /* if it isn't bound, bitch */ if (unbindchar(c) == FALSE) { mlwrite(TEXT19); /* "[Key not bound]" */ return(FALSE); } return(TRUE); } PASCAL NEAR unbindchar(c) int c; /* command key to unbind */ { register KEYTAB *ktp; /* pointer into the command table */ register KEYTAB *sktp; /* saved pointer into the command table */ register int found; /* matched command flag */ /* search the table to see if the key exists */ ktp = &keytab[0]; found = FALSE; while (ktp->k_type != BINDNUL) { if (ktp->k_code == c) { found = TRUE; break; } ++ktp; } /* if it isn't bound, bitch */ if (!found) return(FALSE); /* save the pointer and scan to the end of the table */ sktp = ktp; while (ktp->k_ptr.fp != NULL) ++ktp; --ktp; /* backup to the last legit entry */ /* copy the last entry to the current one */ sktp->k_code = ktp->k_code; sktp->k_type = ktp->k_type; sktp->k_ptr.fp = ktp->k_ptr.fp; /* null out the last one */ ktp->k_code = 0; ktp->k_type = BINDNUL; ktp->k_ptr.fp = NULL; return(TRUE); } /* Describe bindings: bring up a fake buffer and list the key bindings into it with view mode */ PASCAL NEAR desbind(f, n) #if APROP { return(buildlist(TRUE, "")); } PASCAL NEAR apro(f, n) /* Apropos (List functions that match a substring) */ { char mstring[NSTRING]; /* string to match cmd names to */ int status; /* status return */ status = mlreply(TEXT20, mstring, NSTRING - 1); /* "Apropos string: " */ if (status != TRUE) return(status); return(buildlist(FALSE, mstring)); } PASCAL NEAR buildlist(type, mstring) /* build a binding list (limited or full) */ int type; /* true = full list, false = partial list */ char *mstring; /* match string if a partial list */ #endif { register WINDOW *wp; /* scanning pointer to windows */ register KEYTAB *ktp; /* pointer into the command table */ register NBIND *nptr; /* pointer into the name binding table */ register BUFFER *bp; /* buffer to put binding list into */ int cpos; /* current position to use in outseq */ int cmark; /* current mark */ char outseq[80]; /* output buffer for keystroke sequence */ /* split the current window to make room for the binding list */ if (splitwind(FALSE, 1) == FALSE) return(FALSE); /* and get a buffer for it */ bp = bfind(TEXT21, TRUE, 0); /* "Binding list" */ if (bp == NULL || bclear(bp) == FALSE) { mlwrite(TEXT22); /* "Can not display binding list" */ return(FALSE); } /* let us know this is in progress */ mlwrite(TEXT23); /* "[Building binding list]" */ /* disconect the current buffer */ if (--curbp->b_nwnd == 0) { /* Last use. */ curbp->b_dotp = curwp->w_dotp; curbp->b_doto = curwp->w_doto; for (cmark = 0; cmark < NMARKS; cmark++) { curbp->b_markp[cmark] = curwp->w_markp[cmark]; curbp->b_marko[cmark] = curwp->w_marko[cmark]; } curbp->b_fcol = curwp->w_fcol; } /* connect the current window to this buffer */ curbp = bp; /* make this buffer current in current window */ bp->b_mode = 0; /* no modes active in binding list */ bp->b_nwnd++; /* mark us as more in use */ wp = curwp; wp->w_bufp = bp; wp->w_linep = bp->b_linep; wp->w_flag = WFHARD|WFFORCE; wp->w_dotp = bp->b_dotp; wp->w_doto = bp->b_doto; for (cmark = 0; cmark < NMARKS; cmark++) { wp->w_markp[cmark] = NULL; wp->w_marko[cmark] = 0; } /* build the contents of this window, inserting it line by line */ nptr = &names[0]; while (nptr->n_func != NULL) { /* add in the command name */ strcpy(outseq, nptr->n_name); cpos = strlen(outseq); #if APROP /* if we are executing an apropos command..... */ if (type == FALSE && /* and current string doesn't include the search string */ strinc(outseq, mstring) == FALSE) goto fail; #endif /* search down any keys bound to this */ ktp = &keytab[0]; while (ktp->k_type != BINDNUL) { if (ktp->k_type == BINDFNC && ktp->k_ptr.fp == nptr->n_func) { /* padd out some spaces */ while (cpos < 25) outseq[cpos++] = ' '; /* add in the command sequence */ cmdstr(ktp->k_code, &outseq[cpos]); strcat(outseq, "\r"); /* and add it as a line into the buffer */ if (linstr(outseq) != TRUE) return(FALSE); cpos = 0; /* and clear the line */ } ++ktp; } /* if no key was bound, we need to dump it anyway */ if (cpos > 0) { outseq[cpos++] = '\r'; outseq[cpos] = 0; if (linstr(outseq) != TRUE) return(FALSE); } fail: /* and on to the next name */ ++nptr; } /* add a blank line between the key and macro lists */ lnewline(); /* scan all buffers looking for macroes and their bindings */ bp = bheadp; while (bp) { /* is this buffer a macro? */ if (bp->b_bname[0] != '[') goto bfail; /* add in the command name */ strcpy(outseq, bp->b_bname); cpos = strlen(outseq); #if APROP /* if we are executing an apropos command..... */ if (type == FALSE && /* and current string doesn't include the search string */ strinc(outseq, mstring) == FALSE) goto bfail; #endif /* search down any keys bound to this macro */ ktp = &keytab[0]; while (ktp->k_ptr.fp != NULL) { if (ktp->k_type == BINDBUF && ktp->k_ptr.buf == bp) { /* padd out some spaces */ while (cpos < 25) outseq[cpos++] = ' '; /* add in the command sequence */ cmdstr(ktp->k_code, &outseq[cpos]); strcat(outseq, "\r"); /* and add it as a line into the buffer */ if (linstr(outseq) != TRUE) return(FALSE); cpos = 0; /* and clear the line */ } ++ktp; } /* if no key was bound, we need to dump it anyway */ if (cpos > 0) { outseq[cpos++] = '\r'; outseq[cpos] = 0; if (linstr(outseq) != TRUE) return(FALSE); } bfail: /* and on to the next buffer */ bp = bp->b_bufp; } curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */ curbp->b_flag &= ~BFCHG; /* don't flag this as a change */ wp->w_dotp = lforw(curbp->b_linep);/* back to the beginning */ wp->w_doto = 0; upmode(); mlwrite(""); /* clear the mode line */ return(TRUE); } #if APROP PASCAL NEAR strinc(source, sub) /* does source include sub? */ char *source; /* string to search in */ char *sub; /* substring to look for */ { char *sp; /* ptr into source */ char *nxtsp; /* next ptr into source */ char *tp; /* ptr into substring */ /* for each character in the source string */ sp = source; while (*sp) { tp = sub; nxtsp = sp; /* is the substring here? */ while (*tp) { if (*nxtsp++ != *tp) break; else tp++; } /* yes, return a success */ if (*tp == 0) return(TRUE); /* no, onward */ sp++; } return(FALSE); } #endif /* get a command key sequence from the keyboard */ unsigned int PASCAL NEAR getckey(mflag) int mflag; /* going for a meta sequence? */ { register unsigned int c; /* character fetched */ char tok[NSTRING]; /* command incoming */ /* check to see if we are executing a command line */ if (clexec) { macarg(tok); /* get the next token */ return(stock(tok)); } /* or the normal way */ if (mflag) c = getkey(); else c = getcmd(); return(c); } /* execute the startup file */ PASCAL NEAR startup(sfname) char *sfname; /* name of startup file (null if default) */ { char *fname; /* resulting file name to execute */ /* look up the startup file */ if (*sfname != 0) fname = flook(sfname, TRUE); else #if SHARED { strcpy(tname, pathname[0]); fname = flook(tname, TRUE); } #else fname = flook(pathname[0], TRUE); #endif /* if it isn't around, don't sweat it */ if (fname == NULL) return(TRUE); /* otherwise, execute the sucker */ return(dofile(fname)); } /* Look up the existance of a file along the normal or PATH environment variable. Look first in the HOME directory if asked and possible */ char *PASCAL NEAR flook(fname, hflag) char *fname; /* base file name to search for */ int hflag; /* Look in the HOME environment variable first? */ { register char *home; /* path to home directory */ register char *path; /* environmental PATH variable */ register char *sp; /* pointer into path spec */ register int i; /* index */ static char fspec[NFILEN]; /* full path spec to search */ char *getenv(); /* if we have an absolute path.. check only there! */ sp = fname; while (*sp) { if (*sp == ':' || *sp == '\\' || *sp == '/') { if (ffropen(fname) == FIOSUC) { ffclose(); return(fname); } else return(NULL); } ++sp; } #if ENVFUNC if (hflag) { #if WMCS home = getenv("SYS$HOME"); #else home = getenv("HOME"); #endif if (home != NULL) { /* build home dir file spec */ strcpy(fspec, home); #if WMCS strcat(fspec,fname); #else strcat(fspec, "/"); strcat(fspec, fname); #endif /* and try it out */ if (ffropen(fspec) == FIOSUC) { ffclose(); return(fspec); } } } #endif /* always try the current directory first */ if (ffropen(fname) == FIOSUC) { ffclose(); return(fname); } #if ENVFUNC /* get the PATH variable */ #if WMCS path = getenv("OPT$PATH"); #else path = getenv("PATH"); #endif if (path != NULL) while (*path) { /* build next possible file spec */ sp = fspec; #if ST520 & MWC while (*path && (*path != PATHCHR) && (*path != ',')) #else while (*path && (*path != PATHCHR)) #endif *sp++ = *path++; /* add a terminating dir separator if we need it */ if (*(sp-1) != DIRSEPCHAR) *sp++ = DIRSEPCHAR; *sp = 0; strcat(fspec, fname); /* and try it out */ if (ffropen(fspec) == FIOSUC) { ffclose(); return(fspec); } #if ST520 & MWC if ((*path == PATHCHR) || (*path == ',')) #else if (*path == PATHCHR) #endif ++path; } #endif /* look it up via the old table method */ for (i=2; i < NPNAMES; i++) { strcpy(fspec, pathname[i]); strcat(fspec, fname); /* and try it out */ if (ffropen(fspec) == FIOSUC) { ffclose(); return(fspec); } } return(NULL); /* no such luck */ } PASCAL NEAR cmdstr(c, seq) /* change a key command to a string we can print out */ int c; /* sequence to translate */ char *seq; /* destination string for sequence */ { char *ptr; /* pointer into current position in sequence */ ptr = seq; /* apply ^X sequence if needed */ if (c & CTLX) { *ptr++ = '^'; *ptr++ = 'X'; } /* apply ALT key sequence if needed */ if (c & ALTD) { *ptr++ = 'A'; *ptr++ = '-'; } /* apply Shifted sequence if needed */ if (c & SHFT) { *ptr++ = 'S'; *ptr++ = '-'; } /* apply MOUS sequence if needed */ if (c & MOUS) { *ptr++ = 'M'; *ptr++ = 'S'; } /* apply meta sequence if needed */ if (c & META) { *ptr++ = 'M'; *ptr++ = '-'; } /* apply SPEC sequence if needed */ if (c & SPEC) { *ptr++ = 'F'; *ptr++ = 'N'; } /* apply control sequence if needed */ if (c & CTRL) { *ptr++ = '^'; } c = c & 255; /* strip the prefixes */ /* and output the final sequence */ *ptr++ = c; *ptr = 0; /* terminate the string */ } /* This function looks a key binding up in the binding table */ KEYTAB *getbind(c) int c; /* key to find what is bound to it */ { register KEYTAB *ktp; /* scan through the binding table, looking for the key's entry */ ktp = &keytab[0]; while (ktp->k_type != BINDNUL) { if (ktp->k_code == c) return(ktp); ++ktp; } /* no such binding */ return((KEYTAB *)NULL); } /* getfname: This function takes a ptr to KEYTAB entry and gets the name associated with it */ char *PASCAL NEAR getfname(key) KEYTAB *key; /* key binding to return a name of */ { int (PASCAL NEAR *func)(); /* ptr to the requested function */ register NBIND *nptr; /* pointer into the name binding table */ register BUFFER *bp; /* ptr to buffer to test */ register BUFFER *kbuf; /* ptr to requested buffer */ /* if this isn't a valid key, it has no name */ if (key == NULL) return(NULL); /* skim through the binding table, looking for a match */ if (key->k_type == BINDFNC) { func = key->k_ptr.fp; nptr = &names[0]; while (nptr->n_func != NULL) { if (nptr->n_func == func) return(nptr->n_name); ++nptr; } return(NULL); } /* skim through the buffer list looking for a match */ kbuf = key->k_ptr.buf; bp = bheadp; while (bp) { if (bp == kbuf) return(bp->b_bname); bp = bp->b_bufp; } return(NULL); } /* fncmatch: match fname to a function in the names table and return any match or NULL if none */ int (PASCAL NEAR *PASCAL NEAR fncmatch(fname))() char *fname; /* name to attempt to match */ { #if BINARY register int nval; /* value of matched name */ nval = binary(fname, namval, numfunc); if (nval == -1) return(NULL); else return(names[nval].n_func); #else register NBIND *ffp; /* pointer to entry in name binding table */ /* scan through the table, returning any match */ ffp = &names[0]; while (ffp->n_func != NULL) { if (strcmp(fname, ffp->n_name) == 0) return(ffp->n_func); ++ffp; } return(NULL); #endif } #if BINARY char *PASCAL NEAR namval(index) int index; /* index of name to fetch out of the name table */ { return(names[index].n_name); } #endif /* stock() String key name TO Command Key A key binding consists of one or more prefix functions followed by a keystroke. Allowable prefixes must be in the following order: ^X preceeding control-X A- simeltaneous ALT key (on PCs mainly) S- shifted function key MS mouse generated keystroke M- Preceding META key FN function key ^ control key Meta and ^X prefix of lower case letters are converted to upper case. Real control characters are automatically converted to the ^A form. */ unsigned int PASCAL NEAR stock(keyname) char *keyname; /* name of key to translate to Command key form */ { register unsigned int c; /* key sequence to return */ /* parse it up */ c = 0; /* Do ^X prefix */ if(*keyname == '^' && *(keyname+1) == 'X') { if(*(keyname+2) != 0) { /* Key is not bare ^X */ c |= CTLX; keyname += 2; } } /* and the ALT key prefix */ if (*keyname == 'A' && *(keyname+1) == '-') { c |= ALTD; keyname += 2; } /* and the SHIFTED prefix */ if (*keyname == 'S' && *(keyname+1) == '-') { c |= SHFT; keyname += 2; } /* and the mouse (MOUS) prefix */ if (*keyname == 'M' && *(keyname+1) == 'S') { c |= MOUS; keyname += 2; } /* then the META prefix */ if (*keyname == 'M' && *(keyname+1) == '-') { c |= META; keyname += 2; } /* next the function prefix */ if (*keyname == 'F' && *(keyname+1) == 'N') { c |= SPEC; keyname += 2; } /* a control char? (Always upper case) */ if (*keyname == '^' && *(keyname+1) != 0) { c |= CTRL; ++keyname; uppercase(keyname); } /* A literal control character? (Boo, hiss) */ if (*keyname < 32) { c |= CTRL; *keyname += '@'; } /* make sure we are not lower case if used with ^X or M- */ if(!(c & (MOUS|SPEC|ALTD|SHFT))) /* If not a special key */ if( c & (CTLX|META)) /* If is a prefix */ uppercase(keyname); /* Then make sure it's upper case */ /* the final sequence... */ c |= *keyname; return(c); } char *PASCAL NEAR transbind(skey) /* string key name to binding name.... */ char *skey; /* name of key to get binding for */ { char *bindname; bindname = getfname(getbind(stock(skey))); if (bindname == NULL) bindname = errorm; return(bindname); } int PASCAL NEAR execkey(key, f, n) /* execute a function bound to a key */ KEYTAB *key; /* key to execute */ int f, n; /* agruments to C function */ { register int status; /* error return */ if (key->k_type == BINDFNC) return((*(key->k_ptr.fp))(f, n)); if (key->k_type == BINDBUF) { while (n--) { status = dobuf(key->k_ptr.buf); if (status != TRUE) return(status); } } return(TRUE); } /* set a KEYTAB to the given name of the given type */ setkey(key, type, name) KEYTAB *key; /* ptr to key to set */ short type; /* type of binding */ char *name; /* name of function or buffer */ { key->k_type = type; if (type == BINDFNC) key->k_ptr.fp = fncmatch(name); else if (type == BINDBUF) /* not quite yet... */; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.