Commit | Line | Data |
---|---|---|
09c852e2 | 1 | /*- |
ba5e8546 KB |
2 | * Copyright (c) 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
09c852e2 KB |
4 | * |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Rodney Ruddock of the University of Guelph. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | */ | |
10 | ||
11 | #ifndef lint | |
ba5e8546 | 12 | static char sccsid[] = "@(#)sub.c 8.1 (Berkeley) %G%"; |
09c852e2 KB |
13 | #endif /* not lint */ |
14 | ||
ecbf4ad0 KB |
15 | #include <sys/types.h> |
16 | ||
ecbf4ad0 KB |
17 | #include <regex.h> |
18 | #include <setjmp.h> | |
19 | #include <stdio.h> | |
20 | #include <stdlib.h> | |
21 | #include <string.h> | |
22 | ||
e692f66f KB |
23 | #ifdef DBI |
24 | #include <db.h> | |
25 | #endif | |
26 | ||
09c852e2 | 27 | #include "ed.h" |
ecbf4ad0 | 28 | #include "extern.h" |
09c852e2 KB |
29 | |
30 | /* | |
31 | * The substitute command. It's big because of the backward compatability. | |
32 | */ | |
09c852e2 KB |
33 | void |
34 | s(inputt, errnum) | |
ecbf4ad0 KB |
35 | FILE *inputt; |
36 | int *errnum; | |
09c852e2 | 37 | { |
ecbf4ad0 KB |
38 | static int l_count2 = 1, l_global = 0, l_print = 0; |
39 | static int l_first_pass_flag = 0; | |
40 | static char *l_match = NULL, *l_repl = NULL; | |
05ee7127 | 41 | LINE *l_s_ret, *l_temp_line, *l_temp_line2, *l_kval, *l_last, *l_cur; |
ecbf4ad0 | 42 | int l_s_flag, l_count, l_matched, l_nflag, l_cnt, yy, l_sr_flag = 0; |
05ee7127 | 43 | int l_err, l_sl, l_rep_flag, l_u_reuse_flag=0, l_local_len, l_nudge=0; |
ecbf4ad0 | 44 | char *l_match2 = NULL, *l_local = NULL, *l_local_temp = NULL; |
09c852e2 | 45 | #ifndef REG_STARTEND |
ecbf4ad0 | 46 | size_t l_offset = 0; |
09c852e2 KB |
47 | #endif |
48 | ||
035e94f8 RC |
49 | if (Start_default && End_default) |
50 | Start = End = current; | |
ecbf4ad0 | 51 | else |
035e94f8 RC |
52 | if (Start_default) |
53 | Start = End; | |
54 | if (Start == NULL) { | |
ecbf4ad0 KB |
55 | *errnum = -1; |
56 | return; | |
57 | } | |
035e94f8 | 58 | Start_default = End_default = 0; |
09c852e2 | 59 | |
ecbf4ad0 KB |
60 | l_sl = ss = getc(inputt); |
61 | if (l_first_pass_flag == 0) | |
62 | l_match = l_repl = NULL; | |
63 | l_match2 = get_pattern(l_sl, inputt, errnum, 0); | |
e692f66f | 64 | |
ecbf4ad0 KB |
65 | if (*errnum < 0) { |
66 | if ((*errnum == -2) && (l_sl != '\n')) | |
67 | return; | |
68 | if ((l_match2 == NULL) || | |
69 | (strlen(l_match2) > 4) || (l_first_pass_flag == 0)) | |
70 | return; | |
71 | *errnum = 0; | |
72 | l_sr_flag = -1; | |
73 | for (yy = 0; yy < (strlen(l_match2)); yy++) { | |
74 | switch (l_match2[yy]) { | |
75 | case '\n': | |
76 | ss = getc(inputt); | |
77 | goto bcg1; | |
78 | break; | |
79 | case 'r': | |
80 | l_sr_flag = 1; | |
81 | break; | |
82 | case 'p': | |
83 | l_print = (l_print) ? 0 : 1; | |
84 | break; | |
85 | case 'g': | |
86 | l_global = (l_global) ? 0 : 1; | |
87 | break; | |
88 | case 'N': | |
89 | l_count2 = 1; | |
90 | break; | |
91 | default: | |
92 | *errnum = -1; | |
93 | strcpy(help_msg, "illegal modifier to s"); | |
94 | return; | |
95 | } | |
96 | } | |
97 | ss = getc(inputt); | |
98 | if (l_sr_flag == 1) | |
99 | goto bcg2; | |
100 | else | |
101 | goto bcg1; | |
102 | } | |
103 | if (l_first_pass_flag) { | |
104 | free(l_match); | |
105 | free(l_repl); | |
106 | } else | |
107 | l_first_pass_flag = 1; | |
108 | l_match = l_match2; | |
109 | *errnum = 0; | |
110 | l_repl = get_pattern(ss, inputt, errnum, 1); | |
e692f66f | 111 | if (sigint_flag && (!sigspecial)) |
ecbf4ad0 KB |
112 | SIGINT_ACTION; |
113 | l_global = l_print = 0; | |
114 | if (*errnum < 0) | |
115 | if ((*errnum == -1) && (ss == '\n')) | |
116 | /* Note, \n still in stream for next getc. */ | |
117 | l_print = 1; | |
118 | else | |
119 | return; | |
120 | *errnum = 0; | |
09c852e2 | 121 | |
ecbf4ad0 | 122 | l_count2 = 1; |
09c852e2 | 123 | |
ecbf4ad0 KB |
124 | while (((ss = getc(inputt)) != '\n') && (ss != EOF)) |
125 | if (ss == 'g') | |
126 | l_global = 1; | |
127 | else | |
128 | switch (ss) { | |
129 | case 'p': | |
130 | l_print = (l_print | (int) 1); | |
131 | break; | |
132 | case 'n': | |
133 | l_print = (l_print | (int) 2); | |
134 | break; | |
135 | case 'l': | |
136 | l_print = (l_print | (int) 4); | |
137 | break; | |
138 | default: | |
139 | if ((ss > ('0' - 1)) && (ss < ('9' + 1))) | |
140 | l_count2 = dig_num_conv(inputt, errnum); | |
141 | else { | |
142 | *errnum = -1; | |
143 | strcpy(help_msg, | |
144 | "illegal command option"); | |
145 | return; | |
146 | } | |
147 | } | |
09c852e2 KB |
148 | |
149 | bcg1: | |
ecbf4ad0 KB |
150 | if ((RE_flag == 0) && (l_match[1] == '\0')) { |
151 | *errnum = -1; | |
152 | ungetc(ss, inputt); | |
153 | return; | |
154 | } else | |
155 | if ((l_sr_flag == 0) && (l_match[1] || (RE_patt == NULL))) { | |
e692f66f KB |
156 | int l_m_len = 2 + strlen(l_match); |
157 | sigspecial++; | |
ecbf4ad0 | 158 | free(RE_patt); |
e692f66f | 159 | RE_patt = malloc(sizeof(char) * (l_m_len)); |
080766e7 | 160 | memmove(RE_patt, l_match, l_m_len); |
e692f66f KB |
161 | sigspecial--; |
162 | if (sigint_flag && (!sigspecial)) | |
163 | SIGINT_ACTION; | |
ecbf4ad0 KB |
164 | } |
165 | RE_sol = (l_match[1] == '^') ? 1 : 0; | |
166 | if ((l_match[1]) && | |
167 | (regfree(&RE_comp), l_err = regcomp(&RE_comp, &l_match[1], 0))) { | |
168 | regerror(l_err, &RE_comp, help_msg, 128); | |
169 | *errnum = -1; | |
170 | RE_flag = 0; | |
171 | ungetc(ss, inputt); | |
172 | return; | |
173 | } | |
174 | RE_flag = 1; | |
e692f66f | 175 | if (sigint_flag && (!sigspecial)) |
ecbf4ad0 | 176 | SIGINT_ACTION; |
09c852e2 | 177 | bcg2: |
05ee7127 | 178 | l_cur = current; |
035e94f8 | 179 | current = Start; |
ecbf4ad0 KB |
180 | l_s_flag = 0; |
181 | do { | |
ecbf4ad0 KB |
182 | RE_match[0].rm_eo = 0; |
183 | get_line(current->handle, current->len); | |
e692f66f KB |
184 | if (sigint_flag && (!sigspecial)) |
185 | SIGINT_ACTION; | |
ecbf4ad0 KB |
186 | l_count = l_count2; |
187 | l_local = text; | |
afdef93a | 188 | l_rep_flag = 1; |
09c852e2 | 189 | #ifndef REG_STARTEND |
ecbf4ad0 | 190 | l_offset = 0; |
71fc9f52 KB |
191 | #else |
192 | l_local_len = current->len; | |
09c852e2 | 193 | #endif |
ecbf4ad0 KB |
194 | do { |
195 | RE_match[0].rm_so = RE_match[0].rm_eo; | |
05ee7127 KB |
196 | if (l_nudge) |
197 | RE_match[0].rm_so++; | |
198 | l_nudge = 0; | |
09c852e2 | 199 | #ifdef REG_STARTEND |
ecbf4ad0 KB |
200 | l_matched = regexec_n(&RE_comp, l_local, |
201 | (size_t)RE_SEC, RE_match, 0, l_count, | |
71fc9f52 | 202 | (size_t)l_local_len, 0); |
09c852e2 | 203 | #else |
ecbf4ad0 KB |
204 | l_matched = regexec_n(&RE_comp, l_local, |
205 | (size_t)RE_SEC, RE_match, 0, l_count, | |
206 | &l_offset, 0); | |
09c852e2 | 207 | #endif |
ecbf4ad0 | 208 | if (l_matched == 0) { |
05ee7127 KB |
209 | if ((l_s_flag == 0) && (g_flag == 0)) { |
210 | current = l_cur; | |
ecbf4ad0 | 211 | u_clr_stk(); |
05ee7127 KB |
212 | current = Start; |
213 | } | |
ecbf4ad0 | 214 | l_count = l_s_flag = 1; |
afdef93a | 215 | l_rep_flag = 0; |
ecbf4ad0 KB |
216 | /* |
217 | * The l_local passed into re_replace is not | |
218 | * freed in re_replace because it is "text", | |
219 | * the global line holder, for the first pass | |
220 | * through this loop. The value returned by | |
221 | * re_replace is a new string (with the first | |
222 | * replacement in it). If the 'g' flag was | |
223 | * set with substitute then this new string | |
224 | * is passed in for the second pass and can | |
225 | * be freed once re_replace is done with it. | |
226 | * (...and so on for the rest of the 'g' | |
227 | * passes. RE_match[0].rm_eo is changed in | |
228 | * re_replace to be the new location of the | |
229 | * next character immediately after the | |
230 | * replacement since it is likely the | |
231 | * position of that character has changed | |
232 | * because of the replacement. | |
233 | */ | |
05ee7127 KB |
234 | if (RE_match[0].rm_so == RE_match[0].rm_eo) |
235 | l_nudge = 1; | |
09c852e2 | 236 | #ifdef REG_STARTEND |
ecbf4ad0 KB |
237 | l_local = re_replace(l_local, |
238 | (size_t)(RE_SEC - 1), RE_match, &l_repl[1]); | |
71fc9f52 | 239 | l_local_len = strlen(l_local); |
09c852e2 | 240 | #else |
ecbf4ad0 KB |
241 | l_local = re_replace(l_local, |
242 | (size_t)(RE_SEC - 1), RE_match, &l_repl[1], | |
243 | l_offset); | |
09c852e2 | 244 | #endif |
ecbf4ad0 KB |
245 | } |
246 | if (l_global == 0) | |
247 | break; | |
248 | if (l_local[RE_match[0].rm_eo] == '\0') | |
249 | break; | |
250 | } while (!l_matched); | |
09c852e2 | 251 | |
afdef93a KB |
252 | if (l_rep_flag) |
253 | goto next; | |
ecbf4ad0 KB |
254 | l_cnt = l_nflag = 0; |
255 | l_kval = current; | |
256 | l_temp_line = current->above; | |
257 | l_temp_line2 = current->below; | |
258 | l_local_temp = l_local; | |
e692f66f | 259 | sigspecial++; |
ecbf4ad0 KB |
260 | for (;;) { |
261 | /* | |
262 | * Make the new string the one for this line. Check if | |
263 | * it needs to be split. | |
264 | */ | |
265 | if (l_local[l_cnt] == '\n' || l_local[l_cnt] == '\0') { | |
266 | if (l_local[l_cnt] == '\0') | |
267 | l_nflag = 1; | |
268 | l_local[l_cnt] = '\0'; | |
269 | l_s_ret = malloc(sizeof(LINE)); | |
270 | if (l_s_ret == NULL) { | |
271 | *errnum = -1; | |
272 | strcpy(help_msg, "out of memory error"); | |
273 | return; | |
274 | } | |
275 | (l_s_ret->len) = strlen(l_local); | |
276 | (l_s_ret->handle) = add_line(l_local, l_s_ret->len); | |
277 | (l_s_ret->above) = l_temp_line; | |
278 | (l_s_ret->below) = NULL; | |
279 | if (l_temp_line == NULL) | |
280 | top = l_s_ret; | |
281 | else { | |
afdef93a KB |
282 | if ((current != Start) && |
283 | ((&(current->above)) == u_stk->cell)) | |
284 | l_u_reuse_flag = 1; | |
285 | else { | |
286 | u_add_stk(&(l_temp_line->below)); | |
287 | l_u_reuse_flag = 0; | |
288 | } | |
ecbf4ad0 KB |
289 | (l_temp_line->below) = l_s_ret; |
290 | } | |
291 | l_temp_line = l_s_ret; | |
292 | if ((l_local[l_cnt] == '\0') && (l_nflag == 1)) | |
293 | break; | |
294 | else { | |
295 | l_local = &(l_local[l_cnt + 1]); | |
296 | l_cnt = 0; | |
297 | } | |
298 | } else | |
299 | l_cnt++; | |
300 | } | |
301 | (l_s_ret->below) = l_temp_line2; | |
302 | ku_chk(current, current, l_kval->below); | |
303 | if (current == End) | |
304 | End = l_s_ret; | |
305 | current = l_s_ret; | |
306 | l_last = current; | |
307 | if (l_temp_line2 == NULL) | |
308 | bottom = l_s_ret; | |
309 | else { | |
afdef93a KB |
310 | if (l_u_reuse_flag) |
311 | u_pop_n_swap(&(l_temp_line2->above)); | |
312 | else | |
313 | u_add_stk(&(l_temp_line2->above)); | |
ecbf4ad0 KB |
314 | (l_temp_line2->above) = current; |
315 | } | |
e692f66f KB |
316 | sigspecial--; |
317 | if (sigint_flag && (!sigspecial)) | |
318 | SIGINT_ACTION; | |
ecbf4ad0 KB |
319 | if (l_local_temp != text) |
320 | free(l_local_temp); | |
afdef93a | 321 | next: |
ecbf4ad0 KB |
322 | current = current->below; |
323 | } while (current != (End->below)); | |
09c852e2 | 324 | |
ecbf4ad0 | 325 | if (l_s_flag == 0) { |
035e94f8 | 326 | current = Start; |
05ee7127 KB |
327 | if (!g_flag) { |
328 | strcpy(help_msg, "no matches found for substitution"); | |
329 | *errnum = -1; | |
330 | ungetc('\n', inputt); | |
331 | } | |
332 | else | |
333 | *errnum = 0; | |
ecbf4ad0 KB |
334 | return; |
335 | } | |
336 | change_flag = 1; | |
337 | current = l_last; | |
09c852e2 | 338 | |
ecbf4ad0 | 339 | if (l_print > 0) { |
afdef93a | 340 | Start = End = l_s_ret; /*current;*/ |
ecbf4ad0 KB |
341 | ungetc(ss, inputt); |
342 | if (l_print == (l_print | (int) 1)) | |
343 | p(inputt, errnum, 0); | |
344 | if (l_print == (l_print | (int) 2)) | |
345 | p(inputt, errnum, 1); | |
346 | if (l_print == (l_print | (int) 4)) | |
347 | l(inputt, errnum); | |
348 | if (*errnum < 0) | |
349 | return; | |
350 | } | |
351 | if (l_sr_flag == -1) { | |
352 | regfree(&RE_comp); | |
353 | regcomp(&RE_comp, &RE_patt[1], 0); | |
354 | } | |
355 | *errnum = 1; | |
356 | } |