tyname.c revision 1.56
1/*	$NetBSD: tyname.c,v 1.56 2023/06/29 12:52:06 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.56 2023/06/29 12:52:06 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		sym_t *arg;
159
160		arg = tp->t_args;
161		if (arg == NULL)
162			buf_add(buf, "void");
163		for (; arg != NULL; arg = arg->s_next) {
164			buf_add(buf, sep), sep = ", ";
165			buf_add(buf, type_name(arg->s_type));
166		}
167#else
168		type_t **argtype;
169
170		argtype = tp->t_args;
171		if (argtype == NULL)
172			buf_add(buf, "void");
173		for (; *argtype != NULL; argtype++) {
174			buf_add(buf, sep), sep = ", ";
175			buf_add(buf, type_name(*argtype));
176		}
177#endif
178	}
179	if (tp->t_vararg) {
180		buf_add(buf, sep);
181		buf_add(buf, "...");
182	}
183	buf_add(buf, ") returning ");
184	buf_add(buf, type_name(tp->t_subt));
185}
186
187static void
188type_name_of_struct_or_union(buffer *buf, const type_t *tp)
189{
190	buf_add(buf, " ");
191#ifdef IS_LINT1
192	if (tp->t_sou->sou_tag->s_name == unnamed &&
193	    tp->t_sou->sou_first_typedef != NULL) {
194		buf_add(buf, "typedef ");
195		buf_add(buf, tp->t_sou->sou_first_typedef->s_name);
196	} else {
197		buf_add(buf, tp->t_sou->sou_tag->s_name);
198	}
199#else
200	buf_add(buf, tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
201#endif
202}
203
204static void
205type_name_of_enum(buffer *buf, const type_t *tp)
206{
207	buf_add(buf, " ");
208#ifdef IS_LINT1
209	if (tp->t_enum->en_tag->s_name == unnamed &&
210	    tp->t_enum->en_first_typedef != NULL) {
211		buf_add(buf, "typedef ");
212		buf_add(buf, tp->t_enum->en_first_typedef->s_name);
213	} else {
214		buf_add(buf, tp->t_enum->en_tag->s_name);
215	}
216#else
217	buf_add(buf, tp->t_isuniqpos ? "*anonymous*" : tp->t_tag->h_name);
218#endif
219}
220
221static void
222type_name_of_array(buffer *buf, const type_t *tp)
223{
224	buf_add(buf, "[");
225#ifdef IS_LINT1
226	if (tp->t_incomplete_array)
227		buf_add(buf, "unknown_size");
228	else
229		buf_add_int(buf, tp->t_dim);
230#else
231	buf_add_int(buf, tp->t_dim);
232#endif
233	buf_add(buf, "]");
234	buf_add(buf, " of ");
235	buf_add(buf, type_name(tp->t_subt));
236}
237
238const char *
239type_name(const type_t *tp)
240{
241	tspec_t t;
242	buffer buf;
243	const char *name;
244
245	if (tp == NULL)
246		return "(null)";
247
248	if ((t = tp->t_tspec) == INT && tp->t_is_enum)
249		t = ENUM;
250
251	buf_init(&buf);
252	if (tp->t_const)
253		buf_add(&buf, "const ");
254	if (tp->t_volatile)
255		buf_add(&buf, "volatile ");
256
257#ifdef IS_LINT1
258	if (is_struct_or_union(t) && tp->t_sou->sou_incomplete)
259		buf_add(&buf, "incomplete ");
260#endif
261	buf_add(&buf, tspec_name(t));
262
263#ifdef IS_LINT1
264	if (tp->t_bitfield) {
265		buf_add(&buf, ":");
266		buf_add_int(&buf, (int)tp->t_bit_field_width);
267	}
268#endif
269
270	switch (t) {
271	case PTR:
272		buf_add(&buf, " to ");
273		buf_add(&buf, type_name(tp->t_subt));
274		break;
275	case ENUM:
276		type_name_of_enum(&buf, tp);
277		break;
278	case STRUCT:
279	case UNION:
280		type_name_of_struct_or_union(&buf, tp);
281		break;
282	case ARRAY:
283		type_name_of_array(&buf, tp);
284		break;
285	case FUNC:
286		type_name_of_function(&buf, tp);
287		break;
288	default:
289		break;
290	}
291
292	name = intern(buf.data);
293	buf_done(&buf);
294	return name;
295}
296