1 /* $OpenBSD: extend.c,v 1.18 2001/07/05 17:36:05 matthieu Exp $ */ 2 3 /* 4 * Extended (M-X) commands, rebinding, and startup file processing. 5 */ 6 7 #include "def.h" 8 #include "kbd.h" 9 #include "funmap.h" 10 11 #ifndef NO_MACRO 12 #include "macro.h" 13 #endif /* !NO_MACRO */ 14 15 #ifdef FKEYS 16 #include "key.h" 17 #ifndef NO_STARTUP 18 #ifndef BINDKEY 19 #define BINDKEY /* bindkey is used by FKEYS startup code */ 20 #endif /* !BINDKEY */ 21 #endif /* !NO_STARTUP */ 22 #endif /* FKEYS */ 23 24 static int remap __P((KEYMAP *, int, PF, KEYMAP *)); 25 static KEYMAP *realocmap __P((KEYMAP *)); 26 static void fixmap __P((KEYMAP *, KEYMAP *, KEYMAP *)); 27 static int dobind __P((KEYMAP *, char *, int)); 28 static char *skipwhite __P((char *)); 29 static char *parsetoken __P((char *)); 30 static int bindkey __P((KEYMAP **, char *, KCHAR *, int)); 31 32 /* 33 * Insert a string, mainly for use from macros (created by selfinsert) 34 */ 35 /* ARGSUSED */ 36 int 37 insert(f, n) 38 int f, n; 39 { 40 char *cp; 41 char buf[128]; 42 #ifndef NO_MACRO 43 int count, c; 44 45 if (inmacro) { 46 while (--n >= 0) { 47 for (count = 0; count < maclcur->l_used; count++) { 48 if ((((c = maclcur->l_text[count]) == '\n') 49 ? lnewline() : linsert(1, c)) != TRUE) 50 return FALSE; 51 } 52 } 53 maclcur = maclcur->l_fp; 54 return TRUE; 55 } 56 if (n == 1) 57 /* CFINS means selfinsert can tack on the end */ 58 thisflag |= CFINS; 59 #endif /* !NO_MACRO */ 60 if (eread("Insert: ", buf, sizeof(buf), EFNEW) == FALSE) 61 return FALSE; 62 while (--n >= 0) { 63 cp = buf; 64 while (*cp) { 65 if (((*cp == '\n') ? lnewline() : linsert(1, *cp)) 66 != TRUE) 67 return FALSE; 68 cp++; 69 } 70 } 71 return TRUE; 72 } 73 74 /* 75 * Bind a key to a function. Cases range from the trivial (replacing an 76 * existing binding) to the extremly complex (creating a new prefix in a 77 * map_element that already has one, so the map_element must be split, 78 * but the keymap doesn't have enough room for another map_element, so 79 * the keymap is reallocated). No attempt is made to reclaim space no 80 * longer used, if this is a problem flags must be added to indicate 81 * malloced verses static storage in both keymaps and map_elements. 82 * Structure assignments would come in real handy, but K&R based compilers 83 * don't have them. Care is taken so running out of memory will leave 84 * the keymap in a usable state. 85 */ 86 static int 87 remap(curmap, c, funct, pref_map) 88 KEYMAP *curmap; /* pointer to the map being changed */ 89 int c; /* character being changed */ 90 PF funct; /* function being changed to */ 91 KEYMAP *pref_map; /* if funct==NULL, map to bind to or 92 NULL for new */ 93 { 94 int i, n1, n2, nold; 95 KEYMAP *mp; 96 PF *pfp; 97 MAP_ELEMENT *mep; 98 99 if (ele >= &curmap->map_element[curmap->map_num] || c < ele->k_base) { 100 if (ele > &curmap->map_element[0] && (funct != NULL || 101 (ele - 1)->k_prefmap == NULL)) 102 n1 = c - (ele - 1)->k_num; 103 else 104 n1 = HUGE; 105 if (ele < &curmap->map_element[curmap->map_num] && 106 (funct != NULL || ele->k_prefmap == NULL)) 107 n2 = ele->k_base - c; 108 else 109 n2 = HUGE; 110 if (n1 <= MAPELEDEF && n1 <= n2) { 111 ele--; 112 if ((pfp = (PF *)malloc((c - ele->k_base + 1) * 113 sizeof(PF))) == NULL) { 114 ewprintf("Out of memory"); 115 return FALSE; 116 } 117 nold = ele->k_num - ele->k_base + 1; 118 for (i = 0; i < nold; i++) 119 pfp[i] = ele->k_funcp[i]; 120 while (--n1) 121 pfp[i++] = curmap->map_default; 122 pfp[i] = funct; 123 ele->k_num = c; 124 ele->k_funcp = pfp; 125 } else if (n2 <= MAPELEDEF) { 126 if ((pfp = (PF *)malloc((ele->k_num - c + 1) * 127 sizeof(PF))) == NULL) { 128 ewprintf("Out of memory"); 129 return FALSE; 130 } 131 nold = ele->k_num - ele->k_base + 1; 132 for (i = 0; i < nold; i++) 133 pfp[i + n2] = ele->k_funcp[i]; 134 while (--n2) 135 pfp[n2] = curmap->map_default; 136 pfp[0] = funct; 137 ele->k_base = c; 138 ele->k_funcp = pfp; 139 } else { 140 if (curmap->map_num >= curmap->map_max && 141 (curmap = realocmap(curmap)) == NULL) 142 return FALSE; 143 if ((pfp = malloc(sizeof(PF))) == NULL) { 144 ewprintf("Out of memory"); 145 return FALSE; 146 } 147 pfp[0] = funct; 148 for (mep = &curmap->map_element[curmap->map_num]; 149 mep > ele; mep--) { 150 mep->k_base = (mep - 1)->k_base; 151 mep->k_num = (mep - 1)->k_num; 152 mep->k_funcp = (mep - 1)->k_funcp; 153 mep->k_prefmap = (mep - 1)->k_prefmap; 154 } 155 ele->k_base = c; 156 ele->k_num = c; 157 ele->k_funcp = pfp; 158 ele->k_prefmap = NULL; 159 curmap->map_num++; 160 } 161 if (funct == NULL) { 162 if (pref_map != NULL) { 163 ele->k_prefmap = pref_map; 164 } else { 165 if (!(mp = (KEYMAP *)malloc(sizeof(KEYMAP) + 166 (MAPINIT - 1) * sizeof(MAP_ELEMENT)))) { 167 ewprintf("Out of memory"); 168 ele->k_funcp[c - ele->k_base] = 169 curmap->map_default; 170 return FALSE; 171 } 172 mp->map_num = 0; 173 mp->map_max = MAPINIT; 174 mp->map_default = rescan; 175 ele->k_prefmap = mp; 176 } 177 } 178 } else { 179 n1 = c - ele->k_base; 180 if (ele->k_funcp[n1] == funct && (funct != NULL || 181 pref_map == NULL || pref_map == ele->k_prefmap)) 182 /* no change */ 183 return TRUE; 184 if (funct != NULL || ele->k_prefmap == NULL) { 185 if (ele->k_funcp[n1] == NULL) 186 ele->k_prefmap = NULL; 187 /* easy case */ 188 ele->k_funcp[n1] = funct; 189 if (funct == NULL) { 190 if (pref_map != NULL) 191 ele->k_prefmap = pref_map; 192 else { 193 if (!(mp = malloc(sizeof(KEYMAP) + 194 (MAPINIT - 1) * 195 sizeof(MAP_ELEMENT)))) { 196 ewprintf("Out of memory"); 197 ele->k_funcp[c - ele->k_base] = 198 curmap->map_default; 199 return FALSE; 200 } 201 mp->map_num = 0; 202 mp->map_max = MAPINIT; 203 mp->map_default = rescan; 204 ele->k_prefmap = mp; 205 } 206 } 207 } else { 208 /* 209 * This case is the splits. 210 * Determine which side of the break c goes on 211 * 0 = after break; 1 = before break 212 */ 213 n2 = 1; 214 for (i = 0; n2 && i < n1; i++) 215 n2 &= ele->k_funcp[i] != NULL; 216 if (curmap->map_num >= curmap->map_max && 217 (curmap = realocmap(curmap)) == NULL) 218 return FALSE; 219 if ((pfp = malloc((ele->k_num - c + !n2) * 220 sizeof(PF))) == NULL) { 221 ewprintf("Out of memory"); 222 return FALSE; 223 } 224 ele->k_funcp[n1] = NULL; 225 for (i = n1 + n2; i <= ele->k_num - ele->k_base; i++) 226 pfp[i - n1 - n2] = ele->k_funcp[i]; 227 for (mep = &curmap->map_element[curmap->map_num]; 228 mep > ele; mep--) { 229 mep->k_base = (mep - 1)->k_base; 230 mep->k_num = (mep - 1)->k_num; 231 mep->k_funcp = (mep - 1)->k_funcp; 232 mep->k_prefmap = (mep - 1)->k_prefmap; 233 } 234 ele->k_num = c - !n2; 235 (ele + 1)->k_base = c + n2; 236 (ele + 1)->k_funcp = pfp; 237 ele += !n2; 238 ele->k_prefmap = NULL; 239 curmap->map_num++; 240 if (pref_map == NULL) { 241 if ((mp = malloc(sizeof(KEYMAP) + (MAPINIT - 1) 242 * sizeof(MAP_ELEMENT))) == NULL) { 243 ewprintf("Out of memory"); 244 ele->k_funcp[c - ele->k_base] = 245 curmap->map_default; 246 return FALSE; 247 } 248 mp->map_num = 0; 249 mp->map_max = MAPINIT; 250 mp->map_default = rescan; 251 ele->k_prefmap = mp; 252 } else 253 ele->k_prefmap = pref_map; 254 } 255 } 256 return TRUE; 257 } 258 259 /* 260 * Reallocate a keymap, used above. 261 */ 262 static KEYMAP * 263 realocmap(curmap) 264 KEYMAP *curmap; 265 { 266 MAPS *mps; 267 KEYMAP *mp; 268 int i; 269 270 if ((mp = (KEYMAP *)malloc((unsigned)(sizeof(KEYMAP) + 271 (curmap->map_max + (MAPGROW - 1)) * 272 sizeof(MAP_ELEMENT)))) == NULL) { 273 ewprintf("Out of memory"); 274 return NULL; 275 } 276 mp->map_num = curmap->map_num; 277 mp->map_max = curmap->map_max + MAPGROW; 278 mp->map_default = curmap->map_default; 279 for (i = curmap->map_num; i--;) { 280 mp->map_element[i].k_base = curmap->map_element[i].k_base; 281 mp->map_element[i].k_num = curmap->map_element[i].k_num; 282 mp->map_element[i].k_funcp = curmap->map_element[i].k_funcp; 283 mp->map_element[i].k_prefmap = curmap->map_element[i].k_prefmap; 284 } 285 for (mps = maps; mps != NULL; mps = mps->p_next) { 286 if (mps->p_map == curmap) 287 mps->p_map = mp; 288 else 289 fixmap(curmap, mp, mps->p_map); 290 } 291 ele = &mp->map_element[ele - &curmap->map_element[0]]; 292 return mp; 293 } 294 295 /* 296 * Fix references to a reallocated keymap (recursive). 297 */ 298 static void 299 fixmap(curmap, mp, mt) 300 KEYMAP *mt; 301 KEYMAP *curmap; 302 KEYMAP *mp; 303 { 304 int i; 305 306 for (i = mt->map_num; i--;) { 307 if (mt->map_element[i].k_prefmap != NULL) { 308 if (mt->map_element[i].k_prefmap == curmap) 309 mt->map_element[i].k_prefmap = mp; 310 else 311 fixmap(curmap, mp, mt->map_element[i].k_prefmap); 312 } 313 } 314 } 315 316 /* 317 * do the input for local-set-key, global-set-key and define-key 318 * then call remap to do the work. 319 */ 320 static int 321 dobind(curmap, p, unbind) 322 KEYMAP *curmap; 323 char *p; 324 int unbind; 325 { 326 KEYMAP *pref_map = NULL; 327 PF funct; 328 char prompt[80]; 329 char *pep; 330 int c, s; 331 332 #ifndef NO_MACRO 333 if (macrodef) { 334 /* 335 * Keystrokes aren't collected. Not hard, but pretty useless. 336 * Would not work for function keys in any case. 337 */ 338 ewprintf("Can't rebind key in macro"); 339 return FALSE; 340 } 341 #ifndef NO_STARTUP 342 if (inmacro) { 343 for (s = 0; s < maclcur->l_used - 1; s++) { 344 if (doscan(curmap, c = CHARMASK(maclcur->l_text[s]), &curmap) 345 != NULL) { 346 if (remap(curmap, c, NULL, NULL) 347 != TRUE) 348 return FALSE; 349 } 350 } 351 (void)doscan(curmap, c = maclcur->l_text[s], NULL); 352 maclcur = maclcur->l_fp; 353 } else { 354 #endif /* !NO_STARTUP */ 355 #endif /* !NO_MACRO */ 356 pep = prompt + strlcpy(prompt, p, sizeof(prompt)); 357 for (;;) { 358 ewprintf("%s", prompt); 359 pep[-1] = ' '; 360 pep = keyname(pep, sizeof(prompt) - (pep - prompt), 361 c = getkey(FALSE)); 362 if (doscan(curmap, c, &curmap) != NULL) 363 break; 364 *pep++ = '-'; 365 *pep = '\0'; 366 } 367 #ifndef NO_STARTUP 368 } 369 #endif /* !NO_STARTUP */ 370 if (unbind) 371 funct = rescan; 372 else { 373 if ((s = eread("%s to command: ", prompt, 80, EFFUNC | EFNEW, 374 prompt)) != TRUE) 375 return s; 376 if (((funct = name_function(prompt)) == NULL) ? 377 (pref_map = name_map(prompt)) == NULL : funct == NULL) { 378 ewprintf("[No match]"); 379 return FALSE; 380 } 381 } 382 return remap(curmap, c, funct, pref_map); 383 } 384 385 /* 386 * bindkey: bind key sequence to a function in the specified map. Used by 387 * excline so it can bind function keys. To close to release to change 388 * calling sequence, should just pass KEYMAP *curmap rather than 389 * KEYMAP **mapp. 390 */ 391 #ifdef BINDKEY 392 static int 393 bindkey(mapp, fname, keys, kcount) 394 KEYMAP **mapp; 395 char *fname; 396 KCHAR *keys; 397 int kcount; 398 { 399 KEYMAP *curmap = *mapp; 400 KEYMAP *pref_map = NULL; 401 PF funct; 402 int c; 403 404 if (fname == NULL) 405 funct = rescan; 406 else if (((funct = name_function(fname)) == NULL) ? 407 (pref_map = name_map(fname)) == NULL : funct == NULL) { 408 ewprintf("[No match: %s]", fname); 409 return FALSE; 410 } 411 while (--kcount) { 412 if (doscan(curmap, c = *keys++, &curmap) != NULL) { 413 if (remap(curmap, c, NULL, NULL) != TRUE) 414 return FALSE; 415 /* 416 * XXX - Bizzarreness. remap creates an empty KEYMAP 417 * that the last key is supposed to point to. 418 */ 419 curmap = ele->k_prefmap; 420 } 421 } 422 (void)doscan(curmap, c = *keys, NULL); 423 return remap(curmap, c, funct, pref_map); 424 } 425 426 #ifdef FKEYS 427 /* 428 * Wrapper for bindkey() that converts escapes. 429 */ 430 int 431 dobindkey(map, func, str) 432 KEYMAP *map; 433 char *func; 434 char *str; 435 { 436 int i; 437 438 for (i = 0; *str && i < MAXKEY; i++) { 439 /* XXX - convert numbers w/ strol()? */ 440 if (*str != '\\') 441 key.k_chars[i] = *str; 442 else { 443 switch (*++str) { 444 case 't': 445 case 'T': 446 key.k_chars[i] = '\t'; 447 break; 448 case 'n': 449 case 'N': 450 key.k_chars[i] = '\n'; 451 break; 452 case 'r': 453 case 'R': 454 key.k_chars[i] = '\r'; 455 break; 456 case 'e': 457 case 'E': 458 key.k_chars[i] = CCHR('['); 459 break; 460 } 461 } 462 str++; 463 } 464 key.k_count = i; 465 return (bindkey(&map, func, key.k_chars, key.k_count)); 466 } 467 #endif /* FKEYS */ 468 #endif /* BINDKEY */ 469 470 /* 471 * This function modifies the fundamental keyboard map. 472 */ 473 /* ARGSUSED */ 474 int 475 bindtokey(f, n) 476 int f, n; 477 { 478 return dobind(fundamental_map, "Global set key: ", FALSE); 479 } 480 481 /* 482 * This function modifies the current mode's keyboard map. 483 */ 484 /* ARGSUSED */ 485 int 486 localbind(f, n) 487 int f, n; 488 { 489 return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, 490 "Local set key: ", FALSE); 491 } 492 493 /* 494 * This function redefines a key in any keymap. 495 */ 496 /* ARGSUSED */ 497 int 498 define_key(f, n) 499 int f, n; 500 { 501 static char buf[48] = "Define key map: "; 502 KEYMAP *mp; 503 504 buf[16] = '\0'; 505 if (eread(buf, &buf[16], 48 - 16, EFNEW) != TRUE) 506 return FALSE; 507 if ((mp = name_map(&buf[16])) == NULL) { 508 ewprintf("Unknown map %s", &buf[16]); 509 return FALSE; 510 } 511 (void)strncat(&buf[16], " key: ", 48 - 16 - 1); 512 return dobind(mp, buf, FALSE); 513 } 514 515 int 516 unbindtokey(f, n) 517 int f, n; 518 { 519 return dobind(fundamental_map, "Global unset key: ", TRUE); 520 } 521 522 int 523 localunbind(f, n) 524 int f, n; 525 { 526 return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, 527 "Local unset key: ", TRUE); 528 } 529 530 /* 531 * Extended command. Call the message line routine to read in the command 532 * name and apply autocompletion to it. When it comes back, look the name 533 * up in the symbol table and run the command if it is found. Print an 534 * error if there is anything wrong. 535 */ 536 int 537 extend(f, n) 538 int f, n; 539 { 540 PF funct; 541 int s; 542 char xname[NXNAME]; 543 544 if (!(f & FFARG)) 545 s = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC); 546 else 547 s = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n); 548 if (s != TRUE) 549 return s; 550 if ((funct = name_function(xname)) != NULL) { 551 #ifndef NO_MACRO 552 if (macrodef) { 553 LINE *lp = maclcur; 554 macro[macrocount - 1].m_funct = funct; 555 maclcur = lp->l_bp; 556 maclcur->l_fp = lp->l_fp; 557 free((char *)lp); 558 } 559 #endif /* !NO_MACRO */ 560 return (*funct)(f, n); 561 } 562 ewprintf("[No match]"); 563 return FALSE; 564 } 565 566 #ifndef NO_STARTUP 567 /* 568 * Define the commands needed to do startup-file processing. 569 * This code is mostly a kludge just so we can get startup-file processing. 570 * 571 * If you're serious about having this code, you should rewrite it. 572 * To wit: 573 * It has lots of funny things in it to make the startup-file look 574 * like a GNU startup file; mostly dealing with parens and semicolons. 575 * This should all vanish. 576 * 577 * We define eval-expression because it's easy. It can make 578 * *-set-key or define-key set an arbitrary key sequence, so it isn't 579 * useless. 580 */ 581 582 /* 583 * evalexpr - get one line from the user, and run it. 584 */ 585 /* ARGSUSED */ 586 int 587 evalexpr(f, n) 588 int f, n; 589 { 590 int s; 591 char exbuf[128]; 592 593 if ((s = ereply("Eval: ", exbuf, 128)) != TRUE) 594 return s; 595 return excline(exbuf); 596 } 597 598 /* 599 * evalbuffer - evaluate the current buffer as line commands. Useful for 600 * testing startup files. 601 */ 602 /* ARGSUSED */ 603 int 604 evalbuffer(f, n) 605 int f, n; 606 { 607 LINE *lp; 608 BUFFER *bp = curbp; 609 int s; 610 static char excbuf[128]; 611 612 for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) { 613 if (llength(lp) >= 128) 614 return FALSE; 615 (void)strncpy(excbuf, ltext(lp), llength(lp)); 616 617 /* make sure it's terminated */ 618 excbuf[llength(lp)] = '\0'; 619 if ((s = excline(excbuf)) != TRUE) 620 return s; 621 } 622 return TRUE; 623 } 624 625 /* 626 * evalfile - go get a file and evaluate it as line commands. You can 627 * go get your own startup file if need be. 628 */ 629 /* ARGSUSED */ 630 int 631 evalfile(f, n) 632 int f, n; 633 { 634 int s; 635 char fname[NFILEN]; 636 637 if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE) 638 return s; 639 return load(fname); 640 } 641 642 /* 643 * load - go load the file name we got passed. 644 */ 645 int 646 load(fname) 647 char *fname; 648 { 649 int s = TRUE; 650 int nbytes = 0; 651 char excbuf[128]; 652 653 if ((fname = adjustname(fname)) == NULL) 654 /* just to be careful */ 655 return FALSE; 656 657 if (ffropen(fname, NULL) != FIOSUC) 658 return FALSE; 659 660 while ((s = ffgetline(excbuf, sizeof(excbuf) - 1, &nbytes)) == FIOSUC) { 661 excbuf[nbytes] = '\0'; 662 if (excline(excbuf) != TRUE) { 663 s = FIOERR; 664 ewprintf("Error loading file %s", fname); 665 break; 666 } 667 } 668 (void)ffclose(NULL); 669 excbuf[nbytes] = '\0'; 670 if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE)) 671 return FALSE; 672 return TRUE; 673 } 674 675 /* 676 * excline - run a line from a load file or eval-expression. if FKEYS is 677 * defined, duplicate functionallity of dobind so function key values don't 678 * have to fit in type char. 679 */ 680 int 681 excline(line) 682 char *line; 683 { 684 PF fp; 685 LINE *lp, *np; 686 int status, c, f, n; 687 char *funcp; 688 char *argp = NULL; 689 #ifdef FKEYS 690 int bind; 691 KEYMAP *curmap; 692 #define BINDARG 0 /* this arg is key to bind (local/global set key) */ 693 #define BINDNO 1 /* not binding or non-quoted BINDARG */ 694 #define BINDNEXT 2 /* next arg " (define-key) */ 695 #define BINDDO 3 /* already found key to bind */ 696 #define BINDEXT 1 /* space for trailing \0 */ 697 #else /* FKEYS */ 698 #define BINDEXT 0 699 #endif /* FKEYS */ 700 701 lp = NULL; 702 703 if (macrodef || inmacro) { 704 ewprintf("Not now!"); 705 return FALSE; 706 } 707 f = 0; 708 n = 1; 709 funcp = skipwhite(line); 710 if (*funcp == '\0') 711 return TRUE; /* No error on blank lines */ 712 line = parsetoken(funcp); 713 if (*line != '\0') { 714 *line++ = '\0'; 715 line = skipwhite(line); 716 if ((*line >= '0' && *line <= '9') || *line == '-') { 717 argp = line; 718 line = parsetoken(line); 719 } 720 } 721 if (argp != NULL) { 722 f = FFARG; 723 n = atoi(argp); 724 } 725 if ((fp = name_function(funcp)) == NULL) { 726 ewprintf("Unknown function: %s", funcp); 727 return FALSE; 728 } 729 #ifdef FKEYS 730 if (fp == bindtokey || fp == unbindtokey) { 731 bind = BINDARG; 732 curmap = fundamental_map; 733 } else if (fp == localbind || fp == localunbind) { 734 bind = BINDARG; 735 curmap = curbp->b_modes[curbp->b_nmodes]->p_map; 736 } else if (fp == define_key) 737 bind = BINDNEXT; 738 else 739 bind = BINDNO; 740 #endif /* FKEYS */ 741 /* Pack away all the args now... */ 742 if ((np = lalloc(0)) == FALSE) 743 return FALSE; 744 np->l_fp = np->l_bp = maclcur = np; 745 while (*line != '\0') { 746 argp = skipwhite(line); 747 if (*argp == '\0') 748 break; 749 line = parsetoken(argp); 750 if (*argp != '"') { 751 if (*argp == '\'') 752 ++argp; 753 if (!(lp = lalloc((int) (line - argp) + BINDEXT))) { 754 status = FALSE; 755 goto cleanup; 756 } 757 bcopy(argp, ltext(lp), (int)(line - argp)); 758 #ifdef FKEYS 759 /* don't count BINDEXT */ 760 lp->l_used--; 761 if (bind == BINDARG) 762 bind = BINDNO; 763 #endif /* FKEYS */ 764 } else { 765 /* quoted strings are special */ 766 ++argp; 767 #ifdef FKEYS 768 if (bind != BINDARG) { 769 #endif /* FKEYS */ 770 lp = lalloc((int)(line - argp) + BINDEXT); 771 if (lp == NULL) { 772 status = FALSE; 773 goto cleanup; 774 } 775 lp->l_used = 0; 776 #ifdef FKEYS 777 } else { 778 key.k_count = 0; 779 } 780 #endif /* FKEYS */ 781 while (*argp != '"' && *argp != '\0') { 782 if (*argp != '\\') 783 c = *argp++; 784 else { 785 switch (*++argp) { 786 case 't': 787 case 'T': 788 c = CCHR('I'); 789 break; 790 case 'n': 791 case 'N': 792 c = CCHR('J'); 793 break; 794 case 'r': 795 case 'R': 796 c = CCHR('M'); 797 break; 798 case 'e': 799 case 'E': 800 c = CCHR('['); 801 break; 802 case '^': 803 /* 804 * split into two statements 805 * due to bug in OSK cpp 806 */ 807 c = CHARMASK(*++argp); 808 c = ISLOWER(c) ? 809 CCHR(TOUPPER(c)) : CCHR(c); 810 break; 811 case '0': 812 case '1': 813 case '2': 814 case '3': 815 case '4': 816 case '5': 817 case '6': 818 case '7': 819 c = *argp - '0'; 820 if (argp[1] <= '7' && 821 argp[1] >= '0') { 822 c <<= 3; 823 c += *++argp - '0'; 824 if (argp[1] <= '7' && 825 argp[1] >= '0') { 826 c <<= 3; 827 c += *++argp 828 - '0'; 829 } 830 } 831 break; 832 #ifdef FKEYS 833 case 'f': 834 case 'F': 835 c = *++argp - '0'; 836 if (ISDIGIT(argp[1])) { 837 c *= 10; 838 c += *++argp - '0'; 839 } 840 c += KFIRST; 841 break; 842 #endif /* FKEYS */ 843 default: 844 c = CHARMASK(*argp); 845 break; 846 } 847 argp++; 848 } 849 #ifdef FKEYS 850 if (bind == BINDARG) 851 key.k_chars[key.k_count++] = c; 852 else 853 #endif /* FKEYS */ 854 lp->l_text[lp->l_used++] = c; 855 } 856 if (*line) 857 line++; 858 } 859 #ifdef FKEYS 860 switch (bind) { 861 case BINDARG: 862 bind = BINDDO; 863 break; 864 case BINDNEXT: 865 lp->l_text[lp->l_used] = '\0'; 866 if ((curmap = name_map(lp->l_text)) == NULL) { 867 ewprintf("No such mode: %s", lp->l_text); 868 status = FALSE; 869 free((char *)lp); 870 goto cleanup; 871 } 872 free((char *)lp); 873 bind = BINDARG; 874 break; 875 default: 876 #endif /* FKEYS */ 877 lp->l_fp = np->l_fp; 878 lp->l_bp = np; 879 np->l_fp = lp; 880 np = lp; 881 #ifdef FKEYS 882 } 883 #endif /* FKEYS */ 884 } 885 #ifdef FKEYS 886 switch (bind) { 887 default: 888 ewprintf("Bad args to set key"); 889 status = FALSE; 890 break; 891 case BINDDO: 892 if (fp != unbindtokey && fp != localunbind) { 893 lp->l_text[lp->l_used] = '\0'; 894 status = bindkey(&curmap, lp->l_text, key.k_chars, 895 key.k_count); 896 } else { 897 status = bindkey(&curmap, NULL, key.k_chars, 898 key.k_count); 899 } 900 break; 901 case BINDNO: 902 #endif /* FKEYS */ 903 inmacro = TRUE; 904 maclcur = maclcur->l_fp; 905 status = (*fp)(f, n); 906 inmacro = FALSE; 907 #ifdef FKEYS 908 } 909 #endif /* FKEYS */ 910 cleanup: 911 lp = maclcur->l_fp; 912 while (lp != maclcur) { 913 np = lp->l_fp; 914 free((char *)lp); 915 lp = np; 916 } 917 free((char *)lp); 918 return status; 919 } 920 921 /* 922 * a pair of utility functions for the above 923 */ 924 static char * 925 skipwhite(s) 926 char *s; 927 { 928 while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(') 929 s++; 930 if (*s == ';') 931 *s = '\0'; 932 return s; 933 } 934 935 static char * 936 parsetoken(s) 937 char *s; 938 { 939 if (*s != '"') { 940 while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(') 941 s++; 942 if (*s == ';') 943 *s = '\0'; 944 } else 945 do { 946 /* 947 * Strings get special treatment. 948 * Beware: You can \ out the end of the string! 949 */ 950 if (*s == '\\') 951 ++s; 952 } while (*++s != '"' && *s != '\0'); 953 return s; 954 } 955 #endif /* !NO_STARTUP */ 956