chiark / gitweb /
Memory management for hands-off reader
[disorder] / lib / filepart.c
index c080b4d033beb914f22a433e177b05d0b4aa774a..20889afce4ed9f5b759d07ce35a40132da7bfda1 100644 (file)
  * This file is part of DisOrder
  * Copyright (C) 2005, 2007 Richard Kettlewell
  *
- * This program is free software; you can redistribute it and/or modify
+ * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 /** @file lib/filepart.c
  * @brief Filename parsing
  */
 
-#include <config.h>
-#include "types.h"
-
-#include <string.h>
+#include "common.h"
 
 #include "filepart.h"
 #include "mem.h"
 
+/** @brief Parse a filename
+ * @param path Filename to parse
+ * @param dirnamep Where to put directory name, or NULL
+ * @param basenamep Where to put basename, or NULL
+ */
+static void parse_filename(const char *path,
+                           char **dirnamep,
+                           char **basenamep) {
+  const char *s, *e = path + strlen(path);
+
+  /* Strip trailing slashes.  We never take these into account. */
+  while(e > path && e[-1] == '/')
+    --e;
+  if(e == path) {
+    /* The path is empty or contains only slashes */
+    if(*path) {
+      if(dirnamep)
+        *dirnamep = xstrdup("/");
+      if(basenamep)
+        *basenamep = xstrdup("/");
+    } else {
+      if(dirnamep)
+        *dirnamep = xstrdup("");
+      if(basenamep)
+        *basenamep = xstrdup("");
+    }
+  } else {
+    /* The path isn't empty and has more than just slashes.  e therefore now
+     * points at the end of the basename. */
+    s = e;
+    while(s > path && s[-1] != '/')
+      --s;
+    /* Now s points at the start of the basename */
+    if(basenamep)
+      *basenamep = xstrndup(s, e - s);
+    if(s > path) {
+      --s;
+      /* s must now be pointing at a '/' before the basename */
+      assert(*s == '/');
+      while(s > path && s[-1] == '/')
+        --s;
+      /* Now s must be pointing at the last '/' after the dirname */
+      assert(*s == '/');
+      if(s == path) {
+        /* If we reached the start we must be at the root */
+        if(dirnamep)
+          *dirnamep = xstrdup("/");
+      } else {
+        /* There's more than just the root here */
+        if(dirnamep)
+          *dirnamep = xstrndup(path, s - path);
+      }
+    } else {
+      /* There wasn't a slash */
+      if(dirnamep)
+        *dirnamep = xstrdup(".");
+    }
+  }
+}
+
 /** @brief Return the directory part of @p path
  * @param path Path to parse
  * @return Directory part of @p path
  *
  * Extracts the directory part of @p path.  This is a simple lexical
  * transformation and no canonicalization is performed.  The result will only
- * ever end "/" if it is the root directory.
+ * ever end "/" if it is the root directory.  The result will be "." if there
+ * is no directory part.
  */
 char *d_dirname(const char *path) {
-  const char *s;
+  char *d = 0;
 
-  if((s = strrchr(path, '/'))) {
-    while(s > path && s[-1] == '/')
-      --s;
-    if(s == path)
-      return xstrdup("/");
-    else
-      return xstrndup(path, s - path);
-  } else
-    return xstrdup(".");
+  parse_filename(path, &d, 0);
+  assert(d != 0);
+  return d;
+}
+
+/** @brief Return the basename part of @p path
+ * @param path Path to parse
+ * @return Base part of @p path
+ *
+ * Extracts the base part of @p path.  This is a simple lexical transformation
+ * and no canonicalization is performed.  The result is always newly allocated
+ * even if compares equal to @p path.
+ */
+char *d_basename(const char *path) {
+  char *b = 0;
+
+  parse_filename(path, 0, &b);
+  assert(b != 0);
+  return b;
 }
 
 /** @brief Find the extension part of @p path