tcsh: fix warning to keep compiling with WARNS=2
[dragonfly.git] / contrib / tcsh-6 / ed.chared.c
blob1ab5a91b6644861678d7f4abf0b0053ac3252878
1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.95 2009/06/25 21:15:37 christos Exp $ */
2 /*
3 * ed.chared.c: Character editing functions.
4 */
5 /*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
36 e_dabbrev_expand() did not do proper completion if quoted spaces were present
37 in the string being completed. Exemple:
39 # echo hello\ world
40 hello world
41 # echo h<press key bound to dabbrev-expande>
42 # echo hello\<cursor>
44 Correct behavior is:
45 # echo h<press key bound to dabbrev-expande>
46 # echo hello\ world<cursor>
48 The same problem occured if spaces were present in a string withing quotation
49 marks. Example:
51 # echo "hello world"
52 hello world
53 # echo "h<press key bound to dabbrev-expande>
54 # echo "hello<cursor>
56 The former problem could be solved with minor modifications of c_preword()
57 and c_endword(). The latter, however, required a significant rewrite of
58 c_preword(), since quoted strings must be parsed from start to end to
59 determine if a given character is inside or outside the quotation marks.
61 Compare the following two strings:
63 # echo \"" 'foo \' bar\"
64 " 'foo \' bar\
65 # echo '\"" 'foo \' bar\"
66 \"" foo ' bar"
68 The only difference between the two echo lines is in the first character
69 after the echo command. The result is either one or three arguments.
73 #include "sh.h"
75 RCSID("$tcsh: ed.chared.c,v 3.95 2009/06/25 21:15:37 christos Exp $")
77 #include "ed.h"
78 #include "tw.h"
79 #include "ed.defns.h"
81 /* #define SDEBUG */
83 #define TCSHOP_NOP 0x00
84 #define TCSHOP_DELETE 0x01
85 #define TCSHOP_INSERT 0x02
86 #define TCSHOP_CHANGE 0x04
88 #define CHAR_FWD 0
89 #define CHAR_BACK 1
92 * vi word treatment
93 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
95 #define C_CLASS_WHITE 1
96 #define C_CLASS_ALNUM 2
97 #define C_CLASS_OTHER 3
99 static Char *InsertPos = InputBuf; /* Where insertion starts */
100 static Char *ActionPos = 0; /* Where action begins */
101 static int ActionFlag = TCSHOP_NOP; /* What delayed action to take */
103 * Word search state
105 static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */
106 static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
108 * Char search state
110 static int srch_dir = CHAR_FWD; /* Direction of last search */
111 static Char srch_char = 0; /* Search target */
113 /* all routines that start with c_ are private to this set of routines */
114 static void c_alternativ_key_map (int);
115 void c_insert (int);
116 void c_delafter (int);
117 void c_delbefore (int);
118 static int c_to_class (Char);
119 static Char *c_prev_word (Char *, Char *, int);
120 static Char *c_next_word (Char *, Char *, int);
121 static Char *c_number (Char *, int *, int);
122 static Char *c_expand (Char *);
123 static int c_excl (Char *);
124 static int c_substitute (void);
125 static void c_delfini (void);
126 static int c_hmatch (Char *);
127 static void c_hsetpat (void);
128 #ifdef COMMENT
129 static void c_get_word (Char **, Char **);
130 #endif
131 static Char *c_preword (Char *, Char *, int, Char *);
132 static Char *c_nexword (Char *, Char *, int);
133 static Char *c_endword (Char *, Char *, int, Char *);
134 static Char *c_eword (Char *, Char *, int);
135 static void c_push_kill (Char *, Char *);
136 static void c_save_inputbuf (void);
137 static CCRETVAL c_search_line (Char *, int);
138 static CCRETVAL v_repeat_srch (int);
139 static CCRETVAL e_inc_search (int);
140 #ifdef notyet
141 static CCRETVAL e_insert_str (Char *);
142 #endif
143 static CCRETVAL v_search (int);
144 static CCRETVAL v_csearch_fwd (Char, int, int);
145 static CCRETVAL v_action (int);
146 static CCRETVAL v_csearch_back (Char, int, int);
148 static void
149 c_alternativ_key_map(int state)
151 switch (state) {
152 case 0:
153 CurrentKeyMap = CcKeyMap;
154 break;
155 case 1:
156 CurrentKeyMap = CcAltMap;
157 break;
158 default:
159 return;
162 AltKeyMap = (Char) state;
165 void
166 c_insert(int num)
168 Char *cp;
170 if (LastChar + num >= InputLim)
171 return; /* can't go past end of buffer */
173 if (Cursor < LastChar) { /* if I must move chars */
174 for (cp = LastChar; cp >= Cursor; cp--)
175 cp[num] = *cp;
176 if (Mark && Mark > Cursor)
177 Mark += num;
179 LastChar += num;
182 void
183 c_delafter(int num)
185 Char *cp, *kp = NULL;
187 if (num > LastChar - Cursor)
188 num = (int) (LastChar - Cursor); /* bounds check */
190 if (num > 0) { /* if I can delete anything */
191 if (VImode) {
192 kp = UndoBuf; /* Set Up for VI undo command */
193 UndoAction = TCSHOP_INSERT;
194 UndoSize = num;
195 UndoPtr = Cursor;
196 for (cp = Cursor; cp <= LastChar; cp++) {
197 *kp++ = *cp; /* Save deleted chars into undobuf */
198 *cp = cp[num];
201 else
202 for (cp = Cursor; cp + num <= LastChar; cp++)
203 *cp = cp[num];
204 LastChar -= num;
205 /* Mark was within the range of the deleted word? */
206 if (Mark && Mark > Cursor && Mark <= Cursor+num)
207 Mark = Cursor;
208 /* Mark after the deleted word? */
209 else if (Mark && Mark > Cursor)
210 Mark -= num;
212 #ifdef notdef
213 else {
215 * XXX: We don't want to do that. In emacs mode overwrite should be
216 * sticky. I am not sure how that affects vi mode
218 inputmode = MODE_INSERT;
220 #endif /* notdef */
223 void
224 c_delbefore(int num) /* delete before dot, with bounds checking */
226 Char *cp, *kp = NULL;
228 if (num > Cursor - InputBuf)
229 num = (int) (Cursor - InputBuf); /* bounds check */
231 if (num > 0) { /* if I can delete anything */
232 if (VImode) {
233 kp = UndoBuf; /* Set Up for VI undo command */
234 UndoAction = TCSHOP_INSERT;
235 UndoSize = num;
236 UndoPtr = Cursor - num;
237 for (cp = Cursor - num; cp <= LastChar; cp++) {
238 *kp++ = *cp;
239 *cp = cp[num];
242 else
243 for (cp = Cursor - num; cp + num <= LastChar; cp++)
244 *cp = cp[num];
245 LastChar -= num;
246 Cursor -= num;
247 /* Mark was within the range of the deleted word? */
248 if (Mark && Mark > Cursor && Mark <= Cursor+num)
249 Mark = Cursor;
250 /* Mark after the deleted word? */
251 else if (Mark && Mark > Cursor)
252 Mark -= num;
256 static Char *
257 c_preword(Char *p, Char *low, int n, Char *delim)
259 while (n--) {
260 Char *prev = low;
261 Char *new;
263 while (prev < p) { /* Skip initial non-word chars */
264 if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\')
265 break;
266 prev++;
269 new = prev;
271 while (new < p) {
272 prev = new;
273 new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */
274 new++; /* Step away from end of word */
275 while (new <= p) { /* Skip trailing non-word chars */
276 if (!Strchr(delim, *new) || *(new-1) == (Char)'\\')
277 break;
278 new++;
282 p = prev; /* Set to previous word start */
285 if (p < low)
286 p = low;
287 return (p);
291 * c_to_class() returns the class of the given character.
293 * This is used to make the c_prev_word() and c_next_word() functions
294 * work like vi's, which classify characters. A word is a sequence of
295 * characters belonging to the same class, classes being defined as
296 * follows:
298 * 1/ whitespace
299 * 2/ alphanumeric chars, + underscore
300 * 3/ others
302 static int
303 c_to_class(Char ch)
305 if (Isspace(ch))
306 return C_CLASS_WHITE;
308 if (Isdigit(ch) || Isalpha(ch) || ch == '_')
309 return C_CLASS_ALNUM;
311 return C_CLASS_OTHER;
314 static Char *
315 c_prev_word(Char *p, Char *low, int n)
317 p--;
319 if (!VImode) {
320 while (n--) {
321 while ((p >= low) && !isword(*p))
322 p--;
323 while ((p >= low) && isword(*p))
324 p--;
327 /* cp now points to one character before the word */
328 p++;
329 if (p < low)
330 p = low;
331 /* cp now points where we want it */
332 return(p);
335 while (n--) {
336 int c_class;
338 if (p < low)
339 break;
341 /* scan until beginning of current word (may be all whitespace!) */
342 c_class = c_to_class(*p);
343 while ((p >= low) && c_class == c_to_class(*p))
344 p--;
346 /* if this was a non_whitespace word, we're ready */
347 if (c_class != C_CLASS_WHITE)
348 continue;
350 /* otherwise, move back to beginning of the word just found */
351 c_class = c_to_class(*p);
352 while ((p >= low) && c_class == c_to_class(*p))
353 p--;
356 p++; /* correct overshoot */
358 return (p);
361 static Char *
362 c_next_word(Char *p, Char *high, int n)
364 if (!VImode) {
365 while (n--) {
366 while ((p < high) && !isword(*p))
367 p++;
368 while ((p < high) && isword(*p))
369 p++;
371 if (p > high)
372 p = high;
373 /* p now points where we want it */
374 return(p);
377 while (n--) {
378 int c_class;
380 if (p >= high)
381 break;
383 /* scan until end of current word (may be all whitespace!) */
384 c_class = c_to_class(*p);
385 while ((p < high) && c_class == c_to_class(*p))
386 p++;
388 /* if this was all whitespace, we're ready */
389 if (c_class == C_CLASS_WHITE)
390 continue;
392 /* if we've found white-space at the end of the word, skip it */
393 while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
394 p++;
397 p--; /* correct overshoot */
399 return (p);
402 static Char *
403 c_nexword(Char *p, Char *high, int n)
405 while (n--) {
406 while ((p < high) && !Isspace(*p))
407 p++;
408 while ((p < high) && Isspace(*p))
409 p++;
412 if (p > high)
413 p = high;
414 /* p now points where we want it */
415 return(p);
419 * Expand-History (originally "Magic-Space") code added by
420 * Ray Moody <ray@gibbs.physics.purdue.edu>
421 * this is a neat, but odd, addition.
425 * c_number: Ignore character p points to, return number appearing after that.
426 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
427 * Return p pointing to last char used.
431 * dval is the number to subtract from for things like $-3
434 static Char *
435 c_number(Char *p, int *num, int dval)
437 int i;
438 int sign = 1;
440 if (*++p == '^') {
441 *num = 1;
442 return(p);
444 if (*p == '$') {
445 if (*++p != '-') {
446 *num = INT_MAX; /* Handle $ */
447 return(--p);
449 sign = -1; /* Handle $- */
450 ++p;
452 for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
453 continue;
454 *num = (sign < 0 ? dval - i : i);
455 return(--p);
459 * excl_expand: There is an excl to be expanded to p -- do the right thing
460 * with it and return a version of p advanced over the expanded stuff. Also,
461 * update tsh_cur and related things as appropriate...
464 static Char *
465 c_expand(Char *p)
467 Char *q;
468 struct Hist *h = Histlist.Hnext;
469 struct wordent *l;
470 int i, from, to, dval;
471 int all_dig;
472 int been_once = 0;
473 Char *op = p;
474 Char *buf;
475 size_t buf_len;
476 Char *modbuf;
478 buf = NULL;
479 if (!h)
480 goto excl_err;
481 excl_sw:
482 switch (*(q = p + 1)) {
484 case '^':
485 buf = expand_lex(&h->Hlex, 1, 1);
486 break;
488 case '$':
489 if ((l = (h->Hlex).prev) != 0)
490 buf = expand_lex(l->prev->prev, 0, 0);
491 break;
493 case '*':
494 buf = expand_lex(&h->Hlex, 1, INT_MAX);
495 break;
497 default:
498 if (been_once) { /* unknown argument */
499 /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
500 buf = expand_lex(&h->Hlex, 0, INT_MAX);
501 q -= 2;
502 break;
504 been_once = 1;
506 if (*q == ':') /* short form: !:arg */
507 --q;
509 if (*q != HIST) {
511 * Search for a space, tab, or colon. See if we have a number (as
512 * in !1234:xyz). Remember the number.
514 for (i = 0, all_dig = 1;
515 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
517 * PWP: !-4 is a valid history argument too, therefore the test
518 * is if not a digit, or not a - as the first character.
520 if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
521 all_dig = 0;
522 else if (*q == '-')
523 all_dig = 2;/* we are sneeky about this */
524 else
525 i = 10 * i + *q - '0';
527 --q;
530 * If we have a number, search for event i. Otherwise, search for
531 * a named event (as in !foo). (In this case, I is the length of
532 * the named event).
534 if (all_dig) {
535 if (all_dig == 2)
536 i = -i; /* make it negitive */
537 if (i < 0) /* if !-4 (for example) */
538 i = eventno + 1 + i; /* remember: i is < 0 */
539 for (; h; h = h->Hnext) {
540 if (h->Hnum == i)
541 break;
544 else {
545 for (i = (int) (q - p); h; h = h->Hnext) {
546 if ((l = &h->Hlex) != 0) {
547 if (!Strncmp(p + 1, l->next->word, (size_t) i))
548 break;
553 if (!h)
554 goto excl_err;
555 if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
556 q[1] == '$' || q[1] == '^') { /* get some args */
557 p = q[1] == ':' ? ++q : q;
559 * Go handle !foo:*
561 if ((q[1] < '0' || q[1] > '9') &&
562 q[1] != '-' && q[1] != '$' && q[1] != '^')
563 goto excl_sw;
565 * Go handle !foo:$
567 if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
568 goto excl_sw;
570 * Count up the number of words in this event. Store it in dval.
571 * Dval will be fed to number.
573 dval = 0;
574 if ((l = h->Hlex.prev) != 0) {
575 for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
576 continue;
578 if (!dval)
579 goto excl_err;
580 if (q[1] == '-')
581 from = 0;
582 else
583 q = c_number(q, &from, dval);
584 if (q[1] == '-') {
585 ++q;
586 if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
587 to = dval - 1;
588 else
589 q = c_number(q, &to, dval);
591 else if (q[1] == '*') {
592 ++q;
593 to = INT_MAX;
595 else {
596 to = from;
598 if (from < 0 || to < from)
599 goto excl_err;
600 buf = expand_lex(&h->Hlex, from, to);
602 else /* get whole cmd */
603 buf = expand_lex(&h->Hlex, 0, INT_MAX);
604 break;
606 if (buf == NULL)
607 buf = SAVE("");
610 * Apply modifiers, if any.
612 if (q[1] == ':') {
613 modbuf = buf;
614 while (q[1] == ':' && modbuf != NULL) {
615 switch (q[2]) {
616 case 'r':
617 case 'e':
618 case 'h':
619 case 't':
620 case 'q':
621 case 'x':
622 case 'u':
623 case 'l':
624 if ((modbuf = domod(buf, (int) q[2])) != NULL) {
625 xfree(buf);
626 buf = modbuf;
628 ++q;
629 break;
631 case 'a':
632 case 'g':
633 /* Not implemented; this needs to be done before expanding
634 * lex. We don't have the words available to us anymore.
636 ++q;
637 break;
639 case 'p':
640 /* Ok */
641 ++q;
642 break;
644 case '\0':
645 break;
647 default:
648 ++q;
649 break;
651 if (q[1])
652 ++q;
656 buf_len = Strlen(buf);
658 * Now replace the text from op to q inclusive with the text from buf.
660 q++;
663 * Now replace text non-inclusively like a real CS major!
665 if (LastChar + buf_len - (q - op) >= InputLim)
666 goto excl_err;
667 (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
668 LastChar += buf_len - (q - op);
669 Cursor += buf_len - (q - op);
670 (void) memcpy(op, buf, buf_len * sizeof(Char));
671 *LastChar = '\0';
672 xfree(buf);
673 return op + buf_len;
674 excl_err:
675 xfree(buf);
676 SoundBeep();
677 return(op + 1);
681 * c_excl: An excl has been found at point p -- back up and find some white
682 * space (or the beginning of the buffer) and properly expand all the excl's
683 * from there up to the current cursor position. We also avoid (trying to)
684 * expanding '>!'
685 * Returns number of expansions attempted (doesn't matter whether they succeeded
686 * or not).
689 static int
690 c_excl(Char *p)
692 int i;
693 Char *q;
694 int nr_exp;
697 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
698 * back p up to just before the current word.
700 if ((p[1] == ' ' || p[1] == '\t') &&
701 (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
702 for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
703 continue;
704 if (*q == '>')
705 ++p;
707 else {
708 while (*p != ' ' && *p != '\t' && p > InputBuf)
709 --p;
713 * Forever: Look for history char. (Stop looking when we find the cursor.)
714 * Count backslashes. If odd, skip history char. Expand if even number of
715 * backslashes.
717 nr_exp = 0;
718 for (;;) {
719 while (*p != HIST && p < Cursor)
720 ++p;
721 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
722 continue;
723 if (i % 2 == 0)
724 ++p;
725 if (p >= Cursor) /* all done */
726 return nr_exp;
727 if (i % 2 == 1) {
728 p = c_expand(p);
729 ++nr_exp;
733 return nr_exp;
737 static int
738 c_substitute(void)
740 Char *p;
741 int nr_exp;
744 * Start p out one character before the cursor. Move it backwards looking
745 * for white space, the beginning of the line, or a history character.
747 for (p = Cursor - 1;
748 p > InputBuf && *p != ' ' && *p != '\t' && *p != HIST; --p)
749 continue;
752 * If we found a history character, go expand it.
754 if (*p == HIST)
755 nr_exp = c_excl(p);
756 else
757 nr_exp = 0;
758 Refresh();
760 return nr_exp;
763 static void
764 c_delfini(void) /* Finish up delete action */
766 int Size;
768 if (ActionFlag & TCSHOP_INSERT)
769 c_alternativ_key_map(0);
771 ActionFlag = TCSHOP_NOP;
773 if (ActionPos == 0)
774 return;
776 UndoAction = TCSHOP_INSERT;
778 if (Cursor > ActionPos) {
779 Size = (int) (Cursor-ActionPos);
780 c_delbefore(Size);
781 RefCursor();
783 else if (Cursor < ActionPos) {
784 Size = (int)(ActionPos-Cursor);
785 c_delafter(Size);
787 else {
788 Size = 1;
789 c_delafter(Size);
791 UndoPtr = Cursor;
792 UndoSize = Size;
795 static Char *
796 c_endword(Char *p, Char *high, int n, Char *delim)
798 Char inquote = 0;
799 p++;
801 while (n--) {
802 while (p < high) { /* Skip non-word chars */
803 if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
804 break;
805 p++;
807 while (p < high) { /* Skip string */
808 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
809 if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
810 if (inquote == 0) inquote = *p;
811 else if (inquote == *p) inquote = 0;
814 /* Break if unquoted non-word char */
815 if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
816 break;
817 p++;
821 p--;
822 return(p);
826 static Char *
827 c_eword(Char *p, Char *high, int n)
829 p++;
831 while (n--) {
832 while ((p < high) && Isspace(*p))
833 p++;
835 if (Isalnum(*p))
836 while ((p < high) && Isalnum(*p))
837 p++;
838 else
839 while ((p < high) && !(Isspace(*p) || Isalnum(*p)))
840 p++;
843 p--;
844 return(p);
847 /* Set the max length of the kill ring */
848 void
849 SetKillRing(int max)
851 CStr *new;
852 int count, i, j;
854 if (max < 1)
855 max = 1; /* no ring, but always one buffer */
856 if (max == KillRingMax)
857 return;
858 new = xcalloc(max, sizeof(CStr));
859 if (KillRing != NULL) {
860 if (KillRingLen != 0) {
861 if (max >= KillRingLen) {
862 count = KillRingLen;
863 j = KillPos;
864 } else {
865 count = max;
866 j = (KillPos - count + KillRingLen) % KillRingLen;
868 for (i = 0; i < KillRingLen; i++) {
869 if (i < count) /* copy latest */
870 new[i] = KillRing[j];
871 else /* free the others */
872 xfree(KillRing[j].buf);
873 j = (j + 1) % KillRingLen;
875 KillRingLen = count;
876 KillPos = count % max;
877 YankPos = count - 1;
879 xfree(KillRing);
881 KillRing = new;
882 KillRingMax = max;
885 /* Push string from start upto (but not including) end onto kill ring */
886 static void
887 c_push_kill(Char *start, Char *end)
889 CStr save, *pos;
890 Char *dp, *cp, *kp;
891 int len = end - start, i, j, k;
893 /* Check for duplicates? */
894 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
895 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
896 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
897 j = YankPos;
898 for (i = 0; i < KillRingLen; i++) {
899 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
900 KillRing[j].buf[len] == '\0') {
901 save = KillRing[j];
902 for ( ; i > 0; i--) {
903 k = j;
904 j = (j + 1) % KillRingLen;
905 KillRing[k] = KillRing[j];
907 KillRing[j] = save;
908 return;
910 j = (j - 1 + KillRingLen) % KillRingLen;
912 } else if (eq(dp, STRall)) { /* skip if any earlier */
913 for (i = 0; i < KillRingLen; i++)
914 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
915 KillRing[i].buf[len] == '\0')
916 return;
917 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
918 j = YankPos;
919 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
920 KillRing[j].buf[len] == '\0')
921 return;
925 /* No duplicate, go ahead and push */
926 len++; /* need space for '\0' */
927 YankPos = KillPos;
928 if (KillRingLen < KillRingMax)
929 KillRingLen++;
930 pos = &KillRing[KillPos];
931 KillPos = (KillPos + 1) % KillRingMax;
932 if (pos->len < len) {
933 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
934 pos->len = len;
936 cp = start;
937 kp = pos->buf;
938 while (cp < end)
939 *kp++ = *cp++;
940 *kp = '\0';
943 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
944 static void
945 c_save_inputbuf()
947 SavedBuf.len = 0;
948 Strbuf_append(&SavedBuf, InputBuf);
949 Strbuf_terminate(&SavedBuf);
950 LastSaved = LastChar - InputBuf;
951 CursSaved = Cursor - InputBuf;
952 HistSaved = Hist_num;
953 RestoreSaved = 1;
956 CCRETVAL
957 GetHistLine()
959 struct Hist *hp;
960 int h;
962 if (Hist_num == 0) { /* if really the current line */
963 if (HistBuf.s != NULL)
964 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
965 else
966 *InputBuf = '\0';
967 LastChar = InputBuf + HistBuf.len;
969 #ifdef KSHVI
970 if (VImode)
971 Cursor = InputBuf;
972 else
973 #endif /* KSHVI */
974 Cursor = LastChar;
976 return(CC_REFRESH);
979 hp = Histlist.Hnext;
980 if (hp == NULL)
981 return(CC_ERROR);
983 for (h = 1; h < Hist_num; h++) {
984 if ((hp->Hnext) == NULL) {
985 Hist_num = h;
986 return(CC_ERROR);
988 hp = hp->Hnext;
991 if (HistLit && hp->histline) {
992 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
993 CurrentHistLit = 1;
995 else {
996 Char *p;
998 p = sprlex(&hp->Hlex);
999 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1000 xfree(p);
1001 CurrentHistLit = 0;
1003 LastChar = Strend(InputBuf);
1005 if (LastChar > InputBuf) {
1006 if (LastChar[-1] == '\n')
1007 LastChar--;
1008 #if 0
1009 if (LastChar[-1] == ' ')
1010 LastChar--;
1011 #endif
1012 if (LastChar < InputBuf)
1013 LastChar = InputBuf;
1016 #ifdef KSHVI
1017 if (VImode)
1018 Cursor = InputBuf;
1019 else
1020 #endif /* KSHVI */
1021 Cursor = LastChar;
1023 return(CC_REFRESH);
1026 static CCRETVAL
1027 c_search_line(Char *pattern, int dir)
1029 Char *cp;
1030 size_t len;
1032 len = Strlen(pattern);
1034 if (dir == F_UP_SEARCH_HIST) {
1035 for (cp = Cursor; cp >= InputBuf; cp--)
1036 if (Strncmp(cp, pattern, len) == 0 ||
1037 Gmatch(cp, pattern)) {
1038 Cursor = cp;
1039 return(CC_NORM);
1041 return(CC_ERROR);
1042 } else {
1043 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1044 if (Strncmp(cp, pattern, len) == 0 ||
1045 Gmatch(cp, pattern)) {
1046 Cursor = cp;
1047 return(CC_NORM);
1049 return(CC_ERROR);
1053 static CCRETVAL
1054 e_inc_search(int dir)
1056 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1057 STRbck[] = { 'b', 'c', 'k', '\0' };
1058 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1059 static Char endcmd[2];
1060 const Char *cp;
1061 Char ch,
1062 *oldCursor = Cursor,
1063 oldpchar = pchar;
1064 CCRETVAL ret = CC_NORM;
1065 int oldHist_num = Hist_num,
1066 oldpatlen = patbuf.len,
1067 newdir = dir,
1068 done, redo;
1070 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1071 return(CC_ERROR);
1073 for (;;) {
1075 if (patbuf.len == 0) { /* first round */
1076 pchar = ':';
1077 Strbuf_append1(&patbuf, '*');
1079 done = redo = 0;
1080 *LastChar++ = '\n';
1081 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1082 *cp; *LastChar++ = *cp++)
1083 continue;
1084 *LastChar++ = pchar;
1085 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1086 *LastChar++ = *cp++)
1087 continue;
1088 *LastChar = '\0';
1089 if (adrof(STRhighlight) && pchar == ':') {
1090 /* if the no-glob-search patch is applied, remove the - 1 below */
1091 IncMatchLen = patbuf.len - 1;
1092 ClearLines();
1093 ClearDisp();
1095 Refresh();
1097 if (GetNextChar(&ch) != 1)
1098 return(e_send_eof(0));
1100 switch (ch > NT_NUM_KEYS
1101 ? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
1102 case F_INSERT:
1103 case F_DIGIT:
1104 case F_MAGIC_SPACE:
1105 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1106 SoundBeep();
1107 else {
1108 Strbuf_append1(&patbuf, ch);
1109 *LastChar++ = ch;
1110 *LastChar = '\0';
1111 Refresh();
1113 break;
1115 case F_INC_FWD:
1116 newdir = F_DOWN_SEARCH_HIST;
1117 redo++;
1118 break;
1120 case F_INC_BACK:
1121 newdir = F_UP_SEARCH_HIST;
1122 redo++;
1123 break;
1125 case F_DELPREV:
1126 if (patbuf.len > 1)
1127 done++;
1128 else
1129 SoundBeep();
1130 break;
1132 default:
1133 switch (ASC(ch)) {
1134 case 0007: /* ^G: Abort */
1135 ret = CC_ERROR;
1136 done++;
1137 break;
1139 case 0027: /* ^W: Append word */
1140 /* No can do if globbing characters in pattern */
1141 for (cp = &patbuf.s[1]; ; cp++)
1142 if (cp >= &patbuf.s[patbuf.len]) {
1143 Cursor += patbuf.len - 1;
1144 cp = c_next_word(Cursor, LastChar, 1);
1145 while (Cursor < cp && *Cursor != '\n') {
1146 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1147 SoundBeep();
1148 break;
1150 Strbuf_append1(&patbuf, *Cursor);
1151 *LastChar++ = *Cursor++;
1153 Cursor = oldCursor;
1154 *LastChar = '\0';
1155 Refresh();
1156 break;
1157 } else if (isglob(*cp)) {
1158 SoundBeep();
1159 break;
1161 break;
1163 default: /* Terminate and execute cmd */
1164 endcmd[0] = ch;
1165 PushMacro(endcmd);
1166 /*FALLTHROUGH*/
1168 case 0033: /* ESC: Terminate */
1169 ret = CC_REFRESH;
1170 done++;
1171 break;
1173 break;
1176 while (LastChar > InputBuf && *LastChar != '\n')
1177 *LastChar-- = '\0';
1178 *LastChar = '\0';
1180 if (!done) {
1182 /* Can't search if unmatched '[' */
1183 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1184 if (*cp == '[' || *cp == ']') {
1185 ch = *cp;
1186 break;
1189 if (patbuf.len > 1 && ch != '[') {
1190 if (redo && newdir == dir) {
1191 if (pchar == '?') { /* wrap around */
1192 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1193 if (GetHistLine() == CC_ERROR)
1194 /* Hist_num was fixed by first call */
1195 (void) GetHistLine();
1196 Cursor = newdir == F_UP_SEARCH_HIST ?
1197 LastChar : InputBuf;
1198 } else
1199 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1201 Strbuf_append1(&patbuf, '*');
1202 Strbuf_terminate(&patbuf);
1203 if (Cursor < InputBuf || Cursor > LastChar ||
1204 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1205 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1206 ret = newdir == F_UP_SEARCH_HIST ?
1207 e_up_search_hist(0) : e_down_search_hist(0);
1208 if (ret != CC_ERROR) {
1209 Cursor = newdir == F_UP_SEARCH_HIST ?
1210 LastChar : InputBuf;
1211 (void) c_search_line(&patbuf.s[1], newdir);
1214 patbuf.s[--patbuf.len] = '\0';
1215 if (ret == CC_ERROR) {
1216 SoundBeep();
1217 if (Hist_num != oldHist_num) {
1218 Hist_num = oldHist_num;
1219 if (GetHistLine() == CC_ERROR)
1220 return(CC_ERROR);
1222 Cursor = oldCursor;
1223 pchar = '?';
1224 } else {
1225 pchar = ':';
1229 ret = e_inc_search(newdir);
1231 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1232 /* break abort of failed search at last non-failed */
1233 ret = CC_NORM;
1238 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1239 /* restore on normal return or error exit */
1240 pchar = oldpchar;
1241 patbuf.len = oldpatlen;
1242 if (Hist_num != oldHist_num) {
1243 Hist_num = oldHist_num;
1244 if (GetHistLine() == CC_ERROR)
1245 return(CC_ERROR);
1247 Cursor = oldCursor;
1248 if (ret == CC_ERROR)
1249 Refresh();
1251 if (done || ret != CC_NORM)
1252 return(ret);
1258 static CCRETVAL
1259 v_search(int dir)
1261 struct Strbuf tmpbuf = Strbuf_INIT;
1262 Char ch;
1263 Char *oldbuf;
1264 Char *oldlc, *oldc;
1266 cleanup_push(&tmpbuf, Strbuf_cleanup);
1267 oldbuf = Strsave(InputBuf);
1268 cleanup_push(oldbuf, xfree);
1269 oldlc = LastChar;
1270 oldc = Cursor;
1271 Strbuf_append1(&tmpbuf, '*');
1273 InputBuf[0] = '\0';
1274 LastChar = InputBuf;
1275 Cursor = InputBuf;
1276 searchdir = dir;
1278 c_insert(2); /* prompt + '\n' */
1279 *Cursor++ = '\n';
1280 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1281 Refresh();
1282 for (ch = 0;ch == 0;) {
1283 if (GetNextChar(&ch) != 1) {
1284 cleanup_until(&tmpbuf);
1285 return(e_send_eof(0));
1287 switch (ASC(ch)) {
1288 case 0010: /* Delete and backspace */
1289 case 0177:
1290 if (tmpbuf.len > 1) {
1291 *Cursor-- = '\0';
1292 LastChar = Cursor;
1293 tmpbuf.len--;
1295 else {
1296 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1297 LastChar = oldlc;
1298 Cursor = oldc;
1299 cleanup_until(&tmpbuf);
1300 return(CC_REFRESH);
1302 Refresh();
1303 ch = 0;
1304 break;
1306 case 0033: /* ESC */
1307 #ifdef IS_ASCII
1308 case '\r': /* Newline */
1309 case '\n':
1310 #else
1311 case '\012': /* ASCII Line feed */
1312 case '\015': /* ASCII (or EBCDIC) Return */
1313 #endif
1314 break;
1316 default:
1317 Strbuf_append1(&tmpbuf, ch);
1318 *Cursor++ = ch;
1319 LastChar = Cursor;
1320 Refresh();
1321 ch = 0;
1322 break;
1325 cleanup_until(oldbuf);
1327 if (tmpbuf.len == 1) {
1329 * Use the old pattern, but wild-card it.
1331 if (patbuf.len == 0) {
1332 InputBuf[0] = '\0';
1333 LastChar = InputBuf;
1334 Cursor = InputBuf;
1335 Refresh();
1336 cleanup_until(&tmpbuf);
1337 return(CC_ERROR);
1339 if (patbuf.s[0] != '*') {
1340 oldbuf = Strsave(patbuf.s);
1341 patbuf.len = 0;
1342 Strbuf_append1(&patbuf, '*');
1343 Strbuf_append(&patbuf, oldbuf);
1344 xfree(oldbuf);
1345 Strbuf_append1(&patbuf, '*');
1346 Strbuf_terminate(&patbuf);
1349 else {
1350 Strbuf_append1(&tmpbuf, '*');
1351 Strbuf_terminate(&tmpbuf);
1352 patbuf.len = 0;
1353 Strbuf_append(&patbuf, tmpbuf.s);
1354 Strbuf_terminate(&patbuf);
1356 cleanup_until(&tmpbuf);
1357 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1358 Cursor = LastChar = InputBuf;
1359 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1360 e_down_search_hist(0)) == CC_ERROR) {
1361 Refresh();
1362 return(CC_ERROR);
1364 else {
1365 if (ASC(ch) == 0033) {
1366 Refresh();
1367 *LastChar++ = '\n';
1368 *LastChar = '\0';
1369 PastBottom();
1370 return(CC_NEWLINE);
1372 else
1373 return(CC_REFRESH);
1378 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1379 * entry point, called from the CcKeyMap indirected into the
1380 * CcFuncTbl array.
1383 /*ARGSUSED*/
1384 CCRETVAL
1385 v_cmd_mode(Char c)
1387 USE(c);
1388 InsertPos = 0;
1389 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1390 ActionPos = 0;
1391 DoingArg = 0;
1392 if (UndoPtr > Cursor)
1393 UndoSize = (int)(UndoPtr - Cursor);
1394 else
1395 UndoSize = (int)(Cursor - UndoPtr);
1397 inputmode = MODE_INSERT;
1398 c_alternativ_key_map(1);
1399 #ifdef notdef
1401 * We don't want to move the cursor, because all the editing
1402 * commands don't include the character under the cursor.
1404 if (Cursor > InputBuf)
1405 Cursor--;
1406 #endif
1407 RefCursor();
1408 return(CC_NORM);
1411 /*ARGSUSED*/
1412 CCRETVAL
1413 e_unassigned(Char c)
1414 { /* bound to keys that arn't really assigned */
1415 USE(c);
1416 SoundBeep();
1417 flush();
1418 return(CC_NORM);
1421 #ifdef notyet
1422 static CCRETVAL
1423 e_insert_str(Char *c)
1425 int i, n;
1427 n = Strlen(c);
1428 if (LastChar + Argument * n >= InputLim)
1429 return(CC_ERROR); /* end of buffer space */
1430 if (inputmode != MODE_INSERT) {
1431 c_delafter(Argument * Strlen(c));
1433 c_insert(Argument * n);
1434 while (Argument--) {
1435 for (i = 0; i < n; i++)
1436 *Cursor++ = c[i];
1438 Refresh();
1439 return(CC_NORM);
1441 #endif
1443 CCRETVAL
1444 e_insert(Char c)
1446 #ifndef SHORT_STRINGS
1447 c &= ASCII; /* no meta chars ever */
1448 #endif
1450 if (!c)
1451 return(CC_ERROR); /* no NULs in the input ever!! */
1453 if (LastChar + Argument >= InputLim)
1454 return(CC_ERROR); /* end of buffer space */
1456 if (Argument == 1) { /* How was this optimized ???? */
1458 if (inputmode != MODE_INSERT) {
1459 UndoBuf[UndoSize++] = *Cursor;
1460 UndoBuf[UndoSize] = '\0';
1461 c_delafter(1); /* Do NOT use the saving ONE */
1464 c_insert(1);
1465 *Cursor++ = (Char) c;
1466 DoingArg = 0; /* just in case */
1467 RefPlusOne(1); /* fast refresh for one char. */
1469 else {
1470 if (inputmode != MODE_INSERT) {
1471 int i;
1472 for(i = 0; i < Argument; i++)
1473 UndoBuf[UndoSize++] = *(Cursor + i);
1475 UndoBuf[UndoSize] = '\0';
1476 c_delafter(Argument); /* Do NOT use the saving ONE */
1479 c_insert(Argument);
1481 while (Argument--)
1482 *Cursor++ = (Char) c;
1483 Refresh();
1486 if (inputmode == MODE_REPLACE_1)
1487 (void) v_cmd_mode(0);
1489 return(CC_NORM);
1493 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1495 int len;
1497 if ((len = (int) Strlen(s)) <= 0)
1498 return -1;
1499 if (LastChar + len >= InputLim)
1500 return -1; /* end of buffer space */
1502 c_insert(len);
1503 while (len--)
1504 *Cursor++ = *s++;
1505 return 0;
1508 void
1509 DeleteBack(int n) /* delete the n characters before . */
1511 if (n <= 0)
1512 return;
1513 if (Cursor >= &InputBuf[n]) {
1514 c_delbefore(n); /* delete before dot */
1518 CCRETVAL
1519 e_digit(Char c) /* gray magic here */
1521 if (!Isdigit(c))
1522 return(CC_ERROR); /* no NULs in the input ever!! */
1524 if (DoingArg) { /* if doing an arg, add this in... */
1525 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1526 Argument = c - '0';
1527 else {
1528 if (Argument > 1000000)
1529 return CC_ERROR;
1530 Argument = (Argument * 10) + (c - '0');
1532 return(CC_ARGHACK);
1534 else {
1535 if (LastChar + 1 >= InputLim)
1536 return CC_ERROR; /* end of buffer space */
1538 if (inputmode != MODE_INSERT) {
1539 UndoBuf[UndoSize++] = *Cursor;
1540 UndoBuf[UndoSize] = '\0';
1541 c_delafter(1); /* Do NOT use the saving ONE */
1543 c_insert(1);
1544 *Cursor++ = (Char) c;
1545 DoingArg = 0; /* just in case */
1546 RefPlusOne(1); /* fast refresh for one char. */
1548 return(CC_NORM);
1551 CCRETVAL
1552 e_argdigit(Char c) /* for ESC-n */
1554 #ifdef IS_ASCII
1555 c &= ASCII;
1556 #else
1557 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1558 #endif
1560 if (!Isdigit(c))
1561 return(CC_ERROR); /* no NULs in the input ever!! */
1563 if (DoingArg) { /* if doing an arg, add this in... */
1564 if (Argument > 1000000)
1565 return CC_ERROR;
1566 Argument = (Argument * 10) + (c - '0');
1568 else { /* else starting an argument */
1569 Argument = c - '0';
1570 DoingArg = 1;
1572 return(CC_ARGHACK);
1575 CCRETVAL
1576 v_zero(Char c) /* command mode 0 for vi */
1578 if (DoingArg) { /* if doing an arg, add this in... */
1579 if (Argument > 1000000)
1580 return CC_ERROR;
1581 Argument = (Argument * 10) + (c - '0');
1582 return(CC_ARGHACK);
1584 else { /* else starting an argument */
1585 Cursor = InputBuf;
1586 if (ActionFlag & TCSHOP_DELETE) {
1587 c_delfini();
1588 return(CC_REFRESH);
1590 RefCursor(); /* move the cursor */
1591 return(CC_NORM);
1595 /*ARGSUSED*/
1596 CCRETVAL
1597 e_newline(Char c)
1598 { /* always ignore argument */
1599 USE(c);
1600 if (adrof(STRhighlight) && MarkIsSet) {
1601 MarkIsSet = 0;
1602 ClearLines();
1603 ClearDisp();
1604 Refresh();
1606 MarkIsSet = 0;
1608 /* PastBottom(); NOW done in ed.inputl.c */
1609 *LastChar++ = '\n'; /* for the benefit of CSH */
1610 *LastChar = '\0'; /* just in case */
1611 if (VImode)
1612 InsertPos = InputBuf; /* Reset editing position */
1613 return(CC_NEWLINE);
1616 /*ARGSUSED*/
1617 CCRETVAL
1618 e_newline_hold(Char c)
1620 USE(c);
1621 c_save_inputbuf();
1622 HistSaved = 0;
1623 *LastChar++ = '\n'; /* for the benefit of CSH */
1624 *LastChar = '\0'; /* just in case */
1625 return(CC_NEWLINE);
1628 /*ARGSUSED*/
1629 CCRETVAL
1630 e_newline_down_hist(Char c)
1632 USE(c);
1633 if (Hist_num > 1) {
1634 HistSaved = Hist_num;
1636 *LastChar++ = '\n'; /* for the benefit of CSH */
1637 *LastChar = '\0'; /* just in case */
1638 return(CC_NEWLINE);
1641 /*ARGSUSED*/
1642 CCRETVAL
1643 e_send_eof(Char c)
1644 { /* for when ^D is ONLY send-eof */
1645 USE(c);
1646 PastBottom();
1647 *LastChar = '\0'; /* just in case */
1648 return(CC_EOF);
1651 /*ARGSUSED*/
1652 CCRETVAL
1653 e_complete(Char c)
1655 USE(c);
1656 *LastChar = '\0'; /* just in case */
1657 return(CC_COMPLETE);
1660 /*ARGSUSED*/
1661 CCRETVAL
1662 e_complete_back(Char c)
1664 USE(c);
1665 *LastChar = '\0'; /* just in case */
1666 return(CC_COMPLETE_BACK);
1669 /*ARGSUSED*/
1670 CCRETVAL
1671 e_complete_fwd(Char c)
1673 USE(c);
1674 *LastChar = '\0'; /* just in case */
1675 return(CC_COMPLETE_FWD);
1678 /*ARGSUSED*/
1679 CCRETVAL
1680 e_complete_all(Char c)
1682 USE(c);
1683 *LastChar = '\0'; /* just in case */
1684 return(CC_COMPLETE_ALL);
1687 /*ARGSUSED*/
1688 CCRETVAL
1689 v_cm_complete(Char c)
1691 USE(c);
1692 if (Cursor < LastChar)
1693 Cursor++;
1694 *LastChar = '\0'; /* just in case */
1695 return(CC_COMPLETE);
1698 /*ARGSUSED*/
1699 CCRETVAL
1700 e_toggle_hist(Char c)
1702 struct Hist *hp;
1703 int h;
1705 USE(c);
1706 *LastChar = '\0'; /* just in case */
1708 if (Hist_num <= 0) {
1709 return CC_ERROR;
1712 hp = Histlist.Hnext;
1713 if (hp == NULL) { /* this is only if no history */
1714 return(CC_ERROR);
1717 for (h = 1; h < Hist_num; h++)
1718 hp = hp->Hnext;
1720 if (!CurrentHistLit) {
1721 if (hp->histline) {
1722 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1723 CurrentHistLit = 1;
1725 else {
1726 return CC_ERROR;
1729 else {
1730 Char *p;
1732 p = sprlex(&hp->Hlex);
1733 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1734 xfree(p);
1735 CurrentHistLit = 0;
1738 LastChar = Strend(InputBuf);
1739 if (LastChar > InputBuf) {
1740 if (LastChar[-1] == '\n')
1741 LastChar--;
1742 if (LastChar[-1] == ' ')
1743 LastChar--;
1744 if (LastChar < InputBuf)
1745 LastChar = InputBuf;
1748 #ifdef KSHVI
1749 if (VImode)
1750 Cursor = InputBuf;
1751 else
1752 #endif /* KSHVI */
1753 Cursor = LastChar;
1755 return(CC_REFRESH);
1758 /*ARGSUSED*/
1759 CCRETVAL
1760 e_up_hist(Char c)
1762 Char beep = 0;
1764 USE(c);
1765 UndoAction = TCSHOP_NOP;
1766 *LastChar = '\0'; /* just in case */
1768 if (Hist_num == 0) { /* save the current buffer away */
1769 HistBuf.len = 0;
1770 Strbuf_append(&HistBuf, InputBuf);
1771 Strbuf_terminate(&HistBuf);
1774 Hist_num += Argument;
1776 if (GetHistLine() == CC_ERROR) {
1777 beep = 1;
1778 (void) GetHistLine(); /* Hist_num was fixed by first call */
1781 Refresh();
1782 if (beep)
1783 return(CC_ERROR);
1784 else
1785 return(CC_NORM); /* was CC_UP_HIST */
1788 /*ARGSUSED*/
1789 CCRETVAL
1790 e_down_hist(Char c)
1792 USE(c);
1793 UndoAction = TCSHOP_NOP;
1794 *LastChar = '\0'; /* just in case */
1796 Hist_num -= Argument;
1798 if (Hist_num < 0) {
1799 Hist_num = 0;
1800 return(CC_ERROR); /* make it beep */
1803 return(GetHistLine());
1809 * c_hmatch() return True if the pattern matches the prefix
1811 static int
1812 c_hmatch(Char *str)
1814 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1815 return 1;
1816 return Gmatch(str, patbuf.s);
1820 * c_hsetpat(): Set the history seatch pattern
1822 static void
1823 c_hsetpat(void)
1825 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1826 patbuf.len = 0;
1827 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1828 Strbuf_terminate(&patbuf);
1830 #ifdef SDEBUG
1831 xprintf("\nHist_num = %d\n", Hist_num);
1832 xprintf("patlen = %d\n", (int)patbuf.len);
1833 xprintf("patbuf = \"%S\"\n", patbuf.s);
1834 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1835 #endif
1838 /*ARGSUSED*/
1839 CCRETVAL
1840 e_up_search_hist(Char c)
1842 struct Hist *hp;
1843 int h;
1844 int found = 0;
1846 USE(c);
1847 ActionFlag = TCSHOP_NOP;
1848 UndoAction = TCSHOP_NOP;
1849 *LastChar = '\0'; /* just in case */
1850 if (Hist_num < 0) {
1851 #ifdef DEBUG_EDIT
1852 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1853 #endif
1854 Hist_num = 0;
1855 return(CC_ERROR);
1858 if (Hist_num == 0) {
1859 HistBuf.len = 0;
1860 Strbuf_append(&HistBuf, InputBuf);
1861 Strbuf_terminate(&HistBuf);
1865 hp = Histlist.Hnext;
1866 if (hp == NULL)
1867 return(CC_ERROR);
1869 c_hsetpat(); /* Set search pattern !! */
1871 for (h = 1; h <= Hist_num; h++)
1872 hp = hp->Hnext;
1874 while (hp != NULL) {
1875 Char *hl;
1876 int matched;
1878 if (hp->histline == NULL)
1879 hp->histline = sprlex(&hp->Hlex);
1880 if (HistLit)
1881 hl = hp->histline;
1882 else {
1883 hl = sprlex(&hp->Hlex);
1884 cleanup_push(hl, xfree);
1886 #ifdef SDEBUG
1887 xprintf("Comparing with \"%S\"\n", hl);
1888 #endif
1889 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1890 hl[LastChar-InputBuf]) && c_hmatch(hl);
1891 if (!HistLit)
1892 cleanup_until(hl);
1893 if (matched) {
1894 found++;
1895 break;
1897 h++;
1898 hp = hp->Hnext;
1901 if (!found) {
1902 #ifdef SDEBUG
1903 xprintf("not found\n");
1904 #endif
1905 return(CC_ERROR);
1908 Hist_num = h;
1910 return(GetHistLine());
1913 /*ARGSUSED*/
1914 CCRETVAL
1915 e_down_search_hist(Char c)
1917 struct Hist *hp;
1918 int h;
1919 int found = 0;
1921 USE(c);
1922 ActionFlag = TCSHOP_NOP;
1923 UndoAction = TCSHOP_NOP;
1924 *LastChar = '\0'; /* just in case */
1926 if (Hist_num == 0)
1927 return(CC_ERROR);
1929 hp = Histlist.Hnext;
1930 if (hp == 0)
1931 return(CC_ERROR);
1933 c_hsetpat(); /* Set search pattern !! */
1935 for (h = 1; h < Hist_num && hp; h++) {
1936 Char *hl;
1937 if (hp->histline == NULL)
1938 hp->histline = sprlex(&hp->Hlex);
1939 if (HistLit)
1940 hl = hp->histline;
1941 else {
1942 hl = sprlex(&hp->Hlex);
1943 cleanup_push(hl, xfree);
1945 #ifdef SDEBUG
1946 xprintf("Comparing with \"%S\"\n", hl);
1947 #endif
1948 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1949 hl[LastChar-InputBuf]) && c_hmatch(hl))
1950 found = h;
1951 if (!HistLit)
1952 cleanup_until(hl);
1953 hp = hp->Hnext;
1956 if (!found) { /* is it the current history number? */
1957 if (!c_hmatch(HistBuf.s)) {
1958 #ifdef SDEBUG
1959 xprintf("not found\n");
1960 #endif
1961 return(CC_ERROR);
1965 Hist_num = found;
1967 return(GetHistLine());
1970 /*ARGSUSED*/
1971 CCRETVAL
1972 e_helpme(Char c)
1974 USE(c);
1975 PastBottom();
1976 *LastChar = '\0'; /* just in case */
1977 return(CC_HELPME);
1980 /*ARGSUSED*/
1981 CCRETVAL
1982 e_correct(Char c)
1984 USE(c);
1985 *LastChar = '\0'; /* just in case */
1986 return(CC_CORRECT);
1989 /*ARGSUSED*/
1990 CCRETVAL
1991 e_correctl(Char c)
1993 USE(c);
1994 *LastChar = '\0'; /* just in case */
1995 return(CC_CORRECT_L);
1998 /*ARGSUSED*/
1999 CCRETVAL
2000 e_run_fg_editor(Char c)
2002 struct process *pp;
2004 USE(c);
2005 if ((pp = find_stop_ed()) != NULL) {
2006 /* save our editor state so we can restore it */
2007 c_save_inputbuf();
2008 Hist_num = 0; /* for the history commands */
2010 /* put the tty in a sane mode */
2011 PastBottom();
2012 (void) Cookedmode(); /* make sure the tty is set up correctly */
2014 /* do it! */
2015 fg_proc_entry(pp);
2017 (void) Rawmode(); /* go on */
2018 Refresh();
2019 RestoreSaved = 0;
2020 HistSaved = 0;
2022 return(CC_NORM);
2025 /*ARGSUSED*/
2026 CCRETVAL
2027 e_list_choices(Char c)
2029 USE(c);
2030 PastBottom();
2031 *LastChar = '\0'; /* just in case */
2032 return(CC_LIST_CHOICES);
2035 /*ARGSUSED*/
2036 CCRETVAL
2037 e_list_all(Char c)
2039 USE(c);
2040 PastBottom();
2041 *LastChar = '\0'; /* just in case */
2042 return(CC_LIST_ALL);
2045 /*ARGSUSED*/
2046 CCRETVAL
2047 e_list_glob(Char c)
2049 USE(c);
2050 PastBottom();
2051 *LastChar = '\0'; /* just in case */
2052 return(CC_LIST_GLOB);
2055 /*ARGSUSED*/
2056 CCRETVAL
2057 e_expand_glob(Char c)
2059 USE(c);
2060 *LastChar = '\0'; /* just in case */
2061 return(CC_EXPAND_GLOB);
2064 /*ARGSUSED*/
2065 CCRETVAL
2066 e_normalize_path(Char c)
2068 USE(c);
2069 *LastChar = '\0'; /* just in case */
2070 return(CC_NORMALIZE_PATH);
2073 /*ARGSUSED*/
2074 CCRETVAL
2075 e_normalize_command(Char c)
2077 USE(c);
2078 *LastChar = '\0'; /* just in case */
2079 return(CC_NORMALIZE_COMMAND);
2082 /*ARGSUSED*/
2083 CCRETVAL
2084 e_expand_vars(Char c)
2086 USE(c);
2087 *LastChar = '\0'; /* just in case */
2088 return(CC_EXPAND_VARS);
2091 /*ARGSUSED*/
2092 CCRETVAL
2093 e_which(Char c)
2094 { /* do a fast command line which(1) */
2095 USE(c);
2096 c_save_inputbuf();
2097 Hist_num = 0; /* for the history commands */
2098 PastBottom();
2099 *LastChar = '\0'; /* just in case */
2100 return(CC_WHICH);
2103 /*ARGSUSED*/
2104 CCRETVAL
2105 e_last_item(Char c)
2106 { /* insert the last element of the prev. cmd */
2107 struct Hist *hp;
2108 struct wordent *wp, *firstp;
2109 int i;
2110 Char *expanded;
2112 USE(c);
2113 if (Argument <= 0)
2114 return(CC_ERROR);
2116 hp = Histlist.Hnext;
2117 if (hp == NULL) { /* this is only if no history */
2118 return(CC_ERROR);
2121 wp = (hp->Hlex).prev;
2123 if (wp->prev == (struct wordent *) NULL)
2124 return(CC_ERROR); /* an empty history entry */
2126 firstp = (hp->Hlex).next;
2128 /* back up arg words in lex */
2129 for (i = 0; i < Argument && wp != firstp; i++) {
2130 wp = wp->prev;
2133 expanded = expand_lex(wp->prev, 0, i - 1);
2134 if (InsertStr(expanded)) {
2135 xfree(expanded);
2136 return(CC_ERROR);
2139 xfree(expanded);
2140 return(CC_REFRESH);
2143 /*ARGSUSED*/
2144 CCRETVAL
2145 e_dabbrev_expand(Char c)
2146 { /* expand to preceding word matching prefix */
2147 Char *cp, *ncp, *bp;
2148 struct Hist *hp;
2149 int arg = 0, i;
2150 size_t len = 0;
2151 int found = 0;
2152 Char *hbuf;
2153 static int oldevent, hist, word;
2154 static Char *start, *oldcursor;
2156 USE(c);
2157 if (Argument <= 0)
2158 return(CC_ERROR);
2160 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2161 if (cp == Cursor || Isspace(*cp))
2162 return(CC_ERROR);
2164 hbuf = NULL;
2165 hp = Histlist.Hnext;
2166 bp = InputBuf;
2167 if (Argument == 1 && eventno == oldevent && cp == start &&
2168 Cursor == oldcursor && patbuf.len > 0
2169 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2170 /* continue previous search - go to last match (hist/word) */
2171 if (hist != 0) { /* need to move up history */
2172 for (i = 1; i < hist && hp != NULL; i++)
2173 hp = hp->Hnext;
2174 if (hp == NULL) /* "can't happen" */
2175 goto err_hbuf;
2176 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2177 cp = Strend(hbuf);
2178 bp = hbuf;
2179 hp = hp->Hnext;
2181 cp = c_preword(cp, bp, word, STRshwordsep);
2182 } else { /* starting new search */
2183 oldevent = eventno;
2184 start = cp;
2185 patbuf.len = 0;
2186 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2187 hist = 0;
2188 word = 0;
2191 while (!found) {
2192 ncp = c_preword(cp, bp, 1, STRshwordsep);
2193 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2194 hist++;
2195 word = 0;
2196 if (hp == NULL)
2197 goto err_hbuf;
2198 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2199 cp = Strend(hbuf);
2200 bp = hbuf;
2201 hp = hp->Hnext;
2202 continue;
2203 } else {
2204 word++;
2205 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2206 cp = ncp;
2208 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2209 /* We don't fully check distinct matches as Gnuemacs does: */
2210 if (Argument > 1) { /* just count matches */
2211 if (++arg >= Argument)
2212 found++;
2213 } else { /* match if distinct from previous */
2214 if (len != (size_t)(Cursor - start)
2215 || Strncmp(cp, start, len) != 0)
2216 found++;
2221 if (LastChar + len - (Cursor - start) >= InputLim)
2222 goto err_hbuf; /* no room */
2223 DeleteBack(Cursor - start);
2224 c_insert(len);
2225 while (len--)
2226 *Cursor++ = *cp++;
2227 oldcursor = Cursor;
2228 xfree(hbuf);
2229 return(CC_REFRESH);
2231 err_hbuf:
2232 xfree(hbuf);
2233 return CC_ERROR;
2236 /*ARGSUSED*/
2237 CCRETVAL
2238 e_yank_kill(Char c)
2239 { /* almost like GnuEmacs */
2240 int len;
2241 Char *kp, *cp;
2243 USE(c);
2244 if (KillRingLen == 0) /* nothing killed */
2245 return(CC_ERROR);
2246 len = Strlen(KillRing[YankPos].buf);
2247 if (LastChar + len >= InputLim)
2248 return(CC_ERROR); /* end of buffer space */
2250 /* else */
2251 cp = Cursor; /* for speed */
2253 c_insert(len); /* open the space, */
2254 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2255 *cp++ = *kp;
2257 if (Argument == 1) { /* if no arg */
2258 Mark = Cursor; /* mark at beginning, cursor at end */
2259 Cursor = cp;
2260 } else {
2261 Mark = cp; /* else cursor at beginning, mark at end */
2264 if (adrof(STRhighlight) && MarkIsSet) {
2265 ClearLines();
2266 ClearDisp();
2268 MarkIsSet = 0;
2269 return(CC_REFRESH);
2272 /*ARGSUSED*/
2273 CCRETVAL
2274 e_yank_pop(Char c)
2275 { /* almost like GnuEmacs */
2276 int m_bef_c, del_len, ins_len;
2277 Char *kp, *cp;
2279 USE(c);
2281 #if 0
2282 /* XXX This "should" be here, but doesn't work, since LastCmd
2283 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2284 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2285 second one will "succeed" even if the first one wasn't preceded
2286 by a yank, and giving an argument is impossible. Now we "succeed"
2287 regardless of previous command, which is wrong too of course. */
2288 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2289 return(CC_ERROR);
2290 #endif
2292 if (KillRingLen == 0) /* nothing killed */
2293 return(CC_ERROR);
2294 YankPos -= Argument;
2295 while (YankPos < 0)
2296 YankPos += KillRingLen;
2297 YankPos %= KillRingLen;
2299 if (Cursor > Mark) {
2300 del_len = Cursor - Mark;
2301 m_bef_c = 1;
2302 } else {
2303 del_len = Mark - Cursor;
2304 m_bef_c = 0;
2306 ins_len = Strlen(KillRing[YankPos].buf);
2307 if (LastChar + ins_len - del_len >= InputLim)
2308 return(CC_ERROR); /* end of buffer space */
2310 if (m_bef_c) {
2311 c_delbefore(del_len);
2312 } else {
2313 c_delafter(del_len);
2315 cp = Cursor; /* for speed */
2317 c_insert(ins_len); /* open the space, */
2318 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2319 *cp++ = *kp;
2321 if (m_bef_c) {
2322 Mark = Cursor; /* mark at beginning, cursor at end */
2323 Cursor = cp;
2324 } else {
2325 Mark = cp; /* else cursor at beginning, mark at end */
2328 if (adrof(STRhighlight) && MarkIsSet) {
2329 ClearLines();
2330 ClearDisp();
2332 MarkIsSet = 0;
2333 return(CC_REFRESH);
2336 /*ARGSUSED*/
2337 CCRETVAL
2338 v_delprev(Char c) /* Backspace key in insert mode */
2340 int rc;
2342 USE(c);
2343 rc = CC_ERROR;
2345 if (InsertPos != 0) {
2346 if (Argument <= Cursor - InsertPos) {
2347 c_delbefore(Argument); /* delete before */
2348 rc = CC_REFRESH;
2351 return(rc);
2352 } /* v_delprev */
2354 /*ARGSUSED*/
2355 CCRETVAL
2356 e_delprev(Char c)
2358 USE(c);
2359 if (Cursor > InputBuf) {
2360 c_delbefore(Argument); /* delete before dot */
2361 return(CC_REFRESH);
2363 else {
2364 return(CC_ERROR);
2368 /*ARGSUSED*/
2369 CCRETVAL
2370 e_delwordprev(Char c)
2372 Char *cp;
2374 USE(c);
2375 if (Cursor == InputBuf)
2376 return(CC_ERROR);
2377 /* else */
2379 cp = c_prev_word(Cursor, InputBuf, Argument);
2381 c_push_kill(cp, Cursor); /* save the text */
2383 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2384 return(CC_REFRESH);
2387 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2389 * Changed the names of some of the ^D family of editor functions to
2390 * correspond to what they actually do and created new e_delnext_list
2391 * for completeness.
2393 * Old names: New names:
2395 * delete-char delete-char-or-eof
2396 * F_DELNEXT F_DELNEXT_EOF
2397 * e_delnext e_delnext_eof
2398 * edelnxt edelnxteof
2399 * delete-char-or-eof delete-char
2400 * F_DELNEXT_EOF F_DELNEXT
2401 * e_delnext_eof e_delnext
2402 * edelnxteof edelnxt
2403 * delete-char-or-list delete-char-or-list-or-eof
2404 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2405 * e_list_delnext e_delnext_list_eof
2406 * edellsteof
2407 * (no old equivalent) delete-char-or-list
2408 * F_DELNEXT_LIST
2409 * e_delnext_list
2410 * e_delnxtlst
2413 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2414 /* rename e_delnext() -> e_delnext_eof() */
2415 /*ARGSUSED*/
2416 CCRETVAL
2417 e_delnext(Char c)
2419 USE(c);
2420 if (Cursor == LastChar) {/* if I'm at the end */
2421 if (!VImode) {
2422 return(CC_ERROR);
2424 else {
2425 if (Cursor != InputBuf)
2426 Cursor--;
2427 else
2428 return(CC_ERROR);
2431 c_delafter(Argument); /* delete after dot */
2432 if (Cursor > LastChar)
2433 Cursor = LastChar; /* bounds check */
2434 return(CC_REFRESH);
2438 /*ARGSUSED*/
2439 CCRETVAL
2440 e_delnext_eof(Char c)
2442 USE(c);
2443 if (Cursor == LastChar) {/* if I'm at the end */
2444 if (!VImode) {
2445 if (Cursor == InputBuf) {
2446 /* if I'm also at the beginning */
2447 so_write(STReof, 4);/* then do a EOF */
2448 flush();
2449 return(CC_EOF);
2451 else
2452 return(CC_ERROR);
2454 else {
2455 if (Cursor != InputBuf)
2456 Cursor--;
2457 else
2458 return(CC_ERROR);
2461 c_delafter(Argument); /* delete after dot */
2462 if (Cursor > LastChar)
2463 Cursor = LastChar; /* bounds check */
2464 return(CC_REFRESH);
2467 /*ARGSUSED*/
2468 CCRETVAL
2469 e_delnext_list(Char c)
2471 USE(c);
2472 if (Cursor == LastChar) { /* if I'm at the end */
2473 PastBottom();
2474 *LastChar = '\0'; /* just in case */
2475 return(CC_LIST_CHOICES);
2477 else {
2478 c_delafter(Argument); /* delete after dot */
2479 if (Cursor > LastChar)
2480 Cursor = LastChar; /* bounds check */
2481 return(CC_REFRESH);
2485 /*ARGSUSED*/
2486 CCRETVAL
2487 e_delnext_list_eof(Char c)
2489 USE(c);
2490 if (Cursor == LastChar) { /* if I'm at the end */
2491 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2492 so_write(STReof, 4);/* then do a EOF */
2493 flush();
2494 return(CC_EOF);
2496 else {
2497 PastBottom();
2498 *LastChar = '\0'; /* just in case */
2499 return(CC_LIST_CHOICES);
2502 else {
2503 c_delafter(Argument); /* delete after dot */
2504 if (Cursor > LastChar)
2505 Cursor = LastChar; /* bounds check */
2506 return(CC_REFRESH);
2510 /*ARGSUSED*/
2511 CCRETVAL
2512 e_list_eof(Char c)
2514 CCRETVAL rv;
2516 USE(c);
2517 if (Cursor == LastChar && Cursor == InputBuf) {
2518 so_write(STReof, 4); /* then do a EOF */
2519 flush();
2520 rv = CC_EOF;
2522 else {
2523 PastBottom();
2524 *LastChar = '\0'; /* just in case */
2525 rv = CC_LIST_CHOICES;
2527 return rv;
2530 /*ARGSUSED*/
2531 CCRETVAL
2532 e_delwordnext(Char c)
2534 Char *cp;
2536 USE(c);
2537 if (Cursor == LastChar)
2538 return(CC_ERROR);
2539 /* else */
2541 cp = c_next_word(Cursor, LastChar, Argument);
2543 c_push_kill(Cursor, cp); /* save the text */
2545 c_delafter((int)(cp - Cursor)); /* delete after dot */
2546 if (Cursor > LastChar)
2547 Cursor = LastChar; /* bounds check */
2548 return(CC_REFRESH);
2551 /*ARGSUSED*/
2552 CCRETVAL
2553 e_toend(Char c)
2555 USE(c);
2556 Cursor = LastChar;
2557 if (VImode)
2558 if (ActionFlag & TCSHOP_DELETE) {
2559 c_delfini();
2560 return(CC_REFRESH);
2562 RefCursor(); /* move the cursor */
2563 return(CC_NORM);
2566 /*ARGSUSED*/
2567 CCRETVAL
2568 e_tobeg(Char c)
2570 USE(c);
2571 Cursor = InputBuf;
2573 if (VImode) {
2574 while (Isspace(*Cursor)) /* We want FIRST non space character */
2575 Cursor++;
2576 if (ActionFlag & TCSHOP_DELETE) {
2577 c_delfini();
2578 return(CC_REFRESH);
2582 RefCursor(); /* move the cursor */
2583 return(CC_NORM);
2586 /*ARGSUSED*/
2587 CCRETVAL
2588 e_killend(Char c)
2590 USE(c);
2591 c_push_kill(Cursor, LastChar); /* copy it */
2592 LastChar = Cursor; /* zap! -- delete to end */
2593 if (Mark > Cursor)
2594 Mark = Cursor;
2595 MarkIsSet = 0;
2596 return(CC_REFRESH);
2600 /*ARGSUSED*/
2601 CCRETVAL
2602 e_killbeg(Char c)
2604 USE(c);
2605 c_push_kill(InputBuf, Cursor); /* copy it */
2606 c_delbefore((int)(Cursor - InputBuf));
2607 if (Mark && Mark > Cursor)
2608 Mark -= Cursor-InputBuf;
2609 return(CC_REFRESH);
2612 /*ARGSUSED*/
2613 CCRETVAL
2614 e_killall(Char c)
2616 USE(c);
2617 c_push_kill(InputBuf, LastChar); /* copy it */
2618 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2619 MarkIsSet = 0;
2620 return(CC_REFRESH);
2623 /*ARGSUSED*/
2624 CCRETVAL
2625 e_killregion(Char c)
2627 USE(c);
2628 if (!Mark)
2629 return(CC_ERROR);
2631 if (Mark > Cursor) {
2632 c_push_kill(Cursor, Mark); /* copy it */
2633 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2634 Mark = Cursor;
2636 else { /* mark is before cursor */
2637 c_push_kill(Mark, Cursor); /* copy it */
2638 c_delbefore((int)(Cursor - Mark));
2640 if (adrof(STRhighlight) && MarkIsSet) {
2641 ClearLines();
2642 ClearDisp();
2644 MarkIsSet = 0;
2645 return(CC_REFRESH);
2648 /*ARGSUSED*/
2649 CCRETVAL
2650 e_copyregion(Char c)
2652 USE(c);
2653 if (!Mark)
2654 return(CC_ERROR);
2656 if (Mark > Cursor) {
2657 c_push_kill(Cursor, Mark); /* copy it */
2659 else { /* mark is before cursor */
2660 c_push_kill(Mark, Cursor); /* copy it */
2662 return(CC_NORM); /* don't even need to Refresh() */
2665 /*ARGSUSED*/
2666 CCRETVAL
2667 e_charswitch(Char cc)
2669 Char c;
2671 USE(cc);
2673 /* do nothing if we are at beginning of line or have only one char */
2674 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2675 return(CC_ERROR);
2678 if (Cursor < LastChar) {
2679 Cursor++;
2681 c = Cursor[-2];
2682 Cursor[-2] = Cursor[-1];
2683 Cursor[-1] = c;
2684 return(CC_REFRESH);
2687 /*ARGSUSED*/
2688 CCRETVAL
2689 e_gcharswitch(Char cc)
2690 { /* gosmacs style ^T */
2691 Char c;
2693 USE(cc);
2694 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2695 c = Cursor[-2];
2696 Cursor[-2] = Cursor[-1];
2697 Cursor[-1] = c;
2698 return(CC_REFRESH);
2700 else {
2701 return(CC_ERROR);
2705 /*ARGSUSED*/
2706 CCRETVAL
2707 e_charback(Char c)
2709 USE(c);
2710 if (Cursor > InputBuf) {
2711 if (Argument > Cursor - InputBuf)
2712 Cursor = InputBuf;
2713 else
2714 Cursor -= Argument;
2716 if (VImode)
2717 if (ActionFlag & TCSHOP_DELETE) {
2718 c_delfini();
2719 return(CC_REFRESH);
2722 RefCursor();
2723 return(CC_NORM);
2725 else {
2726 return(CC_ERROR);
2730 /*ARGSUSED*/
2731 CCRETVAL
2732 v_wordback(Char c)
2734 USE(c);
2735 if (Cursor == InputBuf)
2736 return(CC_ERROR);
2737 /* else */
2739 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2741 if (ActionFlag & TCSHOP_DELETE) {
2742 c_delfini();
2743 return(CC_REFRESH);
2746 RefCursor();
2747 return(CC_NORM);
2750 /*ARGSUSED*/
2751 CCRETVAL
2752 e_wordback(Char c)
2754 USE(c);
2755 if (Cursor == InputBuf)
2756 return(CC_ERROR);
2757 /* else */
2759 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2761 if (VImode)
2762 if (ActionFlag & TCSHOP_DELETE) {
2763 c_delfini();
2764 return(CC_REFRESH);
2767 RefCursor();
2768 return(CC_NORM);
2771 /*ARGSUSED*/
2772 CCRETVAL
2773 e_charfwd(Char c)
2775 USE(c);
2776 if (Cursor < LastChar) {
2777 Cursor += Argument;
2778 if (Cursor > LastChar)
2779 Cursor = LastChar;
2781 if (VImode)
2782 if (ActionFlag & TCSHOP_DELETE) {
2783 c_delfini();
2784 return(CC_REFRESH);
2787 RefCursor();
2788 return(CC_NORM);
2790 else {
2791 return(CC_ERROR);
2795 /*ARGSUSED*/
2796 CCRETVAL
2797 e_wordfwd(Char c)
2799 USE(c);
2800 if (Cursor == LastChar)
2801 return(CC_ERROR);
2802 /* else */
2804 Cursor = c_next_word(Cursor, LastChar, Argument);
2806 if (VImode)
2807 if (ActionFlag & TCSHOP_DELETE) {
2808 c_delfini();
2809 return(CC_REFRESH);
2812 RefCursor();
2813 return(CC_NORM);
2816 /*ARGSUSED*/
2817 CCRETVAL
2818 v_wordfwd(Char c)
2820 USE(c);
2821 if (Cursor == LastChar)
2822 return(CC_ERROR);
2823 /* else */
2825 Cursor = c_nexword(Cursor, LastChar, Argument);
2827 if (VImode)
2828 if (ActionFlag & TCSHOP_DELETE) {
2829 c_delfini();
2830 return(CC_REFRESH);
2833 RefCursor();
2834 return(CC_NORM);
2837 /*ARGSUSED*/
2838 CCRETVAL
2839 v_wordbegnext(Char c)
2841 USE(c);
2842 if (Cursor == LastChar)
2843 return(CC_ERROR);
2844 /* else */
2846 Cursor = c_next_word(Cursor, LastChar, Argument);
2847 if (Cursor < LastChar)
2848 Cursor++;
2850 if (VImode)
2851 if (ActionFlag & TCSHOP_DELETE) {
2852 c_delfini();
2853 return(CC_REFRESH);
2856 RefCursor();
2857 return(CC_NORM);
2860 /*ARGSUSED*/
2861 static CCRETVAL
2862 v_repeat_srch(int c)
2864 CCRETVAL rv = CC_ERROR;
2865 #ifdef SDEBUG
2866 xprintf("dir %d patlen %d patbuf %S\n",
2867 c, (int)patbuf.len, patbuf.s);
2868 #endif
2870 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2871 LastChar = InputBuf;
2872 switch (c) {
2873 case F_DOWN_SEARCH_HIST:
2874 rv = e_down_search_hist(0);
2875 break;
2876 case F_UP_SEARCH_HIST:
2877 rv = e_up_search_hist(0);
2878 break;
2879 default:
2880 break;
2882 return rv;
2885 static CCRETVAL
2886 v_csearch_back(Char ch, int count, int tflag)
2888 Char *cp;
2890 cp = Cursor;
2891 while (count--) {
2892 if (*cp == ch)
2893 cp--;
2894 while (cp > InputBuf && *cp != ch)
2895 cp--;
2898 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2899 return(CC_ERROR);
2901 if (*cp == ch && tflag)
2902 cp++;
2904 Cursor = cp;
2906 if (ActionFlag & TCSHOP_DELETE) {
2907 Cursor++;
2908 c_delfini();
2909 return(CC_REFRESH);
2912 RefCursor();
2913 return(CC_NORM);
2916 static CCRETVAL
2917 v_csearch_fwd(Char ch, int count, int tflag)
2919 Char *cp;
2921 cp = Cursor;
2922 while (count--) {
2923 if(*cp == ch)
2924 cp++;
2925 while (cp < LastChar && *cp != ch)
2926 cp++;
2929 if (cp >= LastChar)
2930 return(CC_ERROR);
2932 if (*cp == ch && tflag)
2933 cp--;
2935 Cursor = cp;
2937 if (ActionFlag & TCSHOP_DELETE) {
2938 Cursor++;
2939 c_delfini();
2940 return(CC_REFRESH);
2942 RefCursor();
2943 return(CC_NORM);
2946 /*ARGSUSED*/
2947 static CCRETVAL
2948 v_action(int c)
2950 Char *cp, *kp;
2952 if (ActionFlag == TCSHOP_DELETE) {
2953 ActionFlag = TCSHOP_NOP;
2954 ActionPos = 0;
2956 UndoSize = 0;
2957 kp = UndoBuf;
2958 for (cp = InputBuf; cp < LastChar; cp++) {
2959 *kp++ = *cp;
2960 UndoSize++;
2963 UndoAction = TCSHOP_INSERT;
2964 UndoPtr = InputBuf;
2965 LastChar = InputBuf;
2966 Cursor = InputBuf;
2967 if (c & TCSHOP_INSERT)
2968 c_alternativ_key_map(0);
2970 return(CC_REFRESH);
2972 #ifdef notdef
2973 else if (ActionFlag == TCSHOP_NOP) {
2974 #endif
2975 ActionPos = Cursor;
2976 ActionFlag = c;
2977 return(CC_ARGHACK); /* Do NOT clear out argument */
2978 #ifdef notdef
2980 else {
2981 ActionFlag = 0;
2982 ActionPos = 0;
2983 return(CC_ERROR);
2985 #endif
2988 #ifdef COMMENT
2989 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2990 static void
2991 c_get_word(Char **begin, Char **end)
2993 Char *cp;
2995 cp = &Cursor[0];
2996 while (Argument--) {
2997 while ((cp <= LastChar) && (isword(*cp)))
2998 cp++;
2999 *end = --cp;
3000 while ((cp >= InputBuf) && (isword(*cp)))
3001 cp--;
3002 *begin = ++cp;
3005 #endif /* COMMENT */
3007 /*ARGSUSED*/
3008 CCRETVAL
3009 e_uppercase(Char c)
3011 Char *cp, *end;
3013 USE(c);
3014 end = c_next_word(Cursor, LastChar, Argument);
3016 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3017 if (Islower(*cp))
3018 *cp = Toupper(*cp);
3020 Cursor = end;
3021 if (Cursor > LastChar)
3022 Cursor = LastChar;
3023 return(CC_REFRESH);
3027 /*ARGSUSED*/
3028 CCRETVAL
3029 e_capitolcase(Char c)
3031 Char *cp, *end;
3033 USE(c);
3034 end = c_next_word(Cursor, LastChar, Argument);
3036 cp = Cursor;
3037 for (; cp < end; cp++) {
3038 if (Isalpha(*cp)) {
3039 if (Islower(*cp))
3040 *cp = Toupper(*cp);
3041 cp++;
3042 break;
3045 for (; cp < end; cp++)
3046 if (Isupper(*cp))
3047 *cp = Tolower(*cp);
3049 Cursor = end;
3050 if (Cursor > LastChar)
3051 Cursor = LastChar;
3052 return(CC_REFRESH);
3055 /*ARGSUSED*/
3056 CCRETVAL
3057 e_lowercase(Char c)
3059 Char *cp, *end;
3061 USE(c);
3062 end = c_next_word(Cursor, LastChar, Argument);
3064 for (cp = Cursor; cp < end; cp++)
3065 if (Isupper(*cp))
3066 *cp = Tolower(*cp);
3068 Cursor = end;
3069 if (Cursor > LastChar)
3070 Cursor = LastChar;
3071 return(CC_REFRESH);
3075 /*ARGSUSED*/
3076 CCRETVAL
3077 e_set_mark(Char c)
3079 USE(c);
3080 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3081 ClearLines();
3082 ClearDisp();
3083 Refresh();
3085 Mark = Cursor;
3086 MarkIsSet = 1;
3087 return(CC_NORM);
3090 /*ARGSUSED*/
3091 CCRETVAL
3092 e_exchange_mark(Char c)
3094 Char *cp;
3096 USE(c);
3097 cp = Cursor;
3098 Cursor = Mark;
3099 Mark = cp;
3100 RefCursor();
3101 return(CC_NORM);
3104 /*ARGSUSED*/
3105 CCRETVAL
3106 e_argfour(Char c)
3107 { /* multiply current argument by 4 */
3108 USE(c);
3109 if (Argument > 1000000)
3110 return CC_ERROR;
3111 DoingArg = 1;
3112 Argument *= 4;
3113 return(CC_ARGHACK);
3116 static void
3117 quote_mode_cleanup(void *unused)
3119 USE(unused);
3120 QuoteModeOff();
3123 /*ARGSUSED*/
3124 CCRETVAL
3125 e_quote(Char c)
3127 Char ch;
3128 int num;
3130 USE(c);
3131 QuoteModeOn();
3132 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3133 num = GetNextChar(&ch);
3134 cleanup_until(&c);
3135 if (num == 1)
3136 return e_insert(ch);
3137 else
3138 return e_send_eof(0);
3141 /*ARGSUSED*/
3142 CCRETVAL
3143 e_metanext(Char c)
3145 USE(c);
3146 MetaNext = 1;
3147 return(CC_ARGHACK); /* preserve argument */
3150 #ifdef notdef
3151 /*ARGSUSED*/
3152 CCRETVAL
3153 e_extendnext(Char c)
3155 CurrentKeyMap = CcAltMap;
3156 return(CC_ARGHACK); /* preserve argument */
3159 #endif
3161 /*ARGSUSED*/
3162 CCRETVAL
3163 v_insbeg(Char c)
3164 { /* move to beginning of line and start vi
3165 * insert mode */
3166 USE(c);
3167 Cursor = InputBuf;
3168 InsertPos = Cursor;
3170 UndoPtr = Cursor;
3171 UndoAction = TCSHOP_DELETE;
3173 RefCursor(); /* move the cursor */
3174 c_alternativ_key_map(0);
3175 return(CC_NORM);
3178 /*ARGSUSED*/
3179 CCRETVAL
3180 v_replone(Char c)
3181 { /* vi mode overwrite one character */
3182 USE(c);
3183 c_alternativ_key_map(0);
3184 inputmode = MODE_REPLACE_1;
3185 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3186 UndoPtr = Cursor;
3187 UndoSize = 0;
3188 return(CC_NORM);
3191 /*ARGSUSED*/
3192 CCRETVAL
3193 v_replmode(Char c)
3194 { /* vi mode start overwriting */
3195 USE(c);
3196 c_alternativ_key_map(0);
3197 inputmode = MODE_REPLACE;
3198 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3199 UndoPtr = Cursor;
3200 UndoSize = 0;
3201 return(CC_NORM);
3204 /*ARGSUSED*/
3205 CCRETVAL
3206 v_substchar(Char c)
3207 { /* vi mode substitute for one char */
3208 USE(c);
3209 c_delafter(Argument);
3210 c_alternativ_key_map(0);
3211 return(CC_REFRESH);
3214 /*ARGSUSED*/
3215 CCRETVAL
3216 v_substline(Char c)
3217 { /* vi mode replace whole line */
3218 USE(c);
3219 (void) e_killall(0);
3220 c_alternativ_key_map(0);
3221 return(CC_REFRESH);
3224 /*ARGSUSED*/
3225 CCRETVAL
3226 v_chgtoend(Char c)
3227 { /* vi mode change to end of line */
3228 USE(c);
3229 (void) e_killend(0);
3230 c_alternativ_key_map(0);
3231 return(CC_REFRESH);
3234 /*ARGSUSED*/
3235 CCRETVAL
3236 v_insert(Char c)
3237 { /* vi mode start inserting */
3238 USE(c);
3239 c_alternativ_key_map(0);
3241 InsertPos = Cursor;
3242 UndoPtr = Cursor;
3243 UndoAction = TCSHOP_DELETE;
3245 return(CC_NORM);
3248 /*ARGSUSED*/
3249 CCRETVAL
3250 v_add(Char c)
3251 { /* vi mode start adding */
3252 USE(c);
3253 c_alternativ_key_map(0);
3254 if (Cursor < LastChar)
3256 Cursor++;
3257 if (Cursor > LastChar)
3258 Cursor = LastChar;
3259 RefCursor();
3262 InsertPos = Cursor;
3263 UndoPtr = Cursor;
3264 UndoAction = TCSHOP_DELETE;
3266 return(CC_NORM);
3269 /*ARGSUSED*/
3270 CCRETVAL
3271 v_addend(Char c)
3272 { /* vi mode to add at end of line */
3273 USE(c);
3274 c_alternativ_key_map(0);
3275 Cursor = LastChar;
3277 InsertPos = LastChar; /* Mark where insertion begins */
3278 UndoPtr = LastChar;
3279 UndoAction = TCSHOP_DELETE;
3281 RefCursor();
3282 return(CC_NORM);
3285 /*ARGSUSED*/
3286 CCRETVAL
3287 v_change_case(Char cc)
3289 Char c;
3291 USE(cc);
3292 if (Cursor < LastChar) {
3293 #ifndef WINNT_NATIVE
3294 c = *Cursor;
3295 #else
3296 c = CHAR & *Cursor;
3297 #endif /* WINNT_NATIVE */
3298 if (Isupper(c))
3299 *Cursor++ = Tolower(c);
3300 else if (Islower(c))
3301 *Cursor++ = Toupper(c);
3302 else
3303 Cursor++;
3304 RefPlusOne(1); /* fast refresh for one char */
3305 return(CC_NORM);
3307 return(CC_ERROR);
3310 /*ARGSUSED*/
3311 CCRETVAL
3312 e_expand(Char c)
3314 Char *p;
3316 USE(c);
3317 for (p = InputBuf; Isspace(*p); p++)
3318 continue;
3319 if (p == LastChar)
3320 return(CC_ERROR);
3322 justpr++;
3323 Expand++;
3324 return(e_newline(0));
3327 /*ARGSUSED*/
3328 CCRETVAL
3329 e_startover(Char c)
3330 { /* erase all of current line, start again */
3331 USE(c);
3332 ResetInLine(0); /* reset the input pointers */
3333 return(CC_REFRESH);
3336 /*ARGSUSED*/
3337 CCRETVAL
3338 e_redisp(Char c)
3340 USE(c);
3341 ClearLines();
3342 ClearDisp();
3343 return(CC_REFRESH);
3346 /*ARGSUSED*/
3347 CCRETVAL
3348 e_cleardisp(Char c)
3350 USE(c);
3351 ClearScreen(); /* clear the whole real screen */
3352 ClearDisp(); /* reset everything */
3353 return(CC_REFRESH);
3356 /*ARGSUSED*/
3357 CCRETVAL
3358 e_tty_int(Char c)
3360 USE(c);
3361 #if defined(_MINIX) || defined(WINNT_NATIVE)
3362 /* SAK PATCH: erase all of current line, start again */
3363 ResetInLine(0); /* reset the input pointers */
3364 xputchar('\n');
3365 ClearDisp();
3366 return (CC_REFRESH);
3367 #else /* !_MINIX && !WINNT_NATIVE */
3368 /* do no editing */
3369 return (CC_NORM);
3370 #endif /* _MINIX || WINNT_NATIVE */
3374 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3375 * Function to send a character back to the input stream in cooked
3376 * mode. Only works if we have TIOCSTI
3378 /*ARGSUSED*/
3379 CCRETVAL
3380 e_stuff_char(Char c)
3382 #ifdef TIOCSTI
3383 int was_raw = Tty_raw_mode;
3384 char buf[MB_LEN_MAX];
3385 size_t i, len;
3387 if (was_raw)
3388 (void) Cookedmode();
3390 (void) xwrite(SHIN, "\n", 1);
3391 len = one_wctomb(buf, c & CHAR);
3392 for (i = 0; i < len; i++)
3393 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3395 if (was_raw)
3396 (void) Rawmode();
3397 return(e_redisp(c));
3398 #else /* !TIOCSTI */
3399 return(CC_ERROR);
3400 #endif /* !TIOCSTI */
3403 /*ARGSUSED*/
3404 CCRETVAL
3405 e_insovr(Char c)
3407 USE(c);
3408 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3409 return(CC_NORM);
3412 /*ARGSUSED*/
3413 CCRETVAL
3414 e_tty_dsusp(Char c)
3416 USE(c);
3417 /* do no editing */
3418 return(CC_NORM);
3421 /*ARGSUSED*/
3422 CCRETVAL
3423 e_tty_flusho(Char c)
3425 USE(c);
3426 /* do no editing */
3427 return(CC_NORM);
3430 /*ARGSUSED*/
3431 CCRETVAL
3432 e_tty_quit(Char c)
3434 USE(c);
3435 /* do no editing */
3436 return(CC_NORM);
3439 /*ARGSUSED*/
3440 CCRETVAL
3441 e_tty_tsusp(Char c)
3443 USE(c);
3444 /* do no editing */
3445 return(CC_NORM);
3448 /*ARGSUSED*/
3449 CCRETVAL
3450 e_tty_stopo(Char c)
3452 USE(c);
3453 /* do no editing */
3454 return(CC_NORM);
3457 /* returns the number of (attempted) expansions */
3459 ExpandHistory(void)
3461 *LastChar = '\0'; /* just in case */
3462 return c_substitute();
3465 /*ARGSUSED*/
3466 CCRETVAL
3467 e_expand_history(Char c)
3469 USE(c);
3470 (void)ExpandHistory();
3471 return(CC_NORM);
3474 /*ARGSUSED*/
3475 CCRETVAL
3476 e_magic_space(Char c)
3478 USE(c);
3479 *LastChar = '\0'; /* just in case */
3480 (void)c_substitute();
3481 return(e_insert(' '));
3484 /*ARGSUSED*/
3485 CCRETVAL
3486 e_inc_fwd(Char c)
3488 CCRETVAL ret;
3490 USE(c);
3491 patbuf.len = 0;
3492 MarkIsSet = 0;
3493 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3494 if (adrof(STRhighlight) && IncMatchLen) {
3495 IncMatchLen = 0;
3496 ClearLines();
3497 ClearDisp();
3498 Refresh();
3500 IncMatchLen = 0;
3501 return ret;
3505 /*ARGSUSED*/
3506 CCRETVAL
3507 e_inc_back(Char c)
3509 CCRETVAL ret;
3511 USE(c);
3512 patbuf.len = 0;
3513 MarkIsSet = 0;
3514 ret = e_inc_search(F_UP_SEARCH_HIST);
3515 if (adrof(STRhighlight) && IncMatchLen) {
3516 IncMatchLen = 0;
3517 ClearLines();
3518 ClearDisp();
3519 Refresh();
3521 IncMatchLen = 0;
3522 return ret;
3525 /*ARGSUSED*/
3526 CCRETVAL
3527 e_copyprev(Char c)
3529 Char *cp, *oldc, *dp;
3531 USE(c);
3532 if (Cursor == InputBuf)
3533 return(CC_ERROR);
3534 /* else */
3536 oldc = Cursor;
3537 /* does a bounds check */
3538 cp = c_prev_word(Cursor, InputBuf, Argument);
3540 c_insert((int)(oldc - cp));
3541 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3542 *dp++ = *cp;
3544 Cursor = dp; /* put cursor at end */
3546 return(CC_REFRESH);
3549 /*ARGSUSED*/
3550 CCRETVAL
3551 e_tty_starto(Char c)
3553 USE(c);
3554 /* do no editing */
3555 return(CC_NORM);
3558 /*ARGSUSED*/
3559 CCRETVAL
3560 e_load_average(Char c)
3562 USE(c);
3563 PastBottom();
3564 #ifdef TIOCSTAT
3566 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3567 * there even if they don't use it. (lukem@netbsd.org)
3569 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3570 #endif
3571 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3572 return(CC_REFRESH);
3575 /*ARGSUSED*/
3576 CCRETVAL
3577 v_chgmeta(Char c)
3579 USE(c);
3581 * Delete with insert == change: first we delete and then we leave in
3582 * insert mode.
3584 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3587 /*ARGSUSED*/
3588 CCRETVAL
3589 v_delmeta(Char c)
3591 USE(c);
3592 return(v_action(TCSHOP_DELETE));
3596 /*ARGSUSED*/
3597 CCRETVAL
3598 v_endword(Char c)
3600 USE(c);
3601 if (Cursor == LastChar)
3602 return(CC_ERROR);
3603 /* else */
3605 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3607 if (ActionFlag & TCSHOP_DELETE)
3609 Cursor++;
3610 c_delfini();
3611 return(CC_REFRESH);
3614 RefCursor();
3615 return(CC_NORM);
3618 /*ARGSUSED*/
3619 CCRETVAL
3620 v_eword(Char c)
3622 USE(c);
3623 if (Cursor == LastChar)
3624 return(CC_ERROR);
3625 /* else */
3627 Cursor = c_eword(Cursor, LastChar, Argument);
3629 if (ActionFlag & TCSHOP_DELETE) {
3630 Cursor++;
3631 c_delfini();
3632 return(CC_REFRESH);
3635 RefCursor();
3636 return(CC_NORM);
3639 /*ARGSUSED*/
3640 CCRETVAL
3641 v_char_fwd(Char c)
3643 Char ch;
3645 USE(c);
3646 if (GetNextChar(&ch) != 1)
3647 return e_send_eof(0);
3649 srch_dir = CHAR_FWD;
3650 srch_char = ch;
3652 return v_csearch_fwd(ch, Argument, 0);
3656 /*ARGSUSED*/
3657 CCRETVAL
3658 v_char_back(Char c)
3660 Char ch;
3662 USE(c);
3663 if (GetNextChar(&ch) != 1)
3664 return e_send_eof(0);
3666 srch_dir = CHAR_BACK;
3667 srch_char = ch;
3669 return v_csearch_back(ch, Argument, 0);
3672 /*ARGSUSED*/
3673 CCRETVAL
3674 v_charto_fwd(Char c)
3676 Char ch;
3678 USE(c);
3679 if (GetNextChar(&ch) != 1)
3680 return e_send_eof(0);
3682 return v_csearch_fwd(ch, Argument, 1);
3686 /*ARGSUSED*/
3687 CCRETVAL
3688 v_charto_back(Char c)
3690 Char ch;
3692 USE(c);
3693 if (GetNextChar(&ch) != 1)
3694 return e_send_eof(0);
3696 return v_csearch_back(ch, Argument, 1);
3699 /*ARGSUSED*/
3700 CCRETVAL
3701 v_rchar_fwd(Char c)
3703 USE(c);
3704 if (srch_char == 0)
3705 return CC_ERROR;
3707 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3708 v_csearch_back(srch_char, Argument, 0);
3711 /*ARGSUSED*/
3712 CCRETVAL
3713 v_rchar_back(Char c)
3715 USE(c);
3716 if (srch_char == 0)
3717 return CC_ERROR;
3719 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3720 v_csearch_back(srch_char, Argument, 0);
3723 /*ARGSUSED*/
3724 CCRETVAL
3725 v_undo(Char c)
3727 int loop;
3728 Char *kp, *cp;
3729 Char temp;
3730 int size;
3732 USE(c);
3733 switch (UndoAction) {
3734 case TCSHOP_DELETE|TCSHOP_INSERT:
3735 case TCSHOP_DELETE:
3736 if (UndoSize == 0) return(CC_NORM);
3737 cp = UndoPtr;
3738 kp = UndoBuf;
3739 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3740 *kp++ = *cp++; /* into UndoBuf */
3742 for (cp = UndoPtr; cp <= LastChar; cp++)
3743 *cp = cp[UndoSize];
3745 LastChar -= UndoSize;
3746 Cursor = UndoPtr;
3748 UndoAction = TCSHOP_INSERT;
3749 break;
3751 case TCSHOP_INSERT:
3752 if (UndoSize == 0) return(CC_NORM);
3753 cp = UndoPtr;
3754 Cursor = UndoPtr;
3755 kp = UndoBuf;
3756 c_insert(UndoSize); /* open the space, */
3757 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3758 *cp++ = *kp++;
3760 UndoAction = TCSHOP_DELETE;
3761 break;
3763 case TCSHOP_CHANGE:
3764 if (UndoSize == 0) return(CC_NORM);
3765 cp = UndoPtr;
3766 Cursor = UndoPtr;
3767 kp = UndoBuf;
3768 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3769 if (size < UndoSize)
3770 size = UndoSize;
3771 for(loop = 0; loop < size; loop++) {
3772 temp = *kp;
3773 *kp++ = *cp;
3774 *cp++ = temp;
3776 break;
3778 default:
3779 return(CC_ERROR);
3782 return(CC_REFRESH);
3785 /*ARGSUSED*/
3786 CCRETVAL
3787 v_ush_meta(Char c)
3789 USE(c);
3790 return v_search(F_UP_SEARCH_HIST);
3793 /*ARGSUSED*/
3794 CCRETVAL
3795 v_dsh_meta(Char c)
3797 USE(c);
3798 return v_search(F_DOWN_SEARCH_HIST);
3801 /*ARGSUSED*/
3802 CCRETVAL
3803 v_rsrch_fwd(Char c)
3805 USE(c);
3806 if (patbuf.len == 0) return(CC_ERROR);
3807 return(v_repeat_srch(searchdir));
3810 /*ARGSUSED*/
3811 CCRETVAL
3812 v_rsrch_back(Char c)
3814 USE(c);
3815 if (patbuf.len == 0) return(CC_ERROR);
3816 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3817 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3820 #ifndef WINNT_NATIVE
3821 /* Since ed.defns.h is generated from ed.defns.c, these empty
3822 functions will keep the F_NUM_FNS consistent
3824 CCRETVAL
3825 e_copy_to_clipboard(Char c)
3827 USE(c);
3828 return CC_ERROR;
3831 CCRETVAL
3832 e_paste_from_clipboard(Char c)
3834 USE(c);
3835 return (CC_ERROR);
3838 CCRETVAL
3839 e_dosify_next(Char c)
3841 USE(c);
3842 return (CC_ERROR);
3844 CCRETVAL
3845 e_dosify_prev(Char c)
3847 USE(c);
3848 return (CC_ERROR);
3850 CCRETVAL
3851 e_page_up(Char c)
3853 USE(c);
3854 return (CC_ERROR);
3856 CCRETVAL
3857 e_page_down(Char c)
3859 USE(c);
3860 return (CC_ERROR);
3862 #endif /* !WINNT_NATIVE */
3864 #ifdef notdef
3865 void
3866 MoveCursor(int n) /* move cursor + right - left char */
3868 Cursor = Cursor + n;
3869 if (Cursor < InputBuf)
3870 Cursor = InputBuf;
3871 if (Cursor > LastChar)
3872 Cursor = LastChar;
3873 return;
3876 Char *
3877 GetCursor(void)
3879 return(Cursor);
3883 PutCursor(Char *p)
3885 if (p < InputBuf || p > LastChar)
3886 return 1; /* Error */
3887 Cursor = p;
3888 return 0;
3890 #endif