r5123 | ntrel | 2010-08-10 17:12:24 +0100 (Tue, 10 Aug 2010) | 4 lines
[geany-mirror.git] / tagmanager / tm_file_entry.c
blob881ee9485ae7faea77bcc61c63884e5e288fcb76
1 /*
3 * Copyright (c) 2001-2002, Biswapesh Chattopadhyay
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 */
10 #include "general.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <dirent.h>
17 #ifdef HAVE_FCNTL_H
18 # include <fcntl.h>
19 #endif
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #ifdef HAVE_FNMATCH_H
23 # include <fnmatch.h>
24 #endif
25 #include <glib/gstdio.h>
27 #include "tm_work_object.h"
28 #include "tm_file_entry.h"
31 #if GLIB_CHECK_VERSION (2, 10, 0)
32 /* Use GSlices if present */
34 #define FILE_NEW(T) ((T) = g_slice_new0(TMFileEntry))
35 #define FILE_FREE(T) g_slice_free(TMFileEntry, (T))
37 #else /* GLib < 2.10 */
39 static GMemChunk *file_mem_chunk = NULL;
41 #define FILE_NEW(T) {\
42 if (!file_mem_chunk) \
43 file_mem_chunk = g_mem_chunk_new("TMFileEntry MemChunk", sizeof(TMFileEntry), 1024 \
44 , G_ALLOC_AND_FREE); \
45 (T) = g_chunk_new0(TMFileEntry, file_mem_chunk);}
47 #define FILE_FREE(T) g_mem_chunk_free(file_mem_chunk, (T))
49 #endif /* GLib version check */
52 void tm_file_entry_print(TMFileEntry *entry, gpointer __unused__ user_data
53 , guint level)
55 guint i;
57 g_return_if_fail(entry);
58 for (i=0; i < level; ++i)
59 fputc('\t', stderr);
60 fprintf(stderr, "%s\n", entry->name);
63 gint tm_file_entry_compare(TMFileEntry *e1, TMFileEntry *e2)
65 g_return_val_if_fail(e1 && e2 && e1->name && e2->name, 0);
66 #ifdef TM_DEBUG
67 g_message("Comparing %s and %s", e1->name, e2->name);
68 #endif
69 return strcmp(e1->name, e2->name);
72 /* TTimo - modified to handle symlinks */
73 static TMFileType tm_file_entry_type(const char *path)
75 struct stat s;
77 #ifndef G_OS_WIN32
78 if (0 != g_lstat(path, &s))
79 return tm_file_unknown_t;
80 #endif
81 if S_ISDIR(s.st_mode)
82 return tm_file_dir_t;
83 #ifndef G_OS_WIN32
84 else if (S_ISLNK(s.st_mode))
85 return tm_file_link_t;
86 #endif
87 else if S_ISREG(s.st_mode)
88 return tm_file_regular_t;
89 else
90 return tm_file_unknown_t;
93 static gboolean apply_filter(const char *name, GList *match, GList *unmatch
94 , gboolean ignore_hidden)
96 GList *tmp;
97 gboolean matched = (match == NULL);
98 g_return_val_if_fail(name, FALSE);
99 if (ignore_hidden && ('.' == name[0]))
100 return FALSE;
101 /* TTimo - ignore .svn directories */
102 if (!strcmp(name, ".svn"))
103 return FALSE;
104 for (tmp = match; tmp; tmp = g_list_next(tmp))
106 if (0 == fnmatch((char *) tmp->data, name, 0))
108 matched = TRUE;
109 break;
112 if (!matched)
113 return FALSE;
114 for (tmp = unmatch; tmp; tmp = g_list_next(tmp))
116 if (0 == fnmatch((char *) tmp->data, name, 0))
118 return FALSE;
121 return matched;
124 TMFileEntry *tm_file_entry_new(const char *path, TMFileEntry *parent
125 , gboolean recurse, GList *file_match, GList *file_unmatch
126 , GList *dir_match, GList *dir_unmatch, gboolean ignore_hidden_files
127 , gboolean ignore_hidden_dirs)
129 TMFileEntry *entry;
130 /* GList *tmp; */
131 char *real_path;
132 DIR *dir;
133 struct dirent *dir_entry;
134 TMFileEntry *new_entry;
135 char *file_name;
136 struct stat s;
137 char *entries = NULL;
139 g_return_val_if_fail (path != NULL, NULL);
141 /* TTimo - don't follow symlinks */
142 if (tm_file_entry_type(path) == tm_file_link_t)
143 return NULL;
144 real_path = tm_get_real_path(path);
145 if (!real_path)
146 return NULL;
147 FILE_NEW(entry);
148 entry->type = tm_file_entry_type(real_path);
149 entry->parent = parent;
150 entry->path = real_path;
151 entry->name = strrchr(entry->path, '/');
152 if (entry->name)
153 ++ (entry->name);
154 else
155 entry->name = entry->path;
156 switch(entry->type)
158 case tm_file_unknown_t:
159 g_free(real_path);
160 FILE_FREE(entry);
161 return NULL;
162 case tm_file_link_t:
163 case tm_file_regular_t:
164 if (parent && !apply_filter(entry->name, file_match, file_unmatch
165 , ignore_hidden_files))
167 tm_file_entry_free(entry);
168 return NULL;
170 break;
171 case tm_file_dir_t:
172 if (parent && !(recurse && apply_filter(entry->name, dir_match
173 , dir_unmatch, ignore_hidden_dirs)))
175 tm_file_entry_free(entry);
176 return NULL;
178 file_name = g_strdup_printf("%s/CVS/Entries", entry->path);
179 if (0 == g_stat(file_name, &s))
181 if (S_ISREG(s.st_mode))
183 int fd;
184 entries = g_new(char, s.st_size + 2);
185 if (0 > (fd = open(file_name, O_RDONLY)))
187 g_free(entries);
188 entries = NULL;
190 else
192 off_t n =0;
193 off_t total_read = 1;
194 while (0 < (n = read(fd, entries + total_read, s.st_size - total_read)))
195 total_read += n;
196 entries[s.st_size] = '\0';
197 entries[0] = '\n';
198 close(fd);
199 entry->version = g_strdup("D");
203 g_free(file_name);
204 if (NULL != (dir = opendir(entry->path)))
206 while (NULL != (dir_entry = readdir(dir)))
208 if ((0 == strcmp(dir_entry->d_name, "."))
209 || (0 == strcmp(dir_entry->d_name, "..")))
210 continue;
211 file_name = g_strdup_printf("%s/%s", entry->path, dir_entry->d_name);
212 new_entry = tm_file_entry_new(file_name, entry, recurse
213 , file_match, file_unmatch, dir_match, dir_unmatch
214 , ignore_hidden_files, ignore_hidden_dirs);
215 g_free(file_name);
216 if (new_entry)
218 if (entries)
220 char *str = g_strconcat("\n/", new_entry->name, "/", NULL);
221 char *name_pos = strstr(entries, str);
222 if (NULL != name_pos)
224 int len = strlen(str);
225 char *version_pos = strchr(name_pos + len, '/');
226 if (NULL != version_pos)
228 *version_pos = '\0';
229 new_entry->version = g_strdup(name_pos + len);
230 *version_pos = '/';
233 g_free(str);
235 entry->children = g_slist_prepend(entry->children, new_entry);
239 closedir(dir);
240 entry->children = g_slist_sort(entry->children, (GCompareFunc) tm_file_entry_compare);
241 if (entries)
242 g_free(entries);
243 break;
245 return entry;
248 void tm_file_entry_free(gpointer entry)
250 if (entry)
252 TMFileEntry *file_entry = TM_FILE_ENTRY(entry);
253 if (file_entry->children)
255 GSList *tmp;
256 for (tmp = file_entry->children; tmp; tmp = g_slist_next(tmp))
257 tm_file_entry_free(tmp->data);
258 g_slist_free(file_entry->children);
260 if (file_entry->version)
261 g_free(file_entry->version);
262 g_free(file_entry->path);
263 FILE_FREE(file_entry);
267 void tm_file_entry_foreach(TMFileEntry *entry, TMFileEntryFunc func
268 , gpointer user_data, guint level, gboolean reverse)
270 g_return_if_fail (entry != NULL);
271 g_return_if_fail (func != NULL);
273 if ((reverse) && (entry->children))
275 GSList *tmp;
276 for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
277 tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
278 , user_data, level + 1, TRUE);
280 func(entry, user_data, level);
281 if ((!reverse) && (entry->children))
283 GSList *tmp;
284 for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
285 tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
286 , user_data, level + 1, FALSE);
290 GList *tm_file_entry_list(TMFileEntry *entry, GList *files)
292 GSList *tmp;
293 files = g_list_prepend(files, g_strdup(entry->path));
294 for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
296 files = tm_file_entry_list((TMFileEntry *) tmp->data, files);
298 if (!files)
299 files = g_list_reverse(files);
300 return files;