1de572d98SGarrett D'Amore /*
2de572d98SGarrett D'Amore  * This file and its contents are supplied under the terms of the
3de572d98SGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
4de572d98SGarrett D'Amore  * You may only use this file in accordance with the terms of version
5de572d98SGarrett D'Amore  * 1.0 of the CDDL.
6de572d98SGarrett D'Amore  *
7de572d98SGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
8de572d98SGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
9de572d98SGarrett D'Amore  * http://www.illumos.org/license/CDDL.
10de572d98SGarrett D'Amore  */
11de572d98SGarrett D'Amore 
12de572d98SGarrett D'Amore /*
13de572d98SGarrett D'Amore  * Copyright 2015 Garrett D'Amore <garrett@damore.org>
14500cf85bSJason King  * Copyright 2018 Joyent, Inc.
15de572d98SGarrett D'Amore  */
16de572d98SGarrett D'Amore 
17de572d98SGarrett D'Amore /*
18fc2512cfSRobert Mustacchi  * This program tests symbol visibility in different compilation environments.
19de572d98SGarrett D'Amore  */
20de572d98SGarrett D'Amore 
21de572d98SGarrett D'Amore #include <stdio.h>
22de572d98SGarrett D'Amore #include <stdlib.h>
23de572d98SGarrett D'Amore #include <string.h>
24de572d98SGarrett D'Amore #include <errno.h>
25de572d98SGarrett D'Amore #include <err.h>
26de572d98SGarrett D'Amore #include <unistd.h>
27de572d98SGarrett D'Amore #include <sys/types.h>
28de572d98SGarrett D'Amore #include <sys/stat.h>
29de572d98SGarrett D'Amore #include <note.h>
30500cf85bSJason King #include <libcustr.h>
31de572d98SGarrett D'Amore #include <sys/wait.h>
32de572d98SGarrett D'Amore #include "test_common.h"
33de572d98SGarrett D'Amore 
34de572d98SGarrett D'Amore char *dname;
35de572d98SGarrett D'Amore char *cfile;
36de572d98SGarrett D'Amore char *ofile;
37de572d98SGarrett D'Amore char *lfile;
38de572d98SGarrett D'Amore char *efile;
39de572d98SGarrett D'Amore 
40de572d98SGarrett D'Amore const char *sym = NULL;
41de572d98SGarrett D'Amore 
42de572d98SGarrett D'Amore static int good_count = 0;
43de572d98SGarrett D'Amore static int fail_count = 0;
44de572d98SGarrett D'Amore static int full_count = 0;
45de572d98SGarrett D'Amore static int extra_debug = 0;
46de572d98SGarrett D'Amore static char *compilation = "compilation.cfg";
47de572d98SGarrett D'Amore 
48de572d98SGarrett D'Amore #if defined(_LP64)
49de572d98SGarrett D'Amore #define	MFLAG "-m64"
50de572d98SGarrett D'Amore #elif defined(_ILP32)
51de572d98SGarrett D'Amore #define	MFLAG "-m32"
52de572d98SGarrett D'Amore #endif
53de572d98SGarrett D'Amore 
54de572d98SGarrett D'Amore const char *compilers[] = {
55de572d98SGarrett D'Amore 	"cc",
56de572d98SGarrett D'Amore 	"gcc",
57de572d98SGarrett D'Amore 	"/opt/SUNWspro/bin/cc",
58de572d98SGarrett D'Amore 	"/opt/gcc/4.4.4/bin/gcc",
59de572d98SGarrett D'Amore 	"/opt/sunstudio12.1/bin/cc",
60de572d98SGarrett D'Amore 	"/opt/sfw/bin/gcc",
61de572d98SGarrett D'Amore 	"/usr/local/bin/gcc",
62de572d98SGarrett D'Amore 	NULL
63de572d98SGarrett D'Amore };
64de572d98SGarrett D'Amore 
65de572d98SGarrett D'Amore char *compiler = NULL;
66de572d98SGarrett D'Amore const char *c89flags = NULL;
67de572d98SGarrett D'Amore const char *c99flags = NULL;
68fc2512cfSRobert Mustacchi const char *c11flags = NULL;
69de572d98SGarrett D'Amore 
70de572d98SGarrett D'Amore #define	MAXENV	64	/* maximum number of environments (bitmask width) */
71de572d98SGarrett D'Amore #define	MAXHDR	10	/* maximum # headers to require to access symbol */
72de572d98SGarrett D'Amore #define	MAXARG	20	/* maximum # of arguments */
73de572d98SGarrett D'Amore 
74de572d98SGarrett D'Amore #define	WS	" \t"
75de572d98SGarrett D'Amore 
76de572d98SGarrett D'Amore static int next_env = 0;
77de572d98SGarrett D'Amore 
78de572d98SGarrett D'Amore struct compile_env {
79de572d98SGarrett D'Amore 	char		*ce_name;
80de572d98SGarrett D'Amore 	char		*ce_lang;
81de572d98SGarrett D'Amore 	char		*ce_defs;
82de572d98SGarrett D'Amore 	int		ce_index;
83de572d98SGarrett D'Amore };
84de572d98SGarrett D'Amore 
85de572d98SGarrett D'Amore static struct compile_env compile_env[MAXENV];
86de572d98SGarrett D'Amore 
87de572d98SGarrett D'Amore struct env_group {
88de572d98SGarrett D'Amore 	char			*eg_name;
89de572d98SGarrett D'Amore 	uint64_t		eg_mask;
90de572d98SGarrett D'Amore 	struct env_group	*eg_next;
91de572d98SGarrett D'Amore };
92de572d98SGarrett D'Amore 
93fc2512cfSRobert Mustacchi typedef enum {
94fc2512cfSRobert Mustacchi 	SYM_TYPE,
95fc2512cfSRobert Mustacchi 	SYM_VALUE,
96fc2512cfSRobert Mustacchi 	SYM_DEFINE,
97fc2512cfSRobert Mustacchi 	SYM_FUNC
98fc2512cfSRobert Mustacchi } sym_type_t;
99de572d98SGarrett D'Amore 
100de572d98SGarrett D'Amore struct sym_test {
101de572d98SGarrett D'Amore 	char			*st_name;
102de572d98SGarrett D'Amore 	sym_type_t		st_type;
103de572d98SGarrett D'Amore 	char			*st_hdrs[MAXHDR];
104de572d98SGarrett D'Amore 	char			*st_rtype;
105de572d98SGarrett D'Amore 	char			*st_atypes[MAXARG];
106fc2512cfSRobert Mustacchi 	char			*st_defval;
107de572d98SGarrett D'Amore 	uint64_t		st_test_mask;
108de572d98SGarrett D'Amore 	uint64_t		st_need_mask;
109fc2512cfSRobert Mustacchi 	const char		*st_prog;
110de572d98SGarrett D'Amore 	struct sym_test		*st_next;
111de572d98SGarrett D'Amore };
112de572d98SGarrett D'Amore 
113de572d98SGarrett D'Amore struct env_group *env_groups = NULL;
114de572d98SGarrett D'Amore 
115de572d98SGarrett D'Amore struct sym_test *sym_tests = NULL;
116de572d98SGarrett D'Amore struct sym_test **sym_insert = &sym_tests;
117de572d98SGarrett D'Amore 
118de572d98SGarrett D'Amore static char *
mystrdup(const char * s)119de572d98SGarrett D'Amore mystrdup(const char *s)
120de572d98SGarrett D'Amore {
121de572d98SGarrett D'Amore 	char *r;
122de572d98SGarrett D'Amore 	if ((r = strdup(s)) == NULL) {
123de572d98SGarrett D'Amore 		perror("strdup");
124de572d98SGarrett D'Amore 		exit(1);
125de572d98SGarrett D'Amore 	}
126de572d98SGarrett D'Amore 	return (r);
127de572d98SGarrett D'Amore }
128de572d98SGarrett D'Amore 
129de572d98SGarrett D'Amore static void *
myzalloc(size_t sz)130de572d98SGarrett D'Amore myzalloc(size_t sz)
131de572d98SGarrett D'Amore {
132de572d98SGarrett D'Amore 	void *buf;
133de572d98SGarrett D'Amore 	if ((buf = calloc(1, sz)) == NULL) {
134de572d98SGarrett D'Amore 		perror("calloc");
135de572d98SGarrett D'Amore 		exit(1);
136de572d98SGarrett D'Amore 	}
137de572d98SGarrett D'Amore 	return (buf);
138de572d98SGarrett D'Amore }
139de572d98SGarrett D'Amore 
140de572d98SGarrett D'Amore static void
myasprintf(char ** buf,const char * fmt,...)141de572d98SGarrett D'Amore myasprintf(char **buf, const char *fmt, ...)
142de572d98SGarrett D'Amore {
143de572d98SGarrett D'Amore 	int rv;
144de572d98SGarrett D'Amore 	va_list va;
145de572d98SGarrett D'Amore 	va_start(va, fmt);
146de572d98SGarrett D'Amore 	rv = vasprintf(buf, fmt, va);
147de572d98SGarrett D'Amore 	va_end(va);
148de572d98SGarrett D'Amore 	if (rv < 0) {
149de572d98SGarrett D'Amore 		perror("vasprintf");
150de572d98SGarrett D'Amore 		exit(1);
151de572d98SGarrett D'Amore 	}
152de572d98SGarrett D'Amore }
153de572d98SGarrett D'Amore 
154de572d98SGarrett D'Amore static void
append_sym_test(struct sym_test * st)155de572d98SGarrett D'Amore append_sym_test(struct sym_test *st)
156de572d98SGarrett D'Amore {
157de572d98SGarrett D'Amore 	*sym_insert = st;
158de572d98SGarrett D'Amore 	sym_insert = &st->st_next;
159de572d98SGarrett D'Amore }
160de572d98SGarrett D'Amore 
161de572d98SGarrett D'Amore static int
find_env_mask(const char * name,uint64_t * mask)162de572d98SGarrett D'Amore find_env_mask(const char *name, uint64_t *mask)
163de572d98SGarrett D'Amore {
164de572d98SGarrett D'Amore 	for (int i = 0; i < MAXENV; i++) {
165de572d98SGarrett D'Amore 		if (compile_env[i].ce_name != NULL &&
166de572d98SGarrett D'Amore 		    strcmp(compile_env[i].ce_name, name) == 0) {
167de572d98SGarrett D'Amore 			*mask |= (1ULL << i);
168de572d98SGarrett D'Amore 			return (0);
169de572d98SGarrett D'Amore 		}
170de572d98SGarrett D'Amore 	}
171de572d98SGarrett D'Amore 
172de572d98SGarrett D'Amore 	for (struct env_group *eg = env_groups; eg != NULL; eg = eg->eg_next) {
173de572d98SGarrett D'Amore 		if (strcmp(name, eg->eg_name) == 0) {
174de572d98SGarrett D'Amore 			*mask |= eg->eg_mask;
175de572d98SGarrett D'Amore 			return (0);
176de572d98SGarrett D'Amore 		}
177de572d98SGarrett D'Amore 	}
178de572d98SGarrett D'Amore 	return (-1);
179de572d98SGarrett D'Amore }
180de572d98SGarrett D'Amore 
181de572d98SGarrett D'Amore 
182de572d98SGarrett D'Amore static int
expand_env(char * list,uint64_t * mask,char ** erritem)183de572d98SGarrett D'Amore expand_env(char *list, uint64_t *mask, char **erritem)
184de572d98SGarrett D'Amore {
185de572d98SGarrett D'Amore 	char *item;
186de572d98SGarrett D'Amore 	for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) {
187de572d98SGarrett D'Amore 		if (find_env_mask(item, mask) < 0) {
188de572d98SGarrett D'Amore 			if (erritem != NULL) {
189de572d98SGarrett D'Amore 				*erritem = item;
190de572d98SGarrett D'Amore 			}
191de572d98SGarrett D'Amore 			return (-1);
192de572d98SGarrett D'Amore 		}
193de572d98SGarrett D'Amore 	}
194de572d98SGarrett D'Amore 	return (0);
195de572d98SGarrett D'Amore }
196de572d98SGarrett D'Amore 
197de572d98SGarrett D'Amore static int
expand_env_list(char * list,uint64_t * test,uint64_t * need,char ** erritem)198de572d98SGarrett D'Amore expand_env_list(char *list, uint64_t *test, uint64_t *need, char **erritem)
199de572d98SGarrett D'Amore {
200de572d98SGarrett D'Amore 	uint64_t mask = 0;
201de572d98SGarrett D'Amore 	int act;
202de572d98SGarrett D'Amore 	char *item;
203de572d98SGarrett D'Amore 	for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) {
204de572d98SGarrett D'Amore 		switch (item[0]) {
205de572d98SGarrett D'Amore 		case '+':
206de572d98SGarrett D'Amore 			act = 1;
207de572d98SGarrett D'Amore 			item++;
208de572d98SGarrett D'Amore 			break;
209de572d98SGarrett D'Amore 		case '-':
210de572d98SGarrett D'Amore 			act = 0;
211de572d98SGarrett D'Amore 			item++;
212de572d98SGarrett D'Amore 			break;
213de572d98SGarrett D'Amore 		default:
214de572d98SGarrett D'Amore 			act = 1;
215de572d98SGarrett D'Amore 			break;
216de572d98SGarrett D'Amore 		}
217de572d98SGarrett D'Amore 
218de572d98SGarrett D'Amore 		mask = 0;
219de572d98SGarrett D'Amore 		if (find_env_mask(item, &mask) < 0) {
220de572d98SGarrett D'Amore 			if (erritem != NULL) {
221de572d98SGarrett D'Amore 				*erritem = item;
222de572d98SGarrett D'Amore 			}
223de572d98SGarrett D'Amore 			return (-1);
224de572d98SGarrett D'Amore 		}
225de572d98SGarrett D'Amore 		*test |= mask;
226de572d98SGarrett D'Amore 		if (act) {
227de572d98SGarrett D'Amore 			*need |= mask;
228de572d98SGarrett D'Amore 		} else {
229de572d98SGarrett D'Amore 			*need &= ~(mask);
230de572d98SGarrett D'Amore 		}
231de572d98SGarrett D'Amore 	}
232de572d98SGarrett D'Amore 	return (0);
233de572d98SGarrett D'Amore }
234de572d98SGarrett D'Amore 
235de572d98SGarrett D'Amore static int
do_env(char ** fields,int nfields,char ** err)236de572d98SGarrett D'Amore do_env(char **fields, int nfields, char **err)
237de572d98SGarrett D'Amore {
238de572d98SGarrett D'Amore 	char *name;
239de572d98SGarrett D'Amore 	char *lang;
240de572d98SGarrett D'Amore 	char *defs;
241de572d98SGarrett D'Amore 
242de572d98SGarrett D'Amore 	if (nfields != 3) {
243de572d98SGarrett D'Amore 		myasprintf(err, "number of fields (%d) != 3", nfields);
244de572d98SGarrett D'Amore 		return (-1);
245de572d98SGarrett D'Amore 	}
246de572d98SGarrett D'Amore 
247de572d98SGarrett D'Amore 	if (next_env >= MAXENV) {
248de572d98SGarrett D'Amore 		myasprintf(err, "too many environments");
249de572d98SGarrett D'Amore 		return (-1);
250de572d98SGarrett D'Amore 	}
251de572d98SGarrett D'Amore 
252de572d98SGarrett D'Amore 	name = fields[0];
253de572d98SGarrett D'Amore 	lang = fields[1];
254de572d98SGarrett D'Amore 	defs = fields[2];
255de572d98SGarrett D'Amore 
256de572d98SGarrett D'Amore 	compile_env[next_env].ce_name = mystrdup(name);
257de572d98SGarrett D'Amore 	compile_env[next_env].ce_lang = mystrdup(lang);
258de572d98SGarrett D'Amore 	compile_env[next_env].ce_defs = mystrdup(defs);
259de572d98SGarrett D'Amore 	compile_env[next_env].ce_index = next_env;
260de572d98SGarrett D'Amore 	next_env++;
261de572d98SGarrett D'Amore 	return (0);
262de572d98SGarrett D'Amore }
263de572d98SGarrett D'Amore 
264de572d98SGarrett D'Amore static int
do_env_group(char ** fields,int nfields,char ** err)265de572d98SGarrett D'Amore do_env_group(char **fields, int nfields, char **err)
266de572d98SGarrett D'Amore {
267de572d98SGarrett D'Amore 	char *name;
268de572d98SGarrett D'Amore 	char *list;
269de572d98SGarrett D'Amore 	struct env_group *eg;
270de572d98SGarrett D'Amore 	uint64_t mask;
271de572d98SGarrett D'Amore 	char *item;
272de572d98SGarrett D'Amore 
273de572d98SGarrett D'Amore 	if (nfields != 2) {
274de572d98SGarrett D'Amore 		myasprintf(err, "number of fields (%d) != 2", nfields);
275de572d98SGarrett D'Amore 		return (-1);
276de572d98SGarrett D'Amore 	}
277de572d98SGarrett D'Amore 
278de572d98SGarrett D'Amore 	name = fields[0];
279de572d98SGarrett D'Amore 	list = fields[1];
280de572d98SGarrett D'Amore 	mask = 0;
281de572d98SGarrett D'Amore 
282de572d98SGarrett D'Amore 	if (expand_env(list, &mask, &item) < 0) {
283de572d98SGarrett D'Amore 		myasprintf(err, "reference to undefined env %s", item);
284de572d98SGarrett D'Amore 		return (-1);
285de572d98SGarrett D'Amore 	}
286de572d98SGarrett D'Amore 
287de572d98SGarrett D'Amore 	eg = myzalloc(sizeof (*eg));
288de572d98SGarrett D'Amore 	eg->eg_name = mystrdup(name);
289de572d98SGarrett D'Amore 	eg->eg_mask = mask;
290de572d98SGarrett D'Amore 	eg->eg_next = env_groups;
291de572d98SGarrett D'Amore 	env_groups = eg;
292de572d98SGarrett D'Amore 	return (0);
293de572d98SGarrett D'Amore }
294de572d98SGarrett D'Amore 
295fc2512cfSRobert Mustacchi static custr_t *st_custr;
296de572d98SGarrett D'Amore 
297de572d98SGarrett D'Amore static void
addprogch(char c)298de572d98SGarrett D'Amore addprogch(char c)
299de572d98SGarrett D'Amore {
300fc2512cfSRobert Mustacchi 	if (custr_appendc(st_custr, c) == -1) {
301fc2512cfSRobert Mustacchi 		perror("custr_appendc");
302fc2512cfSRobert Mustacchi 		exit(1);
303de572d98SGarrett D'Amore 	}
304de572d98SGarrett D'Amore }
305de572d98SGarrett D'Amore 
306de572d98SGarrett D'Amore static void
addprogstr(char * s)307de572d98SGarrett D'Amore addprogstr(char *s)
308de572d98SGarrett D'Amore {
309fc2512cfSRobert Mustacchi 	if (custr_append(st_custr, s) == -1) {
310fc2512cfSRobert Mustacchi 		perror("custr_append");
311fc2512cfSRobert Mustacchi 		exit(1);
312de572d98SGarrett D'Amore 	}
313de572d98SGarrett D'Amore }
314de572d98SGarrett D'Amore 
315de572d98SGarrett D'Amore static void
addprogfmt(const char * fmt,...)316de572d98SGarrett D'Amore addprogfmt(const char *fmt, ...)
317de572d98SGarrett D'Amore {
318de572d98SGarrett D'Amore 	va_list va;
319de572d98SGarrett D'Amore 	va_start(va, fmt);
320fc2512cfSRobert Mustacchi 	if (custr_append_vprintf(st_custr, fmt, va) == -1) {
321fc2512cfSRobert Mustacchi 		perror("custr_append_vprintf");
322de572d98SGarrett D'Amore 		exit(1);
323de572d98SGarrett D'Amore 	}
324de572d98SGarrett D'Amore 	va_end(va);
325de572d98SGarrett D'Amore }
326de572d98SGarrett D'Amore 
327de572d98SGarrett D'Amore static void
mkprog(struct sym_test * st)328de572d98SGarrett D'Amore mkprog(struct sym_test *st)
329de572d98SGarrett D'Amore {
330fc2512cfSRobert Mustacchi 	char *s = NULL;
331de572d98SGarrett D'Amore 
332fc2512cfSRobert Mustacchi 	custr_reset(st_custr);
333de572d98SGarrett D'Amore 
334de572d98SGarrett D'Amore 	for (int i = 0; i < MAXHDR && st->st_hdrs[i] != NULL; i++) {
335de572d98SGarrett D'Amore 		addprogfmt("#include <%s>\n", st->st_hdrs[i]);
336de572d98SGarrett D'Amore 	}
337de572d98SGarrett D'Amore 
338fc2512cfSRobert Mustacchi 	if (st->st_rtype != NULL) {
339fc2512cfSRobert Mustacchi 		for (s = st->st_rtype; *s; s++) {
340de572d98SGarrett D'Amore 			addprogch(*s);
341fc2512cfSRobert Mustacchi 			if (*s == '(') {
342fc2512cfSRobert Mustacchi 				s++;
343fc2512cfSRobert Mustacchi 				addprogch(*s);
344fc2512cfSRobert Mustacchi 				s++;
345fc2512cfSRobert Mustacchi 				break;
346fc2512cfSRobert Mustacchi 			}
347de572d98SGarrett D'Amore 		}
348fc2512cfSRobert Mustacchi 		addprogch(' ');
349de572d98SGarrett D'Amore 	}
350de572d98SGarrett D'Amore 
351de572d98SGarrett D'Amore 	/* for function pointers, s is closing suffix, otherwise empty */
352de572d98SGarrett D'Amore 
353de572d98SGarrett D'Amore 	switch (st->st_type) {
354de572d98SGarrett D'Amore 	case SYM_TYPE:
355de572d98SGarrett D'Amore 		addprogstr("test_type;");
356de572d98SGarrett D'Amore 		break;
357de572d98SGarrett D'Amore 
358de572d98SGarrett D'Amore 	case SYM_VALUE:
359de572d98SGarrett D'Amore 		addprogfmt("test_value%s;\n", s);	/* s usually empty */
360de572d98SGarrett D'Amore 		addprogstr("void\ntest_func(void)\n{\n");
361de572d98SGarrett D'Amore 		addprogfmt("\ttest_value = %s;\n}", st->st_name);
362de572d98SGarrett D'Amore 		break;
363de572d98SGarrett D'Amore 
364fc2512cfSRobert Mustacchi 	case SYM_DEFINE:
365fc2512cfSRobert Mustacchi 		addprogfmt("#if !defined(%s)", st->st_name);
366fc2512cfSRobert Mustacchi 		if (st->st_defval != NULL)
367fc2512cfSRobert Mustacchi 			addprogfmt("|| %s != %s", st->st_name, st->st_defval);
368fc2512cfSRobert Mustacchi 		addprogfmt("\n#error %s is not defined or has the wrong value",
369fc2512cfSRobert Mustacchi 		    st->st_name);
370fc2512cfSRobert Mustacchi 		addprogfmt("\n#endif\n");
371fc2512cfSRobert Mustacchi 		break;
372fc2512cfSRobert Mustacchi 
373de572d98SGarrett D'Amore 	case SYM_FUNC:
374de572d98SGarrett D'Amore 		addprogstr("\ntest_func(");
375*b36afad7SRobert Mustacchi 		for (int i = 0; i < MAXARG && st->st_atypes[i] != NULL; i++) {
376de572d98SGarrett D'Amore 			int didname = 0;
377de572d98SGarrett D'Amore 			if (i > 0) {
378de572d98SGarrett D'Amore 				addprogstr(", ");
379de572d98SGarrett D'Amore 			}
380de572d98SGarrett D'Amore 			if (strcmp(st->st_atypes[i], "void") == 0) {
381de572d98SGarrett D'Amore 				didname = 1;
382de572d98SGarrett D'Amore 			}
383de572d98SGarrett D'Amore 			if (strcmp(st->st_atypes[i], "") == 0) {
384de572d98SGarrett D'Amore 				didname = 1;
385de572d98SGarrett D'Amore 				addprogstr("void");
386de572d98SGarrett D'Amore 			}
387de572d98SGarrett D'Amore 
388de572d98SGarrett D'Amore 			/* print the argument list */
389de572d98SGarrett D'Amore 			for (char *a = st->st_atypes[i]; *a; a++) {
390de572d98SGarrett D'Amore 				if (*a == '(' && a[1] == '*' && !didname) {
391de572d98SGarrett D'Amore 					addprogfmt("(*a%d", i);
392de572d98SGarrett D'Amore 					didname = 1;
393de572d98SGarrett D'Amore 					a++;
394de572d98SGarrett D'Amore 				} else if (*a == '[' && !didname) {
395de572d98SGarrett D'Amore 					addprogfmt("a%d[", i);
396de572d98SGarrett D'Amore 					didname = 1;
397de572d98SGarrett D'Amore 				} else {
398de572d98SGarrett D'Amore 					addprogch(*a);
399de572d98SGarrett D'Amore 				}
400de572d98SGarrett D'Amore 			}
401de572d98SGarrett D'Amore 			if (!didname) {
402de572d98SGarrett D'Amore 				addprogfmt(" a%d", i);
403de572d98SGarrett D'Amore 			}
404de572d98SGarrett D'Amore 		}
405de572d98SGarrett D'Amore 
406de572d98SGarrett D'Amore 		if (st->st_atypes[0] == NULL) {
407de572d98SGarrett D'Amore 			addprogstr("void");
408de572d98SGarrett D'Amore 		}
409de572d98SGarrett D'Amore 
410de572d98SGarrett D'Amore 		/*
411de572d98SGarrett D'Amore 		 * Close argument list, and closing ")" for func ptrs.
412de572d98SGarrett D'Amore 		 * Note that for non-function pointers, s will be empty
413de572d98SGarrett D'Amore 		 * below, otherwise it points to the trailing argument
414de572d98SGarrett D'Amore 		 * list.
415de572d98SGarrett D'Amore 		 */
416de572d98SGarrett D'Amore 		addprogfmt(")%s\n{\n\t", s);
417de572d98SGarrett D'Amore 
418de572d98SGarrett D'Amore 		if (strcmp(st->st_rtype, "") != 0 &&
419de572d98SGarrett D'Amore 		    strcmp(st->st_rtype, "void") != 0) {
420de572d98SGarrett D'Amore 			addprogstr("return ");
421de572d98SGarrett D'Amore 		}
422de572d98SGarrett D'Amore 
423de572d98SGarrett D'Amore 		/* add the function call */
424de572d98SGarrett D'Amore 		addprogfmt("%s(", st->st_name);
425*b36afad7SRobert Mustacchi 		for (int i = 0; i < MAXARG && st->st_atypes[i] != NULL; i++) {
426de572d98SGarrett D'Amore 			if (strcmp(st->st_atypes[i], "") != 0 &&
427de572d98SGarrett D'Amore 			    strcmp(st->st_atypes[i], "void") != 0) {
428de572d98SGarrett D'Amore 				addprogfmt("%sa%d", i > 0 ? ", " : "", i);
429de572d98SGarrett D'Amore 			}
430de572d98SGarrett D'Amore 		}
431de572d98SGarrett D'Amore 
432de572d98SGarrett D'Amore 		addprogstr(");\n}");
433de572d98SGarrett D'Amore 		break;
434de572d98SGarrett D'Amore 	}
435de572d98SGarrett D'Amore 
436de572d98SGarrett D'Amore 	addprogch('\n');
437de572d98SGarrett D'Amore 
438fc2512cfSRobert Mustacchi 	st->st_prog = custr_cstr(st_custr);
439de572d98SGarrett D'Amore }
440de572d98SGarrett D'Amore 
441de572d98SGarrett D'Amore static int
add_envs(struct sym_test * st,char * envs,char ** err)442de572d98SGarrett D'Amore add_envs(struct sym_test *st, char *envs, char **err)
443de572d98SGarrett D'Amore {
444de572d98SGarrett D'Amore 	char *item;
445de572d98SGarrett D'Amore 	if (expand_env_list(envs, &st->st_test_mask, &st->st_need_mask,
446de572d98SGarrett D'Amore 	    &item) < 0) {
447de572d98SGarrett D'Amore 		myasprintf(err, "bad env action %s", item);
448de572d98SGarrett D'Amore 		return (-1);
449de572d98SGarrett D'Amore 	}
450de572d98SGarrett D'Amore 	return (0);
451de572d98SGarrett D'Amore }
452de572d98SGarrett D'Amore 
453de572d98SGarrett D'Amore static int
add_headers(struct sym_test * st,char * hdrs,char ** err)454de572d98SGarrett D'Amore add_headers(struct sym_test *st, char *hdrs, char **err)
455de572d98SGarrett D'Amore {
456de572d98SGarrett D'Amore 	int i = 0;
457de572d98SGarrett D'Amore 
458de572d98SGarrett D'Amore 	for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) {
459de572d98SGarrett D'Amore 		if (i >= MAXHDR) {
460de572d98SGarrett D'Amore 			myasprintf(err, "too many headers");
461de572d98SGarrett D'Amore 			return (-1);
462de572d98SGarrett D'Amore 		}
463de572d98SGarrett D'Amore 		test_trim(&h);
464de572d98SGarrett D'Amore 		st->st_hdrs[i++] = mystrdup(h);
465de572d98SGarrett D'Amore 	}
466de572d98SGarrett D'Amore 
467de572d98SGarrett D'Amore 	return (0);
468de572d98SGarrett D'Amore }
469de572d98SGarrett D'Amore 
470de572d98SGarrett D'Amore static int
add_arg_types(struct sym_test * st,char * atype,char ** err)471de572d98SGarrett D'Amore add_arg_types(struct sym_test *st, char *atype, char **err)
472de572d98SGarrett D'Amore {
473de572d98SGarrett D'Amore 	int i = 0;
474de572d98SGarrett D'Amore 	char *a;
475de572d98SGarrett D'Amore 	for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) {
476de572d98SGarrett D'Amore 		if (i >= MAXARG) {
477de572d98SGarrett D'Amore 			myasprintf(err, "too many arguments");
478de572d98SGarrett D'Amore 			return (-1);
479de572d98SGarrett D'Amore 		}
480de572d98SGarrett D'Amore 		test_trim(&a);
481de572d98SGarrett D'Amore 		st->st_atypes[i++] = mystrdup(a);
482de572d98SGarrett D'Amore 	}
483de572d98SGarrett D'Amore 
484de572d98SGarrett D'Amore 	return (0);
485de572d98SGarrett D'Amore }
486de572d98SGarrett D'Amore 
487de572d98SGarrett D'Amore static int
do_type(char ** fields,int nfields,char ** err)488de572d98SGarrett D'Amore do_type(char **fields, int nfields, char **err)
489de572d98SGarrett D'Amore {
490de572d98SGarrett D'Amore 	char *decl;
491de572d98SGarrett D'Amore 	char *hdrs;
492de572d98SGarrett D'Amore 	char *envs;
493de572d98SGarrett D'Amore 	struct sym_test *st;
494de572d98SGarrett D'Amore 
495de572d98SGarrett D'Amore 	if (nfields != 3) {
496de572d98SGarrett D'Amore 		myasprintf(err, "number of fields (%d) != 3", nfields);
497de572d98SGarrett D'Amore 		return (-1);
498de572d98SGarrett D'Amore 	}
499de572d98SGarrett D'Amore 	decl = fields[0];
500de572d98SGarrett D'Amore 	hdrs = fields[1];
501de572d98SGarrett D'Amore 	envs = fields[2];
502de572d98SGarrett D'Amore 
503de572d98SGarrett D'Amore 	st = myzalloc(sizeof (*st));
504de572d98SGarrett D'Amore 	st->st_type = SYM_TYPE;
505de572d98SGarrett D'Amore 	st->st_name = mystrdup(decl);
506de572d98SGarrett D'Amore 	st->st_rtype = mystrdup(decl);
507de572d98SGarrett D'Amore 
508de572d98SGarrett D'Amore 	if ((add_envs(st, envs, err) < 0) ||
509de572d98SGarrett D'Amore 	    (add_headers(st, hdrs, err) < 0)) {
510de572d98SGarrett D'Amore 		return (-1);
511de572d98SGarrett D'Amore 	}
512de572d98SGarrett D'Amore 	append_sym_test(st);
513de572d98SGarrett D'Amore 
514de572d98SGarrett D'Amore 	return (0);
515de572d98SGarrett D'Amore }
516de572d98SGarrett D'Amore 
517de572d98SGarrett D'Amore static int
do_value(char ** fields,int nfields,char ** err)518de572d98SGarrett D'Amore do_value(char **fields, int nfields, char **err)
519de572d98SGarrett D'Amore {
520de572d98SGarrett D'Amore 	char *name;
521de572d98SGarrett D'Amore 	char *type;
522de572d98SGarrett D'Amore 	char *hdrs;
523de572d98SGarrett D'Amore 	char *envs;
524de572d98SGarrett D'Amore 	struct sym_test *st;
525de572d98SGarrett D'Amore 
526de572d98SGarrett D'Amore 	if (nfields != 4) {
527de572d98SGarrett D'Amore 		myasprintf(err, "number of fields (%d) != 4", nfields);
528de572d98SGarrett D'Amore 		return (-1);
529de572d98SGarrett D'Amore 	}
530de572d98SGarrett D'Amore 	name = fields[0];
531de572d98SGarrett D'Amore 	type = fields[1];
532de572d98SGarrett D'Amore 	hdrs = fields[2];
533de572d98SGarrett D'Amore 	envs = fields[3];
534de572d98SGarrett D'Amore 
535de572d98SGarrett D'Amore 	st = myzalloc(sizeof (*st));
536de572d98SGarrett D'Amore 	st->st_type = SYM_VALUE;
537de572d98SGarrett D'Amore 	st->st_name = mystrdup(name);
538de572d98SGarrett D'Amore 	st->st_rtype = mystrdup(type);
539de572d98SGarrett D'Amore 
540de572d98SGarrett D'Amore 	if ((add_envs(st, envs, err) < 0) ||
541de572d98SGarrett D'Amore 	    (add_headers(st, hdrs, err) < 0)) {
542de572d98SGarrett D'Amore 		return (-1);
543de572d98SGarrett D'Amore 	}
544de572d98SGarrett D'Amore 	append_sym_test(st);
545de572d98SGarrett D'Amore 
546de572d98SGarrett D'Amore 	return (0);
547de572d98SGarrett D'Amore }
548de572d98SGarrett D'Amore 
549fc2512cfSRobert Mustacchi static int
do_define(char ** fields,int nfields,char ** err)550fc2512cfSRobert Mustacchi do_define(char **fields, int nfields, char **err)
551fc2512cfSRobert Mustacchi {
552fc2512cfSRobert Mustacchi 	char *name, *value, *hdrs, *envs;
553fc2512cfSRobert Mustacchi 	struct sym_test *st;
554fc2512cfSRobert Mustacchi 
555fc2512cfSRobert Mustacchi 	if (nfields != 4) {
556fc2512cfSRobert Mustacchi 		myasprintf(err, "number of fields (%d) != 4", nfields);
557fc2512cfSRobert Mustacchi 		return (-1);
558fc2512cfSRobert Mustacchi 	}
559fc2512cfSRobert Mustacchi 
560fc2512cfSRobert Mustacchi 	name = fields[0];
561fc2512cfSRobert Mustacchi 	value = fields[1];
562fc2512cfSRobert Mustacchi 	hdrs = fields[2];
563fc2512cfSRobert Mustacchi 	envs = fields[3];
564fc2512cfSRobert Mustacchi 
565fc2512cfSRobert Mustacchi 	st = myzalloc(sizeof (*st));
566fc2512cfSRobert Mustacchi 	st->st_type = SYM_DEFINE;
567fc2512cfSRobert Mustacchi 	st->st_name = mystrdup(name);
568fc2512cfSRobert Mustacchi 
569fc2512cfSRobert Mustacchi 	/*
570fc2512cfSRobert Mustacchi 	 * A value to compare against is optional. trim will leave it as a null
571fc2512cfSRobert Mustacchi 	 * pointer if there's nothing there.
572fc2512cfSRobert Mustacchi 	 */
573fc2512cfSRobert Mustacchi 	test_trim(&value);
574fc2512cfSRobert Mustacchi 	if (*value != '\0')
575fc2512cfSRobert Mustacchi 		st->st_defval = mystrdup(value);
576fc2512cfSRobert Mustacchi 
577fc2512cfSRobert Mustacchi 	if ((add_envs(st, envs, err) < 0) ||
578fc2512cfSRobert Mustacchi 	    (add_headers(st, hdrs, err) < 0)) {
579fc2512cfSRobert Mustacchi 		return (-1);
580fc2512cfSRobert Mustacchi 	}
581fc2512cfSRobert Mustacchi 
582fc2512cfSRobert Mustacchi 	append_sym_test(st);
583fc2512cfSRobert Mustacchi 
584fc2512cfSRobert Mustacchi 	return (0);
585fc2512cfSRobert Mustacchi }
586fc2512cfSRobert Mustacchi 
587de572d98SGarrett D'Amore static int
do_func(char ** fields,int nfields,char ** err)588de572d98SGarrett D'Amore do_func(char **fields, int nfields, char **err)
589de572d98SGarrett D'Amore {
590de572d98SGarrett D'Amore 	char *name;
591de572d98SGarrett D'Amore 	char *rtype;
592de572d98SGarrett D'Amore 	char *atype;
593de572d98SGarrett D'Amore 	char *hdrs;
594de572d98SGarrett D'Amore 	char *envs;
595de572d98SGarrett D'Amore 	struct sym_test *st;
596de572d98SGarrett D'Amore 
597de572d98SGarrett D'Amore 	if (nfields != 5) {
598de572d98SGarrett D'Amore 		myasprintf(err, "number of fields (%d) != 5", nfields);
599de572d98SGarrett D'Amore 		return (-1);
600de572d98SGarrett D'Amore 	}
601de572d98SGarrett D'Amore 	name = fields[0];
602de572d98SGarrett D'Amore 	rtype = fields[1];
603de572d98SGarrett D'Amore 	atype = fields[2];
604de572d98SGarrett D'Amore 	hdrs = fields[3];
605de572d98SGarrett D'Amore 	envs = fields[4];
606de572d98SGarrett D'Amore 
607de572d98SGarrett D'Amore 	st = myzalloc(sizeof (*st));
608de572d98SGarrett D'Amore 	st->st_type = SYM_FUNC;
609de572d98SGarrett D'Amore 	st->st_name = mystrdup(name);
610de572d98SGarrett D'Amore 	st->st_rtype = mystrdup(rtype);
611de572d98SGarrett D'Amore 
612de572d98SGarrett D'Amore 	if ((add_envs(st, envs, err) < 0) ||
613de572d98SGarrett D'Amore 	    (add_headers(st, hdrs, err) < 0) ||
614de572d98SGarrett D'Amore 	    (add_arg_types(st, atype, err) < 0)) {
615de572d98SGarrett D'Amore 		return (-1);
616de572d98SGarrett D'Amore 	}
617de572d98SGarrett D'Amore 	append_sym_test(st);
618de572d98SGarrett D'Amore 
619de572d98SGarrett D'Amore 	return (0);
620de572d98SGarrett D'Amore }
621de572d98SGarrett D'Amore 
622de572d98SGarrett D'Amore struct sym_test *
next_sym_test(struct sym_test * st)623de572d98SGarrett D'Amore next_sym_test(struct sym_test *st)
624de572d98SGarrett D'Amore {
625de572d98SGarrett D'Amore 	return (st == NULL ? sym_tests : st->st_next);
626de572d98SGarrett D'Amore }
627de572d98SGarrett D'Amore 
628de572d98SGarrett D'Amore const char *
sym_test_prog(struct sym_test * st)629de572d98SGarrett D'Amore sym_test_prog(struct sym_test *st)
630de572d98SGarrett D'Amore {
631de572d98SGarrett D'Amore 	if (st->st_prog == NULL) {
632de572d98SGarrett D'Amore 		mkprog(st);
633de572d98SGarrett D'Amore 	}
634de572d98SGarrett D'Amore 	return (st->st_prog);
635de572d98SGarrett D'Amore }
636de572d98SGarrett D'Amore 
637de572d98SGarrett D'Amore const char *
sym_test_name(struct sym_test * st)638de572d98SGarrett D'Amore sym_test_name(struct sym_test *st)
639de572d98SGarrett D'Amore {
640de572d98SGarrett D'Amore 	return (st->st_name);
641de572d98SGarrett D'Amore }
642de572d98SGarrett D'Amore 
643de572d98SGarrett D'Amore /*
644de572d98SGarrett D'Amore  * Iterate through tests.  Pass in NULL for cenv to begin the iteration. For
645de572d98SGarrett D'Amore  * subsequent iterations, use the return value from the previous iteration.
646de572d98SGarrett D'Amore  * Returns NULL when there are no more environments.
647de572d98SGarrett D'Amore  */
648de572d98SGarrett D'Amore struct compile_env *
sym_test_env(struct sym_test * st,struct compile_env * cenv,int * need)649de572d98SGarrett D'Amore sym_test_env(struct sym_test *st, struct compile_env *cenv, int *need)
650de572d98SGarrett D'Amore {
651de572d98SGarrett D'Amore 	int i = cenv ? cenv->ce_index + 1: 0;
652de572d98SGarrett D'Amore 	uint64_t b = 1ULL << i;
653de572d98SGarrett D'Amore 
654de572d98SGarrett D'Amore 	while ((i < MAXENV) && (b != 0)) {
655de572d98SGarrett D'Amore 		cenv = &compile_env[i];
656de572d98SGarrett D'Amore 		if (b & st->st_test_mask) {
657de572d98SGarrett D'Amore 			*need = (st->st_need_mask & b) ? 1 : 0;
658de572d98SGarrett D'Amore 			return (cenv);
659de572d98SGarrett D'Amore 		}
660de572d98SGarrett D'Amore 		b <<= 1;
661de572d98SGarrett D'Amore 		i++;
662de572d98SGarrett D'Amore 	}
663de572d98SGarrett D'Amore 	return (NULL);
664de572d98SGarrett D'Amore }
665de572d98SGarrett D'Amore 
666de572d98SGarrett D'Amore const char *
env_name(struct compile_env * cenv)667de572d98SGarrett D'Amore env_name(struct compile_env *cenv)
668de572d98SGarrett D'Amore {
669de572d98SGarrett D'Amore 	return (cenv->ce_name);
670de572d98SGarrett D'Amore }
671de572d98SGarrett D'Amore 
672de572d98SGarrett D'Amore const char *
env_lang(struct compile_env * cenv)673de572d98SGarrett D'Amore env_lang(struct compile_env *cenv)
674de572d98SGarrett D'Amore {
675de572d98SGarrett D'Amore 	return (cenv->ce_lang);
676de572d98SGarrett D'Amore }
677de572d98SGarrett D'Amore 
678de572d98SGarrett D'Amore const char *
env_defs(struct compile_env * cenv)679de572d98SGarrett D'Amore env_defs(struct compile_env *cenv)
680de572d98SGarrett D'Amore {
681de572d98SGarrett D'Amore 	return (cenv->ce_defs);
682de572d98SGarrett D'Amore }
683de572d98SGarrett D'Amore 
684de572d98SGarrett D'Amore static void
show_file(test_t t,const char * path)685de572d98SGarrett D'Amore show_file(test_t t, const char *path)
686de572d98SGarrett D'Amore {
687de572d98SGarrett D'Amore 	FILE *f;
688de572d98SGarrett D'Amore 	char *buf = NULL;
689de572d98SGarrett D'Amore 	size_t cap = 0;
690de572d98SGarrett D'Amore 	int line = 1;
691de572d98SGarrett D'Amore 
692de572d98SGarrett D'Amore 	f = fopen(path, "r");
693de572d98SGarrett D'Amore 	if (f == NULL) {
694de572d98SGarrett D'Amore 		test_debugf(t, "fopen(%s): %s", path, strerror(errno));
695de572d98SGarrett D'Amore 		return;
696de572d98SGarrett D'Amore 	}
697de572d98SGarrett D'Amore 
698de572d98SGarrett D'Amore 	test_debugf(t, "----->> begin (%s) <<------", path);
699de572d98SGarrett D'Amore 	while (getline(&buf, &cap, f) >= 0) {
700de572d98SGarrett D'Amore 		(void) strtok(buf, "\r\n");
701de572d98SGarrett D'Amore 		test_debugf(t, "%d: %s", line, buf);
702de572d98SGarrett D'Amore 		line++;
703de572d98SGarrett D'Amore 	}
704de572d98SGarrett D'Amore 	test_debugf(t, "----->> end (%s) <<------", path);
705de572d98SGarrett D'Amore 	(void) fclose(f);
706de572d98SGarrett D'Amore }
707de572d98SGarrett D'Amore 
708de572d98SGarrett D'Amore static void
cleanup(void)709de572d98SGarrett D'Amore cleanup(void)
710de572d98SGarrett D'Amore {
711de572d98SGarrett D'Amore 	if (ofile != NULL) {
712de572d98SGarrett D'Amore 		(void) unlink(ofile);
713de572d98SGarrett D'Amore 		free(ofile);
714de572d98SGarrett D'Amore 		ofile = NULL;
715de572d98SGarrett D'Amore 	}
716de572d98SGarrett D'Amore 	if (lfile != NULL) {
717de572d98SGarrett D'Amore 		(void) unlink(lfile);
718de572d98SGarrett D'Amore 		free(lfile);
719de572d98SGarrett D'Amore 		lfile = NULL;
720de572d98SGarrett D'Amore 	}
721de572d98SGarrett D'Amore 	if (cfile != NULL) {
722de572d98SGarrett D'Amore 		(void) unlink(cfile);
723de572d98SGarrett D'Amore 		free(cfile);
724de572d98SGarrett D'Amore 		cfile = NULL;
725de572d98SGarrett D'Amore 	}
726de572d98SGarrett D'Amore 	if (efile != NULL) {
727de572d98SGarrett D'Amore 		(void) unlink(efile);
728de572d98SGarrett D'Amore 		free(efile);
729de572d98SGarrett D'Amore 		efile = NULL;
730de572d98SGarrett D'Amore 	}
731de572d98SGarrett D'Amore 	if (dname) {
732de572d98SGarrett D'Amore 		(void) rmdir(dname);
733de572d98SGarrett D'Amore 		free(dname);
734de572d98SGarrett D'Amore 		dname = NULL;
735de572d98SGarrett D'Amore 	}
736de572d98SGarrett D'Amore }
737de572d98SGarrett D'Amore 
738de572d98SGarrett D'Amore static int
mkworkdir(void)739de572d98SGarrett D'Amore mkworkdir(void)
740de572d98SGarrett D'Amore {
741de572d98SGarrett D'Amore 	char b[32];
742de572d98SGarrett D'Amore 	char *d;
743de572d98SGarrett D'Amore 
744de572d98SGarrett D'Amore 	cleanup();
745de572d98SGarrett D'Amore 
746de572d98SGarrett D'Amore 	(void) strlcpy(b, "/tmp/symbols_testXXXXXX", sizeof (b));
747de572d98SGarrett D'Amore 	if ((d = mkdtemp(b)) == NULL) {
748de572d98SGarrett D'Amore 		perror("mkdtemp");
749de572d98SGarrett D'Amore 		return (-1);
750de572d98SGarrett D'Amore 	}
751de572d98SGarrett D'Amore 	dname = mystrdup(d);
752de572d98SGarrett D'Amore 	myasprintf(&cfile, "%s/compile_test.c", d);
753de572d98SGarrett D'Amore 	myasprintf(&ofile, "%s/compile_test.o", d);
754de572d98SGarrett D'Amore 	myasprintf(&lfile, "%s/compile_test.log", d);
755de572d98SGarrett D'Amore 	myasprintf(&efile, "%s/compile_test.exe", d);
756de572d98SGarrett D'Amore 	return (0);
757de572d98SGarrett D'Amore }
758de572d98SGarrett D'Amore 
759de572d98SGarrett D'Amore void
find_compiler(void)760de572d98SGarrett D'Amore find_compiler(void)
761de572d98SGarrett D'Amore {
762de572d98SGarrett D'Amore 	test_t t;
763de572d98SGarrett D'Amore 	int i;
764de572d98SGarrett D'Amore 	FILE *cf;
765de572d98SGarrett D'Amore 
766de572d98SGarrett D'Amore 	t = test_start("finding compiler");
767de572d98SGarrett D'Amore 
768de572d98SGarrett D'Amore 	if ((cf = fopen(cfile, "w+")) == NULL) {
769de572d98SGarrett D'Amore 		test_failed(t, "Unable to open %s for write: %s", cfile,
770de572d98SGarrett D'Amore 		    strerror(errno));
771de572d98SGarrett D'Amore 		return;
772de572d98SGarrett D'Amore 	}
773de572d98SGarrett D'Amore 	(void) fprintf(cf, "#include <stdio.h>\n");
774de572d98SGarrett D'Amore 	(void) fprintf(cf, "int main(int argc, char **argv) {\n");
775de572d98SGarrett D'Amore 	(void) fprintf(cf, "#if defined(__SUNPRO_C)\n");
776de572d98SGarrett D'Amore 	(void) fprintf(cf, "exit(51);\n");
777de572d98SGarrett D'Amore 	(void) fprintf(cf, "#elif defined(__GNUC__)\n");
778de572d98SGarrett D'Amore 	(void) fprintf(cf, "exit(52);\n");
779de572d98SGarrett D'Amore 	(void) fprintf(cf, "#else\n");
780de572d98SGarrett D'Amore 	(void) fprintf(cf, "exit(99)\n");
781de572d98SGarrett D'Amore 	(void) fprintf(cf, "#endif\n}\n");
782de572d98SGarrett D'Amore 	(void) fclose(cf);
783de572d98SGarrett D'Amore 
784de572d98SGarrett D'Amore 	for (i = 0; compilers[i] != NULL; i++) {
785de572d98SGarrett D'Amore 		char cmd[256];
786de572d98SGarrett D'Amore 		int rv;
787de572d98SGarrett D'Amore 
788de572d98SGarrett D'Amore 		(void) snprintf(cmd, sizeof (cmd),
789de572d98SGarrett D'Amore 		    "%s %s %s -o %s >/dev/null 2>&1",
790de572d98SGarrett D'Amore 		    compilers[i], MFLAG, cfile, efile);
791de572d98SGarrett D'Amore 		test_debugf(t, "trying %s", cmd);
792de572d98SGarrett D'Amore 		rv = system(cmd);
793de572d98SGarrett D'Amore 
794de572d98SGarrett D'Amore 		test_debugf(t, "result: %d", rv);
795de572d98SGarrett D'Amore 
796de572d98SGarrett D'Amore 		if ((rv < 0) || !WIFEXITED(rv) || WEXITSTATUS(rv) != 0)
797de572d98SGarrett D'Amore 			continue;
798de572d98SGarrett D'Amore 
799de572d98SGarrett D'Amore 		rv = system(efile);
800de572d98SGarrett D'Amore 		if (rv >= 0 && WIFEXITED(rv)) {
801de572d98SGarrett D'Amore 			rv = WEXITSTATUS(rv);
802de572d98SGarrett D'Amore 		} else {
803de572d98SGarrett D'Amore 			rv = -1;
804de572d98SGarrett D'Amore 		}
805de572d98SGarrett D'Amore 
806de572d98SGarrett D'Amore 		switch (rv) {
807de572d98SGarrett D'Amore 		case 51:	/* STUDIO */
808de572d98SGarrett D'Amore 			test_debugf(t, "Found Studio C");
809de572d98SGarrett D'Amore 			c89flags = "-Xc -errwarn=%all -v -xc99=%none " MFLAG;
810de572d98SGarrett D'Amore 			c99flags = "-Xc -errwarn=%all -v -xc99=%all " MFLAG;
811fc2512cfSRobert Mustacchi 			c11flags = NULL;
812de572d98SGarrett D'Amore 			if (extra_debug) {
813de572d98SGarrett D'Amore 				test_debugf(t, "c89flags: %s", c89flags);
814de572d98SGarrett D'Amore 				test_debugf(t, "c99flags: %s", c99flags);
815de572d98SGarrett D'Amore 			}
816de572d98SGarrett D'Amore 			test_passed(t);
817de572d98SGarrett D'Amore 			break;
818de572d98SGarrett D'Amore 		case 52:	/* GCC */
819de572d98SGarrett D'Amore 			test_debugf(t, "Found GNU C");
820b599bd93SRobert Mustacchi 			c89flags = "-Wall -Werror -std=c89 -nostdinc "
821b599bd93SRobert Mustacchi 			    "-isystem /usr/include " MFLAG;
822b599bd93SRobert Mustacchi 			c99flags = "-Wall -Werror -std=c99 -nostdinc "
823b599bd93SRobert Mustacchi 			    "-isystem /usr/include " MFLAG;
824fc2512cfSRobert Mustacchi 			c11flags = "-Wall -Werror -std=c11 -nostdinc "
825fc2512cfSRobert Mustacchi 			    "-isystem /usr/include " MFLAG;
826de572d98SGarrett D'Amore 			if (extra_debug) {
827de572d98SGarrett D'Amore 				test_debugf(t, "c89flags: %s", c89flags);
828de572d98SGarrett D'Amore 				test_debugf(t, "c99flags: %s", c99flags);
829de572d98SGarrett D'Amore 			}
830de572d98SGarrett D'Amore 			test_passed(t);
831de572d98SGarrett D'Amore 			break;
832de572d98SGarrett D'Amore 		case 99:
833de572d98SGarrett D'Amore 			test_debugf(t, "Found unknown (unsupported) compiler");
834de572d98SGarrett D'Amore 			continue;
835de572d98SGarrett D'Amore 		default:
836de572d98SGarrett D'Amore 			continue;
837de572d98SGarrett D'Amore 		}
838de572d98SGarrett D'Amore 		myasprintf(&compiler, "%s", compilers[i]);
839de572d98SGarrett D'Amore 		test_debugf(t, "compiler: %s", compiler);
840de572d98SGarrett D'Amore 		return;
841de572d98SGarrett D'Amore 	}
842de572d98SGarrett D'Amore 	test_failed(t, "No compiler found.");
843de572d98SGarrett D'Amore }
844de572d98SGarrett D'Amore 
845de572d98SGarrett D'Amore int
do_compile(test_t t,struct sym_test * st,struct compile_env * cenv,int need)846de572d98SGarrett D'Amore do_compile(test_t t, struct sym_test *st, struct compile_env *cenv, int need)
847de572d98SGarrett D'Amore {
848de572d98SGarrett D'Amore 	char *cmd;
849de572d98SGarrett D'Amore 	FILE *logf;
850de572d98SGarrett D'Amore 	FILE *dotc;
851fc2512cfSRobert Mustacchi 	const char *prog, *cflags, *lang;
852de572d98SGarrett D'Amore 
853de572d98SGarrett D'Amore 	full_count++;
854de572d98SGarrett D'Amore 
855de572d98SGarrett D'Amore 	if ((dotc = fopen(cfile, "w+")) == NULL) {
856de572d98SGarrett D'Amore 		test_failed(t, "fopen(%s): %s", cfile, strerror(errno));
857de572d98SGarrett D'Amore 		return (-1);
858de572d98SGarrett D'Amore 	}
859de572d98SGarrett D'Amore 	prog = sym_test_prog(st);
860de572d98SGarrett D'Amore 	if (fwrite(prog, 1, strlen(prog), dotc) < strlen(prog)) {
861de572d98SGarrett D'Amore 		test_failed(t, "fwrite: %s", strerror(errno));
862de572d98SGarrett D'Amore 		(void) fclose(dotc);
863de572d98SGarrett D'Amore 		return (-1);
864de572d98SGarrett D'Amore 	}
865de572d98SGarrett D'Amore 	if (fclose(dotc) < 0) {
866de572d98SGarrett D'Amore 		test_failed(t, "fclose: %s", strerror(errno));
867de572d98SGarrett D'Amore 		return (-1);
868de572d98SGarrett D'Amore 	}
869de572d98SGarrett D'Amore 
870de572d98SGarrett D'Amore 	(void) unlink(ofile);
871de572d98SGarrett D'Amore 
872fc2512cfSRobert Mustacchi 	if (strcmp(env_lang(cenv), "c99") == 0) {
873fc2512cfSRobert Mustacchi 		lang = "c99";
874fc2512cfSRobert Mustacchi 		cflags = c99flags;
875fc2512cfSRobert Mustacchi 	} else if (strcmp(env_lang(cenv), "c11") == 0) {
876fc2512cfSRobert Mustacchi 		lang = "c11";
877fc2512cfSRobert Mustacchi 		cflags = c11flags;
878fc2512cfSRobert Mustacchi 	} else {
879fc2512cfSRobert Mustacchi 		lang = "c89";
880fc2512cfSRobert Mustacchi 		cflags = c89flags;
881fc2512cfSRobert Mustacchi 	}
882fc2512cfSRobert Mustacchi 
883fc2512cfSRobert Mustacchi 	if (cflags == NULL) {
884fc2512cfSRobert Mustacchi 		test_failed(t, "compiler %s does not support %s", compiler,
885fc2512cfSRobert Mustacchi 		    lang);
886fc2512cfSRobert Mustacchi 		return (-1);
887fc2512cfSRobert Mustacchi 	}
888fc2512cfSRobert Mustacchi 
889de572d98SGarrett D'Amore 	myasprintf(&cmd, "%s %s %s -c %s -o %s >>%s 2>&1",
890fc2512cfSRobert Mustacchi 	    compiler, cflags, env_defs(cenv), cfile, ofile, lfile);
891de572d98SGarrett D'Amore 
892de572d98SGarrett D'Amore 	if (extra_debug) {
893de572d98SGarrett D'Amore 		test_debugf(t, "command: %s", cmd);
894de572d98SGarrett D'Amore 	}
895de572d98SGarrett D'Amore 
896de572d98SGarrett D'Amore 	if ((logf = fopen(lfile, "w+")) == NULL) {
897de572d98SGarrett D'Amore 		test_failed(t, "fopen: %s", strerror(errno));
898de572d98SGarrett D'Amore 		return (-1);
899de572d98SGarrett D'Amore 	}
900de572d98SGarrett D'Amore 	(void) fprintf(logf, "===================\n");
901de572d98SGarrett D'Amore 	(void) fprintf(logf, "PROGRAM:\n%s\n", sym_test_prog(st));
902de572d98SGarrett D'Amore 	(void) fprintf(logf, "COMMAND: %s\n", cmd);
903de572d98SGarrett D'Amore 	(void) fprintf(logf, "EXPECT: %s\n", need ? "OK" : "FAIL");
904de572d98SGarrett D'Amore 	(void) fclose(logf);
905de572d98SGarrett D'Amore 
906de572d98SGarrett D'Amore 	switch (system(cmd)) {
907de572d98SGarrett D'Amore 	case -1:
908de572d98SGarrett D'Amore 		test_failed(t, "error compiling in %s: %s", env_name(cenv),
909de572d98SGarrett D'Amore 		    strerror(errno));
910de572d98SGarrett D'Amore 		return (-1);
911de572d98SGarrett D'Amore 	case 0:
912de572d98SGarrett D'Amore 		if (!need) {
913de572d98SGarrett D'Amore 			fail_count++;
914de572d98SGarrett D'Amore 			show_file(t, lfile);
915de572d98SGarrett D'Amore 			test_failed(t, "symbol visible in %s", env_name(cenv));
916de572d98SGarrett D'Amore 			return (-1);
917de572d98SGarrett D'Amore 		}
918de572d98SGarrett D'Amore 		break;
919de572d98SGarrett D'Amore 	default:
920de572d98SGarrett D'Amore 		if (need) {
921de572d98SGarrett D'Amore 			fail_count++;
922de572d98SGarrett D'Amore 			show_file(t, lfile);
923de572d98SGarrett D'Amore 			test_failed(t, "error compiling in %s", env_name(cenv));
924de572d98SGarrett D'Amore 			return (-1);
925de572d98SGarrett D'Amore 		}
926de572d98SGarrett D'Amore 		break;
927de572d98SGarrett D'Amore 	}
928de572d98SGarrett D'Amore 	good_count++;
929de572d98SGarrett D'Amore 	return (0);
930de572d98SGarrett D'Amore }
931de572d98SGarrett D'Amore 
932de572d98SGarrett D'Amore void
test_compile(void)933de572d98SGarrett D'Amore test_compile(void)
934de572d98SGarrett D'Amore {
935de572d98SGarrett D'Amore 	struct sym_test *st;
936de572d98SGarrett D'Amore 	struct compile_env *cenv;
937de572d98SGarrett D'Amore 	test_t t;
938de572d98SGarrett D'Amore 	int need;
939de572d98SGarrett D'Amore 
940de572d98SGarrett D'Amore 	for (st = next_sym_test(NULL); st; st = next_sym_test(st)) {
941de572d98SGarrett D'Amore 		if ((sym != NULL) && strcmp(sym, sym_test_name(st))) {
942de572d98SGarrett D'Amore 			continue;
943de572d98SGarrett D'Amore 		}
944de572d98SGarrett D'Amore 		/* XXX: we really want a sym_test_desc() */
945de572d98SGarrett D'Amore 		for (cenv = sym_test_env(st, NULL, &need);
946de572d98SGarrett D'Amore 		    cenv != NULL;
947de572d98SGarrett D'Amore 		    cenv = sym_test_env(st, cenv, &need)) {
948de572d98SGarrett D'Amore 			t = test_start("%s : %c%s", sym_test_name(st),
949de572d98SGarrett D'Amore 			    need ? '+' : '-', env_name(cenv));
950de572d98SGarrett D'Amore 			if (do_compile(t, st, cenv, need) == 0) {
951de572d98SGarrett D'Amore 				test_passed(t);
952de572d98SGarrett D'Amore 			}
953de572d98SGarrett D'Amore 		}
954de572d98SGarrett D'Amore 	}
955de572d98SGarrett D'Amore 
956de572d98SGarrett D'Amore 	if (full_count > 0) {
957de572d98SGarrett D'Amore 		test_summary();
958de572d98SGarrett D'Amore 	}
959de572d98SGarrett D'Amore }
960de572d98SGarrett D'Amore 
961de572d98SGarrett D'Amore int
main(int argc,char ** argv)962de572d98SGarrett D'Amore main(int argc, char **argv)
963de572d98SGarrett D'Amore {
964de572d98SGarrett D'Amore 	int optc;
965de572d98SGarrett D'Amore 	int optC = 0;
966de572d98SGarrett D'Amore 
967de572d98SGarrett D'Amore 	while ((optc = getopt(argc, argv, "DdfCs:c:")) != EOF) {
968de572d98SGarrett D'Amore 		switch (optc) {
969de572d98SGarrett D'Amore 		case 'd':
970de572d98SGarrett D'Amore 			test_set_debug();
971de572d98SGarrett D'Amore 			break;
972de572d98SGarrett D'Amore 		case 'f':
973de572d98SGarrett D'Amore 			test_set_force();
974de572d98SGarrett D'Amore 			break;
975de572d98SGarrett D'Amore 		case 'D':
976de572d98SGarrett D'Amore 			test_set_debug();
977de572d98SGarrett D'Amore 			extra_debug++;
978de572d98SGarrett D'Amore 			break;
979de572d98SGarrett D'Amore 		case 'c':
980de572d98SGarrett D'Amore 			compilation = optarg;
981de572d98SGarrett D'Amore 			break;
982de572d98SGarrett D'Amore 		case 'C':
983de572d98SGarrett D'Amore 			optC++;
984de572d98SGarrett D'Amore 			break;
985de572d98SGarrett D'Amore 		case 's':
986de572d98SGarrett D'Amore 			sym = optarg;
987de572d98SGarrett D'Amore 			break;
988de572d98SGarrett D'Amore 		default:
989de572d98SGarrett D'Amore 			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
990de572d98SGarrett D'Amore 			exit(1);
991de572d98SGarrett D'Amore 		}
992de572d98SGarrett D'Amore 	}
993de572d98SGarrett D'Amore 
994de572d98SGarrett D'Amore 	if (test_load_config(NULL, compilation,
995de572d98SGarrett D'Amore 	    "env", do_env, "env_group", do_env_group, NULL) < 0) {
996de572d98SGarrett D'Amore 		exit(1);
997de572d98SGarrett D'Amore 	}
998de572d98SGarrett D'Amore 
999de572d98SGarrett D'Amore 	while (optind < argc) {
1000de572d98SGarrett D'Amore 		if (test_load_config(NULL, argv[optind++],
1001de572d98SGarrett D'Amore 		    "type", do_type,
1002de572d98SGarrett D'Amore 		    "value", do_value,
1003fc2512cfSRobert Mustacchi 		    "define", do_define,
1004de572d98SGarrett D'Amore 		    "func", do_func,
1005de572d98SGarrett D'Amore 		    NULL) < 0) {
1006de572d98SGarrett D'Amore 			exit(1);
1007de572d98SGarrett D'Amore 		}
1008de572d98SGarrett D'Amore 	}
1009de572d98SGarrett D'Amore 
1010de572d98SGarrett D'Amore 	if (atexit(cleanup) != 0) {
1011de572d98SGarrett D'Amore 		perror("atexit");
1012de572d98SGarrett D'Amore 		exit(1);
1013de572d98SGarrett D'Amore 	}
1014de572d98SGarrett D'Amore 
1015fc2512cfSRobert Mustacchi 	if (custr_alloc(&st_custr) == -1) {
1016fc2512cfSRobert Mustacchi 		perror("custr");
1017fc2512cfSRobert Mustacchi 		exit(1);
1018fc2512cfSRobert Mustacchi 	}
1019fc2512cfSRobert Mustacchi 
1020de572d98SGarrett D'Amore 	if (mkworkdir() < 0) {
1021de572d98SGarrett D'Amore 		perror("mkdir");
1022de572d98SGarrett D'Amore 		exit(1);
1023de572d98SGarrett D'Amore 	}
1024de572d98SGarrett D'Amore 
1025de572d98SGarrett D'Amore 	find_compiler();
1026de572d98SGarrett D'Amore 	if (!optC)
1027de572d98SGarrett D'Amore 		test_compile();
1028de572d98SGarrett D'Amore 
1029de572d98SGarrett D'Amore 	exit(0);
1030de572d98SGarrett D'Amore }
1031