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