]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcsh/ed.chared.c
This commit was generated by cvs2svn to compensate for changes in r151513,
[FreeBSD/FreeBSD.git] / contrib / tcsh / ed.chared.c
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
75 RCSID("$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
99 static Char *InsertPos = InputBuf; /* Where insertion starts */
100 static Char *ActionPos = 0;        /* Where action begins  */
101 static int  ActionFlag = TCSHOP_NOP;       /* What delayed action to take */
102 /*
103  * Word search state
104  */
105 static int  searchdir = F_UP_SEARCH_HIST;       /* Direction of last search */
106 static Char patbuf[INBUFSIZE];                  /* Search target */
107 static int patlen = 0;
108 /*
109  * Char search state
110  */
111 static int  srch_dir = CHAR_FWD;                /* Direction of last search */
112 static Char srch_char = 0;                      /* Search target */
113
114 /* all routines that start with c_ are private to this set of routines */
115 static  void     c_alternativ_key_map   __P((int));
116 void     c_insert               __P((int));
117 void     c_delafter             __P((int));
118 void     c_delbefore            __P((int));
119 static  int      c_to_class             __P((Char));
120 static  Char    *c_prev_word            __P((Char *, Char *, int));
121 static  Char    *c_next_word            __P((Char *, Char *, int));
122 static  Char    *c_number               __P((Char *, int *, int));
123 static  Char    *c_expand               __P((Char *));
124 static  void     c_excl                 __P((Char *));
125 static  void     c_substitute           __P((void));
126 static  void     c_delfini              __P((void));
127 static  int      c_hmatch               __P((Char *));
128 static  void     c_hsetpat              __P((void));
129 #ifdef COMMENT
130 static  void     c_get_word             __P((Char **, Char **));
131 #endif
132 static  Char    *c_preword              __P((Char *, Char *, int, Char *));
133 static  Char    *c_nexword              __P((Char *, Char *, int));
134 static  Char    *c_endword              __P((Char *, Char *, int, Char *));
135 static  Char    *c_eword                __P((Char *, Char *, int));
136 static  void     c_push_kill            __P((Char *, Char *));
137 static  CCRETVAL c_get_histline         __P((void));
138 static  CCRETVAL c_search_line          __P((Char *, int));
139 static  CCRETVAL v_repeat_srch          __P((int));
140 static  CCRETVAL e_inc_search           __P((int));
141 static  CCRETVAL e_insert_str           __P((Char *));
142 static  CCRETVAL v_search               __P((int));
143 static  CCRETVAL v_csearch_fwd          __P((Char, int, int));
144 static  CCRETVAL v_action               __P((int));
145 static  CCRETVAL v_csearch_back         __P((Char, int, int));
146
147 static void
148 c_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
165 void
166 c_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
183 void
184 c_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
222 void
223 c_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
253 static Char *
254 c_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  */
301 static int
302 c_to_class(ch)
303 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
314 static Char *
315 c_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
363 static Char *
364 c_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
406 static Char *
407 c_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
440 static Char *
441 c_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
473 static Char *
474 c_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;
490 excl_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));
690 excl_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
702 static void
703 c_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
745 static void
746 c_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
766 static void
767 c_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
798 static Char *
799 c_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
831 static Char *
832 c_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 */
855 void
856 SetKillRing(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 */
894 static void
895 c_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
955 static CCRETVAL
956 c_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
1018 static CCRETVAL
1019 c_search_line(pattern, dir)
1020 Char *pattern;
1021 int 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
1047 static CCRETVAL
1048 e_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
1245 static CCRETVAL
1246 v_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*/
1368 CCRETVAL
1369 v_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*/
1397 CCRETVAL
1398 e_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
1407 static CCRETVAL
1408 e_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
1428 CCRETVAL
1429 e_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
1500 int
1501 InsertStr(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
1517 void
1518 DeleteBack(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
1528 CCRETVAL
1529 e_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
1562 CCRETVAL
1563 e_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
1583 CCRETVAL
1584 v_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*/
1605 CCRETVAL
1606 e_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*/
1619 CCRETVAL
1620 e_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*/
1630 CCRETVAL
1631 e_complete(c)
1632     Char c;
1633 {
1634     USE(c);
1635     *LastChar = '\0';           /* just in case */
1636     return(CC_COMPLETE);
1637 }
1638
1639 /*ARGSUSED*/
1640 CCRETVAL
1641 e_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*/
1650 CCRETVAL
1651 e_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*/
1660 CCRETVAL
1661 e_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*/
1670 CCRETVAL
1671 v_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*/
1682 CCRETVAL
1683 e_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*/
1739 CCRETVAL
1740 e_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*/
1769 CCRETVAL
1770 e_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  */
1792 static int
1793 c_hmatch(str)
1794 Char *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  */
1804 static void
1805 c_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*/
1826 CCRETVAL
1827 e_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*/
1895 CCRETVAL
1896 e_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*/
1949 CCRETVAL
1950 e_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*/
1960 CCRETVAL
1961 e_correct(c)
1962     Char c;
1963 {
1964     USE(c);
1965     *LastChar = '\0';           /* just in case */
1966     return(CC_CORRECT);
1967 }
1968
1969 /*ARGSUSED*/
1970 CCRETVAL
1971 e_correctl(c)
1972     Char c;
1973 {
1974     USE(c);
1975     *LastChar = '\0';           /* just in case */
1976     return(CC_CORRECT_L);
1977 }
1978
1979 /*ARGSUSED*/
1980 CCRETVAL
1981 e_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*/
2011 CCRETVAL
2012 e_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*/
2022 CCRETVAL
2023 e_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*/
2033 CCRETVAL
2034 e_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*/
2044 CCRETVAL
2045 e_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*/
2054 CCRETVAL
2055 e_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*/
2064 CCRETVAL
2065 e_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*/
2074 CCRETVAL
2075 e_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*/
2084 CCRETVAL
2085 e_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*/
2095 CCRETVAL
2096 e_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*/
2135 CCRETVAL
2136 e_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*/
2220 CCRETVAL
2221 e_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*/
2252 CCRETVAL
2253 e_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*/
2312 CCRETVAL
2313 v_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*/
2331 CCRETVAL
2332 e_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*/
2346 CCRETVAL
2347 e_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*/
2394 CCRETVAL
2395 e_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*/
2418 CCRETVAL
2419 e_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*/
2448 CCRETVAL
2449 e_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*/
2467 CCRETVAL
2468 e_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*/
2493 CCRETVAL
2494 e_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*/
2514 CCRETVAL
2515 e_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*/
2536 CCRETVAL
2537 e_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*/
2552 CCRETVAL
2553 e_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*/
2573 CCRETVAL
2574 e_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*/
2585 CCRETVAL
2586 e_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*/
2598 CCRETVAL
2599 e_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*/
2609 CCRETVAL
2610 e_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*/
2630 CCRETVAL
2631 e_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*/
2648 CCRETVAL
2649 e_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*/
2671 CCRETVAL
2672 e_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*/
2690 CCRETVAL
2691 e_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*/
2718 CCRETVAL
2719 v_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*/
2739 CCRETVAL
2740 e_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*/
2761 CCRETVAL
2762 e_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*/
2788 CCRETVAL
2789 e_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*/
2810 CCRETVAL
2811 v_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*/
2832 CCRETVAL
2833 v_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*/
2856 static CCRETVAL
2857 v_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
2881 static CCRETVAL
2882 v_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
2914 static CCRETVAL
2915 v_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*/
2947 static CCRETVAL
2948 v_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> */
2991 static void
2992 c_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*/
3011 CCRETVAL
3012 e_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*/
3032 CCRETVAL
3033 e_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*/
3061 CCRETVAL
3062 e_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*/
3082 CCRETVAL
3083 e_set_mark(c)
3084     Char c;
3085 {
3086     USE(c);
3087     Mark = Cursor;
3088     return(CC_NORM);
3089 }
3090
3091 /*ARGSUSED*/
3092 CCRETVAL
3093 e_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*/
3107 CCRETVAL
3108 e_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*/
3120 CCRETVAL
3121 e_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*/
3138 CCRETVAL
3139 e_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*/
3149 CCRETVAL
3150 e_extendnext(c)
3151     Char c;
3152 {
3153     CurrentKeyMap = CcAltMap;
3154     return(CC_ARGHACK); /* preserve argument */
3155 }
3156
3157 #endif
3158
3159 /*ARGSUSED*/
3160 CCRETVAL
3161 v_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*/
3178 CCRETVAL
3179 v_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*/
3192 CCRETVAL
3193 v_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*/
3206 CCRETVAL
3207 v_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*/
3217 CCRETVAL
3218 v_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*/
3228 CCRETVAL
3229 v_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*/
3239 CCRETVAL
3240 v_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*/
3254 CCRETVAL
3255 v_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*/
3276 CCRETVAL
3277 v_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*/
3293 CCRETVAL
3294 v_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*/
3319 CCRETVAL
3320 e_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*/
3337 CCRETVAL
3338 e_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*/
3347 CCRETVAL
3348 e_redisp(c)
3349     Char c;
3350 {
3351     USE(c);
3352     ClearLines();
3353     ClearDisp();
3354     return(CC_REFRESH);
3355 }
3356
3357 /*ARGSUSED*/
3358 CCRETVAL
3359 e_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*/
3369 CCRETVAL
3370 e_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*/
3392 CCRETVAL
3393 e_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*/
3418 CCRETVAL
3419 e_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*/
3428 CCRETVAL
3429 e_tty_dsusp(c)
3430     Char c;
3431 {
3432     USE(c);
3433     /* do no editing */
3434     return(CC_NORM);
3435 }
3436
3437 /*ARGSUSED*/
3438 CCRETVAL
3439 e_tty_flusho(c)
3440     Char c;
3441 {
3442     USE(c);
3443     /* do no editing */
3444     return(CC_NORM);
3445 }
3446
3447 /*ARGSUSED*/
3448 CCRETVAL
3449 e_tty_quit(c)
3450     Char c;
3451 {
3452     USE(c);
3453     /* do no editing */
3454     return(CC_NORM);
3455 }
3456
3457 /*ARGSUSED*/
3458 CCRETVAL
3459 e_tty_tsusp(c)
3460     Char c;
3461 {
3462     USE(c);
3463     /* do no editing */
3464     return(CC_NORM);
3465 }
3466
3467 /*ARGSUSED*/
3468 CCRETVAL
3469 e_tty_stopo(c)
3470     Char c;
3471 {
3472     USE(c);
3473     /* do no editing */
3474     return(CC_NORM);
3475 }
3476
3477 /*ARGSUSED*/
3478 CCRETVAL
3479 e_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*/
3489 CCRETVAL
3490 e_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*/
3500 CCRETVAL
3501 e_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*/
3511 CCRETVAL
3512 e_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*/
3521 CCRETVAL
3522 e_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*/
3546 CCRETVAL
3547 e_tty_starto(c)
3548     Char c;
3549 {
3550     USE(c);
3551     /* do no editing */
3552     return(CC_NORM);
3553 }
3554
3555 /*ARGSUSED*/
3556 CCRETVAL
3557 e_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*/
3574 CCRETVAL
3575 v_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*/
3587 CCRETVAL
3588 v_delmeta(c)
3589     Char c;
3590 {
3591     USE(c);
3592     return(v_action(TCSHOP_DELETE));
3593 }
3594
3595
3596 /*ARGSUSED*/
3597 CCRETVAL
3598 v_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*/
3620 CCRETVAL
3621 v_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*/
3642 CCRETVAL
3643 v_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*/
3660 CCRETVAL
3661 v_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*/
3677 CCRETVAL
3678 v_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*/
3692 CCRETVAL
3693 v_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*/
3706 CCRETVAL
3707 v_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*/
3719 CCRETVAL
3720 v_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*/
3732 CCRETVAL
3733 v_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*/
3795 CCRETVAL
3796 v_ush_meta(c)
3797     Char c;
3798 {
3799     USE(c);
3800     return v_search(F_UP_SEARCH_HIST);
3801 }
3802
3803 /*ARGSUSED*/
3804 CCRETVAL
3805 v_dsh_meta(c)
3806     Char c;
3807 {
3808     USE(c);
3809     return v_search(F_DOWN_SEARCH_HIST);
3810 }
3811
3812 /*ARGSUSED*/
3813 CCRETVAL
3814 v_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*/
3823 CCRETVAL
3824 v_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  */
3837 CCRETVAL
3838 e_copy_to_clipboard(c)
3839     Char c;
3840 {
3841     USE(c);
3842     return CC_ERROR;
3843 }
3844
3845 CCRETVAL
3846 e_paste_from_clipboard(c)
3847     Char c;
3848 {
3849     USE(c);
3850     return (CC_ERROR);
3851 }
3852
3853 CCRETVAL
3854 e_dosify_next(c)
3855     Char c;
3856 {
3857     USE(c);
3858     return (CC_ERROR);
3859 }
3860 CCRETVAL
3861 e_dosify_prev(c)
3862     Char c;
3863 {
3864     USE(c);
3865     return (CC_ERROR);
3866 }
3867 CCRETVAL
3868 e_page_up(c)
3869     Char c;
3870 {
3871     USE(c);
3872     return (CC_ERROR);
3873 }
3874 CCRETVAL
3875 e_page_down(c)
3876     Char c;
3877 {
3878     USE(c);
3879     return (CC_ERROR);
3880 }
3881 #endif /* !WINNT_NATIVE */
3882
3883 #ifdef notdef
3884 void
3885 MoveCursor(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
3896 Char *
3897 GetCursor()
3898 {
3899     return(Cursor);
3900 }
3901
3902 int
3903 PutCursor(p)
3904     Char   *p;
3905 {
3906     if (p < InputBuf || p > LastChar)
3907         return 1;               /* Error */
3908     Cursor = p;
3909     return 0;
3910 }
3911 #endif