Mercurial > hg > Applications > mh
diff miscellany/less-177/lsystem.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/miscellany/less-177/lsystem.c Mon Apr 18 23:46:02 2005 +0900 @@ -0,0 +1,305 @@ +/* + * Routines to execute other programs. + * Necessarily very OS dependent. + */ + +#include <stdio.h> +#include <signal.h> + +#include "less.h" +#include "position.h" + +#if __MSDOS__ +#include <process.h> +#include <dos.h> +#include <fcntl.h> +#include <io.h> +#include <errno.h> +#include <dir.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <ctype.h> +char get_swchar(); +void swchar_to_dos(); +void swchar_to_unix(); +#endif + +extern char *getenv(); + +extern int screen_trashed; +extern IFILE curr_ifile; + + +/* + * Pass the specified command to a shell to be executed. + * Like plain "system()", but handles resetting terminal modes, etc. + */ + public void +lsystem(cmd) + char *cmd; +{ + register int inp; + register char *shell; + register char *p; + register char *curr_filename; + + /* + * Print the command which is to be executed, + * unless the command starts with a "-". + */ + if (cmd[0] == '-') + cmd++; + else + { + lower_left(); + clear_eol(); + putstr("!"); + putstr(cmd); + putstr("\n"); + } + + /* + * Close the current input file. + */ + curr_filename = get_filename(curr_ifile); + (void) edit(NULL, 0); + + /* + * De-initialize the terminal and take out of raw mode. + */ + deinit(); + flush(); /* Make sure the deinit chars get out */ + raw_mode(0); + + /* + * Restore signals to their defaults. + */ + init_signals(0); + + /* + * Force standard input to be the user's terminal + * (the normal standard input), even if less's standard input + * is coming from a pipe. + */ +#if __MSDOS__ +{ + register int inp2; + + inp = dup(0); + inp2 = open("CON", O_TEXT|O_RDONLY); + dup2(0,inp2); +} +#else + inp = dup(0); + close(0); + if (open("/dev/tty", 0) < 0) + dup(inp); +#endif + + /* + * Pass the command to the system to be executed. + * If we have a SHELL environment variable, use + * <$SHELL -c "command"> instead of just <command>. + * If the command is empty, just invoke a shell. + */ +#if __MSDOS__ +{ + int result; + char sw_char; + + sw_char = get_swchar(); + swchar_to_dos(); + result = system(cmd); + if (result != 0) + perror("less"); + if (sw_char == '-') + swchar_to_unix(); +} +#else + p = NULL; + if ((shell = getenv("SHELL")) != NULL && *shell != '\0') + { + if (*cmd == '\0') + p = save(shell); + else + { + p = (char *) ecalloc(strlen(shell) + strlen(cmd) + 7, + sizeof(char)); + sprintf(p, "%s -c \"%s\"", shell, cmd); + } + } + if (p == NULL) + { + if (*cmd == '\0') + p = save("sh"); + else + p = save(cmd); + } + + system(p); + free(p); +#endif + + /* + * Restore standard input, reset signals, raw mode, etc. + */ +#if __MSDOS__ + close(inp2); + dup2(0,inp); + close(inp); +#else + close(0); + dup(inp); + close(inp); +#endif + + init_signals(1); + raw_mode(1); + init(); + screen_trashed = 1; + + /* + * Reopen the current input file. + */ + (void) edit(curr_filename, 0); + +#if defined(SIGWINCH) || defined(SIGWIND) + /* + * Since we were ignoring window change signals while we executed + * the system command, we must assume the window changed. + * Warning: this leaves a signal pending (in "sigs"), + * so psignals() should be called soon after lsystem(). + */ + winch(); +#endif +} + +#if PIPEC + +/* + * Pipe a section of the input file into the given shell command. + * The section to be piped is the section "between" the current + * position and the position marked by the given letter. + * + * The "current" position means the top line displayed if the mark + * is after the current screen, or the bottom line displayed if + * the mark is before the current screen. + * If the mark is on the current screen, the whole screen is displayed. + */ + public int +pipe_mark(c, cmd) + int c; + char *cmd; +{ + POSITION mpos, tpos, bpos; + + /* + * mpos = the marked position. + * tpos = top of screen. + * bpos = bottom of screen. + */ + mpos = markpos(c); + if (mpos == NULL_POSITION) + return (-1); + tpos = position(TOP); + if (tpos == NULL_POSITION) + tpos = ch_zero(); + bpos = position(BOTTOM); + + if (c == '.') + return (pipe_data(cmd, tpos, bpos)); + else if (mpos <= tpos) + return (pipe_data(cmd, mpos, tpos)); + else if (bpos == NULL_POSITION) + return (pipe_data(cmd, tpos, bpos)); + else + return (pipe_data(cmd, tpos, mpos)); +} + +/* + * Create a pipe to the given shell command. + * Feed it the file contents between the positions spos and epos. + */ + public int +pipe_data(cmd, spos, epos) + char *cmd; + POSITION spos; + POSITION epos; +{ + register FILE *f; + register int c; + extern FILE *popen(); + + /* + * This is structured much like lsystem(). + * Since we're running a shell program, we must be careful + * to perform the necessary deinitialization before running + * the command, and reinitialization after it. + */ + if (ch_seek(spos) != 0) + { + error("Cannot seek to start position", NULL_PARG); + return (-1); + } + + if ((f = popen(cmd, "w")) == NULL) + { + error("Cannot create pipe", NULL_PARG); + return (-1); + } + lower_left(); + clear_eol(); + putstr("!"); + putstr(cmd); + putstr("\n"); + + deinit(); + flush(); + raw_mode(0); + init_signals(0); +#ifdef SIGPIPE + SIGNAL(SIGPIPE, SIG_IGN); +#endif + + while (epos == NULL_POSITION || spos++ <= epos) + { + /* + * Read a character from the file and give it to the pipe. + */ + c = ch_forw_get(); + if (c == EOI) + break; + if (putc(c, f) == EOF) + break; + } + + /* + * Finish up the last line. + */ + while (c != '\n' && c != EOI ) + { + c = ch_forw_get(); + if (c == EOI) + break; + if (putc(c, f) == EOF) + break; + } + + pclose(f); + +#ifdef SIGPIPE + SIGNAL(SIGPIPE, SIG_DFL); +#endif + init_signals(1); + raw_mode(1); + init(); + screen_trashed = 1; +#if defined(SIGWINCH) || defined(SIGWIND) + /* {{ Probably don't need this here. }} */ + winch(); +#endif + return (0); +} + +#endif