2 * ed.chared.c: Character editing functions.
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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:
40 # echo h<press key bound to dabbrev-expande>
44 # echo h<press key bound to dabbrev-expande>
45 # echo hello\ world<cursor>
47 The same problem occured if spaces were present in a string withing quotation
52 # echo "h<press key bound to dabbrev-expande>
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\"
64 # echo '\"" '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.
79 #define TCSHOP_NOP 0x00
80 #define TCSHOP_DELETE 0x01
81 #define TCSHOP_INSERT 0x02
82 #define TCSHOP_CHANGE 0x04
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 */
101 static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */
102 static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
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);
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);
125 static void c_get_word (Char **, Char **);
127 static Char *c_preword (Char *, Char *, int, Char *);
128 static Char *c_nexword (Char *, Char *, int);
129 static Char *c_endword (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);
137 static CCRETVAL e_insert_str (Char *);
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);
145 c_alternativ_key_map(int state)
149 CurrentKeyMap = CcKeyMap;
152 CurrentKeyMap = CcAltMap;
158 AltKeyMap = (Char) state;
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--)
172 if (Mark && Mark > Cursor)
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 */
188 kp = UndoBuf; /* Set Up for VI undo command */
189 UndoAction = TCSHOP_INSERT;
192 for (cp = Cursor; cp <= LastChar; cp++) {
193 *kp++ = *cp; /* Save deleted chars into undobuf */
198 for (cp = Cursor; cp + num <= LastChar; cp++)
201 /* Mark was within the range of the deleted word? */
202 if (Mark && Mark > Cursor && Mark <= Cursor+num)
204 /* Mark after the deleted word? */
205 else if (Mark && Mark > Cursor)
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;
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 */
229 kp = UndoBuf; /* Set Up for VI undo command */
230 UndoAction = TCSHOP_INSERT;
232 UndoPtr = Cursor - num;
233 for (cp = Cursor - num; cp <= LastChar; cp++) {
239 for (cp = Cursor - num; cp + num <= LastChar; cp++)
243 /* Mark was within the range of the deleted word? */
244 if (Mark && Mark > Cursor && Mark <= Cursor+num)
246 /* Mark after the deleted word? */
247 else if (Mark && Mark > Cursor)
253 c_preword(Char *p, Char *low, int n, Char *delim)
259 while (prev < p) { /* Skip initial non-word chars */
260 if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\')
269 new = c_endword(prev-1, 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-1) == (Char)'\\')
278 p = prev; /* Set to previous word start */
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
295 * 2/ alphanumeric chars, + underscore
302 return C_CLASS_WHITE;
307 return C_CLASS_OTHER;
311 c_prev_word(Char *p, Char *low, int n)
317 while ((p >= low) && !isword(*p))
319 while ((p >= low) && isword(*p))
323 /* cp now points to one character before the word */
327 /* cp now points where we want it */
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))
342 /* if this was a non_whitespace word, we're ready */
343 if (c_class != C_CLASS_WHITE)
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))
352 p++; /* correct overshoot */
358 c_next_word(Char *p, Char *high, int n)
362 while ((p < high) && !isword(*p))
364 while ((p < high) && isword(*p))
369 /* p now points where we want it */
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))
384 /* if this was all whitespace, we're ready */
385 if (c_class == C_CLASS_WHITE)
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)
393 p--; /* correct overshoot */
399 c_nexword(Char *p, Char *high, int n)
402 while ((p < high) && !Isspace(*p))
404 while ((p < high) && Isspace(*p))
410 /* p now points where we want it */
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
431 c_number(Char *p, int *num, int dval)
442 *num = INT_MAX; /* Handle $ */
445 sign = -1; /* Handle $- */
448 for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
450 *num = (sign < 0 ? dval - i : i);
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...
464 struct Hist *h = Histlist.Hnext;
466 int i, from, to, dval;
478 switch (*(q = p + 1)) {
481 buf = expand_lex(&h->Hlex, 1, 1);
485 if ((l = (h->Hlex).prev) != 0)
486 buf = expand_lex(l->prev->prev, 0, 0);
490 buf = expand_lex(&h->Hlex, 1, INT_MAX);
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);
502 if (*q == ':') /* short form: !:arg */
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))
519 all_dig = 2;/* we are sneeky about this */
521 i = 10 * i + *q - '0';
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
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) {
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))
551 if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
552 q[1] == '$' || q[1] == '^') { /* get some args */
553 p = q[1] == ':' ? ++q : q;
557 if ((q[1] < '0' || q[1] > '9') &&
558 q[1] != '-' && q[1] != '$' && q[1] != '^')
563 if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
566 * Count up the number of words in this event. Store it in dval.
567 * Dval will be fed to number.
570 if ((l = h->Hlex.prev) != 0) {
571 for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
579 q = c_number(q, &from, dval);
582 if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
585 q = c_number(q, &to, dval);
587 else if (q[1] == '*') {
594 if (from < 0 || to < from)
596 buf = expand_lex(&h->Hlex, from, to);
598 else /* get whole cmd */
599 buf = expand_lex(&h->Hlex, 0, INT_MAX);
606 * Apply modifiers, if any.
610 while (q[1] == ':' && modbuf != NULL) {
620 if ((modbuf = domod(buf, (int) q[2])) != NULL) {
629 /* Not implemented; this needs to be done before expanding
630 * lex. We don't have the words available to us anymore.
652 buf_len = Strlen(buf);
654 * Now replace the text from op to q inclusive with the text from buf.
659 * Now replace text non-inclusively like a real CS major!
661 if (LastChar + buf_len - (q - op) >= InputLim)
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));
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)
681 * Returns number of expansions attempted (doesn't matter whether they succeeded
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)
704 while (*p != ' ' && *p != '\t' && p > InputBuf)
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
716 while (*p != HIST && p < Cursor)
718 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
722 if (p >= Cursor) /* all done */
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.
743 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
747 * If we found a history character, go expand it.
749 if (p >= InputBuf && HIST != '\0' && *p == HIST)
759 c_delfini(void) /* Finish up delete action */
763 if (ActionFlag & TCSHOP_INSERT)
764 c_alternativ_key_map(0);
766 ActionFlag = TCSHOP_NOP;
771 UndoAction = TCSHOP_INSERT;
773 if (Cursor > ActionPos) {
774 Size = (int) (Cursor-ActionPos);
778 else if (Cursor < ActionPos) {
779 Size = (int)(ActionPos-Cursor);
791 c_endword(Char *p, Char *high, int n, Char *delim)
797 while (p < high) { /* Skip non-word chars */
798 if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
802 while (p < high) { /* Skip string */
803 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
804 if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
805 if (inquote == 0) inquote = *p;
806 else if (inquote == *p) inquote = 0;
809 /* Break if unquoted non-word char */
810 if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
822 c_eword(Char *p, Char *high, int n)
832 /* scan until end of current word (may be all whitespace!) */
833 c_class = c_to_class(*p);
834 while ((p < high) && c_class == c_to_class(*p))
837 /* if this was a non_whitespace word, we're ready */
838 if (c_class != C_CLASS_WHITE)
841 /* otherwise, move to the end of the word just found */
842 c_class = c_to_class(*p);
843 while ((p < high) && c_class == c_to_class(*p))
851 /* Set the max length of the kill ring */
859 max = 1; /* no ring, but always one buffer */
860 if (max == KillRingMax)
862 new = xcalloc(max, sizeof(CStr));
863 if (KillRing != NULL) {
864 if (KillRingLen != 0) {
865 if (max >= KillRingLen) {
870 j = (KillPos - count + KillRingLen) % KillRingLen;
872 for (i = 0; i < KillRingLen; i++) {
873 if (i < count) /* copy latest */
874 new[i] = KillRing[j];
875 else /* free the others */
876 xfree(KillRing[j].buf);
877 j = (j + 1) % KillRingLen;
880 KillPos = count % max;
889 /* Push string from start upto (but not including) end onto kill ring */
891 c_push_kill(Char *start, Char *end)
895 int len = end - start, i, j, k;
897 /* Check for duplicates? */
898 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
899 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
900 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
902 for (i = 0; i < KillRingLen; i++) {
903 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
904 KillRing[j].buf[len] == '\0') {
906 for ( ; i > 0; i--) {
908 j = (j + 1) % KillRingLen;
909 KillRing[k] = KillRing[j];
914 j = (j - 1 + KillRingLen) % KillRingLen;
916 } else if (eq(dp, STRall)) { /* skip if any earlier */
917 for (i = 0; i < KillRingLen; i++)
918 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
919 KillRing[i].buf[len] == '\0')
921 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
923 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
924 KillRing[j].buf[len] == '\0')
929 /* No duplicate, go ahead and push */
930 len++; /* need space for '\0' */
932 if (KillRingLen < KillRingMax)
934 pos = &KillRing[KillPos];
935 KillPos = (KillPos + 1) % KillRingMax;
936 if (pos->len < len) {
937 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
947 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
949 c_save_inputbuf(void)
952 Strbuf_append(&SavedBuf, InputBuf);
953 Strbuf_terminate(&SavedBuf);
954 LastSaved = LastChar - InputBuf;
955 CursSaved = Cursor - InputBuf;
956 HistSaved = Hist_num;
966 if (Hist_num == 0) { /* if really the current line */
967 if (HistBuf.s != NULL)
968 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
971 LastChar = InputBuf + HistBuf.len;
987 for (h = 1; h < Hist_num; h++) {
988 if ((hp->Hnext) == NULL) {
995 if (HistLit && hp->histline) {
996 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1002 p = sprlex(&hp->Hlex);
1003 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1007 LastChar = Strend(InputBuf);
1009 if (LastChar > InputBuf) {
1010 if (LastChar[-1] == '\n')
1013 if (LastChar[-1] == ' ')
1016 if (LastChar < InputBuf)
1017 LastChar = InputBuf;
1031 c_search_line(Char *pattern, int dir)
1036 len = Strlen(pattern);
1038 if (dir == F_UP_SEARCH_HIST) {
1039 for (cp = Cursor; cp >= InputBuf; cp--)
1040 if (Strncmp(cp, pattern, len) == 0 ||
1041 Gmatch(cp, pattern)) {
1047 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1048 if (Strncmp(cp, pattern, len) == 0 ||
1049 Gmatch(cp, pattern)) {
1058 e_inc_search(int dir)
1060 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1061 STRbck[] = { 'b', 'c', 'k', '\0' };
1062 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1063 static Char endcmd[2];
1066 *oldCursor = Cursor,
1068 CCRETVAL ret = CC_NORM;
1069 int oldHist_num = Hist_num,
1070 oldpatlen = patbuf.len,
1074 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1079 if (patbuf.len == 0) { /* first round */
1081 Strbuf_append1(&patbuf, '*');
1085 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1086 *cp; *LastChar++ = *cp++)
1088 *LastChar++ = pchar;
1089 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1090 *LastChar++ = *cp++)
1093 if (adrof(STRhighlight) && pchar == ':') {
1094 /* if the no-glob-search patch is applied, remove the - 1 below */
1095 IncMatchLen = patbuf.len - 1;
1101 if (GetNextChar(&ch) != 1)
1102 return(e_send_eof(0));
1104 switch (GetCmdChar(ch)) {
1108 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1111 Strbuf_append1(&patbuf, ch);
1119 newdir = F_DOWN_SEARCH_HIST;
1124 newdir = F_UP_SEARCH_HIST;
1137 case 0007: /* ^G: Abort */
1142 case 0027: /* ^W: Append word */
1143 /* No can do if globbing characters in pattern */
1144 for (cp = &patbuf.s[1]; ; cp++)
1145 if (cp >= &patbuf.s[patbuf.len]) {
1146 Cursor += patbuf.len - 1;
1147 cp = c_next_word(Cursor, LastChar, 1);
1148 while (Cursor < cp && *Cursor != '\n') {
1149 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1153 Strbuf_append1(&patbuf, *Cursor);
1154 *LastChar++ = *Cursor++;
1160 } else if (isglob(*cp)) {
1166 default: /* Terminate and execute cmd */
1171 case 0033: /* ESC: Terminate */
1179 while (LastChar > InputBuf && *LastChar != '\n')
1185 /* Can't search if unmatched '[' */
1186 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1187 if (*cp == '[' || *cp == ']') {
1192 if (patbuf.len > 1 && ch != '[') {
1193 if (redo && newdir == dir) {
1194 if (pchar == '?') { /* wrap around */
1195 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1196 if (GetHistLine() == CC_ERROR)
1197 /* Hist_num was fixed by first call */
1198 (void) GetHistLine();
1199 Cursor = newdir == F_UP_SEARCH_HIST ?
1200 LastChar : InputBuf;
1202 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1204 Strbuf_append1(&patbuf, '*');
1205 Strbuf_terminate(&patbuf);
1206 if (Cursor < InputBuf || Cursor > LastChar ||
1207 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1208 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1209 ret = newdir == F_UP_SEARCH_HIST ?
1210 e_up_search_hist(0) : e_down_search_hist(0);
1211 if (ret != CC_ERROR) {
1212 Cursor = newdir == F_UP_SEARCH_HIST ?
1213 LastChar : InputBuf;
1214 (void) c_search_line(&patbuf.s[1], newdir);
1217 patbuf.s[--patbuf.len] = '\0';
1218 if (ret == CC_ERROR) {
1220 if (Hist_num != oldHist_num) {
1221 Hist_num = oldHist_num;
1222 if (GetHistLine() == CC_ERROR)
1232 ret = e_inc_search(newdir);
1234 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1235 /* break abort of failed search at last non-failed */
1241 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1242 /* restore on normal return or error exit */
1244 patbuf.len = oldpatlen;
1245 if (Hist_num != oldHist_num) {
1246 Hist_num = oldHist_num;
1247 if (GetHistLine() == CC_ERROR)
1251 if (ret == CC_ERROR)
1254 if (done || ret != CC_NORM)
1264 struct Strbuf tmpbuf = Strbuf_INIT;
1269 cleanup_push(&tmpbuf, Strbuf_cleanup);
1270 oldbuf = Strsave(InputBuf);
1271 cleanup_push(oldbuf, xfree);
1274 Strbuf_append1(&tmpbuf, '*');
1277 LastChar = InputBuf;
1281 c_insert(2); /* prompt + '\n' */
1283 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1285 for (ch = 0;ch == 0;) {
1286 if (GetNextChar(&ch) != 1) {
1287 cleanup_until(&tmpbuf);
1288 return(e_send_eof(0));
1291 case 0010: /* Delete and backspace */
1293 if (tmpbuf.len > 1) {
1299 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1302 cleanup_until(&tmpbuf);
1309 case 0033: /* ESC */
1311 case '\r': /* Newline */
1314 case '\012': /* ASCII Line feed */
1315 case '\015': /* ASCII (or EBCDIC) Return */
1320 Strbuf_append1(&tmpbuf, ch);
1328 cleanup_until(oldbuf);
1330 if (tmpbuf.len == 1) {
1332 * Use the old pattern, but wild-card it.
1334 if (patbuf.len == 0) {
1336 LastChar = InputBuf;
1339 cleanup_until(&tmpbuf);
1342 if (patbuf.s[0] != '*') {
1343 oldbuf = Strsave(patbuf.s);
1345 Strbuf_append1(&patbuf, '*');
1346 Strbuf_append(&patbuf, oldbuf);
1348 Strbuf_append1(&patbuf, '*');
1349 Strbuf_terminate(&patbuf);
1353 Strbuf_append1(&tmpbuf, '*');
1354 Strbuf_terminate(&tmpbuf);
1356 Strbuf_append(&patbuf, tmpbuf.s);
1357 Strbuf_terminate(&patbuf);
1359 cleanup_until(&tmpbuf);
1360 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1361 Cursor = LastChar = InputBuf;
1362 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1363 e_down_search_hist(0)) == CC_ERROR) {
1368 if (ASC(ch) == 0033) {
1381 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1382 * entry point, called from the CcKeyMap indirected into the
1392 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1395 if (UndoPtr > Cursor)
1396 UndoSize = (int)(UndoPtr - Cursor);
1398 UndoSize = (int)(Cursor - UndoPtr);
1400 inputmode = MODE_INSERT;
1401 c_alternativ_key_map(1);
1404 * We don't want to move the cursor, because all the editing
1405 * commands don't include the character under the cursor.
1407 if (Cursor > InputBuf)
1416 e_unassigned(Char c)
1417 { /* bound to keys that arn't really assigned */
1426 e_insert_str(Char *c)
1431 if (LastChar + Argument * n >= InputLim)
1432 return(CC_ERROR); /* end of buffer space */
1433 if (inputmode != MODE_INSERT) {
1434 c_delafter(Argument * Strlen(c));
1436 c_insert(Argument * n);
1437 while (Argument--) {
1438 for (i = 0; i < n; i++)
1449 #ifndef SHORT_STRINGS
1450 c &= ASCII; /* no meta chars ever */
1454 return(CC_ERROR); /* no NULs in the input ever!! */
1456 if (LastChar + Argument >= InputLim)
1457 return(CC_ERROR); /* end of buffer space */
1459 if (Argument == 1) { /* How was this optimized ???? */
1461 if (inputmode != MODE_INSERT) {
1462 UndoBuf[UndoSize++] = *Cursor;
1463 UndoBuf[UndoSize] = '\0';
1464 c_delafter(1); /* Do NOT use the saving ONE */
1468 *Cursor++ = (Char) c;
1469 DoingArg = 0; /* just in case */
1470 RefPlusOne(1); /* fast refresh for one char. */
1473 if (inputmode != MODE_INSERT) {
1475 for(i = 0; i < Argument; i++)
1476 UndoBuf[UndoSize++] = *(Cursor + i);
1478 UndoBuf[UndoSize] = '\0';
1479 c_delafter(Argument); /* Do NOT use the saving ONE */
1485 *Cursor++ = (Char) c;
1489 if (inputmode == MODE_REPLACE_1)
1490 (void) v_cmd_mode(0);
1496 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1500 if ((len = (int) Strlen(s)) <= 0)
1502 if (LastChar + len >= InputLim)
1503 return -1; /* end of buffer space */
1512 DeleteBack(int n) /* delete the n characters before . */
1516 if (Cursor >= &InputBuf[n]) {
1517 c_delbefore(n); /* delete before dot */
1522 e_digit(Char c) /* gray magic here */
1525 return(CC_ERROR); /* no NULs in the input ever!! */
1527 if (DoingArg) { /* if doing an arg, add this in... */
1528 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1531 if (Argument > 1000000)
1533 Argument = (Argument * 10) + (c - '0');
1538 if (LastChar + 1 >= InputLim)
1539 return CC_ERROR; /* end of buffer space */
1541 if (inputmode != MODE_INSERT) {
1542 UndoBuf[UndoSize++] = *Cursor;
1543 UndoBuf[UndoSize] = '\0';
1544 c_delafter(1); /* Do NOT use the saving ONE */
1547 *Cursor++ = (Char) c;
1548 DoingArg = 0; /* just in case */
1549 RefPlusOne(1); /* fast refresh for one char. */
1555 e_argdigit(Char c) /* for ESC-n */
1560 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1564 return(CC_ERROR); /* no NULs in the input ever!! */
1566 if (DoingArg) { /* if doing an arg, add this in... */
1567 if (Argument > 1000000)
1569 Argument = (Argument * 10) + (c - '0');
1571 else { /* else starting an argument */
1579 v_zero(Char c) /* command mode 0 for vi */
1581 if (DoingArg) { /* if doing an arg, add this in... */
1582 if (Argument > 1000000)
1584 Argument = (Argument * 10) + (c - '0');
1587 else { /* else starting an argument */
1589 if (ActionFlag & TCSHOP_DELETE) {
1593 RefCursor(); /* move the cursor */
1601 { /* always ignore argument */
1603 if (adrof(STRhighlight) && MarkIsSet) {
1611 /* PastBottom(); NOW done in ed.inputl.c */
1612 *LastChar++ = '\n'; /* for the benefit of CSH */
1613 *LastChar = '\0'; /* just in case */
1615 InsertPos = InputBuf; /* Reset editing position */
1621 e_newline_hold(Char c)
1626 *LastChar++ = '\n'; /* for the benefit of CSH */
1627 *LastChar = '\0'; /* just in case */
1633 e_newline_down_hist(Char c)
1637 HistSaved = Hist_num;
1639 *LastChar++ = '\n'; /* for the benefit of CSH */
1640 *LastChar = '\0'; /* just in case */
1647 { /* for when ^D is ONLY send-eof */
1650 *LastChar = '\0'; /* just in case */
1659 *LastChar = '\0'; /* just in case */
1660 return(CC_COMPLETE);
1665 e_complete_back(Char c)
1668 *LastChar = '\0'; /* just in case */
1669 return(CC_COMPLETE_BACK);
1674 e_complete_fwd(Char c)
1677 *LastChar = '\0'; /* just in case */
1678 return(CC_COMPLETE_FWD);
1683 e_complete_all(Char c)
1686 *LastChar = '\0'; /* just in case */
1687 return(CC_COMPLETE_ALL);
1692 v_cm_complete(Char c)
1695 if (Cursor < LastChar)
1697 *LastChar = '\0'; /* just in case */
1698 return(CC_COMPLETE);
1703 e_toggle_hist(Char c)
1709 *LastChar = '\0'; /* just in case */
1711 if (Hist_num <= 0) {
1715 hp = Histlist.Hnext;
1716 if (hp == NULL) { /* this is only if no history */
1720 for (h = 1; h < Hist_num; h++)
1723 if (!CurrentHistLit) {
1725 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1735 p = sprlex(&hp->Hlex);
1736 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1741 LastChar = Strend(InputBuf);
1742 if (LastChar > InputBuf) {
1743 if (LastChar[-1] == '\n')
1745 if (LastChar[-1] == ' ')
1747 if (LastChar < InputBuf)
1748 LastChar = InputBuf;
1768 UndoAction = TCSHOP_NOP;
1769 *LastChar = '\0'; /* just in case */
1771 if (Hist_num == 0) { /* save the current buffer away */
1773 Strbuf_append(&HistBuf, InputBuf);
1774 Strbuf_terminate(&HistBuf);
1777 Hist_num += Argument;
1779 if (GetHistLine() == CC_ERROR) {
1781 (void) GetHistLine(); /* Hist_num was fixed by first call */
1788 return(CC_NORM); /* was CC_UP_HIST */
1796 UndoAction = TCSHOP_NOP;
1797 *LastChar = '\0'; /* just in case */
1799 Hist_num -= Argument;
1803 return(CC_ERROR); /* make it beep */
1806 return(GetHistLine());
1812 * c_hmatch() return True if the pattern matches the prefix
1817 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1819 return Gmatch(str, patbuf.s);
1823 * c_hsetpat(): Set the history seatch pattern
1828 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1830 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1831 Strbuf_terminate(&patbuf);
1834 xprintf("\nHist_num = %d\n", Hist_num);
1835 xprintf("patlen = %d\n", (int)patbuf.len);
1836 xprintf("patbuf = \"%S\"\n", patbuf.s);
1837 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1843 e_up_search_hist(Char c)
1850 ActionFlag = TCSHOP_NOP;
1851 UndoAction = TCSHOP_NOP;
1852 *LastChar = '\0'; /* just in case */
1855 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1861 if (Hist_num == 0) {
1863 Strbuf_append(&HistBuf, InputBuf);
1864 Strbuf_terminate(&HistBuf);
1868 hp = Histlist.Hnext;
1872 c_hsetpat(); /* Set search pattern !! */
1874 for (h = 1; h <= Hist_num; h++)
1877 while (hp != NULL) {
1881 if (hp->histline == NULL)
1882 hp->histline = sprlex(&hp->Hlex);
1886 hl = sprlex(&hp->Hlex);
1887 cleanup_push(hl, xfree);
1890 xprintf("Comparing with \"%S\"\n", hl);
1892 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1893 hl[LastChar-InputBuf]) && c_hmatch(hl);
1906 xprintf("not found\n");
1913 return(GetHistLine());
1918 e_down_search_hist(Char c)
1925 ActionFlag = TCSHOP_NOP;
1926 UndoAction = TCSHOP_NOP;
1927 *LastChar = '\0'; /* just in case */
1932 hp = Histlist.Hnext;
1936 c_hsetpat(); /* Set search pattern !! */
1938 for (h = 1; h < Hist_num && hp; h++) {
1940 if (hp->histline == NULL)
1941 hp->histline = sprlex(&hp->Hlex);
1945 hl = sprlex(&hp->Hlex);
1946 cleanup_push(hl, xfree);
1949 xprintf("Comparing with \"%S\"\n", hl);
1951 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1952 hl[LastChar-InputBuf]) && c_hmatch(hl))
1959 if (!found) { /* is it the current history number? */
1960 if (!c_hmatch(HistBuf.s)) {
1962 xprintf("not found\n");
1970 return(GetHistLine());
1979 *LastChar = '\0'; /* just in case */
1988 *LastChar = '\0'; /* just in case */
1997 *LastChar = '\0'; /* just in case */
1998 return(CC_CORRECT_L);
2003 e_run_fg_editor(Char c)
2008 if ((pp = find_stop_ed()) != NULL) {
2009 /* save our editor state so we can restore it */
2011 Hist_num = 0; /* for the history commands */
2013 /* put the tty in a sane mode */
2015 (void) Cookedmode(); /* make sure the tty is set up correctly */
2020 (void) Rawmode(); /* go on */
2030 e_list_choices(Char c)
2034 *LastChar = '\0'; /* just in case */
2035 return(CC_LIST_CHOICES);
2044 *LastChar = '\0'; /* just in case */
2045 return(CC_LIST_ALL);
2054 *LastChar = '\0'; /* just in case */
2055 return(CC_LIST_GLOB);
2060 e_expand_glob(Char c)
2063 *LastChar = '\0'; /* just in case */
2064 return(CC_EXPAND_GLOB);
2069 e_normalize_path(Char c)
2072 *LastChar = '\0'; /* just in case */
2073 return(CC_NORMALIZE_PATH);
2078 e_normalize_command(Char c)
2081 *LastChar = '\0'; /* just in case */
2082 return(CC_NORMALIZE_COMMAND);
2087 e_expand_vars(Char c)
2090 *LastChar = '\0'; /* just in case */
2091 return(CC_EXPAND_VARS);
2097 { /* do a fast command line which(1) */
2100 Hist_num = 0; /* for the history commands */
2102 *LastChar = '\0'; /* just in case */
2109 { /* insert the last element of the prev. cmd */
2111 struct wordent *wp, *firstp;
2119 hp = Histlist.Hnext;
2120 if (hp == NULL) { /* this is only if no history */
2124 wp = (hp->Hlex).prev;
2126 if (wp->prev == (struct wordent *) NULL)
2127 return(CC_ERROR); /* an empty history entry */
2129 firstp = (hp->Hlex).next;
2131 /* back up arg words in lex */
2132 for (i = 0; i < Argument && wp != firstp; i++) {
2136 expanded = expand_lex(wp->prev, 0, i - 1);
2137 if (InsertStr(expanded)) {
2148 e_dabbrev_expand(Char c)
2149 { /* expand to preceding word matching prefix */
2150 Char *cp, *ncp, *bp;
2156 static int oldevent, hist, word;
2157 static Char *start, *oldcursor;
2163 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2164 if (cp == Cursor || Isspace(*cp))
2168 hp = Histlist.Hnext;
2170 if (Argument == 1 && eventno == oldevent && cp == start &&
2171 Cursor == oldcursor && patbuf.len > 0
2172 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2173 /* continue previous search - go to last match (hist/word) */
2174 if (hist != 0) { /* need to move up history */
2175 for (i = 1; i < hist && hp != NULL; i++)
2177 if (hp == NULL) /* "can't happen" */
2179 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2184 cp = c_preword(cp, bp, word, STRshwordsep);
2185 } else { /* starting new search */
2189 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2195 ncp = c_preword(cp, bp, 1, STRshwordsep);
2196 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2201 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2208 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2211 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2212 /* We don't fully check distinct matches as Gnuemacs does: */
2213 if (Argument > 1) { /* just count matches */
2214 if (++arg >= Argument)
2216 } else { /* match if distinct from previous */
2217 if (len != (size_t)(Cursor - start)
2218 || Strncmp(cp, start, len) != 0)
2224 if (LastChar + len - (Cursor - start) >= InputLim)
2225 goto err_hbuf; /* no room */
2226 DeleteBack(Cursor - start);
2242 { /* almost like GnuEmacs */
2247 if (KillRingLen == 0) /* nothing killed */
2249 len = Strlen(KillRing[YankPos].buf);
2250 if (LastChar + len >= InputLim)
2251 return(CC_ERROR); /* end of buffer space */
2254 cp = Cursor; /* for speed */
2256 c_insert(len); /* open the space, */
2257 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2260 if (Argument == 1) { /* if no arg */
2261 Mark = Cursor; /* mark at beginning, cursor at end */
2264 Mark = cp; /* else cursor at beginning, mark at end */
2267 if (adrof(STRhighlight) && MarkIsSet) {
2278 { /* almost like GnuEmacs */
2279 int m_bef_c, del_len, ins_len;
2285 /* XXX This "should" be here, but doesn't work, since LastCmd
2286 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2287 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2288 second one will "succeed" even if the first one wasn't preceded
2289 by a yank, and giving an argument is impossible. Now we "succeed"
2290 regardless of previous command, which is wrong too of course. */
2291 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2295 if (KillRingLen == 0) /* nothing killed */
2297 YankPos -= Argument;
2299 YankPos += KillRingLen;
2300 YankPos %= KillRingLen;
2302 if (Cursor > Mark) {
2303 del_len = Cursor - Mark;
2306 del_len = Mark - Cursor;
2309 ins_len = Strlen(KillRing[YankPos].buf);
2310 if (LastChar + ins_len - del_len >= InputLim)
2311 return(CC_ERROR); /* end of buffer space */
2314 c_delbefore(del_len);
2316 c_delafter(del_len);
2318 cp = Cursor; /* for speed */
2320 c_insert(ins_len); /* open the space, */
2321 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2325 Mark = Cursor; /* mark at beginning, cursor at end */
2328 Mark = cp; /* else cursor at beginning, mark at end */
2331 if (adrof(STRhighlight) && MarkIsSet) {
2341 v_delprev(Char c) /* Backspace key in insert mode */
2348 if (InsertPos != 0) {
2349 if (Argument <= Cursor - InsertPos) {
2350 c_delbefore(Argument); /* delete before */
2362 if (Cursor > InputBuf) {
2363 c_delbefore(Argument); /* delete before dot */
2373 e_delwordprev(Char c)
2378 if (Cursor == InputBuf)
2382 cp = c_prev_word(Cursor, InputBuf, Argument);
2384 c_push_kill(cp, Cursor); /* save the text */
2386 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2390 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2392 * Changed the names of some of the ^D family of editor functions to
2393 * correspond to what they actually do and created new e_delnext_list
2396 * Old names: New names:
2398 * delete-char delete-char-or-eof
2399 * F_DELNEXT F_DELNEXT_EOF
2400 * e_delnext e_delnext_eof
2401 * edelnxt edelnxteof
2402 * delete-char-or-eof delete-char
2403 * F_DELNEXT_EOF F_DELNEXT
2404 * e_delnext_eof e_delnext
2405 * edelnxteof edelnxt
2406 * delete-char-or-list delete-char-or-list-or-eof
2407 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2408 * e_list_delnext e_delnext_list_eof
2410 * (no old equivalent) delete-char-or-list
2416 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2417 /* rename e_delnext() -> e_delnext_eof() */
2423 if (Cursor == LastChar) {/* if I'm at the end */
2428 if (Cursor != InputBuf)
2434 c_delafter(Argument); /* delete after dot */
2435 if (Cursor > LastChar)
2436 Cursor = LastChar; /* bounds check */
2443 e_delnext_eof(Char c)
2446 if (Cursor == LastChar) {/* if I'm at the end */
2448 if (Cursor == InputBuf) {
2449 /* if I'm also at the beginning */
2450 so_write(STReof, 4);/* then do a EOF */
2458 if (Cursor != InputBuf)
2464 c_delafter(Argument); /* delete after dot */
2465 if (Cursor > LastChar)
2466 Cursor = LastChar; /* bounds check */
2472 e_delnext_list(Char c)
2475 if (Cursor == LastChar) { /* if I'm at the end */
2477 *LastChar = '\0'; /* just in case */
2478 return(CC_LIST_CHOICES);
2481 c_delafter(Argument); /* delete after dot */
2482 if (Cursor > LastChar)
2483 Cursor = LastChar; /* bounds check */
2490 e_delnext_list_eof(Char c)
2493 if (Cursor == LastChar) { /* if I'm at the end */
2494 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2495 so_write(STReof, 4);/* then do a EOF */
2501 *LastChar = '\0'; /* just in case */
2502 return(CC_LIST_CHOICES);
2506 c_delafter(Argument); /* delete after dot */
2507 if (Cursor > LastChar)
2508 Cursor = LastChar; /* bounds check */
2520 if (Cursor == LastChar && Cursor == InputBuf) {
2521 so_write(STReof, 4); /* then do a EOF */
2527 *LastChar = '\0'; /* just in case */
2528 rv = CC_LIST_CHOICES;
2535 e_delwordnext(Char c)
2540 if (Cursor == LastChar)
2544 cp = c_next_word(Cursor, LastChar, Argument);
2546 c_push_kill(Cursor, cp); /* save the text */
2548 c_delafter((int)(cp - Cursor)); /* delete after dot */
2549 if (Cursor > LastChar)
2550 Cursor = LastChar; /* bounds check */
2561 if (ActionFlag & TCSHOP_DELETE) {
2565 RefCursor(); /* move the cursor */
2577 while (Isspace(*Cursor)) /* We want FIRST non space character */
2579 if (ActionFlag & TCSHOP_DELETE) {
2585 RefCursor(); /* move the cursor */
2594 c_push_kill(Cursor, LastChar); /* copy it */
2595 LastChar = Cursor; /* zap! -- delete to end */
2608 c_push_kill(InputBuf, Cursor); /* copy it */
2609 c_delbefore((int)(Cursor - InputBuf));
2610 if (Mark && Mark > Cursor)
2611 Mark -= Cursor-InputBuf;
2620 c_push_kill(InputBuf, LastChar); /* copy it */
2621 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2628 e_killregion(Char c)
2634 if (Mark > Cursor) {
2635 c_push_kill(Cursor, Mark); /* copy it */
2636 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2639 else { /* mark is before cursor */
2640 c_push_kill(Mark, Cursor); /* copy it */
2641 c_delbefore((int)(Cursor - Mark));
2643 if (adrof(STRhighlight) && MarkIsSet) {
2653 e_copyregion(Char c)
2659 if (Mark > Cursor) {
2660 c_push_kill(Cursor, Mark); /* copy it */
2662 else { /* mark is before cursor */
2663 c_push_kill(Mark, Cursor); /* copy it */
2665 return(CC_NORM); /* don't even need to Refresh() */
2670 e_charswitch(Char cc)
2676 /* do nothing if we are at beginning of line or have only one char */
2677 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2681 if (Cursor < LastChar) {
2685 Cursor[-2] = Cursor[-1];
2692 e_gcharswitch(Char cc)
2693 { /* gosmacs style ^T */
2697 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2699 Cursor[-2] = Cursor[-1];
2713 if (Cursor > InputBuf) {
2714 if (Argument > Cursor - InputBuf)
2720 if (ActionFlag & TCSHOP_DELETE) {
2738 if (Cursor == InputBuf)
2742 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2744 if (ActionFlag & TCSHOP_DELETE) {
2758 if (Cursor == InputBuf)
2762 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2765 if (ActionFlag & TCSHOP_DELETE) {
2779 if (Cursor < LastChar) {
2781 if (Cursor > LastChar)
2785 if (ActionFlag & TCSHOP_DELETE) {
2803 if (Cursor == LastChar)
2807 Cursor = c_next_word(Cursor, LastChar, Argument);
2810 if (ActionFlag & TCSHOP_DELETE) {
2824 if (Cursor == LastChar)
2828 Cursor = c_nexword(Cursor, LastChar, Argument);
2831 if (ActionFlag & TCSHOP_DELETE) {
2842 v_wordbegnext(Char c)
2845 if (Cursor == LastChar)
2849 Cursor = c_next_word(Cursor, LastChar, Argument);
2850 if (Cursor < LastChar)
2854 if (ActionFlag & TCSHOP_DELETE) {
2865 v_repeat_srch(int c)
2867 CCRETVAL rv = CC_ERROR;
2869 xprintf("dir %d patlen %d patbuf %S\n",
2870 c, (int)patbuf.len, patbuf.s);
2873 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2874 LastChar = InputBuf;
2876 case F_DOWN_SEARCH_HIST:
2877 rv = e_down_search_hist(0);
2879 case F_UP_SEARCH_HIST:
2880 rv = e_up_search_hist(0);
2889 v_csearch_back(Char ch, int count, int tflag)
2897 while (cp > InputBuf && *cp != ch)
2901 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2904 if (*cp == ch && tflag)
2909 if (ActionFlag & TCSHOP_DELETE) {
2920 v_csearch_fwd(Char ch, int count, int tflag)
2928 while (cp < LastChar && *cp != ch)
2935 if (*cp == ch && tflag)
2940 if (ActionFlag & TCSHOP_DELETE) {
2955 if (ActionFlag == TCSHOP_DELETE) {
2956 ActionFlag = TCSHOP_NOP;
2961 for (cp = InputBuf; cp < LastChar; cp++) {
2966 UndoAction = TCSHOP_INSERT;
2968 LastChar = InputBuf;
2970 if (c & TCSHOP_INSERT)
2971 c_alternativ_key_map(0);
2976 else if (ActionFlag == TCSHOP_NOP) {
2980 return(CC_ARGHACK); /* Do NOT clear out argument */
2992 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2994 c_get_word(Char **begin, Char **end)
2999 while (Argument--) {
3000 while ((cp <= LastChar) && (isword(*cp)))
3003 while ((cp >= InputBuf) && (isword(*cp)))
3008 #endif /* COMMENT */
3017 end = c_next_word(Cursor, LastChar, Argument);
3019 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3024 if (Cursor > LastChar)
3032 e_capitalcase(Char c)
3037 end = c_next_word(Cursor, LastChar, Argument);
3040 for (; cp < end; cp++) {
3048 for (; cp < end; cp++)
3053 if (Cursor > LastChar)
3065 end = c_next_word(Cursor, LastChar, Argument);
3067 for (cp = Cursor; cp < end; cp++)
3072 if (Cursor > LastChar)
3083 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3095 e_exchange_mark(Char c)
3110 { /* multiply current argument by 4 */
3112 if (Argument > 1000000)
3120 quote_mode_cleanup(void *unused)
3135 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3136 num = GetNextChar(&ch);
3139 return e_insert(ch);
3141 return e_send_eof(0);
3150 return(CC_ARGHACK); /* preserve argument */
3156 e_extendnext(Char c)
3158 CurrentKeyMap = CcAltMap;
3159 return(CC_ARGHACK); /* preserve argument */
3167 { /* move to beginning of line and start vi
3174 UndoAction = TCSHOP_DELETE;
3176 RefCursor(); /* move the cursor */
3177 c_alternativ_key_map(0);
3184 { /* vi mode overwrite one character */
3186 c_alternativ_key_map(0);
3187 inputmode = MODE_REPLACE_1;
3188 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3197 { /* vi mode start overwriting */
3199 c_alternativ_key_map(0);
3200 inputmode = MODE_REPLACE;
3201 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3210 { /* vi mode substitute for one char */
3212 c_delafter(Argument);
3213 c_alternativ_key_map(0);
3220 { /* vi mode replace whole line */
3222 (void) e_killall(0);
3223 c_alternativ_key_map(0);
3230 { /* vi mode change to end of line */
3232 (void) e_killend(0);
3233 c_alternativ_key_map(0);
3240 { /* vi mode start inserting */
3242 c_alternativ_key_map(0);
3246 UndoAction = TCSHOP_DELETE;
3254 { /* vi mode start adding */
3256 c_alternativ_key_map(0);
3257 if (Cursor < LastChar)
3260 if (Cursor > LastChar)
3267 UndoAction = TCSHOP_DELETE;
3275 { /* vi mode to add at end of line */
3277 c_alternativ_key_map(0);
3280 InsertPos = LastChar; /* Mark where insertion begins */
3282 UndoAction = TCSHOP_DELETE;
3290 v_change_case(Char cc)
3295 if (Cursor < LastChar) {
3296 #ifndef WINNT_NATIVE
3300 #endif /* WINNT_NATIVE */
3302 *Cursor++ = Tolower(c);
3303 else if (Islower(c))
3304 *Cursor++ = Toupper(c);
3307 RefPlusOne(1); /* fast refresh for one char */
3320 for (p = InputBuf; Isspace(*p); p++)
3327 return(e_newline(0));
3333 { /* erase all of current line, start again */
3335 ResetInLine(0); /* reset the input pointers */
3354 ClearScreen(); /* clear the whole real screen */
3355 ClearDisp(); /* reset everything */
3364 #if defined(_MINIX) || defined(WINNT_NATIVE)
3365 /* SAK PATCH: erase all of current line, start again */
3366 ResetInLine(0); /* reset the input pointers */
3369 return (CC_REFRESH);
3370 #else /* !_MINIX && !WINNT_NATIVE */
3373 #endif /* _MINIX || WINNT_NATIVE */
3377 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3378 * Function to send a character back to the input stream in cooked
3379 * mode. Only works if we have TIOCSTI
3383 e_stuff_char(Char c)
3386 int was_raw = Tty_raw_mode;
3387 char buf[MB_LEN_MAX];
3391 (void) Cookedmode();
3393 (void) xwrite(SHIN, "\n", 1);
3394 len = one_wctomb(buf, c);
3395 for (i = 0; i < len; i++)
3396 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3400 return(e_redisp(c));
3401 #else /* !TIOCSTI */
3403 #endif /* !TIOCSTI */
3411 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3426 e_tty_flusho(Char c)
3460 /* returns the number of (attempted) expansions */
3464 *LastChar = '\0'; /* just in case */
3465 return c_substitute();
3470 e_expand_history(Char c)
3473 (void)ExpandHistory();
3479 e_magic_space(Char c)
3482 *LastChar = '\0'; /* just in case */
3483 (void)c_substitute();
3484 return(e_insert(' '));
3496 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3497 if (adrof(STRhighlight) && IncMatchLen) {
3517 ret = e_inc_search(F_UP_SEARCH_HIST);
3518 if (adrof(STRhighlight) && IncMatchLen) {
3532 Char *cp, *oldc, *dp;
3535 if (Cursor == InputBuf)
3540 /* does a bounds check */
3541 cp = c_prev_word(Cursor, InputBuf, Argument);
3543 c_insert((int)(oldc - cp));
3544 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3547 Cursor = dp; /* put cursor at end */
3554 e_tty_starto(Char c)
3563 e_load_average(Char c)
3569 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3570 * there even if they don't use it. (lukem@netbsd.org)
3572 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3574 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3584 * Delete with insert == change: first we delete and then we leave in
3587 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3595 return(v_action(TCSHOP_DELETE));
3604 if (Cursor == LastChar)
3608 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3610 if (ActionFlag & TCSHOP_DELETE)
3626 if (Cursor == LastChar)
3630 Cursor = c_eword(Cursor, LastChar, Argument);
3632 if (ActionFlag & TCSHOP_DELETE) {
3649 if (GetNextChar(&ch) != 1)
3650 return e_send_eof(0);
3652 srch_dir = CHAR_FWD;
3655 return v_csearch_fwd(ch, Argument, 0);
3666 if (GetNextChar(&ch) != 1)
3667 return e_send_eof(0);
3669 srch_dir = CHAR_BACK;
3672 return v_csearch_back(ch, Argument, 0);
3677 v_charto_fwd(Char c)
3682 if (GetNextChar(&ch) != 1)
3683 return e_send_eof(0);
3685 return v_csearch_fwd(ch, Argument, 1);
3691 v_charto_back(Char c)
3696 if (GetNextChar(&ch) != 1)
3697 return e_send_eof(0);
3699 return v_csearch_back(ch, Argument, 1);
3710 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3711 v_csearch_back(srch_char, Argument, 0);
3716 v_rchar_back(Char c)
3722 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3723 v_csearch_back(srch_char, Argument, 0);
3736 switch (UndoAction) {
3737 case TCSHOP_DELETE|TCSHOP_INSERT:
3739 if (UndoSize == 0) return(CC_NORM);
3742 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3743 *kp++ = *cp++; /* into UndoBuf */
3745 for (cp = UndoPtr; cp <= LastChar; cp++)
3748 LastChar -= UndoSize;
3751 UndoAction = TCSHOP_INSERT;
3755 if (UndoSize == 0) return(CC_NORM);
3759 c_insert(UndoSize); /* open the space, */
3760 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3763 UndoAction = TCSHOP_DELETE;
3767 if (UndoSize == 0) return(CC_NORM);
3771 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3772 if (size < UndoSize)
3774 for(loop = 0; loop < size; loop++) {
3793 return v_search(F_UP_SEARCH_HIST);
3801 return v_search(F_DOWN_SEARCH_HIST);
3809 if (patbuf.len == 0) return(CC_ERROR);
3810 return(v_repeat_srch(searchdir));
3815 v_rsrch_back(Char c)
3818 if (patbuf.len == 0) return(CC_ERROR);
3819 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3820 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3823 #ifndef WINNT_NATIVE
3824 /* Since ed.defns.h is generated from ed.defns.c, these empty
3825 functions will keep the F_NUM_FNS consistent
3828 e_copy_to_clipboard(Char c)
3835 e_paste_from_clipboard(Char c)
3842 e_dosify_next(Char c)
3848 e_dosify_prev(Char c)
3865 #endif /* !WINNT_NATIVE */
3869 MoveCursor(int n) /* move cursor + right - left char */
3871 Cursor = Cursor + n;
3872 if (Cursor < InputBuf)
3874 if (Cursor > LastChar)
3888 if (p < InputBuf || p > LastChar)
3889 return 1; /* Error */