1/* $NetBSD: chared.c,v 1.63 2022/10/30 19:11:31 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.63 2022/10/30 19:11:31 christos Exp $"); 41#endif 42#endif /* not lint && not SCCSID */ 43 44/* 45 * chared.c: Character editor utilities 46 */ 47#include <ctype.h> 48#include <stdlib.h> 49#include <string.h> 50 51#include "el.h" 52#include "common.h" 53#include "fcns.h" 54 55/* value to leave unused in line buffer */ 56#define EL_LEAVE 2 57 58/* cv_undo(): 59 * Handle state for the vi undo command 60 */ 61libedit_private void 62cv_undo(EditLine *el) 63{ 64 c_undo_t *vu = &el->el_chared.c_undo; 65 c_redo_t *r = &el->el_chared.c_redo; 66 size_t size; 67 68 /* Save entire line for undo */ 69 size = (size_t)(el->el_line.lastchar - el->el_line.buffer); 70 vu->len = (ssize_t)size; 71 vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer); 72 (void)memcpy(vu->buf, el->el_line.buffer, size * sizeof(*vu->buf)); 73 74 /* save command info for redo */ 75 r->count = el->el_state.doingarg ? el->el_state.argument : 0; 76 r->action = el->el_chared.c_vcmd.action; 77 r->pos = r->buf; 78 r->cmd = el->el_state.thiscmd; 79 r->ch = el->el_state.thisch; 80} 81 82/* cv_yank(): 83 * Save yank/delete data for paste 84 */ 85libedit_private void 86cv_yank(EditLine *el, const wchar_t *ptr, int size) 87{ 88 c_kill_t *k = &el->el_chared.c_kill; 89 90 (void)memcpy(k->buf, ptr, (size_t)size * sizeof(*k->buf)); 91 k->last = k->buf + size; 92} 93 94 95/* c_insert(): 96 * Insert num characters 97 */ 98libedit_private void 99c_insert(EditLine *el, int num) 100{ 101 wchar_t *cp; 102 103 if (el->el_line.lastchar + num >= el->el_line.limit) { 104 if (!ch_enlargebufs(el, (size_t)num)) 105 return; /* can't go past end of buffer */ 106 } 107 108 if (el->el_line.cursor < el->el_line.lastchar) { 109 /* if I must move chars */ 110 for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--) 111 cp[num] = *cp; 112 } 113 el->el_line.lastchar += num; 114} 115 116 117/* c_delafter(): 118 * Delete num characters after the cursor 119 */ 120libedit_private void 121c_delafter(EditLine *el, int num) 122{ 123 124 if (el->el_line.cursor + num > el->el_line.lastchar) 125 num = (int)(el->el_line.lastchar - el->el_line.cursor); 126 127 if (el->el_map.current != el->el_map.emacs) { 128 cv_undo(el); 129 cv_yank(el, el->el_line.cursor, num); 130 } 131 132 if (num > 0) { 133 wchar_t *cp; 134 135 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) 136 *cp = cp[num]; 137 138 el->el_line.lastchar -= num; 139 } 140} 141 142 143/* c_delafter1(): 144 * Delete the character after the cursor, do not yank 145 */ 146libedit_private void 147c_delafter1(EditLine *el) 148{ 149 wchar_t *cp; 150 151 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) 152 *cp = cp[1]; 153 154 el->el_line.lastchar--; 155} 156 157 158/* c_delbefore(): 159 * Delete num characters before the cursor 160 */ 161libedit_private void 162c_delbefore(EditLine *el, int num) 163{ 164 165 if (el->el_line.cursor - num < el->el_line.buffer) 166 num = (int)(el->el_line.cursor - el->el_line.buffer); 167 168 if (el->el_map.current != el->el_map.emacs) { 169 cv_undo(el); 170 cv_yank(el, el->el_line.cursor - num, num); 171 } 172 173 if (num > 0) { 174 wchar_t *cp; 175 176 for (cp = el->el_line.cursor - num; 177 &cp[num] <= el->el_line.lastchar; 178 cp++) 179 *cp = cp[num]; 180 181 el->el_line.lastchar -= num; 182 } 183} 184 185 186/* c_delbefore1(): 187 * Delete the character before the cursor, do not yank 188 */ 189libedit_private void 190c_delbefore1(EditLine *el) 191{ 192 wchar_t *cp; 193 194 for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++) 195 *cp = cp[1]; 196 197 el->el_line.lastchar--; 198} 199 200 201/* ce__isword(): 202 * Return if p is part of a word according to emacs 203 */ 204libedit_private int 205ce__isword(wint_t p) 206{ 207 return iswalnum(p) || wcschr(L"*?_-.[]~=", p) != NULL; 208} 209 210 211/* cv__isword(): 212 * Return if p is part of a word according to vi 213 */ 214libedit_private int 215cv__isword(wint_t p) 216{ 217 if (iswalnum(p) || p == L'_') 218 return 1; 219 if (iswgraph(p)) 220 return 2; 221 return 0; 222} 223 224 225/* cv__isWord(): 226 * Return if p is part of a big word according to vi 227 */ 228libedit_private int 229cv__isWord(wint_t p) 230{ 231 return !iswspace(p); 232} 233 234 235/* c__prev_word(): 236 * Find the previous word 237 */ 238libedit_private wchar_t * 239c__prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t)) 240{ 241 p--; 242 243 while (n--) { 244 while ((p >= low) && !(*wtest)(*p)) 245 p--; 246 while ((p >= low) && (*wtest)(*p)) 247 p--; 248 } 249 250 /* cp now points to one character before the word */ 251 p++; 252 if (p < low) 253 p = low; 254 /* cp now points where we want it */ 255 return p; 256} 257 258 259/* c__next_word(): 260 * Find the next word 261 */ 262libedit_private wchar_t * 263c__next_word(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t)) 264{ 265 while (n--) { 266 while ((p < high) && !(*wtest)(*p)) 267 p++; 268 while ((p < high) && (*wtest)(*p)) 269 p++; 270 } 271 if (p > high) 272 p = high; 273 /* p now points where we want it */ 274 return p; 275} 276 277/* cv_next_word(): 278 * Find the next word vi style 279 */ 280libedit_private wchar_t * 281cv_next_word(EditLine *el, wchar_t *p, wchar_t *high, int n, 282 int (*wtest)(wint_t)) 283{ 284 int test; 285 286 while (n--) { 287 test = (*wtest)(*p); 288 while ((p < high) && (*wtest)(*p) == test) 289 p++; 290 /* 291 * vi historically deletes with cw only the word preserving the 292 * trailing whitespace! This is not what 'w' does.. 293 */ 294 if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT)) 295 while ((p < high) && iswspace(*p)) 296 p++; 297 } 298 299 /* p now points where we want it */ 300 if (p > high) 301 return high; 302 else 303 return p; 304} 305 306 307/* cv_prev_word(): 308 * Find the previous word vi style 309 */ 310libedit_private wchar_t * 311cv_prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t)) 312{ 313 int test; 314 315 p--; 316 while (n--) { 317 while ((p > low) && iswspace(*p)) 318 p--; 319 test = (*wtest)(*p); 320 while ((p >= low) && (*wtest)(*p) == test) 321 p--; 322 } 323 p++; 324 325 /* p now points where we want it */ 326 if (p < low) 327 return low; 328 else 329 return p; 330} 331 332 333/* cv_delfini(): 334 * Finish vi delete action 335 */ 336libedit_private void 337cv_delfini(EditLine *el) 338{ 339 int size; 340 int action = el->el_chared.c_vcmd.action; 341 342 if (action & INSERT) 343 el->el_map.current = el->el_map.key; 344 345 if (el->el_chared.c_vcmd.pos == 0) 346 /* sanity */ 347 return; 348 349 size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos); 350 if (size == 0) 351 size = 1; 352 el->el_line.cursor = el->el_chared.c_vcmd.pos; 353 if (action & YANK) { 354 if (size > 0) 355 cv_yank(el, el->el_line.cursor, size); 356 else 357 cv_yank(el, el->el_line.cursor + size, -size); 358 } else { 359 if (size > 0) { 360 c_delafter(el, size); 361 re_refresh_cursor(el); 362 } else { 363 c_delbefore(el, -size); 364 el->el_line.cursor += size; 365 } 366 } 367 el->el_chared.c_vcmd.action = NOP; 368} 369 370 371/* cv__endword(): 372 * Go to the end of this word according to vi 373 */ 374libedit_private wchar_t * 375cv__endword(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t)) 376{ 377 int test; 378 379 p++; 380 381 while (n--) { 382 while ((p < high) && iswspace(*p)) 383 p++; 384 385 test = (*wtest)(*p); 386 while ((p < high) && (*wtest)(*p) == test) 387 p++; 388 } 389 p--; 390 return p; 391} 392 393/* ch_init(): 394 * Initialize the character editor 395 */ 396libedit_private int 397ch_init(EditLine *el) 398{ 399 el->el_line.buffer = el_calloc(EL_BUFSIZ, 400 sizeof(*el->el_line.buffer)); 401 if (el->el_line.buffer == NULL) 402 return -1; 403 404 el->el_line.cursor = el->el_line.buffer; 405 el->el_line.lastchar = el->el_line.buffer; 406 el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE]; 407 408 el->el_chared.c_undo.buf = el_calloc(EL_BUFSIZ, 409 sizeof(*el->el_chared.c_undo.buf)); 410 if (el->el_chared.c_undo.buf == NULL) 411 return -1; 412 el->el_chared.c_undo.len = -1; 413 el->el_chared.c_undo.cursor = 0; 414 el->el_chared.c_redo.buf = el_calloc(EL_BUFSIZ, 415 sizeof(*el->el_chared.c_redo.buf)); 416 if (el->el_chared.c_redo.buf == NULL) 417 goto out; 418 el->el_chared.c_redo.pos = el->el_chared.c_redo.buf; 419 el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ; 420 el->el_chared.c_redo.cmd = ED_UNASSIGNED; 421 422 el->el_chared.c_vcmd.action = NOP; 423 el->el_chared.c_vcmd.pos = el->el_line.buffer; 424 425 el->el_chared.c_kill.buf = el_calloc(EL_BUFSIZ, 426 sizeof(*el->el_chared.c_kill.buf)); 427 if (el->el_chared.c_kill.buf == NULL) 428 goto out; 429 el->el_chared.c_kill.mark = el->el_line.buffer; 430 el->el_chared.c_kill.last = el->el_chared.c_kill.buf; 431 el->el_chared.c_resizefun = NULL; 432 el->el_chared.c_resizearg = NULL; 433 el->el_chared.c_aliasfun = NULL; 434 el->el_chared.c_aliasarg = NULL; 435 436 el->el_map.current = el->el_map.key; 437 438 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ 439 el->el_state.doingarg = 0; 440 el->el_state.metanext = 0; 441 el->el_state.argument = 1; 442 el->el_state.lastcmd = ED_UNASSIGNED; 443 444 return 0; 445out: 446 ch_end(el); 447 return -1; 448} 449 450/* ch_reset(): 451 * Reset the character editor 452 */ 453libedit_private void 454ch_reset(EditLine *el) 455{ 456 el->el_line.cursor = el->el_line.buffer; 457 el->el_line.lastchar = el->el_line.buffer; 458 459 el->el_chared.c_undo.len = -1; 460 el->el_chared.c_undo.cursor = 0; 461 462 el->el_chared.c_vcmd.action = NOP; 463 el->el_chared.c_vcmd.pos = el->el_line.buffer; 464 465 el->el_chared.c_kill.mark = el->el_line.buffer; 466 467 el->el_map.current = el->el_map.key; 468 469 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ 470 el->el_state.doingarg = 0; 471 el->el_state.metanext = 0; 472 el->el_state.argument = 1; 473 el->el_state.lastcmd = ED_UNASSIGNED; 474 475 el->el_history.eventno = 0; 476} 477 478/* ch_enlargebufs(): 479 * Enlarge line buffer to be able to hold twice as much characters. 480 * Returns 1 if successful, 0 if not. 481 */ 482libedit_private int 483ch_enlargebufs(EditLine *el, size_t addlen) 484{ 485 size_t sz, newsz; 486 wchar_t *newbuffer, *oldbuf, *oldkbuf; 487 488 sz = (size_t)(el->el_line.limit - el->el_line.buffer + EL_LEAVE); 489 newsz = sz * 2; 490 /* 491 * If newly required length is longer than current buffer, we need 492 * to make the buffer big enough to hold both old and new stuff. 493 */ 494 if (addlen > sz) { 495 while(newsz - sz < addlen) 496 newsz *= 2; 497 } 498 499 /* 500 * Reallocate line buffer. 501 */ 502 newbuffer = el_realloc(el->el_line.buffer, newsz * sizeof(*newbuffer)); 503 if (!newbuffer) 504 return 0; 505 506 /* zero the newly added memory, leave old data in */ 507 (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); 508 509 oldbuf = el->el_line.buffer; 510 511 el->el_line.buffer = newbuffer; 512 el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf); 513 el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf); 514 /* don't set new size until all buffers are enlarged */ 515 el->el_line.limit = &newbuffer[sz - EL_LEAVE]; 516 517 /* 518 * Reallocate kill buffer. 519 */ 520 newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz * 521 sizeof(*newbuffer)); 522 if (!newbuffer) 523 return 0; 524 525 /* zero the newly added memory, leave old data in */ 526 (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); 527 528 oldkbuf = el->el_chared.c_kill.buf; 529 530 el->el_chared.c_kill.buf = newbuffer; 531 el->el_chared.c_kill.last = newbuffer + 532 (el->el_chared.c_kill.last - oldkbuf); 533 el->el_chared.c_kill.mark = el->el_line.buffer + 534 (el->el_chared.c_kill.mark - oldbuf); 535 536 /* 537 * Reallocate undo buffer. 538 */ 539 newbuffer = el_realloc(el->el_chared.c_undo.buf, 540 newsz * sizeof(*newbuffer)); 541 if (!newbuffer) 542 return 0; 543 544 /* zero the newly added memory, leave old data in */ 545 (void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer)); 546 el->el_chared.c_undo.buf = newbuffer; 547 548 newbuffer = el_realloc(el->el_chared.c_redo.buf, 549 newsz * sizeof(*newbuffer)); 550 if (!newbuffer) 551 return 0; 552 el->el_chared.c_redo.pos = newbuffer + 553 (el->el_chared.c_redo.pos - el->el_chared.c_redo.buf); 554 el->el_chared.c_redo.lim = newbuffer + 555 (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf); 556 el->el_chared.c_redo.buf = newbuffer; 557 558 if (!hist_enlargebuf(el, sz, newsz)) 559 return 0; 560 561 /* Safe to set enlarged buffer size */ 562 el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE]; 563 if (el->el_chared.c_resizefun) 564 (*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg); 565 return 1; 566} 567 568/* ch_end(): 569 * Free the data structures used by the editor 570 */ 571libedit_private void 572ch_end(EditLine *el) 573{ 574 el_free(el->el_line.buffer); 575 el->el_line.buffer = NULL; 576 el->el_line.limit = NULL; 577 el_free(el->el_chared.c_undo.buf); 578 el->el_chared.c_undo.buf = NULL; 579 el_free(el->el_chared.c_redo.buf); 580 el->el_chared.c_redo.buf = NULL; 581 el->el_chared.c_redo.pos = NULL; 582 el->el_chared.c_redo.lim = NULL; 583 el->el_chared.c_redo.cmd = ED_UNASSIGNED; 584 el_free(el->el_chared.c_kill.buf); 585 el->el_chared.c_kill.buf = NULL; 586 ch_reset(el); 587} 588 589 590/* el_insertstr(): 591 * Insert string at cursor 592 */ 593int 594el_winsertstr(EditLine *el, const wchar_t *s) 595{ 596 size_t len; 597 598 if (s == NULL || (len = wcslen(s)) == 0) 599 return -1; 600 if (el->el_line.lastchar + len >= el->el_line.limit) { 601 if (!ch_enlargebufs(el, len)) 602 return -1; 603 } 604 605 c_insert(el, (int)len); 606 while (*s) 607 *el->el_line.cursor++ = *s++; 608 return 0; 609} 610 611 612/* el_deletestr(): 613 * Delete num characters before the cursor 614 */ 615void 616el_deletestr(EditLine *el, int n) 617{ 618 if (n <= 0) 619 return; 620 621 if (el->el_line.cursor < &el->el_line.buffer[n]) 622 return; 623 624 c_delbefore(el, n); /* delete before dot */ 625 el->el_line.cursor -= n; 626 if (el->el_line.cursor < el->el_line.buffer) 627 el->el_line.cursor = el->el_line.buffer; 628} 629 630/* el_deletestr1(): 631 * Delete characters between start and end 632 */ 633int 634el_deletestr1(EditLine *el, int start, int end) 635{ 636 size_t line_length, len; 637 wchar_t *p1, *p2; 638 639 if (end <= start) 640 return 0; 641 642 line_length = (size_t)(el->el_line.lastchar - el->el_line.buffer); 643 644 if (start >= (int)line_length || end >= (int)line_length) 645 return 0; 646 647 len = (size_t)(end - start); 648 if (len > line_length - (size_t)end) 649 len = line_length - (size_t)end; 650 651 p1 = el->el_line.buffer + start; 652 p2 = el->el_line.buffer + end; 653 for (size_t i = 0; i < len; i++) { 654 *p1++ = *p2++; 655 el->el_line.lastchar--; 656 } 657 658 if (el->el_line.cursor < el->el_line.buffer) 659 el->el_line.cursor = el->el_line.buffer; 660 661 return end - start; 662} 663 664/* el_wreplacestr(): 665 * Replace the contents of the line with the provided string 666 */ 667int 668el_wreplacestr(EditLine *el, const wchar_t *s) 669{ 670 size_t len; 671 wchar_t * p; 672 673 if (s == NULL || (len = wcslen(s)) == 0) 674 return -1; 675 676 if (el->el_line.buffer + len >= el->el_line.limit) { 677 if (!ch_enlargebufs(el, len)) 678 return -1; 679 } 680 681 p = el->el_line.buffer; 682 for (size_t i = 0; i < len; i++) 683 *p++ = *s++; 684 685 el->el_line.buffer[len] = '\0'; 686 el->el_line.lastchar = el->el_line.buffer + len; 687 if (el->el_line.cursor > el->el_line.lastchar) 688 el->el_line.cursor = el->el_line.lastchar; 689 690 return 0; 691} 692 693/* el_cursor(): 694 * Move the cursor to the left or the right of the current position 695 */ 696int 697el_cursor(EditLine *el, int n) 698{ 699 if (n == 0) 700 goto out; 701 702 el->el_line.cursor += n; 703 704 if (el->el_line.cursor < el->el_line.buffer) 705 el->el_line.cursor = el->el_line.buffer; 706 if (el->el_line.cursor > el->el_line.lastchar) 707 el->el_line.cursor = el->el_line.lastchar; 708out: 709 return (int)(el->el_line.cursor - el->el_line.buffer); 710} 711 712/* c_gets(): 713 * Get a string 714 */ 715libedit_private int 716c_gets(EditLine *el, wchar_t *buf, const wchar_t *prompt) 717{ 718 ssize_t len; 719 wchar_t *cp = el->el_line.buffer, ch; 720 721 if (prompt) { 722 len = (ssize_t)wcslen(prompt); 723 (void)memcpy(cp, prompt, (size_t)len * sizeof(*cp)); 724 cp += len; 725 } 726 len = 0; 727 728 for (;;) { 729 el->el_line.cursor = cp; 730 *cp = ' '; 731 el->el_line.lastchar = cp + 1; 732 re_refresh(el); 733 734 if (el_wgetc(el, &ch) != 1) { 735 ed_end_of_file(el, 0); 736 len = -1; 737 break; 738 } 739 740 switch (ch) { 741 742 case L'\b': /* Delete and backspace */ 743 case 0177: 744 if (len == 0) { 745 len = -1; 746 break; 747 } 748 len--; 749 cp--; 750 continue; 751 752 case 0033: /* ESC */ 753 case L'\r': /* Newline */ 754 case L'\n': 755 buf[len] = ch; 756 break; 757 758 default: 759 if (len >= (ssize_t)(EL_BUFSIZ - 16)) 760 terminal_beep(el); 761 else { 762 buf[len++] = ch; 763 *cp++ = ch; 764 } 765 continue; 766 } 767 break; 768 } 769 770 el->el_line.buffer[0] = '\0'; 771 el->el_line.lastchar = el->el_line.buffer; 772 el->el_line.cursor = el->el_line.buffer; 773 return (int)len; 774} 775 776 777/* c_hpos(): 778 * Return the current horizontal position of the cursor 779 */ 780libedit_private int 781c_hpos(EditLine *el) 782{ 783 wchar_t *ptr; 784 785 /* 786 * Find how many characters till the beginning of this line. 787 */ 788 if (el->el_line.cursor == el->el_line.buffer) 789 return 0; 790 else { 791 for (ptr = el->el_line.cursor - 1; 792 ptr >= el->el_line.buffer && *ptr != '\n'; 793 ptr--) 794 continue; 795 return (int)(el->el_line.cursor - ptr - 1); 796 } 797} 798 799libedit_private int 800ch_resizefun(EditLine *el, el_zfunc_t f, void *a) 801{ 802 el->el_chared.c_resizefun = f; 803 el->el_chared.c_resizearg = a; 804 return 0; 805} 806 807libedit_private int 808ch_aliasfun(EditLine *el, el_afunc_t f, void *a) 809{ 810 el->el_chared.c_aliasfun = f; 811 el->el_chared.c_aliasarg = a; 812 return 0; 813} 814