rework SEQ's to sort on more than the first character of the input
[nvi.git] / vi / v_txt.c
blob31656679aceb38fd55cffb2f3ac943ffc9127bfe
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.57 1993/11/27 15:52:45 bostic Exp $ (Berkeley) $Date: 1993/11/27 15:52:45 $";
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"
25 static int txt_abbrev __P((SCR *, TEXT *, int *, ARG_CHAR_T));
26 static void txt_ai_resolve __P((SCR *, TEXT *));
27 static TEXT *txt_backup __P((SCR *, EXF *, TEXTH *, TEXT *, u_int));
28 static void txt_err __P((SCR *, EXF *, TEXTH *));
29 static int txt_hex __P((SCR *, TEXT *, int *, ARG_CHAR_T));
30 static int txt_indent __P((SCR *, TEXT *));
31 static int txt_margin __P((SCR *, TEXT *, int *, ARG_CHAR_T));
32 static int txt_outdent __P((SCR *, TEXT *));
33 static void txt_showmatch __P((SCR *, EXF *));
34 static int txt_resolve __P((SCR *, EXF *, TEXTH *));
36 /* Cursor character (space is hard to track on the screen). */
37 #if defined(DEBUG) && 0
38 #undef CURSOR_CH
39 #define CURSOR_CH '+'
40 #endif
42 /* Local version of BINC. */
43 #define TBINC(sp, lp, llen, nlen) { \
44 if ((nlen) > llen && binc(sp, &(lp), &(llen), nlen)) \
45 goto err; \
49 * newtext --
50 * Read in text from the user.
52 * !!!
53 * Historic vi always used:
55 * ^D: autoindent deletion
56 * ^H: last character deletion
57 * ^W: last word deletion
58 * ^V: quote the next character
60 * regardless of the user's choices for these characters. The user's erase
61 * and kill characters worked in addition to these characters. Ex was not
62 * completely consistent with this, as it did map the scroll command to the
63 * user's EOF character.
65 * This implementation does not use fixed characters, but uses whatever the
66 * user specified as described by the termios structure. I'm getting away
67 * with something here, but I think I'm unlikely to get caught.
69 int
70 v_ntext(sp, ep, tiqh, tm, lp, len, rp, prompt, ai_line, flags)
71 SCR *sp;
72 EXF *ep;
73 TEXTH *tiqh;
74 MARK *tm; /* To MARK. */
75 const char *lp; /* Input line. */
76 const size_t len; /* Input line length. */
77 MARK *rp; /* Return MARK. */
78 int prompt; /* Prompt to display. */
79 recno_t ai_line; /* Line number to use for autoindent count. */
80 u_int flags; /* TXT_ flags. */
82 /* State of abbreviation checks. */
83 enum { A_NOTSET, A_SPACE, A_NOTSPACE } abb;
84 /* State of the "[^0]^D" sequences. */
85 enum { C_NOTSET, C_CARATSET, C_NOCHANGE, C_ZEROSET } carat_st;
86 /* State of the hex input character. */
87 enum { H_NOTSET, H_NEXTCHAR, H_INHEX } hex;
88 /* State of quotation. */
89 enum { Q_NOTSET, Q_NEXTCHAR, Q_THISCHAR } quoted;
90 CHAR_T ch; /* Input character. */
91 GS *gp; /* Global pointer. */
92 TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
93 size_t rcol; /* 0-N: insert offset in the replay buffer. */
94 size_t col; /* Current column. */
95 u_long margin; /* Wrapmargin value. */
96 int eval; /* Routine return value. */
97 int replay; /* If replaying a set of input. */
98 int showmatch; /* Showmatch set on this character. */
99 int max, tmp;
100 char *p;
103 * Set the input flag, so tabs get displayed correctly
104 * and everyone knows that the text buffer is in use.
106 F_SET(sp, S_INPUT);
108 /* Set return value. */
109 eval = 0;
112 * Get one TEXT structure with some initial buffer space, reusing
113 * the last one if it's big enough. (All TEXT bookkeeping fields
114 * default to 0 -- text_init() handles this.) If changing a line,
115 * copy it into the TEXT buffer.
117 if (tiqh->cqh_first != (void *)tiqh) {
118 tp = tiqh->cqh_first;
119 if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
120 text_lfree(tiqh);
121 goto newtp;
123 tp->ai = tp->insert = tp->offset = tp->owrite = 0;
124 if (lp != NULL) {
125 tp->len = len;
126 memmove(tp->lb, lp, len);
127 } else
128 tp->len = 0;
129 } else {
130 newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
131 return (1);
132 CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
135 /* Set the starting line number. */
136 tp->lno = sp->lno;
139 * Set the insert and overwrite counts. If overwriting characters,
140 * do insertion afterward. If not overwriting characters, assume
141 * doing insertion. If change is to a mark, emphasize it with an
142 * END_CH.
144 if (len) {
145 if (LF_ISSET(TXT_OVERWRITE)) {
146 tp->owrite = tm->cno - sp->cno;
147 tp->insert = len - tm->cno;
148 } else
149 tp->insert = len - sp->cno;
151 if (LF_ISSET(TXT_EMARK))
152 tp->lb[tm->cno - 1] = END_CH;
156 * Many of the special cases in this routine are to handle autoindent
157 * support. Somebody decided that it would be a good idea if "^^D"
158 * and "0^D" deleted all of the autoindented characters. In an editor
159 * that takes single character input from the user, this wasn't a very
160 * good idea. Note also that "^^D" resets the next lines' autoindent,
161 * but "0^D" doesn't.
163 * We assume that autoindent only happens on empty lines, so insert
164 * and overwrite will be zero. If doing autoindent, figure out how
165 * much indentation we need and fill it in. Update input column and
166 * screen cursor as necessary.
168 if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
169 if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
170 return (1);
171 sp->cno = tp->ai;
172 } else {
174 * The cc and S commands have a special feature -- leading
175 * <blank> characters are handled as autoindent characters.
176 * Beauty!
178 if (LF_ISSET(TXT_AICHARS)) {
179 tp->offset = 0;
180 tp->ai = sp->cno;
181 } else
182 tp->offset = sp->cno;
185 /* If getting a command buffer from the user, there may be a prompt. */
186 if (LF_ISSET(TXT_PROMPT)) {
187 tp->lb[sp->cno++] = prompt;
188 ++tp->len;
189 ++tp->offset;
193 * If appending after the end-of-line, add a space into the buffer
194 * and move the cursor right. This space is inserted, i.e. pushed
195 * along, and then deleted when the line is resolved. Assumes that
196 * the cursor is already positioned at the end of the line. This
197 * avoids the nastiness of having the cursor reside on a magical
198 * column, i.e. a column that doesn't really exist. The only down
199 * side is that we may wrap lines or scroll the screen before it's
200 * strictly necessary. Not a big deal.
202 if (LF_ISSET(TXT_APPENDEOL)) {
203 tp->lb[sp->cno] = CURSOR_CH;
204 ++tp->len;
205 ++tp->insert;
209 * Historic practice is that the wrapmargin value was a distance
210 * from the RIGHT-HAND column, not the left. It's more useful to
211 * us as a distance from the left-hand column.
213 * XXX
214 * Setting margin causes a significant performance hit. Normally
215 * we don't update the screen if there are keys waiting, but we
216 * have to if margin is set, otherwise the screen routines don't
217 * know where the cursor is.
219 if (!LF_ISSET(TXT_WRAPMARGIN))
220 margin = 0;
221 else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
222 margin = sp->cols - margin;
225 * Set up the dot command. Dot commands are done by saving the
226 * actual characters and replaying the input. We have to push
227 * the characters onto the key stack and then handle them normally,
228 * otherwise things like wrapmargin will fail.
230 * XXX
231 * It would be nice if we could swallow backspaces and such, but
232 * it's not all that easy to do. Another possibility would be to
233 * recognize full line insertions, which could be performed quickly,
234 * without replay.
236 rcol = 0;
237 if (replay = LF_ISSET(TXT_REPLAY)) {
238 if (term_push(sp, sp->gp->key, VIP(sp)->rep, VIP(sp)->rep_cnt))
239 return (1);
240 LF_CLR(TXT_RECORD);
243 /* Initialize abbreviations check. */
244 abb = F_ISSET(sp, S_ABBREV) &&
245 LF_ISSET(TXT_MAPINPUT) ? A_NOTSPACE : A_NOTSET;
247 gp = sp->gp;
248 for (carat_st = C_NOTSET,
249 hex = H_NOTSET, showmatch = 0, quoted = Q_NOTSET;;) {
251 * Reset the line and update the screen. (The txt_showmatch()
252 * code refreshes the screen for us.) Don't refresh unless
253 * we're about to wait on a character or we need to know where
254 * the cursor really is.
256 if (showmatch || margin ||
257 !TERM_MORE(gp->key) && !TERM_MORE(gp->tty)) {
258 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
259 goto err;
260 if (showmatch) {
261 showmatch = 0;
262 txt_showmatch(sp, ep);
263 } else if (sp->s_refresh(sp, ep))
264 goto err;
268 * Get the character. Check to see if the character fits
269 * into the input (and replay, if necessary) buffers. It
270 * isn't necessary to have tp->len bytes, since it doesn't
271 * consider the overwrite characters, but not worth fixing.
273 next_ch: if (term_key(sp, &ch, flags & TXT_GETKEY_MASK) != INP_OK)
274 goto err;
275 if (LF_ISSET(TXT_RECORD)) {
276 TBINC(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
277 VIP(sp)->rep[rcol++] = ch;
279 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
282 * If the character was quoted, replace the last character
283 * (the literal mark) with the new character.
285 * !!!
286 * Extension -- if the quoted character is HEX_CH, enter hex
287 * mode. If the user enters "<HEX_CH>[isxdigit()]*" we will
288 * try to use the value as a character. Anything else resets
289 * hex mode.
291 if (quoted == Q_THISCHAR) {
292 --sp->cno;
293 ++tp->owrite;
294 quoted = Q_NOTSET;
296 if (ch == HEX_CH)
297 hex = H_NEXTCHAR;
298 goto ins_ch;
301 switch (sp->special[ch]) {
302 case K_CR:
303 case K_NL: /* New line. */
304 #define LINE_RESOLVE { \
305 /* \
306 * Handle abbreviations. If there was one, \
307 * discard the replay characters. \
308 */ \
309 if (abb == A_NOTSPACE && !replay) { \
310 if (txt_abbrev(sp, tp, &tmp, ch)) \
311 goto err; \
312 if (tmp) { \
313 if (LF_ISSET(TXT_RECORD)) \
314 rcol -= tmp; \
315 goto next_ch; \
318 if (abb != A_NOTSET) \
319 abb = A_SPACE; \
320 /* Handle hex numbers. */ \
321 if (hex == H_INHEX) { \
322 if (txt_hex(sp, tp, &tmp, ch)) \
323 goto err; \
324 if (tmp) { \
325 hex = H_NOTSET; \
326 goto next_ch; \
329 /* \
330 * The 'R' command returns any overwriteable \
331 * characters in the first line to the original \
332 * characters.
333 */ \
334 if (LF_ISSET(TXT_REPLACE) && tp->owrite && \
335 tp == tiqh->cqh_first) { \
336 memmove(tp->lb + sp->cno, \
337 lp + sp->cno, tp->owrite); \
338 tp->insert += tp->owrite; \
339 tp->owrite = 0; \
341 /* Delete any appended cursor. */ \
342 if (LF_ISSET(TXT_APPENDEOL)) { \
343 --tp->len; \
344 --tp->insert; \
347 LINE_RESOLVE;
349 /* CR returns from the vi command line. */
350 if (LF_ISSET(TXT_CR)) {
351 if (F_ISSET(sp, S_SCRIPT))
352 (void)term_push(sp, gp->key, "\r", 1);
353 goto k_escape;
357 * Historic practice was to delete any <blank>
358 * characters following the inserted newline.
359 * This affects the 'R', 'c', and 's' commands.
361 for (p = tp->lb + sp->cno + tp->owrite;
362 tp->insert && isblank(*p);
363 ++p, ++tp->owrite, --tp->insert);
366 * Move any remaining insert characters into
367 * a new TEXT structure.
369 if ((ntp = text_init(sp,
370 tp->lb + sp->cno + tp->owrite,
371 tp->insert, tp->insert + 32)) == NULL)
372 goto err;
373 CIRCLEQ_INSERT_TAIL(tiqh, ntp, q);
375 /* Set bookkeeping for the new line. */
376 ntp->lno = tp->lno + 1;
377 ntp->insert = tp->insert;
380 * Resolve autoindented characters for the old line.
381 * Reset the autoindent line value. 0^D keeps the ai
382 * line from changing, ^D changes the level, even if
383 * there are no characters in the old line. Note,
384 * if using the current tp structure, use the cursor
385 * as the length, the user may have erased autoindent
386 * characters.
388 if (LF_ISSET(TXT_AUTOINDENT)) {
389 txt_ai_resolve(sp, tp);
391 if (carat_st == C_NOCHANGE) {
392 if (txt_auto(sp, ep,
393 OOBLNO, &ait, ait.ai, ntp))
394 goto err;
395 FREE_SPACE(sp, ait.lb, ait.lb_len);
396 } else
397 if (txt_auto(sp, ep,
398 OOBLNO, tp, sp->cno, ntp))
399 goto err;
400 carat_st = C_NOTSET;
404 * If the user hasn't entered any characters, delete
405 * autoindent characters.
407 * !!!
408 * Historic vi didn't get the insert test right, if
409 * there were characters being inserted, entering a
410 * <cr> left the autoindent characters on the line.
412 if (sp->cno <= tp->ai)
413 sp->cno = 0;
415 /* Reset bookkeeping for the old line. */
416 tp->len = sp->cno;
417 tp->ai = tp->insert = tp->owrite = 0;
419 /* New cursor position. */
420 sp->cno = ntp->ai;
422 /* New lines are TXT_APPENDEOL if nothing to insert. */
423 if (ntp->insert == 0) {
424 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
425 LF_SET(TXT_APPENDEOL);
426 ntp->lb[sp->cno] = CURSOR_CH;
427 ++ntp->insert;
428 ++ntp->len;
431 /* Update the old line. */
432 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
433 goto err;
435 /* Swap old and new TEXT's. */
436 tp = ntp;
438 /* Reset the cursor. */
439 sp->lno = tp->lno;
441 /* Update the new line. */
442 if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
443 goto err;
445 /* Set the renumber bit. */
446 F_SET(sp, S_RENUMBER);
448 /* Refresh if nothing waiting. */
449 if ((margin ||
450 !TERM_MORE(gp->key) && !TERM_MORE(gp->tty)) &&
451 sp->s_refresh(sp, ep))
452 goto err;
453 goto next_ch;
454 case K_ESCAPE: /* Escape. */
455 if (!LF_ISSET(TXT_ESCAPE))
456 goto ins_ch;
458 LINE_RESOLVE;
461 * If there aren't any trailing characters in the line
462 * and the user hasn't entered any characters, delete
463 * the autoindent characters.
465 if (!tp->insert && sp->cno <= tp->ai) {
466 tp->len = tp->owrite = 0;
467 sp->cno = 0;
468 } else if (LF_ISSET(TXT_AUTOINDENT))
469 txt_ai_resolve(sp, tp);
471 /* If there are insert characters, copy them down. */
472 k_escape: if (tp->insert && tp->owrite)
473 memmove(tp->lb + sp->cno,
474 tp->lb + sp->cno + tp->owrite, tp->insert);
475 tp->len -= tp->owrite;
478 * Delete any lines that were inserted into the text
479 * structure and then erased.
481 while (tp->q.cqe_next != (void *)tiqh) {
482 ntp = tp->q.cqe_next;
483 CIRCLEQ_REMOVE(tiqh, ntp, q);
484 text_free(ntp);
488 * If not resolving the lines into the file, end
489 * it with a nul.
491 * XXX
492 * This is wrong, should pass back a length.
494 if (LF_ISSET(TXT_RESOLVE)) {
495 if (txt_resolve(sp, ep, tiqh))
496 goto err;
497 } else {
498 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
499 tp->lb[tp->len] = '\0';
503 * Set the return cursor position to rest on the last
504 * inserted character.
506 if (rp != NULL) {
507 rp->lno = tp->lno;
508 rp->cno = sp->cno ? sp->cno - 1 : 0;
509 if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
510 goto err;
512 goto ret;
513 case K_CARAT: /* Delete autoindent chars. */
514 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
515 carat_st = C_CARATSET;
516 goto ins_ch;
517 case K_ZERO: /* Delete autoindent chars. */
518 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
519 carat_st = C_ZEROSET;
520 goto ins_ch;
521 case K_VEOF: /* Delete autoindent char. */
523 * If not doing autoindent, in the first column, no
524 * characters to erase, or already inserted non-ai
525 * characters, it's a literal. The last test is done
526 * in the switch, as the CARAT forms are N + 1, not N.
528 if (!LF_ISSET(TXT_AUTOINDENT) ||
529 sp->cno == 0 || tp->ai == 0)
530 goto ins_ch;
531 switch (carat_st) {
532 case C_CARATSET: /* ^^D */
533 if (sp->cno > tp->ai + tp->offset + 1)
534 goto ins_ch;
536 /* Save the ai string for later. */
537 ait.lb = NULL;
538 ait.lb_len = 0;
539 TBINC(sp, ait.lb, ait.lb_len, tp->ai);
540 memmove(ait.lb, tp->lb, tp->ai);
541 ait.ai = ait.len = tp->ai;
543 carat_st = C_NOCHANGE;
544 goto leftmargin;
545 case C_ZEROSET: /* 0^D */
546 if (sp->cno > tp->ai + tp->offset + 1)
547 goto ins_ch;
548 carat_st = C_NOTSET;
549 leftmargin: tp->lb[sp->cno - 1] = ' ';
550 tp->owrite += sp->cno - tp->offset;
551 tp->ai = 0;
552 sp->cno = tp->offset;
553 break;
554 case C_NOTSET: /* ^D */
555 if (sp->cno > tp->ai + tp->offset)
556 goto ins_ch;
557 (void)txt_outdent(sp, tp);
558 break;
559 default:
560 abort();
562 break;
563 case K_VERASE: /* Erase the last character. */
565 * If can erase over the prompt, return. Len is 0
566 * if backspaced over the prompt, 1 if only CR entered.
568 if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
569 tp->len = 0;
570 goto ret;
574 * If at the beginning of the line, try and drop back
575 * to a previously inserted line.
577 if (sp->cno == 0) {
578 if ((ntp = txt_backup(sp,
579 ep, tiqh, tp, flags)) == NULL)
580 goto err;
581 tp = ntp;
582 break;
585 /* If nothing to erase, bell the user. */
586 if (sp->cno <= tp->offset) {
587 msgq(sp, M_BERR,
588 "No more characters to erase.");
589 break;
592 /* Drop back one character. */
593 --sp->cno;
596 * Increment overwrite, decrement ai if deleted.
598 * !!!
599 * Historic vi did not permit users to use erase
600 * characters to delete autoindent characters.
602 ++tp->owrite;
603 if (sp->cno < tp->ai)
604 --tp->ai;
605 break;
606 case K_VWERASE: /* Skip back one word. */
608 * If at the beginning of the line, try and drop back
609 * to a previously inserted line.
611 if (sp->cno == 0) {
612 if ((ntp = txt_backup(sp,
613 ep, tiqh, tp, flags)) == NULL)
614 goto err;
615 tp = ntp;
619 * If at offset, nothing to erase so bell the user.
621 if (sp->cno <= tp->offset) {
622 msgq(sp, M_BERR,
623 "No more characters to erase.");
624 break;
628 * First werase goes back to any autoindent
629 * and second werase goes back to the offset.
631 * !!!
632 * Historic vi did not permit users to use erase
633 * characters to delete autoindent characters.
635 if (tp->ai && sp->cno > tp->ai)
636 max = tp->ai;
637 else {
638 tp->ai = 0;
639 max = tp->offset;
642 /* Skip over trailing space characters. */
643 while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
644 --sp->cno;
645 ++tp->owrite;
647 if (sp->cno == max)
648 break;
650 * There are three types of word erase found on UNIX
651 * systems. They can be identified by how the string
652 * /a/b/c is treated -- as 1, 3, or 6 words. Historic
653 * vi had two classes of characters, and strings were
654 * delimited by them and <blank>'s, so, 6 words. The
655 * historic tty interface used <blank>'s to delimit
656 * strings, so, 1 word. The algorithm offered in the
657 * 4.4BSD tty interface (as stty altwerase) treats it
658 * as 3 words -- there are two classes of characters,
659 * and strings are delimited by them and <blank>'s.
660 * The difference is that the type of the first erased
661 * character erased is ignored, which is exactly right
662 * when erasing pathname components. Here, the options
663 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
664 * tty interface and the historic tty driver behavior,
665 * respectively, and the default is the same as the
666 * historic vi behavior.
668 if (LF_ISSET(TXT_TTYWERASE))
669 while (sp->cno > max) {
670 --sp->cno;
671 ++tp->owrite;
672 if (isblank(tp->lb[sp->cno - 1]))
673 break;
675 else {
676 if (LF_ISSET(TXT_ALTWERASE)) {
677 --sp->cno;
678 ++tp->owrite;
679 if (isblank(tp->lb[sp->cno - 1]))
680 break;
682 if (sp->cno > max)
683 tmp = inword(tp->lb[sp->cno - 1]);
684 while (sp->cno > max) {
685 --sp->cno;
686 ++tp->owrite;
687 if (tmp != inword(tp->lb[sp->cno - 1])
688 || isblank(tp->lb[sp->cno - 1]))
689 break;
692 break;
693 case K_VKILL: /* Restart this line. */
695 * If at the beginning of the line, try and drop back
696 * to a previously inserted line.
698 if (sp->cno == 0) {
699 if ((ntp = txt_backup(sp,
700 ep, tiqh, tp, flags)) == NULL)
701 goto err;
702 tp = ntp;
705 /* If at offset, nothing to erase so bell the user. */
706 if (sp->cno <= tp->offset) {
707 msgq(sp, M_BERR,
708 "No more characters to erase.");
709 break;
713 * First kill goes back to any autoindent
714 * and second kill goes back to the offset.
716 * !!!
717 * Historic vi did not permit users to use erase
718 * characters to delete autoindent characters.
720 if (tp->ai && sp->cno > tp->ai)
721 max = tp->ai;
722 else {
723 tp->ai = 0;
724 max = tp->offset;
726 tp->owrite += sp->cno - max;
727 sp->cno = max;
728 break;
729 case K_CNTRLT: /* Add autoindent char. */
730 if (!LF_ISSET(TXT_CNTRLT))
731 goto ins_ch;
732 if (txt_indent(sp, tp))
733 goto err;
734 goto ebuf_chk;
735 case K_CNTRLZ:
736 (void)sp->s_suspend(sp);
737 break;
738 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
739 case K_FORMFEED:
740 F_SET(sp, S_REFRESH);
741 break;
742 #endif
743 case K_RIGHTBRACE:
744 case K_RIGHTPAREN:
745 showmatch = LF_ISSET(TXT_SHOWMATCH);
746 goto ins_ch;
747 case K_VLNEXT: /* Quote the next character. */
748 /* If in hex mode, see if we've entered a hex value. */
749 if (hex == H_INHEX) {
750 if (txt_hex(sp, tp, &tmp, ch))
751 goto err;
752 if (tmp) {
753 hex = H_NOTSET;
754 goto next_ch;
757 ch = '^';
758 quoted = Q_NEXTCHAR;
759 /* FALLTHROUGH */
760 default: /* Insert the character. */
761 ins_ch: /*
762 * If entering a space character after a word, check
763 * for abbreviations. If there was one, discard the
764 * replay characters.
766 if (isblank(ch) && abb == A_NOTSPACE && !replay) {
767 if (txt_abbrev(sp, tp, &tmp, ch))
768 goto err;
769 if (tmp) {
770 if (LF_ISSET(TXT_RECORD))
771 rcol -= tmp;
772 goto next_ch;
775 /* If in hex mode, see if we've entered a hex value. */
776 if (hex == H_INHEX && !isxdigit(ch)) {
777 if (txt_hex(sp, tp, &tmp, ch))
778 goto err;
779 if (tmp) {
780 hex = H_NOTSET;
781 goto next_ch;
784 /* Check to see if we've crossed the margin. */
785 if (margin) {
786 if (sp->s_column(sp, ep, &col))
787 goto err;
788 if (col >= margin) {
789 if (txt_margin(sp, tp, &tmp, ch))
790 goto err;
791 if (tmp)
792 goto next_ch;
795 if (abb != A_NOTSET)
796 abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
798 if (tp->owrite) /* Overwrite a character. */
799 --tp->owrite;
800 else if (tp->insert) { /* Insert a character. */
801 ++tp->len;
802 if (tp->insert == 1)
803 tp->lb[sp->cno + 1] = tp->lb[sp->cno];
804 else
805 memmove(tp->lb + sp->cno + 1,
806 tp->lb + sp->cno, tp->insert);
809 tp->lb[sp->cno++] = ch;
812 * If we've reached the end of the buffer, then we
813 * need to switch into insert mode. This happens
814 * when there's a change to a mark and the user puts
815 * in more characters than the length of the motion.
817 ebuf_chk: if (sp->cno >= tp->len) {
818 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
819 LF_SET(TXT_APPENDEOL);
820 tp->lb[sp->cno] = CURSOR_CH;
821 ++tp->insert;
822 ++tp->len;
825 if (hex == H_NEXTCHAR)
826 hex = H_INHEX;
827 if (quoted == Q_NEXTCHAR)
828 quoted = Q_THISCHAR;
829 break;
831 #if defined(DEBUG) && 1
832 if (sp->cno + tp->insert + tp->owrite != tp->len)
833 msgq(sp, M_ERR,
834 "len %u != cno: %u ai: %u insert %u overwrite %u",
835 tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
836 tp->len = sp->cno + tp->insert + tp->owrite;
837 #endif
840 /* Clear input flag. */
841 ret: F_CLR(sp, S_INPUT);
843 if (LF_ISSET(TXT_RECORD))
844 VIP(sp)->rep_cnt = rcol;
845 return (eval);
847 /* Error jump. */
848 err: eval = 1;
849 txt_err(sp, ep, tiqh);
850 goto ret;
854 * txt_abbrev --
855 * Handle abbreviations.
857 static int
858 txt_abbrev(sp, tp, didsubp, pushc)
859 SCR *sp;
860 TEXT *tp;
861 int *didsubp;
862 ARG_CHAR_T pushc;
864 CHAR_T ch;
865 SEQ *qp;
866 size_t len, off;
867 char *p;
869 /* Find the beginning of this "word". */
870 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
871 if (isblank(*p)) {
872 ++p;
873 break;
875 ++len;
876 if (off == tp->ai || off == tp->offset)
877 break;
880 /* Check for any abbreviations. */
881 if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL) {
882 *didsubp = 0;
883 return (0);
887 * Push the abbreviation onto the tty stack. Historically, characters
888 * resulting from an abbreviation expansion were themselves subject to
889 * map expansions, O_SHOWMATCH matching etc. This means the expanded
890 * characters will be re-tested for abbreviations. It's difficult to
891 * know what historic practice in this case was, since abbreviations
892 * were applied to :colon command lines, so entering abbreviations that
893 * looped was tricky, if not impossible. In addition, obvious loops
894 * don't work as expected. (The command ':ab a b|ab b c|ab c a' will
895 * silently only implement the last of the abbreviations.)
897 * XXX
898 * There obvious infinite loop, if a abbreviates to b and b to a, is
899 * "fixed" by the looping code in the terminal read routines. It's
900 * an ugly fix, though because it forces the user out of input mode
901 * when it returns an error, flushing the queued characters. My guess
902 * is that the correct fix is to tag each character with the number of
903 * times it has been abbreviated, and permit only a single abbreviation.
904 * This requires a major rework of what an input character looks like.
906 ch = pushc;
907 if (term_push(sp, sp->gp->tty, &ch, 1))
908 return (1);
909 if (term_push(sp, sp->gp->tty, qp->output, qp->olen))
910 return (1);
912 /* Move the cursor to the start of the hex value, adjust the length. */
913 sp->cno -= len;
914 tp->len -= len;
916 /* Copy any insert characters back. */
917 if (tp->insert)
918 memmove(tp->lb + sp->cno + tp->owrite,
919 tp->lb + sp->cno + tp->owrite + len, tp->insert);
922 * We return the length of the abbreviated characters. This is so
923 * the calling routine can replace the replay characters with the
924 * abbreviation. This means that subsequent '.' commands will produce
925 * the same text, regardless of intervening :[un]abbreviate commands.
926 * This is historic practice.
928 *didsubp = len;
929 return (0);
932 /* Offset to next column of stop size. */
933 #define STOP_OFF(c, stop) (stop - (c) % stop)
936 * txt_ai_resolve --
937 * When a line is resolved by <esc> or <cr>, review autoindent
938 * characters.
940 static void
941 txt_ai_resolve(sp, tp)
942 SCR *sp;
943 TEXT *tp;
945 u_long ts;
946 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
947 char *p;
950 * If the line is empty, has an offset, or no autoindent
951 * characters, we're done.
953 if (!tp->len || tp->offset || !tp->ai)
954 return;
957 * The autoindent characters plus any leading <blank> characters
958 * in the line are resolved into the minimum number of characters.
959 * Historic practice.
961 ts = O_VAL(sp, O_TABSTOP);
963 /* Figure out the last <blank> screen column. */
964 for (p = tp->lb, scno = 0, len = tp->len,
965 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
966 if (*p == '\t') {
967 if (spaces)
968 tab_after_sp = 1;
969 scno += STOP_OFF(scno, ts);
970 } else {
971 ++spaces;
972 ++scno;
976 * If there are no spaces, or no tabs after spaces and less than
977 * ts spaces, it's already minimal.
979 if (!spaces || !tab_after_sp && spaces < ts)
980 return;
982 /* Count up spaces/tabs needed to get to the target. */
983 for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
984 cno += STOP_OFF(cno, ts);
985 spaces = scno - cno;
988 * Figure out how many characters we're dropping -- if we're not
989 * dropping any, it's already minimal, we're done.
991 old = p - tp->lb;
992 new = spaces + tabs;
993 if (old == new)
994 return;
996 /* Shift the rest of the characters down. */
997 memmove(p - (old - new), p, tp->len - old);
998 tp->len -= (old - new);
999 sp->cno -= (old - new);
1001 /* Fill in space/tab characters. */
1002 for (p = tp->lb; tabs--;)
1003 *p++ = '\t';
1004 while (spaces--)
1005 *p++ = ' ';
1009 * txt_auto --
1010 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1011 * retrieve the line.
1014 txt_auto(sp, ep, lno, aitp, len, tp)
1015 SCR *sp;
1016 EXF *ep;
1017 recno_t lno;
1018 size_t len;
1019 TEXT *aitp, *tp;
1021 size_t nlen;
1022 char *p, *t;
1024 if (aitp == NULL) {
1025 if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
1026 return (0);
1027 } else
1028 p = t = aitp->lb;
1029 for (nlen = 0; len; ++p) {
1030 if (!isblank(*p))
1031 break;
1032 /* If last character is a space, it counts. */
1033 if (--len == 0) {
1034 ++p;
1035 break;
1039 /* No indentation. */
1040 if (p == t)
1041 return (0);
1043 /* Set count. */
1044 nlen = p - t;
1046 /* Make sure the buffer's big enough. */
1047 BINC(sp, tp->lb, tp->lb_len, tp->len + nlen);
1049 /* Copy the indentation into the new buffer. */
1050 memmove(tp->lb + nlen, tp->lb, tp->len);
1051 memmove(tp->lb, t, nlen);
1052 tp->len += nlen;
1054 /* Return the additional length. */
1055 tp->ai = nlen;
1056 return (0);
1060 * txt_backup --
1061 * Back up to the previously edited line.
1063 static TEXT *
1064 txt_backup(sp, ep, tiqh, tp, flags)
1065 SCR *sp;
1066 EXF *ep;
1067 TEXTH *tiqh;
1068 TEXT *tp;
1069 u_int flags;
1071 TEXT *ntp;
1072 size_t col;
1074 if (tp->q.cqe_prev == (void *)tiqh) {
1075 msgq(sp, M_BERR, "Already at the beginning of the insert");
1076 return (tp);
1079 /* Update the old line on the screen. */
1080 if (sp->s_change(sp, ep, tp->lno, LINE_DELETE))
1081 return (NULL);
1083 /* Get a handle on the previous TEXT structure. */
1084 ntp = tp->q.cqe_prev;
1086 /* Make sure that we can get enough space. */
1087 if (LF_ISSET(TXT_APPENDEOL) && ntp->len + 1 > ntp->lb_len &&
1088 binc(sp, &ntp->lb, &ntp->lb_len, ntp->len + 1))
1089 return (NULL);
1092 * Release current TEXT; now committed to the swap, nothing
1093 * better fail.
1095 CIRCLEQ_REMOVE(tiqh, tp, q);
1096 text_free(tp);
1098 /* Swap TEXT's. */
1099 tp = ntp;
1101 /* Set bookkeeping information. */
1102 col = tp->len;
1103 if (LF_ISSET(TXT_APPENDEOL)) {
1104 tp->lb[col] = CURSOR_CH;
1105 ++tp->insert;
1106 ++tp->len;
1108 sp->lno = tp->lno;
1109 sp->cno = col;
1110 return (tp);
1114 * txt_err --
1115 * Handle an error during input processing.
1117 static void
1118 txt_err(sp, ep, tiqh)
1119 SCR *sp;
1120 EXF *ep;
1121 TEXTH *tiqh;
1123 recno_t lno;
1124 size_t len;
1127 * The problem with input processing is that the cursor is at an
1128 * indeterminate position since some input may have been lost due
1129 * to a malloc error. So, try to go back to the place from which
1130 * the cursor started, knowing that it may no longer be available.
1132 * We depend on at least one line number being set in the text
1133 * chain.
1135 for (lno = tiqh->cqh_first->lno;
1136 file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
1138 sp->lno = lno == 0 ? 1 : lno;
1139 sp->cno = 0;
1141 /* Redraw the screen, just in case. */
1142 F_SET(sp, S_REDRAW);
1146 * txt_hex --
1147 * Let the user insert any character value they want.
1149 * !!!
1150 * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
1151 * for the user to specify a character value which their keyboard
1152 * may not be able to enter.
1154 static int
1155 txt_hex(sp, tp, was_hex, pushc)
1156 SCR *sp;
1157 TEXT *tp;
1158 int *was_hex;
1159 ARG_CHAR_T pushc;
1161 CHAR_T ch, savec;
1162 size_t len, off;
1163 u_long value;
1164 char *p, *wp;
1167 * Null-terminate the string. Since nul isn't a legal hex value,
1168 * this should be okay, and lets us use a local routine, which
1169 * presumably understands the character set, to convert the value.
1171 savec = tp->lb[sp->cno];
1172 tp->lb[sp->cno] = 0;
1174 /* Find the previous HEX_CH. */
1175 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1176 if (*p == HEX_CH) {
1177 wp = p + 1;
1178 break;
1180 ++len;
1181 /* If not on this line, there's nothing to do. */
1182 if (off == tp->ai || off == tp->offset)
1183 goto nothex;
1186 /* If no length, then it wasn't a hex value. */
1187 if (len == 0)
1188 goto nothex;
1190 /* Get the value. */
1191 value = strtol(wp, NULL, 16);
1192 if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
1193 nothex: tp->lb[sp->cno] = savec;
1194 *was_hex = 0;
1195 return (0);
1198 ch = pushc;
1199 if (term_push(sp, sp->gp->tty, &ch, 1))
1200 return (1);
1201 ch = value;
1202 if (term_push(sp, sp->gp->tty, &ch, 1))
1203 return (1);
1205 tp->lb[sp->cno] = savec;
1207 /* Move the cursor to the start of the hex value, adjust the length. */
1208 sp->cno -= len + 1;
1209 tp->len -= len + 1;
1211 /* Copy any insert characters back. */
1212 if (tp->insert)
1213 memmove(tp->lb + sp->cno + tp->owrite,
1214 tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
1216 *was_hex = 1;
1217 return (0);
1221 * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
1222 * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
1223 * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
1224 * the 10th column, and ^D moves it back.
1226 * !!!
1227 * The ^T and ^D characters in historical vi only had special meaning when
1228 * they were the first characters typed after entering text input mode.
1229 * Since normal erase characters couldn't erase autoindent (in this case
1230 * ^T) characters, this meant that inserting text into previously existing
1231 * text was quite strange, ^T only worked if it was the first keystroke,
1232 * and then it could only be erased by using ^D. This implementation treats
1233 * ^T specially anywhere it occurs in the input, and permits the standard
1234 * erase characters to erase characters inserted using it.
1236 * XXX
1237 * Technically, txt_indent, txt_outdent should part of the screen interface,
1238 * as they require knowledge of the size of a space character on the screen.
1239 * (Not the size of tabs, because tabs are logically composed of spaces.)
1240 * They're left in the text code because they're complicated, not to mention
1241 * the gruesome awareness that if spaces aren't a single column on the screen
1242 * for any language, we're into some serious, ah, for lack of a better word,
1243 * "issues".
1247 * txt_indent --
1248 * Handle ^T indents.
1250 static int
1251 txt_indent(sp, tp)
1252 SCR *sp;
1253 TEXT *tp;
1255 u_long sw, ts;
1256 size_t cno, off, scno, spaces, tabs;
1258 ts = O_VAL(sp, O_TABSTOP);
1259 sw = O_VAL(sp, O_SHIFTWIDTH);
1261 /* Get the current screen column. */
1262 for (off = scno = 0; off < sp->cno; ++off)
1263 if (tp->lb[off] == '\t')
1264 scno += STOP_OFF(scno, ts);
1265 else
1266 ++scno;
1268 /* Count up spaces/tabs needed to get to the target. */
1269 for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
1270 cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1271 cno += STOP_OFF(cno, ts);
1272 spaces = scno - cno;
1274 /* Put space/tab characters in place of any overwrite characters. */
1275 for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
1276 tp->lb[sp->cno++] = '\t';
1277 for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
1278 tp->lb[sp->cno++] = ' ';
1280 if (!tabs && !spaces)
1281 return (0);
1283 /* Make sure there's enough room. */
1284 BINC(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
1286 /* Move the insert characters out of the way. */
1287 if (tp->insert)
1288 memmove(tp->lb + sp->cno + spaces + tabs,
1289 tp->lb + sp->cno, tp->insert);
1291 /* Add new space/tab characters. */
1292 for (; tabs--; ++tp->len, ++tp->ai)
1293 tp->lb[sp->cno++] = '\t';
1294 for (; spaces--; ++tp->len, ++tp->ai)
1295 tp->lb[sp->cno++] = ' ';
1296 return (0);
1300 * txt_outdent --
1301 * Handle ^D outdents.
1304 static int
1305 txt_outdent(sp, tp)
1306 SCR *sp;
1307 TEXT *tp;
1309 u_long sw, ts;
1310 size_t cno, off, scno, spaces;
1312 ts = O_VAL(sp, O_TABSTOP);
1313 sw = O_VAL(sp, O_SHIFTWIDTH);
1315 /* Get the current screen column. */
1316 for (off = scno = 0; off < sp->cno; ++off)
1317 if (tp->lb[off] == '\t')
1318 scno += STOP_OFF(scno, ts);
1319 else
1320 ++scno;
1322 /* Get the previous shiftwidth column. */
1323 for (cno = scno; --scno % sw != 0;);
1325 /* Decrement characters until less than or equal to that slot. */
1326 for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
1327 if (tp->lb[--off] == '\t')
1328 cno -= STOP_OFF(cno, ts);
1329 else
1330 --cno;
1332 /* Spaces needed to get to the target. */
1333 spaces = scno - cno;
1335 /* Maybe just a delete. */
1336 if (spaces == 0)
1337 return (0);
1339 /* Make sure there's enough room. */
1340 BINC(sp, tp->lb, tp->lb_len, tp->len + spaces);
1342 /* Use up any overwrite characters. */
1343 for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
1344 tp->lb[sp->cno++] = ' ';
1346 /* Maybe that was enough. */
1347 if (spaces == 0)
1348 return (0);
1350 /* Move the insert characters out of the way. */
1351 if (tp->insert)
1352 memmove(tp->lb + sp->cno + spaces,
1353 tp->lb + sp->cno, tp->insert);
1355 /* Add new space characters. */
1356 for (; spaces--; ++tp->len, ++tp->ai)
1357 tp->lb[sp->cno++] = ' ';
1358 return (0);
1362 * txt_resolve --
1363 * Resolve the input text chain into the file.
1365 static int
1366 txt_resolve(sp, ep, tiqh)
1367 SCR *sp;
1368 EXF *ep;
1369 TEXTH *tiqh;
1371 TEXT *tp;
1372 recno_t lno;
1374 /* The first line replaces a current line. */
1375 tp = tiqh->cqh_first;
1376 if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
1377 return (1);
1379 /* All subsequent lines are appended into the file. */
1380 for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
1381 if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
1382 return (1);
1383 return (0);
1387 * txt_showmatch --
1388 * Show a character match.
1390 * !!!
1391 * Historic vi tried to display matches even in the :colon command line.
1392 * I think not.
1394 static void
1395 txt_showmatch(sp, ep)
1396 SCR *sp;
1397 EXF *ep;
1399 struct timeval second;
1400 VCS cs;
1401 MARK m;
1402 fd_set zero;
1403 int cnt, endc, startc;
1406 * Do a refresh first, in case the v_ntext() code hasn't done
1407 * one in awhile, so the user can see what we're complaining
1408 * about.
1410 if (sp->s_refresh(sp, ep))
1411 return;
1413 * We don't display the match if it's not on the screen. Find
1414 * out what the first character on the screen is.
1416 if (sp->s_position(sp, ep, &m, 0, P_TOP))
1417 return;
1419 /* Initialize the getc() interface. */
1420 cs.cs_lno = sp->lno;
1421 cs.cs_cno = sp->cno - 1;
1422 if (cs_init(sp, ep, &cs))
1423 return;
1424 startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
1426 /* Search for the match. */
1427 for (cnt = 1;;) {
1428 if (cs_prev(sp, ep, &cs))
1429 return;
1430 if (cs.cs_lno < m.lno ||
1431 cs.cs_lno == m.lno && cs.cs_cno < m.cno)
1432 return;
1433 if (cs.cs_flags != 0) {
1434 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
1435 (void)sp->s_bell(sp);
1436 return;
1438 continue;
1440 if (cs.cs_ch == endc)
1441 ++cnt;
1442 else if (cs.cs_ch == startc && --cnt == 0)
1443 break;
1446 /* Move to the match. */
1447 m.lno = sp->lno;
1448 m.cno = sp->cno;
1449 sp->lno = cs.cs_lno;
1450 sp->cno = cs.cs_cno;
1451 (void)sp->s_refresh(sp, ep);
1454 * Sleep(3) is eight system calls. Do it fast -- besides,
1455 * I don't want to wait an entire second.
1457 FD_ZERO(&zero);
1458 second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
1459 second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
1460 (void)select(0, &zero, &zero, &zero, &second);
1462 /* Return to the current location. */
1463 sp->lno = m.lno;
1464 sp->cno = m.cno;
1465 (void)sp->s_refresh(sp, ep);
1469 * txt_margin --
1470 * Handle margin wrap.
1472 * !!!
1473 * Historic vi belled the user each time a character was entered after
1474 * crossing the margin until a space was entered which could be used to
1475 * break the line. I don't, it tends to wake the cats.
1477 static int
1478 txt_margin(sp, tp, didbreak, pushc)
1479 SCR *sp;
1480 TEXT *tp;
1481 int *didbreak;
1482 ARG_CHAR_T pushc;
1484 CHAR_T ch;
1485 size_t len, off, tlen;
1486 char *p, *wp;
1488 /* Find the closest previous blank. */
1489 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1490 if (isblank(*p)) {
1491 wp = p + 1;
1492 break;
1494 ++len;
1495 /* If it's the beginning of the line, there's nothing to do. */
1496 if (off == tp->ai || off == tp->offset) {
1497 *didbreak = 0;
1498 return (0);
1503 * Historic practice is to delete any trailing whitespace
1504 * from the previous line.
1506 for (tlen = len;; --p, --off) {
1507 if (!isblank(*p))
1508 break;
1509 ++tlen;
1510 if (off == tp->ai || off == tp->offset)
1511 break;
1514 ch = pushc;
1515 if (term_push(sp, sp->gp->key, &ch, 1))
1516 return (1);
1517 if (len && term_push(sp, sp->gp->key, wp, len))
1518 return (1);
1519 ch = '\n';
1520 if (term_push(sp, sp->gp->key, &ch, 1))
1521 return (1);
1523 sp->cno -= tlen;
1524 tp->owrite += tlen;
1525 *didbreak = 1;
1526 return (0);