1 /* 2 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice in the documentation and/or other materials provided with 12 * the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 28 /* 29 * Routines to execute other programs. 30 * Necessarily very OS dependent. 31 */ 32 33 #include <signal.h> 34 #include "less.h" 35 #include "position.h" 36 37 #if MSOFTC 38 #include <dos.h> 39 #endif 40 41 extern int screen_trashed; 42 extern IFILE curr_ifile; 43 44 45 #if HAVE_SYSTEM 46 47 /* 48 * Pass the specified command to a shell to be executed. 49 * Like plain "system()", but handles resetting terminal modes, etc. 50 */ 51 public void 52 lsystem(cmd) 53 char *cmd; 54 { 55 register int inp; 56 #if MSOFTC || OS2 57 register int inp2; 58 #endif 59 register char *shell; 60 register char *p; 61 IFILE save_ifile; 62 63 /* 64 * Print the command which is to be executed, 65 * unless the command starts with a "-". 66 */ 67 if (cmd[0] == '-') 68 cmd++; 69 else 70 { 71 clear_bot(); 72 putstr("!"); 73 putstr(cmd); 74 putstr("\n"); 75 } 76 77 /* 78 * Close the current input file. 79 */ 80 save_ifile = curr_ifile; 81 (void) edit_ifile(NULL_IFILE); 82 83 /* 84 * De-initialize the terminal and take out of raw mode. 85 */ 86 deinit(); 87 flush(); /* Make sure the deinit chars get out */ 88 raw_mode(0); 89 90 /* 91 * Restore signals to their defaults. 92 */ 93 init_signals(0); 94 95 /* 96 * Force standard input to be the user's terminal 97 * (the normal standard input), even if less's standard input 98 * is coming from a pipe. 99 */ 100 inp = dup(0); 101 close(0); 102 if (OPEN_TTYIN() < 0) 103 dup(inp); 104 105 /* 106 * Pass the command to the system to be executed. 107 * If we have a SHELL environment variable, use 108 * <$SHELL -c "command"> instead of just <command>. 109 * If the command is empty, just invoke a shell. 110 */ 111 #if HAVE_SHELL 112 p = NULL; 113 if ((shell = getenv("SHELL")) != NULL && *shell != '\0') 114 { 115 if (*cmd == '\0') 116 p = save(shell); 117 else 118 { 119 p = (char *) ecalloc(strlen(shell) + strlen(cmd) + 7, 120 sizeof(char)); 121 sprintf(p, "%s -c \"%s\"", shell, cmd); 122 } 123 } 124 if (p == NULL) 125 { 126 if (*cmd == '\0') 127 p = save("sh"); 128 else 129 p = save(cmd); 130 } 131 132 system(p); 133 free(p); 134 #else 135 #if OS2 136 if (*cmd == '\0') 137 cmd = "cmd.exe"; 138 #endif 139 system(cmd); 140 #endif 141 142 /* 143 * Restore standard input, reset signals, raw mode, etc. 144 */ 145 close(0); 146 dup(inp); 147 close(inp); 148 149 init_signals(1); 150 raw_mode(1); 151 init(); 152 screen_trashed = 1; 153 154 /* 155 * Reopen the current input file. 156 */ 157 if (edit_ifile(save_ifile)) 158 quit(QUIT_ERROR); 159 160 #if defined(SIGWINCH) || defined(SIGWIND) 161 /* 162 * Since we were ignoring window change signals while we executed 163 * the system command, we must assume the window changed. 164 * Warning: this leaves a signal pending (in "sigs"), 165 * so psignals() should be called soon after lsystem(). 166 */ 167 winch(0); 168 #endif 169 } 170 171 #endif 172 173 #if PIPEC 174 175 /* 176 * Pipe a section of the input file into the given shell command. 177 * The section to be piped is the section "between" the current 178 * position and the position marked by the given letter. 179 * 180 * The "current" position means the top line displayed if the mark 181 * is after the current screen, or the bottom line displayed if 182 * the mark is before the current screen. 183 * If the mark is on the current screen, the whole screen is displayed. 184 */ 185 public int 186 pipe_mark(c, cmd) 187 int c; 188 char *cmd; 189 { 190 POSITION mpos, tpos, bpos; 191 192 /* 193 * mpos = the marked position. 194 * tpos = top of screen. 195 * bpos = bottom of screen. 196 */ 197 mpos = markpos(c); 198 if (mpos == NULL_POSITION) 199 return (-1); 200 tpos = position(TOP); 201 if (tpos == NULL_POSITION) 202 tpos = ch_zero(); 203 bpos = position(BOTTOM); 204 205 if (c == '.') 206 return (pipe_data(cmd, tpos, bpos)); 207 else if (mpos <= tpos) 208 return (pipe_data(cmd, mpos, tpos)); 209 else if (bpos == NULL_POSITION) 210 return (pipe_data(cmd, tpos, bpos)); 211 else 212 return (pipe_data(cmd, tpos, mpos)); 213 } 214 215 /* 216 * Create a pipe to the given shell command. 217 * Feed it the file contents between the positions spos and epos. 218 */ 219 public int 220 pipe_data(cmd, spos, epos) 221 char *cmd; 222 POSITION spos; 223 POSITION epos; 224 { 225 register FILE *f; 226 register int c; 227 extern FILE *popen(); 228 229 /* 230 * This is structured much like lsystem(). 231 * Since we're running a shell program, we must be careful 232 * to perform the necessary deinitialization before running 233 * the command, and reinitialization after it. 234 */ 235 if (ch_seek(spos) != 0) 236 { 237 error("Cannot seek to start position", NULL_PARG); 238 return (-1); 239 } 240 241 if ((f = popen(cmd, "w")) == NULL) 242 { 243 error("Cannot create pipe", NULL_PARG); 244 return (-1); 245 } 246 clear_bot(); 247 putstr("!"); 248 putstr(cmd); 249 putstr("\n"); 250 251 deinit(); 252 flush(); 253 raw_mode(0); 254 init_signals(0); 255 #ifdef SIGPIPE 256 SIGNAL(SIGPIPE, SIG_IGN); 257 #endif 258 259 c = EOI; 260 while (epos == NULL_POSITION || spos++ <= epos) 261 { 262 /* 263 * Read a character from the file and give it to the pipe. 264 */ 265 c = ch_forw_get(); 266 if (c == EOI) 267 break; 268 if (putc(c, f) == EOF) 269 break; 270 } 271 272 /* 273 * Finish up the last line. 274 */ 275 while (c != '\n' && c != EOI ) 276 { 277 c = ch_forw_get(); 278 if (c == EOI) 279 break; 280 if (putc(c, f) == EOF) 281 break; 282 } 283 284 pclose(f); 285 286 #ifdef SIGPIPE 287 SIGNAL(SIGPIPE, SIG_DFL); 288 #endif 289 init_signals(1); 290 raw_mode(1); 291 init(); 292 screen_trashed = 1; 293 #if defined(SIGWINCH) || defined(SIGWIND) 294 /* {{ Probably don't need this here. }} */ 295 winch(0); 296 #endif 297 return (0); 298 } 299 300 #endif 301