update to 1.01
[nvi.git] / vi / v_txt.c
blobe3b85f7c02c4504a4c5e911384cee8ac73a3bd31
1 /*-
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: v_txt.c,v 8.79 1994/01/09 16:29:21 bostic Exp $ (Berkeley) $Date: 1994/01/09 16:29:21 $";
10 #endif /* not lint */
12 #include <sys/types.h>
13 #include <sys/time.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
21 #include "vi.h"
22 #include "seq.h"
23 #include "vcmd.h"
24 #include "excmd.h"
26 static int txt_abbrev __P((SCR *, TEXT *, ARG_CHAR_T, int, int *, int *));
27 static void txt_ai_resolve __P((SCR *, TEXT *));
28 static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int));
29 static void txt_err __P((SCR *, EXF *, TEXTH *));
30 static int txt_hex __P((SCR *, TEXT *, int *, ARG_CHAR_T));
31 static int txt_indent __P((SCR *, TEXT *));
32 static int txt_margin __P((SCR *, TEXT *, int *, ARG_CHAR_T));
33 static int txt_outdent __P((SCR *, TEXT *));
34 static void txt_showmatch __P((SCR *, EXF *));
35 static int txt_resolve __P((SCR *, EXF *, TEXTH *));
37 /* Cursor character (space is hard to track on the screen). */
38 #if defined(DEBUG) && 0
39 #undef CURSOR_CH
40 #define CURSOR_CH '+'
41 #endif
43 /* Local version of BINC. */
44 #define TBINC(sp, lp, llen, nlen) { \
45 if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
46 goto err; \
50 * newtext --
51 * Read in text from the user.
53 * !!!
54 * Historic vi always used:
56 * ^D: autoindent deletion
57 * ^H: last character deletion
58 * ^W: last word deletion
59 * ^V: quote the next character
61 * regardless of the user's choices for these characters. The user's erase
62 * and kill characters worked in addition to these characters. Ex was not
63 * completely consistent with this, as it did map the scroll command to the
64 * user's EOF character.
66 * This implementation does not use fixed characters, but uses whatever the
67 * user specified as described by the termios structure. I'm getting away
68 * with something here, but I think I'm unlikely to get caught.
70 * !!!
71 * Historic vi did a special screen optimization for tab characters. For
72 * the keystrokes "iabcd<esc>0C<tab>", the tab would overwrite the rest of
73 * the string when it was displayed. Because this implementation redisplays
74 * the entire line on each keystroke, the "bcd" gets pushed to the right as
75 * we ignore that the user has "promised" to change the rest of the characters.
76 * Users have noticed, but this isn't worth fixing, and, the way that the
77 * historic vi did it results in an even worse bug. Given the keystrokes
78 * "iabcd<esc>0R<tab><esc>", the "bcd" disappears, and magically reappears
79 * on the second <esc> key.
81 int
82 v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
83 SCR *sp;
84 EXF *ep;
85 TEXTH *tiqh;
86 MARK *tm; /* To MARK. */
87 const char *lp; /* Input line. */
88 const size_t len; /* Input line length. */
89 MARK *rp; /* Return MARK. */
90 int prompt; /* Prompt to display. */
91 recno_t ai_line; /* Line number to use for autoindent count. */
92 u_int flags; /* TXT_ flags. */
94 /* State of abbreviation checks. */
95 enum { A_NOTSET, A_SPACE, A_NOTSPACE } abb;
96 /* State of the "[^0]^D" sequences. */
97 enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
98 /* State of the hex input character. */
99 enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;
100 /* State of quotation. */
101 enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
102 CH ikey; /* Input character structure. */
103 CHAR_T ch; /* Input character. */
104 GS *gp; /* Global pointer. */
105 TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
106 size_t rcol; /* 0-N: insert offset in the replay buffer. */
107 size_t col; /* Current column. */
108 u_long margin; /* Wrapmargin value. */
109 u_int iflags; /* Input flags. */
110 int ab_cnt, ab_turnoff; /* Abbreviation count, if turned off. */
111 int eval; /* Routine return value. */
112 int replay; /* If replaying a set of input. */
113 int showmatch; /* Showmatch set on this character. */
114 int testnr; /* Test first character for nul replay. */
115 int max, tmp;
116 char *p;
119 * Set the input flag, so tabs get displayed correctly
120 * and everyone knows that the text buffer is in use.
122 F_SET(sp, S_INPUT);
124 /* Local initialization. */
125 eval = 0;
126 gp = sp->gp;
129 * Get one TEXT structure with some initial buffer space, reusing
130 * the last one if it's big enough. (All TEXT bookkeeping fields
131 * default to 0 -- text_init() handles this.) If changing a line,
132 * copy it into the TEXT buffer.
134 if (tiqh->cqh_first != (void *)tiqh) {
135 tp = tiqh->cqh_first;
136 if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
137 text_lfree(tiqh);
138 goto newtp;
140 tp->ai = tp->insert = tp->offset = tp->owrite = 0;
141 if (lp != NULL) {
142 tp->len = len;
143 memmove(tp->lb, lp, len);
144 } else
145 tp->len = 0;
146 } else {
147 newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
148 return (1);
149 CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
152 /* Set the starting line number. */
153 tp->lno = sp->lno;
156 * Set the insert and overwrite counts. If overwriting characters,
157 * do insertion afterward. If not overwriting characters, assume
158 * doing insertion. If change is to a mark, emphasize it with an
159 * END_CH.
161 if (len) {
162 if (LF_ISSET(TXT_OVERWRITE)) {
163 tp->owrite = tm->cno - sp->cno;
164 tp->insert = len - tm->cno;
165 } else
166 tp->insert = len - sp->cno;
168 if (LF_ISSET(TXT_EMARK))
169 tp->lb[tm->cno - 1] = END_CH;
173 * Many of the special cases in this routine are to handle autoindent
174 * support. Somebody decided that it would be a good idea if "^^D"
175 * and "0^D" deleted all of the autoindented characters. In an editor
176 * that takes single character input from the user, this wasn't a very
177 * good idea. Note also that "^^D" resets the next lines' autoindent,
178 * but "0^D" doesn't.
180 * We assume that autoindent only happens on empty lines, so insert
181 * and overwrite will be zero. If doing autoindent, figure out how
182 * much indentation we need and fill it in. Update input column and
183 * screen cursor as necessary.
185 if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
186 if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
187 return (1);
188 sp->cno = tp->ai;
189 } else {
191 * The cc and S commands have a special feature -- leading
192 * <blank> characters are handled as autoindent characters.
193 * Beauty!
195 if (LF_ISSET(TXT_AICHARS)) {
196 tp->offset = 0;
197 tp->ai = sp->cno;
198 } else
199 tp->offset = sp->cno;
202 /* If getting a command buffer from the user, there may be a prompt. */
203 if (LF_ISSET(TXT_PROMPT)) {
204 tp->lb[sp->cno++] = prompt;
205 ++tp->len;
206 ++tp->offset;
210 * If appending after the end-of-line, add a space into the buffer
211 * and move the cursor right. This space is inserted, i.e. pushed
212 * along, and then deleted when the line is resolved. Assumes that
213 * the cursor is already positioned at the end of the line. This
214 * avoids the nastiness of having the cursor reside on a magical
215 * column, i.e. a column that doesn't really exist. The only down
216 * side is that we may wrap lines or scroll the screen before it's
217 * strictly necessary. Not a big deal.
219 if (LF_ISSET(TXT_APPENDEOL)) {
220 tp->lb[sp->cno] = CURSOR_CH;
221 ++tp->len;
222 ++tp->insert;
226 * Historic practice is that the wrapmargin value was a distance
227 * from the RIGHT-HAND column, not the left. It's more useful to
228 * us as a distance from the left-hand column.
230 * !!!
231 * Replay commands are not affected by wrapmargin values. What
232 * I found surprising was that people actually depend on it, as
233 * in this gem of a macro which centers lines:
235 * map #c $mq81a ^V^[81^V|D`qld0:s/ / /g^V^M$p
237 * XXX
238 * Setting margin causes a significant performance hit. Normally
239 * we don't update the screen if there are keys waiting, but we
240 * have to if margin is set, otherwise the screen routines don't
241 * know where the cursor is.
243 if (LF_ISSET(TXT_REPLAY) || !LF_ISSET(TXT_WRAPMARGIN))
244 margin = 0;
245 else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
246 margin = sp->cols - margin;
248 /* Initialize abbreviations checks. */
249 if (F_ISSET(gp, G_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
250 abb = A_NOTSPACE;
251 ab_cnt = ab_turnoff = 0;
252 } else
253 abb = A_NOTSET;
256 * Set up the dot command. Dot commands are done by saving the
257 * actual characters and replaying the input. We have to push
258 * the characters onto the key stack and then handle them normally,
259 * otherwise things like wrapmargin will fail.
261 * XXX
262 * It would be nice if we could swallow backspaces and such, but
263 * it's not all that easy to do. Another possibility would be to
264 * recognize full line insertions, which could be performed quickly,
265 * without replay.
267 nullreplay:
268 rcol = 0;
269 if (replay = LF_ISSET(TXT_REPLAY)) {
271 * !!!
272 * Historically, it wasn't an error to replay non-existent
273 * input. This test is necessary, we get here by the user
274 * doing an input command followed by a nul.
276 * !!!
277 * Historically, vi did not remap or reabbreviate replayed
278 * input. It did, however, beep at you if you changed an
279 * abbreviation and then replayed the input. We're not that
280 * compatible.
282 if (VIP(sp)->rep == NULL)
283 return (0);
284 if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, 0, CH_NOMAP))
285 return (1);
286 testnr = 0;
287 abb = A_NOTSET;
288 LF_CLR(TXT_RECORD);
289 } else
290 testnr = 1;
292 iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
293 for (gp, showmatch = 0,
294 carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {
296 * Reset the line and update the screen. (The txt_showmatch()
297 * code refreshes the screen for us.) Don't refresh unless
298 * we're about to wait on a character or we need to know where
299 * the cursor really is.
301 if (showmatch || margin || !KEYS_WAITING(sp)) {
302 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
303 goto err;
304 if (showmatch) {
305 showmatch = 0;
306 txt_showmatch(sp, ep);
307 } else if (sp->s_refresh(sp, ep))
308 goto err;
311 /* Get the next character. */
312 next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
313 goto err;
314 ch = ikey.ch;
316 /* Abbreviation check. See comment in txt_abbrev(). */
317 #define MAX_ABBREVIATION_EXPANSION 256
318 if (ikey.flags & CH_ABBREVIATED) {
319 if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) {
320 term_ab_flush(sp,
321 "Abbreviation exceeded maximum number of characters");
322 ab_cnt = 0;
323 continue;
325 } else
326 ab_cnt = 0;
329 * !!!
330 * Historic feature. If the first character of the input is
331 * a nul, replay the previous input. This isn't documented
332 * anywhere, and is a great test of vi clones.
334 if (ch == '\0' && testnr) {
335 LF_SET(TXT_REPLAY);
336 goto nullreplay;
338 testnr = 0;
341 * Check to see if the character fits into the input (and
342 * replay, if necessary) buffers. It isn't necessary to
343 * have tp->len bytes, since it doesn't consider overwrite
344 * characters, but not worth fixing.
346 if (LF_ISSET(TXT_RECORD)) {
347 TBINC(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
348 VIP(sp)->rep[rcol++] = ch;
350 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
353 * If the character was quoted, replace the last character
354 * (the literal mark) with the new character. If quoted
355 * by someone else, simply insert the character.
357 * !!!
358 * Extension -- if the quoted character is HEX_CH, enter hex
359 * mode. If the user enters "<HEX_CH>[isxdigit()]*" we will
360 * try to use the value as a character. Anything else resets
361 * hex mode.
363 if (ikey.flags & CH_QUOTED)
364 goto ins_ch;
365 if (quoted == Q_THISCHAR) {
366 --sp->cno;
367 ++tp->owrite;
368 quoted = Q_NOTSET;
370 if (ch == HEX_CH)
371 hex = H_NEXTCHAR;
372 goto ins_ch;
375 switch (ikey.value) {
376 case K_CR:
377 case K_NL: /* New line. */
378 #define LINE_RESOLVE { \
379 /* \
380 * Handle abbreviations. If there was one, \
381 * discard the replay characters. \
382 */ \
383 if (abb == A_NOTSPACE && !replay) { \
384 if (txt_abbrev(sp, tp, ch, \
385 LF_ISSET(TXT_INFOLINE), &tmp, \
386 &ab_turnoff)) \
387 goto err; \
388 if (tmp) { \
389 if (LF_ISSET(TXT_RECORD)) \
390 rcol -= tmp; \
391 goto next_ch; \
394 if (abb != A_NOTSET) \
395 abb = A_SPACE; \
396 /* Handle hex numbers. */ \
397 if (hex == H_INHEX) { \
398 if (txt_hex(sp, tp, &tmp, ch)) \
399 goto err; \
400 if (tmp) { \
401 hex = H_NOTSET; \
402 goto next_ch; \
405 /* \
406 * The 'R' command returns any overwriteable \
407 * characters in the first line to the original \
408 * characters.
409 */ \
410 if (LF_ISSET(TXT_REPLACE) && tp->owrite && \
411 tp == tiqh->cqh_first) { \
412 memmove(tp->lb + sp->cno, \
413 lp + sp->cno, tp->owrite); \
414 tp->insert += tp->owrite; \
415 tp->owrite = 0; \
417 /* Delete any appended cursor. */ \
418 if (LF_ISSET(TXT_APPENDEOL)) { \
419 --tp->len; \
420 --tp->insert; \
423 LINE_RESOLVE;
425 /* CR returns from the vi command line. */
426 if (LF_ISSET(TXT_CR)) {
428 * If a script window and not the colon
429 * line, push a <cr> so it gets executed.
431 if (F_ISSET(sp, S_SCRIPT) &&
432 !LF_ISSET(TXT_INFOLINE))
433 (void)term_push(sp,
434 "\r", 1, 0, CH_NOMAP);
435 goto k_escape;
439 * Historic practice was to delete any <blank>
440 * characters following the inserted newline.
441 * This affects the 'R', 'c', and 's' commands.
443 for (p = tp->lb + sp->cno + tp->owrite;
444 tp->insert && isblank(*p);
445 ++p, ++tp->owrite, --tp->insert);
448 * Move any remaining insert characters into
449 * a new TEXT structure.
451 if ((ntp = text_init(sp,
452 tp->lb + sp->cno + tp->owrite,
453 tp->insert, tp->insert + 32)) == NULL)
454 goto err;
455 CIRCLEQ_INSERT_TAIL(tiqh, ntp, q);
457 /* Set bookkeeping for the new line. */
458 ntp->lno = tp->lno + 1;
459 ntp->insert = tp->insert;
462 * Note if the user inserted any characters on this
463 * line. Done before calling txt_ai_resolve() because
464 * it changes the value of sp->cno without making the
465 * corresponding changes to tp->ai.
467 tmp = sp->cno <= tp->ai;
470 * Resolve autoindented characters for the old line.
471 * Reset the autoindent line value. 0^D keeps the ai
472 * line from changing, ^D changes the level, even if
473 * there are no characters in the old line. Note,
474 * if using the current tp structure, use the cursor
475 * as the length, the user may have erased autoindent
476 * characters.
478 if (LF_ISSET(TXT_AUTOINDENT)) {
479 txt_ai_resolve(sp, tp);
481 if (carat_st == C_NOCHANGE) {
482 if (txt_auto(sp, ep,
483 OOBLNO, &ait, ait.ai, ntp))
484 goto err;
485 FREE_SPACE(sp, ait.lb, ait.lb_len);
486 } else
487 if (txt_auto(sp, ep,
488 OOBLNO, tp, sp->cno, ntp))
489 goto err;
490 carat_st = C_NOTSET;
494 * If the user hasn't entered any characters, delete
495 * any autoindent characters.
497 * !!!
498 * Historic vi didn't get the insert test right, if
499 * there were characters after the cursor, entering
500 * a <cr> left the autoindent characters on the line.
502 if (tmp)
503 sp->cno = 0;
505 /* Reset bookkeeping for the old line. */
506 tp->len = sp->cno;
507 tp->ai = tp->insert = tp->owrite = 0;
509 /* New cursor position. */
510 sp->cno = ntp->ai;
512 /* New lines are TXT_APPENDEOL if nothing to insert. */
513 if (ntp->insert == 0) {
514 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
515 LF_SET(TXT_APPENDEOL);
516 ntp->lb[sp->cno] = CURSOR_CH;
517 ++ntp->insert;
518 ++ntp->len;
521 /* Update the old line. */
522 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
523 goto err;
525 /* Swap old and new TEXT's. */
526 tp = ntp;
528 /* Reset the cursor. */
529 sp->lno = tp->lno;
531 /* Update the new line. */
532 if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
533 goto err;
535 /* Set the renumber bit. */
536 F_SET(sp, S_RENUMBER);
538 /* Refresh if nothing waiting. */
539 if ((margin || !KEYS_WAITING(sp)) &&
540 sp->s_refresh(sp, ep))
541 goto err;
542 goto next_ch;
543 case K_ESCAPE: /* Escape. */
544 if (!LF_ISSET(TXT_ESCAPE))
545 goto ins_ch;
547 LINE_RESOLVE;
550 * If there aren't any trailing characters in the line
551 * and the user hasn't entered any characters, delete
552 * the autoindent characters.
554 if (!tp->insert && sp->cno <= tp->ai) {
555 tp->len = tp->owrite = 0;
556 sp->cno = 0;
557 } else if (LF_ISSET(TXT_AUTOINDENT))
558 txt_ai_resolve(sp, tp);
560 /* If there are insert characters, copy them down. */
561 k_escape: if (tp->insert && tp->owrite)
562 memmove(tp->lb + sp->cno,
563 tp->lb + sp->cno + tp->owrite, tp->insert);
564 tp->len -= tp->owrite;
567 * Delete any lines that were inserted into the text
568 * structure and then erased.
570 while (tp->q.cqe_next != (void *)tiqh) {
571 ntp = tp->q.cqe_next;
572 CIRCLEQ_REMOVE(tiqh, ntp, q);
573 text_free(ntp);
577 * If not resolving the lines into the file, end
578 * it with a nul.
580 * XXX
581 * This is wrong, should pass back a length.
583 if (LF_ISSET(TXT_RESOLVE)) {
584 if (txt_resolve(sp, ep, tiqh))
585 goto err;
587 * Clear input flag -- input buffer no longer
588 * valid.
590 F_CLR(sp, S_INPUT);
591 } else {
592 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
593 tp->lb[tp->len] = '\0';
597 * Set the return cursor position to rest on the last
598 * inserted character.
600 if (rp != NULL) {
601 rp->lno = tp->lno;
602 rp->cno = sp->cno ? sp->cno - 1 : 0;
603 if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
604 goto err;
606 goto ret;
607 case K_CARAT: /* Delete autoindent chars. */
608 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
609 carat_st = C_CARATSET;
610 goto ins_ch;
611 case K_ZERO: /* Delete autoindent chars. */
612 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
613 carat_st = C_ZEROSET;
614 goto ins_ch;
615 case K_VEOF: /* Delete autoindent char. */
617 * If in the first column or no characters to erase,
618 * ignore the ^D (this matches historic practice). If
619 * not doing autoindent or already inserted non-ai
620 * characters, it's a literal. The latter test is done
621 * in the switch, as the CARAT forms are N + 1, not N.
623 if (!LF_ISSET(TXT_AUTOINDENT))
624 goto ins_ch;
625 if (sp->cno == 0 || tp->ai == 0)
626 break;
627 switch (carat_st) {
628 case C_CARATSET: /* ^^D */
629 if (sp->cno > tp->ai + tp->offset + 1)
630 goto ins_ch;
632 /* Save the ai string for later. */
633 ait.lb = NULL;
634 ait.lb_len = 0;
635 TBINC(sp, ait.lb, ait.lb_len, tp->ai);
636 memmove(ait.lb, tp->lb, tp->ai);
637 ait.ai = ait.len = tp->ai;
639 carat_st = C_NOCHANGE;
640 goto leftmargin;
641 case C_ZEROSET: /* 0^D */
642 if (sp->cno > tp->ai + tp->offset + 1)
643 goto ins_ch;
644 carat_st = C_NOTSET;
645 leftmargin: tp->lb[sp->cno - 1] = ' ';
646 tp->owrite += sp->cno - tp->offset;
647 tp->ai = 0;
648 sp->cno = tp->offset;
649 break;
650 case C_NOTSET: /* ^D */
651 if (sp->cno > tp->ai + tp->offset)
652 goto ins_ch;
653 (void)txt_outdent(sp, tp);
654 break;
655 default:
656 abort();
658 break;
659 case K_VERASE: /* Erase the last character. */
661 * If can erase over the prompt, return. Len is 0
662 * if backspaced over the prompt, 1 if only CR entered.
664 if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
665 tp->len = 0;
666 goto ret;
670 * If at the beginning of the line, try and drop back
671 * to a previously inserted line.
673 if (sp->cno == 0) {
674 if ((ntp = txt_backup(sp,
675 ep, tiqh, tp, flags)) == NULL)
676 goto err;
677 tp = ntp;
678 break;
681 /* If nothing to erase, bell the user. */
682 if (sp->cno <= tp->offset) {
683 msgq(sp, M_BERR,
684 "No more characters to erase.");
685 break;
688 /* Drop back one character. */
689 --sp->cno;
692 * Increment overwrite, decrement ai if deleted.
694 * !!!
695 * Historic vi did not permit users to use erase
696 * characters to delete autoindent characters.
698 ++tp->owrite;
699 if (sp->cno < tp->ai)
700 --tp->ai;
701 break;
702 case K_VINTR:
704 * !!!
705 * Historically, <interrupt> exited the user from
706 * editing the infoline, and returned to the main
707 * screen. It also beeped the terminal, but that
708 * seems excessive.
710 if (LF_ISSET(TXT_INFOLINE)) {
711 tp->lb[tp->len = 0] = '\0';
712 goto ret;
714 goto ins_ch;
715 case K_VWERASE: /* Skip back one word. */
717 * If at the beginning of the line, try and drop back
718 * to a previously inserted line.
720 if (sp->cno == 0) {
721 if ((ntp = txt_backup(sp,
722 ep, tiqh, tp, flags)) == NULL)
723 goto err;
724 tp = ntp;
728 * If at offset, nothing to erase so bell the user.
730 if (sp->cno <= tp->offset) {
731 msgq(sp, M_BERR,
732 "No more characters to erase.");
733 break;
737 * First werase goes back to any autoindent
738 * and second werase goes back to the offset.
740 * !!!
741 * Historic vi did not permit users to use erase
742 * characters to delete autoindent characters.
744 if (tp->ai && sp->cno > tp->ai)
745 max = tp->ai;
746 else {
747 tp->ai = 0;
748 max = tp->offset;
751 /* Skip over trailing space characters. */
752 while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
753 --sp->cno;
754 ++tp->owrite;
756 if (sp->cno == max)
757 break;
759 * There are three types of word erase found on UNIX
760 * systems. They can be identified by how the string
761 * /a/b/c is treated -- as 1, 3, or 6 words. Historic
762 * vi had two classes of characters, and strings were
763 * delimited by them and <blank>'s, so, 6 words. The
764 * historic tty interface used <blank>'s to delimit
765 * strings, so, 1 word. The algorithm offered in the
766 * 4.4BSD tty interface (as stty altwerase) treats it
767 * as 3 words -- there are two classes of characters,
768 * and strings are delimited by them and <blank>'s.
769 * The difference is that the type of the first erased
770 * character erased is ignored, which is exactly right
771 * when erasing pathname components. Here, the options
772 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
773 * tty interface and the historic tty driver behavior,
774 * respectively, and the default is the same as the
775 * historic vi behavior.
777 if (LF_ISSET(TXT_TTYWERASE))
778 while (sp->cno > max) {
779 --sp->cno;
780 ++tp->owrite;
781 if (isblank(tp->lb[sp->cno - 1]))
782 break;
784 else {
785 if (LF_ISSET(TXT_ALTWERASE)) {
786 --sp->cno;
787 ++tp->owrite;
788 if (isblank(tp->lb[sp->cno - 1]))
789 break;
791 if (sp->cno > max)
792 tmp = inword(tp->lb[sp->cno - 1]);
793 while (sp->cno > max) {
794 --sp->cno;
795 ++tp->owrite;
796 if (tmp != inword(tp->lb[sp->cno - 1])
797 || isblank(tp->lb[sp->cno - 1]))
798 break;
801 break;
802 case K_VKILL: /* Restart this line. */
804 * If at the beginning of the line, try and drop back
805 * to a previously inserted line.
807 if (sp->cno == 0) {
808 if ((ntp = txt_backup(sp,
809 ep, tiqh, tp, flags)) == NULL)
810 goto err;
811 tp = ntp;
814 /* If at offset, nothing to erase so bell the user. */
815 if (sp->cno <= tp->offset) {
816 msgq(sp, M_BERR,
817 "No more characters to erase.");
818 break;
822 * First kill goes back to any autoindent
823 * and second kill goes back to the offset.
825 * !!!
826 * Historic vi did not permit users to use erase
827 * characters to delete autoindent characters.
829 if (tp->ai && sp->cno > tp->ai)
830 max = tp->ai;
831 else {
832 tp->ai = 0;
833 max = tp->offset;
835 tp->owrite += sp->cno - max;
836 sp->cno = max;
837 break;
838 case K_CNTRLT: /* Add autoindent char. */
839 if (!LF_ISSET(TXT_CNTRLT))
840 goto ins_ch;
841 if (txt_indent(sp, tp))
842 goto err;
843 goto ebuf_chk;
844 case K_CNTRLZ:
845 (void)sp->s_suspend(sp);
846 break;
847 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
848 case K_FORMFEED:
849 F_SET(sp, S_REFRESH);
850 break;
851 #endif
852 case K_RIGHTBRACE:
853 case K_RIGHTPAREN:
854 showmatch = LF_ISSET(TXT_SHOWMATCH);
855 goto ins_ch;
856 case K_VLNEXT: /* Quote the next character. */
857 /* If in hex mode, see if we've entered a hex value. */
858 if (hex == H_INHEX) {
859 if (txt_hex(sp, tp, &tmp, ch))
860 goto err;
861 if (tmp) {
862 hex = H_NOTSET;
863 goto next_ch;
866 ch = '^';
867 quoted = Q_NEXTCHAR;
868 /* FALLTHROUGH */
869 default: /* Insert the character. */
870 ins_ch: /*
871 * If entering a space character after a word, check
872 * for abbreviations. If there was one, discard the
873 * replay characters.
875 if (isblank(ch) && abb == A_NOTSPACE && !replay) {
876 if (txt_abbrev(sp, tp, ch,
877 LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff))
878 goto err;
879 if (tmp) {
880 if (LF_ISSET(TXT_RECORD))
881 rcol -= tmp;
882 goto next_ch;
885 /* If in hex mode, see if we've entered a hex value. */
886 if (hex == H_INHEX && !isxdigit(ch)) {
887 if (txt_hex(sp, tp, &tmp, ch))
888 goto err;
889 if (tmp) {
890 hex = H_NOTSET;
891 goto next_ch;
894 /* Check to see if we've crossed the margin. */
895 if (margin) {
896 if (sp->s_column(sp, ep, &col))
897 goto err;
898 if (col >= margin) {
899 if (txt_margin(sp, tp, &tmp, ch))
900 goto err;
901 if (tmp)
902 goto next_ch;
905 if (abb != A_NOTSET)
906 abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
908 if (tp->owrite) /* Overwrite a character. */
909 --tp->owrite;
910 else if (tp->insert) { /* Insert a character. */
911 ++tp->len;
912 if (tp->insert == 1)
913 tp->lb[sp->cno + 1] = tp->lb[sp->cno];
914 else
915 memmove(tp->lb + sp->cno + 1,
916 tp->lb + sp->cno, tp->insert);
919 tp->lb[sp->cno++] = ch;
922 * If we've reached the end of the buffer, then we
923 * need to switch into insert mode. This happens
924 * when there's a change to a mark and the user puts
925 * in more characters than the length of the motion.
927 ebuf_chk: if (sp->cno >= tp->len) {
928 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
929 LF_SET(TXT_APPENDEOL);
930 tp->lb[sp->cno] = CURSOR_CH;
931 ++tp->insert;
932 ++tp->len;
935 if (hex == H_NEXTCHAR)
936 hex = H_INHEX;
937 if (quoted == Q_NEXTCHAR)
938 quoted = Q_THISCHAR;
939 break;
941 #if defined(DEBUG) && 1
942 if (sp->cno + tp->insert + tp->owrite != tp->len)
943 msgq(sp, M_ERR,
944 "len %u != cno: %u ai: %u insert %u overwrite %u",
945 tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
946 tp->len = sp->cno + tp->insert + tp->owrite;
947 #endif
950 /* Clear input flag. */
951 ret: F_CLR(sp, S_INPUT);
953 if (LF_ISSET(TXT_RECORD))
954 VIP(sp)->rep_cnt = rcol;
955 return (eval);
957 /* Error jump. */
958 err: eval = 1;
959 txt_err(sp, ep, tiqh);
960 goto ret;
964 * txt_abbrev --
965 * Handle abbreviations.
967 static int
968 txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
969 SCR *sp;
970 TEXT *tp;
971 ARG_CHAR_T pushc;
972 int isinfoline, *didsubp, *turnoffp;
974 CHAR_T ch;
975 SEQ *qp;
976 size_t len, off;
977 char *p;
979 /* Find the beginning of this "word". */
980 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
981 if (isblank(*p)) {
982 ++p;
983 break;
985 ++len;
986 if (off == tp->ai || off == tp->offset)
987 break;
991 * !!!
992 * Historic vi exploded abbreviations on the command line. This has
993 * obvious problems in that unabbreviating the string can be extremely
994 * tricky, particularly if the string has, say, an embedded escape
995 * character. Personally, I think it's a stunningly bad idea. Other
996 * examples of problems this caused in historic vi are:
997 * :ab foo bar
998 * :ab foo baz
999 * results in "bar" being abbreviated to "baz", which wasn't what the
1000 * user had in mind at all. Also, the commands:
1001 * :ab foo bar
1002 * :unab foo<space>
1003 * resulted in an error message that "bar" wasn't mapped. Finally,
1004 * since the string was already exploded by the time the unabbreviate
1005 * command got it, all it knew was that an abbreviation had occurred.
1006 * Cleverly, it checked the replacement string for its unabbreviation
1007 * match, which meant that the commands:
1008 * :ab foo1 bar
1009 * :ab foo2 bar
1010 * :unab foo2
1011 * unabbreviates "foo1", and the commands:
1012 * :ab foo bar
1013 * :ab bar baz
1014 * unabbreviates "foo"!
1016 * Anyway, people neglected to first ask my opinion before they wrote
1017 * macros that depend on this stuff, so, we make this work as follows.
1018 * When checking for an abbreviation on the command line, if we get a
1019 * string which is <blank> terminated and which starts at the beginning
1020 * of the line, we check to see it is the abbreviate or unabbreviate
1021 * commands. If it is, turn abbreviations off and return as if no
1022 * abbreviation was found. Note also, minor trickiness, so that if the
1023 * user erases the line and starts another command, we go ahead an turn
1024 * abbreviations back on.
1026 * This makes the layering look like a Nachos Supreme.
1028 *didsubp = 0;
1029 if (isinfoline)
1030 if (off == tp->ai || off == tp->offset)
1031 if (ex_is_abbrev(p, len)) {
1032 *turnoffp = 1;
1033 return (0);
1034 } else
1035 *turnoffp = 0;
1036 else
1037 if (*turnoffp)
1038 return (0);
1040 /* Check for any abbreviations. */
1041 if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
1042 return (0);
1045 * Push the abbreviation onto the tty stack. Historically, characters
1046 * resulting from an abbreviation expansion were themselves subject to
1047 * map expansions, O_SHOWMATCH matching etc. This means the expanded
1048 * characters will be re-tested for abbreviations. It's difficult to
1049 * know what historic practice in this case was, since abbreviations
1050 * were applied to :colon command lines, so entering abbreviations that
1051 * looped was tricky, although possible. In addition, obvious loops
1052 * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
1053 * silently only implement and/or display the last abbreviation.)
1055 * This implementation doesn't recover well from such abbreviations.
1056 * The main input loop counts abbreviated characters, and, when it
1057 * reaches a limit, discards any abbreviated characters on the queue.
1058 * It's difficult to back up to the original position, as the replay
1059 * queue would have to be adjusted, and the line state when an initial
1060 * abbreviated character was received would have to be saved.
1062 ch = pushc;
1063 if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
1064 return (1);
1065 if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
1066 return (1);
1069 * Move the cursor to the start of the abbreviation,
1070 * adjust the length.
1072 sp->cno -= len;
1073 tp->len -= len;
1075 /* Copy any insert characters back. */
1076 if (tp->insert)
1077 memmove(tp->lb + sp->cno + tp->owrite,
1078 tp->lb + sp->cno + tp->owrite + len, tp->insert);
1081 * We return the length of the abbreviated characters. This is so
1082 * the calling routine can replace the replay characters with the
1083 * abbreviation. This means that subsequent '.' commands will produce
1084 * the same text, regardless of intervening :[un]abbreviate commands.
1085 * This is historic practice.
1087 *didsubp = len;
1088 return (0);
1091 /* Offset to next column of stop size. */
1092 #define STOP_OFF(c, stop) (stop - (c) % stop)
1095 * txt_ai_resolve --
1096 * When a line is resolved by <esc> or <cr>, review autoindent
1097 * characters.
1099 static void
1100 txt_ai_resolve(sp, tp)
1101 SCR *sp;
1102 TEXT *tp;
1104 u_long ts;
1105 int del;
1106 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
1107 char *p;
1110 * If the line is empty, has an offset, or no autoindent
1111 * characters, we're done.
1113 if (!tp->len || tp->offset || !tp->ai)
1114 return;
1117 * The autoindent characters plus any leading <blank> characters
1118 * in the line are resolved into the minimum number of characters.
1119 * Historic practice.
1121 ts = O_VAL(sp, O_TABSTOP);
1123 /* Figure out the last <blank> screen column. */
1124 for (p = tp->lb, scno = 0, len = tp->len,
1125 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
1126 if (*p == '\t') {
1127 if (spaces)
1128 tab_after_sp = 1;
1129 scno += STOP_OFF(scno, ts);
1130 } else {
1131 ++spaces;
1132 ++scno;
1136 * If there are no spaces, or no tabs after spaces and less than
1137 * ts spaces, it's already minimal.
1139 if (!spaces || !tab_after_sp && spaces < ts)
1140 return;
1142 /* Count up spaces/tabs needed to get to the target. */
1143 for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1144 cno += STOP_OFF(cno, ts);
1145 spaces = scno - cno;
1148 * Figure out how many characters we're dropping -- if we're not
1149 * dropping any, it's already minimal, we're done.
1151 old = p - tp->lb;
1152 new = spaces + tabs;
1153 if (old == new)
1154 return;
1156 /* Shift the rest of the characters down, adjust the counts. */
1157 del = old - new;
1158 memmove(p - del, p, tp->len - old);
1159 sp->cno -= del;
1160 tp->len -= del;
1162 /* Fill in space/tab characters. */
1163 for (p = tp->lb; tabs--;)
1164 *p++ = '\t';
1165 while (spaces--)
1166 *p++ = ' ';
1170 * txt_auto --
1171 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1172 * retrieve the line.
1175 txt_auto(sp, ep, lno, aitp, len, tp)
1176 SCR *sp;
1177 EXF *ep;
1178 recno_t lno;
1179 size_t len;
1180 TEXT *aitp, *tp;
1182 size_t nlen;
1183 char *p, *t;
1185 if (aitp == NULL) {
1186 if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
1187 return (0);
1188 } else
1189 p = t = aitp->lb;
1190 for (nlen = 0; len; ++p) {
1191 if (!isblank(*p))
1192 break;
1193 /* If last character is a space, it counts. */
1194 if (--len == 0) {
1195 ++p;
1196 break;
1200 /* No indentation. */
1201 if (p == t)
1202 return (0);
1204 /* Set count. */
1205 nlen = p - t;
1207 /* Make sure the buffer's big enough. */
1208 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
1210 /* Copy the indentation into the new buffer. */
1211 memmove(tp->lb + nlen, tp->lb, tp->len);
1212 memmove(tp->lb, t, nlen);
1213 tp->len += nlen;
1215 /* Return the additional length. */
1216 tp->ai = nlen;
1217 return (0);
1221 * txt_backup --
1222 * Back up to the previously edited line.
1224 static TEXT *
1225 txt_backup(sp, ep, tiqh, tp, flags)
1226 SCR *sp;
1227 EXF *ep;
1228 TEXTH *tiqh;
1229 TEXT *tp;
1230 u_int flags;
1232 TEXT *ntp;
1233 recno_t lno;
1234 size_t total;
1236 /* Get a handle on the previous TEXT structure. */
1237 if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {
1238 msgq(sp, M_BERR, "Already at the beginning of the insert");
1239 return (tp);
1242 /* Make sure that we have enough space. */
1243 total = ntp->len + tp->insert;
1244 if (LF_ISSET(TXT_APPENDEOL))
1245 ++total;
1246 if (total > ntp->lb_len &&
1247 binc(sp, &ntp->lb, &ntp->lb_len, total))
1248 return (NULL);
1251 * Append a cursor or copy inserted bytes to the end of the old line.
1252 * Test for appending a cursor first, because the TEXT insert field
1253 * will be 1 if we're appending a cursor. I don't think there's a
1254 * third case, so abort() if there is.
1256 if (LF_ISSET(TXT_APPENDEOL)) {
1257 ntp->lb[ntp->len] = CURSOR_CH;
1258 ntp->insert = 1;
1259 } else if (tp->insert) {
1260 memmove(ntp->lb + ntp->len, tp->lb + tp->owrite, tp->insert);
1261 ntp->insert = tp->insert;
1262 } else
1263 abort();
1265 /* Set bookkeeping information. */
1266 sp->lno = ntp->lno;
1267 sp->cno = ntp->len;
1268 ntp->len += ntp->insert;
1270 /* Release the current TEXT. */
1271 lno = tp->lno;
1272 CIRCLEQ_REMOVE(tiqh, tp, q);
1273 text_free(tp);
1275 /* Update the old line on the screen. */
1276 if (sp->s_change(sp, ep, lno, LINE_DELETE))
1277 return (NULL);
1279 /* Return the old line. */
1280 return (ntp);
1284 * txt_err --
1285 * Handle an error during input processing.
1287 static void
1288 txt_err(sp, ep, tiqh)
1289 SCR *sp;
1290 EXF *ep;
1291 TEXTH *tiqh;
1293 recno_t lno;
1294 size_t len;
1297 * The problem with input processing is that the cursor is at an
1298 * indeterminate position since some input may have been lost due
1299 * to a malloc error. So, try to go back to the place from which
1300 * the cursor started, knowing that it may no longer be available.
1302 * We depend on at least one line number being set in the text
1303 * chain.
1305 for (lno = tiqh->cqh_first->lno;
1306 file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
1308 sp->lno = lno == 0 ? 1 : lno;
1309 sp->cno = 0;
1311 /* Redraw the screen, just in case. */
1312 F_SET(sp, S_REDRAW);
1316 * txt_hex --
1317 * Let the user insert any character value they want.
1319 * !!!
1320 * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
1321 * for the user to specify a character value which their keyboard
1322 * may not be able to enter.
1324 static int
1325 txt_hex(sp, tp, was_hex, pushc)
1326 SCR *sp;
1327 TEXT *tp;
1328 int *was_hex;
1329 ARG_CHAR_T pushc;
1331 CHAR_T ch, savec;
1332 size_t len, off;
1333 u_long value;
1334 char *p, *wp;
1337 * Null-terminate the string. Since nul isn't a legal hex value,
1338 * this should be okay, and lets us use a local routine, which
1339 * presumably understands the character set, to convert the value.
1341 savec = tp->lb[sp->cno];
1342 tp->lb[sp->cno] = 0;
1344 /* Find the previous HEX_CH. */
1345 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1346 if (*p == HEX_CH) {
1347 wp = p + 1;
1348 break;
1350 ++len;
1351 /* If not on this line, there's nothing to do. */
1352 if (off == tp->ai || off == tp->offset)
1353 goto nothex;
1356 /* If no length, then it wasn't a hex value. */
1357 if (len == 0)
1358 goto nothex;
1360 /* Get the value. */
1361 value = strtol(wp, NULL, 16);
1362 if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
1363 nothex: tp->lb[sp->cno] = savec;
1364 *was_hex = 0;
1365 return (0);
1368 ch = pushc;
1369 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1370 return (1);
1371 ch = value;
1372 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1373 return (1);
1375 tp->lb[sp->cno] = savec;
1377 /* Move the cursor to the start of the hex value, adjust the length. */
1378 sp->cno -= len + 1;
1379 tp->len -= len + 1;
1381 /* Copy any insert characters back. */
1382 if (tp->insert)
1383 memmove(tp->lb + sp->cno + tp->owrite,
1384 tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
1386 *was_hex = 1;
1387 return (0);
1391 * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
1392 * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
1393 * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
1394 * the 10th column, and ^D moves it back.
1396 * !!!
1397 * The ^T and ^D characters in historical vi only had special meaning when
1398 * they were the first characters typed after entering text input mode.
1399 * Since normal erase characters couldn't erase autoindent (in this case
1400 * ^T) characters, this meant that inserting text into previously existing
1401 * text was quite strange, ^T only worked if it was the first keystroke,
1402 * and then it could only be erased by using ^D. This implementation treats
1403 * ^T specially anywhere it occurs in the input, and permits the standard
1404 * erase characters to erase characters inserted using it.
1406 * XXX
1407 * Technically, txt_indent, txt_outdent should part of the screen interface,
1408 * as they require knowledge of the size of a space character on the screen.
1409 * (Not the size of tabs, because tabs are logically composed of spaces.)
1410 * They're left in the text code because they're complicated, not to mention
1411 * the gruesome awareness that if spaces aren't a single column on the screen
1412 * for any language, we're into some serious, ah, for lack of a better word,
1413 * "issues".
1417 * txt_indent --
1418 * Handle ^T indents.
1420 static int
1421 txt_indent(sp, tp)
1422 SCR *sp;
1423 TEXT *tp;
1425 u_long sw, ts;
1426 size_t cno, off, scno, spaces, tabs;
1428 ts = O_VAL(sp, O_TABSTOP);
1429 sw = O_VAL(sp, O_SHIFTWIDTH);
1431 /* Get the current screen column. */
1432 for (off = scno = 0; off < sp->cno; ++off)
1433 if (tp->lb[off] == '\t')
1434 scno += STOP_OFF(scno, ts);
1435 else
1436 ++scno;
1438 /* Count up spaces/tabs needed to get to the target. */
1439 for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
1440 cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1441 cno += STOP_OFF(cno, ts);
1442 spaces = scno - cno;
1444 /* Put space/tab characters in place of any overwrite characters. */
1445 for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
1446 tp->lb[sp->cno++] = '\t';
1447 for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
1448 tp->lb[sp->cno++] = ' ';
1450 if (!tabs && !spaces)
1451 return (0);
1453 /* Make sure there's enough room. */
1454 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
1456 /* Move the insert characters out of the way. */
1457 if (tp->insert)
1458 memmove(tp->lb + sp->cno + spaces + tabs,
1459 tp->lb + sp->cno, tp->insert);
1461 /* Add new space/tab characters. */
1462 for (; tabs--; ++tp->len, ++tp->ai)
1463 tp->lb[sp->cno++] = '\t';
1464 for (; spaces--; ++tp->len, ++tp->ai)
1465 tp->lb[sp->cno++] = ' ';
1466 return (0);
1470 * txt_outdent --
1471 * Handle ^D outdents.
1474 static int
1475 txt_outdent(sp, tp)
1476 SCR *sp;
1477 TEXT *tp;
1479 u_long sw, ts;
1480 size_t cno, off, scno, spaces;
1482 ts = O_VAL(sp, O_TABSTOP);
1483 sw = O_VAL(sp, O_SHIFTWIDTH);
1485 /* Get the current screen column. */
1486 for (off = scno = 0; off < sp->cno; ++off)
1487 if (tp->lb[off] == '\t')
1488 scno += STOP_OFF(scno, ts);
1489 else
1490 ++scno;
1492 /* Get the previous shiftwidth column. */
1493 for (cno = scno; --scno % sw != 0;);
1495 /* Decrement characters until less than or equal to that slot. */
1496 for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
1497 if (tp->lb[--off] == '\t')
1498 cno -= STOP_OFF(cno, ts);
1499 else
1500 --cno;
1502 /* Spaces needed to get to the target. */
1503 spaces = scno - cno;
1505 /* Maybe just a delete. */
1506 if (spaces == 0)
1507 return (0);
1509 /* Make sure there's enough room. */
1510 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
1512 /* Use up any overwrite characters. */
1513 for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
1514 tp->lb[sp->cno++] = ' ';
1516 /* Maybe that was enough. */
1517 if (spaces == 0)
1518 return (0);
1520 /* Move the insert characters out of the way. */
1521 if (tp->insert)
1522 memmove(tp->lb + sp->cno + spaces,
1523 tp->lb + sp->cno, tp->insert);
1525 /* Add new space characters. */
1526 for (; spaces--; ++tp->len, ++tp->ai)
1527 tp->lb[sp->cno++] = ' ';
1528 return (0);
1532 * txt_resolve --
1533 * Resolve the input text chain into the file.
1535 static int
1536 txt_resolve(sp, ep, tiqh)
1537 SCR *sp;
1538 EXF *ep;
1539 TEXTH *tiqh;
1541 TEXT *tp;
1542 recno_t lno;
1544 /* The first line replaces a current line. */
1545 tp = tiqh->cqh_first;
1546 if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
1547 return (1);
1549 /* All subsequent lines are appended into the file. */
1550 for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
1551 if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
1552 return (1);
1553 return (0);
1557 * txt_showmatch --
1558 * Show a character match.
1560 * !!!
1561 * Historic vi tried to display matches even in the :colon command line.
1562 * I think not.
1564 static void
1565 txt_showmatch(sp, ep)
1566 SCR *sp;
1567 EXF *ep;
1569 struct timeval second;
1570 VCS cs;
1571 MARK m;
1572 fd_set zero;
1573 int cnt, endc, startc;
1576 * Do a refresh first, in case the v_ntext() code hasn't done
1577 * one in awhile, so the user can see what we're complaining
1578 * about.
1580 if (sp->s_refresh(sp, ep))
1581 return;
1583 * We don't display the match if it's not on the screen. Find
1584 * out what the first character on the screen is.
1586 if (sp->s_position(sp, ep, &m, 0, P_TOP))
1587 return;
1589 /* Initialize the getc() interface. */
1590 cs.cs_lno = sp->lno;
1591 cs.cs_cno = sp->cno - 1;
1592 if (cs_init(sp, ep, &cs))
1593 return;
1594 startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
1596 /* Search for the match. */
1597 for (cnt = 1;;) {
1598 if (cs_prev(sp, ep, &cs))
1599 return;
1600 if (cs.cs_lno < m.lno ||
1601 cs.cs_lno == m.lno && cs.cs_cno < m.cno)
1602 return;
1603 if (cs.cs_flags != 0) {
1604 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
1605 (void)sp->s_bell(sp);
1606 return;
1608 continue;
1610 if (cs.cs_ch == endc)
1611 ++cnt;
1612 else if (cs.cs_ch == startc && --cnt == 0)
1613 break;
1616 /* Move to the match. */
1617 m.lno = sp->lno;
1618 m.cno = sp->cno;
1619 sp->lno = cs.cs_lno;
1620 sp->cno = cs.cs_cno;
1621 (void)sp->s_refresh(sp, ep);
1624 * Sleep(3) is eight system calls. Do it fast -- besides,
1625 * I don't want to wait an entire second.
1627 FD_ZERO(&zero);
1628 second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
1629 second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
1630 (void)select(0, &zero, &zero, &zero, &second);
1632 /* Return to the current location. */
1633 sp->lno = m.lno;
1634 sp->cno = m.cno;
1635 (void)sp->s_refresh(sp, ep);
1639 * txt_margin --
1640 * Handle margin wrap.
1642 * !!!
1643 * Historic vi belled the user each time a character was entered after
1644 * crossing the margin until a space was entered which could be used to
1645 * break the line. I don't, it tends to wake the cats.
1647 static int
1648 txt_margin(sp, tp, didbreak, pushc)
1649 SCR *sp;
1650 TEXT *tp;
1651 int *didbreak;
1652 ARG_CHAR_T pushc;
1654 CHAR_T ch;
1655 size_t len, off, tlen;
1656 char *p, *wp;
1658 /* Find the closest previous blank. */
1659 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1660 if (isblank(*p)) {
1661 wp = p + 1;
1662 break;
1664 ++len;
1665 /* If it's the beginning of the line, there's nothing to do. */
1666 if (off == tp->ai || off == tp->offset) {
1667 *didbreak = 0;
1668 return (0);
1673 * Historic practice is to delete any trailing whitespace
1674 * from the previous line.
1676 for (tlen = len;; --p, --off) {
1677 if (!isblank(*p))
1678 break;
1679 ++tlen;
1680 if (off == tp->ai || off == tp->offset)
1681 break;
1684 ch = pushc;
1685 if (term_push(sp, &ch, 1, 0, CH_NOMAP))
1686 return (1);
1687 if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
1688 return (1);
1689 ch = '\n';
1690 if (term_push(sp, &ch, 1, 0, CH_NOMAP))
1691 return (1);
1693 sp->cno -= tlen;
1694 tp->owrite += tlen;
1695 *didbreak = 1;
1696 return (0);