2 Internal file viewer for the Midnight Commander
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
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,
43 #include "lib/global.h"
44 #include "lib/tty/tty.h"
47 #include "src/wtools.h"
48 #include "src/charsets.h"
50 #include "lib/vfs/mc-vfs/vfs.h"
54 /*** global variables ****************************************************************************/
56 /*** file scope macro definitions ****************************************************************/
58 /*** file scope type declarations ****************************************************************/
68 /*** file scope variables ************************************************************************/
70 static const char hex_char
[] = "0123456789ABCDEF";
72 /*** file scope functions ************************************************************************/
74 /*** public functions ****************************************************************************/
76 /* --------------------------------------------------------------------------------------------- */
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
93 screen_dimen row
, col
;
96 mark_t boldflag
= MARK_NORMAL
;
97 struct hexedit_change_node
*curr
= view
->change_list
;
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
))
113 for (row
= 0; mcview_get_byte (view
, from
, NULL
) == TRUE
&& row
< height
; row
++)
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]); */
128 tty_setcolor (NORMAL_COLOR
);
130 for (bytes
= 0; bytes
< view
->bytes_per_line
; bytes
++, from
++)
137 gboolean read_res
= TRUE
;
138 ch
= mcview_get_utf (view
, from
, &cw
, &read_res
);
143 if (!mcview_get_byte (view
, from
, &c
))
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 */
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
)
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
);
178 tty_print_char (hex_char
[c
/ 16]);
183 tty_print_char (hex_char
[c
% 16]);
187 /* Print the separator */
188 tty_setcolor (NORMAL_COLOR
);
189 if (bytes
!= view
->bytes_per_line
- 1)
193 tty_print_char (' ');
197 /* After every four bytes, print a group separator */
200 if (view
->data_area
.width
>= 80 && col
< width
)
202 tty_print_one_vline ();
207 tty_print_char (' ');
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
);
226 ch
= convert_from_8bit_to_utf_c ((unsigned char) ch
, view
->converter
);
228 if (!g_unichar_isprint (ch
))
235 ch
= convert_from_utf_to_current_c (ch
, view
->converter
);
240 ch
= convert_to_display_c (ch
);
245 c
= convert_to_display_c (c
);
246 if (!g_ascii_isprint (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
);
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 /* --------------------------------------------------------------------------------------------- */
282 mcview_hexedit_save_changes (mcview_t
* view
)
286 if (view
->change_list
== NULL
)
293 struct hexedit_change_node
*curr
, *next
;
295 assert (view
->filename
!= NULL
);
297 fp
= mc_open (view
->filename
, O_WRONLY
);
300 for (curr
= view
->change_list
; curr
!= NULL
; curr
= next
)
304 if (mc_lseek (fp
, curr
->offset
, SEEK_SET
) == -1
305 || mc_write (fp
, &(curr
->value
), 1) != 1)
308 /* delete the saved item from the change list */
309 view
->change_list
= next
;
311 mcview_set_byte (view
, curr
->offset
, curr
->value
);
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
));
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"));
336 /* --------------------------------------------------------------------------------------------- */
339 mcview_toggle_hexedit_mode (mcview_t
* view
)
341 view
->hexedit_mode
= !view
->hexedit_mode
;
342 view
->dpy_bbar_dirty
= TRUE
;
346 /* --------------------------------------------------------------------------------------------- */
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
)
358 view
->change_list
= NULL
;
362 /* --------------------------------------------------------------------------------------------- */
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
;
379 /* --------------------------------------------------------------------------------------------- */