sub.c revision 1.5 1 /* $NetBSD: sub.c,v 1.5 1997/07/20 06:35:41 thorpej Exp $ */
2
3 /* sub.c: This file contains the substitution routines for the ed
4 line editor */
5 /*-
6 * Copyright (c) 1993 Andrew Moore, Talke Studio.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 #ifndef lint
33 #if 0
34 static char *rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp";
35 #else
36 __RCSID("$NetBSD: sub.c,v 1.5 1997/07/20 06:35:41 thorpej Exp $");
37 #endif
38 #endif /* not lint */
39
40 #include "ed.h"
41
42
43 char *rhbuf; /* rhs substitution buffer */
44 int rhbufsz; /* rhs substitution buffer size */
45 int rhbufi; /* rhs substitution buffer index */
46
47 /* extract_subst_tail: extract substitution tail from the command buffer */
48 int
49 extract_subst_tail(flagp, np)
50 int *flagp;
51 long *np;
52 {
53 char delimiter;
54
55 *flagp = *np = 0;
56 if ((delimiter = *ibufp) == '\n') {
57 rhbufi = 0;
58 *flagp = GPR;
59 return 0;
60 } else if (extract_subst_template() == NULL)
61 return ERR;
62 else if (*ibufp == '\n') {
63 *flagp = GPR;
64 return 0;
65 } else if (*ibufp == delimiter)
66 ibufp++;
67 if ('1' <= *ibufp && *ibufp <= '9') {
68 STRTOL(*np, ibufp);
69 return 0;
70 } else if (*ibufp == 'g') {
71 ibufp++;
72 *flagp = GSG;
73 return 0;
74 }
75 return 0;
76 }
77
78
79 /* extract_subst_template: return pointer to copy of substitution template
80 in the command buffer */
81 char *
82 extract_subst_template()
83 {
84 int n = 0;
85 int i = 0;
86 char c;
87 char delimiter = *ibufp++;
88
89 if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
90 ibufp++;
91 if (!rhbuf) sprintf(errmsg, "no previous substitution");
92 return rhbuf;
93 }
94 while (*ibufp != delimiter) {
95 REALLOC(rhbuf, rhbufsz, i + 2, NULL);
96 if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
97 i--, ibufp--;
98 break;
99 } else if (c != '\\')
100 ;
101 else if ((rhbuf[i++] = *ibufp++) != '\n')
102 ;
103 else if (!isglobal) {
104 while ((n = get_tty_line()) == 0 ||
105 (n > 0 && ibuf[n - 1] != '\n'))
106 clearerr(stdin);
107 if (n < 0)
108 return NULL;
109 }
110 }
111 REALLOC(rhbuf, rhbufsz, i + 1, NULL);
112 rhbuf[rhbufi = i] = '\0';
113 return rhbuf;
114 }
115
116
117 char *rbuf; /* substitute_matching_text buffer */
118 int rbufsz; /* substitute_matching_text buffer size */
119
120 /* search_and_replace: for each line in a range, change text matching a pattern
121 according to a substitution template; return status */
122 int
123 search_and_replace(pat, gflag, kth)
124 pattern_t *pat;
125 int gflag;
126 int kth;
127 {
128 undo_t *up;
129 char *txt;
130 char *eot;
131 long lc;
132 long xa = current_addr;
133 int nsubs = 0;
134 line_t *lp;
135 int len;
136
137 current_addr = first_addr - 1;
138 for (lc = 0; lc <= second_addr - first_addr; lc++) {
139 lp = get_addressed_line_node(++current_addr);
140 if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
141 return ERR;
142 else if (len) {
143 up = NULL;
144 if (delete_lines(current_addr, current_addr) < 0)
145 return ERR;
146 txt = rbuf;
147 eot = rbuf + len;
148 SPL1();
149 do {
150 if ((txt = put_sbuf_line(txt)) == NULL) {
151 SPL0();
152 return ERR;
153 } else if (up)
154 up->t = get_addressed_line_node(current_addr);
155 else if ((up = push_undo_stack(UADD,
156 current_addr, current_addr)) == NULL) {
157 SPL0();
158 return ERR;
159 }
160 } while (txt != eot);
161 SPL0();
162 nsubs++;
163 xa = current_addr;
164 }
165 }
166 current_addr = xa;
167 if (nsubs == 0 && !(gflag & GLB)) {
168 sprintf(errmsg, "no match");
169 return ERR;
170 } else if ((gflag & (GPR | GLS | GNP)) &&
171 display_lines(current_addr, current_addr, gflag) < 0)
172 return ERR;
173 return 0;
174 }
175
176
177 /* substitute_matching_text: replace text matched by a pattern according to
178 a substitution template; return pointer to the modified text */
179 int
180 substitute_matching_text(pat, lp, gflag, kth)
181 pattern_t *pat;
182 line_t *lp;
183 int gflag;
184 int kth;
185 {
186 int off = 0;
187 int changed = 0;
188 int matchno = 0;
189 int i = 0;
190 regmatch_t rm[SE_MAX];
191 char *txt;
192 char *eot;
193
194 if ((txt = get_sbuf_line(lp)) == NULL)
195 return ERR;
196 if (isbinary)
197 NUL_TO_NEWLINE(txt, lp->len);
198 eot = txt + lp->len;
199 if (!regexec(pat, txt, SE_MAX, rm, 0)) {
200 do {
201 if (!kth || kth == ++matchno) {
202 changed++;
203 i = rm[0].rm_so;
204 REALLOC(rbuf, rbufsz, off + i, ERR);
205 if (isbinary)
206 NEWLINE_TO_NUL(txt, rm[0].rm_eo);
207 memcpy(rbuf + off, txt, i);
208 off += i;
209 if ((off = apply_subst_template(txt, rm, off,
210 pat->re_nsub)) < 0)
211 return ERR;
212 } else {
213 i = rm[0].rm_eo;
214 REALLOC(rbuf, rbufsz, off + i, ERR);
215 if (isbinary)
216 NEWLINE_TO_NUL(txt, i);
217 memcpy(rbuf + off, txt, i);
218 off += i;
219 }
220 txt += rm[0].rm_eo;
221 } while (*txt && (!changed || ((gflag & GSG) && rm[0].rm_eo))
222 && !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
223 i = eot - txt;
224 REALLOC(rbuf, rbufsz, off + i + 2, ERR);
225 if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
226 sprintf(errmsg, "infinite substitution loop");
227 return ERR;
228 }
229 if (isbinary)
230 NEWLINE_TO_NUL(txt, i);
231 memcpy(rbuf + off, txt, i);
232 memcpy(rbuf + off + i, "\n", 2);
233 }
234 return changed ? off + i + 1 : 0;
235 }
236
237
238 /* apply_subst_template: modify text according to a substitution template;
239 return offset to end of modified text */
240 int
241 apply_subst_template(boln, rm, off, re_nsub)
242 char *boln;
243 regmatch_t *rm;
244 int off;
245 int re_nsub;
246 {
247 int j = 0;
248 int k = 0;
249 int n;
250 char *sub = rhbuf;
251
252 for (; sub - rhbuf < rhbufi; sub++)
253 if (*sub == '&') {
254 j = rm[0].rm_so;
255 k = rm[0].rm_eo;
256 REALLOC(rbuf, rbufsz, off + k - j, ERR);
257 while (j < k)
258 rbuf[off++] = boln[j++];
259 } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
260 (n = *sub - '0') <= re_nsub) {
261 j = rm[n].rm_so;
262 k = rm[n].rm_eo;
263 REALLOC(rbuf, rbufsz, off + k - j, ERR);
264 while (j < k)
265 rbuf[off++] = boln[j++];
266 } else {
267 REALLOC(rbuf, rbufsz, off + 1, ERR);
268 rbuf[off++] = *sub;
269 }
270 REALLOC(rbuf, rbufsz, off + 1, ERR);
271 rbuf[off] = '\0';
272 return off;
273 }
274