1*00b67f09SDavid van Moolenbroek /* $NetBSD: regex.c,v 1.3 2014/12/10 04:37:59 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek *
6*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek *
10*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek */
18*00b67f09SDavid van Moolenbroek
19*00b67f09SDavid van Moolenbroek #include <config.h>
20*00b67f09SDavid van Moolenbroek
21*00b67f09SDavid van Moolenbroek #include <isc/file.h>
22*00b67f09SDavid van Moolenbroek #include <isc/regex.h>
23*00b67f09SDavid van Moolenbroek #include <isc/string.h>
24*00b67f09SDavid van Moolenbroek
25*00b67f09SDavid van Moolenbroek #if VALREGEX_REPORT_REASON
26*00b67f09SDavid van Moolenbroek #define FAIL(x) do { reason = (x); goto error; } while(/*CONSTCOND*/0)
27*00b67f09SDavid van Moolenbroek #else
28*00b67f09SDavid van Moolenbroek #define FAIL(x) goto error
29*00b67f09SDavid van Moolenbroek #endif
30*00b67f09SDavid van Moolenbroek
31*00b67f09SDavid van Moolenbroek /*
32*00b67f09SDavid van Moolenbroek * Validate the regular expression 'C' locale.
33*00b67f09SDavid van Moolenbroek */
34*00b67f09SDavid van Moolenbroek int
isc_regex_validate(const char * c)35*00b67f09SDavid van Moolenbroek isc_regex_validate(const char *c) {
36*00b67f09SDavid van Moolenbroek enum {
37*00b67f09SDavid van Moolenbroek none, parse_bracket, parse_bound,
38*00b67f09SDavid van Moolenbroek parse_ce, parse_ec, parse_cc
39*00b67f09SDavid van Moolenbroek } state = none;
40*00b67f09SDavid van Moolenbroek /* Well known character classes. */
41*00b67f09SDavid van Moolenbroek const char *cc[] = {
42*00b67f09SDavid van Moolenbroek ":alnum:", ":digit:", ":punct:", ":alpha:", ":graph:",
43*00b67f09SDavid van Moolenbroek ":space:", ":blank:", ":lower:", ":upper:", ":cntrl:",
44*00b67f09SDavid van Moolenbroek ":print:", ":xdigit:"
45*00b67f09SDavid van Moolenbroek };
46*00b67f09SDavid van Moolenbroek isc_boolean_t seen_comma = ISC_FALSE;
47*00b67f09SDavid van Moolenbroek isc_boolean_t seen_high = ISC_FALSE;
48*00b67f09SDavid van Moolenbroek isc_boolean_t seen_char = ISC_FALSE;
49*00b67f09SDavid van Moolenbroek isc_boolean_t seen_ec = ISC_FALSE;
50*00b67f09SDavid van Moolenbroek isc_boolean_t seen_ce = ISC_FALSE;
51*00b67f09SDavid van Moolenbroek isc_boolean_t have_atom = ISC_FALSE;
52*00b67f09SDavid van Moolenbroek int group = 0;
53*00b67f09SDavid van Moolenbroek int range = 0;
54*00b67f09SDavid van Moolenbroek int sub = 0;
55*00b67f09SDavid van Moolenbroek isc_boolean_t empty_ok = ISC_FALSE;
56*00b67f09SDavid van Moolenbroek isc_boolean_t neg = ISC_FALSE;
57*00b67f09SDavid van Moolenbroek isc_boolean_t was_multiple = ISC_FALSE;
58*00b67f09SDavid van Moolenbroek unsigned int low = 0;
59*00b67f09SDavid van Moolenbroek unsigned int high = 0;
60*00b67f09SDavid van Moolenbroek const char *ccname = NULL;
61*00b67f09SDavid van Moolenbroek int range_start = 0;
62*00b67f09SDavid van Moolenbroek #if VALREGEX_REPORT_REASON
63*00b67f09SDavid van Moolenbroek const char *reason = "";
64*00b67f09SDavid van Moolenbroek #endif
65*00b67f09SDavid van Moolenbroek
66*00b67f09SDavid van Moolenbroek if (c == NULL || *c == 0)
67*00b67f09SDavid van Moolenbroek FAIL("empty string");
68*00b67f09SDavid van Moolenbroek
69*00b67f09SDavid van Moolenbroek while (c != NULL && *c != 0) {
70*00b67f09SDavid van Moolenbroek switch (state) {
71*00b67f09SDavid van Moolenbroek case none:
72*00b67f09SDavid van Moolenbroek switch (*c) {
73*00b67f09SDavid van Moolenbroek case '\\': /* make literal */
74*00b67f09SDavid van Moolenbroek ++c;
75*00b67f09SDavid van Moolenbroek switch (*c) {
76*00b67f09SDavid van Moolenbroek case '1': case '2': case '3':
77*00b67f09SDavid van Moolenbroek case '4': case '5': case '6':
78*00b67f09SDavid van Moolenbroek case '7': case '8': case '9':
79*00b67f09SDavid van Moolenbroek if ((*c - '0') > sub)
80*00b67f09SDavid van Moolenbroek FAIL("bad back reference");
81*00b67f09SDavid van Moolenbroek have_atom = ISC_TRUE;
82*00b67f09SDavid van Moolenbroek was_multiple = ISC_FALSE;
83*00b67f09SDavid van Moolenbroek break;
84*00b67f09SDavid van Moolenbroek case 0:
85*00b67f09SDavid van Moolenbroek FAIL("escaped end-of-string");
86*00b67f09SDavid van Moolenbroek default:
87*00b67f09SDavid van Moolenbroek goto literal;
88*00b67f09SDavid van Moolenbroek }
89*00b67f09SDavid van Moolenbroek ++c;
90*00b67f09SDavid van Moolenbroek break;
91*00b67f09SDavid van Moolenbroek case '[': /* bracket start */
92*00b67f09SDavid van Moolenbroek ++c;
93*00b67f09SDavid van Moolenbroek neg = ISC_FALSE;
94*00b67f09SDavid van Moolenbroek was_multiple = ISC_FALSE;
95*00b67f09SDavid van Moolenbroek seen_char = ISC_FALSE;
96*00b67f09SDavid van Moolenbroek state = parse_bracket;
97*00b67f09SDavid van Moolenbroek break;
98*00b67f09SDavid van Moolenbroek case '{': /* bound start */
99*00b67f09SDavid van Moolenbroek switch (c[1]) {
100*00b67f09SDavid van Moolenbroek case '0': case '1': case '2': case '3':
101*00b67f09SDavid van Moolenbroek case '4': case '5': case '6': case '7':
102*00b67f09SDavid van Moolenbroek case '8': case '9':
103*00b67f09SDavid van Moolenbroek if (!have_atom)
104*00b67f09SDavid van Moolenbroek FAIL("no atom");
105*00b67f09SDavid van Moolenbroek if (was_multiple)
106*00b67f09SDavid van Moolenbroek FAIL("was multiple");
107*00b67f09SDavid van Moolenbroek seen_comma = ISC_FALSE;
108*00b67f09SDavid van Moolenbroek seen_high = ISC_FALSE;
109*00b67f09SDavid van Moolenbroek low = high = 0;
110*00b67f09SDavid van Moolenbroek state = parse_bound;
111*00b67f09SDavid van Moolenbroek break;
112*00b67f09SDavid van Moolenbroek default:
113*00b67f09SDavid van Moolenbroek goto literal;
114*00b67f09SDavid van Moolenbroek }
115*00b67f09SDavid van Moolenbroek ++c;
116*00b67f09SDavid van Moolenbroek have_atom = ISC_TRUE;
117*00b67f09SDavid van Moolenbroek was_multiple = ISC_TRUE;
118*00b67f09SDavid van Moolenbroek break;
119*00b67f09SDavid van Moolenbroek case '}':
120*00b67f09SDavid van Moolenbroek goto literal;
121*00b67f09SDavid van Moolenbroek case '(': /* group start */
122*00b67f09SDavid van Moolenbroek have_atom = ISC_FALSE;
123*00b67f09SDavid van Moolenbroek was_multiple = ISC_FALSE;
124*00b67f09SDavid van Moolenbroek empty_ok = ISC_TRUE;
125*00b67f09SDavid van Moolenbroek ++group;
126*00b67f09SDavid van Moolenbroek ++sub;
127*00b67f09SDavid van Moolenbroek ++c;
128*00b67f09SDavid van Moolenbroek break;
129*00b67f09SDavid van Moolenbroek case ')': /* group end */
130*00b67f09SDavid van Moolenbroek if (group && !have_atom && !empty_ok)
131*00b67f09SDavid van Moolenbroek FAIL("empty alternative");
132*00b67f09SDavid van Moolenbroek have_atom = ISC_TRUE;
133*00b67f09SDavid van Moolenbroek was_multiple = ISC_FALSE;
134*00b67f09SDavid van Moolenbroek if (group != 0)
135*00b67f09SDavid van Moolenbroek --group;
136*00b67f09SDavid van Moolenbroek ++c;
137*00b67f09SDavid van Moolenbroek break;
138*00b67f09SDavid van Moolenbroek case '|': /* alternative seperator */
139*00b67f09SDavid van Moolenbroek if (!have_atom)
140*00b67f09SDavid van Moolenbroek FAIL("no atom");
141*00b67f09SDavid van Moolenbroek have_atom = ISC_FALSE;
142*00b67f09SDavid van Moolenbroek empty_ok = ISC_FALSE;
143*00b67f09SDavid van Moolenbroek was_multiple = ISC_FALSE;
144*00b67f09SDavid van Moolenbroek ++c;
145*00b67f09SDavid van Moolenbroek break;
146*00b67f09SDavid van Moolenbroek case '^':
147*00b67f09SDavid van Moolenbroek case '$':
148*00b67f09SDavid van Moolenbroek have_atom = ISC_TRUE;
149*00b67f09SDavid van Moolenbroek was_multiple = ISC_TRUE;
150*00b67f09SDavid van Moolenbroek ++c;
151*00b67f09SDavid van Moolenbroek break;
152*00b67f09SDavid van Moolenbroek case '+':
153*00b67f09SDavid van Moolenbroek case '*':
154*00b67f09SDavid van Moolenbroek case '?':
155*00b67f09SDavid van Moolenbroek if (was_multiple)
156*00b67f09SDavid van Moolenbroek FAIL("was multiple");
157*00b67f09SDavid van Moolenbroek if (!have_atom)
158*00b67f09SDavid van Moolenbroek FAIL("no atom");
159*00b67f09SDavid van Moolenbroek have_atom = ISC_TRUE;
160*00b67f09SDavid van Moolenbroek was_multiple = ISC_TRUE;
161*00b67f09SDavid van Moolenbroek ++c;
162*00b67f09SDavid van Moolenbroek break;
163*00b67f09SDavid van Moolenbroek case '.':
164*00b67f09SDavid van Moolenbroek default:
165*00b67f09SDavid van Moolenbroek literal:
166*00b67f09SDavid van Moolenbroek have_atom = ISC_TRUE;
167*00b67f09SDavid van Moolenbroek was_multiple = ISC_FALSE;
168*00b67f09SDavid van Moolenbroek ++c;
169*00b67f09SDavid van Moolenbroek break;
170*00b67f09SDavid van Moolenbroek }
171*00b67f09SDavid van Moolenbroek break;
172*00b67f09SDavid van Moolenbroek case parse_bound:
173*00b67f09SDavid van Moolenbroek switch (*c) {
174*00b67f09SDavid van Moolenbroek case '0': case '1': case '2': case '3': case '4':
175*00b67f09SDavid van Moolenbroek case '5': case '6': case '7': case '8': case '9':
176*00b67f09SDavid van Moolenbroek if (!seen_comma) {
177*00b67f09SDavid van Moolenbroek low = low * 10 + *c - '0';
178*00b67f09SDavid van Moolenbroek if (low > 255)
179*00b67f09SDavid van Moolenbroek FAIL("lower bound too big");
180*00b67f09SDavid van Moolenbroek } else {
181*00b67f09SDavid van Moolenbroek seen_high = ISC_TRUE;
182*00b67f09SDavid van Moolenbroek high = high * 10 + *c - '0';
183*00b67f09SDavid van Moolenbroek if (high > 255)
184*00b67f09SDavid van Moolenbroek FAIL("upper bound too big");
185*00b67f09SDavid van Moolenbroek }
186*00b67f09SDavid van Moolenbroek ++c;
187*00b67f09SDavid van Moolenbroek break;
188*00b67f09SDavid van Moolenbroek case ',':
189*00b67f09SDavid van Moolenbroek if (seen_comma)
190*00b67f09SDavid van Moolenbroek FAIL("multiple commas");
191*00b67f09SDavid van Moolenbroek seen_comma = ISC_TRUE;
192*00b67f09SDavid van Moolenbroek ++c;
193*00b67f09SDavid van Moolenbroek break;
194*00b67f09SDavid van Moolenbroek default:
195*00b67f09SDavid van Moolenbroek case '{':
196*00b67f09SDavid van Moolenbroek FAIL("non digit/comma");
197*00b67f09SDavid van Moolenbroek case '}':
198*00b67f09SDavid van Moolenbroek if (seen_high && low > high)
199*00b67f09SDavid van Moolenbroek FAIL("bad parse bound");
200*00b67f09SDavid van Moolenbroek seen_comma = ISC_FALSE;
201*00b67f09SDavid van Moolenbroek state = none;
202*00b67f09SDavid van Moolenbroek ++c;
203*00b67f09SDavid van Moolenbroek break;
204*00b67f09SDavid van Moolenbroek }
205*00b67f09SDavid van Moolenbroek break;
206*00b67f09SDavid van Moolenbroek case parse_bracket:
207*00b67f09SDavid van Moolenbroek switch (*c) {
208*00b67f09SDavid van Moolenbroek case '^':
209*00b67f09SDavid van Moolenbroek if (seen_char || neg) goto inside;
210*00b67f09SDavid van Moolenbroek neg = ISC_TRUE;
211*00b67f09SDavid van Moolenbroek ++c;
212*00b67f09SDavid van Moolenbroek break;
213*00b67f09SDavid van Moolenbroek case '-':
214*00b67f09SDavid van Moolenbroek if (range == 2) goto inside;
215*00b67f09SDavid van Moolenbroek if (!seen_char) goto inside;
216*00b67f09SDavid van Moolenbroek if (range == 1)
217*00b67f09SDavid van Moolenbroek FAIL("bad range");
218*00b67f09SDavid van Moolenbroek range = 2;
219*00b67f09SDavid van Moolenbroek ++c;
220*00b67f09SDavid van Moolenbroek break;
221*00b67f09SDavid van Moolenbroek case '[':
222*00b67f09SDavid van Moolenbroek ++c;
223*00b67f09SDavid van Moolenbroek switch (*c) {
224*00b67f09SDavid van Moolenbroek case '.': /* collating element */
225*00b67f09SDavid van Moolenbroek if (range != 0) --range;
226*00b67f09SDavid van Moolenbroek ++c;
227*00b67f09SDavid van Moolenbroek state = parse_ce;
228*00b67f09SDavid van Moolenbroek seen_ce = ISC_FALSE;
229*00b67f09SDavid van Moolenbroek break;
230*00b67f09SDavid van Moolenbroek case '=': /* equivalence class */
231*00b67f09SDavid van Moolenbroek if (range == 2)
232*00b67f09SDavid van Moolenbroek FAIL("equivalence class in range");
233*00b67f09SDavid van Moolenbroek ++c;
234*00b67f09SDavid van Moolenbroek state = parse_ec;
235*00b67f09SDavid van Moolenbroek seen_ec = ISC_FALSE;
236*00b67f09SDavid van Moolenbroek break;
237*00b67f09SDavid van Moolenbroek case ':': /* character class */
238*00b67f09SDavid van Moolenbroek if (range == 2)
239*00b67f09SDavid van Moolenbroek FAIL("character class in range");
240*00b67f09SDavid van Moolenbroek ccname = c;
241*00b67f09SDavid van Moolenbroek ++c;
242*00b67f09SDavid van Moolenbroek state = parse_cc;
243*00b67f09SDavid van Moolenbroek break;
244*00b67f09SDavid van Moolenbroek }
245*00b67f09SDavid van Moolenbroek seen_char = ISC_TRUE;
246*00b67f09SDavid van Moolenbroek break;
247*00b67f09SDavid van Moolenbroek case ']':
248*00b67f09SDavid van Moolenbroek if (!c[1] && !seen_char)
249*00b67f09SDavid van Moolenbroek FAIL("unfinished brace");
250*00b67f09SDavid van Moolenbroek if (!seen_char)
251*00b67f09SDavid van Moolenbroek goto inside;
252*00b67f09SDavid van Moolenbroek ++c;
253*00b67f09SDavid van Moolenbroek range = 0;
254*00b67f09SDavid van Moolenbroek have_atom = ISC_TRUE;
255*00b67f09SDavid van Moolenbroek state = none;
256*00b67f09SDavid van Moolenbroek break;
257*00b67f09SDavid van Moolenbroek default:
258*00b67f09SDavid van Moolenbroek inside:
259*00b67f09SDavid van Moolenbroek seen_char = ISC_TRUE;
260*00b67f09SDavid van Moolenbroek if (range == 2 && (*c & 0xff) < range_start)
261*00b67f09SDavid van Moolenbroek FAIL("out of order range");
262*00b67f09SDavid van Moolenbroek if (range != 0)
263*00b67f09SDavid van Moolenbroek --range;
264*00b67f09SDavid van Moolenbroek range_start = *c & 0xff;
265*00b67f09SDavid van Moolenbroek ++c;
266*00b67f09SDavid van Moolenbroek break;
267*00b67f09SDavid van Moolenbroek };
268*00b67f09SDavid van Moolenbroek break;
269*00b67f09SDavid van Moolenbroek case parse_ce:
270*00b67f09SDavid van Moolenbroek switch (*c) {
271*00b67f09SDavid van Moolenbroek case '.':
272*00b67f09SDavid van Moolenbroek ++c;
273*00b67f09SDavid van Moolenbroek switch (*c) {
274*00b67f09SDavid van Moolenbroek case ']':
275*00b67f09SDavid van Moolenbroek if (!seen_ce)
276*00b67f09SDavid van Moolenbroek FAIL("empty ce");
277*00b67f09SDavid van Moolenbroek ++c;
278*00b67f09SDavid van Moolenbroek state = parse_bracket;
279*00b67f09SDavid van Moolenbroek break;
280*00b67f09SDavid van Moolenbroek default:
281*00b67f09SDavid van Moolenbroek if (seen_ce)
282*00b67f09SDavid van Moolenbroek range_start = 256;
283*00b67f09SDavid van Moolenbroek else
284*00b67f09SDavid van Moolenbroek range_start = '.';
285*00b67f09SDavid van Moolenbroek seen_ce = ISC_TRUE;
286*00b67f09SDavid van Moolenbroek break;
287*00b67f09SDavid van Moolenbroek }
288*00b67f09SDavid van Moolenbroek break;
289*00b67f09SDavid van Moolenbroek default:
290*00b67f09SDavid van Moolenbroek if (seen_ce)
291*00b67f09SDavid van Moolenbroek range_start = 256;
292*00b67f09SDavid van Moolenbroek else
293*00b67f09SDavid van Moolenbroek range_start = *c;
294*00b67f09SDavid van Moolenbroek seen_ce = ISC_TRUE;
295*00b67f09SDavid van Moolenbroek ++c;
296*00b67f09SDavid van Moolenbroek break;
297*00b67f09SDavid van Moolenbroek }
298*00b67f09SDavid van Moolenbroek break;
299*00b67f09SDavid van Moolenbroek case parse_ec:
300*00b67f09SDavid van Moolenbroek switch (*c) {
301*00b67f09SDavid van Moolenbroek case '=':
302*00b67f09SDavid van Moolenbroek ++c;
303*00b67f09SDavid van Moolenbroek switch (*c) {
304*00b67f09SDavid van Moolenbroek case ']':
305*00b67f09SDavid van Moolenbroek if (!seen_ec)
306*00b67f09SDavid van Moolenbroek FAIL("no ec");
307*00b67f09SDavid van Moolenbroek ++c;
308*00b67f09SDavid van Moolenbroek state = parse_bracket;
309*00b67f09SDavid van Moolenbroek break;
310*00b67f09SDavid van Moolenbroek default:
311*00b67f09SDavid van Moolenbroek seen_ec = ISC_TRUE;
312*00b67f09SDavid van Moolenbroek break;
313*00b67f09SDavid van Moolenbroek }
314*00b67f09SDavid van Moolenbroek break;
315*00b67f09SDavid van Moolenbroek default:
316*00b67f09SDavid van Moolenbroek seen_ec = ISC_TRUE;
317*00b67f09SDavid van Moolenbroek ++c;
318*00b67f09SDavid van Moolenbroek break;
319*00b67f09SDavid van Moolenbroek }
320*00b67f09SDavid van Moolenbroek break;
321*00b67f09SDavid van Moolenbroek case parse_cc:
322*00b67f09SDavid van Moolenbroek switch (*c) {
323*00b67f09SDavid van Moolenbroek case ':':
324*00b67f09SDavid van Moolenbroek ++c;
325*00b67f09SDavid van Moolenbroek switch (*c) {
326*00b67f09SDavid van Moolenbroek case ']': {
327*00b67f09SDavid van Moolenbroek unsigned int i;
328*00b67f09SDavid van Moolenbroek isc_boolean_t found = ISC_FALSE;
329*00b67f09SDavid van Moolenbroek for (i = 0;
330*00b67f09SDavid van Moolenbroek i < sizeof(cc)/sizeof(*cc);
331*00b67f09SDavid van Moolenbroek i++)
332*00b67f09SDavid van Moolenbroek {
333*00b67f09SDavid van Moolenbroek unsigned int len;
334*00b67f09SDavid van Moolenbroek len = strlen(cc[i]);
335*00b67f09SDavid van Moolenbroek if (len !=
336*00b67f09SDavid van Moolenbroek (unsigned int)(c - ccname))
337*00b67f09SDavid van Moolenbroek continue;
338*00b67f09SDavid van Moolenbroek if (strncmp(cc[i], ccname, len))
339*00b67f09SDavid van Moolenbroek continue;
340*00b67f09SDavid van Moolenbroek found = ISC_TRUE;
341*00b67f09SDavid van Moolenbroek }
342*00b67f09SDavid van Moolenbroek if (!found)
343*00b67f09SDavid van Moolenbroek FAIL("unknown cc");
344*00b67f09SDavid van Moolenbroek ++c;
345*00b67f09SDavid van Moolenbroek state = parse_bracket;
346*00b67f09SDavid van Moolenbroek break;
347*00b67f09SDavid van Moolenbroek }
348*00b67f09SDavid van Moolenbroek default:
349*00b67f09SDavid van Moolenbroek break;
350*00b67f09SDavid van Moolenbroek }
351*00b67f09SDavid van Moolenbroek break;
352*00b67f09SDavid van Moolenbroek default:
353*00b67f09SDavid van Moolenbroek ++c;
354*00b67f09SDavid van Moolenbroek break;
355*00b67f09SDavid van Moolenbroek }
356*00b67f09SDavid van Moolenbroek break;
357*00b67f09SDavid van Moolenbroek }
358*00b67f09SDavid van Moolenbroek }
359*00b67f09SDavid van Moolenbroek if (group != 0)
360*00b67f09SDavid van Moolenbroek FAIL("group open");
361*00b67f09SDavid van Moolenbroek if (state != none)
362*00b67f09SDavid van Moolenbroek FAIL("incomplete");
363*00b67f09SDavid van Moolenbroek if (!have_atom)
364*00b67f09SDavid van Moolenbroek FAIL("no atom");
365*00b67f09SDavid van Moolenbroek return (sub);
366*00b67f09SDavid van Moolenbroek
367*00b67f09SDavid van Moolenbroek error:
368*00b67f09SDavid van Moolenbroek #if VALREGEX_REPORT_REASON
369*00b67f09SDavid van Moolenbroek fprintf(stderr, "%s\n", reason);
370*00b67f09SDavid van Moolenbroek #endif
371*00b67f09SDavid van Moolenbroek return (-1);
372*00b67f09SDavid van Moolenbroek }
373