GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../lsystem.c Lines: 0 89 0.0 %
Date: 2017-11-07 Branches: 0 48 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 1984-2012  Mark Nudelman
3
 * Modified for use with illumos by Garrett D'Amore.
4
 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5
 *
6
 * You may distribute under the terms of either the GNU General Public
7
 * License or the Less License, as specified in the README file.
8
 *
9
 * For more information, see the README file.
10
 */
11
12
/*
13
 * Routines to execute other programs.
14
 * Necessarily very OS dependent.
15
 */
16
17
#include <signal.h>
18
19
#include "less.h"
20
#include "position.h"
21
22
extern int screen_trashed;
23
extern IFILE curr_ifile;
24
25
static int pipe_data(char *cmd, off_t spos, off_t epos);
26
27
/*
28
 * Pass the specified command to a shell to be executed.
29
 * Like plain "system()", but handles resetting terminal modes, etc.
30
 */
31
void
32
lsystem(const char *cmd, const char *donemsg)
33
{
34
	int inp;
35
	char *shell;
36
	char *p;
37
	IFILE save_ifile;
38
39
	/*
40
	 * Print the command which is to be executed,
41
	 * unless the command starts with a "-".
42
	 */
43
	if (cmd[0] == '-')
44
		cmd++;
45
	else {
46
		clear_bot();
47
		putstr("!");
48
		putstr(cmd);
49
		putstr("\n");
50
	}
51
52
	/*
53
	 * Close the current input file.
54
	 */
55
	save_ifile = save_curr_ifile();
56
	(void) edit_ifile(NULL);
57
58
	/*
59
	 * De-initialize the terminal and take out of raw mode.
60
	 */
61
	deinit();
62
	flush(0);	/* Make sure the deinit chars get out */
63
	raw_mode(0);
64
65
	/*
66
	 * Restore signals to their defaults.
67
	 */
68
	init_signals(0);
69
70
	/*
71
	 * Force standard input to be the user's terminal
72
	 * (the normal standard input), even if less's standard input
73
	 * is coming from a pipe.
74
	 */
75
	inp = dup(0);
76
	(void) close(0);
77
	if (open("/dev/tty", O_RDONLY) < 0)
78
		(void) dup(inp);
79
80
	/*
81
	 * Pass the command to the system to be executed.
82
	 * If we have a SHELL environment variable, use
83
	 * <$SHELL -c "command"> instead of just <command>.
84
	 * If the command is empty, just invoke a shell.
85
	 */
86
	p = NULL;
87
	if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') {
88
		if (*cmd == '\0') {
89
			p = estrdup(shell);
90
		} else {
91
			char *esccmd = shell_quote(cmd);
92
			if (esccmd != NULL) {
93
				p = easprintf("%s -c %s", shell, esccmd);
94
				free(esccmd);
95
			}
96
		}
97
	}
98
	if (p == NULL) {
99
		if (*cmd == '\0')
100
			p = estrdup("sh");
101
		else
102
			p = estrdup(cmd);
103
	}
104
	(void) system(p);
105
	free(p);
106
107
	/*
108
	 * Restore standard input, reset signals, raw mode, etc.
109
	 */
110
	(void) close(0);
111
	(void) dup(inp);
112
	(void) close(inp);
113
114
	init_signals(1);
115
	raw_mode(1);
116
	if (donemsg != NULL) {
117
		putstr(donemsg);
118
		putstr("  (press RETURN)");
119
		get_return();
120
		(void) putchr('\n');
121
		flush(0);
122
	}
123
	init();
124
	screen_trashed = 1;
125
126
	/*
127
	 * Reopen the current input file.
128
	 */
129
	reedit_ifile(save_ifile);
130
131
	/*
132
	 * Since we were ignoring window change signals while we executed
133
	 * the system command, we must assume the window changed.
134
	 * Warning: this leaves a signal pending (in "sigs"),
135
	 * so psignals() should be called soon after lsystem().
136
	 */
137
	sigwinch(0);
138
}
139
140
/*
141
 * Pipe a section of the input file into the given shell command.
142
 * The section to be piped is the section "between" the current
143
 * position and the position marked by the given letter.
144
 *
145
 * If the mark is after the current screen, the section between
146
 * the top line displayed and the mark is piped.
147
 * If the mark is before the current screen, the section between
148
 * the mark and the bottom line displayed is piped.
149
 * If the mark is on the current screen, or if the mark is ".",
150
 * the whole current screen is piped.
151
 */
152
int
153
pipe_mark(int c, char *cmd)
154
{
155
	off_t mpos, tpos, bpos;
156
157
	/*
158
	 * mpos = the marked position.
159
	 * tpos = top of screen.
160
	 * bpos = bottom of screen.
161
	 */
162
	mpos = markpos(c);
163
	if (mpos == -1)
164
		return (-1);
165
	tpos = position(TOP);
166
	if (tpos == -1)
167
		tpos = ch_zero();
168
	bpos = position(BOTTOM);
169
170
	if (c == '.')
171
		return (pipe_data(cmd, tpos, bpos));
172
	else if (mpos <= tpos)
173
		return (pipe_data(cmd, mpos, bpos));
174
	else if (bpos == -1)
175
		return (pipe_data(cmd, tpos, bpos));
176
	else
177
		return (pipe_data(cmd, tpos, mpos));
178
}
179
180
/*
181
 * Create a pipe to the given shell command.
182
 * Feed it the file contents between the positions spos and epos.
183
 */
184
static int
185
pipe_data(char *cmd, off_t spos, off_t epos)
186
{
187
	FILE *f;
188
	int c;
189
190
	/*
191
	 * This is structured much like lsystem().
192
	 * Since we're running a shell program, we must be careful
193
	 * to perform the necessary deinitialization before running
194
	 * the command, and reinitialization after it.
195
	 */
196
	if (ch_seek(spos) != 0) {
197
		error("Cannot seek to start position", NULL);
198
		return (-1);
199
	}
200
201
	if ((f = popen(cmd, "w")) == NULL) {
202
		error("Cannot create pipe", NULL);
203
		return (-1);
204
	}
205
	clear_bot();
206
	putstr("!");
207
	putstr(cmd);
208
	putstr("\n");
209
210
	deinit();
211
	flush(0);
212
	raw_mode(0);
213
	init_signals(0);
214
	lsignal(SIGPIPE, SIG_IGN);
215
216
	c = EOI;
217
	while (epos == -1 || spos++ <= epos) {
218
		/*
219
		 * Read a character from the file and give it to the pipe.
220
		 */
221
		c = ch_forw_get();
222
		if (c == EOI)
223
			break;
224
		if (putc(c, f) == EOF)
225
			break;
226
	}
227
228
	/*
229
	 * Finish up the last line.
230
	 */
231
	while (c != '\n' && c != EOI) {
232
		c = ch_forw_get();
233
		if (c == EOI)
234
			break;
235
		if (putc(c, f) == EOF)
236
			break;
237
	}
238
239
	(void) pclose(f);
240
241
	lsignal(SIGPIPE, SIG_DFL);
242
	init_signals(1);
243
	raw_mode(1);
244
	init();
245
	screen_trashed = 1;
246
	/* {{ Probably don't need this here. }} */
247
	sigwinch(0);
248
	return (0);
249
}