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