Annotation of src/usr.bin/less/lsystem.c, Revision 1.8
1.1 etheisen 1: /*
1.8 ! shadchin 2: * Copyright (C) 1984-2011 Mark Nudelman
1.1 etheisen 3: *
1.5 millert 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.
1.1 etheisen 6: *
1.5 millert 7: * For more information about less, or for information on how to
8: * contact the author, see the README file.
1.1 etheisen 9: */
10:
11:
12: /*
13: * Routines to execute other programs.
14: * Necessarily very OS dependent.
15: */
16:
1.5 millert 17: #include "less.h"
1.1 etheisen 18: #include <signal.h>
19: #include "position.h"
20:
1.5 millert 21: #if MSDOS_COMPILER
1.1 etheisen 22: #include <dos.h>
1.5 millert 23: #ifdef _MSC_VER
24: #include <direct.h>
25: #define setdisk(n) _chdrive((n)+1)
26: #else
27: #include <dir.h>
28: #endif
1.1 etheisen 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
1.5 millert 42: lsystem(cmd, donemsg)
1.1 etheisen 43: char *cmd;
1.5 millert 44: char *donemsg;
1.1 etheisen 45: {
1.5 millert 46: register int inp;
47: #if HAVE_SHELL
48: register char *shell;
49: register char *p;
1.1 etheisen 50: #endif
51: IFILE save_ifile;
1.8 ! shadchin 52: #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
1.5 millert 53: char cwd[FILENAME_MAX+1];
54: #endif
1.1 etheisen 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:
1.5 millert 70: #if MSDOS_COMPILER
1.8 ! shadchin 71: #if MSDOS_COMPILER==WIN32C
! 72: if (*cmd == '\0')
! 73: cmd = getenv("COMSPEC");
! 74: #else
1.5 millert 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
1.8 ! shadchin 84: #endif
1.5 millert 85:
1.1 etheisen 86: /*
87: * Close the current input file.
88: */
1.5 millert 89: save_ifile = save_curr_ifile();
1.1 etheisen 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);
1.5 millert 98: #if MSDOS_COMPILER==WIN32C
99: close_getchr();
100: #endif
1.1 etheisen 101:
102: /*
103: * Restore signals to their defaults.
104: */
105: init_signals(0);
106:
1.5 millert 107: #if HAVE_DUP
1.1 etheisen 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);
1.5 millert 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
1.1 etheisen 121: dup(inp);
1.5 millert 122: #endif
1.1 etheisen 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;
1.5 millert 132: if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0')
1.1 etheisen 133: {
134: if (*cmd == '\0')
135: p = save(shell);
136: else
137: {
1.5 millert 138: char *esccmd = shell_quote(cmd);
139: if (esccmd != NULL)
140: {
141: size_t len = strlen(shell) + strlen(esccmd) + 5;
142: p = (char *) ecalloc(len, sizeof(char));
1.8 ! shadchin 143: SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd);
1.5 millert 144: free(esccmd);
145: }
1.1 etheisen 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
1.5 millert 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);
1.1 etheisen 172: #endif
173: #endif
174:
1.5 millert 175: #if HAVE_DUP
1.1 etheisen 176: /*
177: * Restore standard input, reset signals, raw mode, etc.
178: */
179: close(0);
180: dup(inp);
181: close(inp);
1.5 millert 182: #endif
1.1 etheisen 183:
1.5 millert 184: #if MSDOS_COMPILER==WIN32C
185: open_getchr();
186: #endif
1.1 etheisen 187: init_signals(1);
188: raw_mode(1);
1.5 millert 189: if (donemsg != NULL)
190: {
191: putstr(donemsg);
192: putstr(" (press RETURN)");
193: get_return();
194: putchr('\n');
195: flush();
196: }
1.1 etheisen 197: init();
198: screen_trashed = 1;
199:
1.8 ! shadchin 200: #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C
1.5 millert 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:
1.1 etheisen 221: /*
222: * Reopen the current input file.
223: */
1.5 millert 224: reedit_ifile(save_ifile);
1.1 etheisen 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: *
1.5 millert 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.
1.1 etheisen 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)
1.5 millert 276: return (pipe_data(cmd, mpos, bpos));
1.1 etheisen 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: {
1.5 millert 293: register FILE *f;
294: register int c;
1.1 etheisen 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);
1.5 millert 323: #if MSDOS_COMPILER==WIN32C
324: close_getchr();
325: #endif
1.1 etheisen 326: #ifdef SIGPIPE
1.5 millert 327: LSIGNAL(SIGPIPE, SIG_IGN);
1.1 etheisen 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
1.5 millert 358: LSIGNAL(SIGPIPE, SIG_DFL);
359: #endif
360: #if MSDOS_COMPILER==WIN32C
361: open_getchr();
1.1 etheisen 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