1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23
24 /*
25 * posix regex ed(1) style substitute execute
26 */
27
28 #include "reglib.h"
29
30 #define NEED(p,b,n,r) \
31 do \
32 { \
33 if (((b)->re_end - (b)->re_cur) < (n)) \
34 { \
35 size_t o = (b)->re_cur - (b)->re_buf; \
36 size_t a = ((b)->re_end - (b)->re_buf); \
37 if (a < n) \
38 a = roundof(n, 128); \
39 a *= 2; \
40 if (!((b)->re_buf = alloc(p->env->disc, (b)->re_buf, a))) \
41 { \
42 (b)->re_buf = (b)->re_cur = (b)->re_end = 0; \
43 c = REG_ESPACE; \
44 r; \
45 } \
46 (b)->re_cur = (b)->re_buf + o; \
47 (b)->re_end = (b)->re_buf + a; \
48 } \
49 } while (0)
50
51 #define PUTC(p,b,x,r) \
52 do \
53 { \
54 NEED(p, b, 1, r); \
55 *(b)->re_cur++ = (x); \
56 } while (0)
57
58 #define PUTS(p,b,x,z,r) \
59 do if (z) \
60 { \
61 NEED(p, b, z, r); \
62 memcpy((b)->re_cur, x, z); \
63 (b)->re_cur += (z); \
64 } while (0)
65
66 /*
67 * do a single substitution
68 */
69
70 static int
sub(const regex_t * p,register regsub_t * b,const char * ss,register regsubop_t * op,size_t nmatch,register regmatch_t * match)71 sub(const regex_t* p, register regsub_t* b, const char* ss, register regsubop_t* op, size_t nmatch, register regmatch_t* match)
72 {
73 register char* s;
74 register char* e;
75 register int c;
76
77 for (;; op++)
78 {
79 switch (op->len)
80 {
81 case -1:
82 break;
83 case 0:
84 if (op->off >= nmatch)
85 return REG_ESUBREG;
86 if ((c = match[op->off].rm_so) < 0)
87 continue;
88 s = (char*)ss + c;
89 if ((c = match[op->off].rm_eo) < 0)
90 continue;
91 e = (char*)ss + c;
92 NEED(p, b, e - s, return c);
93 switch (op->op)
94 {
95 case REG_SUB_UPPER:
96 while (s < e)
97 {
98 c = *s++;
99 if (islower(c))
100 c = toupper(c);
101 *b->re_cur++ = c;
102 }
103 break;
104 case REG_SUB_LOWER:
105 while (s < e)
106 {
107 c = *s++;
108 if (isupper(c))
109 c = tolower(c);
110 *b->re_cur++ = c;
111 }
112 break;
113 case REG_SUB_UPPER|REG_SUB_LOWER:
114 while (s < e)
115 {
116 c = *s++;
117 if (isupper(c))
118 c = tolower(c);
119 else if (islower(c))
120 c = toupper(c);
121 *b->re_cur++ = c;
122 }
123 break;
124 default:
125 while (s < e)
126 *b->re_cur++ = *s++;
127 break;
128 }
129 continue;
130 default:
131 NEED(p, b, op->len, return c);
132 s = b->re_rhs + op->off;
133 e = s + op->len;
134 while (s < e)
135 *b->re_cur++ = *s++;
136 continue;
137 }
138 break;
139 }
140 return 0;
141 }
142
143 /*
144 * ed(1) style substitute using matches from last regexec()
145 */
146
147 int
regsubexec(const regex_t * p,const char * s,size_t nmatch,regmatch_t * match)148 regsubexec(const regex_t* p, const char* s, size_t nmatch, regmatch_t* match)
149 {
150 register int c;
151 register regsub_t* b;
152 const char* e;
153 int m;
154
155 if (!p->env->sub || (p->env->flags & REG_NOSUB) || !nmatch)
156 return fatal(p->env->disc, REG_BADPAT, NiL);
157 b = p->re_sub;
158 m = b->re_min;
159 b->re_cur = b->re_buf;
160 e = (const char*)p->env->end;
161 c = 0;
162 for (;;)
163 {
164 if (--m > 0)
165 PUTS(p, b, s, match->rm_eo, return fatal(p->env->disc, c, NiL));
166 else
167 {
168 PUTS(p, b, s, match->rm_so, return fatal(p->env->disc, c, NiL));
169 if (!c && (c = sub(p, b, s, b->re_ops, nmatch, match)))
170 return fatal(p->env->disc, c, NiL);
171 }
172 s += match->rm_eo;
173 if (m <= 0 && !(b->re_flags & REG_SUB_ALL) || !*s)
174 break;
175 if (c = regnexec(p, s, e - s, nmatch, match, p->env->flags|(match->rm_so == match->rm_eo ? REG_ADVANCE : 0)))
176 {
177 if (c != REG_NOMATCH)
178 return fatal(p->env->disc, c, NiL);
179 break;
180 }
181 if (!match->rm_so && !match->rm_eo && *s && m <= 1)
182 {
183 match->rm_so = match->rm_eo = 1;
184 c = 1;
185 }
186 }
187 while (s < e)
188 {
189 c = *s++;
190 PUTC(p, b, c, return fatal(p->env->disc, c, NiL));
191 }
192 NEED(p, b, 1, return fatal(p->env->disc, c, NiL));
193 *b->re_cur = 0;
194 b->re_len = b->re_cur - b->re_buf;
195 return 0;
196 }
197