Index: runtests.sh
===================================================================
--- runtests.sh	(revision 5aa33fd73dce2c8d6c88559e62cd1ae78ef4a36d)
+++ runtests.sh	(revision 37ac3443e4be8b822ab13b34901c88bcb8ed375f)
@@ -5,3 +5,3 @@
 export BARNOWL_BIN_DIR="$SRCDIR/"
 
-HARNESS_PERL=./tester exec prove t/
+HARNESS_PERL=./tester exec prove --failures t/
Index: tester.c
===================================================================
--- tester.c	(revision b4a678ada6187f20944178fb74b7c3694d8b73cf)
+++ tester.c	(revision e073081359531d18526d96f0a9fd47aaede008b6)
@@ -4,6 +4,11 @@
 #undef WINDOW
 
+#include <errno.h>
 #include <unistd.h>
+#include <pwd.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
 
 #undef instr
@@ -124,5 +129,5 @@
 #define FAIL_UNLESS(desc,pred) do { int __pred = (pred);                \
     numtests++;                                                         \
-    printf("%s %s", (__pred)?"ok":(numfailed++,"not ok"), desc);        \
+    printf("%s %d %s", (__pred) ? "ok" : (numfailed++, "not ok"), numtests, desc); \
     if(!(__pred)) printf("\t(%s:%d)", __FILE__, __LINE__); printf("%c", '\n'); } while(0)
 
@@ -131,4 +136,7 @@
 {
   int numfailed=0;
+  const char *home;
+  char *s, *path;
+  struct passwd *pw;
 
   printf("# BEGIN testing owl_util\n");
@@ -225,4 +233,84 @@
   g_string_free(g, true);
 
+
+  s = owl_util_baseclass("barnowl");
+  FAIL_UNLESS("baseclass barnowl", !strcmp("barnowl", s));
+  g_free(s);
+  s = owl_util_baseclass("unbarnowl");
+  FAIL_UNLESS("baseclass unbarnowl", !strcmp("barnowl", s));
+  g_free(s);
+  s = owl_util_baseclass("unununbarnowl.d.d");
+  FAIL_UNLESS("baseclass unununbarnowl.d.d", !strcmp("barnowl", s));
+  g_free(s);
+  s = owl_util_baseclass("ununun.d.d");
+  FAIL_UNLESS("baseclass ununun.d.d", !strcmp("", s));
+  g_free(s);
+  s = owl_util_baseclass("d.d.d.d");
+  FAIL_UNLESS("baseclass d.d.d.d", !strcmp("d", s));
+  g_free(s);
+  s = owl_util_baseclass("n.d.d.d");
+  FAIL_UNLESS("baseclass n.d.d.d", !strcmp("n", s));
+  g_free(s);
+  s = owl_util_baseclass("ununun.");
+  FAIL_UNLESS("baseclass ununun.", !strcmp(".", s));
+  g_free(s);
+  s = owl_util_baseclass("unununu");
+  FAIL_UNLESS("baseclass unununu", !strcmp("u", s));
+  g_free(s);
+
+
+  s = owl_util_makepath("foo/bar");
+  FAIL_UNLESS("makepath foo/bar", !strcmp("foo/bar", s));
+  g_free(s);
+  s = owl_util_makepath("//foo///bar");
+  FAIL_UNLESS("makepath //foo///bar", !strcmp("/foo/bar", s));
+  g_free(s);
+  s = owl_util_makepath("foo/~//bar/");
+  FAIL_UNLESS("makepath foo/~//bar/", !strcmp("foo/~/bar/", s));
+  g_free(s);
+  s = owl_util_makepath("~thisuserhadreallybetternotexist/foobar/");
+  FAIL_UNLESS("makepath ~thisuserhadreallybetternotexist/foobar/",
+              !strcmp("~thisuserhadreallybetternotexist/foobar/", s));
+  g_free(s);
+
+  errno = 0;
+  pw = getpwuid(getuid());
+  if (pw) {
+    home = pw->pw_dir;
+  } else {
+    /* Just make some noise so we notice. */
+    home = "<WHAT>";
+    fprintf(stderr, "getpwuid: %s", errno ? strerror(errno) : "No such user");
+  }
+  s = owl_util_makepath("~");
+  FAIL_UNLESS("makepath ~", !strcmp(home, s));
+  g_free(s);
+
+  path = g_strconcat(home, "/foo/bar/baz", NULL);
+  s = owl_util_makepath("~///foo/bar//baz");
+  FAIL_UNLESS("makepath ~///foo/bar//baz", !strcmp(path, s));
+  g_free(s);
+  g_free(path);
+
+  errno = 0;
+  pw = getpwnam("root");
+  if (pw) {
+    home = pw->pw_dir;
+  } else {
+    /* Just make some noise so we notice. */
+    home = "<WHAT>";
+    fprintf(stderr, "getpwnam: %s", errno ? strerror(errno) : "No such user");
+  }
+
+  s = owl_util_makepath("~root");
+  FAIL_UNLESS("makepath ~root", !strcmp(home, s));
+  g_free(s);
+
+  path = g_strconcat(home, "/foo/bar/baz", NULL);
+  s = owl_util_makepath("~root///foo/bar//baz");
+  FAIL_UNLESS("makepath ~root///foo/bar//baz", !strcmp(path, s));
+  g_free(s);
+  g_free(path);
+
   /* if (numfailed) printf("*** WARNING: failures encountered with owl_util\n"); */
   printf("# END testing owl_util (%d failures)\n", numfailed);
Index: util.c
===================================================================
--- util.c	(revision b8a3e0025038d7a71f4d13206b772d904f95b8a0)
+++ util.c	(revision ffe1135a7340991647a3940a31aa55b00458da5c)
@@ -37,63 +37,42 @@
 CALLER_OWN char *owl_util_makepath(const char *in)
 {
-  int i, j, x;
-  char *out, user[MAXPATHLEN];
-  struct passwd *pw;
-
-  out=g_new(char, MAXPATHLEN+1);
-  out[0]='\0';
-  j=strlen(in);
-  x=0;
-  for (i=0; i<j; i++) {
-    if (in[i]=='~') {
-      if ( (i==(j-1)) ||          /* last character */
-	   (in[i+1]=='/') ) {     /* ~/ */
-	/* use my homedir */
-	pw=getpwuid(getuid());
-	if (!pw) {
-	  out[x]=in[i];
-	} else {
-	  out[x]='\0';
-	  strcat(out, pw->pw_dir);
-	  x+=strlen(pw->pw_dir);
-	}
-      } else {
-	/* another user homedir */
-	int a, b;
-	b=0;
-	for (a=i+1; i<j; a++) {
-	  if (in[a]==' ' || in[a]=='/') {
-	    break;
-	  } else {
-	    user[b]=in[a];
-	    i++;
-	    b++;
-	  }
-	}
-	user[b]='\0';
-	pw=getpwnam(user);
-	if (!pw) {
-	  out[x]=in[i];
-	} else {
-	  out[x]='\0';
-	  strcat(out, pw->pw_dir);
-	  x+=strlen(pw->pw_dir);
-	}
-      }
-    } else if (in[i]=='/') {
-      /* check for a double / */
-      if (i<(j-1) && (in[i+1]=='/')) {
-	/* do nothing */
-      } else {
-	out[x]=in[i];
-	x++;
-      }
+  char *out;
+  int i, j;
+  if (in[0] == '~') {
+    /* Attempt tilde-expansion of the first component. Get the
+       tilde-prefix, which goes up to the next slash. */
+    struct passwd *pw;
+    const char *end = strchr(in + 1, '/');
+    if (end == NULL)
+      end = in + strlen(in);
+
+    if (end == in + 1) {
+      /* My home directory. */
+      pw = getpwuid(getuid());
     } else {
-      out[x]=in[i];
-      x++;
-    }
-  }
-  out[x]='\0';
-  return(out);
+      /* Someone else's home directory. */
+      char *user = g_strndup(in + 1, end - (in + 1));
+      pw = getpwnam(user);
+      g_free(user);
+    }
+
+    /* Patch together a new path. Replace the ~ and tilde-prefix with
+       the homedir. */
+    if (pw) {
+      out = g_strconcat(pw->pw_dir, end, NULL);
+    } else {
+      out = g_strdup(in);
+    }
+  } else {
+      out = g_strdup(in);
+  }
+
+  /* And a quick pass to remove duplicate slashes. */
+  for (i = j = 0; out[i] != '\0'; i++) {
+    if (out[i] != '/' || i == 0 || out[i-1] != '/')
+      out[j++] = out[i];
+  }
+  out[j] = '\0';
+  return out;
 }
 
