Optimization of ini files load.
[midnight-commander.git] / lib / widget / history.c
blob55daa2894577755e07592c48bde2659429397848
1 /*
2 Widgets for the Midnight Commander
4 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012
6 The Free Software Foundation, Inc.
8 Authors:
9 Radek Doulik, 1994, 1995
10 Miguel de Icaza, 1994, 1995
11 Jakub Jelinek, 1995
12 Andrej Borsenkow, 1996
13 Norbert Warmuth, 1997
14 Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012
16 This file is part of the Midnight Commander.
18 The Midnight Commander is free software: you can redistribute it
19 and/or modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation, either version 3 of the License,
21 or (at your option) any later version.
23 The Midnight Commander is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 /** \file history.c
33 * \brief Source: save, load and show history
36 #include <config.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
46 #include "lib/global.h"
48 #include "lib/tty/tty.h" /* LINES, COLS */
49 #include "lib/mcconfig.h" /* for history loading and saving */
50 #include "lib/fileloc.h"
51 #include "lib/strutil.h"
52 #include "lib/util.h" /* list_append_unique */
53 #include "lib/widget.h"
55 /*** global variables ****************************************************************************/
57 /* how much history items are used */
58 int num_history_items_recorded = 60;
60 /*** file scope macro definitions ****************************************************************/
62 /*** file scope type declarations ****************************************************************/
64 typedef struct
66 Widget *widget;
67 size_t count;
68 size_t maxlen;
69 } history_dlg_data;
71 /*** file scope variables ************************************************************************/
73 /*** file scope functions ************************************************************************/
75 static cb_ret_t
76 history_dlg_reposition (Dlg_head * dlg_head)
78 history_dlg_data *data;
79 int x = 0, y, he, wi;
81 /* guard checks */
82 if ((dlg_head == NULL) || (dlg_head->data == NULL))
83 return MSG_NOT_HANDLED;
85 data = (history_dlg_data *) dlg_head->data;
87 y = data->widget->y;
88 he = data->count + 2;
90 if (he <= y || y > (LINES - 6))
92 he = min (he, y - 1);
93 y -= he;
95 else
97 y++;
98 he = min (he, LINES - y);
101 if (data->widget->x > 2)
102 x = data->widget->x - 2;
104 wi = data->maxlen + 4;
106 if ((wi + x) > COLS)
108 wi = min (wi, COLS);
109 x = COLS - wi;
112 dlg_set_position (dlg_head, y, x, y + he, x + wi);
114 return MSG_HANDLED;
117 /* --------------------------------------------------------------------------------------------- */
119 static cb_ret_t
120 history_dlg_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
122 switch (msg)
124 case DLG_RESIZE:
125 return history_dlg_reposition (h);
127 default:
128 return default_dlg_callback (h, sender, msg, parm, data);
132 /* --------------------------------------------------------------------------------------------- */
133 /*** public functions ****************************************************************************/
134 /* --------------------------------------------------------------------------------------------- */
137 * Load the history from the ${XDG_CACHE_HOME}/mc/history file.
138 * It is called with the widgets history name and returns the GList list.
141 GList *
142 history_get (const char *input_name)
144 GList *hist = NULL;
145 char *profile;
146 mc_config_t *cfg;
148 if (num_history_items_recorded == 0) /* this is how to disable */
149 return NULL;
150 if ((input_name == NULL) || (*input_name == '\0'))
151 return NULL;
153 profile = mc_config_get_full_path (MC_HISTORY_FILE);
154 cfg = mc_config_init (profile, TRUE);
156 hist = history_load (cfg, input_name);
158 mc_config_deinit (cfg);
159 g_free (profile);
161 return hist;
164 /* --------------------------------------------------------------------------------------------- */
167 * Load history form the mc_config
169 GList *
170 history_load (struct mc_config_t * cfg, const char *name)
172 size_t i;
173 GList *hist = NULL;
174 char **keys;
175 size_t keys_num = 0;
176 GIConv conv = INVALID_CONV;
177 GString *buffer;
179 if (name == NULL || *name == '\0')
180 return NULL;
182 /* get number of keys */
183 keys = mc_config_get_keys (cfg, name, &keys_num);
184 g_strfreev (keys);
186 /* create charset conversion handler to convert strings
187 from utf-8 to system codepage */
188 if (!mc_global.utf8_display)
189 conv = str_crt_conv_from ("UTF-8");
191 buffer = g_string_sized_new (64);
193 for (i = 0; i < keys_num; i++)
195 char key[BUF_TINY];
196 char *this_entry;
198 g_snprintf (key, sizeof (key), "%lu", (unsigned long) i);
199 this_entry = mc_config_get_string_raw (cfg, name, key, "");
201 if (this_entry == NULL)
202 continue;
204 if (conv == INVALID_CONV)
205 hist = list_append_unique (hist, this_entry);
206 else
208 g_string_set_size (buffer, 0);
209 if (str_convert (conv, this_entry, buffer) == ESTR_FAILURE)
210 hist = list_append_unique (hist, this_entry);
211 else
213 hist = list_append_unique (hist, g_strdup (buffer->str));
214 g_free (this_entry);
219 g_string_free (buffer, TRUE);
220 if (conv != INVALID_CONV)
221 str_close_conv (conv);
223 /* return pointer to the last entry in the list */
224 return g_list_last (hist);
227 /* --------------------------------------------------------------------------------------------- */
230 * Save history to the mc_config, but don't save config to file
232 void
233 history_save (struct mc_config_t *cfg, const char *name, GList * h)
235 GIConv conv = INVALID_CONV;
236 GString *buffer;
237 int i;
239 if (name == NULL || *name == '\0' || h == NULL)
240 return;
242 /* go to end of list */
243 h = g_list_last (h);
245 /* go back 60 places */
246 for (i = 0; (i < num_history_items_recorded - 1) && (h->prev != NULL); i++)
247 h = g_list_previous (h);
249 if (name != NULL)
250 mc_config_del_group (cfg, name);
252 /* create charset conversion handler to convert strings
253 from system codepage to UTF-8 */
254 if (!mc_global.utf8_display)
255 conv = str_crt_conv_to ("UTF-8");
257 buffer = g_string_sized_new (64);
258 /* dump history into profile */
259 for (i = 0; h != NULL; h = g_list_next (h))
261 char key[BUF_TINY];
262 char *text = (char *) h->data;
264 /* We shouldn't have null entries, but let's be sure */
265 if (text == NULL)
266 continue;
268 g_snprintf (key, sizeof (key), "%d", i++);
270 if (conv == INVALID_CONV)
271 mc_config_set_string_raw (cfg, name, key, text);
272 else
274 g_string_set_size (buffer, 0);
275 if (str_convert (conv, text, buffer) == ESTR_FAILURE)
276 mc_config_set_string_raw (cfg, name, key, text);
277 else
278 mc_config_set_string_raw (cfg, name, key, buffer->str);
282 g_string_free (buffer, TRUE);
283 if (conv != INVALID_CONV)
284 str_close_conv (conv);
287 /* --------------------------------------------------------------------------------------------- */
289 char *
290 history_show (GList ** history, Widget * widget, int current)
292 GList *z, *hlist = NULL, *hi;
293 size_t maxlen, i, count = 0;
294 char *r = NULL;
295 Dlg_head *query_dlg;
296 WListbox *query_list;
297 history_dlg_data hist_data;
299 if (*history == NULL)
300 return NULL;
302 maxlen = str_term_width1 (_("History")) + 2;
304 for (z = *history; z != NULL; z = g_list_previous (z))
306 WLEntry *entry;
308 i = str_term_width1 ((char *) z->data);
309 maxlen = max (maxlen, i);
310 count++;
312 entry = g_new0 (WLEntry, 1);
313 /* history is being reverted here */
314 entry->text = g_strdup ((char *) z->data);
315 hlist = g_list_prepend (hlist, entry);
318 hist_data.widget = widget;
319 hist_data.count = count;
320 hist_data.maxlen = maxlen;
322 query_dlg =
323 create_dlg (TRUE, 0, 0, 4, 4, dialog_colors, history_dlg_callback,
324 "[History-query]", _("History"), DLG_COMPACT);
325 query_dlg->data = &hist_data;
327 query_list = listbox_new (1, 1, 2, 2, TRUE, NULL);
329 /* this call makes list stick to all sides of dialog, effectively make
330 it be resized with dialog */
331 add_widget_autopos (query_dlg, query_list, WPOS_KEEP_ALL);
333 /* to avoid diplicating of (calculating sizes in two places)
334 code, call dlg_hist_callback function here, to set dialog and
335 controls positions.
336 The main idea - create 4x4 dialog and add 2x2 list in
337 center of it, and let dialog function resize it to needed
338 size. */
339 history_dlg_callback (query_dlg, NULL, DLG_RESIZE, 0, NULL);
341 if (query_dlg->y < widget->y)
343 /* draw list entries from bottom upto top */
344 listbox_set_list (query_list, hlist);
345 if (current < 0 || (size_t) current >= count)
346 listbox_select_last (query_list);
347 else
348 listbox_select_entry (query_list, count - 1 - (size_t) current);
350 else
352 /* draw list entries from top downto bottom */
353 /* revert history direction */
354 hlist = g_list_reverse (hlist);
355 listbox_set_list (query_list, hlist);
356 if (current > 0)
357 listbox_select_entry (query_list, current);
360 if (run_dlg (query_dlg) != B_CANCEL)
362 char *q;
364 listbox_get_current (query_list, &q, NULL);
365 r = g_strdup (q);
368 /* get modified history from dialog */
369 z = NULL;
370 for (hi = query_list->list; hi != NULL; hi = g_list_next (hi))
372 WLEntry *entry;
374 entry = (WLEntry *) hi->data;
375 /* history is being reverted here again */
376 z = g_list_prepend (z, entry->text);
377 entry->text = NULL;
380 /* restore history direction */
381 if (query_dlg->y < widget->y)
382 z = g_list_reverse (z);
384 destroy_dlg (query_dlg);
386 g_list_foreach (*history, (GFunc) g_free, NULL);
387 g_list_free (*history);
388 *history = g_list_last (z);
390 return r;
393 /* --------------------------------------------------------------------------------------------- */