+/** @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(".");
+ }
+ }
+}
+