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