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