games: Massive style(9) cleanup commit. Reduces differences to NetBSD.
[dragonfly.git] / games / quiz / rxp.c
blob6e14d147b6b128478ba796f70dedb4ea554de8d7
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Jim R. Oldroyd at The Instruction Set and Keith Gabryelski at
7 * Commodore Business Machines.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 * @(#)rxp.c 8.1 (Berkeley) 5/31/93
34 * $FreeBSD: src/games/quiz/rxp.c,v 1.5 1999/12/12 02:29:54 billf Exp $
35 * $DragonFly: src/games/quiz/rxp.c,v 1.4 2005/04/25 16:10:24 liamfoy Exp $
39 * regular expression parser
41 * external functions and return values are:
42 * rxp_compile(s)
43 * TRUE success
44 * FALSE parse failure; error message will be in char rxperr[]
45 * metas are:
46 * {...} optional pattern, equialent to [...|]
47 * | alternate pattern
48 * [...] pattern delimiters
50 * rxp_match(s)
51 * TRUE string s matches compiled pattern
52 * FALSE match failure or regexp error
54 * rxp_expand()
55 * char * reverse-engineered regular expression string
56 * NULL regexp error
59 #include <stdio.h>
60 #include <ctype.h>
61 #include "quiz.h"
62 /* regexp tokens, arg */
63 #define LIT (-1) /* literal character, char */
64 #define SOT (-2) /* start text anchor, - */
65 #define EOT (-3) /* end text anchor, - */
66 #define GRP_S (-4) /* start alternate grp, ptr_to_end */
67 #define GRP_E (-5) /* end group, - */
68 #define ALT_S (-6) /* alternate starts, ptr_to_next */
69 #define ALT_E (-7) /* alternate ends, - */
70 #define END (-8) /* end of regexp, - */
72 typedef short Rxp_t; /* type for regexp tokens */
74 static Rxp_t rxpbuf[RXP_LINE_SZ]; /* compiled regular expression buffer */
75 char rxperr[128]; /* parser error message */
77 static int rxp__compile (char *, int);
78 static char *rxp__expand (int);
79 static int rxp__match (char *, int, Rxp_t *, Rxp_t *, char *);
81 int
82 rxp_compile(char *s)
84 return (rxp__compile(s, TRUE));
87 static int
88 rxp__compile(char *s, int first)
90 static Rxp_t *rp;
91 static char *sp;
92 Rxp_t *grp_ptr;
93 Rxp_t *alt_ptr;
94 int esc, err;
96 esc = 0;
97 if (first) {
98 rp = rxpbuf;
99 sp = s;
100 *rp++ = SOT; /* auto-anchor: pat is really ^pat$ */
101 *rp++ = GRP_S; /* auto-group: ^pat$ is really ^[pat]$ */
102 *rp++ = 0;
104 *rp++ = ALT_S;
105 alt_ptr = rp;
106 *rp++ = 0;
107 for (; *sp; ++sp) {
108 if (rp - rxpbuf >= RXP_LINE_SZ - 4) {
109 (void)snprintf(rxperr, sizeof(rxperr),
110 "regular expression too long %s", s);
111 return (FALSE);
113 if (*sp == ':' && !esc)
114 break;
115 if (esc) {
116 *rp++ = LIT;
117 *rp++ = *sp;
118 esc = 0;
120 else switch (*sp) {
121 case '\\':
122 esc = 1;
123 break;
124 case '{':
125 case '[':
126 *rp++ = GRP_S;
127 grp_ptr = rp;
128 *rp++ = 0;
129 sp++;
130 if ((err = rxp__compile(s, FALSE)) != TRUE)
131 return (err);
132 *rp++ = GRP_E;
133 *grp_ptr = rp - rxpbuf;
134 break;
135 case '}':
136 case ']':
137 case '|':
138 *rp++ = ALT_E;
139 *alt_ptr = rp - rxpbuf;
140 if (*sp != ']') {
141 *rp++ = ALT_S;
142 alt_ptr = rp;
143 *rp++ = 0;
145 if (*sp != '|') {
146 if (*sp != ']') {
147 *rp++ = ALT_E;
148 *alt_ptr = rp - rxpbuf;
150 if (first) {
151 (void)snprintf(rxperr, sizeof(rxperr),
152 "unmatched alternator in regexp %s",
154 return (FALSE);
156 return (TRUE);
158 break;
159 default:
160 *rp++ = LIT;
161 *rp++ = *sp;
162 esc = 0;
163 break;
166 if (!first) {
167 (void)snprintf(rxperr, sizeof(rxperr),
168 "unmatched alternator in regexp %s", s);
169 return (FALSE);
171 *rp++ = ALT_E;
172 *alt_ptr = rp - rxpbuf;
173 *rp++ = GRP_E;
174 *(rxpbuf + 2) = rp - rxpbuf;
175 *rp++ = EOT;
176 *rp = END;
177 return (TRUE);
181 * match string against compiled regular expression
184 rxp_match(char *s)
186 return (rxp__match(s, TRUE, NULL, NULL, NULL));
190 * jump to j_succ on successful alt match
191 * jump to j_fail on failed match
192 * reset sp to sp_fail on failed match
194 static int
195 rxp__match(char *s, int first, Rxp_t *j_succ, Rxp_t *j_fail, char *sp_fail)
197 static Rxp_t *rp;
198 static char *sp;
199 int ch;
200 Rxp_t *grp_end;
201 int err;
203 grp_end = NULL;
204 if (first) {
205 rp = rxpbuf;
206 sp = s;
208 while (rp < rxpbuf + RXP_LINE_SZ && *rp != END)
209 switch(*rp) {
210 case LIT:
211 rp++;
212 ch = isascii(*rp) && isupper(*rp) ? tolower(*rp) : *rp;
213 if (ch != *sp++) {
214 rp = j_fail;
215 sp = sp_fail;
216 return (TRUE);
218 rp++;
219 break;
220 case SOT:
221 if (sp != s)
222 return (FALSE);
223 rp++;
224 break;
225 case EOT:
226 if (*sp != 0)
227 return (FALSE);
228 rp++;
229 break;
230 case GRP_S:
231 rp++;
232 grp_end = rxpbuf + *rp++;
233 break;
234 case ALT_S:
235 rp++;
236 if ((err = rxp__match(sp,
237 FALSE, grp_end, rxpbuf + *rp++, sp)) != TRUE)
238 return (err);
239 break;
240 case ALT_E:
241 rp = j_succ;
242 return (TRUE);
243 case GRP_E:
244 default:
245 return (FALSE);
247 return (*rp != END ? FALSE : TRUE);
251 * Reverse engineer the regular expression, by picking first of all alternates.
253 char *
254 rxp_expand(void)
256 return (rxp__expand(TRUE));
259 static char *
260 rxp__expand(int first)
262 static char buf[RXP_LINE_SZ/2];
263 static Rxp_t *rp;
264 static char *bp;
265 Rxp_t *grp_ptr;
266 char *err;
268 if (first) {
269 rp = rxpbuf;
270 bp = buf;
272 while (rp < rxpbuf + RXP_LINE_SZ && *rp != END)
273 switch(*rp) {
274 case LIT:
275 rp++;
276 *bp++ = *rp++;
277 break;
278 case GRP_S:
279 rp++;
280 grp_ptr = rxpbuf + *rp;
281 rp++;
282 if ((err = rxp__expand(FALSE)) == NULL)
283 return (err);
284 rp = grp_ptr;
285 break;
286 case ALT_E:
287 return (buf);
288 case ALT_S:
289 rp++;
290 /* FALLTHROUGH */
291 case SOT:
292 case EOT:
293 case GRP_E:
294 rp++;
295 break;
296 default:
297 return (NULL);
299 if (first) {
300 if (*rp != END)
301 return (NULL);
302 *bp = '\0';
304 return (buf);