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