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