1/* 2 * zle_params.c - ZLE special parameters 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 32#include "zle_params.pro" 33 34/* 35 * ZLE SPECIAL PARAMETERS: 36 * 37 * These special parameters are created, with a local scope, when 38 * running user-defined widget functions. Reading and writing them 39 * reads and writes bits of ZLE state. The parameters are: 40 * 41 * BUFFER (scalar) entire buffer contents 42 * CURSOR (integer) cursor position; 0 <= $CURSOR <= $#BUFFER 43 * LBUFFER (scalar) portion of buffer to the left of the cursor 44 * RBUFFER (scalar) portion of buffer to the right of the cursor 45 */ 46 47static const struct gsu_scalar buffer_gsu = 48{ get_buffer, set_buffer, zleunsetfn }; 49static const struct gsu_scalar context_gsu = 50{ get_context, nullstrsetfn, zleunsetfn }; 51static const struct gsu_scalar cutbuffer_gsu = 52{ get_cutbuffer, set_cutbuffer, unset_cutbuffer }; 53static const struct gsu_scalar keymap_gsu = 54{ get_keymap, nullstrsetfn, zleunsetfn }; 55static const struct gsu_scalar keys_gsu = 56{ get_keys, nullstrsetfn, zleunsetfn }; 57static const struct gsu_scalar lastabortedsearch_gsu = 58{ get_lasearch, nullstrsetfn, zleunsetfn }; 59static const struct gsu_scalar lastsearch_gsu = 60{ get_lsearch, nullstrsetfn, zleunsetfn }; 61static const struct gsu_scalar lastwidget_gsu = 62{ get_lwidget, nullstrsetfn, zleunsetfn }; 63static const struct gsu_scalar lbuffer_gsu = 64{ get_lbuffer, set_lbuffer, zleunsetfn }; 65static const struct gsu_scalar postdisplay_gsu = 66{ get_postdisplay, set_postdisplay, zleunsetfn }; 67static const struct gsu_scalar prebuffer_gsu = 68{ get_prebuffer, nullstrsetfn, zleunsetfn }; 69static const struct gsu_scalar predisplay_gsu = 70{ get_predisplay, set_predisplay, zleunsetfn }; 71static const struct gsu_scalar rbuffer_gsu = 72{ get_rbuffer, set_rbuffer, zleunsetfn }; 73static const struct gsu_scalar widget_gsu = 74{ get_widget, nullstrsetfn, zleunsetfn }; 75static const struct gsu_scalar widgetfunc_gsu = 76{ get_widgetfunc, nullstrsetfn, zleunsetfn }; 77static const struct gsu_scalar widgetstyle_gsu = 78{ get_widgetstyle, nullstrsetfn, zleunsetfn }; 79static const struct gsu_scalar zle_state_gsu = 80{ get_zle_state, nullstrsetfn, zleunsetfn }; 81 82static const struct gsu_integer bufferlines_gsu = 83{ get_bufferlines, NULL, zleunsetfn }; 84static const struct gsu_integer cursor_gsu = 85{ get_cursor, set_cursor, zleunsetfn }; 86static const struct gsu_integer histno_gsu = 87{ get_histno, set_histno, zleunsetfn }; 88static const struct gsu_integer mark_gsu = 89{ get_mark, set_mark, zleunsetfn }; 90static const struct gsu_integer numeric_gsu = 91{ get_numeric, set_numeric, unset_numeric }; 92static const struct gsu_integer pending_gsu = 93{ get_pending, NULL, zleunsetfn }; 94static const struct gsu_integer region_active_gsu = 95{ get_region_active, set_region_active, zleunsetfn }; 96static const struct gsu_integer undo_change_no_gsu = 97{ get_undo_current_change, NULL, zleunsetfn }; 98 99static const struct gsu_array killring_gsu = 100{ get_killring, set_killring, unset_killring }; 101/* implementation is in zle_refresh.c */ 102static const struct gsu_array region_highlight_gsu = 103{ get_region_highlight, set_region_highlight, unset_region_highlight }; 104 105#define GSU(X) ( (GsuScalar)(void*)(&(X)) ) 106static struct zleparam { 107 char *name; 108 int type; 109 GsuScalar gsu; 110 void *data; 111} zleparams[] = { 112 { "BUFFER", PM_SCALAR, GSU(buffer_gsu), NULL }, 113 { "BUFFERLINES", PM_INTEGER | PM_READONLY, GSU(bufferlines_gsu), 114 NULL }, 115 { "CONTEXT", PM_SCALAR | PM_READONLY, GSU(context_gsu), 116 NULL }, 117 { "CURSOR", PM_INTEGER, GSU(cursor_gsu), 118 NULL }, 119 { "CUTBUFFER", PM_SCALAR, GSU(cutbuffer_gsu), NULL }, 120 { "HISTNO", PM_INTEGER, GSU(histno_gsu), NULL }, 121 { "KEYMAP", PM_SCALAR | PM_READONLY, GSU(keymap_gsu), NULL }, 122 { "KEYS", PM_SCALAR | PM_READONLY, GSU(keys_gsu), NULL }, 123 { "killring", PM_ARRAY, GSU(killring_gsu), NULL }, 124 { "LASTABORTEDSEARCH", PM_SCALAR | PM_READONLY, GSU(lastabortedsearch_gsu), 125 NULL }, 126 { "LASTSEARCH", PM_SCALAR | PM_READONLY, GSU(lastsearch_gsu), NULL }, 127 { "LASTWIDGET", PM_SCALAR | PM_READONLY, GSU(lastwidget_gsu), NULL }, 128 { "LBUFFER", PM_SCALAR, GSU(lbuffer_gsu), NULL }, 129 { "MARK", PM_INTEGER, GSU(mark_gsu), NULL }, 130 { "NUMERIC", PM_INTEGER | PM_UNSET, GSU(numeric_gsu), NULL }, 131 { "PENDING", PM_INTEGER | PM_READONLY, GSU(pending_gsu), NULL }, 132 { "POSTDISPLAY", PM_SCALAR, GSU(postdisplay_gsu), NULL }, 133 { "PREBUFFER", PM_SCALAR | PM_READONLY, GSU(prebuffer_gsu), NULL }, 134 { "PREDISPLAY", PM_SCALAR, GSU(predisplay_gsu), NULL }, 135 { "RBUFFER", PM_SCALAR, GSU(rbuffer_gsu), NULL }, 136 { "REGION_ACTIVE", PM_INTEGER, GSU(region_active_gsu), NULL}, 137 { "region_highlight", PM_ARRAY, GSU(region_highlight_gsu), NULL }, 138 { "UNDO_CHANGE_NO", PM_INTEGER | PM_READONLY, GSU(undo_change_no_gsu), 139 NULL }, 140 { "WIDGET", PM_SCALAR | PM_READONLY, GSU(widget_gsu), NULL }, 141 { "WIDGETFUNC", PM_SCALAR | PM_READONLY, GSU(widgetfunc_gsu), NULL }, 142 { "WIDGETSTYLE", PM_SCALAR | PM_READONLY, GSU(widgetstyle_gsu), NULL }, 143 { "ZLE_STATE", PM_SCALAR | PM_READONLY, GSU(zle_state_gsu), NULL }, 144 { NULL, 0, NULL, NULL } 145}; 146 147/* ro means parameters are readonly, used from completion */ 148 149/**/ 150mod_export void 151makezleparams(int ro) 152{ 153 struct zleparam *zp; 154 155 for(zp = zleparams; zp->name; zp++) { 156 Param pm = createparam(zp->name, (zp->type |PM_SPECIAL|PM_REMOVABLE| 157 PM_LOCAL|(ro ? PM_READONLY : 0))); 158 if (!pm) 159 pm = (Param) paramtab->getnode(paramtab, zp->name); 160 DPUTS(!pm, "param not set in makezleparams"); 161 162 pm->level = locallevel + 1; 163 pm->u.data = zp->data; 164 switch(PM_TYPE(zp->type)) { 165 case PM_SCALAR: 166 pm->gsu.s = zp->gsu; 167 break; 168 case PM_ARRAY: 169 pm->gsu.a = (GsuArray)zp->gsu; 170 break; 171 case PM_INTEGER: 172 pm->gsu.i = (GsuInteger)zp->gsu; 173 pm->base = 10; 174 break; 175 } 176 if ((zp->type & PM_UNSET) && (zmod.flags & MOD_MULT)) 177 pm->node.flags &= ~PM_UNSET; 178 } 179} 180 181/* Special unset function for ZLE special parameters: act like the standard * 182 * unset function if this is a user-initiated unset, but nothing is done if * 183 * the parameter is merely going out of scope (which it will do). */ 184 185/**/ 186static void 187zleunsetfn(Param pm, int exp) 188{ 189 if(exp) 190 stdunsetfn(pm, exp); 191} 192 193/**/ 194static void 195set_buffer(UNUSED(Param pm), char *x) 196{ 197 if(x) { 198 setline(x, 0); 199 zsfree(x); 200 } else 201 zlecs = zlell = 0; 202 fixsuffix(); 203 menucmp = 0; 204} 205 206/**/ 207static char * 208get_buffer(UNUSED(Param pm)) 209{ 210 if (zlemetaline != 0) 211 return dupstring(zlemetaline); 212 return zlelineasstring(zleline, zlell, 0, NULL, NULL, 1); 213} 214 215/**/ 216static void 217set_cursor(UNUSED(Param pm), zlong x) 218{ 219 if(x < 0) 220 zlecs = 0; 221 else if(x > zlell) 222 zlecs = zlell; 223 else 224 zlecs = x; 225 fixsuffix(); 226 menucmp = 0; 227} 228 229/**/ 230static zlong 231get_cursor(UNUSED(Param pm)) 232{ 233 if (zlemetaline != NULL) { 234 /* A lot of work for one number, but still... */ 235 ZLE_STRING_T tmpline; 236 int tmpcs, tmpll, tmpsz; 237 char *tmpmetaline = ztrdup(zlemetaline); 238 tmpline = stringaszleline(tmpmetaline, zlemetacs, 239 &tmpll, &tmpsz, &tmpcs); 240 free(tmpmetaline); 241 free(tmpline); 242 return tmpcs; 243 } 244 return zlecs; 245} 246 247/**/ 248static void 249set_mark(UNUSED(Param pm), zlong x) 250{ 251 if (x < 0) 252 mark = 0; 253 else if (x > zlell) 254 mark = zlell; 255 else 256 mark = x; 257} 258 259/**/ 260static zlong 261get_mark(UNUSED(Param pm)) 262{ 263 return mark; 264} 265 266/**/ 267static void 268set_region_active(UNUSED(Param pm), zlong x) 269{ 270 region_active = (int)!!x; 271} 272 273/**/ 274static zlong 275get_region_active(UNUSED(Param pm)) 276{ 277 return region_active; 278} 279 280/**/ 281static void 282set_lbuffer(UNUSED(Param pm), char *x) 283{ 284 ZLE_STRING_T y; 285 int len; 286 287 if (x && *x != ZWC('\0')) 288 y = stringaszleline(x, 0, &len, NULL, NULL); 289 else 290 y = ZWS(""), len = 0; 291 sizeline(zlell - zlecs + len); 292 ZS_memmove(zleline + len, zleline + zlecs, zlell - zlecs); 293 ZS_memcpy(zleline, y, len); 294 zlell = zlell - zlecs + len; 295 zlecs = len; 296 zsfree(x); 297 if (len) 298 free(y); 299 fixsuffix(); 300 menucmp = 0; 301} 302 303/**/ 304static char * 305get_lbuffer(UNUSED(Param pm)) 306{ 307 if (zlemetaline != NULL) 308 return dupstrpfx(zlemetaline, zlemetacs); 309 return zlelineasstring(zleline, zlecs, 0, NULL, NULL, 1); 310} 311 312/**/ 313static void 314set_rbuffer(UNUSED(Param pm), char *x) 315{ 316 ZLE_STRING_T y; 317 int len; 318 319 if (x && *x != ZWC('\0')) 320 y = stringaszleline(x, 0, &len, NULL, NULL); 321 else 322 y = ZWS(""), len = 0; 323 sizeline(zlell = zlecs + len); 324 ZS_memcpy(zleline + zlecs, y, len); 325 zsfree(x); 326 if (len) 327 free(y); 328 fixsuffix(); 329 menucmp = 0; 330} 331 332/**/ 333static char * 334get_rbuffer(UNUSED(Param pm)) 335{ 336 if (zlemetaline != NULL) 337 return dupstrpfx((char *)zlemetaline + zlemetacs, 338 zlemetall - zlemetacs); 339 return zlelineasstring(zleline + zlecs, zlell - zlecs, 0, NULL, NULL, 1); 340} 341 342/**/ 343static char * 344get_prebuffer(UNUSED(Param pm)) 345{ 346 /* 347 * Use the editing current history line, not necessarily the 348 * history line that's currently in the history mechanism 349 * since our line may have been stacked. 350 */ 351 if (zle_chline) { 352 /* zle_chline was NULL terminated when pushed onto the stack */ 353 return dupstring(zle_chline); 354 } 355 if (chline) { 356 /* hptr is valid */ 357 return dupstrpfx(chline, hptr - chline); 358 } 359 return dupstring(""); 360} 361 362/**/ 363static char * 364get_widget(UNUSED(Param pm)) 365{ 366 return bindk->nam; 367} 368 369/**/ 370static char * 371get_widgetfunc(UNUSED(Param pm)) 372{ 373 Widget widget = bindk->widget; 374 int flags = widget->flags; 375 376 if (flags & WIDGET_INT) 377 return ".internal"; /* Don't see how this can ever be returned... */ 378 if (flags & WIDGET_NCOMP) 379 return widget->u.comp.func; 380 return widget->u.fnnam; 381} 382 383/**/ 384static char * 385get_widgetstyle(UNUSED(Param pm)) 386{ 387 Widget widget = bindk->widget; 388 int flags = widget->flags; 389 390 if (flags & WIDGET_INT) 391 return ".internal"; /* Don't see how this can ever be returned... */ 392 if (flags & WIDGET_NCOMP) 393 return widget->u.comp.wid; 394 return ""; 395} 396 397/**/ 398static char * 399get_lwidget(UNUSED(Param pm)) 400{ 401 return (lbindk ? lbindk->nam : ""); 402} 403 404/**/ 405static char * 406get_keymap(UNUSED(Param pm)) 407{ 408 return dupstring(curkeymapname); 409} 410 411/**/ 412static char * 413get_keys(UNUSED(Param pm)) 414{ 415 return keybuf; 416} 417 418/**/ 419static void 420set_numeric(UNUSED(Param pm), zlong x) 421{ 422 zmult = x; 423 zmod.flags = MOD_MULT; 424} 425 426/**/ 427static zlong 428get_numeric(UNUSED(Param pm)) 429{ 430 return zmult; 431} 432 433/**/ 434static void 435unset_numeric(Param pm, int exp) 436{ 437 if (exp) { 438 stdunsetfn(pm, exp); 439 zmod.flags = 0; 440 zmult = 1; 441 } 442} 443 444/**/ 445static void 446set_histno(UNUSED(Param pm), zlong x) 447{ 448 Histent he; 449 450 if (!(he = quietgethist((int)x))) 451 return; 452 zle_setline(he); 453} 454 455/**/ 456static zlong 457get_histno(UNUSED(Param pm)) 458{ 459 return histline; 460} 461 462/**/ 463static zlong 464get_bufferlines(UNUSED(Param pm)) 465{ 466 return nlnct; 467} 468 469/**/ 470static zlong 471get_pending(UNUSED(Param pm)) 472{ 473 return noquery(0); 474} 475 476/**/ 477static char * 478get_cutbuffer(UNUSED(Param pm)) 479{ 480 if (cutbuf.buf) 481 return zlelineasstring(cutbuf.buf, cutbuf.len, 0, NULL, NULL, 1); 482 return ""; 483} 484 485 486/**/ 487static void 488set_cutbuffer(UNUSED(Param pm), char *x) 489{ 490 if (cutbuf.buf) 491 free(cutbuf.buf); 492 cutbuf.flags = 0; 493 if (x) { 494 int n; 495 cutbuf.buf = stringaszleline(x, 0, &n, NULL, NULL); 496 cutbuf.len = n; 497 free(x); 498 } else { 499 cutbuf.buf = NULL; 500 cutbuf.len = 0; 501 } 502} 503 504/**/ 505static void 506unset_cutbuffer(Param pm, int exp) 507{ 508 if (exp) { 509 stdunsetfn(pm, exp); 510 if (cutbuf.buf) { 511 free(cutbuf.buf); 512 cutbuf.buf = NULL; 513 cutbuf.len = 0; 514 } 515 } 516} 517 518/**/ 519static void 520set_killring(UNUSED(Param pm), char **x) 521{ 522 int kcnt; 523 Cutbuffer kptr; 524 char **p; 525 526 if (kring) { 527 for (kptr = kring, kcnt = 0; kcnt < kringsize; kcnt++, kptr++) 528 if (kptr->buf) 529 free(kptr->buf); 530 zfree(kring, kringsize * sizeof(struct cutbuffer)); 531 kring = NULL; 532 kringsize = kringnum = 0; 533 } 534 if (x) { 535 /* 536 * Insert the elements into the kill ring. 537 * Regardless of the old order, we number it with the current 538 * entry first. 539 * 540 * Be careful to add elements by looping backwards; this 541 * fits in with how we cycle the ring. 542 */ 543 int kpos = 0; 544 kringsize = arrlen(x); 545 if (kringsize != 0) { 546 kring = (Cutbuffer)zshcalloc(kringsize * sizeof(struct cutbuffer)); 547 for (p = x; *p; p++) { 548 int n, len = strlen(*p); 549 kptr = kring + kpos; 550 551 kptr->buf = stringaszleline(*p, 0, &n, NULL, NULL); 552 kptr->len = n; 553 554 zfree(*p, len+1); 555 kpos = (kpos + kringsize -1 ) % kringsize; 556 } 557 } 558 free(x); 559 } 560} 561 562/**/ 563static char ** 564get_killring(UNUSED(Param pm)) 565{ 566 /* 567 * Return the kill ring with the most recently killed first. 568 * Since the kill ring is no longer a fixed length, we return 569 * all entries even if empty. 570 */ 571 int kpos, kcnt; 572 char **ret, **p; 573 574 /* Supposed to work even if kring is NULL */ 575 if (!kring) { 576 kringsize = KRINGCTDEF; 577 kring = (Cutbuffer)zshcalloc(kringsize * sizeof(struct cutbuffer)); 578 } 579 580 p = ret = (char **)zhalloc((kringsize+1) * sizeof(char *)); 581 582 for (kpos = kringnum, kcnt = 0; kcnt < kringsize; kcnt++) { 583 Cutbuffer kptr = kring + kpos; 584 if (kptr->buf) 585 { 586 /* Allocate on heap. */ 587 *p++ = zlelineasstring(kptr->buf, kptr->len, 0, NULL, NULL, 1); 588 } 589 else 590 *p++ = dupstring(""); 591 kpos = (kpos + kringsize - 1) % kringsize; 592 } 593 *p = NULL; 594 595 return ret; 596} 597 598/**/ 599static void 600unset_killring(Param pm, int exp) 601{ 602 if (exp) { 603 set_killring(pm, NULL); 604 stdunsetfn(pm, exp); 605 } 606} 607 608static void 609set_prepost(ZLE_STRING_T *textvar, int *lenvar, char *x) 610{ 611 if (*lenvar) { 612 free(*textvar); 613 *textvar = NULL; 614 *lenvar = 0; 615 } 616 if (x) { 617 *textvar = stringaszleline(x, 0, lenvar, NULL, NULL); 618 free(x); 619 } 620} 621 622static char * 623get_prepost(ZLE_STRING_T text, int len) 624{ 625 return zlelineasstring(text, len, 0, NULL, NULL, 1); 626} 627 628/**/ 629static void 630set_predisplay(UNUSED(Param pm), char *x) 631{ 632 set_prepost(&predisplay, &predisplaylen, x); 633} 634 635/**/ 636static char * 637get_predisplay(UNUSED(Param pm)) 638{ 639 return get_prepost(predisplay, predisplaylen); 640} 641 642/**/ 643static void 644set_postdisplay(UNUSED(Param pm), char *x) 645{ 646 set_prepost(&postdisplay, &postdisplaylen, x); 647} 648 649/**/ 650static char * 651get_postdisplay(UNUSED(Param pm)) 652{ 653 return get_prepost(postdisplay, postdisplaylen); 654} 655 656/**/ 657void 658free_prepostdisplay(void) 659{ 660 if (predisplaylen) 661 set_prepost(&predisplay, &predisplaylen, NULL); 662 if (postdisplaylen) 663 set_prepost(&postdisplay, &postdisplaylen, NULL); 664} 665 666/**/ 667static char * 668get_lasearch(UNUSED(Param pm)) 669{ 670 if (previous_aborted_search) 671 return previous_aborted_search; 672 return ""; 673} 674 675/**/ 676static char * 677get_lsearch(UNUSED(Param pm)) 678{ 679 if (previous_search) 680 return previous_search; 681 return ""; 682} 683 684/**/ 685static char * 686get_context(UNUSED(Param pm)) 687{ 688 switch (zlecontext) { 689 case ZLCON_LINE_CONT: 690 return "cont"; 691 break; 692 693 case ZLCON_SELECT: 694 return "select"; 695 break; 696 697 case ZLCON_VARED: 698 return "vared"; 699 break; 700 701 case ZLCON_LINE_START: 702 default: 703 return "start"; 704 break; 705 } 706} 707 708/**/ 709static char * 710get_zle_state(UNUSED(Param pm)) 711{ 712 char *zle_state = NULL, *ptr = NULL, **arr = NULL; 713 int itp, istate, len = 0; 714 715 /* 716 * Substrings are sorted at the end, so the user can 717 * easily match against this parameter: 718 * if [[ $ZLE_STATE == *bar*foo*zonk* ]]; then ...; fi 719 */ 720 for (itp = 0; itp < 2; itp++) { 721 char *str; 722 for (istate = 0; istate < 2; istate++) { 723 int slen; 724 switch (istate) { 725 case 0: 726 if (insmode) { 727 str = "insert"; 728 } else { 729 str = "overwrite"; 730 } 731 break; 732 case 1: 733 if (hist_skip_flags & HIST_FOREIGN) { 734 str = "localhistory"; 735 } else { 736 str = "globalhistory"; 737 } 738 break; 739 740 default: 741 str = ""; 742 } 743 slen = strlen(str); 744 if (itp == 0) { 745 /* Accumulating length */ 746 if (istate) 747 len++; /* for space */ 748 len += slen; 749 } else { 750 /* Accumulating string */ 751 if (istate) 752 *ptr++ = ':'; 753 memcpy(ptr, str, slen); 754 ptr += slen; 755 } 756 } 757 if (itp == 0) { 758 len++; /* terminating NULL */ 759 ptr = zle_state = (char *)zhalloc(len); 760 } else { 761 *ptr = '\0'; 762 } 763 } 764 765 arr = colonsplit(zle_state, 0); 766 strmetasort(arr, SORTIT_ANYOLDHOW, NULL); 767 zle_state = zjoin(arr, ' ', 1); 768 freearray(arr); 769 770 return zle_state; 771} 772