Current Path : /usr/src/contrib/tcsh/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //usr/src/contrib/tcsh/ed.chared.c |
/* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.98 2010/05/08 00:37:39 christos Exp $ */ /* * ed.chared.c: Character editing functions. */ /*- * Copyright (c) 1980, 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Bjorn Knutsson @ Thu Jun 24 19:02:17 1999 e_dabbrev_expand() did not do proper completion if quoted spaces were present in the string being completed. Exemple: # echo hello\ world hello world # echo h<press key bound to dabbrev-expande> # echo hello\<cursor> Correct behavior is: # echo h<press key bound to dabbrev-expande> # echo hello\ world<cursor> The same problem occured if spaces were present in a string withing quotation marks. Example: # echo "hello world" hello world # echo "h<press key bound to dabbrev-expande> # echo "hello<cursor> The former problem could be solved with minor modifications of c_preword() and c_endword(). The latter, however, required a significant rewrite of c_preword(), since quoted strings must be parsed from start to end to determine if a given character is inside or outside the quotation marks. Compare the following two strings: # echo \"" 'foo \' bar\" " 'foo \' bar\ # echo '\"" 'foo \' bar\" \"" foo ' bar" The only difference between the two echo lines is in the first character after the echo command. The result is either one or three arguments. */ #include "sh.h" RCSID("$tcsh: ed.chared.c,v 3.98 2010/05/08 00:37:39 christos Exp $") #include "ed.h" #include "tw.h" #include "ed.defns.h" /* #define SDEBUG */ #define TCSHOP_NOP 0x00 #define TCSHOP_DELETE 0x01 #define TCSHOP_INSERT 0x02 #define TCSHOP_CHANGE 0x04 #define CHAR_FWD 0 #define CHAR_BACK 1 /* * vi word treatment * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com> */ #define C_CLASS_WHITE 1 #define C_CLASS_ALNUM 2 #define C_CLASS_OTHER 3 static Char *InsertPos = InputBuf; /* Where insertion starts */ static Char *ActionPos = 0; /* Where action begins */ static int ActionFlag = TCSHOP_NOP; /* What delayed action to take */ /* * Word search state */ static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */ static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */ /* * Char search state */ static int srch_dir = CHAR_FWD; /* Direction of last search */ static Char srch_char = 0; /* Search target */ /* all routines that start with c_ are private to this set of routines */ static void c_alternativ_key_map (int); void c_insert (int); void c_delafter (int); void c_delbefore (int); static int c_to_class (Char); static Char *c_prev_word (Char *, Char *, int); static Char *c_next_word (Char *, Char *, int); static Char *c_number (Char *, int *, int); static Char *c_expand (Char *); static int c_excl (Char *); static int c_substitute (void); static void c_delfini (void); static int c_hmatch (Char *); static void c_hsetpat (void); #ifdef COMMENT static void c_get_word (Char **, Char **); #endif static Char *c_preword (Char *, Char *, int, Char *); static Char *c_nexword (Char *, Char *, int); static Char *c_endword (Char *, Char *, int, Char *); static Char *c_eword (Char *, Char *, int); static void c_push_kill (Char *, Char *); static void c_save_inputbuf (void); static CCRETVAL c_search_line (Char *, int); static CCRETVAL v_repeat_srch (int); static CCRETVAL e_inc_search (int); #ifdef notyet static CCRETVAL e_insert_str (Char *); #endif static CCRETVAL v_search (int); static CCRETVAL v_csearch_fwd (Char, int, int); static CCRETVAL v_action (int); static CCRETVAL v_csearch_back (Char, int, int); static void c_alternativ_key_map(int state) { switch (state) { case 0: CurrentKeyMap = CcKeyMap; break; case 1: CurrentKeyMap = CcAltMap; break; default: return; } AltKeyMap = (Char) state; } void c_insert(int num) { Char *cp; if (LastChar + num >= InputLim) return; /* can't go past end of buffer */ if (Cursor < LastChar) { /* if I must move chars */ for (cp = LastChar; cp >= Cursor; cp--) cp[num] = *cp; if (Mark && Mark > Cursor) Mark += num; } LastChar += num; } void c_delafter(int num) { Char *cp, *kp = NULL; if (num > LastChar - Cursor) num = (int) (LastChar - Cursor); /* bounds check */ if (num > 0) { /* if I can delete anything */ if (VImode) { kp = UndoBuf; /* Set Up for VI undo command */ UndoAction = TCSHOP_INSERT; UndoSize = num; UndoPtr = Cursor; for (cp = Cursor; cp <= LastChar; cp++) { *kp++ = *cp; /* Save deleted chars into undobuf */ *cp = cp[num]; } } else for (cp = Cursor; cp + num <= LastChar; cp++) *cp = cp[num]; LastChar -= num; /* Mark was within the range of the deleted word? */ if (Mark && Mark > Cursor && Mark <= Cursor+num) Mark = Cursor; /* Mark after the deleted word? */ else if (Mark && Mark > Cursor) Mark -= num; } #ifdef notdef else { /* * XXX: We don't want to do that. In emacs mode overwrite should be * sticky. I am not sure how that affects vi mode */ inputmode = MODE_INSERT; } #endif /* notdef */ } void c_delbefore(int num) /* delete before dot, with bounds checking */ { Char *cp, *kp = NULL; if (num > Cursor - InputBuf) num = (int) (Cursor - InputBuf); /* bounds check */ if (num > 0) { /* if I can delete anything */ if (VImode) { kp = UndoBuf; /* Set Up for VI undo command */ UndoAction = TCSHOP_INSERT; UndoSize = num; UndoPtr = Cursor - num; for (cp = Cursor - num; cp <= LastChar; cp++) { *kp++ = *cp; *cp = cp[num]; } } else for (cp = Cursor - num; cp + num <= LastChar; cp++) *cp = cp[num]; LastChar -= num; Cursor -= num; /* Mark was within the range of the deleted word? */ if (Mark && Mark > Cursor && Mark <= Cursor+num) Mark = Cursor; /* Mark after the deleted word? */ else if (Mark && Mark > Cursor) Mark -= num; } } static Char * c_preword(Char *p, Char *low, int n, Char *delim) { while (n--) { Char *prev = low; Char *new; while (prev < p) { /* Skip initial non-word chars */ if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\') break; prev++; } new = prev; while (new < p) { prev = new; new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */ new++; /* Step away from end of word */ while (new <= p) { /* Skip trailing non-word chars */ if (!Strchr(delim, *new) || *(new-1) == (Char)'\\') break; new++; } } p = prev; /* Set to previous word start */ } if (p < low) p = low; return (p); } /* * c_to_class() returns the class of the given character. * * This is used to make the c_prev_word() and c_next_word() functions * work like vi's, which classify characters. A word is a sequence of * characters belonging to the same class, classes being defined as * follows: * * 1/ whitespace * 2/ alphanumeric chars, + underscore * 3/ others */ static int c_to_class(Char ch) { if (Isspace(ch)) return C_CLASS_WHITE; if (Isdigit(ch) || Isalpha(ch) || ch == '_') return C_CLASS_ALNUM; return C_CLASS_OTHER; } static Char * c_prev_word(Char *p, Char *low, int n) { p--; if (!VImode) { while (n--) { while ((p >= low) && !isword(*p)) p--; while ((p >= low) && isword(*p)) p--; } /* cp now points to one character before the word */ p++; if (p < low) p = low; /* cp now points where we want it */ return(p); } while (n--) { int c_class; if (p < low) break; /* scan until beginning of current word (may be all whitespace!) */ c_class = c_to_class(*p); while ((p >= low) && c_class == c_to_class(*p)) p--; /* if this was a non_whitespace word, we're ready */ if (c_class != C_CLASS_WHITE) continue; /* otherwise, move back to beginning of the word just found */ c_class = c_to_class(*p); while ((p >= low) && c_class == c_to_class(*p)) p--; } p++; /* correct overshoot */ return (p); } static Char * c_next_word(Char *p, Char *high, int n) { if (!VImode) { while (n--) { while ((p < high) && !isword(*p)) p++; while ((p < high) && isword(*p)) p++; } if (p > high) p = high; /* p now points where we want it */ return(p); } while (n--) { int c_class; if (p >= high) break; /* scan until end of current word (may be all whitespace!) */ c_class = c_to_class(*p); while ((p < high) && c_class == c_to_class(*p)) p++; /* if this was all whitespace, we're ready */ if (c_class == C_CLASS_WHITE) continue; /* if we've found white-space at the end of the word, skip it */ while ((p < high) && c_to_class(*p) == C_CLASS_WHITE) p++; } p--; /* correct overshoot */ return (p); } static Char * c_nexword(Char *p, Char *high, int n) { while (n--) { while ((p < high) && !Isspace(*p)) p++; while ((p < high) && Isspace(*p)) p++; } if (p > high) p = high; /* p now points where we want it */ return(p); } /* * Expand-History (originally "Magic-Space") code added by * Ray Moody <ray@gibbs.physics.purdue.edu> * this is a neat, but odd, addition. */ /* * c_number: Ignore character p points to, return number appearing after that. * A '$' by itself means a big number; "$-" is for negative; '^' means 1. * Return p pointing to last char used. */ /* * dval is the number to subtract from for things like $-3 */ static Char * c_number(Char *p, int *num, int dval) { int i; int sign = 1; if (*++p == '^') { *num = 1; return(p); } if (*p == '$') { if (*++p != '-') { *num = INT_MAX; /* Handle $ */ return(--p); } sign = -1; /* Handle $- */ ++p; } for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0') continue; *num = (sign < 0 ? dval - i : i); return(--p); } /* * excl_expand: There is an excl to be expanded to p -- do the right thing * with it and return a version of p advanced over the expanded stuff. Also, * update tsh_cur and related things as appropriate... */ static Char * c_expand(Char *p) { Char *q; struct Hist *h = Histlist.Hnext; struct wordent *l; int i, from, to, dval; int all_dig; int been_once = 0; Char *op = p; Char *buf; size_t buf_len; Char *modbuf; buf = NULL; if (!h) goto excl_err; excl_sw: switch (*(q = p + 1)) { case '^': buf = expand_lex(&h->Hlex, 1, 1); break; case '$': if ((l = (h->Hlex).prev) != 0) buf = expand_lex(l->prev->prev, 0, 0); break; case '*': buf = expand_lex(&h->Hlex, 1, INT_MAX); break; default: if (been_once) { /* unknown argument */ /* assume it's a modifier, e.g. !foo:h, and get whole cmd */ buf = expand_lex(&h->Hlex, 0, INT_MAX); q -= 2; break; } been_once = 1; if (*q == ':') /* short form: !:arg */ --q; if (HIST != '\0' && *q != HIST) { /* * Search for a space, tab, or colon. See if we have a number (as * in !1234:xyz). Remember the number. */ for (i = 0, all_dig = 1; *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) { /* * PWP: !-4 is a valid history argument too, therefore the test * is if not a digit, or not a - as the first character. */ if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1)) all_dig = 0; else if (*q == '-') all_dig = 2;/* we are sneeky about this */ else i = 10 * i + *q - '0'; } --q; /* * If we have a number, search for event i. Otherwise, search for * a named event (as in !foo). (In this case, I is the length of * the named event). */ if (all_dig) { if (all_dig == 2) i = -i; /* make it negitive */ if (i < 0) /* if !-4 (for example) */ i = eventno + 1 + i; /* remember: i is < 0 */ for (; h; h = h->Hnext) { if (h->Hnum == i) break; } } else { for (i = (int) (q - p); h; h = h->Hnext) { if ((l = &h->Hlex) != 0) { if (!Strncmp(p + 1, l->next->word, (size_t) i)) break; } } } } if (!h) goto excl_err; if (q[1] == ':' || q[1] == '-' || q[1] == '*' || q[1] == '$' || q[1] == '^') { /* get some args */ p = q[1] == ':' ? ++q : q; /* * Go handle !foo:* */ if ((q[1] < '0' || q[1] > '9') && q[1] != '-' && q[1] != '$' && q[1] != '^') goto excl_sw; /* * Go handle !foo:$ */ if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9')) goto excl_sw; /* * Count up the number of words in this event. Store it in dval. * Dval will be fed to number. */ dval = 0; if ((l = h->Hlex.prev) != 0) { for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++) continue; } if (!dval) goto excl_err; if (q[1] == '-') from = 0; else q = c_number(q, &from, dval); if (q[1] == '-') { ++q; if ((q[1] < '0' || q[1] > '9') && q[1] != '$') to = dval - 1; else q = c_number(q, &to, dval); } else if (q[1] == '*') { ++q; to = INT_MAX; } else { to = from; } if (from < 0 || to < from) goto excl_err; buf = expand_lex(&h->Hlex, from, to); } else /* get whole cmd */ buf = expand_lex(&h->Hlex, 0, INT_MAX); break; } if (buf == NULL) buf = SAVE(""); /* * Apply modifiers, if any. */ if (q[1] == ':') { modbuf = buf; while (q[1] == ':' && modbuf != NULL) { switch (q[2]) { case 'r': case 'e': case 'h': case 't': case 'q': case 'x': case 'u': case 'l': if ((modbuf = domod(buf, (int) q[2])) != NULL) { xfree(buf); buf = modbuf; } ++q; break; case 'a': case 'g': /* Not implemented; this needs to be done before expanding * lex. We don't have the words available to us anymore. */ ++q; break; case 'p': /* Ok */ ++q; break; case '\0': break; default: ++q; break; } if (q[1]) ++q; } } buf_len = Strlen(buf); /* * Now replace the text from op to q inclusive with the text from buf. */ q++; /* * Now replace text non-inclusively like a real CS major! */ if (LastChar + buf_len - (q - op) >= InputLim) goto excl_err; (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char)); LastChar += buf_len - (q - op); Cursor += buf_len - (q - op); (void) memcpy(op, buf, buf_len * sizeof(Char)); *LastChar = '\0'; xfree(buf); return op + buf_len; excl_err: xfree(buf); SoundBeep(); return(op + 1); } /* * c_excl: An excl has been found at point p -- back up and find some white * space (or the beginning of the buffer) and properly expand all the excl's * from there up to the current cursor position. We also avoid (trying to) * expanding '>!' * Returns number of expansions attempted (doesn't matter whether they succeeded * or not). */ static int c_excl(Char *p) { int i; Char *q; int nr_exp; /* * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise, * back p up to just before the current word. */ if ((p[1] == ' ' || p[1] == '\t') && (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) { for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q) continue; if (*q == '>') ++p; } else { while (*p != ' ' && *p != '\t' && p > InputBuf) --p; } /* * Forever: Look for history char. (Stop looking when we find the cursor.) * Count backslashes. If odd, skip history char. Expand if even number of * backslashes. */ nr_exp = 0; for (;;) { if (HIST != '\0') while (*p != HIST && p < Cursor) ++p; for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++) continue; if (i % 2 == 0) ++p; if (p >= Cursor) /* all done */ return nr_exp; if (i % 2 == 1) { p = c_expand(p); ++nr_exp; } } } static int c_substitute(void) { Char *p; int nr_exp; /* * Start p out one character before the cursor. Move it backwards looking * for white space, the beginning of the line, or a history character. */ for (p = Cursor - 1; p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p) continue; /* * If we found a history character, go expand it. */ if (HIST != '\0' && *p == HIST) nr_exp = c_excl(p); else nr_exp = 0; Refresh(); return nr_exp; } static void c_delfini(void) /* Finish up delete action */ { int Size; if (ActionFlag & TCSHOP_INSERT) c_alternativ_key_map(0); ActionFlag = TCSHOP_NOP; if (ActionPos == 0) return; UndoAction = TCSHOP_INSERT; if (Cursor > ActionPos) { Size = (int) (Cursor-ActionPos); c_delbefore(Size); RefCursor(); } else if (Cursor < ActionPos) { Size = (int)(ActionPos-Cursor); c_delafter(Size); } else { Size = 1; c_delafter(Size); } UndoPtr = Cursor; UndoSize = Size; } static Char * c_endword(Char *p, Char *high, int n, Char *delim) { Char inquote = 0; p++; while (n--) { while (p < high) { /* Skip non-word chars */ if (!Strchr(delim, *p) || *(p-1) == (Char)'\\') break; p++; } while (p < high) { /* Skip string */ if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */ if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */ if (inquote == 0) inquote = *p; else if (inquote == *p) inquote = 0; } } /* Break if unquoted non-word char */ if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\') break; p++; } } p--; return(p); } static Char * c_eword(Char *p, Char *high, int n) { p++; while (n--) { while ((p < high) && Isspace(*p)) p++; if (isword(*p)) while ((p < high) && isword(*p)) p++; else while ((p < high) && !(Isspace(*p) || isword(*p))) p++; } p--; return(p); } /* Set the max length of the kill ring */ void SetKillRing(int max) { CStr *new; int count, i, j; if (max < 1) max = 1; /* no ring, but always one buffer */ if (max == KillRingMax) return; new = xcalloc(max, sizeof(CStr)); if (KillRing != NULL) { if (KillRingLen != 0) { if (max >= KillRingLen) { count = KillRingLen; j = KillPos; } else { count = max; j = (KillPos - count + KillRingLen) % KillRingLen; } for (i = 0; i < KillRingLen; i++) { if (i < count) /* copy latest */ new[i] = KillRing[j]; else /* free the others */ xfree(KillRing[j].buf); j = (j + 1) % KillRingLen; } KillRingLen = count; KillPos = count % max; YankPos = count - 1; } xfree(KillRing); } KillRing = new; KillRingMax = max; } /* Push string from start upto (but not including) end onto kill ring */ static void c_push_kill(Char *start, Char *end) { CStr save, *pos; Char *dp, *cp, *kp; int len = end - start, i, j, k; /* Check for duplicates? */ if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) { YankPos = (KillPos - 1 + KillRingLen) % KillRingLen; if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */ j = YankPos; for (i = 0; i < KillRingLen; i++) { if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 && KillRing[j].buf[len] == '\0') { save = KillRing[j]; for ( ; i > 0; i--) { k = j; j = (j + 1) % KillRingLen; KillRing[k] = KillRing[j]; } KillRing[j] = save; return; } j = (j - 1 + KillRingLen) % KillRingLen; } } else if (eq(dp, STRall)) { /* skip if any earlier */ for (i = 0; i < KillRingLen; i++) if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 && KillRing[i].buf[len] == '\0') return; } else if (eq(dp, STRprev)) { /* skip if immediately previous */ j = YankPos; if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 && KillRing[j].buf[len] == '\0') return; } } /* No duplicate, go ahead and push */ len++; /* need space for '\0' */ YankPos = KillPos; if (KillRingLen < KillRingMax) KillRingLen++; pos = &KillRing[KillPos]; KillPos = (KillPos + 1) % KillRingMax; if (pos->len < len) { pos->buf = xrealloc(pos->buf, len * sizeof(Char)); pos->len = len; } cp = start; kp = pos->buf; while (cp < end) *kp++ = *cp++; *kp = '\0'; } /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */ static void c_save_inputbuf() { SavedBuf.len = 0; Strbuf_append(&SavedBuf, InputBuf); Strbuf_terminate(&SavedBuf); LastSaved = LastChar - InputBuf; CursSaved = Cursor - InputBuf; HistSaved = Hist_num; RestoreSaved = 1; } CCRETVAL GetHistLine() { struct Hist *hp; int h; if (Hist_num == 0) { /* if really the current line */ if (HistBuf.s != NULL) copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/ else *InputBuf = '\0'; LastChar = InputBuf + HistBuf.len; #ifdef KSHVI if (VImode) Cursor = InputBuf; else #endif /* KSHVI */ Cursor = LastChar; return(CC_REFRESH); } hp = Histlist.Hnext; if (hp == NULL) return(CC_ERROR); for (h = 1; h < Hist_num; h++) { if ((hp->Hnext) == NULL) { Hist_num = h; return(CC_ERROR); } hp = hp->Hnext; } if (HistLit && hp->histline) { copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/ CurrentHistLit = 1; } else { Char *p; p = sprlex(&hp->Hlex); copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/ xfree(p); CurrentHistLit = 0; } LastChar = Strend(InputBuf); if (LastChar > InputBuf) { if (LastChar[-1] == '\n') LastChar--; #if 0 if (LastChar[-1] == ' ') LastChar--; #endif if (LastChar < InputBuf) LastChar = InputBuf; } #ifdef KSHVI if (VImode) Cursor = InputBuf; else #endif /* KSHVI */ Cursor = LastChar; return(CC_REFRESH); } static CCRETVAL c_search_line(Char *pattern, int dir) { Char *cp; size_t len; len = Strlen(pattern); if (dir == F_UP_SEARCH_HIST) { for (cp = Cursor; cp >= InputBuf; cp--) if (Strncmp(cp, pattern, len) == 0 || Gmatch(cp, pattern)) { Cursor = cp; return(CC_NORM); } return(CC_ERROR); } else { for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++) if (Strncmp(cp, pattern, len) == 0 || Gmatch(cp, pattern)) { Cursor = cp; return(CC_NORM); } return(CC_ERROR); } } static CCRETVAL e_inc_search(int dir) { static const Char STRfwd[] = { 'f', 'w', 'd', '\0' }, STRbck[] = { 'b', 'c', 'k', '\0' }; static Char pchar = ':'; /* ':' = normal, '?' = failed */ static Char endcmd[2]; const Char *cp; Char ch, *oldCursor = Cursor, oldpchar = pchar; CCRETVAL ret = CC_NORM; int oldHist_num = Hist_num, oldpatlen = patbuf.len, newdir = dir, done, redo; if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim) return(CC_ERROR); for (;;) { if (patbuf.len == 0) { /* first round */ pchar = ':'; Strbuf_append1(&patbuf, '*'); } done = redo = 0; *LastChar++ = '\n'; for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd; *cp; *LastChar++ = *cp++) continue; *LastChar++ = pchar; for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len]; *LastChar++ = *cp++) continue; *LastChar = '\0'; if (adrof(STRhighlight) && pchar == ':') { /* if the no-glob-search patch is applied, remove the - 1 below */ IncMatchLen = patbuf.len - 1; ClearLines(); ClearDisp(); } Refresh(); if (GetNextChar(&ch) != 1) return(e_send_eof(0)); switch (ch > NT_NUM_KEYS ? F_INSERT : CurrentKeyMap[(unsigned char) ch]) { case F_INSERT: case F_DIGIT: case F_MAGIC_SPACE: if (LastChar + 1 >= InputLim) /*FIXBUF*/ SoundBeep(); else { Strbuf_append1(&patbuf, ch); *LastChar++ = ch; *LastChar = '\0'; Refresh(); } break; case F_INC_FWD: newdir = F_DOWN_SEARCH_HIST; redo++; break; case F_INC_BACK: newdir = F_UP_SEARCH_HIST; redo++; break; case F_DELPREV: if (patbuf.len > 1) done++; else SoundBeep(); break; default: switch (ASC(ch)) { case 0007: /* ^G: Abort */ ret = CC_ERROR; done++; break; case 0027: /* ^W: Append word */ /* No can do if globbing characters in pattern */ for (cp = &patbuf.s[1]; ; cp++) if (cp >= &patbuf.s[patbuf.len]) { Cursor += patbuf.len - 1; cp = c_next_word(Cursor, LastChar, 1); while (Cursor < cp && *Cursor != '\n') { if (LastChar + 1 >= InputLim) {/*FIXBUF*/ SoundBeep(); break; } Strbuf_append1(&patbuf, *Cursor); *LastChar++ = *Cursor++; } Cursor = oldCursor; *LastChar = '\0'; Refresh(); break; } else if (isglob(*cp)) { SoundBeep(); break; } break; default: /* Terminate and execute cmd */ endcmd[0] = ch; PushMacro(endcmd); /*FALLTHROUGH*/ case 0033: /* ESC: Terminate */ ret = CC_REFRESH; done++; break; } break; } while (LastChar > InputBuf && *LastChar != '\n') *LastChar-- = '\0'; *LastChar = '\0'; if (!done) { /* Can't search if unmatched '[' */ for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--) if (*cp == '[' || *cp == ']') { ch = *cp; break; } if (patbuf.len > 1 && ch != '[') { if (redo && newdir == dir) { if (pchar == '?') { /* wrap around */ Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX; if (GetHistLine() == CC_ERROR) /* Hist_num was fixed by first call */ (void) GetHistLine(); Cursor = newdir == F_UP_SEARCH_HIST ? LastChar : InputBuf; } else Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1; } Strbuf_append1(&patbuf, '*'); Strbuf_terminate(&patbuf); if (Cursor < InputBuf || Cursor > LastChar || (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) { LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */ ret = newdir == F_UP_SEARCH_HIST ? e_up_search_hist(0) : e_down_search_hist(0); if (ret != CC_ERROR) { Cursor = newdir == F_UP_SEARCH_HIST ? LastChar : InputBuf; (void) c_search_line(&patbuf.s[1], newdir); } } patbuf.s[--patbuf.len] = '\0'; if (ret == CC_ERROR) { SoundBeep(); if (Hist_num != oldHist_num) { Hist_num = oldHist_num; if (GetHistLine() == CC_ERROR) return(CC_ERROR); } Cursor = oldCursor; pchar = '?'; } else { pchar = ':'; } } ret = e_inc_search(newdir); if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') { /* break abort of failed search at last non-failed */ ret = CC_NORM; } } if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) { /* restore on normal return or error exit */ pchar = oldpchar; patbuf.len = oldpatlen; if (Hist_num != oldHist_num) { Hist_num = oldHist_num; if (GetHistLine() == CC_ERROR) return(CC_ERROR); } Cursor = oldCursor; if (ret == CC_ERROR) Refresh(); } if (done || ret != CC_NORM) return(ret); } } static CCRETVAL v_search(int dir) { struct Strbuf tmpbuf = Strbuf_INIT; Char ch; Char *oldbuf; Char *oldlc, *oldc; cleanup_push(&tmpbuf, Strbuf_cleanup); oldbuf = Strsave(InputBuf); cleanup_push(oldbuf, xfree); oldlc = LastChar; oldc = Cursor; Strbuf_append1(&tmpbuf, '*'); InputBuf[0] = '\0'; LastChar = InputBuf; Cursor = InputBuf; searchdir = dir; c_insert(2); /* prompt + '\n' */ *Cursor++ = '\n'; *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/'; Refresh(); for (ch = 0;ch == 0;) { if (GetNextChar(&ch) != 1) { cleanup_until(&tmpbuf); return(e_send_eof(0)); } switch (ASC(ch)) { case 0010: /* Delete and backspace */ case 0177: if (tmpbuf.len > 1) { *Cursor-- = '\0'; LastChar = Cursor; tmpbuf.len--; } else { copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/ LastChar = oldlc; Cursor = oldc; cleanup_until(&tmpbuf); return(CC_REFRESH); } Refresh(); ch = 0; break; case 0033: /* ESC */ #ifdef IS_ASCII case '\r': /* Newline */ case '\n': #else case '\012': /* ASCII Line feed */ case '\015': /* ASCII (or EBCDIC) Return */ #endif break; default: Strbuf_append1(&tmpbuf, ch); *Cursor++ = ch; LastChar = Cursor; Refresh(); ch = 0; break; } } cleanup_until(oldbuf); if (tmpbuf.len == 1) { /* * Use the old pattern, but wild-card it. */ if (patbuf.len == 0) { InputBuf[0] = '\0'; LastChar = InputBuf; Cursor = InputBuf; Refresh(); cleanup_until(&tmpbuf); return(CC_ERROR); } if (patbuf.s[0] != '*') { oldbuf = Strsave(patbuf.s); patbuf.len = 0; Strbuf_append1(&patbuf, '*'); Strbuf_append(&patbuf, oldbuf); xfree(oldbuf); Strbuf_append1(&patbuf, '*'); Strbuf_terminate(&patbuf); } } else { Strbuf_append1(&tmpbuf, '*'); Strbuf_terminate(&tmpbuf); patbuf.len = 0; Strbuf_append(&patbuf, tmpbuf.s); Strbuf_terminate(&patbuf); } cleanup_until(&tmpbuf); LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */ Cursor = LastChar = InputBuf; if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) : e_down_search_hist(0)) == CC_ERROR) { Refresh(); return(CC_ERROR); } else { if (ASC(ch) == 0033) { Refresh(); *LastChar++ = '\n'; *LastChar = '\0'; PastBottom(); return(CC_NEWLINE); } else return(CC_REFRESH); } } /* * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an * entry point, called from the CcKeyMap indirected into the * CcFuncTbl array. */ /*ARGSUSED*/ CCRETVAL v_cmd_mode(Char c) { USE(c); InsertPos = 0; ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */ ActionPos = 0; DoingArg = 0; if (UndoPtr > Cursor) UndoSize = (int)(UndoPtr - Cursor); else UndoSize = (int)(Cursor - UndoPtr); inputmode = MODE_INSERT; c_alternativ_key_map(1); #ifdef notdef /* * We don't want to move the cursor, because all the editing * commands don't include the character under the cursor. */ if (Cursor > InputBuf) Cursor--; #endif RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_unassigned(Char c) { /* bound to keys that arn't really assigned */ USE(c); SoundBeep(); flush(); return(CC_NORM); } #ifdef notyet static CCRETVAL e_insert_str(Char *c) { int i, n; n = Strlen(c); if (LastChar + Argument * n >= InputLim) return(CC_ERROR); /* end of buffer space */ if (inputmode != MODE_INSERT) { c_delafter(Argument * Strlen(c)); } c_insert(Argument * n); while (Argument--) { for (i = 0; i < n; i++) *Cursor++ = c[i]; } Refresh(); return(CC_NORM); } #endif CCRETVAL e_insert(Char c) { #ifndef SHORT_STRINGS c &= ASCII; /* no meta chars ever */ #endif if (!c) return(CC_ERROR); /* no NULs in the input ever!! */ if (LastChar + Argument >= InputLim) return(CC_ERROR); /* end of buffer space */ if (Argument == 1) { /* How was this optimized ???? */ if (inputmode != MODE_INSERT) { UndoBuf[UndoSize++] = *Cursor; UndoBuf[UndoSize] = '\0'; c_delafter(1); /* Do NOT use the saving ONE */ } c_insert(1); *Cursor++ = (Char) c; DoingArg = 0; /* just in case */ RefPlusOne(1); /* fast refresh for one char. */ } else { if (inputmode != MODE_INSERT) { int i; for(i = 0; i < Argument; i++) UndoBuf[UndoSize++] = *(Cursor + i); UndoBuf[UndoSize] = '\0'; c_delafter(Argument); /* Do NOT use the saving ONE */ } c_insert(Argument); while (Argument--) *Cursor++ = (Char) c; Refresh(); } if (inputmode == MODE_REPLACE_1) (void) v_cmd_mode(0); return(CC_NORM); } int InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */ { int len; if ((len = (int) Strlen(s)) <= 0) return -1; if (LastChar + len >= InputLim) return -1; /* end of buffer space */ c_insert(len); while (len--) *Cursor++ = *s++; return 0; } void DeleteBack(int n) /* delete the n characters before . */ { if (n <= 0) return; if (Cursor >= &InputBuf[n]) { c_delbefore(n); /* delete before dot */ } } CCRETVAL e_digit(Char c) /* gray magic here */ { if (!Isdigit(c)) return(CC_ERROR); /* no NULs in the input ever!! */ if (DoingArg) { /* if doing an arg, add this in... */ if (LastCmd == F_ARGFOUR) /* if last command was ^U */ Argument = c - '0'; else { if (Argument > 1000000) return CC_ERROR; Argument = (Argument * 10) + (c - '0'); } return(CC_ARGHACK); } else { if (LastChar + 1 >= InputLim) return CC_ERROR; /* end of buffer space */ if (inputmode != MODE_INSERT) { UndoBuf[UndoSize++] = *Cursor; UndoBuf[UndoSize] = '\0'; c_delafter(1); /* Do NOT use the saving ONE */ } c_insert(1); *Cursor++ = (Char) c; DoingArg = 0; /* just in case */ RefPlusOne(1); /* fast refresh for one char. */ } return(CC_NORM); } CCRETVAL e_argdigit(Char c) /* for ESC-n */ { #ifdef IS_ASCII c &= ASCII; #else c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */ #endif if (!Isdigit(c)) return(CC_ERROR); /* no NULs in the input ever!! */ if (DoingArg) { /* if doing an arg, add this in... */ if (Argument > 1000000) return CC_ERROR; Argument = (Argument * 10) + (c - '0'); } else { /* else starting an argument */ Argument = c - '0'; DoingArg = 1; } return(CC_ARGHACK); } CCRETVAL v_zero(Char c) /* command mode 0 for vi */ { if (DoingArg) { /* if doing an arg, add this in... */ if (Argument > 1000000) return CC_ERROR; Argument = (Argument * 10) + (c - '0'); return(CC_ARGHACK); } else { /* else starting an argument */ Cursor = InputBuf; if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); /* move the cursor */ return(CC_NORM); } } /*ARGSUSED*/ CCRETVAL e_newline(Char c) { /* always ignore argument */ USE(c); if (adrof(STRhighlight) && MarkIsSet) { MarkIsSet = 0; ClearLines(); ClearDisp(); Refresh(); } MarkIsSet = 0; /* PastBottom(); NOW done in ed.inputl.c */ *LastChar++ = '\n'; /* for the benefit of CSH */ *LastChar = '\0'; /* just in case */ if (VImode) InsertPos = InputBuf; /* Reset editing position */ return(CC_NEWLINE); } /*ARGSUSED*/ CCRETVAL e_newline_hold(Char c) { USE(c); c_save_inputbuf(); HistSaved = 0; *LastChar++ = '\n'; /* for the benefit of CSH */ *LastChar = '\0'; /* just in case */ return(CC_NEWLINE); } /*ARGSUSED*/ CCRETVAL e_newline_down_hist(Char c) { USE(c); if (Hist_num > 1) { HistSaved = Hist_num; } *LastChar++ = '\n'; /* for the benefit of CSH */ *LastChar = '\0'; /* just in case */ return(CC_NEWLINE); } /*ARGSUSED*/ CCRETVAL e_send_eof(Char c) { /* for when ^D is ONLY send-eof */ USE(c); PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_EOF); } /*ARGSUSED*/ CCRETVAL e_complete(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_COMPLETE); } /*ARGSUSED*/ CCRETVAL e_complete_back(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_COMPLETE_BACK); } /*ARGSUSED*/ CCRETVAL e_complete_fwd(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_COMPLETE_FWD); } /*ARGSUSED*/ CCRETVAL e_complete_all(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_COMPLETE_ALL); } /*ARGSUSED*/ CCRETVAL v_cm_complete(Char c) { USE(c); if (Cursor < LastChar) Cursor++; *LastChar = '\0'; /* just in case */ return(CC_COMPLETE); } /*ARGSUSED*/ CCRETVAL e_toggle_hist(Char c) { struct Hist *hp; int h; USE(c); *LastChar = '\0'; /* just in case */ if (Hist_num <= 0) { return CC_ERROR; } hp = Histlist.Hnext; if (hp == NULL) { /* this is only if no history */ return(CC_ERROR); } for (h = 1; h < Hist_num; h++) hp = hp->Hnext; if (!CurrentHistLit) { if (hp->histline) { copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/ CurrentHistLit = 1; } else { return CC_ERROR; } } else { Char *p; p = sprlex(&hp->Hlex); copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/ xfree(p); CurrentHistLit = 0; } LastChar = Strend(InputBuf); if (LastChar > InputBuf) { if (LastChar[-1] == '\n') LastChar--; if (LastChar[-1] == ' ') LastChar--; if (LastChar < InputBuf) LastChar = InputBuf; } #ifdef KSHVI if (VImode) Cursor = InputBuf; else #endif /* KSHVI */ Cursor = LastChar; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_up_hist(Char c) { Char beep = 0; USE(c); UndoAction = TCSHOP_NOP; *LastChar = '\0'; /* just in case */ if (Hist_num == 0) { /* save the current buffer away */ HistBuf.len = 0; Strbuf_append(&HistBuf, InputBuf); Strbuf_terminate(&HistBuf); } Hist_num += Argument; if (GetHistLine() == CC_ERROR) { beep = 1; (void) GetHistLine(); /* Hist_num was fixed by first call */ } Refresh(); if (beep) return(CC_ERROR); else return(CC_NORM); /* was CC_UP_HIST */ } /*ARGSUSED*/ CCRETVAL e_down_hist(Char c) { USE(c); UndoAction = TCSHOP_NOP; *LastChar = '\0'; /* just in case */ Hist_num -= Argument; if (Hist_num < 0) { Hist_num = 0; return(CC_ERROR); /* make it beep */ } return(GetHistLine()); } /* * c_hmatch() return True if the pattern matches the prefix */ static int c_hmatch(Char *str) { if (Strncmp(patbuf.s, str, patbuf.len) == 0) return 1; return Gmatch(str, patbuf.s); } /* * c_hsetpat(): Set the history seatch pattern */ static void c_hsetpat(void) { if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) { patbuf.len = 0; Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf); Strbuf_terminate(&patbuf); } #ifdef SDEBUG xprintf("\nHist_num = %d\n", Hist_num); xprintf("patlen = %d\n", (int)patbuf.len); xprintf("patbuf = \"%S\"\n", patbuf.s); xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf); #endif } /*ARGSUSED*/ CCRETVAL e_up_search_hist(Char c) { struct Hist *hp; int h; int found = 0; USE(c); ActionFlag = TCSHOP_NOP; UndoAction = TCSHOP_NOP; *LastChar = '\0'; /* just in case */ if (Hist_num < 0) { #ifdef DEBUG_EDIT xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname); #endif Hist_num = 0; return(CC_ERROR); } if (Hist_num == 0) { HistBuf.len = 0; Strbuf_append(&HistBuf, InputBuf); Strbuf_terminate(&HistBuf); } hp = Histlist.Hnext; if (hp == NULL) return(CC_ERROR); c_hsetpat(); /* Set search pattern !! */ for (h = 1; h <= Hist_num; h++) hp = hp->Hnext; while (hp != NULL) { Char *hl; int matched; if (hp->histline == NULL) hp->histline = sprlex(&hp->Hlex); if (HistLit) hl = hp->histline; else { hl = sprlex(&hp->Hlex); cleanup_push(hl, xfree); } #ifdef SDEBUG xprintf("Comparing with \"%S\"\n", hl); #endif matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) || hl[LastChar-InputBuf]) && c_hmatch(hl); if (!HistLit) cleanup_until(hl); if (matched) { found++; break; } h++; hp = hp->Hnext; } if (!found) { #ifdef SDEBUG xprintf("not found\n"); #endif return(CC_ERROR); } Hist_num = h; return(GetHistLine()); } /*ARGSUSED*/ CCRETVAL e_down_search_hist(Char c) { struct Hist *hp; int h; int found = 0; USE(c); ActionFlag = TCSHOP_NOP; UndoAction = TCSHOP_NOP; *LastChar = '\0'; /* just in case */ if (Hist_num == 0) return(CC_ERROR); hp = Histlist.Hnext; if (hp == 0) return(CC_ERROR); c_hsetpat(); /* Set search pattern !! */ for (h = 1; h < Hist_num && hp; h++) { Char *hl; if (hp->histline == NULL) hp->histline = sprlex(&hp->Hlex); if (HistLit) hl = hp->histline; else { hl = sprlex(&hp->Hlex); cleanup_push(hl, xfree); } #ifdef SDEBUG xprintf("Comparing with \"%S\"\n", hl); #endif if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) || hl[LastChar-InputBuf]) && c_hmatch(hl)) found = h; if (!HistLit) cleanup_until(hl); hp = hp->Hnext; } if (!found) { /* is it the current history number? */ if (!c_hmatch(HistBuf.s)) { #ifdef SDEBUG xprintf("not found\n"); #endif return(CC_ERROR); } } Hist_num = found; return(GetHistLine()); } /*ARGSUSED*/ CCRETVAL e_helpme(Char c) { USE(c); PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_HELPME); } /*ARGSUSED*/ CCRETVAL e_correct(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_CORRECT); } /*ARGSUSED*/ CCRETVAL e_correctl(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_CORRECT_L); } /*ARGSUSED*/ CCRETVAL e_run_fg_editor(Char c) { struct process *pp; USE(c); if ((pp = find_stop_ed()) != NULL) { /* save our editor state so we can restore it */ c_save_inputbuf(); Hist_num = 0; /* for the history commands */ /* put the tty in a sane mode */ PastBottom(); (void) Cookedmode(); /* make sure the tty is set up correctly */ /* do it! */ fg_proc_entry(pp); (void) Rawmode(); /* go on */ Refresh(); RestoreSaved = 0; HistSaved = 0; } return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_list_choices(Char c) { USE(c); PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_LIST_CHOICES); } /*ARGSUSED*/ CCRETVAL e_list_all(Char c) { USE(c); PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_LIST_ALL); } /*ARGSUSED*/ CCRETVAL e_list_glob(Char c) { USE(c); PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_LIST_GLOB); } /*ARGSUSED*/ CCRETVAL e_expand_glob(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_EXPAND_GLOB); } /*ARGSUSED*/ CCRETVAL e_normalize_path(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_NORMALIZE_PATH); } /*ARGSUSED*/ CCRETVAL e_normalize_command(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_NORMALIZE_COMMAND); } /*ARGSUSED*/ CCRETVAL e_expand_vars(Char c) { USE(c); *LastChar = '\0'; /* just in case */ return(CC_EXPAND_VARS); } /*ARGSUSED*/ CCRETVAL e_which(Char c) { /* do a fast command line which(1) */ USE(c); c_save_inputbuf(); Hist_num = 0; /* for the history commands */ PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_WHICH); } /*ARGSUSED*/ CCRETVAL e_last_item(Char c) { /* insert the last element of the prev. cmd */ struct Hist *hp; struct wordent *wp, *firstp; int i; Char *expanded; USE(c); if (Argument <= 0) return(CC_ERROR); hp = Histlist.Hnext; if (hp == NULL) { /* this is only if no history */ return(CC_ERROR); } wp = (hp->Hlex).prev; if (wp->prev == (struct wordent *) NULL) return(CC_ERROR); /* an empty history entry */ firstp = (hp->Hlex).next; /* back up arg words in lex */ for (i = 0; i < Argument && wp != firstp; i++) { wp = wp->prev; } expanded = expand_lex(wp->prev, 0, i - 1); if (InsertStr(expanded)) { xfree(expanded); return(CC_ERROR); } xfree(expanded); return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_dabbrev_expand(Char c) { /* expand to preceding word matching prefix */ Char *cp, *ncp, *bp; struct Hist *hp; int arg = 0, i; size_t len = 0; int found = 0; Char *hbuf; static int oldevent, hist, word; static Char *start, *oldcursor; USE(c); if (Argument <= 0) return(CC_ERROR); cp = c_preword(Cursor, InputBuf, 1, STRshwordsep); if (cp == Cursor || Isspace(*cp)) return(CC_ERROR); hbuf = NULL; hp = Histlist.Hnext; bp = InputBuf; if (Argument == 1 && eventno == oldevent && cp == start && Cursor == oldcursor && patbuf.len > 0 && Strncmp(patbuf.s, cp, patbuf.len) == 0){ /* continue previous search - go to last match (hist/word) */ if (hist != 0) { /* need to move up history */ for (i = 1; i < hist && hp != NULL; i++) hp = hp->Hnext; if (hp == NULL) /* "can't happen" */ goto err_hbuf; hbuf = expand_lex(&hp->Hlex, 0, INT_MAX); cp = Strend(hbuf); bp = hbuf; hp = hp->Hnext; } cp = c_preword(cp, bp, word, STRshwordsep); } else { /* starting new search */ oldevent = eventno; start = cp; patbuf.len = 0; Strbuf_appendn(&patbuf, cp, Cursor - cp); hist = 0; word = 0; } while (!found) { ncp = c_preword(cp, bp, 1, STRshwordsep); if (ncp == cp || Isspace(*ncp)) { /* beginning of line */ hist++; word = 0; if (hp == NULL) goto err_hbuf; hbuf = expand_lex(&hp->Hlex, 0, INT_MAX); cp = Strend(hbuf); bp = hbuf; hp = hp->Hnext; continue; } else { word++; len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1; cp = ncp; } if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) { /* We don't fully check distinct matches as Gnuemacs does: */ if (Argument > 1) { /* just count matches */ if (++arg >= Argument) found++; } else { /* match if distinct from previous */ if (len != (size_t)(Cursor - start) || Strncmp(cp, start, len) != 0) found++; } } } if (LastChar + len - (Cursor - start) >= InputLim) goto err_hbuf; /* no room */ DeleteBack(Cursor - start); c_insert(len); while (len--) *Cursor++ = *cp++; oldcursor = Cursor; xfree(hbuf); return(CC_REFRESH); err_hbuf: xfree(hbuf); return CC_ERROR; } /*ARGSUSED*/ CCRETVAL e_yank_kill(Char c) { /* almost like GnuEmacs */ int len; Char *kp, *cp; USE(c); if (KillRingLen == 0) /* nothing killed */ return(CC_ERROR); len = Strlen(KillRing[YankPos].buf); if (LastChar + len >= InputLim) return(CC_ERROR); /* end of buffer space */ /* else */ cp = Cursor; /* for speed */ c_insert(len); /* open the space, */ for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */ *cp++ = *kp; if (Argument == 1) { /* if no arg */ Mark = Cursor; /* mark at beginning, cursor at end */ Cursor = cp; } else { Mark = cp; /* else cursor at beginning, mark at end */ } if (adrof(STRhighlight) && MarkIsSet) { ClearLines(); ClearDisp(); } MarkIsSet = 0; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_yank_pop(Char c) { /* almost like GnuEmacs */ int m_bef_c, del_len, ins_len; Char *kp, *cp; USE(c); #if 0 /* XXX This "should" be here, but doesn't work, since LastCmd gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?). (But what about F_ARGFOUR?) I.e. if you hit M-y twice the second one will "succeed" even if the first one wasn't preceded by a yank, and giving an argument is impossible. Now we "succeed" regardless of previous command, which is wrong too of course. */ if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP) return(CC_ERROR); #endif if (KillRingLen == 0) /* nothing killed */ return(CC_ERROR); YankPos -= Argument; while (YankPos < 0) YankPos += KillRingLen; YankPos %= KillRingLen; if (Cursor > Mark) { del_len = Cursor - Mark; m_bef_c = 1; } else { del_len = Mark - Cursor; m_bef_c = 0; } ins_len = Strlen(KillRing[YankPos].buf); if (LastChar + ins_len - del_len >= InputLim) return(CC_ERROR); /* end of buffer space */ if (m_bef_c) { c_delbefore(del_len); } else { c_delafter(del_len); } cp = Cursor; /* for speed */ c_insert(ins_len); /* open the space, */ for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */ *cp++ = *kp; if (m_bef_c) { Mark = Cursor; /* mark at beginning, cursor at end */ Cursor = cp; } else { Mark = cp; /* else cursor at beginning, mark at end */ } if (adrof(STRhighlight) && MarkIsSet) { ClearLines(); ClearDisp(); } MarkIsSet = 0; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL v_delprev(Char c) /* Backspace key in insert mode */ { int rc; USE(c); rc = CC_ERROR; if (InsertPos != 0) { if (Argument <= Cursor - InsertPos) { c_delbefore(Argument); /* delete before */ rc = CC_REFRESH; } } return(rc); } /* v_delprev */ /*ARGSUSED*/ CCRETVAL e_delprev(Char c) { USE(c); if (Cursor > InputBuf) { c_delbefore(Argument); /* delete before dot */ return(CC_REFRESH); } else { return(CC_ERROR); } } /*ARGSUSED*/ CCRETVAL e_delwordprev(Char c) { Char *cp; USE(c); if (Cursor == InputBuf) return(CC_ERROR); /* else */ cp = c_prev_word(Cursor, InputBuf, Argument); c_push_kill(cp, Cursor); /* save the text */ c_delbefore((int)(Cursor - cp)); /* delete before dot */ return(CC_REFRESH); } /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93 * * Changed the names of some of the ^D family of editor functions to * correspond to what they actually do and created new e_delnext_list * for completeness. * * Old names: New names: * * delete-char delete-char-or-eof * F_DELNEXT F_DELNEXT_EOF * e_delnext e_delnext_eof * edelnxt edelnxteof * delete-char-or-eof delete-char * F_DELNEXT_EOF F_DELNEXT * e_delnext_eof e_delnext * edelnxteof edelnxt * delete-char-or-list delete-char-or-list-or-eof * F_LIST_DELNEXT F_DELNEXT_LIST_EOF * e_list_delnext e_delnext_list_eof * edellsteof * (no old equivalent) delete-char-or-list * F_DELNEXT_LIST * e_delnext_list * e_delnxtlst */ /* added by mtk@ari.ncl.omron.co.jp (920818) */ /* rename e_delnext() -> e_delnext_eof() */ /*ARGSUSED*/ CCRETVAL e_delnext(Char c) { USE(c); if (Cursor == LastChar) {/* if I'm at the end */ if (!VImode) { return(CC_ERROR); } else { if (Cursor != InputBuf) Cursor--; else return(CC_ERROR); } } c_delafter(Argument); /* delete after dot */ if (Cursor > LastChar) Cursor = LastChar; /* bounds check */ return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_delnext_eof(Char c) { USE(c); if (Cursor == LastChar) {/* if I'm at the end */ if (!VImode) { if (Cursor == InputBuf) { /* if I'm also at the beginning */ so_write(STReof, 4);/* then do a EOF */ flush(); return(CC_EOF); } else return(CC_ERROR); } else { if (Cursor != InputBuf) Cursor--; else return(CC_ERROR); } } c_delafter(Argument); /* delete after dot */ if (Cursor > LastChar) Cursor = LastChar; /* bounds check */ return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_delnext_list(Char c) { USE(c); if (Cursor == LastChar) { /* if I'm at the end */ PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_LIST_CHOICES); } else { c_delafter(Argument); /* delete after dot */ if (Cursor > LastChar) Cursor = LastChar; /* bounds check */ return(CC_REFRESH); } } /*ARGSUSED*/ CCRETVAL e_delnext_list_eof(Char c) { USE(c); if (Cursor == LastChar) { /* if I'm at the end */ if (Cursor == InputBuf) { /* if I'm also at the beginning */ so_write(STReof, 4);/* then do a EOF */ flush(); return(CC_EOF); } else { PastBottom(); *LastChar = '\0'; /* just in case */ return(CC_LIST_CHOICES); } } else { c_delafter(Argument); /* delete after dot */ if (Cursor > LastChar) Cursor = LastChar; /* bounds check */ return(CC_REFRESH); } } /*ARGSUSED*/ CCRETVAL e_list_eof(Char c) { CCRETVAL rv; USE(c); if (Cursor == LastChar && Cursor == InputBuf) { so_write(STReof, 4); /* then do a EOF */ flush(); rv = CC_EOF; } else { PastBottom(); *LastChar = '\0'; /* just in case */ rv = CC_LIST_CHOICES; } return rv; } /*ARGSUSED*/ CCRETVAL e_delwordnext(Char c) { Char *cp; USE(c); if (Cursor == LastChar) return(CC_ERROR); /* else */ cp = c_next_word(Cursor, LastChar, Argument); c_push_kill(Cursor, cp); /* save the text */ c_delafter((int)(cp - Cursor)); /* delete after dot */ if (Cursor > LastChar) Cursor = LastChar; /* bounds check */ return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_toend(Char c) { USE(c); Cursor = LastChar; if (VImode) if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); /* move the cursor */ return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_tobeg(Char c) { USE(c); Cursor = InputBuf; if (VImode) { while (Isspace(*Cursor)) /* We want FIRST non space character */ Cursor++; if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } } RefCursor(); /* move the cursor */ return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_killend(Char c) { USE(c); c_push_kill(Cursor, LastChar); /* copy it */ LastChar = Cursor; /* zap! -- delete to end */ if (Mark > Cursor) Mark = Cursor; MarkIsSet = 0; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_killbeg(Char c) { USE(c); c_push_kill(InputBuf, Cursor); /* copy it */ c_delbefore((int)(Cursor - InputBuf)); if (Mark && Mark > Cursor) Mark -= Cursor-InputBuf; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_killall(Char c) { USE(c); c_push_kill(InputBuf, LastChar); /* copy it */ Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */ MarkIsSet = 0; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_killregion(Char c) { USE(c); if (!Mark) return(CC_ERROR); if (Mark > Cursor) { c_push_kill(Cursor, Mark); /* copy it */ c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */ Mark = Cursor; } else { /* mark is before cursor */ c_push_kill(Mark, Cursor); /* copy it */ c_delbefore((int)(Cursor - Mark)); } if (adrof(STRhighlight) && MarkIsSet) { ClearLines(); ClearDisp(); } MarkIsSet = 0; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_copyregion(Char c) { USE(c); if (!Mark) return(CC_ERROR); if (Mark > Cursor) { c_push_kill(Cursor, Mark); /* copy it */ } else { /* mark is before cursor */ c_push_kill(Mark, Cursor); /* copy it */ } return(CC_NORM); /* don't even need to Refresh() */ } /*ARGSUSED*/ CCRETVAL e_charswitch(Char cc) { Char c; USE(cc); /* do nothing if we are at beginning of line or have only one char */ if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) { return(CC_ERROR); } if (Cursor < LastChar) { Cursor++; } c = Cursor[-2]; Cursor[-2] = Cursor[-1]; Cursor[-1] = c; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_gcharswitch(Char cc) { /* gosmacs style ^T */ Char c; USE(cc); if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */ c = Cursor[-2]; Cursor[-2] = Cursor[-1]; Cursor[-1] = c; return(CC_REFRESH); } else { return(CC_ERROR); } } /*ARGSUSED*/ CCRETVAL e_charback(Char c) { USE(c); if (Cursor > InputBuf) { if (Argument > Cursor - InputBuf) Cursor = InputBuf; else Cursor -= Argument; if (VImode) if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } else { return(CC_ERROR); } } /*ARGSUSED*/ CCRETVAL v_wordback(Char c) { USE(c); if (Cursor == InputBuf) return(CC_ERROR); /* else */ Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */ if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_wordback(Char c) { USE(c); if (Cursor == InputBuf) return(CC_ERROR); /* else */ Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */ if (VImode) if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_charfwd(Char c) { USE(c); if (Cursor < LastChar) { Cursor += Argument; if (Cursor > LastChar) Cursor = LastChar; if (VImode) if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } else { return(CC_ERROR); } } /*ARGSUSED*/ CCRETVAL e_wordfwd(Char c) { USE(c); if (Cursor == LastChar) return(CC_ERROR); /* else */ Cursor = c_next_word(Cursor, LastChar, Argument); if (VImode) if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_wordfwd(Char c) { USE(c); if (Cursor == LastChar) return(CC_ERROR); /* else */ Cursor = c_nexword(Cursor, LastChar, Argument); if (VImode) if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_wordbegnext(Char c) { USE(c); if (Cursor == LastChar) return(CC_ERROR); /* else */ Cursor = c_next_word(Cursor, LastChar, Argument); if (Cursor < LastChar) Cursor++; if (VImode) if (ActionFlag & TCSHOP_DELETE) { c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ static CCRETVAL v_repeat_srch(int c) { CCRETVAL rv = CC_ERROR; #ifdef SDEBUG xprintf("dir %d patlen %d patbuf %S\n", c, (int)patbuf.len, patbuf.s); #endif LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */ LastChar = InputBuf; switch (c) { case F_DOWN_SEARCH_HIST: rv = e_down_search_hist(0); break; case F_UP_SEARCH_HIST: rv = e_up_search_hist(0); break; default: break; } return rv; } static CCRETVAL v_csearch_back(Char ch, int count, int tflag) { Char *cp; cp = Cursor; while (count--) { if (*cp == ch) cp--; while (cp > InputBuf && *cp != ch) cp--; } if (cp < InputBuf || (cp == InputBuf && *cp != ch)) return(CC_ERROR); if (*cp == ch && tflag) cp++; Cursor = cp; if (ActionFlag & TCSHOP_DELETE) { Cursor++; c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } static CCRETVAL v_csearch_fwd(Char ch, int count, int tflag) { Char *cp; cp = Cursor; while (count--) { if(*cp == ch) cp++; while (cp < LastChar && *cp != ch) cp++; } if (cp >= LastChar) return(CC_ERROR); if (*cp == ch && tflag) cp--; Cursor = cp; if (ActionFlag & TCSHOP_DELETE) { Cursor++; c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ static CCRETVAL v_action(int c) { Char *cp, *kp; if (ActionFlag == TCSHOP_DELETE) { ActionFlag = TCSHOP_NOP; ActionPos = 0; UndoSize = 0; kp = UndoBuf; for (cp = InputBuf; cp < LastChar; cp++) { *kp++ = *cp; UndoSize++; } UndoAction = TCSHOP_INSERT; UndoPtr = InputBuf; LastChar = InputBuf; Cursor = InputBuf; if (c & TCSHOP_INSERT) c_alternativ_key_map(0); return(CC_REFRESH); } #ifdef notdef else if (ActionFlag == TCSHOP_NOP) { #endif ActionPos = Cursor; ActionFlag = c; return(CC_ARGHACK); /* Do NOT clear out argument */ #ifdef notdef } else { ActionFlag = 0; ActionPos = 0; return(CC_ERROR); } #endif } #ifdef COMMENT /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */ static void c_get_word(Char **begin, Char **end) { Char *cp; cp = &Cursor[0]; while (Argument--) { while ((cp <= LastChar) && (isword(*cp))) cp++; *end = --cp; while ((cp >= InputBuf) && (isword(*cp))) cp--; *begin = ++cp; } } #endif /* COMMENT */ /*ARGSUSED*/ CCRETVAL e_uppercase(Char c) { Char *cp, *end; USE(c); end = c_next_word(Cursor, LastChar, Argument); for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */ if (Islower(*cp)) *cp = Toupper(*cp); Cursor = end; if (Cursor > LastChar) Cursor = LastChar; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_capitolcase(Char c) { Char *cp, *end; USE(c); end = c_next_word(Cursor, LastChar, Argument); cp = Cursor; for (; cp < end; cp++) { if (Isalpha(*cp)) { if (Islower(*cp)) *cp = Toupper(*cp); cp++; break; } } for (; cp < end; cp++) if (Isupper(*cp)) *cp = Tolower(*cp); Cursor = end; if (Cursor > LastChar) Cursor = LastChar; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_lowercase(Char c) { Char *cp, *end; USE(c); end = c_next_word(Cursor, LastChar, Argument); for (cp = Cursor; cp < end; cp++) if (Isupper(*cp)) *cp = Tolower(*cp); Cursor = end; if (Cursor > LastChar) Cursor = LastChar; return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_set_mark(Char c) { USE(c); if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) { ClearLines(); ClearDisp(); Refresh(); } Mark = Cursor; MarkIsSet = 1; return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_exchange_mark(Char c) { Char *cp; USE(c); cp = Cursor; Cursor = Mark; Mark = cp; RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_argfour(Char c) { /* multiply current argument by 4 */ USE(c); if (Argument > 1000000) return CC_ERROR; DoingArg = 1; Argument *= 4; return(CC_ARGHACK); } static void quote_mode_cleanup(void *unused) { USE(unused); QuoteModeOff(); } /*ARGSUSED*/ CCRETVAL e_quote(Char c) { Char ch; int num; USE(c); QuoteModeOn(); cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */ num = GetNextChar(&ch); cleanup_until(&c); if (num == 1) return e_insert(ch); else return e_send_eof(0); } /*ARGSUSED*/ CCRETVAL e_metanext(Char c) { USE(c); MetaNext = 1; return(CC_ARGHACK); /* preserve argument */ } #ifdef notdef /*ARGSUSED*/ CCRETVAL e_extendnext(Char c) { CurrentKeyMap = CcAltMap; return(CC_ARGHACK); /* preserve argument */ } #endif /*ARGSUSED*/ CCRETVAL v_insbeg(Char c) { /* move to beginning of line and start vi * insert mode */ USE(c); Cursor = InputBuf; InsertPos = Cursor; UndoPtr = Cursor; UndoAction = TCSHOP_DELETE; RefCursor(); /* move the cursor */ c_alternativ_key_map(0); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_replone(Char c) { /* vi mode overwrite one character */ USE(c); c_alternativ_key_map(0); inputmode = MODE_REPLACE_1; UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */ UndoPtr = Cursor; UndoSize = 0; return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_replmode(Char c) { /* vi mode start overwriting */ USE(c); c_alternativ_key_map(0); inputmode = MODE_REPLACE; UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */ UndoPtr = Cursor; UndoSize = 0; return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_substchar(Char c) { /* vi mode substitute for one char */ USE(c); c_delafter(Argument); c_alternativ_key_map(0); return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL v_substline(Char c) { /* vi mode replace whole line */ USE(c); (void) e_killall(0); c_alternativ_key_map(0); return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL v_chgtoend(Char c) { /* vi mode change to end of line */ USE(c); (void) e_killend(0); c_alternativ_key_map(0); return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL v_insert(Char c) { /* vi mode start inserting */ USE(c); c_alternativ_key_map(0); InsertPos = Cursor; UndoPtr = Cursor; UndoAction = TCSHOP_DELETE; return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_add(Char c) { /* vi mode start adding */ USE(c); c_alternativ_key_map(0); if (Cursor < LastChar) { Cursor++; if (Cursor > LastChar) Cursor = LastChar; RefCursor(); } InsertPos = Cursor; UndoPtr = Cursor; UndoAction = TCSHOP_DELETE; return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_addend(Char c) { /* vi mode to add at end of line */ USE(c); c_alternativ_key_map(0); Cursor = LastChar; InsertPos = LastChar; /* Mark where insertion begins */ UndoPtr = LastChar; UndoAction = TCSHOP_DELETE; RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_change_case(Char cc) { Char c; USE(cc); if (Cursor < LastChar) { #ifndef WINNT_NATIVE c = *Cursor; #else c = CHAR & *Cursor; #endif /* WINNT_NATIVE */ if (Isupper(c)) *Cursor++ = Tolower(c); else if (Islower(c)) *Cursor++ = Toupper(c); else Cursor++; RefPlusOne(1); /* fast refresh for one char */ return(CC_NORM); } return(CC_ERROR); } /*ARGSUSED*/ CCRETVAL e_expand(Char c) { Char *p; USE(c); for (p = InputBuf; Isspace(*p); p++) continue; if (p == LastChar) return(CC_ERROR); justpr++; Expand++; return(e_newline(0)); } /*ARGSUSED*/ CCRETVAL e_startover(Char c) { /* erase all of current line, start again */ USE(c); ResetInLine(0); /* reset the input pointers */ return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_redisp(Char c) { USE(c); ClearLines(); ClearDisp(); return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_cleardisp(Char c) { USE(c); ClearScreen(); /* clear the whole real screen */ ClearDisp(); /* reset everything */ return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_tty_int(Char c) { USE(c); #if defined(_MINIX) || defined(WINNT_NATIVE) /* SAK PATCH: erase all of current line, start again */ ResetInLine(0); /* reset the input pointers */ xputchar('\n'); ClearDisp(); return (CC_REFRESH); #else /* !_MINIX && !WINNT_NATIVE */ /* do no editing */ return (CC_NORM); #endif /* _MINIX || WINNT_NATIVE */ } /* * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi) * Function to send a character back to the input stream in cooked * mode. Only works if we have TIOCSTI */ /*ARGSUSED*/ CCRETVAL e_stuff_char(Char c) { #ifdef TIOCSTI int was_raw = Tty_raw_mode; char buf[MB_LEN_MAX]; size_t i, len; if (was_raw) (void) Cookedmode(); (void) xwrite(SHIN, "\n", 1); len = one_wctomb(buf, c & CHAR); for (i = 0; i < len; i++) (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]); if (was_raw) (void) Rawmode(); return(e_redisp(c)); #else /* !TIOCSTI */ return(CC_ERROR); #endif /* !TIOCSTI */ } /*ARGSUSED*/ CCRETVAL e_insovr(Char c) { USE(c); inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_tty_dsusp(Char c) { USE(c); /* do no editing */ return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_tty_flusho(Char c) { USE(c); /* do no editing */ return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_tty_quit(Char c) { USE(c); /* do no editing */ return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_tty_tsusp(Char c) { USE(c); /* do no editing */ return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_tty_stopo(Char c) { USE(c); /* do no editing */ return(CC_NORM); } /* returns the number of (attempted) expansions */ int ExpandHistory(void) { *LastChar = '\0'; /* just in case */ return c_substitute(); } /*ARGSUSED*/ CCRETVAL e_expand_history(Char c) { USE(c); (void)ExpandHistory(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_magic_space(Char c) { USE(c); *LastChar = '\0'; /* just in case */ (void)c_substitute(); return(e_insert(' ')); } /*ARGSUSED*/ CCRETVAL e_inc_fwd(Char c) { CCRETVAL ret; USE(c); patbuf.len = 0; MarkIsSet = 0; ret = e_inc_search(F_DOWN_SEARCH_HIST); if (adrof(STRhighlight) && IncMatchLen) { IncMatchLen = 0; ClearLines(); ClearDisp(); Refresh(); } IncMatchLen = 0; return ret; } /*ARGSUSED*/ CCRETVAL e_inc_back(Char c) { CCRETVAL ret; USE(c); patbuf.len = 0; MarkIsSet = 0; ret = e_inc_search(F_UP_SEARCH_HIST); if (adrof(STRhighlight) && IncMatchLen) { IncMatchLen = 0; ClearLines(); ClearDisp(); Refresh(); } IncMatchLen = 0; return ret; } /*ARGSUSED*/ CCRETVAL e_copyprev(Char c) { Char *cp, *oldc, *dp; USE(c); if (Cursor == InputBuf) return(CC_ERROR); /* else */ oldc = Cursor; /* does a bounds check */ cp = c_prev_word(Cursor, InputBuf, Argument); c_insert((int)(oldc - cp)); for (dp = oldc; cp < oldc && dp < LastChar; cp++) *dp++ = *cp; Cursor = dp; /* put cursor at end */ return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL e_tty_starto(Char c) { USE(c); /* do no editing */ return(CC_NORM); } /*ARGSUSED*/ CCRETVAL e_load_average(Char c) { USE(c); PastBottom(); #ifdef TIOCSTAT /* * Here we pass &c to the ioctl because some os's (NetBSD) expect it * there even if they don't use it. (lukem@netbsd.org) */ if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0) #endif xprintf("%s", CGETS(5, 1, "Load average unavailable\n")); return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL v_chgmeta(Char c) { USE(c); /* * Delete with insert == change: first we delete and then we leave in * insert mode. */ return(v_action(TCSHOP_DELETE|TCSHOP_INSERT)); } /*ARGSUSED*/ CCRETVAL v_delmeta(Char c) { USE(c); return(v_action(TCSHOP_DELETE)); } /*ARGSUSED*/ CCRETVAL v_endword(Char c) { USE(c); if (Cursor == LastChar) return(CC_ERROR); /* else */ Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace); if (ActionFlag & TCSHOP_DELETE) { Cursor++; c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_eword(Char c) { USE(c); if (Cursor == LastChar) return(CC_ERROR); /* else */ Cursor = c_eword(Cursor, LastChar, Argument); if (ActionFlag & TCSHOP_DELETE) { Cursor++; c_delfini(); return(CC_REFRESH); } RefCursor(); return(CC_NORM); } /*ARGSUSED*/ CCRETVAL v_char_fwd(Char c) { Char ch; USE(c); if (GetNextChar(&ch) != 1) return e_send_eof(0); srch_dir = CHAR_FWD; srch_char = ch; return v_csearch_fwd(ch, Argument, 0); } /*ARGSUSED*/ CCRETVAL v_char_back(Char c) { Char ch; USE(c); if (GetNextChar(&ch) != 1) return e_send_eof(0); srch_dir = CHAR_BACK; srch_char = ch; return v_csearch_back(ch, Argument, 0); } /*ARGSUSED*/ CCRETVAL v_charto_fwd(Char c) { Char ch; USE(c); if (GetNextChar(&ch) != 1) return e_send_eof(0); return v_csearch_fwd(ch, Argument, 1); } /*ARGSUSED*/ CCRETVAL v_charto_back(Char c) { Char ch; USE(c); if (GetNextChar(&ch) != 1) return e_send_eof(0); return v_csearch_back(ch, Argument, 1); } /*ARGSUSED*/ CCRETVAL v_rchar_fwd(Char c) { USE(c); if (srch_char == 0) return CC_ERROR; return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) : v_csearch_back(srch_char, Argument, 0); } /*ARGSUSED*/ CCRETVAL v_rchar_back(Char c) { USE(c); if (srch_char == 0) return CC_ERROR; return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) : v_csearch_back(srch_char, Argument, 0); } /*ARGSUSED*/ CCRETVAL v_undo(Char c) { int loop; Char *kp, *cp; Char temp; int size; USE(c); switch (UndoAction) { case TCSHOP_DELETE|TCSHOP_INSERT: case TCSHOP_DELETE: if (UndoSize == 0) return(CC_NORM); cp = UndoPtr; kp = UndoBuf; for (loop=0; loop < UndoSize; loop++) /* copy the chars */ *kp++ = *cp++; /* into UndoBuf */ for (cp = UndoPtr; cp <= LastChar; cp++) *cp = cp[UndoSize]; LastChar -= UndoSize; Cursor = UndoPtr; UndoAction = TCSHOP_INSERT; break; case TCSHOP_INSERT: if (UndoSize == 0) return(CC_NORM); cp = UndoPtr; Cursor = UndoPtr; kp = UndoBuf; c_insert(UndoSize); /* open the space, */ for (loop = 0; loop < UndoSize; loop++) /* copy the chars */ *cp++ = *kp++; UndoAction = TCSHOP_DELETE; break; case TCSHOP_CHANGE: if (UndoSize == 0) return(CC_NORM); cp = UndoPtr; Cursor = UndoPtr; kp = UndoBuf; size = (int)(Cursor-LastChar); /* NOT NSL independant */ if (size < UndoSize) size = UndoSize; for(loop = 0; loop < size; loop++) { temp = *kp; *kp++ = *cp; *cp++ = temp; } break; default: return(CC_ERROR); } return(CC_REFRESH); } /*ARGSUSED*/ CCRETVAL v_ush_meta(Char c) { USE(c); return v_search(F_UP_SEARCH_HIST); } /*ARGSUSED*/ CCRETVAL v_dsh_meta(Char c) { USE(c); return v_search(F_DOWN_SEARCH_HIST); } /*ARGSUSED*/ CCRETVAL v_rsrch_fwd(Char c) { USE(c); if (patbuf.len == 0) return(CC_ERROR); return(v_repeat_srch(searchdir)); } /*ARGSUSED*/ CCRETVAL v_rsrch_back(Char c) { USE(c); if (patbuf.len == 0) return(CC_ERROR); return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ? F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST)); } #ifndef WINNT_NATIVE /* Since ed.defns.h is generated from ed.defns.c, these empty functions will keep the F_NUM_FNS consistent */ CCRETVAL e_copy_to_clipboard(Char c) { USE(c); return CC_ERROR; } CCRETVAL e_paste_from_clipboard(Char c) { USE(c); return (CC_ERROR); } CCRETVAL e_dosify_next(Char c) { USE(c); return (CC_ERROR); } CCRETVAL e_dosify_prev(Char c) { USE(c); return (CC_ERROR); } CCRETVAL e_page_up(Char c) { USE(c); return (CC_ERROR); } CCRETVAL e_page_down(Char c) { USE(c); return (CC_ERROR); } #endif /* !WINNT_NATIVE */ #ifdef notdef void MoveCursor(int n) /* move cursor + right - left char */ { Cursor = Cursor + n; if (Cursor < InputBuf) Cursor = InputBuf; if (Cursor > LastChar) Cursor = LastChar; return; } Char * GetCursor(void) { return(Cursor); } int PutCursor(Char *p) { if (p < InputBuf || p > LastChar) return 1; /* Error */ Cursor = p; return 0; } #endif