3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
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 $";
12 #include <sys/types.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
43 /* Local version of BINC. */
44 #define TBINC(sp, lp, llen, nlen) { \
45 if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
51 * Read in text from the user.
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.
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.
82 v_ntext(sp
, ep
, tiqh
, tm
, lp
, len
, rp
, prompt
, ai_line
, flags
)
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. */
119 * Set the input flag, so tabs get displayed correctly
120 * and everyone knows that the text buffer is in use.
124 /* Local initialization. */
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) {
140 tp
->ai
= tp
->insert
= tp
->offset
= tp
->owrite
= 0;
143 memmove(tp
->lb
, lp
, len
);
147 newtp
: if ((tp
= text_init(sp
, lp
, len
, len
+ 32)) == NULL
)
149 CIRCLEQ_INSERT_HEAD(tiqh
, tp
, q
);
152 /* Set the starting line number. */
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
162 if (LF_ISSET(TXT_OVERWRITE
)) {
163 tp
->owrite
= tm
->cno
- sp
->cno
;
164 tp
->insert
= len
- tm
->cno
;
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,
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
))
191 * The cc and S commands have a special feature -- leading
192 * <blank> characters are handled as autoindent characters.
195 if (LF_ISSET(TXT_AICHARS
)) {
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
;
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
;
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.
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
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
))
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
)) {
251 ab_cnt
= ab_turnoff
= 0;
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.
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,
269 if (replay
= LF_ISSET(TXT_REPLAY
)) {
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.
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
282 if (VIP(sp
)->rep
== NULL
)
284 if (term_push(sp
, VIP(sp
)->rep
, VIP(sp
)->rep_cnt
, 0, CH_NOMAP
))
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
))
306 txt_showmatch(sp
, ep
);
307 } else if (sp
->s_refresh(sp
, ep
))
311 /* Get the next character. */
312 next_ch
: if (term_key(sp
, &ikey
, iflags
) != INP_OK
)
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
) {
321 "Abbreviation exceeded maximum number of characters");
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
) {
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.
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
363 if (ikey
.flags
& CH_QUOTED
)
365 if (quoted
== Q_THISCHAR
) {
375 switch (ikey
.value
) {
377 case K_NL
: /* New line. */
378 #define LINE_RESOLVE { \
380 * Handle abbreviations. If there was one, \
381 * discard the replay characters. \
383 if (abb == A_NOTSPACE && !replay) { \
384 if (txt_abbrev(sp, tp, ch, \
385 LF_ISSET(TXT_INFOLINE), &tmp, \
389 if (LF_ISSET(TXT_RECORD)) \
394 if (abb != A_NOTSET) \
396 /* Handle hex numbers. */ \
397 if (hex == H_INHEX) { \
398 if (txt_hex(sp, tp, &tmp, ch)) \
406 * The 'R' command returns any overwriteable \
407 * characters in the first line to the original \
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; \
417 /* Delete any appended cursor. */ \
418 if (LF_ISSET(TXT_APPENDEOL)) { \
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
))
434 "\r", 1, 0, CH_NOMAP
);
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
)
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
478 if (LF_ISSET(TXT_AUTOINDENT
)) {
479 txt_ai_resolve(sp
, tp
);
481 if (carat_st
== C_NOCHANGE
) {
483 OOBLNO
, &ait
, ait
.ai
, ntp
))
485 FREE_SPACE(sp
, ait
.lb
, ait
.lb_len
);
488 OOBLNO
, tp
, sp
->cno
, ntp
))
494 * If the user hasn't entered any characters, delete
495 * any autoindent characters.
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.
505 /* Reset bookkeeping for the old line. */
507 tp
->ai
= tp
->insert
= tp
->owrite
= 0;
509 /* New cursor position. */
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
;
521 /* Update the old line. */
522 if (sp
->s_change(sp
, ep
, tp
->lno
, LINE_RESET
))
525 /* Swap old and new TEXT's. */
528 /* Reset the cursor. */
531 /* Update the new line. */
532 if (sp
->s_change(sp
, ep
, tp
->lno
, LINE_INSERT
))
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
))
543 case K_ESCAPE
: /* Escape. */
544 if (!LF_ISSET(TXT_ESCAPE
))
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;
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
);
577 * If not resolving the lines into the file, end
581 * This is wrong, should pass back a length.
583 if (LF_ISSET(TXT_RESOLVE
)) {
584 if (txt_resolve(sp
, ep
, tiqh
))
587 * Clear input flag -- input buffer no longer
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.
602 rp
->cno
= sp
->cno
? sp
->cno
- 1 : 0;
603 if (sp
->s_change(sp
, ep
, rp
->lno
, LINE_RESET
))
607 case K_CARAT
: /* Delete autoindent chars. */
608 if (LF_ISSET(TXT_AUTOINDENT
) && sp
->cno
<= tp
->ai
)
609 carat_st
= C_CARATSET
;
611 case K_ZERO
: /* Delete autoindent chars. */
612 if (LF_ISSET(TXT_AUTOINDENT
) && sp
->cno
<= tp
->ai
)
613 carat_st
= C_ZEROSET
;
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
))
625 if (sp
->cno
== 0 || tp
->ai
== 0)
628 case C_CARATSET
: /* ^^D */
629 if (sp
->cno
> tp
->ai
+ tp
->offset
+ 1)
632 /* Save the ai string for later. */
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
;
641 case C_ZEROSET
: /* 0^D */
642 if (sp
->cno
> tp
->ai
+ tp
->offset
+ 1)
645 leftmargin
: tp
->lb
[sp
->cno
- 1] = ' ';
646 tp
->owrite
+= sp
->cno
- tp
->offset
;
648 sp
->cno
= tp
->offset
;
650 case C_NOTSET
: /* ^D */
651 if (sp
->cno
> tp
->ai
+ tp
->offset
)
653 (void)txt_outdent(sp
, tp
);
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
) {
670 * If at the beginning of the line, try and drop back
671 * to a previously inserted line.
674 if ((ntp
= txt_backup(sp
,
675 ep
, tiqh
, tp
, flags
)) == NULL
)
681 /* If nothing to erase, bell the user. */
682 if (sp
->cno
<= tp
->offset
) {
684 "No more characters to erase.");
688 /* Drop back one character. */
692 * Increment overwrite, decrement ai if deleted.
695 * Historic vi did not permit users to use erase
696 * characters to delete autoindent characters.
699 if (sp
->cno
< tp
->ai
)
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.
708 if ((ntp
= txt_backup(sp
,
709 ep
, tiqh
, tp
, flags
)) == NULL
)
715 * If at offset, nothing to erase so bell the user.
717 if (sp
->cno
<= tp
->offset
) {
719 "No more characters to erase.");
724 * First werase goes back to any autoindent
725 * and second werase goes back to the offset.
728 * Historic vi did not permit users to use erase
729 * characters to delete autoindent characters.
731 if (tp
->ai
&& sp
->cno
> tp
->ai
)
738 /* Skip over trailing space characters. */
739 while (sp
->cno
> max
&& isblank(tp
->lb
[sp
->cno
- 1])) {
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
) {
768 if (isblank(tp
->lb
[sp
->cno
- 1]))
772 if (LF_ISSET(TXT_ALTWERASE
)) {
775 if (isblank(tp
->lb
[sp
->cno
- 1]))
779 tmp
= inword(tp
->lb
[sp
->cno
- 1]);
780 while (sp
->cno
> max
) {
783 if (tmp
!= inword(tp
->lb
[sp
->cno
- 1])
784 || isblank(tp
->lb
[sp
->cno
- 1]))
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.
795 if ((ntp
= txt_backup(sp
,
796 ep
, tiqh
, tp
, flags
)) == NULL
)
801 /* If at offset, nothing to erase so bell the user. */
802 if (sp
->cno
<= tp
->offset
) {
804 "No more characters to erase.");
809 * First kill goes back to any autoindent
810 * and second kill goes back to the offset.
813 * Historic vi did not permit users to use erase
814 * characters to delete autoindent characters.
816 if (tp
->ai
&& sp
->cno
> tp
->ai
)
822 tp
->owrite
+= sp
->cno
- max
;
825 case K_CNTRLT
: /* Add autoindent char. */
826 if (!LF_ISSET(TXT_CNTRLT
))
828 if (txt_indent(sp
, tp
))
832 (void)sp
->s_suspend(sp
);
834 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
836 F_SET(sp
, S_REFRESH
);
841 showmatch
= LF_ISSET(TXT_SHOWMATCH
);
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
))
856 default: /* Insert the character. */
858 * If entering a space character after a word, check
859 * for abbreviations. If there was one, discard the
862 if (isblank(ch
) && abb
== A_NOTSPACE
&& !replay
) {
863 if (txt_abbrev(sp
, tp
, ch
,
864 LF_ISSET(TXT_INFOLINE
), &tmp
, &ab_turnoff
))
867 if (LF_ISSET(TXT_RECORD
))
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
))
881 /* Check to see if we've crossed the margin. */
883 if (sp
->s_column(sp
, ep
, &col
))
886 if (txt_margin(sp
, tp
, &tmp
, ch
))
893 abb
= isblank(ch
) ? A_SPACE
: A_NOTSPACE
;
895 if (tp
->owrite
) /* Overwrite a character. */
897 else if (tp
->insert
) { /* Insert a character. */
900 tp
->lb
[sp
->cno
+ 1] = tp
->lb
[sp
->cno
];
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
;
922 if (hex
== H_NEXTCHAR
)
924 if (quoted
== Q_NEXTCHAR
)
928 #if defined(DEBUG) && 1
929 if (sp
->cno
+ tp
->insert
+ tp
->owrite
!= tp
->len
)
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
;
937 /* Clear input flag. */
938 ret
: F_CLR(sp
, S_INPUT
);
940 if (LF_ISSET(TXT_RECORD
))
941 VIP(sp
)->rep_cnt
= rcol
;
946 txt_err(sp
, ep
, tiqh
);
952 * Handle abbreviations.
955 txt_abbrev(sp
, tp
, pushc
, isinfoline
, didsubp
, turnoffp
)
959 int isinfoline
, *didsubp
, *turnoffp
;
966 /* Find the beginning of this "word". */
967 for (off
= sp
->cno
- 1, p
= tp
->lb
+ off
, len
= 0;; --p
, --off
) {
973 if (off
== tp
->ai
|| off
== tp
->offset
)
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:
986 * results in "bar" being abbreviated to "baz", which wasn't what the
987 * user had in mind at all. Also, the commands:
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:
998 * unabbreviates "foo1", and the commands:
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.
1017 if (off
== tp
->ai
|| off
== tp
->offset
)
1018 if (ex_is_abbrev(p
, len
)) {
1027 /* Check for any abbreviations. */
1028 if ((qp
= seq_find(sp
, NULL
, p
, len
, SEQ_ABBREV
, NULL
)) == NULL
)
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.
1050 if (term_push(sp
, &ch
, 1, 0, CH_ABBREVIATED
))
1052 if (term_push(sp
, qp
->output
, qp
->olen
, 0, CH_ABBREVIATED
))
1056 * Move the cursor to the start of the abbreviation,
1057 * adjust the length.
1062 /* Copy any insert characters back. */
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.
1078 /* Offset to next column of stop size. */
1079 #define STOP_OFF(c, stop) (stop - (c) % stop)
1083 * When a line is resolved by <esc> or <cr>, review autoindent
1087 txt_ai_resolve(sp
, tp
)
1093 size_t cno
, len
, new, old
, scno
, spaces
, tab_after_sp
, tabs
;
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
)
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
)
1116 scno
+= STOP_OFF(scno
, ts
);
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
)
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.
1139 new = spaces
+ tabs
;
1143 /* Shift the rest of the characters down, adjust the counts. */
1145 memmove(p
- del
, p
, tp
->len
- old
);
1149 /* Fill in space/tab characters. */
1150 for (p
= tp
->lb
; tabs
--;)
1158 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1159 * retrieve the line.
1162 txt_auto(sp
, ep
, lno
, aitp
, len
, tp
)
1173 if ((p
= t
= file_gline(sp
, ep
, lno
, &len
)) == NULL
)
1177 for (nlen
= 0; len
; ++p
) {
1180 /* If last character is a space, it counts. */
1187 /* No indentation. */
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
);
1202 /* Return the additional length. */
1209 * Back up to the previously edited line.
1212 txt_backup(sp
, ep
, tiqh
, tp
, flags
)
1222 if (tp
->q
.cqe_prev
== (void *)tiqh
) {
1223 msgq(sp
, M_BERR
, "Already at the beginning of the insert");
1227 /* Update the old line on the screen. */
1228 if (sp
->s_change(sp
, ep
, tp
->lno
, LINE_DELETE
))
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))
1240 * Release current TEXT; now committed to the swap, nothing
1243 CIRCLEQ_REMOVE(tiqh
, tp
, q
);
1249 /* Set bookkeeping information. */
1251 if (LF_ISSET(TXT_APPENDEOL
)) {
1252 tp
->lb
[col
] = CURSOR_CH
;
1263 * Handle an error during input processing.
1266 txt_err(sp
, ep
, tiqh
)
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
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
;
1289 /* Redraw the screen, just in case. */
1290 F_SET(sp
, S_REDRAW
);
1295 * Let the user insert any character value they want.
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.
1303 txt_hex(sp
, tp
, was_hex
, pushc
)
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
) {
1329 /* If not on this line, there's nothing to do. */
1330 if (off
== tp
->ai
|| off
== tp
->offset
)
1334 /* If no length, then it wasn't a hex value. */
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
;
1347 if (term_push(sp
, &ch
, 1, 0, CH_NOMAP
| CH_QUOTED
))
1350 if (term_push(sp
, &ch
, 1, 0, CH_NOMAP
| CH_QUOTED
))
1353 tp
->lb
[sp
->cno
] = savec
;
1355 /* Move the cursor to the start of the hex value, adjust the length. */
1359 /* Copy any insert characters back. */
1361 memmove(tp
->lb
+ sp
->cno
+ tp
->owrite
,
1362 tp
->lb
+ sp
->cno
+ tp
->owrite
+ len
+ 1, tp
->insert
);
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.
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.
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,
1396 * Handle ^T indents.
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
);
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
)
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. */
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
++] = ' ';
1449 * Handle ^D outdents.
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
);
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
);
1480 /* Spaces needed to get to the target. */
1481 spaces
= scno
- cno
;
1483 /* Maybe just a delete. */
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. */
1498 /* Move the insert characters out of the way. */
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
++] = ' ';
1511 * Resolve the input text chain into the file.
1514 txt_resolve(sp
, ep
, tiqh
)
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
))
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
))
1536 * Show a character match.
1539 * Historic vi tried to display matches even in the :colon command line.
1543 txt_showmatch(sp
, ep
)
1547 struct timeval second
;
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
1558 if (sp
->s_refresh(sp
, ep
))
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
))
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
))
1572 startc
= (endc
= cs
.cs_ch
) == ')' ? '(' : '{';
1574 /* Search for the match. */
1576 if (cs_prev(sp
, ep
, &cs
))
1578 if (cs
.cs_lno
< m
.lno
||
1579 cs
.cs_lno
== m
.lno
&& cs
.cs_cno
< m
.cno
)
1581 if (cs
.cs_flags
!= 0) {
1582 if (cs
.cs_flags
== CS_EOF
|| cs
.cs_flags
== CS_SOF
) {
1583 (void)sp
->s_bell(sp
);
1588 if (cs
.cs_ch
== endc
)
1590 else if (cs
.cs_ch
== startc
&& --cnt
== 0)
1594 /* Move to the match. */
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.
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. */
1613 (void)sp
->s_refresh(sp
, ep
);
1618 * Handle margin wrap.
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.
1626 txt_margin(sp
, tp
, didbreak
, pushc
)
1633 size_t len
, off
, tlen
;
1636 /* Find the closest previous blank. */
1637 for (off
= sp
->cno
- 1, p
= tp
->lb
+ off
, len
= 0;; --p
, --off
) {
1643 /* If it's the beginning of the line, there's nothing to do. */
1644 if (off
== tp
->ai
|| off
== tp
->offset
) {
1651 * Historic practice is to delete any trailing whitespace
1652 * from the previous line.
1654 for (tlen
= len
;; --p
, --off
) {
1658 if (off
== tp
->ai
|| off
== tp
->offset
)
1663 if (term_push(sp
, &ch
, 1, 0, CH_NOMAP
| CH_QUOTED
))
1665 if (len
&& term_push(sp
, wp
, len
, 0, CH_NOMAP
| CH_QUOTED
))
1668 if (term_push(sp
, &ch
, 1, 0, CH_NOMAP
))