tc.bind.c revision 100616
1100616Smp/* $Header: /src/pub/tcsh/tc.bind.c,v 3.36 2002/03/08 17:36:47 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tc.bind.c: Key binding functions 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35100616SmpRCSID("$Id: tc.bind.c,v 3.36 2002/03/08 17:36:47 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 3859243Sobrien#include "ed.defns.h" 3959243Sobrien 4059243Sobrien#ifdef OBSOLETE 4159243Sobrienstatic int tocontrol __P((int)); 4259243Sobrienstatic char *unparsekey __P((int)); 4359243Sobrienstatic KEYCMD getkeycmd __P((Char **)); 4459243Sobrienstatic int parsekey __P((Char **)); 4559243Sobrienstatic void pkeys __P((int, int)); 4659243Sobrien#endif /* OBSOLETE */ 4759243Sobrien 4859243Sobrienstatic void printkey __P((KEYCMD *, CStr *)); 4959243Sobrienstatic KEYCMD parsecmd __P((Char *)); 5059243Sobrienstatic void bad_spec __P((Char *)); 5159243Sobrienstatic CStr *parsestring __P((Char *, CStr *)); 5259243Sobrienstatic CStr *parsebind __P((Char *, CStr *)); 5359243Sobrienstatic void print_all_keys __P((void)); 5459243Sobrienstatic void printkeys __P((KEYCMD *, int, int)); 5559243Sobrienstatic void bindkey_usage __P((void)); 5659243Sobrienstatic void list_functions __P((void)); 5759243Sobrien 5859243Sobrienextern int MapsAreInited; 5959243Sobrien 6059243Sobrien 6159243Sobrien 6259243Sobrien 6359243Sobrien/*ARGSUSED*/ 6459243Sobrienvoid 6559243Sobriendobindkey(v, c) 6659243Sobrien Char **v; 6759243Sobrien struct command *c; 6859243Sobrien{ 6959243Sobrien KEYCMD *map; 7059243Sobrien int ntype, no, remove, key, bind; 7159243Sobrien Char *par; 7259243Sobrien Char p; 7359243Sobrien KEYCMD cmd; 7459243Sobrien CStr in; 7559243Sobrien CStr out; 7659243Sobrien Char inbuf[200]; 7759243Sobrien Char outbuf[200]; 7859243Sobrien uChar ch; 7959243Sobrien in.buf = inbuf; 8059243Sobrien out.buf = outbuf; 8159243Sobrien in.len = 0; 8259243Sobrien out.len = 0; 8359243Sobrien 8459243Sobrien USE(c); 8559243Sobrien if (!MapsAreInited) 8659243Sobrien ed_InitMaps(); 8759243Sobrien 8859243Sobrien map = CcKeyMap; 8959243Sobrien ntype = XK_CMD; 9059243Sobrien key = remove = bind = 0; 9159243Sobrien for (no = 1, par = v[no]; 9259243Sobrien par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) { 9359243Sobrien if ((p = (*par & CHAR)) == '-') { 9459243Sobrien no++; 9559243Sobrien break; 9659243Sobrien } 9759243Sobrien else 9859243Sobrien switch (p) { 9959243Sobrien case 'b': 10059243Sobrien bind = 1; 10159243Sobrien break; 10259243Sobrien case 'k': 10359243Sobrien key = 1; 10459243Sobrien break; 10559243Sobrien case 'a': 10659243Sobrien map = CcAltMap; 10759243Sobrien break; 10859243Sobrien case 's': 10959243Sobrien ntype = XK_STR; 11059243Sobrien break; 11159243Sobrien case 'c': 11259243Sobrien ntype = XK_EXE; 11359243Sobrien break; 11459243Sobrien case 'r': 11559243Sobrien remove = 1; 11659243Sobrien break; 11759243Sobrien case 'v': 11859243Sobrien ed_InitVIMaps(); 11959243Sobrien return; 12059243Sobrien case 'e': 12159243Sobrien ed_InitEmacsMaps(); 12259243Sobrien return; 12359243Sobrien case 'd': 12459243Sobrien#ifdef VIDEFAULT 12559243Sobrien ed_InitVIMaps(); 12659243Sobrien#else /* EMACSDEFAULT */ 12759243Sobrien ed_InitEmacsMaps(); 12859243Sobrien#endif /* VIDEFAULT */ 12959243Sobrien return; 13059243Sobrien case 'l': 13159243Sobrien list_functions(); 13259243Sobrien return; 13359243Sobrien default: 13459243Sobrien bindkey_usage(); 13559243Sobrien return; 13659243Sobrien } 13759243Sobrien } 13859243Sobrien 13959243Sobrien if (!v[no]) { 14059243Sobrien print_all_keys(); 14159243Sobrien return; 14259243Sobrien } 14359243Sobrien 14459243Sobrien if (key) { 14559243Sobrien if (!IsArrowKey(v[no])) 14659243Sobrien xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]); 14759243Sobrien in.buf = v[no++]; 14859243Sobrien in.len = Strlen(in.buf); 14959243Sobrien } 15059243Sobrien else { 15159243Sobrien if (bind) { 15259243Sobrien if (parsebind(v[no++], &in) == NULL) 15359243Sobrien return; 15459243Sobrien } 15559243Sobrien else { 15659243Sobrien if (parsestring(v[no++], &in) == NULL) 15759243Sobrien return; 15859243Sobrien } 15959243Sobrien } 16059243Sobrien 16159243Sobrien ch = (uChar) in.buf[0]; 16259243Sobrien 16359243Sobrien if (remove) { 16459243Sobrien if (key) { 16559243Sobrien (void) ClearArrowKeys(&in); 16659243Sobrien return; 16759243Sobrien } 16859243Sobrien if (in.len > 1) { 16959243Sobrien (void) DeleteXkey(&in); 17059243Sobrien } 17159243Sobrien else if (map[ch] == F_XKEY) { 17259243Sobrien (void) DeleteXkey(&in); 17359243Sobrien map[ch] = F_UNASSIGNED; 17459243Sobrien } 17559243Sobrien else { 17659243Sobrien map[ch] = F_UNASSIGNED; 17759243Sobrien } 17859243Sobrien return; 17959243Sobrien } 18059243Sobrien if (!v[no]) { 18159243Sobrien if (key) 18259243Sobrien PrintArrowKeys(&in); 18359243Sobrien else 18459243Sobrien printkey(map, &in); 18559243Sobrien return; 18659243Sobrien } 18759243Sobrien if (v[no + 1]) { 18859243Sobrien bindkey_usage(); 18959243Sobrien return; 19059243Sobrien } 19159243Sobrien switch (ntype) { 19259243Sobrien case XK_STR: 19359243Sobrien case XK_EXE: 19459243Sobrien if (parsestring(v[no], &out) == NULL) 19559243Sobrien return; 19659243Sobrien if (key) { 19759243Sobrien if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1) 19859243Sobrien xprintf(CGETS(20, 2, "Bad key name: %S\n"), in); 19959243Sobrien } 20059243Sobrien else 20159243Sobrien AddXkey(&in, XmapStr(&out), ntype); 20259243Sobrien map[ch] = F_XKEY; 20359243Sobrien break; 20459243Sobrien case XK_CMD: 20559243Sobrien if ((cmd = parsecmd(v[no])) == 0) 20659243Sobrien return; 20759243Sobrien if (key) 20859243Sobrien (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype); 20959243Sobrien else { 21059243Sobrien if (in.len > 1) { 21159243Sobrien AddXkey(&in, XmapCmd((int) cmd), ntype); 21259243Sobrien map[ch] = F_XKEY; 21359243Sobrien } 21459243Sobrien else { 21559243Sobrien ClearXkey(map, &in); 21659243Sobrien map[ch] = cmd; 21759243Sobrien } 21859243Sobrien } 21959243Sobrien break; 22059243Sobrien default: 22159243Sobrien abort(); 22259243Sobrien break; 22359243Sobrien } 22459243Sobrien if (key) 22559243Sobrien BindArrowKeys(); 22659243Sobrien} 22759243Sobrien 22859243Sobrienstatic void 22959243Sobrienprintkey(map, in) 23059243Sobrien KEYCMD *map; 23159243Sobrien CStr *in; 23259243Sobrien{ 23359243Sobrien unsigned char outbuf[100]; 23459243Sobrien register struct KeyFuncs *fp; 23559243Sobrien 23659243Sobrien if (in->len < 2) { 23759243Sobrien (void) unparsestring(in, outbuf, STRQQ); 23859243Sobrien for (fp = FuncNames; fp->name; fp++) { 23959243Sobrien if (fp->func == map[(uChar) *(in->buf)]) { 24059243Sobrien xprintf("%s\t->\t%s\n", outbuf, fp->name); 24159243Sobrien } 24259243Sobrien } 24359243Sobrien } 24459243Sobrien else 24559243Sobrien PrintXkey(in); 24659243Sobrien} 24759243Sobrien 24859243Sobrienstatic KEYCMD 24959243Sobrienparsecmd(str) 25059243Sobrien Char *str; 25159243Sobrien{ 25259243Sobrien register struct KeyFuncs *fp; 25359243Sobrien 25459243Sobrien for (fp = FuncNames; fp->name; fp++) { 25559243Sobrien if (strcmp(short2str(str), fp->name) == 0) { 25659243Sobrien return (KEYCMD) fp->func; 25759243Sobrien } 25859243Sobrien } 25959243Sobrien xprintf(CGETS(20, 3, "Bad command name: %S\n"), str); 26059243Sobrien return 0; 26159243Sobrien} 26259243Sobrien 26359243Sobrien 26459243Sobrienstatic void 26559243Sobrienbad_spec(str) 26659243Sobrien Char *str; 26759243Sobrien{ 26859243Sobrien xprintf(CGETS(20, 4, "Bad key spec %S\n"), str); 26959243Sobrien} 27059243Sobrien 27159243Sobrienstatic CStr * 27259243Sobrienparsebind(s, str) 27359243Sobrien Char *s; 27459243Sobrien CStr *str; 27559243Sobrien{ 27659243Sobrien#ifdef DSPMBYTE 27759243Sobrien extern bool NoNLSRebind; 27859243Sobrien#endif /* DSPMBYTE */ 27959243Sobrien Char *b = str->buf; 28059243Sobrien 28159243Sobrien if (Iscntrl(*s)) { 28259243Sobrien *b++ = *s; 28359243Sobrien *b = '\0'; 28459243Sobrien str->len = (int) (b - str->buf); 28559243Sobrien return str; 28659243Sobrien } 28759243Sobrien 28859243Sobrien switch (*s) { 28959243Sobrien case '^': 29059243Sobrien s++; 29169408Sache#ifdef IS_ASCII 29259243Sobrien *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237); 29369408Sache#else 29459243Sobrien *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237]; 29569408Sache#endif 29659243Sobrien *b = '\0'; 29759243Sobrien break; 29859243Sobrien 29959243Sobrien case 'F': 30059243Sobrien case 'M': 30159243Sobrien case 'X': 30259243Sobrien case 'C': 30369408Sache#ifdef WINNT_NATIVE 30459243Sobrien case 'N': 30569408Sache#endif /* WINNT_NATIVE */ 30659243Sobrien if (s[1] != '-' || s[2] == '\0') { 30759243Sobrien bad_spec(s); 30859243Sobrien return NULL; 30959243Sobrien } 31059243Sobrien s += 2; 31159243Sobrien switch (s[-2]) { 31259243Sobrien case 'F': case 'f': /* Turn into ^[str */ 31359243Sobrien *b++ = CTL_ESC('\033'); 31459243Sobrien while ((*b++ = *s++) != '\0') 31559243Sobrien continue; 31659243Sobrien b--; 31759243Sobrien break; 31859243Sobrien 31959243Sobrien case 'C': case 'c': /* Turn into ^c */ 32069408Sache#ifdef IS_ASCII 32159243Sobrien *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237); 32269408Sache#else 32359243Sobrien *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237]; 32469408Sache#endif 32559243Sobrien *b = '\0'; 32659243Sobrien break; 32759243Sobrien 32859243Sobrien case 'X' : case 'x': /* Turn into ^Xc */ 32969408Sache#ifdef IS_ASCII 33059243Sobrien *b++ = 'X' & 0237; 33169408Sache#else 33259243Sobrien *b++ = _toebcdic[_toascii['X'] & 0237]; 33369408Sache#endif 33459243Sobrien *b++ = *s; 33559243Sobrien *b = '\0'; 33659243Sobrien break; 33759243Sobrien 33859243Sobrien case 'M' : case 'm': /* Turn into 0x80|c */ 33959243Sobrien#ifdef DSPMBYTE 34059243Sobrien if (!NoNLSRebind) { 34159243Sobrien *b++ = CTL_ESC('\033'); 34259243Sobrien *b++ = *s; 34359243Sobrien } else { 34459243Sobrien#endif /* DSPMBYTE */ 34569408Sache#ifdef IS_ASCII 34659243Sobrien *b++ = *s | 0x80; 34769408Sache#else 34859243Sobrien *b++ = _toebcdic[_toascii[*s] | 0x80]; 34969408Sache#endif 35059243Sobrien#ifdef DSPMBYTE 35159243Sobrien } 35259243Sobrien#endif /* DSPMBYTE */ 35359243Sobrien *b = '\0'; 35459243Sobrien break; 35569408Sache#ifdef WINNT_NATIVE 35659243Sobrien case 'N' : case 'n': /* NT */ 35759243Sobrien { 35859243Sobrien Char bnt; 35959243Sobrien 36059243Sobrien bnt = nt_translate_bindkey(s); 36159243Sobrien if (bnt != 0) 36259243Sobrien *b++ = bnt; 36359243Sobrien else 36459243Sobrien bad_spec(s); 36559243Sobrien } 36659243Sobrien break; 36769408Sache#endif /* WINNT_NATIVE */ 36859243Sobrien 36959243Sobrien default: 37059243Sobrien abort(); 37159243Sobrien /*NOTREACHED*/ 37259243Sobrien return NULL; 37359243Sobrien } 37459243Sobrien break; 37559243Sobrien 37659243Sobrien default: 37759243Sobrien bad_spec(s); 37859243Sobrien return NULL; 37959243Sobrien } 38059243Sobrien 38159243Sobrien str->len = (int) (b - str->buf); 38259243Sobrien return str; 38359243Sobrien} 38459243Sobrien 38559243Sobrien 38659243Sobrienstatic CStr * 38759243Sobrienparsestring(str, buf) 38859243Sobrien Char *str; 38959243Sobrien CStr *buf; 39059243Sobrien{ 39159243Sobrien Char *b; 39259243Sobrien const Char *p; 39359243Sobrien int es; 39459243Sobrien 39559243Sobrien b = buf->buf; 39659243Sobrien if (*str == 0) { 39759243Sobrien xprintf(CGETS(20, 5, "Null string specification\n")); 39859243Sobrien return NULL; 39959243Sobrien } 40059243Sobrien 40159243Sobrien for (p = str; *p != 0; p++) { 40259243Sobrien if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') { 40359243Sobrien if ((es = parseescape(&p)) == -1) 40459243Sobrien return 0; 40559243Sobrien else 40659243Sobrien *b++ = (Char) es; 40759243Sobrien } 40859243Sobrien else 40959243Sobrien *b++ = *p & CHAR; 41059243Sobrien } 41159243Sobrien *b = 0; 41259243Sobrien buf->len = (int) (b - buf->buf); 41359243Sobrien return buf; 41459243Sobrien} 41559243Sobrien 41659243Sobrienstatic void 41759243Sobrienprint_all_keys() 41859243Sobrien{ 41959243Sobrien int prev, i; 42059243Sobrien CStr nilstr; 42159243Sobrien nilstr.buf = NULL; 42259243Sobrien nilstr.len = 0; 42359243Sobrien 42459243Sobrien 42559243Sobrien xprintf(CGETS(20, 6, "Standard key bindings\n")); 42659243Sobrien prev = 0; 42759243Sobrien for (i = 0; i < 256; i++) { 42859243Sobrien if (CcKeyMap[prev] == CcKeyMap[i]) 42959243Sobrien continue; 43059243Sobrien printkeys(CcKeyMap, prev, i - 1); 43159243Sobrien prev = i; 43259243Sobrien } 43359243Sobrien printkeys(CcKeyMap, prev, i - 1); 43459243Sobrien 43559243Sobrien xprintf(CGETS(20, 7, "Alternative key bindings\n")); 43659243Sobrien prev = 0; 43759243Sobrien for (i = 0; i < 256; i++) { 43859243Sobrien if (CcAltMap[prev] == CcAltMap[i]) 43959243Sobrien continue; 44059243Sobrien printkeys(CcAltMap, prev, i - 1); 44159243Sobrien prev = i; 44259243Sobrien } 44359243Sobrien printkeys(CcAltMap, prev, i - 1); 44459243Sobrien xprintf(CGETS(20, 8, "Multi-character bindings\n")); 44559243Sobrien PrintXkey(NULL); /* print all Xkey bindings */ 44659243Sobrien xprintf(CGETS(20, 9, "Arrow key bindings\n")); 44759243Sobrien PrintArrowKeys(&nilstr); 44859243Sobrien} 44959243Sobrien 45059243Sobrienstatic void 45159243Sobrienprintkeys(map, first, last) 45259243Sobrien KEYCMD *map; 45359243Sobrien int first, last; 45459243Sobrien{ 45559243Sobrien register struct KeyFuncs *fp; 45659243Sobrien Char firstbuf[2], lastbuf[2]; 45759243Sobrien CStr fb, lb; 45859243Sobrien unsigned char unparsbuf[10], extrabuf[10]; 45959243Sobrien fb.buf = firstbuf; 46059243Sobrien lb.buf = lastbuf; 46159243Sobrien 46259243Sobrien firstbuf[0] = (Char) first; 46359243Sobrien firstbuf[1] = 0; 46459243Sobrien lastbuf[0] = (Char) last; 46559243Sobrien lastbuf[1] = 0; 46659243Sobrien fb.len = 1; 46759243Sobrien lb.len = 1; 46859243Sobrien 46959243Sobrien if (map[first] == F_UNASSIGNED) { 47059243Sobrien if (first == last) 47159243Sobrien xprintf(CGETS(20, 10, "%-15s-> is undefined\n"), 47259243Sobrien unparsestring(&fb, unparsbuf, STRQQ)); 47359243Sobrien return; 47459243Sobrien } 47559243Sobrien 47659243Sobrien for (fp = FuncNames; fp->name; fp++) { 47759243Sobrien if (fp->func == map[first]) { 47859243Sobrien if (first == last) { 47959243Sobrien xprintf("%-15s-> %s\n", 48059243Sobrien unparsestring(&fb, unparsbuf, STRQQ), fp->name); 48159243Sobrien } 48259243Sobrien else { 48359243Sobrien xprintf("%-4s to %-7s-> %s\n", 48459243Sobrien unparsestring(&fb, unparsbuf, STRQQ), 48559243Sobrien unparsestring(&lb, extrabuf, STRQQ), fp->name); 48659243Sobrien } 48759243Sobrien return; 48859243Sobrien } 48959243Sobrien } 49059243Sobrien if (map == CcKeyMap) { 49159243Sobrien xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 49259243Sobrien unparsestring(&fb, unparsbuf, STRQQ)); 49359243Sobrien xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]); 49459243Sobrien } 49559243Sobrien else { 49659243Sobrien xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 49759243Sobrien unparsestring(&fb, unparsbuf, STRQQ)); 49859243Sobrien xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]); 49959243Sobrien } 50059243Sobrien} 50159243Sobrien 50259243Sobrienstatic void 50359243Sobrienbindkey_usage() 50459243Sobrien{ 50559243Sobrien xprintf(CGETS(20, 12, 50659243Sobrien "Usage: bindkey [options] [--] [KEY [COMMAND]]\n")); 50759243Sobrien xprintf(CGETS(20, 13, 50859243Sobrien " -a list or bind KEY in alternative key map\n")); 50959243Sobrien xprintf(CGETS(20, 14, 51059243Sobrien " -b interpret KEY as a C-, M-, F- or X- key name\n")); 51159243Sobrien xprintf(CGETS(20, 15, 51259243Sobrien " -s interpret COMMAND as a literal string to be output\n")); 51359243Sobrien xprintf(CGETS(20, 16, 51459243Sobrien " -c interpret COMMAND as a builtin or external command\n")); 51559243Sobrien xprintf(CGETS(20, 17, 51659243Sobrien " -v bind all keys to vi bindings\n")); 51759243Sobrien xprintf(CGETS(20, 18, 51859243Sobrien " -e bind all keys to emacs bindings\n")); 51959243Sobrien xprintf(CGETS(20, 19, 52059243Sobrien " -d bind all keys to default editor's bindings\n")); 52159243Sobrien xprintf(CGETS(20, 20, 52259243Sobrien " -l list editor commands with descriptions\n")); 52359243Sobrien xprintf(CGETS(20, 21, 52459243Sobrien " -r remove KEY's binding\n")); 52559243Sobrien xprintf(CGETS(20, 22, 52659243Sobrien " -k interpret KEY as a symbolic arrow-key name\n")); 52759243Sobrien xprintf(CGETS(20, 23, 52859243Sobrien " -- force a break from option processing\n")); 52959243Sobrien xprintf(CGETS(20, 24, 53059243Sobrien " -u (or any invalid option) this message\n")); 53159243Sobrien xprintf("\n"); 53259243Sobrien xprintf(CGETS(20, 25, 53359243Sobrien "Without KEY or COMMAND, prints all bindings\n")); 53459243Sobrien xprintf(CGETS(20, 26, 53559243Sobrien "Without COMMAND, prints the binding for KEY.\n")); 53659243Sobrien} 53759243Sobrien 53859243Sobrienstatic void 53959243Sobrienlist_functions() 54059243Sobrien{ 54159243Sobrien register struct KeyFuncs *fp; 54259243Sobrien 54359243Sobrien for (fp = FuncNames; fp->name; fp++) { 54459243Sobrien xprintf("%s\n %s\n", fp->name, fp->desc); 54559243Sobrien } 54659243Sobrien} 54759243Sobrien 54859243Sobrien#ifdef OBSOLETE 54959243Sobrien 55059243Sobrien/* 55159243Sobrien * Unfortunately the apollo optimizer does not like & operations 55259243Sobrien * with 0377, and produces illegal instructions. So we make it 55359243Sobrien * an unsigned char, and hope for the best. 55459243Sobrien * Of-course the compiler is smart enough to produce bad assembly 55559243Sobrien * language instructions, but dumb when it comes to fold the constant :-) 55659243Sobrien */ 55759243Sobrien#ifdef apollo 55859243Sobrienstatic unsigned char APOLLO_0377 = 0377; 55959243Sobrien#else /* sane */ 56059243Sobrien# define APOLLO_0377 0377 56159243Sobrien#endif /* apollo */ 56259243Sobrien 56359243Sobrienstatic int 56459243Sobrientocontrol(c) 56559243Sobrien int c; 56659243Sobrien{ 56759243Sobrien c &= CHAR; 56859243Sobrien if (Islower(c)) 56959243Sobrien c = Toupper(c); 57059243Sobrien else if (c == ' ') 57159243Sobrien c = '@'; 57259243Sobrien if (c == '?') 57359243Sobrien c = CTL_ESC('\177'); 57459243Sobrien else 57569408Sache#ifdef IS_ASCII 57659243Sobrien c &= 037; 57769408Sache#else 57869408Sache /* EBCDIC: simulate ASCII-behavior by transforming to ASCII and back */ 57959243Sobrien c = _toebcdic[_toascii[c] & 037]; 58059243Sobrien#endif 58159243Sobrien return (c); 58259243Sobrien} 58359243Sobrien 58459243Sobrienstatic char * 58559243Sobrienunparsekey(c) /* 'c' -> "c", '^C' -> "^" + "C" */ 58659243Sobrien register int c; 58759243Sobrien{ 58859243Sobrien register char *cp; 58959243Sobrien static char tmp[10]; 59059243Sobrien 59159243Sobrien cp = tmp; 59259243Sobrien 59359243Sobrien if (c & 0400) { 59459243Sobrien *cp++ = 'A'; 59559243Sobrien *cp++ = '-'; 59659243Sobrien c &= APOLLO_0377; 59759243Sobrien } 59859243Sobrien if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) { 59959243Sobrien *cp++ = 'M'; 60059243Sobrien *cp++ = '-'; 60159243Sobrien c &= ASCII; 60259243Sobrien } 60359243Sobrien if (Isprint(c)) { 60459243Sobrien *cp++ = (char) c; 60559243Sobrien *cp = '\0'; 60659243Sobrien return (tmp); 60759243Sobrien } 60859243Sobrien switch (c) { 60959243Sobrien case ' ': 61059243Sobrien (void) strcpy(cp, "Spc"); 61159243Sobrien return (tmp); 61259243Sobrien case '\n': 61359243Sobrien (void) strcpy(cp, "Lfd"); 61459243Sobrien return (tmp); 61559243Sobrien case '\r': 61659243Sobrien (void) strcpy(cp, "Ret"); 61759243Sobrien return (tmp); 61859243Sobrien case '\t': 61959243Sobrien (void) strcpy(cp, "Tab"); 62059243Sobrien return (tmp); 62169408Sache#ifdef IS_ASCII 62259243Sobrien case '\033': 62359243Sobrien (void) strcpy(cp, "Esc"); 62459243Sobrien return (tmp); 62559243Sobrien case '\177': 62659243Sobrien (void) strcpy(cp, "Del"); 62759243Sobrien return (tmp); 62859243Sobrien default: 62959243Sobrien *cp++ = '^'; 63059243Sobrien if (c == '\177') { 63159243Sobrien *cp++ = '?'; 63259243Sobrien } 63359243Sobrien else { 63459243Sobrien *cp++ = c | 0100; 63559243Sobrien } 63659243Sobrien *cp = '\0'; 63759243Sobrien return (tmp); 63869408Sache#else /* IS_ASCII */ 63959243Sobrien default: 64059243Sobrien if (*cp == CTL_ESC('\033')) { 64159243Sobrien (void) strcpy(cp, "Esc"); 64259243Sobrien return (tmp); 64359243Sobrien } 64459243Sobrien else if (*cp == CTL_ESC('\177')) { 64559243Sobrien (void) strcpy(cp, "Del"); 64659243Sobrien return (tmp); 64759243Sobrien } 64859243Sobrien else if (Isupper(_toebcdic[_toascii[c]|0100]) 64959243Sobrien || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) { 65059243Sobrien *cp++ = '^'; 65159243Sobrien *cp++ = _toebcdic[_toascii[c]|0100] 65259243Sobrien } 65359243Sobrien else { 65459243Sobrien xsnprintf(cp, 3, "\\%3.3o", c); 65559243Sobrien cp += 4; 65659243Sobrien } 65769408Sache#endif /* IS_ASCII */ 65859243Sobrien } 65959243Sobrien} 66059243Sobrien 66159243Sobrienstatic KEYCMD 66259243Sobriengetkeycmd(sp) 66359243Sobrien Char **sp; 66459243Sobrien{ 66559243Sobrien register Char *s = *sp; 66659243Sobrien register char c; 66759243Sobrien register KEYCMD keycmd = F_UNASSIGNED; 66859243Sobrien KEYCMD *map; 66959243Sobrien int meta = 0; 67059243Sobrien Char *ret_sp = s; 67159243Sobrien 67259243Sobrien map = CcKeyMap; 67359243Sobrien 67459243Sobrien while (*s) { 67559243Sobrien if (*s == '^' && s[1]) { 67659243Sobrien s++; 67759243Sobrien c = tocontrol(*s++); 67859243Sobrien } 67959243Sobrien else 68059243Sobrien c = *s++; 68159243Sobrien 68259243Sobrien if (*s == '\0') 68359243Sobrien break; 68459243Sobrien 68559243Sobrien switch (map[c | meta]) { 68659243Sobrien case F_METANEXT: 68759243Sobrien meta = META; 68859243Sobrien keycmd = F_METANEXT; 68959243Sobrien ret_sp = s; 69059243Sobrien break; 69159243Sobrien 69259243Sobrien case F_XKEY: 69359243Sobrien keycmd = F_XKEY; 69459243Sobrien ret_sp = s; 69559243Sobrien /* FALLTHROUGH */ 69659243Sobrien 69759243Sobrien default: 69859243Sobrien *sp = ret_sp; 69959243Sobrien return (keycmd); 70059243Sobrien 70159243Sobrien } 70259243Sobrien } 70359243Sobrien *sp = ret_sp; 70459243Sobrien return (keycmd); 70559243Sobrien} 70659243Sobrien 70759243Sobrienstatic int 70859243Sobrienparsekey(sp) 70959243Sobrien Char **sp; /* Return position of first unparsed character 71059243Sobrien * for return value -2 (xkeynext) */ 71159243Sobrien{ 71259243Sobrien register int c, meta = 0, control = 0, ctrlx = 0; 71359243Sobrien Char *s = *sp; 71459243Sobrien KEYCMD keycmd; 71559243Sobrien 71659243Sobrien if (s == NULL) { 71759243Sobrien xprintf(CGETS(20, 27, "bad key specification -- null string\n")); 71859243Sobrien return -1; 71959243Sobrien } 72059243Sobrien if (*s == 0) { 72159243Sobrien xprintf(CGETS(20, 28, "bad key specification -- empty string\n")); 72259243Sobrien return -1; 72359243Sobrien } 72459243Sobrien 72559243Sobrien (void) strip(s); /* trim to 7 bits. */ 72659243Sobrien 72759243Sobrien if (s[1] == 0) /* single char */ 72859243Sobrien return (s[0] & APOLLO_0377); 72959243Sobrien 73059243Sobrien if ((s[0] == 'F' || s[0] == 'f') && s[1] == '-') { 73159243Sobrien if (s[2] == 0) { 73259243Sobrien xprintf(CGETS(20, 29, 73359243Sobrien "Bad function-key specification. Null key not allowed\n")); 73459243Sobrien return (-1); 73559243Sobrien } 73659243Sobrien *sp = s + 2; 73759243Sobrien return (-2); 73859243Sobrien } 73959243Sobrien 74059243Sobrien if (s[0] == '0' && s[1] == 'x') { /* if 0xn, then assume number */ 74159243Sobrien c = 0; 74259243Sobrien for (s += 2; *s; s++) { /* convert to hex; skip the first 0 */ 74359243Sobrien c *= 16; 74459243Sobrien if (!Isxdigit(*s)) { 74559243Sobrien xprintf(CGETS(20, 30, 74659243Sobrien "bad key specification -- malformed hex number\n")); 74759243Sobrien return -1; /* error */ 74859243Sobrien } 74959243Sobrien if (Isdigit(*s)) 75059243Sobrien c += *s - '0'; 75159243Sobrien else if (*s >= 'a' && *s <= 'f') 75259243Sobrien c += *s - 'a' + 0xA; 75359243Sobrien else if (*s >= 'F' && *s <= 'F') 75459243Sobrien c += *s - 'A' + 0xA; 75559243Sobrien } 75659243Sobrien } 75759243Sobrien else if (s[0] == '0' && Isdigit(s[1])) { /* if 0n, then assume number */ 75859243Sobrien c = 0; 75959243Sobrien for (s++; *s; s++) { /* convert to octal; skip the first 0 */ 76059243Sobrien if (!Isdigit(*s) || *s == '8' || *s == '9') { 76159243Sobrien xprintf(CGETS(20, 31, 76259243Sobrien "bad key specification -- malformed octal number\n")); 76359243Sobrien return -1; /* error */ 76459243Sobrien } 76559243Sobrien c = (c * 8) + *s - '0'; 76659243Sobrien } 76759243Sobrien } 76859243Sobrien else if (Isdigit(s[0]) && Isdigit(s[1])) { /* decimal number */ 76959243Sobrien c = 0; 77059243Sobrien for (; *s; s++) { /* convert to octal; skip the first 0 */ 77159243Sobrien if (!Isdigit(*s)) { 77259243Sobrien xprintf(CGETS(20, 32, 77359243Sobrien "bad key specification -- malformed decimal number\n")); 77459243Sobrien return -1; /* error */ 77559243Sobrien } 77659243Sobrien c = (c * 10) + *s - '0'; 77759243Sobrien } 77859243Sobrien } 77959243Sobrien else { 78059243Sobrien keycmd = getkeycmd(&s); 78159243Sobrien 78259243Sobrien if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') { /* X- */ 78359243Sobrien ctrlx++; 78459243Sobrien s += 2; 78559243Sobrien keycmd = getkeycmd(&s); 78659243Sobrien } 78759243Sobrien if ((*s == 'm' || *s == 'M') && s[1] == '-') { /* meta */ 78859243Sobrien meta++; 78959243Sobrien s += 2; 79059243Sobrien keycmd = getkeycmd(&s); 79159243Sobrien } 79259243Sobrien else if (keycmd == F_METANEXT && *s) { /* meta */ 79359243Sobrien meta++; 79459243Sobrien keycmd = getkeycmd(&s); 79559243Sobrien } 79659243Sobrien if (*s == '^' && s[1]) { 79759243Sobrien control++; 79859243Sobrien s++; 79959243Sobrien keycmd = getkeycmd(&s); 80059243Sobrien } 80159243Sobrien else if ((*s == 'c' || *s == 'C') && s[1] == '-') { /* control */ 80259243Sobrien control++; 80359243Sobrien s += 2; 80459243Sobrien keycmd = getkeycmd(&s); 80559243Sobrien } 80659243Sobrien 80759243Sobrien if (keycmd == F_XKEY) { 80859243Sobrien if (*s == 0) { 80959243Sobrien xprintf(CGETS(20, 33, 81059243Sobrien "Bad function-key specification.\n")); 81159243Sobrien xprintf(CGETS(20, 34, "Null key not allowed\n")); 81259243Sobrien return (-1); 81359243Sobrien } 81459243Sobrien *sp = s; 81559243Sobrien return (-2); 81659243Sobrien } 81759243Sobrien 81859243Sobrien if (s[1] != 0) { /* if symbolic name */ 81959243Sobrien char *ts; 82059243Sobrien 82159243Sobrien ts = short2str(s); 82259243Sobrien if (!strcmp(ts, "space") || !strcmp(ts, "Spc")) 82359243Sobrien c = ' '; 82459243Sobrien else if (!strcmp(ts, "return") || !strcmp(ts, "Ret")) 82559243Sobrien c = '\r'; 82659243Sobrien else if (!strcmp(ts, "newline") || !strcmp(ts, "Lfd")) 82759243Sobrien c = '\n'; 82859243Sobrien else if (!strcmp(ts, "linefeed")) 82959243Sobrien c = '\n'; 83059243Sobrien else if (!strcmp(ts, "tab")) 83159243Sobrien c = '\t'; 83259243Sobrien else if (!strcmp(ts, "escape") || !strcmp(ts, "Esc")) 83359243Sobrien c = CTL_ESC('\033'); 83459243Sobrien else if (!strcmp(ts, "backspace")) 83559243Sobrien c = '\b'; 83659243Sobrien else if (!strcmp(ts, "delete")) 83759243Sobrien c = CTL_ESC('\177'); 83859243Sobrien else { 83959243Sobrien xprintf(CGETS(20, 35, 84059243Sobrien "bad key specification -- unknown name \"%S\"\n"), s); 84159243Sobrien return -1; /* error */ 84259243Sobrien } 84359243Sobrien } 84459243Sobrien else 84559243Sobrien c = *s; /* just a single char */ 84659243Sobrien 84759243Sobrien if (control) 84859243Sobrien c = tocontrol(c); 84959243Sobrien if (meta) 85059243Sobrien c |= META; 85159243Sobrien if (ctrlx) 85259243Sobrien c |= 0400; 85359243Sobrien } 85459243Sobrien return (c & 0777); 85559243Sobrien} 85659243Sobrien 85759243Sobrien 85859243Sobrien/*ARGSUSED*/ 85959243Sobrienvoid 86059243Sobriendobind(v, dummy) 86159243Sobrien register Char **v; 86259243Sobrien struct command *dummy; 86359243Sobrien{ 86459243Sobrien register int c; 86559243Sobrien register struct KeyFuncs *fp; 86659243Sobrien register int i, prev; 86759243Sobrien Char *p, *l; 86859243Sobrien CStr cstr; 86959243Sobrien Char buf[1000]; 87059243Sobrien 87159243Sobrien USE(dummy); 87259243Sobrien /* 87359243Sobrien * Assume at this point that i'm given 2 or 3 args - 'bind', the f-name, 87459243Sobrien * and the key; or 'bind' key to print the func for that key. 87559243Sobrien */ 87659243Sobrien 87759243Sobrien if (!MapsAreInited) 87859243Sobrien ed_InitMaps(); 87959243Sobrien 88059243Sobrien if (v[1] && v[2] && v[3]) { 88159243Sobrien xprintf(CGETS(20, 36, 88259243Sobrien "usage: bind [KEY | COMMAND KEY | \"emacs\" | \"vi\" | \"-a\"]\n")); 88359243Sobrien return; 88459243Sobrien } 88559243Sobrien 88659243Sobrien if (v[1] && v[2]) { /* if bind FUNCTION KEY */ 88759243Sobrien for (fp = FuncNames; fp->name; fp++) { 88859243Sobrien if (strcmp(short2str(v[1]), fp->name) == 0) { 88959243Sobrien Char *s = v[2]; 89059243Sobrien 89159243Sobrien if ((c = parsekey(&s)) == -1) 89259243Sobrien return; 89359243Sobrien if (c == -2) { /* extended key */ 89459243Sobrien for (i = 0; i < 256; i++) { 89559243Sobrien if (i != CTL_ESC('\033') && (CcKeyMap[i] == F_XKEY || 89659243Sobrien CcAltMap[i] == F_XKEY)) { 89759243Sobrien p = buf; 89869408Sache#ifdef IS_ASCII 89959243Sobrien if (i > 0177) { 90059243Sobrien *p++ = 033; 90159243Sobrien *p++ = i & ASCII; 90259243Sobrien } 90359243Sobrien else { 90459243Sobrien *p++ = (Char) i; 90559243Sobrien } 90669408Sache#else 90759243Sobrien *p++ = (Char) i; 90869408Sache#endif 90959243Sobrien for (l = s; *l != 0; l++) { 91059243Sobrien *p++ = *l; 91159243Sobrien } 91259243Sobrien *p = 0; 91359243Sobrien cstr.buf = buf; 91459243Sobrien cstr.len = Strlen(buf); 91559243Sobrien AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 91659243Sobrien } 91759243Sobrien } 91859243Sobrien return; 91959243Sobrien } 92059243Sobrien if (c & 0400) { 92159243Sobrien if (VImode) { 92259243Sobrien CcAltMap[c & APOLLO_0377] = fp->func; 92359243Sobrien /* bind the vi cmd mode key */ 92459243Sobrien if (c & META) { 92559243Sobrien buf[0] = CTL_ESC('\033'); 92659243Sobrien buf[1] = c & ASCII; 92759243Sobrien buf[2] = 0; 92859243Sobrien cstr.buf = buf; 92959243Sobrien cstr.len = Strlen(buf); 93059243Sobrien AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 93159243Sobrien } 93259243Sobrien } 93359243Sobrien else { 93459243Sobrien buf[0] = CTL_ESC('\030'); /* ^X */ 93559243Sobrien buf[1] = c & APOLLO_0377; 93659243Sobrien buf[2] = 0; 93759243Sobrien cstr.buf = buf; 93859243Sobrien cstr.len = Strlen(buf); 93959243Sobrien AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 94059243Sobrien CcKeyMap[CTL_ESC('\030')] = F_XKEY; 94159243Sobrien } 94259243Sobrien } 94359243Sobrien else { 94459243Sobrien CcKeyMap[c] = fp->func; /* bind the key */ 94559243Sobrien if (c & META) { 94659243Sobrien buf[0] = CTL_ESC('\033'); 94759243Sobrien buf[1] = c & ASCII; 94859243Sobrien buf[2] = 0; 94959243Sobrien cstr.buf = buf; 95059243Sobrien cstr.len = Strlen(buf); 95159243Sobrien AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 95259243Sobrien } 95359243Sobrien } 95459243Sobrien return; 95559243Sobrien } 95659243Sobrien } 95759243Sobrien stderror(ERR_NAME | ERR_STRING, CGETS(20, 37, "Invalid function")); 95859243Sobrien } 95959243Sobrien else if (v[1]) { 96059243Sobrien char *cv = short2str(v[1]); 96159243Sobrien 96259243Sobrien if (strcmp(cv, "list") == 0) { 96359243Sobrien for (fp = FuncNames; fp->name; fp++) { 96459243Sobrien xprintf("%s\n", fp->name); 96559243Sobrien } 96659243Sobrien return; 96759243Sobrien } 96859243Sobrien if ((strcmp(cv, "emacs") == 0) || 96959243Sobrien#ifndef VIDEFAULT 97059243Sobrien (strcmp(cv, "defaults") == 0) || 97159243Sobrien (strcmp(cv, "default") == 0) || 97259243Sobrien#endif 97359243Sobrien (strcmp(cv, "mg") == 0) || 97459243Sobrien (strcmp(cv, "gnumacs") == 0)) { 97559243Sobrien /* reset keys to default */ 97659243Sobrien ed_InitEmacsMaps(); 97759243Sobrien#ifdef VIDEFAULT 97859243Sobrien } 97959243Sobrien else if ((strcmp(cv, "vi") == 0) 98059243Sobrien || (strcmp(cv, "default") == 0) 98159243Sobrien || (strcmp(cv, "defaults") == 0)) { 98259243Sobrien#else 98359243Sobrien } 98459243Sobrien else if (strcmp(cv, "vi") == 0) { 98559243Sobrien#endif 98659243Sobrien ed_InitVIMaps(); 98759243Sobrien } 98859243Sobrien else { /* want to know what this key does */ 98959243Sobrien Char *s = v[1]; 99059243Sobrien 99159243Sobrien if ((c = parsekey(&s)) == -1) 99259243Sobrien return; 99359243Sobrien if (c == -2) { /* extended key */ 99459243Sobrien cstr.buf = s; 99559243Sobrien cstr.len = Strlen(s); 99659243Sobrien PrintXkey(&cstr); 99759243Sobrien return; 99859243Sobrien } 99959243Sobrien pkeys(c, c); /* must be regular key */ 100059243Sobrien } 100159243Sobrien } 100259243Sobrien else { /* list all the bindings */ 100359243Sobrien prev = 0; 100459243Sobrien for (i = 0; i < 256; i++) { 100559243Sobrien if (CcKeyMap[prev] == CcKeyMap[i]) 100659243Sobrien continue; 100759243Sobrien pkeys(prev, i - 1); 100859243Sobrien prev = i; 100959243Sobrien } 101059243Sobrien pkeys(prev, i - 1); 101159243Sobrien prev = 0; 101259243Sobrien for (i = 256; i < 512; i++) { 101359243Sobrien if (CcAltMap[prev & APOLLO_0377] == CcAltMap[i & APOLLO_0377]) 101459243Sobrien continue; 101559243Sobrien pkeys(prev, i - 1); 101659243Sobrien prev = i; 101759243Sobrien } 101859243Sobrien pkeys(prev, i - 1); 101959243Sobrien cstr.buf = NULL; 102059243Sobrien cstr.len = 0; 102159243Sobrien PrintXkey(&cstr); /* print all Xkey bindings */ 102259243Sobrien } 102359243Sobrien return; 102459243Sobrien} 102559243Sobrien 102659243Sobrienstatic void 102759243Sobrienpkeys(first, last) 102859243Sobrien register int first, last; 102959243Sobrien{ 103059243Sobrien register struct KeyFuncs *fp; 103159243Sobrien register KEYCMD *map; 103259243Sobrien int mask; 103359243Sobrien char buf[8]; 103459243Sobrien 103559243Sobrien if (last & 0400) { 103659243Sobrien map = CcAltMap; 103759243Sobrien first &= APOLLO_0377; 103859243Sobrien last &= APOLLO_0377; 103959243Sobrien mask = 0400; 104059243Sobrien } 104159243Sobrien else { 104259243Sobrien map = CcKeyMap; 104359243Sobrien mask = 0; 104459243Sobrien } 104559243Sobrien if (map[first] == F_UNASSIGNED) { 104659243Sobrien if (first == last) 104759243Sobrien xprintf(CGETS(20, 38, " %s\t\tis undefined\n"), 104859243Sobrien unparsekey(first | mask)); 104959243Sobrien return; 105059243Sobrien } 105159243Sobrien 105259243Sobrien for (fp = FuncNames; fp->name; fp++) { 105359243Sobrien if (fp->func == map[first]) { 105459243Sobrien if (first == last) 105559243Sobrien xprintf(" %s\t\t%s\n", 105659243Sobrien unparsekey((first & APOLLO_0377) | mask), fp->name); 105759243Sobrien else { 105859243Sobrien (void) strcpy(buf, unparsekey((first & APOLLO_0377) | mask)); 105959243Sobrien xprintf(" %s..%s\t\t%s\n", buf, 106059243Sobrien unparsekey((last & APOLLO_0377) | mask), fp->name); 106159243Sobrien } 106259243Sobrien return; 106359243Sobrien } 106459243Sobrien } 106559243Sobrien if (map == CcKeyMap) { 106659243Sobrien xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 106759243Sobrien unparsekey(first)); 106859243Sobrien xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]); 106959243Sobrien } 107059243Sobrien else { 107159243Sobrien xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 107259243Sobrien unparsekey(first & 0400)); 107359243Sobrien xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]); 107459243Sobrien } 107559243Sobrien} 107659243Sobrien#endif /* OBSOLETE */ 1077