~ubuntu-branches/ubuntu/precise/mysql-5.5/precise-201203300109

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-02-14 23:59:22 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20120214235922-cux5uek1e5l0hje9
Tags: 5.5.20-0ubuntu1
* New upstream release.
* d/mysql-server-5.5.mysql.upstart: Fix stop on to make sure mysql is
  fully stopped before shutdown commences. (LP: #688541) Also simplify
  start on as it is redundant.
* d/control: Depend on upstart version which has apparmor profile load
  script to prevent failure on upgrade from lucid to precise.
  (LP: #907465)
* d/apparmor-profile: need to allow /run since that is the true path
  of /var/run files. (LP: #917542)
* d/control: mysql-server-5.5 has files in it that used to be owned
  by libmysqlclient-dev, so it must break/replace it. (LP: #912487)
* d/rules, d/control: 5.5.20 Fixes segfault on tests with gcc 4.6,
  change compiler back to system default.
* d/rules: Turn off embedded libedit/readline.(Closes: #659566)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*      $NetBSD: key.c,v 1.19 2006/03/23 20:22:51 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
 
 * key.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 el->el_key.map)
50
 
 *      to convert these extended-key sequences into input strs
51
 
 *      (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
52
 
 *
53
 
 *      Warning:
54
 
 *        If key is a substr of some other keys, then the longer
55
 
 *        keys are lost!!  That is, if the keys "abcd" and "abcef"
56
 
 *        are in el->el_key.map, adding the key "abc" will cause the first two
57
 
 *        definitions to be lost.
58
 
 *
59
 
 *      Restrictions:
60
 
 *      -------------
61
 
 *      1) It is not possible to have one key that is a
62
 
 *         substr of another.
63
 
 */
64
 
#include <string.h>
65
 
#include <stdlib.h>
66
 
 
67
 
#include "el.h"
68
 
 
69
 
/*
70
 
 * The Nodes of the el->el_key.map.  The el->el_key.map is a linked list
71
 
 * of these node elements
72
 
 */
73
 
struct key_node_t {
74
 
        char            ch;             /* single character of key       */
75
 
        int             type;           /* node type                     */
76
 
        key_value_t     val;            /* command code or pointer to str,  */
77
 
                                        /* if this is a leaf             */
78
 
        struct key_node_t *next;        /* ptr to next char of this key  */
79
 
        struct key_node_t *sibling;     /* ptr to another key with same prefix*/
80
 
};
81
 
 
82
 
private int              node_trav(EditLine *, key_node_t *, char *,
83
 
    key_value_t *);
84
 
private int              node__try(EditLine *, key_node_t *, const char *,
85
 
    key_value_t *, int);
86
 
private key_node_t      *node__get(int);
87
 
private void             node__free(key_node_t *);
88
 
private void             node__put(EditLine *, key_node_t *);
89
 
private int              node__delete(EditLine *, key_node_t **, const char *);
90
 
private int              node_lookup(EditLine *, const char *, key_node_t *,
91
 
    int);
92
 
private int              node_enum(EditLine *, key_node_t *, int);
93
 
 
94
 
#define KEY_BUFSIZ      EL_BUFSIZ
95
 
 
96
 
 
97
 
/* key_init():
98
 
 *      Initialize the key maps
99
 
 */
100
 
protected int
101
 
key_init(EditLine *el)
102
 
{
103
 
 
104
 
        el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ);
105
 
        if (el->el_key.buf == NULL)
106
 
                return (-1);
107
 
        el->el_key.map = NULL;
108
 
        key_reset(el);
109
 
        return (0);
110
 
}
111
 
 
112
 
/* key_end():
113
 
 *      Free the key maps
114
 
 */
115
 
protected void
116
 
key_end(EditLine *el)
117
 
{
118
 
 
119
 
        el_free((ptr_t) el->el_key.buf);
120
 
        el->el_key.buf = NULL;
121
 
        node__free(el->el_key.map);
122
 
}
123
 
 
124
 
 
125
 
/* key_map_cmd():
126
 
 *      Associate cmd with a key value
127
 
 */
128
 
protected key_value_t *
129
 
key_map_cmd(EditLine *el, int cmd)
130
 
{
131
 
 
132
 
        el->el_key.val.cmd = (el_action_t) cmd;
133
 
        return (&el->el_key.val);
134
 
}
135
 
 
136
 
 
137
 
/* key_map_str():
138
 
 *      Associate str with a key value
139
 
 */
140
 
protected key_value_t *
141
 
key_map_str(EditLine *el, char *str)
142
 
{
143
 
 
144
 
        el->el_key.val.str = str;
145
 
        return (&el->el_key.val);
146
 
}
147
 
 
148
 
 
149
 
/* key_reset():
150
 
 *      Takes all nodes on el->el_key.map and puts them on free list.  Then
151
 
 *      initializes el->el_key.map with arrow keys
152
 
 *      [Always bind the ansi arrow keys?]
153
 
 */
154
 
protected void
155
 
key_reset(EditLine *el)
156
 
{
157
 
 
158
 
        node__put(el, el->el_key.map);
159
 
        el->el_key.map = NULL;
160
 
        return;
161
 
}
162
 
 
163
 
 
164
 
/* key_get():
165
 
 *      Calls the recursive function with entry point el->el_key.map
166
 
 *      Looks up *ch in map and then reads characters until a
167
 
 *      complete match is found or a mismatch occurs. Returns the
168
 
 *      type of the match found (XK_STR, XK_CMD, or XK_EXE).
169
 
 *      Returns NULL in val.str and XK_STR for no match.
170
 
 *      The last character read is returned in *ch.
171
 
 */
172
 
protected int
173
 
key_get(EditLine *el, char *ch, key_value_t *val)
174
 
{
175
 
 
176
 
        return (node_trav(el, el->el_key.map, ch, val));
177
 
}
178
 
 
179
 
 
180
 
/* key_add():
181
 
 *      Adds key to the el->el_key.map and associates the value in val with it.
182
 
 *      If key is already is in el->el_key.map, the new code is applied to the
183
 
 *      existing key. Ntype specifies if code is a command, an
184
 
 *      out str or a unix command.
185
 
 */
186
 
protected void
187
 
key_add(EditLine *el, const char *key, key_value_t *val, int ntype)
188
 
{
189
 
 
190
 
        if (key[0] == '\0') {
191
 
                (void) fprintf(el->el_errfile,
192
 
                    "key_add: Null extended-key not allowed.\n");
193
 
                return;
194
 
        }
195
 
        if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
196
 
                (void) fprintf(el->el_errfile,
197
 
                    "key_add: sequence-lead-in command not allowed\n");
198
 
                return;
199
 
        }
200
 
        if (el->el_key.map == NULL)
201
 
                /* tree is initially empty.  Set up new node to match key[0] */
202
 
                el->el_key.map = node__get(key[0]);
203
 
                        /* it is properly initialized */
204
 
 
205
 
        /* Now recurse through el->el_key.map */
206
 
        (void) node__try(el, el->el_key.map, key, val, ntype);
207
 
        return;
208
 
}
209
 
 
210
 
 
211
 
/* key_clear():
212
 
 *
213
 
 */
214
 
protected void
215
 
key_clear(EditLine *el, el_action_t *map, const char *in)
216
 
{
217
 
 
218
 
        if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
219
 
            ((map == el->el_map.key &&
220
 
            el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
221
 
            (map == el->el_map.alt &&
222
 
            el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
223
 
                (void) key_delete(el, in);
224
 
}
225
 
 
226
 
 
227
 
/* key_delete():
228
 
 *      Delete the key and all longer keys staring with key, if
229
 
 *      they exists.
230
 
 */
231
 
protected int
232
 
key_delete(EditLine *el, const char *key)
233
 
{
234
 
 
235
 
        if (key[0] == '\0') {
236
 
                (void) fprintf(el->el_errfile,
237
 
                    "key_delete: Null extended-key not allowed.\n");
238
 
                return (-1);
239
 
        }
240
 
        if (el->el_key.map == NULL)
241
 
                return (0);
242
 
 
243
 
        (void) node__delete(el, &el->el_key.map, key);
244
 
        return (0);
245
 
}
246
 
 
247
 
 
248
 
/* key_print():
249
 
 *      Print the binding associated with key key.
250
 
 *      Print entire el->el_key.map if null
251
 
 */
252
 
protected void
253
 
key_print(EditLine *el, const char *key)
254
 
{
255
 
 
256
 
        /* do nothing if el->el_key.map is empty and null key specified */
257
 
        if (el->el_key.map == NULL && *key == 0)
258
 
                return;
259
 
 
260
 
        el->el_key.buf[0] = '"';
261
 
        if (node_lookup(el, key, el->el_key.map, 1) <= -1)
262
 
                /* key is not bound */
263
 
                (void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n",
264
 
                    key);
265
 
        return;
266
 
}
267
 
 
268
 
 
269
 
/* node_trav():
270
 
 *      recursively traverses node in tree until match or mismatch is
271
 
 *      found.  May read in more characters.
272
 
 */
273
 
private int
274
 
node_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val)
275
 
{
276
 
 
277
 
        if (ptr->ch == *ch) {
278
 
                /* match found */
279
 
                if (ptr->next) {
280
 
                        /* key not complete so get next char */
281
 
                        if (el_getc(el, ch) != 1) {     /* if EOF or error */
282
 
                                val->cmd = ED_END_OF_FILE;
283
 
                                return (XK_CMD);
284
 
                                /* PWP: Pretend we just read an end-of-file */
285
 
                        }
286
 
                        return (node_trav(el, ptr->next, ch, val));
287
 
                } else {
288
 
                        *val = ptr->val;
289
 
                        if (ptr->type != XK_CMD)
290
 
                                *ch = '\0';
291
 
                        return (ptr->type);
292
 
                }
293
 
        } else {
294
 
                /* no match found here */
295
 
                if (ptr->sibling) {
296
 
                        /* try next sibling */
297
 
                        return (node_trav(el, ptr->sibling, ch, val));
298
 
                } else {
299
 
                        /* no next sibling -- mismatch */
300
 
                        val->str = NULL;
301
 
                        return (XK_STR);
302
 
                }
303
 
        }
304
 
}
305
 
 
306
 
 
307
 
/* node__try():
308
 
 *      Find a node that matches *str or allocate a new one
309
 
 */
310
 
private int
311
 
node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ntype)
312
 
{
313
 
 
314
 
        if (ptr->ch != *str) {
315
 
                key_node_t *xm;
316
 
 
317
 
                for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
318
 
                        if (xm->sibling->ch == *str)
319
 
                                break;
320
 
                if (xm->sibling == NULL)
321
 
                        xm->sibling = node__get(*str);  /* setup new node */
322
 
                ptr = xm->sibling;
323
 
        }
324
 
        if (*++str == '\0') {
325
 
                /* we're there */
326
 
                if (ptr->next != NULL) {
327
 
                        node__put(el, ptr->next);
328
 
                                /* lose longer keys with this prefix */
329
 
                        ptr->next = NULL;
330
 
                }
331
 
                switch (ptr->type) {
332
 
                case XK_CMD:
333
 
                case XK_NOD:
334
 
                        break;
335
 
                case XK_STR:
336
 
                case XK_EXE:
337
 
                        if (ptr->val.str)
338
 
                                el_free((ptr_t) ptr->val.str);
339
 
                        break;
340
 
                default:
341
 
                        EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
342
 
                            ptr->type));
343
 
                        break;
344
 
                }
345
 
 
346
 
                switch (ptr->type = ntype) {
347
 
                case XK_CMD:
348
 
                        ptr->val = *val;
349
 
                        break;
350
 
                case XK_STR:
351
 
                case XK_EXE:
352
 
                        if ((ptr->val.str = el_strdup(val->str)) == NULL)
353
 
                                return -1;
354
 
                        break;
355
 
                default:
356
 
                        EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
357
 
                        break;
358
 
                }
359
 
        } else {
360
 
                /* still more chars to go */
361
 
                if (ptr->next == NULL)
362
 
                        ptr->next = node__get(*str);    /* setup new node */
363
 
                (void) node__try(el, ptr->next, str, val, ntype);
364
 
        }
365
 
        return (0);
366
 
}
367
 
 
368
 
 
369
 
/* node__delete():
370
 
 *      Delete node that matches str
371
 
 */
372
 
private int
373
 
node__delete(EditLine *el, key_node_t **inptr, const char *str)
374
 
{
375
 
        key_node_t *ptr;
376
 
        key_node_t *prev_ptr = NULL;
377
 
 
378
 
        ptr = *inptr;
379
 
 
380
 
        if (ptr->ch != *str) {
381
 
                key_node_t *xm;
382
 
 
383
 
                for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
384
 
                        if (xm->sibling->ch == *str)
385
 
                                break;
386
 
                if (xm->sibling == NULL)
387
 
                        return (0);
388
 
                prev_ptr = xm;
389
 
                ptr = xm->sibling;
390
 
        }
391
 
        if (*++str == '\0') {
392
 
                /* we're there */
393
 
                if (prev_ptr == NULL)
394
 
                        *inptr = ptr->sibling;
395
 
                else
396
 
                        prev_ptr->sibling = ptr->sibling;
397
 
                ptr->sibling = NULL;
398
 
                node__put(el, ptr);
399
 
                return (1);
400
 
        } else if (ptr->next != NULL &&
401
 
            node__delete(el, &ptr->next, str) == 1) {
402
 
                if (ptr->next != NULL)
403
 
                        return (0);
404
 
                if (prev_ptr == NULL)
405
 
                        *inptr = ptr->sibling;
406
 
                else
407
 
                        prev_ptr->sibling = ptr->sibling;
408
 
                ptr->sibling = NULL;
409
 
                node__put(el, ptr);
410
 
                return (1);
411
 
        } else {
412
 
                return (0);
413
 
        }
414
 
}
415
 
 
416
 
 
417
 
/* node__put():
418
 
 *      Puts a tree of nodes onto free list using free(3).
419
 
 */
420
 
private void
421
 
node__put(EditLine *el, key_node_t *ptr)
422
 
{
423
 
        if (ptr == NULL)
424
 
                return;
425
 
 
426
 
        if (ptr->next != NULL) {
427
 
                node__put(el, ptr->next);
428
 
                ptr->next = NULL;
429
 
        }
430
 
        node__put(el, ptr->sibling);
431
 
 
432
 
        switch (ptr->type) {
433
 
        case XK_CMD:
434
 
        case XK_NOD:
435
 
                break;
436
 
        case XK_EXE:
437
 
        case XK_STR:
438
 
                if (ptr->val.str != NULL)
439
 
                        el_free((ptr_t) ptr->val.str);
440
 
                break;
441
 
        default:
442
 
                EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
443
 
                break;
444
 
        }
445
 
        el_free((ptr_t) ptr);
446
 
}
447
 
 
448
 
 
449
 
/* node__get():
450
 
 *      Returns pointer to a key_node_t for ch.
451
 
 */
452
 
private key_node_t *
453
 
node__get(int ch)
454
 
{
455
 
        key_node_t *ptr;
456
 
 
457
 
        ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
458
 
        if (ptr == NULL)
459
 
                return NULL;
460
 
        ptr->ch = ch;
461
 
        ptr->type = XK_NOD;
462
 
        ptr->val.str = NULL;
463
 
        ptr->next = NULL;
464
 
        ptr->sibling = NULL;
465
 
        return (ptr);
466
 
}
467
 
 
468
 
private void
469
 
node__free(key_node_t *k)
470
 
{
471
 
        if (k == NULL)
472
 
                return;
473
 
        node__free(k->sibling);
474
 
        node__free(k->next);
475
 
        el_free((ptr_t) k);
476
 
}
477
 
 
478
 
/* node_lookup():
479
 
 *      look for the str starting at node ptr.
480
 
 *      Print if last node
481
 
 */
482
 
private int
483
 
node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt)
484
 
{
485
 
        int ncnt;
486
 
 
487
 
        if (ptr == NULL)
488
 
                return (-1);    /* cannot have null ptr */
489
 
 
490
 
        if (*str == 0) {
491
 
                /* no more chars in str.  node_enum from here. */
492
 
                (void) node_enum(el, ptr, cnt);
493
 
                return (0);
494
 
        } else {
495
 
                /* If match put this char into el->el_key.buf.  Recurse */
496
 
                if (ptr->ch == *str) {
497
 
                        /* match found */
498
 
                        ncnt = key__decode_char(el->el_key.buf, KEY_BUFSIZ, cnt,
499
 
                            (unsigned char) ptr->ch);
500
 
                        if (ptr->next != NULL)
501
 
                                /* not yet at leaf */
502
 
                                return (node_lookup(el, str + 1, ptr->next,
503
 
                                    ncnt + 1));
504
 
                        else {
505
 
                            /* next node is null so key should be complete */
506
 
                                if (str[1] == 0) {
507
 
                                        el->el_key.buf[ncnt + 1] = '"';
508
 
                                        el->el_key.buf[ncnt + 2] = '\0';
509
 
                                        key_kprint(el, el->el_key.buf,
510
 
                                            &ptr->val, ptr->type);
511
 
                                        return (0);
512
 
                                } else
513
 
                                        return (-1);
514
 
                                        /* mismatch -- str still has chars */
515
 
                        }
516
 
                } else {
517
 
                        /* no match found try sibling */
518
 
                        if (ptr->sibling)
519
 
                                return (node_lookup(el, str, ptr->sibling,
520
 
                                    cnt));
521
 
                        else
522
 
                                return (-1);
523
 
                }
524
 
        }
525
 
}
526
 
 
527
 
 
528
 
/* node_enum():
529
 
 *      Traverse the node printing the characters it is bound in buffer
530
 
 */
531
 
private int
532
 
node_enum(EditLine *el, key_node_t *ptr, int cnt)
533
 
{
534
 
        int ncnt;
535
 
 
536
 
        if (cnt >= KEY_BUFSIZ - 5) {    /* buffer too small */
537
 
                el->el_key.buf[++cnt] = '"';
538
 
                el->el_key.buf[++cnt] = '\0';
539
 
                (void) fprintf(el->el_errfile,
540
 
                    "Some extended keys too long for internal print buffer");
541
 
                (void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
542
 
                return (0);
543
 
        }
544
 
        if (ptr == NULL) {
545
 
#ifdef DEBUG_EDIT
546
 
                (void) fprintf(el->el_errfile,
547
 
                    "node_enum: BUG!! Null ptr passed\n!");
548
 
#endif
549
 
                return (-1);
550
 
        }
551
 
        /* put this char at end of str */
552
 
        ncnt = key__decode_char(el->el_key.buf, KEY_BUFSIZ, cnt,
553
 
            (unsigned char)ptr->ch);
554
 
        if (ptr->next == NULL) {
555
 
                /* print this key and function */
556
 
                el->el_key.buf[ncnt + 1] = '"';
557
 
                el->el_key.buf[ncnt + 2] = '\0';
558
 
                key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
559
 
        } else
560
 
                (void) node_enum(el, ptr->next, ncnt + 1);
561
 
 
562
 
        /* go to sibling if there is one */
563
 
        if (ptr->sibling)
564
 
                (void) node_enum(el, ptr->sibling, cnt);
565
 
        return (0);
566
 
}
567
 
 
568
 
 
569
 
/* key_kprint():
570
 
 *      Print the specified key and its associated
571
 
 *      function specified by val
572
 
 */
573
 
protected void
574
 
key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype)
575
 
{
576
 
        el_bindings_t *fp;
577
 
        char unparsbuf[EL_BUFSIZ];
578
 
        static const char fmt[] = "%-15s->  %s\n";
579
 
 
580
 
        if (val != NULL)
581
 
                switch (ntype) {
582
 
                case XK_STR:
583
 
                case XK_EXE:
584
 
                        (void) key__decode_str(val->str, unparsbuf,
585
 
                            sizeof(unparsbuf), 
586
 
                            ntype == XK_STR ? "\"\"" : "[]");
587
 
                        (void) fprintf(el->el_outfile, fmt, key, unparsbuf);
588
 
                        break;
589
 
                case XK_CMD:
590
 
                        for (fp = el->el_map.help; fp->name; fp++)
591
 
                                if (val->cmd == fp->func) {
592
 
                                        (void) fprintf(el->el_outfile, fmt,
593
 
                                            key, fp->name);
594
 
                                        break;
595
 
                                }
596
 
#ifdef DEBUG_KEY
597
 
                        if (fp->name == NULL)
598
 
                                (void) fprintf(el->el_outfile,
599
 
                                    "BUG! Command not found.\n");
600
 
#endif
601
 
 
602
 
                        break;
603
 
                default:
604
 
                        EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
605
 
                        break;
606
 
                }
607
 
        else
608
 
                (void) fprintf(el->el_outfile, fmt, key, "no input");
609
 
}
610
 
 
611
 
 
612
 
#define ADDC(c) \
613
 
        if (b < eb) \
614
 
                *b++ = c; \
615
 
        else \
616
 
                b++
617
 
/* key__decode_char():
618
 
 *      Put a printable form of char in buf.
619
 
 */
620
 
protected int
621
 
key__decode_char(char *buf, int cnt, int off, int ch)
622
 
{
623
 
        char *sb = buf + off;
624
 
        char *eb = buf + cnt;
625
 
        char *b = sb;
626
 
        if (ch == 0) {
627
 
                ADDC('^');
628
 
                ADDC('@');
629
 
                return b - sb;
630
 
        }
631
 
        if (iscntrl(ch)) {
632
 
                ADDC('^');
633
 
                if (ch == '\177')
634
 
                        ADDC('?');
635
 
                else
636
 
                        ADDC(ch | 0100);
637
 
        } else if (ch == '^') {
638
 
                ADDC('\\');
639
 
                ADDC('^');
640
 
        } else if (ch == '\\') {
641
 
                ADDC('\\');
642
 
                ADDC('\\');
643
 
        } else if (ch == ' ' || (el_isprint(ch) && !isspace(ch))) {
644
 
                ADDC(ch);
645
 
        } else {
646
 
                ADDC('\\');
647
 
                ADDC((((unsigned int) ch >> 6) & 7) + '0');
648
 
                ADDC((((unsigned int) ch >> 3) & 7) + '0');
649
 
                ADDC((ch & 7) + '0');
650
 
        }
651
 
        return b - sb;
652
 
}
653
 
 
654
 
 
655
 
/* key__decode_str():
656
 
 *      Make a printable version of the ey
657
 
 */
658
 
protected int
659
 
key__decode_str(const char *str, char *buf, int len, const char *sep)
660
 
{
661
 
        char *b = buf, *eb = b + len;
662
 
        const char *p;
663
 
 
664
 
        b = buf;
665
 
        if (sep[0] != '\0') {
666
 
                ADDC(sep[0]);
667
 
        }
668
 
        if (*str == '\0') {
669
 
                ADDC('^');
670
 
                ADDC('@');
671
 
                if (sep[0] != '\0' && sep[1] != '\0') {
672
 
                        ADDC(sep[1]);
673
 
                }
674
 
                goto done;
675
 
        }
676
 
        for (p = str; *p != 0; p++) {
677
 
                if (iscntrl((unsigned char) *p)) {
678
 
                        ADDC('^');
679
 
                        if (*p == '\177') {
680
 
                                ADDC('?');
681
 
                        } else {
682
 
                                ADDC(*p | 0100);
683
 
                        }
684
 
                } else if (*p == '^' || *p == '\\') {
685
 
                        ADDC('\\');
686
 
                        ADDC(*p);
687
 
                } else if (*p == ' ' || (el_isprint((unsigned char) *p) &&
688
 
                        !isspace((unsigned char) *p))) {
689
 
                        ADDC(*p);
690
 
                } else {
691
 
                        ADDC('\\');
692
 
                        ADDC((((unsigned int) *p >> 6) & 7) + '0');
693
 
                        ADDC((((unsigned int) *p >> 3) & 7) + '0');
694
 
                        ADDC((*p & 7) + '0');
695
 
                }
696
 
        }
697
 
        if (sep[0] != '\0' && sep[1] != '\0') {
698
 
                ADDC(sep[1]);
699
 
        }
700
 
done:
701
 
        ADDC('\0');
702
 
        if (b - buf >= len)
703
 
            buf[len - 1] = '\0';
704
 
        return b - buf;
705
 
}