Optimization of mcview_hexedit_save_changes() function.
[kaloumi3.git] / src / viewer / hex.c
blob6493719c0b5e16ee10ebf716a555daed2f46b48c
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for hex view
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
8 Written by: 1994, 1995, 1998 Miguel de Icaza
9 1994, 1995 Janne Kukonlehto
10 1995 Jakub Jelinek
11 1996 Joseph M. Hinkle
12 1997 Norbert Warmuth
13 1998 Pavel Machek
14 2004 Roland Illig <roland.illig@gmx.de>
15 2005 Roland Illig <roland.illig@gmx.de>
16 2009 Slava Zanko <slavazanko@google.com>
17 2009 Andrew Borodin <aborodin@vmail.ru>
18 2009 Ilia Maslakov <il.smind@gmail.com>
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software; you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2 of the
25 License, or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be
28 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 MA 02110-1301, USA.
38 #include <config.h>
40 #include <errno.h>
41 #include <fcntl.h>
43 #include "lib/global.h"
44 #include "lib/tty/tty.h"
45 #include "lib/skin.h"
46 #include "src/main.h"
47 #include "src/wtools.h"
48 #include "src/charsets.h"
50 #include "lib/vfs/mc-vfs/vfs.h"
52 #include "internal.h"
54 /*** global variables ****************************************************************************/
56 /*** file scope macro definitions ****************************************************************/
58 /*** file scope type declarations ****************************************************************/
60 typedef enum
62 MARK_NORMAL,
63 MARK_SELECTED,
64 MARK_CURSOR,
65 MARK_CHANGED
66 } mark_t;
68 /*** file scope variables ************************************************************************/
70 static const char hex_char[] = "0123456789ABCDEF";
72 /*** file scope functions ************************************************************************/
74 /*** public functions ****************************************************************************/
76 /* --------------------------------------------------------------------------------------------- */
78 void
79 mcview_display_hex (mcview_t * view)
81 const screen_dimen top = view->data_area.top;
82 const screen_dimen left = view->data_area.left;
83 const screen_dimen height = view->data_area.height;
84 const screen_dimen width = view->data_area.width;
85 const int ngroups = view->bytes_per_line / 4;
86 const screen_dimen text_start = 8 + 13 * ngroups + ((width < 80) ? 0 : (ngroups - 1 + 1));
87 /* 8 characters are used for the file offset, and every hex group
88 * takes 13 characters. On ``big'' screens, the groups are separated
89 * by an extra vertical line, and there is an extra space before the
90 * text column.
93 screen_dimen row, col;
94 off_t from;
95 int c;
96 mark_t boldflag = MARK_NORMAL;
97 struct hexedit_change_node *curr = view->change_list;
98 size_t i;
99 int ch = 0;
101 char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */
102 int bytes; /* Number of bytes already printed on the line */
104 mcview_display_clean (view);
106 /* Find the first displayable changed byte */
107 from = view->dpy_start;
108 while (curr && (curr->offset < from))
110 curr = curr->next;
113 for (row = 0; mcview_get_byte (view, from, NULL) == TRUE && row < height; row++)
115 col = 0;
117 /* Print the hex offset */
118 g_snprintf (hex_buff, sizeof (hex_buff), "%08" OFFSETTYPE_PRIX " ",
119 (long unsigned int) from);
120 widget_move (view, top + row, left);
121 tty_setcolor (MARKED_COLOR);
122 for (i = 0; col < width && hex_buff[i] != '\0'; i++)
124 tty_print_char (hex_buff[i]);
125 /* tty_print_char(hex_buff[i]); */
126 col += 1;
128 tty_setcolor (NORMAL_COLOR);
130 for (bytes = 0; bytes < view->bytes_per_line; bytes++, from++)
133 #ifdef HAVE_CHARSET
134 if (view->utf8)
136 int cw = 1;
137 gboolean read_res = TRUE;
138 ch = mcview_get_utf (view, from, &cw, &read_res);
139 if (!read_res)
140 break;
142 #endif
143 if (!mcview_get_byte (view, from, &c))
144 break;
146 /* Save the cursor position for mcview_place_cursor() */
147 if (from == view->hex_cursor && !view->hexview_in_text)
149 view->cursor_row = row;
150 view->cursor_col = col;
153 /* Determine the state of the current byte */
154 boldflag =
155 (from == view->hex_cursor) ? MARK_CURSOR
156 : (curr != NULL && from == curr->offset) ? MARK_CHANGED
157 : (view->search_start <= from &&
158 from < view->search_end) ? MARK_SELECTED : MARK_NORMAL;
160 /* Determine the value of the current byte */
161 if (curr != NULL && from == curr->offset)
163 c = curr->value;
164 curr = curr->next;
167 /* Select the color for the hex number */
168 tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
169 boldflag == MARK_SELECTED ? MARKED_COLOR :
170 boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
171 /* boldflag == MARK_CURSOR */
172 view->hexview_in_text ? MARKED_SELECTED_COLOR : VIEW_UNDERLINED_COLOR);
174 /* Print the hex number */
175 widget_move (view, top + row, left + col);
176 if (col < width)
178 tty_print_char (hex_char[c / 16]);
179 col += 1;
181 if (col < width)
183 tty_print_char (hex_char[c % 16]);
184 col += 1;
187 /* Print the separator */
188 tty_setcolor (NORMAL_COLOR);
189 if (bytes != view->bytes_per_line - 1)
191 if (col < width)
193 tty_print_char (' ');
194 col += 1;
197 /* After every four bytes, print a group separator */
198 if (bytes % 4 == 3)
200 if (view->data_area.width >= 80 && col < width)
202 tty_print_one_vline ();
203 col += 1;
205 if (col < width)
207 tty_print_char (' ');
208 col += 1;
213 /* Select the color for the character; this differs from the
214 * hex color when boldflag == MARK_CURSOR */
215 tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
216 boldflag == MARK_SELECTED ? MARKED_COLOR :
217 boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
218 /* boldflag == MARK_CURSOR */
219 view->hexview_in_text ? VIEW_UNDERLINED_COLOR : MARKED_SELECTED_COLOR);
221 #ifdef HAVE_CHARSET
222 if (utf8_display)
224 if (!view->utf8)
226 ch = convert_from_8bit_to_utf_c ((unsigned char) ch, view->converter);
228 if (!g_unichar_isprint (ch))
229 ch = '.';
231 else
233 if (view->utf8)
235 ch = convert_from_utf_to_current_c (ch, view->converter);
237 else
239 #endif
240 ch = convert_to_display_c (ch);
241 #ifdef HAVE_CHARSET
244 #endif
245 c = convert_to_display_c (c);
246 if (!g_ascii_isprint (c))
247 c = '.';
249 /* Print corresponding character on the text side */
250 if (text_start + bytes < width)
252 widget_move (view, top + row, left + text_start + bytes);
253 if (!view->utf8)
255 tty_print_char (c);
257 else
259 tty_print_anychar (ch);
263 /* Save the cursor position for mcview_place_cursor() */
264 if (from == view->hex_cursor && view->hexview_in_text)
266 view->cursor_row = row;
267 view->cursor_col = text_start + bytes;
272 /* Be polite to the other functions */
273 tty_setcolor (NORMAL_COLOR);
275 mcview_place_cursor (view);
276 view->dpy_end = from;
279 /* --------------------------------------------------------------------------------------------- */
281 gboolean
282 mcview_hexedit_save_changes (mcview_t * view)
284 int answer = 0;
286 if (view->change_list == NULL)
287 return TRUE;
289 while (answer == 0)
291 int fp;
292 char *text;
293 struct hexedit_change_node *curr, *next;
295 assert (view->filename != NULL);
297 fp = mc_open (view->filename, O_WRONLY);
298 if (fp != -1)
300 for (curr = view->change_list; curr != NULL; curr = next)
302 next = curr->next;
304 if (mc_lseek (fp, curr->offset, SEEK_SET) == -1
305 || mc_write (fp, &(curr->value), 1) != 1)
306 goto save_error;
308 /* delete the saved item from the change list */
309 view->change_list = next;
310 view->dirty++;
311 mcview_set_byte (view, curr->offset, curr->value);
312 g_free (curr);
315 if (mc_close (fp) == -1)
316 message (D_ERROR, _(" Save file "),
317 _(" Error while closing the file: \n %s \n"
318 " Data may have been written or not. "),
319 unix_error_string (errno));
321 view->dirty++;
322 return TRUE;
325 save_error:
326 text = g_strdup_printf (_(" Cannot save file: \n %s "), unix_error_string (errno));
327 (void) mc_close (fp);
329 answer = query_dialog (_(" Save file "), text, D_ERROR, 2, _("&Retry"), _("&Cancel"));
330 g_free (text);
333 return FALSE;
336 /* --------------------------------------------------------------------------------------------- */
338 void
339 mcview_toggle_hexedit_mode (mcview_t * view)
341 view->hexedit_mode = !view->hexedit_mode;
342 view->dpy_bbar_dirty = TRUE;
343 view->dirty++;
346 /* --------------------------------------------------------------------------------------------- */
348 void
349 mcview_hexedit_free_change_list (mcview_t * view)
351 struct hexedit_change_node *curr, *next;
353 for (curr = view->change_list; curr != NULL; curr = next)
355 next = curr->next;
356 g_free (curr);
358 view->change_list = NULL;
359 view->dirty++;
362 /* --------------------------------------------------------------------------------------------- */
364 void
365 mcview_enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node)
367 /* chnode always either points to the head of the list or
368 * to one of the ->next fields in the list. The value at
369 * this location will be overwritten with the new node. */
370 struct hexedit_change_node **chnode = head;
372 while (*chnode != NULL && (*chnode)->offset < node->offset)
373 chnode = &((*chnode)->next);
375 node->next = *chnode;
376 *chnode = node;
379 /* --------------------------------------------------------------------------------------------- */