xref: /netbsd-src/lib/libedit/chared.c (revision 62c70a7281dc4f524b80aed6ef9cebc0b65d6ec0)
1*62c70a72Schristos /*	$NetBSD: chared.c,v 1.64 2024/06/29 14:13:14 christos Exp $	*/
22543e3e6Slukem 
36dc2f1dbScgd /*-
46dc2f1dbScgd  * Copyright (c) 1992, 1993
56dc2f1dbScgd  *	The Regents of the University of California.  All rights reserved.
66dc2f1dbScgd  *
76dc2f1dbScgd  * This code is derived from software contributed to Berkeley by
86dc2f1dbScgd  * Christos Zoulas of Cornell University.
96dc2f1dbScgd  *
106dc2f1dbScgd  * Redistribution and use in source and binary forms, with or without
116dc2f1dbScgd  * modification, are permitted provided that the following conditions
126dc2f1dbScgd  * are met:
136dc2f1dbScgd  * 1. Redistributions of source code must retain the above copyright
146dc2f1dbScgd  *    notice, this list of conditions and the following disclaimer.
156dc2f1dbScgd  * 2. Redistributions in binary form must reproduce the above copyright
166dc2f1dbScgd  *    notice, this list of conditions and the following disclaimer in the
176dc2f1dbScgd  *    documentation and/or other materials provided with the distribution.
18eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
196dc2f1dbScgd  *    may be used to endorse or promote products derived from this software
206dc2f1dbScgd  *    without specific prior written permission.
216dc2f1dbScgd  *
226dc2f1dbScgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
236dc2f1dbScgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
246dc2f1dbScgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
256dc2f1dbScgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
266dc2f1dbScgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
276dc2f1dbScgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
286dc2f1dbScgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
296dc2f1dbScgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
306dc2f1dbScgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
316dc2f1dbScgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326dc2f1dbScgd  * SUCH DAMAGE.
336dc2f1dbScgd  */
346dc2f1dbScgd 
350e0ac6b7Schristos #include "config.h"
366dc2f1dbScgd #if !defined(lint) && !defined(SCCSID)
372543e3e6Slukem #if 0
386dc2f1dbScgd static char sccsid[] = "@(#)chared.c	8.1 (Berkeley) 6/4/93";
392543e3e6Slukem #else
40*62c70a72Schristos __RCSID("$NetBSD: chared.c,v 1.64 2024/06/29 14:13:14 christos Exp $");
412543e3e6Slukem #endif
426dc2f1dbScgd #endif /* not lint && not SCCSID */
436dc2f1dbScgd 
446dc2f1dbScgd /*
456dc2f1dbScgd  * chared.c: Character editor utilities
466dc2f1dbScgd  */
47e84df91eSchristos #include <ctype.h>
486dc2f1dbScgd #include <stdlib.h>
49e84df91eSchristos #include <string.h>
50747f6811Schristos 
516dc2f1dbScgd #include "el.h"
52747f6811Schristos #include "common.h"
534fc1f47dSchristos #include "fcns.h"
546dc2f1dbScgd 
5500ff7cacSjdolecek /* value to leave unused in line buffer */
5600ff7cacSjdolecek #define	EL_LEAVE	2
5700ff7cacSjdolecek 
586dc2f1dbScgd /* cv_undo():
596dc2f1dbScgd  *	Handle state for the vi undo command
606dc2f1dbScgd  */
61a2d6b270Schristos libedit_private void
cv_undo(EditLine * el)6239f224afSchristos cv_undo(EditLine *el)
636dc2f1dbScgd {
646dc2f1dbScgd 	c_undo_t *vu = &el->el_chared.c_undo;
6539f224afSchristos 	c_redo_t *r = &el->el_chared.c_redo;
665c894153Schristos 	size_t size;
67a17c7fe4Schristos 
6839f224afSchristos 	/* Save entire line for undo */
693d802cf5Schristos 	size = (size_t)(el->el_line.lastchar - el->el_line.buffer);
703d802cf5Schristos 	vu->len = (ssize_t)size;
715c894153Schristos 	vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer);
7234e53048Schristos 	(void)memcpy(vu->buf, el->el_line.buffer, size * sizeof(*vu->buf));
73a17c7fe4Schristos 
7439f224afSchristos 	/* save command info for redo */
7539f224afSchristos 	r->count = el->el_state.doingarg ? el->el_state.argument : 0;
7639f224afSchristos 	r->action = el->el_chared.c_vcmd.action;
7739f224afSchristos 	r->pos = r->buf;
7839f224afSchristos 	r->cmd = el->el_state.thiscmd;
7939f224afSchristos 	r->ch = el->el_state.thisch;
80a17c7fe4Schristos }
8139f224afSchristos 
8239f224afSchristos /* cv_yank():
8339f224afSchristos  *	Save yank/delete data for paste
8439f224afSchristos  */
85a2d6b270Schristos libedit_private void
cv_yank(EditLine * el,const wchar_t * ptr,int size)860594af80Schristos cv_yank(EditLine *el, const wchar_t *ptr, int size)
8739f224afSchristos {
8839f224afSchristos 	c_kill_t *k = &el->el_chared.c_kill;
8939f224afSchristos 
903d802cf5Schristos 	(void)memcpy(k->buf, ptr, (size_t)size * sizeof(*k->buf));
9139f224afSchristos 	k->last = k->buf + size;
926dc2f1dbScgd }
936dc2f1dbScgd 
946dc2f1dbScgd 
956dc2f1dbScgd /* c_insert():
966dc2f1dbScgd  *	Insert num characters
976dc2f1dbScgd  */
98a2d6b270Schristos libedit_private void
c_insert(EditLine * el,int num)99d30d584aSlukem c_insert(EditLine *el, int num)
1006dc2f1dbScgd {
1010594af80Schristos 	wchar_t *cp;
1026dc2f1dbScgd 
10339f224afSchristos 	if (el->el_line.lastchar + num >= el->el_line.limit) {
1045c894153Schristos 		if (!ch_enlargebufs(el, (size_t)num))
1056dc2f1dbScgd 			return;		/* can't go past end of buffer */
10639f224afSchristos 	}
1076dc2f1dbScgd 
1086dc2f1dbScgd 	if (el->el_line.cursor < el->el_line.lastchar) {
1096dc2f1dbScgd 		/* if I must move chars */
1106dc2f1dbScgd 		for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
1116dc2f1dbScgd 			cp[num] = *cp;
1126dc2f1dbScgd 	}
1136dc2f1dbScgd 	el->el_line.lastchar += num;
114d30d584aSlukem }
1156dc2f1dbScgd 
1166dc2f1dbScgd 
1176dc2f1dbScgd /* c_delafter():
1186dc2f1dbScgd  *	Delete num characters after the cursor
1196dc2f1dbScgd  */
120a2d6b270Schristos libedit_private void
c_delafter(EditLine * el,int num)121d30d584aSlukem c_delafter(EditLine *el, int num)
1226dc2f1dbScgd {
1236dc2f1dbScgd 
1246dc2f1dbScgd 	if (el->el_line.cursor + num > el->el_line.lastchar)
1255c894153Schristos 		num = (int)(el->el_line.lastchar - el->el_line.cursor);
1266dc2f1dbScgd 
12739f224afSchristos 	if (el->el_map.current != el->el_map.emacs) {
12839f224afSchristos 		cv_undo(el);
12939f224afSchristos 		cv_yank(el, el->el_line.cursor, num);
13039f224afSchristos 	}
131a17c7fe4Schristos 
1326dc2f1dbScgd 	if (num > 0) {
1330594af80Schristos 		wchar_t *cp;
1346dc2f1dbScgd 
1356dc2f1dbScgd 		for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
1366dc2f1dbScgd 			*cp = cp[num];
1376dc2f1dbScgd 
1386dc2f1dbScgd 		el->el_line.lastchar -= num;
1396dc2f1dbScgd 	}
1406dc2f1dbScgd }
1416dc2f1dbScgd 
1426dc2f1dbScgd 
1436360c4b0Smycroft /* c_delafter1():
1446360c4b0Smycroft  *	Delete the character after the cursor, do not yank
1456360c4b0Smycroft  */
146a2d6b270Schristos libedit_private void
c_delafter1(EditLine * el)1476360c4b0Smycroft c_delafter1(EditLine *el)
1486360c4b0Smycroft {
1490594af80Schristos 	wchar_t *cp;
1506360c4b0Smycroft 
1516360c4b0Smycroft 	for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
1526360c4b0Smycroft 		*cp = cp[1];
1536360c4b0Smycroft 
1546360c4b0Smycroft 	el->el_line.lastchar--;
1556360c4b0Smycroft }
1566360c4b0Smycroft 
1576360c4b0Smycroft 
1586dc2f1dbScgd /* c_delbefore():
1596dc2f1dbScgd  *	Delete num characters before the cursor
1606dc2f1dbScgd  */
161a2d6b270Schristos libedit_private void
c_delbefore(EditLine * el,int num)162d30d584aSlukem c_delbefore(EditLine *el, int num)
1636dc2f1dbScgd {
1646dc2f1dbScgd 
1656dc2f1dbScgd 	if (el->el_line.cursor - num < el->el_line.buffer)
1665c894153Schristos 		num = (int)(el->el_line.cursor - el->el_line.buffer);
1676dc2f1dbScgd 
16839f224afSchristos 	if (el->el_map.current != el->el_map.emacs) {
16939f224afSchristos 		cv_undo(el);
17039f224afSchristos 		cv_yank(el, el->el_line.cursor - num, num);
17139f224afSchristos 	}
172a17c7fe4Schristos 
1736dc2f1dbScgd 	if (num > 0) {
1740594af80Schristos 		wchar_t *cp;
1756dc2f1dbScgd 
176d30d584aSlukem 		for (cp = el->el_line.cursor - num;
17738ee0c7eSchristos 		    &cp[num] <= el->el_line.lastchar;
178d30d584aSlukem 		    cp++)
1796dc2f1dbScgd 			*cp = cp[num];
1806dc2f1dbScgd 
1816dc2f1dbScgd 		el->el_line.lastchar -= num;
1826dc2f1dbScgd 	}
1836dc2f1dbScgd }
1846dc2f1dbScgd 
1856dc2f1dbScgd 
1866360c4b0Smycroft /* c_delbefore1():
1876360c4b0Smycroft  *	Delete the character before the cursor, do not yank
1886360c4b0Smycroft  */
189a2d6b270Schristos libedit_private void
c_delbefore1(EditLine * el)1906360c4b0Smycroft c_delbefore1(EditLine *el)
1916360c4b0Smycroft {
1920594af80Schristos 	wchar_t *cp;
1936360c4b0Smycroft 
1946360c4b0Smycroft 	for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
1956360c4b0Smycroft 		*cp = cp[1];
1966360c4b0Smycroft 
1976360c4b0Smycroft 	el->el_line.lastchar--;
1986360c4b0Smycroft }
1996360c4b0Smycroft 
2006360c4b0Smycroft 
2016dc2f1dbScgd /* ce__isword():
2026dc2f1dbScgd  *	Return if p is part of a word according to emacs
2036dc2f1dbScgd  */
204a2d6b270Schristos libedit_private int
ce__isword(wint_t p)205f54e4f97Schristos ce__isword(wint_t p)
2066dc2f1dbScgd {
2070aefc7f9Schristos 	return iswalnum(p) || wcschr(L"*?_-.[]~=", p) != NULL;
2086dc2f1dbScgd }
2096dc2f1dbScgd 
2106dc2f1dbScgd 
2116dc2f1dbScgd /* cv__isword():
2126dc2f1dbScgd  *	Return if p is part of a word according to vi
2136dc2f1dbScgd  */
214a2d6b270Schristos libedit_private int
cv__isword(wint_t p)215f54e4f97Schristos cv__isword(wint_t p)
2166dc2f1dbScgd {
217fcf85103Schristos 	if (iswalnum(p) || p == L'_')
21839f224afSchristos 		return 1;
219fcf85103Schristos 	if (iswgraph(p))
22039f224afSchristos 		return 2;
22139f224afSchristos 	return 0;
222a17c7fe4Schristos }
223a17c7fe4Schristos 
224a17c7fe4Schristos 
225a17c7fe4Schristos /* cv__isWord():
226a17c7fe4Schristos  *	Return if p is part of a big word according to vi
227a17c7fe4Schristos  */
228a2d6b270Schristos libedit_private int
cv__isWord(wint_t p)229f54e4f97Schristos cv__isWord(wint_t p)
230a17c7fe4Schristos {
231fcf85103Schristos 	return !iswspace(p);
2326dc2f1dbScgd }
2336dc2f1dbScgd 
2346dc2f1dbScgd 
2356dc2f1dbScgd /* c__prev_word():
2366dc2f1dbScgd  *	Find the previous word
2376dc2f1dbScgd  */
238a2d6b270Schristos libedit_private wchar_t *
c__prev_word(wchar_t * p,wchar_t * low,int n,int (* wtest)(wint_t))2390594af80Schristos c__prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
2406dc2f1dbScgd {
2416dc2f1dbScgd 	p--;
2426dc2f1dbScgd 
2436dc2f1dbScgd 	while (n--) {
24434e53048Schristos 		while ((p >= low) && !(*wtest)(*p))
2456dc2f1dbScgd 			p--;
24634e53048Schristos 		while ((p >= low) && (*wtest)(*p))
2476dc2f1dbScgd 			p--;
2486dc2f1dbScgd 	}
2496dc2f1dbScgd 
2506dc2f1dbScgd 	/* cp now points to one character before the word */
2516dc2f1dbScgd 	p++;
2526dc2f1dbScgd 	if (p < low)
2536dc2f1dbScgd 		p = low;
2546dc2f1dbScgd 	/* cp now points where we want it */
255b71bed95Schristos 	return p;
2566dc2f1dbScgd }
2576dc2f1dbScgd 
2586dc2f1dbScgd 
2596dc2f1dbScgd /* c__next_word():
2606dc2f1dbScgd  *	Find the next word
2616dc2f1dbScgd  */
262a2d6b270Schristos libedit_private wchar_t *
c__next_word(wchar_t * p,wchar_t * high,int n,int (* wtest)(wint_t))2630594af80Schristos c__next_word(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
2646dc2f1dbScgd {
2656dc2f1dbScgd 	while (n--) {
26634e53048Schristos 		while ((p < high) && !(*wtest)(*p))
2676dc2f1dbScgd 			p++;
26834e53048Schristos 		while ((p < high) && (*wtest)(*p))
2696dc2f1dbScgd 			p++;
2706dc2f1dbScgd 	}
2716dc2f1dbScgd 	if (p > high)
2726dc2f1dbScgd 		p = high;
2736dc2f1dbScgd 	/* p now points where we want it */
274b71bed95Schristos 	return p;
2756dc2f1dbScgd }
2766dc2f1dbScgd 
2776dc2f1dbScgd /* cv_next_word():
2786dc2f1dbScgd  *	Find the next word vi style
2796dc2f1dbScgd  */
280a2d6b270Schristos libedit_private wchar_t *
cv_next_word(EditLine * el,wchar_t * p,wchar_t * high,int n,int (* wtest)(wint_t))2810594af80Schristos cv_next_word(EditLine *el, wchar_t *p, wchar_t *high, int n,
2820594af80Schristos     int (*wtest)(wint_t))
2836dc2f1dbScgd {
2846dc2f1dbScgd 	int test;
2856dc2f1dbScgd 
2866dc2f1dbScgd 	while (n--) {
28734e53048Schristos 		test = (*wtest)(*p);
28834e53048Schristos 		while ((p < high) && (*wtest)(*p) == test)
2896dc2f1dbScgd 			p++;
2906dc2f1dbScgd 		/*
2916dc2f1dbScgd 		 * vi historically deletes with cw only the word preserving the
2926dc2f1dbScgd 		 * trailing whitespace! This is not what 'w' does..
2936dc2f1dbScgd 		 */
294a17c7fe4Schristos 		if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
295fcf85103Schristos 			while ((p < high) && iswspace(*p))
2966dc2f1dbScgd 				p++;
2976dc2f1dbScgd 	}
2986dc2f1dbScgd 
2996dc2f1dbScgd 	/* p now points where we want it */
3006dc2f1dbScgd 	if (p > high)
301b71bed95Schristos 		return high;
3026dc2f1dbScgd 	else
303b71bed95Schristos 		return p;
3046dc2f1dbScgd }
3056dc2f1dbScgd 
3066dc2f1dbScgd 
3076dc2f1dbScgd /* cv_prev_word():
3086dc2f1dbScgd  *	Find the previous word vi style
3096dc2f1dbScgd  */
310a2d6b270Schristos libedit_private wchar_t *
cv_prev_word(wchar_t * p,wchar_t * low,int n,int (* wtest)(wint_t))3110594af80Schristos cv_prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
3126dc2f1dbScgd {
3136dc2f1dbScgd 	int test;
3146dc2f1dbScgd 
3156dc2f1dbScgd 	p--;
316a17c7fe4Schristos 	while (n--) {
317fcf85103Schristos 		while ((p > low) && iswspace(*p))
3186dc2f1dbScgd 			p--;
31934e53048Schristos 		test = (*wtest)(*p);
32034e53048Schristos 		while ((p >= low) && (*wtest)(*p) == test)
3216dc2f1dbScgd 			p--;
322*62c70a72Schristos 		if (p < low)
323*62c70a72Schristos 			return low;
3246dc2f1dbScgd 	}
325a17c7fe4Schristos 	p++;
3266dc2f1dbScgd 
3276dc2f1dbScgd 	/* p now points where we want it */
3286dc2f1dbScgd 	if (p < low)
329b71bed95Schristos 		return low;
3306dc2f1dbScgd 	else
331b71bed95Schristos 		return p;
3326dc2f1dbScgd }
3336dc2f1dbScgd 
3346dc2f1dbScgd 
3356dc2f1dbScgd /* cv_delfini():
3366dc2f1dbScgd  *	Finish vi delete action
3376dc2f1dbScgd  */
338a2d6b270Schristos libedit_private void
cv_delfini(EditLine * el)339d30d584aSlukem cv_delfini(EditLine *el)
3406dc2f1dbScgd {
3410b7831a3Sperry 	int size;
34239f224afSchristos 	int action = el->el_chared.c_vcmd.action;
3436dc2f1dbScgd 
34439f224afSchristos 	if (action & INSERT)
3456dc2f1dbScgd 		el->el_map.current = el->el_map.key;
3466dc2f1dbScgd 
3476dc2f1dbScgd 	if (el->el_chared.c_vcmd.pos == 0)
34839f224afSchristos 		/* sanity */
3496dc2f1dbScgd 		return;
3506dc2f1dbScgd 
3515c894153Schristos 	size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos);
35239f224afSchristos 	if (size == 0)
35339f224afSchristos 		size = 1;
3546dc2f1dbScgd 	el->el_line.cursor = el->el_chared.c_vcmd.pos;
35539f224afSchristos 	if (action & YANK) {
35639f224afSchristos 		if (size > 0)
35739f224afSchristos 			cv_yank(el, el->el_line.cursor, size);
35839f224afSchristos 		else
35939f224afSchristos 			cv_yank(el, el->el_line.cursor + size, -size);
36039f224afSchristos 	} else {
361a17c7fe4Schristos 		if (size > 0) {
362a17c7fe4Schristos 			c_delafter(el, size);
3636dc2f1dbScgd 			re_refresh_cursor(el);
36439f224afSchristos 		} else  {
365a17c7fe4Schristos 			c_delbefore(el, -size);
366a17c7fe4Schristos 			el->el_line.cursor += size;
3676dc2f1dbScgd 		}
3686dc2f1dbScgd 	}
36939f224afSchristos 	el->el_chared.c_vcmd.action = NOP;
37039f224afSchristos }
3716dc2f1dbScgd 
3726dc2f1dbScgd 
3736dc2f1dbScgd /* cv__endword():
3746dc2f1dbScgd  *	Go to the end of this word according to vi
3756dc2f1dbScgd  */
376a2d6b270Schristos libedit_private wchar_t *
cv__endword(wchar_t * p,wchar_t * high,int n,int (* wtest)(wint_t))3770594af80Schristos cv__endword(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
3786dc2f1dbScgd {
379a17c7fe4Schristos 	int test;
380a17c7fe4Schristos 
3816dc2f1dbScgd 	p++;
3826dc2f1dbScgd 
3836dc2f1dbScgd 	while (n--) {
384fcf85103Schristos 		while ((p < high) && iswspace(*p))
3856dc2f1dbScgd 			p++;
3866dc2f1dbScgd 
38734e53048Schristos 		test = (*wtest)(*p);
38834e53048Schristos 		while ((p < high) && (*wtest)(*p) == test)
3896dc2f1dbScgd 			p++;
3906dc2f1dbScgd 	}
3916dc2f1dbScgd 	p--;
392b71bed95Schristos 	return p;
3936dc2f1dbScgd }
3946dc2f1dbScgd 
3956dc2f1dbScgd /* ch_init():
3966dc2f1dbScgd  *	Initialize the character editor
3976dc2f1dbScgd  */
398a2d6b270Schristos libedit_private int
ch_init(EditLine * el)399d30d584aSlukem ch_init(EditLine *el)
4006dc2f1dbScgd {
401113f06a3Schristos 	el->el_line.buffer		= el_calloc(EL_BUFSIZ,
40234e53048Schristos 	    sizeof(*el->el_line.buffer));
4032f3389ceSchristos 	if (el->el_line.buffer == NULL)
404b71bed95Schristos 		return -1;
4052f3389ceSchristos 
4066dc2f1dbScgd 	el->el_line.cursor		= el->el_line.buffer;
4076dc2f1dbScgd 	el->el_line.lastchar		= el->el_line.buffer;
408a17c7fe4Schristos 	el->el_line.limit		= &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
4096dc2f1dbScgd 
410113f06a3Schristos 	el->el_chared.c_undo.buf	= el_calloc(EL_BUFSIZ,
41134e53048Schristos 	    sizeof(*el->el_chared.c_undo.buf));
4122f3389ceSchristos 	if (el->el_chared.c_undo.buf == NULL)
413b71bed95Schristos 		return -1;
414a17c7fe4Schristos 	el->el_chared.c_undo.len	= -1;
415a17c7fe4Schristos 	el->el_chared.c_undo.cursor	= 0;
416113f06a3Schristos 	el->el_chared.c_redo.buf	= el_calloc(EL_BUFSIZ,
41734e53048Schristos 	    sizeof(*el->el_chared.c_redo.buf));
41839f224afSchristos 	if (el->el_chared.c_redo.buf == NULL)
41921a4b1ccSchristos 		goto out;
42039f224afSchristos 	el->el_chared.c_redo.pos	= el->el_chared.c_redo.buf;
42139f224afSchristos 	el->el_chared.c_redo.lim	= el->el_chared.c_redo.buf + EL_BUFSIZ;
42239f224afSchristos 	el->el_chared.c_redo.cmd	= ED_UNASSIGNED;
4236dc2f1dbScgd 
4246dc2f1dbScgd 	el->el_chared.c_vcmd.action	= NOP;
4256dc2f1dbScgd 	el->el_chared.c_vcmd.pos	= el->el_line.buffer;
4266dc2f1dbScgd 
427113f06a3Schristos 	el->el_chared.c_kill.buf	= el_calloc(EL_BUFSIZ,
42834e53048Schristos 	    sizeof(*el->el_chared.c_kill.buf));
4292f3389ceSchristos 	if (el->el_chared.c_kill.buf == NULL)
43021a4b1ccSchristos 		goto out;
4316dc2f1dbScgd 	el->el_chared.c_kill.mark	= el->el_line.buffer;
4326dc2f1dbScgd 	el->el_chared.c_kill.last	= el->el_chared.c_kill.buf;
4337741aae9Schristos 	el->el_chared.c_resizefun	= NULL;
4347741aae9Schristos 	el->el_chared.c_resizearg	= NULL;
435e06822a7Schristos 	el->el_chared.c_aliasfun	= NULL;
436e06822a7Schristos 	el->el_chared.c_aliasarg	= NULL;
4376dc2f1dbScgd 
4386dc2f1dbScgd 	el->el_map.current		= el->el_map.key;
4396dc2f1dbScgd 
4406dc2f1dbScgd 	el->el_state.inputmode		= MODE_INSERT; /* XXX: save a default */
4416dc2f1dbScgd 	el->el_state.doingarg		= 0;
4426dc2f1dbScgd 	el->el_state.metanext		= 0;
4436dc2f1dbScgd 	el->el_state.argument		= 1;
4446dc2f1dbScgd 	el->el_state.lastcmd		= ED_UNASSIGNED;
4456dc2f1dbScgd 
446b71bed95Schristos 	return 0;
44721a4b1ccSchristos out:
44821a4b1ccSchristos 	ch_end(el);
44921a4b1ccSchristos 	return -1;
4506dc2f1dbScgd }
4516dc2f1dbScgd 
4526dc2f1dbScgd /* ch_reset():
4536dc2f1dbScgd  *	Reset the character editor
4546dc2f1dbScgd  */
455a2d6b270Schristos libedit_private void
ch_reset(EditLine * el)456bb64d9f1Schristos ch_reset(EditLine *el)
4576dc2f1dbScgd {
4586dc2f1dbScgd 	el->el_line.cursor		= el->el_line.buffer;
4596dc2f1dbScgd 	el->el_line.lastchar		= el->el_line.buffer;
4606dc2f1dbScgd 
461a17c7fe4Schristos 	el->el_chared.c_undo.len	= -1;
462a17c7fe4Schristos 	el->el_chared.c_undo.cursor	= 0;
4636dc2f1dbScgd 
4646dc2f1dbScgd 	el->el_chared.c_vcmd.action	= NOP;
4656dc2f1dbScgd 	el->el_chared.c_vcmd.pos	= el->el_line.buffer;
4666dc2f1dbScgd 
4676dc2f1dbScgd 	el->el_chared.c_kill.mark	= el->el_line.buffer;
4686dc2f1dbScgd 
4696dc2f1dbScgd 	el->el_map.current		= el->el_map.key;
4706dc2f1dbScgd 
4716dc2f1dbScgd 	el->el_state.inputmode		= MODE_INSERT; /* XXX: save a default */
4726dc2f1dbScgd 	el->el_state.doingarg		= 0;
4736dc2f1dbScgd 	el->el_state.metanext		= 0;
4746dc2f1dbScgd 	el->el_state.argument		= 1;
4756dc2f1dbScgd 	el->el_state.lastcmd		= ED_UNASSIGNED;
4766dc2f1dbScgd 
47776b5907bSchristos 	el->el_history.eventno		= 0;
4786dc2f1dbScgd }
4796dc2f1dbScgd 
48000ff7cacSjdolecek /* ch_enlargebufs():
48100ff7cacSjdolecek  *	Enlarge line buffer to be able to hold twice as much characters.
48200ff7cacSjdolecek  *	Returns 1 if successful, 0 if not.
48300ff7cacSjdolecek  */
484a2d6b270Schristos libedit_private int
ch_enlargebufs(EditLine * el,size_t addlen)4855c894153Schristos ch_enlargebufs(EditLine *el, size_t addlen)
48600ff7cacSjdolecek {
4875e45b51aSlukem 	size_t sz, newsz;
4880594af80Schristos 	wchar_t *newbuffer, *oldbuf, *oldkbuf;
48900ff7cacSjdolecek 
4903d802cf5Schristos 	sz = (size_t)(el->el_line.limit - el->el_line.buffer + EL_LEAVE);
4915e45b51aSlukem 	newsz = sz * 2;
49200ff7cacSjdolecek 	/*
49300ff7cacSjdolecek 	 * If newly required length is longer than current buffer, we need
49400ff7cacSjdolecek 	 * to make the buffer big enough to hold both old and new stuff.
49500ff7cacSjdolecek 	 */
49600ff7cacSjdolecek 	if (addlen > sz) {
49700ff7cacSjdolecek 		while(newsz - sz < addlen)
49800ff7cacSjdolecek 			newsz *= 2;
49900ff7cacSjdolecek 	}
50000ff7cacSjdolecek 
50100ff7cacSjdolecek 	/*
50200ff7cacSjdolecek 	 * Reallocate line buffer.
50300ff7cacSjdolecek 	 */
50434e53048Schristos 	newbuffer = el_realloc(el->el_line.buffer, newsz * sizeof(*newbuffer));
50500ff7cacSjdolecek 	if (!newbuffer)
50600ff7cacSjdolecek 		return 0;
50700ff7cacSjdolecek 
50800ff7cacSjdolecek 	/* zero the newly added memory, leave old data in */
50934e53048Schristos 	(void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
51000ff7cacSjdolecek 
51100ff7cacSjdolecek 	oldbuf = el->el_line.buffer;
51200ff7cacSjdolecek 
51300ff7cacSjdolecek 	el->el_line.buffer = newbuffer;
51400ff7cacSjdolecek 	el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
51500ff7cacSjdolecek 	el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
516a17c7fe4Schristos 	/* don't set new size until all buffers are enlarged */
517a17c7fe4Schristos 	el->el_line.limit  = &newbuffer[sz - EL_LEAVE];
51800ff7cacSjdolecek 
51900ff7cacSjdolecek 	/*
52000ff7cacSjdolecek 	 * Reallocate kill buffer.
52100ff7cacSjdolecek 	 */
522a13cd756Schristos 	newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz *
523a13cd756Schristos 	    sizeof(*newbuffer));
52400ff7cacSjdolecek 	if (!newbuffer)
52500ff7cacSjdolecek 		return 0;
52600ff7cacSjdolecek 
52700ff7cacSjdolecek 	/* zero the newly added memory, leave old data in */
52834e53048Schristos 	(void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
52900ff7cacSjdolecek 
53000ff7cacSjdolecek 	oldkbuf = el->el_chared.c_kill.buf;
53100ff7cacSjdolecek 
53200ff7cacSjdolecek 	el->el_chared.c_kill.buf = newbuffer;
53300ff7cacSjdolecek 	el->el_chared.c_kill.last = newbuffer +
53400ff7cacSjdolecek 					(el->el_chared.c_kill.last - oldkbuf);
53500ff7cacSjdolecek 	el->el_chared.c_kill.mark = el->el_line.buffer +
53600ff7cacSjdolecek 					(el->el_chared.c_kill.mark - oldbuf);
53700ff7cacSjdolecek 
53800ff7cacSjdolecek 	/*
53900ff7cacSjdolecek 	 * Reallocate undo buffer.
54000ff7cacSjdolecek 	 */
54134e53048Schristos 	newbuffer = el_realloc(el->el_chared.c_undo.buf,
54234e53048Schristos 	    newsz * sizeof(*newbuffer));
54300ff7cacSjdolecek 	if (!newbuffer)
54400ff7cacSjdolecek 		return 0;
54500ff7cacSjdolecek 
54600ff7cacSjdolecek 	/* zero the newly added memory, leave old data in */
54734e53048Schristos 	(void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
54800ff7cacSjdolecek 	el->el_chared.c_undo.buf = newbuffer;
54900ff7cacSjdolecek 
55034e53048Schristos 	newbuffer = el_realloc(el->el_chared.c_redo.buf,
55134e53048Schristos 	    newsz * sizeof(*newbuffer));
552a17c7fe4Schristos 	if (!newbuffer)
553a17c7fe4Schristos 		return 0;
55439f224afSchristos 	el->el_chared.c_redo.pos = newbuffer +
55539f224afSchristos 			(el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
55639f224afSchristos 	el->el_chared.c_redo.lim = newbuffer +
55739f224afSchristos 			(el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
55839f224afSchristos 	el->el_chared.c_redo.buf = newbuffer;
559a17c7fe4Schristos 
56000ff7cacSjdolecek 	if (!hist_enlargebuf(el, sz, newsz))
56100ff7cacSjdolecek 		return 0;
56200ff7cacSjdolecek 
563a17c7fe4Schristos 	/* Safe to set enlarged buffer size */
56462a5c8a6Schristos 	el->el_line.limit  = &el->el_line.buffer[newsz - EL_LEAVE];
5657741aae9Schristos 	if (el->el_chared.c_resizefun)
5667741aae9Schristos 		(*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg);
56700ff7cacSjdolecek 	return 1;
56800ff7cacSjdolecek }
5696dc2f1dbScgd 
5706dc2f1dbScgd /* ch_end():
5716dc2f1dbScgd  *	Free the data structures used by the editor
5726dc2f1dbScgd  */
573a2d6b270Schristos libedit_private void
ch_end(EditLine * el)574d30d584aSlukem ch_end(EditLine *el)
5756dc2f1dbScgd {
576a13cd756Schristos 	el_free(el->el_line.buffer);
5776dc2f1dbScgd 	el->el_line.buffer = NULL;
5786dc2f1dbScgd 	el->el_line.limit = NULL;
579a13cd756Schristos 	el_free(el->el_chared.c_undo.buf);
5806dc2f1dbScgd 	el->el_chared.c_undo.buf = NULL;
581a13cd756Schristos 	el_free(el->el_chared.c_redo.buf);
58239f224afSchristos 	el->el_chared.c_redo.buf = NULL;
58339f224afSchristos 	el->el_chared.c_redo.pos = NULL;
58439f224afSchristos 	el->el_chared.c_redo.lim = NULL;
58539f224afSchristos 	el->el_chared.c_redo.cmd = ED_UNASSIGNED;
586a13cd756Schristos 	el_free(el->el_chared.c_kill.buf);
5876dc2f1dbScgd 	el->el_chared.c_kill.buf = NULL;
588bb64d9f1Schristos 	ch_reset(el);
5896dc2f1dbScgd }
5906dc2f1dbScgd 
5916dc2f1dbScgd 
5926dc2f1dbScgd /* el_insertstr():
593cf2b6f69Sabhinav  *	Insert string at cursor
5946dc2f1dbScgd  */
595469d44f8Schristos int
el_winsertstr(EditLine * el,const wchar_t * s)5960594af80Schristos el_winsertstr(EditLine *el, const wchar_t *s)
5976dc2f1dbScgd {
59893819542Schristos 	size_t len;
5996dc2f1dbScgd 
6000aefc7f9Schristos 	if (s == NULL || (len = wcslen(s)) == 0)
601b71bed95Schristos 		return -1;
60200ff7cacSjdolecek 	if (el->el_line.lastchar + len >= el->el_line.limit) {
60300ff7cacSjdolecek 		if (!ch_enlargebufs(el, len))
604b71bed95Schristos 			return -1;
60500ff7cacSjdolecek 	}
6066dc2f1dbScgd 
60793819542Schristos 	c_insert(el, (int)len);
6086dc2f1dbScgd 	while (*s)
6096dc2f1dbScgd 		*el->el_line.cursor++ = *s++;
610b71bed95Schristos 	return 0;
6116dc2f1dbScgd }
6126dc2f1dbScgd 
6136dc2f1dbScgd 
6146dc2f1dbScgd /* el_deletestr():
6156dc2f1dbScgd  *	Delete num characters before the cursor
6166dc2f1dbScgd  */
617469d44f8Schristos void
el_deletestr(EditLine * el,int n)618d30d584aSlukem el_deletestr(EditLine *el, int n)
6196dc2f1dbScgd {
6206dc2f1dbScgd 	if (n <= 0)
6216dc2f1dbScgd 		return;
6226dc2f1dbScgd 
6236dc2f1dbScgd 	if (el->el_line.cursor < &el->el_line.buffer[n])
6246dc2f1dbScgd 		return;
6256dc2f1dbScgd 
6266dc2f1dbScgd 	c_delbefore(el, n);		/* delete before dot */
6276dc2f1dbScgd 	el->el_line.cursor -= n;
6286dc2f1dbScgd 	if (el->el_line.cursor < el->el_line.buffer)
6296dc2f1dbScgd 		el->el_line.cursor = el->el_line.buffer;
6306dc2f1dbScgd }
6316dc2f1dbScgd 
632001f54a4Schristos /* el_deletestr1():
63365744508Srillig  *	Delete characters between start and end
634001f54a4Schristos  */
635001f54a4Schristos int
el_deletestr1(EditLine * el,int start,int end)636001f54a4Schristos el_deletestr1(EditLine *el, int start, int end)
637001f54a4Schristos {
63865744508Srillig 	size_t line_length, len;
639001f54a4Schristos 	wchar_t *p1, *p2;
640001f54a4Schristos 
641001f54a4Schristos 	if (end <= start)
642001f54a4Schristos 		return 0;
643001f54a4Schristos 
64465744508Srillig 	line_length = (size_t)(el->el_line.lastchar - el->el_line.buffer);
645001f54a4Schristos 
64665744508Srillig 	if (start >= (int)line_length || end >= (int)line_length)
647001f54a4Schristos 		return 0;
648001f54a4Schristos 
649001f54a4Schristos 	len = (size_t)(end - start);
65065744508Srillig 	if (len > line_length - (size_t)end)
65165744508Srillig 		len = line_length - (size_t)end;
652001f54a4Schristos 
653001f54a4Schristos 	p1 = el->el_line.buffer + start;
654001f54a4Schristos 	p2 = el->el_line.buffer + end;
655001f54a4Schristos 	for (size_t i = 0; i < len; i++) {
656001f54a4Schristos 		*p1++ = *p2++;
657001f54a4Schristos 		el->el_line.lastchar--;
658001f54a4Schristos 	}
659001f54a4Schristos 
660001f54a4Schristos 	if (el->el_line.cursor < el->el_line.buffer)
661001f54a4Schristos 		el->el_line.cursor = el->el_line.buffer;
662001f54a4Schristos 
663001f54a4Schristos 	return end - start;
664001f54a4Schristos }
665001f54a4Schristos 
666b7e56637Schristos /* el_wreplacestr():
667b7e56637Schristos  *	Replace the contents of the line with the provided string
668b7e56637Schristos  */
669b7e56637Schristos int
el_wreplacestr(EditLine * el,const wchar_t * s)670b7e56637Schristos el_wreplacestr(EditLine *el, const wchar_t *s)
671b7e56637Schristos {
672b7e56637Schristos 	size_t len;
673b7e56637Schristos 	wchar_t * p;
674b7e56637Schristos 
675b7e56637Schristos 	if (s == NULL || (len = wcslen(s)) == 0)
676b7e56637Schristos 		return -1;
677b7e56637Schristos 
678b7e56637Schristos 	if (el->el_line.buffer + len >= el->el_line.limit) {
679b7e56637Schristos 		if (!ch_enlargebufs(el, len))
680b7e56637Schristos 			return -1;
681b7e56637Schristos 	}
682b7e56637Schristos 
683b7e56637Schristos 	p = el->el_line.buffer;
684b7e56637Schristos 	for (size_t i = 0; i < len; i++)
685b7e56637Schristos 		*p++ = *s++;
686b7e56637Schristos 
687b7e56637Schristos 	el->el_line.buffer[len] = '\0';
688b7e56637Schristos 	el->el_line.lastchar = el->el_line.buffer + len;
689b7e56637Schristos 	if (el->el_line.cursor > el->el_line.lastchar)
690b7e56637Schristos 		el->el_line.cursor = el->el_line.lastchar;
691b7e56637Schristos 
692b7e56637Schristos 	return 0;
693b7e56637Schristos }
694b7e56637Schristos 
695255f657eSchristos /* el_cursor():
696255f657eSchristos  *	Move the cursor to the left or the right of the current position
697255f657eSchristos  */
698469d44f8Schristos int
el_cursor(EditLine * el,int n)699255f657eSchristos el_cursor(EditLine *el, int n)
700255f657eSchristos {
701255f657eSchristos 	if (n == 0)
702255f657eSchristos 		goto out;
703255f657eSchristos 
704255f657eSchristos 	el->el_line.cursor += n;
705255f657eSchristos 
706255f657eSchristos 	if (el->el_line.cursor < el->el_line.buffer)
707255f657eSchristos 		el->el_line.cursor = el->el_line.buffer;
708255f657eSchristos 	if (el->el_line.cursor > el->el_line.lastchar)
709255f657eSchristos 		el->el_line.cursor = el->el_line.lastchar;
710255f657eSchristos out:
71153fbf029Schristos 	return (int)(el->el_line.cursor - el->el_line.buffer);
712255f657eSchristos }
713255f657eSchristos 
7146dc2f1dbScgd /* c_gets():
7156dc2f1dbScgd  *	Get a string
7166dc2f1dbScgd  */
717a2d6b270Schristos libedit_private int
c_gets(EditLine * el,wchar_t * buf,const wchar_t * prompt)7180594af80Schristos c_gets(EditLine *el, wchar_t *buf, const wchar_t *prompt)
7196dc2f1dbScgd {
7205c894153Schristos 	ssize_t len;
7210594af80Schristos 	wchar_t *cp = el->el_line.buffer, ch;
7226dc2f1dbScgd 
7234a97685cSchristos 	if (prompt) {
7240aefc7f9Schristos 		len = (ssize_t)wcslen(prompt);
7253d802cf5Schristos 		(void)memcpy(cp, prompt, (size_t)len * sizeof(*cp));
7264a97685cSchristos 		cp += len;
7274a97685cSchristos 	}
7284a97685cSchristos 	len = 0;
7294a97685cSchristos 
7304a97685cSchristos 	for (;;) {
7314a97685cSchristos 		el->el_line.cursor = cp;
7324a97685cSchristos 		*cp = ' ';
7334a97685cSchristos 		el->el_line.lastchar = cp + 1;
7344a97685cSchristos 		re_refresh(el);
7354a97685cSchristos 
7360594af80Schristos 		if (el_wgetc(el, &ch) != 1) {
7374a97685cSchristos 			ed_end_of_file(el, 0);
7384a97685cSchristos 			len = -1;
7394a97685cSchristos 			break;
7404a97685cSchristos 		}
7414a97685cSchristos 
7426dc2f1dbScgd 		switch (ch) {
7434a97685cSchristos 
7447ba8c71bSchristos 		case L'\b':	/* Delete and backspace */
7456dc2f1dbScgd 		case 0177:
7465c894153Schristos 			if (len == 0) {
7474a97685cSchristos 				len = -1;
7486dc2f1dbScgd 				break;
7494a97685cSchristos 			}
7505f47d9bdSchristos 			len--;
7514a97685cSchristos 			cp--;
7524a97685cSchristos 			continue;
7536dc2f1dbScgd 
7546dc2f1dbScgd 		case 0033:	/* ESC */
7557ba8c71bSchristos 		case L'\r':	/* Newline */
7567ba8c71bSchristos 		case L'\n':
7574a97685cSchristos 			buf[len] = ch;
7586dc2f1dbScgd 			break;
7596dc2f1dbScgd 
7606dc2f1dbScgd 		default:
761c11bd863Schristos 			if (len >= (ssize_t)(EL_BUFSIZ - 16))
76298c7cbebSchristos 				terminal_beep(el);
7636dc2f1dbScgd 			else {
7646dc2f1dbScgd 				buf[len++] = ch;
7654a97685cSchristos 				*cp++ = ch;
7666dc2f1dbScgd 			}
7674a97685cSchristos 			continue;
7684a97685cSchristos 		}
7696dc2f1dbScgd 		break;
7706dc2f1dbScgd 	}
7714a97685cSchristos 
7724a97685cSchristos 	el->el_line.buffer[0] = '\0';
7734a97685cSchristos 	el->el_line.lastchar = el->el_line.buffer;
7744a97685cSchristos 	el->el_line.cursor = el->el_line.buffer;
7755c894153Schristos 	return (int)len;
7766dc2f1dbScgd }
7776dc2f1dbScgd 
7786dc2f1dbScgd 
7796dc2f1dbScgd /* c_hpos():
7806dc2f1dbScgd  *	Return the current horizontal position of the cursor
7816dc2f1dbScgd  */
782a2d6b270Schristos libedit_private int
c_hpos(EditLine * el)783d30d584aSlukem c_hpos(EditLine *el)
7846dc2f1dbScgd {
7850594af80Schristos 	wchar_t *ptr;
7866dc2f1dbScgd 
7876dc2f1dbScgd 	/*
7886dc2f1dbScgd 	 * Find how many characters till the beginning of this line.
7896dc2f1dbScgd 	 */
7906dc2f1dbScgd 	if (el->el_line.cursor == el->el_line.buffer)
791b71bed95Schristos 		return 0;
7926dc2f1dbScgd 	else {
7936dc2f1dbScgd 		for (ptr = el->el_line.cursor - 1;
7946dc2f1dbScgd 		     ptr >= el->el_line.buffer && *ptr != '\n';
7956dc2f1dbScgd 		     ptr--)
7966dc2f1dbScgd 			continue;
7975c894153Schristos 		return (int)(el->el_line.cursor - ptr - 1);
7986dc2f1dbScgd 	}
7996dc2f1dbScgd }
8007741aae9Schristos 
801a2d6b270Schristos libedit_private int
ch_resizefun(EditLine * el,el_zfunc_t f,void * a)8027741aae9Schristos ch_resizefun(EditLine *el, el_zfunc_t f, void *a)
8037741aae9Schristos {
8047741aae9Schristos 	el->el_chared.c_resizefun = f;
8057741aae9Schristos 	el->el_chared.c_resizearg = a;
8067741aae9Schristos 	return 0;
8077741aae9Schristos }
808e06822a7Schristos 
809a2d6b270Schristos libedit_private int
ch_aliasfun(EditLine * el,el_afunc_t f,void * a)810e06822a7Schristos ch_aliasfun(EditLine *el, el_afunc_t f, void *a)
811e06822a7Schristos {
812e06822a7Schristos 	el->el_chared.c_aliasfun = f;
813e06822a7Schristos 	el->el_chared.c_aliasarg = a;
814e06822a7Schristos 	return 0;
815e06822a7Schristos }
816