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