gqview.h -> main.h
[geeqie.git] / src / pan-util.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12 #include "main.h"
13 #include "pan-types.h"
14
15 #include "ui_fileops.h"
16
17
18 /*
19  *-----------------------------------------------------------------------------
20  * date functions
21  *-----------------------------------------------------------------------------
22  */
23
24 gint pan_date_compare(time_t a, time_t b, PanDateLengthType length)
25 {
26         struct tm ta;
27         struct tm tb;
28
29         if (length == PAN_DATE_LENGTH_EXACT) return (a == b);
30
31         if (!localtime_r(&a, &ta) ||
32             !localtime_r(&b, &tb)) return FALSE;
33
34         if (ta.tm_year != tb.tm_year) return FALSE;
35         if (length == PAN_DATE_LENGTH_YEAR) return TRUE;
36
37         if (ta.tm_mon != tb.tm_mon) return FALSE;
38         if (length == PAN_DATE_LENGTH_MONTH) return TRUE;
39
40         if (length == PAN_DATE_LENGTH_WEEK) return (ta.tm_yday / 7 == tb.tm_yday / 7);
41
42         if (ta.tm_mday != tb.tm_mday) return FALSE;
43         if (length == PAN_DATE_LENGTH_DAY) return TRUE;
44
45         return (ta.tm_hour == tb.tm_hour);
46 }
47
48 gint pan_date_value(time_t d, PanDateLengthType length)
49 {
50         struct tm td;
51
52         if (!localtime_r(&d, &td)) return -1;
53
54         switch (length)
55                 {
56                 case PAN_DATE_LENGTH_DAY:
57                         return td.tm_mday;
58                         break;
59                 case PAN_DATE_LENGTH_WEEK:
60                         return td.tm_wday;
61                         break;
62                 case PAN_DATE_LENGTH_MONTH:
63                         return td.tm_mon + 1;
64                         break;
65                 case PAN_DATE_LENGTH_YEAR:
66                         return td.tm_year + 1900;
67                         break;
68                 case PAN_DATE_LENGTH_EXACT:
69                 default:
70                         break;
71                 }
72
73         return -1;
74 }
75
76 gchar *pan_date_value_string(time_t d, PanDateLengthType length)
77 {
78         struct tm td;
79         gchar buf[128];
80         gchar *format = NULL;
81
82         if (!localtime_r(&d, &td)) return g_strdup("");
83
84         switch (length)
85                 {
86                 case PAN_DATE_LENGTH_DAY:
87                         return g_strdup_printf("%d", td.tm_mday);
88                         break;
89                 case PAN_DATE_LENGTH_WEEK:
90                         format = "%A %e";
91                         break;
92                 case PAN_DATE_LENGTH_MONTH:
93                         format = "%B %Y";
94                         break;
95                 case PAN_DATE_LENGTH_YEAR:
96                         return g_strdup_printf("%d", td.tm_year + 1900);
97                         break;
98                 case PAN_DATE_LENGTH_EXACT:
99                 default:
100                         return g_strdup(text_from_time(d));
101                         break;
102                 }
103
104
105         if (format && strftime(buf, sizeof(buf), format, &td) > 0)
106                 {
107                 gchar *ret = g_locale_to_utf8(buf, -1, NULL, NULL, NULL);
108                 if (ret) return ret;
109                 }
110
111         return g_strdup("");
112 }
113
114 time_t pan_date_to_time(gint year, gint month, gint day)
115 {
116         struct tm lt;
117
118         lt.tm_sec = 0;
119         lt.tm_min = 0;
120         lt.tm_hour = 0;
121         lt.tm_mday = (day >= 1 && day <= 31) ? day : 1;
122         lt.tm_mon = (month >= 1 && month <= 12) ? month - 1 : 0;
123         lt.tm_year = year - 1900;
124         lt.tm_isdst = 0;
125
126         return mktime(&lt);
127 }
128
129
130 /*
131  *-----------------------------------------------------------------------------
132  * folder validation
133  *-----------------------------------------------------------------------------
134  */
135
136 gint pan_is_link_loop(const gchar *s)
137 {
138         gchar *sl;
139         struct stat st;
140         gint ret = FALSE;
141
142         sl = path_from_utf8(s);
143
144         if (lstat(sl, &st) == 0 && S_ISLNK(st.st_mode))
145                 {
146                 gchar *buf;
147                 gint l;
148
149                 buf = g_malloc(st.st_size + 1);
150                 l = readlink(sl, buf, st.st_size);
151                 if (l == st.st_size)
152                         {
153                         buf[l] = '\0';
154
155                         parse_out_relatives(buf);
156                         l = strlen(buf);
157
158                         parse_out_relatives(sl);
159
160                         if (buf[0] == '/')
161                                 {
162                                 if (strncmp(sl, buf, l) == 0 &&
163                                     (sl[l] == '\0' || sl[l] == '/' || l == 1)) ret = TRUE;
164                                 }
165                         else
166                                 {
167                                 gchar *link_path;
168
169                                 link_path = concat_dir_and_file(sl, buf);
170                                 parse_out_relatives(link_path);
171
172                                 if (strncmp(sl, link_path, l) == 0 &&
173                                     (sl[l] == '\0' || sl[l] == '/' || l == 1)) ret = TRUE;
174
175                                 g_free(link_path);
176                                 }
177                         }
178
179                 g_free(buf);
180                 }
181
182         g_free(sl);
183
184         return ret;
185 }
186
187 gint pan_is_ignored(const gchar *s, gint ignore_symlinks)
188 {
189         struct stat st;
190         const gchar *n;
191
192         if (!lstat_utf8(s, &st)) return TRUE;
193
194 #if 0
195         /* normal filesystems have directories with some size or block allocation,
196          * special filesystems (like linux /proc) set both to zero.
197          * enable this check if you enable listing the root "/" folder
198          */
199         if (st.st_size == 0 && st.st_blocks == 0) return TRUE;
200 #endif
201
202         if (S_ISLNK(st.st_mode) && (ignore_symlinks || pan_is_link_loop(s))) return TRUE;
203
204         n = filename_from_path(s);
205         if (n && strcmp(n, GQVIEW_RC_DIR) == 0) return TRUE;
206
207         return FALSE;
208 }
209
210 GList *pan_list_tree(const gchar *path, SortType sort, gint ascend,
211                      gint ignore_symlinks)
212 {
213         GList *flist = NULL;
214         GList *dlist = NULL;
215         GList *result;
216         GList *folders;
217
218         filelist_read(path, &flist, &dlist);
219         if (sort != SORT_NONE)
220                 {
221                 flist = filelist_sort(flist, sort, ascend);
222                 dlist = filelist_sort(dlist, sort, ascend);
223                 }
224
225         result = flist;
226         folders = dlist;
227         while (folders)
228                 {
229                 FileData *fd;
230
231                 fd = folders->data;
232                 folders = g_list_remove(folders, fd);
233
234                 if (!pan_is_ignored(fd->path, ignore_symlinks) &&
235                     filelist_read(fd->path, &flist, &dlist))
236                         {
237                         if (sort != SORT_NONE)
238                                 {
239                                 flist = filelist_sort(flist, sort, ascend);
240                                 dlist = filelist_sort(dlist, sort, ascend);
241                                 }
242
243                         result = g_list_concat(result, flist);
244                         folders = g_list_concat(dlist, folders);
245                         }
246
247                 file_data_unref(fd);
248                 }
249
250         return result;
251 }
252