1 /* $Header: /src/pub/tcsh/ed.xmap.c,v 3.23 2000/11/11 23:03:35 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. 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 3.23 2000/11/11 23:03:35 christos 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 #ifdef IS_ASCII 636 printbuf[cnt++] = '^'; 637 if (*ch == CTL_ESC('\177')) 638 printbuf[cnt] = '?'; 639 else 640 printbuf[cnt] = *ch | 0100; 641 #else 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 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 'e': 705 c = CTL_ESC('\033'); /* Escape */ 706 break; 707 case 'f': 708 c = CTL_ESC('\014'); /* Form Feed */ 709 break; 710 case 'n': 711 c = CTL_ESC('\012'); /* New Line */ 712 break; 713 case 'r': 714 c = CTL_ESC('\015'); /* Carriage Return */ 715 break; 716 case 't': 717 c = CTL_ESC('\011'); /* Horizontal Tab */ 718 break; 719 case 'v': 720 c = CTL_ESC('\013'); /* Vertical Tab */ 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 #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++ = (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_NATIVE 838 *b++ = sep[1]; 839 #else /* WINNT_NATIVE */ 840 *b++ = CHAR & sep[1]; 841 #endif /* !WINNT_NATIVE */ 842 *b++ = 0; 843 return buf; /* should check for overflow */ 844 } 845