x86_64: Cleanup of code for master
[midnight-commander.git] / src / viewer / hex.c
blob73202f60b3a6bd5bcd202a1aca6e8882da65f931
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 {
61 MARK_NORMAL,
62 MARK_SELECTED,
63 MARK_CURSOR,
64 MARK_CHANGED
65 } mark_t;
67 /*** file scope variables ************************************************************************/
69 static const char hex_char[] = "0123456789ABCDEF";
71 /*** file scope functions ************************************************************************/
73 /*** public functions ****************************************************************************/
75 /* --------------------------------------------------------------------------------------------- */
77 void
78 mcview_display_hex (mcview_t * view)
80 const screen_dimen top = view->data_area.top;
81 const screen_dimen left = view->data_area.left;
82 const screen_dimen height = view->data_area.height;
83 const screen_dimen width = view->data_area.width;
84 const int ngroups = view->bytes_per_line / 4;
85 const screen_dimen text_start = 8 + 13 * ngroups + ((width < 80) ? 0 : (ngroups - 1 + 1));
86 /* 8 characters are used for the file offset, and every hex group
87 * takes 13 characters. On ``big'' screens, the groups are separated
88 * by an extra vertical line, and there is an extra space before the
89 * text column.
92 screen_dimen row, col;
93 off_t from;
94 int c;
95 mark_t boldflag = MARK_NORMAL;
96 struct hexedit_change_node *curr = view->change_list;
97 size_t i;
98 int ch = 0;
100 char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */
101 int bytes; /* Number of bytes already printed on the line */
103 mcview_display_clean (view);
105 /* Find the first displayable changed byte */
106 from = view->dpy_start;
107 while (curr && (curr->offset < from)) {
108 curr = curr->next;
111 for (row = 0; mcview_get_byte (view, from, NULL) == TRUE && row < height; row++) {
112 col = 0;
114 /* Print the hex offset */
115 g_snprintf (hex_buff, sizeof (hex_buff), "%08" OFFSETTYPE_PRIX " ",
116 (long unsigned int) from);
117 widget_move (view, top + row, left);
118 tty_setcolor (MARKED_COLOR);
119 for (i = 0; col < width && hex_buff[i] != '\0'; i++) {
120 tty_print_char (hex_buff[i]);
121 /* tty_print_char(hex_buff[i]);*/
122 col += 1;
124 tty_setcolor (NORMAL_COLOR);
126 for (bytes = 0; bytes < view->bytes_per_line; bytes++, from++) {
128 #ifdef HAVE_CHARSET
129 if (view->utf8) {
130 int cw = 1;
131 gboolean read_res = TRUE;
132 ch = mcview_get_utf (view, from, &cw, &read_res);
133 if (!read_res)
134 break;
136 #endif
137 if (! mcview_get_byte (view, from, &c))
138 break;
140 /* Save the cursor position for mcview_place_cursor() */
141 if (from == view->hex_cursor && !view->hexview_in_text) {
142 view->cursor_row = row;
143 view->cursor_col = col;
146 /* Determine the state of the current byte */
147 boldflag =
148 (from == view->hex_cursor) ? MARK_CURSOR
149 : (curr != NULL && from == curr->offset) ? MARK_CHANGED
150 : (view->search_start <= from &&
151 from < view->search_end) ? MARK_SELECTED : MARK_NORMAL;
153 /* Determine the value of the current byte */
154 if (curr != NULL && from == curr->offset) {
155 c = curr->value;
156 curr = curr->next;
159 /* Select the color for the hex number */
160 tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
161 boldflag == MARK_SELECTED ? MARKED_COLOR :
162 boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
163 /* boldflag == MARK_CURSOR */
164 view->hexview_in_text ? MARKED_SELECTED_COLOR : VIEW_UNDERLINED_COLOR);
166 /* Print the hex number */
167 widget_move (view, top + row, left + col);
168 if (col < width) {
169 tty_print_char (hex_char[c / 16]);
170 col += 1;
172 if (col < width) {
173 tty_print_char (hex_char[c % 16]);
174 col += 1;
177 /* Print the separator */
178 tty_setcolor (NORMAL_COLOR);
179 if (bytes != view->bytes_per_line - 1) {
180 if (col < width) {
181 tty_print_char (' ');
182 col += 1;
185 /* After every four bytes, print a group separator */
186 if (bytes % 4 == 3) {
187 if (view->data_area.width >= 80 && col < width) {
188 tty_print_one_vline ();
189 col += 1;
191 if (col < width) {
192 tty_print_char (' ');
193 col += 1;
198 /* Select the color for the character; this differs from the
199 * hex color when boldflag == MARK_CURSOR */
200 tty_setcolor (boldflag == MARK_NORMAL ? NORMAL_COLOR :
201 boldflag == MARK_SELECTED ? MARKED_COLOR :
202 boldflag == MARK_CHANGED ? VIEW_UNDERLINED_COLOR :
203 /* boldflag == MARK_CURSOR */
204 view->hexview_in_text ? VIEW_UNDERLINED_COLOR : MARKED_SELECTED_COLOR);
206 #ifdef HAVE_CHARSET
207 if (utf8_display) {
208 if (!view->utf8) {
209 ch = convert_from_8bit_to_utf_c ((unsigned char) ch, view->converter);
211 if (!g_unichar_isprint (ch))
212 ch = '.';
213 } else {
214 if (view->utf8) {
215 ch = convert_from_utf_to_current_c (ch, view->converter);
216 } else {
217 #endif
218 ch = convert_to_display_c (ch);
219 #ifdef HAVE_CHARSET
222 #endif
223 c = convert_to_display_c (c);
224 if (!g_ascii_isprint (c))
225 c = '.';
227 /* Print corresponding character on the text side */
228 if (text_start + bytes < width) {
229 widget_move (view, top + row, left + text_start + bytes);
230 if (!view->utf8) {
231 tty_print_char (c);
232 } else {
233 tty_print_anychar (ch);
237 /* Save the cursor position for mcview_place_cursor() */
238 if (from == view->hex_cursor && view->hexview_in_text) {
239 view->cursor_row = row;
240 view->cursor_col = text_start + bytes;
245 /* Be polite to the other functions */
246 tty_setcolor (NORMAL_COLOR);
248 mcview_place_cursor (view);
249 view->dpy_end = from;
252 /* --------------------------------------------------------------------------------------------- */
254 gboolean
255 mcview_hexedit_save_changes (mcview_t * view)
257 struct hexedit_change_node *curr, *next;
258 int fp, answer;
259 char *text, *error;
261 if (view->change_list == NULL)
262 return TRUE;
264 retry_save:
265 assert (view->filename != NULL);
266 fp = mc_open (view->filename, O_WRONLY);
267 if (fp == -1)
268 goto save_error;
270 for (curr = view->change_list; curr != NULL; curr = next) {
271 next = curr->next;
273 if (mc_lseek (fp, curr->offset, SEEK_SET) == -1 || mc_write (fp, &(curr->value), 1) != 1)
274 goto save_error;
276 /* delete the saved item from the change list */
277 view->change_list = next;
278 view->dirty++;
279 mcview_set_byte (view, curr->offset, curr->value);
280 g_free (curr);
283 if (mc_close (fp) == -1) {
284 error = g_strdup (unix_error_string (errno));
285 message (D_ERROR, _(" Save file "),
286 _(" Error while closing the file: \n %s \n"
287 " Data may have been written or not. "), error);
288 g_free (error);
290 mcview_update (view);
291 return TRUE;
293 save_error:
294 error = g_strdup (unix_error_string (errno));
295 text = g_strdup_printf (_(" Cannot save file: \n %s "), error);
296 g_free (error);
297 (void) mc_close (fp);
299 answer = query_dialog (_(" Save file "), text, D_ERROR, 2, _("&Retry"), _("&Cancel"));
300 g_free (text);
302 if (answer == 0)
303 goto retry_save;
304 return FALSE;
307 /* --------------------------------------------------------------------------------------------- */
309 void
310 mcview_toggle_hexedit_mode (mcview_t * view)
312 view->hexedit_mode = !view->hexedit_mode;
313 view->dpy_bbar_dirty = TRUE;
314 view->dirty++;
317 /* --------------------------------------------------------------------------------------------- */
319 void
320 mcview_hexedit_free_change_list (mcview_t * view)
322 struct hexedit_change_node *curr, *next;
324 for (curr = view->change_list; curr != NULL; curr = next) {
325 next = curr->next;
326 g_free (curr);
328 view->change_list = NULL;
329 view->dirty++;
332 /* --------------------------------------------------------------------------------------------- */
334 void
335 mcview_enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node)
337 /* chnode always either points to the head of the list or
338 * to one of the ->next fields in the list. The value at
339 * this location will be overwritten with the new node. */
340 struct hexedit_change_node **chnode = head;
342 while (*chnode != NULL && (*chnode)->offset < node->offset)
343 chnode = &((*chnode)->next);
345 node->next = *chnode;
346 *chnode = node;
349 /* --------------------------------------------------------------------------------------------- */