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.
20 #include <sys/types.h>
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
57 g_return_if_fail(entry
);
58 for (i
=0; i
< level
; ++i
)
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);
67 g_message("Comparing %s and %s", e1
->name
, e2
->name
);
69 return strcmp(e1
->name
, e2
->name
);
72 /* TTimo - modified to handle symlinks */
73 static TMFileType
tm_file_entry_type(const char *path
)
78 if (0 != g_lstat(path
, &s
))
79 return tm_file_unknown_t
;
84 else if (S_ISLNK(s
.st_mode
))
85 return tm_file_link_t
;
87 else if S_ISREG(s
.st_mode
)
88 return tm_file_regular_t
;
90 return tm_file_unknown_t
;
93 static gboolean
apply_filter(const char *name
, GList
*match
, GList
*unmatch
94 , gboolean ignore_hidden
)
97 gboolean matched
= (match
== NULL
);
98 g_return_val_if_fail(name
, FALSE
);
99 if (ignore_hidden
&& ('.' == name
[0]))
101 /* TTimo - ignore .svn directories */
102 if (!strcmp(name
, ".svn"))
104 for (tmp
= match
; tmp
; tmp
= g_list_next(tmp
))
106 if (0 == fnmatch((char *) tmp
->data
, name
, 0))
114 for (tmp
= unmatch
; tmp
; tmp
= g_list_next(tmp
))
116 if (0 == fnmatch((char *) tmp
->data
, name
, 0))
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
)
133 struct dirent
*dir_entry
;
134 TMFileEntry
*new_entry
;
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
)
144 real_path
= tm_get_real_path(path
);
148 entry
->type
= tm_file_entry_type(real_path
);
149 entry
->parent
= parent
;
150 entry
->path
= real_path
;
151 entry
->name
= strrchr(entry
->path
, '/');
155 entry
->name
= entry
->path
;
158 case tm_file_unknown_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
);
172 if (parent
&& !(recurse
&& apply_filter(entry
->name
, dir_match
173 , dir_unmatch
, ignore_hidden_dirs
)))
175 tm_file_entry_free(entry
);
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
))
184 entries
= g_new(char, s
.st_size
+ 2);
185 if (0 > (fd
= open(file_name
, O_RDONLY
)))
193 off_t total_read
= 1;
194 while (0 < (n
= read(fd
, entries
+ total_read
, s
.st_size
- total_read
)))
196 entries
[s
.st_size
] = '\0';
199 entry
->version
= g_strdup("D");
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
, "..")))
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
);
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
)
229 new_entry
->version
= g_strdup(name_pos
+ len
);
235 entry
->children
= g_slist_prepend(entry
->children
, new_entry
);
240 entry
->children
= g_slist_sort(entry
->children
, (GCompareFunc
) tm_file_entry_compare
);
248 void tm_file_entry_free(gpointer entry
)
252 TMFileEntry
*file_entry
= TM_FILE_ENTRY(entry
);
253 if (file_entry
->children
)
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
))
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
))
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
)
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
);
299 files
= g_list_reverse(files
);