1 /***************************************************************************
2 * verve-history.h
3 *
4 * Copyright 2006-2007 Jannis Pohlmann
5 * jannis@xfce.org
6 ****************************************************************************/
7
8 /*
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <libxfce4util/libxfce4util.h>
29
30 #include "verve.h"
31 #include "verve-history.h"
32
33
34
35 const gchar *verve_history_cache_get_filename (void);
36 static void verve_history_cache_load (void);
37 static void verve_history_cache_write (void);
38 static void verve_history_append (gchar *command);
39
40
41
42 /*********************************************************************
43 *
44 * Init / Shutdown functions
45 *
46 *********************************************************************/
47
48 static gint history_length = 50;
49 static GList *history = NULL;
50
51
52
53 void
verve_history_init(void)54 verve_history_init (void)
55 {
56 verve_history_cache_load ();
57 }
58
59
60
61 void
verve_history_shutdown(void)62 verve_history_shutdown (void)
63 {
64 /* Write history into the cache file */
65 verve_history_cache_write ();
66
67 /* Free history data */
68 if (G_LIKELY (history != NULL))
69 {
70 /* Free entries */
71 GList *iter = g_list_first (history);
72 while (iter != NULL)
73 {
74 g_free ((gchar *)iter->data);
75 iter = g_list_next (iter);
76 }
77
78 /* Free list */
79 g_list_free (history);
80 }
81 }
82
83
84
85 void
verve_history_set_length(gint length)86 verve_history_set_length (gint length)
87 {
88 history_length = length;
89 }
90
91
92
93 void
verve_history_add(gchar * input)94 verve_history_add (gchar *input)
95 {
96 /* Prepend input to history */
97 history = g_list_prepend (history, input);
98 }
99
100
101
102 void
verve_history_append(gchar * command)103 verve_history_append (gchar *command)
104 {
105 /* Append command to history */
106 history = g_list_append (history, command);
107 }
108
109
110
111 GList*
verve_history_begin(void)112 verve_history_begin (void)
113 {
114 /* Return first list entry or NULL */
115 return g_list_first (history);
116 }
117
118
119
120 GList*
verve_history_end(void)121 verve_history_end (void)
122 {
123 /* Return last list entry or NULL */
124 return g_list_last (history);
125 }
126
127
128
129 GList*
verve_history_get_prev(const GList * current)130 verve_history_get_prev (const GList *current)
131 {
132 /* Return command before the current one or NULL */
133 return g_list_previous (current);
134 }
135
136
137
138 GList*
verve_history_get_next(const GList * current)139 verve_history_get_next (const GList *current)
140 {
141 /* Return command after the current one or NULL */
142 return g_list_next (current);
143 }
144
145
146
147 gboolean
verve_history_is_empty(void)148 verve_history_is_empty (void)
149 {
150 /* Check whether history is uninitialized or its length is zero */
151 if (G_UNLIKELY (history == NULL) || g_list_length (history) == 0)
152 return TRUE;
153 else
154 return FALSE;
155 }
156
157
158
159 const gchar*
verve_history_get_last_command(void)160 verve_history_get_last_command (void)
161 {
162 /* Get first (= latest) history entry */
163 GList *list = verve_history_begin ();
164
165 /* Return NULL if list is empty */
166 if (G_UNLIKELY (list == NULL))
167 return NULL;
168
169 /* Return command data */
170 return (gchar *)list->data;
171 }
172
173
174
175 const gchar *
verve_history_cache_get_filename(void)176 verve_history_cache_get_filename (void)
177 {
178 static const gchar *filename = "xfce4/Verve/history";
179 return filename;
180 }
181
182
183
184 static void
verve_history_cache_load(void)185 verve_history_cache_load (void)
186 {
187 const gchar *basename = verve_history_cache_get_filename ();
188
189 /* Search for cache file */
190 gchar *filename = xfce_resource_lookup (XFCE_RESOURCE_CONFIG, basename);
191
192 /* Only read cache if file exists */
193 if (G_LIKELY (filename != NULL))
194 {
195 GError *error = NULL;
196 GIOChannel *handle;
197
198 /* Open file input stream */
199 handle = g_io_channel_new_file (filename, "r", &error);
200
201 /* Instantly destroy error messages - just ignore them */
202 if (G_UNLIKELY (error != NULL))
203 g_error_free (error);
204
205 /* Only read contents if stream could be opened */
206 if (G_LIKELY (handle != NULL))
207 {
208 GIOStatus status;
209 gchar *line;
210 gsize length;
211
212 /* Read first line */
213 status = g_io_channel_read_line (handle, &line, &length, NULL, &error);
214
215 /* Read lines until EOF is reached or an error occurs */
216 while (status != G_IO_STATUS_EOF && error == NULL)
217 {
218 /* Get current line, remove leading and trailing whitespace */
219 GString *strline = g_string_new (g_strstrip (line));
220
221 /* Only add non-empty lines to the history */
222 if (G_LIKELY (strline->len > 0))
223 verve_history_append (strline->str);
224
225 /* Free string data */
226 g_free (line);
227 g_string_free (strline, FALSE);
228
229 /* Read next line */
230 status = g_io_channel_read_line (handle, &line, &length, NULL, &error);
231 }
232
233 /* Free error message */
234 if (G_UNLIKELY (error != NULL))
235 g_error_free (error);
236
237 /* Close file handle */
238 g_io_channel_shutdown (handle, TRUE, &error);
239
240 /* Again: Free error message */
241 if (G_UNLIKELY (error != NULL))
242 g_error_free (error);
243
244 /* Destroy stream object */
245 g_io_channel_unref (handle);
246 }
247 }
248
249 /* Free filename string */
250 g_free (filename);
251 }
252
253
254
255 static void
verve_history_cache_write(void)256 verve_history_cache_write (void)
257 {
258 /* Do not write history if it is empty */
259 if (verve_history_is_empty ())
260 return;
261
262 const gchar *basename = verve_history_cache_get_filename ();
263
264 /* Search for history file, create if it does not exist yet */
265 gchar *filename = xfce_resource_save_location (XFCE_RESOURCE_CONFIG, basename, TRUE);
266
267 if (G_LIKELY (filename != NULL))
268 {
269 GError *error = NULL;
270 GIOChannel *handle;
271
272 /* Open output stream */
273 handle = g_io_channel_new_file (filename, "w+", &error);
274
275 /* Ignore and free error messages */
276 if (G_UNLIKELY (error != NULL))
277 g_error_free (error);
278
279 /* Only write contents if stream could be opened */
280 if (G_LIKELY (handle != NULL))
281 {
282 GList *current;
283 gsize bytes;
284 int i;
285
286 /* Get first history entry */
287 current = verve_history_begin();
288
289 /* Save the last 25 commands */
290 for (i = 0; i < history_length && current != NULL; i++)
291 {
292 /* Build output line */
293 gchar *line = g_strconcat ("", current->data, "\n", NULL);
294
295 /* Write line */
296 g_io_channel_write_chars (handle, line, -1, &bytes, &error);
297
298 /* Free line string */
299 g_free (line);
300
301 /* Do not write more records if there was an error (e.g. no space left on device) */
302 if (G_UNLIKELY (error != NULL))
303 {
304 g_error_free (error);
305 break;
306 }
307
308 /* Step over to next entry */
309 current = verve_history_get_next (current);
310 }
311
312 /* Close file handle */
313 g_io_channel_shutdown (handle, TRUE, &error);
314
315 /* Free error message */
316 if (G_UNLIKELY (error != NULL))
317 g_error_free (error);
318
319 /* Destroy stream object */
320 g_io_channel_unref (handle);
321 }
322 }
323
324 /* Free filename string */
325 g_free (filename);
326 }
327
328 /* vim:set expandtab sts=2 ts=2 sw=2: */
329