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