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