| @@ -1607,38 +1607,88 @@ bad_twosharp: · 1606 unmodified lines |
| 1607 | 1607 | define_push(v, t, tok_str_dup(&tokstr_buf), first); |
| 1608 | 1608 | } |
| 1609 | 1609 | |
| 1610 | +#ifdef _WIN32 |
| 1611 | +static unsigned long long calc_file_hash(const char *filename) |
| 1612 | +{ |
| 1613 | + unsigned long long hash = 14695981039346656037ull; // FNV_offset_basis; |
| 1614 | + FILE *fp = fopen (filename, "rb"); |
| 1615 | + |
| 1616 | + if (fp == NULL) |
| 1617 | + return 0; |
| 1618 | + for (;;) { |
| 1619 | + unsigned char temp[IO_BUF_SIZE]; |
| 1620 | + int i, n = fread(temp, 1, sizeof(temp), fp); |
| 1621 | + |
| 1622 | + if (n <= 0) |
| 1623 | + break; |
| 1624 | + for (i = 0; i < n; i++) |
| 1625 | + hash = hash * 1099511628211ull + temp[i]; // FNV_prime |
| 1626 | + } |
| 1627 | + fclose(fp); |
| 1628 | + if (hash == 0) |
| 1629 | + hash = 1; |
| 1630 | + return hash; |
| 1631 | +} |
| 1632 | +#endif |
| 1633 | + |
| 1610 | 1634 | static CachedInclude *search_cached_include(TCCState *s1, const char *filename, int add) |
| 1611 | 1635 | { |
| 1612 | | − const unsigned char *s; |
| 1613 | | − unsigned int h; |
| 1636 | + unsigned int h = 0; |
| 1614 | 1637 | CachedInclude *e; |
| 1615 | 1638 | int i; |
| 1616 | | − |
| 1617 | | − h = TOK_HASH_INIT; |
| 1618 | | − s = (unsigned char *) filename; |
| 1619 | | − while (*s) { |
| 1639 | + struct stat st; |
| 1620 | 1640 | #ifdef _WIN32 |
| 1621 | | − h = TOK_HASH_FUNC(h, toup(*s)); |
| 1622 | | −#else |
| 1623 | | − h = TOK_HASH_FUNC(h, *s); |
| 1641 | + unsigned long long hash = 0; |
| 1624 | 1642 | #endif |
| 1625 | | − s++; |
| 1643 | + |
| 1644 | + /* This is needed for #pragmae once |
| 1645 | + * We cannot use stat on windows because st_ino is not set correctly |
| 1646 | + * so we calculate a hash of file contents. |
| 1647 | + * This also works for hard/soft links as in gcc/clang. |
| 1648 | + */ |
| 1649 | + memset (&st, 0, sizeof(st)); |
| 1650 | + if (stat (filename, &st)) |
| 1651 | + goto skip; |
| 1652 | + h = st.st_size & (CACHED_INCLUDES_HASH_SIZE - 1); |
| 1653 | +#ifdef _WIN32 |
| 1654 | + /* Only calculate file hash if file size same. */ |
| 1655 | + i = s1->cached_includes_hash[h]; |
| 1656 | + for(;;) { |
| 1657 | + if (i == 0) |
| 1658 | + break; |
| 1659 | + e = s1->cached_includes[i - 1]; |
| 1660 | + if (e->st.st_size == st.st_size) { |
| 1661 | + if (e->hash == 0) |
| 1662 | + e->hash = calc_file_hash(e->filename); |
| 1663 | + hash = calc_file_hash(filename); |
| 1664 | + break; |
| 1665 | + } |
| 1666 | + i = e->hash_next; |
| 1626 | 1667 | } |
| 1627 | | − h &= (CACHED_INCLUDES_HASH_SIZE - 1); |
| 1668 | +#endif |
| 1628 | 1669 | |
| 1629 | 1670 | i = s1->cached_includes_hash[h]; |
| 1630 | 1671 | for(;;) { |
| 1631 | 1672 | if (i == 0) |
| 1632 | 1673 | break; |
| 1633 | 1674 | e = s1->cached_includes[i - 1]; |
| 1634 | | − if (0 == PATHCMP(e->filename, filename)) |
| 1675 | +#ifdef _WIN32 |
| 1676 | + if (e->st.st_size == st.st_size && e->hash == hash) |
| 1677 | +#else |
| 1678 | + if (st.st_dev == e->st.st_dev && st.st_ino == e->st.st_ino) |
| 1679 | +#endif |
| 1635 | 1680 | return e; |
| 1636 | 1681 | i = e->hash_next; |
| 1637 | 1682 | } |
| 1683 | +skip: |
| 1638 | 1684 | if (!add) |
| 1639 | 1685 | return NULL; |
| 1640 | 1686 | |
| 1641 | 1687 | e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); |
| 1688 | + e->st = st; |
| 1689 | +#ifdef _WIN32 |
| 1690 | + e->hash = hash; |
| 1691 | +#endif |
| 1642 | 1692 | strcpy(e->filename, filename); |
| 1643 | 1693 | e->ifndef_macro = e->once = 0; |
| 1644 | 1694 | dynarray_add(&s1->cached_includes, &s1->nb_cached_includes, e); |