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