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 * @(#)chared.c 8.1 (Berkeley) 6/4/93
33 * $NetBSD: chared.c,v 1.25 2005/08/08 01:41:30 christos Exp $
34 * $DragonFly: src/lib/libedit/chared.c,v 1.8 2007/05/05 00:27:39 pavalos Exp $
40 * chared.c: Character editor utilities
45 private void ch__clearmacro(EditLine
*);
47 /* value to leave unused in line buffer */
51 * Handle state for the vi undo command
56 c_undo_t
*vu
= &el
->el_chared
.c_undo
;
57 c_redo_t
*r
= &el
->el_chared
.c_redo
;
60 /* Save entire line for undo */
61 size
= el
->el_line
.lastchar
- el
->el_line
.buffer
;
63 vu
->cursor
= el
->el_line
.cursor
- el
->el_line
.buffer
;
64 memcpy(vu
->buf
, el
->el_line
.buffer
, size
);
66 /* save command info for redo */
67 r
->count
= el
->el_state
.doingarg
? el
->el_state
.argument
: 0;
68 r
->action
= el
->el_chared
.c_vcmd
.action
;
70 r
->cmd
= el
->el_state
.thiscmd
;
71 r
->ch
= el
->el_state
.thisch
;
75 * Save yank/delete data for paste
78 cv_yank(EditLine
*el
, const char *ptr
, int size
)
80 c_kill_t
*k
= &el
->el_chared
.c_kill
;
82 memcpy(k
->buf
, ptr
, size
+0u);
83 k
->last
= k
->buf
+ size
;
88 * Insert num characters
91 c_insert(EditLine
*el
, int num
)
95 if (el
->el_line
.lastchar
+ num
>= el
->el_line
.limit
) {
96 if (!ch_enlargebufs(el
, num
+0u))
97 return; /* can't go past end of buffer */
100 if (el
->el_line
.cursor
< el
->el_line
.lastchar
) {
101 /* if I must move chars */
102 for (cp
= el
->el_line
.lastchar
; cp
>= el
->el_line
.cursor
; cp
--)
105 el
->el_line
.lastchar
+= num
;
110 * Delete num characters after the cursor
113 c_delafter(EditLine
*el
, int num
)
116 if (el
->el_line
.cursor
+ num
> el
->el_line
.lastchar
)
117 num
= el
->el_line
.lastchar
- el
->el_line
.cursor
;
119 if (el
->el_map
.current
!= el
->el_map
.emacs
) {
121 cv_yank(el
, el
->el_line
.cursor
, num
);
127 for (cp
= el
->el_line
.cursor
; cp
<= el
->el_line
.lastchar
; cp
++)
130 el
->el_line
.lastchar
-= num
;
136 * Delete the character after the cursor, do not yank
139 c_delafter1(EditLine
*el
)
143 for (cp
= el
->el_line
.cursor
; cp
<= el
->el_line
.lastchar
; cp
++)
146 el
->el_line
.lastchar
--;
151 * Delete num characters before the cursor
154 c_delbefore(EditLine
*el
, int num
)
157 if (el
->el_line
.cursor
- num
< el
->el_line
.buffer
)
158 num
= el
->el_line
.cursor
- el
->el_line
.buffer
;
160 if (el
->el_map
.current
!= el
->el_map
.emacs
) {
162 cv_yank(el
, el
->el_line
.cursor
- num
, num
);
168 for (cp
= el
->el_line
.cursor
- num
;
169 cp
<= el
->el_line
.lastchar
;
173 el
->el_line
.lastchar
-= num
;
179 * Delete the character before the cursor, do not yank
182 c_delbefore1(EditLine
*el
)
186 for (cp
= el
->el_line
.cursor
- 1; cp
<= el
->el_line
.lastchar
; cp
++)
189 el
->el_line
.lastchar
--;
194 * Return if p is part of a word according to emacs
199 return (isalnum(p
) || strchr("*?_-.[]~=", p
) != NULL
);
204 * Return if p is part of a word according to vi
209 if (isalnum(p
) || p
== '_')
218 * Return if p is part of a big word according to vi
223 return (!isspace(p
));
228 * Find the previous word
231 c__prev_word(char *p
, char *low
, int n
, int (*wtest
)(int))
236 while ((p
>= low
) && !(*wtest
)((unsigned char) *p
))
238 while ((p
>= low
) && (*wtest
)((unsigned char) *p
))
242 /* cp now points to one character before the word */
246 /* cp now points where we want it */
255 c__next_word(char *p
, char *high
, int n
, int (*wtest
)(int))
258 while ((p
< high
) && !(*wtest
)((unsigned char) *p
))
260 while ((p
< high
) && (*wtest
)((unsigned char) *p
))
265 /* p now points where we want it */
270 * Find the next word vi style
273 cv_next_word(EditLine
*el
, char *p
, char *high
, int n
, int (*wtest
)(int))
278 test
= (*wtest
)((unsigned char) *p
);
279 while ((p
< high
) && (*wtest
)((unsigned char) *p
) == test
)
282 * vi historically deletes with cw only the word preserving the
283 * trailing whitespace! This is not what 'w' does..
285 if (n
|| el
->el_chared
.c_vcmd
.action
!= (DELETE
|INSERT
))
286 while ((p
< high
) && isspace((unsigned char) *p
))
290 /* p now points where we want it */
299 * Find the previous word vi style
302 cv_prev_word(char *p
, char *low
, int n
, int (*wtest
)(int))
308 while ((p
> low
) && isspace((unsigned char) *p
))
310 test
= (*wtest
)((unsigned char) *p
);
311 while ((p
>= low
) && (*wtest
)((unsigned char) *p
) == test
)
316 /* p now points where we want it */
326 * Ignore character p points to, return number appearing after that.
327 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
328 * Return p pointing to last char used.
332 char *p
, /* character position */
333 int *num
, /* Return value */
334 int dval
) /* dval is the number to subtract from like $-3 */
345 *num
= 0x7fffffff; /* Handle $ */
348 sign
= -1; /* Handle $- */
351 for (i
= 0; isdigit((unsigned char) *p
); i
= 10 * i
+ *p
++ - '0')
353 *num
= (sign
< 0 ? dval
- i
: i
);
359 * Finish vi delete action
362 cv_delfini(EditLine
*el
)
365 int action
= el
->el_chared
.c_vcmd
.action
;
368 el
->el_map
.current
= el
->el_map
.key
;
370 if (el
->el_chared
.c_vcmd
.pos
== 0)
374 size
= el
->el_line
.cursor
- el
->el_chared
.c_vcmd
.pos
;
377 el
->el_line
.cursor
= el
->el_chared
.c_vcmd
.pos
;
380 cv_yank(el
, el
->el_line
.cursor
, size
);
382 cv_yank(el
, el
->el_line
.cursor
+ size
, -size
);
385 c_delafter(el
, size
);
386 re_refresh_cursor(el
);
388 c_delbefore(el
, -size
);
389 el
->el_line
.cursor
+= size
;
392 el
->el_chared
.c_vcmd
.action
= NOP
;
398 * Go to the end of this word according to emacs
401 ce__endword(char *p
, char *high
, int n
)
406 while ((p
< high
) && isspace((unsigned char) *p
))
408 while ((p
< high
) && !isspace((unsigned char) *p
))
419 * Go to the end of this word according to vi
422 cv__endword(char *p
, char *high
, int n
, int (*wtest
)(int))
429 while ((p
< high
) && isspace((unsigned char) *p
))
432 test
= (*wtest
)((unsigned char) *p
);
433 while ((p
< high
) && (*wtest
)((unsigned char) *p
) == test
)
441 * Initialize the character editor
444 ch_init(EditLine
*el
)
446 c_macro_t
*ma
= &el
->el_chared
.c_macro
;
448 el
->el_line
.buffer
= (char *) el_malloc(EL_BUFSIZ
);
449 if (el
->el_line
.buffer
== NULL
)
452 (void) memset(el
->el_line
.buffer
, 0, EL_BUFSIZ
);
453 el
->el_line
.cursor
= el
->el_line
.buffer
;
454 el
->el_line
.lastchar
= el
->el_line
.buffer
;
455 el
->el_line
.limit
= &el
->el_line
.buffer
[EL_BUFSIZ
- EL_LEAVE
];
457 el
->el_chared
.c_undo
.buf
= (char *) el_malloc(EL_BUFSIZ
);
458 if (el
->el_chared
.c_undo
.buf
== NULL
)
460 (void) memset(el
->el_chared
.c_undo
.buf
, 0, EL_BUFSIZ
);
461 el
->el_chared
.c_undo
.len
= -1;
462 el
->el_chared
.c_undo
.cursor
= 0;
463 el
->el_chared
.c_redo
.buf
= (char *) el_malloc(EL_BUFSIZ
);
464 if (el
->el_chared
.c_redo
.buf
== NULL
)
466 el
->el_chared
.c_redo
.pos
= el
->el_chared
.c_redo
.buf
;
467 el
->el_chared
.c_redo
.lim
= el
->el_chared
.c_redo
.buf
+ EL_BUFSIZ
;
468 el
->el_chared
.c_redo
.cmd
= ED_UNASSIGNED
;
470 el
->el_chared
.c_vcmd
.action
= NOP
;
471 el
->el_chared
.c_vcmd
.pos
= el
->el_line
.buffer
;
473 el
->el_chared
.c_kill
.buf
= (char *) el_malloc(EL_BUFSIZ
);
474 if (el
->el_chared
.c_kill
.buf
== NULL
)
476 (void) memset(el
->el_chared
.c_kill
.buf
, 0, EL_BUFSIZ
);
477 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
;
478 el
->el_chared
.c_kill
.last
= el
->el_chared
.c_kill
.buf
;
480 el
->el_map
.current
= el
->el_map
.key
;
482 el
->el_state
.inputmode
= MODE_INSERT
; /* XXX: save a default */
483 el
->el_state
.doingarg
= 0;
484 el
->el_state
.metanext
= 0;
485 el
->el_state
.argument
= 1;
486 el
->el_state
.lastcmd
= ED_UNASSIGNED
;
490 ma
->macro
= (char **) el_malloc(EL_MAXMACRO
* sizeof(char *));
491 if (ma
->macro
== NULL
)
497 * Reset the character editor
500 ch_reset(EditLine
*el
, int mclear
)
502 el
->el_line
.cursor
= el
->el_line
.buffer
;
503 el
->el_line
.lastchar
= el
->el_line
.buffer
;
505 el
->el_chared
.c_undo
.len
= -1;
506 el
->el_chared
.c_undo
.cursor
= 0;
508 el
->el_chared
.c_vcmd
.action
= NOP
;
509 el
->el_chared
.c_vcmd
.pos
= el
->el_line
.buffer
;
511 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
;
513 el
->el_map
.current
= el
->el_map
.key
;
515 el
->el_state
.inputmode
= MODE_INSERT
; /* XXX: save a default */
516 el
->el_state
.doingarg
= 0;
517 el
->el_state
.metanext
= 0;
518 el
->el_state
.argument
= 1;
519 el
->el_state
.lastcmd
= ED_UNASSIGNED
;
521 el
->el_history
.eventno
= 0;
531 c_macro_t
*ma
= &el
->el_chared
.c_macro
;
532 while (ma
->level
>= 0)
533 el_free((ptr_t
)ma
->macro
[ma
->level
--]);
537 * Enlarge line buffer to be able to hold twice as much characters.
538 * Returns 1 if successful, 0 if not.
541 ch_enlargebufs(el
, addlen
)
546 char *newbuffer
, *oldbuf
, *oldkbuf
;
548 sz
= el
->el_line
.limit
- el
->el_line
.buffer
+ EL_LEAVE
;
551 * If newly required length is longer than current buffer, we need
552 * to make the buffer big enough to hold both old and new stuff.
555 while(newsz
- sz
< addlen
)
560 * Reallocate line buffer.
562 newbuffer
= el_realloc(el
->el_line
.buffer
, newsz
);
566 /* zero the newly added memory, leave old data in */
567 (void) memset(&newbuffer
[sz
], 0, newsz
- sz
);
569 oldbuf
= el
->el_line
.buffer
;
571 el
->el_line
.buffer
= newbuffer
;
572 el
->el_line
.cursor
= newbuffer
+ (el
->el_line
.cursor
- oldbuf
);
573 el
->el_line
.lastchar
= newbuffer
+ (el
->el_line
.lastchar
- oldbuf
);
574 /* don't set new size until all buffers are enlarged */
575 el
->el_line
.limit
= &newbuffer
[sz
- EL_LEAVE
];
578 * Reallocate kill buffer.
580 newbuffer
= el_realloc(el
->el_chared
.c_kill
.buf
, newsz
);
584 /* zero the newly added memory, leave old data in */
585 (void) memset(&newbuffer
[sz
], 0, newsz
- sz
);
587 oldkbuf
= el
->el_chared
.c_kill
.buf
;
589 el
->el_chared
.c_kill
.buf
= newbuffer
;
590 el
->el_chared
.c_kill
.last
= newbuffer
+
591 (el
->el_chared
.c_kill
.last
- oldkbuf
);
592 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
+
593 (el
->el_chared
.c_kill
.mark
- oldbuf
);
596 * Reallocate undo buffer.
598 newbuffer
= el_realloc(el
->el_chared
.c_undo
.buf
, newsz
);
602 /* zero the newly added memory, leave old data in */
603 (void) memset(&newbuffer
[sz
], 0, newsz
- sz
);
604 el
->el_chared
.c_undo
.buf
= newbuffer
;
606 newbuffer
= el_realloc(el
->el_chared
.c_redo
.buf
, newsz
);
609 el
->el_chared
.c_redo
.pos
= newbuffer
+
610 (el
->el_chared
.c_redo
.pos
- el
->el_chared
.c_redo
.buf
);
611 el
->el_chared
.c_redo
.lim
= newbuffer
+
612 (el
->el_chared
.c_redo
.lim
- el
->el_chared
.c_redo
.buf
);
613 el
->el_chared
.c_redo
.buf
= newbuffer
;
615 if (!hist_enlargebuf(el
, sz
, newsz
))
618 /* Safe to set enlarged buffer size */
619 el
->el_line
.limit
= &el
->el_line
.buffer
[newsz
- EL_LEAVE
];
624 * Free the data structures used by the editor
629 el_free((ptr_t
) el
->el_line
.buffer
);
630 el
->el_line
.buffer
= NULL
;
631 el
->el_line
.limit
= NULL
;
632 el_free((ptr_t
) el
->el_chared
.c_undo
.buf
);
633 el
->el_chared
.c_undo
.buf
= NULL
;
634 el_free((ptr_t
) el
->el_chared
.c_redo
.buf
);
635 el
->el_chared
.c_redo
.buf
= NULL
;
636 el
->el_chared
.c_redo
.pos
= NULL
;
637 el
->el_chared
.c_redo
.lim
= NULL
;
638 el
->el_chared
.c_redo
.cmd
= ED_UNASSIGNED
;
639 el_free((ptr_t
) el
->el_chared
.c_kill
.buf
);
640 el
->el_chared
.c_kill
.buf
= NULL
;
642 el_free((ptr_t
) el
->el_chared
.c_macro
.macro
);
643 el
->el_chared
.c_macro
.macro
= NULL
;
648 * Insert string at cursorI
651 el_insertstr(EditLine
*el
, const char *s
)
655 if ((len
= strlen(s
)) == 0)
657 if (el
->el_line
.lastchar
+ len
>= el
->el_line
.limit
) {
658 if (!ch_enlargebufs(el
, len
))
662 c_insert(el
, (int)len
);
664 *el
->el_line
.cursor
++ = *s
++;
670 * Delete num characters before the cursor
673 el_deletestr(EditLine
*el
, int n
)
678 if (el
->el_line
.cursor
< &el
->el_line
.buffer
[n
])
681 c_delbefore(el
, n
); /* delete before dot */
682 el
->el_line
.cursor
-= n
;
683 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
684 el
->el_line
.cursor
= el
->el_line
.buffer
;
691 c_gets(EditLine
*el
, char *buf
, const char *prompt
)
695 char *cp
= el
->el_line
.buffer
;
698 len
= strlen(prompt
);
699 memcpy(cp
, prompt
, len
+ 0u);
705 el
->el_line
.cursor
= cp
;
707 el
->el_line
.lastchar
= cp
+ 1;
710 if (el_getc(el
, &ch
) != 1) {
711 ed_end_of_file(el
, 0);
718 case 0010: /* Delete and backspace */
728 case '\r': /* Newline */
734 if (len
>= EL_BUFSIZ
- 16)
745 el
->el_line
.buffer
[0] = '\0';
746 el
->el_line
.lastchar
= el
->el_line
.buffer
;
747 el
->el_line
.cursor
= el
->el_line
.buffer
;
753 * Return the current horizontal position of the cursor
761 * Find how many characters till the beginning of this line.
763 if (el
->el_line
.cursor
== el
->el_line
.buffer
)
766 for (ptr
= el
->el_line
.cursor
- 1;
767 ptr
>= el
->el_line
.buffer
&& *ptr
!= '\n';
770 return (el
->el_line
.cursor
- ptr
- 1);