From 4ad28cefef28ce6bdb44a0532cfe20a2076bc694 Mon Sep 17 00:00:00 2001 From: obrien Date: Sat, 15 Apr 2000 04:41:27 +0000 Subject: Import the latest version of the 44BSD C-shell -- tcsh-6.09. --- contrib/tcsh/ed.xmap.c | 844 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 844 insertions(+) create mode 100644 contrib/tcsh/ed.xmap.c (limited to 'contrib/tcsh/ed.xmap.c') diff --git a/contrib/tcsh/ed.xmap.c b/contrib/tcsh/ed.xmap.c new file mode 100644 index 0000000..d4d9bd6 --- /dev/null +++ b/contrib/tcsh/ed.xmap.c @@ -0,0 +1,844 @@ +/* $Header: /src/pub/tcsh/ed.xmap.c,v 3.21 1999/06/01 20:01:32 christos Exp $ */ +/* + * ed.xmap.c: This module contains the procedures for maintaining + * the extended-key map. + * + * An extended-key (Xkey) is a sequence of keystrokes + * introduced with an sequence introducer and consisting + * of an arbitrary number of characters. This module maintains + * a map (the Xmap) to convert these extended-key sequences + * into input strings (XK_STR), editor functions (XK_CMD), or + * unix commands (XK_EXE). It contains the + * following externally visible functions. + * + * int GetXkey(ch,val); + * CStr *ch; + * XmapVal *val; + * + * Looks up *ch in map and then reads characters until a + * complete match is found or a mismatch occurs. Returns the + * type of the match found (XK_STR, XK_CMD, or XK_EXE). + * Returns NULL in val.str and XK_STR for no match. + * The last character read is returned in *ch. + * + * void AddXkey(Xkey, val, ntype); + * CStr *Xkey; + * XmapVal *val; + * int ntype; + * + * Adds Xkey to the Xmap and associates the value in val with it. + * If Xkey is already is in Xmap, the new code is applied to the + * existing Xkey. Ntype specifies if code is a command, an + * out string or a unix command. + * + * int DeleteXkey(Xkey); + * CStr *Xkey; + * + * Delete the Xkey and all longer Xkeys staring with Xkey, if + * they exists. + * + * Warning: + * If Xkey is a substring of some other Xkeys, then the longer + * Xkeys are lost!! That is, if the Xkeys "abcd" and "abcef" + * are in Xmap, adding the key "abc" will cause the first two + * definitions to be lost. + * + * void ResetXmap(); + * + * Removes all entries from Xmap and resets the defaults. + * + * void PrintXkey(Xkey); + * CStr *Xkey; + * + * Prints all extended keys prefixed by Xkey and their associated + * commands. + * + * Restrictions: + * ------------- + * 1) It is not possible to have one Xkey that is a + * substring of another. + */ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sh.h" + +RCSID("$Id: ed.xmap.c,v 3.21 1999/06/01 20:01:32 christos Exp $") + +#include "ed.h" +#include "ed.defns.h" + +#ifndef NULL +#define NULL 0 +#endif + +/* Internal Data types and declarations */ + +/* The Nodes of the Xmap. The Xmap is a linked list of these node + * elements + */ +typedef struct Xmapnode { + Char ch; /* single character of Xkey */ + int type; + XmapVal val; /* command code or pointer to string, if this + * is a leaf */ + struct Xmapnode *next; /* ptr to next char of this Xkey */ + struct Xmapnode *sibling; /* ptr to another Xkey with same prefix */ +} XmapNode; + +static XmapNode *Xmap = NULL; /* the current Xmap */ +#define MAXXKEY 100 /* max length of a Xkey for print putposes */ +static Char printbuf[MAXXKEY]; /* buffer for printing */ + + +/* Some declarations of procedures */ +static int TraverseMap __P((XmapNode *, CStr *, XmapVal *)); +static int TryNode __P((XmapNode *, CStr *, XmapVal *, int)); +static XmapNode *GetFreeNode __P((CStr *)); +static void PutFreeNode __P((XmapNode *)); +static int TryDeleteNode __P((XmapNode **, CStr *)); +static int Lookup __P((CStr *, XmapNode *, int)); +static int Enumerate __P((XmapNode *, int)); +static int unparsech __P((int, Char *)); + + +XmapVal * +XmapCmd(cmd) + int cmd; +{ + static XmapVal xm; + xm.cmd = (KEYCMD) cmd; + return &xm; +} + +XmapVal * +XmapStr(str) + CStr *str; +{ + static XmapVal xm; + xm.str.len = str->len; + xm.str.buf = str->buf; + return &xm; +} + +/* ResetXmap(): + * Takes all nodes on Xmap and puts them on free list. Then + * initializes Xmap with arrow keys + */ +void +ResetXmap() +{ + PutFreeNode(Xmap); + Xmap = NULL; + + DefaultArrowKeys(); + return; +} + + +/* GetXkey(): + * Calls the recursive function with entry point Xmap + */ +int +GetXkey(ch, val) + CStr *ch; + XmapVal *val; +{ + return (TraverseMap(Xmap, ch, val)); +} + +/* TraverseMap(): + * recursively traverses node in tree until match or mismatch is + * found. May read in more characters. + */ +static int +TraverseMap(ptr, ch, val) + XmapNode *ptr; + CStr *ch; + XmapVal *val; +{ + Char tch; + + if (ptr->ch == *(ch->buf)) { + /* match found */ + if (ptr->next) { + /* Xkey not complete so get next char */ + if (GetNextChar(&tch) != 1) { /* if EOF or error */ + val->cmd = F_SEND_EOF; + return XK_CMD;/* PWP: Pretend we just read an end-of-file */ + } + *(ch->buf) = tch; + return (TraverseMap(ptr->next, ch, val)); + } + else { + *val = ptr->val; + if (ptr->type != XK_CMD) + *(ch->buf) = '\0'; + return ptr->type; + } + } + else { + /* no match found here */ + if (ptr->sibling) { + /* try next sibling */ + return (TraverseMap(ptr->sibling, ch, val)); + } + else { + /* no next sibling -- mismatch */ + val->str.buf = NULL; + val->str.len = 0; + return XK_STR; + } + } +} + +void +AddXkey(Xkey, val, ntype) + CStr *Xkey; + XmapVal *val; + int ntype; +{ + CStr cs; + cs.buf = Xkey->buf; + cs.len = Xkey->len; + if (Xkey->len == 0) { + xprintf(CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n")); + return; + } + + if (ntype == XK_CMD && val->cmd == F_XKEY) { + xprintf(CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n")); + return; + } + + if (Xmap == NULL) + /* tree is initially empty. Set up new node to match Xkey[0] */ + Xmap = GetFreeNode(&cs); /* it is properly initialized */ + + /* Now recurse through Xmap */ + (void) TryNode(Xmap, &cs, val, ntype); + return; +} + +static int +TryNode(ptr, str, val, ntype) + XmapNode *ptr; + CStr *str; + XmapVal *val; + int ntype; +{ + /* + * Find a node that matches *string or allocate a new one + */ + if (ptr->ch != *(str->buf)) { + XmapNode *xm; + + for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) + if (xm->sibling->ch == *(str->buf)) + break; + if (xm->sibling == NULL) + xm->sibling = GetFreeNode(str); /* setup new node */ + ptr = xm->sibling; + } + + str->buf++; + str->len--; + if (str->len == 0) { + /* we're there */ + if (ptr->next != NULL) { + PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */ + ptr->next = NULL; + } + + switch (ptr->type) { + case XK_STR: + case XK_EXE: + if (ptr->val.str.buf != NULL) + xfree((ptr_t) ptr->val.str.buf); + ptr->val.str.len = 0; + break; + case XK_NOD: + case XK_CMD: + break; + default: + abort(); + break; + } + + switch (ptr->type = ntype) { + case XK_CMD: + ptr->val = *val; + break; + case XK_STR: + case XK_EXE: + ptr->val.str.len = (val->str.len + 1) * sizeof(Char); + ptr->val.str.buf = (Char *) xmalloc((size_t) ptr->val.str.len); + (void) memmove((ptr_t) ptr->val.str.buf, (ptr_t) val->str.buf, + (size_t) ptr->val.str.len); + ptr->val.str.len = val->str.len; + break; + default: + abort(); + break; + } + } + else { + /* still more chars to go */ + if (ptr->next == NULL) + ptr->next = GetFreeNode(str); /* setup new node */ + (void) TryNode(ptr->next, str, val, ntype); + } + return (0); +} + +void +ClearXkey(map, in) + KEYCMD *map; + CStr *in; +{ + unsigned char c = (unsigned char) *(in->buf); + if ((map[c] == F_XKEY) && + ((map == CcKeyMap && CcAltMap[c] != F_XKEY) || + (map == CcAltMap && CcKeyMap[c] != F_XKEY))) + (void) DeleteXkey(in); +} + +int +DeleteXkey(Xkey) + CStr *Xkey; +{ + if (Xkey->len == 0) { + xprintf(CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n")); + return (-1); + } + + if (Xmap == NULL) + return (0); + + (void) TryDeleteNode(&Xmap, Xkey); + return (0); +} + +static int +TryDeleteNode(inptr, str) + XmapNode **inptr; + CStr *str; +{ + XmapNode *ptr; + XmapNode *prev_ptr = NULL; + + ptr = *inptr; + /* + * Find a node that matches *string or allocate a new one + */ + if (ptr->ch != *(str->buf)) { + XmapNode *xm; + + for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) + if (xm->sibling->ch == *(str->buf)) + break; + if (xm->sibling == NULL) + return (0); + prev_ptr = xm; + ptr = xm->sibling; + } + + str->buf++; + str->len--; + + if (str->len == 0) { + /* we're there */ + if (prev_ptr == NULL) + *inptr = ptr->sibling; + else + prev_ptr->sibling = ptr->sibling; + ptr->sibling = NULL; + PutFreeNode(ptr); + return (1); + } + else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) { + if (ptr->next != NULL) + return (0); + if (prev_ptr == NULL) + *inptr = ptr->sibling; + else + prev_ptr->sibling = ptr->sibling; + ptr->sibling = NULL; + PutFreeNode(ptr); + return (1); + } + else { + return (0); + } +} + +/* PutFreeNode(): + * Puts a tree of nodes onto free list using free(3). + */ +static void +PutFreeNode(ptr) + XmapNode *ptr; +{ + if (ptr == NULL) + return; + + if (ptr->next != NULL) { + PutFreeNode(ptr->next); + ptr->next = NULL; + } + + PutFreeNode(ptr->sibling); + + switch (ptr->type) { + case XK_CMD: + case XK_NOD: + break; + case XK_EXE: + case XK_STR: + if (ptr->val.str.buf != NULL) + xfree((ptr_t) ptr->val.str.buf); + break; + default: + abort(); + break; + } + xfree((ptr_t) ptr); +} + + +/* GetFreeNode(): + * Returns pointer to an XmapNode for ch. + */ +static XmapNode * +GetFreeNode(ch) + CStr *ch; +{ + XmapNode *ptr; + + ptr = (XmapNode *) xmalloc((size_t) sizeof(XmapNode)); + ptr->ch = ch->buf[0]; + ptr->type = XK_NOD; + ptr->val.str.buf = NULL; + ptr->val.str.len = 0; + ptr->next = NULL; + ptr->sibling = NULL; + return (ptr); +} + + +/* PrintXKey(): + * Print the binding associated with Xkey key. + * Print entire Xmap if null + */ +void +PrintXkey(key) + CStr *key; +{ + CStr cs; + + if (key) { + cs.buf = key->buf; + cs.len = key->len; + } + else { + cs.buf = STRNULL; + cs.len = 0; + } + /* do nothing if Xmap is empty and null key specified */ + if (Xmap == NULL && cs.len == 0) + return; + + printbuf[0] = '"'; + if (Lookup(&cs, Xmap, 1) <= -1) + /* key is not bound */ + xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf); + return; +} + +/* Lookup(): + * look for the string starting at node ptr. + * Print if last node + */ +static int +Lookup(str, ptr, cnt) + CStr *str; + XmapNode *ptr; + int cnt; +{ + int ncnt; + + if (ptr == NULL) + return (-1); /* cannot have null ptr */ + + if (str->len == 0) { + /* no more chars in string. Enumerate from here. */ + (void) Enumerate(ptr, cnt); + return (0); + } + else { + /* If match put this char into printbuf. Recurse */ + if (ptr->ch == *(str->buf)) { + /* match found */ + ncnt = unparsech(cnt, &ptr->ch); + if (ptr->next != NULL) { + /* not yet at leaf */ + CStr tstr; + tstr.buf = str->buf + 1; + tstr.len = str->len - 1; + return (Lookup(&tstr, ptr->next, ncnt + 1)); + } + else { + /* next node is null so key should be complete */ + if (str->len == 1) { + CStr pb; + printbuf[ncnt + 1] = '"'; + printbuf[ncnt + 2] = '\0'; + pb.buf = printbuf; + pb.len = ncnt + 2; + (void) printOne(&pb, &ptr->val, ptr->type); + return (0); + } + else + return (-1);/* mismatch -- string still has chars */ + } + } + else { + /* no match found try sibling */ + if (ptr->sibling) + return (Lookup(str, ptr->sibling, cnt)); + else + return (-1); + } + } +} + +static int +Enumerate(ptr, cnt) + XmapNode *ptr; + int cnt; +{ + int ncnt; + + if (cnt >= MAXXKEY - 5) { /* buffer too small */ + printbuf[++cnt] = '"'; + printbuf[++cnt] = '\0'; + xprintf(CGETS(9, 5, + "Some extended keys too long for internal print buffer")); + xprintf(" \"%S...\"\n", printbuf); + return (0); + } + + if (ptr == NULL) { +#ifdef DEBUG_EDIT + xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!")); +#endif + return (-1); + } + + ncnt = unparsech(cnt, &ptr->ch); /* put this char at end of string */ + if (ptr->next == NULL) { + CStr pb; + /* print this Xkey and function */ + printbuf[++ncnt] = '"'; + printbuf[++ncnt] = '\0'; + pb.buf = printbuf; + pb.len = ncnt; + (void) printOne(&pb, &ptr->val, ptr->type); + } + else + (void) Enumerate(ptr->next, ncnt + 1); + + /* go to sibling if there is one */ + if (ptr->sibling) + (void) Enumerate(ptr->sibling, cnt); + return (0); +} + + +/* PrintOne(): + * Print the specified key and its associated + * function specified by val + */ +int +printOne(key, val, ntype) + CStr *key; + XmapVal *val; + int ntype; +{ + struct KeyFuncs *fp; + unsigned char unparsbuf[200]; + static char *fmt = "%s\n"; + + xprintf("%-15S-> ", key->buf); + if (val != NULL) + switch (ntype) { + case XK_STR: + case XK_EXE: + xprintf(fmt, unparsestring(&val->str, unparsbuf, + ntype == XK_STR ? STRQQ : STRBB)); + break; + case XK_CMD: + for (fp = FuncNames; fp->name; fp++) + if (val->cmd == fp->func) + xprintf(fmt, fp->name); + break; + default: + abort(); + break; + } + else + xprintf(fmt, key, CGETS(9, 7, "no input")); + return (0); +} + +static int +unparsech(cnt, ch) + int cnt; + Char *ch; +{ + if (ch == 0) { + printbuf[cnt++] = '^'; + printbuf[cnt] = '@'; + return cnt; + } + + if (Iscntrl(*ch)) { +#ifndef _OSD_POSIX + printbuf[cnt++] = '^'; + if (*ch == CTL_ESC('\177')) + printbuf[cnt] = '?'; + else + printbuf[cnt] = *ch | 0100; +#else /*_OSD_POSIX*/ + if (*ch == CTL_ESC('\177')) + { + printbuf[cnt++] = '^'; + printbuf[cnt] = '?'; + } + else if (Isupper(_toebcdic[_toascii[*ch]|0100]) + || strchr("@[\\]^_", _toebcdic[_toascii[*ch]|0100]) != NULL) + { + printbuf[cnt++] = '^'; + printbuf[cnt] = _toebcdic[_toascii[*ch]|0100]; + } + else + { + printbuf[cnt++] = '\\'; + printbuf[cnt++] = ((*ch >> 6) & 7) + '0'; + printbuf[cnt++] = ((*ch >> 3) & 7) + '0'; + printbuf[cnt] = (*ch & 7) + '0'; + } +#endif /*_OSD_POSIX*/ + } + else if (*ch == '^') { + printbuf[cnt++] = '\\'; + printbuf[cnt] = '^'; + } + else if (*ch == '\\') { + printbuf[cnt++] = '\\'; + printbuf[cnt] = '\\'; + } + else if (*ch == ' ' || (Isprint(*ch) && !Isspace(*ch))) { + printbuf[cnt] = *ch; + } + else { + printbuf[cnt++] = '\\'; + printbuf[cnt++] = ((*ch >> 6) & 7) + '0'; + printbuf[cnt++] = ((*ch >> 3) & 7) + '0'; + printbuf[cnt] = (*ch & 7) + '0'; + } + return cnt; +} + +int +parseescape(ptr) + const Char **ptr; +{ + const Char *p; + Char c; + + p = *ptr; + + if ((p[1] & CHAR) == 0) { + xprintf(CGETS(9, 8, "Something must follow: %c\n"), *p); + return -1; + } + if ((*p & CHAR) == '\\') { + p++; + switch (*p & CHAR) { + case 'a': + c = CTL_ESC('\007'); /* Bell */ + break; + case 'b': + c = CTL_ESC('\010'); /* Backspace */ + break; + case 'e': + c = CTL_ESC('\033'); /* Escape */ + break; + case 'f': + c = CTL_ESC('\014'); /* Form Feed */ + break; + case 'n': + c = CTL_ESC('\012'); /* New Line */ + break; + case 'r': + c = CTL_ESC('\015'); /* Carriage Return */ + break; + case 't': + c = CTL_ESC('\011'); /* Horizontal Tab */ + break; + case 'v': + c = CTL_ESC('\013'); /* Vertical Tab */ + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int cnt, val, ch; + + for (cnt = 0, val = 0; cnt < 3; cnt++) { + ch = *p++ & CHAR; + if (ch < '0' || ch > '7') { + p--; + break; + } + val = (val << 3) | (ch - '0'); + } + if ((val & 0xffffff00) != 0) { + xprintf(CGETS(9, 9, + "Octal constant does not fit in a char.\n")); + return 0; + } +#ifdef _OSD_POSIX + if (CTL_ESC(val) != val && adrof(STRwarnebcdic)) + xprintf(/*CGETS(9, 9, no NLS-String yet!*/ + "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/); +#endif + c = (Char) val; + --p; + } + break; + default: + c = *p; + break; + } + } + else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) || + strchr("@^_?\\|[{]}", p[1] & CHAR))) { + p++; +#ifndef _OSD_POSIX + c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237); +#else /*_OSD_POSIX*/ + c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237]; + if (adrof(STRwarnebcdic)) + xprintf(/*CGETS(9, 9, no NLS-String yet!*/ + "Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/); +#endif /*_OSD_POSIX*/ + } + else + c = *p; + *ptr = p; + return (c); +} + + +unsigned char * +unparsestring(str, buf, sep) + CStr *str; + unsigned char *buf; + Char *sep; +{ + unsigned char *b; + Char p; + int l; + + b = buf; + if (sep[0]) +#ifndef WINNT + *b++ = sep[0]; +#else /* WINNT */ + *b++ = CHAR & sep[0]; +#endif /* !WINNT */ + + for (l = 0; l < str->len; l++) { + p = str->buf[l]; + if (Iscntrl(p)) { +#ifndef _OSD_POSIX + *b++ = '^'; + if (p == CTL_ESC('\177')) + *b++ = '?'; + else + *b++ = (unsigned char) (p | 0100); +#else /*_OSD_POSIX*/ + if (_toascii[p] == '\177' || Isupper(_toebcdic[_toascii[p]|0100]) + || strchr("@[\\]^_", _toebcdic[_toascii[p]|0100]) != NULL) + { + *b++ = '^'; + *b++ = (_toascii[p] == '\177') ? '?' : _toebcdic[_toascii[p]|0100]; + } + else + { + *b++ = '\\'; + *b++ = ((p >> 6) & 7) + '0'; + *b++ = ((p >> 3) & 7) + '0'; + *b++ = (p & 7) + '0'; + } +#endif /*_OSD_POSIX*/ + } + else if (p == '^' || p == '\\') { + *b++ = '\\'; + *b++ = (unsigned char) p; + } + else if (p == ' ' || (Isprint(p) && !Isspace(p))) { + *b++ = (unsigned char) p; + } + else { + *b++ = '\\'; + *b++ = ((p >> 6) & 7) + '0'; + *b++ = ((p >> 3) & 7) + '0'; + *b++ = (p & 7) + '0'; + } + } + if (sep[0] && sep[1]) +#ifndef WINNT + *b++ = sep[1]; +#else /* WINNT */ + *b++ = CHAR & sep[1]; +#endif /* !WINNT */ + *b++ = 0; + return buf; /* should check for overflow */ +} -- cgit v1.1