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