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