root/src/file_history.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. file_history_list_read
  2. file_history_list_write
  3. file_history_create_item
  4. file_history_release_item
  5. file_history_free_item
  6. show_file_history

   1 /*
   2    Load and show history of edited and viewed files
   3 
   4    Copyright (C) 2020-2024
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Andrew Borodin <aborodin@vmail.ru>, 2019-2022
   9 
  10    This file is part of the Midnight Commander.
  11 
  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.
  16 
  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.
  21 
  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/>.
  24  */
  25 
  26 #include <config.h>
  27 
  28 #include <stdio.h>              /* file functions */
  29 
  30 #include "lib/global.h"
  31 
  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 */
  36 
  37 #include "file_history.h"
  38 
  39 /*** global variables ****************************************************************************/
  40 
  41 /*** file scope macro definitions ****************************************************************/
  42 
  43 #define TMP_SUFFIX ".tmp"
  44 
  45 /*** file scope type declarations ****************************************************************/
  46 
  47 typedef struct file_history_data_t
  48 {
  49     char *file_name;
  50     char *file_pos;
  51 } file_history_data_t;
  52 
  53 /*** forward declarations (file scope functions) *************************************************/
  54 
  55 /*** file scope variables ************************************************************************/
  56 
  57 /* --------------------------------------------------------------------------------------------- */
  58 /*** file scope functions ************************************************************************/
  59 /* --------------------------------------------------------------------------------------------- */
  60 
  61 static GList *
  62 file_history_list_read (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  63 {
  64     char *fn;
  65     FILE *f;
  66     char buf[MC_MAXPATHLEN + 100];
  67     GList *file_list = NULL;
  68 
  69     /* open file with positions */
  70     fn = mc_config_get_full_path (MC_FILEPOS_FILE);
  71     if (fn == NULL)
  72         return NULL;
  73 
  74     f = fopen (fn, "r");
  75     g_free (fn);
  76     if (f == NULL)
  77         return NULL;
  78 
  79     while (fgets (buf, sizeof (buf), f) != NULL)
  80     {
  81         char *s;
  82         file_history_data_t *fhd;
  83         size_t len;
  84 
  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);
  92     }
  93 
  94     fclose (f);
  95 
  96     return file_list;
  97 }
  98 
  99 /* --------------------------------------------------------------------------------------------- */
 100 
 101 static void
 102 file_history_list_write (const GList *file_list)
     /* [previous][next][first][last][top][bottom][index][help]  */
 103 {
 104     char *fn;
 105     FILE *f;
 106     gboolean write_error = FALSE;
 107 
 108     fn = mc_config_get_full_path (MC_FILEPOS_FILE);
 109     if (fn == NULL)
 110         return;
 111 
 112     mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
 113 
 114     f = fopen (fn, "w");
 115     if (f != NULL)
 116     {
 117         GString *s;
 118 
 119         s = g_string_sized_new (128);
 120 
 121         for (; file_list != NULL && !write_error; file_list = g_list_next (file_list))
 122         {
 123             file_history_data_t *fhd = (file_history_data_t *) file_list->data;
 124 
 125             g_string_append (s, fhd->file_name);
 126             if (fhd->file_pos != NULL)
 127             {
 128                 g_string_append_c (s, ' ');
 129                 g_string_append (s, fhd->file_pos);
 130             }
 131 
 132             write_error = (fprintf (f, "%s\n", s->str) < 0);
 133             g_string_truncate (s, 0);
 134         }
 135 
 136         g_string_free (s, TRUE);
 137 
 138         fclose (f);
 139     }
 140 
 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);
 145 
 146     g_free (fn);
 147 }
 148 
 149 /* --------------------------------------------------------------------------------------------- */
 150 
 151 static void
 152 file_history_create_item (history_descriptor_t *hd, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 153 {
 154     file_history_data_t *fhd = (file_history_data_t *) data;
 155     size_t width;
 156 
 157     width = str_term_width1 (fhd->file_name);
 158     hd->max_width = MAX (width, hd->max_width);
 159 
 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;
 163 }
 164 
 165 /* --------------------------------------------------------------------------------------------- */
 166 
 167 static void *
 168 file_history_release_item (history_descriptor_t *hd, WLEntry *le)
     /* [previous][next][first][last][top][bottom][index][help]  */
 169 {
 170     file_history_data_t *fhd;
 171 
 172     (void) hd;
 173 
 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;
 179 
 180     return fhd;
 181 }
 182 
 183 /* --------------------------------------------------------------------------------------------- */
 184 
 185 static void
 186 file_history_free_item (void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 187 {
 188     file_history_data_t *fhd = (file_history_data_t *) data;
 189 
 190     g_free (fhd->file_name);
 191     g_free (fhd->file_pos);
 192     g_free (fhd);
 193 }
 194 
 195 /* --------------------------------------------------------------------------------------------- */
 196 /*** public functions ****************************************************************************/
 197 /* --------------------------------------------------------------------------------------------- */
 198 
 199 /**
 200  * Show file history and return the selected file
 201  *
 202  * @param w widget used for positioning of history window
 203  * @param action to do with file (edit, view, etc)
 204  *
 205  * @return name of selected file, A newly allocated string.
 206  */
 207 char *
 208 show_file_history (const Widget *w, int *action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 209 {
 210     GList *file_list;
 211     size_t len;
 212     history_descriptor_t hd;
 213 
 214     file_list = file_history_list_read ();
 215     if (file_list == NULL)
 216         return NULL;
 217 
 218     len = g_list_length (file_list);
 219 
 220     file_list = g_list_last (file_list);
 221 
 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;
 227 
 228     history_show (&hd);
 229 
 230     hd.list = g_list_first (hd.list);
 231 
 232     /* Has history cleaned up or not? */
 233     if (len != g_list_length (hd.list))
 234     {
 235         hd.list = g_list_reverse (hd.list);
 236         file_history_list_write (hd.list);
 237     }
 238 
 239     g_list_free_full (hd.list, (GDestroyNotify) file_history_free_item);
 240 
 241     *action = hd.action;
 242 
 243     return hd.text;
 244 }
 245 
 246 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */