Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(578)

Side by Side Diff: base/file_path.cc

Issue 12907: Make FilePath accept FilePath as Append parameter. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 12 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/file_path.h ('k') | base/file_path_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/file_path.h" 5 #include "base/file_path.h"
6 #include "base/logging.h"
6 7
7 // These includes are just for the *Hack functions, and should be removed 8 // These includes are just for the *Hack functions, and should be removed
8 // when those functions are removed. 9 // when those functions are removed.
9 #include "base/string_piece.h" 10 #include "base/string_piece.h"
10 #include "base/sys_string_conversions.h" 11 #include "base/sys_string_conversions.h"
11 12
12 #if defined(FILE_PATH_USES_WIN_SEPARATORS) 13 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
13 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/"); 14 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
14 #else // FILE_PATH_USES_WIN_SEPARATORS 15 #else // FILE_PATH_USES_WIN_SEPARATORS
15 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/"); 16 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
16 #endif // FILE_PATH_USES_WIN_SEPARATORS 17 #endif // FILE_PATH_USES_WIN_SEPARATORS
17 18
18 const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL("."); 19 const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
19 const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL(".."); 20 const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
20 21
22 namespace {
23
24 // If this FilePath contains a drive letter specification, returns the
25 // position of the last character of the drive letter specification,
26 // otherwise returns npos. This can only be true on Windows, when a pathname
27 // begins with a letter followed by a colon. On other platforms, this always
28 // returns npos.
29 FilePath::StringType::size_type FindDriveLetter(
30 const FilePath::StringType& path) {
31 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
32 // This is dependent on an ASCII-based character set, but that's a
33 // reasonable assumption. iswalpha can be too inclusive here.
34 if (path.length() >= 2 && path[1] == L':' &&
35 ((path[0] >= L'A' && path[0] <= L'Z') ||
36 (path[0] >= L'a' && path[0] <= L'z'))) {
37 return 1;
38 }
39 return FilePath::StringType::npos;
40 #else // FILE_PATH_USES_DRIVE_LETTERS
41 return FilePath::StringType::npos;
42 #endif // FILE_PATH_USES_DRIVE_LETTERS
43 }
44
45 bool IsPathAbsolute(const FilePath::StringType& path) {
46 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
47 FilePath::StringType::size_type letter = FindDriveLetter(path);
48 if (letter != FilePath::StringType::npos) {
49 // Look for a separator right after the drive specification.
50 return path.length() > letter + 1 &&
51 FilePath::IsSeparator(path[letter + 1]);
52 }
53 // Look for a pair of leading separators.
54 return path.length() > 1 &&
55 FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
56 #else // FILE_PATH_USES_DRIVE_LETTERS
57 // Look for a separator in the first position.
58 return path.length() > 0 && FilePath::IsSeparator(path[0]);
59 #endif // FILE_PATH_USES_DRIVE_LETTERS
60 }
61
62 } // namespace
63
21 bool FilePath::IsSeparator(CharType character) { 64 bool FilePath::IsSeparator(CharType character) {
22 for (size_t i = 0; i < arraysize(kSeparators) - 1; ++i) { 65 for (size_t i = 0; i < arraysize(kSeparators) - 1; ++i) {
23 if (character == kSeparators[i]) { 66 if (character == kSeparators[i]) {
24 return true; 67 return true;
25 } 68 }
26 } 69 }
27 70
28 return false; 71 return false;
29 } 72 }
30 73
31 // libgen's dirname and basename aren't guaranteed to be thread-safe and aren't 74 // libgen's dirname and basename aren't guaranteed to be thread-safe and aren't
32 // guaranteed to not modify their input strings, and in fact are implmeneted 75 // guaranteed to not modify their input strings, and in fact are implmeneted
33 // differently in this regard on different platforms. Don't use them, but 76 // differently in this regard on different platforms. Don't use them, but
34 // adhere to their behavior. 77 // adhere to their behavior.
35 FilePath FilePath::DirName() const { 78 FilePath FilePath::DirName() const {
36 FilePath new_path(path_); 79 FilePath new_path(path_);
37 new_path.StripTrailingSeparators(); 80 new_path.StripTrailingSeparators();
38 81
39 // The drive letter, if any, always needs to remain in the output. If there 82 // The drive letter, if any, always needs to remain in the output. If there
40 // is no drive letter, as will always be the case on platforms which do not 83 // is no drive letter, as will always be the case on platforms which do not
41 // support drive letters, letter will be npos, or -1, so the comparisons and 84 // support drive letters, letter will be npos, or -1, so the comparisons and
42 // resizes below using letter will still be valid. 85 // resizes below using letter will still be valid.
43 StringType::size_type letter = new_path.FindDriveLetter(); 86 StringType::size_type letter = FindDriveLetter(new_path.path_);
44 87
45 StringType::size_type last_separator = 88 StringType::size_type last_separator =
46 new_path.path_.find_last_of(kSeparators, StringType::npos, 89 new_path.path_.find_last_of(kSeparators, StringType::npos,
47 arraysize(kSeparators) - 1); 90 arraysize(kSeparators) - 1);
48 if (last_separator == StringType::npos) { 91 if (last_separator == StringType::npos) {
49 // path_ is in the current directory. 92 // path_ is in the current directory.
50 new_path.path_.resize(letter + 1); 93 new_path.path_.resize(letter + 1);
51 } else if (last_separator == letter + 1) { 94 } else if (last_separator == letter + 1) {
52 // path_ is in the root directory. 95 // path_ is in the root directory.
53 new_path.path_.resize(letter + 2); 96 new_path.path_.resize(letter + 2);
(...skipping 12 matching lines...) Expand all
66 new_path.path_ = kCurrentDirectory; 109 new_path.path_ = kCurrentDirectory;
67 110
68 return new_path; 111 return new_path;
69 } 112 }
70 113
71 FilePath FilePath::BaseName() const { 114 FilePath FilePath::BaseName() const {
72 FilePath new_path(path_); 115 FilePath new_path(path_);
73 new_path.StripTrailingSeparators(); 116 new_path.StripTrailingSeparators();
74 117
75 // The drive letter, if any, is always stripped. 118 // The drive letter, if any, is always stripped.
76 StringType::size_type letter = new_path.FindDriveLetter(); 119 StringType::size_type letter = FindDriveLetter(new_path.path_);
77 if (letter != StringType::npos) { 120 if (letter != StringType::npos) {
78 new_path.path_.erase(0, letter + 1); 121 new_path.path_.erase(0, letter + 1);
79 } 122 }
80 123
81 // Keep everything after the final separator, but if the pathname is only 124 // Keep everything after the final separator, but if the pathname is only
82 // one character and it's a separator, leave it alone. 125 // one character and it's a separator, leave it alone.
83 StringType::size_type last_separator = 126 StringType::size_type last_separator =
84 new_path.path_.find_last_of(kSeparators, StringType::npos, 127 new_path.path_.find_last_of(kSeparators, StringType::npos,
85 arraysize(kSeparators) - 1); 128 arraysize(kSeparators) - 1);
86 if (last_separator != StringType::npos && 129 if (last_separator != StringType::npos &&
87 last_separator < new_path.path_.length() - 1) { 130 last_separator < new_path.path_.length() - 1) {
88 new_path.path_.erase(0, last_separator + 1); 131 new_path.path_.erase(0, last_separator + 1);
89 } 132 }
90 133
91 return new_path; 134 return new_path;
92 } 135 }
93 136
94 FilePath FilePath::Append(const FilePath::StringType& component) const { 137 FilePath FilePath::Append(const FilePath::StringType& component) const {
138 DCHECK(!IsPathAbsolute(component));
95 if (path_.compare(kCurrentDirectory) == 0) { 139 if (path_.compare(kCurrentDirectory) == 0) {
96 // Append normally doesn't do any normalization, but as a special case, 140 // Append normally doesn't do any normalization, but as a special case,
97 // when appending to kCurrentDirectory, just return a new path for the 141 // when appending to kCurrentDirectory, just return a new path for the
98 // component argument. Appending component to kCurrentDirectory would 142 // component argument. Appending component to kCurrentDirectory would
99 // serve no purpose other than needlessly lengthening the path, and 143 // serve no purpose other than needlessly lengthening the path, and
100 // it's likely in practice to wind up with FilePath objects containing 144 // it's likely in practice to wind up with FilePath objects containing
101 // only kCurrentDirectory when calling DirName on a single relative path 145 // only kCurrentDirectory when calling DirName on a single relative path
102 // component. 146 // component.
103 return FilePath(component); 147 return FilePath(component);
104 } 148 }
105 149
106 FilePath new_path(path_); 150 FilePath new_path(path_);
107 new_path.StripTrailingSeparators(); 151 new_path.StripTrailingSeparators();
108 152
109 // Don't append a separator if the path is empty (indicating the current 153 // Don't append a separator if the path is empty (indicating the current
110 // directory) or if the path component is empty (indicating nothing to 154 // directory) or if the path component is empty (indicating nothing to
111 // append). 155 // append).
112 if (component.length() > 0 && new_path.path_.length() > 0) { 156 if (component.length() > 0 && new_path.path_.length() > 0) {
113 157
114 // Don't append a separator if the path still ends with a trailing 158 // Don't append a separator if the path still ends with a trailing
115 // separator after stripping (indicating the root directory). 159 // separator after stripping (indicating the root directory).
116 if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) { 160 if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
117 161
118 // Don't append a separator if the path is just a drive letter. 162 // Don't append a separator if the path is just a drive letter.
119 if (new_path.FindDriveLetter() + 1 != new_path.path_.length()) { 163 if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
120 new_path.path_.append(1, kSeparators[0]); 164 new_path.path_.append(1, kSeparators[0]);
121 } 165 }
122 } 166 }
123 } 167 }
124 168
125 new_path.path_.append(component); 169 new_path.path_.append(component);
126 return new_path; 170 return new_path;
127 } 171 }
128 172
129 FilePath::StringType::size_type FilePath::FindDriveLetter() const { 173 FilePath FilePath::Append(const FilePath& component) const {
130 #if defined(FILE_PATH_USES_DRIVE_LETTERS) 174 return Append(component.value());
131 // This is dependent on an ASCII-based character set, but that's a
132 // reasonable assumption. iswalpha can be too inclusive here.
133 if (path_.length() >= 2 && path_[1] == L':' &&
134 ((path_[0] >= L'A' && path_[0] <= L'Z') ||
135 (path_[0] >= L'a' && path_[0] <= L'z'))) {
136 return 1;
137 }
138 return StringType::npos;
139 #else // FILE_PATH_USES_DRIVE_LETTERS
140 return StringType::npos;
141 #endif // FILE_PATH_USES_DRIVE_LETTERS
142 } 175 }
143 176
144 bool FilePath::IsAbsolute() const { 177 bool FilePath::IsAbsolute() const {
145 #if defined(FILE_PATH_USES_DRIVE_LETTERS) 178 return IsPathAbsolute(path_);
146 StringType::size_type letter = FindDriveLetter();
147 if (letter != StringType::npos) {
148 // Look for a separator right after the drive specification.
149 return path_.length() > letter + 1 && IsSeparator(path_[letter + 1]);
150 }
151 // Look for a pair of leading separators.
152 return path_.length() > 1 && IsSeparator(path_[0]) && IsSeparator(path_[1]);
153 #else // FILE_PATH_USES_DRIVE_LETTERS
154 // Look for a separator in the first position.
155 return path_.length() > 0 && IsSeparator(path_[0]);
156 #endif // FILE_PATH_USES_DRIVE_LETTERS
157 } 179 }
158 180
159 #if defined(OS_POSIX) 181 #if defined(OS_POSIX)
160 // See file_path.h for a discussion of the encoding of paths on POSIX 182 // See file_path.h for a discussion of the encoding of paths on POSIX
161 // platforms. These *Hack() functions are not quite correct, but they're 183 // platforms. These *Hack() functions are not quite correct, but they're
162 // only temporary while we fix the remainder of the code. 184 // only temporary while we fix the remainder of the code.
163 // Remember to remove the #includes at the top when you remove these. 185 // Remember to remove the #includes at the top when you remove these.
164 186
165 // static 187 // static
166 FilePath FilePath::FromWStringHack(const std::wstring& wstring) { 188 FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
(...skipping 11 matching lines...) Expand all
178 return path_; 200 return path_;
179 } 201 }
180 #endif 202 #endif
181 203
182 void FilePath::StripTrailingSeparators() { 204 void FilePath::StripTrailingSeparators() {
183 // If there is no drive letter, start will be 1, which will prevent stripping 205 // If there is no drive letter, start will be 1, which will prevent stripping
184 // the leading separator if there is only one separator. If there is a drive 206 // the leading separator if there is only one separator. If there is a drive
185 // letter, start will be set appropriately to prevent stripping the first 207 // letter, start will be set appropriately to prevent stripping the first
186 // separator following the drive letter, if a separator immediately follows 208 // separator following the drive letter, if a separator immediately follows
187 // the drive letter. 209 // the drive letter.
188 StringType::size_type start = FindDriveLetter() + 2; 210 StringType::size_type start = FindDriveLetter(path_) + 2;
189 211
190 StringType::size_type last_stripped = StringType::npos; 212 StringType::size_type last_stripped = StringType::npos;
191 for (StringType::size_type pos = path_.length(); 213 for (StringType::size_type pos = path_.length();
192 pos > start && IsSeparator(path_[pos - 1]); 214 pos > start && IsSeparator(path_[pos - 1]);
193 --pos) { 215 --pos) {
194 // If the string only has two separators and they're at the beginning, 216 // If the string only has two separators and they're at the beginning,
195 // don't strip them, unless the string began with more than two separators. 217 // don't strip them, unless the string began with more than two separators.
196 if (pos != start + 1 || last_stripped == start + 2 || 218 if (pos != start + 1 || last_stripped == start + 2 ||
197 !IsSeparator(path_[start - 1])) { 219 !IsSeparator(path_[start - 1])) {
198 path_.resize(pos - 1); 220 path_.resize(pos - 1);
199 last_stripped = pos; 221 last_stripped = pos;
200 } 222 }
201 } 223 }
202 } 224 }
OLDNEW
« no previous file with comments | « base/file_path.h ('k') | base/file_path_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698