ed.chared.c revision 59243
1/* $Header: /src/pub/tcsh/ed.chared.c,v 3.59 1999/08/13 16:34:57 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.59 1999/08/13 16:34:57 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));
121static	void	 c_delafter		__P((int));
122static	void	 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
190static void
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
257static void
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), &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#ifndef _OSD_POSIX
1262	case '\r':	/* Newline */
1263	case '\n':
1264#else
1265	case '\012':    /* Newline */
1266	case '\015':    /* 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), &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), &hp->Hlex));
1859	}
1860	hl = HistLit ? hp->histline : sprlex(sbuf, sizeof(sbuf), &hp->Hlex);
1861#ifdef SDEBUG
1862	xprintf("Comparing with \"%S\"\n", hl);
1863#endif
1864	if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1865	     hl[LastChar-InputBuf]) && c_hmatch(hl)) {
1866	    found++;
1867	    break;
1868	}
1869	h++;
1870	hp = hp->Hnext;
1871    }
1872
1873    if (!found) {
1874#ifdef SDEBUG
1875	xprintf("not found\n");
1876#endif
1877	return(CC_ERROR);
1878    }
1879
1880    Hist_num = h;
1881
1882    return(c_get_histline());
1883}
1884
1885/*ARGSUSED*/
1886CCRETVAL
1887e_down_search_hist(c)
1888    int c;
1889{
1890    struct Hist *hp;
1891    int h;
1892    bool    found = 0;
1893
1894    USE(c);
1895    ActionFlag = TCSHOP_NOP;
1896    UndoAction = TCSHOP_NOP;
1897    *LastChar = '\0';		/* just in case */
1898
1899    if (Hist_num == 0)
1900	return(CC_ERROR);
1901
1902    hp = Histlist.Hnext;
1903    if (hp == 0)
1904	return(CC_ERROR);
1905
1906    c_hsetpat();		/* Set search pattern !! */
1907
1908    for (h = 1; h < Hist_num && hp; h++) {
1909	Char sbuf[INBUFSIZE], *hl;
1910	if (hp->histline == NULL) {
1911	    hp->histline = Strsave(sprlex(sbuf, sizeof(sbuf), &hp->Hlex));
1912	}
1913	hl = HistLit ? hp->histline : sprlex(sbuf, sizeof(sbuf), &hp->Hlex);
1914#ifdef SDEBUG
1915	xprintf("Comparing with \"%S\"\n", hl);
1916#endif
1917	if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1918	     hl[LastChar-InputBuf]) && c_hmatch(hl))
1919	    found = h;
1920	hp = hp->Hnext;
1921    }
1922
1923    if (!found) {		/* is it the current history number? */
1924	if (!c_hmatch(HistBuf)) {
1925#ifdef SDEBUG
1926	    xprintf("not found\n");
1927#endif
1928	    return(CC_ERROR);
1929	}
1930    }
1931
1932    Hist_num = found;
1933
1934    return(c_get_histline());
1935}
1936
1937/*ARGSUSED*/
1938CCRETVAL
1939e_helpme(c)
1940    int c;
1941{
1942    USE(c);
1943    PastBottom();
1944    *LastChar = '\0';		/* just in case */
1945    return(CC_HELPME);
1946}
1947
1948/*ARGSUSED*/
1949CCRETVAL
1950e_correct(c)
1951    int c;
1952{
1953    USE(c);
1954    *LastChar = '\0';		/* just in case */
1955    return(CC_CORRECT);
1956}
1957
1958/*ARGSUSED*/
1959CCRETVAL
1960e_correctl(c)
1961    int c;
1962{
1963    USE(c);
1964    *LastChar = '\0';		/* just in case */
1965    return(CC_CORRECT_L);
1966}
1967
1968/*ARGSUSED*/
1969CCRETVAL
1970e_run_fg_editor(c)
1971    int c;
1972{
1973    register struct process *pp;
1974    extern bool tellwhat;
1975
1976    USE(c);
1977    if ((pp = find_stop_ed()) != NULL) {
1978	/* save our editor state so we can restore it */
1979	tellwhat = 1;
1980	copyn(WhichBuf, InputBuf, INBUFSIZE);
1981	LastWhich = WhichBuf + (LastChar - InputBuf);
1982	CursWhich = WhichBuf + (Cursor - InputBuf);
1983	HistWhich = Hist_num;
1984	Hist_num = 0;		/* for the history commands */
1985
1986	/* put the tty in a sane mode */
1987	PastBottom();
1988	(void) Cookedmode();	/* make sure the tty is set up correctly */
1989
1990	/* do it! */
1991	fg_proc_entry(pp);
1992
1993	(void) Rawmode();	/* go on */
1994	Refresh();
1995	tellwhat = 0;
1996    }
1997    return(CC_NORM);
1998}
1999
2000/*ARGSUSED*/
2001CCRETVAL
2002e_list_choices(c)
2003    int c;
2004{
2005    USE(c);
2006    PastBottom();
2007    *LastChar = '\0';		/* just in case */
2008    return(CC_LIST_CHOICES);
2009}
2010
2011/*ARGSUSED*/
2012CCRETVAL
2013e_list_all(c)
2014    int c;
2015{
2016    USE(c);
2017    PastBottom();
2018    *LastChar = '\0';		/* just in case */
2019    return(CC_LIST_ALL);
2020}
2021
2022/*ARGSUSED*/
2023CCRETVAL
2024e_list_glob(c)
2025    int c;
2026{
2027    USE(c);
2028    PastBottom();
2029    *LastChar = '\0';		/* just in case */
2030    return(CC_LIST_GLOB);
2031}
2032
2033/*ARGSUSED*/
2034CCRETVAL
2035e_expand_glob(c)
2036    int c;
2037{
2038    USE(c);
2039    *LastChar = '\0';		/* just in case */
2040    return(CC_EXPAND_GLOB);
2041}
2042
2043/*ARGSUSED*/
2044CCRETVAL
2045e_normalize_path(c)
2046    int c;
2047{
2048    USE(c);
2049    *LastChar = '\0';		/* just in case */
2050    return(CC_NORMALIZE_PATH);
2051}
2052
2053/*ARGSUSED*/
2054CCRETVAL
2055e_normalize_command(c)
2056    int c;
2057{
2058    USE(c);
2059    *LastChar = '\0';		/* just in case */
2060    return(CC_NORMALIZE_COMMAND);
2061}
2062
2063/*ARGSUSED*/
2064CCRETVAL
2065e_expand_vars(c)
2066    int c;
2067{
2068    USE(c);
2069    *LastChar = '\0';		/* just in case */
2070    return(CC_EXPAND_VARS);
2071}
2072
2073/*ARGSUSED*/
2074CCRETVAL
2075e_which(c)
2076    int c;
2077{				/* do a fast command line which(1) */
2078    USE(c);
2079    PastBottom();
2080    *LastChar = '\0';		/* just in case */
2081    return(CC_WHICH);
2082}
2083
2084/*ARGSUSED*/
2085CCRETVAL
2086e_last_item(c)
2087    int c;
2088{				/* insert the last element of the prev. cmd */
2089    register Char *cp;
2090    register struct Hist *hp;
2091    register struct wordent *wp, *firstp;
2092    register int i;
2093    Char buf[INBUFSIZE];
2094
2095    USE(c);
2096    if (Argument <= 0)
2097	return(CC_ERROR);
2098
2099    hp = Histlist.Hnext;
2100    if (hp == NULL) {	/* this is only if no history */
2101	return(CC_ERROR);
2102    }
2103
2104    wp = (hp->Hlex).prev;
2105
2106    if (wp->prev == (struct wordent *) NULL)
2107	return(CC_ERROR);	/* an empty history entry */
2108
2109    firstp = (hp->Hlex).next;
2110
2111    /* back up arg words in lex */
2112    for (i = 0; i < Argument && wp != firstp; i++) {
2113	wp = wp->prev;
2114    }
2115
2116    cp = expand_lex(buf, INBUFSIZE, wp->prev, 0, i - 1);
2117    *cp = '\0';
2118    if (InsertStr(buf))
2119	return(CC_ERROR);
2120
2121    return(CC_REFRESH);
2122}
2123
2124/*ARGSUSED*/
2125CCRETVAL
2126e_dabbrev_expand(c)
2127    int c;
2128{				/* expand to preceding word matching prefix */
2129    register Char *cp, *ncp, *bp;
2130    register struct Hist *hp;
2131    register int arg = 0, len = 0, i; /* len = 0 to shut up gcc -Wall */
2132    register bool found = 0;
2133    Char hbuf[INBUFSIZE];
2134    static int oldevent, hist, word;
2135    static Char *start, *oldcursor;
2136
2137    USE(c);
2138    if (Argument <= 0)
2139	return(CC_ERROR);
2140
2141    cp = c_preword(Cursor, InputBuf, 1);
2142    if (cp == Cursor || Isspace(*cp))
2143	return(CC_ERROR);
2144
2145    hp = Histlist.Hnext;
2146    bp = InputBuf;
2147    if (Argument == 1 && eventno == oldevent && cp == start &&
2148	Cursor == oldcursor && patlen > 0 && Strncmp(patbuf, cp, patlen) == 0){
2149	/* continue previous search - go to last match (hist/word) */
2150	if (hist != 0) {		/* need to move up history */
2151	    for (i = 1; i < hist && hp != NULL; i++)
2152		hp = hp->Hnext;
2153	    if (hp == NULL)	/* "can't happen" */
2154		return(CC_ERROR);
2155	    cp = expand_lex(hbuf, INBUFSIZE, &hp->Hlex, 0, NCARGS);
2156	    *cp = '\0';
2157	    bp = hbuf;
2158	    hp = hp->Hnext;
2159	}
2160	cp = c_preword(cp, bp, word);
2161    } else {			/* starting new search */
2162	oldevent = eventno;
2163	start = cp;
2164	patlen = (int) (Cursor - cp);
2165	(void) Strncpy(patbuf, cp, patlen);
2166	hist = 0;
2167	word = 0;
2168    }
2169
2170    while (!found) {
2171	ncp = c_preword(cp, bp, 1);
2172	if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2173	    hist++;
2174	    word = 0;
2175	    if (hp == NULL)
2176		return(CC_ERROR);
2177	    cp = expand_lex(hbuf, INBUFSIZE, &hp->Hlex, 0, NCARGS);
2178	    *cp = '\0';
2179	    bp = hbuf;
2180	    hp = hp->Hnext;
2181	    continue;
2182	} else {
2183	    word++;
2184	    len = (int) (c_endword(ncp-1, cp, 1) - ncp + 1);
2185	    cp = ncp;
2186	}
2187	if (len > patlen && Strncmp(cp, patbuf, patlen) == 0) {
2188	    /* We don't fully check distinct matches as Gnuemacs does: */
2189	    if (Argument > 1) {	/* just count matches */
2190		if (++arg >= Argument)
2191		    found++;
2192	    } else {		/* match if distinct from previous */
2193		if (len != Cursor - start || Strncmp(cp, start, len) != 0)
2194		    found++;
2195	    }
2196	}
2197    }
2198
2199    if (LastChar + len - (Cursor - start) >= InputLim)
2200	return(CC_ERROR);	/* no room */
2201    DeleteBack(Cursor - start);
2202    c_insert(len);
2203    while (len--)
2204	*Cursor++ = *cp++;
2205    oldcursor = Cursor;
2206    return(CC_REFRESH);
2207}
2208
2209/*ARGSUSED*/
2210CCRETVAL
2211e_yank_kill(c)
2212    int c;
2213{				/* almost like GnuEmacs */
2214    register Char *kp, *cp;
2215
2216    USE(c);
2217    if (LastKill == KillBuf)	/* if zero content */
2218	return(CC_ERROR);
2219
2220    if (LastChar + (LastKill - KillBuf) >= InputLim)
2221	return(CC_ERROR);	/* end of buffer space */
2222
2223    /* else */
2224    Mark = Cursor;		/* set the mark */
2225    cp = Cursor;		/* for speed */
2226
2227    c_insert((int)(LastKill - KillBuf));	/* open the space, */
2228    for (kp = KillBuf; kp < LastKill; kp++)	/* copy the chars */
2229	*cp++ = *kp;
2230
2231    if (Argument == 1)		/* if an arg, cursor at beginning */
2232	Cursor = cp;		/* else cursor at end */
2233
2234    return(CC_REFRESH);
2235}
2236
2237/*ARGSUSED*/
2238CCRETVAL
2239v_delprev(c) 		/* Backspace key in insert mode */
2240    int c;
2241{
2242    int rc;
2243
2244    USE(c);
2245    rc = CC_ERROR;
2246
2247    if (InsertPos != 0) {
2248	if (Argument <= Cursor - InsertPos) {
2249	    c_delbefore(Argument);	/* delete before */
2250	    Cursor -= Argument;
2251#if defined(DSPMBYTE)
2252	if (_enable_mbdisp && extdel) {
2253	    Cursor--;
2254	    e_redisp(c);
2255	}
2256#endif
2257	    rc = CC_REFRESH;
2258	}
2259    }
2260    return(rc);
2261}   /* v_delprev  */
2262
2263/*ARGSUSED*/
2264CCRETVAL
2265e_delprev(c)
2266    int c;
2267{
2268    USE(c);
2269    if (Cursor > InputBuf) {
2270	c_delbefore(Argument);	/* delete before dot */
2271	if (Argument > Cursor - InputBuf)
2272	    Cursor = InputBuf;	/* bounds check */
2273	else
2274	    Cursor -= Argument;
2275#if defined(DSPMBYTE)
2276	if (_enable_mbdisp && extdel && Cursor > InputBuf) {
2277	    Cursor--;
2278	    e_redisp(c);
2279	}
2280#endif
2281	return(CC_REFRESH);
2282    }
2283    else {
2284	return(CC_ERROR);
2285    }
2286}
2287
2288/*ARGSUSED*/
2289CCRETVAL
2290e_delwordprev(c)
2291    int c;
2292{
2293    register Char *cp, *p, *kp;
2294
2295    USE(c);
2296    if (Cursor == InputBuf)
2297	return(CC_ERROR);
2298    /* else */
2299
2300    cp = c_prev_word(Cursor, InputBuf, Argument);
2301
2302    for (p = cp, kp = KillBuf; p < Cursor; p++)	/* save the text */
2303	*kp++ = *p;
2304    LastKill = kp;
2305
2306    c_delbefore((int)(Cursor - cp));	/* delete before dot */
2307    Cursor = cp;
2308    if (Cursor < InputBuf)
2309	Cursor = InputBuf;	/* bounds check */
2310    return(CC_REFRESH);
2311}
2312
2313/* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2314 *
2315 * Changed the names of some of the ^D family of editor functions to
2316 * correspond to what they actually do and created new e_delnext_list
2317 * for completeness.
2318 *
2319 *   Old names:			New names:
2320 *
2321 *   delete-char		delete-char-or-eof
2322 *     F_DELNEXT		  F_DELNEXT_EOF
2323 *     e_delnext		  e_delnext_eof
2324 *     edelnxt			  edelnxteof
2325 *   delete-char-or-eof		delete-char
2326 *     F_DELNEXT_EOF		  F_DELNEXT
2327 *     e_delnext_eof		  e_delnext
2328 *     edelnxteof		  edelnxt
2329 *   delete-char-or-list	delete-char-or-list-or-eof
2330 *     F_LIST_DELNEXT		  F_DELNEXT_LIST_EOF
2331 *     e_list_delnext		  e_delnext_list_eof
2332 *   				  edellsteof
2333 *   (no old equivalent)	delete-char-or-list
2334 *   				  F_DELNEXT_LIST
2335 *   				  e_delnext_list
2336 *   				  e_delnxtlst
2337 */
2338
2339/* added by mtk@ari.ncl.omron.co.jp (920818) */
2340/* rename e_delnext() -> e_delnext_eof() */
2341/*ARGSUSED*/
2342CCRETVAL
2343e_delnext(c)
2344    int c;
2345{
2346    USE(c);
2347    if (Cursor == LastChar) {/* if I'm at the end */
2348	if (!VImode) {
2349		return(CC_ERROR);
2350	}
2351	else {
2352	    if (Cursor != InputBuf)
2353		Cursor--;
2354	    else
2355		return(CC_ERROR);
2356	}
2357    }
2358    c_delafter(Argument);	/* delete after dot */
2359    if (Cursor > LastChar)
2360	Cursor = LastChar;	/* bounds check */
2361    return(CC_REFRESH);
2362}
2363
2364
2365/*ARGSUSED*/
2366CCRETVAL
2367e_delnext_eof(c)
2368    int c;
2369{
2370    USE(c);
2371    if (Cursor == LastChar) {/* if I'm at the end */
2372	if (!VImode) {
2373	    if (Cursor == InputBuf) {
2374		/* if I'm also at the beginning */
2375		so_write(STReof, 4);/* then do a EOF */
2376		flush();
2377		return(CC_EOF);
2378	    }
2379	    else
2380		return(CC_ERROR);
2381	}
2382	else {
2383	    if (Cursor != InputBuf)
2384		Cursor--;
2385	    else
2386		return(CC_ERROR);
2387	}
2388    }
2389    c_delafter(Argument);	/* delete after dot */
2390    if (Cursor > LastChar)
2391	Cursor = LastChar;	/* bounds check */
2392    return(CC_REFRESH);
2393}
2394
2395/*ARGSUSED*/
2396CCRETVAL
2397e_delnext_list(c)
2398    int c;
2399{
2400    USE(c);
2401    if (Cursor == LastChar) {	/* if I'm at the end */
2402	PastBottom();
2403	*LastChar = '\0';	/* just in case */
2404	return(CC_LIST_CHOICES);
2405    }
2406    else {
2407	c_delafter(Argument);	/* delete after dot */
2408	if (Cursor > LastChar)
2409	    Cursor = LastChar;	/* bounds check */
2410	return(CC_REFRESH);
2411    }
2412}
2413
2414/*ARGSUSED*/
2415CCRETVAL
2416e_delnext_list_eof(c)
2417    int c;
2418{
2419    USE(c);
2420    if (Cursor == LastChar) {	/* if I'm at the end */
2421	if (Cursor == InputBuf) {	/* if I'm also at the beginning */
2422	    so_write(STReof, 4);/* then do a EOF */
2423	    flush();
2424	    return(CC_EOF);
2425	}
2426	else {
2427	    PastBottom();
2428	    *LastChar = '\0';	/* just in case */
2429	    return(CC_LIST_CHOICES);
2430	}
2431    }
2432    else {
2433	c_delafter(Argument);	/* delete after dot */
2434	if (Cursor > LastChar)
2435	    Cursor = LastChar;	/* bounds check */
2436	return(CC_REFRESH);
2437    }
2438}
2439
2440/*ARGSUSED*/
2441CCRETVAL
2442e_list_eof(c)
2443    int c;
2444{
2445    CCRETVAL rv;
2446
2447    USE(c);
2448    if (Cursor == LastChar && Cursor == InputBuf) {
2449	so_write(STReof, 4);	/* then do a EOF */
2450	flush();
2451	rv = CC_EOF;
2452    }
2453    else {
2454	PastBottom();
2455	*LastChar = '\0';	/* just in case */
2456	rv = CC_LIST_CHOICES;
2457    }
2458    return rv;
2459}
2460
2461/*ARGSUSED*/
2462CCRETVAL
2463e_delwordnext(c)
2464    int c;
2465{
2466    register Char *cp, *p, *kp;
2467
2468    USE(c);
2469    if (Cursor == LastChar)
2470	return(CC_ERROR);
2471    /* else */
2472
2473    cp = c_next_word(Cursor, LastChar, Argument);
2474
2475    for (p = Cursor, kp = KillBuf; p < cp; p++)	/* save the text */
2476	*kp++ = *p;
2477    LastKill = kp;
2478
2479    c_delafter((int)(cp - Cursor));	/* delete after dot */
2480    if (Cursor > LastChar)
2481	Cursor = LastChar;	/* bounds check */
2482    return(CC_REFRESH);
2483}
2484
2485/*ARGSUSED*/
2486CCRETVAL
2487e_toend(c)
2488    int c;
2489{
2490    USE(c);
2491    Cursor = LastChar;
2492    if (VImode)
2493	if (ActionFlag & TCSHOP_DELETE) {
2494	    c_delfini();
2495	    return(CC_REFRESH);
2496	}
2497    RefCursor();		/* move the cursor */
2498    return(CC_NORM);
2499}
2500
2501/*ARGSUSED*/
2502CCRETVAL
2503e_tobeg(c)
2504    int c;
2505{
2506    USE(c);
2507    Cursor = InputBuf;
2508
2509    if (VImode) {
2510       while (Isspace(*Cursor)) /* We want FIRST non space character */
2511	Cursor++;
2512	if (ActionFlag & TCSHOP_DELETE) {
2513	    c_delfini();
2514	    return(CC_REFRESH);
2515	}
2516    }
2517
2518    RefCursor();		/* move the cursor */
2519    return(CC_NORM);
2520}
2521
2522/*ARGSUSED*/
2523CCRETVAL
2524e_killend(c)
2525    int c;
2526{
2527    register Char *kp, *cp;
2528
2529    USE(c);
2530    cp = Cursor;
2531    kp = KillBuf;
2532    while (cp < LastChar)
2533	*kp++ = *cp++;		/* copy it */
2534    LastKill = kp;
2535    LastChar = Cursor;		/* zap! -- delete to end */
2536    return(CC_REFRESH);
2537}
2538
2539
2540/*ARGSUSED*/
2541CCRETVAL
2542e_killbeg(c)
2543    int c;
2544{
2545    register Char *kp, *cp;
2546
2547    USE(c);
2548    cp = InputBuf;
2549    kp = KillBuf;
2550    while (cp < Cursor)
2551	*kp++ = *cp++;		/* copy it */
2552    LastKill = kp;
2553    c_delbefore((int)(Cursor - InputBuf));
2554    Cursor = InputBuf;		/* zap! */
2555    return(CC_REFRESH);
2556}
2557
2558/*ARGSUSED*/
2559CCRETVAL
2560e_killall(c)
2561    int c;
2562{
2563    register Char *kp, *cp;
2564
2565    USE(c);
2566    cp = InputBuf;
2567    kp = KillBuf;
2568    while (cp < LastChar)
2569	*kp++ = *cp++;		/* copy it */
2570    LastKill = kp;
2571    LastChar = InputBuf;	/* zap! -- delete all of it */
2572    Cursor = InputBuf;
2573    return(CC_REFRESH);
2574}
2575
2576/*ARGSUSED*/
2577CCRETVAL
2578e_killregion(c)
2579    int c;
2580{
2581    register Char *kp, *cp;
2582
2583    USE(c);
2584    if (!Mark)
2585	return(CC_ERROR);
2586
2587    if (Mark > Cursor) {
2588	cp = Cursor;
2589	kp = KillBuf;
2590	while (cp < Mark)
2591	    *kp++ = *cp++;	/* copy it */
2592	LastKill = kp;
2593	c_delafter((int)(cp - Cursor));	/* delete it - UNUSED BY VI mode */
2594    }
2595    else {			/* mark is before cursor */
2596	cp = Mark;
2597	kp = KillBuf;
2598	while (cp < Cursor)
2599	    *kp++ = *cp++;	/* copy it */
2600	LastKill = kp;
2601	c_delbefore((int)(cp - Mark));
2602	Cursor = Mark;
2603    }
2604    return(CC_REFRESH);
2605}
2606
2607/*ARGSUSED*/
2608CCRETVAL
2609e_copyregion(c)
2610    int c;
2611{
2612    register Char *kp, *cp;
2613
2614    USE(c);
2615    if (!Mark)
2616	return(CC_ERROR);
2617
2618    if (Mark > Cursor) {
2619	cp = Cursor;
2620	kp = KillBuf;
2621	while (cp < Mark)
2622	    *kp++ = *cp++;	/* copy it */
2623	LastKill = kp;
2624    }
2625    else {			/* mark is before cursor */
2626	cp = Mark;
2627	kp = KillBuf;
2628	while (cp < Cursor)
2629	    *kp++ = *cp++;	/* copy it */
2630	LastKill = kp;
2631    }
2632    return(CC_NORM);		/* don't even need to Refresh() */
2633}
2634
2635/*ARGSUSED*/
2636CCRETVAL
2637e_charswitch(cc)
2638    int cc;
2639{
2640    register Char c;
2641
2642    USE(cc);
2643
2644    /* do nothing if we are at beginning of line or have only one char */
2645    if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2646	return(CC_ERROR);
2647    }
2648
2649    if (Cursor < LastChar) {
2650	Cursor++;
2651    }
2652    c = Cursor[-2];
2653    Cursor[-2] = Cursor[-1];
2654    Cursor[-1] = c;
2655    return(CC_REFRESH);
2656}
2657
2658/*ARGSUSED*/
2659CCRETVAL
2660e_gcharswitch(cc)
2661    int cc;
2662{				/* gosmacs style ^T */
2663    register Char c;
2664
2665    USE(cc);
2666    if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2667	c = Cursor[-2];
2668	Cursor[-2] = Cursor[-1];
2669	Cursor[-1] = c;
2670	return(CC_REFRESH);
2671    }
2672    else {
2673	return(CC_ERROR);
2674    }
2675}
2676
2677#if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2678/*ARGSUSED*/
2679static void
2680e_charback_mbyte(argument)
2681     int argument;
2682{
2683    if (!_enable_mbdisp) {
2684	if (Argument > Cursor - InputBuf)
2685	    Cursor = InputBuf;
2686	else
2687	    Cursor -= Argument;
2688    }
2689    else {
2690	while (0 < argument && Cursor > InputBuf) {
2691	    if (Cursor - 1 != InputBuf &&
2692		Ismbyte1(*(Cursor - 2)) && Ismbyte2(*(Cursor - 1))) {
2693		Cursor--;
2694	    }
2695	    Cursor--;
2696	    argument--;
2697	}
2698    }
2699}
2700#endif
2701
2702/*ARGSUSED*/
2703CCRETVAL
2704e_charback(c)
2705    int c;
2706{
2707    USE(c);
2708    if (Cursor > InputBuf) {
2709#if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2710	e_charback_mbyte(Argument);
2711#else
2712	if (Argument > Cursor - InputBuf)
2713	    Cursor = InputBuf;
2714	else
2715	    Cursor -= Argument;
2716#endif
2717
2718	if (VImode)
2719	    if (ActionFlag & TCSHOP_DELETE) {
2720		c_delfini();
2721		return(CC_REFRESH);
2722	    }
2723
2724	RefCursor();
2725	return(CC_NORM);
2726    }
2727    else {
2728	return(CC_ERROR);
2729    }
2730}
2731
2732/*ARGSUSED*/
2733CCRETVAL
2734v_wordback(c)
2735    int c;
2736{
2737    USE(c);
2738    if (Cursor == InputBuf)
2739	return(CC_ERROR);
2740    /* else */
2741
2742    Cursor = c_preword(Cursor, InputBuf, Argument); /* bounds check */
2743
2744    if (ActionFlag & TCSHOP_DELETE) {
2745	c_delfini();
2746	return(CC_REFRESH);
2747    }
2748
2749    RefCursor();
2750    return(CC_NORM);
2751}
2752
2753/*ARGSUSED*/
2754CCRETVAL
2755e_wordback(c)
2756    int c;
2757{
2758    USE(c);
2759    if (Cursor == InputBuf)
2760	return(CC_ERROR);
2761    /* else */
2762
2763    Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2764
2765    if (VImode)
2766	if (ActionFlag & TCSHOP_DELETE) {
2767	    c_delfini();
2768	    return(CC_REFRESH);
2769	}
2770
2771    RefCursor();
2772    return(CC_NORM);
2773}
2774
2775#if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2776/*ARGSUSED*/
2777static void
2778e_charfwd_mbyte(argument)
2779     int argument;
2780{
2781    if (!_enable_mbdisp)
2782	Cursor += argument;
2783    else
2784	while (0 < argument && Cursor < LastChar) {
2785	    if (Cursor + 1 != LastChar &&
2786		Ismbyte1(*Cursor) && Ismbyte2(*(Cursor + 1))) {
2787		Cursor++;
2788	    }
2789	    Cursor++;
2790	    argument--;
2791	}
2792}
2793#endif
2794
2795/*ARGSUSED*/
2796CCRETVAL
2797e_charfwd(c)
2798    int c;
2799{
2800    USE(c);
2801    if (Cursor < LastChar) {
2802#if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2803	e_charfwd_mbyte(Argument);
2804#else
2805	Cursor += Argument;
2806#endif
2807	if (Cursor > LastChar)
2808	    Cursor = LastChar;
2809
2810	if (VImode)
2811	    if (ActionFlag & TCSHOP_DELETE) {
2812		c_delfini();
2813		return(CC_REFRESH);
2814	    }
2815
2816	RefCursor();
2817	return(CC_NORM);
2818    }
2819    else {
2820	return(CC_ERROR);
2821    }
2822}
2823
2824/*ARGSUSED*/
2825CCRETVAL
2826e_wordfwd(c)
2827    int c;
2828{
2829    USE(c);
2830    if (Cursor == LastChar)
2831	return(CC_ERROR);
2832    /* else */
2833
2834    Cursor = c_next_word(Cursor, LastChar, Argument);
2835
2836    if (VImode)
2837	if (ActionFlag & TCSHOP_DELETE) {
2838	    c_delfini();
2839	    return(CC_REFRESH);
2840	}
2841
2842    RefCursor();
2843    return(CC_NORM);
2844}
2845
2846/*ARGSUSED*/
2847CCRETVAL
2848v_wordfwd(c)
2849    int c;
2850{
2851    USE(c);
2852    if (Cursor == LastChar)
2853	return(CC_ERROR);
2854    /* else */
2855
2856    Cursor = c_nexword(Cursor, LastChar, Argument);
2857
2858    if (VImode)
2859	if (ActionFlag & TCSHOP_DELETE) {
2860	    c_delfini();
2861	    return(CC_REFRESH);
2862	}
2863
2864    RefCursor();
2865    return(CC_NORM);
2866}
2867
2868/*ARGSUSED*/
2869CCRETVAL
2870v_wordbegnext(c)
2871    int c;
2872{
2873    USE(c);
2874    if (Cursor == LastChar)
2875	return(CC_ERROR);
2876    /* else */
2877
2878    Cursor = c_next_word(Cursor, LastChar, Argument);
2879    if (Cursor < LastChar)
2880	Cursor++;
2881
2882    if (VImode)
2883	if (ActionFlag & TCSHOP_DELETE) {
2884	    c_delfini();
2885	    return(CC_REFRESH);
2886	}
2887
2888    RefCursor();
2889    return(CC_NORM);
2890}
2891
2892/*ARGSUSED*/
2893static CCRETVAL
2894v_repeat_srch(c)
2895    int c;
2896{
2897    CCRETVAL rv = CC_ERROR;
2898#ifdef SDEBUG
2899    xprintf("dir %d patlen %d patbuf %S\n",
2900	    c, patlen, patbuf);
2901#endif
2902
2903    LastCmd = (KEYCMD) c;  /* Hack to stop c_hsetpat */
2904    LastChar = InputBuf;
2905    switch (c) {
2906    case F_DOWN_SEARCH_HIST:
2907	rv = e_down_search_hist(0);
2908	break;
2909    case F_UP_SEARCH_HIST:
2910	rv = e_up_search_hist(0);
2911	break;
2912    default:
2913	break;
2914    }
2915    return rv;
2916}
2917
2918static CCRETVAL
2919v_csearch_back(ch, count, tflag)
2920    int ch, count, tflag;
2921{
2922    Char *cp;
2923
2924    cp = Cursor;
2925    while (count--) {
2926	if (*cp == ch)
2927	    cp--;
2928	while (cp > InputBuf && *cp != ch)
2929	    cp--;
2930    }
2931
2932    if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2933	return(CC_ERROR);
2934
2935    if (*cp == ch && tflag)
2936	cp++;
2937
2938    Cursor = cp;
2939
2940    if (ActionFlag & TCSHOP_DELETE) {
2941	Cursor++;
2942	c_delfini();
2943	return(CC_REFRESH);
2944    }
2945
2946    RefCursor();
2947    return(CC_NORM);
2948}
2949
2950static CCRETVAL
2951v_csearch_fwd(ch, count, tflag)
2952    int ch, count, tflag;
2953{
2954    Char *cp;
2955
2956    cp = Cursor;
2957    while (count--) {
2958	if(*cp == ch)
2959	    cp++;
2960	while (cp < LastChar && *cp != ch)
2961	    cp++;
2962    }
2963
2964    if (cp >= LastChar)
2965	return(CC_ERROR);
2966
2967    if (*cp == ch && tflag)
2968	cp--;
2969
2970    Cursor = cp;
2971
2972    if (ActionFlag & TCSHOP_DELETE) {
2973	Cursor++;
2974	c_delfini();
2975	return(CC_REFRESH);
2976    }
2977    RefCursor();
2978    return(CC_NORM);
2979}
2980
2981/*ARGSUSED*/
2982static CCRETVAL
2983v_action(c)
2984    int c;
2985{
2986    register Char *cp, *kp;
2987
2988    if (ActionFlag == TCSHOP_DELETE) {
2989	ActionFlag = TCSHOP_NOP;
2990	ActionPos = 0;
2991
2992	UndoSize = 0;
2993	kp = UndoBuf;
2994	for (cp = InputBuf; cp < LastChar; cp++) {
2995	    *kp++ = *cp;
2996	    UndoSize++;
2997	}
2998
2999	UndoAction = TCSHOP_INSERT;
3000	UndoPtr  = InputBuf;
3001	LastChar = InputBuf;
3002	Cursor   = InputBuf;
3003	if (c & TCSHOP_INSERT)
3004	    c_alternativ_key_map(0);
3005
3006	return(CC_REFRESH);
3007    }
3008#ifdef notdef
3009    else if (ActionFlag == TCSHOP_NOP) {
3010#endif
3011	ActionPos = Cursor;
3012	ActionFlag = c;
3013	return(CC_ARGHACK);  /* Do NOT clear out argument */
3014#ifdef notdef
3015    }
3016    else {
3017	ActionFlag = 0;
3018	ActionPos = 0;
3019	return(CC_ERROR);
3020    }
3021#endif
3022}
3023
3024#ifdef COMMENT
3025/* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
3026static void
3027c_get_word(begin, end)
3028    Char  **begin;
3029    Char  **end;
3030{
3031    Char   *cp;
3032
3033    cp = &Cursor[0];
3034    while (Argument--) {
3035	while ((cp <= LastChar) && (isword(*cp)))
3036	    cp++;
3037	*end = --cp;
3038	while ((cp >= InputBuf) && (isword(*cp)))
3039	    cp--;
3040	*begin = ++cp;
3041    }
3042}
3043#endif /* COMMENT */
3044
3045/*ARGSUSED*/
3046CCRETVAL
3047e_uppercase(c)
3048    int c;
3049{
3050    Char   *cp, *end;
3051
3052    USE(c);
3053    end = c_next_word(Cursor, LastChar, Argument);
3054
3055    for (cp = Cursor; cp < end; cp++)	/* PWP: was cp=begin */
3056	if (Islower(*cp))
3057	    *cp = Toupper(*cp);
3058
3059    Cursor = end;
3060    if (Cursor > LastChar)
3061	Cursor = LastChar;
3062    return(CC_REFRESH);
3063}
3064
3065
3066/*ARGSUSED*/
3067CCRETVAL
3068e_capitolcase(c)
3069    int c;
3070{
3071    Char   *cp, *end;
3072
3073    USE(c);
3074    end = c_next_word(Cursor, LastChar, Argument);
3075
3076    cp = Cursor;
3077    for (; cp < end; cp++) {
3078	if (Isalpha(*cp)) {
3079	    if (Islower(*cp))
3080		*cp = Toupper(*cp);
3081	    cp++;
3082	    break;
3083	}
3084    }
3085    for (; cp < end; cp++)
3086	if (Isupper(*cp))
3087	    *cp = Tolower(*cp);
3088
3089    Cursor = end;
3090    if (Cursor > LastChar)
3091	Cursor = LastChar;
3092    return(CC_REFRESH);
3093}
3094
3095/*ARGSUSED*/
3096CCRETVAL
3097e_lowercase(c)
3098    int c;
3099{
3100    Char   *cp, *end;
3101
3102    USE(c);
3103    end = c_next_word(Cursor, LastChar, Argument);
3104
3105    for (cp = Cursor; cp < end; cp++)
3106	if (Isupper(*cp))
3107	    *cp = Tolower(*cp);
3108
3109    Cursor = end;
3110    if (Cursor > LastChar)
3111	Cursor = LastChar;
3112    return(CC_REFRESH);
3113}
3114
3115
3116/*ARGSUSED*/
3117CCRETVAL
3118e_set_mark(c)
3119    int c;
3120{
3121    USE(c);
3122    Mark = Cursor;
3123    return(CC_NORM);
3124}
3125
3126/*ARGSUSED*/
3127CCRETVAL
3128e_exchange_mark(c)
3129    int c;
3130{
3131    register Char *cp;
3132
3133    USE(c);
3134    cp = Cursor;
3135    Cursor = Mark;
3136    Mark = cp;
3137    RefCursor();
3138    return(CC_NORM);
3139}
3140
3141/*ARGSUSED*/
3142CCRETVAL
3143e_argfour(c)
3144    int c;
3145{				/* multiply current argument by 4 */
3146    USE(c);
3147    if (Argument > 1000000)
3148	return CC_ERROR;
3149    DoingArg = 1;
3150    Argument *= 4;
3151    return(CC_ARGHACK);
3152}
3153
3154/*ARGSUSED*/
3155CCRETVAL
3156e_quote(c)
3157    int c;
3158{
3159    Char    ch;
3160    int     num;
3161
3162    USE(c);
3163    QuoteModeOn();
3164    num = GetNextChar(&ch);
3165    QuoteModeOff();
3166    if (num == 1)
3167	return e_insert(ch);
3168    else
3169	return e_send_eof(0);
3170}
3171
3172/*ARGSUSED*/
3173CCRETVAL
3174e_metanext(c)
3175    int c;
3176{
3177    USE(c);
3178    MetaNext = 1;
3179    return(CC_ARGHACK);	/* preserve argument */
3180}
3181
3182#ifdef notdef
3183/*ARGSUSED*/
3184CCRETVAL
3185e_extendnext(c)
3186    int c;
3187{
3188    CurrentKeyMap = CcAltMap;
3189    return(CC_ARGHACK);	/* preserve argument */
3190}
3191
3192#endif
3193
3194/*ARGSUSED*/
3195CCRETVAL
3196v_insbeg(c)
3197    int c;
3198{				/* move to beginning of line and start vi
3199				 * insert mode */
3200    USE(c);
3201    Cursor = InputBuf;
3202    InsertPos = Cursor;
3203
3204    UndoPtr  = Cursor;
3205    UndoAction = TCSHOP_DELETE;
3206
3207    RefCursor();		/* move the cursor */
3208    c_alternativ_key_map(0);
3209    return(CC_NORM);
3210}
3211
3212/*ARGSUSED*/
3213CCRETVAL
3214v_replone(c)
3215    int c;
3216{				/* vi mode overwrite one character */
3217    USE(c);
3218    c_alternativ_key_map(0);
3219    inputmode = MODE_REPLACE_1;
3220    UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
3221    UndoPtr = Cursor;
3222    UndoSize = 0;
3223    return(CC_NORM);
3224}
3225
3226/*ARGSUSED*/
3227CCRETVAL
3228v_replmode(c)
3229    int c;
3230{				/* vi mode start overwriting */
3231    USE(c);
3232    c_alternativ_key_map(0);
3233    inputmode = MODE_REPLACE;
3234    UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
3235    UndoPtr = Cursor;
3236    UndoSize = 0;
3237    return(CC_NORM);
3238}
3239
3240/*ARGSUSED*/
3241CCRETVAL
3242v_substchar(c)
3243    int c;
3244{				/* vi mode substitute for one char */
3245    USE(c);
3246    c_delafter(Argument);
3247    c_alternativ_key_map(0);
3248    return(CC_REFRESH);
3249}
3250
3251/*ARGSUSED*/
3252CCRETVAL
3253v_substline(c)
3254    int c;
3255{				/* vi mode replace whole line */
3256    USE(c);
3257    (void) e_killall(0);
3258    c_alternativ_key_map(0);
3259    return(CC_REFRESH);
3260}
3261
3262/*ARGSUSED*/
3263CCRETVAL
3264v_chgtoend(c)
3265    int c;
3266{				/* vi mode change to end of line */
3267    USE(c);
3268    (void) e_killend(0);
3269    c_alternativ_key_map(0);
3270    return(CC_REFRESH);
3271}
3272
3273/*ARGSUSED*/
3274CCRETVAL
3275v_insert(c)
3276    int c;
3277{				/* vi mode start inserting */
3278    USE(c);
3279    c_alternativ_key_map(0);
3280
3281    InsertPos = Cursor;
3282    UndoPtr = Cursor;
3283    UndoAction = TCSHOP_DELETE;
3284
3285    return(CC_NORM);
3286}
3287
3288/*ARGSUSED*/
3289CCRETVAL
3290v_add(c)
3291    int c;
3292{				/* vi mode start adding */
3293    USE(c);
3294    c_alternativ_key_map(0);
3295    if (Cursor < LastChar)
3296    {
3297	Cursor++;
3298	if (Cursor > LastChar)
3299	    Cursor = LastChar;
3300	RefCursor();
3301    }
3302
3303    InsertPos = Cursor;
3304    UndoPtr = Cursor;
3305    UndoAction = TCSHOP_DELETE;
3306
3307    return(CC_NORM);
3308}
3309
3310/*ARGSUSED*/
3311CCRETVAL
3312v_addend(c)
3313    int c;
3314{				/* vi mode to add at end of line */
3315    USE(c);
3316    c_alternativ_key_map(0);
3317    Cursor = LastChar;
3318
3319    InsertPos = LastChar;	/* Mark where insertion begins */
3320    UndoPtr = LastChar;
3321    UndoAction = TCSHOP_DELETE;
3322
3323    RefCursor();
3324    return(CC_NORM);
3325}
3326
3327/*ARGSUSED*/
3328CCRETVAL
3329v_change_case(cc)
3330    int cc;
3331{
3332    char    c;
3333
3334    USE(cc);
3335    if (Cursor < LastChar) {
3336#ifndef WINNT
3337	c = *Cursor;
3338#else
3339	c = CHAR & *Cursor;
3340#endif /* WINNT */
3341	if (Isupper(c))
3342	    *Cursor++ = Tolower(c);
3343	else if (Islower(c))
3344	    *Cursor++ = Toupper(c);
3345	else
3346	    Cursor++;
3347	RefPlusOne();		/* fast refresh for one char */
3348	return(CC_NORM);
3349    }
3350    return(CC_ERROR);
3351}
3352
3353/*ARGSUSED*/
3354CCRETVAL
3355e_expand(c)
3356    int c;
3357{
3358    register Char *p;
3359    extern bool justpr;
3360
3361    USE(c);
3362    for (p = InputBuf; Isspace(*p); p++)
3363	continue;
3364    if (p == LastChar)
3365	return(CC_ERROR);
3366
3367    justpr++;
3368    Expand++;
3369    return(e_newline(0));
3370}
3371
3372/*ARGSUSED*/
3373CCRETVAL
3374e_startover(c)
3375    int c;
3376{				/* erase all of current line, start again */
3377    USE(c);
3378    ResetInLine(0);		/* reset the input pointers */
3379    return(CC_REFRESH);
3380}
3381
3382/*ARGSUSED*/
3383CCRETVAL
3384e_redisp(c)
3385    int c;
3386{
3387    USE(c);
3388    ClearLines();
3389    ClearDisp();
3390    return(CC_REFRESH);
3391}
3392
3393/*ARGSUSED*/
3394CCRETVAL
3395e_cleardisp(c)
3396    int c;
3397{
3398    USE(c);
3399    ClearScreen();		/* clear the whole real screen */
3400    ClearDisp();		/* reset everything */
3401    return(CC_REFRESH);
3402}
3403
3404/*ARGSUSED*/
3405CCRETVAL
3406e_tty_int(c)
3407    int c;
3408{
3409    USE(c);
3410#if defined(_MINIX) || defined(WINNT)
3411    /* SAK PATCH: erase all of current line, start again */
3412    ResetInLine(0);		/* reset the input pointers */
3413    xputchar('\n');
3414    ClearDisp();
3415    return (CC_REFRESH);
3416#else /* !_MINIX && !WINNT */
3417    /* do no editing */
3418    return (CC_NORM);
3419#endif /* _MINIX || WINNT */
3420}
3421
3422/*
3423 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3424 * Function to send a character back to the input stream in cooked
3425 * mode. Only works if we have TIOCSTI
3426 */
3427/*ARGSUSED*/
3428CCRETVAL
3429e_stuff_char(c)
3430     int c;
3431{
3432#ifdef TIOCSTI
3433     extern int Tty_raw_mode;
3434     int was_raw = Tty_raw_mode;
3435     char ch = (char) c;
3436
3437     if (was_raw)
3438         (void) Cookedmode();
3439
3440     (void) write(SHIN, "\n", 1);
3441     (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &ch);
3442
3443     if (was_raw)
3444         (void) Rawmode();
3445     return(e_redisp(c));
3446#else /* !TIOCSTI */
3447     return(CC_ERROR);
3448#endif /* !TIOCSTI */
3449}
3450
3451/*ARGSUSED*/
3452CCRETVAL
3453e_insovr(c)
3454    int c;
3455{
3456    USE(c);
3457    inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3458    return(CC_NORM);
3459}
3460
3461/*ARGSUSED*/
3462CCRETVAL
3463e_tty_dsusp(c)
3464    int c;
3465{
3466    USE(c);
3467    /* do no editing */
3468    return(CC_NORM);
3469}
3470
3471/*ARGSUSED*/
3472CCRETVAL
3473e_tty_flusho(c)
3474    int c;
3475{
3476    USE(c);
3477    /* do no editing */
3478    return(CC_NORM);
3479}
3480
3481/*ARGSUSED*/
3482CCRETVAL
3483e_tty_quit(c)
3484    int c;
3485{
3486    USE(c);
3487    /* do no editing */
3488    return(CC_NORM);
3489}
3490
3491/*ARGSUSED*/
3492CCRETVAL
3493e_tty_tsusp(c)
3494    int c;
3495{
3496    USE(c);
3497    /* do no editing */
3498    return(CC_NORM);
3499}
3500
3501/*ARGSUSED*/
3502CCRETVAL
3503e_tty_stopo(c)
3504    int c;
3505{
3506    USE(c);
3507    /* do no editing */
3508    return(CC_NORM);
3509}
3510
3511/*ARGSUSED*/
3512CCRETVAL
3513e_expand_history(c)
3514    int c;
3515{
3516    USE(c);
3517    *LastChar = '\0';		/* just in case */
3518    c_substitute();
3519    return(CC_NORM);
3520}
3521
3522/*ARGSUSED*/
3523CCRETVAL
3524e_magic_space(c)
3525    int c;
3526{
3527    USE(c);
3528    *LastChar = '\0';		/* just in case */
3529    c_substitute();
3530    return(e_insert(' '));
3531}
3532
3533/*ARGSUSED*/
3534CCRETVAL
3535e_inc_fwd(c)
3536    int c;
3537{
3538    USE(c);
3539    patlen = 0;
3540    return e_inc_search(F_DOWN_SEARCH_HIST);
3541}
3542
3543
3544/*ARGSUSED*/
3545CCRETVAL
3546e_inc_back(c)
3547    int c;
3548{
3549    USE(c);
3550    patlen = 0;
3551    return e_inc_search(F_UP_SEARCH_HIST);
3552}
3553
3554/*ARGSUSED*/
3555CCRETVAL
3556e_copyprev(c)
3557    int c;
3558{
3559    register Char *cp, *oldc, *dp;
3560
3561    USE(c);
3562    if (Cursor == InputBuf)
3563	return(CC_ERROR);
3564    /* else */
3565
3566    oldc = Cursor;
3567    /* does a bounds check */
3568    cp = c_prev_word(Cursor, InputBuf, Argument);
3569
3570    c_insert((int)(oldc - cp));
3571    for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3572	*dp++ = *cp;
3573
3574    Cursor = dp;		/* put cursor at end */
3575
3576    return(CC_REFRESH);
3577}
3578
3579/*ARGSUSED*/
3580CCRETVAL
3581e_tty_starto(c)
3582    int c;
3583{
3584    USE(c);
3585    /* do no editing */
3586    return(CC_NORM);
3587}
3588
3589/*ARGSUSED*/
3590CCRETVAL
3591e_load_average(c)
3592    int c;
3593{
3594    USE(c);
3595    PastBottom();
3596#ifdef TIOCSTAT
3597    /*
3598     * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3599     * there even if they don't use it. (lukem@netbsd.org)
3600     */
3601    if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3602#endif
3603	xprintf(CGETS(5, 1, "Load average unavailable\n"));
3604    return(CC_REFRESH);
3605}
3606
3607/*ARGSUSED*/
3608CCRETVAL
3609v_chgmeta(c)
3610    int c;
3611{
3612    USE(c);
3613    /*
3614     * Delete with insert == change: first we delete and then we leave in
3615     * insert mode.
3616     */
3617    return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3618}
3619
3620/*ARGSUSED*/
3621CCRETVAL
3622v_delmeta(c)
3623    int c;
3624{
3625    USE(c);
3626    return(v_action(TCSHOP_DELETE));
3627}
3628
3629
3630/*ARGSUSED*/
3631CCRETVAL
3632v_endword(c)
3633    int c;
3634{
3635    USE(c);
3636    if (Cursor == LastChar)
3637	return(CC_ERROR);
3638    /* else */
3639
3640    Cursor = c_endword(Cursor, LastChar, Argument);
3641
3642    if (ActionFlag & TCSHOP_DELETE)
3643    {
3644	Cursor++;
3645	c_delfini();
3646	return(CC_REFRESH);
3647    }
3648
3649    RefCursor();
3650    return(CC_NORM);
3651}
3652
3653/*ARGSUSED*/
3654CCRETVAL
3655v_eword(c)
3656    int c;
3657{
3658    USE(c);
3659    if (Cursor == LastChar)
3660	return(CC_ERROR);
3661    /* else */
3662
3663    Cursor = c_eword(Cursor, LastChar, Argument);
3664
3665    if (ActionFlag & TCSHOP_DELETE) {
3666	Cursor++;
3667	c_delfini();
3668	return(CC_REFRESH);
3669    }
3670
3671    RefCursor();
3672    return(CC_NORM);
3673}
3674
3675/*ARGSUSED*/
3676CCRETVAL
3677v_char_fwd(c)
3678    int c;
3679{
3680    Char ch;
3681
3682    USE(c);
3683    if (GetNextChar(&ch) != 1)
3684	return e_send_eof(0);
3685
3686    srch_dir = CHAR_FWD;
3687    srch_char = ch;
3688
3689    return v_csearch_fwd(ch, Argument, 0);
3690
3691}
3692
3693/*ARGSUSED*/
3694CCRETVAL
3695v_char_back(c)
3696    int c;
3697{
3698    Char ch;
3699
3700    USE(c);
3701    if (GetNextChar(&ch) != 1)
3702	return e_send_eof(0);
3703
3704    srch_dir = CHAR_BACK;
3705    srch_char = ch;
3706
3707    return v_csearch_back(ch, Argument, 0);
3708}
3709
3710/*ARGSUSED*/
3711CCRETVAL
3712v_charto_fwd(c)
3713    int c;
3714{
3715    Char ch;
3716
3717    USE(c);
3718    if (GetNextChar(&ch) != 1)
3719	return e_send_eof(0);
3720
3721    return v_csearch_fwd(ch, Argument, 1);
3722
3723}
3724
3725/*ARGSUSED*/
3726CCRETVAL
3727v_charto_back(c)
3728    int c;
3729{
3730    Char ch;
3731
3732    USE(c);
3733    if (GetNextChar(&ch) != 1)
3734	return e_send_eof(0);
3735
3736    return v_csearch_back(ch, Argument, 1);
3737}
3738
3739/*ARGSUSED*/
3740CCRETVAL
3741v_rchar_fwd(c)
3742    int c;
3743{
3744    USE(c);
3745    if (srch_char == 0)
3746	return CC_ERROR;
3747
3748    return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3749			          v_csearch_back(srch_char, Argument, 0);
3750}
3751
3752/*ARGSUSED*/
3753CCRETVAL
3754v_rchar_back(c)
3755    int c;
3756{
3757    USE(c);
3758    if (srch_char == 0)
3759	return CC_ERROR;
3760
3761    return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3762			           v_csearch_back(srch_char, Argument, 0);
3763}
3764
3765/*ARGSUSED*/
3766CCRETVAL
3767v_undo(c)
3768    int c;
3769{
3770    register int  loop;
3771    register Char *kp, *cp;
3772    Char temp;
3773    int	 size;
3774
3775    USE(c);
3776    switch (UndoAction) {
3777    case TCSHOP_DELETE|TCSHOP_INSERT:
3778    case TCSHOP_DELETE:
3779	if (UndoSize == 0) return(CC_NORM);
3780	cp = UndoPtr;
3781	kp = UndoBuf;
3782	for (loop=0; loop < UndoSize; loop++)	/* copy the chars */
3783	    *kp++ = *cp++;			/* into UndoBuf   */
3784
3785	for (cp = UndoPtr; cp <= LastChar; cp++)
3786	    *cp = cp[UndoSize];
3787
3788	LastChar -= UndoSize;
3789	Cursor   =  UndoPtr;
3790
3791	UndoAction = TCSHOP_INSERT;
3792	break;
3793
3794    case TCSHOP_INSERT:
3795	if (UndoSize == 0) return(CC_NORM);
3796	cp = UndoPtr;
3797	Cursor = UndoPtr;
3798	kp = UndoBuf;
3799	c_insert(UndoSize);		/* open the space, */
3800	for (loop = 0; loop < UndoSize; loop++)	/* copy the chars */
3801	    *cp++ = *kp++;
3802
3803	UndoAction = TCSHOP_DELETE;
3804	break;
3805
3806    case TCSHOP_CHANGE:
3807	if (UndoSize == 0) return(CC_NORM);
3808	cp = UndoPtr;
3809	Cursor = UndoPtr;
3810	kp = UndoBuf;
3811	size = (int)(Cursor-LastChar); /*  NOT NSL independant */
3812	if (size < UndoSize)
3813	    size = UndoSize;
3814	for(loop = 0; loop < size; loop++) {
3815	    temp = *kp;
3816	    *kp++ = *cp;
3817	    *cp++ = temp;
3818	}
3819	break;
3820
3821    default:
3822	return(CC_ERROR);
3823    }
3824
3825    return(CC_REFRESH);
3826}
3827
3828/*ARGSUSED*/
3829CCRETVAL
3830v_ush_meta(c)
3831    int c;
3832{
3833    USE(c);
3834    return v_search(F_UP_SEARCH_HIST);
3835}
3836
3837/*ARGSUSED*/
3838CCRETVAL
3839v_dsh_meta(c)
3840    int c;
3841{
3842    USE(c);
3843    return v_search(F_DOWN_SEARCH_HIST);
3844}
3845
3846/*ARGSUSED*/
3847CCRETVAL
3848v_rsrch_fwd(c)
3849    int c;
3850{
3851    USE(c);
3852    if (patlen == 0) return(CC_ERROR);
3853    return(v_repeat_srch(searchdir));
3854}
3855
3856/*ARGSUSED*/
3857CCRETVAL
3858v_rsrch_back(c)
3859    int c;
3860{
3861    USE(c);
3862    if (patlen == 0) return(CC_ERROR);
3863    return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3864			 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3865}
3866
3867#ifndef WINNT
3868/* Since ed.defns.h  is generated from ed.defns.c, these empty
3869   functions will keep the F_NUM_FNS consistent
3870 */
3871CCRETVAL
3872e_copy_to_clipboard(c)
3873    int c;
3874{
3875    USE(c);
3876    return CC_ERROR;
3877}
3878
3879CCRETVAL
3880e_paste_from_clipboard(c)
3881    int c;
3882{
3883    USE(c);
3884    return (CC_ERROR);
3885}
3886
3887CCRETVAL
3888e_dosify_next(c)
3889    int c;
3890{
3891    USE(c);
3892    return (CC_ERROR);
3893}
3894CCRETVAL
3895e_dosify_prev(c)
3896    int c;
3897{
3898    USE(c);
3899    return (CC_ERROR);
3900}
3901#else /* WINNT */
3902/*ARGSUSED*/
3903CCRETVAL
3904e_dosify_next(c)
3905    int c;
3906{
3907    register Char *cp, *p, *kp;
3908
3909    USE(c);
3910    if (Cursor == LastChar)
3911	return(CC_ERROR);
3912    /* else */
3913
3914	cp = Cursor;
3915	while(  cp < LastChar) {
3916		if ( (*cp & CHAR == ' ') && (cp[-1] & CHAR != '\\') )
3917			break;
3918		cp++;
3919	}
3920
3921    for (p = Cursor, kp = KillBuf; p < cp; p++)	{/* save the text */
3922	if ( ( *p & CHAR ) == '/') {
3923	    *kp++ = '\\';
3924	    *kp++ = '\\';
3925	}
3926	else
3927	    *kp++ = *p;
3928    }
3929    LastKill = kp;
3930
3931    c_delafter((int)(cp - Cursor));	/* delete after dot */
3932    if (Cursor > LastChar)
3933	Cursor = LastChar;	/* bounds check */
3934    return (e_yank_kill(c));
3935}
3936/*ARGSUSED*/
3937CCRETVAL
3938e_dosify_prev(c)
3939    int c;
3940{
3941    register Char *cp, *p, *kp;
3942
3943    USE(c);
3944    if (Cursor == InputBuf)
3945	return(CC_ERROR);
3946    /* else */
3947
3948    cp = Cursor-1;
3949    /* Skip trailing spaces */
3950    while ((cp > InputBuf) && ( (*cp & CHAR) == ' '))
3951    	cp--;
3952
3953    while (cp > InputBuf) {
3954	if ( ((*cp & CHAR) == ' ') && ((cp[-1] & CHAR) != '\\') )
3955	    break;
3956	cp--;
3957    }
3958
3959    for (p = cp, kp = KillBuf; p < Cursor; p++)	{/* save the text */
3960	if ( ( *p & CHAR ) == '/') {
3961	    *kp++ = '\\';
3962	    *kp++ = '\\';
3963	}
3964	else
3965	    *kp++ = *p;
3966    }
3967    LastKill = kp;
3968
3969    c_delbefore((int)(Cursor - cp));	/* delete before dot */
3970    Cursor = cp;
3971    if (Cursor < InputBuf)
3972	Cursor = InputBuf;	/* bounds check */
3973    return(e_yank_kill(c));
3974}
3975#endif /* !WINNT */
3976
3977#ifdef notdef
3978void
3979MoveCursor(n)			/* move cursor + right - left char */
3980    int     n;
3981{
3982    Cursor = Cursor + n;
3983    if (Cursor < InputBuf)
3984	Cursor = InputBuf;
3985    if (Cursor > LastChar)
3986	Cursor = LastChar;
3987    return;
3988}
3989
3990Char *
3991GetCursor()
3992{
3993    return(Cursor);
3994}
3995
3996int
3997PutCursor(p)
3998    Char   *p;
3999{
4000    if (p < InputBuf || p > LastChar)
4001	return 1;		/* Error */
4002    Cursor = p;
4003    return 0;
4004}
4005#endif
4006