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