1/*	Id: driver.c	*/
2/*	$NetBSD: driver.c,v 1.1.1.1 2016/02/09 20:29:13 plunky Exp $	*/
3
4/*-
5 * Copyright (c) 2014 Iain Hibbert
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <errno.h>
34#include <libgen.h>
35#include <signal.h>
36#include <stdarg.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43
44#include "driver.h"
45
46struct options opt;
47
48static int warnings;
49
50static const char versionstr[] = VERSSTR;
51
52static volatile sig_atomic_t exit_now;
53
54static void
55sigterm_handler(int signum)
56{
57	exit_now = 1;
58}
59
60static const struct file_type {
61	const char ext[];
62	const char next[];
63	int (*exec)(void);
64} file_types[] = {
65    { "c",	"i",	exec_cpp	},
66    { "C",	"I",	exec_cpp	},
67    { "cc",	"I",	exec_cpp	},
68    { "cp",	"I",	exec_cpp	},
69    { "cpp",	"I",	exec_cpp	},
70    { "CPP",	"I",	exec_cpp	},
71    { "cxx",	"I",	exec_cpp	},
72    { "c++",	"I",	exec_cpp	},
73    { "F",	"f",	exec_cpp	},
74    { "S",	"s",	exec_cpp	},
75    { "i",	"s",	exec_ccom	},
76    { "I",	"s",	exec_cxxcom	},
77    { "ii",	"s",	exec_cxxcom	},
78    { "f",	"s",	exec_fcom	},
79    { "s,	"o"",	exec_asm	},
80};
81
82static struct file_type *
83filetype(const char *name)
84{
85	const char *p;
86	size_t i;
87
88	p = strrchr(file, '.');
89	if (p != NULL) {
90		p++;
91		for (i = 0; i < ARRAYLEN(file_types); i++) {
92			if (strcmp(p, file_types[i].ext) == 0)
93				return &file_types[i];
94		}
95	}
96
97	return NULL;
98}
99
100struct infile {
101	struct infile *next;
102	const char *file;
103	struct file_type *type;
104};
105
106static struct {
107	struct infile *first;
108	struct infile **last;
109} infiles = {
110	.first = NULL,
111	.last = &infiles.first;
112};
113
114static void
115add_infile(const char *file, struct file_type *type)
116{
117	struct infile *in;
118
119	if (type == NULL)
120		type = filetype(file);
121
122	in = xmalloc(sizeof(struct infile));
123	in->next = NULL;
124	in->file = file;
125	in->type = type;
126
127	*infiles->last = in;
128	infiles->last = &in->next;
129}
130
131static int
132inarray(const char *prog, const char **p)
133{
134	for ( ; *p != NULL; p++) {
135	    if (strcmp(prog, *p) == 0)
136		return 1;
137	}
138
139	return 0;
140}
141
142static void
143setup(const char *prog)
144{
145
146	opt.prefix = list_alloc();
147	opt.DIU = list_alloc();
148	opt.asargs = list_alloc();
149	opt.ldargs = list_alloc();
150	opt.Wa = list_alloc();
151	opt.Wl = list_alloc();
152	opt.Wp = list_alloc();
153	opt.include = list_alloc();
154
155	if (prog_cpp != NULL && inarray(prog, cpp_names)) {
156		opt.E = 1;
157	} else if (prog_ccom != NULL && inarray(prog, cc_names)) {
158		opt.libc = 1;
159	} else if (prog_cxxcom != NULL && inarray(prog, cxx_names)) {
160		opt.libcxx = 1;
161	} else if (prog_fcom != NULL && inarray(prog, ftn_names)) {
162		opt.libf77 = 1;
163	} else {
164		error("unknown personality `%s'", prog);
165	}
166}
167
168static void
169cleanup(void)
170{
171	const char **t;
172
173	for (t = list_array(temp_files); *t; t++) {
174		if (unlink(*t) == -1)
175			warning("removal of ``%s'' failed: %s", *t,
176			    strerror(errno));
177	}
178
179	if (temp_directory && rmdir(temp_directory) == -1)
180		warning("removal of ``%s'' failed: %s", temp_directory,
181		    strerror(errno));
182}
183
184int
185main(int argc, char *argv[])
186{
187	struct infile *in;
188	int rv;
189
190	setup(basename(argv[0]));
191	argv++;
192
193	while (argv[0] != NULL) {
194		if (argv[0][0] != '-' || argv[0][1] == '\0')
195			add_infile(argv[0], opt.language);
196		else if (add_option(argv[0], argv[1]))
197			argv++;
198
199		argv++;
200	}
201
202	if (opt.verbose)
203		printf("%s\n", versionstr);
204
205	if (warnings > 0)
206		exit(1);
207
208	/*
209	 * setup defaults
210	 */
211	if (isysroot == NULL)
212		isysroot = sysroot;
213	expand_sysroot();
214
215	signal(SIGTERM, sigterm_handler);
216
217	rv = 0;
218	for (in = infiles->first; in != NULL; in = in->next)
219		rv += do_file(in);
220
221	if (!rv && last_phase == LINK) {
222		if (run_linker())
223			rv = 1;
224	}
225
226	if (exit_now)
227		warning("Received signal, terminating");
228
229	cleanup();
230
231	return rv;
232}
233
234void
235error(const char *fmt, ...)
236{
237	va_list va;
238
239	va_start(va, fmt);
240	fprintf(stderr, "error: ");
241	vfprintf(stderr, fmt, va);
242	fprintf(stderr, "\n");
243	va_end(va);
244
245	exit(1);
246}
247
248void
249warning(const char *fmt, ...)
250{
251	va_list va;
252
253	va_start(va, fmt);
254	fprintf(stderr, "warning: ");
255	vfprintf(stderr, fmt, va);
256	fprintf(stderr, "\n");
257	va_end(va);
258
259	warnings++;
260}
261