1 /* $Header: /src/pub/tcsh/ed.xmap.c,v 3.28 2005/01/05 18:06:43 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 91 RCSID("$Id: ed.xmap.c,v 3.28 2005/01/05 18:06:43 christos Exp $") 92 93 #include "ed.h" 94 #include "ed.defns.h" 95 96 #ifndef NULL 97 #define NULL 0 98 #endif 99 100 /* Internal Data types and declarations */ 101 102 /* The Nodes of the Xmap. The Xmap is a linked list of these node 103 * elements 104 */ 105 typedef struct Xmapnode { 106 Char ch; /* single character of Xkey */ 107 int type; 108 XmapVal val; /* command code or pointer to string, if this 109 * is a leaf */ 110 struct Xmapnode *next; /* ptr to next char of this Xkey */ 111 struct Xmapnode *sibling; /* ptr to another Xkey with same prefix */ 112 } XmapNode; 113 114 static XmapNode *Xmap = NULL; /* the current Xmap */ 115 #define MAXXKEY 100 /* max length of a Xkey for print putposes */ 116 static Char printbuf[MAXXKEY]; /* buffer for printing */ 117 118 119 /* Some declarations of procedures */ 120 static int TraverseMap __P((XmapNode *, CStr *, XmapVal *)); 121 static int TryNode __P((XmapNode *, CStr *, XmapVal *, int)); 122 static XmapNode *GetFreeNode __P((CStr *)); 123 static void PutFreeNode __P((XmapNode *)); 124 static int TryDeleteNode __P((XmapNode **, CStr *)); 125 static int Lookup __P((CStr *, XmapNode *, int)); 126 static int Enumerate __P((XmapNode *, int)); 127 static int unparsech __P((int, Char *)); 128 129 130 XmapVal * 131 XmapCmd(cmd) 132 int cmd; 133 { 134 static XmapVal xm; 135 xm.cmd = (KEYCMD) cmd; 136 return &xm; 137 } 138 139 XmapVal * 140 XmapStr(str) 141 CStr *str; 142 { 143 static XmapVal xm; 144 xm.str.len = str->len; 145 xm.str.buf = str->buf; 146 return &xm; 147 } 148 149 /* ResetXmap(): 150 * Takes all nodes on Xmap and puts them on free list. Then 151 * initializes Xmap with arrow keys 152 */ 153 void 154 ResetXmap() 155 { 156 PutFreeNode(Xmap); 157 Xmap = NULL; 158 159 DefaultArrowKeys(); 160 return; 161 } 162 163 164 /* GetXkey(): 165 * Calls the recursive function with entry point Xmap 166 */ 167 int 168 GetXkey(ch, val) 169 CStr *ch; 170 XmapVal *val; 171 { 172 return (TraverseMap(Xmap, ch, val)); 173 } 174 175 /* TraverseMap(): 176 * recursively traverses node in tree until match or mismatch is 177 * found. May read in more characters. 178 */ 179 static int 180 TraverseMap(ptr, ch, val) 181 XmapNode *ptr; 182 CStr *ch; 183 XmapVal *val; 184 { 185 Char tch; 186 187 if (ptr->ch == *(ch->buf)) { 188 /* match found */ 189 if (ptr->next) { 190 /* Xkey not complete so get next char */ 191 if (GetNextChar(&tch) != 1) { /* if EOF or error */ 192 val->cmd = F_SEND_EOF; 193 return XK_CMD;/* PWP: Pretend we just read an end-of-file */ 194 } 195 *(ch->buf) = tch; 196 return (TraverseMap(ptr->next, ch, val)); 197 } 198 else { 199 *val = ptr->val; 200 if (ptr->type != XK_CMD) 201 *(ch->buf) = '\0'; 202 return ptr->type; 203 } 204 } 205 else { 206 /* no match found here */ 207 if (ptr->sibling) { 208 /* try next sibling */ 209 return (TraverseMap(ptr->sibling, ch, val)); 210 } 211 else { 212 /* no next sibling -- mismatch */ 213 val->str.buf = NULL; 214 val->str.len = 0; 215 return XK_STR; 216 } 217 } 218 } 219 220 void 221 AddXkey(Xkey, val, ntype) 222 CStr *Xkey; 223 XmapVal *val; 224 int ntype; 225 { 226 CStr cs; 227 cs.buf = Xkey->buf; 228 cs.len = Xkey->len; 229 if (Xkey->len == 0) { 230 xprintf(CGETS(9, 1, "AddXkey: Null extended-key not allowed.\n")); 231 return; 232 } 233 234 if (ntype == XK_CMD && val->cmd == F_XKEY) { 235 xprintf(CGETS(9, 2, "AddXkey: sequence-lead-in command not allowed\n")); 236 return; 237 } 238 239 if (Xmap == NULL) 240 /* tree is initially empty. Set up new node to match Xkey[0] */ 241 Xmap = GetFreeNode(&cs); /* it is properly initialized */ 242 243 /* Now recurse through Xmap */ 244 (void) TryNode(Xmap, &cs, val, ntype); 245 return; 246 } 247 248 static int 249 TryNode(ptr, str, val, ntype) 250 XmapNode *ptr; 251 CStr *str; 252 XmapVal *val; 253 int ntype; 254 { 255 /* 256 * Find a node that matches *string or allocate a new one 257 */ 258 if (ptr->ch != *(str->buf)) { 259 XmapNode *xm; 260 261 for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 262 if (xm->sibling->ch == *(str->buf)) 263 break; 264 if (xm->sibling == NULL) 265 xm->sibling = GetFreeNode(str); /* setup new node */ 266 ptr = xm->sibling; 267 } 268 269 str->buf++; 270 str->len--; 271 if (str->len == 0) { 272 /* we're there */ 273 if (ptr->next != NULL) { 274 PutFreeNode(ptr->next); /* lose longer Xkeys with this prefix */ 275 ptr->next = NULL; 276 } 277 278 switch (ptr->type) { 279 case XK_STR: 280 case XK_EXE: 281 if (ptr->val.str.buf != NULL) 282 xfree((ptr_t) ptr->val.str.buf); 283 ptr->val.str.len = 0; 284 break; 285 case XK_NOD: 286 case XK_CMD: 287 break; 288 default: 289 abort(); 290 break; 291 } 292 293 switch (ptr->type = ntype) { 294 case XK_CMD: 295 ptr->val = *val; 296 break; 297 case XK_STR: 298 case XK_EXE: 299 ptr->val.str.len = (val->str.len + 1) * sizeof(Char); 300 ptr->val.str.buf = (Char *) xmalloc((size_t) ptr->val.str.len); 301 (void) memmove((ptr_t) ptr->val.str.buf, (ptr_t) val->str.buf, 302 (size_t) ptr->val.str.len); 303 ptr->val.str.len = val->str.len; 304 break; 305 default: 306 abort(); 307 break; 308 } 309 } 310 else { 311 /* still more chars to go */ 312 if (ptr->next == NULL) 313 ptr->next = GetFreeNode(str); /* setup new node */ 314 (void) TryNode(ptr->next, str, val, ntype); 315 } 316 return (0); 317 } 318 319 void 320 ClearXkey(map, in) 321 KEYCMD *map; 322 CStr *in; 323 { 324 unsigned char c = (unsigned char) *(in->buf); 325 if ((map[c] == F_XKEY) && 326 ((map == CcKeyMap && CcAltMap[c] != F_XKEY) || 327 (map == CcAltMap && CcKeyMap[c] != F_XKEY))) 328 (void) DeleteXkey(in); 329 } 330 331 int 332 DeleteXkey(Xkey) 333 CStr *Xkey; 334 { 335 if (Xkey->len == 0) { 336 xprintf(CGETS(9, 3, "DeleteXkey: Null extended-key not allowed.\n")); 337 return (-1); 338 } 339 340 if (Xmap == NULL) 341 return (0); 342 343 (void) TryDeleteNode(&Xmap, Xkey); 344 return (0); 345 } 346 347 static int 348 TryDeleteNode(inptr, str) 349 XmapNode **inptr; 350 CStr *str; 351 { 352 XmapNode *ptr; 353 XmapNode *prev_ptr = NULL; 354 355 ptr = *inptr; 356 /* 357 * Find a node that matches *string or allocate a new one 358 */ 359 if (ptr->ch != *(str->buf)) { 360 XmapNode *xm; 361 362 for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 363 if (xm->sibling->ch == *(str->buf)) 364 break; 365 if (xm->sibling == NULL) 366 return (0); 367 prev_ptr = xm; 368 ptr = xm->sibling; 369 } 370 371 str->buf++; 372 str->len--; 373 374 if (str->len == 0) { 375 /* we're there */ 376 if (prev_ptr == NULL) 377 *inptr = ptr->sibling; 378 else 379 prev_ptr->sibling = ptr->sibling; 380 ptr->sibling = NULL; 381 PutFreeNode(ptr); 382 return (1); 383 } 384 else if (ptr->next != NULL && TryDeleteNode(&ptr->next, str) == 1) { 385 if (ptr->next != NULL) 386 return (0); 387 if (prev_ptr == NULL) 388 *inptr = ptr->sibling; 389 else 390 prev_ptr->sibling = ptr->sibling; 391 ptr->sibling = NULL; 392 PutFreeNode(ptr); 393 return (1); 394 } 395 else { 396 return (0); 397 } 398 } 399 400 /* PutFreeNode(): 401 * Puts a tree of nodes onto free list using free(3). 402 */ 403 static void 404 PutFreeNode(ptr) 405 XmapNode *ptr; 406 { 407 if (ptr == NULL) 408 return; 409 410 if (ptr->next != NULL) { 411 PutFreeNode(ptr->next); 412 ptr->next = NULL; 413 } 414 415 PutFreeNode(ptr->sibling); 416 417 switch (ptr->type) { 418 case XK_CMD: 419 case XK_NOD: 420 break; 421 case XK_EXE: 422 case XK_STR: 423 if (ptr->val.str.buf != NULL) 424 xfree((ptr_t) ptr->val.str.buf); 425 break; 426 default: 427 abort(); 428 break; 429 } 430 xfree((ptr_t) ptr); 431 } 432 433 434 /* GetFreeNode(): 435 * Returns pointer to an XmapNode for ch. 436 */ 437 static XmapNode * 438 GetFreeNode(ch) 439 CStr *ch; 440 { 441 XmapNode *ptr; 442 443 ptr = (XmapNode *) xmalloc((size_t) sizeof(XmapNode)); 444 ptr->ch = ch->buf[0]; 445 ptr->type = XK_NOD; 446 ptr->val.str.buf = NULL; 447 ptr->val.str.len = 0; 448 ptr->next = NULL; 449 ptr->sibling = NULL; 450 return (ptr); 451 } 452 453 454 /* PrintXKey(): 455 * Print the binding associated with Xkey key. 456 * Print entire Xmap if null 457 */ 458 void 459 PrintXkey(key) 460 CStr *key; 461 { 462 CStr cs; 463 464 if (key) { 465 cs.buf = key->buf; 466 cs.len = key->len; 467 } 468 else { 469 cs.buf = STRNULL; 470 cs.len = 0; 471 } 472 /* do nothing if Xmap is empty and null key specified */ 473 if (Xmap == NULL && cs.len == 0) 474 return; 475 476 printbuf[0] = '"'; 477 if (Lookup(&cs, Xmap, 1) <= -1) 478 /* key is not bound */ 479 xprintf(CGETS(9, 4, "Unbound extended key \"%S\"\n"), cs.buf); 480 return; 481 } 482 483 /* Lookup(): 484 * look for the string starting at node ptr. 485 * Print if last node 486 */ 487 static int 488 Lookup(str, ptr, cnt) 489 CStr *str; 490 XmapNode *ptr; 491 int cnt; 492 { 493 int ncnt; 494 495 if (ptr == NULL) 496 return (-1); /* cannot have null ptr */ 497 498 if (str->len == 0) { 499 /* no more chars in string. Enumerate from here. */ 500 (void) Enumerate(ptr, cnt); 501 return (0); 502 } 503 else { 504 /* If match put this char into printbuf. Recurse */ 505 if (ptr->ch == *(str->buf)) { 506 /* match found */ 507 ncnt = unparsech(cnt, &ptr->ch); 508 if (ptr->next != NULL) { 509 /* not yet at leaf */ 510 CStr tstr; 511 tstr.buf = str->buf + 1; 512 tstr.len = str->len - 1; 513 return (Lookup(&tstr, ptr->next, ncnt + 1)); 514 } 515 else { 516 /* next node is null so key should be complete */ 517 if (str->len == 1) { 518 CStr pb; 519 printbuf[ncnt + 1] = '"'; 520 printbuf[ncnt + 2] = '\0'; 521 pb.buf = printbuf; 522 pb.len = ncnt + 2; 523 (void) printOne(&pb, &ptr->val, ptr->type); 524 return (0); 525 } 526 else 527 return (-1);/* mismatch -- string still has chars */ 528 } 529 } 530 else { 531 /* no match found try sibling */ 532 if (ptr->sibling) 533 return (Lookup(str, ptr->sibling, cnt)); 534 else 535 return (-1); 536 } 537 } 538 } 539 540 static int 541 Enumerate(ptr, cnt) 542 XmapNode *ptr; 543 int cnt; 544 { 545 int ncnt; 546 547 if (cnt >= MAXXKEY - 5) { /* buffer too small */ 548 printbuf[++cnt] = '"'; 549 printbuf[++cnt] = '\0'; 550 xprintf(CGETS(9, 5, 551 "Some extended keys too long for internal print buffer")); 552 xprintf(" \"%S...\"\n", printbuf); 553 return (0); 554 } 555 556 if (ptr == NULL) { 557 #ifdef DEBUG_EDIT 558 xprintf(CGETS(9, 6, "Enumerate: BUG!! Null ptr passed\n!")); 559 #endif 560 return (-1); 561 } 562 563 ncnt = unparsech(cnt, &ptr->ch); /* put this char at end of string */ 564 if (ptr->next == NULL) { 565 CStr pb; 566 /* print this Xkey and function */ 567 printbuf[++ncnt] = '"'; 568 printbuf[++ncnt] = '\0'; 569 pb.buf = printbuf; 570 pb.len = ncnt; 571 (void) printOne(&pb, &ptr->val, ptr->type); 572 } 573 else 574 (void) Enumerate(ptr->next, ncnt + 1); 575 576 /* go to sibling if there is one */ 577 if (ptr->sibling) 578 (void) Enumerate(ptr->sibling, cnt); 579 return (0); 580 } 581 582 583 /* PrintOne(): 584 * Print the specified key and its associated 585 * function specified by val 586 */ 587 int 588 printOne(key, val, ntype) 589 CStr *key; 590 XmapVal *val; 591 int ntype; 592 { 593 struct KeyFuncs *fp; 594 unsigned char unparsbuf[200]; 595 static const char *fmt = "%s\n"; 596 597 xprintf("%-15S-> ", key->buf); 598 if (val != NULL) 599 switch (ntype) { 600 case XK_STR: 601 case XK_EXE: 602 xprintf(fmt, unparsestring(&val->str, unparsbuf, 603 ntype == XK_STR ? STRQQ : STRBB)); 604 break; 605 case XK_CMD: 606 for (fp = FuncNames; fp->name; fp++) 607 if (val->cmd == fp->func) 608 xprintf(fmt, fp->name); 609 break; 610 default: 611 abort(); 612 break; 613 } 614 else 615 xprintf(fmt, key, CGETS(9, 7, "no input")); 616 return (0); 617 } 618 619 static int 620 unparsech(cnt, ch) 621 int cnt; 622 Char *ch; 623 { 624 if (ch == 0) { 625 printbuf[cnt++] = '^'; 626 printbuf[cnt] = '@'; 627 return cnt; 628 } 629 630 if (Iscntrl(*ch)) { 631 #ifdef IS_ASCII 632 printbuf[cnt++] = '^'; 633 if (*ch == CTL_ESC('\177')) 634 printbuf[cnt] = '?'; 635 else 636 printbuf[cnt] = *ch | 0100; 637 #else 638 if (*ch == CTL_ESC('\177')) 639 { 640 printbuf[cnt++] = '^'; 641 printbuf[cnt] = '?'; 642 } 643 else if (Isupper(_toebcdic[_toascii[*ch]|0100]) 644 || strchr("@[\\]^_", _toebcdic[_toascii[*ch]|0100]) != NULL) 645 { 646 printbuf[cnt++] = '^'; 647 printbuf[cnt] = _toebcdic[_toascii[*ch]|0100]; 648 } 649 else 650 { 651 printbuf[cnt++] = '\\'; 652 printbuf[cnt++] = ((*ch >> 6) & 7) + '0'; 653 printbuf[cnt++] = ((*ch >> 3) & 7) + '0'; 654 printbuf[cnt] = (*ch & 7) + '0'; 655 } 656 #endif 657 } 658 else if (*ch == '^') { 659 printbuf[cnt++] = '\\'; 660 printbuf[cnt] = '^'; 661 } 662 else if (*ch == '\\') { 663 printbuf[cnt++] = '\\'; 664 printbuf[cnt] = '\\'; 665 } 666 else if (*ch == ' ' || (Isprint(*ch) && !Isspace(*ch))) { 667 printbuf[cnt] = *ch; 668 } 669 else { 670 printbuf[cnt++] = '\\'; 671 printbuf[cnt++] = ((*ch >> 6) & 7) + '0'; 672 printbuf[cnt++] = ((*ch >> 3) & 7) + '0'; 673 printbuf[cnt] = (*ch & 7) + '0'; 674 } 675 return cnt; 676 } 677 678 eChar 679 parseescape(ptr) 680 const Char **ptr; 681 { 682 const Char *p; 683 Char c; 684 685 p = *ptr; 686 687 if ((p[1] & CHAR) == 0) { 688 xprintf(CGETS(9, 8, "Something must follow: %c\n"), *p); 689 return CHAR_ERR; 690 } 691 if ((*p & CHAR) == '\\') { 692 p++; 693 switch (*p & CHAR) { 694 case 'a': 695 c = CTL_ESC('\007'); /* Bell */ 696 break; 697 case 'b': 698 c = CTL_ESC('\010'); /* Backspace */ 699 break; 700 case 'e': 701 c = CTL_ESC('\033'); /* Escape */ 702 break; 703 case 'f': 704 c = CTL_ESC('\014'); /* Form Feed */ 705 break; 706 case 'n': 707 c = CTL_ESC('\012'); /* New Line */ 708 break; 709 case 'r': 710 c = CTL_ESC('\015'); /* Carriage Return */ 711 break; 712 case 't': 713 c = CTL_ESC('\011'); /* Horizontal Tab */ 714 break; 715 case 'v': 716 c = CTL_ESC('\013'); /* Vertical Tab */ 717 break; 718 case '\\': 719 c = '\\'; 720 break; 721 case '0': 722 case '1': 723 case '2': 724 case '3': 725 case '4': 726 case '5': 727 case '6': 728 case '7': 729 { 730 int cnt, val; 731 Char 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 #ifndef IS_ASCII 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 #ifdef IS_ASCII 764 c = ((*p & CHAR) == '?') ? CTL_ESC('\177') : ((*p & CHAR) & 0237); 765 #else 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 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_NATIVE 792 *b++ = sep[0]; 793 #else /* WINNT_NATIVE */ 794 *b++ = CHAR & sep[0]; 795 #endif /* !WINNT_NATIVE */ 796 797 for (l = 0; l < str->len; l++) { 798 p = str->buf[l]; 799 if (Iscntrl(p)) { 800 #ifdef IS_ASCII 801 *b++ = '^'; 802 if (p == CTL_ESC('\177')) 803 *b++ = '?'; 804 else 805 *b++ = (unsigned char) (p | 0100); 806 #else 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 821 } 822 else if (p == '^' || p == '\\') { 823 *b++ = '\\'; 824 *b++ = (unsigned char) p; 825 } 826 else if (p == ' ' || (Isprint(p) && !Isspace(p))) 827 b += one_wctomb((char *)b, p & CHAR); 828 else { 829 *b++ = '\\'; 830 *b++ = ((p >> 6) & 7) + '0'; 831 *b++ = ((p >> 3) & 7) + '0'; 832 *b++ = (p & 7) + '0'; 833 } 834 } 835 if (sep[0] && sep[1]) 836 #ifndef WINNT_NATIVE 837 *b++ = sep[1]; 838 #else /* WINNT_NATIVE */ 839 *b++ = CHAR & sep[1]; 840 #endif /* !WINNT_NATIVE */ 841 *b++ = 0; 842 return buf; /* should check for overflow */ 843 } 844