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