bug, wrong value to getcount for 'z' command
[nvi.git] / vi / v_txt.c
blobdc8566cec82c953727a7515ff01f6e3d844e62a8
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.62 1993/11/30 09:28:57 bostic Exp $ (Berkeley) $Date: 1993/11/30 09:28:57 $";
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 CH ikey; /* Input character structure. */
91 CHAR_T ch; /* Input character. */
92 GS *gp; /* Global pointer. */
93 TEXT *tp, *ntp, ait; /* Input and autoindent text structures. */
94 size_t rcol; /* 0-N: insert offset in the replay buffer. */
95 size_t col; /* Current column. */
96 u_long margin; /* Wrapmargin value. */
97 u_int iflags; /* Input flags. */
98 int ab_cnt; /* Abbreviation count. */
99 int eval; /* Routine return value. */
100 int replay; /* If replaying a set of input. */
101 int showmatch; /* Showmatch set on this character. */
102 int testnr; /* Test first character for nul replay. */
103 int max, tmp;
104 char *p;
107 * Set the input flag, so tabs get displayed correctly
108 * and everyone knows that the text buffer is in use.
110 F_SET(sp, S_INPUT);
112 /* Set return value. */
113 eval = 0;
116 * Get one TEXT structure with some initial buffer space, reusing
117 * the last one if it's big enough. (All TEXT bookkeeping fields
118 * default to 0 -- text_init() handles this.) If changing a line,
119 * copy it into the TEXT buffer.
121 if (tiqh->cqh_first != (void *)tiqh) {
122 tp = tiqh->cqh_first;
123 if (tp->q.cqe_next != (void *)tiqh || tp->lb_len < len + 32) {
124 text_lfree(tiqh);
125 goto newtp;
127 tp->ai = tp->insert = tp->offset = tp->owrite = 0;
128 if (lp != NULL) {
129 tp->len = len;
130 memmove(tp->lb, lp, len);
131 } else
132 tp->len = 0;
133 } else {
134 newtp: if ((tp = text_init(sp, lp, len, len + 32)) == NULL)
135 return (1);
136 CIRCLEQ_INSERT_HEAD(tiqh, tp, q);
139 /* Set the starting line number. */
140 tp->lno = sp->lno;
143 * Set the insert and overwrite counts. If overwriting characters,
144 * do insertion afterward. If not overwriting characters, assume
145 * doing insertion. If change is to a mark, emphasize it with an
146 * END_CH.
148 if (len) {
149 if (LF_ISSET(TXT_OVERWRITE)) {
150 tp->owrite = tm->cno - sp->cno;
151 tp->insert = len - tm->cno;
152 } else
153 tp->insert = len - sp->cno;
155 if (LF_ISSET(TXT_EMARK))
156 tp->lb[tm->cno - 1] = END_CH;
160 * Many of the special cases in this routine are to handle autoindent
161 * support. Somebody decided that it would be a good idea if "^^D"
162 * and "0^D" deleted all of the autoindented characters. In an editor
163 * that takes single character input from the user, this wasn't a very
164 * good idea. Note also that "^^D" resets the next lines' autoindent,
165 * but "0^D" doesn't.
167 * We assume that autoindent only happens on empty lines, so insert
168 * and overwrite will be zero. If doing autoindent, figure out how
169 * much indentation we need and fill it in. Update input column and
170 * screen cursor as necessary.
172 if (LF_ISSET(TXT_AUTOINDENT) && ai_line != OOBLNO) {
173 if (txt_auto(sp, ep, ai_line, NULL, 0, tp))
174 return (1);
175 sp->cno = tp->ai;
176 } else {
178 * The cc and S commands have a special feature -- leading
179 * <blank> characters are handled as autoindent characters.
180 * Beauty!
182 if (LF_ISSET(TXT_AICHARS)) {
183 tp->offset = 0;
184 tp->ai = sp->cno;
185 } else
186 tp->offset = sp->cno;
189 /* If getting a command buffer from the user, there may be a prompt. */
190 if (LF_ISSET(TXT_PROMPT)) {
191 tp->lb[sp->cno++] = prompt;
192 ++tp->len;
193 ++tp->offset;
197 * If appending after the end-of-line, add a space into the buffer
198 * and move the cursor right. This space is inserted, i.e. pushed
199 * along, and then deleted when the line is resolved. Assumes that
200 * the cursor is already positioned at the end of the line. This
201 * avoids the nastiness of having the cursor reside on a magical
202 * column, i.e. a column that doesn't really exist. The only down
203 * side is that we may wrap lines or scroll the screen before it's
204 * strictly necessary. Not a big deal.
206 if (LF_ISSET(TXT_APPENDEOL)) {
207 tp->lb[sp->cno] = CURSOR_CH;
208 ++tp->len;
209 ++tp->insert;
213 * Historic practice is that the wrapmargin value was a distance
214 * from the RIGHT-HAND column, not the left. It's more useful to
215 * us as a distance from the left-hand column.
217 * XXX
218 * Setting margin causes a significant performance hit. Normally
219 * we don't update the screen if there are keys waiting, but we
220 * have to if margin is set, otherwise the screen routines don't
221 * know where the cursor is.
223 if (!LF_ISSET(TXT_WRAPMARGIN))
224 margin = 0;
225 else if ((margin = O_VAL(sp, O_WRAPMARGIN)) != 0)
226 margin = sp->cols - margin;
228 /* Initialize abbreviations checks. */
229 if (F_ISSET(sp, S_ABBREV) && LF_ISSET(TXT_MAPINPUT)) {
230 abb = A_NOTSPACE;
231 ab_cnt = 0;
232 } else
233 abb = A_NOTSET;
236 * Set up the dot command. Dot commands are done by saving the
237 * actual characters and replaying the input. We have to push
238 * the characters onto the key stack and then handle them normally,
239 * otherwise things like wrapmargin will fail.
241 * XXX
242 * It would be nice if we could swallow backspaces and such, but
243 * it's not all that easy to do. Another possibility would be to
244 * recognize full line insertions, which could be performed quickly,
245 * without replay.
247 nullreplay:
248 rcol = 0;
249 if (replay = LF_ISSET(TXT_REPLAY)) {
251 * !!!
252 * Historically, it wasn't an error to replay non-existent
253 * input. This test is necessary, we get here by the user
254 * doing an input command followed by a nul.
256 * !!!
257 * Historically, vi did not remap or reabbreviate replayed
258 * input. It did, however, beep at you if you changed an
259 * abbreviation and then replayed the input. We're not that
260 * compatible.
262 if (VIP(sp)->rep == NULL)
263 return (0);
264 if (term_push(sp, VIP(sp)->rep, VIP(sp)->rep_cnt, 0, CH_NOMAP))
265 return (1);
266 testnr = 0;
267 abb = A_NOTSET;
268 LF_CLR(TXT_RECORD);
269 } else
270 testnr = 1;
272 iflags = LF_ISSET(TXT_MAPCOMMAND | TXT_MAPINPUT);
273 for (gp = sp->gp, showmatch = 0,
274 carat_st = C_NOTSET, hex = H_NOTSET, quoted = Q_NOTSET;;) {
276 * Reset the line and update the screen. (The txt_showmatch()
277 * code refreshes the screen for us.) Don't refresh unless
278 * we're about to wait on a character or we need to know where
279 * the cursor really is.
281 if (showmatch || margin || !KEYS_WAITING(sp)) {
282 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
283 goto err;
284 if (showmatch) {
285 showmatch = 0;
286 txt_showmatch(sp, ep);
287 } else if (sp->s_refresh(sp, ep))
288 goto err;
291 /* Get the next character. */
292 next_ch: if (term_key(sp, &ikey, iflags) != INP_OK)
293 goto err;
294 ch = ikey.ch;
296 /* Abbreviation check. See comment in txt_abbrev(). */
297 #define MAX_ABBREVIATION_EXPANSION 256
298 if (ikey.flags & CH_ABBREVIATED) {
299 if (++ab_cnt > MAX_ABBREVIATION_EXPANSION) {
300 term_ab_flush(sp,
301 "Abbreviation exceeded maximum number of characters");
302 ab_cnt = 0;
303 continue;
305 } else
306 ab_cnt = 0;
309 * !!!
310 * Historic feature. If the first character of the input is
311 * a nul, replay the previous input. This isn't documented
312 * anywhere, and is a great test of vi clones.
314 if (ch == '\0' && testnr) {
315 LF_SET(TXT_REPLAY);
316 goto nullreplay;
318 testnr = 0;
321 * Check to see if the character fits into the input (and
322 * replay, if necessary) buffers. It isn't necessary to
323 * have tp->len bytes, since it doesn't consider overwrite
324 * characters, but not worth fixing.
326 if (LF_ISSET(TXT_RECORD)) {
327 TBINC(sp, VIP(sp)->rep, VIP(sp)->rep_len, rcol + 1);
328 VIP(sp)->rep[rcol++] = ch;
330 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
333 * If the character was quoted, replace the last character
334 * (the literal mark) with the new character. If quoted
335 * by someone else, simply insert the character.
337 * !!!
338 * Extension -- if the quoted character is HEX_CH, enter hex
339 * mode. If the user enters "<HEX_CH>[isxdigit()]*" we will
340 * try to use the value as a character. Anything else resets
341 * hex mode.
343 if (ikey.flags & CH_QUOTED)
344 goto ins_ch;
345 if (quoted == Q_THISCHAR) {
346 --sp->cno;
347 ++tp->owrite;
348 quoted = Q_NOTSET;
350 if (ch == HEX_CH)
351 hex = H_NEXTCHAR;
352 goto ins_ch;
355 switch (ikey.value) {
356 case K_CR:
357 case K_NL: /* New line. */
358 #define LINE_RESOLVE { \
359 /* \
360 * Handle abbreviations. If there was one, \
361 * discard the replay characters. \
362 */ \
363 if (abb == A_NOTSPACE && !replay) { \
364 if (txt_abbrev(sp, tp, &tmp, ch)) \
365 goto err; \
366 if (tmp) { \
367 if (LF_ISSET(TXT_RECORD)) \
368 rcol -= tmp; \
369 goto next_ch; \
372 if (abb != A_NOTSET) \
373 abb = A_SPACE; \
374 /* Handle hex numbers. */ \
375 if (hex == H_INHEX) { \
376 if (txt_hex(sp, tp, &tmp, ch)) \
377 goto err; \
378 if (tmp) { \
379 hex = H_NOTSET; \
380 goto next_ch; \
383 /* \
384 * The 'R' command returns any overwriteable \
385 * characters in the first line to the original \
386 * characters.
387 */ \
388 if (LF_ISSET(TXT_REPLACE) && tp->owrite && \
389 tp == tiqh->cqh_first) { \
390 memmove(tp->lb + sp->cno, \
391 lp + sp->cno, tp->owrite); \
392 tp->insert += tp->owrite; \
393 tp->owrite = 0; \
395 /* Delete any appended cursor. */ \
396 if (LF_ISSET(TXT_APPENDEOL)) { \
397 --tp->len; \
398 --tp->insert; \
401 LINE_RESOLVE;
403 /* CR returns from the vi command line. */
404 if (LF_ISSET(TXT_CR)) {
405 if (F_ISSET(sp, S_SCRIPT))
406 (void)term_push(sp,
407 "\r", 1, 0, CH_NOMAP);
408 goto k_escape;
412 * Historic practice was to delete any <blank>
413 * characters following the inserted newline.
414 * This affects the 'R', 'c', and 's' commands.
416 for (p = tp->lb + sp->cno + tp->owrite;
417 tp->insert && isblank(*p);
418 ++p, ++tp->owrite, --tp->insert);
421 * Move any remaining insert characters into
422 * a new TEXT structure.
424 if ((ntp = text_init(sp,
425 tp->lb + sp->cno + tp->owrite,
426 tp->insert, tp->insert + 32)) == NULL)
427 goto err;
428 CIRCLEQ_INSERT_TAIL(tiqh, ntp, q);
430 /* Set bookkeeping for the new line. */
431 ntp->lno = tp->lno + 1;
432 ntp->insert = tp->insert;
435 * Note if the user inserted any characters on this
436 * line. Done before calling txt_ai_resolve() because
437 * it changes the value of sp->cno without making the
438 * corresponding changes to tp->ai.
440 tmp = sp->cno <= tp->ai;
443 * Resolve autoindented characters for the old line.
444 * Reset the autoindent line value. 0^D keeps the ai
445 * line from changing, ^D changes the level, even if
446 * there are no characters in the old line. Note,
447 * if using the current tp structure, use the cursor
448 * as the length, the user may have erased autoindent
449 * characters.
451 if (LF_ISSET(TXT_AUTOINDENT)) {
452 txt_ai_resolve(sp, tp);
454 if (carat_st == C_NOCHANGE) {
455 if (txt_auto(sp, ep,
456 OOBLNO, &ait, ait.ai, ntp))
457 goto err;
458 FREE_SPACE(sp, ait.lb, ait.lb_len);
459 } else
460 if (txt_auto(sp, ep,
461 OOBLNO, tp, sp->cno, ntp))
462 goto err;
463 carat_st = C_NOTSET;
467 * If the user hasn't entered any characters, delete
468 * any autoindent characters.
470 * !!!
471 * Historic vi didn't get the insert test right, if
472 * there were characters after the cursor, entering
473 * a <cr> left the autoindent characters on the line.
475 if (tmp)
476 sp->cno = 0;
478 /* Reset bookkeeping for the old line. */
479 tp->len = sp->cno;
480 tp->ai = tp->insert = tp->owrite = 0;
482 /* New cursor position. */
483 sp->cno = ntp->ai;
485 /* New lines are TXT_APPENDEOL if nothing to insert. */
486 if (ntp->insert == 0) {
487 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
488 LF_SET(TXT_APPENDEOL);
489 ntp->lb[sp->cno] = CURSOR_CH;
490 ++ntp->insert;
491 ++ntp->len;
494 /* Update the old line. */
495 if (sp->s_change(sp, ep, tp->lno, LINE_RESET))
496 goto err;
498 /* Swap old and new TEXT's. */
499 tp = ntp;
501 /* Reset the cursor. */
502 sp->lno = tp->lno;
504 /* Update the new line. */
505 if (sp->s_change(sp, ep, tp->lno, LINE_INSERT))
506 goto err;
508 /* Set the renumber bit. */
509 F_SET(sp, S_RENUMBER);
511 /* Refresh if nothing waiting. */
512 if ((margin || !KEYS_WAITING(sp)) &&
513 sp->s_refresh(sp, ep))
514 goto err;
515 goto next_ch;
516 case K_ESCAPE: /* Escape. */
517 if (!LF_ISSET(TXT_ESCAPE))
518 goto ins_ch;
520 LINE_RESOLVE;
523 * If there aren't any trailing characters in the line
524 * and the user hasn't entered any characters, delete
525 * the autoindent characters.
527 if (!tp->insert && sp->cno <= tp->ai) {
528 tp->len = tp->owrite = 0;
529 sp->cno = 0;
530 } else if (LF_ISSET(TXT_AUTOINDENT))
531 txt_ai_resolve(sp, tp);
533 /* If there are insert characters, copy them down. */
534 k_escape: if (tp->insert && tp->owrite)
535 memmove(tp->lb + sp->cno,
536 tp->lb + sp->cno + tp->owrite, tp->insert);
537 tp->len -= tp->owrite;
540 * Delete any lines that were inserted into the text
541 * structure and then erased.
543 while (tp->q.cqe_next != (void *)tiqh) {
544 ntp = tp->q.cqe_next;
545 CIRCLEQ_REMOVE(tiqh, ntp, q);
546 text_free(ntp);
550 * If not resolving the lines into the file, end
551 * it with a nul.
553 * XXX
554 * This is wrong, should pass back a length.
556 if (LF_ISSET(TXT_RESOLVE)) {
557 if (txt_resolve(sp, ep, tiqh))
558 goto err;
559 } else {
560 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
561 tp->lb[tp->len] = '\0';
565 * Set the return cursor position to rest on the last
566 * inserted character.
568 if (rp != NULL) {
569 rp->lno = tp->lno;
570 rp->cno = sp->cno ? sp->cno - 1 : 0;
571 if (sp->s_change(sp, ep, rp->lno, LINE_RESET))
572 goto err;
574 goto ret;
575 case K_CARAT: /* Delete autoindent chars. */
576 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
577 carat_st = C_CARATSET;
578 goto ins_ch;
579 case K_ZERO: /* Delete autoindent chars. */
580 if (LF_ISSET(TXT_AUTOINDENT) && sp->cno <= tp->ai)
581 carat_st = C_ZEROSET;
582 goto ins_ch;
583 case K_VEOF: /* Delete autoindent char. */
585 * If not doing autoindent, in the first column, no
586 * characters to erase, or already inserted non-ai
587 * characters, it's a literal. The last test is done
588 * in the switch, as the CARAT forms are N + 1, not N.
590 if (!LF_ISSET(TXT_AUTOINDENT) ||
591 sp->cno == 0 || tp->ai == 0)
592 goto ins_ch;
593 switch (carat_st) {
594 case C_CARATSET: /* ^^D */
595 if (sp->cno > tp->ai + tp->offset + 1)
596 goto ins_ch;
598 /* Save the ai string for later. */
599 ait.lb = NULL;
600 ait.lb_len = 0;
601 TBINC(sp, ait.lb, ait.lb_len, tp->ai);
602 memmove(ait.lb, tp->lb, tp->ai);
603 ait.ai = ait.len = tp->ai;
605 carat_st = C_NOCHANGE;
606 goto leftmargin;
607 case C_ZEROSET: /* 0^D */
608 if (sp->cno > tp->ai + tp->offset + 1)
609 goto ins_ch;
610 carat_st = C_NOTSET;
611 leftmargin: tp->lb[sp->cno - 1] = ' ';
612 tp->owrite += sp->cno - tp->offset;
613 tp->ai = 0;
614 sp->cno = tp->offset;
615 break;
616 case C_NOTSET: /* ^D */
617 if (sp->cno > tp->ai + tp->offset)
618 goto ins_ch;
619 (void)txt_outdent(sp, tp);
620 break;
621 default:
622 abort();
624 break;
625 case K_VERASE: /* Erase the last character. */
627 * If can erase over the prompt, return. Len is 0
628 * if backspaced over the prompt, 1 if only CR entered.
630 if (LF_ISSET(TXT_BS) && sp->cno <= tp->offset) {
631 tp->len = 0;
632 goto ret;
636 * If at the beginning of the line, try and drop back
637 * to a previously inserted line.
639 if (sp->cno == 0) {
640 if ((ntp = txt_backup(sp,
641 ep, tiqh, tp, flags)) == NULL)
642 goto err;
643 tp = ntp;
644 break;
647 /* If nothing to erase, bell the user. */
648 if (sp->cno <= tp->offset) {
649 msgq(sp, M_BERR,
650 "No more characters to erase.");
651 break;
654 /* Drop back one character. */
655 --sp->cno;
658 * Increment overwrite, decrement ai if deleted.
660 * !!!
661 * Historic vi did not permit users to use erase
662 * characters to delete autoindent characters.
664 ++tp->owrite;
665 if (sp->cno < tp->ai)
666 --tp->ai;
667 break;
668 case K_VWERASE: /* Skip back one word. */
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;
681 * If at offset, nothing to erase so bell the user.
683 if (sp->cno <= tp->offset) {
684 msgq(sp, M_BERR,
685 "No more characters to erase.");
686 break;
690 * First werase goes back to any autoindent
691 * and second werase goes back to the offset.
693 * !!!
694 * Historic vi did not permit users to use erase
695 * characters to delete autoindent characters.
697 if (tp->ai && sp->cno > tp->ai)
698 max = tp->ai;
699 else {
700 tp->ai = 0;
701 max = tp->offset;
704 /* Skip over trailing space characters. */
705 while (sp->cno > max && isblank(tp->lb[sp->cno - 1])) {
706 --sp->cno;
707 ++tp->owrite;
709 if (sp->cno == max)
710 break;
712 * There are three types of word erase found on UNIX
713 * systems. They can be identified by how the string
714 * /a/b/c is treated -- as 1, 3, or 6 words. Historic
715 * vi had two classes of characters, and strings were
716 * delimited by them and <blank>'s, so, 6 words. The
717 * historic tty interface used <blank>'s to delimit
718 * strings, so, 1 word. The algorithm offered in the
719 * 4.4BSD tty interface (as stty altwerase) treats it
720 * as 3 words -- there are two classes of characters,
721 * and strings are delimited by them and <blank>'s.
722 * The difference is that the type of the first erased
723 * character erased is ignored, which is exactly right
724 * when erasing pathname components. Here, the options
725 * TXT_ALTWERASE and TXT_TTYWERASE specify the 4.4BSD
726 * tty interface and the historic tty driver behavior,
727 * respectively, and the default is the same as the
728 * historic vi behavior.
730 if (LF_ISSET(TXT_TTYWERASE))
731 while (sp->cno > max) {
732 --sp->cno;
733 ++tp->owrite;
734 if (isblank(tp->lb[sp->cno - 1]))
735 break;
737 else {
738 if (LF_ISSET(TXT_ALTWERASE)) {
739 --sp->cno;
740 ++tp->owrite;
741 if (isblank(tp->lb[sp->cno - 1]))
742 break;
744 if (sp->cno > max)
745 tmp = inword(tp->lb[sp->cno - 1]);
746 while (sp->cno > max) {
747 --sp->cno;
748 ++tp->owrite;
749 if (tmp != inword(tp->lb[sp->cno - 1])
750 || isblank(tp->lb[sp->cno - 1]))
751 break;
754 break;
755 case K_VKILL: /* Restart this line. */
757 * If at the beginning of the line, try and drop back
758 * to a previously inserted line.
760 if (sp->cno == 0) {
761 if ((ntp = txt_backup(sp,
762 ep, tiqh, tp, flags)) == NULL)
763 goto err;
764 tp = ntp;
767 /* If at offset, nothing to erase so bell the user. */
768 if (sp->cno <= tp->offset) {
769 msgq(sp, M_BERR,
770 "No more characters to erase.");
771 break;
775 * First kill goes back to any autoindent
776 * and second kill goes back to the offset.
778 * !!!
779 * Historic vi did not permit users to use erase
780 * characters to delete autoindent characters.
782 if (tp->ai && sp->cno > tp->ai)
783 max = tp->ai;
784 else {
785 tp->ai = 0;
786 max = tp->offset;
788 tp->owrite += sp->cno - max;
789 sp->cno = max;
790 break;
791 case K_CNTRLT: /* Add autoindent char. */
792 if (!LF_ISSET(TXT_CNTRLT))
793 goto ins_ch;
794 if (txt_indent(sp, tp))
795 goto err;
796 goto ebuf_chk;
797 case K_CNTRLZ:
798 (void)sp->s_suspend(sp);
799 break;
800 #ifdef HISTORIC_PRACTICE_IS_TO_INSERT_NOT_REPAINT
801 case K_FORMFEED:
802 F_SET(sp, S_REFRESH);
803 break;
804 #endif
805 case K_RIGHTBRACE:
806 case K_RIGHTPAREN:
807 showmatch = LF_ISSET(TXT_SHOWMATCH);
808 goto ins_ch;
809 case K_VLNEXT: /* Quote the next character. */
810 /* If in hex mode, see if we've entered a hex value. */
811 if (hex == H_INHEX) {
812 if (txt_hex(sp, tp, &tmp, ch))
813 goto err;
814 if (tmp) {
815 hex = H_NOTSET;
816 goto next_ch;
819 ch = '^';
820 quoted = Q_NEXTCHAR;
821 /* FALLTHROUGH */
822 default: /* Insert the character. */
823 ins_ch: /*
824 * If entering a space character after a word, check
825 * for abbreviations. If there was one, discard the
826 * replay characters.
828 if (isblank(ch) && abb == A_NOTSPACE && !replay) {
829 if (txt_abbrev(sp, tp, &tmp, ch))
830 goto err;
831 if (tmp) {
832 if (LF_ISSET(TXT_RECORD))
833 rcol -= tmp;
834 goto next_ch;
837 /* If in hex mode, see if we've entered a hex value. */
838 if (hex == H_INHEX && !isxdigit(ch)) {
839 if (txt_hex(sp, tp, &tmp, ch))
840 goto err;
841 if (tmp) {
842 hex = H_NOTSET;
843 goto next_ch;
846 /* Check to see if we've crossed the margin. */
847 if (margin) {
848 if (sp->s_column(sp, ep, &col))
849 goto err;
850 if (col >= margin) {
851 if (txt_margin(sp, tp, &tmp, ch))
852 goto err;
853 if (tmp)
854 goto next_ch;
857 if (abb != A_NOTSET)
858 abb = isblank(ch) ? A_SPACE : A_NOTSPACE;
860 if (tp->owrite) /* Overwrite a character. */
861 --tp->owrite;
862 else if (tp->insert) { /* Insert a character. */
863 ++tp->len;
864 if (tp->insert == 1)
865 tp->lb[sp->cno + 1] = tp->lb[sp->cno];
866 else
867 memmove(tp->lb + sp->cno + 1,
868 tp->lb + sp->cno, tp->insert);
871 tp->lb[sp->cno++] = ch;
874 * If we've reached the end of the buffer, then we
875 * need to switch into insert mode. This happens
876 * when there's a change to a mark and the user puts
877 * in more characters than the length of the motion.
879 ebuf_chk: if (sp->cno >= tp->len) {
880 TBINC(sp, tp->lb, tp->lb_len, tp->len + 1);
881 LF_SET(TXT_APPENDEOL);
882 tp->lb[sp->cno] = CURSOR_CH;
883 ++tp->insert;
884 ++tp->len;
887 if (hex == H_NEXTCHAR)
888 hex = H_INHEX;
889 if (quoted == Q_NEXTCHAR)
890 quoted = Q_THISCHAR;
891 break;
893 #if defined(DEBUG) && 1
894 if (sp->cno + tp->insert + tp->owrite != tp->len)
895 msgq(sp, M_ERR,
896 "len %u != cno: %u ai: %u insert %u overwrite %u",
897 tp->len, sp->cno, tp->ai, tp->insert, tp->owrite);
898 tp->len = sp->cno + tp->insert + tp->owrite;
899 #endif
902 /* Clear input flag. */
903 ret: F_CLR(sp, S_INPUT);
905 if (LF_ISSET(TXT_RECORD))
906 VIP(sp)->rep_cnt = rcol;
907 return (eval);
909 /* Error jump. */
910 err: eval = 1;
911 txt_err(sp, ep, tiqh);
912 goto ret;
916 * txt_abbrev --
917 * Handle abbreviations.
919 static int
920 txt_abbrev(sp, tp, didsubp, pushc)
921 SCR *sp;
922 TEXT *tp;
923 int *didsubp;
924 ARG_CHAR_T pushc;
926 CHAR_T ch;
927 SEQ *qp;
928 size_t len, off;
929 char *p;
931 /* Find the beginning of this "word". */
932 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
933 if (isblank(*p)) {
934 ++p;
935 break;
937 ++len;
938 if (off == tp->ai || off == tp->offset)
939 break;
942 /* Check for any abbreviations. */
943 if ((qp = seq_find(sp, NULL, p, len, SEQ_ABBREV, NULL)) == NULL) {
944 *didsubp = 0;
945 return (0);
949 * Push the abbreviation onto the tty stack. Historically, characters
950 * resulting from an abbreviation expansion were themselves subject to
951 * map expansions, O_SHOWMATCH matching etc. This means the expanded
952 * characters will be re-tested for abbreviations. It's difficult to
953 * know what historic practice in this case was, since abbreviations
954 * were applied to :colon command lines, so entering abbreviations that
955 * looped was tricky, although possible. In addition, obvious loops
956 * didn't work as expected. (The command ':ab a b|ab b c|ab c a' will
957 * silently only implement and/or display the last abbreviation.)
959 * This implementation doesn't recover well from such abbreviations.
960 * The main input loop counts abbreviated characters, and, when it
961 * reaches a limit, discards any abbreviated characters on the queue.
962 * It's difficult to back up to the original position, as the replay
963 * queue would have to be adjusted, and the line state when an initial
964 * abbreviated character was received would have to be saved.
966 ch = pushc;
967 if (term_push(sp, &ch, 1, 0, CH_ABBREVIATED))
968 return (1);
969 if (term_push(sp, qp->output, qp->olen, 0, CH_ABBREVIATED))
970 return (1);
973 * Move the cursor to the start of the abbreviation,
974 * adjust the length.
976 sp->cno -= len;
977 tp->len -= len;
979 /* Copy any insert characters back. */
980 if (tp->insert)
981 memmove(tp->lb + sp->cno + tp->owrite,
982 tp->lb + sp->cno + tp->owrite + len, tp->insert);
985 * We return the length of the abbreviated characters. This is so
986 * the calling routine can replace the replay characters with the
987 * abbreviation. This means that subsequent '.' commands will produce
988 * the same text, regardless of intervening :[un]abbreviate commands.
989 * This is historic practice.
991 *didsubp = len;
992 return (0);
995 /* Offset to next column of stop size. */
996 #define STOP_OFF(c, stop) (stop - (c) % stop)
999 * txt_ai_resolve --
1000 * When a line is resolved by <esc> or <cr>, review autoindent
1001 * characters.
1003 static void
1004 txt_ai_resolve(sp, tp)
1005 SCR *sp;
1006 TEXT *tp;
1008 u_long ts;
1009 int del;
1010 size_t cno, len, new, old, scno, spaces, tab_after_sp, tabs;
1011 char *p;
1014 * If the line is empty, has an offset, or no autoindent
1015 * characters, we're done.
1017 if (!tp->len || tp->offset || !tp->ai)
1018 return;
1021 * The autoindent characters plus any leading <blank> characters
1022 * in the line are resolved into the minimum number of characters.
1023 * Historic practice.
1025 ts = O_VAL(sp, O_TABSTOP);
1027 /* Figure out the last <blank> screen column. */
1028 for (p = tp->lb, scno = 0, len = tp->len,
1029 spaces = tab_after_sp = 0; len-- && isblank(*p); ++p)
1030 if (*p == '\t') {
1031 if (spaces)
1032 tab_after_sp = 1;
1033 scno += STOP_OFF(scno, ts);
1034 } else {
1035 ++spaces;
1036 ++scno;
1040 * If there are no spaces, or no tabs after spaces and less than
1041 * ts spaces, it's already minimal.
1043 if (!spaces || !tab_after_sp && spaces < ts)
1044 return;
1046 /* Count up spaces/tabs needed to get to the target. */
1047 for (cno = 0, tabs = 0; cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1048 cno += STOP_OFF(cno, ts);
1049 spaces = scno - cno;
1052 * Figure out how many characters we're dropping -- if we're not
1053 * dropping any, it's already minimal, we're done.
1055 old = p - tp->lb;
1056 new = spaces + tabs;
1057 if (old == new)
1058 return;
1060 /* Shift the rest of the characters down, adjust the counts. */
1061 del = old - new;
1062 memmove(p - del, p, tp->len - old);
1063 sp->cno -= del;
1064 tp->len -= del;
1066 /* Fill in space/tab characters. */
1067 for (p = tp->lb; tabs--;)
1068 *p++ = '\t';
1069 while (spaces--)
1070 *p++ = ' ';
1074 * txt_auto --
1075 * Handle autoindent. If aitp isn't NULL, use it, otherwise,
1076 * retrieve the line.
1079 txt_auto(sp, ep, lno, aitp, len, tp)
1080 SCR *sp;
1081 EXF *ep;
1082 recno_t lno;
1083 size_t len;
1084 TEXT *aitp, *tp;
1086 size_t nlen;
1087 char *p, *t;
1089 if (aitp == NULL) {
1090 if ((p = t = file_gline(sp, ep, lno, &len)) == NULL)
1091 return (0);
1092 } else
1093 p = t = aitp->lb;
1094 for (nlen = 0; len; ++p) {
1095 if (!isblank(*p))
1096 break;
1097 /* If last character is a space, it counts. */
1098 if (--len == 0) {
1099 ++p;
1100 break;
1104 /* No indentation. */
1105 if (p == t)
1106 return (0);
1108 /* Set count. */
1109 nlen = p - t;
1111 /* Make sure the buffer's big enough. */
1112 BINC(sp, tp->lb, tp->lb_len, tp->len + nlen);
1114 /* Copy the indentation into the new buffer. */
1115 memmove(tp->lb + nlen, tp->lb, tp->len);
1116 memmove(tp->lb, t, nlen);
1117 tp->len += nlen;
1119 /* Return the additional length. */
1120 tp->ai = nlen;
1121 return (0);
1125 * txt_backup --
1126 * Back up to the previously edited line.
1128 static TEXT *
1129 txt_backup(sp, ep, tiqh, tp, flags)
1130 SCR *sp;
1131 EXF *ep;
1132 TEXTH *tiqh;
1133 TEXT *tp;
1134 u_int flags;
1136 TEXT *ntp;
1137 size_t col;
1139 if (tp->q.cqe_prev == (void *)tiqh) {
1140 msgq(sp, M_BERR, "Already at the beginning of the insert");
1141 return (tp);
1144 /* Update the old line on the screen. */
1145 if (sp->s_change(sp, ep, tp->lno, LINE_DELETE))
1146 return (NULL);
1148 /* Get a handle on the previous TEXT structure. */
1149 ntp = tp->q.cqe_prev;
1151 /* Make sure that we can get enough space. */
1152 if (LF_ISSET(TXT_APPENDEOL) && ntp->len + 1 > ntp->lb_len &&
1153 binc(sp, &ntp->lb, &ntp->lb_len, ntp->len + 1))
1154 return (NULL);
1157 * Release current TEXT; now committed to the swap, nothing
1158 * better fail.
1160 CIRCLEQ_REMOVE(tiqh, tp, q);
1161 text_free(tp);
1163 /* Swap TEXT's. */
1164 tp = ntp;
1166 /* Set bookkeeping information. */
1167 col = tp->len;
1168 if (LF_ISSET(TXT_APPENDEOL)) {
1169 tp->lb[col] = CURSOR_CH;
1170 ++tp->insert;
1171 ++tp->len;
1173 sp->lno = tp->lno;
1174 sp->cno = col;
1175 return (tp);
1179 * txt_err --
1180 * Handle an error during input processing.
1182 static void
1183 txt_err(sp, ep, tiqh)
1184 SCR *sp;
1185 EXF *ep;
1186 TEXTH *tiqh;
1188 recno_t lno;
1189 size_t len;
1192 * The problem with input processing is that the cursor is at an
1193 * indeterminate position since some input may have been lost due
1194 * to a malloc error. So, try to go back to the place from which
1195 * the cursor started, knowing that it may no longer be available.
1197 * We depend on at least one line number being set in the text
1198 * chain.
1200 for (lno = tiqh->cqh_first->lno;
1201 file_gline(sp, ep, lno, &len) == NULL && lno > 0; --lno);
1203 sp->lno = lno == 0 ? 1 : lno;
1204 sp->cno = 0;
1206 /* Redraw the screen, just in case. */
1207 F_SET(sp, S_REDRAW);
1211 * txt_hex --
1212 * Let the user insert any character value they want.
1214 * !!!
1215 * This is an extension. The pattern "^Vx[0-9a-fA-F]*" is a way
1216 * for the user to specify a character value which their keyboard
1217 * may not be able to enter.
1219 static int
1220 txt_hex(sp, tp, was_hex, pushc)
1221 SCR *sp;
1222 TEXT *tp;
1223 int *was_hex;
1224 ARG_CHAR_T pushc;
1226 CHAR_T ch, savec;
1227 size_t len, off;
1228 u_long value;
1229 char *p, *wp;
1232 * Null-terminate the string. Since nul isn't a legal hex value,
1233 * this should be okay, and lets us use a local routine, which
1234 * presumably understands the character set, to convert the value.
1236 savec = tp->lb[sp->cno];
1237 tp->lb[sp->cno] = 0;
1239 /* Find the previous HEX_CH. */
1240 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1241 if (*p == HEX_CH) {
1242 wp = p + 1;
1243 break;
1245 ++len;
1246 /* If not on this line, there's nothing to do. */
1247 if (off == tp->ai || off == tp->offset)
1248 goto nothex;
1251 /* If no length, then it wasn't a hex value. */
1252 if (len == 0)
1253 goto nothex;
1255 /* Get the value. */
1256 value = strtol(wp, NULL, 16);
1257 if (value == LONG_MIN || value == LONG_MAX || value > MAX_CHAR_T) {
1258 nothex: tp->lb[sp->cno] = savec;
1259 *was_hex = 0;
1260 return (0);
1263 ch = pushc;
1264 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1265 return (1);
1266 ch = value;
1267 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1268 return (1);
1270 tp->lb[sp->cno] = savec;
1272 /* Move the cursor to the start of the hex value, adjust the length. */
1273 sp->cno -= len + 1;
1274 tp->len -= len + 1;
1276 /* Copy any insert characters back. */
1277 if (tp->insert)
1278 memmove(tp->lb + sp->cno + tp->owrite,
1279 tp->lb + sp->cno + tp->owrite + len + 1, tp->insert);
1281 *was_hex = 1;
1282 return (0);
1286 * Txt_indent and txt_outdent are truly strange. ^T and ^D do movements
1287 * to the next or previous shiftwidth value, i.e. for a 1-based numbering,
1288 * with shiftwidth=3, ^T moves a cursor on the 7th, 8th or 9th column to
1289 * the 10th column, and ^D moves it back.
1291 * !!!
1292 * The ^T and ^D characters in historical vi only had special meaning when
1293 * they were the first characters typed after entering text input mode.
1294 * Since normal erase characters couldn't erase autoindent (in this case
1295 * ^T) characters, this meant that inserting text into previously existing
1296 * text was quite strange, ^T only worked if it was the first keystroke,
1297 * and then it could only be erased by using ^D. This implementation treats
1298 * ^T specially anywhere it occurs in the input, and permits the standard
1299 * erase characters to erase characters inserted using it.
1301 * XXX
1302 * Technically, txt_indent, txt_outdent should part of the screen interface,
1303 * as they require knowledge of the size of a space character on the screen.
1304 * (Not the size of tabs, because tabs are logically composed of spaces.)
1305 * They're left in the text code because they're complicated, not to mention
1306 * the gruesome awareness that if spaces aren't a single column on the screen
1307 * for any language, we're into some serious, ah, for lack of a better word,
1308 * "issues".
1312 * txt_indent --
1313 * Handle ^T indents.
1315 static int
1316 txt_indent(sp, tp)
1317 SCR *sp;
1318 TEXT *tp;
1320 u_long sw, ts;
1321 size_t cno, off, scno, spaces, tabs;
1323 ts = O_VAL(sp, O_TABSTOP);
1324 sw = O_VAL(sp, O_SHIFTWIDTH);
1326 /* Get the current screen column. */
1327 for (off = scno = 0; off < sp->cno; ++off)
1328 if (tp->lb[off] == '\t')
1329 scno += STOP_OFF(scno, ts);
1330 else
1331 ++scno;
1333 /* Count up spaces/tabs needed to get to the target. */
1334 for (cno = scno, scno += STOP_OFF(scno, sw), tabs = 0;
1335 cno + STOP_OFF(cno, ts) <= scno; ++tabs)
1336 cno += STOP_OFF(cno, ts);
1337 spaces = scno - cno;
1339 /* Put space/tab characters in place of any overwrite characters. */
1340 for (; tp->owrite && tabs; --tp->owrite, --tabs, ++tp->ai)
1341 tp->lb[sp->cno++] = '\t';
1342 for (; tp->owrite && spaces; --tp->owrite, --spaces, ++tp->ai)
1343 tp->lb[sp->cno++] = ' ';
1345 if (!tabs && !spaces)
1346 return (0);
1348 /* Make sure there's enough room. */
1349 BINC(sp, tp->lb, tp->lb_len, tp->len + spaces + tabs);
1351 /* Move the insert characters out of the way. */
1352 if (tp->insert)
1353 memmove(tp->lb + sp->cno + spaces + tabs,
1354 tp->lb + sp->cno, tp->insert);
1356 /* Add new space/tab characters. */
1357 for (; tabs--; ++tp->len, ++tp->ai)
1358 tp->lb[sp->cno++] = '\t';
1359 for (; spaces--; ++tp->len, ++tp->ai)
1360 tp->lb[sp->cno++] = ' ';
1361 return (0);
1365 * txt_outdent --
1366 * Handle ^D outdents.
1369 static int
1370 txt_outdent(sp, tp)
1371 SCR *sp;
1372 TEXT *tp;
1374 u_long sw, ts;
1375 size_t cno, off, scno, spaces;
1377 ts = O_VAL(sp, O_TABSTOP);
1378 sw = O_VAL(sp, O_SHIFTWIDTH);
1380 /* Get the current screen column. */
1381 for (off = scno = 0; off < sp->cno; ++off)
1382 if (tp->lb[off] == '\t')
1383 scno += STOP_OFF(scno, ts);
1384 else
1385 ++scno;
1387 /* Get the previous shiftwidth column. */
1388 for (cno = scno; --scno % sw != 0;);
1390 /* Decrement characters until less than or equal to that slot. */
1391 for (; cno > scno; --sp->cno, --tp->ai, ++tp->owrite)
1392 if (tp->lb[--off] == '\t')
1393 cno -= STOP_OFF(cno, ts);
1394 else
1395 --cno;
1397 /* Spaces needed to get to the target. */
1398 spaces = scno - cno;
1400 /* Maybe just a delete. */
1401 if (spaces == 0)
1402 return (0);
1404 /* Make sure there's enough room. */
1405 BINC(sp, tp->lb, tp->lb_len, tp->len + spaces);
1407 /* Use up any overwrite characters. */
1408 for (; tp->owrite && spaces; --spaces, ++tp->ai, --tp->owrite)
1409 tp->lb[sp->cno++] = ' ';
1411 /* Maybe that was enough. */
1412 if (spaces == 0)
1413 return (0);
1415 /* Move the insert characters out of the way. */
1416 if (tp->insert)
1417 memmove(tp->lb + sp->cno + spaces,
1418 tp->lb + sp->cno, tp->insert);
1420 /* Add new space characters. */
1421 for (; spaces--; ++tp->len, ++tp->ai)
1422 tp->lb[sp->cno++] = ' ';
1423 return (0);
1427 * txt_resolve --
1428 * Resolve the input text chain into the file.
1430 static int
1431 txt_resolve(sp, ep, tiqh)
1432 SCR *sp;
1433 EXF *ep;
1434 TEXTH *tiqh;
1436 TEXT *tp;
1437 recno_t lno;
1439 /* The first line replaces a current line. */
1440 tp = tiqh->cqh_first;
1441 if (file_sline(sp, ep, tp->lno, tp->lb, tp->len))
1442 return (1);
1444 /* All subsequent lines are appended into the file. */
1445 for (lno = tp->lno; (tp = tp->q.cqe_next) != (void *)&sp->tiq; ++lno)
1446 if (file_aline(sp, ep, 0, lno, tp->lb, tp->len))
1447 return (1);
1448 return (0);
1452 * txt_showmatch --
1453 * Show a character match.
1455 * !!!
1456 * Historic vi tried to display matches even in the :colon command line.
1457 * I think not.
1459 static void
1460 txt_showmatch(sp, ep)
1461 SCR *sp;
1462 EXF *ep;
1464 struct timeval second;
1465 VCS cs;
1466 MARK m;
1467 fd_set zero;
1468 int cnt, endc, startc;
1471 * Do a refresh first, in case the v_ntext() code hasn't done
1472 * one in awhile, so the user can see what we're complaining
1473 * about.
1475 if (sp->s_refresh(sp, ep))
1476 return;
1478 * We don't display the match if it's not on the screen. Find
1479 * out what the first character on the screen is.
1481 if (sp->s_position(sp, ep, &m, 0, P_TOP))
1482 return;
1484 /* Initialize the getc() interface. */
1485 cs.cs_lno = sp->lno;
1486 cs.cs_cno = sp->cno - 1;
1487 if (cs_init(sp, ep, &cs))
1488 return;
1489 startc = (endc = cs.cs_ch) == ')' ? '(' : '{';
1491 /* Search for the match. */
1492 for (cnt = 1;;) {
1493 if (cs_prev(sp, ep, &cs))
1494 return;
1495 if (cs.cs_lno < m.lno ||
1496 cs.cs_lno == m.lno && cs.cs_cno < m.cno)
1497 return;
1498 if (cs.cs_flags != 0) {
1499 if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) {
1500 (void)sp->s_bell(sp);
1501 return;
1503 continue;
1505 if (cs.cs_ch == endc)
1506 ++cnt;
1507 else if (cs.cs_ch == startc && --cnt == 0)
1508 break;
1511 /* Move to the match. */
1512 m.lno = sp->lno;
1513 m.cno = sp->cno;
1514 sp->lno = cs.cs_lno;
1515 sp->cno = cs.cs_cno;
1516 (void)sp->s_refresh(sp, ep);
1519 * Sleep(3) is eight system calls. Do it fast -- besides,
1520 * I don't want to wait an entire second.
1522 FD_ZERO(&zero);
1523 second.tv_sec = O_VAL(sp, O_MATCHTIME) / 10;
1524 second.tv_usec = (O_VAL(sp, O_MATCHTIME) % 10) * 100000L;
1525 (void)select(0, &zero, &zero, &zero, &second);
1527 /* Return to the current location. */
1528 sp->lno = m.lno;
1529 sp->cno = m.cno;
1530 (void)sp->s_refresh(sp, ep);
1534 * txt_margin --
1535 * Handle margin wrap.
1537 * !!!
1538 * Historic vi belled the user each time a character was entered after
1539 * crossing the margin until a space was entered which could be used to
1540 * break the line. I don't, it tends to wake the cats.
1542 static int
1543 txt_margin(sp, tp, didbreak, pushc)
1544 SCR *sp;
1545 TEXT *tp;
1546 int *didbreak;
1547 ARG_CHAR_T pushc;
1549 CHAR_T ch;
1550 size_t len, off, tlen;
1551 char *p, *wp;
1553 /* Find the closest previous blank. */
1554 for (off = sp->cno - 1, p = tp->lb + off, len = 0;; --p, --off) {
1555 if (isblank(*p)) {
1556 wp = p + 1;
1557 break;
1559 ++len;
1560 /* If it's the beginning of the line, there's nothing to do. */
1561 if (off == tp->ai || off == tp->offset) {
1562 *didbreak = 0;
1563 return (0);
1568 * Historic practice is to delete any trailing whitespace
1569 * from the previous line.
1571 for (tlen = len;; --p, --off) {
1572 if (!isblank(*p))
1573 break;
1574 ++tlen;
1575 if (off == tp->ai || off == tp->offset)
1576 break;
1579 ch = pushc;
1580 if (term_push(sp, &ch, 1, 0, CH_NOMAP | CH_QUOTED))
1581 return (1);
1582 if (len && term_push(sp, wp, len, 0, CH_NOMAP | CH_QUOTED))
1583 return (1);
1584 ch = '\n';
1585 if (term_push(sp, &ch, 1, 0, CH_NOMAP))
1586 return (1);
1588 sp->cno -= tlen;
1589 tp->owrite += tlen;
1590 *didbreak = 1;
1591 return (0);