@@ -281,13 +281,36 @@ std::string normalize_path(const std::string& _path)
281
281
// Replace multiple slashes with a single path_separator.
282
282
std::string path = fix_path_separators (_path);
283
283
284
- std::string fn ;
285
- fn. reserve (path. size () );
284
+ std::vector<std:: string> parts ;
285
+ split_string (path, parts, path_separators );
286
286
287
- // Add the first separator for absolute paths.
288
- if (!path.empty () && path[0 ] == path_separator) {
289
- fn.push_back (path_separator);
287
+ std::vector<std::string> fn_parts;
288
+ bool has_root = (!path.empty () && path[0 ] == path_separator);
289
+ bool last_dot = (parts.back () == " ." );
290
+ bool last_slash = parts.back ().empty ();
291
+ if (last_slash || last_dot)
292
+ parts.pop_back ();
293
+
294
+ for (const auto & part : parts) {
295
+ // Skip each dot part.
296
+ if (part.empty () || part == " ." )
297
+ continue ;
298
+ else if (part == " .." ) {
299
+ if (has_root && fn_parts.empty ())
300
+ continue ;
301
+ if (!fn_parts.empty () && fn_parts.back () != " .." )
302
+ fn_parts.pop_back ();
303
+ else
304
+ fn_parts.push_back (part);
305
+ }
306
+ else
307
+ fn_parts.push_back (part);
308
+ }
290
309
310
+ // Reconstruct the filename 'fn' from 'fn_parts'
311
+ std::string fn;
312
+ if (has_root) {
313
+ fn.push_back (path_separator);
291
314
#if LAF_WINDOWS
292
315
// Add the second separator for network paths.
293
316
if (path.size () >= 2 && path[1 ] == path_separator) {
@@ -296,51 +319,15 @@ std::string normalize_path(const std::string& _path)
296
319
#endif
297
320
}
298
321
299
- std::vector<std::string> parts;
300
- split_string (path, parts, path_separators);
301
-
302
- // Last element generates a final dot or slash in normalized path.
303
- bool last_dot = false ;
322
+ for (const auto & part : fn_parts)
323
+ fn = join_path (fn, part);
304
324
305
- auto n = int (parts.size ());
306
- for (int i = 0 ; i < n; ++i) {
307
- const auto & part = parts[i];
308
-
309
- // Remove each dot part.
310
- if (part == " ." ) {
311
- last_dot = true ;
312
-
313
- if (i + 1 == n)
314
- break ;
315
-
316
- fn = join_path (fn, std::string ());
317
- continue ;
318
- }
319
-
320
- if (!part.empty ())
321
- last_dot = false ;
325
+ if (!fn.empty () &&
326
+ parts.back () != " .." &&
327
+ (last_slash || last_dot))
328
+ fn.push_back (path_separator);
322
329
323
- if (part != " .." && i + 1 < n && parts[i + 1 ] == " .." ) {
324
- // Skip this "part/.."
325
- ++i;
326
- last_dot = true ;
327
- }
328
- else if (!part.empty ()) {
329
- fn = join_path (fn, part);
330
- }
331
- else
332
- last_dot = true ;
333
- }
334
- if (last_dot) {
335
- if (fn.empty ())
336
- fn = " ." ;
337
- else if (fn.back () != path_separator &&
338
- // Don't include trailing slash for ".." filename
339
- get_file_name (fn) != " .." ) {
340
- fn.push_back (path_separator);
341
- }
342
- }
343
- return fn;
330
+ return (fn.empty () ? " ." : fn);
344
331
}
345
332
346
333
bool has_file_extension (const std::string& filename, const base::paths& extensions)
0 commit comments