1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.103 2015/08/19 14:29:55 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.103 2015/08/19 14:29:55 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_WORD 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(), c_next_word() and c_eword() 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;
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 */
509 if (HIST != '\0' && *q != HIST) {
511 * Search for a space, tab, or colon. See if we have a number (as
512 * in !1234:xyz). Remember the number.
514 for (i = 0, all_dig = 1;
515 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
517 * PWP: !-4 is a valid history argument too, therefore the test
518 * is if not a digit, or not a - as the first character.
520 if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
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
720 while (*p != HIST && p < Cursor)
722 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
726 if (p >= Cursor) /* all done */
743 * Start p out one character before the cursor. Move it backwards looking
744 * for white space, the beginning of the line, or a history character.
747 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
751 * If we found a history character, go expand it.
753 if (p >= InputBuf && HIST != '\0' && *p == HIST)
763 c_delfini(void) /* Finish up delete action */
767 if (ActionFlag & TCSHOP_INSERT)
768 c_alternativ_key_map(0);
770 ActionFlag = TCSHOP_NOP;
775 UndoAction = TCSHOP_INSERT;
777 if (Cursor > ActionPos) {
778 Size = (int) (Cursor-ActionPos);
782 else if (Cursor < ActionPos) {
783 Size = (int)(ActionPos-Cursor);
795 c_endword(Char *p, Char *high, int n, Char *delim)
801 while (p < high) { /* Skip non-word chars */
802 if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
806 while (p < high) { /* Skip string */
807 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
808 if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
809 if (inquote == 0) inquote = *p;
810 else if (inquote == *p) inquote = 0;
813 /* Break if unquoted non-word char */
814 if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
826 c_eword(Char *p, Char *high, int n)
836 /* scan until end of current word (may be all whitespace!) */
837 c_class = c_to_class(*p);
838 while ((p < high) && c_class == c_to_class(*p))
841 /* if this was a non_whitespace word, we're ready */
842 if (c_class != C_CLASS_WHITE)
845 /* otherwise, move to the end of the word just found */
846 c_class = c_to_class(*p);
847 while ((p < high) && c_class == c_to_class(*p))
855 /* Set the max length of the kill ring */
863 max = 1; /* no ring, but always one buffer */
864 if (max == KillRingMax)
866 new = xcalloc(max, sizeof(CStr));
867 if (KillRing != NULL) {
868 if (KillRingLen != 0) {
869 if (max >= KillRingLen) {
874 j = (KillPos - count + KillRingLen) % KillRingLen;
876 for (i = 0; i < KillRingLen; i++) {
877 if (i < count) /* copy latest */
878 new[i] = KillRing[j];
879 else /* free the others */
880 xfree(KillRing[j].buf);
881 j = (j + 1) % KillRingLen;
884 KillPos = count % max;
893 /* Push string from start upto (but not including) end onto kill ring */
895 c_push_kill(Char *start, Char *end)
899 int len = end - start, i, j, k;
901 /* Check for duplicates? */
902 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
903 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
904 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
906 for (i = 0; i < KillRingLen; i++) {
907 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
908 KillRing[j].buf[len] == '\0') {
910 for ( ; i > 0; i--) {
912 j = (j + 1) % KillRingLen;
913 KillRing[k] = KillRing[j];
918 j = (j - 1 + KillRingLen) % KillRingLen;
920 } else if (eq(dp, STRall)) { /* skip if any earlier */
921 for (i = 0; i < KillRingLen; i++)
922 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
923 KillRing[i].buf[len] == '\0')
925 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
927 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
928 KillRing[j].buf[len] == '\0')
933 /* No duplicate, go ahead and push */
934 len++; /* need space for '\0' */
936 if (KillRingLen < KillRingMax)
938 pos = &KillRing[KillPos];
939 KillPos = (KillPos + 1) % KillRingMax;
940 if (pos->len < len) {
941 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
951 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
953 c_save_inputbuf(void)
956 Strbuf_append(&SavedBuf, InputBuf);
957 Strbuf_terminate(&SavedBuf);
958 LastSaved = LastChar - InputBuf;
959 CursSaved = Cursor - InputBuf;
960 HistSaved = Hist_num;
970 if (Hist_num == 0) { /* if really the current line */
971 if (HistBuf.s != NULL)
972 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
975 LastChar = InputBuf + HistBuf.len;
991 for (h = 1; h < Hist_num; h++) {
992 if ((hp->Hnext) == NULL) {
999 if (HistLit && hp->histline) {
1000 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1006 p = sprlex(&hp->Hlex);
1007 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1011 LastChar = Strend(InputBuf);
1013 if (LastChar > InputBuf) {
1014 if (LastChar[-1] == '\n')
1017 if (LastChar[-1] == ' ')
1020 if (LastChar < InputBuf)
1021 LastChar = InputBuf;
1035 c_search_line(Char *pattern, int dir)
1040 len = Strlen(pattern);
1042 if (dir == F_UP_SEARCH_HIST) {
1043 for (cp = Cursor; cp >= InputBuf; cp--)
1044 if (Strncmp(cp, pattern, len) == 0 ||
1045 Gmatch(cp, pattern)) {
1051 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1052 if (Strncmp(cp, pattern, len) == 0 ||
1053 Gmatch(cp, pattern)) {
1062 e_inc_search(int dir)
1064 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1065 STRbck[] = { 'b', 'c', 'k', '\0' };
1066 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1067 static Char endcmd[2];
1070 *oldCursor = Cursor,
1072 CCRETVAL ret = CC_NORM;
1073 int oldHist_num = Hist_num,
1074 oldpatlen = patbuf.len,
1078 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1083 if (patbuf.len == 0) { /* first round */
1085 Strbuf_append1(&patbuf, '*');
1089 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1090 *cp; *LastChar++ = *cp++)
1092 *LastChar++ = pchar;
1093 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1094 *LastChar++ = *cp++)
1097 if (adrof(STRhighlight) && pchar == ':') {
1098 /* if the no-glob-search patch is applied, remove the - 1 below */
1099 IncMatchLen = patbuf.len - 1;
1105 if (GetNextChar(&ch) != 1)
1106 return(e_send_eof(0));
1108 switch (ch > NT_NUM_KEYS
1109 ? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
1113 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1116 Strbuf_append1(&patbuf, ch);
1124 newdir = F_DOWN_SEARCH_HIST;
1129 newdir = F_UP_SEARCH_HIST;
1142 case 0007: /* ^G: Abort */
1147 case 0027: /* ^W: Append word */
1148 /* No can do if globbing characters in pattern */
1149 for (cp = &patbuf.s[1]; ; cp++)
1150 if (cp >= &patbuf.s[patbuf.len]) {
1151 Cursor += patbuf.len - 1;
1152 cp = c_next_word(Cursor, LastChar, 1);
1153 while (Cursor < cp && *Cursor != '\n') {
1154 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1158 Strbuf_append1(&patbuf, *Cursor);
1159 *LastChar++ = *Cursor++;
1165 } else if (isglob(*cp)) {
1171 default: /* Terminate and execute cmd */
1176 case 0033: /* ESC: Terminate */
1184 while (LastChar > InputBuf && *LastChar != '\n')
1190 /* Can't search if unmatched '[' */
1191 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1192 if (*cp == '[' || *cp == ']') {
1197 if (patbuf.len > 1 && ch != '[') {
1198 if (redo && newdir == dir) {
1199 if (pchar == '?') { /* wrap around */
1200 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1201 if (GetHistLine() == CC_ERROR)
1202 /* Hist_num was fixed by first call */
1203 (void) GetHistLine();
1204 Cursor = newdir == F_UP_SEARCH_HIST ?
1205 LastChar : InputBuf;
1207 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1209 Strbuf_append1(&patbuf, '*');
1210 Strbuf_terminate(&patbuf);
1211 if (Cursor < InputBuf || Cursor > LastChar ||
1212 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1213 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1214 ret = newdir == F_UP_SEARCH_HIST ?
1215 e_up_search_hist(0) : e_down_search_hist(0);
1216 if (ret != CC_ERROR) {
1217 Cursor = newdir == F_UP_SEARCH_HIST ?
1218 LastChar : InputBuf;
1219 (void) c_search_line(&patbuf.s[1], newdir);
1222 patbuf.s[--patbuf.len] = '\0';
1223 if (ret == CC_ERROR) {
1225 if (Hist_num != oldHist_num) {
1226 Hist_num = oldHist_num;
1227 if (GetHistLine() == CC_ERROR)
1237 ret = e_inc_search(newdir);
1239 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1240 /* break abort of failed search at last non-failed */
1246 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1247 /* restore on normal return or error exit */
1249 patbuf.len = oldpatlen;
1250 if (Hist_num != oldHist_num) {
1251 Hist_num = oldHist_num;
1252 if (GetHistLine() == CC_ERROR)
1256 if (ret == CC_ERROR)
1259 if (done || ret != CC_NORM)
1269 struct Strbuf tmpbuf = Strbuf_INIT;
1274 cleanup_push(&tmpbuf, Strbuf_cleanup);
1275 oldbuf = Strsave(InputBuf);
1276 cleanup_push(oldbuf, xfree);
1279 Strbuf_append1(&tmpbuf, '*');
1282 LastChar = InputBuf;
1286 c_insert(2); /* prompt + '\n' */
1288 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1290 for (ch = 0;ch == 0;) {
1291 if (GetNextChar(&ch) != 1) {
1292 cleanup_until(&tmpbuf);
1293 return(e_send_eof(0));
1296 case 0010: /* Delete and backspace */
1298 if (tmpbuf.len > 1) {
1304 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1307 cleanup_until(&tmpbuf);
1314 case 0033: /* ESC */
1316 case '\r': /* Newline */
1319 case '\012': /* ASCII Line feed */
1320 case '\015': /* ASCII (or EBCDIC) Return */
1325 Strbuf_append1(&tmpbuf, ch);
1333 cleanup_until(oldbuf);
1335 if (tmpbuf.len == 1) {
1337 * Use the old pattern, but wild-card it.
1339 if (patbuf.len == 0) {
1341 LastChar = InputBuf;
1344 cleanup_until(&tmpbuf);
1347 if (patbuf.s[0] != '*') {
1348 oldbuf = Strsave(patbuf.s);
1350 Strbuf_append1(&patbuf, '*');
1351 Strbuf_append(&patbuf, oldbuf);
1353 Strbuf_append1(&patbuf, '*');
1354 Strbuf_terminate(&patbuf);
1358 Strbuf_append1(&tmpbuf, '*');
1359 Strbuf_terminate(&tmpbuf);
1361 Strbuf_append(&patbuf, tmpbuf.s);
1362 Strbuf_terminate(&patbuf);
1364 cleanup_until(&tmpbuf);
1365 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1366 Cursor = LastChar = InputBuf;
1367 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1368 e_down_search_hist(0)) == CC_ERROR) {
1373 if (ASC(ch) == 0033) {
1386 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1387 * entry point, called from the CcKeyMap indirected into the
1397 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1400 if (UndoPtr > Cursor)
1401 UndoSize = (int)(UndoPtr - Cursor);
1403 UndoSize = (int)(Cursor - UndoPtr);
1405 inputmode = MODE_INSERT;
1406 c_alternativ_key_map(1);
1409 * We don't want to move the cursor, because all the editing
1410 * commands don't include the character under the cursor.
1412 if (Cursor > InputBuf)
1421 e_unassigned(Char c)
1422 { /* bound to keys that arn't really assigned */
1431 e_insert_str(Char *c)
1436 if (LastChar + Argument * n >= InputLim)
1437 return(CC_ERROR); /* end of buffer space */
1438 if (inputmode != MODE_INSERT) {
1439 c_delafter(Argument * Strlen(c));
1441 c_insert(Argument * n);
1442 while (Argument--) {
1443 for (i = 0; i < n; i++)
1454 #ifndef SHORT_STRINGS
1455 c &= ASCII; /* no meta chars ever */
1459 return(CC_ERROR); /* no NULs in the input ever!! */
1461 if (LastChar + Argument >= InputLim)
1462 return(CC_ERROR); /* end of buffer space */
1464 if (Argument == 1) { /* How was this optimized ???? */
1466 if (inputmode != MODE_INSERT) {
1467 UndoBuf[UndoSize++] = *Cursor;
1468 UndoBuf[UndoSize] = '\0';
1469 c_delafter(1); /* Do NOT use the saving ONE */
1473 *Cursor++ = (Char) c;
1474 DoingArg = 0; /* just in case */
1475 RefPlusOne(1); /* fast refresh for one char. */
1478 if (inputmode != MODE_INSERT) {
1480 for(i = 0; i < Argument; i++)
1481 UndoBuf[UndoSize++] = *(Cursor + i);
1483 UndoBuf[UndoSize] = '\0';
1484 c_delafter(Argument); /* Do NOT use the saving ONE */
1490 *Cursor++ = (Char) c;
1494 if (inputmode == MODE_REPLACE_1)
1495 (void) v_cmd_mode(0);
1501 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1505 if ((len = (int) Strlen(s)) <= 0)
1507 if (LastChar + len >= InputLim)
1508 return -1; /* end of buffer space */
1517 DeleteBack(int n) /* delete the n characters before . */
1521 if (Cursor >= &InputBuf[n]) {
1522 c_delbefore(n); /* delete before dot */
1527 e_digit(Char c) /* gray magic here */
1530 return(CC_ERROR); /* no NULs in the input ever!! */
1532 if (DoingArg) { /* if doing an arg, add this in... */
1533 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1536 if (Argument > 1000000)
1538 Argument = (Argument * 10) + (c - '0');
1543 if (LastChar + 1 >= InputLim)
1544 return CC_ERROR; /* end of buffer space */
1546 if (inputmode != MODE_INSERT) {
1547 UndoBuf[UndoSize++] = *Cursor;
1548 UndoBuf[UndoSize] = '\0';
1549 c_delafter(1); /* Do NOT use the saving ONE */
1552 *Cursor++ = (Char) c;
1553 DoingArg = 0; /* just in case */
1554 RefPlusOne(1); /* fast refresh for one char. */
1560 e_argdigit(Char c) /* for ESC-n */
1565 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1569 return(CC_ERROR); /* no NULs in the input ever!! */
1571 if (DoingArg) { /* if doing an arg, add this in... */
1572 if (Argument > 1000000)
1574 Argument = (Argument * 10) + (c - '0');
1576 else { /* else starting an argument */
1584 v_zero(Char c) /* command mode 0 for vi */
1586 if (DoingArg) { /* if doing an arg, add this in... */
1587 if (Argument > 1000000)
1589 Argument = (Argument * 10) + (c - '0');
1592 else { /* else starting an argument */
1594 if (ActionFlag & TCSHOP_DELETE) {
1598 RefCursor(); /* move the cursor */
1606 { /* always ignore argument */
1608 if (adrof(STRhighlight) && MarkIsSet) {
1616 /* PastBottom(); NOW done in ed.inputl.c */
1617 *LastChar++ = '\n'; /* for the benefit of CSH */
1618 *LastChar = '\0'; /* just in case */
1620 InsertPos = InputBuf; /* Reset editing position */
1626 e_newline_hold(Char c)
1631 *LastChar++ = '\n'; /* for the benefit of CSH */
1632 *LastChar = '\0'; /* just in case */
1638 e_newline_down_hist(Char c)
1642 HistSaved = Hist_num;
1644 *LastChar++ = '\n'; /* for the benefit of CSH */
1645 *LastChar = '\0'; /* just in case */
1652 { /* for when ^D is ONLY send-eof */
1655 *LastChar = '\0'; /* just in case */
1664 *LastChar = '\0'; /* just in case */
1665 return(CC_COMPLETE);
1670 e_complete_back(Char c)
1673 *LastChar = '\0'; /* just in case */
1674 return(CC_COMPLETE_BACK);
1679 e_complete_fwd(Char c)
1682 *LastChar = '\0'; /* just in case */
1683 return(CC_COMPLETE_FWD);
1688 e_complete_all(Char c)
1691 *LastChar = '\0'; /* just in case */
1692 return(CC_COMPLETE_ALL);
1697 v_cm_complete(Char c)
1700 if (Cursor < LastChar)
1702 *LastChar = '\0'; /* just in case */
1703 return(CC_COMPLETE);
1708 e_toggle_hist(Char c)
1714 *LastChar = '\0'; /* just in case */
1716 if (Hist_num <= 0) {
1720 hp = Histlist.Hnext;
1721 if (hp == NULL) { /* this is only if no history */
1725 for (h = 1; h < Hist_num; h++)
1728 if (!CurrentHistLit) {
1730 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1740 p = sprlex(&hp->Hlex);
1741 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1746 LastChar = Strend(InputBuf);
1747 if (LastChar > InputBuf) {
1748 if (LastChar[-1] == '\n')
1750 if (LastChar[-1] == ' ')
1752 if (LastChar < InputBuf)
1753 LastChar = InputBuf;
1773 UndoAction = TCSHOP_NOP;
1774 *LastChar = '\0'; /* just in case */
1776 if (Hist_num == 0) { /* save the current buffer away */
1778 Strbuf_append(&HistBuf, InputBuf);
1779 Strbuf_terminate(&HistBuf);
1782 Hist_num += Argument;
1784 if (GetHistLine() == CC_ERROR) {
1786 (void) GetHistLine(); /* Hist_num was fixed by first call */
1793 return(CC_NORM); /* was CC_UP_HIST */
1801 UndoAction = TCSHOP_NOP;
1802 *LastChar = '\0'; /* just in case */
1804 Hist_num -= Argument;
1808 return(CC_ERROR); /* make it beep */
1811 return(GetHistLine());
1817 * c_hmatch() return True if the pattern matches the prefix
1822 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1824 return Gmatch(str, patbuf.s);
1828 * c_hsetpat(): Set the history seatch pattern
1833 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1835 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1836 Strbuf_terminate(&patbuf);
1839 xprintf("\nHist_num = %d\n", Hist_num);
1840 xprintf("patlen = %d\n", (int)patbuf.len);
1841 xprintf("patbuf = \"%S\"\n", patbuf.s);
1842 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1848 e_up_search_hist(Char c)
1855 ActionFlag = TCSHOP_NOP;
1856 UndoAction = TCSHOP_NOP;
1857 *LastChar = '\0'; /* just in case */
1860 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1866 if (Hist_num == 0) {
1868 Strbuf_append(&HistBuf, InputBuf);
1869 Strbuf_terminate(&HistBuf);
1873 hp = Histlist.Hnext;
1877 c_hsetpat(); /* Set search pattern !! */
1879 for (h = 1; h <= Hist_num; h++)
1882 while (hp != NULL) {
1886 if (hp->histline == NULL)
1887 hp->histline = sprlex(&hp->Hlex);
1891 hl = sprlex(&hp->Hlex);
1892 cleanup_push(hl, xfree);
1895 xprintf("Comparing with \"%S\"\n", hl);
1897 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1898 hl[LastChar-InputBuf]) && c_hmatch(hl);
1911 xprintf("not found\n");
1918 return(GetHistLine());
1923 e_down_search_hist(Char c)
1930 ActionFlag = TCSHOP_NOP;
1931 UndoAction = TCSHOP_NOP;
1932 *LastChar = '\0'; /* just in case */
1937 hp = Histlist.Hnext;
1941 c_hsetpat(); /* Set search pattern !! */
1943 for (h = 1; h < Hist_num && hp; h++) {
1945 if (hp->histline == NULL)
1946 hp->histline = sprlex(&hp->Hlex);
1950 hl = sprlex(&hp->Hlex);
1951 cleanup_push(hl, xfree);
1954 xprintf("Comparing with \"%S\"\n", hl);
1956 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1957 hl[LastChar-InputBuf]) && c_hmatch(hl))
1964 if (!found) { /* is it the current history number? */
1965 if (!c_hmatch(HistBuf.s)) {
1967 xprintf("not found\n");
1975 return(GetHistLine());
1984 *LastChar = '\0'; /* just in case */
1993 *LastChar = '\0'; /* just in case */
2002 *LastChar = '\0'; /* just in case */
2003 return(CC_CORRECT_L);
2008 e_run_fg_editor(Char c)
2013 if ((pp = find_stop_ed()) != NULL) {
2014 /* save our editor state so we can restore it */
2016 Hist_num = 0; /* for the history commands */
2018 /* put the tty in a sane mode */
2020 (void) Cookedmode(); /* make sure the tty is set up correctly */
2025 (void) Rawmode(); /* go on */
2035 e_list_choices(Char c)
2039 *LastChar = '\0'; /* just in case */
2040 return(CC_LIST_CHOICES);
2049 *LastChar = '\0'; /* just in case */
2050 return(CC_LIST_ALL);
2059 *LastChar = '\0'; /* just in case */
2060 return(CC_LIST_GLOB);
2065 e_expand_glob(Char c)
2068 *LastChar = '\0'; /* just in case */
2069 return(CC_EXPAND_GLOB);
2074 e_normalize_path(Char c)
2077 *LastChar = '\0'; /* just in case */
2078 return(CC_NORMALIZE_PATH);
2083 e_normalize_command(Char c)
2086 *LastChar = '\0'; /* just in case */
2087 return(CC_NORMALIZE_COMMAND);
2092 e_expand_vars(Char c)
2095 *LastChar = '\0'; /* just in case */
2096 return(CC_EXPAND_VARS);
2102 { /* do a fast command line which(1) */
2105 Hist_num = 0; /* for the history commands */
2107 *LastChar = '\0'; /* just in case */
2114 { /* insert the last element of the prev. cmd */
2116 struct wordent *wp, *firstp;
2124 hp = Histlist.Hnext;
2125 if (hp == NULL) { /* this is only if no history */
2129 wp = (hp->Hlex).prev;
2131 if (wp->prev == (struct wordent *) NULL)
2132 return(CC_ERROR); /* an empty history entry */
2134 firstp = (hp->Hlex).next;
2136 /* back up arg words in lex */
2137 for (i = 0; i < Argument && wp != firstp; i++) {
2141 expanded = expand_lex(wp->prev, 0, i - 1);
2142 if (InsertStr(expanded)) {
2153 e_dabbrev_expand(Char c)
2154 { /* expand to preceding word matching prefix */
2155 Char *cp, *ncp, *bp;
2161 static int oldevent, hist, word;
2162 static Char *start, *oldcursor;
2168 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2169 if (cp == Cursor || Isspace(*cp))
2173 hp = Histlist.Hnext;
2175 if (Argument == 1 && eventno == oldevent && cp == start &&
2176 Cursor == oldcursor && patbuf.len > 0
2177 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2178 /* continue previous search - go to last match (hist/word) */
2179 if (hist != 0) { /* need to move up history */
2180 for (i = 1; i < hist && hp != NULL; i++)
2182 if (hp == NULL) /* "can't happen" */
2184 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2189 cp = c_preword(cp, bp, word, STRshwordsep);
2190 } else { /* starting new search */
2194 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2200 ncp = c_preword(cp, bp, 1, STRshwordsep);
2201 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2206 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2213 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2216 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2217 /* We don't fully check distinct matches as Gnuemacs does: */
2218 if (Argument > 1) { /* just count matches */
2219 if (++arg >= Argument)
2221 } else { /* match if distinct from previous */
2222 if (len != (size_t)(Cursor - start)
2223 || Strncmp(cp, start, len) != 0)
2229 if (LastChar + len - (Cursor - start) >= InputLim)
2230 goto err_hbuf; /* no room */
2231 DeleteBack(Cursor - start);
2247 { /* almost like GnuEmacs */
2252 if (KillRingLen == 0) /* nothing killed */
2254 len = Strlen(KillRing[YankPos].buf);
2255 if (LastChar + len >= InputLim)
2256 return(CC_ERROR); /* end of buffer space */
2259 cp = Cursor; /* for speed */
2261 c_insert(len); /* open the space, */
2262 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2265 if (Argument == 1) { /* if no arg */
2266 Mark = Cursor; /* mark at beginning, cursor at end */
2269 Mark = cp; /* else cursor at beginning, mark at end */
2272 if (adrof(STRhighlight) && MarkIsSet) {
2283 { /* almost like GnuEmacs */
2284 int m_bef_c, del_len, ins_len;
2290 /* XXX This "should" be here, but doesn't work, since LastCmd
2291 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2292 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2293 second one will "succeed" even if the first one wasn't preceded
2294 by a yank, and giving an argument is impossible. Now we "succeed"
2295 regardless of previous command, which is wrong too of course. */
2296 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2300 if (KillRingLen == 0) /* nothing killed */
2302 YankPos -= Argument;
2304 YankPos += KillRingLen;
2305 YankPos %= KillRingLen;
2307 if (Cursor > Mark) {
2308 del_len = Cursor - Mark;
2311 del_len = Mark - Cursor;
2314 ins_len = Strlen(KillRing[YankPos].buf);
2315 if (LastChar + ins_len - del_len >= InputLim)
2316 return(CC_ERROR); /* end of buffer space */
2319 c_delbefore(del_len);
2321 c_delafter(del_len);
2323 cp = Cursor; /* for speed */
2325 c_insert(ins_len); /* open the space, */
2326 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2330 Mark = Cursor; /* mark at beginning, cursor at end */
2333 Mark = cp; /* else cursor at beginning, mark at end */
2336 if (adrof(STRhighlight) && MarkIsSet) {
2346 v_delprev(Char c) /* Backspace key in insert mode */
2353 if (InsertPos != 0) {
2354 if (Argument <= Cursor - InsertPos) {
2355 c_delbefore(Argument); /* delete before */
2367 if (Cursor > InputBuf) {
2368 c_delbefore(Argument); /* delete before dot */
2378 e_delwordprev(Char c)
2383 if (Cursor == InputBuf)
2387 cp = c_prev_word(Cursor, InputBuf, Argument);
2389 c_push_kill(cp, Cursor); /* save the text */
2391 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2395 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2397 * Changed the names of some of the ^D family of editor functions to
2398 * correspond to what they actually do and created new e_delnext_list
2401 * Old names: New names:
2403 * delete-char delete-char-or-eof
2404 * F_DELNEXT F_DELNEXT_EOF
2405 * e_delnext e_delnext_eof
2406 * edelnxt edelnxteof
2407 * delete-char-or-eof delete-char
2408 * F_DELNEXT_EOF F_DELNEXT
2409 * e_delnext_eof e_delnext
2410 * edelnxteof edelnxt
2411 * delete-char-or-list delete-char-or-list-or-eof
2412 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2413 * e_list_delnext e_delnext_list_eof
2415 * (no old equivalent) delete-char-or-list
2421 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2422 /* rename e_delnext() -> e_delnext_eof() */
2428 if (Cursor == LastChar) {/* if I'm at the end */
2433 if (Cursor != InputBuf)
2439 c_delafter(Argument); /* delete after dot */
2440 if (Cursor > LastChar)
2441 Cursor = LastChar; /* bounds check */
2448 e_delnext_eof(Char c)
2451 if (Cursor == LastChar) {/* if I'm at the end */
2453 if (Cursor == InputBuf) {
2454 /* if I'm also at the beginning */
2455 so_write(STReof, 4);/* then do a EOF */
2463 if (Cursor != InputBuf)
2469 c_delafter(Argument); /* delete after dot */
2470 if (Cursor > LastChar)
2471 Cursor = LastChar; /* bounds check */
2477 e_delnext_list(Char c)
2480 if (Cursor == LastChar) { /* if I'm at the end */
2482 *LastChar = '\0'; /* just in case */
2483 return(CC_LIST_CHOICES);
2486 c_delafter(Argument); /* delete after dot */
2487 if (Cursor > LastChar)
2488 Cursor = LastChar; /* bounds check */
2495 e_delnext_list_eof(Char c)
2498 if (Cursor == LastChar) { /* if I'm at the end */
2499 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2500 so_write(STReof, 4);/* then do a EOF */
2506 *LastChar = '\0'; /* just in case */
2507 return(CC_LIST_CHOICES);
2511 c_delafter(Argument); /* delete after dot */
2512 if (Cursor > LastChar)
2513 Cursor = LastChar; /* bounds check */
2525 if (Cursor == LastChar && Cursor == InputBuf) {
2526 so_write(STReof, 4); /* then do a EOF */
2532 *LastChar = '\0'; /* just in case */
2533 rv = CC_LIST_CHOICES;
2540 e_delwordnext(Char c)
2545 if (Cursor == LastChar)
2549 cp = c_next_word(Cursor, LastChar, Argument);
2551 c_push_kill(Cursor, cp); /* save the text */
2553 c_delafter((int)(cp - Cursor)); /* delete after dot */
2554 if (Cursor > LastChar)
2555 Cursor = LastChar; /* bounds check */
2566 if (ActionFlag & TCSHOP_DELETE) {
2570 RefCursor(); /* move the cursor */
2582 while (Isspace(*Cursor)) /* We want FIRST non space character */
2584 if (ActionFlag & TCSHOP_DELETE) {
2590 RefCursor(); /* move the cursor */
2599 c_push_kill(Cursor, LastChar); /* copy it */
2600 LastChar = Cursor; /* zap! -- delete to end */
2613 c_push_kill(InputBuf, Cursor); /* copy it */
2614 c_delbefore((int)(Cursor - InputBuf));
2615 if (Mark && Mark > Cursor)
2616 Mark -= Cursor-InputBuf;
2625 c_push_kill(InputBuf, LastChar); /* copy it */
2626 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2633 e_killregion(Char c)
2639 if (Mark > Cursor) {
2640 c_push_kill(Cursor, Mark); /* copy it */
2641 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2644 else { /* mark is before cursor */
2645 c_push_kill(Mark, Cursor); /* copy it */
2646 c_delbefore((int)(Cursor - Mark));
2648 if (adrof(STRhighlight) && MarkIsSet) {
2658 e_copyregion(Char c)
2664 if (Mark > Cursor) {
2665 c_push_kill(Cursor, Mark); /* copy it */
2667 else { /* mark is before cursor */
2668 c_push_kill(Mark, Cursor); /* copy it */
2670 return(CC_NORM); /* don't even need to Refresh() */
2675 e_charswitch(Char cc)
2681 /* do nothing if we are at beginning of line or have only one char */
2682 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2686 if (Cursor < LastChar) {
2690 Cursor[-2] = Cursor[-1];
2697 e_gcharswitch(Char cc)
2698 { /* gosmacs style ^T */
2702 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2704 Cursor[-2] = Cursor[-1];
2718 if (Cursor > InputBuf) {
2719 if (Argument > Cursor - InputBuf)
2725 if (ActionFlag & TCSHOP_DELETE) {
2743 if (Cursor == InputBuf)
2747 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2749 if (ActionFlag & TCSHOP_DELETE) {
2763 if (Cursor == InputBuf)
2767 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2770 if (ActionFlag & TCSHOP_DELETE) {
2784 if (Cursor < LastChar) {
2786 if (Cursor > LastChar)
2790 if (ActionFlag & TCSHOP_DELETE) {
2808 if (Cursor == LastChar)
2812 Cursor = c_next_word(Cursor, LastChar, Argument);
2815 if (ActionFlag & TCSHOP_DELETE) {
2829 if (Cursor == LastChar)
2833 Cursor = c_nexword(Cursor, LastChar, Argument);
2836 if (ActionFlag & TCSHOP_DELETE) {
2847 v_wordbegnext(Char c)
2850 if (Cursor == LastChar)
2854 Cursor = c_next_word(Cursor, LastChar, Argument);
2855 if (Cursor < LastChar)
2859 if (ActionFlag & TCSHOP_DELETE) {
2870 v_repeat_srch(int c)
2872 CCRETVAL rv = CC_ERROR;
2874 xprintf("dir %d patlen %d patbuf %S\n",
2875 c, (int)patbuf.len, patbuf.s);
2878 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2879 LastChar = InputBuf;
2881 case F_DOWN_SEARCH_HIST:
2882 rv = e_down_search_hist(0);
2884 case F_UP_SEARCH_HIST:
2885 rv = e_up_search_hist(0);
2894 v_csearch_back(Char ch, int count, int tflag)
2902 while (cp > InputBuf && *cp != ch)
2906 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2909 if (*cp == ch && tflag)
2914 if (ActionFlag & TCSHOP_DELETE) {
2925 v_csearch_fwd(Char ch, int count, int tflag)
2933 while (cp < LastChar && *cp != ch)
2940 if (*cp == ch && tflag)
2945 if (ActionFlag & TCSHOP_DELETE) {
2960 if (ActionFlag == TCSHOP_DELETE) {
2961 ActionFlag = TCSHOP_NOP;
2966 for (cp = InputBuf; cp < LastChar; cp++) {
2971 UndoAction = TCSHOP_INSERT;
2973 LastChar = InputBuf;
2975 if (c & TCSHOP_INSERT)
2976 c_alternativ_key_map(0);
2981 else if (ActionFlag == TCSHOP_NOP) {
2985 return(CC_ARGHACK); /* Do NOT clear out argument */
2997 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2999 c_get_word(Char **begin, Char **end)
3004 while (Argument--) {
3005 while ((cp <= LastChar) && (isword(*cp)))
3008 while ((cp >= InputBuf) && (isword(*cp)))
3013 #endif /* COMMENT */
3022 end = c_next_word(Cursor, LastChar, Argument);
3024 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3029 if (Cursor > LastChar)
3037 e_capitalcase(Char c)
3042 end = c_next_word(Cursor, LastChar, Argument);
3045 for (; cp < end; cp++) {
3053 for (; cp < end; cp++)
3058 if (Cursor > LastChar)
3070 end = c_next_word(Cursor, LastChar, Argument);
3072 for (cp = Cursor; cp < end; cp++)
3077 if (Cursor > LastChar)
3088 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3100 e_exchange_mark(Char c)
3115 { /* multiply current argument by 4 */
3117 if (Argument > 1000000)
3125 quote_mode_cleanup(void *unused)
3140 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3141 num = GetNextChar(&ch);
3144 return e_insert(ch);
3146 return e_send_eof(0);
3155 return(CC_ARGHACK); /* preserve argument */
3161 e_extendnext(Char c)
3163 CurrentKeyMap = CcAltMap;
3164 return(CC_ARGHACK); /* preserve argument */
3172 { /* move to beginning of line and start vi
3179 UndoAction = TCSHOP_DELETE;
3181 RefCursor(); /* move the cursor */
3182 c_alternativ_key_map(0);
3189 { /* vi mode overwrite one character */
3191 c_alternativ_key_map(0);
3192 inputmode = MODE_REPLACE_1;
3193 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3202 { /* vi mode start overwriting */
3204 c_alternativ_key_map(0);
3205 inputmode = MODE_REPLACE;
3206 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3215 { /* vi mode substitute for one char */
3217 c_delafter(Argument);
3218 c_alternativ_key_map(0);
3225 { /* vi mode replace whole line */
3227 (void) e_killall(0);
3228 c_alternativ_key_map(0);
3235 { /* vi mode change to end of line */
3237 (void) e_killend(0);
3238 c_alternativ_key_map(0);
3245 { /* vi mode start inserting */
3247 c_alternativ_key_map(0);
3251 UndoAction = TCSHOP_DELETE;
3259 { /* vi mode start adding */
3261 c_alternativ_key_map(0);
3262 if (Cursor < LastChar)
3265 if (Cursor > LastChar)
3272 UndoAction = TCSHOP_DELETE;
3280 { /* vi mode to add at end of line */
3282 c_alternativ_key_map(0);
3285 InsertPos = LastChar; /* Mark where insertion begins */
3287 UndoAction = TCSHOP_DELETE;
3295 v_change_case(Char cc)
3300 if (Cursor < LastChar) {
3301 #ifndef WINNT_NATIVE
3305 #endif /* WINNT_NATIVE */
3307 *Cursor++ = Tolower(c);
3308 else if (Islower(c))
3309 *Cursor++ = Toupper(c);
3312 RefPlusOne(1); /* fast refresh for one char */
3325 for (p = InputBuf; Isspace(*p); p++)
3332 return(e_newline(0));
3338 { /* erase all of current line, start again */
3340 ResetInLine(0); /* reset the input pointers */
3359 ClearScreen(); /* clear the whole real screen */
3360 ClearDisp(); /* reset everything */
3369 #if defined(_MINIX) || defined(WINNT_NATIVE)
3370 /* SAK PATCH: erase all of current line, start again */
3371 ResetInLine(0); /* reset the input pointers */
3374 return (CC_REFRESH);
3375 #else /* !_MINIX && !WINNT_NATIVE */
3378 #endif /* _MINIX || WINNT_NATIVE */
3382 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3383 * Function to send a character back to the input stream in cooked
3384 * mode. Only works if we have TIOCSTI
3388 e_stuff_char(Char c)
3391 int was_raw = Tty_raw_mode;
3392 char buf[MB_LEN_MAX];
3396 (void) Cookedmode();
3398 (void) xwrite(SHIN, "\n", 1);
3399 len = one_wctomb(buf, c);
3400 for (i = 0; i < len; i++)
3401 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3405 return(e_redisp(c));
3406 #else /* !TIOCSTI */
3408 #endif /* !TIOCSTI */
3416 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3431 e_tty_flusho(Char c)
3465 /* returns the number of (attempted) expansions */
3469 *LastChar = '\0'; /* just in case */
3470 return c_substitute();
3475 e_expand_history(Char c)
3478 (void)ExpandHistory();
3484 e_magic_space(Char c)
3487 *LastChar = '\0'; /* just in case */
3488 (void)c_substitute();
3489 return(e_insert(' '));
3501 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3502 if (adrof(STRhighlight) && IncMatchLen) {
3522 ret = e_inc_search(F_UP_SEARCH_HIST);
3523 if (adrof(STRhighlight) && IncMatchLen) {
3537 Char *cp, *oldc, *dp;
3540 if (Cursor == InputBuf)
3545 /* does a bounds check */
3546 cp = c_prev_word(Cursor, InputBuf, Argument);
3548 c_insert((int)(oldc - cp));
3549 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3552 Cursor = dp; /* put cursor at end */
3559 e_tty_starto(Char c)
3568 e_load_average(Char c)
3574 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3575 * there even if they don't use it. (lukem@netbsd.org)
3577 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3579 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3589 * Delete with insert == change: first we delete and then we leave in
3592 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3600 return(v_action(TCSHOP_DELETE));
3609 if (Cursor == LastChar)
3613 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3615 if (ActionFlag & TCSHOP_DELETE)
3631 if (Cursor == LastChar)
3635 Cursor = c_eword(Cursor, LastChar, Argument);
3637 if (ActionFlag & TCSHOP_DELETE) {
3654 if (GetNextChar(&ch) != 1)
3655 return e_send_eof(0);
3657 srch_dir = CHAR_FWD;
3660 return v_csearch_fwd(ch, Argument, 0);
3671 if (GetNextChar(&ch) != 1)
3672 return e_send_eof(0);
3674 srch_dir = CHAR_BACK;
3677 return v_csearch_back(ch, Argument, 0);
3682 v_charto_fwd(Char c)
3687 if (GetNextChar(&ch) != 1)
3688 return e_send_eof(0);
3690 return v_csearch_fwd(ch, Argument, 1);
3696 v_charto_back(Char c)
3701 if (GetNextChar(&ch) != 1)
3702 return e_send_eof(0);
3704 return v_csearch_back(ch, Argument, 1);
3715 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3716 v_csearch_back(srch_char, Argument, 0);
3721 v_rchar_back(Char c)
3727 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3728 v_csearch_back(srch_char, Argument, 0);
3741 switch (UndoAction) {
3742 case TCSHOP_DELETE|TCSHOP_INSERT:
3744 if (UndoSize == 0) return(CC_NORM);
3747 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3748 *kp++ = *cp++; /* into UndoBuf */
3750 for (cp = UndoPtr; cp <= LastChar; cp++)
3753 LastChar -= UndoSize;
3756 UndoAction = TCSHOP_INSERT;
3760 if (UndoSize == 0) return(CC_NORM);
3764 c_insert(UndoSize); /* open the space, */
3765 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3768 UndoAction = TCSHOP_DELETE;
3772 if (UndoSize == 0) return(CC_NORM);
3776 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3777 if (size < UndoSize)
3779 for(loop = 0; loop < size; loop++) {
3798 return v_search(F_UP_SEARCH_HIST);
3806 return v_search(F_DOWN_SEARCH_HIST);
3814 if (patbuf.len == 0) return(CC_ERROR);
3815 return(v_repeat_srch(searchdir));
3820 v_rsrch_back(Char c)
3823 if (patbuf.len == 0) return(CC_ERROR);
3824 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3825 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3828 #ifndef WINNT_NATIVE
3829 /* Since ed.defns.h is generated from ed.defns.c, these empty
3830 functions will keep the F_NUM_FNS consistent
3833 e_copy_to_clipboard(Char c)
3840 e_paste_from_clipboard(Char c)
3847 e_dosify_next(Char c)
3853 e_dosify_prev(Char c)
3870 #endif /* !WINNT_NATIVE */
3874 MoveCursor(int n) /* move cursor + right - left char */
3876 Cursor = Cursor + n;
3877 if (Cursor < InputBuf)
3879 if (Cursor > LastChar)
3893 if (p < InputBuf || p > LastChar)
3894 return 1; /* Error */