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) { \ 225 (sp)->lno = (tp)->lno; \ 226 (sp)->cno = (tp)->cno; \ 227 } 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 { \ 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 } 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 /* Check for any abbreviations. */ 1542 if ((qp = seq_find(sp, NULL, NULL, p, len, SEQ_ABBREV, NULL)) == NULL) 1543 return (0); 1544 1545 /* 1546 * Push the abbreviation onto the tty stack. Historically, characters 1547 * resulting from an abbreviation expansion were themselves subject to 1548 * map expansions, O_SHOWMATCH matching etc. This means the expanded 1549 * characters will be re-tested for abbreviations. It's difficult to 1550 * know what historic practice in this case was, since abbreviations 1551 * were applied to :colon command lines, so entering abbreviations that 1552 * looped was tricky, although possible. In addition, obvious loops 1553 * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will 1554 * silently only implement and/or display the last abbreviation.) 1555 * 1556 * This implementation doesn't recover well from such abbreviations. 1557 * The main input loop counts abbreviated characters, and, when it 1558 * reaches a limit, discards any abbreviated characters on the queue. 1559 * It's difficult to back up to the original position, as the replay 1560 * queue would have to be adjusted, and the line state when an initial 1561 * abbreviated character was received would have to be saved. 1562 */ 1563 ch = *pushcp; 1564 if (v_event_push(sp, NULL, &ch, 1, CH_ABBREVIATED)) 1565 return (1); 1566 if (v_event_push(sp, NULL, qp->output, qp->olen, CH_ABBREVIATED)) 1567 return (1); 1568 1569 /* 1570 * If the size of the abbreviation is larger than or equal to the size 1571 * of the original text, move to the start of the replaced characters, 1572 * and add their length to the overwrite count. 1573 * 1574 * If the abbreviation is smaller than the original text, we have to 1575 * delete the additional overwrite characters and copy down any insert 1576 * characters. 1577 */ 1578 tp->cno -= len; 1579 if (qp->olen >= len) 1580 tp->owrite += len; 1581 else { 1582 if (tp->insert) 1583 MEMMOVE(tp->lb + tp->cno + qp->olen, 1584 tp->lb + tp->cno + tp->owrite + len, tp->insert); 1585 tp->owrite += qp->olen; 1586 tp->len -= len - qp->olen; 1587 } 1588 1589 /* 1590 * We return the length of the abbreviated characters. This is so 1591 * the calling routine can replace the replay characters with the 1592 * abbreviation. This means that subsequent '.' commands will produce 1593 * the same text, regardless of intervening :[un]abbreviate commands. 1594 * This is historic practice. 1595 */ 1596 *didsubp = len; 1597 return (0); 1598 } 1599 1600 /* 1601 * txt_unmap -- 1602 * Handle the unmap command. 1603 */ 1604 static void 1605 txt_unmap(SCR *sp, TEXT *tp, u_int32_t *ec_flagsp) 1606 { 1607 size_t len, off; 1608 CHAR_T *p; 1609 1610 /* Find the beginning of this "word". */ 1611 for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) { 1612 if (isblank(*p)) { 1613 ++p; 1614 break; 1615 } 1616 ++len; 1617 if (off == tp->ai || off == tp->offset) 1618 break; 1619 } 1620 1621 /* 1622 * !!! 1623 * Historic vi exploded input mappings on the command line. See the 1624 * txt_abbrev() routine for an explanation of the problems inherent 1625 * in this. 1626 * 1627 * We make this work as follows. If we get a string which is <blank> 1628 * terminated and which starts at the beginning of the line, we check 1629 * to see it is the unmap command. If it is, we return that the input 1630 * mapping should be turned off. Note also, minor trickiness, so that 1631 * if the user erases the line and starts another command, we go ahead 1632 * an turn mapping back on. 1633 */ 1634 if ((off == tp->ai || off == tp->offset) && ex_is_unmap(p, len)) 1635 FL_CLR(*ec_flagsp, EC_MAPINPUT); 1636 else 1637 FL_SET(*ec_flagsp, EC_MAPINPUT); 1638 } 1639 1640 /* 1641 * txt_ai_resolve -- 1642 * When a line is resolved by <esc>, review autoindent characters. 1643 */ 1644 static void 1645 txt_ai_resolve(SCR *sp, TEXT *tp, int *changedp) 1646 { 1647 u_long ts; 1648 int del; 1649 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs; 1650 CHAR_T *p; 1651 1652 *changedp = 0; 1653 1654 /* 1655 * If the line is empty, has an offset, or no autoindent 1656 * characters, we're done. 1657 */ 1658 if (!tp->len || tp->offset || !tp->ai) 1659 return; 1660 1661 /* 1662 * If the length is less than or equal to the autoindent 1663 * characters, delete them. 1664 */ 1665 if (tp->len <= tp->ai) { 1666 tp->ai = tp->cno = tp->len = 0; 1667 return; 1668 } 1669 1670 /* 1671 * The autoindent characters plus any leading <blank> characters 1672 * in the line are resolved into the minimum number of characters. 1673 * Historic practice. 1674 */ 1675 ts = O_VAL(sp, O_TABSTOP); 1676 1677 /* Figure out the last <blank> screen column. */ 1678 for (p = tp->lb, scno = 0, len = tp->len, 1679 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p) 1680 if (*p == '\t') { 1681 if (spaces) 1682 tab_after_sp = 1; 1683 scno += COL_OFF(scno, ts); 1684 } else { 1685 ++spaces; 1686 ++scno; 1687 } 1688 1689 /* 1690 * If there are no spaces, or no tabs after spaces and less than 1691 * ts spaces, it's already minimal. 1692 * Keep analysing if expandtab is set. 1693 */ 1694 if ((!spaces || (!tab_after_sp && spaces < ts)) && 1695 !O_ISSET(sp, O_EXPANDTAB)) 1696 return; 1697 1698 /* Count up spaces/tabs needed to get to the target. */ 1699 cno = 0; 1700 tabs = 0; 1701 if (!O_ISSET(sp, O_EXPANDTAB)) { 1702 for (; cno + COL_OFF(cno, ts) <= scno; ++tabs) 1703 cno += COL_OFF(cno, ts); 1704 } 1705 spaces = scno - cno; 1706 1707 /* 1708 * Figure out how many characters we're dropping -- if we're not 1709 * dropping any, it's already minimal, we're done. 1710 */ 1711 old = p - tp->lb; 1712 new = spaces + tabs; 1713 if (old == new) 1714 return; 1715 1716 /* Shift the rest of the characters down, adjust the counts. */ 1717 del = old - new; 1718 MEMMOVE(p - del, p, tp->len - old); 1719 tp->len -= del; 1720 tp->cno -= del; 1721 1722 /* Fill in space/tab characters. */ 1723 for (p = tp->lb; tabs--;) 1724 *p++ = '\t'; 1725 while (spaces--) 1726 *p++ = ' '; 1727 *changedp = 1; 1728 } 1729 1730 /* 1731 * v_txt_auto -- 1732 * Handle autoindent. If aitp isn't NULL, use it, otherwise, 1733 * retrieve the line. 1734 * 1735 * PUBLIC: int v_txt_auto(SCR *, recno_t, TEXT *, size_t, TEXT *); 1736 */ 1737 int 1738 v_txt_auto(SCR *sp, recno_t lno, TEXT *aitp, size_t len, TEXT *tp) 1739 { 1740 size_t nlen; 1741 CHAR_T *p, *t; 1742 1743 if (aitp == NULL) { 1744 /* 1745 * If the ex append command is executed with an address of 0, 1746 * it's possible to get here with a line number of 0. Return 1747 * an indent of 0. 1748 */ 1749 if (lno == 0) { 1750 tp->ai = 0; 1751 return (0); 1752 } 1753 if (db_get(sp, lno, DBG_FATAL, &t, &len)) 1754 return (1); 1755 } else 1756 t = aitp->lb; 1757 1758 /* Count whitespace characters. */ 1759 for (p = t; len > 0; ++p, --len) 1760 if (!isblank(*p)) 1761 break; 1762 1763 /* Set count, check for no indentation. */ 1764 if ((nlen = (p - t)) == 0) 1765 return (0); 1766 1767 /* Make sure the buffer's big enough. */ 1768 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen); 1769 1770 /* Copy the buffer's current contents up. */ 1771 if (tp->len != 0) 1772 MEMMOVE(tp->lb + nlen, tp->lb, tp->len); 1773 tp->len += nlen; 1774 1775 /* Copy the indentation into the new buffer. */ 1776 MEMMOVE(tp->lb, t, nlen); 1777 1778 /* Set the autoindent count. */ 1779 tp->ai = nlen; 1780 return (0); 1781 } 1782 1783 /* 1784 * txt_backup -- 1785 * Back up to the previously edited line. 1786 */ 1787 static TEXT * 1788 txt_backup(SCR *sp, TEXTH *tiqh, TEXT *tp, u_int32_t *flagsp) 1789 { 1790 VI_PRIVATE *vip; 1791 TEXT *ntp; 1792 1793 /* Get a handle on the previous TEXT structure. */ 1794 if ((ntp = TAILQ_PREV(tp, _texth, q)) == NULL) { 1795 if (!FL_ISSET(*flagsp, TXT_REPLAY)) 1796 msgq(sp, M_BERR, 1797 "193|Already at the beginning of the insert"); 1798 return (tp); 1799 } 1800 1801 /* Bookkeeping. */ 1802 ntp->len = ntp->sv_len; 1803 1804 /* Handle appending to the line. */ 1805 vip = VIP(sp); 1806 if (ntp->owrite == 0 && ntp->insert == 0) { 1807 ntp->lb[ntp->len] = CH_CURSOR; 1808 ++ntp->insert; 1809 ++ntp->len; 1810 FL_SET(*flagsp, TXT_APPENDEOL); 1811 } else 1812 FL_CLR(*flagsp, TXT_APPENDEOL); 1813 1814 /* Release the current TEXT. */ 1815 TAILQ_REMOVE(tiqh, tp, q); 1816 text_free(tp); 1817 1818 /* Update the old line on the screen. */ 1819 if (vs_change(sp, ntp->lno + 1, LINE_DELETE)) 1820 return (NULL); 1821 1822 /* Return the new/current TEXT. */ 1823 return (ntp); 1824 } 1825 1826 /* 1827 * Text indentation is truly strange. ^T and ^D do movements to the next or 1828 * previous shiftwidth value, i.e. for a 1-based numbering, with shiftwidth=3, 1829 * ^T moves a cursor on the 7th, 8th or 9th column to the 10th column, and ^D 1830 * moves it back. 1831 * 1832 * !!! 1833 * The ^T and ^D characters in historical vi had special meaning only when they 1834 * were the first characters entered after entering text input mode. As normal 1835 * erase characters couldn't erase autoindent characters (^T in this case), it 1836 * meant that inserting text into previously existing text was strange -- ^T 1837 * only worked if it was the first keystroke(s), and then could only be erased 1838 * using ^D. This implementation treats ^T specially anywhere it occurs in the 1839 * input, and permits the standard erase characters to erase the characters it 1840 * inserts. 1841 * 1842 * !!! 1843 * A fun test is to try: 1844 * :se sw=4 ai list 1845 * i<CR>^Tx<CR>^Tx<CR>^Tx<CR>^Dx<CR>^Dx<CR>^Dx<esc> 1846 * Historic vi loses some of the '$' marks on the line ends, but otherwise gets 1847 * it right. 1848 * 1849 * XXX 1850 * Technically, txt_dent should be part of the screen interface, as it requires 1851 * knowledge of character sizes, including <space>s, on the screen. It's here 1852 * because it's a complicated little beast, and I didn't want to shove it down 1853 * into the screen. It's probable that KEY_COL will call into the screen once 1854 * there are screens with different character representations. 1855 * 1856 * txt_dent -- 1857 * Handle ^T indents, ^D outdents. 1858 * 1859 * If anything changes here, check the ex version to see if it needs similar 1860 * changes. 1861 */ 1862 static int 1863 txt_dent(SCR *sp, TEXT *tp, int swopt, int isindent) 1864 { 1865 CHAR_T ch; 1866 u_long sw, ts; 1867 size_t cno, current, spaces, target, tabs; 1868 int ai_reset; 1869 1870 ts = O_VAL(sp, O_TABSTOP); 1871 sw = O_VAL(sp, swopt); 1872 1873 /* 1874 * Since we don't know what precedes the character(s) being inserted 1875 * (or deleted), the preceding whitespace characters must be resolved. 1876 * An example is a <tab>, which doesn't need a full shiftwidth number 1877 * of columns because it's preceded by <space>s. This is easy to get 1878 * if the user sets shiftwidth to a value less than tabstop (or worse, 1879 * something for which tabstop isn't a multiple) and then uses ^T to 1880 * indent, and ^D to outdent. 1881 * 1882 * Figure out the current and target screen columns. In the historic 1883 * vi, the autoindent column was NOT determined using display widths 1884 * of characters as was the wrapmargin column. For that reason, we 1885 * can't use the vs_column() function, but have to calculate it here. 1886 * This is slow, but it's normally only on the first few characters of 1887 * a line. 1888 */ 1889 for (current = cno = 0; cno < tp->cno; ++cno) 1890 current += tp->lb[cno] == '\t' ? 1891 COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]); 1892 1893 target = current; 1894 if (isindent) 1895 target += COL_OFF(target, sw); 1896 else { 1897 --target; 1898 target -= target % sw; 1899 } 1900 1901 /* 1902 * The AI characters will be turned into overwrite characters if the 1903 * cursor immediately follows them. We test both the cursor position 1904 * and the indent flag because there's no single test. (^T can only 1905 * be detected by the cursor position, and while we know that the test 1906 * is always true for ^D, the cursor can be in more than one place, as 1907 * "0^D" and "^D" are different.) 1908 */ 1909 ai_reset = !isindent || tp->cno == tp->ai + tp->offset; 1910 1911 /* 1912 * Back up over any previous <blank> characters, changing them into 1913 * overwrite characters (including any ai characters). Then figure 1914 * out the current screen column. 1915 */ 1916 for (; tp->cno > tp->offset && 1917 (tp->lb[tp->cno - 1] == ' ' || tp->lb[tp->cno - 1] == '\t'); 1918 --tp->cno, ++tp->owrite); 1919 for (current = cno = 0; cno < tp->cno; ++cno) 1920 current += tp->lb[cno] == '\t' ? 1921 COL_OFF(current, ts) : KEY_COL(sp, tp->lb[cno]); 1922 1923 /* 1924 * If we didn't move up to or past the target, it's because there 1925 * weren't enough characters to delete, e.g. the first character 1926 * of the line was a tp->offset character, and the user entered 1927 * ^D to move to the beginning of a line. An example of this is: 1928 * 1929 * :set ai sw=4<cr>i<space>a<esc>i^T^D 1930 * 1931 * Otherwise, count up the total spaces/tabs needed to get from the 1932 * beginning of the line (or the last non-<blank> character) to the 1933 * target. 1934 */ 1935 if (current >= target) 1936 spaces = tabs = 0; 1937 else { 1938 cno = current; 1939 tabs = 0; 1940 if (!O_ISSET(sp, O_EXPANDTAB)) { 1941 for (; cno + COL_OFF(cno, ts) <= target; ++tabs) 1942 cno += COL_OFF(cno, ts); 1943 } 1944 spaces = target - cno; 1945 } 1946 1947 /* If we overwrote ai characters, reset the ai count. */ 1948 if (ai_reset) 1949 tp->ai = tabs + spaces; 1950 1951 /* 1952 * Call txt_insch() to insert each character, so that we get the 1953 * correct effect when we add a <tab> to replace N <spaces>. 1954 */ 1955 for (ch = '\t'; tabs > 0; --tabs) 1956 (void)txt_insch(sp, tp, &ch, 0); 1957 for (ch = ' '; spaces > 0; --spaces) 1958 (void)txt_insch(sp, tp, &ch, 0); 1959 return (0); 1960 } 1961 1962 /* 1963 * txt_fc -- 1964 * File name and ex command completion. 1965 */ 1966 static int 1967 txt_fc(SCR *sp, TEXT *tp, int *redrawp) 1968 { 1969 struct stat sb; 1970 ARGS **argv; 1971 EXCMD cmd; 1972 size_t indx, len, nlen, off; 1973 int argc; 1974 CHAR_T *p, *t, *bp; 1975 char *np, *epd = NULL; 1976 size_t nplen; 1977 int fstwd = 1; 1978 1979 *redrawp = 0; 1980 ex_cinit(sp, &cmd, 0, 0, OOBLNO, OOBLNO, 0); 1981 1982 /* 1983 * Find the beginning of this "word" -- if we're at the beginning 1984 * of the line, it's a special case. 1985 */ 1986 if (tp->cno == 1) { 1987 len = 0; 1988 p = tp->lb; 1989 } else { 1990 CHAR_T *ap; 1991 1992 for (len = 0, 1993 off = MAX(tp->ai, tp->offset), ap = tp->lb + off, p = ap; 1994 off < tp->cno; ++off, ++ap) { 1995 if (IS_ESCAPE(sp, &cmd, *ap)) { 1996 if (++off == tp->cno) 1997 break; 1998 ++ap; 1999 len += 2; 2000 } else if (cmdskip(*ap)) { 2001 p = ap + 1; 2002 if (len > 0) 2003 fstwd = 0; 2004 len = 0; 2005 } else 2006 ++len; 2007 } 2008 } 2009 2010 /* 2011 * If we are at the first word, do ex command completion instead of 2012 * file name completion. 2013 */ 2014 if (fstwd) 2015 (void)argv_flt_ex(sp, &cmd, p, len); 2016 else { 2017 if ((bp = argv_uesc(sp, &cmd, p, len)) == NULL) 2018 return (1); 2019 if (argv_flt_path(sp, &cmd, bp, STRLEN(bp))) { 2020 FREE_SPACEW(sp, bp, 0); 2021 return (0); 2022 } 2023 FREE_SPACEW(sp, bp, 0); 2024 } 2025 argc = cmd.argc; 2026 argv = cmd.argv; 2027 2028 switch (argc) { 2029 case 0: /* No matches. */ 2030 (void)sp->gp->scr_bell(sp); 2031 return (0); 2032 case 1: /* One match. */ 2033 /* Always overwrite the old text. */ 2034 nlen = STRLEN(cmd.argv[0]->bp); 2035 break; 2036 default: /* Multiple matches. */ 2037 *redrawp = 1; 2038 if (txt_fc_col(sp, argc, argv)) 2039 return (1); 2040 2041 /* Find the length of the shortest match. */ 2042 for (nlen = cmd.argv[0]->len; --argc > 0;) { 2043 if (cmd.argv[argc]->len < nlen) 2044 nlen = cmd.argv[argc]->len; 2045 for (indx = 0; indx < nlen && 2046 cmd.argv[argc]->bp[indx] == cmd.argv[0]->bp[indx]; 2047 ++indx); 2048 nlen = indx; 2049 } 2050 break; 2051 } 2052 2053 /* Escape the matched part of the path. */ 2054 if (fstwd) 2055 bp = cmd.argv[0]->bp; 2056 else { 2057 if ((bp = argv_esc(sp, &cmd, cmd.argv[0]->bp, nlen)) == NULL) 2058 return (1); 2059 nlen = STRLEN(bp); 2060 } 2061 2062 /* Overwrite the expanded text first. */ 2063 for (t = bp; len > 0 && nlen > 0; --len, --nlen) 2064 *p++ = *t++; 2065 2066 /* If lost text, make the remaining old text overwrite characters. */ 2067 if (len) { 2068 tp->cno -= len; 2069 tp->owrite += len; 2070 } 2071 2072 /* Overwrite any overwrite characters next. */ 2073 for (; nlen > 0 && tp->owrite > 0; --nlen, --tp->owrite, ++tp->cno) 2074 *p++ = *t++; 2075 2076 /* Shift remaining text up, and move the cursor to the end. */ 2077 if (nlen) { 2078 off = p - tp->lb; 2079 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + nlen); 2080 p = tp->lb + off; 2081 2082 tp->cno += nlen; 2083 tp->len += nlen; 2084 2085 if (tp->insert != 0) 2086 (void)MEMMOVE(p + nlen, p, tp->insert); 2087 while (nlen--) 2088 *p++ = *t++; 2089 } 2090 2091 if (!fstwd) 2092 FREE_SPACEW(sp, bp, 0); 2093 2094 /* If not a single match of path, we've done. */ 2095 if (argc != 1 || fstwd) 2096 return (0); 2097 2098 /* If a single match and it's a directory, append a '/'. */ 2099 INT2CHAR(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, np, nplen); 2100 if ((epd = expanduser(np)) != NULL) 2101 np = epd; 2102 if (!stat(np, &sb) && S_ISDIR(sb.st_mode)) { 2103 if (tp->owrite == 0) { 2104 off = p - tp->lb; 2105 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1); 2106 p = tp->lb + off; 2107 if (tp->insert != 0) 2108 (void)MEMMOVE(p + 1, p, tp->insert); 2109 ++tp->len; 2110 } else 2111 --tp->owrite; 2112 2113 ++tp->cno; 2114 *p++ = '/'; 2115 } 2116 free(epd); 2117 return (0); 2118 } 2119 2120 /* 2121 * txt_fc_col -- 2122 * Display file names for file name completion. 2123 */ 2124 static int 2125 txt_fc_col(SCR *sp, int argc, ARGS **argv) 2126 { 2127 ARGS **av; 2128 CHAR_T *p; 2129 GS *gp; 2130 size_t base, cnt, col, colwidth, numrows, numcols, prefix, row; 2131 int ac, nf, reset; 2132 char *np, *pp; 2133 size_t nlen; 2134 2135 gp = sp->gp; 2136 2137 /* Trim any directory prefix common to all of the files. */ 2138 INT2CHAR(sp, argv[0]->bp, argv[0]->len + 1, np, nlen); 2139 if ((pp = strrchr(np, '/')) == NULL) 2140 prefix = 0; 2141 else { 2142 prefix = (pp - np) + 1; 2143 for (ac = argc - 1, av = argv + 1; ac > 0; --ac, ++av) 2144 if (av[0]->len < prefix || 2145 MEMCMP(av[0]->bp, argv[0]->bp, 2146 prefix)) { 2147 prefix = 0; 2148 break; 2149 } 2150 } 2151 2152 /* 2153 * Figure out the column width for the longest name. Output is done on 2154 * 6 character "tab" boundaries for no particular reason. (Since we 2155 * don't output tab characters, we ignore the terminal's tab settings.) 2156 * Ignore the user's tab setting because we have no idea how reasonable 2157 * it is. 2158 */ 2159 for (ac = argc, av = argv, colwidth = 0; ac > 0; --ac, ++av) { 2160 for (col = 0, p = av[0]->bp + prefix; *p != '\0'; ++p) 2161 col += KEY_COL(sp, *p); 2162 if (col > colwidth) 2163 colwidth = col; 2164 } 2165 colwidth += COL_OFF(colwidth, 6); 2166 2167 /* 2168 * Writing to the bottom line of the screen is always turned off when 2169 * SC_TINPUT_INFO is set. Turn it back on, we know what we're doing. 2170 */ 2171 if (F_ISSET(sp, SC_TINPUT_INFO)) { 2172 reset = 1; 2173 F_CLR(sp, SC_TINPUT_INFO); 2174 } else 2175 reset = 0; 2176 2177 #define CHK_INTR \ 2178 if (F_ISSET(gp, G_INTERRUPTED)) \ 2179 goto intr; 2180 2181 /* If the largest file name is too large, just print them. */ 2182 if (colwidth >= sp->cols) { 2183 for (ac = argc, av = argv; ac > 0; --ac, ++av) { 2184 INT2CHAR(sp, av[0]->bp+prefix, av[0]->len+1-prefix, 2185 np, nlen); 2186 pp = msg_print(sp, np, &nf); 2187 (void)ex_printf(sp, "%s\n", pp); 2188 if (nf) 2189 FREE_SPACE(sp, pp, 0); 2190 if (F_ISSET(gp, G_INTERRUPTED)) 2191 break; 2192 } 2193 CHK_INTR; 2194 } else { 2195 /* Figure out the number of columns. */ 2196 numcols = (sp->cols - 1) / colwidth; 2197 if (argc > numcols) { 2198 numrows = argc / numcols; 2199 if (argc % numcols) 2200 ++numrows; 2201 } else 2202 numrows = 1; 2203 2204 /* Display the files in sorted order. */ 2205 for (row = 0; row < numrows; ++row) { 2206 for (base = row, col = 0; col < numcols; ++col) { 2207 INT2CHAR(sp, argv[base]->bp+prefix, 2208 argv[base]->len+1-prefix, np, nlen); 2209 pp = msg_print(sp, np, &nf); 2210 cnt = ex_printf(sp, "%s", pp); 2211 if (nf) 2212 FREE_SPACE(sp, pp, 0); 2213 CHK_INTR; 2214 if ((base += numrows) >= argc) 2215 break; 2216 (void)ex_printf(sp, 2217 "%*s", (int)(colwidth - cnt), ""); 2218 CHK_INTR; 2219 } 2220 (void)ex_puts(sp, "\n"); 2221 CHK_INTR; 2222 } 2223 (void)ex_puts(sp, "\n"); 2224 CHK_INTR; 2225 } 2226 (void)ex_fflush(sp); 2227 2228 if (0) { 2229 intr: F_CLR(gp, G_INTERRUPTED); 2230 } 2231 if (reset) 2232 F_SET(sp, SC_TINPUT_INFO); 2233 2234 return (0); 2235 } 2236 2237 /* 2238 * txt_emark -- 2239 * Set the end mark on the line. 2240 */ 2241 static int 2242 txt_emark(SCR *sp, TEXT *tp, size_t cno) 2243 { 2244 CHAR_T ch; 2245 u_char *kp; 2246 size_t chlen, nlen, olen; 2247 CHAR_T *p; 2248 2249 ch = CH_ENDMARK; 2250 2251 /* 2252 * The end mark may not be the same size as the current character. 2253 * Don't let the line shift. 2254 */ 2255 nlen = KEY_COL(sp, ch); 2256 if (tp->lb[cno] == '\t') 2257 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &olen); 2258 else 2259 olen = KEY_COL(sp, tp->lb[cno]); 2260 2261 /* 2262 * If the line got longer, well, it's weird, but it's easy. If 2263 * it's the same length, it's easy. If it got shorter, we have 2264 * to fix it up. 2265 */ 2266 if (olen > nlen) { 2267 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + olen); 2268 chlen = olen - nlen; 2269 if (tp->insert != 0) 2270 MEMMOVE(tp->lb + cno + 1 + chlen, 2271 tp->lb + cno + 1, tp->insert); 2272 2273 tp->len += chlen; 2274 tp->owrite += chlen; 2275 p = tp->lb + cno; 2276 if (tp->lb[cno] == '\t' || 2277 KEY_NEEDSWIDE(sp, tp->lb[cno])) 2278 for (cno += chlen; chlen--;) 2279 *p++ = ' '; 2280 else 2281 for (kp = (u_char *) 2282 KEY_NAME(sp, tp->lb[cno]), 2283 cno += chlen; chlen--;) 2284 *p++ = *kp++; 2285 } 2286 tp->lb[cno] = ch; 2287 return (vs_change(sp, tp->lno, LINE_RESET)); 2288 } 2289 2290 /* 2291 * txt_err -- 2292 * Handle an error during input processing. 2293 */ 2294 static void 2295 txt_err(SCR *sp, TEXTH *tiqh) 2296 { 2297 recno_t lno; 2298 2299 /* 2300 * The problem with input processing is that the cursor is at an 2301 * indeterminate position since some input may have been lost due 2302 * to a malloc error. So, try to go back to the place from which 2303 * the cursor started, knowing that it may no longer be available. 2304 * 2305 * We depend on at least one line number being set in the text 2306 * chain. 2307 */ 2308 for (lno = TAILQ_FIRST(tiqh)->lno; 2309 !db_exist(sp, lno) && lno > 0; --lno); 2310 2311 sp->lno = lno == 0 ? 1 : lno; 2312 sp->cno = 0; 2313 2314 /* Redraw the screen, just in case. */ 2315 F_SET(sp, SC_SCR_REDRAW); 2316 } 2317 2318 /* 2319 * txt_hex -- 2320 * Let the user insert any character value they want. 2321 * 2322 * !!! 2323 * This is an extension. The pattern "^X[0-9a-fA-F]*" is a way 2324 * for the user to specify a character value which their keyboard 2325 * may not be able to enter. 2326 */ 2327 static int 2328 txt_hex(SCR *sp, TEXT *tp) 2329 { 2330 CHAR_T savec; 2331 size_t len, off; 2332 u_long value; 2333 CHAR_T *p, *wp; 2334 2335 /* 2336 * Null-terminate the string. Since nul isn't a legal hex value, 2337 * this should be okay, and lets us use a local routine, which 2338 * presumably understands the character set, to convert the value. 2339 */ 2340 savec = tp->lb[tp->cno]; 2341 tp->lb[tp->cno] = 0; 2342 2343 /* Find the previous CH_HEX character. */ 2344 for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --p, --off, ++len) { 2345 if (*p == CH_HEX) { 2346 wp = p + 1; 2347 break; 2348 } 2349 /* Not on this line? Shouldn't happen. */ 2350 if (off == tp->ai || off == tp->offset) 2351 goto nothex; 2352 } 2353 2354 /* If length of 0, then it wasn't a hex value. */ 2355 if (len == 0) 2356 goto nothex; 2357 2358 /* Get the value. */ 2359 errno = 0; 2360 value = STRTOL(wp, NULL, 16); 2361 if (errno || value > UCHAR_MAX) { 2362 nothex: tp->lb[tp->cno] = savec; 2363 return (0); 2364 } 2365 2366 /* Restore the original character. */ 2367 tp->lb[tp->cno] = savec; 2368 2369 /* Adjust the bookkeeping. */ 2370 tp->cno -= len; 2371 tp->len -= len; 2372 tp->lb[tp->cno - 1] = value; 2373 2374 /* Copy down any overwrite characters. */ 2375 if (tp->owrite) 2376 MEMMOVE(tp->lb + tp->cno, tp->lb + tp->cno + len, 2377 tp->owrite); 2378 2379 /* Copy down any insert characters. */ 2380 if (tp->insert) 2381 MEMMOVE(tp->lb + tp->cno + tp->owrite, 2382 tp->lb + tp->cno + tp->owrite + len, 2383 tp->insert); 2384 2385 return (0); 2386 } 2387 2388 /* 2389 * txt_insch -- 2390 * 2391 * !!! 2392 * Historic vi did a special screen optimization for tab characters. As an 2393 * example, for the keystrokes "iabcd<esc>0C<tab>", the tab overwrote the 2394 * rest of the string when it was displayed. 2395 * 2396 * Because early versions of this implementation redisplayed the entire line 2397 * on each keystroke, the "bcd" was pushed to the right as it ignored that 2398 * the user had "promised" to change the rest of the characters. However, 2399 * the historic vi implementation had an even worse bug: given the keystrokes 2400 * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears 2401 * on the second <esc> key. 2402 * 2403 * POSIX 1003.2 requires (will require) that this be fixed, specifying that 2404 * vi overwrite characters the user has committed to changing, on the basis 2405 * of the screen space they require, but that it not overwrite other characters. 2406 */ 2407 static int 2408 txt_insch(SCR *sp, TEXT *tp, CHAR_T *chp, u_int flags) 2409 { 2410 u_char *kp; 2411 CHAR_T savech; 2412 size_t chlen, cno, copydown, olen, nlen; 2413 CHAR_T *p; 2414 2415 /* 2416 * The 'R' command does one-for-one replacement, because there's 2417 * no way to know how many characters the user intends to replace. 2418 */ 2419 if (LF_ISSET(TXT_REPLACE)) { 2420 if (tp->owrite) { 2421 --tp->owrite; 2422 tp->lb[tp->cno++] = *chp; 2423 return (0); 2424 } 2425 } else if (tp->owrite) { /* Overwrite a character. */ 2426 cno = tp->cno; 2427 2428 /* 2429 * If the old or new characters are tabs, then the length of the 2430 * display depends on the character position in the display. We 2431 * don't even try to handle this here, just ask the screen. 2432 */ 2433 if (*chp == '\t') { 2434 savech = tp->lb[cno]; 2435 tp->lb[cno] = '\t'; 2436 (void)vs_columns(sp, tp->lb, tp->lno, &cno, &nlen); 2437 tp->lb[cno] = savech; 2438 } else 2439 nlen = KEY_COL(sp, *chp); 2440 2441 /* 2442 * Eat overwrite characters until we run out of them or we've 2443 * handled the length of the new character. If we only eat 2444 * part of an overwrite character, break it into its component 2445 * elements and display the remaining components. 2446 */ 2447 for (copydown = 0; nlen != 0 && tp->owrite != 0;) { 2448 --tp->owrite; 2449 2450 if (tp->lb[cno] == '\t') 2451 (void)vs_columns(sp, 2452 tp->lb, tp->lno, &cno, &olen); 2453 else 2454 olen = KEY_COL(sp, tp->lb[cno]); 2455 2456 if (olen == nlen) { 2457 nlen = 0; 2458 break; 2459 } 2460 if (olen < nlen) { 2461 ++copydown; 2462 nlen -= olen; 2463 } else { 2464 BINC_RETW(sp, 2465 tp->lb, tp->lb_len, tp->len + olen); 2466 chlen = olen - nlen; 2467 MEMMOVE(tp->lb + cno + 1 + chlen, 2468 tp->lb + cno + 1, 2469 tp->owrite + tp->insert); 2470 2471 tp->len += chlen; 2472 tp->owrite += chlen; 2473 if (tp->lb[cno] == '\t' || 2474 KEY_NEEDSWIDE(sp, tp->lb[cno])) 2475 for (p = tp->lb + cno + 1; chlen--;) 2476 *p++ = ' '; 2477 else 2478 for (kp = (u_char *) 2479 KEY_NAME(sp, tp->lb[cno]) + nlen, 2480 p = tp->lb + cno + 1; chlen--;) 2481 *p++ = *kp++; 2482 nlen = 0; 2483 break; 2484 } 2485 } 2486 2487 /* 2488 * If had to erase several characters, we adjust the total 2489 * count, and if there are any characters left, shift them 2490 * into position. 2491 */ 2492 if (copydown != 0 && (tp->len -= copydown) != 0) 2493 MEMMOVE(tp->lb + cno, tp->lb + cno + copydown, 2494 tp->owrite + tp->insert + copydown); 2495 2496 /* If we had enough overwrite characters, we're done. */ 2497 if (nlen == 0) { 2498 tp->lb[tp->cno++] = *chp; 2499 return (0); 2500 } 2501 } 2502 2503 /* Check to see if the character fits into the input buffer. */ 2504 BINC_RETW(sp, tp->lb, tp->lb_len, tp->len + 1); 2505 2506 ++tp->len; 2507 if (tp->insert) { /* Insert a character. */ 2508 if (tp->insert == 1) 2509 tp->lb[tp->cno + 1] = tp->lb[tp->cno]; 2510 else 2511 MEMMOVE(tp->lb + tp->cno + 1, 2512 tp->lb + tp->cno, tp->owrite + tp->insert); 2513 } 2514 tp->lb[tp->cno++] = *chp; 2515 return (0); 2516 } 2517 2518 /* 2519 * txt_isrch -- 2520 * Do an incremental search. 2521 */ 2522 static int 2523 txt_isrch(SCR *sp, VICMD *vp, TEXT *tp, u_int8_t *is_flagsp) 2524 { 2525 MARK start; 2526 recno_t lno; 2527 u_int sf; 2528 2529 /* If it's a one-line screen, we don't do incrementals. */ 2530 if (IS_ONELINE(sp)) { 2531 FL_CLR(*is_flagsp, IS_RUNNING); 2532 return (0); 2533 } 2534 2535 /* 2536 * If the user erases back to the beginning of the buffer, there's 2537 * nothing to search for. Reset the cursor to the starting point. 2538 */ 2539 if (tp->cno <= 1) { 2540 vp->m_final = vp->m_start; 2541 return (0); 2542 } 2543 2544 /* 2545 * If it's an RE quote character, and not quoted, ignore it until 2546 * we get another character. 2547 */ 2548 if (tp->lb[tp->cno - 1] == '\\' && 2549 (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) 2550 return (0); 2551 2552 /* 2553 * If it's a magic shell character, and not quoted, reset the cursor 2554 * to the starting point. 2555 */ 2556 if (IS_SHELLMETA(sp, tp->lb[tp->cno - 1]) && 2557 (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) 2558 vp->m_final = vp->m_start; 2559 2560 /* 2561 * If we see the search pattern termination character, then quit doing 2562 * an incremental search. There may be more, e.g., ":/foo/;/bar/", 2563 * and we can't handle that incrementally. Also, reset the cursor to 2564 * the original location, the ex search routines don't know anything 2565 * about incremental searches. 2566 */ 2567 if (tp->lb[0] == tp->lb[tp->cno - 1] && 2568 (tp->cno == 2 || tp->lb[tp->cno - 2] != '\\')) { 2569 vp->m_final = vp->m_start; 2570 FL_CLR(*is_flagsp, IS_RUNNING); 2571 return (0); 2572 } 2573 2574 /* 2575 * Remember the input line and discard the special input map, 2576 * but don't overwrite the input line on the screen. 2577 */ 2578 lno = tp->lno; 2579 F_SET(VIP(sp), VIP_S_MODELINE); 2580 F_CLR(sp, SC_TINPUT | SC_TINPUT_INFO); 2581 if (txt_map_end(sp)) 2582 return (1); 2583 2584 /* 2585 * Specify a starting point and search. If we find a match, move to 2586 * it and refresh the screen. If we didn't find the match, then we 2587 * beep the screen. When searching from the original cursor position, 2588 * we have to move the cursor, otherwise, we don't want to move the 2589 * cursor in case the text at the current position continues to match. 2590 */ 2591 if (FL_ISSET(*is_flagsp, IS_RESTART)) { 2592 start = vp->m_start; 2593 sf = SEARCH_SET; 2594 } else { 2595 start = vp->m_final; 2596 sf = SEARCH_INCR | SEARCH_SET; 2597 } 2598 2599 if (tp->lb[0] == '/' ? 2600 !f_search(sp, 2601 &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf) : 2602 !b_search(sp, 2603 &start, &vp->m_final, tp->lb + 1, tp->cno - 1, NULL, sf)) { 2604 sp->lno = vp->m_final.lno; 2605 sp->cno = vp->m_final.cno; 2606 FL_CLR(*is_flagsp, IS_RESTART); 2607 2608 if (!KEYS_WAITING(sp) && vs_refresh(sp, 0)) 2609 return (1); 2610 } else 2611 FL_SET(*is_flagsp, IS_RESTART); 2612 2613 /* Reinstantiate the special input map. */ 2614 if (txt_map_init(sp)) 2615 return (1); 2616 F_CLR(VIP(sp), VIP_S_MODELINE); 2617 F_SET(sp, SC_TINPUT | SC_TINPUT_INFO); 2618 2619 /* Reset the line number of the input line. */ 2620 tp->lno = TMAP[0].lno; 2621 2622 /* 2623 * If the colon command-line moved, i.e. the screen scrolled, 2624 * refresh the input line. 2625 * 2626 * XXX 2627 * We shouldn't be calling vs_line, here -- we need dirty bits 2628 * on entries in the SMAP array. 2629 */ 2630 if (lno != TMAP[0].lno) { 2631 if (vs_line(sp, &TMAP[0], NULL, NULL)) 2632 return (1); 2633 (void)sp->gp->scr_refresh(sp, 0); 2634 } 2635 return (0); 2636 } 2637 2638 /* 2639 * txt_resolve -- 2640 * Resolve the input text chain into the file. 2641 */ 2642 static int 2643 txt_resolve(SCR *sp, TEXTH *tiqh, u_int32_t flags) 2644 { 2645 VI_PRIVATE *vip; 2646 TEXT *tp; 2647 recno_t lno; 2648 int changed; 2649 2650 /* 2651 * The first line replaces a current line, and all subsequent lines 2652 * are appended into the file. Resolve autoindented characters for 2653 * each line before committing it. If the latter causes the line to 2654 * change, we have to redisplay it, otherwise the information cached 2655 * about the line will be wrong. 2656 */ 2657 vip = VIP(sp); 2658 tp = TAILQ_FIRST(tiqh); 2659 2660 if (LF_ISSET(TXT_AUTOINDENT)) 2661 txt_ai_resolve(sp, tp, &changed); 2662 else 2663 changed = 0; 2664 if (db_set(sp, tp->lno, tp->lb, tp->len) || 2665 (changed && vs_change(sp, tp->lno, LINE_RESET))) 2666 return (1); 2667 2668 for (lno = tp->lno; (tp = TAILQ_NEXT(tp, q)) != NULL; ++lno) { 2669 if (LF_ISSET(TXT_AUTOINDENT)) 2670 txt_ai_resolve(sp, tp, &changed); 2671 else 2672 changed = 0; 2673 if (db_append(sp, 0, lno, tp->lb, tp->len) || 2674 (changed && vs_change(sp, tp->lno, LINE_RESET))) 2675 return (1); 2676 } 2677 2678 /* 2679 * Clear the input flag, the look-aside buffer is no longer valid. 2680 * Has to be done as part of text resolution, or upon return we'll 2681 * be looking at incorrect data. 2682 */ 2683 F_CLR(sp, SC_TINPUT); 2684 2685 return (0); 2686 } 2687 2688 /* 2689 * txt_showmatch -- 2690 * Show a character match. 2691 * 2692 * !!! 2693 * Historic vi tried to display matches even in the :colon command line. 2694 * I think not. 2695 */ 2696 static int 2697 txt_showmatch(SCR *sp, TEXT *tp) 2698 { 2699 GS *gp; 2700 VCS cs; 2701 MARK m; 2702 int cnt, endc, startc; 2703 2704 gp = sp->gp; 2705 2706 /* 2707 * Do a refresh first, in case we haven't done one in awhile, 2708 * so the user can see what we're complaining about. 2709 */ 2710 UPDATE_POSITION(sp, tp); 2711 if (vs_refresh(sp, 1)) 2712 return (1); 2713 2714 /* 2715 * We don't display the match if it's not on the screen. Find 2716 * out what the first character on the screen is. 2717 */ 2718 if (vs_sm_position(sp, &m, 0, P_TOP)) 2719 return (1); 2720 2721 /* Initialize the getc() interface. */ 2722 cs.cs_lno = tp->lno; 2723 cs.cs_cno = tp->cno - 1; 2724 if (cs_init(sp, &cs)) 2725 return (1); 2726 startc = STRCHR(VIP(sp)->mcs, endc = cs.cs_ch)[-1]; 2727 2728 /* Search for the match. */ 2729 for (cnt = 1;;) { 2730 if (cs_prev(sp, &cs)) 2731 return (1); 2732 if (cs.cs_flags != 0) { 2733 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) { 2734 msgq(sp, M_BERR, 2735 "Unmatched %s", KEY_NAME(sp, endc)); 2736 return (0); 2737 } 2738 continue; 2739 } 2740 if (cs.cs_ch == endc) 2741 ++cnt; 2742 else if (cs.cs_ch == startc && --cnt == 0) 2743 break; 2744 } 2745 2746 /* If the match is on the screen, move to it. */ 2747 if (cs.cs_lno < m.lno || (cs.cs_lno == m.lno && cs.cs_cno < m.cno)) 2748 return (0); 2749 sp->lno = cs.cs_lno; 2750 sp->cno = cs.cs_cno; 2751 if (vs_refresh(sp, 1)) 2752 return (1); 2753 2754 /* Wait for timeout or character arrival. */ 2755 return (v_event_get(sp, 2756 NULL, O_VAL(sp, O_MATCHTIME) * 100, EC_TIMEOUT)); 2757 } 2758 2759 /* 2760 * txt_margin -- 2761 * Handle margin wrap. 2762 */ 2763 static int 2764 txt_margin(SCR *sp, TEXT *tp, TEXT *wmtp, int *didbreak, u_int32_t flags) 2765 { 2766 VI_PRIVATE *vip; 2767 size_t len, off; 2768 CHAR_T *p, *wp; 2769 2770 /* Find the nearest previous blank. */ 2771 for (off = tp->cno - 1, p = tp->lb + off, len = 0;; --off, --p, ++len) { 2772 if (isblank(*p)) { 2773 wp = p + 1; 2774 break; 2775 } 2776 2777 /* 2778 * If reach the start of the line, there's nowhere to break. 2779 * 2780 * !!! 2781 * Historic vi belled each time a character was entered after 2782 * crossing the margin until a space was entered which could 2783 * be used to break the line. I don't as it tends to wake the 2784 * cats. 2785 */ 2786 if (off == tp->ai || off == tp->offset) { 2787 *didbreak = 0; 2788 return (0); 2789 } 2790 } 2791 2792 /* 2793 * Store saved information about the rest of the line in the 2794 * wrapmargin TEXT structure. 2795 * 2796 * !!! 2797 * The offset field holds the length of the current characters 2798 * that the user entered, but which are getting split to the new 2799 * line -- it's going to be used to set the cursor value when we 2800 * move to the new line. 2801 */ 2802 vip = VIP(sp); 2803 wmtp->lb = p + 1; 2804 wmtp->offset = len; 2805 wmtp->insert = LF_ISSET(TXT_APPENDEOL) ? tp->insert - 1 : tp->insert; 2806 wmtp->owrite = tp->owrite; 2807 2808 /* Correct current bookkeeping information. */ 2809 tp->cno -= len; 2810 if (LF_ISSET(TXT_APPENDEOL)) { 2811 tp->len -= len + tp->owrite + (tp->insert - 1); 2812 tp->insert = 1; 2813 } else { 2814 tp->len -= len + tp->owrite + tp->insert; 2815 tp->insert = 0; 2816 } 2817 tp->owrite = 0; 2818 2819 /* 2820 * !!! 2821 * Delete any trailing whitespace from the current line. 2822 */ 2823 for (;; --p, --off) { 2824 if (!isblank(*p)) 2825 break; 2826 --tp->cno; 2827 --tp->len; 2828 if (off == tp->ai || off == tp->offset) 2829 break; 2830 } 2831 *didbreak = 1; 2832 return (0); 2833 } 2834 2835 /* 2836 * txt_Rresolve -- 2837 * Resolve the input line for the 'R' command. 2838 */ 2839 static void 2840 txt_Rresolve(SCR *sp, TEXTH *tiqh, TEXT *tp, const size_t orig_len) 2841 { 2842 TEXT *ttp; 2843 size_t input_len, retain; 2844 CHAR_T *p; 2845 2846 /* 2847 * Check to make sure that the cursor hasn't moved beyond 2848 * the end of the line. 2849 */ 2850 if (tp->owrite == 0) 2851 return; 2852 2853 /* 2854 * Calculate how many characters the user has entered, 2855 * plus the blanks erased by <carriage-return>/<newline>s. 2856 */ 2857 for (ttp = TAILQ_FIRST(tiqh), input_len = 0;;) { 2858 input_len += ttp == tp ? tp->cno : ttp->len + ttp->R_erase; 2859 if ((ttp = TAILQ_NEXT(ttp, q)) == NULL) 2860 break; 2861 } 2862 2863 /* 2864 * If the user has entered less characters than the original line 2865 * was long, restore any overwriteable characters to the original 2866 * characters. These characters are entered as "insert characters", 2867 * because they're after the cursor and we don't want to lose them. 2868 * (This is okay because the R command has no insert characters.) 2869 * We set owrite to 0 so that the insert characters don't get copied 2870 * to somewhere else, which means that the line and the length have 2871 * to be adjusted here as well. 2872 * 2873 * We have to retrieve the original line because the original pinned 2874 * page has long since been discarded. If it doesn't exist, that's 2875 * okay, the user just extended the file. 2876 */ 2877 if (input_len < orig_len) { 2878 retain = MIN(tp->owrite, orig_len - input_len); 2879 if (db_get(sp, 2880 TAILQ_FIRST(tiqh)->lno, DBG_FATAL | DBG_NOCACHE, &p, NULL)) 2881 return; 2882 MEMCPY(tp->lb + tp->cno, p + input_len, retain); 2883 tp->len -= tp->owrite - retain; 2884 tp->owrite = 0; 2885 tp->insert += retain; 2886 } 2887 } 2888 2889 /* 2890 * txt_nomorech -- 2891 * No more characters message. 2892 */ 2893 static void 2894 txt_nomorech(SCR *sp) 2895 { 2896 msgq(sp, M_BERR, "194|No more characters to erase"); 2897 } 2898