Cleanup main.h header
[geeqie.git] / src / pan-view / pan-util.cc
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 <config.h>
25
26 #include "main-defines.h"
27 #include "ui-fileops.h"
28
29
30 /*
31  *-----------------------------------------------------------------------------
32  * date functions
33  *-----------------------------------------------------------------------------
34  */
35
36 gboolean pan_date_compare(time_t a, time_t b, PanDateLengthType length)
37 {
38         struct tm ta;
39         struct tm tb;
40
41         if (length == PAN_DATE_LENGTH_EXACT) return (a == b);
42
43         if (!localtime_r(&a, &ta) ||
44             !localtime_r(&b, &tb)) return FALSE;
45
46         if (ta.tm_year != tb.tm_year) return FALSE;
47         if (length == PAN_DATE_LENGTH_YEAR) return TRUE;
48
49         if (ta.tm_mon != tb.tm_mon) return FALSE;
50         if (length == PAN_DATE_LENGTH_MONTH) return TRUE;
51
52         if (length == PAN_DATE_LENGTH_WEEK) return (ta.tm_yday / 7 == tb.tm_yday / 7);
53
54         if (ta.tm_mday != tb.tm_mday) return FALSE;
55         if (length == PAN_DATE_LENGTH_DAY) return TRUE;
56
57         return (ta.tm_hour == tb.tm_hour);
58 }
59
60 gint pan_date_value(time_t d, PanDateLengthType length)
61 {
62         struct tm td;
63
64         if (!localtime_r(&d, &td)) return -1;
65
66         switch (length)
67                 {
68                 case PAN_DATE_LENGTH_DAY:
69                         return td.tm_mday;
70                         break;
71                 case PAN_DATE_LENGTH_WEEK:
72                         return td.tm_wday;
73                         break;
74                 case PAN_DATE_LENGTH_MONTH:
75                         return td.tm_mon + 1;
76                         break;
77                 case PAN_DATE_LENGTH_YEAR:
78                         return td.tm_year + 1900;
79                         break;
80                 case PAN_DATE_LENGTH_EXACT:
81                 default:
82                         break;
83                 }
84
85         return -1;
86 }
87
88 #if defined(__GLIBC_PREREQ)
89 # if __GLIBC_PREREQ(2, 27)
90 #  define HAS_GLIBC_STRFTIME_EXTENSIONS
91 # endif
92 #endif
93
94 gchar *pan_date_value_string(time_t d, PanDateLengthType length)
95 {
96         struct tm td;
97         gchar buf[128];
98         const gchar *format = nullptr;
99
100         if (!localtime_r(&d, &td)) return g_strdup("");
101
102         switch (length)
103                 {
104                 case PAN_DATE_LENGTH_DAY:
105                         return g_strdup_printf("%d", td.tm_mday);
106                         break;
107                 case PAN_DATE_LENGTH_WEEK:
108                         format = "%A %e";
109                         break;
110                 case PAN_DATE_LENGTH_MONTH:
111 #if defined(HAS_GLIBC_STRFTIME_EXTENSIONS) || defined(__FreeBSD__)
112                         format = "%OB %Y";
113 #else
114                         format = "%B %Y";
115 #endif
116                         break;
117                 case PAN_DATE_LENGTH_YEAR:
118                         return g_strdup_printf("%d", td.tm_year + 1900);
119                         break;
120                 case PAN_DATE_LENGTH_EXACT:
121                 default:
122                         return g_strdup(text_from_time(d));
123                         break;
124                 }
125
126
127         if (format && strftime(buf, sizeof(buf), format, &td) > 0)
128                 {
129                 gchar *ret = g_locale_to_utf8(buf, -1, nullptr, nullptr, nullptr);
130                 if (ret) return ret;
131                 }
132
133         return g_strdup("");
134 }
135
136 time_t pan_date_to_time(gint year, gint month, gint day)
137 {
138         struct tm lt;
139
140         lt.tm_sec = 0;
141         lt.tm_min = 0;
142         lt.tm_hour = 0;
143         lt.tm_mday = (day >= 1 && day <= 31) ? day : 1;
144         lt.tm_mon = (month >= 1 && month <= 12) ? month - 1 : 0;
145         lt.tm_year = year - 1900;
146         lt.tm_isdst = 0;
147
148         return mktime(&lt);
149 }
150
151
152 /*
153  *-----------------------------------------------------------------------------
154  * folder validation
155  *-----------------------------------------------------------------------------
156  */
157
158 gboolean pan_is_link_loop(const gchar *s)
159 {
160         gchar *sl;
161         struct stat st;
162         gboolean ret = FALSE;
163
164         sl = path_from_utf8(s);
165
166         if (lstat(sl, &st) == 0 && S_ISLNK(st.st_mode))
167                 {
168                 gchar *buf;
169                 gint l;
170
171                 buf = static_cast<gchar *>(g_malloc(st.st_size + 1));
172                 l = readlink(sl, buf, st.st_size);
173                 if (l == st.st_size)
174                         {
175                         buf[l] = '\0';
176
177                         parse_out_relatives(buf);
178                         l = strlen(buf);
179
180                         parse_out_relatives(sl);
181
182                         if (buf[0] == G_DIR_SEPARATOR)
183                                 {
184                                 if (strncmp(sl, buf, l) == 0 &&
185                                     (sl[l] == '\0' || sl[l] == G_DIR_SEPARATOR || l == 1)) ret = TRUE;
186                                 }
187                         else
188                                 {
189                                 gchar *link_path;
190
191                                 link_path = g_build_filename(sl, buf, NULL);
192                                 parse_out_relatives(link_path);
193
194                                 if (strncmp(sl, link_path, l) == 0 &&
195                                     (sl[l] == '\0' || sl[l] == G_DIR_SEPARATOR || l == 1)) ret = TRUE;
196
197                                 g_free(link_path);
198                                 }
199                         }
200
201                 g_free(buf);
202                 }
203
204         g_free(sl);
205
206         return ret;
207 }
208
209 gboolean pan_is_ignored(const gchar *s, gboolean ignore_symlinks)
210 {
211         struct stat st;
212         const gchar *n;
213
214         if (!lstat_utf8(s, &st)) return TRUE;
215
216 #if 0
217         /* normal filesystems have directories with some size or block allocation,
218          * special filesystems (like linux /proc) set both to zero.
219          * enable this check if you enable listing the root "/" folder
220          */
221         if (st.st_size == 0 && st.st_blocks == 0) return TRUE;
222 #endif
223
224         if (S_ISLNK(st.st_mode) && (ignore_symlinks || pan_is_link_loop(s))) return TRUE;
225
226         n = filename_from_path(s);
227         if (n && strcmp(n, GQ_RC_DIR) == 0) return TRUE;
228
229         return FALSE;
230 }
231
232 GList *pan_list_tree(FileData *dir_fd, SortType sort, gboolean ascend, gboolean case_sensitive,
233                      gboolean ignore_symlinks)
234 {
235         GList *flist;
236         GList *dlist;
237         GList *result;
238         GList *folders;
239
240         filelist_read(dir_fd, &flist, &dlist);
241         if (sort != SORT_NONE)
242                 {
243                 flist = filelist_sort(flist, sort, ascend, case_sensitive);
244                 dlist = filelist_sort(dlist, sort, ascend, case_sensitive);
245                 }
246
247         result = flist;
248         folders = dlist;
249         while (folders)
250                 {
251                 FileData *fd;
252
253                 fd = static_cast<FileData *>(folders->data);
254                 folders = g_list_remove(folders, fd);
255
256                 if (!pan_is_ignored(fd->path, ignore_symlinks) &&
257                     filelist_read(fd, &flist, &dlist))
258                         {
259                         if (sort != SORT_NONE)
260                                 {
261                                 flist = filelist_sort(flist, sort, ascend, case_sensitive);
262                                 dlist = filelist_sort(dlist, sort, ascend, case_sensitive);
263                                 }
264
265                         result = g_list_concat(result, flist);
266                         folders = g_list_concat(dlist, folders);
267                         }
268
269                 file_data_unref(fd);
270                 }
271
272         return result;
273 }
274 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */