xref: /openbsd-src/lib/libedit/chared.c (revision 7b6df1e236be9d0d76ed74eabe303425a43c91fc)
1*7b6df1e2Stb /*	$OpenBSD: chared.c,v 1.28 2017/04/12 18:24:37 tb Exp $	*/
2aed0ee81Snicm /*	$NetBSD: chared.c,v 1.28 2009/12/30 22:37:40 christos Exp $	*/
3babb851aSmillert 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1992, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Christos Zoulas of Cornell University.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
196580fee3Smillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36d484b7d0Sotto #include "config.h"
37df930be7Sderaadt 
38df930be7Sderaadt /*
39df930be7Sderaadt  * chared.c: Character editor utilities
40df930be7Sderaadt  */
417ccfa089Sschwarze #include <ctype.h>
42df930be7Sderaadt #include <stdlib.h>
437ccfa089Sschwarze #include <string.h>
445564fb94Sschwarze 
45df930be7Sderaadt #include "el.h"
465564fb94Sschwarze #include "common.h"
4713e01c7aSschwarze #include "fcns.h"
48df930be7Sderaadt 
49d484b7d0Sotto /* value to leave unused in line buffer */
50d484b7d0Sotto #define	EL_LEAVE	2
51d484b7d0Sotto 
52df930be7Sderaadt /* cv_undo():
53df930be7Sderaadt  *	Handle state for the vi undo command
54df930be7Sderaadt  */
55df930be7Sderaadt protected void
cv_undo(EditLine * el)56d484b7d0Sotto cv_undo(EditLine *el)
57df930be7Sderaadt {
58df930be7Sderaadt 	c_undo_t *vu = &el->el_chared.c_undo;
59d484b7d0Sotto 	c_redo_t *r = &el->el_chared.c_redo;
60aed0ee81Snicm 	size_t size;
61d484b7d0Sotto 
62d484b7d0Sotto 	/* Save entire line for undo */
63d484b7d0Sotto 	size = el->el_line.lastchar - el->el_line.buffer;
64d484b7d0Sotto 	vu->len = size;
65aed0ee81Snicm 	vu->cursor = (int)(el->el_line.cursor - el->el_line.buffer);
66aed0ee81Snicm 	(void)memcpy(vu->buf, el->el_line.buffer, size * sizeof(*vu->buf));
67d484b7d0Sotto 
68d484b7d0Sotto 	/* save command info for redo */
69d484b7d0Sotto 	r->count = el->el_state.doingarg ? el->el_state.argument : 0;
70d484b7d0Sotto 	r->action = el->el_chared.c_vcmd.action;
71d484b7d0Sotto 	r->pos = r->buf;
72d484b7d0Sotto 	r->cmd = el->el_state.thiscmd;
73d484b7d0Sotto 	r->ch = el->el_state.thisch;
74d484b7d0Sotto }
75d484b7d0Sotto 
76d484b7d0Sotto /* cv_yank():
77d484b7d0Sotto  *	Save yank/delete data for paste
78d484b7d0Sotto  */
79d484b7d0Sotto protected void
cv_yank(EditLine * el,const wchar_t * ptr,int size)80e3191321Sschwarze cv_yank(EditLine *el, const wchar_t *ptr, int size)
81d484b7d0Sotto {
82d484b7d0Sotto 	c_kill_t *k = &el->el_chared.c_kill;
83d484b7d0Sotto 
84aed0ee81Snicm 	(void)memcpy(k->buf, ptr, size * sizeof(*k->buf));
85d484b7d0Sotto 	k->last = k->buf + size;
86df930be7Sderaadt }
87df930be7Sderaadt 
88df930be7Sderaadt 
89df930be7Sderaadt /* c_insert():
90df930be7Sderaadt  *	Insert num characters
91df930be7Sderaadt  */
92df930be7Sderaadt protected void
c_insert(EditLine * el,int num)93d484b7d0Sotto c_insert(EditLine *el, int num)
94df930be7Sderaadt {
95e3191321Sschwarze 	wchar_t *cp;
96df930be7Sderaadt 
97d484b7d0Sotto 	if (el->el_line.lastchar + num >= el->el_line.limit) {
98aed0ee81Snicm 		if (!ch_enlargebufs(el, (size_t)num))
99df930be7Sderaadt 			return;		/* can't go past end of buffer */
100d484b7d0Sotto 	}
101df930be7Sderaadt 
102df930be7Sderaadt 	if (el->el_line.cursor < el->el_line.lastchar) {
103df930be7Sderaadt 		/* if I must move chars */
104df930be7Sderaadt 		for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
105df930be7Sderaadt 			cp[num] = *cp;
106df930be7Sderaadt 	}
107df930be7Sderaadt 	el->el_line.lastchar += num;
108d484b7d0Sotto }
109df930be7Sderaadt 
110df930be7Sderaadt 
111df930be7Sderaadt /* c_delafter():
112df930be7Sderaadt  *	Delete num characters after the cursor
113df930be7Sderaadt  */
114df930be7Sderaadt protected void
c_delafter(EditLine * el,int num)115d484b7d0Sotto c_delafter(EditLine *el, int num)
116df930be7Sderaadt {
117df930be7Sderaadt 
118df930be7Sderaadt 	if (el->el_line.cursor + num > el->el_line.lastchar)
119aed0ee81Snicm 		num = (int)(el->el_line.lastchar - el->el_line.cursor);
120df930be7Sderaadt 
121d484b7d0Sotto 	if (el->el_map.current != el->el_map.emacs) {
122d484b7d0Sotto 		cv_undo(el);
123d484b7d0Sotto 		cv_yank(el, el->el_line.cursor, num);
124d484b7d0Sotto 	}
125d484b7d0Sotto 
126df930be7Sderaadt 	if (num > 0) {
127e3191321Sschwarze 		wchar_t *cp;
128df930be7Sderaadt 
129df930be7Sderaadt 		for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
130df930be7Sderaadt 			*cp = cp[num];
131df930be7Sderaadt 
132df930be7Sderaadt 		el->el_line.lastchar -= num;
133df930be7Sderaadt 	}
134df930be7Sderaadt }
135df930be7Sderaadt 
136df930be7Sderaadt 
137aed0ee81Snicm /* c_delafter1():
138aed0ee81Snicm  *	Delete the character after the cursor, do not yank
139aed0ee81Snicm  */
140aed0ee81Snicm protected void
c_delafter1(EditLine * el)141aed0ee81Snicm c_delafter1(EditLine *el)
142aed0ee81Snicm {
143e3191321Sschwarze 	wchar_t *cp;
144aed0ee81Snicm 
145aed0ee81Snicm 	for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
146aed0ee81Snicm 		*cp = cp[1];
147aed0ee81Snicm 
148aed0ee81Snicm 	el->el_line.lastchar--;
149aed0ee81Snicm }
150aed0ee81Snicm 
151aed0ee81Snicm 
152df930be7Sderaadt /* c_delbefore():
153df930be7Sderaadt  *	Delete num characters before the cursor
154df930be7Sderaadt  */
155df930be7Sderaadt protected void
c_delbefore(EditLine * el,int num)156d484b7d0Sotto c_delbefore(EditLine *el, int num)
157df930be7Sderaadt {
158df930be7Sderaadt 
159df930be7Sderaadt 	if (el->el_line.cursor - num < el->el_line.buffer)
160aed0ee81Snicm 		num = (int)(el->el_line.cursor - el->el_line.buffer);
161df930be7Sderaadt 
162d484b7d0Sotto 	if (el->el_map.current != el->el_map.emacs) {
163d484b7d0Sotto 		cv_undo(el);
164d484b7d0Sotto 		cv_yank(el, el->el_line.cursor - num, num);
165d484b7d0Sotto 	}
166d484b7d0Sotto 
167df930be7Sderaadt 	if (num > 0) {
168e3191321Sschwarze 		wchar_t *cp;
169df930be7Sderaadt 
170d484b7d0Sotto 		for (cp = el->el_line.cursor - num;
171d484b7d0Sotto 		    cp <= el->el_line.lastchar;
172d484b7d0Sotto 		    cp++)
173df930be7Sderaadt 			*cp = cp[num];
174df930be7Sderaadt 
175df930be7Sderaadt 		el->el_line.lastchar -= num;
176df930be7Sderaadt 	}
177df930be7Sderaadt }
178df930be7Sderaadt 
179df930be7Sderaadt 
180aed0ee81Snicm /* c_delbefore1():
181aed0ee81Snicm  *	Delete the character before the cursor, do not yank
182aed0ee81Snicm  */
183aed0ee81Snicm protected void
c_delbefore1(EditLine * el)184aed0ee81Snicm c_delbefore1(EditLine *el)
185aed0ee81Snicm {
186e3191321Sschwarze 	wchar_t *cp;
187aed0ee81Snicm 
188aed0ee81Snicm 	for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++)
189aed0ee81Snicm 		*cp = cp[1];
190aed0ee81Snicm 
191aed0ee81Snicm 	el->el_line.lastchar--;
192aed0ee81Snicm }
193aed0ee81Snicm 
194aed0ee81Snicm 
195df930be7Sderaadt /* ce__isword():
196df930be7Sderaadt  *	Return if p is part of a word according to emacs
197df930be7Sderaadt  */
198df930be7Sderaadt protected int
ce__isword(wint_t p)199b2589f0bSschwarze ce__isword(wint_t p)
200df930be7Sderaadt {
2015c93237dSschwarze 	return iswalnum(p) || wcschr(L"*?_-.[]~=", p) != NULL;
202df930be7Sderaadt }
203df930be7Sderaadt 
204df930be7Sderaadt 
205df930be7Sderaadt /* cv__isword():
206df930be7Sderaadt  *	Return if p is part of a word according to vi
207df930be7Sderaadt  */
208df930be7Sderaadt protected int
cv__isword(wint_t p)209b2589f0bSschwarze cv__isword(wint_t p)
210df930be7Sderaadt {
211565aa7e8Sschwarze 	if (iswalnum(p) || p == L'_')
212d484b7d0Sotto 		return 1;
213565aa7e8Sschwarze 	if (iswgraph(p))
214d484b7d0Sotto 		return 2;
215d484b7d0Sotto 	return 0;
216d484b7d0Sotto }
217d484b7d0Sotto 
218d484b7d0Sotto 
219d484b7d0Sotto /* cv__isWord():
220d484b7d0Sotto  *	Return if p is part of a big word according to vi
221d484b7d0Sotto  */
222d484b7d0Sotto protected int
cv__isWord(wint_t p)223b2589f0bSschwarze cv__isWord(wint_t p)
224d484b7d0Sotto {
225565aa7e8Sschwarze 	return !iswspace(p);
226df930be7Sderaadt }
227df930be7Sderaadt 
228df930be7Sderaadt 
229df930be7Sderaadt /* c__prev_word():
230df930be7Sderaadt  *	Find the previous word
231df930be7Sderaadt  */
232e3191321Sschwarze protected wchar_t *
c__prev_word(wchar_t * p,wchar_t * low,int n,int (* wtest)(wint_t))233e3191321Sschwarze c__prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
234df930be7Sderaadt {
235df930be7Sderaadt 	p--;
236df930be7Sderaadt 
237df930be7Sderaadt 	while (n--) {
238aed0ee81Snicm 		while ((p >= low) && !(*wtest)(*p))
239df930be7Sderaadt 			p--;
240aed0ee81Snicm 		while ((p >= low) && (*wtest)(*p))
241df930be7Sderaadt 			p--;
242df930be7Sderaadt 	}
243df930be7Sderaadt 
244df930be7Sderaadt 	/* cp now points to one character before the word */
245df930be7Sderaadt 	p++;
246df930be7Sderaadt 	if (p < low)
247df930be7Sderaadt 		p = low;
248df930be7Sderaadt 	/* cp now points where we want it */
24928d54ee8Sschwarze 	return p;
250df930be7Sderaadt }
251df930be7Sderaadt 
252df930be7Sderaadt 
253df930be7Sderaadt /* c__next_word():
254df930be7Sderaadt  *	Find the next word
255df930be7Sderaadt  */
256e3191321Sschwarze protected wchar_t *
c__next_word(wchar_t * p,wchar_t * high,int n,int (* wtest)(wint_t))257e3191321Sschwarze c__next_word(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
258df930be7Sderaadt {
259df930be7Sderaadt 	while (n--) {
260aed0ee81Snicm 		while ((p < high) && !(*wtest)(*p))
261df930be7Sderaadt 			p++;
262aed0ee81Snicm 		while ((p < high) && (*wtest)(*p))
263df930be7Sderaadt 			p++;
264df930be7Sderaadt 	}
265df930be7Sderaadt 	if (p > high)
266df930be7Sderaadt 		p = high;
267df930be7Sderaadt 	/* p now points where we want it */
26828d54ee8Sschwarze 	return p;
269df930be7Sderaadt }
270df930be7Sderaadt 
271df930be7Sderaadt /* cv_next_word():
272df930be7Sderaadt  *	Find the next word vi style
273df930be7Sderaadt  */
274e3191321Sschwarze protected wchar_t *
cv_next_word(EditLine * el,wchar_t * p,wchar_t * high,int n,int (* wtest)(wint_t))275e3191321Sschwarze cv_next_word(EditLine *el, wchar_t *p, wchar_t *high, int n,
276e3191321Sschwarze     int (*wtest)(wint_t))
277df930be7Sderaadt {
278df930be7Sderaadt 	int test;
279df930be7Sderaadt 
280df930be7Sderaadt 	while (n--) {
281aed0ee81Snicm 		test = (*wtest)(*p);
282aed0ee81Snicm 		while ((p < high) && (*wtest)(*p) == test)
283df930be7Sderaadt 			p++;
284df930be7Sderaadt 		/*
285df930be7Sderaadt 		 * vi historically deletes with cw only the word preserving the
286df930be7Sderaadt 		 * trailing whitespace! This is not what 'w' does..
287df930be7Sderaadt 		 */
288d484b7d0Sotto 		if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
289565aa7e8Sschwarze 			while ((p < high) && iswspace(*p))
290df930be7Sderaadt 				p++;
291df930be7Sderaadt 	}
292df930be7Sderaadt 
293df930be7Sderaadt 	/* p now points where we want it */
294df930be7Sderaadt 	if (p > high)
29528d54ee8Sschwarze 		return high;
296df930be7Sderaadt 	else
29728d54ee8Sschwarze 		return p;
298df930be7Sderaadt }
299df930be7Sderaadt 
300df930be7Sderaadt 
301df930be7Sderaadt /* cv_prev_word():
302df930be7Sderaadt  *	Find the previous word vi style
303df930be7Sderaadt  */
304e3191321Sschwarze protected wchar_t *
cv_prev_word(wchar_t * p,wchar_t * low,int n,int (* wtest)(wint_t))305e3191321Sschwarze cv_prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
306df930be7Sderaadt {
307df930be7Sderaadt 	int test;
308df930be7Sderaadt 
309df930be7Sderaadt 	p--;
310d484b7d0Sotto 	while (n--) {
311565aa7e8Sschwarze 		while ((p > low) && iswspace(*p))
312df930be7Sderaadt 			p--;
313aed0ee81Snicm 		test = (*wtest)(*p);
314aed0ee81Snicm 		while ((p >= low) && (*wtest)(*p) == test)
315df930be7Sderaadt 			p--;
316df930be7Sderaadt 	}
317d484b7d0Sotto 	p++;
318df930be7Sderaadt 
319df930be7Sderaadt 	/* p now points where we want it */
320df930be7Sderaadt 	if (p < low)
32128d54ee8Sschwarze 		return low;
322df930be7Sderaadt 	else
32328d54ee8Sschwarze 		return p;
324df930be7Sderaadt }
325df930be7Sderaadt 
326df930be7Sderaadt 
327df930be7Sderaadt /* cv_delfini():
328df930be7Sderaadt  *	Finish vi delete action
329df930be7Sderaadt  */
330df930be7Sderaadt protected void
cv_delfini(EditLine * el)331d484b7d0Sotto cv_delfini(EditLine *el)
332df930be7Sderaadt {
333d484b7d0Sotto 	int size;
334d484b7d0Sotto 	int action = el->el_chared.c_vcmd.action;
335df930be7Sderaadt 
336d484b7d0Sotto 	if (action & INSERT)
337df930be7Sderaadt 		el->el_map.current = el->el_map.key;
338df930be7Sderaadt 
339df930be7Sderaadt 	if (el->el_chared.c_vcmd.pos == 0)
340d484b7d0Sotto 		/* sanity */
341df930be7Sderaadt 		return;
342df930be7Sderaadt 
343aed0ee81Snicm 	size = (int)(el->el_line.cursor - el->el_chared.c_vcmd.pos);
344d484b7d0Sotto 	if (size == 0)
345df930be7Sderaadt 		size = 1;
346d484b7d0Sotto 	el->el_line.cursor = el->el_chared.c_vcmd.pos;
347d484b7d0Sotto 	if (action & YANK) {
348d484b7d0Sotto 		if (size > 0)
349d484b7d0Sotto 			cv_yank(el, el->el_line.cursor, size);
350d484b7d0Sotto 		else
351d484b7d0Sotto 			cv_yank(el, el->el_line.cursor + size, -size);
352d484b7d0Sotto 	} else {
353d484b7d0Sotto 		if (size > 0) {
354df930be7Sderaadt 			c_delafter(el, size);
355d484b7d0Sotto 			re_refresh_cursor(el);
356d484b7d0Sotto 		} else  {
357d484b7d0Sotto 			c_delbefore(el, -size);
358d484b7d0Sotto 			el->el_line.cursor += size;
359df930be7Sderaadt 		}
360df930be7Sderaadt 	}
361d484b7d0Sotto 	el->el_chared.c_vcmd.action = NOP;
362df930be7Sderaadt }
363df930be7Sderaadt 
364df930be7Sderaadt 
365df930be7Sderaadt /* cv__endword():
366df930be7Sderaadt  *	Go to the end of this word according to vi
367df930be7Sderaadt  */
368e3191321Sschwarze protected wchar_t *
cv__endword(wchar_t * p,wchar_t * high,int n,int (* wtest)(wint_t))369e3191321Sschwarze cv__endword(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
370df930be7Sderaadt {
371d484b7d0Sotto 	int test;
372d484b7d0Sotto 
373df930be7Sderaadt 	p++;
374df930be7Sderaadt 
375df930be7Sderaadt 	while (n--) {
376565aa7e8Sschwarze 		while ((p < high) && iswspace(*p))
377df930be7Sderaadt 			p++;
378df930be7Sderaadt 
379aed0ee81Snicm 		test = (*wtest)(*p);
380aed0ee81Snicm 		while ((p < high) && (*wtest)(*p) == test)
381df930be7Sderaadt 			p++;
382df930be7Sderaadt 	}
383df930be7Sderaadt 	p--;
38428d54ee8Sschwarze 	return p;
385df930be7Sderaadt }
386df930be7Sderaadt 
387df930be7Sderaadt /* ch_init():
388df930be7Sderaadt  *	Initialize the character editor
389df930be7Sderaadt  */
390df930be7Sderaadt protected int
ch_init(EditLine * el)391d484b7d0Sotto ch_init(EditLine *el)
392df930be7Sderaadt {
393*7b6df1e2Stb 	el->el_line.buffer = calloc(EL_BUFSIZ, sizeof(*el->el_line.buffer));
394d484b7d0Sotto 	if (el->el_line.buffer == NULL)
39528d54ee8Sschwarze 		return -1;
396df930be7Sderaadt 	el->el_line.cursor = el->el_line.buffer;
397df930be7Sderaadt 	el->el_line.lastchar = el->el_line.buffer;
398d484b7d0Sotto 	el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - EL_LEAVE];
399df930be7Sderaadt 
400*7b6df1e2Stb 	el->el_chared.c_undo.buf = calloc(EL_BUFSIZ,
401aed0ee81Snicm 	    sizeof(*el->el_chared.c_undo.buf));
402d484b7d0Sotto 	if (el->el_chared.c_undo.buf == NULL)
40328d54ee8Sschwarze 		return -1;
404d484b7d0Sotto 	el->el_chared.c_undo.len = -1;
405d484b7d0Sotto 	el->el_chared.c_undo.cursor = 0;
406*7b6df1e2Stb 
407014b1be8Sderaadt 	el->el_chared.c_redo.buf = reallocarray(NULL, EL_BUFSIZ,
408aed0ee81Snicm 	    sizeof(*el->el_chared.c_redo.buf));
409d484b7d0Sotto 	if (el->el_chared.c_redo.buf == NULL)
41028d54ee8Sschwarze 		return -1;
411d484b7d0Sotto 	el->el_chared.c_redo.pos = el->el_chared.c_redo.buf;
412d484b7d0Sotto 	el->el_chared.c_redo.lim = el->el_chared.c_redo.buf + EL_BUFSIZ;
413d484b7d0Sotto 	el->el_chared.c_redo.cmd = ED_UNASSIGNED;
414df930be7Sderaadt 
415df930be7Sderaadt 	el->el_chared.c_vcmd.action = NOP;
416df930be7Sderaadt 	el->el_chared.c_vcmd.pos = el->el_line.buffer;
417df930be7Sderaadt 
418*7b6df1e2Stb 	el->el_chared.c_kill.buf = calloc(EL_BUFSIZ,
419aed0ee81Snicm 	    sizeof(*el->el_chared.c_kill.buf));
420d484b7d0Sotto 	if (el->el_chared.c_kill.buf == NULL)
42128d54ee8Sschwarze 		return -1;
422df930be7Sderaadt 	el->el_chared.c_kill.mark = el->el_line.buffer;
423df930be7Sderaadt 	el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
4245f805b19Sokan 	el->el_chared.c_resizefun = NULL;
4255f805b19Sokan 	el->el_chared.c_resizearg = NULL;
426df930be7Sderaadt 
427df930be7Sderaadt 	el->el_map.current = el->el_map.key;
428df930be7Sderaadt 
429df930be7Sderaadt 	el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
430df930be7Sderaadt 	el->el_state.doingarg = 0;
431df930be7Sderaadt 	el->el_state.metanext = 0;
432df930be7Sderaadt 	el->el_state.argument = 1;
433df930be7Sderaadt 	el->el_state.lastcmd = ED_UNASSIGNED;
434df930be7Sderaadt 
43528d54ee8Sschwarze 	return 0;
436df930be7Sderaadt }
437df930be7Sderaadt 
438df930be7Sderaadt /* ch_reset():
439df930be7Sderaadt  *	Reset the character editor
440df930be7Sderaadt  */
441df930be7Sderaadt protected void
ch_reset(EditLine * el)4425161d913Sschwarze ch_reset(EditLine *el)
443df930be7Sderaadt {
444df930be7Sderaadt 	el->el_line.cursor		= el->el_line.buffer;
445df930be7Sderaadt 	el->el_line.lastchar		= el->el_line.buffer;
446df930be7Sderaadt 
447d484b7d0Sotto 	el->el_chared.c_undo.len	= -1;
448d484b7d0Sotto 	el->el_chared.c_undo.cursor	= 0;
449df930be7Sderaadt 
450df930be7Sderaadt 	el->el_chared.c_vcmd.action	= NOP;
451df930be7Sderaadt 	el->el_chared.c_vcmd.pos	= el->el_line.buffer;
452df930be7Sderaadt 
453df930be7Sderaadt 	el->el_chared.c_kill.mark	= el->el_line.buffer;
454df930be7Sderaadt 
455df930be7Sderaadt 	el->el_map.current		= el->el_map.key;
456df930be7Sderaadt 
457df930be7Sderaadt 	el->el_state.inputmode		= MODE_INSERT; /* XXX: save a default */
458df930be7Sderaadt 	el->el_state.doingarg		= 0;
459df930be7Sderaadt 	el->el_state.metanext		= 0;
460df930be7Sderaadt 	el->el_state.argument		= 1;
461df930be7Sderaadt 	el->el_state.lastcmd		= ED_UNASSIGNED;
462df930be7Sderaadt 
463df930be7Sderaadt 	el->el_history.eventno		= 0;
464df930be7Sderaadt }
465df930be7Sderaadt 
466d484b7d0Sotto /* ch_enlargebufs():
467d484b7d0Sotto  *	Enlarge line buffer to be able to hold twice as much characters.
468d484b7d0Sotto  *	Returns 1 if successful, 0 if not.
469d484b7d0Sotto  */
470d484b7d0Sotto protected int
ch_enlargebufs(EditLine * el,size_t addlen)471aed0ee81Snicm ch_enlargebufs(EditLine *el, size_t addlen)
472d484b7d0Sotto {
473d484b7d0Sotto 	size_t sz, newsz;
474e3191321Sschwarze 	wchar_t *newbuffer, *oldbuf, *oldkbuf;
475d484b7d0Sotto 
476d484b7d0Sotto 	sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
477d484b7d0Sotto 	newsz = sz * 2;
478d484b7d0Sotto 	/*
479d484b7d0Sotto 	 * If newly required length is longer than current buffer, we need
480d484b7d0Sotto 	 * to make the buffer big enough to hold both old and new stuff.
481d484b7d0Sotto 	 */
482d484b7d0Sotto 	if (addlen > sz) {
483d484b7d0Sotto 		while(newsz - sz < addlen)
484d484b7d0Sotto 			newsz *= 2;
485d484b7d0Sotto 	}
486d484b7d0Sotto 
487d484b7d0Sotto 	/*
488d484b7d0Sotto 	 * Reallocate line buffer.
489d484b7d0Sotto 	 */
490*7b6df1e2Stb 	newbuffer = recallocarray(el->el_line.buffer, sz, newsz,
491014b1be8Sderaadt 	    sizeof(*newbuffer));
492d484b7d0Sotto 	if (!newbuffer)
493d484b7d0Sotto 		return 0;
494d484b7d0Sotto 
495d484b7d0Sotto 	oldbuf = el->el_line.buffer;
496d484b7d0Sotto 
497d484b7d0Sotto 	el->el_line.buffer = newbuffer;
498d484b7d0Sotto 	el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
499d484b7d0Sotto 	el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
500d484b7d0Sotto 	/* don't set new size until all buffers are enlarged */
501d484b7d0Sotto 	el->el_line.limit  = &newbuffer[sz - EL_LEAVE];
502d484b7d0Sotto 
503d484b7d0Sotto 	/*
504d484b7d0Sotto 	 * Reallocate kill buffer.
505d484b7d0Sotto 	 */
506*7b6df1e2Stb 	newbuffer = recallocarray(el->el_chared.c_kill.buf, sz, newsz,
507014b1be8Sderaadt 	    sizeof(*newbuffer));
508d484b7d0Sotto 	if (!newbuffer)
509d484b7d0Sotto 		return 0;
510d484b7d0Sotto 
511d484b7d0Sotto 	oldkbuf = el->el_chared.c_kill.buf;
512d484b7d0Sotto 
513d484b7d0Sotto 	el->el_chared.c_kill.buf = newbuffer;
514d484b7d0Sotto 	el->el_chared.c_kill.last = newbuffer +
515d484b7d0Sotto 					(el->el_chared.c_kill.last - oldkbuf);
516d484b7d0Sotto 	el->el_chared.c_kill.mark = el->el_line.buffer +
517d484b7d0Sotto 					(el->el_chared.c_kill.mark - oldbuf);
518d484b7d0Sotto 
519d484b7d0Sotto 	/*
520d484b7d0Sotto 	 * Reallocate undo buffer.
521d484b7d0Sotto 	 */
522*7b6df1e2Stb 	newbuffer = recallocarray(el->el_chared.c_undo.buf, sz, newsz,
523*7b6df1e2Stb 	    sizeof(*newbuffer));
524d484b7d0Sotto 	if (!newbuffer)
525d484b7d0Sotto 		return 0;
526d484b7d0Sotto 	el->el_chared.c_undo.buf = newbuffer;
527d484b7d0Sotto 
528014b1be8Sderaadt 	newbuffer = reallocarray(el->el_chared.c_redo.buf,
529014b1be8Sderaadt 	    newsz, sizeof(*newbuffer));
530d484b7d0Sotto 	if (!newbuffer)
531d484b7d0Sotto 		return 0;
532d484b7d0Sotto 	el->el_chared.c_redo.pos = newbuffer +
533d484b7d0Sotto 			(el->el_chared.c_redo.pos - el->el_chared.c_redo.buf);
534d484b7d0Sotto 	el->el_chared.c_redo.lim = newbuffer +
535d484b7d0Sotto 			(el->el_chared.c_redo.lim - el->el_chared.c_redo.buf);
536d484b7d0Sotto 	el->el_chared.c_redo.buf = newbuffer;
537d484b7d0Sotto 
538d484b7d0Sotto 	if (!hist_enlargebuf(el, sz, newsz))
539d484b7d0Sotto 		return 0;
540d484b7d0Sotto 
541d484b7d0Sotto 	/* Safe to set enlarged buffer size */
5426e02e073Sotto 	el->el_line.limit  = &el->el_line.buffer[newsz - EL_LEAVE];
5435f805b19Sokan 	if (el->el_chared.c_resizefun)
5445f805b19Sokan 		(*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg);
545d484b7d0Sotto 	return 1;
546d484b7d0Sotto }
547df930be7Sderaadt 
548df930be7Sderaadt /* ch_end():
549df930be7Sderaadt  *	Free the data structures used by the editor
550df930be7Sderaadt  */
551df930be7Sderaadt protected void
ch_end(EditLine * el)552d484b7d0Sotto ch_end(EditLine *el)
553df930be7Sderaadt {
5547b85e16bSschwarze 	free(el->el_line.buffer);
555df930be7Sderaadt 	el->el_line.buffer = NULL;
556df930be7Sderaadt 	el->el_line.limit = NULL;
5577b85e16bSschwarze 	free(el->el_chared.c_undo.buf);
558df930be7Sderaadt 	el->el_chared.c_undo.buf = NULL;
5597b85e16bSschwarze 	free(el->el_chared.c_redo.buf);
560d484b7d0Sotto 	el->el_chared.c_redo.buf = NULL;
561d484b7d0Sotto 	el->el_chared.c_redo.pos = NULL;
562d484b7d0Sotto 	el->el_chared.c_redo.lim = NULL;
563d484b7d0Sotto 	el->el_chared.c_redo.cmd = ED_UNASSIGNED;
5647b85e16bSschwarze 	free(el->el_chared.c_kill.buf);
565df930be7Sderaadt 	el->el_chared.c_kill.buf = NULL;
5665161d913Sschwarze 	ch_reset(el);
567df930be7Sderaadt }
568df930be7Sderaadt 
569df930be7Sderaadt 
570df930be7Sderaadt /* el_insertstr():
571df930be7Sderaadt  *	Insert string at cursorI
572df930be7Sderaadt  */
573ddc81437Sschwarze int
el_winsertstr(EditLine * el,const wchar_t * s)574e3191321Sschwarze el_winsertstr(EditLine *el, const wchar_t *s)
575df930be7Sderaadt {
576d484b7d0Sotto 	size_t len;
577df930be7Sderaadt 
5785c93237dSschwarze 	if ((len = wcslen(s)) == 0)
57928d54ee8Sschwarze 		return -1;
580d484b7d0Sotto 	if (el->el_line.lastchar + len >= el->el_line.limit) {
581d484b7d0Sotto 		if (!ch_enlargebufs(el, len))
58228d54ee8Sschwarze 			return -1;
583d484b7d0Sotto 	}
584df930be7Sderaadt 
585d484b7d0Sotto 	c_insert(el, (int)len);
586df930be7Sderaadt 	while (*s)
587df930be7Sderaadt 		*el->el_line.cursor++ = *s++;
58828d54ee8Sschwarze 	return 0;
589df930be7Sderaadt }
590df930be7Sderaadt 
591df930be7Sderaadt 
592df930be7Sderaadt /* el_deletestr():
593df930be7Sderaadt  *	Delete num characters before the cursor
594df930be7Sderaadt  */
595ddc81437Sschwarze void
el_deletestr(EditLine * el,int n)596d484b7d0Sotto el_deletestr(EditLine *el, int n)
597df930be7Sderaadt {
598df930be7Sderaadt 	if (n <= 0)
599df930be7Sderaadt 		return;
600df930be7Sderaadt 
601df930be7Sderaadt 	if (el->el_line.cursor < &el->el_line.buffer[n])
602df930be7Sderaadt 		return;
603df930be7Sderaadt 
604df930be7Sderaadt 	c_delbefore(el, n);		/* delete before dot */
605df930be7Sderaadt 	el->el_line.cursor -= n;
606df930be7Sderaadt 	if (el->el_line.cursor < el->el_line.buffer)
607df930be7Sderaadt 		el->el_line.cursor = el->el_line.buffer;
608df930be7Sderaadt }
609df930be7Sderaadt 
610df930be7Sderaadt /* c_gets():
611df930be7Sderaadt  *	Get a string
612df930be7Sderaadt  */
613df930be7Sderaadt protected int
c_gets(EditLine * el,wchar_t * buf,const wchar_t * prompt)614e3191321Sschwarze c_gets(EditLine *el, wchar_t *buf, const wchar_t *prompt)
615df930be7Sderaadt {
616aed0ee81Snicm 	ssize_t len;
617e3191321Sschwarze 	wchar_t *cp = el->el_line.buffer, ch;
618df930be7Sderaadt 
619d484b7d0Sotto 	if (prompt) {
6205c93237dSschwarze 		len = wcslen(prompt);
621aed0ee81Snicm 		(void)memcpy(cp, prompt, len * sizeof(*cp));
622d484b7d0Sotto 		cp += len;
623d484b7d0Sotto 	}
624d484b7d0Sotto 	len = 0;
625d484b7d0Sotto 
626d484b7d0Sotto 	for (;;) {
627d484b7d0Sotto 		el->el_line.cursor = cp;
628d484b7d0Sotto 		*cp = ' ';
629d484b7d0Sotto 		el->el_line.lastchar = cp + 1;
630d484b7d0Sotto 		re_refresh(el);
631d484b7d0Sotto 
632e3191321Sschwarze 		if (el_wgetc(el, &ch) != 1) {
633d484b7d0Sotto 			ed_end_of_file(el, 0);
634d484b7d0Sotto 			len = -1;
635d484b7d0Sotto 			break;
636d484b7d0Sotto 		}
637d484b7d0Sotto 
638df930be7Sderaadt 		switch (ch) {
639d484b7d0Sotto 
640df2a7d38Sschwarze 		case L'\b':	/* Delete and backspace */
641df930be7Sderaadt 		case 0177:
642aed0ee81Snicm 			if (len == 0) {
643d484b7d0Sotto 				len = -1;
644df930be7Sderaadt 				break;
645d484b7d0Sotto 			}
64609f612eeSschwarze 			len--;
647d484b7d0Sotto 			cp--;
648d484b7d0Sotto 			continue;
649df930be7Sderaadt 
650df930be7Sderaadt 		case 0033:	/* ESC */
651df2a7d38Sschwarze 		case L'\r':	/* Newline */
652df2a7d38Sschwarze 		case L'\n':
653d484b7d0Sotto 			buf[len] = ch;
654df930be7Sderaadt 			break;
655df930be7Sderaadt 
656df930be7Sderaadt 		default:
657d484b7d0Sotto 			if (len >= EL_BUFSIZ - 16)
658fd40972aSschwarze 				terminal_beep(el);
659df930be7Sderaadt 			else {
660df930be7Sderaadt 				buf[len++] = ch;
661d484b7d0Sotto 				*cp++ = ch;
662df930be7Sderaadt 			}
663d484b7d0Sotto 			continue;
664d484b7d0Sotto 		}
665df930be7Sderaadt 		break;
666df930be7Sderaadt 	}
667d484b7d0Sotto 
668d484b7d0Sotto 	el->el_line.buffer[0] = '\0';
669d484b7d0Sotto 	el->el_line.lastchar = el->el_line.buffer;
670d484b7d0Sotto 	el->el_line.cursor = el->el_line.buffer;
671aed0ee81Snicm 	return (int)len;
672df930be7Sderaadt }
673df930be7Sderaadt 
674df930be7Sderaadt 
675df930be7Sderaadt /* c_hpos():
676df930be7Sderaadt  *	Return the current horizontal position of the cursor
677df930be7Sderaadt  */
678df930be7Sderaadt protected int
c_hpos(EditLine * el)679d484b7d0Sotto c_hpos(EditLine *el)
680df930be7Sderaadt {
681e3191321Sschwarze 	wchar_t *ptr;
682df930be7Sderaadt 
683df930be7Sderaadt 	/*
684df930be7Sderaadt 	 * Find how many characters till the beginning of this line.
685df930be7Sderaadt 	 */
686df930be7Sderaadt 	if (el->el_line.cursor == el->el_line.buffer)
68728d54ee8Sschwarze 		return 0;
688df930be7Sderaadt 	else {
689df930be7Sderaadt 		for (ptr = el->el_line.cursor - 1;
690df930be7Sderaadt 		     ptr >= el->el_line.buffer && *ptr != '\n';
691df930be7Sderaadt 		     ptr--)
692df930be7Sderaadt 			continue;
693aed0ee81Snicm 		return (int)(el->el_line.cursor - ptr - 1);
694df930be7Sderaadt 	}
695df930be7Sderaadt }
6965f805b19Sokan 
6975f805b19Sokan protected int
ch_resizefun(EditLine * el,el_zfunc_t f,void * a)6985f805b19Sokan ch_resizefun(EditLine *el, el_zfunc_t f, void *a)
6995f805b19Sokan {
7005f805b19Sokan 	el->el_chared.c_resizefun = f;
7015f805b19Sokan 	el->el_chared.c_resizearg = a;
7025f805b19Sokan 	return 0;
7035f805b19Sokan }
704