This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / usr.bin / elvis / regsub.c
CommitLineData
15637ed4
RG
1/* regsub.c */
2
3/* This file contains the regsub() function, which performs substitutions
4 * after a regexp match has been found.
5 */
6
7#include "config.h"
8#include "ctype.h"
9#include "vi.h"
78ed81a3 10#ifdef REGEX
11# include <regex.h>
12#else
13# include "regexp.h"
14#endif
15637ed4
RG
15
16
17/* perform substitutions after a regexp match */
78ed81a3 18#ifdef REGEX
19void regsub(rm, startp, endp, src, dst)
20 regmatch_t *rm; /* the regexp with pointers into matched text */
21 char *startp, *endp;
22 REG char *src; /* the replacement string */
23 REG char *dst; /* where to put the result of the subst */
24#else
15637ed4
RG
25void regsub(re, src, dst)
26 regexp *re; /* the regexp with pointers into matched text */
27 REG char *src; /* the replacement string */
28 REG char *dst; /* where to put the result of the subst */
78ed81a3 29#endif
15637ed4
RG
30{
31 REG char *cpy; /* pointer to start of text to copy */
32 REG char *end; /* pointer to end of text to copy */
33 REG char c;
34 char *start;
35#ifndef CRUNCH
36 int mod = 0;/* used to track \U, \L, \u, \l, and \E */
37 int len; /* used to calculate length of subst string */
38 static char *prev; /* a copy of the text from the previous subst */
39
40 /* replace \~ (or maybe ~) by previous substitution text */
41
42 /* step 1: calculate the length of the new substitution text */
43 for (len = strlen(src), c = '\0', cpy = src; *cpy; cpy++)
44 {
45# ifdef NO_MAGIC
46 if (c == '\\' && *cpy == '~')
47# else
48 if (c == (*o_magic ? '\0' : '\\') && *cpy == '~')
49# endif
50 {
51 if (!prev)
52 {
78ed81a3 53 regerr("No prev text to substitute for ~");
54
15637ed4
RG
55 return;
56 }
57 len += strlen(prev) - 1;
58# ifndef NO_MAGIC
59 if (!*o_magic)
60# endif
61 len -= 1; /* because we lose the \ too */
62 }
63
64 /* watch backslash quoting */
65 if (c != '\\' && *cpy == '\\')
66 c = '\\';
67 else
68 c = '\0';
69 }
70
71 /* allocate memory for the ~ed version of src */
78ed81a3 72 checkmem();
15637ed4
RG
73 start = cpy = (char *)malloc((unsigned)(len + 1));
74 if (!cpy)
75 {
78ed81a3 76 regerr("Not enough memory for ~ expansion");
15637ed4
RG
77 return;
78 }
79
80 /* copy src into start, replacing the ~s by the previous text */
81 while (*src)
82 {
83# ifndef NO_MAGIC
84 if (*o_magic && *src == '~')
85 {
86 strcpy(cpy, prev);
87 cpy += strlen(prev);
88 src++;
89 }
90 else if (!*o_magic && *src == '\\' && *(src + 1) == '~')
91# else /* NO_MAGIC */
92 if (*src == '\\' && *(src + 1) == '~')
93# endif /* NO_MAGIC */
94 {
95 strcpy(cpy, prev);
96 cpy += strlen(prev);
97 src += 2;
98 }
99 else
100 {
101 *cpy++ = *src++;
102 }
103 }
104 *cpy = '\0';
105#ifdef DEBUG
106 if ((int)(cpy - start) != len)
107 {
108 msg("Bug in regsub.c! Predicted length = %d, Actual length = %d", len, (int)(cpy - start));
109 }
110#endif
78ed81a3 111 checkmem();
15637ed4
RG
112
113 /* remember this as the "previous" for next time */
114 if (prev)
78ed81a3 115 _free_(prev);
15637ed4
RG
116 prev = src = start;
117
118#endif /* undef CRUNCH */
119
120 start = src;
121 while ((c = *src++) != '\0')
122 {
123#ifndef NO_MAGIC
124 /* recognize any meta characters */
125 if (c == '&' && *o_magic)
126 {
78ed81a3 127#ifdef REGEX
128 cpy = startp;
129 end = endp;
130#else
15637ed4
RG
131 cpy = re->startp[0];
132 end = re->endp[0];
78ed81a3 133#endif
15637ed4
RG
134 }
135 else
136#endif /* not NO_MAGIC */
137 if (c == '\\')
138 {
139 c = *src++;
140 switch (c)
141 {
142#ifndef NO_MAGIC
143 case '0':
144 case '1':
145 case '2':
146 case '3':
147 case '4':
148 case '5':
149 case '6':
150 case '7':
151 case '8':
152 case '9':
153 /* \0 thru \9 mean "copy subexpression" */
154 c -= '0';
78ed81a3 155#ifdef REGEX
156 cpy = startp + (rm[c].rm_so - rm[0].rm_so);
157 end = endp + (rm[c].rm_eo - rm[0].rm_eo);
158#else
15637ed4
RG
159 cpy = re->startp[c];
160 end = re->endp[c];
78ed81a3 161#endif
15637ed4
RG
162 break;
163# ifndef CRUNCH
164 case 'U':
165 case 'u':
166 case 'L':
167 case 'l':
168 /* \U and \L mean "convert to upper/lowercase" */
169 mod = c;
170 continue;
171
172 case 'E':
173 case 'e':
174 /* \E ends the \U or \L */
175 mod = 0;
176 continue;
177# endif /* not CRUNCH */
178 case '&':
179 /* "\&" means "original text" */
180 if (*o_magic)
181 {
182 *dst++ = c;
183 continue;
184 }
78ed81a3 185#ifdef REGEX
186 cpy = startp;
187 end = endp;
188#else
15637ed4
RG
189 cpy = re->startp[0];
190 end = re->endp[0];
78ed81a3 191#endif
15637ed4
RG
192 break;
193
194#else /* NO_MAGIC */
195 case '&':
196 /* "\&" means "original text" */
78ed81a3 197#ifdef REGEX
198 cpy = startp;
199 end = endp;
200#else
15637ed4
RG
201 cpy = re->startp[0];
202 end = re->endp[0];
78ed81a3 203#endif
15637ed4
RG
204 break;
205#endif /* NO_MAGIC */
206 default:
207 /* ordinary char preceded by backslash */
208 *dst++ = c;
209 continue;
210 }
211 }
212#ifndef CRUNCH
213# if OSK
214 else if (c == '\l')
215# else
216 else if (c == '\r')
217# endif
218 {
219 /* transliterate ^M into newline */
220 *dst++ = '\n';
221 continue;
222 }
223#endif /* !CRUNCH */
224 else
225 {
226 /* ordinary character, so just copy it */
227 *dst++ = c;
228 continue;
229 }
230
231 /* Note: to reach this point in the code, we must have evaded
232 * all "continue" statements. To do that, we must have hit
233 * a metacharacter that involves copying.
234 */
235
236 /* if there is nothing to copy, loop */
237 if (!cpy)
238 continue;
239
240 /* copy over a portion of the original */
241 while (cpy < end)
242 {
243#ifndef NO_MAGIC
244# ifndef CRUNCH
245 switch (mod)
246 {
247 case 'U':
248 case 'u':
249 /* convert to uppercase */
250 *dst++ = toupper(*cpy++);
251 break;
252
253 case 'L':
254 case 'l':
255 /* convert to lowercase */
256 *dst++ = tolower(*cpy++);
257 break;
258
259 default:
260 /* copy without any conversion */
261 *dst++ = *cpy++;
262 }
263
264 /* \u and \l end automatically after the first char */
265 if (mod && (mod == 'u' || mod == 'l'))
266 {
267 mod = 0;
268 }
269# else /* CRUNCH */
270 *dst++ = *cpy++;
271# endif /* CRUNCH */
272#else /* NO_MAGIC */
273 *dst++ = *cpy++;
274#endif /* NO_MAGIC */
275 }
276 }
277 *dst = '\0';
278}