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