summaryrefslogtreecommitdiffstats
path: root/src/dir-util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dir-util.cpp')
-rw-r--r--src/dir-util.cpp278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/dir-util.cpp b/src/dir-util.cpp
new file mode 100644
index 000000000..b83eec002
--- /dev/null
+++ b/src/dir-util.cpp
@@ -0,0 +1,278 @@
+/** \file Some utility functions for filenames. */
+
+#define DIR_UTIL_C
+
+#include <errno.h>
+#include <string.h>
+#include <glib/gutils.h>
+#include <glib/gmem.h>
+#include <glib/gerror.h>
+#include <glib/gconvert.h>
+#include <glib/gstrfuncs.h>
+
+/** Returns a form of \a path relative to \a base if that is easy to construct (e.g. if \a path
+ appears to be in the directory specified by \a base), otherwise returns \a path.
+
+ N.B. The return value is a pointer into the \a path string.
+
+ \a base is expected to be either NULL or the absolute path of a directory.
+
+ \a path is expected to be an absolute path.
+
+ \see inkscape_abs2rel for a more sophisticated version.
+ \see prepend_current_dir_if_relative.
+*/
+char const *
+sp_relative_path_from_path(char const *const path, char const *const base)
+{
+ if (base == NULL || path == NULL) {
+ return path;
+ }
+
+ size_t base_len = strlen(base);
+ while (base_len != 0
+ && (base[base_len - 1] == G_DIR_SEPARATOR))
+ {
+ --base_len;
+ }
+
+ if ((memcmp(path, base, base_len) == 0)
+ && (path[base_len] == G_DIR_SEPARATOR))
+ {
+ char const *ret = path + base_len + 1;
+ while (*ret == G_DIR_SEPARATOR) {
+ ++ret;
+ }
+ if (*ret != '\0') {
+ return ret;
+ }
+ }
+
+ return path;
+}
+
+char const *
+sp_extension_from_path(char const *const path)
+{
+ if (path == NULL) {
+ return NULL;
+ }
+
+ char const *p = path;
+ while (*p != '\0') p++;
+
+ while ((p >= path) && (*p != G_DIR_SEPARATOR) && (*p != '.')) p--;
+ if (* p != '.') return NULL;
+ p++;
+
+ return p;
+}
+
+
+/* current == "./", parent == "../" */
+static char const dots[] = {'.', '.', G_DIR_SEPARATOR, '\0'};
+static char const *const parent = dots;
+static char const *const current = dots + 1;
+
+/**
+ * \brief Convert a relative path name into absolute. If path is already absolute, does nothing except copying path to result.
+ *
+ * \param path relative path
+ * \param base base directory (must be absolute path)
+ * \param result result buffer
+ * \param size size of result buffer
+ * \return != NULL: absolute path
+ * == NULL: error
+
+\comment
+ based on functions by Shigio Yamaguchi.
+ FIXME:TODO: force it to also do path normalization of the entire resulting path,
+ i.e. get rid of any .. and . in any place, even if 'path' is already absolute
+ (now it returns it unchanged in this case)
+
+ */
+char *
+inkscape_rel2abs (const char *path, const char *base, char *result, const size_t size)
+{
+ const char *pp, *bp;
+ /* endp points the last position which is safe in the result buffer. */
+ const char *endp = result + size - 1;
+ char *rp;
+ int length;
+ if (*path == G_DIR_SEPARATOR)
+ {
+ if (strlen (path) >= size)
+ goto erange;
+ strcpy (result, path);
+ goto finish;
+ }
+ else if (*base != G_DIR_SEPARATOR || !size)
+ {
+ errno = EINVAL;
+ return (NULL);
+ }
+ else if (size == 1)
+ goto erange;
+ if (!strcmp (path, ".") || !strcmp (path, current))
+ {
+ if (strlen (base) >= size)
+ goto erange;
+ strcpy (result, base);
+ /* rp points the last char. */
+ rp = result + strlen (base) - 1;
+ if (*rp == G_DIR_SEPARATOR)
+ *rp = 0;
+ else
+ rp++;
+ /* rp point NULL char */
+ if (*++path == G_DIR_SEPARATOR)
+ {
+ /* Append G_DIR_SEPARATOR to the tail of path name. */
+ *rp++ = G_DIR_SEPARATOR;
+ if (rp > endp)
+ goto erange;
+ *rp = 0;
+ }
+ goto finish;
+ }
+ bp = base + strlen (base);
+ if (*(bp - 1) == G_DIR_SEPARATOR)
+ --bp;
+ /* up to root. */
+ for (pp = path; *pp && *pp == '.';)
+ {
+ if (!strncmp (pp, parent, 3))
+ {
+ pp += 3;
+ while (bp > base && *--bp != G_DIR_SEPARATOR)
+ ;
+ }
+ else if (!strncmp (pp, current, 2))
+ {
+ pp += 2;
+ }
+ else if (!strncmp (pp, "..\0", 3))
+ {
+ pp += 2;
+ while (bp > base && *--bp != G_DIR_SEPARATOR)
+ ;
+ }
+ else
+ break;
+ }
+ /* down to leaf. */
+ length = bp - base;
+ if (length >= static_cast<int>(size))
+ goto erange;
+ strncpy (result, base, length);
+ rp = result + length;
+ if (*pp || *(pp - 1) == G_DIR_SEPARATOR || length == 0)
+ *rp++ = G_DIR_SEPARATOR;
+ if (rp + strlen (pp) > endp)
+ goto erange;
+ strcpy (rp, pp);
+finish:
+ return result;
+erange:
+ errno = ERANGE;
+ return (NULL);
+}
+
+char *
+inkscape_abs2rel (const char *path, const char *base, char *result, const size_t size)
+{
+ const char *pp, *bp, *branch;
+ /* endp points the last position which is safe in the result buffer. */
+ const char *endp = result + size - 1;
+ char *rp;
+
+ if (*path != G_DIR_SEPARATOR)
+ {
+ if (strlen (path) >= size)
+ goto erange;
+ strcpy (result, path);
+ goto finish;
+ }
+ else if (*base != G_DIR_SEPARATOR || !size)
+ {
+ errno = EINVAL;
+ return (NULL);
+ }
+ else if (size == 1)
+ goto erange;
+ /* seek to branched point. */
+ branch = path;
+ for (pp = path, bp = base; *pp && *bp && *pp == *bp; pp++, bp++)
+ if (*pp == G_DIR_SEPARATOR)
+ branch = pp;
+ if ((*pp == 0 || *pp == G_DIR_SEPARATOR && *(pp + 1) == 0) &&
+ (*bp == 0 || *bp == G_DIR_SEPARATOR && *(bp + 1) == 0))
+ {
+ rp = result;
+ *rp++ = '.';
+ if (*pp == G_DIR_SEPARATOR || *(pp - 1) == G_DIR_SEPARATOR)
+ *rp++ = G_DIR_SEPARATOR;
+ if (rp > endp)
+ goto erange;
+ *rp = 0;
+ goto finish;
+ }
+ if (*pp == 0 && *bp == G_DIR_SEPARATOR || *pp == G_DIR_SEPARATOR && *bp == 0)
+ branch = pp;
+ /* up to root. */
+ rp = result;
+ for (bp = base + (branch - path); *bp; bp++)
+ if (*bp == G_DIR_SEPARATOR && *(bp + 1) != 0)
+ {
+ if (rp + 3 > endp)
+ goto erange;
+ *rp++ = '.';
+ *rp++ = '.';
+ *rp++ = G_DIR_SEPARATOR;
+ }
+ if (rp > endp)
+ goto erange;
+ *rp = 0;
+ /* down to leaf. */
+ if (*branch)
+ {
+ if (rp + strlen (branch + 1) > endp)
+ goto erange;
+ strcpy (rp, branch + 1);
+ }
+ else
+ *--rp = 0;
+finish:
+ return result;
+erange:
+ errno = ERANGE;
+ return (NULL);
+}
+
+void
+prepend_current_dir_if_relative (char **result, const gchar *uri)
+{
+ if (!uri) {
+ *(result) = NULL;
+ return;
+ }
+
+ char *full_path = (char *) g_malloc (1001);
+ char *cwd = g_get_current_dir();
+
+ gsize bytesRead = 0;
+ gsize bytesWritten = 0;
+ GError* error = NULL;
+ gchar* cwd_utf8 = g_filename_to_utf8 ( cwd,
+ -1,
+ &bytesRead,
+ &bytesWritten,
+ &error);
+
+ inkscape_rel2abs (uri, cwd_utf8, full_path, 1000);
+ *(result) = g_strdup (full_path);
+ g_free (full_path);
+ g_free (cwd);
+}
+
+