Move arguments parsing to option.c
This commit is contained in:
parent
6318a909ff
commit
db4e043cd9
11 changed files with 747 additions and 813 deletions
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
713
libtcc/libtcc.c
713
libtcc/libtcc.c
|
@ -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)
|
||||
|
|
674
libtcc/option.c
674
libtcc/option.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
#include <tcc.h>
|
||||
#include "utils/string.h"
|
||||
#include "token.h"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
79
tcc/tcc.c
79
tcc/tcc.c
|
@ -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() */
|
||||
|
|
|
@ -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++)
|
||||
|
|
Loading…
Reference in a new issue