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