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