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