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