/contrib/tcsh/ed.xmap.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 762 lines · 576 code · 51 blank · 135 comment · 83 complexity · 6c13610f6a3df39184fd3cf5eb4959cb MD5 · raw file

  1. /* $Header: /p/tcsh/cvsroot/tcsh/ed.xmap.c,v 3.37 2009/06/25 21:15:37 christos 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. Neither the name of the University nor the names of its contributors
  74. * may be used to endorse or promote products derived from this software
  75. * without specific prior written permission.
  76. *
  77. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  78. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  79. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  80. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  81. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  82. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  83. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  84. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  85. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  86. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  87. * SUCH DAMAGE.
  88. */
  89. #include "sh.h"
  90. RCSID("$tcsh: ed.xmap.c,v 3.37 2009/06/25 21:15:37 christos Exp $")
  91. #include "ed.h"
  92. #include "ed.defns.h"
  93. #ifndef NULL
  94. #define NULL 0
  95. #endif
  96. /* Internal Data types and declarations */
  97. /* The Nodes of the Xmap. The Xmap is a linked list of these node
  98. * elements
  99. */
  100. typedef struct Xmapnode {
  101. Char ch; /* single character of Xkey */
  102. int type;
  103. XmapVal val; /* command code or pointer to string, if this
  104. * is a leaf */
  105. struct Xmapnode *next; /* ptr to next char of this Xkey */
  106. struct Xmapnode *sibling; /* ptr to another Xkey with same prefix */
  107. } XmapNode;
  108. static XmapNode *Xmap = NULL; /* the current Xmap */
  109. /* Some declarations of procedures */
  110. static int TraverseMap (XmapNode *, CStr *, XmapVal *);
  111. static int TryNode (XmapNode *, CStr *, XmapVal *, int);
  112. static XmapNode *GetFreeNode (CStr *);
  113. static void PutFreeNode (XmapNode *);
  114. static int TryDeleteNode (XmapNode **, CStr *);
  115. static int Lookup (struct Strbuf *, const CStr *,
  116. const XmapNode *);
  117. static void Enumerate (struct Strbuf *, const XmapNode *);
  118. static void unparsech (struct Strbuf *, Char);
  119. XmapVal *
  120. XmapCmd(int cmd)
  121. {
  122. static XmapVal xm;
  123. xm.cmd = (KEYCMD) cmd;
  124. return &xm;
  125. }
  126. XmapVal *
  127. XmapStr(CStr *str)
  128. {
  129. static XmapVal xm;
  130. xm.str.len = str->len;
  131. xm.str.buf = str->buf;
  132. return &xm;
  133. }
  134. /* ResetXmap():
  135. * Takes all nodes on Xmap and puts them on free list. Then
  136. * initializes Xmap with arrow keys
  137. */
  138. void
  139. ResetXmap(void)
  140. {
  141. PutFreeNode(Xmap);
  142. Xmap = NULL;
  143. DefaultArrowKeys();
  144. return;
  145. }
  146. /* GetXkey():
  147. * Calls the recursive function with entry point Xmap
  148. */
  149. int
  150. GetXkey(CStr *ch, XmapVal *val)
  151. {
  152. return (TraverseMap(Xmap, ch, val));
  153. }
  154. /* TraverseMap():
  155. * recursively traverses node in tree until match or mismatch is
  156. * found. May read in more characters.
  157. */
  158. static int
  159. TraverseMap(XmapNode *ptr, CStr *ch, XmapVal *val)
  160. {
  161. Char tch;
  162. if (ptr->ch == *(ch->buf)) {
  163. /* match found */
  164. if (ptr->next) {
  165. /* Xkey not complete so get next char */
  166. if (GetNextChar(&tch) != 1) { /* if EOF or error */
  167. val->cmd = F_SEND_EOF;
  168. return XK_CMD;/* PWP: Pretend we just read an end-of-file */
  169. }
  170. *(ch->buf) = tch;
  171. return (TraverseMap(ptr->next, ch, val));
  172. }
  173. else {
  174. *val = ptr->val;
  175. if (ptr->type != XK_CMD)
  176. *(ch->buf) = '\0';
  177. return ptr->type;
  178. }
  179. }
  180. else {
  181. /* no match found here */
  182. if (ptr->sibling) {
  183. /* try next sibling */
  184. return (TraverseMap(ptr->sibling, ch, val));
  185. }
  186. else {
  187. /* no next sibling -- mismatch */
  188. val->str.buf = NULL;
  189. val->str.len = 0;
  190. return XK_STR;
  191. }
  192. }
  193. }
  194. void
  195. AddXkey(const CStr *Xkey, XmapVal *val, int ntype)
  196. {
  197. CStr cs;
  198. cs.buf = Xkey->buf;
  199. cs.len = Xkey->len;
  200. if (Xkey->len == 0) {
  201. xprintf("%s", CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n"));
  202. return;
  203. }
  204. if (ntype == XK_CMD && val->cmd == F_XKEY) {
  205. xprintf("%s",
  206. CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n"));
  207. return;
  208. }
  209. if (Xmap == NULL)
  210. /* tree is initially empty. Set up new node to match Xkey[0] */
  211. Xmap = GetFreeNode(&cs); /* it is properly initialized */
  212. /* Now recurse through Xmap */
  213. (void) TryNode(Xmap, &cs, val, ntype);
  214. return;
  215. }
  216. static int
  217. TryNode(XmapNode *ptr, CStr *str, XmapVal *val, int ntype)
  218. {
  219. /*
  220. * Find a node that matches *string or allocate a new one
  221. */
  222. if (ptr->ch != *(str->buf)) {
  223. XmapNode *xm;
  224. for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  225. if (xm->sibling->ch == *(str->buf))
  226. break;
  227. if (xm->sibling == NULL)
  228. xm->sibling = GetFreeNode(str); /* setup new node */
  229. ptr = xm->sibling;
  230. }
  231. str->buf++;
  232. str->len--;
  233. if (str->len == 0) {
  234. size_t len;
  235. /* we're there */
  236. if (ptr->next != NULL) {
  237. PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */
  238. ptr->next = NULL;
  239. }
  240. switch (ptr->type) {
  241. case XK_STR:
  242. case XK_EXE:
  243. xfree(ptr->val.str.buf);
  244. ptr->val.str.len = 0;
  245. break;
  246. case XK_NOD:
  247. case XK_CMD:
  248. break;
  249. default:
  250. abort();
  251. break;
  252. }
  253. switch (ptr->type = ntype) {
  254. case XK_CMD:
  255. ptr->val = *val;
  256. break;
  257. case XK_STR:
  258. case XK_EXE:
  259. ptr->val.str.len = val->str.len;
  260. len = (val->str.len + 1) * sizeof(*ptr->val.str.buf);
  261. ptr->val.str.buf = xmalloc(len);
  262. (void) memcpy(ptr->val.str.buf, val->str.buf, len);
  263. break;
  264. default:
  265. abort();
  266. break;
  267. }
  268. }
  269. else {
  270. /* still more chars to go */
  271. if (ptr->next == NULL)
  272. ptr->next = GetFreeNode(str); /* setup new node */
  273. (void) TryNode(ptr->next, str, val, ntype);
  274. }
  275. return (0);
  276. }
  277. void
  278. ClearXkey(KEYCMD *map, const CStr *in)
  279. {
  280. unsigned char c = (unsigned char) *(in->buf);
  281. if ((map[c] == F_XKEY) &&
  282. ((map == CcKeyMap && CcAltMap[c] != F_XKEY) ||
  283. (map == CcAltMap && CcKeyMap[c] != F_XKEY)))
  284. (void) DeleteXkey(in);
  285. }
  286. int
  287. DeleteXkey(const CStr *Xkey)
  288. {
  289. CStr s;
  290. s = *Xkey;
  291. if (s.len == 0) {
  292. xprintf("%s",
  293. CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n"));
  294. return (-1);
  295. }
  296. if (Xmap == NULL)
  297. return (0);
  298. (void) TryDeleteNode(&Xmap, &s);
  299. return (0);
  300. }
  301. /* Destroys str */
  302. static int
  303. TryDeleteNode(XmapNode **inptr, CStr *str)
  304. {
  305. XmapNode *ptr;
  306. ptr = *inptr;
  307. /*
  308. * Find a node that matches *string or allocate a new one
  309. */
  310. if (ptr->ch != *(str->buf)) {
  311. XmapNode *xm;
  312. for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
  313. if (xm->sibling->ch == *(str->buf))
  314. break;
  315. if (xm->sibling == NULL)
  316. return (0);
  317. inptr = &xm->sibling;
  318. ptr = xm->sibling;
  319. }
  320. str->buf++;
  321. str->len--;
  322. if (str->len == 0) {
  323. /* we're there */
  324. *inptr = ptr->sibling;
  325. ptr->sibling = NULL;
  326. PutFreeNode(ptr);
  327. return (1);
  328. }
  329. else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) {
  330. if (ptr->next != NULL)
  331. return (0);
  332. *inptr = ptr->sibling;
  333. ptr->sibling = NULL;
  334. PutFreeNode(ptr);
  335. return (1);
  336. }
  337. else {
  338. return (0);
  339. }
  340. }
  341. /* PutFreeNode():
  342. * Puts a tree of nodes onto free list using free(3).
  343. */
  344. static void
  345. PutFreeNode(XmapNode *ptr)
  346. {
  347. if (ptr == NULL)
  348. return;
  349. if (ptr->next != NULL) {
  350. PutFreeNode(ptr->next);
  351. ptr->next = NULL;
  352. }
  353. PutFreeNode(ptr->sibling);
  354. switch (ptr->type) {
  355. case XK_CMD:
  356. case XK_NOD:
  357. break;
  358. case XK_EXE:
  359. case XK_STR:
  360. xfree(ptr->val.str.buf);
  361. break;
  362. default:
  363. abort();
  364. break;
  365. }
  366. xfree(ptr);
  367. }
  368. /* GetFreeNode():
  369. * Returns pointer to an XmapNode for ch.
  370. */
  371. static XmapNode *
  372. GetFreeNode(CStr *ch)
  373. {
  374. XmapNode *ptr;
  375. ptr = xmalloc(sizeof(XmapNode));
  376. ptr->ch = ch->buf[0];
  377. ptr->type = XK_NOD;
  378. ptr->val.str.buf = NULL;
  379. ptr->val.str.len = 0;
  380. ptr->next = NULL;
  381. ptr->sibling = NULL;
  382. return (ptr);
  383. }
  384. /* PrintXKey():
  385. * Print the binding associated with Xkey key.
  386. * Print entire Xmap if null
  387. */
  388. void
  389. PrintXkey(const CStr *key)
  390. {
  391. struct Strbuf buf = Strbuf_INIT;
  392. CStr cs;
  393. if (key) {
  394. cs.buf = key->buf;
  395. cs.len = key->len;
  396. }
  397. else {
  398. cs.buf = STRNULL;
  399. cs.len = 0;
  400. }
  401. /* do nothing if Xmap is empty and null key specified */
  402. if (Xmap == NULL && cs.len == 0)
  403. return;
  404. Strbuf_append1(&buf, '"');
  405. cleanup_push(&buf, Strbuf_cleanup);
  406. if (Lookup(&buf, &cs, Xmap) <= -1)
  407. /* key is not bound */
  408. xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf);
  409. cleanup_until(&buf);
  410. }
  411. /* Lookup():
  412. * look for the string starting at node ptr.
  413. * Print if last node
  414. */
  415. static int
  416. Lookup(struct Strbuf *buf, const CStr *str, const XmapNode *ptr)
  417. {
  418. if (ptr == NULL)
  419. return (-1); /* cannot have null ptr */
  420. if (str->len == 0) {
  421. /* no more chars in string. Enumerate from here. */
  422. Enumerate(buf, ptr);
  423. return (0);
  424. }
  425. else {
  426. /* If match put this char into buf. Recurse */
  427. if (ptr->ch == *(str->buf)) {
  428. /* match found */
  429. unparsech(buf, ptr->ch);
  430. if (ptr->next != NULL) {
  431. /* not yet at leaf */
  432. CStr tstr;
  433. tstr.buf = str->buf + 1;
  434. tstr.len = str->len - 1;
  435. return (Lookup(buf, &tstr, ptr->next));
  436. }
  437. else {
  438. /* next node is null so key should be complete */
  439. if (str->len == 1) {
  440. Strbuf_append1(buf, '"');
  441. Strbuf_terminate(buf);
  442. printOne(buf->s, &ptr->val, ptr->type);
  443. return (0);
  444. }
  445. else
  446. return (-1);/* mismatch -- string still has chars */
  447. }
  448. }
  449. else {
  450. /* no match found try sibling */
  451. if (ptr->sibling)
  452. return (Lookup(buf, str, ptr->sibling));
  453. else
  454. return (-1);
  455. }
  456. }
  457. }
  458. static void
  459. Enumerate(struct Strbuf *buf, const XmapNode *ptr)
  460. {
  461. size_t old_len;
  462. if (ptr == NULL) {
  463. #ifdef DEBUG_EDIT
  464. xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!"));
  465. #endif
  466. return;
  467. }
  468. old_len = buf->len;
  469. unparsech(buf, ptr->ch); /* put this char at end of string */
  470. if (ptr->next == NULL) {
  471. /* print this Xkey and function */
  472. Strbuf_append1(buf, '"');
  473. Strbuf_terminate(buf);
  474. printOne(buf->s, &ptr->val, ptr->type);
  475. }
  476. else
  477. Enumerate(buf, ptr->next);
  478. /* go to sibling if there is one */
  479. if (ptr->sibling) {
  480. buf->len = old_len;
  481. Enumerate(buf, ptr->sibling);
  482. }
  483. }
  484. /* PrintOne():
  485. * Print the specified key and its associated
  486. * function specified by val
  487. */
  488. void
  489. printOne(const Char *key, const XmapVal *val, int ntype)
  490. {
  491. struct KeyFuncs *fp;
  492. static const char *fmt = "%s\n";
  493. xprintf("%-15S-> ", key);
  494. if (val != NULL)
  495. switch (ntype) {
  496. case XK_STR:
  497. case XK_EXE: {
  498. unsigned char *p;
  499. p = unparsestring(&val->str, ntype == XK_STR ? STRQQ : STRBB);
  500. cleanup_push(p, xfree);
  501. xprintf(fmt, p);
  502. cleanup_until(p);
  503. break;
  504. }
  505. case XK_CMD:
  506. for (fp = FuncNames; fp->name; fp++)
  507. if (val->cmd == fp->func)
  508. xprintf(fmt, fp->name);
  509. break;
  510. default:
  511. abort();
  512. break;
  513. }
  514. else
  515. xprintf(fmt, CGETS(9, 7, "no input"));
  516. }
  517. static void
  518. unparsech(struct Strbuf *buf, Char ch)
  519. {
  520. if (ch == 0) {
  521. Strbuf_append1(buf, '^');
  522. Strbuf_append1(buf, '@');
  523. }
  524. else if (Iscntrl(ch)) {
  525. Strbuf_append1(buf, '^');
  526. if (ch == CTL_ESC('\177'))
  527. Strbuf_append1(buf, '?');
  528. else
  529. #ifdef IS_ASCII
  530. Strbuf_append1(buf, ch | 0100);
  531. #else
  532. Strbuf_append1(buf, _toebcdic[_toascii[ch]|0100]);
  533. #endif
  534. }
  535. else if (ch == '^') {
  536. Strbuf_append1(buf, '\\');
  537. Strbuf_append1(buf, '^');
  538. } else if (ch == '\\') {
  539. Strbuf_append1(buf, '\\');
  540. Strbuf_append1(buf, '\\');
  541. } else if (ch == ' ' || (Isprint(ch) && !Isspace(ch))) {
  542. Strbuf_append1(buf, ch);
  543. }
  544. else {
  545. Strbuf_append1(buf, '\\');
  546. Strbuf_append1(buf, ((ch >> 6) & 7) + '0');
  547. Strbuf_append1(buf, ((ch >> 3) & 7) + '0');
  548. Strbuf_append1(buf, (ch & 7) + '0');
  549. }
  550. }
  551. eChar
  552. parseescape(const Char **ptr)
  553. {
  554. const Char *p;
  555. Char c;
  556. p = *ptr;
  557. if ((p[1] & CHAR) == 0) {
  558. xprintf(CGETS(9, 8, "Something must follow: %c\n"), (char)*p);
  559. return CHAR_ERR;
  560. }
  561. if ((*p & CHAR) == '\\') {
  562. p++;
  563. switch (*p & CHAR) {
  564. case 'a':
  565. c = CTL_ESC('\007'); /* Bell */
  566. break;
  567. case 'b':
  568. c = CTL_ESC('\010'); /* Backspace */
  569. break;
  570. case 'e':
  571. c = CTL_ESC('\033'); /* Escape */
  572. break;
  573. case 'f':
  574. c = CTL_ESC('\014'); /* Form Feed */
  575. break;
  576. case 'n':
  577. c = CTL_ESC('\012'); /* New Line */
  578. break;
  579. case 'r':
  580. c = CTL_ESC('\015'); /* Carriage Return */
  581. break;
  582. case 't':
  583. c = CTL_ESC('\011'); /* Horizontal Tab */
  584. break;
  585. case 'v':
  586. c = CTL_ESC('\013'); /* Vertical Tab */
  587. break;
  588. case '\\':
  589. c = '\\';
  590. break;
  591. case '0':
  592. case '1':
  593. case '2':
  594. case '3':
  595. case '4':
  596. case '5':
  597. case '6':
  598. case '7':
  599. {
  600. int cnt, val;
  601. Char ch;
  602. for (cnt = 0, val = 0; cnt < 3; cnt++) {
  603. ch = *p++ & CHAR;
  604. if (ch < '0' || ch > '7') {
  605. p--;
  606. break;
  607. }
  608. val = (val << 3) | (ch - '0');
  609. }
  610. if ((val & ~0xff) != 0) {
  611. xprintf("%s", CGETS(9, 9,
  612. "Octal constant does not fit in a char.\n"));
  613. return 0;
  614. }
  615. #ifndef IS_ASCII
  616. if (CTL_ESC(val) != val && adrof(STRwarnebcdic))
  617. xprintf(/*CGETS(9, 9, no NLS-String yet!*/
  618. "Warning: Octal constant \\%3.3o is interpreted as EBCDIC value.\n", val/*)*/);
  619. #endif
  620. c = (Char) val;
  621. --p;
  622. }
  623. break;
  624. default:
  625. c = *p;
  626. break;
  627. }
  628. }
  629. else if ((*p & CHAR) == '^' && (Isalpha(p[1] & CHAR) ||
  630. strchr("@^_?\\|[{]}", p[1] & CHAR))) {
  631. p++;
  632. #ifdef IS_ASCII
  633. c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237);
  634. #else
  635. c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*p & CHAR] & 0237];
  636. if (adrof(STRwarnebcdic))
  637. xprintf(/*CGETS(9, 9, no NLS-String yet!*/
  638. "Warning: Control character ^%c may be interpreted differently in EBCDIC.\n", *p & CHAR /*)*/);
  639. #endif
  640. }
  641. else
  642. c = *p;
  643. *ptr = p;
  644. return (c);
  645. }
  646. unsigned char *
  647. unparsestring(const CStr *str, const Char *sep)
  648. {
  649. unsigned char *buf, *b;
  650. Char p;
  651. int l;
  652. /* Worst-case is "\uuu" or result of wctomb() for each char from str */
  653. buf = xmalloc((str->len + 1) * max(4, MB_LEN_MAX));
  654. b = buf;
  655. if (sep[0])
  656. #ifndef WINNT_NATIVE
  657. *b++ = sep[0];
  658. #else /* WINNT_NATIVE */
  659. *b++ = CHAR & sep[0];
  660. #endif /* !WINNT_NATIVE */
  661. for (l = 0; l < str->len; l++) {
  662. p = str->buf[l];
  663. if (Iscntrl(p)) {
  664. *b++ = '^';
  665. if (p == CTL_ESC('\177'))
  666. *b++ = '?';
  667. else
  668. #ifdef IS_ASCII
  669. *b++ = (unsigned char) (p | 0100);
  670. #else
  671. *b++ = _toebcdic[_toascii[p]|0100];
  672. #endif
  673. }
  674. else if (p == '^' || p == '\\') {
  675. *b++ = '\\';
  676. *b++ = (unsigned char) p;
  677. }
  678. else if (p == ' ' || (Isprint(p) && !Isspace(p)))
  679. b += one_wctomb((char *)b, p & CHAR);
  680. else {
  681. *b++ = '\\';
  682. *b++ = ((p >> 6) & 7) + '0';
  683. *b++ = ((p >> 3) & 7) + '0';
  684. *b++ = (p & 7) + '0';
  685. }
  686. }
  687. if (sep[0] && sep[1])
  688. #ifndef WINNT_NATIVE
  689. *b++ = sep[1];
  690. #else /* WINNT_NATIVE */
  691. *b++ = CHAR & sep[1];
  692. #endif /* !WINNT_NATIVE */
  693. *b++ = 0;
  694. return buf; /* should check for overflow */
  695. }