diff options
author | Nico Weber <nicolasweber@gmx.de> | 2014-11-12 18:10:29 (GMT) |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2014-11-12 18:10:29 (GMT) |
commit | 6aa1b4b6d3d2d3efa55f91649271ed253ef5cab7 (patch) | |
tree | c0cbdf6e814038385bad3945b2229e7dd611eb00 /src/util.cc | |
parent | 513f5bb1ed7392686c455cbe2989d143230a1d80 (diff) | |
parent | cc8b72a87d72a030dc5b2bb212958c0e46213a6b (diff) | |
download | Ninja-6aa1b4b6d3d2d3efa55f91649271ed253ef5cab7.zip Ninja-6aa1b4b6d3d2d3efa55f91649271ed253ef5cab7.tar.gz Ninja-6aa1b4b6d3d2d3efa55f91649271ed253ef5cab7.tar.bz2 |
Merge pull request #848 from sgraham/canon-maintain
Maintain bitvector of original slashes from manifest when canonicalizing
Diffstat (limited to 'src/util.cc')
-rw-r--r-- | src/util.cc | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/src/util.cc b/src/util.cc index cb8adf1..4df81dd 100644 --- a/src/util.cc +++ b/src/util.cc @@ -85,19 +85,33 @@ void Error(const char* msg, ...) { fprintf(stderr, "\n"); } -bool CanonicalizePath(string* path, string* err) { +bool CanonicalizePath(string* path, unsigned int* slash_bits, string* err) { METRIC_RECORD("canonicalize str"); size_t len = path->size(); char* str = 0; if (len > 0) str = &(*path)[0]; - if (!CanonicalizePath(str, &len, err)) + if (!CanonicalizePath(str, &len, slash_bits, err)) return false; path->resize(len); return true; } -bool CanonicalizePath(char* path, size_t* len, string* err) { +#ifdef _WIN32 +static unsigned int ShiftOverBit(int offset, unsigned int bits) { + // e.g. for |offset| == 2: + // | ... 9 8 7 6 5 4 3 2 1 0 | + // \_________________/ \_/ + // above below + // So we drop the bit at offset and move above "down" into its place. + unsigned int above = bits & ~((1 << (offset + 1)) - 1); + unsigned int below = bits & ((1 << offset) - 1); + return (above >> 1) | below; +} +#endif + +bool CanonicalizePath(char* path, size_t* len, unsigned int* slash_bits, + string* err) { // WARNING: this function is performance-critical; please benchmark // any changes you make to it. METRIC_RECORD("canonicalize path"); @@ -106,11 +120,6 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { return false; } -#ifdef _WIN32 - for (char* c = path; (c = strchr(c, '\\')) != NULL;) - *c = '/'; -#endif - const int kMaxPathComponents = 30; char* components[kMaxPathComponents]; int component_count = 0; @@ -120,12 +129,35 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { const char* src = start; const char* end = start + *len; +#ifdef _WIN32 + unsigned int bits = 0; + unsigned int bits_mask = 1; + int bits_offset = 0; + // Convert \ to /, setting a bit in |bits| for each \ encountered. + for (char* c = path; c < end; ++c) { + switch (*c) { + case '\\': + bits |= bits_mask; + *c = '/'; + // Intentional fallthrough. + case '/': + bits_mask <<= 1; + bits_offset++; + } + } + if (bits_offset > 32) + return false; + bits_offset = 0; +#endif + if (*src == '/') { #ifdef _WIN32 + bits_offset++; // network path starts with // if (*len > 1 && *(src + 1) == '/') { src += 2; dst += 2; + bits_offset++; } else { ++src; ++dst; @@ -141,6 +173,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { if (src + 1 == end || src[1] == '/') { // '.' component; eliminate. src += 2; +#ifdef _WIN32 + bits = ShiftOverBit(bits_offset, bits); +#endif continue; } else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) { // '..' component. Back up if possible. @@ -148,6 +183,11 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { dst = components[component_count - 1]; src += 3; --component_count; +#ifdef _WIN32 + bits = ShiftOverBit(bits_offset, bits); + bits_offset--; + bits = ShiftOverBit(bits_offset, bits); +#endif } else { *dst++ = *src++; *dst++ = *src++; @@ -159,6 +199,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { if (*src == '/') { src++; +#ifdef _WIN32 + bits = ShiftOverBit(bits_offset, bits); +#endif continue; } @@ -169,6 +212,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { while (*src != '/' && src != end) *dst++ = *src++; +#ifdef _WIN32 + bits_offset++; +#endif *dst++ = *src++; // Copy '/' or final \0 character as well. } @@ -178,6 +224,11 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { } *len = dst - start - 1; +#ifdef _WIN32 + *slash_bits = bits; +#else + *slash_bits = 0; +#endif return true; } |