Merge branch '4524_cleanup'
[midnight-commander.git] / src / file_history.c
blobf4989e79c9554d11d73a0f8dc82260e9baf64ce8
1 /*
2 Load and show history of edited and viewed files
4 Copyright (C) 2020-2024
5 Free Software Foundation, Inc.
7 Written by:
8 Andrew Borodin <aborodin@vmail.ru>, 2019-2022
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <config.h>
28 #include <stdio.h> /* file functions */
30 #include "lib/global.h"
32 #include "lib/fileloc.h" /* MC_FILEPOS_FILE */
33 #include "lib/mcconfig.h" /* mc_config_get_full_path() */
34 #include "lib/strutil.h" /* str_term_width1() */
35 #include "lib/util.h" /* backup functions */
37 #include "file_history.h"
39 /*** global variables ****************************************************************************/
41 /*** file scope macro definitions ****************************************************************/
43 #define TMP_SUFFIX ".tmp"
45 /*** file scope type declarations ****************************************************************/
47 typedef struct file_history_data_t
49 char *file_name;
50 char *file_pos;
51 } file_history_data_t;
53 /*** forward declarations (file scope functions) *************************************************/
55 /*** file scope variables ************************************************************************/
57 /* --------------------------------------------------------------------------------------------- */
58 /*** file scope functions ************************************************************************/
59 /* --------------------------------------------------------------------------------------------- */
61 static GList *
62 file_history_list_read (void)
64 char *fn;
65 FILE *f;
66 char buf[MC_MAXPATHLEN + 100];
67 GList *file_list = NULL;
69 /* open file with positions */
70 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
71 if (fn == NULL)
72 return NULL;
74 f = fopen (fn, "r");
75 g_free (fn);
76 if (f == NULL)
77 return NULL;
79 while (fgets (buf, sizeof (buf), f) != NULL)
81 char *s;
82 file_history_data_t *fhd;
83 size_t len;
85 s = strrchr (buf, ' ');
86 /* FIXME: saved file position info is present in filepos file */
87 fhd = g_new (file_history_data_t, 1);
88 fhd->file_name = g_strndup (buf, s - buf);
89 len = strlen (s + 1);
90 fhd->file_pos = g_strndup (s + 1, len - 1); /* ignore '\n' */
91 file_list = g_list_prepend (file_list, fhd);
94 fclose (f);
96 return file_list;
99 /* --------------------------------------------------------------------------------------------- */
101 static void
102 file_history_list_write (const GList * file_list)
104 char *fn;
105 FILE *f;
106 gboolean write_error = FALSE;
108 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
109 if (fn == NULL)
110 return;
112 mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
114 f = fopen (fn, "w");
115 if (f != NULL)
117 GString *s;
119 s = g_string_sized_new (128);
121 for (; file_list != NULL && !write_error; file_list = g_list_next (file_list))
123 file_history_data_t *fhd = (file_history_data_t *) file_list->data;
125 g_string_append (s, fhd->file_name);
126 if (fhd->file_pos != NULL)
128 g_string_append_c (s, ' ');
129 g_string_append (s, fhd->file_pos);
132 write_error = (fprintf (f, "%s\n", s->str) < 0);
133 g_string_truncate (s, 0);
136 g_string_free (s, TRUE);
138 fclose (f);
141 if (write_error)
142 mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
143 else
144 mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
146 g_free (fn);
149 /* --------------------------------------------------------------------------------------------- */
151 static void
152 file_history_create_item (history_descriptor_t * hd, void *data)
154 file_history_data_t *fhd = (file_history_data_t *) data;
155 size_t width;
157 width = str_term_width1 (fhd->file_name);
158 hd->max_width = MAX (width, hd->max_width);
160 listbox_add_item (hd->listbox, LISTBOX_APPEND_AT_END, 0, fhd->file_name, fhd->file_pos, TRUE);
161 /* fhd->file_pos is not copied, NULLize it to prevent double free */
162 fhd->file_pos = NULL;
165 /* --------------------------------------------------------------------------------------------- */
167 static void *
168 file_history_release_item (history_descriptor_t * hd, WLEntry * le)
170 file_history_data_t *fhd;
172 (void) hd;
174 fhd = g_new (file_history_data_t, 1);
175 fhd->file_name = le->text;
176 le->text = NULL;
177 fhd->file_pos = (char *) le->data;
178 le->data = NULL;
180 return fhd;
183 /* --------------------------------------------------------------------------------------------- */
185 static void
186 file_history_free_item (void *data)
188 file_history_data_t *fhd = (file_history_data_t *) data;
190 g_free (fhd->file_name);
191 g_free (fhd->file_pos);
192 g_free (fhd);
195 /* --------------------------------------------------------------------------------------------- */
196 /*** public functions ****************************************************************************/
197 /* --------------------------------------------------------------------------------------------- */
200 * Show file history and return the selected file
202 * @param w widget used for positioning of history window
203 * @param action to do with file (edit, view, etc)
205 * @return name of selected file, A newly allocated string.
207 char *
208 show_file_history (const Widget * w, int *action)
210 GList *file_list;
211 size_t len;
212 history_descriptor_t hd;
214 file_list = file_history_list_read ();
215 if (file_list == NULL)
216 return NULL;
218 len = g_list_length (file_list);
220 file_list = g_list_last (file_list);
222 history_descriptor_init (&hd, w->rect.y, w->rect.x, file_list, 0);
223 /* redefine list-specific functions */
224 hd.create = file_history_create_item;
225 hd.release = file_history_release_item;
226 hd.free = file_history_free_item;
228 history_show (&hd);
230 hd.list = g_list_first (hd.list);
232 /* Has history cleaned up or not? */
233 if (len != g_list_length (hd.list))
235 hd.list = g_list_reverse (hd.list);
236 file_history_list_write (hd.list);
239 g_list_free_full (hd.list, (GDestroyNotify) file_history_free_item);
241 *action = hd.action;
243 return hd.text;
246 /* --------------------------------------------------------------------------------------------- */