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