Home | History | Annotate | Line # | Download | only in libedit
common.c revision 1.11
      1 /*	$NetBSD: common.c,v 1.11 2002/03/18 16:00:51 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. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  */
     38 
     39 #include "config.h"
     40 #if !defined(lint) && !defined(SCCSID)
     41 #if 0
     42 static char sccsid[] = "@(#)common.c	8.1 (Berkeley) 6/4/93";
     43 #else
     44 __RCSID("$NetBSD: common.c,v 1.11 2002/03/18 16:00:51 christos Exp $");
     45 #endif
     46 #endif /* not lint && not SCCSID */
     47 
     48 /*
     49  * common.c: Common Editor functions
     50  */
     51 #include "el.h"
     52 
     53 /* ed_end_of_file():
     54  *	Indicate end of file
     55  *	[^D]
     56  */
     57 protected el_action_t
     58 /*ARGSUSED*/
     59 ed_end_of_file(EditLine *el, int c)
     60 {
     61 
     62 	re_goto_bottom(el);
     63 	*el->el_line.lastchar = '\0';
     64 	return (CC_EOF);
     65 }
     66 
     67 
     68 /* ed_insert():
     69  *	Add character to the line
     70  *	Insert a character [bound to all insert keys]
     71  */
     72 protected el_action_t
     73 ed_insert(EditLine *el, int c)
     74 {
     75 	int i;
     76 
     77 	if (c == '\0')
     78 		return (CC_ERROR);
     79 
     80 	if (el->el_line.lastchar + el->el_state.argument >=
     81 	    el->el_line.limit) {
     82 		/* end of buffer space, try to allocate more */
     83 		if (!ch_enlargebufs(el, (size_t) el->el_state.argument))
     84 			return CC_ERROR;	/* error allocating more */
     85 	}
     86 
     87 	if (el->el_state.argument == 1) {
     88 		if (el->el_state.inputmode != MODE_INSERT) {
     89 			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] =
     90 			    *el->el_line.cursor;
     91 			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] =
     92 			    '\0';
     93 			c_delafter(el, 1);
     94 		}
     95 		c_insert(el, 1);
     96 
     97 		*el->el_line.cursor++ = c;
     98 		el->el_state.doingarg = 0;	/* just in case */
     99 		re_fastaddc(el);		/* fast refresh for one char. */
    100 	} else {
    101 		if (el->el_state.inputmode != MODE_INSERT) {
    102 			for (i = 0; i < el->el_state.argument; i++)
    103 				el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] =
    104 				    el->el_line.cursor[i];
    105 
    106 			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] =
    107 			    '\0';
    108 			c_delafter(el, el->el_state.argument);
    109 		}
    110 		c_insert(el, el->el_state.argument);
    111 
    112 		while (el->el_state.argument--)
    113 			*el->el_line.cursor++ = c;
    114 		re_refresh(el);
    115 	}
    116 
    117 	if (el->el_state.inputmode == MODE_REPLACE_1)
    118 		(void) vi_command_mode(el, 0);
    119 
    120 	return (CC_NORM);
    121 }
    122 
    123 
    124 /* ed_delete_prev_word():
    125  *	Delete from beginning of current word to cursor
    126  *	[M-^?] [^W]
    127  */
    128 protected el_action_t
    129 /*ARGSUSED*/
    130 ed_delete_prev_word(EditLine *el, int c)
    131 {
    132 	char *cp, *p, *kp;
    133 
    134 	if (el->el_line.cursor == el->el_line.buffer)
    135 		return (CC_ERROR);
    136 
    137 	cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
    138 	    el->el_state.argument, ce__isword);
    139 
    140 	for (p = cp, kp = el->el_chared.c_kill.buf; p < el->el_line.cursor; p++)
    141 		*kp++ = *p;
    142 	el->el_chared.c_kill.last = kp;
    143 
    144 	c_delbefore(el, el->el_line.cursor - cp);	/* delete before dot */
    145 	el->el_line.cursor = cp;
    146 	if (el->el_line.cursor < el->el_line.buffer)
    147 		el->el_line.cursor = el->el_line.buffer; /* bounds check */
    148 	return (CC_REFRESH);
    149 }
    150 
    151 
    152 /* ed_delete_next_char():
    153  *	Delete character under cursor
    154  *	[^D] [x]
    155  */
    156 protected el_action_t
    157 /*ARGSUSED*/
    158 ed_delete_next_char(EditLine *el, int c)
    159 {
    160 #ifdef notdef			/* XXX */
    161 #define	EL	el->el_line
    162 	(void) fprintf(el->el_errlfile,
    163 	    "\nD(b: %x(%s)  c: %x(%s) last: %x(%s) limit: %x(%s)\n",
    164 	    EL.buffer, EL.buffer, EL.cursor, EL.cursor, EL.lastchar,
    165 	    EL.lastchar, EL.limit, EL.limit);
    166 #endif
    167 	if (el->el_line.cursor == el->el_line.lastchar) {
    168 			/* if I'm at the end */
    169 		if (el->el_map.type == MAP_VI) {
    170 			if (el->el_line.cursor == el->el_line.buffer) {
    171 				/* if I'm also at the beginning */
    172 #ifdef KSHVI
    173 				return (CC_ERROR);
    174 #else
    175 				term_overwrite(el, STReof, 4);
    176 					/* then do a EOF */
    177 				term__flush();
    178 				return (CC_EOF);
    179 #endif
    180 			} else {
    181 #ifdef KSHVI
    182 				el->el_line.cursor--;
    183 #else
    184 				return (CC_ERROR);
    185 #endif
    186 			}
    187 		} else {
    188 			if (el->el_line.cursor != el->el_line.buffer)
    189 				el->el_line.cursor--;
    190 			else
    191 				return (CC_ERROR);
    192 		}
    193 	}
    194 	c_delafter(el, el->el_state.argument);	/* delete after dot */
    195 	if (el->el_line.cursor >= el->el_line.lastchar &&
    196 	    el->el_line.cursor > el->el_line.buffer)
    197 			/* bounds check */
    198 		el->el_line.cursor = el->el_line.lastchar - 1;
    199 	return (CC_REFRESH);
    200 }
    201 
    202 
    203 /* ed_kill_line():
    204  *	Cut to the end of line
    205  *	[^K] [^K]
    206  */
    207 protected el_action_t
    208 /*ARGSUSED*/
    209 ed_kill_line(EditLine *el, int c)
    210 {
    211 	char *kp, *cp;
    212 
    213 	cp = el->el_line.cursor;
    214 	kp = el->el_chared.c_kill.buf;
    215 	while (cp < el->el_line.lastchar)
    216 		*kp++ = *cp++;	/* copy it */
    217 	el->el_chared.c_kill.last = kp;
    218 			/* zap! -- delete to end */
    219 	el->el_line.lastchar = el->el_line.cursor;
    220 	return (CC_REFRESH);
    221 }
    222 
    223 
    224 /* ed_move_to_end():
    225  *	Move cursor to the end of line
    226  *	[^E] [^E]
    227  */
    228 protected el_action_t
    229 /*ARGSUSED*/
    230 ed_move_to_end(EditLine *el, int c)
    231 {
    232 
    233 	el->el_line.cursor = el->el_line.lastchar;
    234 	if (el->el_map.type == MAP_VI) {
    235 #ifdef VI_MOVE
    236 		el->el_line.cursor--;
    237 #endif
    238 		if (el->el_chared.c_vcmd.action & DELETE) {
    239 			cv_delfini(el);
    240 			return (CC_REFRESH);
    241 		}
    242 	}
    243 	return (CC_CURSOR);
    244 }
    245 
    246 
    247 /* ed_move_to_beg():
    248  *	Move cursor to the beginning of line
    249  *	[^A] [^A]
    250  */
    251 protected el_action_t
    252 /*ARGSUSED*/
    253 ed_move_to_beg(EditLine *el, int c)
    254 {
    255 
    256 	el->el_line.cursor = el->el_line.buffer;
    257 
    258 	if (el->el_map.type == MAP_VI) {
    259 			/* We want FIRST non space character */
    260 		while (isspace((unsigned char) *el->el_line.cursor))
    261 			el->el_line.cursor++;
    262 		if (el->el_chared.c_vcmd.action & DELETE) {
    263 			cv_delfini(el);
    264 			return (CC_REFRESH);
    265 		}
    266 	}
    267 	return (CC_CURSOR);
    268 }
    269 
    270 
    271 /* ed_transpose_chars():
    272  *	Exchange the character to the left of the cursor with the one under it
    273  *	[^T] [^T]
    274  */
    275 protected el_action_t
    276 ed_transpose_chars(EditLine *el, int c)
    277 {
    278 
    279 	if (el->el_line.cursor < el->el_line.lastchar) {
    280 		if (el->el_line.lastchar <= &el->el_line.buffer[1])
    281 			return (CC_ERROR);
    282 		else
    283 			el->el_line.cursor++;
    284 	}
    285 	if (el->el_line.cursor > &el->el_line.buffer[1]) {
    286 		/* must have at least two chars entered */
    287 		c = el->el_line.cursor[-2];
    288 		el->el_line.cursor[-2] = el->el_line.cursor[-1];
    289 		el->el_line.cursor[-1] = c;
    290 		return (CC_REFRESH);
    291 	} else
    292 		return (CC_ERROR);
    293 }
    294 
    295 
    296 /* ed_next_char():
    297  *	Move to the right one character
    298  *	[^F] [^F]
    299  */
    300 protected el_action_t
    301 /*ARGSUSED*/
    302 ed_next_char(EditLine *el, int c)
    303 {
    304 
    305 	if (el->el_line.cursor >= el->el_line.lastchar)
    306 		return (CC_ERROR);
    307 
    308 	el->el_line.cursor += el->el_state.argument;
    309 	if (el->el_line.cursor > el->el_line.lastchar)
    310 		el->el_line.cursor = el->el_line.lastchar;
    311 
    312 	if (el->el_map.type == MAP_VI)
    313 		if (el->el_chared.c_vcmd.action & DELETE) {
    314 			cv_delfini(el);
    315 			return (CC_REFRESH);
    316 		}
    317 	return (CC_CURSOR);
    318 }
    319 
    320 
    321 /* ed_prev_word():
    322  *	Move to the beginning of the current word
    323  *	[M-b] [b]
    324  */
    325 protected el_action_t
    326 /*ARGSUSED*/
    327 ed_prev_word(EditLine *el, int c)
    328 {
    329 
    330 	if (el->el_line.cursor == el->el_line.buffer)
    331 		return (CC_ERROR);
    332 
    333 	el->el_line.cursor = c__prev_word(el->el_line.cursor,
    334 	    el->el_line.buffer,
    335 	    el->el_state.argument,
    336 	    ce__isword);
    337 
    338 	if (el->el_map.type == MAP_VI)
    339 		if (el->el_chared.c_vcmd.action & DELETE) {
    340 			cv_delfini(el);
    341 			return (CC_REFRESH);
    342 		}
    343 	return (CC_CURSOR);
    344 }
    345 
    346 
    347 /* ed_prev_char():
    348  *	Move to the left one character
    349  *	[^B] [^B]
    350  */
    351 protected el_action_t
    352 /*ARGSUSED*/
    353 ed_prev_char(EditLine *el, int c)
    354 {
    355 
    356 	if (el->el_line.cursor > el->el_line.buffer) {
    357 		el->el_line.cursor -= el->el_state.argument;
    358 		if (el->el_line.cursor < el->el_line.buffer)
    359 			el->el_line.cursor = el->el_line.buffer;
    360 
    361 		if (el->el_map.type == MAP_VI)
    362 			if (el->el_chared.c_vcmd.action & DELETE) {
    363 				cv_delfini(el);
    364 				return (CC_REFRESH);
    365 			}
    366 		return (CC_CURSOR);
    367 	} else
    368 		return (CC_ERROR);
    369 }
    370 
    371 
    372 /* ed_quoted_insert():
    373  *	Add the next character typed verbatim
    374  *	[^V] [^V]
    375  */
    376 protected el_action_t
    377 ed_quoted_insert(EditLine *el, int c)
    378 {
    379 	int num;
    380 	char tc;
    381 
    382 	tty_quotemode(el);
    383 	num = el_getc(el, &tc);
    384 	c = (unsigned char) tc;
    385 	tty_noquotemode(el);
    386 	if (num == 1)
    387 		return (ed_insert(el, c));
    388 	else
    389 		return (ed_end_of_file(el, 0));
    390 }
    391 
    392 
    393 /* ed_digit():
    394  *	Adds to argument or enters a digit
    395  */
    396 protected el_action_t
    397 ed_digit(EditLine *el, int c)
    398 {
    399 
    400 	if (!isdigit(c))
    401 		return (CC_ERROR);
    402 
    403 	if (el->el_state.doingarg) {
    404 			/* if doing an arg, add this in... */
    405 		if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
    406 			el->el_state.argument = c - '0';
    407 		else {
    408 			if (el->el_state.argument > 1000000)
    409 				return (CC_ERROR);
    410 			el->el_state.argument =
    411 			    (el->el_state.argument * 10) + (c - '0');
    412 		}
    413 		return (CC_ARGHACK);
    414 	} else {
    415 		if (el->el_line.lastchar + 1 >= el->el_line.limit) {
    416 			if (!ch_enlargebufs(el, 1))
    417 				return (CC_ERROR);
    418 		}
    419 
    420 		if (el->el_state.inputmode != MODE_INSERT) {
    421 			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize++] =
    422 			    *el->el_line.cursor;
    423 			el->el_chared.c_undo.buf[el->el_chared.c_undo.isize] =
    424 			    '\0';
    425 			c_delafter(el, 1);
    426 		}
    427 		c_insert(el, 1);
    428 		*el->el_line.cursor++ = c;
    429 		el->el_state.doingarg = 0;
    430 		re_fastaddc(el);
    431 	}
    432 	return (CC_NORM);
    433 }
    434 
    435 
    436 /* ed_argument_digit():
    437  *	Digit that starts argument
    438  *	For ESC-n
    439  */
    440 protected el_action_t
    441 ed_argument_digit(EditLine *el, int c)
    442 {
    443 
    444 	if (!isdigit(c))
    445 		return (CC_ERROR);
    446 
    447 	if (el->el_state.doingarg) {
    448 		if (el->el_state.argument > 1000000)
    449 			return (CC_ERROR);
    450 		el->el_state.argument = (el->el_state.argument * 10) +
    451 		    (c - '0');
    452 	} else {		/* else starting an argument */
    453 		el->el_state.argument = c - '0';
    454 		el->el_state.doingarg = 1;
    455 	}
    456 	return (CC_ARGHACK);
    457 }
    458 
    459 
    460 /* ed_unassigned():
    461  *	Indicates unbound character
    462  *	Bound to keys that are not assigned
    463  */
    464 protected el_action_t
    465 /*ARGSUSED*/
    466 ed_unassigned(EditLine *el, int c)
    467 {
    468 
    469 	term_beep(el);
    470 	term__flush();
    471 	return (CC_NORM);
    472 }
    473 
    474 
    475 /**
    476  ** TTY key handling.
    477  **/
    478 
    479 /* ed_tty_sigint():
    480  *	Tty interrupt character
    481  *	[^C]
    482  */
    483 protected el_action_t
    484 /*ARGSUSED*/
    485 ed_tty_sigint(EditLine *el, int c)
    486 {
    487 
    488 	return (CC_NORM);
    489 }
    490 
    491 
    492 /* ed_tty_dsusp():
    493  *	Tty delayed suspend character
    494  *	[^Y]
    495  */
    496 protected el_action_t
    497 /*ARGSUSED*/
    498 ed_tty_dsusp(EditLine *el, int c)
    499 {
    500 
    501 	return (CC_NORM);
    502 }
    503 
    504 
    505 /* ed_tty_flush_output():
    506  *	Tty flush output characters
    507  *	[^O]
    508  */
    509 protected el_action_t
    510 /*ARGSUSED*/
    511 ed_tty_flush_output(EditLine *el, int c)
    512 {
    513 
    514 	return (CC_NORM);
    515 }
    516 
    517 
    518 /* ed_tty_sigquit():
    519  *	Tty quit character
    520  *	[^\]
    521  */
    522 protected el_action_t
    523 /*ARGSUSED*/
    524 ed_tty_sigquit(EditLine *el, int c)
    525 {
    526 
    527 	return (CC_NORM);
    528 }
    529 
    530 
    531 /* ed_tty_sigtstp():
    532  *	Tty suspend character
    533  *	[^Z]
    534  */
    535 protected el_action_t
    536 /*ARGSUSED*/
    537 ed_tty_sigtstp(EditLine *el, int c)
    538 {
    539 
    540 	return (CC_NORM);
    541 }
    542 
    543 
    544 /* ed_tty_stop_output():
    545  *	Tty disallow output characters
    546  *	[^S]
    547  */
    548 protected el_action_t
    549 /*ARGSUSED*/
    550 ed_tty_stop_output(EditLine *el, int c)
    551 {
    552 
    553 	return (CC_NORM);
    554 }
    555 
    556 
    557 /* ed_tty_start_output():
    558  *	Tty allow output characters
    559  *	[^Q]
    560  */
    561 protected el_action_t
    562 /*ARGSUSED*/
    563 ed_tty_start_output(EditLine *el, int c)
    564 {
    565 
    566 	return (CC_NORM);
    567 }
    568 
    569 
    570 /* ed_newline():
    571  *	Execute command
    572  *	[^J]
    573  */
    574 protected el_action_t
    575 /*ARGSUSED*/
    576 ed_newline(EditLine *el, int c)
    577 {
    578 
    579 	re_goto_bottom(el);
    580 	*el->el_line.lastchar++ = '\n';
    581 	*el->el_line.lastchar = '\0';
    582 	if (el->el_map.type == MAP_VI)
    583 		el->el_chared.c_vcmd.ins = el->el_line.buffer;
    584 	return (CC_NEWLINE);
    585 }
    586 
    587 
    588 /* ed_delete_prev_char():
    589  *	Delete the character to the left of the cursor
    590  *	[^?]
    591  */
    592 protected el_action_t
    593 /*ARGSUSED*/
    594 ed_delete_prev_char(EditLine *el, int c)
    595 {
    596 
    597 	if (el->el_line.cursor <= el->el_line.buffer)
    598 		return (CC_ERROR);
    599 
    600 	c_delbefore(el, el->el_state.argument);
    601 	el->el_line.cursor -= el->el_state.argument;
    602 	if (el->el_line.cursor < el->el_line.buffer)
    603 		el->el_line.cursor = el->el_line.buffer;
    604 	return (CC_REFRESH);
    605 }
    606 
    607 
    608 /* ed_clear_screen():
    609  *	Clear screen leaving current line at the top
    610  *	[^L]
    611  */
    612 protected el_action_t
    613 /*ARGSUSED*/
    614 ed_clear_screen(EditLine *el, int c)
    615 {
    616 
    617 	term_clear_screen(el);	/* clear the whole real screen */
    618 	re_clear_display(el);	/* reset everything */
    619 	return (CC_REFRESH);
    620 }
    621 
    622 
    623 /* ed_redisplay():
    624  *	Redisplay everything
    625  *	^R
    626  */
    627 protected el_action_t
    628 /*ARGSUSED*/
    629 ed_redisplay(EditLine *el, int c)
    630 {
    631 
    632 	return (CC_REDISPLAY);
    633 }
    634 
    635 
    636 /* ed_start_over():
    637  *	Erase current line and start from scratch
    638  *	[^G]
    639  */
    640 protected el_action_t
    641 /*ARGSUSED*/
    642 ed_start_over(EditLine *el, int c)
    643 {
    644 
    645 	ch_reset(el);
    646 	return (CC_REFRESH);
    647 }
    648 
    649 
    650 /* ed_sequence_lead_in():
    651  *	First character in a bound sequence
    652  *	Placeholder for external keys
    653  */
    654 protected el_action_t
    655 /*ARGSUSED*/
    656 ed_sequence_lead_in(EditLine *el, int c)
    657 {
    658 
    659 	return (CC_NORM);
    660 }
    661 
    662 
    663 /* ed_prev_history():
    664  *	Move to the previous history line
    665  *	[^P] [k]
    666  */
    667 protected el_action_t
    668 /*ARGSUSED*/
    669 ed_prev_history(EditLine *el, int c)
    670 {
    671 	char beep = 0;
    672 
    673 	el->el_chared.c_undo.action = NOP;
    674 	*el->el_line.lastchar = '\0';		/* just in case */
    675 
    676 	if (el->el_history.eventno == 0) {	/* save the current buffer
    677 						 * away */
    678 		(void) strncpy(el->el_history.buf, el->el_line.buffer,
    679 		    EL_BUFSIZ);
    680 		el->el_history.last = el->el_history.buf +
    681 		    (el->el_line.lastchar - el->el_line.buffer);
    682 	}
    683 	el->el_history.eventno += el->el_state.argument;
    684 
    685 	if (hist_get(el) == CC_ERROR) {
    686 		beep = 1;
    687 		/* el->el_history.eventno was fixed by first call */
    688 		(void) hist_get(el);
    689 	}
    690 	re_refresh(el);
    691 	if (beep)
    692 		return (CC_ERROR);
    693 	else
    694 		return (CC_NORM);	/* was CC_UP_HIST */
    695 }
    696 
    697 
    698 /* ed_next_history():
    699  *	Move to the next history line
    700  *	[^N] [j]
    701  */
    702 protected el_action_t
    703 /*ARGSUSED*/
    704 ed_next_history(EditLine *el, int c)
    705 {
    706 
    707 	el->el_chared.c_undo.action = NOP;
    708 	*el->el_line.lastchar = '\0';	/* just in case */
    709 
    710 	el->el_history.eventno -= el->el_state.argument;
    711 
    712 	if (el->el_history.eventno < 0) {
    713 		el->el_history.eventno = 0;
    714 		return (CC_ERROR);/* make it beep */
    715 	}
    716 	return (hist_get(el));
    717 }
    718 
    719 
    720 /* ed_search_prev_history():
    721  *	Search previous in history for a line matching the current
    722  *	next search history [M-P] [K]
    723  */
    724 protected el_action_t
    725 /*ARGSUSED*/
    726 ed_search_prev_history(EditLine *el, int c)
    727 {
    728 	const char *hp;
    729 	int h;
    730 	bool_t found = 0;
    731 
    732 	el->el_chared.c_vcmd.action = NOP;
    733 	el->el_chared.c_undo.action = NOP;
    734 	*el->el_line.lastchar = '\0';	/* just in case */
    735 	if (el->el_history.eventno < 0) {
    736 #ifdef DEBUG_EDIT
    737 		(void) fprintf(el->el_errfile,
    738 		    "e_prev_search_hist(): eventno < 0;\n");
    739 #endif
    740 		el->el_history.eventno = 0;
    741 		return (CC_ERROR);
    742 	}
    743 	if (el->el_history.eventno == 0) {
    744 		(void) strncpy(el->el_history.buf, el->el_line.buffer,
    745 		    EL_BUFSIZ);
    746 		el->el_history.last = el->el_history.buf +
    747 		    (el->el_line.lastchar - el->el_line.buffer);
    748 	}
    749 	if (el->el_history.ref == NULL)
    750 		return (CC_ERROR);
    751 
    752 	hp = HIST_FIRST(el);
    753 	if (hp == NULL)
    754 		return (CC_ERROR);
    755 
    756 	c_setpat(el);		/* Set search pattern !! */
    757 
    758 	for (h = 1; h <= el->el_history.eventno; h++)
    759 		hp = HIST_NEXT(el);
    760 
    761 	while (hp != NULL) {
    762 #ifdef SDEBUG
    763 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
    764 #endif
    765 		if ((strncmp(hp, el->el_line.buffer, (size_t)
    766 			    (el->el_line.lastchar - el->el_line.buffer)) ||
    767 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
    768 		    c_hmatch(el, hp)) {
    769 			found++;
    770 			break;
    771 		}
    772 		h++;
    773 		hp = HIST_NEXT(el);
    774 	}
    775 
    776 	if (!found) {
    777 #ifdef SDEBUG
    778 		(void) fprintf(el->el_errfile, "not found\n");
    779 #endif
    780 		return (CC_ERROR);
    781 	}
    782 	el->el_history.eventno = h;
    783 
    784 	return (hist_get(el));
    785 }
    786 
    787 
    788 /* ed_search_next_history():
    789  *	Search next in history for a line matching the current
    790  *	[M-N] [J]
    791  */
    792 protected el_action_t
    793 /*ARGSUSED*/
    794 ed_search_next_history(EditLine *el, int c)
    795 {
    796 	const char *hp;
    797 	int h;
    798 	bool_t found = 0;
    799 
    800 	el->el_chared.c_vcmd.action = NOP;
    801 	el->el_chared.c_undo.action = NOP;
    802 	*el->el_line.lastchar = '\0';	/* just in case */
    803 
    804 	if (el->el_history.eventno == 0)
    805 		return (CC_ERROR);
    806 
    807 	if (el->el_history.ref == NULL)
    808 		return (CC_ERROR);
    809 
    810 	hp = HIST_FIRST(el);
    811 	if (hp == NULL)
    812 		return (CC_ERROR);
    813 
    814 	c_setpat(el);		/* Set search pattern !! */
    815 
    816 	for (h = 1; h < el->el_history.eventno && hp; h++) {
    817 #ifdef SDEBUG
    818 		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
    819 #endif
    820 		if ((strncmp(hp, el->el_line.buffer, (size_t)
    821 			    (el->el_line.lastchar - el->el_line.buffer)) ||
    822 			hp[el->el_line.lastchar - el->el_line.buffer]) &&
    823 		    c_hmatch(el, hp))
    824 			found = h;
    825 		hp = HIST_NEXT(el);
    826 	}
    827 
    828 	if (!found) {		/* is it the current history number? */
    829 		if (!c_hmatch(el, el->el_history.buf)) {
    830 #ifdef SDEBUG
    831 			(void) fprintf(el->el_errfile, "not found\n");
    832 #endif
    833 			return (CC_ERROR);
    834 		}
    835 	}
    836 	el->el_history.eventno = found;
    837 
    838 	return (hist_get(el));
    839 }
    840 
    841 
    842 /* ed_prev_line():
    843  *	Move up one line
    844  *	Could be [k] [^p]
    845  */
    846 protected el_action_t
    847 /*ARGSUSED*/
    848 ed_prev_line(EditLine *el, int c)
    849 {
    850 	char *ptr;
    851 	int nchars = c_hpos(el);
    852 
    853 	/*
    854          * Move to the line requested
    855          */
    856 	if (*(ptr = el->el_line.cursor) == '\n')
    857 		ptr--;
    858 
    859 	for (; ptr >= el->el_line.buffer; ptr--)
    860 		if (*ptr == '\n' && --el->el_state.argument <= 0)
    861 			break;
    862 
    863 	if (el->el_state.argument > 0)
    864 		return (CC_ERROR);
    865 
    866 	/*
    867          * Move to the beginning of the line
    868          */
    869 	for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
    870 		continue;
    871 
    872 	/*
    873          * Move to the character requested
    874          */
    875 	for (ptr++;
    876 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
    877 	    ptr++)
    878 		continue;
    879 
    880 	el->el_line.cursor = ptr;
    881 	return (CC_CURSOR);
    882 }
    883 
    884 
    885 /* ed_next_line():
    886  *	Move down one line
    887  *	Could be [j] [^n]
    888  */
    889 protected el_action_t
    890 /*ARGSUSED*/
    891 ed_next_line(EditLine *el, int c)
    892 {
    893 	char *ptr;
    894 	int nchars = c_hpos(el);
    895 
    896 	/*
    897          * Move to the line requested
    898          */
    899 	for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
    900 		if (*ptr == '\n' && --el->el_state.argument <= 0)
    901 			break;
    902 
    903 	if (el->el_state.argument > 0)
    904 		return (CC_ERROR);
    905 
    906 	/*
    907          * Move to the character requested
    908          */
    909 	for (ptr++;
    910 	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
    911 	    ptr++)
    912 		continue;
    913 
    914 	el->el_line.cursor = ptr;
    915 	return (CC_CURSOR);
    916 }
    917 
    918 
    919 /* ed_command():
    920  *	Editline extended command
    921  *	[M-X] [:]
    922  */
    923 protected el_action_t
    924 /*ARGSUSED*/
    925 ed_command(EditLine *el, int c)
    926 {
    927 	char tmpbuf[EL_BUFSIZ];
    928 	int tmplen;
    929 
    930 	el->el_line.buffer[0] = '\0';
    931 	el->el_line.lastchar = el->el_line.buffer;
    932 	el->el_line.cursor = el->el_line.buffer;
    933 
    934 	c_insert(el, 3);	/* prompt + ": " */
    935 	*el->el_line.cursor++ = '\n';
    936 	*el->el_line.cursor++ = ':';
    937 	*el->el_line.cursor++ = ' ';
    938 	re_refresh(el);
    939 
    940 	tmplen = c_gets(el, tmpbuf);
    941 	tmpbuf[tmplen] = '\0';
    942 
    943 	el->el_line.buffer[0] = '\0';
    944 	el->el_line.lastchar = el->el_line.buffer;
    945 	el->el_line.cursor = el->el_line.buffer;
    946 
    947 	if (parse_line(el, tmpbuf) == -1)
    948 		return (CC_ERROR);
    949 	else
    950 		return (CC_REFRESH);
    951 }
    952