 |
Changeset 3764
- Timestamp:
- 07/20/08 07:31:09
(5 months ago)
- Author:
- larsivi
- Message:
Remove heap churn, make it possible to use optional buffer
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r3763 |
r3764 |
|
| 16 | 16 | |
|---|
| 17 | 17 | private import tango.core.Exception; |
|---|
| | 18 | |
|---|
| | 19 | private extern (C) void memmove (void* dst, void* src, uint bytes); |
|---|
| 18 | 20 | |
|---|
| 19 | 21 | /******************************************************************************* |
|---|
| … | … | |
| 34 | 36 | be fully normalized. |
|---|
| 35 | 37 | |
|---|
| | 38 | The input path is copied into either the provided buffer, or a heap |
|---|
| | 39 | allocated array if no buffer was provided. Normalization modifies |
|---|
| | 40 | this copy before returning the relevant slice. |
|---|
| | 41 | |
|---|
| 36 | 42 | Throws: IllegalArgumentException if the root separator is followed by .. |
|---|
| 37 | 43 | |
|---|
| … | … | |
| 43 | 49 | *******************************************************************************/ |
|---|
| 44 | 50 | |
|---|
| 45 | | char[] normalize(char[] path) |
|---|
| 46 | | { |
|---|
| 47 | | |
|---|
| | 51 | char[] normalize(char[] path, char[] buf = null) |
|---|
| | 52 | { |
|---|
| | 53 | uint end; |
|---|
| 48 | 54 | version (Windows) { |
|---|
| 49 | 55 | /* |
|---|
| … | … | |
| 60 | 66 | } |
|---|
| 61 | 67 | } |
|---|
| | 68 | /* |
|---|
| | 69 | Internal helper to truncate the path, avoids heap usage. |
|---|
| | 70 | */ |
|---|
| | 71 | void truncate(char[] path, char[] slice1, char[] slice2) { |
|---|
| | 72 | memmove(path.ptr, slice1.ptr, slice1.length); |
|---|
| | 73 | memmove(path.ptr + slice1.length, slice2.ptr, slice2.length); |
|---|
| | 74 | assert (end > slice1.length+slice2.length); |
|---|
| | 75 | end = slice1.length+slice2.length; |
|---|
| | 76 | } |
|---|
| 62 | 77 | |
|---|
| 63 | 78 | /* |
|---|
| … | … | |
| 65 | 80 | */ |
|---|
| 66 | 81 | int findSlashDot(char[] path, int start) { |
|---|
| 67 | | assert(start < path.length); |
|---|
| 68 | | foreach(i, c; path[start..$-1]) |
|---|
| | 82 | assert(start < end); |
|---|
| | 83 | foreach(i, c; path[start..end-1]) |
|---|
| 69 | 84 | if (c == '/') |
|---|
| 70 | 85 | if (path[start+i+1] == '.') |
|---|
| … | … | |
| 78 | 93 | */ |
|---|
| 79 | 94 | int findSlash(char[] path, int start) { |
|---|
| 80 | | assert(start < path.length); |
|---|
| | 95 | assert(start < end); |
|---|
| 81 | 96 | |
|---|
| 82 | 97 | if (start < 0) |
|---|
| … | … | |
| 94 | 109 | Internal helper that recursively shortens all segments with dots. |
|---|
| 95 | 110 | */ |
|---|
| 96 | | char[] removeDots(char[] path, int start) { |
|---|
| 97 | | assert (start < path.length); |
|---|
| | 111 | void removeDots(char[] path, int start) { |
|---|
| | 112 | assert (start < end); |
|---|
| 98 | 113 | assert (path[start] == '.'); |
|---|
| 99 | | if (start + 1 == path.length) { |
|---|
| | 114 | if (start + 1 == end) { |
|---|
| 100 | 115 | // path ends with /., remove |
|---|
| 101 | | return path[0..start - 1]; |
|---|
| | 116 | end = start - 1; |
|---|
| | 117 | return; |
|---|
| 102 | 118 | } |
|---|
| 103 | 119 | else if (path[start+1] == '/') { |
|---|
| 104 | 120 | // remove all subsequent './' |
|---|
| 105 | 121 | do { |
|---|
| 106 | | path = path[0..start] ~ path[start+2..$]; |
|---|
| 107 | | } while (start + 2 < path.length && path[start..start+2] == "./"); |
|---|
| | 122 | truncate(path, path[0..start], path[start+2..end]); |
|---|
| | 123 | } while (start + 2 < end && path[start..start+2] == "./"); |
|---|
| 108 | 124 | int idx = findSlashDot(path, start - 1); |
|---|
| 109 | 125 | if (idx < 0) { |
|---|
| 110 | 126 | // no more /., return path |
|---|
| 111 | | return path; |
|---|
| | 127 | return; |
|---|
| 112 | 128 | } |
|---|
| 113 | 129 | return removeDots(path, idx); |
|---|
| … | … | |
| 127 | 143 | } |
|---|
| 128 | 144 | int idx = findSlash(path, start - 2); |
|---|
| 129 | | if (start + 2 == path.length) { |
|---|
| | 145 | if (start + 2 == end) { |
|---|
| 130 | 146 | // path ends with /.. |
|---|
| 131 | 147 | if (idx < 0) { |
|---|
| 132 | 148 | // no more slashes in front of /.., resolves to empty path |
|---|
| 133 | | return ""; |
|---|
| | 149 | end = 0; |
|---|
| | 150 | return; |
|---|
| 134 | 151 | } |
|---|
| 135 | 152 | // remove /.. and preceding segment and return |
|---|
| 136 | | return path[0..idx]; |
|---|
| | 153 | end = idx; |
|---|
| | 154 | return; |
|---|
| 137 | 155 | } |
|---|
| 138 | 156 | else if (path[start+2] == '/') { |
|---|
| … | … | |
| 145 | 163 | if (idx < 0) { |
|---|
| 146 | 164 | // no more /., path fully shortened |
|---|
| 147 | | return path; |
|---|
| | 165 | return; |
|---|
| 148 | 166 | } |
|---|
| 149 | 167 | return removeDots(path, idx); |
|---|
| 150 | 168 | } |
|---|
| 151 | | path = path[0..idx < 0 ? 0 : idx + 1] ~ path[start+3..$]; |
|---|
| | 169 | truncate(path, path[0..idx < 0 ? 0 : idx + 1], path[start+3..end]); |
|---|
| 152 | 170 | idx = findSlashDot(path, idx < 0 ? 0 : idx); |
|---|
| 153 | 171 | if (idx < 0) { |
|---|
| 154 | 172 | // no more /., path fully shortened |
|---|
| 155 | | return path; |
|---|
| | 173 | return; |
|---|
| 156 | 174 | } |
|---|
| 157 | 175 | // examine next /. |
|---|
| … | … | |
| 160 | 178 | } |
|---|
| 161 | 179 | else { |
|---|
| 162 | | if (findSlash(path, path.length - 1) < start) |
|---|
| | 180 | if (findSlash(path, end - 1) < start) |
|---|
| 163 | 181 | // segment is filename that starts with ., and at the end |
|---|
| 164 | | return path; |
|---|
| | 182 | return; |
|---|
| 165 | 183 | else { |
|---|
| 166 | 184 | // not at end |
|---|
| … | … | |
| 169 | 187 | return removeDots(path, idx); |
|---|
| 170 | 188 | else |
|---|
| 171 | | return path; |
|---|
| | 189 | return; |
|---|
| 172 | 190 | } |
|---|
| 173 | 191 | } |
|---|
| … | … | |
| 178 | 196 | return path; |
|---|
| 179 | 197 | |
|---|
| 180 | | char[] normpath = path.dup; |
|---|
| | 198 | char[] normpath; |
|---|
| | 199 | if (buf is null) { |
|---|
| | 200 | normpath = path.dup; |
|---|
| | 201 | } |
|---|
| | 202 | else { |
|---|
| | 203 | normpath = buf; |
|---|
| | 204 | normpath[0..path.length] = path; |
|---|
| | 205 | } |
|---|
| | 206 | |
|---|
| 181 | 207 | version (Windows) { |
|---|
| 182 | 208 | normpath = normalizeSlashes(normpath); |
|---|
| 183 | 209 | } |
|---|
| | 210 | end = normpath.length; |
|---|
| 184 | 211 | |
|---|
| 185 | 212 | // if path starts with ./, remove all subsequent instances |
|---|
| 186 | | while (normpath.length > 1 && normpath[0] == '.' && |
|---|
| 187 | | normpath[1] == '/') { |
|---|
| 188 | | normpath = normpath[2..$]; |
|---|
| | 213 | while (end > 1 && normpath[0] == '.' && normpath[1] == '/') { |
|---|
| | 214 | truncate(normpath, normpath[0..0], normpath[2..end]); |
|---|
| 189 | 215 | } |
|---|
| 190 | 216 | int idx = findSlashDot(normpath, 0); |
|---|
| 191 | 217 | if (idx > -1) { |
|---|
| 192 | | normpath = removeDots(normpath, idx); |
|---|
| 193 | | } |
|---|
| 194 | | |
|---|
| 195 | | return normpath; |
|---|
| | 218 | removeDots(normpath, idx); |
|---|
| | 219 | } |
|---|
| | 220 | |
|---|
| | 221 | return normpath[0..end]; |
|---|
| 196 | 222 | } |
|---|
| 197 | 223 | |
|---|
| … | … | |
| 203 | 229 | { |
|---|
| 204 | 230 | assert (normalize ("") == ""); |
|---|
| 205 | | assert (normalize ("/home/../john/../.tango/.htaccess") == "/.tango/.htaccess", |
|---|
| 206 | | normalize ("/home/../john/../.tango/.htaccess")); |
|---|
| 207 | | assert (normalize ("/home/../john/../.tango/foo.conf") == "/.tango/foo.conf", |
|---|
| 208 | | normalize ("/home/../john/../.tango/foo.conf")); |
|---|
| 209 | | assert (normalize ("/home/john/.tango/foo.conf") == "/home/john/.tango/foo.conf", |
|---|
| 210 | | normalize ("/home/john/.tango/foo.conf")); |
|---|
| 211 | | assert (normalize ("/foo/bar/.htaccess") == "/foo/bar/.htaccess", |
|---|
| 212 | | normalize ("/foo/bar/.htaccess")); |
|---|
| 213 | | assert (normalize ("foo/bar/././.") == "foo/bar", |
|---|
| 214 | | normalize ("foo/bar/././.")); |
|---|
| 215 | | assert (normalize ("././foo/././././bar") == "foo/bar", |
|---|
| 216 | | normalize ("././foo/././././bar")); |
|---|
| 217 | | assert (normalize ("/foo/../john") == "/john", |
|---|
| 218 | | normalize("/foo/../john")); |
|---|
| | 231 | assert (normalize ("/home/../john/../.tango/.htaccess") == "/.tango/.htaccess"); |
|---|
| | 232 | assert (normalize ("/home/../john/../.tango/foo.conf") == "/.tango/foo.conf"); |
|---|
| | 233 | assert (normalize ("/home/john/.tango/foo.conf") == "/home/john/.tango/foo.conf"); |
|---|
| | 234 | assert (normalize ("/foo/bar/.htaccess") == "/foo/bar/.htaccess"); |
|---|
| | 235 | assert (normalize ("foo/bar/././.") == "foo/bar"); |
|---|
| | 236 | assert (normalize ("././foo/././././bar") == "foo/bar"); |
|---|
| | 237 | assert (normalize ("/foo/../john") == "/john"); |
|---|
| 219 | 238 | assert (normalize ("foo/../john") == "john"); |
|---|
| 220 | 239 | assert (normalize ("foo/bar/..") == "foo"); |
|---|
Download in other formats:
|
 |
 |
|
 |
Copyright © 2006-2008 Tango. All Rights Reserved. | Page Width:
Static or
Dynamic