xref: /freebsd/contrib/tcsh/ed.xmap.c (revision 3b6eaa7b1ef31985836f61a8d833b90490c337b5)
13b6eaa7bSAndrey A. Chernov /* $Header: /src/pub/tcsh/ed.xmap.c,v 3.23 2000/11/11 23:03:35 christos Exp $ */
2c80476e4SDavid E. O'Brien /*
3c80476e4SDavid E. O'Brien  * ed.xmap.c: This module contains the procedures for maintaining
4c80476e4SDavid E. O'Brien  *	      the extended-key map.
5c80476e4SDavid E. O'Brien  *
6c80476e4SDavid E. O'Brien  * 	      An extended-key (Xkey) is a sequence of keystrokes
7c80476e4SDavid E. O'Brien  *	      introduced with an sequence introducer and consisting
8c80476e4SDavid E. O'Brien  *	      of an arbitrary number of characters.  This module maintains
9c80476e4SDavid E. O'Brien  *	      a map (the Xmap) to convert these extended-key sequences
10c80476e4SDavid E. O'Brien  * 	      into input strings (XK_STR), editor functions (XK_CMD), or
11c80476e4SDavid E. O'Brien  *	      unix commands (XK_EXE). It contains the
12c80476e4SDavid E. O'Brien  *	      following externally visible functions.
13c80476e4SDavid E. O'Brien  *
14c80476e4SDavid E. O'Brien  *		int GetXkey(ch,val);
15c80476e4SDavid E. O'Brien  *		CStr *ch;
16c80476e4SDavid E. O'Brien  *		XmapVal *val;
17c80476e4SDavid E. O'Brien  *
18c80476e4SDavid E. O'Brien  *	      Looks up *ch in map and then reads characters until a
19c80476e4SDavid E. O'Brien  *	      complete match is found or a mismatch occurs. Returns the
20c80476e4SDavid E. O'Brien  *	      type of the match found (XK_STR, XK_CMD, or XK_EXE).
21c80476e4SDavid E. O'Brien  *	      Returns NULL in val.str and XK_STR for no match.
22c80476e4SDavid E. O'Brien  *	      The last character read is returned in *ch.
23c80476e4SDavid E. O'Brien  *
24c80476e4SDavid E. O'Brien  *		void AddXkey(Xkey, val, ntype);
25c80476e4SDavid E. O'Brien  *		CStr *Xkey;
26c80476e4SDavid E. O'Brien  *		XmapVal *val;
27c80476e4SDavid E. O'Brien  *		int ntype;
28c80476e4SDavid E. O'Brien  *
29c80476e4SDavid E. O'Brien  *	      Adds Xkey to the Xmap and associates the value in val with it.
30c80476e4SDavid E. O'Brien  *	      If Xkey is already is in Xmap, the new code is applied to the
31c80476e4SDavid E. O'Brien  *	      existing Xkey. Ntype specifies if code is a command, an
32c80476e4SDavid E. O'Brien  *	      out string or a unix command.
33c80476e4SDavid E. O'Brien  *
34c80476e4SDavid E. O'Brien  *	        int DeleteXkey(Xkey);
35c80476e4SDavid E. O'Brien  *	        CStr *Xkey;
36c80476e4SDavid E. O'Brien  *
37c80476e4SDavid E. O'Brien  *	      Delete the Xkey and all longer Xkeys staring with Xkey, if
38c80476e4SDavid E. O'Brien  *	      they exists.
39c80476e4SDavid E. O'Brien  *
40c80476e4SDavid E. O'Brien  *	      Warning:
41c80476e4SDavid E. O'Brien  *		If Xkey is a substring of some other Xkeys, then the longer
42c80476e4SDavid E. O'Brien  *		Xkeys are lost!!  That is, if the Xkeys "abcd" and "abcef"
43c80476e4SDavid E. O'Brien  *		are in Xmap, adding the key "abc" will cause the first two
44c80476e4SDavid E. O'Brien  *		definitions to be lost.
45c80476e4SDavid E. O'Brien  *
46c80476e4SDavid E. O'Brien  *		void ResetXmap();
47c80476e4SDavid E. O'Brien  *
48c80476e4SDavid E. O'Brien  *	      Removes all entries from Xmap and resets the defaults.
49c80476e4SDavid E. O'Brien  *
50c80476e4SDavid E. O'Brien  *		void PrintXkey(Xkey);
51c80476e4SDavid E. O'Brien  *		CStr *Xkey;
52c80476e4SDavid E. O'Brien  *
53c80476e4SDavid E. O'Brien  *	      Prints all extended keys prefixed by Xkey and their associated
54c80476e4SDavid E. O'Brien  *	      commands.
55c80476e4SDavid E. O'Brien  *
56c80476e4SDavid E. O'Brien  *	      Restrictions:
57c80476e4SDavid E. O'Brien  *	      -------------
58c80476e4SDavid E. O'Brien  *	        1) It is not possible to have one Xkey that is a
59c80476e4SDavid E. O'Brien  *		   substring of another.
60c80476e4SDavid E. O'Brien  */
61c80476e4SDavid E. O'Brien /*-
62c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
63c80476e4SDavid E. O'Brien  * All rights reserved.
64c80476e4SDavid E. O'Brien  *
65c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
66c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
67c80476e4SDavid E. O'Brien  * are met:
68c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
69c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
70c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
71c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
72c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
73c80476e4SDavid E. O'Brien  * 3. All advertising materials mentioning features or use of this software
74c80476e4SDavid E. O'Brien  *    must display the following acknowledgement:
75c80476e4SDavid E. O'Brien  *	This product includes software developed by the University of
76c80476e4SDavid E. O'Brien  *	California, Berkeley and its contributors.
77c80476e4SDavid E. O'Brien  * 4. Neither the name of the University nor the names of its contributors
78c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
79c80476e4SDavid E. O'Brien  *    without specific prior written permission.
80c80476e4SDavid E. O'Brien  *
81c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
82c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
83c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
84c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
85c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
86c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
87c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
88c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
89c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
90c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
92c80476e4SDavid E. O'Brien  */
93c80476e4SDavid E. O'Brien #include "sh.h"
94c80476e4SDavid E. O'Brien 
953b6eaa7bSAndrey A. Chernov RCSID("$Id: ed.xmap.c,v 3.23 2000/11/11 23:03:35 christos Exp $")
96c80476e4SDavid E. O'Brien 
97c80476e4SDavid E. O'Brien #include "ed.h"
98c80476e4SDavid E. O'Brien #include "ed.defns.h"
99c80476e4SDavid E. O'Brien 
100c80476e4SDavid E. O'Brien #ifndef NULL
101c80476e4SDavid E. O'Brien #define NULL 0
102c80476e4SDavid E. O'Brien #endif
103c80476e4SDavid E. O'Brien 
104c80476e4SDavid E. O'Brien /* Internal Data types and declarations */
105c80476e4SDavid E. O'Brien 
106c80476e4SDavid E. O'Brien /* The Nodes of the Xmap.  The Xmap is a linked list of these node
107c80476e4SDavid E. O'Brien  * elements
108c80476e4SDavid E. O'Brien  */
109c80476e4SDavid E. O'Brien typedef struct Xmapnode {
110c80476e4SDavid E. O'Brien     Char    ch;			/* single character of Xkey */
111c80476e4SDavid E. O'Brien     int     type;
112c80476e4SDavid E. O'Brien     XmapVal val; 		/* command code or pointer to string, if this
113c80476e4SDavid E. O'Brien 				 * is a leaf */
114c80476e4SDavid E. O'Brien     struct Xmapnode *next;	/* ptr to next char of this Xkey */
115c80476e4SDavid E. O'Brien     struct Xmapnode *sibling;	/* ptr to another Xkey with same prefix */
116c80476e4SDavid E. O'Brien } XmapNode;
117c80476e4SDavid E. O'Brien 
118c80476e4SDavid E. O'Brien static XmapNode *Xmap = NULL;	/* the current Xmap */
119c80476e4SDavid E. O'Brien #define MAXXKEY 100		/* max length of a Xkey for print putposes */
120c80476e4SDavid E. O'Brien static Char printbuf[MAXXKEY];	/* buffer for printing */
121c80476e4SDavid E. O'Brien 
122c80476e4SDavid E. O'Brien 
123c80476e4SDavid E. O'Brien /* Some declarations of procedures */
124c80476e4SDavid E. O'Brien static	int       TraverseMap	__P((XmapNode *, CStr *, XmapVal *));
125c80476e4SDavid E. O'Brien static	int       TryNode	__P((XmapNode *, CStr *, XmapVal *, int));
126c80476e4SDavid E. O'Brien static	XmapNode *GetFreeNode	__P((CStr *));
127c80476e4SDavid E. O'Brien static	void	  PutFreeNode	__P((XmapNode *));
128c80476e4SDavid E. O'Brien static	int	  TryDeleteNode	__P((XmapNode **, CStr *));
129c80476e4SDavid E. O'Brien static	int	  Lookup	__P((CStr *, XmapNode *, int));
130c80476e4SDavid E. O'Brien static	int	  Enumerate	__P((XmapNode *, int));
131c80476e4SDavid E. O'Brien static	int	  unparsech	__P((int, Char *));
132c80476e4SDavid E. O'Brien 
133c80476e4SDavid E. O'Brien 
134c80476e4SDavid E. O'Brien XmapVal *
135c80476e4SDavid E. O'Brien XmapCmd(cmd)
136c80476e4SDavid E. O'Brien     int cmd;
137c80476e4SDavid E. O'Brien {
138c80476e4SDavid E. O'Brien     static XmapVal xm;
139c80476e4SDavid E. O'Brien     xm.cmd = (KEYCMD) cmd;
140c80476e4SDavid E. O'Brien     return &xm;
141c80476e4SDavid E. O'Brien }
142c80476e4SDavid E. O'Brien 
143c80476e4SDavid E. O'Brien XmapVal *
144c80476e4SDavid E. O'Brien XmapStr(str)
145c80476e4SDavid E. O'Brien     CStr  *str;
146c80476e4SDavid E. O'Brien {
147c80476e4SDavid E. O'Brien     static XmapVal xm;
148c80476e4SDavid E. O'Brien     xm.str.len = str->len;
149c80476e4SDavid E. O'Brien     xm.str.buf = str->buf;
150c80476e4SDavid E. O'Brien     return &xm;
151c80476e4SDavid E. O'Brien }
152c80476e4SDavid E. O'Brien 
153c80476e4SDavid E. O'Brien /* ResetXmap():
154c80476e4SDavid E. O'Brien  *	Takes all nodes on Xmap and puts them on free list.  Then
155c80476e4SDavid E. O'Brien  *	initializes Xmap with arrow keys
156c80476e4SDavid E. O'Brien  */
157c80476e4SDavid E. O'Brien void
158c80476e4SDavid E. O'Brien ResetXmap()
159c80476e4SDavid E. O'Brien {
160c80476e4SDavid E. O'Brien     PutFreeNode(Xmap);
161c80476e4SDavid E. O'Brien     Xmap = NULL;
162c80476e4SDavid E. O'Brien 
163c80476e4SDavid E. O'Brien     DefaultArrowKeys();
164c80476e4SDavid E. O'Brien     return;
165c80476e4SDavid E. O'Brien }
166c80476e4SDavid E. O'Brien 
167c80476e4SDavid E. O'Brien 
168c80476e4SDavid E. O'Brien /* GetXkey():
169c80476e4SDavid E. O'Brien  *	Calls the recursive function with entry point Xmap
170c80476e4SDavid E. O'Brien  */
171c80476e4SDavid E. O'Brien int
172c80476e4SDavid E. O'Brien GetXkey(ch, val)
173c80476e4SDavid E. O'Brien     CStr     *ch;
174c80476e4SDavid E. O'Brien     XmapVal  *val;
175c80476e4SDavid E. O'Brien {
176c80476e4SDavid E. O'Brien     return (TraverseMap(Xmap, ch, val));
177c80476e4SDavid E. O'Brien }
178c80476e4SDavid E. O'Brien 
179c80476e4SDavid E. O'Brien /* TraverseMap():
180c80476e4SDavid E. O'Brien  *	recursively traverses node in tree until match or mismatch is
181c80476e4SDavid E. O'Brien  * 	found.  May read in more characters.
182c80476e4SDavid E. O'Brien  */
183c80476e4SDavid E. O'Brien static int
184c80476e4SDavid E. O'Brien TraverseMap(ptr, ch, val)
185c80476e4SDavid E. O'Brien     XmapNode *ptr;
186c80476e4SDavid E. O'Brien     CStr     *ch;
187c80476e4SDavid E. O'Brien     XmapVal  *val;
188c80476e4SDavid E. O'Brien {
189c80476e4SDavid E. O'Brien     Char    tch;
190c80476e4SDavid E. O'Brien 
191c80476e4SDavid E. O'Brien     if (ptr->ch == *(ch->buf)) {
192c80476e4SDavid E. O'Brien 	/* match found */
193c80476e4SDavid E. O'Brien 	if (ptr->next) {
194c80476e4SDavid E. O'Brien 	    /* Xkey not complete so get next char */
195c80476e4SDavid E. O'Brien 	    if (GetNextChar(&tch) != 1) {	/* if EOF or error */
196c80476e4SDavid E. O'Brien 		val->cmd = F_SEND_EOF;
197c80476e4SDavid E. O'Brien 		return XK_CMD;/* PWP: Pretend we just read an end-of-file */
198c80476e4SDavid E. O'Brien 	    }
199c80476e4SDavid E. O'Brien 	    *(ch->buf) = tch;
200c80476e4SDavid E. O'Brien 	    return (TraverseMap(ptr->next, ch, val));
201c80476e4SDavid E. O'Brien 	}
202c80476e4SDavid E. O'Brien 	else {
203c80476e4SDavid E. O'Brien 	    *val = ptr->val;
204c80476e4SDavid E. O'Brien 	    if (ptr->type != XK_CMD)
205c80476e4SDavid E. O'Brien 		*(ch->buf) = '\0';
206c80476e4SDavid E. O'Brien 	    return ptr->type;
207c80476e4SDavid E. O'Brien 	}
208c80476e4SDavid E. O'Brien     }
209c80476e4SDavid E. O'Brien     else {
210c80476e4SDavid E. O'Brien 	/* no match found here */
211c80476e4SDavid E. O'Brien 	if (ptr->sibling) {
212c80476e4SDavid E. O'Brien 	    /* try next sibling */
213c80476e4SDavid E. O'Brien 	    return (TraverseMap(ptr->sibling, ch, val));
214c80476e4SDavid E. O'Brien 	}
215c80476e4SDavid E. O'Brien 	else {
216c80476e4SDavid E. O'Brien 	    /* no next sibling -- mismatch */
217c80476e4SDavid E. O'Brien 	    val->str.buf = NULL;
218c80476e4SDavid E. O'Brien 	    val->str.len = 0;
219c80476e4SDavid E. O'Brien 	    return XK_STR;
220c80476e4SDavid E. O'Brien 	}
221c80476e4SDavid E. O'Brien     }
222c80476e4SDavid E. O'Brien }
223c80476e4SDavid E. O'Brien 
224c80476e4SDavid E. O'Brien void
225c80476e4SDavid E. O'Brien AddXkey(Xkey, val, ntype)
226c80476e4SDavid E. O'Brien     CStr    *Xkey;
227c80476e4SDavid E. O'Brien     XmapVal *val;
228c80476e4SDavid E. O'Brien     int      ntype;
229c80476e4SDavid E. O'Brien {
230c80476e4SDavid E. O'Brien     CStr cs;
231c80476e4SDavid E. O'Brien     cs.buf = Xkey->buf;
232c80476e4SDavid E. O'Brien     cs.len = Xkey->len;
233c80476e4SDavid E. O'Brien     if (Xkey->len == 0) {
234c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n"));
235c80476e4SDavid E. O'Brien 	return;
236c80476e4SDavid E. O'Brien     }
237c80476e4SDavid E. O'Brien 
238c80476e4SDavid E. O'Brien     if (ntype == XK_CMD && val->cmd == F_XKEY) {
239c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n"));
240c80476e4SDavid E. O'Brien 	return;
241c80476e4SDavid E. O'Brien     }
242c80476e4SDavid E. O'Brien 
243c80476e4SDavid E. O'Brien     if (Xmap == NULL)
244c80476e4SDavid E. O'Brien 	/* tree is initially empty.  Set up new node to match Xkey[0] */
245c80476e4SDavid E. O'Brien 	Xmap = GetFreeNode(&cs);	/* it is properly initialized */
246c80476e4SDavid E. O'Brien 
247c80476e4SDavid E. O'Brien     /* Now recurse through Xmap */
248c80476e4SDavid E. O'Brien     (void) TryNode(Xmap, &cs, val, ntype);
249c80476e4SDavid E. O'Brien     return;
250c80476e4SDavid E. O'Brien }
251c80476e4SDavid E. O'Brien 
252c80476e4SDavid E. O'Brien static int
253c80476e4SDavid E. O'Brien TryNode(ptr, str, val, ntype)
254c80476e4SDavid E. O'Brien     XmapNode *ptr;
255c80476e4SDavid E. O'Brien     CStr     *str;
256c80476e4SDavid E. O'Brien     XmapVal  *val;
257c80476e4SDavid E. O'Brien     int       ntype;
258c80476e4SDavid E. O'Brien {
259c80476e4SDavid E. O'Brien     /*
260c80476e4SDavid E. O'Brien      * Find a node that matches *string or allocate a new one
261c80476e4SDavid E. O'Brien      */
262c80476e4SDavid E. O'Brien     if (ptr->ch != *(str->buf)) {
263c80476e4SDavid E. O'Brien 	XmapNode *xm;
264c80476e4SDavid E. O'Brien 
265c80476e4SDavid E. O'Brien 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
266c80476e4SDavid E. O'Brien 	    if (xm->sibling->ch == *(str->buf))
267c80476e4SDavid E. O'Brien 		break;
268c80476e4SDavid E. O'Brien 	if (xm->sibling == NULL)
269c80476e4SDavid E. O'Brien 	    xm->sibling = GetFreeNode(str);	/* setup new node */
270c80476e4SDavid E. O'Brien 	ptr = xm->sibling;
271c80476e4SDavid E. O'Brien     }
272c80476e4SDavid E. O'Brien 
273c80476e4SDavid E. O'Brien     str->buf++;
274c80476e4SDavid E. O'Brien     str->len--;
275c80476e4SDavid E. O'Brien     if (str->len == 0) {
276c80476e4SDavid E. O'Brien 	/* we're there */
277c80476e4SDavid E. O'Brien 	if (ptr->next != NULL) {
278c80476e4SDavid E. O'Brien 	    PutFreeNode(ptr->next);	/* lose longer Xkeys with this prefix */
279c80476e4SDavid E. O'Brien 	    ptr->next = NULL;
280c80476e4SDavid E. O'Brien 	}
281c80476e4SDavid E. O'Brien 
282c80476e4SDavid E. O'Brien 	switch (ptr->type) {
283c80476e4SDavid E. O'Brien 	case XK_STR:
284c80476e4SDavid E. O'Brien 	case XK_EXE:
285c80476e4SDavid E. O'Brien 	    if (ptr->val.str.buf != NULL)
286c80476e4SDavid E. O'Brien 		xfree((ptr_t) ptr->val.str.buf);
287c80476e4SDavid E. O'Brien 	    ptr->val.str.len = 0;
288c80476e4SDavid E. O'Brien 	    break;
289c80476e4SDavid E. O'Brien 	case XK_NOD:
290c80476e4SDavid E. O'Brien 	case XK_CMD:
291c80476e4SDavid E. O'Brien 	    break;
292c80476e4SDavid E. O'Brien 	default:
293c80476e4SDavid E. O'Brien 	    abort();
294c80476e4SDavid E. O'Brien 	    break;
295c80476e4SDavid E. O'Brien 	}
296c80476e4SDavid E. O'Brien 
297c80476e4SDavid E. O'Brien 	switch (ptr->type = ntype) {
298c80476e4SDavid E. O'Brien 	case XK_CMD:
299c80476e4SDavid E. O'Brien 	    ptr->val = *val;
300c80476e4SDavid E. O'Brien 	    break;
301c80476e4SDavid E. O'Brien 	case XK_STR:
302c80476e4SDavid E. O'Brien 	case XK_EXE:
303c80476e4SDavid E. O'Brien 	    ptr->val.str.len = (val->str.len + 1) * sizeof(Char);
304c80476e4SDavid E. O'Brien 	    ptr->val.str.buf = (Char *) xmalloc((size_t) ptr->val.str.len);
305c80476e4SDavid E. O'Brien 	    (void) memmove((ptr_t) ptr->val.str.buf, (ptr_t) val->str.buf,
306c80476e4SDavid E. O'Brien 			   (size_t) ptr->val.str.len);
307c80476e4SDavid E. O'Brien 	    ptr->val.str.len = val->str.len;
308c80476e4SDavid E. O'Brien 	    break;
309c80476e4SDavid E. O'Brien 	default:
310c80476e4SDavid E. O'Brien 	    abort();
311c80476e4SDavid E. O'Brien 	    break;
312c80476e4SDavid E. O'Brien 	}
313c80476e4SDavid E. O'Brien     }
314c80476e4SDavid E. O'Brien     else {
315c80476e4SDavid E. O'Brien 	/* still more chars to go */
316c80476e4SDavid E. O'Brien 	if (ptr->next == NULL)
317c80476e4SDavid E. O'Brien 	    ptr->next = GetFreeNode(str);	/* setup new node */
318c80476e4SDavid E. O'Brien 	(void) TryNode(ptr->next, str, val, ntype);
319c80476e4SDavid E. O'Brien     }
320c80476e4SDavid E. O'Brien     return (0);
321c80476e4SDavid E. O'Brien }
322c80476e4SDavid E. O'Brien 
323c80476e4SDavid E. O'Brien void
324c80476e4SDavid E. O'Brien ClearXkey(map, in)
325c80476e4SDavid E. O'Brien     KEYCMD *map;
326c80476e4SDavid E. O'Brien     CStr   *in;
327c80476e4SDavid E. O'Brien {
328c80476e4SDavid E. O'Brien     unsigned char c = (unsigned char) *(in->buf);
329c80476e4SDavid E. O'Brien     if ((map[c] == F_XKEY) &&
330c80476e4SDavid E. O'Brien 	((map == CcKeyMap && CcAltMap[c] != F_XKEY) ||
331c80476e4SDavid E. O'Brien 	 (map == CcAltMap && CcKeyMap[c] != F_XKEY)))
332c80476e4SDavid E. O'Brien 	(void) DeleteXkey(in);
333c80476e4SDavid E. O'Brien }
334c80476e4SDavid E. O'Brien 
335c80476e4SDavid E. O'Brien int
336c80476e4SDavid E. O'Brien DeleteXkey(Xkey)
337c80476e4SDavid E. O'Brien     CStr   *Xkey;
338c80476e4SDavid E. O'Brien {
339c80476e4SDavid E. O'Brien     if (Xkey->len == 0) {
340c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n"));
341c80476e4SDavid E. O'Brien 	return (-1);
342c80476e4SDavid E. O'Brien     }
343c80476e4SDavid E. O'Brien 
344c80476e4SDavid E. O'Brien     if (Xmap == NULL)
345c80476e4SDavid E. O'Brien 	return (0);
346c80476e4SDavid E. O'Brien 
347c80476e4SDavid E. O'Brien     (void) TryDeleteNode(&Xmap, Xkey);
348c80476e4SDavid E. O'Brien     return (0);
349c80476e4SDavid E. O'Brien }
350c80476e4SDavid E. O'Brien 
351c80476e4SDavid E. O'Brien static int
352c80476e4SDavid E. O'Brien TryDeleteNode(inptr, str)
353c80476e4SDavid E. O'Brien     XmapNode **inptr;
354c80476e4SDavid E. O'Brien     CStr   *str;
355c80476e4SDavid E. O'Brien {
356c80476e4SDavid E. O'Brien     XmapNode *ptr;
357c80476e4SDavid E. O'Brien     XmapNode *prev_ptr = NULL;
358c80476e4SDavid E. O'Brien 
359c80476e4SDavid E. O'Brien     ptr = *inptr;
360c80476e4SDavid E. O'Brien     /*
361c80476e4SDavid E. O'Brien      * Find a node that matches *string or allocate a new one
362c80476e4SDavid E. O'Brien      */
363c80476e4SDavid E. O'Brien     if (ptr->ch != *(str->buf)) {
364c80476e4SDavid E. O'Brien 	XmapNode *xm;
365c80476e4SDavid E. O'Brien 
366c80476e4SDavid E. O'Brien 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
367c80476e4SDavid E. O'Brien 	    if (xm->sibling->ch == *(str->buf))
368c80476e4SDavid E. O'Brien 		break;
369c80476e4SDavid E. O'Brien 	if (xm->sibling == NULL)
370c80476e4SDavid E. O'Brien 	    return (0);
371c80476e4SDavid E. O'Brien 	prev_ptr = xm;
372c80476e4SDavid E. O'Brien 	ptr = xm->sibling;
373c80476e4SDavid E. O'Brien     }
374c80476e4SDavid E. O'Brien 
375c80476e4SDavid E. O'Brien     str->buf++;
376c80476e4SDavid E. O'Brien     str->len--;
377c80476e4SDavid E. O'Brien 
378c80476e4SDavid E. O'Brien     if (str->len == 0) {
379c80476e4SDavid E. O'Brien 	/* we're there */
380c80476e4SDavid E. O'Brien 	if (prev_ptr == NULL)
381c80476e4SDavid E. O'Brien 	    *inptr = ptr->sibling;
382c80476e4SDavid E. O'Brien 	else
383c80476e4SDavid E. O'Brien 	    prev_ptr->sibling = ptr->sibling;
384c80476e4SDavid E. O'Brien 	ptr->sibling = NULL;
385c80476e4SDavid E. O'Brien 	PutFreeNode(ptr);
386c80476e4SDavid E. O'Brien 	return (1);
387c80476e4SDavid E. O'Brien     }
388c80476e4SDavid E. O'Brien     else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) {
389c80476e4SDavid E. O'Brien 	if (ptr->next != NULL)
390c80476e4SDavid E. O'Brien 	    return (0);
391c80476e4SDavid E. O'Brien 	if (prev_ptr == NULL)
392c80476e4SDavid E. O'Brien 	    *inptr = ptr->sibling;
393c80476e4SDavid E. O'Brien 	else
394c80476e4SDavid E. O'Brien 	    prev_ptr->sibling = ptr->sibling;
395c80476e4SDavid E. O'Brien 	ptr->sibling = NULL;
396c80476e4SDavid E. O'Brien 	PutFreeNode(ptr);
397c80476e4SDavid E. O'Brien 	return (1);
398c80476e4SDavid E. O'Brien     }
399c80476e4SDavid E. O'Brien     else {
400c80476e4SDavid E. O'Brien 	return (0);
401c80476e4SDavid E. O'Brien     }
402c80476e4SDavid E. O'Brien }
403c80476e4SDavid E. O'Brien 
404c80476e4SDavid E. O'Brien /* PutFreeNode():
405c80476e4SDavid E. O'Brien  *	Puts a tree of nodes onto free list using free(3).
406c80476e4SDavid E. O'Brien  */
407c80476e4SDavid E. O'Brien static void
408c80476e4SDavid E. O'Brien PutFreeNode(ptr)
409c80476e4SDavid E. O'Brien     XmapNode *ptr;
410c80476e4SDavid E. O'Brien {
411c80476e4SDavid E. O'Brien     if (ptr == NULL)
412c80476e4SDavid E. O'Brien 	return;
413c80476e4SDavid E. O'Brien 
414c80476e4SDavid E. O'Brien     if (ptr->next != NULL) {
415c80476e4SDavid E. O'Brien 	PutFreeNode(ptr->next);
416c80476e4SDavid E. O'Brien 	ptr->next = NULL;
417c80476e4SDavid E. O'Brien     }
418c80476e4SDavid E. O'Brien 
419c80476e4SDavid E. O'Brien     PutFreeNode(ptr->sibling);
420c80476e4SDavid E. O'Brien 
421c80476e4SDavid E. O'Brien     switch (ptr->type) {
422c80476e4SDavid E. O'Brien     case XK_CMD:
423c80476e4SDavid E. O'Brien     case XK_NOD:
424c80476e4SDavid E. O'Brien 	break;
425c80476e4SDavid E. O'Brien     case XK_EXE:
426c80476e4SDavid E. O'Brien     case XK_STR:
427c80476e4SDavid E. O'Brien 	if (ptr->val.str.buf != NULL)
428c80476e4SDavid E. O'Brien 	    xfree((ptr_t) ptr->val.str.buf);
429c80476e4SDavid E. O'Brien 	break;
430c80476e4SDavid E. O'Brien     default:
431c80476e4SDavid E. O'Brien 	abort();
432c80476e4SDavid E. O'Brien 	break;
433c80476e4SDavid E. O'Brien     }
434c80476e4SDavid E. O'Brien     xfree((ptr_t) ptr);
435c80476e4SDavid E. O'Brien }
436c80476e4SDavid E. O'Brien 
437c80476e4SDavid E. O'Brien 
438c80476e4SDavid E. O'Brien /* GetFreeNode():
439c80476e4SDavid E. O'Brien  *	Returns pointer to an XmapNode for ch.
440c80476e4SDavid E. O'Brien  */
441c80476e4SDavid E. O'Brien static XmapNode *
442c80476e4SDavid E. O'Brien GetFreeNode(ch)
443c80476e4SDavid E. O'Brien     CStr *ch;
444c80476e4SDavid E. O'Brien {
445c80476e4SDavid E. O'Brien     XmapNode *ptr;
446c80476e4SDavid E. O'Brien 
447c80476e4SDavid E. O'Brien     ptr = (XmapNode *) xmalloc((size_t) sizeof(XmapNode));
448c80476e4SDavid E. O'Brien     ptr->ch = ch->buf[0];
449c80476e4SDavid E. O'Brien     ptr->type = XK_NOD;
450c80476e4SDavid E. O'Brien     ptr->val.str.buf = NULL;
451c80476e4SDavid E. O'Brien     ptr->val.str.len = 0;
452c80476e4SDavid E. O'Brien     ptr->next = NULL;
453c80476e4SDavid E. O'Brien     ptr->sibling = NULL;
454c80476e4SDavid E. O'Brien     return (ptr);
455c80476e4SDavid E. O'Brien }
456c80476e4SDavid E. O'Brien 
457c80476e4SDavid E. O'Brien 
458c80476e4SDavid E. O'Brien /* PrintXKey():
459c80476e4SDavid E. O'Brien  *	Print the binding associated with Xkey key.
460c80476e4SDavid E. O'Brien  *	Print entire Xmap if null
461c80476e4SDavid E. O'Brien  */
462c80476e4SDavid E. O'Brien void
463c80476e4SDavid E. O'Brien PrintXkey(key)
464c80476e4SDavid E. O'Brien     CStr   *key;
465c80476e4SDavid E. O'Brien {
466c80476e4SDavid E. O'Brien     CStr cs;
467c80476e4SDavid E. O'Brien 
468c80476e4SDavid E. O'Brien     if (key) {
469c80476e4SDavid E. O'Brien 	cs.buf = key->buf;
470c80476e4SDavid E. O'Brien 	cs.len = key->len;
471c80476e4SDavid E. O'Brien     }
472c80476e4SDavid E. O'Brien     else {
473c80476e4SDavid E. O'Brien 	cs.buf = STRNULL;
474c80476e4SDavid E. O'Brien 	cs.len = 0;
475c80476e4SDavid E. O'Brien     }
476c80476e4SDavid E. O'Brien     /* do nothing if Xmap is empty and null key specified */
477c80476e4SDavid E. O'Brien     if (Xmap == NULL && cs.len == 0)
478c80476e4SDavid E. O'Brien 	return;
479c80476e4SDavid E. O'Brien 
480c80476e4SDavid E. O'Brien     printbuf[0] =  '"';
481c80476e4SDavid E. O'Brien     if (Lookup(&cs, Xmap, 1) <= -1)
482c80476e4SDavid E. O'Brien 	/* key is not bound */
483c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf);
484c80476e4SDavid E. O'Brien     return;
485c80476e4SDavid E. O'Brien }
486c80476e4SDavid E. O'Brien 
487c80476e4SDavid E. O'Brien /* Lookup():
488c80476e4SDavid E. O'Brien  *	look for the string starting at node ptr.
489c80476e4SDavid E. O'Brien  *	Print if last node
490c80476e4SDavid E. O'Brien  */
491c80476e4SDavid E. O'Brien static int
492c80476e4SDavid E. O'Brien Lookup(str, ptr, cnt)
493c80476e4SDavid E. O'Brien     CStr   *str;
494c80476e4SDavid E. O'Brien     XmapNode *ptr;
495c80476e4SDavid E. O'Brien     int     cnt;
496c80476e4SDavid E. O'Brien {
497c80476e4SDavid E. O'Brien     int     ncnt;
498c80476e4SDavid E. O'Brien 
499c80476e4SDavid E. O'Brien     if (ptr == NULL)
500c80476e4SDavid E. O'Brien 	return (-1);		/* cannot have null ptr */
501c80476e4SDavid E. O'Brien 
502c80476e4SDavid E. O'Brien     if (str->len == 0) {
503c80476e4SDavid E. O'Brien 	/* no more chars in string.  Enumerate from here. */
504c80476e4SDavid E. O'Brien 	(void) Enumerate(ptr, cnt);
505c80476e4SDavid E. O'Brien 	return (0);
506c80476e4SDavid E. O'Brien     }
507c80476e4SDavid E. O'Brien     else {
508c80476e4SDavid E. O'Brien 	/* If match put this char into printbuf.  Recurse */
509c80476e4SDavid E. O'Brien 	if (ptr->ch == *(str->buf)) {
510c80476e4SDavid E. O'Brien 	    /* match found */
511c80476e4SDavid E. O'Brien 	    ncnt = unparsech(cnt, &ptr->ch);
512c80476e4SDavid E. O'Brien 	    if (ptr->next != NULL) {
513c80476e4SDavid E. O'Brien 		/* not yet at leaf */
514c80476e4SDavid E. O'Brien 		CStr tstr;
515c80476e4SDavid E. O'Brien 		tstr.buf = str->buf + 1;
516c80476e4SDavid E. O'Brien 		tstr.len = str->len - 1;
517c80476e4SDavid E. O'Brien 		return (Lookup(&tstr, ptr->next, ncnt + 1));
518c80476e4SDavid E. O'Brien 	    }
519c80476e4SDavid E. O'Brien 	    else {
520c80476e4SDavid E. O'Brien 		/* next node is null so key should be complete */
521c80476e4SDavid E. O'Brien 		if (str->len == 1) {
522c80476e4SDavid E. O'Brien 		    CStr pb;
523c80476e4SDavid E. O'Brien 		    printbuf[ncnt + 1] = '"';
524c80476e4SDavid E. O'Brien 		    printbuf[ncnt + 2] = '\0';
525c80476e4SDavid E. O'Brien 		    pb.buf = printbuf;
526c80476e4SDavid E. O'Brien 		    pb.len = ncnt + 2;
527c80476e4SDavid E. O'Brien 		    (void) printOne(&pb, &ptr->val, ptr->type);
528c80476e4SDavid E. O'Brien 		    return (0);
529c80476e4SDavid E. O'Brien 		}
530c80476e4SDavid E. O'Brien 		else
531c80476e4SDavid E. O'Brien 		    return (-1);/* mismatch -- string still has chars */
532c80476e4SDavid E. O'Brien 	    }
533c80476e4SDavid E. O'Brien 	}
534c80476e4SDavid E. O'Brien 	else {
535c80476e4SDavid E. O'Brien 	    /* no match found try sibling */
536c80476e4SDavid E. O'Brien 	    if (ptr->sibling)
537c80476e4SDavid E. O'Brien 		return (Lookup(str, ptr->sibling, cnt));
538c80476e4SDavid E. O'Brien 	    else
539c80476e4SDavid E. O'Brien 		return (-1);
540c80476e4SDavid E. O'Brien 	}
541c80476e4SDavid E. O'Brien     }
542c80476e4SDavid E. O'Brien }
543c80476e4SDavid E. O'Brien 
544c80476e4SDavid E. O'Brien static int
545c80476e4SDavid E. O'Brien Enumerate(ptr, cnt)
546c80476e4SDavid E. O'Brien     XmapNode *ptr;
547c80476e4SDavid E. O'Brien     int     cnt;
548c80476e4SDavid E. O'Brien {
549c80476e4SDavid E. O'Brien     int     ncnt;
550c80476e4SDavid E. O'Brien 
551c80476e4SDavid E. O'Brien     if (cnt >= MAXXKEY - 5) {	/* buffer too small */
552c80476e4SDavid E. O'Brien 	printbuf[++cnt] = '"';
553c80476e4SDavid E. O'Brien 	printbuf[++cnt] = '\0';
554c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 5,
555c80476e4SDavid E. O'Brien 		"Some extended keys too long for internal print buffer"));
556c80476e4SDavid E. O'Brien 	xprintf(" \"%S...\"\n", printbuf);
557c80476e4SDavid E. O'Brien 	return (0);
558c80476e4SDavid E. O'Brien     }
559c80476e4SDavid E. O'Brien 
560c80476e4SDavid E. O'Brien     if (ptr == NULL) {
561c80476e4SDavid E. O'Brien #ifdef DEBUG_EDIT
562c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!"));
563c80476e4SDavid E. O'Brien #endif
564c80476e4SDavid E. O'Brien 	return (-1);
565c80476e4SDavid E. O'Brien     }
566c80476e4SDavid E. O'Brien 
567c80476e4SDavid E. O'Brien     ncnt = unparsech(cnt, &ptr->ch); /* put this char at end of string */
568c80476e4SDavid E. O'Brien     if (ptr->next == NULL) {
569c80476e4SDavid E. O'Brien 	CStr pb;
570c80476e4SDavid E. O'Brien 	/* print this Xkey and function */
571c80476e4SDavid E. O'Brien 	printbuf[++ncnt] = '"';
572c80476e4SDavid E. O'Brien 	printbuf[++ncnt] = '\0';
573c80476e4SDavid E. O'Brien 	pb.buf = printbuf;
574c80476e4SDavid E. O'Brien 	pb.len = ncnt;
575c80476e4SDavid E. O'Brien 	(void) printOne(&pb, &ptr->val, ptr->type);
576c80476e4SDavid E. O'Brien     }
577c80476e4SDavid E. O'Brien     else
578c80476e4SDavid E. O'Brien 	(void) Enumerate(ptr->next, ncnt + 1);
579c80476e4SDavid E. O'Brien 
580c80476e4SDavid E. O'Brien     /* go to sibling if there is one */
581c80476e4SDavid E. O'Brien     if (ptr->sibling)
582c80476e4SDavid E. O'Brien 	(void) Enumerate(ptr->sibling, cnt);
583c80476e4SDavid E. O'Brien     return (0);
584c80476e4SDavid E. O'Brien }
585c80476e4SDavid E. O'Brien 
586c80476e4SDavid E. O'Brien 
587c80476e4SDavid E. O'Brien /* PrintOne():
588c80476e4SDavid E. O'Brien  *	Print the specified key and its associated
589c80476e4SDavid E. O'Brien  *	function specified by val
590c80476e4SDavid E. O'Brien  */
591c80476e4SDavid E. O'Brien int
592c80476e4SDavid E. O'Brien printOne(key, val, ntype)
593c80476e4SDavid E. O'Brien     CStr    *key;
594c80476e4SDavid E. O'Brien     XmapVal *val;
595c80476e4SDavid E. O'Brien     int      ntype;
596c80476e4SDavid E. O'Brien {
597c80476e4SDavid E. O'Brien     struct KeyFuncs *fp;
598c80476e4SDavid E. O'Brien     unsigned char unparsbuf[200];
599c80476e4SDavid E. O'Brien     static char *fmt = "%s\n";
600c80476e4SDavid E. O'Brien 
601c80476e4SDavid E. O'Brien     xprintf("%-15S-> ", key->buf);
602c80476e4SDavid E. O'Brien     if (val != NULL)
603c80476e4SDavid E. O'Brien 	switch (ntype) {
604c80476e4SDavid E. O'Brien 	case XK_STR:
605c80476e4SDavid E. O'Brien 	case XK_EXE:
606c80476e4SDavid E. O'Brien 	    xprintf(fmt, unparsestring(&val->str, unparsbuf,
607c80476e4SDavid E. O'Brien 				       ntype == XK_STR ? STRQQ : STRBB));
608c80476e4SDavid E. O'Brien 	    break;
609c80476e4SDavid E. O'Brien 	case XK_CMD:
610c80476e4SDavid E. O'Brien 	    for (fp = FuncNames; fp->name; fp++)
611c80476e4SDavid E. O'Brien 		if (val->cmd == fp->func)
612c80476e4SDavid E. O'Brien 		    xprintf(fmt, fp->name);
613c80476e4SDavid E. O'Brien 		break;
614c80476e4SDavid E. O'Brien 	default:
615c80476e4SDavid E. O'Brien 	    abort();
616c80476e4SDavid E. O'Brien 	    break;
617c80476e4SDavid E. O'Brien 	}
618c80476e4SDavid E. O'Brien     else
619c80476e4SDavid E. O'Brien 	xprintf(fmt, key, CGETS(9, 7, "no input"));
620c80476e4SDavid E. O'Brien     return (0);
621c80476e4SDavid E. O'Brien }
622c80476e4SDavid E. O'Brien 
623c80476e4SDavid E. O'Brien static int
624c80476e4SDavid E. O'Brien unparsech(cnt, ch)
625c80476e4SDavid E. O'Brien     int   cnt;
626c80476e4SDavid E. O'Brien     Char  *ch;
627c80476e4SDavid E. O'Brien {
628c80476e4SDavid E. O'Brien     if (ch == 0) {
629c80476e4SDavid E. O'Brien 	printbuf[cnt++] = '^';
630c80476e4SDavid E. O'Brien 	printbuf[cnt] = '@';
631c80476e4SDavid E. O'Brien 	return cnt;
632c80476e4SDavid E. O'Brien     }
633c80476e4SDavid E. O'Brien 
634c80476e4SDavid E. O'Brien     if (Iscntrl(*ch)) {
6353b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
636c80476e4SDavid E. O'Brien 	printbuf[cnt++] = '^';
637c80476e4SDavid E. O'Brien 	if (*ch == CTL_ESC('\177'))
638c80476e4SDavid E. O'Brien 	    printbuf[cnt] = '?';
639c80476e4SDavid E. O'Brien 	else
640c80476e4SDavid E. O'Brien 	    printbuf[cnt] = *ch | 0100;
6413b6eaa7bSAndrey A. Chernov #else
642c80476e4SDavid E. O'Brien 	if (*ch == CTL_ESC('\177'))
643c80476e4SDavid E. O'Brien 	{
644c80476e4SDavid E. O'Brien 		printbuf[cnt++] = '^';
645c80476e4SDavid E. O'Brien 		printbuf[cnt] = '?';
646c80476e4SDavid E. O'Brien 	}
647c80476e4SDavid E. O'Brien 	else if (Isupper(_toebcdic[_toascii[*ch]|0100])
648c80476e4SDavid E. O'Brien 		|| strchr("@[\\]^_", _toebcdic[_toascii[*ch]|0100]) != NULL)
649c80476e4SDavid E. O'Brien 	{
650c80476e4SDavid E. O'Brien 		printbuf[cnt++] = '^';
651c80476e4SDavid E. O'Brien 		printbuf[cnt] = _toebcdic[_toascii[*ch]|0100];
652c80476e4SDavid E. O'Brien 	}
653c80476e4SDavid E. O'Brien 	else
654c80476e4SDavid E. O'Brien 	{
655c80476e4SDavid E. O'Brien 		printbuf[cnt++] = '\\';
656c80476e4SDavid E. O'Brien 		printbuf[cnt++] = ((*ch >> 6) & 7) + '0';
657c80476e4SDavid E. O'Brien 		printbuf[cnt++] = ((*ch >> 3) & 7) + '0';
658c80476e4SDavid E. O'Brien 		printbuf[cnt] = (*ch & 7) + '0';
659c80476e4SDavid E. O'Brien 	}
6603b6eaa7bSAndrey A. Chernov #endif
661c80476e4SDavid E. O'Brien     }
662c80476e4SDavid E. O'Brien     else if (*ch == '^') {
663c80476e4SDavid E. O'Brien 	printbuf[cnt++] = '\\';
664c80476e4SDavid E. O'Brien 	printbuf[cnt] = '^';
665c80476e4SDavid E. O'Brien     }
666c80476e4SDavid E. O'Brien     else if (*ch == '\\') {
667c80476e4SDavid E. O'Brien 	printbuf[cnt++] = '\\';
668c80476e4SDavid E. O'Brien 	printbuf[cnt] = '\\';
669c80476e4SDavid E. O'Brien     }
670c80476e4SDavid E. O'Brien     else if (*ch == ' ' || (Isprint(*ch) && !Isspace(*ch))) {
671c80476e4SDavid E. O'Brien 	printbuf[cnt] = *ch;
672c80476e4SDavid E. O'Brien     }
673c80476e4SDavid E. O'Brien     else {
674c80476e4SDavid E. O'Brien 	printbuf[cnt++] = '\\';
675c80476e4SDavid E. O'Brien 	printbuf[cnt++] = ((*ch >> 6) & 7) + '0';
676c80476e4SDavid E. O'Brien 	printbuf[cnt++] = ((*ch >> 3) & 7) + '0';
677c80476e4SDavid E. O'Brien 	printbuf[cnt] = (*ch & 7) + '0';
678c80476e4SDavid E. O'Brien     }
679c80476e4SDavid E. O'Brien     return cnt;
680c80476e4SDavid E. O'Brien }
681c80476e4SDavid E. O'Brien 
682c80476e4SDavid E. O'Brien int
683c80476e4SDavid E. O'Brien parseescape(ptr)
684c80476e4SDavid E. O'Brien     const Char  **ptr;
685c80476e4SDavid E. O'Brien {
686c80476e4SDavid E. O'Brien     const Char *p;
687c80476e4SDavid E. O'Brien     Char c;
688c80476e4SDavid E. O'Brien 
689c80476e4SDavid E. O'Brien     p = *ptr;
690c80476e4SDavid E. O'Brien 
691c80476e4SDavid E. O'Brien     if ((p[1] & CHAR) == 0) {
692c80476e4SDavid E. O'Brien 	xprintf(CGETS(9, 8, "Something must follow: %c\n"), *p);
693c80476e4SDavid E. O'Brien 	return -1;
694c80476e4SDavid E. O'Brien     }
695c80476e4SDavid E. O'Brien     if ((*p & CHAR) == '\\') {
696c80476e4SDavid E. O'Brien 	p++;
697c80476e4SDavid E. O'Brien 	switch (*p & CHAR) {
698c80476e4SDavid E. O'Brien 	case 'a':
699c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\007');         /* Bell */
700c80476e4SDavid E. O'Brien 	    break;
701c80476e4SDavid E. O'Brien 	case 'b':
702c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\010');         /* Backspace */
703c80476e4SDavid E. O'Brien 	    break;
704c80476e4SDavid E. O'Brien 	case 'e':
705c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\033');         /* Escape */
706c80476e4SDavid E. O'Brien 	    break;
707c80476e4SDavid E. O'Brien 	case 'f':
708c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\014');         /* Form Feed */
709c80476e4SDavid E. O'Brien 	    break;
710c80476e4SDavid E. O'Brien 	case 'n':
711c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\012');         /* New Line */
712c80476e4SDavid E. O'Brien 	    break;
713c80476e4SDavid E. O'Brien 	case 'r':
714c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\015');         /* Carriage Return */
715c80476e4SDavid E. O'Brien 	    break;
716c80476e4SDavid E. O'Brien 	case 't':
717c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\011');         /* Horizontal Tab */
718c80476e4SDavid E. O'Brien 	    break;
719c80476e4SDavid E. O'Brien 	case 'v':
720c80476e4SDavid E. O'Brien 	    c = CTL_ESC('\013');         /* Vertical Tab */
721c80476e4SDavid E. O'Brien 	    break;
722c80476e4SDavid E. O'Brien 	case '0':
723c80476e4SDavid E. O'Brien 	case '1':
724c80476e4SDavid E. O'Brien 	case '2':
725c80476e4SDavid E. O'Brien 	case '3':
726c80476e4SDavid E. O'Brien 	case '4':
727c80476e4SDavid E. O'Brien 	case '5':
728c80476e4SDavid E. O'Brien 	case '6':
729c80476e4SDavid E. O'Brien 	case '7':
730c80476e4SDavid E. O'Brien 	    {
731c80476e4SDavid E. O'Brien 		register int cnt, val, ch;
732c80476e4SDavid E. O'Brien 
733c80476e4SDavid E. O'Brien 		for (cnt = 0, val = 0; cnt < 3; cnt++) {
734c80476e4SDavid E. O'Brien 		    ch = *p++ & CHAR;
735c80476e4SDavid E. O'Brien 		    if (ch < '0' || ch > '7') {
736c80476e4SDavid E. O'Brien 			p--;
737c80476e4SDavid E. O'Brien 			break;
738c80476e4SDavid E. O'Brien 		    }
739c80476e4SDavid E. O'Brien 		    val = (val << 3) | (ch - '0');
740c80476e4SDavid E. O'Brien 		}
741c80476e4SDavid E. O'Brien 		if ((val & 0xffffff00) != 0) {
742c80476e4SDavid E. O'Brien 		    xprintf(CGETS(9, 9,
743c80476e4SDavid E. O'Brien 			    "Octal constant does not fit in a char.\n"));
744c80476e4SDavid E. O'Brien 		    return 0;
745c80476e4SDavid E. O'Brien 		}
7463b6eaa7bSAndrey A. Chernov #ifndef IS_ASCII
747c80476e4SDavid E. O'Brien 		if (CTL_ESC(val) != val && adrof(STRwarnebcdic))
748c80476e4SDavid E. O'Brien 		    xprintf(/*CGETS(9, 9, no NLS-String yet!*/
749c80476e4SDavid E. O'Brien 			    "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/);
750c80476e4SDavid E. O'Brien #endif
751c80476e4SDavid E. O'Brien 		c = (Char) val;
752c80476e4SDavid E. O'Brien 		--p;
753c80476e4SDavid E. O'Brien 	    }
754c80476e4SDavid E. O'Brien 	    break;
755c80476e4SDavid E. O'Brien 	default:
756c80476e4SDavid E. O'Brien 	    c = *p;
757c80476e4SDavid E. O'Brien 	    break;
758c80476e4SDavid E. O'Brien 	}
759c80476e4SDavid E. O'Brien     }
760c80476e4SDavid E. O'Brien     else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) ||
761c80476e4SDavid E. O'Brien 				    strchr("@^_?\\|[{]}", p[1] & CHAR))) {
762c80476e4SDavid E. O'Brien 	p++;
7633b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
764c80476e4SDavid E. O'Brien 	c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
7653b6eaa7bSAndrey A. Chernov #else
766c80476e4SDavid E. O'Brien 	c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
767c80476e4SDavid E. O'Brien 	if (adrof(STRwarnebcdic))
768c80476e4SDavid E. O'Brien 	    xprintf(/*CGETS(9, 9, no NLS-String yet!*/
769c80476e4SDavid E. O'Brien 		"Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/);
7703b6eaa7bSAndrey A. Chernov #endif
771c80476e4SDavid E. O'Brien     }
772c80476e4SDavid E. O'Brien     else
773c80476e4SDavid E. O'Brien 	c = *p;
774c80476e4SDavid E. O'Brien     *ptr = p;
775c80476e4SDavid E. O'Brien     return (c);
776c80476e4SDavid E. O'Brien }
777c80476e4SDavid E. O'Brien 
778c80476e4SDavid E. O'Brien 
779c80476e4SDavid E. O'Brien unsigned char *
780c80476e4SDavid E. O'Brien unparsestring(str, buf, sep)
781c80476e4SDavid E. O'Brien     CStr   *str;
782c80476e4SDavid E. O'Brien     unsigned char *buf;
783c80476e4SDavid E. O'Brien     Char   *sep;
784c80476e4SDavid E. O'Brien {
785c80476e4SDavid E. O'Brien     unsigned char *b;
786c80476e4SDavid E. O'Brien     Char   p;
787c80476e4SDavid E. O'Brien     int l;
788c80476e4SDavid E. O'Brien 
789c80476e4SDavid E. O'Brien     b = buf;
790c80476e4SDavid E. O'Brien     if (sep[0])
7913b6eaa7bSAndrey A. Chernov #ifndef WINNT_NATIVE
792c80476e4SDavid E. O'Brien 	*b++ = sep[0];
7933b6eaa7bSAndrey A. Chernov #else /* WINNT_NATIVE */
794c80476e4SDavid E. O'Brien 	*b++ = CHAR & sep[0];
7953b6eaa7bSAndrey A. Chernov #endif /* !WINNT_NATIVE */
796c80476e4SDavid E. O'Brien 
797c80476e4SDavid E. O'Brien     for (l = 0; l < str->len; l++) {
798c80476e4SDavid E. O'Brien 	p = str->buf[l];
799c80476e4SDavid E. O'Brien 	if (Iscntrl(p)) {
8003b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
801c80476e4SDavid E. O'Brien 	    *b++ = '^';
802c80476e4SDavid E. O'Brien 	    if (p == CTL_ESC('\177'))
803c80476e4SDavid E. O'Brien 		*b++ = '?';
804c80476e4SDavid E. O'Brien 	    else
805c80476e4SDavid E. O'Brien 		*b++ = (unsigned char) (p | 0100);
8063b6eaa7bSAndrey A. Chernov #else
807c80476e4SDavid E. O'Brien 	    if (_toascii[p] == '\177' || Isupper(_toebcdic[_toascii[p]|0100])
808c80476e4SDavid E. O'Brien 		 || strchr("@[\\]^_", _toebcdic[_toascii[p]|0100]) != NULL)
809c80476e4SDavid E. O'Brien 	    {
810c80476e4SDavid E. O'Brien 		*b++ = '^';
811c80476e4SDavid E. O'Brien 		*b++ = (_toascii[p] == '\177') ? '?' : _toebcdic[_toascii[p]|0100];
812c80476e4SDavid E. O'Brien 	    }
813c80476e4SDavid E. O'Brien 	    else
814c80476e4SDavid E. O'Brien 	    {
815c80476e4SDavid E. O'Brien 		*b++ = '\\';
816c80476e4SDavid E. O'Brien 		*b++ = ((p >> 6) & 7) + '0';
817c80476e4SDavid E. O'Brien 		*b++ = ((p >> 3) & 7) + '0';
818c80476e4SDavid E. O'Brien 		*b++ = (p & 7) + '0';
819c80476e4SDavid E. O'Brien 	    }
8203b6eaa7bSAndrey A. Chernov #endif
821c80476e4SDavid E. O'Brien 	}
822c80476e4SDavid E. O'Brien 	else if (p == '^' || p == '\\') {
823c80476e4SDavid E. O'Brien 	    *b++ = '\\';
824c80476e4SDavid E. O'Brien 	    *b++ = (unsigned char) p;
825c80476e4SDavid E. O'Brien 	}
826c80476e4SDavid E. O'Brien 	else if (p == ' ' || (Isprint(p) && !Isspace(p))) {
827c80476e4SDavid E. O'Brien 	    *b++ = (unsigned char) p;
828c80476e4SDavid E. O'Brien 	}
829c80476e4SDavid E. O'Brien 	else {
830c80476e4SDavid E. O'Brien 	    *b++ = '\\';
831c80476e4SDavid E. O'Brien 	    *b++ = ((p >> 6) & 7) + '0';
832c80476e4SDavid E. O'Brien 	    *b++ = ((p >> 3) & 7) + '0';
833c80476e4SDavid E. O'Brien 	    *b++ = (p & 7) + '0';
834c80476e4SDavid E. O'Brien 	}
835c80476e4SDavid E. O'Brien     }
836c80476e4SDavid E. O'Brien     if (sep[0] && sep[1])
8373b6eaa7bSAndrey A. Chernov #ifndef WINNT_NATIVE
838c80476e4SDavid E. O'Brien 	*b++ = sep[1];
8393b6eaa7bSAndrey A. Chernov #else /* WINNT_NATIVE */
840c80476e4SDavid E. O'Brien 	*b++ = CHAR & sep[1];
8413b6eaa7bSAndrey A. Chernov #endif /* !WINNT_NATIVE */
842c80476e4SDavid E. O'Brien     *b++ = 0;
843c80476e4SDavid E. O'Brien     return buf;			/* should check for overflow */
844c80476e4SDavid E. O'Brien }
845