xref: /freebsd/contrib/tcsh/ed.xmap.c (revision 6560ac57ce879857203bc456cdc3849808dc0700)
1c80476e4SDavid E. O'Brien /*
2c80476e4SDavid E. O'Brien  * ed.xmap.c: This module contains the procedures for maintaining
3c80476e4SDavid E. O'Brien  *	      the extended-key map.
4c80476e4SDavid E. O'Brien  *
5c80476e4SDavid E. O'Brien  * 	      An extended-key (Xkey) is a sequence of keystrokes
6c80476e4SDavid E. O'Brien  *	      introduced with an sequence introducer and consisting
7c80476e4SDavid E. O'Brien  *	      of an arbitrary number of characters.  This module maintains
8c80476e4SDavid E. O'Brien  *	      a map (the Xmap) to convert these extended-key sequences
9c80476e4SDavid E. O'Brien  * 	      into input strings (XK_STR), editor functions (XK_CMD), or
10c80476e4SDavid E. O'Brien  *	      unix commands (XK_EXE). It contains the
11c80476e4SDavid E. O'Brien  *	      following externally visible functions.
12c80476e4SDavid E. O'Brien  *
13c80476e4SDavid E. O'Brien  *		int GetXkey(ch,val);
14c80476e4SDavid E. O'Brien  *		CStr *ch;
15c80476e4SDavid E. O'Brien  *		XmapVal *val;
16c80476e4SDavid E. O'Brien  *
17c80476e4SDavid E. O'Brien  *	      Looks up *ch in map and then reads characters until a
18c80476e4SDavid E. O'Brien  *	      complete match is found or a mismatch occurs. Returns the
19c80476e4SDavid E. O'Brien  *	      type of the match found (XK_STR, XK_CMD, or XK_EXE).
20c80476e4SDavid E. O'Brien  *	      Returns NULL in val.str and XK_STR for no match.
21c80476e4SDavid E. O'Brien  *	      The last character read is returned in *ch.
22c80476e4SDavid E. O'Brien  *
23c80476e4SDavid E. O'Brien  *		void AddXkey(Xkey, val, ntype);
24c80476e4SDavid E. O'Brien  *		CStr *Xkey;
25c80476e4SDavid E. O'Brien  *		XmapVal *val;
26c80476e4SDavid E. O'Brien  *		int ntype;
27c80476e4SDavid E. O'Brien  *
28c80476e4SDavid E. O'Brien  *	      Adds Xkey to the Xmap and associates the value in val with it.
29c80476e4SDavid E. O'Brien  *	      If Xkey is already is in Xmap, the new code is applied to the
30c80476e4SDavid E. O'Brien  *	      existing Xkey. Ntype specifies if code is a command, an
31c80476e4SDavid E. O'Brien  *	      out string or a unix command.
32c80476e4SDavid E. O'Brien  *
33c80476e4SDavid E. O'Brien  *	        int DeleteXkey(Xkey);
34c80476e4SDavid E. O'Brien  *	        CStr *Xkey;
35c80476e4SDavid E. O'Brien  *
36c80476e4SDavid E. O'Brien  *	      Delete the Xkey and all longer Xkeys staring with Xkey, if
37c80476e4SDavid E. O'Brien  *	      they exists.
38c80476e4SDavid E. O'Brien  *
39c80476e4SDavid E. O'Brien  *	      Warning:
40c80476e4SDavid E. O'Brien  *		If Xkey is a substring of some other Xkeys, then the longer
41c80476e4SDavid E. O'Brien  *		Xkeys are lost!!  That is, if the Xkeys "abcd" and "abcef"
42c80476e4SDavid E. O'Brien  *		are in Xmap, adding the key "abc" will cause the first two
43c80476e4SDavid E. O'Brien  *		definitions to be lost.
44c80476e4SDavid E. O'Brien  *
45c80476e4SDavid E. O'Brien  *		void ResetXmap();
46c80476e4SDavid E. O'Brien  *
47c80476e4SDavid E. O'Brien  *	      Removes all entries from Xmap and resets the defaults.
48c80476e4SDavid E. O'Brien  *
49c80476e4SDavid E. O'Brien  *		void PrintXkey(Xkey);
50c80476e4SDavid E. O'Brien  *		CStr *Xkey;
51c80476e4SDavid E. O'Brien  *
52c80476e4SDavid E. O'Brien  *	      Prints all extended keys prefixed by Xkey and their associated
53c80476e4SDavid E. O'Brien  *	      commands.
54c80476e4SDavid E. O'Brien  *
55c80476e4SDavid E. O'Brien  *	      Restrictions:
56c80476e4SDavid E. O'Brien  *	      -------------
57c80476e4SDavid E. O'Brien  *	        1) It is not possible to have one Xkey that is a
58c80476e4SDavid E. O'Brien  *		   substring of another.
59c80476e4SDavid E. O'Brien  */
60c80476e4SDavid E. O'Brien /*-
61c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
62c80476e4SDavid E. O'Brien  * All rights reserved.
63c80476e4SDavid E. O'Brien  *
64c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
65c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
66c80476e4SDavid E. O'Brien  * are met:
67c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
68c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
69c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
70c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
71c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
7229301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
73c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
74c80476e4SDavid E. O'Brien  *    without specific prior written permission.
75c80476e4SDavid E. O'Brien  *
76c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
77c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
80c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
81c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
82c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
83c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
84c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
85c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
86c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
87c80476e4SDavid E. O'Brien  */
88c80476e4SDavid E. O'Brien #include "sh.h"
89c80476e4SDavid E. O'Brien #include "ed.h"
90c80476e4SDavid E. O'Brien #include "ed.defns.h"
91c80476e4SDavid E. O'Brien 
92c80476e4SDavid E. O'Brien #ifndef NULL
93c80476e4SDavid E. O'Brien #define NULL 0
94c80476e4SDavid E. O'Brien #endif
95c80476e4SDavid E. O'Brien 
96c80476e4SDavid E. O'Brien /* Internal Data types and declarations */
97c80476e4SDavid E. O'Brien 
98c80476e4SDavid E. O'Brien /* The Nodes of the Xmap.  The Xmap is a linked list of these node
99c80476e4SDavid E. O'Brien  * elements
100c80476e4SDavid E. O'Brien  */
101c80476e4SDavid E. O'Brien typedef struct Xmapnode {
102c80476e4SDavid E. O'Brien     Char    ch;			/* single character of Xkey */
103c80476e4SDavid E. O'Brien     int     type;
104c80476e4SDavid E. O'Brien     XmapVal val; 		/* command code or pointer to string, if this
105c80476e4SDavid E. O'Brien 				 * is a leaf */
106c80476e4SDavid E. O'Brien     struct Xmapnode *next;	/* ptr to next char of this Xkey */
107c80476e4SDavid E. O'Brien     struct Xmapnode *sibling;	/* ptr to another Xkey with same prefix */
108c80476e4SDavid E. O'Brien } XmapNode;
109c80476e4SDavid E. O'Brien 
110c80476e4SDavid E. O'Brien static XmapNode *Xmap = NULL;	/* the current Xmap */
111c80476e4SDavid E. O'Brien 
112c80476e4SDavid E. O'Brien 
113c80476e4SDavid E. O'Brien /* Some declarations of procedures */
11445e5710bSMark Peek static	int       TraverseMap	(XmapNode *, CStr *, XmapVal *);
11545e5710bSMark Peek static	int       TryNode	(XmapNode *, CStr *, XmapVal *, int);
11645e5710bSMark Peek static	XmapNode *GetFreeNode	(CStr *);
11745e5710bSMark Peek static	void	  PutFreeNode	(XmapNode *);
11845e5710bSMark Peek static	int	  TryDeleteNode	(XmapNode **, CStr *);
11945e5710bSMark Peek static	int	  Lookup	(struct Strbuf *, const CStr *,
12045e5710bSMark Peek 				 const XmapNode *);
12145e5710bSMark Peek static	void	  Enumerate	(struct Strbuf *, const XmapNode *);
12245e5710bSMark Peek static	void	  unparsech	(struct Strbuf *, Char);
123c80476e4SDavid E. O'Brien 
124c80476e4SDavid E. O'Brien 
125c80476e4SDavid E. O'Brien XmapVal *
XmapCmd(int cmd)12645e5710bSMark Peek XmapCmd(int cmd)
127c80476e4SDavid E. O'Brien {
128c80476e4SDavid E. O'Brien     static XmapVal xm;
129c80476e4SDavid E. O'Brien     xm.cmd = (KEYCMD) cmd;
130c80476e4SDavid E. O'Brien     return &xm;
131c80476e4SDavid E. O'Brien }
132c80476e4SDavid E. O'Brien 
133c80476e4SDavid E. O'Brien XmapVal *
XmapStr(CStr * str)13445e5710bSMark Peek XmapStr(CStr *str)
135c80476e4SDavid E. O'Brien {
136c80476e4SDavid E. O'Brien     static XmapVal xm;
137c80476e4SDavid E. O'Brien     xm.str.len = str->len;
138c80476e4SDavid E. O'Brien     xm.str.buf = str->buf;
139c80476e4SDavid E. O'Brien     return &xm;
140c80476e4SDavid E. O'Brien }
141c80476e4SDavid E. O'Brien 
142c80476e4SDavid E. O'Brien /* ResetXmap():
143c80476e4SDavid E. O'Brien  *	Takes all nodes on Xmap and puts them on free list.  Then
144c80476e4SDavid E. O'Brien  *	initializes Xmap with arrow keys
145c80476e4SDavid E. O'Brien  */
146c80476e4SDavid E. O'Brien void
ResetXmap(void)14745e5710bSMark Peek ResetXmap(void)
148c80476e4SDavid E. O'Brien {
149c80476e4SDavid E. O'Brien     PutFreeNode(Xmap);
150c80476e4SDavid E. O'Brien     Xmap = NULL;
151c80476e4SDavid E. O'Brien 
152c80476e4SDavid E. O'Brien     DefaultArrowKeys();
153c80476e4SDavid E. O'Brien     return;
154c80476e4SDavid E. O'Brien }
155c80476e4SDavid E. O'Brien 
156c80476e4SDavid E. O'Brien 
157c80476e4SDavid E. O'Brien /* GetXkey():
158c80476e4SDavid E. O'Brien  *	Calls the recursive function with entry point Xmap
159c80476e4SDavid E. O'Brien  */
160c80476e4SDavid E. O'Brien int
GetXkey(CStr * ch,XmapVal * val)16145e5710bSMark Peek GetXkey(CStr *ch, XmapVal *val)
162c80476e4SDavid E. O'Brien {
163c80476e4SDavid E. O'Brien     return (TraverseMap(Xmap, ch, val));
164c80476e4SDavid E. O'Brien }
165c80476e4SDavid E. O'Brien 
166c80476e4SDavid E. O'Brien /* TraverseMap():
167c80476e4SDavid E. O'Brien  *	recursively traverses node in tree until match or mismatch is
168c80476e4SDavid E. O'Brien  * 	found.  May read in more characters.
169c80476e4SDavid E. O'Brien  */
170c80476e4SDavid E. O'Brien static int
TraverseMap(XmapNode * ptr,CStr * ch,XmapVal * val)17145e5710bSMark Peek TraverseMap(XmapNode *ptr, CStr *ch, XmapVal *val)
172c80476e4SDavid E. O'Brien {
173c80476e4SDavid E. O'Brien     Char    tch;
174c80476e4SDavid E. O'Brien 
175c80476e4SDavid E. O'Brien     if (ptr->ch == *(ch->buf)) {
176c80476e4SDavid E. O'Brien 	/* match found */
177c80476e4SDavid E. O'Brien 	if (ptr->next) {
178c80476e4SDavid E. O'Brien 	    /* Xkey not complete so get next char */
179c80476e4SDavid E. O'Brien 	    if (GetNextChar(&tch) != 1) {	/* if EOF or error */
180c80476e4SDavid E. O'Brien 		val->cmd = F_SEND_EOF;
181c80476e4SDavid E. O'Brien 		return XK_CMD;/* PWP: Pretend we just read an end-of-file */
182c80476e4SDavid E. O'Brien 	    }
183c80476e4SDavid E. O'Brien 	    *(ch->buf) = tch;
184c80476e4SDavid E. O'Brien 	    return (TraverseMap(ptr->next, ch, val));
185c80476e4SDavid E. O'Brien 	}
186c80476e4SDavid E. O'Brien 	else {
187c80476e4SDavid E. O'Brien 	    *val = ptr->val;
188c80476e4SDavid E. O'Brien 	    if (ptr->type != XK_CMD)
189c80476e4SDavid E. O'Brien 		*(ch->buf) = '\0';
190c80476e4SDavid E. O'Brien 	    return ptr->type;
191c80476e4SDavid E. O'Brien 	}
192c80476e4SDavid E. O'Brien     }
193c80476e4SDavid E. O'Brien     else {
194c80476e4SDavid E. O'Brien 	/* no match found here */
195c80476e4SDavid E. O'Brien 	if (ptr->sibling) {
196c80476e4SDavid E. O'Brien 	    /* try next sibling */
197c80476e4SDavid E. O'Brien 	    return (TraverseMap(ptr->sibling, ch, val));
198c80476e4SDavid E. O'Brien 	}
199c80476e4SDavid E. O'Brien 	else {
200c80476e4SDavid E. O'Brien 	    /* no next sibling -- mismatch */
201c80476e4SDavid E. O'Brien 	    val->str.buf = NULL;
202c80476e4SDavid E. O'Brien 	    val->str.len = 0;
203c80476e4SDavid E. O'Brien 	    return XK_STR;
204c80476e4SDavid E. O'Brien 	}
205c80476e4SDavid E. O'Brien     }
206c80476e4SDavid E. O'Brien }
207c80476e4SDavid E. O'Brien 
208c80476e4SDavid E. O'Brien void
AddXkey(const CStr * Xkey,XmapVal * val,int ntype)20945e5710bSMark Peek AddXkey(const CStr *Xkey, XmapVal *val, int ntype)
210c80476e4SDavid E. O'Brien {
211c80476e4SDavid E. O'Brien     CStr cs;
212c80476e4SDavid E. O'Brien     cs.buf = Xkey->buf;
213c80476e4SDavid E. O'Brien     cs.len = Xkey->len;
214c80476e4SDavid E. O'Brien     if (Xkey->len == 0) {
215a15e6f9aSMark Peek 	xprintf("%s", CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n"));
216c80476e4SDavid E. O'Brien 	return;
217c80476e4SDavid E. O'Brien     }
218c80476e4SDavid E. O'Brien 
219c80476e4SDavid E. O'Brien     if (ntype == XK_CMD && val->cmd == F_XKEY) {
220a15e6f9aSMark Peek 	xprintf("%s",
221a15e6f9aSMark Peek 	    CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n"));
222c80476e4SDavid E. O'Brien 	return;
223c80476e4SDavid E. O'Brien     }
224c80476e4SDavid E. O'Brien 
225c80476e4SDavid E. O'Brien     if (Xmap == NULL)
226c80476e4SDavid E. O'Brien 	/* tree is initially empty.  Set up new node to match Xkey[0] */
227c80476e4SDavid E. O'Brien 	Xmap = GetFreeNode(&cs);	/* it is properly initialized */
228c80476e4SDavid E. O'Brien 
229c80476e4SDavid E. O'Brien     /* Now recurse through Xmap */
230c80476e4SDavid E. O'Brien     (void) TryNode(Xmap, &cs, val, ntype);
231c80476e4SDavid E. O'Brien     return;
232c80476e4SDavid E. O'Brien }
233c80476e4SDavid E. O'Brien 
234c80476e4SDavid E. O'Brien static int
TryNode(XmapNode * ptr,CStr * str,XmapVal * val,int ntype)23545e5710bSMark Peek TryNode(XmapNode *ptr, CStr *str, XmapVal *val, int ntype)
236c80476e4SDavid E. O'Brien {
237c80476e4SDavid E. O'Brien     /*
238c80476e4SDavid E. O'Brien      * Find a node that matches *string or allocate a new one
239c80476e4SDavid E. O'Brien      */
240c80476e4SDavid E. O'Brien     if (ptr->ch != *(str->buf)) {
241c80476e4SDavid E. O'Brien 	XmapNode *xm;
242c80476e4SDavid E. O'Brien 
243c80476e4SDavid E. O'Brien 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
244c80476e4SDavid E. O'Brien 	    if (xm->sibling->ch == *(str->buf))
245c80476e4SDavid E. O'Brien 		break;
246c80476e4SDavid E. O'Brien 	if (xm->sibling == NULL)
247c80476e4SDavid E. O'Brien 	    xm->sibling = GetFreeNode(str);	/* setup new node */
248c80476e4SDavid E. O'Brien 	ptr = xm->sibling;
249c80476e4SDavid E. O'Brien     }
250c80476e4SDavid E. O'Brien 
251c80476e4SDavid E. O'Brien     str->buf++;
252c80476e4SDavid E. O'Brien     str->len--;
253c80476e4SDavid E. O'Brien     if (str->len == 0) {
25445e5710bSMark Peek 	size_t len;
25545e5710bSMark Peek 
256c80476e4SDavid E. O'Brien 	/* we're there */
257c80476e4SDavid E. O'Brien 	if (ptr->next != NULL) {
258c80476e4SDavid E. O'Brien 	    PutFreeNode(ptr->next);	/* lose longer Xkeys with this prefix */
259c80476e4SDavid E. O'Brien 	    ptr->next = NULL;
260c80476e4SDavid E. O'Brien 	}
261c80476e4SDavid E. O'Brien 
262c80476e4SDavid E. O'Brien 	switch (ptr->type) {
263c80476e4SDavid E. O'Brien 	case XK_STR:
264c80476e4SDavid E. O'Brien 	case XK_EXE:
26545e5710bSMark Peek 	    xfree(ptr->val.str.buf);
266c80476e4SDavid E. O'Brien 	    ptr->val.str.len = 0;
267c80476e4SDavid E. O'Brien 	    break;
268c80476e4SDavid E. O'Brien 	case XK_NOD:
269c80476e4SDavid E. O'Brien 	case XK_CMD:
270c80476e4SDavid E. O'Brien 	    break;
271c80476e4SDavid E. O'Brien 	default:
272c80476e4SDavid E. O'Brien 	    abort();
273c80476e4SDavid E. O'Brien 	    break;
274c80476e4SDavid E. O'Brien 	}
275c80476e4SDavid E. O'Brien 
276c80476e4SDavid E. O'Brien 	switch (ptr->type = ntype) {
277c80476e4SDavid E. O'Brien 	case XK_CMD:
278c80476e4SDavid E. O'Brien 	    ptr->val = *val;
279c80476e4SDavid E. O'Brien 	    break;
280c80476e4SDavid E. O'Brien 	case XK_STR:
281c80476e4SDavid E. O'Brien 	case XK_EXE:
282c80476e4SDavid E. O'Brien 	    ptr->val.str.len = val->str.len;
28345e5710bSMark Peek 	    len = (val->str.len + 1) * sizeof(*ptr->val.str.buf);
28445e5710bSMark Peek 	    ptr->val.str.buf = xmalloc(len);
28545e5710bSMark Peek 	    (void) memcpy(ptr->val.str.buf, val->str.buf, len);
286c80476e4SDavid E. O'Brien 	    break;
287c80476e4SDavid E. O'Brien 	default:
288c80476e4SDavid E. O'Brien 	    abort();
289c80476e4SDavid E. O'Brien 	    break;
290c80476e4SDavid E. O'Brien 	}
291c80476e4SDavid E. O'Brien     }
292c80476e4SDavid E. O'Brien     else {
293c80476e4SDavid E. O'Brien 	/* still more chars to go */
294c80476e4SDavid E. O'Brien 	if (ptr->next == NULL)
295c80476e4SDavid E. O'Brien 	    ptr->next = GetFreeNode(str);	/* setup new node */
296c80476e4SDavid E. O'Brien 	(void) TryNode(ptr->next, str, val, ntype);
297c80476e4SDavid E. O'Brien     }
298c80476e4SDavid E. O'Brien     return (0);
299c80476e4SDavid E. O'Brien }
300c80476e4SDavid E. O'Brien 
301c80476e4SDavid E. O'Brien void
ClearXkey(KEYCMD * map,const CStr * in)30245e5710bSMark Peek ClearXkey(KEYCMD *map, const CStr *in)
303c80476e4SDavid E. O'Brien {
304c80476e4SDavid E. O'Brien     unsigned char c = (unsigned char) *(in->buf);
305c80476e4SDavid E. O'Brien     if ((map[c] == F_XKEY) &&
306c80476e4SDavid E. O'Brien 	((map == CcKeyMap && CcAltMap[c] != F_XKEY) ||
307c80476e4SDavid E. O'Brien 	 (map == CcAltMap && CcKeyMap[c] != F_XKEY)))
308c80476e4SDavid E. O'Brien 	(void) DeleteXkey(in);
309c80476e4SDavid E. O'Brien }
310c80476e4SDavid E. O'Brien 
311c80476e4SDavid E. O'Brien int
DeleteXkey(const CStr * Xkey)31245e5710bSMark Peek DeleteXkey(const CStr *Xkey)
313c80476e4SDavid E. O'Brien {
31445e5710bSMark Peek     CStr s;
31545e5710bSMark Peek 
31645e5710bSMark Peek     s = *Xkey;
31745e5710bSMark Peek     if (s.len == 0) {
318a15e6f9aSMark Peek 	xprintf("%s",
319a15e6f9aSMark Peek 	        CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n"));
320c80476e4SDavid E. O'Brien 	return (-1);
321c80476e4SDavid E. O'Brien     }
322c80476e4SDavid E. O'Brien 
323c80476e4SDavid E. O'Brien     if (Xmap == NULL)
324c80476e4SDavid E. O'Brien 	return (0);
325c80476e4SDavid E. O'Brien 
32645e5710bSMark Peek     (void) TryDeleteNode(&Xmap, &s);
327c80476e4SDavid E. O'Brien     return (0);
328c80476e4SDavid E. O'Brien }
329c80476e4SDavid E. O'Brien 
33045e5710bSMark Peek /* Destroys str */
331c80476e4SDavid E. O'Brien static int
TryDeleteNode(XmapNode ** inptr,CStr * str)33245e5710bSMark Peek TryDeleteNode(XmapNode **inptr, CStr *str)
333c80476e4SDavid E. O'Brien {
334c80476e4SDavid E. O'Brien     XmapNode *ptr;
335c80476e4SDavid E. O'Brien 
336c80476e4SDavid E. O'Brien     ptr = *inptr;
337c80476e4SDavid E. O'Brien     /*
338c80476e4SDavid E. O'Brien      * Find a node that matches *string or allocate a new one
339c80476e4SDavid E. O'Brien      */
340c80476e4SDavid E. O'Brien     if (ptr->ch != *(str->buf)) {
341c80476e4SDavid E. O'Brien 	XmapNode *xm;
342c80476e4SDavid E. O'Brien 
343c80476e4SDavid E. O'Brien 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
344c80476e4SDavid E. O'Brien 	    if (xm->sibling->ch == *(str->buf))
345c80476e4SDavid E. O'Brien 		break;
346c80476e4SDavid E. O'Brien 	if (xm->sibling == NULL)
347c80476e4SDavid E. O'Brien 	    return (0);
34845e5710bSMark Peek 	inptr = &xm->sibling;
349c80476e4SDavid E. O'Brien 	ptr = xm->sibling;
350c80476e4SDavid E. O'Brien     }
351c80476e4SDavid E. O'Brien 
352c80476e4SDavid E. O'Brien     str->buf++;
353c80476e4SDavid E. O'Brien     str->len--;
354c80476e4SDavid E. O'Brien 
355c80476e4SDavid E. O'Brien     if (str->len == 0) {
356c80476e4SDavid E. O'Brien 	/* we're there */
357c80476e4SDavid E. O'Brien 	*inptr = ptr->sibling;
358c80476e4SDavid E. O'Brien 	ptr->sibling = NULL;
359c80476e4SDavid E. O'Brien 	PutFreeNode(ptr);
360c80476e4SDavid E. O'Brien 	return (1);
361c80476e4SDavid E. O'Brien     }
362c80476e4SDavid E. O'Brien     else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) {
363c80476e4SDavid E. O'Brien 	if (ptr->next != NULL)
364c80476e4SDavid E. O'Brien 	    return (0);
365c80476e4SDavid E. O'Brien 	*inptr = ptr->sibling;
366c80476e4SDavid E. O'Brien 	ptr->sibling = NULL;
367c80476e4SDavid E. O'Brien 	PutFreeNode(ptr);
368c80476e4SDavid E. O'Brien 	return (1);
369c80476e4SDavid E. O'Brien     }
370c80476e4SDavid E. O'Brien     else {
371c80476e4SDavid E. O'Brien 	return (0);
372c80476e4SDavid E. O'Brien     }
373c80476e4SDavid E. O'Brien }
374c80476e4SDavid E. O'Brien 
375c80476e4SDavid E. O'Brien /* PutFreeNode():
376c80476e4SDavid E. O'Brien  *	Puts a tree of nodes onto free list using free(3).
377c80476e4SDavid E. O'Brien  */
378c80476e4SDavid E. O'Brien static void
PutFreeNode(XmapNode * ptr)37945e5710bSMark Peek PutFreeNode(XmapNode *ptr)
380c80476e4SDavid E. O'Brien {
381c80476e4SDavid E. O'Brien     if (ptr == NULL)
382c80476e4SDavid E. O'Brien 	return;
383c80476e4SDavid E. O'Brien 
384c80476e4SDavid E. O'Brien     if (ptr->next != NULL) {
385c80476e4SDavid E. O'Brien 	PutFreeNode(ptr->next);
386c80476e4SDavid E. O'Brien 	ptr->next = NULL;
387c80476e4SDavid E. O'Brien     }
388c80476e4SDavid E. O'Brien 
389c80476e4SDavid E. O'Brien     PutFreeNode(ptr->sibling);
390c80476e4SDavid E. O'Brien 
391c80476e4SDavid E. O'Brien     switch (ptr->type) {
392c80476e4SDavid E. O'Brien     case XK_CMD:
393c80476e4SDavid E. O'Brien     case XK_NOD:
394c80476e4SDavid E. O'Brien 	break;
395c80476e4SDavid E. O'Brien     case XK_EXE:
396c80476e4SDavid E. O'Brien     case XK_STR:
39745e5710bSMark Peek 	xfree(ptr->val.str.buf);
398c80476e4SDavid E. O'Brien 	break;
399c80476e4SDavid E. O'Brien     default:
400c80476e4SDavid E. O'Brien 	abort();
401c80476e4SDavid E. O'Brien 	break;
402c80476e4SDavid E. O'Brien     }
40345e5710bSMark Peek     xfree(ptr);
404c80476e4SDavid E. O'Brien }
405c80476e4SDavid E. O'Brien 
406c80476e4SDavid E. O'Brien 
407c80476e4SDavid E. O'Brien /* GetFreeNode():
408c80476e4SDavid E. O'Brien  *	Returns pointer to an XmapNode for ch.
409c80476e4SDavid E. O'Brien  */
410c80476e4SDavid E. O'Brien static XmapNode *
GetFreeNode(CStr * ch)41145e5710bSMark Peek GetFreeNode(CStr *ch)
412c80476e4SDavid E. O'Brien {
413c80476e4SDavid E. O'Brien     XmapNode *ptr;
414c80476e4SDavid E. O'Brien 
41545e5710bSMark Peek     ptr = xmalloc(sizeof(XmapNode));
416c80476e4SDavid E. O'Brien     ptr->ch = ch->buf[0];
417c80476e4SDavid E. O'Brien     ptr->type = XK_NOD;
418c80476e4SDavid E. O'Brien     ptr->val.str.buf = NULL;
419c80476e4SDavid E. O'Brien     ptr->val.str.len = 0;
420c80476e4SDavid E. O'Brien     ptr->next = NULL;
421c80476e4SDavid E. O'Brien     ptr->sibling = NULL;
422c80476e4SDavid E. O'Brien     return (ptr);
423c80476e4SDavid E. O'Brien }
424c80476e4SDavid E. O'Brien 
425c80476e4SDavid E. O'Brien 
426c80476e4SDavid E. O'Brien /* PrintXKey():
427c80476e4SDavid E. O'Brien  *	Print the binding associated with Xkey key.
428c80476e4SDavid E. O'Brien  *	Print entire Xmap if null
429c80476e4SDavid E. O'Brien  */
430c80476e4SDavid E. O'Brien void
PrintXkey(const CStr * key)43145e5710bSMark Peek PrintXkey(const CStr *key)
432c80476e4SDavid E. O'Brien {
43345e5710bSMark Peek     struct Strbuf buf = Strbuf_INIT;
434c80476e4SDavid E. O'Brien     CStr cs;
435c80476e4SDavid E. O'Brien 
436c80476e4SDavid E. O'Brien     if (key) {
437c80476e4SDavid E. O'Brien 	cs.buf = key->buf;
438c80476e4SDavid E. O'Brien 	cs.len = key->len;
439c80476e4SDavid E. O'Brien     }
440c80476e4SDavid E. O'Brien     else {
441c80476e4SDavid E. O'Brien 	cs.buf = STRNULL;
442c80476e4SDavid E. O'Brien 	cs.len = 0;
443c80476e4SDavid E. O'Brien     }
444c80476e4SDavid E. O'Brien     /* do nothing if Xmap is empty and null key specified */
445c80476e4SDavid E. O'Brien     if (Xmap == NULL && cs.len == 0)
446c80476e4SDavid E. O'Brien 	return;
447c80476e4SDavid E. O'Brien 
44845e5710bSMark Peek     Strbuf_append1(&buf, '"');
44945e5710bSMark Peek     cleanup_push(&buf, Strbuf_cleanup);
45045e5710bSMark Peek     if (Lookup(&buf, &cs, Xmap) <= -1)
451c80476e4SDavid E. O'Brien 	/* key is not bound */
452c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf);
45345e5710bSMark Peek     cleanup_until(&buf);
454c80476e4SDavid E. O'Brien }
455c80476e4SDavid E. O'Brien 
456c80476e4SDavid E. O'Brien /* Lookup():
457c80476e4SDavid E. O'Brien  *	look for the string starting at node ptr.
458c80476e4SDavid E. O'Brien  *	Print if last node
459c80476e4SDavid E. O'Brien  */
460c80476e4SDavid E. O'Brien static int
Lookup(struct Strbuf * buf,const CStr * str,const XmapNode * ptr)46145e5710bSMark Peek Lookup(struct Strbuf *buf, const CStr *str, const XmapNode *ptr)
462c80476e4SDavid E. O'Brien {
463c80476e4SDavid E. O'Brien     if (ptr == NULL)
464c80476e4SDavid E. O'Brien 	return (-1);		/* cannot have null ptr */
465c80476e4SDavid E. O'Brien 
466c80476e4SDavid E. O'Brien     if (str->len == 0) {
467c80476e4SDavid E. O'Brien 	/* no more chars in string.  Enumerate from here. */
46845e5710bSMark Peek 	Enumerate(buf, ptr);
469c80476e4SDavid E. O'Brien 	return (0);
470c80476e4SDavid E. O'Brien     }
471c80476e4SDavid E. O'Brien     else {
47245e5710bSMark Peek 	/* If match put this char into buf.  Recurse */
473c80476e4SDavid E. O'Brien 	if (ptr->ch == *(str->buf)) {
474c80476e4SDavid E. O'Brien 	    /* match found */
47545e5710bSMark Peek 	    unparsech(buf, ptr->ch);
476c80476e4SDavid E. O'Brien 	    if (ptr->next != NULL) {
477c80476e4SDavid E. O'Brien 		/* not yet at leaf */
478c80476e4SDavid E. O'Brien 		CStr tstr;
479c80476e4SDavid E. O'Brien 		tstr.buf = str->buf + 1;
480c80476e4SDavid E. O'Brien 		tstr.len = str->len - 1;
48145e5710bSMark Peek 		return (Lookup(buf, &tstr, ptr->next));
482c80476e4SDavid E. O'Brien 	    }
483c80476e4SDavid E. O'Brien 	    else {
484c80476e4SDavid E. O'Brien 		/* next node is null so key should be complete */
485c80476e4SDavid E. O'Brien 		if (str->len == 1) {
48645e5710bSMark Peek 		    Strbuf_append1(buf, '"');
48745e5710bSMark Peek 		    Strbuf_terminate(buf);
48845e5710bSMark Peek 		    printOne(buf->s, &ptr->val, ptr->type);
489c80476e4SDavid E. O'Brien 		    return (0);
490c80476e4SDavid E. O'Brien 		}
491c80476e4SDavid E. O'Brien 		else
492c80476e4SDavid E. O'Brien 		    return (-1);/* mismatch -- string still has chars */
493c80476e4SDavid E. O'Brien 	    }
494c80476e4SDavid E. O'Brien 	}
495c80476e4SDavid E. O'Brien 	else {
496c80476e4SDavid E. O'Brien 	    /* no match found try sibling */
497c80476e4SDavid E. O'Brien 	    if (ptr->sibling)
49845e5710bSMark Peek 		return (Lookup(buf, str, ptr->sibling));
499c80476e4SDavid E. O'Brien 	    else
500c80476e4SDavid E. O'Brien 		return (-1);
501c80476e4SDavid E. O'Brien 	}
502c80476e4SDavid E. O'Brien     }
503c80476e4SDavid E. O'Brien }
504c80476e4SDavid E. O'Brien 
50545e5710bSMark Peek static void
Enumerate(struct Strbuf * buf,const XmapNode * ptr)50645e5710bSMark Peek Enumerate(struct Strbuf *buf, const XmapNode *ptr)
507c80476e4SDavid E. O'Brien {
50845e5710bSMark Peek     size_t old_len;
509c80476e4SDavid E. O'Brien 
510c80476e4SDavid E. O'Brien     if (ptr == NULL) {
511c80476e4SDavid E. O'Brien #ifdef DEBUG_EDIT
512c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!"));
513c80476e4SDavid E. O'Brien #endif
51445e5710bSMark Peek 	return;
515c80476e4SDavid E. O'Brien     }
516c80476e4SDavid E. O'Brien 
51745e5710bSMark Peek     old_len = buf->len;
51845e5710bSMark Peek     unparsech(buf, ptr->ch); /* put this char at end of string */
519c80476e4SDavid E. O'Brien     if (ptr->next == NULL) {
520c80476e4SDavid E. O'Brien 	/* print this Xkey and function */
52145e5710bSMark Peek 	Strbuf_append1(buf, '"');
52245e5710bSMark Peek 	Strbuf_terminate(buf);
52345e5710bSMark Peek 	printOne(buf->s, &ptr->val, ptr->type);
524c80476e4SDavid E. O'Brien     }
525c80476e4SDavid E. O'Brien     else
52645e5710bSMark Peek 	Enumerate(buf, ptr->next);
527c80476e4SDavid E. O'Brien 
528c80476e4SDavid E. O'Brien     /* go to sibling if there is one */
52945e5710bSMark Peek     if (ptr->sibling) {
53045e5710bSMark Peek 	buf->len = old_len;
53145e5710bSMark Peek 	Enumerate(buf, ptr->sibling);
53245e5710bSMark Peek     }
533c80476e4SDavid E. O'Brien }
534c80476e4SDavid E. O'Brien 
535c80476e4SDavid E. O'Brien 
536c80476e4SDavid E. O'Brien /* PrintOne():
537c80476e4SDavid E. O'Brien  *	Print the specified key and its associated
538c80476e4SDavid E. O'Brien  *	function specified by val
539c80476e4SDavid E. O'Brien  */
54045e5710bSMark Peek void
printOne(const Char * key,const XmapVal * val,int ntype)54145e5710bSMark Peek printOne(const Char *key, const XmapVal *val, int ntype)
542c80476e4SDavid E. O'Brien {
543c80476e4SDavid E. O'Brien     struct KeyFuncs *fp;
54423338178SMark Peek     static const char *fmt = "%s\n";
545c80476e4SDavid E. O'Brien 
54645e5710bSMark Peek     xprintf("%-15S-> ", key);
547c80476e4SDavid E. O'Brien     if (val != NULL)
548c80476e4SDavid E. O'Brien 	switch (ntype) {
549c80476e4SDavid E. O'Brien 	case XK_STR:
55045e5710bSMark Peek 	case XK_EXE: {
55145e5710bSMark Peek 	    unsigned char *p;
55245e5710bSMark Peek 
55345e5710bSMark Peek 	    p = unparsestring(&val->str, ntype == XK_STR ? STRQQ : STRBB);
55445e5710bSMark Peek 	    cleanup_push(p, xfree);
55545e5710bSMark Peek 	    xprintf(fmt, p);
55645e5710bSMark Peek 	    cleanup_until(p);
557c80476e4SDavid E. O'Brien 	    break;
55845e5710bSMark Peek 	}
559c80476e4SDavid E. O'Brien 	case XK_CMD:
560c80476e4SDavid E. O'Brien 	    for (fp = FuncNames; fp->name; fp++)
561c80476e4SDavid E. O'Brien 		if (val->cmd == fp->func)
562c80476e4SDavid E. O'Brien 		    xprintf(fmt, fp->name);
563c80476e4SDavid E. O'Brien 	    break;
564c80476e4SDavid E. O'Brien 	default:
565c80476e4SDavid E. O'Brien 	    abort();
566c80476e4SDavid E. O'Brien 	    break;
567c80476e4SDavid E. O'Brien 	}
568c80476e4SDavid E. O'Brien     else
56945e5710bSMark Peek 	xprintf(fmt, CGETS(9, 7, "no input"));
570c80476e4SDavid E. O'Brien }
571c80476e4SDavid E. O'Brien 
57245e5710bSMark Peek static void
unparsech(struct Strbuf * buf,Char ch)57345e5710bSMark Peek unparsech(struct Strbuf *buf, Char ch)
574c80476e4SDavid E. O'Brien {
575c80476e4SDavid E. O'Brien     if (ch == 0) {
57645e5710bSMark Peek 	Strbuf_append1(buf, '^');
57745e5710bSMark Peek 	Strbuf_append1(buf, '@');
578c80476e4SDavid E. O'Brien     }
57945e5710bSMark Peek     else if (Iscntrl(ch)) {
58045e5710bSMark Peek 	Strbuf_append1(buf, '^');
58145e5710bSMark Peek 	if (ch == CTL_ESC('\177'))
58245e5710bSMark Peek 	    Strbuf_append1(buf, '?');
58345e5710bSMark Peek 	else
5843b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
58545e5710bSMark Peek 	    Strbuf_append1(buf, ch | 0100);
5863b6eaa7bSAndrey A. Chernov #else
58745e5710bSMark Peek 	    Strbuf_append1(buf, _toebcdic[_toascii[ch]|0100]);
5883b6eaa7bSAndrey A. Chernov #endif
589c80476e4SDavid E. O'Brien     }
59045e5710bSMark Peek     else if (ch == '^') {
59145e5710bSMark Peek 	Strbuf_append1(buf, '\\');
59245e5710bSMark Peek 	Strbuf_append1(buf, '^');
59345e5710bSMark Peek     } else if (ch == '\\') {
59445e5710bSMark Peek 	Strbuf_append1(buf, '\\');
59545e5710bSMark Peek 	Strbuf_append1(buf, '\\');
59645e5710bSMark Peek     } else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) {
59745e5710bSMark Peek 	Strbuf_append1(buf, ch);
598c80476e4SDavid E. O'Brien     }
599c80476e4SDavid E. O'Brien     else {
60045e5710bSMark Peek 	Strbuf_append1(buf, '\\');
60145e5710bSMark Peek 	Strbuf_append1(buf, ((ch >> 6) & 7) + '0');
60245e5710bSMark Peek 	Strbuf_append1(buf, ((ch >> 3) & 7) + '0');
60345e5710bSMark Peek 	Strbuf_append1(buf, (ch & 7) + '0');
604c80476e4SDavid E. O'Brien     }
605c80476e4SDavid E. O'Brien }
606c80476e4SDavid E. O'Brien 
60723338178SMark Peek eChar
parseescape(const Char ** ptr)60845e5710bSMark Peek parseescape(const Char **ptr)
609c80476e4SDavid E. O'Brien {
610c80476e4SDavid E. O'Brien     const Char *p;
611c80476e4SDavid E. O'Brien     Char c;
612c80476e4SDavid E. O'Brien 
613c80476e4SDavid E. O'Brien     p = *ptr;
614c80476e4SDavid E. O'Brien 
615c80476e4SDavid E. O'Brien     if ((p[1] & CHAR) == 0) {
61645e5710bSMark Peek 	xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p);
61723338178SMark Peek 	return CHAR_ERR;
618c80476e4SDavid E. O'Brien     }
619c80476e4SDavid E. O'Brien     if ((*p & CHAR) == '\\') {
620c80476e4SDavid E. O'Brien 	p++;
621c80476e4SDavid E. O'Brien 	switch (*p & CHAR) {
622c80476e4SDavid E. O'Brien 	case 'a':
623c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\007');         /* Bell */
624c80476e4SDavid E. O'Brien 	    break;
625c80476e4SDavid E. O'Brien 	case 'b':
626c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\010');         /* Backspace */
627c80476e4SDavid E. O'Brien 	    break;
628c80476e4SDavid E. O'Brien 	case 'e':
629c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\033');         /* Escape */
630c80476e4SDavid E. O'Brien 	    break;
631c80476e4SDavid E. O'Brien 	case 'f':
632c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\014');         /* Form Feed */
633c80476e4SDavid E. O'Brien 	    break;
634c80476e4SDavid E. O'Brien 	case 'n':
635c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\012');         /* New Line */
636c80476e4SDavid E. O'Brien 	    break;
637c80476e4SDavid E. O'Brien 	case 'r':
638c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\015');         /* Carriage Return */
639c80476e4SDavid E. O'Brien 	    break;
640c80476e4SDavid E. O'Brien 	case 't':
641c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\011');         /* Horizontal Tab */
642c80476e4SDavid E. O'Brien 	    break;
643c80476e4SDavid E. O'Brien 	case 'v':
644c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\013');         /* Vertical Tab */
645c80476e4SDavid E. O'Brien 	    break;
6466767bd61SMark Peek 	case '\\':
6476767bd61SMark Peek 	    c = '\\';
6486767bd61SMark Peek 	    break;
649c80476e4SDavid E. O'Brien 	case '0':
650c80476e4SDavid E. O'Brien 	case '1':
651c80476e4SDavid E. O'Brien 	case '2':
652c80476e4SDavid E. O'Brien 	case '3':
653c80476e4SDavid E. O'Brien 	case '4':
654c80476e4SDavid E. O'Brien 	case '5':
655c80476e4SDavid E. O'Brien 	case '6':
656c80476e4SDavid E. O'Brien 	case '7':
657c80476e4SDavid E. O'Brien 	    {
65823338178SMark Peek 		int cnt, val;
65923338178SMark Peek 		Char ch;
660c80476e4SDavid E. O'Brien 
661c80476e4SDavid E. O'Brien 		for (cnt = 0, val = 0; cnt < 3; cnt++) {
662c80476e4SDavid E. O'Brien 		    ch = *p++ & CHAR;
663c80476e4SDavid E. O'Brien 		    if (ch < '0' || ch > '7') {
664c80476e4SDavid E. O'Brien 			p--;
665c80476e4SDavid E. O'Brien 			break;
666c80476e4SDavid E. O'Brien 		    }
667c80476e4SDavid E. O'Brien 		    val = (val << 3) | (ch - '0');
668c80476e4SDavid E. O'Brien 		}
66945e5710bSMark Peek 		if ((val & ~0xff) != 0) {
670a15e6f9aSMark Peek 		    xprintf("%s", CGETS(9, 9,
671c80476e4SDavid E. O'Brien 			    "Octal constant does not fit in a char.\n"));
672c80476e4SDavid E. O'Brien 		    return 0;
673c80476e4SDavid E. O'Brien 		}
6743b6eaa7bSAndrey A. Chernov #ifndef IS_ASCII
675c80476e4SDavid E. O'Brien 		if (CTL_ESC(val) != val && adrof(STRwarnebcdic))
676c80476e4SDavid E. O'Brien 		    xprintf(/*CGETS(9, 9, no NLS-String yet!*/
677c80476e4SDavid E. O'Brien 			    "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/);
678c80476e4SDavid E. O'Brien #endif
679c80476e4SDavid E. O'Brien 		c = (Char) val;
680c80476e4SDavid E. O'Brien 		--p;
681c80476e4SDavid E. O'Brien 	    }
682c80476e4SDavid E. O'Brien 	    break;
683c80476e4SDavid E. O'Brien 	default:
684c80476e4SDavid E. O'Brien 	    c = *p;
685c80476e4SDavid E. O'Brien 	    break;
686c80476e4SDavid E. O'Brien 	}
687c80476e4SDavid E. O'Brien     }
688c80476e4SDavid E. O'Brien     else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) ||
689c80476e4SDavid E. O'Brien 				    strchr("@^_?\\|[{]}", p[1] & CHAR))) {
690c80476e4SDavid E. O'Brien 	p++;
6913b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
692c80476e4SDavid E. O'Brien 	c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
6933b6eaa7bSAndrey A. Chernov #else
694c80476e4SDavid E. O'Brien 	c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
695c80476e4SDavid E. O'Brien 	if (adrof(STRwarnebcdic))
696c80476e4SDavid E. O'Brien 	    xprintf(/*CGETS(9, 9, no NLS-String yet!*/
697c80476e4SDavid E. O'Brien 		"Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/);
6983b6eaa7bSAndrey A. Chernov #endif
699c80476e4SDavid E. O'Brien     }
700c80476e4SDavid E. O'Brien     else
701*5224c2a3SDmitry Chagin 	c = *p & CHAR;
702c80476e4SDavid E. O'Brien     *ptr = p;
703c80476e4SDavid E. O'Brien     return (c);
704c80476e4SDavid E. O'Brien }
705c80476e4SDavid E. O'Brien 
706c80476e4SDavid E. O'Brien 
707c80476e4SDavid E. O'Brien unsigned char *
unparsestring(const CStr * str,const Char * sep)70845e5710bSMark Peek unparsestring(const CStr *str, const Char *sep)
709c80476e4SDavid E. O'Brien {
71045e5710bSMark Peek     unsigned char *buf, *b;
711c80476e4SDavid E. O'Brien     Char   p;
712c80476e4SDavid E. O'Brien     int l;
713c80476e4SDavid E. O'Brien 
71445e5710bSMark Peek     /* Worst-case is "\uuu" or result of wctomb() for each char from str */
71545e5710bSMark Peek     buf = xmalloc((str->len + 1) * max(4, MB_LEN_MAX));
716c80476e4SDavid E. O'Brien     b = buf;
717c80476e4SDavid E. O'Brien     if (sep[0])
7183b6eaa7bSAndrey A. Chernov #ifndef WINNT_NATIVE
719c80476e4SDavid E. O'Brien 	*b++ = sep[0];
7203b6eaa7bSAndrey A. Chernov #else /* WINNT_NATIVE */
721c80476e4SDavid E. O'Brien 	*b++ = CHAR & sep[0];
7223b6eaa7bSAndrey A. Chernov #endif /* !WINNT_NATIVE */
723c80476e4SDavid E. O'Brien 
724c80476e4SDavid E. O'Brien     for (l = 0; l < str->len; l++) {
725c80476e4SDavid E. O'Brien 	p = str->buf[l];
726c80476e4SDavid E. O'Brien 	if (Iscntrl(p)) {
727c80476e4SDavid E. O'Brien 	    *b++ = '^';
728c80476e4SDavid E. O'Brien 	    if (p == CTL_ESC('\177'))
729c80476e4SDavid E. O'Brien 		*b++ = '?';
730c80476e4SDavid E. O'Brien 	    else
73145e5710bSMark Peek #ifdef IS_ASCII
732c80476e4SDavid E. O'Brien 		*b++ = (unsigned char) (p | 0100);
7333b6eaa7bSAndrey A. Chernov #else
73445e5710bSMark Peek 		*b++ = _toebcdic[_toascii[p]|0100];
7353b6eaa7bSAndrey A. Chernov #endif
736c80476e4SDavid E. O'Brien 	}
737c80476e4SDavid E. O'Brien 	else if (p == '^' || p == '\\') {
738c80476e4SDavid E. O'Brien 	    *b++ = '\\';
739c80476e4SDavid E. O'Brien 	    *b++ = (unsigned char) p;
740c80476e4SDavid E. O'Brien 	}
74123338178SMark Peek 	else if (p == ' ' || (Isprint(p) && !Isspace(p)))
74219d2e3deSDmitry Chagin 	    b += one_wctomb((char *)b, p);
743c80476e4SDavid E. O'Brien 	else {
744c80476e4SDavid E. O'Brien 	    *b++ = '\\';
745c80476e4SDavid E. O'Brien 	    *b++ = ((p >> 6) & 7) + '0';
746c80476e4SDavid E. O'Brien 	    *b++ = ((p >> 3) & 7) + '0';
747c80476e4SDavid E. O'Brien 	    *b++ = (p & 7) + '0';
748c80476e4SDavid E. O'Brien 	}
749c80476e4SDavid E. O'Brien     }
750c80476e4SDavid E. O'Brien     if (sep[0] && sep[1])
7513b6eaa7bSAndrey A. Chernov #ifndef WINNT_NATIVE
752c80476e4SDavid E. O'Brien 	*b++ = sep[1];
7533b6eaa7bSAndrey A. Chernov #else /* WINNT_NATIVE */
754c80476e4SDavid E. O'Brien 	*b++ = CHAR & sep[1];
7553b6eaa7bSAndrey A. Chernov #endif /* !WINNT_NATIVE */
756c80476e4SDavid E. O'Brien     *b++ = 0;
757c80476e4SDavid E. O'Brien     return buf;			/* should check for overflow */
758c80476e4SDavid E. O'Brien }
759