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