Home | History | Annotate | Line # | Download | only in m4
      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(&macros, 10, &macro_info);
     98 }
     99 
    100 /*
    101  * find name in the hash table
    102  */
    103 ndptr
    104 lookup(const char *name)
    105 {
    106 	return ohash_find(&macros, ohash_qlookup(&macros, name));
    107 }
    108 
    109 struct macro_definition *
    110 lookup_macro_definition(const char *name)
    111 {
    112 	ndptr p;
    113 
    114 	p = ohash_find(&macros, ohash_qlookup(&macros, 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(&macros, name, &end);
    149 	n = ohash_find(&macros, i);
    150 	if (n == NULL) {
    151 		n = ohash_create_entry(&macro_info, name, &end);
    152 		ohash_insert(&macros, 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(&macros, &i); n != NULL;
    227 	    n = ohash_next(&macros, &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(&macros, &i); p != NULL;
    265 		    p = ohash_next(&macros, &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(&macros, &i); n != NULL;
    376 	    n = ohash_next(&macros, &i))
    377 		dump_entry(f, n);
    378 }
    379 #endif
    380