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