summaryrefslogtreecommitdiff
path: root/fitz/base_cleanname.c
diff options
context:
space:
mode:
Diffstat (limited to 'fitz/base_cleanname.c')
-rw-r--r--fitz/base_cleanname.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/fitz/base_cleanname.c b/fitz/base_cleanname.c
new file mode 100644
index 00000000..54764630
--- /dev/null
+++ b/fitz/base_cleanname.c
@@ -0,0 +1,52 @@
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+
+#define SEP(x) ((x)=='/' || (x) == 0)
+
+char *
+cleanname(char *name)
+{
+ char *p, *q, *dotdot;
+ int rooted;
+
+ rooted = name[0] == '/';
+
+ /*
+ * invariants:
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ * dotdot points just past the point where .. cannot backtrack
+ * any further (no slash).
+ */
+ p = q = dotdot = name+rooted;
+ while(*p) {
+ if(p[0] == '/') /* null element */
+ p++;
+ else if(p[0] == '.' && SEP(p[1]))
+ p += 1; /* don't count the separator in case it is nul */
+ else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+ p += 2;
+ if(q > dotdot) { /* can backtrack */
+ while(--q > dotdot && *q != '/')
+ ;
+ } else if(!rooted) { /* /.. is / but ./../ is .. */
+ if(q != name)
+ *q++ = '/';
+ *q++ = '.';
+ *q++ = '.';
+ dotdot = q;
+ }
+ } else { /* real path element */
+ if(q != name+rooted)
+ *q++ = '/';
+ while((*q = *p) != '/' && *q != 0)
+ p++, q++;
+ }
+ }
+ if(q == name) /* empty string is really ``.'' */
+ *q++ = '.';
+ *q = '\0';
+ return name;
+}
+