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 ****************************************************************/
67 /*** file scope variables ************************************************************************/
69 static const char hex_char
[] = "0123456789ABCDEF";
71 /*** file scope functions ************************************************************************/
73 /*** public functions ****************************************************************************/
75 /* --------------------------------------------------------------------------------------------- */
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
92 screen_dimen row
, col
;
95 mark_t boldflag
= MARK_NORMAL
;
96 struct hexedit_change_node
*curr
= view
->change_list
;
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
)) {
111 for (row
= 0; mcview_get_byte (view
, from
, NULL
) == TRUE
&& row
< height
; row
++) {
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]);*/
124 tty_setcolor (NORMAL_COLOR
);
126 for (bytes
= 0; bytes
< view
->bytes_per_line
; bytes
++, from
++) {
131 gboolean read_res
= TRUE
;
132 ch
= mcview_get_utf (view
, from
, &cw
, &read_res
);
137 if (! mcview_get_byte (view
, from
, &c
))
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 */
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
) {
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
);
169 tty_print_char (hex_char
[c
/ 16]);
173 tty_print_char (hex_char
[c
% 16]);
177 /* Print the separator */
178 tty_setcolor (NORMAL_COLOR
);
179 if (bytes
!= view
->bytes_per_line
- 1) {
181 tty_print_char (' ');
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 ();
192 tty_print_char (' ');
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
);
209 ch
= convert_from_8bit_to_utf_c ((unsigned char) ch
, view
->converter
);
211 if (!g_unichar_isprint (ch
))
215 ch
= convert_from_utf_to_current_c (ch
, view
->converter
);
218 ch
= convert_to_display_c (ch
);
223 c
= convert_to_display_c (c
);
224 if (!g_ascii_isprint (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
);
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 /* --------------------------------------------------------------------------------------------- */
255 mcview_hexedit_save_changes (mcview_t
* view
)
257 struct hexedit_change_node
*curr
, *next
;
261 if (view
->change_list
== NULL
)
265 assert (view
->filename
!= NULL
);
266 fp
= mc_open (view
->filename
, O_WRONLY
);
270 for (curr
= view
->change_list
; curr
!= NULL
; curr
= next
) {
273 if (mc_lseek (fp
, curr
->offset
, SEEK_SET
) == -1 || mc_write (fp
, &(curr
->value
), 1) != 1)
276 /* delete the saved item from the change list */
277 view
->change_list
= next
;
279 mcview_set_byte (view
, curr
->offset
, curr
->value
);
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
);
290 mcview_update (view
);
294 error
= g_strdup (unix_error_string (errno
));
295 text
= g_strdup_printf (_(" Cannot save file: \n %s "), error
);
297 (void) mc_close (fp
);
299 answer
= query_dialog (_(" Save file "), text
, D_ERROR
, 2, _("&Retry"), _("&Cancel"));
307 /* --------------------------------------------------------------------------------------------- */
310 mcview_toggle_hexedit_mode (mcview_t
* view
)
312 view
->hexedit_mode
= !view
->hexedit_mode
;
313 view
->dpy_bbar_dirty
= TRUE
;
317 /* --------------------------------------------------------------------------------------------- */
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
) {
328 view
->change_list
= NULL
;
332 /* --------------------------------------------------------------------------------------------- */
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
;
349 /* --------------------------------------------------------------------------------------------- */