xref: /minix3/external/bsd/less/dist/lsystem.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: lsystem.c,v 1.4 2013/09/04 19:44:21 tron Exp $	*/
2f7cf2976SLionel Sambuc 
3f7cf2976SLionel Sambuc /*
4*84d9c625SLionel Sambuc  * Copyright (C) 1984-2012  Mark Nudelman
5f7cf2976SLionel Sambuc  *
6f7cf2976SLionel Sambuc  * You may distribute under the terms of either the GNU General Public
7f7cf2976SLionel Sambuc  * License or the Less License, as specified in the README file.
8f7cf2976SLionel Sambuc  *
9*84d9c625SLionel Sambuc  * For more information, see the README file.
10f7cf2976SLionel Sambuc  */
11f7cf2976SLionel Sambuc 
12f7cf2976SLionel Sambuc 
13f7cf2976SLionel Sambuc /*
14f7cf2976SLionel Sambuc  * Routines to execute other programs.
15f7cf2976SLionel Sambuc  * Necessarily very OS dependent.
16f7cf2976SLionel Sambuc  */
17f7cf2976SLionel Sambuc 
18f7cf2976SLionel Sambuc #include "less.h"
19f7cf2976SLionel Sambuc #include <signal.h>
20f7cf2976SLionel Sambuc #include "position.h"
21f7cf2976SLionel Sambuc 
22f7cf2976SLionel Sambuc #if MSDOS_COMPILER
23f7cf2976SLionel Sambuc #include <dos.h>
24f7cf2976SLionel Sambuc #ifdef _MSC_VER
25f7cf2976SLionel Sambuc #include <direct.h>
26f7cf2976SLionel Sambuc #define setdisk(n) _chdrive((n)+1)
27f7cf2976SLionel Sambuc #else
28f7cf2976SLionel Sambuc #include <dir.h>
29f7cf2976SLionel Sambuc #endif
30f7cf2976SLionel Sambuc #endif
31f7cf2976SLionel Sambuc 
32f7cf2976SLionel Sambuc extern int screen_trashed;
33f7cf2976SLionel Sambuc extern IFILE curr_ifile;
34f7cf2976SLionel Sambuc 
35f7cf2976SLionel Sambuc 
36f7cf2976SLionel Sambuc #if HAVE_SYSTEM
37f7cf2976SLionel Sambuc 
38f7cf2976SLionel Sambuc /*
39f7cf2976SLionel Sambuc  * Pass the specified command to a shell to be executed.
40f7cf2976SLionel Sambuc  * Like plain "system()", but handles resetting terminal modes, etc.
41f7cf2976SLionel Sambuc  */
42f7cf2976SLionel Sambuc 	public void
lsystem(cmd,donemsg)43f7cf2976SLionel Sambuc lsystem(cmd, donemsg)
44f7cf2976SLionel Sambuc 	char *cmd;
45f7cf2976SLionel Sambuc 	char *donemsg;
46f7cf2976SLionel Sambuc {
47f7cf2976SLionel Sambuc 	register int inp;
48f7cf2976SLionel Sambuc #if HAVE_SHELL
49f7cf2976SLionel Sambuc 	register char *shell;
50f7cf2976SLionel Sambuc 	register char *p;
51f7cf2976SLionel Sambuc #endif
52f7cf2976SLionel Sambuc 	IFILE save_ifile;
53f7cf2976SLionel Sambuc #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
54f7cf2976SLionel Sambuc 	char cwd[FILENAME_MAX+1];
55f7cf2976SLionel Sambuc #endif
56f7cf2976SLionel Sambuc 
57f7cf2976SLionel Sambuc 	/*
58f7cf2976SLionel Sambuc 	 * Print the command which is to be executed,
59f7cf2976SLionel Sambuc 	 * unless the command starts with a "-".
60f7cf2976SLionel Sambuc 	 */
61f7cf2976SLionel Sambuc 	if (cmd[0] == '-')
62f7cf2976SLionel Sambuc 		cmd++;
63f7cf2976SLionel Sambuc 	else
64f7cf2976SLionel Sambuc 	{
65f7cf2976SLionel Sambuc 		clear_bot();
66f7cf2976SLionel Sambuc 		putstr("!");
67f7cf2976SLionel Sambuc 		putstr(cmd);
68f7cf2976SLionel Sambuc 		putstr("\n");
69f7cf2976SLionel Sambuc 	}
70f7cf2976SLionel Sambuc 
71f7cf2976SLionel Sambuc #if MSDOS_COMPILER
72f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
73f7cf2976SLionel Sambuc 	if (*cmd == '\0')
74f7cf2976SLionel Sambuc 		cmd = getenv("COMSPEC");
75f7cf2976SLionel Sambuc #else
76f7cf2976SLionel Sambuc 	/*
77f7cf2976SLionel Sambuc 	 * Working directory is global on MSDOS.
78f7cf2976SLionel Sambuc 	 * The child might change the working directory, so we
79f7cf2976SLionel Sambuc 	 * must save and restore CWD across calls to "system",
80f7cf2976SLionel Sambuc 	 * or else we won't find our file when we return and
81f7cf2976SLionel Sambuc 	 * try to "reedit_ifile" it.
82f7cf2976SLionel Sambuc 	 */
83f7cf2976SLionel Sambuc 	getcwd(cwd, FILENAME_MAX);
84f7cf2976SLionel Sambuc #endif
85f7cf2976SLionel Sambuc #endif
86f7cf2976SLionel Sambuc 
87f7cf2976SLionel Sambuc 	/*
88f7cf2976SLionel Sambuc 	 * Close the current input file.
89f7cf2976SLionel Sambuc 	 */
90f7cf2976SLionel Sambuc 	save_ifile = save_curr_ifile();
91f7cf2976SLionel Sambuc 	(void) edit_ifile(NULL_IFILE);
92f7cf2976SLionel Sambuc 
93f7cf2976SLionel Sambuc 	/*
94f7cf2976SLionel Sambuc 	 * De-initialize the terminal and take out of raw mode.
95f7cf2976SLionel Sambuc 	 */
96f7cf2976SLionel Sambuc 	deinit();
97f7cf2976SLionel Sambuc 	flush();	/* Make sure the deinit chars get out */
98f7cf2976SLionel Sambuc 	raw_mode(0);
99f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
100f7cf2976SLionel Sambuc 	close_getchr();
101f7cf2976SLionel Sambuc #endif
102f7cf2976SLionel Sambuc 
103f7cf2976SLionel Sambuc 	/*
104f7cf2976SLionel Sambuc 	 * Restore signals to their defaults.
105f7cf2976SLionel Sambuc 	 */
106f7cf2976SLionel Sambuc 	init_signals(0);
107f7cf2976SLionel Sambuc 
108f7cf2976SLionel Sambuc #if HAVE_DUP
109f7cf2976SLionel Sambuc 	/*
110f7cf2976SLionel Sambuc 	 * Force standard input to be the user's terminal
111f7cf2976SLionel Sambuc 	 * (the normal standard input), even if less's standard input
112f7cf2976SLionel Sambuc 	 * is coming from a pipe.
113f7cf2976SLionel Sambuc 	 */
114f7cf2976SLionel Sambuc 	inp = dup(0);
115f7cf2976SLionel Sambuc 	close(0);
116f7cf2976SLionel Sambuc #if OS2
117f7cf2976SLionel Sambuc 	/* The __open() system call translates "/dev/tty" to "con". */
118f7cf2976SLionel Sambuc 	if (__open("/dev/tty", OPEN_READ) < 0)
119f7cf2976SLionel Sambuc #else
120f7cf2976SLionel Sambuc 	if (open("/dev/tty", OPEN_READ) < 0)
121f7cf2976SLionel Sambuc #endif
122f7cf2976SLionel Sambuc 		dup(inp);
123f7cf2976SLionel Sambuc #endif
124f7cf2976SLionel Sambuc 
125f7cf2976SLionel Sambuc 	/*
126f7cf2976SLionel Sambuc 	 * Pass the command to the system to be executed.
127f7cf2976SLionel Sambuc 	 * If we have a SHELL environment variable, use
128f7cf2976SLionel Sambuc 	 * <$SHELL -c "command"> instead of just <command>.
129f7cf2976SLionel Sambuc 	 * If the command is empty, just invoke a shell.
130f7cf2976SLionel Sambuc 	 */
131f7cf2976SLionel Sambuc #if HAVE_SHELL
132f7cf2976SLionel Sambuc 	p = NULL;
133f7cf2976SLionel Sambuc 	if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0')
134f7cf2976SLionel Sambuc 	{
135f7cf2976SLionel Sambuc 		if (*cmd == '\0')
136f7cf2976SLionel Sambuc 			p = save(shell);
137f7cf2976SLionel Sambuc 		else
138f7cf2976SLionel Sambuc 		{
139f7cf2976SLionel Sambuc 			char *esccmd = shell_quote(cmd);
140f7cf2976SLionel Sambuc 			if (esccmd != NULL)
141f7cf2976SLionel Sambuc 			{
142f7cf2976SLionel Sambuc 				int len = strlen(shell) + strlen(esccmd) + 5;
143f7cf2976SLionel Sambuc 				p = (char *) ecalloc(len, sizeof(char));
144f7cf2976SLionel Sambuc 				SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd);
145f7cf2976SLionel Sambuc 				free(esccmd);
146f7cf2976SLionel Sambuc 			}
147f7cf2976SLionel Sambuc 		}
148f7cf2976SLionel Sambuc 	}
149f7cf2976SLionel Sambuc 	if (p == NULL)
150f7cf2976SLionel Sambuc 	{
151f7cf2976SLionel Sambuc 		if (*cmd == '\0')
152f7cf2976SLionel Sambuc 			p = save("sh");
153f7cf2976SLionel Sambuc 		else
154f7cf2976SLionel Sambuc 			p = save(cmd);
155f7cf2976SLionel Sambuc 	}
156f7cf2976SLionel Sambuc 	system(p);
157f7cf2976SLionel Sambuc 	free(p);
158f7cf2976SLionel Sambuc #else
159f7cf2976SLionel Sambuc #if MSDOS_COMPILER==DJGPPC
160f7cf2976SLionel Sambuc 	/*
161f7cf2976SLionel Sambuc 	 * Make stdin of the child be in cooked mode.
162f7cf2976SLionel Sambuc 	 */
163f7cf2976SLionel Sambuc 	setmode(0, O_TEXT);
164f7cf2976SLionel Sambuc 	/*
165f7cf2976SLionel Sambuc 	 * We don't need to catch signals of the child (it
166f7cf2976SLionel Sambuc 	 * also makes trouble with some DPMI servers).
167f7cf2976SLionel Sambuc 	 */
168f7cf2976SLionel Sambuc 	__djgpp_exception_toggle();
169f7cf2976SLionel Sambuc   	system(cmd);
170f7cf2976SLionel Sambuc 	__djgpp_exception_toggle();
171f7cf2976SLionel Sambuc #else
172f7cf2976SLionel Sambuc 	system(cmd);
173f7cf2976SLionel Sambuc #endif
174f7cf2976SLionel Sambuc #endif
175f7cf2976SLionel Sambuc 
176f7cf2976SLionel Sambuc #if HAVE_DUP
177f7cf2976SLionel Sambuc 	/*
178f7cf2976SLionel Sambuc 	 * Restore standard input, reset signals, raw mode, etc.
179f7cf2976SLionel Sambuc 	 */
180f7cf2976SLionel Sambuc 	close(0);
181f7cf2976SLionel Sambuc 	dup(inp);
182f7cf2976SLionel Sambuc 	close(inp);
183f7cf2976SLionel Sambuc #endif
184f7cf2976SLionel Sambuc 
185f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
186f7cf2976SLionel Sambuc 	open_getchr();
187f7cf2976SLionel Sambuc #endif
188f7cf2976SLionel Sambuc 	init_signals(1);
189f7cf2976SLionel Sambuc 	raw_mode(1);
190f7cf2976SLionel Sambuc 	if (donemsg != NULL)
191f7cf2976SLionel Sambuc 	{
192f7cf2976SLionel Sambuc 		putstr(donemsg);
193f7cf2976SLionel Sambuc 		putstr("  (press RETURN)");
194f7cf2976SLionel Sambuc 		get_return();
195f7cf2976SLionel Sambuc 		putchr('\n');
196f7cf2976SLionel Sambuc 		flush();
197f7cf2976SLionel Sambuc 	}
198f7cf2976SLionel Sambuc 	init();
199f7cf2976SLionel Sambuc 	screen_trashed = 1;
200f7cf2976SLionel Sambuc 
201f7cf2976SLionel Sambuc #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
202f7cf2976SLionel Sambuc 	/*
203f7cf2976SLionel Sambuc 	 * Restore the previous directory (possibly
204f7cf2976SLionel Sambuc 	 * changed by the child program we just ran).
205f7cf2976SLionel Sambuc 	 */
206f7cf2976SLionel Sambuc 	chdir(cwd);
207f7cf2976SLionel Sambuc #if MSDOS_COMPILER != DJGPPC
208f7cf2976SLionel Sambuc 	/*
209f7cf2976SLionel Sambuc 	 * Some versions of chdir() don't change to the drive
210f7cf2976SLionel Sambuc 	 * which is part of CWD.  (DJGPP does this in chdir.)
211f7cf2976SLionel Sambuc 	 */
212f7cf2976SLionel Sambuc 	if (cwd[1] == ':')
213f7cf2976SLionel Sambuc 	{
214f7cf2976SLionel Sambuc 		if (cwd[0] >= 'a' && cwd[0] <= 'z')
215f7cf2976SLionel Sambuc 			setdisk(cwd[0] - 'a');
216f7cf2976SLionel Sambuc 		else if (cwd[0] >= 'A' && cwd[0] <= 'Z')
217f7cf2976SLionel Sambuc 			setdisk(cwd[0] - 'A');
218f7cf2976SLionel Sambuc 	}
219f7cf2976SLionel Sambuc #endif
220f7cf2976SLionel Sambuc #endif
221f7cf2976SLionel Sambuc 
222f7cf2976SLionel Sambuc 	/*
223f7cf2976SLionel Sambuc 	 * Reopen the current input file.
224f7cf2976SLionel Sambuc 	 */
225f7cf2976SLionel Sambuc 	reedit_ifile(save_ifile);
226f7cf2976SLionel Sambuc 
227f7cf2976SLionel Sambuc #if defined(SIGWINCH) || defined(SIGWIND)
228f7cf2976SLionel Sambuc 	/*
229f7cf2976SLionel Sambuc 	 * Since we were ignoring window change signals while we executed
230f7cf2976SLionel Sambuc 	 * the system command, we must assume the window changed.
231f7cf2976SLionel Sambuc 	 * Warning: this leaves a signal pending (in "sigs"),
232f7cf2976SLionel Sambuc 	 * so psignals() should be called soon after lsystem().
233f7cf2976SLionel Sambuc 	 */
234f7cf2976SLionel Sambuc 	winch(0);
235f7cf2976SLionel Sambuc #endif
236f7cf2976SLionel Sambuc }
237f7cf2976SLionel Sambuc 
238f7cf2976SLionel Sambuc #endif
239f7cf2976SLionel Sambuc 
240f7cf2976SLionel Sambuc #if PIPEC
241f7cf2976SLionel Sambuc 
242f7cf2976SLionel Sambuc /*
243f7cf2976SLionel Sambuc  * Pipe a section of the input file into the given shell command.
244f7cf2976SLionel Sambuc  * The section to be piped is the section "between" the current
245f7cf2976SLionel Sambuc  * position and the position marked by the given letter.
246f7cf2976SLionel Sambuc  *
247f7cf2976SLionel Sambuc  * If the mark is after the current screen, the section between
248f7cf2976SLionel Sambuc  * the top line displayed and the mark is piped.
249f7cf2976SLionel Sambuc  * If the mark is before the current screen, the section between
250f7cf2976SLionel Sambuc  * the mark and the bottom line displayed is piped.
251f7cf2976SLionel Sambuc  * If the mark is on the current screen, or if the mark is ".",
252f7cf2976SLionel Sambuc  * the whole current screen is piped.
253f7cf2976SLionel Sambuc  */
254f7cf2976SLionel Sambuc 	public int
pipe_mark(c,cmd)255f7cf2976SLionel Sambuc pipe_mark(c, cmd)
256f7cf2976SLionel Sambuc 	int c;
257f7cf2976SLionel Sambuc 	char *cmd;
258f7cf2976SLionel Sambuc {
259f7cf2976SLionel Sambuc 	POSITION mpos, tpos, bpos;
260f7cf2976SLionel Sambuc 
261f7cf2976SLionel Sambuc 	/*
262f7cf2976SLionel Sambuc 	 * mpos = the marked position.
263f7cf2976SLionel Sambuc 	 * tpos = top of screen.
264f7cf2976SLionel Sambuc 	 * bpos = bottom of screen.
265f7cf2976SLionel Sambuc 	 */
266f7cf2976SLionel Sambuc 	mpos = markpos(c);
267f7cf2976SLionel Sambuc 	if (mpos == NULL_POSITION)
268f7cf2976SLionel Sambuc 		return (-1);
269f7cf2976SLionel Sambuc 	tpos = position(TOP);
270f7cf2976SLionel Sambuc 	if (tpos == NULL_POSITION)
271f7cf2976SLionel Sambuc 		tpos = ch_zero();
272f7cf2976SLionel Sambuc 	bpos = position(BOTTOM);
273f7cf2976SLionel Sambuc 
274f7cf2976SLionel Sambuc  	if (c == '.')
275f7cf2976SLionel Sambuc  		return (pipe_data(cmd, tpos, bpos));
276f7cf2976SLionel Sambuc  	else if (mpos <= tpos)
277f7cf2976SLionel Sambuc  		return (pipe_data(cmd, mpos, bpos));
278f7cf2976SLionel Sambuc  	else if (bpos == NULL_POSITION)
279f7cf2976SLionel Sambuc  		return (pipe_data(cmd, tpos, bpos));
280f7cf2976SLionel Sambuc  	else
281f7cf2976SLionel Sambuc  		return (pipe_data(cmd, tpos, mpos));
282f7cf2976SLionel Sambuc }
283f7cf2976SLionel Sambuc 
284f7cf2976SLionel Sambuc /*
285f7cf2976SLionel Sambuc  * Create a pipe to the given shell command.
286f7cf2976SLionel Sambuc  * Feed it the file contents between the positions spos and epos.
287f7cf2976SLionel Sambuc  */
288f7cf2976SLionel Sambuc 	public int
pipe_data(cmd,spos,epos)289f7cf2976SLionel Sambuc pipe_data(cmd, spos, epos)
290f7cf2976SLionel Sambuc 	char *cmd;
291f7cf2976SLionel Sambuc 	POSITION spos;
292f7cf2976SLionel Sambuc 	POSITION epos;
293f7cf2976SLionel Sambuc {
294f7cf2976SLionel Sambuc 	register FILE *f;
295f7cf2976SLionel Sambuc 	register int c;
296f7cf2976SLionel Sambuc 
297f7cf2976SLionel Sambuc 	/*
298f7cf2976SLionel Sambuc 	 * This is structured much like lsystem().
299f7cf2976SLionel Sambuc 	 * Since we're running a shell program, we must be careful
300f7cf2976SLionel Sambuc 	 * to perform the necessary deinitialization before running
301f7cf2976SLionel Sambuc 	 * the command, and reinitialization after it.
302f7cf2976SLionel Sambuc 	 */
303f7cf2976SLionel Sambuc 	if (ch_seek(spos) != 0)
304f7cf2976SLionel Sambuc 	{
305f7cf2976SLionel Sambuc 		error("Cannot seek to start position", NULL_PARG);
306f7cf2976SLionel Sambuc 		return (-1);
307f7cf2976SLionel Sambuc 	}
308f7cf2976SLionel Sambuc 
309f7cf2976SLionel Sambuc 	if ((f = popen(cmd, "w")) == NULL)
310f7cf2976SLionel Sambuc 	{
311f7cf2976SLionel Sambuc 		error("Cannot create pipe", NULL_PARG);
312f7cf2976SLionel Sambuc 		return (-1);
313f7cf2976SLionel Sambuc 	}
314f7cf2976SLionel Sambuc 	clear_bot();
315f7cf2976SLionel Sambuc 	putstr("!");
316f7cf2976SLionel Sambuc 	putstr(cmd);
317f7cf2976SLionel Sambuc 	putstr("\n");
318f7cf2976SLionel Sambuc 
319f7cf2976SLionel Sambuc 	deinit();
320f7cf2976SLionel Sambuc 	flush();
321f7cf2976SLionel Sambuc 	raw_mode(0);
322f7cf2976SLionel Sambuc 	init_signals(0);
323f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
324f7cf2976SLionel Sambuc 	close_getchr();
325f7cf2976SLionel Sambuc #endif
326f7cf2976SLionel Sambuc #ifdef SIGPIPE
327f7cf2976SLionel Sambuc 	LSIGNAL(SIGPIPE, SIG_IGN);
328f7cf2976SLionel Sambuc #endif
329f7cf2976SLionel Sambuc 
330f7cf2976SLionel Sambuc 	c = EOI;
331f7cf2976SLionel Sambuc 	while (epos == NULL_POSITION || spos++ <= epos)
332f7cf2976SLionel Sambuc 	{
333f7cf2976SLionel Sambuc 		/*
334f7cf2976SLionel Sambuc 		 * Read a character from the file and give it to the pipe.
335f7cf2976SLionel Sambuc 		 */
336f7cf2976SLionel Sambuc 		c = ch_forw_get();
337f7cf2976SLionel Sambuc 		if (c == EOI)
338f7cf2976SLionel Sambuc 			break;
339f7cf2976SLionel Sambuc 		if (putc(c, f) == EOF)
340f7cf2976SLionel Sambuc 			break;
341f7cf2976SLionel Sambuc 	}
342f7cf2976SLionel Sambuc 
343f7cf2976SLionel Sambuc 	/*
344f7cf2976SLionel Sambuc 	 * Finish up the last line.
345f7cf2976SLionel Sambuc 	 */
346f7cf2976SLionel Sambuc  	while (c != '\n' && c != EOI )
347f7cf2976SLionel Sambuc  	{
348f7cf2976SLionel Sambuc  		c = ch_forw_get();
349f7cf2976SLionel Sambuc  		if (c == EOI)
350f7cf2976SLionel Sambuc  			break;
351f7cf2976SLionel Sambuc  		if (putc(c, f) == EOF)
352f7cf2976SLionel Sambuc  			break;
353f7cf2976SLionel Sambuc  	}
354f7cf2976SLionel Sambuc 
355f7cf2976SLionel Sambuc 	pclose(f);
356f7cf2976SLionel Sambuc 
357f7cf2976SLionel Sambuc #ifdef SIGPIPE
358f7cf2976SLionel Sambuc 	LSIGNAL(SIGPIPE, SIG_DFL);
359f7cf2976SLionel Sambuc #endif
360f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
361f7cf2976SLionel Sambuc 	open_getchr();
362f7cf2976SLionel Sambuc #endif
363f7cf2976SLionel Sambuc 	init_signals(1);
364f7cf2976SLionel Sambuc 	raw_mode(1);
365f7cf2976SLionel Sambuc 	init();
366f7cf2976SLionel Sambuc 	screen_trashed = 1;
367f7cf2976SLionel Sambuc #if defined(SIGWINCH) || defined(SIGWIND)
368f7cf2976SLionel Sambuc 	/* {{ Probably don't need this here. }} */
369f7cf2976SLionel Sambuc 	winch(0);
370f7cf2976SLionel Sambuc #endif
371f7cf2976SLionel Sambuc 	return (0);
372f7cf2976SLionel Sambuc }
373f7cf2976SLionel Sambuc 
374f7cf2976SLionel Sambuc #endif
375