[Python-checkins] CVS: python/dist/src/Modules posixmodule.c,2.144,2.145
Fredrik Lundh
python-dev@python.org
Sun, 9 Jul 2000 07:49:53 -0700
- Previous message: [Python-checkins] CVS: python/dist/src acconfig.h,1.32,1.33 config.h.in,2.61,2.62 configure,1.124,1.125 configure.in,1.133,1.134
- Next message: [Python-checkins] CVS: python/dist/src/Modules socketmodule.c,1.114,1.115
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/python/python/dist/src/Modules
In directory slayer.i.sourceforge.net:/tmp/cvs-serv7152/Modules
Modified Files:
posixmodule.c
Log Message:
- improved os.popen support for windows, based on win32pipe
by Bill Tutt.
note: to run this on Windows 95/98, you need to have the
w9xpopen.exe helper in the same directory as the python DLL.
Index: posixmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v
retrieving revision 2.144
retrieving revision 2.145
diff -C2 -r2.144 -r2.145
*** posixmodule.c 2000/07/09 13:10:40 2.144
--- posixmodule.c 2000/07/09 14:49:51 2.145
***************
*** 223,226 ****
--- 223,227 ----
#include <io.h>
#include <process.h>
+ #define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#ifdef MS_WIN32
***************
*** 354,357 ****
--- 355,370 ----
}
+ #ifdef MS_WIN32
+ static PyObject *
+ win32_error(char* function, char* filename)
+ {
+ /* XXX this could be improved */
+ errno = GetLastError();
+ if (filename)
+ return PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+ else
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ #endif
#if defined(PYOS_OS2)
***************
*** 846,850 ****
if (errno == ERROR_FILE_NOT_FOUND)
return PyList_New(0);
! return posix_error_with_filename(name);
}
do {
--- 859,863 ----
if (errno == ERROR_FILE_NOT_FOUND)
return PyList_New(0);
! return win32_error("FindFirstFile", name);
}
do {
***************
*** 869,876 ****
} while (FindNextFile(hFindFile, &FileData) == TRUE);
! if (FindClose(hFindFile) == FALSE) {
! errno = GetLastError();
! return posix_error_with_filename(name);
! }
return d;
--- 882,887 ----
} while (FindNextFile(hFindFile, &FileData) == TRUE);
! if (FindClose(hFindFile) == FALSE)
! return win32_error("FindClose", name);
return d;
***************
*** 2109,2112 ****
--- 2120,2563 ----
}
+ #elif defined(MS_WIN32)
+
+ /*
+ * Portable 'popen' replacement for Win32.
+ *
+ * Written by Bill Tutt <billtut@microsoft.com>. Minor tweaks
+ * and 2.0 integration by Fredrik Lundh <fredrik@pythonware.com>
+ */
+
+ #include <malloc.h>
+ #include <io.h>
+ #include <fcntl.h>
+
+ /* These tell _PyPopen() wether to return 1, 2, or 3 file objects. */
+ #define POPEN_1 1
+ #define POPEN_2 2
+ #define POPEN_3 3
+ #define POPEN_4 4
+
+ static PyObject *_PyPopen(char *, int, int);
+
+ /* popen that works from a GUI.
+ *
+ * The result of this function is a pipe (file) connected to the
+ * processes stdin or stdout, depending on the requested mode.
+ */
+
+ static PyObject *
+ posix_popen(PyObject *self, PyObject *args)
+ {
+ int bufsize = -1;
+ PyObject *f, *s;
+ int tm = 0;
+
+ char *cmdstring;
+ char *mode = "r";
+ if (!PyArg_ParseTuple(args, "s|s:popen", &cmdstring, &mode))
+ return NULL;
+
+ s = PyTuple_New(0);
+
+ if (*mode == 'r')
+ tm = _O_RDONLY;
+ else if (*mode != 'w') {
+ PyErr_SetString(PyExc_ValueError, "mode must be 'r' or 'w'");
+ return NULL;
+ } else
+ tm = _O_WRONLY;
+
+ if (*(mode+1) == 't')
+ f = _PyPopen(cmdstring, tm | _O_TEXT , POPEN_1);
+ else if (*(mode+1) == 'b')
+ f = _PyPopen(cmdstring, tm | _O_BINARY , POPEN_1);
+ else
+ f = _PyPopen(cmdstring, tm | _O_TEXT, POPEN_1);
+
+ return f;
+ }
+
+ /* Variation on win32pipe.popen
+ *
+ * The result of this function is a pipe (file) connected to the
+ * process's stdin, and a pipe connected to the process's stdout.
+ */
+
+ static PyObject *
+ win32_popen2(PyObject *self, PyObject *args)
+ {
+ PyObject *f;
+ int tm=0;
+
+ char *cmdstring;
+ char *mode = "t";
+ if (!PyArg_ParseTuple(args, "s|s:popen2", &cmdstring, &mode))
+ return NULL;
+
+ if (*mode == 't')
+ tm = _O_TEXT;
+ else if (*mode != 'b') {
+ PyErr_SetString(PyExc_ValueError, "mode must be 't' or 'b'");
+ return NULL;
+ } else
+ tm = _O_BINARY;
+
+ f = _PyPopen(cmdstring, tm , POPEN_2);
+
+ return f;
+ }
+
+ /*
+ * Variation on <om win32pipe.popen>
+ * The result of this function is 3 pipes - the process's stdin,
+ * stdout and stderr
+ *
+ */
+
+ static PyObject *
+ win32_popen3(PyObject *self, PyObject *args)
+ {
+ PyObject *f;
+ int tm = 0;
+
+ char *cmdstring;
+ char *mode = "t";
+ if (!PyArg_ParseTuple(args, "s|s:Popen3", &cmdstring, &mode))
+ return NULL;
+
+ if (*mode == 't')
+ tm = _O_TEXT;
+ else if (*mode != 'b') {
+ PyErr_SetString(PyExc_ValueError, "mode must be 't' or 'b'");
+ return NULL;
+ } else
+ tm = _O_BINARY;
+
+ f = _PyPopen(cmdstring, tm, POPEN_3);
+
+ return f;
+ }
+
+ /*
+ * Variation on win32pipe.popen
+ *
+ * The result of this function is 2 pipes - the processes stdin,
+ * and stdout+stderr combined as a single pipe.
+ */
+
+ static PyObject *
+ win32_popen4(PyObject *self, PyObject *args)
+ {
+ PyObject *f;
+ int tm = 0;
+
+ char *cmdstring;
+ char *mode = "t";
+ if (!PyArg_ParseTuple(args, "s|s:popen4", &cmdstring, &mode))
+ return NULL;
+
+ if (*mode == 't')
+ tm = _O_TEXT;
+ else if (*mode != 'b') {
+ PyErr_SetString(PyExc_ValueError, "mode must be 't' or 'b'");
+ return NULL;
+ } else
+ tm = _O_BINARY;
+
+ f = _PyPopen(cmdstring, tm , POPEN_4);
+
+ return f;
+ }
+
+ static int
+ _PyPopenCreateProcess(char *cmdstring,
+ HANDLE hStdin,
+ HANDLE hStdout,
+ HANDLE hStderr)
+ {
+ PROCESS_INFORMATION piProcInfo;
+ STARTUPINFO siStartInfo;
+ char *s1,*s2, *s3 = " /c ";
+ const char *szConsoleSpawn = "w9xpopen.exe \"";
+ int i;
+ int x;
+
+ if (i = GetEnvironmentVariable("COMSPEC",NULL,0)) {
+ s1 = (char *)_alloca(i);
+ if (!(x = GetEnvironmentVariable("COMSPEC", s1, i)))
+ return x;
+ if (GetVersion() < 0x80000000) {
+ /*
+ * NT/2000
+ */
+ x = i + strlen(s3) + strlen(cmdstring) + 1;
+ s2 = (char *)_alloca(x);
+ ZeroMemory(s2, x);
+ sprintf(s2, "%s%s%s", s1, s3, cmdstring);
+ }
+ else {
+ /*
+ * Oh gag, we're on Win9x. Use the workaround listed in
+ * KB: Q150956
+ */
+ char modulepath[256];
+ GetModuleFileName(NULL, modulepath, sizeof(modulepath));
+ for (i = x = 0; modulepath[i]; i++)
+ if (modulepath[i] == '\\')
+ x = i+1;
+ modulepath[x] = '\0';
+ x = i + strlen(s3) + strlen(cmdstring) + 1 +
+ strlen(modulepath) +
+ strlen(szConsoleSpawn) + 1;
+ s2 = (char *)_alloca(x);
+ ZeroMemory(s2, x);
+ sprintf(
+ s2,
+ "%s%s%s%s%s\"",
+ modulepath,
+ szConsoleSpawn,
+ s1,
+ s3,
+ cmdstring);
+ }
+ }
+
+ /* Could be an else here to try cmd.exe / command.com in the path
+ Now we'll just error out.. */
+ else
+ return -1;
+
+ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
+ siStartInfo.cb = sizeof(STARTUPINFO);
+ siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ siStartInfo.hStdInput = hStdin;
+ siStartInfo.hStdOutput = hStdout;
+ siStartInfo.hStdError = hStderr;
+ siStartInfo.wShowWindow = SW_HIDE;
+
+ if (CreateProcess(NULL,
+ s2,
+ NULL,
+ NULL,
+ TRUE,
+ CREATE_NEW_CONSOLE,
+ NULL,
+ NULL,
+ &siStartInfo,
+ &piProcInfo) ) {
+ /* Close the handles now so anyone waiting is woken. */
+ CloseHandle(piProcInfo.hProcess);
+ CloseHandle(piProcInfo.hThread);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ /* The following code is based off of KB: Q190351 */
+
+ static PyObject *
+ _PyPopen(char *cmdstring, int mode, int n)
+ {
+ HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr,
+ hChildStderrRd, hChildStderrWr, hChildStdinWrDup, hChildStdoutRdDup,
+ hChildStderrRdDup; /* hChildStdoutWrDup; */
+
+ SECURITY_ATTRIBUTES saAttr;
+ BOOL fSuccess;
+ int fd1, fd2, fd3;
+ FILE *f1, *f2, *f3;
+ PyObject *f;
+
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
+ return win32_error("CreatePipe", NULL);
+
+ /* Create new output read handle and the input write handle. Set
+ * the inheritance properties to FALSE. Otherwise, the child inherits
+ * the these handles; resulting in non-closeable handles to the pipes
+ * being created. */
+ fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
+ GetCurrentProcess(), &hChildStdinWrDup, 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ if (!fSuccess)
+ return win32_error("DuplicateHandle", NULL);
+
+ /* Close the inheritable version of ChildStdin
+ that we're using. */
+ CloseHandle(hChildStdinWr);
+
+ if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
+ return win32_error("CreatePipe", NULL);
+
+ fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
+ GetCurrentProcess(), &hChildStdoutRdDup, 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ if (!fSuccess)
+ return win32_error("DuplicateHandle", NULL);
+
+ /* Close the inheritable version of ChildStdout
+ that we're using. */
+ CloseHandle(hChildStdoutRd);
+
+ if (n != POPEN_4) {
+ if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0))
+ return win32_error("CreatePipe", NULL);
+ fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStderrRd,
+ GetCurrentProcess(), &hChildStderrRdDup, 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ if (!fSuccess)
+ return win32_error("DuplicateHandle", NULL);
+ /* Close the inheritable version of ChildStdErr that we're using. */
+ CloseHandle(hChildStderrRd);
+ }
+
+ switch (n) {
+ case POPEN_1:
+ switch (mode & (_O_RDONLY | _O_TEXT | _O_BINARY | _O_WRONLY)) {
+ case _O_WRONLY | _O_TEXT:
+ /* Case for writing to child Stdin in text mode. */
+ fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
+ f1 = _fdopen(fd1, "w");
+ f = PyFile_FromFile(f1, cmdstring, "w", fclose);
+ PyFile_SetBufSize(f, 0);
+ /* We don't care about these pipes anymore, so close them. */
+ CloseHandle(hChildStdoutRdDup);
+ CloseHandle(hChildStderrRdDup);
+ break;
+
+ case _O_RDONLY | _O_TEXT:
+ /* Case for reading from child Stdout in text mode. */
+ fd1 = _open_osfhandle((long)hChildStdoutRdDup, mode);
+ f1 = _fdopen(fd1, "r");
+ f = PyFile_FromFile(f1, cmdstring, "r", fclose);
+ PyFile_SetBufSize(f, 0);
+ /* We don't care about these pipes anymore, so close them. */
+ CloseHandle(hChildStdinWrDup);
+ CloseHandle(hChildStderrRdDup);
+ break;
+
+ case _O_RDONLY | _O_BINARY:
+ /* Case for readinig from child Stdout in binary mode. */
+ fd1 = _open_osfhandle((long)hChildStdoutRdDup, mode);
+ f1 = _fdopen(fd1, "rb");
+ f = PyFile_FromFile(f1, cmdstring, "rb", fclose);
+ PyFile_SetBufSize(f, 0);
+ /* We don't care about these pipes anymore, so close them. */
+ CloseHandle(hChildStdinWrDup);
+ CloseHandle(hChildStderrRdDup);
+ break;
+
+ case _O_WRONLY | _O_BINARY:
+ /* Case for writing to child Stdin in binary mode. */
+ fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
+ f1 = _fdopen(fd1, "wb");
+ f = PyFile_FromFile(f1, cmdstring, "wb", fclose);
+ PyFile_SetBufSize(f, 0);
+ /* We don't care about these pipes anymore, so close them. */
+ CloseHandle(hChildStdoutRdDup);
+ CloseHandle(hChildStderrRdDup);
+ break;
+ }
+ break;
+
+ case POPEN_2:
+ case POPEN_4:
+ {
+ char *m1, *m2;
+ PyObject *p1, *p2;
+
+ if (mode && _O_TEXT) {
+ m1 = "r";
+ m2 = "w";
+ } else {
+ m1 = "rb";
+ m2 = "wb";
+ }
+
+ fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
+ f1 = _fdopen(fd1, m2);
+ fd2 = _open_osfhandle((long)hChildStdoutRdDup, mode);
+ f2 = _fdopen(fd2, m1);
+ p1 = PyFile_FromFile(f1, cmdstring, m2, fclose);
+ PyFile_SetBufSize(p1, 0);
+ p2 = PyFile_FromFile(f2, cmdstring, m1, fclose);
+ PyFile_SetBufSize(p2, 0);
+
+ if (n != 4)
+ CloseHandle(hChildStderrRdDup);
+
+ f = Py_BuildValue("OO",p1,p2);
+ break;
+ }
+
+ case POPEN_3:
+ {
+ char *m1, *m2;
+ PyObject *p1, *p2, *p3;
+
+ if (mode && _O_TEXT) {
+ m1 = "r";
+ m2 = "w";
+ } else {
+ m1 = "rb";
+ m2 = "wb";
+ }
+
+ fd1 = _open_osfhandle((long)hChildStdinWrDup, mode);
+ f1 = _fdopen(fd1, m2);
+ fd2 = _open_osfhandle((long)hChildStdoutRdDup, mode);
+ f2 = _fdopen(fd2, m1);
+ fd3 = _open_osfhandle((long)hChildStderrRdDup, mode);
+ f3 = _fdopen(fd3, m1);
+ p1 = PyFile_FromFile(f1, cmdstring, m2, fclose);
+ p2 = PyFile_FromFile(f2, cmdstring, m1, fclose);
+ p3 = PyFile_FromFile(f3, cmdstring, m1, fclose);
+ PyFile_SetBufSize(p1, 0);
+ PyFile_SetBufSize(p2, 0);
+ PyFile_SetBufSize(p3, 0);
+ f = Py_BuildValue("OOO",p1,p2,p3);
+ break;
+ }
+ }
+
+ if (n == POPEN_4) {
+ if (!_PyPopenCreateProcess(cmdstring,
+ hChildStdinRd,
+ hChildStdoutWr,
+ hChildStdoutWr))
+ return win32_error("CreateProcess", NULL);
+ }
+ else {
+ if (!_PyPopenCreateProcess(cmdstring,
+ hChildStdinRd,
+ hChildStdoutWr,
+ hChildStderrWr))
+ return win32_error("CreateProcess", NULL);
+ }
+
+ /* Child is launched. Close the parents copy of those pipe
+ * handles that only the child should have open. You need to
+ * make sure that no handles to the write end of the output pipe
+ * are maintained in this process or else the pipe will not close
+ * when the child process exits and the ReadFile will hang. */
+
+ if (!CloseHandle(hChildStdinRd))
+ return win32_error("CloseHandle", NULL);
+
+ if (!CloseHandle(hChildStdoutWr))
+ return win32_error("CloseHandle", NULL);
+
+ if ((n != 4) && (!CloseHandle(hChildStderrWr)))
+ return win32_error("CloseHandle", NULL);
+
+ return f;
+ }
#else
static PyObject *
***************
*** 2729,2733 ****
Py_END_ALLOW_THREADS
if (!ok)
! return posix_error();
read_fd = _open_osfhandle((intptr_t)read, 0);
write_fd = _open_osfhandle((intptr_t)write, 1);
--- 3180,3184 ----
Py_END_ALLOW_THREADS
if (!ok)
! return win32_error("CreatePipe", NULL);
read_fd = _open_osfhandle((intptr_t)read, 0);
write_fd = _open_osfhandle((intptr_t)write, 1);
***************
*** 4424,4427 ****
--- 4875,4883 ----
#ifdef HAVE_POPEN
{"popen", posix_popen, METH_VARARGS, posix_popen__doc__},
+ #ifdef MS_WIN32
+ {"popen2", win32_popen2, METH_VARARGS},
+ {"popen3", win32_popen3, METH_VARARGS},
+ {"popen4", win32_popen4, METH_VARARGS},
+ #endif
#endif /* HAVE_POPEN */
#ifdef HAVE_SETUID
- Previous message: [Python-checkins] CVS: python/dist/src acconfig.h,1.32,1.33 config.h.in,2.61,2.62 configure,1.124,1.125 configure.in,1.133,1.134
- Next message: [Python-checkins] CVS: python/dist/src/Modules socketmodule.c,1.114,1.115
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]