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