summaryrefslogtreecommitdiffstats
path: root/src/util.cc
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2014-11-12 18:10:29 (GMT)
committerNico Weber <nicolasweber@gmx.de>2014-11-12 18:10:29 (GMT)
commit6aa1b4b6d3d2d3efa55f91649271ed253ef5cab7 (patch)
treec0cbdf6e814038385bad3945b2229e7dd611eb00 /src/util.cc
parent513f5bb1ed7392686c455cbe2989d143230a1d80 (diff)
parentcc8b72a87d72a030dc5b2bb212958c0e46213a6b (diff)
downloadNinja-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.cc67
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;
}