1238730Sdelphij/* 2238730Sdelphij * Copyright (C) 1984-2012 Mark Nudelman 3238730Sdelphij * 4238730Sdelphij * You may distribute under the terms of either the GNU General Public 5238730Sdelphij * License or the Less License, as specified in the README file. 6238730Sdelphij * 7238730Sdelphij * For more information, see the README file. 8238730Sdelphij */ 960786Sps 1060786Sps 1160786Sps/* 1260786Sps * Routines to execute other programs. 1360786Sps * Necessarily very OS dependent. 1460786Sps */ 1560786Sps 1689019Sps#include "less.h" 1760786Sps#include <signal.h> 1860786Sps#include "position.h" 1960786Sps 2060786Sps#if MSDOS_COMPILER 2160786Sps#include <dos.h> 2260786Sps#ifdef _MSC_VER 2360786Sps#include <direct.h> 2460786Sps#define setdisk(n) _chdrive((n)+1) 2560786Sps#else 2660786Sps#include <dir.h> 2760786Sps#endif 2860786Sps#endif 2960786Sps 3060786Spsextern int screen_trashed; 3160786Spsextern IFILE curr_ifile; 3260786Sps 3360786Sps 3460786Sps#if HAVE_SYSTEM 3560786Sps 3660786Sps/* 3760786Sps * Pass the specified command to a shell to be executed. 3860786Sps * Like plain "system()", but handles resetting terminal modes, etc. 3960786Sps */ 4060786Sps public void 4160786Spslsystem(cmd, donemsg) 4260786Sps char *cmd; 4360786Sps char *donemsg; 4460786Sps{ 4560786Sps register int inp; 4660786Sps#if HAVE_SHELL 4760786Sps register char *shell; 4860786Sps register char *p; 4960786Sps#endif 5060786Sps IFILE save_ifile; 51191930Sdelphij#if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C 5260786Sps char cwd[FILENAME_MAX+1]; 5360786Sps#endif 5460786Sps 5560786Sps /* 5660786Sps * Print the command which is to be executed, 5760786Sps * unless the command starts with a "-". 5860786Sps */ 5960786Sps if (cmd[0] == '-') 6060786Sps cmd++; 6160786Sps else 6260786Sps { 6360786Sps clear_bot(); 6460786Sps putstr("!"); 6560786Sps putstr(cmd); 6660786Sps putstr("\n"); 6760786Sps } 6860786Sps 6960786Sps#if MSDOS_COMPILER 70191930Sdelphij#if MSDOS_COMPILER==WIN32C 71191930Sdelphij if (*cmd == '\0') 72191930Sdelphij cmd = getenv("COMSPEC"); 73191930Sdelphij#else 7460786Sps /* 7560786Sps * Working directory is global on MSDOS. 7660786Sps * The child might change the working directory, so we 7760786Sps * must save and restore CWD across calls to "system", 7860786Sps * or else we won't find our file when we return and 7960786Sps * try to "reedit_ifile" it. 8060786Sps */ 8160786Sps getcwd(cwd, FILENAME_MAX); 8260786Sps#endif 83191930Sdelphij#endif 8460786Sps 8560786Sps /* 8660786Sps * Close the current input file. 8760786Sps */ 8860786Sps save_ifile = save_curr_ifile(); 8960786Sps (void) edit_ifile(NULL_IFILE); 9060786Sps 9160786Sps /* 9260786Sps * De-initialize the terminal and take out of raw mode. 9360786Sps */ 9460786Sps deinit(); 9560786Sps flush(); /* Make sure the deinit chars get out */ 9660786Sps raw_mode(0); 9760786Sps#if MSDOS_COMPILER==WIN32C 9860786Sps close_getchr(); 9960786Sps#endif 10060786Sps 10160786Sps /* 10260786Sps * Restore signals to their defaults. 10360786Sps */ 10460786Sps init_signals(0); 10560786Sps 10660786Sps#if HAVE_DUP 10760786Sps /* 10860786Sps * Force standard input to be the user's terminal 10960786Sps * (the normal standard input), even if less's standard input 11060786Sps * is coming from a pipe. 11160786Sps */ 11260786Sps inp = dup(0); 11360786Sps close(0); 11489019Sps#if OS2 11589019Sps /* The __open() system call translates "/dev/tty" to "con". */ 11689019Sps if (__open("/dev/tty", OPEN_READ) < 0) 11789019Sps#else 11860786Sps if (open("/dev/tty", OPEN_READ) < 0) 11989019Sps#endif 12060786Sps dup(inp); 12160786Sps#endif 12260786Sps 12360786Sps /* 12460786Sps * Pass the command to the system to be executed. 12560786Sps * If we have a SHELL environment variable, use 12660786Sps * <$SHELL -c "command"> instead of just <command>. 12760786Sps * If the command is empty, just invoke a shell. 12860786Sps */ 12960786Sps#if HAVE_SHELL 13060786Sps p = NULL; 13160786Sps if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') 13260786Sps { 13360786Sps if (*cmd == '\0') 13460786Sps p = save(shell); 13560786Sps else 13660786Sps { 137128345Stjr char *esccmd = shell_quote(cmd); 138128345Stjr if (esccmd != NULL) 13960786Sps { 140161475Sdelphij int len = strlen(shell) + strlen(esccmd) + 5; 141161475Sdelphij p = (char *) ecalloc(len, sizeof(char)); 142161475Sdelphij SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd); 14360786Sps free(esccmd); 14460786Sps } 14560786Sps } 14660786Sps } 14760786Sps if (p == NULL) 14860786Sps { 14960786Sps if (*cmd == '\0') 15060786Sps p = save("sh"); 15160786Sps else 15260786Sps p = save(cmd); 15360786Sps } 15460786Sps system(p); 15560786Sps free(p); 15660786Sps#else 15760786Sps#if MSDOS_COMPILER==DJGPPC 15860786Sps /* 15960786Sps * Make stdin of the child be in cooked mode. 16060786Sps */ 16160786Sps setmode(0, O_TEXT); 16260786Sps /* 16360786Sps * We don't need to catch signals of the child (it 16460786Sps * also makes trouble with some DPMI servers). 16560786Sps */ 16660786Sps __djgpp_exception_toggle(); 16760786Sps system(cmd); 16860786Sps __djgpp_exception_toggle(); 16960786Sps#else 17060786Sps system(cmd); 17160786Sps#endif 17260786Sps#endif 17360786Sps 17460786Sps#if HAVE_DUP 17560786Sps /* 17660786Sps * Restore standard input, reset signals, raw mode, etc. 17760786Sps */ 17860786Sps close(0); 17960786Sps dup(inp); 18060786Sps close(inp); 18160786Sps#endif 18260786Sps 18360786Sps#if MSDOS_COMPILER==WIN32C 18460786Sps open_getchr(); 18560786Sps#endif 18660786Sps init_signals(1); 18760786Sps raw_mode(1); 18860786Sps if (donemsg != NULL) 18960786Sps { 19060786Sps putstr(donemsg); 19160786Sps putstr(" (press RETURN)"); 19260786Sps get_return(); 19360786Sps putchr('\n'); 19460786Sps flush(); 19560786Sps } 19660786Sps init(); 19760786Sps screen_trashed = 1; 19860786Sps 199191930Sdelphij#if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C 20060786Sps /* 20160786Sps * Restore the previous directory (possibly 20260786Sps * changed by the child program we just ran). 20360786Sps */ 20460786Sps chdir(cwd); 20560786Sps#if MSDOS_COMPILER != DJGPPC 20660786Sps /* 20760786Sps * Some versions of chdir() don't change to the drive 20860786Sps * which is part of CWD. (DJGPP does this in chdir.) 20960786Sps */ 21060786Sps if (cwd[1] == ':') 21160786Sps { 21260786Sps if (cwd[0] >= 'a' && cwd[0] <= 'z') 21360786Sps setdisk(cwd[0] - 'a'); 21460786Sps else if (cwd[0] >= 'A' && cwd[0] <= 'Z') 21560786Sps setdisk(cwd[0] - 'A'); 21660786Sps } 21760786Sps#endif 21860786Sps#endif 21960786Sps 22060786Sps /* 22160786Sps * Reopen the current input file. 22260786Sps */ 22360786Sps reedit_ifile(save_ifile); 22460786Sps 22560786Sps#if defined(SIGWINCH) || defined(SIGWIND) 22660786Sps /* 22760786Sps * Since we were ignoring window change signals while we executed 22860786Sps * the system command, we must assume the window changed. 22960786Sps * Warning: this leaves a signal pending (in "sigs"), 23060786Sps * so psignals() should be called soon after lsystem(). 23160786Sps */ 23260786Sps winch(0); 23360786Sps#endif 23460786Sps} 23560786Sps 23660786Sps#endif 23760786Sps 23860786Sps#if PIPEC 23960786Sps 24060786Sps/* 24160786Sps * Pipe a section of the input file into the given shell command. 24260786Sps * The section to be piped is the section "between" the current 24360786Sps * position and the position marked by the given letter. 24460786Sps * 24560786Sps * If the mark is after the current screen, the section between 24660786Sps * the top line displayed and the mark is piped. 24760786Sps * If the mark is before the current screen, the section between 24860786Sps * the mark and the bottom line displayed is piped. 24960786Sps * If the mark is on the current screen, or if the mark is ".", 25060786Sps * the whole current screen is piped. 25160786Sps */ 25260786Sps public int 25360786Spspipe_mark(c, cmd) 25460786Sps int c; 25560786Sps char *cmd; 25660786Sps{ 25760786Sps POSITION mpos, tpos, bpos; 25860786Sps 25960786Sps /* 26060786Sps * mpos = the marked position. 26160786Sps * tpos = top of screen. 26260786Sps * bpos = bottom of screen. 26360786Sps */ 26460786Sps mpos = markpos(c); 26560786Sps if (mpos == NULL_POSITION) 26660786Sps return (-1); 26760786Sps tpos = position(TOP); 26860786Sps if (tpos == NULL_POSITION) 26960786Sps tpos = ch_zero(); 27060786Sps bpos = position(BOTTOM); 27160786Sps 27260786Sps if (c == '.') 27360786Sps return (pipe_data(cmd, tpos, bpos)); 27460786Sps else if (mpos <= tpos) 27560786Sps return (pipe_data(cmd, mpos, bpos)); 27660786Sps else if (bpos == NULL_POSITION) 27760786Sps return (pipe_data(cmd, tpos, bpos)); 27860786Sps else 27960786Sps return (pipe_data(cmd, tpos, mpos)); 28060786Sps} 28160786Sps 28260786Sps/* 28360786Sps * Create a pipe to the given shell command. 28460786Sps * Feed it the file contents between the positions spos and epos. 28560786Sps */ 28660786Sps public int 28760786Spspipe_data(cmd, spos, epos) 28860786Sps char *cmd; 28960786Sps POSITION spos; 29060786Sps POSITION epos; 29160786Sps{ 29260786Sps register FILE *f; 29360786Sps register int c; 29460786Sps extern FILE *popen(); 29560786Sps 29660786Sps /* 29760786Sps * This is structured much like lsystem(). 29860786Sps * Since we're running a shell program, we must be careful 29960786Sps * to perform the necessary deinitialization before running 30060786Sps * the command, and reinitialization after it. 30160786Sps */ 30260786Sps if (ch_seek(spos) != 0) 30360786Sps { 30460786Sps error("Cannot seek to start position", NULL_PARG); 30560786Sps return (-1); 30660786Sps } 30760786Sps 30860786Sps if ((f = popen(cmd, "w")) == NULL) 30960786Sps { 31060786Sps error("Cannot create pipe", NULL_PARG); 31160786Sps return (-1); 31260786Sps } 31360786Sps clear_bot(); 31460786Sps putstr("!"); 31560786Sps putstr(cmd); 31660786Sps putstr("\n"); 31760786Sps 31860786Sps deinit(); 31960786Sps flush(); 32060786Sps raw_mode(0); 32160786Sps init_signals(0); 32260786Sps#if MSDOS_COMPILER==WIN32C 32360786Sps close_getchr(); 32460786Sps#endif 32560786Sps#ifdef SIGPIPE 32660786Sps LSIGNAL(SIGPIPE, SIG_IGN); 32760786Sps#endif 32860786Sps 32960786Sps c = EOI; 33060786Sps while (epos == NULL_POSITION || spos++ <= epos) 33160786Sps { 33260786Sps /* 33360786Sps * Read a character from the file and give it to the pipe. 33460786Sps */ 33560786Sps c = ch_forw_get(); 33660786Sps if (c == EOI) 33760786Sps break; 33860786Sps if (putc(c, f) == EOF) 33960786Sps break; 34060786Sps } 34160786Sps 34260786Sps /* 34360786Sps * Finish up the last line. 34460786Sps */ 34560786Sps while (c != '\n' && c != EOI ) 34660786Sps { 34760786Sps c = ch_forw_get(); 34860786Sps if (c == EOI) 34960786Sps break; 35060786Sps if (putc(c, f) == EOF) 35160786Sps break; 35260786Sps } 35360786Sps 35460786Sps pclose(f); 35560786Sps 35660786Sps#ifdef SIGPIPE 35760786Sps LSIGNAL(SIGPIPE, SIG_DFL); 35860786Sps#endif 35960786Sps#if MSDOS_COMPILER==WIN32C 36060786Sps open_getchr(); 36160786Sps#endif 36260786Sps init_signals(1); 36360786Sps raw_mode(1); 36460786Sps init(); 36560786Sps screen_trashed = 1; 36660786Sps#if defined(SIGWINCH) || defined(SIGWIND) 36760786Sps /* {{ Probably don't need this here. }} */ 36860786Sps winch(0); 36960786Sps#endif 37060786Sps return (0); 37160786Sps} 37260786Sps 37360786Sps#endif 374