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