159243Sobrien/* 259243Sobrien * ed.xmap.c: This module contains the procedures for maintaining 359243Sobrien * the extended-key map. 459243Sobrien * 559243Sobrien * An extended-key (Xkey) is a sequence of keystrokes 659243Sobrien * introduced with an sequence introducer and consisting 759243Sobrien * of an arbitrary number of characters. This module maintains 859243Sobrien * a map (the Xmap) to convert these extended-key sequences 959243Sobrien * into input strings (XK_STR), editor functions (XK_CMD), or 1059243Sobrien * unix commands (XK_EXE). It contains the 1159243Sobrien * following externally visible functions. 1259243Sobrien * 1359243Sobrien * int GetXkey(ch,val); 1459243Sobrien * CStr *ch; 1559243Sobrien * XmapVal *val; 1659243Sobrien * 1759243Sobrien * Looks up *ch in map and then reads characters until a 1859243Sobrien * complete match is found or a mismatch occurs. Returns the 1959243Sobrien * type of the match found (XK_STR, XK_CMD, or XK_EXE). 2059243Sobrien * Returns NULL in val.str and XK_STR for no match. 2159243Sobrien * The last character read is returned in *ch. 2259243Sobrien * 2359243Sobrien * void AddXkey(Xkey, val, ntype); 2459243Sobrien * CStr *Xkey; 2559243Sobrien * XmapVal *val; 2659243Sobrien * int ntype; 2759243Sobrien * 2859243Sobrien * Adds Xkey to the Xmap and associates the value in val with it. 2959243Sobrien * If Xkey is already is in Xmap, the new code is applied to the 3059243Sobrien * existing Xkey. Ntype specifies if code is a command, an 3159243Sobrien * out string or a unix command. 3259243Sobrien * 3359243Sobrien * int DeleteXkey(Xkey); 3459243Sobrien * CStr *Xkey; 3559243Sobrien * 3659243Sobrien * Delete the Xkey and all longer Xkeys staring with Xkey, if 3759243Sobrien * they exists. 3859243Sobrien * 3959243Sobrien * Warning: 4059243Sobrien * If Xkey is a substring of some other Xkeys, then the longer 4159243Sobrien * Xkeys are lost!! That is, if the Xkeys "abcd" and "abcef" 4259243Sobrien * are in Xmap, adding the key "abc" will cause the first two 4359243Sobrien * definitions to be lost. 4459243Sobrien * 4559243Sobrien * void ResetXmap(); 4659243Sobrien * 4759243Sobrien * Removes all entries from Xmap and resets the defaults. 4859243Sobrien * 4959243Sobrien * void PrintXkey(Xkey); 5059243Sobrien * CStr *Xkey; 5159243Sobrien * 5259243Sobrien * Prints all extended keys prefixed by Xkey and their associated 5359243Sobrien * commands. 5459243Sobrien * 5559243Sobrien * Restrictions: 5659243Sobrien * ------------- 5759243Sobrien * 1) It is not possible to have one Xkey that is a 5859243Sobrien * substring of another. 5959243Sobrien */ 6059243Sobrien/*- 6159243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 6259243Sobrien * All rights reserved. 6359243Sobrien * 6459243Sobrien * Redistribution and use in source and binary forms, with or without 6559243Sobrien * modification, are permitted provided that the following conditions 6659243Sobrien * are met: 6759243Sobrien * 1. Redistributions of source code must retain the above copyright 6859243Sobrien * notice, this list of conditions and the following disclaimer. 6959243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 7059243Sobrien * notice, this list of conditions and the following disclaimer in the 7159243Sobrien * documentation and/or other materials provided with the distribution. 72100616Smp * 3. Neither the name of the University nor the names of its contributors 7359243Sobrien * may be used to endorse or promote products derived from this software 7459243Sobrien * without specific prior written permission. 7559243Sobrien * 7659243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 7759243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7859243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 7959243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 8059243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 8159243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 8259243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 8359243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 8459243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 8559243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 8659243Sobrien * SUCH DAMAGE. 8759243Sobrien */ 8859243Sobrien#include "sh.h" 8959243Sobrien#include "ed.h" 9059243Sobrien#include "ed.defns.h" 9159243Sobrien 9259243Sobrien#ifndef NULL 9359243Sobrien#define NULL 0 9459243Sobrien#endif 9559243Sobrien 9659243Sobrien/* Internal Data types and declarations */ 9759243Sobrien 9859243Sobrien/* The Nodes of the Xmap. The Xmap is a linked list of these node 9959243Sobrien * elements 10059243Sobrien */ 10159243Sobrientypedef struct Xmapnode { 10259243Sobrien Char ch; /* single character of Xkey */ 10359243Sobrien int type; 10459243Sobrien XmapVal val; /* command code or pointer to string, if this 10559243Sobrien * is a leaf */ 10659243Sobrien struct Xmapnode *next; /* ptr to next char of this Xkey */ 10759243Sobrien struct Xmapnode *sibling; /* ptr to another Xkey with same prefix */ 10859243Sobrien} XmapNode; 10959243Sobrien 11059243Sobrienstatic XmapNode *Xmap = NULL; /* the current Xmap */ 11159243Sobrien 11259243Sobrien 11359243Sobrien/* Some declarations of procedures */ 114167465Smpstatic int TraverseMap (XmapNode *, CStr *, XmapVal *); 115167465Smpstatic int TryNode (XmapNode *, CStr *, XmapVal *, int); 116167465Smpstatic XmapNode *GetFreeNode (CStr *); 117167465Smpstatic void PutFreeNode (XmapNode *); 118167465Smpstatic int TryDeleteNode (XmapNode **, CStr *); 119167465Smpstatic int Lookup (struct Strbuf *, const CStr *, 120167465Smp const XmapNode *); 121167465Smpstatic void Enumerate (struct Strbuf *, const XmapNode *); 122167465Smpstatic void unparsech (struct Strbuf *, Char); 12359243Sobrien 12459243Sobrien 12559243SobrienXmapVal * 126167465SmpXmapCmd(int cmd) 12759243Sobrien{ 12859243Sobrien static XmapVal xm; 12959243Sobrien xm.cmd = (KEYCMD) cmd; 13059243Sobrien return &xm; 13159243Sobrien} 13259243Sobrien 13359243SobrienXmapVal * 134167465SmpXmapStr(CStr *str) 13559243Sobrien{ 13659243Sobrien static XmapVal xm; 13759243Sobrien xm.str.len = str->len; 13859243Sobrien xm.str.buf = str->buf; 13959243Sobrien return &xm; 14059243Sobrien} 14159243Sobrien 14259243Sobrien/* ResetXmap(): 14359243Sobrien * Takes all nodes on Xmap and puts them on free list. Then 14459243Sobrien * initializes Xmap with arrow keys 14559243Sobrien */ 14659243Sobrienvoid 147167465SmpResetXmap(void) 14859243Sobrien{ 14959243Sobrien PutFreeNode(Xmap); 15059243Sobrien Xmap = NULL; 15159243Sobrien 15259243Sobrien DefaultArrowKeys(); 15359243Sobrien return; 15459243Sobrien} 15559243Sobrien 15659243Sobrien 15759243Sobrien/* GetXkey(): 15859243Sobrien * Calls the recursive function with entry point Xmap 15959243Sobrien */ 16059243Sobrienint 161167465SmpGetXkey(CStr *ch, XmapVal *val) 16259243Sobrien{ 16359243Sobrien return (TraverseMap(Xmap, ch, val)); 16459243Sobrien} 16559243Sobrien 16659243Sobrien/* TraverseMap(): 16759243Sobrien * recursively traverses node in tree until match or mismatch is 16859243Sobrien * found. May read in more characters. 16959243Sobrien */ 17059243Sobrienstatic int 171167465SmpTraverseMap(XmapNode *ptr, CStr *ch, XmapVal *val) 17259243Sobrien{ 17359243Sobrien Char tch; 17459243Sobrien 17559243Sobrien if (ptr->ch == *(ch->buf)) { 17659243Sobrien /* match found */ 17759243Sobrien if (ptr->next) { 17859243Sobrien /* Xkey not complete so get next char */ 17959243Sobrien if (GetNextChar(&tch) != 1) { /* if EOF or error */ 18059243Sobrien val->cmd = F_SEND_EOF; 18159243Sobrien return XK_CMD;/* PWP: Pretend we just read an end-of-file */ 18259243Sobrien } 18359243Sobrien *(ch->buf) = tch; 18459243Sobrien return (TraverseMap(ptr->next, ch, val)); 18559243Sobrien } 18659243Sobrien else { 18759243Sobrien *val = ptr->val; 18859243Sobrien if (ptr->type != XK_CMD) 18959243Sobrien *(ch->buf) = '\0'; 19059243Sobrien return ptr->type; 19159243Sobrien } 19259243Sobrien } 19359243Sobrien else { 19459243Sobrien /* no match found here */ 19559243Sobrien if (ptr->sibling) { 19659243Sobrien /* try next sibling */ 19759243Sobrien return (TraverseMap(ptr->sibling, ch, val)); 19859243Sobrien } 19959243Sobrien else { 20059243Sobrien /* no next sibling -- mismatch */ 20159243Sobrien val->str.buf = NULL; 20259243Sobrien val->str.len = 0; 20359243Sobrien return XK_STR; 20459243Sobrien } 20559243Sobrien } 20659243Sobrien} 20759243Sobrien 20859243Sobrienvoid 209167465SmpAddXkey(const CStr *Xkey, XmapVal *val, int ntype) 21059243Sobrien{ 21159243Sobrien CStr cs; 21259243Sobrien cs.buf = Xkey->buf; 21359243Sobrien cs.len = Xkey->len; 21459243Sobrien if (Xkey->len == 0) { 215195609Smp xprintf("%s", CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n")); 21659243Sobrien return; 21759243Sobrien } 21859243Sobrien 21959243Sobrien if (ntype == XK_CMD && val->cmd == F_XKEY) { 220195609Smp xprintf("%s", 221195609Smp CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n")); 22259243Sobrien return; 22359243Sobrien } 22459243Sobrien 22559243Sobrien if (Xmap == NULL) 22659243Sobrien /* tree is initially empty. Set up new node to match Xkey[0] */ 22759243Sobrien Xmap = GetFreeNode(&cs); /* it is properly initialized */ 22859243Sobrien 22959243Sobrien /* Now recurse through Xmap */ 23059243Sobrien (void) TryNode(Xmap, &cs, val, ntype); 23159243Sobrien return; 23259243Sobrien} 23359243Sobrien 23459243Sobrienstatic int 235167465SmpTryNode(XmapNode *ptr, CStr *str, XmapVal *val, int ntype) 23659243Sobrien{ 23759243Sobrien /* 23859243Sobrien * Find a node that matches *string or allocate a new one 23959243Sobrien */ 24059243Sobrien if (ptr->ch != *(str->buf)) { 24159243Sobrien XmapNode *xm; 24259243Sobrien 24359243Sobrien for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 24459243Sobrien if (xm->sibling->ch == *(str->buf)) 24559243Sobrien break; 24659243Sobrien if (xm->sibling == NULL) 24759243Sobrien xm->sibling = GetFreeNode(str); /* setup new node */ 24859243Sobrien ptr = xm->sibling; 24959243Sobrien } 25059243Sobrien 25159243Sobrien str->buf++; 25259243Sobrien str->len--; 25359243Sobrien if (str->len == 0) { 254167465Smp size_t len; 255167465Smp 25659243Sobrien /* we're there */ 25759243Sobrien if (ptr->next != NULL) { 25859243Sobrien PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */ 25959243Sobrien ptr->next = NULL; 26059243Sobrien } 26159243Sobrien 26259243Sobrien switch (ptr->type) { 26359243Sobrien case XK_STR: 26459243Sobrien case XK_EXE: 265167465Smp xfree(ptr->val.str.buf); 26659243Sobrien ptr->val.str.len = 0; 26759243Sobrien break; 26859243Sobrien case XK_NOD: 26959243Sobrien case XK_CMD: 27059243Sobrien break; 27159243Sobrien default: 27259243Sobrien abort(); 27359243Sobrien break; 27459243Sobrien } 27559243Sobrien 27659243Sobrien switch (ptr->type = ntype) { 27759243Sobrien case XK_CMD: 27859243Sobrien ptr->val = *val; 27959243Sobrien break; 28059243Sobrien case XK_STR: 28159243Sobrien case XK_EXE: 28259243Sobrien ptr->val.str.len = val->str.len; 283167465Smp len = (val->str.len + 1) * sizeof(*ptr->val.str.buf); 284167465Smp ptr->val.str.buf = xmalloc(len); 285167465Smp (void) memcpy(ptr->val.str.buf, val->str.buf, len); 28659243Sobrien break; 28759243Sobrien default: 28859243Sobrien abort(); 28959243Sobrien break; 29059243Sobrien } 29159243Sobrien } 29259243Sobrien else { 29359243Sobrien /* still more chars to go */ 29459243Sobrien if (ptr->next == NULL) 29559243Sobrien ptr->next = GetFreeNode(str); /* setup new node */ 29659243Sobrien (void) TryNode(ptr->next, str, val, ntype); 29759243Sobrien } 29859243Sobrien return (0); 29959243Sobrien} 30059243Sobrien 30159243Sobrienvoid 302167465SmpClearXkey(KEYCMD *map, const CStr *in) 30359243Sobrien{ 30459243Sobrien unsigned char c = (unsigned char) *(in->buf); 30559243Sobrien if ((map[c] == F_XKEY) && 30659243Sobrien ((map == CcKeyMap && CcAltMap[c] != F_XKEY) || 30759243Sobrien (map == CcAltMap && CcKeyMap[c] != F_XKEY))) 30859243Sobrien (void) DeleteXkey(in); 30959243Sobrien} 31059243Sobrien 31159243Sobrienint 312167465SmpDeleteXkey(const CStr *Xkey) 31359243Sobrien{ 314167465Smp CStr s; 315167465Smp 316167465Smp s = *Xkey; 317167465Smp if (s.len == 0) { 318195609Smp xprintf("%s", 319195609Smp CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n")); 32059243Sobrien return (-1); 32159243Sobrien } 32259243Sobrien 32359243Sobrien if (Xmap == NULL) 32459243Sobrien return (0); 32559243Sobrien 326167465Smp (void) TryDeleteNode(&Xmap, &s); 32759243Sobrien return (0); 32859243Sobrien} 32959243Sobrien 330167465Smp/* Destroys str */ 33159243Sobrienstatic int 332167465SmpTryDeleteNode(XmapNode **inptr, CStr *str) 33359243Sobrien{ 33459243Sobrien XmapNode *ptr; 33559243Sobrien 33659243Sobrien ptr = *inptr; 33759243Sobrien /* 33859243Sobrien * Find a node that matches *string or allocate a new one 33959243Sobrien */ 34059243Sobrien if (ptr->ch != *(str->buf)) { 34159243Sobrien XmapNode *xm; 34259243Sobrien 34359243Sobrien for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 34459243Sobrien if (xm->sibling->ch == *(str->buf)) 34559243Sobrien break; 34659243Sobrien if (xm->sibling == NULL) 34759243Sobrien return (0); 348167465Smp inptr = &xm->sibling; 34959243Sobrien ptr = xm->sibling; 35059243Sobrien } 35159243Sobrien 35259243Sobrien str->buf++; 35359243Sobrien str->len--; 35459243Sobrien 35559243Sobrien if (str->len == 0) { 35659243Sobrien /* we're there */ 357167465Smp *inptr = ptr->sibling; 35859243Sobrien ptr->sibling = NULL; 35959243Sobrien PutFreeNode(ptr); 36059243Sobrien return (1); 36159243Sobrien } 36259243Sobrien else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) { 36359243Sobrien if (ptr->next != NULL) 36459243Sobrien return (0); 365167465Smp *inptr = ptr->sibling; 36659243Sobrien ptr->sibling = NULL; 36759243Sobrien PutFreeNode(ptr); 36859243Sobrien return (1); 36959243Sobrien } 37059243Sobrien else { 37159243Sobrien return (0); 37259243Sobrien } 37359243Sobrien} 37459243Sobrien 37559243Sobrien/* PutFreeNode(): 37659243Sobrien * Puts a tree of nodes onto free list using free(3). 37759243Sobrien */ 37859243Sobrienstatic void 379167465SmpPutFreeNode(XmapNode *ptr) 38059243Sobrien{ 38159243Sobrien if (ptr == NULL) 38259243Sobrien return; 38359243Sobrien 38459243Sobrien if (ptr->next != NULL) { 38559243Sobrien PutFreeNode(ptr->next); 38659243Sobrien ptr->next = NULL; 38759243Sobrien } 38859243Sobrien 38959243Sobrien PutFreeNode(ptr->sibling); 39059243Sobrien 39159243Sobrien switch (ptr->type) { 39259243Sobrien case XK_CMD: 39359243Sobrien case XK_NOD: 39459243Sobrien break; 39559243Sobrien case XK_EXE: 39659243Sobrien case XK_STR: 397167465Smp xfree(ptr->val.str.buf); 39859243Sobrien break; 39959243Sobrien default: 40059243Sobrien abort(); 40159243Sobrien break; 40259243Sobrien } 403167465Smp xfree(ptr); 40459243Sobrien} 40559243Sobrien 40659243Sobrien 40759243Sobrien/* GetFreeNode(): 40859243Sobrien * Returns pointer to an XmapNode for ch. 40959243Sobrien */ 41059243Sobrienstatic XmapNode * 411167465SmpGetFreeNode(CStr *ch) 41259243Sobrien{ 41359243Sobrien XmapNode *ptr; 41459243Sobrien 415167465Smp ptr = xmalloc(sizeof(XmapNode)); 41659243Sobrien ptr->ch = ch->buf[0]; 41759243Sobrien ptr->type = XK_NOD; 41859243Sobrien ptr->val.str.buf = NULL; 41959243Sobrien ptr->val.str.len = 0; 42059243Sobrien ptr->next = NULL; 42159243Sobrien ptr->sibling = NULL; 42259243Sobrien return (ptr); 42359243Sobrien} 42459243Sobrien 42559243Sobrien 42659243Sobrien/* PrintXKey(): 42759243Sobrien * Print the binding associated with Xkey key. 42859243Sobrien * Print entire Xmap if null 42959243Sobrien */ 43059243Sobrienvoid 431167465SmpPrintXkey(const CStr *key) 43259243Sobrien{ 433167465Smp struct Strbuf buf = Strbuf_INIT; 43459243Sobrien CStr cs; 43559243Sobrien 43659243Sobrien if (key) { 43759243Sobrien cs.buf = key->buf; 43859243Sobrien cs.len = key->len; 43959243Sobrien } 44059243Sobrien else { 44159243Sobrien cs.buf = STRNULL; 44259243Sobrien cs.len = 0; 44359243Sobrien } 44459243Sobrien /* do nothing if Xmap is empty and null key specified */ 44559243Sobrien if (Xmap == NULL && cs.len == 0) 44659243Sobrien return; 44759243Sobrien 448167465Smp Strbuf_append1(&buf, '"'); 449167465Smp cleanup_push(&buf, Strbuf_cleanup); 450167465Smp if (Lookup(&buf, &cs, Xmap) <= -1) 45159243Sobrien /* key is not bound */ 45259243Sobrien xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf); 453167465Smp cleanup_until(&buf); 45459243Sobrien} 45559243Sobrien 45659243Sobrien/* Lookup(): 45759243Sobrien * look for the string starting at node ptr. 45859243Sobrien * Print if last node 45959243Sobrien */ 46059243Sobrienstatic int 461167465SmpLookup(struct Strbuf *buf, const CStr *str, const XmapNode *ptr) 46259243Sobrien{ 46359243Sobrien if (ptr == NULL) 46459243Sobrien return (-1); /* cannot have null ptr */ 46559243Sobrien 46659243Sobrien if (str->len == 0) { 46759243Sobrien /* no more chars in string. Enumerate from here. */ 468167465Smp Enumerate(buf, ptr); 46959243Sobrien return (0); 47059243Sobrien } 47159243Sobrien else { 472167465Smp /* If match put this char into buf. Recurse */ 47359243Sobrien if (ptr->ch == *(str->buf)) { 47459243Sobrien /* match found */ 475167465Smp unparsech(buf, ptr->ch); 47659243Sobrien if (ptr->next != NULL) { 47759243Sobrien /* not yet at leaf */ 47859243Sobrien CStr tstr; 47959243Sobrien tstr.buf = str->buf + 1; 48059243Sobrien tstr.len = str->len - 1; 481167465Smp return (Lookup(buf, &tstr, ptr->next)); 48259243Sobrien } 48359243Sobrien else { 48459243Sobrien /* next node is null so key should be complete */ 48559243Sobrien if (str->len == 1) { 486167465Smp Strbuf_append1(buf, '"'); 487167465Smp Strbuf_terminate(buf); 488167465Smp printOne(buf->s, &ptr->val, ptr->type); 48959243Sobrien return (0); 49059243Sobrien } 49159243Sobrien else 49259243Sobrien return (-1);/* mismatch -- string still has chars */ 49359243Sobrien } 49459243Sobrien } 49559243Sobrien else { 49659243Sobrien /* no match found try sibling */ 49759243Sobrien if (ptr->sibling) 498167465Smp return (Lookup(buf, str, ptr->sibling)); 49959243Sobrien else 50059243Sobrien return (-1); 50159243Sobrien } 50259243Sobrien } 50359243Sobrien} 50459243Sobrien 505167465Smpstatic void 506167465SmpEnumerate(struct Strbuf *buf, const XmapNode *ptr) 50759243Sobrien{ 508167465Smp size_t old_len; 50959243Sobrien 51059243Sobrien if (ptr == NULL) { 51159243Sobrien#ifdef DEBUG_EDIT 51259243Sobrien xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!")); 51359243Sobrien#endif 514167465Smp return; 51559243Sobrien } 51659243Sobrien 517167465Smp old_len = buf->len; 518167465Smp unparsech(buf, ptr->ch); /* put this char at end of string */ 51959243Sobrien if (ptr->next == NULL) { 52059243Sobrien /* print this Xkey and function */ 521167465Smp Strbuf_append1(buf, '"'); 522167465Smp Strbuf_terminate(buf); 523167465Smp printOne(buf->s, &ptr->val, ptr->type); 52459243Sobrien } 52559243Sobrien else 526167465Smp Enumerate(buf, ptr->next); 52759243Sobrien 52859243Sobrien /* go to sibling if there is one */ 529167465Smp if (ptr->sibling) { 530167465Smp buf->len = old_len; 531167465Smp Enumerate(buf, ptr->sibling); 532167465Smp } 53359243Sobrien} 53459243Sobrien 53559243Sobrien 53659243Sobrien/* PrintOne(): 53759243Sobrien * Print the specified key and its associated 53859243Sobrien * function specified by val 53959243Sobrien */ 540167465Smpvoid 541167465SmpprintOne(const Char *key, const XmapVal *val, int ntype) 54259243Sobrien{ 54359243Sobrien struct KeyFuncs *fp; 544145479Smp static const char *fmt = "%s\n"; 54559243Sobrien 546167465Smp xprintf("%-15S-> ", key); 54759243Sobrien if (val != NULL) 54859243Sobrien switch (ntype) { 54959243Sobrien case XK_STR: 550167465Smp case XK_EXE: { 551167465Smp unsigned char *p; 552167465Smp 553167465Smp p = unparsestring(&val->str, ntype == XK_STR ? STRQQ : STRBB); 554167465Smp cleanup_push(p, xfree); 555167465Smp xprintf(fmt, p); 556167465Smp cleanup_until(p); 55759243Sobrien break; 558167465Smp } 55959243Sobrien case XK_CMD: 56059243Sobrien for (fp = FuncNames; fp->name; fp++) 56159243Sobrien if (val->cmd == fp->func) 56259243Sobrien xprintf(fmt, fp->name); 56359243Sobrien break; 56459243Sobrien default: 56559243Sobrien abort(); 56659243Sobrien break; 56759243Sobrien } 56859243Sobrien else 569167465Smp xprintf(fmt, CGETS(9, 7, "no input")); 57059243Sobrien} 57159243Sobrien 572167465Smpstatic void 573167465Smpunparsech(struct Strbuf *buf, Char ch) 57459243Sobrien{ 57559243Sobrien if (ch == 0) { 576167465Smp Strbuf_append1(buf, '^'); 577167465Smp Strbuf_append1(buf, '@'); 57859243Sobrien } 579167465Smp else if (Iscntrl(ch)) { 580167465Smp Strbuf_append1(buf, '^'); 581167465Smp if (ch == CTL_ESC('\177')) 582167465Smp Strbuf_append1(buf, '?'); 583167465Smp else 58469408Sache#ifdef IS_ASCII 585167465Smp Strbuf_append1(buf, ch | 0100); 58669408Sache#else 587167465Smp Strbuf_append1(buf, _toebcdic[_toascii[ch]|0100]); 58869408Sache#endif 58959243Sobrien } 590167465Smp else if (ch == '^') { 591167465Smp Strbuf_append1(buf, '\\'); 592167465Smp Strbuf_append1(buf, '^'); 593167465Smp } else if (ch == '\\') { 594167465Smp Strbuf_append1(buf, '\\'); 595167465Smp Strbuf_append1(buf, '\\'); 596167465Smp } else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) { 597167465Smp Strbuf_append1(buf, ch); 59859243Sobrien } 59959243Sobrien else { 600167465Smp Strbuf_append1(buf, '\\'); 601167465Smp Strbuf_append1(buf, ((ch >> 6) & 7) + '0'); 602167465Smp Strbuf_append1(buf, ((ch >> 3) & 7) + '0'); 603167465Smp Strbuf_append1(buf, (ch & 7) + '0'); 60459243Sobrien } 60559243Sobrien} 60659243Sobrien 607145479SmpeChar 608167465Smpparseescape(const Char **ptr) 60959243Sobrien{ 61059243Sobrien const Char *p; 61159243Sobrien Char c; 61259243Sobrien 61359243Sobrien p = *ptr; 61459243Sobrien 61559243Sobrien if ((p[1] & CHAR) == 0) { 616167465Smp xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p); 617145479Smp return CHAR_ERR; 61859243Sobrien } 61959243Sobrien if ((*p & CHAR) == '\\') { 62059243Sobrien p++; 62159243Sobrien switch (*p & CHAR) { 62259243Sobrien case 'a': 62359243Sobrien c = CTL_ESC('\007'); /* Bell */ 62459243Sobrien break; 62559243Sobrien case 'b': 62659243Sobrien c = CTL_ESC('\010'); /* Backspace */ 62759243Sobrien break; 62859243Sobrien case 'e': 62959243Sobrien c = CTL_ESC('\033'); /* Escape */ 63059243Sobrien break; 63159243Sobrien case 'f': 63259243Sobrien c = CTL_ESC('\014'); /* Form Feed */ 63359243Sobrien break; 63459243Sobrien case 'n': 63559243Sobrien c = CTL_ESC('\012'); /* New Line */ 63659243Sobrien break; 63759243Sobrien case 'r': 63859243Sobrien c = CTL_ESC('\015'); /* Carriage Return */ 63959243Sobrien break; 64059243Sobrien case 't': 64159243Sobrien c = CTL_ESC('\011'); /* Horizontal Tab */ 64259243Sobrien break; 64359243Sobrien case 'v': 64459243Sobrien c = CTL_ESC('\013'); /* Vertical Tab */ 64559243Sobrien break; 64683098Smp case '\\': 64783098Smp c = '\\'; 64883098Smp break; 64959243Sobrien case '0': 65059243Sobrien case '1': 65159243Sobrien case '2': 65259243Sobrien case '3': 65359243Sobrien case '4': 65459243Sobrien case '5': 65559243Sobrien case '6': 65659243Sobrien case '7': 65759243Sobrien { 658145479Smp int cnt, val; 659145479Smp Char ch; 66059243Sobrien 66159243Sobrien for (cnt = 0, val = 0; cnt < 3; cnt++) { 66259243Sobrien ch = *p++ & CHAR; 66359243Sobrien if (ch < '0' || ch > '7') { 66459243Sobrien p--; 66559243Sobrien break; 66659243Sobrien } 66759243Sobrien val = (val << 3) | (ch - '0'); 66859243Sobrien } 669167465Smp if ((val & ~0xff) != 0) { 670195609Smp xprintf("%s", CGETS(9, 9, 67159243Sobrien "Octal constant does not fit in a char.\n")); 67259243Sobrien return 0; 67359243Sobrien } 67469408Sache#ifndef IS_ASCII 67559243Sobrien if (CTL_ESC(val) != val && adrof(STRwarnebcdic)) 67659243Sobrien xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 67759243Sobrien "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/); 67859243Sobrien#endif 67959243Sobrien c = (Char) val; 68059243Sobrien --p; 68159243Sobrien } 68259243Sobrien break; 68359243Sobrien default: 68459243Sobrien c = *p; 68559243Sobrien break; 68659243Sobrien } 68759243Sobrien } 68859243Sobrien else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) || 68959243Sobrien strchr("@^_?\\|[{]}", p[1] & CHAR))) { 69059243Sobrien p++; 69169408Sache#ifdef IS_ASCII 69259243Sobrien c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237); 69369408Sache#else 69459243Sobrien c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237]; 69559243Sobrien if (adrof(STRwarnebcdic)) 69659243Sobrien xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 69759243Sobrien "Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/); 69869408Sache#endif 69959243Sobrien } 70059243Sobrien else 70159243Sobrien c = *p; 70259243Sobrien *ptr = p; 70359243Sobrien return (c); 70459243Sobrien} 70559243Sobrien 70659243Sobrien 70759243Sobrienunsigned char * 708167465Smpunparsestring(const CStr *str, const Char *sep) 70959243Sobrien{ 710167465Smp unsigned char *buf, *b; 71159243Sobrien Char p; 71259243Sobrien int l; 71359243Sobrien 714167465Smp /* Worst-case is "\uuu" or result of wctomb() for each char from str */ 715167465Smp buf = xmalloc((str->len + 1) * max(4, MB_LEN_MAX)); 71659243Sobrien b = buf; 71759243Sobrien if (sep[0]) 71869408Sache#ifndef WINNT_NATIVE 71959243Sobrien *b++ = sep[0]; 72069408Sache#else /* WINNT_NATIVE */ 72159243Sobrien *b++ = CHAR & sep[0]; 72269408Sache#endif /* !WINNT_NATIVE */ 72359243Sobrien 72459243Sobrien for (l = 0; l < str->len; l++) { 72559243Sobrien p = str->buf[l]; 72659243Sobrien if (Iscntrl(p)) { 72759243Sobrien *b++ = '^'; 72859243Sobrien if (p == CTL_ESC('\177')) 72959243Sobrien *b++ = '?'; 73059243Sobrien else 731167465Smp#ifdef IS_ASCII 73259243Sobrien *b++ = (unsigned char) (p | 0100); 73369408Sache#else 734167465Smp *b++ = _toebcdic[_toascii[p]|0100]; 73569408Sache#endif 73659243Sobrien } 73759243Sobrien else if (p == '^' || p == '\\') { 73859243Sobrien *b++ = '\\'; 73959243Sobrien *b++ = (unsigned char) p; 74059243Sobrien } 741145479Smp else if (p == ' ' || (Isprint(p) && !Isspace(p))) 742316957Sdchagin b += one_wctomb((char *)b, p); 74359243Sobrien else { 74459243Sobrien *b++ = '\\'; 74559243Sobrien *b++ = ((p >> 6) & 7) + '0'; 74659243Sobrien *b++ = ((p >> 3) & 7) + '0'; 74759243Sobrien *b++ = (p & 7) + '0'; 74859243Sobrien } 74959243Sobrien } 75059243Sobrien if (sep[0] && sep[1]) 75169408Sache#ifndef WINNT_NATIVE 75259243Sobrien *b++ = sep[1]; 75369408Sache#else /* WINNT_NATIVE */ 75459243Sobrien *b++ = CHAR & sep[1]; 75569408Sache#endif /* !WINNT_NATIVE */ 75659243Sobrien *b++ = 0; 75759243Sobrien return buf; /* should check for overflow */ 75859243Sobrien} 759