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