1*d0ef721eSBaptiste Daroussin /* $NetBSD: keymacro.c,v 1.24 2019/07/23 10:18:52 christos Exp $ */
2*d0ef721eSBaptiste Daroussin
3*d0ef721eSBaptiste Daroussin /*-
4*d0ef721eSBaptiste Daroussin * Copyright (c) 1992, 1993
5*d0ef721eSBaptiste Daroussin * The Regents of the University of California. All rights reserved.
6*d0ef721eSBaptiste Daroussin *
7*d0ef721eSBaptiste Daroussin * This code is derived from software contributed to Berkeley by
8*d0ef721eSBaptiste Daroussin * Christos Zoulas of Cornell University.
9*d0ef721eSBaptiste Daroussin *
10*d0ef721eSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without
11*d0ef721eSBaptiste Daroussin * modification, are permitted provided that the following conditions
12*d0ef721eSBaptiste Daroussin * are met:
13*d0ef721eSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright
14*d0ef721eSBaptiste Daroussin * notice, this list of conditions and the following disclaimer.
15*d0ef721eSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright
16*d0ef721eSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the
17*d0ef721eSBaptiste Daroussin * documentation and/or other materials provided with the distribution.
18*d0ef721eSBaptiste Daroussin * 3. Neither the name of the University nor the names of its contributors
19*d0ef721eSBaptiste Daroussin * may be used to endorse or promote products derived from this software
20*d0ef721eSBaptiste Daroussin * without specific prior written permission.
21*d0ef721eSBaptiste Daroussin *
22*d0ef721eSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*d0ef721eSBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*d0ef721eSBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*d0ef721eSBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*d0ef721eSBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*d0ef721eSBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*d0ef721eSBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*d0ef721eSBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*d0ef721eSBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*d0ef721eSBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*d0ef721eSBaptiste Daroussin * SUCH DAMAGE.
33*d0ef721eSBaptiste Daroussin */
34*d0ef721eSBaptiste Daroussin
35*d0ef721eSBaptiste Daroussin #include "config.h"
36*d0ef721eSBaptiste Daroussin #if !defined(lint) && !defined(SCCSID)
37*d0ef721eSBaptiste Daroussin #if 0
38*d0ef721eSBaptiste Daroussin static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93";
39*d0ef721eSBaptiste Daroussin #else
40*d0ef721eSBaptiste Daroussin __RCSID("$NetBSD: keymacro.c,v 1.24 2019/07/23 10:18:52 christos Exp $");
41*d0ef721eSBaptiste Daroussin #endif
42*d0ef721eSBaptiste Daroussin #endif /* not lint && not SCCSID */
43*d0ef721eSBaptiste Daroussin
44*d0ef721eSBaptiste Daroussin /*
45*d0ef721eSBaptiste Daroussin * keymacro.c: This module contains the procedures for maintaining
46*d0ef721eSBaptiste Daroussin * the extended-key map.
47*d0ef721eSBaptiste Daroussin *
48*d0ef721eSBaptiste Daroussin * An extended-key (key) is a sequence of keystrokes introduced
49*d0ef721eSBaptiste Daroussin * with a sequence introducer and consisting of an arbitrary
50*d0ef721eSBaptiste Daroussin * number of characters. This module maintains a map (the
51*d0ef721eSBaptiste Daroussin * el->el_keymacro.map)
52*d0ef721eSBaptiste Daroussin * to convert these extended-key sequences into input strs
53*d0ef721eSBaptiste Daroussin * (XK_STR) or editor functions (XK_CMD).
54*d0ef721eSBaptiste Daroussin *
55*d0ef721eSBaptiste Daroussin * Warning:
56*d0ef721eSBaptiste Daroussin * If key is a substr of some other keys, then the longer
57*d0ef721eSBaptiste Daroussin * keys are lost!! That is, if the keys "abcd" and "abcef"
58*d0ef721eSBaptiste Daroussin * are in el->el_keymacro.map, adding the key "abc" will cause
59*d0ef721eSBaptiste Daroussin * the first two definitions to be lost.
60*d0ef721eSBaptiste Daroussin *
61*d0ef721eSBaptiste Daroussin * Restrictions:
62*d0ef721eSBaptiste Daroussin * -------------
63*d0ef721eSBaptiste Daroussin * 1) It is not possible to have one key that is a
64*d0ef721eSBaptiste Daroussin * substr of another.
65*d0ef721eSBaptiste Daroussin */
66*d0ef721eSBaptiste Daroussin #include <stdlib.h>
67*d0ef721eSBaptiste Daroussin #include <string.h>
68*d0ef721eSBaptiste Daroussin
69*d0ef721eSBaptiste Daroussin #include "el.h"
70*d0ef721eSBaptiste Daroussin #include "fcns.h"
71*d0ef721eSBaptiste Daroussin
72*d0ef721eSBaptiste Daroussin /*
73*d0ef721eSBaptiste Daroussin * The Nodes of the el->el_keymacro.map. The el->el_keymacro.map is a
74*d0ef721eSBaptiste Daroussin * linked list of these node elements
75*d0ef721eSBaptiste Daroussin */
76*d0ef721eSBaptiste Daroussin struct keymacro_node_t {
77*d0ef721eSBaptiste Daroussin wchar_t ch; /* single character of key */
78*d0ef721eSBaptiste Daroussin int type; /* node type */
79*d0ef721eSBaptiste Daroussin keymacro_value_t val; /* command code or pointer to str, */
80*d0ef721eSBaptiste Daroussin /* if this is a leaf */
81*d0ef721eSBaptiste Daroussin struct keymacro_node_t *next; /* ptr to next char of this key */
82*d0ef721eSBaptiste Daroussin struct keymacro_node_t *sibling;/* ptr to another key with same prefix*/
83*d0ef721eSBaptiste Daroussin };
84*d0ef721eSBaptiste Daroussin
85*d0ef721eSBaptiste Daroussin static int node_trav(EditLine *, keymacro_node_t *, wchar_t *,
86*d0ef721eSBaptiste Daroussin keymacro_value_t *);
87*d0ef721eSBaptiste Daroussin static int node__try(EditLine *, keymacro_node_t *,
88*d0ef721eSBaptiste Daroussin const wchar_t *, keymacro_value_t *, int);
89*d0ef721eSBaptiste Daroussin static keymacro_node_t *node__get(wint_t);
90*d0ef721eSBaptiste Daroussin static void node__free(keymacro_node_t *);
91*d0ef721eSBaptiste Daroussin static void node__put(EditLine *, keymacro_node_t *);
92*d0ef721eSBaptiste Daroussin static int node__delete(EditLine *, keymacro_node_t **,
93*d0ef721eSBaptiste Daroussin const wchar_t *);
94*d0ef721eSBaptiste Daroussin static int node_lookup(EditLine *, const wchar_t *,
95*d0ef721eSBaptiste Daroussin keymacro_node_t *, size_t);
96*d0ef721eSBaptiste Daroussin static int node_enum(EditLine *, keymacro_node_t *, size_t);
97*d0ef721eSBaptiste Daroussin
98*d0ef721eSBaptiste Daroussin #define KEY_BUFSIZ EL_BUFSIZ
99*d0ef721eSBaptiste Daroussin
100*d0ef721eSBaptiste Daroussin
101*d0ef721eSBaptiste Daroussin /* keymacro_init():
102*d0ef721eSBaptiste Daroussin * Initialize the key maps
103*d0ef721eSBaptiste Daroussin */
104*d0ef721eSBaptiste Daroussin libedit_private int
keymacro_init(EditLine * el)105*d0ef721eSBaptiste Daroussin keymacro_init(EditLine *el)
106*d0ef721eSBaptiste Daroussin {
107*d0ef721eSBaptiste Daroussin
108*d0ef721eSBaptiste Daroussin el->el_keymacro.buf = el_calloc(KEY_BUFSIZ,
109*d0ef721eSBaptiste Daroussin sizeof(*el->el_keymacro.buf));
110*d0ef721eSBaptiste Daroussin if (el->el_keymacro.buf == NULL)
111*d0ef721eSBaptiste Daroussin return -1;
112*d0ef721eSBaptiste Daroussin el->el_keymacro.map = NULL;
113*d0ef721eSBaptiste Daroussin keymacro_reset(el);
114*d0ef721eSBaptiste Daroussin return 0;
115*d0ef721eSBaptiste Daroussin }
116*d0ef721eSBaptiste Daroussin
117*d0ef721eSBaptiste Daroussin /* keymacro_end():
118*d0ef721eSBaptiste Daroussin * Free the key maps
119*d0ef721eSBaptiste Daroussin */
120*d0ef721eSBaptiste Daroussin libedit_private void
keymacro_end(EditLine * el)121*d0ef721eSBaptiste Daroussin keymacro_end(EditLine *el)
122*d0ef721eSBaptiste Daroussin {
123*d0ef721eSBaptiste Daroussin
124*d0ef721eSBaptiste Daroussin el_free(el->el_keymacro.buf);
125*d0ef721eSBaptiste Daroussin el->el_keymacro.buf = NULL;
126*d0ef721eSBaptiste Daroussin node__free(el->el_keymacro.map);
127*d0ef721eSBaptiste Daroussin }
128*d0ef721eSBaptiste Daroussin
129*d0ef721eSBaptiste Daroussin
130*d0ef721eSBaptiste Daroussin /* keymacro_map_cmd():
131*d0ef721eSBaptiste Daroussin * Associate cmd with a key value
132*d0ef721eSBaptiste Daroussin */
133*d0ef721eSBaptiste Daroussin libedit_private keymacro_value_t *
keymacro_map_cmd(EditLine * el,int cmd)134*d0ef721eSBaptiste Daroussin keymacro_map_cmd(EditLine *el, int cmd)
135*d0ef721eSBaptiste Daroussin {
136*d0ef721eSBaptiste Daroussin
137*d0ef721eSBaptiste Daroussin el->el_keymacro.val.cmd = (el_action_t) cmd;
138*d0ef721eSBaptiste Daroussin return &el->el_keymacro.val;
139*d0ef721eSBaptiste Daroussin }
140*d0ef721eSBaptiste Daroussin
141*d0ef721eSBaptiste Daroussin
142*d0ef721eSBaptiste Daroussin /* keymacro_map_str():
143*d0ef721eSBaptiste Daroussin * Associate str with a key value
144*d0ef721eSBaptiste Daroussin */
145*d0ef721eSBaptiste Daroussin libedit_private keymacro_value_t *
keymacro_map_str(EditLine * el,wchar_t * str)146*d0ef721eSBaptiste Daroussin keymacro_map_str(EditLine *el, wchar_t *str)
147*d0ef721eSBaptiste Daroussin {
148*d0ef721eSBaptiste Daroussin
149*d0ef721eSBaptiste Daroussin el->el_keymacro.val.str = str;
150*d0ef721eSBaptiste Daroussin return &el->el_keymacro.val;
151*d0ef721eSBaptiste Daroussin }
152*d0ef721eSBaptiste Daroussin
153*d0ef721eSBaptiste Daroussin
154*d0ef721eSBaptiste Daroussin /* keymacro_reset():
155*d0ef721eSBaptiste Daroussin * Takes all nodes on el->el_keymacro.map and puts them on free list.
156*d0ef721eSBaptiste Daroussin * Then initializes el->el_keymacro.map with arrow keys
157*d0ef721eSBaptiste Daroussin * [Always bind the ansi arrow keys?]
158*d0ef721eSBaptiste Daroussin */
159*d0ef721eSBaptiste Daroussin libedit_private void
keymacro_reset(EditLine * el)160*d0ef721eSBaptiste Daroussin keymacro_reset(EditLine *el)
161*d0ef721eSBaptiste Daroussin {
162*d0ef721eSBaptiste Daroussin
163*d0ef721eSBaptiste Daroussin node__put(el, el->el_keymacro.map);
164*d0ef721eSBaptiste Daroussin el->el_keymacro.map = NULL;
165*d0ef721eSBaptiste Daroussin return;
166*d0ef721eSBaptiste Daroussin }
167*d0ef721eSBaptiste Daroussin
168*d0ef721eSBaptiste Daroussin
169*d0ef721eSBaptiste Daroussin /* keymacro_get():
170*d0ef721eSBaptiste Daroussin * Calls the recursive function with entry point el->el_keymacro.map
171*d0ef721eSBaptiste Daroussin * Looks up *ch in map and then reads characters until a
172*d0ef721eSBaptiste Daroussin * complete match is found or a mismatch occurs. Returns the
173*d0ef721eSBaptiste Daroussin * type of the match found (XK_STR or XK_CMD).
174*d0ef721eSBaptiste Daroussin * Returns NULL in val.str and XK_STR for no match.
175*d0ef721eSBaptiste Daroussin * Returns XK_NOD for end of file or read error.
176*d0ef721eSBaptiste Daroussin * The last character read is returned in *ch.
177*d0ef721eSBaptiste Daroussin */
178*d0ef721eSBaptiste Daroussin libedit_private int
keymacro_get(EditLine * el,wchar_t * ch,keymacro_value_t * val)179*d0ef721eSBaptiste Daroussin keymacro_get(EditLine *el, wchar_t *ch, keymacro_value_t *val)
180*d0ef721eSBaptiste Daroussin {
181*d0ef721eSBaptiste Daroussin
182*d0ef721eSBaptiste Daroussin return node_trav(el, el->el_keymacro.map, ch, val);
183*d0ef721eSBaptiste Daroussin }
184*d0ef721eSBaptiste Daroussin
185*d0ef721eSBaptiste Daroussin
186*d0ef721eSBaptiste Daroussin /* keymacro_add():
187*d0ef721eSBaptiste Daroussin * Adds key to the el->el_keymacro.map and associates the value in
188*d0ef721eSBaptiste Daroussin * val with it. If key is already is in el->el_keymacro.map, the new
189*d0ef721eSBaptiste Daroussin * code is applied to the existing key. Ntype specifies if code is a
190*d0ef721eSBaptiste Daroussin * command, an out str or a unix command.
191*d0ef721eSBaptiste Daroussin */
192*d0ef721eSBaptiste Daroussin libedit_private void
keymacro_add(EditLine * el,const wchar_t * key,keymacro_value_t * val,int ntype)193*d0ef721eSBaptiste Daroussin keymacro_add(EditLine *el, const wchar_t *key, keymacro_value_t *val,
194*d0ef721eSBaptiste Daroussin int ntype)
195*d0ef721eSBaptiste Daroussin {
196*d0ef721eSBaptiste Daroussin
197*d0ef721eSBaptiste Daroussin if (key[0] == '\0') {
198*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile,
199*d0ef721eSBaptiste Daroussin "keymacro_add: Null extended-key not allowed.\n");
200*d0ef721eSBaptiste Daroussin return;
201*d0ef721eSBaptiste Daroussin }
202*d0ef721eSBaptiste Daroussin if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
203*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile,
204*d0ef721eSBaptiste Daroussin "keymacro_add: sequence-lead-in command not allowed\n");
205*d0ef721eSBaptiste Daroussin return;
206*d0ef721eSBaptiste Daroussin }
207*d0ef721eSBaptiste Daroussin if (el->el_keymacro.map == NULL)
208*d0ef721eSBaptiste Daroussin /* tree is initially empty. Set up new node to match key[0] */
209*d0ef721eSBaptiste Daroussin el->el_keymacro.map = node__get(key[0]);
210*d0ef721eSBaptiste Daroussin /* it is properly initialized */
211*d0ef721eSBaptiste Daroussin
212*d0ef721eSBaptiste Daroussin /* Now recurse through el->el_keymacro.map */
213*d0ef721eSBaptiste Daroussin (void) node__try(el, el->el_keymacro.map, key, val, ntype);
214*d0ef721eSBaptiste Daroussin return;
215*d0ef721eSBaptiste Daroussin }
216*d0ef721eSBaptiste Daroussin
217*d0ef721eSBaptiste Daroussin
218*d0ef721eSBaptiste Daroussin /* keymacro_clear():
219*d0ef721eSBaptiste Daroussin *
220*d0ef721eSBaptiste Daroussin */
221*d0ef721eSBaptiste Daroussin libedit_private void
keymacro_clear(EditLine * el,el_action_t * map,const wchar_t * in)222*d0ef721eSBaptiste Daroussin keymacro_clear(EditLine *el, el_action_t *map, const wchar_t *in)
223*d0ef721eSBaptiste Daroussin {
224*d0ef721eSBaptiste Daroussin if (*in > N_KEYS) /* can't be in the map */
225*d0ef721eSBaptiste Daroussin return;
226*d0ef721eSBaptiste Daroussin if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
227*d0ef721eSBaptiste Daroussin ((map == el->el_map.key &&
228*d0ef721eSBaptiste Daroussin el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
229*d0ef721eSBaptiste Daroussin (map == el->el_map.alt &&
230*d0ef721eSBaptiste Daroussin el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
231*d0ef721eSBaptiste Daroussin (void) keymacro_delete(el, in);
232*d0ef721eSBaptiste Daroussin }
233*d0ef721eSBaptiste Daroussin
234*d0ef721eSBaptiste Daroussin
235*d0ef721eSBaptiste Daroussin /* keymacro_delete():
236*d0ef721eSBaptiste Daroussin * Delete the key and all longer keys staring with key, if
237*d0ef721eSBaptiste Daroussin * they exists.
238*d0ef721eSBaptiste Daroussin */
239*d0ef721eSBaptiste Daroussin libedit_private int
keymacro_delete(EditLine * el,const wchar_t * key)240*d0ef721eSBaptiste Daroussin keymacro_delete(EditLine *el, const wchar_t *key)
241*d0ef721eSBaptiste Daroussin {
242*d0ef721eSBaptiste Daroussin
243*d0ef721eSBaptiste Daroussin if (key[0] == '\0') {
244*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile,
245*d0ef721eSBaptiste Daroussin "keymacro_delete: Null extended-key not allowed.\n");
246*d0ef721eSBaptiste Daroussin return -1;
247*d0ef721eSBaptiste Daroussin }
248*d0ef721eSBaptiste Daroussin if (el->el_keymacro.map == NULL)
249*d0ef721eSBaptiste Daroussin return 0;
250*d0ef721eSBaptiste Daroussin
251*d0ef721eSBaptiste Daroussin (void) node__delete(el, &el->el_keymacro.map, key);
252*d0ef721eSBaptiste Daroussin return 0;
253*d0ef721eSBaptiste Daroussin }
254*d0ef721eSBaptiste Daroussin
255*d0ef721eSBaptiste Daroussin
256*d0ef721eSBaptiste Daroussin /* keymacro_print():
257*d0ef721eSBaptiste Daroussin * Print the binding associated with key key.
258*d0ef721eSBaptiste Daroussin * Print entire el->el_keymacro.map if null
259*d0ef721eSBaptiste Daroussin */
260*d0ef721eSBaptiste Daroussin libedit_private void
keymacro_print(EditLine * el,const wchar_t * key)261*d0ef721eSBaptiste Daroussin keymacro_print(EditLine *el, const wchar_t *key)
262*d0ef721eSBaptiste Daroussin {
263*d0ef721eSBaptiste Daroussin
264*d0ef721eSBaptiste Daroussin /* do nothing if el->el_keymacro.map is empty and null key specified */
265*d0ef721eSBaptiste Daroussin if (el->el_keymacro.map == NULL && *key == 0)
266*d0ef721eSBaptiste Daroussin return;
267*d0ef721eSBaptiste Daroussin
268*d0ef721eSBaptiste Daroussin el->el_keymacro.buf[0] = '"';
269*d0ef721eSBaptiste Daroussin if (node_lookup(el, key, el->el_keymacro.map, (size_t)1) <= -1)
270*d0ef721eSBaptiste Daroussin /* key is not bound */
271*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile, "Unbound extended key \"%ls"
272*d0ef721eSBaptiste Daroussin "\"\n", key);
273*d0ef721eSBaptiste Daroussin return;
274*d0ef721eSBaptiste Daroussin }
275*d0ef721eSBaptiste Daroussin
276*d0ef721eSBaptiste Daroussin
277*d0ef721eSBaptiste Daroussin /* node_trav():
278*d0ef721eSBaptiste Daroussin * recursively traverses node in tree until match or mismatch is
279*d0ef721eSBaptiste Daroussin * found. May read in more characters.
280*d0ef721eSBaptiste Daroussin */
281*d0ef721eSBaptiste Daroussin static int
node_trav(EditLine * el,keymacro_node_t * ptr,wchar_t * ch,keymacro_value_t * val)282*d0ef721eSBaptiste Daroussin node_trav(EditLine *el, keymacro_node_t *ptr, wchar_t *ch,
283*d0ef721eSBaptiste Daroussin keymacro_value_t *val)
284*d0ef721eSBaptiste Daroussin {
285*d0ef721eSBaptiste Daroussin
286*d0ef721eSBaptiste Daroussin if (ptr->ch == *ch) {
287*d0ef721eSBaptiste Daroussin /* match found */
288*d0ef721eSBaptiste Daroussin if (ptr->next) {
289*d0ef721eSBaptiste Daroussin /* key not complete so get next char */
290*d0ef721eSBaptiste Daroussin if (el_wgetc(el, ch) != 1)
291*d0ef721eSBaptiste Daroussin return XK_NOD;
292*d0ef721eSBaptiste Daroussin return node_trav(el, ptr->next, ch, val);
293*d0ef721eSBaptiste Daroussin } else {
294*d0ef721eSBaptiste Daroussin *val = ptr->val;
295*d0ef721eSBaptiste Daroussin if (ptr->type != XK_CMD)
296*d0ef721eSBaptiste Daroussin *ch = '\0';
297*d0ef721eSBaptiste Daroussin return ptr->type;
298*d0ef721eSBaptiste Daroussin }
299*d0ef721eSBaptiste Daroussin } else {
300*d0ef721eSBaptiste Daroussin /* no match found here */
301*d0ef721eSBaptiste Daroussin if (ptr->sibling) {
302*d0ef721eSBaptiste Daroussin /* try next sibling */
303*d0ef721eSBaptiste Daroussin return node_trav(el, ptr->sibling, ch, val);
304*d0ef721eSBaptiste Daroussin } else {
305*d0ef721eSBaptiste Daroussin /* no next sibling -- mismatch */
306*d0ef721eSBaptiste Daroussin val->str = NULL;
307*d0ef721eSBaptiste Daroussin return XK_STR;
308*d0ef721eSBaptiste Daroussin }
309*d0ef721eSBaptiste Daroussin }
310*d0ef721eSBaptiste Daroussin }
311*d0ef721eSBaptiste Daroussin
312*d0ef721eSBaptiste Daroussin
313*d0ef721eSBaptiste Daroussin /* node__try():
314*d0ef721eSBaptiste Daroussin * Find a node that matches *str or allocate a new one
315*d0ef721eSBaptiste Daroussin */
316*d0ef721eSBaptiste Daroussin static int
node__try(EditLine * el,keymacro_node_t * ptr,const wchar_t * str,keymacro_value_t * val,int ntype)317*d0ef721eSBaptiste Daroussin node__try(EditLine *el, keymacro_node_t *ptr, const wchar_t *str,
318*d0ef721eSBaptiste Daroussin keymacro_value_t *val, int ntype)
319*d0ef721eSBaptiste Daroussin {
320*d0ef721eSBaptiste Daroussin
321*d0ef721eSBaptiste Daroussin if (ptr->ch != *str) {
322*d0ef721eSBaptiste Daroussin keymacro_node_t *xm;
323*d0ef721eSBaptiste Daroussin
324*d0ef721eSBaptiste Daroussin for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
325*d0ef721eSBaptiste Daroussin if (xm->sibling->ch == *str)
326*d0ef721eSBaptiste Daroussin break;
327*d0ef721eSBaptiste Daroussin if (xm->sibling == NULL)
328*d0ef721eSBaptiste Daroussin xm->sibling = node__get(*str); /* setup new node */
329*d0ef721eSBaptiste Daroussin ptr = xm->sibling;
330*d0ef721eSBaptiste Daroussin }
331*d0ef721eSBaptiste Daroussin if (*++str == '\0') {
332*d0ef721eSBaptiste Daroussin /* we're there */
333*d0ef721eSBaptiste Daroussin if (ptr->next != NULL) {
334*d0ef721eSBaptiste Daroussin node__put(el, ptr->next);
335*d0ef721eSBaptiste Daroussin /* lose longer keys with this prefix */
336*d0ef721eSBaptiste Daroussin ptr->next = NULL;
337*d0ef721eSBaptiste Daroussin }
338*d0ef721eSBaptiste Daroussin switch (ptr->type) {
339*d0ef721eSBaptiste Daroussin case XK_CMD:
340*d0ef721eSBaptiste Daroussin case XK_NOD:
341*d0ef721eSBaptiste Daroussin break;
342*d0ef721eSBaptiste Daroussin case XK_STR:
343*d0ef721eSBaptiste Daroussin if (ptr->val.str)
344*d0ef721eSBaptiste Daroussin el_free(ptr->val.str);
345*d0ef721eSBaptiste Daroussin break;
346*d0ef721eSBaptiste Daroussin default:
347*d0ef721eSBaptiste Daroussin EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
348*d0ef721eSBaptiste Daroussin ptr->type));
349*d0ef721eSBaptiste Daroussin break;
350*d0ef721eSBaptiste Daroussin }
351*d0ef721eSBaptiste Daroussin
352*d0ef721eSBaptiste Daroussin switch (ptr->type = ntype) {
353*d0ef721eSBaptiste Daroussin case XK_CMD:
354*d0ef721eSBaptiste Daroussin ptr->val = *val;
355*d0ef721eSBaptiste Daroussin break;
356*d0ef721eSBaptiste Daroussin case XK_STR:
357*d0ef721eSBaptiste Daroussin if ((ptr->val.str = wcsdup(val->str)) == NULL)
358*d0ef721eSBaptiste Daroussin return -1;
359*d0ef721eSBaptiste Daroussin break;
360*d0ef721eSBaptiste Daroussin default:
361*d0ef721eSBaptiste Daroussin EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
362*d0ef721eSBaptiste Daroussin break;
363*d0ef721eSBaptiste Daroussin }
364*d0ef721eSBaptiste Daroussin } else {
365*d0ef721eSBaptiste Daroussin /* still more chars to go */
366*d0ef721eSBaptiste Daroussin if (ptr->next == NULL)
367*d0ef721eSBaptiste Daroussin ptr->next = node__get(*str); /* setup new node */
368*d0ef721eSBaptiste Daroussin (void) node__try(el, ptr->next, str, val, ntype);
369*d0ef721eSBaptiste Daroussin }
370*d0ef721eSBaptiste Daroussin return 0;
371*d0ef721eSBaptiste Daroussin }
372*d0ef721eSBaptiste Daroussin
373*d0ef721eSBaptiste Daroussin
374*d0ef721eSBaptiste Daroussin /* node__delete():
375*d0ef721eSBaptiste Daroussin * Delete node that matches str
376*d0ef721eSBaptiste Daroussin */
377*d0ef721eSBaptiste Daroussin static int
node__delete(EditLine * el,keymacro_node_t ** inptr,const wchar_t * str)378*d0ef721eSBaptiste Daroussin node__delete(EditLine *el, keymacro_node_t **inptr, const wchar_t *str)
379*d0ef721eSBaptiste Daroussin {
380*d0ef721eSBaptiste Daroussin keymacro_node_t *ptr;
381*d0ef721eSBaptiste Daroussin keymacro_node_t *prev_ptr = NULL;
382*d0ef721eSBaptiste Daroussin
383*d0ef721eSBaptiste Daroussin ptr = *inptr;
384*d0ef721eSBaptiste Daroussin
385*d0ef721eSBaptiste Daroussin if (ptr->ch != *str) {
386*d0ef721eSBaptiste Daroussin keymacro_node_t *xm;
387*d0ef721eSBaptiste Daroussin
388*d0ef721eSBaptiste Daroussin for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
389*d0ef721eSBaptiste Daroussin if (xm->sibling->ch == *str)
390*d0ef721eSBaptiste Daroussin break;
391*d0ef721eSBaptiste Daroussin if (xm->sibling == NULL)
392*d0ef721eSBaptiste Daroussin return 0;
393*d0ef721eSBaptiste Daroussin prev_ptr = xm;
394*d0ef721eSBaptiste Daroussin ptr = xm->sibling;
395*d0ef721eSBaptiste Daroussin }
396*d0ef721eSBaptiste Daroussin if (*++str == '\0') {
397*d0ef721eSBaptiste Daroussin /* we're there */
398*d0ef721eSBaptiste Daroussin if (prev_ptr == NULL)
399*d0ef721eSBaptiste Daroussin *inptr = ptr->sibling;
400*d0ef721eSBaptiste Daroussin else
401*d0ef721eSBaptiste Daroussin prev_ptr->sibling = ptr->sibling;
402*d0ef721eSBaptiste Daroussin ptr->sibling = NULL;
403*d0ef721eSBaptiste Daroussin node__put(el, ptr);
404*d0ef721eSBaptiste Daroussin return 1;
405*d0ef721eSBaptiste Daroussin } else if (ptr->next != NULL &&
406*d0ef721eSBaptiste Daroussin node__delete(el, &ptr->next, str) == 1) {
407*d0ef721eSBaptiste Daroussin if (ptr->next != NULL)
408*d0ef721eSBaptiste Daroussin return 0;
409*d0ef721eSBaptiste Daroussin if (prev_ptr == NULL)
410*d0ef721eSBaptiste Daroussin *inptr = ptr->sibling;
411*d0ef721eSBaptiste Daroussin else
412*d0ef721eSBaptiste Daroussin prev_ptr->sibling = ptr->sibling;
413*d0ef721eSBaptiste Daroussin ptr->sibling = NULL;
414*d0ef721eSBaptiste Daroussin node__put(el, ptr);
415*d0ef721eSBaptiste Daroussin return 1;
416*d0ef721eSBaptiste Daroussin } else {
417*d0ef721eSBaptiste Daroussin return 0;
418*d0ef721eSBaptiste Daroussin }
419*d0ef721eSBaptiste Daroussin }
420*d0ef721eSBaptiste Daroussin
421*d0ef721eSBaptiste Daroussin
422*d0ef721eSBaptiste Daroussin /* node__put():
423*d0ef721eSBaptiste Daroussin * Puts a tree of nodes onto free list using free(3).
424*d0ef721eSBaptiste Daroussin */
425*d0ef721eSBaptiste Daroussin static void
node__put(EditLine * el,keymacro_node_t * ptr)426*d0ef721eSBaptiste Daroussin node__put(EditLine *el, keymacro_node_t *ptr)
427*d0ef721eSBaptiste Daroussin {
428*d0ef721eSBaptiste Daroussin if (ptr == NULL)
429*d0ef721eSBaptiste Daroussin return;
430*d0ef721eSBaptiste Daroussin
431*d0ef721eSBaptiste Daroussin if (ptr->next != NULL) {
432*d0ef721eSBaptiste Daroussin node__put(el, ptr->next);
433*d0ef721eSBaptiste Daroussin ptr->next = NULL;
434*d0ef721eSBaptiste Daroussin }
435*d0ef721eSBaptiste Daroussin node__put(el, ptr->sibling);
436*d0ef721eSBaptiste Daroussin
437*d0ef721eSBaptiste Daroussin switch (ptr->type) {
438*d0ef721eSBaptiste Daroussin case XK_CMD:
439*d0ef721eSBaptiste Daroussin case XK_NOD:
440*d0ef721eSBaptiste Daroussin break;
441*d0ef721eSBaptiste Daroussin case XK_STR:
442*d0ef721eSBaptiste Daroussin if (ptr->val.str != NULL)
443*d0ef721eSBaptiste Daroussin el_free(ptr->val.str);
444*d0ef721eSBaptiste Daroussin break;
445*d0ef721eSBaptiste Daroussin default:
446*d0ef721eSBaptiste Daroussin EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
447*d0ef721eSBaptiste Daroussin break;
448*d0ef721eSBaptiste Daroussin }
449*d0ef721eSBaptiste Daroussin el_free(ptr);
450*d0ef721eSBaptiste Daroussin }
451*d0ef721eSBaptiste Daroussin
452*d0ef721eSBaptiste Daroussin
453*d0ef721eSBaptiste Daroussin /* node__get():
454*d0ef721eSBaptiste Daroussin * Returns pointer to a keymacro_node_t for ch.
455*d0ef721eSBaptiste Daroussin */
456*d0ef721eSBaptiste Daroussin static keymacro_node_t *
node__get(wint_t ch)457*d0ef721eSBaptiste Daroussin node__get(wint_t ch)
458*d0ef721eSBaptiste Daroussin {
459*d0ef721eSBaptiste Daroussin keymacro_node_t *ptr;
460*d0ef721eSBaptiste Daroussin
461*d0ef721eSBaptiste Daroussin ptr = el_malloc(sizeof(*ptr));
462*d0ef721eSBaptiste Daroussin if (ptr == NULL)
463*d0ef721eSBaptiste Daroussin return NULL;
464*d0ef721eSBaptiste Daroussin ptr->ch = ch;
465*d0ef721eSBaptiste Daroussin ptr->type = XK_NOD;
466*d0ef721eSBaptiste Daroussin ptr->val.str = NULL;
467*d0ef721eSBaptiste Daroussin ptr->next = NULL;
468*d0ef721eSBaptiste Daroussin ptr->sibling = NULL;
469*d0ef721eSBaptiste Daroussin return ptr;
470*d0ef721eSBaptiste Daroussin }
471*d0ef721eSBaptiste Daroussin
472*d0ef721eSBaptiste Daroussin static void
node__free(keymacro_node_t * k)473*d0ef721eSBaptiste Daroussin node__free(keymacro_node_t *k)
474*d0ef721eSBaptiste Daroussin {
475*d0ef721eSBaptiste Daroussin if (k == NULL)
476*d0ef721eSBaptiste Daroussin return;
477*d0ef721eSBaptiste Daroussin node__free(k->sibling);
478*d0ef721eSBaptiste Daroussin node__free(k->next);
479*d0ef721eSBaptiste Daroussin el_free(k);
480*d0ef721eSBaptiste Daroussin }
481*d0ef721eSBaptiste Daroussin
482*d0ef721eSBaptiste Daroussin /* node_lookup():
483*d0ef721eSBaptiste Daroussin * look for the str starting at node ptr.
484*d0ef721eSBaptiste Daroussin * Print if last node
485*d0ef721eSBaptiste Daroussin */
486*d0ef721eSBaptiste Daroussin static int
node_lookup(EditLine * el,const wchar_t * str,keymacro_node_t * ptr,size_t cnt)487*d0ef721eSBaptiste Daroussin node_lookup(EditLine *el, const wchar_t *str, keymacro_node_t *ptr,
488*d0ef721eSBaptiste Daroussin size_t cnt)
489*d0ef721eSBaptiste Daroussin {
490*d0ef721eSBaptiste Daroussin ssize_t used;
491*d0ef721eSBaptiste Daroussin
492*d0ef721eSBaptiste Daroussin if (ptr == NULL)
493*d0ef721eSBaptiste Daroussin return -1; /* cannot have null ptr */
494*d0ef721eSBaptiste Daroussin
495*d0ef721eSBaptiste Daroussin if (!str || *str == 0) {
496*d0ef721eSBaptiste Daroussin /* no more chars in str. node_enum from here. */
497*d0ef721eSBaptiste Daroussin (void) node_enum(el, ptr, cnt);
498*d0ef721eSBaptiste Daroussin return 0;
499*d0ef721eSBaptiste Daroussin } else {
500*d0ef721eSBaptiste Daroussin /* If match put this char into el->el_keymacro.buf. Recurse */
501*d0ef721eSBaptiste Daroussin if (ptr->ch == *str) {
502*d0ef721eSBaptiste Daroussin /* match found */
503*d0ef721eSBaptiste Daroussin used = ct_visual_char(el->el_keymacro.buf + cnt,
504*d0ef721eSBaptiste Daroussin KEY_BUFSIZ - cnt, ptr->ch);
505*d0ef721eSBaptiste Daroussin if (used == -1)
506*d0ef721eSBaptiste Daroussin return -1; /* ran out of buffer space */
507*d0ef721eSBaptiste Daroussin if (ptr->next != NULL)
508*d0ef721eSBaptiste Daroussin /* not yet at leaf */
509*d0ef721eSBaptiste Daroussin return (node_lookup(el, str + 1, ptr->next,
510*d0ef721eSBaptiste Daroussin (size_t)used + cnt));
511*d0ef721eSBaptiste Daroussin else {
512*d0ef721eSBaptiste Daroussin /* next node is null so key should be complete */
513*d0ef721eSBaptiste Daroussin if (str[1] == 0) {
514*d0ef721eSBaptiste Daroussin size_t px = cnt + (size_t)used;
515*d0ef721eSBaptiste Daroussin el->el_keymacro.buf[px] = '"';
516*d0ef721eSBaptiste Daroussin el->el_keymacro.buf[px + 1] = '\0';
517*d0ef721eSBaptiste Daroussin keymacro_kprint(el, el->el_keymacro.buf,
518*d0ef721eSBaptiste Daroussin &ptr->val, ptr->type);
519*d0ef721eSBaptiste Daroussin return 0;
520*d0ef721eSBaptiste Daroussin } else
521*d0ef721eSBaptiste Daroussin return -1;
522*d0ef721eSBaptiste Daroussin /* mismatch -- str still has chars */
523*d0ef721eSBaptiste Daroussin }
524*d0ef721eSBaptiste Daroussin } else {
525*d0ef721eSBaptiste Daroussin /* no match found try sibling */
526*d0ef721eSBaptiste Daroussin if (ptr->sibling)
527*d0ef721eSBaptiste Daroussin return (node_lookup(el, str, ptr->sibling,
528*d0ef721eSBaptiste Daroussin cnt));
529*d0ef721eSBaptiste Daroussin else
530*d0ef721eSBaptiste Daroussin return -1;
531*d0ef721eSBaptiste Daroussin }
532*d0ef721eSBaptiste Daroussin }
533*d0ef721eSBaptiste Daroussin }
534*d0ef721eSBaptiste Daroussin
535*d0ef721eSBaptiste Daroussin
536*d0ef721eSBaptiste Daroussin /* node_enum():
537*d0ef721eSBaptiste Daroussin * Traverse the node printing the characters it is bound in buffer
538*d0ef721eSBaptiste Daroussin */
539*d0ef721eSBaptiste Daroussin static int
node_enum(EditLine * el,keymacro_node_t * ptr,size_t cnt)540*d0ef721eSBaptiste Daroussin node_enum(EditLine *el, keymacro_node_t *ptr, size_t cnt)
541*d0ef721eSBaptiste Daroussin {
542*d0ef721eSBaptiste Daroussin ssize_t used;
543*d0ef721eSBaptiste Daroussin
544*d0ef721eSBaptiste Daroussin if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */
545*d0ef721eSBaptiste Daroussin el->el_keymacro.buf[++cnt] = '"';
546*d0ef721eSBaptiste Daroussin el->el_keymacro.buf[++cnt] = '\0';
547*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile,
548*d0ef721eSBaptiste Daroussin "Some extended keys too long for internal print buffer");
549*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile, " \"%ls...\"\n",
550*d0ef721eSBaptiste Daroussin el->el_keymacro.buf);
551*d0ef721eSBaptiste Daroussin return 0;
552*d0ef721eSBaptiste Daroussin }
553*d0ef721eSBaptiste Daroussin if (ptr == NULL) {
554*d0ef721eSBaptiste Daroussin #ifdef DEBUG_EDIT
555*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_errfile,
556*d0ef721eSBaptiste Daroussin "node_enum: BUG!! Null ptr passed\n!");
557*d0ef721eSBaptiste Daroussin #endif
558*d0ef721eSBaptiste Daroussin return -1;
559*d0ef721eSBaptiste Daroussin }
560*d0ef721eSBaptiste Daroussin /* put this char at end of str */
561*d0ef721eSBaptiste Daroussin used = ct_visual_char(el->el_keymacro.buf + cnt, KEY_BUFSIZ - cnt,
562*d0ef721eSBaptiste Daroussin ptr->ch);
563*d0ef721eSBaptiste Daroussin if (ptr->next == NULL) {
564*d0ef721eSBaptiste Daroussin /* print this key and function */
565*d0ef721eSBaptiste Daroussin el->el_keymacro.buf[cnt + (size_t)used ] = '"';
566*d0ef721eSBaptiste Daroussin el->el_keymacro.buf[cnt + (size_t)used + 1] = '\0';
567*d0ef721eSBaptiste Daroussin keymacro_kprint(el, el->el_keymacro.buf, &ptr->val, ptr->type);
568*d0ef721eSBaptiste Daroussin } else
569*d0ef721eSBaptiste Daroussin (void) node_enum(el, ptr->next, cnt + (size_t)used);
570*d0ef721eSBaptiste Daroussin
571*d0ef721eSBaptiste Daroussin /* go to sibling if there is one */
572*d0ef721eSBaptiste Daroussin if (ptr->sibling)
573*d0ef721eSBaptiste Daroussin (void) node_enum(el, ptr->sibling, cnt);
574*d0ef721eSBaptiste Daroussin return 0;
575*d0ef721eSBaptiste Daroussin }
576*d0ef721eSBaptiste Daroussin
577*d0ef721eSBaptiste Daroussin
578*d0ef721eSBaptiste Daroussin /* keymacro_kprint():
579*d0ef721eSBaptiste Daroussin * Print the specified key and its associated
580*d0ef721eSBaptiste Daroussin * function specified by val
581*d0ef721eSBaptiste Daroussin */
582*d0ef721eSBaptiste Daroussin libedit_private void
keymacro_kprint(EditLine * el,const wchar_t * key,keymacro_value_t * val,int ntype)583*d0ef721eSBaptiste Daroussin keymacro_kprint(EditLine *el, const wchar_t *key, keymacro_value_t *val,
584*d0ef721eSBaptiste Daroussin int ntype)
585*d0ef721eSBaptiste Daroussin {
586*d0ef721eSBaptiste Daroussin el_bindings_t *fp;
587*d0ef721eSBaptiste Daroussin char unparsbuf[EL_BUFSIZ];
588*d0ef721eSBaptiste Daroussin static const char fmt[] = "%-15s-> %s\n";
589*d0ef721eSBaptiste Daroussin
590*d0ef721eSBaptiste Daroussin if (val != NULL)
591*d0ef721eSBaptiste Daroussin switch (ntype) {
592*d0ef721eSBaptiste Daroussin case XK_STR:
593*d0ef721eSBaptiste Daroussin (void) keymacro__decode_str(val->str, unparsbuf,
594*d0ef721eSBaptiste Daroussin sizeof(unparsbuf),
595*d0ef721eSBaptiste Daroussin ntype == XK_STR ? "\"\"" : "[]");
596*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_outfile, fmt,
597*d0ef721eSBaptiste Daroussin ct_encode_string(key, &el->el_scratch), unparsbuf);
598*d0ef721eSBaptiste Daroussin break;
599*d0ef721eSBaptiste Daroussin case XK_CMD:
600*d0ef721eSBaptiste Daroussin for (fp = el->el_map.help; fp->name; fp++)
601*d0ef721eSBaptiste Daroussin if (val->cmd == fp->func) {
602*d0ef721eSBaptiste Daroussin wcstombs(unparsbuf, fp->name, sizeof(unparsbuf));
603*d0ef721eSBaptiste Daroussin unparsbuf[sizeof(unparsbuf) -1] = '\0';
604*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_outfile, fmt,
605*d0ef721eSBaptiste Daroussin ct_encode_string(key, &el->el_scratch), unparsbuf);
606*d0ef721eSBaptiste Daroussin break;
607*d0ef721eSBaptiste Daroussin }
608*d0ef721eSBaptiste Daroussin #ifdef DEBUG_KEY
609*d0ef721eSBaptiste Daroussin if (fp->name == NULL)
610*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_outfile,
611*d0ef721eSBaptiste Daroussin "BUG! Command not found.\n");
612*d0ef721eSBaptiste Daroussin #endif
613*d0ef721eSBaptiste Daroussin
614*d0ef721eSBaptiste Daroussin break;
615*d0ef721eSBaptiste Daroussin default:
616*d0ef721eSBaptiste Daroussin EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
617*d0ef721eSBaptiste Daroussin break;
618*d0ef721eSBaptiste Daroussin }
619*d0ef721eSBaptiste Daroussin else
620*d0ef721eSBaptiste Daroussin (void) fprintf(el->el_outfile, fmt, ct_encode_string(key,
621*d0ef721eSBaptiste Daroussin &el->el_scratch), "no input");
622*d0ef721eSBaptiste Daroussin }
623*d0ef721eSBaptiste Daroussin
624*d0ef721eSBaptiste Daroussin
625*d0ef721eSBaptiste Daroussin #define ADDC(c) \
626*d0ef721eSBaptiste Daroussin if (b < eb) \
627*d0ef721eSBaptiste Daroussin *b++ = c; \
628*d0ef721eSBaptiste Daroussin else \
629*d0ef721eSBaptiste Daroussin b++
630*d0ef721eSBaptiste Daroussin /* keymacro__decode_str():
631*d0ef721eSBaptiste Daroussin * Make a printable version of the ey
632*d0ef721eSBaptiste Daroussin */
633*d0ef721eSBaptiste Daroussin libedit_private size_t
keymacro__decode_str(const wchar_t * str,char * buf,size_t len,const char * sep)634*d0ef721eSBaptiste Daroussin keymacro__decode_str(const wchar_t *str, char *buf, size_t len,
635*d0ef721eSBaptiste Daroussin const char *sep)
636*d0ef721eSBaptiste Daroussin {
637*d0ef721eSBaptiste Daroussin char *b = buf, *eb = b + len;
638*d0ef721eSBaptiste Daroussin const wchar_t *p;
639*d0ef721eSBaptiste Daroussin
640*d0ef721eSBaptiste Daroussin b = buf;
641*d0ef721eSBaptiste Daroussin if (sep[0] != '\0') {
642*d0ef721eSBaptiste Daroussin ADDC(sep[0]);
643*d0ef721eSBaptiste Daroussin }
644*d0ef721eSBaptiste Daroussin if (*str == '\0') {
645*d0ef721eSBaptiste Daroussin ADDC('^');
646*d0ef721eSBaptiste Daroussin ADDC('@');
647*d0ef721eSBaptiste Daroussin goto add_endsep;
648*d0ef721eSBaptiste Daroussin }
649*d0ef721eSBaptiste Daroussin for (p = str; *p != 0; p++) {
650*d0ef721eSBaptiste Daroussin wchar_t dbuf[VISUAL_WIDTH_MAX];
651*d0ef721eSBaptiste Daroussin wchar_t *p2 = dbuf;
652*d0ef721eSBaptiste Daroussin ssize_t l = ct_visual_char(dbuf, VISUAL_WIDTH_MAX, *p);
653*d0ef721eSBaptiste Daroussin while (l-- > 0) {
654*d0ef721eSBaptiste Daroussin ssize_t n = ct_encode_char(b, (size_t)(eb - b), *p2++);
655*d0ef721eSBaptiste Daroussin if (n == -1) /* ran out of space */
656*d0ef721eSBaptiste Daroussin goto add_endsep;
657*d0ef721eSBaptiste Daroussin else
658*d0ef721eSBaptiste Daroussin b += n;
659*d0ef721eSBaptiste Daroussin }
660*d0ef721eSBaptiste Daroussin }
661*d0ef721eSBaptiste Daroussin add_endsep:
662*d0ef721eSBaptiste Daroussin if (sep[0] != '\0' && sep[1] != '\0') {
663*d0ef721eSBaptiste Daroussin ADDC(sep[1]);
664*d0ef721eSBaptiste Daroussin }
665*d0ef721eSBaptiste Daroussin ADDC('\0');
666*d0ef721eSBaptiste Daroussin if ((size_t)(b - buf) >= len)
667*d0ef721eSBaptiste Daroussin buf[len - 1] = '\0';
668*d0ef721eSBaptiste Daroussin return (size_t)(b - buf);
669*d0ef721eSBaptiste Daroussin }
670