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