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