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