Code

moving trunk for module inkscape
[inkscape.git] / src / dir-util.cpp
1 /** \file Some utility functions for filenames. */
3 #define DIR_UTIL_C
5 #include <errno.h>
6 #include <string.h>
7 #include <glib/gutils.h>
8 #include <glib/gmem.h>
9 #include <glib/gerror.h>
10 #include <glib/gconvert.h>
11 #include <glib/gstrfuncs.h>
13 /** Returns a form of \a path relative to \a base if that is easy to construct (e.g. if \a path
14     appears to be in the directory specified by \a base), otherwise returns \a path.
16     N.B. The return value is a pointer into the \a path string.
18     \a base is expected to be either NULL or the absolute path of a directory.
20     \a path is expected to be an absolute path.
22     \see inkscape_abs2rel for a more sophisticated version.
23     \see prepend_current_dir_if_relative.
24 */
25 char const *
26 sp_relative_path_from_path(char const *const path, char const *const base)
27 {
28         if (base == NULL || path == NULL) {
29                 return path;
30         }
32         size_t base_len = strlen(base);
33         while (base_len != 0
34                && (base[base_len - 1] == G_DIR_SEPARATOR))
35         {
36                 --base_len;
37         }
39         if ((memcmp(path, base, base_len) == 0)
40             && (path[base_len] == G_DIR_SEPARATOR))
41         {
42                 char const *ret = path + base_len + 1;
43                 while (*ret == G_DIR_SEPARATOR) {
44                         ++ret;
45                 }
46                 if (*ret != '\0') {
47                         return ret;
48                 }
49         }
51         return path;
52 }
54 char const *
55 sp_extension_from_path(char const *const path)
56 {
57         if (path == NULL) {
58                 return NULL;
59         }
61         char const *p = path;
62         while (*p != '\0') p++;
64         while ((p >= path) && (*p != G_DIR_SEPARATOR) && (*p != '.')) p--;
65         if (* p != '.') return NULL;
66         p++;
68         return p;
69 }
72 /* current == "./", parent == "../" */
73 static char const dots[] = {'.', '.', G_DIR_SEPARATOR, '\0'};
74 static char const *const parent = dots;
75 static char const *const current = dots + 1;
77 /**
78  * \brief   Convert a relative path name into absolute. If path is already absolute, does nothing except copying path to result.
79  *
80  *      \param path     relative path
81  *      \param base     base directory (must be absolute path)
82  *      \param result   result buffer
83  *      \param size     size of result buffer
84  *      \return         != NULL: absolute path
85  *                      == NULL: error
87 \comment
88  based on functions by Shigio Yamaguchi.
89  FIXME:TODO: force it to also do path normalization of the entire resulting path, 
90  i.e. get rid of any .. and . in any place, even if 'path' is already absolute 
91  (now it returns it unchanged in this case)
93  */
94 char *
95 inkscape_rel2abs (const char *path, const char *base, char *result, const size_t size)
96 {
97   const char *pp, *bp;
98   /* endp points the last position which is safe in the result buffer. */
99   const char *endp = result + size - 1;
100   char *rp;
101   int length;
102   if (*path == G_DIR_SEPARATOR)
103     {
104       if (strlen (path) >= size)
105         goto erange;
106         strcpy (result, path);
107         goto finish;
108     }
109   else if (*base != G_DIR_SEPARATOR || !size)
110     {
111       errno = EINVAL;
112       return (NULL);
113     }
114   else if (size == 1)
115     goto erange;
116   if (!strcmp (path, ".") || !strcmp (path, current))
117     {
118       if (strlen (base) >= size)
119         goto erange;
120       strcpy (result, base);
121       /* rp points the last char. */
122       rp = result + strlen (base) - 1;
123       if (*rp == G_DIR_SEPARATOR)
124         *rp = 0;
125       else
126         rp++;
127       /* rp point NULL char */
128       if (*++path == G_DIR_SEPARATOR)
129         {
130           /* Append G_DIR_SEPARATOR to the tail of path name. */
131           *rp++ = G_DIR_SEPARATOR;
132           if (rp > endp)
133             goto erange;
134           *rp = 0;
135         }
136       goto finish;
137     }
138   bp = base + strlen (base);
139   if (*(bp - 1) == G_DIR_SEPARATOR)
140     --bp;
141   /* up to root. */
142   for (pp = path; *pp && *pp == '.';)
143     {
144       if (!strncmp (pp, parent, 3))
145         {
146           pp += 3;
147           while (bp > base && *--bp != G_DIR_SEPARATOR)
148             ;
149         }
150       else if (!strncmp (pp, current, 2))
151         {
152           pp += 2;
153         }
154       else if (!strncmp (pp, "..\0", 3))
155         {
156           pp += 2;
157           while (bp > base && *--bp != G_DIR_SEPARATOR)
158             ;
159         }
160       else
161         break;
162     }
163   /* down to leaf. */
164   length = bp - base;
165   if (length >= static_cast<int>(size))
166     goto erange;
167   strncpy (result, base, length);
168   rp = result + length;
169   if (*pp || *(pp - 1) == G_DIR_SEPARATOR || length == 0)
170     *rp++ = G_DIR_SEPARATOR;
171   if (rp + strlen (pp) > endp)
172     goto erange;
173   strcpy (rp, pp);
174 finish:
175   return result;
176 erange:
177   errno = ERANGE;
178   return (NULL);
181 char *
182 inkscape_abs2rel (const char *path, const char *base, char *result, const size_t size)
184   const char *pp, *bp, *branch;
185   /* endp points the last position which is safe in the result buffer. */
186   const char *endp = result + size - 1;
187   char *rp;
189   if (*path != G_DIR_SEPARATOR)
190     {
191       if (strlen (path) >= size)
192         goto erange;
193       strcpy (result, path);
194       goto finish;
195     }
196   else if (*base != G_DIR_SEPARATOR || !size)
197     {
198       errno = EINVAL;
199       return (NULL);
200     }
201   else if (size == 1)
202     goto erange;
203   /* seek to branched point. */
204   branch = path;
205   for (pp = path, bp = base; *pp && *bp && *pp == *bp; pp++, bp++)
206     if (*pp == G_DIR_SEPARATOR)
207       branch = pp;
208   if ((*pp == 0 || *pp == G_DIR_SEPARATOR && *(pp + 1) == 0) &&
209       (*bp == 0 || *bp == G_DIR_SEPARATOR && *(bp + 1) == 0))
210     {
211       rp = result;
212       *rp++ = '.';
213       if (*pp == G_DIR_SEPARATOR || *(pp - 1) == G_DIR_SEPARATOR)
214         *rp++ = G_DIR_SEPARATOR;
215       if (rp > endp)
216         goto erange;
217       *rp = 0;
218       goto finish;
219     }
220   if (*pp == 0 && *bp == G_DIR_SEPARATOR || *pp == G_DIR_SEPARATOR && *bp == 0)
221     branch = pp;
222   /* up to root. */
223   rp = result;
224   for (bp = base + (branch - path); *bp; bp++)
225     if (*bp == G_DIR_SEPARATOR && *(bp + 1) != 0)
226       {
227         if (rp + 3 > endp)
228           goto erange;
229         *rp++ = '.';
230         *rp++ = '.';
231         *rp++ = G_DIR_SEPARATOR;
232       }
233   if (rp > endp)
234     goto erange;
235   *rp = 0;
236   /* down to leaf. */
237   if (*branch)
238     {
239       if (rp + strlen (branch + 1) > endp)
240         goto erange;
241       strcpy (rp, branch + 1);
242     }
243   else
244     *--rp = 0;
245 finish:
246   return result;
247 erange:
248   errno = ERANGE;
249   return (NULL);
252 void
253 prepend_current_dir_if_relative (char **result, const gchar *uri)
255         if (!uri) {
256                 *(result) = NULL;
257                 return;
258         }
260         char *full_path = (char *) g_malloc (1001);
261         char *cwd = g_get_current_dir();
263         gsize bytesRead = 0;
264         gsize bytesWritten = 0;
265         GError* error = NULL;
266         gchar* cwd_utf8 = g_filename_to_utf8 ( cwd,
267                                                   -1,
268                                                   &bytesRead,
269                                                   &bytesWritten,
270                                                   &error);
272         inkscape_rel2abs (uri, cwd_utf8, full_path, 1000);
273         *(result) = g_strdup (full_path);
274         g_free (full_path);
275         g_free (cwd);