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