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