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