1 /* 2 * Copyright (C) 1984-2000 Mark Nudelman 3 * 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. 6 * 7 * For more information about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12 /* 13 * Routines to execute other programs. 14 * Necessarily very OS dependent. 15 */ 16 17 #include <signal.h> 18 #include "less.h" 19 #include "position.h" 20 21 #if MSDOS_COMPILER 22 #include <dos.h> 23 #ifdef _MSC_VER 24 #include <direct.h> 25 #define setdisk(n) _chdrive((n)+1) 26 #else 27 #include <dir.h> 28 #endif 29 #endif 30 31 extern int screen_trashed; 32 extern IFILE curr_ifile; 33 34 35 #if HAVE_SYSTEM 36 37 /* 38 * Pass the specified command to a shell to be executed. 39 * Like plain "system()", but handles resetting terminal modes, etc. 40 */ 41 public void 42 lsystem(cmd, donemsg) 43 char *cmd; 44 char *donemsg; 45 { 46 register int inp; 47 #if HAVE_SHELL 48 register char *shell; 49 register char *p; 50 #endif 51 IFILE save_ifile; 52 #if MSDOS_COMPILER 53 char cwd[FILENAME_MAX+1]; 54 #endif 55 56 /* 57 * Print the command which is to be executed, 58 * unless the command starts with a "-". 59 */ 60 if (cmd[0] == '-') 61 cmd++; 62 else 63 { 64 clear_bot(); 65 putstr("!"); 66 putstr(cmd); 67 putstr("\n"); 68 } 69 70 #if MSDOS_COMPILER 71 /* 72 * Working directory is global on MSDOS. 73 * The child might change the working directory, so we 74 * must save and restore CWD across calls to "system", 75 * or else we won't find our file when we return and 76 * try to "reedit_ifile" it. 77 */ 78 getcwd(cwd, FILENAME_MAX); 79 #endif 80 81 /* 82 * Close the current input file. 83 */ 84 save_ifile = save_curr_ifile(); 85 (void) edit_ifile(NULL_IFILE); 86 87 /* 88 * De-initialize the terminal and take out of raw mode. 89 */ 90 deinit(); 91 flush(); /* Make sure the deinit chars get out */ 92 raw_mode(0); 93 #if MSDOS_COMPILER==WIN32C 94 close_getchr(); 95 #endif 96 97 /* 98 * Restore signals to their defaults. 99 */ 100 init_signals(0); 101 102 #if HAVE_DUP 103 /* 104 * Force standard input to be the user's terminal 105 * (the normal standard input), even if less's standard input 106 * is coming from a pipe. 107 */ 108 inp = dup(0); 109 close(0); 110 if (open("/dev/tty", OPEN_READ) < 0) 111 dup(inp); 112 #endif 113 114 /* 115 * Pass the command to the system to be executed. 116 * If we have a SHELL environment variable, use 117 * <$SHELL -c "command"> instead of just <command>. 118 * If the command is empty, just invoke a shell. 119 */ 120 #if HAVE_SHELL 121 p = NULL; 122 if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') 123 { 124 if (*cmd == '\0') 125 p = save(shell); 126 else 127 { 128 char *esccmd; 129 if ((esccmd = esc_metachars(cmd)) == NULL) 130 { 131 p = (char *) ecalloc(strlen(shell) + 132 strlen(cmd) + 7, sizeof(char)); 133 sprintf(p, "%s -c \"%s\"", shell, cmd); 134 } else 135 { 136 p = (char *) ecalloc(strlen(shell) + 137 strlen(esccmd) + 5, sizeof(char)); 138 sprintf(p, "%s -c %s", shell, esccmd); 139 free(esccmd); 140 } 141 } 142 } 143 if (p == NULL) 144 { 145 if (*cmd == '\0') 146 p = save("sh"); 147 else 148 p = save(cmd); 149 } 150 151 system(p); 152 free(p); 153 #else 154 #if MSDOS_COMPILER==DJGPPC 155 /* 156 * Make stdin of the child be in cooked mode. 157 */ 158 setmode(0, O_TEXT); 159 /* 160 * We don't need to catch signals of the child (it 161 * also makes trouble with some DPMI servers). 162 */ 163 __djgpp_exception_toggle(); 164 system(cmd); 165 __djgpp_exception_toggle(); 166 #else 167 system(cmd); 168 #endif 169 #endif 170 171 #if HAVE_DUP 172 /* 173 * Restore standard input, reset signals, raw mode, etc. 174 */ 175 close(0); 176 dup(inp); 177 close(inp); 178 #endif 179 180 #if MSDOS_COMPILER==WIN32C 181 open_getchr(); 182 #endif 183 init_signals(1); 184 raw_mode(1); 185 if (donemsg != NULL) 186 { 187 putstr(donemsg); 188 putstr(" (press RETURN)"); 189 get_return(); 190 putchr('\n'); 191 flush(); 192 } 193 init(); 194 screen_trashed = 1; 195 196 #if MSDOS_COMPILER 197 /* 198 * Restore the previous directory (possibly 199 * changed by the child program we just ran). 200 */ 201 chdir(cwd); 202 #if MSDOS_COMPILER != DJGPPC 203 /* 204 * Some versions of chdir() don't change to the drive 205 * which is part of CWD. (DJGPP does this in chdir.) 206 */ 207 if (cwd[1] == ':') 208 { 209 if (cwd[0] >= 'a' && cwd[0] <= 'z') 210 setdisk(cwd[0] - 'a'); 211 else if (cwd[0] >= 'A' && cwd[0] <= 'Z') 212 setdisk(cwd[0] - 'A'); 213 } 214 #endif 215 #endif 216 217 /* 218 * Reopen the current input file. 219 */ 220 reedit_ifile(save_ifile); 221 222 #if defined(SIGWINCH) || defined(SIGWIND) 223 /* 224 * Since we were ignoring window change signals while we executed 225 * the system command, we must assume the window changed. 226 * Warning: this leaves a signal pending (in "sigs"), 227 * so psignals() should be called soon after lsystem(). 228 */ 229 winch(0); 230 #endif 231 } 232 233 #endif 234 235 #if PIPEC 236 237 /* 238 * Pipe a section of the input file into the given shell command. 239 * The section to be piped is the section "between" the current 240 * position and the position marked by the given letter. 241 * 242 * If the mark is after the current screen, the section between 243 * the top line displayed and the mark is piped. 244 * If the mark is before the current screen, the section between 245 * the mark and the bottom line displayed is piped. 246 * If the mark is on the current screen, or if the mark is ".", 247 * the whole current screen is piped. 248 */ 249 public int 250 pipe_mark(c, cmd) 251 int c; 252 char *cmd; 253 { 254 POSITION mpos, tpos, bpos; 255 256 /* 257 * mpos = the marked position. 258 * tpos = top of screen. 259 * bpos = bottom of screen. 260 */ 261 mpos = markpos(c); 262 if (mpos == NULL_POSITION) 263 return (-1); 264 tpos = position(TOP); 265 if (tpos == NULL_POSITION) 266 tpos = ch_zero(); 267 bpos = position(BOTTOM); 268 269 if (c == '.') 270 return (pipe_data(cmd, tpos, bpos)); 271 else if (mpos <= tpos) 272 return (pipe_data(cmd, mpos, bpos)); 273 else if (bpos == NULL_POSITION) 274 return (pipe_data(cmd, tpos, bpos)); 275 else 276 return (pipe_data(cmd, tpos, mpos)); 277 } 278 279 /* 280 * Create a pipe to the given shell command. 281 * Feed it the file contents between the positions spos and epos. 282 */ 283 public int 284 pipe_data(cmd, spos, epos) 285 char *cmd; 286 POSITION spos; 287 POSITION epos; 288 { 289 register FILE *f; 290 register int c; 291 extern FILE *popen(); 292 293 /* 294 * This is structured much like lsystem(). 295 * Since we're running a shell program, we must be careful 296 * to perform the necessary deinitialization before running 297 * the command, and reinitialization after it. 298 */ 299 if (ch_seek(spos) != 0) 300 { 301 error("Cannot seek to start position", NULL_PARG); 302 return (-1); 303 } 304 305 if ((f = popen(cmd, "w")) == NULL) 306 { 307 error("Cannot create pipe", NULL_PARG); 308 return (-1); 309 } 310 clear_bot(); 311 putstr("!"); 312 putstr(cmd); 313 putstr("\n"); 314 315 deinit(); 316 flush(); 317 raw_mode(0); 318 init_signals(0); 319 #if MSDOS_COMPILER==WIN32C 320 close_getchr(); 321 #endif 322 #ifdef SIGPIPE 323 LSIGNAL(SIGPIPE, SIG_IGN); 324 #endif 325 326 c = EOI; 327 while (epos == NULL_POSITION || spos++ <= epos) 328 { 329 /* 330 * Read a character from the file and give it to the pipe. 331 */ 332 c = ch_forw_get(); 333 if (c == EOI) 334 break; 335 if (putc(c, f) == EOF) 336 break; 337 } 338 339 /* 340 * Finish up the last line. 341 */ 342 while (c != '\n' && c != EOI ) 343 { 344 c = ch_forw_get(); 345 if (c == EOI) 346 break; 347 if (putc(c, f) == EOF) 348 break; 349 } 350 351 pclose(f); 352 353 #ifdef SIGPIPE 354 LSIGNAL(SIGPIPE, SIG_DFL); 355 #endif 356 #if MSDOS_COMPILER==WIN32C 357 open_getchr(); 358 #endif 359 init_signals(1); 360 raw_mode(1); 361 init(); 362 screen_trashed = 1; 363 #if defined(SIGWINCH) || defined(SIGWIND) 364 /* {{ Probably don't need this here. }} */ 365 winch(0); 366 #endif 367 return (0); 368 } 369 370 #endif 371 372 #ifdef _OSK 373 /* 374 * Popen, and Pclose, for OS-9. 375 * 376 * Based on code copyright (c) 1988 by Wolfgang Ocker, Puchheim, 377 * Ulli Dessauer, Germering and 378 * Reimer Mellin, Muenchen 379 * (W-Germany) 380 * 381 * These functions can be copied and distributed freely for any 382 * non-commercial purposes. It can only be incorporated into 383 * commercial software with the written permission of the authors. 384 * 385 * TOP-specific code stripped out and adapted for less by M.Gregorie, 1996 386 * 387 * address: Wolfgang Ocker 388 * Lochhauserstrasse 35a 389 * D-8039 Puchheim 390 * West Germany 391 * 392 * e-mail: weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP 393 * pyramid!tmpmbx!recco!weo 394 * pyramid!tmpmbx!nitmar!ud 395 * pyramid!tmpmbx!ramsys!ram 396 * 397 * Martin Gregorie 398 * 10 Sadlers Mead 399 * Harlow 400 * Essex, CM18 6HG 401 * U.K. 402 * 403 * gregorie@logica.com 404 */ 405 #include <strings.h> 406 #include <errno.h> 407 extern char **environ; 408 extern char *getenv(); 409 extern int os9forkc(); 410 static int pids[_NFILE] = { 0, 0, 0, 0, 0, 0, 0, 0, 411 0, 0, 0, 0, 0, 0, 0, 0, 412 0, 0, 0, 0, 0, 0, 0, 0, 413 0, 0, 0, 0, 0, 0, 0, 0 }; 414 /* 415 * p o p e n 416 */ 417 FILE *popen(name, mode) 418 char *name; 419 char *mode; 420 { 421 int fd, fd2, fdsav, pid; 422 static char *argv[] = {NULL, NULL, NULL }; 423 static char cmd[200]; 424 static char cmd_path[200]; 425 char *cp; 426 char *shell; 427 FILE *r; 428 if ((shell = getenv("SHELL")) == NULL) 429 return(NULL); 430 cp = name; 431 while (*cp == ' ') 432 cp++; 433 strcpy(cmd_path, cp); 434 if (cp = index(cmd_path, ' ')) 435 *cp++ = '\0'; 436 strcpy(cmd, "ex "); 437 strcat(cmd, cmd_path); 438 if (cp) 439 { 440 strcat(cmd, " "); 441 strcat(cmd, cp); 442 } 443 argv[0] = shell; 444 argv[1] = cmd; 445 /* 446 mode is "r" (stdout) or "w" (stdin) 447 */ 448 switch(mode[0]) 449 { 450 case 'w': fd = 0; 451 break; 452 case 'r': fd = 1; 453 break; 454 default: return(NULL); 455 } 456 if (fd == 1) 457 fflush(stdout); 458 fdsav = dup(fd); 459 close(fd); 460 461 creat("/pipe", S_IWRITE+S_IREAD); 462 pid = os9exec(os9forkc, argv[0], argv, environ, 0, 0, 3); 463 fd2 = dup(fd); 464 close(fd); 465 dup(fdsav); 466 close(fdsav); 467 if (pid > 0) 468 { 469 pids[fd2] = pid; 470 r = fdopen(fd2, mode); 471 } 472 else 473 { 474 close(fd2); 475 r = NULL; 476 } 477 return(r); 478 } 479 480 /* 481 * p c l o s e 482 */ 483 int pclose(fp) 484 FILE *fp; 485 { 486 unsigned int status; 487 int pid; 488 int fd, 489 i; 490 fd = fileno(fp); 491 if (pids[fd] == 0) 492 return(-1); 493 fflush(fp); 494 fclose(fp); 495 while ((pid = wait(&status)) != -1) 496 if (pid == pids[fd]) 497 break; 498 else 499 for (i = 0; i < _NFILE; i++) 500 if (pids[i] == pid) 501 { 502 pids[i] = 0; 503 break; 504 } 505 if (pid == -1) 506 status = -1; 507 pids[fd] = 0; 508 return(status); 509 } 510 #endif /* _OSK */ 511