update to 1.01
[nvi.git] / vi / v_replace.c
blob35410db564d84320e71149f2f100fa99def579a4
1 /*-
2 * Copyright (c) 1992, 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_replace.c,v 8.12 1993/12/09 19:43:17 bostic Exp $ (Berkeley) $Date: 1993/12/09 19:43:17 $";
10 #endif /* not lint */
12 #include <sys/types.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #include "vi.h"
20 #include "vcmd.h"
23 * v_replace -- [count]rc
24 * The r command in historic vi was almost beautiful in its badness.
25 * For example, "r<erase>" and "r<word erase>" beeped the terminal
26 * and deleted a single character. "Nr<carriage return>", where N
27 * was greater than 1, inserted a single carriage return. This may
28 * not be right, but at least it's not insane.
30 int
31 v_replace(sp, ep, vp, fm, tm, rp)
32 SCR *sp;
33 EXF *ep;
34 VICMDARG *vp;
35 MARK *fm, *tm, *rp;
37 CH ikey;
38 TEXT *tp;
39 recno_t lno;
40 size_t blen, len;
41 u_long cnt;
42 int rval;
43 char *bp, *p;
46 * If the line doesn't exist, or it's empty, replacement isn't
47 * allowed. It's not hard to implement, but:
49 * 1: It's historic practice.
50 * 2: For consistency, this change would require that the more
51 * general case, "Nr", when the user is < N characters from
52 * the end of the line, also work.
53 * 3: Replacing a newline has somewhat odd semantics.
55 if ((p = file_gline(sp, ep, fm->lno, &len)) == NULL) {
56 if (file_lline(sp, ep, &lno))
57 return (1);
58 if (lno != 0) {
59 GETLINE_ERR(sp, fm->lno);
60 return (1);
62 goto nochar;
64 if (len == 0) {
65 nochar: msgq(sp, M_BERR, "No characters to replace");
66 return (1);
70 * Figure out how many characters to be replace; for no particular
71 * reason other than that the semantics of replacing the newline
72 * are confusing, only permit the replacement of the characters in
73 * the current line. I suppose we could simply append the replacement
74 * characters to the line, but I see no compelling reason to do so.
76 cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
77 rp->cno = fm->cno + cnt - 1;
78 if (rp->cno > len - 1) {
79 v_eol(sp, ep, fm);
80 return (1);
83 /* Get the character, literal escapes, escape terminates. */
84 if (F_ISSET(vp, VC_ISDOT)) {
85 ikey.ch = VIP(sp)->rlast;
86 ikey.value = term_key_val(sp, ikey.ch);
87 } else {
88 if (term_key(sp, &ikey, 0) != INP_OK)
89 return (1);
90 switch (ikey.value) {
91 case K_ESCAPE:
92 *rp = *fm;
93 return (0);
94 case K_VLNEXT:
95 if (term_key(sp, &ikey, 0) != INP_OK)
96 return (1);
97 break;
99 VIP(sp)->rlast = ikey.ch;
102 /* Copy the line. */
103 GET_SPACE_RET(sp, bp, blen, len);
104 memmove(bp, p, len);
105 p = bp;
107 if (ikey.value == K_CR || ikey.value == K_NL) {
108 /* Set return line. */
109 rp->lno = fm->lno + cnt;
111 /* The first part of the current line. */
112 if (file_sline(sp, ep, fm->lno, p, fm->cno))
113 goto err_ret;
116 * The rest of the current line. And, of course, now it gets
117 * tricky. Any white space after the replaced character is
118 * stripped, and autoindent is applied. Put the cursor on the
119 * last indent character as did historic vi.
121 for (p += fm->cno + cnt, len -= fm->cno + cnt;
122 len && isblank(*p); --len, ++p);
124 if ((tp = text_init(sp, p, len, len)) == NULL)
125 goto err_ret;
126 if (txt_auto(sp, ep, fm->lno, NULL, 0, tp))
127 goto err_ret;
128 rp->cno = tp->ai ? tp->ai - 1 : 0;
129 if (file_aline(sp, ep, 1, fm->lno, tp->lb, tp->len))
130 goto err_ret;
131 text_free(tp);
133 rval = 0;
135 /* All of the middle lines. */
136 while (--cnt)
137 if (file_aline(sp, ep, 1, fm->lno, "", 0)) {
138 err_ret: rval = 1;
139 break;
141 } else {
142 memset(bp + fm->cno, ikey.ch, cnt);
143 rval = file_sline(sp, ep, fm->lno, bp, len);
145 rp->lno = fm->lno;
146 rp->cno = fm->cno + cnt - 1;
148 FREE_SPACE(sp, bp, blen);
149 return (rval);