1 /* $OpenBSD: look.c,v 1.24 2014/12/21 09:33:12 espie Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Copyright (c) 1989, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Ozan Yigit at York University. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 /* 40 * look.c 41 * Facility: m4 macro processor 42 * by: oz 43 */ 44 45 #include <sys/types.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <stdint.h> 49 #include <stddef.h> 50 #include <string.h> 51 #include <ohash.h> 52 #include "mdef.h" 53 #include "stdd.h" 54 #include "extern.h" 55 56 static void *hash_calloc(size_t, size_t, void *); 57 static void hash_free(void *, void *); 58 static void *element_alloc(size_t, void *); 59 static void setup_definition(struct macro_definition *, const char *, 60 const char *); 61 static void free_definition(char *); 62 static void keep(char *); 63 static int string_in_use(const char *); 64 65 static struct ohash_info macro_info = { 66 offsetof(struct ndblock, name), 67 NULL, hash_calloc, hash_free, element_alloc }; 68 69 struct ohash macros; 70 71 /* Support routines for hash tables. */ 72 void * 73 hash_calloc(size_t n, size_t s, void *u __unused) 74 { 75 void *storage = xcalloc(n, s, "hash alloc"); 76 return storage; 77 } 78 79 void 80 hash_free(void *p, void *u __unused) 81 { 82 free(p); 83 } 84 85 void * 86 element_alloc(size_t s, void *u __unused) 87 { 88 return xalloc(s, "element alloc"); 89 } 90 91 void 92 init_macros(void) 93 { 94 ohash_init(¯os, 10, ¯o_info); 95 } 96 97 /* 98 * find name in the hash table 99 */ 100 ndptr 101 lookup(const char *name) 102 { 103 return ohash_find(¯os, ohash_qlookup(¯os, name)); 104 } 105 106 struct macro_definition * 107 lookup_macro_definition(const char *name) 108 { 109 ndptr p; 110 111 p = ohash_find(¯os, ohash_qlookup(¯os, name)); 112 if (p) 113 return p->d; 114 else 115 return NULL; 116 } 117 118 static void 119 setup_definition(struct macro_definition *d, const char *defn, const char *name) 120 { 121 ndptr p; 122 123 if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0 && 124 (p = macro_getbuiltin(defn+sizeof(BUILTIN_MARKER)-1)) != NULL) { 125 d->type = macro_builtin_type(p); 126 d->defn = xstrdup(defn+sizeof(BUILTIN_MARKER)-1); 127 } else { 128 if (!*defn) 129 d->defn = __DECONST(char *, null); 130 else 131 d->defn = xstrdup(defn); 132 d->type = MACRTYPE; 133 } 134 if (STREQ(name, defn)) 135 d->type |= RECDEF; 136 } 137 138 static ndptr 139 create_entry(const char *name) 140 { 141 const char *end = NULL; 142 unsigned int i; 143 ndptr n; 144 145 i = ohash_qlookupi(¯os, name, &end); 146 n = ohash_find(¯os, i); 147 if (n == NULL) { 148 n = ohash_create_entry(¯o_info, name, &end); 149 ohash_insert(¯os, i, n); 150 n->trace_flags = FLAG_NO_TRACE; 151 n->builtin_type = MACRTYPE; 152 n->d = NULL; 153 } 154 return n; 155 } 156 157 void 158 macro_define(const char *name, const char *defn) 159 { 160 ndptr n = create_entry(name); 161 if (n->d != NULL) { 162 if (n->d->defn != null) 163 free_definition(n->d->defn); 164 } else { 165 n->d = xalloc(sizeof(struct macro_definition), NULL); 166 n->d->next = NULL; 167 } 168 setup_definition(n->d, defn, name); 169 } 170 171 void 172 macro_pushdef(const char *name, const char *defn) 173 { 174 ndptr n; 175 struct macro_definition *d; 176 177 n = create_entry(name); 178 d = xalloc(sizeof(struct macro_definition), NULL); 179 d->next = n->d; 180 n->d = d; 181 setup_definition(n->d, defn, name); 182 } 183 184 void 185 macro_undefine(const char *name) 186 { 187 ndptr n = lookup(name); 188 if (n != NULL) { 189 struct macro_definition *r, *r2; 190 191 for (r = n->d; r != NULL; r = r2) { 192 r2 = r->next; 193 if (r->defn != null) 194 free(r->defn); 195 free(r); 196 } 197 n->d = NULL; 198 } 199 } 200 201 void 202 macro_popdef(const char *name) 203 { 204 ndptr n = lookup(name); 205 206 if (n != NULL) { 207 struct macro_definition *r = n->d; 208 if (r != NULL) { 209 n->d = r->next; 210 if (r->defn != null) 211 free(r->defn); 212 free(r); 213 } 214 } 215 } 216 217 void 218 macro_for_all(void (*f)(const char *, struct macro_definition *)) 219 { 220 ndptr n; 221 unsigned int i; 222 223 for (n = ohash_first(¯os, &i); n != NULL; 224 n = ohash_next(¯os, &i)) 225 if (n->d != NULL) 226 f(n->name, n->d); 227 } 228 229 void 230 setup_builtin(const char *name, unsigned int type) 231 { 232 ndptr n; 233 char *name2; 234 235 if (prefix_builtins) { 236 name2 = xalloc(strlen(name)+3+1, NULL); 237 memcpy(name2, "m4_", 3); 238 memcpy(name2 + 3, name, strlen(name)+1); 239 } else 240 name2 = xstrdup(name); 241 242 n = create_entry(name2); 243 n->builtin_type = type; 244 n->d = xalloc(sizeof(struct macro_definition), NULL); 245 n->d->defn = name2; 246 n->d->type = type; 247 n->d->next = NULL; 248 } 249 250 void 251 mark_traced(const char *name, int on) 252 { 253 ndptr p; 254 unsigned int i; 255 256 if (name == NULL) { 257 if (on) 258 trace_flags |= TRACE_ALL; 259 else 260 trace_flags &= ~TRACE_ALL; 261 for (p = ohash_first(¯os, &i); p != NULL; 262 p = ohash_next(¯os, &i)) 263 p->trace_flags = FLAG_NO_TRACE; 264 } else { 265 p = create_entry(name); 266 p->trace_flags = on; 267 } 268 } 269 270 ndptr 271 macro_getbuiltin(const char *name) 272 { 273 ndptr p; 274 275 p = lookup(name); 276 if (p == NULL || p->builtin_type == MACRTYPE) 277 return NULL; 278 else 279 return p; 280 } 281 282 /* XXX things are slightly more complicated than they seem. 283 * a macro may actually be "live" (in the middle of an expansion 284 * on the stack. 285 * So we actually may need to place it in an array for later... 286 */ 287 288 static int kept_capacity = 0; 289 static int kept_size = 0; 290 static char **kept = NULL; 291 292 static void 293 keep(char *ptr) 294 { 295 if (kept_capacity <= kept_size) { 296 if (kept_capacity) 297 kept_capacity *= 2; 298 else 299 kept_capacity = 50; 300 kept = xreallocarray(kept, kept_capacity, 301 sizeof(char *), "Out of memory while saving %d strings\n", 302 kept_capacity); 303 } 304 kept[kept_size++] = ptr; 305 } 306 307 static int 308 string_in_use(const char *ptr) 309 { 310 int i; 311 for (i = 0; i <= sp; i++) { 312 if (sstack[i] == STORAGE_MACRO && mstack[i].sstr == ptr) 313 return 1; 314 } 315 return 0; 316 } 317 318 319 static void 320 free_definition(char *ptr) 321 { 322 int i; 323 324 /* first try to free old strings */ 325 for (i = 0; i < kept_size; i++) { 326 if (!string_in_use(kept[i])) { 327 kept_size--; 328 free(kept[i]); 329 if (i != kept_size) 330 kept[i] = kept[kept_size]; 331 i--; 332 } 333 } 334 335 /* then deal with us */ 336 if (string_in_use(ptr)) 337 keep(ptr); 338 else 339 free(ptr); 340 } 341 342