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