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 * 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 * 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 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 * 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 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 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 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 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