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