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