1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "nacl_io/path.h"
12 #include "sdk_util/string_util.h"
16 Path::Path() : len_(0) {
20 Path::Path(const Path
& path
) {
22 strcpy(path_
, path
.path_
);
25 Path::Path(const std::string
& path
) {
29 bool Path::IsAbsolute() const {
30 return path_
[0] == '/';
33 std::string
Path::Part(size_t index
) const {
34 if (IsAbsolute() && index
== 0) {
35 return std::string("/");
38 const char* start
= &path_
[0];
41 for (p
= &path_
[0]; *p
; p
++) {
43 if (++slashes
== index
+ 1)
50 return std::string(start
, p
- start
);
53 size_t Path::Size() const {
57 const char* p
= &path_
[0];
58 if (len_
== 1 && *p
== '/') {
70 bool Path::IsRoot() const {
71 return strcmp(path_
, "/") == 0;
74 Path
& Path::MakeRelative() {
76 memmove(&path_
[0], &path_
[1], PATH_MAX
- 1);
82 Path
& Path::Append(const Path
& path
) {
83 // Appending an absolute path effectivly sets the path, ignoring
84 // the current contents.
85 if (path
.IsAbsolute()) {
86 strcpy(path_
, path
.path_
);
88 strncat(path_
, "/", PATH_MAX
- len_
- 1);
90 strncat(path_
, path
.path_
, PATH_MAX
- len_
- 1);
93 if (len_
>= PATH_MAX
- 1) {
102 Path
& Path::Append(const std::string
& path
) {
103 return Append(Path(path
));
106 Path
& Path::Set(const std::string
& path
) {
107 strncpy(path_
, path
.c_str(), PATH_MAX
- 1);
108 path_
[PATH_MAX
- 1] = 0;
109 len_
= path
.length();
110 if (len_
> PATH_MAX
- 1)
116 Path
Path::Parent() const {
117 const char* last_slash
= strrchr(path_
, '/');
120 if (last_slash
== &path_
[0]) {
122 strcpy(out
.path_
, "/");
124 out
.len_
= last_slash
- &path_
[0];
125 strncpy(out
.path_
, path_
, out
.len_
);
126 out
.path_
[out
.len_
] = 0;
135 std::string
Path::Basename() const {
137 return std::string(path_
);
139 const char* last_slash
= strrchr(path_
, '/');
141 return std::string(last_slash
+ 1, path_
+ len_
- (last_slash
+ 1));
143 return std::string(path_
);
146 std::string
Path::Join() const {
147 return std::string(path_
);
150 std::string
Path::Range(size_t start
, size_t end
) const {
151 assert(start
<= end
);
153 const char* pstart
= &path_
[0];
154 const char* pend
= &path_
[len_
];
156 if (IsAbsolute() && start
== 0 && end
== 1)
157 return std::string("/");
160 for (const char* p
= &path_
[0]; *p
; p
++) {
163 if (slashes
== start
)
166 if (slashes
== end
) {
173 if (slashes
< start
|| pstart
> pend
)
174 return std::string();
176 return std::string(pstart
, pend
- pstart
);
179 void Path::Normalize() {
180 char* outp
= &path_
[0];
181 const char* start
= outp
;
182 const char* part_start
= start
;
183 const char* next_slash
;
184 bool is_absolute
= false;
187 // Absolute path. Append the slash, then continue the algorithm as if the
188 // path were relative.
196 next_slash
= strchr(part_start
, '/');
197 const char* part_end
= next_slash
;
199 part_end
= part_start
+ strlen(part_start
);
201 size_t part_len
= part_end
- part_start
;
203 bool should_append
= true;
205 // Don't append if the part is empty.
206 should_append
= false;
207 } else if (part_len
== 1 && part_start
[0] == '.') {
209 should_append
= false;
210 } else if (part_len
== 2 && part_start
[0] == '.' && part_start
[1] == '.') {
211 // If part is "..", only append if the output is empty or already has
214 (outp
- start
>= 2 && outp
[-1] == '.' && outp
[-2] == '.')) {
215 should_append
= !is_absolute
;
217 should_append
= false;
218 // Move outp backward to the one past the previous slash, or to the
219 // beginning of the string. Unless outp == start, outp[-1] is a '/'.
222 while (outp
> start
&& outp
[0] != '/')
228 // Append [part_start, part_end) to outp.
230 // Append slash to separate from previous path.
234 // Only need to copy bytes when the pointers are different.
235 if (outp
!= part_start
) {
236 memmove(outp
, part_start
, part_len
);
242 part_start
= next_slash
+ 1;
243 } while (next_slash
);
245 // Return '.' instead of an empty path.
246 if (outp
== start
&& !is_absolute
) {
251 len_
= outp
- &path_
[0];
254 Path
& Path::operator=(const Path
& p
) {
256 strcpy(path_
, p
.path_
);
260 Path
& Path::operator=(const std::string
& p
) {
264 bool Path::operator==(const Path
& other
) {
265 return len_
== other
.len_
&& strncmp(path_
, other
.path_
, len_
) == 0;
268 bool Path::operator!=(const Path
& other
) {
269 return !operator==(other
);
272 } // namespace nacl_io