Set WOP_TOP_SELECT options for panel widgets: WPanel, WView and WTree.
[midnight-commander.git] / src / viewer / datasource.c
blob0379be413da781093850c73c36cf508c87aaf465
1 /*
2 Internal file viewer for the Midnight Commander
3 Functions for datasources
5 Copyright (C) 1994-2016
6 Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
11 Jakub Jelinek, 1995
12 Joseph M. Hinkle, 1996
13 Norbert Warmuth, 1997
14 Pavel Machek, 1998
15 Roland Illig <roland.illig@gmx.de>, 2004, 2005
16 Slava Zanko <slavazanko@google.com>, 2009
17 Andrew Borodin <aborodin@vmail.ru>, 2009
18 Ilia Maslakov <il.smind@gmail.com>, 2009
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 3 of the License,
25 or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU 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, see <http://www.gnu.org/licenses/>.
37 The data source provides the viewer with data from either a file, a
38 string or the output of a command. The mcview_get_byte() function can be
39 used to get the value of a byte at a specific offset. If the offset
40 is out of range, -1 is returned. The function mcview_get_byte_indexed(a,b)
41 returns the byte at the offset a+b, or -1 if a+b is out of range.
43 The mcview_set_byte() function has the effect that later calls to
44 mcview_get_byte() will return the specified byte for this offset. This
45 function is designed only for use by the hexedit component after
46 saving its changes. Inspect the source before you want to use it for
47 other purposes.
49 The mcview_get_filesize() function returns the current size of the
50 data source. If the growing buffer is used, this size may increase
51 later on. Use the mcview_may_still_grow() function when you want to
52 know if the size can change later.
55 #include <config.h>
57 #include "lib/global.h"
58 #include "lib/vfs/vfs.h"
59 #include "lib/util.h"
60 #include "lib/widget.h" /* D_NORMAL, D_ERROR */
62 #include "internal.h"
64 /*** global variables ****************************************************************************/
66 /*** file scope macro definitions ****************************************************************/
68 /*** file scope type declarations ****************************************************************/
70 /*** file scope variables ************************************************************************/
72 /* --------------------------------------------------------------------------------------------- */
73 /*** file scope functions ************************************************************************/
74 /* --------------------------------------------------------------------------------------------- */
76 static void
77 mcview_set_datasource_stdio_pipe (WView * view, mc_pipe_t * p)
79 p->out.len = MC_PIPE_BUFSIZE;
80 p->out.null_term = FALSE;
81 p->err.len = MC_PIPE_BUFSIZE;
82 p->err.null_term = TRUE;
83 view->datasource = DS_STDIO_PIPE;
84 view->ds_stdio_pipe = p;
85 view->pipe_first_err_msg = TRUE;
87 mcview_growbuf_init (view);
90 /* --------------------------------------------------------------------------------------------- */
91 /*** public functions ****************************************************************************/
92 /* --------------------------------------------------------------------------------------------- */
94 void
95 mcview_set_datasource_none (WView * view)
97 view->datasource = DS_NONE;
100 /* --------------------------------------------------------------------------------------------- */
102 off_t
103 mcview_get_filesize (WView * view)
105 switch (view->datasource)
107 case DS_NONE:
108 return 0;
109 case DS_STDIO_PIPE:
110 case DS_VFS_PIPE:
111 return mcview_growbuf_filesize (view);
112 case DS_FILE:
113 return view->ds_file_filesize;
114 case DS_STRING:
115 return view->ds_string_len;
116 default:
117 #ifdef HAVE_ASSERT_H
118 assert (!"Unknown datasource type");
119 #endif
120 return 0;
124 /* --------------------------------------------------------------------------------------------- */
126 void
127 mcview_update_filesize (WView * view)
129 if (view->datasource == DS_FILE)
131 struct stat st;
132 if (mc_fstat (view->ds_file_fd, &st) != -1)
133 view->ds_file_filesize = st.st_size;
137 /* --------------------------------------------------------------------------------------------- */
139 char *
140 mcview_get_ptr_file (WView * view, off_t byte_index)
142 #ifdef HAVE_ASSERT_H
143 assert (view->datasource == DS_FILE);
144 #endif
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));
149 return NULL;
152 /* --------------------------------------------------------------------------------------------- */
154 gboolean
155 mcview_get_utf (WView * view, off_t byte_index, int *ch, int *ch_len)
157 gchar *str = NULL;
158 int res;
159 gchar utf8buf[UTF8_CHAR_LEN + 1];
161 switch (view->datasource)
163 case DS_STDIO_PIPE:
164 case DS_VFS_PIPE:
165 str = mcview_get_ptr_growing_buffer (view, byte_index);
166 break;
167 case DS_FILE:
168 str = mcview_get_ptr_file (view, byte_index);
169 break;
170 case DS_STRING:
171 str = mcview_get_ptr_string (view, byte_index);
172 break;
173 case DS_NONE:
174 default:
175 break;
178 *ch = 0;
180 if (str == NULL)
181 return FALSE;
183 res = g_utf8_get_char_validated (str, -1);
185 if (res < 0)
187 /* Retry with explicit bytes to make sure it's not a buffer boundary */
188 int i;
190 for (i = 0; i < UTF8_CHAR_LEN; i++)
192 if (mcview_get_byte (view, byte_index + i, &res))
193 utf8buf[i] = res;
194 else
196 utf8buf[i] = '\0';
197 break;
200 utf8buf[UTF8_CHAR_LEN] = '\0';
201 str = utf8buf;
202 res = g_utf8_get_char_validated (str, -1);
205 if (res < 0)
207 *ch = (unsigned char) (*str);
208 *ch_len = 1;
210 else
212 gchar *next_ch = NULL;
214 *ch = res;
215 /* Calculate UTF-8 char length */
216 next_ch = g_utf8_next_char (str);
217 *ch_len = next_ch - str;
220 return TRUE;
223 /* --------------------------------------------------------------------------------------------- */
225 char *
226 mcview_get_ptr_string (WView * view, off_t byte_index)
228 #ifdef HAVE_ASSERT_H
229 assert (view->datasource == DS_STRING);
230 #endif
231 if (byte_index >= 0 && byte_index < (off_t) view->ds_string_len)
232 return (char *) (view->ds_string_data + byte_index);
233 return NULL;
236 /* --------------------------------------------------------------------------------------------- */
238 gboolean
239 mcview_get_byte_string (WView * view, off_t byte_index, int *retval)
241 char *p;
243 if (retval != NULL)
244 *retval = -1;
246 p = mcview_get_ptr_string (view, byte_index);
247 if (p == NULL)
248 return FALSE;
250 if (retval != NULL)
251 *retval = (unsigned char) (*p);
252 return TRUE;
255 /* --------------------------------------------------------------------------------------------- */
257 gboolean
258 mcview_get_byte_none (WView * view, off_t byte_index, int *retval)
260 (void) &view;
261 (void) byte_index;
263 #ifdef HAVE_ASSERT_H
264 assert (view->datasource == DS_NONE);
265 #endif
267 if (retval != NULL)
268 *retval = -1;
269 return FALSE;
272 /* --------------------------------------------------------------------------------------------- */
274 void
275 mcview_set_byte (WView * view, off_t offset, byte b)
277 (void) &b;
278 #ifndef HAVE_ASSERT_H
279 (void) offset;
280 #else
281 assert (offset < mcview_get_filesize (view));
282 assert (view->datasource == DS_FILE);
284 #endif
285 view->ds_file_datalen = 0; /* just force reloading */
288 /* --------------------------------------------------------------------------------------------- */
290 /*static */
291 void
292 mcview_file_load_data (WView * view, off_t byte_index)
294 off_t blockoffset;
295 ssize_t res;
296 size_t bytes_read;
298 #ifdef HAVE_ASSERT_H
299 assert (view->datasource == DS_FILE);
300 #endif
302 if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen))
303 return;
305 if (byte_index >= view->ds_file_filesize)
306 return;
308 blockoffset = mcview_offset_rounddown (byte_index, view->ds_file_datasize);
309 if (mc_lseek (view->ds_file_fd, blockoffset, SEEK_SET) == -1)
310 goto error;
312 bytes_read = 0;
313 while (bytes_read < view->ds_file_datasize)
315 res =
316 mc_read (view->ds_file_fd, view->ds_file_data + bytes_read,
317 view->ds_file_datasize - bytes_read);
318 if (res == -1)
319 goto error;
320 if (res == 0)
321 break;
322 bytes_read += (size_t) res;
324 view->ds_file_offset = blockoffset;
325 if ((off_t) bytes_read > view->ds_file_filesize - view->ds_file_offset)
327 /* the file has grown in the meantime -- stick to the old size */
328 view->ds_file_datalen = view->ds_file_filesize - view->ds_file_offset;
330 else
332 view->ds_file_datalen = bytes_read;
334 return;
336 error:
337 view->ds_file_datalen = 0;
340 /* --------------------------------------------------------------------------------------------- */
342 void
343 mcview_close_datasource (WView * view)
345 switch (view->datasource)
347 case DS_NONE:
348 break;
349 case DS_STDIO_PIPE:
350 if (view->ds_stdio_pipe != NULL)
352 mcview_growbuf_done (view);
353 mcview_display (view);
355 mcview_growbuf_free (view);
356 break;
357 case DS_VFS_PIPE:
358 if (view->ds_vfs_pipe != -1)
359 mcview_growbuf_done (view);
360 mcview_growbuf_free (view);
361 break;
362 case DS_FILE:
363 (void) mc_close (view->ds_file_fd);
364 view->ds_file_fd = -1;
365 MC_PTR_FREE (view->ds_file_data);
366 break;
367 case DS_STRING:
368 MC_PTR_FREE (view->ds_string_data);
369 break;
370 default:
371 #ifdef HAVE_ASSERT_H
372 assert (!"Unknown datasource type")
373 #endif
376 view->datasource = DS_NONE;
379 /* --------------------------------------------------------------------------------------------- */
381 void
382 mcview_set_datasource_file (WView * view, int fd, const struct stat *st)
384 view->datasource = DS_FILE;
385 view->ds_file_fd = fd;
386 view->ds_file_filesize = st->st_size;
387 view->ds_file_offset = 0;
388 view->ds_file_data = g_malloc (4096);
389 view->ds_file_datalen = 0;
390 view->ds_file_datasize = 4096;
393 /* --------------------------------------------------------------------------------------------- */
395 gboolean
396 mcview_load_command_output (WView * view, const char *command)
398 mc_pipe_t *p;
399 GError *error = NULL;
401 mcview_close_datasource (view);
403 p = mc_popen (command, &error);
404 if (p == NULL)
406 mcview_display (view);
407 mcview_show_error (view, error->message);
408 g_error_free (error);
409 return FALSE;
412 /* Check if filter produced any output */
413 mcview_set_datasource_stdio_pipe (view, p);
414 if (!mcview_get_byte (view, 0, NULL))
416 mcview_close_datasource (view);
417 mcview_display (view);
418 return FALSE;
421 return TRUE;
424 /* --------------------------------------------------------------------------------------------- */
426 void
427 mcview_set_datasource_vfs_pipe (WView * view, int fd)
429 #ifdef HAVE_ASSERT_H
430 assert (fd != -1);
431 #endif
432 view->datasource = DS_VFS_PIPE;
433 view->ds_vfs_pipe = fd;
435 mcview_growbuf_init (view);
438 /* --------------------------------------------------------------------------------------------- */
440 void
441 mcview_set_datasource_string (WView * view, const char *s)
443 view->datasource = DS_STRING;
444 view->ds_string_len = strlen (s);
445 view->ds_string_data = (byte *) g_strndup (s, view->ds_string_len);
448 /* --------------------------------------------------------------------------------------------- */