Refactoring in sbr/path.c.
authormarkus schnalke <meillo@marmaro.de>
Sat, 5 Nov 2011 16:35:13 +0000 (17:35 +0100)
committermarkus schnalke <meillo@marmaro.de>
Sat, 5 Nov 2011 16:35:13 +0000 (17:35 +0100)
Especially: Replaced compath() with a more general packpath().

sbr/path.c

index b13c5fe..3b633d0 100644 (file)
@@ -8,20 +8,13 @@
 
 #include <h/mh.h>
 
-#define CWD     "./"
-#define NCWD    (sizeof(CWD) - 1)
-#define DOT     "."
-#define DOTDOT  ".."
-#define PWD     "../"
-#define NPWD    (sizeof(PWD) - 1)
-
 static char *pwds;
 
 /*
 ** static prototypes
 */
-static char *expath(char *,int);
-static void compath(char *);
+static char *expath(char *, int);
+static void packpath(char *);
 
 char *
 pluspath(char *name)
@@ -30,134 +23,165 @@ pluspath(char *name)
 }
 
 char *
-path(char *name, int flag)
+path(char *name, int type)
 {
-       register char *cp, *ep;
+       char *cp, *ep;
 
-       if ((cp = expath(name, flag))
-               && (ep = cp + strlen(cp) - 1) > cp
-               && *ep == '/')
+       if ((cp = expath(name, type)) &&
+                       (ep = cp+strlen(cp)-1) > cp &&
+                       *ep == '/') {
                *ep = '\0';
+       }
 
        return cp;
 }
 
 
 static char *
-expath(char *name, int flag)
+expath(char *name, int type)
 {
-       register char *cp, *ep;
+       char *cp, *ep;
        char buffer[BUFSIZ];
 
-       if (flag == TSUBCWF) {
+       if (type == TSUBCWF) {
+               /* @folder to +folder */
                snprintf(buffer, sizeof(buffer), "%s/%s", getfolder(1), name);
                name = m_mailpath(buffer);
-               compath(name);
+               packpath(name);
                snprintf(buffer, sizeof(buffer), "%s/", m_maildir(""));
                if (isprefix(buffer, name)) {
                        cp = name;
                        name = getcpy(name + strlen(buffer));
                        free(cp);
                }
-               flag = TFOLDER;
+               type = TFOLDER;
        }
 
-       if (*name == '/' || (flag == TFOLDER
-               && (strncmp(name, CWD, NCWD) && strcmp(name, DOT)
-               && strcmp(name, DOTDOT) && strncmp(name, PWD, NPWD))))
+       if (*name == '/') {
                return getcpy(name);
+       }
 
-       if (pwds == NULL)
+       if (type == TFOLDER &&
+                       (strncmp(name, "./", 2) && strcmp(name, ".") &&
+                       strcmp(name, "..") && strncmp(name, "../", 3))) {
+               /*
+               ** FIXME: Seems as if this check does not catch names like:
+               **        ``foo/../../..''.
+               */
+               return getcpy(name);
+       }
+
+       if (pwds == NULL) {
                pwds = pwd();
+       }
 
-       if (strcmp(name, DOT) == 0 || strcmp(name, CWD) == 0)
+       if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0) {
                return getcpy(pwds);
+       }
 
        ep = pwds + strlen(pwds);
-       if ((cp = strrchr(pwds, '/')) == NULL)
+       if ((cp = strrchr(pwds, '/')) == NULL) {
                cp = ep;
-       else
-               if (cp == pwds)
-                       cp++;
+       } else if (cp == pwds)  {
+               cp++;
+       }
 
-       if (strncmp(name, CWD, NCWD) == 0)
-               name += NCWD;
+       if (strncmp(name, "./", 2) == 0) {
+               name += 2;
+       }
 
-       if (strcmp(name, DOTDOT) == 0 || strcmp(name, PWD) == 0) {
-               snprintf(buffer, sizeof(buffer), "%.*s", (int)(cp - pwds), pwds);
+       if (strcmp(name, "..") == 0 || strcmp(name, "../") == 0) {
+               snprintf(buffer, sizeof(buffer), "%.*s",
+                               (int)(cp - pwds), pwds);
                return getcpy(buffer);
        }
 
-       if (strncmp(name, PWD, NPWD) == 0)
-               name += NPWD;
-       else
+       if (strncmp(name, "../", 3) == 0) {
+               name += 3;
+       } else {
                cp = ep;
+       }
 
-       snprintf(buffer, sizeof(buffer), "%.*s/%s", (int)(cp - pwds), pwds, name);
+       snprintf(buffer, sizeof(buffer), "%.*s/%s",
+                       (int)(cp - pwds), pwds, name);
        return getcpy(buffer);
 }
 
 
+/*
+**  Compactify an absolute path name by removing unneccessary parts.
+**  Removes trailing slashes, but not if it would empty the string then.
+**  Modifies f.
+*/
 static void
-compath(char *f)
+packpath(char *f)
 {
-       register char *cp, *dp;
+       char *cp, *dp;
+       int abspath;
 
-       if (*f != '/')
+       if (!f || !*f) {
                return;
+       }
+       abspath = (*f == '/');
 
-       for (cp = f; *cp;)
-               if (*cp == '/') {
-                       switch (*++cp) {
-                               case 0:
-                                       if (--cp > f)
-                                               *cp = '\0';
-                                       break;
-
-                               case '/':
-                                       for (dp = cp; *dp == '/'; dp++)
-                                               continue;
-                                       strcpy (cp--, dp);
-                                       continue;
+       for (cp=f; *cp; ) {
+               if (*cp != '/') {
+                       /* Skip. Interesting places are only after slashes. */
+                       /* We don't care about "./" beginnings */
+                       cp++;
+                       continue;
+               }
 
-                               case '.':
-                                       if (strcmp(cp, DOT) == 0) {
-                                               if (cp > f + 1)
-                                                       cp--;
-                                               *cp = '\0';
-                                               break;
-                                       }
-                                       if (strcmp(cp, DOTDOT) == 0) {
-                                               for (cp -= 2; cp > f; cp--)
-                                                       if (*cp == '/')
-                                                               break;
-                                               if (cp <= f)
-                                                       cp = f + 1;
-                                               *cp = '\0';
-                                               break;
-                                       }
-                                       if (strncmp(cp, PWD, NPWD) == 0) {
-                                               for (dp = cp - 2; dp > f; dp--)
-                                                       if (*dp == '/')
-                                                               break;
-                                               if (dp <= f)
-                                                       dp = f;
-                                               strcpy(dp, cp + NPWD - 1);
-                                               cp = dp;
-                                               continue;
-                                       }
-                                       if (strncmp(cp, CWD, NCWD) == 0) {
-                                               strcpy(cp - 1, cp + NCWD - 1);
-                                               cp--;
-                                               continue;
-                                       }
-                                       continue;
+               /* Let's see what follows the slash ... */
+               switch (*++cp) {
+               case '\0':
+                       *--cp = '\0';
+                       continue;  /* ... and thus exit the loop */
 
-                               default:
-                                       cp++;
+               case '/':
+                       /* reduce subsequent slashes to one */
+                       for (dp = cp; *dp == '/'; dp++) {
+                               continue;
+                       }
+                       strcpy(cp, dp);
+                       cp--;
+                       continue;  /* ... at the slash */
+
+               case '.':
+                       if (cp[1] == '/' || cp[1] == '\0') {
+                               /* one-dot element */
+                               strcpy(cp-1, cp+1);
+                               cp--;
+                               continue;
+                       } else if ((strncmp(cp, "../", 3) == 0) ||
+                                       (strcmp(cp, "..") == 0)) {
+                               /* dot-dot element */
+                               /* crop out previous path element */
+                               for (dp=cp-2; dp>f && *dp!='/'; dp--) {
                                        continue;
+                               }
+                               if (dp < f) {
+                                       /* path starts with "/.." */
+                                       dp = f;
+                               }
+                               strcpy(dp, cp+2);
+                               cp = dp;
+                               continue;
+                       } else {
+                               /* a normal hidden file */
+                               cp++;
+                               continue;
                        }
-                       break;
-               } else
+
+               default:
+                       /* nothing special */
                        cp++;
+                       continue;
+               }
+       }
+
+       if (!strlen(f)) {
+               /* We have removed everything, but need something. */
+               strcpy(f, abspath ? "/" : ".");
+       }
 }