usr.sbin/makefs: Add -o c|C option to specify comp|check type
[dragonfly.git] / contrib / tcsh-6 / ed.chared.c
blobae0aaf3b0e4de55786b8d777ccddd71d330200e0
1 /*
2 * ed.chared.c: Character editing functions.
3 */
4 /*-
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
35 e_dabbrev_expand() did not do proper completion if quoted spaces were present
36 in the string being completed. Exemple:
38 # echo hello\ world
39 hello world
40 # echo h<press key bound to dabbrev-expande>
41 # echo hello\<cursor>
43 Correct behavior is:
44 # echo h<press key bound to dabbrev-expande>
45 # echo hello\ world<cursor>
47 The same problem occurred if spaces were present in a string withing
48 quotation marks. Example:
50 # echo "hello world"
51 hello world
52 # echo "h<press key bound to dabbrev-expande>
53 # echo "hello<cursor>
55 The former problem could be solved with minor modifications of c_preword()
56 and c_endword(). The latter, however, required a significant rewrite of
57 c_preword(), since quoted strings must be parsed from start to end to
58 determine if a given character is inside or outside the quotation marks.
60 Compare the following two strings:
62 # echo \"" 'foo \' bar\"
63 " 'foo \' bar\
64 # echo '\"" 'foo \' bar\"
65 \"" foo ' bar"
67 The only difference between the two echo lines is in the first character
68 after the echo command. The result is either one or three arguments.
72 #include "sh.h"
73 #include "ed.h"
74 #include "tw.h"
75 #include "ed.defns.h"
77 /* #define SDEBUG */
79 #define TCSHOP_NOP 0x00
80 #define TCSHOP_DELETE 0x01
81 #define TCSHOP_INSERT 0x02
82 #define TCSHOP_CHANGE 0x04
84 #define CHAR_FWD 0
85 #define CHAR_BACK 1
88 * vi word treatment
89 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
91 #define C_CLASS_WHITE 1
92 #define C_CLASS_WORD 2
93 #define C_CLASS_OTHER 3
95 static Char *InsertPos = InputBuf; /* Where insertion starts */
96 static Char *ActionPos = 0; /* Where action begins */
97 static int ActionFlag = TCSHOP_NOP; /* What delayed action to take */
99 * Word search state
101 static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */
102 static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
104 * Char search state
106 static int srch_dir = CHAR_FWD; /* Direction of last search */
107 static Char srch_char = 0; /* Search target */
109 /* all routines that start with c_ are private to this set of routines */
110 static void c_alternativ_key_map (int);
111 void c_insert (int);
112 void c_delafter (int);
113 void c_delbefore (int);
114 static int c_to_class (Char);
115 static Char *c_prev_word (Char *, Char *, int);
116 static Char *c_next_word (Char *, Char *, int);
117 static Char *c_number (Char *, int *, int);
118 static Char *c_expand (Char *);
119 static int c_excl (Char *);
120 static int c_substitute (void);
121 static void c_delfini (void);
122 static int c_hmatch (Char *);
123 static void c_hsetpat (void);
124 #ifdef COMMENT
125 static void c_get_word (Char **, Char **);
126 #endif
127 static Char *c_preword (Char *, Char *, int, Char *);
128 static Char *c_nexword (Char *, Char *, int);
129 static Char *c_endword (Char *, Char *, Char *, int, Char *);
130 static Char *c_eword (Char *, Char *, int);
131 static void c_push_kill (Char *, Char *);
132 static void c_save_inputbuf (void);
133 static CCRETVAL c_search_line (Char *, int);
134 static CCRETVAL v_repeat_srch (int);
135 static CCRETVAL e_inc_search (int);
136 #ifdef notyet
137 static CCRETVAL e_insert_str (Char *);
138 #endif
139 static CCRETVAL v_search (int);
140 static CCRETVAL v_csearch_fwd (Char, int, int);
141 static CCRETVAL v_action (int);
142 static CCRETVAL v_csearch_back (Char, int, int);
144 static void
145 c_alternativ_key_map(int state)
147 switch (state) {
148 case 0:
149 CurrentKeyMap = CcKeyMap;
150 break;
151 case 1:
152 CurrentKeyMap = CcAltMap;
153 break;
154 default:
155 return;
158 AltKeyMap = (Char) state;
161 void
162 c_insert(int num)
164 Char *cp;
166 if (LastChar + num >= InputLim)
167 return; /* can't go past end of buffer */
169 if (Cursor < LastChar) { /* if I must move chars */
170 for (cp = LastChar; cp >= Cursor; cp--)
171 cp[num] = *cp;
172 if (Mark && Mark > Cursor)
173 Mark += num;
175 LastChar += num;
178 void
179 c_delafter(int num)
181 Char *cp, *kp = NULL;
183 if (num > LastChar - Cursor)
184 num = (int) (LastChar - Cursor); /* bounds check */
186 if (num > 0) { /* if I can delete anything */
187 if (VImode) {
188 kp = UndoBuf; /* Set Up for VI undo command */
189 UndoAction = TCSHOP_INSERT;
190 UndoSize = num;
191 UndoPtr = Cursor;
192 for (cp = Cursor; cp <= LastChar; cp++) {
193 *kp++ = *cp; /* Save deleted chars into undobuf */
194 *cp = cp[num];
197 else
198 for (cp = Cursor; cp + num <= LastChar; cp++)
199 *cp = cp[num];
200 LastChar -= num;
201 /* Mark was within the range of the deleted word? */
202 if (Mark && Mark > Cursor && Mark <= Cursor+num)
203 Mark = Cursor;
204 /* Mark after the deleted word? */
205 else if (Mark && Mark > Cursor)
206 Mark -= num;
208 #ifdef notdef
209 else {
211 * XXX: We don't want to do that. In emacs mode overwrite should be
212 * sticky. I am not sure how that affects vi mode
214 inputmode = MODE_INSERT;
216 #endif /* notdef */
219 void
220 c_delbefore(int num) /* delete before dot, with bounds checking */
222 Char *cp, *kp = NULL;
224 if (num > Cursor - InputBuf)
225 num = (int) (Cursor - InputBuf); /* bounds check */
227 if (num > 0) { /* if I can delete anything */
228 if (VImode) {
229 kp = UndoBuf; /* Set Up for VI undo command */
230 UndoAction = TCSHOP_INSERT;
231 UndoSize = num;
232 UndoPtr = Cursor - num;
233 for (cp = Cursor - num; cp <= LastChar; cp++) {
234 *kp++ = *cp;
235 *cp = cp[num];
238 else
239 for (cp = Cursor - num; cp + num <= LastChar; cp++)
240 *cp = cp[num];
241 LastChar -= num;
242 Cursor -= num;
243 /* Mark was within the range of the deleted word? */
244 if (Mark && Mark > Cursor && Mark <= Cursor+num)
245 Mark = Cursor;
246 /* Mark after the deleted word? */
247 else if (Mark && Mark > Cursor)
248 Mark -= num;
252 static Char *
253 c_preword(Char *p, Char *low, int n, Char *delim)
255 while (n--) {
256 Char *prev = low;
257 Char *new;
259 while (prev < p) { /* Skip initial non-word chars */
260 if (!Strchr(delim, *prev) || (prev > low && prev[-1] == (Char)'\\'))
261 break;
262 prev++;
265 new = prev;
267 while (new < p) {
268 prev = new;
269 new = c_endword(prev-1, low, p, 1, delim); /* Skip to next non-word char */
270 new++; /* Step away from end of word */
271 while (new <= p) { /* Skip trailing non-word chars */
272 if (!Strchr(delim, *new) || (new > prev && new[-1] == (Char)'\\'))
273 break;
274 new++;
278 p = prev; /* Set to previous word start */
281 if (p < low)
282 p = low;
283 return (p);
287 * c_to_class() returns the class of the given character.
289 * This is used to make the c_prev_word(), c_next_word() and c_eword() functions
290 * work like vi's, which classify characters. A word is a sequence of
291 * characters belonging to the same class, classes being defined as
292 * follows:
294 * 1/ whitespace
295 * 2/ alphanumeric chars, + underscore
296 * 3/ others
298 static int
299 c_to_class(Char ch)
301 if (Isspace(ch))
302 return C_CLASS_WHITE;
304 if (isword(ch))
305 return C_CLASS_WORD;
307 return C_CLASS_OTHER;
310 static Char *
311 c_prev_word(Char *p, Char *low, int n)
313 p--;
315 if (!VImode) {
316 while (n--) {
317 while ((p >= low) && !isword(*p))
318 p--;
319 while ((p >= low) && isword(*p))
320 p--;
323 /* cp now points to one character before the word */
324 p++;
325 if (p < low)
326 p = low;
327 /* cp now points where we want it */
328 return(p);
331 while (n--) {
332 int c_class;
334 if (p < low)
335 break;
337 /* scan until beginning of current word (may be all whitespace!) */
338 c_class = c_to_class(*p);
339 while ((p >= low) && c_class == c_to_class(*p))
340 p--;
342 /* if this was a non_whitespace word, we're ready */
343 if (c_class != C_CLASS_WHITE)
344 continue;
346 /* otherwise, move back to beginning of the word just found */
347 c_class = c_to_class(*p);
348 while ((p >= low) && c_class == c_to_class(*p))
349 p--;
352 p++; /* correct overshoot */
354 return (p);
357 static Char *
358 c_next_word(Char *p, Char *high, int n)
360 if (!VImode) {
361 while (n--) {
362 while ((p < high) && !isword(*p))
363 p++;
364 while ((p < high) && isword(*p))
365 p++;
367 if (p > high)
368 p = high;
369 /* p now points where we want it */
370 return(p);
373 while (n--) {
374 int c_class;
376 if (p >= high)
377 break;
379 /* scan until end of current word (may be all whitespace!) */
380 c_class = c_to_class(*p);
381 while ((p < high) && c_class == c_to_class(*p))
382 p++;
384 /* if this was all whitespace, we're ready */
385 if (c_class == C_CLASS_WHITE)
386 continue;
388 /* if we've found white-space at the end of the word, skip it */
389 while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
390 p++;
393 p--; /* correct overshoot */
395 return (p);
398 static Char *
399 c_nexword(Char *p, Char *high, int n)
401 while (n--) {
402 while ((p < high) && !Isspace(*p))
403 p++;
404 while ((p < high) && Isspace(*p))
405 p++;
408 if (p > high)
409 p = high;
410 /* p now points where we want it */
411 return(p);
415 * Expand-History (originally "Magic-Space") code added by
416 * Ray Moody <ray@gibbs.physics.purdue.edu>
417 * this is a neat, but odd, addition.
421 * c_number: Ignore character p points to, return number appearing after that.
422 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
423 * Return p pointing to last char used.
427 * dval is the number to subtract from for things like $-3
430 static Char *
431 c_number(Char *p, int *num, int dval)
433 int i;
434 int sign = 1;
436 if (*++p == '^') {
437 *num = 1;
438 return(p);
440 if (*p == '$') {
441 if (*++p != '-') {
442 *num = INT_MAX; /* Handle $ */
443 return(--p);
445 sign = -1; /* Handle $- */
446 ++p;
448 for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
449 continue;
450 *num = (sign < 0 ? dval - i : i);
451 return(--p);
455 * excl_expand: There is an excl to be expanded to p -- do the right thing
456 * with it and return a version of p advanced over the expanded stuff. Also,
457 * update tsh_cur and related things as appropriate...
460 static Char *
461 c_expand(Char *p)
463 Char *q;
464 struct Hist *h = Histlist.Hnext;
465 struct wordent *l;
466 int i, from, to, dval;
467 int all_dig;
468 int been_once = 0;
469 Char *op = p;
470 Char *buf;
471 size_t buf_len;
472 Char *modbuf;
474 buf = NULL;
475 if (!h)
476 goto excl_err;
477 excl_sw:
478 switch (*(q = p + 1)) {
480 case '^':
481 buf = expand_lex(&h->Hlex, 1, 1);
482 break;
484 case '$':
485 if ((l = (h->Hlex).prev) != 0)
486 buf = expand_lex(l->prev->prev, 0, 0);
487 break;
489 case '*':
490 buf = expand_lex(&h->Hlex, 1, INT_MAX);
491 break;
493 default:
494 if (been_once) { /* unknown argument */
495 /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
496 buf = expand_lex(&h->Hlex, 0, INT_MAX);
497 q -= 2;
498 break;
500 been_once = 1;
502 if (*q == ':') /* short form: !:arg */
503 --q;
505 if (HIST != '\0' && *q != HIST) {
507 * Search for a space, tab, or colon. See if we have a number (as
508 * in !1234:xyz). Remember the number.
510 for (i = 0, all_dig = 1;
511 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
513 * PWP: !-4 is a valid history argument too, therefore the test
514 * is if not a digit, or not a - as the first character.
516 if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
517 all_dig = 0;
518 else if (*q == '-')
519 all_dig = 2;/* we are sneeky about this */
520 else
521 i = 10 * i + *q - '0';
523 --q;
526 * If we have a number, search for event i. Otherwise, search for
527 * a named event (as in !foo). (In this case, I is the length of
528 * the named event).
530 if (all_dig) {
531 if (all_dig == 2)
532 i = -i; /* make it negitive */
533 if (i < 0) /* if !-4 (for example) */
534 i = eventno + 1 + i; /* remember: i is < 0 */
535 for (; h; h = h->Hnext) {
536 if (h->Hnum == i)
537 break;
540 else {
541 for (i = (int) (q - p); h; h = h->Hnext) {
542 if ((l = &h->Hlex) != 0) {
543 if (!Strncmp(p + 1, l->next->word, (size_t) i))
544 break;
549 if (!h)
550 goto excl_err;
551 if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
552 q[1] == '$' || q[1] == '^') { /* get some args */
553 p = q[1] == ':' ? ++q : q;
555 * Go handle !foo:*
557 if ((q[1] < '0' || q[1] > '9') &&
558 q[1] != '-' && q[1] != '$' && q[1] != '^')
559 goto excl_sw;
561 * Go handle !foo:$
563 if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
564 goto excl_sw;
566 * Count up the number of words in this event. Store it in dval.
567 * Dval will be fed to number.
569 dval = 0;
570 if ((l = h->Hlex.prev) != 0) {
571 for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
572 continue;
574 if (!dval)
575 goto excl_err;
576 if (q[1] == '-')
577 from = 0;
578 else
579 q = c_number(q, &from, dval);
580 if (q[1] == '-') {
581 ++q;
582 if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
583 to = dval - 1;
584 else
585 q = c_number(q, &to, dval);
587 else if (q[1] == '*') {
588 ++q;
589 to = INT_MAX;
591 else {
592 to = from;
594 if (from < 0 || to < from)
595 goto excl_err;
596 buf = expand_lex(&h->Hlex, from, to);
598 else /* get whole cmd */
599 buf = expand_lex(&h->Hlex, 0, INT_MAX);
600 break;
602 if (buf == NULL)
603 buf = SAVE("");
606 * Apply modifiers, if any.
608 if (q[1] == ':') {
609 modbuf = buf;
610 while (q[1] == ':' && modbuf != NULL) {
611 switch (q[2]) {
612 case 'r':
613 case 'e':
614 case 'h':
615 case 't':
616 case 'q':
617 case 'x':
618 case 'u':
619 case 'l':
620 if ((modbuf = domod(buf, (int) q[2])) != NULL) {
621 xfree(buf);
622 buf = modbuf;
624 ++q;
625 break;
627 case 'a':
628 case 'g':
629 /* Not implemented; this needs to be done before expanding
630 * lex. We don't have the words available to us anymore.
632 ++q;
633 break;
635 case 'p':
636 /* Ok */
637 ++q;
638 break;
640 case '\0':
641 break;
643 default:
644 ++q;
645 break;
647 if (q[1])
648 ++q;
652 buf_len = Strlen(buf);
654 * Now replace the text from op to q inclusive with the text from buf.
656 q++;
659 * Now replace text non-inclusively like a real CS major!
661 if (LastChar + buf_len - (q - op) >= InputLim)
662 goto excl_err;
663 (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
664 LastChar += buf_len - (q - op);
665 Cursor += buf_len - (q - op);
666 (void) memcpy(op, buf, buf_len * sizeof(Char));
667 *LastChar = '\0';
668 xfree(buf);
669 return op + buf_len;
670 excl_err:
671 xfree(buf);
672 SoundBeep();
673 return(op + 1);
677 * c_excl: An excl has been found at point p -- back up and find some white
678 * space (or the beginning of the buffer) and properly expand all the excl's
679 * from there up to the current cursor position. We also avoid (trying to)
680 * expanding '>!'
681 * Returns number of expansions attempted (doesn't matter whether they succeeded
682 * or not).
685 static int
686 c_excl(Char *p)
688 int i;
689 Char *q;
690 int nr_exp;
693 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
694 * back p up to just before the current word.
696 if ((p[1] == ' ' || p[1] == '\t') &&
697 (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
698 for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
699 continue;
700 if (*q == '>')
701 ++p;
703 else {
704 while (*p != ' ' && *p != '\t' && p > InputBuf)
705 --p;
709 * Forever: Look for history char. (Stop looking when we find the cursor.)
710 * Count backslashes. If odd, skip history char. Expand if even number of
711 * backslashes.
713 nr_exp = 0;
714 for (;;) {
715 if (HIST != '\0')
716 while (*p != HIST && p < Cursor)
717 ++p;
718 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
719 continue;
720 if (i % 2 == 0)
721 ++p;
722 if (p >= Cursor) /* all done */
723 return nr_exp;
724 if (i % 2 == 1) {
725 p = c_expand(p);
726 ++nr_exp;
732 static int
733 c_substitute(void)
735 Char *p;
736 int nr_exp;
739 * Start p out one character before the cursor. Move it backwards looking
740 * for white space, the beginning of the line, or a history character.
742 for (p = Cursor - 1;
743 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
744 continue;
747 * If we found a history character, go expand it.
749 if (p >= InputBuf && HIST != '\0' && *p == HIST)
750 nr_exp = c_excl(p);
751 else
752 nr_exp = 0;
753 Refresh();
755 return nr_exp;
758 static void
759 c_delfini(void) /* Finish up delete action */
761 int Size;
763 if (ActionFlag & TCSHOP_INSERT)
764 c_alternativ_key_map(0);
766 ActionFlag = TCSHOP_NOP;
768 if (ActionPos == 0)
769 return;
771 UndoAction = TCSHOP_INSERT;
773 if (Cursor > ActionPos) {
774 Size = (int) (Cursor-ActionPos);
775 c_delbefore(Size);
776 RefCursor();
778 else if (Cursor < ActionPos) {
779 Size = (int)(ActionPos-Cursor);
780 c_delafter(Size);
782 else {
783 Size = 1;
784 c_delafter(Size);
786 UndoPtr = Cursor;
787 UndoSize = Size;
790 static Char *
791 c_endword(Char *p, Char *low, Char *high, int n, Char *delim)
793 Char inquote = 0;
794 p++;
796 while (n--) {
797 while (p < high) { /* Skip non-word chars */
798 if (!Strchr(delim, *p) || p[-1] == (Char)'\\')
799 break;
800 p++;
802 while (p < high) { /* Skip string */
803 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
804 /* Should it be honored? */
805 if (inquote || (p > low && p[-1] != (Char)'\\')) {
806 if (inquote == 0) inquote = *p;
807 else if (inquote == *p) inquote = 0;
810 /* Break if unquoted non-word char */
811 if (!inquote && Strchr(delim, *p) && p > low && p[-1] != (Char)'\\')
812 break;
813 p++;
817 p--;
818 return(p);
822 static Char *
823 c_eword(Char *p, Char *high, int n)
825 p++;
827 while (n--) {
828 int c_class;
830 if (p >= high)
831 break;
833 /* scan until end of current word (may be all whitespace!) */
834 c_class = c_to_class(*p);
835 while ((p < high) && c_class == c_to_class(*p))
836 p++;
838 /* if this was a non_whitespace word, we're ready */
839 if (c_class != C_CLASS_WHITE)
840 continue;
842 /* otherwise, move to the end of the word just found */
843 c_class = c_to_class(*p);
844 while ((p < high) && c_class == c_to_class(*p))
845 p++;
848 p--;
849 return(p);
852 /* Set the max length of the kill ring */
853 void
854 SetKillRing(int max)
856 CStr *new;
857 int count, i, j;
859 if (max < 1)
860 max = 1; /* no ring, but always one buffer */
861 if (max == KillRingMax)
862 return;
863 new = xcalloc(max, sizeof(CStr));
864 if (KillRing != NULL) {
865 if (KillRingLen != 0) {
866 if (max >= KillRingLen) {
867 count = KillRingLen;
868 j = KillPos;
869 } else {
870 count = max;
871 j = (KillPos - count + KillRingLen) % KillRingLen;
873 for (i = 0; i < KillRingLen; i++) {
874 if (i < count) /* copy latest */
875 new[i] = KillRing[j];
876 else /* free the others */
877 xfree(KillRing[j].buf);
878 j = (j + 1) % KillRingLen;
880 KillRingLen = count;
881 KillPos = count % max;
882 YankPos = count - 1;
884 xfree(KillRing);
886 KillRing = new;
887 KillRingMax = max;
890 /* Push string from start upto (but not including) end onto kill ring */
891 static void
892 c_push_kill(Char *start, Char *end)
894 CStr save, *pos;
895 Char *dp, *cp, *kp;
896 int len = end - start, i, j, k;
898 /* Check for duplicates? */
899 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
900 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
901 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
902 j = YankPos;
903 for (i = 0; i < KillRingLen; i++) {
904 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
905 KillRing[j].buf[len] == '\0') {
906 save = KillRing[j];
907 for ( ; i > 0; i--) {
908 k = j;
909 j = (j + 1) % KillRingLen;
910 KillRing[k] = KillRing[j];
912 KillRing[j] = save;
913 return;
915 j = (j - 1 + KillRingLen) % KillRingLen;
917 } else if (eq(dp, STRall)) { /* skip if any earlier */
918 for (i = 0; i < KillRingLen; i++)
919 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
920 KillRing[i].buf[len] == '\0')
921 return;
922 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
923 j = YankPos;
924 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
925 KillRing[j].buf[len] == '\0')
926 return;
930 /* No duplicate, go ahead and push */
931 len++; /* need space for '\0' */
932 YankPos = KillPos;
933 if (KillRingLen < KillRingMax)
934 KillRingLen++;
935 pos = &KillRing[KillPos];
936 KillPos = (KillPos + 1) % KillRingMax;
937 if (pos->len < len) {
938 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
939 pos->len = len;
941 cp = start;
942 kp = pos->buf;
943 while (cp < end)
944 *kp++ = *cp++;
945 *kp = '\0';
948 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
949 static void
950 c_save_inputbuf(void)
952 SavedBuf.len = 0;
953 Strbuf_append(&SavedBuf, InputBuf);
954 Strbuf_terminate(&SavedBuf);
955 LastSaved = LastChar - InputBuf;
956 CursSaved = Cursor - InputBuf;
957 HistSaved = Hist_num;
958 RestoreSaved = 1;
961 CCRETVAL
962 GetHistLine(void)
964 struct Hist *hp;
965 int h;
967 if (Hist_num == 0) { /* if really the current line */
968 if (HistBuf.s != NULL)
969 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
970 else
971 *InputBuf = '\0';
972 LastChar = InputBuf + HistBuf.len;
974 #ifdef KSHVI
975 if (VImode)
976 Cursor = InputBuf;
977 else
978 #endif /* KSHVI */
979 Cursor = LastChar;
981 return(CC_REFRESH);
984 hp = Histlist.Hnext;
985 if (hp == NULL)
986 return(CC_ERROR);
988 for (h = 1; h < Hist_num; h++) {
989 if ((hp->Hnext) == NULL) {
990 Hist_num = h;
991 return(CC_ERROR);
993 hp = hp->Hnext;
996 if (HistLit && hp->histline) {
997 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
998 CurrentHistLit = 1;
1000 else {
1001 Char *p;
1003 p = sprlex(&hp->Hlex);
1004 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1005 xfree(p);
1006 CurrentHistLit = 0;
1008 LastChar = Strend(InputBuf);
1010 if (LastChar > InputBuf) {
1011 if (LastChar[-1] == '\n')
1012 LastChar--;
1013 #if 0
1014 if (LastChar[-1] == ' ')
1015 LastChar--;
1016 #endif
1017 if (LastChar < InputBuf)
1018 LastChar = InputBuf;
1021 #ifdef KSHVI
1022 if (VImode)
1023 Cursor = InputBuf;
1024 else
1025 #endif /* KSHVI */
1026 Cursor = LastChar;
1028 return(CC_REFRESH);
1031 static CCRETVAL
1032 c_search_line(Char *pattern, int dir)
1034 Char *cp;
1035 size_t len;
1037 len = Strlen(pattern);
1039 if (dir == F_UP_SEARCH_HIST) {
1040 for (cp = Cursor; cp >= InputBuf; cp--)
1041 if (Strncmp(cp, pattern, len) == 0 ||
1042 Gmatch(cp, pattern)) {
1043 Cursor = cp;
1044 return(CC_NORM);
1046 return(CC_ERROR);
1047 } else {
1048 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1049 if (Strncmp(cp, pattern, len) == 0 ||
1050 Gmatch(cp, pattern)) {
1051 Cursor = cp;
1052 return(CC_NORM);
1054 return(CC_ERROR);
1058 static CCRETVAL
1059 e_inc_search(int dir)
1061 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1062 STRbck[] = { 'b', 'c', 'k', '\0' };
1063 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1064 static Char endcmd[2];
1065 const Char *cp;
1066 Char ch,
1067 *oldCursor = Cursor,
1068 oldpchar = pchar;
1069 CCRETVAL ret = CC_NORM;
1070 int oldHist_num = Hist_num,
1071 oldpatlen = patbuf.len,
1072 newdir = dir,
1073 done, redo;
1075 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1076 return(CC_ERROR);
1078 for (;;) {
1080 if (patbuf.len == 0) { /* first round */
1081 pchar = ':';
1082 Strbuf_append1(&patbuf, '*');
1084 done = redo = 0;
1085 *LastChar++ = '\n';
1086 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1087 *cp; *LastChar++ = *cp++)
1088 continue;
1089 *LastChar++ = pchar;
1090 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1091 *LastChar++ = *cp++)
1092 continue;
1093 *LastChar = '\0';
1094 if (adrof(STRhighlight) && pchar == ':') {
1095 /* if the no-glob-search patch is applied, remove the - 1 below */
1096 IncMatchLen = patbuf.len - 1;
1097 ClearLines();
1098 ClearDisp();
1100 Refresh();
1102 if (GetNextChar(&ch) != 1)
1103 return(e_send_eof(0));
1105 switch (GetCmdChar(ch)) {
1106 case F_INSERT:
1107 case F_DIGIT:
1108 case F_MAGIC_SPACE:
1109 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1110 SoundBeep();
1111 else {
1112 Strbuf_append1(&patbuf, ch);
1113 *LastChar++ = ch;
1114 *LastChar = '\0';
1115 Refresh();
1117 break;
1119 case F_INC_FWD:
1120 newdir = F_DOWN_SEARCH_HIST;
1121 redo++;
1122 break;
1124 case F_INC_BACK:
1125 newdir = F_UP_SEARCH_HIST;
1126 redo++;
1127 break;
1129 case F_DELPREV:
1130 if (patbuf.len > 1)
1131 done++;
1132 else
1133 SoundBeep();
1134 break;
1136 default:
1137 switch (ASC(ch)) {
1138 case 0007: /* ^G: Abort */
1139 ret = CC_ERROR;
1140 done++;
1141 break;
1143 case 0027: /* ^W: Append word */
1144 /* No can do if globbing characters in pattern */
1145 for (cp = &patbuf.s[1]; ; cp++)
1146 if (cp >= &patbuf.s[patbuf.len]) {
1147 Cursor += patbuf.len - 1;
1148 cp = c_next_word(Cursor, LastChar, 1);
1149 while (Cursor < cp && *Cursor != '\n') {
1150 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1151 SoundBeep();
1152 break;
1154 Strbuf_append1(&patbuf, *Cursor);
1155 *LastChar++ = *Cursor++;
1157 Cursor = oldCursor;
1158 *LastChar = '\0';
1159 Refresh();
1160 break;
1161 } else if (isglob(*cp)) {
1162 SoundBeep();
1163 break;
1165 break;
1167 default: /* Terminate and execute cmd */
1168 endcmd[0] = ch;
1169 PushMacro(endcmd);
1170 /*FALLTHROUGH*/
1172 case 0033: /* ESC: Terminate */
1173 ret = CC_REFRESH;
1174 done++;
1175 break;
1177 break;
1180 while (LastChar > InputBuf && *LastChar != '\n')
1181 *LastChar-- = '\0';
1182 *LastChar = '\0';
1184 if (!done) {
1186 /* Can't search if unmatched '[' */
1187 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1188 if (*cp == '[' || *cp == ']') {
1189 ch = *cp;
1190 break;
1193 if (patbuf.len > 1 && ch != '[') {
1194 if (redo && newdir == dir) {
1195 if (pchar == '?') { /* wrap around */
1196 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1197 if (GetHistLine() == CC_ERROR)
1198 /* Hist_num was fixed by first call */
1199 (void) GetHistLine();
1200 Cursor = newdir == F_UP_SEARCH_HIST ?
1201 LastChar : InputBuf;
1202 } else
1203 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1205 Strbuf_append1(&patbuf, '*');
1206 Strbuf_terminate(&patbuf);
1207 if (Cursor < InputBuf || Cursor > LastChar ||
1208 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1209 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1210 ret = newdir == F_UP_SEARCH_HIST ?
1211 e_up_search_hist(0) : e_down_search_hist(0);
1212 if (ret != CC_ERROR) {
1213 Cursor = newdir == F_UP_SEARCH_HIST ?
1214 LastChar : InputBuf;
1215 (void) c_search_line(&patbuf.s[1], newdir);
1218 patbuf.s[--patbuf.len] = '\0';
1219 if (ret == CC_ERROR) {
1220 SoundBeep();
1221 if (Hist_num != oldHist_num) {
1222 Hist_num = oldHist_num;
1223 if (GetHistLine() == CC_ERROR)
1224 return(CC_ERROR);
1226 Cursor = oldCursor;
1227 pchar = '?';
1228 } else {
1229 pchar = ':';
1233 ret = e_inc_search(newdir);
1235 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1236 /* break abort of failed search at last non-failed */
1237 ret = CC_NORM;
1242 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1243 /* restore on normal return or error exit */
1244 pchar = oldpchar;
1245 patbuf.len = oldpatlen;
1246 if (Hist_num != oldHist_num) {
1247 Hist_num = oldHist_num;
1248 if (GetHistLine() == CC_ERROR)
1249 return(CC_ERROR);
1251 Cursor = oldCursor;
1252 if (ret == CC_ERROR)
1253 Refresh();
1255 if (done || ret != CC_NORM)
1256 return(ret);
1262 static CCRETVAL
1263 v_search(int dir)
1265 struct Strbuf tmpbuf = Strbuf_INIT;
1266 Char ch;
1267 Char *oldbuf;
1268 Char *oldlc, *oldc;
1270 cleanup_push(&tmpbuf, Strbuf_cleanup);
1271 oldbuf = Strsave(InputBuf);
1272 cleanup_push(oldbuf, xfree);
1273 oldlc = LastChar;
1274 oldc = Cursor;
1275 Strbuf_append1(&tmpbuf, '*');
1277 InputBuf[0] = '\0';
1278 LastChar = InputBuf;
1279 Cursor = InputBuf;
1280 searchdir = dir;
1282 c_insert(2); /* prompt + '\n' */
1283 *Cursor++ = '\n';
1284 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1285 Refresh();
1286 for (ch = 0;ch == 0;) {
1287 if (GetNextChar(&ch) != 1) {
1288 cleanup_until(&tmpbuf);
1289 return(e_send_eof(0));
1291 switch (ASC(ch)) {
1292 case 0010: /* Delete and backspace */
1293 case 0177:
1294 if (tmpbuf.len > 1) {
1295 *Cursor-- = '\0';
1296 LastChar = Cursor;
1297 tmpbuf.len--;
1299 else {
1300 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1301 LastChar = oldlc;
1302 Cursor = oldc;
1303 cleanup_until(&tmpbuf);
1304 return(CC_REFRESH);
1306 Refresh();
1307 ch = 0;
1308 break;
1310 case 0033: /* ESC */
1311 #ifdef IS_ASCII
1312 case '\r': /* Newline */
1313 case '\n':
1314 #else
1315 case '\012': /* ASCII Line feed */
1316 case '\015': /* ASCII (or EBCDIC) Return */
1317 #endif
1318 break;
1320 default:
1321 Strbuf_append1(&tmpbuf, ch);
1322 *Cursor++ = ch;
1323 LastChar = Cursor;
1324 Refresh();
1325 ch = 0;
1326 break;
1329 cleanup_until(oldbuf);
1331 if (tmpbuf.len == 1) {
1333 * Use the old pattern, but wild-card it.
1335 if (patbuf.len == 0) {
1336 InputBuf[0] = '\0';
1337 LastChar = InputBuf;
1338 Cursor = InputBuf;
1339 Refresh();
1340 cleanup_until(&tmpbuf);
1341 return(CC_ERROR);
1343 if (patbuf.s[0] != '*') {
1344 oldbuf = Strsave(patbuf.s);
1345 patbuf.len = 0;
1346 Strbuf_append1(&patbuf, '*');
1347 Strbuf_append(&patbuf, oldbuf);
1348 xfree(oldbuf);
1349 Strbuf_append1(&patbuf, '*');
1350 Strbuf_terminate(&patbuf);
1353 else {
1354 Strbuf_append1(&tmpbuf, '*');
1355 Strbuf_terminate(&tmpbuf);
1356 patbuf.len = 0;
1357 Strbuf_append(&patbuf, tmpbuf.s);
1358 Strbuf_terminate(&patbuf);
1360 cleanup_until(&tmpbuf);
1361 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1362 Cursor = LastChar = InputBuf;
1363 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1364 e_down_search_hist(0)) == CC_ERROR) {
1365 Refresh();
1366 return(CC_ERROR);
1368 else {
1369 if (ASC(ch) == 0033) {
1370 Refresh();
1371 *LastChar++ = '\n';
1372 *LastChar = '\0';
1373 PastBottom();
1374 return(CC_NEWLINE);
1376 else
1377 return(CC_REFRESH);
1382 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1383 * entry point, called from the CcKeyMap indirected into the
1384 * CcFuncTbl array.
1387 /*ARGSUSED*/
1388 CCRETVAL
1389 v_cmd_mode(Char c)
1391 USE(c);
1392 InsertPos = 0;
1393 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1394 ActionPos = 0;
1395 DoingArg = 0;
1396 if (UndoPtr > Cursor)
1397 UndoSize = (int)(UndoPtr - Cursor);
1398 else
1399 UndoSize = (int)(Cursor - UndoPtr);
1401 inputmode = MODE_INSERT;
1402 c_alternativ_key_map(1);
1403 #ifdef notdef
1405 * We don't want to move the cursor, because all the editing
1406 * commands don't include the character under the cursor.
1408 if (Cursor > InputBuf)
1409 Cursor--;
1410 #endif
1411 RefCursor();
1412 return(CC_NORM);
1415 /*ARGSUSED*/
1416 CCRETVAL
1417 e_unassigned(Char c)
1418 { /* bound to keys that arn't really assigned */
1419 USE(c);
1420 SoundBeep();
1421 flush();
1422 return(CC_NORM);
1425 #ifdef notyet
1426 static CCRETVAL
1427 e_insert_str(Char *c)
1429 int i, n;
1431 n = Strlen(c);
1432 if (LastChar + Argument * n >= InputLim)
1433 return(CC_ERROR); /* end of buffer space */
1434 if (inputmode != MODE_INSERT) {
1435 c_delafter(Argument * Strlen(c));
1437 c_insert(Argument * n);
1438 while (Argument--) {
1439 for (i = 0; i < n; i++)
1440 *Cursor++ = c[i];
1442 Refresh();
1443 return(CC_NORM);
1445 #endif
1447 CCRETVAL
1448 e_insert(Char c)
1450 #ifndef SHORT_STRINGS
1451 c &= ASCII; /* no meta chars ever */
1452 #endif
1454 if (!c)
1455 return(CC_ERROR); /* no NULs in the input ever!! */
1457 if (LastChar + Argument >= InputLim)
1458 return(CC_ERROR); /* end of buffer space */
1460 if (Argument == 1) { /* How was this optimized ???? */
1462 if (inputmode != MODE_INSERT) {
1463 UndoBuf[UndoSize++] = *Cursor;
1464 UndoBuf[UndoSize] = '\0';
1465 c_delafter(1); /* Do NOT use the saving ONE */
1468 c_insert(1);
1469 *Cursor++ = (Char) c;
1470 DoingArg = 0; /* just in case */
1471 RefPlusOne(1); /* fast refresh for one char. */
1473 else {
1474 if (inputmode != MODE_INSERT) {
1475 int i;
1476 for (i = 0; i < Argument; i++)
1477 UndoBuf[UndoSize++] = Cursor[i];
1479 UndoBuf[UndoSize] = '\0';
1480 c_delafter(Argument); /* Do NOT use the saving ONE */
1483 c_insert(Argument);
1485 while (Argument--)
1486 *Cursor++ = (Char) c;
1487 Refresh();
1490 if (inputmode == MODE_REPLACE_1)
1491 (void) v_cmd_mode(0);
1493 return(CC_NORM);
1497 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1499 int len;
1501 if ((len = (int) Strlen(s)) <= 0)
1502 return -1;
1503 if (LastChar + len >= InputLim)
1504 return -1; /* end of buffer space */
1506 c_insert(len);
1507 while (len--)
1508 *Cursor++ = *s++;
1509 return 0;
1512 void
1513 DeleteBack(int n) /* delete the n characters before . */
1515 if (n <= 0)
1516 return;
1517 if (Cursor >= &InputBuf[n]) {
1518 c_delbefore(n); /* delete before dot */
1522 CCRETVAL
1523 e_digit(Char c) /* gray magic here */
1525 if (!Isdigit(c))
1526 return(CC_ERROR); /* no NULs in the input ever!! */
1528 if (DoingArg) { /* if doing an arg, add this in... */
1529 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1530 Argument = c - '0';
1531 else {
1532 if (Argument > 1000000)
1533 return CC_ERROR;
1534 Argument = (Argument * 10) + (c - '0');
1536 return(CC_ARGHACK);
1538 else {
1539 if (LastChar + 1 >= InputLim)
1540 return CC_ERROR; /* end of buffer space */
1542 if (inputmode != MODE_INSERT) {
1543 UndoBuf[UndoSize++] = *Cursor;
1544 UndoBuf[UndoSize] = '\0';
1545 c_delafter(1); /* Do NOT use the saving ONE */
1547 c_insert(1);
1548 *Cursor++ = (Char) c;
1549 DoingArg = 0; /* just in case */
1550 RefPlusOne(1); /* fast refresh for one char. */
1552 return(CC_NORM);
1555 CCRETVAL
1556 e_argdigit(Char c) /* for ESC-n */
1558 #ifdef IS_ASCII
1559 c &= ASCII;
1560 #else
1561 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1562 #endif
1564 if (!Isdigit(c))
1565 return(CC_ERROR); /* no NULs in the input ever!! */
1567 if (DoingArg) { /* if doing an arg, add this in... */
1568 if (Argument > 1000000)
1569 return CC_ERROR;
1570 Argument = (Argument * 10) + (c - '0');
1572 else { /* else starting an argument */
1573 Argument = c - '0';
1574 DoingArg = 1;
1576 return(CC_ARGHACK);
1579 CCRETVAL
1580 v_zero(Char c) /* command mode 0 for vi */
1582 if (DoingArg) { /* if doing an arg, add this in... */
1583 if (Argument > 1000000)
1584 return CC_ERROR;
1585 Argument = (Argument * 10) + (c - '0');
1586 return(CC_ARGHACK);
1588 else { /* else starting an argument */
1589 Cursor = InputBuf;
1590 if (ActionFlag & TCSHOP_DELETE) {
1591 c_delfini();
1592 return(CC_REFRESH);
1594 RefCursor(); /* move the cursor */
1595 return(CC_NORM);
1599 /*ARGSUSED*/
1600 CCRETVAL
1601 e_newline(Char c)
1602 { /* always ignore argument */
1603 USE(c);
1604 if (adrof(STRhighlight) && MarkIsSet) {
1605 MarkIsSet = 0;
1606 ClearLines();
1607 ClearDisp();
1608 Refresh();
1610 MarkIsSet = 0;
1612 /* PastBottom(); NOW done in ed.inputl.c */
1613 *LastChar++ = '\n'; /* for the benefit of CSH */
1614 *LastChar = '\0'; /* just in case */
1615 if (VImode)
1616 InsertPos = InputBuf; /* Reset editing position */
1617 return(CC_NEWLINE);
1620 /*ARGSUSED*/
1621 CCRETVAL
1622 e_newline_hold(Char c)
1624 USE(c);
1625 c_save_inputbuf();
1626 HistSaved = 0;
1627 *LastChar++ = '\n'; /* for the benefit of CSH */
1628 *LastChar = '\0'; /* just in case */
1629 return(CC_NEWLINE);
1632 /*ARGSUSED*/
1633 CCRETVAL
1634 e_newline_down_hist(Char c)
1636 USE(c);
1637 if (Hist_num > 1) {
1638 HistSaved = Hist_num;
1640 *LastChar++ = '\n'; /* for the benefit of CSH */
1641 *LastChar = '\0'; /* just in case */
1642 return(CC_NEWLINE);
1645 /*ARGSUSED*/
1646 CCRETVAL
1647 e_send_eof(Char c)
1648 { /* for when ^D is ONLY send-eof */
1649 USE(c);
1650 PastBottom();
1651 *LastChar = '\0'; /* just in case */
1652 return(CC_EOF);
1655 /*ARGSUSED*/
1656 CCRETVAL
1657 e_complete(Char c)
1659 USE(c);
1660 *LastChar = '\0'; /* just in case */
1661 return(CC_COMPLETE);
1664 /*ARGSUSED*/
1665 CCRETVAL
1666 e_complete_back(Char c)
1668 USE(c);
1669 *LastChar = '\0'; /* just in case */
1670 return(CC_COMPLETE_BACK);
1673 /*ARGSUSED*/
1674 CCRETVAL
1675 e_complete_fwd(Char c)
1677 USE(c);
1678 *LastChar = '\0'; /* just in case */
1679 return(CC_COMPLETE_FWD);
1682 /*ARGSUSED*/
1683 CCRETVAL
1684 e_complete_all(Char c)
1686 USE(c);
1687 *LastChar = '\0'; /* just in case */
1688 return(CC_COMPLETE_ALL);
1691 /*ARGSUSED*/
1692 CCRETVAL
1693 v_cm_complete(Char c)
1695 USE(c);
1696 if (Cursor < LastChar)
1697 Cursor++;
1698 *LastChar = '\0'; /* just in case */
1699 return(CC_COMPLETE);
1702 /*ARGSUSED*/
1703 CCRETVAL
1704 e_toggle_hist(Char c)
1706 struct Hist *hp;
1707 int h;
1709 USE(c);
1710 *LastChar = '\0'; /* just in case */
1712 if (Hist_num <= 0) {
1713 return CC_ERROR;
1716 hp = Histlist.Hnext;
1717 if (hp == NULL) { /* this is only if no history */
1718 return(CC_ERROR);
1721 for (h = 1; h < Hist_num; h++)
1722 hp = hp->Hnext;
1724 if (!CurrentHistLit) {
1725 if (hp->histline) {
1726 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1727 CurrentHistLit = 1;
1729 else {
1730 return CC_ERROR;
1733 else {
1734 Char *p;
1736 p = sprlex(&hp->Hlex);
1737 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1738 xfree(p);
1739 CurrentHistLit = 0;
1742 LastChar = Strend(InputBuf);
1743 if (LastChar > InputBuf) {
1744 if (LastChar[-1] == '\n')
1745 LastChar--;
1746 if (LastChar[-1] == ' ')
1747 LastChar--;
1748 if (LastChar < InputBuf)
1749 LastChar = InputBuf;
1752 #ifdef KSHVI
1753 if (VImode)
1754 Cursor = InputBuf;
1755 else
1756 #endif /* KSHVI */
1757 Cursor = LastChar;
1759 return(CC_REFRESH);
1762 /*ARGSUSED*/
1763 CCRETVAL
1764 e_up_hist(Char c)
1766 Char beep = 0;
1768 USE(c);
1769 UndoAction = TCSHOP_NOP;
1770 *LastChar = '\0'; /* just in case */
1772 if (Hist_num == 0) { /* save the current buffer away */
1773 HistBuf.len = 0;
1774 Strbuf_append(&HistBuf, InputBuf);
1775 Strbuf_terminate(&HistBuf);
1778 Hist_num += Argument;
1780 if (GetHistLine() == CC_ERROR) {
1781 beep = 1;
1782 (void) GetHistLine(); /* Hist_num was fixed by first call */
1785 Refresh();
1786 if (beep)
1787 return(CC_ERROR);
1788 else
1789 return(CC_NORM); /* was CC_UP_HIST */
1792 /*ARGSUSED*/
1793 CCRETVAL
1794 e_down_hist(Char c)
1796 USE(c);
1797 UndoAction = TCSHOP_NOP;
1798 *LastChar = '\0'; /* just in case */
1800 Hist_num -= Argument;
1802 if (Hist_num < 0) {
1803 Hist_num = 0;
1804 return(CC_ERROR); /* make it beep */
1807 return(GetHistLine());
1813 * c_hmatch() return True if the pattern matches the prefix
1815 static int
1816 c_hmatch(Char *str)
1818 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1819 return 1;
1820 return Gmatch(str, patbuf.s);
1824 * c_hsetpat(): Set the history seatch pattern
1826 static void
1827 c_hsetpat(void)
1829 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1830 patbuf.len = 0;
1831 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1832 Strbuf_terminate(&patbuf);
1834 #ifdef SDEBUG
1835 xprintf("\nHist_num = %d\n", Hist_num);
1836 xprintf("patlen = %d\n", (int)patbuf.len);
1837 xprintf("patbuf = \"%S\"\n", patbuf.s);
1838 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1839 #endif
1842 /*ARGSUSED*/
1843 CCRETVAL
1844 e_up_search_hist(Char c)
1846 struct Hist *hp;
1847 int h;
1848 int found = 0;
1850 USE(c);
1851 ActionFlag = TCSHOP_NOP;
1852 UndoAction = TCSHOP_NOP;
1853 *LastChar = '\0'; /* just in case */
1854 if (Hist_num < 0) {
1855 #ifdef DEBUG_EDIT
1856 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1857 #endif
1858 Hist_num = 0;
1859 return(CC_ERROR);
1862 if (Hist_num == 0) {
1863 HistBuf.len = 0;
1864 Strbuf_append(&HistBuf, InputBuf);
1865 Strbuf_terminate(&HistBuf);
1869 hp = Histlist.Hnext;
1870 if (hp == NULL)
1871 return(CC_ERROR);
1873 c_hsetpat(); /* Set search pattern !! */
1875 for (h = 1; h <= Hist_num; h++)
1876 hp = hp->Hnext;
1878 while (hp != NULL) {
1879 Char *hl;
1880 int matched;
1882 if (hp->histline == NULL)
1883 hp->histline = sprlex(&hp->Hlex);
1884 if (HistLit)
1885 hl = hp->histline;
1886 else {
1887 hl = sprlex(&hp->Hlex);
1888 cleanup_push(hl, xfree);
1890 #ifdef SDEBUG
1891 xprintf("Comparing with \"%S\"\n", hl);
1892 #endif
1893 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1894 hl[LastChar-InputBuf]) && c_hmatch(hl);
1895 if (!HistLit)
1896 cleanup_until(hl);
1897 if (matched) {
1898 found++;
1899 break;
1901 h++;
1902 hp = hp->Hnext;
1905 if (!found) {
1906 #ifdef SDEBUG
1907 xprintf("not found\n");
1908 #endif
1909 return(CC_ERROR);
1912 Hist_num = h;
1914 return(GetHistLine());
1917 /*ARGSUSED*/
1918 CCRETVAL
1919 e_down_search_hist(Char c)
1921 struct Hist *hp;
1922 int h;
1923 int found = 0;
1925 USE(c);
1926 ActionFlag = TCSHOP_NOP;
1927 UndoAction = TCSHOP_NOP;
1928 *LastChar = '\0'; /* just in case */
1930 if (Hist_num == 0)
1931 return(CC_ERROR);
1933 hp = Histlist.Hnext;
1934 if (hp == 0)
1935 return(CC_ERROR);
1937 c_hsetpat(); /* Set search pattern !! */
1939 for (h = 1; h < Hist_num && hp; h++) {
1940 Char *hl;
1941 if (hp->histline == NULL)
1942 hp->histline = sprlex(&hp->Hlex);
1943 if (HistLit)
1944 hl = hp->histline;
1945 else {
1946 hl = sprlex(&hp->Hlex);
1947 cleanup_push(hl, xfree);
1949 #ifdef SDEBUG
1950 xprintf("Comparing with \"%S\"\n", hl);
1951 #endif
1952 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1953 hl[LastChar-InputBuf]) && c_hmatch(hl))
1954 found = h;
1955 if (!HistLit)
1956 cleanup_until(hl);
1957 hp = hp->Hnext;
1960 if (!found) { /* is it the current history number? */
1961 if (!c_hmatch(HistBuf.s)) {
1962 #ifdef SDEBUG
1963 xprintf("not found\n");
1964 #endif
1965 return(CC_ERROR);
1969 Hist_num = found;
1971 return(GetHistLine());
1974 /*ARGSUSED*/
1975 CCRETVAL
1976 e_helpme(Char c)
1978 USE(c);
1979 PastBottom();
1980 *LastChar = '\0'; /* just in case */
1981 return(CC_HELPME);
1984 /*ARGSUSED*/
1985 CCRETVAL
1986 e_correct(Char c)
1988 USE(c);
1989 *LastChar = '\0'; /* just in case */
1990 return(CC_CORRECT);
1993 /*ARGSUSED*/
1994 CCRETVAL
1995 e_correctl(Char c)
1997 USE(c);
1998 *LastChar = '\0'; /* just in case */
1999 return(CC_CORRECT_L);
2002 /*ARGSUSED*/
2003 CCRETVAL
2004 e_run_fg_editor(Char c)
2006 struct process *pp;
2008 USE(c);
2009 if ((pp = find_stop_ed()) != NULL) {
2010 /* save our editor state so we can restore it */
2011 c_save_inputbuf();
2012 Hist_num = 0; /* for the history commands */
2014 /* put the tty in a sane mode */
2015 PastBottom();
2016 (void) Cookedmode(); /* make sure the tty is set up correctly */
2018 /* do it! */
2019 fg_proc_entry(pp);
2021 (void) Rawmode(); /* go on */
2022 Refresh();
2023 RestoreSaved = 0;
2024 HistSaved = 0;
2026 return(CC_NORM);
2029 /*ARGSUSED*/
2030 CCRETVAL
2031 e_list_choices(Char c)
2033 USE(c);
2034 PastBottom();
2035 *LastChar = '\0'; /* just in case */
2036 return(CC_LIST_CHOICES);
2039 /*ARGSUSED*/
2040 CCRETVAL
2041 e_list_all(Char c)
2043 USE(c);
2044 PastBottom();
2045 *LastChar = '\0'; /* just in case */
2046 return(CC_LIST_ALL);
2049 /*ARGSUSED*/
2050 CCRETVAL
2051 e_list_glob(Char c)
2053 USE(c);
2054 PastBottom();
2055 *LastChar = '\0'; /* just in case */
2056 return(CC_LIST_GLOB);
2059 /*ARGSUSED*/
2060 CCRETVAL
2061 e_expand_glob(Char c)
2063 USE(c);
2064 *LastChar = '\0'; /* just in case */
2065 return(CC_EXPAND_GLOB);
2068 /*ARGSUSED*/
2069 CCRETVAL
2070 e_normalize_path(Char c)
2072 USE(c);
2073 *LastChar = '\0'; /* just in case */
2074 return(CC_NORMALIZE_PATH);
2077 /*ARGSUSED*/
2078 CCRETVAL
2079 e_normalize_command(Char c)
2081 USE(c);
2082 *LastChar = '\0'; /* just in case */
2083 return(CC_NORMALIZE_COMMAND);
2086 /*ARGSUSED*/
2087 CCRETVAL
2088 e_expand_vars(Char c)
2090 USE(c);
2091 *LastChar = '\0'; /* just in case */
2092 return(CC_EXPAND_VARS);
2095 /*ARGSUSED*/
2096 CCRETVAL
2097 e_which(Char c)
2098 { /* do a fast command line which(1) */
2099 USE(c);
2100 c_save_inputbuf();
2101 Hist_num = 0; /* for the history commands */
2102 PastBottom();
2103 *LastChar = '\0'; /* just in case */
2104 return(CC_WHICH);
2107 /*ARGSUSED*/
2108 CCRETVAL
2109 e_last_item(Char c)
2110 { /* insert the last element of the prev. cmd */
2111 struct Hist *hp;
2112 struct wordent *wp, *firstp;
2113 int i;
2114 Char *expanded;
2116 USE(c);
2117 if (Argument <= 0)
2118 return(CC_ERROR);
2120 hp = Histlist.Hnext;
2121 if (hp == NULL) { /* this is only if no history */
2122 return(CC_ERROR);
2125 wp = (hp->Hlex).prev;
2127 if (wp->prev == (struct wordent *) NULL)
2128 return(CC_ERROR); /* an empty history entry */
2130 firstp = (hp->Hlex).next;
2132 /* back up arg words in lex */
2133 for (i = 0; i < Argument && wp != firstp; i++) {
2134 wp = wp->prev;
2137 expanded = expand_lex(wp->prev, 0, i - 1);
2138 if (InsertStr(expanded)) {
2139 xfree(expanded);
2140 return(CC_ERROR);
2143 xfree(expanded);
2144 return(CC_REFRESH);
2147 /*ARGSUSED*/
2148 CCRETVAL
2149 e_dabbrev_expand(Char c)
2150 { /* expand to preceding word matching prefix */
2151 Char *cp, *ncp, *bp;
2152 struct Hist *hp;
2153 int arg = 0, i;
2154 size_t len = 0;
2155 int found = 0;
2156 Char *hbuf;
2157 static int oldevent, hist, word;
2158 static Char *start, *oldcursor;
2160 USE(c);
2161 if (Argument <= 0)
2162 return(CC_ERROR);
2164 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2165 if (cp == Cursor || Isspace(*cp))
2166 return(CC_ERROR);
2168 hbuf = NULL;
2169 hp = Histlist.Hnext;
2170 bp = InputBuf;
2171 if (Argument == 1 && eventno == oldevent && cp == start &&
2172 Cursor == oldcursor && patbuf.len > 0
2173 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2174 /* continue previous search - go to last match (hist/word) */
2175 if (hist != 0) { /* need to move up history */
2176 for (i = 1; i < hist && hp != NULL; i++)
2177 hp = hp->Hnext;
2178 if (hp == NULL) /* "can't happen" */
2179 goto err_hbuf;
2180 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2181 cp = Strend(hbuf);
2182 bp = hbuf;
2183 hp = hp->Hnext;
2185 cp = c_preword(cp, bp, word, STRshwordsep);
2186 } else { /* starting new search */
2187 oldevent = eventno;
2188 start = cp;
2189 patbuf.len = 0;
2190 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2191 hist = 0;
2192 word = 0;
2195 while (!found) {
2196 ncp = c_preword(cp, bp, 1, STRshwordsep);
2197 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2198 hist++;
2199 word = 0;
2200 if (hp == NULL)
2201 goto err_hbuf;
2202 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2203 cp = Strend(hbuf);
2204 bp = hbuf;
2205 hp = hp->Hnext;
2206 continue;
2207 } else {
2208 word++;
2209 len = c_endword(ncp-1, InputBuf, cp, 1, STRshwordsep) - ncp + 1;
2210 cp = ncp;
2212 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2213 /* We don't fully check distinct matches as Gnuemacs does: */
2214 if (Argument > 1) { /* just count matches */
2215 if (++arg >= Argument)
2216 found++;
2217 } else { /* match if distinct from previous */
2218 if (len != (size_t)(Cursor - start)
2219 || Strncmp(cp, start, len) != 0)
2220 found++;
2225 if (LastChar + len - (Cursor - start) >= InputLim)
2226 goto err_hbuf; /* no room */
2227 DeleteBack(Cursor - start);
2228 c_insert(len);
2229 while (len--)
2230 *Cursor++ = *cp++;
2231 oldcursor = Cursor;
2232 xfree(hbuf);
2233 return(CC_REFRESH);
2235 err_hbuf:
2236 xfree(hbuf);
2237 return CC_ERROR;
2240 /*ARGSUSED*/
2241 CCRETVAL
2242 e_yank_kill(Char c)
2243 { /* almost like GnuEmacs */
2244 int len;
2245 Char *kp, *cp;
2247 USE(c);
2248 if (KillRingLen == 0) /* nothing killed */
2249 return(CC_ERROR);
2250 len = Strlen(KillRing[YankPos].buf);
2251 if (LastChar + len >= InputLim)
2252 return(CC_ERROR); /* end of buffer space */
2254 /* else */
2255 cp = Cursor; /* for speed */
2257 c_insert(len); /* open the space, */
2258 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2259 *cp++ = *kp;
2261 if (Argument == 1) { /* if no arg */
2262 Mark = Cursor; /* mark at beginning, cursor at end */
2263 Cursor = cp;
2264 } else {
2265 Mark = cp; /* else cursor at beginning, mark at end */
2268 if (adrof(STRhighlight) && MarkIsSet) {
2269 ClearLines();
2270 ClearDisp();
2272 MarkIsSet = 0;
2273 return(CC_REFRESH);
2276 /*ARGSUSED*/
2277 CCRETVAL
2278 e_yank_pop(Char c)
2279 { /* almost like GnuEmacs */
2280 int m_bef_c, del_len, ins_len;
2281 Char *kp, *cp;
2283 USE(c);
2285 #if 0
2286 /* XXX This "should" be here, but doesn't work, since LastCmd
2287 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2288 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2289 second one will "succeed" even if the first one wasn't preceded
2290 by a yank, and giving an argument is impossible. Now we "succeed"
2291 regardless of previous command, which is wrong too of course. */
2292 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2293 return(CC_ERROR);
2294 #endif
2296 if (KillRingLen == 0) /* nothing killed */
2297 return(CC_ERROR);
2298 YankPos -= Argument;
2299 while (YankPos < 0)
2300 YankPos += KillRingLen;
2301 YankPos %= KillRingLen;
2303 if (Cursor > Mark) {
2304 del_len = Cursor - Mark;
2305 m_bef_c = 1;
2306 } else {
2307 del_len = Mark - Cursor;
2308 m_bef_c = 0;
2310 ins_len = Strlen(KillRing[YankPos].buf);
2311 if (LastChar + ins_len - del_len >= InputLim)
2312 return(CC_ERROR); /* end of buffer space */
2314 if (m_bef_c) {
2315 c_delbefore(del_len);
2316 } else {
2317 c_delafter(del_len);
2319 cp = Cursor; /* for speed */
2321 c_insert(ins_len); /* open the space, */
2322 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2323 *cp++ = *kp;
2325 if (m_bef_c) {
2326 Mark = Cursor; /* mark at beginning, cursor at end */
2327 Cursor = cp;
2328 } else {
2329 Mark = cp; /* else cursor at beginning, mark at end */
2332 if (adrof(STRhighlight) && MarkIsSet) {
2333 ClearLines();
2334 ClearDisp();
2336 MarkIsSet = 0;
2337 return(CC_REFRESH);
2340 /*ARGSUSED*/
2341 CCRETVAL
2342 v_delprev(Char c) /* Backspace key in insert mode */
2344 int rc;
2346 USE(c);
2347 rc = CC_ERROR;
2349 if (InsertPos != 0) {
2350 if (Argument <= Cursor - InsertPos) {
2351 c_delbefore(Argument); /* delete before */
2352 rc = CC_REFRESH;
2355 return(rc);
2356 } /* v_delprev */
2358 /*ARGSUSED*/
2359 CCRETVAL
2360 e_delprev(Char c)
2362 USE(c);
2363 if (Cursor > InputBuf) {
2364 c_delbefore(Argument); /* delete before dot */
2365 return(CC_REFRESH);
2367 else {
2368 return(CC_ERROR);
2372 /*ARGSUSED*/
2373 CCRETVAL
2374 e_delwordprev(Char c)
2376 Char *cp;
2378 USE(c);
2379 if (Cursor == InputBuf)
2380 return(CC_ERROR);
2381 /* else */
2383 cp = c_prev_word(Cursor, InputBuf, Argument);
2385 c_push_kill(cp, Cursor); /* save the text */
2387 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2388 return(CC_REFRESH);
2391 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2393 * Changed the names of some of the ^D family of editor functions to
2394 * correspond to what they actually do and created new e_delnext_list
2395 * for completeness.
2397 * Old names: New names:
2399 * delete-char delete-char-or-eof
2400 * F_DELNEXT F_DELNEXT_EOF
2401 * e_delnext e_delnext_eof
2402 * edelnxt edelnxteof
2403 * delete-char-or-eof delete-char
2404 * F_DELNEXT_EOF F_DELNEXT
2405 * e_delnext_eof e_delnext
2406 * edelnxteof edelnxt
2407 * delete-char-or-list delete-char-or-list-or-eof
2408 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2409 * e_list_delnext e_delnext_list_eof
2410 * edellsteof
2411 * (no old equivalent) delete-char-or-list
2412 * F_DELNEXT_LIST
2413 * e_delnext_list
2414 * e_delnxtlst
2417 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2418 /* rename e_delnext() -> e_delnext_eof() */
2419 /*ARGSUSED*/
2420 CCRETVAL
2421 e_delnext(Char c)
2423 USE(c);
2424 if (Cursor == LastChar) {/* if I'm at the end */
2425 if (!VImode) {
2426 return(CC_ERROR);
2428 else {
2429 if (Cursor != InputBuf)
2430 Cursor--;
2431 else
2432 return(CC_ERROR);
2435 c_delafter(Argument); /* delete after dot */
2436 if (Cursor > LastChar)
2437 Cursor = LastChar; /* bounds check */
2438 return(CC_REFRESH);
2442 /*ARGSUSED*/
2443 CCRETVAL
2444 e_delnext_eof(Char c)
2446 USE(c);
2447 if (Cursor == LastChar) {/* if I'm at the end */
2448 if (!VImode) {
2449 if (Cursor == InputBuf) {
2450 /* if I'm also at the beginning */
2451 so_write(STReof, 4);/* then do a EOF */
2452 flush();
2453 return(CC_EOF);
2455 else
2456 return(CC_ERROR);
2458 else {
2459 if (Cursor != InputBuf)
2460 Cursor--;
2461 else
2462 return(CC_ERROR);
2465 c_delafter(Argument); /* delete after dot */
2466 if (Cursor > LastChar)
2467 Cursor = LastChar; /* bounds check */
2468 return(CC_REFRESH);
2471 /*ARGSUSED*/
2472 CCRETVAL
2473 e_delnext_list(Char c)
2475 USE(c);
2476 if (Cursor == LastChar) { /* if I'm at the end */
2477 PastBottom();
2478 *LastChar = '\0'; /* just in case */
2479 return(CC_LIST_CHOICES);
2481 else {
2482 c_delafter(Argument); /* delete after dot */
2483 if (Cursor > LastChar)
2484 Cursor = LastChar; /* bounds check */
2485 return(CC_REFRESH);
2489 /*ARGSUSED*/
2490 CCRETVAL
2491 e_delnext_list_eof(Char c)
2493 USE(c);
2494 if (Cursor == LastChar) { /* if I'm at the end */
2495 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2496 so_write(STReof, 4);/* then do a EOF */
2497 flush();
2498 return(CC_EOF);
2500 else {
2501 PastBottom();
2502 *LastChar = '\0'; /* just in case */
2503 return(CC_LIST_CHOICES);
2506 else {
2507 c_delafter(Argument); /* delete after dot */
2508 if (Cursor > LastChar)
2509 Cursor = LastChar; /* bounds check */
2510 return(CC_REFRESH);
2514 /*ARGSUSED*/
2515 CCRETVAL
2516 e_list_eof(Char c)
2518 CCRETVAL rv;
2520 USE(c);
2521 if (Cursor == LastChar && Cursor == InputBuf) {
2522 so_write(STReof, 4); /* then do a EOF */
2523 flush();
2524 rv = CC_EOF;
2526 else {
2527 PastBottom();
2528 *LastChar = '\0'; /* just in case */
2529 rv = CC_LIST_CHOICES;
2531 return rv;
2534 /*ARGSUSED*/
2535 CCRETVAL
2536 e_delwordnext(Char c)
2538 Char *cp;
2540 USE(c);
2541 if (Cursor == LastChar)
2542 return(CC_ERROR);
2543 /* else */
2545 cp = c_next_word(Cursor, LastChar, Argument);
2547 c_push_kill(Cursor, cp); /* save the text */
2549 c_delafter((int)(cp - Cursor)); /* delete after dot */
2550 if (Cursor > LastChar)
2551 Cursor = LastChar; /* bounds check */
2552 return(CC_REFRESH);
2555 /*ARGSUSED*/
2556 CCRETVAL
2557 e_toend(Char c)
2559 USE(c);
2560 Cursor = LastChar;
2561 if (VImode)
2562 if (ActionFlag & TCSHOP_DELETE) {
2563 c_delfini();
2564 return(CC_REFRESH);
2566 RefCursor(); /* move the cursor */
2567 return(CC_NORM);
2570 /*ARGSUSED*/
2571 CCRETVAL
2572 e_tobeg(Char c)
2574 USE(c);
2575 Cursor = InputBuf;
2577 if (VImode) {
2578 while (Isspace(*Cursor)) /* We want FIRST non space character */
2579 Cursor++;
2580 if (ActionFlag & TCSHOP_DELETE) {
2581 c_delfini();
2582 return(CC_REFRESH);
2586 RefCursor(); /* move the cursor */
2587 return(CC_NORM);
2590 /*ARGSUSED*/
2591 CCRETVAL
2592 e_killend(Char c)
2594 USE(c);
2595 c_push_kill(Cursor, LastChar); /* copy it */
2596 LastChar = Cursor; /* zap! -- delete to end */
2597 if (Mark > Cursor)
2598 Mark = Cursor;
2599 MarkIsSet = 0;
2600 return(CC_REFRESH);
2604 /*ARGSUSED*/
2605 CCRETVAL
2606 e_killbeg(Char c)
2608 USE(c);
2609 c_push_kill(InputBuf, Cursor); /* copy it */
2610 c_delbefore((int)(Cursor - InputBuf));
2611 if (Mark && Mark > Cursor)
2612 Mark -= Cursor-InputBuf;
2613 return(CC_REFRESH);
2616 /*ARGSUSED*/
2617 CCRETVAL
2618 e_killall(Char c)
2620 USE(c);
2621 c_push_kill(InputBuf, LastChar); /* copy it */
2622 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2623 MarkIsSet = 0;
2624 return(CC_REFRESH);
2627 /*ARGSUSED*/
2628 CCRETVAL
2629 e_killregion(Char c)
2631 USE(c);
2632 if (!Mark)
2633 return(CC_ERROR);
2635 if (Mark > Cursor) {
2636 c_push_kill(Cursor, Mark); /* copy it */
2637 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2638 Mark = Cursor;
2640 else { /* mark is before cursor */
2641 c_push_kill(Mark, Cursor); /* copy it */
2642 c_delbefore((int)(Cursor - Mark));
2644 if (adrof(STRhighlight) && MarkIsSet) {
2645 ClearLines();
2646 ClearDisp();
2648 MarkIsSet = 0;
2649 return(CC_REFRESH);
2652 /*ARGSUSED*/
2653 CCRETVAL
2654 e_copyregion(Char c)
2656 USE(c);
2657 if (!Mark)
2658 return(CC_ERROR);
2660 if (Mark > Cursor) {
2661 c_push_kill(Cursor, Mark); /* copy it */
2663 else { /* mark is before cursor */
2664 c_push_kill(Mark, Cursor); /* copy it */
2666 return(CC_NORM); /* don't even need to Refresh() */
2669 /*ARGSUSED*/
2670 CCRETVAL
2671 e_charswitch(Char cc)
2673 Char c;
2675 USE(cc);
2677 /* do nothing if we are at beginning of line or have only one char */
2678 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2679 return(CC_ERROR);
2682 if (Cursor < LastChar) {
2683 Cursor++;
2685 c = Cursor[-2];
2686 Cursor[-2] = Cursor[-1];
2687 Cursor[-1] = c;
2688 return(CC_REFRESH);
2691 /*ARGSUSED*/
2692 CCRETVAL
2693 e_gcharswitch(Char cc)
2694 { /* gosmacs style ^T */
2695 Char c;
2697 USE(cc);
2698 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2699 c = Cursor[-2];
2700 Cursor[-2] = Cursor[-1];
2701 Cursor[-1] = c;
2702 return(CC_REFRESH);
2704 else {
2705 return(CC_ERROR);
2709 /*ARGSUSED*/
2710 CCRETVAL
2711 e_charback(Char c)
2713 USE(c);
2714 if (Cursor > InputBuf) {
2715 if (Argument > Cursor - InputBuf)
2716 Cursor = InputBuf;
2717 else
2718 Cursor -= Argument;
2720 if (VImode)
2721 if (ActionFlag & TCSHOP_DELETE) {
2722 c_delfini();
2723 return(CC_REFRESH);
2726 RefCursor();
2727 return(CC_NORM);
2729 else {
2730 return(CC_ERROR);
2734 /*ARGSUSED*/
2735 CCRETVAL
2736 v_wordback(Char c)
2738 USE(c);
2739 if (Cursor == InputBuf)
2740 return(CC_ERROR);
2741 /* else */
2743 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2745 if (ActionFlag & TCSHOP_DELETE) {
2746 c_delfini();
2747 return(CC_REFRESH);
2750 RefCursor();
2751 return(CC_NORM);
2754 /*ARGSUSED*/
2755 CCRETVAL
2756 e_wordback(Char c)
2758 USE(c);
2759 if (Cursor == InputBuf)
2760 return(CC_ERROR);
2761 /* else */
2763 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2765 if (VImode)
2766 if (ActionFlag & TCSHOP_DELETE) {
2767 c_delfini();
2768 return(CC_REFRESH);
2771 RefCursor();
2772 return(CC_NORM);
2775 /*ARGSUSED*/
2776 CCRETVAL
2777 e_charfwd(Char c)
2779 USE(c);
2780 if (Cursor < LastChar) {
2781 Cursor += Argument;
2782 if (Cursor > LastChar)
2783 Cursor = LastChar;
2785 if (VImode)
2786 if (ActionFlag & TCSHOP_DELETE) {
2787 c_delfini();
2788 return(CC_REFRESH);
2791 RefCursor();
2792 return(CC_NORM);
2794 else {
2795 return(CC_ERROR);
2799 /*ARGSUSED*/
2800 CCRETVAL
2801 e_wordfwd(Char c)
2803 USE(c);
2804 if (Cursor == LastChar)
2805 return(CC_ERROR);
2806 /* else */
2808 Cursor = c_next_word(Cursor, LastChar, Argument);
2810 if (VImode)
2811 if (ActionFlag & TCSHOP_DELETE) {
2812 c_delfini();
2813 return(CC_REFRESH);
2816 RefCursor();
2817 return(CC_NORM);
2820 /*ARGSUSED*/
2821 CCRETVAL
2822 v_wordfwd(Char c)
2824 USE(c);
2825 if (Cursor == LastChar)
2826 return(CC_ERROR);
2827 /* else */
2829 Cursor = c_nexword(Cursor, LastChar, Argument);
2831 if (VImode)
2832 if (ActionFlag & TCSHOP_DELETE) {
2833 c_delfini();
2834 return(CC_REFRESH);
2837 RefCursor();
2838 return(CC_NORM);
2841 /*ARGSUSED*/
2842 CCRETVAL
2843 v_wordbegnext(Char c)
2845 USE(c);
2846 if (Cursor == LastChar)
2847 return(CC_ERROR);
2848 /* else */
2850 Cursor = c_next_word(Cursor, LastChar, Argument);
2851 if (Cursor < LastChar)
2852 Cursor++;
2854 if (VImode)
2855 if (ActionFlag & TCSHOP_DELETE) {
2856 c_delfini();
2857 return(CC_REFRESH);
2860 RefCursor();
2861 return(CC_NORM);
2864 /*ARGSUSED*/
2865 static CCRETVAL
2866 v_repeat_srch(int c)
2868 CCRETVAL rv = CC_ERROR;
2869 #ifdef SDEBUG
2870 xprintf("dir %d patlen %d patbuf %S\n",
2871 c, (int)patbuf.len, patbuf.s);
2872 #endif
2874 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2875 LastChar = InputBuf;
2876 switch (c) {
2877 case F_DOWN_SEARCH_HIST:
2878 rv = e_down_search_hist(0);
2879 break;
2880 case F_UP_SEARCH_HIST:
2881 rv = e_up_search_hist(0);
2882 break;
2883 default:
2884 break;
2886 return rv;
2889 static CCRETVAL
2890 v_csearch_back(Char ch, int count, int tflag)
2892 Char *cp;
2894 cp = Cursor;
2895 while (count--) {
2896 if (*cp == ch)
2897 cp--;
2898 while (cp > InputBuf && *cp != ch)
2899 cp--;
2902 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2903 return(CC_ERROR);
2905 if (*cp == ch && tflag)
2906 cp++;
2908 Cursor = cp;
2910 if (ActionFlag & TCSHOP_DELETE) {
2911 Cursor++;
2912 c_delfini();
2913 return(CC_REFRESH);
2916 RefCursor();
2917 return(CC_NORM);
2920 static CCRETVAL
2921 v_csearch_fwd(Char ch, int count, int tflag)
2923 Char *cp;
2925 cp = Cursor;
2926 while (count--) {
2927 if (*cp == ch)
2928 cp++;
2929 while (cp < LastChar && *cp != ch)
2930 cp++;
2933 if (cp >= LastChar)
2934 return(CC_ERROR);
2936 if (*cp == ch && tflag)
2937 cp--;
2939 Cursor = cp;
2941 if (ActionFlag & TCSHOP_DELETE) {
2942 Cursor++;
2943 c_delfini();
2944 return(CC_REFRESH);
2946 RefCursor();
2947 return(CC_NORM);
2950 /*ARGSUSED*/
2951 static CCRETVAL
2952 v_action(int c)
2954 Char *cp, *kp;
2956 if (ActionFlag == TCSHOP_DELETE) {
2957 ActionFlag = TCSHOP_NOP;
2958 ActionPos = 0;
2960 UndoSize = 0;
2961 kp = UndoBuf;
2962 for (cp = InputBuf; cp < LastChar; cp++) {
2963 *kp++ = *cp;
2964 UndoSize++;
2967 UndoAction = TCSHOP_INSERT;
2968 UndoPtr = InputBuf;
2969 LastChar = InputBuf;
2970 Cursor = InputBuf;
2971 if (c & TCSHOP_INSERT)
2972 c_alternativ_key_map(0);
2974 return(CC_REFRESH);
2976 #ifdef notdef
2977 else if (ActionFlag == TCSHOP_NOP) {
2978 #endif
2979 ActionPos = Cursor;
2980 ActionFlag = c;
2981 return(CC_ARGHACK); /* Do NOT clear out argument */
2982 #ifdef notdef
2984 else {
2985 ActionFlag = 0;
2986 ActionPos = 0;
2987 return(CC_ERROR);
2989 #endif
2992 #ifdef COMMENT
2993 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2994 static void
2995 c_get_word(Char **begin, Char **end)
2997 Char *cp;
2999 cp = &Cursor[0];
3000 while (Argument--) {
3001 while ((cp <= LastChar) && (isword(*cp)))
3002 cp++;
3003 *end = --cp;
3004 while ((cp >= InputBuf) && (isword(*cp)))
3005 cp--;
3006 *begin = ++cp;
3009 #endif /* COMMENT */
3011 /*ARGSUSED*/
3012 CCRETVAL
3013 e_uppercase(Char c)
3015 Char *cp, *end;
3017 USE(c);
3018 end = c_next_word(Cursor, LastChar, Argument);
3020 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3021 if (Islower(*cp))
3022 *cp = Toupper(*cp);
3024 Cursor = end;
3025 if (Cursor > LastChar)
3026 Cursor = LastChar;
3027 return(CC_REFRESH);
3031 /*ARGSUSED*/
3032 CCRETVAL
3033 e_capitalcase(Char c)
3035 Char *cp, *end;
3037 USE(c);
3038 end = c_next_word(Cursor, LastChar, Argument);
3040 cp = Cursor;
3041 for (; cp < end; cp++) {
3042 if (Isalpha(*cp)) {
3043 if (Islower(*cp))
3044 *cp = Toupper(*cp);
3045 cp++;
3046 break;
3049 for (; cp < end; cp++)
3050 if (Isupper(*cp))
3051 *cp = Tolower(*cp);
3053 Cursor = end;
3054 if (Cursor > LastChar)
3055 Cursor = LastChar;
3056 return(CC_REFRESH);
3059 /*ARGSUSED*/
3060 CCRETVAL
3061 e_lowercase(Char c)
3063 Char *cp, *end;
3065 USE(c);
3066 end = c_next_word(Cursor, LastChar, Argument);
3068 for (cp = Cursor; cp < end; cp++)
3069 if (Isupper(*cp))
3070 *cp = Tolower(*cp);
3072 Cursor = end;
3073 if (Cursor > LastChar)
3074 Cursor = LastChar;
3075 return(CC_REFRESH);
3079 /*ARGSUSED*/
3080 CCRETVAL
3081 e_set_mark(Char c)
3083 USE(c);
3084 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3085 ClearLines();
3086 ClearDisp();
3087 Refresh();
3089 Mark = Cursor;
3090 MarkIsSet = 1;
3091 return(CC_NORM);
3094 /*ARGSUSED*/
3095 CCRETVAL
3096 e_exchange_mark(Char c)
3098 Char *cp;
3100 USE(c);
3101 cp = Cursor;
3102 Cursor = Mark;
3103 Mark = cp;
3104 RefCursor();
3105 return(CC_NORM);
3108 /*ARGSUSED*/
3109 CCRETVAL
3110 e_argfour(Char c)
3111 { /* multiply current argument by 4 */
3112 USE(c);
3113 if (Argument > 1000000)
3114 return CC_ERROR;
3115 DoingArg = 1;
3116 Argument *= 4;
3117 return(CC_ARGHACK);
3120 static void
3121 quote_mode_cleanup(void *unused)
3123 USE(unused);
3124 QuoteModeOff();
3127 /*ARGSUSED*/
3128 CCRETVAL
3129 e_quote(Char c)
3131 Char ch;
3132 int num;
3134 USE(c);
3135 QuoteModeOn();
3136 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3137 num = GetNextChar(&ch);
3138 cleanup_until(&c);
3139 if (num == 1)
3140 return e_insert(ch);
3141 else
3142 return e_send_eof(0);
3145 /*ARGSUSED*/
3146 CCRETVAL
3147 e_metanext(Char c)
3149 USE(c);
3150 MetaNext = 1;
3151 return(CC_ARGHACK); /* preserve argument */
3154 #ifdef notdef
3155 /*ARGSUSED*/
3156 CCRETVAL
3157 e_extendnext(Char c)
3159 CurrentKeyMap = CcAltMap;
3160 return(CC_ARGHACK); /* preserve argument */
3163 #endif
3165 /*ARGSUSED*/
3166 CCRETVAL
3167 v_insbeg(Char c)
3168 { /* move to beginning of line and start vi
3169 * insert mode */
3170 USE(c);
3171 Cursor = InputBuf;
3172 InsertPos = Cursor;
3174 UndoPtr = Cursor;
3175 UndoAction = TCSHOP_DELETE;
3177 RefCursor(); /* move the cursor */
3178 c_alternativ_key_map(0);
3179 return(CC_NORM);
3182 /*ARGSUSED*/
3183 CCRETVAL
3184 v_replone(Char c)
3185 { /* vi mode overwrite one character */
3186 USE(c);
3187 c_alternativ_key_map(0);
3188 inputmode = MODE_REPLACE_1;
3189 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3190 UndoPtr = Cursor;
3191 UndoSize = 0;
3192 return(CC_NORM);
3195 /*ARGSUSED*/
3196 CCRETVAL
3197 v_replmode(Char c)
3198 { /* vi mode start overwriting */
3199 USE(c);
3200 c_alternativ_key_map(0);
3201 inputmode = MODE_REPLACE;
3202 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3203 UndoPtr = Cursor;
3204 UndoSize = 0;
3205 return(CC_NORM);
3208 /*ARGSUSED*/
3209 CCRETVAL
3210 v_substchar(Char c)
3211 { /* vi mode substitute for one char */
3212 USE(c);
3213 c_delafter(Argument);
3214 c_alternativ_key_map(0);
3215 return(CC_REFRESH);
3218 /*ARGSUSED*/
3219 CCRETVAL
3220 v_substline(Char c)
3221 { /* vi mode replace whole line */
3222 USE(c);
3223 (void) e_killall(0);
3224 c_alternativ_key_map(0);
3225 return(CC_REFRESH);
3228 /*ARGSUSED*/
3229 CCRETVAL
3230 v_chgtoend(Char c)
3231 { /* vi mode change to end of line */
3232 USE(c);
3233 (void) e_killend(0);
3234 c_alternativ_key_map(0);
3235 return(CC_REFRESH);
3238 /*ARGSUSED*/
3239 CCRETVAL
3240 v_insert(Char c)
3241 { /* vi mode start inserting */
3242 USE(c);
3243 c_alternativ_key_map(0);
3245 InsertPos = Cursor;
3246 UndoPtr = Cursor;
3247 UndoAction = TCSHOP_DELETE;
3249 return(CC_NORM);
3252 /*ARGSUSED*/
3253 CCRETVAL
3254 v_add(Char c)
3255 { /* vi mode start adding */
3256 USE(c);
3257 c_alternativ_key_map(0);
3258 if (Cursor < LastChar)
3260 Cursor++;
3261 if (Cursor > LastChar)
3262 Cursor = LastChar;
3263 RefCursor();
3266 InsertPos = Cursor;
3267 UndoPtr = Cursor;
3268 UndoAction = TCSHOP_DELETE;
3270 return(CC_NORM);
3273 /*ARGSUSED*/
3274 CCRETVAL
3275 v_addend(Char c)
3276 { /* vi mode to add at end of line */
3277 USE(c);
3278 c_alternativ_key_map(0);
3279 Cursor = LastChar;
3281 InsertPos = LastChar; /* Mark where insertion begins */
3282 UndoPtr = LastChar;
3283 UndoAction = TCSHOP_DELETE;
3285 RefCursor();
3286 return(CC_NORM);
3289 /*ARGSUSED*/
3290 CCRETVAL
3291 v_change_case(Char cc)
3293 Char c;
3295 USE(cc);
3296 if (Cursor < LastChar) {
3297 #ifndef WINNT_NATIVE
3298 c = *Cursor;
3299 #else
3300 c = CHAR & *Cursor;
3301 #endif /* WINNT_NATIVE */
3302 if (Isupper(c))
3303 *Cursor++ = Tolower(c);
3304 else if (Islower(c))
3305 *Cursor++ = Toupper(c);
3306 else
3307 Cursor++;
3308 RefPlusOne(1); /* fast refresh for one char */
3309 return(CC_NORM);
3311 return(CC_ERROR);
3314 /*ARGSUSED*/
3315 CCRETVAL
3316 e_expand(Char c)
3318 Char *p;
3320 USE(c);
3321 for (p = InputBuf; Isspace(*p); p++)
3322 continue;
3323 if (p == LastChar)
3324 return(CC_ERROR);
3326 justpr++;
3327 Expand++;
3328 return(e_newline(0));
3331 /*ARGSUSED*/
3332 CCRETVAL
3333 e_startover(Char c)
3334 { /* erase all of current line, start again */
3335 USE(c);
3336 ResetInLine(0); /* reset the input pointers */
3337 return(CC_REFRESH);
3340 /*ARGSUSED*/
3341 CCRETVAL
3342 e_redisp(Char c)
3344 USE(c);
3345 ClearLines();
3346 ClearDisp();
3347 return(CC_REFRESH);
3350 /*ARGSUSED*/
3351 CCRETVAL
3352 e_cleardisp(Char c)
3354 USE(c);
3355 ClearScreen(); /* clear the whole real screen */
3356 ClearDisp(); /* reset everything */
3357 return(CC_REFRESH);
3360 /*ARGSUSED*/
3361 CCRETVAL
3362 e_tty_int(Char c)
3364 USE(c);
3365 #if defined(_MINIX) || defined(WINNT_NATIVE)
3366 /* SAK PATCH: erase all of current line, start again */
3367 ResetInLine(0); /* reset the input pointers */
3368 xputchar('\n');
3369 ClearDisp();
3370 return (CC_REFRESH);
3371 #else /* !_MINIX && !WINNT_NATIVE */
3372 /* do no editing */
3373 return (CC_NORM);
3374 #endif /* _MINIX || WINNT_NATIVE */
3378 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3379 * Function to send a character back to the input stream in cooked
3380 * mode. Only works if we have TIOCSTI
3382 /*ARGSUSED*/
3383 CCRETVAL
3384 e_stuff_char(Char c)
3386 #ifdef TIOCSTI
3387 int was_raw = Tty_raw_mode;
3388 char buf[MB_LEN_MAX];
3389 size_t i, len;
3391 if (was_raw)
3392 (void) Cookedmode();
3394 (void) xwrite(SHIN, "\n", 1);
3395 len = one_wctomb(buf, c);
3396 for (i = 0; i < len; i++)
3397 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3399 if (was_raw)
3400 (void) Rawmode();
3401 return(e_redisp(c));
3402 #else /* !TIOCSTI */
3403 return(CC_ERROR);
3404 #endif /* !TIOCSTI */
3407 /*ARGSUSED*/
3408 CCRETVAL
3409 e_insovr(Char c)
3411 USE(c);
3412 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3413 return(CC_NORM);
3416 /*ARGSUSED*/
3417 CCRETVAL
3418 e_tty_dsusp(Char c)
3420 USE(c);
3421 /* do no editing */
3422 return(CC_NORM);
3425 /*ARGSUSED*/
3426 CCRETVAL
3427 e_tty_flusho(Char c)
3429 USE(c);
3430 /* do no editing */
3431 return(CC_NORM);
3434 /*ARGSUSED*/
3435 CCRETVAL
3436 e_tty_quit(Char c)
3438 USE(c);
3439 /* do no editing */
3440 return(CC_NORM);
3443 /*ARGSUSED*/
3444 CCRETVAL
3445 e_tty_tsusp(Char c)
3447 USE(c);
3448 /* do no editing */
3449 return(CC_NORM);
3452 /*ARGSUSED*/
3453 CCRETVAL
3454 e_tty_stopo(Char c)
3456 USE(c);
3457 /* do no editing */
3458 return(CC_NORM);
3461 /* returns the number of (attempted) expansions */
3463 ExpandHistory(void)
3465 *LastChar = '\0'; /* just in case */
3466 return c_substitute();
3469 /*ARGSUSED*/
3470 CCRETVAL
3471 e_expand_history(Char c)
3473 USE(c);
3474 (void)ExpandHistory();
3475 return(CC_NORM);
3478 /*ARGSUSED*/
3479 CCRETVAL
3480 e_magic_space(Char c)
3482 USE(c);
3483 *LastChar = '\0'; /* just in case */
3484 (void)c_substitute();
3485 return(e_insert(' '));
3488 /*ARGSUSED*/
3489 CCRETVAL
3490 e_inc_fwd(Char c)
3492 CCRETVAL ret;
3494 USE(c);
3495 patbuf.len = 0;
3496 MarkIsSet = 0;
3497 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3498 if (adrof(STRhighlight) && IncMatchLen) {
3499 IncMatchLen = 0;
3500 ClearLines();
3501 ClearDisp();
3502 Refresh();
3504 IncMatchLen = 0;
3505 return ret;
3509 /*ARGSUSED*/
3510 CCRETVAL
3511 e_inc_back(Char c)
3513 CCRETVAL ret;
3515 USE(c);
3516 patbuf.len = 0;
3517 MarkIsSet = 0;
3518 ret = e_inc_search(F_UP_SEARCH_HIST);
3519 if (adrof(STRhighlight) && IncMatchLen) {
3520 IncMatchLen = 0;
3521 ClearLines();
3522 ClearDisp();
3523 Refresh();
3525 IncMatchLen = 0;
3526 return ret;
3529 /*ARGSUSED*/
3530 CCRETVAL
3531 e_copyprev(Char c)
3533 Char *cp, *oldc, *dp;
3535 USE(c);
3536 if (Cursor == InputBuf)
3537 return(CC_ERROR);
3538 /* else */
3540 oldc = Cursor;
3541 /* does a bounds check */
3542 cp = c_prev_word(Cursor, InputBuf, Argument);
3544 c_insert((int)(oldc - cp));
3545 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3546 *dp++ = *cp;
3548 Cursor = dp; /* put cursor at end */
3550 return(CC_REFRESH);
3553 /*ARGSUSED*/
3554 CCRETVAL
3555 e_tty_starto(Char c)
3557 USE(c);
3558 /* do no editing */
3559 return(CC_NORM);
3562 /*ARGSUSED*/
3563 CCRETVAL
3564 e_load_average(Char c)
3566 USE(c);
3567 PastBottom();
3568 #ifdef TIOCSTAT
3570 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3571 * there even if they don't use it. (lukem@netbsd.org)
3573 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3574 #endif
3575 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3576 return(CC_REFRESH);
3579 /*ARGSUSED*/
3580 CCRETVAL
3581 v_chgmeta(Char c)
3583 USE(c);
3585 * Delete with insert == change: first we delete and then we leave in
3586 * insert mode.
3588 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3591 /*ARGSUSED*/
3592 CCRETVAL
3593 v_delmeta(Char c)
3595 USE(c);
3596 return(v_action(TCSHOP_DELETE));
3600 /*ARGSUSED*/
3601 CCRETVAL
3602 v_endword(Char c)
3604 USE(c);
3605 if (Cursor == LastChar)
3606 return(CC_ERROR);
3607 /* else */
3609 Cursor = c_endword(Cursor, InputBuf, LastChar, Argument, STRshwspace);
3611 if (ActionFlag & TCSHOP_DELETE)
3613 Cursor++;
3614 c_delfini();
3615 return(CC_REFRESH);
3618 RefCursor();
3619 return(CC_NORM);
3622 /*ARGSUSED*/
3623 CCRETVAL
3624 v_eword(Char c)
3626 USE(c);
3627 if (Cursor == LastChar)
3628 return(CC_ERROR);
3629 /* else */
3631 Cursor = c_eword(Cursor, LastChar, Argument);
3633 if (ActionFlag & TCSHOP_DELETE) {
3634 Cursor++;
3635 c_delfini();
3636 return(CC_REFRESH);
3639 RefCursor();
3640 return(CC_NORM);
3643 /*ARGSUSED*/
3644 CCRETVAL
3645 v_char_fwd(Char c)
3647 Char ch;
3649 USE(c);
3650 if (GetNextChar(&ch) != 1)
3651 return e_send_eof(0);
3653 srch_dir = CHAR_FWD;
3654 srch_char = ch;
3656 return v_csearch_fwd(ch, Argument, 0);
3660 /*ARGSUSED*/
3661 CCRETVAL
3662 v_char_back(Char c)
3664 Char ch;
3666 USE(c);
3667 if (GetNextChar(&ch) != 1)
3668 return e_send_eof(0);
3670 srch_dir = CHAR_BACK;
3671 srch_char = ch;
3673 return v_csearch_back(ch, Argument, 0);
3676 /*ARGSUSED*/
3677 CCRETVAL
3678 v_charto_fwd(Char c)
3680 Char ch;
3682 USE(c);
3683 if (GetNextChar(&ch) != 1)
3684 return e_send_eof(0);
3686 return v_csearch_fwd(ch, Argument, 1);
3690 /*ARGSUSED*/
3691 CCRETVAL
3692 v_charto_back(Char c)
3694 Char ch;
3696 USE(c);
3697 if (GetNextChar(&ch) != 1)
3698 return e_send_eof(0);
3700 return v_csearch_back(ch, Argument, 1);
3703 /*ARGSUSED*/
3704 CCRETVAL
3705 v_rchar_fwd(Char c)
3707 USE(c);
3708 if (srch_char == 0)
3709 return CC_ERROR;
3711 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3712 v_csearch_back(srch_char, Argument, 0);
3715 /*ARGSUSED*/
3716 CCRETVAL
3717 v_rchar_back(Char c)
3719 USE(c);
3720 if (srch_char == 0)
3721 return CC_ERROR;
3723 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3724 v_csearch_back(srch_char, Argument, 0);
3727 /*ARGSUSED*/
3728 CCRETVAL
3729 v_undo(Char c)
3731 int loop;
3732 Char *kp, *cp;
3733 Char temp;
3734 int size;
3736 USE(c);
3737 switch (UndoAction) {
3738 case TCSHOP_DELETE|TCSHOP_INSERT:
3739 case TCSHOP_DELETE:
3740 if (UndoSize == 0) return(CC_NORM);
3741 cp = UndoPtr;
3742 kp = UndoBuf;
3743 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3744 *kp++ = *cp++; /* into UndoBuf */
3746 for (cp = UndoPtr; cp <= LastChar; cp++)
3747 *cp = cp[UndoSize];
3749 LastChar -= UndoSize;
3750 Cursor = UndoPtr;
3752 UndoAction = TCSHOP_INSERT;
3753 break;
3755 case TCSHOP_INSERT:
3756 if (UndoSize == 0) return(CC_NORM);
3757 cp = UndoPtr;
3758 Cursor = UndoPtr;
3759 kp = UndoBuf;
3760 c_insert(UndoSize); /* open the space, */
3761 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3762 *cp++ = *kp++;
3764 UndoAction = TCSHOP_DELETE;
3765 break;
3767 case TCSHOP_CHANGE:
3768 if (UndoSize == 0) return(CC_NORM);
3769 cp = UndoPtr;
3770 Cursor = UndoPtr;
3771 kp = UndoBuf;
3772 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3773 if (size < UndoSize)
3774 size = UndoSize;
3775 for (loop = 0; loop < size; loop++) {
3776 temp = *kp;
3777 *kp++ = *cp;
3778 *cp++ = temp;
3780 break;
3782 default:
3783 return(CC_ERROR);
3786 return(CC_REFRESH);
3789 /*ARGSUSED*/
3790 CCRETVAL
3791 v_ush_meta(Char c)
3793 USE(c);
3794 return v_search(F_UP_SEARCH_HIST);
3797 /*ARGSUSED*/
3798 CCRETVAL
3799 v_dsh_meta(Char c)
3801 USE(c);
3802 return v_search(F_DOWN_SEARCH_HIST);
3805 /*ARGSUSED*/
3806 CCRETVAL
3807 v_rsrch_fwd(Char c)
3809 USE(c);
3810 if (patbuf.len == 0) return(CC_ERROR);
3811 return(v_repeat_srch(searchdir));
3814 /*ARGSUSED*/
3815 CCRETVAL
3816 v_rsrch_back(Char c)
3818 USE(c);
3819 if (patbuf.len == 0) return(CC_ERROR);
3820 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3821 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3824 #ifndef WINNT_NATIVE
3825 /* Since ed.defns.h is generated from ed.defns.c, these empty
3826 functions will keep the F_NUM_FNS consistent
3828 CCRETVAL
3829 e_copy_to_clipboard(Char c)
3831 USE(c);
3832 return CC_ERROR;
3835 CCRETVAL
3836 e_paste_from_clipboard(Char c)
3838 USE(c);
3839 return (CC_ERROR);
3842 CCRETVAL
3843 e_dosify_next(Char c)
3845 USE(c);
3846 return (CC_ERROR);
3848 CCRETVAL
3849 e_dosify_prev(Char c)
3851 USE(c);
3852 return (CC_ERROR);
3854 CCRETVAL
3855 e_page_up(Char c)
3857 USE(c);
3858 return (CC_ERROR);
3860 CCRETVAL
3861 e_page_down(Char c)
3863 USE(c);
3864 return (CC_ERROR);
3866 #endif /* !WINNT_NATIVE */
3868 #ifdef notdef
3869 void
3870 MoveCursor(int n) /* move cursor + right - left char */
3872 Cursor = Cursor + n;
3873 if (Cursor < InputBuf)
3874 Cursor = InputBuf;
3875 if (Cursor > LastChar)
3876 Cursor = LastChar;
3877 return;
3880 Char *
3881 GetCursor(void)
3883 return(Cursor);
3887 PutCursor(Char *p)
3889 if (p < InputBuf || p > LastChar)
3890 return 1; /* Error */
3891 Cursor = p;
3892 return 0;
3894 #endif