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