medit/moo/mooterm/mootermpt-unix.c

784 lines
20 KiB
C
Raw Normal View History

2005-06-22 15:13:12 -07:00
/*
2005-07-07 04:06:23 -07:00
* mooterm/mootermpt-unix.c
2005-06-22 15:13:12 -07:00
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
2005-06-22 15:13:12 -07:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define MOOTERM_COMPILATION
#include "mooterm/mootermpt-private.h"
#include "mooterm/mooterm-private.h"
2005-06-22 15:13:12 -07:00
#include "mooterm/pty.h"
#include "mooutils/moomarshals.h"
#include "mooutils/moocompat.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <termios.h>
2005-06-22 15:13:12 -07:00
#ifdef HAVE_POLL_H
2005-07-26 04:12:40 -07:00
# include <poll.h>
2005-06-22 15:13:12 -07:00
#elif HAVE_SYS_POLL_H
2005-07-26 04:12:40 -07:00
# include <sys/poll.h>
2005-06-22 15:13:12 -07:00
#endif
#define TERM_EMULATION "xterm"
#define WRITE_CHUNK_SIZE 4096
#define POLL_TIME 5
#define POLL_NUM 1
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
#define MOO_TERM_PT_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOO_TYPE_TERM_PT_UNIX, MooTermPtUnix))
#define MOO_TERM_PT_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_TERM_PT_UNIX, MooTermPtUnixClass))
#define MOO_IS_TERM_PT_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOO_TYPE_TERM_PT_UNIX))
#define MOO_IS_TERM_PT_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_TERM_PT_UNIX))
#define MOO_TERM_PT_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_TERM_PT_UNIX, MooTermPtUnixClass))
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
typedef struct _MooTermPtUnix MooTermPtUnix;
typedef struct _MooTermPtUnixClass MooTermPtUnixClass;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
struct _MooTermPtUnix {
MooTermPt parent;
2005-06-22 15:13:12 -07:00
GPid child_pid;
int master;
int width;
int height;
gboolean non_block;
2005-06-22 15:13:12 -07:00
GIOChannel *io;
guint io_watch_id;
};
2005-07-07 04:06:23 -07:00
struct _MooTermPtUnixClass {
MooTermPtClass parent_class;
2005-06-22 15:13:12 -07:00
};
2005-07-07 04:06:23 -07:00
static void moo_term_pt_unix_finalize (GObject *object);
2005-06-22 15:13:12 -07:00
2005-07-26 04:12:40 -07:00
static void set_size (MooTermPt *pt,
guint width,
guint height);
static gboolean fork_command (MooTermPt *pt,
const MooTermCommand *cmd,
2005-07-26 04:12:40 -07:00
const char *working_dir,
char **envp,
GError **error);
2005-07-26 04:12:40 -07:00
static gboolean fork_argv (MooTermPt *pt,
char **argv,
const char *working_dir,
char **envp,
GError **error);
2005-07-26 04:12:40 -07:00
static void pt_write (MooTermPt *pt,
const char *string,
gssize len);
static void kill_child (MooTermPt *pt);
static void send_intr (MooTermPt *pt);
static char get_erase_char (MooTermPt *pt);
2005-07-26 04:12:40 -07:00
static gboolean read_child_out (GIOChannel *source,
GIOCondition condition,
MooTermPtUnix *pt);
static void feed_buffer (MooTermPtUnix *pt,
const char *string,
int len);
static void start_writer (MooTermPt *pt);
static void stop_writer (MooTermPt *pt);
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
/* MOO_TYPE_TERM_PT_UNIX */
G_DEFINE_TYPE (MooTermPtUnix, moo_term_pt_unix, MOO_TYPE_TERM_PT)
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
static void moo_term_pt_unix_class_init (MooTermPtUnixClass *klass)
2005-06-22 15:13:12 -07:00
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2005-07-07 04:06:23 -07:00
MooTermPtClass *pt_class = MOO_TERM_PT_CLASS (klass);
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
gobject_class->finalize = moo_term_pt_unix_finalize;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
pt_class->set_size = set_size;
pt_class->fork_command = fork_command;
pt_class->write = pt_write;
pt_class->kill_child = kill_child;
pt_class->get_erase_char = get_erase_char;
pt_class->send_intr = send_intr;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
static void moo_term_pt_unix_init (MooTermPtUnix *pt)
2005-06-22 15:13:12 -07:00
{
MOO_TERM_PT(pt)->priv->child_alive = FALSE;
2005-07-07 04:06:23 -07:00
pt->child_pid = (GPid)-1;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
pt->master = -1;
pt->width = 80;
pt->height = 24;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
pt->non_block = FALSE;
pt->io = NULL;
pt->io_watch_id = 0;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
static void moo_term_pt_unix_finalize (GObject *object)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
MooTermPtUnix *pt = MOO_TERM_PT_UNIX (object);
kill_child (MOO_TERM_PT (pt));
G_OBJECT_CLASS (moo_term_pt_unix_parent_class)->finalize (object);
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
static void set_size (MooTermPt *pt,
guint width,
guint height)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
MooTermPtUnix *ptu;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
g_return_if_fail (MOO_IS_TERM_PT_UNIX (pt));
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
ptu = MOO_TERM_PT_UNIX (pt);
2005-06-22 15:13:12 -07:00
if (pt->priv->child_alive)
2005-07-07 04:06:23 -07:00
_vte_pty_set_size (ptu->master, width, height);
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
ptu->width = width;
ptu->height = height;
2005-06-22 15:13:12 -07:00
}
static gboolean
fork_argv (MooTermPt *pt_gen,
char **argv,
const char *working_dir,
char **envp,
GError **error)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
MooTermPtUnix *pt;
2005-06-22 15:13:12 -07:00
int env_len = 0;
char **new_env;
int status, flags;
int i;
GSource *src;
2005-06-22 15:13:12 -07:00
g_return_val_if_fail (argv != NULL, FALSE);
2005-07-07 04:06:23 -07:00
g_return_val_if_fail (MOO_IS_TERM_PT_UNIX (pt_gen), FALSE);
2005-06-22 15:13:12 -07:00
if (!argv[0])
{
g_set_error (error, MOO_TERM_ERROR, MOO_TERM_ERROR_INVAL,
"empty arguments array");
return FALSE;
}
2005-07-07 04:06:23 -07:00
pt = MOO_TERM_PT_UNIX (pt_gen);
2005-06-22 15:13:12 -07:00
g_return_val_if_fail (!pt_gen->priv->child_alive, FALSE);
2005-06-22 15:13:12 -07:00
if (envp)
{
char **e;
for (e = envp; *e != NULL; ++e)
++env_len;
}
new_env = g_new (char*, env_len + 2);
for (i = 0; i < env_len; ++i)
new_env[i] = g_strdup (envp[i]);
new_env[env_len] = g_strdup ("TERM=" TERM_EMULATION);
new_env[env_len + 1] = NULL;
2005-07-07 04:06:23 -07:00
pt->master = _vte_pty_open (&pt->child_pid, new_env,
2005-06-22 15:13:12 -07:00
argv[0],
argv,
working_dir,
2005-07-07 04:06:23 -07:00
pt->width, pt->height,
2005-06-22 15:13:12 -07:00
FALSE, FALSE, FALSE);
g_strfreev (new_env);
2005-07-07 04:06:23 -07:00
if (pt->master == -1)
2005-06-22 15:13:12 -07:00
{
g_critical ("%s: could not fork child", G_STRLOC);
if (errno)
g_set_error (error, MOO_TERM_ERROR,
MOO_TERM_ERROR_FAILED,
"could not fork command: %s",
g_strerror (errno));
else
g_set_error (error, MOO_TERM_ERROR,
MOO_TERM_ERROR_FAILED,
"could not fork command");
2005-06-22 15:13:12 -07:00
return FALSE;
}
else
{
#if 0
2005-07-07 04:06:23 -07:00
g_message ("%s: forked child pid %d", G_STRLOC, pt->child_pid);
#endif
2005-06-22 15:13:12 -07:00
}
if (waitpid (-1, &status, WNOHANG) == -1)
g_critical ("%s: error in waitpid", G_STRLOC);
2005-07-07 04:06:23 -07:00
if ((flags = fcntl (pt->master, F_GETFL)) < 0)
2005-06-22 15:13:12 -07:00
g_critical ("%s: F_GETFL on master", G_STRLOC);
2005-07-07 04:06:23 -07:00
else if (-1 == fcntl (pt->master, F_SETFL, O_NONBLOCK | flags))
2005-06-22 15:13:12 -07:00
g_critical ("%s: F_SETFL on master", G_STRLOC);
else
2005-07-07 04:06:23 -07:00
pt->non_block = TRUE;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
pt->io = g_io_channel_unix_new (pt->master);
g_return_val_if_fail (pt->io != NULL, FALSE);
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
g_io_channel_set_encoding (pt->io, NULL, NULL);
g_io_channel_set_buffered (pt->io, FALSE);
2005-06-22 15:13:12 -07:00
2006-06-09 12:28:17 -07:00
pt->io_watch_id = g_io_add_watch_full (pt->io,
G_PRIORITY_DEFAULT_IDLE,
G_IO_IN | G_IO_PRI | G_IO_HUP,
(GIOFunc) read_child_out,
pt, NULL);
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
src = g_main_context_find_source_by_id (NULL, pt->io_watch_id);
if (src)
2005-07-07 04:06:23 -07:00
g_source_set_priority (src, PT_READER_PRIORITY);
else
g_warning ("%s: could not find io_watch_id source", G_STRLOC);
2005-06-22 15:13:12 -07:00
pt_gen->priv->child_alive = TRUE;
2005-06-22 15:13:12 -07:00
return TRUE;
}
2005-07-26 04:12:40 -07:00
static gboolean fork_command (MooTermPt *pt_gen,
const MooTermCommand *cmd,
2005-07-26 04:12:40 -07:00
const char *working_dir,
char **envp,
GError **error)
2005-07-26 04:12:40 -07:00
{
g_return_val_if_fail (cmd != NULL, FALSE);
g_return_val_if_fail (cmd->argv != NULL, FALSE);
2005-07-26 04:12:40 -07:00
g_return_val_if_fail (MOO_IS_TERM_PT_UNIX (pt_gen), FALSE);
return fork_argv (pt_gen, cmd->argv, working_dir, envp, error);
2005-07-26 04:12:40 -07:00
}
2005-07-07 04:06:23 -07:00
static void kill_child (MooTermPt *pt_gen)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
MooTermPtUnix *pt = MOO_TERM_PT_UNIX (pt_gen);
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
if (pt->io_watch_id)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
g_source_remove (pt->io_watch_id);
pt->io_watch_id = 0;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
if (pt->io)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
g_io_channel_shutdown (pt->io, TRUE, NULL);
g_io_channel_unref (pt->io);
pt->io = NULL;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
stop_writer (pt_gen);
pt_discard_pending_write (pt_gen);
2005-07-07 04:06:23 -07:00
if (pt->master != -1)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
_vte_pty_close (pt->master);
pt->master = -1;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
pt->non_block = FALSE;
2005-07-07 04:06:23 -07:00
pt->child_pid = (GPid)-1;
2005-06-22 15:13:12 -07:00
if (pt_gen->priv->child_alive)
2005-06-22 15:13:12 -07:00
{
pt_gen->priv->child_alive = FALSE;
2005-07-07 04:06:23 -07:00
g_signal_emit_by_name (pt, "child-died");
2005-06-22 15:13:12 -07:00
}
}
2006-06-09 12:28:17 -07:00
static gboolean
read_child_out (G_GNUC_UNUSED GIOChannel *source,
GIOCondition condition,
MooTermPtUnix *pt)
2005-06-22 15:13:12 -07:00
{
gboolean error_occured = FALSE;
int error_no = 0;
2006-06-09 12:28:17 -07:00
char buf[INPUT_CHUNK_SIZE];
2005-06-22 15:13:12 -07:00
guint again = POLL_NUM;
2006-06-09 12:28:17 -07:00
gsize to_read;
gsize current = 0;
2005-06-22 15:13:12 -07:00
2006-06-09 12:28:17 -07:00
/* try to read leftover from the pipe */
2005-06-22 15:13:12 -07:00
if (condition & G_IO_HUP)
{
2006-06-09 12:28:17 -07:00
int bytes;
2006-03-16 00:47:59 -08:00
2005-06-22 15:13:12 -07:00
g_message ("%s: G_IO_HUP", G_STRLOC);
error_no = errno;
2006-03-16 00:47:59 -08:00
2006-06-09 12:28:17 -07:00
bytes = read (pt->master, buf, sizeof (buf));
2006-03-16 00:47:59 -08:00
2006-06-09 12:28:17 -07:00
if (bytes > 0)
feed_buffer (pt, buf, bytes);
2006-03-16 00:47:59 -08:00
2005-06-22 15:13:12 -07:00
goto error;
}
else if (condition & G_IO_ERR)
{
g_message ("%s: G_IO_ERR", G_STRLOC);
error_no = errno;
goto error;
}
g_assert (condition & (G_IO_IN | G_IO_PRI));
2006-06-09 12:28:17 -07:00
to_read = _moo_term_get_input_chunk_len (MOO_TERM_PT(pt)->priv->term);
g_assert (to_read <= sizeof (buf));
if (!to_read)
{
// g_print ("read_child_out: skipping\n");
return TRUE;
}
2005-07-07 04:06:23 -07:00
if (pt->non_block)
{
2006-06-09 12:28:17 -07:00
int bytes;
bytes = read (pt->master, buf, to_read);
2006-06-09 12:28:17 -07:00
switch (bytes)
{
case -1:
if (errno != EAGAIN && errno != EINTR)
{
error_occured = TRUE;
error_no = errno;
goto error;
}
break;
case 0:
break;
default:
#if 0
{
char *s = _moo_term_nice_bytes (buf, r);
g_print ("got '%s'\n", s);
g_free (s);
}
#endif
2006-06-09 12:28:17 -07:00
feed_buffer (pt, buf, bytes);
break;
}
return TRUE;
}
2006-06-09 12:28:17 -07:00
while (again && !error_occured && current < to_read)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
struct pollfd fd = {pt->master, POLLIN | POLLPRI, 0};
2005-06-22 15:13:12 -07:00
int res = poll (&fd, 1, POLL_TIME);
switch (res)
{
case 0:
--again;
break;
case 1:
if (fd.revents & (POLLNVAL | POLLERR | POLLHUP))
{
again = 0;
if (errno != EAGAIN && errno != EINTR)
{
error_occured = TRUE;
error_no = errno;
}
}
else if (fd.revents & (POLLIN | POLLPRI))
{
2005-07-07 04:06:23 -07:00
int r = read (pt->master, buf + current, 1);
2005-06-22 15:13:12 -07:00
switch (r)
{
case -1:
error_occured = TRUE;
error_no = errno;
break;
case 0:
--again;
break;
case 1:
++current;
break;
default:
g_assert_not_reached();
}
}
2005-06-22 15:13:12 -07:00
break;
case -1:
again = 0;
if (errno != EAGAIN && errno != EINTR)
{
error_occured = TRUE;
error_no = errno;
}
break;
default:
g_assert_not_reached();
}
}
if (current > 0)
2005-07-07 04:06:23 -07:00
feed_buffer (pt, buf, current);
2005-06-22 15:13:12 -07:00
if (error_occured)
goto error;
return TRUE;
error:
if (error_occured)
g_message ("error in %s", G_STRLOC);
if (error_no)
g_message ("%s: %s", G_STRLOC, g_strerror (error_no));
2005-07-07 04:06:23 -07:00
if (pt->io)
2005-06-22 15:13:12 -07:00
{
2005-07-07 04:06:23 -07:00
_vte_pty_close (pt->master);
pt->master = -1;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
g_io_channel_shutdown (pt->io, TRUE, NULL);
g_io_channel_unref (pt->io);
pt->io = NULL;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
pt->io_watch_id = 0;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
kill_child (MOO_TERM_PT (pt));
2005-06-22 15:13:12 -07:00
return FALSE;
}
2006-06-09 12:28:17 -07:00
static void
feed_buffer (MooTermPtUnix *pt,
const char *string,
int len)
2005-06-22 15:13:12 -07:00
{
2006-06-09 12:28:17 -07:00
moo_term_feed (MOO_TERM_PT(pt)->priv->term, string, len);
2005-06-22 15:13:12 -07:00
}
/* writes given data to file, returns TRUE on successful write,
FALSE when could not write al teh data, puts start of leftover
to string, length of it to len, and fills err in case of error */
2005-07-07 04:06:23 -07:00
static gboolean do_write (MooTermPt *pt_gen,
const char **string,
guint *plen,
int *err)
2005-06-22 15:13:12 -07:00
{
int written;
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
MooTermPtUnix *pt = MOO_TERM_PT_UNIX (pt_gen);
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
g_return_val_if_fail (pt->io != NULL, FALSE);
written = write (pt->master, *string,
*plen > WRITE_CHUNK_SIZE ? WRITE_CHUNK_SIZE : *plen);
2005-06-22 15:13:12 -07:00
if (written == -1)
{
*err = errno;
switch (errno)
{
case EAGAIN:
case EINTR:
g_warning ("%s", G_STRLOC);
return TRUE;
default:
return FALSE;
}
}
else
2005-06-22 15:13:12 -07:00
{
*string += written;
*plen -= written;
2005-06-22 15:13:12 -07:00
if (!*plen)
*string = NULL;
return TRUE;
}
}
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
static void append (MooTermPt *pt,
const char *data,
guint len)
{
GByteArray *ar = g_byte_array_sized_new (len);
g_byte_array_append (ar, (const guint8*)data, len);
2005-07-07 04:06:23 -07:00
g_queue_push_tail (pt->priv->pending_write, ar);
}
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
static gboolean write_cb (MooTermPt *pt)
{
2005-07-07 04:06:23 -07:00
pt_write (pt, NULL, 0);
return TRUE;
}
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
static void start_writer (MooTermPt *pt)
{
2005-07-07 04:06:23 -07:00
if (!pt->priv->pending_write_id)
pt->priv->pending_write_id =
g_idle_add_full (PT_WRITER_PRIORITY,
(GSourceFunc) write_cb,
2005-07-07 04:06:23 -07:00
pt, NULL);
}
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
static void stop_writer (MooTermPt *pt)
{
2005-07-07 04:06:23 -07:00
if (pt->priv->pending_write_id)
{
2005-07-07 04:06:23 -07:00
g_source_remove (pt->priv->pending_write_id);
pt->priv->pending_write_id = 0;
}
}
2005-06-22 15:13:12 -07:00
2005-07-07 04:06:23 -07:00
static void pt_write (MooTermPt *pt,
const char *data,
2006-04-30 11:53:04 -07:00
gssize data_len)
{
g_return_if_fail (data == NULL || data_len != 0);
g_return_if_fail (pt->priv->child_alive);
2005-07-07 04:06:23 -07:00
while (data || !g_queue_is_empty (pt->priv->pending_write))
{
int err = 0;
const char *string;
guint len;
GByteArray *freeme = NULL;
2005-07-07 04:06:23 -07:00
if (!g_queue_is_empty (pt->priv->pending_write))
{
if (data)
{
2005-07-07 04:06:23 -07:00
append (pt, data, data_len > 0 ? (guint)data_len : strlen (data));
data = NULL;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
freeme = g_queue_peek_head (pt->priv->pending_write);
2005-07-19 07:01:41 -07:00
string = (const char *) freeme->data;
len = freeme->len;
2005-06-22 15:13:12 -07:00
}
else
2005-06-22 15:13:12 -07:00
{
string = data;
len = data_len > 0 ? (guint)data_len : strlen (data);
data = NULL;
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
if (do_write (pt, &string, &len, &err))
{
if (len)
{
if (freeme)
{
memmove (freeme->data, freeme->data + (freeme->len - len), len);
g_byte_array_set_size (freeme, len);
}
else
{
2005-07-07 04:06:23 -07:00
append (pt, string, len);
}
break;
}
else if (freeme)
{
g_byte_array_free (freeme, TRUE);
2005-07-07 04:06:23 -07:00
g_queue_pop_head (pt->priv->pending_write);
}
}
else
{
g_message ("%s: stopping writing to child", G_STRLOC);
if (err)
g_message ("%s: %s", G_STRLOC, g_strerror (err));
2005-07-07 04:06:23 -07:00
kill_child (pt);
}
2005-06-22 15:13:12 -07:00
}
2005-07-07 04:06:23 -07:00
if (!g_queue_is_empty (pt->priv->pending_write))
start_writer (pt);
else
2005-07-07 04:06:23 -07:00
stop_writer (pt);
2005-06-22 15:13:12 -07:00
}
static char
get_erase_char (MooTermPt *pt_gen)
{
MooTermPtUnix *pt = MOO_TERM_PT_UNIX (pt_gen);
struct termios tio;
g_return_val_if_fail (pt->master != -1, 0);
if (!tcgetattr (pt->master, &tio))
{
return tio.c_cc[VERASE];
}
else
{
g_warning ("%s: %s", G_STRLOC,
g_strerror (errno));
2005-07-26 04:12:40 -07:00
return 127;
}
}
static void
send_intr (MooTermPt *pt)
{
g_return_if_fail (pt->priv->child_alive);
pt_discard_pending_write (pt);
pt_write (pt, "\003", 1);
}
2005-07-26 04:12:40 -07:00
/* TODO: it should be in glib */
MooTermCommand*
_moo_term_get_default_shell (void)
2005-07-26 04:12:40 -07:00
{
static char *argv[2] = {NULL, NULL};
2005-07-26 04:12:40 -07:00
if (!argv[0])
{
argv[0] = g_strdup (g_getenv ("SHELL"));
if (!argv[0]) argv[0] = g_strdup ("/bin/sh");
}
2005-07-26 04:12:40 -07:00
return moo_term_command_new (NULL, argv);
2005-07-26 04:12:40 -07:00
}
2005-07-30 23:20:59 -07:00
/* it's a win32 function */
void
moo_term_set_helper_directory (G_GNUC_UNUSED const char *dir)
2005-07-30 23:20:59 -07:00
{
g_return_if_reached ();
}
static char *argv_to_cmd_line (char **argv)
{
GString *cmd = NULL;
char **p;
g_return_val_if_fail (argv && argv[0], NULL);
for (p = argv; *p != NULL; ++p)
{
char *quoted = g_shell_quote (*p);
/* TODO: may not happen? */
g_return_val_if_fail (quoted != NULL,
g_string_free (cmd, FALSE));
if (cmd)
g_string_append_printf (cmd, " %s", quoted);
else
cmd = g_string_new (quoted);
g_free (quoted);
}
return g_string_free (cmd, FALSE);
}
static char **cmd_line_to_argv (const char *cmd_line,
GError **error)
{
int argc;
char **argv;
g_shell_parse_argv (cmd_line, &argc, &argv, error);
return argv;
}
gboolean
_moo_term_check_cmd (MooTermCommand *cmd,
GError **error)
{
g_return_val_if_fail (cmd != NULL, FALSE);
g_return_val_if_fail (cmd->cmd_line != NULL || cmd->argv != NULL, FALSE);
if (cmd->argv)
{
if (!cmd->argv[0])
{
g_set_error (error, MOO_TERM_ERROR, MOO_TERM_ERROR_INVAL,
"empty arguments array");
return FALSE;
}
g_free (cmd->cmd_line);
cmd->cmd_line = argv_to_cmd_line (cmd->argv);
g_return_val_if_fail (cmd->cmd_line != NULL, FALSE);
return TRUE;
}
cmd->argv = cmd_line_to_argv (cmd->cmd_line, error);
return cmd->argv != NULL;
}