2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $NetBSD: chared.c,v 1.27 2009/02/15 21:55:23 christos Exp $
35 #if !defined(lint) && !defined(SCCSID)
36 static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
37 #endif /* not lint && not SCCSID */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
42 * chared.c: Character editor utilities
49 private void ch__clearmacro(EditLine *);
51 /* value to leave unused in line buffer */
55 * Handle state for the vi undo command
60 c_undo_t *vu = &el->el_chared.c_undo;
61 c_redo_t *r = &el->el_chared.c_redo;
64 /* Save entire line for undo */
65 size = el->el_line.lastchar - el->el_line.buffer;
67 vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer);
68 memcpy(vu->buf, el->el_line.buffer, size);
70 /* save command info for redo */
71 r->count = el->el_state.doingarg ? el->el_state.argument : 0;
72 r->action = el->el_chared.c_vcmd.action;
74 r->cmd = el->el_state.thiscmd;
75 r->ch = el->el_state.thisch;
79 * Save yank/delete data for paste
82 cv_yank(EditLine *el, const char *ptr, int size)
84 c_kill_t *k = &el->el_chared.c_kill;
86 memcpy(k->buf, ptr, (size_t)size);
87 k->last = k->buf + size;
92 * Insert num characters
95 c_insert(EditLine *el, int num)
99 if (el->el_line.lastchar + num >= el->el_line.limit) {
100 if (!ch_enlargebufs(el, (size_t)num))
101 return; /* can't go past end of buffer */
104 if (el->el_line.cursor < el->el_line.lastchar) {
105 /* if I must move chars */
106 for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
109 el->el_line.lastchar += num;
114 * Delete num characters after the cursor
117 c_delafter(EditLine *el, int num)
120 if (el->el_line.cursor + num > el->el_line.lastchar)
121 num = (int)(el->el_line.lastchar - el->el_line.cursor);
123 if (el->el_map.current != el->el_map.emacs) {
125 cv_yank(el, el->el_line.cursor, num);
131 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
134 el->el_line.lastchar -= num;
140 * Delete the character after the cursor, do not yank
143 c_delafter1(EditLine *el)
147 for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
150 el->el_line.lastchar--;
155 * Delete num characters before the cursor
158 c_delbefore(EditLine *el, int num)
161 if (el->el_line.cursor - num < el->el_line.buffer)
162 num = (int)(el->el_line.cursor - el->el_line.buffer);
164 if (el->el_map.current != el->el_map.emacs) {
166 cv_yank(el, el->el_line.cursor - num, num);
172 for (cp = el->el_line.cursor - num;
173 cp <= el->el_line.lastchar;
177 el->el_line.lastchar -= num;
183 * Delete the character before the cursor, do not yank
186 c_delbefore1(EditLine *el)
190 for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
193 el->el_line.lastchar--;
198 * Return if p is part of a word according to emacs
203 return (isalnum(p) || strchr("*?_-.[]~=", p) != NULL);
208 * Return if p is part of a word according to vi
213 if (isalnum(p) || p == '_')
222 * Return if p is part of a big word according to vi
227 return (!isspace(p));
232 * Find the previous word
235 c__prev_word(char *p, char *low, int n, int (*wtest)(int))
240 while ((p >= low) && !(*wtest)((unsigned char) *p))
242 while ((p >= low) && (*wtest)((unsigned char) *p))
246 /* cp now points to one character before the word */
250 /* cp now points where we want it */
259 c__next_word(char *p, char *high, int n, int (*wtest)(int))
262 while ((p < high) && !(*wtest)((unsigned char) *p))
264 while ((p < high) && (*wtest)((unsigned char) *p))
269 /* p now points where we want it */
274 * Find the next word vi style
277 cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
282 test = (*wtest)((unsigned char) *p);
283 while ((p < high) && (*wtest)((unsigned char) *p) == test)
286 * vi historically deletes with cw only the word preserving the
287 * trailing whitespace! This is not what 'w' does..
289 if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
290 while ((p < high) && isspace((unsigned char) *p))
294 /* p now points where we want it */
303 * Find the previous word vi style
306 cv_prev_word(char *p, char *low, int n, int (*wtest)(int))
312 while ((p > low) && isspace((unsigned char) *p))
314 test = (*wtest)((unsigned char) *p);
315 while ((p >= low) && (*wtest)((unsigned char) *p) == test)
320 /* p now points where we want it */
330 * Ignore character p points to, return number appearing after that.
331 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
332 * Return p pointing to last char used.
336 char *p, /* character position */
337 int *num, /* Return value */
338 int dval) /* dval is the number to subtract from like $-3 */
349 *num = 0x7fffffff; /* Handle $ */
352 sign = -1; /* Handle $- */
355 for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
357 *num = (sign < 0 ? dval - i : i);
363 * Finish vi delete action
366 cv_delfini(EditLine *el)
369 int action = el->el_chared.c_vcmd.action;
372 el->el_map.current = el->el_map.key;
374 if (el->el_chared.c_vcmd.pos == 0)
378 size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos);
381 el->el_line.cursor = el->el_chared.c_vcmd.pos;
384 cv_yank(el, el->el_line.cursor, size);
386 cv_yank(el, el->el_line.cursor + size, -size);
389 c_delafter(el, size);
390 re_refresh_cursor(el);
392 c_delbefore(el, -size);
393 el->el_line.cursor += size;
396 el->el_chared.c_vcmd.action = NOP;
402 * Go to the end of this word according to emacs
405 ce__endword(char *p, char *high, int n)
410 while ((p < high) && isspace((unsigned char) *p))
412 while ((p < high) && !isspace((unsigned char) *p))
423 * Go to the end of this word according to vi
426 cv__endword(char *p, char *high, int n, int (*wtest)(int))
433 while ((p < high) && isspace((unsigned char) *p))
436 test = (*wtest)((unsigned char) *p);
437 while ((p < high) && (*wtest)((unsigned char) *p) == test)
445 * Initialize the character editor
448 ch_init(EditLine *el)
450 c_macro_t *ma = &el->el_chared.c_macro;
452 el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ);
453 if (el->el_line.buffer == NULL)
456 (void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
457 el->el_line.cursor = el->el_line.buffer;
458 el->el_line.lastchar = el->el_line.buffer;
459 el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
461 el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ);
462 if (el->el_chared.c_undo.buf == NULL)
464 (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
465 el->el_chared.c_undo.len = -1;
466 el->el_chared.c_undo.cursor = 0;
467 el->el_chared.c_redo.buf = (char *) el_malloc(EL_BUFSIZ);
468 if (el->el_chared.c_redo.buf == NULL)
470 el->el_chared.c_redo.pos = el->el_chared.c_redo.buf;
471 el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ;
472 el->el_chared.c_redo.cmd = ED_UNASSIGNED;
474 el->el_chared.c_vcmd.action = NOP;
475 el->el_chared.c_vcmd.pos = el->el_line.buffer;
477 el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ);
478 if (el->el_chared.c_kill.buf == NULL)
480 (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
481 el->el_chared.c_kill.mark = el->el_line.buffer;
482 el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
484 el->el_map.current = el->el_map.key;
486 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
487 el->el_state.doingarg = 0;
488 el->el_state.metanext = 0;
489 el->el_state.argument = 1;
490 el->el_state.lastcmd = ED_UNASSIGNED;
494 ma->macro = (char **) el_malloc(EL_MAXMACRO * sizeof(char *));
495 if (ma->macro == NULL)
501 * Reset the character editor
504 ch_reset(EditLine *el, int mclear)
506 el->el_line.cursor = el->el_line.buffer;
507 el->el_line.lastchar = el->el_line.buffer;
509 el->el_chared.c_undo.len = -1;
510 el->el_chared.c_undo.cursor = 0;
512 el->el_chared.c_vcmd.action = NOP;
513 el->el_chared.c_vcmd.pos = el->el_line.buffer;
515 el->el_chared.c_kill.mark = el->el_line.buffer;
517 el->el_map.current = el->el_map.key;
519 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
520 el->el_state.doingarg = 0;
521 el->el_state.metanext = 0;
522 el->el_state.argument = 1;
523 el->el_state.lastcmd = ED_UNASSIGNED;
525 el->el_history.eventno = 0;
532 ch__clearmacro(EditLine *el)
534 c_macro_t *ma = &el->el_chared.c_macro;
535 while (ma->level >= 0)
536 el_free((ptr_t)ma->macro[ma->level--]);
540 * Enlarge line buffer to be able to hold twice as much characters.
541 * Returns 1 if successful, 0 if not.
544 ch_enlargebufs(EditLine *el, size_t addlen)
547 char *newbuffer, *oldbuf, *oldkbuf;
549 sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
552 * If newly required length is longer than current buffer, we need
553 * to make the buffer big enough to hold both old and new stuff.
556 while(newsz - sz < addlen)
561 * Reallocate line buffer.
563 newbuffer = el_realloc(el->el_line.buffer, newsz);
567 /* zero the newly added memory, leave old data in */
568 (void) memset(&newbuffer[sz], 0, newsz - sz);
570 oldbuf = el->el_line.buffer;
572 el->el_line.buffer = newbuffer;
573 el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
574 el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
575 /* don't set new size until all buffers are enlarged */
576 el->el_line.limit = &newbuffer[sz - EL_LEAVE];
579 * Reallocate kill buffer.
581 newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
585 /* zero the newly added memory, leave old data in */
586 (void) memset(&newbuffer[sz], 0, newsz - sz);
588 oldkbuf = el->el_chared.c_kill.buf;
590 el->el_chared.c_kill.buf = newbuffer;
591 el->el_chared.c_kill.last = newbuffer +
592 (el->el_chared.c_kill.last - oldkbuf);
593 el->el_chared.c_kill.mark = el->el_line.buffer +
594 (el->el_chared.c_kill.mark - oldbuf);
597 * Reallocate undo buffer.
599 newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
603 /* zero the newly added memory, leave old data in */
604 (void) memset(&newbuffer[sz], 0, newsz - sz);
605 el->el_chared.c_undo.buf = newbuffer;
607 newbuffer = el_realloc(el->el_chared.c_redo.buf, newsz);
610 el->el_chared.c_redo.pos = newbuffer +
611 (el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
612 el->el_chared.c_redo.lim = newbuffer +
613 (el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
614 el->el_chared.c_redo.buf = newbuffer;
616 if (!hist_enlargebuf(el, sz, newsz))
619 /* Safe to set enlarged buffer size */
620 el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE];
625 * Free the data structures used by the editor
630 el_free((ptr_t) el->el_line.buffer);
631 el->el_line.buffer = NULL;
632 el->el_line.limit = NULL;
633 el_free((ptr_t) el->el_chared.c_undo.buf);
634 el->el_chared.c_undo.buf = NULL;
635 el_free((ptr_t) el->el_chared.c_redo.buf);
636 el->el_chared.c_redo.buf = NULL;
637 el->el_chared.c_redo.pos = NULL;
638 el->el_chared.c_redo.lim = NULL;
639 el->el_chared.c_redo.cmd = ED_UNASSIGNED;
640 el_free((ptr_t) el->el_chared.c_kill.buf);
641 el->el_chared.c_kill.buf = NULL;
643 el_free((ptr_t) el->el_chared.c_macro.macro);
644 el->el_chared.c_macro.macro = NULL;
649 * Insert string at cursorI
652 el_insertstr(EditLine *el, const char *s)
656 if ((len = strlen(s)) == 0)
658 if (el->el_line.lastchar + len >= el->el_line.limit) {
659 if (!ch_enlargebufs(el, len))
663 c_insert(el, (int)len);
665 *el->el_line.cursor++ = *s++;
671 * Delete num characters before the cursor
674 el_deletestr(EditLine *el, int n)
679 if (el->el_line.cursor < &el->el_line.buffer[n])
682 c_delbefore(el, n); /* delete before dot */
683 el->el_line.cursor -= n;
684 if (el->el_line.cursor < el->el_line.buffer)
685 el->el_line.cursor = el->el_line.buffer;
692 c_gets(EditLine *el, char *buf, const char *prompt)
696 char *cp = el->el_line.buffer;
699 len = strlen(prompt);
700 memcpy(cp, prompt, (size_t)len);
706 el->el_line.cursor = cp;
708 el->el_line.lastchar = cp + 1;
711 if (el_getc(el, &ch) != 1) {
712 ed_end_of_file(el, 0);
719 case '\010': /* Delete and backspace */
728 case '\033': /* ESC */
729 case '\r': /* Newline */
735 if (len >= EL_BUFSIZ - 16)
746 el->el_line.buffer[0] = '\0';
747 el->el_line.lastchar = el->el_line.buffer;
748 el->el_line.cursor = el->el_line.buffer;
754 * Return the current horizontal position of the cursor
762 * Find how many characters till the beginning of this line.
764 if (el->el_line.cursor == el->el_line.buffer)
767 for (ptr = el->el_line.cursor - 1;
768 ptr >= el->el_line.buffer && *ptr != '\n';
771 return (int)(el->el_line.cursor - ptr - 1);