6560ac57ce
Merge commit '174d8b60324d7e8754709f7155e13ca95220b48c' into main. MFC After: 2 weeks
3894 lines
75 KiB
C
3894 lines
75 KiB
C
/*
|
|
* 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"
|
|
#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_WORD 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 > low && 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 > prev && 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(), c_next_word() and c_eword() 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 (isword(ch))
|
|
return C_CLASS_WORD;
|
|
|
|
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 (p >= InputBuf && 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--) {
|
|
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 a non_whitespace word, we're ready */
|
|
if (c_class != C_CLASS_WHITE)
|
|
continue;
|
|
|
|
/* otherwise, move to the end of the word just found */
|
|
c_class = c_to_class(*p);
|
|
while ((p < high) && c_class == c_to_class(*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(void)
|
|
{
|
|
SavedBuf.len = 0;
|
|
Strbuf_append(&SavedBuf, InputBuf);
|
|
Strbuf_terminate(&SavedBuf);
|
|
LastSaved = LastChar - InputBuf;
|
|
CursSaved = Cursor - InputBuf;
|
|
HistSaved = Hist_num;
|
|
RestoreSaved = 1;
|
|
}
|
|
|
|
CCRETVAL
|
|
GetHistLine(void)
|
|
{
|
|
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 (GetCmdChar(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_capitalcase(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);
|
|
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
|