From fc94bd411a46847f24e56b9fa2a524ccf1f5d8b6 Mon Sep 17 00:00:00 2001
From: Kelvin Ly <kelvin.ly1618@gmail.com>
Date: Sat, 7 Jan 2017 00:23:16 -0500
Subject: [PATCH] Allow for more complicated directory paths

---
 src/context/context.rs | 45 +++++++++++++++++++++++++++---------------
 1 file changed, 29 insertions(+), 16 deletions(-)

diff --git a/src/context/context.rs b/src/context/context.rs
index 607653c8..7c794f52 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -133,20 +133,6 @@ impl Context {
                                    .iter().rposition(|&b| b == b'/' || b == b':')
                                    .map_or(cwd.len(), |i| i + 1)]
                    .to_vec()
-            } else if path.starts_with(b"./") {
-                let mut canon = cwd.clone();
-                if ! canon.ends_with(b"/") {
-                    canon.push(b'/');
-                }
-                canon.extend_from_slice(&path[2..]);
-                canon
-            } else if path.starts_with(b"../") {
-                let mut canon = cwd[..cwd[..cwd.len() - 1]
-                                   .iter().rposition(|&b| b == b'/' || b == b':')
-                                   .map_or(cwd.len(), |i| i + 1)]
-                   .to_vec();
-                canon.extend_from_slice(&path[3..]);
-                canon
             } else if path.starts_with(b"/") {
                 let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                 canon.extend_from_slice(&path);
@@ -157,8 +143,35 @@ impl Context {
                     canon.push(b'/');
                 }
                 canon.extend_from_slice(&path);
-                canon
-            }
+                // NOTE: assumes the scheme does not include anything like "../" or "./"
+                let rparts = canon.split(|&c| c == b'/')
+                    .filter(|&part| part != b".")
+                    .rev()
+                    .scan(0, |nskip, part| {
+                        if part == b".." {
+                            *nskip += 1;
+                            Some(None)
+                        } else {
+                            if *nskip > 0 {
+                                *nskip -= 1;
+                                Some(None)
+                            } else {
+                                Some(Some(part))
+                            }
+                        }
+                    })
+                    .filter_map(|x| x)
+                    .collect::<Vec<_>>();
+                let mut result = rparts
+                    .iter()
+                    .rev()
+                    .fold(Vec::new(), |mut vec, &part| {
+                        vec.extend_from_slice(part);
+                        vec.push(b'/');
+                        vec
+                    });
+                result.pop(); // remove extra '/'
+                result
         } else {
             path.to_vec()
         }
-- 
GitLab