always store full path in memory. Transform should happend only on project load
[geanyprj.git] / utils.c
blobfb6054e4fe8a204f73352c516c4974e24bc198f5
1 /*
2 * Copyright 2008 Yura Siamashka <yurand2@gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <string.h>
20 #include <glib.h>
22 #include "geany.h"
23 #include "plugindata.h"
24 #include "pluginmacros.h"
25 #include "utils.h"
27 extern GeanyData *geany_data;
30 gchar *
31 find_file_path(const gchar * dir, const gchar * filename)
33 gboolean ret = FALSE;
34 gchar *base;
35 gchar *gitdir = NULL;
36 gchar *base_prev = g_strdup(":");
38 base = g_strdup(dir);
40 while (strcmp(base, base_prev) != 0)
42 gitdir = g_build_path("/", base, filename, NULL);
43 ret = g_file_test(gitdir, G_FILE_TEST_IS_REGULAR);
44 if (ret)
46 g_free(base_prev);
47 g_free(base);
48 return gitdir;
50 g_free(gitdir);
51 g_free(base_prev);
52 base_prev = base;
53 base = g_path_get_dirname(base);
56 g_free(base_prev);
57 g_free(base);
58 return NULL;
61 /* Normalize a pathname. This collapses redundant separators and up-level references so that A//B, A/./B
62 * and A/foo/../B all become A/B. It does not normalize the case. On Windows, it converts forward
63 * slashes to backward slashes. It should be understood that this may change the meaning of the
64 * path if it contains symbolic links!
66 gchar *
67 normpath(const gchar * filename)
69 gchar **v;
70 gchar **p;
71 gchar **out;
72 gchar **pout;
73 gchar *ret;
75 if (!filename || strlen(filename) == 0)
76 return g_strdup(".");
77 v = g_strsplit_set(filename, "/\\", -1);
78 if (!g_strv_length(v))
79 return g_strdup(".");
81 out = g_malloc0(sizeof(gchar *) * (g_strv_length(v) + 2));
82 pout = out;
84 if (filename[0] == '.' && strcmp(v[0], ".") == 0)
86 *pout = strdup(".");
87 pout++;
89 else if (filename[0] == '/')
91 *pout = strdup("/");
92 pout++;
95 for (p = v; *p; p++)
97 if (strcmp(*p, ".") == 0 || strcmp(*p, "") == 0)
99 continue;
101 else if (strcmp(*p, "..") == 0)
103 if (pout != out)
105 pout--;
106 if (strcmp(*pout, "..") != 0)
108 g_free(*pout);
109 *pout = NULL;
110 continue;
112 pout++;
115 *pout++ = g_strdup(*p);
118 ret = g_build_filenamev(out);
120 g_strfreev(out);
121 g_strfreev(v);
122 return ret;
125 gchar *
126 get_full_path(const gchar * location, const gchar * path)
128 gchar *dir;
130 dir = g_path_get_dirname(location);
131 setptr(dir, g_build_filename(dir, path, NULL));
132 setptr(dir, normpath(dir));
133 return dir;
136 gchar *
137 get_relative_path(const gchar * location, const gchar * path)
139 gchar *dir;
140 gint plen;
141 gint dlen;
143 if (!g_path_is_absolute(path))
145 return g_strdup(path);
148 dir = g_path_get_dirname(location);
149 setptr(dir, normpath(dir));
151 plen = strlen(path);
152 dlen = strlen(dir);
154 if (strstr(path, dir) == path)
156 if (plen > dlen)
158 setptr(dir, g_strdup(path + strlen(dir) + 1));
159 return dir;
161 else if (plen == dlen)
163 return g_strdup("./");
166 g_free(dir);
167 return NULL;
170 void
171 save_config(GKeyFile * config, const gchar * path)
173 gchar *data = g_key_file_to_data(config, NULL, NULL);
174 p_utils->write_file(path, data);
175 g_free(data);
178 gint
179 config_length(GKeyFile * config, const gchar * section, const gchar * name)
181 gchar *key;
182 gint i = 0;
184 key = g_strdup_printf("%s%d", name, i);
185 while (g_key_file_has_key(config, section, key, NULL))
187 i++;
188 g_free(key);
189 key = g_strdup_printf("%s%d", name, i);
191 g_free(key);
192 return i;
196 /* Gets a list of files from the specified directory.
197 * Locale encoding is expected for path and used for the file list.
198 * The list and the data in the list should be freed after use.
199 * Returns: The list or NULL if no files found.
200 * length will point to the number of non-NULL data items in the list, unless NULL.
201 * error is the location for storing a possible error, or NULL. */
202 GSList *
203 get_file_list(const gchar * path, guint * length, gboolean(*func) (const gchar *), GError ** error)
205 GSList *list = NULL;
206 guint len = 0;
207 GDir *dir;
208 gchar *filename;
209 gchar *abs_path;
211 if (error)
212 *error = NULL;
213 if (length)
214 *length = 0;
215 g_return_val_if_fail(path != NULL, NULL);
217 if (g_path_is_absolute(path))
219 abs_path = g_strdup(path);
221 else
223 abs_path = g_get_current_dir();
224 setptr(abs_path, g_build_filename(abs_path, path, NULL));
226 dir = g_dir_open(abs_path, 0, error);
227 if (dir == NULL)
229 g_free(abs_path);
230 return NULL;
233 while (1)
235 const gchar *name = g_dir_read_name(dir);
236 if (name == NULL)
237 break;
239 filename = g_build_filename(abs_path, name, NULL);
241 if (g_file_test(filename, G_FILE_TEST_IS_DIR))
243 guint l;
244 GError *err;
245 GSList *lst = get_file_list(filename, &l, func, &err);
246 if (err != NULL)
248 *error = err;
249 g_slist_foreach(list, (GFunc) g_free, NULL);
250 g_slist_free(list);
251 g_free(filename);
252 g_free(abs_path);
253 return NULL;
255 g_free(filename);
256 list = g_slist_concat(list, lst);
257 len += l;
259 else
261 if (!func || func(filename))
263 list = g_slist_prepend(list, filename);
264 len++;
266 else
268 g_free(filename);
272 g_dir_close(dir);
273 g_free(abs_path);
275 if (length)
276 *length = len;
277 return list;