55b903e2e0
Update vendor/tcsh to git b605cb561d Vendor changes: 1. PR/471: Daiki Ueno: Delay interpreting arginp until we've processed our startup files (which can change the NLS environment). 2. Fix type of read in prompt confirmation (eg. rmstar) (David Kaspar). 3. Fix out of bounds read (Brooks Davis) (reproduce by starting tcsh and hitting tab at the prompt). 4. Don't play pointer tricks that are undefined in modern c (Brooks Davis).
3899 lines
75 KiB
C
3899 lines
75 KiB
C
/* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.103 2015/08/19 14:29:55 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.103 2015/08/19 14:29:55 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_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-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(), 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 (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_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
|