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