1 /* $OpenBSD: chared.c,v 1.11 2011/07/07 05:40:42 okan Exp $ */ 2 /* $NetBSD: chared.c,v 1.28 2009/12/30 22:37:40 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Christos Zoulas of Cornell University. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "config.h" 37 38 /* 39 * chared.c: Character editor utilities 40 */ 41 #include <stdlib.h> 42 #include "el.h" 43 44 private void ch__clearmacro (EditLine *); 45 46 /* value to leave unused in line buffer */ 47 #define EL_LEAVE 2 48 49 /* cv_undo(): 50 * Handle state for the vi undo command 51 */ 52 protected void 53 cv_undo(EditLine *el) 54 { 55 c_undo_t *vu = &el->el_chared.c_undo; 56 c_redo_t *r = &el->el_chared.c_redo; 57 size_t size; 58 59 /* Save entire line for undo */ 60 size = el->el_line.lastchar - el->el_line.buffer; 61 vu->len = size; 62 vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer); 63 (void)memcpy(vu->buf, el->el_line.buffer, size * sizeof(*vu->buf)); 64 65 /* save command info for redo */ 66 r->count = el->el_state.doingarg ? el->el_state.argument : 0; 67 r->action = el->el_chared.c_vcmd.action; 68 r->pos = r->buf; 69 r->cmd = el->el_state.thiscmd; 70 r->ch = el->el_state.thisch; 71 } 72 73 /* cv_yank(): 74 * Save yank/delete data for paste 75 */ 76 protected void 77 cv_yank(EditLine *el, const Char *ptr, int size) 78 { 79 c_kill_t *k = &el->el_chared.c_kill; 80 81 (void)memcpy(k->buf, ptr, size * sizeof(*k->buf)); 82 k->last = k->buf + size; 83 } 84 85 86 /* c_insert(): 87 * Insert num characters 88 */ 89 protected void 90 c_insert(EditLine *el, int num) 91 { 92 Char *cp; 93 94 if (el->el_line.lastchar + num >= el->el_line.limit) { 95 if (!ch_enlargebufs(el, (size_t)num)) 96 return; /* can't go past end of buffer */ 97 } 98 99 if (el->el_line.cursor < el->el_line.lastchar) { 100 /* if I must move chars */ 101 for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--) 102 cp[num] = *cp; 103 } 104 el->el_line.lastchar += num; 105 } 106 107 108 /* c_delafter(): 109 * Delete num characters after the cursor 110 */ 111 protected void 112 c_delafter(EditLine *el, int num) 113 { 114 115 if (el->el_line.cursor + num > el->el_line.lastchar) 116 num = (int)(el->el_line.lastchar - el->el_line.cursor); 117 118 if (el->el_map.current != el->el_map.emacs) { 119 cv_undo(el); 120 cv_yank(el, el->el_line.cursor, num); 121 } 122 123 if (num > 0) { 124 Char *cp; 125 126 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) 127 *cp = cp[num]; 128 129 el->el_line.lastchar -= num; 130 } 131 } 132 133 134 /* c_delafter1(): 135 * Delete the character after the cursor, do not yank 136 */ 137 protected void 138 c_delafter1(EditLine *el) 139 { 140 Char *cp; 141 142 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) 143 *cp = cp[1]; 144 145 el->el_line.lastchar--; 146 } 147 148 149 /* c_delbefore(): 150 * Delete num characters before the cursor 151 */ 152 protected void 153 c_delbefore(EditLine *el, int num) 154 { 155 156 if (el->el_line.cursor - num < el->el_line.buffer) 157 num = (int)(el->el_line.cursor - el->el_line.buffer); 158 159 if (el->el_map.current != el->el_map.emacs) { 160 cv_undo(el); 161 cv_yank(el, el->el_line.cursor - num, num); 162 } 163 164 if (num > 0) { 165 Char *cp; 166 167 for (cp = el->el_line.cursor - num; 168 cp <= el->el_line.lastchar; 169 cp++) 170 *cp = cp[num]; 171 172 el->el_line.lastchar -= num; 173 } 174 } 175 176 177 /* c_delbefore1(): 178 * Delete the character before the cursor, do not yank 179 */ 180 protected void 181 c_delbefore1(EditLine *el) 182 { 183 Char *cp; 184 185 for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++) 186 *cp = cp[1]; 187 188 el->el_line.lastchar--; 189 } 190 191 192 /* ce__isword(): 193 * Return if p is part of a word according to emacs 194 */ 195 protected int 196 ce__isword(Int p) 197 { 198 return (Isalnum(p) || Strchr(STR("*?_-.[]~="), p) != NULL); 199 } 200 201 202 /* cv__isword(): 203 * Return if p is part of a word according to vi 204 */ 205 protected int 206 cv__isword(Int p) 207 { 208 if (Isalnum(p) || p == '_') 209 return 1; 210 if (Isgraph(p)) 211 return 2; 212 return 0; 213 } 214 215 216 /* cv__isWord(): 217 * Return if p is part of a big word according to vi 218 */ 219 protected int 220 cv__isWord(Int p) 221 { 222 return (!Isspace(p)); 223 } 224 225 226 /* c__prev_word(): 227 * Find the previous word 228 */ 229 protected Char * 230 c__prev_word(Char *p, Char *low, int n, int (*wtest)(Int)) 231 { 232 p--; 233 234 while (n--) { 235 while ((p >= low) && !(*wtest)(*p)) 236 p--; 237 while ((p >= low) && (*wtest)(*p)) 238 p--; 239 } 240 241 /* cp now points to one character before the word */ 242 p++; 243 if (p < low) 244 p = low; 245 /* cp now points where we want it */ 246 return (p); 247 } 248 249 250 /* c__next_word(): 251 * Find the next word 252 */ 253 protected Char * 254 c__next_word(Char *p, Char *high, int n, int (*wtest)(Int)) 255 { 256 while (n--) { 257 while ((p < high) && !(*wtest)(*p)) 258 p++; 259 while ((p < high) && (*wtest)(*p)) 260 p++; 261 } 262 if (p > high) 263 p = high; 264 /* p now points where we want it */ 265 return (p); 266 } 267 268 /* cv_next_word(): 269 * Find the next word vi style 270 */ 271 protected Char * 272 cv_next_word(EditLine *el, Char *p, Char *high, int n, int (*wtest)(Int)) 273 { 274 int test; 275 276 while (n--) { 277 test = (*wtest)(*p); 278 while ((p < high) && (*wtest)(*p) == test) 279 p++; 280 /* 281 * vi historically deletes with cw only the word preserving the 282 * trailing whitespace! This is not what 'w' does.. 283 */ 284 if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT)) 285 while ((p < high) && Isspace(*p)) 286 p++; 287 } 288 289 /* p now points where we want it */ 290 if (p > high) 291 return (high); 292 else 293 return (p); 294 } 295 296 297 /* cv_prev_word(): 298 * Find the previous word vi style 299 */ 300 protected Char * 301 cv_prev_word(Char *p, Char *low, int n, int (*wtest)(Int)) 302 { 303 int test; 304 305 p--; 306 while (n--) { 307 while ((p > low) && Isspace(*p)) 308 p--; 309 test = (*wtest)(*p); 310 while ((p >= low) && (*wtest)(*p) == test) 311 p--; 312 } 313 p++; 314 315 /* p now points where we want it */ 316 if (p < low) 317 return (low); 318 else 319 return (p); 320 } 321 322 323 #ifdef notdef 324 /* c__number(): 325 * Ignore character p points to, return number appearing after that. 326 * A '$' by itself means a big number; "$-" is for negative; '^' means 1. 327 * Return p pointing to last char used. 328 */ 329 protected Char * 330 c__number( 331 Char *p, /* character position */ 332 int *num, /* Return value */ 333 int dval) /* dval is the number to subtract from like $-3 */ 334 { 335 int i; 336 int sign = 1; 337 338 if (*++p == '^') { 339 *num = 1; 340 return (p); 341 } 342 if (*p == '$') { 343 if (*++p != '-') { 344 *num = 0x7fffffff; /* Handle $ */ 345 return (--p); 346 } 347 sign = -1; /* Handle $- */ 348 ++p; 349 } 350 /* XXX: this assumes ASCII compatible digits */ 351 for (i = 0; Isdigit(*p); i = 10 * i + *p++ - '0') 352 continue; 353 *num = (sign < 0 ? dval - i : i); 354 return (--p); 355 } 356 #endif 357 358 /* cv_delfini(): 359 * Finish vi delete action 360 */ 361 protected void 362 cv_delfini(EditLine *el) 363 { 364 int size; 365 int action = el->el_chared.c_vcmd.action; 366 367 if (action & INSERT) 368 el->el_map.current = el->el_map.key; 369 370 if (el->el_chared.c_vcmd.pos == 0) 371 /* sanity */ 372 return; 373 374 size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos); 375 if (size == 0) 376 size = 1; 377 el->el_line.cursor = el->el_chared.c_vcmd.pos; 378 if (action & YANK) { 379 if (size > 0) 380 cv_yank(el, el->el_line.cursor, size); 381 else 382 cv_yank(el, el->el_line.cursor + size, -size); 383 } else { 384 if (size > 0) { 385 c_delafter(el, size); 386 re_refresh_cursor(el); 387 } else { 388 c_delbefore(el, -size); 389 el->el_line.cursor += size; 390 } 391 } 392 el->el_chared.c_vcmd.action = NOP; 393 } 394 395 396 #ifdef notdef 397 /* ce__endword(): 398 * Go to the end of this word according to emacs 399 */ 400 protected Char * 401 ce__endword(Char *p, Char *high, int n) 402 { 403 p++; 404 405 while (n--) { 406 while ((p < high) && Isspace(*p)) 407 p++; 408 while ((p < high) && !Isspace(*p)) 409 p++; 410 } 411 412 p--; 413 return (p); 414 } 415 #endif 416 417 418 /* cv__endword(): 419 * Go to the end of this word according to vi 420 */ 421 protected Char * 422 cv__endword(Char *p, Char *high, int n, int (*wtest)(Int)) 423 { 424 int test; 425 426 p++; 427 428 while (n--) { 429 while ((p < high) && Isspace(*p)) 430 p++; 431 432 test = (*wtest)(*p); 433 while ((p < high) && (*wtest)(*p) == test) 434 p++; 435 } 436 p--; 437 return (p); 438 } 439 440 /* ch_init(): 441 * Initialize the character editor 442 */ 443 protected int 444 ch_init(EditLine *el) 445 { 446 c_macro_t *ma = &el->el_chared.c_macro; 447 448 el->el_line.buffer = el_malloc(EL_BUFSIZ * 449 sizeof(*el->el_line.buffer)); 450 if (el->el_line.buffer == NULL) 451 return (-1); 452 453 (void) memset(el->el_line.buffer, 0, EL_BUFSIZ * 454 sizeof(*el->el_line.buffer)); 455 el->el_line.cursor = el->el_line.buffer; 456 el->el_line.lastchar = el->el_line.buffer; 457 el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE]; 458 459 el->el_chared.c_undo.buf = el_malloc(EL_BUFSIZ * 460 sizeof(*el->el_chared.c_undo.buf)); 461 if (el->el_chared.c_undo.buf == NULL) 462 return (-1); 463 (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ * 464 sizeof(*el->el_chared.c_undo.buf)); 465 el->el_chared.c_undo.len = -1; 466 el->el_chared.c_undo.cursor = 0; 467 el->el_chared.c_redo.buf = el_malloc(EL_BUFSIZ * 468 sizeof(*el->el_chared.c_redo.buf)); 469 if (el->el_chared.c_redo.buf == NULL) 470 return (-1); 471 el->el_chared.c_redo.pos = el->el_chared.c_redo.buf; 472 el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ; 473 el->el_chared.c_redo.cmd = ED_UNASSIGNED; 474 475 el->el_chared.c_vcmd.action = NOP; 476 el->el_chared.c_vcmd.pos = el->el_line.buffer; 477 478 el->el_chared.c_kill.buf = el_malloc(EL_BUFSIZ * 479 sizeof(*el->el_chared.c_kill.buf)); 480 if (el->el_chared.c_kill.buf == NULL) 481 return (-1); 482 (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ * 483 sizeof(*el->el_chared.c_kill.buf)); 484 el->el_chared.c_kill.mark = el->el_line.buffer; 485 el->el_chared.c_kill.last = el->el_chared.c_kill.buf; 486 el->el_chared.c_resizefun = NULL; 487 el->el_chared.c_resizearg = NULL; 488 489 el->el_map.current = el->el_map.key; 490 491 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ 492 el->el_state.doingarg = 0; 493 el->el_state.metanext = 0; 494 el->el_state.argument = 1; 495 el->el_state.lastcmd = ED_UNASSIGNED; 496 497 ma->level = -1; 498 ma->offset = 0; 499 ma->macro = el_malloc(EL_MAXMACRO * sizeof(*ma->macro)); 500 if (ma->macro == NULL) 501 return (-1); 502 return (0); 503 } 504 505 /* ch_reset(): 506 * Reset the character editor 507 */ 508 protected void 509 ch_reset(EditLine *el, int mclear) 510 { 511 el->el_line.cursor = el->el_line.buffer; 512 el->el_line.lastchar = el->el_line.buffer; 513 514 el->el_chared.c_undo.len = -1; 515 el->el_chared.c_undo.cursor = 0; 516 517 el->el_chared.c_vcmd.action = NOP; 518 el->el_chared.c_vcmd.pos = el->el_line.buffer; 519 520 el->el_chared.c_kill.mark = el->el_line.buffer; 521 522 el->el_map.current = el->el_map.key; 523 524 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ 525 el->el_state.doingarg = 0; 526 el->el_state.metanext = 0; 527 el->el_state.argument = 1; 528 el->el_state.lastcmd = ED_UNASSIGNED; 529 530 el->el_history.eventno = 0; 531 532 if (mclear) 533 ch__clearmacro(el); 534 } 535 536 private void 537 ch__clearmacro(EditLine *el) 538 { 539 c_macro_t *ma = &el->el_chared.c_macro; 540 while (ma->level >= 0) 541 el_free((ptr_t)ma->macro[ma->level--]); 542 } 543 544 /* ch_enlargebufs(): 545 * Enlarge line buffer to be able to hold twice as much characters. 546 * Returns 1 if successful, 0 if not. 547 */ 548 protected int 549 ch_enlargebufs(EditLine *el, size_t addlen) 550 { 551 size_t sz, newsz; 552 Char *newbuffer, *oldbuf, *oldkbuf; 553 554 sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE; 555 newsz = sz * 2; 556 /* 557 * If newly required length is longer than current buffer, we need 558 * to make the buffer big enough to hold both old and new stuff. 559 */ 560 if (addlen > sz) { 561 while(newsz - sz < addlen) 562 newsz *= 2; 563 } 564 565 /* 566 * Reallocate line buffer. 567 */ 568 newbuffer = el_realloc(el->el_line.buffer, newsz * sizeof(*newbuffer)); 569 if (!newbuffer) 570 return 0; 571 572 /* zero the newly added memory, leave old data in */ 573 (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); 574 575 oldbuf = el->el_line.buffer; 576 577 el->el_line.buffer = newbuffer; 578 el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf); 579 el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf); 580 /* don't set new size until all buffers are enlarged */ 581 el->el_line.limit = &newbuffer[sz - EL_LEAVE]; 582 583 /* 584 * Reallocate kill buffer. 585 */ 586 newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz * sizeof(*newbuffer)); 587 if (!newbuffer) 588 return 0; 589 590 /* zero the newly added memory, leave old data in */ 591 (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); 592 593 oldkbuf = el->el_chared.c_kill.buf; 594 595 el->el_chared.c_kill.buf = newbuffer; 596 el->el_chared.c_kill.last = newbuffer + 597 (el->el_chared.c_kill.last - oldkbuf); 598 el->el_chared.c_kill.mark = el->el_line.buffer + 599 (el->el_chared.c_kill.mark - oldbuf); 600 601 /* 602 * Reallocate undo buffer. 603 */ 604 newbuffer = el_realloc(el->el_chared.c_undo.buf, 605 newsz * sizeof(*newbuffer)); 606 if (!newbuffer) 607 return 0; 608 609 /* zero the newly added memory, leave old data in */ 610 (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); 611 el->el_chared.c_undo.buf = newbuffer; 612 613 newbuffer = el_realloc(el->el_chared.c_redo.buf, 614 newsz * sizeof(*newbuffer)); 615 if (!newbuffer) 616 return 0; 617 el->el_chared.c_redo.pos = newbuffer + 618 (el->el_chared.c_redo.pos - el->el_chared.c_redo.buf); 619 el->el_chared.c_redo.lim = newbuffer + 620 (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf); 621 el->el_chared.c_redo.buf = newbuffer; 622 623 if (!hist_enlargebuf(el, sz, newsz)) 624 return 0; 625 626 /* Safe to set enlarged buffer size */ 627 el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE]; 628 if (el->el_chared.c_resizefun) 629 (*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg); 630 return 1; 631 } 632 633 /* ch_end(): 634 * Free the data structures used by the editor 635 */ 636 protected void 637 ch_end(EditLine *el) 638 { 639 el_free((ptr_t) el->el_line.buffer); 640 el->el_line.buffer = NULL; 641 el->el_line.limit = NULL; 642 el_free((ptr_t) el->el_chared.c_undo.buf); 643 el->el_chared.c_undo.buf = NULL; 644 el_free((ptr_t) el->el_chared.c_redo.buf); 645 el->el_chared.c_redo.buf = NULL; 646 el->el_chared.c_redo.pos = NULL; 647 el->el_chared.c_redo.lim = NULL; 648 el->el_chared.c_redo.cmd = ED_UNASSIGNED; 649 el_free((ptr_t) el->el_chared.c_kill.buf); 650 el->el_chared.c_kill.buf = NULL; 651 ch_reset(el, 1); 652 el_free((ptr_t) el->el_chared.c_macro.macro); 653 el->el_chared.c_macro.macro = NULL; 654 } 655 656 657 /* el_insertstr(): 658 * Insert string at cursorI 659 */ 660 public int 661 FUN(el,insertstr)(EditLine *el, const Char *s) 662 { 663 size_t len; 664 665 if ((len = Strlen(s)) == 0) 666 return (-1); 667 if (el->el_line.lastchar + len >= el->el_line.limit) { 668 if (!ch_enlargebufs(el, len)) 669 return (-1); 670 } 671 672 c_insert(el, (int)len); 673 while (*s) 674 *el->el_line.cursor++ = *s++; 675 return (0); 676 } 677 678 679 /* el_deletestr(): 680 * Delete num characters before the cursor 681 */ 682 public void 683 el_deletestr(EditLine *el, int n) 684 { 685 if (n <= 0) 686 return; 687 688 if (el->el_line.cursor < &el->el_line.buffer[n]) 689 return; 690 691 c_delbefore(el, n); /* delete before dot */ 692 el->el_line.cursor -= n; 693 if (el->el_line.cursor < el->el_line.buffer) 694 el->el_line.cursor = el->el_line.buffer; 695 } 696 697 /* c_gets(): 698 * Get a string 699 */ 700 protected int 701 c_gets(EditLine *el, Char *buf, const Char *prompt) 702 { 703 Char ch; 704 ssize_t len; 705 Char *cp = el->el_line.buffer; 706 707 if (prompt) { 708 len = Strlen(prompt); 709 (void)memcpy(cp, prompt, len * sizeof(*cp)); 710 cp += len; 711 } 712 len = 0; 713 714 for (;;) { 715 el->el_line.cursor = cp; 716 *cp = ' '; 717 el->el_line.lastchar = cp + 1; 718 re_refresh(el); 719 720 if (FUN(el,getc)(el, &ch) != 1) { 721 ed_end_of_file(el, 0); 722 len = -1; 723 break; 724 } 725 726 switch (ch) { 727 728 case 0010: /* Delete and backspace */ 729 case 0177: 730 if (len == 0) { 731 len = -1; 732 break; 733 } 734 cp--; 735 continue; 736 737 case 0033: /* ESC */ 738 case '\r': /* Newline */ 739 case '\n': 740 buf[len] = ch; 741 break; 742 743 default: 744 if (len >= EL_BUFSIZ - 16) 745 term_beep(el); 746 else { 747 buf[len++] = ch; 748 *cp++ = ch; 749 } 750 continue; 751 } 752 break; 753 } 754 755 el->el_line.buffer[0] = '\0'; 756 el->el_line.lastchar = el->el_line.buffer; 757 el->el_line.cursor = el->el_line.buffer; 758 return (int)len; 759 } 760 761 762 /* c_hpos(): 763 * Return the current horizontal position of the cursor 764 */ 765 protected int 766 c_hpos(EditLine *el) 767 { 768 Char *ptr; 769 770 /* 771 * Find how many characters till the beginning of this line. 772 */ 773 if (el->el_line.cursor == el->el_line.buffer) 774 return (0); 775 else { 776 for (ptr = el->el_line.cursor - 1; 777 ptr >= el->el_line.buffer && *ptr != '\n'; 778 ptr--) 779 continue; 780 return (int)(el->el_line.cursor - ptr - 1); 781 } 782 } 783 784 protected int 785 ch_resizefun(EditLine *el, el_zfunc_t f, void *a) 786 { 787 el->el_chared.c_resizefun = f; 788 el->el_chared.c_resizearg = a; 789 return 0; 790 } 791