1 /* 2 * Copyright (C) 1984-2002 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 "less.h" 18 #include <signal.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 OS2 111 /* The __open() system call translates "/dev/tty" to "con". */ 112 if (__open("/dev/tty", OPEN_READ) < 0) 113 #else 114 if (open("/dev/tty", OPEN_READ) < 0) 115 #endif 116 dup(inp); 117 #endif 118 119 /* 120 * Pass the command to the system to be executed. 121 * If we have a SHELL environment variable, use 122 * <$SHELL -c "command"> instead of just <command>. 123 * If the command is empty, just invoke a shell. 124 */ 125 #if HAVE_SHELL 126 p = NULL; 127 if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') 128 { 129 if (*cmd == '\0') 130 p = save(shell); 131 else 132 { 133 char *esccmd = shell_quote(cmd); 134 if (esccmd != NULL) 135 { 136 p = (char *) ecalloc(strlen(shell) + 137 strlen(esccmd) + 5, sizeof(char)); 138 sprintf(p, "%s %s %s", shell, shell_coption(), 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 system(p); 151 free(p); 152 #else 153 #if MSDOS_COMPILER==DJGPPC 154 /* 155 * Make stdin of the child be in cooked mode. 156 */ 157 setmode(0, O_TEXT); 158 /* 159 * We don't need to catch signals of the child (it 160 * also makes trouble with some DPMI servers). 161 */ 162 __djgpp_exception_toggle(); 163 system(cmd); 164 __djgpp_exception_toggle(); 165 #else 166 system(cmd); 167 #endif 168 #endif 169 170 #if HAVE_DUP 171 /* 172 * Restore standard input, reset signals, raw mode, etc. 173 */ 174 close(0); 175 dup(inp); 176 close(inp); 177 #endif 178 179 #if MSDOS_COMPILER==WIN32C 180 open_getchr(); 181 #endif 182 init_signals(1); 183 raw_mode(1); 184 if (donemsg != NULL) 185 { 186 putstr(donemsg); 187 putstr(" (press RETURN)"); 188 get_return(); 189 putchr('\n'); 190 flush(); 191 } 192 init(); 193 screen_trashed = 1; 194 195 #if MSDOS_COMPILER 196 /* 197 * Restore the previous directory (possibly 198 * changed by the child program we just ran). 199 */ 200 chdir(cwd); 201 #if MSDOS_COMPILER != DJGPPC 202 /* 203 * Some versions of chdir() don't change to the drive 204 * which is part of CWD. (DJGPP does this in chdir.) 205 */ 206 if (cwd[1] == ':') 207 { 208 if (cwd[0] >= 'a' && cwd[0] <= 'z') 209 setdisk(cwd[0] - 'a'); 210 else if (cwd[0] >= 'A' && cwd[0] <= 'Z') 211 setdisk(cwd[0] - 'A'); 212 } 213 #endif 214 #endif 215 216 /* 217 * Reopen the current input file. 218 */ 219 reedit_ifile(save_ifile); 220 221 #if defined(SIGWINCH) || defined(SIGWIND) 222 /* 223 * Since we were ignoring window change signals while we executed 224 * the system command, we must assume the window changed. 225 * Warning: this leaves a signal pending (in "sigs"), 226 * so psignals() should be called soon after lsystem(). 227 */ 228 winch(0); 229 #endif 230 } 231 232 #endif 233 234 #if PIPEC 235 236 /* 237 * Pipe a section of the input file into the given shell command. 238 * The section to be piped is the section "between" the current 239 * position and the position marked by the given letter. 240 * 241 * If the mark is after the current screen, the section between 242 * the top line displayed and the mark is piped. 243 * If the mark is before the current screen, the section between 244 * the mark and the bottom line displayed is piped. 245 * If the mark is on the current screen, or if the mark is ".", 246 * the whole current screen is piped. 247 */ 248 public int 249 pipe_mark(c, cmd) 250 int c; 251 char *cmd; 252 { 253 POSITION mpos, tpos, bpos; 254 255 /* 256 * mpos = the marked position. 257 * tpos = top of screen. 258 * bpos = bottom of screen. 259 */ 260 mpos = markpos(c); 261 if (mpos == NULL_POSITION) 262 return (-1); 263 tpos = position(TOP); 264 if (tpos == NULL_POSITION) 265 tpos = ch_zero(); 266 bpos = position(BOTTOM); 267 268 if (c == '.') 269 return (pipe_data(cmd, tpos, bpos)); 270 else if (mpos <= tpos) 271 return (pipe_data(cmd, mpos, bpos)); 272 else if (bpos == NULL_POSITION) 273 return (pipe_data(cmd, tpos, bpos)); 274 else 275 return (pipe_data(cmd, tpos, mpos)); 276 } 277 278 /* 279 * Create a pipe to the given shell command. 280 * Feed it the file contents between the positions spos and epos. 281 */ 282 public int 283 pipe_data(cmd, spos, epos) 284 char *cmd; 285 POSITION spos; 286 POSITION epos; 287 { 288 register FILE *f; 289 register int c; 290 extern FILE *popen(); 291 292 /* 293 * This is structured much like lsystem(). 294 * Since we're running a shell program, we must be careful 295 * to perform the necessary deinitialization before running 296 * the command, and reinitialization after it. 297 */ 298 if (ch_seek(spos) != 0) 299 { 300 error("Cannot seek to start position", NULL_PARG); 301 return (-1); 302 } 303 304 if ((f = popen(cmd, "w")) == NULL) 305 { 306 error("Cannot create pipe", NULL_PARG); 307 return (-1); 308 } 309 clear_bot(); 310 putstr("!"); 311 putstr(cmd); 312 putstr("\n"); 313 314 deinit(); 315 flush(); 316 raw_mode(0); 317 init_signals(0); 318 #if MSDOS_COMPILER==WIN32C 319 close_getchr(); 320 #endif 321 #ifdef SIGPIPE 322 LSIGNAL(SIGPIPE, SIG_IGN); 323 #endif 324 325 c = EOI; 326 while (epos == NULL_POSITION || spos++ <= epos) 327 { 328 /* 329 * Read a character from the file and give it to the pipe. 330 */ 331 c = ch_forw_get(); 332 if (c == EOI) 333 break; 334 if (putc(c, f) == EOF) 335 break; 336 } 337 338 /* 339 * Finish up the last line. 340 */ 341 while (c != '\n' && c != EOI ) 342 { 343 c = ch_forw_get(); 344 if (c == EOI) 345 break; 346 if (putc(c, f) == EOF) 347 break; 348 } 349 350 pclose(f); 351 352 #ifdef SIGPIPE 353 LSIGNAL(SIGPIPE, SIG_DFL); 354 #endif 355 #if MSDOS_COMPILER==WIN32C 356 open_getchr(); 357 #endif 358 init_signals(1); 359 raw_mode(1); 360 init(); 361 screen_trashed = 1; 362 #if defined(SIGWINCH) || defined(SIGWIND) 363 /* {{ Probably don't need this here. }} */ 364 winch(0); 365 #endif 366 return (0); 367 } 368 369 #endif 370 371 #ifdef _OSK 372 /* 373 * Popen, and Pclose, for OS-9. 374 * 375 * Based on code copyright (c) 1988 by Wolfgang Ocker, Puchheim, 376 * Ulli Dessauer, Germering and 377 * Reimer Mellin, Muenchen 378 * (W-Germany) 379 * 380 * These functions can be copied and distributed freely for any 381 * non-commercial purposes. It can only be incorporated into 382 * commercial software with the written permission of the authors. 383 * 384 * TOP-specific code stripped out and adapted for less by M.Gregorie, 1996 385 * 386 * address: Wolfgang Ocker 387 * Lochhauserstrasse 35a 388 * D-8039 Puchheim 389 * West Germany 390 * 391 * e-mail: weo@altger.UUCP, ud@altger.UUCP, ram@altger.UUCP 392 * pyramid!tmpmbx!recco!weo 393 * pyramid!tmpmbx!nitmar!ud 394 * pyramid!tmpmbx!ramsys!ram 395 * 396 * Martin Gregorie 397 * 10 Sadlers Mead 398 * Harlow 399 * Essex, CM18 6HG 400 * U.K. 401 * 402 * gregorie@logica.com 403 */ 404 #include <strings.h> 405 #include <errno.h> 406 extern char **environ; 407 extern char *getenv(); 408 extern int os9forkc(); 409 static int pids[_NFILE] = { 0, 0, 0, 0, 0, 0, 0, 0, 410 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 /* 414 * p o p e n 415 */ 416 FILE *popen(name, mode) 417 char *name; 418 char *mode; 419 { 420 int fd, fd2, fdsav, pid; 421 static char *argv[] = {NULL, NULL, NULL }; 422 static char cmd[200]; 423 static char cmd_path[200]; 424 char *cp; 425 char *shell; 426 FILE *r; 427 if ((shell = getenv("SHELL")) == NULL) 428 return(NULL); 429 cp = name; 430 while (*cp == ' ') 431 cp++; 432 strcpy(cmd_path, cp); 433 if (cp = index(cmd_path, ' ')) 434 *cp++ = '\0'; 435 strcpy(cmd, "ex "); 436 strcat(cmd, cmd_path); 437 if (cp) 438 { 439 strcat(cmd, " "); 440 strcat(cmd, cp); 441 } 442 argv[0] = shell; 443 argv[1] = cmd; 444 /* 445 mode is "r" (stdout) or "w" (stdin) 446 */ 447 switch(mode[0]) 448 { 449 case 'w': fd = 0; 450 break; 451 case 'r': fd = 1; 452 break; 453 default: return(NULL); 454 } 455 if (fd == 1) 456 fflush(stdout); 457 fdsav = dup(fd); 458 close(fd); 459 460 creat("/pipe", S_IWRITE+S_IREAD); 461 pid = os9exec(os9forkc, argv[0], argv, environ, 0, 0, 3); 462 fd2 = dup(fd); 463 close(fd); 464 dup(fdsav); 465 close(fdsav); 466 if (pid > 0) 467 { 468 pids[fd2] = pid; 469 r = fdopen(fd2, mode); 470 } 471 else 472 { 473 close(fd2); 474 r = NULL; 475 } 476 return(r); 477 } 478 479 /* 480 * p c l o s e 481 */ 482 int pclose(fp) 483 FILE *fp; 484 { 485 unsigned int status; 486 int pid; 487 int fd, 488 i; 489 fd = fileno(fp); 490 if (pids[fd] == 0) 491 return(-1); 492 fflush(fp); 493 fclose(fp); 494 while ((pid = wait(&status)) != -1) 495 if (pid == pids[fd]) 496 break; 497 else 498 for (i = 0; i < _NFILE; i++) 499 if (pids[i] == pid) 500 { 501 pids[i] = 0; 502 break; 503 } 504 if (pid == -1) 505 status = -1; 506 pids[fd] = 0; 507 return(status); 508 } 509 #endif /* _OSK */ 510