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