Vendor import of tcsh 6.15.00
[dragonfly.git] / contrib / tcsh-6 / ed.chared.c
blob9f09c68562af05775f22943d5a52237cda82ddf2
1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.93 2006/08/23 15:03:13 christos Exp $ */
2 /*
3 * ed.chared.c: Character editing functions.
4 */
5 /*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
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.93 2006/08/23 15:03:13 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 void c_excl (Char *);
124 static void c_substitute (void);
125 static void c_delfini (void);
126 static int c_hmatch (Char *);
127 static void c_hsetpat (void);
128 #ifdef COMMENT
129 static void c_get_word (Char **, Char **);
130 #endif
131 static Char *c_preword (Char *, Char *, int, Char *);
132 static Char *c_nexword (Char *, Char *, int);
133 static Char *c_endword (Char *, Char *, int, Char *);
134 static Char *c_eword (Char *, Char *, int);
135 static void c_push_kill (Char *, Char *);
136 static void c_save_inputbuf (void);
137 static CCRETVAL c_search_line (Char *, int);
138 static CCRETVAL v_repeat_srch (int);
139 static CCRETVAL e_inc_search (int);
140 #ifdef notyet
141 static CCRETVAL e_insert_str (Char *);
142 #endif
143 static CCRETVAL v_search (int);
144 static CCRETVAL v_csearch_fwd (Char, int, int);
145 static CCRETVAL v_action (int);
146 static CCRETVAL v_csearch_back (Char, int, int);
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 '>!'
687 static void
688 c_excl(Char *p)
690 int i;
691 Char *q;
694 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
695 * back p up to just before the current word.
697 if ((p[1] == ' ' || p[1] == '\t') &&
698 (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
699 for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
700 continue;
701 if (*q == '>')
702 ++p;
704 else {
705 while (*p != ' ' && *p != '\t' && p > InputBuf)
706 --p;
710 * Forever: Look for history char. (Stop looking when we find the cursor.)
711 * Count backslashes. Of odd, skip history char. Return if all done.
712 * Expand if even number of backslashes.
714 for (;;) {
715 while (*p != HIST && p < Cursor)
716 ++p;
717 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
718 continue;
719 if (i % 2 == 0)
720 ++p;
721 if (p >= Cursor)
722 return;
723 if (i % 2 == 1)
724 p = c_expand(p);
729 static void
730 c_substitute(void)
732 Char *p;
735 * Start p out one character before the cursor. Move it backwards looking
736 * for white space, the beginning of the line, or a history character.
738 for (p = Cursor - 1;
739 p > InputBuf && *p != ' ' && *p != '\t' && *p != HIST; --p)
740 continue;
743 * If we found a history character, go expand it.
745 if (*p == HIST)
746 c_excl(p);
747 Refresh();
750 static void
751 c_delfini(void) /* Finish up delete action */
753 int Size;
755 if (ActionFlag & TCSHOP_INSERT)
756 c_alternativ_key_map(0);
758 ActionFlag = TCSHOP_NOP;
760 if (ActionPos == 0)
761 return;
763 UndoAction = TCSHOP_INSERT;
765 if (Cursor > ActionPos) {
766 Size = (int) (Cursor-ActionPos);
767 c_delbefore(Size);
768 RefCursor();
770 else if (Cursor < ActionPos) {
771 Size = (int)(ActionPos-Cursor);
772 c_delafter(Size);
774 else {
775 Size = 1;
776 c_delafter(Size);
778 UndoPtr = Cursor;
779 UndoSize = Size;
782 static Char *
783 c_endword(Char *p, Char *high, int n, Char *delim)
785 Char inquote = 0;
786 p++;
788 while (n--) {
789 while (p < high) { /* Skip non-word chars */
790 if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
791 break;
792 p++;
794 while (p < high) { /* Skip string */
795 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
796 if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
797 if (inquote == 0) inquote = *p;
798 else if (inquote == *p) inquote = 0;
801 /* Break if unquoted non-word char */
802 if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
803 break;
804 p++;
808 p--;
809 return(p);
813 static Char *
814 c_eword(Char *p, Char *high, int n)
816 p++;
818 while (n--) {
819 while ((p < high) && Isspace(*p))
820 p++;
822 if (Isalnum(*p))
823 while ((p < high) && Isalnum(*p))
824 p++;
825 else
826 while ((p < high) && !(Isspace(*p) || Isalnum(*p)))
827 p++;
830 p--;
831 return(p);
834 /* Set the max length of the kill ring */
835 void
836 SetKillRing(int max)
838 CStr *new;
839 int count, i, j;
841 if (max < 1)
842 max = 1; /* no ring, but always one buffer */
843 if (max == KillRingMax)
844 return;
845 new = xcalloc(max, sizeof(CStr));
846 if (KillRing != NULL) {
847 if (KillRingLen != 0) {
848 if (max >= KillRingLen) {
849 count = KillRingLen;
850 j = KillPos;
851 } else {
852 count = max;
853 j = (KillPos - count + KillRingLen) % KillRingLen;
855 for (i = 0; i < KillRingLen; i++) {
856 if (i < count) /* copy latest */
857 new[i] = KillRing[j];
858 else /* free the others */
859 xfree(KillRing[j].buf);
860 j = (j + 1) % KillRingLen;
862 KillRingLen = count;
863 KillPos = count % max;
864 YankPos = count - 1;
866 xfree(KillRing);
868 KillRing = new;
869 KillRingMax = max;
872 /* Push string from start upto (but not including) end onto kill ring */
873 static void
874 c_push_kill(Char *start, Char *end)
876 CStr save, *pos;
877 Char *dp, *cp, *kp;
878 int len = end - start, i, j, k;
880 /* Check for duplicates? */
881 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
882 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
883 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
884 j = YankPos;
885 for (i = 0; i < KillRingLen; i++) {
886 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
887 KillRing[j].buf[len] == '\0') {
888 save = KillRing[j];
889 for ( ; i > 0; i--) {
890 k = j;
891 j = (j + 1) % KillRingLen;
892 KillRing[k] = KillRing[j];
894 KillRing[j] = save;
895 return;
897 j = (j - 1 + KillRingLen) % KillRingLen;
899 } else if (eq(dp, STRall)) { /* skip if any earlier */
900 for (i = 0; i < KillRingLen; i++)
901 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
902 KillRing[i].buf[len] == '\0')
903 return;
904 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
905 j = YankPos;
906 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
907 KillRing[j].buf[len] == '\0')
908 return;
912 /* No duplicate, go ahead and push */
913 len++; /* need space for '\0' */
914 YankPos = KillPos;
915 if (KillRingLen < KillRingMax)
916 KillRingLen++;
917 pos = &KillRing[KillPos];
918 KillPos = (KillPos + 1) % KillRingMax;
919 if (pos->len < len) {
920 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
921 pos->len = len;
923 cp = start;
924 kp = pos->buf;
925 while (cp < end)
926 *kp++ = *cp++;
927 *kp = '\0';
930 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
931 static void
932 c_save_inputbuf()
934 SavedBuf.len = 0;
935 Strbuf_append(&SavedBuf, InputBuf);
936 Strbuf_terminate(&SavedBuf);
937 LastSaved = LastChar - InputBuf;
938 CursSaved = Cursor - InputBuf;
939 HistSaved = Hist_num;
940 RestoreSaved = 1;
943 CCRETVAL
944 GetHistLine()
946 struct Hist *hp;
947 int h;
949 if (Hist_num == 0) { /* if really the current line */
950 if (HistBuf.s != NULL)
951 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
952 else
953 *InputBuf = '\0';
954 LastChar = InputBuf + HistBuf.len;
956 #ifdef KSHVI
957 if (VImode)
958 Cursor = InputBuf;
959 else
960 #endif /* KSHVI */
961 Cursor = LastChar;
963 return(CC_REFRESH);
966 hp = Histlist.Hnext;
967 if (hp == NULL)
968 return(CC_ERROR);
970 for (h = 1; h < Hist_num; h++) {
971 if ((hp->Hnext) == NULL) {
972 Hist_num = h;
973 return(CC_ERROR);
975 hp = hp->Hnext;
978 if (HistLit && hp->histline) {
979 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
980 CurrentHistLit = 1;
982 else {
983 Char *p;
985 p = sprlex(&hp->Hlex);
986 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
987 xfree(p);
988 CurrentHistLit = 0;
990 LastChar = Strend(InputBuf);
992 if (LastChar > InputBuf) {
993 if (LastChar[-1] == '\n')
994 LastChar--;
995 #if 0
996 if (LastChar[-1] == ' ')
997 LastChar--;
998 #endif
999 if (LastChar < InputBuf)
1000 LastChar = InputBuf;
1003 #ifdef KSHVI
1004 if (VImode)
1005 Cursor = InputBuf;
1006 else
1007 #endif /* KSHVI */
1008 Cursor = LastChar;
1010 return(CC_REFRESH);
1013 static CCRETVAL
1014 c_search_line(Char *pattern, int dir)
1016 Char *cp;
1017 size_t len;
1019 len = Strlen(pattern);
1021 if (dir == F_UP_SEARCH_HIST) {
1022 for (cp = Cursor; cp >= InputBuf; cp--)
1023 if (Strncmp(cp, pattern, len) == 0 ||
1024 Gmatch(cp, pattern)) {
1025 Cursor = cp;
1026 return(CC_NORM);
1028 return(CC_ERROR);
1029 } else {
1030 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1031 if (Strncmp(cp, pattern, len) == 0 ||
1032 Gmatch(cp, pattern)) {
1033 Cursor = cp;
1034 return(CC_NORM);
1036 return(CC_ERROR);
1040 static CCRETVAL
1041 e_inc_search(int dir)
1043 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1044 STRbck[] = { 'b', 'c', 'k', '\0' };
1045 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1046 static Char endcmd[2];
1047 const Char *cp;
1048 Char ch,
1049 *oldCursor = Cursor,
1050 oldpchar = pchar;
1051 CCRETVAL ret = CC_NORM;
1052 int oldHist_num = Hist_num,
1053 oldpatlen = patbuf.len,
1054 newdir = dir,
1055 done, redo;
1057 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1058 return(CC_ERROR);
1060 for (;;) {
1062 if (patbuf.len == 0) { /* first round */
1063 pchar = ':';
1064 Strbuf_append1(&patbuf, '*');
1066 done = redo = 0;
1067 *LastChar++ = '\n';
1068 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1069 *cp; *LastChar++ = *cp++)
1070 continue;
1071 *LastChar++ = pchar;
1072 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1073 *LastChar++ = *cp++)
1074 continue;
1075 *LastChar = '\0';
1076 if (adrof(STRhighlight) && pchar == ':') {
1077 /* if the no-glob-search patch is applied, remove the - 1 below */
1078 IncMatchLen = patbuf.len - 1;
1079 ClearLines();
1080 ClearDisp();
1082 Refresh();
1084 if (GetNextChar(&ch) != 1)
1085 return(e_send_eof(0));
1087 switch (ch > NT_NUM_KEYS
1088 ? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
1089 case F_INSERT:
1090 case F_DIGIT:
1091 case F_MAGIC_SPACE:
1092 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1093 SoundBeep();
1094 else {
1095 Strbuf_append1(&patbuf, ch);
1096 *LastChar++ = ch;
1097 *LastChar = '\0';
1098 Refresh();
1100 break;
1102 case F_INC_FWD:
1103 newdir = F_DOWN_SEARCH_HIST;
1104 redo++;
1105 break;
1107 case F_INC_BACK:
1108 newdir = F_UP_SEARCH_HIST;
1109 redo++;
1110 break;
1112 case F_DELPREV:
1113 if (patbuf.len > 1)
1114 done++;
1115 else
1116 SoundBeep();
1117 break;
1119 default:
1120 switch (ASC(ch)) {
1121 case 0007: /* ^G: Abort */
1122 ret = CC_ERROR;
1123 done++;
1124 break;
1126 case 0027: /* ^W: Append word */
1127 /* No can do if globbing characters in pattern */
1128 for (cp = &patbuf.s[1]; ; cp++)
1129 if (cp >= &patbuf.s[patbuf.len]) {
1130 Cursor += patbuf.len - 1;
1131 cp = c_next_word(Cursor, LastChar, 1);
1132 while (Cursor < cp && *Cursor != '\n') {
1133 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1134 SoundBeep();
1135 break;
1137 Strbuf_append1(&patbuf, *Cursor);
1138 *LastChar++ = *Cursor++;
1140 Cursor = oldCursor;
1141 *LastChar = '\0';
1142 Refresh();
1143 break;
1144 } else if (isglob(*cp)) {
1145 SoundBeep();
1146 break;
1148 break;
1150 default: /* Terminate and execute cmd */
1151 endcmd[0] = ch;
1152 PushMacro(endcmd);
1153 /*FALLTHROUGH*/
1155 case 0033: /* ESC: Terminate */
1156 ret = CC_REFRESH;
1157 done++;
1158 break;
1160 break;
1163 while (LastChar > InputBuf && *LastChar != '\n')
1164 *LastChar-- = '\0';
1165 *LastChar = '\0';
1167 if (!done) {
1169 /* Can't search if unmatched '[' */
1170 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1171 if (*cp == '[' || *cp == ']') {
1172 ch = *cp;
1173 break;
1176 if (patbuf.len > 1 && ch != '[') {
1177 if (redo && newdir == dir) {
1178 if (pchar == '?') { /* wrap around */
1179 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1180 if (GetHistLine() == CC_ERROR)
1181 /* Hist_num was fixed by first call */
1182 (void) GetHistLine();
1183 Cursor = newdir == F_UP_SEARCH_HIST ?
1184 LastChar : InputBuf;
1185 } else
1186 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1188 Strbuf_append1(&patbuf, '*');
1189 Strbuf_terminate(&patbuf);
1190 if (Cursor < InputBuf || Cursor > LastChar ||
1191 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1192 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1193 ret = newdir == F_UP_SEARCH_HIST ?
1194 e_up_search_hist(0) : e_down_search_hist(0);
1195 if (ret != CC_ERROR) {
1196 Cursor = newdir == F_UP_SEARCH_HIST ?
1197 LastChar : InputBuf;
1198 (void) c_search_line(&patbuf.s[1], newdir);
1201 patbuf.s[--patbuf.len] = '\0';
1202 if (ret == CC_ERROR) {
1203 SoundBeep();
1204 if (Hist_num != oldHist_num) {
1205 Hist_num = oldHist_num;
1206 if (GetHistLine() == CC_ERROR)
1207 return(CC_ERROR);
1209 Cursor = oldCursor;
1210 pchar = '?';
1211 } else {
1212 pchar = ':';
1216 ret = e_inc_search(newdir);
1218 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1219 /* break abort of failed search at last non-failed */
1220 ret = CC_NORM;
1225 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1226 /* restore on normal return or error exit */
1227 pchar = oldpchar;
1228 patbuf.len = oldpatlen;
1229 if (Hist_num != oldHist_num) {
1230 Hist_num = oldHist_num;
1231 if (GetHistLine() == CC_ERROR)
1232 return(CC_ERROR);
1234 Cursor = oldCursor;
1235 if (ret == CC_ERROR)
1236 Refresh();
1238 if (done || ret != CC_NORM)
1239 return(ret);
1245 static CCRETVAL
1246 v_search(int dir)
1248 struct Strbuf tmpbuf = Strbuf_INIT;
1249 Char ch;
1250 Char *oldbuf;
1251 Char *oldlc, *oldc;
1253 cleanup_push(&tmpbuf, Strbuf_cleanup);
1254 oldbuf = Strsave(InputBuf);
1255 cleanup_push(oldbuf, xfree);
1256 oldlc = LastChar;
1257 oldc = Cursor;
1258 Strbuf_append1(&tmpbuf, '*');
1260 InputBuf[0] = '\0';
1261 LastChar = InputBuf;
1262 Cursor = InputBuf;
1263 searchdir = dir;
1265 c_insert(2); /* prompt + '\n' */
1266 *Cursor++ = '\n';
1267 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1268 Refresh();
1269 for (ch = 0;ch == 0;) {
1270 if (GetNextChar(&ch) != 1) {
1271 cleanup_until(&tmpbuf);
1272 return(e_send_eof(0));
1274 switch (ASC(ch)) {
1275 case 0010: /* Delete and backspace */
1276 case 0177:
1277 if (tmpbuf.len > 1) {
1278 *Cursor-- = '\0';
1279 LastChar = Cursor;
1280 tmpbuf.len--;
1282 else {
1283 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1284 LastChar = oldlc;
1285 Cursor = oldc;
1286 cleanup_until(&tmpbuf);
1287 return(CC_REFRESH);
1289 Refresh();
1290 ch = 0;
1291 break;
1293 case 0033: /* ESC */
1294 #ifdef IS_ASCII
1295 case '\r': /* Newline */
1296 case '\n':
1297 #else
1298 case '\012': /* ASCII Line feed */
1299 case '\015': /* ASCII (or EBCDIC) Return */
1300 #endif
1301 break;
1303 default:
1304 Strbuf_append1(&tmpbuf, ch);
1305 *Cursor++ = ch;
1306 LastChar = Cursor;
1307 Refresh();
1308 ch = 0;
1309 break;
1312 cleanup_until(oldbuf);
1314 if (tmpbuf.len == 1) {
1316 * Use the old pattern, but wild-card it.
1318 if (patbuf.len == 0) {
1319 InputBuf[0] = '\0';
1320 LastChar = InputBuf;
1321 Cursor = InputBuf;
1322 Refresh();
1323 cleanup_until(&tmpbuf);
1324 return(CC_ERROR);
1326 if (patbuf.s[0] != '*') {
1327 oldbuf = Strsave(patbuf.s);
1328 patbuf.len = 0;
1329 Strbuf_append1(&patbuf, '*');
1330 Strbuf_append(&patbuf, oldbuf);
1331 xfree(oldbuf);
1332 Strbuf_append1(&patbuf, '*');
1333 Strbuf_terminate(&patbuf);
1336 else {
1337 Strbuf_append1(&tmpbuf, '*');
1338 Strbuf_terminate(&tmpbuf);
1339 patbuf.len = 0;
1340 Strbuf_append(&patbuf, tmpbuf.s);
1341 Strbuf_terminate(&patbuf);
1343 cleanup_until(&tmpbuf);
1344 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1345 Cursor = LastChar = InputBuf;
1346 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1347 e_down_search_hist(0)) == CC_ERROR) {
1348 Refresh();
1349 return(CC_ERROR);
1351 else {
1352 if (ASC(ch) == 0033) {
1353 Refresh();
1354 *LastChar++ = '\n';
1355 *LastChar = '\0';
1356 PastBottom();
1357 return(CC_NEWLINE);
1359 else
1360 return(CC_REFRESH);
1365 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1366 * entry point, called from the CcKeyMap indirected into the
1367 * CcFuncTbl array.
1370 /*ARGSUSED*/
1371 CCRETVAL
1372 v_cmd_mode(Char c)
1374 USE(c);
1375 InsertPos = 0;
1376 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1377 ActionPos = 0;
1378 DoingArg = 0;
1379 if (UndoPtr > Cursor)
1380 UndoSize = (int)(UndoPtr - Cursor);
1381 else
1382 UndoSize = (int)(Cursor - UndoPtr);
1384 inputmode = MODE_INSERT;
1385 c_alternativ_key_map(1);
1386 #ifdef notdef
1388 * We don't want to move the cursor, because all the editing
1389 * commands don't include the character under the cursor.
1391 if (Cursor > InputBuf)
1392 Cursor--;
1393 #endif
1394 RefCursor();
1395 return(CC_NORM);
1398 /*ARGSUSED*/
1399 CCRETVAL
1400 e_unassigned(Char c)
1401 { /* bound to keys that arn't really assigned */
1402 USE(c);
1403 SoundBeep();
1404 flush();
1405 return(CC_NORM);
1408 #ifdef notyet
1409 static CCRETVAL
1410 e_insert_str(Char *c)
1412 int i, n;
1414 n = Strlen(c);
1415 if (LastChar + Argument * n >= InputLim)
1416 return(CC_ERROR); /* end of buffer space */
1417 if (inputmode != MODE_INSERT) {
1418 c_delafter(Argument * Strlen(c));
1420 c_insert(Argument * n);
1421 while (Argument--) {
1422 for (i = 0; i < n; i++)
1423 *Cursor++ = c[i];
1425 Refresh();
1426 return(CC_NORM);
1428 #endif
1430 CCRETVAL
1431 e_insert(Char c)
1433 #ifndef SHORT_STRINGS
1434 c &= ASCII; /* no meta chars ever */
1435 #endif
1437 if (!c)
1438 return(CC_ERROR); /* no NULs in the input ever!! */
1440 if (LastChar + Argument >= InputLim)
1441 return(CC_ERROR); /* end of buffer space */
1443 if (Argument == 1) { /* How was this optimized ???? */
1445 if (inputmode != MODE_INSERT) {
1446 UndoBuf[UndoSize++] = *Cursor;
1447 UndoBuf[UndoSize] = '\0';
1448 c_delafter(1); /* Do NOT use the saving ONE */
1451 c_insert(1);
1452 *Cursor++ = (Char) c;
1453 DoingArg = 0; /* just in case */
1454 RefPlusOne(1); /* fast refresh for one char. */
1456 else {
1457 if (inputmode != MODE_INSERT) {
1458 int i;
1459 for(i = 0; i < Argument; i++)
1460 UndoBuf[UndoSize++] = *(Cursor + i);
1462 UndoBuf[UndoSize] = '\0';
1463 c_delafter(Argument); /* Do NOT use the saving ONE */
1466 c_insert(Argument);
1468 while (Argument--)
1469 *Cursor++ = (Char) c;
1470 Refresh();
1473 if (inputmode == MODE_REPLACE_1)
1474 (void) v_cmd_mode(0);
1476 return(CC_NORM);
1480 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1482 int len;
1484 if ((len = (int) Strlen(s)) <= 0)
1485 return -1;
1486 if (LastChar + len >= InputLim)
1487 return -1; /* end of buffer space */
1489 c_insert(len);
1490 while (len--)
1491 *Cursor++ = *s++;
1492 return 0;
1495 void
1496 DeleteBack(int n) /* delete the n characters before . */
1498 if (n <= 0)
1499 return;
1500 if (Cursor >= &InputBuf[n]) {
1501 c_delbefore(n); /* delete before dot */
1505 CCRETVAL
1506 e_digit(Char c) /* gray magic here */
1508 if (!Isdigit(c))
1509 return(CC_ERROR); /* no NULs in the input ever!! */
1511 if (DoingArg) { /* if doing an arg, add this in... */
1512 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1513 Argument = c - '0';
1514 else {
1515 if (Argument > 1000000)
1516 return CC_ERROR;
1517 Argument = (Argument * 10) + (c - '0');
1519 return(CC_ARGHACK);
1521 else {
1522 if (LastChar + 1 >= InputLim)
1523 return CC_ERROR; /* end of buffer space */
1525 if (inputmode != MODE_INSERT) {
1526 UndoBuf[UndoSize++] = *Cursor;
1527 UndoBuf[UndoSize] = '\0';
1528 c_delafter(1); /* Do NOT use the saving ONE */
1530 c_insert(1);
1531 *Cursor++ = (Char) c;
1532 DoingArg = 0; /* just in case */
1533 RefPlusOne(1); /* fast refresh for one char. */
1535 return(CC_NORM);
1538 CCRETVAL
1539 e_argdigit(Char c) /* for ESC-n */
1541 #ifdef IS_ASCII
1542 c &= ASCII;
1543 #else
1544 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1545 #endif
1547 if (!Isdigit(c))
1548 return(CC_ERROR); /* no NULs in the input ever!! */
1550 if (DoingArg) { /* if doing an arg, add this in... */
1551 if (Argument > 1000000)
1552 return CC_ERROR;
1553 Argument = (Argument * 10) + (c - '0');
1555 else { /* else starting an argument */
1556 Argument = c - '0';
1557 DoingArg = 1;
1559 return(CC_ARGHACK);
1562 CCRETVAL
1563 v_zero(Char c) /* command mode 0 for vi */
1565 if (DoingArg) { /* if doing an arg, add this in... */
1566 if (Argument > 1000000)
1567 return CC_ERROR;
1568 Argument = (Argument * 10) + (c - '0');
1569 return(CC_ARGHACK);
1571 else { /* else starting an argument */
1572 Cursor = InputBuf;
1573 if (ActionFlag & TCSHOP_DELETE) {
1574 c_delfini();
1575 return(CC_REFRESH);
1577 RefCursor(); /* move the cursor */
1578 return(CC_NORM);
1582 /*ARGSUSED*/
1583 CCRETVAL
1584 e_newline(Char c)
1585 { /* always ignore argument */
1586 USE(c);
1587 if (adrof(STRhighlight) && MarkIsSet) {
1588 MarkIsSet = 0;
1589 ClearLines();
1590 ClearDisp();
1591 Refresh();
1593 MarkIsSet = 0;
1595 /* PastBottom(); NOW done in ed.inputl.c */
1596 *LastChar++ = '\n'; /* for the benefit of CSH */
1597 *LastChar = '\0'; /* just in case */
1598 if (VImode)
1599 InsertPos = InputBuf; /* Reset editing position */
1600 return(CC_NEWLINE);
1603 /*ARGSUSED*/
1604 CCRETVAL
1605 e_newline_hold(Char c)
1607 USE(c);
1608 c_save_inputbuf();
1609 HistSaved = 0;
1610 *LastChar++ = '\n'; /* for the benefit of CSH */
1611 *LastChar = '\0'; /* just in case */
1612 return(CC_NEWLINE);
1615 /*ARGSUSED*/
1616 CCRETVAL
1617 e_newline_down_hist(Char c)
1619 USE(c);
1620 if (Hist_num > 1) {
1621 HistSaved = Hist_num;
1623 *LastChar++ = '\n'; /* for the benefit of CSH */
1624 *LastChar = '\0'; /* just in case */
1625 return(CC_NEWLINE);
1628 /*ARGSUSED*/
1629 CCRETVAL
1630 e_send_eof(Char c)
1631 { /* for when ^D is ONLY send-eof */
1632 USE(c);
1633 PastBottom();
1634 *LastChar = '\0'; /* just in case */
1635 return(CC_EOF);
1638 /*ARGSUSED*/
1639 CCRETVAL
1640 e_complete(Char c)
1642 USE(c);
1643 *LastChar = '\0'; /* just in case */
1644 return(CC_COMPLETE);
1647 /*ARGSUSED*/
1648 CCRETVAL
1649 e_complete_back(Char c)
1651 USE(c);
1652 *LastChar = '\0'; /* just in case */
1653 return(CC_COMPLETE_BACK);
1656 /*ARGSUSED*/
1657 CCRETVAL
1658 e_complete_fwd(Char c)
1660 USE(c);
1661 *LastChar = '\0'; /* just in case */
1662 return(CC_COMPLETE_FWD);
1665 /*ARGSUSED*/
1666 CCRETVAL
1667 e_complete_all(Char c)
1669 USE(c);
1670 *LastChar = '\0'; /* just in case */
1671 return(CC_COMPLETE_ALL);
1674 /*ARGSUSED*/
1675 CCRETVAL
1676 v_cm_complete(Char c)
1678 USE(c);
1679 if (Cursor < LastChar)
1680 Cursor++;
1681 *LastChar = '\0'; /* just in case */
1682 return(CC_COMPLETE);
1685 /*ARGSUSED*/
1686 CCRETVAL
1687 e_toggle_hist(Char c)
1689 struct Hist *hp;
1690 int h;
1692 USE(c);
1693 *LastChar = '\0'; /* just in case */
1695 if (Hist_num <= 0) {
1696 return CC_ERROR;
1699 hp = Histlist.Hnext;
1700 if (hp == NULL) { /* this is only if no history */
1701 return(CC_ERROR);
1704 for (h = 1; h < Hist_num; h++)
1705 hp = hp->Hnext;
1707 if (!CurrentHistLit) {
1708 if (hp->histline) {
1709 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1710 CurrentHistLit = 1;
1712 else {
1713 return CC_ERROR;
1716 else {
1717 Char *p;
1719 p = sprlex(&hp->Hlex);
1720 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1721 xfree(p);
1722 CurrentHistLit = 0;
1725 LastChar = Strend(InputBuf);
1726 if (LastChar > InputBuf) {
1727 if (LastChar[-1] == '\n')
1728 LastChar--;
1729 if (LastChar[-1] == ' ')
1730 LastChar--;
1731 if (LastChar < InputBuf)
1732 LastChar = InputBuf;
1735 #ifdef KSHVI
1736 if (VImode)
1737 Cursor = InputBuf;
1738 else
1739 #endif /* KSHVI */
1740 Cursor = LastChar;
1742 return(CC_REFRESH);
1745 /*ARGSUSED*/
1746 CCRETVAL
1747 e_up_hist(Char c)
1749 Char beep = 0;
1751 USE(c);
1752 UndoAction = TCSHOP_NOP;
1753 *LastChar = '\0'; /* just in case */
1755 if (Hist_num == 0) { /* save the current buffer away */
1756 HistBuf.len = 0;
1757 Strbuf_append(&HistBuf, InputBuf);
1758 Strbuf_terminate(&HistBuf);
1761 Hist_num += Argument;
1763 if (GetHistLine() == CC_ERROR) {
1764 beep = 1;
1765 (void) GetHistLine(); /* Hist_num was fixed by first call */
1768 Refresh();
1769 if (beep)
1770 return(CC_ERROR);
1771 else
1772 return(CC_NORM); /* was CC_UP_HIST */
1775 /*ARGSUSED*/
1776 CCRETVAL
1777 e_down_hist(Char c)
1779 USE(c);
1780 UndoAction = TCSHOP_NOP;
1781 *LastChar = '\0'; /* just in case */
1783 Hist_num -= Argument;
1785 if (Hist_num < 0) {
1786 Hist_num = 0;
1787 return(CC_ERROR); /* make it beep */
1790 return(GetHistLine());
1796 * c_hmatch() return True if the pattern matches the prefix
1798 static int
1799 c_hmatch(Char *str)
1801 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1802 return 1;
1803 return Gmatch(str, patbuf.s);
1807 * c_hsetpat(): Set the history seatch pattern
1809 static void
1810 c_hsetpat(void)
1812 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1813 patbuf.len = 0;
1814 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1815 Strbuf_terminate(&patbuf);
1817 #ifdef SDEBUG
1818 xprintf("\nHist_num = %d\n", Hist_num);
1819 xprintf("patlen = %d\n", (int)patbuf.len);
1820 xprintf("patbuf = \"%S\"\n", patbuf.s);
1821 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1822 #endif
1825 /*ARGSUSED*/
1826 CCRETVAL
1827 e_up_search_hist(Char c)
1829 struct Hist *hp;
1830 int h;
1831 int found = 0;
1833 USE(c);
1834 ActionFlag = TCSHOP_NOP;
1835 UndoAction = TCSHOP_NOP;
1836 *LastChar = '\0'; /* just in case */
1837 if (Hist_num < 0) {
1838 #ifdef DEBUG_EDIT
1839 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1840 #endif
1841 Hist_num = 0;
1842 return(CC_ERROR);
1845 if (Hist_num == 0) {
1846 HistBuf.len = 0;
1847 Strbuf_append(&HistBuf, InputBuf);
1848 Strbuf_terminate(&HistBuf);
1852 hp = Histlist.Hnext;
1853 if (hp == NULL)
1854 return(CC_ERROR);
1856 c_hsetpat(); /* Set search pattern !! */
1858 for (h = 1; h <= Hist_num; h++)
1859 hp = hp->Hnext;
1861 while (hp != NULL) {
1862 Char *hl;
1863 int matched;
1865 if (hp->histline == NULL)
1866 hp->histline = sprlex(&hp->Hlex);
1867 if (HistLit)
1868 hl = hp->histline;
1869 else {
1870 hl = sprlex(&hp->Hlex);
1871 cleanup_push(hl, xfree);
1873 #ifdef SDEBUG
1874 xprintf("Comparing with \"%S\"\n", hl);
1875 #endif
1876 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1877 hl[LastChar-InputBuf]) && c_hmatch(hl);
1878 if (!HistLit)
1879 cleanup_until(hl);
1880 if (matched) {
1881 found++;
1882 break;
1884 h++;
1885 hp = hp->Hnext;
1888 if (!found) {
1889 #ifdef SDEBUG
1890 xprintf("not found\n");
1891 #endif
1892 return(CC_ERROR);
1895 Hist_num = h;
1897 return(GetHistLine());
1900 /*ARGSUSED*/
1901 CCRETVAL
1902 e_down_search_hist(Char c)
1904 struct Hist *hp;
1905 int h;
1906 int found = 0;
1908 USE(c);
1909 ActionFlag = TCSHOP_NOP;
1910 UndoAction = TCSHOP_NOP;
1911 *LastChar = '\0'; /* just in case */
1913 if (Hist_num == 0)
1914 return(CC_ERROR);
1916 hp = Histlist.Hnext;
1917 if (hp == 0)
1918 return(CC_ERROR);
1920 c_hsetpat(); /* Set search pattern !! */
1922 for (h = 1; h < Hist_num && hp; h++) {
1923 Char *hl;
1924 if (hp->histline == NULL)
1925 hp->histline = sprlex(&hp->Hlex);
1926 if (HistLit)
1927 hl = hp->histline;
1928 else {
1929 hl = sprlex(&hp->Hlex);
1930 cleanup_push(hl, xfree);
1932 #ifdef SDEBUG
1933 xprintf("Comparing with \"%S\"\n", hl);
1934 #endif
1935 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1936 hl[LastChar-InputBuf]) && c_hmatch(hl))
1937 found = h;
1938 if (!HistLit)
1939 cleanup_until(hl);
1940 hp = hp->Hnext;
1943 if (!found) { /* is it the current history number? */
1944 if (!c_hmatch(HistBuf.s)) {
1945 #ifdef SDEBUG
1946 xprintf("not found\n");
1947 #endif
1948 return(CC_ERROR);
1952 Hist_num = found;
1954 return(GetHistLine());
1957 /*ARGSUSED*/
1958 CCRETVAL
1959 e_helpme(Char c)
1961 USE(c);
1962 PastBottom();
1963 *LastChar = '\0'; /* just in case */
1964 return(CC_HELPME);
1967 /*ARGSUSED*/
1968 CCRETVAL
1969 e_correct(Char c)
1971 USE(c);
1972 *LastChar = '\0'; /* just in case */
1973 return(CC_CORRECT);
1976 /*ARGSUSED*/
1977 CCRETVAL
1978 e_correctl(Char c)
1980 USE(c);
1981 *LastChar = '\0'; /* just in case */
1982 return(CC_CORRECT_L);
1985 /*ARGSUSED*/
1986 CCRETVAL
1987 e_run_fg_editor(Char c)
1989 struct process *pp;
1991 USE(c);
1992 if ((pp = find_stop_ed()) != NULL) {
1993 /* save our editor state so we can restore it */
1994 c_save_inputbuf();
1995 Hist_num = 0; /* for the history commands */
1997 /* put the tty in a sane mode */
1998 PastBottom();
1999 (void) Cookedmode(); /* make sure the tty is set up correctly */
2001 /* do it! */
2002 fg_proc_entry(pp);
2004 (void) Rawmode(); /* go on */
2005 Refresh();
2006 RestoreSaved = 0;
2007 HistSaved = 0;
2009 return(CC_NORM);
2012 /*ARGSUSED*/
2013 CCRETVAL
2014 e_list_choices(Char c)
2016 USE(c);
2017 PastBottom();
2018 *LastChar = '\0'; /* just in case */
2019 return(CC_LIST_CHOICES);
2022 /*ARGSUSED*/
2023 CCRETVAL
2024 e_list_all(Char c)
2026 USE(c);
2027 PastBottom();
2028 *LastChar = '\0'; /* just in case */
2029 return(CC_LIST_ALL);
2032 /*ARGSUSED*/
2033 CCRETVAL
2034 e_list_glob(Char c)
2036 USE(c);
2037 PastBottom();
2038 *LastChar = '\0'; /* just in case */
2039 return(CC_LIST_GLOB);
2042 /*ARGSUSED*/
2043 CCRETVAL
2044 e_expand_glob(Char c)
2046 USE(c);
2047 *LastChar = '\0'; /* just in case */
2048 return(CC_EXPAND_GLOB);
2051 /*ARGSUSED*/
2052 CCRETVAL
2053 e_normalize_path(Char c)
2055 USE(c);
2056 *LastChar = '\0'; /* just in case */
2057 return(CC_NORMALIZE_PATH);
2060 /*ARGSUSED*/
2061 CCRETVAL
2062 e_normalize_command(Char c)
2064 USE(c);
2065 *LastChar = '\0'; /* just in case */
2066 return(CC_NORMALIZE_COMMAND);
2069 /*ARGSUSED*/
2070 CCRETVAL
2071 e_expand_vars(Char c)
2073 USE(c);
2074 *LastChar = '\0'; /* just in case */
2075 return(CC_EXPAND_VARS);
2078 /*ARGSUSED*/
2079 CCRETVAL
2080 e_which(Char c)
2081 { /* do a fast command line which(1) */
2082 USE(c);
2083 c_save_inputbuf();
2084 Hist_num = 0; /* for the history commands */
2085 PastBottom();
2086 *LastChar = '\0'; /* just in case */
2087 return(CC_WHICH);
2090 /*ARGSUSED*/
2091 CCRETVAL
2092 e_last_item(Char c)
2093 { /* insert the last element of the prev. cmd */
2094 struct Hist *hp;
2095 struct wordent *wp, *firstp;
2096 int i;
2097 Char *expanded;
2099 USE(c);
2100 if (Argument <= 0)
2101 return(CC_ERROR);
2103 hp = Histlist.Hnext;
2104 if (hp == NULL) { /* this is only if no history */
2105 return(CC_ERROR);
2108 wp = (hp->Hlex).prev;
2110 if (wp->prev == (struct wordent *) NULL)
2111 return(CC_ERROR); /* an empty history entry */
2113 firstp = (hp->Hlex).next;
2115 /* back up arg words in lex */
2116 for (i = 0; i < Argument && wp != firstp; i++) {
2117 wp = wp->prev;
2120 expanded = expand_lex(wp->prev, 0, i - 1);
2121 if (InsertStr(expanded)) {
2122 xfree(expanded);
2123 return(CC_ERROR);
2126 xfree(expanded);
2127 return(CC_REFRESH);
2130 /*ARGSUSED*/
2131 CCRETVAL
2132 e_dabbrev_expand(Char c)
2133 { /* expand to preceding word matching prefix */
2134 Char *cp, *ncp, *bp;
2135 struct Hist *hp;
2136 int arg = 0, i;
2137 size_t len = 0;
2138 int found = 0;
2139 Char *hbuf;
2140 static int oldevent, hist, word;
2141 static Char *start, *oldcursor;
2143 USE(c);
2144 if (Argument <= 0)
2145 return(CC_ERROR);
2147 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2148 if (cp == Cursor || Isspace(*cp))
2149 return(CC_ERROR);
2151 hbuf = NULL;
2152 hp = Histlist.Hnext;
2153 bp = InputBuf;
2154 if (Argument == 1 && eventno == oldevent && cp == start &&
2155 Cursor == oldcursor && patbuf.len > 0
2156 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2157 /* continue previous search - go to last match (hist/word) */
2158 if (hist != 0) { /* need to move up history */
2159 for (i = 1; i < hist && hp != NULL; i++)
2160 hp = hp->Hnext;
2161 if (hp == NULL) /* "can't happen" */
2162 goto err_hbuf;
2163 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2164 cp = Strend(hbuf);
2165 bp = hbuf;
2166 hp = hp->Hnext;
2168 cp = c_preword(cp, bp, word, STRshwordsep);
2169 } else { /* starting new search */
2170 oldevent = eventno;
2171 start = cp;
2172 patbuf.len = 0;
2173 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2174 hist = 0;
2175 word = 0;
2178 while (!found) {
2179 ncp = c_preword(cp, bp, 1, STRshwordsep);
2180 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2181 hist++;
2182 word = 0;
2183 if (hp == NULL)
2184 goto err_hbuf;
2185 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2186 cp = Strend(hbuf);
2187 bp = hbuf;
2188 hp = hp->Hnext;
2189 continue;
2190 } else {
2191 word++;
2192 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2193 cp = ncp;
2195 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2196 /* We don't fully check distinct matches as Gnuemacs does: */
2197 if (Argument > 1) { /* just count matches */
2198 if (++arg >= Argument)
2199 found++;
2200 } else { /* match if distinct from previous */
2201 if (len != (size_t)(Cursor - start)
2202 || Strncmp(cp, start, len) != 0)
2203 found++;
2208 if (LastChar + len - (Cursor - start) >= InputLim)
2209 goto err_hbuf; /* no room */
2210 DeleteBack(Cursor - start);
2211 c_insert(len);
2212 while (len--)
2213 *Cursor++ = *cp++;
2214 oldcursor = Cursor;
2215 xfree(hbuf);
2216 return(CC_REFRESH);
2218 err_hbuf:
2219 xfree(hbuf);
2220 return CC_ERROR;
2223 /*ARGSUSED*/
2224 CCRETVAL
2225 e_yank_kill(Char c)
2226 { /* almost like GnuEmacs */
2227 int len;
2228 Char *kp, *cp;
2230 USE(c);
2231 if (KillRingLen == 0) /* nothing killed */
2232 return(CC_ERROR);
2233 len = Strlen(KillRing[YankPos].buf);
2234 if (LastChar + len >= InputLim)
2235 return(CC_ERROR); /* end of buffer space */
2237 /* else */
2238 cp = Cursor; /* for speed */
2240 c_insert(len); /* open the space, */
2241 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2242 *cp++ = *kp;
2244 if (Argument == 1) { /* if no arg */
2245 Mark = Cursor; /* mark at beginning, cursor at end */
2246 Cursor = cp;
2247 } else {
2248 Mark = cp; /* else cursor at beginning, mark at end */
2251 if (adrof(STRhighlight) && MarkIsSet) {
2252 ClearLines();
2253 ClearDisp();
2255 MarkIsSet = 0;
2256 return(CC_REFRESH);
2259 /*ARGSUSED*/
2260 CCRETVAL
2261 e_yank_pop(Char c)
2262 { /* almost like GnuEmacs */
2263 int m_bef_c, del_len, ins_len;
2264 Char *kp, *cp;
2266 USE(c);
2268 #if 0
2269 /* XXX This "should" be here, but doesn't work, since LastCmd
2270 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2271 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2272 second one will "succeed" even if the first one wasn't preceded
2273 by a yank, and giving an argument is impossible. Now we "succeed"
2274 regardless of previous command, which is wrong too of course. */
2275 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2276 return(CC_ERROR);
2277 #endif
2279 if (KillRingLen == 0) /* nothing killed */
2280 return(CC_ERROR);
2281 YankPos -= Argument;
2282 while (YankPos < 0)
2283 YankPos += KillRingLen;
2284 YankPos %= KillRingLen;
2286 if (Cursor > Mark) {
2287 del_len = Cursor - Mark;
2288 m_bef_c = 1;
2289 } else {
2290 del_len = Mark - Cursor;
2291 m_bef_c = 0;
2293 ins_len = Strlen(KillRing[YankPos].buf);
2294 if (LastChar + ins_len - del_len >= InputLim)
2295 return(CC_ERROR); /* end of buffer space */
2297 if (m_bef_c) {
2298 c_delbefore(del_len);
2299 } else {
2300 c_delafter(del_len);
2302 cp = Cursor; /* for speed */
2304 c_insert(ins_len); /* open the space, */
2305 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2306 *cp++ = *kp;
2308 if (m_bef_c) {
2309 Mark = Cursor; /* mark at beginning, cursor at end */
2310 Cursor = cp;
2311 } else {
2312 Mark = cp; /* else cursor at beginning, mark at end */
2315 if (adrof(STRhighlight) && MarkIsSet) {
2316 ClearLines();
2317 ClearDisp();
2319 MarkIsSet = 0;
2320 return(CC_REFRESH);
2323 /*ARGSUSED*/
2324 CCRETVAL
2325 v_delprev(Char c) /* Backspace key in insert mode */
2327 int rc;
2329 USE(c);
2330 rc = CC_ERROR;
2332 if (InsertPos != 0) {
2333 if (Argument <= Cursor - InsertPos) {
2334 c_delbefore(Argument); /* delete before */
2335 rc = CC_REFRESH;
2338 return(rc);
2339 } /* v_delprev */
2341 /*ARGSUSED*/
2342 CCRETVAL
2343 e_delprev(Char c)
2345 USE(c);
2346 if (Cursor > InputBuf) {
2347 c_delbefore(Argument); /* delete before dot */
2348 return(CC_REFRESH);
2350 else {
2351 return(CC_ERROR);
2355 /*ARGSUSED*/
2356 CCRETVAL
2357 e_delwordprev(Char c)
2359 Char *cp;
2361 USE(c);
2362 if (Cursor == InputBuf)
2363 return(CC_ERROR);
2364 /* else */
2366 cp = c_prev_word(Cursor, InputBuf, Argument);
2368 c_push_kill(cp, Cursor); /* save the text */
2370 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2371 return(CC_REFRESH);
2374 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2376 * Changed the names of some of the ^D family of editor functions to
2377 * correspond to what they actually do and created new e_delnext_list
2378 * for completeness.
2380 * Old names: New names:
2382 * delete-char delete-char-or-eof
2383 * F_DELNEXT F_DELNEXT_EOF
2384 * e_delnext e_delnext_eof
2385 * edelnxt edelnxteof
2386 * delete-char-or-eof delete-char
2387 * F_DELNEXT_EOF F_DELNEXT
2388 * e_delnext_eof e_delnext
2389 * edelnxteof edelnxt
2390 * delete-char-or-list delete-char-or-list-or-eof
2391 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2392 * e_list_delnext e_delnext_list_eof
2393 * edellsteof
2394 * (no old equivalent) delete-char-or-list
2395 * F_DELNEXT_LIST
2396 * e_delnext_list
2397 * e_delnxtlst
2400 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2401 /* rename e_delnext() -> e_delnext_eof() */
2402 /*ARGSUSED*/
2403 CCRETVAL
2404 e_delnext(Char c)
2406 USE(c);
2407 if (Cursor == LastChar) {/* if I'm at the end */
2408 if (!VImode) {
2409 return(CC_ERROR);
2411 else {
2412 if (Cursor != InputBuf)
2413 Cursor--;
2414 else
2415 return(CC_ERROR);
2418 c_delafter(Argument); /* delete after dot */
2419 if (Cursor > LastChar)
2420 Cursor = LastChar; /* bounds check */
2421 return(CC_REFRESH);
2425 /*ARGSUSED*/
2426 CCRETVAL
2427 e_delnext_eof(Char c)
2429 USE(c);
2430 if (Cursor == LastChar) {/* if I'm at the end */
2431 if (!VImode) {
2432 if (Cursor == InputBuf) {
2433 /* if I'm also at the beginning */
2434 so_write(STReof, 4);/* then do a EOF */
2435 flush();
2436 return(CC_EOF);
2438 else
2439 return(CC_ERROR);
2441 else {
2442 if (Cursor != InputBuf)
2443 Cursor--;
2444 else
2445 return(CC_ERROR);
2448 c_delafter(Argument); /* delete after dot */
2449 if (Cursor > LastChar)
2450 Cursor = LastChar; /* bounds check */
2451 return(CC_REFRESH);
2454 /*ARGSUSED*/
2455 CCRETVAL
2456 e_delnext_list(Char c)
2458 USE(c);
2459 if (Cursor == LastChar) { /* if I'm at the end */
2460 PastBottom();
2461 *LastChar = '\0'; /* just in case */
2462 return(CC_LIST_CHOICES);
2464 else {
2465 c_delafter(Argument); /* delete after dot */
2466 if (Cursor > LastChar)
2467 Cursor = LastChar; /* bounds check */
2468 return(CC_REFRESH);
2472 /*ARGSUSED*/
2473 CCRETVAL
2474 e_delnext_list_eof(Char c)
2476 USE(c);
2477 if (Cursor == LastChar) { /* if I'm at the end */
2478 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2479 so_write(STReof, 4);/* then do a EOF */
2480 flush();
2481 return(CC_EOF);
2483 else {
2484 PastBottom();
2485 *LastChar = '\0'; /* just in case */
2486 return(CC_LIST_CHOICES);
2489 else {
2490 c_delafter(Argument); /* delete after dot */
2491 if (Cursor > LastChar)
2492 Cursor = LastChar; /* bounds check */
2493 return(CC_REFRESH);
2497 /*ARGSUSED*/
2498 CCRETVAL
2499 e_list_eof(Char c)
2501 CCRETVAL rv;
2503 USE(c);
2504 if (Cursor == LastChar && Cursor == InputBuf) {
2505 so_write(STReof, 4); /* then do a EOF */
2506 flush();
2507 rv = CC_EOF;
2509 else {
2510 PastBottom();
2511 *LastChar = '\0'; /* just in case */
2512 rv = CC_LIST_CHOICES;
2514 return rv;
2517 /*ARGSUSED*/
2518 CCRETVAL
2519 e_delwordnext(Char c)
2521 Char *cp;
2523 USE(c);
2524 if (Cursor == LastChar)
2525 return(CC_ERROR);
2526 /* else */
2528 cp = c_next_word(Cursor, LastChar, Argument);
2530 c_push_kill(Cursor, cp); /* save the text */
2532 c_delafter((int)(cp - Cursor)); /* delete after dot */
2533 if (Cursor > LastChar)
2534 Cursor = LastChar; /* bounds check */
2535 return(CC_REFRESH);
2538 /*ARGSUSED*/
2539 CCRETVAL
2540 e_toend(Char c)
2542 USE(c);
2543 Cursor = LastChar;
2544 if (VImode)
2545 if (ActionFlag & TCSHOP_DELETE) {
2546 c_delfini();
2547 return(CC_REFRESH);
2549 RefCursor(); /* move the cursor */
2550 return(CC_NORM);
2553 /*ARGSUSED*/
2554 CCRETVAL
2555 e_tobeg(Char c)
2557 USE(c);
2558 Cursor = InputBuf;
2560 if (VImode) {
2561 while (Isspace(*Cursor)) /* We want FIRST non space character */
2562 Cursor++;
2563 if (ActionFlag & TCSHOP_DELETE) {
2564 c_delfini();
2565 return(CC_REFRESH);
2569 RefCursor(); /* move the cursor */
2570 return(CC_NORM);
2573 /*ARGSUSED*/
2574 CCRETVAL
2575 e_killend(Char c)
2577 USE(c);
2578 c_push_kill(Cursor, LastChar); /* copy it */
2579 LastChar = Cursor; /* zap! -- delete to end */
2580 if (Mark > Cursor)
2581 Mark = Cursor;
2582 MarkIsSet = 0;
2583 return(CC_REFRESH);
2587 /*ARGSUSED*/
2588 CCRETVAL
2589 e_killbeg(Char c)
2591 USE(c);
2592 c_push_kill(InputBuf, Cursor); /* copy it */
2593 c_delbefore((int)(Cursor - InputBuf));
2594 if (Mark && Mark > Cursor)
2595 Mark -= Cursor-InputBuf;
2596 return(CC_REFRESH);
2599 /*ARGSUSED*/
2600 CCRETVAL
2601 e_killall(Char c)
2603 USE(c);
2604 c_push_kill(InputBuf, LastChar); /* copy it */
2605 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2606 MarkIsSet = 0;
2607 return(CC_REFRESH);
2610 /*ARGSUSED*/
2611 CCRETVAL
2612 e_killregion(Char c)
2614 USE(c);
2615 if (!Mark)
2616 return(CC_ERROR);
2618 if (Mark > Cursor) {
2619 c_push_kill(Cursor, Mark); /* copy it */
2620 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2621 Mark = Cursor;
2623 else { /* mark is before cursor */
2624 c_push_kill(Mark, Cursor); /* copy it */
2625 c_delbefore((int)(Cursor - Mark));
2627 if (adrof(STRhighlight) && MarkIsSet) {
2628 ClearLines();
2629 ClearDisp();
2631 MarkIsSet = 0;
2632 return(CC_REFRESH);
2635 /*ARGSUSED*/
2636 CCRETVAL
2637 e_copyregion(Char c)
2639 USE(c);
2640 if (!Mark)
2641 return(CC_ERROR);
2643 if (Mark > Cursor) {
2644 c_push_kill(Cursor, Mark); /* copy it */
2646 else { /* mark is before cursor */
2647 c_push_kill(Mark, Cursor); /* copy it */
2649 return(CC_NORM); /* don't even need to Refresh() */
2652 /*ARGSUSED*/
2653 CCRETVAL
2654 e_charswitch(Char cc)
2656 Char c;
2658 USE(cc);
2660 /* do nothing if we are at beginning of line or have only one char */
2661 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2662 return(CC_ERROR);
2665 if (Cursor < LastChar) {
2666 Cursor++;
2668 c = Cursor[-2];
2669 Cursor[-2] = Cursor[-1];
2670 Cursor[-1] = c;
2671 return(CC_REFRESH);
2674 /*ARGSUSED*/
2675 CCRETVAL
2676 e_gcharswitch(Char cc)
2677 { /* gosmacs style ^T */
2678 Char c;
2680 USE(cc);
2681 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2682 c = Cursor[-2];
2683 Cursor[-2] = Cursor[-1];
2684 Cursor[-1] = c;
2685 return(CC_REFRESH);
2687 else {
2688 return(CC_ERROR);
2692 /*ARGSUSED*/
2693 CCRETVAL
2694 e_charback(Char c)
2696 USE(c);
2697 if (Cursor > InputBuf) {
2698 if (Argument > Cursor - InputBuf)
2699 Cursor = InputBuf;
2700 else
2701 Cursor -= Argument;
2703 if (VImode)
2704 if (ActionFlag & TCSHOP_DELETE) {
2705 c_delfini();
2706 return(CC_REFRESH);
2709 RefCursor();
2710 return(CC_NORM);
2712 else {
2713 return(CC_ERROR);
2717 /*ARGSUSED*/
2718 CCRETVAL
2719 v_wordback(Char c)
2721 USE(c);
2722 if (Cursor == InputBuf)
2723 return(CC_ERROR);
2724 /* else */
2726 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2728 if (ActionFlag & TCSHOP_DELETE) {
2729 c_delfini();
2730 return(CC_REFRESH);
2733 RefCursor();
2734 return(CC_NORM);
2737 /*ARGSUSED*/
2738 CCRETVAL
2739 e_wordback(Char c)
2741 USE(c);
2742 if (Cursor == InputBuf)
2743 return(CC_ERROR);
2744 /* else */
2746 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2748 if (VImode)
2749 if (ActionFlag & TCSHOP_DELETE) {
2750 c_delfini();
2751 return(CC_REFRESH);
2754 RefCursor();
2755 return(CC_NORM);
2758 /*ARGSUSED*/
2759 CCRETVAL
2760 e_charfwd(Char c)
2762 USE(c);
2763 if (Cursor < LastChar) {
2764 Cursor += Argument;
2765 if (Cursor > LastChar)
2766 Cursor = LastChar;
2768 if (VImode)
2769 if (ActionFlag & TCSHOP_DELETE) {
2770 c_delfini();
2771 return(CC_REFRESH);
2774 RefCursor();
2775 return(CC_NORM);
2777 else {
2778 return(CC_ERROR);
2782 /*ARGSUSED*/
2783 CCRETVAL
2784 e_wordfwd(Char c)
2786 USE(c);
2787 if (Cursor == LastChar)
2788 return(CC_ERROR);
2789 /* else */
2791 Cursor = c_next_word(Cursor, LastChar, Argument);
2793 if (VImode)
2794 if (ActionFlag & TCSHOP_DELETE) {
2795 c_delfini();
2796 return(CC_REFRESH);
2799 RefCursor();
2800 return(CC_NORM);
2803 /*ARGSUSED*/
2804 CCRETVAL
2805 v_wordfwd(Char c)
2807 USE(c);
2808 if (Cursor == LastChar)
2809 return(CC_ERROR);
2810 /* else */
2812 Cursor = c_nexword(Cursor, LastChar, Argument);
2814 if (VImode)
2815 if (ActionFlag & TCSHOP_DELETE) {
2816 c_delfini();
2817 return(CC_REFRESH);
2820 RefCursor();
2821 return(CC_NORM);
2824 /*ARGSUSED*/
2825 CCRETVAL
2826 v_wordbegnext(Char c)
2828 USE(c);
2829 if (Cursor == LastChar)
2830 return(CC_ERROR);
2831 /* else */
2833 Cursor = c_next_word(Cursor, LastChar, Argument);
2834 if (Cursor < LastChar)
2835 Cursor++;
2837 if (VImode)
2838 if (ActionFlag & TCSHOP_DELETE) {
2839 c_delfini();
2840 return(CC_REFRESH);
2843 RefCursor();
2844 return(CC_NORM);
2847 /*ARGSUSED*/
2848 static CCRETVAL
2849 v_repeat_srch(int c)
2851 CCRETVAL rv = CC_ERROR;
2852 #ifdef SDEBUG
2853 xprintf("dir %d patlen %d patbuf %S\n",
2854 c, (int)patbuf.len, patbuf.s);
2855 #endif
2857 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2858 LastChar = InputBuf;
2859 switch (c) {
2860 case F_DOWN_SEARCH_HIST:
2861 rv = e_down_search_hist(0);
2862 break;
2863 case F_UP_SEARCH_HIST:
2864 rv = e_up_search_hist(0);
2865 break;
2866 default:
2867 break;
2869 return rv;
2872 static CCRETVAL
2873 v_csearch_back(Char ch, int count, int tflag)
2875 Char *cp;
2877 cp = Cursor;
2878 while (count--) {
2879 if (*cp == ch)
2880 cp--;
2881 while (cp > InputBuf && *cp != ch)
2882 cp--;
2885 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2886 return(CC_ERROR);
2888 if (*cp == ch && tflag)
2889 cp++;
2891 Cursor = cp;
2893 if (ActionFlag & TCSHOP_DELETE) {
2894 Cursor++;
2895 c_delfini();
2896 return(CC_REFRESH);
2899 RefCursor();
2900 return(CC_NORM);
2903 static CCRETVAL
2904 v_csearch_fwd(Char ch, int count, int tflag)
2906 Char *cp;
2908 cp = Cursor;
2909 while (count--) {
2910 if(*cp == ch)
2911 cp++;
2912 while (cp < LastChar && *cp != ch)
2913 cp++;
2916 if (cp >= LastChar)
2917 return(CC_ERROR);
2919 if (*cp == ch && tflag)
2920 cp--;
2922 Cursor = cp;
2924 if (ActionFlag & TCSHOP_DELETE) {
2925 Cursor++;
2926 c_delfini();
2927 return(CC_REFRESH);
2929 RefCursor();
2930 return(CC_NORM);
2933 /*ARGSUSED*/
2934 static CCRETVAL
2935 v_action(int c)
2937 Char *cp, *kp;
2939 if (ActionFlag == TCSHOP_DELETE) {
2940 ActionFlag = TCSHOP_NOP;
2941 ActionPos = 0;
2943 UndoSize = 0;
2944 kp = UndoBuf;
2945 for (cp = InputBuf; cp < LastChar; cp++) {
2946 *kp++ = *cp;
2947 UndoSize++;
2950 UndoAction = TCSHOP_INSERT;
2951 UndoPtr = InputBuf;
2952 LastChar = InputBuf;
2953 Cursor = InputBuf;
2954 if (c & TCSHOP_INSERT)
2955 c_alternativ_key_map(0);
2957 return(CC_REFRESH);
2959 #ifdef notdef
2960 else if (ActionFlag == TCSHOP_NOP) {
2961 #endif
2962 ActionPos = Cursor;
2963 ActionFlag = c;
2964 return(CC_ARGHACK); /* Do NOT clear out argument */
2965 #ifdef notdef
2967 else {
2968 ActionFlag = 0;
2969 ActionPos = 0;
2970 return(CC_ERROR);
2972 #endif
2975 #ifdef COMMENT
2976 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2977 static void
2978 c_get_word(Char **begin, Char **end)
2980 Char *cp;
2982 cp = &Cursor[0];
2983 while (Argument--) {
2984 while ((cp <= LastChar) && (isword(*cp)))
2985 cp++;
2986 *end = --cp;
2987 while ((cp >= InputBuf) && (isword(*cp)))
2988 cp--;
2989 *begin = ++cp;
2992 #endif /* COMMENT */
2994 /*ARGSUSED*/
2995 CCRETVAL
2996 e_uppercase(Char c)
2998 Char *cp, *end;
3000 USE(c);
3001 end = c_next_word(Cursor, LastChar, Argument);
3003 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3004 if (Islower(*cp))
3005 *cp = Toupper(*cp);
3007 Cursor = end;
3008 if (Cursor > LastChar)
3009 Cursor = LastChar;
3010 return(CC_REFRESH);
3014 /*ARGSUSED*/
3015 CCRETVAL
3016 e_capitolcase(Char c)
3018 Char *cp, *end;
3020 USE(c);
3021 end = c_next_word(Cursor, LastChar, Argument);
3023 cp = Cursor;
3024 for (; cp < end; cp++) {
3025 if (Isalpha(*cp)) {
3026 if (Islower(*cp))
3027 *cp = Toupper(*cp);
3028 cp++;
3029 break;
3032 for (; cp < end; cp++)
3033 if (Isupper(*cp))
3034 *cp = Tolower(*cp);
3036 Cursor = end;
3037 if (Cursor > LastChar)
3038 Cursor = LastChar;
3039 return(CC_REFRESH);
3042 /*ARGSUSED*/
3043 CCRETVAL
3044 e_lowercase(Char c)
3046 Char *cp, *end;
3048 USE(c);
3049 end = c_next_word(Cursor, LastChar, Argument);
3051 for (cp = Cursor; cp < end; cp++)
3052 if (Isupper(*cp))
3053 *cp = Tolower(*cp);
3055 Cursor = end;
3056 if (Cursor > LastChar)
3057 Cursor = LastChar;
3058 return(CC_REFRESH);
3062 /*ARGSUSED*/
3063 CCRETVAL
3064 e_set_mark(Char c)
3066 USE(c);
3067 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3068 ClearLines();
3069 ClearDisp();
3070 Refresh();
3072 Mark = Cursor;
3073 MarkIsSet = 1;
3074 return(CC_NORM);
3077 /*ARGSUSED*/
3078 CCRETVAL
3079 e_exchange_mark(Char c)
3081 Char *cp;
3083 USE(c);
3084 cp = Cursor;
3085 Cursor = Mark;
3086 Mark = cp;
3087 RefCursor();
3088 return(CC_NORM);
3091 /*ARGSUSED*/
3092 CCRETVAL
3093 e_argfour(Char c)
3094 { /* multiply current argument by 4 */
3095 USE(c);
3096 if (Argument > 1000000)
3097 return CC_ERROR;
3098 DoingArg = 1;
3099 Argument *= 4;
3100 return(CC_ARGHACK);
3103 static void
3104 quote_mode_cleanup(void *unused)
3106 USE(unused);
3107 QuoteModeOff();
3110 /*ARGSUSED*/
3111 CCRETVAL
3112 e_quote(Char c)
3114 Char ch;
3115 int num;
3117 USE(c);
3118 QuoteModeOn();
3119 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3120 num = GetNextChar(&ch);
3121 cleanup_until(&c);
3122 if (num == 1)
3123 return e_insert(ch);
3124 else
3125 return e_send_eof(0);
3128 /*ARGSUSED*/
3129 CCRETVAL
3130 e_metanext(Char c)
3132 USE(c);
3133 MetaNext = 1;
3134 return(CC_ARGHACK); /* preserve argument */
3137 #ifdef notdef
3138 /*ARGSUSED*/
3139 CCRETVAL
3140 e_extendnext(Char c)
3142 CurrentKeyMap = CcAltMap;
3143 return(CC_ARGHACK); /* preserve argument */
3146 #endif
3148 /*ARGSUSED*/
3149 CCRETVAL
3150 v_insbeg(Char c)
3151 { /* move to beginning of line and start vi
3152 * insert mode */
3153 USE(c);
3154 Cursor = InputBuf;
3155 InsertPos = Cursor;
3157 UndoPtr = Cursor;
3158 UndoAction = TCSHOP_DELETE;
3160 RefCursor(); /* move the cursor */
3161 c_alternativ_key_map(0);
3162 return(CC_NORM);
3165 /*ARGSUSED*/
3166 CCRETVAL
3167 v_replone(Char c)
3168 { /* vi mode overwrite one character */
3169 USE(c);
3170 c_alternativ_key_map(0);
3171 inputmode = MODE_REPLACE_1;
3172 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3173 UndoPtr = Cursor;
3174 UndoSize = 0;
3175 return(CC_NORM);
3178 /*ARGSUSED*/
3179 CCRETVAL
3180 v_replmode(Char c)
3181 { /* vi mode start overwriting */
3182 USE(c);
3183 c_alternativ_key_map(0);
3184 inputmode = MODE_REPLACE;
3185 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3186 UndoPtr = Cursor;
3187 UndoSize = 0;
3188 return(CC_NORM);
3191 /*ARGSUSED*/
3192 CCRETVAL
3193 v_substchar(Char c)
3194 { /* vi mode substitute for one char */
3195 USE(c);
3196 c_delafter(Argument);
3197 c_alternativ_key_map(0);
3198 return(CC_REFRESH);
3201 /*ARGSUSED*/
3202 CCRETVAL
3203 v_substline(Char c)
3204 { /* vi mode replace whole line */
3205 USE(c);
3206 (void) e_killall(0);
3207 c_alternativ_key_map(0);
3208 return(CC_REFRESH);
3211 /*ARGSUSED*/
3212 CCRETVAL
3213 v_chgtoend(Char c)
3214 { /* vi mode change to end of line */
3215 USE(c);
3216 (void) e_killend(0);
3217 c_alternativ_key_map(0);
3218 return(CC_REFRESH);
3221 /*ARGSUSED*/
3222 CCRETVAL
3223 v_insert(Char c)
3224 { /* vi mode start inserting */
3225 USE(c);
3226 c_alternativ_key_map(0);
3228 InsertPos = Cursor;
3229 UndoPtr = Cursor;
3230 UndoAction = TCSHOP_DELETE;
3232 return(CC_NORM);
3235 /*ARGSUSED*/
3236 CCRETVAL
3237 v_add(Char c)
3238 { /* vi mode start adding */
3239 USE(c);
3240 c_alternativ_key_map(0);
3241 if (Cursor < LastChar)
3243 Cursor++;
3244 if (Cursor > LastChar)
3245 Cursor = LastChar;
3246 RefCursor();
3249 InsertPos = Cursor;
3250 UndoPtr = Cursor;
3251 UndoAction = TCSHOP_DELETE;
3253 return(CC_NORM);
3256 /*ARGSUSED*/
3257 CCRETVAL
3258 v_addend(Char c)
3259 { /* vi mode to add at end of line */
3260 USE(c);
3261 c_alternativ_key_map(0);
3262 Cursor = LastChar;
3264 InsertPos = LastChar; /* Mark where insertion begins */
3265 UndoPtr = LastChar;
3266 UndoAction = TCSHOP_DELETE;
3268 RefCursor();
3269 return(CC_NORM);
3272 /*ARGSUSED*/
3273 CCRETVAL
3274 v_change_case(Char cc)
3276 Char c;
3278 USE(cc);
3279 if (Cursor < LastChar) {
3280 #ifndef WINNT_NATIVE
3281 c = *Cursor;
3282 #else
3283 c = CHAR & *Cursor;
3284 #endif /* WINNT_NATIVE */
3285 if (Isupper(c))
3286 *Cursor++ = Tolower(c);
3287 else if (Islower(c))
3288 *Cursor++ = Toupper(c);
3289 else
3290 Cursor++;
3291 RefPlusOne(1); /* fast refresh for one char */
3292 return(CC_NORM);
3294 return(CC_ERROR);
3297 /*ARGSUSED*/
3298 CCRETVAL
3299 e_expand(Char c)
3301 Char *p;
3303 USE(c);
3304 for (p = InputBuf; Isspace(*p); p++)
3305 continue;
3306 if (p == LastChar)
3307 return(CC_ERROR);
3309 justpr++;
3310 Expand++;
3311 return(e_newline(0));
3314 /*ARGSUSED*/
3315 CCRETVAL
3316 e_startover(Char c)
3317 { /* erase all of current line, start again */
3318 USE(c);
3319 ResetInLine(0); /* reset the input pointers */
3320 return(CC_REFRESH);
3323 /*ARGSUSED*/
3324 CCRETVAL
3325 e_redisp(Char c)
3327 USE(c);
3328 ClearLines();
3329 ClearDisp();
3330 return(CC_REFRESH);
3333 /*ARGSUSED*/
3334 CCRETVAL
3335 e_cleardisp(Char c)
3337 USE(c);
3338 ClearScreen(); /* clear the whole real screen */
3339 ClearDisp(); /* reset everything */
3340 return(CC_REFRESH);
3343 /*ARGSUSED*/
3344 CCRETVAL
3345 e_tty_int(Char c)
3347 USE(c);
3348 #if defined(_MINIX) || defined(WINNT_NATIVE)
3349 /* SAK PATCH: erase all of current line, start again */
3350 ResetInLine(0); /* reset the input pointers */
3351 xputchar('\n');
3352 ClearDisp();
3353 return (CC_REFRESH);
3354 #else /* !_MINIX && !WINNT_NATIVE */
3355 /* do no editing */
3356 return (CC_NORM);
3357 #endif /* _MINIX || WINNT_NATIVE */
3361 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3362 * Function to send a character back to the input stream in cooked
3363 * mode. Only works if we have TIOCSTI
3365 /*ARGSUSED*/
3366 CCRETVAL
3367 e_stuff_char(Char c)
3369 #ifdef TIOCSTI
3370 int was_raw = Tty_raw_mode;
3371 char buf[MB_LEN_MAX];
3372 size_t i, len;
3374 if (was_raw)
3375 (void) Cookedmode();
3377 (void) xwrite(SHIN, "\n", 1);
3378 len = one_wctomb(buf, c & CHAR);
3379 for (i = 0; i < len; i++)
3380 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3382 if (was_raw)
3383 (void) Rawmode();
3384 return(e_redisp(c));
3385 #else /* !TIOCSTI */
3386 return(CC_ERROR);
3387 #endif /* !TIOCSTI */
3390 /*ARGSUSED*/
3391 CCRETVAL
3392 e_insovr(Char c)
3394 USE(c);
3395 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3396 return(CC_NORM);
3399 /*ARGSUSED*/
3400 CCRETVAL
3401 e_tty_dsusp(Char c)
3403 USE(c);
3404 /* do no editing */
3405 return(CC_NORM);
3408 /*ARGSUSED*/
3409 CCRETVAL
3410 e_tty_flusho(Char c)
3412 USE(c);
3413 /* do no editing */
3414 return(CC_NORM);
3417 /*ARGSUSED*/
3418 CCRETVAL
3419 e_tty_quit(Char c)
3421 USE(c);
3422 /* do no editing */
3423 return(CC_NORM);
3426 /*ARGSUSED*/
3427 CCRETVAL
3428 e_tty_tsusp(Char c)
3430 USE(c);
3431 /* do no editing */
3432 return(CC_NORM);
3435 /*ARGSUSED*/
3436 CCRETVAL
3437 e_tty_stopo(Char c)
3439 USE(c);
3440 /* do no editing */
3441 return(CC_NORM);
3444 /*ARGSUSED*/
3445 CCRETVAL
3446 e_expand_history(Char c)
3448 USE(c);
3449 *LastChar = '\0'; /* just in case */
3450 c_substitute();
3451 return(CC_NORM);
3454 /*ARGSUSED*/
3455 CCRETVAL
3456 e_magic_space(Char c)
3458 USE(c);
3459 *LastChar = '\0'; /* just in case */
3460 c_substitute();
3461 return(e_insert(' '));
3464 /*ARGSUSED*/
3465 CCRETVAL
3466 e_inc_fwd(Char c)
3468 CCRETVAL ret;
3470 USE(c);
3471 patbuf.len = 0;
3472 MarkIsSet = 0;
3473 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3474 if (adrof(STRhighlight) && IncMatchLen) {
3475 IncMatchLen = 0;
3476 ClearLines();
3477 ClearDisp();
3478 Refresh();
3480 IncMatchLen = 0;
3481 return ret;
3485 /*ARGSUSED*/
3486 CCRETVAL
3487 e_inc_back(Char c)
3489 CCRETVAL ret;
3491 USE(c);
3492 patbuf.len = 0;
3493 MarkIsSet = 0;
3494 ret = e_inc_search(F_UP_SEARCH_HIST);
3495 if (adrof(STRhighlight) && IncMatchLen) {
3496 IncMatchLen = 0;
3497 ClearLines();
3498 ClearDisp();
3499 Refresh();
3501 IncMatchLen = 0;
3502 return ret;
3505 /*ARGSUSED*/
3506 CCRETVAL
3507 e_copyprev(Char c)
3509 Char *cp, *oldc, *dp;
3511 USE(c);
3512 if (Cursor == InputBuf)
3513 return(CC_ERROR);
3514 /* else */
3516 oldc = Cursor;
3517 /* does a bounds check */
3518 cp = c_prev_word(Cursor, InputBuf, Argument);
3520 c_insert((int)(oldc - cp));
3521 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3522 *dp++ = *cp;
3524 Cursor = dp; /* put cursor at end */
3526 return(CC_REFRESH);
3529 /*ARGSUSED*/
3530 CCRETVAL
3531 e_tty_starto(Char c)
3533 USE(c);
3534 /* do no editing */
3535 return(CC_NORM);
3538 /*ARGSUSED*/
3539 CCRETVAL
3540 e_load_average(Char c)
3542 USE(c);
3543 PastBottom();
3544 #ifdef TIOCSTAT
3546 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3547 * there even if they don't use it. (lukem@netbsd.org)
3549 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3550 #endif
3551 xprintf(CGETS(5, 1, "Load average unavailable\n"));
3552 return(CC_REFRESH);
3555 /*ARGSUSED*/
3556 CCRETVAL
3557 v_chgmeta(Char c)
3559 USE(c);
3561 * Delete with insert == change: first we delete and then we leave in
3562 * insert mode.
3564 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3567 /*ARGSUSED*/
3568 CCRETVAL
3569 v_delmeta(Char c)
3571 USE(c);
3572 return(v_action(TCSHOP_DELETE));
3576 /*ARGSUSED*/
3577 CCRETVAL
3578 v_endword(Char c)
3580 USE(c);
3581 if (Cursor == LastChar)
3582 return(CC_ERROR);
3583 /* else */
3585 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3587 if (ActionFlag & TCSHOP_DELETE)
3589 Cursor++;
3590 c_delfini();
3591 return(CC_REFRESH);
3594 RefCursor();
3595 return(CC_NORM);
3598 /*ARGSUSED*/
3599 CCRETVAL
3600 v_eword(Char c)
3602 USE(c);
3603 if (Cursor == LastChar)
3604 return(CC_ERROR);
3605 /* else */
3607 Cursor = c_eword(Cursor, LastChar, Argument);
3609 if (ActionFlag & TCSHOP_DELETE) {
3610 Cursor++;
3611 c_delfini();
3612 return(CC_REFRESH);
3615 RefCursor();
3616 return(CC_NORM);
3619 /*ARGSUSED*/
3620 CCRETVAL
3621 v_char_fwd(Char c)
3623 Char ch;
3625 USE(c);
3626 if (GetNextChar(&ch) != 1)
3627 return e_send_eof(0);
3629 srch_dir = CHAR_FWD;
3630 srch_char = ch;
3632 return v_csearch_fwd(ch, Argument, 0);
3636 /*ARGSUSED*/
3637 CCRETVAL
3638 v_char_back(Char c)
3640 Char ch;
3642 USE(c);
3643 if (GetNextChar(&ch) != 1)
3644 return e_send_eof(0);
3646 srch_dir = CHAR_BACK;
3647 srch_char = ch;
3649 return v_csearch_back(ch, Argument, 0);
3652 /*ARGSUSED*/
3653 CCRETVAL
3654 v_charto_fwd(Char c)
3656 Char ch;
3658 USE(c);
3659 if (GetNextChar(&ch) != 1)
3660 return e_send_eof(0);
3662 return v_csearch_fwd(ch, Argument, 1);
3666 /*ARGSUSED*/
3667 CCRETVAL
3668 v_charto_back(Char c)
3670 Char ch;
3672 USE(c);
3673 if (GetNextChar(&ch) != 1)
3674 return e_send_eof(0);
3676 return v_csearch_back(ch, Argument, 1);
3679 /*ARGSUSED*/
3680 CCRETVAL
3681 v_rchar_fwd(Char c)
3683 USE(c);
3684 if (srch_char == 0)
3685 return CC_ERROR;
3687 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3688 v_csearch_back(srch_char, Argument, 0);
3691 /*ARGSUSED*/
3692 CCRETVAL
3693 v_rchar_back(Char c)
3695 USE(c);
3696 if (srch_char == 0)
3697 return CC_ERROR;
3699 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3700 v_csearch_back(srch_char, Argument, 0);
3703 /*ARGSUSED*/
3704 CCRETVAL
3705 v_undo(Char c)
3707 int loop;
3708 Char *kp, *cp;
3709 Char temp;
3710 int size;
3712 USE(c);
3713 switch (UndoAction) {
3714 case TCSHOP_DELETE|TCSHOP_INSERT:
3715 case TCSHOP_DELETE:
3716 if (UndoSize == 0) return(CC_NORM);
3717 cp = UndoPtr;
3718 kp = UndoBuf;
3719 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3720 *kp++ = *cp++; /* into UndoBuf */
3722 for (cp = UndoPtr; cp <= LastChar; cp++)
3723 *cp = cp[UndoSize];
3725 LastChar -= UndoSize;
3726 Cursor = UndoPtr;
3728 UndoAction = TCSHOP_INSERT;
3729 break;
3731 case TCSHOP_INSERT:
3732 if (UndoSize == 0) return(CC_NORM);
3733 cp = UndoPtr;
3734 Cursor = UndoPtr;
3735 kp = UndoBuf;
3736 c_insert(UndoSize); /* open the space, */
3737 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3738 *cp++ = *kp++;
3740 UndoAction = TCSHOP_DELETE;
3741 break;
3743 case TCSHOP_CHANGE:
3744 if (UndoSize == 0) return(CC_NORM);
3745 cp = UndoPtr;
3746 Cursor = UndoPtr;
3747 kp = UndoBuf;
3748 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3749 if (size < UndoSize)
3750 size = UndoSize;
3751 for(loop = 0; loop < size; loop++) {
3752 temp = *kp;
3753 *kp++ = *cp;
3754 *cp++ = temp;
3756 break;
3758 default:
3759 return(CC_ERROR);
3762 return(CC_REFRESH);
3765 /*ARGSUSED*/
3766 CCRETVAL
3767 v_ush_meta(Char c)
3769 USE(c);
3770 return v_search(F_UP_SEARCH_HIST);
3773 /*ARGSUSED*/
3774 CCRETVAL
3775 v_dsh_meta(Char c)
3777 USE(c);
3778 return v_search(F_DOWN_SEARCH_HIST);
3781 /*ARGSUSED*/
3782 CCRETVAL
3783 v_rsrch_fwd(Char c)
3785 USE(c);
3786 if (patbuf.len == 0) return(CC_ERROR);
3787 return(v_repeat_srch(searchdir));
3790 /*ARGSUSED*/
3791 CCRETVAL
3792 v_rsrch_back(Char c)
3794 USE(c);
3795 if (patbuf.len == 0) return(CC_ERROR);
3796 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3797 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3800 #ifndef WINNT_NATIVE
3801 /* Since ed.defns.h is generated from ed.defns.c, these empty
3802 functions will keep the F_NUM_FNS consistent
3804 CCRETVAL
3805 e_copy_to_clipboard(Char c)
3807 USE(c);
3808 return CC_ERROR;
3811 CCRETVAL
3812 e_paste_from_clipboard(Char c)
3814 USE(c);
3815 return (CC_ERROR);
3818 CCRETVAL
3819 e_dosify_next(Char c)
3821 USE(c);
3822 return (CC_ERROR);
3824 CCRETVAL
3825 e_dosify_prev(Char c)
3827 USE(c);
3828 return (CC_ERROR);
3830 CCRETVAL
3831 e_page_up(Char c)
3833 USE(c);
3834 return (CC_ERROR);
3836 CCRETVAL
3837 e_page_down(Char c)
3839 USE(c);
3840 return (CC_ERROR);
3842 #endif /* !WINNT_NATIVE */
3844 #ifdef notdef
3845 void
3846 MoveCursor(int n) /* move cursor + right - left char */
3848 Cursor = Cursor + n;
3849 if (Cursor < InputBuf)
3850 Cursor = InputBuf;
3851 if (Cursor > LastChar)
3852 Cursor = LastChar;
3853 return;
3856 Char *
3857 GetCursor(void)
3859 return(Cursor);
3863 PutCursor(Char *p)
3865 if (p < InputBuf || p > LastChar)
3866 return 1; /* Error */
3867 Cursor = p;
3868 return 0;
3870 #endif