1a5f0fb15SPaul Saab /* 2*2235c7feSXin LI * Copyright (C) 1984-2021 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 796e55cc7SXin LI * For more information, see the README file. 8a5f0fb15SPaul Saab */ 9a5f0fb15SPaul Saab 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab /* 12a5f0fb15SPaul Saab * Routines to execute other programs. 13a5f0fb15SPaul Saab * Necessarily very OS dependent. 14a5f0fb15SPaul Saab */ 15a5f0fb15SPaul Saab 16a5f0fb15SPaul Saab #include "less.h" 17c9346414SPaul Saab #include <signal.h> 18a5f0fb15SPaul Saab #include "position.h" 19a5f0fb15SPaul Saab 20a5f0fb15SPaul Saab #if MSDOS_COMPILER 21a5f0fb15SPaul Saab #include <dos.h> 22b7780dbeSXin LI #if MSDOS_COMPILER==WIN32C && defined(MINGW) 23b7780dbeSXin LI #include <direct.h> 24b7780dbeSXin LI #define setdisk(n) _chdrive((n)+1) 25b7780dbeSXin LI #else 26a5f0fb15SPaul Saab #ifdef _MSC_VER 27a5f0fb15SPaul Saab #include <direct.h> 28a5f0fb15SPaul Saab #define setdisk(n) _chdrive((n)+1) 29a5f0fb15SPaul Saab #else 30a5f0fb15SPaul Saab #include <dir.h> 31a5f0fb15SPaul Saab #endif 32a5f0fb15SPaul Saab #endif 33b7780dbeSXin LI #endif 34a5f0fb15SPaul Saab 35a5f0fb15SPaul Saab extern int screen_trashed; 36a5f0fb15SPaul Saab extern IFILE curr_ifile; 37a5f0fb15SPaul Saab 38a5f0fb15SPaul Saab 39a5f0fb15SPaul Saab #if HAVE_SYSTEM 40a5f0fb15SPaul Saab 41a5f0fb15SPaul Saab /* 42a5f0fb15SPaul Saab * Pass the specified command to a shell to be executed. 43a5f0fb15SPaul Saab * Like plain "system()", but handles resetting terminal modes, etc. 44a5f0fb15SPaul Saab */ 45a5f0fb15SPaul Saab public void 46f6b74a7dSXin LI lsystem(cmd, donemsg) 47f6b74a7dSXin LI char *cmd; 48f6b74a7dSXin LI char *donemsg; 49a5f0fb15SPaul Saab { 501ea31627SRobert Watson int inp; 51a5f0fb15SPaul Saab #if HAVE_SHELL 521ea31627SRobert Watson char *shell; 531ea31627SRobert Watson char *p; 54a5f0fb15SPaul Saab #endif 55a5f0fb15SPaul Saab IFILE save_ifile; 567374caaaSXin LI #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C 57a5f0fb15SPaul Saab char cwd[FILENAME_MAX+1]; 58a5f0fb15SPaul Saab #endif 59a5f0fb15SPaul Saab 60a5f0fb15SPaul Saab /* 61a5f0fb15SPaul Saab * Print the command which is to be executed, 62a5f0fb15SPaul Saab * unless the command starts with a "-". 63a5f0fb15SPaul Saab */ 64a5f0fb15SPaul Saab if (cmd[0] == '-') 65a5f0fb15SPaul Saab cmd++; 66a5f0fb15SPaul Saab else 67a5f0fb15SPaul Saab { 68a5f0fb15SPaul Saab clear_bot(); 69a5f0fb15SPaul Saab putstr("!"); 70a5f0fb15SPaul Saab putstr(cmd); 71a5f0fb15SPaul Saab putstr("\n"); 72a5f0fb15SPaul Saab } 73a5f0fb15SPaul Saab 74a5f0fb15SPaul Saab #if MSDOS_COMPILER 757374caaaSXin LI #if MSDOS_COMPILER==WIN32C 767374caaaSXin LI if (*cmd == '\0') 777374caaaSXin LI cmd = getenv("COMSPEC"); 787374caaaSXin LI #else 79a5f0fb15SPaul Saab /* 80a5f0fb15SPaul Saab * Working directory is global on MSDOS. 81a5f0fb15SPaul Saab * The child might change the working directory, so we 82a5f0fb15SPaul Saab * must save and restore CWD across calls to "system", 83a5f0fb15SPaul Saab * or else we won't find our file when we return and 84a5f0fb15SPaul Saab * try to "reedit_ifile" it. 85a5f0fb15SPaul Saab */ 86a5f0fb15SPaul Saab getcwd(cwd, FILENAME_MAX); 87a5f0fb15SPaul Saab #endif 887374caaaSXin LI #endif 89a5f0fb15SPaul Saab 90a5f0fb15SPaul Saab /* 91a5f0fb15SPaul Saab * Close the current input file. 92a5f0fb15SPaul Saab */ 93a5f0fb15SPaul Saab save_ifile = save_curr_ifile(); 94a5f0fb15SPaul Saab (void) edit_ifile(NULL_IFILE); 95a5f0fb15SPaul Saab 96a5f0fb15SPaul Saab /* 97a5f0fb15SPaul Saab * De-initialize the terminal and take out of raw mode. 98a5f0fb15SPaul Saab */ 99a5f0fb15SPaul Saab deinit(); 100a5f0fb15SPaul Saab flush(); /* Make sure the deinit chars get out */ 101a5f0fb15SPaul Saab raw_mode(0); 102a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C 103a5f0fb15SPaul Saab close_getchr(); 104a5f0fb15SPaul Saab #endif 105a5f0fb15SPaul Saab 106a5f0fb15SPaul Saab /* 107a5f0fb15SPaul Saab * Restore signals to their defaults. 108a5f0fb15SPaul Saab */ 109a5f0fb15SPaul Saab init_signals(0); 110a5f0fb15SPaul Saab 111a5f0fb15SPaul Saab #if HAVE_DUP 112a5f0fb15SPaul Saab /* 113a5f0fb15SPaul Saab * Force standard input to be the user's terminal 114a5f0fb15SPaul Saab * (the normal standard input), even if less's standard input 115a5f0fb15SPaul Saab * is coming from a pipe. 116a5f0fb15SPaul Saab */ 117a5f0fb15SPaul Saab inp = dup(0); 118a5f0fb15SPaul Saab close(0); 119*2235c7feSXin LI #if !MSDOS_COMPILER 120c9346414SPaul Saab #if OS2 121c9346414SPaul Saab /* The __open() system call translates "/dev/tty" to "con". */ 122*2235c7feSXin LI if (__open(tty_device(), OPEN_READ) < 0) 123c9346414SPaul Saab #else 124*2235c7feSXin LI if (open(tty_device(), OPEN_READ) < 0) 125*2235c7feSXin LI #endif 126c9346414SPaul Saab #endif 127a5f0fb15SPaul Saab dup(inp); 128a5f0fb15SPaul Saab #endif 129a5f0fb15SPaul Saab 130a5f0fb15SPaul Saab /* 131a5f0fb15SPaul Saab * Pass the command to the system to be executed. 132a5f0fb15SPaul Saab * If we have a SHELL environment variable, use 133a5f0fb15SPaul Saab * <$SHELL -c "command"> instead of just <command>. 134a5f0fb15SPaul Saab * If the command is empty, just invoke a shell. 135a5f0fb15SPaul Saab */ 136a5f0fb15SPaul Saab #if HAVE_SHELL 137a5f0fb15SPaul Saab p = NULL; 138a5f0fb15SPaul Saab if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') 139a5f0fb15SPaul Saab { 140a5f0fb15SPaul Saab if (*cmd == '\0') 141a5f0fb15SPaul Saab p = save(shell); 142a5f0fb15SPaul Saab else 143a5f0fb15SPaul Saab { 144000ba3e8STim J. Robbins char *esccmd = shell_quote(cmd); 145000ba3e8STim J. Robbins if (esccmd != NULL) 146a5f0fb15SPaul Saab { 147a15691bfSXin LI int len = (int) (strlen(shell) + strlen(esccmd) + 5); 1486dcb072bSXin LI p = (char *) ecalloc(len, sizeof(char)); 1496dcb072bSXin LI SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd); 150a5f0fb15SPaul Saab free(esccmd); 151a5f0fb15SPaul Saab } 152a5f0fb15SPaul Saab } 153a5f0fb15SPaul Saab } 154a5f0fb15SPaul Saab if (p == NULL) 155a5f0fb15SPaul Saab { 156a5f0fb15SPaul Saab if (*cmd == '\0') 157a5f0fb15SPaul Saab p = save("sh"); 158a5f0fb15SPaul Saab else 159a5f0fb15SPaul Saab p = save(cmd); 160a5f0fb15SPaul Saab } 161a5f0fb15SPaul Saab system(p); 162a5f0fb15SPaul Saab free(p); 163a5f0fb15SPaul Saab #else 164a5f0fb15SPaul Saab #if MSDOS_COMPILER==DJGPPC 165a5f0fb15SPaul Saab /* 166a5f0fb15SPaul Saab * Make stdin of the child be in cooked mode. 167a5f0fb15SPaul Saab */ 168a5f0fb15SPaul Saab setmode(0, O_TEXT); 169a5f0fb15SPaul Saab /* 170a5f0fb15SPaul Saab * We don't need to catch signals of the child (it 171a5f0fb15SPaul Saab * also makes trouble with some DPMI servers). 172a5f0fb15SPaul Saab */ 173a5f0fb15SPaul Saab __djgpp_exception_toggle(); 174a5f0fb15SPaul Saab system(cmd); 175a5f0fb15SPaul Saab __djgpp_exception_toggle(); 176a5f0fb15SPaul Saab #else 177a5f0fb15SPaul Saab system(cmd); 178a5f0fb15SPaul Saab #endif 179a5f0fb15SPaul Saab #endif 180a5f0fb15SPaul Saab 181a5f0fb15SPaul Saab #if HAVE_DUP 182a5f0fb15SPaul Saab /* 183a5f0fb15SPaul Saab * Restore standard input, reset signals, raw mode, etc. 184a5f0fb15SPaul Saab */ 185a5f0fb15SPaul Saab close(0); 186a5f0fb15SPaul Saab dup(inp); 187a5f0fb15SPaul Saab close(inp); 188a5f0fb15SPaul Saab #endif 189a5f0fb15SPaul Saab 190a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C 191a5f0fb15SPaul Saab open_getchr(); 192a5f0fb15SPaul Saab #endif 193a5f0fb15SPaul Saab init_signals(1); 194a5f0fb15SPaul Saab raw_mode(1); 195a5f0fb15SPaul Saab if (donemsg != NULL) 196a5f0fb15SPaul Saab { 197a5f0fb15SPaul Saab putstr(donemsg); 198a5f0fb15SPaul Saab putstr(" (press RETURN)"); 199a5f0fb15SPaul Saab get_return(); 200a5f0fb15SPaul Saab putchr('\n'); 201a5f0fb15SPaul Saab flush(); 202a5f0fb15SPaul Saab } 203a5f0fb15SPaul Saab init(); 204a5f0fb15SPaul Saab screen_trashed = 1; 205a5f0fb15SPaul Saab 2067374caaaSXin LI #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C 207a5f0fb15SPaul Saab /* 208a5f0fb15SPaul Saab * Restore the previous directory (possibly 209a5f0fb15SPaul Saab * changed by the child program we just ran). 210a5f0fb15SPaul Saab */ 211a5f0fb15SPaul Saab chdir(cwd); 212a5f0fb15SPaul Saab #if MSDOS_COMPILER != DJGPPC 213a5f0fb15SPaul Saab /* 214a5f0fb15SPaul Saab * Some versions of chdir() don't change to the drive 215a5f0fb15SPaul Saab * which is part of CWD. (DJGPP does this in chdir.) 216a5f0fb15SPaul Saab */ 217a5f0fb15SPaul Saab if (cwd[1] == ':') 218a5f0fb15SPaul Saab { 219a5f0fb15SPaul Saab if (cwd[0] >= 'a' && cwd[0] <= 'z') 220a5f0fb15SPaul Saab setdisk(cwd[0] - 'a'); 221a5f0fb15SPaul Saab else if (cwd[0] >= 'A' && cwd[0] <= 'Z') 222a5f0fb15SPaul Saab setdisk(cwd[0] - 'A'); 223a5f0fb15SPaul Saab } 224a5f0fb15SPaul Saab #endif 225a5f0fb15SPaul Saab #endif 226a5f0fb15SPaul Saab 227a5f0fb15SPaul Saab /* 228a5f0fb15SPaul Saab * Reopen the current input file. 229a5f0fb15SPaul Saab */ 230a5f0fb15SPaul Saab reedit_ifile(save_ifile); 231a5f0fb15SPaul Saab 232a5f0fb15SPaul Saab #if defined(SIGWINCH) || defined(SIGWIND) 233a5f0fb15SPaul Saab /* 234a5f0fb15SPaul Saab * Since we were ignoring window change signals while we executed 235a5f0fb15SPaul Saab * the system command, we must assume the window changed. 236a5f0fb15SPaul Saab * Warning: this leaves a signal pending (in "sigs"), 237a5f0fb15SPaul Saab * so psignals() should be called soon after lsystem(). 238a5f0fb15SPaul Saab */ 239a5f0fb15SPaul Saab winch(0); 240a5f0fb15SPaul Saab #endif 241a5f0fb15SPaul Saab } 242a5f0fb15SPaul Saab 243a5f0fb15SPaul Saab #endif 244a5f0fb15SPaul Saab 245a5f0fb15SPaul Saab #if PIPEC 246a5f0fb15SPaul Saab 247a5f0fb15SPaul Saab /* 248a5f0fb15SPaul Saab * Pipe a section of the input file into the given shell command. 249a5f0fb15SPaul Saab * The section to be piped is the section "between" the current 250a5f0fb15SPaul Saab * position and the position marked by the given letter. 251a5f0fb15SPaul Saab * 252a5f0fb15SPaul Saab * If the mark is after the current screen, the section between 253a5f0fb15SPaul Saab * the top line displayed and the mark is piped. 254a5f0fb15SPaul Saab * If the mark is before the current screen, the section between 255a5f0fb15SPaul Saab * the mark and the bottom line displayed is piped. 256a5f0fb15SPaul Saab * If the mark is on the current screen, or if the mark is ".", 257a5f0fb15SPaul Saab * the whole current screen is piped. 258a5f0fb15SPaul Saab */ 259a5f0fb15SPaul Saab public int 260f6b74a7dSXin LI pipe_mark(c, cmd) 261f6b74a7dSXin LI int c; 262f6b74a7dSXin LI char *cmd; 263a5f0fb15SPaul Saab { 264a5f0fb15SPaul Saab POSITION mpos, tpos, bpos; 265a5f0fb15SPaul Saab 266a5f0fb15SPaul Saab /* 267a5f0fb15SPaul Saab * mpos = the marked position. 268a5f0fb15SPaul Saab * tpos = top of screen. 269a5f0fb15SPaul Saab * bpos = bottom of screen. 270a5f0fb15SPaul Saab */ 271a5f0fb15SPaul Saab mpos = markpos(c); 272a5f0fb15SPaul Saab if (mpos == NULL_POSITION) 273a5f0fb15SPaul Saab return (-1); 274a5f0fb15SPaul Saab tpos = position(TOP); 275a5f0fb15SPaul Saab if (tpos == NULL_POSITION) 276a5f0fb15SPaul Saab tpos = ch_zero(); 277a5f0fb15SPaul Saab bpos = position(BOTTOM); 278a5f0fb15SPaul Saab 279a5f0fb15SPaul Saab if (c == '.') 280a5f0fb15SPaul Saab return (pipe_data(cmd, tpos, bpos)); 281a5f0fb15SPaul Saab else if (mpos <= tpos) 282a5f0fb15SPaul Saab return (pipe_data(cmd, mpos, bpos)); 283a5f0fb15SPaul Saab else if (bpos == NULL_POSITION) 284a5f0fb15SPaul Saab return (pipe_data(cmd, tpos, bpos)); 285a5f0fb15SPaul Saab else 286a5f0fb15SPaul Saab return (pipe_data(cmd, tpos, mpos)); 287a5f0fb15SPaul Saab } 288a5f0fb15SPaul Saab 289a5f0fb15SPaul Saab /* 290a5f0fb15SPaul Saab * Create a pipe to the given shell command. 291a5f0fb15SPaul Saab * Feed it the file contents between the positions spos and epos. 292a5f0fb15SPaul Saab */ 293a5f0fb15SPaul Saab public int 294f6b74a7dSXin LI pipe_data(cmd, spos, epos) 295f6b74a7dSXin LI char *cmd; 296f6b74a7dSXin LI POSITION spos; 297f6b74a7dSXin LI POSITION epos; 298a5f0fb15SPaul Saab { 2991ea31627SRobert Watson FILE *f; 3001ea31627SRobert Watson int c; 301a5f0fb15SPaul Saab 302a5f0fb15SPaul Saab /* 303a5f0fb15SPaul Saab * This is structured much like lsystem(). 304a5f0fb15SPaul Saab * Since we're running a shell program, we must be careful 305a5f0fb15SPaul Saab * to perform the necessary deinitialization before running 306a5f0fb15SPaul Saab * the command, and reinitialization after it. 307a5f0fb15SPaul Saab */ 308a5f0fb15SPaul Saab if (ch_seek(spos) != 0) 309a5f0fb15SPaul Saab { 310a5f0fb15SPaul Saab error("Cannot seek to start position", NULL_PARG); 311a5f0fb15SPaul Saab return (-1); 312a5f0fb15SPaul Saab } 313a5f0fb15SPaul Saab 314a5f0fb15SPaul Saab if ((f = popen(cmd, "w")) == NULL) 315a5f0fb15SPaul Saab { 316a5f0fb15SPaul Saab error("Cannot create pipe", NULL_PARG); 317a5f0fb15SPaul Saab return (-1); 318a5f0fb15SPaul Saab } 319a5f0fb15SPaul Saab clear_bot(); 320a5f0fb15SPaul Saab putstr("!"); 321a5f0fb15SPaul Saab putstr(cmd); 322a5f0fb15SPaul Saab putstr("\n"); 323a5f0fb15SPaul Saab 324a5f0fb15SPaul Saab deinit(); 325a5f0fb15SPaul Saab flush(); 326a5f0fb15SPaul Saab raw_mode(0); 327a5f0fb15SPaul Saab init_signals(0); 328a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C 329a5f0fb15SPaul Saab close_getchr(); 330a5f0fb15SPaul Saab #endif 331a5f0fb15SPaul Saab #ifdef SIGPIPE 332a5f0fb15SPaul Saab LSIGNAL(SIGPIPE, SIG_IGN); 333a5f0fb15SPaul Saab #endif 334a5f0fb15SPaul Saab 335a5f0fb15SPaul Saab c = EOI; 336a5f0fb15SPaul Saab while (epos == NULL_POSITION || spos++ <= epos) 337a5f0fb15SPaul Saab { 338a5f0fb15SPaul Saab /* 339a5f0fb15SPaul Saab * Read a character from the file and give it to the pipe. 340a5f0fb15SPaul Saab */ 341a5f0fb15SPaul Saab c = ch_forw_get(); 342a5f0fb15SPaul Saab if (c == EOI) 343a5f0fb15SPaul Saab break; 344a5f0fb15SPaul Saab if (putc(c, f) == EOF) 345a5f0fb15SPaul Saab break; 346a5f0fb15SPaul Saab } 347a5f0fb15SPaul Saab 348a5f0fb15SPaul Saab /* 349a5f0fb15SPaul Saab * Finish up the last line. 350a5f0fb15SPaul Saab */ 351a5f0fb15SPaul Saab while (c != '\n' && c != EOI ) 352a5f0fb15SPaul Saab { 353a5f0fb15SPaul Saab c = ch_forw_get(); 354a5f0fb15SPaul Saab if (c == EOI) 355a5f0fb15SPaul Saab break; 356a5f0fb15SPaul Saab if (putc(c, f) == EOF) 357a5f0fb15SPaul Saab break; 358a5f0fb15SPaul Saab } 359a5f0fb15SPaul Saab 360a5f0fb15SPaul Saab pclose(f); 361a5f0fb15SPaul Saab 362a5f0fb15SPaul Saab #ifdef SIGPIPE 363a5f0fb15SPaul Saab LSIGNAL(SIGPIPE, SIG_DFL); 364a5f0fb15SPaul Saab #endif 365a5f0fb15SPaul Saab #if MSDOS_COMPILER==WIN32C 366a5f0fb15SPaul Saab open_getchr(); 367a5f0fb15SPaul Saab #endif 368a5f0fb15SPaul Saab init_signals(1); 369a5f0fb15SPaul Saab raw_mode(1); 370a5f0fb15SPaul Saab init(); 371a5f0fb15SPaul Saab screen_trashed = 1; 372a5f0fb15SPaul Saab #if defined(SIGWINCH) || defined(SIGWIND) 373a5f0fb15SPaul Saab /* {{ Probably don't need this here. }} */ 374a5f0fb15SPaul Saab winch(0); 375a5f0fb15SPaul Saab #endif 376a5f0fb15SPaul Saab return (0); 377a5f0fb15SPaul Saab } 378a5f0fb15SPaul Saab 379a5f0fb15SPaul Saab #endif 380