1 /* $OpenBSD: common.c,v 1.22 2016/05/22 23:09:56 schwarze Exp $ */
2 /* $NetBSD: common.c,v 1.24 2009/12/30 22:37:40 christos Exp $ */
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * common.c: Common Editor functions
51 * Indicate end of file
56 ed_end_of_file(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
60 *el
->el_line
.lastchar
= '\0';
66 * Add character to the line
67 * Insert a character [bound to all insert keys]
70 ed_insert(EditLine
*el
, wint_t c
)
72 int count
= el
->el_state
.argument
;
77 if (el
->el_line
.lastchar
+ el
->el_state
.argument
>=
79 /* end of buffer space, try to allocate more */
80 if (!ch_enlargebufs(el
, (size_t) count
))
81 return CC_ERROR
; /* error allocating more */
85 if (el
->el_state
.inputmode
== MODE_INSERT
86 || el
->el_line
.cursor
>= el
->el_line
.lastchar
)
89 *el
->el_line
.cursor
++ = c
;
90 re_fastaddc(el
); /* fast refresh for one char. */
92 if (el
->el_state
.inputmode
!= MODE_REPLACE_1
)
93 c_insert(el
, el
->el_state
.argument
);
95 while (count
-- && el
->el_line
.cursor
< el
->el_line
.lastchar
)
96 *el
->el_line
.cursor
++ = c
;
100 if (el
->el_state
.inputmode
== MODE_REPLACE_1
)
101 return vi_command_mode(el
, 0);
107 /* ed_delete_prev_word():
108 * Delete from beginning of current word to cursor
111 protected el_action_t
113 ed_delete_prev_word(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
115 wchar_t *cp
, *p
, *kp
;
117 if (el
->el_line
.cursor
== el
->el_line
.buffer
)
120 cp
= c__prev_word(el
->el_line
.cursor
, el
->el_line
.buffer
,
121 el
->el_state
.argument
, ce__isword
);
123 for (p
= cp
, kp
= el
->el_chared
.c_kill
.buf
; p
< el
->el_line
.cursor
; p
++)
125 el
->el_chared
.c_kill
.last
= kp
;
127 c_delbefore(el
, (int)(el
->el_line
.cursor
- cp
));/* delete before dot */
128 el
->el_line
.cursor
= cp
;
129 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
130 el
->el_line
.cursor
= el
->el_line
.buffer
; /* bounds check */
135 /* ed_delete_next_char():
136 * Delete character under cursor
139 protected el_action_t
141 ed_delete_next_char(EditLine
*el
, wint_t c
)
143 #ifdef notdef /* XXX */
144 #define EL el->el_line
145 (void) fprintf(el
->el_errfile
,
146 "\nD(b: %p(%ls) c: %p(%ls) last: %p(%ls) limit: %p(%ls)\n",
147 EL
.buffer
, EL
.buffer
, EL
.cursor
, EL
.cursor
, EL
.lastchar
,
148 EL
.lastchar
, EL
.limit
, EL
.limit
);
150 if (el
->el_line
.cursor
== el
->el_line
.lastchar
) {
151 /* if I'm at the end */
152 if (el
->el_map
.type
== MAP_VI
) {
153 if (el
->el_line
.cursor
== el
->el_line
.buffer
) {
154 /* if I'm also at the beginning */
159 terminal_writec(el
, c
);
164 el
->el_line
.cursor
--;
170 if (el
->el_line
.cursor
!= el
->el_line
.buffer
)
171 el
->el_line
.cursor
--;
176 c_delafter(el
, el
->el_state
.argument
); /* delete after dot */
177 if (el
->el_line
.cursor
>= el
->el_line
.lastchar
&&
178 el
->el_line
.cursor
> el
->el_line
.buffer
)
180 el
->el_line
.cursor
= el
->el_line
.lastchar
- 1;
186 * Cut to the end of line
189 protected el_action_t
191 ed_kill_line(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
195 cp
= el
->el_line
.cursor
;
196 kp
= el
->el_chared
.c_kill
.buf
;
197 while (cp
< el
->el_line
.lastchar
)
198 *kp
++ = *cp
++; /* copy it */
199 el
->el_chared
.c_kill
.last
= kp
;
200 /* zap! -- delete to end */
201 el
->el_line
.lastchar
= el
->el_line
.cursor
;
207 * Move cursor to the end of line
210 protected el_action_t
212 ed_move_to_end(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
215 el
->el_line
.cursor
= el
->el_line
.lastchar
;
216 if (el
->el_map
.type
== MAP_VI
) {
217 if (el
->el_chared
.c_vcmd
.action
!= NOP
) {
222 el
->el_line
.cursor
--;
230 * Move cursor to the beginning of line
233 protected el_action_t
235 ed_move_to_beg(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
238 el
->el_line
.cursor
= el
->el_line
.buffer
;
240 if (el
->el_map
.type
== MAP_VI
) {
241 /* We want FIRST non space character */
242 while (iswspace(*el
->el_line
.cursor
))
243 el
->el_line
.cursor
++;
244 if (el
->el_chared
.c_vcmd
.action
!= NOP
) {
253 /* ed_transpose_chars():
254 * Exchange the character to the left of the cursor with the one under it
257 protected el_action_t
258 ed_transpose_chars(EditLine
*el
, wint_t c
)
261 if (el
->el_line
.cursor
< el
->el_line
.lastchar
) {
262 if (el
->el_line
.lastchar
<= &el
->el_line
.buffer
[1])
265 el
->el_line
.cursor
++;
267 if (el
->el_line
.cursor
> &el
->el_line
.buffer
[1]) {
268 /* must have at least two chars entered */
269 c
= el
->el_line
.cursor
[-2];
270 el
->el_line
.cursor
[-2] = el
->el_line
.cursor
[-1];
271 el
->el_line
.cursor
[-1] = c
;
279 * Move to the right one character
282 protected el_action_t
284 ed_next_char(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
286 wchar_t *lim
= el
->el_line
.lastchar
;
288 if (el
->el_line
.cursor
>= lim
||
289 (el
->el_line
.cursor
== lim
- 1 &&
290 el
->el_map
.type
== MAP_VI
&&
291 el
->el_chared
.c_vcmd
.action
== NOP
))
294 el
->el_line
.cursor
+= el
->el_state
.argument
;
295 if (el
->el_line
.cursor
> lim
)
296 el
->el_line
.cursor
= lim
;
298 if (el
->el_map
.type
== MAP_VI
)
299 if (el
->el_chared
.c_vcmd
.action
!= NOP
) {
308 * Move to the beginning of the current word
311 protected el_action_t
313 ed_prev_word(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
316 if (el
->el_line
.cursor
== el
->el_line
.buffer
)
319 el
->el_line
.cursor
= c__prev_word(el
->el_line
.cursor
,
321 el
->el_state
.argument
,
324 if (el
->el_map
.type
== MAP_VI
)
325 if (el
->el_chared
.c_vcmd
.action
!= NOP
) {
334 * Move to the left one character
337 protected el_action_t
339 ed_prev_char(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
342 if (el
->el_line
.cursor
> el
->el_line
.buffer
) {
343 el
->el_line
.cursor
-= el
->el_state
.argument
;
344 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
345 el
->el_line
.cursor
= el
->el_line
.buffer
;
347 if (el
->el_map
.type
== MAP_VI
)
348 if (el
->el_chared
.c_vcmd
.action
!= NOP
) {
358 /* ed_quoted_insert():
359 * Add the next character typed verbatim
362 protected el_action_t
363 ed_quoted_insert(EditLine
*el
, wint_t c
)
368 num
= el_wgetc(el
, &c
);
371 return ed_insert(el
, c
);
373 return ed_end_of_file(el
, 0);
378 * Adds to argument or enters a digit
380 protected el_action_t
381 ed_digit(EditLine
*el
, wint_t c
)
387 if (el
->el_state
.doingarg
) {
388 /* if doing an arg, add this in... */
389 if (el
->el_state
.lastcmd
== EM_UNIVERSAL_ARGUMENT
)
390 el
->el_state
.argument
= c
- '0';
392 if (el
->el_state
.argument
> 1000000)
394 el
->el_state
.argument
=
395 (el
->el_state
.argument
* 10) + (c
- '0');
400 return ed_insert(el
, c
);
404 /* ed_argument_digit():
405 * Digit that starts argument
408 protected el_action_t
409 ed_argument_digit(EditLine
*el
, wint_t c
)
415 if (el
->el_state
.doingarg
) {
416 if (el
->el_state
.argument
> 1000000)
418 el
->el_state
.argument
= (el
->el_state
.argument
* 10) +
420 } else { /* else starting an argument */
421 el
->el_state
.argument
= c
- '0';
422 el
->el_state
.doingarg
= 1;
429 * Indicates unbound character
430 * Bound to keys that are not assigned
432 protected el_action_t
434 ed_unassigned(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
442 * Input characters that have no effect
443 * [^C ^O ^Q ^S ^Z ^\ ^]] [^C ^O ^Q ^S ^\]
445 protected el_action_t
447 ed_ignore(EditLine
*el
__attribute__((__unused__
)),
448 wint_t c
__attribute__((__unused__
)))
459 protected el_action_t
461 ed_newline(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
465 *el
->el_line
.lastchar
++ = '\n';
466 *el
->el_line
.lastchar
= '\0';
471 /* ed_delete_prev_char():
472 * Delete the character to the left of the cursor
475 protected el_action_t
477 ed_delete_prev_char(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
480 if (el
->el_line
.cursor
<= el
->el_line
.buffer
)
483 c_delbefore(el
, el
->el_state
.argument
);
484 el
->el_line
.cursor
-= el
->el_state
.argument
;
485 if (el
->el_line
.cursor
< el
->el_line
.buffer
)
486 el
->el_line
.cursor
= el
->el_line
.buffer
;
491 /* ed_clear_screen():
492 * Clear screen leaving current line at the top
495 protected el_action_t
497 ed_clear_screen(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
500 terminal_clear_screen(el
); /* clear the whole real screen */
501 re_clear_display(el
); /* reset everything */
507 * Redisplay everything
510 protected el_action_t
512 ed_redisplay(EditLine
*el
__attribute__((__unused__
)),
513 wint_t c
__attribute__((__unused__
)))
521 * Erase current line and start from scratch
524 protected el_action_t
526 ed_start_over(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
534 /* ed_sequence_lead_in():
535 * First character in a bound sequence
536 * Placeholder for external keys
538 protected el_action_t
540 ed_sequence_lead_in(EditLine
*el
__attribute__((__unused__
)),
541 wint_t c
__attribute__((__unused__
)))
548 /* ed_prev_history():
549 * Move to the previous history line
552 protected el_action_t
554 ed_prev_history(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
557 int sv_event
= el
->el_history
.eventno
;
559 el
->el_chared
.c_undo
.len
= -1;
560 *el
->el_line
.lastchar
= '\0'; /* just in case */
562 if (el
->el_history
.eventno
== 0) { /* save the current buffer
564 (void) wcsncpy(el
->el_history
.buf
, el
->el_line
.buffer
,
566 el
->el_history
.last
= el
->el_history
.buf
+
567 (el
->el_line
.lastchar
- el
->el_line
.buffer
);
569 el
->el_history
.eventno
+= el
->el_state
.argument
;
571 if (hist_get(el
) == CC_ERROR
) {
572 if (el
->el_map
.type
== MAP_VI
) {
573 el
->el_history
.eventno
= sv_event
;
576 /* el->el_history.eventno was fixed by first call */
580 return CC_REFRESH_BEEP
;
585 /* ed_next_history():
586 * Move to the next history line
589 protected el_action_t
591 ed_next_history(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
593 el_action_t beep
= CC_REFRESH
, rval
;
595 el
->el_chared
.c_undo
.len
= -1;
596 *el
->el_line
.lastchar
= '\0'; /* just in case */
598 el
->el_history
.eventno
-= el
->el_state
.argument
;
600 if (el
->el_history
.eventno
< 0) {
601 el
->el_history
.eventno
= 0;
602 beep
= CC_REFRESH_BEEP
;
605 if (rval
== CC_REFRESH
)
612 /* ed_search_prev_history():
613 * Search previous in history for a line matching the current
614 * next search history [M-P] [K]
616 protected el_action_t
618 ed_search_prev_history(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
624 el
->el_chared
.c_vcmd
.action
= NOP
;
625 el
->el_chared
.c_undo
.len
= -1;
626 *el
->el_line
.lastchar
= '\0'; /* just in case */
627 if (el
->el_history
.eventno
< 0) {
629 (void) fprintf(el
->el_errfile
,
630 "e_prev_search_hist(): eventno < 0;\n");
632 el
->el_history
.eventno
= 0;
635 if (el
->el_history
.eventno
== 0) {
636 (void) wcsncpy(el
->el_history
.buf
, el
->el_line
.buffer
,
638 el
->el_history
.last
= el
->el_history
.buf
+
639 (el
->el_line
.lastchar
- el
->el_line
.buffer
);
641 if (el
->el_history
.ref
== NULL
)
648 c_setpat(el
); /* Set search pattern !! */
650 for (h
= 1; h
<= el
->el_history
.eventno
; h
++)
655 (void) fprintf(el
->el_errfile
, "Comparing with \"%s\"\n", hp
);
657 if ((wcsncmp(hp
, el
->el_line
.buffer
, (size_t)
658 (el
->el_line
.lastchar
- el
->el_line
.buffer
)) ||
659 hp
[el
->el_line
.lastchar
- el
->el_line
.buffer
]) &&
670 (void) fprintf(el
->el_errfile
, "not found\n");
674 el
->el_history
.eventno
= h
;
680 /* ed_search_next_history():
681 * Search next in history for a line matching the current
684 protected el_action_t
686 ed_search_next_history(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
692 el
->el_chared
.c_vcmd
.action
= NOP
;
693 el
->el_chared
.c_undo
.len
= -1;
694 *el
->el_line
.lastchar
= '\0'; /* just in case */
696 if (el
->el_history
.eventno
== 0)
699 if (el
->el_history
.ref
== NULL
)
706 c_setpat(el
); /* Set search pattern !! */
708 for (h
= 1; h
< el
->el_history
.eventno
&& hp
; h
++) {
710 (void) fprintf(el
->el_errfile
, "Comparing with \"%s\"\n", hp
);
712 if ((wcsncmp(hp
, el
->el_line
.buffer
, (size_t)
713 (el
->el_line
.lastchar
- el
->el_line
.buffer
)) ||
714 hp
[el
->el_line
.lastchar
- el
->el_line
.buffer
]) &&
720 if (!found
) { /* is it the current history number? */
721 if (!c_hmatch(el
, el
->el_history
.buf
)) {
723 (void) fprintf(el
->el_errfile
, "not found\n");
728 el
->el_history
.eventno
= found
;
738 protected el_action_t
740 ed_prev_line(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
743 int nchars
= c_hpos(el
);
746 * Move to the line requested
748 if (*(ptr
= el
->el_line
.cursor
) == '\n')
751 for (; ptr
>= el
->el_line
.buffer
; ptr
--)
752 if (*ptr
== '\n' && --el
->el_state
.argument
<= 0)
755 if (el
->el_state
.argument
> 0)
759 * Move to the beginning of the line
761 for (ptr
--; ptr
>= el
->el_line
.buffer
&& *ptr
!= '\n'; ptr
--)
765 * Move to the character requested
768 nchars
-- > 0 && ptr
< el
->el_line
.lastchar
&& *ptr
!= '\n';
772 el
->el_line
.cursor
= ptr
;
781 protected el_action_t
783 ed_next_line(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
786 int nchars
= c_hpos(el
);
789 * Move to the line requested
791 for (ptr
= el
->el_line
.cursor
; ptr
< el
->el_line
.lastchar
; ptr
++)
792 if (*ptr
== '\n' && --el
->el_state
.argument
<= 0)
795 if (el
->el_state
.argument
> 0)
799 * Move to the character requested
802 nchars
-- > 0 && ptr
< el
->el_line
.lastchar
&& *ptr
!= '\n';
806 el
->el_line
.cursor
= ptr
;
812 * Editline extended command
815 protected el_action_t
817 ed_command(EditLine
*el
, wint_t c
__attribute__((__unused__
)))
819 wchar_t tmpbuf
[EL_BUFSIZ
];
822 tmplen
= c_gets(el
, tmpbuf
, L
"\n: ");
823 terminal__putc(el
, '\n');
825 if (tmplen
< 0 || (tmpbuf
[tmplen
] = 0, parse_line(el
, tmpbuf
)) == -1)
828 el
->el_map
.current
= el
->el_map
.key
;
829 re_clear_display(el
);