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