diff --git a/libtcc.c b/libtcc.c
index ee149aa7..cb0d6807 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -2074,43 +2074,51 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype
     dynarray_add((void ***)&s->files, &s->nb_files, f);
 }
 
-ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
+/* read list file */
+static void args_parser_listfile(TCCState *s, const char *filename)
+{
+    int fd;
+    size_t len;
+    char *p;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        tcc_error("file '%s' not found", filename);
+
+    len = lseek(fd, 0, SEEK_END);
+    p = tcc_malloc(len + 1), p[len] = 0;
+    lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd);
+    tcc_set_options(s, p);
+    tcc_free(p);
+}
+
+PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
 {
     const TCCOption *popt;
     const char *optarg, *r;
     int optind = 0;
-    ParseArgsState *pas = s->parse_args_state;
+    int run = 0;
+    int filetype = 0;
+    int x;
+    char buf[1024];
+
+    ++s->args_ref;
 
     while (optind < argc) {
 
         r = argv[optind++];
-        if (r[0] != '-' || r[1] == '\0') {
-            /* handle list files */
-            if (r[0] == '@' && r[1]) {
-                char buf[sizeof file->filename], *p;
-                char **argv = NULL;
-                int argc = 0;
-                FILE *fp;
 
-                fp = fopen(r + 1, "rb");
-                if (fp == NULL)
-                    tcc_error("list file '%s' not found", r + 1);
-                while (fgets(buf, sizeof buf, fp)) {
-                    p = trimfront(trimback(buf, strchr(buf, 0)));
-                    if (0 == *p || ';' == *p)
-                        continue;
-                    dynarray_add((void ***)&argv, &argc, tcc_strdup(p));
-                }
-                fclose(fp);
-                tcc_parse_args1(s, argc, argv);
-                dynarray_reset(&argv, &argc);
-            } else {
-                args_parser_add_file(s, r, pas->filetype);
-                if (pas->run) {
-                    optind--;
-                    /* argv[0] will be this file */
-                    break;
-                }
+        if (r[0] == '@' && r[1] != '\0') {
+            args_parser_listfile(s, r + 1);
+	    continue;
+        }
+
+        if (r[0] != '-' || r[1] == '\0') {
+            args_parser_add_file(s, r, filetype);
+            if (run) {
+                optind--;
+                /* argv[0] will be this file */
+                break;
             }
             continue;
         }
@@ -2160,7 +2168,7 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
             break;
         case TCC_OPTION_pthread:
             parse_option_D(s, "_REENTRANT");
-            pas->pthread = 1;
+            s->args_pthread = 1;
             break;
         case TCC_OPTION_bench:
             s->do_bench = 1;
@@ -2180,9 +2188,11 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
             s->do_debug = 1;
             break;
         case TCC_OPTION_c:
+            x = TCC_OUTPUT_OBJ;
+        set_output_type:
             if (s->output_type)
-                tcc_warning("-c: some compiler action already specified (%d)", s->output_type);
-            s->output_type = TCC_OUTPUT_OBJ;
+                tcc_warning("-%s: overriding compiler action already specified", popt->name);
+            s->output_type = x;
             break;
         case TCC_OPTION_d:
             if (*optarg == 'D')
@@ -2214,10 +2224,8 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
     	       allow to use a tcc as a reference compiler for "make test" */
             break;
         case TCC_OPTION_shared:
-    	    if (s->output_type)
-                tcc_warning("-shared: some compiler action already specified (%d)", s->output_type);
-            s->output_type = TCC_OUTPUT_DLL;
-            break;
+            x = TCC_OUTPUT_DLL;
+            goto set_output_type;
         case TCC_OPTION_soname:
             s->soname = tcc_strdup(optarg);
             break;
@@ -2233,34 +2241,15 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
             break;
         case TCC_OPTION_r:
             /* generate a .o merging several output files */
-    	    if (s->output_type)
-                tcc_warning("-r: some compiler action already specified (%d)", s->output_type);
             s->option_r = 1;
-            s->output_type = TCC_OUTPUT_OBJ;
-            break;
+            x = TCC_OUTPUT_OBJ;
+            goto set_output_type;
         case TCC_OPTION_isystem:
             tcc_add_sysinclude_path(s, optarg);
             break;
         case TCC_OPTION_iwithprefix:
-            if (1) {
-                char buf[1024];
-                int buf_size = sizeof(buf)-1;
-                char *p = &buf[0];
-
-                char *sysroot = "{B}/";
-                int len = strlen(sysroot);
-                if (len > buf_size)
-                    len = buf_size;
-                strncpy(p, sysroot, len);
-                p += len;
-                buf_size -= len;
-
-                len = strlen(optarg);
-                if (len > buf_size)
-                    len = buf_size;
-                strncpy(p, optarg, len+1);
-                tcc_add_sysinclude_path(s, buf);
-            }
+            snprintf(buf, sizeof buf, "{B}/%s", optarg);
+            tcc_add_sysinclude_path(s, buf);
             break;
         case TCC_OPTION_nostdinc:
             s->nostdinc = 1;
@@ -2275,12 +2264,10 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
 #ifndef TCC_IS_NATIVE
             tcc_error("-run is not available in a cross compiler");
 #endif
-    	    if (s->output_type)
-                tcc_warning("-run: some compiler action already specified (%d)", s->output_type);
-            s->output_type = TCC_OUTPUT_MEMORY;
             tcc_set_options(s, optarg);
-            pas->run = 1;
-            break;
+            run = 1;
+            x = TCC_OUTPUT_MEMORY;
+            goto set_output_type;
         case TCC_OPTION_v:
             do ++s->verbose; while (*optarg++ == 'v');
             break;
@@ -2299,15 +2286,13 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
             s->rdynamic = 1;
             break;
         case TCC_OPTION_Wl:
-            if (pas->linker_arg.size)
-                --pas->linker_arg.size, cstr_ccat(&pas->linker_arg, ',');
-            cstr_cat(&pas->linker_arg, optarg, 0);
+            if (s->linker_arg.size)
+                --s->linker_arg.size, cstr_ccat(&s->linker_arg, ',');
+            cstr_cat(&s->linker_arg, optarg, 0);
             break;
         case TCC_OPTION_E:
-    	    if (s->output_type)
-                tcc_warning("-E: some compiler action already specified (%d)", s->output_type);
-            s->output_type = TCC_OUTPUT_PREPROCESS;
-            break;
+            x = TCC_OUTPUT_PREPROCESS;
+            goto set_output_type;
         case TCC_OPTION_P:
             s->Pflag = atoi(optarg) + 1;
             break;
@@ -2327,25 +2312,20 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
             break;
         case TCC_OPTION_x:
             if (*optarg == 'c')
-                pas->filetype = TCC_FILETYPE_C;
+                filetype = TCC_FILETYPE_C;
             else
             if (*optarg == 'a')
-                pas->filetype = TCC_FILETYPE_ASM_PP;
+                filetype = TCC_FILETYPE_ASM_PP;
             else
             if (*optarg == 'n')
-                pas->filetype = 0;
+                filetype = 0;
             else
                 tcc_warning("unsupported language '%s'", optarg);
             break;
         case TCC_OPTION_O:
-            if (1) {
-                int opt = atoi(optarg);
-                char *sym = "__OPTIMIZE__";
-                if (opt)
-                    tcc_define_symbol(s, sym, 0);
-                else
-                    tcc_undefine_symbol(s, sym);
-            }
+            x = atoi(optarg);
+            if (x > 0)
+                tcc_define_symbol(s, "__OPTIMIZE__", NULL);
             break;
         case TCC_OPTION_pedantic:
         case TCC_OPTION_pipe:
@@ -2358,62 +2338,55 @@ unsupported_option:
             break;
         }
     }
+
+    if (1 == s->args_ref) {
+        /* top instance */
+	if (s->output_type != TCC_OUTPUT_OBJ) {
+	    tcc_set_linker(s, (const char *)s->linker_arg.data);
+	    if (s->args_pthread) {
+                args_parser_add_file(s, optarg, 'l');
+                s->nb_libraries++;
+            }
+        }
+        cstr_free(&s->linker_arg);
+        s->args_pthread = 0;
+    }
+    --s->args_ref;
+
     return optind;
 }
 
-PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
+LIBTCCAPI int tcc_set_options(TCCState *s, const char *r)
 {
-    ParseArgsState *pas;
-    int ret, is_allocated = 0;
-
-    if (!s->parse_args_state) {
-        s->parse_args_state = tcc_mallocz(sizeof(ParseArgsState));
-        cstr_new(&s->parse_args_state->linker_arg);
-        is_allocated = 1;
-    }
-    pas = s->parse_args_state;
-
-    ret = tcc_parse_args1(s, argc, argv);
-
-    if (s->output_type == 0)
-        s->output_type = TCC_OUTPUT_EXE;
-
-    if (pas->pthread && s->output_type != TCC_OUTPUT_OBJ) {
-      args_parser_add_file(s, "-lpthread", TCC_FILETYPE_BINARY);
-      s->nb_libraries++;
-    }
-
-    if (s->output_type == TCC_OUTPUT_EXE || s->output_type == TCC_OUTPUT_DLL)
-        tcc_set_linker(s, (const char *)pas->linker_arg.data);
-
-    if (is_allocated) {
-        cstr_free(&pas->linker_arg);
-        tcc_free(pas);
-        s->parse_args_state = NULL;
-    }
-    return ret;
-}
-
-LIBTCCAPI int tcc_set_options(TCCState *s, const char *str)
-{
-    const char *s1;
-    char **argv, *arg;
-    int argc, len;
-    int ret;
+    char **argv;
+    int argc;
+    int ret, q, c;
+    CString str;
 
     argc = 0, argv = NULL;
     for(;;) {
-        while (is_space(*str))
-            str++;
-        if (*str == '\0')
+        while (c = (unsigned char)*r, c && c <= ' ')
+	    ++r;
+        if (c == 0)
             break;
-        s1 = str;
-        while (*str != '\0' && !is_space(*str))
-            str++;
-        len = str - s1;
-        arg = tcc_malloc(len + 1);
-        pstrncpy(arg, s1, len);
-        dynarray_add((void ***)&argv, &argc, arg);
+        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((void ***)&argv, &argc, tcc_strdup(str.data));
+        cstr_free(&str);
     }
     ret = tcc_parse_args(s, argc, argv);
     dynarray_reset(&argv, &argc);
diff --git a/tcc.c b/tcc.c
index 0132a2e2..730e1e4c 100644
--- a/tcc.c
+++ b/tcc.c
@@ -92,7 +92,7 @@ static void help(void)
            "  -bench      show compilation statistics\n"
            "  -xc -xa     specify type of the next infile\n"
            "  -           use stdin pipe as infile\n"
-           "  @listfile   read line separated arguments from 'listfile'\n"
+           "  @listfile   read arguments from listfile\n"
            "Preprocessor options:\n"
            "  -Idir       add include path 'dir'\n"
            "  -Dsym[=val] define 'sym' with value 'val'\n"
@@ -256,9 +256,6 @@ int main(int argc, char **argv)
 
     optind = tcc_parse_args(s, argc - 1, argv + 1);
 
-    if (s->do_bench)
-        start_time = getclock_us();
-
     tcc_set_environment(s);
 
     if (optind == 0) {
@@ -272,17 +269,18 @@ int main(int argc, char **argv)
     if (s->verbose)
         display_info(s, 0);
 
-    if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) {
-        tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
-        display_info(s, 1);
-        return 0;
-    }
-
-    if (s->verbose && optind == 1)
-        return 0;
-
-    if (s->nb_files == 0)
+    if (s->nb_files == 0) {
+        if (optind == 1) {
+            if (s->print_search_dirs || s->verbose == 2) {
+                tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
+                display_info(s, 1);
+                return 1;
+            }
+            if (s->verbose)
+                return 1;
+        }
         tcc_error("no input files\n");
+    }
 
     /* check -c consistency : only single file handled. XXX: checks file type */
     if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
@@ -293,6 +291,8 @@ int main(int argc, char **argv)
             tcc_error("cannot specify multiple files with -c");
     }
 
+    if (s->output_type == 0)
+        s->output_type = TCC_OUTPUT_EXE;
     tcc_set_output_type(s, s->output_type);
 
     if (s->output_type == TCC_OUTPUT_PREPROCESS) {
@@ -305,6 +305,9 @@ int main(int argc, char **argv)
 	}
     }
 
+    if (s->do_bench)
+        start_time = getclock_us();
+
     /* compile or add each files or library */
     for(i = ret = 0; i < s->nb_files && ret == 0; i++) {
         struct filespec *f = s->files[i];
@@ -322,6 +325,8 @@ int main(int argc, char **argv)
     }
 
     if (0 == ret) {
+        if (s->do_bench)
+            tcc_print_stats(s, getclock_us() - start_time);
         if (s->output_type == TCC_OUTPUT_MEMORY) {
 #ifdef TCC_IS_NATIVE
             ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
@@ -335,9 +340,6 @@ int main(int argc, char **argv)
         }
     }
 
-    if (s->do_bench)
-        tcc_print_stats(s, getclock_us() - start_time);
-
     tcc_delete(s);
     return ret;
 }
diff --git a/tcc.h b/tcc.h
index 42088e14..95678480 100644
--- a/tcc.h
+++ b/tcc.h
@@ -638,14 +638,6 @@ struct sym_attr {
 #endif
 };
 
-typedef struct ParseArgsState
-{
-    int run;
-    int pthread;
-    int filetype;
-    CString linker_arg; /* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */
-} ParseArgsState;
-
 #if !defined(MEM_DEBUG)
 #define tal_free(al, p) tal_free_impl(al, p)
 #define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size)
@@ -682,6 +674,7 @@ typedef struct tal_header_t {
 #endif
 } tal_header_t;
 
+
 struct TCCState {
 
     int verbose; /* if true, display some information during compilation */
@@ -860,7 +853,10 @@ struct TCCState {
     int do_bench; /* option -bench */
     int gen_deps; /* option -MD  */
     char *deps_outfile; /* option -MF */
-    ParseArgsState *parse_args_state;
+
+    int args_pthread; /* -pthread option */
+    CString linker_arg; /* collect -Wl options for input such as "-Wl,-rpath -Wl,<path>" */
+    int args_ref; /* tcc_parse_args recursive counter */
 };
 
 struct filespec {
@@ -1312,8 +1308,6 @@ ST_FUNC void preprocess_delete(void);
 ST_FUNC int tcc_preprocess(TCCState *s1);
 ST_FUNC void skip(int c);
 ST_FUNC NORETURN void expect(const char *msg);
-ST_FUNC char *trimfront(char *p);
-ST_FUNC char *trimback(char *a, char *e);
 
 /* ------------ tccgen.c ------------ */
 
diff --git a/tccpe.c b/tccpe.c
index 4069e514..83acc2f8 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1565,6 +1565,23 @@ quit:
     return ret;
 }
 
+/* ------------------------------------------------------------- */
+
+static char *trimfront(char *p)
+{
+    while (*p && (unsigned char)*p <= ' ')
+	++p;
+    return p;
+}
+
+static char *trimback(char *a, char *e)
+{
+    while (e > a && (unsigned char)e[-1] <= ' ')
+	--e;
+    *e = 0;;
+    return a;
+}
+
 /* ------------------------------------------------------------- */
 static int pe_load_def(TCCState *s1, int fd)
 {
diff --git a/tccpp.c b/tccpp.c
index c40a14cb..11d8dab0 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -133,21 +133,6 @@ ST_FUNC void end_macro(void)
     }
 }
 
-ST_FUNC char *trimfront(char *p)
-{
-    while (*p && (unsigned char)*p <= ' ')
-	++p;
-    return p;
-}
-
-ST_FUNC char *trimback(char *a, char *e)
-{
-    while (e > a && (unsigned char)e[-1] <= ' ')
-	--e;
-    *e = 0;;
-    return a;
-}
-
 /* ------------------------------------------------------------------------- */
 /* Custom allocator for tiny objects */