common.c revision 1.20
1/*	$OpenBSD: common.c,v 1.20 2016/04/18 20:13:07 schwarze Exp $	*/
2/*	$NetBSD: common.c,v 1.24 2009/12/30 22:37:40 christos Exp $	*/
3
4/*-
5 * Copyright (c) 1992, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "config.h"
37
38/*
39 * common.c: Common Editor functions
40 */
41#include <ctype.h>
42#include <string.h>
43
44#include "el.h"
45#include "common.h"
46#include "parse.h"
47#include "vi.h"
48
49/* ed_end_of_file():
50 *	Indicate end of file
51 *	[^D]
52 */
53protected el_action_t
54/*ARGSUSED*/
55ed_end_of_file(EditLine *el, wint_t 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 */
68protected el_action_t
69ed_insert(EditLine *el, wint_t 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 */
110protected el_action_t
111/*ARGSUSED*/
112ed_delete_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
113{
114	wchar_t *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 */
138protected el_action_t
139/*ARGSUSED*/
140ed_delete_next_char(EditLine *el, wint_t c)
141{
142#ifdef notdef			/* XXX */
143#define	EL	el->el_line
144	(void) fprintf(el->el_errfile,
145	    "\nD(b: %p(%ls)  c: %p(%ls) last: %p(%ls) limit: %p(%ls)\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				terminal_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 */
188protected el_action_t
189/*ARGSUSED*/
190ed_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
191{
192	wchar_t *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 */
209protected el_action_t
210/*ARGSUSED*/
211ed_move_to_end(EditLine *el, wint_t 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 */
232protected el_action_t
233/*ARGSUSED*/
234ed_move_to_beg(EditLine *el, wint_t 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 (iswspace(*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 */
256protected el_action_t
257ed_transpose_chars(EditLine *el, wint_t 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 */
281protected el_action_t
282/*ARGSUSED*/
283ed_next_char(EditLine *el, wint_t c __attribute__((__unused__)))
284{
285	wchar_t *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 */
310protected el_action_t
311/*ARGSUSED*/
312ed_prev_word(EditLine *el, wint_t 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 */
336protected el_action_t
337/*ARGSUSED*/
338ed_prev_char(EditLine *el, wint_t 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 */
361protected el_action_t
362ed_quoted_insert(EditLine *el, wint_t c)
363{
364	int num;
365
366	tty_quotemode(el);
367	num = el_wgetc(el, &c);
368	tty_noquotemode(el);
369	if (num == 1)
370		return ed_insert(el, c);
371	else
372		return ed_end_of_file(el, 0);
373}
374
375
376/* ed_digit():
377 *	Adds to argument or enters a digit
378 */
379protected el_action_t
380ed_digit(EditLine *el, wint_t c)
381{
382
383	if (!iswdigit(c))
384		return CC_ERROR;
385
386	if (el->el_state.doingarg) {
387			/* if doing an arg, add this in... */
388		if (el->el_state.lastcmd == EM_UNIVERSAL_ARGUMENT)
389			el->el_state.argument = c - '0';
390		else {
391			if (el->el_state.argument > 1000000)
392				return CC_ERROR;
393			el->el_state.argument =
394			    (el->el_state.argument * 10) + (c - '0');
395		}
396		return CC_ARGHACK;
397	}
398
399	return ed_insert(el, c);
400}
401
402
403/* ed_argument_digit():
404 *	Digit that starts argument
405 *	For ESC-n
406 */
407protected el_action_t
408ed_argument_digit(EditLine *el, wint_t c)
409{
410
411	if (!iswdigit(c))
412		return CC_ERROR;
413
414	if (el->el_state.doingarg) {
415		if (el->el_state.argument > 1000000)
416			return CC_ERROR;
417		el->el_state.argument = (el->el_state.argument * 10) +
418		    (c - '0');
419	} else {		/* else starting an argument */
420		el->el_state.argument = c - '0';
421		el->el_state.doingarg = 1;
422	}
423	return CC_ARGHACK;
424}
425
426
427/* ed_unassigned():
428 *	Indicates unbound character
429 *	Bound to keys that are not assigned
430 */
431protected el_action_t
432/*ARGSUSED*/
433ed_unassigned(EditLine *el, wint_t c __attribute__((__unused__)))
434{
435
436	return CC_ERROR;
437}
438
439
440/* ed_ignore():
441 *	Input characters that have no effect
442 *	[^C ^O ^Q ^S ^Z ^\ ^]] [^C ^O ^Q ^S ^\]
443 */
444protected el_action_t
445/*ARGSUSED*/
446ed_ignore(EditLine *el __attribute__((__unused__)),
447	      wint_t c __attribute__((__unused__)))
448{
449
450	return CC_NORM;
451}
452
453
454/* ed_newline():
455 *	Execute command
456 *	[^J]
457 */
458protected el_action_t
459/*ARGSUSED*/
460ed_newline(EditLine *el, wint_t c __attribute__((__unused__)))
461{
462
463	re_goto_bottom(el);
464	*el->el_line.lastchar++ = '\n';
465	*el->el_line.lastchar = '\0';
466	return CC_NEWLINE;
467}
468
469
470/* ed_delete_prev_char():
471 *	Delete the character to the left of the cursor
472 *	[^?]
473 */
474protected el_action_t
475/*ARGSUSED*/
476ed_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
477{
478
479	if (el->el_line.cursor <= el->el_line.buffer)
480		return CC_ERROR;
481
482	c_delbefore(el, el->el_state.argument);
483	el->el_line.cursor -= el->el_state.argument;
484	if (el->el_line.cursor < el->el_line.buffer)
485		el->el_line.cursor = el->el_line.buffer;
486	return CC_REFRESH;
487}
488
489
490/* ed_clear_screen():
491 *	Clear screen leaving current line at the top
492 *	[^L]
493 */
494protected el_action_t
495/*ARGSUSED*/
496ed_clear_screen(EditLine *el, wint_t c __attribute__((__unused__)))
497{
498
499	terminal_clear_screen(el);	/* clear the whole real screen */
500	re_clear_display(el);	/* reset everything */
501	return CC_REFRESH;
502}
503
504
505/* ed_redisplay():
506 *	Redisplay everything
507 *	^R
508 */
509protected el_action_t
510/*ARGSUSED*/
511ed_redisplay(EditLine *el __attribute__((__unused__)),
512	     wint_t c __attribute__((__unused__)))
513{
514
515	return CC_REDISPLAY;
516}
517
518
519/* ed_start_over():
520 *	Erase current line and start from scratch
521 *	[^G]
522 */
523protected el_action_t
524/*ARGSUSED*/
525ed_start_over(EditLine *el, wint_t c __attribute__((__unused__)))
526{
527
528	ch_reset(el, 0);
529	return CC_REFRESH;
530}
531
532
533/* ed_sequence_lead_in():
534 *	First character in a bound sequence
535 *	Placeholder for external keys
536 */
537protected el_action_t
538/*ARGSUSED*/
539ed_sequence_lead_in(EditLine *el __attribute__((__unused__)),
540		    wint_t c __attribute__((__unused__)))
541{
542
543	return CC_NORM;
544}
545
546
547/* ed_prev_history():
548 *	Move to the previous history line
549 *	[^P] [k]
550 */
551protected el_action_t
552/*ARGSUSED*/
553ed_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
554{
555	char beep = 0;
556	int sv_event = el->el_history.eventno;
557
558	el->el_chared.c_undo.len = -1;
559	*el->el_line.lastchar = '\0';		/* just in case */
560
561	if (el->el_history.eventno == 0) {	/* save the current buffer
562						 * away */
563		(void) wcsncpy(el->el_history.buf, el->el_line.buffer,
564		    EL_BUFSIZ);
565		el->el_history.last = el->el_history.buf +
566		    (el->el_line.lastchar - el->el_line.buffer);
567	}
568	el->el_history.eventno += el->el_state.argument;
569
570	if (hist_get(el) == CC_ERROR) {
571		if (el->el_map.type == MAP_VI) {
572			el->el_history.eventno = sv_event;
573		}
574		beep = 1;
575		/* el->el_history.eventno was fixed by first call */
576		(void) hist_get(el);
577	}
578	if (beep)
579		return CC_REFRESH_BEEP;
580	return CC_REFRESH;
581}
582
583
584/* ed_next_history():
585 *	Move to the next history line
586 *	[^N] [j]
587 */
588protected el_action_t
589/*ARGSUSED*/
590ed_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
591{
592	el_action_t beep = CC_REFRESH, rval;
593
594	el->el_chared.c_undo.len = -1;
595	*el->el_line.lastchar = '\0';	/* just in case */
596
597	el->el_history.eventno -= el->el_state.argument;
598
599	if (el->el_history.eventno < 0) {
600		el->el_history.eventno = 0;
601		beep = CC_REFRESH_BEEP;
602	}
603	rval = hist_get(el);
604	if (rval == CC_REFRESH)
605		return beep;
606	return rval;
607
608}
609
610
611/* ed_search_prev_history():
612 *	Search previous in history for a line matching the current
613 *	next search history [M-P] [K]
614 */
615protected el_action_t
616/*ARGSUSED*/
617ed_search_prev_history(EditLine *el, wint_t c __attribute__((__unused__)))
618{
619	const wchar_t *hp;
620	int h;
621	int found = 0;
622
623	el->el_chared.c_vcmd.action = NOP;
624	el->el_chared.c_undo.len = -1;
625	*el->el_line.lastchar = '\0';	/* just in case */
626	if (el->el_history.eventno < 0) {
627#ifdef DEBUG_EDIT
628		(void) fprintf(el->el_errfile,
629		    "e_prev_search_hist(): eventno < 0;\n");
630#endif
631		el->el_history.eventno = 0;
632		return CC_ERROR;
633	}
634	if (el->el_history.eventno == 0) {
635		(void) wcsncpy(el->el_history.buf, el->el_line.buffer,
636		    EL_BUFSIZ);
637		el->el_history.last = el->el_history.buf +
638		    (el->el_line.lastchar - el->el_line.buffer);
639	}
640	if (el->el_history.ref == NULL)
641		return CC_ERROR;
642
643	hp = HIST_FIRST(el);
644	if (hp == NULL)
645		return CC_ERROR;
646
647	c_setpat(el);		/* Set search pattern !! */
648
649	for (h = 1; h <= el->el_history.eventno; h++)
650		hp = HIST_NEXT(el);
651
652	while (hp != NULL) {
653#ifdef SDEBUG
654		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
655#endif
656		if ((wcsncmp(hp, el->el_line.buffer, (size_t)
657			    (el->el_line.lastchar - el->el_line.buffer)) ||
658			hp[el->el_line.lastchar - el->el_line.buffer]) &&
659		    c_hmatch(el, hp)) {
660			found = 1;
661			break;
662		}
663		h++;
664		hp = HIST_NEXT(el);
665	}
666
667	if (!found) {
668#ifdef SDEBUG
669		(void) fprintf(el->el_errfile, "not found\n");
670#endif
671		return CC_ERROR;
672	}
673	el->el_history.eventno = h;
674
675	return hist_get(el);
676}
677
678
679/* ed_search_next_history():
680 *	Search next in history for a line matching the current
681 *	[M-N] [J]
682 */
683protected el_action_t
684/*ARGSUSED*/
685ed_search_next_history(EditLine *el, wint_t c __attribute__((__unused__)))
686{
687	const wchar_t *hp;
688	int h;
689	int found = 0;
690
691	el->el_chared.c_vcmd.action = NOP;
692	el->el_chared.c_undo.len = -1;
693	*el->el_line.lastchar = '\0';	/* just in case */
694
695	if (el->el_history.eventno == 0)
696		return CC_ERROR;
697
698	if (el->el_history.ref == NULL)
699		return CC_ERROR;
700
701	hp = HIST_FIRST(el);
702	if (hp == NULL)
703		return CC_ERROR;
704
705	c_setpat(el);		/* Set search pattern !! */
706
707	for (h = 1; h < el->el_history.eventno && hp; h++) {
708#ifdef SDEBUG
709		(void) fprintf(el->el_errfile, "Comparing with \"%s\"\n", hp);
710#endif
711		if ((wcsncmp(hp, el->el_line.buffer, (size_t)
712			    (el->el_line.lastchar - el->el_line.buffer)) ||
713			hp[el->el_line.lastchar - el->el_line.buffer]) &&
714		    c_hmatch(el, hp))
715			found = h;
716		hp = HIST_NEXT(el);
717	}
718
719	if (!found) {		/* is it the current history number? */
720		if (!c_hmatch(el, el->el_history.buf)) {
721#ifdef SDEBUG
722			(void) fprintf(el->el_errfile, "not found\n");
723#endif
724			return CC_ERROR;
725		}
726	}
727	el->el_history.eventno = found;
728
729	return hist_get(el);
730}
731
732
733/* ed_prev_line():
734 *	Move up one line
735 *	Could be [k] [^p]
736 */
737protected el_action_t
738/*ARGSUSED*/
739ed_prev_line(EditLine *el, wint_t c __attribute__((__unused__)))
740{
741	wchar_t *ptr;
742	int nchars = c_hpos(el);
743
744	/*
745         * Move to the line requested
746         */
747	if (*(ptr = el->el_line.cursor) == '\n')
748		ptr--;
749
750	for (; ptr >= el->el_line.buffer; ptr--)
751		if (*ptr == '\n' && --el->el_state.argument <= 0)
752			break;
753
754	if (el->el_state.argument > 0)
755		return CC_ERROR;
756
757	/*
758         * Move to the beginning of the line
759         */
760	for (ptr--; ptr >= el->el_line.buffer && *ptr != '\n'; ptr--)
761		continue;
762
763	/*
764         * Move to the character requested
765         */
766	for (ptr++;
767	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
768	    ptr++)
769		continue;
770
771	el->el_line.cursor = ptr;
772	return CC_CURSOR;
773}
774
775
776/* ed_next_line():
777 *	Move down one line
778 *	Could be [j] [^n]
779 */
780protected el_action_t
781/*ARGSUSED*/
782ed_next_line(EditLine *el, wint_t c __attribute__((__unused__)))
783{
784	wchar_t *ptr;
785	int nchars = c_hpos(el);
786
787	/*
788         * Move to the line requested
789         */
790	for (ptr = el->el_line.cursor; ptr < el->el_line.lastchar; ptr++)
791		if (*ptr == '\n' && --el->el_state.argument <= 0)
792			break;
793
794	if (el->el_state.argument > 0)
795		return CC_ERROR;
796
797	/*
798         * Move to the character requested
799         */
800	for (ptr++;
801	    nchars-- > 0 && ptr < el->el_line.lastchar && *ptr != '\n';
802	    ptr++)
803		continue;
804
805	el->el_line.cursor = ptr;
806	return CC_CURSOR;
807}
808
809
810/* ed_command():
811 *	Editline extended command
812 *	[M-X] [:]
813 */
814protected el_action_t
815/*ARGSUSED*/
816ed_command(EditLine *el, wint_t c __attribute__((__unused__)))
817{
818	wchar_t tmpbuf[EL_BUFSIZ];
819	int tmplen;
820
821	tmplen = c_gets(el, tmpbuf, L"\n: ");
822	terminal__putc(el, '\n');
823
824	if (tmplen < 0 || (tmpbuf[tmplen] = 0, parse_line(el, tmpbuf)) == -1)
825		terminal_beep(el);
826
827	el->el_map.current = el->el_map.key;
828	re_clear_display(el);
829	return CC_REFRESH;
830}
831