1 /* $NetBSD: chared.c,v 1.40 2014/06/18 18:12:28 christos Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
36 #if !defined(lint) && !defined(SCCSID)
38 static char sccsid
[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
40 __RCSID("$NetBSD: chared.c,v 1.40 2014/06/18 18:12:28 christos Exp $");
42 #endif /* not lint && not SCCSID */
45 * chared.c: Character editor utilities
50 private void ch__clearmacro (EditLine
*);
52 /* value to leave unused in line buffer */
56 * Handle state for the vi undo command
61 c_undo_t
*vu
= &el
->el_chared
.c_undo
;
62 c_redo_t
*r
= &el
->el_chared
.c_redo
;
65 /* Save entire line for undo */
66 size
= (size_t)(el
->el_line
.lastchar
- el
->el_line
.buffer
);
67 vu
->len
= (ssize_t
)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
));
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
;
75 r
->cmd
= el
->el_state
.thiscmd
;
76 r
->ch
= el
->el_state
.thisch
;
80 * Save yank/delete data for paste
83 cv_yank(EditLine
*el
, const Char
*ptr
, int size
)
85 c_kill_t
*k
= &el
->el_chared
.c_kill
;
87 (void)memcpy(k
->buf
, ptr
, (size_t)size
* sizeof(*k
->buf
));
88 k
->last
= k
->buf
+ size
;
93 * Insert num characters
96 c_insert(EditLine
*el
, int num
)
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 */
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
--)
110 el
->el_line
.lastchar
+= num
;
115 * Delete num characters after the cursor
118 c_delafter(EditLine
*el
, int num
)
121 if (el
->el_line
.cursor
+ num
> el
->el_line
.lastchar
)
122 num
= (int)(el
->el_line
.lastchar
- el
->el_line
.cursor
);
124 if (el
->el_map
.current
!= el
->el_map
.emacs
) {
126 cv_yank(el
, el
->el_line
.cursor
, num
);
132 for (cp
= el
->el_line
.cursor
; cp
<= el
->el_line
.lastchar
; cp
++)
135 el
->el_line
.lastchar
-= num
;
141 * Delete the character after the cursor, do not yank
144 c_delafter1(EditLine
*el
)
148 for (cp
= el
->el_line
.cursor
; cp
<= el
->el_line
.lastchar
; cp
++)
151 el
->el_line
.lastchar
--;
156 * Delete num characters before the cursor
159 c_delbefore(EditLine
*el
, int num
)
162 if (el
->el_line
.cursor
- num
< el
->el_line
.buffer
)
163 num
= (int)(el
->el_line
.cursor
- el
->el_line
.buffer
);
165 if (el
->el_map
.current
!= el
->el_map
.emacs
) {
167 cv_yank(el
, el
->el_line
.cursor
- num
, num
);
173 for (cp
= el
->el_line
.cursor
- num
;
174 cp
<= el
->el_line
.lastchar
;
178 el
->el_line
.lastchar
-= num
;
184 * Delete the character before the cursor, do not yank
187 c_delbefore1(EditLine
*el
)
191 for (cp
= el
->el_line
.cursor
- 1; cp
<= el
->el_line
.lastchar
; cp
++)
194 el
->el_line
.lastchar
--;
199 * Return if p is part of a word according to emacs
204 return Isalnum(p
) || Strchr(STR("*?_-.[]~="), p
) != NULL
;
209 * Return if p is part of a word according to vi
214 if (Isalnum(p
) || p
== '_')
223 * Return if p is part of a big word according to vi
233 * Find the previous word
236 c__prev_word(Char
*p
, Char
*low
, int n
, int (*wtest
)(Int
))
241 while ((p
>= low
) && !(*wtest
)(*p
))
243 while ((p
>= low
) && (*wtest
)(*p
))
247 /* cp now points to one character before the word */
251 /* cp now points where we want it */
260 c__next_word(Char
*p
, Char
*high
, int n
, int (*wtest
)(Int
))
263 while ((p
< high
) && !(*wtest
)(*p
))
265 while ((p
< high
) && (*wtest
)(*p
))
270 /* p now points where we want it */
275 * Find the next word vi style
278 cv_next_word(EditLine
*el
, Char
*p
, Char
*high
, int n
, int (*wtest
)(Int
))
284 while ((p
< high
) && (*wtest
)(*p
) == test
)
287 * vi historically deletes with cw only the word preserving the
288 * trailing whitespace! This is not what 'w' does..
290 if (n
|| el
->el_chared
.c_vcmd
.action
!= (DELETE
|INSERT
))
291 while ((p
< high
) && Isspace(*p
))
295 /* p now points where we want it */
304 * Find the previous word vi style
307 cv_prev_word(Char
*p
, Char
*low
, int n
, int (*wtest
)(Int
))
313 while ((p
> low
) && Isspace(*p
))
316 while ((p
>= low
) && (*wtest
)(*p
) == test
)
321 /* p now points where we want it */
330 * Finish vi delete action
333 cv_delfini(EditLine
*el
)
336 int action
= el
->el_chared
.c_vcmd
.action
;
339 el
->el_map
.current
= el
->el_map
.key
;
341 if (el
->el_chared
.c_vcmd
.pos
== 0)
345 size
= (int)(el
->el_line
.cursor
- el
->el_chared
.c_vcmd
.pos
);
348 el
->el_line
.cursor
= el
->el_chared
.c_vcmd
.pos
;
351 cv_yank(el
, el
->el_line
.cursor
, size
);
353 cv_yank(el
, el
->el_line
.cursor
+ size
, -size
);
356 c_delafter(el
, size
);
357 re_refresh_cursor(el
);
359 c_delbefore(el
, -size
);
360 el
->el_line
.cursor
+= size
;
363 el
->el_chared
.c_vcmd
.action
= NOP
;
368 * Go to the end of this word according to vi
371 cv__endword(Char
*p
, Char
*high
, int n
, int (*wtest
)(Int
))
378 while ((p
< high
) && Isspace(*p
))
382 while ((p
< high
) && (*wtest
)(*p
) == test
)
390 * Initialize the character editor
393 ch_init(EditLine
*el
)
395 c_macro_t
*ma
= &el
->el_chared
.c_macro
;
397 el
->el_line
.buffer
= el_malloc(EL_BUFSIZ
*
398 sizeof(*el
->el_line
.buffer
));
399 if (el
->el_line
.buffer
== NULL
)
402 (void) memset(el
->el_line
.buffer
, 0, EL_BUFSIZ
*
403 sizeof(*el
->el_line
.buffer
));
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
];
408 el
->el_chared
.c_undo
.buf
= el_malloc(EL_BUFSIZ
*
409 sizeof(*el
->el_chared
.c_undo
.buf
));
410 if (el
->el_chared
.c_undo
.buf
== NULL
)
412 (void) memset(el
->el_chared
.c_undo
.buf
, 0, EL_BUFSIZ
*
413 sizeof(*el
->el_chared
.c_undo
.buf
));
414 el
->el_chared
.c_undo
.len
= -1;
415 el
->el_chared
.c_undo
.cursor
= 0;
416 el
->el_chared
.c_redo
.buf
= el_malloc(EL_BUFSIZ
*
417 sizeof(*el
->el_chared
.c_redo
.buf
));
418 if (el
->el_chared
.c_redo
.buf
== NULL
)
420 el
->el_chared
.c_redo
.pos
= el
->el_chared
.c_redo
.buf
;
421 el
->el_chared
.c_redo
.lim
= el
->el_chared
.c_redo
.buf
+ EL_BUFSIZ
;
422 el
->el_chared
.c_redo
.cmd
= ED_UNASSIGNED
;
424 el
->el_chared
.c_vcmd
.action
= NOP
;
425 el
->el_chared
.c_vcmd
.pos
= el
->el_line
.buffer
;
427 el
->el_chared
.c_kill
.buf
= el_malloc(EL_BUFSIZ
*
428 sizeof(*el
->el_chared
.c_kill
.buf
));
429 if (el
->el_chared
.c_kill
.buf
== NULL
)
431 (void) memset(el
->el_chared
.c_kill
.buf
, 0, EL_BUFSIZ
*
432 sizeof(*el
->el_chared
.c_kill
.buf
));
433 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
;
434 el
->el_chared
.c_kill
.last
= el
->el_chared
.c_kill
.buf
;
435 el
->el_chared
.c_resizefun
= NULL
;
436 el
->el_chared
.c_resizearg
= NULL
;
437 el
->el_chared
.c_aliasfun
= NULL
;
438 el
->el_chared
.c_aliasarg
= NULL
;
440 el
->el_map
.current
= el
->el_map
.key
;
442 el
->el_state
.inputmode
= MODE_INSERT
; /* XXX: save a default */
443 el
->el_state
.doingarg
= 0;
444 el
->el_state
.metanext
= 0;
445 el
->el_state
.argument
= 1;
446 el
->el_state
.lastcmd
= ED_UNASSIGNED
;
450 ma
->macro
= el_malloc(EL_MAXMACRO
* sizeof(*ma
->macro
));
451 if (ma
->macro
== NULL
)
457 * Reset the character editor
460 ch_reset(EditLine
*el
, int mclear
)
462 el
->el_line
.cursor
= el
->el_line
.buffer
;
463 el
->el_line
.lastchar
= el
->el_line
.buffer
;
465 el
->el_chared
.c_undo
.len
= -1;
466 el
->el_chared
.c_undo
.cursor
= 0;
468 el
->el_chared
.c_vcmd
.action
= NOP
;
469 el
->el_chared
.c_vcmd
.pos
= el
->el_line
.buffer
;
471 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
;
473 el
->el_map
.current
= el
->el_map
.key
;
475 el
->el_state
.inputmode
= MODE_INSERT
; /* XXX: save a default */
476 el
->el_state
.doingarg
= 0;
477 el
->el_state
.metanext
= 0;
478 el
->el_state
.argument
= 1;
479 el
->el_state
.lastcmd
= ED_UNASSIGNED
;
481 el
->el_history
.eventno
= 0;
488 ch__clearmacro(EditLine
*el
)
490 c_macro_t
*ma
= &el
->el_chared
.c_macro
;
491 while (ma
->level
>= 0)
492 el_free(ma
->macro
[ma
->level
--]);
496 * Enlarge line buffer to be able to hold twice as much characters.
497 * Returns 1 if successful, 0 if not.
500 ch_enlargebufs(EditLine
*el
, size_t addlen
)
503 Char
*newbuffer
, *oldbuf
, *oldkbuf
;
505 sz
= (size_t)(el
->el_line
.limit
- el
->el_line
.buffer
+ EL_LEAVE
);
508 * If newly required length is longer than current buffer, we need
509 * to make the buffer big enough to hold both old and new stuff.
512 while(newsz
- sz
< addlen
)
517 * Reallocate line buffer.
519 newbuffer
= el_realloc(el
->el_line
.buffer
, newsz
* sizeof(*newbuffer
));
523 /* zero the newly added memory, leave old data in */
524 (void) memset(&newbuffer
[sz
], 0, (newsz
- sz
) * sizeof(*newbuffer
));
526 oldbuf
= el
->el_line
.buffer
;
528 el
->el_line
.buffer
= newbuffer
;
529 el
->el_line
.cursor
= newbuffer
+ (el
->el_line
.cursor
- oldbuf
);
530 el
->el_line
.lastchar
= newbuffer
+ (el
->el_line
.lastchar
- oldbuf
);
531 /* don't set new size until all buffers are enlarged */
532 el
->el_line
.limit
= &newbuffer
[sz
- EL_LEAVE
];
535 * Reallocate kill buffer.
537 newbuffer
= el_realloc(el
->el_chared
.c_kill
.buf
, newsz
*
542 /* zero the newly added memory, leave old data in */
543 (void) memset(&newbuffer
[sz
], 0, (newsz
- sz
) * sizeof(*newbuffer
));
545 oldkbuf
= el
->el_chared
.c_kill
.buf
;
547 el
->el_chared
.c_kill
.buf
= newbuffer
;
548 el
->el_chared
.c_kill
.last
= newbuffer
+
549 (el
->el_chared
.c_kill
.last
- oldkbuf
);
550 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
+
551 (el
->el_chared
.c_kill
.mark
- oldbuf
);
554 * Reallocate undo buffer.
556 newbuffer
= el_realloc(el
->el_chared
.c_undo
.buf
,
557 newsz
* sizeof(*newbuffer
));
561 /* zero the newly added memory, leave old data in */
562 (void) memset(&newbuffer
[sz
], 0, (newsz
- sz
) * sizeof(*newbuffer
));
563 el
->el_chared
.c_undo
.buf
= newbuffer
;
565 newbuffer
= el_realloc(el
->el_chared
.c_redo
.buf
,
566 newsz
* sizeof(*newbuffer
));
569 el
->el_chared
.c_redo
.pos
= newbuffer
+
570 (el
->el_chared
.c_redo
.pos
- el
->el_chared
.c_redo
.buf
);
571 el
->el_chared
.c_redo
.lim
= newbuffer
+
572 (el
->el_chared
.c_redo
.lim
- el
->el_chared
.c_redo
.buf
);
573 el
->el_chared
.c_redo
.buf
= newbuffer
;
575 if (!hist_enlargebuf(el
, sz
, newsz
))
578 /* Safe to set enlarged buffer size */
579 el
->el_line
.limit
= &el
->el_line
.buffer
[newsz
- EL_LEAVE
];
580 if (el
->el_chared
.c_resizefun
)
581 (*el
->el_chared
.c_resizefun
)(el
, el
->el_chared
.c_resizearg
);
586 * Free the data structures used by the editor
591 el_free(el
->el_line
.buffer
);
592 el
->el_line
.buffer
= NULL
;
593 el
->el_line
.limit
= NULL
;
594 el_free(el
->el_chared
.c_undo
.buf
);
595 el
->el_chared
.c_undo
.buf
= NULL
;
596 el_free(el
->el_chared
.c_redo
.buf
);
597 el
->el_chared
.c_redo
.buf
= NULL
;
598 el
->el_chared
.c_redo
.pos
= NULL
;
599 el
->el_chared
.c_redo
.lim
= NULL
;
600 el
->el_chared
.c_redo
.cmd
= ED_UNASSIGNED
;
601 el_free(el
->el_chared
.c_kill
.buf
);
602 el
->el_chared
.c_kill
.buf
= NULL
;
604 el_free(el
->el_chared
.c_macro
.macro
);
605 el
->el_chared
.c_macro
.macro
= NULL
;
610 * Insert string at cursorI
613 FUN(el
,insertstr
)(EditLine
*el
, const Char
*s
)
617 if (s
== NULL
|| (len
= Strlen(s
)) == 0)
619 if (el
->el_line
.lastchar
+ len
>= el
->el_line
.limit
) {
620 if (!ch_enlargebufs(el
, len
))
624 c_insert(el
, (int)len
);
626 *el
->el_line
.cursor
++ = *s
++;
632 * Delete num characters before the cursor
635 el_deletestr(EditLine
*el
, int n
)
640 if (el
->el_line
.cursor
< &el
->el_line
.buffer
[n
])
643 c_delbefore(el
, n
); /* delete before dot */
644 el
->el_line
.cursor
-= n
;
645 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
646 el
->el_line
.cursor
= el
->el_line
.buffer
;
650 * Move the cursor to the left or the right of the current position
653 el_cursor(EditLine
*el
, int n
)
658 el
->el_line
.cursor
+= n
;
660 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
661 el
->el_line
.cursor
= el
->el_line
.buffer
;
662 if (el
->el_line
.cursor
> el
->el_line
.lastchar
)
663 el
->el_line
.cursor
= el
->el_line
.lastchar
;
665 return (int)(el
->el_line
.cursor
- el
->el_line
.buffer
);
672 c_gets(EditLine
*el
, Char
*buf
, const Char
*prompt
)
676 Char
*cp
= el
->el_line
.buffer
;
679 len
= (ssize_t
)Strlen(prompt
);
680 (void)memcpy(cp
, prompt
, (size_t)len
* sizeof(*cp
));
686 el
->el_line
.cursor
= cp
;
688 el
->el_line
.lastchar
= cp
+ 1;
691 if (FUN(el
,getc
)(el
, &ch
) != 1) {
692 ed_end_of_file(el
, 0);
699 case 0010: /* Delete and backspace */
709 case '\r': /* Newline */
715 if (len
>= (ssize_t
)(EL_BUFSIZ
- 16))
726 el
->el_line
.buffer
[0] = '\0';
727 el
->el_line
.lastchar
= el
->el_line
.buffer
;
728 el
->el_line
.cursor
= el
->el_line
.buffer
;
734 * Return the current horizontal position of the cursor
742 * Find how many characters till the beginning of this line.
744 if (el
->el_line
.cursor
== el
->el_line
.buffer
)
747 for (ptr
= el
->el_line
.cursor
- 1;
748 ptr
>= el
->el_line
.buffer
&& *ptr
!= '\n';
751 return (int)(el
->el_line
.cursor
- ptr
- 1);
756 ch_resizefun(EditLine
*el
, el_zfunc_t f
, void *a
)
758 el
->el_chared
.c_resizefun
= f
;
759 el
->el_chared
.c_resizearg
= a
;
764 ch_aliasfun(EditLine
*el
, el_afunc_t f
, void *a
)
766 el
->el_chared
.c_aliasfun
= f
;
767 el
->el_chared
.c_aliasarg
= a
;