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