lsystem.c revision 128345
160786Sps/* 2128345Stjr * Copyright (C) 1984-2002 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Routines to execute other programs. 1460786Sps * Necessarily very OS dependent. 1560786Sps */ 1660786Sps 1789019Sps#include "less.h" 1860786Sps#include <signal.h> 1960786Sps#include "position.h" 2060786Sps 2160786Sps#if MSDOS_COMPILER 2260786Sps#include <dos.h> 2360786Sps#ifdef _MSC_VER 2460786Sps#include <direct.h> 2560786Sps#define setdisk(n) _chdrive((n)+1) 2660786Sps#else 2760786Sps#include <dir.h> 2860786Sps#endif 2960786Sps#endif 3060786Sps 3160786Spsextern int screen_trashed; 3260786Spsextern IFILE curr_ifile; 3360786Sps 3460786Sps 3560786Sps#if HAVE_SYSTEM 3660786Sps 3760786Sps/* 3860786Sps * Pass the specified command to a shell to be executed. 3960786Sps * Like plain "system()", but handles resetting terminal modes, etc. 4060786Sps */ 4160786Sps public void 4260786Spslsystem(cmd, donemsg) 4360786Sps char *cmd; 4460786Sps char *donemsg; 4560786Sps{ 4660786Sps register int inp; 4760786Sps#if HAVE_SHELL 4860786Sps register char *shell; 4960786Sps register char *p; 5060786Sps#endif 5160786Sps IFILE save_ifile; 5260786Sps#if MSDOS_COMPILER 5360786Sps char cwd[FILENAME_MAX+1]; 5460786Sps#endif 5560786Sps 5660786Sps /* 5760786Sps * Print the command which is to be executed, 5860786Sps * unless the command starts with a "-". 5960786Sps */ 6060786Sps if (cmd[0] == '-') 6160786Sps cmd++; 6260786Sps else 6360786Sps { 6460786Sps clear_bot(); 6560786Sps putstr("!"); 6660786Sps putstr(cmd); 6760786Sps putstr("\n"); 6860786Sps } 6960786Sps 7060786Sps#if MSDOS_COMPILER 7160786Sps /* 7260786Sps * Working directory is global on MSDOS. 7360786Sps * The child might change the working directory, so we 7460786Sps * must save and restore CWD across calls to "system", 7560786Sps * or else we won't find our file when we return and 7660786Sps * try to "reedit_ifile" it. 7760786Sps */ 7860786Sps getcwd(cwd, FILENAME_MAX); 7960786Sps#endif 8060786Sps 8160786Sps /* 8260786Sps * Close the current input file. 8360786Sps */ 8460786Sps save_ifile = save_curr_ifile(); 8560786Sps (void) edit_ifile(NULL_IFILE); 8660786Sps 8760786Sps /* 8860786Sps * De-initialize the terminal and take out of raw mode. 8960786Sps */ 9060786Sps deinit(); 9160786Sps flush(); /* Make sure the deinit chars get out */ 9260786Sps raw_mode(0); 9360786Sps#if MSDOS_COMPILER==WIN32C 9460786Sps close_getchr(); 9560786Sps#endif 9660786Sps 9760786Sps /* 9860786Sps * Restore signals to their defaults. 9960786Sps */ 10060786Sps init_signals(0); 10160786Sps 10260786Sps#if HAVE_DUP 10360786Sps /* 10460786Sps * Force standard input to be the user's terminal 10560786Sps * (the normal standard input), even if less's standard input 10660786Sps * is coming from a pipe. 10760786Sps */ 10860786Sps inp = dup(0); 10960786Sps close(0); 11089019Sps#if OS2 11189019Sps /* The __open() system call translates "/dev/tty" to "con". */ 11289019Sps if (__open("/dev/tty", OPEN_READ) < 0) 11389019Sps#else 11460786Sps if (open("/dev/tty", OPEN_READ) < 0) 11589019Sps#endif 11660786Sps dup(inp); 11760786Sps#endif 11860786Sps 11960786Sps /* 12060786Sps * Pass the command to the system to be executed. 12160786Sps * If we have a SHELL environment variable, use 12260786Sps * <$SHELL -c "command"> instead of just <command>. 12360786Sps * If the command is empty, just invoke a shell. 12460786Sps */ 12560786Sps#if HAVE_SHELL 12660786Sps p = NULL; 12760786Sps if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') 12860786Sps { 12960786Sps if (*cmd == '\0') 13060786Sps p = save(shell); 13160786Sps else 13260786Sps { 133128345Stjr char *esccmd = shell_quote(cmd); 134128345Stjr if (esccmd != NULL) 13560786Sps { 13660786Sps p = (char *) ecalloc(strlen(shell) + 13760786Sps strlen(esccmd) + 5, sizeof(char)); 138128345Stjr sprintf(p, "%s %s %s", shell, shell_coption(), esccmd); 13960786Sps free(esccmd); 14060786Sps } 14160786Sps } 14260786Sps } 14360786Sps if (p == NULL) 14460786Sps { 14560786Sps if (*cmd == '\0') 14660786Sps p = save("sh"); 14760786Sps else 14860786Sps p = save(cmd); 14960786Sps } 15060786Sps system(p); 15160786Sps free(p); 15260786Sps#else 15360786Sps#if MSDOS_COMPILER==DJGPPC 15460786Sps /* 15560786Sps * Make stdin of the child be in cooked mode. 15660786Sps */ 15760786Sps setmode(0, O_TEXT); 15860786Sps /* 15960786Sps * We don't need to catch signals of the child (it 16060786Sps * also makes trouble with some DPMI servers). 16160786Sps */ 16260786Sps __djgpp_exception_toggle(); 16360786Sps system(cmd); 16460786Sps __djgpp_exception_toggle(); 16560786Sps#else 16660786Sps system(cmd); 16760786Sps#endif 16860786Sps#endif 16960786Sps 17060786Sps#if HAVE_DUP 17160786Sps /* 17260786Sps * Restore standard input, reset signals, raw mode, etc. 17360786Sps */ 17460786Sps close(0); 17560786Sps dup(inp); 17660786Sps close(inp); 17760786Sps#endif 17860786Sps 17960786Sps#if MSDOS_COMPILER==WIN32C 18060786Sps open_getchr(); 18160786Sps#endif 18260786Sps init_signals(1); 18360786Sps raw_mode(1); 18460786Sps if (donemsg != NULL) 18560786Sps { 18660786Sps putstr(donemsg); 18760786Sps putstr(" (press RETURN)"); 18860786Sps get_return(); 18960786Sps putchr('\n'); 19060786Sps flush(); 19160786Sps } 19260786Sps init(); 19360786Sps screen_trashed = 1; 19460786Sps 19560786Sps#if MSDOS_COMPILER 19660786Sps /* 19760786Sps * Restore the previous directory (possibly 19860786Sps * changed by the child program we just ran). 19960786Sps */ 20060786Sps chdir(cwd); 20160786Sps#if MSDOS_COMPILER != DJGPPC 20260786Sps /* 20360786Sps * Some versions of chdir() don't change to the drive 20460786Sps * which is part of CWD. (DJGPP does this in chdir.) 20560786Sps */ 20660786Sps if (cwd[1] == ':') 20760786Sps { 20860786Sps if (cwd[0] >= 'a' && cwd[0] <= 'z') 20960786Sps setdisk(cwd[0] - 'a'); 21060786Sps else if (cwd[0] >= 'A' && cwd[0] <= 'Z') 21160786Sps setdisk(cwd[0] - 'A'); 21260786Sps } 21360786Sps#endif 21460786Sps#endif 21560786Sps 21660786Sps /* 21760786Sps * Reopen the current input file. 21860786Sps */ 21960786Sps reedit_ifile(save_ifile); 22060786Sps 22160786Sps#if defined(SIGWINCH) || defined(SIGWIND) 22260786Sps /* 22360786Sps * Since we were ignoring window change signals while we executed 22460786Sps * the system command, we must assume the window changed. 22560786Sps * Warning: this leaves a signal pending (in "sigs"), 22660786Sps * so psignals() should be called soon after lsystem(). 22760786Sps */ 22860786Sps winch(0); 22960786Sps#endif 23060786Sps} 23160786Sps 23260786Sps#endif 23360786Sps 23460786Sps#if PIPEC 23560786Sps 23660786Sps/* 23760786Sps * Pipe a section of the input file into the given shell command. 23860786Sps * The section to be piped is the section "between" the current 23960786Sps * position and the position marked by the given letter. 24060786Sps * 24160786Sps * If the mark is after the current screen, the section between 24260786Sps * the top line displayed and the mark is piped. 24360786Sps * If the mark is before the current screen, the section between 24460786Sps * the mark and the bottom line displayed is piped. 24560786Sps * If the mark is on the current screen, or if the mark is ".", 24660786Sps * the whole current screen is piped. 24760786Sps */ 24860786Sps public int 24960786Spspipe_mark(c, cmd) 25060786Sps int c; 25160786Sps char *cmd; 25260786Sps{ 25360786Sps POSITION mpos, tpos, bpos; 25460786Sps 25560786Sps /* 25660786Sps * mpos = the marked position. 25760786Sps * tpos = top of screen. 25860786Sps * bpos = bottom of screen. 25960786Sps */ 26060786Sps mpos = markpos(c); 26160786Sps if (mpos == NULL_POSITION) 26260786Sps return (-1); 26360786Sps tpos = position(TOP); 26460786Sps if (tpos == NULL_POSITION) 26560786Sps tpos = ch_zero(); 26660786Sps bpos = position(BOTTOM); 26760786Sps 26860786Sps if (c == '.') 26960786Sps return (pipe_data(cmd, tpos, bpos)); 27060786Sps else if (mpos <= tpos) 27160786Sps return (pipe_data(cmd, mpos, bpos)); 27260786Sps else if (bpos == NULL_POSITION) 27360786Sps return (pipe_data(cmd, tpos, bpos)); 27460786Sps else 27560786Sps return (pipe_data(cmd, tpos, mpos)); 27660786Sps} 27760786Sps 27860786Sps/* 27960786Sps * Create a pipe to the given shell command. 28060786Sps * Feed it the file contents between the positions spos and epos. 28160786Sps */ 28260786Sps public int 28360786Spspipe_data(cmd, spos, epos) 28460786Sps char *cmd; 28560786Sps POSITION spos; 28660786Sps POSITION epos; 28760786Sps{ 28860786Sps register FILE *f; 28960786Sps register int c; 29060786Sps extern FILE *popen(); 29160786Sps 29260786Sps /* 29360786Sps * This is structured much like lsystem(). 29460786Sps * Since we're running a shell program, we must be careful 29560786Sps * to perform the necessary deinitialization before running 29660786Sps * the command, and reinitialization after it. 29760786Sps */ 29860786Sps if (ch_seek(spos) != 0) 29960786Sps { 30060786Sps error("Cannot seek to start position", NULL_PARG); 30160786Sps return (-1); 30260786Sps } 30360786Sps 30460786Sps if ((f = popen(cmd, "w")) == NULL) 30560786Sps { 30660786Sps error("Cannot create pipe", NULL_PARG); 30760786Sps return (-1); 30860786Sps } 30960786Sps clear_bot(); 31060786Sps putstr("!"); 31160786Sps putstr(cmd); 31260786Sps putstr("\n"); 31360786Sps 31460786Sps deinit(); 31560786Sps flush(); 31660786Sps raw_mode(0); 31760786Sps init_signals(0); 31860786Sps#if MSDOS_COMPILER==WIN32C 31960786Sps close_getchr(); 32060786Sps#endif 32160786Sps#ifdef SIGPIPE 32260786Sps LSIGNAL(SIGPIPE, SIG_IGN); 32360786Sps#endif 32460786Sps 32560786Sps c = EOI; 32660786Sps while (epos == NULL_POSITION || spos++ <= epos) 32760786Sps { 32860786Sps /* 32960786Sps * Read a character from the file and give it to the pipe. 33060786Sps */ 33160786Sps c = ch_forw_get(); 33260786Sps if (c == EOI) 33360786Sps break; 33460786Sps if (putc(c, f) == EOF) 33560786Sps break; 33660786Sps } 33760786Sps 33860786Sps /* 33960786Sps * Finish up the last line. 34060786Sps */ 34160786Sps while (c != '\n' && c != EOI ) 34260786Sps { 34360786Sps c = ch_forw_get(); 34460786Sps if (c == EOI) 34560786Sps break; 34660786Sps if (putc(c, f) == EOF) 34760786Sps break; 34860786Sps } 34960786Sps 35060786Sps pclose(f); 35160786Sps 35260786Sps#ifdef SIGPIPE 35360786Sps LSIGNAL(SIGPIPE, SIG_DFL); 35460786Sps#endif 35560786Sps#if MSDOS_COMPILER==WIN32C 35660786Sps open_getchr(); 35760786Sps#endif 35860786Sps init_signals(1); 35960786Sps raw_mode(1); 36060786Sps init(); 36160786Sps screen_trashed = 1; 36260786Sps#if defined(SIGWINCH) || defined(SIGWIND) 36360786Sps /* {{ Probably don't need this here. }} */ 36460786Sps winch(0); 36560786Sps#endif 36660786Sps return (0); 36760786Sps} 36860786Sps 36960786Sps#endif 37060786Sps 37160786Sps#ifdef _OSK 37260786Sps/* 37360786Sps * Popen, and Pclose, for OS-9. 37460786Sps * 37560786Sps * Based on code copyright (c) 1988 by Wolfgang Ocker, Puchheim, 37660786Sps * Ulli Dessauer, Germering and 37760786Sps * Reimer Mellin, Muenchen 37860786Sps * (W-Germany) 37960786Sps * 38060786Sps * These functions can be copied and distributed freely for any 38160786Sps * non-commercial purposes. It can only be incorporated into 38260786Sps * commercial software with the written permission of the authors. 38360786Sps * 38460786Sps * TOP-specific code stripped out and adapted for less by M.Gregorie, 1996 38560786Sps * 38660786Sps * address: Wolfgang Ocker 38760786Sps * Lochhauserstrasse 35a 38860786Sps * D-8039 Puchheim 38960786Sps * West Germany 39060786Sps * 39160786Sps * e-mail: weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP 39260786Sps * pyramid!tmpmbx!recco!weo 39360786Sps * pyramid!tmpmbx!nitmar!ud 39460786Sps * pyramid!tmpmbx!ramsys!ram 39560786Sps * 39660786Sps * Martin Gregorie 39760786Sps * 10 Sadlers Mead 39860786Sps * Harlow 39960786Sps * Essex, CM18 6HG 40060786Sps * U.K. 40160786Sps * 40260786Sps * gregorie@logica.com 40360786Sps */ 40460786Sps#include <strings.h> 40560786Sps#include <errno.h> 40660786Spsextern char **environ; 40760786Spsextern char *getenv(); 40860786Spsextern int os9forkc(); 40960786Spsstatic int pids[_NFILE] = { 0, 0, 0, 0, 0, 0, 0, 0, 41060786Sps 0, 0, 0, 0, 0, 0, 0, 0, 41160786Sps 0, 0, 0, 0, 0, 0, 0, 0, 41260786Sps 0, 0, 0, 0, 0, 0, 0, 0 }; 41360786Sps/* 41460786Sps * p o p e n 41560786Sps */ 41660786SpsFILE *popen(name, mode) 41760786Sps char *name; 41860786Sps char *mode; 41960786Sps{ 42060786Sps int fd, fd2, fdsav, pid; 42160786Sps static char *argv[] = {NULL, NULL, NULL }; 42260786Sps static char cmd[200]; 42360786Sps static char cmd_path[200]; 42460786Sps char *cp; 42560786Sps char *shell; 42660786Sps FILE *r; 42760786Sps if ((shell = getenv("SHELL")) == NULL) 42860786Sps return(NULL); 42960786Sps cp = name; 43060786Sps while (*cp == ' ') 43160786Sps cp++; 43260786Sps strcpy(cmd_path, cp); 43360786Sps if (cp = index(cmd_path, ' ')) 43460786Sps *cp++ = '\0'; 43560786Sps strcpy(cmd, "ex "); 43660786Sps strcat(cmd, cmd_path); 43760786Sps if (cp) 43860786Sps { 43960786Sps strcat(cmd, " "); 44060786Sps strcat(cmd, cp); 44160786Sps } 44260786Sps argv[0] = shell; 44360786Sps argv[1] = cmd; 44460786Sps /* 44560786Sps mode is "r" (stdout) or "w" (stdin) 44660786Sps */ 44760786Sps switch(mode[0]) 44860786Sps { 44960786Sps case 'w': fd = 0; 45060786Sps break; 45160786Sps case 'r': fd = 1; 45260786Sps break; 45360786Sps default: return(NULL); 45460786Sps } 45560786Sps if (fd == 1) 45660786Sps fflush(stdout); 45760786Sps fdsav = dup(fd); 45860786Sps close(fd); 45960786Sps 46060786Sps creat("/pipe", S_IWRITE+S_IREAD); 46160786Sps pid = os9exec(os9forkc, argv[0], argv, environ, 0, 0, 3); 46260786Sps fd2 = dup(fd); 46360786Sps close(fd); 46460786Sps dup(fdsav); 46560786Sps close(fdsav); 46660786Sps if (pid > 0) 46760786Sps { 46860786Sps pids[fd2] = pid; 46960786Sps r = fdopen(fd2, mode); 47060786Sps } 47160786Sps else 47260786Sps { 47360786Sps close(fd2); 47460786Sps r = NULL; 47560786Sps } 47660786Sps return(r); 47760786Sps} 47860786Sps 47960786Sps/* 48060786Sps * p c l o s e 48160786Sps */ 48260786Spsint pclose(fp) 48360786Sps FILE *fp; 48460786Sps{ 48560786Sps unsigned int status; 48660786Sps int pid; 48760786Sps int fd, 48860786Sps i; 48960786Sps fd = fileno(fp); 49060786Sps if (pids[fd] == 0) 49160786Sps return(-1); 49260786Sps fflush(fp); 49360786Sps fclose(fp); 49460786Sps while ((pid = wait(&status)) != -1) 49560786Sps if (pid == pids[fd]) 49660786Sps break; 49760786Sps else 49860786Sps for (i = 0; i < _NFILE; i++) 49960786Sps if (pids[i] == pid) 50060786Sps { 50160786Sps pids[i] = 0; 50260786Sps break; 50360786Sps } 50460786Sps if (pid == -1) 50560786Sps status = -1; 50660786Sps pids[fd] = 0; 50760786Sps return(status); 50860786Sps} 50960786Sps#endif /* _OSK */ 510