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
);
146 mcview_file_load_data (view
, byte_index
);
147 if (mcview_already_loaded (view
->ds_file_offset
, byte_index
, view
->ds_file_datalen
))
148 return (char *) (view
->ds_file_data
+ (byte_index
- view
->ds_file_offset
));
152 /* --------------------------------------------------------------------------------------------- */
155 mcview_get_ptr_string (mcview_t
* view
, off_t byte_index
)
158 assert (view
->datasource
== DS_STRING
);
160 if (byte_index
< (off_t
) view
->ds_string_len
)
161 return (char *) (view
->ds_string_data
+ byte_index
);
165 /* --------------------------------------------------------------------------------------------- */
168 mcview_get_utf (mcview_t
* view
, off_t byte_index
, int *char_width
, gboolean
* result
)
173 gchar
*next_ch
= NULL
;
174 gchar utf8buf
[UTF8_CHAR_LEN
+ 1];
179 switch (view
->datasource
)
183 str
= mcview_get_ptr_growing_buffer (view
, byte_index
);
186 str
= mcview_get_ptr_file (view
, byte_index
);
189 str
= mcview_get_ptr_string (view
, byte_index
);
198 res
= g_utf8_get_char_validated (str
, -1);
202 /* Retry with explicit bytes to make sure it's not a buffer boundary */
204 for (i
= 0; i
< UTF8_CHAR_LEN
; i
++)
206 if (mcview_get_byte (view
, byte_index
+ i
, &res
))
214 utf8buf
[UTF8_CHAR_LEN
] = '\0';
216 res
= g_utf8_get_char_validated (str
, -1);
227 /* Calculate UTF-8 char width */
228 next_ch
= g_utf8_next_char (str
);
230 *char_width
= next_ch
- str
;
238 /* --------------------------------------------------------------------------------------------- */
241 mcview_get_byte_string (mcview_t
* view
, off_t byte_index
, int *retval
)
244 assert (view
->datasource
== DS_STRING
);
246 if (byte_index
< (off_t
) view
->ds_string_len
)
249 *retval
= view
->ds_string_data
[byte_index
];
257 /* --------------------------------------------------------------------------------------------- */
260 mcview_get_byte_none (mcview_t
* view
, off_t byte_index
, int *retval
)
266 assert (view
->datasource
== DS_NONE
);
274 /* --------------------------------------------------------------------------------------------- */
277 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
);
287 view
->ds_file_datalen
= 0; /* just force reloading */
290 /* --------------------------------------------------------------------------------------------- */
294 mcview_file_load_data (mcview_t
* view
, off_t byte_index
)
301 assert (view
->datasource
== DS_FILE
);
304 if (mcview_already_loaded (view
->ds_file_offset
, byte_index
, view
->ds_file_datalen
))
307 if (byte_index
>= view
->ds_file_filesize
)
310 blockoffset
= mcview_offset_rounddown (byte_index
, view
->ds_file_datasize
);
311 if (mc_lseek (view
->ds_file_fd
, blockoffset
, SEEK_SET
) == -1)
315 while (bytes_read
< view
->ds_file_datasize
)
318 mc_read (view
->ds_file_fd
, view
->ds_file_data
+ bytes_read
,
319 view
->ds_file_datasize
- bytes_read
);
324 bytes_read
+= (size_t) res
;
326 view
->ds_file_offset
= blockoffset
;
327 if ((off_t
) bytes_read
> view
->ds_file_filesize
- view
->ds_file_offset
)
329 /* the file has grown in the meantime -- stick to the old size */
330 view
->ds_file_datalen
= view
->ds_file_filesize
- view
->ds_file_offset
;
334 view
->ds_file_datalen
= bytes_read
;
339 view
->ds_file_datalen
= 0;
342 /* --------------------------------------------------------------------------------------------- */
345 mcview_close_datasource (mcview_t
* view
)
347 switch (view
->datasource
)
352 if (view
->ds_stdio_pipe
!= NULL
)
354 (void) pclose (view
->ds_stdio_pipe
);
355 mcview_display (view
);
356 close_error_pipe (D_NORMAL
, NULL
);
357 view
->ds_stdio_pipe
= NULL
;
359 mcview_growbuf_free (view
);
362 if (view
->ds_vfs_pipe
!= -1)
364 (void) mc_close (view
->ds_vfs_pipe
);
365 view
->ds_vfs_pipe
= -1;
367 mcview_growbuf_free (view
);
370 (void) mc_close (view
->ds_file_fd
);
371 view
->ds_file_fd
= -1;
372 g_free (view
->ds_file_data
);
373 view
->ds_file_data
= NULL
;
376 g_free (view
->ds_string_data
);
377 view
->ds_string_data
= NULL
;
381 assert (!"Unknown datasource type")
385 view
->datasource
= DS_NONE
;
388 /* --------------------------------------------------------------------------------------------- */
391 mcview_set_datasource_file (mcview_t
* view
, int fd
, const struct stat
*st
)
393 view
->datasource
= DS_FILE
;
394 view
->ds_file_fd
= fd
;
395 view
->ds_file_filesize
= st
->st_size
;
396 view
->ds_file_offset
= 0;
397 view
->ds_file_data
= g_malloc (4096);
398 view
->ds_file_datalen
= 0;
399 view
->ds_file_datasize
= 4096;
402 /* --------------------------------------------------------------------------------------------- */
405 mcview_load_command_output (mcview_t
* view
, const char *command
)
409 mcview_close_datasource (view
);
412 fp
= popen (command
, "r");
415 /* Avoid two messages. Message from stderr has priority. */
416 mcview_display (view
);
417 if (!close_error_pipe (mcview_is_in_panel (view
) ? -1 : D_ERROR
, NULL
))
418 mcview_show_error (view
, _("Cannot spawn child process"));
422 /* First, check if filter produced any output */
423 mcview_set_datasource_stdio_pipe (view
, fp
);
424 if (!mcview_get_byte (view
, 0, NULL
))
426 mcview_close_datasource (view
);
428 /* Avoid two messages. Message from stderr has priority. */
429 mcview_display (view
);
430 if (!close_error_pipe (mcview_is_in_panel (view
) ? -1 : D_ERROR
, NULL
))
431 mcview_show_error (view
, _("Empty output from child filter"));
437 * At least something was read correctly. Close stderr and let
438 * program die if it will try to write something there.
440 * Ideally stderr should be read asynchronously to prevent programs
441 * from blocking (poll/select multiplexor).
443 close_error_pipe (D_NORMAL
, NULL
);
448 /* --------------------------------------------------------------------------------------------- */
451 mcview_set_datasource_vfs_pipe (mcview_t
* view
, int fd
)
456 view
->datasource
= DS_VFS_PIPE
;
457 view
->ds_vfs_pipe
= fd
;
459 mcview_growbuf_init (view
);
462 /* --------------------------------------------------------------------------------------------- */
465 mcview_set_datasource_string (mcview_t
* view
, const char *s
)
467 view
->datasource
= DS_STRING
;
468 view
->ds_string_data
= (byte
*) g_strdup (s
);
469 view
->ds_string_len
= strlen (s
);
472 /* --------------------------------------------------------------------------------------------- */