chared.c revision 37199
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 type of word for p according to vi 157 */ 158protected int 159cv__isword(p) 160 int p; 161{ 162 if (isspace((unsigned char) p)) 163 return 0; 164 if ((unsigned char) p == '_' || isalnum((unsigned char) p)) 165 return 1; 166 return 2; 167} 168 169 170/* c___isword(): 171 * Return if p is part of a space-delimited word (!isspace) 172 */ 173protected int 174c___isword(p) 175 int p; 176{ 177 return !isspace((unsigned char) p); 178} 179 180 181/* c__prev_word(): 182 * Find the previous word 183 */ 184protected char * 185c__prev_word(p, low, n, wtest) 186 register char *p, *low; 187 register int n; 188 int (*wtest) __P((int)); 189{ 190 p--; 191 192 while (n--) { 193 while ((p >= low) && !(*wtest)((unsigned char) *p)) 194 p--; 195 while ((p >= low) && (*wtest)((unsigned char) *p)) 196 p--; 197 } 198 199 /* cp now points to one character before the word */ 200 p++; 201 if (p < low) 202 p = low; 203 /* cp now points where we want it */ 204 return p; 205} 206 207 208/* c__next_word(): 209 * Find the next word 210 */ 211protected char * 212c__next_word(p, high, n, wtest) 213 register char *p, *high; 214 register int n; 215 int (*wtest) __P((int)); 216{ 217 while (n--) { 218 while ((p < high) && !(*wtest)((unsigned char) *p)) 219 p++; 220 while ((p < high) && (*wtest)((unsigned char) *p)) 221 p++; 222 } 223 if (p > high) 224 p = high; 225 /* p now points where we want it */ 226 return p; 227} 228 229/* cv_next_word(): 230 * Find the next word vi style 231 */ 232protected char * 233cv_next_word(el, p, high, n, wtest) 234 EditLine *el; 235 register char *p, *high; 236 register int n; 237 int (*wtest) __P((int)); 238{ 239 int test; 240 241 while (n--) { 242 test = (*wtest)((unsigned char) *p); 243 while ((p < high) && (*wtest)((unsigned char) *p) == test) 244 p++; 245 /* 246 * vi historically deletes with cw only the word preserving the 247 * trailing whitespace! This is not what 'w' does.. 248 */ 249 if (el->el_chared.c_vcmd.action != (DELETE|INSERT)) 250 while ((p < high) && isspace((unsigned char) *p)) 251 p++; 252 } 253 254 /* p now points where we want it */ 255 if (p > high) 256 return high; 257 else 258 return p; 259} 260 261 262/* cv_prev_word(): 263 * Find the previous word vi style 264 */ 265protected char * 266cv_prev_word(el, p, low, n, wtest) 267 EditLine *el; 268 register char *p, *low; 269 register int n; 270 int (*wtest) __P((int)); 271{ 272 int test; 273 274 while (n--) { 275 p--; 276 /* 277 * vi historically deletes with cb only the word preserving the 278 * leading whitespace! This is not what 'b' does.. 279 */ 280 if (el->el_chared.c_vcmd.action != (DELETE|INSERT)) 281 while ((p > low) && isspace((unsigned char) *p)) 282 p--; 283 test = (*wtest)((unsigned char) *p); 284 while ((p >= low) && (*wtest)((unsigned char) *p) == test) 285 p--; 286 p++; 287 while (isspace((unsigned char) *p)) 288 p++; 289 } 290 291 /* p now points where we want it */ 292 if (p < low) 293 return low; 294 else 295 return p; 296} 297 298 299#ifdef notdef 300/* c__number(): 301 * Ignore character p points to, return number appearing after that. 302 * A '$' by itself means a big number; "$-" is for negative; '^' means 1. 303 * Return p pointing to last char used. 304 */ 305protected char * 306c__number(p, num, dval) 307 char *p; /* character position */ 308 int *num; /* Return value */ 309 int dval; /* dval is the number to subtract from like $-3 */ 310{ 311 register int i; 312 register int sign = 1; 313 314 if (*++p == '^') { 315 *num = 1; 316 return p; 317 } 318 if (*p == '$') { 319 if (*++p != '-') { 320 *num = 0x7fffffff; /* Handle $ */ 321 return --p; 322 } 323 sign = -1; /* Handle $- */ 324 ++p; 325 } 326 for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0') 327 continue; 328 *num = (sign < 0 ? dval - i : i); 329 return --p; 330} 331#endif 332 333/* cv_delfini(): 334 * Finish vi delete action 335 */ 336protected void 337cv_delfini(el) 338 EditLine *el; 339{ 340 register int size; 341 int oaction; 342 343 if (el->el_chared.c_vcmd.action & INSERT) 344 el->el_map.current = el->el_map.key; 345 346 oaction = el->el_chared.c_vcmd.action; 347 el->el_chared.c_vcmd.action = NOP; 348 349 if (el->el_chared.c_vcmd.pos == 0) 350 return; 351 352 353 if (el->el_line.cursor > el->el_chared.c_vcmd.pos) { 354 size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos); 355 c_delbefore(el, size); 356 el->el_line.cursor = el->el_chared.c_vcmd.pos; 357 re_refresh_cursor(el); 358 } 359 else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) { 360 size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor); 361 c_delafter(el, size); 362 } 363 else { 364 size = 1; 365 c_delafter(el, size); 366 } 367 switch (oaction) { 368 case DELETE|INSERT: 369 el->el_chared.c_undo.action = DELETE|INSERT; 370 break; 371 case DELETE: 372 el->el_chared.c_undo.action = INSERT; 373 break; 374 case NOP: 375 case INSERT: 376 default: 377 abort(); 378 break; 379 } 380 381 382 el->el_chared.c_undo.ptr = el->el_line.cursor; 383 el->el_chared.c_undo.dsize = size; 384} 385 386 387#ifdef notdef 388/* ce__endword(): 389 * Go to the end of this word according to emacs 390 */ 391protected char * 392ce__endword(p, high, n) 393 char *p, *high; 394 int n; 395{ 396 p++; 397 398 while (n--) { 399 while ((p < high) && isspace((unsigned char) *p)) 400 p++; 401 while ((p < high) && !isspace((unsigned char) *p)) 402 p++; 403 } 404 405 p--; 406 return p; 407} 408#endif 409 410 411/* cv__endword(): 412 * Go to the end of this word according to vi 413 */ 414protected char * 415cv__endword(p, high, n) 416 char *p, *high; 417 int n; 418{ 419 p++; 420 421 while (n--) { 422 while ((p < high) && isspace((unsigned char) *p)) 423 p++; 424 425 if (isalnum((unsigned char) *p)) 426 while ((p < high) && isalnum((unsigned char) *p)) 427 p++; 428 else 429 while ((p < high) && !(isspace((unsigned char) *p) || 430 isalnum((unsigned char) *p))) 431 p++; 432 } 433 p--; 434 return p; 435} 436 437/* ch_init(): 438 * Initialize the character editor 439 */ 440protected int 441ch_init(el) 442 EditLine *el; 443{ 444 el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ); 445 (void) memset(el->el_line.buffer, 0, EL_BUFSIZ); 446 el->el_line.cursor = el->el_line.buffer; 447 el->el_line.lastchar = el->el_line.buffer; 448 el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - 2]; 449 450 el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ); 451 (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ); 452 el->el_chared.c_undo.action = NOP; 453 el->el_chared.c_undo.isize = 0; 454 el->el_chared.c_undo.dsize = 0; 455 el->el_chared.c_undo.ptr = el->el_line.buffer; 456 457 el->el_chared.c_vcmd.action = NOP; 458 el->el_chared.c_vcmd.pos = el->el_line.buffer; 459 el->el_chared.c_vcmd.ins = el->el_line.buffer; 460 461 el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ); 462 (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ); 463 el->el_chared.c_kill.mark = el->el_line.buffer; 464 el->el_chared.c_kill.last = el->el_chared.c_kill.buf; 465 466 el->el_map.current = el->el_map.key; 467 468 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ 469 el->el_state.doingarg = 0; 470 el->el_state.metanext = 0; 471 el->el_state.argument = 1; 472 el->el_state.lastcmd = ED_UNASSIGNED; 473 474 el->el_chared.c_macro.nline = NULL; 475 el->el_chared.c_macro.level = -1; 476 el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO * 477 sizeof(char *)); 478 return 0; 479} 480 481/* ch_reset(): 482 * Reset the character editor 483 */ 484protected void 485ch_reset(el) 486 EditLine *el; 487{ 488 el->el_line.cursor = el->el_line.buffer; 489 el->el_line.lastchar = el->el_line.buffer; 490 491 el->el_chared.c_undo.action = NOP; 492 el->el_chared.c_undo.isize = 0; 493 el->el_chared.c_undo.dsize = 0; 494 el->el_chared.c_undo.ptr = el->el_line.buffer; 495 496 el->el_chared.c_vcmd.action = NOP; 497 el->el_chared.c_vcmd.pos = el->el_line.buffer; 498 el->el_chared.c_vcmd.ins = el->el_line.buffer; 499 500 el->el_chared.c_kill.mark = el->el_line.buffer; 501 502 el->el_map.current = el->el_map.key; 503 504 el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */ 505 el->el_state.doingarg = 0; 506 el->el_state.metanext = 0; 507 el->el_state.argument = 1; 508 el->el_state.lastcmd = ED_UNASSIGNED; 509 510 el->el_chared.c_macro.level = -1; 511 512 el->el_history.eventno = 0; 513} 514 515 516/* ch_end(): 517 * Free the data structures used by the editor 518 */ 519protected void 520ch_end(el) 521 EditLine *el; 522{ 523 el_free((ptr_t) el->el_line.buffer); 524 el->el_line.buffer = NULL; 525 el->el_line.limit = NULL; 526 el_free((ptr_t) el->el_chared.c_undo.buf); 527 el->el_chared.c_undo.buf = NULL; 528 el_free((ptr_t) el->el_chared.c_kill.buf); 529 el->el_chared.c_kill.buf = NULL; 530 el_free((ptr_t) el->el_chared.c_macro.macro); 531 el->el_chared.c_macro.macro = NULL; 532 ch_reset(el); 533} 534 535 536/* el_insertstr(): 537 * Insert string at cursorI 538 */ 539public int 540el_insertstr(el, s) 541 EditLine *el; 542 char *s; 543{ 544 int len; 545 546 if ((len = strlen(s)) == 0) 547 return -1; 548 if (el->el_line.lastchar + len >= el->el_line.limit) 549 return -1; 550 551 c_insert(el, len); 552 while (*s) 553 *el->el_line.cursor++ = *s++; 554 return 0; 555} 556 557 558/* el_deletestr(): 559 * Delete num characters before the cursor 560 */ 561public void 562el_deletestr(el, n) 563 EditLine *el; 564 int n; 565{ 566 if (n <= 0) 567 return; 568 569 if (el->el_line.cursor < &el->el_line.buffer[n]) 570 return; 571 572 c_delbefore(el, n); /* delete before dot */ 573 el->el_line.cursor -= n; 574 if (el->el_line.cursor < el->el_line.buffer) 575 el->el_line.cursor = el->el_line.buffer; 576} 577 578/* c_gets(): 579 * Get a string 580 */ 581protected int 582c_gets(el, buf) 583 EditLine *el; 584 char *buf; 585{ 586 char ch; 587 int len = 0; 588 589 for (ch = 0; ch == 0;) { 590 if (el_getc(el, &ch) != 1) 591 return ed_end_of_file(el, 0); 592 switch (ch) { 593 case '\010': /* Delete and backspace */ 594 case '\177': 595 if (len > 1) { 596 *el->el_line.cursor-- = '\0'; 597 el->el_line.lastchar = el->el_line.cursor; 598 buf[len--] = '\0'; 599 } 600 else { 601 el->el_line.buffer[0] = '\0'; 602 el->el_line.lastchar = el->el_line.buffer; 603 el->el_line.cursor = el->el_line.buffer; 604 return CC_REFRESH; 605 } 606 re_refresh(el); 607 ch = 0; 608 break; 609 610 case '\033': /* ESC */ 611 case '\r': /* Newline */ 612 case '\n': 613 break; 614 615 default: 616 if (len >= EL_BUFSIZ) 617 term_beep(el); 618 else { 619 buf[len++] = ch; 620 *el->el_line.cursor++ = ch; 621 el->el_line.lastchar = el->el_line.cursor; 622 } 623 re_refresh(el); 624 ch = 0; 625 break; 626 } 627 } 628 buf[len] = ch; 629 return len; 630} 631 632 633/* c_hpos(): 634 * Return the current horizontal position of the cursor 635 */ 636protected int 637c_hpos(el) 638 EditLine *el; 639{ 640 char *ptr; 641 642 /* 643 * Find how many characters till the beginning of this line. 644 */ 645 if (el->el_line.cursor == el->el_line.buffer) 646 return 0; 647 else { 648 for (ptr = el->el_line.cursor - 1; 649 ptr >= el->el_line.buffer && *ptr != '\n'; 650 ptr--) 651 continue; 652 return el->el_line.cursor - ptr - 1; 653 } 654} 655