1 /* $NetBSD: chared.c,v 1.62 2022/02/08 21:13:22 rillig 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.62 2022/02/08 21:13:22 rillig Exp $");
42 #endif /* not lint && not SCCSID */
45 * chared.c: Character editor utilities
55 /* value to leave unused in line buffer */
59 * Handle state for the vi undo command
64 c_undo_t
*vu
= &el
->el_chared
.c_undo
;
65 c_redo_t
*r
= &el
->el_chared
.c_redo
;
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
));
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
;
78 r
->cmd
= el
->el_state
.thiscmd
;
79 r
->ch
= el
->el_state
.thisch
;
83 * Save yank/delete data for paste
86 cv_yank(EditLine
*el
, const wchar_t *ptr
, int size
)
88 c_kill_t
*k
= &el
->el_chared
.c_kill
;
90 (void)memcpy(k
->buf
, ptr
, (size_t)size
* sizeof(*k
->buf
));
91 k
->last
= k
->buf
+ size
;
96 * Insert num characters
99 c_insert(EditLine
*el
, int num
)
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 */
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
--)
113 el
->el_line
.lastchar
+= num
;
118 * Delete num characters after the cursor
121 c_delafter(EditLine
*el
, int num
)
124 if (el
->el_line
.cursor
+ num
> el
->el_line
.lastchar
)
125 num
= (int)(el
->el_line
.lastchar
- el
->el_line
.cursor
);
127 if (el
->el_map
.current
!= el
->el_map
.emacs
) {
129 cv_yank(el
, el
->el_line
.cursor
, num
);
135 for (cp
= el
->el_line
.cursor
; cp
<= el
->el_line
.lastchar
; cp
++)
138 el
->el_line
.lastchar
-= num
;
144 * Delete the character after the cursor, do not yank
147 c_delafter1(EditLine
*el
)
151 for (cp
= el
->el_line
.cursor
; cp
<= el
->el_line
.lastchar
; cp
++)
154 el
->el_line
.lastchar
--;
159 * Delete num characters before the cursor
162 c_delbefore(EditLine
*el
, int num
)
165 if (el
->el_line
.cursor
- num
< el
->el_line
.buffer
)
166 num
= (int)(el
->el_line
.cursor
- el
->el_line
.buffer
);
168 if (el
->el_map
.current
!= el
->el_map
.emacs
) {
170 cv_yank(el
, el
->el_line
.cursor
- num
, num
);
176 for (cp
= el
->el_line
.cursor
- num
;
177 &cp
[num
] <= el
->el_line
.lastchar
;
181 el
->el_line
.lastchar
-= num
;
187 * Delete the character before the cursor, do not yank
190 c_delbefore1(EditLine
*el
)
194 for (cp
= el
->el_line
.cursor
- 1; cp
<= el
->el_line
.lastchar
; cp
++)
197 el
->el_line
.lastchar
--;
202 * Return if p is part of a word according to emacs
207 return iswalnum(p
) || wcschr(L
"*?_-.[]~=", p
) != NULL
;
212 * Return if p is part of a word according to vi
217 if (iswalnum(p
) || p
== L
'_')
226 * Return if p is part of a big word according to vi
236 * Find the previous word
238 libedit_private
wchar_t *
239 c__prev_word(wchar_t *p
, wchar_t *low
, int n
, int (*wtest
)(wint_t))
244 while ((p
>= low
) && !(*wtest
)(*p
))
246 while ((p
>= low
) && (*wtest
)(*p
))
250 /* cp now points to one character before the word */
254 /* cp now points where we want it */
262 libedit_private
wchar_t *
263 c__next_word(wchar_t *p
, wchar_t *high
, int n
, int (*wtest
)(wint_t))
266 while ((p
< high
) && !(*wtest
)(*p
))
268 while ((p
< high
) && (*wtest
)(*p
))
273 /* p now points where we want it */
278 * Find the next word vi style
280 libedit_private
wchar_t *
281 cv_next_word(EditLine
*el
, wchar_t *p
, wchar_t *high
, int n
,
282 int (*wtest
)(wint_t))
288 while ((p
< high
) && (*wtest
)(*p
) == test
)
291 * vi historically deletes with cw only the word preserving the
292 * trailing whitespace! This is not what 'w' does..
294 if (n
|| el
->el_chared
.c_vcmd
.action
!= (DELETE
|INSERT
))
295 while ((p
< high
) && iswspace(*p
))
299 /* p now points where we want it */
308 * Find the previous word vi style
310 libedit_private
wchar_t *
311 cv_prev_word(wchar_t *p
, wchar_t *low
, int n
, int (*wtest
)(wint_t))
317 while ((p
> low
) && iswspace(*p
))
320 while ((p
>= low
) && (*wtest
)(*p
) == test
)
325 /* p now points where we want it */
334 * Finish vi delete action
337 cv_delfini(EditLine
*el
)
340 int action
= el
->el_chared
.c_vcmd
.action
;
343 el
->el_map
.current
= el
->el_map
.key
;
345 if (el
->el_chared
.c_vcmd
.pos
== 0)
349 size
= (int)(el
->el_line
.cursor
- el
->el_chared
.c_vcmd
.pos
);
352 el
->el_line
.cursor
= el
->el_chared
.c_vcmd
.pos
;
355 cv_yank(el
, el
->el_line
.cursor
, size
);
357 cv_yank(el
, el
->el_line
.cursor
+ size
, -size
);
360 c_delafter(el
, size
);
361 re_refresh_cursor(el
);
363 c_delbefore(el
, -size
);
364 el
->el_line
.cursor
+= size
;
367 el
->el_chared
.c_vcmd
.action
= NOP
;
372 * Go to the end of this word according to vi
374 libedit_private
wchar_t *
375 cv__endword(wchar_t *p
, wchar_t *high
, int n
, int (*wtest
)(wint_t))
382 while ((p
< high
) && iswspace(*p
))
386 while ((p
< high
) && (*wtest
)(*p
) == test
)
394 * Initialize the character editor
397 ch_init(EditLine
*el
)
399 el
->el_line
.buffer
= el_calloc(EL_BUFSIZ
,
400 sizeof(*el
->el_line
.buffer
));
401 if (el
->el_line
.buffer
== NULL
)
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_calloc(EL_BUFSIZ
,
409 sizeof(*el
->el_chared
.c_undo
.buf
));
410 if (el
->el_chared
.c_undo
.buf
== NULL
)
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
)
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
;
422 el
->el_chared
.c_vcmd
.action
= NOP
;
423 el
->el_chared
.c_vcmd
.pos
= el
->el_line
.buffer
;
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
)
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
;
436 el
->el_map
.current
= el
->el_map
.key
;
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
;
448 * Reset the character editor
451 ch_reset(EditLine
*el
)
453 el
->el_line
.cursor
= el
->el_line
.buffer
;
454 el
->el_line
.lastchar
= el
->el_line
.buffer
;
456 el
->el_chared
.c_undo
.len
= -1;
457 el
->el_chared
.c_undo
.cursor
= 0;
459 el
->el_chared
.c_vcmd
.action
= NOP
;
460 el
->el_chared
.c_vcmd
.pos
= el
->el_line
.buffer
;
462 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
;
464 el
->el_map
.current
= el
->el_map
.key
;
466 el
->el_state
.inputmode
= MODE_INSERT
; /* XXX: save a default */
467 el
->el_state
.doingarg
= 0;
468 el
->el_state
.metanext
= 0;
469 el
->el_state
.argument
= 1;
470 el
->el_state
.lastcmd
= ED_UNASSIGNED
;
472 el
->el_history
.eventno
= 0;
476 * Enlarge line buffer to be able to hold twice as much characters.
477 * Returns 1 if successful, 0 if not.
480 ch_enlargebufs(EditLine
*el
, size_t addlen
)
483 wchar_t *newbuffer
, *oldbuf
, *oldkbuf
;
485 sz
= (size_t)(el
->el_line
.limit
- el
->el_line
.buffer
+ EL_LEAVE
);
488 * If newly required length is longer than current buffer, we need
489 * to make the buffer big enough to hold both old and new stuff.
492 while(newsz
- sz
< addlen
)
497 * Reallocate line buffer.
499 newbuffer
= el_realloc(el
->el_line
.buffer
, newsz
* sizeof(*newbuffer
));
503 /* zero the newly added memory, leave old data in */
504 (void) memset(&newbuffer
[sz
], 0, (newsz
- sz
) * sizeof(*newbuffer
));
506 oldbuf
= el
->el_line
.buffer
;
508 el
->el_line
.buffer
= newbuffer
;
509 el
->el_line
.cursor
= newbuffer
+ (el
->el_line
.cursor
- oldbuf
);
510 el
->el_line
.lastchar
= newbuffer
+ (el
->el_line
.lastchar
- oldbuf
);
511 /* don't set new size until all buffers are enlarged */
512 el
->el_line
.limit
= &newbuffer
[sz
- EL_LEAVE
];
515 * Reallocate kill buffer.
517 newbuffer
= el_realloc(el
->el_chared
.c_kill
.buf
, newsz
*
522 /* zero the newly added memory, leave old data in */
523 (void) memset(&newbuffer
[sz
], 0, (newsz
- sz
) * sizeof(*newbuffer
));
525 oldkbuf
= el
->el_chared
.c_kill
.buf
;
527 el
->el_chared
.c_kill
.buf
= newbuffer
;
528 el
->el_chared
.c_kill
.last
= newbuffer
+
529 (el
->el_chared
.c_kill
.last
- oldkbuf
);
530 el
->el_chared
.c_kill
.mark
= el
->el_line
.buffer
+
531 (el
->el_chared
.c_kill
.mark
- oldbuf
);
534 * Reallocate undo buffer.
536 newbuffer
= el_realloc(el
->el_chared
.c_undo
.buf
,
537 newsz
* sizeof(*newbuffer
));
541 /* zero the newly added memory, leave old data in */
542 (void) memset(&newbuffer
[sz
], 0, (newsz
- sz
) * sizeof(*newbuffer
));
543 el
->el_chared
.c_undo
.buf
= newbuffer
;
545 newbuffer
= el_realloc(el
->el_chared
.c_redo
.buf
,
546 newsz
* sizeof(*newbuffer
));
549 el
->el_chared
.c_redo
.pos
= newbuffer
+
550 (el
->el_chared
.c_redo
.pos
- el
->el_chared
.c_redo
.buf
);
551 el
->el_chared
.c_redo
.lim
= newbuffer
+
552 (el
->el_chared
.c_redo
.lim
- el
->el_chared
.c_redo
.buf
);
553 el
->el_chared
.c_redo
.buf
= newbuffer
;
555 if (!hist_enlargebuf(el
, sz
, newsz
))
558 /* Safe to set enlarged buffer size */
559 el
->el_line
.limit
= &el
->el_line
.buffer
[newsz
- EL_LEAVE
];
560 if (el
->el_chared
.c_resizefun
)
561 (*el
->el_chared
.c_resizefun
)(el
, el
->el_chared
.c_resizearg
);
566 * Free the data structures used by the editor
571 el_free(el
->el_line
.buffer
);
572 el
->el_line
.buffer
= NULL
;
573 el
->el_line
.limit
= NULL
;
574 el_free(el
->el_chared
.c_undo
.buf
);
575 el
->el_chared
.c_undo
.buf
= NULL
;
576 el_free(el
->el_chared
.c_redo
.buf
);
577 el
->el_chared
.c_redo
.buf
= NULL
;
578 el
->el_chared
.c_redo
.pos
= NULL
;
579 el
->el_chared
.c_redo
.lim
= NULL
;
580 el
->el_chared
.c_redo
.cmd
= ED_UNASSIGNED
;
581 el_free(el
->el_chared
.c_kill
.buf
);
582 el
->el_chared
.c_kill
.buf
= NULL
;
588 * Insert string at cursor
591 el_winsertstr(EditLine
*el
, const wchar_t *s
)
595 if (s
== NULL
|| (len
= wcslen(s
)) == 0)
597 if (el
->el_line
.lastchar
+ len
>= el
->el_line
.limit
) {
598 if (!ch_enlargebufs(el
, len
))
602 c_insert(el
, (int)len
);
604 *el
->el_line
.cursor
++ = *s
++;
610 * Delete num characters before the cursor
613 el_deletestr(EditLine
*el
, int n
)
618 if (el
->el_line
.cursor
< &el
->el_line
.buffer
[n
])
621 c_delbefore(el
, n
); /* delete before dot */
622 el
->el_line
.cursor
-= n
;
623 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
624 el
->el_line
.cursor
= el
->el_line
.buffer
;
628 * Delete characters between start and end
631 el_deletestr1(EditLine
*el
, int start
, int end
)
633 size_t line_length
, len
;
639 line_length
= (size_t)(el
->el_line
.lastchar
- el
->el_line
.buffer
);
641 if (start
>= (int)line_length
|| end
>= (int)line_length
)
644 len
= (size_t)(end
- start
);
645 if (len
> line_length
- (size_t)end
)
646 len
= line_length
- (size_t)end
;
648 p1
= el
->el_line
.buffer
+ start
;
649 p2
= el
->el_line
.buffer
+ end
;
650 for (size_t i
= 0; i
< len
; i
++) {
652 el
->el_line
.lastchar
--;
655 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
656 el
->el_line
.cursor
= el
->el_line
.buffer
;
662 * Replace the contents of the line with the provided string
665 el_wreplacestr(EditLine
*el
, const wchar_t *s
)
670 if (s
== NULL
|| (len
= wcslen(s
)) == 0)
673 if (el
->el_line
.buffer
+ len
>= el
->el_line
.limit
) {
674 if (!ch_enlargebufs(el
, len
))
678 p
= el
->el_line
.buffer
;
679 for (size_t i
= 0; i
< len
; i
++)
682 el
->el_line
.buffer
[len
] = '\0';
683 el
->el_line
.lastchar
= el
->el_line
.buffer
+ len
;
684 if (el
->el_line
.cursor
> el
->el_line
.lastchar
)
685 el
->el_line
.cursor
= el
->el_line
.lastchar
;
691 * Move the cursor to the left or the right of the current position
694 el_cursor(EditLine
*el
, int n
)
699 el
->el_line
.cursor
+= n
;
701 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
702 el
->el_line
.cursor
= el
->el_line
.buffer
;
703 if (el
->el_line
.cursor
> el
->el_line
.lastchar
)
704 el
->el_line
.cursor
= el
->el_line
.lastchar
;
706 return (int)(el
->el_line
.cursor
- el
->el_line
.buffer
);
713 c_gets(EditLine
*el
, wchar_t *buf
, const wchar_t *prompt
)
716 wchar_t *cp
= el
->el_line
.buffer
, ch
;
719 len
= (ssize_t
)wcslen(prompt
);
720 (void)memcpy(cp
, prompt
, (size_t)len
* sizeof(*cp
));
726 el
->el_line
.cursor
= cp
;
728 el
->el_line
.lastchar
= cp
+ 1;
731 if (el_wgetc(el
, &ch
) != 1) {
732 ed_end_of_file(el
, 0);
739 case L
'\b': /* Delete and backspace */
750 case L
'\r': /* Newline */
756 if (len
>= (ssize_t
)(EL_BUFSIZ
- 16))
767 el
->el_line
.buffer
[0] = '\0';
768 el
->el_line
.lastchar
= el
->el_line
.buffer
;
769 el
->el_line
.cursor
= el
->el_line
.buffer
;
775 * Return the current horizontal position of the cursor
783 * Find how many characters till the beginning of this line.
785 if (el
->el_line
.cursor
== el
->el_line
.buffer
)
788 for (ptr
= el
->el_line
.cursor
- 1;
789 ptr
>= el
->el_line
.buffer
&& *ptr
!= '\n';
792 return (int)(el
->el_line
.cursor
- ptr
- 1);
797 ch_resizefun(EditLine
*el
, el_zfunc_t f
, void *a
)
799 el
->el_chared
.c_resizefun
= f
;
800 el
->el_chared
.c_resizearg
= a
;
805 ch_aliasfun(EditLine
*el
, el_afunc_t f
, void *a
)
807 el
->el_chared
.c_aliasfun
= f
;
808 el
->el_chared
.c_aliasarg
= a
;