xref: /freebsd/contrib/tcsh/ed.chared.c (revision 42249ef2)
1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.103 2015/08/19 14:29:55 christos Exp $ */
2 /*
3  * ed.chared.c: Character editing functions.
4  */
5 /*-
6  * Copyright (c) 1980, 1991 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 /*
34   Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
35 
36   e_dabbrev_expand() did not do proper completion if quoted spaces were present
37   in the string being completed. Exemple:
38 
39   # echo hello\ world
40   hello world
41   # echo h<press key bound to dabbrev-expande>
42   # echo hello\<cursor>
43 
44   Correct behavior is:
45   # echo h<press key bound to dabbrev-expande>
46   # echo hello\ world<cursor>
47 
48   The same problem occured if spaces were present in a string withing quotation
49   marks. Example:
50 
51   # echo "hello world"
52   hello world
53   # echo "h<press key bound to dabbrev-expande>
54   # echo "hello<cursor>
55 
56   The former problem could be solved with minor modifications of c_preword()
57   and c_endword(). The latter, however, required a significant rewrite of
58   c_preword(), since quoted strings must be parsed from start to end to
59   determine if a given character is inside or outside the quotation marks.
60 
61   Compare the following two strings:
62 
63   # echo \"" 'foo \' bar\"
64   " 'foo \' bar\
65   # echo '\"" 'foo \' bar\"
66   \"" foo ' bar"
67 
68   The only difference between the two echo lines is in the first character
69   after the echo command. The result is either one or three arguments.
70 
71  */
72 
73 #include "sh.h"
74 
75 RCSID("$tcsh: ed.chared.c,v 3.103 2015/08/19 14:29:55 christos Exp $")
76 
77 #include "ed.h"
78 #include "tw.h"
79 #include "ed.defns.h"
80 
81 /* #define SDEBUG */
82 
83 #define TCSHOP_NOP    	  0x00
84 #define TCSHOP_DELETE 	  0x01
85 #define TCSHOP_INSERT 	  0x02
86 #define TCSHOP_CHANGE 	  0x04
87 
88 #define CHAR_FWD	0
89 #define CHAR_BACK	1
90 
91 /*
92  * vi word treatment
93  * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
94  */
95 #define C_CLASS_WHITE	1
96 #define C_CLASS_WORD	2
97 #define C_CLASS_OTHER	3
98 
99 static Char *InsertPos = InputBuf; /* Where insertion starts */
100 static Char *ActionPos = 0;	   /* Where action begins  */
101 static int  ActionFlag = TCSHOP_NOP;	   /* What delayed action to take */
102 /*
103  * Word search state
104  */
105 static int  searchdir = F_UP_SEARCH_HIST; 	/* Direction of last search */
106 static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
107 /*
108  * Char search state
109  */
110 static int  srch_dir = CHAR_FWD;		/* Direction of last search */
111 static Char srch_char = 0;			/* Search target */
112 
113 /* all routines that start with c_ are private to this set of routines */
114 static	void	 c_alternativ_key_map	(int);
115 void	 c_insert		(int);
116 void	 c_delafter		(int);
117 void	 c_delbefore		(int);
118 static 	int	 c_to_class		(Char);
119 static	Char	*c_prev_word		(Char *, Char *, int);
120 static	Char	*c_next_word		(Char *, Char *, int);
121 static	Char	*c_number		(Char *, int *, int);
122 static	Char	*c_expand		(Char *);
123 static	int	 c_excl			(Char *);
124 static	int	 c_substitute		(void);
125 static	void	 c_delfini		(void);
126 static	int	 c_hmatch		(Char *);
127 static	void	 c_hsetpat		(void);
128 #ifdef COMMENT
129 static	void	 c_get_word		(Char **, Char **);
130 #endif
131 static	Char	*c_preword		(Char *, Char *, int, Char *);
132 static	Char	*c_nexword		(Char *, Char *, int);
133 static	Char	*c_endword		(Char *, Char *, int, Char *);
134 static	Char	*c_eword		(Char *, Char *, int);
135 static	void	 c_push_kill		(Char *, Char *);
136 static	void	 c_save_inputbuf	(void);
137 static  CCRETVAL c_search_line		(Char *, int);
138 static  CCRETVAL v_repeat_srch		(int);
139 static	CCRETVAL e_inc_search		(int);
140 #ifdef notyet
141 static  CCRETVAL e_insert_str		(Char *);
142 #endif
143 static	CCRETVAL v_search		(int);
144 static	CCRETVAL v_csearch_fwd		(Char, int, int);
145 static	CCRETVAL v_action		(int);
146 static	CCRETVAL v_csearch_back		(Char, int, int);
147 
148 static void
149 c_alternativ_key_map(int state)
150 {
151     switch (state) {
152     case 0:
153 	CurrentKeyMap = CcKeyMap;
154 	break;
155     case 1:
156 	CurrentKeyMap = CcAltMap;
157 	break;
158     default:
159 	return;
160     }
161 
162     AltKeyMap = (Char) state;
163 }
164 
165 void
166 c_insert(int num)
167 {
168     Char *cp;
169 
170     if (LastChar + num >= InputLim)
171 	return;			/* can't go past end of buffer */
172 
173     if (Cursor < LastChar) {	/* if I must move chars */
174 	for (cp = LastChar; cp >= Cursor; cp--)
175 	    cp[num] = *cp;
176 	if (Mark && Mark > Cursor)
177 		Mark += num;
178     }
179     LastChar += num;
180 }
181 
182 void
183 c_delafter(int num)
184 {
185     Char *cp, *kp = NULL;
186 
187     if (num > LastChar - Cursor)
188 	num = (int) (LastChar - Cursor);	/* bounds check */
189 
190     if (num > 0) {			/* if I can delete anything */
191 	if (VImode) {
192 	    kp = UndoBuf;		/* Set Up for VI undo command */
193 	    UndoAction = TCSHOP_INSERT;
194 	    UndoSize = num;
195 	    UndoPtr  = Cursor;
196 	    for (cp = Cursor; cp <= LastChar; cp++) {
197 		*kp++ = *cp;	/* Save deleted chars into undobuf */
198 		*cp = cp[num];
199 	    }
200 	}
201 	else
202 	    for (cp = Cursor; cp + num <= LastChar; cp++)
203 		*cp = cp[num];
204 	LastChar -= num;
205 	/* Mark was within the range of the deleted word? */
206 	if (Mark && Mark > Cursor && Mark <= Cursor+num)
207 		Mark = Cursor;
208 	/* Mark after the deleted word? */
209 	else if (Mark && Mark > Cursor)
210 		Mark -= num;
211     }
212 #ifdef notdef
213     else {
214 	/*
215 	 * XXX: We don't want to do that. In emacs mode overwrite should be
216 	 * sticky. I am not sure how that affects vi mode
217 	 */
218 	inputmode = MODE_INSERT;
219     }
220 #endif /* notdef */
221 }
222 
223 void
224 c_delbefore(int num)		/* delete before dot, with bounds checking */
225 {
226     Char *cp, *kp = NULL;
227 
228     if (num > Cursor - InputBuf)
229 	num = (int) (Cursor - InputBuf);	/* bounds check */
230 
231     if (num > 0) {			/* if I can delete anything */
232 	if (VImode) {
233 	    kp = UndoBuf;		/* Set Up for VI undo command */
234 	    UndoAction = TCSHOP_INSERT;
235 	    UndoSize = num;
236 	    UndoPtr  = Cursor - num;
237 	    for (cp = Cursor - num; cp <= LastChar; cp++) {
238 		*kp++ = *cp;
239 		*cp = cp[num];
240 	    }
241 	}
242 	else
243 	    for (cp = Cursor - num; cp + num <= LastChar; cp++)
244 		*cp = cp[num];
245 	LastChar -= num;
246 	Cursor -= num;
247 	/* Mark was within the range of the deleted word? */
248 	if (Mark && Mark > Cursor && Mark <= Cursor+num)
249 		Mark = Cursor;
250 	/* Mark after the deleted word? */
251 	else if (Mark && Mark > Cursor)
252 		Mark -= num;
253     }
254 }
255 
256 static Char *
257 c_preword(Char *p, Char *low, int n, Char *delim)
258 {
259   while (n--) {
260     Char *prev = low;
261     Char *new;
262 
263     while (prev < p) {		/* Skip initial non-word chars */
264       if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\')
265 	break;
266       prev++;
267     }
268 
269     new = prev;
270 
271     while (new < p) {
272       prev = new;
273       new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */
274       new++;			/* Step away from end of word */
275       while (new <= p) {	/* Skip trailing non-word chars */
276 	if (!Strchr(delim, *new) || *(new-1) == (Char)'\\')
277 	  break;
278 	new++;
279       }
280     }
281 
282     p = prev;			/* Set to previous word start */
283 
284   }
285   if (p < low)
286     p = low;
287   return (p);
288 }
289 
290 /*
291  * c_to_class() returns the class of the given character.
292  *
293  * This is used to make the c_prev_word(), c_next_word() and c_eword() functions
294  * work like vi's, which classify characters. A word is a sequence of
295  * characters belonging to the same class, classes being defined as
296  * follows:
297  *
298  *	1/ whitespace
299  *	2/ alphanumeric chars, + underscore
300  *	3/ others
301  */
302 static int
303 c_to_class(Char ch)
304 {
305     if (Isspace(ch))
306         return C_CLASS_WHITE;
307 
308     if (isword(ch))
309         return C_CLASS_WORD;
310 
311     return C_CLASS_OTHER;
312 }
313 
314 static Char *
315 c_prev_word(Char *p, Char *low, int n)
316 {
317     p--;
318 
319     if (!VImode) {
320 	while (n--) {
321 	    while ((p >= low) && !isword(*p))
322 		p--;
323 	    while ((p >= low) && isword(*p))
324 		p--;
325 	}
326 
327 	/* cp now points to one character before the word */
328 	p++;
329 	if (p < low)
330 	    p = low;
331 	/* cp now points where we want it */
332 	return(p);
333     }
334 
335     while (n--) {
336         int  c_class;
337 
338         if (p < low)
339             break;
340 
341         /* scan until beginning of current word (may be all whitespace!) */
342         c_class = c_to_class(*p);
343         while ((p >= low) && c_class == c_to_class(*p))
344             p--;
345 
346         /* if this was a non_whitespace word, we're ready */
347         if (c_class != C_CLASS_WHITE)
348             continue;
349 
350         /* otherwise, move back to beginning of the word just found */
351         c_class = c_to_class(*p);
352         while ((p >= low) && c_class == c_to_class(*p))
353             p--;
354     }
355 
356     p++;                        /* correct overshoot */
357 
358     return (p);
359 }
360 
361 static Char *
362 c_next_word(Char *p, Char *high, int n)
363 {
364     if (!VImode) {
365 	while (n--) {
366 	    while ((p < high) && !isword(*p))
367 		p++;
368 	    while ((p < high) && isword(*p))
369 		p++;
370 	}
371 	if (p > high)
372 	    p = high;
373 	/* p now points where we want it */
374 	return(p);
375     }
376 
377     while (n--) {
378         int  c_class;
379 
380         if (p >= high)
381             break;
382 
383         /* scan until end of current word (may be all whitespace!) */
384         c_class = c_to_class(*p);
385         while ((p < high) && c_class == c_to_class(*p))
386             p++;
387 
388         /* if this was all whitespace, we're ready */
389         if (c_class == C_CLASS_WHITE)
390             continue;
391 
392 	/* if we've found white-space at the end of the word, skip it */
393         while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
394             p++;
395     }
396 
397     p--;                        /* correct overshoot */
398 
399     return (p);
400 }
401 
402 static Char *
403 c_nexword(Char *p, Char *high, int n)
404 {
405     while (n--) {
406 	while ((p < high) && !Isspace(*p))
407 	    p++;
408 	while ((p < high) && Isspace(*p))
409 	    p++;
410     }
411 
412     if (p > high)
413 	p = high;
414     /* p now points where we want it */
415     return(p);
416 }
417 
418 /*
419  * Expand-History (originally "Magic-Space") code added by
420  * Ray Moody <ray@gibbs.physics.purdue.edu>
421  * this is a neat, but odd, addition.
422  */
423 
424 /*
425  * c_number: Ignore character p points to, return number appearing after that.
426  * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
427  * Return p pointing to last char used.
428  */
429 
430 /*
431  * dval is the number to subtract from for things like $-3
432  */
433 
434 static Char *
435 c_number(Char *p, int *num, int dval)
436 {
437     int i;
438     int sign = 1;
439 
440     if (*++p == '^') {
441 	*num = 1;
442 	return(p);
443     }
444     if (*p == '$') {
445 	if (*++p != '-') {
446 	    *num = INT_MAX;	/* Handle $ */
447 	    return(--p);
448 	}
449 	sign = -1;		/* Handle $- */
450 	++p;
451     }
452     for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
453 	continue;
454     *num = (sign < 0 ? dval - i : i);
455     return(--p);
456 }
457 
458 /*
459  * excl_expand: There is an excl to be expanded to p -- do the right thing
460  * with it and return a version of p advanced over the expanded stuff.  Also,
461  * update tsh_cur and related things as appropriate...
462  */
463 
464 static Char *
465 c_expand(Char *p)
466 {
467     Char *q;
468     struct Hist *h = Histlist.Hnext;
469     struct wordent *l;
470     int     i, from, to, dval;
471     int    all_dig;
472     int    been_once = 0;
473     Char   *op = p;
474     Char   *buf;
475     size_t buf_len;
476     Char   *modbuf;
477 
478     buf = NULL;
479     if (!h)
480 	goto excl_err;
481 excl_sw:
482     switch (*(q = p + 1)) {
483 
484     case '^':
485 	buf = expand_lex(&h->Hlex, 1, 1);
486 	break;
487 
488     case '$':
489 	if ((l = (h->Hlex).prev) != 0)
490 	    buf = expand_lex(l->prev->prev, 0, 0);
491 	break;
492 
493     case '*':
494 	buf = expand_lex(&h->Hlex, 1, INT_MAX);
495 	break;
496 
497     default:
498 	if (been_once) {	/* unknown argument */
499 	    /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
500 	    buf = expand_lex(&h->Hlex, 0, INT_MAX);
501 	    q -= 2;
502 	    break;
503 	}
504 	been_once = 1;
505 
506 	if (*q == ':')		/* short form: !:arg */
507 	    --q;
508 
509 	if (HIST != '\0' && *q != HIST) {
510 	    /*
511 	     * Search for a space, tab, or colon.  See if we have a number (as
512 	     * in !1234:xyz).  Remember the number.
513 	     */
514 	    for (i = 0, all_dig = 1;
515 		 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
516 		/*
517 		 * PWP: !-4 is a valid history argument too, therefore the test
518 		 * is if not a digit, or not a - as the first character.
519 		 */
520 		if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
521 		    all_dig = 0;
522 		else if (*q == '-')
523 		    all_dig = 2;/* we are sneeky about this */
524 		else
525 		    i = 10 * i + *q - '0';
526 	    }
527 	    --q;
528 
529 	    /*
530 	     * If we have a number, search for event i.  Otherwise, search for
531 	     * a named event (as in !foo).  (In this case, I is the length of
532 	     * the named event).
533 	     */
534 	    if (all_dig) {
535 		if (all_dig == 2)
536 		    i = -i;	/* make it negitive */
537 		if (i < 0)	/* if !-4 (for example) */
538 		    i = eventno + 1 + i;	/* remember: i is < 0 */
539 		for (; h; h = h->Hnext) {
540 		    if (h->Hnum == i)
541 			break;
542 		}
543 	    }
544 	    else {
545 		for (i = (int) (q - p); h; h = h->Hnext) {
546 		    if ((l = &h->Hlex) != 0) {
547 			if (!Strncmp(p + 1, l->next->word, (size_t) i))
548 			    break;
549 		    }
550 		}
551 	    }
552 	}
553 	if (!h)
554 	    goto excl_err;
555 	if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
556 	    q[1] == '$' || q[1] == '^') {	/* get some args */
557 	    p = q[1] == ':' ? ++q : q;
558 	    /*
559 	     * Go handle !foo:*
560 	     */
561 	    if ((q[1] < '0' || q[1] > '9') &&
562 		q[1] != '-' && q[1] != '$' && q[1] != '^')
563 		goto excl_sw;
564 	    /*
565 	     * Go handle !foo:$
566 	     */
567 	    if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
568 		goto excl_sw;
569 	    /*
570 	     * Count up the number of words in this event.  Store it in dval.
571 	     * Dval will be fed to number.
572 	     */
573 	    dval = 0;
574 	    if ((l = h->Hlex.prev) != 0) {
575 		for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
576 		    continue;
577 	    }
578 	    if (!dval)
579 		goto excl_err;
580 	    if (q[1] == '-')
581 		from = 0;
582 	    else
583 		q = c_number(q, &from, dval);
584 	    if (q[1] == '-') {
585 		++q;
586 		if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
587 		    to = dval - 1;
588 		else
589 		    q = c_number(q, &to, dval);
590 	    }
591 	    else if (q[1] == '*') {
592 		++q;
593 		to = INT_MAX;
594 	    }
595 	    else {
596 		to = from;
597 	    }
598 	    if (from < 0 || to < from)
599 		goto excl_err;
600 	    buf = expand_lex(&h->Hlex, from, to);
601 	}
602 	else			/* get whole cmd */
603 	    buf = expand_lex(&h->Hlex, 0, INT_MAX);
604 	break;
605     }
606     if (buf == NULL)
607 	buf = SAVE("");
608 
609     /*
610      * Apply modifiers, if any.
611      */
612     if (q[1] == ':') {
613 	modbuf = buf;
614 	while (q[1] == ':' && modbuf != NULL) {
615 	    switch (q[2]) {
616 	    case 'r':
617 	    case 'e':
618 	    case 'h':
619 	    case 't':
620 	    case 'q':
621 	    case 'x':
622 	    case 'u':
623 	    case 'l':
624 		if ((modbuf = domod(buf, (int) q[2])) != NULL) {
625 		    xfree(buf);
626 		    buf = modbuf;
627 		}
628 		++q;
629 		break;
630 
631 	    case 'a':
632 	    case 'g':
633 		/* Not implemented; this needs to be done before expanding
634 		 * lex. We don't have the words available to us anymore.
635 		 */
636 		++q;
637 		break;
638 
639 	    case 'p':
640 		/* Ok */
641 		++q;
642 		break;
643 
644 	    case '\0':
645 		break;
646 
647 	    default:
648 		++q;
649 		break;
650 	    }
651 	    if (q[1])
652 		++q;
653 	}
654     }
655 
656     buf_len = Strlen(buf);
657     /*
658      * Now replace the text from op to q inclusive with the text from buf.
659      */
660     q++;
661 
662     /*
663      * Now replace text non-inclusively like a real CS major!
664      */
665     if (LastChar + buf_len - (q - op) >= InputLim)
666 	goto excl_err;
667     (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
668     LastChar += buf_len - (q - op);
669     Cursor += buf_len - (q - op);
670     (void) memcpy(op, buf, buf_len * sizeof(Char));
671     *LastChar = '\0';
672     xfree(buf);
673     return op + buf_len;
674 excl_err:
675     xfree(buf);
676     SoundBeep();
677     return(op + 1);
678 }
679 
680 /*
681  * c_excl: An excl has been found at point p -- back up and find some white
682  * space (or the beginning of the buffer) and properly expand all the excl's
683  * from there up to the current cursor position. We also avoid (trying to)
684  * expanding '>!'
685  * Returns number of expansions attempted (doesn't matter whether they succeeded
686  * or not).
687  */
688 
689 static int
690 c_excl(Char *p)
691 {
692     int i;
693     Char *q;
694     int nr_exp;
695 
696     /*
697      * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
698      * back p up to just before the current word.
699      */
700     if ((p[1] == ' ' || p[1] == '\t') &&
701 	(p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
702 	for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
703 	    continue;
704 	if (*q == '>')
705 	    ++p;
706     }
707     else {
708 	while (*p != ' ' && *p != '\t' && p > InputBuf)
709 	    --p;
710     }
711 
712     /*
713      * Forever: Look for history char.  (Stop looking when we find the cursor.)
714      * Count backslashes.  If odd, skip history char.  Expand if even number of
715      * backslashes.
716      */
717     nr_exp = 0;
718     for (;;) {
719 	if (HIST != '\0')
720 	    while (*p != HIST && p < Cursor)
721 		++p;
722 	for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
723 	    continue;
724 	if (i % 2 == 0)
725 	    ++p;
726 	if (p >= Cursor)   /* all done */
727 	    return nr_exp;
728 	if (i % 2 == 1) {
729 	    p = c_expand(p);
730 	    ++nr_exp;
731 	}
732     }
733 }
734 
735 
736 static int
737 c_substitute(void)
738 {
739     Char *p;
740     int  nr_exp;
741 
742     /*
743      * Start p out one character before the cursor.  Move it backwards looking
744      * for white space, the beginning of the line, or a history character.
745      */
746     for (p = Cursor - 1;
747 	 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
748 	continue;
749 
750     /*
751      * If we found a history character, go expand it.
752      */
753     if (p >= InputBuf && HIST != '\0' && *p == HIST)
754 	nr_exp = c_excl(p);
755     else
756         nr_exp = 0;
757     Refresh();
758 
759     return nr_exp;
760 }
761 
762 static void
763 c_delfini(void)		/* Finish up delete action */
764 {
765     int Size;
766 
767     if (ActionFlag & TCSHOP_INSERT)
768 	c_alternativ_key_map(0);
769 
770     ActionFlag = TCSHOP_NOP;
771 
772     if (ActionPos == 0)
773 	return;
774 
775     UndoAction = TCSHOP_INSERT;
776 
777     if (Cursor > ActionPos) {
778 	Size = (int) (Cursor-ActionPos);
779 	c_delbefore(Size);
780 	RefCursor();
781     }
782     else if (Cursor < ActionPos) {
783 	Size = (int)(ActionPos-Cursor);
784 	c_delafter(Size);
785     }
786     else  {
787 	Size = 1;
788 	c_delafter(Size);
789     }
790     UndoPtr = Cursor;
791     UndoSize = Size;
792 }
793 
794 static Char *
795 c_endword(Char *p, Char *high, int n, Char *delim)
796 {
797     Char inquote = 0;
798     p++;
799 
800     while (n--) {
801         while (p < high) {	/* Skip non-word chars */
802 	  if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
803 	    break;
804 	  p++;
805         }
806 	while (p < high) {	/* Skip string */
807 	  if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
808 	    if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
809 	      if (inquote == 0) inquote = *p;
810 	      else if (inquote == *p) inquote = 0;
811 	    }
812 	  }
813 	  /* Break if unquoted non-word char */
814 	  if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
815 	    break;
816 	  p++;
817 	}
818     }
819 
820     p--;
821     return(p);
822 }
823 
824 
825 static Char *
826 c_eword(Char *p, Char *high, int n)
827 {
828     p++;
829 
830     while (n--) {
831         int  c_class;
832 
833         if (p >= high)
834             break;
835 
836         /* scan until end of current word (may be all whitespace!) */
837         c_class = c_to_class(*p);
838         while ((p < high) && c_class == c_to_class(*p))
839             p++;
840 
841         /* if this was a non_whitespace word, we're ready */
842         if (c_class != C_CLASS_WHITE)
843             continue;
844 
845         /* otherwise, move to the end of the word just found */
846         c_class = c_to_class(*p);
847         while ((p < high) && c_class == c_to_class(*p))
848             p++;
849     }
850 
851     p--;
852     return(p);
853 }
854 
855 /* Set the max length of the kill ring */
856 void
857 SetKillRing(int max)
858 {
859     CStr *new;
860     int count, i, j;
861 
862     if (max < 1)
863 	max = 1;		/* no ring, but always one buffer */
864     if (max == KillRingMax)
865 	return;
866     new = xcalloc(max, sizeof(CStr));
867     if (KillRing != NULL) {
868 	if (KillRingLen != 0) {
869 	    if (max >= KillRingLen) {
870 		count = KillRingLen;
871 		j = KillPos;
872 	    } else {
873 		count = max;
874 		j = (KillPos - count + KillRingLen) % KillRingLen;
875 	    }
876 	    for (i = 0; i < KillRingLen; i++) {
877 		if (i < count)	/* copy latest */
878 		    new[i] = KillRing[j];
879 		else		/* free the others */
880 		    xfree(KillRing[j].buf);
881 		j = (j + 1) % KillRingLen;
882 	    }
883 	    KillRingLen = count;
884 	    KillPos = count % max;
885 	    YankPos = count - 1;
886 	}
887 	xfree(KillRing);
888     }
889     KillRing = new;
890     KillRingMax = max;
891 }
892 
893 /* Push string from start upto (but not including) end onto kill ring */
894 static void
895 c_push_kill(Char *start, Char *end)
896 {
897     CStr save, *pos;
898     Char *dp, *cp, *kp;
899     int len = end - start, i, j, k;
900 
901     /* Check for duplicates? */
902     if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
903 	YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
904 	if (eq(dp, STRerase)) {	/* erase earlier one (actually move up) */
905 	    j = YankPos;
906 	    for (i = 0; i < KillRingLen; i++) {
907 		if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
908 		    KillRing[j].buf[len] == '\0') {
909 		    save = KillRing[j];
910 		    for ( ; i > 0; i--) {
911 			k = j;
912 			j = (j + 1) % KillRingLen;
913 			KillRing[k] = KillRing[j];
914 		    }
915 		    KillRing[j] = save;
916 		    return;
917 		}
918 		j = (j - 1 + KillRingLen) % KillRingLen;
919 	    }
920 	} else if (eq(dp, STRall)) { /* skip if any earlier */
921 	    for (i = 0; i < KillRingLen; i++)
922 		if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
923 		    KillRing[i].buf[len] == '\0')
924 		    return;
925 	} else if (eq(dp, STRprev)) { /* skip if immediately previous */
926 	    j = YankPos;
927 	    if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
928 		KillRing[j].buf[len] == '\0')
929 		return;
930 	}
931     }
932 
933     /* No duplicate, go ahead and push */
934     len++;			/* need space for '\0' */
935     YankPos = KillPos;
936     if (KillRingLen < KillRingMax)
937 	KillRingLen++;
938     pos = &KillRing[KillPos];
939     KillPos = (KillPos + 1) % KillRingMax;
940     if (pos->len < len) {
941 	pos->buf = xrealloc(pos->buf, len * sizeof(Char));
942 	pos->len = len;
943     }
944     cp = start;
945     kp = pos->buf;
946     while (cp < end)
947 	*kp++ = *cp++;
948     *kp = '\0';
949 }
950 
951 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
952 static void
953 c_save_inputbuf(void)
954 {
955     SavedBuf.len = 0;
956     Strbuf_append(&SavedBuf, InputBuf);
957     Strbuf_terminate(&SavedBuf);
958     LastSaved = LastChar - InputBuf;
959     CursSaved = Cursor - InputBuf;
960     HistSaved = Hist_num;
961     RestoreSaved = 1;
962 }
963 
964 CCRETVAL
965 GetHistLine(void)
966 {
967     struct Hist *hp;
968     int     h;
969 
970     if (Hist_num == 0) {	/* if really the current line */
971 	if (HistBuf.s != NULL)
972 	    copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
973 	else
974 	    *InputBuf = '\0';
975 	LastChar = InputBuf + HistBuf.len;
976 
977 #ifdef KSHVI
978     if (VImode)
979 	Cursor = InputBuf;
980     else
981 #endif /* KSHVI */
982 	Cursor = LastChar;
983 
984 	return(CC_REFRESH);
985     }
986 
987     hp = Histlist.Hnext;
988     if (hp == NULL)
989 	return(CC_ERROR);
990 
991     for (h = 1; h < Hist_num; h++) {
992 	if ((hp->Hnext) == NULL) {
993 	    Hist_num = h;
994 	    return(CC_ERROR);
995 	}
996 	hp = hp->Hnext;
997     }
998 
999     if (HistLit && hp->histline) {
1000 	copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1001 	CurrentHistLit = 1;
1002     }
1003     else {
1004 	Char *p;
1005 
1006 	p = sprlex(&hp->Hlex);
1007 	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1008 	xfree(p);
1009 	CurrentHistLit = 0;
1010     }
1011     LastChar = Strend(InputBuf);
1012 
1013     if (LastChar > InputBuf) {
1014 	if (LastChar[-1] == '\n')
1015 	    LastChar--;
1016 #if 0
1017 	if (LastChar[-1] == ' ')
1018 	    LastChar--;
1019 #endif
1020 	if (LastChar < InputBuf)
1021 	    LastChar = InputBuf;
1022     }
1023 
1024 #ifdef KSHVI
1025     if (VImode)
1026 	Cursor = InputBuf;
1027     else
1028 #endif /* KSHVI */
1029 	Cursor = LastChar;
1030 
1031     return(CC_REFRESH);
1032 }
1033 
1034 static CCRETVAL
1035 c_search_line(Char *pattern, int dir)
1036 {
1037     Char *cp;
1038     size_t len;
1039 
1040     len = Strlen(pattern);
1041 
1042     if (dir == F_UP_SEARCH_HIST) {
1043 	for (cp = Cursor; cp >= InputBuf; cp--)
1044 	    if (Strncmp(cp, pattern, len) == 0 ||
1045 		Gmatch(cp, pattern)) {
1046 		Cursor = cp;
1047 		return(CC_NORM);
1048 	    }
1049 	return(CC_ERROR);
1050     } else {
1051 	for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1052 	    if (Strncmp(cp, pattern, len) == 0 ||
1053 		Gmatch(cp, pattern)) {
1054 		Cursor = cp;
1055 		return(CC_NORM);
1056 	    }
1057 	return(CC_ERROR);
1058     }
1059 }
1060 
1061 static CCRETVAL
1062 e_inc_search(int dir)
1063 {
1064     static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1065 		      STRbck[] = { 'b', 'c', 'k', '\0' };
1066     static Char pchar = ':';	/* ':' = normal, '?' = failed */
1067     static Char endcmd[2];
1068     const Char *cp;
1069     Char ch,
1070 	*oldCursor = Cursor,
1071 	oldpchar = pchar;
1072     CCRETVAL ret = CC_NORM;
1073     int oldHist_num = Hist_num,
1074 	oldpatlen = patbuf.len,
1075 	newdir = dir,
1076         done, redo;
1077 
1078     if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1079 	return(CC_ERROR);
1080 
1081     for (;;) {
1082 
1083 	if (patbuf.len == 0) {	/* first round */
1084 	    pchar = ':';
1085 	    Strbuf_append1(&patbuf, '*');
1086 	}
1087 	done = redo = 0;
1088 	*LastChar++ = '\n';
1089 	for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1090 	     *cp; *LastChar++ = *cp++)
1091 	    continue;
1092 	*LastChar++ = pchar;
1093 	for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1094 	     *LastChar++ = *cp++)
1095 	    continue;
1096 	*LastChar = '\0';
1097 	if (adrof(STRhighlight) && pchar == ':') {
1098 	    /* if the no-glob-search patch is applied, remove the - 1 below */
1099 	    IncMatchLen = patbuf.len - 1;
1100 	    ClearLines();
1101 	    ClearDisp();
1102 	}
1103 	Refresh();
1104 
1105 	if (GetNextChar(&ch) != 1)
1106 	    return(e_send_eof(0));
1107 
1108 	switch (ch > NT_NUM_KEYS
1109 		? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
1110 	case F_INSERT:
1111 	case F_DIGIT:
1112 	case F_MAGIC_SPACE:
1113 	    if (LastChar + 1 >= InputLim) /*FIXBUF*/
1114 		SoundBeep();
1115 	    else {
1116 		Strbuf_append1(&patbuf, ch);
1117 		*LastChar++ = ch;
1118 		*LastChar = '\0';
1119 		Refresh();
1120 	    }
1121 	    break;
1122 
1123 	case F_INC_FWD:
1124 	    newdir = F_DOWN_SEARCH_HIST;
1125 	    redo++;
1126 	    break;
1127 
1128 	case F_INC_BACK:
1129 	    newdir = F_UP_SEARCH_HIST;
1130 	    redo++;
1131 	    break;
1132 
1133 	case F_DELPREV:
1134 	    if (patbuf.len > 1)
1135 		done++;
1136 	    else
1137 		SoundBeep();
1138 	    break;
1139 
1140 	default:
1141 	    switch (ASC(ch)) {
1142 	    case 0007:		/* ^G: Abort */
1143 		ret = CC_ERROR;
1144 		done++;
1145 		break;
1146 
1147 	    case 0027:		/* ^W: Append word */
1148 		/* No can do if globbing characters in pattern */
1149 		for (cp = &patbuf.s[1]; ; cp++)
1150 		    if (cp >= &patbuf.s[patbuf.len]) {
1151 			Cursor += patbuf.len - 1;
1152 			cp = c_next_word(Cursor, LastChar, 1);
1153 			while (Cursor < cp && *Cursor != '\n') {
1154 			    if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1155 				SoundBeep();
1156 				break;
1157 			    }
1158 			    Strbuf_append1(&patbuf, *Cursor);
1159 			    *LastChar++ = *Cursor++;
1160 			}
1161 			Cursor = oldCursor;
1162 			*LastChar = '\0';
1163 			Refresh();
1164 			break;
1165 		    } else if (isglob(*cp)) {
1166 			SoundBeep();
1167 			break;
1168 		    }
1169 		break;
1170 
1171 	    default:		/* Terminate and execute cmd */
1172 		endcmd[0] = ch;
1173 		PushMacro(endcmd);
1174 		/*FALLTHROUGH*/
1175 
1176 	    case 0033:		/* ESC: Terminate */
1177 		ret = CC_REFRESH;
1178 		done++;
1179 		break;
1180 	    }
1181 	    break;
1182 	}
1183 
1184 	while (LastChar > InputBuf && *LastChar != '\n')
1185 	    *LastChar-- = '\0';
1186 	*LastChar = '\0';
1187 
1188 	if (!done) {
1189 
1190 	    /* Can't search if unmatched '[' */
1191 	    for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1192 		if (*cp == '[' || *cp == ']') {
1193 		    ch = *cp;
1194 		    break;
1195 		}
1196 
1197 	    if (patbuf.len > 1 && ch != '[') {
1198 		if (redo && newdir == dir) {
1199 		    if (pchar == '?') {	/* wrap around */
1200 			Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1201 			if (GetHistLine() == CC_ERROR)
1202 			    /* Hist_num was fixed by first call */
1203 			    (void) GetHistLine();
1204 			Cursor = newdir == F_UP_SEARCH_HIST ?
1205 			    LastChar : InputBuf;
1206 		    } else
1207 			Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1208 		}
1209 		Strbuf_append1(&patbuf, '*');
1210 		Strbuf_terminate(&patbuf);
1211 		if (Cursor < InputBuf || Cursor > LastChar ||
1212 		    (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1213 		    LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1214 		    ret = newdir == F_UP_SEARCH_HIST ?
1215 			e_up_search_hist(0) : e_down_search_hist(0);
1216 		    if (ret != CC_ERROR) {
1217 			Cursor = newdir == F_UP_SEARCH_HIST ?
1218 			    LastChar : InputBuf;
1219 			(void) c_search_line(&patbuf.s[1], newdir);
1220 		    }
1221 		}
1222 		patbuf.s[--patbuf.len] = '\0';
1223 		if (ret == CC_ERROR) {
1224 		    SoundBeep();
1225 		    if (Hist_num != oldHist_num) {
1226 			Hist_num = oldHist_num;
1227 			if (GetHistLine() == CC_ERROR)
1228 			    return(CC_ERROR);
1229 		    }
1230 		    Cursor = oldCursor;
1231 		    pchar = '?';
1232 		} else {
1233 		    pchar = ':';
1234 		}
1235 	    }
1236 
1237 	    ret = e_inc_search(newdir);
1238 
1239 	    if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1240 		/* break abort of failed search at last non-failed */
1241 		ret = CC_NORM;
1242 	    }
1243 
1244 	}
1245 
1246 	if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1247 	    /* restore on normal return or error exit */
1248 	    pchar = oldpchar;
1249 	    patbuf.len = oldpatlen;
1250 	    if (Hist_num != oldHist_num) {
1251 		Hist_num = oldHist_num;
1252 		if (GetHistLine() == CC_ERROR)
1253 		    return(CC_ERROR);
1254 	    }
1255 	    Cursor = oldCursor;
1256 	    if (ret == CC_ERROR)
1257 		Refresh();
1258 	}
1259 	if (done || ret != CC_NORM)
1260 	    return(ret);
1261 
1262     }
1263 
1264 }
1265 
1266 static CCRETVAL
1267 v_search(int dir)
1268 {
1269     struct Strbuf tmpbuf = Strbuf_INIT;
1270     Char ch;
1271     Char *oldbuf;
1272     Char *oldlc, *oldc;
1273 
1274     cleanup_push(&tmpbuf, Strbuf_cleanup);
1275     oldbuf = Strsave(InputBuf);
1276     cleanup_push(oldbuf, xfree);
1277     oldlc = LastChar;
1278     oldc = Cursor;
1279     Strbuf_append1(&tmpbuf, '*');
1280 
1281     InputBuf[0] = '\0';
1282     LastChar = InputBuf;
1283     Cursor = InputBuf;
1284     searchdir = dir;
1285 
1286     c_insert(2);	/* prompt + '\n' */
1287     *Cursor++ = '\n';
1288     *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1289     Refresh();
1290     for (ch = 0;ch == 0;) {
1291 	if (GetNextChar(&ch) != 1) {
1292 	    cleanup_until(&tmpbuf);
1293 	    return(e_send_eof(0));
1294 	}
1295 	switch (ASC(ch)) {
1296 	case 0010:	/* Delete and backspace */
1297 	case 0177:
1298 	    if (tmpbuf.len > 1) {
1299 		*Cursor-- = '\0';
1300 		LastChar = Cursor;
1301 		tmpbuf.len--;
1302 	    }
1303 	    else {
1304 		copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1305 		LastChar = oldlc;
1306 		Cursor = oldc;
1307 		cleanup_until(&tmpbuf);
1308 		return(CC_REFRESH);
1309 	    }
1310 	    Refresh();
1311 	    ch = 0;
1312 	    break;
1313 
1314 	case 0033:	/* ESC */
1315 #ifdef IS_ASCII
1316 	case '\r':	/* Newline */
1317 	case '\n':
1318 #else
1319 	case '\012':    /* ASCII Line feed */
1320 	case '\015':    /* ASCII (or EBCDIC) Return */
1321 #endif
1322 	    break;
1323 
1324 	default:
1325 	    Strbuf_append1(&tmpbuf, ch);
1326 	    *Cursor++ = ch;
1327 	    LastChar = Cursor;
1328 	    Refresh();
1329 	    ch = 0;
1330 	    break;
1331 	}
1332     }
1333     cleanup_until(oldbuf);
1334 
1335     if (tmpbuf.len == 1) {
1336 	/*
1337 	 * Use the old pattern, but wild-card it.
1338 	 */
1339 	if (patbuf.len == 0) {
1340 	    InputBuf[0] = '\0';
1341 	    LastChar = InputBuf;
1342 	    Cursor = InputBuf;
1343 	    Refresh();
1344 	    cleanup_until(&tmpbuf);
1345 	    return(CC_ERROR);
1346 	}
1347 	if (patbuf.s[0] != '*') {
1348 	    oldbuf = Strsave(patbuf.s);
1349 	    patbuf.len = 0;
1350 	    Strbuf_append1(&patbuf, '*');
1351 	    Strbuf_append(&patbuf, oldbuf);
1352 	    xfree(oldbuf);
1353 	    Strbuf_append1(&patbuf, '*');
1354 	    Strbuf_terminate(&patbuf);
1355 	}
1356     }
1357     else {
1358 	Strbuf_append1(&tmpbuf, '*');
1359 	Strbuf_terminate(&tmpbuf);
1360 	patbuf.len = 0;
1361 	Strbuf_append(&patbuf, tmpbuf.s);
1362 	Strbuf_terminate(&patbuf);
1363     }
1364     cleanup_until(&tmpbuf);
1365     LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1366     Cursor = LastChar = InputBuf;
1367     if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1368 				   e_down_search_hist(0)) == CC_ERROR) {
1369 	Refresh();
1370 	return(CC_ERROR);
1371     }
1372     else {
1373 	if (ASC(ch) == 0033) {
1374 	    Refresh();
1375 	    *LastChar++ = '\n';
1376 	    *LastChar = '\0';
1377 	    PastBottom();
1378 	    return(CC_NEWLINE);
1379 	}
1380 	else
1381 	    return(CC_REFRESH);
1382     }
1383 }
1384 
1385 /*
1386  * semi-PUBLIC routines.  Any routine that is of type CCRETVAL is an
1387  * entry point, called from the CcKeyMap indirected into the
1388  * CcFuncTbl array.
1389  */
1390 
1391 /*ARGSUSED*/
1392 CCRETVAL
1393 v_cmd_mode(Char c)
1394 {
1395     USE(c);
1396     InsertPos = 0;
1397     ActionFlag = TCSHOP_NOP;	/* [Esc] cancels pending action */
1398     ActionPos = 0;
1399     DoingArg = 0;
1400     if (UndoPtr > Cursor)
1401 	UndoSize = (int)(UndoPtr - Cursor);
1402     else
1403 	UndoSize = (int)(Cursor - UndoPtr);
1404 
1405     inputmode = MODE_INSERT;
1406     c_alternativ_key_map(1);
1407 #ifdef notdef
1408     /*
1409      * We don't want to move the cursor, because all the editing
1410      * commands don't include the character under the cursor.
1411      */
1412     if (Cursor > InputBuf)
1413 	Cursor--;
1414 #endif
1415     RefCursor();
1416     return(CC_NORM);
1417 }
1418 
1419 /*ARGSUSED*/
1420 CCRETVAL
1421 e_unassigned(Char c)
1422 {				/* bound to keys that arn't really assigned */
1423     USE(c);
1424     SoundBeep();
1425     flush();
1426     return(CC_NORM);
1427 }
1428 
1429 #ifdef notyet
1430 static CCRETVAL
1431 e_insert_str(Char *c)
1432 {
1433     int i, n;
1434 
1435     n = Strlen(c);
1436     if (LastChar + Argument * n >= InputLim)
1437 	return(CC_ERROR);	/* end of buffer space */
1438     if (inputmode != MODE_INSERT) {
1439 	c_delafter(Argument * Strlen(c));
1440     }
1441     c_insert(Argument * n);
1442     while (Argument--) {
1443 	for (i = 0; i < n; i++)
1444 	    *Cursor++ = c[i];
1445     }
1446     Refresh();
1447     return(CC_NORM);
1448 }
1449 #endif
1450 
1451 CCRETVAL
1452 e_insert(Char c)
1453 {
1454 #ifndef SHORT_STRINGS
1455     c &= ASCII;			/* no meta chars ever */
1456 #endif
1457 
1458     if (!c)
1459 	return(CC_ERROR);	/* no NULs in the input ever!! */
1460 
1461     if (LastChar + Argument >= InputLim)
1462 	return(CC_ERROR);	/* end of buffer space */
1463 
1464     if (Argument == 1) {  	/* How was this optimized ???? */
1465 
1466 	if (inputmode != MODE_INSERT) {
1467 	    UndoBuf[UndoSize++] = *Cursor;
1468 	    UndoBuf[UndoSize] = '\0';
1469 	    c_delafter(1);   /* Do NOT use the saving ONE */
1470     	}
1471 
1472         c_insert(1);
1473 	*Cursor++ = (Char) c;
1474 	DoingArg = 0;		/* just in case */
1475 	RefPlusOne(1);		/* fast refresh for one char. */
1476     }
1477     else {
1478 	if (inputmode != MODE_INSERT) {
1479 	    int i;
1480 	    for(i = 0; i < Argument; i++)
1481 		UndoBuf[UndoSize++] = *(Cursor + i);
1482 
1483 	    UndoBuf[UndoSize] = '\0';
1484 	    c_delafter(Argument);   /* Do NOT use the saving ONE */
1485     	}
1486 
1487         c_insert(Argument);
1488 
1489 	while (Argument--)
1490 	    *Cursor++ = (Char) c;
1491 	Refresh();
1492     }
1493 
1494     if (inputmode == MODE_REPLACE_1)
1495 	(void) v_cmd_mode(0);
1496 
1497     return(CC_NORM);
1498 }
1499 
1500 int
1501 InsertStr(Char *s)		/* insert ASCIZ s at cursor (for complete) */
1502 {
1503     int len;
1504 
1505     if ((len = (int) Strlen(s)) <= 0)
1506 	return -1;
1507     if (LastChar + len >= InputLim)
1508 	return -1;		/* end of buffer space */
1509 
1510     c_insert(len);
1511     while (len--)
1512 	*Cursor++ = *s++;
1513     return 0;
1514 }
1515 
1516 void
1517 DeleteBack(int n)		/* delete the n characters before . */
1518 {
1519     if (n <= 0)
1520 	return;
1521     if (Cursor >= &InputBuf[n]) {
1522 	c_delbefore(n);		/* delete before dot */
1523     }
1524 }
1525 
1526 CCRETVAL
1527 e_digit(Char c)			/* gray magic here */
1528 {
1529     if (!Isdigit(c))
1530 	return(CC_ERROR);	/* no NULs in the input ever!! */
1531 
1532     if (DoingArg) {		/* if doing an arg, add this in... */
1533 	if (LastCmd == F_ARGFOUR)	/* if last command was ^U */
1534 	    Argument = c - '0';
1535 	else {
1536 	    if (Argument > 1000000)
1537 		return CC_ERROR;
1538 	    Argument = (Argument * 10) + (c - '0');
1539 	}
1540 	return(CC_ARGHACK);
1541     }
1542     else {
1543 	if (LastChar + 1 >= InputLim)
1544 	    return CC_ERROR;	/* end of buffer space */
1545 
1546 	if (inputmode != MODE_INSERT) {
1547 	    UndoBuf[UndoSize++] = *Cursor;
1548 	    UndoBuf[UndoSize] = '\0';
1549 	    c_delafter(1);   /* Do NOT use the saving ONE */
1550     	}
1551 	c_insert(1);
1552 	*Cursor++ = (Char) c;
1553 	DoingArg = 0;		/* just in case */
1554 	RefPlusOne(1);		/* fast refresh for one char. */
1555     }
1556     return(CC_NORM);
1557 }
1558 
1559 CCRETVAL
1560 e_argdigit(Char c)		/* for ESC-n */
1561 {
1562 #ifdef IS_ASCII
1563     c &= ASCII;
1564 #else
1565     c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1566 #endif
1567 
1568     if (!Isdigit(c))
1569 	return(CC_ERROR);	/* no NULs in the input ever!! */
1570 
1571     if (DoingArg) {		/* if doing an arg, add this in... */
1572 	if (Argument > 1000000)
1573 	    return CC_ERROR;
1574 	Argument = (Argument * 10) + (c - '0');
1575     }
1576     else {			/* else starting an argument */
1577 	Argument = c - '0';
1578 	DoingArg = 1;
1579     }
1580     return(CC_ARGHACK);
1581 }
1582 
1583 CCRETVAL
1584 v_zero(Char c)			/* command mode 0 for vi */
1585 {
1586     if (DoingArg) {		/* if doing an arg, add this in... */
1587 	if (Argument > 1000000)
1588 	    return CC_ERROR;
1589 	Argument = (Argument * 10) + (c - '0');
1590 	return(CC_ARGHACK);
1591     }
1592     else {			/* else starting an argument */
1593 	Cursor = InputBuf;
1594 	if (ActionFlag & TCSHOP_DELETE) {
1595 	   c_delfini();
1596 	   return(CC_REFRESH);
1597         }
1598 	RefCursor();		/* move the cursor */
1599 	return(CC_NORM);
1600     }
1601 }
1602 
1603 /*ARGSUSED*/
1604 CCRETVAL
1605 e_newline(Char c)
1606 {				/* always ignore argument */
1607     USE(c);
1608     if (adrof(STRhighlight) && MarkIsSet) {
1609 	MarkIsSet = 0;
1610 	ClearLines();
1611 	ClearDisp();
1612 	Refresh();
1613     }
1614     MarkIsSet = 0;
1615 
1616   /*  PastBottom();  NOW done in ed.inputl.c */
1617     *LastChar++ = '\n';		/* for the benefit of CSH */
1618     *LastChar = '\0';		/* just in case */
1619     if (VImode)
1620 	InsertPos = InputBuf;	/* Reset editing position */
1621     return(CC_NEWLINE);
1622 }
1623 
1624 /*ARGSUSED*/
1625 CCRETVAL
1626 e_newline_hold(Char c)
1627 {
1628     USE(c);
1629     c_save_inputbuf();
1630     HistSaved = 0;
1631     *LastChar++ = '\n';		/* for the benefit of CSH */
1632     *LastChar = '\0';		/* just in case */
1633     return(CC_NEWLINE);
1634 }
1635 
1636 /*ARGSUSED*/
1637 CCRETVAL
1638 e_newline_down_hist(Char c)
1639 {
1640     USE(c);
1641     if (Hist_num > 1) {
1642 	HistSaved = Hist_num;
1643     }
1644     *LastChar++ = '\n';		/* for the benefit of CSH */
1645     *LastChar = '\0';		/* just in case */
1646     return(CC_NEWLINE);
1647 }
1648 
1649 /*ARGSUSED*/
1650 CCRETVAL
1651 e_send_eof(Char c)
1652 {				/* for when ^D is ONLY send-eof */
1653     USE(c);
1654     PastBottom();
1655     *LastChar = '\0';		/* just in case */
1656     return(CC_EOF);
1657 }
1658 
1659 /*ARGSUSED*/
1660 CCRETVAL
1661 e_complete(Char c)
1662 {
1663     USE(c);
1664     *LastChar = '\0';		/* just in case */
1665     return(CC_COMPLETE);
1666 }
1667 
1668 /*ARGSUSED*/
1669 CCRETVAL
1670 e_complete_back(Char c)
1671 {
1672     USE(c);
1673     *LastChar = '\0';		/* just in case */
1674     return(CC_COMPLETE_BACK);
1675 }
1676 
1677 /*ARGSUSED*/
1678 CCRETVAL
1679 e_complete_fwd(Char c)
1680 {
1681     USE(c);
1682     *LastChar = '\0';		/* just in case */
1683     return(CC_COMPLETE_FWD);
1684 }
1685 
1686 /*ARGSUSED*/
1687 CCRETVAL
1688 e_complete_all(Char c)
1689 {
1690     USE(c);
1691     *LastChar = '\0';		/* just in case */
1692     return(CC_COMPLETE_ALL);
1693 }
1694 
1695 /*ARGSUSED*/
1696 CCRETVAL
1697 v_cm_complete(Char c)
1698 {
1699     USE(c);
1700     if (Cursor < LastChar)
1701 	Cursor++;
1702     *LastChar = '\0';		/* just in case */
1703     return(CC_COMPLETE);
1704 }
1705 
1706 /*ARGSUSED*/
1707 CCRETVAL
1708 e_toggle_hist(Char c)
1709 {
1710     struct Hist *hp;
1711     int     h;
1712 
1713     USE(c);
1714     *LastChar = '\0';		/* just in case */
1715 
1716     if (Hist_num <= 0) {
1717 	return CC_ERROR;
1718     }
1719 
1720     hp = Histlist.Hnext;
1721     if (hp == NULL) {	/* this is only if no history */
1722 	return(CC_ERROR);
1723     }
1724 
1725     for (h = 1; h < Hist_num; h++)
1726 	hp = hp->Hnext;
1727 
1728     if (!CurrentHistLit) {
1729 	if (hp->histline) {
1730 	    copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1731 	    CurrentHistLit = 1;
1732 	}
1733 	else {
1734 	    return CC_ERROR;
1735 	}
1736     }
1737     else {
1738 	Char *p;
1739 
1740 	p = sprlex(&hp->Hlex);
1741 	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1742 	xfree(p);
1743 	CurrentHistLit = 0;
1744     }
1745 
1746     LastChar = Strend(InputBuf);
1747     if (LastChar > InputBuf) {
1748 	if (LastChar[-1] == '\n')
1749 	    LastChar--;
1750 	if (LastChar[-1] == ' ')
1751 	    LastChar--;
1752 	if (LastChar < InputBuf)
1753 	    LastChar = InputBuf;
1754     }
1755 
1756 #ifdef KSHVI
1757     if (VImode)
1758 	Cursor = InputBuf;
1759     else
1760 #endif /* KSHVI */
1761 	Cursor = LastChar;
1762 
1763     return(CC_REFRESH);
1764 }
1765 
1766 /*ARGSUSED*/
1767 CCRETVAL
1768 e_up_hist(Char c)
1769 {
1770     Char    beep = 0;
1771 
1772     USE(c);
1773     UndoAction = TCSHOP_NOP;
1774     *LastChar = '\0';		/* just in case */
1775 
1776     if (Hist_num == 0) {	/* save the current buffer away */
1777 	HistBuf.len = 0;
1778 	Strbuf_append(&HistBuf, InputBuf);
1779 	Strbuf_terminate(&HistBuf);
1780     }
1781 
1782     Hist_num += Argument;
1783 
1784     if (GetHistLine() == CC_ERROR) {
1785 	beep = 1;
1786 	(void) GetHistLine(); /* Hist_num was fixed by first call */
1787     }
1788 
1789     Refresh();
1790     if (beep)
1791 	return(CC_ERROR);
1792     else
1793 	return(CC_NORM);	/* was CC_UP_HIST */
1794 }
1795 
1796 /*ARGSUSED*/
1797 CCRETVAL
1798 e_down_hist(Char c)
1799 {
1800     USE(c);
1801     UndoAction = TCSHOP_NOP;
1802     *LastChar = '\0';		/* just in case */
1803 
1804     Hist_num -= Argument;
1805 
1806     if (Hist_num < 0) {
1807 	Hist_num = 0;
1808 	return(CC_ERROR);	/* make it beep */
1809     }
1810 
1811     return(GetHistLine());
1812 }
1813 
1814 
1815 
1816 /*
1817  * c_hmatch() return True if the pattern matches the prefix
1818  */
1819 static int
1820 c_hmatch(Char *str)
1821 {
1822     if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1823 	return 1;
1824     return Gmatch(str, patbuf.s);
1825 }
1826 
1827 /*
1828  * c_hsetpat(): Set the history seatch pattern
1829  */
1830 static void
1831 c_hsetpat(void)
1832 {
1833     if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1834 	patbuf.len = 0;
1835 	Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1836 	Strbuf_terminate(&patbuf);
1837     }
1838 #ifdef SDEBUG
1839     xprintf("\nHist_num = %d\n", Hist_num);
1840     xprintf("patlen = %d\n", (int)patbuf.len);
1841     xprintf("patbuf = \"%S\"\n", patbuf.s);
1842     xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1843 #endif
1844 }
1845 
1846 /*ARGSUSED*/
1847 CCRETVAL
1848 e_up_search_hist(Char c)
1849 {
1850     struct Hist *hp;
1851     int h;
1852     int    found = 0;
1853 
1854     USE(c);
1855     ActionFlag = TCSHOP_NOP;
1856     UndoAction = TCSHOP_NOP;
1857     *LastChar = '\0';		/* just in case */
1858     if (Hist_num < 0) {
1859 #ifdef DEBUG_EDIT
1860 	xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1861 #endif
1862 	Hist_num = 0;
1863 	return(CC_ERROR);
1864     }
1865 
1866     if (Hist_num == 0) {
1867 	HistBuf.len = 0;
1868 	Strbuf_append(&HistBuf, InputBuf);
1869 	Strbuf_terminate(&HistBuf);
1870     }
1871 
1872 
1873     hp = Histlist.Hnext;
1874     if (hp == NULL)
1875 	return(CC_ERROR);
1876 
1877     c_hsetpat();		/* Set search pattern !! */
1878 
1879     for (h = 1; h <= Hist_num; h++)
1880 	hp = hp->Hnext;
1881 
1882     while (hp != NULL) {
1883 	Char *hl;
1884 	int matched;
1885 
1886 	if (hp->histline == NULL)
1887 	    hp->histline = sprlex(&hp->Hlex);
1888 	if (HistLit)
1889 	    hl = hp->histline;
1890 	else {
1891 	    hl = sprlex(&hp->Hlex);
1892 	    cleanup_push(hl, xfree);
1893 	}
1894 #ifdef SDEBUG
1895 	xprintf("Comparing with \"%S\"\n", hl);
1896 #endif
1897 	matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1898 		   hl[LastChar-InputBuf]) && c_hmatch(hl);
1899 	if (!HistLit)
1900 	    cleanup_until(hl);
1901 	if (matched) {
1902 	    found++;
1903 	    break;
1904 	}
1905 	h++;
1906 	hp = hp->Hnext;
1907     }
1908 
1909     if (!found) {
1910 #ifdef SDEBUG
1911 	xprintf("not found\n");
1912 #endif
1913 	return(CC_ERROR);
1914     }
1915 
1916     Hist_num = h;
1917 
1918     return(GetHistLine());
1919 }
1920 
1921 /*ARGSUSED*/
1922 CCRETVAL
1923 e_down_search_hist(Char c)
1924 {
1925     struct Hist *hp;
1926     int h;
1927     int    found = 0;
1928 
1929     USE(c);
1930     ActionFlag = TCSHOP_NOP;
1931     UndoAction = TCSHOP_NOP;
1932     *LastChar = '\0';		/* just in case */
1933 
1934     if (Hist_num == 0)
1935 	return(CC_ERROR);
1936 
1937     hp = Histlist.Hnext;
1938     if (hp == 0)
1939 	return(CC_ERROR);
1940 
1941     c_hsetpat();		/* Set search pattern !! */
1942 
1943     for (h = 1; h < Hist_num && hp; h++) {
1944 	Char *hl;
1945 	if (hp->histline == NULL)
1946 	    hp->histline = sprlex(&hp->Hlex);
1947 	if (HistLit)
1948 	    hl = hp->histline;
1949 	else {
1950 	    hl = sprlex(&hp->Hlex);
1951 	    cleanup_push(hl, xfree);
1952 	}
1953 #ifdef SDEBUG
1954 	xprintf("Comparing with \"%S\"\n", hl);
1955 #endif
1956 	if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1957 	     hl[LastChar-InputBuf]) && c_hmatch(hl))
1958 	    found = h;
1959 	if (!HistLit)
1960 	    cleanup_until(hl);
1961 	hp = hp->Hnext;
1962     }
1963 
1964     if (!found) {		/* is it the current history number? */
1965 	if (!c_hmatch(HistBuf.s)) {
1966 #ifdef SDEBUG
1967 	    xprintf("not found\n");
1968 #endif
1969 	    return(CC_ERROR);
1970 	}
1971     }
1972 
1973     Hist_num = found;
1974 
1975     return(GetHistLine());
1976 }
1977 
1978 /*ARGSUSED*/
1979 CCRETVAL
1980 e_helpme(Char c)
1981 {
1982     USE(c);
1983     PastBottom();
1984     *LastChar = '\0';		/* just in case */
1985     return(CC_HELPME);
1986 }
1987 
1988 /*ARGSUSED*/
1989 CCRETVAL
1990 e_correct(Char c)
1991 {
1992     USE(c);
1993     *LastChar = '\0';		/* just in case */
1994     return(CC_CORRECT);
1995 }
1996 
1997 /*ARGSUSED*/
1998 CCRETVAL
1999 e_correctl(Char c)
2000 {
2001     USE(c);
2002     *LastChar = '\0';		/* just in case */
2003     return(CC_CORRECT_L);
2004 }
2005 
2006 /*ARGSUSED*/
2007 CCRETVAL
2008 e_run_fg_editor(Char c)
2009 {
2010     struct process *pp;
2011 
2012     USE(c);
2013     if ((pp = find_stop_ed()) != NULL) {
2014 	/* save our editor state so we can restore it */
2015 	c_save_inputbuf();
2016 	Hist_num = 0;		/* for the history commands */
2017 
2018 	/* put the tty in a sane mode */
2019 	PastBottom();
2020 	(void) Cookedmode();	/* make sure the tty is set up correctly */
2021 
2022 	/* do it! */
2023 	fg_proc_entry(pp);
2024 
2025 	(void) Rawmode();	/* go on */
2026 	Refresh();
2027 	RestoreSaved = 0;
2028 	HistSaved = 0;
2029     }
2030     return(CC_NORM);
2031 }
2032 
2033 /*ARGSUSED*/
2034 CCRETVAL
2035 e_list_choices(Char c)
2036 {
2037     USE(c);
2038     PastBottom();
2039     *LastChar = '\0';		/* just in case */
2040     return(CC_LIST_CHOICES);
2041 }
2042 
2043 /*ARGSUSED*/
2044 CCRETVAL
2045 e_list_all(Char c)
2046 {
2047     USE(c);
2048     PastBottom();
2049     *LastChar = '\0';		/* just in case */
2050     return(CC_LIST_ALL);
2051 }
2052 
2053 /*ARGSUSED*/
2054 CCRETVAL
2055 e_list_glob(Char c)
2056 {
2057     USE(c);
2058     PastBottom();
2059     *LastChar = '\0';		/* just in case */
2060     return(CC_LIST_GLOB);
2061 }
2062 
2063 /*ARGSUSED*/
2064 CCRETVAL
2065 e_expand_glob(Char c)
2066 {
2067     USE(c);
2068     *LastChar = '\0';		/* just in case */
2069     return(CC_EXPAND_GLOB);
2070 }
2071 
2072 /*ARGSUSED*/
2073 CCRETVAL
2074 e_normalize_path(Char c)
2075 {
2076     USE(c);
2077     *LastChar = '\0';		/* just in case */
2078     return(CC_NORMALIZE_PATH);
2079 }
2080 
2081 /*ARGSUSED*/
2082 CCRETVAL
2083 e_normalize_command(Char c)
2084 {
2085     USE(c);
2086     *LastChar = '\0';		/* just in case */
2087     return(CC_NORMALIZE_COMMAND);
2088 }
2089 
2090 /*ARGSUSED*/
2091 CCRETVAL
2092 e_expand_vars(Char c)
2093 {
2094     USE(c);
2095     *LastChar = '\0';		/* just in case */
2096     return(CC_EXPAND_VARS);
2097 }
2098 
2099 /*ARGSUSED*/
2100 CCRETVAL
2101 e_which(Char c)
2102 {				/* do a fast command line which(1) */
2103     USE(c);
2104     c_save_inputbuf();
2105     Hist_num = 0;		/* for the history commands */
2106     PastBottom();
2107     *LastChar = '\0';		/* just in case */
2108     return(CC_WHICH);
2109 }
2110 
2111 /*ARGSUSED*/
2112 CCRETVAL
2113 e_last_item(Char c)
2114 {				/* insert the last element of the prev. cmd */
2115     struct Hist *hp;
2116     struct wordent *wp, *firstp;
2117     int i;
2118     Char *expanded;
2119 
2120     USE(c);
2121     if (Argument <= 0)
2122 	return(CC_ERROR);
2123 
2124     hp = Histlist.Hnext;
2125     if (hp == NULL) {	/* this is only if no history */
2126 	return(CC_ERROR);
2127     }
2128 
2129     wp = (hp->Hlex).prev;
2130 
2131     if (wp->prev == (struct wordent *) NULL)
2132 	return(CC_ERROR);	/* an empty history entry */
2133 
2134     firstp = (hp->Hlex).next;
2135 
2136     /* back up arg words in lex */
2137     for (i = 0; i < Argument && wp != firstp; i++) {
2138 	wp = wp->prev;
2139     }
2140 
2141     expanded = expand_lex(wp->prev, 0, i - 1);
2142     if (InsertStr(expanded)) {
2143 	xfree(expanded);
2144 	return(CC_ERROR);
2145     }
2146 
2147     xfree(expanded);
2148     return(CC_REFRESH);
2149 }
2150 
2151 /*ARGSUSED*/
2152 CCRETVAL
2153 e_dabbrev_expand(Char c)
2154 {				/* expand to preceding word matching prefix */
2155     Char *cp, *ncp, *bp;
2156     struct Hist *hp;
2157     int arg = 0, i;
2158     size_t len = 0;
2159     int found = 0;
2160     Char *hbuf;
2161     static int oldevent, hist, word;
2162     static Char *start, *oldcursor;
2163 
2164     USE(c);
2165     if (Argument <= 0)
2166 	return(CC_ERROR);
2167 
2168     cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2169     if (cp == Cursor || Isspace(*cp))
2170 	return(CC_ERROR);
2171 
2172     hbuf = NULL;
2173     hp = Histlist.Hnext;
2174     bp = InputBuf;
2175     if (Argument == 1 && eventno == oldevent && cp == start &&
2176 	Cursor == oldcursor && patbuf.len > 0
2177 	&& Strncmp(patbuf.s, cp, patbuf.len) == 0){
2178 	/* continue previous search - go to last match (hist/word) */
2179 	if (hist != 0) {		/* need to move up history */
2180 	    for (i = 1; i < hist && hp != NULL; i++)
2181 		hp = hp->Hnext;
2182 	    if (hp == NULL)	/* "can't happen" */
2183 		goto err_hbuf;
2184 	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2185 	    cp = Strend(hbuf);
2186 	    bp = hbuf;
2187 	    hp = hp->Hnext;
2188 	}
2189 	cp = c_preword(cp, bp, word, STRshwordsep);
2190     } else {			/* starting new search */
2191 	oldevent = eventno;
2192 	start = cp;
2193 	patbuf.len = 0;
2194 	Strbuf_appendn(&patbuf, cp, Cursor - cp);
2195 	hist = 0;
2196 	word = 0;
2197     }
2198 
2199     while (!found) {
2200 	ncp = c_preword(cp, bp, 1, STRshwordsep);
2201 	if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2202 	    hist++;
2203 	    word = 0;
2204 	    if (hp == NULL)
2205 		goto err_hbuf;
2206 	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2207 	    cp = Strend(hbuf);
2208 	    bp = hbuf;
2209 	    hp = hp->Hnext;
2210 	    continue;
2211 	} else {
2212 	    word++;
2213 	    len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2214 	    cp = ncp;
2215 	}
2216 	if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2217 	    /* We don't fully check distinct matches as Gnuemacs does: */
2218 	    if (Argument > 1) {	/* just count matches */
2219 		if (++arg >= Argument)
2220 		    found++;
2221 	    } else {		/* match if distinct from previous */
2222 		if (len != (size_t)(Cursor - start)
2223 		    || Strncmp(cp, start, len) != 0)
2224 		    found++;
2225 	    }
2226 	}
2227     }
2228 
2229     if (LastChar + len - (Cursor - start) >= InputLim)
2230 	goto err_hbuf;	/* no room */
2231     DeleteBack(Cursor - start);
2232     c_insert(len);
2233     while (len--)
2234 	*Cursor++ = *cp++;
2235     oldcursor = Cursor;
2236     xfree(hbuf);
2237     return(CC_REFRESH);
2238 
2239  err_hbuf:
2240     xfree(hbuf);
2241     return CC_ERROR;
2242 }
2243 
2244 /*ARGSUSED*/
2245 CCRETVAL
2246 e_yank_kill(Char c)
2247 {				/* almost like GnuEmacs */
2248     int len;
2249     Char *kp, *cp;
2250 
2251     USE(c);
2252     if (KillRingLen == 0)	/* nothing killed */
2253 	return(CC_ERROR);
2254     len = Strlen(KillRing[YankPos].buf);
2255     if (LastChar + len >= InputLim)
2256 	return(CC_ERROR);	/* end of buffer space */
2257 
2258     /* else */
2259     cp = Cursor;		/* for speed */
2260 
2261     c_insert(len);		/* open the space, */
2262     for (kp = KillRing[YankPos].buf; *kp; kp++)	/* copy the chars */
2263 	*cp++ = *kp;
2264 
2265     if (Argument == 1) {	/* if no arg */
2266 	Mark = Cursor;		/* mark at beginning, cursor at end */
2267 	Cursor = cp;
2268     } else {
2269 	Mark = cp;		/* else cursor at beginning, mark at end */
2270     }
2271 
2272     if (adrof(STRhighlight) && MarkIsSet) {
2273 	ClearLines();
2274 	ClearDisp();
2275     }
2276     MarkIsSet = 0;
2277     return(CC_REFRESH);
2278 }
2279 
2280 /*ARGSUSED*/
2281 CCRETVAL
2282 e_yank_pop(Char c)
2283 {				/* almost like GnuEmacs */
2284     int m_bef_c, del_len, ins_len;
2285     Char *kp, *cp;
2286 
2287     USE(c);
2288 
2289 #if 0
2290     /* XXX This "should" be here, but doesn't work, since LastCmd
2291        gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2292        (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2293        second one will "succeed" even if the first one wasn't preceded
2294        by a yank, and giving an argument is impossible. Now we "succeed"
2295        regardless of previous command, which is wrong too of course. */
2296     if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2297 	return(CC_ERROR);
2298 #endif
2299 
2300     if (KillRingLen == 0)	/* nothing killed */
2301 	return(CC_ERROR);
2302     YankPos -= Argument;
2303     while (YankPos < 0)
2304 	YankPos += KillRingLen;
2305     YankPos %= KillRingLen;
2306 
2307     if (Cursor > Mark) {
2308 	del_len = Cursor - Mark;
2309 	m_bef_c = 1;
2310     } else {
2311 	del_len = Mark - Cursor;
2312 	m_bef_c = 0;
2313     }
2314     ins_len = Strlen(KillRing[YankPos].buf);
2315     if (LastChar + ins_len - del_len >= InputLim)
2316 	return(CC_ERROR);	/* end of buffer space */
2317 
2318     if (m_bef_c) {
2319 	c_delbefore(del_len);
2320     } else {
2321 	c_delafter(del_len);
2322     }
2323     cp = Cursor;		/* for speed */
2324 
2325     c_insert(ins_len);		/* open the space, */
2326     for (kp = KillRing[YankPos].buf; *kp; kp++)	/* copy the chars */
2327 	*cp++ = *kp;
2328 
2329     if (m_bef_c) {
2330 	Mark = Cursor;		/* mark at beginning, cursor at end */
2331 	Cursor = cp;
2332     } else {
2333 	Mark = cp;		/* else cursor at beginning, mark at end */
2334     }
2335 
2336     if (adrof(STRhighlight) && MarkIsSet) {
2337 	ClearLines();
2338 	ClearDisp();
2339     }
2340     MarkIsSet = 0;
2341     return(CC_REFRESH);
2342 }
2343 
2344 /*ARGSUSED*/
2345 CCRETVAL
2346 v_delprev(Char c) 		/* Backspace key in insert mode */
2347 {
2348     int rc;
2349 
2350     USE(c);
2351     rc = CC_ERROR;
2352 
2353     if (InsertPos != 0) {
2354 	if (Argument <= Cursor - InsertPos) {
2355 	    c_delbefore(Argument);	/* delete before */
2356 	    rc = CC_REFRESH;
2357 	}
2358     }
2359     return(rc);
2360 }   /* v_delprev  */
2361 
2362 /*ARGSUSED*/
2363 CCRETVAL
2364 e_delprev(Char c)
2365 {
2366     USE(c);
2367     if (Cursor > InputBuf) {
2368 	c_delbefore(Argument);	/* delete before dot */
2369 	return(CC_REFRESH);
2370     }
2371     else {
2372 	return(CC_ERROR);
2373     }
2374 }
2375 
2376 /*ARGSUSED*/
2377 CCRETVAL
2378 e_delwordprev(Char c)
2379 {
2380     Char *cp;
2381 
2382     USE(c);
2383     if (Cursor == InputBuf)
2384 	return(CC_ERROR);
2385     /* else */
2386 
2387     cp = c_prev_word(Cursor, InputBuf, Argument);
2388 
2389     c_push_kill(cp, Cursor);	/* save the text */
2390 
2391     c_delbefore((int)(Cursor - cp));	/* delete before dot */
2392     return(CC_REFRESH);
2393 }
2394 
2395 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2396  *
2397  * Changed the names of some of the ^D family of editor functions to
2398  * correspond to what they actually do and created new e_delnext_list
2399  * for completeness.
2400  *
2401  *   Old names:			New names:
2402  *
2403  *   delete-char		delete-char-or-eof
2404  *     F_DELNEXT		  F_DELNEXT_EOF
2405  *     e_delnext		  e_delnext_eof
2406  *     edelnxt			  edelnxteof
2407  *   delete-char-or-eof		delete-char
2408  *     F_DELNEXT_EOF		  F_DELNEXT
2409  *     e_delnext_eof		  e_delnext
2410  *     edelnxteof		  edelnxt
2411  *   delete-char-or-list	delete-char-or-list-or-eof
2412  *     F_LIST_DELNEXT		  F_DELNEXT_LIST_EOF
2413  *     e_list_delnext		  e_delnext_list_eof
2414  *   				  edellsteof
2415  *   (no old equivalent)	delete-char-or-list
2416  *   				  F_DELNEXT_LIST
2417  *   				  e_delnext_list
2418  *   				  e_delnxtlst
2419  */
2420 
2421 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2422 /* rename e_delnext() -> e_delnext_eof() */
2423 /*ARGSUSED*/
2424 CCRETVAL
2425 e_delnext(Char c)
2426 {
2427     USE(c);
2428     if (Cursor == LastChar) {/* if I'm at the end */
2429 	if (!VImode) {
2430 		return(CC_ERROR);
2431 	}
2432 	else {
2433 	    if (Cursor != InputBuf)
2434 		Cursor--;
2435 	    else
2436 		return(CC_ERROR);
2437 	}
2438     }
2439     c_delafter(Argument);	/* delete after dot */
2440     if (Cursor > LastChar)
2441 	Cursor = LastChar;	/* bounds check */
2442     return(CC_REFRESH);
2443 }
2444 
2445 
2446 /*ARGSUSED*/
2447 CCRETVAL
2448 e_delnext_eof(Char c)
2449 {
2450     USE(c);
2451     if (Cursor == LastChar) {/* if I'm at the end */
2452 	if (!VImode) {
2453 	    if (Cursor == InputBuf) {
2454 		/* if I'm also at the beginning */
2455 		so_write(STReof, 4);/* then do a EOF */
2456 		flush();
2457 		return(CC_EOF);
2458 	    }
2459 	    else
2460 		return(CC_ERROR);
2461 	}
2462 	else {
2463 	    if (Cursor != InputBuf)
2464 		Cursor--;
2465 	    else
2466 		return(CC_ERROR);
2467 	}
2468     }
2469     c_delafter(Argument);	/* delete after dot */
2470     if (Cursor > LastChar)
2471 	Cursor = LastChar;	/* bounds check */
2472     return(CC_REFRESH);
2473 }
2474 
2475 /*ARGSUSED*/
2476 CCRETVAL
2477 e_delnext_list(Char c)
2478 {
2479     USE(c);
2480     if (Cursor == LastChar) {	/* if I'm at the end */
2481 	PastBottom();
2482 	*LastChar = '\0';	/* just in case */
2483 	return(CC_LIST_CHOICES);
2484     }
2485     else {
2486 	c_delafter(Argument);	/* delete after dot */
2487 	if (Cursor > LastChar)
2488 	    Cursor = LastChar;	/* bounds check */
2489 	return(CC_REFRESH);
2490     }
2491 }
2492 
2493 /*ARGSUSED*/
2494 CCRETVAL
2495 e_delnext_list_eof(Char c)
2496 {
2497     USE(c);
2498     if (Cursor == LastChar) {	/* if I'm at the end */
2499 	if (Cursor == InputBuf) {	/* if I'm also at the beginning */
2500 	    so_write(STReof, 4);/* then do a EOF */
2501 	    flush();
2502 	    return(CC_EOF);
2503 	}
2504 	else {
2505 	    PastBottom();
2506 	    *LastChar = '\0';	/* just in case */
2507 	    return(CC_LIST_CHOICES);
2508 	}
2509     }
2510     else {
2511 	c_delafter(Argument);	/* delete after dot */
2512 	if (Cursor > LastChar)
2513 	    Cursor = LastChar;	/* bounds check */
2514 	return(CC_REFRESH);
2515     }
2516 }
2517 
2518 /*ARGSUSED*/
2519 CCRETVAL
2520 e_list_eof(Char c)
2521 {
2522     CCRETVAL rv;
2523 
2524     USE(c);
2525     if (Cursor == LastChar && Cursor == InputBuf) {
2526 	so_write(STReof, 4);	/* then do a EOF */
2527 	flush();
2528 	rv = CC_EOF;
2529     }
2530     else {
2531 	PastBottom();
2532 	*LastChar = '\0';	/* just in case */
2533 	rv = CC_LIST_CHOICES;
2534     }
2535     return rv;
2536 }
2537 
2538 /*ARGSUSED*/
2539 CCRETVAL
2540 e_delwordnext(Char c)
2541 {
2542     Char *cp;
2543 
2544     USE(c);
2545     if (Cursor == LastChar)
2546 	return(CC_ERROR);
2547     /* else */
2548 
2549     cp = c_next_word(Cursor, LastChar, Argument);
2550 
2551     c_push_kill(Cursor, cp);	/* save the text */
2552 
2553     c_delafter((int)(cp - Cursor));	/* delete after dot */
2554     if (Cursor > LastChar)
2555 	Cursor = LastChar;	/* bounds check */
2556     return(CC_REFRESH);
2557 }
2558 
2559 /*ARGSUSED*/
2560 CCRETVAL
2561 e_toend(Char c)
2562 {
2563     USE(c);
2564     Cursor = LastChar;
2565     if (VImode)
2566 	if (ActionFlag & TCSHOP_DELETE) {
2567 	    c_delfini();
2568 	    return(CC_REFRESH);
2569 	}
2570     RefCursor();		/* move the cursor */
2571     return(CC_NORM);
2572 }
2573 
2574 /*ARGSUSED*/
2575 CCRETVAL
2576 e_tobeg(Char c)
2577 {
2578     USE(c);
2579     Cursor = InputBuf;
2580 
2581     if (VImode) {
2582        while (Isspace(*Cursor)) /* We want FIRST non space character */
2583 	Cursor++;
2584 	if (ActionFlag & TCSHOP_DELETE) {
2585 	    c_delfini();
2586 	    return(CC_REFRESH);
2587 	}
2588     }
2589 
2590     RefCursor();		/* move the cursor */
2591     return(CC_NORM);
2592 }
2593 
2594 /*ARGSUSED*/
2595 CCRETVAL
2596 e_killend(Char c)
2597 {
2598     USE(c);
2599     c_push_kill(Cursor, LastChar); /* copy it */
2600     LastChar = Cursor;		/* zap! -- delete to end */
2601     if (Mark > Cursor)
2602         Mark = Cursor;
2603     MarkIsSet = 0;
2604     return(CC_REFRESH);
2605 }
2606 
2607 
2608 /*ARGSUSED*/
2609 CCRETVAL
2610 e_killbeg(Char c)
2611 {
2612     USE(c);
2613     c_push_kill(InputBuf, Cursor); /* copy it */
2614     c_delbefore((int)(Cursor - InputBuf));
2615     if (Mark && Mark > Cursor)
2616         Mark -= Cursor-InputBuf;
2617     return(CC_REFRESH);
2618 }
2619 
2620 /*ARGSUSED*/
2621 CCRETVAL
2622 e_killall(Char c)
2623 {
2624     USE(c);
2625     c_push_kill(InputBuf, LastChar); /* copy it */
2626     Cursor = Mark = LastChar = InputBuf;	/* zap! -- delete all of it */
2627     MarkIsSet = 0;
2628     return(CC_REFRESH);
2629 }
2630 
2631 /*ARGSUSED*/
2632 CCRETVAL
2633 e_killregion(Char c)
2634 {
2635     USE(c);
2636     if (!Mark)
2637 	return(CC_ERROR);
2638 
2639     if (Mark > Cursor) {
2640 	c_push_kill(Cursor, Mark); /* copy it */
2641 	c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2642 	Mark = Cursor;
2643     }
2644     else {			/* mark is before cursor */
2645 	c_push_kill(Mark, Cursor); /* copy it */
2646 	c_delbefore((int)(Cursor - Mark));
2647     }
2648     if (adrof(STRhighlight) && MarkIsSet) {
2649 	ClearLines();
2650 	ClearDisp();
2651     }
2652     MarkIsSet = 0;
2653     return(CC_REFRESH);
2654 }
2655 
2656 /*ARGSUSED*/
2657 CCRETVAL
2658 e_copyregion(Char c)
2659 {
2660     USE(c);
2661     if (!Mark)
2662 	return(CC_ERROR);
2663 
2664     if (Mark > Cursor) {
2665 	c_push_kill(Cursor, Mark); /* copy it */
2666     }
2667     else {			/* mark is before cursor */
2668 	c_push_kill(Mark, Cursor); /* copy it */
2669     }
2670     return(CC_NORM);		/* don't even need to Refresh() */
2671 }
2672 
2673 /*ARGSUSED*/
2674 CCRETVAL
2675 e_charswitch(Char cc)
2676 {
2677     Char c;
2678 
2679     USE(cc);
2680 
2681     /* do nothing if we are at beginning of line or have only one char */
2682     if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2683 	return(CC_ERROR);
2684     }
2685 
2686     if (Cursor < LastChar) {
2687 	Cursor++;
2688     }
2689     c = Cursor[-2];
2690     Cursor[-2] = Cursor[-1];
2691     Cursor[-1] = c;
2692     return(CC_REFRESH);
2693 }
2694 
2695 /*ARGSUSED*/
2696 CCRETVAL
2697 e_gcharswitch(Char cc)
2698 {				/* gosmacs style ^T */
2699     Char c;
2700 
2701     USE(cc);
2702     if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2703 	c = Cursor[-2];
2704 	Cursor[-2] = Cursor[-1];
2705 	Cursor[-1] = c;
2706 	return(CC_REFRESH);
2707     }
2708     else {
2709 	return(CC_ERROR);
2710     }
2711 }
2712 
2713 /*ARGSUSED*/
2714 CCRETVAL
2715 e_charback(Char c)
2716 {
2717     USE(c);
2718     if (Cursor > InputBuf) {
2719 	if (Argument > Cursor - InputBuf)
2720 	    Cursor = InputBuf;
2721 	else
2722 	    Cursor -= Argument;
2723 
2724 	if (VImode)
2725 	    if (ActionFlag & TCSHOP_DELETE) {
2726 		c_delfini();
2727 		return(CC_REFRESH);
2728 	    }
2729 
2730 	RefCursor();
2731 	return(CC_NORM);
2732     }
2733     else {
2734 	return(CC_ERROR);
2735     }
2736 }
2737 
2738 /*ARGSUSED*/
2739 CCRETVAL
2740 v_wordback(Char c)
2741 {
2742     USE(c);
2743     if (Cursor == InputBuf)
2744 	return(CC_ERROR);
2745     /* else */
2746 
2747     Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2748 
2749     if (ActionFlag & TCSHOP_DELETE) {
2750 	c_delfini();
2751 	return(CC_REFRESH);
2752     }
2753 
2754     RefCursor();
2755     return(CC_NORM);
2756 }
2757 
2758 /*ARGSUSED*/
2759 CCRETVAL
2760 e_wordback(Char c)
2761 {
2762     USE(c);
2763     if (Cursor == InputBuf)
2764 	return(CC_ERROR);
2765     /* else */
2766 
2767     Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2768 
2769     if (VImode)
2770 	if (ActionFlag & TCSHOP_DELETE) {
2771 	    c_delfini();
2772 	    return(CC_REFRESH);
2773 	}
2774 
2775     RefCursor();
2776     return(CC_NORM);
2777 }
2778 
2779 /*ARGSUSED*/
2780 CCRETVAL
2781 e_charfwd(Char c)
2782 {
2783     USE(c);
2784     if (Cursor < LastChar) {
2785 	Cursor += Argument;
2786 	if (Cursor > LastChar)
2787 	    Cursor = LastChar;
2788 
2789 	if (VImode)
2790 	    if (ActionFlag & TCSHOP_DELETE) {
2791 		c_delfini();
2792 		return(CC_REFRESH);
2793 	    }
2794 
2795 	RefCursor();
2796 	return(CC_NORM);
2797     }
2798     else {
2799 	return(CC_ERROR);
2800     }
2801 }
2802 
2803 /*ARGSUSED*/
2804 CCRETVAL
2805 e_wordfwd(Char c)
2806 {
2807     USE(c);
2808     if (Cursor == LastChar)
2809 	return(CC_ERROR);
2810     /* else */
2811 
2812     Cursor = c_next_word(Cursor, LastChar, Argument);
2813 
2814     if (VImode)
2815 	if (ActionFlag & TCSHOP_DELETE) {
2816 	    c_delfini();
2817 	    return(CC_REFRESH);
2818 	}
2819 
2820     RefCursor();
2821     return(CC_NORM);
2822 }
2823 
2824 /*ARGSUSED*/
2825 CCRETVAL
2826 v_wordfwd(Char c)
2827 {
2828     USE(c);
2829     if (Cursor == LastChar)
2830 	return(CC_ERROR);
2831     /* else */
2832 
2833     Cursor = c_nexword(Cursor, LastChar, Argument);
2834 
2835     if (VImode)
2836 	if (ActionFlag & TCSHOP_DELETE) {
2837 	    c_delfini();
2838 	    return(CC_REFRESH);
2839 	}
2840 
2841     RefCursor();
2842     return(CC_NORM);
2843 }
2844 
2845 /*ARGSUSED*/
2846 CCRETVAL
2847 v_wordbegnext(Char c)
2848 {
2849     USE(c);
2850     if (Cursor == LastChar)
2851 	return(CC_ERROR);
2852     /* else */
2853 
2854     Cursor = c_next_word(Cursor, LastChar, Argument);
2855     if (Cursor < LastChar)
2856 	Cursor++;
2857 
2858     if (VImode)
2859 	if (ActionFlag & TCSHOP_DELETE) {
2860 	    c_delfini();
2861 	    return(CC_REFRESH);
2862 	}
2863 
2864     RefCursor();
2865     return(CC_NORM);
2866 }
2867 
2868 /*ARGSUSED*/
2869 static CCRETVAL
2870 v_repeat_srch(int c)
2871 {
2872     CCRETVAL rv = CC_ERROR;
2873 #ifdef SDEBUG
2874     xprintf("dir %d patlen %d patbuf %S\n",
2875 	    c, (int)patbuf.len, patbuf.s);
2876 #endif
2877 
2878     LastCmd = (KEYCMD) c;  /* Hack to stop c_hsetpat */
2879     LastChar = InputBuf;
2880     switch (c) {
2881     case F_DOWN_SEARCH_HIST:
2882 	rv = e_down_search_hist(0);
2883 	break;
2884     case F_UP_SEARCH_HIST:
2885 	rv = e_up_search_hist(0);
2886 	break;
2887     default:
2888 	break;
2889     }
2890     return rv;
2891 }
2892 
2893 static CCRETVAL
2894 v_csearch_back(Char ch, int count, int tflag)
2895 {
2896     Char *cp;
2897 
2898     cp = Cursor;
2899     while (count--) {
2900 	if (*cp == ch)
2901 	    cp--;
2902 	while (cp > InputBuf && *cp != ch)
2903 	    cp--;
2904     }
2905 
2906     if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2907 	return(CC_ERROR);
2908 
2909     if (*cp == ch && tflag)
2910 	cp++;
2911 
2912     Cursor = cp;
2913 
2914     if (ActionFlag & TCSHOP_DELETE) {
2915 	Cursor++;
2916 	c_delfini();
2917 	return(CC_REFRESH);
2918     }
2919 
2920     RefCursor();
2921     return(CC_NORM);
2922 }
2923 
2924 static CCRETVAL
2925 v_csearch_fwd(Char ch, int count, int tflag)
2926 {
2927     Char *cp;
2928 
2929     cp = Cursor;
2930     while (count--) {
2931 	if(*cp == ch)
2932 	    cp++;
2933 	while (cp < LastChar && *cp != ch)
2934 	    cp++;
2935     }
2936 
2937     if (cp >= LastChar)
2938 	return(CC_ERROR);
2939 
2940     if (*cp == ch && tflag)
2941 	cp--;
2942 
2943     Cursor = cp;
2944 
2945     if (ActionFlag & TCSHOP_DELETE) {
2946 	Cursor++;
2947 	c_delfini();
2948 	return(CC_REFRESH);
2949     }
2950     RefCursor();
2951     return(CC_NORM);
2952 }
2953 
2954 /*ARGSUSED*/
2955 static CCRETVAL
2956 v_action(int c)
2957 {
2958     Char *cp, *kp;
2959 
2960     if (ActionFlag == TCSHOP_DELETE) {
2961 	ActionFlag = TCSHOP_NOP;
2962 	ActionPos = 0;
2963 
2964 	UndoSize = 0;
2965 	kp = UndoBuf;
2966 	for (cp = InputBuf; cp < LastChar; cp++) {
2967 	    *kp++ = *cp;
2968 	    UndoSize++;
2969 	}
2970 
2971 	UndoAction = TCSHOP_INSERT;
2972 	UndoPtr  = InputBuf;
2973 	LastChar = InputBuf;
2974 	Cursor   = InputBuf;
2975 	if (c & TCSHOP_INSERT)
2976 	    c_alternativ_key_map(0);
2977 
2978 	return(CC_REFRESH);
2979     }
2980 #ifdef notdef
2981     else if (ActionFlag == TCSHOP_NOP) {
2982 #endif
2983 	ActionPos = Cursor;
2984 	ActionFlag = c;
2985 	return(CC_ARGHACK);  /* Do NOT clear out argument */
2986 #ifdef notdef
2987     }
2988     else {
2989 	ActionFlag = 0;
2990 	ActionPos = 0;
2991 	return(CC_ERROR);
2992     }
2993 #endif
2994 }
2995 
2996 #ifdef COMMENT
2997 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2998 static void
2999 c_get_word(Char **begin, Char **end)
3000 {
3001     Char   *cp;
3002 
3003     cp = &Cursor[0];
3004     while (Argument--) {
3005 	while ((cp <= LastChar) && (isword(*cp)))
3006 	    cp++;
3007 	*end = --cp;
3008 	while ((cp >= InputBuf) && (isword(*cp)))
3009 	    cp--;
3010 	*begin = ++cp;
3011     }
3012 }
3013 #endif /* COMMENT */
3014 
3015 /*ARGSUSED*/
3016 CCRETVAL
3017 e_uppercase(Char c)
3018 {
3019     Char   *cp, *end;
3020 
3021     USE(c);
3022     end = c_next_word(Cursor, LastChar, Argument);
3023 
3024     for (cp = Cursor; cp < end; cp++)	/* PWP: was cp=begin */
3025 	if (Islower(*cp))
3026 	    *cp = Toupper(*cp);
3027 
3028     Cursor = end;
3029     if (Cursor > LastChar)
3030 	Cursor = LastChar;
3031     return(CC_REFRESH);
3032 }
3033 
3034 
3035 /*ARGSUSED*/
3036 CCRETVAL
3037 e_capitalcase(Char c)
3038 {
3039     Char   *cp, *end;
3040 
3041     USE(c);
3042     end = c_next_word(Cursor, LastChar, Argument);
3043 
3044     cp = Cursor;
3045     for (; cp < end; cp++) {
3046 	if (Isalpha(*cp)) {
3047 	    if (Islower(*cp))
3048 		*cp = Toupper(*cp);
3049 	    cp++;
3050 	    break;
3051 	}
3052     }
3053     for (; cp < end; cp++)
3054 	if (Isupper(*cp))
3055 	    *cp = Tolower(*cp);
3056 
3057     Cursor = end;
3058     if (Cursor > LastChar)
3059 	Cursor = LastChar;
3060     return(CC_REFRESH);
3061 }
3062 
3063 /*ARGSUSED*/
3064 CCRETVAL
3065 e_lowercase(Char c)
3066 {
3067     Char   *cp, *end;
3068 
3069     USE(c);
3070     end = c_next_word(Cursor, LastChar, Argument);
3071 
3072     for (cp = Cursor; cp < end; cp++)
3073 	if (Isupper(*cp))
3074 	    *cp = Tolower(*cp);
3075 
3076     Cursor = end;
3077     if (Cursor > LastChar)
3078 	Cursor = LastChar;
3079     return(CC_REFRESH);
3080 }
3081 
3082 
3083 /*ARGSUSED*/
3084 CCRETVAL
3085 e_set_mark(Char c)
3086 {
3087     USE(c);
3088     if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3089 	ClearLines();
3090 	ClearDisp();
3091 	Refresh();
3092     }
3093     Mark = Cursor;
3094     MarkIsSet = 1;
3095     return(CC_NORM);
3096 }
3097 
3098 /*ARGSUSED*/
3099 CCRETVAL
3100 e_exchange_mark(Char c)
3101 {
3102     Char *cp;
3103 
3104     USE(c);
3105     cp = Cursor;
3106     Cursor = Mark;
3107     Mark = cp;
3108     RefCursor();
3109     return(CC_NORM);
3110 }
3111 
3112 /*ARGSUSED*/
3113 CCRETVAL
3114 e_argfour(Char c)
3115 {				/* multiply current argument by 4 */
3116     USE(c);
3117     if (Argument > 1000000)
3118 	return CC_ERROR;
3119     DoingArg = 1;
3120     Argument *= 4;
3121     return(CC_ARGHACK);
3122 }
3123 
3124 static void
3125 quote_mode_cleanup(void *unused)
3126 {
3127     USE(unused);
3128     QuoteModeOff();
3129 }
3130 
3131 /*ARGSUSED*/
3132 CCRETVAL
3133 e_quote(Char c)
3134 {
3135     Char    ch;
3136     int     num;
3137 
3138     USE(c);
3139     QuoteModeOn();
3140     cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3141     num = GetNextChar(&ch);
3142     cleanup_until(&c);
3143     if (num == 1)
3144 	return e_insert(ch);
3145     else
3146 	return e_send_eof(0);
3147 }
3148 
3149 /*ARGSUSED*/
3150 CCRETVAL
3151 e_metanext(Char c)
3152 {
3153     USE(c);
3154     MetaNext = 1;
3155     return(CC_ARGHACK);	/* preserve argument */
3156 }
3157 
3158 #ifdef notdef
3159 /*ARGSUSED*/
3160 CCRETVAL
3161 e_extendnext(Char c)
3162 {
3163     CurrentKeyMap = CcAltMap;
3164     return(CC_ARGHACK);	/* preserve argument */
3165 }
3166 
3167 #endif
3168 
3169 /*ARGSUSED*/
3170 CCRETVAL
3171 v_insbeg(Char c)
3172 {				/* move to beginning of line and start vi
3173 				 * insert mode */
3174     USE(c);
3175     Cursor = InputBuf;
3176     InsertPos = Cursor;
3177 
3178     UndoPtr  = Cursor;
3179     UndoAction = TCSHOP_DELETE;
3180 
3181     RefCursor();		/* move the cursor */
3182     c_alternativ_key_map(0);
3183     return(CC_NORM);
3184 }
3185 
3186 /*ARGSUSED*/
3187 CCRETVAL
3188 v_replone(Char c)
3189 {				/* vi mode overwrite one character */
3190     USE(c);
3191     c_alternativ_key_map(0);
3192     inputmode = MODE_REPLACE_1;
3193     UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
3194     UndoPtr = Cursor;
3195     UndoSize = 0;
3196     return(CC_NORM);
3197 }
3198 
3199 /*ARGSUSED*/
3200 CCRETVAL
3201 v_replmode(Char c)
3202 {				/* vi mode start overwriting */
3203     USE(c);
3204     c_alternativ_key_map(0);
3205     inputmode = MODE_REPLACE;
3206     UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
3207     UndoPtr = Cursor;
3208     UndoSize = 0;
3209     return(CC_NORM);
3210 }
3211 
3212 /*ARGSUSED*/
3213 CCRETVAL
3214 v_substchar(Char c)
3215 {				/* vi mode substitute for one char */
3216     USE(c);
3217     c_delafter(Argument);
3218     c_alternativ_key_map(0);
3219     return(CC_REFRESH);
3220 }
3221 
3222 /*ARGSUSED*/
3223 CCRETVAL
3224 v_substline(Char c)
3225 {				/* vi mode replace whole line */
3226     USE(c);
3227     (void) e_killall(0);
3228     c_alternativ_key_map(0);
3229     return(CC_REFRESH);
3230 }
3231 
3232 /*ARGSUSED*/
3233 CCRETVAL
3234 v_chgtoend(Char c)
3235 {				/* vi mode change to end of line */
3236     USE(c);
3237     (void) e_killend(0);
3238     c_alternativ_key_map(0);
3239     return(CC_REFRESH);
3240 }
3241 
3242 /*ARGSUSED*/
3243 CCRETVAL
3244 v_insert(Char c)
3245 {				/* vi mode start inserting */
3246     USE(c);
3247     c_alternativ_key_map(0);
3248 
3249     InsertPos = Cursor;
3250     UndoPtr = Cursor;
3251     UndoAction = TCSHOP_DELETE;
3252 
3253     return(CC_NORM);
3254 }
3255 
3256 /*ARGSUSED*/
3257 CCRETVAL
3258 v_add(Char c)
3259 {				/* vi mode start adding */
3260     USE(c);
3261     c_alternativ_key_map(0);
3262     if (Cursor < LastChar)
3263     {
3264 	Cursor++;
3265 	if (Cursor > LastChar)
3266 	    Cursor = LastChar;
3267 	RefCursor();
3268     }
3269 
3270     InsertPos = Cursor;
3271     UndoPtr = Cursor;
3272     UndoAction = TCSHOP_DELETE;
3273 
3274     return(CC_NORM);
3275 }
3276 
3277 /*ARGSUSED*/
3278 CCRETVAL
3279 v_addend(Char c)
3280 {				/* vi mode to add at end of line */
3281     USE(c);
3282     c_alternativ_key_map(0);
3283     Cursor = LastChar;
3284 
3285     InsertPos = LastChar;	/* Mark where insertion begins */
3286     UndoPtr = LastChar;
3287     UndoAction = TCSHOP_DELETE;
3288 
3289     RefCursor();
3290     return(CC_NORM);
3291 }
3292 
3293 /*ARGSUSED*/
3294 CCRETVAL
3295 v_change_case(Char cc)
3296 {
3297     Char    c;
3298 
3299     USE(cc);
3300     if (Cursor < LastChar) {
3301 #ifndef WINNT_NATIVE
3302 	c = *Cursor;
3303 #else
3304 	c = CHAR & *Cursor;
3305 #endif /* WINNT_NATIVE */
3306 	if (Isupper(c))
3307 	    *Cursor++ = Tolower(c);
3308 	else if (Islower(c))
3309 	    *Cursor++ = Toupper(c);
3310 	else
3311 	    Cursor++;
3312 	RefPlusOne(1);		/* fast refresh for one char */
3313 	return(CC_NORM);
3314     }
3315     return(CC_ERROR);
3316 }
3317 
3318 /*ARGSUSED*/
3319 CCRETVAL
3320 e_expand(Char c)
3321 {
3322     Char *p;
3323 
3324     USE(c);
3325     for (p = InputBuf; Isspace(*p); p++)
3326 	continue;
3327     if (p == LastChar)
3328 	return(CC_ERROR);
3329 
3330     justpr++;
3331     Expand++;
3332     return(e_newline(0));
3333 }
3334 
3335 /*ARGSUSED*/
3336 CCRETVAL
3337 e_startover(Char c)
3338 {				/* erase all of current line, start again */
3339     USE(c);
3340     ResetInLine(0);		/* reset the input pointers */
3341     return(CC_REFRESH);
3342 }
3343 
3344 /*ARGSUSED*/
3345 CCRETVAL
3346 e_redisp(Char c)
3347 {
3348     USE(c);
3349     ClearLines();
3350     ClearDisp();
3351     return(CC_REFRESH);
3352 }
3353 
3354 /*ARGSUSED*/
3355 CCRETVAL
3356 e_cleardisp(Char c)
3357 {
3358     USE(c);
3359     ClearScreen();		/* clear the whole real screen */
3360     ClearDisp();		/* reset everything */
3361     return(CC_REFRESH);
3362 }
3363 
3364 /*ARGSUSED*/
3365 CCRETVAL
3366 e_tty_int(Char c)
3367 {
3368     USE(c);
3369 #if defined(_MINIX) || defined(WINNT_NATIVE)
3370     /* SAK PATCH: erase all of current line, start again */
3371     ResetInLine(0);		/* reset the input pointers */
3372     xputchar('\n');
3373     ClearDisp();
3374     return (CC_REFRESH);
3375 #else /* !_MINIX && !WINNT_NATIVE */
3376     /* do no editing */
3377     return (CC_NORM);
3378 #endif /* _MINIX || WINNT_NATIVE */
3379 }
3380 
3381 /*
3382  * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3383  * Function to send a character back to the input stream in cooked
3384  * mode. Only works if we have TIOCSTI
3385  */
3386 /*ARGSUSED*/
3387 CCRETVAL
3388 e_stuff_char(Char c)
3389 {
3390 #ifdef TIOCSTI
3391      int was_raw = Tty_raw_mode;
3392      char buf[MB_LEN_MAX];
3393      size_t i, len;
3394 
3395      if (was_raw)
3396          (void) Cookedmode();
3397 
3398      (void) xwrite(SHIN, "\n", 1);
3399      len = one_wctomb(buf, c);
3400      for (i = 0; i < len; i++)
3401 	 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3402 
3403      if (was_raw)
3404 	 (void) Rawmode();
3405      return(e_redisp(c));
3406 #else /* !TIOCSTI */
3407      return(CC_ERROR);
3408 #endif /* !TIOCSTI */
3409 }
3410 
3411 /*ARGSUSED*/
3412 CCRETVAL
3413 e_insovr(Char c)
3414 {
3415     USE(c);
3416     inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3417     return(CC_NORM);
3418 }
3419 
3420 /*ARGSUSED*/
3421 CCRETVAL
3422 e_tty_dsusp(Char c)
3423 {
3424     USE(c);
3425     /* do no editing */
3426     return(CC_NORM);
3427 }
3428 
3429 /*ARGSUSED*/
3430 CCRETVAL
3431 e_tty_flusho(Char c)
3432 {
3433     USE(c);
3434     /* do no editing */
3435     return(CC_NORM);
3436 }
3437 
3438 /*ARGSUSED*/
3439 CCRETVAL
3440 e_tty_quit(Char c)
3441 {
3442     USE(c);
3443     /* do no editing */
3444     return(CC_NORM);
3445 }
3446 
3447 /*ARGSUSED*/
3448 CCRETVAL
3449 e_tty_tsusp(Char c)
3450 {
3451     USE(c);
3452     /* do no editing */
3453     return(CC_NORM);
3454 }
3455 
3456 /*ARGSUSED*/
3457 CCRETVAL
3458 e_tty_stopo(Char c)
3459 {
3460     USE(c);
3461     /* do no editing */
3462     return(CC_NORM);
3463 }
3464 
3465 /* returns the number of (attempted) expansions */
3466 int
3467 ExpandHistory(void)
3468 {
3469     *LastChar = '\0';		/* just in case */
3470     return c_substitute();
3471 }
3472 
3473 /*ARGSUSED*/
3474 CCRETVAL
3475 e_expand_history(Char c)
3476 {
3477     USE(c);
3478     (void)ExpandHistory();
3479     return(CC_NORM);
3480 }
3481 
3482 /*ARGSUSED*/
3483 CCRETVAL
3484 e_magic_space(Char c)
3485 {
3486     USE(c);
3487     *LastChar = '\0';		/* just in case */
3488     (void)c_substitute();
3489     return(e_insert(' '));
3490 }
3491 
3492 /*ARGSUSED*/
3493 CCRETVAL
3494 e_inc_fwd(Char c)
3495 {
3496     CCRETVAL ret;
3497 
3498     USE(c);
3499     patbuf.len = 0;
3500     MarkIsSet = 0;
3501     ret = e_inc_search(F_DOWN_SEARCH_HIST);
3502     if (adrof(STRhighlight) && IncMatchLen) {
3503 	IncMatchLen = 0;
3504 	ClearLines();
3505 	ClearDisp();
3506 	Refresh();
3507     }
3508     IncMatchLen = 0;
3509     return ret;
3510 }
3511 
3512 
3513 /*ARGSUSED*/
3514 CCRETVAL
3515 e_inc_back(Char c)
3516 {
3517     CCRETVAL ret;
3518 
3519     USE(c);
3520     patbuf.len = 0;
3521     MarkIsSet = 0;
3522     ret = e_inc_search(F_UP_SEARCH_HIST);
3523     if (adrof(STRhighlight) && IncMatchLen) {
3524 	IncMatchLen = 0;
3525 	ClearLines();
3526 	ClearDisp();
3527 	Refresh();
3528     }
3529     IncMatchLen = 0;
3530     return ret;
3531 }
3532 
3533 /*ARGSUSED*/
3534 CCRETVAL
3535 e_copyprev(Char c)
3536 {
3537     Char *cp, *oldc, *dp;
3538 
3539     USE(c);
3540     if (Cursor == InputBuf)
3541 	return(CC_ERROR);
3542     /* else */
3543 
3544     oldc = Cursor;
3545     /* does a bounds check */
3546     cp = c_prev_word(Cursor, InputBuf, Argument);
3547 
3548     c_insert((int)(oldc - cp));
3549     for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3550 	*dp++ = *cp;
3551 
3552     Cursor = dp;		/* put cursor at end */
3553 
3554     return(CC_REFRESH);
3555 }
3556 
3557 /*ARGSUSED*/
3558 CCRETVAL
3559 e_tty_starto(Char c)
3560 {
3561     USE(c);
3562     /* do no editing */
3563     return(CC_NORM);
3564 }
3565 
3566 /*ARGSUSED*/
3567 CCRETVAL
3568 e_load_average(Char c)
3569 {
3570     USE(c);
3571     PastBottom();
3572 #ifdef TIOCSTAT
3573     /*
3574      * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3575      * there even if they don't use it. (lukem@netbsd.org)
3576      */
3577     if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3578 #endif
3579 	xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3580     return(CC_REFRESH);
3581 }
3582 
3583 /*ARGSUSED*/
3584 CCRETVAL
3585 v_chgmeta(Char c)
3586 {
3587     USE(c);
3588     /*
3589      * Delete with insert == change: first we delete and then we leave in
3590      * insert mode.
3591      */
3592     return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3593 }
3594 
3595 /*ARGSUSED*/
3596 CCRETVAL
3597 v_delmeta(Char c)
3598 {
3599     USE(c);
3600     return(v_action(TCSHOP_DELETE));
3601 }
3602 
3603 
3604 /*ARGSUSED*/
3605 CCRETVAL
3606 v_endword(Char c)
3607 {
3608     USE(c);
3609     if (Cursor == LastChar)
3610 	return(CC_ERROR);
3611     /* else */
3612 
3613     Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3614 
3615     if (ActionFlag & TCSHOP_DELETE)
3616     {
3617 	Cursor++;
3618 	c_delfini();
3619 	return(CC_REFRESH);
3620     }
3621 
3622     RefCursor();
3623     return(CC_NORM);
3624 }
3625 
3626 /*ARGSUSED*/
3627 CCRETVAL
3628 v_eword(Char c)
3629 {
3630     USE(c);
3631     if (Cursor == LastChar)
3632 	return(CC_ERROR);
3633     /* else */
3634 
3635     Cursor = c_eword(Cursor, LastChar, Argument);
3636 
3637     if (ActionFlag & TCSHOP_DELETE) {
3638 	Cursor++;
3639 	c_delfini();
3640 	return(CC_REFRESH);
3641     }
3642 
3643     RefCursor();
3644     return(CC_NORM);
3645 }
3646 
3647 /*ARGSUSED*/
3648 CCRETVAL
3649 v_char_fwd(Char c)
3650 {
3651     Char ch;
3652 
3653     USE(c);
3654     if (GetNextChar(&ch) != 1)
3655 	return e_send_eof(0);
3656 
3657     srch_dir = CHAR_FWD;
3658     srch_char = ch;
3659 
3660     return v_csearch_fwd(ch, Argument, 0);
3661 
3662 }
3663 
3664 /*ARGSUSED*/
3665 CCRETVAL
3666 v_char_back(Char c)
3667 {
3668     Char ch;
3669 
3670     USE(c);
3671     if (GetNextChar(&ch) != 1)
3672 	return e_send_eof(0);
3673 
3674     srch_dir = CHAR_BACK;
3675     srch_char = ch;
3676 
3677     return v_csearch_back(ch, Argument, 0);
3678 }
3679 
3680 /*ARGSUSED*/
3681 CCRETVAL
3682 v_charto_fwd(Char c)
3683 {
3684     Char ch;
3685 
3686     USE(c);
3687     if (GetNextChar(&ch) != 1)
3688 	return e_send_eof(0);
3689 
3690     return v_csearch_fwd(ch, Argument, 1);
3691 
3692 }
3693 
3694 /*ARGSUSED*/
3695 CCRETVAL
3696 v_charto_back(Char c)
3697 {
3698     Char ch;
3699 
3700     USE(c);
3701     if (GetNextChar(&ch) != 1)
3702 	return e_send_eof(0);
3703 
3704     return v_csearch_back(ch, Argument, 1);
3705 }
3706 
3707 /*ARGSUSED*/
3708 CCRETVAL
3709 v_rchar_fwd(Char c)
3710 {
3711     USE(c);
3712     if (srch_char == 0)
3713 	return CC_ERROR;
3714 
3715     return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3716 			          v_csearch_back(srch_char, Argument, 0);
3717 }
3718 
3719 /*ARGSUSED*/
3720 CCRETVAL
3721 v_rchar_back(Char c)
3722 {
3723     USE(c);
3724     if (srch_char == 0)
3725 	return CC_ERROR;
3726 
3727     return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3728 			           v_csearch_back(srch_char, Argument, 0);
3729 }
3730 
3731 /*ARGSUSED*/
3732 CCRETVAL
3733 v_undo(Char c)
3734 {
3735     int  loop;
3736     Char *kp, *cp;
3737     Char temp;
3738     int	 size;
3739 
3740     USE(c);
3741     switch (UndoAction) {
3742     case TCSHOP_DELETE|TCSHOP_INSERT:
3743     case TCSHOP_DELETE:
3744 	if (UndoSize == 0) return(CC_NORM);
3745 	cp = UndoPtr;
3746 	kp = UndoBuf;
3747 	for (loop=0; loop < UndoSize; loop++)	/* copy the chars */
3748 	    *kp++ = *cp++;			/* into UndoBuf   */
3749 
3750 	for (cp = UndoPtr; cp <= LastChar; cp++)
3751 	    *cp = cp[UndoSize];
3752 
3753 	LastChar -= UndoSize;
3754 	Cursor   =  UndoPtr;
3755 
3756 	UndoAction = TCSHOP_INSERT;
3757 	break;
3758 
3759     case TCSHOP_INSERT:
3760 	if (UndoSize == 0) return(CC_NORM);
3761 	cp = UndoPtr;
3762 	Cursor = UndoPtr;
3763 	kp = UndoBuf;
3764 	c_insert(UndoSize);		/* open the space, */
3765 	for (loop = 0; loop < UndoSize; loop++)	/* copy the chars */
3766 	    *cp++ = *kp++;
3767 
3768 	UndoAction = TCSHOP_DELETE;
3769 	break;
3770 
3771     case TCSHOP_CHANGE:
3772 	if (UndoSize == 0) return(CC_NORM);
3773 	cp = UndoPtr;
3774 	Cursor = UndoPtr;
3775 	kp = UndoBuf;
3776 	size = (int)(Cursor-LastChar); /*  NOT NSL independant */
3777 	if (size < UndoSize)
3778 	    size = UndoSize;
3779 	for(loop = 0; loop < size; loop++) {
3780 	    temp = *kp;
3781 	    *kp++ = *cp;
3782 	    *cp++ = temp;
3783 	}
3784 	break;
3785 
3786     default:
3787 	return(CC_ERROR);
3788     }
3789 
3790     return(CC_REFRESH);
3791 }
3792 
3793 /*ARGSUSED*/
3794 CCRETVAL
3795 v_ush_meta(Char c)
3796 {
3797     USE(c);
3798     return v_search(F_UP_SEARCH_HIST);
3799 }
3800 
3801 /*ARGSUSED*/
3802 CCRETVAL
3803 v_dsh_meta(Char c)
3804 {
3805     USE(c);
3806     return v_search(F_DOWN_SEARCH_HIST);
3807 }
3808 
3809 /*ARGSUSED*/
3810 CCRETVAL
3811 v_rsrch_fwd(Char c)
3812 {
3813     USE(c);
3814     if (patbuf.len == 0) return(CC_ERROR);
3815     return(v_repeat_srch(searchdir));
3816 }
3817 
3818 /*ARGSUSED*/
3819 CCRETVAL
3820 v_rsrch_back(Char c)
3821 {
3822     USE(c);
3823     if (patbuf.len == 0) return(CC_ERROR);
3824     return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3825 			 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3826 }
3827 
3828 #ifndef WINNT_NATIVE
3829 /* Since ed.defns.h  is generated from ed.defns.c, these empty
3830    functions will keep the F_NUM_FNS consistent
3831  */
3832 CCRETVAL
3833 e_copy_to_clipboard(Char c)
3834 {
3835     USE(c);
3836     return CC_ERROR;
3837 }
3838 
3839 CCRETVAL
3840 e_paste_from_clipboard(Char c)
3841 {
3842     USE(c);
3843     return (CC_ERROR);
3844 }
3845 
3846 CCRETVAL
3847 e_dosify_next(Char c)
3848 {
3849     USE(c);
3850     return (CC_ERROR);
3851 }
3852 CCRETVAL
3853 e_dosify_prev(Char c)
3854 {
3855     USE(c);
3856     return (CC_ERROR);
3857 }
3858 CCRETVAL
3859 e_page_up(Char c)
3860 {
3861     USE(c);
3862     return (CC_ERROR);
3863 }
3864 CCRETVAL
3865 e_page_down(Char c)
3866 {
3867     USE(c);
3868     return (CC_ERROR);
3869 }
3870 #endif /* !WINNT_NATIVE */
3871 
3872 #ifdef notdef
3873 void
3874 MoveCursor(int n)		/* move cursor + right - left char */
3875 {
3876     Cursor = Cursor + n;
3877     if (Cursor < InputBuf)
3878 	Cursor = InputBuf;
3879     if (Cursor > LastChar)
3880 	Cursor = LastChar;
3881     return;
3882 }
3883 
3884 Char *
3885 GetCursor(void)
3886 {
3887     return(Cursor);
3888 }
3889 
3890 int
3891 PutCursor(Char *p)
3892 {
3893     if (p < InputBuf || p > LastChar)
3894 	return 1;		/* Error */
3895     Cursor = p;
3896     return 0;
3897 }
3898 #endif
3899