Update copyright in all files
[geeqie.git] / src / history_list.c
1 /*
2  * Copyright (C) 2008 - 2016 The Geeqie Team
3  *
4  * Authors: John Ellis, Vladimir Nadvornik, Laurent Monin
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "main.h"
22 #include "history_list.h"
23
24 #include "secure_save.h"
25 #include "ui_fileops.h"
26
27 /*
28  *-----------------------------------------------------------------------------
29  * history lists
30  *-----------------------------------------------------------------------------
31  */
32
33 #define HISTORY_DEFAULT_KEY_COUNT 16
34
35
36 typedef struct _HistoryData HistoryData;
37 struct _HistoryData
38 {
39         gchar *key;
40         GList *list;
41 };
42
43 static GList *history_list = NULL;
44
45
46 static gchar *quoted_from_text(const gchar *text)
47 {
48         const gchar *ptr;
49         gint c = 0;
50         gint l = strlen(text);
51
52         if (l == 0) return NULL;
53
54         while (c < l && text[c] !='"') c++;
55         if (text[c] == '"')
56                 {
57                 gint e;
58                 c++;
59                 ptr = text + c;
60                 e = c;
61                 while (e < l && text[e] !='"') e++;
62                 if (text[e] == '"')
63                         {
64                         if (e - c > 0)
65                                 {
66                                 return g_strndup(ptr, e - c);
67                                 }
68                         }
69                 }
70         return NULL;
71 }
72
73 gboolean history_list_load(const gchar *path)
74 {
75         FILE *f;
76         gchar *key = NULL;
77         gchar s_buf[1024];
78         gchar *pathl;
79
80         pathl = path_from_utf8(path);
81         f = fopen(pathl, "r");
82         g_free(pathl);
83         if (!f) return FALSE;
84
85         /* first line must start with History comment */
86         if (!fgets(s_buf, sizeof(s_buf), f) ||
87             strncmp(s_buf, "#History", 8) != 0)
88                 {
89                 fclose(f);
90                 return FALSE;
91                 }
92
93         while (fgets(s_buf, sizeof(s_buf), f))
94                 {
95                 if (s_buf[0]=='#') continue;
96                 if (s_buf[0]=='[')
97                         {
98                         gint c;
99                         gchar *ptr;
100
101                         ptr = s_buf + 1;
102                         c = 0;
103                         while (ptr[c] != ']' && ptr[c] != '\n' && ptr[c] != '\0') c++;
104
105                         g_free(key);
106                         key = g_strndup(ptr, c);
107                         }
108                 else
109                         {
110                         gchar *value;
111
112                         value = quoted_from_text(s_buf);
113                         if (value && key)
114                                 {
115                                 history_list_add_to_key(key, value, 0);
116                                 }
117                         g_free(value);
118                         }
119                 }
120
121         fclose(f);
122
123         g_free(key);
124
125         return TRUE;
126 }
127
128 gboolean history_list_save(const gchar *path)
129 {
130         SecureSaveInfo *ssi;
131         GList *list;
132         gchar *pathl;
133
134         pathl = path_from_utf8(path);
135         ssi = secure_open(pathl);
136         g_free(pathl);
137         if (!ssi)
138                 {
139                 log_printf(_("Unable to write history lists to: %s\n"), path);
140                 return FALSE;
141                 }
142
143         secure_fprintf(ssi, "#History lists\n\n");
144
145         list = g_list_last(history_list);
146         while (list && secsave_errno == SS_ERR_NONE)
147                 {
148                 HistoryData *hd;
149                 GList *work;
150
151                 hd = list->data;
152                 list = list->prev;
153
154                 secure_fprintf(ssi, "[%s]\n", hd->key);
155
156                 /* save them inverted (oldest to newest)
157                  * so that when reading they are added correctly
158                  */
159                 work = g_list_last(hd->list);
160                 while (work && secsave_errno == SS_ERR_NONE)
161                         {
162                         secure_fprintf(ssi, "\"%s\"\n", (gchar *)work->data);
163                         work = work->prev;
164                         }
165                 secure_fputc(ssi, '\n');
166                 }
167
168         secure_fprintf(ssi, "#end\n");
169
170         return (secure_close(ssi) == 0);
171 }
172
173 static void history_list_free(HistoryData *hd)
174 {
175         GList *work;
176
177         if (!hd) return;
178
179         work = hd->list;
180         while (work)
181                 {
182                 g_free(work->data);
183                 work = work->next;
184                 }
185
186         g_free(hd->key);
187         g_free(hd);
188 }
189
190 static HistoryData *history_list_find_by_key(const gchar *key)
191 {
192         GList *work = history_list;
193
194         if (!key) return NULL;
195
196         while (work)
197                 {
198                 HistoryData *hd = work->data;
199                 if (strcmp(hd->key, key) == 0) return hd;
200                 work = work->next;
201                 }
202         return NULL;
203 }
204
205 const gchar *history_list_find_last_path_by_key(const gchar *key)
206 {
207         HistoryData *hd;
208
209         hd = history_list_find_by_key(key);
210         if (!hd || !hd->list) return NULL;
211
212         return hd->list->data;
213 }
214
215 void history_list_free_key(const gchar *key)
216 {
217         HistoryData *hd;
218         hd = history_list_find_by_key(key);
219         if (!hd) return;
220
221         history_list = g_list_remove(history_list, hd);
222         history_list_free(hd);
223 }
224
225 void history_list_add_to_key(const gchar *key, const gchar *path, gint max)
226 {
227         HistoryData *hd;
228         GList *work;
229
230         if (!key || !path) return;
231
232         hd = history_list_find_by_key(key);
233         if (!hd)
234                 {
235                 hd = g_new(HistoryData, 1);
236                 hd->key = g_strdup(key);
237                 hd->list = NULL;
238                 history_list = g_list_prepend(history_list, hd);
239                 }
240
241         /* if already in the list, simply move it to the top */
242         work = hd->list;
243         while (work)
244                 {
245                 gchar *buf = work->data;
246
247                 if (strcmp(buf, path) == 0)
248                         {
249                         /* if not first, move it */
250                         if (work != hd->list)
251                                 {
252                                 hd->list = g_list_remove(hd->list, buf);
253                                 hd->list = g_list_prepend(hd->list, buf);
254                                 }
255                         return;
256                         }
257                 work = work->next;
258                 }
259
260         hd->list = g_list_prepend(hd->list, g_strdup(path));
261
262         if (max == -1) max = HISTORY_DEFAULT_KEY_COUNT;
263         if (max > 0)
264                 {
265                 gint len = 0;
266                 GList *work = hd->list;
267                 GList *last = NULL;
268
269                 while (work)
270                         {
271                         len++;
272                         last = work;
273                         work = work->next;
274                         }
275
276                 work = last;
277                 while (work && len > max)
278                         {
279                         GList *node = work;
280                         work = work->prev;
281
282                         g_free(node->data);
283                         hd->list = g_list_delete_link(hd->list, node);
284                         len--;
285                         }
286                 }
287 }
288
289 void history_list_item_change(const gchar *key, const gchar *oldpath, const gchar *newpath)
290 {
291         HistoryData *hd;
292         GList *work;
293
294         if (!oldpath) return;
295         hd = history_list_find_by_key(key);
296         if (!hd) return;
297
298         work = hd->list;
299         while (work)
300                 {
301                 gchar *buf = work->data;
302                 if (strcmp(buf, oldpath) == 0)
303                         {
304                         if (newpath)
305                                 {
306                                 work->data = g_strdup(newpath);
307                                 }
308                         else
309                                 {
310                                 hd->list = g_list_remove(hd->list, buf);
311                                 }
312                         g_free(buf);
313                         return;
314                         }
315                 work = work->next;
316                 }
317 }
318
319 void history_list_item_move(const gchar *key, const gchar *path, gint direction)
320 {
321         HistoryData *hd;
322         GList *work;
323         gint p = 0;
324
325         if (!path) return;
326         hd = history_list_find_by_key(key);
327         if (!hd) return;
328
329         work = hd->list;
330         while (work)
331                 {
332                 gchar *buf = work->data;
333                 if (strcmp(buf, path) == 0)
334                         {
335                         p += direction;
336                         if (p < 0) return;
337                         hd->list = g_list_remove(hd->list, buf);
338                         hd->list = g_list_insert(hd->list, buf, p);
339                         return;
340                         }
341                 work = work->next;
342                 p++;
343                 }
344 }
345
346 void history_list_item_remove(const gchar *key, const gchar *path)
347 {
348         history_list_item_change(key, path, NULL);
349 }
350
351 GList *history_list_get_by_key(const gchar *key)
352 {
353         HistoryData *hd;
354
355         hd = history_list_find_by_key(key);
356         if (!hd) return NULL;
357
358         return hd->list;
359 }
360 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */