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