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