#include <sys/cdefs.h>
#include <sys/types.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sysexits.h>
#include <limits.h>
#include <mach-o/dyld.h>
char **args;
u_int cargs, nargs;
void addarg(const char *);
void addlib(const char *);
void combine_and_addarg (const char *, const char *);
void usage(void);
char **undef_args;
u_int undef_cargs, undef_nargs;
void record_undef(const char *);
void add_def(const char *);
void combine_and_addarg (const char *, const char *);
int
main(int argc, char *argv[])
{
char exec_path[PATH_MAX];
char link_path[PATH_MAX];
uint32_t exec_path_size = sizeof(exec_path);
char *compiler_path = exec_path;
char *lastslash;
int link = 1;
int inputs = 0;
int verbose = 0;
int m_32_64_set = 0;
if (_NSGetExecutablePath(exec_path, &exec_path_size))
memcpy(exec_path, "/usr/bin/c99", sizeof("/usr/bin/c99"));
if (realpath(exec_path, link_path))
compiler_path = link_path;
lastslash = strrchr(compiler_path, '/');
if (!lastslash)
err(EX_OSERR, "unexpected path name: %s", compiler_path);
strcpy(lastslash+1, "clang");
addarg(compiler_path);
addarg("-std=iso9899:1999");
addarg("-pedantic");
addarg("-Wextra-tokens");
addarg("-Wno-error=return-type");
addarg("-Wstatic-in-inline");
addarg("-Wignored-qualifiers");
addarg("-fmath-errno");
addarg("-fno-blocks");
for (;;)
{
int ch = getopt(argc, argv, "cD:EgI:L:o:O:sU:W:l:");
if (optind >= argc && ch == -1)
break;
switch (ch)
{
case 'c':
addarg ("-c");
link = 0;
break;
case 'D':
add_def (optarg);
break;
case 'E':
addarg ("-E");
link = 0;
break;
case 'g':
addarg ("-g");
break;
case 'I':
combine_and_addarg ("-I", optarg);
break;
case 'L':
combine_and_addarg ("-L", optarg);
break;
case 'o':
addarg ("-o");
addarg (optarg);
break;
case 'O':
combine_and_addarg ("-O", optarg);
break;
case 's':
addarg ("-s");
break;
case 'U':
record_undef (optarg);
combine_and_addarg ("-U", optarg);
break;
case 'W':
if (strcmp (optarg, "32") == 0) {
addarg ("-m32");
m_32_64_set = 1;
} else if (strcmp (optarg, "64") == 0) {
addarg ("-m64");
m_32_64_set = 1;
} else if (strcmp (optarg, "verbose") == 0)
{
addarg ("-v");
verbose = 1;
}
else
errx(EX_USAGE, "invalid argument `%s' to -W", optarg);
break;
case 'l':
addlib (optarg);
break;
case -1:
if (strcmp (argv[optind-1], "--") == 0)
{
while (optind < argc)
{
if (argv[optind][0] == '-')
combine_and_addarg ("./", argv[optind]);
else
addarg (argv[optind]);
inputs++;
optind++;
}
}
else
{
addarg (argv[optind++]);
inputs++;
}
break;
case '?':
usage ();
break;
}
}
#ifdef __LP64__
if (!m_32_64_set)
addarg("-m64");
#else
if (!m_32_64_set)
addarg("-m32");
#endif
if (link && inputs > 0) {
addarg("-liconv");
}
if (verbose)
{
int i;
for (i = 0; args[i]; i++)
printf ("\"%s\" ", args[i]);
putchar ('\n');
}
execv(compiler_path, args);
err(EX_OSERR, "failed to exec compiler %s", compiler_path);
}
void
combine_and_addarg (const char *item1, const char *item2)
{
char *item = (char *) malloc (sizeof (char) * (strlen(item1) + strlen(item2) + 1));
if (item == NULL)
err (EX_OSERR, "malloc");
strcpy (item, item1);
strcat (item, item2);
addarg (item);
}
void
record_undef (const char *item)
{
if (undef_nargs + 1 > undef_cargs) {
undef_cargs += 16;
undef_args = realloc(undef_args, sizeof(*undef_args) * undef_cargs);
if (undef_args == NULL)
err(EX_OSERR, "malloc");
}
if ((undef_args[undef_nargs++] = strdup(item)) == NULL)
err(EX_OSERR, "strdup");
undef_args[undef_nargs] = NULL;
}
void
add_def (const char *item)
{
u_int i;
const char * equ_pos;
equ_pos = strchr (item, '=');
if (equ_pos == NULL)
equ_pos = item + strlen (item);
for (i = 0; i < undef_nargs; i++)
if (strncmp (item, undef_args[i], equ_pos - item) == 0
&& undef_args[i][equ_pos - item] == '\0')
return;
combine_and_addarg ("-D", item);
}
void
addarg(const char *item)
{
if (nargs + 2 > cargs) {
cargs += 16;
if ((args = realloc(args, sizeof(*args) * cargs)) == NULL)
err(EX_OSERR, "malloc");
}
args[nargs++] = strdup (item);
if (args[nargs-1] == NULL)
err(EX_OSERR, "strdup");
args[nargs] = NULL;
}
void
addlib(const char *lib)
{
if (strcmp(lib, "pthread") == 0)
return;
if (strcmp(lib, "rt") == 0)
return;
if (strcmp(lib, "xnet") == 0)
return;
combine_and_addarg("-l", lib);
}
void
usage(void)
{
fprintf(stderr,
"usage: c99 [-cEgs] [-D name[=value]] [-I directory] ... [-L directory] ...\n");
fprintf(stderr,
" [-o outfile] [-O optlevel] [-U name]... [-W 64] operand ...\n");
exit(1);
}