version 1.9, 2014/04/25 13:38:21 |
version 1.10, 2015/11/05 22:08:44 |
|
|
* |
* |
* For more information, see the README file. |
* For more information, see the README file. |
*/ |
*/ |
|
/* |
|
* Modified for use with illumos. |
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
|
*/ |
|
|
|
|
/* |
/* |
* Routines to execute other programs. |
* Routines to execute other programs. |
* Necessarily very OS dependent. |
* Necessarily very OS dependent. |
|
|
#include <signal.h> |
#include <signal.h> |
#include "position.h" |
#include "position.h" |
|
|
#if MSDOS_COMPILER |
|
#include <dos.h> |
|
#ifdef _MSC_VER |
|
#include <direct.h> |
|
#define setdisk(n) _chdrive((n)+1) |
|
#else |
|
#include <dir.h> |
|
#endif |
|
#endif |
|
|
|
extern int screen_trashed; |
extern int screen_trashed; |
extern IFILE curr_ifile; |
extern IFILE curr_ifile; |
|
|
|
static int pipe_data(char *cmd, off_t spos, off_t epos); |
|
|
#if HAVE_SYSTEM |
|
|
|
/* |
/* |
* Pass the specified command to a shell to be executed. |
* Pass the specified command to a shell to be executed. |
* Like plain "system()", but handles resetting terminal modes, etc. |
* Like plain "system()", but handles resetting terminal modes, etc. |
*/ |
*/ |
public void |
void |
lsystem(cmd, donemsg) |
lsystem(const char *cmd, const char *donemsg) |
char *cmd; |
|
char *donemsg; |
|
{ |
{ |
register int inp; |
int inp; |
#if HAVE_SHELL |
char *shell; |
register char *shell; |
char *p; |
register char *p; |
|
#endif |
|
IFILE save_ifile; |
IFILE save_ifile; |
#if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C |
|
char cwd[FILENAME_MAX+1]; |
|
#endif |
|
|
|
/* |
/* |
* Print the command which is to be executed, |
* Print the command which is to be executed, |
|
|
*/ |
*/ |
if (cmd[0] == '-') |
if (cmd[0] == '-') |
cmd++; |
cmd++; |
else |
else { |
{ |
|
clear_bot(); |
clear_bot(); |
putstr("!"); |
putstr("!"); |
putstr(cmd); |
putstr(cmd); |
putstr("\n"); |
putstr("\n"); |
} |
} |
|
|
#if MSDOS_COMPILER |
|
#if MSDOS_COMPILER==WIN32C |
|
if (*cmd == '\0') |
|
cmd = getenv("COMSPEC"); |
|
#else |
|
/* |
/* |
* Working directory is global on MSDOS. |
|
* The child might change the working directory, so we |
|
* must save and restore CWD across calls to "system", |
|
* or else we won't find our file when we return and |
|
* try to "reedit_ifile" it. |
|
*/ |
|
getcwd(cwd, FILENAME_MAX); |
|
#endif |
|
#endif |
|
|
|
/* |
|
* Close the current input file. |
* Close the current input file. |
*/ |
*/ |
save_ifile = save_curr_ifile(); |
save_ifile = save_curr_ifile(); |
|
|
deinit(); |
deinit(); |
flush(); /* Make sure the deinit chars get out */ |
flush(); /* Make sure the deinit chars get out */ |
raw_mode(0); |
raw_mode(0); |
#if MSDOS_COMPILER==WIN32C |
|
close_getchr(); |
|
#endif |
|
|
|
/* |
/* |
* Restore signals to their defaults. |
* Restore signals to their defaults. |
*/ |
*/ |
init_signals(0); |
init_signals(0); |
|
|
#if HAVE_DUP |
|
/* |
/* |
* Force standard input to be the user's terminal |
* Force standard input to be the user's terminal |
* (the normal standard input), even if less's standard input |
* (the normal standard input), even if less's standard input |
* is coming from a pipe. |
* is coming from a pipe. |
*/ |
*/ |
inp = dup(0); |
inp = dup(0); |
close(0); |
(void) close(0); |
#if OS2 |
|
/* The __open() system call translates "/dev/tty" to "con". */ |
|
if (__open("/dev/tty", OPEN_READ) < 0) |
|
#else |
|
if (open("/dev/tty", OPEN_READ) < 0) |
if (open("/dev/tty", OPEN_READ) < 0) |
#endif |
(void) dup(inp); |
dup(inp); |
|
#endif |
|
|
|
/* |
/* |
* Pass the command to the system to be executed. |
* Pass the command to the system to be executed. |
|
|
* <$SHELL -c "command"> instead of just <command>. |
* <$SHELL -c "command"> instead of just <command>. |
* If the command is empty, just invoke a shell. |
* If the command is empty, just invoke a shell. |
*/ |
*/ |
#if HAVE_SHELL |
|
p = NULL; |
p = NULL; |
if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') |
if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') { |
{ |
if (*cmd == '\0') { |
if (*cmd == '\0') |
|
p = save(shell); |
p = save(shell); |
else |
} else { |
{ |
|
char *esccmd = shell_quote(cmd); |
char *esccmd = shell_quote(cmd); |
if (esccmd != NULL) |
if (esccmd != NULL) { |
{ |
p = easprintf("%s -c %s", shell, esccmd); |
size_t len = strlen(shell) + strlen(esccmd) + 5; |
|
p = (char *) ecalloc(len, sizeof(char)); |
|
SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd); |
|
free(esccmd); |
free(esccmd); |
} |
} |
} |
} |
} |
} |
if (p == NULL) |
if (p == NULL) { |
{ |
|
if (*cmd == '\0') |
if (*cmd == '\0') |
p = save("sh"); |
p = save("sh"); |
else |
else |
p = save(cmd); |
p = save(cmd); |
} |
} |
system(p); |
(void) system(p); |
free(p); |
free(p); |
#else |
|
#if MSDOS_COMPILER==DJGPPC |
|
/* |
|
* Make stdin of the child be in cooked mode. |
|
*/ |
|
setmode(0, O_TEXT); |
|
/* |
|
* We don't need to catch signals of the child (it |
|
* also makes trouble with some DPMI servers). |
|
*/ |
|
__djgpp_exception_toggle(); |
|
system(cmd); |
|
__djgpp_exception_toggle(); |
|
#else |
|
system(cmd); |
|
#endif |
|
#endif |
|
|
|
#if HAVE_DUP |
|
/* |
/* |
* Restore standard input, reset signals, raw mode, etc. |
* Restore standard input, reset signals, raw mode, etc. |
*/ |
*/ |
close(0); |
(void) close(0); |
dup(inp); |
(void) dup(inp); |
close(inp); |
(void) close(inp); |
#endif |
|
|
|
#if MSDOS_COMPILER==WIN32C |
|
open_getchr(); |
|
#endif |
|
init_signals(1); |
init_signals(1); |
raw_mode(1); |
raw_mode(1); |
if (donemsg != NULL) |
if (donemsg != NULL) { |
{ |
|
putstr(donemsg); |
putstr(donemsg); |
putstr(" (press RETURN)"); |
putstr(" (press RETURN)"); |
get_return(); |
get_return(); |
putchr('\n'); |
(void) putchr('\n'); |
flush(); |
flush(); |
} |
} |
init(); |
init(); |
screen_trashed = 1; |
screen_trashed = 1; |
|
|
#if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C |
|
/* |
/* |
* Restore the previous directory (possibly |
|
* changed by the child program we just ran). |
|
*/ |
|
chdir(cwd); |
|
#if MSDOS_COMPILER != DJGPPC |
|
/* |
|
* Some versions of chdir() don't change to the drive |
|
* which is part of CWD. (DJGPP does this in chdir.) |
|
*/ |
|
if (cwd[1] == ':') |
|
{ |
|
if (cwd[0] >= 'a' && cwd[0] <= 'z') |
|
setdisk(cwd[0] - 'a'); |
|
else if (cwd[0] >= 'A' && cwd[0] <= 'Z') |
|
setdisk(cwd[0] - 'A'); |
|
} |
|
#endif |
|
#endif |
|
|
|
/* |
|
* Reopen the current input file. |
* Reopen the current input file. |
*/ |
*/ |
reedit_ifile(save_ifile); |
reedit_ifile(save_ifile); |
|
|
#if defined(SIGWINCH) || defined(SIGWIND) |
|
/* |
/* |
* Since we were ignoring window change signals while we executed |
* Since we were ignoring window change signals while we executed |
* the system command, we must assume the window changed. |
* the system command, we must assume the window changed. |
* Warning: this leaves a signal pending (in "sigs"), |
* Warning: this leaves a signal pending (in "sigs"), |
* so psignals() should be called soon after lsystem(). |
* so psignals() should be called soon after lsystem(). |
*/ |
*/ |
winch(0); |
sigwinch(0); |
#endif |
|
} |
} |
|
|
#endif |
|
|
|
#if PIPEC |
|
|
|
/* |
/* |
* Pipe a section of the input file into the given shell command. |
* Pipe a section of the input file into the given shell command. |
* The section to be piped is the section "between" the current |
* The section to be piped is the section "between" the current |
|
|
* If the mark is on the current screen, or if the mark is ".", |
* If the mark is on the current screen, or if the mark is ".", |
* the whole current screen is piped. |
* the whole current screen is piped. |
*/ |
*/ |
public int |
int |
pipe_mark(c, cmd) |
pipe_mark(int c, char *cmd) |
int c; |
|
char *cmd; |
|
{ |
{ |
POSITION mpos, tpos, bpos; |
off_t mpos, tpos, bpos; |
|
|
/* |
/* |
* mpos = the marked position. |
* mpos = the marked position. |
|
|
* bpos = bottom of screen. |
* bpos = bottom of screen. |
*/ |
*/ |
mpos = markpos(c); |
mpos = markpos(c); |
if (mpos == NULL_POSITION) |
if (mpos == -1) |
return (-1); |
return (-1); |
tpos = position(TOP); |
tpos = position(TOP); |
if (tpos == NULL_POSITION) |
if (tpos == -1) |
tpos = ch_zero(); |
tpos = ch_zero(); |
bpos = position(BOTTOM); |
bpos = position(BOTTOM); |
|
|
if (c == '.') |
if (c == '.') |
return (pipe_data(cmd, tpos, bpos)); |
return (pipe_data(cmd, tpos, bpos)); |
else if (mpos <= tpos) |
else if (mpos <= tpos) |
return (pipe_data(cmd, mpos, bpos)); |
return (pipe_data(cmd, mpos, bpos)); |
else if (bpos == NULL_POSITION) |
else if (bpos == -1) |
return (pipe_data(cmd, tpos, bpos)); |
return (pipe_data(cmd, tpos, bpos)); |
else |
else |
return (pipe_data(cmd, tpos, mpos)); |
return (pipe_data(cmd, tpos, mpos)); |
} |
} |
|
|
/* |
/* |
* Create a pipe to the given shell command. |
* Create a pipe to the given shell command. |
* Feed it the file contents between the positions spos and epos. |
* Feed it the file contents between the positions spos and epos. |
*/ |
*/ |
public int |
static int |
pipe_data(cmd, spos, epos) |
pipe_data(char *cmd, off_t spos, off_t epos) |
char *cmd; |
|
POSITION spos; |
|
POSITION epos; |
|
{ |
{ |
register FILE *f; |
FILE *f; |
register int c; |
int c; |
extern FILE *popen(); |
|
|
|
/* |
/* |
* This is structured much like lsystem(). |
* This is structured much like lsystem(). |
|
|
* to perform the necessary deinitialization before running |
* to perform the necessary deinitialization before running |
* the command, and reinitialization after it. |
* the command, and reinitialization after it. |
*/ |
*/ |
if (ch_seek(spos) != 0) |
if (ch_seek(spos) != 0) { |
{ |
|
error("Cannot seek to start position", NULL_PARG); |
error("Cannot seek to start position", NULL_PARG); |
return (-1); |
return (-1); |
} |
} |
|
|
if ((f = popen(cmd, "w")) == NULL) |
if ((f = popen(cmd, "w")) == NULL) { |
{ |
|
error("Cannot create pipe", NULL_PARG); |
error("Cannot create pipe", NULL_PARG); |
return (-1); |
return (-1); |
} |
} |
|
|
flush(); |
flush(); |
raw_mode(0); |
raw_mode(0); |
init_signals(0); |
init_signals(0); |
#if MSDOS_COMPILER==WIN32C |
|
close_getchr(); |
|
#endif |
|
#ifdef SIGPIPE |
|
LSIGNAL(SIGPIPE, SIG_IGN); |
LSIGNAL(SIGPIPE, SIG_IGN); |
#endif |
|
|
|
c = EOI; |
c = EOI; |
while (epos == NULL_POSITION || spos++ <= epos) |
while (epos == -1 || spos++ <= epos) { |
{ |
|
/* |
/* |
* Read a character from the file and give it to the pipe. |
* Read a character from the file and give it to the pipe. |
*/ |
*/ |
|
|
/* |
/* |
* Finish up the last line. |
* Finish up the last line. |
*/ |
*/ |
while (c != '\n' && c != EOI ) |
while (c != '\n' && c != EOI) { |
{ |
c = ch_forw_get(); |
c = ch_forw_get(); |
if (c == EOI) |
if (c == EOI) |
break; |
break; |
if (putc(c, f) == EOF) |
if (putc(c, f) == EOF) |
break; |
break; |
} |
} |
|
|
|
pclose(f); |
(void) pclose(f); |
|
|
#ifdef SIGPIPE |
|
LSIGNAL(SIGPIPE, SIG_DFL); |
LSIGNAL(SIGPIPE, SIG_DFL); |
#endif |
|
#if MSDOS_COMPILER==WIN32C |
|
open_getchr(); |
|
#endif |
|
init_signals(1); |
init_signals(1); |
raw_mode(1); |
raw_mode(1); |
init(); |
init(); |
screen_trashed = 1; |
screen_trashed = 1; |
#if defined(SIGWINCH) || defined(SIGWIND) |
|
/* {{ Probably don't need this here. }} */ |
/* {{ Probably don't need this here. }} */ |
winch(0); |
sigwinch(0); |
#endif |
|
return (0); |
return (0); |
} |
} |
|
|
#endif |
|