improve exit status handling for program map code
[unix-history] / usr / src / contrib / ed / sub.c
CommitLineData
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 12static 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
33void
34s(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
149bcg1:
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 177bcg2:
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 321next:
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}