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 /* 38 * look.c 39 * Facility: m4 macro processor 40 * by: oz 41 */ 42 43 #include <sys/types.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <stdint.h> 47 #include <stddef.h> 48 #include <string.h> 49 #include <ohash.h> 50 #include "mdef.h" 51 #include "stdd.h" 52 #include "extern.h" 53 54 static void *hash_calloc(size_t, size_t, void *); 55 static void hash_free(void *, void *); 56 static void *element_alloc(size_t, void *); 57 static void setup_definition(struct macro_definition *, const char *, 58 const char *); 59 static void free_definition(char *); 60 static void keep(char *); 61 static int string_in_use(const char *); 62 63 static struct ohash_info macro_info = { 64 offsetof(struct ndblock, name), 65 NULL, hash_calloc, hash_free, element_alloc }; 66 67 struct ohash macros; 68 69 /* Support routines for hash tables. */ 70 void * 71 hash_calloc(size_t n, size_t s, void *u __unused) 72 { 73 void *storage = xcalloc(n, s, "hash alloc"); 74 return storage; 75 } 76 77 void 78 hash_free(void *p, void *u __unused) 79 { 80 free(p); 81 } 82 83 void * 84 element_alloc(size_t s, void *u __unused) 85 { 86 return xalloc(s, "element alloc"); 87 } 88 89 void 90 init_macros(void) 91 { 92 ohash_init(¯os, 10, ¯o_info); 93 } 94 95 /* 96 * find name in the hash table 97 */ 98 ndptr 99 lookup(const char *name) 100 { 101 return ohash_find(¯os, ohash_qlookup(¯os, name)); 102 } 103 104 struct macro_definition * 105 lookup_macro_definition(const char *name) 106 { 107 ndptr p; 108 109 p = ohash_find(¯os, ohash_qlookup(¯os, name)); 110 if (p) 111 return p->d; 112 else 113 return NULL; 114 } 115 116 static void 117 setup_definition(struct macro_definition *d, const char *defn, const char *name) 118 { 119 ndptr p; 120 121 if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0 && 122 (p = macro_getbuiltin(defn+sizeof(BUILTIN_MARKER)-1)) != NULL) { 123 d->type = macro_builtin_type(p); 124 d->defn = xstrdup(defn+sizeof(BUILTIN_MARKER)-1); 125 } else { 126 if (!*defn) 127 d->defn = __DECONST(char *, null); 128 else 129 d->defn = xstrdup(defn); 130 d->type = MACRTYPE; 131 } 132 if (STREQ(name, defn)) 133 d->type |= RECDEF; 134 } 135 136 static ndptr 137 create_entry(const char *name) 138 { 139 const char *end = NULL; 140 unsigned int i; 141 ndptr n; 142 143 i = ohash_qlookupi(¯os, name, &end); 144 n = ohash_find(¯os, i); 145 if (n == NULL) { 146 n = ohash_create_entry(¯o_info, name, &end); 147 ohash_insert(¯os, i, n); 148 n->trace_flags = FLAG_NO_TRACE; 149 n->builtin_type = MACRTYPE; 150 n->d = NULL; 151 } 152 return n; 153 } 154 155 void 156 macro_define(const char *name, const char *defn) 157 { 158 ndptr n = create_entry(name); 159 if (n->d != NULL) { 160 if (n->d->defn != null) 161 free_definition(n->d->defn); 162 } else { 163 n->d = xalloc(sizeof(struct macro_definition), NULL); 164 n->d->next = NULL; 165 } 166 setup_definition(n->d, defn, name); 167 } 168 169 void 170 macro_pushdef(const char *name, const char *defn) 171 { 172 ndptr n; 173 struct macro_definition *d; 174 175 n = create_entry(name); 176 d = xalloc(sizeof(struct macro_definition), NULL); 177 d->next = n->d; 178 n->d = d; 179 setup_definition(n->d, defn, name); 180 } 181 182 void 183 macro_undefine(const char *name) 184 { 185 ndptr n = lookup(name); 186 if (n != NULL) { 187 struct macro_definition *r, *r2; 188 189 for (r = n->d; r != NULL; r = r2) { 190 r2 = r->next; 191 if (r->defn != null) 192 free(r->defn); 193 free(r); 194 } 195 n->d = NULL; 196 } 197 } 198 199 void 200 macro_popdef(const char *name) 201 { 202 ndptr n = lookup(name); 203 204 if (n != NULL) { 205 struct macro_definition *r = n->d; 206 if (r != NULL) { 207 n->d = r->next; 208 if (r->defn != null) 209 free(r->defn); 210 free(r); 211 } 212 } 213 } 214 215 void 216 macro_for_all(void (*f)(const char *, struct macro_definition *)) 217 { 218 ndptr n; 219 unsigned int i; 220 221 for (n = ohash_first(¯os, &i); n != NULL; 222 n = ohash_next(¯os, &i)) 223 if (n->d != NULL) 224 f(n->name, n->d); 225 } 226 227 void 228 setup_builtin(const char *name, unsigned int type) 229 { 230 ndptr n; 231 char *name2; 232 233 if (prefix_builtins) { 234 name2 = xalloc(strlen(name)+3+1, NULL); 235 memcpy(name2, "m4_", 3); 236 memcpy(name2 + 3, name, strlen(name)+1); 237 } else 238 name2 = xstrdup(name); 239 240 n = create_entry(name2); 241 n->builtin_type = type; 242 n->d = xalloc(sizeof(struct macro_definition), NULL); 243 n->d->defn = name2; 244 n->d->type = type; 245 n->d->next = NULL; 246 } 247 248 void 249 mark_traced(const char *name, int on) 250 { 251 ndptr p; 252 unsigned int i; 253 254 if (name == NULL) { 255 if (on) 256 trace_flags |= TRACE_ALL; 257 else 258 trace_flags &= ~TRACE_ALL; 259 for (p = ohash_first(¯os, &i); p != NULL; 260 p = ohash_next(¯os, &i)) 261 p->trace_flags = FLAG_NO_TRACE; 262 } else { 263 p = create_entry(name); 264 p->trace_flags = on; 265 } 266 } 267 268 ndptr 269 macro_getbuiltin(const char *name) 270 { 271 ndptr p; 272 273 p = lookup(name); 274 if (p == NULL || p->builtin_type == MACRTYPE) 275 return NULL; 276 else 277 return p; 278 } 279 280 /* XXX things are slightly more complicated than they seem. 281 * a macro may actually be "live" (in the middle of an expansion 282 * on the stack. 283 * So we actually may need to place it in an array for later... 284 */ 285 286 static int kept_capacity = 0; 287 static int kept_size = 0; 288 static char **kept = NULL; 289 290 static void 291 keep(char *ptr) 292 { 293 if (kept_capacity <= kept_size) { 294 if (kept_capacity) 295 kept_capacity *= 2; 296 else 297 kept_capacity = 50; 298 kept = xreallocarray(kept, kept_capacity, 299 sizeof(char *), "Out of memory while saving %d strings\n", 300 kept_capacity); 301 } 302 kept[kept_size++] = ptr; 303 } 304 305 static int 306 string_in_use(const char *ptr) 307 { 308 int i; 309 for (i = 0; i <= sp; i++) { 310 if (sstack[i] == STORAGE_MACRO && mstack[i].sstr == ptr) 311 return 1; 312 } 313 return 0; 314 } 315 316 317 static void 318 free_definition(char *ptr) 319 { 320 int i; 321 322 /* first try to free old strings */ 323 for (i = 0; i < kept_size; i++) { 324 if (!string_in_use(kept[i])) { 325 kept_size--; 326 free(kept[i]); 327 if (i != kept_size) 328 kept[i] = kept[kept_size]; 329 i--; 330 } 331 } 332 333 /* then deal with us */ 334 if (string_in_use(ptr)) 335 keep(ptr); 336 else 337 free(ptr); 338 } 339 340