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