src/lib/osunix.c 1.44
1.44 2009/11/22 00:18:04 kent
Adding simplifyPathToDir
Index: src/lib/osunix.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/lib/osunix.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -b -B -U 4 -r1.43 -r1.44
--- src/lib/osunix.c 10 Jul 2009 01:52:27 -0000 1.43
+++ src/lib/osunix.c 22 Nov 2009 00:18:04 -0000 1.44
@@ -347,8 +347,148 @@
}
return fileName;
}
+static void eatSlashSlashInPath(char *path)
+/* Convert multiple // to single // */
+{
+char *s, *d;
+s = d = path;
+char c, lastC = 0;
+while ((c = *s++) != 0)
+ {
+ if (c == '/' && lastC == c)
+ continue;
+ *d++ = c;
+ lastC = c;
+ }
+*d = 0;
+}
+
+static void eatExcessDotDotInPath(char *path)
+/* If there's a /.. in path take it out. Turns
+ * 'this/long/../dir/file' to 'this/dir/file
+ * and
+ * 'this/../file' to 'file'
+ *
+ * and
+ * 'this/long/..' to 'this'
+ * and
+ * 'this/..' to ''
+ * and
+ * /this/..' to '/' */
+{
+/* Take out each /../ individually */
+for (;;)
+ {
+ /* Find first bit that needs to be taken out. */
+ char *excess= strstr(path, "/../");
+ char *excessEnd = excess+4;
+ if (excess == NULL || excess == path)
+ break;
+
+ /* Look for a '/' before this */
+ char *excessStart = matchingCharBeforeInLimits(path, excess, '/');
+ if (excessStart == NULL) /* Preceding '/' not found */
+ excessStart = path;
+ else
+ excessStart += 1;
+ strcpy(excessStart, excessEnd);
+ }
+
+/* Take out final /.. if any */
+if (endsWith(path, "/.."))
+ {
+ if (!sameString(path, "/..")) /* We don't want to turn this to blank. */
+ {
+ int len = strlen(path);
+ char *excessStart = matchingCharBeforeInLimits(path, path+len-3, '/');
+ if (excessStart == NULL) /* Preceding '/' not found */
+ excessStart = path;
+ else
+ excessStart += 1;
+ *excessStart = 0;
+ }
+ }
+}
+
+char *simplifyPathToDir(char *path)
+/* Return path with ~ and .. taken out. Also any // or trailing /.
+ * freeMem result when done. */
+{
+/* Expand ~ if any with result in newPath */
+char newPath[PATH_LEN];
+int newLen = 0;
+char *s = path;
+if (*s == '~')
+ {
+ char *homeDir = getenv("HOME");
+ if (homeDir == NULL)
+ errAbort("No HOME environment var defined after ~ in simplifyPathToDir");
+ ++s;
+ if (*s == '/') /* ~/something */
+ {
+ ++s;
+ safef(newPath, sizeof(newPath), "%s/", homeDir);
+ }
+ else /* ~something */
+ {
+ safef(newPath, sizeof(newPath), "%s/../", homeDir);
+ }
+ newLen = strlen(newPath);
+ }
+int remainingLen = strlen(s);
+if (newLen + remainingLen >= sizeof(newPath))
+ errAbort("path too big in simplifyPathToDir");
+strcpy(newPath+newLen, s);
+
+/* Remove //, .. and trailing / */
+eatSlashSlashInPath(newPath);
+eatExcessDotDotInPath(newPath);
+int lastPos = strlen(newPath)-1;
+if (lastPos > 0 && newPath[lastPos] == '/')
+ newPath[lastPos] = 0;
+
+return cloneString(newPath);
+}
+
+#ifdef DEBUG
+void simplifyPathToDirSelfTest()
+{
+/* First test some cases which should remain the same. */
+assert(sameString(simplifyPathToDir(""),""));
+assert(sameString(simplifyPathToDir("a"),"a"));
+assert(sameString(simplifyPathToDir("a/b"),"a/b"));
+assert(sameString(simplifyPathToDir("/"),"/"));
+assert(sameString(simplifyPathToDir("/.."),"/.."));
+assert(sameString(simplifyPathToDir("/../a"),"/../a"));
+
+/* Now test removing trailing slash. */
+assert(sameString(simplifyPathToDir("a/"),"a"));
+assert(sameString(simplifyPathToDir("a/b/"),"a/b"));
+
+/* Test .. removal. */
+assert(sameString(simplifyPathToDir("a/.."),""));
+assert(sameString(simplifyPathToDir("a/../"),""));
+assert(sameString(simplifyPathToDir("a/../b"),"b"));
+assert(sameString(simplifyPathToDir("/a/.."),"/"));
+assert(sameString(simplifyPathToDir("/a/../"),"/"));
+assert(sameString(simplifyPathToDir("/a/../b"),"/b"));
+assert(sameString(simplifyPathToDir("a/b/.."),"a"));
+assert(sameString(simplifyPathToDir("a/b/../"),"a"));
+assert(sameString(simplifyPathToDir("a/b/../c"),"a/c"));
+assert(sameString(simplifyPathToDir("a/../b/../c"),"c"));
+assert(sameString(simplifyPathToDir("a/../b/../c/.."),""));
+assert(sameString(simplifyPathToDir("/a/../b/../c/.."),"/"));
+
+/* Test // removal */
+assert(sameString(simplifyPathToDir("//"),"/"));
+assert(sameString(simplifyPathToDir("//../"),"/.."));
+assert(sameString(simplifyPathToDir("a//b///c"),"a/b/c"));
+assert(sameString(simplifyPathToDir("a/b///"),"a/b"));
+}
+#endif /* DEBUG */
+
char *getUser()
/* Get user name */
{
uid_t uid = geteuid();