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(&macros, 10, &macro_info);
95}
96
97/*
98 * find name in the hash table
99 */
100ndptr
101lookup(const char *name)
102{
103	return ohash_find(&macros, ohash_qlookup(&macros, name));
104}
105
106struct macro_definition *
107lookup_macro_definition(const char *name)
108{
109	ndptr p;
110
111	p = ohash_find(&macros, ohash_qlookup(&macros, 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(&macros, name, &end);
146	n = ohash_find(&macros, i);
147	if (n == NULL) {
148		n = ohash_create_entry(&macro_info, name, &end);
149		ohash_insert(&macros, 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(&macros, &i); n != NULL;
224	    n = ohash_next(&macros, &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(&macros, &i); p != NULL;
262		    p = ohash_next(&macros, &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