1 /*- 2 * Copyright (c) 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 #include <sys/types.h> 13 #include <sys/queue.h> 14 #include <sys/stat.h> 15 16 #include <bitstring.h> 17 #include <ctype.h> 18 #include <errno.h> 19 #include <limits.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include "../common/common.h" 26 #include "vi.h" 27 28 static int txt_abbrev(SCR *, TEXT *, CHAR_T *, int, int *, int *); 29 static void txt_ai_resolve(SCR *, TEXT *, int *); 30 static TEXT *txt_backup(SCR *, TEXTH *, TEXT *, u_int32_t *); 31 static int txt_dent(SCR *, TEXT *, int, int); 32 static int txt_emark(SCR *, TEXT *, size_t); 33 static void txt_err(SCR *, TEXTH *); 34 static int txt_fc(SCR *, TEXT *, int *); 35 static int txt_fc_col(SCR *, int, ARGS **); 36 static int txt_hex(SCR *, TEXT *); 37 static int txt_insch(SCR *, TEXT *, CHAR_T *, u_int); 38 static int txt_isrch(SCR *, VICMD *, TEXT *, u_int8_t *); 39 static int txt_map_end(SCR *); 40 static int txt_map_init(SCR *); 41 static int txt_margin(SCR *, TEXT *, TEXT *, int *, u_int32_t); 42 static void txt_nomorech(SCR *); 43 static void txt_Rresolve(SCR *, TEXTH *, TEXT *, const size_t); 44 static int txt_resolve(SCR *, TEXTH *, u_int32_t); 45 static int txt_showmatch(SCR *, TEXT *); 46 static void txt_unmap(SCR *, TEXT *, u_int32_t *); 47 48 /* Cursor character (space is hard to track on the screen). */ 49 #if defined(DEBUG) && 0 50 #undef CH_CURSOR 51 #define CH_CURSOR '+' 52 #endif 53 54 /* 55 * v_tcmd -- 56 * Fill a buffer from the terminal for vi. 57 * 58 * PUBLIC: int v_tcmd(SCR *, VICMD *, ARG_CHAR_T, u_int); 59 */ 60 int 61 v_tcmd(SCR *sp, VICMD *vp, ARG_CHAR_T prompt, u_int flags) 62 { 63 /* Normally, we end up where we started. */ 64 vp->m_final.lno = sp->lno; 65 vp->m_final.cno = sp->cno; 66 67 /* Initialize the map. */ 68 if (txt_map_init(sp)) 69 return (1); 70 71 /* Move to the last line. */ 72 sp->lno = TMAP[0].lno; 73 sp->cno = 0; 74 75 /* Don't update the modeline for now. */ 76 F_SET(sp, SC_TINPUT_INFO); 77 78 /* Set the input flags. */ 79 LF_SET(TXT_APPENDEOL | 80 TXT_CR | TXT_ESCAPE | TXT_INFOLINE | TXT_MAPINPUT); 81 if (O_ISSET(sp, O_ALTWERASE)) 82 LF_SET(TXT_ALTWERASE); 83 if (O_ISSET(sp, O_TTYWERASE)) 84 LF_SET(TXT_TTYWERASE); 85 86 /* Do the input thing. */ 87 if (v_txt(sp, vp, NULL, NULL, 0, prompt, 0, 1, flags)) 88 return (1); 89 90 /* Reenable the modeline updates. */ 91 F_CLR(sp, SC_TINPUT_INFO); 92 93 /* Clean up the map. */ 94 if (txt_map_end(sp)) 95 return (1); 96 97 if (IS_ONELINE(sp)) 98 F_SET(sp, SC_SCR_REDRAW); /* XXX */ 99 100 /* Set the cursor to the resulting position. */ 101 sp->lno = vp->m_final.lno; 102 sp->cno = vp->m_final.cno; 103 104 return (0); 105 } 106 107 /* 108 * txt_map_init 109 * Initialize the screen map for colon command-line input. 110 */ 111 static int 112 txt_map_init(SCR *sp) 113 { 114 SMAP *esmp; 115 VI_PRIVATE *vip; 116 117 vip = VIP(sp); 118 if (!IS_ONELINE(sp)) { 119 /* 120 * Fake like the user is doing input on the last line of the 121 * screen. This makes all of the scrolling work correctly, 122 * and allows us the use of the vi text editing routines, not 123 * to mention practically infinite length ex commands. 124 * 125 * Save the current location. 126 */ 127 vip->sv_tm_lno = TMAP->lno; 128 vip->sv_tm_soff = TMAP->soff; 129 vip->sv_tm_coff = TMAP->coff; 130 vip->sv_t_maxrows = sp->t_maxrows; 131 vip->sv_t_minrows = sp->t_minrows; 132 vip->sv_t_rows = sp->t_rows; 133 134 /* 135 * If it's a small screen, TMAP may be small for the screen. 136 * Fix it, filling in fake lines as we go. 137 */ 138 if (IS_SMALL(sp)) 139 for (esmp = 140 HMAP + (sp->t_maxrows - 1); TMAP < esmp; ++TMAP) { 141 TMAP[1].lno = TMAP[0].lno + 1; 142 TMAP[1].coff = HMAP->coff; 143 TMAP[1].soff = 1; 144 } 145 146 /* Build the fake entry. */ 147 TMAP[1].lno = TMAP[0].lno + 1; 148 TMAP[1].soff = 1; 149 TMAP[1].coff = 0; 150 SMAP_FLUSH(&TMAP[1]); 151 ++TMAP; 152 153 /* Reset the screen information. */ 154 sp->t_rows = sp->t_minrows = ++sp->t_maxrows; 155 } 156 return (0); 157 } 158 159 /* 160 * txt_map_end 161 * Reset the screen map for colon command-line input. 162 */ 163 static int 164 txt_map_end(SCR *sp) 165 { 166 VI_PRIVATE *vip; 167 size_t cnt; 168 169 vip = VIP(sp); 170 if (!IS_ONELINE(sp)) { 171 /* Restore the screen information. */ 172 sp->t_rows = vip->sv_t_rows; 173 sp->t_minrows = vip->sv_t_minrows; 174 sp->t_maxrows = vip->sv_t_maxrows; 175 176 /* 177 * If it's a small screen, TMAP may be wrong. Clear any 178 * lines that might have been overwritten. 179 */ 180 if (IS_SMALL(sp)) { 181 for (cnt = sp->t_rows; cnt <= sp->t_maxrows; ++cnt) { 182 (void)sp->gp->scr_move(sp, cnt, 0); 183 (void)sp->gp->scr_clrtoeol(sp); 184 } 185 TMAP = HMAP + (sp->t_rows - 1); 186 } else 187 --TMAP; 188 189 /* 190 * The map may be wrong if the user entered more than one 191 * (logical) line. Fix it. If the user entered a whole 192 * screen, this will be slow, but we probably don't care. 193 */ 194 if (!O_ISSET(sp, O_LEFTRIGHT)) 195 while (vip->sv_tm_lno != TMAP->lno || 196 vip->sv_tm_soff != TMAP->soff) 197 if (vs_sm_1down(sp)) 198 return (1); 199 } 200 201 /* 202 * Invalidate the cursor and the line size cache, the line never 203 * really existed. This fixes bugs where the user searches for 204 * the last line on the screen + 1 and the refresh routine thinks 205 * that's where we just were. 206 */ 207 VI_SCR_CFLUSH(vip); 208 F_SET(vip, VIP_CUR_INVALID); 209 210 return (0); 211 } 212 213 /* 214 * If doing input mapping on the colon command line, may need to unmap 215 * based on the command. 216 */ 217 #define UNMAP_TST \ 218 FL_ISSET(ec_flags, EC_MAPINPUT) && LF_ISSET(TXT_INFOLINE) 219 220 /* 221 * Internally, we maintain tp->lno and tp->cno, externally, everyone uses 222 * sp->lno and sp->cno. Make them consistent as necessary. 223 */ 224 #define UPDATE_POSITION(sp, tp) do { \ 225 (sp)->lno = (tp)->lno; \ 226 (sp)->cno = (tp)->cno; \ 227 } while (0) 228 229 /* 230 * v_txt -- 231 * Vi text input. 232 * 233 * PUBLIC: int v_txt(SCR *, VICMD *, MARK *, 234 * PUBLIC: const CHAR_T *, size_t, ARG_CHAR_T, recno_t, u_long, u_int32_t); 235 */ 236 int 237 v_txt( 238 SCR *sp, 239 VICMD *vp, 240 MARK *tm, /* To MARK. */ 241 const CHAR_T *lp, /* Input line. */ 242 size_t len, /* Input line length. */ 243 ARG_CHAR_T prompt, /* Prompt to display. */ 244 recno_t ai_line, /* Line number to use for autoindent count. */ 245 u_long rcount, /* Replay count. */ 246 u_int32_t flags) /* TXT_* flags. */ 247 { 248 EVENT ev, *evp = NULL; /* Current event. */ 249 EVENT fc; /* File name completion event. */ 250 GS *gp; 251 TEXT *ntp, *tp; /* Input text structures. */ 252 TEXT ait; /* Autoindent text structure. */ 253 TEXT wmt = {{ 0 }}; /* Wrapmargin text structure. */ 254 TEXTH *tiqh; 255 VI_PRIVATE *vip; 256 abb_t abb; /* State of abbreviation checks. */ 257 carat_t carat; /* State of the "[^0]^D" sequences. */ 258 quote_t quote; /* State of quotation. */ 259 size_t owrite, insert; /* Temporary copies of TEXT fields. */ 260 size_t margin; /* Wrapmargin value. */ 261 size_t rcol; /* 0-N: insert offset in the replay buffer. */ 262 size_t tcol; /* Temporary column. */ 263 u_int32_t ec_flags; /* Input mapping flags. */ 264 #define IS_RESTART 0x01 /* Reset the incremental search. */ 265 #define IS_RUNNING 0x02 /* Incremental search turned on. */ 266 u_int8_t is_flags; 267 int abcnt, ab_turnoff; /* Abbreviation character count, switch. */ 268 int filec_redraw; /* Redraw after the file completion routine. */ 269 int hexcnt; /* Hex character count. */ 270 int showmatch; /* Showmatch set on this character. */ 271 int wm_set, wm_skip; /* Wrapmargin happened, blank skip flags. */ 272 int max, tmp; 273 int nochange; 274 CHAR_T *p; 275 276 gp = sp->gp; 277 vip = VIP(sp); 278 279 /* 280 * Set the input flag, so tabs get displayed correctly 281 * and everyone knows that the text buffer is in use. 282 */ 283 F_SET(sp, SC_TINPUT); 284 285 /* 286 * Get one TEXT structure with some initial buffer space, reusing 287 * the last one if it's big enough. (All TEXT bookkeeping fields 288 * default to 0 -- text_init() handles this.) If changing a line, 289 * copy it into the TEXT buffer. 290 */ 291 tiqh = sp->tiq; 292 if (!TAILQ_EMPTY(tiqh)) { 293 tp = TAILQ_FIRST(tiqh); 294 if (TAILQ_NEXT(tp, q) != NULL || 295 tp->lb_len < (len + 32) * sizeof(CHAR_T)) { 296 text_lfree(tiqh); 297 goto newtp; 298 } 299 tp->ai = tp->insert = tp->offset = tp->owrite = 0; 300 if (lp != NULL) { 301 tp->len = len; 302 BINC_RETW(sp, tp->lb, tp->lb_len, len); 303 MEMMOVE(tp->lb, lp, len); 304 } else 305 tp->len = 0; 306 } else { 307 newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL) 308 return (1); 309 TAILQ_INSERT_HEAD(tiqh, tp, q); 310 } 311 312 /* Set default termination condition. */ 313 tp->term = TERM_OK; 314 315 /* Set the starting line, column. */ 316 tp->lno = sp->lno; 317 tp->cno = sp->cno; 318 319 /* 320 * Set the insert and overwrite counts. If overwriting characters, 321 * do insertion afterward. If not overwriting characters, assume 322 * doing insertion. If change is to a mark, emphasize it with an 323 * CH_ENDMARK character. 324 */ 325 if (len) { 326 if (LF_ISSET(TXT_OVERWRITE)) { 327 tp->owrite = (tm->cno - tp->cno) + 1; 328 tp->insert = (len - tm->cno) - 1; 329 } else 330 tp->insert = len - tp->cno; 331 332 if (LF_ISSET(TXT_EMARK) && txt_emark(sp, tp, tm->cno)) 333 return (1); 334 } 335 336 /* 337 * Many of the special cases in text input are to handle autoindent 338 * support. Somebody decided that it would be a good idea if "^^D" 339 * and "0^D" deleted all of the autoindented characters. In an editor 340 * that takes single character input from the user, this beggars the 341 * imagination. Note also, "^^D" resets the next lines' autoindent, 342 * but "0^D" doesn't. 343 * 344 * We assume that autoindent only happens on empty lines, so insert 345 * and overwrite will be zero. If doing autoindent, figure out how 346 * much indentation we need and fill it in. Update input column and 347 * screen cursor as necessary. 348 */ 349 if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) { 350 if (v_txt_auto(sp, ai_line, NULL, 0, tp)) 351 return (1); 352 tp->cno = tp->ai; 353 } else { 354 /* 355 * The cc and S commands have a special feature -- leading 356 * <blank> characters are handled as autoindent characters. 357 * Beauty! 358 */ 359 if (LF_ISSET(TXT_AICHARS)) { 360 tp->offset = 0; 361 tp->ai = tp->cno; 362 } else 363 tp->offset = tp->cno; 364 } 365 366 /* If getting a command buffer from the user, there may be a prompt. */ 367 if (LF_ISSET(TXT_PROMPT)) { 368 tp->lb[tp->cno++] = prompt; 369 ++tp->len; 370 ++tp->offset; 371 } 372 373 /* 374 * If appending after the end-of-line, add a space into the buffer 375 * and move the cursor right. This space is inserted, i.e. pushed 376 * along, and then deleted when the line is resolved. Assumes that 377 * the cursor is already positioned at the end of the line. This 378 * avoids the nastiness of having the cursor reside on a magical 379 * column, i.e. a column that doesn't really exist. The only down 380 * side is that we may wrap lines or scroll the screen before it's 381 * strictly necessary. Not a big deal. 382 */ 383 if (LF_ISSET(TXT_APPENDEOL)) { 384 tp->lb[tp->cno] = CH_CURSOR; 385 ++tp->len; 386 ++tp->insert; 387 (void)vs_change(sp, tp->lno, LINE_RESET); 388 } 389 390 /* 391 * Historic practice is that the wrapmargin value was a distance 392 * from the RIGHT-HAND margin, not the left. It's more useful to 393 * us as a distance from the left-hand margin, i.e. the same as 394 * the wraplen value. The wrapmargin option is historic practice. 395 * Nvi added the wraplen option so that it would be possible to 396 * edit files with consistent margins without knowing the number of 397 * columns in the window. 398 * 399 * XXX 400 * Setting margin causes a significant performance hit. Normally 401 * we don't update the screen if there are keys waiting, but we 402 * have to if margin is set, otherwise the screen routines don't 403 * know where the cursor is. 404 * 405 * !!! 406 * Abbreviated keys were affected by the wrapmargin option in the 407 * historic 4BSD vi. Mapped keys were usually, but sometimes not. 408 * See the comment in vi/v_text():set_txt_std for more information. 409 * 410 * !!! 411 * One more special case. If an inserted <blank> character causes 412 * wrapmargin to split the line, the next user entered character is 413 * discarded if it's a <space> character. 414 */ 415 wm_set = wm_skip = 0; 416 if (LF_ISSET(TXT_WRAPMARGIN)) 417 if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0) 418 margin = sp->cols - margin; 419 else 420 margin = O_VAL(sp, O_WRAPLEN); 421 else 422 margin = 0; 423 424 /* Initialize abbreviation checks. */ 425 abcnt = ab_turnoff = 0; 426 abb = F_ISSET(gp, G_ABBREV) && 427 LF_ISSET(TXT_MAPINPUT) ? AB_INWORD : AB_NOTSET; 428 429 /* 430 * Set up the dot command. Dot commands are done by saving the actual 431 * characters and then reevaluating them so that things like wrapmargin 432 * can change between the insert and the replay. 433 * 434 * !!! 435 * Historically, vi did not remap or reabbreviate replayed input. (It 436 * did beep at you if you changed an abbreviation and then replayed the 437 * input. We're not that compatible.) We don't have to do anything to 438 * avoid remapping, as we're not getting characters from the terminal 439 * routines. Turn the abbreviation check off. 440 * 441 * XXX 442 * It would be nice if we could swallow backspaces and such, but it's 443 * not all that easy to do. What we can do is turn off the common 444 * error messages during the replay. Otherwise, when the user enters 445 * an illegal command, e.g., "Ia<erase><erase><erase><erase>b<escape>", 446 * and then does a '.', they get a list of error messages after command 447 * completion. 448 */ 449 rcol = 0; 450 if (LF_ISSET(TXT_REPLAY)) { 451 abb = AB_NOTSET; 452 LF_CLR(TXT_RECORD); 453 } 454 455 /* Other text input mode setup. */ 456 quote = Q_NOTSET; 457 carat = C_NOTSET; 458 nochange = 0; 459 FL_INIT(is_flags, 460 LF_ISSET(TXT_SEARCHINCR) ? IS_RESTART | IS_RUNNING : 0); 461 filec_redraw = hexcnt = showmatch = 0; 462 463 /* Initialize input flags. */ 464 ec_flags = LF_ISSET(TXT_MAPINPUT) ? EC_MAPINPUT : 0; 465 466 /* Refresh the screen. */ 467 UPDATE_POSITION(sp, tp); 468 if (vs_refresh(sp, 1)) 469 return (1); 470 471 /* If it's dot, just do it now. */ 472 if (F_ISSET(vp, VC_ISDOT)) 473 goto replay; 474 475 /* Get an event. */ 476 evp = &ev; 477 next: if (v_event_get(sp, evp, 0, ec_flags)) 478 return (1); 479 480 /* 481 * If file completion overwrote part of the screen and nothing else has 482 * been displayed, clean up. We don't do this as part of the normal 483 * message resolution because we know the user is on the colon command 484 * line and there's no reason to enter explicit characters to continue. 485 */ 486 if (filec_redraw && !F_ISSET(sp, SC_SCR_EXWROTE)) { 487 filec_redraw = 0; 488 489 fc.e_event = E_REPAINT; 490 fc.e_flno = vip->totalcount >= 491 sp->rows ? 1 : sp->rows - vip->totalcount; 492 fc.e_tlno = sp->rows; 493 vip->linecount = vip->lcontinue = vip->totalcount = 0; 494 (void)vs_repaint(sp, &fc); 495 (void)vs_refresh(sp, 1); 496 } 497 498 /* Deal with all non-character events. */ 499 switch (evp->e_event) { 500 case E_CHARACTER: 501 break; 502 case E_ERR: 503 case E_EOF: 504 F_SET(sp, SC_EXIT_FORCE); 505 return (1); 506 case E_INTERRUPT: 507 /* 508 * !!! 509 * Historically, <interrupt> exited the user from text input 510 * mode or cancelled a colon command, and returned to command 511 * mode. It also beeped the terminal, but that seems a bit 512 * excessive. 513 */ 514 goto k_escape; 515 case E_REPAINT: 516 if (vs_repaint(sp, &ev)) 517 return (1); 518 goto next; 519 case E_WRESIZE: 520 /* <resize> interrupts the input mode. */ 521 v_emsg(sp, NULL, VIM_WRESIZE); 522 goto k_escape; 523 default: 524 v_event_err(sp, evp); 525 goto k_escape; 526 } 527 528 /* 529 * !!! 530 * If the first character of the input is a nul, replay the previous 531 * input. (Historically, it's okay to replay non-existent input.) 532 * This was not documented as far as I know, and is a great test of vi 533 * clones. 534 */ 535 if (LF_ISSET(TXT_RECORD) && rcol == 0 && evp->e_c == '\0') { 536 if (vip->rep == NULL) 537 goto done; 538 539 abb = AB_NOTSET; 540 LF_CLR(TXT_RECORD); 541 LF_SET(TXT_REPLAY); 542 goto replay; 543 } 544 545 /* 546 * File name completion and colon command-line editing. We don't 547 * have enough meta characters, so we expect people to overload 548 * them. If the two characters are the same, then we do file name 549 * completion if the cursor is past the first column, and do colon 550 * command-line editing if it's not. 551 */ 552 if (quote == Q_NOTSET) { 553 int L__cedit, L__filec; 554 555 L__cedit = L__filec = 0; 556 if (LF_ISSET(TXT_CEDIT) && O_STR(sp, O_CEDIT) != NULL && 557 O_STR(sp, O_CEDIT)[0] == evp->e_c) 558 L__cedit = 1; 559 if (LF_ISSET(TXT_FILEC) && O_STR(sp, O_FILEC) != NULL && 560 O_STR(sp, O_FILEC)[0] == evp->e_c) 561 L__filec = 1; 562 if (L__cedit == 1 && (L__filec == 0 || tp->cno == tp->offset)) { 563 tp->term = TERM_CEDIT; 564 goto k_escape; 565 } 566 if (L__filec == 1) { 567 if (txt_fc(sp, tp, &filec_redraw)) 568 goto err; 569 goto resolve; 570 } 571 } 572 573 /* Abbreviation overflow check. See comment in txt_abbrev(). */ 574 #define MAX_ABBREVIATION_EXPANSION 256 575 if (F_ISSET(&evp->e_ch, CH_ABBREVIATED)) { 576 if (++abcnt > MAX_ABBREVIATION_EXPANSION) { 577 if (v_event_flush(sp, CH_ABBREVIATED)) 578 msgq(sp, M_ERR, 579 "191|Abbreviation exceeded expansion limit: characters discarded"); 580 abcnt = 0; 581 if (LF_ISSET(TXT_REPLAY)) 582 goto done; 583 goto resolve; 584 } 585 } else 586 abcnt = 0; 587 588 /* Check to see if the character fits into the replay buffers. */ 589 if (LF_ISSET(TXT_RECORD)) { 590 BINC_GOTO(sp, EVENT, vip->rep, 591 vip->rep_len, (rcol + 1) * sizeof(EVENT)); 592 vip->rep[rcol++] = *evp; 593 } 594 595 replay: if (LF_ISSET(TXT_REPLAY)) { 596 if (rcol == vip->rep_cnt) 597 goto k_escape; 598 evp = vip->rep + rcol++; 599 } 600 601 /* Wrapmargin check for leading space. */ 602 if (wm_skip) { 603 wm_skip = 0; 604 if (evp->e_c == ' ') 605 goto resolve; 606 } 607 608 /* If quoted by someone else, simply insert the character. */ 609 if (F_ISSET(&evp->e_ch, CH_QUOTED)) 610 goto insq_ch; 611 612 /* 613 * !!! 614 * If this character was quoted by a K_VLNEXT, replace the placeholder 615 * (a carat) with the new character. We've already adjusted the cursor 616 * because it has to appear on top of the placeholder character. 617 * Historic practice. 618 * 619 * Skip tests for abbreviations; ":ab xa XA" followed by "ixa^V<space>" 620 * doesn't perform an abbreviation. Special case, ^V^J (not ^V^M) is 621 * the same as ^J, historically. 622 */ 623 if (quote == Q_VTHIS) { 624 FL_CLR(ec_flags, EC_QUOTED); 625 if (LF_ISSET(TXT_MAPINPUT)) 626 FL_SET(ec_flags, EC_MAPINPUT); 627 628 if (evp->e_value != K_NL) { 629 quote = Q_NOTSET; 630 goto insl_ch; 631 } 632 quote = Q_NOTSET; 633 } 634 635 /* 636 * !!! 637 * Translate "<CH_HEX>[isxdigit()]*" to a character with a hex value: 638 * this test delimits the value by any non-hex character. Offset by 639 * one, we use 0 to mean that we've found <CH_HEX>. 640 */ 641 if (hexcnt > 1 && !ISXDIGIT(evp->e_c)) { 642 hexcnt = 0; 643 if (txt_hex(sp, tp)) 644 goto err; 645 } 646 647 switch (evp->e_value) { 648 case K_CR: /* Carriage return. */ 649 case K_NL: /* New line. */ 650 /* Return in script windows and the command line. */ 651 k_cr: if (LF_ISSET(TXT_CR)) { 652 /* 653 * If this was a map, we may have not displayed 654 * the line. Display it, just in case. 655 * 656 * If a script window and not the colon line, 657 * push a <cr> so it gets executed. 658 */ 659 if (LF_ISSET(TXT_INFOLINE)) { 660 if (vs_change(sp, tp->lno, LINE_RESET)) 661 goto err; 662 } else if (F_ISSET(sp, SC_SCRIPT)) 663 (void)v_event_push(sp, NULL, L("\r"), 1, CH_NOMAP); 664 665 /* Set term condition: if empty. */ 666 if (tp->cno <= tp->offset) 667 tp->term = TERM_CR; 668 /* 669 * Set term condition: if searching incrementally and 670 * the user entered a pattern, return a completed 671 * search, regardless if the entire pattern was found. 672 */ 673 if (FL_ISSET(is_flags, IS_RUNNING) && 674 tp->cno >= tp->offset + 1) 675 tp->term = TERM_SEARCH; 676 677 goto k_escape; 678 } 679 680 #define LINE_RESOLVE do { \ 681 /* \ 682 * Handle abbreviations. If there was one, discard the \ 683 * replay characters. \ 684 */ \ 685 if (abb == AB_INWORD && \ 686 !LF_ISSET(TXT_REPLAY) && F_ISSET(gp, G_ABBREV)) { \ 687 if (txt_abbrev(sp, tp, &evp->e_c, \ 688 LF_ISSET(TXT_INFOLINE), &tmp, \ 689 &ab_turnoff)) \ 690 goto err; \ 691 if (tmp) { \ 692 if (LF_ISSET(TXT_RECORD)) \ 693 rcol -= tmp + 1; \ 694 goto resolve; \ 695 } \ 696 } \ 697 if (abb != AB_NOTSET) \ 698 abb = AB_NOTWORD; \ 699 if (UNMAP_TST) \ 700 txt_unmap(sp, tp, &ec_flags); \ 701 /* \ 702 * Delete any appended cursor. It's possible to get in \ 703 * situations where TXT_APPENDEOL is set but tp->insert \ 704 * is 0 when using the R command and all the characters \ 705 * are tp->owrite characters. \ 706 */ \ 707 if (LF_ISSET(TXT_APPENDEOL) && tp->insert > 0) { \ 708 --tp->len; \ 709 --tp->insert; \ 710 } \ 711 } while (0) 712 LINE_RESOLVE; 713 714 /* 715 * Save the current line information for restoration in 716 * txt_backup(), and set the line final length. 717 */ 718 tp->sv_len = tp->len; 719 tp->sv_cno = tp->cno; 720 tp->len = tp->cno; 721 722 /* Update the old line. */ 723 if (vs_change(sp, tp->lno, LINE_RESET)) 724 goto err; 725 726 /* 727 * Historic practice, when the autoindent edit option was set, 728 * was to delete <blank> characters following the inserted 729 * newline. This affected the 'R', 'c', and 's' commands; 'c' 730 * and 's' retained the insert characters only, 'R' moved the 731 * overwrite and insert characters into the next TEXT structure. 732 * We keep track of the number of characters erased for the 'R' 733 * command so that the final resolution of the line is correct. 734 */ 735 tp->R_erase = 0; 736 owrite = tp->owrite; 737 insert = tp->insert; 738 if (LF_ISSET(TXT_REPLACE) && owrite != 0) { 739 for (p = tp->lb + tp->cno; owrite > 0 && isblank(*p); 740 ++p, --owrite, ++tp->R_erase); 741 if (owrite == 0) 742 for (; insert > 0 && isblank(*p); 743 ++p, ++tp->R_erase, --insert); 744 } else { 745 p = tp->lb + tp->cno + owrite; 746 if (O_ISSET(sp, O_AUTOINDENT)) 747 for (; insert > 0 && 748 isblank(*p); ++p, --insert); 749 owrite = 0; 750 } 751 752 /* 753 * !!! 754 * Create a new line and insert the new TEXT into the queue. 755 * DON'T insert until the old line has been updated, or the 756 * inserted line count in line.c:db_get() will be wrong. 757 */ 758 if ((ntp = text_init(sp, p, 759 insert + owrite, insert + owrite + 32)) == NULL) 760 goto err; 761 TAILQ_INSERT_TAIL(sp->tiq, ntp, q); 762 763 /* Set up bookkeeping for the new line. */ 764 ntp->insert = insert; 765 ntp->owrite = owrite; 766 ntp->lno = tp->lno + 1; 767 768 /* 769 * Reset the autoindent line value. 0^D keeps the autoindent 770 * line from changing, ^D changes the level, even if there were 771 * no characters in the old line. Note, if using the current 772 * tp structure, use the cursor as the length, the autoindent 773 * characters may have been erased. 774 */ 775 if (LF_ISSET(TXT_AUTOINDENT)) { 776 if (nochange) { 777 nochange = 0; 778 if (v_txt_auto(sp, OOBLNO, &ait, ait.ai, ntp)) 779 goto err; 780 FREE_SPACEW(sp, ait.lb, ait.lb_len); 781 } else 782 if (v_txt_auto(sp, OOBLNO, tp, tp->cno, ntp)) 783 goto err; 784 carat = C_NOTSET; 785 } 786 787 /* Reset the cursor. */ 788 ntp->cno = ntp->ai; 789 790 /* 791 * If we're here because wrapmargin was set and we've broken a 792 * line, there may be additional information (i.e. the start of 793 * a line) in the wmt structure. 794 */ 795 if (wm_set) { 796 if (wmt.offset != 0 || 797 wmt.owrite != 0 || wmt.insert != 0) { 798 #define WMTSPACE wmt.offset + wmt.owrite + wmt.insert 799 BINC_GOTOW(sp, ntp->lb, 800 ntp->lb_len, ntp->len + WMTSPACE + 32); 801 MEMMOVE(ntp->lb + ntp->cno, wmt.lb, WMTSPACE); 802 ntp->len += WMTSPACE; 803 ntp->cno += wmt.offset; 804 ntp->owrite = wmt.owrite; 805 ntp->insert = wmt.insert; 806 } 807 wm_set = 0; 808 } 809 810 /* New lines are TXT_APPENDEOL. */ 811 if (ntp->owrite == 0 && ntp->insert == 0) { 812 BINC_GOTOW(sp, ntp->lb, ntp->lb_len, ntp->len + 1); 813 LF_SET(TXT_APPENDEOL); 814 ntp->lb[ntp->cno] = CH_CURSOR; 815 ++ntp->insert; 816 ++ntp->len; 817 } 818 819 /* Swap old and new TEXT's, and update the new line. */ 820 tp = ntp; 821 if (vs_change(sp, tp->lno, LINE_INSERT)) 822 goto err; 823 824 goto resolve; 825 case K_ESCAPE: /* Escape. */ 826 if (!LF_ISSET(TXT_ESCAPE)) 827 goto ins_ch; 828 829 /* If we have a count, start replaying the input. */ 830 if (rcount > 1) { 831 --rcount; 832 833 vip->rep_cnt = rcol; 834 rcol = 0; 835 abb = AB_NOTSET; 836 LF_CLR(TXT_RECORD); 837 LF_SET(TXT_REPLAY); 838 839 /* 840 * Some commands (e.g. 'o') need a <newline> for each 841 * repetition. 842 */ 843 if (LF_ISSET(TXT_ADDNEWLINE)) 844 goto k_cr; 845 846 /* 847 * The R command turns into the 'a' command after the 848 * first repetition. 849 */ 850 if (LF_ISSET(TXT_REPLACE)) { 851 tp->insert = tp->owrite; 852 tp->owrite = 0; 853 LF_CLR(TXT_REPLACE); 854 } 855 goto replay; 856 } 857 858 /* Set term condition: if empty. */ 859 if (tp->cno <= tp->offset) 860 tp->term = TERM_ESC; 861 /* 862 * Set term condition: if searching incrementally and the user 863 * entered a pattern, return a completed search, regardless if 864 * the entire pattern was found. 865 */ 866 if (FL_ISSET(is_flags, IS_RUNNING) && tp->cno >= tp->offset + 1) 867 tp->term = TERM_SEARCH; 868 869 k_escape: LINE_RESOLVE; 870 871 /* 872 * Clean up for the 'R' command, restoring overwrite 873 * characters, and making them into insert characters. 874 */ 875 if (LF_ISSET(TXT_REPLACE)) 876 txt_Rresolve(sp, sp->tiq, tp, len); 877 878 /* 879 * If there are any overwrite characters, copy down 880 * any insert characters, and decrement the length. 881 */ 882 if (tp->owrite) { 883 if (tp->insert) 884 MEMMOVE(tp->lb + tp->cno, 885 tp->lb + tp->cno + tp->owrite, tp->insert); 886 tp->len -= tp->owrite; 887 } 888 889 /* 890 * Optionally resolve the lines into the file. If not 891 * resolving the lines into the file, end the line with 892 * a nul. If the line is empty, then set the length to 893 * 0, the termination condition has already been set. 894 * 895 * XXX 896 * This is wrong, should pass back a length. 897 */ 898 if (LF_ISSET(TXT_RESOLVE)) { 899 if (txt_resolve(sp, sp->tiq, flags)) 900 goto err; 901 } else { 902 BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1); 903 tp->lb[tp->len] = '\0'; 904 } 905 906 /* 907 * Set the return cursor position to rest on the last 908 * inserted character. 909 */ 910 if (tp->cno != 0) 911 --tp->cno; 912 913 /* Update the last line. */ 914 if (vs_change(sp, tp->lno, LINE_RESET)) 915 return (1); 916 goto done; 917 case K_CARAT: /* Delete autoindent chars. */ 918 if (tp->cno <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) 919 carat = C_CARATSET; 920 goto ins_ch; 921 case K_ZERO: /* Delete autoindent chars. */ 922 if (tp->cno <= tp->ai && LF_ISSET(TXT_AUTOINDENT)) 923 carat = C_ZEROSET; 924 goto ins_ch; 925 case K_CNTRLD: /* Delete autoindent char. */ 926 /* 927 * If in the first column or no characters to erase, ignore 928 * the ^D (this matches historic practice). If not doing 929 * autoindent or already inserted non-ai characters, it's a 930 * literal. The latter test is done in the switch, as the 931 * CARAT forms are N + 1, not N. 932 */ 933 if (!LF_ISSET(TXT_AUTOINDENT)) 934 goto ins_ch; 935 if (tp->cno == 0) 936 goto resolve; 937 938 switch (carat) { 939 case C_CARATSET: /* ^^D */ 940 if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1) 941 goto ins_ch; 942 943 /* Save the ai string for later. */ 944 ait.lb = NULL; 945 ait.lb_len = 0; 946 BINC_GOTOW(sp, ait.lb, ait.lb_len, tp->ai); 947 MEMMOVE(ait.lb, tp->lb, tp->ai); 948 ait.ai = ait.len = tp->ai; 949 950 carat = C_NOTSET; 951 nochange = 1; 952 goto leftmargin; 953 case C_ZEROSET: /* 0^D */ 954 if (tp->ai == 0 || tp->cno > tp->ai + tp->offset + 1) 955 goto ins_ch; 956 957 carat = C_NOTSET; 958 leftmargin: tp->lb[tp->cno - 1] = ' '; 959 tp->owrite += tp->cno - tp->offset; 960 tp->ai = 0; 961 tp->cno = tp->offset; 962 break; 963 case C_NOTSET: /* ^D */ 964 if (tp->ai == 0 || tp->cno > tp->ai + tp->offset) 965 goto ins_ch; 966 967 (void)txt_dent(sp, tp, O_SHIFTWIDTH, 0); 968 break; 969 default: 970 abort(); 971 } 972 break; 973 case K_VERASE: /* Erase the last character. */ 974 /* If can erase over the prompt, return. */ 975 if (tp->cno <= tp->offset && LF_ISSET(TXT_BS)) { 976 tp->term = TERM_BS; 977 goto done; 978 } 979 980 /* 981 * If at the beginning of the line, try and drop back to a 982 * previously inserted line. 983 */ 984 if (tp->cno == 0) { 985 if ((ntp = 986 txt_backup(sp, sp->tiq, tp, &flags)) == NULL) 987 goto err; 988 tp = ntp; 989 break; 990 } 991 992 /* If nothing to erase, bell the user. */ 993 if (tp->cno <= tp->offset) { 994 if (!LF_ISSET(TXT_REPLAY)) 995 txt_nomorech(sp); 996 break; 997 } 998 999 /* Drop back one character. */ 1000 --tp->cno; 1001 1002 /* 1003 * Historically, vi didn't replace the erased characters with 1004 * <blank>s, presumably because it's easier to fix a minor 1005 * typing mistake and continue on if the previous letters are 1006 * already there. This is a problem for incremental searching, 1007 * because the user can no longer tell where they are in the 1008 * colon command line because the cursor is at the last search 1009 * point in the screen. So, if incrementally searching, erase 1010 * the erased characters from the screen. 1011 */ 1012 if (FL_ISSET(is_flags, IS_RUNNING)) 1013 tp->lb[tp->cno] = ' '; 1014 1015 /* 1016 * Increment overwrite, decrement ai if deleted. 1017 * 1018 * !!! 1019 * Historic vi did not permit users to use erase characters 1020 * to delete autoindent characters. We do. Eat hot death, 1021 * POSIX. 1022 */ 1023 ++tp->owrite; 1024 if (tp->cno < tp->ai) 1025 --tp->ai; 1026 1027 /* Reset if we deleted an incremental search character. */ 1028 if (FL_ISSET(is_flags, IS_RUNNING)) 1029 FL_SET(is_flags, IS_RESTART); 1030 break; 1031 case K_VWERASE: /* Skip back one word. */ 1032 /* 1033 * If at the beginning of the line, try and drop back to a 1034 * previously inserted line. 1035 */ 1036 if (tp->cno == 0) { 1037 if ((ntp = 1038 txt_backup(sp, sp->tiq, tp, &flags)) == NULL) 1039 goto err; 1040 tp = ntp; 1041 } 1042 1043 /* 1044 * If at offset, nothing to erase so bell the user. 1045 */ 1046 if (tp->cno <= tp->offset) { 1047 if (!LF_ISSET(TXT_REPLAY)) 1048 txt_nomorech(sp); 1049 break; 1050 } 1051 1052 /* 1053 * The first werase goes back to any autoindent column and the 1054 * second werase goes back to the offset. 1055 * 1056 * !!! 1057 * Historic vi did not permit users to use erase characters to 1058 * delete autoindent characters. 1059 */ 1060 if (tp->ai && tp->cno > tp->ai) 1061 max = tp->ai; 1062 else { 1063 tp->ai = 0; 1064 max = tp->offset; 1065 } 1066 1067 /* Skip over trailing space characters. */ 1068 while (tp->cno > max && ISBLANK(tp->lb[tp->cno - 1])) { 1069 --tp->cno; 1070 ++tp->owrite; 1071 } 1072 if (tp->cno == max) 1073 break; 1074 /* 1075 * There are three types of word erase found on UNIX systems. 1076 * They can be identified by how the string /a/b/c is treated 1077 * -- as 1, 3, or 6 words. Historic vi had two classes of 1078 * characters, and strings were delimited by them and 1079 * <blank>'s, so, 6 words. The historic tty interface used 1080 * <blank>'s to delimit strings, so, 1 word. The algorithm 1081 * offered in the 4.4BSD tty interface (as stty altwerase) 1082 * treats it as 3 words -- there are two classes of 1083 * characters, and strings are delimited by them and 1084 * <blank>'s. The difference is that the type of the first 1085 * erased character erased is ignored, which is exactly right 1086 * when erasing pathname components. The edit options 1087 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD tty 1088 * interface and the historic tty driver behavior, 1089 * respectively, and the default is the same as the historic 1090 * vi behavior. 1091 * 1092 * Overwrite erased characters if doing incremental search; 1093 * see comment above. 1094 */ 1095 if (LF_ISSET(TXT_TTYWERASE)) 1096 while (tp->cno > max) { 1097 if (ISBLANK(tp->lb[tp->cno - 1])) 1098 break; 1099 --tp->cno; 1100 ++tp->owrite; 1101 if (FL_ISSET(is_flags, IS_RUNNING)) 1102 tp->lb[tp->cno] = ' '; 1103 } 1104 else { 1105 if (LF_ISSET(TXT_ALTWERASE)) { 1106 --tp->cno; 1107 ++tp->owrite; 1108 if (FL_ISSET(is_flags, IS_RUNNING)) 1109 tp->lb[tp->cno] = ' '; 1110 } 1111 if (tp->cno > max) 1112 tmp = inword(tp->lb[tp->cno - 1]); 1113 while (tp->cno > max) { 1114 if (tmp != inword(tp->lb[tp->cno - 1]) 1115 || ISBLANK(tp->lb[tp->cno - 1])) 1116 break; 1117 --tp->cno; 1118 ++tp->owrite; 1119 if (FL_ISSET(is_flags, IS_RUNNING)) 1120 tp->lb[tp->cno] = ' '; 1121 } 1122 } 1123 1124 /* Reset if we deleted an incremental search character. */ 1125 if (FL_ISSET(is_flags, IS_RUNNING)) 1126 FL_SET(is_flags, IS_RESTART); 1127 break; 1128 case K_VKILL: /* Restart this line. */ 1129 /* 1130 * !!! 1131 * If at the beginning of the line, try and drop back to a 1132 * previously inserted line. Historic vi did not permit 1133 * users to go back to previous lines. 1134 */ 1135 if (tp->cno == 0) { 1136 if ((ntp = 1137 txt_backup(sp, sp->tiq, tp, &flags)) == NULL) 1138 goto err; 1139 tp = ntp; 1140 } 1141 1142 /* If at offset, nothing to erase so bell the user. */ 1143 if (tp->cno <= tp->offset) { 1144 if (!LF_ISSET(TXT_REPLAY)) 1145 txt_nomorech(sp); 1146 break; 1147 } 1148 1149 /* 1150 * First kill goes back to any autoindent and second kill goes 1151 * back to the offset. 1152 * 1153 * !!! 1154 * Historic vi did not permit users to use erase characters to 1155 * delete autoindent characters. 1156 */ 1157 if (tp->ai && tp->cno > tp->ai) 1158 max = tp->ai; 1159 else { 1160 tp->ai = 0; 1161 max = tp->offset; 1162 } 1163 tp->owrite += tp->cno - max; 1164 1165 /* 1166 * Overwrite erased characters if doing incremental search; 1167 * see comment above. 1168 */ 1169 if (FL_ISSET(is_flags, IS_RUNNING)) 1170 do { 1171 tp->lb[--tp->cno] = ' '; 1172 } while (tp->cno > max); 1173 else 1174 tp->cno = max; 1175 1176 /* Reset if we deleted an incremental search character. */ 1177 if (FL_ISSET(is_flags, IS_RUNNING)) 1178 FL_SET(is_flags, IS_RESTART); 1179 break; 1180 case K_CNTRLT: /* Add autoindent characters. */ 1181 if (!LF_ISSET(TXT_CNTRLT)) 1182 goto ins_ch; 1183 if (txt_dent(sp, tp, O_SHIFTWIDTH, 1)) 1184 goto err; 1185 goto ebuf_chk; 1186 case K_VLNEXT: /* Quote next character. */ 1187 evp->e_c = '^'; 1188 quote = Q_VNEXT; 1189 /* 1190 * Turn on the quote flag so that the underlying routines 1191 * quote the next character where it's possible. Turn off 1192 * the input mapbiting flag so that we don't remap the next 1193 * character. 1194 */ 1195 FL_SET(ec_flags, EC_QUOTED); 1196 FL_CLR(ec_flags, EC_MAPINPUT); 1197 1198 /* 1199 * !!! 1200 * Skip the tests for abbreviations, so ":ab xa XA", 1201 * "ixa^V<space>" doesn't perform the abbreviation. 1202 */ 1203 goto insl_ch; 1204 case K_HEXCHAR: 1205 hexcnt = 1; 1206 goto insq_ch; 1207 case K_TAB: 1208 if (sp->showmode != SM_COMMAND && quote != Q_VTHIS && 1209 O_ISSET(sp, O_EXPANDTAB)) { 1210 if (txt_dent(sp, tp, O_TABSTOP, 1)) 1211 goto err; 1212 goto ebuf_chk; 1213 } 1214 goto insq_ch; 1215 default: /* Insert the character. */ 1216 if (LF_ISSET(TXT_SHOWMATCH)) { 1217 CHAR_T *match_chars, *cp; 1218 1219 match_chars = VIP(sp)->mcs; 1220 cp = STRCHR(match_chars, evp->e_c); 1221 if (cp != NULL && (cp - match_chars) & 1) 1222 showmatch = 1; 1223 } 1224 ins_ch: /* 1225 * Historically, vi eliminated nul's out of hand. If the 1226 * beautify option was set, it also deleted any unknown 1227 * ASCII value less than space (040) and the del character 1228 * (0177), except for tabs. Unknown is a key word here. 1229 * Most vi documentation claims that it deleted everything 1230 * but <tab>, <nl> and <ff>, as that's what the original 1231 * 4BSD documentation said. This is obviously wrong, 1232 * however, as <esc> would be included in that list. What 1233 * we do is eliminate any unquoted, iscntrl() character that 1234 * wasn't a replay and wasn't handled specially, except 1235 * <tab> or <ff>. 1236 */ 1237 if (LF_ISSET(TXT_BEAUTIFY) && ISCNTRL(evp->e_c) && 1238 evp->e_value != K_FORMFEED && evp->e_value != K_TAB) { 1239 msgq(sp, M_BERR, 1240 "192|Illegal character; quote to enter"); 1241 if (LF_ISSET(TXT_REPLAY)) 1242 goto done; 1243 break; 1244 } 1245 1246 insq_ch: /* 1247 * If entering a non-word character after a word, check for 1248 * abbreviations. If there was one, discard replay characters. 1249 * If entering a blank character, check for unmap commands, 1250 * as well. 1251 */ 1252 if (!inword(evp->e_c)) { 1253 if (abb == AB_INWORD && 1254 !LF_ISSET(TXT_REPLAY) && F_ISSET(gp, G_ABBREV)) { 1255 if (txt_abbrev(sp, tp, &evp->e_c, 1256 LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff)) 1257 goto err; 1258 if (tmp) { 1259 if (LF_ISSET(TXT_RECORD)) 1260 rcol -= tmp + 1; 1261 goto resolve; 1262 } 1263 } 1264 if (isblank(evp->e_c) && UNMAP_TST) 1265 txt_unmap(sp, tp, &ec_flags); 1266 } 1267 if (abb != AB_NOTSET) 1268 abb = inword(evp->e_c) ? AB_INWORD : AB_NOTWORD; 1269 1270 insl_ch: if (txt_insch(sp, tp, &evp->e_c, flags)) 1271 goto err; 1272 1273 /* 1274 * If we're using K_VLNEXT to quote the next character, then 1275 * we want the cursor to position itself on the ^ placeholder 1276 * we're displaying, to match historic practice. 1277 */ 1278 if (quote == Q_VNEXT) { 1279 --tp->cno; 1280 ++tp->owrite; 1281 } 1282 1283 /* 1284 * !!! 1285 * Translate "<CH_HEX>[isxdigit()]*" to a character with 1286 * a hex value: this test delimits the value by the max 1287 * number of hex bytes. Offset by one, we use 0 to mean 1288 * that we've found <CH_HEX>. 1289 */ 1290 if (hexcnt != 0 && hexcnt++ == 3) { 1291 hexcnt = 0; 1292 if (txt_hex(sp, tp)) 1293 goto err; 1294 } 1295 1296 /* 1297 * Check to see if we've crossed the margin. 1298 * 1299 * !!! 1300 * In the historic vi, the wrapmargin value was figured out 1301 * using the display widths of the characters, i.e. <tab> 1302 * characters were counted as two characters if the list edit 1303 * option is set, but as the tabstop edit option number of 1304 * characters otherwise. That's what the vs_column() function 1305 * gives us, so we use it. 1306 */ 1307 if (margin != 0) { 1308 if (vs_column(sp, &tcol)) 1309 goto err; 1310 if (tcol >= margin) { 1311 if (txt_margin(sp, tp, &wmt, &tmp, flags)) 1312 goto err; 1313 if (tmp) { 1314 if (isblank(evp->e_c)) 1315 wm_skip = 1; 1316 wm_set = 1; 1317 goto k_cr; 1318 } 1319 } 1320 } 1321 1322 /* 1323 * If we've reached the end of the buffer, then we need to 1324 * switch into insert mode. This happens when there's a 1325 * change to a mark and the user puts in more characters than 1326 * the length of the motion. 1327 */ 1328 ebuf_chk: if (tp->cno >= tp->len) { 1329 BINC_GOTOW(sp, tp->lb, tp->lb_len, tp->len + 1); 1330 LF_SET(TXT_APPENDEOL); 1331 1332 tp->lb[tp->cno] = CH_CURSOR; 1333 ++tp->insert; 1334 ++tp->len; 1335 } 1336 1337 /* Step the quote state forward. */ 1338 if (quote == Q_VNEXT) 1339 quote = Q_VTHIS; 1340 break; 1341 } 1342 1343 #ifdef DEBUG 1344 if (tp->cno + tp->insert + tp->owrite != tp->len) { 1345 msgq(sp, M_ERR, 1346 "len %zu != cno: %zu ai: %zu insert %zu overwrite %zu", 1347 tp->len, tp->cno, tp->ai, tp->insert, tp->owrite); 1348 if (LF_ISSET(TXT_REPLAY)) 1349 goto done; 1350 tp->len = tp->cno + tp->insert + tp->owrite; 1351 } 1352 #endif 1353 1354 resolve:/* 1355 * 1: If we don't need to know where the cursor really is and we're 1356 * replaying text, keep going. 1357 */ 1358 if (margin == 0 && LF_ISSET(TXT_REPLAY)) 1359 goto replay; 1360 1361 /* 1362 * 2: Reset the line. Don't bother unless we're about to wait on 1363 * a character or we need to know where the cursor really is. 1364 * We have to do this before showing matching characters so the 1365 * user can see what they're matching. 1366 */ 1367 if ((margin != 0 || !KEYS_WAITING(sp)) && 1368 vs_change(sp, tp->lno, LINE_RESET)) 1369 return (1); 1370 1371 /* 1372 * 3: If there aren't keys waiting, display the matching character. 1373 * We have to do this before resolving any messages, otherwise 1374 * the error message from a missing match won't appear correctly. 1375 */ 1376 if (showmatch) { 1377 if (!KEYS_WAITING(sp) && txt_showmatch(sp, tp)) 1378 return (1); 1379 showmatch = 0; 1380 } 1381 1382 /* 1383 * 4: If there have been messages and we're not editing on the colon 1384 * command line or doing file name completion, resolve them. 1385 */ 1386 if ((vip->totalcount != 0 || F_ISSET(gp, G_BELLSCHED)) && 1387 !F_ISSET(sp, SC_TINPUT_INFO) && !filec_redraw && 1388 vs_resolve(sp, NULL, 0)) 1389 return (1); 1390 1391 /* 1392 * 5: Refresh the screen if we're about to wait on a character or we 1393 * need to know where the cursor really is. 1394 */ 1395 if (margin != 0 || !KEYS_WAITING(sp)) { 1396 UPDATE_POSITION(sp, tp); 1397 if (vs_refresh(sp, margin != 0)) 1398 return (1); 1399 } 1400 1401 /* 6: Proceed with the incremental search. */ 1402 if (FL_ISSET(is_flags, IS_RUNNING) && txt_isrch(sp, vp, tp, &is_flags)) 1403 return (1); 1404 1405 /* 7: Next character... */ 1406 if (LF_ISSET(TXT_REPLAY)) 1407 goto replay; 1408 goto next; 1409 1410 done: /* Leave input mode. */ 1411 F_CLR(sp, SC_TINPUT); 1412 1413 /* If recording for playback, save it. */ 1414 if (LF_ISSET(TXT_RECORD)) 1415 vip->rep_cnt = rcol; 1416 1417 /* 1418 * If not working on the colon command line, set the final cursor 1419 * position. 1420 */ 1421 if (!F_ISSET(sp, SC_TINPUT_INFO)) { 1422 vp->m_final.lno = tp->lno; 1423 vp->m_final.cno = tp->cno; 1424 } 1425 return (0); 1426 1427 err: 1428 alloc_err: 1429 F_CLR(sp, SC_TINPUT); 1430 txt_err(sp, sp->tiq); 1431 return (1); 1432 } 1433 1434 /* 1435 * txt_abbrev -- 1436 * Handle abbreviations. 1437 */ 1438 static int 1439 txt_abbrev(SCR *sp, TEXT *tp, CHAR_T *pushcp, int isinfoline, int *didsubp, int *turnoffp) 1440 { 1441 VI_PRIVATE *vip; 1442 CHAR_T ch, *p; 1443 SEQ *qp; 1444 size_t len, off; 1445 1446 /* Check to make sure we're not at the start of an append. */ 1447 *didsubp = 0; 1448 if (tp->cno == tp->offset) 1449 return (0); 1450 1451 vip = VIP(sp); 1452 1453 /* 1454 * Find the start of the "word". 1455 * 1456 * !!! 1457 * We match historic practice, which, as far as I can tell, had an 1458 * off-by-one error. The way this worked was that when the inserted 1459 * text switched from a "word" character to a non-word character, 1460 * vi would check for possible abbreviations. It would then take the 1461 * type (i.e. word/non-word) of the character entered TWO characters 1462 * ago, and move backward in the text until reaching a character that 1463 * was not that type, or the beginning of the insert, the line, or 1464 * the file. For example, in the string "abc<space>", when the <space> 1465 * character triggered the abbreviation check, the type of the 'b' 1466 * character was used for moving through the string. Maybe there's a 1467 * reason for not using the first (i.e. 'c') character, but I can't 1468 * think of one. 1469 * 1470 * Terminate at the beginning of the insert or the character after the 1471 * offset character -- both can be tested for using tp->offset. 1472 */ 1473 off = tp->cno - 1; /* Previous character. */ 1474 p = tp->lb + off; 1475 len = 1; /* One character test. */ 1476 if (off == tp->offset || isblank(p[-1])) 1477 goto search; 1478 if (inword(p[-1])) /* Move backward to change. */ 1479 for (;;) { 1480 --off; --p; ++len; 1481 if (off == tp->offset || !inword(p[-1])) 1482 break; 1483 } 1484 else 1485 for (;;) { 1486 --off; --p; ++len; 1487 if (off == tp->offset || 1488 inword(p[-1]) || isblank(p[-1])) 1489 break; 1490 } 1491 1492 /* 1493 * !!! 1494 * Historic vi exploded abbreviations on the command line. This has 1495 * obvious problems in that unabbreviating the string can be extremely 1496 * tricky, particularly if the string has, say, an embedded escape 1497 * character. Personally, I think it's a stunningly bad idea. Other 1498 * examples of problems this caused in historic vi are: 1499 * :ab foo bar 1500 * :ab foo baz 1501 * results in "bar" being abbreviated to "baz", which wasn't what the 1502 * user had in mind at all. Also, the commands: 1503 * :ab foo bar 1504 * :unab foo<space> 1505 * resulted in an error message that "bar" wasn't mapped. Finally, 1506 * since the string was already exploded by the time the unabbreviate 1507 * command got it, all it knew was that an abbreviation had occurred. 1508 * Cleverly, it checked the replacement string for its unabbreviation 1509 * match, which meant that the commands: 1510 * :ab foo1 bar 1511 * :ab foo2 bar 1512 * :unab foo2 1513 * unabbreviate "foo1", and the commands: 1514 * :ab foo bar 1515 * :ab bar baz 1516 * unabbreviate "foo"! 1517 * 1518 * Anyway, people neglected to first ask my opinion before they wrote 1519 * macros that depend on this stuff, so, we make this work as follows. 1520 * When checking for an abbreviation on the command line, if we get a 1521 * string which is <blank> terminated and which starts at the beginning 1522 * of the line, we check to see it is the abbreviate or unabbreviate 1523 * commands. If it is, turn abbreviations off and return as if no 1524 * abbreviation was found. Note also, minor trickiness, so that if 1525 * the user erases the line and starts another command, we turn the 1526 * abbreviations back on. 1527 * 1528 * This makes the layering look like a Nachos Supreme. 1529 */ 1530 search: if (isinfoline) { 1531 if (off == tp->ai || off == tp->offset) 1532 if (ex_is_abbrev(p, len)) { 1533 *turnoffp = 1; 1534 return (0); 1535 } else 1536 *turnoffp = 0; 1537 else 1538 if (*turnoffp) 1539 return (0); 1540 } 1541 1542 /* Check for any abbreviations. */ 1543 if ((qp = seq_find(sp, NULL, NULL, p, len, SEQ_ABBREV, NULL)) == NULL) 1544 return (0); 1545 1546 /* 1547 * Push the abbreviation onto the tty stack. Historically, characters 1548 * resulting from an abbreviation expansion were themselves subject to 1549 * map expansions, O_SHOWMATCH matching etc. This means the expanded 1550 * characters will be re-tested for abbreviations. It's difficult to 1551 * know what historic practice in this case was, since abbreviations 1552 * were applied to :colon command lines, so entering abbreviations that 1553 * looped was tricky, although possible. In addition, obvious loops 1554 * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will 1555 * silently only implement and/or display the last abbreviation.) 1556 * 1557 * This implementation doesn't recover well from such abbreviations. 1558 * The main input loop counts abbreviated characters, and, when it 1559 * reaches a limit, discards any abbreviated characters on the queue. 1560 * It's difficult to back up to the original position, as the replay 1561 * queue would have to be adjusted, and the line state when an initial 1562 * abbreviated character was received would have to be saved. 1563 */ 1564 ch = *pushcp; 1565 if (v_event_push(sp, NULL, &ch, 1, CH_ABBREVIATED)) 1566 return (1); 1567 if (v_event_push(sp, NULL, qp->output, qp->olen, CH_ABBREVIATED)) 1568 return (1); 1569 1570 /* 1571 * If the size of the abbreviation is larger than or equal to the size 1572 * of the original text, move to the start of the replaced characters, 1573 * and add their length to the overwrite count. 1574 * 1575 * If the abbreviation is smaller than the original text, we have to 1576 * delete the additional overwrite characters and copy down any insert 1577 * characters. 1578 */ 1579 tp->cno -= len; 1580 if (qp->olen >= len) 1581 tp->owrite += len; 1582 else { 1583 if (tp->insert) 1584 MEMMOVE(tp->lb + tp->cno + qp->olen, 1585 tp->lb + tp->cno + tp->owrite + len, tp->insert); 1586 tp->owrite += qp->olen; 1587 tp->len -= len - qp->olen; 1588 } 1589 1590 /* 1591 * We return the length of the abbreviated characters. This is so 1592 * the calling routine can replace the replay characters with the 1593 * abbreviation. This means that subsequent '.' commands will produce 1594 * the same text, regardless of intervening :[un]abbreviate commands. 1595 * This is historic practice. 1596 */ 1597 *didsubp = len; 1598 return (0); 1599 } 1600 1601 /* 1602 * txt_unmap -- 1603 * Handle the unmap command. 1604 */ 1605 static void 1606 txt_unmap(SCR *sp, TEXT *tp, u_int32_t *ec_flagsp) 1607 { 1608 size_t len, off; 1609 CHAR_T *p; 1610 1611 /* Find the beginning of this "word". */ 1612 for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) { 1613 if (isblank(*p)) { 1614 ++p; 1615 break; 1616 } 1617 ++len; 1618 if (off == tp->ai || off == tp->offset) 1619 break; 1620 } 1621 1622 /* 1623 * !!! 1624 * Historic vi exploded input mappings on the command line. See the 1625 * txt_abbrev() routine for an explanation of the problems inherent 1626 * in this. 1627 * 1628 * We make this work as follows. If we get a string which is <blank> 1629 * terminated and which starts at the beginning of the line, we check 1630 * to see it is the unmap command. If it is, we return that the input 1631 * mapping should be turned off. Note also, minor trickiness, so that 1632 * if the user erases the line and starts another command, we go ahead 1633 * an turn mapping back on. 1634 */ 1635 if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len)) 1636 FL_CLR(*ec_flagsp, EC_MAPINPUT); 1637 else 1638 FL_SET(*ec_flagsp, EC_MAPINPUT); 1639 } 1640 1641 /* 1642 * txt_ai_resolve -- 1643 * When a line is resolved by <esc>, review autoindent characters. 1644 */ 1645 static void 1646 txt_ai_resolve(SCR *sp, TEXT *tp, int *changedp) 1647 { 1648 u_long ts; 1649 int del; 1650 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs; 1651 CHAR_T *p; 1652 1653 *changedp = 0; 1654 1655 /* 1656 * If the line is empty, has an offset, or no autoindent 1657 * characters, we're done. 1658 */ 1659 if (!tp->len || tp->offset || !tp->ai) 1660 return; 1661 1662 /* 1663 * If the length is less than or equal to the autoindent 1664 * characters, delete them. 1665 */ 1666 if (tp->len <= tp->ai) { 1667 tp->ai = tp->cno = tp->len = 0; 1668 return; 1669 } 1670 1671 /* 1672 * The autoindent characters plus any leading <blank> characters 1673 * in the line are resolved into the minimum number of characters. 1674 * Historic practice. 1675 */ 1676 ts = O_VAL(sp, O_TABSTOP); 1677 1678 /* Figure out the last <blank> screen column. */ 1679 for (p = tp->lb, scno = 0, len = tp->len, 1680 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p) 1681 if (*p == '\t') { 1682 if (spaces) 1683 tab_after_sp = 1; 1684 scno += COL_OFF(scno, ts); 1685 } else { 1686 ++spaces; 1687 ++scno; 1688 } 1689 1690 /* 1691 * If there are no spaces, or no tabs after spaces and less than 1692 * ts spaces, it's already minimal. 1693 * Keep analysing if expandtab is set. 1694 */ 1695 if ((!spaces || (!tab_after_sp && spaces < ts)) && 1696 !O_ISSET(sp, O_EXPANDTAB)) 1697 return; 1698 1699 /* Count up spaces/tabs needed to get to the target. */ 1700 cno = 0; 1701 tabs = 0; 1702 if (!O_ISSET(sp, O_EXPANDTAB)) { 1703 for (; cno + COL_OFF(cno, ts) <= scno; ++tabs) 1704 cno += COL_OFF(cno, ts); 1705 } 1706 spaces = scno - cno; 1707 1708 /* 1709 * Figure out how many characters we're dropping -- if we're not 1710 * dropping any, it's already minimal, we're done. 1711 */ 1712 old = p - tp->lb; 1713 new = spaces + tabs; 1714 if (old == new) 1715 return; 1716 1717 /* Shift the rest of the characters down, adjust the counts. */ 1718 del = old - new; 1719 MEMMOVE(p - del, p, tp->len - old); 1720 tp->len -= del; 1721 tp->cno -= del; 1722 1723 /* Fill in space/tab characters. */ 1724 for (p = tp->lb; tabs--;) 1725 *p++ = '\t'; 1726 while (spaces--) 1727 *p++ = ' '; 1728 *changedp = 1; 1729 } 1730 1731 /* 1732 * v_txt_auto -- 1733 * Handle autoindent. If aitp isn't NULL, use it, otherwise, 1734 * retrieve the line. 1735 * 1736 * PUBLIC: int v_txt_auto(SCR *, recno_t, TEXT *, size_t, TEXT *); 1737 */ 1738 int 1739 v_txt_auto(SCR *sp, recno_t lno, TEXT *aitp, size_t len, TEXT *tp) 1740 { 1741 size_t nlen; 1742 CHAR_T *p, *t; 1743 1744 if (aitp == NULL) { 1745 /* 1746 * If the ex append command is executed with an address of 0, 1747 * it's possible to get here with a line number of 0. Return 1748 * an indent of 0. 1749 */ 1750 if (lno == 0) { 1751 tp->ai = 0; 1752 return (0); 1753 } 1754 if (db_get(sp, lno, DBG_FATAL, &t, &len)) 1755 return (1); 1756 } else 1757 t = aitp->lb; 1758 1759 /* Count whitespace characters. */ 1760 for (p = t; len > 0; ++p, --len) 1761 if (!isblank(*p)) 1762 break; 1763 1764 /* Set count, check for no indentation. */ 1765 if ((nlen = (p - t)) == 0) 1766 return (0); 1767 1768 /* Make sure the buffer's big enough. */ 1769 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen); 1770 1771 /* Copy the buffer's current contents up. */ 1772 if (tp->len != 0) 1773 MEMMOVE(tp->lb + nlen, tp->lb, tp->len); 1774 tp->len += nlen; 1775 1776 /* Copy the indentation into the new buffer. */ 1777 MEMMOVE(tp->lb, t, nlen); 1778 1779 /* Set the autoindent count. */ 1780 tp->ai = nlen; 1781 return (0); 1782 } 1783 1784 /* 1785 * txt_backup -- 1786 * Back up to the previously edited line. 1787 */ 1788 static TEXT * 1789 txt_backup(SCR *sp, TEXTH *tiqh, TEXT *tp, u_int32_t *flagsp) 1790 { 1791 VI_PRIVATE *vip; 1792 TEXT *ntp; 1793 1794 /* Get a handle on the previous TEXT structure. */ 1795 if ((ntp = TAILQ_PREV(tp, _texth, q)) == NULL) { 1796 if (!FL_ISSET(*flagsp, TXT_REPLAY)) 1797 msgq(sp, M_BERR, 1798 "193|Already at the beginning of the insert"); 1799 return (tp); 1800 } 1801 1802 /* Bookkeeping. */ 1803 ntp->len = ntp->sv_len; 1804 1805 /* Handle appending to the line. */ 1806 vip = VIP(sp); 1807 if (ntp->owrite == 0 && ntp->insert == 0) { 1808 ntp->lb[ntp->len] = CH_CURSOR; 1809 ++ntp->insert; 1810 ++ntp->len; 1811 FL_SET(*flagsp, TXT_APPENDEOL); 1812 } else 1813 FL_CLR(*flagsp, TXT_APPENDEOL); 1814 1815 /* Release the current TEXT. */ 1816 TAILQ_REMOVE(tiqh, tp, q); 1817 text_free(tp); 1818 1819 /* Update the old line on the screen. */ 1820 if (vs_change(sp, ntp->lno + 1, LINE_DELETE)) 1821 return (NULL); 1822 1823 /* Return the new/current TEXT. */ 1824 return (ntp); 1825 } 1826 1827 /* 1828 * Text indentation is truly strange. ^T and ^D do movements to the next or 1829 * previous shiftwidth value, i.e. for a 1-based numbering, with shiftwidth=3, 1830 * ^T moves a cursor on the 7th, 8th or 9th column to the 10th column, and ^D 1831 * moves it back. 1832 * 1833 * !!! 1834 * The ^T and ^D characters in historical vi had special meaning only when they 1835 * were the first characters entered after entering text input mode. As normal 1836 * erase characters couldn't erase autoindent characters (^T in this case), it 1837 * meant that inserting text into previously existing text was strange -- ^T 1838 * only worked if it was the first keystroke(s), and then could only be erased 1839 * using ^D. This implementation treats ^T specially anywhere it occurs in the 1840 * input, and permits the standard erase characters to erase the characters it 1841 * inserts. 1842 * 1843 * !!! 1844 * A fun test is to try: 1845 * :se sw=4 ai list 1846 * i<CR>^Tx<CR>^Tx<CR>^Tx<CR>^Dx<CR>^Dx<CR>^Dx<esc> 1847 * Historic vi loses some of the '$' marks on the line ends, but otherwise gets 1848 * it right. 1849 * 1850 * XXX 1851 * Technically, txt_dent should be part of the screen interface, as it requires 1852 * knowledge of character sizes, including <space>s, on the screen. It's here 1853 * because it's a complicated little beast, and I didn't want to shove it down 1854 * into the screen. It's probable that KEY_COL will call into the screen once 1855 * there are screens with different character representations. 1856 * 1857 * txt_dent -- 1858 * Handle ^T indents, ^D outdents. 1859 * 1860 * If anything changes here, check the ex version to see if it needs similar 1861 * changes. 1862 */ 1863 static int 1864 txt_dent(SCR *sp, TEXT *tp, int swopt, int isindent) 1865 { 1866 CHAR_T ch; 1867 u_long sw, ts; 1868 size_t cno, current, spaces, target, tabs; 1869 int ai_reset; 1870 1871 ts = O_VAL(sp, O_TABSTOP); 1872 sw = O_VAL(sp, swopt); 1873 1874 /* 1875 * Since we don't know what precedes the character(s) being inserted 1876 * (or deleted), the preceding whitespace characters must be resolved. 1877 * An example is a <tab>, which doesn't need a full shiftwidth number 1878 * of columns because it's preceded by <space>s. This is easy to get 1879 * if the user sets shiftwidth to a value less than tabstop (or worse, 1880 * something for which tabstop isn't a multiple) and then uses ^T to 1881 * indent, and ^D to outdent. 1882 * 1883 * Figure out the current and target screen columns. In the historic 1884 * vi, the autoindent column was NOT determined using display widths 1885 * of characters as was the wrapmargin column. For that reason, we 1886 * can't use the vs_column() function, but have to calculate it here. 1887 * This is slow, but it's normally only on the first few characters of 1888 * a line. 1889 */ 1890 for (current = cno = 0; cno < tp->cno; ++cno) 1891 current += tp->lb[cno] == '\t' ? 1892 COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]); 1893 1894 target = current; 1895 if (isindent) 1896 target += COL_OFF(target, sw); 1897 else { 1898 --target; 1899 target -= target % sw; 1900 } 1901 1902 /* 1903 * The AI characters will be turned into overwrite characters if the 1904 * cursor immediately follows them. We test both the cursor position 1905 * and the indent flag because there's no single test. (^T can only 1906 * be detected by the cursor position, and while we know that the test 1907 * is always true for ^D, the cursor can be in more than one place, as 1908 * "0^D" and "^D" are different.) 1909 */ 1910 ai_reset = !isindent || tp->cno == tp->ai + tp->offset; 1911 1912 /* 1913 * Back up over any previous <blank> characters, changing them into 1914 * overwrite characters (including any ai characters). Then figure 1915 * out the current screen column. 1916 */ 1917 for (; tp->cno > tp->offset && 1918 (tp->lb[tp->cno - 1] == ' ' || tp->lb[tp->cno - 1] == '\t'); 1919 --tp->cno, ++tp->owrite); 1920 for (current = cno = 0; cno < tp->cno; ++cno) 1921 current += tp->lb[cno] == '\t' ? 1922 COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]); 1923 1924 /* 1925 * If we didn't move up to or past the target, it's because there 1926 * weren't enough characters to delete, e.g. the first character 1927 * of the line was a tp->offset character, and the user entered 1928 * ^D to move to the beginning of a line. An example of this is: 1929 * 1930 * :set ai sw=4<cr>i<space>a<esc>i^T^D 1931 * 1932 * Otherwise, count up the total spaces/tabs needed to get from the 1933 * beginning of the line (or the last non-<blank> character) to the 1934 * target. 1935 */ 1936 if (current >= target) 1937 spaces = tabs = 0; 1938 else { 1939 cno = current; 1940 tabs = 0; 1941 if (!O_ISSET(sp, O_EXPANDTAB)) { 1942 for (; cno + COL_OFF(cno, ts) <= target; ++tabs) 1943 cno += COL_OFF(cno, ts); 1944 } 1945 spaces = target - cno; 1946 } 1947 1948 /* If we overwrote ai characters, reset the ai count. */ 1949 if (ai_reset) 1950 tp->ai = tabs + spaces; 1951 1952 /* 1953 * Call txt_insch() to insert each character, so that we get the 1954 * correct effect when we add a <tab> to replace N <spaces>. 1955 */ 1956 for (ch = '\t'; tabs > 0; --tabs) 1957 (void)txt_insch(sp, tp, &ch, 0); 1958 for (ch = ' '; spaces > 0; --spaces) 1959 (void)txt_insch(sp, tp, &ch, 0); 1960 return (0); 1961 } 1962 1963 /* 1964 * txt_fc -- 1965 * File name and ex command completion. 1966 */ 1967 static int 1968 txt_fc(SCR *sp, TEXT *tp, int *redrawp) 1969 { 1970 struct stat sb; 1971 ARGS **argv; 1972 EXCMD cmd; 1973 size_t indx, len, nlen, off; 1974 int argc; 1975 CHAR_T *p, *t, *bp; 1976 char *np, *epd = NULL; 1977 size_t nplen; 1978 int fstwd = 1; 1979 1980 *redrawp = 0; 1981 ex_cinit(sp, &cmd, 0, 0, OOBLNO, OOBLNO, 0); 1982 1983 /* 1984 * Find the beginning of this "word" -- if we're at the beginning 1985 * of the line, it's a special case. 1986 */ 1987 if (tp->cno == 1) { 1988 len = 0; 1989 p = tp->lb; 1990 } else { 1991 CHAR_T *ap; 1992 1993 for (len = 0, 1994 off = MAX(tp->ai, tp->offset), ap = tp->lb + off, p = ap; 1995 off < tp->cno; ++off, ++ap) { 1996 if (IS_ESCAPE(sp, &cmd, *ap)) { 1997 if (++off == tp->cno) 1998 break; 1999 ++ap; 2000 len += 2; 2001 } else if (cmdskip(*ap)) { 2002 p = ap + 1; 2003 if (len > 0) 2004 fstwd = 0; 2005 len = 0; 2006 } else 2007 ++len; 2008 } 2009 } 2010 2011 /* 2012 * If we are at the first word, do ex command completion instead of 2013 * file name completion. 2014 */ 2015 if (fstwd) 2016 (void)argv_flt_ex(sp, &cmd, p, len); 2017 else { 2018 if ((bp = argv_uesc(sp, &cmd, p, len)) == NULL) 2019 return (1); 2020 if (argv_flt_path(sp, &cmd, bp, STRLEN(bp))) { 2021 FREE_SPACEW(sp, bp, 0); 2022 return (0); 2023 } 2024 FREE_SPACEW(sp, bp, 0); 2025 } 2026 argc = cmd.argc; 2027 argv = cmd.argv; 2028 2029 switch (argc) { 2030 case 0: /* No matches. */ 2031 (void)sp->gp->scr_bell(sp); 2032 return (0); 2033 case 1: /* One match. */ 2034 /* Always overwrite the old text. */ 2035 nlen = STRLEN(cmd.argv[0]->bp); 2036 break; 2037 default: /* Multiple matches. */ 2038 *redrawp = 1; 2039 if (txt_fc_col(sp, argc, argv)) 2040 return (1); 2041 2042 /* Find the length of the shortest match. */ 2043 for (nlen = cmd.argv[0]->len; --argc > 0;) { 2044 if (cmd.argv[argc]->len < nlen) 2045 nlen = cmd.argv[argc]->len; 2046 for (indx = 0; indx < nlen && 2047 cmd.argv[argc]->bp[indx] == cmd.argv[0]->bp[indx]; 2048 ++indx); 2049 nlen = indx; 2050 } 2051 break; 2052 } 2053 2054 /* Escape the matched part of the path. */ 2055 if (fstwd) 2056 bp = cmd.argv[0]->bp; 2057 else { 2058 if ((bp = argv_esc(sp, &cmd, cmd.argv[0]->bp, nlen)) == NULL) 2059 return (1); 2060 nlen = STRLEN(bp); 2061 } 2062 2063 /* Overwrite the expanded text first. */ 2064 for (t = bp; len > 0 && nlen > 0; --len, --nlen) 2065 *p++ = *t++; 2066 2067 /* If lost text, make the remaining old text overwrite characters. */ 2068 if (len) { 2069 tp->cno -= len; 2070 tp->owrite += len; 2071 } 2072 2073 /* Overwrite any overwrite characters next. */ 2074 for (; nlen > 0 && tp->owrite > 0; --nlen, --tp->owrite, ++tp->cno) 2075 *p++ = *t++; 2076 2077 /* Shift remaining text up, and move the cursor to the end. */ 2078 if (nlen) { 2079 off = p - tp->lb; 2080 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen); 2081 p = tp->lb + off; 2082 2083 tp->cno += nlen; 2084 tp->len += nlen; 2085 2086 if (tp->insert != 0) 2087 (void)MEMMOVE(p + nlen, p, tp->insert); 2088 while (nlen--) 2089 *p++ = *t++; 2090 } 2091 2092 if (!fstwd) 2093 FREE_SPACEW(sp, bp, 0); 2094 2095 /* If not a single match of path, we've done. */ 2096 if (argc != 1 || fstwd) 2097 return (0); 2098 2099 /* If a single match and it's a directory, append a '/'. */ 2100 INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, np, nplen); 2101 if ((epd = expanduser(np)) != NULL) 2102 np = epd; 2103 if (!stat(np, &sb) && S_ISDIR(sb.st_mode)) { 2104 if (tp->owrite == 0) { 2105 off = p - tp->lb; 2106 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1); 2107 p = tp->lb + off; 2108 if (tp->insert != 0) 2109 (void)MEMMOVE(p + 1, p, tp->insert); 2110 ++tp->len; 2111 } else 2112 --tp->owrite; 2113 2114 ++tp->cno; 2115 *p++ = '/'; 2116 } 2117 free(epd); 2118 return (0); 2119 } 2120 2121 /* 2122 * txt_fc_col -- 2123 * Display file names for file name completion. 2124 */ 2125 static int 2126 txt_fc_col(SCR *sp, int argc, ARGS **argv) 2127 { 2128 ARGS **av; 2129 CHAR_T *p; 2130 GS *gp; 2131 size_t base, cnt, col, colwidth, numrows, numcols, prefix, row; 2132 int ac, nf, reset; 2133 char *np, *pp; 2134 size_t nlen; 2135 2136 gp = sp->gp; 2137 2138 /* Trim any directory prefix common to all of the files. */ 2139 INT2CHAR(sp, argv[0]->bp, argv[0]->len + 1, np, nlen); 2140 if ((pp = strrchr(np, '/')) == NULL) 2141 prefix = 0; 2142 else { 2143 prefix = (pp - np) + 1; 2144 for (ac = argc - 1, av = argv + 1; ac > 0; --ac, ++av) 2145 if (av[0]->len < prefix || 2146 MEMCMP(av[0]->bp, argv[0]->bp, 2147 prefix)) { 2148 prefix = 0; 2149 break; 2150 } 2151 } 2152 2153 /* 2154 * Figure out the column width for the longest name. Output is done on 2155 * 6 character "tab" boundaries for no particular reason. (Since we 2156 * don't output tab characters, we ignore the terminal's tab settings.) 2157 * Ignore the user's tab setting because we have no idea how reasonable 2158 * it is. 2159 */ 2160 for (ac = argc, av = argv, colwidth = 0; ac > 0; --ac, ++av) { 2161 for (col = 0, p = av[0]->bp + prefix; *p != '\0'; ++p) 2162 col += KEY_COL(sp, *p); 2163 if (col > colwidth) 2164 colwidth = col; 2165 } 2166 colwidth += COL_OFF(colwidth, 6); 2167 2168 /* 2169 * Writing to the bottom line of the screen is always turned off when 2170 * SC_TINPUT_INFO is set. Turn it back on, we know what we're doing. 2171 */ 2172 if (F_ISSET(sp, SC_TINPUT_INFO)) { 2173 reset = 1; 2174 F_CLR(sp, SC_TINPUT_INFO); 2175 } else 2176 reset = 0; 2177 2178 #define CHK_INTR \ 2179 if (F_ISSET(gp, G_INTERRUPTED)) \ 2180 goto intr; 2181 2182 /* If the largest file name is too large, just print them. */ 2183 if (colwidth >= sp->cols) { 2184 for (ac = argc, av = argv; ac > 0; --ac, ++av) { 2185 INT2CHAR(sp, av[0]->bp+prefix, av[0]->len+1-prefix, 2186 np, nlen); 2187 pp = msg_print(sp, np, &nf); 2188 (void)ex_printf(sp, "%s\n", pp); 2189 if (nf) 2190 FREE_SPACE(sp, pp, 0); 2191 if (F_ISSET(gp, G_INTERRUPTED)) 2192 break; 2193 } 2194 CHK_INTR; 2195 } else { 2196 /* Figure out the number of columns. */ 2197 numcols = (sp->cols - 1) / colwidth; 2198 if (argc > numcols) { 2199 numrows = argc / numcols; 2200 if (argc % numcols) 2201 ++numrows; 2202 } else 2203 numrows = 1; 2204 2205 /* Display the files in sorted order. */ 2206 for (row = 0; row < numrows; ++row) { 2207 for (base = row, col = 0; col < numcols; ++col) { 2208 INT2CHAR(sp, argv[base]->bp+prefix, 2209 argv[base]->len+1-prefix, np, nlen); 2210 pp = msg_print(sp, np, &nf); 2211 cnt = ex_printf(sp, "%s", pp); 2212 if (nf) 2213 FREE_SPACE(sp, pp, 0); 2214 CHK_INTR; 2215 if ((base += numrows) >= argc) 2216 break; 2217 (void)ex_printf(sp, 2218 "%*s", (int)(colwidth - cnt), ""); 2219 CHK_INTR; 2220 } 2221 (void)ex_puts(sp, "\n"); 2222 CHK_INTR; 2223 } 2224 (void)ex_puts(sp, "\n"); 2225 CHK_INTR; 2226 } 2227 (void)ex_fflush(sp); 2228 2229 if (0) { 2230 intr: F_CLR(gp, G_INTERRUPTED); 2231 } 2232 if (reset) 2233 F_SET(sp, SC_TINPUT_INFO); 2234 2235 return (0); 2236 } 2237 2238 /* 2239 * txt_emark -- 2240 * Set the end mark on the line. 2241 */ 2242 static int 2243 txt_emark(SCR *sp, TEXT *tp, size_t cno) 2244 { 2245 CHAR_T ch; 2246 u_char *kp; 2247 size_t chlen, nlen, olen; 2248 CHAR_T *p; 2249 2250 ch = CH_ENDMARK; 2251 2252 /* 2253 * The end mark may not be the same size as the current character. 2254 * Don't let the line shift. 2255 */ 2256 nlen = KEY_COL(sp, ch); 2257 if (tp->lb[cno] == '\t') 2258 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &olen); 2259 else 2260 olen = KEY_COL(sp, tp->lb[cno]); 2261 2262 /* 2263 * If the line got longer, well, it's weird, but it's easy. If 2264 * it's the same length, it's easy. If it got shorter, we have 2265 * to fix it up. 2266 */ 2267 if (olen > nlen) { 2268 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + olen); 2269 chlen = olen - nlen; 2270 if (tp->insert != 0) 2271 MEMMOVE(tp->lb + cno + 1 + chlen, 2272 tp->lb + cno + 1, tp->insert); 2273 2274 tp->len += chlen; 2275 tp->owrite += chlen; 2276 p = tp->lb + cno; 2277 if (tp->lb[cno] == '\t' || 2278 KEY_NEEDSWIDE(sp, tp->lb[cno])) 2279 for (cno += chlen; chlen--;) 2280 *p++ = ' '; 2281 else 2282 for (kp = (u_char *) 2283 KEY_NAME(sp, tp->lb[cno]), 2284 cno += chlen; chlen--;) 2285 *p++ = *kp++; 2286 } 2287 tp->lb[cno] = ch; 2288 return (vs_change(sp, tp->lno, LINE_RESET)); 2289 } 2290 2291 /* 2292 * txt_err -- 2293 * Handle an error during input processing. 2294 */ 2295 static void 2296 txt_err(SCR *sp, TEXTH *tiqh) 2297 { 2298 recno_t lno; 2299 2300 /* 2301 * The problem with input processing is that the cursor is at an 2302 * indeterminate position since some input may have been lost due 2303 * to a malloc error. So, try to go back to the place from which 2304 * the cursor started, knowing that it may no longer be available. 2305 * 2306 * We depend on at least one line number being set in the text 2307 * chain. 2308 */ 2309 for (lno = TAILQ_FIRST(tiqh)->lno; 2310 !db_exist(sp, lno) && lno > 0; --lno); 2311 2312 sp->lno = lno == 0 ? 1 : lno; 2313 sp->cno = 0; 2314 2315 /* Redraw the screen, just in case. */ 2316 F_SET(sp, SC_SCR_REDRAW); 2317 } 2318 2319 /* 2320 * txt_hex -- 2321 * Let the user insert any character value they want. 2322 * 2323 * !!! 2324 * This is an extension. The pattern "^X[0-9a-fA-F]*" is a way 2325 * for the user to specify a character value which their keyboard 2326 * may not be able to enter. 2327 */ 2328 static int 2329 txt_hex(SCR *sp, TEXT *tp) 2330 { 2331 CHAR_T savec; 2332 size_t len, off; 2333 u_long value; 2334 CHAR_T *p, *wp; 2335 2336 /* 2337 * Null-terminate the string. Since nul isn't a legal hex value, 2338 * this should be okay, and lets us use a local routine, which 2339 * presumably understands the character set, to convert the value. 2340 */ 2341 savec = tp->lb[tp->cno]; 2342 tp->lb[tp->cno] = 0; 2343 2344 /* Find the previous CH_HEX character. */ 2345 for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off, ++len) { 2346 if (*p == CH_HEX) { 2347 wp = p + 1; 2348 break; 2349 } 2350 /* Not on this line? Shouldn't happen. */ 2351 if (off == tp->ai || off == tp->offset) 2352 goto nothex; 2353 } 2354 2355 /* If length of 0, then it wasn't a hex value. */ 2356 if (len == 0) 2357 goto nothex; 2358 2359 /* Get the value. */ 2360 errno = 0; 2361 value = STRTOL(wp, NULL, 16); 2362 if (errno || value > UCHAR_MAX) { 2363 nothex: tp->lb[tp->cno] = savec; 2364 return (0); 2365 } 2366 2367 /* Restore the original character. */ 2368 tp->lb[tp->cno] = savec; 2369 2370 /* Adjust the bookkeeping. */ 2371 tp->cno -= len; 2372 tp->len -= len; 2373 tp->lb[tp->cno - 1] = value; 2374 2375 /* Copy down any overwrite characters. */ 2376 if (tp->owrite) 2377 MEMMOVE(tp->lb + tp->cno, tp->lb + tp->cno + len, 2378 tp->owrite); 2379 2380 /* Copy down any insert characters. */ 2381 if (tp->insert) 2382 MEMMOVE(tp->lb + tp->cno + tp->owrite, 2383 tp->lb + tp->cno + tp->owrite + len, 2384 tp->insert); 2385 2386 return (0); 2387 } 2388 2389 /* 2390 * txt_insch -- 2391 * 2392 * !!! 2393 * Historic vi did a special screen optimization for tab characters. As an 2394 * example, for the keystrokes "iabcd<esc>0C<tab>", the tab overwrote the 2395 * rest of the string when it was displayed. 2396 * 2397 * Because early versions of this implementation redisplayed the entire line 2398 * on each keystroke, the "bcd" was pushed to the right as it ignored that 2399 * the user had "promised" to change the rest of the characters. However, 2400 * the historic vi implementation had an even worse bug: given the keystrokes 2401 * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears 2402 * on the second <esc> key. 2403 * 2404 * POSIX 1003.2 requires (will require) that this be fixed, specifying that 2405 * vi overwrite characters the user has committed to changing, on the basis 2406 * of the screen space they require, but that it not overwrite other characters. 2407 */ 2408 static int 2409 txt_insch(SCR *sp, TEXT *tp, CHAR_T *chp, u_int flags) 2410 { 2411 u_char *kp; 2412 CHAR_T savech; 2413 size_t chlen, cno, copydown, olen, nlen; 2414 CHAR_T *p; 2415 2416 /* 2417 * The 'R' command does one-for-one replacement, because there's 2418 * no way to know how many characters the user intends to replace. 2419 */ 2420 if (LF_ISSET(TXT_REPLACE)) { 2421 if (tp->owrite) { 2422 --tp->owrite; 2423 tp->lb[tp->cno++] = *chp; 2424 return (0); 2425 } 2426 } else if (tp->owrite) { /* Overwrite a character. */ 2427 cno = tp->cno; 2428 2429 /* 2430 * If the old or new characters are tabs, then the length of the 2431 * display depends on the character position in the display. We 2432 * don't even try to handle this here, just ask the screen. 2433 */ 2434 if (*chp == '\t') { 2435 savech = tp->lb[cno]; 2436 tp->lb[cno] = '\t'; 2437 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &nlen); 2438 tp->lb[cno] = savech; 2439 } else 2440 nlen = KEY_COL(sp, *chp); 2441 2442 /* 2443 * Eat overwrite characters until we run out of them or we've 2444 * handled the length of the new character. If we only eat 2445 * part of an overwrite character, break it into its component 2446 * elements and display the remaining components. 2447 */ 2448 for (copydown = 0; nlen != 0 && tp->owrite != 0;) { 2449 --tp->owrite; 2450 2451 if (tp->lb[cno] == '\t') 2452 (void)vs_columns(sp, 2453 tp->lb, tp->lno, &cno, &olen); 2454 else 2455 olen = KEY_COL(sp, tp->lb[cno]); 2456 2457 if (olen == nlen) { 2458 nlen = 0; 2459 break; 2460 } 2461 if (olen < nlen) { 2462 ++copydown; 2463 nlen -= olen; 2464 } else { 2465 BINC_RETW(sp, 2466 tp->lb, tp->lb_len, tp->len + olen); 2467 chlen = olen - nlen; 2468 MEMMOVE(tp->lb + cno + 1 + chlen, 2469 tp->lb + cno + 1, 2470 tp->owrite + tp->insert); 2471 2472 tp->len += chlen; 2473 tp->owrite += chlen; 2474 if (tp->lb[cno] == '\t' || 2475 KEY_NEEDSWIDE(sp, tp->lb[cno])) 2476 for (p = tp->lb + cno + 1; chlen--;) 2477 *p++ = ' '; 2478 else 2479 for (kp = (u_char *) 2480 KEY_NAME(sp, tp->lb[cno]) + nlen, 2481 p = tp->lb + cno + 1; chlen--;) 2482 *p++ = *kp++; 2483 nlen = 0; 2484 break; 2485 } 2486 } 2487 2488 /* 2489 * If had to erase several characters, we adjust the total 2490 * count, and if there are any characters left, shift them 2491 * into position. 2492 */ 2493 if (copydown != 0 && (tp->len -= copydown) != 0) 2494 MEMMOVE(tp->lb + cno, tp->lb + cno + copydown, 2495 tp->owrite + tp->insert + copydown); 2496 2497 /* If we had enough overwrite characters, we're done. */ 2498 if (nlen == 0) { 2499 tp->lb[tp->cno++] = *chp; 2500 return (0); 2501 } 2502 } 2503 2504 /* Check to see if the character fits into the input buffer. */ 2505 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1); 2506 2507 ++tp->len; 2508 if (tp->insert) { /* Insert a character. */ 2509 if (tp->insert == 1) 2510 tp->lb[tp->cno + 1] = tp->lb[tp->cno]; 2511 else 2512 MEMMOVE(tp->lb + tp->cno + 1, 2513 tp->lb + tp->cno, tp->owrite + tp->insert); 2514 } 2515 tp->lb[tp->cno++] = *chp; 2516 return (0); 2517 } 2518 2519 /* 2520 * txt_isrch -- 2521 * Do an incremental search. 2522 */ 2523 static int 2524 txt_isrch(SCR *sp, VICMD *vp, TEXT *tp, u_int8_t *is_flagsp) 2525 { 2526 MARK start; 2527 recno_t lno; 2528 u_int sf; 2529 2530 /* If it's a one-line screen, we don't do incrementals. */ 2531 if (IS_ONELINE(sp)) { 2532 FL_CLR(*is_flagsp, IS_RUNNING); 2533 return (0); 2534 } 2535 2536 /* 2537 * If the user erases back to the beginning of the buffer, there's 2538 * nothing to search for. Reset the cursor to the starting point. 2539 */ 2540 if (tp->cno <= 1) { 2541 vp->m_final = vp->m_start; 2542 return (0); 2543 } 2544 2545 /* 2546 * If it's an RE quote character, and not quoted, ignore it until 2547 * we get another character. 2548 */ 2549 if (tp->lb[tp->cno - 1] == '\\' && 2550 (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) 2551 return (0); 2552 2553 /* 2554 * If it's a magic shell character, and not quoted, reset the cursor 2555 * to the starting point. 2556 */ 2557 if (IS_SHELLMETA(sp, tp->lb[tp->cno - 1]) && 2558 (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) 2559 vp->m_final = vp->m_start; 2560 2561 /* 2562 * If we see the search pattern termination character, then quit doing 2563 * an incremental search. There may be more, e.g., ":/foo/;/bar/", 2564 * and we can't handle that incrementally. Also, reset the cursor to 2565 * the original location, the ex search routines don't know anything 2566 * about incremental searches. 2567 */ 2568 if (tp->lb[0] == tp->lb[tp->cno - 1] && 2569 (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) { 2570 vp->m_final = vp->m_start; 2571 FL_CLR(*is_flagsp, IS_RUNNING); 2572 return (0); 2573 } 2574 2575 /* 2576 * Remember the input line and discard the special input map, 2577 * but don't overwrite the input line on the screen. 2578 */ 2579 lno = tp->lno; 2580 F_SET(VIP(sp), VIP_S_MODELINE); 2581 F_CLR(sp, SC_TINPUT | SC_TINPUT_INFO); 2582 if (txt_map_end(sp)) 2583 return (1); 2584 2585 /* 2586 * Specify a starting point and search. If we find a match, move to 2587 * it and refresh the screen. If we didn't find the match, then we 2588 * beep the screen. When searching from the original cursor position, 2589 * we have to move the cursor, otherwise, we don't want to move the 2590 * cursor in case the text at the current position continues to match. 2591 */ 2592 if (FL_ISSET(*is_flagsp, IS_RESTART)) { 2593 start = vp->m_start; 2594 sf = SEARCH_SET; 2595 } else { 2596 start = vp->m_final; 2597 sf = SEARCH_INCR | SEARCH_SET; 2598 } 2599 2600 if (tp->lb[0] == '/' ? 2601 !f_search(sp, 2602 &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf) : 2603 !b_search(sp, 2604 &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf)) { 2605 sp->lno = vp->m_final.lno; 2606 sp->cno = vp->m_final.cno; 2607 FL_CLR(*is_flagsp, IS_RESTART); 2608 2609 if (!KEYS_WAITING(sp) && vs_refresh(sp, 0)) 2610 return (1); 2611 } else 2612 FL_SET(*is_flagsp, IS_RESTART); 2613 2614 /* Reinstantiate the special input map. */ 2615 if (txt_map_init(sp)) 2616 return (1); 2617 F_CLR(VIP(sp), VIP_S_MODELINE); 2618 F_SET(sp, SC_TINPUT | SC_TINPUT_INFO); 2619 2620 /* Reset the line number of the input line. */ 2621 tp->lno = TMAP[0].lno; 2622 2623 /* 2624 * If the colon command-line moved, i.e. the screen scrolled, 2625 * refresh the input line. 2626 * 2627 * XXX 2628 * We shouldn't be calling vs_line, here -- we need dirty bits 2629 * on entries in the SMAP array. 2630 */ 2631 if (lno != TMAP[0].lno) { 2632 if (vs_line(sp, &TMAP[0], NULL, NULL)) 2633 return (1); 2634 (void)sp->gp->scr_refresh(sp, 0); 2635 } 2636 return (0); 2637 } 2638 2639 /* 2640 * txt_resolve -- 2641 * Resolve the input text chain into the file. 2642 */ 2643 static int 2644 txt_resolve(SCR *sp, TEXTH *tiqh, u_int32_t flags) 2645 { 2646 VI_PRIVATE *vip; 2647 TEXT *tp; 2648 recno_t lno; 2649 int changed; 2650 2651 /* 2652 * The first line replaces a current line, and all subsequent lines 2653 * are appended into the file. Resolve autoindented characters for 2654 * each line before committing it. If the latter causes the line to 2655 * change, we have to redisplay it, otherwise the information cached 2656 * about the line will be wrong. 2657 */ 2658 vip = VIP(sp); 2659 tp = TAILQ_FIRST(tiqh); 2660 2661 if (LF_ISSET(TXT_AUTOINDENT)) 2662 txt_ai_resolve(sp, tp, &changed); 2663 else 2664 changed = 0; 2665 if (db_set(sp, tp->lno, tp->lb, tp->len) || 2666 (changed && vs_change(sp, tp->lno, LINE_RESET))) 2667 return (1); 2668 2669 for (lno = tp->lno; (tp = TAILQ_NEXT(tp, q)) != NULL; ++lno) { 2670 if (LF_ISSET(TXT_AUTOINDENT)) 2671 txt_ai_resolve(sp, tp, &changed); 2672 else 2673 changed = 0; 2674 if (db_append(sp, 0, lno, tp->lb, tp->len) || 2675 (changed && vs_change(sp, tp->lno, LINE_RESET))) 2676 return (1); 2677 } 2678 2679 /* 2680 * Clear the input flag, the look-aside buffer is no longer valid. 2681 * Has to be done as part of text resolution, or upon return we'll 2682 * be looking at incorrect data. 2683 */ 2684 F_CLR(sp, SC_TINPUT); 2685 2686 return (0); 2687 } 2688 2689 /* 2690 * txt_showmatch -- 2691 * Show a character match. 2692 * 2693 * !!! 2694 * Historic vi tried to display matches even in the :colon command line. 2695 * I think not. 2696 */ 2697 static int 2698 txt_showmatch(SCR *sp, TEXT *tp) 2699 { 2700 GS *gp; 2701 VCS cs; 2702 MARK m; 2703 int cnt, endc, startc; 2704 2705 gp = sp->gp; 2706 2707 /* 2708 * Do a refresh first, in case we haven't done one in awhile, 2709 * so the user can see what we're complaining about. 2710 */ 2711 UPDATE_POSITION(sp, tp); 2712 if (vs_refresh(sp, 1)) 2713 return (1); 2714 2715 /* 2716 * We don't display the match if it's not on the screen. Find 2717 * out what the first character on the screen is. 2718 */ 2719 if (vs_sm_position(sp, &m, 0, P_TOP)) 2720 return (1); 2721 2722 /* Initialize the getc() interface. */ 2723 cs.cs_lno = tp->lno; 2724 cs.cs_cno = tp->cno - 1; 2725 if (cs_init(sp, &cs)) 2726 return (1); 2727 startc = STRCHR(VIP(sp)->mcs, endc = cs.cs_ch)[-1]; 2728 2729 /* Search for the match. */ 2730 for (cnt = 1;;) { 2731 if (cs_prev(sp, &cs)) 2732 return (1); 2733 if (cs.cs_flags != 0) { 2734 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) { 2735 msgq(sp, M_BERR, 2736 "Unmatched %s", KEY_NAME(sp, endc)); 2737 return (0); 2738 } 2739 continue; 2740 } 2741 if (cs.cs_ch == endc) 2742 ++cnt; 2743 else if (cs.cs_ch == startc && --cnt == 0) 2744 break; 2745 } 2746 2747 /* If the match is on the screen, move to it. */ 2748 if (cs.cs_lno < m.lno || (cs.cs_lno == m.lno && cs.cs_cno < m.cno)) 2749 return (0); 2750 sp->lno = cs.cs_lno; 2751 sp->cno = cs.cs_cno; 2752 if (vs_refresh(sp, 1)) 2753 return (1); 2754 2755 /* Wait for timeout or character arrival. */ 2756 return (v_event_get(sp, 2757 NULL, O_VAL(sp, O_MATCHTIME) * 100, EC_TIMEOUT)); 2758 } 2759 2760 /* 2761 * txt_margin -- 2762 * Handle margin wrap. 2763 */ 2764 static int 2765 txt_margin(SCR *sp, TEXT *tp, TEXT *wmtp, int *didbreak, u_int32_t flags) 2766 { 2767 VI_PRIVATE *vip; 2768 size_t len, off; 2769 CHAR_T *p, *wp; 2770 2771 /* Find the nearest previous blank. */ 2772 for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --off, --p, ++len) { 2773 if (isblank(*p)) { 2774 wp = p + 1; 2775 break; 2776 } 2777 2778 /* 2779 * If reach the start of the line, there's nowhere to break. 2780 * 2781 * !!! 2782 * Historic vi belled each time a character was entered after 2783 * crossing the margin until a space was entered which could 2784 * be used to break the line. I don't as it tends to wake the 2785 * cats. 2786 */ 2787 if (off == tp->ai || off == tp->offset) { 2788 *didbreak = 0; 2789 return (0); 2790 } 2791 } 2792 2793 /* 2794 * Store saved information about the rest of the line in the 2795 * wrapmargin TEXT structure. 2796 * 2797 * !!! 2798 * The offset field holds the length of the current characters 2799 * that the user entered, but which are getting split to the new 2800 * line -- it's going to be used to set the cursor value when we 2801 * move to the new line. 2802 */ 2803 vip = VIP(sp); 2804 wmtp->lb = p + 1; 2805 wmtp->offset = len; 2806 wmtp->insert = LF_ISSET(TXT_APPENDEOL) ? tp->insert - 1 : tp->insert; 2807 wmtp->owrite = tp->owrite; 2808 2809 /* Correct current bookkeeping information. */ 2810 tp->cno -= len; 2811 if (LF_ISSET(TXT_APPENDEOL)) { 2812 tp->len -= len + tp->owrite + (tp->insert - 1); 2813 tp->insert = 1; 2814 } else { 2815 tp->len -= len + tp->owrite + tp->insert; 2816 tp->insert = 0; 2817 } 2818 tp->owrite = 0; 2819 2820 /* 2821 * !!! 2822 * Delete any trailing whitespace from the current line. 2823 */ 2824 for (;; --p, --off) { 2825 if (!isblank(*p)) 2826 break; 2827 --tp->cno; 2828 --tp->len; 2829 if (off == tp->ai || off == tp->offset) 2830 break; 2831 } 2832 *didbreak = 1; 2833 return (0); 2834 } 2835 2836 /* 2837 * txt_Rresolve -- 2838 * Resolve the input line for the 'R' command. 2839 */ 2840 static void 2841 txt_Rresolve(SCR *sp, TEXTH *tiqh, TEXT *tp, const size_t orig_len) 2842 { 2843 TEXT *ttp; 2844 size_t input_len, retain; 2845 CHAR_T *p; 2846 2847 /* 2848 * Check to make sure that the cursor hasn't moved beyond 2849 * the end of the line. 2850 */ 2851 if (tp->owrite == 0) 2852 return; 2853 2854 /* 2855 * Calculate how many characters the user has entered, 2856 * plus the blanks erased by <carriage-return>/<newline>s. 2857 */ 2858 for (ttp = TAILQ_FIRST(tiqh), input_len = 0;;) { 2859 input_len += ttp == tp ? tp->cno : ttp->len + ttp->R_erase; 2860 if ((ttp = TAILQ_NEXT(ttp, q)) == NULL) 2861 break; 2862 } 2863 2864 /* 2865 * If the user has entered less characters than the original line 2866 * was long, restore any overwriteable characters to the original 2867 * characters. These characters are entered as "insert characters", 2868 * because they're after the cursor and we don't want to lose them. 2869 * (This is okay because the R command has no insert characters.) 2870 * We set owrite to 0 so that the insert characters don't get copied 2871 * to somewhere else, which means that the line and the length have 2872 * to be adjusted here as well. 2873 * 2874 * We have to retrieve the original line because the original pinned 2875 * page has long since been discarded. If it doesn't exist, that's 2876 * okay, the user just extended the file. 2877 */ 2878 if (input_len < orig_len) { 2879 retain = MIN(tp->owrite, orig_len - input_len); 2880 if (db_get(sp, 2881 TAILQ_FIRST(tiqh)->lno, DBG_FATAL | DBG_NOCACHE, &p, NULL)) 2882 return; 2883 MEMCPY(tp->lb + tp->cno, p + input_len, retain); 2884 tp->len -= tp->owrite - retain; 2885 tp->owrite = 0; 2886 tp->insert += retain; 2887 } 2888 } 2889 2890 /* 2891 * txt_nomorech -- 2892 * No more characters message. 2893 */ 2894 static void 2895 txt_nomorech(SCR *sp) 2896 { 2897 msgq(sp, M_BERR, "194|No more characters to erase"); 2898 } 2899