1195609Smp/* $Header: /p/tcsh/cvsroot/tcsh/ed.xmap.c,v 3.37 2009/06/25 21:15:37 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 91195609SmpRCSID("$tcsh: ed.xmap.c,v 3.37 2009/06/25 21:15:37 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 11659243Sobrien 11759243Sobrien/* Some declarations of procedures */ 118167465Smpstatic int TraverseMap (XmapNode *, CStr *, XmapVal *); 119167465Smpstatic int TryNode (XmapNode *, CStr *, XmapVal *, int); 120167465Smpstatic XmapNode *GetFreeNode (CStr *); 121167465Smpstatic void PutFreeNode (XmapNode *); 122167465Smpstatic int TryDeleteNode (XmapNode **, CStr *); 123167465Smpstatic int Lookup (struct Strbuf *, const CStr *, 124167465Smp const XmapNode *); 125167465Smpstatic void Enumerate (struct Strbuf *, const XmapNode *); 126167465Smpstatic void unparsech (struct Strbuf *, Char); 12759243Sobrien 12859243Sobrien 12959243SobrienXmapVal * 130167465SmpXmapCmd(int cmd) 13159243Sobrien{ 13259243Sobrien static XmapVal xm; 13359243Sobrien xm.cmd = (KEYCMD) cmd; 13459243Sobrien return &xm; 13559243Sobrien} 13659243Sobrien 13759243SobrienXmapVal * 138167465SmpXmapStr(CStr *str) 13959243Sobrien{ 14059243Sobrien static XmapVal xm; 14159243Sobrien xm.str.len = str->len; 14259243Sobrien xm.str.buf = str->buf; 14359243Sobrien return &xm; 14459243Sobrien} 14559243Sobrien 14659243Sobrien/* ResetXmap(): 14759243Sobrien * Takes all nodes on Xmap and puts them on free list. Then 14859243Sobrien * initializes Xmap with arrow keys 14959243Sobrien */ 15059243Sobrienvoid 151167465SmpResetXmap(void) 15259243Sobrien{ 15359243Sobrien PutFreeNode(Xmap); 15459243Sobrien Xmap = NULL; 15559243Sobrien 15659243Sobrien DefaultArrowKeys(); 15759243Sobrien return; 15859243Sobrien} 15959243Sobrien 16059243Sobrien 16159243Sobrien/* GetXkey(): 16259243Sobrien * Calls the recursive function with entry point Xmap 16359243Sobrien */ 16459243Sobrienint 165167465SmpGetXkey(CStr *ch, XmapVal *val) 16659243Sobrien{ 16759243Sobrien return (TraverseMap(Xmap, ch, val)); 16859243Sobrien} 16959243Sobrien 17059243Sobrien/* TraverseMap(): 17159243Sobrien * recursively traverses node in tree until match or mismatch is 17259243Sobrien * found. May read in more characters. 17359243Sobrien */ 17459243Sobrienstatic int 175167465SmpTraverseMap(XmapNode *ptr, CStr *ch, XmapVal *val) 17659243Sobrien{ 17759243Sobrien Char tch; 17859243Sobrien 17959243Sobrien if (ptr->ch == *(ch->buf)) { 18059243Sobrien /* match found */ 18159243Sobrien if (ptr->next) { 18259243Sobrien /* Xkey not complete so get next char */ 18359243Sobrien if (GetNextChar(&tch) != 1) { /* if EOF or error */ 18459243Sobrien val->cmd = F_SEND_EOF; 18559243Sobrien return XK_CMD;/* PWP: Pretend we just read an end-of-file */ 18659243Sobrien } 18759243Sobrien *(ch->buf) = tch; 18859243Sobrien return (TraverseMap(ptr->next, ch, val)); 18959243Sobrien } 19059243Sobrien else { 19159243Sobrien *val = ptr->val; 19259243Sobrien if (ptr->type != XK_CMD) 19359243Sobrien *(ch->buf) = '\0'; 19459243Sobrien return ptr->type; 19559243Sobrien } 19659243Sobrien } 19759243Sobrien else { 19859243Sobrien /* no match found here */ 19959243Sobrien if (ptr->sibling) { 20059243Sobrien /* try next sibling */ 20159243Sobrien return (TraverseMap(ptr->sibling, ch, val)); 20259243Sobrien } 20359243Sobrien else { 20459243Sobrien /* no next sibling -- mismatch */ 20559243Sobrien val->str.buf = NULL; 20659243Sobrien val->str.len = 0; 20759243Sobrien return XK_STR; 20859243Sobrien } 20959243Sobrien } 21059243Sobrien} 21159243Sobrien 21259243Sobrienvoid 213167465SmpAddXkey(const CStr *Xkey, XmapVal *val, int ntype) 21459243Sobrien{ 21559243Sobrien CStr cs; 21659243Sobrien cs.buf = Xkey->buf; 21759243Sobrien cs.len = Xkey->len; 21859243Sobrien if (Xkey->len == 0) { 219195609Smp xprintf("%s", CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n")); 22059243Sobrien return; 22159243Sobrien } 22259243Sobrien 22359243Sobrien if (ntype == XK_CMD && val->cmd == F_XKEY) { 224195609Smp xprintf("%s", 225195609Smp CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n")); 22659243Sobrien return; 22759243Sobrien } 22859243Sobrien 22959243Sobrien if (Xmap == NULL) 23059243Sobrien /* tree is initially empty. Set up new node to match Xkey[0] */ 23159243Sobrien Xmap = GetFreeNode(&cs); /* it is properly initialized */ 23259243Sobrien 23359243Sobrien /* Now recurse through Xmap */ 23459243Sobrien (void) TryNode(Xmap, &cs, val, ntype); 23559243Sobrien return; 23659243Sobrien} 23759243Sobrien 23859243Sobrienstatic int 239167465SmpTryNode(XmapNode *ptr, CStr *str, XmapVal *val, int ntype) 24059243Sobrien{ 24159243Sobrien /* 24259243Sobrien * Find a node that matches *string or allocate a new one 24359243Sobrien */ 24459243Sobrien if (ptr->ch != *(str->buf)) { 24559243Sobrien XmapNode *xm; 24659243Sobrien 24759243Sobrien for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 24859243Sobrien if (xm->sibling->ch == *(str->buf)) 24959243Sobrien break; 25059243Sobrien if (xm->sibling == NULL) 25159243Sobrien xm->sibling = GetFreeNode(str); /* setup new node */ 25259243Sobrien ptr = xm->sibling; 25359243Sobrien } 25459243Sobrien 25559243Sobrien str->buf++; 25659243Sobrien str->len--; 25759243Sobrien if (str->len == 0) { 258167465Smp size_t len; 259167465Smp 26059243Sobrien /* we're there */ 26159243Sobrien if (ptr->next != NULL) { 26259243Sobrien PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */ 26359243Sobrien ptr->next = NULL; 26459243Sobrien } 26559243Sobrien 26659243Sobrien switch (ptr->type) { 26759243Sobrien case XK_STR: 26859243Sobrien case XK_EXE: 269167465Smp xfree(ptr->val.str.buf); 27059243Sobrien ptr->val.str.len = 0; 27159243Sobrien break; 27259243Sobrien case XK_NOD: 27359243Sobrien case XK_CMD: 27459243Sobrien break; 27559243Sobrien default: 27659243Sobrien abort(); 27759243Sobrien break; 27859243Sobrien } 27959243Sobrien 28059243Sobrien switch (ptr->type = ntype) { 28159243Sobrien case XK_CMD: 28259243Sobrien ptr->val = *val; 28359243Sobrien break; 28459243Sobrien case XK_STR: 28559243Sobrien case XK_EXE: 28659243Sobrien ptr->val.str.len = val->str.len; 287167465Smp len = (val->str.len + 1) * sizeof(*ptr->val.str.buf); 288167465Smp ptr->val.str.buf = xmalloc(len); 289167465Smp (void) memcpy(ptr->val.str.buf, val->str.buf, len); 29059243Sobrien break; 29159243Sobrien default: 29259243Sobrien abort(); 29359243Sobrien break; 29459243Sobrien } 29559243Sobrien } 29659243Sobrien else { 29759243Sobrien /* still more chars to go */ 29859243Sobrien if (ptr->next == NULL) 29959243Sobrien ptr->next = GetFreeNode(str); /* setup new node */ 30059243Sobrien (void) TryNode(ptr->next, str, val, ntype); 30159243Sobrien } 30259243Sobrien return (0); 30359243Sobrien} 30459243Sobrien 30559243Sobrienvoid 306167465SmpClearXkey(KEYCMD *map, const CStr *in) 30759243Sobrien{ 30859243Sobrien unsigned char c = (unsigned char) *(in->buf); 30959243Sobrien if ((map[c] == F_XKEY) && 31059243Sobrien ((map == CcKeyMap && CcAltMap[c] != F_XKEY) || 31159243Sobrien (map == CcAltMap && CcKeyMap[c] != F_XKEY))) 31259243Sobrien (void) DeleteXkey(in); 31359243Sobrien} 31459243Sobrien 31559243Sobrienint 316167465SmpDeleteXkey(const CStr *Xkey) 31759243Sobrien{ 318167465Smp CStr s; 319167465Smp 320167465Smp s = *Xkey; 321167465Smp if (s.len == 0) { 322195609Smp xprintf("%s", 323195609Smp CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n")); 32459243Sobrien return (-1); 32559243Sobrien } 32659243Sobrien 32759243Sobrien if (Xmap == NULL) 32859243Sobrien return (0); 32959243Sobrien 330167465Smp (void) TryDeleteNode(&Xmap, &s); 33159243Sobrien return (0); 33259243Sobrien} 33359243Sobrien 334167465Smp/* Destroys str */ 33559243Sobrienstatic int 336167465SmpTryDeleteNode(XmapNode **inptr, CStr *str) 33759243Sobrien{ 33859243Sobrien XmapNode *ptr; 33959243Sobrien 34059243Sobrien ptr = *inptr; 34159243Sobrien /* 34259243Sobrien * Find a node that matches *string or allocate a new one 34359243Sobrien */ 34459243Sobrien if (ptr->ch != *(str->buf)) { 34559243Sobrien XmapNode *xm; 34659243Sobrien 34759243Sobrien for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 34859243Sobrien if (xm->sibling->ch == *(str->buf)) 34959243Sobrien break; 35059243Sobrien if (xm->sibling == NULL) 35159243Sobrien return (0); 352167465Smp inptr = &xm->sibling; 35359243Sobrien ptr = xm->sibling; 35459243Sobrien } 35559243Sobrien 35659243Sobrien str->buf++; 35759243Sobrien str->len--; 35859243Sobrien 35959243Sobrien if (str->len == 0) { 36059243Sobrien /* we're there */ 361167465Smp *inptr = ptr->sibling; 36259243Sobrien ptr->sibling = NULL; 36359243Sobrien PutFreeNode(ptr); 36459243Sobrien return (1); 36559243Sobrien } 36659243Sobrien else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) { 36759243Sobrien if (ptr->next != NULL) 36859243Sobrien return (0); 369167465Smp *inptr = ptr->sibling; 37059243Sobrien ptr->sibling = NULL; 37159243Sobrien PutFreeNode(ptr); 37259243Sobrien return (1); 37359243Sobrien } 37459243Sobrien else { 37559243Sobrien return (0); 37659243Sobrien } 37759243Sobrien} 37859243Sobrien 37959243Sobrien/* PutFreeNode(): 38059243Sobrien * Puts a tree of nodes onto free list using free(3). 38159243Sobrien */ 38259243Sobrienstatic void 383167465SmpPutFreeNode(XmapNode *ptr) 38459243Sobrien{ 38559243Sobrien if (ptr == NULL) 38659243Sobrien return; 38759243Sobrien 38859243Sobrien if (ptr->next != NULL) { 38959243Sobrien PutFreeNode(ptr->next); 39059243Sobrien ptr->next = NULL; 39159243Sobrien } 39259243Sobrien 39359243Sobrien PutFreeNode(ptr->sibling); 39459243Sobrien 39559243Sobrien switch (ptr->type) { 39659243Sobrien case XK_CMD: 39759243Sobrien case XK_NOD: 39859243Sobrien break; 39959243Sobrien case XK_EXE: 40059243Sobrien case XK_STR: 401167465Smp xfree(ptr->val.str.buf); 40259243Sobrien break; 40359243Sobrien default: 40459243Sobrien abort(); 40559243Sobrien break; 40659243Sobrien } 407167465Smp xfree(ptr); 40859243Sobrien} 40959243Sobrien 41059243Sobrien 41159243Sobrien/* GetFreeNode(): 41259243Sobrien * Returns pointer to an XmapNode for ch. 41359243Sobrien */ 41459243Sobrienstatic XmapNode * 415167465SmpGetFreeNode(CStr *ch) 41659243Sobrien{ 41759243Sobrien XmapNode *ptr; 41859243Sobrien 419167465Smp ptr = xmalloc(sizeof(XmapNode)); 42059243Sobrien ptr->ch = ch->buf[0]; 42159243Sobrien ptr->type = XK_NOD; 42259243Sobrien ptr->val.str.buf = NULL; 42359243Sobrien ptr->val.str.len = 0; 42459243Sobrien ptr->next = NULL; 42559243Sobrien ptr->sibling = NULL; 42659243Sobrien return (ptr); 42759243Sobrien} 42859243Sobrien 42959243Sobrien 43059243Sobrien/* PrintXKey(): 43159243Sobrien * Print the binding associated with Xkey key. 43259243Sobrien * Print entire Xmap if null 43359243Sobrien */ 43459243Sobrienvoid 435167465SmpPrintXkey(const CStr *key) 43659243Sobrien{ 437167465Smp struct Strbuf buf = Strbuf_INIT; 43859243Sobrien CStr cs; 43959243Sobrien 44059243Sobrien if (key) { 44159243Sobrien cs.buf = key->buf; 44259243Sobrien cs.len = key->len; 44359243Sobrien } 44459243Sobrien else { 44559243Sobrien cs.buf = STRNULL; 44659243Sobrien cs.len = 0; 44759243Sobrien } 44859243Sobrien /* do nothing if Xmap is empty and null key specified */ 44959243Sobrien if (Xmap == NULL && cs.len == 0) 45059243Sobrien return; 45159243Sobrien 452167465Smp Strbuf_append1(&buf, '"'); 453167465Smp cleanup_push(&buf, Strbuf_cleanup); 454167465Smp if (Lookup(&buf, &cs, Xmap) <= -1) 45559243Sobrien /* key is not bound */ 45659243Sobrien xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf); 457167465Smp cleanup_until(&buf); 45859243Sobrien} 45959243Sobrien 46059243Sobrien/* Lookup(): 46159243Sobrien * look for the string starting at node ptr. 46259243Sobrien * Print if last node 46359243Sobrien */ 46459243Sobrienstatic int 465167465SmpLookup(struct Strbuf *buf, const CStr *str, const XmapNode *ptr) 46659243Sobrien{ 46759243Sobrien if (ptr == NULL) 46859243Sobrien return (-1); /* cannot have null ptr */ 46959243Sobrien 47059243Sobrien if (str->len == 0) { 47159243Sobrien /* no more chars in string. Enumerate from here. */ 472167465Smp Enumerate(buf, ptr); 47359243Sobrien return (0); 47459243Sobrien } 47559243Sobrien else { 476167465Smp /* If match put this char into buf. Recurse */ 47759243Sobrien if (ptr->ch == *(str->buf)) { 47859243Sobrien /* match found */ 479167465Smp unparsech(buf, ptr->ch); 48059243Sobrien if (ptr->next != NULL) { 48159243Sobrien /* not yet at leaf */ 48259243Sobrien CStr tstr; 48359243Sobrien tstr.buf = str->buf + 1; 48459243Sobrien tstr.len = str->len - 1; 485167465Smp return (Lookup(buf, &tstr, ptr->next)); 48659243Sobrien } 48759243Sobrien else { 48859243Sobrien /* next node is null so key should be complete */ 48959243Sobrien if (str->len == 1) { 490167465Smp Strbuf_append1(buf, '"'); 491167465Smp Strbuf_terminate(buf); 492167465Smp printOne(buf->s, &ptr->val, ptr->type); 49359243Sobrien return (0); 49459243Sobrien } 49559243Sobrien else 49659243Sobrien return (-1);/* mismatch -- string still has chars */ 49759243Sobrien } 49859243Sobrien } 49959243Sobrien else { 50059243Sobrien /* no match found try sibling */ 50159243Sobrien if (ptr->sibling) 502167465Smp return (Lookup(buf, str, ptr->sibling)); 50359243Sobrien else 50459243Sobrien return (-1); 50559243Sobrien } 50659243Sobrien } 50759243Sobrien} 50859243Sobrien 509167465Smpstatic void 510167465SmpEnumerate(struct Strbuf *buf, const XmapNode *ptr) 51159243Sobrien{ 512167465Smp size_t old_len; 51359243Sobrien 51459243Sobrien if (ptr == NULL) { 51559243Sobrien#ifdef DEBUG_EDIT 51659243Sobrien xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!")); 51759243Sobrien#endif 518167465Smp return; 51959243Sobrien } 52059243Sobrien 521167465Smp old_len = buf->len; 522167465Smp unparsech(buf, ptr->ch); /* put this char at end of string */ 52359243Sobrien if (ptr->next == NULL) { 52459243Sobrien /* print this Xkey and function */ 525167465Smp Strbuf_append1(buf, '"'); 526167465Smp Strbuf_terminate(buf); 527167465Smp printOne(buf->s, &ptr->val, ptr->type); 52859243Sobrien } 52959243Sobrien else 530167465Smp Enumerate(buf, ptr->next); 53159243Sobrien 53259243Sobrien /* go to sibling if there is one */ 533167465Smp if (ptr->sibling) { 534167465Smp buf->len = old_len; 535167465Smp Enumerate(buf, ptr->sibling); 536167465Smp } 53759243Sobrien} 53859243Sobrien 53959243Sobrien 54059243Sobrien/* PrintOne(): 54159243Sobrien * Print the specified key and its associated 54259243Sobrien * function specified by val 54359243Sobrien */ 544167465Smpvoid 545167465SmpprintOne(const Char *key, const XmapVal *val, int ntype) 54659243Sobrien{ 54759243Sobrien struct KeyFuncs *fp; 548145479Smp static const char *fmt = "%s\n"; 54959243Sobrien 550167465Smp xprintf("%-15S-> ", key); 55159243Sobrien if (val != NULL) 55259243Sobrien switch (ntype) { 55359243Sobrien case XK_STR: 554167465Smp case XK_EXE: { 555167465Smp unsigned char *p; 556167465Smp 557167465Smp p = unparsestring(&val->str, ntype == XK_STR ? STRQQ : STRBB); 558167465Smp cleanup_push(p, xfree); 559167465Smp xprintf(fmt, p); 560167465Smp cleanup_until(p); 56159243Sobrien break; 562167465Smp } 56359243Sobrien case XK_CMD: 56459243Sobrien for (fp = FuncNames; fp->name; fp++) 56559243Sobrien if (val->cmd == fp->func) 56659243Sobrien xprintf(fmt, fp->name); 56759243Sobrien break; 56859243Sobrien default: 56959243Sobrien abort(); 57059243Sobrien break; 57159243Sobrien } 57259243Sobrien else 573167465Smp xprintf(fmt, CGETS(9, 7, "no input")); 57459243Sobrien} 57559243Sobrien 576167465Smpstatic void 577167465Smpunparsech(struct Strbuf *buf, Char ch) 57859243Sobrien{ 57959243Sobrien if (ch == 0) { 580167465Smp Strbuf_append1(buf, '^'); 581167465Smp Strbuf_append1(buf, '@'); 58259243Sobrien } 583167465Smp else if (Iscntrl(ch)) { 584167465Smp Strbuf_append1(buf, '^'); 585167465Smp if (ch == CTL_ESC('\177')) 586167465Smp Strbuf_append1(buf, '?'); 587167465Smp else 58869408Sache#ifdef IS_ASCII 589167465Smp Strbuf_append1(buf, ch | 0100); 59069408Sache#else 591167465Smp Strbuf_append1(buf, _toebcdic[_toascii[ch]|0100]); 59269408Sache#endif 59359243Sobrien } 594167465Smp else if (ch == '^') { 595167465Smp Strbuf_append1(buf, '\\'); 596167465Smp Strbuf_append1(buf, '^'); 597167465Smp } else if (ch == '\\') { 598167465Smp Strbuf_append1(buf, '\\'); 599167465Smp Strbuf_append1(buf, '\\'); 600167465Smp } else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) { 601167465Smp Strbuf_append1(buf, ch); 60259243Sobrien } 60359243Sobrien else { 604167465Smp Strbuf_append1(buf, '\\'); 605167465Smp Strbuf_append1(buf, ((ch >> 6) & 7) + '0'); 606167465Smp Strbuf_append1(buf, ((ch >> 3) & 7) + '0'); 607167465Smp Strbuf_append1(buf, (ch & 7) + '0'); 60859243Sobrien } 60959243Sobrien} 61059243Sobrien 611145479SmpeChar 612167465Smpparseescape(const Char **ptr) 61359243Sobrien{ 61459243Sobrien const Char *p; 61559243Sobrien Char c; 61659243Sobrien 61759243Sobrien p = *ptr; 61859243Sobrien 61959243Sobrien if ((p[1] & CHAR) == 0) { 620167465Smp xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p); 621145479Smp return CHAR_ERR; 62259243Sobrien } 62359243Sobrien if ((*p & CHAR) == '\\') { 62459243Sobrien p++; 62559243Sobrien switch (*p & CHAR) { 62659243Sobrien case 'a': 62759243Sobrien c = CTL_ESC('\007'); /* Bell */ 62859243Sobrien break; 62959243Sobrien case 'b': 63059243Sobrien c = CTL_ESC('\010'); /* Backspace */ 63159243Sobrien break; 63259243Sobrien case 'e': 63359243Sobrien c = CTL_ESC('\033'); /* Escape */ 63459243Sobrien break; 63559243Sobrien case 'f': 63659243Sobrien c = CTL_ESC('\014'); /* Form Feed */ 63759243Sobrien break; 63859243Sobrien case 'n': 63959243Sobrien c = CTL_ESC('\012'); /* New Line */ 64059243Sobrien break; 64159243Sobrien case 'r': 64259243Sobrien c = CTL_ESC('\015'); /* Carriage Return */ 64359243Sobrien break; 64459243Sobrien case 't': 64559243Sobrien c = CTL_ESC('\011'); /* Horizontal Tab */ 64659243Sobrien break; 64759243Sobrien case 'v': 64859243Sobrien c = CTL_ESC('\013'); /* Vertical Tab */ 64959243Sobrien break; 65083098Smp case '\\': 65183098Smp c = '\\'; 65283098Smp break; 65359243Sobrien case '0': 65459243Sobrien case '1': 65559243Sobrien case '2': 65659243Sobrien case '3': 65759243Sobrien case '4': 65859243Sobrien case '5': 65959243Sobrien case '6': 66059243Sobrien case '7': 66159243Sobrien { 662145479Smp int cnt, val; 663145479Smp Char ch; 66459243Sobrien 66559243Sobrien for (cnt = 0, val = 0; cnt < 3; cnt++) { 66659243Sobrien ch = *p++ & CHAR; 66759243Sobrien if (ch < '0' || ch > '7') { 66859243Sobrien p--; 66959243Sobrien break; 67059243Sobrien } 67159243Sobrien val = (val << 3) | (ch - '0'); 67259243Sobrien } 673167465Smp if ((val & ~0xff) != 0) { 674195609Smp xprintf("%s", CGETS(9, 9, 67559243Sobrien "Octal constant does not fit in a char.\n")); 67659243Sobrien return 0; 67759243Sobrien } 67869408Sache#ifndef IS_ASCII 67959243Sobrien if (CTL_ESC(val) != val && adrof(STRwarnebcdic)) 68059243Sobrien xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 68159243Sobrien "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/); 68259243Sobrien#endif 68359243Sobrien c = (Char) val; 68459243Sobrien --p; 68559243Sobrien } 68659243Sobrien break; 68759243Sobrien default: 68859243Sobrien c = *p; 68959243Sobrien break; 69059243Sobrien } 69159243Sobrien } 69259243Sobrien else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) || 69359243Sobrien strchr("@^_?\\|[{]}", p[1] & CHAR))) { 69459243Sobrien p++; 69569408Sache#ifdef IS_ASCII 69659243Sobrien c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237); 69769408Sache#else 69859243Sobrien c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237]; 69959243Sobrien if (adrof(STRwarnebcdic)) 70059243Sobrien xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 70159243Sobrien "Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/); 70269408Sache#endif 70359243Sobrien } 70459243Sobrien else 70559243Sobrien c = *p; 70659243Sobrien *ptr = p; 70759243Sobrien return (c); 70859243Sobrien} 70959243Sobrien 71059243Sobrien 71159243Sobrienunsigned char * 712167465Smpunparsestring(const CStr *str, const Char *sep) 71359243Sobrien{ 714167465Smp unsigned char *buf, *b; 71559243Sobrien Char p; 71659243Sobrien int l; 71759243Sobrien 718167465Smp /* Worst-case is "\uuu" or result of wctomb() for each char from str */ 719167465Smp buf = xmalloc((str->len + 1) * max(4, MB_LEN_MAX)); 72059243Sobrien b = buf; 72159243Sobrien if (sep[0]) 72269408Sache#ifndef WINNT_NATIVE 72359243Sobrien *b++ = sep[0]; 72469408Sache#else /* WINNT_NATIVE */ 72559243Sobrien *b++ = CHAR & sep[0]; 72669408Sache#endif /* !WINNT_NATIVE */ 72759243Sobrien 72859243Sobrien for (l = 0; l < str->len; l++) { 72959243Sobrien p = str->buf[l]; 73059243Sobrien if (Iscntrl(p)) { 73159243Sobrien *b++ = '^'; 73259243Sobrien if (p == CTL_ESC('\177')) 73359243Sobrien *b++ = '?'; 73459243Sobrien else 735167465Smp#ifdef IS_ASCII 73659243Sobrien *b++ = (unsigned char) (p | 0100); 73769408Sache#else 738167465Smp *b++ = _toebcdic[_toascii[p]|0100]; 73969408Sache#endif 74059243Sobrien } 74159243Sobrien else if (p == '^' || p == '\\') { 74259243Sobrien *b++ = '\\'; 74359243Sobrien *b++ = (unsigned char) p; 74459243Sobrien } 745145479Smp else if (p == ' ' || (Isprint(p) && !Isspace(p))) 746145479Smp b += one_wctomb((char *)b, p & CHAR); 74759243Sobrien else { 74859243Sobrien *b++ = '\\'; 74959243Sobrien *b++ = ((p >> 6) & 7) + '0'; 75059243Sobrien *b++ = ((p >> 3) & 7) + '0'; 75159243Sobrien *b++ = (p & 7) + '0'; 75259243Sobrien } 75359243Sobrien } 75459243Sobrien if (sep[0] && sep[1]) 75569408Sache#ifndef WINNT_NATIVE 75659243Sobrien *b++ = sep[1]; 75769408Sache#else /* WINNT_NATIVE */ 75859243Sobrien *b++ = CHAR & sep[1]; 75969408Sache#endif /* !WINNT_NATIVE */ 76059243Sobrien *b++ = 0; 76159243Sobrien return buf; /* should check for overflow */ 76259243Sobrien} 763