xref: /freebsd/contrib/tcsh/ed.chared.c (revision 514fb3872166a361faa81d89909f65913e90b1b2)
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 occured if spaces were present in a string withing quotation
48   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 *, 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, 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 *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 	    if (inquote || p[-1] != (Char)'\\') { /* Should it be honored? */
805 	      if (inquote == 0) inquote = *p;
806 	      else if (inquote == *p) inquote = 0;
807 	    }
808 	  }
809 	  /* Break if unquoted non-word char */
810 	  if (!inquote && Strchr(delim, *p) && p[-1] != (Char)'\\')
811 	    break;
812 	  p++;
813 	}
814     }
815 
816     p--;
817     return(p);
818 }
819 
820 
821 static Char *
822 c_eword(Char *p, Char *high, int n)
823 {
824     p++;
825 
826     while (n--) {
827         int  c_class;
828 
829         if (p >= high)
830             break;
831 
832         /* scan until end of current word (may be all whitespace!) */
833         c_class = c_to_class(*p);
834         while ((p < high) && c_class == c_to_class(*p))
835             p++;
836 
837         /* if this was a non_whitespace word, we're ready */
838         if (c_class != C_CLASS_WHITE)
839             continue;
840 
841         /* otherwise, move to the end of the word just found */
842         c_class = c_to_class(*p);
843         while ((p < high) && c_class == c_to_class(*p))
844             p++;
845     }
846 
847     p--;
848     return(p);
849 }
850 
851 /* Set the max length of the kill ring */
852 void
853 SetKillRing(int max)
854 {
855     CStr *new;
856     int count, i, j;
857 
858     if (max < 1)
859 	max = 1;		/* no ring, but always one buffer */
860     if (max == KillRingMax)
861 	return;
862     new = xcalloc(max, sizeof(CStr));
863     if (KillRing != NULL) {
864 	if (KillRingLen != 0) {
865 	    if (max >= KillRingLen) {
866 		count = KillRingLen;
867 		j = KillPos;
868 	    } else {
869 		count = max;
870 		j = (KillPos - count + KillRingLen) % KillRingLen;
871 	    }
872 	    for (i = 0; i < KillRingLen; i++) {
873 		if (i < count)	/* copy latest */
874 		    new[i] = KillRing[j];
875 		else		/* free the others */
876 		    xfree(KillRing[j].buf);
877 		j = (j + 1) % KillRingLen;
878 	    }
879 	    KillRingLen = count;
880 	    KillPos = count % max;
881 	    YankPos = count - 1;
882 	}
883 	xfree(KillRing);
884     }
885     KillRing = new;
886     KillRingMax = max;
887 }
888 
889 /* Push string from start upto (but not including) end onto kill ring */
890 static void
891 c_push_kill(Char *start, Char *end)
892 {
893     CStr save, *pos;
894     Char *dp, *cp, *kp;
895     int len = end - start, i, j, k;
896 
897     /* Check for duplicates? */
898     if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
899 	YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
900 	if (eq(dp, STRerase)) {	/* erase earlier one (actually move up) */
901 	    j = YankPos;
902 	    for (i = 0; i < KillRingLen; i++) {
903 		if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
904 		    KillRing[j].buf[len] == '\0') {
905 		    save = KillRing[j];
906 		    for ( ; i > 0; i--) {
907 			k = j;
908 			j = (j + 1) % KillRingLen;
909 			KillRing[k] = KillRing[j];
910 		    }
911 		    KillRing[j] = save;
912 		    return;
913 		}
914 		j = (j - 1 + KillRingLen) % KillRingLen;
915 	    }
916 	} else if (eq(dp, STRall)) { /* skip if any earlier */
917 	    for (i = 0; i < KillRingLen; i++)
918 		if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
919 		    KillRing[i].buf[len] == '\0')
920 		    return;
921 	} else if (eq(dp, STRprev)) { /* skip if immediately previous */
922 	    j = YankPos;
923 	    if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
924 		KillRing[j].buf[len] == '\0')
925 		return;
926 	}
927     }
928 
929     /* No duplicate, go ahead and push */
930     len++;			/* need space for '\0' */
931     YankPos = KillPos;
932     if (KillRingLen < KillRingMax)
933 	KillRingLen++;
934     pos = &KillRing[KillPos];
935     KillPos = (KillPos + 1) % KillRingMax;
936     if (pos->len < len) {
937 	pos->buf = xrealloc(pos->buf, len * sizeof(Char));
938 	pos->len = len;
939     }
940     cp = start;
941     kp = pos->buf;
942     while (cp < end)
943 	*kp++ = *cp++;
944     *kp = '\0';
945 }
946 
947 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
948 static void
949 c_save_inputbuf(void)
950 {
951     SavedBuf.len = 0;
952     Strbuf_append(&SavedBuf, InputBuf);
953     Strbuf_terminate(&SavedBuf);
954     LastSaved = LastChar - InputBuf;
955     CursSaved = Cursor - InputBuf;
956     HistSaved = Hist_num;
957     RestoreSaved = 1;
958 }
959 
960 CCRETVAL
961 GetHistLine(void)
962 {
963     struct Hist *hp;
964     int     h;
965 
966     if (Hist_num == 0) {	/* if really the current line */
967 	if (HistBuf.s != NULL)
968 	    copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
969 	else
970 	    *InputBuf = '\0';
971 	LastChar = InputBuf + HistBuf.len;
972 
973 #ifdef KSHVI
974     if (VImode)
975 	Cursor = InputBuf;
976     else
977 #endif /* KSHVI */
978 	Cursor = LastChar;
979 
980 	return(CC_REFRESH);
981     }
982 
983     hp = Histlist.Hnext;
984     if (hp == NULL)
985 	return(CC_ERROR);
986 
987     for (h = 1; h < Hist_num; h++) {
988 	if ((hp->Hnext) == NULL) {
989 	    Hist_num = h;
990 	    return(CC_ERROR);
991 	}
992 	hp = hp->Hnext;
993     }
994 
995     if (HistLit && hp->histline) {
996 	copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
997 	CurrentHistLit = 1;
998     }
999     else {
1000 	Char *p;
1001 
1002 	p = sprlex(&hp->Hlex);
1003 	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1004 	xfree(p);
1005 	CurrentHistLit = 0;
1006     }
1007     LastChar = Strend(InputBuf);
1008 
1009     if (LastChar > InputBuf) {
1010 	if (LastChar[-1] == '\n')
1011 	    LastChar--;
1012 #if 0
1013 	if (LastChar[-1] == ' ')
1014 	    LastChar--;
1015 #endif
1016 	if (LastChar < InputBuf)
1017 	    LastChar = InputBuf;
1018     }
1019 
1020 #ifdef KSHVI
1021     if (VImode)
1022 	Cursor = InputBuf;
1023     else
1024 #endif /* KSHVI */
1025 	Cursor = LastChar;
1026 
1027     return(CC_REFRESH);
1028 }
1029 
1030 static CCRETVAL
1031 c_search_line(Char *pattern, int dir)
1032 {
1033     Char *cp;
1034     size_t len;
1035 
1036     len = Strlen(pattern);
1037 
1038     if (dir == F_UP_SEARCH_HIST) {
1039 	for (cp = Cursor; cp >= InputBuf; cp--)
1040 	    if (Strncmp(cp, pattern, len) == 0 ||
1041 		Gmatch(cp, pattern)) {
1042 		Cursor = cp;
1043 		return(CC_NORM);
1044 	    }
1045 	return(CC_ERROR);
1046     } else {
1047 	for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1048 	    if (Strncmp(cp, pattern, len) == 0 ||
1049 		Gmatch(cp, pattern)) {
1050 		Cursor = cp;
1051 		return(CC_NORM);
1052 	    }
1053 	return(CC_ERROR);
1054     }
1055 }
1056 
1057 static CCRETVAL
1058 e_inc_search(int dir)
1059 {
1060     static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1061 		      STRbck[] = { 'b', 'c', 'k', '\0' };
1062     static Char pchar = ':';	/* ':' = normal, '?' = failed */
1063     static Char endcmd[2];
1064     const Char *cp;
1065     Char ch,
1066 	*oldCursor = Cursor,
1067 	oldpchar = pchar;
1068     CCRETVAL ret = CC_NORM;
1069     int oldHist_num = Hist_num,
1070 	oldpatlen = patbuf.len,
1071 	newdir = dir,
1072         done, redo;
1073 
1074     if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1075 	return(CC_ERROR);
1076 
1077     for (;;) {
1078 
1079 	if (patbuf.len == 0) {	/* first round */
1080 	    pchar = ':';
1081 	    Strbuf_append1(&patbuf, '*');
1082 	}
1083 	done = redo = 0;
1084 	*LastChar++ = '\n';
1085 	for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1086 	     *cp; *LastChar++ = *cp++)
1087 	    continue;
1088 	*LastChar++ = pchar;
1089 	for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1090 	     *LastChar++ = *cp++)
1091 	    continue;
1092 	*LastChar = '\0';
1093 	if (adrof(STRhighlight) && pchar == ':') {
1094 	    /* if the no-glob-search patch is applied, remove the - 1 below */
1095 	    IncMatchLen = patbuf.len - 1;
1096 	    ClearLines();
1097 	    ClearDisp();
1098 	}
1099 	Refresh();
1100 
1101 	if (GetNextChar(&ch) != 1)
1102 	    return(e_send_eof(0));
1103 
1104 	switch (GetCmdChar(ch)) {
1105 	case F_INSERT:
1106 	case F_DIGIT:
1107 	case F_MAGIC_SPACE:
1108 	    if (LastChar + 1 >= InputLim) /*FIXBUF*/
1109 		SoundBeep();
1110 	    else {
1111 		Strbuf_append1(&patbuf, ch);
1112 		*LastChar++ = ch;
1113 		*LastChar = '\0';
1114 		Refresh();
1115 	    }
1116 	    break;
1117 
1118 	case F_INC_FWD:
1119 	    newdir = F_DOWN_SEARCH_HIST;
1120 	    redo++;
1121 	    break;
1122 
1123 	case F_INC_BACK:
1124 	    newdir = F_UP_SEARCH_HIST;
1125 	    redo++;
1126 	    break;
1127 
1128 	case F_DELPREV:
1129 	    if (patbuf.len > 1)
1130 		done++;
1131 	    else
1132 		SoundBeep();
1133 	    break;
1134 
1135 	default:
1136 	    switch (ASC(ch)) {
1137 	    case 0007:		/* ^G: Abort */
1138 		ret = CC_ERROR;
1139 		done++;
1140 		break;
1141 
1142 	    case 0027:		/* ^W: Append word */
1143 		/* No can do if globbing characters in pattern */
1144 		for (cp = &patbuf.s[1]; ; cp++)
1145 		    if (cp >= &patbuf.s[patbuf.len]) {
1146 			Cursor += patbuf.len - 1;
1147 			cp = c_next_word(Cursor, LastChar, 1);
1148 			while (Cursor < cp && *Cursor != '\n') {
1149 			    if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1150 				SoundBeep();
1151 				break;
1152 			    }
1153 			    Strbuf_append1(&patbuf, *Cursor);
1154 			    *LastChar++ = *Cursor++;
1155 			}
1156 			Cursor = oldCursor;
1157 			*LastChar = '\0';
1158 			Refresh();
1159 			break;
1160 		    } else if (isglob(*cp)) {
1161 			SoundBeep();
1162 			break;
1163 		    }
1164 		break;
1165 
1166 	    default:		/* Terminate and execute cmd */
1167 		endcmd[0] = ch;
1168 		PushMacro(endcmd);
1169 		/*FALLTHROUGH*/
1170 
1171 	    case 0033:		/* ESC: Terminate */
1172 		ret = CC_REFRESH;
1173 		done++;
1174 		break;
1175 	    }
1176 	    break;
1177 	}
1178 
1179 	while (LastChar > InputBuf && *LastChar != '\n')
1180 	    *LastChar-- = '\0';
1181 	*LastChar = '\0';
1182 
1183 	if (!done) {
1184 
1185 	    /* Can't search if unmatched '[' */
1186 	    for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1187 		if (*cp == '[' || *cp == ']') {
1188 		    ch = *cp;
1189 		    break;
1190 		}
1191 
1192 	    if (patbuf.len > 1 && ch != '[') {
1193 		if (redo && newdir == dir) {
1194 		    if (pchar == '?') {	/* wrap around */
1195 			Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1196 			if (GetHistLine() == CC_ERROR)
1197 			    /* Hist_num was fixed by first call */
1198 			    (void) GetHistLine();
1199 			Cursor = newdir == F_UP_SEARCH_HIST ?
1200 			    LastChar : InputBuf;
1201 		    } else
1202 			Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1203 		}
1204 		Strbuf_append1(&patbuf, '*');
1205 		Strbuf_terminate(&patbuf);
1206 		if (Cursor < InputBuf || Cursor > LastChar ||
1207 		    (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1208 		    LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1209 		    ret = newdir == F_UP_SEARCH_HIST ?
1210 			e_up_search_hist(0) : e_down_search_hist(0);
1211 		    if (ret != CC_ERROR) {
1212 			Cursor = newdir == F_UP_SEARCH_HIST ?
1213 			    LastChar : InputBuf;
1214 			(void) c_search_line(&patbuf.s[1], newdir);
1215 		    }
1216 		}
1217 		patbuf.s[--patbuf.len] = '\0';
1218 		if (ret == CC_ERROR) {
1219 		    SoundBeep();
1220 		    if (Hist_num != oldHist_num) {
1221 			Hist_num = oldHist_num;
1222 			if (GetHistLine() == CC_ERROR)
1223 			    return(CC_ERROR);
1224 		    }
1225 		    Cursor = oldCursor;
1226 		    pchar = '?';
1227 		} else {
1228 		    pchar = ':';
1229 		}
1230 	    }
1231 
1232 	    ret = e_inc_search(newdir);
1233 
1234 	    if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1235 		/* break abort of failed search at last non-failed */
1236 		ret = CC_NORM;
1237 	    }
1238 
1239 	}
1240 
1241 	if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1242 	    /* restore on normal return or error exit */
1243 	    pchar = oldpchar;
1244 	    patbuf.len = oldpatlen;
1245 	    if (Hist_num != oldHist_num) {
1246 		Hist_num = oldHist_num;
1247 		if (GetHistLine() == CC_ERROR)
1248 		    return(CC_ERROR);
1249 	    }
1250 	    Cursor = oldCursor;
1251 	    if (ret == CC_ERROR)
1252 		Refresh();
1253 	}
1254 	if (done || ret != CC_NORM)
1255 	    return(ret);
1256 
1257     }
1258 
1259 }
1260 
1261 static CCRETVAL
1262 v_search(int dir)
1263 {
1264     struct Strbuf tmpbuf = Strbuf_INIT;
1265     Char ch;
1266     Char *oldbuf;
1267     Char *oldlc, *oldc;
1268 
1269     cleanup_push(&tmpbuf, Strbuf_cleanup);
1270     oldbuf = Strsave(InputBuf);
1271     cleanup_push(oldbuf, xfree);
1272     oldlc = LastChar;
1273     oldc = Cursor;
1274     Strbuf_append1(&tmpbuf, '*');
1275 
1276     InputBuf[0] = '\0';
1277     LastChar = InputBuf;
1278     Cursor = InputBuf;
1279     searchdir = dir;
1280 
1281     c_insert(2);	/* prompt + '\n' */
1282     *Cursor++ = '\n';
1283     *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1284     Refresh();
1285     for (ch = 0;ch == 0;) {
1286 	if (GetNextChar(&ch) != 1) {
1287 	    cleanup_until(&tmpbuf);
1288 	    return(e_send_eof(0));
1289 	}
1290 	switch (ASC(ch)) {
1291 	case 0010:	/* Delete and backspace */
1292 	case 0177:
1293 	    if (tmpbuf.len > 1) {
1294 		*Cursor-- = '\0';
1295 		LastChar = Cursor;
1296 		tmpbuf.len--;
1297 	    }
1298 	    else {
1299 		copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1300 		LastChar = oldlc;
1301 		Cursor = oldc;
1302 		cleanup_until(&tmpbuf);
1303 		return(CC_REFRESH);
1304 	    }
1305 	    Refresh();
1306 	    ch = 0;
1307 	    break;
1308 
1309 	case 0033:	/* ESC */
1310 #ifdef IS_ASCII
1311 	case '\r':	/* Newline */
1312 	case '\n':
1313 #else
1314 	case '\012':    /* ASCII Line feed */
1315 	case '\015':    /* ASCII (or EBCDIC) Return */
1316 #endif
1317 	    break;
1318 
1319 	default:
1320 	    Strbuf_append1(&tmpbuf, ch);
1321 	    *Cursor++ = ch;
1322 	    LastChar = Cursor;
1323 	    Refresh();
1324 	    ch = 0;
1325 	    break;
1326 	}
1327     }
1328     cleanup_until(oldbuf);
1329 
1330     if (tmpbuf.len == 1) {
1331 	/*
1332 	 * Use the old pattern, but wild-card it.
1333 	 */
1334 	if (patbuf.len == 0) {
1335 	    InputBuf[0] = '\0';
1336 	    LastChar = InputBuf;
1337 	    Cursor = InputBuf;
1338 	    Refresh();
1339 	    cleanup_until(&tmpbuf);
1340 	    return(CC_ERROR);
1341 	}
1342 	if (patbuf.s[0] != '*') {
1343 	    oldbuf = Strsave(patbuf.s);
1344 	    patbuf.len = 0;
1345 	    Strbuf_append1(&patbuf, '*');
1346 	    Strbuf_append(&patbuf, oldbuf);
1347 	    xfree(oldbuf);
1348 	    Strbuf_append1(&patbuf, '*');
1349 	    Strbuf_terminate(&patbuf);
1350 	}
1351     }
1352     else {
1353 	Strbuf_append1(&tmpbuf, '*');
1354 	Strbuf_terminate(&tmpbuf);
1355 	patbuf.len = 0;
1356 	Strbuf_append(&patbuf, tmpbuf.s);
1357 	Strbuf_terminate(&patbuf);
1358     }
1359     cleanup_until(&tmpbuf);
1360     LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1361     Cursor = LastChar = InputBuf;
1362     if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1363 				   e_down_search_hist(0)) == CC_ERROR) {
1364 	Refresh();
1365 	return(CC_ERROR);
1366     }
1367     else {
1368 	if (ASC(ch) == 0033) {
1369 	    Refresh();
1370 	    *LastChar++ = '\n';
1371 	    *LastChar = '\0';
1372 	    PastBottom();
1373 	    return(CC_NEWLINE);
1374 	}
1375 	else
1376 	    return(CC_REFRESH);
1377     }
1378 }
1379 
1380 /*
1381  * semi-PUBLIC routines.  Any routine that is of type CCRETVAL is an
1382  * entry point, called from the CcKeyMap indirected into the
1383  * CcFuncTbl array.
1384  */
1385 
1386 /*ARGSUSED*/
1387 CCRETVAL
1388 v_cmd_mode(Char c)
1389 {
1390     USE(c);
1391     InsertPos = 0;
1392     ActionFlag = TCSHOP_NOP;	/* [Esc] cancels pending action */
1393     ActionPos = 0;
1394     DoingArg = 0;
1395     if (UndoPtr > Cursor)
1396 	UndoSize = (int)(UndoPtr - Cursor);
1397     else
1398 	UndoSize = (int)(Cursor - UndoPtr);
1399 
1400     inputmode = MODE_INSERT;
1401     c_alternativ_key_map(1);
1402 #ifdef notdef
1403     /*
1404      * We don't want to move the cursor, because all the editing
1405      * commands don't include the character under the cursor.
1406      */
1407     if (Cursor > InputBuf)
1408 	Cursor--;
1409 #endif
1410     RefCursor();
1411     return(CC_NORM);
1412 }
1413 
1414 /*ARGSUSED*/
1415 CCRETVAL
1416 e_unassigned(Char c)
1417 {				/* bound to keys that arn't really assigned */
1418     USE(c);
1419     SoundBeep();
1420     flush();
1421     return(CC_NORM);
1422 }
1423 
1424 #ifdef notyet
1425 static CCRETVAL
1426 e_insert_str(Char *c)
1427 {
1428     int i, n;
1429 
1430     n = Strlen(c);
1431     if (LastChar + Argument * n >= InputLim)
1432 	return(CC_ERROR);	/* end of buffer space */
1433     if (inputmode != MODE_INSERT) {
1434 	c_delafter(Argument * Strlen(c));
1435     }
1436     c_insert(Argument * n);
1437     while (Argument--) {
1438 	for (i = 0; i < n; i++)
1439 	    *Cursor++ = c[i];
1440     }
1441     Refresh();
1442     return(CC_NORM);
1443 }
1444 #endif
1445 
1446 CCRETVAL
1447 e_insert(Char c)
1448 {
1449 #ifndef SHORT_STRINGS
1450     c &= ASCII;			/* no meta chars ever */
1451 #endif
1452 
1453     if (!c)
1454 	return(CC_ERROR);	/* no NULs in the input ever!! */
1455 
1456     if (LastChar + Argument >= InputLim)
1457 	return(CC_ERROR);	/* end of buffer space */
1458 
1459     if (Argument == 1) {  	/* How was this optimized ???? */
1460 
1461 	if (inputmode != MODE_INSERT) {
1462 	    UndoBuf[UndoSize++] = *Cursor;
1463 	    UndoBuf[UndoSize] = '\0';
1464 	    c_delafter(1);   /* Do NOT use the saving ONE */
1465     	}
1466 
1467         c_insert(1);
1468 	*Cursor++ = (Char) c;
1469 	DoingArg = 0;		/* just in case */
1470 	RefPlusOne(1);		/* fast refresh for one char. */
1471     }
1472     else {
1473 	if (inputmode != MODE_INSERT) {
1474 	    int i;
1475 	    for (i = 0; i < Argument; i++)
1476 		UndoBuf[UndoSize++] = Cursor[i];
1477 
1478 	    UndoBuf[UndoSize] = '\0';
1479 	    c_delafter(Argument);   /* Do NOT use the saving ONE */
1480     	}
1481 
1482         c_insert(Argument);
1483 
1484 	while (Argument--)
1485 	    *Cursor++ = (Char) c;
1486 	Refresh();
1487     }
1488 
1489     if (inputmode == MODE_REPLACE_1)
1490 	(void) v_cmd_mode(0);
1491 
1492     return(CC_NORM);
1493 }
1494 
1495 int
1496 InsertStr(Char *s)		/* insert ASCIZ s at cursor (for complete) */
1497 {
1498     int len;
1499 
1500     if ((len = (int) Strlen(s)) <= 0)
1501 	return -1;
1502     if (LastChar + len >= InputLim)
1503 	return -1;		/* end of buffer space */
1504 
1505     c_insert(len);
1506     while (len--)
1507 	*Cursor++ = *s++;
1508     return 0;
1509 }
1510 
1511 void
1512 DeleteBack(int n)		/* delete the n characters before . */
1513 {
1514     if (n <= 0)
1515 	return;
1516     if (Cursor >= &InputBuf[n]) {
1517 	c_delbefore(n);		/* delete before dot */
1518     }
1519 }
1520 
1521 CCRETVAL
1522 e_digit(Char c)			/* gray magic here */
1523 {
1524     if (!Isdigit(c))
1525 	return(CC_ERROR);	/* no NULs in the input ever!! */
1526 
1527     if (DoingArg) {		/* if doing an arg, add this in... */
1528 	if (LastCmd == F_ARGFOUR)	/* if last command was ^U */
1529 	    Argument = c - '0';
1530 	else {
1531 	    if (Argument > 1000000)
1532 		return CC_ERROR;
1533 	    Argument = (Argument * 10) + (c - '0');
1534 	}
1535 	return(CC_ARGHACK);
1536     }
1537     else {
1538 	if (LastChar + 1 >= InputLim)
1539 	    return CC_ERROR;	/* end of buffer space */
1540 
1541 	if (inputmode != MODE_INSERT) {
1542 	    UndoBuf[UndoSize++] = *Cursor;
1543 	    UndoBuf[UndoSize] = '\0';
1544 	    c_delafter(1);   /* Do NOT use the saving ONE */
1545     	}
1546 	c_insert(1);
1547 	*Cursor++ = (Char) c;
1548 	DoingArg = 0;		/* just in case */
1549 	RefPlusOne(1);		/* fast refresh for one char. */
1550     }
1551     return(CC_NORM);
1552 }
1553 
1554 CCRETVAL
1555 e_argdigit(Char c)		/* for ESC-n */
1556 {
1557 #ifdef IS_ASCII
1558     c &= ASCII;
1559 #else
1560     c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1561 #endif
1562 
1563     if (!Isdigit(c))
1564 	return(CC_ERROR);	/* no NULs in the input ever!! */
1565 
1566     if (DoingArg) {		/* if doing an arg, add this in... */
1567 	if (Argument > 1000000)
1568 	    return CC_ERROR;
1569 	Argument = (Argument * 10) + (c - '0');
1570     }
1571     else {			/* else starting an argument */
1572 	Argument = c - '0';
1573 	DoingArg = 1;
1574     }
1575     return(CC_ARGHACK);
1576 }
1577 
1578 CCRETVAL
1579 v_zero(Char c)			/* command mode 0 for vi */
1580 {
1581     if (DoingArg) {		/* if doing an arg, add this in... */
1582 	if (Argument > 1000000)
1583 	    return CC_ERROR;
1584 	Argument = (Argument * 10) + (c - '0');
1585 	return(CC_ARGHACK);
1586     }
1587     else {			/* else starting an argument */
1588 	Cursor = InputBuf;
1589 	if (ActionFlag & TCSHOP_DELETE) {
1590 	   c_delfini();
1591 	   return(CC_REFRESH);
1592         }
1593 	RefCursor();		/* move the cursor */
1594 	return(CC_NORM);
1595     }
1596 }
1597 
1598 /*ARGSUSED*/
1599 CCRETVAL
1600 e_newline(Char c)
1601 {				/* always ignore argument */
1602     USE(c);
1603     if (adrof(STRhighlight) && MarkIsSet) {
1604 	MarkIsSet = 0;
1605 	ClearLines();
1606 	ClearDisp();
1607 	Refresh();
1608     }
1609     MarkIsSet = 0;
1610 
1611   /*  PastBottom();  NOW done in ed.inputl.c */
1612     *LastChar++ = '\n';		/* for the benefit of CSH */
1613     *LastChar = '\0';		/* just in case */
1614     if (VImode)
1615 	InsertPos = InputBuf;	/* Reset editing position */
1616     return(CC_NEWLINE);
1617 }
1618 
1619 /*ARGSUSED*/
1620 CCRETVAL
1621 e_newline_hold(Char c)
1622 {
1623     USE(c);
1624     c_save_inputbuf();
1625     HistSaved = 0;
1626     *LastChar++ = '\n';		/* for the benefit of CSH */
1627     *LastChar = '\0';		/* just in case */
1628     return(CC_NEWLINE);
1629 }
1630 
1631 /*ARGSUSED*/
1632 CCRETVAL
1633 e_newline_down_hist(Char c)
1634 {
1635     USE(c);
1636     if (Hist_num > 1) {
1637 	HistSaved = Hist_num;
1638     }
1639     *LastChar++ = '\n';		/* for the benefit of CSH */
1640     *LastChar = '\0';		/* just in case */
1641     return(CC_NEWLINE);
1642 }
1643 
1644 /*ARGSUSED*/
1645 CCRETVAL
1646 e_send_eof(Char c)
1647 {				/* for when ^D is ONLY send-eof */
1648     USE(c);
1649     PastBottom();
1650     *LastChar = '\0';		/* just in case */
1651     return(CC_EOF);
1652 }
1653 
1654 /*ARGSUSED*/
1655 CCRETVAL
1656 e_complete(Char c)
1657 {
1658     USE(c);
1659     *LastChar = '\0';		/* just in case */
1660     return(CC_COMPLETE);
1661 }
1662 
1663 /*ARGSUSED*/
1664 CCRETVAL
1665 e_complete_back(Char c)
1666 {
1667     USE(c);
1668     *LastChar = '\0';		/* just in case */
1669     return(CC_COMPLETE_BACK);
1670 }
1671 
1672 /*ARGSUSED*/
1673 CCRETVAL
1674 e_complete_fwd(Char c)
1675 {
1676     USE(c);
1677     *LastChar = '\0';		/* just in case */
1678     return(CC_COMPLETE_FWD);
1679 }
1680 
1681 /*ARGSUSED*/
1682 CCRETVAL
1683 e_complete_all(Char c)
1684 {
1685     USE(c);
1686     *LastChar = '\0';		/* just in case */
1687     return(CC_COMPLETE_ALL);
1688 }
1689 
1690 /*ARGSUSED*/
1691 CCRETVAL
1692 v_cm_complete(Char c)
1693 {
1694     USE(c);
1695     if (Cursor < LastChar)
1696 	Cursor++;
1697     *LastChar = '\0';		/* just in case */
1698     return(CC_COMPLETE);
1699 }
1700 
1701 /*ARGSUSED*/
1702 CCRETVAL
1703 e_toggle_hist(Char c)
1704 {
1705     struct Hist *hp;
1706     int     h;
1707 
1708     USE(c);
1709     *LastChar = '\0';		/* just in case */
1710 
1711     if (Hist_num <= 0) {
1712 	return CC_ERROR;
1713     }
1714 
1715     hp = Histlist.Hnext;
1716     if (hp == NULL) {	/* this is only if no history */
1717 	return(CC_ERROR);
1718     }
1719 
1720     for (h = 1; h < Hist_num; h++)
1721 	hp = hp->Hnext;
1722 
1723     if (!CurrentHistLit) {
1724 	if (hp->histline) {
1725 	    copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1726 	    CurrentHistLit = 1;
1727 	}
1728 	else {
1729 	    return CC_ERROR;
1730 	}
1731     }
1732     else {
1733 	Char *p;
1734 
1735 	p = sprlex(&hp->Hlex);
1736 	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1737 	xfree(p);
1738 	CurrentHistLit = 0;
1739     }
1740 
1741     LastChar = Strend(InputBuf);
1742     if (LastChar > InputBuf) {
1743 	if (LastChar[-1] == '\n')
1744 	    LastChar--;
1745 	if (LastChar[-1] == ' ')
1746 	    LastChar--;
1747 	if (LastChar < InputBuf)
1748 	    LastChar = InputBuf;
1749     }
1750 
1751 #ifdef KSHVI
1752     if (VImode)
1753 	Cursor = InputBuf;
1754     else
1755 #endif /* KSHVI */
1756 	Cursor = LastChar;
1757 
1758     return(CC_REFRESH);
1759 }
1760 
1761 /*ARGSUSED*/
1762 CCRETVAL
1763 e_up_hist(Char c)
1764 {
1765     Char    beep = 0;
1766 
1767     USE(c);
1768     UndoAction = TCSHOP_NOP;
1769     *LastChar = '\0';		/* just in case */
1770 
1771     if (Hist_num == 0) {	/* save the current buffer away */
1772 	HistBuf.len = 0;
1773 	Strbuf_append(&HistBuf, InputBuf);
1774 	Strbuf_terminate(&HistBuf);
1775     }
1776 
1777     Hist_num += Argument;
1778 
1779     if (GetHistLine() == CC_ERROR) {
1780 	beep = 1;
1781 	(void) GetHistLine(); /* Hist_num was fixed by first call */
1782     }
1783 
1784     Refresh();
1785     if (beep)
1786 	return(CC_ERROR);
1787     else
1788 	return(CC_NORM);	/* was CC_UP_HIST */
1789 }
1790 
1791 /*ARGSUSED*/
1792 CCRETVAL
1793 e_down_hist(Char c)
1794 {
1795     USE(c);
1796     UndoAction = TCSHOP_NOP;
1797     *LastChar = '\0';		/* just in case */
1798 
1799     Hist_num -= Argument;
1800 
1801     if (Hist_num < 0) {
1802 	Hist_num = 0;
1803 	return(CC_ERROR);	/* make it beep */
1804     }
1805 
1806     return(GetHistLine());
1807 }
1808 
1809 
1810 
1811 /*
1812  * c_hmatch() return True if the pattern matches the prefix
1813  */
1814 static int
1815 c_hmatch(Char *str)
1816 {
1817     if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1818 	return 1;
1819     return Gmatch(str, patbuf.s);
1820 }
1821 
1822 /*
1823  * c_hsetpat(): Set the history seatch pattern
1824  */
1825 static void
1826 c_hsetpat(void)
1827 {
1828     if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1829 	patbuf.len = 0;
1830 	Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1831 	Strbuf_terminate(&patbuf);
1832     }
1833 #ifdef SDEBUG
1834     xprintf("\nHist_num = %d\n", Hist_num);
1835     xprintf("patlen = %d\n", (int)patbuf.len);
1836     xprintf("patbuf = \"%S\"\n", patbuf.s);
1837     xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1838 #endif
1839 }
1840 
1841 /*ARGSUSED*/
1842 CCRETVAL
1843 e_up_search_hist(Char c)
1844 {
1845     struct Hist *hp;
1846     int h;
1847     int    found = 0;
1848 
1849     USE(c);
1850     ActionFlag = TCSHOP_NOP;
1851     UndoAction = TCSHOP_NOP;
1852     *LastChar = '\0';		/* just in case */
1853     if (Hist_num < 0) {
1854 #ifdef DEBUG_EDIT
1855 	xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1856 #endif
1857 	Hist_num = 0;
1858 	return(CC_ERROR);
1859     }
1860 
1861     if (Hist_num == 0) {
1862 	HistBuf.len = 0;
1863 	Strbuf_append(&HistBuf, InputBuf);
1864 	Strbuf_terminate(&HistBuf);
1865     }
1866 
1867 
1868     hp = Histlist.Hnext;
1869     if (hp == NULL)
1870 	return(CC_ERROR);
1871 
1872     c_hsetpat();		/* Set search pattern !! */
1873 
1874     for (h = 1; h <= Hist_num; h++)
1875 	hp = hp->Hnext;
1876 
1877     while (hp != NULL) {
1878 	Char *hl;
1879 	int matched;
1880 
1881 	if (hp->histline == NULL)
1882 	    hp->histline = sprlex(&hp->Hlex);
1883 	if (HistLit)
1884 	    hl = hp->histline;
1885 	else {
1886 	    hl = sprlex(&hp->Hlex);
1887 	    cleanup_push(hl, xfree);
1888 	}
1889 #ifdef SDEBUG
1890 	xprintf("Comparing with \"%S\"\n", hl);
1891 #endif
1892 	matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1893 		   hl[LastChar-InputBuf]) && c_hmatch(hl);
1894 	if (!HistLit)
1895 	    cleanup_until(hl);
1896 	if (matched) {
1897 	    found++;
1898 	    break;
1899 	}
1900 	h++;
1901 	hp = hp->Hnext;
1902     }
1903 
1904     if (!found) {
1905 #ifdef SDEBUG
1906 	xprintf("not found\n");
1907 #endif
1908 	return(CC_ERROR);
1909     }
1910 
1911     Hist_num = h;
1912 
1913     return(GetHistLine());
1914 }
1915 
1916 /*ARGSUSED*/
1917 CCRETVAL
1918 e_down_search_hist(Char c)
1919 {
1920     struct Hist *hp;
1921     int h;
1922     int    found = 0;
1923 
1924     USE(c);
1925     ActionFlag = TCSHOP_NOP;
1926     UndoAction = TCSHOP_NOP;
1927     *LastChar = '\0';		/* just in case */
1928 
1929     if (Hist_num == 0)
1930 	return(CC_ERROR);
1931 
1932     hp = Histlist.Hnext;
1933     if (hp == 0)
1934 	return(CC_ERROR);
1935 
1936     c_hsetpat();		/* Set search pattern !! */
1937 
1938     for (h = 1; h < Hist_num && hp; h++) {
1939 	Char *hl;
1940 	if (hp->histline == NULL)
1941 	    hp->histline = sprlex(&hp->Hlex);
1942 	if (HistLit)
1943 	    hl = hp->histline;
1944 	else {
1945 	    hl = sprlex(&hp->Hlex);
1946 	    cleanup_push(hl, xfree);
1947 	}
1948 #ifdef SDEBUG
1949 	xprintf("Comparing with \"%S\"\n", hl);
1950 #endif
1951 	if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1952 	     hl[LastChar-InputBuf]) && c_hmatch(hl))
1953 	    found = h;
1954 	if (!HistLit)
1955 	    cleanup_until(hl);
1956 	hp = hp->Hnext;
1957     }
1958 
1959     if (!found) {		/* is it the current history number? */
1960 	if (!c_hmatch(HistBuf.s)) {
1961 #ifdef SDEBUG
1962 	    xprintf("not found\n");
1963 #endif
1964 	    return(CC_ERROR);
1965 	}
1966     }
1967 
1968     Hist_num = found;
1969 
1970     return(GetHistLine());
1971 }
1972 
1973 /*ARGSUSED*/
1974 CCRETVAL
1975 e_helpme(Char c)
1976 {
1977     USE(c);
1978     PastBottom();
1979     *LastChar = '\0';		/* just in case */
1980     return(CC_HELPME);
1981 }
1982 
1983 /*ARGSUSED*/
1984 CCRETVAL
1985 e_correct(Char c)
1986 {
1987     USE(c);
1988     *LastChar = '\0';		/* just in case */
1989     return(CC_CORRECT);
1990 }
1991 
1992 /*ARGSUSED*/
1993 CCRETVAL
1994 e_correctl(Char c)
1995 {
1996     USE(c);
1997     *LastChar = '\0';		/* just in case */
1998     return(CC_CORRECT_L);
1999 }
2000 
2001 /*ARGSUSED*/
2002 CCRETVAL
2003 e_run_fg_editor(Char c)
2004 {
2005     struct process *pp;
2006 
2007     USE(c);
2008     if ((pp = find_stop_ed()) != NULL) {
2009 	/* save our editor state so we can restore it */
2010 	c_save_inputbuf();
2011 	Hist_num = 0;		/* for the history commands */
2012 
2013 	/* put the tty in a sane mode */
2014 	PastBottom();
2015 	(void) Cookedmode();	/* make sure the tty is set up correctly */
2016 
2017 	/* do it! */
2018 	fg_proc_entry(pp);
2019 
2020 	(void) Rawmode();	/* go on */
2021 	Refresh();
2022 	RestoreSaved = 0;
2023 	HistSaved = 0;
2024     }
2025     return(CC_NORM);
2026 }
2027 
2028 /*ARGSUSED*/
2029 CCRETVAL
2030 e_list_choices(Char c)
2031 {
2032     USE(c);
2033     PastBottom();
2034     *LastChar = '\0';		/* just in case */
2035     return(CC_LIST_CHOICES);
2036 }
2037 
2038 /*ARGSUSED*/
2039 CCRETVAL
2040 e_list_all(Char c)
2041 {
2042     USE(c);
2043     PastBottom();
2044     *LastChar = '\0';		/* just in case */
2045     return(CC_LIST_ALL);
2046 }
2047 
2048 /*ARGSUSED*/
2049 CCRETVAL
2050 e_list_glob(Char c)
2051 {
2052     USE(c);
2053     PastBottom();
2054     *LastChar = '\0';		/* just in case */
2055     return(CC_LIST_GLOB);
2056 }
2057 
2058 /*ARGSUSED*/
2059 CCRETVAL
2060 e_expand_glob(Char c)
2061 {
2062     USE(c);
2063     *LastChar = '\0';		/* just in case */
2064     return(CC_EXPAND_GLOB);
2065 }
2066 
2067 /*ARGSUSED*/
2068 CCRETVAL
2069 e_normalize_path(Char c)
2070 {
2071     USE(c);
2072     *LastChar = '\0';		/* just in case */
2073     return(CC_NORMALIZE_PATH);
2074 }
2075 
2076 /*ARGSUSED*/
2077 CCRETVAL
2078 e_normalize_command(Char c)
2079 {
2080     USE(c);
2081     *LastChar = '\0';		/* just in case */
2082     return(CC_NORMALIZE_COMMAND);
2083 }
2084 
2085 /*ARGSUSED*/
2086 CCRETVAL
2087 e_expand_vars(Char c)
2088 {
2089     USE(c);
2090     *LastChar = '\0';		/* just in case */
2091     return(CC_EXPAND_VARS);
2092 }
2093 
2094 /*ARGSUSED*/
2095 CCRETVAL
2096 e_which(Char c)
2097 {				/* do a fast command line which(1) */
2098     USE(c);
2099     c_save_inputbuf();
2100     Hist_num = 0;		/* for the history commands */
2101     PastBottom();
2102     *LastChar = '\0';		/* just in case */
2103     return(CC_WHICH);
2104 }
2105 
2106 /*ARGSUSED*/
2107 CCRETVAL
2108 e_last_item(Char c)
2109 {				/* insert the last element of the prev. cmd */
2110     struct Hist *hp;
2111     struct wordent *wp, *firstp;
2112     int i;
2113     Char *expanded;
2114 
2115     USE(c);
2116     if (Argument <= 0)
2117 	return(CC_ERROR);
2118 
2119     hp = Histlist.Hnext;
2120     if (hp == NULL) {	/* this is only if no history */
2121 	return(CC_ERROR);
2122     }
2123 
2124     wp = (hp->Hlex).prev;
2125 
2126     if (wp->prev == (struct wordent *) NULL)
2127 	return(CC_ERROR);	/* an empty history entry */
2128 
2129     firstp = (hp->Hlex).next;
2130 
2131     /* back up arg words in lex */
2132     for (i = 0; i < Argument && wp != firstp; i++) {
2133 	wp = wp->prev;
2134     }
2135 
2136     expanded = expand_lex(wp->prev, 0, i - 1);
2137     if (InsertStr(expanded)) {
2138 	xfree(expanded);
2139 	return(CC_ERROR);
2140     }
2141 
2142     xfree(expanded);
2143     return(CC_REFRESH);
2144 }
2145 
2146 /*ARGSUSED*/
2147 CCRETVAL
2148 e_dabbrev_expand(Char c)
2149 {				/* expand to preceding word matching prefix */
2150     Char *cp, *ncp, *bp;
2151     struct Hist *hp;
2152     int arg = 0, i;
2153     size_t len = 0;
2154     int found = 0;
2155     Char *hbuf;
2156     static int oldevent, hist, word;
2157     static Char *start, *oldcursor;
2158 
2159     USE(c);
2160     if (Argument <= 0)
2161 	return(CC_ERROR);
2162 
2163     cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2164     if (cp == Cursor || Isspace(*cp))
2165 	return(CC_ERROR);
2166 
2167     hbuf = NULL;
2168     hp = Histlist.Hnext;
2169     bp = InputBuf;
2170     if (Argument == 1 && eventno == oldevent && cp == start &&
2171 	Cursor == oldcursor && patbuf.len > 0
2172 	&& Strncmp(patbuf.s, cp, patbuf.len) == 0){
2173 	/* continue previous search - go to last match (hist/word) */
2174 	if (hist != 0) {		/* need to move up history */
2175 	    for (i = 1; i < hist && hp != NULL; i++)
2176 		hp = hp->Hnext;
2177 	    if (hp == NULL)	/* "can't happen" */
2178 		goto err_hbuf;
2179 	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2180 	    cp = Strend(hbuf);
2181 	    bp = hbuf;
2182 	    hp = hp->Hnext;
2183 	}
2184 	cp = c_preword(cp, bp, word, STRshwordsep);
2185     } else {			/* starting new search */
2186 	oldevent = eventno;
2187 	start = cp;
2188 	patbuf.len = 0;
2189 	Strbuf_appendn(&patbuf, cp, Cursor - cp);
2190 	hist = 0;
2191 	word = 0;
2192     }
2193 
2194     while (!found) {
2195 	ncp = c_preword(cp, bp, 1, STRshwordsep);
2196 	if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2197 	    hist++;
2198 	    word = 0;
2199 	    if (hp == NULL)
2200 		goto err_hbuf;
2201 	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2202 	    cp = Strend(hbuf);
2203 	    bp = hbuf;
2204 	    hp = hp->Hnext;
2205 	    continue;
2206 	} else {
2207 	    word++;
2208 	    len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2209 	    cp = ncp;
2210 	}
2211 	if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2212 	    /* We don't fully check distinct matches as Gnuemacs does: */
2213 	    if (Argument > 1) {	/* just count matches */
2214 		if (++arg >= Argument)
2215 		    found++;
2216 	    } else {		/* match if distinct from previous */
2217 		if (len != (size_t)(Cursor - start)
2218 		    || Strncmp(cp, start, len) != 0)
2219 		    found++;
2220 	    }
2221 	}
2222     }
2223 
2224     if (LastChar + len - (Cursor - start) >= InputLim)
2225 	goto err_hbuf;	/* no room */
2226     DeleteBack(Cursor - start);
2227     c_insert(len);
2228     while (len--)
2229 	*Cursor++ = *cp++;
2230     oldcursor = Cursor;
2231     xfree(hbuf);
2232     return(CC_REFRESH);
2233 
2234  err_hbuf:
2235     xfree(hbuf);
2236     return CC_ERROR;
2237 }
2238 
2239 /*ARGSUSED*/
2240 CCRETVAL
2241 e_yank_kill(Char c)
2242 {				/* almost like GnuEmacs */
2243     int len;
2244     Char *kp, *cp;
2245 
2246     USE(c);
2247     if (KillRingLen == 0)	/* nothing killed */
2248 	return(CC_ERROR);
2249     len = Strlen(KillRing[YankPos].buf);
2250     if (LastChar + len >= InputLim)
2251 	return(CC_ERROR);	/* end of buffer space */
2252 
2253     /* else */
2254     cp = Cursor;		/* for speed */
2255 
2256     c_insert(len);		/* open the space, */
2257     for (kp = KillRing[YankPos].buf; *kp; kp++)	/* copy the chars */
2258 	*cp++ = *kp;
2259 
2260     if (Argument == 1) {	/* if no arg */
2261 	Mark = Cursor;		/* mark at beginning, cursor at end */
2262 	Cursor = cp;
2263     } else {
2264 	Mark = cp;		/* else cursor at beginning, mark at end */
2265     }
2266 
2267     if (adrof(STRhighlight) && MarkIsSet) {
2268 	ClearLines();
2269 	ClearDisp();
2270     }
2271     MarkIsSet = 0;
2272     return(CC_REFRESH);
2273 }
2274 
2275 /*ARGSUSED*/
2276 CCRETVAL
2277 e_yank_pop(Char c)
2278 {				/* almost like GnuEmacs */
2279     int m_bef_c, del_len, ins_len;
2280     Char *kp, *cp;
2281 
2282     USE(c);
2283 
2284 #if 0
2285     /* XXX This "should" be here, but doesn't work, since LastCmd
2286        gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2287        (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2288        second one will "succeed" even if the first one wasn't preceded
2289        by a yank, and giving an argument is impossible. Now we "succeed"
2290        regardless of previous command, which is wrong too of course. */
2291     if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2292 	return(CC_ERROR);
2293 #endif
2294 
2295     if (KillRingLen == 0)	/* nothing killed */
2296 	return(CC_ERROR);
2297     YankPos -= Argument;
2298     while (YankPos < 0)
2299 	YankPos += KillRingLen;
2300     YankPos %= KillRingLen;
2301 
2302     if (Cursor > Mark) {
2303 	del_len = Cursor - Mark;
2304 	m_bef_c = 1;
2305     } else {
2306 	del_len = Mark - Cursor;
2307 	m_bef_c = 0;
2308     }
2309     ins_len = Strlen(KillRing[YankPos].buf);
2310     if (LastChar + ins_len - del_len >= InputLim)
2311 	return(CC_ERROR);	/* end of buffer space */
2312 
2313     if (m_bef_c) {
2314 	c_delbefore(del_len);
2315     } else {
2316 	c_delafter(del_len);
2317     }
2318     cp = Cursor;		/* for speed */
2319 
2320     c_insert(ins_len);		/* open the space, */
2321     for (kp = KillRing[YankPos].buf; *kp; kp++)	/* copy the chars */
2322 	*cp++ = *kp;
2323 
2324     if (m_bef_c) {
2325 	Mark = Cursor;		/* mark at beginning, cursor at end */
2326 	Cursor = cp;
2327     } else {
2328 	Mark = cp;		/* else cursor at beginning, mark at end */
2329     }
2330 
2331     if (adrof(STRhighlight) && MarkIsSet) {
2332 	ClearLines();
2333 	ClearDisp();
2334     }
2335     MarkIsSet = 0;
2336     return(CC_REFRESH);
2337 }
2338 
2339 /*ARGSUSED*/
2340 CCRETVAL
2341 v_delprev(Char c) 		/* Backspace key in insert mode */
2342 {
2343     int rc;
2344 
2345     USE(c);
2346     rc = CC_ERROR;
2347 
2348     if (InsertPos != 0) {
2349 	if (Argument <= Cursor - InsertPos) {
2350 	    c_delbefore(Argument);	/* delete before */
2351 	    rc = CC_REFRESH;
2352 	}
2353     }
2354     return(rc);
2355 }   /* v_delprev  */
2356 
2357 /*ARGSUSED*/
2358 CCRETVAL
2359 e_delprev(Char c)
2360 {
2361     USE(c);
2362     if (Cursor > InputBuf) {
2363 	c_delbefore(Argument);	/* delete before dot */
2364 	return(CC_REFRESH);
2365     }
2366     else {
2367 	return(CC_ERROR);
2368     }
2369 }
2370 
2371 /*ARGSUSED*/
2372 CCRETVAL
2373 e_delwordprev(Char c)
2374 {
2375     Char *cp;
2376 
2377     USE(c);
2378     if (Cursor == InputBuf)
2379 	return(CC_ERROR);
2380     /* else */
2381 
2382     cp = c_prev_word(Cursor, InputBuf, Argument);
2383 
2384     c_push_kill(cp, Cursor);	/* save the text */
2385 
2386     c_delbefore((int)(Cursor - cp));	/* delete before dot */
2387     return(CC_REFRESH);
2388 }
2389 
2390 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2391  *
2392  * Changed the names of some of the ^D family of editor functions to
2393  * correspond to what they actually do and created new e_delnext_list
2394  * for completeness.
2395  *
2396  *   Old names:			New names:
2397  *
2398  *   delete-char		delete-char-or-eof
2399  *     F_DELNEXT		  F_DELNEXT_EOF
2400  *     e_delnext		  e_delnext_eof
2401  *     edelnxt			  edelnxteof
2402  *   delete-char-or-eof		delete-char
2403  *     F_DELNEXT_EOF		  F_DELNEXT
2404  *     e_delnext_eof		  e_delnext
2405  *     edelnxteof		  edelnxt
2406  *   delete-char-or-list	delete-char-or-list-or-eof
2407  *     F_LIST_DELNEXT		  F_DELNEXT_LIST_EOF
2408  *     e_list_delnext		  e_delnext_list_eof
2409  *   				  edellsteof
2410  *   (no old equivalent)	delete-char-or-list
2411  *   				  F_DELNEXT_LIST
2412  *   				  e_delnext_list
2413  *   				  e_delnxtlst
2414  */
2415 
2416 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2417 /* rename e_delnext() -> e_delnext_eof() */
2418 /*ARGSUSED*/
2419 CCRETVAL
2420 e_delnext(Char c)
2421 {
2422     USE(c);
2423     if (Cursor == LastChar) {/* if I'm at the end */
2424 	if (!VImode) {
2425 		return(CC_ERROR);
2426 	}
2427 	else {
2428 	    if (Cursor != InputBuf)
2429 		Cursor--;
2430 	    else
2431 		return(CC_ERROR);
2432 	}
2433     }
2434     c_delafter(Argument);	/* delete after dot */
2435     if (Cursor > LastChar)
2436 	Cursor = LastChar;	/* bounds check */
2437     return(CC_REFRESH);
2438 }
2439 
2440 
2441 /*ARGSUSED*/
2442 CCRETVAL
2443 e_delnext_eof(Char c)
2444 {
2445     USE(c);
2446     if (Cursor == LastChar) {/* if I'm at the end */
2447 	if (!VImode) {
2448 	    if (Cursor == InputBuf) {
2449 		/* if I'm also at the beginning */
2450 		so_write(STReof, 4);/* then do a EOF */
2451 		flush();
2452 		return(CC_EOF);
2453 	    }
2454 	    else
2455 		return(CC_ERROR);
2456 	}
2457 	else {
2458 	    if (Cursor != InputBuf)
2459 		Cursor--;
2460 	    else
2461 		return(CC_ERROR);
2462 	}
2463     }
2464     c_delafter(Argument);	/* delete after dot */
2465     if (Cursor > LastChar)
2466 	Cursor = LastChar;	/* bounds check */
2467     return(CC_REFRESH);
2468 }
2469 
2470 /*ARGSUSED*/
2471 CCRETVAL
2472 e_delnext_list(Char c)
2473 {
2474     USE(c);
2475     if (Cursor == LastChar) {	/* if I'm at the end */
2476 	PastBottom();
2477 	*LastChar = '\0';	/* just in case */
2478 	return(CC_LIST_CHOICES);
2479     }
2480     else {
2481 	c_delafter(Argument);	/* delete after dot */
2482 	if (Cursor > LastChar)
2483 	    Cursor = LastChar;	/* bounds check */
2484 	return(CC_REFRESH);
2485     }
2486 }
2487 
2488 /*ARGSUSED*/
2489 CCRETVAL
2490 e_delnext_list_eof(Char c)
2491 {
2492     USE(c);
2493     if (Cursor == LastChar) {	/* if I'm at the end */
2494 	if (Cursor == InputBuf) {	/* if I'm also at the beginning */
2495 	    so_write(STReof, 4);/* then do a EOF */
2496 	    flush();
2497 	    return(CC_EOF);
2498 	}
2499 	else {
2500 	    PastBottom();
2501 	    *LastChar = '\0';	/* just in case */
2502 	    return(CC_LIST_CHOICES);
2503 	}
2504     }
2505     else {
2506 	c_delafter(Argument);	/* delete after dot */
2507 	if (Cursor > LastChar)
2508 	    Cursor = LastChar;	/* bounds check */
2509 	return(CC_REFRESH);
2510     }
2511 }
2512 
2513 /*ARGSUSED*/
2514 CCRETVAL
2515 e_list_eof(Char c)
2516 {
2517     CCRETVAL rv;
2518 
2519     USE(c);
2520     if (Cursor == LastChar && Cursor == InputBuf) {
2521 	so_write(STReof, 4);	/* then do a EOF */
2522 	flush();
2523 	rv = CC_EOF;
2524     }
2525     else {
2526 	PastBottom();
2527 	*LastChar = '\0';	/* just in case */
2528 	rv = CC_LIST_CHOICES;
2529     }
2530     return rv;
2531 }
2532 
2533 /*ARGSUSED*/
2534 CCRETVAL
2535 e_delwordnext(Char c)
2536 {
2537     Char *cp;
2538 
2539     USE(c);
2540     if (Cursor == LastChar)
2541 	return(CC_ERROR);
2542     /* else */
2543 
2544     cp = c_next_word(Cursor, LastChar, Argument);
2545 
2546     c_push_kill(Cursor, cp);	/* save the text */
2547 
2548     c_delafter((int)(cp - Cursor));	/* delete after dot */
2549     if (Cursor > LastChar)
2550 	Cursor = LastChar;	/* bounds check */
2551     return(CC_REFRESH);
2552 }
2553 
2554 /*ARGSUSED*/
2555 CCRETVAL
2556 e_toend(Char c)
2557 {
2558     USE(c);
2559     Cursor = LastChar;
2560     if (VImode)
2561 	if (ActionFlag & TCSHOP_DELETE) {
2562 	    c_delfini();
2563 	    return(CC_REFRESH);
2564 	}
2565     RefCursor();		/* move the cursor */
2566     return(CC_NORM);
2567 }
2568 
2569 /*ARGSUSED*/
2570 CCRETVAL
2571 e_tobeg(Char c)
2572 {
2573     USE(c);
2574     Cursor = InputBuf;
2575 
2576     if (VImode) {
2577 	while (Isspace(*Cursor)) /* We want FIRST non space character */
2578 	    Cursor++;
2579 	if (ActionFlag & TCSHOP_DELETE) {
2580 	    c_delfini();
2581 	    return(CC_REFRESH);
2582 	}
2583     }
2584 
2585     RefCursor();		/* move the cursor */
2586     return(CC_NORM);
2587 }
2588 
2589 /*ARGSUSED*/
2590 CCRETVAL
2591 e_killend(Char c)
2592 {
2593     USE(c);
2594     c_push_kill(Cursor, LastChar); /* copy it */
2595     LastChar = Cursor;		/* zap! -- delete to end */
2596     if (Mark > Cursor)
2597         Mark = Cursor;
2598     MarkIsSet = 0;
2599     return(CC_REFRESH);
2600 }
2601 
2602 
2603 /*ARGSUSED*/
2604 CCRETVAL
2605 e_killbeg(Char c)
2606 {
2607     USE(c);
2608     c_push_kill(InputBuf, Cursor); /* copy it */
2609     c_delbefore((int)(Cursor - InputBuf));
2610     if (Mark && Mark > Cursor)
2611         Mark -= Cursor-InputBuf;
2612     return(CC_REFRESH);
2613 }
2614 
2615 /*ARGSUSED*/
2616 CCRETVAL
2617 e_killall(Char c)
2618 {
2619     USE(c);
2620     c_push_kill(InputBuf, LastChar); /* copy it */
2621     Cursor = Mark = LastChar = InputBuf;	/* zap! -- delete all of it */
2622     MarkIsSet = 0;
2623     return(CC_REFRESH);
2624 }
2625 
2626 /*ARGSUSED*/
2627 CCRETVAL
2628 e_killregion(Char c)
2629 {
2630     USE(c);
2631     if (!Mark)
2632 	return(CC_ERROR);
2633 
2634     if (Mark > Cursor) {
2635 	c_push_kill(Cursor, Mark); /* copy it */
2636 	c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2637 	Mark = Cursor;
2638     }
2639     else {			/* mark is before cursor */
2640 	c_push_kill(Mark, Cursor); /* copy it */
2641 	c_delbefore((int)(Cursor - Mark));
2642     }
2643     if (adrof(STRhighlight) && MarkIsSet) {
2644 	ClearLines();
2645 	ClearDisp();
2646     }
2647     MarkIsSet = 0;
2648     return(CC_REFRESH);
2649 }
2650 
2651 /*ARGSUSED*/
2652 CCRETVAL
2653 e_copyregion(Char c)
2654 {
2655     USE(c);
2656     if (!Mark)
2657 	return(CC_ERROR);
2658 
2659     if (Mark > Cursor) {
2660 	c_push_kill(Cursor, Mark); /* copy it */
2661     }
2662     else {			/* mark is before cursor */
2663 	c_push_kill(Mark, Cursor); /* copy it */
2664     }
2665     return(CC_NORM);		/* don't even need to Refresh() */
2666 }
2667 
2668 /*ARGSUSED*/
2669 CCRETVAL
2670 e_charswitch(Char cc)
2671 {
2672     Char c;
2673 
2674     USE(cc);
2675 
2676     /* do nothing if we are at beginning of line or have only one char */
2677     if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2678 	return(CC_ERROR);
2679     }
2680 
2681     if (Cursor < LastChar) {
2682 	Cursor++;
2683     }
2684     c = Cursor[-2];
2685     Cursor[-2] = Cursor[-1];
2686     Cursor[-1] = c;
2687     return(CC_REFRESH);
2688 }
2689 
2690 /*ARGSUSED*/
2691 CCRETVAL
2692 e_gcharswitch(Char cc)
2693 {				/* gosmacs style ^T */
2694     Char c;
2695 
2696     USE(cc);
2697     if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2698 	c = Cursor[-2];
2699 	Cursor[-2] = Cursor[-1];
2700 	Cursor[-1] = c;
2701 	return(CC_REFRESH);
2702     }
2703     else {
2704 	return(CC_ERROR);
2705     }
2706 }
2707 
2708 /*ARGSUSED*/
2709 CCRETVAL
2710 e_charback(Char c)
2711 {
2712     USE(c);
2713     if (Cursor > InputBuf) {
2714 	if (Argument > Cursor - InputBuf)
2715 	    Cursor = InputBuf;
2716 	else
2717 	    Cursor -= Argument;
2718 
2719 	if (VImode)
2720 	    if (ActionFlag & TCSHOP_DELETE) {
2721 		c_delfini();
2722 		return(CC_REFRESH);
2723 	    }
2724 
2725 	RefCursor();
2726 	return(CC_NORM);
2727     }
2728     else {
2729 	return(CC_ERROR);
2730     }
2731 }
2732 
2733 /*ARGSUSED*/
2734 CCRETVAL
2735 v_wordback(Char c)
2736 {
2737     USE(c);
2738     if (Cursor == InputBuf)
2739 	return(CC_ERROR);
2740     /* else */
2741 
2742     Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2743 
2744     if (ActionFlag & TCSHOP_DELETE) {
2745 	c_delfini();
2746 	return(CC_REFRESH);
2747     }
2748 
2749     RefCursor();
2750     return(CC_NORM);
2751 }
2752 
2753 /*ARGSUSED*/
2754 CCRETVAL
2755 e_wordback(Char c)
2756 {
2757     USE(c);
2758     if (Cursor == InputBuf)
2759 	return(CC_ERROR);
2760     /* else */
2761 
2762     Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2763 
2764     if (VImode)
2765 	if (ActionFlag & TCSHOP_DELETE) {
2766 	    c_delfini();
2767 	    return(CC_REFRESH);
2768 	}
2769 
2770     RefCursor();
2771     return(CC_NORM);
2772 }
2773 
2774 /*ARGSUSED*/
2775 CCRETVAL
2776 e_charfwd(Char c)
2777 {
2778     USE(c);
2779     if (Cursor < LastChar) {
2780 	Cursor += Argument;
2781 	if (Cursor > LastChar)
2782 	    Cursor = LastChar;
2783 
2784 	if (VImode)
2785 	    if (ActionFlag & TCSHOP_DELETE) {
2786 		c_delfini();
2787 		return(CC_REFRESH);
2788 	    }
2789 
2790 	RefCursor();
2791 	return(CC_NORM);
2792     }
2793     else {
2794 	return(CC_ERROR);
2795     }
2796 }
2797 
2798 /*ARGSUSED*/
2799 CCRETVAL
2800 e_wordfwd(Char c)
2801 {
2802     USE(c);
2803     if (Cursor == LastChar)
2804 	return(CC_ERROR);
2805     /* else */
2806 
2807     Cursor = c_next_word(Cursor, LastChar, Argument);
2808 
2809     if (VImode)
2810 	if (ActionFlag & TCSHOP_DELETE) {
2811 	    c_delfini();
2812 	    return(CC_REFRESH);
2813 	}
2814 
2815     RefCursor();
2816     return(CC_NORM);
2817 }
2818 
2819 /*ARGSUSED*/
2820 CCRETVAL
2821 v_wordfwd(Char c)
2822 {
2823     USE(c);
2824     if (Cursor == LastChar)
2825 	return(CC_ERROR);
2826     /* else */
2827 
2828     Cursor = c_nexword(Cursor, LastChar, Argument);
2829 
2830     if (VImode)
2831 	if (ActionFlag & TCSHOP_DELETE) {
2832 	    c_delfini();
2833 	    return(CC_REFRESH);
2834 	}
2835 
2836     RefCursor();
2837     return(CC_NORM);
2838 }
2839 
2840 /*ARGSUSED*/
2841 CCRETVAL
2842 v_wordbegnext(Char c)
2843 {
2844     USE(c);
2845     if (Cursor == LastChar)
2846 	return(CC_ERROR);
2847     /* else */
2848 
2849     Cursor = c_next_word(Cursor, LastChar, Argument);
2850     if (Cursor < LastChar)
2851 	Cursor++;
2852 
2853     if (VImode)
2854 	if (ActionFlag & TCSHOP_DELETE) {
2855 	    c_delfini();
2856 	    return(CC_REFRESH);
2857 	}
2858 
2859     RefCursor();
2860     return(CC_NORM);
2861 }
2862 
2863 /*ARGSUSED*/
2864 static CCRETVAL
2865 v_repeat_srch(int c)
2866 {
2867     CCRETVAL rv = CC_ERROR;
2868 #ifdef SDEBUG
2869     xprintf("dir %d patlen %d patbuf %S\n",
2870 	    c, (int)patbuf.len, patbuf.s);
2871 #endif
2872 
2873     LastCmd = (KEYCMD) c;  /* Hack to stop c_hsetpat */
2874     LastChar = InputBuf;
2875     switch (c) {
2876     case F_DOWN_SEARCH_HIST:
2877 	rv = e_down_search_hist(0);
2878 	break;
2879     case F_UP_SEARCH_HIST:
2880 	rv = e_up_search_hist(0);
2881 	break;
2882     default:
2883 	break;
2884     }
2885     return rv;
2886 }
2887 
2888 static CCRETVAL
2889 v_csearch_back(Char ch, int count, int tflag)
2890 {
2891     Char *cp;
2892 
2893     cp = Cursor;
2894     while (count--) {
2895 	if (*cp == ch)
2896 	    cp--;
2897 	while (cp > InputBuf && *cp != ch)
2898 	    cp--;
2899     }
2900 
2901     if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2902 	return(CC_ERROR);
2903 
2904     if (*cp == ch && tflag)
2905 	cp++;
2906 
2907     Cursor = cp;
2908 
2909     if (ActionFlag & TCSHOP_DELETE) {
2910 	Cursor++;
2911 	c_delfini();
2912 	return(CC_REFRESH);
2913     }
2914 
2915     RefCursor();
2916     return(CC_NORM);
2917 }
2918 
2919 static CCRETVAL
2920 v_csearch_fwd(Char ch, int count, int tflag)
2921 {
2922     Char *cp;
2923 
2924     cp = Cursor;
2925     while (count--) {
2926 	if (*cp == ch)
2927 	    cp++;
2928 	while (cp < LastChar && *cp != ch)
2929 	    cp++;
2930     }
2931 
2932     if (cp >= LastChar)
2933 	return(CC_ERROR);
2934 
2935     if (*cp == ch && tflag)
2936 	cp--;
2937 
2938     Cursor = cp;
2939 
2940     if (ActionFlag & TCSHOP_DELETE) {
2941 	Cursor++;
2942 	c_delfini();
2943 	return(CC_REFRESH);
2944     }
2945     RefCursor();
2946     return(CC_NORM);
2947 }
2948 
2949 /*ARGSUSED*/
2950 static CCRETVAL
2951 v_action(int c)
2952 {
2953     Char *cp, *kp;
2954 
2955     if (ActionFlag == TCSHOP_DELETE) {
2956 	ActionFlag = TCSHOP_NOP;
2957 	ActionPos = 0;
2958 
2959 	UndoSize = 0;
2960 	kp = UndoBuf;
2961 	for (cp = InputBuf; cp < LastChar; cp++) {
2962 	    *kp++ = *cp;
2963 	    UndoSize++;
2964 	}
2965 
2966 	UndoAction = TCSHOP_INSERT;
2967 	UndoPtr  = InputBuf;
2968 	LastChar = InputBuf;
2969 	Cursor   = InputBuf;
2970 	if (c & TCSHOP_INSERT)
2971 	    c_alternativ_key_map(0);
2972 
2973 	return(CC_REFRESH);
2974     }
2975 #ifdef notdef
2976     else if (ActionFlag == TCSHOP_NOP) {
2977 #endif
2978 	ActionPos = Cursor;
2979 	ActionFlag = c;
2980 	return(CC_ARGHACK);  /* Do NOT clear out argument */
2981 #ifdef notdef
2982     }
2983     else {
2984 	ActionFlag = 0;
2985 	ActionPos = 0;
2986 	return(CC_ERROR);
2987     }
2988 #endif
2989 }
2990 
2991 #ifdef COMMENT
2992 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2993 static void
2994 c_get_word(Char **begin, Char **end)
2995 {
2996     Char   *cp;
2997 
2998     cp = &Cursor[0];
2999     while (Argument--) {
3000 	while ((cp <= LastChar) && (isword(*cp)))
3001 	    cp++;
3002 	*end = --cp;
3003 	while ((cp >= InputBuf) && (isword(*cp)))
3004 	    cp--;
3005 	*begin = ++cp;
3006     }
3007 }
3008 #endif /* COMMENT */
3009 
3010 /*ARGSUSED*/
3011 CCRETVAL
3012 e_uppercase(Char c)
3013 {
3014     Char   *cp, *end;
3015 
3016     USE(c);
3017     end = c_next_word(Cursor, LastChar, Argument);
3018 
3019     for (cp = Cursor; cp < end; cp++)	/* PWP: was cp=begin */
3020 	if (Islower(*cp))
3021 	    *cp = Toupper(*cp);
3022 
3023     Cursor = end;
3024     if (Cursor > LastChar)
3025 	Cursor = LastChar;
3026     return(CC_REFRESH);
3027 }
3028 
3029 
3030 /*ARGSUSED*/
3031 CCRETVAL
3032 e_capitalcase(Char c)
3033 {
3034     Char   *cp, *end;
3035 
3036     USE(c);
3037     end = c_next_word(Cursor, LastChar, Argument);
3038 
3039     cp = Cursor;
3040     for (; cp < end; cp++) {
3041 	if (Isalpha(*cp)) {
3042 	    if (Islower(*cp))
3043 		*cp = Toupper(*cp);
3044 	    cp++;
3045 	    break;
3046 	}
3047     }
3048     for (; cp < end; cp++)
3049 	if (Isupper(*cp))
3050 	    *cp = Tolower(*cp);
3051 
3052     Cursor = end;
3053     if (Cursor > LastChar)
3054 	Cursor = LastChar;
3055     return(CC_REFRESH);
3056 }
3057 
3058 /*ARGSUSED*/
3059 CCRETVAL
3060 e_lowercase(Char c)
3061 {
3062     Char   *cp, *end;
3063 
3064     USE(c);
3065     end = c_next_word(Cursor, LastChar, Argument);
3066 
3067     for (cp = Cursor; cp < end; cp++)
3068 	if (Isupper(*cp))
3069 	    *cp = Tolower(*cp);
3070 
3071     Cursor = end;
3072     if (Cursor > LastChar)
3073 	Cursor = LastChar;
3074     return(CC_REFRESH);
3075 }
3076 
3077 
3078 /*ARGSUSED*/
3079 CCRETVAL
3080 e_set_mark(Char c)
3081 {
3082     USE(c);
3083     if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3084 	ClearLines();
3085 	ClearDisp();
3086 	Refresh();
3087     }
3088     Mark = Cursor;
3089     MarkIsSet = 1;
3090     return(CC_NORM);
3091 }
3092 
3093 /*ARGSUSED*/
3094 CCRETVAL
3095 e_exchange_mark(Char c)
3096 {
3097     Char *cp;
3098 
3099     USE(c);
3100     cp = Cursor;
3101     Cursor = Mark;
3102     Mark = cp;
3103     RefCursor();
3104     return(CC_NORM);
3105 }
3106 
3107 /*ARGSUSED*/
3108 CCRETVAL
3109 e_argfour(Char c)
3110 {				/* multiply current argument by 4 */
3111     USE(c);
3112     if (Argument > 1000000)
3113 	return CC_ERROR;
3114     DoingArg = 1;
3115     Argument *= 4;
3116     return(CC_ARGHACK);
3117 }
3118 
3119 static void
3120 quote_mode_cleanup(void *unused)
3121 {
3122     USE(unused);
3123     QuoteModeOff();
3124 }
3125 
3126 /*ARGSUSED*/
3127 CCRETVAL
3128 e_quote(Char c)
3129 {
3130     Char    ch;
3131     int     num;
3132 
3133     USE(c);
3134     QuoteModeOn();
3135     cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3136     num = GetNextChar(&ch);
3137     cleanup_until(&c);
3138     if (num == 1)
3139 	return e_insert(ch);
3140     else
3141 	return e_send_eof(0);
3142 }
3143 
3144 /*ARGSUSED*/
3145 CCRETVAL
3146 e_metanext(Char c)
3147 {
3148     USE(c);
3149     MetaNext = 1;
3150     return(CC_ARGHACK);	/* preserve argument */
3151 }
3152 
3153 #ifdef notdef
3154 /*ARGSUSED*/
3155 CCRETVAL
3156 e_extendnext(Char c)
3157 {
3158     CurrentKeyMap = CcAltMap;
3159     return(CC_ARGHACK);	/* preserve argument */
3160 }
3161 
3162 #endif
3163 
3164 /*ARGSUSED*/
3165 CCRETVAL
3166 v_insbeg(Char c)
3167 {				/* move to beginning of line and start vi
3168 				 * insert mode */
3169     USE(c);
3170     Cursor = InputBuf;
3171     InsertPos = Cursor;
3172 
3173     UndoPtr  = Cursor;
3174     UndoAction = TCSHOP_DELETE;
3175 
3176     RefCursor();		/* move the cursor */
3177     c_alternativ_key_map(0);
3178     return(CC_NORM);
3179 }
3180 
3181 /*ARGSUSED*/
3182 CCRETVAL
3183 v_replone(Char c)
3184 {				/* vi mode overwrite one character */
3185     USE(c);
3186     c_alternativ_key_map(0);
3187     inputmode = MODE_REPLACE_1;
3188     UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
3189     UndoPtr = Cursor;
3190     UndoSize = 0;
3191     return(CC_NORM);
3192 }
3193 
3194 /*ARGSUSED*/
3195 CCRETVAL
3196 v_replmode(Char c)
3197 {				/* vi mode start overwriting */
3198     USE(c);
3199     c_alternativ_key_map(0);
3200     inputmode = MODE_REPLACE;
3201     UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
3202     UndoPtr = Cursor;
3203     UndoSize = 0;
3204     return(CC_NORM);
3205 }
3206 
3207 /*ARGSUSED*/
3208 CCRETVAL
3209 v_substchar(Char c)
3210 {				/* vi mode substitute for one char */
3211     USE(c);
3212     c_delafter(Argument);
3213     c_alternativ_key_map(0);
3214     return(CC_REFRESH);
3215 }
3216 
3217 /*ARGSUSED*/
3218 CCRETVAL
3219 v_substline(Char c)
3220 {				/* vi mode replace whole line */
3221     USE(c);
3222     (void) e_killall(0);
3223     c_alternativ_key_map(0);
3224     return(CC_REFRESH);
3225 }
3226 
3227 /*ARGSUSED*/
3228 CCRETVAL
3229 v_chgtoend(Char c)
3230 {				/* vi mode change to end of line */
3231     USE(c);
3232     (void) e_killend(0);
3233     c_alternativ_key_map(0);
3234     return(CC_REFRESH);
3235 }
3236 
3237 /*ARGSUSED*/
3238 CCRETVAL
3239 v_insert(Char c)
3240 {				/* vi mode start inserting */
3241     USE(c);
3242     c_alternativ_key_map(0);
3243 
3244     InsertPos = Cursor;
3245     UndoPtr = Cursor;
3246     UndoAction = TCSHOP_DELETE;
3247 
3248     return(CC_NORM);
3249 }
3250 
3251 /*ARGSUSED*/
3252 CCRETVAL
3253 v_add(Char c)
3254 {				/* vi mode start adding */
3255     USE(c);
3256     c_alternativ_key_map(0);
3257     if (Cursor < LastChar)
3258     {
3259 	Cursor++;
3260 	if (Cursor > LastChar)
3261 	    Cursor = LastChar;
3262 	RefCursor();
3263     }
3264 
3265     InsertPos = Cursor;
3266     UndoPtr = Cursor;
3267     UndoAction = TCSHOP_DELETE;
3268 
3269     return(CC_NORM);
3270 }
3271 
3272 /*ARGSUSED*/
3273 CCRETVAL
3274 v_addend(Char c)
3275 {				/* vi mode to add at end of line */
3276     USE(c);
3277     c_alternativ_key_map(0);
3278     Cursor = LastChar;
3279 
3280     InsertPos = LastChar;	/* Mark where insertion begins */
3281     UndoPtr = LastChar;
3282     UndoAction = TCSHOP_DELETE;
3283 
3284     RefCursor();
3285     return(CC_NORM);
3286 }
3287 
3288 /*ARGSUSED*/
3289 CCRETVAL
3290 v_change_case(Char cc)
3291 {
3292     Char    c;
3293 
3294     USE(cc);
3295     if (Cursor < LastChar) {
3296 #ifndef WINNT_NATIVE
3297 	c = *Cursor;
3298 #else
3299 	c = CHAR & *Cursor;
3300 #endif /* WINNT_NATIVE */
3301 	if (Isupper(c))
3302 	    *Cursor++ = Tolower(c);
3303 	else if (Islower(c))
3304 	    *Cursor++ = Toupper(c);
3305 	else
3306 	    Cursor++;
3307 	RefPlusOne(1);		/* fast refresh for one char */
3308 	return(CC_NORM);
3309     }
3310     return(CC_ERROR);
3311 }
3312 
3313 /*ARGSUSED*/
3314 CCRETVAL
3315 e_expand(Char c)
3316 {
3317     Char *p;
3318 
3319     USE(c);
3320     for (p = InputBuf; Isspace(*p); p++)
3321 	continue;
3322     if (p == LastChar)
3323 	return(CC_ERROR);
3324 
3325     justpr++;
3326     Expand++;
3327     return(e_newline(0));
3328 }
3329 
3330 /*ARGSUSED*/
3331 CCRETVAL
3332 e_startover(Char c)
3333 {				/* erase all of current line, start again */
3334     USE(c);
3335     ResetInLine(0);		/* reset the input pointers */
3336     return(CC_REFRESH);
3337 }
3338 
3339 /*ARGSUSED*/
3340 CCRETVAL
3341 e_redisp(Char c)
3342 {
3343     USE(c);
3344     ClearLines();
3345     ClearDisp();
3346     return(CC_REFRESH);
3347 }
3348 
3349 /*ARGSUSED*/
3350 CCRETVAL
3351 e_cleardisp(Char c)
3352 {
3353     USE(c);
3354     ClearScreen();		/* clear the whole real screen */
3355     ClearDisp();		/* reset everything */
3356     return(CC_REFRESH);
3357 }
3358 
3359 /*ARGSUSED*/
3360 CCRETVAL
3361 e_tty_int(Char c)
3362 {
3363     USE(c);
3364 #if defined(_MINIX) || defined(WINNT_NATIVE)
3365     /* SAK PATCH: erase all of current line, start again */
3366     ResetInLine(0);		/* reset the input pointers */
3367     xputchar('\n');
3368     ClearDisp();
3369     return (CC_REFRESH);
3370 #else /* !_MINIX && !WINNT_NATIVE */
3371     /* do no editing */
3372     return (CC_NORM);
3373 #endif /* _MINIX || WINNT_NATIVE */
3374 }
3375 
3376 /*
3377  * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3378  * Function to send a character back to the input stream in cooked
3379  * mode. Only works if we have TIOCSTI
3380  */
3381 /*ARGSUSED*/
3382 CCRETVAL
3383 e_stuff_char(Char c)
3384 {
3385 #ifdef TIOCSTI
3386      int was_raw = Tty_raw_mode;
3387      char buf[MB_LEN_MAX];
3388      size_t i, len;
3389 
3390      if (was_raw)
3391          (void) Cookedmode();
3392 
3393      (void) xwrite(SHIN, "\n", 1);
3394      len = one_wctomb(buf, c);
3395      for (i = 0; i < len; i++)
3396 	 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3397 
3398      if (was_raw)
3399 	 (void) Rawmode();
3400      return(e_redisp(c));
3401 #else /* !TIOCSTI */
3402      return(CC_ERROR);
3403 #endif /* !TIOCSTI */
3404 }
3405 
3406 /*ARGSUSED*/
3407 CCRETVAL
3408 e_insovr(Char c)
3409 {
3410     USE(c);
3411     inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3412     return(CC_NORM);
3413 }
3414 
3415 /*ARGSUSED*/
3416 CCRETVAL
3417 e_tty_dsusp(Char c)
3418 {
3419     USE(c);
3420     /* do no editing */
3421     return(CC_NORM);
3422 }
3423 
3424 /*ARGSUSED*/
3425 CCRETVAL
3426 e_tty_flusho(Char c)
3427 {
3428     USE(c);
3429     /* do no editing */
3430     return(CC_NORM);
3431 }
3432 
3433 /*ARGSUSED*/
3434 CCRETVAL
3435 e_tty_quit(Char c)
3436 {
3437     USE(c);
3438     /* do no editing */
3439     return(CC_NORM);
3440 }
3441 
3442 /*ARGSUSED*/
3443 CCRETVAL
3444 e_tty_tsusp(Char c)
3445 {
3446     USE(c);
3447     /* do no editing */
3448     return(CC_NORM);
3449 }
3450 
3451 /*ARGSUSED*/
3452 CCRETVAL
3453 e_tty_stopo(Char c)
3454 {
3455     USE(c);
3456     /* do no editing */
3457     return(CC_NORM);
3458 }
3459 
3460 /* returns the number of (attempted) expansions */
3461 int
3462 ExpandHistory(void)
3463 {
3464     *LastChar = '\0';		/* just in case */
3465     return c_substitute();
3466 }
3467 
3468 /*ARGSUSED*/
3469 CCRETVAL
3470 e_expand_history(Char c)
3471 {
3472     USE(c);
3473     (void)ExpandHistory();
3474     return(CC_NORM);
3475 }
3476 
3477 /*ARGSUSED*/
3478 CCRETVAL
3479 e_magic_space(Char c)
3480 {
3481     USE(c);
3482     *LastChar = '\0';		/* just in case */
3483     (void)c_substitute();
3484     return(e_insert(' '));
3485 }
3486 
3487 /*ARGSUSED*/
3488 CCRETVAL
3489 e_inc_fwd(Char c)
3490 {
3491     CCRETVAL ret;
3492 
3493     USE(c);
3494     patbuf.len = 0;
3495     MarkIsSet = 0;
3496     ret = e_inc_search(F_DOWN_SEARCH_HIST);
3497     if (adrof(STRhighlight) && IncMatchLen) {
3498 	IncMatchLen = 0;
3499 	ClearLines();
3500 	ClearDisp();
3501 	Refresh();
3502     }
3503     IncMatchLen = 0;
3504     return ret;
3505 }
3506 
3507 
3508 /*ARGSUSED*/
3509 CCRETVAL
3510 e_inc_back(Char c)
3511 {
3512     CCRETVAL ret;
3513 
3514     USE(c);
3515     patbuf.len = 0;
3516     MarkIsSet = 0;
3517     ret = e_inc_search(F_UP_SEARCH_HIST);
3518     if (adrof(STRhighlight) && IncMatchLen) {
3519 	IncMatchLen = 0;
3520 	ClearLines();
3521 	ClearDisp();
3522 	Refresh();
3523     }
3524     IncMatchLen = 0;
3525     return ret;
3526 }
3527 
3528 /*ARGSUSED*/
3529 CCRETVAL
3530 e_copyprev(Char c)
3531 {
3532     Char *cp, *oldc, *dp;
3533 
3534     USE(c);
3535     if (Cursor == InputBuf)
3536 	return(CC_ERROR);
3537     /* else */
3538 
3539     oldc = Cursor;
3540     /* does a bounds check */
3541     cp = c_prev_word(Cursor, InputBuf, Argument);
3542 
3543     c_insert((int)(oldc - cp));
3544     for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3545 	*dp++ = *cp;
3546 
3547     Cursor = dp;		/* put cursor at end */
3548 
3549     return(CC_REFRESH);
3550 }
3551 
3552 /*ARGSUSED*/
3553 CCRETVAL
3554 e_tty_starto(Char c)
3555 {
3556     USE(c);
3557     /* do no editing */
3558     return(CC_NORM);
3559 }
3560 
3561 /*ARGSUSED*/
3562 CCRETVAL
3563 e_load_average(Char c)
3564 {
3565     USE(c);
3566     PastBottom();
3567 #ifdef TIOCSTAT
3568     /*
3569      * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3570      * there even if they don't use it. (lukem@netbsd.org)
3571      */
3572     if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3573 #endif
3574 	xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3575     return(CC_REFRESH);
3576 }
3577 
3578 /*ARGSUSED*/
3579 CCRETVAL
3580 v_chgmeta(Char c)
3581 {
3582     USE(c);
3583     /*
3584      * Delete with insert == change: first we delete and then we leave in
3585      * insert mode.
3586      */
3587     return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3588 }
3589 
3590 /*ARGSUSED*/
3591 CCRETVAL
3592 v_delmeta(Char c)
3593 {
3594     USE(c);
3595     return(v_action(TCSHOP_DELETE));
3596 }
3597 
3598 
3599 /*ARGSUSED*/
3600 CCRETVAL
3601 v_endword(Char c)
3602 {
3603     USE(c);
3604     if (Cursor == LastChar)
3605 	return(CC_ERROR);
3606     /* else */
3607 
3608     Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3609 
3610     if (ActionFlag & TCSHOP_DELETE)
3611     {
3612 	Cursor++;
3613 	c_delfini();
3614 	return(CC_REFRESH);
3615     }
3616 
3617     RefCursor();
3618     return(CC_NORM);
3619 }
3620 
3621 /*ARGSUSED*/
3622 CCRETVAL
3623 v_eword(Char c)
3624 {
3625     USE(c);
3626     if (Cursor == LastChar)
3627 	return(CC_ERROR);
3628     /* else */
3629 
3630     Cursor = c_eword(Cursor, LastChar, Argument);
3631 
3632     if (ActionFlag & TCSHOP_DELETE) {
3633 	Cursor++;
3634 	c_delfini();
3635 	return(CC_REFRESH);
3636     }
3637 
3638     RefCursor();
3639     return(CC_NORM);
3640 }
3641 
3642 /*ARGSUSED*/
3643 CCRETVAL
3644 v_char_fwd(Char c)
3645 {
3646     Char ch;
3647 
3648     USE(c);
3649     if (GetNextChar(&ch) != 1)
3650 	return e_send_eof(0);
3651 
3652     srch_dir = CHAR_FWD;
3653     srch_char = ch;
3654 
3655     return v_csearch_fwd(ch, Argument, 0);
3656 
3657 }
3658 
3659 /*ARGSUSED*/
3660 CCRETVAL
3661 v_char_back(Char c)
3662 {
3663     Char ch;
3664 
3665     USE(c);
3666     if (GetNextChar(&ch) != 1)
3667 	return e_send_eof(0);
3668 
3669     srch_dir = CHAR_BACK;
3670     srch_char = ch;
3671 
3672     return v_csearch_back(ch, Argument, 0);
3673 }
3674 
3675 /*ARGSUSED*/
3676 CCRETVAL
3677 v_charto_fwd(Char c)
3678 {
3679     Char ch;
3680 
3681     USE(c);
3682     if (GetNextChar(&ch) != 1)
3683 	return e_send_eof(0);
3684 
3685     return v_csearch_fwd(ch, Argument, 1);
3686 
3687 }
3688 
3689 /*ARGSUSED*/
3690 CCRETVAL
3691 v_charto_back(Char c)
3692 {
3693     Char ch;
3694 
3695     USE(c);
3696     if (GetNextChar(&ch) != 1)
3697 	return e_send_eof(0);
3698 
3699     return v_csearch_back(ch, Argument, 1);
3700 }
3701 
3702 /*ARGSUSED*/
3703 CCRETVAL
3704 v_rchar_fwd(Char c)
3705 {
3706     USE(c);
3707     if (srch_char == 0)
3708 	return CC_ERROR;
3709 
3710     return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3711 			          v_csearch_back(srch_char, Argument, 0);
3712 }
3713 
3714 /*ARGSUSED*/
3715 CCRETVAL
3716 v_rchar_back(Char c)
3717 {
3718     USE(c);
3719     if (srch_char == 0)
3720 	return CC_ERROR;
3721 
3722     return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3723 			           v_csearch_back(srch_char, Argument, 0);
3724 }
3725 
3726 /*ARGSUSED*/
3727 CCRETVAL
3728 v_undo(Char c)
3729 {
3730     int  loop;
3731     Char *kp, *cp;
3732     Char temp;
3733     int	 size;
3734 
3735     USE(c);
3736     switch (UndoAction) {
3737     case TCSHOP_DELETE|TCSHOP_INSERT:
3738     case TCSHOP_DELETE:
3739 	if (UndoSize == 0) return(CC_NORM);
3740 	cp = UndoPtr;
3741 	kp = UndoBuf;
3742 	for (loop=0; loop < UndoSize; loop++)	/* copy the chars */
3743 	    *kp++ = *cp++;			/* into UndoBuf   */
3744 
3745 	for (cp = UndoPtr; cp <= LastChar; cp++)
3746 	    *cp = cp[UndoSize];
3747 
3748 	LastChar -= UndoSize;
3749 	Cursor   =  UndoPtr;
3750 
3751 	UndoAction = TCSHOP_INSERT;
3752 	break;
3753 
3754     case TCSHOP_INSERT:
3755 	if (UndoSize == 0) return(CC_NORM);
3756 	cp = UndoPtr;
3757 	Cursor = UndoPtr;
3758 	kp = UndoBuf;
3759 	c_insert(UndoSize);		/* open the space, */
3760 	for (loop = 0; loop < UndoSize; loop++)	/* copy the chars */
3761 	    *cp++ = *kp++;
3762 
3763 	UndoAction = TCSHOP_DELETE;
3764 	break;
3765 
3766     case TCSHOP_CHANGE:
3767 	if (UndoSize == 0) return(CC_NORM);
3768 	cp = UndoPtr;
3769 	Cursor = UndoPtr;
3770 	kp = UndoBuf;
3771 	size = (int)(Cursor-LastChar); /*  NOT NSL independant */
3772 	if (size < UndoSize)
3773 	    size = UndoSize;
3774 	for (loop = 0; loop < size; loop++) {
3775 	    temp = *kp;
3776 	    *kp++ = *cp;
3777 	    *cp++ = temp;
3778 	}
3779 	break;
3780 
3781     default:
3782 	return(CC_ERROR);
3783     }
3784 
3785     return(CC_REFRESH);
3786 }
3787 
3788 /*ARGSUSED*/
3789 CCRETVAL
3790 v_ush_meta(Char c)
3791 {
3792     USE(c);
3793     return v_search(F_UP_SEARCH_HIST);
3794 }
3795 
3796 /*ARGSUSED*/
3797 CCRETVAL
3798 v_dsh_meta(Char c)
3799 {
3800     USE(c);
3801     return v_search(F_DOWN_SEARCH_HIST);
3802 }
3803 
3804 /*ARGSUSED*/
3805 CCRETVAL
3806 v_rsrch_fwd(Char c)
3807 {
3808     USE(c);
3809     if (patbuf.len == 0) return(CC_ERROR);
3810     return(v_repeat_srch(searchdir));
3811 }
3812 
3813 /*ARGSUSED*/
3814 CCRETVAL
3815 v_rsrch_back(Char c)
3816 {
3817     USE(c);
3818     if (patbuf.len == 0) return(CC_ERROR);
3819     return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3820 			 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3821 }
3822 
3823 #ifndef WINNT_NATIVE
3824 /* Since ed.defns.h  is generated from ed.defns.c, these empty
3825    functions will keep the F_NUM_FNS consistent
3826  */
3827 CCRETVAL
3828 e_copy_to_clipboard(Char c)
3829 {
3830     USE(c);
3831     return CC_ERROR;
3832 }
3833 
3834 CCRETVAL
3835 e_paste_from_clipboard(Char c)
3836 {
3837     USE(c);
3838     return (CC_ERROR);
3839 }
3840 
3841 CCRETVAL
3842 e_dosify_next(Char c)
3843 {
3844     USE(c);
3845     return (CC_ERROR);
3846 }
3847 CCRETVAL
3848 e_dosify_prev(Char c)
3849 {
3850     USE(c);
3851     return (CC_ERROR);
3852 }
3853 CCRETVAL
3854 e_page_up(Char c)
3855 {
3856     USE(c);
3857     return (CC_ERROR);
3858 }
3859 CCRETVAL
3860 e_page_down(Char c)
3861 {
3862     USE(c);
3863     return (CC_ERROR);
3864 }
3865 #endif /* !WINNT_NATIVE */
3866 
3867 #ifdef notdef
3868 void
3869 MoveCursor(int n)		/* move cursor + right - left char */
3870 {
3871     Cursor = Cursor + n;
3872     if (Cursor < InputBuf)
3873 	Cursor = InputBuf;
3874     if (Cursor > LastChar)
3875 	Cursor = LastChar;
3876     return;
3877 }
3878 
3879 Char *
3880 GetCursor(void)
3881 {
3882     return(Cursor);
3883 }
3884 
3885 int
3886 PutCursor(Char *p)
3887 {
3888     if (p < InputBuf || p > LastChar)
3889 	return 1;		/* Error */
3890     Cursor = p;
3891     return 0;
3892 }
3893 #endif
3894