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