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