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