Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / lsystem.c
1 /*
2  * Routines to execute other programs.
3  * Necessarily very OS dependent.
4  */
5
6 #include <stdio.h>
7 #include <signal.h>
8
9 #include "less.h"
10 #include "position.h"
11
12 #if __MSDOS__
13 #include <process.h>
14 #include <dos.h>
15 #include <fcntl.h>
16 #include <io.h>
17 #include <errno.h>
18 #include <dir.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <time.h>
22 #include <ctype.h>
23 char get_swchar();
24 void swchar_to_dos();
25 void swchar_to_unix();
26 #endif
27
28 extern char *getenv();
29
30 extern int screen_trashed;
31 extern IFILE curr_ifile;
32
33
34 /*
35  * Pass the specified command to a shell to be executed.
36  * Like plain "system()", but handles resetting terminal modes, etc.
37  */
38         public void
39 lsystem(cmd)
40         char *cmd;
41 {
42         register int inp;
43         register char *shell;
44         register char *p;
45         register char *curr_filename;
46
47         /*
48          * Print the command which is to be executed,
49          * unless the command starts with a "-".
50          */
51         if (cmd[0] == '-')
52                 cmd++;
53         else
54         {
55                 lower_left();
56                 clear_eol();
57                 putstr("!");
58                 putstr(cmd);
59                 putstr("\n");
60         }
61
62         /*
63          * Close the current input file.
64          */
65         curr_filename = get_filename(curr_ifile);
66         (void) edit(NULL, 0);
67
68         /*
69          * De-initialize the terminal and take out of raw mode.
70          */
71         deinit();
72         flush();        /* Make sure the deinit chars get out */
73         raw_mode(0);
74
75         /*
76          * Restore signals to their defaults.
77          */
78         init_signals(0);
79
80         /*
81          * Force standard input to be the user's terminal
82          * (the normal standard input), even if less's standard input 
83          * is coming from a pipe.
84          */
85 #if __MSDOS__
86 {
87         register int inp2;
88
89         inp = dup(0);
90         inp2 = open("CON", O_TEXT|O_RDONLY);
91         dup2(0,inp2);
92 }
93 #else
94         inp = dup(0);
95         close(0);
96         if (open("/dev/tty", 0) < 0)
97                 dup(inp);
98 #endif
99
100         /*
101          * Pass the command to the system to be executed.
102          * If we have a SHELL environment variable, use
103          * <$SHELL -c "command"> instead of just <command>.
104          * If the command is empty, just invoke a shell.
105          */
106 #if __MSDOS__
107 {
108         int result;
109         char sw_char;
110
111         sw_char = get_swchar();
112         swchar_to_dos();
113         result = system(cmd);
114         if (result != 0)
115                 perror("less");
116         if (sw_char == '-')
117                 swchar_to_unix();
118 }
119 #else
120         p = NULL;
121         if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
122         {
123                 if (*cmd == '\0')
124                         p = save(shell);
125                 else
126                 {
127                         p = (char *) ecalloc(strlen(shell) + strlen(cmd) + 7, 
128                                         sizeof(char));
129                         sprintf(p, "%s -c \"%s\"", shell, cmd);
130                 }
131         }
132         if (p == NULL)
133         {
134                 if (*cmd == '\0')
135                         p = save("sh");
136                 else
137                         p = save(cmd);
138         }
139
140         system(p);
141         free(p);
142 #endif
143
144         /*
145          * Restore standard input, reset signals, raw mode, etc.
146          */
147 #if __MSDOS__
148         close(inp2);
149         dup2(0,inp);
150         close(inp);
151 #else
152         close(0);
153         dup(inp);
154         close(inp);
155 #endif
156
157         init_signals(1);
158         raw_mode(1);
159         init();
160         screen_trashed = 1;
161
162         /*
163          * Reopen the current input file.
164          */
165         (void) edit(curr_filename, 0);
166
167 #if defined(SIGWINCH) || defined(SIGWIND)
168         /*
169          * Since we were ignoring window change signals while we executed
170          * the system command, we must assume the window changed.
171          * Warning: this leaves a signal pending (in "sigs"),
172          * so psignals() should be called soon after lsystem().
173          */
174         winch();
175 #endif
176 }
177
178 #if PIPEC
179
180 /*
181  * Pipe a section of the input file into the given shell command.
182  * The section to be piped is the section "between" the current
183  * position and the position marked by the given letter.
184  *
185  * The "current" position means the top line displayed if the mark
186  * is after the current screen, or the bottom line displayed if
187  * the mark is before the current screen.
188  * If the mark is on the current screen, the whole screen is displayed.
189  */
190         public int
191 pipe_mark(c, cmd)
192         int c;
193         char *cmd;
194 {
195         POSITION mpos, tpos, bpos;
196
197         /*
198          * mpos = the marked position.
199          * tpos = top of screen.
200          * bpos = bottom of screen.
201          */
202         mpos = markpos(c);
203         if (mpos == NULL_POSITION)
204                 return (-1);
205         tpos = position(TOP);
206         if (tpos == NULL_POSITION)
207                 tpos = ch_zero();
208         bpos = position(BOTTOM);
209
210         if (c == '.') 
211                 return (pipe_data(cmd, tpos, bpos));
212         else if (mpos <= tpos)
213                 return (pipe_data(cmd, mpos, tpos));
214         else if (bpos == NULL_POSITION)
215                 return (pipe_data(cmd, tpos, bpos));
216         else
217                 return (pipe_data(cmd, tpos, mpos));
218 }
219
220 /*
221  * Create a pipe to the given shell command.
222  * Feed it the file contents between the positions spos and epos.
223  */
224         public int
225 pipe_data(cmd, spos, epos)
226         char *cmd;
227         POSITION spos;
228         POSITION epos;
229 {
230         register FILE *f;
231         register int c;
232         extern FILE *popen();
233
234         /*
235          * This is structured much like lsystem().
236          * Since we're running a shell program, we must be careful
237          * to perform the necessary deinitialization before running
238          * the command, and reinitialization after it.
239          */
240         if (ch_seek(spos) != 0)
241         {
242                 error("Cannot seek to start position", NULL_PARG);
243                 return (-1);
244         }
245
246         if ((f = popen(cmd, "w")) == NULL)
247         {
248                 error("Cannot create pipe", NULL_PARG);
249                 return (-1);
250         }
251         lower_left();
252         clear_eol();
253         putstr("!");
254         putstr(cmd);
255         putstr("\n");
256
257         deinit();
258         flush();
259         raw_mode(0);
260         init_signals(0);
261 #ifdef SIGPIPE
262         SIGNAL(SIGPIPE, SIG_IGN);
263 #endif
264
265         while (epos == NULL_POSITION || spos++ <= epos)
266         {
267                 /*
268                  * Read a character from the file and give it to the pipe.
269                  */
270                 c = ch_forw_get();
271                 if (c == EOI)
272                         break;
273                 if (putc(c, f) == EOF)
274                         break;
275         }
276
277         /*
278          * Finish up the last line.
279          */
280         while (c != '\n' && c != EOI ) 
281         {
282                 c = ch_forw_get();
283                 if (c == EOI)
284                         break;
285                 if (putc(c, f) == EOF)
286                         break;
287         }
288
289         pclose(f);
290
291 #ifdef SIGPIPE
292         SIGNAL(SIGPIPE, SIG_DFL);
293 #endif
294         init_signals(1);
295         raw_mode(1);
296         init();
297         screen_trashed = 1;
298 #if defined(SIGWINCH) || defined(SIGWIND)
299         /* {{ Probably don't need this here. }} */
300         winch();
301 #endif
302         return (0);
303 }
304
305 #endif