vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

ccan-config.c

(18266B)


      1 /* Simple tool to create config.h.
      2  * Would be much easier with ccan modules, but deliberately standalone.
      3  *
      4  * Copyright 2011 Rusty Russell <rusty@rustcorp.com.au>.  MIT license.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 #include <stdio.h>
     25 #include <stdbool.h>
     26 #include <stdlib.h>
     27 #include <unistd.h>
     28 #include <err.h>
     29 #include <sys/types.h>
     30 #include <sys/wait.h>
     31 #include <sys/stat.h>
     32 #include <fcntl.h>
     33 #include <string.h>
     34 
     35 #define DEFAULT_COMPILER "cc"
     36 #define DEFAULT_FLAGS "-g3 -ggdb -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition"
     37 
     38 #define OUTPUT_FILE "configurator.out"
     39 #define INPUT_FILE "configuratortest.c"
     40 
     41 static int verbose;
     42 
     43 enum test_style {
     44 	OUTSIDE_MAIN		= 0x1,
     45 	DEFINES_FUNC		= 0x2,
     46 	INSIDE_MAIN		= 0x4,
     47 	DEFINES_EVERYTHING	= 0x8,
     48 	MAY_NOT_COMPILE		= 0x10,
     49 	EXECUTE			= 0x8000
     50 };
     51 
     52 struct test {
     53 	const char *name;
     54 	enum test_style style;
     55 	const char *depends;
     56 	const char *link;
     57 	const char *fragment;
     58 	const char *overrides; /* On success, force this to '1' */
     59 	bool done;
     60 	bool answer;
     61 };
     62 
     63 static struct test tests[] = {
     64 	{ "HAVE_32BIT_OFF_T", DEFINES_EVERYTHING|EXECUTE, NULL, NULL,
     65 	  "#include <sys/types.h>\n"
     66 	  "int main(int argc, char *argv[]) {\n"
     67 	  "	return sizeof(off_t) == 4 ? 0 : 1;\n"
     68 	  "}\n" },
     69 	{ "HAVE_ALIGNOF", INSIDE_MAIN, NULL, NULL,
     70 	  "return __alignof__(double) > 0 ? 0 : 1;" },
     71 	{ "HAVE_ASPRINTF", DEFINES_FUNC, NULL, NULL,
     72 	  "#define _GNU_SOURCE\n"
     73 	  "#include <stdio.h>\n"
     74 	  "static char *func(int x) {"
     75 	  "	char *p;\n"
     76 	  "	if (asprintf(&p, \"%u\", x) == -1) p = NULL;"
     77 	  "	return p;\n"
     78 	  "}" },
     79 	{ "HAVE_ATTRIBUTE_COLD", DEFINES_FUNC, NULL, NULL,
     80 	  "static int __attribute__((cold)) func(int x) { return x; }" },
     81 	{ "HAVE_ATTRIBUTE_CONST", DEFINES_FUNC, NULL, NULL,
     82 	  "static int __attribute__((const)) func(int x) { return x; }" },
     83 	{ "HAVE_ATTRIBUTE_PURE", DEFINES_FUNC, NULL, NULL,
     84 	  "static int __attribute__((pure)) func(int x) { return x; }" },
     85 	{ "HAVE_ATTRIBUTE_MAY_ALIAS", OUTSIDE_MAIN, NULL, NULL,
     86 	  "typedef short __attribute__((__may_alias__)) short_a;" },
     87 	{ "HAVE_ATTRIBUTE_NORETURN", DEFINES_FUNC, NULL, NULL,
     88 	  "#include <stdlib.h>\n"
     89 	  "static void __attribute__((noreturn)) func(int x) { exit(x); }" },
     90 	{ "HAVE_ATTRIBUTE_PRINTF", DEFINES_FUNC, NULL, NULL,
     91 	  "static void __attribute__((format(__printf__, 1, 2))) func(const char *fmt, ...) { }" },
     92 	{ "HAVE_ATTRIBUTE_UNUSED", OUTSIDE_MAIN, NULL, NULL,
     93 	  "static int __attribute__((unused)) func(int x) { return x; }" },
     94 	{ "HAVE_ATTRIBUTE_USED", OUTSIDE_MAIN, NULL, NULL,
     95 	  "static int __attribute__((used)) func(int x) { return x; }" },
     96 	{ "HAVE_BACKTRACE", DEFINES_FUNC, NULL, NULL,
     97 	  "#include <execinfo.h>\n"
     98 	  "static int func(int x) {"
     99 	  "	void *bt[10];\n"
    100 	  "	return backtrace(bt, 10) < x;\n"
    101 	  "}" },
    102 	{ "HAVE_BIG_ENDIAN", INSIDE_MAIN|EXECUTE, NULL, NULL,
    103 	  "union { int i; char c[sizeof(int)]; } u;\n"
    104 	  "u.i = 0x01020304;\n"
    105 	  "return u.c[0] == 0x01 && u.c[1] == 0x02 && u.c[2] == 0x03 && u.c[3] == 0x04 ? 0 : 1;" },
    106 	{ "HAVE_BSWAP_64", DEFINES_FUNC, "HAVE_BYTESWAP_H", NULL,
    107 	  "#include <byteswap.h>\n"
    108 	  "static int func(int x) { return bswap_64(x); }" },
    109 	{ "HAVE_BUILTIN_CHOOSE_EXPR", INSIDE_MAIN, NULL, NULL,
    110 	  "return __builtin_choose_expr(1, 0, \"garbage\");" },
    111 	{ "HAVE_BUILTIN_CLZ", INSIDE_MAIN, NULL, NULL,
    112 	  "return __builtin_clz(1) == (sizeof(int)*8 - 1) ? 0 : 1;" },
    113 	{ "HAVE_BUILTIN_CLZL", INSIDE_MAIN, NULL, NULL,
    114 	  "return __builtin_clzl(1) == (sizeof(long)*8 - 1) ? 0 : 1;" },
    115 	{ "HAVE_BUILTIN_CLZLL", INSIDE_MAIN, NULL, NULL,
    116 	  "return __builtin_clzll(1) == (sizeof(long long)*8 - 1) ? 0 : 1;" },
    117 	{ "HAVE_BUILTIN_CTZ", INSIDE_MAIN, NULL, NULL,
    118 	  "return __builtin_ctz(1 << (sizeof(int)*8 - 1)) == (sizeof(int)*8 - 1) ? 0 : 1;" },
    119 	{ "HAVE_BUILTIN_CTZL", INSIDE_MAIN, NULL, NULL,
    120 	  "return __builtin_ctzl(1UL << (sizeof(long)*8 - 1)) == (sizeof(long)*8 - 1) ? 0 : 1;" },
    121 	{ "HAVE_BUILTIN_CTZLL", INSIDE_MAIN, NULL, NULL,
    122 	  "return __builtin_ctzll(1ULL << (sizeof(long long)*8 - 1)) == (sizeof(long long)*8 - 1) ? 0 : 1;" },
    123 	{ "HAVE_BUILTIN_CONSTANT_P", INSIDE_MAIN, NULL, NULL,
    124 	  "return __builtin_constant_p(1) ? 0 : 1;" },
    125 	{ "HAVE_BUILTIN_EXPECT", INSIDE_MAIN, NULL, NULL,
    126 	  "return __builtin_expect(argc == 1, 1) ? 0 : 1;" },
    127 	{ "HAVE_BUILTIN_FFS", INSIDE_MAIN, NULL, NULL,
    128 	  "return __builtin_ffs(0) == 0 ? 0 : 1;" },
    129 	{ "HAVE_BUILTIN_FFSL", INSIDE_MAIN, NULL, NULL,
    130 	  "return __builtin_ffsl(0L) == 0 ? 0 : 1;" },
    131 	{ "HAVE_BUILTIN_FFSLL", INSIDE_MAIN, NULL, NULL,
    132 	  "return __builtin_ffsll(0LL) == 0 ? 0 : 1;" },
    133 	{ "HAVE_BUILTIN_POPCOUNTL", INSIDE_MAIN, NULL, NULL,
    134 	  "return __builtin_popcountl(255L) == 8 ? 0 : 1;" },
    135 	{ "HAVE_BUILTIN_TYPES_COMPATIBLE_P", INSIDE_MAIN, NULL, NULL,
    136 	  "return __builtin_types_compatible_p(char *, int) ? 1 : 0;" },
    137 	{ "HAVE_ICCARM_INTRINSICS", DEFINES_FUNC, NULL, NULL,
    138 	  "#include <intrinsics.h>\n"
    139 	  "int func(int v) {\n"
    140 	  "	return __CLZ(__RBIT(v));\n"
    141 	  "}" },
    142 	{ "HAVE_BYTESWAP_H", OUTSIDE_MAIN, NULL, NULL,
    143 	  "#include <byteswap.h>\n" },
    144 	{ "HAVE_CLOCK_GETTIME",
    145 	  DEFINES_FUNC, "HAVE_STRUCT_TIMESPEC", NULL,
    146 	  "#include <time.h>\n"
    147 	  "static struct timespec func(void) {\n"
    148 	  "	struct timespec ts;\n"
    149 	  "	clock_gettime(CLOCK_REALTIME, &ts);\n"
    150 	  "	return ts;\n"
    151 	  "}\n" },
    152 	{ "HAVE_CLOCK_GETTIME_IN_LIBRT",
    153 	  DEFINES_FUNC,
    154 	  "HAVE_STRUCT_TIMESPEC !HAVE_CLOCK_GETTIME",
    155 	  "-lrt",
    156 	  "#include <time.h>\n"
    157 	  "static struct timespec func(void) {\n"
    158 	  "	struct timespec ts;\n"
    159 	  "	clock_gettime(CLOCK_REALTIME, &ts);\n"
    160 	  "	return ts;\n"
    161 	  "}\n",
    162 	  /* This means HAVE_CLOCK_GETTIME, too */
    163 	  "HAVE_CLOCK_GETTIME" },
    164 	{ "HAVE_COMPOUND_LITERALS", INSIDE_MAIN, NULL, NULL,
    165 	  "int *foo = (int[]) { 1, 2, 3, 4 };\n"
    166 	  "return foo[0] ? 0 : 1;" },
    167 	{ "HAVE_FCHDIR", DEFINES_EVERYTHING|EXECUTE, NULL, NULL,
    168 	  "#include <sys/types.h>\n"
    169 	  "#include <sys/stat.h>\n"
    170 	  "#include <fcntl.h>\n"
    171 	  "#include <unistd.h>\n"
    172 	  "int main(void) {\n"
    173 	  "	int fd = open(\"..\", O_RDONLY);\n"
    174 	  "	return fchdir(fd) == 0 ? 0 : 1;\n"
    175 	  "}\n" },
    176 	{ "HAVE_ERR_H", DEFINES_FUNC, NULL, NULL,
    177 	  "#include <err.h>\n"
    178 	  "static void func(int arg) {\n"
    179 	  "	if (arg == 0)\n"
    180 	  "		err(1, \"err %u\", arg);\n"
    181 	  "	if (arg == 1)\n"
    182 	  "		errx(1, \"err %u\", arg);\n"
    183 	  "	if (arg == 3)\n"
    184 	  "		warn(\"warn %u\", arg);\n"
    185 	  "	if (arg == 4)\n"
    186 	  "		warnx(\"warn %u\", arg);\n"
    187 	  "}\n" },
    188 	{ "HAVE_FILE_OFFSET_BITS", DEFINES_EVERYTHING|EXECUTE,
    189 	  "HAVE_32BIT_OFF_T", NULL,
    190 	  "#define _FILE_OFFSET_BITS 64\n"
    191 	  "#include <sys/types.h>\n"
    192 	  "int main(int argc, char *argv[]) {\n"
    193 	  "	return sizeof(off_t) == 8 ? 0 : 1;\n"
    194 	  "}\n" },
    195 	{ "HAVE_FOR_LOOP_DECLARATION", INSIDE_MAIN, NULL, NULL,
    196 	  "for (int i = 0; i < argc; i++) { return 0; };\n"
    197 	  "return 1;" },
    198 	{ "HAVE_FLEXIBLE_ARRAY_MEMBER", OUTSIDE_MAIN, NULL, NULL,
    199 	  "struct foo { unsigned int x; int arr[]; };" },
    200 	{ "HAVE_GETPAGESIZE", DEFINES_FUNC, NULL, NULL,
    201 	  "#include <unistd.h>\n"
    202 	  "static int func(void) { return getpagesize(); }" },
    203 	{ "HAVE_ISBLANK", DEFINES_FUNC, NULL, NULL,
    204 	  "#define _GNU_SOURCE\n"
    205 	  "#include <ctype.h>\n"
    206 	  "static int func(void) { return isblank(' '); }" },
    207 	{ "HAVE_LITTLE_ENDIAN", INSIDE_MAIN|EXECUTE, NULL, NULL,
    208 	  "union { int i; char c[sizeof(int)]; } u;\n"
    209 	  "u.i = 0x01020304;\n"
    210 	  "return u.c[0] == 0x04 && u.c[1] == 0x03 && u.c[2] == 0x02 && u.c[3] == 0x01 ? 0 : 1;" },
    211 	{ "HAVE_MEMMEM", DEFINES_FUNC, NULL, NULL,
    212 	  "#define _GNU_SOURCE\n"
    213 	  "#include <string.h>\n"
    214 	  "static void *func(void *h, size_t hl, void *n, size_t nl) {\n"
    215 	  "return memmem(h, hl, n, nl);"
    216 	  "}\n", },
    217 	{ "HAVE_MEMRCHR", DEFINES_FUNC, NULL, NULL,
    218 	  "#define _GNU_SOURCE\n"
    219 	  "#include <string.h>\n"
    220 	  "static void *func(void *s, int c, size_t n) {\n"
    221 	  "return memrchr(s, c, n);"
    222 	  "}\n", },
    223 	{ "HAVE_MMAP", DEFINES_FUNC, NULL, NULL,
    224 	  "#include <sys/mman.h>\n"
    225 	  "static void *func(int fd) {\n"
    226 	  "	return mmap(0, 65536, PROT_READ, MAP_SHARED, fd, 0);\n"
    227 	  "}" },
    228 	{ "HAVE_PROC_SELF_MAPS", DEFINES_EVERYTHING|EXECUTE, NULL, NULL,
    229 	  "#include <sys/types.h>\n"
    230 	  "#include <sys/stat.h>\n"
    231 	  "#include <fcntl.h>\n"
    232 	  "int main(void) {\n"
    233 	  "	return open(\"/proc/self/maps\", O_RDONLY) != -1 ? 0 : 1;\n"
    234 	  "}\n" },
    235 	{ "HAVE_QSORT_R_PRIVATE_LAST",
    236 	  DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE, NULL, NULL,
    237 	  "#define _GNU_SOURCE 1\n"
    238 	  "#include <stdlib.h>\n"
    239 	  "static int cmp(const void *lp, const void *rp, void *priv) {\n"
    240 	  " *(unsigned int *)priv = 1;\n"
    241 	  " return *(const int *)lp - *(const int *)rp; }\n"
    242 	  "int main(void) {\n"
    243 	  " int array[] = { 9, 2, 5 };\n"
    244 	  " unsigned int called = 0;\n"
    245 	  " qsort_r(array, 3, sizeof(int), cmp, &called);\n"
    246 	  " return called && array[0] == 2 && array[1] == 5 && array[2] == 9 ? 0 : 1;\n"
    247 	  "}\n" },
    248 	{ "HAVE_STRUCT_TIMESPEC",
    249 	  DEFINES_FUNC, NULL, NULL,
    250 	  "#include <time.h>\n"
    251 	  "static void func(void) {\n"
    252 	  "	struct timespec ts;\n"
    253 	  "	ts.tv_sec = ts.tv_nsec = 1;\n"
    254 	  "}\n" },
    255 	{ "HAVE_SECTION_START_STOP",
    256 	  DEFINES_FUNC, NULL, NULL,
    257 	  "static void *__attribute__((__section__(\"mysec\"))) p = &p;\n"
    258 	  "static int func(void) {\n"
    259 	  "	extern void *__start_mysec[], *__stop_mysec[];\n"
    260 	  "	return __stop_mysec - __start_mysec;\n"
    261 	  "}\n" },
    262 	{ "HAVE_STACK_GROWS_UPWARDS", DEFINES_EVERYTHING|EXECUTE, NULL, NULL,
    263 	  "static long nest(const void *base, unsigned int i)\n"
    264 	  "{\n"
    265 	  "	if (i == 0)\n"
    266 	  "		return (const char *)&i - (const char *)base;\n"
    267 	  "	return nest(base, i-1);\n"
    268 	  "}\n"
    269 	  "int main(int argc, char *argv[]) {\n"
    270 	  "	return (nest(&argc, argc) > 0) ? 0 : 1\n;"
    271 	  "}\n" },
    272 	{ "HAVE_STATEMENT_EXPR", INSIDE_MAIN, NULL, NULL,
    273 	  "return ({ int x = argc; x == argc ? 0 : 1; });" },
    274 	{ "HAVE_SYS_FILIO_H", OUTSIDE_MAIN, NULL, NULL, /* Solaris needs this for FIONREAD */
    275 	  "#include <sys/filio.h>\n" },
    276 	{ "HAVE_SYS_TERMIOS_H", OUTSIDE_MAIN, NULL, NULL,
    277 	  "#include <sys/termios.h>\n" },
    278 	{ "HAVE_TYPEOF", INSIDE_MAIN, NULL, NULL,
    279 	  "__typeof__(argc) i; i = argc; return i == argc ? 0 : 1;" },
    280 	{ "HAVE_UNALIGNED_ACCESS", DEFINES_EVERYTHING|EXECUTE, NULL, NULL,
    281 	  "#include <string.h>\n"
    282 	  "int main(int argc, char *argv[]) {\n"
    283 	  "     char pad[sizeof(int *) * 1];\n"
    284 	  "	memcpy(pad, argv[0], sizeof(pad));\n"
    285 	  "	return *(int *)(pad) == *(int *)(pad + 1);\n"
    286 	  "}\n" },
    287 	{ "HAVE_UTIME", DEFINES_FUNC, NULL, NULL,
    288 	  "#include <sys/types.h>\n"
    289 	  "#include <utime.h>\n"
    290 	  "static int func(const char *filename) {\n"
    291 	  "	struct utimbuf times = { 0 };\n"
    292 	  "	return utime(filename, &times);\n"
    293 	  "}" },
    294 	{ "HAVE_WARN_UNUSED_RESULT", DEFINES_FUNC, NULL, NULL,
    295 	  "#include <sys/types.h>\n"
    296 	  "#include <utime.h>\n"
    297 	  "static __attribute__((warn_unused_result)) int func(int i) {\n"
    298 	  "	return i + 1;\n"
    299 	  "}" },
    300 };
    301 
    302 static char *grab_fd(int fd)
    303 {
    304 	int ret;
    305 	size_t max, size = 0;
    306 	char *buffer;
    307 
    308 	max = 16384;
    309 	buffer = malloc(max+1);
    310 	while ((ret = read(fd, buffer + size, max - size)) > 0) {
    311 		size += ret;
    312 		if (size == max)
    313 			buffer = realloc(buffer, max *= 2);
    314 	}
    315 	if (ret < 0)
    316 		err(1, "reading from command");
    317 	buffer[size] = '\0';
    318 	return buffer;
    319 }
    320 
    321 static char *run(const char *cmd, int *exitstatus)
    322 {
    323 	pid_t pid;
    324 	int p[2];
    325 	char *ret;
    326 	int status;
    327 
    328 	if (pipe(p) != 0)
    329 		err(1, "creating pipe");
    330 
    331 	pid = fork();
    332 	if (pid == -1)
    333 		err(1, "forking");
    334 
    335 	if (pid == 0) {
    336 		if (dup2(p[1], STDOUT_FILENO) != STDOUT_FILENO
    337 		    || dup2(p[1], STDERR_FILENO) != STDERR_FILENO
    338 		    || close(p[0]) != 0
    339 		    || close(STDIN_FILENO) != 0
    340 		    || open("/dev/null", O_RDONLY) != STDIN_FILENO)
    341 			exit(128);
    342 
    343 		status = system(cmd);
    344 		if (WIFEXITED(status))
    345 			exit(WEXITSTATUS(status));
    346 		/* Here's a hint... */
    347 		exit(128 + WTERMSIG(status));
    348 	}
    349 
    350 	close(p[1]);
    351 	ret = grab_fd(p[0]);
    352 	/* This shouldn't fail... */
    353 	if (waitpid(pid, &status, 0) != pid)
    354 		err(1, "Failed to wait for child");
    355 	close(p[0]);
    356 	if (WIFEXITED(status))
    357 		*exitstatus = WEXITSTATUS(status);
    358 	else
    359 		*exitstatus = -WTERMSIG(status);
    360 	return ret;
    361 }
    362 
    363 static char *connect_args(const char *argv[], const char *extra)
    364 {
    365 	unsigned int i, len = strlen(extra) + 1;
    366 	char *ret;
    367 
    368 	for (i = 1; argv[i]; i++)
    369 		len += 1 + strlen(argv[i]);
    370 
    371 	ret = malloc(len);
    372 	len = 0;
    373 	for (i = 1; argv[i]; i++) {
    374 		strcpy(ret + len, argv[i]);
    375 		len += strlen(argv[i]);
    376 		if (argv[i+1])
    377 			ret[len++] = ' ';
    378 	}
    379 	strcpy(ret + len, extra);
    380 	return ret;
    381 }
    382 
    383 static struct test *find_test(const char *name)
    384 {
    385 	unsigned int i;
    386 
    387 	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
    388 		if (strcmp(tests[i].name, name) == 0)
    389 			return &tests[i];
    390 	}
    391 	abort();
    392 }
    393 
    394 #define PRE_BOILERPLATE "/* Test program generated by configurator. */\n"
    395 #define MAIN_START_BOILERPLATE "int main(int argc, char *argv[]) {\n"
    396 #define USE_FUNC_BOILERPLATE "(void)func;\n"
    397 #define MAIN_BODY_BOILERPLATE "return 0;\n"
    398 #define MAIN_END_BOILERPLATE "}\n"
    399 
    400 static bool run_test(const char *cmd, struct test *test)
    401 {
    402 	char *output;
    403 	FILE *outf;
    404 	int status;
    405 
    406 	if (test->done)
    407 		return test->answer;
    408 
    409 	if (test->depends) {
    410 		size_t len;
    411 		const char *deps = test->depends;
    412 		char *dep;
    413 
    414 		/* Space-separated dependencies, could be ! for inverse. */
    415 		while ((len = strcspn(deps, " "))) {
    416 			bool positive = true;
    417 			if (deps[len]) {
    418 				dep = strdup(deps);
    419 				dep[len] = '\0';
    420 			} else {
    421 				dep = (char *)deps;
    422 			}
    423 
    424 			if (dep[0] == '!') {
    425 				dep++;
    426 				positive = false;
    427 			}
    428 			if (run_test(cmd, find_test(dep)) != positive) {
    429 				test->answer = false;
    430 				test->done = true;
    431 				return test->answer;
    432 			}
    433 			deps += len;
    434 			deps += strspn(deps, " ");
    435 		}
    436 	}
    437 
    438 	outf = fopen(INPUT_FILE, "w");
    439 	if (!outf)
    440 		err(1, "creating %s", INPUT_FILE);
    441 
    442 	fprintf(outf, "%s", PRE_BOILERPLATE);
    443 	switch (test->style & ~(EXECUTE|MAY_NOT_COMPILE)) {
    444 	case INSIDE_MAIN:
    445 		fprintf(outf, "%s", MAIN_START_BOILERPLATE);
    446 		fprintf(outf, "%s", test->fragment);
    447 		fprintf(outf, "%s", MAIN_END_BOILERPLATE);
    448 		break;
    449 	case OUTSIDE_MAIN:
    450 		fprintf(outf, "%s", test->fragment);
    451 		fprintf(outf, "%s", MAIN_START_BOILERPLATE);
    452 		fprintf(outf, "%s", MAIN_BODY_BOILERPLATE);
    453 		fprintf(outf, "%s", MAIN_END_BOILERPLATE);
    454 		break;
    455 	case DEFINES_FUNC:
    456 		fprintf(outf, "%s", test->fragment);
    457 		fprintf(outf, "%s", MAIN_START_BOILERPLATE);
    458 		fprintf(outf, "%s", USE_FUNC_BOILERPLATE);
    459 		fprintf(outf, "%s", MAIN_BODY_BOILERPLATE);
    460 		fprintf(outf, "%s", MAIN_END_BOILERPLATE);
    461 		break;
    462 	case DEFINES_EVERYTHING:
    463 		fprintf(outf, "%s", test->fragment);
    464 		break;
    465 	default:
    466 		abort();
    467 
    468 	}
    469 	fclose(outf);
    470 
    471 	if (verbose > 1)
    472 		if (system("cat " INPUT_FILE) == -1)
    473 			;
    474 
    475 	if (test->link) {
    476 		char *newcmd;
    477 		newcmd = malloc(strlen(cmd) + strlen(" ")
    478 				+ strlen(test->link) + 1);
    479 		sprintf(newcmd, "%s %s", cmd, test->link);
    480 		if (verbose > 1)
    481 			printf("Extra link line: %s", newcmd);
    482 		cmd = newcmd;
    483 	}
    484 
    485 	output = run(cmd, &status);
    486 	if (status != 0 || strstr(output, "warning")) {
    487 		if (verbose)
    488 			printf("Compile %s for %s, status %i: %s\n",
    489 			       status ? "fail" : "warning",
    490 			       test->name, status, output);
    491 		if ((test->style & EXECUTE) && !(test->style & MAY_NOT_COMPILE))
    492 			errx(1, "Test for %s did not compile:\n%s",
    493 			     test->name, output);
    494 		test->answer = false;
    495 		free(output);
    496 	} else {
    497 		/* Compile succeeded. */
    498 		free(output);
    499 		/* We run INSIDE_MAIN tests for sanity checking. */
    500 		if ((test->style & EXECUTE) || (test->style & INSIDE_MAIN)) {
    501 			output = run("./" OUTPUT_FILE, &status);
    502 			if (!(test->style & EXECUTE) && status != 0)
    503 				errx(1, "Test for %s failed with %i:\n%s",
    504 				     test->name, status, output);
    505 			if (verbose && status)
    506 				printf("%s exited %i\n", test->name, status);
    507 			free(output);
    508 		}
    509 		test->answer = (status == 0);
    510 	}
    511 	test->done = true;
    512 
    513 	if (test->answer && test->overrides) {
    514 		struct test *override = find_test(test->overrides);
    515 		override->done = true;
    516 		override->answer = true;
    517 	}
    518 	return test->answer;
    519 }
    520 
    521 int main(int argc, const char *argv[])
    522 {
    523 	char *cmd;
    524 	unsigned int i;
    525 	const char *default_args[]
    526 		= { "", DEFAULT_COMPILER, DEFAULT_FLAGS, NULL };
    527 
    528 	if (argc > 1) {
    529 		if (strcmp(argv[1], "--help") == 0) {
    530 			printf("Usage: configurator [-v] [<compiler> <flags>...]\n"
    531 			       "  <compiler> <flags> will have \"-o <outfile> <infile.c>\" appended\n"
    532 			       "Default: %s %s\n",
    533 			       DEFAULT_COMPILER, DEFAULT_FLAGS);
    534 			exit(0);
    535 		}
    536 		if (strcmp(argv[1], "-v") == 0) {
    537 			argc--;
    538 			argv++;
    539 			verbose = 1;
    540 		} else if (strcmp(argv[1], "-vv") == 0) {
    541 			argc--;
    542 			argv++;
    543 			verbose = 2;
    544 		}
    545 	}
    546 
    547 	if (argc == 1)
    548 		argv = default_args;
    549 
    550 	cmd = connect_args(argv, " -o " OUTPUT_FILE " " INPUT_FILE);
    551 	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
    552 		run_test(cmd, &tests[i]);
    553 
    554 	unlink(OUTPUT_FILE);
    555 	unlink(INPUT_FILE);
    556 
    557 	printf("/* Generated by CCAN configurator */\n"
    558 	       "#ifndef CCAN_CONFIG_H\n"
    559 	       "#define CCAN_CONFIG_H\n");
    560 	printf("#ifndef _GNU_SOURCE\n");
    561 	printf("#define _GNU_SOURCE /* Always use GNU extensions. */\n");
    562 	printf("#endif\n");
    563 	printf("#define CCAN_COMPILER \"%s\"\n", argv[1]);
    564 	printf("#define CCAN_CFLAGS \"%s\"\n\n", connect_args(argv+1, ""));
    565 	/* This one implies "#include <ccan/..." works, eg. for tdb2.h */
    566 	printf("#define HAVE_CCAN 1\n");
    567 	for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
    568 		printf("#define %s %u\n", tests[i].name, tests[i].answer);
    569 	printf("#endif /* CCAN_CONFIG_H */\n");
    570 	return 0;
    571 }