diff lib/lib.c @ 707:977e19296b3f

Update readlink so -f works. Add -menq while there.
author Rob Landley <rob@landley.net>
date Tue, 20 Nov 2012 09:21:52 -0600
parents 078138791b5c
children 50d759f8b371
line wrap: on
line diff
--- a/lib/lib.c	Tue Nov 20 01:00:17 2012 -0600
+++ b/lib/lib.c	Tue Nov 20 09:21:52 2012 -0600
@@ -323,52 +323,37 @@
   if(stat(path, st)) perror_exit("Can't stat %s", path);
 }
 
-// Cannonicalizes path by removing ".", "..", and "//" elements.  This is not
-// the same as realpath(), where "dir/.." could wind up somewhere else by
-// following symlinks.
-char *xabspath(char *path)
+// Cannonicalize path, even to file with one or more missing components at end
+char *xabspath(char *path, unsigned missing) 
 {
-  char *from, *to;
+  char *apath, *temp, *slash;
+  int i=0;
 
   // If this isn't an absolute path, make it one with cwd.
   if (path[0]!='/') {
-    char *cwd=xgetcwd();
-    path = xmsprintf("%s/%s", cwd, path);
-    free(cwd);
-  } else path = xstrdup(path);
-
-  // Loop through path elements
-  from = to = path;
-  while (*from) {
-
-    // Continue any current path component.
-    if (*from!='/') {
-      *(to++) = *(from++);
-      continue;
-    }
-
-    // Skip duplicate slashes.
-    while (*from=='/') from++;
+    char *temp=xgetcwd();
+    apath = xmsprintf("%s/%s", temp, path);
+    free(temp);
+  } else apath = path;
+  slash = apath+strlen(apath);
 
-    // Start of a new filename.  Handle . and ..
-    while (*from=='.') {
-      // Skip .
-      if (from[1]=='/') from += 2;
-      else if (!from[1]) from++;
-      // Back up for ..
-      else if (from[1]=='.') {
-        if (from[2]=='/') from +=3;
-        else if(!from[2]) from+=2;
-        else break;
-        while (to>path && *(--to)!='/');
-      } else break;
-    }
-    // Add directory separator slash.
-    *(to++) = '/';
+  for (;;) {
+    temp = realpath(apath, NULL);
+    if (i) *slash = '/';
+    if (temp || ++i > missing) break;
+    while (slash>apath) if (*--slash == '/') break;
+    *slash=0;
+    free(temp);
   }
-  *to = 0;
 
-  return path;
+  if (i && temp) {
+    slash = xmsprintf("%s%s", temp, slash);
+    free(temp);
+    temp = slash;
+  }
+
+  if (path != apath) free(apath); 
+  return temp;
 }
 
 // Resolve all symlinks, returning malloc() memory.