mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-22 12:32:40 +03:00
mcviewer: use mc_pipe_t to show command output.
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
parent
a31b78003e
commit
b69b8947d9
@ -69,25 +69,26 @@
|
||||
|
||||
/*** file scope variables ************************************************************************/
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/*** file scope functions ************************************************************************/
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/*** public functions ****************************************************************************/
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
mcview_set_datasource_stdio_pipe (mcview_t * view, FILE * fp)
|
||||
mcview_set_datasource_stdio_pipe (mcview_t * view, mc_pipe_t * p)
|
||||
{
|
||||
#ifdef HAVE_ASSERT_H
|
||||
assert (fp != NULL);
|
||||
#endif
|
||||
p->out.len = MC_PIPE_BUFSIZE;
|
||||
p->out.null_term = FALSE;
|
||||
p->err.len = MC_PIPE_BUFSIZE;
|
||||
p->err.null_term = TRUE;
|
||||
view->datasource = DS_STDIO_PIPE;
|
||||
view->ds_stdio_pipe = fp;
|
||||
view->ds_stdio_pipe = p;
|
||||
view->pipe_first_err_msg = TRUE;
|
||||
|
||||
mcview_growbuf_init (view);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
/*** public functions ****************************************************************************/
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
@ -350,19 +351,14 @@ mcview_close_datasource (mcview_t * view)
|
||||
case DS_STDIO_PIPE:
|
||||
if (view->ds_stdio_pipe != NULL)
|
||||
{
|
||||
(void) pclose (view->ds_stdio_pipe);
|
||||
mcview_growbuf_done (view);
|
||||
mcview_display (view);
|
||||
close_error_pipe (D_NORMAL, NULL);
|
||||
view->ds_stdio_pipe = NULL;
|
||||
}
|
||||
mcview_growbuf_free (view);
|
||||
break;
|
||||
case DS_VFS_PIPE:
|
||||
if (view->ds_vfs_pipe != -1)
|
||||
{
|
||||
(void) mc_close (view->ds_vfs_pipe);
|
||||
view->ds_vfs_pipe = -1;
|
||||
}
|
||||
mcview_growbuf_done (view);
|
||||
mcview_growbuf_free (view);
|
||||
break;
|
||||
case DS_FILE:
|
||||
@ -401,44 +397,29 @@ mcview_set_datasource_file (mcview_t * view, int fd, const struct stat *st)
|
||||
gboolean
|
||||
mcview_load_command_output (mcview_t * view, const char *command)
|
||||
{
|
||||
FILE *fp;
|
||||
mc_pipe_t *pipe;
|
||||
GError *error = NULL;
|
||||
|
||||
mcview_close_datasource (view);
|
||||
|
||||
open_error_pipe ();
|
||||
fp = popen (command, "r");
|
||||
if (fp == NULL)
|
||||
pipe = mc_popen (command, &error);
|
||||
if (pipe == NULL)
|
||||
{
|
||||
/* Avoid two messages. Message from stderr has priority. */
|
||||
mcview_display (view);
|
||||
if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL))
|
||||
mcview_show_error (view, _("Cannot spawn child process"));
|
||||
mcview_show_error (view, error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* First, check if filter produced any output */
|
||||
mcview_set_datasource_stdio_pipe (view, fp);
|
||||
/* Check if filter produced any output */
|
||||
mcview_set_datasource_stdio_pipe (view, pipe);
|
||||
if (!mcview_get_byte (view, 0, NULL))
|
||||
{
|
||||
mcview_close_datasource (view);
|
||||
|
||||
/* Avoid two messages. Message from stderr has priority. */
|
||||
mcview_display (view);
|
||||
if (!close_error_pipe (mcview_is_in_panel (view) ? -1 : D_ERROR, NULL))
|
||||
mcview_show_error (view, _("Empty output from child filter"));
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* At least something was read correctly. Close stderr and let
|
||||
* program die if it will try to write something there.
|
||||
*
|
||||
* Ideally stderr should be read asynchronously to prevent programs
|
||||
* from blocking (poll/select multiplexor).
|
||||
*/
|
||||
close_error_pipe (D_NORMAL, NULL);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
Pavel Machek, 1998
|
||||
Roland Illig <roland.illig@gmx.de>, 2004, 2005
|
||||
Slava Zanko <slavazanko@google.com>, 2009
|
||||
Andrew Borodin <aborodin@vmail.ru>, 2009
|
||||
Andrew Borodin <aborodin@vmail.ru>, 2009, 2014
|
||||
Ilia Maslakov <il.smind@gmail.com>, 2009
|
||||
|
||||
This file is part of the Midnight Commander.
|
||||
@ -72,6 +72,25 @@ mcview_growbuf_init (mcview_t * view)
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
mcview_growbuf_done (mcview_t * view)
|
||||
{
|
||||
view->growbuf_finished = TRUE;
|
||||
|
||||
if (view->datasource == DS_STDIO_PIPE)
|
||||
{
|
||||
mc_pclose (view->ds_stdio_pipe, NULL);
|
||||
view->ds_stdio_pipe = NULL;
|
||||
}
|
||||
else /* view->datasource == DS_VFS_PIPE */
|
||||
{
|
||||
(void) mc_close (view->ds_vfs_pipe);
|
||||
view->ds_vfs_pipe = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
void
|
||||
mcview_growbuf_free (mcview_t * view)
|
||||
{
|
||||
@ -111,8 +130,7 @@ mcview_growbuf_filesize (mcview_t * view)
|
||||
void
|
||||
mcview_growbuf_read_until (mcview_t * view, off_t ofs)
|
||||
{
|
||||
ssize_t nread;
|
||||
gboolean short_read;
|
||||
gboolean short_read = FALSE;
|
||||
|
||||
#ifdef HAVE_ASSERT_H
|
||||
assert (view->growbuf_in_use);
|
||||
@ -121,9 +139,9 @@ mcview_growbuf_read_until (mcview_t * view, off_t ofs)
|
||||
if (view->growbuf_finished)
|
||||
return;
|
||||
|
||||
short_read = FALSE;
|
||||
while (mcview_growbuf_filesize (view) < ofs || short_read)
|
||||
{
|
||||
ssize_t nread = 0;
|
||||
byte *p;
|
||||
size_t bytesfree;
|
||||
|
||||
@ -144,14 +162,56 @@ mcview_growbuf_read_until (mcview_t * view, off_t ofs)
|
||||
|
||||
if (view->datasource == DS_STDIO_PIPE)
|
||||
{
|
||||
nread = fread (p, 1, bytesfree, view->ds_stdio_pipe);
|
||||
if (nread == 0)
|
||||
mc_pipe_t *sp = view->ds_stdio_pipe;
|
||||
GError *error = NULL;
|
||||
|
||||
if (bytesfree > MC_PIPE_BUFSIZE)
|
||||
bytesfree = MC_PIPE_BUFSIZE;
|
||||
|
||||
sp->out.len = bytesfree;
|
||||
sp->err.len = MC_PIPE_BUFSIZE;
|
||||
|
||||
mc_pread (sp, &error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
view->growbuf_finished = TRUE;
|
||||
(void) pclose (view->ds_stdio_pipe);
|
||||
mcview_show_error (view, error->message);
|
||||
g_error_free (error);
|
||||
mcview_growbuf_done (view);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view->pipe_first_err_msg && sp->err.len > 0)
|
||||
{
|
||||
/* ignore possible following errors */
|
||||
/* reset this flag before call of mcview_show_error() to break
|
||||
* endless recursion: mcview_growbuf_read_until() -> mcview_show_error() ->
|
||||
* MSG_DRAW -> mcview_display() -> mcview_get_byte() -> mcview_growbuf_read_until()
|
||||
*/
|
||||
view->pipe_first_err_msg = FALSE;
|
||||
|
||||
mcview_show_error (view, sp->err.buf);
|
||||
}
|
||||
|
||||
if (sp->out.len > 0)
|
||||
{
|
||||
memmove (p, sp->out.buf, sp->out.len);
|
||||
nread = sp->out.len;
|
||||
}
|
||||
else if (sp->out.len == MC_PIPE_STREAM_EOF || sp->out.len == MC_PIPE_ERROR_READ)
|
||||
{
|
||||
if (sp->out.len == MC_PIPE_ERROR_READ)
|
||||
{
|
||||
char *err_msg;
|
||||
|
||||
err_msg = g_strdup_printf (_("Failed to read data from child stdout:\n%s"),
|
||||
unix_error_string (sp->out.error));
|
||||
mcview_show_error (view, err_msg);
|
||||
g_free (err_msg);
|
||||
}
|
||||
|
||||
mcview_growbuf_done (view);
|
||||
mcview_display (view);
|
||||
close_error_pipe (D_NORMAL, NULL);
|
||||
view->ds_stdio_pipe = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -165,11 +225,10 @@ mcview_growbuf_read_until (mcview_t * view, off_t ofs)
|
||||
nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
|
||||
}
|
||||
while (nread == -1 && errno == EINTR);
|
||||
if (nread == -1 || nread == 0)
|
||||
|
||||
if (nread <= 0)
|
||||
{
|
||||
view->growbuf_finished = TRUE;
|
||||
(void) mc_close (view->ds_vfs_pipe);
|
||||
view->ds_vfs_pipe = -1;
|
||||
mcview_growbuf_done (view);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,8 @@ struct mcview_struct
|
||||
enum view_ds datasource; /* Where the displayed data comes from */
|
||||
|
||||
/* stdio pipe data source */
|
||||
FILE *ds_stdio_pipe; /* Output of a shell command */
|
||||
mc_pipe_t *ds_stdio_pipe; /* Output of a shell command */
|
||||
gboolean pipe_first_err_msg; /* Show only 1st message from stderr */
|
||||
|
||||
/* vfs pipe data source */
|
||||
int ds_vfs_pipe; /* Non-seekable vfs file descriptor */
|
||||
@ -263,6 +264,7 @@ void mcview_display_ruler (mcview_t * view);
|
||||
|
||||
/* growbuf.c: */
|
||||
void mcview_growbuf_init (mcview_t * view);
|
||||
void mcview_growbuf_done (mcview_t * view);
|
||||
void mcview_growbuf_free (mcview_t * view);
|
||||
off_t mcview_growbuf_filesize (mcview_t * view);
|
||||
void mcview_growbuf_read_until (mcview_t * view, off_t p);
|
||||
|
@ -304,15 +304,10 @@ mcview_select_encoding (mcview_t * view)
|
||||
void
|
||||
mcview_show_error (mcview_t * view, const char *msg)
|
||||
{
|
||||
mcview_close_datasource (view);
|
||||
if (mcview_is_in_panel (view))
|
||||
{
|
||||
mcview_set_datasource_string (view, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
message (D_ERROR, MSG_ERROR, "%s", msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
@ -325,6 +325,7 @@ mcview_load (mcview_t * view, const char *command, const char *file, int start_l
|
||||
{
|
||||
g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\"\n%s"),
|
||||
file, unix_error_string (errno));
|
||||
mcview_close_datasource (view);
|
||||
mcview_show_error (view, tmp);
|
||||
vfs_path_free (view->filename_vpath);
|
||||
view->filename_vpath = NULL;
|
||||
@ -339,6 +340,7 @@ mcview_load (mcview_t * view, const char *command, const char *file, int start_l
|
||||
mc_close (fd);
|
||||
g_snprintf (tmp, sizeof (tmp), _("Cannot stat \"%s\"\n%s"),
|
||||
file, unix_error_string (errno));
|
||||
mcview_close_datasource (view);
|
||||
mcview_show_error (view, tmp);
|
||||
vfs_path_free (view->filename_vpath);
|
||||
view->filename_vpath = NULL;
|
||||
@ -350,6 +352,7 @@ mcview_load (mcview_t * view, const char *command, const char *file, int start_l
|
||||
if (!S_ISREG (st.st_mode))
|
||||
{
|
||||
mc_close (fd);
|
||||
mcview_close_datasource (view);
|
||||
mcview_show_error (view, _("Cannot view: not a regular file"));
|
||||
vfs_path_free (view->filename_vpath);
|
||||
view->filename_vpath = NULL;
|
||||
@ -382,6 +385,7 @@ mcview_load (mcview_t * view, const char *command, const char *file, int start_l
|
||||
{
|
||||
g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\" in parse mode\n%s"),
|
||||
file, unix_error_string (errno));
|
||||
mcview_close_datasource (view);
|
||||
mcview_show_error (view, tmp);
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user