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