IMPORT openssh-9.8p1
[dragonfly.git] / contrib / tcsh-6 / ed.xmap.c
blob65f025b238a61636e4fc45af352279e899fe73dc
1 /*
2 * ed.xmap.c: This module contains the procedures for maintaining
3 * the extended-key map.
5 * An extended-key (Xkey) is a sequence of keystrokes
6 * introduced with an sequence introducer and consisting
7 * of an arbitrary number of characters. This module maintains
8 * a map (the Xmap) to convert these extended-key sequences
9 * into input strings (XK_STR), editor functions (XK_CMD), or
10 * unix commands (XK_EXE). It contains the
11 * following externally visible functions.
13 * int GetXkey(ch,val);
14 * CStr *ch;
15 * XmapVal *val;
17 * Looks up *ch in map and then reads characters until a
18 * complete match is found or a mismatch occurs. Returns the
19 * type of the match found (XK_STR, XK_CMD, or XK_EXE).
20 * Returns NULL in val.str and XK_STR for no match.
21 * The last character read is returned in *ch.
23 * void AddXkey(Xkey, val, ntype);
24 * CStr *Xkey;
25 * XmapVal *val;
26 * int ntype;
28 * Adds Xkey to the Xmap and associates the value in val with it.
29 * If Xkey is already is in Xmap, the new code is applied to the
30 * existing Xkey. Ntype specifies if code is a command, an
31 * out string or a unix command.
33 * int DeleteXkey(Xkey);
34 * CStr *Xkey;
36 * Delete the Xkey and all longer Xkeys staring with Xkey, if
37 * they exists.
39 * Warning:
40 * If Xkey is a substring of some other Xkeys, then the longer
41 * Xkeys are lost!! That is, if the Xkeys "abcd" and "abcef"
42 * are in Xmap, adding the key "abc" will cause the first two
43 * definitions to be lost.
45 * void ResetXmap();
47 * Removes all entries from Xmap and resets the defaults.
49 * void PrintXkey(Xkey);
50 * CStr *Xkey;
52 * Prints all extended keys prefixed by Xkey and their associated
53 * commands.
55 * Restrictions:
56 * -------------
57 * 1) It is not possible to have one Xkey that is a
58 * substring of another.
60 /*-
61 * Copyright (c) 1980, 1991 The Regents of the University of California.
62 * All rights reserved.
64 * Redistribution and use in source and binary forms, with or without
65 * modification, are permitted provided that the following conditions
66 * are met:
67 * 1. Redistributions of source code must retain the above copyright
68 * notice, this list of conditions and the following disclaimer.
69 * 2. Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in the
71 * documentation and/or other materials provided with the distribution.
72 * 3. Neither the name of the University nor the names of its contributors
73 * may be used to endorse or promote products derived from this software
74 * without specific prior written permission.
76 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
77 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
80 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
81 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
82 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
83 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
84 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
85 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
86 * SUCH DAMAGE.
88 #include "sh.h"
89 #include "ed.h"
90 #include "ed.defns.h"
92 #ifndef NULL
93 #define NULL 0
94 #endif
96 /* Internal Data types and declarations */
98 /* The Nodes of the Xmap. The Xmap is a linked list of these node
99 * elements
101 typedef struct Xmapnode {
102 Char ch; /* single character of Xkey */
103 int type;
104 XmapVal val; /* command code or pointer to string, if this
105 * is a leaf */
106 struct Xmapnode *next; /* ptr to next char of this Xkey */
107 struct Xmapnode *sibling; /* ptr to another Xkey with same prefix */
108 } XmapNode;
110 static XmapNode *Xmap = NULL; /* the current Xmap */
113 /* Some declarations of procedures */
114 static int TraverseMap (XmapNode *, CStr *, XmapVal *);
115 static int TryNode (XmapNode *, CStr *, XmapVal *, int);
116 static XmapNode *GetFreeNode (CStr *);
117 static void PutFreeNode (XmapNode *);
118 static int TryDeleteNode (XmapNode **, CStr *);
119 static int Lookup (struct Strbuf *, const CStr *,
120 const XmapNode *);
121 static void Enumerate (struct Strbuf *, const XmapNode *);
122 static void unparsech (struct Strbuf *, Char);
125 XmapVal *
126 XmapCmd(int cmd)
128 static XmapVal xm;
129 xm.cmd = (KEYCMD) cmd;
130 return &xm;
133 XmapVal *
134 XmapStr(CStr *str)
136 static XmapVal xm;
137 xm.str.len = str->len;
138 xm.str.buf = str->buf;
139 return &xm;
142 /* ResetXmap():
143 * Takes all nodes on Xmap and puts them on free list. Then
144 * initializes Xmap with arrow keys
146 void
147 ResetXmap(void)
149 PutFreeNode(Xmap);
150 Xmap = NULL;
152 DefaultArrowKeys();
153 return;
157 /* GetXkey():
158 * Calls the recursive function with entry point Xmap
161 GetXkey(CStr *ch, XmapVal *val)
163 return (TraverseMap(Xmap, ch, val));
166 /* TraverseMap():
167 * recursively traverses node in tree until match or mismatch is
168 * found. May read in more characters.
170 static int
171 TraverseMap(XmapNode *ptr, CStr *ch, XmapVal *val)
173 Char tch;
175 if (ptr->ch == *(ch->buf)) {
176 /* match found */
177 if (ptr->next) {
178 /* Xkey not complete so get next char */
179 if (GetNextChar(&tch) != 1) { /* if EOF or error */
180 val->cmd = F_SEND_EOF;
181 return XK_CMD;/* PWP: Pretend we just read an end-of-file */
183 *(ch->buf) = tch;
184 return (TraverseMap(ptr->next, ch, val));
186 else {
187 *val = ptr->val;
188 if (ptr->type != XK_CMD)
189 *(ch->buf) = '\0';
190 return ptr->type;
193 else {
194 /* no match found here */
195 if (ptr->sibling) {
196 /* try next sibling */
197 return (TraverseMap(ptr->sibling, ch, val));
199 else {
200 /* no next sibling -- mismatch */
201 val->str.buf = NULL;
202 val->str.len = 0;
203 return XK_STR;
208 void
209 AddXkey(const CStr *Xkey, XmapVal *val, int ntype)
211 CStr cs;
212 cs.buf = Xkey->buf;
213 cs.len = Xkey->len;
214 if (Xkey->len == 0) {
215 xprintf("%s", CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n"));
216 return;
219 if (ntype == XK_CMD && val->cmd == F_XKEY) {
220 xprintf("%s",
221 CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n"));
222 return;
225 if (Xmap == NULL)
226 /* tree is initially empty. Set up new node to match Xkey[0] */
227 Xmap = GetFreeNode(&cs); /* it is properly initialized */
229 /* Now recurse through Xmap */
230 (void) TryNode(Xmap, &cs, val, ntype);
231 return;
234 static int
235 TryNode(XmapNode *ptr, CStr *str, XmapVal *val, int ntype)
238 * Find a node that matches *string or allocate a new one
240 if (ptr->ch != *(str->buf)) {
241 XmapNode *xm;
243 for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
244 if (xm->sibling->ch == *(str->buf))
245 break;
246 if (xm->sibling == NULL)
247 xm->sibling = GetFreeNode(str); /* setup new node */
248 ptr = xm->sibling;
251 str->buf++;
252 str->len--;
253 if (str->len == 0) {
254 size_t len;
256 /* we're there */
257 if (ptr->next != NULL) {
258 PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */
259 ptr->next = NULL;
262 switch (ptr->type) {
263 case XK_STR:
264 case XK_EXE:
265 xfree(ptr->val.str.buf);
266 ptr->val.str.len = 0;
267 break;
268 case XK_NOD:
269 case XK_CMD:
270 break;
271 default:
272 abort();
273 break;
276 switch (ptr->type = ntype) {
277 case XK_CMD:
278 ptr->val = *val;
279 break;
280 case XK_STR:
281 case XK_EXE:
282 ptr->val.str.len = val->str.len;
283 len = (val->str.len + 1) * sizeof(*ptr->val.str.buf);
284 ptr->val.str.buf = xmalloc(len);
285 (void) memcpy(ptr->val.str.buf, val->str.buf, len);
286 break;
287 default:
288 abort();
289 break;
292 else {
293 /* still more chars to go */
294 if (ptr->next == NULL)
295 ptr->next = GetFreeNode(str); /* setup new node */
296 (void) TryNode(ptr->next, str, val, ntype);
298 return (0);
301 void
302 ClearXkey(KEYCMD *map, const CStr *in)
304 unsigned char c = (unsigned char) *(in->buf);
305 if ((map[c] == F_XKEY) &&
306 ((map == CcKeyMap && CcAltMap[c] != F_XKEY) ||
307 (map == CcAltMap && CcKeyMap[c] != F_XKEY)))
308 (void) DeleteXkey(in);
312 DeleteXkey(const CStr *Xkey)
314 CStr s;
316 s = *Xkey;
317 if (s.len == 0) {
318 xprintf("%s",
319 CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n"));
320 return (-1);
323 if (Xmap == NULL)
324 return (0);
326 (void) TryDeleteNode(&Xmap, &s);
327 return (0);
330 /* Destroys str */
331 static int
332 TryDeleteNode(XmapNode **inptr, CStr *str)
334 XmapNode *ptr;
336 ptr = *inptr;
338 * Find a node that matches *string or allocate a new one
340 if (ptr->ch != *(str->buf)) {
341 XmapNode *xm;
343 for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
344 if (xm->sibling->ch == *(str->buf))
345 break;
346 if (xm->sibling == NULL)
347 return (0);
348 inptr = &xm->sibling;
349 ptr = xm->sibling;
352 str->buf++;
353 str->len--;
355 if (str->len == 0) {
356 /* we're there */
357 *inptr = ptr->sibling;
358 ptr->sibling = NULL;
359 PutFreeNode(ptr);
360 return (1);
362 else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) {
363 if (ptr->next != NULL)
364 return (0);
365 *inptr = ptr->sibling;
366 ptr->sibling = NULL;
367 PutFreeNode(ptr);
368 return (1);
370 else {
371 return (0);
375 /* PutFreeNode():
376 * Puts a tree of nodes onto free list using free(3).
378 static void
379 PutFreeNode(XmapNode *ptr)
381 if (ptr == NULL)
382 return;
384 if (ptr->next != NULL) {
385 PutFreeNode(ptr->next);
386 ptr->next = NULL;
389 PutFreeNode(ptr->sibling);
391 switch (ptr->type) {
392 case XK_CMD:
393 case XK_NOD:
394 break;
395 case XK_EXE:
396 case XK_STR:
397 xfree(ptr->val.str.buf);
398 break;
399 default:
400 abort();
401 break;
403 xfree(ptr);
407 /* GetFreeNode():
408 * Returns pointer to an XmapNode for ch.
410 static XmapNode *
411 GetFreeNode(CStr *ch)
413 XmapNode *ptr;
415 ptr = xmalloc(sizeof(XmapNode));
416 ptr->ch = ch->buf[0];
417 ptr->type = XK_NOD;
418 ptr->val.str.buf = NULL;
419 ptr->val.str.len = 0;
420 ptr->next = NULL;
421 ptr->sibling = NULL;
422 return (ptr);
426 /* PrintXKey():
427 * Print the binding associated with Xkey key.
428 * Print entire Xmap if null
430 void
431 PrintXkey(const CStr *key)
433 struct Strbuf buf = Strbuf_INIT;
434 CStr cs;
436 if (key) {
437 cs.buf = key->buf;
438 cs.len = key->len;
440 else {
441 cs.buf = STRNULL;
442 cs.len = 0;
444 /* do nothing if Xmap is empty and null key specified */
445 if (Xmap == NULL && cs.len == 0)
446 return;
448 Strbuf_append1(&buf, '"');
449 cleanup_push(&buf, Strbuf_cleanup);
450 if (Lookup(&buf, &cs, Xmap) <= -1)
451 /* key is not bound */
452 xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf);
453 cleanup_until(&buf);
456 /* Lookup():
457 * look for the string starting at node ptr.
458 * Print if last node
460 static int
461 Lookup(struct Strbuf *buf, const CStr *str, const XmapNode *ptr)
463 if (ptr == NULL)
464 return (-1); /* cannot have null ptr */
466 if (str->len == 0) {
467 /* no more chars in string. Enumerate from here. */
468 Enumerate(buf, ptr);
469 return (0);
471 else {
472 /* If match put this char into buf. Recurse */
473 if (ptr->ch == *(str->buf)) {
474 /* match found */
475 unparsech(buf, ptr->ch);
476 if (ptr->next != NULL) {
477 /* not yet at leaf */
478 CStr tstr;
479 tstr.buf = str->buf + 1;
480 tstr.len = str->len - 1;
481 return (Lookup(buf, &tstr, ptr->next));
483 else {
484 /* next node is null so key should be complete */
485 if (str->len == 1) {
486 Strbuf_append1(buf, '"');
487 Strbuf_terminate(buf);
488 printOne(buf->s, &ptr->val, ptr->type);
489 return (0);
491 else
492 return (-1);/* mismatch -- string still has chars */
495 else {
496 /* no match found try sibling */
497 if (ptr->sibling)
498 return (Lookup(buf, str, ptr->sibling));
499 else
500 return (-1);
505 static void
506 Enumerate(struct Strbuf *buf, const XmapNode *ptr)
508 size_t old_len;
510 if (ptr == NULL) {
511 #ifdef DEBUG_EDIT
512 xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!"));
513 #endif
514 return;
517 old_len = buf->len;
518 unparsech(buf, ptr->ch); /* put this char at end of string */
519 if (ptr->next == NULL) {
520 /* print this Xkey and function */
521 Strbuf_append1(buf, '"');
522 Strbuf_terminate(buf);
523 printOne(buf->s, &ptr->val, ptr->type);
525 else
526 Enumerate(buf, ptr->next);
528 /* go to sibling if there is one */
529 if (ptr->sibling) {
530 buf->len = old_len;
531 Enumerate(buf, ptr->sibling);
536 /* PrintOne():
537 * Print the specified key and its associated
538 * function specified by val
540 void
541 printOne(const Char *key, const XmapVal *val, int ntype)
543 struct KeyFuncs *fp;
544 static const char *fmt = "%s\n";
546 xprintf("%-15" TCSH_S "-> ", key);
547 if (val != NULL)
548 switch (ntype) {
549 case XK_STR:
550 case XK_EXE: {
551 unsigned char *p;
553 p = unparsestring(&val->str, ntype == XK_STR ? STRQQ : STRBB);
554 cleanup_push(p, xfree);
555 xprintf(fmt, p);
556 cleanup_until(p);
557 break;
559 case XK_CMD:
560 for (fp = FuncNames; fp->name; fp++)
561 if (val->cmd == fp->func)
562 xprintf(fmt, fp->name);
563 break;
564 default:
565 abort();
566 break;
568 else
569 xprintf(fmt, CGETS(9, 7, "no input"));
572 static void
573 unparsech(struct Strbuf *buf, Char ch)
575 if (ch == 0) {
576 Strbuf_append1(buf, '^');
577 Strbuf_append1(buf, '@');
579 else if (Iscntrl(ch)) {
580 Strbuf_append1(buf, '^');
581 if (ch == CTL_ESC('\177'))
582 Strbuf_append1(buf, '?');
583 else
584 #ifdef IS_ASCII
585 Strbuf_append1(buf, ch | 0100);
586 #else
587 Strbuf_append1(buf, _toebcdic[_toascii[ch]|0100]);
588 #endif
590 else if (ch == '^') {
591 Strbuf_append1(buf, '\\');
592 Strbuf_append1(buf, '^');
593 } else if (ch == '\\') {
594 Strbuf_append1(buf, '\\');
595 Strbuf_append1(buf, '\\');
596 } else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) {
597 Strbuf_append1(buf, ch);
599 else {
600 Strbuf_append1(buf, '\\');
601 Strbuf_append1(buf, ((ch >> 6) & 7) + '0');
602 Strbuf_append1(buf, ((ch >> 3) & 7) + '0');
603 Strbuf_append1(buf, (ch & 7) + '0');
607 static Char
608 parse_hex_range(const Char **cp, size_t l)
610 size_t ui = 0;
611 Char r = 0, c;
613 if (l > 8)
614 abort();
616 for (; (c = (**cp & CHAR)) != '\0' && ui < l && Isxdigit(c); (*cp)++, ui++) {
617 Char x = Isdigit(c) ? '0' : ((Isupper(c) ? 'A' : 'a') - 10);
618 #ifndef IS_ASCII
619 c = _toascii(c);
620 #endif
621 r <<= 4;
622 r |= c - x;
624 (*cp)--;
625 #ifndef IS_ASCII
626 return _toebcdic[r & 0xff];
627 #else
628 return r;
629 #endif
633 * The e parameter is false when we are doing echo and true when we are
634 * using it to parse other escaped strings. For echo, we don't print errors
635 * and we don't unescape backslashes that we don't understand. Perhaps we
636 * always not unescape backslashes we don't understand...
638 eChar
639 parseescape(const Char **ptr, int e)
641 const Char *p;
642 Char c;
644 p = *ptr;
646 if ((p[1] & CHAR) == 0) {
647 if (e)
648 xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p);
649 return CHAR_ERR;
651 if ((*p & CHAR) == '\\') {
652 p++;
653 switch (*p & CHAR) {
654 case 'a':
655 c = CTL_ESC('\007'); /* Bell */
656 break;
657 case 'b':
658 c = CTL_ESC('\010'); /* Backspace */
659 break;
660 case 'c':
661 p++;
662 if ((*p & CHAR) == '\\') {
663 p++;
664 if ((*p & CHAR) != '\\') {
665 *ptr = p;
666 if (e)
667 xprintf(/*CGETS(9, 9, */
668 "Invalid escape sequence: %s%c\n"/*)*/, "\\c\\", (char)*p);
669 return CHAR_ERR;
671 c = (*p & CHAR) & 0237;
672 } else if ((Isalpha(*p & CHAR) || strchr("@^_?\\|[{]}", *p & CHAR))) {
673 /* XXX: Duplicate code from ^ below */
674 #ifdef IS_ASCII
675 c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
676 #else
677 c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
678 if (adrof(STRwarnebcdic))
679 xprintf(/*CGETS(9, 9, no NLS-String yet!*/
680 "Warning: Control character %s%c may be interpreted differently in EBCDIC.\n", "\\c", *p & CHAR /*)*/);
681 #endif
682 } else { /* backward compat */
683 c = '\\';
684 p -= 2;
686 break;
687 case 'e':
688 c = CTL_ESC('\033'); /* Escape */
689 break;
690 case 'f':
691 c = CTL_ESC('\014'); /* Form Feed */
692 break;
693 case 'n':
694 c = CTL_ESC('\012'); /* New Line */
695 break;
696 case 'r':
697 c = CTL_ESC('\015'); /* Carriage Return */
698 break;
699 case 't':
700 c = CTL_ESC('\011'); /* Horizontal Tab */
701 break;
702 case 'v':
703 c = CTL_ESC('\013'); /* Vertical Tab */
704 break;
705 case '\\':
706 c = '\\';
707 break;
708 case 'x':
709 p++;
710 if ((*p & CHAR) == '{' && Isxdigit(*(p + 1) & CHAR)) { /* \x{20ac} */
711 const Char *q = p - 2;
712 p++;
713 c = parse_hex_range(&p, 8);
714 if ((p[1] & CHAR) != '}') {
715 if (e)
716 xprintf("%s", /* CGETS(9, 9, */
717 "Missing closing brace");
718 p = q;
719 c = '\\';
720 break;
722 p++;
723 } else if (Isxdigit(*p & CHAR)) { /* \x9f */
724 c = parse_hex_range(&p, 2);
725 } else { /* backward compat */
726 c = '\\';
727 p -= 2;
729 break;
730 case 'u':
731 case 'U':
733 size_t limit = (*p & CHAR) == 'u' ? 4 : 8;
734 p++;
735 if (Isxdigit(*p & CHAR)) { /* \u20ac or \U000020ac */
736 c = parse_hex_range(&p, limit);
737 } else { /* backward compat */
738 c = '\\';
739 p -= 2;
742 break;
743 case '0':
744 case '1':
745 case '2':
746 case '3':
747 case '4':
748 case '5':
749 case '6':
750 case '7':
752 int cnt, val;
753 Char ch;
755 for (cnt = 0, val = 0; cnt < 3; cnt++) {
756 ch = *p++ & CHAR;
757 if (ch < '0' || ch > '7') {
758 p--;
759 break;
761 val = (val << 3) | (ch - '0');
763 if ((val & ~0xff) != 0) {
764 if (e)
765 xprintf("%s", CGETS(9, 9,
766 "Octal constant does not fit in a char.\n"));
767 *ptr = p;
768 return CHAR_ERR;
770 #ifndef IS_ASCII
771 if (CTL_ESC(val) != val && adrof(STRwarnebcdic))
772 xprintf(/*CGETS(9, 9, no NLS-String yet!*/
773 "Warning: Octal constant \\%3.3o is interpreted as "
774 "EBCDIC value.\n", val/*)*/);
775 #endif
776 c = (Char) val;
777 --p;
779 break;
780 default:
781 if (!e)
782 --p;
783 c = *p;
784 break;
787 else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) ||
788 strchr("@^_?\\|[{]}", p[1] & CHAR))) {
789 p++;
790 #ifdef IS_ASCII
791 c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
792 #else
793 c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
794 if (adrof(STRwarnebcdic))
795 xprintf(/*CGETS(9, 9, no NLS-String yet!*/
796 "Warning: Control character %s%c may be interpreted differently in EBCDIC.\n", "^", *p & CHAR /*)*/);
797 #endif
799 else
800 c = *p & CHAR;
801 *ptr = p;
802 return (c);
806 unsigned char *
807 unparsestring(const CStr *str, const Char *sep)
809 unsigned char *buf, *b;
810 Char p;
811 int l;
813 /* Worst-case is "\uuu" or result of wctomb() for each char from str */
814 buf = xmalloc((str->len + 1) * max(4, MB_LEN_MAX));
815 b = buf;
816 if (sep[0])
817 #ifndef WINNT_NATIVE
818 *b++ = sep[0];
819 #else /* WINNT_NATIVE */
820 *b++ = CHAR & sep[0];
821 #endif /* !WINNT_NATIVE */
823 for (l = 0; l < str->len; l++) {
824 p = str->buf[l];
825 if (Iscntrl(p)) {
826 *b++ = '^';
827 if (p == CTL_ESC('\177'))
828 *b++ = '?';
829 else
830 #ifdef IS_ASCII
831 *b++ = (unsigned char) (p | 0100);
832 #else
833 *b++ = _toebcdic[_toascii[p]|0100];
834 #endif
836 else if (p == '^' || p == '\\') {
837 *b++ = '\\';
838 *b++ = (unsigned char) p;
840 else if (p == ' ' || (Isprint(p) && !Isspace(p)))
841 b += one_wctomb((char *)b, p);
842 else {
843 *b++ = '\\';
844 *b++ = ((p >> 6) & 7) + '0';
845 *b++ = ((p >> 3) & 7) + '0';
846 *b++ = (p & 7) + '0';
849 if (sep[0] && sep[1])
850 #ifndef WINNT_NATIVE
851 *b++ = sep[1];
852 #else /* WINNT_NATIVE */
853 *b++ = CHAR & sep[1];
854 #endif /* !WINNT_NATIVE */
855 *b++ = 0;
856 return buf; /* should check for overflow */