diff --git a/tcc.h b/tcc.h
index e4c38b53..7bae6aff 100644
--- a/tcc.h
+++ b/tcc.h
@@ -502,7 +502,7 @@ typedef union CValue {
     float f;
     uint64_t i;
     struct {
-        const void *data;
+        char *data;
         int size;
     } str;
     int tab[LDOUBLE_SIZE/4];
@@ -1390,6 +1390,7 @@ ST_FUNC void define_undef(Sym *s);
 ST_INLN Sym *define_find(int v);
 ST_FUNC void free_defines(Sym *b);
 ST_FUNC void parse_define(void);
+ST_FUNC void skip_to_eol(int warn);
 ST_FUNC void preprocess(int is_bof);
 ST_FUNC void next(void);
 ST_INLN void unget_tok(int last_tok);
@@ -1397,6 +1398,7 @@ ST_FUNC void preprocess_start(TCCState *s1, int filetype);
 ST_FUNC void preprocess_end(TCCState *s1);
 ST_FUNC void tccpp_new(TCCState *s);
 ST_FUNC void tccpp_delete(TCCState *s);
+ST_FUNC void tccpp_putfile(const char *filename);
 ST_FUNC int tcc_preprocess(TCCState *s1);
 ST_FUNC void skip(int c);
 ST_FUNC NORETURN void expect(const char *msg);
@@ -1822,7 +1824,7 @@ ST_FUNC void tcc_debug_start(TCCState *s1);
 ST_FUNC void tcc_debug_end(TCCState *s1);
 ST_FUNC void tcc_debug_bincl(TCCState *s1);
 ST_FUNC void tcc_debug_eincl(TCCState *s1);
-ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename);
+ST_FUNC void tcc_debug_newfile(TCCState *s1);
 
 ST_FUNC void tcc_debug_line(TCCState *s1);
 ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e);
diff --git a/tccasm.c b/tccasm.c
index ba7ffe97..d056c703 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -728,7 +728,7 @@ static void asm_parse_directive(TCCState *s1, int global)
     case TOK_ASMDIR_ascii:
     case TOK_ASMDIR_asciz:
         {
-            const uint8_t *p;
+            const char *p;
             int i, size, t;
 
             t = tok;
@@ -772,15 +772,21 @@ static void asm_parse_directive(TCCState *s1, int global)
 	break;
     case TOK_ASMDIR_file:
         {
-            char filename[512];
-
-            filename[0] = '\0';
+            const char *p;
+            parse_flags &= ~PARSE_FLAG_TOK_STR;
             next();
-            if (tok == TOK_STR)
-                pstrcat(filename, sizeof(filename), tokc.str.data);
-            else
-                pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL));
-            tcc_warning_c(warn_unsupported)("ignoring .file %s", filename);
+            if (tok == TOK_PPNUM)
+                next();
+            if (tok == TOK_PPSTR && tokc.str.data[0] == '"') {
+                tokc.str.data[tokc.str.size - 2] = 0;
+                p = tokc.str.data + 1;
+            } else if (tok >= TOK_IDENT) {
+                p = get_tok_str(tok, &tokc);
+            } else {
+                skip_to_eol(0);
+                break;
+            }
+            tccpp_putfile(p);
             next();
         }
         break;
@@ -968,6 +974,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
         next();
         if (tok == TOK_EOF)
             break;
+        tcc_debug_line(s1);
         parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
     redo:
         if (tok == '#') {
@@ -1033,9 +1040,8 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
 /* GCC inline asm support */
 
 /* assemble the string 'str' in the current C compilation unit without
-   C preprocessing. NOTE: str is modified by modifying the '\0' at the
-   end */
-static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
+   C preprocessing. */
+static void tcc_assemble_inline(TCCState *s1, const char *str, int len, int global)
 {
     const int *saved_macro_ptr = macro_ptr;
     int dotid = set_idnum('.', IS_ID);
diff --git a/tccdbg.c b/tccdbg.c
index a2c6b56f..7760f4fd 100644
--- a/tccdbg.c
+++ b/tccdbg.c
@@ -1048,11 +1048,8 @@ static BufferedFile* put_new_file(TCCState *s1)
 }
 
 /* put alternative filename */
-ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename)
+ST_FUNC void tcc_debug_newfile(TCCState *s1)
 {
-    if (0 == strcmp(file->filename, filename))
-        return;
-    pstrcpy(file->filename, sizeof(file->filename), filename);
     if (!s1->do_debug)
         return;
     if (s1->dwarf)
diff --git a/tccgen.c b/tccgen.c
index abde20c4..a1c7db47 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -8387,7 +8387,7 @@ static void gen_inline_functions(TCCState *s)
                 /* the function was used or forced (and then not internal):
                    generate its code and convert it to a normal function */
                 fn->sym = NULL;
-                tcc_debug_putfile(s, fn->filename);
+                tccpp_putfile(fn->filename);
                 begin_macro(fn->func_str, 1);
                 next();
                 cur_text_section = text_section;
diff --git a/tccpp.c b/tccpp.c
index 7f9bb627..6f2bc173 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -53,6 +53,8 @@ static int pp_debug_tok, pp_debug_symv;
 static int pp_counter;
 static void tok_print(const int *str, const char *msg, ...);
 static void next_nomacro(void);
+static void parse_number(const char *p);
+static void parse_string(const char *p, int len);
 
 static struct TinyAlloc *toksym_alloc;
 static struct TinyAlloc *tokstr_alloc;
@@ -884,7 +886,6 @@ redo_start:
     start_of_line = 1;
     in_warn_or_error = 0;
     for(;;) {
-    redo_no_start:
         c = *p;
         switch(c) {
         case ' ':
@@ -893,7 +894,7 @@ redo_start:
         case '\v':
         case '\r':
             p++;
-            goto redo_no_start;
+            continue;
         case '\n':
             file->line_num++;
             p++;
@@ -904,7 +905,7 @@ redo_start:
                 expect("#endif");
             if (c == '\\')
                 ++p;
-            goto redo_no_start;
+            continue;
         /* skip strings */
         case '\"':
         case '\'':
@@ -924,7 +925,7 @@ redo_start:
             } else if (c == '/') {
                 p = parse_line_comment(p);
             }
-            break;
+            continue;
         case '#':
             p++;
             if (start_of_line) {
@@ -1209,7 +1210,7 @@ static inline void tok_get(int *t, const int **pp, CValue *cv)
     case TOK_PPNUM:
     case TOK_PPSTR:
         cv->str.size = *p++;
-        cv->str.data = p;
+        cv->str.data = (char*)p;
         p += (cv->str.size + sizeof(int) - 1) / sizeof(int);
         break;
     case TOK_CDOUBLE:
@@ -1331,6 +1332,16 @@ static void maybe_run_test(TCCState *s)
     define_push(tok, MACRO_OBJ, NULL, NULL);
 }
 
+ST_FUNC void skip_to_eol(int warn)
+{
+    if (tok == TOK_LINEFEED)
+        return;
+    if (warn)
+        tcc_warning("extra tokens after directive");
+    file->buf_ptr = parse_line_comment(file->buf_ptr - 1);
+    tok = TOK_LINEFEED;
+}
+
 static CachedInclude *
 search_cached_include(TCCState *s1, const char *filename, int add);
 
@@ -1370,6 +1381,9 @@ static int parse_include(TCCState *s1, int do_next, int test)
         memmove(p, p + 1, i - 1), p[i - 1] = 0;
     }
 
+    if (!test)
+        skip_to_eol(1);
+
     i = do_next ? file->include_next_index : -1;
     for (;;) {
         ++i;
@@ -1658,7 +1672,7 @@ static CachedInclude *search_cached_include(TCCState *s1, const char *filename,
     return e;
 }
 
-static void pragma_parse(TCCState *s1)
+static int pragma_parse(TCCState *s1)
 {
     next_nomacro();
     if (tok == TOK_push_macro || tok == TOK_pop_macro) {
@@ -1690,7 +1704,7 @@ static void pragma_parse(TCCState *s1)
         pp_debug_tok = t, pp_debug_symv = v;
 
     } else if (tok == TOK_once) {
-        search_cached_include(s1, file->filename, 1)->once = 1;
+        search_cached_include(s1, file->true_filename, 1)->once = 1;
 
     } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
         /* tcc -E: keep pragmas below unchanged */
@@ -1698,6 +1712,7 @@ static void pragma_parse(TCCState *s1)
         unget_tok(TOK_PRAGMA);
         unget_tok('#');
         unget_tok(TOK_LINEFEED);
+        return 1;
 
     } else if (tok == TOK_pack) {
         /* This may be:
@@ -1749,7 +1764,7 @@ static void pragma_parse(TCCState *s1)
         skip(',');
         if (tok != TOK_STR)
             goto pragma_err;
-        p = tcc_strdup((char *)tokc.str.data);
+        p = tcc_strdup(tokc.str.data);
         next();
         if (tok != ')')
             goto pragma_err;
@@ -1761,13 +1776,37 @@ static void pragma_parse(TCCState *s1)
             tcc_free(p);
         }
 
-    } else
-        tcc_warning_c(warn_unsupported)("#pragma %s ignored", get_tok_str(tok, &tokc));
-    return;
-
+    } else {
+        tcc_warning_c(warn_all)("#pragma %s ignored", get_tok_str(tok, &tokc));
+        return 0;
+    }
+    next();
+    return 1;
 pragma_err:
     tcc_error("malformed #pragma directive");
-    return;
+}
+
+/* put alternative filename */
+ST_FUNC void tccpp_putfile(const char *filename)
+{
+    char buf[1024];
+    buf[0] = 0;
+    if (!IS_ABSPATH(filename)) {
+        /* prepend directory from real file */
+        pstrcpy(buf, sizeof buf, file->true_filename);
+        *tcc_basename(buf) = 0;
+    }
+    pstrcat(buf, sizeof buf, filename);
+#ifdef _WIN32
+    normalize_slashes(buf);
+#endif
+    if (0 == strcmp(file->filename, buf))
+        return;
+    //printf("new file '%s'\n", buf);
+    if (file->true_filename == file->filename)
+        file->true_filename = tcc_strdup(file->filename);
+    pstrcpy(file->filename, sizeof file->filename, buf);
+    tcc_debug_newfile(tcc_state);
 }
 
 /* is_bof is true if first non space token at beginning of file */
@@ -1803,6 +1842,7 @@ ST_FUNC void preprocess(int is_bof)
         /* undefine symbol by putting an invalid name */
         if (s)
             define_undef(s);
+        next_nomacro();
         break;
     case TOK_INCLUDE:
     case TOK_INCLUDE_NEXT:
@@ -1832,12 +1872,14 @@ ST_FUNC void preprocess(int is_bof)
             || tok == TOK___HAS_INCLUDE
             || tok == TOK___HAS_INCLUDE_NEXT)
             c ^= 1;
+        next_nomacro();
     do_if:
         if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE)
             tcc_error("memory full (ifdef)");
         *s1->ifdef_stack_ptr++ = c;
         goto test_skip;
     case TOK_ELSE:
+        next_nomacro();
         if (s1->ifdef_stack_ptr == s1->ifdef_stack)
             tcc_error("#else without matching #if");
         if (s1->ifdef_stack_ptr[-1] & 2)
@@ -1852,6 +1894,7 @@ ST_FUNC void preprocess(int is_bof)
             tcc_error("#elif after #else");
         /* last #if/#elif expression was true: we skip */
         if (c == 1) {
+            skip_to_eol(0);
             c = 0;
         } else {
             c = expr_preprocess(s1);
@@ -1862,12 +1905,14 @@ ST_FUNC void preprocess(int is_bof)
             file->ifndef_macro = 0;
     test_skip:
         if (!(c & 1)) {
+            skip_to_eol(1);
             preprocess_skip();
             is_bof = 0;
             goto redo;
         }
         break;
     case TOK_ENDIF:
+        next_nomacro();
         if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr)
             tcc_error("#endif without matching #if");
         s1->ifdef_stack_ptr--;
@@ -1879,41 +1924,27 @@ ST_FUNC void preprocess(int is_bof)
             /* need to set to zero to avoid false matches if another
                #ifndef at middle of file */
             file->ifndef_macro = 0;
-            while (tok != TOK_LINEFEED)
-                next_nomacro();
             tok_flags |= TOK_FLAG_ENDIF;
-            goto the_end;
         }
         break;
-    case TOK_PPNUM:
-        n = strtoul((char*)tokc.str.data, &q, 10);
-        goto _line_num;
     case TOK_LINE:
-        next();
-        if (tok != TOK_CINT)
+        next_nomacro();
+        if (tok != TOK_PPNUM)
     _line_err:
             tcc_error("wrong #line format");
+    case TOK_PPNUM:
+        parse_number(tokc.str.data);
         n = tokc.i;
-    _line_num:
-        next();
+        next_nomacro();
         if (tok != TOK_LINEFEED) {
-            if (tok == TOK_STR) {
-                if (file->true_filename == file->filename)
-                    file->true_filename = tcc_strdup(file->filename);
-                q = (char *)tokc.str.data;
-                buf[0] = 0;
-                if (!IS_ABSPATH(q)) {
-                    /* prepend directory from real file */
-                    pstrcpy(buf, sizeof buf, file->true_filename);
-                    *tcc_basename(buf) = 0;
-                }
-                pstrcat(buf, sizeof buf, q);
-                tcc_debug_putfile(s1, buf);
+            if (tok == TOK_PPSTR && tokc.str.data[0] == '"') {
+                tokc.str.data[tokc.str.size - 2] = 0;
+                tccpp_putfile(tokc.str.data + 1);
             } else if (parse_flags & PARSE_FLAG_ASM_FILE)
-                break;
+                goto ignore;
             else
                 goto _line_err;
-            --n;
+            next_nomacro();
         }
         if (file->fd > 0)
             total_lines += file->line_num - n;
@@ -1922,6 +1953,7 @@ ST_FUNC void preprocess(int is_bof)
 
     case TOK_ERROR:
     case TOK_WARNING:
+    {
         q = buf;
         c = skip_spaces();
         while (c != '\n' && c != CH_EOF) {
@@ -1934,9 +1966,12 @@ ST_FUNC void preprocess(int is_bof)
             tcc_error("#error %s", buf);
         else
             tcc_warning("#warning %s", buf);
+        next_nomacro();
         break;
+    }
     case TOK_PRAGMA:
-        pragma_parse(s1);
+        if (!pragma_parse(s1))
+            goto ignore;
         break;
     case TOK_LINEFEED:
         goto the_end;
@@ -1945,16 +1980,14 @@ ST_FUNC void preprocess(int is_bof)
         if (saved_parse_flags & PARSE_FLAG_ASM_FILE)
             goto ignore;
         if (tok == '!' && is_bof)
-            /* '!' is ignored at beginning to allow C scripts. */
+            /* '#!' is ignored at beginning to allow C scripts. */
             goto ignore;
         tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
     ignore:
-        file->buf_ptr = parse_line_comment(file->buf_ptr - 1);
-        break;
+        skip_to_eol(0);
+        goto the_end;
     }
-    /* ignore other preprocess commands or #! for C scripts */
-    while (tok != TOK_LINEFEED)
-        next_nomacro();
+    skip_to_eol(1);
  the_end:
     parse_flags = saved_parse_flags;
 }
@@ -2006,7 +2039,7 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long
                         c = c - 'A' + 10;
                     else if (isnum(c))
                         c = c - '0';
-                    else if (i > 0)
+                    else if (i >= 0)
                         expect("more hex digits in universal-character-name");
                     else
                         goto add_hex_or_ucn;
@@ -2564,7 +2597,7 @@ static void next_nomacro(void)
 #ifdef INC_DEBUG
                     printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL));
 #endif
-                    search_cached_include(s1, file->filename, 1)
+                    search_cached_include(s1, file->true_filename, 1)
                         ->ifndef_macro = file->ifndef_macro_saved;
                     tok_flags &= ~TOK_FLAG_ENDIF;
                 }
@@ -3481,10 +3514,10 @@ convert:
     /* convert preprocessor tokens into C tokens */
     if (t == TOK_PPNUM) {
         if  (parse_flags & PARSE_FLAG_TOK_NUM)
-            parse_number((char *)tokc.str.data);
+            parse_number(tokc.str.data);
     } else if (t == TOK_PPSTR) {
         if (parse_flags & PARSE_FLAG_TOK_STR)
-            parse_string((char *)tokc.str.data, tokc.str.size - 1);
+            parse_string(tokc.str.data, tokc.str.size - 1);
     }
 }