~ubuntu-branches/ubuntu/natty/mysql-5.1/natty-proposed

« back to all changes in this revision

Viewing changes to cmd-line-utils/libedit/keymacro.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-02-22 08:30:45 UTC
  • mfrom: (1.4.1)
  • Revision ID: package-import@ubuntu.com-20120222083045-2rd53r4bnyx7qus4
Tags: 5.1.61-0ubuntu0.11.04.1
* SECURITY UPDATE: Update to 5.1.61 to fix multiple security issues
  (LP: #937869)
  - http://www.oracle.com/technetwork/topics/security/cpujan2012-366304.html
  - CVE-2011-2262
  - CVE-2012-0075
  - CVE-2012-0112
  - CVE-2012-0113
  - CVE-2012-0114
  - CVE-2012-0115
  - CVE-2012-0116
  - CVE-2012-0117
  - CVE-2012-0118
  - CVE-2012-0119
  - CVE-2012-0120
  - CVE-2012-0484
  - CVE-2012-0485
  - CVE-2012-0486
  - CVE-2012-0487
  - CVE-2012-0488
  - CVE-2012-0489
  - CVE-2012-0490
  - CVE-2012-0491
  - CVE-2012-0492
  - CVE-2012-0493
  - CVE-2012-0494
  - CVE-2012-0495
  - CVE-2012-0496

Show diffs side-by-side

added added

removed removed

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