PageRenderTime 109ms CodeModel.GetById 3ms app.highlight 90ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/tcsh/ed.chared.c

https://bitbucket.org/freebsd/freebsd-head/
C | 3889 lines | 3609 code | 88 blank | 192 comment | 253 complexity | a2c5a75c5215a6e8990bfe15e981ea72 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.98 2010/05/08 00:37:39 christos Exp $ */
   2/*
   3 * ed.chared.c: Character editing functions.
   4 */
   5/*-
   6 * Copyright (c) 1980, 1991 The Regents of the University of California.
   7 * All rights reserved.
   8 *
   9 * Redistribution and use in source and binary forms, with or without
  10 * modification, are permitted provided that the following conditions
  11 * are met:
  12 * 1. Redistributions of source code must retain the above copyright
  13 *    notice, this list of conditions and the following disclaimer.
  14 * 2. Redistributions in binary form must reproduce the above copyright
  15 *    notice, this list of conditions and the following disclaimer in the
  16 *    documentation and/or other materials provided with the distribution.
  17 * 3. Neither the name of the University nor the names of its contributors
  18 *    may be used to endorse or promote products derived from this software
  19 *    without specific prior written permission.
  20 *
  21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31 * SUCH DAMAGE.
  32 */
  33/*
  34  Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
  35
  36  e_dabbrev_expand() did not do proper completion if quoted spaces were present
  37  in the string being completed. Exemple:
  38
  39  # echo hello\ world
  40  hello world
  41  # echo h<press key bound to dabbrev-expande>
  42  # echo hello\<cursor>
  43
  44  Correct behavior is:
  45  # echo h<press key bound to dabbrev-expande>
  46  # echo hello\ world<cursor>
  47
  48  The same problem occured if spaces were present in a string withing quotation
  49  marks. Example:
  50
  51  # echo "hello world"
  52  hello world
  53  # echo "h<press key bound to dabbrev-expande>
  54  # echo "hello<cursor>
  55  
  56  The former problem could be solved with minor modifications of c_preword()
  57  and c_endword(). The latter, however, required a significant rewrite of
  58  c_preword(), since quoted strings must be parsed from start to end to
  59  determine if a given character is inside or outside the quotation marks.
  60
  61  Compare the following two strings:
  62
  63  # echo \"" 'foo \' bar\"
  64  " 'foo \' bar\
  65  # echo '\"" 'foo \' bar\"
  66  \"" foo ' bar"
  67
  68  The only difference between the two echo lines is in the first character
  69  after the echo command. The result is either one or three arguments.
  70
  71 */
  72
  73#include "sh.h"
  74
  75RCSID("$tcsh: ed.chared.c,v 3.98 2010/05/08 00:37:39 christos Exp $")
  76
  77#include "ed.h"
  78#include "tw.h"
  79#include "ed.defns.h"
  80
  81/* #define SDEBUG */
  82
  83#define TCSHOP_NOP    	  0x00
  84#define TCSHOP_DELETE 	  0x01
  85#define TCSHOP_INSERT 	  0x02
  86#define TCSHOP_CHANGE 	  0x04
  87
  88#define CHAR_FWD	0
  89#define CHAR_BACK	1
  90
  91/*
  92 * vi word treatment
  93 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
  94 */
  95#define C_CLASS_WHITE	1
  96#define C_CLASS_ALNUM	2
  97#define C_CLASS_OTHER	3
  98
  99static Char *InsertPos = InputBuf; /* Where insertion starts */
 100static Char *ActionPos = 0;	   /* Where action begins  */
 101static int  ActionFlag = TCSHOP_NOP;	   /* What delayed action to take */
 102/*
 103 * Word search state
 104 */
 105static int  searchdir = F_UP_SEARCH_HIST; 	/* Direction of last search */
 106static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
 107/*
 108 * Char search state
 109 */
 110static int  srch_dir = CHAR_FWD;		/* Direction of last search */
 111static Char srch_char = 0;			/* Search target */
 112
 113/* all routines that start with c_ are private to this set of routines */
 114static	void	 c_alternativ_key_map	(int);
 115void	 c_insert		(int);
 116void	 c_delafter		(int);
 117void	 c_delbefore		(int);
 118static 	int	 c_to_class		(Char);
 119static	Char	*c_prev_word		(Char *, Char *, int);
 120static	Char	*c_next_word		(Char *, Char *, int);
 121static	Char	*c_number		(Char *, int *, int);
 122static	Char	*c_expand		(Char *);
 123static	int	 c_excl			(Char *);
 124static	int	 c_substitute		(void);
 125static	void	 c_delfini		(void);
 126static	int	 c_hmatch		(Char *);
 127static	void	 c_hsetpat		(void);
 128#ifdef COMMENT
 129static	void	 c_get_word		(Char **, Char **);
 130#endif
 131static	Char	*c_preword		(Char *, Char *, int, Char *);
 132static	Char	*c_nexword		(Char *, Char *, int);
 133static	Char	*c_endword		(Char *, Char *, int, Char *);
 134static	Char	*c_eword		(Char *, Char *, int);
 135static	void	 c_push_kill		(Char *, Char *);
 136static	void	 c_save_inputbuf	(void);
 137static  CCRETVAL c_search_line		(Char *, int);
 138static  CCRETVAL v_repeat_srch		(int);
 139static	CCRETVAL e_inc_search		(int);
 140#ifdef notyet
 141static  CCRETVAL e_insert_str		(Char *);
 142#endif
 143static	CCRETVAL v_search		(int);
 144static	CCRETVAL v_csearch_fwd		(Char, int, int);
 145static	CCRETVAL v_action		(int);
 146static	CCRETVAL v_csearch_back		(Char, int, int);
 147
 148static void
 149c_alternativ_key_map(int state)
 150{
 151    switch (state) {
 152    case 0:
 153	CurrentKeyMap = CcKeyMap;
 154	break;
 155    case 1:
 156	CurrentKeyMap = CcAltMap;
 157	break;
 158    default:
 159	return;
 160    }
 161
 162    AltKeyMap = (Char) state;
 163}
 164
 165void
 166c_insert(int num)
 167{
 168    Char *cp;
 169
 170    if (LastChar + num >= InputLim)
 171	return;			/* can't go past end of buffer */
 172
 173    if (Cursor < LastChar) {	/* if I must move chars */
 174	for (cp = LastChar; cp >= Cursor; cp--)
 175	    cp[num] = *cp;
 176	if (Mark && Mark > Cursor)
 177		Mark += num;
 178    }
 179    LastChar += num;
 180}
 181
 182void
 183c_delafter(int num)
 184{
 185    Char *cp, *kp = NULL;
 186
 187    if (num > LastChar - Cursor)
 188	num = (int) (LastChar - Cursor);	/* bounds check */
 189
 190    if (num > 0) {			/* if I can delete anything */
 191	if (VImode) {
 192	    kp = UndoBuf;		/* Set Up for VI undo command */
 193	    UndoAction = TCSHOP_INSERT;
 194	    UndoSize = num;
 195	    UndoPtr  = Cursor;
 196	    for (cp = Cursor; cp <= LastChar; cp++) {
 197		*kp++ = *cp;	/* Save deleted chars into undobuf */
 198		*cp = cp[num];
 199	    }
 200	}
 201	else
 202	    for (cp = Cursor; cp + num <= LastChar; cp++)
 203		*cp = cp[num];
 204	LastChar -= num;
 205	/* Mark was within the range of the deleted word? */
 206	if (Mark && Mark > Cursor && Mark <= Cursor+num)
 207		Mark = Cursor;
 208	/* Mark after the deleted word? */
 209	else if (Mark && Mark > Cursor)
 210		Mark -= num;
 211    }
 212#ifdef notdef
 213    else {
 214	/* 
 215	 * XXX: We don't want to do that. In emacs mode overwrite should be
 216	 * sticky. I am not sure how that affects vi mode 
 217	 */
 218	inputmode = MODE_INSERT;
 219    }
 220#endif /* notdef */
 221}
 222
 223void
 224c_delbefore(int num)		/* delete before dot, with bounds checking */
 225{
 226    Char *cp, *kp = NULL;
 227
 228    if (num > Cursor - InputBuf)
 229	num = (int) (Cursor - InputBuf);	/* bounds check */
 230
 231    if (num > 0) {			/* if I can delete anything */
 232	if (VImode) {
 233	    kp = UndoBuf;		/* Set Up for VI undo command */
 234	    UndoAction = TCSHOP_INSERT;
 235	    UndoSize = num;
 236	    UndoPtr  = Cursor - num;
 237	    for (cp = Cursor - num; cp <= LastChar; cp++) {
 238		*kp++ = *cp;
 239		*cp = cp[num];
 240	    }
 241	}
 242	else
 243	    for (cp = Cursor - num; cp + num <= LastChar; cp++)
 244		*cp = cp[num];
 245	LastChar -= num;
 246	Cursor -= num;
 247	/* Mark was within the range of the deleted word? */
 248	if (Mark && Mark > Cursor && Mark <= Cursor+num)
 249		Mark = Cursor;
 250	/* Mark after the deleted word? */
 251	else if (Mark && Mark > Cursor)
 252		Mark -= num;
 253    }
 254}
 255
 256static Char *
 257c_preword(Char *p, Char *low, int n, Char *delim)
 258{
 259  while (n--) {
 260    Char *prev = low;
 261    Char *new;
 262
 263    while (prev < p) {		/* Skip initial non-word chars */
 264      if (!Strchr(delim, *prev) || *(prev-1) == (Char)'\\')
 265	break;
 266      prev++;
 267    }
 268
 269    new = prev;
 270
 271    while (new < p) {
 272      prev = new;
 273      new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */
 274      new++;			/* Step away from end of word */
 275      while (new <= p) {	/* Skip trailing non-word chars */
 276	if (!Strchr(delim, *new) || *(new-1) == (Char)'\\')
 277	  break;
 278	new++;
 279      }
 280    }
 281
 282    p = prev;			/* Set to previous word start */
 283
 284  }
 285  if (p < low)
 286    p = low;
 287  return (p);
 288}
 289
 290/*
 291 * c_to_class() returns the class of the given character.
 292 *
 293 * This is used to make the c_prev_word() and c_next_word() functions
 294 * work like vi's, which classify characters. A word is a sequence of
 295 * characters belonging to the same class, classes being defined as
 296 * follows:
 297 *
 298 *	1/ whitespace
 299 *	2/ alphanumeric chars, + underscore
 300 *	3/ others
 301 */
 302static int
 303c_to_class(Char ch)
 304{
 305    if (Isspace(ch))
 306        return C_CLASS_WHITE;
 307
 308    if (Isdigit(ch) || Isalpha(ch) || ch == '_')
 309        return C_CLASS_ALNUM;
 310
 311    return C_CLASS_OTHER;
 312}
 313
 314static Char *
 315c_prev_word(Char *p, Char *low, int n)
 316{
 317    p--;
 318
 319    if (!VImode) {
 320	while (n--) {
 321	    while ((p >= low) && !isword(*p)) 
 322		p--;
 323	    while ((p >= low) && isword(*p)) 
 324		p--;
 325	}
 326      
 327	/* cp now points to one character before the word */
 328	p++;
 329	if (p < low)
 330	    p = low;
 331	/* cp now points where we want it */
 332	return(p);
 333    }
 334  
 335    while (n--) {
 336        int  c_class;
 337
 338        if (p < low)
 339            break;
 340
 341        /* scan until beginning of current word (may be all whitespace!) */
 342        c_class = c_to_class(*p);
 343        while ((p >= low) && c_class == c_to_class(*p))
 344            p--;
 345
 346        /* if this was a non_whitespace word, we're ready */
 347        if (c_class != C_CLASS_WHITE)
 348            continue;
 349
 350        /* otherwise, move back to beginning of the word just found */
 351        c_class = c_to_class(*p);
 352        while ((p >= low) && c_class == c_to_class(*p))
 353            p--;
 354    }
 355
 356    p++;                        /* correct overshoot */
 357
 358    return (p);
 359}
 360
 361static Char *
 362c_next_word(Char *p, Char *high, int n)
 363{
 364    if (!VImode) {
 365	while (n--) {
 366	    while ((p < high) && !isword(*p)) 
 367		p++;
 368	    while ((p < high) && isword(*p)) 
 369		p++;
 370	}
 371	if (p > high)
 372	    p = high;
 373	/* p now points where we want it */
 374	return(p);
 375    }
 376
 377    while (n--) {
 378        int  c_class;
 379
 380        if (p >= high)
 381            break;
 382
 383        /* scan until end of current word (may be all whitespace!) */
 384        c_class = c_to_class(*p);
 385        while ((p < high) && c_class == c_to_class(*p))
 386            p++;
 387
 388        /* if this was all whitespace, we're ready */
 389        if (c_class == C_CLASS_WHITE)
 390            continue;
 391
 392	/* if we've found white-space at the end of the word, skip it */
 393        while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
 394            p++;
 395    }
 396
 397    p--;                        /* correct overshoot */
 398
 399    return (p);
 400}
 401
 402static Char *
 403c_nexword(Char *p, Char *high, int n)
 404{
 405    while (n--) {
 406	while ((p < high) && !Isspace(*p)) 
 407	    p++;
 408	while ((p < high) && Isspace(*p)) 
 409	    p++;
 410    }
 411
 412    if (p > high)
 413	p = high;
 414    /* p now points where we want it */
 415    return(p);
 416}
 417
 418/*
 419 * Expand-History (originally "Magic-Space") code added by
 420 * Ray Moody <ray@gibbs.physics.purdue.edu>
 421 * this is a neat, but odd, addition.
 422 */
 423
 424/*
 425 * c_number: Ignore character p points to, return number appearing after that.
 426 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
 427 * Return p pointing to last char used.
 428 */
 429
 430/*
 431 * dval is the number to subtract from for things like $-3
 432 */
 433
 434static Char *
 435c_number(Char *p, int *num, int dval)
 436{
 437    int i;
 438    int sign = 1;
 439
 440    if (*++p == '^') {
 441	*num = 1;
 442	return(p);
 443    }
 444    if (*p == '$') {
 445	if (*++p != '-') {
 446	    *num = INT_MAX;	/* Handle $ */
 447	    return(--p);
 448	}
 449	sign = -1;		/* Handle $- */
 450	++p;
 451    }
 452    for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
 453	continue;
 454    *num = (sign < 0 ? dval - i : i);
 455    return(--p);
 456}
 457
 458/*
 459 * excl_expand: There is an excl to be expanded to p -- do the right thing
 460 * with it and return a version of p advanced over the expanded stuff.  Also,
 461 * update tsh_cur and related things as appropriate...
 462 */
 463
 464static Char *
 465c_expand(Char *p)
 466{
 467    Char *q;
 468    struct Hist *h = Histlist.Hnext;
 469    struct wordent *l;
 470    int     i, from, to, dval;
 471    int    all_dig;
 472    int    been_once = 0;
 473    Char   *op = p;
 474    Char   *buf;
 475    size_t buf_len;
 476    Char   *modbuf;
 477
 478    buf = NULL;
 479    if (!h)
 480	goto excl_err;
 481excl_sw:
 482    switch (*(q = p + 1)) {
 483
 484    case '^':
 485	buf = expand_lex(&h->Hlex, 1, 1);
 486	break;
 487
 488    case '$':
 489	if ((l = (h->Hlex).prev) != 0)
 490	    buf = expand_lex(l->prev->prev, 0, 0);
 491	break;
 492
 493    case '*':
 494	buf = expand_lex(&h->Hlex, 1, INT_MAX);
 495	break;
 496
 497    default:
 498	if (been_once) {	/* unknown argument */
 499	    /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
 500	    buf = expand_lex(&h->Hlex, 0, INT_MAX);
 501	    q -= 2;
 502	    break;
 503	}
 504	been_once = 1;
 505
 506	if (*q == ':')		/* short form: !:arg */
 507	    --q;
 508
 509	if (HIST != '\0' && *q != HIST) {
 510	    /*
 511	     * Search for a space, tab, or colon.  See if we have a number (as
 512	     * in !1234:xyz).  Remember the number.
 513	     */
 514	    for (i = 0, all_dig = 1; 
 515		 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
 516		/*
 517		 * PWP: !-4 is a valid history argument too, therefore the test
 518		 * is if not a digit, or not a - as the first character.
 519		 */
 520		if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
 521		    all_dig = 0;
 522		else if (*q == '-')
 523		    all_dig = 2;/* we are sneeky about this */
 524		else
 525		    i = 10 * i + *q - '0';
 526	    }
 527	    --q;
 528
 529	    /*
 530	     * If we have a number, search for event i.  Otherwise, search for
 531	     * a named event (as in !foo).  (In this case, I is the length of
 532	     * the named event).
 533	     */
 534	    if (all_dig) {
 535		if (all_dig == 2)
 536		    i = -i;	/* make it negitive */
 537		if (i < 0)	/* if !-4 (for example) */
 538		    i = eventno + 1 + i;	/* remember: i is < 0 */
 539		for (; h; h = h->Hnext) {
 540		    if (h->Hnum == i)
 541			break;
 542		}
 543	    }
 544	    else {
 545		for (i = (int) (q - p); h; h = h->Hnext) {
 546		    if ((l = &h->Hlex) != 0) {
 547			if (!Strncmp(p + 1, l->next->word, (size_t) i))
 548			    break;
 549		    }
 550		}
 551	    }
 552	}
 553	if (!h)
 554	    goto excl_err;
 555	if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
 556	    q[1] == '$' || q[1] == '^') {	/* get some args */
 557	    p = q[1] == ':' ? ++q : q;
 558	    /*
 559	     * Go handle !foo:*
 560	     */
 561	    if ((q[1] < '0' || q[1] > '9') &&
 562		q[1] != '-' && q[1] != '$' && q[1] != '^')
 563		goto excl_sw;
 564	    /*
 565	     * Go handle !foo:$
 566	     */
 567	    if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
 568		goto excl_sw;
 569	    /*
 570	     * Count up the number of words in this event.  Store it in dval.
 571	     * Dval will be fed to number.
 572	     */
 573	    dval = 0;
 574	    if ((l = h->Hlex.prev) != 0) {
 575		for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
 576		    continue;
 577	    }
 578	    if (!dval)
 579		goto excl_err;
 580	    if (q[1] == '-')
 581		from = 0;
 582	    else
 583		q = c_number(q, &from, dval);
 584	    if (q[1] == '-') {
 585		++q;
 586		if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
 587		    to = dval - 1;
 588		else
 589		    q = c_number(q, &to, dval);
 590	    }
 591	    else if (q[1] == '*') {
 592		++q;
 593		to = INT_MAX;
 594	    }
 595	    else {
 596		to = from;
 597	    }
 598	    if (from < 0 || to < from)
 599		goto excl_err;
 600	    buf = expand_lex(&h->Hlex, from, to);
 601	}
 602	else			/* get whole cmd */
 603	    buf = expand_lex(&h->Hlex, 0, INT_MAX);
 604	break;
 605    }
 606    if (buf == NULL)
 607	buf = SAVE("");
 608
 609    /*
 610     * Apply modifiers, if any.
 611     */
 612    if (q[1] == ':') {
 613	modbuf = buf;
 614	while (q[1] == ':' && modbuf != NULL) {
 615	    switch (q[2]) {
 616	    case 'r':
 617	    case 'e':
 618	    case 'h':
 619	    case 't':
 620	    case 'q':
 621	    case 'x':
 622	    case 'u':
 623	    case 'l':
 624		if ((modbuf = domod(buf, (int) q[2])) != NULL) {
 625		    xfree(buf);
 626		    buf = modbuf;
 627		}
 628		++q;
 629		break;
 630
 631	    case 'a':
 632	    case 'g':
 633		/* Not implemented; this needs to be done before expanding
 634		 * lex. We don't have the words available to us anymore.
 635		 */
 636		++q;
 637		break;
 638
 639	    case 'p':
 640		/* Ok */
 641		++q;
 642		break;
 643
 644	    case '\0':
 645		break;
 646
 647	    default:
 648		++q;
 649		break;
 650	    }
 651	    if (q[1])
 652		++q;
 653	}
 654    }
 655
 656    buf_len = Strlen(buf);
 657    /*
 658     * Now replace the text from op to q inclusive with the text from buf.
 659     */
 660    q++;
 661
 662    /*
 663     * Now replace text non-inclusively like a real CS major!
 664     */
 665    if (LastChar + buf_len - (q - op) >= InputLim)
 666	goto excl_err;
 667    (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
 668    LastChar += buf_len - (q - op);
 669    Cursor += buf_len - (q - op);
 670    (void) memcpy(op, buf, buf_len * sizeof(Char));
 671    *LastChar = '\0';
 672    xfree(buf);
 673    return op + buf_len;
 674excl_err:
 675    xfree(buf);
 676    SoundBeep();
 677    return(op + 1);
 678}
 679
 680/*
 681 * c_excl: An excl has been found at point p -- back up and find some white
 682 * space (or the beginning of the buffer) and properly expand all the excl's
 683 * from there up to the current cursor position. We also avoid (trying to)
 684 * expanding '>!'
 685 * Returns number of expansions attempted (doesn't matter whether they succeeded
 686 * or not).
 687 */
 688
 689static int
 690c_excl(Char *p)
 691{
 692    int i;
 693    Char *q;
 694    int nr_exp;
 695
 696    /*
 697     * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
 698     * back p up to just before the current word.
 699     */
 700    if ((p[1] == ' ' || p[1] == '\t') &&
 701	(p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
 702	for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
 703	    continue;
 704	if (*q == '>')
 705	    ++p;
 706    }
 707    else {
 708	while (*p != ' ' && *p != '\t' && p > InputBuf)
 709	    --p;
 710    }
 711
 712    /*
 713     * Forever: Look for history char.  (Stop looking when we find the cursor.)
 714     * Count backslashes.  If odd, skip history char.  Expand if even number of
 715     * backslashes.
 716     */
 717    nr_exp = 0;
 718    for (;;) {
 719	if (HIST != '\0')
 720	    while (*p != HIST && p < Cursor)
 721		++p;
 722	for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
 723	    continue;
 724	if (i % 2 == 0)
 725	    ++p;
 726	if (p >= Cursor)   /* all done */
 727	    return nr_exp;
 728	if (i % 2 == 1) {
 729	    p = c_expand(p);
 730	    ++nr_exp;
 731	}
 732    }
 733}
 734
 735
 736static int
 737c_substitute(void)
 738{
 739    Char *p;
 740    int  nr_exp;
 741
 742    /*
 743     * Start p out one character before the cursor.  Move it backwards looking
 744     * for white space, the beginning of the line, or a history character.
 745     */
 746    for (p = Cursor - 1; 
 747	 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
 748	continue;
 749
 750    /*
 751     * If we found a history character, go expand it.
 752     */
 753    if (HIST != '\0' && *p == HIST)
 754	nr_exp = c_excl(p);
 755    else
 756        nr_exp = 0;
 757    Refresh();
 758
 759    return nr_exp;
 760}
 761
 762static void
 763c_delfini(void)		/* Finish up delete action */
 764{
 765    int Size;
 766
 767    if (ActionFlag & TCSHOP_INSERT)
 768	c_alternativ_key_map(0);
 769
 770    ActionFlag = TCSHOP_NOP;
 771
 772    if (ActionPos == 0) 
 773	return;
 774
 775    UndoAction = TCSHOP_INSERT;
 776
 777    if (Cursor > ActionPos) {
 778	Size = (int) (Cursor-ActionPos);
 779	c_delbefore(Size); 
 780	RefCursor();
 781    }
 782    else if (Cursor < ActionPos) {
 783	Size = (int)(ActionPos-Cursor);
 784	c_delafter(Size);
 785    }
 786    else  {
 787	Size = 1;
 788	c_delafter(Size);
 789    }
 790    UndoPtr = Cursor;
 791    UndoSize = Size;
 792}
 793
 794static Char *
 795c_endword(Char *p, Char *high, int n, Char *delim)
 796{
 797    Char inquote = 0;
 798    p++;
 799
 800    while (n--) {
 801        while (p < high) {	/* Skip non-word chars */
 802	  if (!Strchr(delim, *p) || *(p-1) == (Char)'\\')
 803	    break;
 804	  p++;
 805        }
 806	while (p < high) {	/* Skip string */
 807	  if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
 808	    if (inquote || *(p-1) != (Char)'\\') { /* Should it be honored? */
 809	      if (inquote == 0) inquote = *p;
 810	      else if (inquote == *p) inquote = 0;
 811	    }
 812	  }
 813	  /* Break if unquoted non-word char */
 814	  if (!inquote && Strchr(delim, *p) && *(p-1) != (Char)'\\')
 815	    break;
 816	  p++;
 817	}
 818    }
 819
 820    p--;
 821    return(p);
 822}
 823
 824
 825static Char *
 826c_eword(Char *p, Char *high, int n)
 827{
 828    p++;
 829
 830    while (n--) {
 831	while ((p < high) && Isspace(*p)) 
 832	    p++;
 833
 834	if (isword(*p))
 835	    while ((p < high) && isword(*p)) 
 836		p++;
 837	else
 838	    while ((p < high) && !(Isspace(*p) || isword(*p)))
 839		p++;
 840    }
 841
 842    p--;
 843    return(p);
 844}
 845
 846/* Set the max length of the kill ring */
 847void
 848SetKillRing(int max)
 849{
 850    CStr *new;
 851    int count, i, j;
 852
 853    if (max < 1)
 854	max = 1;		/* no ring, but always one buffer */
 855    if (max == KillRingMax)
 856	return;
 857    new = xcalloc(max, sizeof(CStr));
 858    if (KillRing != NULL) {
 859	if (KillRingLen != 0) {
 860	    if (max >= KillRingLen) {
 861		count = KillRingLen;
 862		j = KillPos;
 863	    } else {
 864		count = max;
 865		j = (KillPos - count + KillRingLen) % KillRingLen;
 866	    }
 867	    for (i = 0; i < KillRingLen; i++) {
 868		if (i < count)	/* copy latest */
 869		    new[i] = KillRing[j];
 870		else		/* free the others */
 871		    xfree(KillRing[j].buf);
 872		j = (j + 1) % KillRingLen;
 873	    }
 874	    KillRingLen = count;
 875	    KillPos = count % max;
 876	    YankPos = count - 1;
 877	}
 878	xfree(KillRing);
 879    }
 880    KillRing = new;
 881    KillRingMax = max;
 882}
 883
 884/* Push string from start upto (but not including) end onto kill ring */
 885static void
 886c_push_kill(Char *start, Char *end)
 887{
 888    CStr save, *pos;
 889    Char *dp, *cp, *kp;
 890    int len = end - start, i, j, k;
 891
 892    /* Check for duplicates? */
 893    if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
 894	YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
 895	if (eq(dp, STRerase)) {	/* erase earlier one (actually move up) */
 896	    j = YankPos;
 897	    for (i = 0; i < KillRingLen; i++) {
 898		if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
 899		    KillRing[j].buf[len] == '\0') {
 900		    save = KillRing[j];
 901		    for ( ; i > 0; i--) {
 902			k = j;
 903			j = (j + 1) % KillRingLen;
 904			KillRing[k] = KillRing[j];
 905		    }
 906		    KillRing[j] = save;
 907		    return;
 908		}
 909		j = (j - 1 + KillRingLen) % KillRingLen;
 910	    }
 911	} else if (eq(dp, STRall)) { /* skip if any earlier */
 912	    for (i = 0; i < KillRingLen; i++)
 913		if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
 914		    KillRing[i].buf[len] == '\0')
 915		    return;
 916	} else if (eq(dp, STRprev)) { /* skip if immediately previous */
 917	    j = YankPos;
 918	    if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
 919		KillRing[j].buf[len] == '\0')
 920		return;
 921	}
 922    }
 923
 924    /* No duplicate, go ahead and push */
 925    len++;			/* need space for '\0' */
 926    YankPos = KillPos;
 927    if (KillRingLen < KillRingMax)
 928	KillRingLen++;
 929    pos = &KillRing[KillPos];
 930    KillPos = (KillPos + 1) % KillRingMax;
 931    if (pos->len < len) {
 932	pos->buf = xrealloc(pos->buf, len * sizeof(Char));
 933	pos->len = len;
 934    }
 935    cp = start;
 936    kp = pos->buf;
 937    while (cp < end)
 938	*kp++ = *cp++;
 939    *kp = '\0';
 940}
 941
 942/* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
 943static void
 944c_save_inputbuf()
 945{
 946    SavedBuf.len = 0;
 947    Strbuf_append(&SavedBuf, InputBuf);
 948    Strbuf_terminate(&SavedBuf);
 949    LastSaved = LastChar - InputBuf;
 950    CursSaved = Cursor - InputBuf;
 951    HistSaved = Hist_num;
 952    RestoreSaved = 1;
 953}
 954
 955CCRETVAL
 956GetHistLine()
 957{
 958    struct Hist *hp;
 959    int     h;
 960
 961    if (Hist_num == 0) {	/* if really the current line */
 962	if (HistBuf.s != NULL)
 963	    copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
 964	else
 965	    *InputBuf = '\0';
 966	LastChar = InputBuf + HistBuf.len;
 967
 968#ifdef KSHVI
 969    if (VImode)
 970	Cursor = InputBuf;
 971    else
 972#endif /* KSHVI */
 973	Cursor = LastChar;
 974
 975	return(CC_REFRESH);
 976    }
 977
 978    hp = Histlist.Hnext;
 979    if (hp == NULL)
 980	return(CC_ERROR);
 981
 982    for (h = 1; h < Hist_num; h++) {
 983	if ((hp->Hnext) == NULL) {
 984	    Hist_num = h;
 985	    return(CC_ERROR);
 986	}
 987	hp = hp->Hnext;
 988    }
 989
 990    if (HistLit && hp->histline) {
 991	copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
 992	CurrentHistLit = 1;
 993    }
 994    else {
 995	Char *p;
 996
 997	p = sprlex(&hp->Hlex);
 998	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
 999	xfree(p);
1000	CurrentHistLit = 0;
1001    }
1002    LastChar = Strend(InputBuf);
1003
1004    if (LastChar > InputBuf) {
1005	if (LastChar[-1] == '\n')
1006	    LastChar--;
1007#if 0
1008	if (LastChar[-1] == ' ')
1009	    LastChar--;
1010#endif
1011	if (LastChar < InputBuf)
1012	    LastChar = InputBuf;
1013    }
1014  
1015#ifdef KSHVI
1016    if (VImode)
1017	Cursor = InputBuf;
1018    else
1019#endif /* KSHVI */
1020	Cursor = LastChar;
1021
1022    return(CC_REFRESH);
1023}
1024
1025static CCRETVAL
1026c_search_line(Char *pattern, int dir)
1027{
1028    Char *cp;
1029    size_t len;
1030
1031    len = Strlen(pattern);
1032
1033    if (dir == F_UP_SEARCH_HIST) {
1034	for (cp = Cursor; cp >= InputBuf; cp--)
1035	    if (Strncmp(cp, pattern, len) == 0 ||
1036		Gmatch(cp, pattern)) {
1037		Cursor = cp;
1038		return(CC_NORM);
1039	    }
1040	return(CC_ERROR);
1041    } else {
1042	for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1043	    if (Strncmp(cp, pattern, len) == 0 ||
1044		Gmatch(cp, pattern)) {
1045		Cursor = cp;
1046		return(CC_NORM);
1047	    }
1048	return(CC_ERROR);
1049    }
1050}
1051
1052static CCRETVAL
1053e_inc_search(int dir)
1054{
1055    static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1056		      STRbck[] = { 'b', 'c', 'k', '\0' };
1057    static Char pchar = ':';	/* ':' = normal, '?' = failed */
1058    static Char endcmd[2];
1059    const Char *cp;
1060    Char ch,
1061	*oldCursor = Cursor,
1062	oldpchar = pchar;
1063    CCRETVAL ret = CC_NORM;
1064    int oldHist_num = Hist_num,
1065	oldpatlen = patbuf.len,
1066	newdir = dir,
1067        done, redo;
1068
1069    if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1070	return(CC_ERROR);
1071
1072    for (;;) {
1073
1074	if (patbuf.len == 0) {	/* first round */
1075	    pchar = ':';
1076	    Strbuf_append1(&patbuf, '*');
1077	}
1078	done = redo = 0;
1079	*LastChar++ = '\n';
1080	for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd; 
1081	     *cp; *LastChar++ = *cp++)
1082	    continue;
1083	*LastChar++ = pchar;
1084	for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1085	     *LastChar++ = *cp++)
1086	    continue;
1087	*LastChar = '\0';
1088	if (adrof(STRhighlight) && pchar == ':') {
1089	    /* if the no-glob-search patch is applied, remove the - 1 below */
1090	    IncMatchLen = patbuf.len - 1;
1091	    ClearLines();
1092	    ClearDisp();
1093	}
1094	Refresh();
1095
1096	if (GetNextChar(&ch) != 1)
1097	    return(e_send_eof(0));
1098
1099	switch (ch > NT_NUM_KEYS
1100		? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
1101	case F_INSERT:
1102	case F_DIGIT:
1103	case F_MAGIC_SPACE:
1104	    if (LastChar + 1 >= InputLim) /*FIXBUF*/
1105		SoundBeep();
1106	    else {
1107		Strbuf_append1(&patbuf, ch);
1108		*LastChar++ = ch;
1109		*LastChar = '\0';
1110		Refresh();
1111	    }
1112	    break;
1113
1114	case F_INC_FWD:
1115	    newdir = F_DOWN_SEARCH_HIST;
1116	    redo++;
1117	    break;
1118
1119	case F_INC_BACK:
1120	    newdir = F_UP_SEARCH_HIST;
1121	    redo++;
1122	    break;
1123
1124	case F_DELPREV:
1125	    if (patbuf.len > 1)
1126		done++;
1127	    else 
1128		SoundBeep();
1129	    break;
1130
1131	default:
1132	    switch (ASC(ch)) {
1133	    case 0007:		/* ^G: Abort */
1134		ret = CC_ERROR;
1135		done++;
1136		break;
1137
1138	    case 0027:		/* ^W: Append word */
1139		/* No can do if globbing characters in pattern */
1140		for (cp = &patbuf.s[1]; ; cp++)
1141		    if (cp >= &patbuf.s[patbuf.len]) {
1142			Cursor += patbuf.len - 1;
1143			cp = c_next_word(Cursor, LastChar, 1);
1144			while (Cursor < cp && *Cursor != '\n') {
1145			    if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1146				SoundBeep();
1147				break;
1148			    }
1149			    Strbuf_append1(&patbuf, *Cursor);
1150			    *LastChar++ = *Cursor++;
1151			}
1152			Cursor = oldCursor;
1153			*LastChar = '\0';
1154			Refresh();
1155			break;
1156		    } else if (isglob(*cp)) {
1157			SoundBeep();
1158			break;
1159		    }
1160		break;
1161	    
1162	    default:		/* Terminate and execute cmd */
1163		endcmd[0] = ch;
1164		PushMacro(endcmd);
1165		/*FALLTHROUGH*/
1166
1167	    case 0033:		/* ESC: Terminate */
1168		ret = CC_REFRESH;
1169		done++;
1170		break;
1171	    }
1172	    break;
1173	}
1174
1175	while (LastChar > InputBuf && *LastChar != '\n')
1176	    *LastChar-- = '\0';
1177	*LastChar = '\0';
1178
1179	if (!done) {
1180
1181	    /* Can't search if unmatched '[' */
1182	    for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1183		if (*cp == '[' || *cp == ']') {
1184		    ch = *cp;
1185		    break;
1186		}
1187
1188	    if (patbuf.len > 1 && ch != '[') {
1189		if (redo && newdir == dir) {
1190		    if (pchar == '?') {	/* wrap around */
1191			Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1192			if (GetHistLine() == CC_ERROR)
1193			    /* Hist_num was fixed by first call */
1194			    (void) GetHistLine();
1195			Cursor = newdir == F_UP_SEARCH_HIST ?
1196			    LastChar : InputBuf;
1197		    } else
1198			Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1199		}
1200		Strbuf_append1(&patbuf, '*');
1201		Strbuf_terminate(&patbuf);
1202		if (Cursor < InputBuf || Cursor > LastChar ||
1203		    (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1204		    LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1205		    ret = newdir == F_UP_SEARCH_HIST ?
1206			e_up_search_hist(0) : e_down_search_hist(0);
1207		    if (ret != CC_ERROR) {
1208			Cursor = newdir == F_UP_SEARCH_HIST ?
1209			    LastChar : InputBuf;
1210			(void) c_search_line(&patbuf.s[1], newdir);
1211		    }
1212		}
1213		patbuf.s[--patbuf.len] = '\0';
1214		if (ret == CC_ERROR) {
1215		    SoundBeep();
1216		    if (Hist_num != oldHist_num) {
1217			Hist_num = oldHist_num;
1218			if (GetHistLine() == CC_ERROR)
1219			    return(CC_ERROR);
1220		    }
1221		    Cursor = oldCursor;
1222		    pchar = '?';
1223		} else {
1224		    pchar = ':';
1225		}
1226	    }
1227
1228	    ret = e_inc_search(newdir);
1229
1230	    if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1231		/* break abort of failed search at last non-failed */
1232		ret = CC_NORM;
1233	    }
1234
1235	}
1236
1237	if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1238	    /* restore on normal return or error exit */
1239	    pchar = oldpchar;
1240	    patbuf.len = oldpatlen;
1241	    if (Hist_num != oldHist_num) {
1242		Hist_num = oldHist_num;
1243		if (GetHistLine() == CC_ERROR)
1244		    return(CC_ERROR);
1245	    }
1246	    Cursor = oldCursor;
1247	    if (ret == CC_ERROR)
1248		Refresh();
1249	}
1250	if (done || ret != CC_NORM)
1251	    return(ret);
1252	    
1253    }
1254
1255}
1256
1257static CCRETVAL
1258v_search(int dir)
1259{
1260    struct Strbuf tmpbuf = Strbuf_INIT;
1261    Char ch;
1262    Char *oldbuf;
1263    Char *oldlc, *oldc;
1264
1265    cleanup_push(&tmpbuf, Strbuf_cleanup);
1266    oldbuf = Strsave(InputBuf);
1267    cleanup_push(oldbuf, xfree);
1268    oldlc = LastChar;
1269    oldc = Cursor;
1270    Strbuf_append1(&tmpbuf, '*');
1271
1272    InputBuf[0] = '\0';
1273    LastChar = InputBuf;
1274    Cursor = InputBuf;
1275    searchdir = dir;
1276
1277    c_insert(2);	/* prompt + '\n' */
1278    *Cursor++ = '\n';
1279    *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1280    Refresh();
1281    for (ch = 0;ch == 0;) {
1282	if (GetNextChar(&ch) != 1) {
1283	    cleanup_until(&tmpbuf);
1284	    return(e_send_eof(0));
1285	}
1286	switch (ASC(ch)) {
1287	case 0010:	/* Delete and backspace */
1288	case 0177:
1289	    if (tmpbuf.len > 1) {
1290		*Cursor-- = '\0';
1291		LastChar = Cursor;
1292		tmpbuf.len--;
1293	    }
1294	    else {
1295		copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1296		LastChar = oldlc;
1297		Cursor = oldc;
1298		cleanup_until(&tmpbuf);
1299		return(CC_REFRESH);
1300	    }
1301	    Refresh();
1302	    ch = 0;
1303	    break;
1304
1305	case 0033:	/* ESC */
1306#ifdef IS_ASCII
1307	case '\r':	/* Newline */
1308	case '\n':
1309#else
1310	case '\012':    /* ASCII Line feed */
1311	case '\015':    /* ASCII (or EBCDIC) Return */
1312#endif
1313	    break;
1314
1315	default:
1316	    Strbuf_append1(&tmpbuf, ch);
1317	    *Cursor++ = ch;
1318	    LastChar = Cursor;
1319	    Refresh();
1320	    ch = 0;
1321	    break;
1322	}
1323    }
1324    cleanup_until(oldbuf);
1325
1326    if (tmpbuf.len == 1) {
1327	/*
1328	 * Use the old pattern, but wild-card it.
1329	 */
1330	if (patbuf.len == 0) {
1331	    InputBuf[0] = '\0';
1332	    LastChar = InputBuf;
1333	    Cursor = InputBuf;
1334	    Refresh();
1335	    cleanup_until(&tmpbuf);
1336	    return(CC_ERROR);
1337	}
1338	if (patbuf.s[0] != '*') {
1339	    oldbuf = Strsave(patbuf.s);
1340	    patbuf.len = 0;
1341	    Strbuf_append1(&patbuf, '*');
1342	    Strbuf_append(&patbuf, oldbuf);
1343	    xfree(oldbuf);
1344	    Strbuf_append1(&patbuf, '*');
1345	    Strbuf_terminate(&patbuf);
1346	}
1347    }
1348    else {
1349	Strbuf_append1(&tmpbuf, '*');
1350	Strbuf_terminate(&tmpbuf);
1351	patbuf.len = 0;
1352	Strbuf_append(&patbuf, tmpbuf.s);
1353	Strbuf_terminate(&patbuf);
1354    }
1355    cleanup_until(&tmpbuf);
1356    LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1357    Cursor = LastChar = InputBuf;
1358    if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) : 
1359				   e_down_search_hist(0)) == CC_ERROR) {
1360	Refresh();
1361	return(CC_ERROR);
1362    }
1363    else {
1364	if (ASC(ch) == 0033) {
1365	    Refresh();
1366	    *LastChar++ = '\n';
1367	    *LastChar = '\0';
1368	    PastBottom();
1369	    return(CC_NEWLINE);
1370	}
1371	else
1372	    return(CC_REFRESH);
1373    }
1374}
1375
1376/*
1377 * semi-PUBLIC routines.  Any routine that is of type CCRETVAL is an
1378 * entry point, called from the CcKeyMap indirected into the
1379 * CcFuncTbl array.
1380 */
1381
1382/*ARGSUSED*/
1383CCRETVAL
1384v_cmd_mode(Char c)
1385{
1386    USE(c);
1387    InsertPos = 0;
1388    ActionFlag = TCSHOP_NOP;	/* [Esc] cancels pending action */
1389    ActionPos = 0;
1390    DoingArg = 0;
1391    if (UndoPtr > Cursor)
1392	UndoSize = (int)(UndoPtr - Cursor);
1393    else
1394	UndoSize = (int)(Cursor - UndoPtr);
1395
1396    inputmode = MODE_INSERT;
1397    c_alternativ_key_map(1);
1398#ifdef notdef
1399    /*
1400     * We don't want to move the cursor, because all the editing
1401     * commands don't include the character under the cursor.
1402     */
1403    if (Cursor > InputBuf)
1404	Cursor--;
1405#endif
1406    RefCursor();
1407    return(CC_NORM);
1408}
1409
1410/*ARGSUSED*/
1411CCRETVAL
1412e_unassigned(Char c)
1413{				/* bound to keys that arn't really assigned */
1414    USE(c);
1415    SoundBeep();
1416    flush();
1417    return(CC_NORM);
1418}
1419
1420#ifdef notyet
1421static CCRETVAL
1422e_insert_str(Char *c)
1423{
1424    int i, n;
1425
1426    n = Strlen(c);
1427    if (LastChar + Argument * n >= InputLim)
1428	return(CC_ERROR);	/* end of buffer space */
1429    if (inputmode != MODE_INSERT) {
1430	c_delafter(Argument * Strlen(c));
1431    }
1432    c_insert(Argument * n);
1433    while (Argument--) {
1434	for (i = 0; i < n; i++)
1435	    *Cursor++ = c[i];
1436    }
1437    Refresh();
1438    return(CC_NORM);
1439}
1440#endif
1441
1442CCRETVAL
1443e_insert(Char c)
1444{
1445#ifndef SHORT_STRINGS
1446    c &= ASCII;			/* no meta chars ever */
1447#endif
1448
1449    if (!c)
1450	return(CC_ERROR);	/* no NULs in the input ever!! */
1451
1452    if (LastChar + Argument >= InputLim)
1453	return(CC_ERROR);	/* end of buffer space */
1454
1455    if (Argument == 1) {  	/* How was this optimized ???? */
1456
1457	if (inputmode != MODE_INSERT) {
1458	    UndoBuf[UndoSize++] = *Cursor;
1459	    UndoBuf[UndoSize] = '\0';
1460	    c_delafter(1);   /* Do NOT use the saving ONE */
1461    	}
1462
1463        c_insert(1);
1464	*Cursor++ = (Char) c;
1465	DoingArg = 0;		/* just in case */
1466	RefPlusOne(1);		/* fast refresh for one char. */
1467    }
1468    else {
1469	if (inputmode != MODE_INSERT) {
1470	    int i;
1471	    for(i = 0; i < Argument; i++) 
1472		UndoBuf[UndoSize++] = *(Cursor + i);
1473
1474	    UndoBuf[UndoSize] = '\0';
1475	    c_delafter(Argument);   /* Do NOT use the saving ONE */
1476    	}
1477
1478        c_insert(Argument);
1479
1480	while (Argument--)
1481	    *Cursor++ = (Char) c;
1482	Refresh();
1483    }
1484
1485    if (inputmode == MODE_REPLACE_1)
1486	(void) v_cmd_mode(0);
1487
1488    return(CC_NORM);
1489}
1490
1491int
1492InsertStr(Char *s)		/* insert ASCIZ s at cursor (for complete) */
1493{
1494    int len;
1495
1496    if ((len = (int) Strlen(s)) <= 0)
1497	return -1;
1498    if (LastChar + len >= InputLim)
1499	return -1;		/* end of buffer space */
1500
1501    c_insert(len);
1502    while (len--)
1503	*Cursor++ = *s++;
1504    return 0;
1505}
1506
1507void
1508DeleteBack(int n)		/* delete the n characters before . */
1509{
1510    if (n <= 0)
1511	return;
1512    if (Cursor >= &InputBuf[n]) {
1513	c_delbefore(n);		/* delete before dot */
1514    }
1515}
1516
1517CCRETVAL
1518e_digit(Char c)			/* gray magic here */
1519{
1520    if (!Isdigit(c))
1521	return(CC_ERROR);	/* no NULs in the input ever!! */
1522
1523    if (DoingArg) {		/* if doing an arg, add this in... */
1524	if (LastCmd == F_ARGFOUR)	/* if last command was ^U */
1525	    Argument = c - '0';
1526	else {
1527	    if (Argument > 1000000)
1528		return CC_ERROR;
1529	    Argument = (Argument * 10) + (c - '0');
1530	}
1531	return(CC_ARGHACK);
1532    }
1533    else {
1534	if (LastChar + 1 >= InputLim)
1535	    return CC_ERROR;	/* end of buffer space */
1536
1537	if (inputmode != MODE_INSERT) {
1538	    UndoBuf[UndoSize++] = *Cursor;
1539	    UndoBuf[UndoSize] = '\0';
1540	    c_delafter(1);   /* Do NOT use the saving ONE */
1541    	}
1542	c_insert(1);
1543	*Cursor++ = (Char) c;
1544	DoingArg = 0;		/* just in case */
1545	RefPlusOne(1);		/* fast refresh for one char. */
1546    }
1547    return(CC_NORM);
1548}
1549
1550CCRETVAL
1551e_argdigit(Char c)		/* for ESC-n */
1552{
1553#ifdef IS_ASCII
1554    c &= ASCII;
1555#else
1556    c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1557#endif
1558
1559    if (!Isdigit(c))
1560	return(CC_ERROR);	/* no NULs in the input ever!! */
1561
1562    if (DoingArg) {		/* if doing an arg, add this in... */
1563	if (Argument > 1000000)
1564	    return CC_ERROR;
1565	Argument = (Argument * 10) + (c - '0');
1566    }
1567    else {			/* else starting an argument */
1568	Argument = c - '0';
1569	DoingArg = 1;
1570    }
1571    return(CC_ARGHACK);
1572}
1573
1574CCRETVAL
1575v_zero(Char c)			/* command mode 0 for vi */
1576{
1577    if (DoingArg) {		/* if doing an arg, add this in... */
1578	if (Argument > 1000000)
1579	    return CC_ERROR;
1580	Argument = (Argument * 10) + (c - '0');
1581	return(CC_ARGHACK);
1582    }
1583    else {			/* else starting an argument */
1584	Cursor = InputBuf;
1585	if (ActionFlag & TCSHOP_DELETE) {
1586	   c_delfini();
1587	   return(CC_REFRESH);
1588        }
1589	RefCursor();		/* move the cursor */
1590	return(CC_NORM);
1591    }
1592}
1593
1594/*ARGSUSED*/
1595CCRETVAL
1596e_newline(Char c)
1597{				/* always ignore argument */
1598    USE(c);
1599    if (adrof(STRhighlight) && MarkIsSet) {
1600	MarkIsSet = 0;
1601	ClearLines();
1602	ClearDisp();
1603	Refresh();
1604    }
1605    MarkIsSet = 0;
1606
1607  /*  PastBottom();  NOW done in ed.inputl.c */
1608    *LastChar++ = '\n';		/* for the benefit of CSH */
1609    *LastChar = '\0';		/* just in case */
1610    if (VImode)
1611	InsertPos = InputBuf;	/* Reset editing position */
1612    return(CC_NEWLINE);
1613}
1614
1615/*ARGSUSED*/
1616CCRETVAL
1617e_newline_hold(Char c)
1618{
1619    USE(c);
1620    c_save_inputbuf();
1621    HistSaved = 0;
1622    *LastChar++ = '\n';		/* for the benefit of CSH */
1623    *LastChar = '\0';		/* just in case */
1624    return(CC_NEWLINE);
1625}
1626
1627/*ARGSUSED*/
1628CCRETVAL
1629e_newline_down_hist(Char c)
1630{
1631    USE(c);
1632    if (Hist_num > 1) {
1633	HistSaved = Hist_num;
1634    }
1635    *LastChar++ = '\n';		/* for the benefit of CSH */
1636    *LastChar = '\0';		/* just in case */
1637    return(CC_NEWLINE);
1638}
1639
1640/*ARGSUSED*/
1641CCRETVAL
1642e_send_eof(Char c)
1643{				/* for when ^D is ONLY send-eof */
1644    USE(c);
1645    PastBottom();
1646    *LastChar = '\0';		/* just in case */
1647    return(CC_EOF);
1648}
1649
1650/*ARGSUSED*/
1651CCRETVAL
1652e_complete(Char c)
1653{
1654    USE(c);
1655    *LastChar = '\0';		/* just in case */
1656    return(CC_COMPLETE);
1657}
1658
1659/*ARGSUSED*/
1660CCRETVAL
1661e_complete_back(Char c)
1662{
1663    USE(c);
1664    *LastChar = '\0';		/* just in case */
1665    return(CC_COMPLETE_BACK);
1666}
1667
1668/*ARGSUSED*/
1669CCRETVAL
1670e_complete_fwd(Char c)
1671{
1672    USE(c);
1673    *LastChar = '\0';		/* just in case */
1674    return(CC_COMPLETE_FWD);
1675}
1676
1677/*ARGSUSED*/
1678CCRETVAL
1679e_complete_all(Char c)
1680{
1681    USE(c);
1682    *LastChar = '\0';		/* just in case */
1683    return(CC_COMPLETE_ALL);
1684}
1685
1686/*ARGSUSED*/
1687CCRETVAL
1688v_cm_complete(Char c)
1689{
1690    USE(c);
1691    if (Cursor < LastChar)
1692	Cursor++;
1693    *LastChar = '\0';		/* just in case */
1694    return(CC_COMPLETE);
1695}
1696
1697/*ARGSUSED*/
1698CCRETVAL
1699e_toggle_hist(Char c)
1700{
1701    struct Hist *hp;
1702    int     h;
1703
1704    USE(c);
1705    *LastChar = '\0';		/* just in case */
1706
1707    if (Hist_num <= 0) {
1708	return CC_ERROR;
1709    }
1710
1711    hp = Histlist.Hnext;
1712    if (hp == NULL) {	/* this is only if no history */
1713	return(CC_ERROR);
1714    }
1715
1716    for (h = 1; h < Hist_num; h++)
1717	hp = hp->Hnext;
1718
1719    if (!CurrentHistLit) {
1720	if (hp->histline) {
1721	    copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1722	    CurrentHistLit = 1;
1723	}
1724	else {
1725	    return CC_ERROR;
1726	}
1727    }
1728    else {
1729	Char *p;
1730
1731	p = sprlex(&hp->Hlex);
1732	copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1733	xfree(p);
1734	CurrentHistLit = 0;
1735    }
1736
1737    LastChar = Strend(InputBuf);
1738    if (LastChar > InputBuf) {
1739	if (LastChar[-1] == '\n')
1740	    LastChar--;
1741	if (LastChar[-1] == ' ')
1742	    LastChar--;
1743	if (LastChar < InputBuf)
1744	    LastChar = InputBuf;
1745    }
1746
1747#ifdef KSHVI
1748    if (VImode)
1749	Cursor = InputBuf;
1750    else
1751#endif /* KSHVI */
1752	Cursor = LastChar;
1753
1754    return(CC_REFRESH);
1755}
1756
1757/*ARGSUSED*/
1758CCRETVAL
1759e_up_hist(Char c)
1760{
1761    Char    beep = 0;
1762
1763    USE(c);
1764    UndoAction = TCSHOP_NOP;
1765    *LastChar = '\0';		/* just in case */
1766
1767    if (Hist_num == 0) {	/* save the current buffer away */
1768	HistBuf.len = 0;
1769	Strbuf_append(&HistBuf, InputBuf);
1770	Strbuf_terminate(&HistBuf);
1771    }
1772
1773    Hist_num += Argument;
1774
1775    if (GetHistLine() == CC_ERROR) {
1776	beep = 1;
1777	(void) GetHistLine(); /* Hist_num was fixed by first call */
1778    }
1779
1780    Refresh();
1781    if (beep)
1782	return(CC_ERROR);
1783    else
1784	return(CC_NORM);	/* was CC_UP_HIST */
1785}
1786
1787/*ARGSUSED*/
1788CCRETVAL
1789e_down_hist(Char c)
1790{
1791    USE(c);
1792    UndoAction = TCSHOP_NOP;
1793    *LastChar = '\0';		/* just in case */
1794
1795    Hist_num -= Argument;
1796
1797    if (Hist_num < 0) {
1798	Hist_num = 0;
1799	return(CC_ERROR);	/* make it beep */
1800    }
1801
1802    return(GetHistLine());
1803}
1804
1805
1806
1807/*
1808 * c_hmatch() return True if the pattern matches the prefix
1809 */
1810static int
1811c_hmatch(Char *str)
1812{
1813    if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1814	return 1;
1815    return Gmatch(str, patbuf.s);
1816}
1817
1818/*
1819 * c_hsetpat(): Set the history seatch pattern
1820 */
1821static void
1822c_hsetpat(void)
1823{
1824    if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1825	patbuf.len = 0;
1826	Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1827	Strbuf_terminate(&patbuf);
1828    }
1829#ifdef SDEBUG
1830    xprintf("\nHist_num = %d\n", Hist_num);
1831    xprintf("patlen = %d\n", (int)patbuf.len);
1832    xprintf("patbuf = \"%S\"\n", patbuf.s);
1833    xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1834#endif
1835}
1836
1837/*ARGSUSED*/
1838CCRETVAL
1839e_up_search_hist(Char c)
1840{
1841    struct Hist *hp;
1842    int h;
1843    int    found = 0;
1844
1845    USE(c);
1846    ActionFlag = TCSHOP_NOP;
1847    UndoAction = TCSHOP_NOP;
1848    *LastChar = '\0';		/* just in case */
1849    if (Hist_num < 0) {
1850#ifdef DEBUG_EDIT
1851	xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1852#endif
1853	Hist_num = 0;
1854	return(CC_ERROR);
1855    }
1856
1857    if (Hist_num == 0) {
1858	HistBuf.len = 0;
1859	Strbuf_append(&HistBuf, InputBuf);
1860	Strbuf_terminate(&HistBuf);
1861    }
1862
1863
1864    hp = Histlist.Hnext;
1865    if (hp == NULL)
1866	return(CC_ERROR);
1867
1868    c_hsetpat();		/* Set search pattern !! */
1869
1870    for (h = 1; h <= Hist_num; h++)
1871	hp = hp->Hnext;
1872
1873    while (hp != NULL) {
1874	Char *hl;
1875	int matched;
1876
1877	if (hp->histline == NULL)
1878	    hp->histline = sprlex(&hp->Hlex);
1879	if (HistLit)
1880	    hl = hp->histline;
1881	else {
1882	    hl = sprlex(&hp->Hlex);
1883	    cleanup_push(hl, xfree);
1884	}
1885#ifdef SDEBUG
1886	xprintf("Comparing with \"%S\"\n", hl);
1887#endif
1888	matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1889		   hl[LastChar-InputBuf]) && c_hmatch(hl);
1890	if (!HistLit)
1891	    cleanup_until(hl);
1892	if (matched) {
1893	    found++;
1894	    break;
1895	}
1896	h++;
1897	hp = hp->Hnext;
1898    }
1899
1900    if (!found) {
1901#ifdef SDEBUG
1902	xprintf("not found\n");
1903#endif
1904	return(CC_ERROR);
1905    }
1906
1907    Hist_num = h;
1908
1909    return(GetHistLine());
1910}
1911
1912/*ARGSUSED*/
1913CCRETVAL
1914e_down_search_hist(Char c)
1915{
1916    struct Hist *hp;
1917    int h;
1918    int    found = 0;
1919
1920    USE(c);
1921    ActionFlag = TCSHOP_NOP;
1922    UndoAction = TCSHOP_NOP;
1923    *LastChar = '\0';		/* just in case */
1924
1925    if (Hist_num == 0)
1926	return(CC_ERROR);
1927
1928    hp = Histlist.Hnext;
1929    if (hp == 0)
1930	return(CC_ERROR);
1931
1932    c_hsetpat();		/* Set search pattern !! */
1933
1934    for (h = 1; h < Hist_num && hp; h++) {
1935	Char *hl;
1936	if (hp->histline == NULL)
1937	    hp->histline = sprlex(&hp->Hlex);
1938	if (HistLit)
1939	    hl = hp->histline;
1940	else {
1941	    hl = sprlex(&hp->Hlex);
1942	    cleanup_push(hl, xfree);
1943	}
1944#ifdef SDEBUG
1945	xprintf("Comparing with \"%S\"\n", hl);
1946#endif
1947	if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) || 
1948	     hl[LastChar-InputBuf]) && c_hmatch(hl))
1949	    found = h;
1950	if (!HistLit)
1951	    cleanup_until(hl);
1952	hp = hp->Hnext;
1953    }
1954
1955    if (!found) {		/* is it the current history number? */
1956	if (!c_hmatch(HistBuf.s)) {
1957#ifdef SDEBUG
1958	    xprintf("not found\n");
1959#endif
1960	    return(CC_ERROR);
1961	}
1962    }
1963
1964    Hist_num = found;
1965
1966    return(GetHistLine());
1967}
1968
1969/*ARGSUSED*/
1970CCRETVAL
1971e_helpme(Char c)
1972{
1973    USE(c);
1974    PastBottom();
1975    *LastChar = '\0';		/* just in case */
1976    return(CC_HELPME);
1977}
1978
1979/*ARGSUSED*/
1980CCRETVAL
1981e_correct(Char c)
1982{
1983    USE(c);
1984    *LastChar = '\0';		/* just in case */
1985    return(CC_CORRECT);
1986}
1987
1988/*ARGSUSED*/
1989CCRETVAL
1990e_correctl(Char c)
1991{
1992    USE(c);
1993    *LastChar = '\0';		/* just in case */
1994    return(CC_CORRECT_L);
1995}
1996
1997/*ARGSUSED*/
1998CCRETVAL
1999e_run_fg_editor(Char c)
2000{
2001    struct process *pp;
2002
2003    USE(c);
2004    if ((pp = find_stop_ed()) != NULL) {
2005	/* save our editor state so we can restore it */
2006	c_save_inputbuf();
2007	Hist_num = 0;		/* for the history commands */
2008
2009	/* put the tty in a sane mode */
2010	PastBottom();
2011	(void) Cookedmode();	/* make sure the tty is set up correctly */
2012
2013	/* do it! */
2014	fg_proc_entry(pp);
2015
2016	(void) Rawmode();	/* go on */
2017	Refresh();
2018	RestoreSaved = 0;
2019	HistSaved = 0;
2020    }
2021    return(CC_NORM);
2022}
2023
2024/*ARGSUSED*/
2025CCRETVAL
2026e_list_choices(Char c)
2027{
2028    USE(c);
2029    PastBottom();
2030    *LastChar = '\0';		/* just in case */
2031    return(CC_LIST_CHOICES);
2032}
2033
2034/*ARGSUSED*/
2035CCRETVAL
2036e_list_all(Char c)
2037{
2038    USE(c);
2039    PastBottom();
2040    *LastChar = '\0';		/* just in case */
2041    return(CC_LIST_ALL);
2042}
2043
2044/*ARGSUSED*/
2045CCRETVAL
2046e_list_glob(Char c)
2047{
2048    USE(c);
2049    PastBottom();
2050    *LastChar = '\0';		/* just in case */
2051    return(CC_LIST_GLOB);
2052}
2053
2054/*ARGSUSED*/
2055CCRETVAL
2056e_expand_glob(Char c)
2057{
2058    USE(c);
2059    *LastChar = '\0';		/* just in case */
2060    return(CC_EXPAND_GLOB);
2061}
2062
2063/*ARGSUSED*/
2064CCRETVAL
2065e_normalize_path(Char c)
2066{
2067    USE(c);
2068    *LastChar = '\0';		/* just in case */
2069    return(CC_NORMALIZE_PATH);
2070}
2071
2072/*ARGSUSED*/
2073CCRETVAL
2074e_normalize_command(Char c)
2075{
2076    USE(c);
2077    *LastChar = '\0';		/* just in case */
2078    return(CC_NORMALIZE_COMMAND);
2079}
2080
2081/*ARGSUSED*/
2082CCRETVAL
2083e_expand_vars(Char c)
2084{
2085    USE(c);
2086    *LastChar = '\0';		/* just in case */
2087    return(CC_EXPAND_VARS);
2088}
2089
2090/*ARGSUSED*/
2091CCRETVAL
2092e_which(Char c)
2093{				/* do a fast command line which(1) */
2094    USE(c);
2095    c_save_inputbuf();
2096    Hist_num = 0;		/* for the history commands */
2097    PastBottom();
2098    *LastChar = '\0';		/* just in case */
2099    return(CC_WHICH);
2100}
2101
2102/*ARGSUSED*/
2103CCRETVAL
2104e_last_item(Char c)
2105{				/* insert the last element of the prev. cmd */
2106    struct Hist *hp;
2107    struct wordent *wp, *firstp;
2108    int i;
2109    Char *expanded;
2110
2111    USE(c);
2112    if (Argument <= 0)
2113	return(CC_ERROR);
2114
2115    hp = Histlist.Hnext;
2116    if (hp == NULL) {	/* this is only if no history */
2117	return(CC_ERROR);
2118    }
2119
2120    wp = (hp->Hlex).prev;
2121
2122    if (wp->prev == (struct wordent *) NULL)
2123	return(CC_ERROR);	/* an empty history entry */
2124
2125    firstp = (hp->Hlex).next;
2126
2127    /* back up arg words in lex */
2128    for (i = 0; i < Argument && wp != firstp; i++) {
2129	wp = wp->prev;
2130    }
2131
2132    expanded = expand_lex(wp->prev, 0, i - 1);
2133    if (InsertStr(expanded)) {
2134	xfree(expanded);
2135	return(CC_ERROR);
2136    }
2137
2138    xfree(expanded);
2139    return(CC_REFRESH);
2140}
2141
2142/*ARGSUSED*/
2143CCRETVAL
2144e_dabbrev_expand(Char c)
2145{				/* expand to preceding word matching prefix */
2146    Char *cp, *ncp, *bp;
2147    struct Hist *hp;
2148    int arg = 0, i;
2149    size_t len = 0;
2150    int found = 0;
2151    Char *hbuf;
2152    static int oldevent, hist, word;
2153    static Char *start, *oldcursor;
2154
2155    USE(c);
2156    if (Argument <= 0)
2157	return(CC_ERROR);
2158
2159    cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2160    if (cp == Cursor || Isspace(*cp))
2161	return(CC_ERROR);
2162
2163    hbuf = NULL;
2164    hp = Histlist.Hnext;
2165    bp = InputBuf;
2166    if (Argument == 1 && eventno == oldevent && cp == start &&
2167	Cursor == oldcursor && patbuf.len > 0
2168	&& Strncmp(patbuf.s, cp, patbuf.len) == 0){
2169	/* continue previous search - go to last match (hist/word) */
2170	if (hist != 0) {		/* need to move up history */
2171	    for (i = 1; i < hist && hp != NULL; i++)
2172		hp = hp->Hnext;
2173	    if (hp == NULL)	/* "can't happen" */
2174		goto err_hbuf;
2175	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2176	    cp = Strend(hbuf);
2177	    bp = hbuf;
2178	    hp = hp->Hnext;
2179	}
2180	cp = c_preword(cp, bp, word, STRshwordsep);
2181    } else {			/* starting new search */
2182	oldevent = eventno;
2183	start = cp;
2184	patbuf.len = 0;
2185	Strbuf_appendn(&patbuf, cp, Cursor - cp);
2186	hist = 0;
2187	word = 0;
2188    }
2189
2190    while (!found) {
2191	ncp = c_preword(cp, bp, 1, STRshwordsep);
2192	if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2193	    hist++;
2194	    word = 0;
2195	    if (hp == NULL)
2196		goto err_hbuf;
2197	    hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2198	    cp = Strend(hbuf);
2199	    bp = hbuf;
2200	    hp = hp->Hnext;
2201	    continue;
2202	} else {
2203	    word++;
2204	    len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2205	    cp = ncp;
2206	}
2207	if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2208	    /* We don't fully check distinct matches as Gnuemacs does: */
2209	    if (Argument > 1) {	/* just count matches */
2210		if (++arg >= Argument)
2211		    found++;
2212	    } else {		/* match if distinct from previous */
2213		if (len != (size_t)(Cursor - start)
2214		    || Strncmp(cp, start, len) != 0)
2215		    found++;
2216	    }
2217	}
2218    }
2219
2220    if (LastChar + len - (Cursor - start) >= InputLim)
2221	goto err_hbuf;	/* no room */
2222    DeleteBack(Cursor - start);
2223    c_insert(len);
2224    while (len--)
2225	*Cursor++ = *cp++;
2226    oldcursor = Cursor;
2227    xfree(hbuf);
2228    return(CC_REFRESH);
2229
2230 err_hbuf:
2231    xfree(hbuf);
2232    return CC_ERROR;
2233}
2234
2235/*ARGSUSED*/
2236CCRETVAL
2237e_yank_kill(Char c)
2238{				/* almost like GnuEmacs */
2239    int len;
2240    Char *kp, *cp;
2241
2242    USE(c);
2243    if (KillRingLen == 0)	/* nothing killed */
2244	return(CC_ERROR);
2245    len = Strlen(KillRing[YankPos].buf);
2246    if (LastChar + len >= InputLim)
2247	return(CC_ERROR);	/* end of buffer space */
2248
2249    /* else */
2250    cp = Cursor;		/* for speed */
2251
2252    c_insert(len);		/* open the space, */
2253    for (kp = KillRing[YankPos].buf; *kp; kp++)	/* copy the chars */
2254	*cp++ = *kp;
2255
2256    if (Argument == 1) {	/* if no arg */
2257	Mark = Cursor;		/* mark at beginning, cursor at end */
2258	Cursor = cp;
2259    } else {
2260	Mark = cp;		/* else cursor at beginning, mark at end */
2261    }
2262
2263    if (adrof(STRhighlight) && MarkIsSet) {
2264	ClearLines();
2265	ClearDisp();
2266    }
2267    MarkIsSet = 0;
2268    return(CC_REFRESH);
2269}
2270
2271/*ARGSUSED*/
2272CCRETVAL
2273e_yank_pop(Char c)
2274{				/* almost like GnuEmacs */
2275    int m_bef_c, del_len, ins_len;
2276    Char *kp, *cp;
2277
2278    USE(c);
2279
2280#if 0
2281    /* XXX This "should" be here, but doesn't work, since LastCmd
2282       gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2283       (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2284       second one will "succeed" even if the first one wasn't preceded
2285       by a yank, and giving an argument is impossible. Now we "succeed"
2286       regardless of previous command, which is wrong too of course. */
2287    if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2288	return(CC_ERROR);
2289#endif
2290
2291    if (KillRingLen == 0)	/* nothing killed */
2292	return(CC_ERROR);
2293    YankPos -= Argument;
2294    while (YankPos < 0)
2295	YankPos += KillRingLen;
2296    YankPos %= KillRingLen;
2297
2298    if (Cursor > Mark) {
2299	del_len = Cursor - Mark;
2300	m_bef_c = 1;
2301    } else {
2302	del_len = Mark - Cursor;
2303	m_bef_c = 0;
2304    }
2305    ins_len = Strlen(KillRing[YankPos].buf);
2306    if (LastChar + ins_len - del_len >= InputLim)
2307	return(CC_ERROR);	/* end of buffer space */
2308
2309    if (m_bef_c) {
2310	c_delbefore(del_len);
2311    } else {
2312	c_delafter(del_len);
2313    }
2314    cp = Cursor;		/* for speed */
2315
2316    c_insert

Large files files are truncated, but you can click here to view the full file