ed.xmap.c revision 267654
1290650Shselasky/* $Header: /p/tcsh/cvsroot/tcsh/ed.xmap.c,v 3.37 2009/06/25 21:15:37 christos Exp $ */ 2290650Shselasky/* 3290650Shselasky * ed.xmap.c: This module contains the procedures for maintaining 4290650Shselasky * the extended-key map. 5290650Shselasky * 6290650Shselasky * An extended-key (Xkey) is a sequence of keystrokes 7290650Shselasky * introduced with an sequence introducer and consisting 8290650Shselasky * of an arbitrary number of characters. This module maintains 9290650Shselasky * a map (the Xmap) to convert these extended-key sequences 10290650Shselasky * into input strings (XK_STR), editor functions (XK_CMD), or 11290650Shselasky * unix commands (XK_EXE). It contains the 12290650Shselasky * following externally visible functions. 13290650Shselasky * 14290650Shselasky * int GetXkey(ch,val); 15290650Shselasky * CStr *ch; 16290650Shselasky * XmapVal *val; 17290650Shselasky * 18290650Shselasky * Looks up *ch in map and then reads characters until a 19290650Shselasky * complete match is found or a mismatch occurs. Returns the 20290650Shselasky * type of the match found (XK_STR, XK_CMD, or XK_EXE). 21290650Shselasky * Returns NULL in val.str and XK_STR for no match. 22290650Shselasky * The last character read is returned in *ch. 23290650Shselasky * 24290650Shselasky * void AddXkey(Xkey, val, ntype); 25290650Shselasky * CStr *Xkey; 26290650Shselasky * XmapVal *val; 27290650Shselasky * int ntype; 28290650Shselasky * 29290650Shselasky * Adds Xkey to the Xmap and associates the value in val with it. 30290650Shselasky * If Xkey is already is in Xmap, the new code is applied to the 31290650Shselasky * existing Xkey. Ntype specifies if code is a command, an 32290650Shselasky * out string or a unix command. 33290650Shselasky * 34290650Shselasky * int DeleteXkey(Xkey); 35290650Shselasky * CStr *Xkey; 36290650Shselasky * 37290650Shselasky * Delete the Xkey and all longer Xkeys staring with Xkey, if 38290650Shselasky * they exists. 39290650Shselasky * 40290650Shselasky * Warning: 41290650Shselasky * If Xkey is a substring of some other Xkeys, then the longer 42290650Shselasky * Xkeys are lost!! That is, if the Xkeys "abcd" and "abcef" 43290650Shselasky * are in Xmap, adding the key "abc" will cause the first two 44290650Shselasky * definitions to be lost. 45290650Shselasky * 46290650Shselasky * void ResetXmap(); 47290650Shselasky * 48290650Shselasky * Removes all entries from Xmap and resets the defaults. 49290650Shselasky * 50290650Shselasky * void PrintXkey(Xkey); 51290650Shselasky * CStr *Xkey; 52290650Shselasky * 53290650Shselasky * Prints all extended keys prefixed by Xkey and their associated 54290650Shselasky * commands. 55290650Shselasky * 56290650Shselasky * Restrictions: 57290650Shselasky * ------------- 58290650Shselasky * 1) It is not possible to have one Xkey that is a 59290650Shselasky * substring of another. 60290650Shselasky */ 61290650Shselasky/*- 62290650Shselasky * Copyright (c) 1980, 1991 The Regents of the University of California. 63290650Shselasky * All rights reserved. 64290650Shselasky * 65290650Shselasky * Redistribution and use in source and binary forms, with or without 66290650Shselasky * modification, are permitted provided that the following conditions 67290650Shselasky * are met: 68290650Shselasky * 1. Redistributions of source code must retain the above copyright 69290650Shselasky * notice, this list of conditions and the following disclaimer. 70290650Shselasky * 2. Redistributions in binary form must reproduce the above copyright 71290650Shselasky * notice, this list of conditions and the following disclaimer in the 72290650Shselasky * documentation and/or other materials provided with the distribution. 73290650Shselasky * 3. Neither the name of the University nor the names of its contributors 74290650Shselasky * may be used to endorse or promote products derived from this software 75290650Shselasky * without specific prior written permission. 76290650Shselasky * 77290650Shselasky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 78290650Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 79290650Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 80290650Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 81290650Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 82290650Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 83290650Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 84290650Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 85290650Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 86290650Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 87290650Shselasky * SUCH DAMAGE. 88290650Shselasky */ 89290650Shselasky#include "sh.h" 90290650Shselasky 91290650ShselaskyRCSID("$tcsh: ed.xmap.c,v 3.37 2009/06/25 21:15:37 christos Exp $") 92290650Shselasky 93290650Shselasky#include "ed.h" 94290650Shselasky#include "ed.defns.h" 95290650Shselasky 96290650Shselasky#ifndef NULL 97290650Shselasky#define NULL 0 98290650Shselasky#endif 99290650Shselasky 100290650Shselasky/* Internal Data types and declarations */ 101290650Shselasky 102290650Shselasky/* The Nodes of the Xmap. The Xmap is a linked list of these node 103290650Shselasky * elements 104290650Shselasky */ 105290650Shselaskytypedef struct Xmapnode { 106290650Shselasky Char ch; /* single character of Xkey */ 107290650Shselasky int type; 108290650Shselasky XmapVal val; /* command code or pointer to string, if this 109290650Shselasky * is a leaf */ 110290650Shselasky struct Xmapnode *next; /* ptr to next char of this Xkey */ 111290650Shselasky struct Xmapnode *sibling; /* ptr to another Xkey with same prefix */ 112290650Shselasky} XmapNode; 113290650Shselasky 114290650Shselaskystatic XmapNode *Xmap = NULL; /* the current Xmap */ 115290650Shselasky 116290650Shselasky 117290650Shselasky/* Some declarations of procedures */ 118290650Shselaskystatic int TraverseMap (XmapNode *, CStr *, XmapVal *); 119290650Shselaskystatic int TryNode (XmapNode *, CStr *, XmapVal *, int); 120290650Shselaskystatic XmapNode *GetFreeNode (CStr *); 121290650Shselaskystatic void PutFreeNode (XmapNode *); 122290650Shselaskystatic int TryDeleteNode (XmapNode **, CStr *); 123290650Shselaskystatic int Lookup (struct Strbuf *, const CStr *, 124290650Shselasky const XmapNode *); 125290650Shselaskystatic void Enumerate (struct Strbuf *, const XmapNode *); 126290650Shselaskystatic void unparsech (struct Strbuf *, Char); 127290650Shselasky 128290650Shselasky 129290650ShselaskyXmapVal * 130290650ShselaskyXmapCmd(int cmd) 131290650Shselasky{ 132290650Shselasky static XmapVal xm; 133290650Shselasky xm.cmd = (KEYCMD) cmd; 134290650Shselasky return &xm; 135290650Shselasky} 136290650Shselasky 137290650ShselaskyXmapVal * 138290650ShselaskyXmapStr(CStr *str) 139290650Shselasky{ 140290650Shselasky static XmapVal xm; 141290650Shselasky xm.str.len = str->len; 142290650Shselasky xm.str.buf = str->buf; 143290650Shselasky return &xm; 144290650Shselasky} 145290650Shselasky 146290650Shselasky/* ResetXmap(): 147290650Shselasky * Takes all nodes on Xmap and puts them on free list. Then 148290650Shselasky * initializes Xmap with arrow keys 149290650Shselasky */ 150290650Shselaskyvoid 151290650ShselaskyResetXmap(void) 152290650Shselasky{ 153290650Shselasky PutFreeNode(Xmap); 154290650Shselasky Xmap = NULL; 155290650Shselasky 156290650Shselasky DefaultArrowKeys(); 157290650Shselasky return; 158290650Shselasky} 159290650Shselasky 160290650Shselasky 161290650Shselasky/* GetXkey(): 162290650Shselasky * Calls the recursive function with entry point Xmap 163290650Shselasky */ 164290650Shselaskyint 165290650ShselaskyGetXkey(CStr *ch, XmapVal *val) 166290650Shselasky{ 167290650Shselasky return (TraverseMap(Xmap, ch, val)); 168290650Shselasky} 169290650Shselasky 170290650Shselasky/* TraverseMap(): 171290650Shselasky * recursively traverses node in tree until match or mismatch is 172290650Shselasky * found. May read in more characters. 173290650Shselasky */ 174290650Shselaskystatic int 175290650ShselaskyTraverseMap(XmapNode *ptr, CStr *ch, XmapVal *val) 176290650Shselasky{ 177290650Shselasky Char tch; 178290650Shselasky 179290650Shselasky if (ptr->ch == *(ch->buf)) { 180290650Shselasky /* match found */ 181290650Shselasky if (ptr->next) { 182290650Shselasky /* Xkey not complete so get next char */ 183290650Shselasky if (GetNextChar(&tch) != 1) { /* if EOF or error */ 184290650Shselasky val->cmd = F_SEND_EOF; 185290650Shselasky return XK_CMD;/* PWP: Pretend we just read an end-of-file */ 186290650Shselasky } 187290650Shselasky *(ch->buf) = tch; 188290650Shselasky return (TraverseMap(ptr->next, ch, val)); 189290650Shselasky } 190290650Shselasky else { 191290650Shselasky *val = ptr->val; 192290650Shselasky if (ptr->type != XK_CMD) 193290650Shselasky *(ch->buf) = '\0'; 194290650Shselasky return ptr->type; 195290650Shselasky } 196290650Shselasky } 197290650Shselasky else { 198290650Shselasky /* no match found here */ 199290650Shselasky if (ptr->sibling) { 200290650Shselasky /* try next sibling */ 201290650Shselasky return (TraverseMap(ptr->sibling, ch, val)); 202290650Shselasky } 203290650Shselasky else { 204290650Shselasky /* no next sibling -- mismatch */ 205290650Shselasky val->str.buf = NULL; 206290650Shselasky val->str.len = 0; 207290650Shselasky return XK_STR; 208290650Shselasky } 209290650Shselasky } 210290650Shselasky} 211290650Shselasky 212290650Shselaskyvoid 213290650ShselaskyAddXkey(const CStr *Xkey, XmapVal *val, int ntype) 214290650Shselasky{ 215290650Shselasky CStr cs; 216290650Shselasky cs.buf = Xkey->buf; 217290650Shselasky cs.len = Xkey->len; 218290650Shselasky if (Xkey->len == 0) { 219290650Shselasky xprintf("%s", CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n")); 220290650Shselasky return; 221290650Shselasky } 222290650Shselasky 223290650Shselasky if (ntype == XK_CMD && val->cmd == F_XKEY) { 224290650Shselasky xprintf("%s", 225290650Shselasky CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n")); 226290650Shselasky return; 227290650Shselasky } 228290650Shselasky 229290650Shselasky if (Xmap == NULL) 230290650Shselasky /* tree is initially empty. Set up new node to match Xkey[0] */ 231290650Shselasky Xmap = GetFreeNode(&cs); /* it is properly initialized */ 232290650Shselasky 233290650Shselasky /* Now recurse through Xmap */ 234290650Shselasky (void) TryNode(Xmap, &cs, val, ntype); 235290650Shselasky return; 236290650Shselasky} 237290650Shselasky 238290650Shselaskystatic int 239290650ShselaskyTryNode(XmapNode *ptr, CStr *str, XmapVal *val, int ntype) 240290650Shselasky{ 241290650Shselasky /* 242290650Shselasky * Find a node that matches *string or allocate a new one 243290650Shselasky */ 244290650Shselasky if (ptr->ch != *(str->buf)) { 245290650Shselasky XmapNode *xm; 246290650Shselasky 247290650Shselasky for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 248290650Shselasky if (xm->sibling->ch == *(str->buf)) 249290650Shselasky break; 250290650Shselasky if (xm->sibling == NULL) 251290650Shselasky xm->sibling = GetFreeNode(str); /* setup new node */ 252290650Shselasky ptr = xm->sibling; 253290650Shselasky } 254290650Shselasky 255290650Shselasky str->buf++; 256290650Shselasky str->len--; 257290650Shselasky if (str->len == 0) { 258290650Shselasky size_t len; 259290650Shselasky 260290650Shselasky /* we're there */ 261290650Shselasky if (ptr->next != NULL) { 262290650Shselasky PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */ 263290650Shselasky ptr->next = NULL; 264290650Shselasky } 265290650Shselasky 266290650Shselasky switch (ptr->type) { 267290650Shselasky case XK_STR: 268290650Shselasky case XK_EXE: 269290650Shselasky xfree(ptr->val.str.buf); 270290650Shselasky ptr->val.str.len = 0; 271290650Shselasky break; 272290650Shselasky case XK_NOD: 273290650Shselasky case XK_CMD: 274290650Shselasky break; 275290650Shselasky default: 276290650Shselasky abort(); 277290650Shselasky break; 278290650Shselasky } 279290650Shselasky 280290650Shselasky switch (ptr->type = ntype) { 281290650Shselasky case XK_CMD: 282290650Shselasky ptr->val = *val; 283290650Shselasky break; 284290650Shselasky case XK_STR: 285290650Shselasky case XK_EXE: 286290650Shselasky ptr->val.str.len = val->str.len; 287290650Shselasky len = (val->str.len + 1) * sizeof(*ptr->val.str.buf); 288290650Shselasky ptr->val.str.buf = xmalloc(len); 289290650Shselasky (void) memcpy(ptr->val.str.buf, val->str.buf, len); 290290650Shselasky break; 291290650Shselasky default: 292290650Shselasky abort(); 293290650Shselasky break; 294290650Shselasky } 295290650Shselasky } 296290650Shselasky else { 297290650Shselasky /* still more chars to go */ 298290650Shselasky if (ptr->next == NULL) 299290650Shselasky ptr->next = GetFreeNode(str); /* setup new node */ 300290650Shselasky (void) TryNode(ptr->next, str, val, ntype); 301290650Shselasky } 302290650Shselasky return (0); 303290650Shselasky} 304290650Shselasky 305290650Shselaskyvoid 306290650ShselaskyClearXkey(KEYCMD *map, const CStr *in) 307290650Shselasky{ 308290650Shselasky unsigned char c = (unsigned char) *(in->buf); 309290650Shselasky if ((map[c] == F_XKEY) && 310290650Shselasky ((map == CcKeyMap && CcAltMap[c] != F_XKEY) || 311290650Shselasky (map == CcAltMap && CcKeyMap[c] != F_XKEY))) 312290650Shselasky (void) DeleteXkey(in); 313290650Shselasky} 314290650Shselasky 315290650Shselaskyint 316290650ShselaskyDeleteXkey(const CStr *Xkey) 317290650Shselasky{ 318290650Shselasky CStr s; 319290650Shselasky 320290650Shselasky s = *Xkey; 321290650Shselasky if (s.len == 0) { 322290650Shselasky xprintf("%s", 323290650Shselasky CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n")); 324290650Shselasky return (-1); 325290650Shselasky } 326290650Shselasky 327290650Shselasky if (Xmap == NULL) 328290650Shselasky return (0); 329290650Shselasky 330290650Shselasky (void) TryDeleteNode(&Xmap, &s); 331290650Shselasky return (0); 332290650Shselasky} 333290650Shselasky 334290650Shselasky/* Destroys str */ 335290650Shselaskystatic int 336290650ShselaskyTryDeleteNode(XmapNode **inptr, CStr *str) 337290650Shselasky{ 338290650Shselasky XmapNode *ptr; 339290650Shselasky 340290650Shselasky ptr = *inptr; 341290650Shselasky /* 342290650Shselasky * Find a node that matches *string or allocate a new one 343290650Shselasky */ 344290650Shselasky if (ptr->ch != *(str->buf)) { 345290650Shselasky XmapNode *xm; 346290650Shselasky 347290650Shselasky for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 348290650Shselasky if (xm->sibling->ch == *(str->buf)) 349290650Shselasky break; 350290650Shselasky if (xm->sibling == NULL) 351290650Shselasky return (0); 352290650Shselasky inptr = &xm->sibling; 353290650Shselasky ptr = xm->sibling; 354290650Shselasky } 355290650Shselasky 356290650Shselasky str->buf++; 357290650Shselasky str->len--; 358290650Shselasky 359290650Shselasky if (str->len == 0) { 360290650Shselasky /* we're there */ 361290650Shselasky *inptr = ptr->sibling; 362290650Shselasky ptr->sibling = NULL; 363290650Shselasky PutFreeNode(ptr); 364290650Shselasky return (1); 365290650Shselasky } 366290650Shselasky else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) { 367290650Shselasky if (ptr->next != NULL) 368290650Shselasky return (0); 369290650Shselasky *inptr = ptr->sibling; 370290650Shselasky ptr->sibling = NULL; 371290650Shselasky PutFreeNode(ptr); 372290650Shselasky return (1); 373290650Shselasky } 374290650Shselasky else { 375290650Shselasky return (0); 376290650Shselasky } 377290650Shselasky} 378290650Shselasky 379290650Shselasky/* PutFreeNode(): 380290650Shselasky * Puts a tree of nodes onto free list using free(3). 381290650Shselasky */ 382290650Shselaskystatic void 383290650ShselaskyPutFreeNode(XmapNode *ptr) 384290650Shselasky{ 385290650Shselasky if (ptr == NULL) 386290650Shselasky return; 387290650Shselasky 388290650Shselasky if (ptr->next != NULL) { 389290650Shselasky PutFreeNode(ptr->next); 390290650Shselasky ptr->next = NULL; 391290650Shselasky } 392290650Shselasky 393290650Shselasky PutFreeNode(ptr->sibling); 394290650Shselasky 395290650Shselasky switch (ptr->type) { 396290650Shselasky case XK_CMD: 397290650Shselasky case XK_NOD: 398290650Shselasky break; 399290650Shselasky case XK_EXE: 400290650Shselasky case XK_STR: 401290650Shselasky xfree(ptr->val.str.buf); 402290650Shselasky break; 403290650Shselasky default: 404290650Shselasky abort(); 405290650Shselasky break; 406290650Shselasky } 407290650Shselasky xfree(ptr); 408290650Shselasky} 409290650Shselasky 410290650Shselasky 411290650Shselasky/* GetFreeNode(): 412290650Shselasky * Returns pointer to an XmapNode for ch. 413290650Shselasky */ 414290650Shselaskystatic XmapNode * 415290650ShselaskyGetFreeNode(CStr *ch) 416290650Shselasky{ 417290650Shselasky XmapNode *ptr; 418290650Shselasky 419290650Shselasky ptr = xmalloc(sizeof(XmapNode)); 420290650Shselasky ptr->ch = ch->buf[0]; 421290650Shselasky ptr->type = XK_NOD; 422290650Shselasky ptr->val.str.buf = NULL; 423290650Shselasky ptr->val.str.len = 0; 424290650Shselasky ptr->next = NULL; 425290650Shselasky ptr->sibling = NULL; 426290650Shselasky return (ptr); 427290650Shselasky} 428290650Shselasky 429290650Shselasky 430290650Shselasky/* PrintXKey(): 431290650Shselasky * Print the binding associated with Xkey key. 432290650Shselasky * Print entire Xmap if null 433290650Shselasky */ 434290650Shselaskyvoid 435290650ShselaskyPrintXkey(const CStr *key) 436290650Shselasky{ 437290650Shselasky struct Strbuf buf = Strbuf_INIT; 438290650Shselasky CStr cs; 439290650Shselasky 440290650Shselasky if (key) { 441290650Shselasky cs.buf = key->buf; 442290650Shselasky cs.len = key->len; 443290650Shselasky } 444290650Shselasky else { 445290650Shselasky cs.buf = STRNULL; 446290650Shselasky cs.len = 0; 447290650Shselasky } 448290650Shselasky /* do nothing if Xmap is empty and null key specified */ 449290650Shselasky if (Xmap == NULL && cs.len == 0) 450290650Shselasky return; 451290650Shselasky 452290650Shselasky Strbuf_append1(&buf, '"'); 453290650Shselasky cleanup_push(&buf, Strbuf_cleanup); 454290650Shselasky if (Lookup(&buf, &cs, Xmap) <= -1) 455290650Shselasky /* key is not bound */ 456290650Shselasky xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf); 457290650Shselasky cleanup_until(&buf); 458290650Shselasky} 459290650Shselasky 460290650Shselasky/* Lookup(): 461290650Shselasky * look for the string starting at node ptr. 462290650Shselasky * Print if last node 463290650Shselasky */ 464290650Shselaskystatic int 465290650ShselaskyLookup(struct Strbuf *buf, const CStr *str, const XmapNode *ptr) 466290650Shselasky{ 467290650Shselasky if (ptr == NULL) 468290650Shselasky return (-1); /* cannot have null ptr */ 469290650Shselasky 470290650Shselasky if (str->len == 0) { 471290650Shselasky /* no more chars in string. Enumerate from here. */ 472290650Shselasky Enumerate(buf, ptr); 473290650Shselasky return (0); 474290650Shselasky } 475290650Shselasky else { 476290650Shselasky /* If match put this char into buf. Recurse */ 477290650Shselasky if (ptr->ch == *(str->buf)) { 478290650Shselasky /* match found */ 479290650Shselasky unparsech(buf, ptr->ch); 480290650Shselasky if (ptr->next != NULL) { 481290650Shselasky /* not yet at leaf */ 482290650Shselasky CStr tstr; 483290650Shselasky tstr.buf = str->buf + 1; 484290650Shselasky tstr.len = str->len - 1; 485290650Shselasky return (Lookup(buf, &tstr, ptr->next)); 486290650Shselasky } 487290650Shselasky else { 488290650Shselasky /* next node is null so key should be complete */ 489290650Shselasky if (str->len == 1) { 490290650Shselasky Strbuf_append1(buf, '"'); 491290650Shselasky Strbuf_terminate(buf); 492290650Shselasky printOne(buf->s, &ptr->val, ptr->type); 493290650Shselasky return (0); 494290650Shselasky } 495290650Shselasky else 496290650Shselasky return (-1);/* mismatch -- string still has chars */ 497290650Shselasky } 498290650Shselasky } 499290650Shselasky else { 500290650Shselasky /* no match found try sibling */ 501290650Shselasky if (ptr->sibling) 502290650Shselasky return (Lookup(buf, str, ptr->sibling)); 503290650Shselasky else 504290650Shselasky return (-1); 505290650Shselasky } 506290650Shselasky } 507290650Shselasky} 508290650Shselasky 509290650Shselaskystatic void 510290650ShselaskyEnumerate(struct Strbuf *buf, const XmapNode *ptr) 511290650Shselasky{ 512290650Shselasky size_t old_len; 513290650Shselasky 514290650Shselasky if (ptr == NULL) { 515290650Shselasky#ifdef DEBUG_EDIT 516290650Shselasky xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!")); 517290650Shselasky#endif 518290650Shselasky return; 519290650Shselasky } 520290650Shselasky 521290650Shselasky old_len = buf->len; 522290650Shselasky unparsech(buf, ptr->ch); /* put this char at end of string */ 523290650Shselasky if (ptr->next == NULL) { 524290650Shselasky /* print this Xkey and function */ 525290650Shselasky Strbuf_append1(buf, '"'); 526290650Shselasky Strbuf_terminate(buf); 527290650Shselasky printOne(buf->s, &ptr->val, ptr->type); 528290650Shselasky } 529290650Shselasky else 530290650Shselasky Enumerate(buf, ptr->next); 531290650Shselasky 532290650Shselasky /* go to sibling if there is one */ 533290650Shselasky if (ptr->sibling) { 534290650Shselasky buf->len = old_len; 535290650Shselasky Enumerate(buf, ptr->sibling); 536290650Shselasky } 537290650Shselasky} 538290650Shselasky 539290650Shselasky 540290650Shselasky/* PrintOne(): 541290650Shselasky * Print the specified key and its associated 542290650Shselasky * function specified by val 543290650Shselasky */ 544290650Shselaskyvoid 545290650ShselaskyprintOne(const Char *key, const XmapVal *val, int ntype) 546290650Shselasky{ 547290650Shselasky struct KeyFuncs *fp; 548290650Shselasky static const char *fmt = "%s\n"; 549290650Shselasky 550290650Shselasky xprintf("%-15S-> ", key); 551290650Shselasky if (val != NULL) 552290650Shselasky switch (ntype) { 553290650Shselasky case XK_STR: 554290650Shselasky case XK_EXE: { 555290650Shselasky unsigned char *p; 556290650Shselasky 557290650Shselasky p = unparsestring(&val->str, ntype == XK_STR ? STRQQ : STRBB); 558290650Shselasky cleanup_push(p, xfree); 559290650Shselasky xprintf(fmt, p); 560290650Shselasky cleanup_until(p); 561290650Shselasky break; 562290650Shselasky } 563290650Shselasky case XK_CMD: 564290650Shselasky for (fp = FuncNames; fp->name; fp++) 565290650Shselasky if (val->cmd == fp->func) 566290650Shselasky xprintf(fmt, fp->name); 567290650Shselasky break; 568290650Shselasky default: 569290650Shselasky abort(); 570290650Shselasky break; 571290650Shselasky } 572290650Shselasky else 573290650Shselasky xprintf(fmt, CGETS(9, 7, "no input")); 574290650Shselasky} 575290650Shselasky 576290650Shselaskystatic void 577290650Shselaskyunparsech(struct Strbuf *buf, Char ch) 578290650Shselasky{ 579290650Shselasky if (ch == 0) { 580290650Shselasky Strbuf_append1(buf, '^'); 581290650Shselasky Strbuf_append1(buf, '@'); 582290650Shselasky } 583290650Shselasky else if (Iscntrl(ch)) { 584290650Shselasky Strbuf_append1(buf, '^'); 585290650Shselasky if (ch == CTL_ESC('\177')) 586290650Shselasky Strbuf_append1(buf, '?'); 587290650Shselasky else 588290650Shselasky#ifdef IS_ASCII 589290650Shselasky Strbuf_append1(buf, ch | 0100); 590290650Shselasky#else 591290650Shselasky Strbuf_append1(buf, _toebcdic[_toascii[ch]|0100]); 592290650Shselasky#endif 593290650Shselasky } 594290650Shselasky else if (ch == '^') { 595290650Shselasky Strbuf_append1(buf, '\\'); 596290650Shselasky Strbuf_append1(buf, '^'); 597290650Shselasky } else if (ch == '\\') { 598290650Shselasky Strbuf_append1(buf, '\\'); 599290650Shselasky Strbuf_append1(buf, '\\'); 600290650Shselasky } else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) { 601290650Shselasky Strbuf_append1(buf, ch); 602290650Shselasky } 603290650Shselasky else { 604290650Shselasky Strbuf_append1(buf, '\\'); 605290650Shselasky Strbuf_append1(buf, ((ch >> 6) & 7) + '0'); 606290650Shselasky Strbuf_append1(buf, ((ch >> 3) & 7) + '0'); 607290650Shselasky Strbuf_append1(buf, (ch & 7) + '0'); 608290650Shselasky } 609290650Shselasky} 610290650Shselasky 611290650ShselaskyeChar 612290650Shselaskyparseescape(const Char **ptr) 613290650Shselasky{ 614290650Shselasky const Char *p; 615290650Shselasky Char c; 616290650Shselasky 617290650Shselasky p = *ptr; 618290650Shselasky 619290650Shselasky if ((p[1] & CHAR) == 0) { 620290650Shselasky xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p); 621290650Shselasky return CHAR_ERR; 622290650Shselasky } 623290650Shselasky if ((*p & CHAR) == '\\') { 624290650Shselasky p++; 625290650Shselasky switch (*p & CHAR) { 626290650Shselasky case 'a': 627290650Shselasky c = CTL_ESC('\007'); /* Bell */ 628290650Shselasky break; 629290650Shselasky case 'b': 630290650Shselasky c = CTL_ESC('\010'); /* Backspace */ 631290650Shselasky break; 632290650Shselasky case 'e': 633290650Shselasky c = CTL_ESC('\033'); /* Escape */ 634290650Shselasky break; 635290650Shselasky case 'f': 636290650Shselasky c = CTL_ESC('\014'); /* Form Feed */ 637290650Shselasky break; 638290650Shselasky case 'n': 639290650Shselasky c = CTL_ESC('\012'); /* New Line */ 640290650Shselasky break; 641290650Shselasky case 'r': 642290650Shselasky c = CTL_ESC('\015'); /* Carriage Return */ 643290650Shselasky break; 644290650Shselasky case 't': 645290650Shselasky c = CTL_ESC('\011'); /* Horizontal Tab */ 646290650Shselasky break; 647290650Shselasky case 'v': 648290650Shselasky c = CTL_ESC('\013'); /* Vertical Tab */ 649290650Shselasky break; 650290650Shselasky case '\\': 651290650Shselasky c = '\\'; 652290650Shselasky break; 653290650Shselasky case '0': 654290650Shselasky case '1': 655290650Shselasky case '2': 656290650Shselasky case '3': 657290650Shselasky case '4': 658290650Shselasky case '5': 659290650Shselasky case '6': 660290650Shselasky case '7': 661290650Shselasky { 662290650Shselasky int cnt, val; 663290650Shselasky Char ch; 664290650Shselasky 665290650Shselasky for (cnt = 0, val = 0; cnt < 3; cnt++) { 666290650Shselasky ch = *p++ & CHAR; 667290650Shselasky if (ch < '0' || ch > '7') { 668290650Shselasky p--; 669290650Shselasky break; 670290650Shselasky } 671290650Shselasky val = (val << 3) | (ch - '0'); 672290650Shselasky } 673290650Shselasky if ((val & ~0xff) != 0) { 674290650Shselasky xprintf("%s", CGETS(9, 9, 675290650Shselasky "Octal constant does not fit in a char.\n")); 676290650Shselasky return 0; 677290650Shselasky } 678290650Shselasky#ifndef IS_ASCII 679290650Shselasky if (CTL_ESC(val) != val && adrof(STRwarnebcdic)) 680290650Shselasky xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 681290650Shselasky "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/); 682290650Shselasky#endif 683290650Shselasky c = (Char) val; 684290650Shselasky --p; 685290650Shselasky } 686290650Shselasky break; 687290650Shselasky default: 688290650Shselasky c = *p; 689290650Shselasky break; 690290650Shselasky } 691290650Shselasky } 692290650Shselasky else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) || 693290650Shselasky strchr("@^_?\\|[{]}", p[1] & CHAR))) { 694290650Shselasky p++; 695290650Shselasky#ifdef IS_ASCII 696290650Shselasky c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237); 697290650Shselasky#else 698290650Shselasky c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237]; 699290650Shselasky if (adrof(STRwarnebcdic)) 700290650Shselasky xprintf(/*CGETS(9, 9, no NLS-String yet!*/ 701290650Shselasky "Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/); 702290650Shselasky#endif 703290650Shselasky } 704290650Shselasky else 705290650Shselasky c = *p; 706290650Shselasky *ptr = p; 707290650Shselasky return (c); 708290650Shselasky} 709290650Shselasky 710290650Shselasky 711290650Shselaskyunsigned char * 712290650Shselaskyunparsestring(const CStr *str, const Char *sep) 713290650Shselasky{ 714290650Shselasky unsigned char *buf, *b; 715290650Shselasky Char p; 716290650Shselasky int l; 717290650Shselasky 718290650Shselasky /* Worst-case is "\uuu" or result of wctomb() for each char from str */ 719290650Shselasky buf = xmalloc((str->len + 1) * max(4, MB_LEN_MAX)); 720290650Shselasky b = buf; 721290650Shselasky if (sep[0]) 722290650Shselasky#ifndef WINNT_NATIVE 723290650Shselasky *b++ = sep[0]; 724290650Shselasky#else /* WINNT_NATIVE */ 725290650Shselasky *b++ = CHAR & sep[0]; 726290650Shselasky#endif /* !WINNT_NATIVE */ 727290650Shselasky 728290650Shselasky for (l = 0; l < str->len; l++) { 729290650Shselasky p = str->buf[l]; 730290650Shselasky if (Iscntrl(p)) { 731290650Shselasky *b++ = '^'; 732290650Shselasky if (p == CTL_ESC('\177')) 733290650Shselasky *b++ = '?'; 734290650Shselasky else 735290650Shselasky#ifdef IS_ASCII 736290650Shselasky *b++ = (unsigned char) (p | 0100); 737290650Shselasky#else 738290650Shselasky *b++ = _toebcdic[_toascii[p]|0100]; 739290650Shselasky#endif 740290650Shselasky } 741290650Shselasky else if (p == '^' || p == '\\') { 742290650Shselasky *b++ = '\\'; 743290650Shselasky *b++ = (unsigned char) p; 744290650Shselasky } 745290650Shselasky else if (p == ' ' || (Isprint(p) && !Isspace(p))) 746290650Shselasky b += one_wctomb((char *)b, p & CHAR); 747290650Shselasky else { 748290650Shselasky *b++ = '\\'; 749290650Shselasky *b++ = ((p >> 6) & 7) + '0'; 750290650Shselasky *b++ = ((p >> 3) & 7) + '0'; 751290650Shselasky *b++ = (p & 7) + '0'; 752290650Shselasky } 753290650Shselasky } 754290650Shselasky if (sep[0] && sep[1]) 755290650Shselasky#ifndef WINNT_NATIVE 756290650Shselasky *b++ = sep[1]; 757290650Shselasky#else /* WINNT_NATIVE */ 758290650Shselasky *b++ = CHAR & sep[1]; 759290650Shselasky#endif /* !WINNT_NATIVE */ 760290650Shselasky *b++ = 0; 761290650Shselasky return buf; /* should check for overflow */ 762290650Shselasky} 763290650Shselasky