Home | History | Annotate | Line # | Download | only in libedit
      1 /*	$NetBSD: common.c,v 1.50 2024/06/30 16:29:42 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Christos Zoulas of Cornell University.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     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.
     21  *
     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
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include "config.h"
     36 #if !defined(lint) && !defined(SCCSID)
     37 #if 0
     38 static char sccsid[] = "@(#)common.c	8.1 (Berkeley) 6/4/93";
     39 #else
     40 __RCSID("$NetBSD: common.c,v 1.50 2024/06/30 16:29:42 christos Exp $");
     41 #endif
     42 #endif /* not lint && not SCCSID */
     43 
     44 /*
     45  * common.c: Common Editor functions
     46  */
     47 #include <ctype.h>
     48 #include <string.h>
     49 
     50 #include "el.h"
     51 #include "common.h"
     52 #include "fcns.h"
     53 #include "parse.h"
     54 #include "vi.h"
     55 
     56 /* ed_end_of_file():
     57  *	Indicate end of file
     58  *	[^D]
     59  */
     60 libedit_private el_action_t
     61 /*ARGSUSED*/
     62 ed_end_of_file(EditLine *el, wint_t c __attribute__((__unused__)))
     63 {
     64 
     65 	re_goto_bottom(el);
     66 	*el->el_line.lastchar = '\0';
     67 	return CC_EOF;
     68 }
     69 
     70 
     71 /* ed_insert():
     72  *	Add character to the line
     73  *	Insert a character [bound to all insert keys]
     74  */
     75 libedit_private el_action_t
     76 ed_insert(EditLine *el, wint_t c)
     77 {
     78 	int count = el->el_state.argument;
     79 
     80 	if (c == '\0')
     81 		return CC_ERROR;
     82 
     83 	if (el->el_line.lastchar + el->el_state.argument >=
     84 	    el->el_line.limit) {
     85 		/* end of buffer space, try to allocate more */
     86 		if (!ch_enlargebufs(el, (size_t) count))
     87 			return CC_ERROR;	/* error allocating more */
     88 	}
     89 
     90 	if (count == 1) {
     91 		if (el->el_state.inputmode == MODE_INSERT
     92 		    || el->el_line.cursor >= el->el_line.lastchar)
     93 			c_insert(el, 1);
     94 
     95 		*el->el_line.cursor++ = c;
     96 		re_fastaddc(el);		/* fast refresh for one char. */
     97 	} else {
     98 		if (el->el_state.inputmode != MODE_REPLACE_1)
     99 			c_insert(el, el->el_state.argument);
    100 
    101 		while (count-- && el->el_line.cursor < el->el_line.lastchar)
    102 			*el->el_line.cursor++ = c;
    103 		re_refresh(el);
    104 	}
    105 
    106 	if (el->el_state.inputmode == MODE_REPLACE_1)
    107 		return vi_command_mode(el, 0);
    108 
    109 	return CC_NORM;
    110 }
    111 
    112 
    113 /* ed_delete_prev_word():
    114  *	Delete from beginning of current word to cursor
    115  *	[M-^?] [^W]
    116  */
    117 libedit_private el_action_t
    118 /*ARGSUSED*/
    119 ed_delete_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
    120 {
    121 	wchar_t *cp, *p, *kp;
    122 
    123 	if (el->el_line.cursor == el->el_line.buffer)
    124 		return CC_ERROR;
    125 
    126 	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
    127 	    el->el_state.argument, ce__isword);
    128 
    129 	for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
    130 		*kp++ = *p;
    131 	el->el_chared.c_kill.last = kp;
    132 
    133 	c_delbefore(el, (int)(el->el_line.cursor - cp));/* delete before dot */
    134 	el->el_line.cursor = cp;
    135 	if (el->el_line.cursor < el->el_line.buffer)
    136 		el->el_line.cursor = el->el_line.buffer; /* bounds check */
    137 	return CC_REFRESH;
    138 }
    139 
    140 
    141 /* ed_delete_next_char():
    142  *	Delete character under cursor
    143  *	[^D] [x]
    144  */
    145 libedit_private el_action_t
    146 /*ARGSUSED*/
    147 ed_delete_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
    148 {
    149 #ifdef DEBUG_EDIT
    150 #define	EL	el->el_line
    151 	(void) fprintf(el->el_errfile,
    152 	    "\nD(b: %p(%ls)  c: %p(%ls) last: %p(%ls) limit: %p(%ls)\n",
    153 	    EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
    154 	    EL.lastchar, EL.limit, EL.limit);
    155 #endif
    156 	if (el->el_line.cursor == el->el_line.lastchar) {
    157 			/* if I'm at the end */
    158 		if (el->el_map.type == MAP_VI) {
    159 			if (el->el_line.cursor == el->el_line.buffer) {
    160 				/* if I'm also at the beginning */
    161 #ifdef KSHVI
    162 				return CC_ERROR;
    163 #else
    164 				/* then do an EOF */
    165 				terminal_writec(el, c);
    166 				return CC_EOF;
    167 #endif
    168 			} else {
    169 #ifdef KSHVI
    170 				el->el_line.cursor--;
    171 #else
    172 				return CC_ERROR;
    173 #endif
    174 			}
    175 		} else
    176 				return CC_ERROR;
    177 	}
    178 	c_delafter(el, el->el_state.argument);	/* delete after dot */
    179 	if (el->el_map.type == MAP_VI &&
    180 	    el->el_line.cursor >= el->el_line.lastchar &&
    181 	    el->el_line.cursor > el->el_line.buffer)
    182 			/* bounds check */
    183 		el->el_line.cursor = el->el_line.lastchar - 1;
    184 	return CC_REFRESH;
    185 }
    186 
    187 
    188 /* ed_kill_line():
    189  *	Cut to the end of line
    190  *	[^K] [^K]
    191  */
    192 libedit_private el_action_t
    193 /*ARGSUSED*/
    194 ed_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
    195 {
    196 	wchar_t *kp, *cp;
    197 
    198 	cp = el->el_line.cursor;
    199 	kp = el->el_chared.c_kill.buf;
    200 	while (cp < el->el_line.lastchar)
    201 		*kp++ = *cp++;	/* copy it */
    202 	el->el_chared.c_kill.last = kp;
    203 			/* zap! -- delete to end */
    204 	el->el_line.lastchar = el->el_line.cursor;
    205 	return CC_REFRESH;
    206 }
    207 
    208 
    209 /* ed_move_to_end():
    210  *	Move cursor to the end of line
    211  *	[^E] [^E]
    212  */
    213 libedit_private el_action_t
    214 /*ARGSUSED*/
    215 ed_move_to_end(EditLine *el, wint_t c __attribute__((__unused__)))
    216 {
    217 
    218 	el->el_line.cursor = el->el_line.lastchar;
    219 	if (el->el_map.type == MAP_VI) {
    220 		if (el->el_chared.c_vcmd.action != NOP) {
    221 			cv_delfini(el);
    222 			return CC_REFRESH;
    223 		}
    224 #ifdef VI_MOVE
    225 		if (el->el_line.cursor > el->el_line.buffer)
    226 			el->el_line.cursor--;
    227 #endif
    228 	}
    229 	return CC_CURSOR;
    230 }
    231 
    232 
    233 /* ed_move_to_beg():
    234  *	Move cursor to the beginning of line
    235  *	[^A] [^A]
    236  */
    237 libedit_private el_action_t
    238 /*ARGSUSED*/
    239 ed_move_to_beg(EditLine *el, wint_t c __attribute__((__unused__)))
    240 {
    241 
    242 	el->el_line.cursor = el->el_line.buffer;
    243 
    244 	if (el->el_map.type == MAP_VI) {
    245 			/* We want FIRST non space character */
    246 		while (iswspace(*el->el_line.cursor))
    247 			el->el_line.cursor++;
    248 		if (el->el_chared.c_vcmd.action != NOP) {
    249 			cv_delfini(el);
    250 			return CC_REFRESH;
    251 		}
    252 	}
    253 	return CC_CURSOR;
    254 }
    255 
    256 
    257 /* ed_transpose_chars():
    258  *	Exchange the character to the left of the cursor with the one under it
    259  *	[^T] [^T]
    260  */
    261 libedit_private el_action_t
    262 ed_transpose_chars(EditLine *el, wint_t c)
    263 {
    264 
    265 	if (el->el_line.cursor < el->el_line.lastchar) {
    266 		if (el->el_line.lastchar <= &el->el_line.buffer[1])
    267 			return CC_ERROR;
    268 		else
    269 			el->el_line.cursor++;
    270 	}
    271 	if (el->el_line.cursor > &el->el_line.buffer[1]) {
    272 		/* must have at least two chars entered */
    273 		c = el->el_line.cursor[-2];
    274 		el->el_line.cursor[-2] = el->el_line.cursor[-1];
    275 		el->el_line.cursor[-1] = c;
    276 		return CC_REFRESH;
    277 	} else
    278 		return CC_ERROR;
    279 }
    280 
    281 
    282 /* ed_next_char():
    283  *	Move to the right one character
    284  *	[^F] [^F]
    285  */
    286 libedit_private el_action_t
    287 /*ARGSUSED*/
    288 ed_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
    289 {
    290 	wchar_t *lim = el->el_line.lastchar;
    291 
    292 	if (el->el_line.cursor >= lim ||
    293 	    (el->el_line.cursor == lim - 1 &&
    294 	    el->el_map.type == MAP_VI &&
    295 	    el->el_chared.c_vcmd.action == NOP))
    296 		return CC_ERROR;
    297 
    298 	el->el_line.cursor += el->el_state.argument;
    299 	if (el->el_line.cursor > lim)
    300 		el->el_line.cursor = lim;
    301 
    302 	if (el->el_map.type == MAP_VI)
    303 		if (el->el_chared.c_vcmd.action != NOP) {
    304 			cv_delfini(el);
    305 			return CC_REFRESH;
    306 		}
    307 	return CC_CURSOR;
    308 }
    309 
    310 
    311 /* ed_prev_word():
    312  *	Move to the beginning of the current word
    313  *	[M-b] [b]
    314  */
    315 libedit_private el_action_t
    316 /*ARGSUSED*/
    317 ed_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
    318 {
    319 
    320 	if (el->el_line.cursor == el->el_line.buffer)
    321 		return CC_ERROR;
    322 
    323 	el->el_line.cursor = c__prev_word(el->el_line.cursor,
    324 	    el->el_line.buffer,
    325 	    el->el_state.argument,
    326 	    ce__isword);
    327 
    328 	if (el->el_map.type == MAP_VI)
    329 		if (el->el_chared.c_vcmd.action != NOP) {
    330 			cv_delfini(el);
    331 			return CC_REFRESH;
    332 		}
    333 	return CC_CURSOR;
    334 }
    335 
    336 
    337 /* ed_prev_char():
    338  *	Move to the left one character
    339  *	[^B] [^B]
    340  */
    341 libedit_private el_action_t
    342 /*ARGSUSED*/
    343 ed_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
    344 {
    345 
    346 	if (el->el_line.cursor > el->el_line.buffer) {
    347 		el->el_line.cursor -= el->el_state.argument;
    348 		if (el->el_line.cursor < el->el_line.buffer)
    349 			el->el_line.cursor = el->el_line.buffer;
    350 
    351 		if (el->el_map.type == MAP_VI)
    352 			if (el->el_chared.c_vcmd.action != NOP) {
    353 				cv_delfini(el);
    354 				return CC_REFRESH;
    355 			}
    356 		return CC_CURSOR;
    357 	} else
    358 		return CC_ERROR;
    359 }
    360 
    361 
    362 /* ed_quoted_insert():
    363  *	Add the next character typed verbatim
    364  *	[^V] [^V]
    365  */
    366 libedit_private el_action_t
    367 /*ARGSUSED*/
    368 ed_quoted_insert(EditLine *el, wint_t c __attribute__((__unused__)))
    369 {
    370 	int num;
    371 	wchar_t ch;
    372 
    373 	tty_quotemode(el);
    374 	num = el_wgetc(el, &ch);
    375 	tty_noquotemode(el);
    376 	if (num == 1)
    377 		return ed_insert(el, ch);
    378 	else
    379 		return ed_end_of_file(el, 0);
    380 }
    381 
    382 
    383 /* ed_digit():
    384  *	Adds to argument or enters a digit
    385  */
    386 libedit_private el_action_t
    387 ed_digit(EditLine *el, wint_t c)
    388 {
    389 
    390 	if (!iswdigit(c))
    391 		return CC_ERROR;
    392 
    393 	if (el->el_state.doingarg) {
    394 			/* if doing an arg, add this in... */
    395 		if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
    396 			el->el_state.argument = c - '0';
    397 		else {
    398 			if (el->el_state.argument > 1000000)
    399 				return CC_ERROR;
    400 			el->el_state.argument =
    401 			    (el->el_state.argument * 10) + (c - '0');
    402 		}
    403 		return CC_ARGHACK;
    404 	}
    405 
    406 	return ed_insert(el, c);
    407 }
    408 
    409 
    410 /* ed_argument_digit():
    411  *	Digit that starts argument
    412  *	For ESC-n
    413  */
    414 libedit_private el_action_t
    415 ed_argument_digit(EditLine *el, wint_t c)
    416 {
    417 
    418 	if (!iswdigit(c))
    419 		return CC_ERROR;
    420 
    421 	if (el->el_state.doingarg) {
    422 		if (el->el_state.argument > 1000000)
    423 			return CC_ERROR;
    424 		el->el_state.argument = (el->el_state.argument * 10) +
    425 		    (c - '0');
    426 	} else {		/* else starting an argument */
    427 		el->el_state.argument = c - '0';
    428 		el->el_state.doingarg = 1;
    429 	}
    430 	return CC_ARGHACK;
    431 }
    432 
    433 
    434 /* ed_unassigned():
    435  *	Indicates unbound character
    436  *	Bound to keys that are not assigned
    437  */
    438 libedit_private el_action_t
    439 /*ARGSUSED*/
    440 ed_unassigned(EditLine *el __attribute__((__unused__)),
    441     wint_t c __attribute__((__unused__)))
    442 {
    443 
    444 	return CC_ERROR;
    445 }
    446 
    447 
    448 /* ed_ignore():
    449  *	Input characters that have no effect
    450  *	[^C ^O ^Q ^S ^Z ^\ ^]] [^C ^O ^Q ^S ^\]
    451  */
    452 libedit_private el_action_t
    453 /*ARGSUSED*/
    454 ed_ignore(EditLine *el __attribute__((__unused__)),
    455 	      wint_t c __attribute__((__unused__)))
    456 {
    457 
    458 	return CC_NORM;
    459 }
    460 
    461 
    462 /* ed_newline():
    463  *	Execute command
    464  *	[^J]
    465  */
    466 libedit_private el_action_t
    467 /*ARGSUSED*/
    468 ed_newline(EditLine *el, wint_t c __attribute__((__unused__)))
    469 {
    470 
    471 	re_goto_bottom(el);
    472 	*el->el_line.lastchar++ = '\n';
    473 	*el->el_line.lastchar = '\0';
    474 	return CC_NEWLINE;
    475 }
    476 
    477 
    478 /* ed_delete_prev_char():
    479  *	Delete the character to the left of the cursor
    480  *	[^?]
    481  */
    482 libedit_private el_action_t
    483 /*ARGSUSED*/
    484 ed_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
    485 {
    486 
    487 	if (el->el_line.cursor <= el->el_line.buffer)
    488 		return CC_ERROR;
    489 
    490 	c_delbefore(el, el->el_state.argument);
    491 	el->el_line.cursor -= el->el_state.argument;
    492 	if (el->el_line.cursor < el->el_line.buffer)
    493 		el->el_line.cursor = el->el_line.buffer;
    494 	return CC_REFRESH;
    495 }
    496 
    497 
    498 /* ed_clear_screen():
    499  *	Clear screen leaving current line at the top
    500  *	[^L]
    501  */
    502 libedit_private el_action_t
    503 /*ARGSUSED*/
    504 ed_clear_screen(EditLine *el, wint_t c __attribute__((__unused__)))
    505 {
    506 
    507 	terminal_clear_screen(el);	/* clear the whole real screen */
    508 	re_clear_display(el);	/* reset everything */
    509 	return CC_REFRESH;
    510 }
    511 
    512 
    513 /* ed_redisplay():
    514  *	Redisplay everything
    515  *	^R
    516  */
    517 libedit_private el_action_t
    518 /*ARGSUSED*/
    519 ed_redisplay(EditLine *el __attribute__((__unused__)),
    520 	     wint_t c __attribute__((__unused__)))
    521 {
    522 
    523 	return CC_REDISPLAY;
    524 }
    525 
    526 
    527 /* ed_start_over():
    528  *	Erase current line and start from scratch
    529  *	[^G]
    530  */
    531 libedit_private el_action_t
    532 /*ARGSUSED*/
    533 ed_start_over(EditLine *el, wint_t c __attribute__((__unused__)))
    534 {
    535 
    536 	ch_reset(el);
    537 	return CC_REFRESH;
    538 }
    539 
    540 
    541 /* ed_sequence_lead_in():
    542  *	First character in a bound sequence
    543  *	Placeholder for external keys
    544  */
    545 libedit_private el_action_t
    546 /*ARGSUSED*/
    547 ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
    548 		    wint_t c __attribute__((__unused__)))
    549 {
    550 
    551 	return CC_NORM;
    552 }
    553 
    554 
    555 /* ed_prev_history():
    556  *	Move to the previous history line
    557  *	[^P] [k]
    558  */
    559 libedit_private el_action_t
    560 /*ARGSUSED*/
    561 ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
    562 {
    563 	char beep = 0;
    564 	int sv_event = el->el_history.eventno;
    565 
    566 	el->el_chared.c_undo.len = -1;
    567 	*el->el_line.lastchar = '\0';		/* just in case */
    568 
    569 	if (el->el_history.eventno == 0) {	/* save the current buffer
    570 						 * away */
    571 		(void) wcsncpy(el->el_history.buf, el->el_line.buffer,
    572 		    EL_BUFSIZ);
    573 		el->el_history.last = el->el_history.buf +
    574 		    (el->el_line.lastchar - el->el_line.buffer);
    575 	}
    576 	el->el_history.eventno += el->el_state.argument;
    577 
    578 	if (hist_get(el) == CC_ERROR) {
    579 		if (el->el_map.type == MAP_VI) {
    580 			el->el_history.eventno = sv_event;
    581 		}
    582 		beep = 1;
    583 		/* el->el_history.eventno was fixed by first call */
    584 		(void) hist_get(el);
    585 	}
    586 	if (beep)
    587 		return CC_REFRESH_BEEP;
    588 	return CC_REFRESH;
    589 }
    590 
    591 
    592 /* ed_next_history():
    593  *	Move to the next history line
    594  *	[^N] [j]
    595  */
    596 libedit_private el_action_t
    597 /*ARGSUSED*/
    598 ed_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
    599 {
    600 	el_action_t beep = CC_REFRESH, rval;
    601 
    602 	el->el_chared.c_undo.len = -1;
    603 	*el->el_line.lastchar = '\0';	/* just in case */
    604 
    605 	el->el_history.eventno -= el->el_state.argument;
    606 
    607 	if (el->el_history.eventno < 0) {
    608 		el->el_history.eventno = 0;
    609 		beep = CC_REFRESH_BEEP;
    610 	}
    611 	rval = hist_get(el);
    612 	if (rval == CC_REFRESH)
    613 		return beep;
    614 	return rval;
    615 
    616 }
    617 
    618 
    619 /* ed_search_prev_history():
    620  *	Search previous in history for a line matching the current
    621  *	next search history [M-P] [K]
    622  */
    623 libedit_private el_action_t
    624 /*ARGSUSED*/
    625 ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
    626 {
    627 	const wchar_t *hp;
    628 	int h;
    629 	int found = 0;
    630 
    631 	el->el_chared.c_vcmd.action = NOP;
    632 	el->el_chared.c_undo.len = -1;
    633 	*el->el_line.lastchar = '\0';	/* just in case */
    634 	if (el->el_history.eventno < 0) {
    635 #ifdef DEBUG_EDIT
    636 		(void) fprintf(el->el_errfile,
    637 		    "e_prev_search_hist(): eventno < 0;\n");
    638 #endif
    639 		el->el_history.eventno = 0;
    640 		return CC_ERROR;
    641 	}
    642 	if (el->el_history.eventno == 0) {
    643 		(void) wcsncpy(el->el_history.buf, el->el_line.buffer,
    644 		    EL_BUFSIZ);
    645 		el->el_history.last = el->el_history.buf +
    646 		    (el->el_line.lastchar - el->el_line.buffer);
    647 	}
    648 	if (el->el_history.ref == NULL)
    649 		return CC_ERROR;
    650 
    651 	hp = HIST_FIRST(el);
    652 	if (hp == NULL)
    653 		return CC_ERROR;
    654 
    655 	c_setpat(el);		/* Set search pattern !! */
    656 
    657 	for (h = 1; h <= el->el_history.eventno; h++)
    658 		hp = HIST_NEXT(el);
    659 
    660 	while (hp != NULL) {
    661 #ifdef SDEBUG
    662 		(void) fprintf(el->el_errfile, "Comparing with \"%ls\"\n", hp);
    663 #endif
    664 		if ((wcsncmp(hp, el->el_line.buffer, (size_t)
    665 			    (el->el_line.lastchar - el->el_line.buffer)) ||
    666 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
    667 		    c_hmatch(el, hp)) {
    668 			found = 1;
    669 			break;
    670 		}
    671 		h++;
    672 		hp = HIST_NEXT(el);
    673 	}
    674 
    675 	if (!found) {
    676 #ifdef SDEBUG
    677 		(void) fprintf(el->el_errfile, "not found\n");
    678 #endif
    679 		return CC_ERROR;
    680 	}
    681 	el->el_history.eventno = h;
    682 
    683 	return hist_get(el);
    684 }
    685 
    686 
    687 /* ed_search_next_history():
    688  *	Search next in history for a line matching the current
    689  *	[M-N] [J]
    690  */
    691 libedit_private el_action_t
    692 /*ARGSUSED*/
    693 ed_search_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
    694 {
    695 	const wchar_t *hp;
    696 	int h;
    697 	int found = 0;
    698 
    699 	el->el_chared.c_vcmd.action = NOP;
    700 	el->el_chared.c_undo.len = -1;
    701 	*el->el_line.lastchar = '\0';	/* just in case */
    702 
    703 	if (el->el_history.eventno == 0)
    704 		return CC_ERROR;
    705 
    706 	if (el->el_history.ref == NULL)
    707 		return CC_ERROR;
    708 
    709 	hp = HIST_FIRST(el);
    710 	if (hp == NULL)
    711 		return CC_ERROR;
    712 
    713 	c_setpat(el);		/* Set search pattern !! */
    714 
    715 	for (h = 1; h < el->el_history.eventno && hp; h++) {
    716 #ifdef SDEBUG
    717 		(void) fprintf(el->el_errfile, "Comparing with \"%ls\"\n", hp);
    718 #endif
    719 		if ((wcsncmp(hp, el->el_line.buffer, (size_t)
    720 			    (el->el_line.lastchar - el->el_line.buffer)) ||
    721 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
    722 		    c_hmatch(el, hp))
    723 			found = h;
    724 		hp = HIST_NEXT(el);
    725 	}
    726 
    727 	if (!found) {		/* is it the current history number? */
    728 		if (!c_hmatch(el, el->el_history.buf)) {
    729 #ifdef SDEBUG
    730 			(void) fprintf(el->el_errfile, "not found\n");
    731 #endif
    732 			return CC_ERROR;
    733 		}
    734 	}
    735 	el->el_history.eventno = found;
    736 
    737 	return hist_get(el);
    738 }
    739 
    740 
    741 /* ed_prev_line():
    742  *	Move up one line
    743  *	Could be [k] [^p]
    744  */
    745 libedit_private el_action_t
    746 /*ARGSUSED*/
    747 ed_prev_line(EditLine *el, wint_t c __attribute__((__unused__)))
    748 {
    749 	wchar_t *ptr;
    750 	int nchars = c_hpos(el);
    751 
    752 	/*
    753          * Move to the line requested
    754          */
    755 	if (*(ptr = el->el_line.cursor) == '\n')
    756 		ptr--;
    757 
    758 	for (; ptr >= el->el_line.buffer; ptr--)
    759 		if (*ptr == '\n' && --el->el_state.argument <= 0)
    760 			break;
    761 
    762 	if (el->el_state.argument > 0)
    763 		return CC_ERROR;
    764 
    765 	/*
    766          * Move to the beginning of the line
    767          */
    768 	for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
    769 		continue;
    770 
    771 	/*
    772          * Move to the character requested
    773          */
    774 	for (ptr++;
    775 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
    776 	    ptr++)
    777 		continue;
    778 
    779 	el->el_line.cursor = ptr;
    780 	return CC_CURSOR;
    781 }
    782 
    783 
    784 /* ed_next_line():
    785  *	Move down one line
    786  *	Could be [j] [^n]
    787  */
    788 libedit_private el_action_t
    789 /*ARGSUSED*/
    790 ed_next_line(EditLine *el, wint_t c __attribute__((__unused__)))
    791 {
    792 	wchar_t *ptr;
    793 	int nchars = c_hpos(el);
    794 
    795 	/*
    796          * Move to the line requested
    797          */
    798 	for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
    799 		if (*ptr == '\n' && --el->el_state.argument <= 0)
    800 			break;
    801 
    802 	if (el->el_state.argument > 0)
    803 		return CC_ERROR;
    804 
    805 	/*
    806          * Move to the character requested
    807          */
    808 	for (ptr++;
    809 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
    810 	    ptr++)
    811 		continue;
    812 
    813 	el->el_line.cursor = ptr;
    814 	return CC_CURSOR;
    815 }
    816 
    817 
    818 /* ed_command():
    819  *	Editline extended command
    820  *	[M-X] [:]
    821  */
    822 libedit_private el_action_t
    823 /*ARGSUSED*/
    824 ed_command(EditLine *el, wint_t c __attribute__((__unused__)))
    825 {
    826 	wchar_t tmpbuf[EL_BUFSIZ];
    827 	int tmplen;
    828 
    829 	tmplen = c_gets(el, tmpbuf, L"\n: ");
    830 	terminal__putc(el, '\n');
    831 
    832 	if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
    833 		terminal_beep(el);
    834 
    835 	el->el_map.current = el->el_map.key;
    836 	re_clear_display(el);
    837 	return CC_REFRESH;
    838 }
    839