diff --git a/tcc.h b/tcc.h index 78b0174..7c210fd 100644 --- a/tcc.h +++ b/tcc.h @@ -38,11 +38,11 @@ #include #include #include -#include #ifndef _WIN32 # include # include +#include # ifndef CONFIG_TCC_STATIC # include # endif @@ -717,9 +717,8 @@ typedef struct InlineFunc { /* include file cache, used to find files faster and also to eliminate inclusion if the include file is protected by #ifndef ... #endif */ typedef struct CachedInclude { +#ifndef _WIN32 struct stat st; -#ifdef _WIN32 - unsigned long long hash; #endif int ifndef_macro; int once; diff --git a/tccpp.c b/tccpp.c index b95c63d..42ae463 100644 --- a/tccpp.c +++ b/tccpp.c @@ -51,6 +51,9 @@ static int pp_debug_tok, pp_debug_symv; static int pp_once; static int pp_expr; static int pp_counter; +#ifdef _WIN32 +static char pp_wd[1024]; +#endif static void tok_print(const char *msg, const int *str); static struct TinyAlloc *toksym_alloc; @@ -1607,66 +1610,76 @@ bad_twosharp: define_push(v, t, tok_str_dup(&tokstr_buf), first); } -#ifdef _WIN32 -static unsigned long long calc_file_hash(const char *filename) -{ - unsigned long long hash = 14695981039346656037ull; // FNV_offset_basis; - int fd = open (filename, O_RDONLY | O_BINARY); - - if (fd < 0) - return 0; - for (;;) { - unsigned char temp[IO_BUF_SIZE]; - int i, n = read(fd, temp, sizeof(temp)); - - if (n <= 0) - break; - for (i = 0; i < n; i++) - hash = hash * 1099511628211ull ^ temp[i]; // FNV_prime - } - close(fd); - return hash ? hash : 1ull; -} -#endif - static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add) { unsigned int h = 0; CachedInclude *e; int i; - struct stat st; -#ifdef _WIN32 - unsigned long long hash = 0; -#endif /* This is needed for #pragmae once - * We cannot use stat on windows because st_ino is not set correctly - * so we calculate a hash of file contents. - * This also works for hard/soft links as in gcc/clang. - */ - memset (&st, 0, sizeof(st)); - if (stat (filename, &st)) - goto skip; - h = st.st_size & (CACHED_INCLUDES_HASH_SIZE - 1); + * We cannot use stat on Windows because st_ino is not set correctly + * and it takes a lot of time. + * So we calculate the full pathname of the file. + * This also means on Windows links do not work. + * On linux we can use stat so hard/soft links work like in gcc/clang. + */ #ifdef _WIN32 - /* Only calculate file hash if file size same. */ - i = s1->cached_includes_hash[h]; - for(;;) { - if (i == 0) - break; - e = s1->cached_includes[i - 1]; - if (e->st.st_size == st.st_size) { - if (0 == PATHCMP(e->filename, filename)) { - hash = e->hash; - break; +#define NAME fullname + char fullname[sizeof(pp_wd)]; + unsigned char *s, *t, *f; + + if (IS_DIRSEP (filename[0])) + pstrcpy (fullname, sizeof(fullname), filename); + else { + pstrcpy (fullname, sizeof(fullname), pp_wd); + pstrcat (fullname, sizeof(fullname), "/"); + pstrcat (fullname, sizeof(fullname), filename); + } + normalize_slashes(fullname); + /* Skip possible drive letter */ + f = (unsigned char *) fullname; + while (*f != '/') + f++; + s = f; + t = f; + while (*s) { + if (*s == '/') { + *t++ = *s++; + while (*s == '/') { + s++; } - if (e->hash == 0) - e->hash = calc_file_hash(e->filename); - if (hash == 0) - hash = calc_file_hash(filename); } - i = e->hash_next; + if (s[0] == '.' && s[1] == '/') + s += 2; + else if (s[0] == '.' && s[1] == '.' && s[2] == '/') { + s += 3; + if (t > (f + 1) && t[-1] == '/') + t--; + while (t > (f + 1) && t[-1] != '/') + t--; + } + else + while (*s && *s != '/') { + *t++ = *s++; + } + } + *t = '\0'; + + h = TOK_HASH_INIT; + s = (unsigned char *) fullname; + while (*s) { + h = TOK_HASH_FUNC(h, toup(*s)); + s++; } + h &= (CACHED_INCLUDES_HASH_SIZE - 1); +#else +#define NAME filename + struct stat st; + + memset (&st, 0, sizeof(st)); + if (stat (filename, &st)) + goto skip; + h = st.st_size & (CACHED_INCLUDES_HASH_SIZE - 1); #endif i = s1->cached_includes_hash[h]; @@ -1675,7 +1688,7 @@ static CachedInclude *search_cached_include(TCCState *s1, const char *filename, break; e = s1->cached_includes[i - 1]; #ifdef _WIN32 - if (e->st.st_size == st.st_size && e->hash == hash) + if (0 == PATHCMP(e->filename, fullname)) #else if (st.st_dev == e->st.st_dev && st.st_ino == e->st.st_ino) #endif @@ -1686,20 +1699,20 @@ skip: if (!add) return NULL; - e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); + e = tcc_malloc(sizeof(CachedInclude) + strlen(NAME)); +#ifndef _WIN32 e->st = st; -#ifdef _WIN32 - e->hash = hash; #endif - strcpy(e->filename, filename); + strcpy(e->filename, NAME); e->ifndef_macro = e->once = 0; dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e); /* add in hash table */ e->hash_next = s1->cached_includes_hash[h]; s1->cached_includes_hash[h] = s1->nb_cached_includes; #ifdef INC_DEBUG - printf("adding cached '%s'\n", filename); + printf("adding cached '%s'\n", NAME); #endif +#undef NAME return e; } @@ -3709,6 +3722,9 @@ ST_FUNC void preprocess_start(TCCState *s1, int filetype) parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0; tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; +#ifdef _WIN32 + getcwd(pp_wd, sizeof(pp_wd)); +#endif } /* cleanup from error/setjmp */