1 /*- 2 * Copyright (c) 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1992, 1993, 1994, 1995, 1996 5 * Keith Bostic. All rights reserved. 6 * 7 * See the LICENSE file for redistribution information. 8 */ 9 10 #include "config.h" 11 12 #ifndef lint 13 static const char sccsid[] = "@(#)vi.c 10.57 (Berkeley) 10/13/96"; 14 #endif /* not lint */ 15 16 #include <sys/types.h> 17 #include <sys/queue.h> 18 #include <sys/time.h> 19 20 #include <bitstring.h> 21 #include <ctype.h> 22 #include <errno.h> 23 #include <limits.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include "../common/common.h" 30 #include "vi.h" 31 32 typedef enum { 33 GC_ERR, GC_ERR_NOFLUSH, GC_EVENT, GC_FATAL, GC_INTERRUPT, GC_OK 34 } gcret_t; 35 36 static VIKEYS const 37 *v_alias __P((SCR *, VICMD *, VIKEYS const *)); 38 static gcret_t v_cmd __P((SCR *, VICMD *, VICMD *, VICMD *, int *, int *)); 39 static int v_count __P((SCR *, ARG_CHAR_T, u_long *)); 40 static void v_dtoh __P((SCR *)); 41 static int v_init __P((SCR *)); 42 static gcret_t v_key __P((SCR *, int, EVENT *, u_int32_t)); 43 static int v_keyword __P((SCR *)); 44 static int v_motion __P((SCR *, VICMD *, VICMD *, int *)); 45 46 #if defined(DEBUG) && defined(COMLOG) 47 static void v_comlog __P((SCR *, VICMD *)); 48 #endif 49 50 /* 51 * Side-effect: 52 * The dot structure can be set by the underlying vi functions, 53 * see v_Put() and v_put(). 54 */ 55 #define DOT (&VIP(sp)->sdot) 56 #define DOTMOTION (&VIP(sp)->sdotmotion) 57 58 /* 59 * vi -- 60 * Main vi command loop. 61 * 62 * PUBLIC: int vi __P((SCR **)); 63 */ 64 int 65 vi(spp) 66 SCR **spp; 67 { 68 GS *gp; 69 MARK abs; 70 SCR *next, *sp; 71 VICMD cmd, *vp; 72 VI_PRIVATE *vip; 73 int comcount, mapped, rval; 74 75 /* Get the first screen. */ 76 sp = *spp; 77 gp = sp->gp; 78 79 /* Initialize the command structure. */ 80 vp = &cmd; 81 memset(vp, 0, sizeof(VICMD)); 82 83 /* Reset strange attraction. */ 84 F_SET(vp, VM_RCM_SET); 85 86 /* Initialize the vi screen. */ 87 if (v_init(sp)) 88 return (1); 89 90 /* Set the focus. */ 91 (void)sp->gp->scr_rename(sp, sp->frp->name, 1); 92 93 for (vip = VIP(sp), rval = 0;;) { 94 /* Resolve messages. */ 95 if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0)) 96 goto ret; 97 98 /* 99 * If not skipping a refresh, return to command mode and 100 * refresh the screen. 101 */ 102 if (F_ISSET(vip, VIP_S_REFRESH)) 103 F_CLR(vip, VIP_S_REFRESH); 104 else { 105 sp->showmode = SM_COMMAND; 106 if (vs_refresh(sp, 0)) 107 goto ret; 108 } 109 110 /* Set the new favorite position. */ 111 if (F_ISSET(vp, VM_RCM_SET | VM_RCM_SETFNB | VM_RCM_SETNNB)) { 112 F_CLR(vip, VIP_RCM_LAST); 113 (void)vs_column(sp, &sp->rcm); 114 } 115 116 /* 117 * If not currently in a map, log the cursor position, 118 * and set a flag so that this command can become the 119 * DOT command. 120 */ 121 if (MAPPED_KEYS_WAITING(sp)) 122 mapped = 1; 123 else { 124 if (log_cursor(sp)) 125 goto err; 126 mapped = 0; 127 } 128 129 /* 130 * There may be an ex command waiting, and we returned here 131 * only because we exited a screen or file. In this case, 132 * we simply go back into the ex parser. 133 */ 134 if (EXCMD_RUNNING(gp)) { 135 vp->kp = &vikeys[':']; 136 goto ex_continue; 137 } 138 139 /* Refresh the command structure. */ 140 memset(vp, 0, sizeof(VICMD)); 141 142 /* 143 * We get a command, which may or may not have an associated 144 * motion. If it does, we get it too, calling its underlying 145 * function to get the resulting mark. We then call the 146 * command setting the cursor to the resulting mark. 147 * 148 * !!! 149 * Vi historically flushed mapped characters on error, but 150 * entering extra <escape> characters at the beginning of 151 * a map wasn't considered an error -- in fact, users would 152 * put leading <escape> characters in maps to clean up vi 153 * state before the map was interpreted. Beauty! 154 */ 155 switch (v_cmd(sp, DOT, vp, NULL, &comcount, &mapped)) { 156 case GC_ERR: 157 goto err; 158 case GC_ERR_NOFLUSH: 159 goto gc_err_noflush; 160 case GC_EVENT: 161 if (v_event_exec(sp, vp)) 162 goto err; 163 goto gc_event; 164 case GC_FATAL: 165 goto ret; 166 case GC_INTERRUPT: 167 goto intr; 168 case GC_OK: 169 break; 170 } 171 172 /* Check for security setting. */ 173 if (F_ISSET(vp->kp, V_SECURE) && O_ISSET(sp, O_SECURE)) { 174 ex_emsg(sp, KEY_NAME(sp, vp->key), EXM_SECURE); 175 goto err; 176 } 177 178 /* 179 * Historical practice: if a dot command gets a new count, 180 * any motion component goes away, i.e. "d3w2." deletes a 181 * total of 5 words. 182 */ 183 if (F_ISSET(vp, VC_ISDOT) && comcount) 184 DOTMOTION->count = 1; 185 186 /* Copy the key flags into the local structure. */ 187 F_SET(vp, vp->kp->flags); 188 189 /* Prepare to set the previous context. */ 190 if (F_ISSET(vp, V_ABS | V_ABS_C | V_ABS_L)) { 191 abs.lno = sp->lno; 192 abs.cno = sp->cno; 193 } 194 195 /* 196 * Set the three cursor locations to the current cursor. The 197 * underlying routines don't bother if the cursor doesn't move. 198 * This also handles line commands (e.g. Y) defaulting to the 199 * current line. 200 */ 201 vp->m_start.lno = vp->m_stop.lno = vp->m_final.lno = sp->lno; 202 vp->m_start.cno = vp->m_stop.cno = vp->m_final.cno = sp->cno; 203 204 /* 205 * Do any required motion; v_motion sets the from MARK and the 206 * line mode flag, as well as the VM_RCM flags. 207 */ 208 if (F_ISSET(vp, V_MOTION) && 209 v_motion(sp, DOTMOTION, vp, &mapped)) { 210 if (INTERRUPTED(sp)) 211 goto intr; 212 goto err; 213 } 214 215 /* 216 * If a count is set and the command is line oriented, set the 217 * to MARK here relative to the cursor/from MARK. This is for 218 * commands that take both counts and motions, i.e. "4yy" and 219 * "y%". As there's no way the command can know which the user 220 * did, we have to do it here. (There are commands that are 221 * line oriented and that take counts ("#G", "#H"), for which 222 * this calculation is either completely meaningless or wrong. 223 * Each command must validate the value for itself. 224 */ 225 if (F_ISSET(vp, VC_C1SET) && F_ISSET(vp, VM_LMODE)) 226 vp->m_stop.lno += vp->count - 1; 227 228 /* Increment the command count. */ 229 ++sp->ccnt; 230 231 #if defined(DEBUG) && defined(COMLOG) 232 v_comlog(sp, vp); 233 #endif 234 /* Call the function. */ 235 ex_continue: if (vp->kp->func(sp, vp)) 236 goto err; 237 gc_event: 238 #ifdef DEBUG 239 /* Make sure no function left the temporary space locked. */ 240 if (F_ISSET(gp, G_TMP_INUSE)) { 241 F_CLR(gp, G_TMP_INUSE); 242 msgq(sp, M_ERR, 243 "232|vi: temporary buffer not released"); 244 } 245 #endif 246 /* 247 * If we're exiting this screen, move to the next one, or, if 248 * there aren't any more, return to the main editor loop. The 249 * ordering is careful, don't discard the contents of sp until 250 * the end. 251 */ 252 if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { 253 if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE))) 254 goto ret; 255 if (vs_discard(sp, &next)) 256 goto ret; 257 if (next == NULL && vs_swap(sp, &next, NULL)) 258 goto ret; 259 *spp = next; 260 if (screen_end(sp)) 261 goto ret; 262 if (next == NULL) 263 break; 264 265 /* Switch screens, change focus. */ 266 sp = next; 267 vip = VIP(sp); 268 (void)sp->gp->scr_rename(sp, sp->frp->name, 1); 269 270 /* Don't trust the cursor. */ 271 F_SET(vip, VIP_CUR_INVALID); 272 273 continue; 274 } 275 276 /* 277 * Set the dot command structure. 278 * 279 * !!! 280 * Historically, commands which used mapped keys did not 281 * set the dot command, with the exception of the text 282 * input commands. 283 */ 284 if (F_ISSET(vp, V_DOT) && !mapped) { 285 *DOT = cmd; 286 F_SET(DOT, VC_ISDOT); 287 288 /* 289 * If a count was supplied for both the command and 290 * its motion, the count was used only for the motion. 291 * Turn the count back on for the dot structure. 292 */ 293 if (F_ISSET(vp, VC_C1RESET)) 294 F_SET(DOT, VC_C1SET); 295 296 /* VM flags aren't retained. */ 297 F_CLR(DOT, VM_COMMASK | VM_RCM_MASK); 298 } 299 300 /* 301 * Some vi row movements are "attracted" to the last position 302 * set, i.e. the VM_RCM commands are moths to the VM_RCM_SET 303 * commands' candle. If the movement is to the EOL the vi 304 * command handles it. If it's to the beginning, we handle it 305 * here. 306 * 307 * Note, some commands (e.g. _, ^) don't set the VM_RCM_SETFNB 308 * flag, but do the work themselves. The reason is that they 309 * have to modify the column in case they're being used as a 310 * motion component. Other similar commands (e.g. +, -) don't 311 * have to modify the column because they are always line mode 312 * operations when used as motions, so the column number isn't 313 * of any interest. 314 * 315 * Does this totally violate the screen and editor layering? 316 * You betcha. As they say, if you think you understand it, 317 * you don't. 318 */ 319 switch (F_ISSET(vp, VM_RCM_MASK)) { 320 case 0: 321 case VM_RCM_SET: 322 break; 323 case VM_RCM: 324 vp->m_final.cno = vs_rcm(sp, 325 vp->m_final.lno, F_ISSET(vip, VIP_RCM_LAST)); 326 break; 327 case VM_RCM_SETLAST: 328 F_SET(vip, VIP_RCM_LAST); 329 break; 330 case VM_RCM_SETFNB: 331 vp->m_final.cno = 0; 332 /* FALLTHROUGH */ 333 case VM_RCM_SETNNB: 334 if (nonblank(sp, vp->m_final.lno, &vp->m_final.cno)) 335 goto err; 336 break; 337 default: 338 abort(); 339 } 340 341 /* Update the cursor. */ 342 sp->lno = vp->m_final.lno; 343 sp->cno = vp->m_final.cno; 344 345 /* 346 * Set the absolute mark -- set even if a tags or similar 347 * command, since the tag may be moving to the same file. 348 */ 349 if ((F_ISSET(vp, V_ABS) || 350 F_ISSET(vp, V_ABS_L) && sp->lno != abs.lno || 351 F_ISSET(vp, V_ABS_C) && 352 (sp->lno != abs.lno || sp->cno != abs.cno)) && 353 mark_set(sp, ABSMARK1, &abs, 1)) 354 goto err; 355 356 if (0) { 357 err: if (v_event_flush(sp, CH_MAPPED)) 358 msgq(sp, M_BERR, 359 "110|Vi command failed: mapped keys discarded"); 360 } 361 362 /* 363 * Check and clear interrupts. There's an obvious race, but 364 * it's not worth fixing. 365 */ 366 gc_err_noflush: if (INTERRUPTED(sp)) { 367 intr: CLR_INTERRUPT(sp); 368 if (v_event_flush(sp, CH_MAPPED)) 369 msgq(sp, M_ERR, 370 "231|Interrupted: mapped keys discarded"); 371 else 372 msgq(sp, M_ERR, "236|Interrupted"); 373 } 374 375 /* If the last command switched screens, update. */ 376 if (F_ISSET(sp, SC_SSWITCH)) { 377 F_CLR(sp, SC_SSWITCH); 378 379 /* 380 * If the current screen is still displayed, it will 381 * need a new status line. 382 */ 383 F_SET(sp, SC_STATUS); 384 385 /* Switch screens, change focus. */ 386 sp = sp->nextdisp; 387 vip = VIP(sp); 388 (void)sp->gp->scr_rename(sp, sp->frp->name, 1); 389 390 /* Don't trust the cursor. */ 391 F_SET(vip, VIP_CUR_INVALID); 392 393 /* Refresh so we can display messages. */ 394 if (vs_refresh(sp, 1)) 395 return (1); 396 } 397 398 /* If the last command switched files, change focus. */ 399 if (F_ISSET(sp, SC_FSWITCH)) { 400 F_CLR(sp, SC_FSWITCH); 401 (void)sp->gp->scr_rename(sp, sp->frp->name, 1); 402 } 403 404 /* If leaving vi, return to the main editor loop. */ 405 if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_EX)) { 406 *spp = sp; 407 v_dtoh(sp); 408 break; 409 } 410 } 411 if (0) 412 ret: rval = 1; 413 return (rval); 414 } 415 416 #define KEY(key, ec_flags) { \ 417 if ((gcret = v_key(sp, 0, &ev, ec_flags)) != GC_OK) \ 418 return (gcret); \ 419 if (ev.e_value == K_ESCAPE) \ 420 goto esc; \ 421 if (F_ISSET(&ev.e_ch, CH_MAPPED)) \ 422 *mappedp = 1; \ 423 key = ev.e_c; \ 424 } 425 426 /* 427 * The O_TILDEOP option makes the ~ command take a motion instead 428 * of a straight count. This is the replacement structure we use 429 * instead of the one currently in the VIKEYS table. 430 * 431 * XXX 432 * This should probably be deleted -- it's not all that useful, and 433 * we get help messages wrong. 434 */ 435 VIKEYS const tmotion = { 436 v_mulcase, V_CNT|V_DOT|V_MOTION|VM_RCM_SET, 437 "[count]~[count]motion", 438 " ~ change case to motion" 439 }; 440 441 /* 442 * v_cmd -- 443 * 444 * The command structure for vi is less complex than ex (and don't think 445 * I'm not grateful!) The command syntax is: 446 * 447 * [count] [buffer] [count] key [[motion] | [buffer] [character]] 448 * 449 * and there are several special cases. The motion value is itself a vi 450 * command, with the syntax: 451 * 452 * [count] key [character] 453 */ 454 static gcret_t 455 v_cmd(sp, dp, vp, ismotion, comcountp, mappedp) 456 SCR *sp; 457 VICMD *dp, *vp; 458 VICMD *ismotion; /* Previous key if getting motion component. */ 459 int *comcountp, *mappedp; 460 { 461 enum { COMMANDMODE, ISPARTIAL, NOTPARTIAL } cpart; 462 EVENT ev; 463 VIKEYS const *kp; 464 gcret_t gcret; 465 u_int flags; 466 CHAR_T key; 467 char *s; 468 469 /* 470 * Get a key. 471 * 472 * <escape> cancels partial commands, i.e. a command where at least 473 * one non-numeric character has been entered. Otherwise, it beeps 474 * the terminal. 475 * 476 * !!! 477 * POSIX 1003.2-1992 explicitly disallows cancelling commands where 478 * all that's been entered is a number, requiring that the terminal 479 * be alerted. 480 */ 481 cpart = ismotion == NULL ? COMMANDMODE : ISPARTIAL; 482 if ((gcret = 483 v_key(sp, ismotion == NULL, &ev, EC_MAPCOMMAND)) != GC_OK) { 484 if (gcret == GC_EVENT) 485 vp->ev = ev; 486 return (gcret); 487 } 488 if (ev.e_value == K_ESCAPE) 489 goto esc; 490 if (F_ISSET(&ev.e_ch, CH_MAPPED)) 491 *mappedp = 1; 492 key = ev.e_c; 493 494 if (ismotion == NULL) 495 cpart = NOTPARTIAL; 496 497 /* Pick up optional buffer. */ 498 if (key == '"') { 499 cpart = ISPARTIAL; 500 if (ismotion != NULL) { 501 v_emsg(sp, NULL, VIM_COMBUF); 502 return (GC_ERR); 503 } 504 KEY(vp->buffer, 0); 505 F_SET(vp, VC_BUFFER); 506 507 KEY(key, EC_MAPCOMMAND); 508 } 509 510 /* 511 * Pick up optional count, where a leading 0 is not a count, 512 * it's a command. 513 */ 514 if (isdigit(key) && key != '0') { 515 if (v_count(sp, key, &vp->count)) 516 return (GC_ERR); 517 F_SET(vp, VC_C1SET); 518 *comcountp = 1; 519 520 KEY(key, EC_MAPCOMMAND); 521 } else 522 *comcountp = 0; 523 524 /* Pick up optional buffer. */ 525 if (key == '"') { 526 cpart = ISPARTIAL; 527 if (F_ISSET(vp, VC_BUFFER)) { 528 msgq(sp, M_ERR, "234|Only one buffer may be specified"); 529 return (GC_ERR); 530 } 531 if (ismotion != NULL) { 532 v_emsg(sp, NULL, VIM_COMBUF); 533 return (GC_ERR); 534 } 535 KEY(vp->buffer, 0); 536 F_SET(vp, VC_BUFFER); 537 538 KEY(key, EC_MAPCOMMAND); 539 } 540 541 /* Check for an OOB command key. */ 542 cpart = ISPARTIAL; 543 if (key > MAXVIKEY) { 544 v_emsg(sp, KEY_NAME(sp, key), VIM_NOCOM); 545 return (GC_ERR); 546 } 547 kp = &vikeys[vp->key = key]; 548 549 /* 550 * !!! 551 * Historically, D accepted and then ignored a count. Match it. 552 */ 553 if (vp->key == 'D' && F_ISSET(vp, VC_C1SET)) { 554 *comcountp = 0; 555 vp->count = 0; 556 F_CLR(vp, VC_C1SET); 557 } 558 559 /* Check for command aliases. */ 560 if (kp->func == NULL && (kp = v_alias(sp, vp, kp)) == NULL) 561 return (GC_ERR); 562 563 /* The tildeop option makes the ~ command take a motion. */ 564 if (key == '~' && O_ISSET(sp, O_TILDEOP)) 565 kp = &tmotion; 566 567 vp->kp = kp; 568 569 /* 570 * Find the command. The only legal command with no underlying 571 * function is dot. It's historic practice that <escape> doesn't 572 * just erase the preceding number, it beeps the terminal as well. 573 * It's a common problem, so just beep the terminal unless verbose 574 * was set. 575 */ 576 if (kp->func == NULL) { 577 if (key != '.') { 578 v_emsg(sp, KEY_NAME(sp, key), 579 ev.e_value == K_ESCAPE ? VIM_NOCOM_B : VIM_NOCOM); 580 return (GC_ERR); 581 } 582 583 /* If called for a motion command, stop now. */ 584 if (dp == NULL) 585 goto usage; 586 587 /* 588 * !!! 589 * If a '.' is immediately entered after an undo command, we 590 * replay the log instead of redoing the last command. This 591 * is necessary because 'u' can't set the dot command -- see 592 * vi/v_undo.c:v_undo for details. 593 */ 594 if (VIP(sp)->u_ccnt == sp->ccnt) { 595 vp->kp = &vikeys['u']; 596 F_SET(vp, VC_ISDOT); 597 return (GC_OK); 598 } 599 600 /* Otherwise, a repeatable command must have been executed. */ 601 if (!F_ISSET(dp, VC_ISDOT)) { 602 msgq(sp, M_ERR, "208|No command to repeat"); 603 return (GC_ERR); 604 } 605 606 /* Set new count/buffer, if any, and return. */ 607 if (F_ISSET(vp, VC_C1SET)) { 608 F_SET(dp, VC_C1SET); 609 dp->count = vp->count; 610 } 611 if (F_ISSET(vp, VC_BUFFER)) 612 dp->buffer = vp->buffer; 613 614 *vp = *dp; 615 return (GC_OK); 616 } 617 618 /* Set the flags based on the command flags. */ 619 flags = kp->flags; 620 621 /* Check for illegal count. */ 622 if (F_ISSET(vp, VC_C1SET) && !LF_ISSET(V_CNT)) 623 goto usage; 624 625 /* Illegal motion command. */ 626 if (ismotion == NULL) { 627 /* Illegal buffer. */ 628 if (!LF_ISSET(V_OBUF) && F_ISSET(vp, VC_BUFFER)) 629 goto usage; 630 631 /* Required buffer. */ 632 if (LF_ISSET(V_RBUF)) { 633 KEY(vp->buffer, 0); 634 F_SET(vp, VC_BUFFER); 635 } 636 } 637 638 /* 639 * Special case: '[', ']' and 'Z' commands. Doesn't the fact that 640 * the *single* characters don't mean anything but the *doubled* 641 * characters do, just frost your shorts? 642 */ 643 if (vp->key == '[' || vp->key == ']' || vp->key == 'Z') { 644 /* 645 * Historically, half entered [[, ]] or Z commands weren't 646 * cancelled by <escape>, the terminal was beeped instead. 647 * POSIX.2-1992 probably didn't notice, and requires that 648 * they be cancelled instead of beeping. Seems fine to me. 649 * 650 * Don't set the EC_MAPCOMMAND flag, apparently ] is a popular 651 * vi meta-character, and we don't want the user to wait while 652 * we time out a possible mapping. This *appears* to match 653 * historic vi practice, but with mapping characters, you Just 654 * Never Know. 655 */ 656 KEY(key, 0); 657 658 if (vp->key != key) { 659 usage: if (ismotion == NULL) 660 s = kp->usage; 661 else if (ismotion->key == '~' && O_ISSET(sp, O_TILDEOP)) 662 s = tmotion.usage; 663 else 664 s = vikeys[ismotion->key].usage; 665 v_emsg(sp, s, VIM_USAGE); 666 return (GC_ERR); 667 } 668 } 669 /* Special case: 'z' command. */ 670 if (vp->key == 'z') { 671 KEY(vp->character, 0); 672 if (isdigit(vp->character)) { 673 if (v_count(sp, vp->character, &vp->count2)) 674 return (GC_ERR); 675 F_SET(vp, VC_C2SET); 676 KEY(vp->character, 0); 677 } 678 } 679 680 /* 681 * Commands that have motion components can be doubled to 682 * imply the current line. 683 */ 684 if (ismotion != NULL && ismotion->key != key && !LF_ISSET(V_MOVE)) { 685 msgq(sp, M_ERR, "210|%s may not be used as a motion command", 686 KEY_NAME(sp, key)); 687 return (GC_ERR); 688 } 689 690 /* Required character. */ 691 if (LF_ISSET(V_CHAR)) 692 KEY(vp->character, 0); 693 694 /* Get any associated cursor word. */ 695 if (F_ISSET(kp, V_KEYW) && v_keyword(sp)) 696 return (GC_ERR); 697 698 return (GC_OK); 699 700 esc: switch (cpart) { 701 case COMMANDMODE: 702 msgq(sp, M_BERR, "211|Already in command mode"); 703 return (GC_ERR_NOFLUSH); 704 case ISPARTIAL: 705 break; 706 case NOTPARTIAL: 707 (void)sp->gp->scr_bell(sp); 708 break; 709 } 710 return (GC_ERR); 711 } 712 713 /* 714 * v_motion -- 715 * 716 * Get resulting motion mark. 717 */ 718 static int 719 v_motion(sp, dm, vp, mappedp) 720 SCR *sp; 721 VICMD *dm, *vp; 722 int *mappedp; 723 { 724 VICMD motion; 725 size_t len; 726 u_long cnt; 727 u_int flags; 728 int tilde_reset, notused; 729 730 /* 731 * If '.' command, use the dot motion, else get the motion command. 732 * Clear any line motion flags, the subsequent motion isn't always 733 * the same, i.e. "/aaa" may or may not be a line motion. 734 */ 735 if (F_ISSET(vp, VC_ISDOT)) { 736 motion = *dm; 737 F_SET(&motion, VC_ISDOT); 738 F_CLR(&motion, VM_COMMASK); 739 } else { 740 memset(&motion, 0, sizeof(VICMD)); 741 if (v_cmd(sp, NULL, &motion, vp, ¬used, mappedp) != GC_OK) 742 return (1); 743 } 744 745 /* 746 * A count may be provided both to the command and to the motion, in 747 * which case the count is multiplicative. For example, "3y4y" is the 748 * same as "12yy". This count is provided to the motion command and 749 * not to the regular function. 750 */ 751 cnt = motion.count = F_ISSET(&motion, VC_C1SET) ? motion.count : 1; 752 if (F_ISSET(vp, VC_C1SET)) { 753 motion.count *= vp->count; 754 F_SET(&motion, VC_C1SET); 755 756 /* 757 * Set flags to restore the original values of the command 758 * structure so dot commands can change the count values, 759 * e.g. "2dw" "3." deletes a total of five words. 760 */ 761 F_CLR(vp, VC_C1SET); 762 F_SET(vp, VC_C1RESET); 763 } 764 765 /* 766 * Some commands can be repeated to indicate the current line. In 767 * this case, or if the command is a "line command", set the flags 768 * appropriately. If not a doubled command, run the function to get 769 * the resulting mark. 770 */ 771 if (vp->key == motion.key) { 772 F_SET(vp, VM_LDOUBLE | VM_LMODE); 773 774 /* Set the origin of the command. */ 775 vp->m_start.lno = sp->lno; 776 vp->m_start.cno = 0; 777 778 /* 779 * Set the end of the command. 780 * 781 * If the current line is missing, i.e. the file is empty, 782 * historic vi permitted a "cc" or "!!" command to insert 783 * text. 784 */ 785 vp->m_stop.lno = sp->lno + motion.count - 1; 786 if (db_get(sp, vp->m_stop.lno, 0, NULL, &len)) { 787 if (vp->m_stop.lno != 1 || 788 vp->key != 'c' && vp->key != '!') { 789 v_emsg(sp, NULL, VIM_EMPTY); 790 return (1); 791 } 792 vp->m_stop.cno = 0; 793 } else 794 vp->m_stop.cno = len ? len - 1 : 0; 795 } else { 796 /* 797 * Motion commands change the underlying movement (*snarl*). 798 * For example, "l" is illegal at the end of a line, but "dl" 799 * is not. Set flags so the function knows the situation. 800 */ 801 motion.rkp = vp->kp; 802 803 /* 804 * XXX 805 * Use yank instead of creating a new motion command, it's a 806 * lot easier for now. 807 */ 808 if (vp->kp == &tmotion) { 809 tilde_reset = 1; 810 vp->kp = &vikeys['y']; 811 } else 812 tilde_reset = 0; 813 814 /* 815 * Copy the key flags into the local structure, except for the 816 * RCM flags -- the motion command will set the RCM flags in 817 * the vp structure if necessary. This means that the motion 818 * command is expected to determine where the cursor ends up! 819 * However, we save off the current RCM mask and restore it if 820 * it no RCM flags are set by the motion command, with a small 821 * modification. 822 * 823 * We replace the VM_RCM_SET flag with the VM_RCM flag. This 824 * is so that cursor movement doesn't set the relative position 825 * unless the motion command explicitly specified it. This 826 * appears to match historic practice, but I've never been able 827 * to develop a hard-and-fast rule. 828 */ 829 flags = F_ISSET(vp, VM_RCM_MASK); 830 if (LF_ISSET(VM_RCM_SET)) { 831 LF_SET(VM_RCM); 832 LF_CLR(VM_RCM_SET); 833 } 834 F_CLR(vp, VM_RCM_MASK); 835 F_SET(&motion, motion.kp->flags & ~VM_RCM_MASK); 836 837 /* 838 * Set the three cursor locations to the current cursor. This 839 * permits commands like 'j' and 'k', that are line oriented 840 * motions and have special cursor suck semantics when they are 841 * used as standalone commands, to ignore column positioning. 842 */ 843 motion.m_final.lno = 844 motion.m_stop.lno = motion.m_start.lno = sp->lno; 845 motion.m_final.cno = 846 motion.m_stop.cno = motion.m_start.cno = sp->cno; 847 848 /* Run the function. */ 849 if ((motion.kp->func)(sp, &motion)) 850 return (1); 851 852 /* 853 * If the current line is missing, i.e. the file is empty, 854 * historic vi allowed "c<motion>" or "!<motion>" to insert 855 * text. Otherwise fail -- most motion commands will have 856 * already failed, but some, e.g. G, succeed in empty files. 857 */ 858 if (!db_exist(sp, vp->m_stop.lno)) { 859 if (vp->m_stop.lno != 1 || 860 vp->key != 'c' && vp->key != '!') { 861 v_emsg(sp, NULL, VIM_EMPTY); 862 return (1); 863 } 864 vp->m_stop.cno = 0; 865 } 866 867 /* 868 * XXX 869 * See above. 870 */ 871 if (tilde_reset) 872 vp->kp = &tmotion; 873 874 /* 875 * Copy cut buffer, line mode and cursor position information 876 * from the motion command structure, i.e. anything that the 877 * motion command can set for us. The commands can flag the 878 * movement as a line motion (see v_sentence) as well as set 879 * the VM_RCM_* flags explicitly. 880 */ 881 F_SET(vp, F_ISSET(&motion, VM_COMMASK | VM_RCM_MASK)); 882 883 /* 884 * If the motion command set no relative motion flags, use 885 * the (slightly) modified previous values. 886 */ 887 if (!F_ISSET(vp, VM_RCM_MASK)) 888 F_SET(vp, flags); 889 890 /* 891 * Commands can change behaviors based on the motion command 892 * used, for example, the ! command repeated the last bang 893 * command if N or n was used as the motion. 894 */ 895 vp->rkp = motion.kp; 896 897 /* 898 * Motion commands can reset all of the cursor information. 899 * If the motion is in the reverse direction, switch the 900 * from and to MARK's so that it's in a forward direction. 901 * Motions are from the from MARK to the to MARK (inclusive). 902 */ 903 if (motion.m_start.lno > motion.m_stop.lno || 904 motion.m_start.lno == motion.m_stop.lno && 905 motion.m_start.cno > motion.m_stop.cno) { 906 vp->m_start = motion.m_stop; 907 vp->m_stop = motion.m_start; 908 } else { 909 vp->m_start = motion.m_start; 910 vp->m_stop = motion.m_stop; 911 } 912 vp->m_final = motion.m_final; 913 } 914 915 /* 916 * If the command sets dot, save the motion structure. The motion 917 * count was changed above and needs to be reset, that's why this 918 * is done here, and not in the calling routine. 919 */ 920 if (F_ISSET(vp->kp, V_DOT)) { 921 *dm = motion; 922 dm->count = cnt; 923 } 924 return (0); 925 } 926 927 /* 928 * v_init -- 929 * Initialize the vi screen. 930 */ 931 static int 932 v_init(sp) 933 SCR *sp; 934 { 935 GS *gp; 936 VI_PRIVATE *vip; 937 938 gp = sp->gp; 939 vip = VIP(sp); 940 941 /* Switch into vi. */ 942 if (gp->scr_screen(sp, SC_VI)) 943 return (1); 944 (void)gp->scr_attr(sp, SA_ALTERNATE, 1); 945 946 F_CLR(sp, SC_EX | SC_SCR_EX); 947 F_SET(sp, SC_VI); 948 949 /* 950 * Initialize screen values. 951 * 952 * Small windows: see vs_refresh(), section 6a. 953 * 954 * Setup: 955 * t_minrows is the minimum rows to display 956 * t_maxrows is the maximum rows to display (rows - 1) 957 * t_rows is the rows currently being displayed 958 */ 959 sp->rows = vip->srows = O_VAL(sp, O_LINES); 960 sp->cols = O_VAL(sp, O_COLUMNS); 961 sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW); 962 if (sp->rows != 1) { 963 if (sp->t_rows > sp->rows - 1) { 964 sp->t_minrows = sp->t_rows = sp->rows - 1; 965 msgq(sp, M_INFO, 966 "214|Windows option value is too large, max is %u", 967 sp->t_rows); 968 } 969 sp->t_maxrows = sp->rows - 1; 970 } else 971 sp->t_maxrows = 1; 972 sp->woff = 0; 973 974 /* Create a screen map. */ 975 CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP)); 976 TMAP = HMAP + (sp->t_rows - 1); 977 HMAP->lno = sp->lno; 978 HMAP->coff = 0; 979 HMAP->soff = 1; 980 981 /* 982 * Fill the screen map from scratch -- try and center the line. That 983 * way if we're starting with a file we've seen before, we'll put the 984 * line in the middle, otherwise, it won't work and we'll end up with 985 * the line at the top. 986 */ 987 F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER); 988 989 /* Invalidate the cursor. */ 990 F_SET(vip, VIP_CUR_INVALID); 991 992 /* Paint the screen image from scratch. */ 993 F_SET(vip, VIP_N_EX_PAINT); 994 995 return (0); 996 } 997 998 /* 999 * v_dtoh -- 1000 * Move all but the current screen to the hidden queue. 1001 */ 1002 static void 1003 v_dtoh(sp) 1004 SCR *sp; 1005 { 1006 GS *gp; 1007 SCR *tsp; 1008 int hidden; 1009 1010 /* Move all screens to the hidden queue, tossing screen maps. */ 1011 for (hidden = 0, gp = sp->gp; 1012 (tsp = gp->dq.cqh_first) != (void *)&gp->dq; ++hidden) { 1013 if (_HMAP(tsp) != NULL) { 1014 free(_HMAP(tsp)); 1015 _HMAP(tsp) = NULL; 1016 } 1017 CIRCLEQ_REMOVE(&gp->dq, tsp, q); 1018 CIRCLEQ_INSERT_TAIL(&gp->hq, tsp, q); 1019 } 1020 1021 /* Move current screen back to the display queue. */ 1022 CIRCLEQ_REMOVE(&gp->hq, sp, q); 1023 CIRCLEQ_INSERT_TAIL(&gp->dq, sp, q); 1024 1025 /* 1026 * XXX 1027 * Don't bother internationalizing this message, it's going to 1028 * go away as soon as we have one-line screens. --TK 1029 */ 1030 if (hidden > 1) 1031 msgq(sp, M_INFO, 1032 "%d screens backgrounded; use :display to list them", 1033 hidden - 1); 1034 } 1035 1036 /* 1037 * v_keyword -- 1038 * Get the word (or non-word) the cursor is on. 1039 */ 1040 static int 1041 v_keyword(sp) 1042 SCR *sp; 1043 { 1044 VI_PRIVATE *vip; 1045 size_t beg, end, len; 1046 int moved, state; 1047 char *p; 1048 1049 if (db_get(sp, sp->lno, DBG_FATAL, &p, &len)) 1050 return (1); 1051 1052 /* 1053 * !!! 1054 * Historically, tag commands skipped over any leading whitespace 1055 * characters. Make this true in general when using cursor words. 1056 * If movement, getting a cursor word implies moving the cursor to 1057 * its beginning. Refresh now. 1058 * 1059 * !!! 1060 * Find the beginning/end of the keyword. Keywords are currently 1061 * used for cursor-word searching and for tags. Historical vi 1062 * only used the word in a tag search from the cursor to the end 1063 * of the word, i.e. if the cursor was on the 'b' in " abc ", the 1064 * tag was "bc". For consistency, we make cursor word searches 1065 * follow the same rule. 1066 */ 1067 for (moved = 0, 1068 beg = sp->cno; beg < len && isspace(p[beg]); moved = 1, ++beg); 1069 if (beg >= len) { 1070 msgq(sp, M_BERR, "212|Cursor not in a word"); 1071 return (1); 1072 } 1073 if (moved) { 1074 sp->cno = beg; 1075 (void)vs_refresh(sp, 0); 1076 } 1077 1078 /* Find the end of the word. */ 1079 for (state = inword(p[beg]), 1080 end = beg; ++end < len && state == inword(p[end]);); 1081 1082 vip = VIP(sp); 1083 len = (end - beg); 1084 BINC_RET(sp, vip->keyw, vip->klen, len); 1085 memmove(vip->keyw, p + beg, len); 1086 vip->keyw[len] = '\0'; /* XXX */ 1087 return (0); 1088 } 1089 1090 /* 1091 * v_alias -- 1092 * Check for a command alias. 1093 */ 1094 static VIKEYS const * 1095 v_alias(sp, vp, kp) 1096 SCR *sp; 1097 VICMD *vp; 1098 VIKEYS const *kp; 1099 { 1100 CHAR_T push; 1101 1102 switch (vp->key) { 1103 case 'C': /* C -> c$ */ 1104 push = '$'; 1105 vp->key = 'c'; 1106 break; 1107 case 'D': /* D -> d$ */ 1108 push = '$'; 1109 vp->key = 'd'; 1110 break; 1111 case 'S': /* S -> c_ */ 1112 push = '_'; 1113 vp->key = 'c'; 1114 break; 1115 case 'Y': /* Y -> y_ */ 1116 push = '_'; 1117 vp->key = 'y'; 1118 break; 1119 default: 1120 return (kp); 1121 } 1122 return (v_event_push(sp, 1123 NULL, &push, 1, CH_NOMAP | CH_QUOTED) ? NULL : &vikeys[vp->key]); 1124 } 1125 1126 /* 1127 * v_count -- 1128 * Return the next count. 1129 */ 1130 static int 1131 v_count(sp, fkey, countp) 1132 SCR *sp; 1133 ARG_CHAR_T fkey; 1134 u_long *countp; 1135 { 1136 EVENT ev; 1137 u_long count, tc; 1138 1139 ev.e_c = fkey; 1140 count = tc = 0; 1141 do { 1142 /* 1143 * XXX 1144 * Assume that overflow results in a smaller number. 1145 */ 1146 tc = count * 10 + ev.e_c - '0'; 1147 if (count > tc) { 1148 /* Toss to the next non-digit. */ 1149 do { 1150 if (v_key(sp, 0, &ev, 1151 EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK) 1152 return (1); 1153 } while (isdigit(ev.e_c)); 1154 msgq(sp, M_ERR, 1155 "235|Number larger than %lu", ULONG_MAX); 1156 return (1); 1157 } 1158 count = tc; 1159 if (v_key(sp, 0, &ev, EC_MAPCOMMAND | EC_MAPNODIGIT) != GC_OK) 1160 return (1); 1161 } while (isdigit(ev.e_c)); 1162 *countp = count; 1163 return (0); 1164 } 1165 1166 /* 1167 * v_key -- 1168 * Return the next event. 1169 */ 1170 static gcret_t 1171 v_key(sp, command_events, evp, ec_flags) 1172 SCR *sp; 1173 int command_events; 1174 EVENT *evp; 1175 u_int32_t ec_flags; 1176 { 1177 u_int32_t quote; 1178 1179 for (quote = 0;;) { 1180 if (v_event_get(sp, evp, 0, ec_flags | quote)) 1181 return (GC_FATAL); 1182 quote = 0; 1183 1184 switch (evp->e_event) { 1185 case E_CHARACTER: 1186 /* 1187 * !!! 1188 * Historically, ^V was ignored in the command stream, 1189 * although it had a useful side-effect of interrupting 1190 * mappings. Adding a quoting bit to the call probably 1191 * extends historic practice, but it feels right. 1192 */ 1193 if (evp->e_value == K_VLNEXT) { 1194 quote = EC_QUOTED; 1195 break; 1196 } 1197 return (GC_OK); 1198 case E_ERR: 1199 case E_EOF: 1200 return (GC_FATAL); 1201 case E_INTERRUPT: 1202 /* 1203 * !!! 1204 * Historically, vi beeped on command level interrupts. 1205 * 1206 * Historically, vi exited to ex mode if no file was 1207 * named on the command line, and two interrupts were 1208 * generated in a row. (Just figured you might want 1209 * to know that.) 1210 */ 1211 (void)sp->gp->scr_bell(sp); 1212 return (GC_INTERRUPT); 1213 case E_REPAINT: 1214 if (vs_repaint(sp, evp)) 1215 return (GC_FATAL); 1216 break; 1217 case E_WRESIZE: 1218 return (GC_ERR); 1219 case E_QUIT: 1220 case E_WRITE: 1221 if (command_events) 1222 return (GC_EVENT); 1223 /* FALLTHROUGH */ 1224 default: 1225 v_event_err(sp, evp); 1226 return (GC_ERR); 1227 } 1228 } 1229 /* NOTREACHED */ 1230 } 1231 1232 #if defined(DEBUG) && defined(COMLOG) 1233 /* 1234 * v_comlog -- 1235 * Log the contents of the command structure. 1236 */ 1237 static void 1238 v_comlog(sp, vp) 1239 SCR *sp; 1240 VICMD *vp; 1241 { 1242 TRACE(sp, "vcmd: %c", vp->key); 1243 if (F_ISSET(vp, VC_BUFFER)) 1244 TRACE(sp, " buffer: %c", vp->buffer); 1245 if (F_ISSET(vp, VC_C1SET)) 1246 TRACE(sp, " c1: %lu", vp->count); 1247 if (F_ISSET(vp, VC_C2SET)) 1248 TRACE(sp, " c2: %lu", vp->count2); 1249 TRACE(sp, " flags: 0x%x\n", vp->flags); 1250 } 1251 #endif 1252