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