/src/rtpproxy/external/libre/src/fmt/regex.c
Line | Count | Source |
1 | | /** |
2 | | * @file regex.c Implements basic regular expressions |
3 | | * |
4 | | * Copyright (C) 2010 Creytiv.com |
5 | | */ |
6 | | #include <ctype.h> |
7 | | #include <re_types.h> |
8 | | #include <re_fmt.h> |
9 | | |
10 | | |
11 | | /** Defines a character range */ |
12 | | struct chr { |
13 | | uint8_t min; /**< Minimum value */ |
14 | | uint8_t max; /**< Maximum value */ |
15 | | }; |
16 | | |
17 | | |
18 | | static bool expr_match(const struct chr *chrv, uint32_t n, uint8_t c, |
19 | | bool neg) |
20 | 0 | { |
21 | 0 | uint32_t i; |
22 | |
|
23 | 0 | for (i=0; i<n; i++) { |
24 | |
|
25 | 0 | if (c < chrv[i].min) |
26 | 0 | continue; |
27 | | |
28 | 0 | if (c > chrv[i].max) |
29 | 0 | continue; |
30 | | |
31 | 0 | break; |
32 | 0 | } |
33 | |
|
34 | 0 | return neg ? (i == n) : (i != n); |
35 | 0 | } |
36 | | |
37 | | |
38 | | /** |
39 | | * Parse a string using basic regular expressions. Any number of matching |
40 | | * expressions can be given, and each match will be stored in a "struct pl" |
41 | | * pointer-length type. |
42 | | * |
43 | | * @param ptr String to parse |
44 | | * @param len Length of string |
45 | | * @param expr Regular expressions string |
46 | | * |
47 | | * @return 0 if success, otherwise errorcode |
48 | | * |
49 | | * Example: |
50 | | * |
51 | | * We parse the buffer for any numerical values, to get a match we must have |
52 | | * 1 or more occurences of the digits 0-9. The result is stored in 'num', |
53 | | * which is of pointer-length type and will point to the first location in |
54 | | * the buffer that contains "42". |
55 | | * |
56 | | * <pre> |
57 | | const char buf[] = "foo 42 bar"; |
58 | | struct pl num; |
59 | | int err = re_regex(buf, strlen(buf), "[0-9]+", &num); |
60 | | |
61 | | here num contains a pointer to '42' |
62 | | * </pre> |
63 | | */ |
64 | | int re_regex(const char *ptr, size_t len, const char *expr, ...) |
65 | 0 | { |
66 | 0 | struct chr chrv[64]; |
67 | 0 | const char *p, *ep; |
68 | 0 | bool fm, range = false, ec = false, neg = false, qesc = false; |
69 | 0 | uint32_t n = 0; |
70 | 0 | va_list ap; |
71 | 0 | bool eesc; |
72 | 0 | size_t l; |
73 | |
|
74 | 0 | if (!ptr || !expr) |
75 | 0 | return EINVAL; |
76 | | |
77 | 0 | again: |
78 | 0 | eesc = false; |
79 | 0 | fm = false; |
80 | 0 | l = len--; |
81 | 0 | p = ptr++; |
82 | 0 | ep = expr; |
83 | |
|
84 | 0 | va_start(ap, expr); |
85 | |
|
86 | 0 | if (!l) |
87 | 0 | goto out; |
88 | | |
89 | 0 | for (; *ep; ep++) { |
90 | |
|
91 | 0 | if ('\\' == *ep && !eesc) { |
92 | 0 | eesc = true; |
93 | 0 | continue; |
94 | 0 | } |
95 | | |
96 | 0 | if (!fm) { |
97 | | |
98 | | /* Start of character class */ |
99 | 0 | if ('[' == *ep && !eesc) { |
100 | 0 | n = 0; |
101 | 0 | fm = true; |
102 | 0 | ec = false; |
103 | 0 | neg = false; |
104 | 0 | range = false; |
105 | 0 | qesc = false; |
106 | 0 | continue; |
107 | 0 | } |
108 | | |
109 | 0 | if (!l) |
110 | 0 | break; |
111 | | |
112 | 0 | if (tolower(*ep) != tolower(*p)) { |
113 | 0 | va_end(ap); |
114 | 0 | goto again; |
115 | 0 | } |
116 | | |
117 | 0 | eesc = false; |
118 | 0 | ++p; |
119 | 0 | --l; |
120 | 0 | continue; |
121 | 0 | } |
122 | | /* End of character class */ |
123 | 0 | else if (ec) { |
124 | |
|
125 | 0 | uint32_t nm, nmin, nmax; |
126 | 0 | struct pl lpl, *pl = va_arg(ap, struct pl *); |
127 | 0 | bool quote = false, esc = false; |
128 | | |
129 | | /* Match 0 or more times */ |
130 | 0 | if ('*' == *ep) { |
131 | 0 | nmin = 0; |
132 | 0 | nmax = -1; |
133 | 0 | } |
134 | | /* Match 1 or more times */ |
135 | 0 | else if ('+' == *ep) { |
136 | 0 | nmin = 1; |
137 | 0 | nmax = -1; |
138 | 0 | } |
139 | | /* Match exactly n times */ |
140 | 0 | else if ('1' <= *ep && *ep <= '9') { |
141 | 0 | nmin = *ep - '0'; |
142 | 0 | nmax = *ep - '0'; |
143 | 0 | } |
144 | 0 | else |
145 | 0 | break; |
146 | | |
147 | 0 | fm = false; |
148 | |
|
149 | 0 | lpl.p = p; |
150 | 0 | lpl.l = 0; |
151 | |
|
152 | 0 | for (nm = 0; l && nm < nmax; nm++, p++, l--, lpl.l++) { |
153 | |
|
154 | 0 | if (qesc) { |
155 | |
|
156 | 0 | if (esc) { |
157 | 0 | esc = false; |
158 | 0 | continue; |
159 | 0 | } |
160 | | |
161 | 0 | switch (*p) { |
162 | | |
163 | 0 | case '\\': |
164 | 0 | esc = true; |
165 | 0 | continue; |
166 | | |
167 | 0 | case '"': |
168 | 0 | quote = !quote; |
169 | 0 | continue; |
170 | 0 | } |
171 | | |
172 | 0 | if (quote) |
173 | 0 | continue; |
174 | 0 | } |
175 | | |
176 | 0 | if (!expr_match(chrv, n, tolower(*p), neg)) |
177 | 0 | break; |
178 | 0 | } |
179 | | |
180 | | /* Strip quotes */ |
181 | 0 | if (qesc && lpl.l > 1 && |
182 | 0 | lpl.p[0] == '"' && lpl.p[lpl.l - 1] == '"') { |
183 | |
|
184 | 0 | lpl.p += 1; |
185 | 0 | lpl.l -= 2; |
186 | 0 | nm -= 2; |
187 | 0 | } |
188 | |
|
189 | 0 | if ((nm < nmin) || (nm > nmax)) { |
190 | 0 | va_end(ap); |
191 | 0 | goto again; |
192 | 0 | } |
193 | | |
194 | 0 | if (pl) |
195 | 0 | *pl = lpl; |
196 | |
|
197 | 0 | eesc = false; |
198 | 0 | continue; |
199 | 0 | } |
200 | | |
201 | 0 | if (eesc) { |
202 | 0 | eesc = false; |
203 | 0 | goto chr; |
204 | 0 | } |
205 | | |
206 | 0 | switch (*ep) { |
207 | | |
208 | | /* End of character class */ |
209 | 0 | case ']': |
210 | 0 | ec = true; |
211 | 0 | continue; |
212 | | |
213 | | /* Negate with quote escape */ |
214 | 0 | case '~': |
215 | 0 | if (n) |
216 | 0 | break; |
217 | | |
218 | 0 | qesc = true; |
219 | 0 | neg = true; |
220 | 0 | continue; |
221 | | |
222 | | /* Negate */ |
223 | 0 | case '^': |
224 | 0 | if (n) |
225 | 0 | break; |
226 | | |
227 | 0 | neg = true; |
228 | 0 | continue; |
229 | | |
230 | | /* Range */ |
231 | 0 | case '-': |
232 | 0 | if (!n || range) |
233 | 0 | break; |
234 | | |
235 | 0 | range = true; |
236 | 0 | --n; |
237 | 0 | continue; |
238 | 0 | } |
239 | | |
240 | 0 | chr: |
241 | 0 | if (n >= ARRAY_SIZE(chrv)) |
242 | 0 | break; |
243 | | |
244 | 0 | chrv[n].max = tolower(*ep); |
245 | |
|
246 | 0 | if (range) |
247 | 0 | range = false; |
248 | 0 | else |
249 | 0 | chrv[n].min = tolower(*ep); |
250 | |
|
251 | 0 | ++n; |
252 | 0 | } |
253 | 0 | out: |
254 | 0 | va_end(ap); |
255 | |
|
256 | 0 | if (fm) |
257 | 0 | return EINVAL; |
258 | | |
259 | 0 | return *ep ? ENOENT : 0; |
260 | 0 | } |