Merge commit 'git-svn'
[anjuta-git-plugin.git] / tagmanager / tm_file_entry.c
blobf31fd228404233c690bb8daac68f938b1b297e25
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 #include <fnmatch.h>
18 #include <fcntl.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
22 #include "tm_work_object.h"
23 #include "tm_file_entry.h"
25 static GMemChunk *file_mem_chunk = NULL;
27 #define FILE_NEW(T) {\
28 if (!file_mem_chunk) \
29 file_mem_chunk = g_mem_chunk_new("TMFileEntry MemChunk", sizeof(TMFileEntry), 1024 \
30 , G_ALLOC_AND_FREE); \
31 (T) = g_chunk_new0(TMFileEntry, file_mem_chunk);}
33 #define FILE_FREE(T) g_mem_chunk_free(file_mem_chunk, (T))
35 void tm_file_entry_print(TMFileEntry *entry, gpointer __unused__ user_data
36 , guint level)
38 guint i;
40 g_return_if_fail(entry);
41 for (i=0; i < level; ++i)
42 fputc('\t', stderr);
43 fprintf(stderr, "%s\n", entry->name);
46 gint tm_file_entry_compare(TMFileEntry *e1, TMFileEntry *e2)
48 g_return_val_if_fail(e1 && e2 && e1->name && e2->name, 0);
49 #ifdef TM_DEBUG
50 g_message("Comparing %s and %s", e1->name, e2->name);
51 #endif
52 return strcmp(e1->name, e2->name);
55 /* TTimo - modified to handle symlinks */
56 static TMFileType tm_file_entry_type(const char *path)
58 struct stat s;
60 if (0 != lstat(path, &s))
61 return tm_file_unknown_t;
62 if S_ISLNK(s.st_mode)
63 return tm_file_link_t;
64 else if S_ISDIR(s.st_mode)
65 return tm_file_dir_t;
66 else if S_ISREG(s.st_mode)
67 return tm_file_regular_t;
68 else
69 return tm_file_unknown_t;
72 static gboolean apply_filter(const char *name, GList *match, GList *unmatch
73 , gboolean ignore_hidden)
75 GList *tmp;
76 gboolean matched = (match == NULL);
77 g_return_val_if_fail(name, FALSE);
78 if (ignore_hidden && ('.' == name[0]))
79 return FALSE;
80 /* TTimo - ignore .svn directories */
81 if (!strcmp(name, ".svn"))
82 return FALSE;
83 for (tmp = match; tmp; tmp = g_list_next(tmp))
85 if (0 == fnmatch((char *) tmp->data, name, 0))
87 matched = TRUE;
88 break;
91 if (!matched)
92 return FALSE;
93 for (tmp = unmatch; tmp; tmp = g_list_next(tmp))
95 if (0 == fnmatch((char *) tmp->data, name, 0))
97 return FALSE;
100 return matched;
103 TMFileEntry *tm_file_entry_new(const char *path, TMFileEntry *parent
104 , gboolean recurse, GList *file_match, GList *file_unmatch
105 , GList *dir_match, GList *dir_unmatch, gboolean ignore_hidden_files
106 , gboolean ignore_hidden_dirs)
108 TMFileEntry *entry;
109 /* GList *tmp; */
110 char *real_path;
111 DIR *dir;
112 struct dirent *dir_entry;
113 TMFileEntry *new_entry;
114 char file_name[PATH_MAX];
115 struct stat s;
116 char *entries = NULL;
118 g_return_val_if_fail (path != NULL, NULL);
120 /* TTimo - don't follow symlinks */
121 if (tm_file_entry_type(path) == tm_file_link_t)
122 return NULL;
124 real_path = tm_get_real_path(path);
125 if (!real_path)
126 return NULL;
128 FILE_NEW(entry);
129 entry->type = tm_file_entry_type(real_path);
130 entry->parent = parent;
131 entry->path = real_path;
132 entry->name = strrchr(entry->path, '/');
133 if (entry->name)
134 ++ (entry->name);
135 else
136 entry->name = entry->path;
137 switch(entry->type)
139 case tm_file_link_t:
140 FILE_FREE (entry);
141 return NULL;
142 case tm_file_unknown_t:
143 g_free(real_path);
144 FILE_FREE(entry);
145 return NULL;
146 case tm_file_regular_t:
147 if (parent && !apply_filter(entry->name, file_match, file_unmatch
148 , ignore_hidden_files))
150 tm_file_entry_free(entry);
151 return NULL;
153 break;
154 case tm_file_dir_t:
155 if (parent && !(recurse && apply_filter(entry->name, dir_match
156 , dir_unmatch, ignore_hidden_dirs)))
158 tm_file_entry_free(entry);
159 return NULL;
161 g_snprintf(file_name, PATH_MAX, "%s/CVS/Entries", entry->path);
162 if (0 == stat(file_name, &s))
164 if (S_ISREG(s.st_mode))
166 int fd;
167 entries = g_new(char, s.st_size + 2);
168 if (0 > (fd = open(file_name, O_RDONLY)))
170 g_free(entries);
171 entries = NULL;
173 else
175 off_t n =0;
176 off_t total_read = 1;
177 while (0 < (n = read(fd, entries + total_read, s.st_size - total_read)))
178 total_read += n;
179 entries[s.st_size] = '\0';
180 entries[0] = '\n';
181 close(fd);
182 entry->version = g_strdup("D");
186 if (NULL != (dir = opendir(entry->path)))
188 while (NULL != (dir_entry = readdir(dir)))
190 if ((0 == strcmp(dir_entry->d_name, "."))
191 || (0 == strcmp(dir_entry->d_name, "..")))
192 continue;
193 g_snprintf(file_name, PATH_MAX, "%s/%s", entry->path
194 , dir_entry->d_name);
195 new_entry = tm_file_entry_new(file_name, entry, recurse
196 , file_match, file_unmatch, dir_match, dir_unmatch
197 , ignore_hidden_files, ignore_hidden_dirs);
198 if (new_entry)
200 if (entries)
202 char *str = g_strconcat("\n/", new_entry->name, "/", NULL);
203 char *name_pos = strstr(entries, str);
204 if (NULL != name_pos)
206 int len = strlen(str);
207 char *version_pos = strchr(name_pos + len, '/');
208 if (NULL != version_pos)
210 *version_pos = '\0';
211 new_entry->version = g_strdup(name_pos + len);
212 *version_pos = '/';
215 g_free(str);
217 entry->children = g_slist_prepend(entry->children, new_entry);
221 closedir(dir);
222 entry->children = g_slist_sort(entry->children, (GCompareFunc) tm_file_entry_compare);
223 if (entries)
224 g_free(entries);
225 break;
227 return entry;
230 void tm_file_entry_free(gpointer entry)
232 if (entry)
234 TMFileEntry *file_entry = TM_FILE_ENTRY(entry);
235 if (file_entry->children)
237 GSList *tmp;
238 for (tmp = file_entry->children; tmp; tmp = g_slist_next(tmp))
239 tm_file_entry_free(tmp->data);
240 g_slist_free(file_entry->children);
242 if (file_entry->version)
243 g_free(file_entry->version);
244 g_free(file_entry->path);
245 FILE_FREE(file_entry);
249 void tm_file_entry_foreach(TMFileEntry *entry, TMFileEntryFunc func
250 , gpointer user_data, guint level, gboolean reverse)
252 g_return_if_fail (entry != NULL);
253 g_return_if_fail (func != NULL);
255 if ((reverse) && (entry->children))
257 GSList *tmp;
258 for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
259 tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
260 , user_data, level + 1, TRUE);
262 func(entry, user_data, level);
263 if ((!reverse) && (entry->children))
265 GSList *tmp;
266 for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
267 tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
268 , user_data, level + 1, FALSE);
272 GList *tm_file_entry_list(TMFileEntry *entry, GList *files)
274 GSList *tmp;
275 files = g_list_prepend(files, g_strdup(entry->path));
276 for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
278 files = tm_file_entry_list((TMFileEntry *) tmp->data, files);
280 if (files)
281 files = g_list_reverse(files);
282 return files;