1/* 2 * zle_thingy.c - thingies 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1992-1997 Paul Falstad 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Paul Falstad or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Paul Falstad and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Paul Falstad and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Paul Falstad and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zle.mdh" 31#include "zle_thingy.pro" 32 33/* 34 * Thingies: 35 * 36 * From the user's point of view, a thingy is just a string. Internally, 37 * the thingy is a struct thingy; these structures are in a hash table 38 * indexed by the string the user sees. This hash table contains all 39 * thingies currently referenced anywhere; each has a reference count, 40 * and is deleted when it becomes unused. Being the name of a function 41 * counts as a reference. 42 * 43 * The DISABLED flag on a thingy indicates that it is not the name of a 44 * widget. This makes it easy to generate completion lists; 45 * looking only at the `enabled' nodes makes the thingy table look like 46 * a table of widgets. 47 */ 48 49/* Hashtable of thingies. Enabled nodes are those that refer to widgets. */ 50 51/**/ 52mod_export HashTable thingytab; 53 54/**********************************/ 55/* hashtable management functions */ 56/**********************************/ 57 58/**/ 59static void 60createthingytab(void) 61{ 62 thingytab = newhashtable(199, "thingytab", NULL); 63 64 thingytab->hash = hasher; 65 thingytab->emptytable = emptythingytab; 66 thingytab->filltable = NULL; 67 thingytab->cmpnodes = strcmp; 68 thingytab->addnode = addhashnode; 69 thingytab->getnode = gethashnode; 70 thingytab->getnode2 = gethashnode2; 71 thingytab->removenode = removehashnode; 72 thingytab->disablenode = NULL; 73 thingytab->enablenode = NULL; 74 thingytab->freenode = freethingynode; 75 thingytab->printnode = NULL; 76} 77 78/**/ 79static void 80emptythingytab(UNUSED(HashTable ht)) 81{ 82 /* This will only be called when deleting the thingy table, which * 83 * is only done to unload the zle module. A normal emptytable() * 84 * function would free all the thingies, but we don't want to do * 85 * that because some of them are the known thingies in the fixed * 86 * `thingies' table. As the module cleanup code deletes all the * 87 * keymaps and so on before deleting the thingy table, we can * 88 * just remove the user-defined widgets and then be sure that * 89 * *all* the thingies left are the fixed ones. This has the side * 90 * effect of freeing all resources used by user-defined widgets. */ 91 scanhashtable(thingytab, 0, 0, DISABLED, scanemptythingies, 0); 92} 93 94/**/ 95static void 96scanemptythingies(HashNode hn, UNUSED(int flags)) 97{ 98 Thingy t = (Thingy) hn; 99 100 /* Mustn't unbind internal widgets -- we wouldn't want to free the * 101 * memory they use. */ 102 if(!(t->widget->flags & WIDGET_INT)) 103 unbindwidget(t, 1); 104} 105 106/**/ 107static Thingy 108makethingynode(void) 109{ 110 Thingy t = (Thingy) zshcalloc(sizeof(*t)); 111 112 t->flags = DISABLED; 113 return t; 114} 115 116/**/ 117static void 118freethingynode(HashNode hn) 119{ 120 Thingy th = (Thingy) hn; 121 122 zsfree(th->nam); 123 zfree(th, sizeof(*th)); 124} 125 126/************************/ 127/* referencing thingies */ 128/************************/ 129 130/* It is important to maintain the reference counts on thingies. When * 131 * copying a reference to a thingy, wrap the copy in refthingy(), to * 132 * increase its reference count. When removing a reference, * 133 * unrefthingy() it. Both of these functions handle NULL arguments * 134 * correctly. */ 135 136/**/ 137mod_export Thingy 138refthingy(Thingy th) 139{ 140 if(th) 141 th->rc++; 142 return th; 143} 144 145/**/ 146void 147unrefthingy(Thingy th) 148{ 149 if(th && !--th->rc) 150 thingytab->freenode(thingytab->removenode(thingytab, th->nam)); 151} 152 153/* Use rthingy() to turn a string into a thingy. It increases the reference * 154 * count, after creating the thingy structure if necessary. */ 155 156/**/ 157Thingy 158rthingy(char *nam) 159{ 160 Thingy t = (Thingy) thingytab->getnode2(thingytab, nam); 161 162 if(!t) 163 thingytab->addnode(thingytab, ztrdup(nam), t = makethingynode()); 164 return refthingy(t); 165} 166 167/**/ 168Thingy 169rthingy_nocreate(char *nam) 170{ 171 Thingy t = (Thingy) thingytab->getnode2(thingytab, nam); 172 173 if(!t) 174 return NULL; 175 return refthingy(t); 176} 177 178/***********/ 179/* widgets */ 180/***********/ 181 182/* 183 * Each widget is attached to one or more thingies. Each thingy 184 * names either zero or one widgets. Thingies that name a widget 185 * are treated as being referenced. The widget type, flags and pointer 186 * are stored in a separate structure pointed to by the thingies. Each 187 * thingy also has a pointer to the `next' thingy (in a circular list) 188 * that references the same widget. The DISABLED flag is unset in these 189 * thingies. 190 */ 191 192/* Bind a widget to a thingy. The thingy's reference count must already * 193 * have been incremented. The widget may already be bound to other * 194 * thingies; if it is not, then its `first' member must be NULL. Return * 195 * is 0 on success, or -1 if the thingy has the TH_IMMORTAL flag set. */ 196 197/**/ 198static int 199bindwidget(Widget w, Thingy t) 200{ 201 if(t->flags & TH_IMMORTAL) { 202 unrefthingy(t); 203 return -1; 204 } 205 if(!(t->flags & DISABLED)) { 206 if(t->widget == w) 207 return 0; 208 unbindwidget(t, 1); 209 } 210 if(w->first) { 211 t->samew = w->first->samew; 212 w->first->samew = t; 213 } else { 214 w->first = t; 215 t->samew = t; 216 } 217 t->widget = w; 218 t->flags &= ~DISABLED; 219 return 0; 220} 221 222/* Unbind a widget from a thingy. This decrements the thingy's reference * 223 * count. The widget will be destroyed if this is its last name. * 224 * TH_IMMORTAL thingies won't be touched, unless override is non-zero. * 225 * Returns 0 on success, or -1 if the thingy is protected. If the thingy * 226 * doesn't actually reference a widget, this is considered successful. */ 227 228/**/ 229static int 230unbindwidget(Thingy t, int override) 231{ 232 Widget w; 233 234 if(t->flags & DISABLED) 235 return 0; 236 if(!override && (t->flags & TH_IMMORTAL)) 237 return -1; 238 w = t->widget; 239 if(t->samew == t) 240 freewidget(w); 241 else { 242 Thingy p; 243 for(p = w->first; p->samew != t; p = p->samew) ; 244 w->first = p; /* optimised for deletezlefunction() */ 245 p->samew = t->samew; 246 } 247 t->flags &= ~TH_IMMORTAL; 248 t->flags |= DISABLED; 249 unrefthingy(t); 250 return 0; 251} 252 253/* Free a widget. */ 254 255/**/ 256static void 257freewidget(Widget w) 258{ 259 if (w->flags & WIDGET_NCOMP) { 260 zsfree(w->u.comp.wid); 261 zsfree(w->u.comp.func); 262 } else if(!(w->flags & WIDGET_INT)) 263 zsfree(w->u.fnnam); 264 zfree(w, sizeof(*w)); 265} 266 267/* Add am internal widget provided by a module. The name given is the * 268 * canonical one, which must not begin with a dot. The widget is first * 269 * bound to the dotted canonical name; if that name is already taken by * 270 * an internal widget, failure is indicated. The same widget is then * 271 * bound to the canonical name, and a pointer to the widget structure * 272 * returned. */ 273 274/**/ 275mod_export Widget 276addzlefunction(char *name, ZleIntFunc ifunc, int flags) 277{ 278 VARARR(char, dotn, strlen(name) + 2); 279 Widget w; 280 Thingy t; 281 282 if(name[0] == '.') 283 return NULL; 284 dotn[0] = '.'; 285 strcpy(dotn + 1, name); 286 t = (Thingy) thingytab->getnode(thingytab, dotn); 287 if(t && (t->flags & TH_IMMORTAL)) 288 return NULL; 289 w = zalloc(sizeof(*w)); 290 w->flags = WIDGET_INT | flags; 291 w->first = NULL; 292 w->u.fn = ifunc; 293 t = rthingy(dotn); 294 bindwidget(w, t); 295 t->flags |= TH_IMMORTAL; 296 bindwidget(w, rthingy(name)); 297 return w; 298} 299 300/* Delete an internal widget provided by a module. Don't try to delete * 301 * a widget from the fixed table -- it would be bad. (Thanks, Egon.) */ 302 303/**/ 304mod_export void 305deletezlefunction(Widget w) 306{ 307 Thingy p, n; 308 309 p = w->first; 310 while(1) { 311 n = p->samew; 312 if(n == p) { 313 unbindwidget(p, 1); 314 return; 315 } 316 unbindwidget(p, 1); 317 p = n; 318 } 319} 320 321/***************/ 322/* zle builtin */ 323/***************/ 324 325/* 326 * The available operations are: 327 * 328 * -l list widgets/test for existence 329 * -D delete widget names 330 * -A link the two named widgets (2 arguments) 331 * -C create completion widget (3 arguments) 332 * -N create new user-defined widget (1 or 2 arguments) 333 * invoke a widget (1 argument) 334 */ 335 336/**/ 337int 338bin_zle(char *name, char **args, Options ops, UNUSED(int func)) 339{ 340 static struct opn { 341 char o; 342 int (*func) _((char *, char **, Options, char)); 343 int min, max; 344 } const opns[] = { 345 { 'l', bin_zle_list, 0, -1 }, 346 { 'D', bin_zle_del, 1, -1 }, 347 { 'A', bin_zle_link, 2, 2 }, 348 { 'N', bin_zle_new, 1, 2 }, 349 { 'C', bin_zle_complete, 3, 3 }, 350 { 'R', bin_zle_refresh, 0, -1 }, 351 { 'M', bin_zle_mesg, 1, 1 }, 352 { 'U', bin_zle_unget, 1, 1 }, 353 { 'K', bin_zle_keymap, 1, 1 }, 354 { 'I', bin_zle_invalidate, 0, 0 }, 355 { 'F', bin_zle_fd, 0, 2 }, 356 { 'T', bin_zle_transform, 0, 2}, 357 { 0, bin_zle_call, 0, -1 }, 358 }; 359 struct opn const *op, *opp; 360 int n; 361 362 /* select operation and ensure no clashing arguments */ 363 for(op = opns; op->o && !OPT_ISSET(ops,STOUC(op->o)); op++) ; 364 if(op->o) 365 for(opp = op; (++opp)->o; ) 366 if(OPT_ISSET(ops,STOUC(opp->o))) { 367 zwarnnam(name, "incompatible operation selection options"); 368 return 1; 369 } 370 371 /* check number of arguments */ 372 for(n = 0; args[n]; n++) ; 373 if(n < op->min) { 374 zwarnnam(name, "not enough arguments for -%c", op->o); 375 return 1; 376 } else if(op->max != -1 && n > op->max) { 377 zwarnnam(name, "too many arguments for -%c", op->o); 378 return 1; 379 } 380 381 /* pass on the work to the operation function */ 382 return op->func(name, args, ops, op->o); 383} 384 385/**/ 386static int 387bin_zle_list(UNUSED(char *name), char **args, Options ops, UNUSED(char func)) 388{ 389 if (!*args) { 390 scanhashtable(thingytab, 1, 0, DISABLED, scanlistwidgets, 391 (OPT_ISSET(ops,'a') ? -1 : OPT_ISSET(ops,'L'))); 392 return 0; 393 } else { 394 int ret = 0; 395 Thingy t; 396 397 for (; *args && !ret; args++) { 398 HashNode hn = thingytab->getnode2(thingytab, *args); 399 if (!(t = (Thingy) hn) || 400 (!OPT_ISSET(ops,'a') && (t->widget->flags & WIDGET_INT))) 401 ret = 1; 402 else if (OPT_ISSET(ops,'L')) { 403 scanlistwidgets(hn, 1); 404 } 405 } 406 return ret; 407 } 408} 409 410/**/ 411static int 412bin_zle_refresh(UNUSED(char *name), char **args, Options ops, UNUSED(char func)) 413{ 414 char *s = statusline; 415 int ocl = clearlist; 416 417 if (!zleactive) 418 return 1; 419 statusline = NULL; 420 if (*args) { 421 if (**args) 422 statusline = *args; 423 if (*++args) { 424 LinkList l = newlinklist(); 425 int zmultsav = zmult; 426 427 for (; *args; args++) 428 addlinknode(l, *args); 429 430 zmult = 1; 431 listlist(l); 432 if (statusline) 433 lastlistlen++; 434 showinglist = clearlist = 0; 435 zmult = zmultsav; 436 } else if (OPT_ISSET(ops,'c')) { 437 clearlist = 1; 438 lastlistlen = 0; 439 } 440 } else if (OPT_ISSET(ops,'c')) { 441 clearlist = listshown = 1; 442 lastlistlen = 0; 443 } 444 zrefresh(); 445 446 clearlist = ocl; 447 statusline = s; 448 return 0; 449} 450 451/**/ 452static int 453bin_zle_mesg(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 454{ 455 if (!zleactive) { 456 zwarnnam(name, "can only be called from widget function"); 457 return 1; 458 } 459 showmsg(*args); 460 if (sfcontext != SFC_WIDGET) 461 zrefresh(); 462 return 0; 463} 464 465/**/ 466static int 467bin_zle_unget(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 468{ 469 char *b = *args, *p = b + strlen(b); 470 471 if (!zleactive) { 472 zwarnnam(name, "can only be called from widget function"); 473 return 1; 474 } 475 while (p > b) 476 ungetbyte((int) *--p); 477 return 0; 478} 479 480/**/ 481static int 482bin_zle_keymap(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 483{ 484 if (!zleactive) { 485 zwarnnam(name, "can only be called from widget function"); 486 return 1; 487 } 488 return selectkeymap(*args, 0); 489} 490 491/* 492 * List a widget. 493 * If list is negative, just print the name. 494 * If list is 0, use abbreviated format. 495 * If list is positive, output as a command. 496 */ 497/**/ 498static void 499scanlistwidgets(HashNode hn, int list) 500{ 501 Thingy t = (Thingy) hn; 502 Widget w = t->widget; 503 504 if(list < 0) { 505 printf("%s\n", hn->nam); 506 return; 507 } 508 if(w->flags & WIDGET_INT) 509 return; 510 if(list) { 511 printf("zle -%c ", (w->flags & WIDGET_NCOMP) ? 'C' : 'N'); 512 if(t->nam[0] == '-') 513 fputs("-- ", stdout); 514 quotedzputs(t->nam, stdout); 515 if (w->flags & WIDGET_NCOMP) { 516 fputc(' ', stdout); 517 quotedzputs(w->u.comp.wid, stdout); 518 fputc(' ', stdout); 519 quotedzputs(w->u.comp.func, stdout); 520 } else if(strcmp(t->nam, w->u.fnnam)) { 521 fputc(' ', stdout); 522 quotedzputs(w->u.fnnam, stdout); 523 } 524 } else { 525 nicezputs(t->nam, stdout); 526 if (w->flags & WIDGET_NCOMP) { 527 fputs(" -C ", stdout); 528 nicezputs(w->u.comp.wid, stdout); 529 fputc(' ', stdout); 530 nicezputs(w->u.comp.func, stdout); 531 } else if(strcmp(t->nam, w->u.fnnam)) { 532 fputs(" (", stdout); 533 nicezputs(w->u.fnnam, stdout); 534 fputc(')', stdout); 535 } 536 } 537 putchar('\n'); 538} 539 540/**/ 541static int 542bin_zle_del(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 543{ 544 int ret = 0; 545 546 do { 547 Thingy t = (Thingy) thingytab->getnode(thingytab, *args); 548 if(!t) { 549 zwarnnam(name, "no such widget `%s'", *args); 550 ret = 1; 551 } else if(unbindwidget(t, 0)) { 552 zwarnnam(name, "widget name `%s' is protected", *args); 553 ret = 1; 554 } 555 } while(*++args); 556 return ret; 557} 558 559/**/ 560static int 561bin_zle_link(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 562{ 563 Thingy t = (Thingy) thingytab->getnode(thingytab, args[0]); 564 565 if(!t) { 566 zwarnnam(name, "no such widget `%s'", args[0]); 567 return 1; 568 } else if(bindwidget(t->widget, rthingy(args[1]))) { 569 zwarnnam(name, "widget name `%s' is protected", args[1]); 570 return 1; 571 } 572 return 0; 573 574} 575 576/**/ 577static int 578bin_zle_new(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 579{ 580 Widget w = zalloc(sizeof(*w)); 581 582 w->flags = 0; 583 w->first = NULL; 584 w->u.fnnam = ztrdup(args[1] ? args[1] : args[0]); 585 if(!bindwidget(w, rthingy(args[0]))) 586 return 0; 587 freewidget(w); 588 zwarnnam(name, "widget name `%s' is protected", args[0]); 589 return 1; 590} 591 592/**/ 593static int 594bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 595{ 596 Thingy t; 597 Widget w, cw; 598 599 if (require_module("zsh/complete", NULL) == 1) { 600 zwarnnam(name, "can't load complete module"); 601 return 1; 602 } 603 t = rthingy((args[1][0] == '.') ? args[1] : dyncat(".", args[1])); 604 cw = t->widget; 605 unrefthingy(t); 606 if (!cw || !(cw->flags & ZLE_ISCOMP)) { 607 zwarnnam(name, "invalid widget `%s'", args[1]); 608 return 1; 609 } 610 w = zalloc(sizeof(*w)); 611 w->flags = WIDGET_NCOMP|ZLE_MENUCMP|ZLE_KEEPSUFFIX; 612 w->first = NULL; 613 w->u.comp.fn = cw->u.fn; 614 w->u.comp.wid = ztrdup(args[1]); 615 w->u.comp.func = ztrdup(args[2]); 616 if (bindwidget(w, rthingy(args[0]))) { 617 freewidget(w); 618 zwarnnam(name, "widget name `%s' is protected", args[0]); 619 return 1; 620 } 621 hascompwidgets++; 622 623 return 0; 624} 625 626/**/ 627static int 628zle_usable() 629{ 630 return zleactive && !incompctlfunc && !incompfunc 631#if 0 632 /* 633 * PWS experiment: commenting this out allows zle widgets 634 * in signals, hooks etc. I'm not sure if this has a down side; 635 * it ought to be that zleactive is good enough to test whether 636 * widgets are callable. 637 */ 638 && sfcontext == SFC_WIDGET 639#endif 640 ; 641} 642 643/**/ 644static int 645bin_zle_call(char *name, char **args, UNUSED(Options ops), UNUSED(char func)) 646{ 647 Thingy t; 648 struct modifier modsave = zmod; 649 int ret, saveflag = 0, setbindk = 0; 650 char *wname = *args++, *keymap_restore = NULL, *keymap_tmp; 651 652 if (!wname) 653 return !zle_usable(); 654 655 if(!zle_usable()) { 656 zwarnnam(name, "widgets can only be called when ZLE is active"); 657 return 1; 658 } 659 660 UNMETACHECK(); 661 662 while (*args && **args == '-') { 663 char *num; 664 if (!args[0][1] || args[0][1] == '-') { 665 args++; 666 break; 667 } 668 while (*++(*args)) { 669 switch (**args) { 670 case 'n': 671 num = args[0][1] ? args[0]+1 : args[1]; 672 if (!num) { 673 zwarnnam(name, "number expected after -%c", **args); 674 return 1; 675 } 676 if (!args[0][1]) 677 *++args = "" - 1; 678 saveflag = 1; 679 zmod.mult = atoi(num); 680 zmod.flags |= MOD_MULT; 681 break; 682 case 'N': 683 saveflag = 1; 684 zmod.mult = 1; 685 zmod.flags &= ~MOD_MULT; 686 break; 687 case 'K': 688 keymap_tmp = args[0][1] ? args[0]+1 : args[1]; 689 if (!keymap_tmp) { 690 zwarnnam(name, "keymap expected after -%c", **args); 691 return 1; 692 } 693 if (!args[0][1]) 694 *++args = "" - 1; 695 keymap_restore = dupstring(curkeymapname); 696 if (selectkeymap(keymap_tmp, 0)) 697 return 1; 698 break; 699 case 'w': 700 setbindk = 1; 701 break; 702 default: 703 zwarnnam(name, "unknown option: %s", *args); 704 return 1; 705 } 706 } 707 args++; 708 } 709 710 t = rthingy(wname); 711 ret = execzlefunc(t, args, setbindk); 712 unrefthingy(t); 713 if (saveflag) 714 zmod = modsave; 715 if (keymap_restore) 716 selectkeymap(keymap_restore, 0); 717 return ret; 718} 719 720 721/* 722 * Flag that the user has requested the terminal be trashed 723 * for whatever use. We attempt to keep the tty settings in 724 * this mode synced with the normal (non-zle) settings unless 725 * they are frozen. 726 */ 727 728/**/ 729int fetchttyinfo; 730 731/**/ 732static int 733bin_zle_invalidate(UNUSED(char *name), UNUSED(char **args), UNUSED(Options ops), UNUSED(char func)) 734{ 735 /* 736 * Trash zle if trashable, but only indicate that zle is usable 737 * if it's possible to call a zle widget next. This is not 738 * true if a completion widget is active. 739 */ 740 if (zleactive) { 741 int wastrashed = trashedzle; 742 trashzle(); 743 if (!wastrashed && (zlereadflags & ZLRF_NOSETTY)) { 744 /* 745 * We normally wouldn't have restored the terminal 746 * in this case, but as it's at user request we do 747 * so (hence the apparently illogical sense of the 748 * second part of the test). 749 */ 750 settyinfo(&shttyinfo); 751 } 752 fetchttyinfo = 1; 753 return 0; 754 } else 755 return 1; 756} 757 758/**/ 759static int 760bin_zle_fd(char *name, char **args, Options ops, UNUSED(char func)) 761{ 762 int fd = 0, i, found = 0; 763 char *endptr; 764 765 if (*args) { 766 fd = (int)zstrtol(*args, &endptr, 10); 767 768 if (*endptr || fd < 0) { 769 zwarnnam(name, "Bad file descriptor number for -F: %s", *args); 770 return 1; 771 } 772 } 773 774 if (OPT_ISSET(ops,'L') || !*args) { 775 /* Listing handlers. */ 776 if (*args && args[1]) { 777 zwarnnam(name, "too many arguments for -FL"); 778 return 1; 779 } 780 for (i = 0; i < nwatch; i++) { 781 if (*args && watch_fds[i] != fd) 782 continue; 783 found = 1; 784 printf("%s -F %d %s\n", name, watch_fds[i], watch_funcs[i]); 785 } 786 /* only return status 1 if fd given and not found */ 787 return *args && !found; 788 } 789 790 if (args[1]) { 791 /* Adding or replacing a handler */ 792 char *funcnam = ztrdup(args[1]); 793 if (nwatch) { 794 for (i = 0; i < nwatch; i++) { 795 if (watch_fds[i] == fd) { 796 zsfree(watch_funcs[i]); 797 watch_funcs[i] = funcnam; 798 found = 1; 799 break; 800 } 801 } 802 } 803 if (!found) { 804 /* zrealloc handles NULL pointers, so OK for first time through */ 805 int newnwatch = nwatch+1; 806 watch_fds = (int *)zrealloc(watch_fds, 807 newnwatch * sizeof(int)); 808 watch_funcs = (char **)zrealloc(watch_funcs, 809 (newnwatch+1) * sizeof(char *)); 810 watch_fds[nwatch] = fd; 811 watch_funcs[nwatch] = funcnam; 812 watch_funcs[newnwatch] = NULL; 813 nwatch = newnwatch; 814 } 815 } else { 816 /* Deleting a handler */ 817 for (i = 0; i < nwatch; i++) { 818 if (watch_fds[i] == fd) { 819 int newnwatch = nwatch-1; 820 int *new_fds; 821 char **new_funcs; 822 823 zsfree(watch_funcs[i]); 824 if (newnwatch) { 825 new_fds = zalloc(newnwatch*sizeof(int)); 826 new_funcs = zalloc((newnwatch+1)*sizeof(char*)); 827 if (i) { 828 memcpy(new_fds, watch_fds, i*sizeof(int)); 829 memcpy(new_funcs, watch_funcs, i*sizeof(char *)); 830 } 831 if (i < newnwatch) { 832 memcpy(new_fds+i, watch_fds+i+1, 833 (newnwatch-i)*sizeof(int)); 834 memcpy(new_funcs+i, watch_funcs+i+1, 835 (newnwatch-i)*sizeof(char *)); 836 } 837 new_funcs[newnwatch] = NULL; 838 } else { 839 new_fds = NULL; 840 new_funcs = NULL; 841 } 842 zfree(watch_fds, nwatch*sizeof(int)); 843 zfree(watch_funcs, (nwatch+1)*sizeof(char *)); 844 watch_fds = new_fds; 845 watch_funcs = new_funcs; 846 nwatch = newnwatch; 847 found = 1; 848 break; 849 } 850 } 851 if (!found) { 852 zwarnnam(name, "No handler installed for fd %d", fd); 853 return 1; 854 } 855 } 856 857 return 0; 858} 859 860/**/ 861static int 862bin_zle_transform(char *name, char **args, Options ops, UNUSED(char func)) 863{ 864 /* 865 * -1: too few arguments 866 * 0: just right 867 * 1: too many arguments 868 * 2: first argument not recognised 869 */ 870 int badargs = 0; 871 872 if (OPT_ISSET(ops,'L')) { 873 if (args[0]) { 874 if (args[1]) { 875 badargs = 1; 876 } else if (strcmp(args[0], "tc")) { 877 badargs = 2; 878 } 879 } 880 if (!badargs && tcout_func_name) { 881 fputs("zle -T tc ", stdout); 882 quotedzputs(tcout_func_name, stdout); 883 putchar('\n'); 884 } 885 } else if (OPT_ISSET(ops,'r')) { 886 if (!args[0]) { 887 badargs = -1; 888 } else if (args[1]) { 889 badargs = 1; 890 } else if (tcout_func_name) { 891 zsfree(tcout_func_name); 892 tcout_func_name = NULL; 893 } 894 } else { 895 if (!args[0] || !args[1]) { 896 badargs = -1; 897 /* we've already checked args <= 2 */ 898 } else { 899 if (!strcmp(args[0], "tc")) { 900 if (tcout_func_name) { 901 zsfree(tcout_func_name); 902 } 903 tcout_func_name = ztrdup(args[1]); 904 } else { 905 badargs = 2; 906 } 907 } 908 } 909 910 if (badargs) { 911 if (badargs == 2) { 912 zwarnnam(name, "-T: no such transformation '%s'", args[0]); 913 } else { 914 char *way = (badargs > 0) ? "many" : "few"; 915 zwarnnam(name, "too %s arguments for option -T", way); 916 } 917 return 1; 918 } 919 920 return 0; 921} 922 923/*******************/ 924/* initialiasation */ 925/*******************/ 926 927/**/ 928void 929init_thingies(void) 930{ 931 Thingy t; 932 933 createthingytab(); 934 for(t = thingies; t->nam; t++) 935 thingytab->addnode(thingytab, t->nam, t); 936} 937