1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * Includes
30 */
31
32 /* we need to define this to get strtok_r from string.h */
33 /* SEEMS LIKE A BUG TO ME */
34 #define _REENTRANT
35
36 #ifndef DEBUG
37 #define NDEBUG 1
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <libintl.h>
44 #include <regexpr.h>
45 #include <assert.h>
46 #include <sys/types.h>
47 #include "spec.h"
48 #include "new.h"
49 #include "source.h"
50
51
52 static boolean_t spec_match(spec_t * spec_p, char *str);
53
54 /*
55 * Globals
56 */
57
58
59
60 /*
61 * spec() - builds a spec
62 */
63
64 spec_t *
spec(char * str_p,spec_type_t type)65 spec(char *str_p,
66 spec_type_t type)
67 {
68 spec_t *new_p;
69
70 new_p = new(spec_t);
71 queue_init(&new_p->qn);
72 new_p->str = str_p;
73 new_p->type = type;
74 new_p->regexp_p = NULL;
75
76 if (type == SPEC_REGEXP) {
77 new_p->regexp_p = compile(str_p, NULL, NULL);
78 if (!new_p->regexp_p) {
79 semantic_err(gettext("invalid regular expression"));
80 free(new_p);
81 return (NULL);
82 }
83 }
84 return (new_p);
85
86 } /* end spec */
87
88
89 /*
90 * spec_dup() - duplicates a spec, NOT A SPEC LIST!
91 */
92
93 spec_t *
spec_dup(spec_t * spec_p)94 spec_dup(spec_t * spec_p)
95 {
96 spec_t *new_p;
97
98 new_p = spec(strdup(spec_p->str), spec_p->type);
99
100 return (new_p);
101
102 } /* end spec_dup */
103
104
105 /*
106 * spec_destroy() - destroys a spec list
107 */
108
109 void
spec_destroy(spec_t * list_p)110 spec_destroy(spec_t * list_p)
111 {
112 spec_t *spec_p;
113
114 while ((spec_p = (spec_t *) queue_next(&list_p->qn, &list_p->qn))) {
115 (void) queue_remove(&spec_p->qn);
116
117 if (spec_p->str)
118 free(spec_p->str);
119 if (spec_p->regexp_p)
120 free(spec_p->regexp_p);
121 free(spec_p);
122 }
123
124 if (list_p->str)
125 free(list_p->str);
126 if (list_p->regexp_p)
127 free(list_p->regexp_p);
128 free(list_p);
129
130 } /* end spec_destroy */
131
132
133 /*
134 * spec_list() - append a spec_t to a list
135 */
136
137 spec_t *
spec_list(spec_t * h,spec_t * f)138 spec_list(spec_t * h,
139 spec_t * f)
140 {
141 /* queue append handles the NULL cases OK */
142 return ((spec_t *) queue_append(&h->qn, &f->qn));
143
144 } /* end spec_list */
145
146
147 /*
148 * spec_print() - pretty prints a speclist
149 */
150
151 void
spec_print(FILE * stream,spec_t * list_p)152 spec_print(FILE * stream,
153 spec_t * list_p)
154 {
155 spec_t *spec_p = NULL;
156
157 while ((spec_p = (spec_t *) queue_next(&list_p->qn, &spec_p->qn))) {
158 switch (spec_p->type) {
159 case SPEC_EXACT:
160 (void) fprintf(stream, "'%s'", spec_p->str);
161 break;
162 case SPEC_REGEXP:
163 (void) fprintf(stream, "/%s/", spec_p->str);
164 break;
165 }
166 }
167
168 } /* end spec_print */
169
170
171 /*
172 * spec_match() - called with a spec and a string, returns whether they
173 * match.
174 */
175
176 static boolean_t
spec_match(spec_t * spec_p,char * str)177 spec_match(spec_t * spec_p,
178 char *str)
179 {
180 if (!spec_p)
181 return (B_FALSE);
182
183 switch (spec_p->type) {
184 case SPEC_EXACT:
185 return ((strcmp(spec_p->str, str) == 0));
186
187 case SPEC_REGEXP:
188 return ((step(str, spec_p->regexp_p) != NULL));
189 }
190
191 return (B_FALSE);
192
193 } /* end spec_match */
194
195
196 /*
197 * spec_attrtrav() - traverse an attribute list, calling the supplied
198 * function on each matching attribute.
199 */
200
201 void
spec_attrtrav(spec_t * spec_p,char * attrs,spec_attr_fun_t fun,void * calldatap)202 spec_attrtrav(spec_t * spec_p,
203 char *attrs,
204 spec_attr_fun_t fun,
205 void *calldatap)
206 {
207 char *lasts;
208 char *refptr = NULL;
209 char *escptr = NULL;
210 char *pair;
211 char *s;
212 boolean_t inquote = B_FALSE;
213
214 /*
215 * * STRATEGY - we make two copies of the attr string. In one *
216 * string we escape (translate) all relevant quoted characters to * a
217 * non-significant character. We use this string to feed to * strtok
218 * to do the parsing. * Once strtok has parsed the string, we use the
219 * same fragement * positions from the unescaped string to pass to
220 * the next level.
221 */
222
223 /* make two copies of the string */
224 refptr = strdup(attrs);
225 escptr = strdup(attrs);
226
227 /* escape any quoted ';'s in the escptr string */
228 for (s = escptr; *s; s++) {
229 switch (*s) {
230 case ';':
231 if (inquote)
232 *s = '#';
233 break;
234
235 case '\'':
236 inquote = (inquote) ? B_FALSE : B_TRUE;
237 break;
238
239 default:
240 /* nothing on purpose */
241 break;
242 }
243 }
244
245 /* loop over each attribute section separated by ';' */
246 for (pair = strtok_r(escptr, ";", &lasts); pair;
247 pair = strtok_r(NULL, ";", &lasts)) {
248 char *escattr;
249 char *escvals;
250 char *refattr;
251 char *refvals;
252 char emptystr[1];
253
254 escattr = strtok_r(pair, " \t", &escvals);
255
256 /*
257 * setup the ref pointers to the same locations as the esc
258 * ptrs
259 */
260 /*
261 * null the reference string in the same spots as the esc
262 * string
263 */
264 refattr = (refptr + (escattr - escptr));
265 refattr[strlen(escattr)] = '\0';
266
267 if (escvals && *escvals) {
268 refvals = (refptr + (escvals - escptr));
269 refvals[strlen(escvals)] = '\0';
270 } else {
271 refvals = NULL;
272 emptystr[0] = '\0';
273 }
274
275 if (spec_match(spec_p, refattr)) {
276 if (refvals)
277 (*fun) (spec_p, refattr, refvals, calldatap);
278 else
279 (*fun) (spec_p, refattr, emptystr, calldatap);
280 }
281 }
282
283 alldone:
284 if (refptr)
285 free(refptr);
286 if (escptr)
287 free(escptr);
288
289 } /* end spec_attrtrav */
290
291
292 /*
293 * spec_valtrav() - traverse an value list, calling the supplied function on
294 * each matching value.
295 */
296
297 void
spec_valtrav(spec_t * spec_p,char * valstr,spec_val_fun_t fun,void * calldatap)298 spec_valtrav(spec_t * spec_p,
299 char *valstr,
300 spec_val_fun_t fun,
301 void *calldatap)
302 {
303 char *s0;
304 char *s;
305 boolean_t intoken = B_FALSE;
306 boolean_t inquote = B_FALSE;
307
308 /* return immeadiatly on null pointers */
309 if (!valstr)
310 return;
311
312 /* special case, match once on empty string */
313 if (!*valstr) {
314 if (spec_match(spec_p, valstr))
315 (*fun) (spec_p, valstr, calldatap);
316 return;
317 }
318 for (s = s0 = valstr; ; s++) {
319 switch (*s) {
320 case NULL:
321 if (intoken) {
322 if (spec_match(spec_p, s0))
323 (*fun) (spec_p, s0, calldatap);
324 }
325 return; /* ALL DONE */
326
327 case '\'':
328 if (inquote) {
329 /* end a quoted string */
330 inquote = B_FALSE;
331 intoken = B_FALSE;
332 *s = '\0';
333 if (spec_match(spec_p, s0))
334 (*fun) (spec_p, s0, calldatap);
335 /* next string starts past the quote */
336 s0 = s + 1;
337 } else {
338 /* start a quoted string */
339 inquote = B_TRUE;
340 intoken = B_TRUE;
341 s0 = s + 1; /* point past the quote */
342 }
343 break;
344
345 case ' ':
346 case '\t':
347 /* ignore whitespace in quoted strings */
348 if (inquote)
349 break;
350
351 if (intoken) {
352 /* whitespace ended this token */
353 intoken = B_FALSE;
354 *s = '\0';
355 if (spec_match(spec_p, s0))
356 (*fun) (spec_p, s0, calldatap);
357 /* next string starts past the whitespace */
358 s0 = s + 1;
359 }
360 break;
361
362 default:
363 /* characters all OK inside quoted string */
364 if (inquote)
365 break;
366
367 if (!intoken) {
368 /* start of unquoted token */
369 intoken = B_TRUE;
370 s0 = s; /* token starts here */
371 }
372 break;
373 }
374 }
375
376
377 #ifdef TOOSIMPLE
378 char *v;
379 char *ls;
380
381 /*
382 * #### MISSING - need to handle quoted value strings * containing
383 * whitespace.
384 */
385
386 for (v = strtok_r(valstr, " \t", &ls); v;
387 v = strtok_r(NULL, " \t", &ls)) {
388 if (spec_match(spec_p, v)) {
389 (*fun) (spec_p, v, calldatap);
390 }
391 }
392 #endif
393
394 } /* end spec_valtrav */
395