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