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