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