Move arguments parsing to option.c

This commit is contained in:
d0p1 🏳️‍⚧️ 2025-02-08 18:38:14 +01:00
parent 6318a909ff
commit db4e043cd9
11 changed files with 747 additions and 813 deletions

View file

@ -1,6 +1,6 @@
noinst_LIBRARIES = libtcc.a
libtcc_a_SOURCES = libtcc.c tccpp.c tccgen.c \
libtcc_a_SOURCES = libtcc.c option.c tccpp.c tccgen.c \
tccasm.c tccelf.c \
i386/gen.c i386/link.c \
i386/asm.c tcccoff.c
libtcc_a_CPPFLAGS = -I$(top_srcdir) -I$(srcdir) -I$(srcdir)/include
libtcc_a_CPPFLAGS = -I$(top_srcdir) -I$(srcdir) -I$(srcdir)/include

View file

@ -25,9 +25,8 @@
#define _DARWIN_C_SOURCE
#include "config.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
/* gnu headers use to #define __attribute__ to empty for non-gcc compilers */
#ifdef __TINYC__
# undef __attribute__
@ -853,21 +852,13 @@ int tcc_add_support(TCCState *s1, const char *filename);
void tcc_add_pragma_libs(TCCState *s1);
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind);
char *tcc_load_text(int fd);
#ifdef _WIN32
char *normalize_slashes(char *path);
#endif
/* for #pragma once */
int normalized_PATHCMP(const char *f1, const char *f2);
/* tcc_parse_args return codes: */
#define OPT_HELP 1
#define OPT_HELP2 2
#define OPT_V 3
#define OPT_PRINT_DIRS 4
#define OPT_AR 5
#define OPT_IMPDEF 6
/* ------------ tccpp.c ------------ */
extern struct BufferedFile *file;

View file

@ -6,10 +6,11 @@
# define TCC_OPTION_HAS_ARG 0x0001
# define TCC_OPTION_NOSEP 0x0002 /** cannot have space before option and arg */
# define TCC_OPT_HELP 'h'
# define TCC_OPT_HELP_MORE 'm'
# define TCC_OPT_ARCHIVE 'a'
# define TCC_OPT_VERSION 'V'
# define TCC_OPT_HELP 'h'
# define TCC_OPT_HELP_MORE 'm'
# define TCC_OPT_ARCHIVE 'a'
# define TCC_OPT_VERSION 'V'
# define TCC_OPT_PRINT_DIRS 'P'
typedef struct TCCOption {
const char *name;

View file

@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tcc.h"
#include <tcc.h>
#include "utils/string.h"
/********************************************************/
@ -989,717 +989,6 @@ void tcc_set_lib_path(TCCState *s, const char *path)
/********************************************************/
/* options parser */
static int strstart(const char *val, const char **str)
{
const char *p, *q;
p = *str;
q = val;
while (*q) {
if (*p != *q)
return 0;
p++;
q++;
}
*str = p;
return 1;
}
/* Like strstart, but automatically takes into account that ld options can
*
* - start with double or single dash (e.g. '--soname' or '-soname')
* - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so'
* or '-Wl,-soname=x.so')
*
* you provide `val` always in 'option[=]' form (no leading -)
*/
static int link_option(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
int ret;
/* there should be 1 or 2 dashes */
if (*str++ != '-')
return 0;
if (*str == '-')
str++;
/* then str & val should match (potentially up to '=') */
p = str;
q = val;
ret = 1;
if (q[0] == '?') {
++q;
if (strstart("no-", &p))
ret = -1;
}
while (*q != '\0' && *q != '=') {
if (*p != *q)
return 0;
p++;
q++;
}
/* '=' near eos means ',' or '=' is ok */
if (*q == '=') {
if (*p == 0)
*ptr = p;
if (*p != ',' && *p != '=')
return 0;
p++;
} else if (*p) {
return 0;
}
*ptr = p;
return ret;
}
static int link_arg(const char *opt, const char *str)
{
int l = strlen(opt);
return 0 == strncmp(opt, str, l) && (str[l] == '\0' || str[l] == ',');
}
static const char *skip_linker_arg(const char **str)
{
const char *s1 = *str;
const char *s2 = strchr(s1, ',');
*str = s2 ? s2++ : (s2 = s1 + strlen(s1));
return s2;
}
static void copy_linker_arg(char **pp, const char *s, int sep)
{
const char *q = s;
char *p = *pp;
int l = 0;
if (p && sep)
p[l = strlen(p)] = sep, ++l;
skip_linker_arg(&q);
pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s);
}
static void args_parser_add_file(TCCState *s, const char* filename, int filetype)
{
struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
f->type = filetype;
strcpy(f->name, filename);
dynarray_add(&s->files, &s->nb_files, f);
}
/* set linker options */
static int tcc_set_linker(TCCState *s, const char *option)
{
TCCState *s1 = s;
while (*option) {
const char *p = NULL;
char *end = NULL;
int ignoring = 0;
int ret;
if (link_option(option, "Bsymbolic", &p)) {
s->symbolic = 1;
} else if (link_option(option, "nostdlib", &p)) {
s->nostdlib = 1;
} else if (link_option(option, "e=", &p)
|| link_option(option, "entry=", &p)) {
copy_linker_arg(&s->elf_entryname, p, 0);
} else if (link_option(option, "fini=", &p)) {
copy_linker_arg(&s->fini_symbol, p, 0);
ignoring = 1;
} else if (link_option(option, "image-base=", &p)
|| link_option(option, "Ttext=", &p)) {
s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1;
} else if (link_option(option, "init=", &p)) {
copy_linker_arg(&s->init_symbol, p, 0);
ignoring = 1;
} else if (link_option(option, "Map=", &p)) {
copy_linker_arg(&s->mapfile, p, 0);
ignoring = 1;
} else if (link_option(option, "oformat=", &p)) {
if (strstart("elf32-", &p)) {
s->output_format = TCC_OUTPUT_FORMAT_ELF;
} else if (link_arg("binary", p)) {
s->output_format = TCC_OUTPUT_FORMAT_BINARY;
#ifdef TCC_TARGET_COFF
} else if (link_arg("coff", p)) {
s->output_format = TCC_OUTPUT_FORMAT_COFF;
#endif
} else
goto err;
} else if (link_option(option, "as-needed", &p)) {
ignoring = 1;
} else if (link_option(option, "O", &p)) {
ignoring = 1;
} else if (link_option(option, "rpath=", &p)) {
copy_linker_arg(&s->rpath, p, ':');
} else if (link_option(option, "enable-new-dtags", &p)) {
s->enable_new_dtags = 1;
} else if (link_option(option, "section-alignment=", &p)) {
s->section_align = strtoul(p, &end, 16);
} else if (ret = link_option(option, "?whole-archive", &p), ret) {
if (ret > 0)
s->filetype |= AFF_WHOLE_ARCHIVE;
else
s->filetype &= ~AFF_WHOLE_ARCHIVE;
} else if (link_option(option, "z=", &p)) {
ignoring = 1;
} else if (p) {
return 0;
} else {
err:
return tcc_error_noabort("unsupported linker option '%s'", option);
}
if (ignoring)
tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", option);
option = skip_linker_arg(&p);
}
return 1;
}
typedef struct TCCOption {
const char *name;
uint16_t index;
uint16_t flags;
} TCCOption;
enum {
TCC_OPTION_ignored = 0,
TCC_OPTION_HELP,
TCC_OPTION_HELP2,
TCC_OPTION_v,
TCC_OPTION_I,
TCC_OPTION_D,
TCC_OPTION_U,
TCC_OPTION_P,
TCC_OPTION_L,
TCC_OPTION_B,
TCC_OPTION_l,
TCC_OPTION_bench,
TCC_OPTION_bt,
TCC_OPTION_b,
TCC_OPTION_ba,
TCC_OPTION_g,
TCC_OPTION_c,
TCC_OPTION_dumpmachine,
TCC_OPTION_dumpversion,
TCC_OPTION_d,
TCC_OPTION_static,
TCC_OPTION_std,
TCC_OPTION_shared,
TCC_OPTION_soname,
TCC_OPTION_o,
TCC_OPTION_r,
TCC_OPTION_Wl,
TCC_OPTION_Wp,
TCC_OPTION_W,
TCC_OPTION_O,
TCC_OPTION_mfloat_abi,
TCC_OPTION_m,
TCC_OPTION_f,
TCC_OPTION_isystem,
TCC_OPTION_iwithprefix,
TCC_OPTION_include,
TCC_OPTION_nostdinc,
TCC_OPTION_nostdlib,
TCC_OPTION_print_search_dirs,
TCC_OPTION_rdynamic,
TCC_OPTION_pthread,
TCC_OPTION_w,
TCC_OPTION_E,
TCC_OPTION_M,
TCC_OPTION_MD,
TCC_OPTION_MF,
TCC_OPTION_MM,
TCC_OPTION_MMD,
TCC_OPTION_MP,
TCC_OPTION_x,
TCC_OPTION_ar,
TCC_OPTION_impdef,
TCC_OPTION_dynamiclib,
TCC_OPTION_flat_namespace,
TCC_OPTION_two_levelnamespace,
TCC_OPTION_undefined,
TCC_OPTION_install_name,
TCC_OPTION_compatibility_version ,
TCC_OPTION_current_version,
};
#define TCC_OPTION_HAS_ARG 0x0001
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
static const TCCOption tcc_options[] = {
{ "h", TCC_OPTION_HELP, 0 },
{ "-help", TCC_OPTION_HELP, 0 },
{ "?", TCC_OPTION_HELP, 0 },
{ "hh", TCC_OPTION_HELP2, 0 },
{ "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "-version", TCC_OPTION_v, 0 }, /* handle as verbose, also prints version*/
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
{ "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
{ "bench", TCC_OPTION_bench, 0 },
{ "c", TCC_OPTION_c, 0 },
{ "dumpmachine", TCC_OPTION_dumpmachine, 0},
{ "dumpversion", TCC_OPTION_dumpversion, 0},
{ "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
{ "pthread", TCC_OPTION_pthread, 0},
{ "rdynamic", TCC_OPTION_rdynamic, 0 },
{ "r", TCC_OPTION_r, 0 },
{ "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "Wp,", TCC_OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
{ "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG },
{ "nostdinc", TCC_OPTION_nostdinc, 0 },
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
{ "w", TCC_OPTION_w, 0 },
{ "E", TCC_OPTION_E, 0},
{ "M", TCC_OPTION_M, 0},
{ "MD", TCC_OPTION_MD, 0},
{ "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG },
{ "MM", TCC_OPTION_MM, 0},
{ "MMD", TCC_OPTION_MMD, 0},
{ "MP", TCC_OPTION_MP, 0},
{ "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
{ "ar", TCC_OPTION_ar, 0},
/* ignored (silently, except after -Wunsupported) */
{ "arch", 0, TCC_OPTION_HAS_ARG},
{ "g", 0, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
{ "C", 0, 0 },
{ "-param", 0, TCC_OPTION_HAS_ARG },
{ "pedantic", 0, 0 },
{ "pipe", 0, 0 },
{ "s", 0, 0 },
{ "traditional", 0, 0 },
{ "static", 0, 0},
{ "shared", 0, 0},
{ "soname", 0, 0},
{ NULL, 0, 0 },
};
typedef struct FlagDef {
uint16_t offset;
uint16_t flags;
const char *name;
} FlagDef;
#define WD_ALL 0x0001 /* warning is activated when using -Wall */
#define FD_INVERT 0x0002 /* invert value before storing */
static const FlagDef options_W[] = {
{ offsetof(TCCState, warn_all), WD_ALL, "all" },
{ offsetof(TCCState, warn_error), 0, "error" },
{ offsetof(TCCState, warn_write_strings), 0, "write-strings" },
{ offsetof(TCCState, warn_unsupported), 0, "unsupported" },
{ offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, "implicit-function-declaration" },
{ offsetof(TCCState, warn_discarded_qualifiers), WD_ALL, "discarded-qualifiers" },
{ 0, 0, NULL }
};
static const FlagDef options_f[] = {
{ offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
{ offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
{ offsetof(TCCState, nocommon), FD_INVERT, "common" },
{ offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
{ offsetof(TCCState, ms_extensions), 0, "ms-extensions" },
{ offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },
{ offsetof(TCCState, reverse_funcargs), 0, "reverse-funcargs" },
{ offsetof(TCCState, gnu89_inline), 0, "gnu89-inline" },
{ offsetof(TCCState, unwind_tables), 0, "asynchronous-unwind-tables" },
{ 0, 0, NULL }
};
static const FlagDef options_m[] = {
{ offsetof(TCCState, ms_bitfields), 0, "ms-bitfields" },
{ 0, 0, NULL }
};
static int set_flag(TCCState *s, const FlagDef *flags, const char *name)
{
int value, mask, ret;
const FlagDef *p;
const char *r;
unsigned char *f;
r = name, value = !strstart("no-", &r), mask = 0;
/* when called with options_W, look for -W[no-]error=<option> */
if ((flags->flags & WD_ALL) && strstart("error=", &r))
value = value ? WARN_ON|WARN_ERR : WARN_NOE, mask = WARN_ON;
for (ret = -1, p = flags; p->name; ++p) {
if (ret) {
if (strcmp(r, p->name))
continue;
} else {
if (0 == (p->flags & WD_ALL))
continue;
}
f = (unsigned char *)s + p->offset;
*f = (*f & mask) | (value ^ !!(p->flags & FD_INVERT));
if (ret) {
ret = 0;
if (strcmp(r, "all"))
break;
}
}
return ret;
}
static const char dumpmachine_str[] = "i386-pc-stupidos";
static int args_parser_make_argv(const char *r, int *argc, char ***argv)
{
int ret = 0, q, c;
CString str;
for(;;) {
while (c = (unsigned char)*r, c && c <= ' ')
++r;
if (c == 0)
break;
q = 0;
cstr_new(&str);
while (c = (unsigned char)*r, c) {
++r;
if (c == '\\' && (*r == '"' || *r == '\\')) {
c = *r++;
} else if (c == '"') {
q = !q;
continue;
} else if (q == 0 && c <= ' ') {
break;
}
cstr_ccat(&str, c);
}
cstr_ccat(&str, 0);
//printf("<%s>\n", str.data), fflush(stdout);
dynarray_add(argv, argc, tcc_strdup(str.data));
cstr_free(&str);
++ret;
}
return ret;
}
/* read list file */
static int args_parser_listfile(TCCState *s,
const char *filename, int optind, int *pargc, char ***pargv)
{
TCCState *s1 = s;
int fd, i;
char *p;
int argc = 0;
char **argv = NULL;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return tcc_error_noabort("listfile '%s' not found", filename);
p = tcc_load_text(fd);
for (i = 0; i < *pargc; ++i)
if (i == optind)
args_parser_make_argv(p, &argc, &argv);
else
dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i]));
tcc_free(p);
dynarray_reset(&s->argv, &s->argc);
*pargc = s->argc = argc, *pargv = s->argv = argv;
return 0;
}
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
{
TCCState *s1 = s;
const TCCOption *popt;
const char *optarg, *r;
const char *run = NULL;
int x;
int tool = 0, arg_start = 0, noaction = optind;
char **argv = *pargv;
int argc = *pargc;
cstr_reset(&s->linker_arg);
while (optind < argc) {
r = argv[optind];
if (r[0] == '@' && r[1] != '\0') {
if (args_parser_listfile(s, r + 1, optind, &argc, &argv))
return -1;
continue;
}
optind++;
if (tool) {
if (r[0] == '-' && r[1] == 'v' && r[2] == 0)
++s->verbose;
continue;
}
reparse:
if (r[0] != '-' || r[1] == '\0') {
args_parser_add_file(s, r, s->filetype);
if (run) {
dorun:
if (tcc_set_options(s, run))
return -1;
arg_start = optind - 1;
break;
}
continue;
}
/* allow "tcc files... -run -- args ..." */
if (r[1] == '-' && r[2] == '\0' && run)
goto dorun;
/* find option in table */
for(popt = tcc_options; ; ++popt) {
const char *p1 = popt->name;
const char *r1 = r + 1;
if (p1 == NULL)
return tcc_error_noabort("invalid option -- '%s'", r);
if (!strstart(p1, &r1))
continue;
optarg = r1;
if (popt->flags & TCC_OPTION_HAS_ARG) {
if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) {
if (optind >= argc)
arg_err:
return tcc_error_noabort("argument to '%s' is missing", r);
optarg = argv[optind++];
}
} else if (*r1 != '\0')
continue;
break;
}
switch(popt->index) {
case TCC_OPTION_HELP:
x = OPT_HELP;
goto extra_action;
case TCC_OPTION_HELP2:
x = OPT_HELP2;
goto extra_action;
case TCC_OPTION_I:
tcc_add_include_path(s, optarg);
break;
case TCC_OPTION_D:
tcc_define_symbol(s, optarg, NULL);
break;
case TCC_OPTION_U:
tcc_undefine_symbol(s, optarg);
break;
case TCC_OPTION_L:
tcc_add_library_path(s, optarg);
break;
case TCC_OPTION_B:
/* set tcc utilities path (mainly for tcc development) */
tcc_set_lib_path(s, optarg);
++noaction;
break;
case TCC_OPTION_l:
args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
s->nb_libraries++;
break;
case TCC_OPTION_pthread:
s->option_pthread = 1;
break;
case TCC_OPTION_bench:
s->do_bench = 1;
break;
case TCC_OPTION_c:
x = TCC_OUTPUT_OBJ;
set_output_type:
if (s->output_type)
tcc_warning("-%s: overriding compiler action already specified", popt->name);
s->output_type = x;
break;
case TCC_OPTION_d:
if (*optarg == 'D')
s->dflag = 3;
else if (*optarg == 'M')
s->dflag = 7;
else
goto unsupported_option;
break;
case TCC_OPTION_std:
if (strcmp(optarg, "=c11") == 0 || strcmp(optarg, "=gnu11") == 0)
s->cversion = 201112;
break;
case TCC_OPTION_o:
if (s->outfile) {
tcc_warning("multiple -o option");
tcc_free(s->outfile);
}
s->outfile = tcc_strdup(optarg);
break;
case TCC_OPTION_r:
/* generate a .o merging several output files */
s->option_r = 1;
x = TCC_OUTPUT_OBJ;
goto set_output_type;
case TCC_OPTION_isystem:
tcc_add_sysinclude_path(s, optarg);
break;
case TCC_OPTION_include:
cstr_printf(&s->cmdline_incl, "#include \"%s\"\n", optarg);
break;
case TCC_OPTION_nostdinc:
s->nostdinc = 1;
break;
case TCC_OPTION_nostdlib:
s->nostdlib = 1;
break;
case TCC_OPTION_v:
do ++s->verbose; while (*optarg++ == 'v');
++noaction;
break;
case TCC_OPTION_f:
if (set_flag(s, options_f, optarg) < 0)
goto unsupported_option;
break;
case TCC_OPTION_m:
if (set_flag(s, options_m, optarg) < 0) {
if (x = atoi(optarg), x != 32 && x != 64)
goto unsupported_option;
if (PTR_SIZE != x/8)
return x;
++noaction;
}
break;
case TCC_OPTION_W:
s->warn_none = 0;
if (optarg[0] && set_flag(s, options_W, optarg) < 0)
goto unsupported_option;
break;
case TCC_OPTION_w:
s->warn_none = 1;
break;
case TCC_OPTION_Wl:
if (s->linker_arg.size)
((char*)s->linker_arg.data)[s->linker_arg.size - 1] = ',';
cstr_cat(&s->linker_arg, optarg, 0);
x = tcc_set_linker(s, s->linker_arg.data);
if (x)
cstr_reset(&s->linker_arg);
if (x < 0)
return -1;
break;
case TCC_OPTION_Wp:
r = optarg;
goto reparse;
case TCC_OPTION_E:
x = TCC_OUTPUT_PREPROCESS;
goto set_output_type;
case TCC_OPTION_P:
s->Pflag = atoi(optarg) + 1;
break;
case TCC_OPTION_M:
s->include_sys_deps = 1;
// fall through
case TCC_OPTION_MM:
s->just_deps = 1;
if(!s->deps_outfile)
s->deps_outfile = tcc_strdup("-");
// fall through
case TCC_OPTION_MMD:
s->gen_deps = 1;
break;
case TCC_OPTION_MD:
s->gen_deps = 1;
s->include_sys_deps = 1;
break;
case TCC_OPTION_MF:
s->deps_outfile = tcc_strdup(optarg);
break;
case TCC_OPTION_MP:
s->gen_phony_deps = 1;
break;
case TCC_OPTION_dumpmachine:
printf("%s\n", dumpmachine_str);
exit(0);
case TCC_OPTION_dumpversion:
printf ("%s\n", PACKAGE_VERSION);
exit(0);
case TCC_OPTION_x:
x = 0;
if (*optarg == 'c')
x = AFF_TYPE_C;
else if (*optarg == 'a')
x = AFF_TYPE_ASMPP;
else if (*optarg == 'b')
x = AFF_TYPE_BIN;
else if (*optarg == 'n')
x = AFF_TYPE_NONE;
else
tcc_warning("unsupported language '%s'", optarg);
s->filetype = x | (s->filetype & ~AFF_TYPE_MASK);
break;
case TCC_OPTION_O:
s->optimize = atoi(optarg);
break;
case TCC_OPTION_print_search_dirs:
x = OPT_PRINT_DIRS;
goto extra_action;
case TCC_OPTION_impdef:
x = OPT_IMPDEF;
goto extra_action;
case TCC_OPTION_ar:
x = OPT_AR;
extra_action:
arg_start = optind - 1;
if (arg_start != noaction)
return tcc_error_noabort("cannot parse %s here", r);
tool = x;
break;
default:
unsupported_option:
tcc_warning_c(warn_unsupported)("unsupported option '%s'", r);
break;
}
}
if (s->linker_arg.size) {
r = s->linker_arg.data;
goto arg_err;
}
*pargc = argc - arg_start;
*pargv = argv + arg_start;
if (tool)
return tool;
if (optind != noaction)
return 0;
if (s->verbose == 2)
return OPT_PRINT_DIRS;
if (s->verbose)
return OPT_V;
return OPT_HELP;
}
int tcc_set_options(TCCState *s, const char *r)
{
char **argv = NULL;
int argc = 0, ret;
args_parser_make_argv(r, &argc, &argv);
ret = tcc_parse_args(s, &argc, &argv, 0);
dynarray_reset(&argv, &argc);
return ret < 0 ? ret : 0;
}
PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time)
{
if (!total_time)

View file

@ -1,10 +1,28 @@
#include <stdlib.h>
#include <string.h>
#include <tcc.h>
#include <tcc/option.h>
#include "utils/cstr.h"
#include "utils/string.h"
# define F_WD_ALL 0x0001 /* warning is activated when using -Wall */
# define F_FD_INVERT 0x0002 /* invert value before storing */
# define WARN_ON 1 /* warning is on (-Woption) */
# define WARN_ERR 2 /* warning is an error (-Werror=option) */
# define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */
typedef struct Flag {
uint16_t offset;
uint16_t flags;
const char *name;
} Flag;
enum {
OPTION_ignored = 0,
OPTION_HELP,
OPTION_HELP_MORE,
OPTION_v,
OPTION_I,
OPTION_D,
OPTION_U,
@ -41,9 +59,16 @@ enum {
OPTION_MMD,
OPTION_MP,
OPTION_x,
OPTION_ar,
};
static const TCCOption options[] = {
{"h", OPTION_HELP, 0},
{"-help", OPTION_HELP, 0},
{"?", OPTION_HELP, 0},
{"hh", OPTION_HELP_MORE, 0},
{"v", OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
{"-version", OPTION_v, 0}, /* handle as verbose, also prints version*/
{"I", OPTION_I, TCC_OPTION_HAS_ARG},
{"D", OPTION_D, TCC_OPTION_HAS_ARG},
{"U", OPTION_U, TCC_OPTION_HAS_ARG},
@ -91,23 +116,662 @@ static const TCCOption options[] = {
{"s", 0, 0},
{"traditional", 0, 0},
{"shared", 0, 0},
{"soname", 0, 0},
{"static", 0, 0},
{NULL, 0, 0}
};
static TCCOption *options_ext = NULL;
static const Flag options_W[] = {
{offsetof(TCCState, warn_all), F_WD_ALL, "all"},
{offsetof(TCCState, warn_error), 0, "error"},
{offsetof(TCCState, warn_write_strings), 0, "write-strings"},
{offsetof(TCCState, warn_unsupported), 0, "unsupported"},
{offsetof(TCCState, warn_implicit_function_declaration), F_WD_ALL, "implicit-function-declaration"},
{offsetof(TCCState, warn_discarded_qualifiers), F_WD_ALL, "discarded-qualifiers"},
{0, 0, NULL}
};
static const Flag options_f[] = {
{offsetof(TCCState, char_is_unsigned), 0, "unsigned-char"},
{offsetof(TCCState, char_is_unsigned), F_FD_INVERT, "signed-char"},
{offsetof(TCCState, nocommon), F_FD_INVERT, "common"},
{offsetof(TCCState, leading_underscore), 0, "leading-underscore"},
{offsetof(TCCState, ms_extensions), 0, "ms-extensions"},
{offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers"},
{offsetof(TCCState, reverse_funcargs), 0, "reverse-funcargs"},
{offsetof(TCCState, gnu89_inline), 0, "gnu89-inline"},
{offsetof(TCCState, unwind_tables), 0, "asynchronous-unwind-tables"},
{0, 0, NULL}
};
static const Flag options_m[] = {
{offsetof(TCCState, ms_bitfields), 0, "ms-bitfields"},
{0, 0, NULL}
};
static const char dumpmachine_str[] = "i386-pc-stupidos";
void
tcc_add_options(TCCOption *opt)
static int
strstart(const char *val, const char **str)
{
options_ext = opt;
const char *p;
const char *q;
p = *str;
q = val;
while (*q)
{
if (*p != *q) return (0);
p++;
q++;
}
*str = p;
return (1);
}
static int
set_flag(TCCState *s, const Flag *flags, const char *name)
{
int value, mask, ret;
const Flag *p;
const char *r;
unsigned char *f;
r = name;
value = !strstart("no-", &r);
mask = 0;
/* when called with options_W, look for -W[no-]error=<option> */
if ((flags->flags & F_WD_ALL) && strstart("error=", &r))
{
value = value ? WARN_ON|WARN_ERR : WARN_NOE;
mask = WARN_ON;
}
for (ret = -1, p = flags; p->name; ++p)
{
if ((ret && strcmp(r, p->name))
|| ((p->flags & F_WD_ALL) == 0))
{
continue;
}
f = (unsigned char *)s + p->offset;
*f = (*f & mask) | (value ^ !!(p->flags & F_FD_INVERT));
if (ret)
{
ret = 0;
if (strcmp(r, "all"))
{
break;
}
}
}
return ret;
}
/* Like strstart, but automatically takes into account that ld options can
*
* - start with double or single dash (e.g. '--soname' or '-soname')
* - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so'
* or '-Wl,-soname=x.so')
*
* you provide `val` always in 'option[=]' form (no leading -)
*/
static int
link_option(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
int ret;
/* there should be 1 or 2 dashes */
if (*str++ != '-')
return 0;
if (*str == '-')
str++;
/* then str & val should match (potentially up to '=') */
p = str;
q = val;
ret = 1;
if (q[0] == '?')
{
++q;
if (strstart("no-", &p))
ret = -1;
}
while (*q != '\0' && *q != '=')
{
if (*p != *q)
return (0);
p++;
q++;
}
/* '=' near eos means ',' or '=' is ok */
if (*q == '=')
{
if (*p == 0)
*ptr = p;
if (*p != ',' && *p != '=')
return 0;
p++;
} else if (*p) {
return (0);
}
*ptr = p;
return (ret);
}
static int
link_arg(const char *opt, const char *str)
{
int l = strlen(opt);
return 0 == strncmp(opt, str, l) && (str[l] == '\0' || str[l] == ',');
}
static const char *
skip_linker_arg(const char **str)
{
const char *s1 = *str;
const char *s2 = strchr(s1, ',');
*str = s2 ? s2++ : (s2 = s1 + strlen(s1));
return s2;
}
static void
copy_linker_arg(char **pp, const char *s, int sep)
{
const char *q = s;
char *p = *pp;
int l = 0;
if (p && sep)
p[l = strlen(p)] = sep, ++l;
skip_linker_arg(&q);
pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s);
}
/* set linker options */
static int
set_linker(TCCState *s, const char *option)
{
const char *p;
char *end;
int ignoring;
int ret;
TCCState *s1 = s;
while (*option)
{
p = NULL;
end = NULL;
ignoring = 0;
if (link_option(option, "Bsymbolic", &p))
{
s->symbolic = 1;
} else if (link_option(option, "nostdlib", &p)) {
s->nostdlib = 1;
} else if (link_option(option, "e=", &p)
|| link_option(option, "entry=", &p)) {
copy_linker_arg(&s->elf_entryname, p, 0);
} else if (link_option(option, "fini=", &p)) {
copy_linker_arg(&s->fini_symbol, p, 0);
ignoring = 1;
} else if (link_option(option, "image-base=", &p)
|| link_option(option, "Ttext=", &p)) {
s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1;
} else if (link_option(option, "init=", &p)) {
copy_linker_arg(&s->init_symbol, p, 0);
ignoring = 1;
} else if (link_option(option, "Map=", &p)) {
copy_linker_arg(&s->mapfile, p, 0);
ignoring = 1;
} else if (link_option(option, "oformat=", &p)) {
if (strstart("elf32-", &p)) {
s->output_format = TCC_OUTPUT_FORMAT_ELF;
} else if (link_arg("binary", p)) {
s->output_format = TCC_OUTPUT_FORMAT_BINARY;
#ifdef TCC_TARGET_COFF
} else if (link_arg("coff", p)) {
s->output_format = TCC_OUTPUT_FORMAT_COFF;
#endif
} else
goto err;
} else if (link_option(option, "as-needed", &p)) {
ignoring = 1;
} else if (link_option(option, "O", &p)) {
ignoring = 1;
} else if (link_option(option, "rpath=", &p)) {
copy_linker_arg(&s->rpath, p, ':');
} else if (link_option(option, "enable-new-dtags", &p)) {
s->enable_new_dtags = 1;
} else if (link_option(option, "section-alignment=", &p)) {
s->section_align = strtoul(p, &end, 16);
} else if (ret = link_option(option, "?whole-archive", &p), ret) {
if (ret > 0)
s->filetype |= AFF_WHOLE_ARCHIVE;
else
s->filetype &= ~AFF_WHOLE_ARCHIVE;
} else if (link_option(option, "z=", &p)) {
ignoring = 1;
} else if (p) {
return 0;
} else {
err:
return tcc_error_noabort("unsupported linker option '%s'", option);
}
if (ignoring)
tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", option);
option = skip_linker_arg(&p);
}
return 1;
}
static int
args_parser_make_argv(const char *r, int *argc, char ***argv)
{
int ret = 0;
int q;
int c;
CString str;
for(;;)
{
while (c = (unsigned char)*r, c && c <= ' ')
{
++r;
}
if (c == 0)
{
break;
}
q = 0;
cstr_new(&str);
while (c = (unsigned char)*r, c)
{
++r;
if (c == '\\' && (*r == '"' || *r == '\\'))
{
c = *r++;
}
else if (c == '"')
{
q = !q;
continue;
}
else if (q == 0 && c <= ' ')
{
break;
}
cstr_ccat(&str, c);
}
cstr_ccat(&str, 0);
dynarray_add(argv, argc, tcc_strdup(str.data));
cstr_free(&str);
++ret;
}
return (ret);
}
static int
args_parser_listfile(TCCState *s, const char *fname, int optind, int *pargc,
char ***pargv)
{
TCCState *s1;
int fd, i;
char *p;
int argc = 0;
char **argv = NULL;
s1 = s;
fd = open(fname, O_RDONLY | O_BINARY);
if (fd < 0)
{
return (tcc_error_noabort("listfile '%s' not found", fname));
}
p = tcc_load_text(fd);
for (i = 0; i < *pargc; ++i)
{
if (i == optind)
{
args_parser_make_argv(p, &argc, &argv);
}
else
{
dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i]));
}
}
tcc_free(p);
dynarray_reset(&s->argv, &s->argc);
*pargc = s->argc = argc, *pargv = s->argv = argv;
return (0);
}
static void
args_parser_add_file(TCCState *s, const char *fname, int ftype)
{
struct filespec *f;
f= tcc_malloc(sizeof *f + strlen(fname));
f->type = ftype;
strcpy(f->name, fname);
dynarray_add(&s->files, &s->nb_files, f);
}
int
tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
{
TCCState *s1 = s;
const TCCOption *popt;
const char *optarg, *r;
const char *p1;
const char *r1;
int x;
int tool = 0;
int arg_start = 0;
int noaction;
char **argv;
int argc;
noaction = optind;
argv = *pargv;
argc = *pargc;
cstr_reset(&s->linker_arg);
while (optind < argc) {
r = argv[optind];
if (r[0] == '@' && r[1] != '\0')
{
if (args_parser_listfile(s, r + 1, optind, &argc, &argv))
{
return (-1);
}
continue;
}
optind++;
if (tool)
{
if (r[0] == '-' && r[1] == 'v' && r[2] == 0)
{
s->verbose++;
}
continue;
}
reparse:
if (r[0] != '-' || r[1] == '\0')
{
args_parser_add_file(s, r, s->filetype);
continue;
}
/* find option in table */
for (popt = options; ; ++popt)
{
p1 = popt->name;
r1 = r + 1;
if (p1 == NULL)
{
return tcc_error_noabort("invalid option -- '%s'", r);
}
if (!strstart(p1, &r1))
{
continue;
}
optarg = r1;
if (popt->flags & TCC_OPTION_HAS_ARG)
{
if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP))
{
if (optind >= argc)
{
return (tcc_error_noabort("argument to '%s' is missing", r));
}
optarg = argv[optind++];
}
}
else if (*r1 != '\0')
{
continue;
}
break;
}
switch(popt->index)
{
case OPTION_HELP:
x = TCC_OPT_HELP;
goto extra_action;
case OPTION_HELP_MORE:
x = TCC_OPT_HELP_MORE;
goto extra_action;
case OPTION_I:
tcc_add_include_path(s, optarg);
break;
case OPTION_D:
tcc_define_symbol(s, optarg, NULL);
break;
case OPTION_U:
tcc_undefine_symbol(s, optarg);
break;
case OPTION_L:
tcc_add_library_path(s, optarg);
break;
case OPTION_B:
/* set tcc utilities path (mainly for tcc development) */
tcc_set_lib_path(s, optarg);
++noaction;
break;
case OPTION_l:
args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
s->nb_libraries++;
break;
case OPTION_pthread:
s->option_pthread = 1;
break;
case OPTION_bench:
s->do_bench = 1;
break;
case OPTION_c:
x = TCC_OUTPUT_OBJ;
set_output_type:
if (s->output_type)
tcc_warning("-%s: overriding compiler action already specified", popt->name);
s->output_type = x;
break;
case OPTION_d:
if (*optarg == 'D')
s->dflag = 3;
else if (*optarg == 'M')
s->dflag = 7;
else
goto unsupported_option;
break;
case OPTION_std:
if (strcmp(optarg, "=c11") == 0 || strcmp(optarg, "=gnu11") == 0)
s->cversion = 201112;
break;
case OPTION_o:
if (s->outfile)
{
tcc_warning("multiple -o option");
tcc_free(s->outfile);
}
s->outfile = tcc_strdup(optarg);
break;
case OPTION_r:
/* generate a .o merging several output files */
s->option_r = 1;
x = TCC_OUTPUT_OBJ;
goto set_output_type;
case OPTION_isystem:
tcc_add_sysinclude_path(s, optarg);
break;
case OPTION_include:
cstr_printf(&s->cmdline_incl, "#include \"%s\"\n", optarg);
break;
case OPTION_nostdinc:
s->nostdinc = 1;
break;
case OPTION_nostdlib:
s->nostdlib = 1;
break;
case OPTION_v:
do { ++s->verbose; } while (*optarg++ == 'v');
++noaction;
break;
case OPTION_f:
if (set_flag(s, options_f, optarg) < 0)
goto unsupported_option;
break;
case OPTION_m:
if (set_flag(s, options_m, optarg) < 0)
{
if (x = atoi(optarg), x != 32 && x != 64)
goto unsupported_option;
if (PTR_SIZE != x/8)
return x;
++noaction;
}
break;
case OPTION_W:
s->warn_none = 0;
if (optarg[0] && set_flag(s, options_W, optarg) < 0)
goto unsupported_option;
break;
case OPTION_w:
s->warn_none = 1;
break;
case OPTION_Wl:
if (s->linker_arg.size)
((char*)s->linker_arg.data)[s->linker_arg.size - 1] = ',';
cstr_cat(&s->linker_arg, optarg, 0);
x = set_linker(s, s->linker_arg.data);
if (x)
cstr_reset(&s->linker_arg);
if (x < 0)
return -1;
break;
case OPTION_Wp:
r = optarg;
goto reparse;
case OPTION_E:
x = TCC_OUTPUT_PREPROCESS;
goto set_output_type;
case OPTION_P:
s->Pflag = atoi(optarg) + 1;
break;
case OPTION_M:
s->include_sys_deps = 1;
// fall through
case OPTION_MM:
s->just_deps = 1;
if(!s->deps_outfile)
s->deps_outfile = tcc_strdup("-");
// fall through
case OPTION_MMD:
s->gen_deps = 1;
break;
case OPTION_MD:
s->gen_deps = 1;
s->include_sys_deps = 1;
break;
case OPTION_MF:
s->deps_outfile = tcc_strdup(optarg);
break;
case OPTION_MP:
s->gen_phony_deps = 1;
break;
case OPTION_dumpmachine:
printf("%s\n", dumpmachine_str);
exit(0);
case OPTION_dumpversion:
printf ("%s\n", PACKAGE_VERSION);
exit(0);
case OPTION_x:
x = 0;
if (*optarg == 'c')
x = AFF_TYPE_C;
else if (*optarg == 'a')
x = AFF_TYPE_ASMPP;
else if (*optarg == 'b')
x = AFF_TYPE_BIN;
else if (*optarg == 'n')
x = AFF_TYPE_NONE;
else
tcc_warning("unsupported language '%s'", optarg);
s->filetype = x | (s->filetype & ~AFF_TYPE_MASK);
break;
case OPTION_O:
s->optimize = atoi(optarg);
break;
case OPTION_print_search_dirs:
x = TCC_OPT_PRINT_DIRS;
goto extra_action;
case OPTION_ar:
x = TCC_OPT_ARCHIVE;
extra_action:
arg_start = optind - 1;
if (arg_start != noaction)
return tcc_error_noabort("cannot parse %s here", r);
tool = x;
break;
default:
unsupported_option:
tcc_warning_c(warn_unsupported)("unsupported option '%s'", r);
break;
}
}
if (s->linker_arg.size)
{
r = s->linker_arg.data;
return (tcc_error_noabort("argument to '%s' is missing", r));
}
*pargc = argc - arg_start;
*pargv = argv + arg_start;
if (tool)
return (tool);
if (optind != noaction)
return (0);
if (s->verbose == 2)
return (TCC_OPT_PRINT_DIRS);
if (s->verbose)
return (TCC_OPT_VERSION);
return (TCC_OPT_HELP);
}
int
tcc_set_options(TCCState *s, const char *str)
{
char **argv;
int argc;
int ret;
argv = NULL;
argc = 0;
args_parser_make_argv(str, &argc, &argv);
ret = tcc_parse_args(s, &argc, &argv, 0);
dynarray_reset(&argv, &argc);
if (ret < 0)
{
return (ret);
}
return (0);
}

View file

@ -1,6 +1,4 @@
#include "tcc/coff.h"
#include "tcc.h"
#include <tcc.h>
static int
read_mem(int fd, unsigned offset, void *buffer, unsigned len)

View file

@ -18,7 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tcc.h"
#include <tcc.h>
#include "utils/string.h"
/* Define this to get some debug output during relocation processing. */

View file

@ -19,7 +19,7 @@
*/
#define USING_GLOBALS
#include "tcc.h"
#include <tcc.h>
#include "utils/string.h"
#include "token.h"

View file

@ -19,7 +19,7 @@
*/
#define USING_GLOBALS
#include "tcc.h"
#include <tcc.h>
#include "utils/string.h"
#include "token.h"
#include <math.h>
@ -1343,7 +1343,7 @@ static int parse_include(TCCState *s1, int do_next, int test)
cstr_reset(&tokcstr);
file->buf_ptr = parse_pp_string(file->buf_ptr, c == '<' ? '>' : c, &tokcstr);
i = tokcstr.size;
pstrncpy(name, tokcstr.data, i >= sizeof name ? sizeof name - 1 : i);
pstrncpy(name, tokcstr.data, i >= sizeof(name) ? sizeof(name) - 1 : i);
next_nomacro();
} else {
/* computed #include : concatenate tokens until result is one of

View file

@ -19,17 +19,19 @@
*/
#include "config.h"
#include <stdlib.h>
#include <tcc.h>
#include <tcc/option.h>
#include "tcctools.h"
static const char HELP_STR[] =
static const char help_str[] =
"Tiny C Compiler "PACKAGE_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n"
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
" tcc [options...] -run infile (or --) [arguments...]\n"
"General options:\n"
" -c compile only - generate an object file\n"
" -o outfile set output filename\n"
" -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n"
@ -48,9 +50,6 @@ static const char HELP_STR[] =
" -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n"
" -r generate (relocatable) object file\n"
" -shared generate a shared library/dll\n"
" -rdynamic export all global symbols to dynamic linker\n"
" -soname set name for shared library to be used at runtime\n"
" -Wl,-opt[=val] set linker option (see tcc -hh)\n"
"Misc. options:\n"
" -std=version define __STDC_VERSION__ according to version (c11/gnu11)\n"
@ -65,7 +64,7 @@ static const char HELP_STR[] =
" create library : tcc -ar [crstvx] lib [files]\n"
;
static const char HELP_MORE_STR[] =
static const char help_more_str[] =
"Tiny C Compiler "PACKAGE_VERSION" - More Options\n"
"Special options:\n"
" -P -P1 with -E: no/alternative #line output\n"
@ -75,11 +74,10 @@ static const char HELP_MORE_STR[] =
" -Wp,-opt same as -opt\n"
" -include file include 'file' above each input file\n"
" -isystem dir add 'dir' to system include path\n"
" -static link to static libraries (not recommended)\n"
" -dumpversion print version\n"
" -print-search-dirs print search paths\n"
"Ignored options:\n"
" -arch -C --param -pedantic -pipe -s -traditional\n"
" -arch -C --param -pedantic -pipe -s -traditional -g -static -shared -soname\n"
"-W[no-]... warnings:\n"
" all turn on some (*) warnings\n"
" error[=warning] stop after warning (any or specified)\n"
@ -102,14 +100,9 @@ static const char HELP_MORE_STR[] =
"-Wl,... linker options:\n"
" -nostdlib do not link with standard crt/libs\n"
" -[no-]whole-archive load lib(s) fully/only as needed\n"
" -export-all-symbols same as -rdynamic\n"
" -export-dynamic same as -rdynamic\n"
" -image-base= -Ttext= set base address of executable\n"
" -section-alignment= set section alignment in executable\n"
" -rpath= set dynamic library search path\n"
" -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n"
" -soname= set DT_SONAME elf tag\n"
" -Bsymbolic set DT_SYMBOLIC elf tag\n"
" -oformat=[coff,binary] set executable output format\n"
" -init= -fini= -Map= -as-needed -O (ignored)\n"
"Predefined macros:\n"
@ -117,10 +110,11 @@ static const char HELP_MORE_STR[] =
"See also the manual for more details.\n"
;
static const char VERSION_STR[] =
static const char version_str[] =
"tcc version "PACKAGE_VERSION" (i386)\n";
static void print_dirs(const char *msg, char **paths, int nb_paths)
static void
print_dirs(const char *msg, char **paths, int nb_paths)
{
int i;
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
@ -128,17 +122,18 @@ static void print_dirs(const char *msg, char **paths, int nb_paths)
printf(" %s\n", paths[i]);
}
static void print_search_dirs(TCCState *s)
static void
print_search_dirs(TCCState *s)
{
printf("install: %s\n", s->tcc_lib_path);
/* print_dirs("programs", NULL, 0); */
print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
print_dirs("libraries", s->library_paths, s->nb_library_paths);
printf("libtcc1:\n %s/%s\n", s->library_paths[0], CONFIG_TCC_CROSSPREFIX TCC_LIBTCC1);
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
}
static void set_environment(TCCState *s)
static void
set_environment(TCCState *s)
{
char * path;
@ -156,7 +151,8 @@ static void set_environment(TCCState *s)
}
}
static char *default_outputfile(TCCState *s, const char *first_file)
static char
*default_outputfile(TCCState *s, const char *first_file)
{
char buf[1024];
char *ext;
@ -173,7 +169,8 @@ static char *default_outputfile(TCCState *s, const char *first_file)
return tcc_strdup(buf);
}
static unsigned getclock_ms(void)
static unsigned
getclock_ms(void)
{
#ifdef _WIN32
return GetTickCount();
@ -184,10 +181,11 @@ static unsigned getclock_ms(void)
#endif
}
int main(int argc0, char **argv0)
int
main(int argc0, char **argv0)
{
TCCState *s, *s1;
int ret, opt, n = 0, t = 0, done;
int ret, opt, n = 0, done;
unsigned start_time = 0, end_time = 0;
const char *first_file;
int argc; char **argv;
@ -196,36 +194,41 @@ int main(int argc0, char **argv0)
redo:
argc = argc0, argv = argv0;
s = s1 = tcc_new();
#ifdef CONFIG_TCC_SWITCHES /* predefined options */
tcc_set_options(s, CONFIG_TCC_SWITCHES);
#endif
opt = tcc_parse_args(s, &argc, &argv, 1);
if (opt < 0)
return 1;
return (EXIT_FAILURE);
if (n == 0) {
if (opt == OPT_HELP) {
fputs(HELP_STR, stdout);
if (n == 0)
{
if (opt == TCC_OPT_HELP)
{
fputs(help_str, stdout);
if (!s->verbose)
return 0;
return (EXIT_SUCCESS);
++opt;
}
if (opt == OPT_HELP2) {
fputs(HELP_MORE_STR, stdout);
return 0;
if (opt == TCC_OPT_HELP_MORE)
{
fputs(help_more_str, stdout);
return (EXIT_SUCCESS);
}
if (s->verbose)
printf("%s", VERSION_STR);
if (opt == OPT_AR)
printf("%s", version_str);
if (opt == TCC_OPT_ARCHIVE)
return tcc_tool_ar(s, argc, argv);
if (opt == OPT_V)
if (opt == TCC_OPT_VERSION)
return 0;
if (opt == OPT_PRINT_DIRS) {
if (opt == TCC_OPT_PRINT_DIRS) {
/* initialize search dirs */
set_environment(s);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
print_search_dirs(s);
return 0;
return (EXIT_SUCCESS);
}
if (s->nb_files == 0) {
@ -290,9 +293,7 @@ redo:
}
done = 1;
if (t)
done = 0; /* run more tests with -dt -run */
else if (ret) {
if (ret) {
if (s->nb_errors)
ret = 1;
/* else keep the original exit code from tcc_run() */

View file

@ -30,18 +30,7 @@
#include "tcc.h"
//#define ARMAG "!<arch>\n"
#define ARFMAG "`\n"
typedef struct {
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
} ArHdr;
#include <tcc/object/archive.h>
static unsigned long le2belong(unsigned long ul) {
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
@ -56,18 +45,18 @@ static int ar_usage(int ret) {
int tcc_tool_ar(TCCState *s1, int argc, char **argv)
{
static const ArHdr arhdr_init = {
static const ArchiveFileHeader arhdr_init = {
"/ ",
"0 ",
"0 ",
"0 ",
"0 ",
"0 ",
ARFMAG
ARCHIVE_FILMAG
};
ArHdr arhdr = arhdr_init;
ArHdr arhdro = arhdr_init;
ArchiveFileHeader arhdr = arhdr_init;
ArchiveFileHeader arhdro = arhdr_init;
FILE *fi, *fh = NULL, *fo = NULL;
const char *created_file = NULL; // must delete on error
@ -133,27 +122,27 @@ no_ar:
while (fread(&arhdr, 1, sizeof(arhdr), fh) == sizeof(arhdr)) {
char *p, *e;
if (memcmp(arhdr.ar_fmag, ARFMAG, 2))
if (memcmp(arhdr.fmag, ARFMAG, 2))
goto no_ar;
p = arhdr.ar_name;
for (e = p + sizeof arhdr.ar_name; e > p && e[-1] == ' ';)
p = arhdr.name;
for (e = p + sizeof arhdr.name; e > p && e[-1] == ' ';)
e--;
*e = '\0';
arhdr.ar_size[sizeof arhdr.ar_size-1] = 0;
fsize = atoi(arhdr.ar_size);
arhdr.size[sizeof arhdr.size-1] = 0;
fsize = atoi(arhdr.size);
buf = tcc_malloc(fsize + 1);
fread(buf, fsize, 1, fh);
if (strcmp(arhdr.ar_name,"/") && strcmp(arhdr.ar_name,"/SYM64/")) {
if (strcmp(arhdr.name,"/") && strcmp(arhdr.name,"/SYM64/")) {
if (e > p && e[-1] == '/')
e[-1] = '\0';
/* tv not implemented */
if (table || verbose)
printf("%s%s\n", extract ? "x - " : "", arhdr.ar_name);
printf("%s%s\n", extract ? "x - " : "", arhdr.name);
if (extract) {
if ((fo = fopen(arhdr.ar_name, "wb")) == NULL)
if ((fo = fopen(arhdr.name, "wb")) == NULL)
{
fprintf(stderr, "tcc: ar: can't create file %s\n",
arhdr.ar_name);
arhdr.name);
tcc_free(buf);
goto finish;
}
@ -189,7 +178,7 @@ finish:
funcmax = 250;
afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func
memcpy(&arhdro.ar_mode, "100644", 6);
memcpy(&arhdro.mode, "100644", 6);
// i_obj = first input object file
while (i_obj < argc)
@ -277,13 +266,13 @@ finish:
name > file && name[-1] != '/' && name[-1] != '\\';
--name);
istrlen = strlen(name);
if (istrlen >= sizeof(arhdro.ar_name))
istrlen = sizeof(arhdro.ar_name) - 1;
memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
memcpy(arhdro.ar_name, name, istrlen);
arhdro.ar_name[istrlen] = '/';
if (istrlen >= sizeof(arhdro.name))
istrlen = sizeof(arhdro.name) - 1;
memset(arhdro.name, ' ', sizeof(arhdro.name));
memcpy(arhdro.name, name, istrlen);
arhdro.name[istrlen] = '/';
sprintf(stmp, "%-10d", fsize);
memcpy(&arhdro.ar_size, stmp, 10);
memcpy(&arhdro.size, stmp, 10);
fwrite(&arhdro, sizeof(arhdro), 1, fo);
fwrite(buf, fsize, 1, fo);
tcc_free(buf);
@ -304,7 +293,7 @@ finish:
goto the_end;
}
sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)) + fpos);
memcpy(&arhdr.ar_size, stmp, 10);
memcpy(&arhdr.size, stmp, 10);
fwrite(&arhdr, sizeof(arhdr), 1, fh);
afpos[0] = le2belong(funccnt);
for (i=1; i<=funccnt; i++)