Deleted Added
full compact
sub.c (22988) sub.c (27963)
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.
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 * $Id$
29 */
30
31#ifndef lint
27 */
28
29#ifndef lint
30#if 0
32static char * const rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp";
31static char * const rcsid = "@(#)sub.c,v 1.1 1994/02/01 00:34:44 alm Exp";
32#else
33static char * const rcsid =
34 "$Id: sub.c,v 1.9 1997/02/22 14:03:19 peter Exp $";
35#endif
33#endif /* not lint */
34
35#include "ed.h"
36
37
38char *rhbuf; /* rhs substitution buffer */
39int rhbufsz; /* rhs substitution buffer size */
40int rhbufi; /* rhs substitution buffer index */
41
42/* extract_subst_tail: extract substitution tail from the command buffer */
43int
44extract_subst_tail(flagp, np)
45 int *flagp;
46 int *np;
47{
48 char delimiter;
49
50 *flagp = *np = 0;
51 if ((delimiter = *ibufp) == '\n') {
52 rhbufi = 0;
53 *flagp = GPR;
54 return 0;
55 } else if (extract_subst_template() == NULL)
56 return ERR;
57 else if (*ibufp == '\n') {
58 *flagp = GPR;
59 return 0;
60 } else if (*ibufp == delimiter)
61 ibufp++;
62 if ('1' <= *ibufp && *ibufp <= '9') {
63 STRTOL(*np, ibufp);
64 return 0;
65 } else if (*ibufp == 'g') {
66 ibufp++;
67 *flagp = GSG;
68 return 0;
69 }
70 return 0;
71}
72
73
74/* extract_subst_template: return pointer to copy of substitution template
75 in the command buffer */
76char *
77extract_subst_template()
78{
79 int n = 0;
80 int i = 0;
81 char c;
82 char delimiter = *ibufp++;
83
84 if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
85 ibufp++;
86 if (!rhbuf) sprintf(errmsg, "no previous substitution");
87 return rhbuf;
88 }
89 while (*ibufp != delimiter) {
90 REALLOC(rhbuf, rhbufsz, i + 2, NULL);
91 if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
92 i--, ibufp--;
93 break;
94 } else if (c != '\\')
95 ;
96 else if ((rhbuf[i++] = *ibufp++) != '\n')
97 ;
98 else if (!isglobal) {
99 while ((n = get_tty_line()) == 0 ||
100 (n > 0 && ibuf[n - 1] != '\n'))
101 clearerr(stdin);
102 if (n < 0)
103 return NULL;
104 }
105 }
106 REALLOC(rhbuf, rhbufsz, i + 1, NULL);
107 rhbuf[rhbufi = i] = '\0';
108 return rhbuf;
109}
110
111
112char *rbuf; /* substitute_matching_text buffer */
113int rbufsz; /* substitute_matching_text buffer size */
114
115/* search_and_replace: for each line in a range, change text matching a pattern
116 according to a substitution template; return status */
117int
118search_and_replace(pat, gflag, kth)
119 pattern_t *pat;
120 int gflag;
121 int kth;
122{
123 undo_t *up;
124 char *txt;
125 char *eot;
126 long lc;
127 long xa = current_addr;
128 int nsubs = 0;
129 line_t *lp;
130 int len;
131
132 current_addr = first_addr - 1;
133 for (lc = 0; lc <= second_addr - first_addr; lc++) {
134 lp = get_addressed_line_node(++current_addr);
135 if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
136 return ERR;
137 else if (len) {
138 up = NULL;
139 if (delete_lines(current_addr, current_addr) < 0)
140 return ERR;
141 txt = rbuf;
142 eot = rbuf + len;
143 SPL1();
144 do {
145 if ((txt = put_sbuf_line(txt)) == NULL) {
146 SPL0();
147 return ERR;
148 } else if (up)
149 up->t = get_addressed_line_node(current_addr);
150 else if ((up = push_undo_stack(UADD,
151 current_addr, current_addr)) == NULL) {
152 SPL0();
153 return ERR;
154 }
155 } while (txt != eot);
156 SPL0();
157 nsubs++;
158 xa = current_addr;
159 }
160 }
161 current_addr = xa;
162 if (nsubs == 0 && !(gflag & GLB)) {
163 sprintf(errmsg, "no match");
164 return ERR;
165 } else if ((gflag & (GPR | GLS | GNP)) &&
166 display_lines(current_addr, current_addr, gflag) < 0)
167 return ERR;
168 return 0;
169}
170
171
172/* substitute_matching_text: replace text matched by a pattern according to
173 a substitution template; return pointer to the modified text */
174int
175substitute_matching_text(pat, lp, gflag, kth)
176 pattern_t *pat;
177 line_t *lp;
178 int gflag;
179 int kth;
180{
181 int off = 0;
182 int changed = 0;
183 int matchno = 0;
184 int i = 0;
185 regmatch_t rm[SE_MAX];
186 char *txt;
187 char *eot;
188
189 if ((txt = get_sbuf_line(lp)) == NULL)
190 return ERR;
191 if (isbinary)
192 NUL_TO_NEWLINE(txt, lp->len);
193 eot = txt + lp->len;
194 if (!regexec(pat, txt, SE_MAX, rm, 0)) {
195 do {
196 if (!kth || kth == ++matchno) {
197 changed++;
198 i = rm[0].rm_so;
199 REALLOC(rbuf, rbufsz, off + i, ERR);
200 if (isbinary)
201 NEWLINE_TO_NUL(txt, rm[0].rm_eo);
202 memcpy(rbuf + off, txt, i);
203 off += i;
204 if ((off = apply_subst_template(txt, rm, off,
205 pat->re_nsub)) < 0)
206 return ERR;
207 } else {
208 i = rm[0].rm_eo;
209 REALLOC(rbuf, rbufsz, off + i, ERR);
210 if (isbinary)
211 NEWLINE_TO_NUL(txt, i);
212 memcpy(rbuf + off, txt, i);
213 off += i;
214 }
215 txt += rm[0].rm_eo;
216 } while (*txt &&
217 (!changed || ((gflag & GSG) && rm[0].rm_eo)) &&
218 !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
219 i = eot - txt;
220 REALLOC(rbuf, rbufsz, off + i + 2, ERR);
221 if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
222 sprintf(errmsg, "infinite substitution loop");
223 return ERR;
224 }
225 if (isbinary)
226 NEWLINE_TO_NUL(txt, i);
227 memcpy(rbuf + off, txt, i);
228 memcpy(rbuf + off + i, "\n", 2);
229 }
230 return changed ? off + i + 1 : 0;
231}
232
233
234/* apply_subst_template: modify text according to a substitution template;
235 return offset to end of modified text */
236int
237apply_subst_template(boln, rm, off, re_nsub)
238 char *boln;
239 regmatch_t *rm;
240 int off;
241 int re_nsub;
242{
243 int j = 0;
244 int k = 0;
245 int n;
246 char *sub = rhbuf;
247
248 for (; sub - rhbuf < rhbufi; sub++)
249 if (*sub == '&') {
250 j = rm[0].rm_so;
251 k = rm[0].rm_eo;
252 REALLOC(rbuf, rbufsz, off + k - j, ERR);
253 while (j < k)
254 rbuf[off++] = boln[j++];
255 } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
256 (n = *sub - '0') <= re_nsub) {
257 j = rm[n].rm_so;
258 k = rm[n].rm_eo;
259 REALLOC(rbuf, rbufsz, off + k - j, ERR);
260 while (j < k)
261 rbuf[off++] = boln[j++];
262 } else {
263 REALLOC(rbuf, rbufsz, off + 1, ERR);
264 rbuf[off++] = *sub;
265 }
266 REALLOC(rbuf, rbufsz, off + 1, ERR);
267 rbuf[off] = '\0';
268 return off;
269}
36#endif /* not lint */
37
38#include "ed.h"
39
40
41char *rhbuf; /* rhs substitution buffer */
42int rhbufsz; /* rhs substitution buffer size */
43int rhbufi; /* rhs substitution buffer index */
44
45/* extract_subst_tail: extract substitution tail from the command buffer */
46int
47extract_subst_tail(flagp, np)
48 int *flagp;
49 int *np;
50{
51 char delimiter;
52
53 *flagp = *np = 0;
54 if ((delimiter = *ibufp) == '\n') {
55 rhbufi = 0;
56 *flagp = GPR;
57 return 0;
58 } else if (extract_subst_template() == NULL)
59 return ERR;
60 else if (*ibufp == '\n') {
61 *flagp = GPR;
62 return 0;
63 } else if (*ibufp == delimiter)
64 ibufp++;
65 if ('1' <= *ibufp && *ibufp <= '9') {
66 STRTOL(*np, ibufp);
67 return 0;
68 } else if (*ibufp == 'g') {
69 ibufp++;
70 *flagp = GSG;
71 return 0;
72 }
73 return 0;
74}
75
76
77/* extract_subst_template: return pointer to copy of substitution template
78 in the command buffer */
79char *
80extract_subst_template()
81{
82 int n = 0;
83 int i = 0;
84 char c;
85 char delimiter = *ibufp++;
86
87 if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
88 ibufp++;
89 if (!rhbuf) sprintf(errmsg, "no previous substitution");
90 return rhbuf;
91 }
92 while (*ibufp != delimiter) {
93 REALLOC(rhbuf, rhbufsz, i + 2, NULL);
94 if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
95 i--, ibufp--;
96 break;
97 } else if (c != '\\')
98 ;
99 else if ((rhbuf[i++] = *ibufp++) != '\n')
100 ;
101 else if (!isglobal) {
102 while ((n = get_tty_line()) == 0 ||
103 (n > 0 && ibuf[n - 1] != '\n'))
104 clearerr(stdin);
105 if (n < 0)
106 return NULL;
107 }
108 }
109 REALLOC(rhbuf, rhbufsz, i + 1, NULL);
110 rhbuf[rhbufi = i] = '\0';
111 return rhbuf;
112}
113
114
115char *rbuf; /* substitute_matching_text buffer */
116int rbufsz; /* substitute_matching_text buffer size */
117
118/* search_and_replace: for each line in a range, change text matching a pattern
119 according to a substitution template; return status */
120int
121search_and_replace(pat, gflag, kth)
122 pattern_t *pat;
123 int gflag;
124 int kth;
125{
126 undo_t *up;
127 char *txt;
128 char *eot;
129 long lc;
130 long xa = current_addr;
131 int nsubs = 0;
132 line_t *lp;
133 int len;
134
135 current_addr = first_addr - 1;
136 for (lc = 0; lc <= second_addr - first_addr; lc++) {
137 lp = get_addressed_line_node(++current_addr);
138 if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
139 return ERR;
140 else if (len) {
141 up = NULL;
142 if (delete_lines(current_addr, current_addr) < 0)
143 return ERR;
144 txt = rbuf;
145 eot = rbuf + len;
146 SPL1();
147 do {
148 if ((txt = put_sbuf_line(txt)) == NULL) {
149 SPL0();
150 return ERR;
151 } else if (up)
152 up->t = get_addressed_line_node(current_addr);
153 else if ((up = push_undo_stack(UADD,
154 current_addr, current_addr)) == NULL) {
155 SPL0();
156 return ERR;
157 }
158 } while (txt != eot);
159 SPL0();
160 nsubs++;
161 xa = current_addr;
162 }
163 }
164 current_addr = xa;
165 if (nsubs == 0 && !(gflag & GLB)) {
166 sprintf(errmsg, "no match");
167 return ERR;
168 } else if ((gflag & (GPR | GLS | GNP)) &&
169 display_lines(current_addr, current_addr, gflag) < 0)
170 return ERR;
171 return 0;
172}
173
174
175/* substitute_matching_text: replace text matched by a pattern according to
176 a substitution template; return pointer to the modified text */
177int
178substitute_matching_text(pat, lp, gflag, kth)
179 pattern_t *pat;
180 line_t *lp;
181 int gflag;
182 int kth;
183{
184 int off = 0;
185 int changed = 0;
186 int matchno = 0;
187 int i = 0;
188 regmatch_t rm[SE_MAX];
189 char *txt;
190 char *eot;
191
192 if ((txt = get_sbuf_line(lp)) == NULL)
193 return ERR;
194 if (isbinary)
195 NUL_TO_NEWLINE(txt, lp->len);
196 eot = txt + lp->len;
197 if (!regexec(pat, txt, SE_MAX, rm, 0)) {
198 do {
199 if (!kth || kth == ++matchno) {
200 changed++;
201 i = rm[0].rm_so;
202 REALLOC(rbuf, rbufsz, off + i, ERR);
203 if (isbinary)
204 NEWLINE_TO_NUL(txt, rm[0].rm_eo);
205 memcpy(rbuf + off, txt, i);
206 off += i;
207 if ((off = apply_subst_template(txt, rm, off,
208 pat->re_nsub)) < 0)
209 return ERR;
210 } else {
211 i = rm[0].rm_eo;
212 REALLOC(rbuf, rbufsz, off + i, ERR);
213 if (isbinary)
214 NEWLINE_TO_NUL(txt, i);
215 memcpy(rbuf + off, txt, i);
216 off += i;
217 }
218 txt += rm[0].rm_eo;
219 } while (*txt &&
220 (!changed || ((gflag & GSG) && rm[0].rm_eo)) &&
221 !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
222 i = eot - txt;
223 REALLOC(rbuf, rbufsz, off + i + 2, ERR);
224 if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
225 sprintf(errmsg, "infinite substitution loop");
226 return ERR;
227 }
228 if (isbinary)
229 NEWLINE_TO_NUL(txt, i);
230 memcpy(rbuf + off, txt, i);
231 memcpy(rbuf + off + i, "\n", 2);
232 }
233 return changed ? off + i + 1 : 0;
234}
235
236
237/* apply_subst_template: modify text according to a substitution template;
238 return offset to end of modified text */
239int
240apply_subst_template(boln, rm, off, re_nsub)
241 char *boln;
242 regmatch_t *rm;
243 int off;
244 int re_nsub;
245{
246 int j = 0;
247 int k = 0;
248 int n;
249 char *sub = rhbuf;
250
251 for (; sub - rhbuf < rhbufi; sub++)
252 if (*sub == '&') {
253 j = rm[0].rm_so;
254 k = rm[0].rm_eo;
255 REALLOC(rbuf, rbufsz, off + k - j, ERR);
256 while (j < k)
257 rbuf[off++] = boln[j++];
258 } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
259 (n = *sub - '0') <= re_nsub) {
260 j = rm[n].rm_so;
261 k = rm[n].rm_eo;
262 REALLOC(rbuf, rbufsz, off + k - j, ERR);
263 while (j < k)
264 rbuf[off++] = boln[j++];
265 } else {
266 REALLOC(rbuf, rbufsz, off + 1, ERR);
267 rbuf[off++] = *sub;
268 }
269 REALLOC(rbuf, rbufsz, off + 1, ERR);
270 rbuf[off] = '\0';
271 return off;
272}