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