159243Sobrien/*
259243Sobrien * ed.chared.c: Character editing functions.
359243Sobrien */
459243Sobrien/*-
559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
659243Sobrien * All rights reserved.
759243Sobrien *
859243Sobrien * Redistribution and use in source and binary forms, with or without
959243Sobrien * modification, are permitted provided that the following conditions
1059243Sobrien * are met:
1159243Sobrien * 1. Redistributions of source code must retain the above copyright
1259243Sobrien *    notice, this list of conditions and the following disclaimer.
1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1459243Sobrien *    notice, this list of conditions and the following disclaimer in the
1559243Sobrien *    documentation and/or other materials provided with the distribution.
16100616Smp * 3. Neither the name of the University nor the names of its contributors
1759243Sobrien *    may be used to endorse or promote products derived from this software
1859243Sobrien *    without specific prior written permission.
1959243Sobrien *
2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2359243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3059243Sobrien * SUCH DAMAGE.
3159243Sobrien */
3259243Sobrien/*
3359243Sobrien  Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
3459243Sobrien
3559243Sobrien  e_dabbrev_expand() did not do proper completion if quoted spaces were present
3659243Sobrien  in the string being completed. Exemple:
3759243Sobrien
3859243Sobrien  # echo hello\ world
3959243Sobrien  hello world
4059243Sobrien  # echo h<press key bound to dabbrev-expande>
4159243Sobrien  # echo hello\<cursor>
4259243Sobrien
4359243Sobrien  Correct behavior is:
4459243Sobrien  # echo h<press key bound to dabbrev-expande>
4559243Sobrien  # echo hello\ world<cursor>
4659243Sobrien
4759243Sobrien  The same problem occured if spaces were present in a string withing quotation
4859243Sobrien  marks. Example:
4959243Sobrien
5059243Sobrien  # echo "hello world"
5159243Sobrien  hello world
5259243Sobrien  # echo "h<press key bound to dabbrev-expande>
5359243Sobrien  # echo "hello<cursor>
5459243Sobrien
5559243Sobrien  The former problem could be solved with minor modifications of c_preword()
5659243Sobrien  and c_endword(). The latter, however, required a significant rewrite of
5759243Sobrien  c_preword(), since quoted strings must be parsed from start to end to
5859243Sobrien  determine if a given character is inside or outside the quotation marks.
5959243Sobrien
6059243Sobrien  Compare the following two strings:
6159243Sobrien
6259243Sobrien  # echo \"" 'foo \' bar\"
6359243Sobrien  " 'foo \' bar\
6459243Sobrien  # echo '\"" 'foo \' bar\"
6559243Sobrien  \"" foo ' bar"
6659243Sobrien
6759243Sobrien  The only difference between the two echo lines is in the first character
6859243Sobrien  after the echo command. The result is either one or three arguments.
6959243Sobrien
7059243Sobrien */
7159243Sobrien
7259243Sobrien#include "sh.h"
7359243Sobrien#include "ed.h"
7459243Sobrien#include "tw.h"
7559243Sobrien#include "ed.defns.h"
7659243Sobrien
7759243Sobrien/* #define SDEBUG */
7859243Sobrien
7959243Sobrien#define TCSHOP_NOP    	  0x00
8059243Sobrien#define TCSHOP_DELETE 	  0x01
8159243Sobrien#define TCSHOP_INSERT 	  0x02
8259243Sobrien#define TCSHOP_CHANGE 	  0x04
8359243Sobrien
8459243Sobrien#define CHAR_FWD	0
8559243Sobrien#define CHAR_BACK	1
8659243Sobrien
8759243Sobrien/*
8859243Sobrien * vi word treatment
8959243Sobrien * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
9059243Sobrien */
9159243Sobrien#define C_CLASS_WHITE	1
92316957Sdchagin#define C_CLASS_WORD	2
9359243Sobrien#define C_CLASS_OTHER	3
9459243Sobrien
9559243Sobrienstatic Char *InsertPos = InputBuf; /* Where insertion starts */
9659243Sobrienstatic Char *ActionPos = 0;	   /* Where action begins  */
9759243Sobrienstatic int  ActionFlag = TCSHOP_NOP;	   /* What delayed action to take */
9859243Sobrien/*
9959243Sobrien * Word search state
10059243Sobrien */
10159243Sobrienstatic int  searchdir = F_UP_SEARCH_HIST; 	/* Direction of last search */
102167465Smpstatic struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
10359243Sobrien/*
10459243Sobrien * Char search state
10559243Sobrien */
10659243Sobrienstatic int  srch_dir = CHAR_FWD;		/* Direction of last search */
10759243Sobrienstatic Char srch_char = 0;			/* Search target */
10859243Sobrien
10959243Sobrien/* all routines that start with c_ are private to this set of routines */
110167465Smpstatic	void	 c_alternativ_key_map	(int);
111167465Smpvoid	 c_insert		(int);
112167465Smpvoid	 c_delafter		(int);
113167465Smpvoid	 c_delbefore		(int);
114167465Smpstatic 	int	 c_to_class		(Char);
115167465Smpstatic	Char	*c_prev_word		(Char *, Char *, int);
116167465Smpstatic	Char	*c_next_word		(Char *, Char *, int);
117167465Smpstatic	Char	*c_number		(Char *, int *, int);
118167465Smpstatic	Char	*c_expand		(Char *);
119195609Smpstatic	int	 c_excl			(Char *);
120195609Smpstatic	int	 c_substitute		(void);
121167465Smpstatic	void	 c_delfini		(void);
122167465Smpstatic	int	 c_hmatch		(Char *);
123167465Smpstatic	void	 c_hsetpat		(void);
12459243Sobrien#ifdef COMMENT
125167465Smpstatic	void	 c_get_word		(Char **, Char **);
12659243Sobrien#endif
127167465Smpstatic	Char	*c_preword		(Char *, Char *, int, Char *);
128167465Smpstatic	Char	*c_nexword		(Char *, Char *, int);
129167465Smpstatic	Char	*c_endword		(Char *, Char *, int, Char *);
130167465Smpstatic	Char	*c_eword		(Char *, Char *, int);
131167465Smpstatic	void	 c_push_kill		(Char *, Char *);
132167465Smpstatic	void	 c_save_inputbuf	(void);
133167465Smpstatic  CCRETVAL c_search_line		(Char *, int);
134167465Smpstatic  CCRETVAL v_repeat_srch		(int);
135167465Smpstatic	CCRETVAL e_inc_search		(int);
136167465Smp#ifdef notyet
137167465Smpstatic  CCRETVAL e_insert_str		(Char *);
138167465Smp#endif
139167465Smpstatic	CCRETVAL v_search		(int);
140167465Smpstatic	CCRETVAL v_csearch_fwd		(Char, int, int);
141167465Smpstatic	CCRETVAL v_action		(int);
142167465Smpstatic	CCRETVAL v_csearch_back		(Char, int, int);
14359243Sobrien
14459243Sobrienstatic void
145167465Smpc_alternativ_key_map(int state)
14659243Sobrien{
14759243Sobrien    switch (state) {
14859243Sobrien    case 0:
14959243Sobrien	CurrentKeyMap = CcKeyMap;
15059243Sobrien	break;
15159243Sobrien    case 1:
15259243Sobrien	CurrentKeyMap = CcAltMap;
15359243Sobrien	break;
15459243Sobrien    default:
15559243Sobrien	return;
15659243Sobrien    }
15759243Sobrien
15859243Sobrien    AltKeyMap = (Char) state;
15959243Sobrien}
16059243Sobrien
16183098Smpvoid
162167465Smpc_insert(int num)
16359243Sobrien{
16483098Smp    Char *cp;
16559243Sobrien
16659243Sobrien    if (LastChar + num >= InputLim)
16759243Sobrien	return;			/* can't go past end of buffer */
16859243Sobrien
16959243Sobrien    if (Cursor < LastChar) {	/* if I must move chars */
17059243Sobrien	for (cp = LastChar; cp >= Cursor; cp--)
17159243Sobrien	    cp[num] = *cp;
172145479Smp	if (Mark && Mark > Cursor)
173145479Smp		Mark += num;
17459243Sobrien    }
17559243Sobrien    LastChar += num;
17659243Sobrien}
17759243Sobrien
17869408Sachevoid
179167465Smpc_delafter(int num)
18059243Sobrien{
18183098Smp    Char *cp, *kp = NULL;
18259243Sobrien
18359243Sobrien    if (num > LastChar - Cursor)
18459243Sobrien	num = (int) (LastChar - Cursor);	/* bounds check */
18559243Sobrien
18659243Sobrien    if (num > 0) {			/* if I can delete anything */
18759243Sobrien	if (VImode) {
18859243Sobrien	    kp = UndoBuf;		/* Set Up for VI undo command */
18959243Sobrien	    UndoAction = TCSHOP_INSERT;
19059243Sobrien	    UndoSize = num;
19159243Sobrien	    UndoPtr  = Cursor;
19259243Sobrien	    for (cp = Cursor; cp <= LastChar; cp++) {
19359243Sobrien		*kp++ = *cp;	/* Save deleted chars into undobuf */
19459243Sobrien		*cp = cp[num];
19559243Sobrien	    }
19659243Sobrien	}
19759243Sobrien	else
198145479Smp	    for (cp = Cursor; cp + num <= LastChar; cp++)
19959243Sobrien		*cp = cp[num];
20059243Sobrien	LastChar -= num;
201167465Smp	/* Mark was within the range of the deleted word? */
202167465Smp	if (Mark && Mark > Cursor && Mark <= Cursor+num)
203167465Smp		Mark = Cursor;
204167465Smp	/* Mark after the deleted word? */
205167465Smp	else if (Mark && Mark > Cursor)
206145479Smp		Mark -= num;
20759243Sobrien    }
20859243Sobrien#ifdef notdef
20959243Sobrien    else {
21059243Sobrien	/*
21159243Sobrien	 * XXX: We don't want to do that. In emacs mode overwrite should be
21259243Sobrien	 * sticky. I am not sure how that affects vi mode
21359243Sobrien	 */
21459243Sobrien	inputmode = MODE_INSERT;
21559243Sobrien    }
21659243Sobrien#endif /* notdef */
21759243Sobrien}
21859243Sobrien
21969408Sachevoid
220167465Smpc_delbefore(int num)		/* delete before dot, with bounds checking */
22159243Sobrien{
22283098Smp    Char *cp, *kp = NULL;
22359243Sobrien
22459243Sobrien    if (num > Cursor - InputBuf)
22559243Sobrien	num = (int) (Cursor - InputBuf);	/* bounds check */
22659243Sobrien
22759243Sobrien    if (num > 0) {			/* if I can delete anything */
22859243Sobrien	if (VImode) {
22959243Sobrien	    kp = UndoBuf;		/* Set Up for VI undo command */
23059243Sobrien	    UndoAction = TCSHOP_INSERT;
23159243Sobrien	    UndoSize = num;
23259243Sobrien	    UndoPtr  = Cursor - num;
23359243Sobrien	    for (cp = Cursor - num; cp <= LastChar; cp++) {
23459243Sobrien		*kp++ = *cp;
23559243Sobrien		*cp = cp[num];
23659243Sobrien	    }
23759243Sobrien	}
23859243Sobrien	else
239145479Smp	    for (cp = Cursor - num; cp + num <= LastChar; cp++)
24059243Sobrien		*cp = cp[num];
24159243Sobrien	LastChar -= num;
242145479Smp	Cursor -= num;
243167465Smp	/* Mark was within the range of the deleted word? */
244167465Smp	if (Mark && Mark > Cursor && Mark <= Cursor+num)
245167465Smp		Mark = Cursor;
246167465Smp	/* Mark after the deleted word? */
247167465Smp	else if (Mark && Mark > Cursor)
248145479Smp		Mark -= num;
24959243Sobrien    }
25059243Sobrien}
25159243Sobrien
25259243Sobrienstatic Char *
253167465Smpc_preword(Char *p, Char *low, int n, Char *delim)
25459243Sobrien{
25559243Sobrien  while (n--) {
25683098Smp    Char *prev = low;
25783098Smp    Char *new;
25859243Sobrien
25983098Smp    while (prev < p) {		/* Skip initial non-word chars */
26083098Smp      if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\')
26159243Sobrien	break;
26259243Sobrien      prev++;
26359243Sobrien    }
26459243Sobrien
26559243Sobrien    new = prev;
26659243Sobrien
26759243Sobrien    while (new < p) {
26859243Sobrien      prev = new;
26983098Smp      new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */
27059243Sobrien      new++;			/* Step away from end of word */
27183098Smp      while (new <= p) {	/* Skip trailing non-word chars */
27283098Smp	if (!Strchr(delim, *new) || *(new-1) == (Char)'\\')
27359243Sobrien	  break;
27459243Sobrien	new++;
27559243Sobrien      }
27659243Sobrien    }
27759243Sobrien
27859243Sobrien    p = prev;			/* Set to previous word start */
27959243Sobrien
28059243Sobrien  }
28159243Sobrien  if (p < low)
28259243Sobrien    p = low;
28359243Sobrien  return (p);
28459243Sobrien}
28559243Sobrien
28659243Sobrien/*
28759243Sobrien * c_to_class() returns the class of the given character.
28859243Sobrien *
289316957Sdchagin * This is used to make the c_prev_word(), c_next_word() and c_eword() functions
29059243Sobrien * work like vi's, which classify characters. A word is a sequence of
29159243Sobrien * characters belonging to the same class, classes being defined as
29259243Sobrien * follows:
29359243Sobrien *
29459243Sobrien *	1/ whitespace
29559243Sobrien *	2/ alphanumeric chars, + underscore
29659243Sobrien *	3/ others
29759243Sobrien */
29859243Sobrienstatic int
299167465Smpc_to_class(Char ch)
30059243Sobrien{
30159243Sobrien    if (Isspace(ch))
30259243Sobrien        return C_CLASS_WHITE;
30359243Sobrien
304316957Sdchagin    if (isword(ch))
305316957Sdchagin        return C_CLASS_WORD;
30659243Sobrien
30759243Sobrien    return C_CLASS_OTHER;
30859243Sobrien}
30959243Sobrien
31059243Sobrienstatic Char *
311167465Smpc_prev_word(Char *p, Char *low, int n)
31259243Sobrien{
31359243Sobrien    p--;
31459243Sobrien
31559243Sobrien    if (!VImode) {
31659243Sobrien	while (n--) {
31759243Sobrien	    while ((p >= low) && !isword(*p))
31859243Sobrien		p--;
31959243Sobrien	    while ((p >= low) && isword(*p))
32059243Sobrien		p--;
32159243Sobrien	}
32259243Sobrien
32359243Sobrien	/* cp now points to one character before the word */
32459243Sobrien	p++;
32559243Sobrien	if (p < low)
32659243Sobrien	    p = low;
32759243Sobrien	/* cp now points where we want it */
32859243Sobrien	return(p);
32959243Sobrien    }
33059243Sobrien
33159243Sobrien    while (n--) {
33283098Smp        int  c_class;
33359243Sobrien
33459243Sobrien        if (p < low)
33559243Sobrien            break;
33659243Sobrien
33759243Sobrien        /* scan until beginning of current word (may be all whitespace!) */
33859243Sobrien        c_class = c_to_class(*p);
33959243Sobrien        while ((p >= low) && c_class == c_to_class(*p))
34059243Sobrien            p--;
34159243Sobrien
34259243Sobrien        /* if this was a non_whitespace word, we're ready */
34359243Sobrien        if (c_class != C_CLASS_WHITE)
34459243Sobrien            continue;
34559243Sobrien
34659243Sobrien        /* otherwise, move back to beginning of the word just found */
34759243Sobrien        c_class = c_to_class(*p);
34859243Sobrien        while ((p >= low) && c_class == c_to_class(*p))
34959243Sobrien            p--;
35059243Sobrien    }
35159243Sobrien
35259243Sobrien    p++;                        /* correct overshoot */
35359243Sobrien
35459243Sobrien    return (p);
35559243Sobrien}
35659243Sobrien
35759243Sobrienstatic Char *
358167465Smpc_next_word(Char *p, Char *high, int n)
35959243Sobrien{
36059243Sobrien    if (!VImode) {
36159243Sobrien	while (n--) {
36259243Sobrien	    while ((p < high) && !isword(*p))
36359243Sobrien		p++;
36459243Sobrien	    while ((p < high) && isword(*p))
36559243Sobrien		p++;
36659243Sobrien	}
36759243Sobrien	if (p > high)
36859243Sobrien	    p = high;
36959243Sobrien	/* p now points where we want it */
37059243Sobrien	return(p);
37159243Sobrien    }
37259243Sobrien
37359243Sobrien    while (n--) {
37483098Smp        int  c_class;
37559243Sobrien
37659243Sobrien        if (p >= high)
37759243Sobrien            break;
37859243Sobrien
37959243Sobrien        /* scan until end of current word (may be all whitespace!) */
38059243Sobrien        c_class = c_to_class(*p);
38159243Sobrien        while ((p < high) && c_class == c_to_class(*p))
38259243Sobrien            p++;
38359243Sobrien
38459243Sobrien        /* if this was all whitespace, we're ready */
38559243Sobrien        if (c_class == C_CLASS_WHITE)
38659243Sobrien            continue;
38759243Sobrien
38859243Sobrien	/* if we've found white-space at the end of the word, skip it */
38959243Sobrien        while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
39059243Sobrien            p++;
39159243Sobrien    }
39259243Sobrien
39359243Sobrien    p--;                        /* correct overshoot */
39459243Sobrien
39559243Sobrien    return (p);
39659243Sobrien}
39759243Sobrien
39859243Sobrienstatic Char *
399167465Smpc_nexword(Char *p, Char *high, int n)
40059243Sobrien{
40159243Sobrien    while (n--) {
40259243Sobrien	while ((p < high) && !Isspace(*p))
40359243Sobrien	    p++;
40459243Sobrien	while ((p < high) && Isspace(*p))
40559243Sobrien	    p++;
40659243Sobrien    }
40759243Sobrien
40859243Sobrien    if (p > high)
40959243Sobrien	p = high;
41059243Sobrien    /* p now points where we want it */
41159243Sobrien    return(p);
41259243Sobrien}
41359243Sobrien
41459243Sobrien/*
41559243Sobrien * Expand-History (originally "Magic-Space") code added by
41659243Sobrien * Ray Moody <ray@gibbs.physics.purdue.edu>
41759243Sobrien * this is a neat, but odd, addition.
41859243Sobrien */
41959243Sobrien
42059243Sobrien/*
42159243Sobrien * c_number: Ignore character p points to, return number appearing after that.
42259243Sobrien * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
42359243Sobrien * Return p pointing to last char used.
42459243Sobrien */
42559243Sobrien
42659243Sobrien/*
42759243Sobrien * dval is the number to subtract from for things like $-3
42859243Sobrien */
42959243Sobrien
43059243Sobrienstatic Char *
431167465Smpc_number(Char *p, int *num, int dval)
43259243Sobrien{
43383098Smp    int i;
43483098Smp    int sign = 1;
43559243Sobrien
43659243Sobrien    if (*++p == '^') {
43759243Sobrien	*num = 1;
43859243Sobrien	return(p);
43959243Sobrien    }
44059243Sobrien    if (*p == '$') {
44159243Sobrien	if (*++p != '-') {
442167465Smp	    *num = INT_MAX;	/* Handle $ */
44359243Sobrien	    return(--p);
44459243Sobrien	}
44559243Sobrien	sign = -1;		/* Handle $- */
44659243Sobrien	++p;
44759243Sobrien    }
44859243Sobrien    for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
44959243Sobrien	continue;
45059243Sobrien    *num = (sign < 0 ? dval - i : i);
45159243Sobrien    return(--p);
45259243Sobrien}
45359243Sobrien
45459243Sobrien/*
45559243Sobrien * excl_expand: There is an excl to be expanded to p -- do the right thing
45659243Sobrien * with it and return a version of p advanced over the expanded stuff.  Also,
45759243Sobrien * update tsh_cur and related things as appropriate...
45859243Sobrien */
45959243Sobrien
46059243Sobrienstatic Char *
461167465Smpc_expand(Char *p)
46259243Sobrien{
46383098Smp    Char *q;
46483098Smp    struct Hist *h = Histlist.Hnext;
46583098Smp    struct wordent *l;
46659243Sobrien    int     i, from, to, dval;
467145479Smp    int    all_dig;
468145479Smp    int    been_once = 0;
46959243Sobrien    Char   *op = p;
470167465Smp    Char   *buf;
471167465Smp    size_t buf_len;
472167465Smp    Char   *modbuf;
47359243Sobrien
474167465Smp    buf = NULL;
47559243Sobrien    if (!h)
47659243Sobrien	goto excl_err;
47759243Sobrienexcl_sw:
47859243Sobrien    switch (*(q = p + 1)) {
47959243Sobrien
48059243Sobrien    case '^':
481167465Smp	buf = expand_lex(&h->Hlex, 1, 1);
48259243Sobrien	break;
48359243Sobrien
48459243Sobrien    case '$':
48559243Sobrien	if ((l = (h->Hlex).prev) != 0)
486167465Smp	    buf = expand_lex(l->prev->prev, 0, 0);
48759243Sobrien	break;
48859243Sobrien
48959243Sobrien    case '*':
490167465Smp	buf = expand_lex(&h->Hlex, 1, INT_MAX);
49159243Sobrien	break;
49259243Sobrien
49359243Sobrien    default:
49459243Sobrien	if (been_once) {	/* unknown argument */
49559243Sobrien	    /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
496167465Smp	    buf = expand_lex(&h->Hlex, 0, INT_MAX);
49759243Sobrien	    q -= 2;
49859243Sobrien	    break;
49959243Sobrien	}
50059243Sobrien	been_once = 1;
50159243Sobrien
50259243Sobrien	if (*q == ':')		/* short form: !:arg */
50359243Sobrien	    --q;
50459243Sobrien
505231990Smp	if (HIST != '\0' && *q != HIST) {
50659243Sobrien	    /*
50759243Sobrien	     * Search for a space, tab, or colon.  See if we have a number (as
50859243Sobrien	     * in !1234:xyz).  Remember the number.
50959243Sobrien	     */
51059243Sobrien	    for (i = 0, all_dig = 1;
51159243Sobrien		 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
51259243Sobrien		/*
51359243Sobrien		 * PWP: !-4 is a valid history argument too, therefore the test
51459243Sobrien		 * is if not a digit, or not a - as the first character.
51559243Sobrien		 */
51659243Sobrien		if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
51759243Sobrien		    all_dig = 0;
51859243Sobrien		else if (*q == '-')
51959243Sobrien		    all_dig = 2;/* we are sneeky about this */
52059243Sobrien		else
52159243Sobrien		    i = 10 * i + *q - '0';
52259243Sobrien	    }
52359243Sobrien	    --q;
52459243Sobrien
52559243Sobrien	    /*
52659243Sobrien	     * If we have a number, search for event i.  Otherwise, search for
52759243Sobrien	     * a named event (as in !foo).  (In this case, I is the length of
52859243Sobrien	     * the named event).
52959243Sobrien	     */
53059243Sobrien	    if (all_dig) {
53159243Sobrien		if (all_dig == 2)
53259243Sobrien		    i = -i;	/* make it negitive */
53359243Sobrien		if (i < 0)	/* if !-4 (for example) */
53459243Sobrien		    i = eventno + 1 + i;	/* remember: i is < 0 */
53559243Sobrien		for (; h; h = h->Hnext) {
53659243Sobrien		    if (h->Hnum == i)
53759243Sobrien			break;
53859243Sobrien		}
53959243Sobrien	    }
54059243Sobrien	    else {
54159243Sobrien		for (i = (int) (q - p); h; h = h->Hnext) {
54259243Sobrien		    if ((l = &h->Hlex) != 0) {
54359243Sobrien			if (!Strncmp(p + 1, l->next->word, (size_t) i))
54459243Sobrien			    break;
54559243Sobrien		    }
54659243Sobrien		}
54759243Sobrien	    }
54859243Sobrien	}
54959243Sobrien	if (!h)
55059243Sobrien	    goto excl_err;
55159243Sobrien	if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
55259243Sobrien	    q[1] == '$' || q[1] == '^') {	/* get some args */
55359243Sobrien	    p = q[1] == ':' ? ++q : q;
55459243Sobrien	    /*
55559243Sobrien	     * Go handle !foo:*
55659243Sobrien	     */
55759243Sobrien	    if ((q[1] < '0' || q[1] > '9') &&
55859243Sobrien		q[1] != '-' && q[1] != '$' && q[1] != '^')
55959243Sobrien		goto excl_sw;
56059243Sobrien	    /*
56159243Sobrien	     * Go handle !foo:$
56259243Sobrien	     */
56359243Sobrien	    if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
56459243Sobrien		goto excl_sw;
56559243Sobrien	    /*
56659243Sobrien	     * Count up the number of words in this event.  Store it in dval.
56759243Sobrien	     * Dval will be fed to number.
56859243Sobrien	     */
56959243Sobrien	    dval = 0;
57059243Sobrien	    if ((l = h->Hlex.prev) != 0) {
57159243Sobrien		for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
57259243Sobrien		    continue;
57359243Sobrien	    }
57459243Sobrien	    if (!dval)
57559243Sobrien		goto excl_err;
57659243Sobrien	    if (q[1] == '-')
57759243Sobrien		from = 0;
57859243Sobrien	    else
57959243Sobrien		q = c_number(q, &from, dval);
58059243Sobrien	    if (q[1] == '-') {
58159243Sobrien		++q;
58259243Sobrien		if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
58359243Sobrien		    to = dval - 1;
58459243Sobrien		else
58559243Sobrien		    q = c_number(q, &to, dval);
58659243Sobrien	    }
58759243Sobrien	    else if (q[1] == '*') {
58859243Sobrien		++q;
589167465Smp		to = INT_MAX;
59059243Sobrien	    }
59159243Sobrien	    else {
59259243Sobrien		to = from;
59359243Sobrien	    }
59459243Sobrien	    if (from < 0 || to < from)
59559243Sobrien		goto excl_err;
596167465Smp	    buf = expand_lex(&h->Hlex, from, to);
59759243Sobrien	}
598167465Smp	else			/* get whole cmd */
599167465Smp	    buf = expand_lex(&h->Hlex, 0, INT_MAX);
60059243Sobrien	break;
60159243Sobrien    }
602167465Smp    if (buf == NULL)
603167465Smp	buf = SAVE("");
60459243Sobrien
60559243Sobrien    /*
60659243Sobrien     * Apply modifiers, if any.
60759243Sobrien     */
60859243Sobrien    if (q[1] == ':') {
609167465Smp	modbuf = buf;
61059243Sobrien	while (q[1] == ':' && modbuf != NULL) {
61159243Sobrien	    switch (q[2]) {
61259243Sobrien	    case 'r':
61359243Sobrien	    case 'e':
61459243Sobrien	    case 'h':
61559243Sobrien	    case 't':
61659243Sobrien	    case 'q':
61759243Sobrien	    case 'x':
61859243Sobrien	    case 'u':
61959243Sobrien	    case 'l':
620167465Smp		if ((modbuf = domod(buf, (int) q[2])) != NULL) {
621167465Smp		    xfree(buf);
622167465Smp		    buf = modbuf;
62359243Sobrien		}
62459243Sobrien		++q;
62559243Sobrien		break;
62659243Sobrien
62759243Sobrien	    case 'a':
62859243Sobrien	    case 'g':
62959243Sobrien		/* Not implemented; this needs to be done before expanding
63059243Sobrien		 * lex. We don't have the words available to us anymore.
63159243Sobrien		 */
63259243Sobrien		++q;
63359243Sobrien		break;
63459243Sobrien
63559243Sobrien	    case 'p':
63659243Sobrien		/* Ok */
63759243Sobrien		++q;
63859243Sobrien		break;
63959243Sobrien
64059243Sobrien	    case '\0':
64159243Sobrien		break;
64259243Sobrien
64359243Sobrien	    default:
64459243Sobrien		++q;
64559243Sobrien		break;
64659243Sobrien	    }
64759243Sobrien	    if (q[1])
64859243Sobrien		++q;
64959243Sobrien	}
65059243Sobrien    }
65159243Sobrien
652167465Smp    buf_len = Strlen(buf);
65359243Sobrien    /*
654167465Smp     * Now replace the text from op to q inclusive with the text from buf.
65559243Sobrien     */
65659243Sobrien    q++;
65759243Sobrien
65859243Sobrien    /*
65959243Sobrien     * Now replace text non-inclusively like a real CS major!
66059243Sobrien     */
661167465Smp    if (LastChar + buf_len - (q - op) >= InputLim)
66259243Sobrien	goto excl_err;
663167465Smp    (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
664167465Smp    LastChar += buf_len - (q - op);
665167465Smp    Cursor += buf_len - (q - op);
666167465Smp    (void) memcpy(op, buf, buf_len * sizeof(Char));
66759243Sobrien    *LastChar = '\0';
668167465Smp    xfree(buf);
669167465Smp    return op + buf_len;
67059243Sobrienexcl_err:
671167465Smp    xfree(buf);
67259243Sobrien    SoundBeep();
67359243Sobrien    return(op + 1);
67459243Sobrien}
67559243Sobrien
67659243Sobrien/*
67759243Sobrien * c_excl: An excl has been found at point p -- back up and find some white
67859243Sobrien * space (or the beginning of the buffer) and properly expand all the excl's
67959243Sobrien * from there up to the current cursor position. We also avoid (trying to)
68059243Sobrien * expanding '>!'
681195609Smp * Returns number of expansions attempted (doesn't matter whether they succeeded
682195609Smp * or not).
68359243Sobrien */
68459243Sobrien
685195609Smpstatic int
686167465Smpc_excl(Char *p)
68759243Sobrien{
68883098Smp    int i;
68983098Smp    Char *q;
690195609Smp    int nr_exp;
69159243Sobrien
69259243Sobrien    /*
69359243Sobrien     * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
69459243Sobrien     * back p up to just before the current word.
69559243Sobrien     */
69659243Sobrien    if ((p[1] == ' ' || p[1] == '\t') &&
69759243Sobrien	(p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
69859243Sobrien	for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
69959243Sobrien	    continue;
70059243Sobrien	if (*q == '>')
70159243Sobrien	    ++p;
70259243Sobrien    }
70359243Sobrien    else {
70459243Sobrien	while (*p != ' ' && *p != '\t' && p > InputBuf)
70559243Sobrien	    --p;
70659243Sobrien    }
70759243Sobrien
70859243Sobrien    /*
70959243Sobrien     * Forever: Look for history char.  (Stop looking when we find the cursor.)
710195609Smp     * Count backslashes.  If odd, skip history char.  Expand if even number of
711195609Smp     * backslashes.
71259243Sobrien     */
713195609Smp    nr_exp = 0;
71459243Sobrien    for (;;) {
715231990Smp	if (HIST != '\0')
716231990Smp	    while (*p != HIST && p < Cursor)
717231990Smp		++p;
71859243Sobrien	for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
71959243Sobrien	    continue;
72059243Sobrien	if (i % 2 == 0)
72159243Sobrien	    ++p;
722195609Smp	if (p >= Cursor)   /* all done */
723195609Smp	    return nr_exp;
724195609Smp	if (i % 2 == 1) {
72559243Sobrien	    p = c_expand(p);
726195609Smp	    ++nr_exp;
727195609Smp	}
72859243Sobrien    }
72959243Sobrien}
73059243Sobrien
73159243Sobrien
732195609Smpstatic int
733167465Smpc_substitute(void)
73459243Sobrien{
73583098Smp    Char *p;
736195609Smp    int  nr_exp;
73759243Sobrien
73859243Sobrien    /*
73959243Sobrien     * Start p out one character before the cursor.  Move it backwards looking
74059243Sobrien     * for white space, the beginning of the line, or a history character.
74159243Sobrien     */
74259243Sobrien    for (p = Cursor - 1;
743231990Smp	 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
74459243Sobrien	continue;
74559243Sobrien
74659243Sobrien    /*
74759243Sobrien     * If we found a history character, go expand it.
74859243Sobrien     */
749316957Sdchagin    if (p >= InputBuf && HIST != '\0' && *p == HIST)
750195609Smp	nr_exp = c_excl(p);
751195609Smp    else
752195609Smp        nr_exp = 0;
75359243Sobrien    Refresh();
754195609Smp
755195609Smp    return nr_exp;
75659243Sobrien}
75759243Sobrien
75859243Sobrienstatic void
759167465Smpc_delfini(void)		/* Finish up delete action */
76059243Sobrien{
76183098Smp    int Size;
76259243Sobrien
76359243Sobrien    if (ActionFlag & TCSHOP_INSERT)
76459243Sobrien	c_alternativ_key_map(0);
76559243Sobrien
76659243Sobrien    ActionFlag = TCSHOP_NOP;
76759243Sobrien
76859243Sobrien    if (ActionPos == 0)
76959243Sobrien	return;
77059243Sobrien
77159243Sobrien    UndoAction = TCSHOP_INSERT;
77259243Sobrien
77359243Sobrien    if (Cursor > ActionPos) {
77459243Sobrien	Size = (int) (Cursor-ActionPos);
77559243Sobrien	c_delbefore(Size);
77659243Sobrien	RefCursor();
77759243Sobrien    }
77859243Sobrien    else if (Cursor < ActionPos) {
77959243Sobrien	Size = (int)(ActionPos-Cursor);
78059243Sobrien	c_delafter(Size);
78159243Sobrien    }
78259243Sobrien    else  {
78359243Sobrien	Size = 1;
78459243Sobrien	c_delafter(Size);
78559243Sobrien    }
78659243Sobrien    UndoPtr = Cursor;
78759243Sobrien    UndoSize = Size;
78859243Sobrien}
78959243Sobrien
79059243Sobrienstatic Char *
791167465Smpc_endword(Char *p, Char *high, int n, Char *delim)
79259243Sobrien{
793145479Smp    Char inquote = 0;
79459243Sobrien    p++;
79559243Sobrien
79659243Sobrien    while (n--) {
79783098Smp        while (p < high) {	/* Skip non-word chars */
79883098Smp	  if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
79959243Sobrien	    break;
80059243Sobrien	  p++;
80159243Sobrien        }
80259243Sobrien	while (p < high) {	/* Skip string */
80359243Sobrien	  if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
80483098Smp	    if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
80559243Sobrien	      if (inquote == 0) inquote = *p;
80659243Sobrien	      else if (inquote == *p) inquote = 0;
80759243Sobrien	    }
80859243Sobrien	  }
80983098Smp	  /* Break if unquoted non-word char */
81083098Smp	  if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
81159243Sobrien	    break;
81259243Sobrien	  p++;
81359243Sobrien	}
81459243Sobrien    }
81559243Sobrien
81659243Sobrien    p--;
81759243Sobrien    return(p);
81859243Sobrien}
81959243Sobrien
82059243Sobrien
82159243Sobrienstatic Char *
822167465Smpc_eword(Char *p, Char *high, int n)
82359243Sobrien{
82459243Sobrien    p++;
82559243Sobrien
82659243Sobrien    while (n--) {
827316957Sdchagin        int  c_class;
82859243Sobrien
829316957Sdchagin        if (p >= high)
830316957Sdchagin            break;
831316957Sdchagin
832316957Sdchagin        /* scan until end of current word (may be all whitespace!) */
833316957Sdchagin        c_class = c_to_class(*p);
834316957Sdchagin        while ((p < high) && c_class == c_to_class(*p))
835316957Sdchagin            p++;
836316957Sdchagin
837316957Sdchagin        /* if this was a non_whitespace word, we're ready */
838316957Sdchagin        if (c_class != C_CLASS_WHITE)
839316957Sdchagin            continue;
840316957Sdchagin
841316957Sdchagin        /* otherwise, move to the end of the word just found */
842316957Sdchagin        c_class = c_to_class(*p);
843316957Sdchagin        while ((p < high) && c_class == c_to_class(*p))
844316957Sdchagin            p++;
84559243Sobrien    }
84659243Sobrien
84759243Sobrien    p--;
84859243Sobrien    return(p);
84959243Sobrien}
85059243Sobrien
85183098Smp/* Set the max length of the kill ring */
85283098Smpvoid
853167465SmpSetKillRing(int max)
85483098Smp{
85583098Smp    CStr *new;
85683098Smp    int count, i, j;
85783098Smp
85883098Smp    if (max < 1)
85983098Smp	max = 1;		/* no ring, but always one buffer */
86083098Smp    if (max == KillRingMax)
86183098Smp	return;
862167465Smp    new = xcalloc(max, sizeof(CStr));
86383098Smp    if (KillRing != NULL) {
86483098Smp	if (KillRingLen != 0) {
86583098Smp	    if (max >= KillRingLen) {
86683098Smp		count = KillRingLen;
86783098Smp		j = KillPos;
86883098Smp	    } else {
86983098Smp		count = max;
87083098Smp		j = (KillPos - count + KillRingLen) % KillRingLen;
87183098Smp	    }
87283098Smp	    for (i = 0; i < KillRingLen; i++) {
87383098Smp		if (i < count)	/* copy latest */
87483098Smp		    new[i] = KillRing[j];
87583098Smp		else		/* free the others */
87683098Smp		    xfree(KillRing[j].buf);
87783098Smp		j = (j + 1) % KillRingLen;
87883098Smp	    }
87983098Smp	    KillRingLen = count;
88083098Smp	    KillPos = count % max;
88183098Smp	    YankPos = count - 1;
88283098Smp	}
88383098Smp	xfree(KillRing);
88483098Smp    }
88583098Smp    KillRing = new;
88683098Smp    KillRingMax = max;
88783098Smp}
88883098Smp
88983098Smp/* Push string from start upto (but not including) end onto kill ring */
89083098Smpstatic void
891167465Smpc_push_kill(Char *start, Char *end)
89283098Smp{
89383098Smp    CStr save, *pos;
89483098Smp    Char *dp, *cp, *kp;
89583098Smp    int len = end - start, i, j, k;
89683098Smp
89783098Smp    /* Check for duplicates? */
89883098Smp    if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
89983098Smp	YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
90083098Smp	if (eq(dp, STRerase)) {	/* erase earlier one (actually move up) */
90183098Smp	    j = YankPos;
90283098Smp	    for (i = 0; i < KillRingLen; i++) {
90383098Smp		if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
90483098Smp		    KillRing[j].buf[len] == '\0') {
90583098Smp		    save = KillRing[j];
90683098Smp		    for ( ; i > 0; i--) {
90783098Smp			k = j;
90883098Smp			j = (j + 1) % KillRingLen;
90983098Smp			KillRing[k] = KillRing[j];
91083098Smp		    }
91183098Smp		    KillRing[j] = save;
91283098Smp		    return;
91383098Smp		}
91483098Smp		j = (j - 1 + KillRingLen) % KillRingLen;
91583098Smp	    }
91683098Smp	} else if (eq(dp, STRall)) { /* skip if any earlier */
91783098Smp	    for (i = 0; i < KillRingLen; i++)
91883098Smp		if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
91983098Smp		    KillRing[i].buf[len] == '\0')
92083098Smp		    return;
92183098Smp	} else if (eq(dp, STRprev)) { /* skip if immediately previous */
92283098Smp	    j = YankPos;
92383098Smp	    if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
92483098Smp		KillRing[j].buf[len] == '\0')
92583098Smp		return;
92683098Smp	}
92783098Smp    }
92883098Smp
92983098Smp    /* No duplicate, go ahead and push */
93083098Smp    len++;			/* need space for '\0' */
93183098Smp    YankPos = KillPos;
93283098Smp    if (KillRingLen < KillRingMax)
93383098Smp	KillRingLen++;
93483098Smp    pos = &KillRing[KillPos];
93583098Smp    KillPos = (KillPos + 1) % KillRingMax;
93683098Smp    if (pos->len < len) {
937167465Smp	pos->buf = xrealloc(pos->buf, len * sizeof(Char));
93883098Smp	pos->len = len;
93983098Smp    }
94083098Smp    cp = start;
94183098Smp    kp = pos->buf;
94283098Smp    while (cp < end)
94383098Smp	*kp++ = *cp++;
94483098Smp    *kp = '\0';
94583098Smp}
94683098Smp
947167465Smp/* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
948167465Smpstatic void
949316957Sdchaginc_save_inputbuf(void)
95059243Sobrien{
951167465Smp    SavedBuf.len = 0;
952167465Smp    Strbuf_append(&SavedBuf, InputBuf);
953167465Smp    Strbuf_terminate(&SavedBuf);
954167465Smp    LastSaved = LastChar - InputBuf;
955167465Smp    CursSaved = Cursor - InputBuf;
956167465Smp    HistSaved = Hist_num;
957167465Smp    RestoreSaved = 1;
958167465Smp}
959167465Smp
960167465SmpCCRETVAL
961316957SdchaginGetHistLine(void)
962167465Smp{
96359243Sobrien    struct Hist *hp;
96459243Sobrien    int     h;
96559243Sobrien
96659243Sobrien    if (Hist_num == 0) {	/* if really the current line */
967167465Smp	if (HistBuf.s != NULL)
968167465Smp	    copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
969167465Smp	else
970167465Smp	    *InputBuf = '\0';
971167465Smp	LastChar = InputBuf + HistBuf.len;
97259243Sobrien
97359243Sobrien#ifdef KSHVI
97459243Sobrien    if (VImode)
97559243Sobrien	Cursor = InputBuf;
97659243Sobrien    else
97759243Sobrien#endif /* KSHVI */
97859243Sobrien	Cursor = LastChar;
97959243Sobrien
98059243Sobrien	return(CC_REFRESH);
98159243Sobrien    }
98259243Sobrien
98359243Sobrien    hp = Histlist.Hnext;
98459243Sobrien    if (hp == NULL)
98559243Sobrien	return(CC_ERROR);
98659243Sobrien
98759243Sobrien    for (h = 1; h < Hist_num; h++) {
98859243Sobrien	if ((hp->Hnext) == NULL) {
98959243Sobrien	    Hist_num = h;
99059243Sobrien	    return(CC_ERROR);
99159243Sobrien	}
99259243Sobrien	hp = hp->Hnext;
99359243Sobrien    }
99459243Sobrien
99559243Sobrien    if (HistLit && hp->histline) {
996167465Smp	copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
99759243Sobrien	CurrentHistLit = 1;
99859243Sobrien    }
99959243Sobrien    else {
1000167465Smp	Char *p;
1001167465Smp
1002167465Smp	p = sprlex(&hp->Hlex);
1003167465Smp	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1004167465Smp	xfree(p);
100559243Sobrien	CurrentHistLit = 0;
100659243Sobrien    }
1007167465Smp    LastChar = Strend(InputBuf);
100859243Sobrien
100959243Sobrien    if (LastChar > InputBuf) {
101059243Sobrien	if (LastChar[-1] == '\n')
101159243Sobrien	    LastChar--;
101259243Sobrien#if 0
101359243Sobrien	if (LastChar[-1] == ' ')
101459243Sobrien	    LastChar--;
101559243Sobrien#endif
101659243Sobrien	if (LastChar < InputBuf)
101759243Sobrien	    LastChar = InputBuf;
101859243Sobrien    }
1019145479Smp
102059243Sobrien#ifdef KSHVI
102159243Sobrien    if (VImode)
102259243Sobrien	Cursor = InputBuf;
102359243Sobrien    else
102459243Sobrien#endif /* KSHVI */
102559243Sobrien	Cursor = LastChar;
102659243Sobrien
102759243Sobrien    return(CC_REFRESH);
102859243Sobrien}
102959243Sobrien
103059243Sobrienstatic CCRETVAL
1031167465Smpc_search_line(Char *pattern, int dir)
103259243Sobrien{
103359243Sobrien    Char *cp;
1034167465Smp    size_t len;
103559243Sobrien
1036167465Smp    len = Strlen(pattern);
103759243Sobrien
103859243Sobrien    if (dir == F_UP_SEARCH_HIST) {
103959243Sobrien	for (cp = Cursor; cp >= InputBuf; cp--)
1040167465Smp	    if (Strncmp(cp, pattern, len) == 0 ||
104159243Sobrien		Gmatch(cp, pattern)) {
104259243Sobrien		Cursor = cp;
104359243Sobrien		return(CC_NORM);
104459243Sobrien	    }
104559243Sobrien	return(CC_ERROR);
104659243Sobrien    } else {
104759243Sobrien	for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1048167465Smp	    if (Strncmp(cp, pattern, len) == 0 ||
104959243Sobrien		Gmatch(cp, pattern)) {
105059243Sobrien		Cursor = cp;
105159243Sobrien		return(CC_NORM);
105259243Sobrien	    }
105359243Sobrien	return(CC_ERROR);
105459243Sobrien    }
105559243Sobrien}
105659243Sobrien
105759243Sobrienstatic CCRETVAL
1058167465Smpe_inc_search(int dir)
105959243Sobrien{
1060167465Smp    static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1061167465Smp		      STRbck[] = { 'b', 'c', 'k', '\0' };
106259243Sobrien    static Char pchar = ':';	/* ':' = normal, '?' = failed */
106359243Sobrien    static Char endcmd[2];
1064167465Smp    const Char *cp;
1065167465Smp    Char ch,
106659243Sobrien	*oldCursor = Cursor,
106759243Sobrien	oldpchar = pchar;
106859243Sobrien    CCRETVAL ret = CC_NORM;
106959243Sobrien    int oldHist_num = Hist_num,
1070167465Smp	oldpatlen = patbuf.len,
107159243Sobrien	newdir = dir,
107259243Sobrien        done, redo;
107359243Sobrien
1074167465Smp    if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
107559243Sobrien	return(CC_ERROR);
107659243Sobrien
107759243Sobrien    for (;;) {
107859243Sobrien
1079167465Smp	if (patbuf.len == 0) {	/* first round */
108059243Sobrien	    pchar = ':';
1081167465Smp	    Strbuf_append1(&patbuf, '*');
108259243Sobrien	}
108359243Sobrien	done = redo = 0;
108459243Sobrien	*LastChar++ = '\n';
108559243Sobrien	for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
108659243Sobrien	     *cp; *LastChar++ = *cp++)
108759243Sobrien	    continue;
108859243Sobrien	*LastChar++ = pchar;
1089167465Smp	for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1090167465Smp	     *LastChar++ = *cp++)
109159243Sobrien	    continue;
109259243Sobrien	*LastChar = '\0';
1093167465Smp	if (adrof(STRhighlight) && pchar == ':') {
1094167465Smp	    /* if the no-glob-search patch is applied, remove the - 1 below */
1095167465Smp	    IncMatchLen = patbuf.len - 1;
1096167465Smp	    ClearLines();
1097167465Smp	    ClearDisp();
1098167465Smp	}
109959243Sobrien	Refresh();
110059243Sobrien
110159243Sobrien	if (GetNextChar(&ch) != 1)
110259243Sobrien	    return(e_send_eof(0));
110359243Sobrien
1104354195Sbrooks	switch (GetCmdChar(ch)) {
110559243Sobrien	case F_INSERT:
110659243Sobrien	case F_DIGIT:
110759243Sobrien	case F_MAGIC_SPACE:
1108167465Smp	    if (LastChar + 1 >= InputLim) /*FIXBUF*/
110959243Sobrien		SoundBeep();
111059243Sobrien	    else {
1111167465Smp		Strbuf_append1(&patbuf, ch);
111259243Sobrien		*LastChar++ = ch;
111359243Sobrien		*LastChar = '\0';
111459243Sobrien		Refresh();
111559243Sobrien	    }
111659243Sobrien	    break;
111759243Sobrien
111859243Sobrien	case F_INC_FWD:
111959243Sobrien	    newdir = F_DOWN_SEARCH_HIST;
112059243Sobrien	    redo++;
112159243Sobrien	    break;
112259243Sobrien
112359243Sobrien	case F_INC_BACK:
112459243Sobrien	    newdir = F_UP_SEARCH_HIST;
112559243Sobrien	    redo++;
112659243Sobrien	    break;
112759243Sobrien
112859243Sobrien	case F_DELPREV:
1129167465Smp	    if (patbuf.len > 1)
113059243Sobrien		done++;
113159243Sobrien	    else
113259243Sobrien		SoundBeep();
113359243Sobrien	    break;
113459243Sobrien
113559243Sobrien	default:
1136167465Smp	    switch (ASC(ch)) {
113759243Sobrien	    case 0007:		/* ^G: Abort */
113859243Sobrien		ret = CC_ERROR;
113959243Sobrien		done++;
114059243Sobrien		break;
114159243Sobrien
114259243Sobrien	    case 0027:		/* ^W: Append word */
114359243Sobrien		/* No can do if globbing characters in pattern */
1144167465Smp		for (cp = &patbuf.s[1]; ; cp++)
1145167465Smp		    if (cp >= &patbuf.s[patbuf.len]) {
1146167465Smp			Cursor += patbuf.len - 1;
114759243Sobrien			cp = c_next_word(Cursor, LastChar, 1);
114859243Sobrien			while (Cursor < cp && *Cursor != '\n') {
1149167465Smp			    if (LastChar + 1 >= InputLim) {/*FIXBUF*/
115059243Sobrien				SoundBeep();
115159243Sobrien				break;
115259243Sobrien			    }
1153167465Smp			    Strbuf_append1(&patbuf, *Cursor);
115459243Sobrien			    *LastChar++ = *Cursor++;
115559243Sobrien			}
115659243Sobrien			Cursor = oldCursor;
115759243Sobrien			*LastChar = '\0';
115859243Sobrien			Refresh();
115959243Sobrien			break;
116059243Sobrien		    } else if (isglob(*cp)) {
116159243Sobrien			SoundBeep();
116259243Sobrien			break;
116359243Sobrien		    }
116459243Sobrien		break;
116559243Sobrien
116659243Sobrien	    default:		/* Terminate and execute cmd */
116759243Sobrien		endcmd[0] = ch;
116859243Sobrien		PushMacro(endcmd);
116959243Sobrien		/*FALLTHROUGH*/
117059243Sobrien
117159243Sobrien	    case 0033:		/* ESC: Terminate */
117259243Sobrien		ret = CC_REFRESH;
117359243Sobrien		done++;
117459243Sobrien		break;
117559243Sobrien	    }
117659243Sobrien	    break;
117759243Sobrien	}
117859243Sobrien
117959243Sobrien	while (LastChar > InputBuf && *LastChar != '\n')
118059243Sobrien	    *LastChar-- = '\0';
118159243Sobrien	*LastChar = '\0';
118259243Sobrien
118359243Sobrien	if (!done) {
118459243Sobrien
118559243Sobrien	    /* Can't search if unmatched '[' */
1186167465Smp	    for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
118759243Sobrien		if (*cp == '[' || *cp == ']') {
118859243Sobrien		    ch = *cp;
118959243Sobrien		    break;
119059243Sobrien		}
119159243Sobrien
1192167465Smp	    if (patbuf.len > 1 && ch != '[') {
119359243Sobrien		if (redo && newdir == dir) {
119459243Sobrien		    if (pchar == '?') {	/* wrap around */
1195167465Smp			Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1196167465Smp			if (GetHistLine() == CC_ERROR)
119759243Sobrien			    /* Hist_num was fixed by first call */
1198167465Smp			    (void) GetHistLine();
119959243Sobrien			Cursor = newdir == F_UP_SEARCH_HIST ?
120059243Sobrien			    LastChar : InputBuf;
120159243Sobrien		    } else
120259243Sobrien			Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
120359243Sobrien		}
1204167465Smp		Strbuf_append1(&patbuf, '*');
1205167465Smp		Strbuf_terminate(&patbuf);
120659243Sobrien		if (Cursor < InputBuf || Cursor > LastChar ||
1207167465Smp		    (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
120859243Sobrien		    LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
120959243Sobrien		    ret = newdir == F_UP_SEARCH_HIST ?
121059243Sobrien			e_up_search_hist(0) : e_down_search_hist(0);
121159243Sobrien		    if (ret != CC_ERROR) {
121259243Sobrien			Cursor = newdir == F_UP_SEARCH_HIST ?
121359243Sobrien			    LastChar : InputBuf;
1214167465Smp			(void) c_search_line(&patbuf.s[1], newdir);
121559243Sobrien		    }
121659243Sobrien		}
1217167465Smp		patbuf.s[--patbuf.len] = '\0';
121859243Sobrien		if (ret == CC_ERROR) {
121959243Sobrien		    SoundBeep();
122059243Sobrien		    if (Hist_num != oldHist_num) {
122159243Sobrien			Hist_num = oldHist_num;
1222167465Smp			if (GetHistLine() == CC_ERROR)
122359243Sobrien			    return(CC_ERROR);
122459243Sobrien		    }
122559243Sobrien		    Cursor = oldCursor;
122659243Sobrien		    pchar = '?';
122759243Sobrien		} else {
122859243Sobrien		    pchar = ':';
122959243Sobrien		}
123059243Sobrien	    }
123159243Sobrien
123259243Sobrien	    ret = e_inc_search(newdir);
123359243Sobrien
123459243Sobrien	    if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
123559243Sobrien		/* break abort of failed search at last non-failed */
123659243Sobrien		ret = CC_NORM;
123759243Sobrien	    }
123859243Sobrien
123959243Sobrien	}
124059243Sobrien
124159243Sobrien	if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
124259243Sobrien	    /* restore on normal return or error exit */
124359243Sobrien	    pchar = oldpchar;
1244167465Smp	    patbuf.len = oldpatlen;
124559243Sobrien	    if (Hist_num != oldHist_num) {
124659243Sobrien		Hist_num = oldHist_num;
1247167465Smp		if (GetHistLine() == CC_ERROR)
124859243Sobrien		    return(CC_ERROR);
124959243Sobrien	    }
125059243Sobrien	    Cursor = oldCursor;
125159243Sobrien	    if (ret == CC_ERROR)
125259243Sobrien		Refresh();
125359243Sobrien	}
125459243Sobrien	if (done || ret != CC_NORM)
125559243Sobrien	    return(ret);
125659243Sobrien
125759243Sobrien    }
125859243Sobrien
125959243Sobrien}
126059243Sobrien
126159243Sobrienstatic CCRETVAL
1262167465Smpv_search(int dir)
126359243Sobrien{
1264167465Smp    struct Strbuf tmpbuf = Strbuf_INIT;
126559243Sobrien    Char ch;
1266167465Smp    Char *oldbuf;
126759243Sobrien    Char *oldlc, *oldc;
126859243Sobrien
1269167465Smp    cleanup_push(&tmpbuf, Strbuf_cleanup);
1270167465Smp    oldbuf = Strsave(InputBuf);
1271167465Smp    cleanup_push(oldbuf, xfree);
127259243Sobrien    oldlc = LastChar;
127359243Sobrien    oldc = Cursor;
1274167465Smp    Strbuf_append1(&tmpbuf, '*');
127559243Sobrien
127659243Sobrien    InputBuf[0] = '\0';
127759243Sobrien    LastChar = InputBuf;
127859243Sobrien    Cursor = InputBuf;
127959243Sobrien    searchdir = dir;
128059243Sobrien
128159243Sobrien    c_insert(2);	/* prompt + '\n' */
128259243Sobrien    *Cursor++ = '\n';
128359243Sobrien    *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
128459243Sobrien    Refresh();
128559243Sobrien    for (ch = 0;ch == 0;) {
1286167465Smp	if (GetNextChar(&ch) != 1) {
1287167465Smp	    cleanup_until(&tmpbuf);
128859243Sobrien	    return(e_send_eof(0));
1289167465Smp	}
129059243Sobrien	switch (ASC(ch)) {
129159243Sobrien	case 0010:	/* Delete and backspace */
129259243Sobrien	case 0177:
1293167465Smp	    if (tmpbuf.len > 1) {
129459243Sobrien		*Cursor-- = '\0';
129559243Sobrien		LastChar = Cursor;
1296167465Smp		tmpbuf.len--;
129759243Sobrien	    }
129859243Sobrien	    else {
1299167465Smp		copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
130059243Sobrien		LastChar = oldlc;
130159243Sobrien		Cursor = oldc;
1302167465Smp		cleanup_until(&tmpbuf);
130359243Sobrien		return(CC_REFRESH);
130459243Sobrien	    }
130559243Sobrien	    Refresh();
130659243Sobrien	    ch = 0;
130759243Sobrien	    break;
130859243Sobrien
130959243Sobrien	case 0033:	/* ESC */
131069408Sache#ifdef IS_ASCII
131159243Sobrien	case '\r':	/* Newline */
131259243Sobrien	case '\n':
131359243Sobrien#else
131469408Sache	case '\012':    /* ASCII Line feed */
131569408Sache	case '\015':    /* ASCII (or EBCDIC) Return */
131659243Sobrien#endif
131759243Sobrien	    break;
131859243Sobrien
131959243Sobrien	default:
1320167465Smp	    Strbuf_append1(&tmpbuf, ch);
1321167465Smp	    *Cursor++ = ch;
1322167465Smp	    LastChar = Cursor;
132359243Sobrien	    Refresh();
132459243Sobrien	    ch = 0;
132559243Sobrien	    break;
132659243Sobrien	}
132759243Sobrien    }
1328167465Smp    cleanup_until(oldbuf);
132959243Sobrien
1330167465Smp    if (tmpbuf.len == 1) {
133159243Sobrien	/*
133259243Sobrien	 * Use the old pattern, but wild-card it.
133359243Sobrien	 */
1334167465Smp	if (patbuf.len == 0) {
133559243Sobrien	    InputBuf[0] = '\0';
133659243Sobrien	    LastChar = InputBuf;
133759243Sobrien	    Cursor = InputBuf;
133859243Sobrien	    Refresh();
1339167465Smp	    cleanup_until(&tmpbuf);
134059243Sobrien	    return(CC_ERROR);
134159243Sobrien	}
1342167465Smp	if (patbuf.s[0] != '*') {
1343167465Smp	    oldbuf = Strsave(patbuf.s);
1344167465Smp	    patbuf.len = 0;
1345167465Smp	    Strbuf_append1(&patbuf, '*');
1346167465Smp	    Strbuf_append(&patbuf, oldbuf);
1347167465Smp	    xfree(oldbuf);
1348167465Smp	    Strbuf_append1(&patbuf, '*');
1349167465Smp	    Strbuf_terminate(&patbuf);
135059243Sobrien	}
135159243Sobrien    }
135259243Sobrien    else {
1353167465Smp	Strbuf_append1(&tmpbuf, '*');
1354167465Smp	Strbuf_terminate(&tmpbuf);
1355167465Smp	patbuf.len = 0;
1356167465Smp	Strbuf_append(&patbuf, tmpbuf.s);
1357167465Smp	Strbuf_terminate(&patbuf);
135859243Sobrien    }
1359167465Smp    cleanup_until(&tmpbuf);
136059243Sobrien    LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
136159243Sobrien    Cursor = LastChar = InputBuf;
136259243Sobrien    if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
136359243Sobrien				   e_down_search_hist(0)) == CC_ERROR) {
136459243Sobrien	Refresh();
136559243Sobrien	return(CC_ERROR);
136659243Sobrien    }
136759243Sobrien    else {
1368167465Smp	if (ASC(ch) == 0033) {
136959243Sobrien	    Refresh();
137059243Sobrien	    *LastChar++ = '\n';
137159243Sobrien	    *LastChar = '\0';
137259243Sobrien	    PastBottom();
137359243Sobrien	    return(CC_NEWLINE);
137459243Sobrien	}
137559243Sobrien	else
137659243Sobrien	    return(CC_REFRESH);
137759243Sobrien    }
137859243Sobrien}
137959243Sobrien
138059243Sobrien/*
138159243Sobrien * semi-PUBLIC routines.  Any routine that is of type CCRETVAL is an
138259243Sobrien * entry point, called from the CcKeyMap indirected into the
138359243Sobrien * CcFuncTbl array.
138459243Sobrien */
138559243Sobrien
138659243Sobrien/*ARGSUSED*/
138759243SobrienCCRETVAL
1388167465Smpv_cmd_mode(Char c)
138959243Sobrien{
139059243Sobrien    USE(c);
139159243Sobrien    InsertPos = 0;
139259243Sobrien    ActionFlag = TCSHOP_NOP;	/* [Esc] cancels pending action */
139359243Sobrien    ActionPos = 0;
139459243Sobrien    DoingArg = 0;
139559243Sobrien    if (UndoPtr > Cursor)
139659243Sobrien	UndoSize = (int)(UndoPtr - Cursor);
139759243Sobrien    else
139859243Sobrien	UndoSize = (int)(Cursor - UndoPtr);
139959243Sobrien
140059243Sobrien    inputmode = MODE_INSERT;
140159243Sobrien    c_alternativ_key_map(1);
140259243Sobrien#ifdef notdef
140359243Sobrien    /*
140459243Sobrien     * We don't want to move the cursor, because all the editing
140559243Sobrien     * commands don't include the character under the cursor.
140659243Sobrien     */
140759243Sobrien    if (Cursor > InputBuf)
140859243Sobrien	Cursor--;
140959243Sobrien#endif
141059243Sobrien    RefCursor();
141159243Sobrien    return(CC_NORM);
141259243Sobrien}
141359243Sobrien
141459243Sobrien/*ARGSUSED*/
141559243SobrienCCRETVAL
1416167465Smpe_unassigned(Char c)
141759243Sobrien{				/* bound to keys that arn't really assigned */
141859243Sobrien    USE(c);
141959243Sobrien    SoundBeep();
142059243Sobrien    flush();
142159243Sobrien    return(CC_NORM);
142259243Sobrien}
142359243Sobrien
1424167465Smp#ifdef notyet
1425145479Smpstatic CCRETVAL
1426167465Smpe_insert_str(Char *c)
1427145479Smp{
1428145479Smp    int i, n;
1429145479Smp
1430145479Smp    n = Strlen(c);
1431145479Smp    if (LastChar + Argument * n >= InputLim)
1432145479Smp	return(CC_ERROR);	/* end of buffer space */
1433145479Smp    if (inputmode != MODE_INSERT) {
1434167465Smp	c_delafter(Argument * Strlen(c));
1435145479Smp    }
1436145479Smp    c_insert(Argument * n);
1437145479Smp    while (Argument--) {
1438145479Smp	for (i = 0; i < n; i++)
1439145479Smp	    *Cursor++ = c[i];
1440145479Smp    }
1441145479Smp    Refresh();
1442145479Smp    return(CC_NORM);
1443145479Smp}
1444167465Smp#endif
1445145479Smp
144659243SobrienCCRETVAL
1447167465Smpe_insert(Char c)
144859243Sobrien{
144959243Sobrien#ifndef SHORT_STRINGS
145059243Sobrien    c &= ASCII;			/* no meta chars ever */
145159243Sobrien#endif
145259243Sobrien
145359243Sobrien    if (!c)
145459243Sobrien	return(CC_ERROR);	/* no NULs in the input ever!! */
145559243Sobrien
145659243Sobrien    if (LastChar + Argument >= InputLim)
145759243Sobrien	return(CC_ERROR);	/* end of buffer space */
145859243Sobrien
145959243Sobrien    if (Argument == 1) {  	/* How was this optimized ???? */
146059243Sobrien
146159243Sobrien	if (inputmode != MODE_INSERT) {
146259243Sobrien	    UndoBuf[UndoSize++] = *Cursor;
146359243Sobrien	    UndoBuf[UndoSize] = '\0';
146459243Sobrien	    c_delafter(1);   /* Do NOT use the saving ONE */
146559243Sobrien    	}
146659243Sobrien
146759243Sobrien        c_insert(1);
146859243Sobrien	*Cursor++ = (Char) c;
146959243Sobrien	DoingArg = 0;		/* just in case */
1470145479Smp	RefPlusOne(1);		/* fast refresh for one char. */
147159243Sobrien    }
147259243Sobrien    else {
147359243Sobrien	if (inputmode != MODE_INSERT) {
1474145479Smp	    int i;
1475145479Smp	    for(i = 0; i < Argument; i++)
1476145479Smp		UndoBuf[UndoSize++] = *(Cursor + i);
147759243Sobrien
147859243Sobrien	    UndoBuf[UndoSize] = '\0';
147959243Sobrien	    c_delafter(Argument);   /* Do NOT use the saving ONE */
148059243Sobrien    	}
148159243Sobrien
148259243Sobrien        c_insert(Argument);
148359243Sobrien
148459243Sobrien	while (Argument--)
148559243Sobrien	    *Cursor++ = (Char) c;
148659243Sobrien	Refresh();
148759243Sobrien    }
148859243Sobrien
148959243Sobrien    if (inputmode == MODE_REPLACE_1)
149059243Sobrien	(void) v_cmd_mode(0);
149159243Sobrien
149259243Sobrien    return(CC_NORM);
149359243Sobrien}
149459243Sobrien
149559243Sobrienint
1496167465SmpInsertStr(Char *s)		/* insert ASCIZ s at cursor (for complete) */
149759243Sobrien{
149883098Smp    int len;
149959243Sobrien
150059243Sobrien    if ((len = (int) Strlen(s)) <= 0)
150159243Sobrien	return -1;
150259243Sobrien    if (LastChar + len >= InputLim)
150359243Sobrien	return -1;		/* end of buffer space */
150459243Sobrien
150559243Sobrien    c_insert(len);
150659243Sobrien    while (len--)
150759243Sobrien	*Cursor++ = *s++;
150859243Sobrien    return 0;
150959243Sobrien}
151059243Sobrien
151159243Sobrienvoid
1512167465SmpDeleteBack(int n)		/* delete the n characters before . */
151359243Sobrien{
151459243Sobrien    if (n <= 0)
151559243Sobrien	return;
151659243Sobrien    if (Cursor >= &InputBuf[n]) {
151759243Sobrien	c_delbefore(n);		/* delete before dot */
151859243Sobrien    }
151959243Sobrien}
152059243Sobrien
152159243SobrienCCRETVAL
1522167465Smpe_digit(Char c)			/* gray magic here */
152359243Sobrien{
152459243Sobrien    if (!Isdigit(c))
152559243Sobrien	return(CC_ERROR);	/* no NULs in the input ever!! */
152659243Sobrien
152759243Sobrien    if (DoingArg) {		/* if doing an arg, add this in... */
152859243Sobrien	if (LastCmd == F_ARGFOUR)	/* if last command was ^U */
152959243Sobrien	    Argument = c - '0';
153059243Sobrien	else {
153159243Sobrien	    if (Argument > 1000000)
153259243Sobrien		return CC_ERROR;
153359243Sobrien	    Argument = (Argument * 10) + (c - '0');
153459243Sobrien	}
153559243Sobrien	return(CC_ARGHACK);
153659243Sobrien    }
153759243Sobrien    else {
153859243Sobrien	if (LastChar + 1 >= InputLim)
153959243Sobrien	    return CC_ERROR;	/* end of buffer space */
154059243Sobrien
154159243Sobrien	if (inputmode != MODE_INSERT) {
154259243Sobrien	    UndoBuf[UndoSize++] = *Cursor;
154359243Sobrien	    UndoBuf[UndoSize] = '\0';
154459243Sobrien	    c_delafter(1);   /* Do NOT use the saving ONE */
154559243Sobrien    	}
154659243Sobrien	c_insert(1);
154759243Sobrien	*Cursor++ = (Char) c;
154859243Sobrien	DoingArg = 0;		/* just in case */
1549145479Smp	RefPlusOne(1);		/* fast refresh for one char. */
155059243Sobrien    }
155159243Sobrien    return(CC_NORM);
155259243Sobrien}
155359243Sobrien
155459243SobrienCCRETVAL
1555167465Smpe_argdigit(Char c)		/* for ESC-n */
155659243Sobrien{
1557167465Smp#ifdef IS_ASCII
155859243Sobrien    c &= ASCII;
1559167465Smp#else
1560167465Smp    c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1561167465Smp#endif
156259243Sobrien
156359243Sobrien    if (!Isdigit(c))
156459243Sobrien	return(CC_ERROR);	/* no NULs in the input ever!! */
156559243Sobrien
156659243Sobrien    if (DoingArg) {		/* if doing an arg, add this in... */
156759243Sobrien	if (Argument > 1000000)
156859243Sobrien	    return CC_ERROR;
156959243Sobrien	Argument = (Argument * 10) + (c - '0');
157059243Sobrien    }
157159243Sobrien    else {			/* else starting an argument */
157259243Sobrien	Argument = c - '0';
157359243Sobrien	DoingArg = 1;
157459243Sobrien    }
157559243Sobrien    return(CC_ARGHACK);
157659243Sobrien}
157759243Sobrien
157859243SobrienCCRETVAL
1579167465Smpv_zero(Char c)			/* command mode 0 for vi */
158059243Sobrien{
158159243Sobrien    if (DoingArg) {		/* if doing an arg, add this in... */
158259243Sobrien	if (Argument > 1000000)
158359243Sobrien	    return CC_ERROR;
158459243Sobrien	Argument = (Argument * 10) + (c - '0');
158559243Sobrien	return(CC_ARGHACK);
158659243Sobrien    }
158759243Sobrien    else {			/* else starting an argument */
158859243Sobrien	Cursor = InputBuf;
158959243Sobrien	if (ActionFlag & TCSHOP_DELETE) {
159059243Sobrien	   c_delfini();
159159243Sobrien	   return(CC_REFRESH);
159259243Sobrien        }
159359243Sobrien	RefCursor();		/* move the cursor */
159459243Sobrien	return(CC_NORM);
159559243Sobrien    }
159659243Sobrien}
159759243Sobrien
159859243Sobrien/*ARGSUSED*/
159959243SobrienCCRETVAL
1600167465Smpe_newline(Char c)
160159243Sobrien{				/* always ignore argument */
160259243Sobrien    USE(c);
1603167465Smp    if (adrof(STRhighlight) && MarkIsSet) {
1604167465Smp	MarkIsSet = 0;
1605167465Smp	ClearLines();
1606167465Smp	ClearDisp();
1607167465Smp	Refresh();
1608167465Smp    }
1609167465Smp    MarkIsSet = 0;
1610167465Smp
161159243Sobrien  /*  PastBottom();  NOW done in ed.inputl.c */
161259243Sobrien    *LastChar++ = '\n';		/* for the benefit of CSH */
161359243Sobrien    *LastChar = '\0';		/* just in case */
161459243Sobrien    if (VImode)
161559243Sobrien	InsertPos = InputBuf;	/* Reset editing position */
161659243Sobrien    return(CC_NEWLINE);
161759243Sobrien}
161859243Sobrien
161959243Sobrien/*ARGSUSED*/
162059243SobrienCCRETVAL
1621167465Smpe_newline_hold(Char c)
1622167465Smp{
1623167465Smp    USE(c);
1624167465Smp    c_save_inputbuf();
1625167465Smp    HistSaved = 0;
1626167465Smp    *LastChar++ = '\n';		/* for the benefit of CSH */
1627167465Smp    *LastChar = '\0';		/* just in case */
1628167465Smp    return(CC_NEWLINE);
1629167465Smp}
1630167465Smp
1631167465Smp/*ARGSUSED*/
1632167465SmpCCRETVAL
1633167465Smpe_newline_down_hist(Char c)
1634167465Smp{
1635167465Smp    USE(c);
1636167465Smp    if (Hist_num > 1) {
1637167465Smp	HistSaved = Hist_num;
1638167465Smp    }
1639167465Smp    *LastChar++ = '\n';		/* for the benefit of CSH */
1640167465Smp    *LastChar = '\0';		/* just in case */
1641167465Smp    return(CC_NEWLINE);
1642167465Smp}
1643167465Smp
1644167465Smp/*ARGSUSED*/
1645167465SmpCCRETVAL
1646167465Smpe_send_eof(Char c)
164759243Sobrien{				/* for when ^D is ONLY send-eof */
164859243Sobrien    USE(c);
164959243Sobrien    PastBottom();
165059243Sobrien    *LastChar = '\0';		/* just in case */
165159243Sobrien    return(CC_EOF);
165259243Sobrien}
165359243Sobrien
165459243Sobrien/*ARGSUSED*/
165559243SobrienCCRETVAL
1656167465Smpe_complete(Char c)
165759243Sobrien{
165859243Sobrien    USE(c);
165959243Sobrien    *LastChar = '\0';		/* just in case */
166059243Sobrien    return(CC_COMPLETE);
166159243Sobrien}
166259243Sobrien
166359243Sobrien/*ARGSUSED*/
166459243SobrienCCRETVAL
1665167465Smpe_complete_back(Char c)
166659243Sobrien{
166759243Sobrien    USE(c);
166859243Sobrien    *LastChar = '\0';		/* just in case */
166959243Sobrien    return(CC_COMPLETE_BACK);
167059243Sobrien}
167159243Sobrien
167259243Sobrien/*ARGSUSED*/
167359243SobrienCCRETVAL
1674167465Smpe_complete_fwd(Char c)
167559243Sobrien{
167659243Sobrien    USE(c);
167759243Sobrien    *LastChar = '\0';		/* just in case */
167859243Sobrien    return(CC_COMPLETE_FWD);
167959243Sobrien}
168059243Sobrien
168159243Sobrien/*ARGSUSED*/
168259243SobrienCCRETVAL
1683167465Smpe_complete_all(Char c)
168459243Sobrien{
168559243Sobrien    USE(c);
168659243Sobrien    *LastChar = '\0';		/* just in case */
168759243Sobrien    return(CC_COMPLETE_ALL);
168859243Sobrien}
168959243Sobrien
169059243Sobrien/*ARGSUSED*/
169159243SobrienCCRETVAL
1692167465Smpv_cm_complete(Char c)
169359243Sobrien{
169459243Sobrien    USE(c);
169559243Sobrien    if (Cursor < LastChar)
169659243Sobrien	Cursor++;
169759243Sobrien    *LastChar = '\0';		/* just in case */
169859243Sobrien    return(CC_COMPLETE);
169959243Sobrien}
170059243Sobrien
170159243Sobrien/*ARGSUSED*/
170259243SobrienCCRETVAL
1703167465Smpe_toggle_hist(Char c)
170459243Sobrien{
170559243Sobrien    struct Hist *hp;
170659243Sobrien    int     h;
170759243Sobrien
170859243Sobrien    USE(c);
170959243Sobrien    *LastChar = '\0';		/* just in case */
171059243Sobrien
171159243Sobrien    if (Hist_num <= 0) {
171259243Sobrien	return CC_ERROR;
171359243Sobrien    }
171459243Sobrien
171559243Sobrien    hp = Histlist.Hnext;
171659243Sobrien    if (hp == NULL) {	/* this is only if no history */
171759243Sobrien	return(CC_ERROR);
171859243Sobrien    }
171959243Sobrien
172059243Sobrien    for (h = 1; h < Hist_num; h++)
172159243Sobrien	hp = hp->Hnext;
172259243Sobrien
172359243Sobrien    if (!CurrentHistLit) {
172459243Sobrien	if (hp->histline) {
1725167465Smp	    copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
172659243Sobrien	    CurrentHistLit = 1;
172759243Sobrien	}
172859243Sobrien	else {
172959243Sobrien	    return CC_ERROR;
173059243Sobrien	}
173159243Sobrien    }
173259243Sobrien    else {
1733167465Smp	Char *p;
1734167465Smp
1735167465Smp	p = sprlex(&hp->Hlex);
1736167465Smp	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1737167465Smp	xfree(p);
173859243Sobrien	CurrentHistLit = 0;
173959243Sobrien    }
174059243Sobrien
1741167465Smp    LastChar = Strend(InputBuf);
174259243Sobrien    if (LastChar > InputBuf) {
174359243Sobrien	if (LastChar[-1] == '\n')
174459243Sobrien	    LastChar--;
174559243Sobrien	if (LastChar[-1] == ' ')
174659243Sobrien	    LastChar--;
174759243Sobrien	if (LastChar < InputBuf)
174859243Sobrien	    LastChar = InputBuf;
174959243Sobrien    }
175059243Sobrien
175159243Sobrien#ifdef KSHVI
175259243Sobrien    if (VImode)
175359243Sobrien	Cursor = InputBuf;
175459243Sobrien    else
175559243Sobrien#endif /* KSHVI */
175659243Sobrien	Cursor = LastChar;
175759243Sobrien
175859243Sobrien    return(CC_REFRESH);
175959243Sobrien}
176059243Sobrien
176159243Sobrien/*ARGSUSED*/
176259243SobrienCCRETVAL
1763167465Smpe_up_hist(Char c)
176459243Sobrien{
176559243Sobrien    Char    beep = 0;
176659243Sobrien
176759243Sobrien    USE(c);
176859243Sobrien    UndoAction = TCSHOP_NOP;
176959243Sobrien    *LastChar = '\0';		/* just in case */
177059243Sobrien
177159243Sobrien    if (Hist_num == 0) {	/* save the current buffer away */
1772167465Smp	HistBuf.len = 0;
1773167465Smp	Strbuf_append(&HistBuf, InputBuf);
1774167465Smp	Strbuf_terminate(&HistBuf);
177559243Sobrien    }
177659243Sobrien
177759243Sobrien    Hist_num += Argument;
177859243Sobrien
1779167465Smp    if (GetHistLine() == CC_ERROR) {
178059243Sobrien	beep = 1;
1781167465Smp	(void) GetHistLine(); /* Hist_num was fixed by first call */
178259243Sobrien    }
178359243Sobrien
178459243Sobrien    Refresh();
178559243Sobrien    if (beep)
178659243Sobrien	return(CC_ERROR);
178759243Sobrien    else
178859243Sobrien	return(CC_NORM);	/* was CC_UP_HIST */
178959243Sobrien}
179059243Sobrien
179159243Sobrien/*ARGSUSED*/
179259243SobrienCCRETVAL
1793167465Smpe_down_hist(Char c)
179459243Sobrien{
179559243Sobrien    USE(c);
179659243Sobrien    UndoAction = TCSHOP_NOP;
179759243Sobrien    *LastChar = '\0';		/* just in case */
179859243Sobrien
179959243Sobrien    Hist_num -= Argument;
180059243Sobrien
180159243Sobrien    if (Hist_num < 0) {
180259243Sobrien	Hist_num = 0;
180359243Sobrien	return(CC_ERROR);	/* make it beep */
180459243Sobrien    }
180559243Sobrien
1806167465Smp    return(GetHistLine());
180759243Sobrien}
180859243Sobrien
180959243Sobrien
181059243Sobrien
181159243Sobrien/*
181259243Sobrien * c_hmatch() return True if the pattern matches the prefix
181359243Sobrien */
181459243Sobrienstatic int
1815167465Smpc_hmatch(Char *str)
181659243Sobrien{
1817167465Smp    if (Strncmp(patbuf.s, str, patbuf.len) == 0)
181859243Sobrien	return 1;
1819167465Smp    return Gmatch(str, patbuf.s);
182059243Sobrien}
182159243Sobrien
182259243Sobrien/*
182359243Sobrien * c_hsetpat(): Set the history seatch pattern
182459243Sobrien */
182559243Sobrienstatic void
1826167465Smpc_hsetpat(void)
182759243Sobrien{
182859243Sobrien    if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1829167465Smp	patbuf.len = 0;
1830167465Smp	Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1831167465Smp	Strbuf_terminate(&patbuf);
183259243Sobrien    }
183359243Sobrien#ifdef SDEBUG
183459243Sobrien    xprintf("\nHist_num = %d\n", Hist_num);
1835167465Smp    xprintf("patlen = %d\n", (int)patbuf.len);
1836167465Smp    xprintf("patbuf = \"%S\"\n", patbuf.s);
183759243Sobrien    xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
183859243Sobrien#endif
183959243Sobrien}
184059243Sobrien
184159243Sobrien/*ARGSUSED*/
184259243SobrienCCRETVAL
1843167465Smpe_up_search_hist(Char c)
184459243Sobrien{
184559243Sobrien    struct Hist *hp;
184659243Sobrien    int h;
1847145479Smp    int    found = 0;
184859243Sobrien
184959243Sobrien    USE(c);
185059243Sobrien    ActionFlag = TCSHOP_NOP;
185159243Sobrien    UndoAction = TCSHOP_NOP;
185259243Sobrien    *LastChar = '\0';		/* just in case */
185359243Sobrien    if (Hist_num < 0) {
185459243Sobrien#ifdef DEBUG_EDIT
185559243Sobrien	xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
185659243Sobrien#endif
185759243Sobrien	Hist_num = 0;
185859243Sobrien	return(CC_ERROR);
185959243Sobrien    }
186059243Sobrien
1861167465Smp    if (Hist_num == 0) {
1862167465Smp	HistBuf.len = 0;
1863167465Smp	Strbuf_append(&HistBuf, InputBuf);
1864167465Smp	Strbuf_terminate(&HistBuf);
186559243Sobrien    }
186659243Sobrien
186759243Sobrien
186859243Sobrien    hp = Histlist.Hnext;
186959243Sobrien    if (hp == NULL)
187059243Sobrien	return(CC_ERROR);
187159243Sobrien
187259243Sobrien    c_hsetpat();		/* Set search pattern !! */
187359243Sobrien
187459243Sobrien    for (h = 1; h <= Hist_num; h++)
187559243Sobrien	hp = hp->Hnext;
187659243Sobrien
187759243Sobrien    while (hp != NULL) {
1878167465Smp	Char *hl;
1879167465Smp	int matched;
1880167465Smp
1881167465Smp	if (hp->histline == NULL)
1882167465Smp	    hp->histline = sprlex(&hp->Hlex);
1883167465Smp	if (HistLit)
1884167465Smp	    hl = hp->histline;
1885167465Smp	else {
1886167465Smp	    hl = sprlex(&hp->Hlex);
1887167465Smp	    cleanup_push(hl, xfree);
188859243Sobrien	}
188959243Sobrien#ifdef SDEBUG
189059243Sobrien	xprintf("Comparing with \"%S\"\n", hl);
189159243Sobrien#endif
1892167465Smp	matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1893167465Smp		   hl[LastChar-InputBuf]) && c_hmatch(hl);
1894167465Smp	if (!HistLit)
1895167465Smp	    cleanup_until(hl);
1896167465Smp	if (matched) {
189759243Sobrien	    found++;
189859243Sobrien	    break;
189959243Sobrien	}
190059243Sobrien	h++;
190159243Sobrien	hp = hp->Hnext;
190259243Sobrien    }
190359243Sobrien
190459243Sobrien    if (!found) {
190559243Sobrien#ifdef SDEBUG
1906167465Smp	xprintf("not found\n");
190759243Sobrien#endif
190859243Sobrien	return(CC_ERROR);
190959243Sobrien    }
191059243Sobrien
191159243Sobrien    Hist_num = h;
191259243Sobrien
1913167465Smp    return(GetHistLine());
191459243Sobrien}
191559243Sobrien
191659243Sobrien/*ARGSUSED*/
191759243SobrienCCRETVAL
1918167465Smpe_down_search_hist(Char c)
191959243Sobrien{
192059243Sobrien    struct Hist *hp;
192159243Sobrien    int h;
1922145479Smp    int    found = 0;
192359243Sobrien
192459243Sobrien    USE(c);
192559243Sobrien    ActionFlag = TCSHOP_NOP;
192659243Sobrien    UndoAction = TCSHOP_NOP;
192759243Sobrien    *LastChar = '\0';		/* just in case */
192859243Sobrien
192959243Sobrien    if (Hist_num == 0)
193059243Sobrien	return(CC_ERROR);
193159243Sobrien
193259243Sobrien    hp = Histlist.Hnext;
193359243Sobrien    if (hp == 0)
193459243Sobrien	return(CC_ERROR);
193559243Sobrien
193659243Sobrien    c_hsetpat();		/* Set search pattern !! */
193759243Sobrien
193859243Sobrien    for (h = 1; h < Hist_num && hp; h++) {
1939167465Smp	Char *hl;
1940167465Smp	if (hp->histline == NULL)
1941167465Smp	    hp->histline = sprlex(&hp->Hlex);
1942167465Smp	if (HistLit)
1943167465Smp	    hl = hp->histline;
1944167465Smp	else {
1945167465Smp	    hl = sprlex(&hp->Hlex);
1946167465Smp	    cleanup_push(hl, xfree);
194759243Sobrien	}
194859243Sobrien#ifdef SDEBUG
194959243Sobrien	xprintf("Comparing with \"%S\"\n", hl);
195059243Sobrien#endif
195159243Sobrien	if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
195259243Sobrien	     hl[LastChar-InputBuf]) && c_hmatch(hl))
195359243Sobrien	    found = h;
1954167465Smp	if (!HistLit)
1955167465Smp	    cleanup_until(hl);
195659243Sobrien	hp = hp->Hnext;
195759243Sobrien    }
195859243Sobrien
195959243Sobrien    if (!found) {		/* is it the current history number? */
1960167465Smp	if (!c_hmatch(HistBuf.s)) {
196159243Sobrien#ifdef SDEBUG
1962167465Smp	    xprintf("not found\n");
196359243Sobrien#endif
196459243Sobrien	    return(CC_ERROR);
196559243Sobrien	}
196659243Sobrien    }
196759243Sobrien
196859243Sobrien    Hist_num = found;
196959243Sobrien
1970167465Smp    return(GetHistLine());
197159243Sobrien}
197259243Sobrien
197359243Sobrien/*ARGSUSED*/
197459243SobrienCCRETVAL
1975167465Smpe_helpme(Char c)
197659243Sobrien{
197759243Sobrien    USE(c);
197859243Sobrien    PastBottom();
197959243Sobrien    *LastChar = '\0';		/* just in case */
198059243Sobrien    return(CC_HELPME);
198159243Sobrien}
198259243Sobrien
198359243Sobrien/*ARGSUSED*/
198459243SobrienCCRETVAL
1985167465Smpe_correct(Char c)
198659243Sobrien{
198759243Sobrien    USE(c);
198859243Sobrien    *LastChar = '\0';		/* just in case */
198959243Sobrien    return(CC_CORRECT);
199059243Sobrien}
199159243Sobrien
199259243Sobrien/*ARGSUSED*/
199359243SobrienCCRETVAL
1994167465Smpe_correctl(Char c)
199559243Sobrien{
199659243Sobrien    USE(c);
199759243Sobrien    *LastChar = '\0';		/* just in case */
199859243Sobrien    return(CC_CORRECT_L);
199959243Sobrien}
200059243Sobrien
200159243Sobrien/*ARGSUSED*/
200259243SobrienCCRETVAL
2003167465Smpe_run_fg_editor(Char c)
200459243Sobrien{
200583098Smp    struct process *pp;
200659243Sobrien
200759243Sobrien    USE(c);
200859243Sobrien    if ((pp = find_stop_ed()) != NULL) {
200959243Sobrien	/* save our editor state so we can restore it */
2010167465Smp	c_save_inputbuf();
201159243Sobrien	Hist_num = 0;		/* for the history commands */
201259243Sobrien
201359243Sobrien	/* put the tty in a sane mode */
201459243Sobrien	PastBottom();
201559243Sobrien	(void) Cookedmode();	/* make sure the tty is set up correctly */
201659243Sobrien
201759243Sobrien	/* do it! */
201859243Sobrien	fg_proc_entry(pp);
201959243Sobrien
202059243Sobrien	(void) Rawmode();	/* go on */
202159243Sobrien	Refresh();
2022167465Smp	RestoreSaved = 0;
2023167465Smp	HistSaved = 0;
202459243Sobrien    }
202559243Sobrien    return(CC_NORM);
202659243Sobrien}
202759243Sobrien
202859243Sobrien/*ARGSUSED*/
202959243SobrienCCRETVAL
2030167465Smpe_list_choices(Char c)
203159243Sobrien{
203259243Sobrien    USE(c);
203359243Sobrien    PastBottom();
203459243Sobrien    *LastChar = '\0';		/* just in case */
203559243Sobrien    return(CC_LIST_CHOICES);
203659243Sobrien}
203759243Sobrien
203859243Sobrien/*ARGSUSED*/
203959243SobrienCCRETVAL
2040167465Smpe_list_all(Char c)
204159243Sobrien{
204259243Sobrien    USE(c);
204359243Sobrien    PastBottom();
204459243Sobrien    *LastChar = '\0';		/* just in case */
204559243Sobrien    return(CC_LIST_ALL);
204659243Sobrien}
204759243Sobrien
204859243Sobrien/*ARGSUSED*/
204959243SobrienCCRETVAL
2050167465Smpe_list_glob(Char c)
205159243Sobrien{
205259243Sobrien    USE(c);
205359243Sobrien    PastBottom();
205459243Sobrien    *LastChar = '\0';		/* just in case */
205559243Sobrien    return(CC_LIST_GLOB);
205659243Sobrien}
205759243Sobrien
205859243Sobrien/*ARGSUSED*/
205959243SobrienCCRETVAL
2060167465Smpe_expand_glob(Char c)
206159243Sobrien{
206259243Sobrien    USE(c);
206359243Sobrien    *LastChar = '\0';		/* just in case */
206459243Sobrien    return(CC_EXPAND_GLOB);
206559243Sobrien}
206659243Sobrien
206759243Sobrien/*ARGSUSED*/
206859243SobrienCCRETVAL
2069167465Smpe_normalize_path(Char c)
207059243Sobrien{
207159243Sobrien    USE(c);
207259243Sobrien    *LastChar = '\0';		/* just in case */
207359243Sobrien    return(CC_NORMALIZE_PATH);
207459243Sobrien}
207559243Sobrien
207659243Sobrien/*ARGSUSED*/
207759243SobrienCCRETVAL
2078167465Smpe_normalize_command(Char c)
207959243Sobrien{
208059243Sobrien    USE(c);
208159243Sobrien    *LastChar = '\0';		/* just in case */
208259243Sobrien    return(CC_NORMALIZE_COMMAND);
208359243Sobrien}
208459243Sobrien
208559243Sobrien/*ARGSUSED*/
208659243SobrienCCRETVAL
2087167465Smpe_expand_vars(Char c)
208859243Sobrien{
208959243Sobrien    USE(c);
209059243Sobrien    *LastChar = '\0';		/* just in case */
209159243Sobrien    return(CC_EXPAND_VARS);
209259243Sobrien}
209359243Sobrien
209459243Sobrien/*ARGSUSED*/
209559243SobrienCCRETVAL
2096167465Smpe_which(Char c)
209759243Sobrien{				/* do a fast command line which(1) */
209859243Sobrien    USE(c);
2099167465Smp    c_save_inputbuf();
2100167465Smp    Hist_num = 0;		/* for the history commands */
210159243Sobrien    PastBottom();
210259243Sobrien    *LastChar = '\0';		/* just in case */
210359243Sobrien    return(CC_WHICH);
210459243Sobrien}
210559243Sobrien
210659243Sobrien/*ARGSUSED*/
210759243SobrienCCRETVAL
2108167465Smpe_last_item(Char c)
210959243Sobrien{				/* insert the last element of the prev. cmd */
211083098Smp    struct Hist *hp;
211183098Smp    struct wordent *wp, *firstp;
211283098Smp    int i;
2113167465Smp    Char *expanded;
211459243Sobrien
211559243Sobrien    USE(c);
211659243Sobrien    if (Argument <= 0)
211759243Sobrien	return(CC_ERROR);
211859243Sobrien
211959243Sobrien    hp = Histlist.Hnext;
212059243Sobrien    if (hp == NULL) {	/* this is only if no history */
212159243Sobrien	return(CC_ERROR);
212259243Sobrien    }
212359243Sobrien
212459243Sobrien    wp = (hp->Hlex).prev;
212559243Sobrien
212659243Sobrien    if (wp->prev == (struct wordent *) NULL)
212759243Sobrien	return(CC_ERROR);	/* an empty history entry */
212859243Sobrien
212959243Sobrien    firstp = (hp->Hlex).next;
213059243Sobrien
213159243Sobrien    /* back up arg words in lex */
213259243Sobrien    for (i = 0; i < Argument && wp != firstp; i++) {
213359243Sobrien	wp = wp->prev;
213459243Sobrien    }
213559243Sobrien
2136167465Smp    expanded = expand_lex(wp->prev, 0, i - 1);
2137167465Smp    if (InsertStr(expanded)) {
2138167465Smp	xfree(expanded);
213959243Sobrien	return(CC_ERROR);
2140167465Smp    }
214159243Sobrien
2142167465Smp    xfree(expanded);
214359243Sobrien    return(CC_REFRESH);
214459243Sobrien}
214559243Sobrien
214659243Sobrien/*ARGSUSED*/
214759243SobrienCCRETVAL
2148167465Smpe_dabbrev_expand(Char c)
214959243Sobrien{				/* expand to preceding word matching prefix */
215083098Smp    Char *cp, *ncp, *bp;
215183098Smp    struct Hist *hp;
2152167465Smp    int arg = 0, i;
2153167465Smp    size_t len = 0;
2154145479Smp    int found = 0;
2155167465Smp    Char *hbuf;
215659243Sobrien    static int oldevent, hist, word;
215759243Sobrien    static Char *start, *oldcursor;
215859243Sobrien
215959243Sobrien    USE(c);
216059243Sobrien    if (Argument <= 0)
216159243Sobrien	return(CC_ERROR);
216259243Sobrien
216383098Smp    cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
216459243Sobrien    if (cp == Cursor || Isspace(*cp))
216559243Sobrien	return(CC_ERROR);
216659243Sobrien
2167167465Smp    hbuf = NULL;
216859243Sobrien    hp = Histlist.Hnext;
216959243Sobrien    bp = InputBuf;
217059243Sobrien    if (Argument == 1 && eventno == oldevent && cp == start &&
2171167465Smp	Cursor == oldcursor && patbuf.len > 0
2172167465Smp	&& Strncmp(patbuf.s, cp, patbuf.len) == 0){
217359243Sobrien	/* continue previous search - go to last match (hist/word) */
217459243Sobrien	if (hist != 0) {		/* need to move up history */
217559243Sobrien	    for (i = 1; i < hist && hp != NULL; i++)
217659243Sobrien		hp = hp->Hnext;
217759243Sobrien	    if (hp == NULL)	/* "can't happen" */
2178167465Smp		goto err_hbuf;
2179167465Smp	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2180167465Smp	    cp = Strend(hbuf);
218159243Sobrien	    bp = hbuf;
218259243Sobrien	    hp = hp->Hnext;
218359243Sobrien	}
218483098Smp	cp = c_preword(cp, bp, word, STRshwordsep);
218559243Sobrien    } else {			/* starting new search */
218659243Sobrien	oldevent = eventno;
218759243Sobrien	start = cp;
2188167465Smp	patbuf.len = 0;
2189167465Smp	Strbuf_appendn(&patbuf, cp, Cursor - cp);
219059243Sobrien	hist = 0;
219159243Sobrien	word = 0;
219259243Sobrien    }
219359243Sobrien
219459243Sobrien    while (!found) {
219583098Smp	ncp = c_preword(cp, bp, 1, STRshwordsep);
219659243Sobrien	if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
219759243Sobrien	    hist++;
219859243Sobrien	    word = 0;
219959243Sobrien	    if (hp == NULL)
2200167465Smp		goto err_hbuf;
2201167465Smp	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2202167465Smp	    cp = Strend(hbuf);
220359243Sobrien	    bp = hbuf;
220459243Sobrien	    hp = hp->Hnext;
220559243Sobrien	    continue;
220659243Sobrien	} else {
220759243Sobrien	    word++;
2208167465Smp	    len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
220959243Sobrien	    cp = ncp;
221059243Sobrien	}
2211167465Smp	if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
221259243Sobrien	    /* We don't fully check distinct matches as Gnuemacs does: */
221359243Sobrien	    if (Argument > 1) {	/* just count matches */
221459243Sobrien		if (++arg >= Argument)
221559243Sobrien		    found++;
221659243Sobrien	    } else {		/* match if distinct from previous */
2217167465Smp		if (len != (size_t)(Cursor - start)
2218167465Smp		    || Strncmp(cp, start, len) != 0)
221959243Sobrien		    found++;
222059243Sobrien	    }
222159243Sobrien	}
222259243Sobrien    }
222359243Sobrien
222459243Sobrien    if (LastChar + len - (Cursor - start) >= InputLim)
2225167465Smp	goto err_hbuf;	/* no room */
222659243Sobrien    DeleteBack(Cursor - start);
222759243Sobrien    c_insert(len);
222859243Sobrien    while (len--)
222959243Sobrien	*Cursor++ = *cp++;
223059243Sobrien    oldcursor = Cursor;
2231167465Smp    xfree(hbuf);
223259243Sobrien    return(CC_REFRESH);
2233167465Smp
2234167465Smp err_hbuf:
2235167465Smp    xfree(hbuf);
2236167465Smp    return CC_ERROR;
223759243Sobrien}
223859243Sobrien
223959243Sobrien/*ARGSUSED*/
224059243SobrienCCRETVAL
2241167465Smpe_yank_kill(Char c)
224259243Sobrien{				/* almost like GnuEmacs */
224383098Smp    int len;
224483098Smp    Char *kp, *cp;
224559243Sobrien
224659243Sobrien    USE(c);
224783098Smp    if (KillRingLen == 0)	/* nothing killed */
224859243Sobrien	return(CC_ERROR);
224983098Smp    len = Strlen(KillRing[YankPos].buf);
225083098Smp    if (LastChar + len >= InputLim)
225159243Sobrien	return(CC_ERROR);	/* end of buffer space */
225259243Sobrien
225359243Sobrien    /* else */
225459243Sobrien    cp = Cursor;		/* for speed */
225559243Sobrien
225683098Smp    c_insert(len);		/* open the space, */
225783098Smp    for (kp = KillRing[YankPos].buf; *kp; kp++)	/* copy the chars */
225859243Sobrien	*cp++ = *kp;
225959243Sobrien
226083098Smp    if (Argument == 1) {	/* if no arg */
226183098Smp	Mark = Cursor;		/* mark at beginning, cursor at end */
226283098Smp	Cursor = cp;
226383098Smp    } else {
226483098Smp	Mark = cp;		/* else cursor at beginning, mark at end */
226583098Smp    }
226659243Sobrien
2267167465Smp    if (adrof(STRhighlight) && MarkIsSet) {
2268167465Smp	ClearLines();
2269167465Smp	ClearDisp();
2270167465Smp    }
2271167465Smp    MarkIsSet = 0;
227259243Sobrien    return(CC_REFRESH);
227359243Sobrien}
227459243Sobrien
227559243Sobrien/*ARGSUSED*/
227659243SobrienCCRETVAL
2277167465Smpe_yank_pop(Char c)
227883098Smp{				/* almost like GnuEmacs */
227983098Smp    int m_bef_c, del_len, ins_len;
228083098Smp    Char *kp, *cp;
228183098Smp
228283098Smp    USE(c);
228383098Smp
228483098Smp#if 0
228583098Smp    /* XXX This "should" be here, but doesn't work, since LastCmd
228683098Smp       gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
228783098Smp       (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
228883098Smp       second one will "succeed" even if the first one wasn't preceded
228983098Smp       by a yank, and giving an argument is impossible. Now we "succeed"
229083098Smp       regardless of previous command, which is wrong too of course. */
229183098Smp    if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
229283098Smp	return(CC_ERROR);
229383098Smp#endif
229483098Smp
229583098Smp    if (KillRingLen == 0)	/* nothing killed */
229683098Smp	return(CC_ERROR);
229783098Smp    YankPos -= Argument;
229883098Smp    while (YankPos < 0)
229983098Smp	YankPos += KillRingLen;
230083098Smp    YankPos %= KillRingLen;
230183098Smp
230283098Smp    if (Cursor > Mark) {
230383098Smp	del_len = Cursor - Mark;
230483098Smp	m_bef_c = 1;
230583098Smp    } else {
230683098Smp	del_len = Mark - Cursor;
230783098Smp	m_bef_c = 0;
230883098Smp    }
230983098Smp    ins_len = Strlen(KillRing[YankPos].buf);
231083098Smp    if (LastChar + ins_len - del_len >= InputLim)
231183098Smp	return(CC_ERROR);	/* end of buffer space */
231283098Smp
231383098Smp    if (m_bef_c) {
231483098Smp	c_delbefore(del_len);
231583098Smp    } else {
231683098Smp	c_delafter(del_len);
231783098Smp    }
231883098Smp    cp = Cursor;		/* for speed */
231983098Smp
232083098Smp    c_insert(ins_len);		/* open the space, */
232183098Smp    for (kp = KillRing[YankPos].buf; *kp; kp++)	/* copy the chars */
232283098Smp	*cp++ = *kp;
232383098Smp
232483098Smp    if (m_bef_c) {
232583098Smp	Mark = Cursor;		/* mark at beginning, cursor at end */
232683098Smp	Cursor = cp;
232783098Smp    } else {
232883098Smp	Mark = cp;		/* else cursor at beginning, mark at end */
232983098Smp    }
233083098Smp
2331167465Smp    if (adrof(STRhighlight) && MarkIsSet) {
2332167465Smp	ClearLines();
2333167465Smp	ClearDisp();
2334167465Smp    }
2335167465Smp    MarkIsSet = 0;
233683098Smp    return(CC_REFRESH);
233783098Smp}
233883098Smp
233983098Smp/*ARGSUSED*/
234083098SmpCCRETVAL
2341167465Smpv_delprev(Char c) 		/* Backspace key in insert mode */
234259243Sobrien{
234359243Sobrien    int rc;
234459243Sobrien
234559243Sobrien    USE(c);
234659243Sobrien    rc = CC_ERROR;
234759243Sobrien
234859243Sobrien    if (InsertPos != 0) {
234959243Sobrien	if (Argument <= Cursor - InsertPos) {
235059243Sobrien	    c_delbefore(Argument);	/* delete before */
235159243Sobrien	    rc = CC_REFRESH;
235259243Sobrien	}
235359243Sobrien    }
235459243Sobrien    return(rc);
235559243Sobrien}   /* v_delprev  */
235659243Sobrien
235759243Sobrien/*ARGSUSED*/
235859243SobrienCCRETVAL
2359167465Smpe_delprev(Char c)
236059243Sobrien{
236159243Sobrien    USE(c);
236259243Sobrien    if (Cursor > InputBuf) {
236359243Sobrien	c_delbefore(Argument);	/* delete before dot */
236459243Sobrien	return(CC_REFRESH);
236559243Sobrien    }
236659243Sobrien    else {
236759243Sobrien	return(CC_ERROR);
236859243Sobrien    }
236959243Sobrien}
237059243Sobrien
237159243Sobrien/*ARGSUSED*/
237259243SobrienCCRETVAL
2373167465Smpe_delwordprev(Char c)
237459243Sobrien{
237583098Smp    Char *cp;
237659243Sobrien
237759243Sobrien    USE(c);
237859243Sobrien    if (Cursor == InputBuf)
237959243Sobrien	return(CC_ERROR);
238059243Sobrien    /* else */
238159243Sobrien
238259243Sobrien    cp = c_prev_word(Cursor, InputBuf, Argument);
238359243Sobrien
238483098Smp    c_push_kill(cp, Cursor);	/* save the text */
238559243Sobrien
238659243Sobrien    c_delbefore((int)(Cursor - cp));	/* delete before dot */
238759243Sobrien    return(CC_REFRESH);
238859243Sobrien}
238959243Sobrien
239059243Sobrien/* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
239159243Sobrien *
239259243Sobrien * Changed the names of some of the ^D family of editor functions to
239359243Sobrien * correspond to what they actually do and created new e_delnext_list
239459243Sobrien * for completeness.
239559243Sobrien *
239659243Sobrien *   Old names:			New names:
239759243Sobrien *
239859243Sobrien *   delete-char		delete-char-or-eof
239959243Sobrien *     F_DELNEXT		  F_DELNEXT_EOF
240059243Sobrien *     e_delnext		  e_delnext_eof
240159243Sobrien *     edelnxt			  edelnxteof
240259243Sobrien *   delete-char-or-eof		delete-char
240359243Sobrien *     F_DELNEXT_EOF		  F_DELNEXT
240459243Sobrien *     e_delnext_eof		  e_delnext
240559243Sobrien *     edelnxteof		  edelnxt
240659243Sobrien *   delete-char-or-list	delete-char-or-list-or-eof
240759243Sobrien *     F_LIST_DELNEXT		  F_DELNEXT_LIST_EOF
240859243Sobrien *     e_list_delnext		  e_delnext_list_eof
240959243Sobrien *   				  edellsteof
241059243Sobrien *   (no old equivalent)	delete-char-or-list
241159243Sobrien *   				  F_DELNEXT_LIST
241259243Sobrien *   				  e_delnext_list
241359243Sobrien *   				  e_delnxtlst
241459243Sobrien */
241559243Sobrien
241659243Sobrien/* added by mtk@ari.ncl.omron.co.jp (920818) */
241759243Sobrien/* rename e_delnext() -> e_delnext_eof() */
241859243Sobrien/*ARGSUSED*/
241959243SobrienCCRETVAL
2420167465Smpe_delnext(Char c)
242159243Sobrien{
242259243Sobrien    USE(c);
242359243Sobrien    if (Cursor == LastChar) {/* if I'm at the end */
242459243Sobrien	if (!VImode) {
242559243Sobrien		return(CC_ERROR);
242659243Sobrien	}
242759243Sobrien	else {
242859243Sobrien	    if (Cursor != InputBuf)
242959243Sobrien		Cursor--;
243059243Sobrien	    else
243159243Sobrien		return(CC_ERROR);
243259243Sobrien	}
243359243Sobrien    }
243459243Sobrien    c_delafter(Argument);	/* delete after dot */
243559243Sobrien    if (Cursor > LastChar)
243659243Sobrien	Cursor = LastChar;	/* bounds check */
243759243Sobrien    return(CC_REFRESH);
243859243Sobrien}
243959243Sobrien
244059243Sobrien
244159243Sobrien/*ARGSUSED*/
244259243SobrienCCRETVAL
2443167465Smpe_delnext_eof(Char c)
244459243Sobrien{
244559243Sobrien    USE(c);
244659243Sobrien    if (Cursor == LastChar) {/* if I'm at the end */
244759243Sobrien	if (!VImode) {
244859243Sobrien	    if (Cursor == InputBuf) {
244959243Sobrien		/* if I'm also at the beginning */
245059243Sobrien		so_write(STReof, 4);/* then do a EOF */
245159243Sobrien		flush();
245259243Sobrien		return(CC_EOF);
245359243Sobrien	    }
245459243Sobrien	    else
245559243Sobrien		return(CC_ERROR);
245659243Sobrien	}
245759243Sobrien	else {
245859243Sobrien	    if (Cursor != InputBuf)
245959243Sobrien		Cursor--;
246059243Sobrien	    else
246159243Sobrien		return(CC_ERROR);
246259243Sobrien	}
246359243Sobrien    }
246459243Sobrien    c_delafter(Argument);	/* delete after dot */
246559243Sobrien    if (Cursor > LastChar)
246659243Sobrien	Cursor = LastChar;	/* bounds check */
246759243Sobrien    return(CC_REFRESH);
246859243Sobrien}
246959243Sobrien
247059243Sobrien/*ARGSUSED*/
247159243SobrienCCRETVAL
2472167465Smpe_delnext_list(Char c)
247359243Sobrien{
247459243Sobrien    USE(c);
247559243Sobrien    if (Cursor == LastChar) {	/* if I'm at the end */
247659243Sobrien	PastBottom();
247759243Sobrien	*LastChar = '\0';	/* just in case */
247859243Sobrien	return(CC_LIST_CHOICES);
247959243Sobrien    }
248059243Sobrien    else {
248159243Sobrien	c_delafter(Argument);	/* delete after dot */
248259243Sobrien	if (Cursor > LastChar)
248359243Sobrien	    Cursor = LastChar;	/* bounds check */
248459243Sobrien	return(CC_REFRESH);
248559243Sobrien    }
248659243Sobrien}
248759243Sobrien
248859243Sobrien/*ARGSUSED*/
248959243SobrienCCRETVAL
2490167465Smpe_delnext_list_eof(Char c)
249159243Sobrien{
249259243Sobrien    USE(c);
249359243Sobrien    if (Cursor == LastChar) {	/* if I'm at the end */
249459243Sobrien	if (Cursor == InputBuf) {	/* if I'm also at the beginning */
249559243Sobrien	    so_write(STReof, 4);/* then do a EOF */
249659243Sobrien	    flush();
249759243Sobrien	    return(CC_EOF);
249859243Sobrien	}
249959243Sobrien	else {
250059243Sobrien	    PastBottom();
250159243Sobrien	    *LastChar = '\0';	/* just in case */
250259243Sobrien	    return(CC_LIST_CHOICES);
250359243Sobrien	}
250459243Sobrien    }
250559243Sobrien    else {
250659243Sobrien	c_delafter(Argument);	/* delete after dot */
250759243Sobrien	if (Cursor > LastChar)
250859243Sobrien	    Cursor = LastChar;	/* bounds check */
250959243Sobrien	return(CC_REFRESH);
251059243Sobrien    }
251159243Sobrien}
251259243Sobrien
251359243Sobrien/*ARGSUSED*/
251459243SobrienCCRETVAL
2515167465Smpe_list_eof(Char c)
251659243Sobrien{
251759243Sobrien    CCRETVAL rv;
251859243Sobrien
251959243Sobrien    USE(c);
252059243Sobrien    if (Cursor == LastChar && Cursor == InputBuf) {
252159243Sobrien	so_write(STReof, 4);	/* then do a EOF */
252259243Sobrien	flush();
252359243Sobrien	rv = CC_EOF;
252459243Sobrien    }
252559243Sobrien    else {
252659243Sobrien	PastBottom();
252759243Sobrien	*LastChar = '\0';	/* just in case */
252859243Sobrien	rv = CC_LIST_CHOICES;
252959243Sobrien    }
253059243Sobrien    return rv;
253159243Sobrien}
253259243Sobrien
253359243Sobrien/*ARGSUSED*/
253459243SobrienCCRETVAL
2535167465Smpe_delwordnext(Char c)
253659243Sobrien{
253783098Smp    Char *cp;
253859243Sobrien
253959243Sobrien    USE(c);
254059243Sobrien    if (Cursor == LastChar)
254159243Sobrien	return(CC_ERROR);
254259243Sobrien    /* else */
254359243Sobrien
254459243Sobrien    cp = c_next_word(Cursor, LastChar, Argument);
254559243Sobrien
254683098Smp    c_push_kill(Cursor, cp);	/* save the text */
254759243Sobrien
254859243Sobrien    c_delafter((int)(cp - Cursor));	/* delete after dot */
254959243Sobrien    if (Cursor > LastChar)
255059243Sobrien	Cursor = LastChar;	/* bounds check */
255159243Sobrien    return(CC_REFRESH);
255259243Sobrien}
255359243Sobrien
255459243Sobrien/*ARGSUSED*/
255559243SobrienCCRETVAL
2556167465Smpe_toend(Char c)
255759243Sobrien{
255859243Sobrien    USE(c);
255959243Sobrien    Cursor = LastChar;
256059243Sobrien    if (VImode)
256159243Sobrien	if (ActionFlag & TCSHOP_DELETE) {
256259243Sobrien	    c_delfini();
256359243Sobrien	    return(CC_REFRESH);
256459243Sobrien	}
256559243Sobrien    RefCursor();		/* move the cursor */
256659243Sobrien    return(CC_NORM);
256759243Sobrien}
256859243Sobrien
256959243Sobrien/*ARGSUSED*/
257059243SobrienCCRETVAL
2571167465Smpe_tobeg(Char c)
257259243Sobrien{
257359243Sobrien    USE(c);
257459243Sobrien    Cursor = InputBuf;
257559243Sobrien
257659243Sobrien    if (VImode) {
257759243Sobrien       while (Isspace(*Cursor)) /* We want FIRST non space character */
257859243Sobrien	Cursor++;
257959243Sobrien	if (ActionFlag & TCSHOP_DELETE) {
258059243Sobrien	    c_delfini();
258159243Sobrien	    return(CC_REFRESH);
258259243Sobrien	}
258359243Sobrien    }
258459243Sobrien
258559243Sobrien    RefCursor();		/* move the cursor */
258659243Sobrien    return(CC_NORM);
258759243Sobrien}
258859243Sobrien
258959243Sobrien/*ARGSUSED*/
259059243SobrienCCRETVAL
2591167465Smpe_killend(Char c)
259259243Sobrien{
259359243Sobrien    USE(c);
259483098Smp    c_push_kill(Cursor, LastChar); /* copy it */
2595167465Smp    LastChar = Cursor;		/* zap! -- delete to end */
2596167465Smp    if (Mark > Cursor)
2597167465Smp        Mark = Cursor;
2598167465Smp    MarkIsSet = 0;
259959243Sobrien    return(CC_REFRESH);
260059243Sobrien}
260159243Sobrien
260259243Sobrien
260359243Sobrien/*ARGSUSED*/
260459243SobrienCCRETVAL
2605167465Smpe_killbeg(Char c)
260659243Sobrien{
260759243Sobrien    USE(c);
260883098Smp    c_push_kill(InputBuf, Cursor); /* copy it */
260959243Sobrien    c_delbefore((int)(Cursor - InputBuf));
2610145479Smp    if (Mark && Mark > Cursor)
2611145479Smp        Mark -= Cursor-InputBuf;
261259243Sobrien    return(CC_REFRESH);
261359243Sobrien}
261459243Sobrien
261559243Sobrien/*ARGSUSED*/
261659243SobrienCCRETVAL
2617167465Smpe_killall(Char c)
261859243Sobrien{
261959243Sobrien    USE(c);
262083098Smp    c_push_kill(InputBuf, LastChar); /* copy it */
2621145479Smp    Cursor = Mark = LastChar = InputBuf;	/* zap! -- delete all of it */
2622167465Smp    MarkIsSet = 0;
262359243Sobrien    return(CC_REFRESH);
262459243Sobrien}
262559243Sobrien
262659243Sobrien/*ARGSUSED*/
262759243SobrienCCRETVAL
2628167465Smpe_killregion(Char c)
262959243Sobrien{
263059243Sobrien    USE(c);
263159243Sobrien    if (!Mark)
263259243Sobrien	return(CC_ERROR);
263359243Sobrien
263459243Sobrien    if (Mark > Cursor) {
263583098Smp	c_push_kill(Cursor, Mark); /* copy it */
263683098Smp	c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
263783098Smp	Mark = Cursor;
263859243Sobrien    }
263959243Sobrien    else {			/* mark is before cursor */
264083098Smp	c_push_kill(Mark, Cursor); /* copy it */
264183098Smp	c_delbefore((int)(Cursor - Mark));
264259243Sobrien    }
2643167465Smp    if (adrof(STRhighlight) && MarkIsSet) {
2644167465Smp	ClearLines();
2645167465Smp	ClearDisp();
2646167465Smp    }
2647167465Smp    MarkIsSet = 0;
264859243Sobrien    return(CC_REFRESH);
264959243Sobrien}
265059243Sobrien
265159243Sobrien/*ARGSUSED*/
265259243SobrienCCRETVAL
2653167465Smpe_copyregion(Char c)
265459243Sobrien{
265559243Sobrien    USE(c);
265659243Sobrien    if (!Mark)
265759243Sobrien	return(CC_ERROR);
265859243Sobrien
265959243Sobrien    if (Mark > Cursor) {
266083098Smp	c_push_kill(Cursor, Mark); /* copy it */
266159243Sobrien    }
266259243Sobrien    else {			/* mark is before cursor */
266383098Smp	c_push_kill(Mark, Cursor); /* copy it */
266459243Sobrien    }
266559243Sobrien    return(CC_NORM);		/* don't even need to Refresh() */
266659243Sobrien}
266759243Sobrien
266859243Sobrien/*ARGSUSED*/
266959243SobrienCCRETVAL
2670167465Smpe_charswitch(Char cc)
267159243Sobrien{
267283098Smp    Char c;
267359243Sobrien
267459243Sobrien    USE(cc);
267559243Sobrien
267659243Sobrien    /* do nothing if we are at beginning of line or have only one char */
267759243Sobrien    if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
267859243Sobrien	return(CC_ERROR);
267959243Sobrien    }
268059243Sobrien
268159243Sobrien    if (Cursor < LastChar) {
268259243Sobrien	Cursor++;
268359243Sobrien    }
268459243Sobrien    c = Cursor[-2];
268559243Sobrien    Cursor[-2] = Cursor[-1];
268659243Sobrien    Cursor[-1] = c;
268759243Sobrien    return(CC_REFRESH);
268859243Sobrien}
268959243Sobrien
269059243Sobrien/*ARGSUSED*/
269159243SobrienCCRETVAL
2692167465Smpe_gcharswitch(Char cc)
269359243Sobrien{				/* gosmacs style ^T */
269483098Smp    Char c;
269559243Sobrien
269659243Sobrien    USE(cc);
269759243Sobrien    if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
269859243Sobrien	c = Cursor[-2];
269959243Sobrien	Cursor[-2] = Cursor[-1];
270059243Sobrien	Cursor[-1] = c;
270159243Sobrien	return(CC_REFRESH);
270259243Sobrien    }
270359243Sobrien    else {
270459243Sobrien	return(CC_ERROR);
270559243Sobrien    }
270659243Sobrien}
270759243Sobrien
270859243Sobrien/*ARGSUSED*/
270959243SobrienCCRETVAL
2710167465Smpe_charback(Char c)
271159243Sobrien{
271259243Sobrien    USE(c);
271359243Sobrien    if (Cursor > InputBuf) {
2714167465Smp	if (Argument > Cursor - InputBuf)
271559243Sobrien	    Cursor = InputBuf;
271659243Sobrien	else
2717167465Smp	    Cursor -= Argument;
271859243Sobrien
271959243Sobrien	if (VImode)
272059243Sobrien	    if (ActionFlag & TCSHOP_DELETE) {
272159243Sobrien		c_delfini();
272259243Sobrien		return(CC_REFRESH);
272359243Sobrien	    }
272459243Sobrien
272559243Sobrien	RefCursor();
272659243Sobrien	return(CC_NORM);
272759243Sobrien    }
272859243Sobrien    else {
272959243Sobrien	return(CC_ERROR);
273059243Sobrien    }
273159243Sobrien}
273259243Sobrien
273359243Sobrien/*ARGSUSED*/
273459243SobrienCCRETVAL
2735167465Smpv_wordback(Char c)
273659243Sobrien{
273759243Sobrien    USE(c);
273859243Sobrien    if (Cursor == InputBuf)
273959243Sobrien	return(CC_ERROR);
274059243Sobrien    /* else */
274159243Sobrien
274283098Smp    Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
274359243Sobrien
274459243Sobrien    if (ActionFlag & TCSHOP_DELETE) {
274559243Sobrien	c_delfini();
274659243Sobrien	return(CC_REFRESH);
274759243Sobrien    }
274859243Sobrien
274959243Sobrien    RefCursor();
275059243Sobrien    return(CC_NORM);
275159243Sobrien}
275259243Sobrien
275359243Sobrien/*ARGSUSED*/
275459243SobrienCCRETVAL
2755167465Smpe_wordback(Char c)
275659243Sobrien{
275759243Sobrien    USE(c);
275859243Sobrien    if (Cursor == InputBuf)
275959243Sobrien	return(CC_ERROR);
276059243Sobrien    /* else */
276159243Sobrien
276259243Sobrien    Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
276359243Sobrien
276459243Sobrien    if (VImode)
276559243Sobrien	if (ActionFlag & TCSHOP_DELETE) {
276659243Sobrien	    c_delfini();
276759243Sobrien	    return(CC_REFRESH);
276859243Sobrien	}
276959243Sobrien
277059243Sobrien    RefCursor();
277159243Sobrien    return(CC_NORM);
277259243Sobrien}
277359243Sobrien
277459243Sobrien/*ARGSUSED*/
277559243SobrienCCRETVAL
2776167465Smpe_charfwd(Char c)
277759243Sobrien{
277859243Sobrien    USE(c);
277959243Sobrien    if (Cursor < LastChar) {
2780167465Smp	Cursor += Argument;
278159243Sobrien	if (Cursor > LastChar)
278259243Sobrien	    Cursor = LastChar;
278359243Sobrien
278459243Sobrien	if (VImode)
278559243Sobrien	    if (ActionFlag & TCSHOP_DELETE) {
278659243Sobrien		c_delfini();
278759243Sobrien		return(CC_REFRESH);
278859243Sobrien	    }
278959243Sobrien
279059243Sobrien	RefCursor();
279159243Sobrien	return(CC_NORM);
279259243Sobrien    }
279359243Sobrien    else {
279459243Sobrien	return(CC_ERROR);
279559243Sobrien    }
279659243Sobrien}
279759243Sobrien
279859243Sobrien/*ARGSUSED*/
279959243SobrienCCRETVAL
2800167465Smpe_wordfwd(Char c)
280159243Sobrien{
280259243Sobrien    USE(c);
280359243Sobrien    if (Cursor == LastChar)
280459243Sobrien	return(CC_ERROR);
280559243Sobrien    /* else */
280659243Sobrien
280759243Sobrien    Cursor = c_next_word(Cursor, LastChar, Argument);
280859243Sobrien
280959243Sobrien    if (VImode)
281059243Sobrien	if (ActionFlag & TCSHOP_DELETE) {
281159243Sobrien	    c_delfini();
281259243Sobrien	    return(CC_REFRESH);
281359243Sobrien	}
281459243Sobrien
281559243Sobrien    RefCursor();
281659243Sobrien    return(CC_NORM);
281759243Sobrien}
281859243Sobrien
281959243Sobrien/*ARGSUSED*/
282059243SobrienCCRETVAL
2821167465Smpv_wordfwd(Char c)
282259243Sobrien{
282359243Sobrien    USE(c);
282459243Sobrien    if (Cursor == LastChar)
282559243Sobrien	return(CC_ERROR);
282659243Sobrien    /* else */
282759243Sobrien
282859243Sobrien    Cursor = c_nexword(Cursor, LastChar, Argument);
282959243Sobrien
283059243Sobrien    if (VImode)
283159243Sobrien	if (ActionFlag & TCSHOP_DELETE) {
283259243Sobrien	    c_delfini();
283359243Sobrien	    return(CC_REFRESH);
283459243Sobrien	}
283559243Sobrien
283659243Sobrien    RefCursor();
283759243Sobrien    return(CC_NORM);
283859243Sobrien}
283959243Sobrien
284059243Sobrien/*ARGSUSED*/
284159243SobrienCCRETVAL
2842167465Smpv_wordbegnext(Char c)
284359243Sobrien{
284459243Sobrien    USE(c);
284559243Sobrien    if (Cursor == LastChar)
284659243Sobrien	return(CC_ERROR);
284759243Sobrien    /* else */
284859243Sobrien
284959243Sobrien    Cursor = c_next_word(Cursor, LastChar, Argument);
285059243Sobrien    if (Cursor < LastChar)
285159243Sobrien	Cursor++;
285259243Sobrien
285359243Sobrien    if (VImode)
285459243Sobrien	if (ActionFlag & TCSHOP_DELETE) {
285559243Sobrien	    c_delfini();
285659243Sobrien	    return(CC_REFRESH);
285759243Sobrien	}
285859243Sobrien
285959243Sobrien    RefCursor();
286059243Sobrien    return(CC_NORM);
286159243Sobrien}
286259243Sobrien
286359243Sobrien/*ARGSUSED*/
286459243Sobrienstatic CCRETVAL
2865167465Smpv_repeat_srch(int c)
286659243Sobrien{
286759243Sobrien    CCRETVAL rv = CC_ERROR;
286859243Sobrien#ifdef SDEBUG
2869167465Smp    xprintf("dir %d patlen %d patbuf %S\n",
2870167465Smp	    c, (int)patbuf.len, patbuf.s);
287159243Sobrien#endif
287259243Sobrien
287359243Sobrien    LastCmd = (KEYCMD) c;  /* Hack to stop c_hsetpat */
287459243Sobrien    LastChar = InputBuf;
287559243Sobrien    switch (c) {
287659243Sobrien    case F_DOWN_SEARCH_HIST:
287759243Sobrien	rv = e_down_search_hist(0);
287859243Sobrien	break;
287959243Sobrien    case F_UP_SEARCH_HIST:
288059243Sobrien	rv = e_up_search_hist(0);
288159243Sobrien	break;
288259243Sobrien    default:
288359243Sobrien	break;
288459243Sobrien    }
288559243Sobrien    return rv;
288659243Sobrien}
288759243Sobrien
288859243Sobrienstatic CCRETVAL
2889167465Smpv_csearch_back(Char ch, int count, int tflag)
289059243Sobrien{
289159243Sobrien    Char *cp;
289259243Sobrien
289359243Sobrien    cp = Cursor;
289459243Sobrien    while (count--) {
289559243Sobrien	if (*cp == ch)
289659243Sobrien	    cp--;
289759243Sobrien	while (cp > InputBuf && *cp != ch)
289859243Sobrien	    cp--;
289959243Sobrien    }
290059243Sobrien
290159243Sobrien    if (cp < InputBuf || (cp == InputBuf && *cp != ch))
290259243Sobrien	return(CC_ERROR);
290359243Sobrien
290459243Sobrien    if (*cp == ch && tflag)
290559243Sobrien	cp++;
290659243Sobrien
290759243Sobrien    Cursor = cp;
290859243Sobrien
290959243Sobrien    if (ActionFlag & TCSHOP_DELETE) {
291059243Sobrien	Cursor++;
291159243Sobrien	c_delfini();
291259243Sobrien	return(CC_REFRESH);
291359243Sobrien    }
291459243Sobrien
291559243Sobrien    RefCursor();
291659243Sobrien    return(CC_NORM);
291759243Sobrien}
291859243Sobrien
291959243Sobrienstatic CCRETVAL
2920167465Smpv_csearch_fwd(Char ch, int count, int tflag)
292159243Sobrien{
292259243Sobrien    Char *cp;
292359243Sobrien
292459243Sobrien    cp = Cursor;
292559243Sobrien    while (count--) {
292659243Sobrien	if(*cp == ch)
292759243Sobrien	    cp++;
292859243Sobrien	while (cp < LastChar && *cp != ch)
292959243Sobrien	    cp++;
293059243Sobrien    }
293159243Sobrien
293259243Sobrien    if (cp >= LastChar)
293359243Sobrien	return(CC_ERROR);
293459243Sobrien
293559243Sobrien    if (*cp == ch && tflag)
293659243Sobrien	cp--;
293759243Sobrien
293859243Sobrien    Cursor = cp;
293959243Sobrien
294059243Sobrien    if (ActionFlag & TCSHOP_DELETE) {
294159243Sobrien	Cursor++;
294259243Sobrien	c_delfini();
294359243Sobrien	return(CC_REFRESH);
294459243Sobrien    }
294559243Sobrien    RefCursor();
294659243Sobrien    return(CC_NORM);
294759243Sobrien}
294859243Sobrien
294959243Sobrien/*ARGSUSED*/
295059243Sobrienstatic CCRETVAL
2951167465Smpv_action(int c)
295259243Sobrien{
295383098Smp    Char *cp, *kp;
295459243Sobrien
295559243Sobrien    if (ActionFlag == TCSHOP_DELETE) {
295659243Sobrien	ActionFlag = TCSHOP_NOP;
295759243Sobrien	ActionPos = 0;
295859243Sobrien
295959243Sobrien	UndoSize = 0;
296059243Sobrien	kp = UndoBuf;
296159243Sobrien	for (cp = InputBuf; cp < LastChar; cp++) {
296259243Sobrien	    *kp++ = *cp;
296359243Sobrien	    UndoSize++;
296459243Sobrien	}
296559243Sobrien
296659243Sobrien	UndoAction = TCSHOP_INSERT;
296759243Sobrien	UndoPtr  = InputBuf;
296859243Sobrien	LastChar = InputBuf;
296959243Sobrien	Cursor   = InputBuf;
297059243Sobrien	if (c & TCSHOP_INSERT)
297159243Sobrien	    c_alternativ_key_map(0);
297259243Sobrien
297359243Sobrien	return(CC_REFRESH);
297459243Sobrien    }
297559243Sobrien#ifdef notdef
297659243Sobrien    else if (ActionFlag == TCSHOP_NOP) {
297759243Sobrien#endif
297859243Sobrien	ActionPos = Cursor;
297959243Sobrien	ActionFlag = c;
298059243Sobrien	return(CC_ARGHACK);  /* Do NOT clear out argument */
298159243Sobrien#ifdef notdef
298259243Sobrien    }
298359243Sobrien    else {
298459243Sobrien	ActionFlag = 0;
298559243Sobrien	ActionPos = 0;
298659243Sobrien	return(CC_ERROR);
298759243Sobrien    }
298859243Sobrien#endif
298959243Sobrien}
299059243Sobrien
299159243Sobrien#ifdef COMMENT
299259243Sobrien/* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
299359243Sobrienstatic void
2994167465Smpc_get_word(Char **begin, Char **end)
299559243Sobrien{
299659243Sobrien    Char   *cp;
299759243Sobrien
299859243Sobrien    cp = &Cursor[0];
299959243Sobrien    while (Argument--) {
300059243Sobrien	while ((cp <= LastChar) && (isword(*cp)))
300159243Sobrien	    cp++;
300259243Sobrien	*end = --cp;
300359243Sobrien	while ((cp >= InputBuf) && (isword(*cp)))
300459243Sobrien	    cp--;
300559243Sobrien	*begin = ++cp;
300659243Sobrien    }
300759243Sobrien}
300859243Sobrien#endif /* COMMENT */
300959243Sobrien
301059243Sobrien/*ARGSUSED*/
301159243SobrienCCRETVAL
3012167465Smpe_uppercase(Char c)
301359243Sobrien{
301459243Sobrien    Char   *cp, *end;
301559243Sobrien
301659243Sobrien    USE(c);
301759243Sobrien    end = c_next_word(Cursor, LastChar, Argument);
301859243Sobrien
301959243Sobrien    for (cp = Cursor; cp < end; cp++)	/* PWP: was cp=begin */
302059243Sobrien	if (Islower(*cp))
302159243Sobrien	    *cp = Toupper(*cp);
302259243Sobrien
302359243Sobrien    Cursor = end;
302459243Sobrien    if (Cursor > LastChar)
302559243Sobrien	Cursor = LastChar;
302659243Sobrien    return(CC_REFRESH);
302759243Sobrien}
302859243Sobrien
302959243Sobrien
303059243Sobrien/*ARGSUSED*/
303159243SobrienCCRETVAL
3032316957Sdchagine_capitalcase(Char c)
303359243Sobrien{
303459243Sobrien    Char   *cp, *end;
303559243Sobrien
303659243Sobrien    USE(c);
303759243Sobrien    end = c_next_word(Cursor, LastChar, Argument);
303859243Sobrien
303959243Sobrien    cp = Cursor;
304059243Sobrien    for (; cp < end; cp++) {
304159243Sobrien	if (Isalpha(*cp)) {
304259243Sobrien	    if (Islower(*cp))
304359243Sobrien		*cp = Toupper(*cp);
304459243Sobrien	    cp++;
304559243Sobrien	    break;
304659243Sobrien	}
304759243Sobrien    }
304859243Sobrien    for (; cp < end; cp++)
304959243Sobrien	if (Isupper(*cp))
305059243Sobrien	    *cp = Tolower(*cp);
305159243Sobrien
305259243Sobrien    Cursor = end;
305359243Sobrien    if (Cursor > LastChar)
305459243Sobrien	Cursor = LastChar;
305559243Sobrien    return(CC_REFRESH);
305659243Sobrien}
305759243Sobrien
305859243Sobrien/*ARGSUSED*/
305959243SobrienCCRETVAL
3060167465Smpe_lowercase(Char c)
306159243Sobrien{
306259243Sobrien    Char   *cp, *end;
306359243Sobrien
306459243Sobrien    USE(c);
306559243Sobrien    end = c_next_word(Cursor, LastChar, Argument);
306659243Sobrien
306759243Sobrien    for (cp = Cursor; cp < end; cp++)
306859243Sobrien	if (Isupper(*cp))
306959243Sobrien	    *cp = Tolower(*cp);
307059243Sobrien
307159243Sobrien    Cursor = end;
307259243Sobrien    if (Cursor > LastChar)
307359243Sobrien	Cursor = LastChar;
307459243Sobrien    return(CC_REFRESH);
307559243Sobrien}
307659243Sobrien
307759243Sobrien
307859243Sobrien/*ARGSUSED*/
307959243SobrienCCRETVAL
3080167465Smpe_set_mark(Char c)
308159243Sobrien{
308259243Sobrien    USE(c);
3083167465Smp    if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3084167465Smp	ClearLines();
3085167465Smp	ClearDisp();
3086167465Smp	Refresh();
3087167465Smp    }
308859243Sobrien    Mark = Cursor;
3089167465Smp    MarkIsSet = 1;
309059243Sobrien    return(CC_NORM);
309159243Sobrien}
309259243Sobrien
309359243Sobrien/*ARGSUSED*/
309459243SobrienCCRETVAL
3095167465Smpe_exchange_mark(Char c)
309659243Sobrien{
309783098Smp    Char *cp;
309859243Sobrien
309959243Sobrien    USE(c);
310059243Sobrien    cp = Cursor;
310159243Sobrien    Cursor = Mark;
310259243Sobrien    Mark = cp;
310359243Sobrien    RefCursor();
310459243Sobrien    return(CC_NORM);
310559243Sobrien}
310659243Sobrien
310759243Sobrien/*ARGSUSED*/
310859243SobrienCCRETVAL
3109167465Smpe_argfour(Char c)
311059243Sobrien{				/* multiply current argument by 4 */
311159243Sobrien    USE(c);
311259243Sobrien    if (Argument > 1000000)
311359243Sobrien	return CC_ERROR;
311459243Sobrien    DoingArg = 1;
311559243Sobrien    Argument *= 4;
311659243Sobrien    return(CC_ARGHACK);
311759243Sobrien}
311859243Sobrien
3119167465Smpstatic void
3120167465Smpquote_mode_cleanup(void *unused)
3121167465Smp{
3122167465Smp    USE(unused);
3123167465Smp    QuoteModeOff();
3124167465Smp}
3125167465Smp
312659243Sobrien/*ARGSUSED*/
312759243SobrienCCRETVAL
3128167465Smpe_quote(Char c)
312959243Sobrien{
313059243Sobrien    Char    ch;
313159243Sobrien    int     num;
313259243Sobrien
313359243Sobrien    USE(c);
313459243Sobrien    QuoteModeOn();
3135167465Smp    cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
313659243Sobrien    num = GetNextChar(&ch);
3137167465Smp    cleanup_until(&c);
313859243Sobrien    if (num == 1)
313959243Sobrien	return e_insert(ch);
314059243Sobrien    else
314159243Sobrien	return e_send_eof(0);
314259243Sobrien}
314359243Sobrien
314459243Sobrien/*ARGSUSED*/
314559243SobrienCCRETVAL
3146167465Smpe_metanext(Char c)
314759243Sobrien{
314859243Sobrien    USE(c);
314959243Sobrien    MetaNext = 1;
315059243Sobrien    return(CC_ARGHACK);	/* preserve argument */
315159243Sobrien}
315259243Sobrien
315359243Sobrien#ifdef notdef
315459243Sobrien/*ARGSUSED*/
315559243SobrienCCRETVAL
3156167465Smpe_extendnext(Char c)
315759243Sobrien{
315859243Sobrien    CurrentKeyMap = CcAltMap;
315959243Sobrien    return(CC_ARGHACK);	/* preserve argument */
316059243Sobrien}
316159243Sobrien
316259243Sobrien#endif
316359243Sobrien
316459243Sobrien/*ARGSUSED*/
316559243SobrienCCRETVAL
3166167465Smpv_insbeg(Char c)
316759243Sobrien{				/* move to beginning of line and start vi
316859243Sobrien				 * insert mode */
316959243Sobrien    USE(c);
317059243Sobrien    Cursor = InputBuf;
317159243Sobrien    InsertPos = Cursor;
317259243Sobrien
317359243Sobrien    UndoPtr  = Cursor;
317459243Sobrien    UndoAction = TCSHOP_DELETE;
317559243Sobrien
317659243Sobrien    RefCursor();		/* move the cursor */
317759243Sobrien    c_alternativ_key_map(0);
317859243Sobrien    return(CC_NORM);
317959243Sobrien}
318059243Sobrien
318159243Sobrien/*ARGSUSED*/
318259243SobrienCCRETVAL
3183167465Smpv_replone(Char c)
318459243Sobrien{				/* vi mode overwrite one character */
318559243Sobrien    USE(c);
318659243Sobrien    c_alternativ_key_map(0);
318759243Sobrien    inputmode = MODE_REPLACE_1;
318859243Sobrien    UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
318959243Sobrien    UndoPtr = Cursor;
319059243Sobrien    UndoSize = 0;
319159243Sobrien    return(CC_NORM);
319259243Sobrien}
319359243Sobrien
319459243Sobrien/*ARGSUSED*/
319559243SobrienCCRETVAL
3196167465Smpv_replmode(Char c)
319759243Sobrien{				/* vi mode start overwriting */
319859243Sobrien    USE(c);
319959243Sobrien    c_alternativ_key_map(0);
320059243Sobrien    inputmode = MODE_REPLACE;
320159243Sobrien    UndoAction = TCSHOP_CHANGE;	/* Set Up for VI undo command */
320259243Sobrien    UndoPtr = Cursor;
320359243Sobrien    UndoSize = 0;
320459243Sobrien    return(CC_NORM);
320559243Sobrien}
320659243Sobrien
320759243Sobrien/*ARGSUSED*/
320859243SobrienCCRETVAL
3209167465Smpv_substchar(Char c)
321059243Sobrien{				/* vi mode substitute for one char */
321159243Sobrien    USE(c);
321259243Sobrien    c_delafter(Argument);
321359243Sobrien    c_alternativ_key_map(0);
321459243Sobrien    return(CC_REFRESH);
321559243Sobrien}
321659243Sobrien
321759243Sobrien/*ARGSUSED*/
321859243SobrienCCRETVAL
3219167465Smpv_substline(Char c)
322059243Sobrien{				/* vi mode replace whole line */
322159243Sobrien    USE(c);
322259243Sobrien    (void) e_killall(0);
322359243Sobrien    c_alternativ_key_map(0);
322459243Sobrien    return(CC_REFRESH);
322559243Sobrien}
322659243Sobrien
322759243Sobrien/*ARGSUSED*/
322859243SobrienCCRETVAL
3229167465Smpv_chgtoend(Char c)
323059243Sobrien{				/* vi mode change to end of line */
323159243Sobrien    USE(c);
323259243Sobrien    (void) e_killend(0);
323359243Sobrien    c_alternativ_key_map(0);
323459243Sobrien    return(CC_REFRESH);
323559243Sobrien}
323659243Sobrien
323759243Sobrien/*ARGSUSED*/
323859243SobrienCCRETVAL
3239167465Smpv_insert(Char c)
324059243Sobrien{				/* vi mode start inserting */
324159243Sobrien    USE(c);
324259243Sobrien    c_alternativ_key_map(0);
324359243Sobrien
324459243Sobrien    InsertPos = Cursor;
324559243Sobrien    UndoPtr = Cursor;
324659243Sobrien    UndoAction = TCSHOP_DELETE;
324759243Sobrien
324859243Sobrien    return(CC_NORM);
324959243Sobrien}
325059243Sobrien
325159243Sobrien/*ARGSUSED*/
325259243SobrienCCRETVAL
3253167465Smpv_add(Char c)
325459243Sobrien{				/* vi mode start adding */
325559243Sobrien    USE(c);
325659243Sobrien    c_alternativ_key_map(0);
325759243Sobrien    if (Cursor < LastChar)
325859243Sobrien    {
325959243Sobrien	Cursor++;
326059243Sobrien	if (Cursor > LastChar)
326159243Sobrien	    Cursor = LastChar;
326259243Sobrien	RefCursor();
326359243Sobrien    }
326459243Sobrien
326559243Sobrien    InsertPos = Cursor;
326659243Sobrien    UndoPtr = Cursor;
326759243Sobrien    UndoAction = TCSHOP_DELETE;
326859243Sobrien
326959243Sobrien    return(CC_NORM);
327059243Sobrien}
327159243Sobrien
327259243Sobrien/*ARGSUSED*/
327359243SobrienCCRETVAL
3274167465Smpv_addend(Char c)
327559243Sobrien{				/* vi mode to add at end of line */
327659243Sobrien    USE(c);
327759243Sobrien    c_alternativ_key_map(0);
327859243Sobrien    Cursor = LastChar;
327959243Sobrien
328059243Sobrien    InsertPos = LastChar;	/* Mark where insertion begins */
328159243Sobrien    UndoPtr = LastChar;
328259243Sobrien    UndoAction = TCSHOP_DELETE;
328359243Sobrien
328459243Sobrien    RefCursor();
328559243Sobrien    return(CC_NORM);
328659243Sobrien}
328759243Sobrien
328859243Sobrien/*ARGSUSED*/
328959243SobrienCCRETVAL
3290167465Smpv_change_case(Char cc)
329159243Sobrien{
3292145479Smp    Char    c;
329359243Sobrien
329459243Sobrien    USE(cc);
329559243Sobrien    if (Cursor < LastChar) {
329669408Sache#ifndef WINNT_NATIVE
329759243Sobrien	c = *Cursor;
329859243Sobrien#else
329959243Sobrien	c = CHAR & *Cursor;
330069408Sache#endif /* WINNT_NATIVE */
330159243Sobrien	if (Isupper(c))
330259243Sobrien	    *Cursor++ = Tolower(c);
330359243Sobrien	else if (Islower(c))
330459243Sobrien	    *Cursor++ = Toupper(c);
330559243Sobrien	else
330659243Sobrien	    Cursor++;
3307145479Smp	RefPlusOne(1);		/* fast refresh for one char */
330859243Sobrien	return(CC_NORM);
330959243Sobrien    }
331059243Sobrien    return(CC_ERROR);
331159243Sobrien}
331259243Sobrien
331359243Sobrien/*ARGSUSED*/
331459243SobrienCCRETVAL
3315167465Smpe_expand(Char c)
331659243Sobrien{
331783098Smp    Char *p;
331859243Sobrien
331959243Sobrien    USE(c);
332059243Sobrien    for (p = InputBuf; Isspace(*p); p++)
332159243Sobrien	continue;
332259243Sobrien    if (p == LastChar)
332359243Sobrien	return(CC_ERROR);
332459243Sobrien
332559243Sobrien    justpr++;
332659243Sobrien    Expand++;
332759243Sobrien    return(e_newline(0));
332859243Sobrien}
332959243Sobrien
333059243Sobrien/*ARGSUSED*/
333159243SobrienCCRETVAL
3332167465Smpe_startover(Char c)
333359243Sobrien{				/* erase all of current line, start again */
333459243Sobrien    USE(c);
333559243Sobrien    ResetInLine(0);		/* reset the input pointers */
333659243Sobrien    return(CC_REFRESH);
333759243Sobrien}
333859243Sobrien
333959243Sobrien/*ARGSUSED*/
334059243SobrienCCRETVAL
3341167465Smpe_redisp(Char c)
334259243Sobrien{
334359243Sobrien    USE(c);
334459243Sobrien    ClearLines();
334559243Sobrien    ClearDisp();
334659243Sobrien    return(CC_REFRESH);
334759243Sobrien}
334859243Sobrien
334959243Sobrien/*ARGSUSED*/
335059243SobrienCCRETVAL
3351167465Smpe_cleardisp(Char c)
335259243Sobrien{
335359243Sobrien    USE(c);
335459243Sobrien    ClearScreen();		/* clear the whole real screen */
335559243Sobrien    ClearDisp();		/* reset everything */
335659243Sobrien    return(CC_REFRESH);
335759243Sobrien}
335859243Sobrien
335959243Sobrien/*ARGSUSED*/
336059243SobrienCCRETVAL
3361167465Smpe_tty_int(Char c)
336259243Sobrien{
336359243Sobrien    USE(c);
336469408Sache#if defined(_MINIX) || defined(WINNT_NATIVE)
336559243Sobrien    /* SAK PATCH: erase all of current line, start again */
336659243Sobrien    ResetInLine(0);		/* reset the input pointers */
336759243Sobrien    xputchar('\n');
336859243Sobrien    ClearDisp();
336959243Sobrien    return (CC_REFRESH);
337069408Sache#else /* !_MINIX && !WINNT_NATIVE */
337159243Sobrien    /* do no editing */
337259243Sobrien    return (CC_NORM);
337369408Sache#endif /* _MINIX || WINNT_NATIVE */
337459243Sobrien}
337559243Sobrien
337659243Sobrien/*
337759243Sobrien * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
337859243Sobrien * Function to send a character back to the input stream in cooked
337959243Sobrien * mode. Only works if we have TIOCSTI
338059243Sobrien */
338159243Sobrien/*ARGSUSED*/
338259243SobrienCCRETVAL
3383167465Smpe_stuff_char(Char c)
338459243Sobrien{
338559243Sobrien#ifdef TIOCSTI
338659243Sobrien     int was_raw = Tty_raw_mode;
3387145479Smp     char buf[MB_LEN_MAX];
3388145479Smp     size_t i, len;
338959243Sobrien
339059243Sobrien     if (was_raw)
339159243Sobrien         (void) Cookedmode();
339259243Sobrien
3393167465Smp     (void) xwrite(SHIN, "\n", 1);
3394316957Sdchagin     len = one_wctomb(buf, c);
3395145479Smp     for (i = 0; i < len; i++)
3396145479Smp	 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
339759243Sobrien
339859243Sobrien     if (was_raw)
3399167465Smp	 (void) Rawmode();
340059243Sobrien     return(e_redisp(c));
340159243Sobrien#else /* !TIOCSTI */
340259243Sobrien     return(CC_ERROR);
340359243Sobrien#endif /* !TIOCSTI */
340459243Sobrien}
340559243Sobrien
340659243Sobrien/*ARGSUSED*/
340759243SobrienCCRETVAL
3408167465Smpe_insovr(Char c)
340959243Sobrien{
341059243Sobrien    USE(c);
341159243Sobrien    inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
341259243Sobrien    return(CC_NORM);
341359243Sobrien}
341459243Sobrien
341559243Sobrien/*ARGSUSED*/
341659243SobrienCCRETVAL
3417167465Smpe_tty_dsusp(Char c)
341859243Sobrien{
341959243Sobrien    USE(c);
342059243Sobrien    /* do no editing */
342159243Sobrien    return(CC_NORM);
342259243Sobrien}
342359243Sobrien
342459243Sobrien/*ARGSUSED*/
342559243SobrienCCRETVAL
3426167465Smpe_tty_flusho(Char c)
342759243Sobrien{
342859243Sobrien    USE(c);
342959243Sobrien    /* do no editing */
343059243Sobrien    return(CC_NORM);
343159243Sobrien}
343259243Sobrien
343359243Sobrien/*ARGSUSED*/
343459243SobrienCCRETVAL
3435167465Smpe_tty_quit(Char c)
343659243Sobrien{
343759243Sobrien    USE(c);
343859243Sobrien    /* do no editing */
343959243Sobrien    return(CC_NORM);
344059243Sobrien}
344159243Sobrien
344259243Sobrien/*ARGSUSED*/
344359243SobrienCCRETVAL
3444167465Smpe_tty_tsusp(Char c)
344559243Sobrien{
344659243Sobrien    USE(c);
344759243Sobrien    /* do no editing */
344859243Sobrien    return(CC_NORM);
344959243Sobrien}
345059243Sobrien
345159243Sobrien/*ARGSUSED*/
345259243SobrienCCRETVAL
3453167465Smpe_tty_stopo(Char c)
345459243Sobrien{
345559243Sobrien    USE(c);
345659243Sobrien    /* do no editing */
345759243Sobrien    return(CC_NORM);
345859243Sobrien}
345959243Sobrien
3460195609Smp/* returns the number of (attempted) expansions */
3461195609Smpint
3462195609SmpExpandHistory(void)
3463195609Smp{
3464195609Smp    *LastChar = '\0';		/* just in case */
3465195609Smp    return c_substitute();
3466195609Smp}
3467195609Smp
346859243Sobrien/*ARGSUSED*/
346959243SobrienCCRETVAL
3470167465Smpe_expand_history(Char c)
347159243Sobrien{
347259243Sobrien    USE(c);
3473195609Smp    (void)ExpandHistory();
347459243Sobrien    return(CC_NORM);
347559243Sobrien}
347659243Sobrien
347759243Sobrien/*ARGSUSED*/
347859243SobrienCCRETVAL
3479167465Smpe_magic_space(Char c)
348059243Sobrien{
348159243Sobrien    USE(c);
348259243Sobrien    *LastChar = '\0';		/* just in case */
3483195609Smp    (void)c_substitute();
348459243Sobrien    return(e_insert(' '));
348559243Sobrien}
348659243Sobrien
348759243Sobrien/*ARGSUSED*/
348859243SobrienCCRETVAL
3489167465Smpe_inc_fwd(Char c)
349059243Sobrien{
3491167465Smp    CCRETVAL ret;
3492167465Smp
349359243Sobrien    USE(c);
3494167465Smp    patbuf.len = 0;
3495167465Smp    MarkIsSet = 0;
3496167465Smp    ret = e_inc_search(F_DOWN_SEARCH_HIST);
3497167465Smp    if (adrof(STRhighlight) && IncMatchLen) {
3498167465Smp	IncMatchLen = 0;
3499167465Smp	ClearLines();
3500167465Smp	ClearDisp();
3501167465Smp	Refresh();
3502167465Smp    }
3503167465Smp    IncMatchLen = 0;
3504167465Smp    return ret;
350559243Sobrien}
350659243Sobrien
350759243Sobrien
350859243Sobrien/*ARGSUSED*/
350959243SobrienCCRETVAL
3510167465Smpe_inc_back(Char c)
351159243Sobrien{
3512167465Smp    CCRETVAL ret;
3513167465Smp
351459243Sobrien    USE(c);
3515167465Smp    patbuf.len = 0;
3516167465Smp    MarkIsSet = 0;
3517167465Smp    ret = e_inc_search(F_UP_SEARCH_HIST);
3518167465Smp    if (adrof(STRhighlight) && IncMatchLen) {
3519167465Smp	IncMatchLen = 0;
3520167465Smp	ClearLines();
3521167465Smp	ClearDisp();
3522167465Smp	Refresh();
3523167465Smp    }
3524167465Smp    IncMatchLen = 0;
3525167465Smp    return ret;
352659243Sobrien}
352759243Sobrien
352859243Sobrien/*ARGSUSED*/
352959243SobrienCCRETVAL
3530167465Smpe_copyprev(Char c)
353159243Sobrien{
353283098Smp    Char *cp, *oldc, *dp;
353359243Sobrien
353459243Sobrien    USE(c);
353559243Sobrien    if (Cursor == InputBuf)
353659243Sobrien	return(CC_ERROR);
353759243Sobrien    /* else */
353859243Sobrien
353959243Sobrien    oldc = Cursor;
354059243Sobrien    /* does a bounds check */
354159243Sobrien    cp = c_prev_word(Cursor, InputBuf, Argument);
354259243Sobrien
354359243Sobrien    c_insert((int)(oldc - cp));
354459243Sobrien    for (dp = oldc; cp < oldc && dp < LastChar; cp++)
354559243Sobrien	*dp++ = *cp;
354659243Sobrien
354759243Sobrien    Cursor = dp;		/* put cursor at end */
354859243Sobrien
354959243Sobrien    return(CC_REFRESH);
355059243Sobrien}
355159243Sobrien
355259243Sobrien/*ARGSUSED*/
355359243SobrienCCRETVAL
3554167465Smpe_tty_starto(Char c)
355559243Sobrien{
355659243Sobrien    USE(c);
355759243Sobrien    /* do no editing */
355859243Sobrien    return(CC_NORM);
355959243Sobrien}
356059243Sobrien
356159243Sobrien/*ARGSUSED*/
356259243SobrienCCRETVAL
3563167465Smpe_load_average(Char c)
356459243Sobrien{
356559243Sobrien    USE(c);
356659243Sobrien    PastBottom();
356759243Sobrien#ifdef TIOCSTAT
356859243Sobrien    /*
356959243Sobrien     * Here we pass &c to the ioctl because some os's (NetBSD) expect it
357059243Sobrien     * there even if they don't use it. (lukem@netbsd.org)
357159243Sobrien     */
357259243Sobrien    if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
357359243Sobrien#endif
3574195609Smp	xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
357559243Sobrien    return(CC_REFRESH);
357659243Sobrien}
357759243Sobrien
357859243Sobrien/*ARGSUSED*/
357959243SobrienCCRETVAL
3580167465Smpv_chgmeta(Char c)
358159243Sobrien{
358259243Sobrien    USE(c);
358359243Sobrien    /*
358459243Sobrien     * Delete with insert == change: first we delete and then we leave in
358559243Sobrien     * insert mode.
358659243Sobrien     */
358759243Sobrien    return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
358859243Sobrien}
358959243Sobrien
359059243Sobrien/*ARGSUSED*/
359159243SobrienCCRETVAL
3592167465Smpv_delmeta(Char c)
359359243Sobrien{
359459243Sobrien    USE(c);
359559243Sobrien    return(v_action(TCSHOP_DELETE));
359659243Sobrien}
359759243Sobrien
359859243Sobrien
359959243Sobrien/*ARGSUSED*/
360059243SobrienCCRETVAL
3601167465Smpv_endword(Char c)
360259243Sobrien{
360359243Sobrien    USE(c);
360459243Sobrien    if (Cursor == LastChar)
360559243Sobrien	return(CC_ERROR);
360659243Sobrien    /* else */
360759243Sobrien
360883098Smp    Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
360959243Sobrien
361059243Sobrien    if (ActionFlag & TCSHOP_DELETE)
361159243Sobrien    {
361259243Sobrien	Cursor++;
361359243Sobrien	c_delfini();
361459243Sobrien	return(CC_REFRESH);
361559243Sobrien    }
361659243Sobrien
361759243Sobrien    RefCursor();
361859243Sobrien    return(CC_NORM);
361959243Sobrien}
362059243Sobrien
362159243Sobrien/*ARGSUSED*/
362259243SobrienCCRETVAL
3623167465Smpv_eword(Char c)
362459243Sobrien{
362559243Sobrien    USE(c);
362659243Sobrien    if (Cursor == LastChar)
362759243Sobrien	return(CC_ERROR);
362859243Sobrien    /* else */
362959243Sobrien
363059243Sobrien    Cursor = c_eword(Cursor, LastChar, Argument);
363159243Sobrien
363259243Sobrien    if (ActionFlag & TCSHOP_DELETE) {
363359243Sobrien	Cursor++;
363459243Sobrien	c_delfini();
363559243Sobrien	return(CC_REFRESH);
363659243Sobrien    }
363759243Sobrien
363859243Sobrien    RefCursor();
363959243Sobrien    return(CC_NORM);
364059243Sobrien}
364159243Sobrien
364259243Sobrien/*ARGSUSED*/
364359243SobrienCCRETVAL
3644167465Smpv_char_fwd(Char c)
364559243Sobrien{
364659243Sobrien    Char ch;
364759243Sobrien
364859243Sobrien    USE(c);
364959243Sobrien    if (GetNextChar(&ch) != 1)
365059243Sobrien	return e_send_eof(0);
365159243Sobrien
365259243Sobrien    srch_dir = CHAR_FWD;
365359243Sobrien    srch_char = ch;
365459243Sobrien
365559243Sobrien    return v_csearch_fwd(ch, Argument, 0);
365659243Sobrien
365759243Sobrien}
365859243Sobrien
365959243Sobrien/*ARGSUSED*/
366059243SobrienCCRETVAL
3661167465Smpv_char_back(Char c)
366259243Sobrien{
366359243Sobrien    Char ch;
366459243Sobrien
366559243Sobrien    USE(c);
366659243Sobrien    if (GetNextChar(&ch) != 1)
366759243Sobrien	return e_send_eof(0);
366859243Sobrien
366959243Sobrien    srch_dir = CHAR_BACK;
367059243Sobrien    srch_char = ch;
367159243Sobrien
367259243Sobrien    return v_csearch_back(ch, Argument, 0);
367359243Sobrien}
367459243Sobrien
367559243Sobrien/*ARGSUSED*/
367659243SobrienCCRETVAL
3677167465Smpv_charto_fwd(Char c)
367859243Sobrien{
367959243Sobrien    Char ch;
368059243Sobrien
368159243Sobrien    USE(c);
368259243Sobrien    if (GetNextChar(&ch) != 1)
368359243Sobrien	return e_send_eof(0);
368459243Sobrien
368559243Sobrien    return v_csearch_fwd(ch, Argument, 1);
368659243Sobrien
368759243Sobrien}
368859243Sobrien
368959243Sobrien/*ARGSUSED*/
369059243SobrienCCRETVAL
3691167465Smpv_charto_back(Char c)
369259243Sobrien{
369359243Sobrien    Char ch;
369459243Sobrien
369559243Sobrien    USE(c);
369659243Sobrien    if (GetNextChar(&ch) != 1)
369759243Sobrien	return e_send_eof(0);
369859243Sobrien
369959243Sobrien    return v_csearch_back(ch, Argument, 1);
370059243Sobrien}
370159243Sobrien
370259243Sobrien/*ARGSUSED*/
370359243SobrienCCRETVAL
3704167465Smpv_rchar_fwd(Char c)
370559243Sobrien{
370659243Sobrien    USE(c);
370759243Sobrien    if (srch_char == 0)
370859243Sobrien	return CC_ERROR;
370959243Sobrien
371059243Sobrien    return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
371159243Sobrien			          v_csearch_back(srch_char, Argument, 0);
371259243Sobrien}
371359243Sobrien
371459243Sobrien/*ARGSUSED*/
371559243SobrienCCRETVAL
3716167465Smpv_rchar_back(Char c)
371759243Sobrien{
371859243Sobrien    USE(c);
371959243Sobrien    if (srch_char == 0)
372059243Sobrien	return CC_ERROR;
372159243Sobrien
372259243Sobrien    return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
372359243Sobrien			           v_csearch_back(srch_char, Argument, 0);
372459243Sobrien}
372559243Sobrien
372659243Sobrien/*ARGSUSED*/
372759243SobrienCCRETVAL
3728167465Smpv_undo(Char c)
372959243Sobrien{
373083098Smp    int  loop;
373183098Smp    Char *kp, *cp;
373259243Sobrien    Char temp;
373359243Sobrien    int	 size;
373459243Sobrien
373559243Sobrien    USE(c);
373659243Sobrien    switch (UndoAction) {
373759243Sobrien    case TCSHOP_DELETE|TCSHOP_INSERT:
373859243Sobrien    case TCSHOP_DELETE:
373959243Sobrien	if (UndoSize == 0) return(CC_NORM);
374059243Sobrien	cp = UndoPtr;
374159243Sobrien	kp = UndoBuf;
374259243Sobrien	for (loop=0; loop < UndoSize; loop++)	/* copy the chars */
374359243Sobrien	    *kp++ = *cp++;			/* into UndoBuf   */
374459243Sobrien
374559243Sobrien	for (cp = UndoPtr; cp <= LastChar; cp++)
374659243Sobrien	    *cp = cp[UndoSize];
374759243Sobrien
374859243Sobrien	LastChar -= UndoSize;
374959243Sobrien	Cursor   =  UndoPtr;
375059243Sobrien
375159243Sobrien	UndoAction = TCSHOP_INSERT;
375259243Sobrien	break;
375359243Sobrien
375459243Sobrien    case TCSHOP_INSERT:
375559243Sobrien	if (UndoSize == 0) return(CC_NORM);
375659243Sobrien	cp = UndoPtr;
375759243Sobrien	Cursor = UndoPtr;
375859243Sobrien	kp = UndoBuf;
375959243Sobrien	c_insert(UndoSize);		/* open the space, */
376059243Sobrien	for (loop = 0; loop < UndoSize; loop++)	/* copy the chars */
376159243Sobrien	    *cp++ = *kp++;
376259243Sobrien
376359243Sobrien	UndoAction = TCSHOP_DELETE;
376459243Sobrien	break;
376559243Sobrien
376659243Sobrien    case TCSHOP_CHANGE:
376759243Sobrien	if (UndoSize == 0) return(CC_NORM);
376859243Sobrien	cp = UndoPtr;
376959243Sobrien	Cursor = UndoPtr;
377059243Sobrien	kp = UndoBuf;
377159243Sobrien	size = (int)(Cursor-LastChar); /*  NOT NSL independant */
377259243Sobrien	if (size < UndoSize)
377359243Sobrien	    size = UndoSize;
377459243Sobrien	for(loop = 0; loop < size; loop++) {
377559243Sobrien	    temp = *kp;
377659243Sobrien	    *kp++ = *cp;
377759243Sobrien	    *cp++ = temp;
377859243Sobrien	}
377959243Sobrien	break;
378059243Sobrien
378159243Sobrien    default:
378259243Sobrien	return(CC_ERROR);
378359243Sobrien    }
378459243Sobrien
378559243Sobrien    return(CC_REFRESH);
378659243Sobrien}
378759243Sobrien
378859243Sobrien/*ARGSUSED*/
378959243SobrienCCRETVAL
3790167465Smpv_ush_meta(Char c)
379159243Sobrien{
379259243Sobrien    USE(c);
379359243Sobrien    return v_search(F_UP_SEARCH_HIST);
379459243Sobrien}
379559243Sobrien
379659243Sobrien/*ARGSUSED*/
379759243SobrienCCRETVAL
3798167465Smpv_dsh_meta(Char c)
379959243Sobrien{
380059243Sobrien    USE(c);
380159243Sobrien    return v_search(F_DOWN_SEARCH_HIST);
380259243Sobrien}
380359243Sobrien
380459243Sobrien/*ARGSUSED*/
380559243SobrienCCRETVAL
3806167465Smpv_rsrch_fwd(Char c)
380759243Sobrien{
380859243Sobrien    USE(c);
3809167465Smp    if (patbuf.len == 0) return(CC_ERROR);
381059243Sobrien    return(v_repeat_srch(searchdir));
381159243Sobrien}
381259243Sobrien
381359243Sobrien/*ARGSUSED*/
381459243SobrienCCRETVAL
3815167465Smpv_rsrch_back(Char c)
381659243Sobrien{
381759243Sobrien    USE(c);
3818167465Smp    if (patbuf.len == 0) return(CC_ERROR);
381959243Sobrien    return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
382059243Sobrien			 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
382159243Sobrien}
382259243Sobrien
382369408Sache#ifndef WINNT_NATIVE
382459243Sobrien/* Since ed.defns.h  is generated from ed.defns.c, these empty
382559243Sobrien   functions will keep the F_NUM_FNS consistent
382659243Sobrien */
382759243SobrienCCRETVAL
3828167465Smpe_copy_to_clipboard(Char c)
382959243Sobrien{
383059243Sobrien    USE(c);
383159243Sobrien    return CC_ERROR;
383259243Sobrien}
383359243Sobrien
383459243SobrienCCRETVAL
3835167465Smpe_paste_from_clipboard(Char c)
383659243Sobrien{
383759243Sobrien    USE(c);
383859243Sobrien    return (CC_ERROR);
383959243Sobrien}
384059243Sobrien
384159243SobrienCCRETVAL
3842167465Smpe_dosify_next(Char c)
384359243Sobrien{
384459243Sobrien    USE(c);
384559243Sobrien    return (CC_ERROR);
384659243Sobrien}
384759243SobrienCCRETVAL
3848167465Smpe_dosify_prev(Char c)
384959243Sobrien{
385059243Sobrien    USE(c);
385159243Sobrien    return (CC_ERROR);
385259243Sobrien}
385359243SobrienCCRETVAL
3854167465Smpe_page_up(Char c)
385559243Sobrien{
385659243Sobrien    USE(c);
385769408Sache    return (CC_ERROR);
385859243Sobrien}
385959243SobrienCCRETVAL
3860167465Smpe_page_down(Char c)
386159243Sobrien{
386259243Sobrien    USE(c);
386369408Sache    return (CC_ERROR);
386459243Sobrien}
386569408Sache#endif /* !WINNT_NATIVE */
386659243Sobrien
386759243Sobrien#ifdef notdef
386859243Sobrienvoid
3869167465SmpMoveCursor(int n)		/* move cursor + right - left char */
387059243Sobrien{
387159243Sobrien    Cursor = Cursor + n;
387259243Sobrien    if (Cursor < InputBuf)
387359243Sobrien	Cursor = InputBuf;
387459243Sobrien    if (Cursor > LastChar)
387559243Sobrien	Cursor = LastChar;
387659243Sobrien    return;
387759243Sobrien}
387859243Sobrien
387959243SobrienChar *
3880167465SmpGetCursor(void)
388159243Sobrien{
388259243Sobrien    return(Cursor);
388359243Sobrien}
388459243Sobrien
388559243Sobrienint
3886167465SmpPutCursor(Char *p)
388759243Sobrien{
388859243Sobrien    if (p < InputBuf || p > LastChar)
388959243Sobrien	return 1;		/* Error */
389059243Sobrien    Cursor = p;
389159243Sobrien    return 0;
389259243Sobrien}
389359243Sobrien#endif
3894