xref: /dflybsd-src/contrib/tcsh-6/ed.xmap.c (revision 84d884bf08edef6c02f15218458cd5df8010b654)
17d8fb588SMatthias Schmidt /*
27d8fb588SMatthias Schmidt  * ed.xmap.c: This module contains the procedures for maintaining
37d8fb588SMatthias Schmidt  *	      the extended-key map.
47d8fb588SMatthias Schmidt  *
57d8fb588SMatthias Schmidt  * 	      An extended-key (Xkey) is a sequence of keystrokes
67d8fb588SMatthias Schmidt  *	      introduced with an sequence introducer and consisting
77d8fb588SMatthias Schmidt  *	      of an arbitrary number of characters.  This module maintains
87d8fb588SMatthias Schmidt  *	      a map (the Xmap) to convert these extended-key sequences
97d8fb588SMatthias Schmidt  * 	      into input strings (XK_STR), editor functions (XK_CMD), or
107d8fb588SMatthias Schmidt  *	      unix commands (XK_EXE). It contains the
117d8fb588SMatthias Schmidt  *	      following externally visible functions.
127d8fb588SMatthias Schmidt  *
137d8fb588SMatthias Schmidt  *		int GetXkey(ch,val);
147d8fb588SMatthias Schmidt  *		CStr *ch;
157d8fb588SMatthias Schmidt  *		XmapVal *val;
167d8fb588SMatthias Schmidt  *
177d8fb588SMatthias Schmidt  *	      Looks up *ch in map and then reads characters until a
187d8fb588SMatthias Schmidt  *	      complete match is found or a mismatch occurs. Returns the
197d8fb588SMatthias Schmidt  *	      type of the match found (XK_STR, XK_CMD, or XK_EXE).
207d8fb588SMatthias Schmidt  *	      Returns NULL in val.str and XK_STR for no match.
217d8fb588SMatthias Schmidt  *	      The last character read is returned in *ch.
227d8fb588SMatthias Schmidt  *
237d8fb588SMatthias Schmidt  *		void AddXkey(Xkey, val, ntype);
247d8fb588SMatthias Schmidt  *		CStr *Xkey;
257d8fb588SMatthias Schmidt  *		XmapVal *val;
267d8fb588SMatthias Schmidt  *		int ntype;
277d8fb588SMatthias Schmidt  *
287d8fb588SMatthias Schmidt  *	      Adds Xkey to the Xmap and associates the value in val with it.
297d8fb588SMatthias Schmidt  *	      If Xkey is already is in Xmap, the new code is applied to the
307d8fb588SMatthias Schmidt  *	      existing Xkey. Ntype specifies if code is a command, an
317d8fb588SMatthias Schmidt  *	      out string or a unix command.
327d8fb588SMatthias Schmidt  *
337d8fb588SMatthias Schmidt  *	        int DeleteXkey(Xkey);
347d8fb588SMatthias Schmidt  *	        CStr *Xkey;
357d8fb588SMatthias Schmidt  *
367d8fb588SMatthias Schmidt  *	      Delete the Xkey and all longer Xkeys staring with Xkey, if
377d8fb588SMatthias Schmidt  *	      they exists.
387d8fb588SMatthias Schmidt  *
397d8fb588SMatthias Schmidt  *	      Warning:
407d8fb588SMatthias Schmidt  *		If Xkey is a substring of some other Xkeys, then the longer
417d8fb588SMatthias Schmidt  *		Xkeys are lost!!  That is, if the Xkeys "abcd" and "abcef"
427d8fb588SMatthias Schmidt  *		are in Xmap, adding the key "abc" will cause the first two
437d8fb588SMatthias Schmidt  *		definitions to be lost.
447d8fb588SMatthias Schmidt  *
457d8fb588SMatthias Schmidt  *		void ResetXmap();
467d8fb588SMatthias Schmidt  *
477d8fb588SMatthias Schmidt  *	      Removes all entries from Xmap and resets the defaults.
487d8fb588SMatthias Schmidt  *
497d8fb588SMatthias Schmidt  *		void PrintXkey(Xkey);
507d8fb588SMatthias Schmidt  *		CStr *Xkey;
517d8fb588SMatthias Schmidt  *
527d8fb588SMatthias Schmidt  *	      Prints all extended keys prefixed by Xkey and their associated
537d8fb588SMatthias Schmidt  *	      commands.
547d8fb588SMatthias Schmidt  *
557d8fb588SMatthias Schmidt  *	      Restrictions:
567d8fb588SMatthias Schmidt  *	      -------------
577d8fb588SMatthias Schmidt  *	        1) It is not possible to have one Xkey that is a
587d8fb588SMatthias Schmidt  *		   substring of another.
597d8fb588SMatthias Schmidt  */
607d8fb588SMatthias Schmidt /*-
617d8fb588SMatthias Schmidt  * Copyright (c) 1980, 1991 The Regents of the University of California.
627d8fb588SMatthias Schmidt  * All rights reserved.
637d8fb588SMatthias Schmidt  *
647d8fb588SMatthias Schmidt  * Redistribution and use in source and binary forms, with or without
657d8fb588SMatthias Schmidt  * modification, are permitted provided that the following conditions
667d8fb588SMatthias Schmidt  * are met:
677d8fb588SMatthias Schmidt  * 1. Redistributions of source code must retain the above copyright
687d8fb588SMatthias Schmidt  *    notice, this list of conditions and the following disclaimer.
697d8fb588SMatthias Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
707d8fb588SMatthias Schmidt  *    notice, this list of conditions and the following disclaimer in the
717d8fb588SMatthias Schmidt  *    documentation and/or other materials provided with the distribution.
727d8fb588SMatthias Schmidt  * 3. Neither the name of the University nor the names of its contributors
737d8fb588SMatthias Schmidt  *    may be used to endorse or promote products derived from this software
747d8fb588SMatthias Schmidt  *    without specific prior written permission.
757d8fb588SMatthias Schmidt  *
767d8fb588SMatthias Schmidt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
777d8fb588SMatthias Schmidt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
787d8fb588SMatthias Schmidt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
797d8fb588SMatthias Schmidt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
807d8fb588SMatthias Schmidt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
817d8fb588SMatthias Schmidt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
827d8fb588SMatthias Schmidt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
837d8fb588SMatthias Schmidt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
847d8fb588SMatthias Schmidt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
857d8fb588SMatthias Schmidt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
867d8fb588SMatthias Schmidt  * SUCH DAMAGE.
877d8fb588SMatthias Schmidt  */
887d8fb588SMatthias Schmidt #include "sh.h"
897d8fb588SMatthias Schmidt #include "ed.h"
907d8fb588SMatthias Schmidt #include "ed.defns.h"
917d8fb588SMatthias Schmidt 
927d8fb588SMatthias Schmidt #ifndef NULL
937d8fb588SMatthias Schmidt #define NULL 0
947d8fb588SMatthias Schmidt #endif
957d8fb588SMatthias Schmidt 
967d8fb588SMatthias Schmidt /* Internal Data types and declarations */
977d8fb588SMatthias Schmidt 
987d8fb588SMatthias Schmidt /* The Nodes of the Xmap.  The Xmap is a linked list of these node
997d8fb588SMatthias Schmidt  * elements
1007d8fb588SMatthias Schmidt  */
1017d8fb588SMatthias Schmidt typedef struct Xmapnode {
1027d8fb588SMatthias Schmidt     Char    ch;			/* single character of Xkey */
1037d8fb588SMatthias Schmidt     int     type;
1047d8fb588SMatthias Schmidt     XmapVal val; 		/* command code or pointer to string, if this
1057d8fb588SMatthias Schmidt 				 * is a leaf */
1067d8fb588SMatthias Schmidt     struct Xmapnode *next;	/* ptr to next char of this Xkey */
1077d8fb588SMatthias Schmidt     struct Xmapnode *sibling;	/* ptr to another Xkey with same prefix */
1087d8fb588SMatthias Schmidt } XmapNode;
1097d8fb588SMatthias Schmidt 
1107d8fb588SMatthias Schmidt static XmapNode *Xmap = NULL;	/* the current Xmap */
1117d8fb588SMatthias Schmidt 
1127d8fb588SMatthias Schmidt 
1137d8fb588SMatthias Schmidt /* Some declarations of procedures */
1147d8fb588SMatthias Schmidt static	int       TraverseMap	(XmapNode *, CStr *, XmapVal *);
1157d8fb588SMatthias Schmidt static	int       TryNode	(XmapNode *, CStr *, XmapVal *, int);
1167d8fb588SMatthias Schmidt static	XmapNode *GetFreeNode	(CStr *);
1177d8fb588SMatthias Schmidt static	void	  PutFreeNode	(XmapNode *);
1187d8fb588SMatthias Schmidt static	int	  TryDeleteNode	(XmapNode **, CStr *);
1197d8fb588SMatthias Schmidt static	int	  Lookup	(struct Strbuf *, const CStr *,
1207d8fb588SMatthias Schmidt 				 const XmapNode *);
1217d8fb588SMatthias Schmidt static	void	  Enumerate	(struct Strbuf *, const XmapNode *);
1227d8fb588SMatthias Schmidt static	void	  unparsech	(struct Strbuf *, Char);
1237d8fb588SMatthias Schmidt 
1247d8fb588SMatthias Schmidt 
1257d8fb588SMatthias Schmidt XmapVal *
XmapCmd(int cmd)1267d8fb588SMatthias Schmidt XmapCmd(int cmd)
1277d8fb588SMatthias Schmidt {
1287d8fb588SMatthias Schmidt     static XmapVal xm;
1297d8fb588SMatthias Schmidt     xm.cmd = (KEYCMD) cmd;
1307d8fb588SMatthias Schmidt     return &xm;
1317d8fb588SMatthias Schmidt }
1327d8fb588SMatthias Schmidt 
1337d8fb588SMatthias Schmidt XmapVal *
XmapStr(CStr * str)1347d8fb588SMatthias Schmidt XmapStr(CStr *str)
1357d8fb588SMatthias Schmidt {
1367d8fb588SMatthias Schmidt     static XmapVal xm;
1377d8fb588SMatthias Schmidt     xm.str.len = str->len;
1387d8fb588SMatthias Schmidt     xm.str.buf = str->buf;
1397d8fb588SMatthias Schmidt     return &xm;
1407d8fb588SMatthias Schmidt }
1417d8fb588SMatthias Schmidt 
1427d8fb588SMatthias Schmidt /* ResetXmap():
1437d8fb588SMatthias Schmidt  *	Takes all nodes on Xmap and puts them on free list.  Then
1447d8fb588SMatthias Schmidt  *	initializes Xmap with arrow keys
1457d8fb588SMatthias Schmidt  */
1467d8fb588SMatthias Schmidt void
ResetXmap(void)1477d8fb588SMatthias Schmidt ResetXmap(void)
1487d8fb588SMatthias Schmidt {
1497d8fb588SMatthias Schmidt     PutFreeNode(Xmap);
1507d8fb588SMatthias Schmidt     Xmap = NULL;
1517d8fb588SMatthias Schmidt 
1527d8fb588SMatthias Schmidt     DefaultArrowKeys();
1537d8fb588SMatthias Schmidt     return;
1547d8fb588SMatthias Schmidt }
1557d8fb588SMatthias Schmidt 
1567d8fb588SMatthias Schmidt 
1577d8fb588SMatthias Schmidt /* GetXkey():
1587d8fb588SMatthias Schmidt  *	Calls the recursive function with entry point Xmap
1597d8fb588SMatthias Schmidt  */
1607d8fb588SMatthias Schmidt int
GetXkey(CStr * ch,XmapVal * val)1617d8fb588SMatthias Schmidt GetXkey(CStr *ch, XmapVal *val)
1627d8fb588SMatthias Schmidt {
1637d8fb588SMatthias Schmidt     return (TraverseMap(Xmap, ch, val));
1647d8fb588SMatthias Schmidt }
1657d8fb588SMatthias Schmidt 
1667d8fb588SMatthias Schmidt /* TraverseMap():
1677d8fb588SMatthias Schmidt  *	recursively traverses node in tree until match or mismatch is
1687d8fb588SMatthias Schmidt  * 	found.  May read in more characters.
1697d8fb588SMatthias Schmidt  */
1707d8fb588SMatthias Schmidt static int
TraverseMap(XmapNode * ptr,CStr * ch,XmapVal * val)1717d8fb588SMatthias Schmidt TraverseMap(XmapNode *ptr, CStr *ch, XmapVal *val)
1727d8fb588SMatthias Schmidt {
1737d8fb588SMatthias Schmidt     Char    tch;
1747d8fb588SMatthias Schmidt 
1757d8fb588SMatthias Schmidt     if (ptr->ch == *(ch->buf)) {
1767d8fb588SMatthias Schmidt 	/* match found */
1777d8fb588SMatthias Schmidt 	if (ptr->next) {
1787d8fb588SMatthias Schmidt 	    /* Xkey not complete so get next char */
1797d8fb588SMatthias Schmidt 	    if (GetNextChar(&tch) != 1) {	/* if EOF or error */
1807d8fb588SMatthias Schmidt 		val->cmd = F_SEND_EOF;
1817d8fb588SMatthias Schmidt 		return XK_CMD;/* PWP: Pretend we just read an end-of-file */
1827d8fb588SMatthias Schmidt 	    }
1837d8fb588SMatthias Schmidt 	    *(ch->buf) = tch;
1847d8fb588SMatthias Schmidt 	    return (TraverseMap(ptr->next, ch, val));
1857d8fb588SMatthias Schmidt 	}
1867d8fb588SMatthias Schmidt 	else {
1877d8fb588SMatthias Schmidt 	    *val = ptr->val;
1887d8fb588SMatthias Schmidt 	    if (ptr->type != XK_CMD)
1897d8fb588SMatthias Schmidt 		*(ch->buf) = '\0';
1907d8fb588SMatthias Schmidt 	    return ptr->type;
1917d8fb588SMatthias Schmidt 	}
1927d8fb588SMatthias Schmidt     }
1937d8fb588SMatthias Schmidt     else {
1947d8fb588SMatthias Schmidt 	/* no match found here */
1957d8fb588SMatthias Schmidt 	if (ptr->sibling) {
1967d8fb588SMatthias Schmidt 	    /* try next sibling */
1977d8fb588SMatthias Schmidt 	    return (TraverseMap(ptr->sibling, ch, val));
1987d8fb588SMatthias Schmidt 	}
1997d8fb588SMatthias Schmidt 	else {
2007d8fb588SMatthias Schmidt 	    /* no next sibling -- mismatch */
2017d8fb588SMatthias Schmidt 	    val->str.buf = NULL;
2027d8fb588SMatthias Schmidt 	    val->str.len = 0;
2037d8fb588SMatthias Schmidt 	    return XK_STR;
2047d8fb588SMatthias Schmidt 	}
2057d8fb588SMatthias Schmidt     }
2067d8fb588SMatthias Schmidt }
2077d8fb588SMatthias Schmidt 
2087d8fb588SMatthias Schmidt void
AddXkey(const CStr * Xkey,XmapVal * val,int ntype)2097d8fb588SMatthias Schmidt AddXkey(const CStr *Xkey, XmapVal *val, int ntype)
2107d8fb588SMatthias Schmidt {
2117d8fb588SMatthias Schmidt     CStr cs;
2127d8fb588SMatthias Schmidt     cs.buf = Xkey->buf;
2137d8fb588SMatthias Schmidt     cs.len = Xkey->len;
2147d8fb588SMatthias Schmidt     if (Xkey->len == 0) {
21557e3f2b5SSimon 'corecode' Schubert 	xprintf("%s", CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n"));
2167d8fb588SMatthias Schmidt 	return;
2177d8fb588SMatthias Schmidt     }
2187d8fb588SMatthias Schmidt 
2197d8fb588SMatthias Schmidt     if (ntype == XK_CMD && val->cmd == F_XKEY) {
22057e3f2b5SSimon 'corecode' Schubert 	xprintf("%s",
22157e3f2b5SSimon 'corecode' Schubert 	    CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n"));
2227d8fb588SMatthias Schmidt 	return;
2237d8fb588SMatthias Schmidt     }
2247d8fb588SMatthias Schmidt 
2257d8fb588SMatthias Schmidt     if (Xmap == NULL)
2267d8fb588SMatthias Schmidt 	/* tree is initially empty.  Set up new node to match Xkey[0] */
2277d8fb588SMatthias Schmidt 	Xmap = GetFreeNode(&cs);	/* it is properly initialized */
2287d8fb588SMatthias Schmidt 
2297d8fb588SMatthias Schmidt     /* Now recurse through Xmap */
2307d8fb588SMatthias Schmidt     (void) TryNode(Xmap, &cs, val, ntype);
2317d8fb588SMatthias Schmidt     return;
2327d8fb588SMatthias Schmidt }
2337d8fb588SMatthias Schmidt 
2347d8fb588SMatthias Schmidt static int
TryNode(XmapNode * ptr,CStr * str,XmapVal * val,int ntype)2357d8fb588SMatthias Schmidt TryNode(XmapNode *ptr, CStr *str, XmapVal *val, int ntype)
2367d8fb588SMatthias Schmidt {
2377d8fb588SMatthias Schmidt     /*
2387d8fb588SMatthias Schmidt      * Find a node that matches *string or allocate a new one
2397d8fb588SMatthias Schmidt      */
2407d8fb588SMatthias Schmidt     if (ptr->ch != *(str->buf)) {
2417d8fb588SMatthias Schmidt 	XmapNode *xm;
2427d8fb588SMatthias Schmidt 
2437d8fb588SMatthias Schmidt 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
2447d8fb588SMatthias Schmidt 	    if (xm->sibling->ch == *(str->buf))
2457d8fb588SMatthias Schmidt 		break;
2467d8fb588SMatthias Schmidt 	if (xm->sibling == NULL)
2477d8fb588SMatthias Schmidt 	    xm->sibling = GetFreeNode(str);	/* setup new node */
2487d8fb588SMatthias Schmidt 	ptr = xm->sibling;
2497d8fb588SMatthias Schmidt     }
2507d8fb588SMatthias Schmidt 
2517d8fb588SMatthias Schmidt     str->buf++;
2527d8fb588SMatthias Schmidt     str->len--;
2537d8fb588SMatthias Schmidt     if (str->len == 0) {
2547d8fb588SMatthias Schmidt 	size_t len;
2557d8fb588SMatthias Schmidt 
2567d8fb588SMatthias Schmidt 	/* we're there */
2577d8fb588SMatthias Schmidt 	if (ptr->next != NULL) {
2587d8fb588SMatthias Schmidt 	    PutFreeNode(ptr->next);	/* lose longer Xkeys with this prefix */
2597d8fb588SMatthias Schmidt 	    ptr->next = NULL;
2607d8fb588SMatthias Schmidt 	}
2617d8fb588SMatthias Schmidt 
2627d8fb588SMatthias Schmidt 	switch (ptr->type) {
2637d8fb588SMatthias Schmidt 	case XK_STR:
2647d8fb588SMatthias Schmidt 	case XK_EXE:
2657d8fb588SMatthias Schmidt 	    xfree(ptr->val.str.buf);
2667d8fb588SMatthias Schmidt 	    ptr->val.str.len = 0;
2677d8fb588SMatthias Schmidt 	    break;
2687d8fb588SMatthias Schmidt 	case XK_NOD:
2697d8fb588SMatthias Schmidt 	case XK_CMD:
2707d8fb588SMatthias Schmidt 	    break;
2717d8fb588SMatthias Schmidt 	default:
2727d8fb588SMatthias Schmidt 	    abort();
2737d8fb588SMatthias Schmidt 	    break;
2747d8fb588SMatthias Schmidt 	}
2757d8fb588SMatthias Schmidt 
2767d8fb588SMatthias Schmidt 	switch (ptr->type = ntype) {
2777d8fb588SMatthias Schmidt 	case XK_CMD:
2787d8fb588SMatthias Schmidt 	    ptr->val = *val;
2797d8fb588SMatthias Schmidt 	    break;
2807d8fb588SMatthias Schmidt 	case XK_STR:
2817d8fb588SMatthias Schmidt 	case XK_EXE:
2827d8fb588SMatthias Schmidt 	    ptr->val.str.len = val->str.len;
2837d8fb588SMatthias Schmidt 	    len = (val->str.len + 1) * sizeof(*ptr->val.str.buf);
2847d8fb588SMatthias Schmidt 	    ptr->val.str.buf = xmalloc(len);
2857d8fb588SMatthias Schmidt 	    (void) memcpy(ptr->val.str.buf, val->str.buf, len);
2867d8fb588SMatthias Schmidt 	    break;
2877d8fb588SMatthias Schmidt 	default:
2887d8fb588SMatthias Schmidt 	    abort();
2897d8fb588SMatthias Schmidt 	    break;
2907d8fb588SMatthias Schmidt 	}
2917d8fb588SMatthias Schmidt     }
2927d8fb588SMatthias Schmidt     else {
2937d8fb588SMatthias Schmidt 	/* still more chars to go */
2947d8fb588SMatthias Schmidt 	if (ptr->next == NULL)
2957d8fb588SMatthias Schmidt 	    ptr->next = GetFreeNode(str);	/* setup new node */
2967d8fb588SMatthias Schmidt 	(void) TryNode(ptr->next, str, val, ntype);
2977d8fb588SMatthias Schmidt     }
2987d8fb588SMatthias Schmidt     return (0);
2997d8fb588SMatthias Schmidt }
3007d8fb588SMatthias Schmidt 
3017d8fb588SMatthias Schmidt void
ClearXkey(KEYCMD * map,const CStr * in)3027d8fb588SMatthias Schmidt ClearXkey(KEYCMD *map, const CStr *in)
3037d8fb588SMatthias Schmidt {
3047d8fb588SMatthias Schmidt     unsigned char c = (unsigned char) *(in->buf);
3057d8fb588SMatthias Schmidt     if ((map[c] == F_XKEY) &&
3067d8fb588SMatthias Schmidt 	((map == CcKeyMap && CcAltMap[c] != F_XKEY) ||
3077d8fb588SMatthias Schmidt 	 (map == CcAltMap && CcKeyMap[c] != F_XKEY)))
3087d8fb588SMatthias Schmidt 	(void) DeleteXkey(in);
3097d8fb588SMatthias Schmidt }
3107d8fb588SMatthias Schmidt 
3117d8fb588SMatthias Schmidt int
DeleteXkey(const CStr * Xkey)3127d8fb588SMatthias Schmidt DeleteXkey(const CStr *Xkey)
3137d8fb588SMatthias Schmidt {
3147d8fb588SMatthias Schmidt     CStr s;
3157d8fb588SMatthias Schmidt 
3167d8fb588SMatthias Schmidt     s = *Xkey;
3177d8fb588SMatthias Schmidt     if (s.len == 0) {
31857e3f2b5SSimon 'corecode' Schubert 	xprintf("%s",
31957e3f2b5SSimon 'corecode' Schubert 	        CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n"));
3207d8fb588SMatthias Schmidt 	return (-1);
3217d8fb588SMatthias Schmidt     }
3227d8fb588SMatthias Schmidt 
3237d8fb588SMatthias Schmidt     if (Xmap == NULL)
3247d8fb588SMatthias Schmidt 	return (0);
3257d8fb588SMatthias Schmidt 
3267d8fb588SMatthias Schmidt     (void) TryDeleteNode(&Xmap, &s);
3277d8fb588SMatthias Schmidt     return (0);
3287d8fb588SMatthias Schmidt }
3297d8fb588SMatthias Schmidt 
3307d8fb588SMatthias Schmidt /* Destroys str */
3317d8fb588SMatthias Schmidt static int
TryDeleteNode(XmapNode ** inptr,CStr * str)3327d8fb588SMatthias Schmidt TryDeleteNode(XmapNode **inptr, CStr *str)
3337d8fb588SMatthias Schmidt {
3347d8fb588SMatthias Schmidt     XmapNode *ptr;
3357d8fb588SMatthias Schmidt 
3367d8fb588SMatthias Schmidt     ptr = *inptr;
3377d8fb588SMatthias Schmidt     /*
3387d8fb588SMatthias Schmidt      * Find a node that matches *string or allocate a new one
3397d8fb588SMatthias Schmidt      */
3407d8fb588SMatthias Schmidt     if (ptr->ch != *(str->buf)) {
3417d8fb588SMatthias Schmidt 	XmapNode *xm;
3427d8fb588SMatthias Schmidt 
3437d8fb588SMatthias Schmidt 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
3447d8fb588SMatthias Schmidt 	    if (xm->sibling->ch == *(str->buf))
3457d8fb588SMatthias Schmidt 		break;
3467d8fb588SMatthias Schmidt 	if (xm->sibling == NULL)
3477d8fb588SMatthias Schmidt 	    return (0);
3487d8fb588SMatthias Schmidt 	inptr = &xm->sibling;
3497d8fb588SMatthias Schmidt 	ptr = xm->sibling;
3507d8fb588SMatthias Schmidt     }
3517d8fb588SMatthias Schmidt 
3527d8fb588SMatthias Schmidt     str->buf++;
3537d8fb588SMatthias Schmidt     str->len--;
3547d8fb588SMatthias Schmidt 
3557d8fb588SMatthias Schmidt     if (str->len == 0) {
3567d8fb588SMatthias Schmidt 	/* we're there */
3577d8fb588SMatthias Schmidt 	*inptr = ptr->sibling;
3587d8fb588SMatthias Schmidt 	ptr->sibling = NULL;
3597d8fb588SMatthias Schmidt 	PutFreeNode(ptr);
3607d8fb588SMatthias Schmidt 	return (1);
3617d8fb588SMatthias Schmidt     }
3627d8fb588SMatthias Schmidt     else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) {
3637d8fb588SMatthias Schmidt 	if (ptr->next != NULL)
3647d8fb588SMatthias Schmidt 	    return (0);
3657d8fb588SMatthias Schmidt 	*inptr = ptr->sibling;
3667d8fb588SMatthias Schmidt 	ptr->sibling = NULL;
3677d8fb588SMatthias Schmidt 	PutFreeNode(ptr);
3687d8fb588SMatthias Schmidt 	return (1);
3697d8fb588SMatthias Schmidt     }
3707d8fb588SMatthias Schmidt     else {
3717d8fb588SMatthias Schmidt 	return (0);
3727d8fb588SMatthias Schmidt     }
3737d8fb588SMatthias Schmidt }
3747d8fb588SMatthias Schmidt 
3757d8fb588SMatthias Schmidt /* PutFreeNode():
3767d8fb588SMatthias Schmidt  *	Puts a tree of nodes onto free list using free(3).
3777d8fb588SMatthias Schmidt  */
3787d8fb588SMatthias Schmidt static void
PutFreeNode(XmapNode * ptr)3797d8fb588SMatthias Schmidt PutFreeNode(XmapNode *ptr)
3807d8fb588SMatthias Schmidt {
3817d8fb588SMatthias Schmidt     if (ptr == NULL)
3827d8fb588SMatthias Schmidt 	return;
3837d8fb588SMatthias Schmidt 
3847d8fb588SMatthias Schmidt     if (ptr->next != NULL) {
3857d8fb588SMatthias Schmidt 	PutFreeNode(ptr->next);
3867d8fb588SMatthias Schmidt 	ptr->next = NULL;
3877d8fb588SMatthias Schmidt     }
3887d8fb588SMatthias Schmidt 
3897d8fb588SMatthias Schmidt     PutFreeNode(ptr->sibling);
3907d8fb588SMatthias Schmidt 
3917d8fb588SMatthias Schmidt     switch (ptr->type) {
3927d8fb588SMatthias Schmidt     case XK_CMD:
3937d8fb588SMatthias Schmidt     case XK_NOD:
3947d8fb588SMatthias Schmidt 	break;
3957d8fb588SMatthias Schmidt     case XK_EXE:
3967d8fb588SMatthias Schmidt     case XK_STR:
3977d8fb588SMatthias Schmidt 	xfree(ptr->val.str.buf);
3987d8fb588SMatthias Schmidt 	break;
3997d8fb588SMatthias Schmidt     default:
4007d8fb588SMatthias Schmidt 	abort();
4017d8fb588SMatthias Schmidt 	break;
4027d8fb588SMatthias Schmidt     }
4037d8fb588SMatthias Schmidt     xfree(ptr);
4047d8fb588SMatthias Schmidt }
4057d8fb588SMatthias Schmidt 
4067d8fb588SMatthias Schmidt 
4077d8fb588SMatthias Schmidt /* GetFreeNode():
4087d8fb588SMatthias Schmidt  *	Returns pointer to an XmapNode for ch.
4097d8fb588SMatthias Schmidt  */
4107d8fb588SMatthias Schmidt static XmapNode *
GetFreeNode(CStr * ch)4117d8fb588SMatthias Schmidt GetFreeNode(CStr *ch)
4127d8fb588SMatthias Schmidt {
4137d8fb588SMatthias Schmidt     XmapNode *ptr;
4147d8fb588SMatthias Schmidt 
4157d8fb588SMatthias Schmidt     ptr = xmalloc(sizeof(XmapNode));
4167d8fb588SMatthias Schmidt     ptr->ch = ch->buf[0];
4177d8fb588SMatthias Schmidt     ptr->type = XK_NOD;
4187d8fb588SMatthias Schmidt     ptr->val.str.buf = NULL;
4197d8fb588SMatthias Schmidt     ptr->val.str.len = 0;
4207d8fb588SMatthias Schmidt     ptr->next = NULL;
4217d8fb588SMatthias Schmidt     ptr->sibling = NULL;
4227d8fb588SMatthias Schmidt     return (ptr);
4237d8fb588SMatthias Schmidt }
4247d8fb588SMatthias Schmidt 
4257d8fb588SMatthias Schmidt 
4267d8fb588SMatthias Schmidt /* PrintXKey():
4277d8fb588SMatthias Schmidt  *	Print the binding associated with Xkey key.
4287d8fb588SMatthias Schmidt  *	Print entire Xmap if null
4297d8fb588SMatthias Schmidt  */
4307d8fb588SMatthias Schmidt void
PrintXkey(const CStr * key)4317d8fb588SMatthias Schmidt PrintXkey(const CStr *key)
4327d8fb588SMatthias Schmidt {
4337d8fb588SMatthias Schmidt     struct Strbuf buf = Strbuf_INIT;
4347d8fb588SMatthias Schmidt     CStr cs;
4357d8fb588SMatthias Schmidt 
4367d8fb588SMatthias Schmidt     if (key) {
4377d8fb588SMatthias Schmidt 	cs.buf = key->buf;
4387d8fb588SMatthias Schmidt 	cs.len = key->len;
4397d8fb588SMatthias Schmidt     }
4407d8fb588SMatthias Schmidt     else {
4417d8fb588SMatthias Schmidt 	cs.buf = STRNULL;
4427d8fb588SMatthias Schmidt 	cs.len = 0;
4437d8fb588SMatthias Schmidt     }
4447d8fb588SMatthias Schmidt     /* do nothing if Xmap is empty and null key specified */
4457d8fb588SMatthias Schmidt     if (Xmap == NULL && cs.len == 0)
4467d8fb588SMatthias Schmidt 	return;
4477d8fb588SMatthias Schmidt 
4487d8fb588SMatthias Schmidt     Strbuf_append1(&buf, '"');
4497d8fb588SMatthias Schmidt     cleanup_push(&buf, Strbuf_cleanup);
4507d8fb588SMatthias Schmidt     if (Lookup(&buf, &cs, Xmap) <= -1)
4517d8fb588SMatthias Schmidt 	/* key is not bound */
4527d8fb588SMatthias Schmidt 	xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf);
4537d8fb588SMatthias Schmidt     cleanup_until(&buf);
4547d8fb588SMatthias Schmidt }
4557d8fb588SMatthias Schmidt 
4567d8fb588SMatthias Schmidt /* Lookup():
4577d8fb588SMatthias Schmidt  *	look for the string starting at node ptr.
4587d8fb588SMatthias Schmidt  *	Print if last node
4597d8fb588SMatthias Schmidt  */
4607d8fb588SMatthias Schmidt static int
Lookup(struct Strbuf * buf,const CStr * str,const XmapNode * ptr)4617d8fb588SMatthias Schmidt Lookup(struct Strbuf *buf, const CStr *str, const XmapNode *ptr)
4627d8fb588SMatthias Schmidt {
4637d8fb588SMatthias Schmidt     if (ptr == NULL)
4647d8fb588SMatthias Schmidt 	return (-1);		/* cannot have null ptr */
4657d8fb588SMatthias Schmidt 
4667d8fb588SMatthias Schmidt     if (str->len == 0) {
4677d8fb588SMatthias Schmidt 	/* no more chars in string.  Enumerate from here. */
4687d8fb588SMatthias Schmidt 	Enumerate(buf, ptr);
4697d8fb588SMatthias Schmidt 	return (0);
4707d8fb588SMatthias Schmidt     }
4717d8fb588SMatthias Schmidt     else {
4727d8fb588SMatthias Schmidt 	/* If match put this char into buf.  Recurse */
4737d8fb588SMatthias Schmidt 	if (ptr->ch == *(str->buf)) {
4747d8fb588SMatthias Schmidt 	    /* match found */
4757d8fb588SMatthias Schmidt 	    unparsech(buf, ptr->ch);
4767d8fb588SMatthias Schmidt 	    if (ptr->next != NULL) {
4777d8fb588SMatthias Schmidt 		/* not yet at leaf */
4787d8fb588SMatthias Schmidt 		CStr tstr;
4797d8fb588SMatthias Schmidt 		tstr.buf = str->buf + 1;
4807d8fb588SMatthias Schmidt 		tstr.len = str->len - 1;
4817d8fb588SMatthias Schmidt 		return (Lookup(buf, &tstr, ptr->next));
4827d8fb588SMatthias Schmidt 	    }
4837d8fb588SMatthias Schmidt 	    else {
4847d8fb588SMatthias Schmidt 		/* next node is null so key should be complete */
4857d8fb588SMatthias Schmidt 		if (str->len == 1) {
4867d8fb588SMatthias Schmidt 		    Strbuf_append1(buf, '"');
4877d8fb588SMatthias Schmidt 		    Strbuf_terminate(buf);
4887d8fb588SMatthias Schmidt 		    printOne(buf->s, &ptr->val, ptr->type);
4897d8fb588SMatthias Schmidt 		    return (0);
4907d8fb588SMatthias Schmidt 		}
4917d8fb588SMatthias Schmidt 		else
4927d8fb588SMatthias Schmidt 		    return (-1);/* mismatch -- string still has chars */
4937d8fb588SMatthias Schmidt 	    }
4947d8fb588SMatthias Schmidt 	}
4957d8fb588SMatthias Schmidt 	else {
4967d8fb588SMatthias Schmidt 	    /* no match found try sibling */
4977d8fb588SMatthias Schmidt 	    if (ptr->sibling)
4987d8fb588SMatthias Schmidt 		return (Lookup(buf, str, ptr->sibling));
4997d8fb588SMatthias Schmidt 	    else
5007d8fb588SMatthias Schmidt 		return (-1);
5017d8fb588SMatthias Schmidt 	}
5027d8fb588SMatthias Schmidt     }
5037d8fb588SMatthias Schmidt }
5047d8fb588SMatthias Schmidt 
5057d8fb588SMatthias Schmidt static void
Enumerate(struct Strbuf * buf,const XmapNode * ptr)5067d8fb588SMatthias Schmidt Enumerate(struct Strbuf *buf, const XmapNode *ptr)
5077d8fb588SMatthias Schmidt {
5087d8fb588SMatthias Schmidt     size_t old_len;
5097d8fb588SMatthias Schmidt 
5107d8fb588SMatthias Schmidt     if (ptr == NULL) {
5117d8fb588SMatthias Schmidt #ifdef DEBUG_EDIT
5127d8fb588SMatthias Schmidt 	xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!"));
5137d8fb588SMatthias Schmidt #endif
5147d8fb588SMatthias Schmidt 	return;
5157d8fb588SMatthias Schmidt     }
5167d8fb588SMatthias Schmidt 
5177d8fb588SMatthias Schmidt     old_len = buf->len;
5187d8fb588SMatthias Schmidt     unparsech(buf, ptr->ch); /* put this char at end of string */
5197d8fb588SMatthias Schmidt     if (ptr->next == NULL) {
5207d8fb588SMatthias Schmidt 	/* print this Xkey and function */
5217d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '"');
5227d8fb588SMatthias Schmidt 	Strbuf_terminate(buf);
5237d8fb588SMatthias Schmidt 	printOne(buf->s, &ptr->val, ptr->type);
5247d8fb588SMatthias Schmidt     }
5257d8fb588SMatthias Schmidt     else
5267d8fb588SMatthias Schmidt 	Enumerate(buf, ptr->next);
5277d8fb588SMatthias Schmidt 
5287d8fb588SMatthias Schmidt     /* go to sibling if there is one */
5297d8fb588SMatthias Schmidt     if (ptr->sibling) {
5307d8fb588SMatthias Schmidt 	buf->len = old_len;
5317d8fb588SMatthias Schmidt 	Enumerate(buf, ptr->sibling);
5327d8fb588SMatthias Schmidt     }
5337d8fb588SMatthias Schmidt }
5347d8fb588SMatthias Schmidt 
5357d8fb588SMatthias Schmidt 
5367d8fb588SMatthias Schmidt /* PrintOne():
5377d8fb588SMatthias Schmidt  *	Print the specified key and its associated
5387d8fb588SMatthias Schmidt  *	function specified by val
5397d8fb588SMatthias Schmidt  */
5407d8fb588SMatthias Schmidt void
printOne(const Char * key,const XmapVal * val,int ntype)5417d8fb588SMatthias Schmidt printOne(const Char *key, const XmapVal *val, int ntype)
5427d8fb588SMatthias Schmidt {
5437d8fb588SMatthias Schmidt     struct KeyFuncs *fp;
5447d8fb588SMatthias Schmidt     static const char *fmt = "%s\n";
5457d8fb588SMatthias Schmidt 
546*d6ab524cSAntonio Huete Jimenez     xprintf("%-15" TCSH_S "-> ", key);
5477d8fb588SMatthias Schmidt     if (val != NULL)
5487d8fb588SMatthias Schmidt 	switch (ntype) {
5497d8fb588SMatthias Schmidt 	case XK_STR:
5507d8fb588SMatthias Schmidt 	case XK_EXE: {
5517d8fb588SMatthias Schmidt 	    unsigned char *p;
5527d8fb588SMatthias Schmidt 
5537d8fb588SMatthias Schmidt 	    p = unparsestring(&val->str, ntype == XK_STR ? STRQQ : STRBB);
5547d8fb588SMatthias Schmidt 	    cleanup_push(p, xfree);
5557d8fb588SMatthias Schmidt 	    xprintf(fmt, p);
5567d8fb588SMatthias Schmidt 	    cleanup_until(p);
5577d8fb588SMatthias Schmidt 	    break;
5587d8fb588SMatthias Schmidt 	}
5597d8fb588SMatthias Schmidt 	case XK_CMD:
5607d8fb588SMatthias Schmidt 	    for (fp = FuncNames; fp->name; fp++)
5617d8fb588SMatthias Schmidt 		if (val->cmd == fp->func)
5627d8fb588SMatthias Schmidt 		    xprintf(fmt, fp->name);
5637d8fb588SMatthias Schmidt 	    break;
5647d8fb588SMatthias Schmidt 	default:
5657d8fb588SMatthias Schmidt 	    abort();
5667d8fb588SMatthias Schmidt 	    break;
5677d8fb588SMatthias Schmidt 	}
5687d8fb588SMatthias Schmidt     else
5697d8fb588SMatthias Schmidt 	xprintf(fmt, CGETS(9, 7, "no input"));
5707d8fb588SMatthias Schmidt }
5717d8fb588SMatthias Schmidt 
5727d8fb588SMatthias Schmidt static void
unparsech(struct Strbuf * buf,Char ch)5737d8fb588SMatthias Schmidt unparsech(struct Strbuf *buf, Char ch)
5747d8fb588SMatthias Schmidt {
5757d8fb588SMatthias Schmidt     if (ch == 0) {
5767d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '^');
5777d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '@');
5787d8fb588SMatthias Schmidt     }
5797d8fb588SMatthias Schmidt     else if (Iscntrl(ch)) {
5807d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '^');
5817d8fb588SMatthias Schmidt 	if (ch == CTL_ESC('\177'))
5827d8fb588SMatthias Schmidt 	    Strbuf_append1(buf, '?');
5837d8fb588SMatthias Schmidt 	else
5847d8fb588SMatthias Schmidt #ifdef IS_ASCII
5857d8fb588SMatthias Schmidt 	    Strbuf_append1(buf, ch | 0100);
5867d8fb588SMatthias Schmidt #else
5877d8fb588SMatthias Schmidt 	    Strbuf_append1(buf, _toebcdic[_toascii[ch]|0100]);
5887d8fb588SMatthias Schmidt #endif
5897d8fb588SMatthias Schmidt     }
5907d8fb588SMatthias Schmidt     else if (ch == '^') {
5917d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '\\');
5927d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '^');
5937d8fb588SMatthias Schmidt     } else if (ch == '\\') {
5947d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '\\');
5957d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '\\');
5967d8fb588SMatthias Schmidt     } else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) {
5977d8fb588SMatthias Schmidt 	Strbuf_append1(buf, ch);
5987d8fb588SMatthias Schmidt     }
5997d8fb588SMatthias Schmidt     else {
6007d8fb588SMatthias Schmidt 	Strbuf_append1(buf, '\\');
6017d8fb588SMatthias Schmidt 	Strbuf_append1(buf, ((ch >> 6) & 7) + '0');
6027d8fb588SMatthias Schmidt 	Strbuf_append1(buf, ((ch >> 3) & 7) + '0');
6037d8fb588SMatthias Schmidt 	Strbuf_append1(buf, (ch & 7) + '0');
6047d8fb588SMatthias Schmidt     }
6057d8fb588SMatthias Schmidt }
6067d8fb588SMatthias Schmidt 
607*d6ab524cSAntonio Huete Jimenez static Char
parse_hex_range(const Char ** cp,size_t l)608*d6ab524cSAntonio Huete Jimenez parse_hex_range(const Char **cp, size_t l)
609*d6ab524cSAntonio Huete Jimenez {
610*d6ab524cSAntonio Huete Jimenez     size_t ui = 0;
611*d6ab524cSAntonio Huete Jimenez     Char r = 0, c;
612*d6ab524cSAntonio Huete Jimenez 
613*d6ab524cSAntonio Huete Jimenez     if (l > 8)
614*d6ab524cSAntonio Huete Jimenez 	abort();
615*d6ab524cSAntonio Huete Jimenez 
616*d6ab524cSAntonio Huete Jimenez     for (; (c = (**cp & CHAR)) != '\0' && ui < l && Isxdigit(c); (*cp)++, ui++) {
617*d6ab524cSAntonio Huete Jimenez 	Char x = Isdigit(c) ? '0' : ((Isupper(c) ? 'A' : 'a') - 10);
618*d6ab524cSAntonio Huete Jimenez #ifndef IS_ASCII
619*d6ab524cSAntonio Huete Jimenez 	c = _toascii(c);
620*d6ab524cSAntonio Huete Jimenez #endif
621*d6ab524cSAntonio Huete Jimenez 	r <<= 4;
622*d6ab524cSAntonio Huete Jimenez 	r |= c - x;
623*d6ab524cSAntonio Huete Jimenez     }
624*d6ab524cSAntonio Huete Jimenez     (*cp)--;
625*d6ab524cSAntonio Huete Jimenez #ifndef IS_ASCII
626*d6ab524cSAntonio Huete Jimenez     return _toebcdic[r & 0xff];
627*d6ab524cSAntonio Huete Jimenez #else
628*d6ab524cSAntonio Huete Jimenez     return r;
629*d6ab524cSAntonio Huete Jimenez #endif
630*d6ab524cSAntonio Huete Jimenez }
631*d6ab524cSAntonio Huete Jimenez 
632*d6ab524cSAntonio Huete Jimenez /*
633*d6ab524cSAntonio Huete Jimenez  * The e parameter is false when we are doing echo and true when we are
634*d6ab524cSAntonio Huete Jimenez  * using it to parse other escaped strings. For echo, we don't print errors
635*d6ab524cSAntonio Huete Jimenez  * and we don't unescape backslashes that we don't understand. Perhaps we
636*d6ab524cSAntonio Huete Jimenez  * always not unescape backslashes we don't understand...
637*d6ab524cSAntonio Huete Jimenez  */
6387d8fb588SMatthias Schmidt eChar
parseescape(const Char ** ptr,int e)639*d6ab524cSAntonio Huete Jimenez parseescape(const Char **ptr, int e)
6407d8fb588SMatthias Schmidt {
6417d8fb588SMatthias Schmidt     const Char *p;
6427d8fb588SMatthias Schmidt     Char c;
6437d8fb588SMatthias Schmidt 
6447d8fb588SMatthias Schmidt     p = *ptr;
6457d8fb588SMatthias Schmidt 
6467d8fb588SMatthias Schmidt     if ((p[1] & CHAR) == 0) {
647*d6ab524cSAntonio Huete Jimenez 	if (e)
6487d8fb588SMatthias Schmidt 	    xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p);
6497d8fb588SMatthias Schmidt 	return CHAR_ERR;
6507d8fb588SMatthias Schmidt     }
6517d8fb588SMatthias Schmidt     if ((*p & CHAR) == '\\') {
6527d8fb588SMatthias Schmidt 	p++;
6537d8fb588SMatthias Schmidt 	switch (*p & CHAR) {
6547d8fb588SMatthias Schmidt 	case 'a':
6557d8fb588SMatthias Schmidt 	    c = CTL_ESC('\007');         /* Bell */
6567d8fb588SMatthias Schmidt 	    break;
6577d8fb588SMatthias Schmidt 	case 'b':
6587d8fb588SMatthias Schmidt 	    c = CTL_ESC('\010');         /* Backspace */
6597d8fb588SMatthias Schmidt 	    break;
660*d6ab524cSAntonio Huete Jimenez 	case 'c':
661*d6ab524cSAntonio Huete Jimenez 	    p++;
662*d6ab524cSAntonio Huete Jimenez 	    if ((*p & CHAR) == '\\') {
663*d6ab524cSAntonio Huete Jimenez 		p++;
664*d6ab524cSAntonio Huete Jimenez 		if ((*p & CHAR) != '\\') {
665*d6ab524cSAntonio Huete Jimenez 		    *ptr = p;
666*d6ab524cSAntonio Huete Jimenez 		    if (e)
667*d6ab524cSAntonio Huete Jimenez 			xprintf(/*CGETS(9, 9, */
668*d6ab524cSAntonio Huete Jimenez 			    "Invalid escape sequence: %s%c\n"/*)*/, "\\c\\", (char)*p);
669*d6ab524cSAntonio Huete Jimenez 		    return CHAR_ERR;
670*d6ab524cSAntonio Huete Jimenez 		}
671*d6ab524cSAntonio Huete Jimenez 		c = (*p & CHAR) & 0237;
672*d6ab524cSAntonio Huete Jimenez 	    } else if ((Isalpha(*p & CHAR) || strchr("@^_?\\|[{]}", *p & CHAR))) {
673*d6ab524cSAntonio Huete Jimenez 		/* XXX: Duplicate code from ^ below */
674*d6ab524cSAntonio Huete Jimenez #ifdef IS_ASCII
675*d6ab524cSAntonio Huete Jimenez 		c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
676*d6ab524cSAntonio Huete Jimenez #else
677*d6ab524cSAntonio Huete Jimenez 		c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
678*d6ab524cSAntonio Huete Jimenez 		if (adrof(STRwarnebcdic))
679*d6ab524cSAntonio Huete Jimenez 		    xprintf(/*CGETS(9, 9, no NLS-String yet!*/
680*d6ab524cSAntonio Huete Jimenez 			"Warning: Control character %s%c may be interpreted differently in EBCDIC.\n", "\\c", *p & CHAR /*)*/);
681*d6ab524cSAntonio Huete Jimenez #endif
682*d6ab524cSAntonio Huete Jimenez 	    } else { /* backward compat */
683*d6ab524cSAntonio Huete Jimenez 		c = '\\';
684*d6ab524cSAntonio Huete Jimenez 		p -= 2;
685*d6ab524cSAntonio Huete Jimenez 	    }
686*d6ab524cSAntonio Huete Jimenez 	    break;
6877d8fb588SMatthias Schmidt 	case 'e':
6887d8fb588SMatthias Schmidt 	    c = CTL_ESC('\033');         /* Escape */
6897d8fb588SMatthias Schmidt 	    break;
6907d8fb588SMatthias Schmidt 	case 'f':
6917d8fb588SMatthias Schmidt 	    c = CTL_ESC('\014');         /* Form Feed */
6927d8fb588SMatthias Schmidt 	    break;
6937d8fb588SMatthias Schmidt 	case 'n':
6947d8fb588SMatthias Schmidt 	    c = CTL_ESC('\012');         /* New Line */
6957d8fb588SMatthias Schmidt 	    break;
6967d8fb588SMatthias Schmidt 	case 'r':
6977d8fb588SMatthias Schmidt 	    c = CTL_ESC('\015');         /* Carriage Return */
6987d8fb588SMatthias Schmidt 	    break;
6997d8fb588SMatthias Schmidt 	case 't':
7007d8fb588SMatthias Schmidt 	    c = CTL_ESC('\011');         /* Horizontal Tab */
7017d8fb588SMatthias Schmidt 	    break;
7027d8fb588SMatthias Schmidt 	case 'v':
7037d8fb588SMatthias Schmidt 	    c = CTL_ESC('\013');         /* Vertical Tab */
7047d8fb588SMatthias Schmidt 	    break;
7057d8fb588SMatthias Schmidt 	case '\\':
7067d8fb588SMatthias Schmidt 	    c = '\\';
7077d8fb588SMatthias Schmidt 	    break;
708*d6ab524cSAntonio Huete Jimenez 	case 'x':
709*d6ab524cSAntonio Huete Jimenez 	    p++;
710*d6ab524cSAntonio Huete Jimenez 	    if ((*p & CHAR) == '{' && Isxdigit(*(p + 1) & CHAR)) { /* \x{20ac} */
711*d6ab524cSAntonio Huete Jimenez 		const Char *q = p - 2;
712*d6ab524cSAntonio Huete Jimenez 		p++;
713*d6ab524cSAntonio Huete Jimenez 		c = parse_hex_range(&p, 8);
714*d6ab524cSAntonio Huete Jimenez 		if ((p[1] & CHAR) != '}') {
715*d6ab524cSAntonio Huete Jimenez 		    if (e)
716*d6ab524cSAntonio Huete Jimenez 			xprintf("%s", /* CGETS(9, 9, */
717*d6ab524cSAntonio Huete Jimenez 			    "Missing closing brace");
718*d6ab524cSAntonio Huete Jimenez 		    p = q;
719*d6ab524cSAntonio Huete Jimenez 		    c = '\\';
720*d6ab524cSAntonio Huete Jimenez 		    break;
721*d6ab524cSAntonio Huete Jimenez 		}
722*d6ab524cSAntonio Huete Jimenez 		p++;
723*d6ab524cSAntonio Huete Jimenez 	    } else if (Isxdigit(*p & CHAR)) {	/* \x9f */
724*d6ab524cSAntonio Huete Jimenez 		c = parse_hex_range(&p, 2);
725*d6ab524cSAntonio Huete Jimenez 	    } else { /* backward compat */
726*d6ab524cSAntonio Huete Jimenez 		c = '\\';
727*d6ab524cSAntonio Huete Jimenez 		p -= 2;
728*d6ab524cSAntonio Huete Jimenez 	    }
729*d6ab524cSAntonio Huete Jimenez 	    break;
730*d6ab524cSAntonio Huete Jimenez 	case 'u':
731*d6ab524cSAntonio Huete Jimenez 	case 'U':
732*d6ab524cSAntonio Huete Jimenez 	    {
733*d6ab524cSAntonio Huete Jimenez 		size_t limit = (*p & CHAR) == 'u' ? 4 : 8;
734*d6ab524cSAntonio Huete Jimenez 		p++;
735*d6ab524cSAntonio Huete Jimenez 		if (Isxdigit(*p & CHAR)) {	/* \u20ac or \U000020ac */
736*d6ab524cSAntonio Huete Jimenez 		    c = parse_hex_range(&p, limit);
737*d6ab524cSAntonio Huete Jimenez 		} else { /* backward compat */
738*d6ab524cSAntonio Huete Jimenez 		    c = '\\';
739*d6ab524cSAntonio Huete Jimenez 		    p -= 2;
740*d6ab524cSAntonio Huete Jimenez 		}
741*d6ab524cSAntonio Huete Jimenez 	    }
742*d6ab524cSAntonio Huete Jimenez 	    break;
7437d8fb588SMatthias Schmidt 	case '0':
7447d8fb588SMatthias Schmidt 	case '1':
7457d8fb588SMatthias Schmidt 	case '2':
7467d8fb588SMatthias Schmidt 	case '3':
7477d8fb588SMatthias Schmidt 	case '4':
7487d8fb588SMatthias Schmidt 	case '5':
7497d8fb588SMatthias Schmidt 	case '6':
7507d8fb588SMatthias Schmidt 	case '7':
7517d8fb588SMatthias Schmidt 	    {
7527d8fb588SMatthias Schmidt 		int cnt, val;
7537d8fb588SMatthias Schmidt 		Char ch;
7547d8fb588SMatthias Schmidt 
7557d8fb588SMatthias Schmidt 		for (cnt = 0, val = 0; cnt < 3; cnt++) {
7567d8fb588SMatthias Schmidt 		    ch = *p++ & CHAR;
7577d8fb588SMatthias Schmidt 		    if (ch < '0' || ch > '7') {
7587d8fb588SMatthias Schmidt 			p--;
7597d8fb588SMatthias Schmidt 			break;
7607d8fb588SMatthias Schmidt 		    }
7617d8fb588SMatthias Schmidt 		    val = (val << 3) | (ch - '0');
7627d8fb588SMatthias Schmidt 		}
7637d8fb588SMatthias Schmidt 		if ((val & ~0xff) != 0) {
764*d6ab524cSAntonio Huete Jimenez 		    if (e)
76557e3f2b5SSimon 'corecode' Schubert 			xprintf("%s", CGETS(9, 9,
7667d8fb588SMatthias Schmidt 			    "Octal constant does not fit in a char.\n"));
767*d6ab524cSAntonio Huete Jimenez 		    *ptr = p;
768*d6ab524cSAntonio Huete Jimenez 		    return CHAR_ERR;
7697d8fb588SMatthias Schmidt 		}
7707d8fb588SMatthias Schmidt #ifndef IS_ASCII
7717d8fb588SMatthias Schmidt 		if (CTL_ESC(val) != val && adrof(STRwarnebcdic))
7727d8fb588SMatthias Schmidt 		    xprintf(/*CGETS(9, 9, no NLS-String yet!*/
773*d6ab524cSAntonio Huete Jimenez 			"Warning: Octal constant \\%3.3o is interpreted as "
774*d6ab524cSAntonio Huete Jimenez 			"EBCDIC value.\n", val/*)*/);
7757d8fb588SMatthias Schmidt #endif
7767d8fb588SMatthias Schmidt 		c = (Char) val;
7777d8fb588SMatthias Schmidt 		--p;
7787d8fb588SMatthias Schmidt 	    }
7797d8fb588SMatthias Schmidt 	    break;
7807d8fb588SMatthias Schmidt 	default:
781*d6ab524cSAntonio Huete Jimenez 	    if (!e)
782*d6ab524cSAntonio Huete Jimenez 		--p;
7837d8fb588SMatthias Schmidt 	    c = *p;
7847d8fb588SMatthias Schmidt 	    break;
7857d8fb588SMatthias Schmidt 	}
7867d8fb588SMatthias Schmidt     }
7877d8fb588SMatthias Schmidt     else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) ||
7887d8fb588SMatthias Schmidt 				    strchr("@^_?\\|[{]}", p[1] & CHAR))) {
7897d8fb588SMatthias Schmidt 	p++;
7907d8fb588SMatthias Schmidt #ifdef IS_ASCII
7917d8fb588SMatthias Schmidt 	c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
7927d8fb588SMatthias Schmidt #else
7937d8fb588SMatthias Schmidt 	c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
7947d8fb588SMatthias Schmidt 	if (adrof(STRwarnebcdic))
7957d8fb588SMatthias Schmidt 	    xprintf(/*CGETS(9, 9, no NLS-String yet!*/
796*d6ab524cSAntonio Huete Jimenez 		"Warning: Control character %s%c may be interpreted differently in EBCDIC.\n", "^", *p & CHAR /*)*/);
7977d8fb588SMatthias Schmidt #endif
7987d8fb588SMatthias Schmidt     }
7997d8fb588SMatthias Schmidt     else
800*d6ab524cSAntonio Huete Jimenez 	c = *p & CHAR;
8017d8fb588SMatthias Schmidt     *ptr = p;
8027d8fb588SMatthias Schmidt     return (c);
8037d8fb588SMatthias Schmidt }
8047d8fb588SMatthias Schmidt 
8057d8fb588SMatthias Schmidt 
8067d8fb588SMatthias Schmidt unsigned char *
unparsestring(const CStr * str,const Char * sep)8077d8fb588SMatthias Schmidt unparsestring(const CStr *str, const Char *sep)
8087d8fb588SMatthias Schmidt {
8097d8fb588SMatthias Schmidt     unsigned char *buf, *b;
8107d8fb588SMatthias Schmidt     Char   p;
8117d8fb588SMatthias Schmidt     int l;
8127d8fb588SMatthias Schmidt 
8137d8fb588SMatthias Schmidt     /* Worst-case is "\uuu" or result of wctomb() for each char from str */
8147d8fb588SMatthias Schmidt     buf = xmalloc((str->len + 1) * max(4, MB_LEN_MAX));
8157d8fb588SMatthias Schmidt     b = buf;
8167d8fb588SMatthias Schmidt     if (sep[0])
8177d8fb588SMatthias Schmidt #ifndef WINNT_NATIVE
8187d8fb588SMatthias Schmidt 	*b++ = sep[0];
8197d8fb588SMatthias Schmidt #else /* WINNT_NATIVE */
8207d8fb588SMatthias Schmidt 	*b++ = CHAR & sep[0];
8217d8fb588SMatthias Schmidt #endif /* !WINNT_NATIVE */
8227d8fb588SMatthias Schmidt 
8237d8fb588SMatthias Schmidt     for (l = 0; l < str->len; l++) {
8247d8fb588SMatthias Schmidt 	p = str->buf[l];
8257d8fb588SMatthias Schmidt 	if (Iscntrl(p)) {
8267d8fb588SMatthias Schmidt 	    *b++ = '^';
8277d8fb588SMatthias Schmidt 	    if (p == CTL_ESC('\177'))
8287d8fb588SMatthias Schmidt 		*b++ = '?';
8297d8fb588SMatthias Schmidt 	    else
8307d8fb588SMatthias Schmidt #ifdef IS_ASCII
8317d8fb588SMatthias Schmidt 		*b++ = (unsigned char) (p | 0100);
8327d8fb588SMatthias Schmidt #else
8337d8fb588SMatthias Schmidt 		*b++ = _toebcdic[_toascii[p]|0100];
8347d8fb588SMatthias Schmidt #endif
8357d8fb588SMatthias Schmidt 	}
8367d8fb588SMatthias Schmidt 	else if (p == '^' || p == '\\') {
8377d8fb588SMatthias Schmidt 	    *b++ = '\\';
8387d8fb588SMatthias Schmidt 	    *b++ = (unsigned char) p;
8397d8fb588SMatthias Schmidt 	}
8407d8fb588SMatthias Schmidt 	else if (p == ' ' || (Isprint(p) && !Isspace(p)))
841653fab9eSSascha Wildner 	    b += one_wctomb((char *)b, p);
8427d8fb588SMatthias Schmidt 	else {
8437d8fb588SMatthias Schmidt 	    *b++ = '\\';
8447d8fb588SMatthias Schmidt 	    *b++ = ((p >> 6) & 7) + '0';
8457d8fb588SMatthias Schmidt 	    *b++ = ((p >> 3) & 7) + '0';
8467d8fb588SMatthias Schmidt 	    *b++ = (p & 7) + '0';
8477d8fb588SMatthias Schmidt 	}
8487d8fb588SMatthias Schmidt     }
8497d8fb588SMatthias Schmidt     if (sep[0] && sep[1])
8507d8fb588SMatthias Schmidt #ifndef WINNT_NATIVE
8517d8fb588SMatthias Schmidt 	*b++ = sep[1];
8527d8fb588SMatthias Schmidt #else /* WINNT_NATIVE */
8537d8fb588SMatthias Schmidt 	*b++ = CHAR & sep[1];
8547d8fb588SMatthias Schmidt #endif /* !WINNT_NATIVE */
8557d8fb588SMatthias Schmidt     *b++ = 0;
8567d8fb588SMatthias Schmidt     return buf;			/* should check for overflow */
8577d8fb588SMatthias Schmidt }
858