1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.95 2009/06/25 21:15:37 christos Exp $ */
3 * ed.chared.c: Character editing functions.
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
36 e_dabbrev_expand() did not do proper completion if quoted spaces were present
37 in the string being completed. Exemple:
41 # echo h<press key bound to dabbrev-expande>
45 # echo h<press key bound to dabbrev-expande>
46 # echo hello\ world<cursor>
48 The same problem occured if spaces were present in a string withing quotation
53 # echo "h<press key bound to dabbrev-expande>
56 The former problem could be solved with minor modifications of c_preword()
57 and c_endword(). The latter, however, required a significant rewrite of
58 c_preword(), since quoted strings must be parsed from start to end to
59 determine if a given character is inside or outside the quotation marks.
61 Compare the following two strings:
63 # echo \"" 'foo \' bar\"
65 # echo '\"" 'foo \' bar\"
68 The only difference between the two echo lines is in the first character
69 after the echo command. The result is either one or three arguments.
75 RCSID("$tcsh: ed.chared.c,v 3.95 2009/06/25 21:15:37 christos Exp $")
83 #define TCSHOP_NOP 0x00
84 #define TCSHOP_DELETE 0x01
85 #define TCSHOP_INSERT 0x02
86 #define TCSHOP_CHANGE 0x04
93 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
95 #define C_CLASS_WHITE 1
96 #define C_CLASS_ALNUM 2
97 #define C_CLASS_OTHER 3
99 static Char *InsertPos = InputBuf; /* Where insertion starts */
100 static Char *ActionPos = 0; /* Where action begins */
101 static int ActionFlag = TCSHOP_NOP; /* What delayed action to take */
105 static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */
106 static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
110 static int srch_dir = CHAR_FWD; /* Direction of last search */
111 static Char srch_char = 0; /* Search target */
113 /* all routines that start with c_ are private to this set of routines */
114 static void c_alternativ_key_map (int);
116 void c_delafter (int);
117 void c_delbefore (int);
118 static int c_to_class (Char);
119 static Char *c_prev_word (Char *, Char *, int);
120 static Char *c_next_word (Char *, Char *, int);
121 static Char *c_number (Char *, int *, int);
122 static Char *c_expand (Char *);
123 static int c_excl (Char *);
124 static int c_substitute (void);
125 static void c_delfini (void);
126 static int c_hmatch (Char *);
127 static void c_hsetpat (void);
129 static void c_get_word (Char **, Char **);
131 static Char *c_preword (Char *, Char *, int, Char *);
132 static Char *c_nexword (Char *, Char *, int);
133 static Char *c_endword (Char *, Char *, int, Char *);
134 static Char *c_eword (Char *, Char *, int);
135 static void c_push_kill (Char *, Char *);
136 static void c_save_inputbuf (void);
137 static CCRETVAL c_search_line (Char *, int);
138 static CCRETVAL v_repeat_srch (int);
139 static CCRETVAL e_inc_search (int);
141 static CCRETVAL e_insert_str (Char *);
143 static CCRETVAL v_search (int);
144 static CCRETVAL v_csearch_fwd (Char, int, int);
145 static CCRETVAL v_action (int);
146 static CCRETVAL v_csearch_back (Char, int, int);
149 c_alternativ_key_map(int state)
153 CurrentKeyMap = CcKeyMap;
156 CurrentKeyMap = CcAltMap;
162 AltKeyMap = (Char) state;
170 if (LastChar + num >= InputLim)
171 return; /* can't go past end of buffer */
173 if (Cursor < LastChar) { /* if I must move chars */
174 for (cp = LastChar; cp >= Cursor; cp--)
176 if (Mark && Mark > Cursor)
185 Char *cp, *kp = NULL;
187 if (num > LastChar - Cursor)
188 num = (int) (LastChar - Cursor); /* bounds check */
190 if (num > 0) { /* if I can delete anything */
192 kp = UndoBuf; /* Set Up for VI undo command */
193 UndoAction = TCSHOP_INSERT;
196 for (cp = Cursor; cp <= LastChar; cp++) {
197 *kp++ = *cp; /* Save deleted chars into undobuf */
202 for (cp = Cursor; cp + num <= LastChar; cp++)
205 /* Mark was within the range of the deleted word? */
206 if (Mark && Mark > Cursor && Mark <= Cursor+num)
208 /* Mark after the deleted word? */
209 else if (Mark && Mark > Cursor)
215 * XXX: We don't want to do that. In emacs mode overwrite should be
216 * sticky. I am not sure how that affects vi mode
218 inputmode = MODE_INSERT;
224 c_delbefore(int num) /* delete before dot, with bounds checking */
226 Char *cp, *kp = NULL;
228 if (num > Cursor - InputBuf)
229 num = (int) (Cursor - InputBuf); /* bounds check */
231 if (num > 0) { /* if I can delete anything */
233 kp = UndoBuf; /* Set Up for VI undo command */
234 UndoAction = TCSHOP_INSERT;
236 UndoPtr = Cursor - num;
237 for (cp = Cursor - num; cp <= LastChar; cp++) {
243 for (cp = Cursor - num; cp + num <= LastChar; cp++)
247 /* Mark was within the range of the deleted word? */
248 if (Mark && Mark > Cursor && Mark <= Cursor+num)
250 /* Mark after the deleted word? */
251 else if (Mark && Mark > Cursor)
257 c_preword(Char *p, Char *low, int n, Char *delim)
263 while (prev < p) { /* Skip initial non-word chars */
264 if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\')
273 new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */
274 new++; /* Step away from end of word */
275 while (new <= p) { /* Skip trailing non-word chars */
276 if (!Strchr(delim, *new) || *(new-1) == (Char)'\\')
282 p = prev; /* Set to previous word start */
291 * c_to_class() returns the class of the given character.
293 * This is used to make the c_prev_word() and c_next_word() functions
294 * work like vi's, which classify characters. A word is a sequence of
295 * characters belonging to the same class, classes being defined as
299 * 2/ alphanumeric chars, + underscore
306 return C_CLASS_WHITE;
308 if (Isdigit(ch) || Isalpha(ch) || ch == '_')
309 return C_CLASS_ALNUM;
311 return C_CLASS_OTHER;
315 c_prev_word(Char *p, Char *low, int n)
321 while ((p >= low) && !isword(*p))
323 while ((p >= low) && isword(*p))
327 /* cp now points to one character before the word */
331 /* cp now points where we want it */
341 /* scan until beginning of current word (may be all whitespace!) */
342 c_class = c_to_class(*p);
343 while ((p >= low) && c_class == c_to_class(*p))
346 /* if this was a non_whitespace word, we're ready */
347 if (c_class != C_CLASS_WHITE)
350 /* otherwise, move back to beginning of the word just found */
351 c_class = c_to_class(*p);
352 while ((p >= low) && c_class == c_to_class(*p))
356 p++; /* correct overshoot */
362 c_next_word(Char *p, Char *high, int n)
366 while ((p < high) && !isword(*p))
368 while ((p < high) && isword(*p))
373 /* p now points where we want it */
383 /* scan until end of current word (may be all whitespace!) */
384 c_class = c_to_class(*p);
385 while ((p < high) && c_class == c_to_class(*p))
388 /* if this was all whitespace, we're ready */
389 if (c_class == C_CLASS_WHITE)
392 /* if we've found white-space at the end of the word, skip it */
393 while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
397 p--; /* correct overshoot */
403 c_nexword(Char *p, Char *high, int n)
406 while ((p < high) && !Isspace(*p))
408 while ((p < high) && Isspace(*p))
414 /* p now points where we want it */
419 * Expand-History (originally "Magic-Space") code added by
420 * Ray Moody <ray@gibbs.physics.purdue.edu>
421 * this is a neat, but odd, addition.
425 * c_number: Ignore character p points to, return number appearing after that.
426 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
427 * Return p pointing to last char used.
431 * dval is the number to subtract from for things like $-3
435 c_number(Char *p, int *num, int dval)
446 *num = INT_MAX; /* Handle $ */
449 sign = -1; /* Handle $- */
452 for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
454 *num = (sign < 0 ? dval - i : i);
459 * excl_expand: There is an excl to be expanded to p -- do the right thing
460 * with it and return a version of p advanced over the expanded stuff. Also,
461 * update tsh_cur and related things as appropriate...
468 struct Hist *h = Histlist.Hnext;
470 int i, from, to, dval;
482 switch (*(q = p + 1)) {
485 buf = expand_lex(&h->Hlex, 1, 1);
489 if ((l = (h->Hlex).prev) != 0)
490 buf = expand_lex(l->prev->prev, 0, 0);
494 buf = expand_lex(&h->Hlex, 1, INT_MAX);
498 if (been_once) { /* unknown argument */
499 /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
500 buf = expand_lex(&h->Hlex, 0, INT_MAX);
506 if (*q == ':') /* short form: !:arg */
511 * Search for a space, tab, or colon. See if we have a number (as
512 * in !1234:xyz). Remember the number.
514 for (i = 0, all_dig = 1;
515 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
517 * PWP: !-4 is a valid history argument too, therefore the test
518 * is if not a digit, or not a - as the first character.
520 if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
523 all_dig = 2;/* we are sneeky about this */
525 i = 10 * i + *q - '0';
530 * If we have a number, search for event i. Otherwise, search for
531 * a named event (as in !foo). (In this case, I is the length of
536 i = -i; /* make it negitive */
537 if (i < 0) /* if !-4 (for example) */
538 i = eventno + 1 + i; /* remember: i is < 0 */
539 for (; h; h = h->Hnext) {
545 for (i = (int) (q - p); h; h = h->Hnext) {
546 if ((l = &h->Hlex) != 0) {
547 if (!Strncmp(p + 1, l->next->word, (size_t) i))
555 if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
556 q[1] == '$' || q[1] == '^') { /* get some args */
557 p = q[1] == ':' ? ++q : q;
561 if ((q[1] < '0' || q[1] > '9') &&
562 q[1] != '-' && q[1] != '$' && q[1] != '^')
567 if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
570 * Count up the number of words in this event. Store it in dval.
571 * Dval will be fed to number.
574 if ((l = h->Hlex.prev) != 0) {
575 for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
583 q = c_number(q, &from, dval);
586 if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
589 q = c_number(q, &to, dval);
591 else if (q[1] == '*') {
598 if (from < 0 || to < from)
600 buf = expand_lex(&h->Hlex, from, to);
602 else /* get whole cmd */
603 buf = expand_lex(&h->Hlex, 0, INT_MAX);
610 * Apply modifiers, if any.
614 while (q[1] == ':' && modbuf != NULL) {
624 if ((modbuf = domod(buf, (int) q[2])) != NULL) {
633 /* Not implemented; this needs to be done before expanding
634 * lex. We don't have the words available to us anymore.
656 buf_len = Strlen(buf);
658 * Now replace the text from op to q inclusive with the text from buf.
663 * Now replace text non-inclusively like a real CS major!
665 if (LastChar + buf_len - (q - op) >= InputLim)
667 (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
668 LastChar += buf_len - (q - op);
669 Cursor += buf_len - (q - op);
670 (void) memcpy(op, buf, buf_len * sizeof(Char));
681 * c_excl: An excl has been found at point p -- back up and find some white
682 * space (or the beginning of the buffer) and properly expand all the excl's
683 * from there up to the current cursor position. We also avoid (trying to)
685 * Returns number of expansions attempted (doesn't matter whether they succeeded
697 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
698 * back p up to just before the current word.
700 if ((p[1] == ' ' || p[1] == '\t') &&
701 (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
702 for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
708 while (*p != ' ' && *p != '\t' && p > InputBuf)
713 * Forever: Look for history char. (Stop looking when we find the cursor.)
714 * Count backslashes. If odd, skip history char. Expand if even number of
719 while (*p != HIST && p < Cursor)
721 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
725 if (p >= Cursor) /* all done */
744 * Start p out one character before the cursor. Move it backwards looking
745 * for white space, the beginning of the line, or a history character.
748 p > InputBuf && *p != ' ' && *p != '\t' && *p != HIST; --p)
752 * If we found a history character, go expand it.
764 c_delfini(void) /* Finish up delete action */
768 if (ActionFlag & TCSHOP_INSERT)
769 c_alternativ_key_map(0);
771 ActionFlag = TCSHOP_NOP;
776 UndoAction = TCSHOP_INSERT;
778 if (Cursor > ActionPos) {
779 Size = (int) (Cursor-ActionPos);
783 else if (Cursor < ActionPos) {
784 Size = (int)(ActionPos-Cursor);
796 c_endword(Char *p, Char *high, int n, Char *delim)
802 while (p < high) { /* Skip non-word chars */
803 if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
807 while (p < high) { /* Skip string */
808 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
809 if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
810 if (inquote == 0) inquote = *p;
811 else if (inquote == *p) inquote = 0;
814 /* Break if unquoted non-word char */
815 if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
827 c_eword(Char *p, Char *high, int n)
832 while ((p < high) && Isspace(*p))
836 while ((p < high) && Isalnum(*p))
839 while ((p < high) && !(Isspace(*p) || Isalnum(*p)))
847 /* Set the max length of the kill ring */
855 max = 1; /* no ring, but always one buffer */
856 if (max == KillRingMax)
858 new = xcalloc(max, sizeof(CStr));
859 if (KillRing != NULL) {
860 if (KillRingLen != 0) {
861 if (max >= KillRingLen) {
866 j = (KillPos - count + KillRingLen) % KillRingLen;
868 for (i = 0; i < KillRingLen; i++) {
869 if (i < count) /* copy latest */
870 new[i] = KillRing[j];
871 else /* free the others */
872 xfree(KillRing[j].buf);
873 j = (j + 1) % KillRingLen;
876 KillPos = count % max;
885 /* Push string from start upto (but not including) end onto kill ring */
887 c_push_kill(Char *start, Char *end)
891 int len = end - start, i, j, k;
893 /* Check for duplicates? */
894 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
895 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
896 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
898 for (i = 0; i < KillRingLen; i++) {
899 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
900 KillRing[j].buf[len] == '\0') {
902 for ( ; i > 0; i--) {
904 j = (j + 1) % KillRingLen;
905 KillRing[k] = KillRing[j];
910 j = (j - 1 + KillRingLen) % KillRingLen;
912 } else if (eq(dp, STRall)) { /* skip if any earlier */
913 for (i = 0; i < KillRingLen; i++)
914 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
915 KillRing[i].buf[len] == '\0')
917 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
919 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
920 KillRing[j].buf[len] == '\0')
925 /* No duplicate, go ahead and push */
926 len++; /* need space for '\0' */
928 if (KillRingLen < KillRingMax)
930 pos = &KillRing[KillPos];
931 KillPos = (KillPos + 1) % KillRingMax;
932 if (pos->len < len) {
933 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
943 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
948 Strbuf_append(&SavedBuf, InputBuf);
949 Strbuf_terminate(&SavedBuf);
950 LastSaved = LastChar - InputBuf;
951 CursSaved = Cursor - InputBuf;
952 HistSaved = Hist_num;
962 if (Hist_num == 0) { /* if really the current line */
963 if (HistBuf.s != NULL)
964 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
967 LastChar = InputBuf + HistBuf.len;
983 for (h = 1; h < Hist_num; h++) {
984 if ((hp->Hnext) == NULL) {
991 if (HistLit && hp->histline) {
992 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
998 p = sprlex(&hp->Hlex);
999 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1003 LastChar = Strend(InputBuf);
1005 if (LastChar > InputBuf) {
1006 if (LastChar[-1] == '\n')
1009 if (LastChar[-1] == ' ')
1012 if (LastChar < InputBuf)
1013 LastChar = InputBuf;
1027 c_search_line(Char *pattern, int dir)
1032 len = Strlen(pattern);
1034 if (dir == F_UP_SEARCH_HIST) {
1035 for (cp = Cursor; cp >= InputBuf; cp--)
1036 if (Strncmp(cp, pattern, len) == 0 ||
1037 Gmatch(cp, pattern)) {
1043 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1044 if (Strncmp(cp, pattern, len) == 0 ||
1045 Gmatch(cp, pattern)) {
1054 e_inc_search(int dir)
1056 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1057 STRbck[] = { 'b', 'c', 'k', '\0' };
1058 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1059 static Char endcmd[2];
1062 *oldCursor = Cursor,
1064 CCRETVAL ret = CC_NORM;
1065 int oldHist_num = Hist_num,
1066 oldpatlen = patbuf.len,
1070 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1075 if (patbuf.len == 0) { /* first round */
1077 Strbuf_append1(&patbuf, '*');
1081 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1082 *cp; *LastChar++ = *cp++)
1084 *LastChar++ = pchar;
1085 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1086 *LastChar++ = *cp++)
1089 if (adrof(STRhighlight) && pchar == ':') {
1090 /* if the no-glob-search patch is applied, remove the - 1 below */
1091 IncMatchLen = patbuf.len - 1;
1097 if (GetNextChar(&ch) != 1)
1098 return(e_send_eof(0));
1100 switch (ch > NT_NUM_KEYS
1101 ? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
1105 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1108 Strbuf_append1(&patbuf, ch);
1116 newdir = F_DOWN_SEARCH_HIST;
1121 newdir = F_UP_SEARCH_HIST;
1134 case 0007: /* ^G: Abort */
1139 case 0027: /* ^W: Append word */
1140 /* No can do if globbing characters in pattern */
1141 for (cp = &patbuf.s[1]; ; cp++)
1142 if (cp >= &patbuf.s[patbuf.len]) {
1143 Cursor += patbuf.len - 1;
1144 cp = c_next_word(Cursor, LastChar, 1);
1145 while (Cursor < cp && *Cursor != '\n') {
1146 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1150 Strbuf_append1(&patbuf, *Cursor);
1151 *LastChar++ = *Cursor++;
1157 } else if (isglob(*cp)) {
1163 default: /* Terminate and execute cmd */
1168 case 0033: /* ESC: Terminate */
1176 while (LastChar > InputBuf && *LastChar != '\n')
1182 /* Can't search if unmatched '[' */
1183 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1184 if (*cp == '[' || *cp == ']') {
1189 if (patbuf.len > 1 && ch != '[') {
1190 if (redo && newdir == dir) {
1191 if (pchar == '?') { /* wrap around */
1192 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1193 if (GetHistLine() == CC_ERROR)
1194 /* Hist_num was fixed by first call */
1195 (void) GetHistLine();
1196 Cursor = newdir == F_UP_SEARCH_HIST ?
1197 LastChar : InputBuf;
1199 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1201 Strbuf_append1(&patbuf, '*');
1202 Strbuf_terminate(&patbuf);
1203 if (Cursor < InputBuf || Cursor > LastChar ||
1204 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1205 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1206 ret = newdir == F_UP_SEARCH_HIST ?
1207 e_up_search_hist(0) : e_down_search_hist(0);
1208 if (ret != CC_ERROR) {
1209 Cursor = newdir == F_UP_SEARCH_HIST ?
1210 LastChar : InputBuf;
1211 (void) c_search_line(&patbuf.s[1], newdir);
1214 patbuf.s[--patbuf.len] = '\0';
1215 if (ret == CC_ERROR) {
1217 if (Hist_num != oldHist_num) {
1218 Hist_num = oldHist_num;
1219 if (GetHistLine() == CC_ERROR)
1229 ret = e_inc_search(newdir);
1231 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1232 /* break abort of failed search at last non-failed */
1238 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1239 /* restore on normal return or error exit */
1241 patbuf.len = oldpatlen;
1242 if (Hist_num != oldHist_num) {
1243 Hist_num = oldHist_num;
1244 if (GetHistLine() == CC_ERROR)
1248 if (ret == CC_ERROR)
1251 if (done || ret != CC_NORM)
1261 struct Strbuf tmpbuf = Strbuf_INIT;
1266 cleanup_push(&tmpbuf, Strbuf_cleanup);
1267 oldbuf = Strsave(InputBuf);
1268 cleanup_push(oldbuf, xfree);
1271 Strbuf_append1(&tmpbuf, '*');
1274 LastChar = InputBuf;
1278 c_insert(2); /* prompt + '\n' */
1280 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1282 for (ch = 0;ch == 0;) {
1283 if (GetNextChar(&ch) != 1) {
1284 cleanup_until(&tmpbuf);
1285 return(e_send_eof(0));
1288 case 0010: /* Delete and backspace */
1290 if (tmpbuf.len > 1) {
1296 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1299 cleanup_until(&tmpbuf);
1306 case 0033: /* ESC */
1308 case '\r': /* Newline */
1311 case '\012': /* ASCII Line feed */
1312 case '\015': /* ASCII (or EBCDIC) Return */
1317 Strbuf_append1(&tmpbuf, ch);
1325 cleanup_until(oldbuf);
1327 if (tmpbuf.len == 1) {
1329 * Use the old pattern, but wild-card it.
1331 if (patbuf.len == 0) {
1333 LastChar = InputBuf;
1336 cleanup_until(&tmpbuf);
1339 if (patbuf.s[0] != '*') {
1340 oldbuf = Strsave(patbuf.s);
1342 Strbuf_append1(&patbuf, '*');
1343 Strbuf_append(&patbuf, oldbuf);
1345 Strbuf_append1(&patbuf, '*');
1346 Strbuf_terminate(&patbuf);
1350 Strbuf_append1(&tmpbuf, '*');
1351 Strbuf_terminate(&tmpbuf);
1353 Strbuf_append(&patbuf, tmpbuf.s);
1354 Strbuf_terminate(&patbuf);
1356 cleanup_until(&tmpbuf);
1357 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1358 Cursor = LastChar = InputBuf;
1359 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1360 e_down_search_hist(0)) == CC_ERROR) {
1365 if (ASC(ch) == 0033) {
1378 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1379 * entry point, called from the CcKeyMap indirected into the
1389 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1392 if (UndoPtr > Cursor)
1393 UndoSize = (int)(UndoPtr - Cursor);
1395 UndoSize = (int)(Cursor - UndoPtr);
1397 inputmode = MODE_INSERT;
1398 c_alternativ_key_map(1);
1401 * We don't want to move the cursor, because all the editing
1402 * commands don't include the character under the cursor.
1404 if (Cursor > InputBuf)
1413 e_unassigned(Char c)
1414 { /* bound to keys that arn't really assigned */
1423 e_insert_str(Char *c)
1428 if (LastChar + Argument * n >= InputLim)
1429 return(CC_ERROR); /* end of buffer space */
1430 if (inputmode != MODE_INSERT) {
1431 c_delafter(Argument * Strlen(c));
1433 c_insert(Argument * n);
1434 while (Argument--) {
1435 for (i = 0; i < n; i++)
1446 #ifndef SHORT_STRINGS
1447 c &= ASCII; /* no meta chars ever */
1451 return(CC_ERROR); /* no NULs in the input ever!! */
1453 if (LastChar + Argument >= InputLim)
1454 return(CC_ERROR); /* end of buffer space */
1456 if (Argument == 1) { /* How was this optimized ???? */
1458 if (inputmode != MODE_INSERT) {
1459 UndoBuf[UndoSize++] = *Cursor;
1460 UndoBuf[UndoSize] = '\0';
1461 c_delafter(1); /* Do NOT use the saving ONE */
1465 *Cursor++ = (Char) c;
1466 DoingArg = 0; /* just in case */
1467 RefPlusOne(1); /* fast refresh for one char. */
1470 if (inputmode != MODE_INSERT) {
1472 for(i = 0; i < Argument; i++)
1473 UndoBuf[UndoSize++] = *(Cursor + i);
1475 UndoBuf[UndoSize] = '\0';
1476 c_delafter(Argument); /* Do NOT use the saving ONE */
1482 *Cursor++ = (Char) c;
1486 if (inputmode == MODE_REPLACE_1)
1487 (void) v_cmd_mode(0);
1493 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1497 if ((len = (int) Strlen(s)) <= 0)
1499 if (LastChar + len >= InputLim)
1500 return -1; /* end of buffer space */
1509 DeleteBack(int n) /* delete the n characters before . */
1513 if (Cursor >= &InputBuf[n]) {
1514 c_delbefore(n); /* delete before dot */
1519 e_digit(Char c) /* gray magic here */
1522 return(CC_ERROR); /* no NULs in the input ever!! */
1524 if (DoingArg) { /* if doing an arg, add this in... */
1525 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1528 if (Argument > 1000000)
1530 Argument = (Argument * 10) + (c - '0');
1535 if (LastChar + 1 >= InputLim)
1536 return CC_ERROR; /* end of buffer space */
1538 if (inputmode != MODE_INSERT) {
1539 UndoBuf[UndoSize++] = *Cursor;
1540 UndoBuf[UndoSize] = '\0';
1541 c_delafter(1); /* Do NOT use the saving ONE */
1544 *Cursor++ = (Char) c;
1545 DoingArg = 0; /* just in case */
1546 RefPlusOne(1); /* fast refresh for one char. */
1552 e_argdigit(Char c) /* for ESC-n */
1557 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1561 return(CC_ERROR); /* no NULs in the input ever!! */
1563 if (DoingArg) { /* if doing an arg, add this in... */
1564 if (Argument > 1000000)
1566 Argument = (Argument * 10) + (c - '0');
1568 else { /* else starting an argument */
1576 v_zero(Char c) /* command mode 0 for vi */
1578 if (DoingArg) { /* if doing an arg, add this in... */
1579 if (Argument > 1000000)
1581 Argument = (Argument * 10) + (c - '0');
1584 else { /* else starting an argument */
1586 if (ActionFlag & TCSHOP_DELETE) {
1590 RefCursor(); /* move the cursor */
1598 { /* always ignore argument */
1600 if (adrof(STRhighlight) && MarkIsSet) {
1608 /* PastBottom(); NOW done in ed.inputl.c */
1609 *LastChar++ = '\n'; /* for the benefit of CSH */
1610 *LastChar = '\0'; /* just in case */
1612 InsertPos = InputBuf; /* Reset editing position */
1618 e_newline_hold(Char c)
1623 *LastChar++ = '\n'; /* for the benefit of CSH */
1624 *LastChar = '\0'; /* just in case */
1630 e_newline_down_hist(Char c)
1634 HistSaved = Hist_num;
1636 *LastChar++ = '\n'; /* for the benefit of CSH */
1637 *LastChar = '\0'; /* just in case */
1644 { /* for when ^D is ONLY send-eof */
1647 *LastChar = '\0'; /* just in case */
1656 *LastChar = '\0'; /* just in case */
1657 return(CC_COMPLETE);
1662 e_complete_back(Char c)
1665 *LastChar = '\0'; /* just in case */
1666 return(CC_COMPLETE_BACK);
1671 e_complete_fwd(Char c)
1674 *LastChar = '\0'; /* just in case */
1675 return(CC_COMPLETE_FWD);
1680 e_complete_all(Char c)
1683 *LastChar = '\0'; /* just in case */
1684 return(CC_COMPLETE_ALL);
1689 v_cm_complete(Char c)
1692 if (Cursor < LastChar)
1694 *LastChar = '\0'; /* just in case */
1695 return(CC_COMPLETE);
1700 e_toggle_hist(Char c)
1706 *LastChar = '\0'; /* just in case */
1708 if (Hist_num <= 0) {
1712 hp = Histlist.Hnext;
1713 if (hp == NULL) { /* this is only if no history */
1717 for (h = 1; h < Hist_num; h++)
1720 if (!CurrentHistLit) {
1722 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1732 p = sprlex(&hp->Hlex);
1733 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1738 LastChar = Strend(InputBuf);
1739 if (LastChar > InputBuf) {
1740 if (LastChar[-1] == '\n')
1742 if (LastChar[-1] == ' ')
1744 if (LastChar < InputBuf)
1745 LastChar = InputBuf;
1765 UndoAction = TCSHOP_NOP;
1766 *LastChar = '\0'; /* just in case */
1768 if (Hist_num == 0) { /* save the current buffer away */
1770 Strbuf_append(&HistBuf, InputBuf);
1771 Strbuf_terminate(&HistBuf);
1774 Hist_num += Argument;
1776 if (GetHistLine() == CC_ERROR) {
1778 (void) GetHistLine(); /* Hist_num was fixed by first call */
1785 return(CC_NORM); /* was CC_UP_HIST */
1793 UndoAction = TCSHOP_NOP;
1794 *LastChar = '\0'; /* just in case */
1796 Hist_num -= Argument;
1800 return(CC_ERROR); /* make it beep */
1803 return(GetHistLine());
1809 * c_hmatch() return True if the pattern matches the prefix
1814 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1816 return Gmatch(str, patbuf.s);
1820 * c_hsetpat(): Set the history seatch pattern
1825 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1827 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1828 Strbuf_terminate(&patbuf);
1831 xprintf("\nHist_num = %d\n", Hist_num);
1832 xprintf("patlen = %d\n", (int)patbuf.len);
1833 xprintf("patbuf = \"%S\"\n", patbuf.s);
1834 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1840 e_up_search_hist(Char c)
1847 ActionFlag = TCSHOP_NOP;
1848 UndoAction = TCSHOP_NOP;
1849 *LastChar = '\0'; /* just in case */
1852 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1858 if (Hist_num == 0) {
1860 Strbuf_append(&HistBuf, InputBuf);
1861 Strbuf_terminate(&HistBuf);
1865 hp = Histlist.Hnext;
1869 c_hsetpat(); /* Set search pattern !! */
1871 for (h = 1; h <= Hist_num; h++)
1874 while (hp != NULL) {
1878 if (hp->histline == NULL)
1879 hp->histline = sprlex(&hp->Hlex);
1883 hl = sprlex(&hp->Hlex);
1884 cleanup_push(hl, xfree);
1887 xprintf("Comparing with \"%S\"\n", hl);
1889 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1890 hl[LastChar-InputBuf]) && c_hmatch(hl);
1903 xprintf("not found\n");
1910 return(GetHistLine());
1915 e_down_search_hist(Char c)
1922 ActionFlag = TCSHOP_NOP;
1923 UndoAction = TCSHOP_NOP;
1924 *LastChar = '\0'; /* just in case */
1929 hp = Histlist.Hnext;
1933 c_hsetpat(); /* Set search pattern !! */
1935 for (h = 1; h < Hist_num && hp; h++) {
1937 if (hp->histline == NULL)
1938 hp->histline = sprlex(&hp->Hlex);
1942 hl = sprlex(&hp->Hlex);
1943 cleanup_push(hl, xfree);
1946 xprintf("Comparing with \"%S\"\n", hl);
1948 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1949 hl[LastChar-InputBuf]) && c_hmatch(hl))
1956 if (!found) { /* is it the current history number? */
1957 if (!c_hmatch(HistBuf.s)) {
1959 xprintf("not found\n");
1967 return(GetHistLine());
1976 *LastChar = '\0'; /* just in case */
1985 *LastChar = '\0'; /* just in case */
1994 *LastChar = '\0'; /* just in case */
1995 return(CC_CORRECT_L);
2000 e_run_fg_editor(Char c)
2005 if ((pp = find_stop_ed()) != NULL) {
2006 /* save our editor state so we can restore it */
2008 Hist_num = 0; /* for the history commands */
2010 /* put the tty in a sane mode */
2012 (void) Cookedmode(); /* make sure the tty is set up correctly */
2017 (void) Rawmode(); /* go on */
2027 e_list_choices(Char c)
2031 *LastChar = '\0'; /* just in case */
2032 return(CC_LIST_CHOICES);
2041 *LastChar = '\0'; /* just in case */
2042 return(CC_LIST_ALL);
2051 *LastChar = '\0'; /* just in case */
2052 return(CC_LIST_GLOB);
2057 e_expand_glob(Char c)
2060 *LastChar = '\0'; /* just in case */
2061 return(CC_EXPAND_GLOB);
2066 e_normalize_path(Char c)
2069 *LastChar = '\0'; /* just in case */
2070 return(CC_NORMALIZE_PATH);
2075 e_normalize_command(Char c)
2078 *LastChar = '\0'; /* just in case */
2079 return(CC_NORMALIZE_COMMAND);
2084 e_expand_vars(Char c)
2087 *LastChar = '\0'; /* just in case */
2088 return(CC_EXPAND_VARS);
2094 { /* do a fast command line which(1) */
2097 Hist_num = 0; /* for the history commands */
2099 *LastChar = '\0'; /* just in case */
2106 { /* insert the last element of the prev. cmd */
2108 struct wordent *wp, *firstp;
2116 hp = Histlist.Hnext;
2117 if (hp == NULL) { /* this is only if no history */
2121 wp = (hp->Hlex).prev;
2123 if (wp->prev == (struct wordent *) NULL)
2124 return(CC_ERROR); /* an empty history entry */
2126 firstp = (hp->Hlex).next;
2128 /* back up arg words in lex */
2129 for (i = 0; i < Argument && wp != firstp; i++) {
2133 expanded = expand_lex(wp->prev, 0, i - 1);
2134 if (InsertStr(expanded)) {
2145 e_dabbrev_expand(Char c)
2146 { /* expand to preceding word matching prefix */
2147 Char *cp, *ncp, *bp;
2153 static int oldevent, hist, word;
2154 static Char *start, *oldcursor;
2160 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2161 if (cp == Cursor || Isspace(*cp))
2165 hp = Histlist.Hnext;
2167 if (Argument == 1 && eventno == oldevent && cp == start &&
2168 Cursor == oldcursor && patbuf.len > 0
2169 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2170 /* continue previous search - go to last match (hist/word) */
2171 if (hist != 0) { /* need to move up history */
2172 for (i = 1; i < hist && hp != NULL; i++)
2174 if (hp == NULL) /* "can't happen" */
2176 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2181 cp = c_preword(cp, bp, word, STRshwordsep);
2182 } else { /* starting new search */
2186 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2192 ncp = c_preword(cp, bp, 1, STRshwordsep);
2193 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2198 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2205 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2208 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2209 /* We don't fully check distinct matches as Gnuemacs does: */
2210 if (Argument > 1) { /* just count matches */
2211 if (++arg >= Argument)
2213 } else { /* match if distinct from previous */
2214 if (len != (size_t)(Cursor - start)
2215 || Strncmp(cp, start, len) != 0)
2221 if (LastChar + len - (Cursor - start) >= InputLim)
2222 goto err_hbuf; /* no room */
2223 DeleteBack(Cursor - start);
2239 { /* almost like GnuEmacs */
2244 if (KillRingLen == 0) /* nothing killed */
2246 len = Strlen(KillRing[YankPos].buf);
2247 if (LastChar + len >= InputLim)
2248 return(CC_ERROR); /* end of buffer space */
2251 cp = Cursor; /* for speed */
2253 c_insert(len); /* open the space, */
2254 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2257 if (Argument == 1) { /* if no arg */
2258 Mark = Cursor; /* mark at beginning, cursor at end */
2261 Mark = cp; /* else cursor at beginning, mark at end */
2264 if (adrof(STRhighlight) && MarkIsSet) {
2275 { /* almost like GnuEmacs */
2276 int m_bef_c, del_len, ins_len;
2282 /* XXX This "should" be here, but doesn't work, since LastCmd
2283 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2284 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2285 second one will "succeed" even if the first one wasn't preceded
2286 by a yank, and giving an argument is impossible. Now we "succeed"
2287 regardless of previous command, which is wrong too of course. */
2288 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2292 if (KillRingLen == 0) /* nothing killed */
2294 YankPos -= Argument;
2296 YankPos += KillRingLen;
2297 YankPos %= KillRingLen;
2299 if (Cursor > Mark) {
2300 del_len = Cursor - Mark;
2303 del_len = Mark - Cursor;
2306 ins_len = Strlen(KillRing[YankPos].buf);
2307 if (LastChar + ins_len - del_len >= InputLim)
2308 return(CC_ERROR); /* end of buffer space */
2311 c_delbefore(del_len);
2313 c_delafter(del_len);
2315 cp = Cursor; /* for speed */
2317 c_insert(ins_len); /* open the space, */
2318 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2322 Mark = Cursor; /* mark at beginning, cursor at end */
2325 Mark = cp; /* else cursor at beginning, mark at end */
2328 if (adrof(STRhighlight) && MarkIsSet) {
2338 v_delprev(Char c) /* Backspace key in insert mode */
2345 if (InsertPos != 0) {
2346 if (Argument <= Cursor - InsertPos) {
2347 c_delbefore(Argument); /* delete before */
2359 if (Cursor > InputBuf) {
2360 c_delbefore(Argument); /* delete before dot */
2370 e_delwordprev(Char c)
2375 if (Cursor == InputBuf)
2379 cp = c_prev_word(Cursor, InputBuf, Argument);
2381 c_push_kill(cp, Cursor); /* save the text */
2383 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2387 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2389 * Changed the names of some of the ^D family of editor functions to
2390 * correspond to what they actually do and created new e_delnext_list
2393 * Old names: New names:
2395 * delete-char delete-char-or-eof
2396 * F_DELNEXT F_DELNEXT_EOF
2397 * e_delnext e_delnext_eof
2398 * edelnxt edelnxteof
2399 * delete-char-or-eof delete-char
2400 * F_DELNEXT_EOF F_DELNEXT
2401 * e_delnext_eof e_delnext
2402 * edelnxteof edelnxt
2403 * delete-char-or-list delete-char-or-list-or-eof
2404 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2405 * e_list_delnext e_delnext_list_eof
2407 * (no old equivalent) delete-char-or-list
2413 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2414 /* rename e_delnext() -> e_delnext_eof() */
2420 if (Cursor == LastChar) {/* if I'm at the end */
2425 if (Cursor != InputBuf)
2431 c_delafter(Argument); /* delete after dot */
2432 if (Cursor > LastChar)
2433 Cursor = LastChar; /* bounds check */
2440 e_delnext_eof(Char c)
2443 if (Cursor == LastChar) {/* if I'm at the end */
2445 if (Cursor == InputBuf) {
2446 /* if I'm also at the beginning */
2447 so_write(STReof, 4);/* then do a EOF */
2455 if (Cursor != InputBuf)
2461 c_delafter(Argument); /* delete after dot */
2462 if (Cursor > LastChar)
2463 Cursor = LastChar; /* bounds check */
2469 e_delnext_list(Char c)
2472 if (Cursor == LastChar) { /* if I'm at the end */
2474 *LastChar = '\0'; /* just in case */
2475 return(CC_LIST_CHOICES);
2478 c_delafter(Argument); /* delete after dot */
2479 if (Cursor > LastChar)
2480 Cursor = LastChar; /* bounds check */
2487 e_delnext_list_eof(Char c)
2490 if (Cursor == LastChar) { /* if I'm at the end */
2491 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2492 so_write(STReof, 4);/* then do a EOF */
2498 *LastChar = '\0'; /* just in case */
2499 return(CC_LIST_CHOICES);
2503 c_delafter(Argument); /* delete after dot */
2504 if (Cursor > LastChar)
2505 Cursor = LastChar; /* bounds check */
2517 if (Cursor == LastChar && Cursor == InputBuf) {
2518 so_write(STReof, 4); /* then do a EOF */
2524 *LastChar = '\0'; /* just in case */
2525 rv = CC_LIST_CHOICES;
2532 e_delwordnext(Char c)
2537 if (Cursor == LastChar)
2541 cp = c_next_word(Cursor, LastChar, Argument);
2543 c_push_kill(Cursor, cp); /* save the text */
2545 c_delafter((int)(cp - Cursor)); /* delete after dot */
2546 if (Cursor > LastChar)
2547 Cursor = LastChar; /* bounds check */
2558 if (ActionFlag & TCSHOP_DELETE) {
2562 RefCursor(); /* move the cursor */
2574 while (Isspace(*Cursor)) /* We want FIRST non space character */
2576 if (ActionFlag & TCSHOP_DELETE) {
2582 RefCursor(); /* move the cursor */
2591 c_push_kill(Cursor, LastChar); /* copy it */
2592 LastChar = Cursor; /* zap! -- delete to end */
2605 c_push_kill(InputBuf, Cursor); /* copy it */
2606 c_delbefore((int)(Cursor - InputBuf));
2607 if (Mark && Mark > Cursor)
2608 Mark -= Cursor-InputBuf;
2617 c_push_kill(InputBuf, LastChar); /* copy it */
2618 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2625 e_killregion(Char c)
2631 if (Mark > Cursor) {
2632 c_push_kill(Cursor, Mark); /* copy it */
2633 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2636 else { /* mark is before cursor */
2637 c_push_kill(Mark, Cursor); /* copy it */
2638 c_delbefore((int)(Cursor - Mark));
2640 if (adrof(STRhighlight) && MarkIsSet) {
2650 e_copyregion(Char c)
2656 if (Mark > Cursor) {
2657 c_push_kill(Cursor, Mark); /* copy it */
2659 else { /* mark is before cursor */
2660 c_push_kill(Mark, Cursor); /* copy it */
2662 return(CC_NORM); /* don't even need to Refresh() */
2667 e_charswitch(Char cc)
2673 /* do nothing if we are at beginning of line or have only one char */
2674 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2678 if (Cursor < LastChar) {
2682 Cursor[-2] = Cursor[-1];
2689 e_gcharswitch(Char cc)
2690 { /* gosmacs style ^T */
2694 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2696 Cursor[-2] = Cursor[-1];
2710 if (Cursor > InputBuf) {
2711 if (Argument > Cursor - InputBuf)
2717 if (ActionFlag & TCSHOP_DELETE) {
2735 if (Cursor == InputBuf)
2739 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2741 if (ActionFlag & TCSHOP_DELETE) {
2755 if (Cursor == InputBuf)
2759 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2762 if (ActionFlag & TCSHOP_DELETE) {
2776 if (Cursor < LastChar) {
2778 if (Cursor > LastChar)
2782 if (ActionFlag & TCSHOP_DELETE) {
2800 if (Cursor == LastChar)
2804 Cursor = c_next_word(Cursor, LastChar, Argument);
2807 if (ActionFlag & TCSHOP_DELETE) {
2821 if (Cursor == LastChar)
2825 Cursor = c_nexword(Cursor, LastChar, Argument);
2828 if (ActionFlag & TCSHOP_DELETE) {
2839 v_wordbegnext(Char c)
2842 if (Cursor == LastChar)
2846 Cursor = c_next_word(Cursor, LastChar, Argument);
2847 if (Cursor < LastChar)
2851 if (ActionFlag & TCSHOP_DELETE) {
2862 v_repeat_srch(int c)
2864 CCRETVAL rv = CC_ERROR;
2866 xprintf("dir %d patlen %d patbuf %S\n",
2867 c, (int)patbuf.len, patbuf.s);
2870 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2871 LastChar = InputBuf;
2873 case F_DOWN_SEARCH_HIST:
2874 rv = e_down_search_hist(0);
2876 case F_UP_SEARCH_HIST:
2877 rv = e_up_search_hist(0);
2886 v_csearch_back(Char ch, int count, int tflag)
2894 while (cp > InputBuf && *cp != ch)
2898 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2901 if (*cp == ch && tflag)
2906 if (ActionFlag & TCSHOP_DELETE) {
2917 v_csearch_fwd(Char ch, int count, int tflag)
2925 while (cp < LastChar && *cp != ch)
2932 if (*cp == ch && tflag)
2937 if (ActionFlag & TCSHOP_DELETE) {
2952 if (ActionFlag == TCSHOP_DELETE) {
2953 ActionFlag = TCSHOP_NOP;
2958 for (cp = InputBuf; cp < LastChar; cp++) {
2963 UndoAction = TCSHOP_INSERT;
2965 LastChar = InputBuf;
2967 if (c & TCSHOP_INSERT)
2968 c_alternativ_key_map(0);
2973 else if (ActionFlag == TCSHOP_NOP) {
2977 return(CC_ARGHACK); /* Do NOT clear out argument */
2989 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2991 c_get_word(Char **begin, Char **end)
2996 while (Argument--) {
2997 while ((cp <= LastChar) && (isword(*cp)))
3000 while ((cp >= InputBuf) && (isword(*cp)))
3005 #endif /* COMMENT */
3014 end = c_next_word(Cursor, LastChar, Argument);
3016 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3021 if (Cursor > LastChar)
3029 e_capitolcase(Char c)
3034 end = c_next_word(Cursor, LastChar, Argument);
3037 for (; cp < end; cp++) {
3045 for (; cp < end; cp++)
3050 if (Cursor > LastChar)
3062 end = c_next_word(Cursor, LastChar, Argument);
3064 for (cp = Cursor; cp < end; cp++)
3069 if (Cursor > LastChar)
3080 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3092 e_exchange_mark(Char c)
3107 { /* multiply current argument by 4 */
3109 if (Argument > 1000000)
3117 quote_mode_cleanup(void *unused)
3132 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3133 num = GetNextChar(&ch);
3136 return e_insert(ch);
3138 return e_send_eof(0);
3147 return(CC_ARGHACK); /* preserve argument */
3153 e_extendnext(Char c)
3155 CurrentKeyMap = CcAltMap;
3156 return(CC_ARGHACK); /* preserve argument */
3164 { /* move to beginning of line and start vi
3171 UndoAction = TCSHOP_DELETE;
3173 RefCursor(); /* move the cursor */
3174 c_alternativ_key_map(0);
3181 { /* vi mode overwrite one character */
3183 c_alternativ_key_map(0);
3184 inputmode = MODE_REPLACE_1;
3185 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3194 { /* vi mode start overwriting */
3196 c_alternativ_key_map(0);
3197 inputmode = MODE_REPLACE;
3198 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3207 { /* vi mode substitute for one char */
3209 c_delafter(Argument);
3210 c_alternativ_key_map(0);
3217 { /* vi mode replace whole line */
3219 (void) e_killall(0);
3220 c_alternativ_key_map(0);
3227 { /* vi mode change to end of line */
3229 (void) e_killend(0);
3230 c_alternativ_key_map(0);
3237 { /* vi mode start inserting */
3239 c_alternativ_key_map(0);
3243 UndoAction = TCSHOP_DELETE;
3251 { /* vi mode start adding */
3253 c_alternativ_key_map(0);
3254 if (Cursor < LastChar)
3257 if (Cursor > LastChar)
3264 UndoAction = TCSHOP_DELETE;
3272 { /* vi mode to add at end of line */
3274 c_alternativ_key_map(0);
3277 InsertPos = LastChar; /* Mark where insertion begins */
3279 UndoAction = TCSHOP_DELETE;
3287 v_change_case(Char cc)
3292 if (Cursor < LastChar) {
3293 #ifndef WINNT_NATIVE
3297 #endif /* WINNT_NATIVE */
3299 *Cursor++ = Tolower(c);
3300 else if (Islower(c))
3301 *Cursor++ = Toupper(c);
3304 RefPlusOne(1); /* fast refresh for one char */
3317 for (p = InputBuf; Isspace(*p); p++)
3324 return(e_newline(0));
3330 { /* erase all of current line, start again */
3332 ResetInLine(0); /* reset the input pointers */
3351 ClearScreen(); /* clear the whole real screen */
3352 ClearDisp(); /* reset everything */
3361 #if defined(_MINIX) || defined(WINNT_NATIVE)
3362 /* SAK PATCH: erase all of current line, start again */
3363 ResetInLine(0); /* reset the input pointers */
3366 return (CC_REFRESH);
3367 #else /* !_MINIX && !WINNT_NATIVE */
3370 #endif /* _MINIX || WINNT_NATIVE */
3374 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3375 * Function to send a character back to the input stream in cooked
3376 * mode. Only works if we have TIOCSTI
3380 e_stuff_char(Char c)
3383 int was_raw = Tty_raw_mode;
3384 char buf[MB_LEN_MAX];
3388 (void) Cookedmode();
3390 (void) xwrite(SHIN, "\n", 1);
3391 len = one_wctomb(buf, c & CHAR);
3392 for (i = 0; i < len; i++)
3393 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3397 return(e_redisp(c));
3398 #else /* !TIOCSTI */
3400 #endif /* !TIOCSTI */
3408 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3423 e_tty_flusho(Char c)
3457 /* returns the number of (attempted) expansions */
3461 *LastChar = '\0'; /* just in case */
3462 return c_substitute();
3467 e_expand_history(Char c)
3470 (void)ExpandHistory();
3476 e_magic_space(Char c)
3479 *LastChar = '\0'; /* just in case */
3480 (void)c_substitute();
3481 return(e_insert(' '));
3493 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3494 if (adrof(STRhighlight) && IncMatchLen) {
3514 ret = e_inc_search(F_UP_SEARCH_HIST);
3515 if (adrof(STRhighlight) && IncMatchLen) {
3529 Char *cp, *oldc, *dp;
3532 if (Cursor == InputBuf)
3537 /* does a bounds check */
3538 cp = c_prev_word(Cursor, InputBuf, Argument);
3540 c_insert((int)(oldc - cp));
3541 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3544 Cursor = dp; /* put cursor at end */
3551 e_tty_starto(Char c)
3560 e_load_average(Char c)
3566 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3567 * there even if they don't use it. (lukem@netbsd.org)
3569 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3571 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3581 * Delete with insert == change: first we delete and then we leave in
3584 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3592 return(v_action(TCSHOP_DELETE));
3601 if (Cursor == LastChar)
3605 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3607 if (ActionFlag & TCSHOP_DELETE)
3623 if (Cursor == LastChar)
3627 Cursor = c_eword(Cursor, LastChar, Argument);
3629 if (ActionFlag & TCSHOP_DELETE) {
3646 if (GetNextChar(&ch) != 1)
3647 return e_send_eof(0);
3649 srch_dir = CHAR_FWD;
3652 return v_csearch_fwd(ch, Argument, 0);
3663 if (GetNextChar(&ch) != 1)
3664 return e_send_eof(0);
3666 srch_dir = CHAR_BACK;
3669 return v_csearch_back(ch, Argument, 0);
3674 v_charto_fwd(Char c)
3679 if (GetNextChar(&ch) != 1)
3680 return e_send_eof(0);
3682 return v_csearch_fwd(ch, Argument, 1);
3688 v_charto_back(Char c)
3693 if (GetNextChar(&ch) != 1)
3694 return e_send_eof(0);
3696 return v_csearch_back(ch, Argument, 1);
3707 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3708 v_csearch_back(srch_char, Argument, 0);
3713 v_rchar_back(Char c)
3719 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3720 v_csearch_back(srch_char, Argument, 0);
3733 switch (UndoAction) {
3734 case TCSHOP_DELETE|TCSHOP_INSERT:
3736 if (UndoSize == 0) return(CC_NORM);
3739 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3740 *kp++ = *cp++; /* into UndoBuf */
3742 for (cp = UndoPtr; cp <= LastChar; cp++)
3745 LastChar -= UndoSize;
3748 UndoAction = TCSHOP_INSERT;
3752 if (UndoSize == 0) return(CC_NORM);
3756 c_insert(UndoSize); /* open the space, */
3757 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3760 UndoAction = TCSHOP_DELETE;
3764 if (UndoSize == 0) return(CC_NORM);
3768 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3769 if (size < UndoSize)
3771 for(loop = 0; loop < size; loop++) {
3790 return v_search(F_UP_SEARCH_HIST);
3798 return v_search(F_DOWN_SEARCH_HIST);
3806 if (patbuf.len == 0) return(CC_ERROR);
3807 return(v_repeat_srch(searchdir));
3812 v_rsrch_back(Char c)
3815 if (patbuf.len == 0) return(CC_ERROR);
3816 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3817 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3820 #ifndef WINNT_NATIVE
3821 /* Since ed.defns.h is generated from ed.defns.c, these empty
3822 functions will keep the F_NUM_FNS consistent
3825 e_copy_to_clipboard(Char c)
3832 e_paste_from_clipboard(Char c)
3839 e_dosify_next(Char c)
3845 e_dosify_prev(Char c)
3862 #endif /* !WINNT_NATIVE */
3866 MoveCursor(int n) /* move cursor + right - left char */
3868 Cursor = Cursor + n;
3869 if (Cursor < InputBuf)
3871 if (Cursor > LastChar)
3885 if (p < InputBuf || p > LastChar)
3886 return 1; /* Error */