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