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 54static void *hash_calloc(size_t, size_t, void *); 55static void hash_free(void *, void *); 56static void *element_alloc(size_t, void *); 57static void setup_definition(struct macro_definition *, const char *, 58 const char *); 59static void free_definition(char *); 60static void keep(char *); 61static int string_in_use(const char *); 62 63static struct ohash_info macro_info = { 64 offsetof(struct ndblock, name), 65 NULL, hash_calloc, hash_free, element_alloc }; 66 67struct ohash macros; 68 69/* Support routines for hash tables. */ 70void * 71hash_calloc(size_t n, size_t s, void *u __unused) 72{ 73 void *storage = xcalloc(n, s, "hash alloc"); 74 return storage; 75} 76 77void 78hash_free(void *p, void *u __unused) 79{ 80 free(p); 81} 82 83void * 84element_alloc(size_t s, void *u __unused) 85{ 86 return xalloc(s, "element alloc"); 87} 88 89void 90init_macros(void) 91{ 92 ohash_init(¯os, 10, ¯o_info); 93} 94 95/* 96 * find name in the hash table 97 */ 98ndptr 99lookup(const char *name) 100{ 101 return ohash_find(¯os, ohash_qlookup(¯os, name)); 102} 103 104struct macro_definition * 105lookup_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 116static void 117setup_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 136static ndptr 137create_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 155void 156macro_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 169void 170macro_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 182void 183macro_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 199void 200macro_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 215void 216macro_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 227void 228setup_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 248void 249mark_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 268ndptr 269macro_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 286static int kept_capacity = 0; 287static int kept_size = 0; 288static char **kept = NULL; 289 290static void 291keep(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 305static int 306string_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 317static void 318free_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