tyname.c revision 1.57
1/*	$NetBSD: tyname.c,v 1.57 2023/08/02 18:51:25 rillig Exp $	*/
2
3/*-
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#if HAVE_NBTOOL_CONFIG_H
33#include "nbtool_config.h"
34#endif
35
36#include <sys/cdefs.h>
37#if defined(__RCSID)
38__RCSID("$NetBSD: tyname.c,v 1.57 2023/08/02 18:51:25 rillig Exp $");
39#endif
40
41#include <assert.h>
42#include <limits.h>
43#include <string.h>
44#include <stdlib.h>
45
46#if defined(IS_LINT1)
47#include "lint1.h"
48#else
49#include "lint2.h"
50#endif
51
52/* A tree of strings. */
53typedef struct name_tree_node {
54	const char *ntn_name;
55	struct name_tree_node *ntn_less;
56	struct name_tree_node *ntn_greater;
57} name_tree_node;
58
59/* A growable string buffer. */
60typedef struct buffer {
61	size_t	len;
62	size_t	cap;
63	char *	data;
64} buffer;
65
66static name_tree_node *type_names;
67
68static name_tree_node *
69new_name_tree_node(const char *name)
70{
71	name_tree_node *n;
72
73	n = xmalloc(sizeof(*n));
74	n->ntn_name = xstrdup(name);
75	n->ntn_less = NULL;
76	n->ntn_greater = NULL;
77	return n;
78}
79
80/* Return the canonical instance of the string, with unlimited lifetime. */
81static const char *
82intern(const char *name)
83{
84	name_tree_node *n = type_names, **next;
85	int cmp;
86
87	if (n == NULL) {
88		n = new_name_tree_node(name);
89		type_names = n;
90		return n->ntn_name;
91	}
92
93	while ((cmp = strcmp(name, n->ntn_name)) != 0) {
94		next = cmp < 0 ? &n->ntn_less : &n->ntn_greater;
95		if (*next == NULL) {
96			*next = new_name_tree_node(name);
97			return (*next)->ntn_name;
98		}
99		n = *next;
100	}
101	return n->ntn_name;
102}
103
104static void
105buf_init(buffer *buf)
106{
107	buf->len = 0;
108	buf->cap = 128;
109	buf->data = xmalloc(buf->cap);
110	buf->data[0] = '\0';
111}
112
113static void
114buf_done(buffer *buf)
115{
116	free(buf->data);
117}
118
119static void
120buf_add(buffer *buf, const char *s)
121{
122	size_t len = strlen(s);
123
124	while (buf->len + len + 1 >= buf->cap) {
125		buf->data = xrealloc(buf->data, 2 * buf->cap);
126		buf->cap = 2 * buf->cap;
127	}
128
129	memcpy(buf->data + buf->len, s, len + 1);
130	buf->len += len;
131}
132
133static void
134buf_add_int(buffer *buf, int n)
135{
136	char num[1 + sizeof(n) * CHAR_BIT + 1];
137
138	(void)snprintf(num, sizeof(num), "%d", n);
139	buf_add(buf, num);
140}
141
142const char *
143tspec_name(tspec_t t)
144{
145	const char *name = ttab[t].tt_name;
146	assert(name != NULL);
147	return name;
148}
149
150static void
151type_name_of_function(buffer *buf, const type_t *tp)
152{
153	const char *sep = "";
154
155	buf_add(buf, "(");
156	if (tp->t_proto) {
157#ifdef IS_LINT1
158		const sym_t *param = tp->t_params;
159		if (param == NULL)
160			buf_add(buf, "void");
161		for (; param != NULL; param = param->s_next) {
162			buf_add(buf, sep), sep = ", ";
163			buf_add(buf, type_name(param->s_type));
164		}
165#else
166		type_t **argtype;
167
168		argtype = tp->t_args;
169		if (argtype == NULL)
170			buf_add(buf, "void");
171		for (; *argtype != NULL; argtype++) {
172			buf_add(buf, sep), sep = ", ";
173			buf_add(buf, type_name(*argtype));
174		}
175#endif
176	}
177	if (tp->t_vararg) {
178		buf_add(buf, sep);
179		buf_add(buf, "...");
180	}
181	buf_add(buf, ") returning ");
182	buf_add(buf, type_name(tp->t_subt));
183}
184
185static void
186type_name_of_struct_or_union(buffer *buf, const type_t *tp)
187{
188	buf_add(buf, " ");
189#ifdef IS_LINT1
190	if (tp->t_sou->sou_tag->s_name == unnamed &&
191	    tp->t_sou->sou_first_typedef != NULL) {
192		buf_add(buf, "typedef ");
193		buf_add(buf, tp->t_sou->sou_first_typedef->s_name);
194	} else {
195		buf_add(buf, tp->t_sou->sou_tag->s_name);
196	}
197#else
198	buf_add(buf, tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
199#endif
200}
201
202static void
203type_name_of_enum(buffer *buf, const type_t *tp)
204{
205	buf_add(buf, " ");
206#ifdef IS_LINT1
207	if (tp->t_enum->en_tag->s_name == unnamed &&
208	    tp->t_enum->en_first_typedef != NULL) {
209		buf_add(buf, "typedef ");
210		buf_add(buf, tp->t_enum->en_first_typedef->s_name);
211	} else {
212		buf_add(buf, tp->t_enum->en_tag->s_name);
213	}
214#else
215	buf_add(buf, tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
216#endif
217}
218
219static void
220type_name_of_array(buffer *buf, const type_t *tp)
221{
222	buf_add(buf, "[");
223#ifdef IS_LINT1
224	if (tp->t_incomplete_array)
225		buf_add(buf, "unknown_size");
226	else
227		buf_add_int(buf, tp->t_dim);
228#else
229	buf_add_int(buf, tp->t_dim);
230#endif
231	buf_add(buf, "]");
232	buf_add(buf, " of ");
233	buf_add(buf, type_name(tp->t_subt));
234}
235
236const char *
237type_name(const type_t *tp)
238{
239	tspec_t t;
240	buffer buf;
241	const char *name;
242
243	if (tp == NULL)
244		return "(null)";
245
246	if ((t = tp->t_tspec) == INT && tp->t_is_enum)
247		t = ENUM;
248
249	buf_init(&buf);
250	if (tp->t_const)
251		buf_add(&buf, "const ");
252	if (tp->t_volatile)
253		buf_add(&buf, "volatile ");
254
255#ifdef IS_LINT1
256	if (is_struct_or_union(t) && tp->t_sou->sou_incomplete)
257		buf_add(&buf, "incomplete ");
258#endif
259	buf_add(&buf, tspec_name(t));
260
261#ifdef IS_LINT1
262	if (tp->t_bitfield) {
263		buf_add(&buf, ":");
264		buf_add_int(&buf, (int)tp->t_bit_field_width);
265	}
266#endif
267
268	switch (t) {
269	case PTR:
270		buf_add(&buf, " to ");
271		buf_add(&buf, type_name(tp->t_subt));
272		break;
273	case ENUM:
274		type_name_of_enum(&buf, tp);
275		break;
276	case STRUCT:
277	case UNION:
278		type_name_of_struct_or_union(&buf, tp);
279		break;
280	case ARRAY:
281		type_name_of_array(&buf, tp);
282		break;
283	case FUNC:
284		type_name_of_function(&buf, tp);
285		break;
286	default:
287		break;
288	}
289
290	name = intern(buf.data);
291	buf_done(&buf);
292	return name;
293}
294