static int native_inout_popen(FILE **fr, FILE **fw, char *cmd) { char buf[NFILEN + 128]; HANDLE handles[3]; int i, rc, rp[3], tmpin_fd, wp[3]; TRACE((T_CALLED "native_inout_popen cmd=%s\n", cmd)); proc_handle = BAD_PROC_HANDLE; rp[0] = rp[1] = rp[2] = wp[0] = wp[1] = wp[2] = BAD_FD; handles[0] = handles[1] = handles[2] = INVALID_HANDLE_VALUE; tmpin_fd = BAD_FD; tmpin_name = NULL; set_console_title(cmd); if (is_win95()) { char *cmdp; /* * If w32pipes is set on a win95 host, you don't ever want slowreadf() * to periodically update the display while an intrinisic, high * bandwidth DOS command is in progress. Reason: the win95 shell, * command.com, will simply hang in the following scenario: * * ^X!<high_bandwidth_cmd> * * and * * PIPESIZ < output of <high_bandwidth_cmd> * * I'm assuming that what's going on here is that command.com is * written in ASM and is using very low level BIOS/DOS calls to * effect output and, furthermore, that these low level calls don't * block when the input consumer is busy. */ cmdp = skip_blanks(cmd); nowait_pipe_cmd = (strnicmp(cmdp, "dir", 3) == 0) || (strnicmp(cmdp, "type", 4) == 0); } do { if (fr) { *fr = NULL; /* * Open (parent's) input pipe in TEXT mode, which will force * translation of the child's CR/LF record delimiters to NL * and keep the dreaded ^M chars from temporarily appearing * in a vile buffer (ugly). */ if (_pipe(rp, PIPESIZ, O_TEXT|O_NOINHERIT) == -1) break; if ((rp[2] = _dup(rp[1])) == -1) break; handles[2] = handles[1] = (HANDLE) _get_osfhandle(rp[2]); (void) close(rp[1]); rp[1] = BAD_FD; if (! fw) { /* * This is a read pipe (only). Connect child's stdin to * an empty file. Under no circumstances should the * child's stdin be connected to a device (else lots of * screwy things will occur). In particular, connecting * the child's stdin to the parent's stdin will cause * aborts and hangs on the various Win32 hosts. You've * been warned. */ if ((tmpin_name = _tempnam(getenv("TEMP"), "vile")) == NULL) break; if ((tmpin_fd = open(tmpin_name, O_RDONLY|O_CREAT|O_TRUNC, _S_IWRITE|_S_IREAD)) == BAD_FD) { break; } handles[0] = (HANDLE) _get_osfhandle(tmpin_fd); } if ((*fr = fdopen(rp[0], "r")) == 0) break; } if (fw) { *fw = NULL; /* * Open (child's) output pipe in binary mode, which will * prevent translation of the parent's CR/LF record delimiters * to NL. Apparently, many apps want those delimiters :-) . */ if (_pipe(wp, PIPESIZ, O_BINARY|O_NOINHERIT) == -1) break; if ((wp[2] = _dup(wp[0])) == -1) break; handles[0] = (HANDLE)_get_osfhandle(wp[2]); (void) close(wp[0]); wp[0] = BAD_FD; if (! fr) handles[1] = handles[2] = GetStdHandle(STD_OUTPUT_HANDLE); if ((*fw = fdopen(wp[1], "w")) == 0) break; } rc = (exec_shell(cmd, handles, fr != NULL /* Child wdw hidden unless write pipe. */ ) == BAD_PROC_HANDLE) ? FALSE : TRUE; if (fw) { if (! rc) { /* Shell process failed, put complaint in user's face. */ sprintf(buf, SHELL_ERR_MSG, get_shell()); lastditch_msg(buf); } w32_close_handle(handles[0]); } if (fr) { if (! rc) { unsigned len; /* * Shell process failed, put complaint in user's buffer. * Can't write to handles[1] on a win2k host because the * previously failed CreateProcess() call damaged the * handle. */ len = (unsigned) (lsprintf(buf, SHELL_ERR_MSG, get_shell()) - buf); (void) write(rp[2], buf, len); (void) close(rp[2]); /* in weird state; why not? */ } w32_close_handle(handles[1]); close_fd(tmpin_fd); } returnCode(rc); } while (FALSE); /* If we get here -- some operation has failed. Clean up. */ close_fd(wp[0]); close_fd(wp[1]); close_fd(wp[2]); close_fd(rp[0]); close_fd(rp[1]); close_fd(rp[2]); close_fd(tmpin_fd); for (i = 0; i < 3; i++) { if (handles[i] != INVALID_HANDLE_VALUE) w32_close_handle(handles[i]); } common_cleanup(); returnCode(FALSE); }
static int tmp_inout_popen(FILE **fr, FILE **fw, char *cmd) { char buf[NFILEN + 128]; DWORD dummy, len; int rc, term_status, tmpin_fd; TRACE(("tmp_inout_popen cmd=%s\n", cmd)); proc_handle = BAD_PROC_HANDLE; handles[0] = handles[1] = handles[2] = INVALID_HANDLE_VALUE; tmpin_fd = stdin_fd = stdout_fd = BAD_FD; tmpin_name = stdin_name = stdout_name = NULL; set_console_title(cmd); do { if (fr) { *fr = NULL; if ((stdin_name = _tempnam(getenv("TEMP"), "vile")) == NULL) break; if ((stdin_fd = open(stdin_name, O_RDWR|O_CREAT|O_TRUNC|O_TEXT, _S_IWRITE|_S_IREAD)) == BAD_FD) { break; } handles[2] = handles[1] = (HANDLE) _get_osfhandle(stdin_fd); if (! fw) { /* * This is a read pipe (only). Connect child's stdin to * an empty file. Under no circumstances should the * child's stdin be connected to a device (else lots of * screwy things will occur). In particular, connecting * the child's stdin to the parent's stdin will cause * aborts and hangs on the various Win32 hosts. You've * been warned. */ if ((tmpin_name = _tempnam(getenv("TEMP"), "vile")) == NULL) break; if ((tmpin_fd = open(tmpin_name, O_RDONLY|O_CREAT|O_TRUNC, _S_IWRITE|_S_IREAD)) == BAD_FD) { break; } handles[0] = (HANDLE) _get_osfhandle(tmpin_fd); } else { /* * Set up descriptor for filter operation. Note the * sublteties here: exec'd shell is passed a descriptor * to the temp file that's opened "w". The editor * receives a descriptor to the file that's opened "r". */ if ((*fr = fopen(stdin_name, "r")) == NULL) break; } } if (fw) { *fw = NULL; /* create a temp file to receive data from the editor */ if ((stdout_name = _tempnam(getenv("TEMP"), "vile")) == NULL) break; if ((stdout_fd = open(stdout_name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, _S_IWRITE|_S_IREAD)) == BAD_FD) { break; } if ((*fw = fdopen(stdout_fd, "w")) == 0) break; /* * we're all set up, but can't exec "cmd" until the editor * writes data to the temp file connected to stdout. */ shcmd = cmd; /* remember this */ return (TRUE); } /* This must be a read (only) pipe. Appropriate to exec "cmd". */ rc = (exec_shell(cmd, handles, TRUE /* hide child wdw */ ) == BAD_PROC_HANDLE) ? FALSE : TRUE; if (! rc) { /* * Shell process failed, put complaint in user's buffer, which * is currently proxied by a temp file that the editor will * suck in shortly. */ len = (DWORD) (lsprintf(buf, SHELL_ERR_MSG, get_shell()) - buf); (void) WriteFile(handles[1], buf, len, &dummy, NULL); FlushFileBuffers(handles[1]); } else { /* wait for exec'd process to exit */ (void) cwait(&term_status, (CWAIT_PARAM_TYPE) proc_handle, 0); TRACE(("...CreateProcess finished waiting in tmp_inout_popen\n")); close_proc_handle(); } /* * When closing descriptors shared between parent and child, order * is quite important when $shell == command.com . In this * situation, the descriptors can't be closed until the exec'd * process exits (I kid you not). */ close_fd(stdin_fd); (void) close(tmpin_fd); /* let the editor consume the output of the read pipe */ if ((*fr = fopen(stdin_name, "r")) == NULL) { /* * impossible to put error in user's buffer since that file * descriptor is closed. */ sprintf(buf, "[error opening temp file \"%s\": %s]", stdin_name, strerror(errno)); lastditch_msg(buf); break; } return (rc); } while (FALSE); /* If we get here -- some operation has failed. Clean up. */ tmp_cleanup(); return (FALSE); }
/* int main(int argc, char *argv[], char *environ[]) */ int main(int argc, char *argv[]) { char tmpbuf[MAX_OBJNAMELEN + 1]; obj_t *tobj; int i; char *p; char c; short intstatus = 0; short preload = 1; char *fn=NULL; setvbuf(stdout, NULL, _IONBF, 0); if (argc < 2) { do_banner(); do_help(argv[0]); return -1; } if ((N = nsp_newstate()) == NULL) return -1; setsigs(); N->debug = 0; //nspbase_register_all(N); /* add env */ tobj = nsp_settable(N, &N->g, "_ENV"); for (i = 0;environ[i] != NULL;i++) { strncpy(tmpbuf, environ[i], MAX_OBJNAMELEN); p = strchr(tmpbuf, '='); if (!p) continue; *p = '\0'; p = strchr(environ[i], '=') + 1; nsp_setstr(N, tobj, tmpbuf, p, -1); } /* add args */ tobj = nsp_settable(N, &N->g, "_ARGS"); for (i = 0;i < argc;i++) { n_ntoa(N, tmpbuf, i, 10, 0); nsp_setstr(N, tobj, tmpbuf, argv[i], -1); } tobj = nsp_settable(N, &N->g, "io"); nsp_setcfunc(N, tobj, "gets", (NSP_CFUNC)neslib_io_gets); for (i = 1;i < argc;i++) { if (argv[i] == NULL) break; if (argv[i][0] == '-') { c = argv[i][1]; if (!c) { break; } else if ((c == 'd') || (c == 'D')) { N->debug = 1; } else if ((c == 's') || (c == 'S')) { intstatus = 1; } else if ((c == 'b') || (c == 'B')) { preload = 0; } else if ((c == 'e') || (c == 'E')) { if (++i < argc) { if (preload) do_preload(N); nsp_exec(N, argv[i]); if (N->err) goto err; } } else if ((c == 'f') || (c == 'F')) { if (++i < argc) { preppath(N, argv[i]); set_console_title(N); if (preload) do_preload(N); fn=argv[i]; nsp_execfile(N, fn); if (N->err) goto err; } } else if ((c == 'v') || (c == 'V')) { printf(NSP_VERSION "\r\n"); return 0; } else { do_help(argv[0]); return -1; } } else { preppath(N, argv[i]); set_console_title(N); if (preload) do_preload(N); fn=argv[i]; nsp_execfile(N, fn); if (N->err) goto err; } } err: if (N->err) printf("%s\r\n", N->errbuf); nsp_freestate(N); if (intstatus || N->allocs != N->frees) printstate(N, fn); nsp_endstate(N); return 0; }