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 56static void *hash_calloc(size_t, size_t, void *); 57static void hash_free(void *, void *); 58static void *element_alloc(size_t, void *); 59static void setup_definition(struct macro_definition *, const char *, 60 const char *); 61static void free_definition(char *); 62static void keep(char *); 63static int string_in_use(const char *); 64 65static struct ohash_info macro_info = { 66 offsetof(struct ndblock, name), 67 NULL, hash_calloc, hash_free, element_alloc }; 68 69struct ohash macros; 70 71/* Support routines for hash tables. */ 72void * 73hash_calloc(size_t n, size_t s, void *u __unused) 74{ 75 void *storage = xcalloc(n, s, "hash alloc"); 76 return storage; 77} 78 79void 80hash_free(void *p, void *u __unused) 81{ 82 free(p); 83} 84 85void * 86element_alloc(size_t s, void *u __unused) 87{ 88 return xalloc(s, "element alloc"); 89} 90 91void 92init_macros(void) 93{ 94 ohash_init(¯os, 10, ¯o_info); 95} 96 97/* 98 * find name in the hash table 99 */ 100ndptr 101lookup(const char *name) 102{ 103 return ohash_find(¯os, ohash_qlookup(¯os, name)); 104} 105 106struct macro_definition * 107lookup_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 118static void 119setup_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 138static ndptr 139create_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 157void 158macro_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 171void 172macro_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 184void 185macro_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 201void 202macro_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 217void 218macro_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 229void 230setup_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 250void 251mark_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 270ndptr 271macro_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 288static int kept_capacity = 0; 289static int kept_size = 0; 290static char **kept = NULL; 291 292static void 293keep(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 307static int 308string_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 319static void 320free_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