rework initial error handling -- since we check for any screens on
[nvi.git] / vi / v_txt.c
blob6bc04be5224db360d8aea17f439ff9b7450a83aa
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.80 1994/01/13 10:24:27 bostic Exp $ (Berkeley) $Date: 1994/01/13 10:24:27 $";
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;
456 /* Set bookkeeping for the new line. */
457 ntp->lno = tp->lno + 1;
458 ntp->insert = tp->insert;
461 * Note if the user inserted any characters on this
462 * line. Done before calling txt_ai_resolve() because
463 * it changes the value of sp->cno without making the
464 * corresponding changes to tp->ai.
466 tmp = sp->cno <= tp->ai;
469 * Resolve autoindented characters for the old line.
470 * Reset the autoindent line value. 0^D keeps the ai
471 * line from changing, ^D changes the level, even if
472 * there are no characters in the old line. Note,
473 * if using the current tp structure, use the cursor
474 * as the length, the user may have erased autoindent
475 * characters.
477 if (LF_ISSET(TXT_AUTOINDENT)) {
478 txt_ai_resolve(sp, tp);
480 if (carat_st == C_NOCHANGE) {
481 if (txt_auto(sp, ep,
482 OOBLNO, &ait, ait.ai, ntp))
483 goto err;
484 FREE_SPACE(sp, ait.lb, ait.lb_len);
485 } else
486 if (txt_auto(sp, ep,
487 OOBLNO, tp, sp->cno, ntp))
488 goto err;
489 carat_st = C_NOTSET;
493 * If the user hasn't entered any characters, delete
494 * any autoindent characters.
496 * !!!
497 * Historic vi didn't get the insert test right, if
498 * there were characters after the cursor, entering
499 * a <cr> left the autoindent characters on the line.
501 if (tmp)
502 sp->cno = 0;
504 /* Reset bookkeeping for the old line. */
505 tp->len = sp->cno;
506 tp->ai = tp->insert = tp->owrite = 0;
508 /* New cursor position. */
509 sp->cno = ntp->ai;
511 /* New lines are TXT_APPENDEOL if nothing to insert. */
512 if (ntp->insert == 0) {
513 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
514 LF_SET(TXT_APPENDEOL);
515 ntp->lb[sp->cno] = CURSOR_CH;
516 ++ntp->insert;
517 ++ntp->len;
520 /* Update the old line. */
521 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
522 goto err;
525 * Swap old and new TEXT's, and insert the new TEXT
526 * into the queue. (DON'T insert until the old line
527 * has been updated, or the inserted line count in
528 * line.c:file_gline() will be wrong.)
530 tp = ntp;
531 CIRCLEQ_INSERT_TAIL(tiqh, tp, q);
533 /* Reset the cursor. */
534 sp->lno = tp->lno;
536 /* Update the new line. */
537 if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
538 goto err;
540 /* Set the renumber bit. */
541 F_SET(sp, S_RENUMBER);
543 /* Refresh if nothing waiting. */
544 if ((margin || !KEYS_WAITING(sp)) &&
545 sp->s_refresh(sp, ep))
546 goto err;
547 goto next_ch;
548 case K_ESCAPE: /* Escape. */
549 if (!LF_ISSET(TXT_ESCAPE))
550 goto ins_ch;
552 LINE_RESOLVE;
555 * If there aren't any trailing characters in the line
556 * and the user hasn't entered any characters, delete
557 * the autoindent characters.
559 if (!tp->insert && sp->cno <= tp->ai) {
560 tp->len = tp->owrite = 0;
561 sp->cno = 0;
562 } else if (LF_ISSET(TXT_AUTOINDENT))
563 txt_ai_resolve(sp, tp);
565 /* If there are insert characters, copy them down. */
566 k_escape: if (tp->insert && tp->owrite)
567 memmove(tp->lb + sp->cno,
568 tp->lb + sp->cno + tp->owrite, tp->insert);
569 tp->len -= tp->owrite;
572 * Delete any lines that were inserted into the text
573 * structure and then erased.
575 while (tp->q.cqe_next != (void *)tiqh) {
576 ntp = tp->q.cqe_next;
577 CIRCLEQ_REMOVE(tiqh, ntp, q);
578 text_free(ntp);
582 * If not resolving the lines into the file, end
583 * it with a nul.
585 * XXX
586 * This is wrong, should pass back a length.
588 if (LF_ISSET(TXT_RESOLVE)) {
589 if (txt_resolve(sp, ep, tiqh))
590 goto err;
592 * Clear input flag -- input buffer no longer
593 * valid.
595 F_CLR(sp, S_INPUT);
596 } else {
597 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
598 tp->lb[tp->len] = '\0';
602 * Set the return cursor position to rest on the last
603 * inserted character.
605 if (rp != NULL) {
606 rp->lno = tp->lno;
607 rp->cno = sp->cno ? sp->cno - 1 : 0;
608 if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
609 goto err;
611 goto ret;
612 case K_CARAT: /* Delete autoindent chars. */
613 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
614 carat_st = C_CARATSET;
615 goto ins_ch;
616 case K_ZERO: /* Delete autoindent chars. */
617 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
618 carat_st = C_ZEROSET;
619 goto ins_ch;
620 case K_VEOF: /* Delete autoindent char. */
622 * If in the first column or no characters to erase,
623 * ignore the ^D (this matches historic practice). If
624 * not doing autoindent or already inserted non-ai
625 * characters, it's a literal. The latter test is done
626 * in the switch, as the CARAT forms are N + 1, not N.
628 if (!LF_ISSET(TXT_AUTOINDENT))
629 goto ins_ch;
630 if (sp->cno == 0 || tp->ai == 0)
631 break;
632 switch (carat_st) {
633 case C_CARATSET: /* ^^D */
634 if (sp->cno > tp->ai + tp->offset + 1)
635 goto ins_ch;
637 /* Save the ai string for later. */
638 ait.lb = NULL;
639 ait.lb_len = 0;
640 TBINC(sp, ait.lb, ait.lb_len, tp->ai);
641 memmove(ait.lb, tp->lb, tp->ai);
642 ait.ai = ait.len = tp->ai;
644 carat_st = C_NOCHANGE;
645 goto leftmargin;
646 case C_ZEROSET: /* 0^D */
647 if (sp->cno > tp->ai + tp->offset + 1)
648 goto ins_ch;
649 carat_st = C_NOTSET;
650 leftmargin: tp->lb[sp->cno - 1] = ' ';
651 tp->owrite += sp->cno - tp->offset;
652 tp->ai = 0;
653 sp->cno = tp->offset;
654 break;
655 case C_NOTSET: /* ^D */
656 if (sp->cno > tp->ai + tp->offset)
657 goto ins_ch;
658 (void)txt_outdent(sp, tp);
659 break;
660 default:
661 abort();
663 break;
664 case K_VERASE: /* Erase the last character. */
666 * If can erase over the prompt, return. Len is 0
667 * if backspaced over the prompt, 1 if only CR entered.
669 if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
670 tp->len = 0;
671 goto ret;
675 * If at the beginning of the line, try and drop back
676 * to a previously inserted line.
678 if (sp->cno == 0) {
679 if ((ntp = txt_backup(sp,
680 ep, tiqh, tp, flags)) == NULL)
681 goto err;
682 tp = ntp;
683 break;
686 /* If nothing to erase, bell the user. */
687 if (sp->cno <= tp->offset) {
688 msgq(sp, M_BERR,
689 "No more characters to erase.");
690 break;
693 /* Drop back one character. */
694 --sp->cno;
697 * Increment overwrite, decrement ai if deleted.
699 * !!!
700 * Historic vi did not permit users to use erase
701 * characters to delete autoindent characters.
703 ++tp->owrite;
704 if (sp->cno < tp->ai)
705 --tp->ai;
706 break;
707 case K_VINTR:
709 * !!!
710 * Historically, <interrupt> exited the user from
711 * editing the infoline, and returned to the main
712 * screen. It also beeped the terminal, but that
713 * seems excessive.
715 if (LF_ISSET(TXT_INFOLINE)) {
716 tp->lb[tp->len = 0] = '\0';
717 goto ret;
719 goto ins_ch;
720 case K_VWERASE: /* Skip back one word. */
722 * If at the beginning of the line, try and drop back
723 * to a previously inserted line.
725 if (sp->cno == 0) {
726 if ((ntp = txt_backup(sp,
727 ep, tiqh, tp, flags)) == NULL)
728 goto err;
729 tp = ntp;
733 * If at offset, nothing to erase so bell the user.
735 if (sp->cno <= tp->offset) {
736 msgq(sp, M_BERR,
737 "No more characters to erase.");
738 break;
742 * First werase goes back to any autoindent
743 * and second werase goes back to the offset.
745 * !!!
746 * Historic vi did not permit users to use erase
747 * characters to delete autoindent characters.
749 if (tp->ai && sp->cno > tp->ai)
750 max = tp->ai;
751 else {
752 tp->ai = 0;
753 max = tp->offset;
756 /* Skip over trailing space characters. */
757 while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
758 --sp->cno;
759 ++tp->owrite;
761 if (sp->cno == max)
762 break;
764 * There are three types of word erase found on UNIX
765 * systems. They can be identified by how the string
766 * /a/b/c is treated -- as 1, 3, or 6 words. Historic
767 * vi had two classes of characters, and strings were
768 * delimited by them and <blank>'s, so, 6 words. The
769 * historic tty interface used <blank>'s to delimit
770 * strings, so, 1 word. The algorithm offered in the
771 * 4.4BSD tty interface (as stty altwerase) treats it
772 * as 3 words -- there are two classes of characters,
773 * and strings are delimited by them and <blank>'s.
774 * The difference is that the type of the first erased
775 * character erased is ignored, which is exactly right
776 * when erasing pathname components. Here, the options
777 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
778 * tty interface and the historic tty driver behavior,
779 * respectively, and the default is the same as the
780 * historic vi behavior.
782 if (LF_ISSET(TXT_TTYWERASE))
783 while (sp->cno > max) {
784 --sp->cno;
785 ++tp->owrite;
786 if (isblank(tp->lb[sp->cno - 1]))
787 break;
789 else {
790 if (LF_ISSET(TXT_ALTWERASE)) {
791 --sp->cno;
792 ++tp->owrite;
793 if (isblank(tp->lb[sp->cno - 1]))
794 break;
796 if (sp->cno > max)
797 tmp = inword(tp->lb[sp->cno - 1]);
798 while (sp->cno > max) {
799 --sp->cno;
800 ++tp->owrite;
801 if (tmp != inword(tp->lb[sp->cno - 1])
802 || isblank(tp->lb[sp->cno - 1]))
803 break;
806 break;
807 case K_VKILL: /* Restart this line. */
809 * If at the beginning of the line, try and drop back
810 * to a previously inserted line.
812 if (sp->cno == 0) {
813 if ((ntp = txt_backup(sp,
814 ep, tiqh, tp, flags)) == NULL)
815 goto err;
816 tp = ntp;
819 /* If at offset, nothing to erase so bell the user. */
820 if (sp->cno <= tp->offset) {
821 msgq(sp, M_BERR,
822 "No more characters to erase.");
823 break;
827 * First kill goes back to any autoindent
828 * and second kill goes back to the offset.
830 * !!!
831 * Historic vi did not permit users to use erase
832 * characters to delete autoindent characters.
834 if (tp->ai && sp->cno > tp->ai)
835 max = tp->ai;
836 else {
837 tp->ai = 0;
838 max = tp->offset;
840 tp->owrite += sp->cno - max;
841 sp->cno = max;
842 break;
843 case K_CNTRLT: /* Add autoindent char. */
844 if (!LF_ISSET(TXT_CNTRLT))
845 goto ins_ch;
846 if (txt_indent(sp, tp))
847 goto err;
848 goto ebuf_chk;
849 case K_CNTRLZ:
850 (void)sp->s_suspend(sp);
851 break;
852 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
853 case K_FORMFEED:
854 F_SET(sp, S_REFRESH);
855 break;
856 #endif
857 case K_RIGHTBRACE:
858 case K_RIGHTPAREN:
859 showmatch = LF_ISSET(TXT_SHOWMATCH);
860 goto ins_ch;
861 case K_VLNEXT: /* Quote the next character. */
862 /* If in hex mode, see if we've entered a hex value. */
863 if (hex == H_INHEX) {
864 if (txt_hex(sp, tp, &tmp, ch))
865 goto err;
866 if (tmp) {
867 hex = H_NOTSET;
868 goto next_ch;
871 ch = '^';
872 quoted = Q_NEXTCHAR;
873 /* FALLTHROUGH */
874 default: /* Insert the character. */
875 ins_ch: /*
876 * If entering a space character after a word, check
877 * for abbreviations. If there was one, discard the
878 * replay characters.
880 if (isblank(ch) && abb == A_NOTSPACE && !replay) {
881 if (txt_abbrev(sp, tp, ch,
882 LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff))
883 goto err;
884 if (tmp) {
885 if (LF_ISSET(TXT_RECORD))
886 rcol -= tmp;
887 goto next_ch;
890 /* If in hex mode, see if we've entered a hex value. */
891 if (hex == H_INHEX && !isxdigit(ch)) {
892 if (txt_hex(sp, tp, &tmp, ch))
893 goto err;
894 if (tmp) {
895 hex = H_NOTSET;
896 goto next_ch;
899 /* Check to see if we've crossed the margin. */
900 if (margin) {
901 if (sp->s_column(sp, ep, &col))
902 goto err;
903 if (col >= margin) {
904 if (txt_margin(sp, tp, &tmp, ch))
905 goto err;
906 if (tmp)
907 goto next_ch;
910 if (abb != A_NOTSET)
911 abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
913 if (tp->owrite) /* Overwrite a character. */
914 --tp->owrite;
915 else if (tp->insert) { /* Insert a character. */
916 ++tp->len;
917 if (tp->insert == 1)
918 tp->lb[sp->cno + 1] = tp->lb[sp->cno];
919 else
920 memmove(tp->lb + sp->cno + 1,
921 tp->lb + sp->cno, tp->insert);
924 tp->lb[sp->cno++] = ch;
927 * If we've reached the end of the buffer, then we
928 * need to switch into insert mode. This happens
929 * when there's a change to a mark and the user puts
930 * in more characters than the length of the motion.
932 ebuf_chk: if (sp->cno >= tp->len) {
933 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
934 LF_SET(TXT_APPENDEOL);
935 tp->lb[sp->cno] = CURSOR_CH;
936 ++tp->insert;
937 ++tp->len;
940 if (hex == H_NEXTCHAR)
941 hex = H_INHEX;
942 if (quoted == Q_NEXTCHAR)
943 quoted = Q_THISCHAR;
944 break;
946 #if defined(DEBUG) && 1
947 if (sp->cno + tp->insert + tp->owrite != tp->len)
948 msgq(sp, M_ERR,
949 "len %u != cno: %u ai: %u insert %u overwrite %u",
950 tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
951 tp->len = sp->cno + tp->insert + tp->owrite;
952 #endif
955 /* Clear input flag. */
956 ret: F_CLR(sp, S_INPUT);
958 if (LF_ISSET(TXT_RECORD))
959 VIP(sp)->rep_cnt = rcol;
960 return (eval);
962 /* Error jump. */
963 err: eval = 1;
964 txt_err(sp, ep, tiqh);
965 goto ret;
969 * txt_abbrev --
970 * Handle abbreviations.
972 static int
973 txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
974 SCR *sp;
975 TEXT *tp;
976 ARG_CHAR_T pushc;
977 int isinfoline, *didsubp, *turnoffp;
979 CHAR_T ch;
980 SEQ *qp;
981 size_t len, off;
982 char *p;
984 /* Find the beginning of this "word". */
985 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
986 if (isblank(*p)) {
987 ++p;
988 break;
990 ++len;
991 if (off == tp->ai || off == tp->offset)
992 break;
996 * !!!
997 * Historic vi exploded abbreviations on the command line. This has
998 * obvious problems in that unabbreviating the string can be extremely
999 * tricky, particularly if the string has, say, an embedded escape
1000 * character. Personally, I think it's a stunningly bad idea. Other
1001 * examples of problems this caused in historic vi are:
1002 * :ab foo bar
1003 * :ab foo baz
1004 * results in "bar" being abbreviated to "baz", which wasn't what the
1005 * user had in mind at all. Also, the commands:
1006 * :ab foo bar
1007 * :unab foo<space>
1008 * resulted in an error message that "bar" wasn't mapped. Finally,
1009 * since the string was already exploded by the time the unabbreviate
1010 * command got it, all it knew was that an abbreviation had occurred.
1011 * Cleverly, it checked the replacement string for its unabbreviation
1012 * match, which meant that the commands:
1013 * :ab foo1 bar
1014 * :ab foo2 bar
1015 * :unab foo2
1016 * unabbreviates "foo1", and the commands:
1017 * :ab foo bar
1018 * :ab bar baz
1019 * unabbreviates "foo"!
1021 * Anyway, people neglected to first ask my opinion before they wrote
1022 * macros that depend on this stuff, so, we make this work as follows.
1023 * When checking for an abbreviation on the command line, if we get a
1024 * string which is <blank> terminated and which starts at the beginning
1025 * of the line, we check to see it is the abbreviate or unabbreviate
1026 * commands. If it is, turn abbreviations off and return as if no
1027 * abbreviation was found. Note also, minor trickiness, so that if the
1028 * user erases the line and starts another command, we go ahead an turn
1029 * abbreviations back on.
1031 * This makes the layering look like a Nachos Supreme.
1033 *didsubp = 0;
1034 if (isinfoline)
1035 if (off == tp->ai || off == tp->offset)
1036 if (ex_is_abbrev(p, len)) {
1037 *turnoffp = 1;
1038 return (0);
1039 } else
1040 *turnoffp = 0;
1041 else
1042 if (*turnoffp)
1043 return (0);
1045 /* Check for any abbreviations. */
1046 if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
1047 return (0);
1050 * Push the abbreviation onto the tty stack. Historically, characters
1051 * resulting from an abbreviation expansion were themselves subject to
1052 * map expansions, O_SHOWMATCH matching etc. This means the expanded
1053 * characters will be re-tested for abbreviations. It's difficult to
1054 * know what historic practice in this case was, since abbreviations
1055 * were applied to :colon command lines, so entering abbreviations that
1056 * looped was tricky, although possible. In addition, obvious loops
1057 * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
1058 * silently only implement and/or display the last abbreviation.)
1060 * This implementation doesn't recover well from such abbreviations.
1061 * The main input loop counts abbreviated characters, and, when it
1062 * reaches a limit, discards any abbreviated characters on the queue.
1063 * It's difficult to back up to the original position, as the replay
1064 * queue would have to be adjusted, and the line state when an initial
1065 * abbreviated character was received would have to be saved.
1067 ch = pushc;
1068 if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
1069 return (1);
1070 if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
1071 return (1);
1074 * Move the cursor to the start of the abbreviation,
1075 * adjust the length.
1077 sp->cno -= len;
1078 tp->len -= len;
1080 /* Copy any insert characters back. */
1081 if (tp->insert)
1082 memmove(tp->lb + sp->cno + tp->owrite,
1083 tp->lb + sp->cno + tp->owrite + len, tp->insert);
1086 * We return the length of the abbreviated characters. This is so
1087 * the calling routine can replace the replay characters with the
1088 * abbreviation. This means that subsequent '.' commands will produce
1089 * the same text, regardless of intervening :[un]abbreviate commands.
1090 * This is historic practice.
1092 *didsubp = len;
1093 return (0);
1096 /* Offset to next column of stop size. */
1097 #define STOP_OFF(c, stop) (stop - (c) % stop)
1100 * txt_ai_resolve --
1101 * When a line is resolved by <esc> or <cr>, review autoindent
1102 * characters.
1104 static void
1105 txt_ai_resolve(sp, tp)
1106 SCR *sp;
1107 TEXT *tp;
1109 u_long ts;
1110 int del;
1111 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
1112 char *p;
1115 * If the line is empty, has an offset, or no autoindent
1116 * characters, we're done.
1118 if (!tp->len || tp->offset || !tp->ai)
1119 return;
1122 * The autoindent characters plus any leading <blank> characters
1123 * in the line are resolved into the minimum number of characters.
1124 * Historic practice.
1126 ts = O_VAL(sp, O_TABSTOP);
1128 /* Figure out the last <blank> screen column. */
1129 for (p = tp->lb, scno = 0, len = tp->len,
1130 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
1131 if (*p == '\t') {
1132 if (spaces)
1133 tab_after_sp = 1;
1134 scno += STOP_OFF(scno, ts);
1135 } else {
1136 ++spaces;
1137 ++scno;
1141 * If there are no spaces, or no tabs after spaces and less than
1142 * ts spaces, it's already minimal.
1144 if (!spaces || !tab_after_sp && spaces < ts)
1145 return;
1147 /* Count up spaces/tabs needed to get to the target. */
1148 for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1149 cno += STOP_OFF(cno, ts);
1150 spaces = scno - cno;
1153 * Figure out how many characters we're dropping -- if we're not
1154 * dropping any, it's already minimal, we're done.
1156 old = p - tp->lb;
1157 new = spaces + tabs;
1158 if (old == new)
1159 return;
1161 /* Shift the rest of the characters down, adjust the counts. */
1162 del = old - new;
1163 memmove(p - del, p, tp->len - old);
1164 sp->cno -= del;
1165 tp->len -= del;
1167 /* Fill in space/tab characters. */
1168 for (p = tp->lb; tabs--;)
1169 *p++ = '\t';
1170 while (spaces--)
1171 *p++ = ' ';
1175 * txt_auto --
1176 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1177 * retrieve the line.
1180 txt_auto(sp, ep, lno, aitp, len, tp)
1181 SCR *sp;
1182 EXF *ep;
1183 recno_t lno;
1184 size_t len;
1185 TEXT *aitp, *tp;
1187 size_t nlen;
1188 char *p, *t;
1190 if (aitp == NULL) {
1191 if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
1192 return (0);
1193 } else
1194 p = t = aitp->lb;
1195 for (nlen = 0; len; ++p) {
1196 if (!isblank(*p))
1197 break;
1198 /* If last character is a space, it counts. */
1199 if (--len == 0) {
1200 ++p;
1201 break;
1205 /* No indentation. */
1206 if (p == t)
1207 return (0);
1209 /* Set count. */
1210 nlen = p - t;
1212 /* Make sure the buffer's big enough. */
1213 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
1215 /* Copy the indentation into the new buffer. */
1216 memmove(tp->lb + nlen, tp->lb, tp->len);
1217 memmove(tp->lb, t, nlen);
1218 tp->len += nlen;
1220 /* Return the additional length. */
1221 tp->ai = nlen;
1222 return (0);
1226 * txt_backup --
1227 * Back up to the previously edited line.
1229 static TEXT *
1230 txt_backup(sp, ep, tiqh, tp, flags)
1231 SCR *sp;
1232 EXF *ep;
1233 TEXTH *tiqh;
1234 TEXT *tp;
1235 u_int flags;
1237 TEXT *ntp;
1238 recno_t lno;
1239 size_t total;
1241 /* Get a handle on the previous TEXT structure. */
1242 if ((ntp = tp->q.cqe_prev) == (void *)tiqh) {
1243 msgq(sp, M_BERR, "Already at the beginning of the insert");
1244 return (tp);
1247 /* Make sure that we have enough space. */
1248 total = ntp->len + tp->insert;
1249 if (LF_ISSET(TXT_APPENDEOL))
1250 ++total;
1251 if (total > ntp->lb_len &&
1252 binc(sp, &ntp->lb, &ntp->lb_len, total))
1253 return (NULL);
1256 * Append a cursor or copy inserted bytes to the end of the old line.
1257 * Test for appending a cursor first, because the TEXT insert field
1258 * will be 1 if we're appending a cursor. I don't think there's a
1259 * third case, so abort() if there is.
1261 if (LF_ISSET(TXT_APPENDEOL)) {
1262 ntp->lb[ntp->len] = CURSOR_CH;
1263 ntp->insert = 1;
1264 } else if (tp->insert) {
1265 memmove(ntp->lb + ntp->len, tp->lb + tp->owrite, tp->insert);
1266 ntp->insert = tp->insert;
1267 } else
1268 abort();
1270 /* Set bookkeeping information. */
1271 sp->lno = ntp->lno;
1272 sp->cno = ntp->len;
1273 ntp->len += ntp->insert;
1275 /* Release the current TEXT. */
1276 lno = tp->lno;
1277 CIRCLEQ_REMOVE(tiqh, tp, q);
1278 text_free(tp);
1280 /* Update the old line on the screen. */
1281 if (sp->s_change(sp, ep, lno, LINE_DELETE))
1282 return (NULL);
1284 /* Return the old line. */
1285 return (ntp);
1289 * txt_err --
1290 * Handle an error during input processing.
1292 static void
1293 txt_err(sp, ep, tiqh)
1294 SCR *sp;
1295 EXF *ep;
1296 TEXTH *tiqh;
1298 recno_t lno;
1299 size_t len;
1302 * The problem with input processing is that the cursor is at an
1303 * indeterminate position since some input may have been lost due
1304 * to a malloc error. So, try to go back to the place from which
1305 * the cursor started, knowing that it may no longer be available.
1307 * We depend on at least one line number being set in the text
1308 * chain.
1310 for (lno = tiqh->cqh_first->lno;
1311 file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
1313 sp->lno = lno == 0 ? 1 : lno;
1314 sp->cno = 0;
1316 /* Redraw the screen, just in case. */
1317 F_SET(sp, S_REDRAW);
1321 * txt_hex --
1322 * Let the user insert any character value they want.
1324 * !!!
1325 * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
1326 * for the user to specify a character value which their keyboard
1327 * may not be able to enter.
1329 static int
1330 txt_hex(sp, tp, was_hex, pushc)
1331 SCR *sp;
1332 TEXT *tp;
1333 int *was_hex;
1334 ARG_CHAR_T pushc;
1336 CHAR_T ch, savec;
1337 size_t len, off;
1338 u_long value;
1339 char *p, *wp;
1342 * Null-terminate the string. Since nul isn't a legal hex value,
1343 * this should be okay, and lets us use a local routine, which
1344 * presumably understands the character set, to convert the value.
1346 savec = tp->lb[sp->cno];
1347 tp->lb[sp->cno] = 0;
1349 /* Find the previous HEX_CH. */
1350 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1351 if (*p == HEX_CH) {
1352 wp = p + 1;
1353 break;
1355 ++len;
1356 /* If not on this line, there's nothing to do. */
1357 if (off == tp->ai || off == tp->offset)
1358 goto nothex;
1361 /* If no length, then it wasn't a hex value. */
1362 if (len == 0)
1363 goto nothex;
1365 /* Get the value. */
1366 value = strtol(wp, NULL, 16);
1367 if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
1368 nothex: tp->lb[sp->cno] = savec;
1369 *was_hex = 0;
1370 return (0);
1373 ch = pushc;
1374 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1375 return (1);
1376 ch = value;
1377 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1378 return (1);
1380 tp->lb[sp->cno] = savec;
1382 /* Move the cursor to the start of the hex value, adjust the length. */
1383 sp->cno -= len + 1;
1384 tp->len -= len + 1;
1386 /* Copy any insert characters back. */
1387 if (tp->insert)
1388 memmove(tp->lb + sp->cno + tp->owrite,
1389 tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
1391 *was_hex = 1;
1392 return (0);
1396 * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
1397 * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
1398 * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
1399 * the 10th column, and ^D moves it back.
1401 * !!!
1402 * The ^T and ^D characters in historical vi only had special meaning when
1403 * they were the first characters typed after entering text input mode.
1404 * Since normal erase characters couldn't erase autoindent (in this case
1405 * ^T) characters, this meant that inserting text into previously existing
1406 * text was quite strange, ^T only worked if it was the first keystroke,
1407 * and then it could only be erased by using ^D. This implementation treats
1408 * ^T specially anywhere it occurs in the input, and permits the standard
1409 * erase characters to erase characters inserted using it.
1411 * XXX
1412 * Technically, txt_indent, txt_outdent should part of the screen interface,
1413 * as they require knowledge of the size of a space character on the screen.
1414 * (Not the size of tabs, because tabs are logically composed of spaces.)
1415 * They're left in the text code because they're complicated, not to mention
1416 * the gruesome awareness that if spaces aren't a single column on the screen
1417 * for any language, we're into some serious, ah, for lack of a better word,
1418 * "issues".
1422 * txt_indent --
1423 * Handle ^T indents.
1425 static int
1426 txt_indent(sp, tp)
1427 SCR *sp;
1428 TEXT *tp;
1430 u_long sw, ts;
1431 size_t cno, off, scno, spaces, tabs;
1433 ts = O_VAL(sp, O_TABSTOP);
1434 sw = O_VAL(sp, O_SHIFTWIDTH);
1436 /* Get the current screen column. */
1437 for (off = scno = 0; off < sp->cno; ++off)
1438 if (tp->lb[off] == '\t')
1439 scno += STOP_OFF(scno, ts);
1440 else
1441 ++scno;
1443 /* Count up spaces/tabs needed to get to the target. */
1444 for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
1445 cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1446 cno += STOP_OFF(cno, ts);
1447 spaces = scno - cno;
1449 /* Put space/tab characters in place of any overwrite characters. */
1450 for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
1451 tp->lb[sp->cno++] = '\t';
1452 for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
1453 tp->lb[sp->cno++] = ' ';
1455 if (!tabs && !spaces)
1456 return (0);
1458 /* Make sure there's enough room. */
1459 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
1461 /* Move the insert characters out of the way. */
1462 if (tp->insert)
1463 memmove(tp->lb + sp->cno + spaces + tabs,
1464 tp->lb + sp->cno, tp->insert);
1466 /* Add new space/tab characters. */
1467 for (; tabs--; ++tp->len, ++tp->ai)
1468 tp->lb[sp->cno++] = '\t';
1469 for (; spaces--; ++tp->len, ++tp->ai)
1470 tp->lb[sp->cno++] = ' ';
1471 return (0);
1475 * txt_outdent --
1476 * Handle ^D outdents.
1479 static int
1480 txt_outdent(sp, tp)
1481 SCR *sp;
1482 TEXT *tp;
1484 u_long sw, ts;
1485 size_t cno, off, scno, spaces;
1487 ts = O_VAL(sp, O_TABSTOP);
1488 sw = O_VAL(sp, O_SHIFTWIDTH);
1490 /* Get the current screen column. */
1491 for (off = scno = 0; off < sp->cno; ++off)
1492 if (tp->lb[off] == '\t')
1493 scno += STOP_OFF(scno, ts);
1494 else
1495 ++scno;
1497 /* Get the previous shiftwidth column. */
1498 for (cno = scno; --scno % sw != 0;);
1500 /* Decrement characters until less than or equal to that slot. */
1501 for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
1502 if (tp->lb[--off] == '\t')
1503 cno -= STOP_OFF(cno, ts);
1504 else
1505 --cno;
1507 /* Spaces needed to get to the target. */
1508 spaces = scno - cno;
1510 /* Maybe just a delete. */
1511 if (spaces == 0)
1512 return (0);
1514 /* Make sure there's enough room. */
1515 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
1517 /* Use up any overwrite characters. */
1518 for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
1519 tp->lb[sp->cno++] = ' ';
1521 /* Maybe that was enough. */
1522 if (spaces == 0)
1523 return (0);
1525 /* Move the insert characters out of the way. */
1526 if (tp->insert)
1527 memmove(tp->lb + sp->cno + spaces,
1528 tp->lb + sp->cno, tp->insert);
1530 /* Add new space characters. */
1531 for (; spaces--; ++tp->len, ++tp->ai)
1532 tp->lb[sp->cno++] = ' ';
1533 return (0);
1537 * txt_resolve --
1538 * Resolve the input text chain into the file.
1540 static int
1541 txt_resolve(sp, ep, tiqh)
1542 SCR *sp;
1543 EXF *ep;
1544 TEXTH *tiqh;
1546 TEXT *tp;
1547 recno_t lno;
1549 /* The first line replaces a current line. */
1550 tp = tiqh->cqh_first;
1551 if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
1552 return (1);
1554 /* All subsequent lines are appended into the file. */
1555 for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
1556 if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
1557 return (1);
1558 return (0);
1562 * txt_showmatch --
1563 * Show a character match.
1565 * !!!
1566 * Historic vi tried to display matches even in the :colon command line.
1567 * I think not.
1569 static void
1570 txt_showmatch(sp, ep)
1571 SCR *sp;
1572 EXF *ep;
1574 struct timeval second;
1575 VCS cs;
1576 MARK m;
1577 fd_set zero;
1578 int cnt, endc, startc;
1581 * Do a refresh first, in case the v_ntext() code hasn't done
1582 * one in awhile, so the user can see what we're complaining
1583 * about.
1585 if (sp->s_refresh(sp, ep))
1586 return;
1588 * We don't display the match if it's not on the screen. Find
1589 * out what the first character on the screen is.
1591 if (sp->s_position(sp, ep, &m, 0, P_TOP))
1592 return;
1594 /* Initialize the getc() interface. */
1595 cs.cs_lno = sp->lno;
1596 cs.cs_cno = sp->cno - 1;
1597 if (cs_init(sp, ep, &cs))
1598 return;
1599 startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
1601 /* Search for the match. */
1602 for (cnt = 1;;) {
1603 if (cs_prev(sp, ep, &cs))
1604 return;
1605 if (cs.cs_lno < m.lno ||
1606 cs.cs_lno == m.lno && cs.cs_cno < m.cno)
1607 return;
1608 if (cs.cs_flags != 0) {
1609 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
1610 (void)sp->s_bell(sp);
1611 return;
1613 continue;
1615 if (cs.cs_ch == endc)
1616 ++cnt;
1617 else if (cs.cs_ch == startc && --cnt == 0)
1618 break;
1621 /* Move to the match. */
1622 m.lno = sp->lno;
1623 m.cno = sp->cno;
1624 sp->lno = cs.cs_lno;
1625 sp->cno = cs.cs_cno;
1626 (void)sp->s_refresh(sp, ep);
1629 * Sleep(3) is eight system calls. Do it fast -- besides,
1630 * I don't want to wait an entire second.
1632 FD_ZERO(&zero);
1633 second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
1634 second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
1635 (void)select(0, &zero, &zero, &zero, &second);
1637 /* Return to the current location. */
1638 sp->lno = m.lno;
1639 sp->cno = m.cno;
1640 (void)sp->s_refresh(sp, ep);
1644 * txt_margin --
1645 * Handle margin wrap.
1647 * !!!
1648 * Historic vi belled the user each time a character was entered after
1649 * crossing the margin until a space was entered which could be used to
1650 * break the line. I don't, it tends to wake the cats.
1652 static int
1653 txt_margin(sp, tp, didbreak, pushc)
1654 SCR *sp;
1655 TEXT *tp;
1656 int *didbreak;
1657 ARG_CHAR_T pushc;
1659 CHAR_T ch;
1660 size_t len, off, tlen;
1661 char *p, *wp;
1663 /* Find the closest previous blank. */
1664 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1665 if (isblank(*p)) {
1666 wp = p + 1;
1667 break;
1669 ++len;
1670 /* If it's the beginning of the line, there's nothing to do. */
1671 if (off == tp->ai || off == tp->offset) {
1672 *didbreak = 0;
1673 return (0);
1678 * Historic practice is to delete any trailing whitespace
1679 * from the previous line.
1681 for (tlen = len;; --p, --off) {
1682 if (!isblank(*p))
1683 break;
1684 ++tlen;
1685 if (off == tp->ai || off == tp->offset)
1686 break;
1689 ch = pushc;
1690 if (term_push(sp, &ch, 1, 0, CH_NOMAP))
1691 return (1);
1692 if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
1693 return (1);
1694 ch = '\n';
1695 if (term_push(sp, &ch, 1, 0, CH_NOMAP))
1696 return (1);
1698 sp->cno -= tlen;
1699 tp->owrite += tlen;
1700 *didbreak = 1;
1701 return (0);