diff options
author | Scott Graham <scottmg@chromium.org> | 2014-11-08 06:20:34 (GMT) |
---|---|---|
committer | Scott Graham <scottmg@chromium.org> | 2014-11-08 06:20:34 (GMT) |
commit | e24d31901fc79aa7348be46bef5dea8d0dce6c4b (patch) | |
tree | 6f5461e13d02a44c4ce9d7287688329a9ef52774 /src/util.cc | |
parent | 513f5bb1ed7392686c455cbe2989d143230a1d80 (diff) | |
download | Ninja-e24d31901fc79aa7348be46bef5dea8d0dce6c4b.zip Ninja-e24d31901fc79aa7348be46bef5dea8d0dce6c4b.tar.gz Ninja-e24d31901fc79aa7348be46bef5dea8d0dce6c4b.tar.bz2 |
track back->forward conversions in a bitmask
Diffstat (limited to 'src/util.cc')
-rw-r--r-- | src/util.cc | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/src/util.cc b/src/util.cc index cb8adf1..6a9079e 100644 --- a/src/util.cc +++ b/src/util.cc @@ -86,18 +86,40 @@ void Error(const char* msg, ...) { } bool CanonicalizePath(string* path, string* err) { + unsigned int unused; + return CanonicalizePath(path, err, &unused); +} + +bool CanonicalizePath(string* path, string* err, unsigned int* slash_bits) { 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, err, slash_bits)) return false; path->resize(len); return true; } bool CanonicalizePath(char* path, size_t* len, string* err) { + unsigned int unused; + return CanonicalizePath(path, len, err, &unused); +} + +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; +} + +bool CanonicalizePath(char* path, size_t* len, string* err, + unsigned int* slash_bits) { // WARNING: this function is performance-critical; please benchmark // any changes you make to it. METRIC_RECORD("canonicalize path"); @@ -106,15 +128,22 @@ 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; +#ifdef _WIN32 + // kMaxPathComponents protects this from overflowing. + unsigned int bits = 0; + int bits_offset = 0; + for (char* c = path; (c = strpbrk(c, "/\\")) != NULL;) { + bits |= (*c == '\\') << bits_offset; + *c++ = '/'; + bits_offset++; + } + bits_offset = 0; +#endif + char* start = path; char* dst = start; const char* src = start; @@ -122,10 +151,12 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { 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 +172,7 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { if (src + 1 == end || src[1] == '/') { // '.' component; eliminate. src += 2; + bits = ShiftOverBit(bits_offset, bits); continue; } else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) { // '..' component. Back up if possible. @@ -148,6 +180,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { dst = components[component_count - 1]; src += 3; --component_count; + bits = ShiftOverBit(bits_offset, bits); + bits_offset--; + bits = ShiftOverBit(bits_offset, bits); } else { *dst++ = *src++; *dst++ = *src++; @@ -159,6 +194,7 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { if (*src == '/') { src++; + bits_offset++; continue; } @@ -169,6 +205,7 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { while (*src != '/' && src != end) *dst++ = *src++; + bits_offset++; *dst++ = *src++; // Copy '/' or final \0 character as well. } @@ -178,6 +215,9 @@ bool CanonicalizePath(char* path, size_t* len, string* err) { } *len = dst - start - 1; +#ifdef _WIN32 + *slash_bits = bits; +#endif return true; } |