2 Internal file viewer for the Midnight Commander
3 Functions for datasources
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009, 2011
7 The Free Software Foundation, Inc.
10 Miguel de Icaza, 1994, 1995, 1998
11 Janne Kukonlehto, 1994, 1995
13 Joseph M. Hinkle, 1996
16 Roland Illig <roland.illig@gmx.de>, 2004, 2005
17 Slava Zanko <slavazanko@google.com>, 2009
18 Andrew Borodin <aborodin@vmail.ru>, 2009
19 Ilia Maslakov <il.smind@gmail.com>, 2009
21 This file is part of the Midnight Commander.
23 The Midnight Commander is free software: you can redistribute it
24 and/or modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation, either version 3 of the License,
26 or (at your option) any later version.
28 The Midnight Commander is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with this program. If not, see <http://www.gnu.org/licenses/>.
38 The data source provides the viewer with data from either a file, a
39 string or the output of a command. The mcview_get_byte() function can be
40 used to get the value of a byte at a specific offset. If the offset
41 is out of range, -1 is returned. The function mcview_get_byte_indexed(a,b)
42 returns the byte at the offset a+b, or -1 if a+b is out of range.
44 The mcview_set_byte() function has the effect that later calls to
45 mcview_get_byte() will return the specified byte for this offset. This
46 function is designed only for use by the hexedit component after
47 saving its changes. Inspect the source before you want to use it for
50 The mcview_get_filesize() function returns the current size of the
51 data source. If the growing buffer is used, this size may increase
52 later on. Use the mcview_may_still_grow() function when you want to
53 know if the size can change later.
58 #include "lib/global.h"
59 #include "lib/vfs/vfs.h"
61 #include "lib/widget.h" /* D_NORMAL, D_ERROR */
65 /*** global variables ****************************************************************************/
67 /*** file scope macro definitions ****************************************************************/
69 /*** file scope type declarations ****************************************************************/
71 /*** file scope variables ************************************************************************/
73 /*** file scope functions ************************************************************************/
74 /* --------------------------------------------------------------------------------------------- */
76 /* --------------------------------------------------------------------------------------------- */
77 /*** public functions ****************************************************************************/
78 /* --------------------------------------------------------------------------------------------- */
81 mcview_set_datasource_stdio_pipe (mcview_t
* view
, FILE * fp
)
86 view
->datasource
= DS_STDIO_PIPE
;
87 view
->ds_stdio_pipe
= fp
;
89 mcview_growbuf_init (view
);
92 /* --------------------------------------------------------------------------------------------- */
95 mcview_set_datasource_none (mcview_t
* view
)
97 view
->datasource
= DS_NONE
;
100 /* --------------------------------------------------------------------------------------------- */
103 mcview_get_filesize (mcview_t
* view
)
105 switch (view
->datasource
)
111 return mcview_growbuf_filesize (view
);
113 return view
->ds_file_filesize
;
115 return view
->ds_string_len
;
118 assert (!"Unknown datasource type");
124 /* --------------------------------------------------------------------------------------------- */
127 mcview_update_filesize (mcview_t
* view
)
129 if (view
->datasource
== DS_FILE
)
132 if (mc_fstat (view
->ds_file_fd
, &st
) != -1)
133 view
->ds_file_filesize
= st
.st_size
;
137 /* --------------------------------------------------------------------------------------------- */
140 mcview_get_ptr_file (mcview_t
* view
, off_t byte_index
)
143 assert (view
->datasource
== DS_FILE
);
145 mcview_file_load_data (view
, byte_index
);
146 if (mcview_already_loaded (view
->ds_file_offset
, byte_index
, view
->ds_file_datalen
))
147 return (char *) (view
->ds_file_data
+ (byte_index
- view
->ds_file_offset
));
151 /* --------------------------------------------------------------------------------------------- */
154 mcview_get_ptr_string (mcview_t
* view
, off_t byte_index
)
157 assert (view
->datasource
== DS_STRING
);
159 if (byte_index
< (off_t
) view
->ds_string_len
)
160 return (char *) (view
->ds_string_data
+ byte_index
);
164 /* --------------------------------------------------------------------------------------------- */
167 mcview_get_utf (mcview_t
* view
, off_t byte_index
, int *char_width
, gboolean
* result
)
172 gchar
*next_ch
= NULL
;
173 gchar utf8buf
[UTF8_CHAR_LEN
+ 1];
178 switch (view
->datasource
)
182 str
= mcview_get_ptr_growing_buffer (view
, byte_index
);
185 str
= mcview_get_ptr_file (view
, byte_index
);
188 str
= mcview_get_ptr_string (view
, byte_index
);
197 res
= g_utf8_get_char_validated (str
, -1);
201 /* Retry with explicit bytes to make sure it's not a buffer boundary */
203 for (i
= 0; i
< UTF8_CHAR_LEN
; i
++)
205 if (mcview_get_byte (view
, byte_index
+ i
, &res
))
213 utf8buf
[UTF8_CHAR_LEN
] = '\0';
215 res
= g_utf8_get_char_validated (str
, -1);
226 /* Calculate UTF-8 char width */
227 next_ch
= g_utf8_next_char (str
);
229 *char_width
= next_ch
- str
;
237 /* --------------------------------------------------------------------------------------------- */
240 mcview_get_byte_string (mcview_t
* view
, off_t byte_index
, int *retval
)
243 assert (view
->datasource
== DS_STRING
);
245 if (byte_index
< (off_t
) view
->ds_string_len
)
248 *retval
= view
->ds_string_data
[byte_index
];
256 /* --------------------------------------------------------------------------------------------- */
259 mcview_get_byte_none (mcview_t
* view
, off_t byte_index
, int *retval
)
265 assert (view
->datasource
== DS_NONE
);
273 /* --------------------------------------------------------------------------------------------- */
276 mcview_set_byte (mcview_t
* view
, off_t offset
, byte b
)
280 #ifndef HAVE_ASSERT_H
283 assert (offset
< mcview_get_filesize (view
));
284 assert (view
->datasource
== DS_FILE
);
286 view
->ds_file_datalen
= 0; /* just force reloading */
289 /* --------------------------------------------------------------------------------------------- */
293 mcview_file_load_data (mcview_t
* view
, off_t byte_index
)
300 assert (view
->datasource
== DS_FILE
);
303 if (mcview_already_loaded (view
->ds_file_offset
, byte_index
, view
->ds_file_datalen
))
306 if (byte_index
>= view
->ds_file_filesize
)
309 blockoffset
= mcview_offset_rounddown (byte_index
, view
->ds_file_datasize
);
310 if (mc_lseek (view
->ds_file_fd
, blockoffset
, SEEK_SET
) == -1)
314 while (bytes_read
< view
->ds_file_datasize
)
317 mc_read (view
->ds_file_fd
, view
->ds_file_data
+ bytes_read
,
318 view
->ds_file_datasize
- bytes_read
);
323 bytes_read
+= (size_t) res
;
325 view
->ds_file_offset
= blockoffset
;
326 if ((off_t
) bytes_read
> view
->ds_file_filesize
- view
->ds_file_offset
)
328 /* the file has grown in the meantime -- stick to the old size */
329 view
->ds_file_datalen
= view
->ds_file_filesize
- view
->ds_file_offset
;
333 view
->ds_file_datalen
= bytes_read
;
338 view
->ds_file_datalen
= 0;
341 /* --------------------------------------------------------------------------------------------- */
344 mcview_close_datasource (mcview_t
* view
)
346 switch (view
->datasource
)
351 if (view
->ds_stdio_pipe
!= NULL
)
353 (void) pclose (view
->ds_stdio_pipe
);
354 mcview_display (view
);
355 close_error_pipe (D_NORMAL
, NULL
);
356 view
->ds_stdio_pipe
= NULL
;
358 mcview_growbuf_free (view
);
361 if (view
->ds_vfs_pipe
!= -1)
363 (void) mc_close (view
->ds_vfs_pipe
);
364 view
->ds_vfs_pipe
= -1;
366 mcview_growbuf_free (view
);
369 (void) mc_close (view
->ds_file_fd
);
370 view
->ds_file_fd
= -1;
371 g_free (view
->ds_file_data
);
372 view
->ds_file_data
= NULL
;
375 g_free (view
->ds_string_data
);
376 view
->ds_string_data
= NULL
;
380 assert (!"Unknown datasource type")
384 view
->datasource
= DS_NONE
;
387 /* --------------------------------------------------------------------------------------------- */
390 mcview_set_datasource_file (mcview_t
* view
, int fd
, const struct stat
*st
)
392 view
->datasource
= DS_FILE
;
393 view
->ds_file_fd
= fd
;
394 view
->ds_file_filesize
= st
->st_size
;
395 view
->ds_file_offset
= 0;
396 view
->ds_file_data
= g_malloc (4096);
397 view
->ds_file_datalen
= 0;
398 view
->ds_file_datasize
= 4096;
401 /* --------------------------------------------------------------------------------------------- */
404 mcview_load_command_output (mcview_t
* view
, const char *command
)
408 mcview_close_datasource (view
);
411 fp
= popen (command
, "r");
414 /* Avoid two messages. Message from stderr has priority. */
415 mcview_display (view
);
416 if (!close_error_pipe (mcview_is_in_panel (view
) ? -1 : D_ERROR
, NULL
))
417 mcview_show_error (view
, _("Cannot spawn child process"));
421 /* First, check if filter produced any output */
422 mcview_set_datasource_stdio_pipe (view
, fp
);
423 if (!mcview_get_byte (view
, 0, NULL
))
425 mcview_close_datasource (view
);
427 /* Avoid two messages. Message from stderr has priority. */
428 mcview_display (view
);
429 if (!close_error_pipe (mcview_is_in_panel (view
) ? -1 : D_ERROR
, NULL
))
430 mcview_show_error (view
, _("Empty output from child filter"));
436 * At least something was read correctly. Close stderr and let
437 * program die if it will try to write something there.
439 * Ideally stderr should be read asynchronously to prevent programs
440 * from blocking (poll/select multiplexor).
442 close_error_pipe (D_NORMAL
, NULL
);
447 /* --------------------------------------------------------------------------------------------- */
450 mcview_set_datasource_vfs_pipe (mcview_t
* view
, int fd
)
455 view
->datasource
= DS_VFS_PIPE
;
456 view
->ds_vfs_pipe
= fd
;
458 mcview_growbuf_init (view
);
461 /* --------------------------------------------------------------------------------------------- */
464 mcview_set_datasource_string (mcview_t
* view
, const char *s
)
466 view
->datasource
= DS_STRING
;
467 view
->ds_string_data
= (byte
*) g_strdup (s
);
468 view
->ds_string_len
= strlen (s
);
471 /* --------------------------------------------------------------------------------------------- */