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