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 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,
39 The data source provides the viewer with data from either a file, a
40 string or the output of a command. The mcview_get_byte() function can be
41 used to get the value of a byte at a specific offset. If the offset
42 is out of range, -1 is returned. The function mcview_get_byte_indexed(a,b)
43 returns the byte at the offset a+b, or -1 if a+b is out of range.
45 The mcview_set_byte() function has the effect that later calls to
46 mcview_get_byte() will return the specified byte for this offset. This
47 function is designed only for use by the hexedit component after
48 saving its changes. Inspect the source before you want to use it for
51 The mcview_get_filesize() function returns the current size of the
52 data source. If the growing buffer is used, this size may increase
53 later on. Use the mcview_may_still_grow() function when you want to
54 know if the size can change later.
59 #include "lib/global.h"
60 #include "lib/vfs/vfs.h"
62 #include "lib/widget.h" /* D_NORMAL, D_ERROR */
66 /*** global variables ****************************************************************************/
68 /*** file scope macro definitions ****************************************************************/
70 /*** file scope type declarations ****************************************************************/
72 /*** file scope variables ************************************************************************/
74 /*** file scope functions ************************************************************************/
75 /* --------------------------------------------------------------------------------------------- */
77 /* --------------------------------------------------------------------------------------------- */
78 /*** public functions ****************************************************************************/
79 /* --------------------------------------------------------------------------------------------- */
82 mcview_set_datasource_stdio_pipe (mcview_t
* view
, FILE * fp
)
85 view
->datasource
= DS_STDIO_PIPE
;
86 view
->ds_stdio_pipe
= fp
;
88 mcview_growbuf_init (view
);
91 /* --------------------------------------------------------------------------------------------- */
94 mcview_set_datasource_none (mcview_t
* view
)
96 view
->datasource
= DS_NONE
;
99 /* --------------------------------------------------------------------------------------------- */
102 mcview_get_filesize (mcview_t
* view
)
104 switch (view
->datasource
)
110 return mcview_growbuf_filesize (view
);
112 return view
->ds_file_filesize
;
114 return view
->ds_string_len
;
116 assert (!"Unknown datasource type");
121 /* --------------------------------------------------------------------------------------------- */
124 mcview_update_filesize (mcview_t
* view
)
126 if (view
->datasource
== DS_FILE
)
129 if (mc_fstat (view
->ds_file_fd
, &st
) != -1)
130 view
->ds_file_filesize
= st
.st_size
;
134 /* --------------------------------------------------------------------------------------------- */
137 mcview_get_ptr_file (mcview_t
* view
, off_t byte_index
)
139 assert (view
->datasource
== DS_FILE
);
141 mcview_file_load_data (view
, byte_index
);
142 if (mcview_already_loaded (view
->ds_file_offset
, byte_index
, view
->ds_file_datalen
))
143 return (char *) (view
->ds_file_data
+ (byte_index
- view
->ds_file_offset
));
147 /* --------------------------------------------------------------------------------------------- */
150 mcview_get_ptr_string (mcview_t
* view
, off_t byte_index
)
152 assert (view
->datasource
== DS_STRING
);
153 if (byte_index
< (off_t
) view
->ds_string_len
)
154 return (char *) (view
->ds_string_data
+ byte_index
);
158 /* --------------------------------------------------------------------------------------------- */
161 mcview_get_utf (mcview_t
* view
, off_t byte_index
, int *char_width
, gboolean
* result
)
166 gchar
*next_ch
= NULL
;
171 switch (view
->datasource
)
175 str
= mcview_get_ptr_growing_buffer (view
, byte_index
);
178 str
= mcview_get_ptr_file (view
, byte_index
);
181 str
= mcview_get_ptr_string (view
, byte_index
);
190 res
= g_utf8_get_char_validated (str
, -1);
200 /* Calculate UTF-8 char width */
201 next_ch
= g_utf8_next_char (str
);
203 *char_width
= next_ch
- str
;
211 /* --------------------------------------------------------------------------------------------- */
214 mcview_get_byte_string (mcview_t
* view
, off_t byte_index
, int *retval
)
216 assert (view
->datasource
== DS_STRING
);
217 if (byte_index
< (off_t
) view
->ds_string_len
)
220 *retval
= view
->ds_string_data
[byte_index
];
228 /* --------------------------------------------------------------------------------------------- */
231 mcview_get_byte_none (mcview_t
* view
, off_t byte_index
, int *retval
)
233 assert (view
->datasource
== DS_NONE
);
241 /* --------------------------------------------------------------------------------------------- */
244 mcview_set_byte (mcview_t
* view
, off_t offset
, byte b
)
247 assert (offset
< mcview_get_filesize (view
));
248 assert (view
->datasource
== DS_FILE
);
249 view
->ds_file_datalen
= 0; /* just force reloading */
252 /* --------------------------------------------------------------------------------------------- */
256 mcview_file_load_data (mcview_t
* view
, off_t byte_index
)
262 assert (view
->datasource
== DS_FILE
);
264 if (mcview_already_loaded (view
->ds_file_offset
, byte_index
, view
->ds_file_datalen
))
267 if (byte_index
>= view
->ds_file_filesize
)
270 blockoffset
= mcview_offset_rounddown (byte_index
, view
->ds_file_datasize
);
271 if (mc_lseek (view
->ds_file_fd
, blockoffset
, SEEK_SET
) == -1)
275 while (bytes_read
< view
->ds_file_datasize
)
278 mc_read (view
->ds_file_fd
, view
->ds_file_data
+ bytes_read
,
279 view
->ds_file_datasize
- bytes_read
);
284 bytes_read
+= (size_t) res
;
286 view
->ds_file_offset
= blockoffset
;
287 if ((off_t
) bytes_read
> view
->ds_file_filesize
- view
->ds_file_offset
)
289 /* the file has grown in the meantime -- stick to the old size */
290 view
->ds_file_datalen
= view
->ds_file_filesize
- view
->ds_file_offset
;
294 view
->ds_file_datalen
= bytes_read
;
299 view
->ds_file_datalen
= 0;
302 /* --------------------------------------------------------------------------------------------- */
305 mcview_close_datasource (mcview_t
* view
)
307 switch (view
->datasource
)
312 if (view
->ds_stdio_pipe
!= NULL
)
314 (void) pclose (view
->ds_stdio_pipe
);
315 mcview_display (view
);
316 close_error_pipe (D_NORMAL
, NULL
);
317 view
->ds_stdio_pipe
= NULL
;
319 mcview_growbuf_free (view
);
322 if (view
->ds_vfs_pipe
!= -1)
324 (void) mc_close (view
->ds_vfs_pipe
);
325 view
->ds_vfs_pipe
= -1;
327 mcview_growbuf_free (view
);
330 (void) mc_close (view
->ds_file_fd
);
331 view
->ds_file_fd
= -1;
332 g_free (view
->ds_file_data
);
333 view
->ds_file_data
= NULL
;
336 g_free (view
->ds_string_data
);
337 view
->ds_string_data
= NULL
;
340 assert (!"Unknown datasource type");
342 view
->datasource
= DS_NONE
;
345 /* --------------------------------------------------------------------------------------------- */
348 mcview_set_datasource_file (mcview_t
* view
, int fd
, const struct stat
*st
)
350 view
->datasource
= DS_FILE
;
351 view
->ds_file_fd
= fd
;
352 view
->ds_file_filesize
= st
->st_size
;
353 view
->ds_file_offset
= 0;
354 view
->ds_file_data
= g_malloc (4096);
355 view
->ds_file_datalen
= 0;
356 view
->ds_file_datasize
= 4096;
359 /* --------------------------------------------------------------------------------------------- */
362 mcview_load_command_output (mcview_t
* view
, const char *command
)
366 mcview_close_datasource (view
);
369 fp
= popen (command
, "r");
372 /* Avoid two messages. Message from stderr has priority. */
373 mcview_display (view
);
374 if (!close_error_pipe (mcview_is_in_panel (view
) ? -1 : D_ERROR
, NULL
))
375 mcview_show_error (view
, _("Cannot spawn child process"));
379 /* First, check if filter produced any output */
380 mcview_set_datasource_stdio_pipe (view
, fp
);
381 if (!mcview_get_byte (view
, 0, NULL
))
383 mcview_close_datasource (view
);
385 /* Avoid two messages. Message from stderr has priority. */
386 mcview_display (view
);
387 if (!close_error_pipe (mcview_is_in_panel (view
) ? -1 : D_ERROR
, NULL
))
388 mcview_show_error (view
, _("Empty output from child filter"));
394 * At least something was read correctly. Close stderr and let
395 * program die if it will try to write something there.
397 * Ideally stderr should be read asynchronously to prevent programs
398 * from blocking (poll/select multiplexor).
400 close_error_pipe (D_NORMAL
, NULL
);
405 /* --------------------------------------------------------------------------------------------- */
408 mcview_set_datasource_vfs_pipe (mcview_t
* view
, int fd
)
411 view
->datasource
= DS_VFS_PIPE
;
412 view
->ds_vfs_pipe
= fd
;
414 mcview_growbuf_init (view
);
417 /* --------------------------------------------------------------------------------------------- */
420 mcview_set_datasource_string (mcview_t
* view
, const char *s
)
422 view
->datasource
= DS_STRING
;
423 view
->ds_string_data
= (byte
*) g_strdup (s
);
424 view
->ds_string_len
= strlen (s
);
427 /* --------------------------------------------------------------------------------------------- */