it's even worse, document another horrible case
[nvi.git] / vi / v_txt.c
blob3866fe2fe688a84a4ba22f90d25b1b2420484bfd
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.75 1993/12/27 17:09:26 bostic Exp $ (Berkeley) $Date: 1993/12/27 17:09:26 $";
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_VWERASE: /* Skip back one word. */
704 * If at the beginning of the line, try and drop back
705 * to a previously inserted line.
707 if (sp->cno == 0) {
708 if ((ntp = txt_backup(sp,
709 ep, tiqh, tp, flags)) == NULL)
710 goto err;
711 tp = ntp;
715 * If at offset, nothing to erase so bell the user.
717 if (sp->cno <= tp->offset) {
718 msgq(sp, M_BERR,
719 "No more characters to erase.");
720 break;
724 * First werase goes back to any autoindent
725 * and second werase goes back to the offset.
727 * !!!
728 * Historic vi did not permit users to use erase
729 * characters to delete autoindent characters.
731 if (tp->ai && sp->cno > tp->ai)
732 max = tp->ai;
733 else {
734 tp->ai = 0;
735 max = tp->offset;
738 /* Skip over trailing space characters. */
739 while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
740 --sp->cno;
741 ++tp->owrite;
743 if (sp->cno == max)
744 break;
746 * There are three types of word erase found on UNIX
747 * systems. They can be identified by how the string
748 * /a/b/c is treated -- as 1, 3, or 6 words. Historic
749 * vi had two classes of characters, and strings were
750 * delimited by them and <blank>'s, so, 6 words. The
751 * historic tty interface used <blank>'s to delimit
752 * strings, so, 1 word. The algorithm offered in the
753 * 4.4BSD tty interface (as stty altwerase) treats it
754 * as 3 words -- there are two classes of characters,
755 * and strings are delimited by them and <blank>'s.
756 * The difference is that the type of the first erased
757 * character erased is ignored, which is exactly right
758 * when erasing pathname components. Here, the options
759 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
760 * tty interface and the historic tty driver behavior,
761 * respectively, and the default is the same as the
762 * historic vi behavior.
764 if (LF_ISSET(TXT_TTYWERASE))
765 while (sp->cno > max) {
766 --sp->cno;
767 ++tp->owrite;
768 if (isblank(tp->lb[sp->cno - 1]))
769 break;
771 else {
772 if (LF_ISSET(TXT_ALTWERASE)) {
773 --sp->cno;
774 ++tp->owrite;
775 if (isblank(tp->lb[sp->cno - 1]))
776 break;
778 if (sp->cno > max)
779 tmp = inword(tp->lb[sp->cno - 1]);
780 while (sp->cno > max) {
781 --sp->cno;
782 ++tp->owrite;
783 if (tmp != inword(tp->lb[sp->cno - 1])
784 || isblank(tp->lb[sp->cno - 1]))
785 break;
788 break;
789 case K_VKILL: /* Restart this line. */
791 * If at the beginning of the line, try and drop back
792 * to a previously inserted line.
794 if (sp->cno == 0) {
795 if ((ntp = txt_backup(sp,
796 ep, tiqh, tp, flags)) == NULL)
797 goto err;
798 tp = ntp;
801 /* If at offset, nothing to erase so bell the user. */
802 if (sp->cno <= tp->offset) {
803 msgq(sp, M_BERR,
804 "No more characters to erase.");
805 break;
809 * First kill goes back to any autoindent
810 * and second kill goes back to the offset.
812 * !!!
813 * Historic vi did not permit users to use erase
814 * characters to delete autoindent characters.
816 if (tp->ai && sp->cno > tp->ai)
817 max = tp->ai;
818 else {
819 tp->ai = 0;
820 max = tp->offset;
822 tp->owrite += sp->cno - max;
823 sp->cno = max;
824 break;
825 case K_CNTRLT: /* Add autoindent char. */
826 if (!LF_ISSET(TXT_CNTRLT))
827 goto ins_ch;
828 if (txt_indent(sp, tp))
829 goto err;
830 goto ebuf_chk;
831 case K_CNTRLZ:
832 (void)sp->s_suspend(sp);
833 break;
834 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
835 case K_FORMFEED:
836 F_SET(sp, S_REFRESH);
837 break;
838 #endif
839 case K_RIGHTBRACE:
840 case K_RIGHTPAREN:
841 showmatch = LF_ISSET(TXT_SHOWMATCH);
842 goto ins_ch;
843 case K_VLNEXT: /* Quote the next character. */
844 /* If in hex mode, see if we've entered a hex value. */
845 if (hex == H_INHEX) {
846 if (txt_hex(sp, tp, &tmp, ch))
847 goto err;
848 if (tmp) {
849 hex = H_NOTSET;
850 goto next_ch;
853 ch = '^';
854 quoted = Q_NEXTCHAR;
855 /* FALLTHROUGH */
856 default: /* Insert the character. */
857 ins_ch: /*
858 * If entering a space character after a word, check
859 * for abbreviations. If there was one, discard the
860 * replay characters.
862 if (isblank(ch) && abb == A_NOTSPACE && !replay) {
863 if (txt_abbrev(sp, tp, ch,
864 LF_ISSET(TXT_INFOLINE), &tmp, &ab_turnoff))
865 goto err;
866 if (tmp) {
867 if (LF_ISSET(TXT_RECORD))
868 rcol -= tmp;
869 goto next_ch;
872 /* If in hex mode, see if we've entered a hex value. */
873 if (hex == H_INHEX && !isxdigit(ch)) {
874 if (txt_hex(sp, tp, &tmp, ch))
875 goto err;
876 if (tmp) {
877 hex = H_NOTSET;
878 goto next_ch;
881 /* Check to see if we've crossed the margin. */
882 if (margin) {
883 if (sp->s_column(sp, ep, &col))
884 goto err;
885 if (col >= margin) {
886 if (txt_margin(sp, tp, &tmp, ch))
887 goto err;
888 if (tmp)
889 goto next_ch;
892 if (abb != A_NOTSET)
893 abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
895 if (tp->owrite) /* Overwrite a character. */
896 --tp->owrite;
897 else if (tp->insert) { /* Insert a character. */
898 ++tp->len;
899 if (tp->insert == 1)
900 tp->lb[sp->cno + 1] = tp->lb[sp->cno];
901 else
902 memmove(tp->lb + sp->cno + 1,
903 tp->lb + sp->cno, tp->insert);
906 tp->lb[sp->cno++] = ch;
909 * If we've reached the end of the buffer, then we
910 * need to switch into insert mode. This happens
911 * when there's a change to a mark and the user puts
912 * in more characters than the length of the motion.
914 ebuf_chk: if (sp->cno >= tp->len) {
915 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
916 LF_SET(TXT_APPENDEOL);
917 tp->lb[sp->cno] = CURSOR_CH;
918 ++tp->insert;
919 ++tp->len;
922 if (hex == H_NEXTCHAR)
923 hex = H_INHEX;
924 if (quoted == Q_NEXTCHAR)
925 quoted = Q_THISCHAR;
926 break;
928 #if defined(DEBUG) && 1
929 if (sp->cno + tp->insert + tp->owrite != tp->len)
930 msgq(sp, M_ERR,
931 "len %u != cno: %u ai: %u insert %u overwrite %u",
932 tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
933 tp->len = sp->cno + tp->insert + tp->owrite;
934 #endif
937 /* Clear input flag. */
938 ret: F_CLR(sp, S_INPUT);
940 if (LF_ISSET(TXT_RECORD))
941 VIP(sp)->rep_cnt = rcol;
942 return (eval);
944 /* Error jump. */
945 err: eval = 1;
946 txt_err(sp, ep, tiqh);
947 goto ret;
951 * txt_abbrev --
952 * Handle abbreviations.
954 static int
955 txt_abbrev(sp, tp, pushc, isinfoline, didsubp, turnoffp)
956 SCR *sp;
957 TEXT *tp;
958 ARG_CHAR_T pushc;
959 int isinfoline, *didsubp, *turnoffp;
961 CHAR_T ch;
962 SEQ *qp;
963 size_t len, off;
964 char *p;
966 /* Find the beginning of this "word". */
967 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
968 if (isblank(*p)) {
969 ++p;
970 break;
972 ++len;
973 if (off == tp->ai || off == tp->offset)
974 break;
978 * !!!
979 * Historic vi exploded abbreviations on the command line. This has
980 * obvious problems in that unabbreviating the string can be extremely
981 * tricky, particularly if the string has, say, an embedded escape
982 * character. Personally, I think it's a stunningly bad idea. Other
983 * examples of problems this caused in historic vi are:
984 * :ab foo bar
985 * :ab foo baz
986 * results in "bar" being abbreviated to "baz", which wasn't what the
987 * user had in mind at all. Also, the commands:
988 * :ab foo bar
989 * :unab foo<space>
990 * resulted in an error message that "bar" wasn't mapped. Finally,
991 * since the string was already exploded by the time the unabbreviate
992 * command got it, all it knew was that an abbreviation had occurred.
993 * Cleverly, it checked the replacement string for its unabbreviation
994 * match, which meant that the commands:
995 * :ab foo1 bar
996 * :ab foo2 bar
997 * :unab foo2
998 * unabbreviates "foo1", and the commands:
999 * :ab foo bar
1000 * :ab bar baz
1001 * unabbreviates "foo"!
1003 * Anyway, people neglected to first ask my opinion before they wrote
1004 * macros that depend on this stuff, so, we make this work as follows.
1005 * When checking for an abbreviation on the command line, if we get a
1006 * string which is <blank> terminated and which starts at the beginning
1007 * of the line, we check to see it is the abbreviate or unabbreviate
1008 * commands. If it is, turn abbreviations off and return as if no
1009 * abbreviation was found. Note also, minor trickiness, so that if the
1010 * user erases the line and starts another command, we go ahead an turn
1011 * abbreviations back on.
1013 * This makes the layering look like a Nachos Supreme.
1015 *didsubp = 0;
1016 if (isinfoline)
1017 if (off == tp->ai || off == tp->offset)
1018 if (ex_is_abbrev(p, len)) {
1019 *turnoffp = 1;
1020 return (0);
1021 } else
1022 *turnoffp = 0;
1023 else
1024 if (*turnoffp)
1025 return (0);
1027 /* Check for any abbreviations. */
1028 if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL)
1029 return (0);
1032 * Push the abbreviation onto the tty stack. Historically, characters
1033 * resulting from an abbreviation expansion were themselves subject to
1034 * map expansions, O_SHOWMATCH matching etc. This means the expanded
1035 * characters will be re-tested for abbreviations. It's difficult to
1036 * know what historic practice in this case was, since abbreviations
1037 * were applied to :colon command lines, so entering abbreviations that
1038 * looped was tricky, although possible. In addition, obvious loops
1039 * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
1040 * silently only implement and/or display the last abbreviation.)
1042 * This implementation doesn't recover well from such abbreviations.
1043 * The main input loop counts abbreviated characters, and, when it
1044 * reaches a limit, discards any abbreviated characters on the queue.
1045 * It's difficult to back up to the original position, as the replay
1046 * queue would have to be adjusted, and the line state when an initial
1047 * abbreviated character was received would have to be saved.
1049 ch = pushc;
1050 if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
1051 return (1);
1052 if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
1053 return (1);
1056 * Move the cursor to the start of the abbreviation,
1057 * adjust the length.
1059 sp->cno -= len;
1060 tp->len -= len;
1062 /* Copy any insert characters back. */
1063 if (tp->insert)
1064 memmove(tp->lb + sp->cno + tp->owrite,
1065 tp->lb + sp->cno + tp->owrite + len, tp->insert);
1068 * We return the length of the abbreviated characters. This is so
1069 * the calling routine can replace the replay characters with the
1070 * abbreviation. This means that subsequent '.' commands will produce
1071 * the same text, regardless of intervening :[un]abbreviate commands.
1072 * This is historic practice.
1074 *didsubp = len;
1075 return (0);
1078 /* Offset to next column of stop size. */
1079 #define STOP_OFF(c, stop) (stop - (c) % stop)
1082 * txt_ai_resolve --
1083 * When a line is resolved by <esc> or <cr>, review autoindent
1084 * characters.
1086 static void
1087 txt_ai_resolve(sp, tp)
1088 SCR *sp;
1089 TEXT *tp;
1091 u_long ts;
1092 int del;
1093 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
1094 char *p;
1097 * If the line is empty, has an offset, or no autoindent
1098 * characters, we're done.
1100 if (!tp->len || tp->offset || !tp->ai)
1101 return;
1104 * The autoindent characters plus any leading <blank> characters
1105 * in the line are resolved into the minimum number of characters.
1106 * Historic practice.
1108 ts = O_VAL(sp, O_TABSTOP);
1110 /* Figure out the last <blank> screen column. */
1111 for (p = tp->lb, scno = 0, len = tp->len,
1112 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
1113 if (*p == '\t') {
1114 if (spaces)
1115 tab_after_sp = 1;
1116 scno += STOP_OFF(scno, ts);
1117 } else {
1118 ++spaces;
1119 ++scno;
1123 * If there are no spaces, or no tabs after spaces and less than
1124 * ts spaces, it's already minimal.
1126 if (!spaces || !tab_after_sp && spaces < ts)
1127 return;
1129 /* Count up spaces/tabs needed to get to the target. */
1130 for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1131 cno += STOP_OFF(cno, ts);
1132 spaces = scno - cno;
1135 * Figure out how many characters we're dropping -- if we're not
1136 * dropping any, it's already minimal, we're done.
1138 old = p - tp->lb;
1139 new = spaces + tabs;
1140 if (old == new)
1141 return;
1143 /* Shift the rest of the characters down, adjust the counts. */
1144 del = old - new;
1145 memmove(p - del, p, tp->len - old);
1146 sp->cno -= del;
1147 tp->len -= del;
1149 /* Fill in space/tab characters. */
1150 for (p = tp->lb; tabs--;)
1151 *p++ = '\t';
1152 while (spaces--)
1153 *p++ = ' ';
1157 * txt_auto --
1158 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1159 * retrieve the line.
1162 txt_auto(sp, ep, lno, aitp, len, tp)
1163 SCR *sp;
1164 EXF *ep;
1165 recno_t lno;
1166 size_t len;
1167 TEXT *aitp, *tp;
1169 size_t nlen;
1170 char *p, *t;
1172 if (aitp == NULL) {
1173 if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
1174 return (0);
1175 } else
1176 p = t = aitp->lb;
1177 for (nlen = 0; len; ++p) {
1178 if (!isblank(*p))
1179 break;
1180 /* If last character is a space, it counts. */
1181 if (--len == 0) {
1182 ++p;
1183 break;
1187 /* No indentation. */
1188 if (p == t)
1189 return (0);
1191 /* Set count. */
1192 nlen = p - t;
1194 /* Make sure the buffer's big enough. */
1195 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + nlen);
1197 /* Copy the indentation into the new buffer. */
1198 memmove(tp->lb + nlen, tp->lb, tp->len);
1199 memmove(tp->lb, t, nlen);
1200 tp->len += nlen;
1202 /* Return the additional length. */
1203 tp->ai = nlen;
1204 return (0);
1208 * txt_backup --
1209 * Back up to the previously edited line.
1211 static TEXT *
1212 txt_backup(sp, ep, tiqh, tp, flags)
1213 SCR *sp;
1214 EXF *ep;
1215 TEXTH *tiqh;
1216 TEXT *tp;
1217 u_int flags;
1219 TEXT *ntp;
1220 size_t col;
1222 if (tp->q.cqe_prev == (void *)tiqh) {
1223 msgq(sp, M_BERR, "Already at the beginning of the insert");
1224 return (tp);
1227 /* Update the old line on the screen. */
1228 if (sp->s_change(sp, ep, tp->lno, LINE_DELETE))
1229 return (NULL);
1231 /* Get a handle on the previous TEXT structure. */
1232 ntp = tp->q.cqe_prev;
1234 /* Make sure that we can get enough space. */
1235 if (LF_ISSET(TXT_APPENDEOL) && ntp->len + 1 > ntp->lb_len &&
1236 binc(sp, &ntp->lb, &ntp->lb_len, ntp->len + 1))
1237 return (NULL);
1240 * Release current TEXT; now committed to the swap, nothing
1241 * better fail.
1243 CIRCLEQ_REMOVE(tiqh, tp, q);
1244 text_free(tp);
1246 /* Swap TEXT's. */
1247 tp = ntp;
1249 /* Set bookkeeping information. */
1250 col = tp->len;
1251 if (LF_ISSET(TXT_APPENDEOL)) {
1252 tp->lb[col] = CURSOR_CH;
1253 ++tp->insert;
1254 ++tp->len;
1256 sp->lno = tp->lno;
1257 sp->cno = col;
1258 return (tp);
1262 * txt_err --
1263 * Handle an error during input processing.
1265 static void
1266 txt_err(sp, ep, tiqh)
1267 SCR *sp;
1268 EXF *ep;
1269 TEXTH *tiqh;
1271 recno_t lno;
1272 size_t len;
1275 * The problem with input processing is that the cursor is at an
1276 * indeterminate position since some input may have been lost due
1277 * to a malloc error. So, try to go back to the place from which
1278 * the cursor started, knowing that it may no longer be available.
1280 * We depend on at least one line number being set in the text
1281 * chain.
1283 for (lno = tiqh->cqh_first->lno;
1284 file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
1286 sp->lno = lno == 0 ? 1 : lno;
1287 sp->cno = 0;
1289 /* Redraw the screen, just in case. */
1290 F_SET(sp, S_REDRAW);
1294 * txt_hex --
1295 * Let the user insert any character value they want.
1297 * !!!
1298 * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
1299 * for the user to specify a character value which their keyboard
1300 * may not be able to enter.
1302 static int
1303 txt_hex(sp, tp, was_hex, pushc)
1304 SCR *sp;
1305 TEXT *tp;
1306 int *was_hex;
1307 ARG_CHAR_T pushc;
1309 CHAR_T ch, savec;
1310 size_t len, off;
1311 u_long value;
1312 char *p, *wp;
1315 * Null-terminate the string. Since nul isn't a legal hex value,
1316 * this should be okay, and lets us use a local routine, which
1317 * presumably understands the character set, to convert the value.
1319 savec = tp->lb[sp->cno];
1320 tp->lb[sp->cno] = 0;
1322 /* Find the previous HEX_CH. */
1323 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1324 if (*p == HEX_CH) {
1325 wp = p + 1;
1326 break;
1328 ++len;
1329 /* If not on this line, there's nothing to do. */
1330 if (off == tp->ai || off == tp->offset)
1331 goto nothex;
1334 /* If no length, then it wasn't a hex value. */
1335 if (len == 0)
1336 goto nothex;
1338 /* Get the value. */
1339 value = strtol(wp, NULL, 16);
1340 if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
1341 nothex: tp->lb[sp->cno] = savec;
1342 *was_hex = 0;
1343 return (0);
1346 ch = pushc;
1347 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1348 return (1);
1349 ch = value;
1350 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1351 return (1);
1353 tp->lb[sp->cno] = savec;
1355 /* Move the cursor to the start of the hex value, adjust the length. */
1356 sp->cno -= len + 1;
1357 tp->len -= len + 1;
1359 /* Copy any insert characters back. */
1360 if (tp->insert)
1361 memmove(tp->lb + sp->cno + tp->owrite,
1362 tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
1364 *was_hex = 1;
1365 return (0);
1369 * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
1370 * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
1371 * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
1372 * the 10th column, and ^D moves it back.
1374 * !!!
1375 * The ^T and ^D characters in historical vi only had special meaning when
1376 * they were the first characters typed after entering text input mode.
1377 * Since normal erase characters couldn't erase autoindent (in this case
1378 * ^T) characters, this meant that inserting text into previously existing
1379 * text was quite strange, ^T only worked if it was the first keystroke,
1380 * and then it could only be erased by using ^D. This implementation treats
1381 * ^T specially anywhere it occurs in the input, and permits the standard
1382 * erase characters to erase characters inserted using it.
1384 * XXX
1385 * Technically, txt_indent, txt_outdent should part of the screen interface,
1386 * as they require knowledge of the size of a space character on the screen.
1387 * (Not the size of tabs, because tabs are logically composed of spaces.)
1388 * They're left in the text code because they're complicated, not to mention
1389 * the gruesome awareness that if spaces aren't a single column on the screen
1390 * for any language, we're into some serious, ah, for lack of a better word,
1391 * "issues".
1395 * txt_indent --
1396 * Handle ^T indents.
1398 static int
1399 txt_indent(sp, tp)
1400 SCR *sp;
1401 TEXT *tp;
1403 u_long sw, ts;
1404 size_t cno, off, scno, spaces, tabs;
1406 ts = O_VAL(sp, O_TABSTOP);
1407 sw = O_VAL(sp, O_SHIFTWIDTH);
1409 /* Get the current screen column. */
1410 for (off = scno = 0; off < sp->cno; ++off)
1411 if (tp->lb[off] == '\t')
1412 scno += STOP_OFF(scno, ts);
1413 else
1414 ++scno;
1416 /* Count up spaces/tabs needed to get to the target. */
1417 for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
1418 cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1419 cno += STOP_OFF(cno, ts);
1420 spaces = scno - cno;
1422 /* Put space/tab characters in place of any overwrite characters. */
1423 for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
1424 tp->lb[sp->cno++] = '\t';
1425 for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
1426 tp->lb[sp->cno++] = ' ';
1428 if (!tabs && !spaces)
1429 return (0);
1431 /* Make sure there's enough room. */
1432 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
1434 /* Move the insert characters out of the way. */
1435 if (tp->insert)
1436 memmove(tp->lb + sp->cno + spaces + tabs,
1437 tp->lb + sp->cno, tp->insert);
1439 /* Add new space/tab characters. */
1440 for (; tabs--; ++tp->len, ++tp->ai)
1441 tp->lb[sp->cno++] = '\t';
1442 for (; spaces--; ++tp->len, ++tp->ai)
1443 tp->lb[sp->cno++] = ' ';
1444 return (0);
1448 * txt_outdent --
1449 * Handle ^D outdents.
1452 static int
1453 txt_outdent(sp, tp)
1454 SCR *sp;
1455 TEXT *tp;
1457 u_long sw, ts;
1458 size_t cno, off, scno, spaces;
1460 ts = O_VAL(sp, O_TABSTOP);
1461 sw = O_VAL(sp, O_SHIFTWIDTH);
1463 /* Get the current screen column. */
1464 for (off = scno = 0; off < sp->cno; ++off)
1465 if (tp->lb[off] == '\t')
1466 scno += STOP_OFF(scno, ts);
1467 else
1468 ++scno;
1470 /* Get the previous shiftwidth column. */
1471 for (cno = scno; --scno % sw != 0;);
1473 /* Decrement characters until less than or equal to that slot. */
1474 for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
1475 if (tp->lb[--off] == '\t')
1476 cno -= STOP_OFF(cno, ts);
1477 else
1478 --cno;
1480 /* Spaces needed to get to the target. */
1481 spaces = scno - cno;
1483 /* Maybe just a delete. */
1484 if (spaces == 0)
1485 return (0);
1487 /* Make sure there's enough room. */
1488 BINC_RET(sp, tp->lb, tp->lb_len, tp->len + spaces);
1490 /* Use up any overwrite characters. */
1491 for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
1492 tp->lb[sp->cno++] = ' ';
1494 /* Maybe that was enough. */
1495 if (spaces == 0)
1496 return (0);
1498 /* Move the insert characters out of the way. */
1499 if (tp->insert)
1500 memmove(tp->lb + sp->cno + spaces,
1501 tp->lb + sp->cno, tp->insert);
1503 /* Add new space characters. */
1504 for (; spaces--; ++tp->len, ++tp->ai)
1505 tp->lb[sp->cno++] = ' ';
1506 return (0);
1510 * txt_resolve --
1511 * Resolve the input text chain into the file.
1513 static int
1514 txt_resolve(sp, ep, tiqh)
1515 SCR *sp;
1516 EXF *ep;
1517 TEXTH *tiqh;
1519 TEXT *tp;
1520 recno_t lno;
1522 /* The first line replaces a current line. */
1523 tp = tiqh->cqh_first;
1524 if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
1525 return (1);
1527 /* All subsequent lines are appended into the file. */
1528 for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
1529 if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
1530 return (1);
1531 return (0);
1535 * txt_showmatch --
1536 * Show a character match.
1538 * !!!
1539 * Historic vi tried to display matches even in the :colon command line.
1540 * I think not.
1542 static void
1543 txt_showmatch(sp, ep)
1544 SCR *sp;
1545 EXF *ep;
1547 struct timeval second;
1548 VCS cs;
1549 MARK m;
1550 fd_set zero;
1551 int cnt, endc, startc;
1554 * Do a refresh first, in case the v_ntext() code hasn't done
1555 * one in awhile, so the user can see what we're complaining
1556 * about.
1558 if (sp->s_refresh(sp, ep))
1559 return;
1561 * We don't display the match if it's not on the screen. Find
1562 * out what the first character on the screen is.
1564 if (sp->s_position(sp, ep, &m, 0, P_TOP))
1565 return;
1567 /* Initialize the getc() interface. */
1568 cs.cs_lno = sp->lno;
1569 cs.cs_cno = sp->cno - 1;
1570 if (cs_init(sp, ep, &cs))
1571 return;
1572 startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
1574 /* Search for the match. */
1575 for (cnt = 1;;) {
1576 if (cs_prev(sp, ep, &cs))
1577 return;
1578 if (cs.cs_lno < m.lno ||
1579 cs.cs_lno == m.lno && cs.cs_cno < m.cno)
1580 return;
1581 if (cs.cs_flags != 0) {
1582 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
1583 (void)sp->s_bell(sp);
1584 return;
1586 continue;
1588 if (cs.cs_ch == endc)
1589 ++cnt;
1590 else if (cs.cs_ch == startc && --cnt == 0)
1591 break;
1594 /* Move to the match. */
1595 m.lno = sp->lno;
1596 m.cno = sp->cno;
1597 sp->lno = cs.cs_lno;
1598 sp->cno = cs.cs_cno;
1599 (void)sp->s_refresh(sp, ep);
1602 * Sleep(3) is eight system calls. Do it fast -- besides,
1603 * I don't want to wait an entire second.
1605 FD_ZERO(&zero);
1606 second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
1607 second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
1608 (void)select(0, &zero, &zero, &zero, &second);
1610 /* Return to the current location. */
1611 sp->lno = m.lno;
1612 sp->cno = m.cno;
1613 (void)sp->s_refresh(sp, ep);
1617 * txt_margin --
1618 * Handle margin wrap.
1620 * !!!
1621 * Historic vi belled the user each time a character was entered after
1622 * crossing the margin until a space was entered which could be used to
1623 * break the line. I don't, it tends to wake the cats.
1625 static int
1626 txt_margin(sp, tp, didbreak, pushc)
1627 SCR *sp;
1628 TEXT *tp;
1629 int *didbreak;
1630 ARG_CHAR_T pushc;
1632 CHAR_T ch;
1633 size_t len, off, tlen;
1634 char *p, *wp;
1636 /* Find the closest previous blank. */
1637 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1638 if (isblank(*p)) {
1639 wp = p + 1;
1640 break;
1642 ++len;
1643 /* If it's the beginning of the line, there's nothing to do. */
1644 if (off == tp->ai || off == tp->offset) {
1645 *didbreak = 0;
1646 return (0);
1651 * Historic practice is to delete any trailing whitespace
1652 * from the previous line.
1654 for (tlen = len;; --p, --off) {
1655 if (!isblank(*p))
1656 break;
1657 ++tlen;
1658 if (off == tp->ai || off == tp->offset)
1659 break;
1662 ch = pushc;
1663 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1664 return (1);
1665 if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
1666 return (1);
1667 ch = '\n';
1668 if (term_push(sp, &ch, 1, 0, CH_NOMAP))
1669 return (1);
1671 sp->cno -= tlen;
1672 tp->owrite += tlen;
1673 *didbreak = 1;
1674 return (0);