/* * Copyright (C) 1984-2002 Mark Nudelman * * You may distribute under the terms of either the GNU General Public * License or the Less License, as specified in the README file. * * For more information about less, or for information on how to * contact the author, see the README file. */ /* * Routines to execute other programs. * Necessarily very OS dependent. */ #include "less.h" #include #include "position.h" #if MSDOS_COMPILER #include #ifdef _MSC_VER #include #define setdisk(n) _chdrive((n)+1) #else #include #endif #endif extern int screen_trashed; extern IFILE curr_ifile; #if HAVE_SYSTEM /* * Pass the specified command to a shell to be executed. * Like plain "system()", but handles resetting terminal modes, etc. */ public void lsystem(cmd, donemsg) char *cmd; char *donemsg; { register int inp; #if HAVE_SHELL register char *shell; register char *p; #endif IFILE save_ifile; #if MSDOS_COMPILER char cwd[FILENAME_MAX+1]; #endif /* * Print the command which is to be executed, * unless the command starts with a "-". */ if (cmd[0] == '-') cmd++; else { clear_bot(); putstr("!"); putstr(cmd); putstr("\n"); } #if MSDOS_COMPILER /* * 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 /* * Close the current input file. */ save_ifile = save_curr_ifile(); (void) edit_ifile(NULL_IFILE); /* * De-initialize the terminal and take out of raw mode. */ deinit(); flush(); /* Make sure the deinit chars get out */ raw_mode(0); #if MSDOS_COMPILER==WIN32C close_getchr(); #endif /* * Restore signals to their defaults. */ init_signals(0); #if HAVE_DUP /* * Force standard input to be the user's terminal * (the normal standard input), even if less's standard input * is coming from a pipe. */ inp = dup(0); 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) #endif 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 . * If the command is empty, just invoke a shell. */ #if HAVE_SHELL p = NULL; if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') { if (*cmd == '\0') p = save(shell); else { char *esccmd = shell_quote(cmd); if (esccmd != NULL) { size_t len = strlen(shell) + strlen(esccmd) + 5; p = (char *) ecalloc(len, sizeof(char)); snprintf(p, len, "%s %s %s", shell, shell_coption(), esccmd); free(esccmd); } } } if (p == NULL) { if (*cmd == '\0') p = save("sh"); else p = save(cmd); } system(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. */ close(0); dup(inp); close(inp); #endif #if MSDOS_COMPILER==WIN32C open_getchr(); #endif init_signals(1); raw_mode(1); if (donemsg != NULL) { putstr(donemsg); putstr(" (press RETURN)"); get_return(); putchr('\n'); flush(); } init(); screen_trashed = 1; #if MSDOS_COMPILER /* * 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. */ reedit_ifile(save_ifile); #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(0); #endif } #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. * * If the mark is after the current screen, the section between * the top line displayed and the mark is piped. * If the mark is before the current screen, the section between * the mark and the bottom line displayed is piped. * If the mark is on the current screen, or if the mark is ".", * the whole current screen is piped. */ 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, bpos)); 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); } clear_bot(); putstr("!"); putstr(cmd); putstr("\n"); deinit(); flush(); raw_mode(0); init_signals(0); #if MSDOS_COMPILER==WIN32C close_getchr(); #endif #ifdef SIGPIPE LSIGNAL(SIGPIPE, SIG_IGN); #endif c = EOI; 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 LSIGNAL(SIGPIPE, SIG_DFL); #endif #if MSDOS_COMPILER==WIN32C open_getchr(); #endif init_signals(1); raw_mode(1); init(); screen_trashed = 1; #if defined(SIGWINCH) || defined(SIGWIND) /* {{ Probably don't need this here. }} */ winch(0); #endif return (0); } #endif #ifdef _OSK /* * Popen, and Pclose, for OS-9. * * Based on code copyright (c) 1988 by Wolfgang Ocker, Puchheim, * Ulli Dessauer, Germering and * Reimer Mellin, Muenchen * (W-Germany) * * These functions can be copied and distributed freely for any * non-commercial purposes. It can only be incorporated into * commercial software with the written permission of the authors. * * TOP-specific code stripped out and adapted for less by M.Gregorie, 1996 * * address: Wolfgang Ocker * Lochhauserstrasse 35a * D-8039 Puchheim * West Germany * * e-mail: weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP * pyramid!tmpmbx!recco!weo * pyramid!tmpmbx!nitmar!ud * pyramid!tmpmbx!ramsys!ram * * Martin Gregorie * 10 Sadlers Mead * Harlow * Essex, CM18 6HG * U.K. * * gregorie@logica.com */ #include #include extern char **environ; extern char *getenv(); extern int os9forkc(); static int pids[_NFILE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * p o p e n */ FILE *popen(name, mode) char *name; char *mode; { int fd, fd2, fdsav, pid; static char *argv[] = {NULL, NULL, NULL }; static char cmd[200]; static char cmd_path[200]; char *cp; char *shell; FILE *r; if ((shell = getenv("SHELL")) == NULL) return(NULL); cp = name; while (*cp == ' ') cp++; strlcpy(cmd_path, cp, sizeof(cmd_path)); if (cp = strchr(cmd_path, ' ')) *cp++ = '\0'; strlcpy(cmd, "ex ", sizeof(cmd)); strlcat(cmd, cmd_path, sizeof(cmd)); if (cp) { strlcat(cmd, " ", sizeof(cmd)); strlcat(cmd, cp, sizeof(cmd)); } argv[0] = shell; argv[1] = cmd; /* mode is "r" (stdout) or "w" (stdin) */ switch(mode[0]) { case 'w': fd = 0; break; case 'r': fd = 1; break; default: return(NULL); } if (fd == 1) fflush(stdout); fdsav = dup(fd); close(fd); creat("/pipe", S_IWRITE+S_IREAD); pid = os9exec(os9forkc, argv[0], argv, environ, 0, 0, 3); fd2 = dup(fd); close(fd); dup(fdsav); close(fdsav); if (pid > 0) { pids[fd2] = pid; r = fdopen(fd2, mode); } else { close(fd2); r = NULL; } return(r); } /* * p c l o s e */ int pclose(fp) FILE *fp; { unsigned int status; int pid; int fd, i; fd = fileno(fp); if (pids[fd] == 0) return(-1); fflush(fp); fclose(fp); while ((pid = wait(&status)) != -1) if (pid == pids[fd]) break; else for (i = 0; i < _NFILE; i++) if (pids[i] == pid) { pids[i] = 0; break; } if (pid == -1) status = -1; pids[fd] = 0; return(status); } #endif /* _OSK */