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