Remove the old mch_call_shell implementation

This commit is contained in:
Thiago de Arruda 2014-04-05 09:35:54 -03:00
parent 2dcae28328
commit 57cd2d6614
2 changed files with 0 additions and 493 deletions

View File

@ -87,7 +87,6 @@ typedef union wait waitstatus;
#else
typedef int waitstatus;
#endif
static pid_t wait4pid(pid_t, waitstatus *);
static int RealWaitForChar(int, long, int *);
@ -1069,497 +1068,6 @@ void mch_new_shellsize()
/* Nothing to do. */
}
/*
* Wait for process "child" to end.
* Return "child" if it exited properly, <= 0 on error.
*/
static pid_t wait4pid(child, status)
pid_t child;
waitstatus *status;
{
pid_t wait_pid = 0;
while (wait_pid != child) {
/* When compiled with Python threads are probably used, in which case
* wait() sometimes hangs for no obvious reason. Use waitpid()
* instead and loop (like the GUI). Also needed for other interfaces,
* they might call system(). */
# ifdef __NeXT__
wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
# else
wait_pid = waitpid(child, status, WNOHANG);
# endif
if (wait_pid == 0) {
/* Wait for 10 msec before trying again. */
os_delay(10L, TRUE);
continue;
}
if (wait_pid <= 0
# ifdef ECHILD
&& errno == ECHILD
# endif
)
break;
}
return wait_pid;
}
int mch_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
{
int tmode = cur_tmode;
# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
127, some shells use that already */
pid_t pid;
pid_t wpid = 0;
pid_t wait_pid = 0;
# ifdef HAVE_UNION_WAIT
union wait status;
# else
int status = -1;
# endif
int retval = -1;
char **argv = NULL;
int i;
int fd_toshell[2]; /* for pipes */
int fd_fromshell[2];
int pipe_error = FALSE;
char envbuf[50];
int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
out_flush();
if (opts & kShellOptCooked)
settmode(TMODE_COOK); /* set to normal mode */
argv = shell_build_argv(cmd, extra_shell_arg);
if (argv == NULL) {
goto error;
}
/*
* For the GUI, when writing the output into the buffer and when reading
* input from the buffer: Try using a pseudo-tty to get the stdin/stdout
* of the executed command into the Vim window. Or use a pipe.
*/
if (opts & (kShellOptRead|kShellOptWrite)) {
{
pipe_error = (pipe(fd_toshell) < 0);
if (!pipe_error) { /* pipe create OK */
pipe_error = (pipe(fd_fromshell) < 0);
if (pipe_error) { /* pipe create failed */
close(fd_toshell[0]);
close(fd_toshell[1]);
}
}
if (pipe_error) {
MSG_PUTS(_("\nCannot create pipes\n"));
out_flush();
}
}
}
if (!pipe_error) { /* pty or pipe opened or not used */
if ((pid = fork()) == -1) { /* maybe we should use vfork() */
MSG_PUTS(_("\nCannot fork\n"));
if (opts & (kShellOptRead | kShellOptWrite)) {
{
close(fd_toshell[0]);
close(fd_toshell[1]);
close(fd_fromshell[0]);
close(fd_fromshell[1]);
}
}
} else if (pid == 0) { /* child */
signal_stop(); /* handle signals normally */
if (opts & (kShellOptHideMess | kShellOptExpand)) {
int fd;
/*
* Don't want to show any message from the shell. Can't just
* close stdout and stderr though, because some systems will
* break if you try to write to them after that, so we must
* use dup() to replace them with something else -- webb
* Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
* waiting for input.
*/
fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
fclose(stdin);
fclose(stdout);
fclose(stderr);
/*
* If any of these open()'s and dup()'s fail, we just continue
* anyway. It's not fatal, and on most systems it will make
* no difference at all. On a few it will cause the execvp()
* to exit with a non-zero status even when the completion
* could be done, which is nothing too serious. If the open()
* or dup() failed we'd just do the same thing ourselves
* anyway -- webb
*/
if (fd >= 0) {
ignored = dup(fd); /* To replace stdin (fd 0) */
ignored = dup(fd); /* To replace stdout (fd 1) */
ignored = dup(fd); /* To replace stderr (fd 2) */
/* Don't need this now that we've duplicated it */
close(fd);
}
} else if (opts & (kShellOptRead|kShellOptWrite)) {
# ifdef HAVE_SETSID
/* Create our own process group, so that the child and all its
* children can be kill()ed. Don't do this when using pipes,
* because stdin is not a tty, we would lose /dev/tty. */
if (p_stmp) {
(void)setsid();
# if defined(SIGHUP)
/* When doing "!xterm&" and 'shell' is bash: the shell
* will exit and send SIGHUP to all processes in its
* group, killing the just started process. Ignore SIGHUP
* to avoid that. (suggested by Simon Schubert)
*/
signal(SIGHUP, SIG_IGN);
# endif
}
# endif
/* Simulate to have a dumb terminal (for now) */
os_setenv("TERM", "dumb", 1);
sprintf((char *)envbuf, "%ld", Rows);
os_setenv("ROWS", (char *)envbuf, 1);
sprintf((char *)envbuf, "%ld", Rows);
os_setenv("LINES", (char *)envbuf, 1);
sprintf((char *)envbuf, "%ld", Columns);
os_setenv("COLUMNS", (char *)envbuf, 1);
/*
* stderr is only redirected when using the GUI, so that a
* program like gpg can still access the terminal to get a
* passphrase using stderr.
*/
{
/* set up stdin for the child */
close(fd_toshell[1]);
close(0);
ignored = dup(fd_toshell[0]);
close(fd_toshell[0]);
/* set up stdout for the child */
close(fd_fromshell[0]);
close(1);
ignored = dup(fd_fromshell[1]);
close(fd_fromshell[1]);
}
}
/*
* There is no type cast for the argv, because the type may be
* different on different machines. This may cause a warning
* message with strict compilers, don't worry about it.
* Call _exit() instead of exit() to avoid closing the connection
* to the X server (esp. with GTK, which uses atexit()).
*/
execvp(argv[0], argv);
_exit(EXEC_FAILED); /* exec failed, return failure code */
} else { /* parent */
/*
* While child is running, ignore terminating signals.
* Do catch CTRL-C, so that "got_int" is set.
*/
signal_reject_deadly();
/*
* For the GUI we redirect stdin, stdout and stderr to our window.
* This is also used to pipe stdin/stdout to/from the external
* command.
*/
if (opts & (kShellOptRead|kShellOptWrite)) {
# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
char_u buffer[BUFLEN + 1];
int buffer_off = 0; /* valid bytes in buffer[] */
char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
int ta_len = 0; /* valid bytes in ta_buf[] */
int len;
int p_more_save;
int old_State;
int toshell_fd;
int fromshell_fd;
garray_T ga;
int noread_cnt;
# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
struct timeval start_tv;
# endif
{
close(fd_toshell[0]);
close(fd_fromshell[1]);
toshell_fd = fd_toshell[1];
fromshell_fd = fd_fromshell[0];
}
/*
* Write to the child if there are typed characters.
* Read from the child if there are characters available.
* Repeat the reading a few times if more characters are
* available. Need to check for typed keys now and then, but
* not too often (delays when no chars are available).
* This loop is quit if no characters can be read from the pty
* (WaitForChar detected special condition), or there are no
* characters available and the child has exited.
* Only check if the child has exited when there is no more
* output. The child may exit before all the output has
* been printed.
*
* Currently this busy loops!
* This can probably dead-lock when the write blocks!
*/
p_more_save = p_more;
p_more = FALSE;
old_State = State;
State = EXTERNCMD; /* don't redraw at window resize */
if ((opts & kShellOptWrite) && toshell_fd >= 0) {
/* Fork a process that will write the lines to the
* external program. */
if ((wpid = fork()) == -1) {
MSG_PUTS(_("\nCannot fork\n"));
} else if (wpid == 0) { /* child */
linenr_T lnum = curbuf->b_op_start.lnum;
int written = 0;
char_u *lp = ml_get(lnum);
size_t l;
close(fromshell_fd);
for (;; ) {
l = STRLEN(lp + written);
if (l == 0)
len = 0;
else if (lp[written] == NL)
/* NL -> NUL translation */
len = write(toshell_fd, "", (size_t)1);
else {
char_u *s = vim_strchr(lp + written, NL);
len = write(toshell_fd, (char *)lp + written,
s == NULL ? l
: (size_t)(s - (lp + written)));
}
if (len == (int)l) {
/* Finished a line, add a NL, unless this line
* should not have one. */
if (lnum != curbuf->b_op_end.lnum
|| !curbuf->b_p_bin
|| (lnum != curbuf->b_no_eol_lnum
&& (lnum !=
curbuf->b_ml.ml_line_count
|| curbuf->b_p_eol)))
ignored = write(toshell_fd, "\n",
(size_t)1);
++lnum;
if (lnum > curbuf->b_op_end.lnum) {
/* finished all the lines, close pipe */
close(toshell_fd);
toshell_fd = -1;
break;
}
lp = ml_get(lnum);
written = 0;
} else if (len > 0)
written += len;
}
_exit(0);
} else { /* parent */
close(toshell_fd);
toshell_fd = -1;
}
}
if (opts & kShellOptRead)
ga_init(&ga, 1, BUFLEN);
noread_cnt = 0;
# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
gettimeofday(&start_tv, NULL);
# endif
for (;; ) {
len = 0;
if (got_int) {
/* CTRL-C sends a signal to the child, we ignore it
* ourselves */
# ifdef HAVE_SETSID
kill(-pid, SIGINT);
# else
kill(0, SIGINT);
# endif
if (wpid > 0)
kill(wpid, SIGINT);
got_int = FALSE;
}
/*
* Check if the child has any characters to be printed.
* Read them and write them to our window. Repeat this as
* long as there is something to do, avoid the 10ms wait
* for os_inchar(), or sending typeahead characters to
* the external process.
* TODO: This should handle escape sequences, compatible
* to some terminal (vt52?).
*/
++noread_cnt;
while (RealWaitForChar(fromshell_fd, 10L, NULL)) {
len = read_eintr(fromshell_fd, buffer
+ buffer_off, (size_t)(BUFLEN - buffer_off)
);
if (len <= 0) /* end of file or error */
goto finished;
noread_cnt = 0;
if (opts & kShellOptRead) {
/* Do NUL -> NL translation, append NL separated
* lines to the current buffer. */
for (i = 0; i < len; ++i) {
if (buffer[i] == NL)
append_ga_line(&ga);
else if (buffer[i] == NUL)
ga_append(&ga, NL);
else
ga_append(&ga, buffer[i]);
}
}
windgoto(msg_row, msg_col);
cursor_on();
out_flush();
if (got_int)
break;
# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
{
struct timeval now_tv;
long msec;
/* Avoid that we keep looping here without
* checking for a CTRL-C for a long time. Don't
* break out too often to avoid losing typeahead. */
gettimeofday(&now_tv, NULL);
msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
+ (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
if (msec > 2000) {
noread_cnt = 5;
break;
}
}
# endif
}
/* If we already detected the child has finished break the
* loop now. */
if (wait_pid == pid)
break;
/*
* Check if the child still exists, before checking for
* typed characters (otherwise we would lose typeahead).
*/
# ifdef __NeXT__
wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
# else
wait_pid = waitpid(pid, &status, WNOHANG);
# endif
if ((wait_pid == (pid_t)-1 && errno == ECHILD)
|| (wait_pid == pid && WIFEXITED(status))) {
/* Don't break the loop yet, try reading more
* characters from "fromshell_fd" first. When using
* pipes there might still be something to read and
* then we'll break the loop at the "break" above. */
wait_pid = pid;
} else
wait_pid = 0;
}
finished:
p_more = p_more_save;
if (opts & kShellOptRead) {
if (ga.ga_len > 0) {
append_ga_line(&ga);
/* remember that the NL was missing */
curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
} else
curbuf->b_no_eol_lnum = 0;
ga_clear(&ga);
}
/*
* Give all typeahead that wasn't used back to ui_inchar().
*/
if (ta_len)
ui_inchar_undo(ta_buf, ta_len);
State = old_State;
if (toshell_fd >= 0)
close(toshell_fd);
close(fromshell_fd);
}
/*
* Wait until our child has exited.
* Ignore wait() returning pids of other children and returning
* because of some signal like SIGWINCH.
* Don't wait if wait_pid was already set above, indicating the
* child already exited.
*/
if (wait_pid != pid)
wait_pid = wait4pid(pid, &status);
/* Make sure the child that writes to the external program is
* dead. */
if (wpid > 0) {
kill(wpid, SIGKILL);
wait4pid(wpid, NULL);
}
/*
* Set to raw mode right now, otherwise a CTRL-C after
* catch_signals() will kill Vim.
*/
if (tmode == TMODE_RAW)
settmode(TMODE_RAW);
did_settmode = TRUE;
signal_accept_deadly();
if (WIFEXITED(status)) {
/* LINTED avoid "bitwise operation on signed value" */
retval = WEXITSTATUS(status);
if (retval != 0 && !emsg_silent) {
if (retval == EXEC_FAILED) {
MSG_PUTS(_("\nCannot execute shell "));
msg_outtrans(p_sh);
msg_putchar('\n');
} else if (!(opts & kShellOptSilent)) {
MSG_PUTS(_("\nshell returned "));
msg_outnum((long)retval);
msg_putchar('\n');
}
}
} else
MSG_PUTS(_("\nCommand terminated\n"));
}
}
shell_free_argv(argv);
error:
if (!did_settmode)
if (tmode == TMODE_RAW)
settmode(TMODE_RAW); /* set to raw mode */
resettitle();
return retval;
}
/*
* Wait "msec" msec until a character is available from file descriptor "fd".
* "msec" == 0 will check for characters once.

View File

@ -40,7 +40,6 @@ int mch_screenmode(char_u *arg);
int mch_get_shellsize(void);
void mch_set_shellsize(void);
void mch_new_shellsize(void);
int mch_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg);
int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file,
char_u ***file,
int flags);