ed.xmap.c revision 83098
183098Smp/* $Header: /src/pub/tcsh/ed.xmap.c,v 3.24 2001/04/27 22:37:03 christos Exp $ */ 259243Sobrien/* 359243Sobrien * ed.xmap.c: This module contains the procedures for maintaining 459243Sobrien * the extended-key map. 559243Sobrien * 659243Sobrien * An extended-key (Xkey) is a sequence of keystrokes 759243Sobrien * introduced with an sequence introducer and consisting 859243Sobrien * of an arbitrary number of characters. This module maintains 959243Sobrien * a map (the Xmap) to convert these extended-key sequences 1059243Sobrien * into input strings (XK_STR), editor functions (XK_CMD), or 1159243Sobrien * unix commands (XK_EXE). It contains the 1259243Sobrien * following externally visible functions. 1359243Sobrien * 1459243Sobrien * int GetXkey(ch,val); 1559243Sobrien * CStr *ch; 1659243Sobrien * XmapVal *val; 1759243Sobrien * 1859243Sobrien * Looks up *ch in map and then reads characters until a 1959243Sobrien * complete match is found or a mismatch occurs. Returns the 2059243Sobrien * type of the match found (XK_STR, XK_CMD, or XK_EXE). 2159243Sobrien * Returns NULL in val.str and XK_STR for no match. 2259243Sobrien * The last character read is returned in *ch. 2359243Sobrien * 2459243Sobrien * void AddXkey(Xkey, val, ntype); 2559243Sobrien * CStr *Xkey; 2659243Sobrien * XmapVal *val; 2759243Sobrien * int ntype; 2859243Sobrien * 2959243Sobrien * Adds Xkey to the Xmap and associates the value in val with it. 3059243Sobrien * If Xkey is already is in Xmap, the new code is applied to the 3159243Sobrien * existing Xkey. Ntype specifies if code is a command, an 3259243Sobrien * out string or a unix command. 3359243Sobrien * 3459243Sobrien * int DeleteXkey(Xkey); 3559243Sobrien * CStr *Xkey; 3659243Sobrien * 3759243Sobrien * Delete the Xkey and all longer Xkeys staring with Xkey, if 3859243Sobrien * they exists. 3959243Sobrien * 4059243Sobrien * Warning: 4159243Sobrien * If Xkey is a substring of some other Xkeys, then the longer 4259243Sobrien * Xkeys are lost!! That is, if the Xkeys "abcd" and "abcef" 4359243Sobrien * are in Xmap, adding the key "abc" will cause the first two 4459243Sobrien * definitions to be lost. 4559243Sobrien * 4659243Sobrien * void ResetXmap(); 4759243Sobrien * 4859243Sobrien * Removes all entries from Xmap and resets the defaults. 4959243Sobrien * 5059243Sobrien * void PrintXkey(Xkey); 5159243Sobrien * CStr *Xkey; 5259243Sobrien * 5359243Sobrien * Prints all extended keys prefixed by Xkey and their associated 5459243Sobrien * commands. 5559243Sobrien * 5659243Sobrien * Restrictions: 5759243Sobrien * ------------- 5859243Sobrien * 1) It is not possible to have one Xkey that is a 5959243Sobrien * substring of another. 6059243Sobrien */ 6159243Sobrien/*- 6259243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 6359243Sobrien * All rights reserved. 6459243Sobrien * 6559243Sobrien * Redistribution and use in source and binary forms, with or without 6659243Sobrien * modification, are permitted provided that the following conditions 6759243Sobrien * are met: 6859243Sobrien * 1. Redistributions of source code must retain the above copyright 6959243Sobrien * notice, this list of conditions and the following disclaimer. 7059243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 7159243Sobrien * notice, this list of conditions and the following disclaimer in the 7259243Sobrien * documentation and/or other materials provided with the distribution. 7359243Sobrien * 3. All advertising materials mentioning features or use of this software 7459243Sobrien * must display the following acknowledgement: 7559243Sobrien * This product includes software developed by the University of 7659243Sobrien * California, Berkeley and its contributors. 7759243Sobrien * 4. Neither the name of the University nor the names of its contributors 7859243Sobrien * may be used to endorse or promote products derived from this software 7959243Sobrien * without specific prior written permission. 8059243Sobrien * 8159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 8259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 8459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 8559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 8659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 8759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 8859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 8959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 9059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 9159243Sobrien * SUCH DAMAGE. 9259243Sobrien */ 9359243Sobrien#include "sh.h" 9459243Sobrien 9583098SmpRCSID("$Id: ed.xmap.c,v 3.24 2001/04/27 22:37:03 christos Exp $") 9659243Sobrien 9759243Sobrien#include "ed.h" 9859243Sobrien#include "ed.defns.h" 9959243Sobrien 10059243Sobrien#ifndef NULL 10159243Sobrien#define NULL 0 10259243Sobrien#endif 10359243Sobrien 10459243Sobrien/* Internal Data types and declarations */ 10559243Sobrien 10659243Sobrien/* The Nodes of the Xmap. The Xmap is a linked list of these node 10759243Sobrien * elements 10859243Sobrien */ 10959243Sobrientypedef struct Xmapnode { 11059243Sobrien Char ch; /* single character of Xkey */ 11159243Sobrien int type; 11259243Sobrien XmapVal val; /* command code or pointer to string, if this 11359243Sobrien * is a leaf */ 11459243Sobrien struct Xmapnode *next; /* ptr to next char of this Xkey */ 11559243Sobrien struct Xmapnode *sibling; /* ptr to another Xkey with same prefix */ 11659243Sobrien} XmapNode; 11759243Sobrien 11859243Sobrienstatic XmapNode *Xmap = NULL; /* the current Xmap */ 11959243Sobrien#define MAXXKEY 100 /* max length of a Xkey for print putposes */ 12059243Sobrienstatic Char printbuf[MAXXKEY]; /* buffer for printing */ 12159243Sobrien 12259243Sobrien 12359243Sobrien/* Some declarations of procedures */ 12459243Sobrienstatic int TraverseMap __P((XmapNode *, CStr *, XmapVal *)); 12559243Sobrienstatic int TryNode __P((XmapNode *, CStr *, XmapVal *, int)); 12659243Sobrienstatic XmapNode *GetFreeNode __P((CStr *)); 12759243Sobrienstatic void PutFreeNode __P((XmapNode *)); 12859243Sobrienstatic int TryDeleteNode __P((XmapNode **, CStr *)); 12959243Sobrienstatic int Lookup __P((CStr *, XmapNode *, int)); 13059243Sobrienstatic int Enumerate __P((XmapNode *, int)); 13159243Sobrienstatic int unparsech __P((int, Char *)); 13259243Sobrien 13359243Sobrien 13459243SobrienXmapVal * 13559243SobrienXmapCmd(cmd) 13659243Sobrien int cmd; 13759243Sobrien{ 13859243Sobrien static XmapVal xm; 13959243Sobrien xm.cmd = (KEYCMD) cmd; 14059243Sobrien return &xm; 14159243Sobrien} 14259243Sobrien 14359243SobrienXmapVal * 14459243SobrienXmapStr(str) 14559243Sobrien CStr *str; 14659243Sobrien{ 14759243Sobrien static XmapVal xm; 14859243Sobrien xm.str.len = str->len; 14959243Sobrien xm.str.buf = str->buf; 15059243Sobrien return &xm; 15159243Sobrien} 15259243Sobrien 15359243Sobrien/* ResetXmap(): 15459243Sobrien * Takes all nodes on Xmap and puts them on free list. Then 15559243Sobrien * initializes Xmap with arrow keys 15659243Sobrien */ 15759243Sobrienvoid 15859243SobrienResetXmap() 15959243Sobrien{ 16059243Sobrien PutFreeNode(Xmap); 16159243Sobrien Xmap = NULL; 16259243Sobrien 16359243Sobrien DefaultArrowKeys(); 16459243Sobrien return; 16559243Sobrien} 16659243Sobrien 16759243Sobrien 16859243Sobrien/* GetXkey(): 16959243Sobrien * Calls the recursive function with entry point Xmap 17059243Sobrien */ 17159243Sobrienint 17259243SobrienGetXkey(ch, val) 17359243Sobrien CStr *ch; 17459243Sobrien XmapVal *val; 17559243Sobrien{ 17659243Sobrien return (TraverseMap(Xmap, ch, val)); 17759243Sobrien} 17859243Sobrien 17959243Sobrien/* TraverseMap(): 18059243Sobrien * recursively traverses node in tree until match or mismatch is 18159243Sobrien * found. May read in more characters. 18259243Sobrien */ 18359243Sobrienstatic int 18459243SobrienTraverseMap(ptr, ch, val) 18559243Sobrien XmapNode *ptr; 18659243Sobrien CStr *ch; 18759243Sobrien XmapVal *val; 18859243Sobrien{ 18959243Sobrien Char tch; 19059243Sobrien 19159243Sobrien if (ptr->ch == *(ch->buf)) { 19259243Sobrien /* match found */ 19359243Sobrien if (ptr->next) { 19459243Sobrien /* Xkey not complete so get next char */ 19559243Sobrien if (GetNextChar(&tch) != 1) { /* if EOF or error */ 19659243Sobrien val->cmd = F_SEND_EOF; 19759243Sobrien return XK_CMD;/* PWP: Pretend we just read an end-of-file */ 19859243Sobrien } 19959243Sobrien *(ch->buf) = tch; 20059243Sobrien return (TraverseMap(ptr->next, ch, val)); 20159243Sobrien } 20259243Sobrien else { 20359243Sobrien *val = ptr->val; 20459243Sobrien if (ptr->type != XK_CMD) 20559243Sobrien *(ch->buf) = '\0'; 20659243Sobrien return ptr->type; 20759243Sobrien } 20859243Sobrien } 20959243Sobrien else { 21059243Sobrien /* no match found here */ 21159243Sobrien if (ptr->sibling) { 21259243Sobrien /* try next sibling */ 21359243Sobrien return (TraverseMap(ptr->sibling, ch, val)); 21459243Sobrien } 21559243Sobrien else { 21659243Sobrien /* no next sibling -- mismatch */ 21759243Sobrien val->str.buf = NULL; 21859243Sobrien val->str.len = 0; 21959243Sobrien return XK_STR; 22059243Sobrien } 22159243Sobrien } 22259243Sobrien} 22359243Sobrien 22459243Sobrienvoid 22559243SobrienAddXkey(Xkey, val, ntype) 22659243Sobrien CStr *Xkey; 22759243Sobrien XmapVal *val; 22859243Sobrien int ntype; 22959243Sobrien{ 23059243Sobrien CStr cs; 23159243Sobrien cs.buf = Xkey->buf; 23259243Sobrien cs.len = Xkey->len; 23359243Sobrien if (Xkey->len == 0) { 23459243Sobrien xprintf(CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n")); 23559243Sobrien return; 23659243Sobrien } 23759243Sobrien 23859243Sobrien if (ntype == XK_CMD && val->cmd == F_XKEY) { 23959243Sobrien xprintf(CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n")); 24059243Sobrien return; 24159243Sobrien } 24259243Sobrien 24359243Sobrien if (Xmap == NULL) 24459243Sobrien /* tree is initially empty. Set up new node to match Xkey[0] */ 24559243Sobrien Xmap = GetFreeNode(&cs); /* it is properly initialized */ 24659243Sobrien 24759243Sobrien /* Now recurse through Xmap */ 24859243Sobrien (void) TryNode(Xmap, &cs, val, ntype); 24959243Sobrien return; 25059243Sobrien} 25159243Sobrien 25259243Sobrienstatic int 25359243SobrienTryNode(ptr, str, val, ntype) 25459243Sobrien XmapNode *ptr; 25559243Sobrien CStr *str; 25659243Sobrien XmapVal *val; 25759243Sobrien int ntype; 25859243Sobrien{ 25959243Sobrien /* 26059243Sobrien * Find a node that matches *string or allocate a new one 26159243Sobrien */ 26259243Sobrien if (ptr->ch != *(str->buf)) { 26359243Sobrien XmapNode *xm; 26459243Sobrien 26559243Sobrien for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 26659243Sobrien if (xm->sibling->ch == *(str->buf)) 26759243Sobrien break; 26859243Sobrien if (xm->sibling == NULL) 26959243Sobrien xm->sibling = GetFreeNode(str); /* setup new node */ 27059243Sobrien ptr = xm->sibling; 27159243Sobrien } 27259243Sobrien 27359243Sobrien str->buf++; 27459243Sobrien str->len--; 27559243Sobrien if (str->len == 0) { 27659243Sobrien /* we're there */ 27759243Sobrien if (ptr->next != NULL) { 27859243Sobrien PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */ 27959243Sobrien ptr->next = NULL; 28059243Sobrien } 28159243Sobrien 28259243Sobrien switch (ptr->type) { 28359243Sobrien case XK_STR: 28459243Sobrien case XK_EXE: 28559243Sobrien if (ptr->val.str.buf != NULL) 28659243Sobrien xfree((ptr_t) ptr->val.str.buf); 28759243Sobrien ptr->val.str.len = 0; 28859243Sobrien break; 28959243Sobrien case XK_NOD: 29059243Sobrien case XK_CMD: 29159243Sobrien break; 29259243Sobrien default: 29359243Sobrien abort(); 29459243Sobrien break; 29559243Sobrien } 29659243Sobrien 29759243Sobrien switch (ptr->type = ntype) { 29859243Sobrien case XK_CMD: 29959243Sobrien ptr->val = *val; 30059243Sobrien break; 30159243Sobrien case XK_STR: 30259243Sobrien case XK_EXE: 30359243Sobrien ptr->val.str.len = (val->str.len + 1) * sizeof(Char); 30459243Sobrien ptr->val.str.buf = (Char *) xmalloc((size_t) ptr->val.str.len); 30559243Sobrien (void) memmove((ptr_t) ptr->val.str.buf, (ptr_t) val->str.buf, 30659243Sobrien (size_t) ptr->val.str.len); 30759243Sobrien ptr->val.str.len = val->str.len; 30859243Sobrien break; 30959243Sobrien default: 31059243Sobrien abort(); 31159243Sobrien break; 31259243Sobrien } 31359243Sobrien } 31459243Sobrien else { 31559243Sobrien /* still more chars to go */ 31659243Sobrien if (ptr->next == NULL) 31759243Sobrien ptr->next = GetFreeNode(str); /* setup new node */ 31859243Sobrien (void) TryNode(ptr->next, str, val, ntype); 31959243Sobrien } 32059243Sobrien return (0); 32159243Sobrien} 32259243Sobrien 32359243Sobrienvoid 32459243SobrienClearXkey(map, in) 32559243Sobrien KEYCMD *map; 32659243Sobrien CStr *in; 32759243Sobrien{ 32859243Sobrien unsigned char c = (unsigned char) *(in->buf); 32959243Sobrien if ((map[c] == F_XKEY) && 33059243Sobrien ((map == CcKeyMap && CcAltMap[c] != F_XKEY) || 33159243Sobrien (map == CcAltMap && CcKeyMap[c] != F_XKEY))) 33259243Sobrien (void) DeleteXkey(in); 33359243Sobrien} 33459243Sobrien 33559243Sobrienint 33659243SobrienDeleteXkey(Xkey) 33759243Sobrien CStr *Xkey; 33859243Sobrien{ 33959243Sobrien if (Xkey->len == 0) { 34059243Sobrien xprintf(CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n")); 34159243Sobrien return (-1); 34259243Sobrien } 34359243Sobrien 34459243Sobrien if (Xmap == NULL) 34559243Sobrien return (0); 34659243Sobrien 34759243Sobrien (void) TryDeleteNode(&Xmap, Xkey); 34859243Sobrien return (0); 34959243Sobrien} 35059243Sobrien 35159243Sobrienstatic int 35259243SobrienTryDeleteNode(inptr, str) 35359243Sobrien XmapNode **inptr; 35459243Sobrien CStr *str; 35559243Sobrien{ 35659243Sobrien XmapNode *ptr; 35759243Sobrien XmapNode *prev_ptr = NULL; 35859243Sobrien 35959243Sobrien ptr = *inptr; 36059243Sobrien /* 36159243Sobrien * Find a node that matches *string or allocate a new one 36259243Sobrien */ 36359243Sobrien if (ptr->ch != *(str->buf)) { 36459243Sobrien XmapNode *xm; 36559243Sobrien 36659243Sobrien for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 36759243Sobrien if (xm->sibling->ch == *(str->buf)) 36859243Sobrien break; 36959243Sobrien if (xm->sibling == NULL) 37059243Sobrien return (0); 37159243Sobrien prev_ptr = xm; 37259243Sobrien ptr = xm->sibling; 37359243Sobrien } 37459243Sobrien 37559243Sobrien str->buf++; 37659243Sobrien str->len--; 37759243Sobrien 37859243Sobrien if (str->len == 0) { 37959243Sobrien /* we're there */ 38059243Sobrien if (prev_ptr == NULL) 38159243Sobrien *inptr = ptr->sibling; 38259243Sobrien else 38359243Sobrien prev_ptr->sibling = ptr->sibling; 38459243Sobrien ptr->sibling = NULL; 38559243Sobrien PutFreeNode(ptr); 38659243Sobrien return (1); 38759243Sobrien } 38859243Sobrien else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) { 38959243Sobrien if (ptr->next != NULL) 39059243Sobrien return (0); 39159243Sobrien if (prev_ptr == NULL) 39259243Sobrien *inptr = ptr->sibling; 39359243Sobrien else 39459243Sobrien prev_ptr->sibling = ptr->sibling; 39559243Sobrien ptr->sibling = NULL; 39659243Sobrien PutFreeNode(ptr); 39759243Sobrien return (1); 39859243Sobrien } 39959243Sobrien else { 40059243Sobrien return (0); 40159243Sobrien } 40259243Sobrien} 40359243Sobrien 40459243Sobrien/* PutFreeNode(): 40559243Sobrien * Puts a tree of nodes onto free list using free(3). 40659243Sobrien */ 40759243Sobrienstatic void 40859243SobrienPutFreeNode(ptr) 40959243Sobrien XmapNode *ptr; 41059243Sobrien{ 41159243Sobrien if (ptr == NULL) 41259243Sobrien return; 41359243Sobrien 41459243Sobrien if (ptr->next != NULL) { 41559243Sobrien PutFreeNode(ptr->next); 41659243Sobrien ptr->next = NULL; 41759243Sobrien } 41859243Sobrien 41959243Sobrien PutFreeNode(ptr->sibling); 42059243Sobrien 42159243Sobrien switch (ptr->type) { 42259243Sobrien case XK_CMD: 42359243Sobrien case XK_NOD: 42459243Sobrien break; 42559243Sobrien case XK_EXE: 42659243Sobrien case XK_STR: 42759243Sobrien if (ptr->val.str.buf != NULL) 42859243Sobrien xfree((ptr_t) ptr->val.str.buf); 42959243Sobrien break; 43059243Sobrien default: 43159243Sobrien abort(); 43259243Sobrien break; 43359243Sobrien } 43459243Sobrien xfree((ptr_t) ptr); 43559243Sobrien} 43659243Sobrien 43759243Sobrien 43859243Sobrien/* GetFreeNode(): 43959243Sobrien * Returns pointer to an XmapNode for ch. 44059243Sobrien */ 44159243Sobrienstatic XmapNode * 44259243SobrienGetFreeNode(ch) 44359243Sobrien CStr *ch; 44459243Sobrien{ 44559243Sobrien XmapNode *ptr; 44659243Sobrien 44759243Sobrien ptr = (XmapNode *) xmalloc((size_t) sizeof(XmapNode)); 44859243Sobrien ptr->ch = ch->buf[0]; 44959243Sobrien ptr->type = XK_NOD; 45059243Sobrien ptr->val.str.buf = NULL; 45159243Sobrien ptr->val.str.len = 0; 45259243Sobrien ptr->next = NULL; 45359243Sobrien ptr->sibling = NULL; 45459243Sobrien return (ptr); 45559243Sobrien} 45659243Sobrien 45759243Sobrien 45859243Sobrien/* PrintXKey(): 45959243Sobrien * Print the binding associated with Xkey key. 46059243Sobrien * Print entire Xmap if null 46159243Sobrien */ 46259243Sobrienvoid 46359243SobrienPrintXkey(key) 46459243Sobrien CStr *key; 46559243Sobrien{ 46659243Sobrien CStr cs; 46759243Sobrien 46859243Sobrien if (key) { 46959243Sobrien cs.buf = key->buf; 47059243Sobrien cs.len = key->len; 47159243Sobrien } 47259243Sobrien else { 47359243Sobrien cs.buf = STRNULL; 47459243Sobrien cs.len = 0; 47559243Sobrien } 47659243Sobrien /* do nothing if Xmap is empty and null key specified */ 47759243Sobrien if (Xmap == NULL && cs.len == 0) 47859243Sobrien return; 47959243Sobrien 48059243Sobrien printbuf[0] = '"'; 48159243Sobrien if (Lookup(&cs, Xmap, 1) <= -1) 48259243Sobrien /* key is not bound */ 48359243Sobrien xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf); 48459243Sobrien return; 48559243Sobrien} 48659243Sobrien 48759243Sobrien/* Lookup(): 48859243Sobrien * look for the string starting at node ptr. 48959243Sobrien * Print if last node 49059243Sobrien */ 49159243Sobrienstatic int 49259243SobrienLookup(str, ptr, cnt) 49359243Sobrien CStr *str; 49459243Sobrien XmapNode *ptr; 49559243Sobrien int cnt; 49659243Sobrien{ 49759243Sobrien int ncnt; 49859243Sobrien 49959243Sobrien if (ptr == NULL) 50059243Sobrien return (-1); /* cannot have null ptr */ 50159243Sobrien 50259243Sobrien if (str->len == 0) { 50359243Sobrien /* no more chars in string. Enumerate from here. */ 50459243Sobrien (void) Enumerate(ptr, cnt); 50559243Sobrien return (0); 50659243Sobrien } 50759243Sobrien else { 50859243Sobrien /* If match put this char into printbuf. Recurse */ 50959243Sobrien if (ptr->ch == *(str->buf)) { 51059243Sobrien /* match found */ 51159243Sobrien ncnt = unparsech(cnt, &ptr->ch); 51259243Sobrien if (ptr->next != NULL) { 51359243Sobrien /* not yet at leaf */ 51459243Sobrien CStr tstr; 51559243Sobrien tstr.buf = str->buf + 1; 51659243Sobrien tstr.len = str->len - 1; 51759243Sobrien return (Lookup(&tstr, ptr->next, ncnt + 1)); 51859243Sobrien } 51959243Sobrien else { 52059243Sobrien /* next node is null so key should be complete */ 52159243Sobrien if (str->len == 1) { 52259243Sobrien CStr pb; 52359243Sobrien printbuf[ncnt + 1] = '"'; 52459243Sobrien printbuf[ncnt + 2] = '\0'; 52559243Sobrien pb.buf = printbuf; 52659243Sobrien pb.len = ncnt + 2; 52759243Sobrien (void) printOne(&pb, &ptr->val, ptr->type); 52859243Sobrien return (0); 52959243Sobrien } 53059243Sobrien else 53159243Sobrien return (-1);/* mismatch -- string still has chars */ 53259243Sobrien } 53359243Sobrien } 53459243Sobrien else { 53559243Sobrien /* no match found try sibling */ 53659243Sobrien if (ptr->sibling) 53759243Sobrien return (Lookup(str, ptr->sibling, cnt)); 53859243Sobrien else 53959243Sobrien return (-1); 54059243Sobrien } 54159243Sobrien } 54259243Sobrien} 54359243Sobrien 54459243Sobrienstatic int 54559243SobrienEnumerate(ptr, cnt) 54659243Sobrien XmapNode *ptr; 54759243Sobrien int cnt; 54859243Sobrien{ 54959243Sobrien int ncnt; 55059243Sobrien 55159243Sobrien if (cnt >= MAXXKEY - 5) { /* buffer too small */ 55259243Sobrien printbuf[++cnt] = '"'; 55359243Sobrien printbuf[++cnt] = '\0'; 55459243Sobrien xprintf(CGETS(9, 5, 55559243Sobrien "Some extended keys too long for internal print buffer")); 55659243Sobrien xprintf(" \"%S...\"\n", printbuf); 55759243Sobrien return (0); 55859243Sobrien } 55959243Sobrien 56059243Sobrien if (ptr == NULL) { 56159243Sobrien#ifdef DEBUG_EDIT 56259243Sobrien xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!")); 56359243Sobrien#endif 56459243Sobrien return (-1); 56559243Sobrien } 56659243Sobrien 56759243Sobrien ncnt = unparsech(cnt, &ptr->ch); /* put this char at end of string */ 56859243Sobrien if (ptr->next == NULL) { 56959243Sobrien CStr pb; 57059243Sobrien /* print this Xkey and function */ 57159243Sobrien printbuf[++ncnt] = '"'; 57259243Sobrien printbuf[++ncnt] = '\0'; 57359243Sobrien pb.buf = printbuf; 57459243Sobrien pb.len = ncnt; 57559243Sobrien (void) printOne(&pb, &ptr->val, ptr->type); 57659243Sobrien } 57759243Sobrien else 57859243Sobrien (void) Enumerate(ptr->next, ncnt + 1); 57959243Sobrien 58059243Sobrien /* go to sibling if there is one */ 58159243Sobrien if (ptr->sibling) 58259243Sobrien (void) Enumerate(ptr->sibling, cnt); 58359243Sobrien return (0); 58459243Sobrien} 58559243Sobrien 58659243Sobrien 58759243Sobrien/* PrintOne(): 58859243Sobrien * Print the specified key and its associated 58959243Sobrien * function specified by val 59059243Sobrien */ 59159243Sobrienint 59259243SobrienprintOne(key, val, ntype) 59359243Sobrien CStr *key; 59459243Sobrien XmapVal *val; 59559243Sobrien int ntype; 59659243Sobrien{ 59759243Sobrien struct KeyFuncs *fp; 59859243Sobrien unsigned char unparsbuf[200]; 59959243Sobrien static char *fmt = "%s\n"; 60059243Sobrien 60159243Sobrien xprintf("%-15S-> ", key->buf); 60259243Sobrien if (val != NULL) 60359243Sobrien switch (ntype) { 60459243Sobrien case XK_STR: 60559243Sobrien case XK_EXE: 60659243Sobrien xprintf(fmt, unparsestring(&val->str, unparsbuf, 60759243Sobrien ntype == XK_STR ? STRQQ : STRBB)); 60859243Sobrien break; 60959243Sobrien case XK_CMD: 61059243Sobrien for (fp = FuncNames; fp->name; fp++) 61159243Sobrien if (val->cmd == fp->func) 61259243Sobrien xprintf(fmt, fp->name); 61359243Sobrien break; 61459243Sobrien default: 61559243Sobrien abort(); 61659243Sobrien break; 61759243Sobrien } 61859243Sobrien else 61959243Sobrien xprintf(fmt, key, CGETS(9, 7, "no input")); 62059243Sobrien return (0); 62159243Sobrien} 62259243Sobrien 62359243Sobrienstatic int 62459243Sobrienunparsech(cnt, ch) 62559243Sobrien int cnt; 62659243Sobrien Char *ch; 62759243Sobrien{ 62859243Sobrien if (ch == 0) { 62959243Sobrien printbuf[cnt++] = '^'; 63059243Sobrien printbuf[cnt] = '@'; 63159243Sobrien return cnt; 63259243Sobrien } 63359243Sobrien 63459243Sobrien if (Iscntrl(*ch)) { 63569408Sache#ifdef IS_ASCII 63659243Sobrien printbuf[cnt++] = '^'; 63759243Sobrien if (*ch == CTL_ESC('\177')) 63859243Sobrien printbuf[cnt] = '?'; 63959243Sobrien else 64059243Sobrien printbuf[cnt] = *ch | 0100; 64169408Sache#else 64259243Sobrien if (*ch == CTL_ESC('\177')) 64359243Sobrien { 64459243Sobrien printbuf[cnt++] = '^'; 64559243Sobrien printbuf[cnt] = '?'; 64659243Sobrien } 64759243Sobrien else if (Isupper(_toebcdic[_toascii[*ch]|0100]) 64859243Sobrien || strchr("@[\\]^_", _toebcdic[_toascii[*ch]|0100]) != NULL) 64959243Sobrien { 65059243Sobrien printbuf[cnt++] = '^'; 65159243Sobrien printbuf[cnt] = _toebcdic[_toascii[*ch]|0100]; 65259243Sobrien } 65359243Sobrien else 65459243Sobrien { 65559243Sobrien printbuf[cnt++] = '\\'; 65659243Sobrien printbuf[cnt++] = ((*ch >> 6) & 7) + '0'; 65759243Sobrien printbuf[cnt++] = ((*ch >> 3) & 7) + '0'; 65859243Sobrien printbuf[cnt] = (*ch & 7) + '0'; 65959243Sobrien } 66069408Sache#endif 66159243Sobrien } 66259243Sobrien else if (*ch == '^') { 66359243Sobrien printbuf[cnt++] = '\\'; 66459243Sobrien printbuf[cnt] = '^'; 66559243Sobrien } 66659243Sobrien else if (*ch == '\\') { 66759243Sobrien printbuf[cnt++] = '\\'; 66859243Sobrien printbuf[cnt] = '\\'; 66959243Sobrien } 67059243Sobrien else if (*ch == ' ' || (Isprint(*ch) && !Isspace(*ch))) { 67159243Sobrien printbuf[cnt] = *ch; 67259243Sobrien } 67359243Sobrien else { 67459243Sobrien printbuf[cnt++] = '\\'; 67559243Sobrien printbuf[cnt++] = ((*ch >> 6) & 7) + '0'; 67659243Sobrien printbuf[cnt++] = ((*ch >> 3) & 7) + '0'; 67759243Sobrien printbuf[cnt] = (*ch & 7) + '0'; 67859243Sobrien } 67959243Sobrien return cnt; 68059243Sobrien} 68159243Sobrien 68259243Sobrienint 68359243Sobrienparseescape(ptr) 68459243Sobrien const Char **ptr; 68559243Sobrien{ 68659243Sobrien const Char *p; 68759243Sobrien Char c; 68859243Sobrien 68959243Sobrien p = *ptr; 69059243Sobrien 69159243Sobrien if ((p[1] & CHAR) == 0) { 69259243Sobrien xprintf(CGETS(9, 8, "Something must follow: %c\n"), *p); 69359243Sobrien return -1; 69459243Sobrien } 69559243Sobrien if ((*p & CHAR) == '\\') { 69659243Sobrien p++; 69759243Sobrien switch (*p & CHAR) { 69859243Sobrien case 'a': 69959243Sobrien c = CTL_ESC('\007'); /* Bell */ 70059243Sobrien break; 70159243Sobrien case 'b': 70259243Sobrien c = CTL_ESC('\010'); /* Backspace */ 70359243Sobrien break; 70459243Sobrien case 'e': 70559243Sobrien c = CTL_ESC('\033'); /* Escape */ 70659243Sobrien break; 70759243Sobrien case 'f': 70859243Sobrien c = CTL_ESC('\014'); /* Form Feed */ 70959243Sobrien break; 71059243Sobrien case 'n': 71159243Sobrien c = CTL_ESC('\012'); /* New Line */ 71259243Sobrien break; 71359243Sobrien case 'r': 71459243Sobrien c = CTL_ESC('\015'); /* Carriage Return */ 71559243Sobrien break; 71659243Sobrien case 't': 71759243Sobrien c = CTL_ESC('\011'); /* Horizontal Tab */ 71859243Sobrien break; 71959243Sobrien case 'v': 72059243Sobrien c = CTL_ESC('\013'); /* Vertical Tab */ 72159243Sobrien break; 72283098Smp case '\\': 72383098Smp c = '\\'; 72483098Smp break; 72559243Sobrien case '0': 72659243Sobrien case '1': 72759243Sobrien case '2': 72859243Sobrien case '3': 72959243Sobrien case '4': 73059243Sobrien case '5': 73159243Sobrien case '6': 73259243Sobrien case '7': 73359243Sobrien { 73459243Sobrien register int cnt, val, ch; 73559243Sobrien 73659243Sobrien for (cnt = 0, val = 0; cnt < 3; cnt++) { 73759243Sobrien ch = *p++ & CHAR; 73859243Sobrien if (ch < '0' || ch > '7') { 73959243Sobrien p--; 74059243Sobrien break; 74159243Sobrien } 74259243Sobrien val = (val << 3) | (ch - '0'); 74359243Sobrien } 74459243Sobrien if ((val & 0xffffff00) != 0) { 74559243Sobrien xprintf(CGETS(9, 9, 74659243Sobrien "Octal constant does not fit in a char.\n")); 74759243Sobrien return 0; 74859243Sobrien } 74969408Sache#ifndef IS_ASCII 75059243Sobrien if (CTL_ESC(val) != val && adrof(STRwarnebcdic)) 75159243Sobrien xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 75259243Sobrien "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/); 75359243Sobrien#endif 75459243Sobrien c = (Char) val; 75559243Sobrien --p; 75659243Sobrien } 75759243Sobrien break; 75859243Sobrien default: 75959243Sobrien c = *p; 76059243Sobrien break; 76159243Sobrien } 76259243Sobrien } 76359243Sobrien else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) || 76459243Sobrien strchr("@^_?\\|[{]}", p[1] & CHAR))) { 76559243Sobrien p++; 76669408Sache#ifdef IS_ASCII 76759243Sobrien c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237); 76869408Sache#else 76959243Sobrien c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237]; 77059243Sobrien if (adrof(STRwarnebcdic)) 77159243Sobrien xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 77259243Sobrien "Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/); 77369408Sache#endif 77459243Sobrien } 77559243Sobrien else 77659243Sobrien c = *p; 77759243Sobrien *ptr = p; 77859243Sobrien return (c); 77959243Sobrien} 78059243Sobrien 78159243Sobrien 78259243Sobrienunsigned char * 78359243Sobrienunparsestring(str, buf, sep) 78459243Sobrien CStr *str; 78559243Sobrien unsigned char *buf; 78659243Sobrien Char *sep; 78759243Sobrien{ 78859243Sobrien unsigned char *b; 78959243Sobrien Char p; 79059243Sobrien int l; 79159243Sobrien 79259243Sobrien b = buf; 79359243Sobrien if (sep[0]) 79469408Sache#ifndef WINNT_NATIVE 79559243Sobrien *b++ = sep[0]; 79669408Sache#else /* WINNT_NATIVE */ 79759243Sobrien *b++ = CHAR & sep[0]; 79869408Sache#endif /* !WINNT_NATIVE */ 79959243Sobrien 80059243Sobrien for (l = 0; l < str->len; l++) { 80159243Sobrien p = str->buf[l]; 80259243Sobrien if (Iscntrl(p)) { 80369408Sache#ifdef IS_ASCII 80459243Sobrien *b++ = '^'; 80559243Sobrien if (p == CTL_ESC('\177')) 80659243Sobrien *b++ = '?'; 80759243Sobrien else 80859243Sobrien *b++ = (unsigned char) (p | 0100); 80969408Sache#else 81059243Sobrien if (_toascii[p] == '\177' || Isupper(_toebcdic[_toascii[p]|0100]) 81159243Sobrien || strchr("@[\\]^_", _toebcdic[_toascii[p]|0100]) != NULL) 81259243Sobrien { 81359243Sobrien *b++ = '^'; 81459243Sobrien *b++ = (_toascii[p] == '\177') ? '?' : _toebcdic[_toascii[p]|0100]; 81559243Sobrien } 81659243Sobrien else 81759243Sobrien { 81859243Sobrien *b++ = '\\'; 81959243Sobrien *b++ = ((p >> 6) & 7) + '0'; 82059243Sobrien *b++ = ((p >> 3) & 7) + '0'; 82159243Sobrien *b++ = (p & 7) + '0'; 82259243Sobrien } 82369408Sache#endif 82459243Sobrien } 82559243Sobrien else if (p == '^' || p == '\\') { 82659243Sobrien *b++ = '\\'; 82759243Sobrien *b++ = (unsigned char) p; 82859243Sobrien } 82959243Sobrien else if (p == ' ' || (Isprint(p) && !Isspace(p))) { 83059243Sobrien *b++ = (unsigned char) p; 83159243Sobrien } 83259243Sobrien else { 83359243Sobrien *b++ = '\\'; 83459243Sobrien *b++ = ((p >> 6) & 7) + '0'; 83559243Sobrien *b++ = ((p >> 3) & 7) + '0'; 83659243Sobrien *b++ = (p & 7) + '0'; 83759243Sobrien } 83859243Sobrien } 83959243Sobrien if (sep[0] && sep[1]) 84069408Sache#ifndef WINNT_NATIVE 84159243Sobrien *b++ = sep[1]; 84269408Sache#else /* WINNT_NATIVE */ 84359243Sobrien *b++ = CHAR & sep[1]; 84469408Sache#endif /* !WINNT_NATIVE */ 84559243Sobrien *b++ = 0; 84659243Sobrien return buf; /* should check for overflow */ 84759243Sobrien} 848