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