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