posixmodule.c revision 3886bb6997f8f7b0b64eed19045161e697f415fe
1/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
16
17While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
29
30******************************************************************/
31
32/* POSIX module implementation */
33
34/* This file is also used for Windows NT and MS-Win.  In that case the module
35   actually calls itself 'nt', not 'posix', and a few functions are
36   either unimplemented or implemented differently.  The source
37   assumes that for Windows NT, the macro 'MS_WIN32' is defined independent
38   of the compiler used.  Different compilers define their own feature
39   test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */
40
41/* See also ../Dos/dosmodule.c */
42
43static char posix__doc__ [] =
44"This module provides access to operating system functionality that is\n\
45standardized by the C Standard and the POSIX standard (a thinly\n\
46disguised Unix interface).  Refer to the library manual and\n\
47corresponding Unix manual entries for more information on calls.";
48
49#include "Python.h"
50
51#if defined(PYOS_OS2)
52#define  INCL_DOS
53#define  INCL_DOSERRORS
54#define  INCL_DOSPROCESS
55#define  INCL_NOPMAPI
56#include <os2.h>
57#endif
58
59#include <sys/types.h>
60#include <sys/stat.h>
61#ifdef HAVE_SYS_WAIT_H
62#include <sys/wait.h>		/* For WNOHANG */
63#endif
64
65#ifdef HAVE_SIGNAL_H
66#include <signal.h>
67#endif
68
69#include "mytime.h"		/* For clock_t on some systems */
70
71#ifdef HAVE_FCNTL_H
72#include <fcntl.h>
73#endif /* HAVE_FCNTL_H */
74
75/* Various compilers have only certain posix functions */
76/* XXX Gosh I wish these were all moved into config.h */
77#if defined(PYCC_VACPP) && defined(PYOS_OS2)
78#include <process.h>
79#else
80#if defined(__WATCOMC__) && !defined(__QNX__)		/* Watcom compiler */
81#define HAVE_GETCWD     1
82#define HAVE_OPENDIR    1
83#define HAVE_SYSTEM	1
84#if defined(__OS2__)
85#define HAVE_EXECV      1
86#define HAVE_WAIT       1
87#endif
88#include <process.h>
89#else
90#ifdef __BORLANDC__		/* Borland compiler */
91#define HAVE_EXECV      1
92#define HAVE_GETCWD     1
93#define HAVE_GETEGID    1
94#define HAVE_GETEUID    1
95#define HAVE_GETGID     1
96#define HAVE_GETPPID    1
97#define HAVE_GETUID     1
98#define HAVE_KILL       1
99#define HAVE_OPENDIR    1
100#define HAVE_PIPE       1
101#define HAVE_POPEN      1
102#define HAVE_SYSTEM	1
103#define HAVE_WAIT       1
104#else
105#ifdef _MSC_VER		/* Microsoft compiler */
106#define HAVE_GETCWD     1
107#ifdef MS_WIN32
108#define HAVE_EXECV      1
109#define HAVE_PIPE       1
110#define HAVE_POPEN      1
111#define HAVE_SYSTEM	1
112#else /* 16-bit Windows */
113#endif /* !MS_WIN32 */
114#else			/* all other compilers */
115/* Unix functions that the configure script doesn't check for */
116#define HAVE_EXECV      1
117#define HAVE_FORK       1
118#define HAVE_GETCWD     1
119#define HAVE_GETEGID    1
120#define HAVE_GETEUID    1
121#define HAVE_GETGID     1
122#define HAVE_GETPPID    1
123#define HAVE_GETUID     1
124#define HAVE_KILL       1
125#define HAVE_OPENDIR    1
126#define HAVE_PIPE       1
127#define HAVE_POPEN      1
128#define HAVE_SYSTEM	1
129#define HAVE_WAIT       1
130#endif  /* _MSC_VER */
131#endif  /* __BORLANDC__ */
132#endif  /* ! __WATCOMC__ || __QNX__ */
133#endif /* ! __IBMC__ */
134
135#ifndef _MSC_VER
136
137#ifdef HAVE_UNISTD_H
138#include <unistd.h>
139#endif
140
141#ifdef NeXT
142/* NeXT's <unistd.h> and <utime.h> aren't worth much */
143#undef HAVE_UNISTD_H
144#undef HAVE_UTIME_H
145#define HAVE_WAITPID
146/* #undef HAVE_GETCWD */
147#endif
148
149#ifdef HAVE_UNISTD_H
150/* XXX These are for SunOS4.1.3 but shouldn't hurt elsewhere */
151extern int rename();
152extern int pclose();
153extern int lstat();
154extern int symlink();
155#else /* !HAVE_UNISTD_H */
156#if defined(PYCC_VACPP)
157extern int mkdir Py_PROTO((char *));
158#else
159#if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__)
160extern int mkdir Py_PROTO((const char *));
161#else
162extern int mkdir Py_PROTO((const char *, mode_t));
163#endif
164#endif
165#if defined(__IBMC__) || defined(__IBMCPP__)
166extern int chdir Py_PROTO((char *));
167extern int rmdir Py_PROTO((char *));
168#else
169extern int chdir Py_PROTO((const char *));
170extern int rmdir Py_PROTO((const char *));
171#endif
172extern int chmod Py_PROTO((const char *, mode_t));
173extern int chown Py_PROTO((const char *, uid_t, gid_t));
174extern char *getcwd Py_PROTO((char *, int));
175extern char *strerror Py_PROTO((int));
176extern int link Py_PROTO((const char *, const char *));
177extern int rename Py_PROTO((const char *, const char *));
178extern int stat Py_PROTO((const char *, struct stat *));
179extern int unlink Py_PROTO((const char *));
180extern int pclose Py_PROTO((FILE *));
181#ifdef HAVE_SYMLINK
182extern int symlink Py_PROTO((const char *, const char *));
183#endif /* HAVE_SYMLINK */
184#ifdef HAVE_LSTAT
185extern int lstat Py_PROTO((const char *, struct stat *));
186#endif /* HAVE_LSTAT */
187#endif /* !HAVE_UNISTD_H */
188
189#endif /* !_MSC_VER */
190
191#ifdef HAVE_UTIME_H
192#include <utime.h>
193#endif /* HAVE_UTIME_H */
194
195#ifdef HAVE_SYS_UTIME_H
196#include <sys/utime.h>
197#define HAVE_UTIME_H /* pretend we do for the rest of this file */
198#endif /* HAVE_SYS_UTIME_H */
199
200#ifdef HAVE_SYS_TIMES_H
201#include <sys/times.h>
202#endif /* HAVE_SYS_TIMES_H */
203
204#ifdef HAVE_SYS_PARAM_H
205#include <sys/param.h>
206#endif /* HAVE_SYS_PARAM_H */
207
208#ifdef HAVE_SYS_UTSNAME_H
209#include <sys/utsname.h>
210#endif /* HAVE_SYS_UTSNAME_H */
211
212#ifndef MAXPATHLEN
213#define MAXPATHLEN 1024
214#endif /* MAXPATHLEN */
215
216#ifdef HAVE_DIRENT_H
217#include <dirent.h>
218#define NAMLEN(dirent) strlen((dirent)->d_name)
219#else
220#if defined(__WATCOMC__) && !defined(__QNX__)
221#include <direct.h>
222#define NAMLEN(dirent) strlen((dirent)->d_name)
223#else
224#define dirent direct
225#define NAMLEN(dirent) (dirent)->d_namlen
226#endif
227#ifdef HAVE_SYS_NDIR_H
228#include <sys/ndir.h>
229#endif
230#ifdef HAVE_SYS_DIR_H
231#include <sys/dir.h>
232#endif
233#ifdef HAVE_NDIR_H
234#include <ndir.h>
235#endif
236#endif
237
238#ifdef _MSC_VER
239#include <direct.h>
240#include <io.h>
241#include <process.h>
242#include <windows.h>
243#ifdef MS_WIN32
244#define popen	_popen
245#define pclose	_pclose
246#else /* 16-bit Windows */
247#include <dos.h>
248#include <ctype.h>
249#endif /* MS_WIN32 */
250#endif /* _MSC_VER */
251
252#if defined(PYCC_VACPP) && defined(PYOS_OS2)
253#include <io.h>
254#endif /* OS2 */
255
256/* Return a dictionary corresponding to the POSIX environment table */
257
258#if !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) )
259extern char **environ;
260#endif /* !_MSC_VER */
261
262static PyObject *
263convertenviron()
264{
265	PyObject *d;
266	char **e;
267	d = PyDict_New();
268	if (d == NULL)
269		return NULL;
270	if (environ == NULL)
271		return d;
272	/* XXX This part ignores errors */
273	for (e = environ; *e != NULL; e++) {
274		PyObject *v;
275		char *p = strchr(*e, '=');
276		if (p == NULL)
277			continue;
278		v = PyString_FromString(p+1);
279		if (v == NULL)
280			continue;
281		*p = '\0';
282		(void) PyDict_SetItemString(d, *e, v);
283		*p = '=';
284		Py_DECREF(v);
285	}
286#if defined(PYOS_OS2)
287    {
288        APIRET rc;
289        char   buffer[1024]; /* OS/2 Provides a Documented Max of 1024 Chars */
290
291        rc = DosQueryExtLIBPATH(buffer, BEGIN_LIBPATH);
292        if (rc == NO_ERROR) { /* (not a type, envname is NOT 'BEGIN_LIBPATH') */
293            PyObject *v = PyString_FromString(buffer);
294		    PyDict_SetItemString(d, "BEGINLIBPATH", v);
295            Py_DECREF(v);
296        }
297        rc = DosQueryExtLIBPATH(buffer, END_LIBPATH);
298        if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'END_LIBPATH') */
299            PyObject *v = PyString_FromString(buffer);
300		    PyDict_SetItemString(d, "ENDLIBPATH", v);
301            Py_DECREF(v);
302        }
303    }
304#endif
305	return d;
306}
307
308
309static PyObject *PosixError; /* Exception posix.error */
310
311/* Set a POSIX-specific error from errno, and return NULL */
312
313static PyObject *
314posix_error()
315{
316	return PyErr_SetFromErrno(PosixError);
317}
318static PyObject *
319posix_error_with_filename(name)
320	char* name;
321{
322	return PyErr_SetFromErrnoWithFilename(PosixError, name);
323}
324
325
326#if defined(PYOS_OS2)
327/**********************************************************************
328 *         Helper Function to Trim and Format OS/2 Messages
329 **********************************************************************/
330    static void
331os2_formatmsg(char *msgbuf, int msglen, char *reason)
332{
333    msgbuf[msglen] = '\0'; /* OS/2 Doesn't Guarantee a Terminator */
334
335    if (strlen(msgbuf) > 0) { /* If Non-Empty Msg, Trim CRLF */
336        char *lastc = &msgbuf[ strlen(msgbuf)-1 ];
337
338        while (lastc > msgbuf && isspace(*lastc))
339            *lastc-- = '\0'; /* Trim Trailing Whitespace (CRLF) */
340    }
341
342    /* Add Optional Reason Text */
343    if (reason) {
344        strcat(msgbuf, " : ");
345        strcat(msgbuf, reason);
346    }
347}
348
349/**********************************************************************
350 *             Decode an OS/2 Operating System Error Code
351 *
352 * A convenience function to lookup an OS/2 error code and return a
353 * text message we can use to raise a Python exception.
354 *
355 * Notes:
356 *   The messages for errors returned from the OS/2 kernel reside in
357 *   the file OSO001.MSG in the \OS2 directory hierarchy.
358 *
359 **********************************************************************/
360    static char *
361os2_strerror(char *msgbuf, int msgbuflen, int errorcode, char *reason)
362{
363    APIRET rc;
364    ULONG  msglen;
365
366    /* Retrieve Kernel-Related Error Message from OSO001.MSG File */
367    Py_BEGIN_ALLOW_THREADS
368    rc = DosGetMessage(NULL, 0, msgbuf, msgbuflen,
369                       errorcode, "oso001.msg", &msglen);
370    Py_END_ALLOW_THREADS
371
372    if (rc == NO_ERROR)
373        os2_formatmsg(msgbuf, msglen, reason);
374    else
375        sprintf(msgbuf, "unknown OS error #%d", errorcode);
376
377    return msgbuf;
378}
379
380/* Set an OS/2-specific error and return NULL.  OS/2 kernel
381   errors are not in a global variable e.g. 'errno' nor are
382   they congruent with posix error numbers. */
383
384static PyObject * os2_error(int code)
385{
386    char text[1024];
387    PyObject *v;
388
389    os2_strerror(text, sizeof(text), code, "");
390
391    v = Py_BuildValue("(is)", code, text);
392    if (v != NULL) {
393        PyErr_SetObject(PosixError, v);
394        Py_DECREF(v);
395    }
396    return NULL; /* Signal to Python that an Exception is Pending */
397}
398
399#endif /* OS2 */
400
401/* POSIX generic methods */
402
403static PyObject *
404posix_1str(args, func)
405	PyObject *args;
406	int (*func) Py_FPROTO((const char *));
407{
408	char *path1;
409	int res;
410	if (!PyArg_Parse(args, "s", &path1))
411		return NULL;
412	Py_BEGIN_ALLOW_THREADS
413	res = (*func)(path1);
414	Py_END_ALLOW_THREADS
415	if (res < 0)
416		return posix_error_with_filename(path1);
417	Py_INCREF(Py_None);
418	return Py_None;
419}
420
421static PyObject *
422posix_2str(args, func)
423	PyObject *args;
424	int (*func) Py_FPROTO((const char *, const char *));
425{
426	char *path1, *path2;
427	int res;
428	if (!PyArg_Parse(args, "(ss)", &path1, &path2))
429		return NULL;
430	Py_BEGIN_ALLOW_THREADS
431	res = (*func)(path1, path2);
432	Py_END_ALLOW_THREADS
433	if (res != 0)
434		/* XXX how to report both path1 and path2??? */
435		return posix_error();
436	Py_INCREF(Py_None);
437	return Py_None;
438}
439
440static PyObject *
441posix_strint(args, func)
442	PyObject *args;
443	int (*func) Py_FPROTO((const char *, int));
444{
445	char *path;
446	int i;
447	int res;
448	if (!PyArg_Parse(args, "(si)", &path, &i))
449		return NULL;
450	Py_BEGIN_ALLOW_THREADS
451	res = (*func)(path, i);
452	Py_END_ALLOW_THREADS
453	if (res < 0)
454		return posix_error_with_filename(path);
455	Py_INCREF(Py_None);
456	return Py_None;
457}
458
459static PyObject *
460posix_strintint(args, func)
461	PyObject *args;
462	int (*func) Py_FPROTO((const char *, int, int));
463{
464	char *path;
465	int i,i2;
466	int res;
467	if (!PyArg_Parse(args, "(sii)", &path, &i, &i2))
468		return NULL;
469	Py_BEGIN_ALLOW_THREADS
470	res = (*func)(path, i, i2);
471	Py_END_ALLOW_THREADS
472	if (res < 0)
473		return posix_error_with_filename(path);
474	Py_INCREF(Py_None);
475	return Py_None;
476}
477
478static PyObject *
479posix_do_stat(self, args, statfunc)
480	PyObject *self;
481	PyObject *args;
482	int (*statfunc) Py_FPROTO((const char *, struct stat *));
483{
484	struct stat st;
485	char *path;
486	int res;
487	if (!PyArg_Parse(args, "s", &path))
488		return NULL;
489	Py_BEGIN_ALLOW_THREADS
490	res = (*statfunc)(path, &st);
491	Py_END_ALLOW_THREADS
492	if (res != 0)
493		return posix_error_with_filename(path);
494	return Py_BuildValue("(llllllllll)",
495		    (long)st.st_mode,
496		    (long)st.st_ino,
497		    (long)st.st_dev,
498		    (long)st.st_nlink,
499		    (long)st.st_uid,
500		    (long)st.st_gid,
501		    (long)st.st_size,
502		    (long)st.st_atime,
503		    (long)st.st_mtime,
504		    (long)st.st_ctime);
505}
506
507
508/* POSIX methods */
509
510static char posix_chdir__doc__[] =
511"chdir(path) -> None\n\
512Change the current working directory to the specified path.";
513
514static PyObject *
515posix_chdir(self, args)
516	PyObject *self;
517	PyObject *args;
518{
519	return posix_1str(args, chdir);
520}
521
522
523static char posix_chmod__doc__[] =
524"chmod(path, mode) -> None\n\
525Change the access permissions of a file.";
526
527static PyObject *
528posix_chmod(self, args)
529	PyObject *self;
530	PyObject *args;
531{
532	return posix_strint(args, chmod);
533}
534
535
536#ifdef HAVE_CHOWN
537static char posix_chown__doc__[] =
538"chown(path, uid, gid) -> None\n\
539Change the owner and group id of path to the numeric uid and gid.";
540
541static PyObject *
542posix_chown(self, args)
543	PyObject *self;
544	PyObject *args;
545{
546	return posix_strintint(args, chown);
547}
548#endif /* HAVE_CHOWN */
549
550
551#ifdef HAVE_GETCWD
552static char posix_getcwd__doc__[] =
553"getcwd() -> path\n\
554Return a string representing the current working directory.";
555
556static PyObject *
557posix_getcwd(self, args)
558	PyObject *self;
559	PyObject *args;
560{
561	char buf[1026];
562	char *res;
563	if (!PyArg_NoArgs(args))
564		return NULL;
565	Py_BEGIN_ALLOW_THREADS
566	res = getcwd(buf, sizeof buf);
567	Py_END_ALLOW_THREADS
568	if (res == NULL)
569		return posix_error();
570	return PyString_FromString(buf);
571}
572#endif
573
574
575#ifdef HAVE_LINK
576static char posix_link__doc__[] =
577"link(src, dst) -> None\n\
578Create a hard link to a file.";
579
580static PyObject *
581posix_link(self, args)
582	PyObject *self;
583	PyObject *args;
584{
585	return posix_2str(args, link);
586}
587#endif /* HAVE_LINK */
588
589
590static char posix_listdir__doc__[] =
591"listdir(path) -> list_of_strings\n\
592Return a list containing the names of the entries in the directory.\n\
593\n\
594	path: path of directory to list\n\
595\n\
596The list is in arbitrary order.  It does not include the special\n\
597entries '.' and '..' even if they are present in the directory.";
598
599static PyObject *
600posix_listdir(self, args)
601	PyObject *self;
602	PyObject *args;
603{
604	/* XXX Should redo this putting the (now four) versions of opendir
605	   in separate files instead of having them all here... */
606#if defined(MS_WIN32) && !defined(HAVE_OPENDIR)
607
608	char *name;
609	int len;
610	PyObject *d, *v;
611	HANDLE hFindFile;
612	WIN32_FIND_DATA FileData;
613	char namebuf[MAX_PATH+5];
614
615	if (!PyArg_Parse(args, "t#", &name, &len))
616		return NULL;
617	if (len >= MAX_PATH) {
618		PyErr_SetString(PyExc_ValueError, "path too long");
619		return NULL;
620	}
621	strcpy(namebuf, name);
622	if (namebuf[len-1] != '/' && namebuf[len-1] != '\\')
623		namebuf[len++] = '/';
624	strcpy(namebuf + len, "*.*");
625
626	if ((d = PyList_New(0)) == NULL)
627		return NULL;
628
629	hFindFile = FindFirstFile(namebuf, &FileData);
630	if (hFindFile == INVALID_HANDLE_VALUE) {
631		errno = GetLastError();
632		if (errno == ERROR_FILE_NOT_FOUND)
633			return PyList_New(0);
634		return posix_error();
635	}
636	do {
637		if (FileData.cFileName[0] == '.' &&
638		    (FileData.cFileName[1] == '\0' ||
639		     FileData.cFileName[1] == '.' &&
640		     FileData.cFileName[2] == '\0'))
641			continue;
642		v = PyString_FromString(FileData.cFileName);
643		if (v == NULL) {
644			Py_DECREF(d);
645			d = NULL;
646			break;
647		}
648		if (PyList_Append(d, v) != 0) {
649			Py_DECREF(v);
650			Py_DECREF(d);
651			d = NULL;
652			break;
653		}
654		Py_DECREF(v);
655	} while (FindNextFile(hFindFile, &FileData) == TRUE);
656
657	if (FindClose(hFindFile) == FALSE) {
658		errno = GetLastError();
659		return posix_error();
660	}
661
662	return d;
663
664#else /* !MS_WIN32 */
665#ifdef _MSC_VER /* 16-bit Windows */
666
667#ifndef MAX_PATH
668#define MAX_PATH	250
669#endif
670	char *name, *pt;
671	int len;
672	PyObject *d, *v;
673	char namebuf[MAX_PATH+5];
674	struct _find_t ep;
675
676	if (!PyArg_Parse(args, "t#", &name, &len))
677		return NULL;
678	if (len >= MAX_PATH) {
679		PyErr_SetString(PyExc_ValueError, "path too long");
680		return NULL;
681	}
682	strcpy(namebuf, name);
683	for (pt = namebuf; *pt; pt++)
684		if (*pt == '/')
685			*pt = '\\';
686	if (namebuf[len-1] != '\\')
687		namebuf[len++] = '\\';
688	strcpy(namebuf + len, "*.*");
689
690	if ((d = PyList_New(0)) == NULL)
691		return NULL;
692
693	if (_dos_findfirst(namebuf, _A_RDONLY |
694			   _A_HIDDEN | _A_SYSTEM | _A_SUBDIR, &ep) != 0)
695        {
696		errno = ENOENT;
697		return posix_error();
698	}
699	do {
700		if (ep.name[0] == '.' &&
701		    (ep.name[1] == '\0' ||
702		     ep.name[1] == '.' &&
703		     ep.name[2] == '\0'))
704			continue;
705		strcpy(namebuf, ep.name);
706		for (pt = namebuf; *pt; pt++)
707			if (isupper(*pt))
708				*pt = tolower(*pt);
709		v = PyString_FromString(namebuf);
710		if (v == NULL) {
711			Py_DECREF(d);
712			d = NULL;
713			break;
714		}
715		if (PyList_Append(d, v) != 0) {
716			Py_DECREF(v);
717			Py_DECREF(d);
718			d = NULL;
719			break;
720		}
721		Py_DECREF(v);
722	} while (_dos_findnext(&ep) == 0);
723
724	return d;
725
726#else
727#if defined(PYOS_OS2)
728
729#ifndef MAX_PATH
730#define MAX_PATH    CCHMAXPATH
731#endif
732    char *name, *pt;
733    int len;
734    PyObject *d, *v;
735    char namebuf[MAX_PATH+5];
736    HDIR  hdir = 1;
737    ULONG srchcnt = 1;
738    FILEFINDBUF3   ep;
739    APIRET rc;
740
741	if (!PyArg_Parse(args, "t#", &name, &len))
742        return NULL;
743    if (len >= MAX_PATH) {
744		PyErr_SetString(PyExc_ValueError, "path too long");
745        return NULL;
746    }
747    strcpy(namebuf, name);
748    for (pt = namebuf; *pt; pt++)
749        if (*pt == '/')
750            *pt = '\\';
751    if (namebuf[len-1] != '\\')
752        namebuf[len++] = '\\';
753    strcpy(namebuf + len, "*.*");
754
755	if ((d = PyList_New(0)) == NULL)
756        return NULL;
757
758    rc = DosFindFirst(namebuf,         /* Wildcard Pattern to Match */
759                      &hdir,           /* Handle to Use While Search Directory */
760                      FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY,
761                      &ep, sizeof(ep), /* Structure to Receive Directory Entry */
762                      &srchcnt,        /* Max and Actual Count of Entries Per Iteration */
763                      FIL_STANDARD);   /* Format of Entry (EAs or Not) */
764
765    if (rc != NO_ERROR) {
766        errno = ENOENT;
767        return posix_error();
768    }
769
770    if (srchcnt > 0) { /* If Directory is NOT Totally Empty, */
771        do {
772            if (ep.achName[0] == '.'
773            && (ep.achName[1] == '\0' || ep.achName[1] == '.' && ep.achName[2] == '\0'))
774                continue; /* Skip Over "." and ".." Names */
775
776            strcpy(namebuf, ep.achName);
777
778            /* Leave Case of Name Alone -- In Native Form */
779            /* (Removed Forced Lowercasing Code) */
780
781            v = PyString_FromString(namebuf);
782            if (v == NULL) {
783                Py_DECREF(d);
784                d = NULL;
785                break;
786            }
787            if (PyList_Append(d, v) != 0) {
788                Py_DECREF(v);
789                Py_DECREF(d);
790                d = NULL;
791                break;
792            }
793            Py_DECREF(v);
794        } while (DosFindNext(hdir, &ep, sizeof(ep), &srchcnt) == NO_ERROR && srchcnt > 0);
795    }
796
797    return d;
798#else
799
800	char *name;
801	PyObject *d, *v;
802	DIR *dirp;
803	struct dirent *ep;
804	if (!PyArg_Parse(args, "s", &name))
805		return NULL;
806	Py_BEGIN_ALLOW_THREADS
807	if ((dirp = opendir(name)) == NULL) {
808		Py_BLOCK_THREADS
809		return posix_error();
810	}
811	if ((d = PyList_New(0)) == NULL) {
812		closedir(dirp);
813		Py_BLOCK_THREADS
814		return NULL;
815	}
816	while ((ep = readdir(dirp)) != NULL) {
817		if (ep->d_name[0] == '.' &&
818		    (NAMLEN(ep) == 1 ||
819		     (ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
820			continue;
821		v = PyString_FromStringAndSize(ep->d_name, NAMLEN(ep));
822		if (v == NULL) {
823			Py_DECREF(d);
824			d = NULL;
825			break;
826		}
827		if (PyList_Append(d, v) != 0) {
828			Py_DECREF(v);
829			Py_DECREF(d);
830			d = NULL;
831			break;
832		}
833		Py_DECREF(v);
834	}
835	closedir(dirp);
836	Py_END_ALLOW_THREADS
837
838	return d;
839
840#endif /* !PYOS_OS2 */
841#endif /* !_MSC_VER */
842#endif /* !MS_WIN32 */
843}
844
845static char posix_mkdir__doc__[] =
846"mkdir(path [, mode=0777]) -> None\n\
847Create a directory.";
848
849static PyObject *
850posix_mkdir(self, args)
851	PyObject *self;
852	PyObject *args;
853{
854	int res;
855	char *path;
856	int mode = 0777;
857	if (!PyArg_ParseTuple(args, "s|i", &path, &mode))
858		return NULL;
859	Py_BEGIN_ALLOW_THREADS
860#if ( defined(__WATCOMC__) || defined(_MSC_VER) || defined(PYCC_VACPP) ) && !defined(__QNX__)
861	res = mkdir(path);
862#else
863	res = mkdir(path, mode);
864#endif
865	Py_END_ALLOW_THREADS
866	if (res < 0)
867		return posix_error_with_filename(path);
868	Py_INCREF(Py_None);
869	return Py_None;
870}
871
872
873#ifdef HAVE_NICE
874static char posix_nice__doc__[] =
875"nice(inc) -> new_priority\n\
876Decrease the priority of process and return new priority.";
877
878static PyObject *
879posix_nice(self, args)
880	PyObject *self;
881	PyObject *args;
882{
883	int increment, value;
884
885	if (!PyArg_Parse(args, "i", &increment))
886		return NULL;
887	value = nice(increment);
888	if (value == -1)
889		return posix_error();
890	return PyInt_FromLong((long) value);
891}
892#endif /* HAVE_NICE */
893
894
895static char posix_rename__doc__[] =
896"rename(old, new) -> None\n\
897Rename a file or directory.";
898
899static PyObject *
900posix_rename(self, args)
901	PyObject *self;
902	PyObject *args;
903{
904	return posix_2str(args, rename);
905}
906
907
908static char posix_rmdir__doc__[] =
909"rmdir(path) -> None\n\
910Remove a directory.";
911
912static PyObject *
913posix_rmdir(self, args)
914	PyObject *self;
915	PyObject *args;
916{
917	return posix_1str(args, rmdir);
918}
919
920
921static char posix_stat__doc__[] =
922"stat(path) -> (mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime)\n\
923Perform a stat system call on the given path.";
924
925static PyObject *
926posix_stat(self, args)
927	PyObject *self;
928	PyObject *args;
929{
930	return posix_do_stat(self, args, stat);
931}
932
933
934#ifdef HAVE_SYSTEM
935static char posix_system__doc__[] =
936"system(command) -> exit_status\n\
937Execute the command (a string) in a subshell.";
938
939static PyObject *
940posix_system(self, args)
941	PyObject *self;
942	PyObject *args;
943{
944	char *command;
945	long sts;
946	if (!PyArg_Parse(args, "s", &command))
947		return NULL;
948	Py_BEGIN_ALLOW_THREADS
949	sts = system(command);
950	Py_END_ALLOW_THREADS
951	return PyInt_FromLong(sts);
952}
953#endif
954
955
956static char posix_umask__doc__[] =
957"umask(new_mask) -> old_mask\n\
958Set the current numeric umask and return the previous umask.";
959
960static PyObject *
961posix_umask(self, args)
962	PyObject *self;
963	PyObject *args;
964{
965	int i;
966	if (!PyArg_Parse(args, "i", &i))
967		return NULL;
968	i = umask(i);
969	if (i < 0)
970		return posix_error();
971	return PyInt_FromLong((long)i);
972}
973
974
975static char posix_unlink__doc__[] =
976"unlink(path) -> None\n\
977Remove a file (same as remove(path)).";
978
979static char posix_remove__doc__[] =
980"remove(path) -> None\n\
981Remove a file (same as unlink(path)).";
982
983static PyObject *
984posix_unlink(self, args)
985	PyObject *self;
986	PyObject *args;
987{
988	return posix_1str(args, unlink);
989}
990
991
992#ifdef HAVE_UNAME
993static char posix_uname__doc__[] =
994"uname() -> (sysname, nodename, release, version, machine)\n\
995Return a tuple identifying the current operating system.";
996
997static PyObject *
998posix_uname(self, args)
999	PyObject *self;
1000	PyObject *args;
1001{
1002	struct utsname u;
1003	int res;
1004	if (!PyArg_NoArgs(args))
1005		return NULL;
1006	Py_BEGIN_ALLOW_THREADS
1007	res = uname(&u);
1008	Py_END_ALLOW_THREADS
1009	if (res < 0)
1010		return posix_error();
1011	return Py_BuildValue("(sssss)",
1012			     u.sysname,
1013			     u.nodename,
1014			     u.release,
1015			     u.version,
1016			     u.machine);
1017}
1018#endif /* HAVE_UNAME */
1019
1020
1021static char posix_utime__doc__[] =
1022"utime(path, (atime, utime)) -> None\n\
1023Set the access and modified time of the file to the given values.";
1024
1025static PyObject *
1026posix_utime(self, args)
1027	PyObject *self;
1028	PyObject *args;
1029{
1030	char *path;
1031	long atime, mtime;
1032	int res;
1033
1034/* XXX should define struct utimbuf instead, above */
1035#ifdef HAVE_UTIME_H
1036	struct utimbuf buf;
1037#define ATIME buf.actime
1038#define MTIME buf.modtime
1039#define UTIME_ARG &buf
1040#else /* HAVE_UTIME_H */
1041	time_t buf[2];
1042#define ATIME buf[0]
1043#define MTIME buf[1]
1044#define UTIME_ARG buf
1045#endif /* HAVE_UTIME_H */
1046
1047	if (!PyArg_Parse(args, "(s(ll))", &path, &atime, &mtime))
1048		return NULL;
1049	ATIME = atime;
1050	MTIME = mtime;
1051	Py_BEGIN_ALLOW_THREADS
1052	res = utime(path, UTIME_ARG);
1053	Py_END_ALLOW_THREADS
1054	if (res < 0)
1055		return posix_error_with_filename(path);
1056	Py_INCREF(Py_None);
1057	return Py_None;
1058#undef UTIME_ARG
1059#undef ATIME
1060#undef MTIME
1061}
1062
1063
1064/* Process operations */
1065
1066static char posix__exit__doc__[] =
1067"_exit(status)\n\
1068Exit to the system with specified status, without normal exit processing.";
1069
1070static PyObject *
1071posix__exit(self, args)
1072	PyObject *self;
1073	PyObject *args;
1074{
1075	int sts;
1076	if (!PyArg_Parse(args, "i", &sts))
1077		return NULL;
1078	_exit(sts);
1079	return NULL; /* Make gcc -Wall happy */
1080}
1081
1082
1083#ifdef HAVE_EXECV
1084static char posix_execv__doc__[] =
1085"execv(path, args)\n\
1086Execute an executable path with arguments, replacing current process.\n\
1087\n\
1088	path: path of executable file\n\
1089	args: tuple or list of strings";
1090
1091static PyObject *
1092posix_execv(self, args)
1093	PyObject *self;
1094	PyObject *args;
1095{
1096	char *path;
1097	PyObject *argv;
1098	char **argvlist;
1099	int i, argc;
1100	PyObject *(*getitem) Py_PROTO((PyObject *, int));
1101
1102	/* execv has two arguments: (path, argv), where
1103	   argv is a list or tuple of strings. */
1104
1105	if (!PyArg_Parse(args, "(sO)", &path, &argv))
1106		return NULL;
1107	if (PyList_Check(argv)) {
1108		argc = PyList_Size(argv);
1109		getitem = PyList_GetItem;
1110	}
1111	else if (PyTuple_Check(argv)) {
1112		argc = PyTuple_Size(argv);
1113		getitem = PyTuple_GetItem;
1114	}
1115	else {
1116 badarg:
1117		PyErr_BadArgument();
1118		return NULL;
1119	}
1120
1121	argvlist = PyMem_NEW(char *, argc+1);
1122	if (argvlist == NULL)
1123		return NULL;
1124	for (i = 0; i < argc; i++) {
1125		if (!PyArg_Parse((*getitem)(argv, i), "s", &argvlist[i])) {
1126			PyMem_DEL(argvlist);
1127			goto badarg;
1128		}
1129	}
1130	argvlist[argc] = NULL;
1131
1132#ifdef BAD_EXEC_PROTOTYPES
1133	execv(path, (const char **) argvlist);
1134#else /* BAD_EXEC_PROTOTYPES */
1135	execv(path, argvlist);
1136#endif /* BAD_EXEC_PROTOTYPES */
1137
1138	/* If we get here it's definitely an error */
1139
1140	PyMem_DEL(argvlist);
1141	return posix_error();
1142}
1143
1144
1145static char posix_execve__doc__[] =
1146"execve(path, args, env)\n\
1147Execute a path with arguments and environment, replacing current process.\n\
1148\n\
1149	path: path of executable file\n\
1150	args: tuple or list of arguments\n\
1151	env: dictonary of strings mapping to strings";
1152
1153static PyObject *
1154posix_execve(self, args)
1155	PyObject *self;
1156	PyObject *args;
1157{
1158	char *path;
1159	PyObject *argv, *env;
1160	char **argvlist;
1161	char **envlist;
1162	PyObject *key, *val, *keys=NULL, *vals=NULL;
1163	int i, pos, argc, envc;
1164	PyObject *(*getitem) Py_PROTO((PyObject *, int));
1165
1166	/* execve has three arguments: (path, argv, env), where
1167	   argv is a list or tuple of strings and env is a dictionary
1168	   like posix.environ. */
1169
1170	if (!PyArg_Parse(args, "(sOO)", &path, &argv, &env))
1171		return NULL;
1172	if (PyList_Check(argv)) {
1173		argc = PyList_Size(argv);
1174		getitem = PyList_GetItem;
1175	}
1176	else if (PyTuple_Check(argv)) {
1177		argc = PyTuple_Size(argv);
1178		getitem = PyTuple_GetItem;
1179	}
1180	else {
1181		PyErr_SetString(PyExc_TypeError, "argv must be tuple or list");
1182		return NULL;
1183	}
1184	if (!PyMapping_Check(env)) {
1185		PyErr_SetString(PyExc_TypeError, "env must be mapping object");
1186		return NULL;
1187	}
1188
1189	argvlist = PyMem_NEW(char *, argc+1);
1190	if (argvlist == NULL) {
1191		PyErr_NoMemory();
1192		return NULL;
1193	}
1194	for (i = 0; i < argc; i++) {
1195		if (!PyArg_Parse((*getitem)(argv, i),
1196				 "s;argv must be list of strings",
1197				 &argvlist[i]))
1198		{
1199			goto fail_1;
1200		}
1201	}
1202	argvlist[argc] = NULL;
1203
1204	i = PyMapping_Length(env);
1205	envlist = PyMem_NEW(char *, i + 1);
1206	if (envlist == NULL) {
1207		PyErr_NoMemory();
1208		goto fail_1;
1209	}
1210	envc = 0;
1211	keys = PyMapping_Keys(env);
1212	vals = PyMapping_Values(env);
1213	if (!keys || !vals)
1214		goto fail_2;
1215
1216	for (pos = 0; pos < i; pos++) {
1217		char *p, *k, *v;
1218
1219		key = PyList_GetItem(keys, pos);
1220		val = PyList_GetItem(vals, pos);
1221		if (!key || !val)
1222			goto fail_2;
1223
1224		if (!PyArg_Parse(key, "s;non-string key in env", &k) ||
1225		    !PyArg_Parse(val, "s;non-string value in env", &v))
1226		{
1227			goto fail_2;
1228		}
1229
1230#if defined(PYOS_OS2)
1231        /* Omit Pseudo-Env Vars that Would Confuse Programs if Passed On */
1232        if (stricmp(k, "BEGINLIBPATH") != 0 && stricmp(k, "ENDLIBPATH") != 0) {
1233#endif
1234		p = PyMem_NEW(char, PyString_Size(key)+PyString_Size(val) + 2);
1235		if (p == NULL) {
1236			PyErr_NoMemory();
1237			goto fail_2;
1238		}
1239		sprintf(p, "%s=%s", k, v);
1240		envlist[envc++] = p;
1241#if defined(PYOS_OS2)
1242    }
1243#endif
1244	}
1245	envlist[envc] = 0;
1246
1247
1248#ifdef BAD_EXEC_PROTOTYPES
1249	execve(path, (const char **)argvlist, envlist);
1250#else /* BAD_EXEC_PROTOTYPES */
1251	execve(path, argvlist, envlist);
1252#endif /* BAD_EXEC_PROTOTYPES */
1253
1254	/* If we get here it's definitely an error */
1255
1256	(void) posix_error();
1257
1258 fail_2:
1259	while (--envc >= 0)
1260		PyMem_DEL(envlist[envc]);
1261	PyMem_DEL(envlist);
1262 fail_1:
1263	PyMem_DEL(argvlist);
1264	Py_XDECREF(vals);
1265	Py_XDECREF(keys);
1266	return NULL;
1267}
1268#endif /* HAVE_EXECV */
1269
1270
1271#ifdef HAVE_FORK
1272static char posix_fork__doc__[] =
1273"fork() -> pid\n\
1274Fork a child process.\n\
1275\n\
1276Return 0 to child process and PID of child to parent process.";
1277
1278static PyObject *
1279posix_fork(self, args)
1280	PyObject *self;
1281	PyObject *args;
1282{
1283	int pid;
1284	if (!PyArg_NoArgs(args))
1285		return NULL;
1286	pid = fork();
1287	if (pid == -1)
1288		return posix_error();
1289	PyOS_AfterFork();
1290	return PyInt_FromLong((long)pid);
1291}
1292#endif
1293
1294
1295#ifdef HAVE_GETEGID
1296static char posix_getegid__doc__[] =
1297"getegid() -> egid\n\
1298Return the current process's effective group id.";
1299
1300static PyObject *
1301posix_getegid(self, args)
1302	PyObject *self;
1303	PyObject *args;
1304{
1305	if (!PyArg_NoArgs(args))
1306		return NULL;
1307	return PyInt_FromLong((long)getegid());
1308}
1309#endif
1310
1311
1312#ifdef HAVE_GETEUID
1313static char posix_geteuid__doc__[] =
1314"geteuid() -> euid\n\
1315Return the current process's effective user id.";
1316
1317static PyObject *
1318posix_geteuid(self, args)
1319	PyObject *self;
1320	PyObject *args;
1321{
1322	if (!PyArg_NoArgs(args))
1323		return NULL;
1324	return PyInt_FromLong((long)geteuid());
1325}
1326#endif
1327
1328
1329#ifdef HAVE_GETGID
1330static char posix_getgid__doc__[] =
1331"getgid() -> gid\n\
1332Return the current process's group id.";
1333
1334static PyObject *
1335posix_getgid(self, args)
1336	PyObject *self;
1337	PyObject *args;
1338{
1339	if (!PyArg_NoArgs(args))
1340		return NULL;
1341	return PyInt_FromLong((long)getgid());
1342}
1343#endif
1344
1345
1346static char posix_getpid__doc__[] =
1347"getpid() -> pid\n\
1348Return the current process id";
1349
1350static PyObject *
1351posix_getpid(self, args)
1352	PyObject *self;
1353	PyObject *args;
1354{
1355	if (!PyArg_NoArgs(args))
1356		return NULL;
1357	return PyInt_FromLong((long)getpid());
1358}
1359
1360
1361#ifdef HAVE_GETPGRP
1362static char posix_getpgrp__doc__[] =
1363"getpgrp() -> pgrp\n\
1364Return the current process group id.";
1365
1366static PyObject *
1367posix_getpgrp(self, args)
1368	PyObject *self;
1369	PyObject *args;
1370{
1371	if (!PyArg_NoArgs(args))
1372		return NULL;
1373#ifdef GETPGRP_HAVE_ARG
1374	return PyInt_FromLong((long)getpgrp(0));
1375#else /* GETPGRP_HAVE_ARG */
1376	return PyInt_FromLong((long)getpgrp());
1377#endif /* GETPGRP_HAVE_ARG */
1378}
1379#endif /* HAVE_GETPGRP */
1380
1381
1382#ifdef HAVE_SETPGRP
1383static char posix_setpgrp__doc__[] =
1384"setpgrp() -> None\n\
1385Make this process a session leader.";
1386
1387static PyObject *
1388posix_setpgrp(self, args)
1389	PyObject *self;
1390	PyObject *args;
1391{
1392	if (!PyArg_NoArgs(args))
1393		return NULL;
1394#ifdef SETPGRP_HAVE_ARG
1395	if (setpgrp(0, 0) < 0)
1396#else /* SETPGRP_HAVE_ARG */
1397	if (setpgrp() < 0)
1398#endif /* SETPGRP_HAVE_ARG */
1399		return posix_error();
1400	Py_INCREF(Py_None);
1401	return Py_None;
1402}
1403
1404#endif /* HAVE_SETPGRP */
1405
1406#ifdef HAVE_GETPPID
1407static char posix_getppid__doc__[] =
1408"getppid() -> ppid\n\
1409Return the parent's process id.";
1410
1411static PyObject *
1412posix_getppid(self, args)
1413	PyObject *self;
1414	PyObject *args;
1415{
1416	if (!PyArg_NoArgs(args))
1417		return NULL;
1418	return PyInt_FromLong((long)getppid());
1419}
1420#endif
1421
1422
1423#ifdef HAVE_GETUID
1424static char posix_getuid__doc__[] =
1425"getuid() -> uid\n\
1426Return the current process's user id.";
1427
1428static PyObject *
1429posix_getuid(self, args)
1430	PyObject *self;
1431	PyObject *args;
1432{
1433	if (!PyArg_NoArgs(args))
1434		return NULL;
1435	return PyInt_FromLong((long)getuid());
1436}
1437#endif
1438
1439
1440#ifdef HAVE_KILL
1441static char posix_kill__doc__[] =
1442"kill(pid, sig) -> None\n\
1443Kill a process with a signal.";
1444
1445static PyObject *
1446posix_kill(self, args)
1447	PyObject *self;
1448	PyObject *args;
1449{
1450	int pid, sig;
1451	if (!PyArg_Parse(args, "(ii)", &pid, &sig))
1452		return NULL;
1453#if defined(PYOS_OS2)
1454    if (sig == XCPT_SIGNAL_INTR || sig == XCPT_SIGNAL_BREAK) {
1455        APIRET rc;
1456        if ((rc = DosSendSignalException(pid, sig)) != NO_ERROR)
1457            return os2_error(rc);
1458
1459    } else if (sig == XCPT_SIGNAL_KILLPROC) {
1460        APIRET rc;
1461        if ((rc = DosKillProcess(DKP_PROCESS, pid)) != NO_ERROR)
1462            return os2_error(rc);
1463
1464    } else
1465        return NULL; /* Unrecognized Signal Requested */
1466#else
1467	if (kill(pid, sig) == -1)
1468		return posix_error();
1469#endif
1470	Py_INCREF(Py_None);
1471	return Py_None;
1472}
1473#endif
1474
1475#ifdef HAVE_PLOCK
1476
1477#ifdef HAVE_SYS_LOCK_H
1478#include <sys/lock.h>
1479#endif
1480
1481static char posix_plock__doc__[] =
1482"plock(op) -> None\n\
1483Lock program segments into memory.";
1484
1485static PyObject *
1486posix_plock(self, args)
1487	PyObject *self;
1488	PyObject *args;
1489{
1490	int op;
1491	if (!PyArg_Parse(args, "i", &op))
1492		return NULL;
1493	if (plock(op) == -1)
1494		return posix_error();
1495	Py_INCREF(Py_None);
1496	return Py_None;
1497}
1498#endif
1499
1500
1501#ifdef HAVE_POPEN
1502static char posix_popen__doc__[] =
1503"popen(command [, mode='r' [, bufsize]]) -> pipe\n\
1504Open a pipe to/from a command returning a file object.";
1505
1506#if defined(PYOS_OS2)
1507static int
1508async_system(const char *command)
1509{
1510    char        *p, errormsg[256], args[1024];
1511    RESULTCODES  rcodes;
1512    APIRET       rc;
1513    char        *shell = getenv("COMSPEC");
1514    if (!shell)
1515        shell = "cmd";
1516
1517    strcpy(args, shell);
1518    p = &args[ strlen(args)+1 ];
1519    strcpy(p, "/c ");
1520    strcat(p, command);
1521    p += strlen(p) + 1;
1522    *p = '\0';
1523
1524    rc = DosExecPgm(errormsg, sizeof(errormsg),
1525                    EXEC_ASYNC, /* Execute Async w/o Wait for Results */
1526                    args,
1527                    NULL,       /* Inherit Parent's Environment */
1528                    &rcodes, shell);
1529    return rc;
1530}
1531
1532static FILE *
1533popen(const char *command, const char *mode, int pipesize, int *err)
1534{
1535    HFILE    rhan, whan;
1536    FILE    *retfd = NULL;
1537    APIRET   rc = DosCreatePipe(&rhan, &whan, pipesize);
1538
1539    if (rc != NO_ERROR) {
1540	*err = rc;
1541        return NULL; /* ERROR - Unable to Create Anon Pipe */
1542    }
1543
1544    if (strchr(mode, 'r') != NULL) { /* Treat Command as a Data Source */
1545        int oldfd = dup(1);      /* Save STDOUT Handle in Another Handle */
1546
1547        DosEnterCritSec();      /* Stop Other Threads While Changing Handles */
1548        close(1);                /* Make STDOUT Available for Reallocation */
1549
1550        if (dup2(whan, 1) == 0) {      /* Connect STDOUT to Pipe Write Side */
1551            DosClose(whan);            /* Close Now-Unused Pipe Write Handle */
1552
1553            if (async_system(command) == NO_ERROR)
1554                retfd = fdopen(rhan, mode); /* And Return Pipe Read Handle */
1555        }
1556
1557        dup2(oldfd, 1);          /* Reconnect STDOUT to Original Handle */
1558        DosExitCritSec();        /* Now Allow Other Threads to Run */
1559
1560        close(oldfd);            /* And Close Saved STDOUT Handle */
1561        return retfd;            /* Return fd of Pipe or NULL if Error */
1562
1563    } else if (strchr(mode, 'w')) { /* Treat Command as a Data Sink */
1564        int oldfd = dup(0);      /* Save STDIN Handle in Another Handle */
1565
1566        DosEnterCritSec();      /* Stop Other Threads While Changing Handles */
1567        close(0);                /* Make STDIN Available for Reallocation */
1568
1569        if (dup2(rhan, 0) == 0)     { /* Connect STDIN to Pipe Read Side */
1570            DosClose(rhan);           /* Close Now-Unused Pipe Read Handle */
1571
1572            if (async_system(command) == NO_ERROR)
1573                retfd = fdopen(whan, mode); /* And Return Pipe Write Handle */
1574        }
1575
1576        dup2(oldfd, 0);          /* Reconnect STDIN to Original Handle */
1577        DosExitCritSec();        /* Now Allow Other Threads to Run */
1578
1579        close(oldfd);            /* And Close Saved STDIN Handle */
1580        return retfd;            /* Return fd of Pipe or NULL if Error */
1581
1582    } else {
1583	*err = ERROR_INVALID_ACCESS;
1584        return NULL; /* ERROR - Invalid Mode (Neither Read nor Write) */
1585    }
1586}
1587
1588static PyObject *
1589posix_popen(self, args)
1590	PyObject *self;
1591	PyObject *args;
1592{
1593	char *name;
1594	char *mode = "r";
1595	int   err, bufsize = -1;
1596	FILE *fp;
1597	PyObject *f;
1598	if (!PyArg_ParseTuple(args, "s|si", &name, &mode, &bufsize))
1599		return NULL;
1600	Py_BEGIN_ALLOW_THREADS
1601	fp = popen(name, mode, (bufsize > 0) ? bufsize : 4096, &err);
1602	Py_END_ALLOW_THREADS
1603	if (fp == NULL)
1604		return os2_error(err);
1605
1606	f = PyFile_FromFile(fp, name, mode, fclose);
1607	if (f != NULL)
1608		PyFile_SetBufSize(f, bufsize);
1609	return f;
1610}
1611
1612#else
1613static PyObject *
1614posix_popen(self, args)
1615	PyObject *self;
1616	PyObject *args;
1617{
1618	char *name;
1619	char *mode = "r";
1620	int bufsize = -1;
1621	FILE *fp;
1622	PyObject *f;
1623	if (!PyArg_ParseTuple(args, "s|si", &name, &mode, &bufsize))
1624		return NULL;
1625	Py_BEGIN_ALLOW_THREADS
1626	fp = popen(name, mode);
1627	Py_END_ALLOW_THREADS
1628	if (fp == NULL)
1629		return posix_error();
1630	f = PyFile_FromFile(fp, name, mode, pclose);
1631	if (f != NULL)
1632		PyFile_SetBufSize(f, bufsize);
1633	return f;
1634}
1635#endif
1636
1637#endif /* HAVE_POPEN */
1638
1639
1640#ifdef HAVE_SETUID
1641static char posix_setuid__doc__[] =
1642"setuid(uid) -> None\n\
1643Set the current process's user id.";
1644static PyObject *
1645posix_setuid(self, args)
1646	PyObject *self;
1647	PyObject *args;
1648{
1649	int uid;
1650	if (!PyArg_Parse(args, "i", &uid))
1651		return NULL;
1652	if (setuid(uid) < 0)
1653		return posix_error();
1654	Py_INCREF(Py_None);
1655	return Py_None;
1656}
1657#endif /* HAVE_SETUID */
1658
1659
1660#ifdef HAVE_SETGID
1661static char posix_setgid__doc__[] =
1662"setgid(gid) -> None\n\
1663Set the current process's group id.";
1664
1665static PyObject *
1666posix_setgid(self, args)
1667	PyObject *self;
1668	PyObject *args;
1669{
1670	int gid;
1671	if (!PyArg_Parse(args, "i", &gid))
1672		return NULL;
1673	if (setgid(gid) < 0)
1674		return posix_error();
1675	Py_INCREF(Py_None);
1676	return Py_None;
1677}
1678#endif /* HAVE_SETGID */
1679
1680
1681#ifdef HAVE_WAITPID
1682static char posix_waitpid__doc__[] =
1683"waitpid(pid, options) -> (pid, status)\n\
1684Wait for completion of a give child process.";
1685
1686static PyObject *
1687posix_waitpid(self, args)
1688	PyObject *self;
1689	PyObject *args;
1690{
1691	int pid, options, sts = 0;
1692	if (!PyArg_Parse(args, "(ii)", &pid, &options))
1693		return NULL;
1694	Py_BEGIN_ALLOW_THREADS
1695#ifdef NeXT
1696	pid = wait4(pid, (union wait *)&sts, options, NULL);
1697#else
1698	pid = waitpid(pid, &sts, options);
1699#endif
1700	Py_END_ALLOW_THREADS
1701	if (pid == -1)
1702		return posix_error();
1703	else
1704		return Py_BuildValue("ii", pid, sts);
1705}
1706#endif /* HAVE_WAITPID */
1707
1708
1709#ifdef HAVE_WAIT
1710static char posix_wait__doc__[] =
1711"wait() -> (pid, status)\n\
1712Wait for completion of a child process.";
1713
1714static PyObject *
1715posix_wait(self, args)
1716	PyObject *self;
1717	PyObject *args;
1718{
1719	int pid, sts;
1720	Py_BEGIN_ALLOW_THREADS
1721#ifdef NeXT
1722	pid = wait((union wait *)&sts);
1723#else
1724	pid = wait(&sts);
1725#endif
1726	Py_END_ALLOW_THREADS
1727	if (pid == -1)
1728		return posix_error();
1729	else
1730		return Py_BuildValue("ii", pid, sts);
1731}
1732#endif
1733
1734
1735static char posix_lstat__doc__[] =
1736"lstat(path) -> (mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime)\n\
1737Like stat(path), but do not follow symbolic links.";
1738
1739static PyObject *
1740posix_lstat(self, args)
1741	PyObject *self;
1742	PyObject *args;
1743{
1744#ifdef HAVE_LSTAT
1745	return posix_do_stat(self, args, lstat);
1746#else /* !HAVE_LSTAT */
1747	return posix_do_stat(self, args, stat);
1748#endif /* !HAVE_LSTAT */
1749}
1750
1751
1752#ifdef HAVE_READLINK
1753static char posix_readlink__doc__[] =
1754"readlink(path) -> path\n\
1755Return a string representing the path to which the symbolic link points.";
1756
1757static PyObject *
1758posix_readlink(self, args)
1759	PyObject *self;
1760	PyObject *args;
1761{
1762	char buf[MAXPATHLEN];
1763	char *path;
1764	int n;
1765	if (!PyArg_Parse(args, "s", &path))
1766		return NULL;
1767	Py_BEGIN_ALLOW_THREADS
1768	n = readlink(path, buf, (int) sizeof buf);
1769	Py_END_ALLOW_THREADS
1770	if (n < 0)
1771		return posix_error_with_filename(path);
1772	return PyString_FromStringAndSize(buf, n);
1773}
1774#endif /* HAVE_READLINK */
1775
1776
1777#ifdef HAVE_SYMLINK
1778static char posix_symlink__doc__[] =
1779"symlink(src, dst) -> None\n\
1780Create a symbolic link.";
1781
1782static PyObject *
1783posix_symlink(self, args)
1784	PyObject *self;
1785	PyObject *args;
1786{
1787	return posix_2str(args, symlink);
1788}
1789#endif /* HAVE_SYMLINK */
1790
1791
1792#ifdef HAVE_TIMES
1793#ifndef HZ
1794#define HZ 60 /* Universal constant :-) */
1795#endif /* HZ */
1796
1797#if defined(PYCC_VACPP) && defined(PYOS_OS2)
1798static long
1799system_uptime()
1800{
1801    ULONG     value = 0;
1802
1803    Py_BEGIN_ALLOW_THREADS
1804    DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &value, sizeof(value));
1805    Py_END_ALLOW_THREADS
1806
1807    return value;
1808}
1809
1810static PyObject *
1811posix_times(self, args)
1812	PyObject *self;
1813	PyObject *args;
1814{
1815	if (!PyArg_NoArgs(args))
1816		return NULL;
1817
1818    /* Currently Only Uptime is Provided -- Others Later */
1819	return Py_BuildValue("ddddd",
1820			     (double)0 /* t.tms_utime / HZ */,
1821			     (double)0 /* t.tms_stime / HZ */,
1822			     (double)0 /* t.tms_cutime / HZ */,
1823			     (double)0 /* t.tms_cstime / HZ */,
1824			     (double)system_uptime() / 1000);
1825}
1826#else /* not OS2 */
1827static PyObject *
1828posix_times(self, args)
1829	PyObject *self;
1830	PyObject *args;
1831{
1832	struct tms t;
1833	clock_t c;
1834	if (!PyArg_NoArgs(args))
1835		return NULL;
1836	errno = 0;
1837	c = times(&t);
1838	if (c == (clock_t) -1)
1839		return posix_error();
1840	return Py_BuildValue("ddddd",
1841			     (double)t.tms_utime / HZ,
1842			     (double)t.tms_stime / HZ,
1843			     (double)t.tms_cutime / HZ,
1844			     (double)t.tms_cstime / HZ,
1845			     (double)c / HZ);
1846}
1847#endif /* not OS2 */
1848#endif /* HAVE_TIMES */
1849
1850
1851#ifdef MS_WIN32
1852#define HAVE_TIMES	/* so the method table will pick it up */
1853static PyObject *
1854posix_times(self, args)
1855	PyObject *self;
1856	PyObject *args;
1857{
1858	FILETIME create, exit, kernel, user;
1859	HANDLE hProc;
1860	if (!PyArg_NoArgs(args))
1861		return NULL;
1862	hProc = GetCurrentProcess();
1863	GetProcessTimes(hProc,&create, &exit, &kernel, &user);
1864	return Py_BuildValue(
1865		"ddddd",
1866		(double)(kernel.dwHighDateTime*2E32+kernel.dwLowDateTime)/2E6,
1867		(double)(user.dwHighDateTime*2E32+user.dwLowDateTime) / 2E6,
1868		(double)0,
1869		(double)0,
1870		(double)0);
1871}
1872#endif /* MS_WIN32 */
1873
1874#ifdef HAVE_TIMES
1875static char posix_times__doc__[] =
1876"times() -> (utime, stime, cutime, cstime, elapsed_time)\n\
1877Return a tuple of floating point numbers indicating process times.";
1878#endif
1879
1880
1881#ifdef HAVE_SETSID
1882static char posix_setsid__doc__[] =
1883"setsid() -> None\n\
1884Call the system call setsid().";
1885
1886static PyObject *
1887posix_setsid(self, args)
1888	PyObject *self;
1889	PyObject *args;
1890{
1891	if (!PyArg_NoArgs(args))
1892		return NULL;
1893	if (setsid() < 0)
1894		return posix_error();
1895	Py_INCREF(Py_None);
1896	return Py_None;
1897}
1898#endif /* HAVE_SETSID */
1899
1900#ifdef HAVE_SETPGID
1901static char posix_setpgid__doc__[] =
1902"setpgid(pid, pgrp) -> None\n\
1903Call the system call setpgid().";
1904
1905static PyObject *
1906posix_setpgid(self, args)
1907	PyObject *self;
1908	PyObject *args;
1909{
1910	int pid, pgrp;
1911	if (!PyArg_Parse(args, "(ii)", &pid, &pgrp))
1912		return NULL;
1913	if (setpgid(pid, pgrp) < 0)
1914		return posix_error();
1915	Py_INCREF(Py_None);
1916	return Py_None;
1917}
1918#endif /* HAVE_SETPGID */
1919
1920
1921#ifdef HAVE_TCGETPGRP
1922static char posix_tcgetpgrp__doc__[] =
1923"tcgetpgrp(fd) -> pgid\n\
1924Return the process group associated with the terminal given by a fd.";
1925
1926static PyObject *
1927posix_tcgetpgrp(self, args)
1928	PyObject *self;
1929	PyObject *args;
1930{
1931	int fd, pgid;
1932	if (!PyArg_Parse(args, "i", &fd))
1933		return NULL;
1934	pgid = tcgetpgrp(fd);
1935	if (pgid < 0)
1936		return posix_error();
1937	return PyInt_FromLong((long)pgid);
1938}
1939#endif /* HAVE_TCGETPGRP */
1940
1941
1942#ifdef HAVE_TCSETPGRP
1943static char posix_tcsetpgrp__doc__[] =
1944"tcsetpgrp(fd, pgid) -> None\n\
1945Set the process group associated with the terminal given by a fd.";
1946
1947static PyObject *
1948posix_tcsetpgrp(self, args)
1949	PyObject *self;
1950	PyObject *args;
1951{
1952	int fd, pgid;
1953	if (!PyArg_Parse(args, "(ii)", &fd, &pgid))
1954		return NULL;
1955	if (tcsetpgrp(fd, pgid) < 0)
1956		return posix_error();
1957	Py_INCREF(Py_None);
1958	return Py_None;
1959}
1960#endif /* HAVE_TCSETPGRP */
1961
1962/* Functions acting on file descriptors */
1963
1964static char posix_open__doc__[] =
1965"open(filename, flag [, mode=0777]) -> fd\n\
1966Open a file (for low level IO).";
1967
1968static PyObject *
1969posix_open(self, args)
1970	PyObject *self;
1971	PyObject *args;
1972{
1973	char *file;
1974	int flag;
1975	int mode = 0777;
1976	int fd;
1977	if (!PyArg_ParseTuple(args, "si|i", &file, &flag, &mode))
1978		return NULL;
1979
1980	Py_BEGIN_ALLOW_THREADS
1981	fd = open(file, flag, mode);
1982	Py_END_ALLOW_THREADS
1983	if (fd < 0)
1984		return posix_error_with_filename(file);
1985	return PyInt_FromLong((long)fd);
1986}
1987
1988
1989static char posix_close__doc__[] =
1990"close(fd) -> None\n\
1991Close a file descriptor (for low level IO).";
1992
1993static PyObject *
1994posix_close(self, args)
1995	PyObject *self;
1996	PyObject *args;
1997{
1998	int fd, res;
1999	if (!PyArg_Parse(args, "i", &fd))
2000		return NULL;
2001	Py_BEGIN_ALLOW_THREADS
2002	res = close(fd);
2003	Py_END_ALLOW_THREADS
2004	if (res < 0)
2005		return posix_error();
2006	Py_INCREF(Py_None);
2007	return Py_None;
2008}
2009
2010
2011static char posix_dup__doc__[] =
2012"dup(fd) -> fd2\n\
2013Return a duplicate of a file descriptor.";
2014
2015static PyObject *
2016posix_dup(self, args)
2017	PyObject *self;
2018	PyObject *args;
2019{
2020	int fd;
2021	if (!PyArg_Parse(args, "i", &fd))
2022		return NULL;
2023	Py_BEGIN_ALLOW_THREADS
2024	fd = dup(fd);
2025	Py_END_ALLOW_THREADS
2026	if (fd < 0)
2027		return posix_error();
2028	return PyInt_FromLong((long)fd);
2029}
2030
2031
2032static char posix_dup2__doc__[] =
2033"dup2(fd, fd2) -> None\n\
2034Duplicate file descriptor.";
2035
2036static PyObject *
2037posix_dup2(self, args)
2038	PyObject *self;
2039	PyObject *args;
2040{
2041	int fd, fd2, res;
2042	if (!PyArg_Parse(args, "(ii)", &fd, &fd2))
2043		return NULL;
2044	Py_BEGIN_ALLOW_THREADS
2045	res = dup2(fd, fd2);
2046	Py_END_ALLOW_THREADS
2047	if (res < 0)
2048		return posix_error();
2049	Py_INCREF(Py_None);
2050	return Py_None;
2051}
2052
2053
2054static char posix_lseek__doc__[] =
2055"lseek(fd, pos, how) -> newpos\n\
2056Set the current position of a file descriptor.";
2057
2058static PyObject *
2059posix_lseek(self, args)
2060	PyObject *self;
2061	PyObject *args;
2062{
2063	int fd, how;
2064	long pos, res;
2065	if (!PyArg_Parse(args, "(ili)", &fd, &pos, &how))
2066		return NULL;
2067#ifdef SEEK_SET
2068	/* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
2069	switch (how) {
2070	case 0: how = SEEK_SET; break;
2071	case 1: how = SEEK_CUR; break;
2072	case 2: how = SEEK_END; break;
2073	}
2074#endif /* SEEK_END */
2075	Py_BEGIN_ALLOW_THREADS
2076	res = lseek(fd, pos, how);
2077	Py_END_ALLOW_THREADS
2078	if (res < 0)
2079		return posix_error();
2080	return PyInt_FromLong(res);
2081}
2082
2083
2084static char posix_read__doc__[] =
2085"read(fd, buffersize) -> string\n\
2086Read a file descriptor.";
2087
2088static PyObject *
2089posix_read(self, args)
2090	PyObject *self;
2091	PyObject *args;
2092{
2093	int fd, size, n;
2094	PyObject *buffer;
2095	if (!PyArg_Parse(args, "(ii)", &fd, &size))
2096		return NULL;
2097	buffer = PyString_FromStringAndSize((char *)NULL, size);
2098	if (buffer == NULL)
2099		return NULL;
2100	Py_BEGIN_ALLOW_THREADS
2101	n = read(fd, PyString_AsString(buffer), size);
2102	Py_END_ALLOW_THREADS
2103	if (n < 0) {
2104		Py_DECREF(buffer);
2105		return posix_error();
2106	}
2107	if (n != size)
2108		_PyString_Resize(&buffer, n);
2109	return buffer;
2110}
2111
2112
2113static char posix_write__doc__[] =
2114"write(fd, string) -> byteswritten\n\
2115Write a string to a file descriptor.";
2116
2117static PyObject *
2118posix_write(self, args)
2119	PyObject *self;
2120	PyObject *args;
2121{
2122	int fd, size;
2123	char *buffer;
2124	if (!PyArg_Parse(args, "(is#)", &fd, &buffer, &size))
2125		return NULL;
2126	Py_BEGIN_ALLOW_THREADS
2127	size = write(fd, buffer, size);
2128	Py_END_ALLOW_THREADS
2129	if (size < 0)
2130		return posix_error();
2131	return PyInt_FromLong((long)size);
2132}
2133
2134
2135static char posix_fstat__doc__[]=
2136"fstat(fd) -> (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\
2137Like stat(), but for an open file descriptor.";
2138
2139static PyObject *
2140posix_fstat(self, args)
2141	PyObject *self;
2142	PyObject *args;
2143{
2144	int fd;
2145	struct stat st;
2146	int res;
2147	if (!PyArg_Parse(args, "i", &fd))
2148		return NULL;
2149	Py_BEGIN_ALLOW_THREADS
2150	res = fstat(fd, &st);
2151	Py_END_ALLOW_THREADS
2152	if (res != 0)
2153		return posix_error();
2154	return Py_BuildValue("(llllllllll)",
2155			     (long)st.st_mode,
2156			     (long)st.st_ino,
2157			     (long)st.st_dev,
2158			     (long)st.st_nlink,
2159			     (long)st.st_uid,
2160			     (long)st.st_gid,
2161			     (long)st.st_size,
2162			     (long)st.st_atime,
2163			     (long)st.st_mtime,
2164			     (long)st.st_ctime);
2165}
2166
2167
2168static char posix_fdopen__doc__[] =
2169"fdopen(fd, [, mode='r' [, bufsize]]) -> file_object\n\
2170Return an open file object connected to a file descriptor.";
2171
2172static PyObject *
2173posix_fdopen(self, args)
2174	PyObject *self;
2175	PyObject *args;
2176{
2177	extern int fclose Py_PROTO((FILE *));
2178	int fd;
2179	char *mode = "r";
2180	int bufsize = -1;
2181	FILE *fp;
2182	PyObject *f;
2183	if (!PyArg_ParseTuple(args, "i|si", &fd, &mode, &bufsize))
2184		return NULL;
2185
2186	Py_BEGIN_ALLOW_THREADS
2187	fp = fdopen(fd, mode);
2188	Py_END_ALLOW_THREADS
2189	if (fp == NULL)
2190		return posix_error();
2191	f = PyFile_FromFile(fp, "(fdopen)", mode, fclose);
2192	if (f != NULL)
2193		PyFile_SetBufSize(f, bufsize);
2194	return f;
2195}
2196
2197
2198#ifdef HAVE_PIPE
2199static char posix_pipe__doc__[] =
2200"pipe() -> (read_end, write_end)\n\
2201Create a pipe.";
2202
2203static PyObject *
2204posix_pipe(self, args)
2205	PyObject *self;
2206	PyObject *args;
2207{
2208#if defined(PYOS_OS2)
2209    HFILE read, write;
2210    APIRET rc;
2211
2212    if (!PyArg_Parse(args, ""))
2213        return NULL;
2214
2215	Py_BEGIN_ALLOW_THREADS
2216    rc = DosCreatePipe( &read, &write, 4096);
2217	Py_END_ALLOW_THREADS
2218    if (rc != NO_ERROR)
2219        return os2_error(rc);
2220
2221    return Py_BuildValue("(ii)", read, write);
2222#else
2223#if !defined(MS_WIN32)
2224	int fds[2];
2225	int res;
2226	if (!PyArg_Parse(args, ""))
2227		return NULL;
2228	Py_BEGIN_ALLOW_THREADS
2229	res = pipe(fds);
2230	Py_END_ALLOW_THREADS
2231	if (res != 0)
2232		return posix_error();
2233	return Py_BuildValue("(ii)", fds[0], fds[1]);
2234#else /* MS_WIN32 */
2235	HANDLE read, write;
2236	int read_fd, write_fd;
2237	BOOL ok;
2238	if (!PyArg_Parse(args, ""))
2239		return NULL;
2240	Py_BEGIN_ALLOW_THREADS
2241	ok = CreatePipe(&read, &write, NULL, 0);
2242	Py_END_ALLOW_THREADS
2243	if (!ok)
2244		return posix_error();
2245	read_fd = _open_osfhandle((long)read, 0);
2246	write_fd = _open_osfhandle((long)write, 1);
2247	return Py_BuildValue("(ii)", read_fd, write_fd);
2248#endif /* MS_WIN32 */
2249#endif
2250}
2251#endif  /* HAVE_PIPE */
2252
2253
2254#ifdef HAVE_MKFIFO
2255static char posix_mkfifo__doc__[] =
2256"mkfifo(file, [, mode=0666]) -> None\n\
2257Create a FIFO (a POSIX named pipe).";
2258
2259static PyObject *
2260posix_mkfifo(self, args)
2261	PyObject *self;
2262	PyObject *args;
2263{
2264	char *file;
2265	int mode = 0666;
2266	int res;
2267	if (!PyArg_ParseTuple(args, "s|i", &file, &mode))
2268		return NULL;
2269	Py_BEGIN_ALLOW_THREADS
2270	res = mkfifo(file, mode);
2271	Py_END_ALLOW_THREADS
2272	if (res < 0)
2273		return posix_error();
2274	Py_INCREF(Py_None);
2275	return Py_None;
2276}
2277#endif
2278
2279
2280#ifdef HAVE_FTRUNCATE
2281static char posix_ftruncate__doc__[] =
2282"ftruncate(fd, length) -> None\n\
2283Truncate a file to a specified length.";
2284
2285static PyObject *
2286posix_ftruncate(self, args)
2287	PyObject *self; /* Not used */
2288	PyObject *args;
2289{
2290	int fd;
2291	long length;
2292	int res;
2293
2294	if (!PyArg_Parse(args, "(il)", &fd, &length))
2295		return NULL;
2296
2297	Py_BEGIN_ALLOW_THREADS
2298	res = ftruncate(fd, length);
2299	Py_END_ALLOW_THREADS
2300	if (res < 0) {
2301		PyErr_SetFromErrno(PyExc_IOError);
2302		return NULL;
2303	}
2304	Py_INCREF(Py_None);
2305	return Py_None;
2306}
2307#endif
2308
2309#ifdef NeXT
2310#define HAVE_PUTENV
2311/* Steve Spicklemire got this putenv from NeXTAnswers */
2312static int
2313putenv(char *newval)
2314{
2315	extern char **environ;
2316
2317	static int firstTime = 1;
2318	char **ep;
2319	char *cp;
2320	int esiz;
2321	char *np;
2322
2323	if (!(np = strchr(newval, '=')))
2324		return 1;
2325	*np = '\0';
2326
2327	/* look it up */
2328	for (ep=environ ; *ep ; ep++)
2329	{
2330		/* this should always be true... */
2331		if (cp = strchr(*ep, '='))
2332		{
2333			*cp = '\0';
2334			if (!strcmp(*ep, newval))
2335			{
2336				/* got it! */
2337				*cp = '=';
2338				break;
2339			}
2340			*cp = '=';
2341		}
2342		else
2343		{
2344			*np = '=';
2345			return 1;
2346		}
2347	}
2348
2349	*np = '=';
2350	if (*ep)
2351	{
2352		/* the string was already there:
2353		   just replace it with the new one */
2354		*ep = newval;
2355		return 0;
2356	}
2357
2358	/* expand environ by one */
2359	for (esiz=2, ep=environ ; *ep ; ep++)
2360		esiz++;
2361	if (firstTime)
2362	{
2363		char **epp;
2364		char **newenv;
2365		if (!(newenv = malloc(esiz * sizeof(char *))))
2366			return 1;
2367
2368		for (ep=environ, epp=newenv ; *ep ;)
2369			*epp++ = *ep++;
2370		*epp++ = newval;
2371		*epp = (char *) 0;
2372		environ = newenv;
2373	}
2374	else
2375	{
2376		if (!(environ = realloc(environ, esiz * sizeof(char *))))
2377			return 1;
2378		environ[esiz - 2] = newval;
2379		environ[esiz - 1] = (char *) 0;
2380		firstTime = 0;
2381	}
2382
2383	return 0;
2384}
2385#endif /* NeXT */
2386
2387
2388#ifdef HAVE_PUTENV
2389static char posix_putenv__doc__[] =
2390"putenv(key, value) -> None\n\
2391Change or add an environment variable.";
2392
2393#ifdef __BEOS__
2394/* We have putenv(), but not in the headers (as of PR2). - [cjh] */
2395int putenv( const char *str );
2396#endif
2397
2398static PyObject *
2399posix_putenv(self, args)
2400	PyObject *self;
2401	PyObject *args;
2402{
2403        char *s1, *s2;
2404        char *new;
2405
2406	if (!PyArg_ParseTuple(args, "ss", &s1, &s2))
2407		return NULL;
2408
2409#if defined(PYOS_OS2)
2410    if (stricmp(s1, "BEGINLIBPATH") == 0) {
2411        APIRET rc;
2412
2413        if (strlen(s2) == 0)  /* If New Value is an Empty String */
2414            s2 = NULL;        /* Then OS/2 API Wants a NULL to Undefine It */
2415
2416        rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH);
2417        if (rc != NO_ERROR)
2418            return os2_error(rc);
2419
2420    } else if (stricmp(s1, "ENDLIBPATH") == 0) {
2421        APIRET rc;
2422
2423        if (strlen(s2) == 0)  /* If New Value is an Empty String */
2424            s2 = NULL;        /* Then OS/2 API Wants a NULL to Undefine It */
2425
2426        rc = DosSetExtLIBPATH(s2, END_LIBPATH);
2427        if (rc != NO_ERROR)
2428            return os2_error(rc);
2429    } else {
2430#endif
2431
2432	/* XXX This leaks memory -- not easy to fix :-( */
2433	if ((new = malloc(strlen(s1) + strlen(s2) + 2)) == NULL)
2434                return PyErr_NoMemory();
2435	(void) sprintf(new, "%s=%s", s1, s2);
2436	if (putenv(new)) {
2437                posix_error();
2438                return NULL;
2439	}
2440
2441#if defined(PYOS_OS2)
2442    }
2443#endif
2444	Py_INCREF(Py_None);
2445        return Py_None;
2446}
2447#endif /* putenv */
2448
2449#ifdef HAVE_STRERROR
2450static char posix_strerror__doc__[] =
2451"strerror(code) -> string\n\
2452Translate an error code to a message string.";
2453
2454PyObject *
2455posix_strerror(self, args)
2456	PyObject *self;
2457	PyObject *args;
2458{
2459	int code;
2460	char *message;
2461	if (!PyArg_ParseTuple(args, "i", &code))
2462		return NULL;
2463	message = strerror(code);
2464	if (message == NULL) {
2465		PyErr_SetString(PyExc_ValueError,
2466				"strerror code out of range");
2467		return NULL;
2468	}
2469	return PyString_FromString(message);
2470}
2471#endif /* strerror */
2472
2473
2474#ifdef HAVE_SYS_WAIT_H
2475
2476#ifdef WIFSTOPPED
2477static char posix_WIFSTOPPED__doc__[] =
2478"WIFSTOPPED(status) -> Boolean\n\
2479See Unix documentation.";
2480
2481static PyObject *
2482posix_WIFSTOPPED(self, args)
2483	PyObject *self;
2484	PyObject *args;
2485{
2486	int status = 0;
2487
2488	if (!PyArg_Parse(args, "i", &status))
2489	{
2490		return NULL;
2491	}
2492
2493	return Py_BuildValue("i", WIFSTOPPED(status));
2494}
2495#endif /* WIFSTOPPED */
2496
2497#ifdef WIFSIGNALED
2498static char posix_WIFSIGNALED__doc__[] =
2499"WIFSIGNALED(status) -> Boolean\n\
2500See Unix documentation.";
2501
2502static PyObject *
2503posix_WIFSIGNALED(self, args)
2504	PyObject *self;
2505	PyObject *args;
2506{
2507	int status = 0;
2508
2509	if (!PyArg_Parse(args, "i", &status))
2510	{
2511		return NULL;
2512	}
2513
2514	return Py_BuildValue("i", WIFSIGNALED(status));
2515}
2516#endif /* WIFSIGNALED */
2517
2518#ifdef WIFEXITED
2519static char posix_WIFEXITED__doc__[] =
2520"WIFEXITED(status) -> Boolean\n\
2521See Unix documentation.";
2522
2523static PyObject *
2524posix_WIFEXITED(self, args)
2525	PyObject *self;
2526	PyObject *args;
2527{
2528	int status = 0;
2529
2530	if (!PyArg_Parse(args, "i", &status))
2531	{
2532		return NULL;
2533	}
2534
2535	return Py_BuildValue("i", WIFEXITED(status));
2536}
2537#endif /* WIFEXITED */
2538
2539#ifdef WIFSTOPPED
2540static char posix_WEXITSTATUS__doc__[] =
2541"WEXITSTATUS(status) -> integer\n\
2542See Unix documentation.";
2543
2544static PyObject *
2545posix_WEXITSTATUS(self, args)
2546	PyObject *self;
2547	PyObject *args;
2548{
2549	int status = 0;
2550
2551	if (!PyArg_Parse(args, "i", &status))
2552	{
2553		return NULL;
2554	}
2555
2556	return Py_BuildValue("i", WEXITSTATUS(status));
2557}
2558#endif /* WEXITSTATUS */
2559
2560#ifdef WTERMSIG
2561static char posix_WTERMSIG__doc__[] =
2562"WTERMSIG(status) -> integer\n\
2563See Unix documentation.";
2564
2565static PyObject *
2566posix_WTERMSIG(self, args)
2567	PyObject *self;
2568	PyObject *args;
2569{
2570	int status = 0;
2571
2572	if (!PyArg_Parse(args, "i", &status))
2573	{
2574		return NULL;
2575	}
2576
2577	return Py_BuildValue("i", WTERMSIG(status));
2578}
2579#endif /* WTERMSIG */
2580
2581#ifdef WSTOPSIG
2582static char posix_WSTOPSIG__doc__[] =
2583"WSTOPSIG(status) -> integer\n\
2584See Unix documentation.";
2585
2586static PyObject *
2587posix_WSTOPSIG(self, args)
2588	PyObject *self;
2589	PyObject *args;
2590{
2591	int status = 0;
2592
2593	if (!PyArg_Parse(args, "i", &status))
2594	{
2595		return NULL;
2596	}
2597
2598	return Py_BuildValue("i", WSTOPSIG(status));
2599}
2600#endif /* WSTOPSIG */
2601
2602#endif /* HAVE_SYS_WAIT_H */
2603
2604
2605static PyMethodDef posix_methods[] = {
2606	{"chdir",	posix_chdir, 0, posix_chdir__doc__},
2607	{"chmod",	posix_chmod, 0, posix_chmod__doc__},
2608#ifdef HAVE_CHOWN
2609	{"chown",	posix_chown, 0, posix_chown__doc__},
2610#endif /* HAVE_CHOWN */
2611#ifdef HAVE_GETCWD
2612	{"getcwd",	posix_getcwd, 0, posix_getcwd__doc__},
2613#endif
2614#ifdef HAVE_LINK
2615	{"link",	posix_link, 0, posix_link__doc__},
2616#endif /* HAVE_LINK */
2617	{"listdir",	posix_listdir, 0, posix_listdir__doc__},
2618	{"lstat",	posix_lstat, 0, posix_lstat__doc__},
2619	{"mkdir",	posix_mkdir, 1, posix_mkdir__doc__},
2620#ifdef HAVE_NICE
2621	{"nice",	posix_nice, 0, posix_nice__doc__},
2622#endif /* HAVE_NICE */
2623#ifdef HAVE_READLINK
2624	{"readlink",	posix_readlink, 0, posix_readlink__doc__},
2625#endif /* HAVE_READLINK */
2626	{"rename",	posix_rename, 0, posix_rename__doc__},
2627	{"rmdir",	posix_rmdir, 0, posix_rmdir__doc__},
2628	{"stat",	posix_stat, 0, posix_stat__doc__},
2629#ifdef HAVE_SYMLINK
2630	{"symlink",	posix_symlink, 0, posix_symlink__doc__},
2631#endif /* HAVE_SYMLINK */
2632#ifdef HAVE_SYSTEM
2633	{"system",	posix_system, 0, posix_system__doc__},
2634#endif
2635	{"umask",	posix_umask, 0, posix_umask__doc__},
2636#ifdef HAVE_UNAME
2637	{"uname",	posix_uname, 0, posix_uname__doc__},
2638#endif /* HAVE_UNAME */
2639	{"unlink",	posix_unlink, 0, posix_unlink__doc__},
2640	{"remove",	posix_unlink, 0, posix_remove__doc__},
2641	{"utime",	posix_utime, 0, posix_utime__doc__},
2642#ifdef HAVE_TIMES
2643	{"times",	posix_times, 0, posix_times__doc__},
2644#endif /* HAVE_TIMES */
2645	{"_exit",	posix__exit, 0, posix__exit__doc__},
2646#ifdef HAVE_EXECV
2647	{"execv",	posix_execv, 0, posix_execv__doc__},
2648	{"execve",	posix_execve, 0, posix_execve__doc__},
2649#endif /* HAVE_EXECV */
2650#ifdef HAVE_FORK
2651	{"fork",	posix_fork, 0, posix_fork__doc__},
2652#endif /* HAVE_FORK */
2653#ifdef HAVE_GETEGID
2654	{"getegid",	posix_getegid, 0, posix_getegid__doc__},
2655#endif /* HAVE_GETEGID */
2656#ifdef HAVE_GETEUID
2657	{"geteuid",	posix_geteuid, 0, posix_geteuid__doc__},
2658#endif /* HAVE_GETEUID */
2659#ifdef HAVE_GETGID
2660	{"getgid",	posix_getgid, 0, posix_getgid__doc__},
2661#endif /* HAVE_GETGID */
2662	{"getpid",	posix_getpid, 0, posix_getpid__doc__},
2663#ifdef HAVE_GETPGRP
2664	{"getpgrp",	posix_getpgrp, 0, posix_getpgrp__doc__},
2665#endif /* HAVE_GETPGRP */
2666#ifdef HAVE_GETPPID
2667	{"getppid",	posix_getppid, 0, posix_getppid__doc__},
2668#endif /* HAVE_GETPPID */
2669#ifdef HAVE_GETUID
2670	{"getuid",	posix_getuid, 0, posix_getuid__doc__},
2671#endif /* HAVE_GETUID */
2672#ifdef HAVE_KILL
2673	{"kill",	posix_kill, 0, posix_kill__doc__},
2674#endif /* HAVE_KILL */
2675#ifdef HAVE_PLOCK
2676	{"plock",	posix_plock, 0, posix_plock__doc__},
2677#endif /* HAVE_PLOCK */
2678#ifdef HAVE_POPEN
2679	{"popen",	posix_popen, 1, posix_popen__doc__},
2680#endif /* HAVE_POPEN */
2681#ifdef HAVE_SETUID
2682	{"setuid",	posix_setuid, 0, posix_setuid__doc__},
2683#endif /* HAVE_SETUID */
2684#ifdef HAVE_SETGID
2685	{"setgid",	posix_setgid, 0, posix_setgid__doc__},
2686#endif /* HAVE_SETGID */
2687#ifdef HAVE_SETPGRP
2688	{"setpgrp",	posix_setpgrp, 0, posix_setpgrp__doc__},
2689#endif /* HAVE_SETPGRP */
2690#ifdef HAVE_WAIT
2691	{"wait",	posix_wait, 0, posix_wait__doc__},
2692#endif /* HAVE_WAIT */
2693#ifdef HAVE_WAITPID
2694	{"waitpid",	posix_waitpid, 0, posix_waitpid__doc__},
2695#endif /* HAVE_WAITPID */
2696#ifdef HAVE_SETSID
2697	{"setsid",	posix_setsid, 0, posix_setsid__doc__},
2698#endif /* HAVE_SETSID */
2699#ifdef HAVE_SETPGID
2700	{"setpgid",	posix_setpgid, 0, posix_setpgid__doc__},
2701#endif /* HAVE_SETPGID */
2702#ifdef HAVE_TCGETPGRP
2703	{"tcgetpgrp",	posix_tcgetpgrp, 0, posix_tcgetpgrp__doc__},
2704#endif /* HAVE_TCGETPGRP */
2705#ifdef HAVE_TCSETPGRP
2706	{"tcsetpgrp",	posix_tcsetpgrp, 0, posix_tcsetpgrp__doc__},
2707#endif /* HAVE_TCSETPGRP */
2708	{"open",	posix_open, 1, posix_open__doc__},
2709	{"close",	posix_close, 0, posix_close__doc__},
2710	{"dup",		posix_dup, 0, posix_dup__doc__},
2711	{"dup2",	posix_dup2, 0, posix_dup2__doc__},
2712	{"lseek",	posix_lseek, 0, posix_lseek__doc__},
2713	{"read",	posix_read, 0, posix_read__doc__},
2714	{"write",	posix_write, 0, posix_write__doc__},
2715	{"fstat",	posix_fstat, 0, posix_fstat__doc__},
2716	{"fdopen",	posix_fdopen,	1, posix_fdopen__doc__},
2717#ifdef HAVE_PIPE
2718	{"pipe",	posix_pipe, 0, posix_pipe__doc__},
2719#endif
2720#ifdef HAVE_MKFIFO
2721	{"mkfifo",	posix_mkfifo, 1, posix_mkfifo__doc__},
2722#endif
2723#ifdef HAVE_FTRUNCATE
2724	{"ftruncate",	posix_ftruncate, 1, posix_ftruncate__doc__},
2725#endif
2726#ifdef HAVE_PUTENV
2727	{"putenv",	posix_putenv, 1, posix_putenv__doc__},
2728#endif
2729#ifdef HAVE_STRERROR
2730	{"strerror",	posix_strerror, 1, posix_strerror__doc__},
2731#endif
2732#ifdef HAVE_SYS_WAIT_H
2733#ifdef WIFSTOPPED
2734        {"WIFSTOPPED",	posix_WIFSTOPPED, 0, posix_WIFSTOPPED__doc__},
2735#endif /* WIFSTOPPED */
2736#ifdef WIFSIGNALED
2737        {"WIFSIGNALED",	posix_WIFSIGNALED, 0, posix_WIFSIGNALED__doc__},
2738#endif /* WIFSIGNALED */
2739#ifdef WIFEXITED
2740        {"WIFEXITED",	posix_WIFEXITED, 0, posix_WIFEXITED__doc__},
2741#endif /* WIFEXITED */
2742#ifdef WEXITSTATUS
2743        {"WEXITSTATUS",	posix_WEXITSTATUS, 0, posix_WEXITSTATUS__doc__},
2744#endif /* WEXITSTATUS */
2745#ifdef WTERMSIG
2746        {"WTERMSIG",	posix_WTERMSIG, 0, posix_WTERMSIG__doc__},
2747#endif /* WTERMSIG */
2748#ifdef WSTOPSIG
2749        {"WSTOPSIG",	posix_WSTOPSIG, 0, posix_WSTOPSIG__doc__},
2750#endif /* WSTOPSIG */
2751#endif /* HAVE_SYS_WAIT_H */
2752	{NULL,		NULL}		 /* Sentinel */
2753};
2754
2755
2756static int
2757ins(d, symbol, value)
2758        PyObject* d;
2759        char* symbol;
2760        long value;
2761{
2762        PyObject* v = PyInt_FromLong(value);
2763        if (!v || PyDict_SetItemString(d, symbol, v) < 0)
2764                return -1;                   /* triggers fatal error */
2765
2766        Py_DECREF(v);
2767        return 0;
2768}
2769
2770#if defined(PYOS_OS2)
2771/* Insert Platform-Specific Constant Values (Strings & Numbers) of Common Use */
2772static int insertvalues(PyObject *d)
2773{
2774    APIRET    rc;
2775    ULONG     values[QSV_MAX+1];
2776    PyObject *v;
2777    char     *ver, tmp[10];
2778
2779    Py_BEGIN_ALLOW_THREADS
2780    rc = DosQuerySysInfo(1, QSV_MAX, &values[1], sizeof(values));
2781    Py_END_ALLOW_THREADS
2782
2783    if (rc != NO_ERROR) {
2784        os2_error(rc);
2785        return -1;
2786    }
2787
2788    if (ins(d, "meminstalled", values[QSV_TOTPHYSMEM])) return -1;
2789    if (ins(d, "memkernel",    values[QSV_TOTRESMEM])) return -1;
2790    if (ins(d, "memvirtual",   values[QSV_TOTAVAILMEM])) return -1;
2791    if (ins(d, "maxpathlen",   values[QSV_MAX_PATH_LENGTH])) return -1;
2792    if (ins(d, "maxnamelen",   values[QSV_MAX_COMP_LENGTH])) return -1;
2793    if (ins(d, "revision",     values[QSV_VERSION_REVISION])) return -1;
2794    if (ins(d, "timeslice",    values[QSV_MIN_SLICE])) return -1;
2795
2796    switch (values[QSV_VERSION_MINOR]) {
2797    case 0:  ver = "2.00"; break;
2798    case 10: ver = "2.10"; break;
2799    case 11: ver = "2.11"; break;
2800    case 30: ver = "3.00"; break;
2801    case 40: ver = "4.00"; break;
2802    case 50: ver = "5.00"; break;
2803    default:
2804        sprintf(tmp, "%d-%d", values[QSV_VERSION_MAJOR],
2805                              values[QSV_VERSION_MINOR]);
2806        ver = &tmp[0];
2807    }
2808
2809    /* Add Indicator of the Version of the Operating System */
2810    v = PyString_FromString(ver);
2811    if (!v || PyDict_SetItemString(d, "version", v) < 0)
2812        return -1;
2813    Py_DECREF(v);
2814
2815    /* Add Indicator of Which Drive was Used to Boot the System */
2816    tmp[0] = 'A' + values[QSV_BOOT_DRIVE] - 1;
2817    tmp[1] = ':';
2818    tmp[2] = '\0';
2819
2820    v = PyString_FromString(tmp);
2821    if (!v || PyDict_SetItemString(d, "bootdrive", v) < 0)
2822        return -1;
2823    Py_DECREF(v);
2824
2825    return 0;
2826}
2827#endif
2828
2829static int
2830all_ins(d)
2831        PyObject* d;
2832{
2833#ifdef WNOHANG
2834        if (ins(d, "WNOHANG", (long)WNOHANG)) return -1;
2835#endif
2836#ifdef O_RDONLY
2837        if (ins(d, "O_RDONLY", (long)O_RDONLY)) return -1;
2838#endif
2839#ifdef O_WRONLY
2840        if (ins(d, "O_WRONLY", (long)O_WRONLY)) return -1;
2841#endif
2842#ifdef O_RDWR
2843        if (ins(d, "O_RDWR", (long)O_RDWR)) return -1;
2844#endif
2845#ifdef O_NDELAY
2846        if (ins(d, "O_NDELAY", (long)O_NDELAY)) return -1;
2847#endif
2848#ifdef O_NONBLOCK
2849        if (ins(d, "O_NONBLOCK", (long)O_NONBLOCK)) return -1;
2850#endif
2851#ifdef O_APPEND
2852        if (ins(d, "O_APPEND", (long)O_APPEND)) return -1;
2853#endif
2854#ifdef O_DSYNC
2855        if (ins(d, "O_DSYNC", (long)O_DSYNC)) return -1;
2856#endif
2857#ifdef O_RSYNC
2858        if (ins(d, "O_RSYNC", (long)O_RSYNC)) return -1;
2859#endif
2860#ifdef O_SYNC
2861        if (ins(d, "O_SYNC", (long)O_SYNC)) return -1;
2862#endif
2863#ifdef O_NOCTTY
2864        if (ins(d, "O_NOCTTY", (long)O_NOCTTY)) return -1;
2865#endif
2866#ifdef O_CREAT
2867        if (ins(d, "O_CREAT", (long)O_CREAT)) return -1;
2868#endif
2869#ifdef O_EXCL
2870        if (ins(d, "O_EXCL", (long)O_EXCL)) return -1;
2871#endif
2872#ifdef O_TRUNC
2873        if (ins(d, "O_TRUNC", (long)O_TRUNC)) return -1;
2874#endif
2875#ifdef O_BINARY
2876        if (ins(d, "O_BINARY", (long)O_BINARY)) return -1;
2877#endif
2878#ifdef O_TEXT
2879        if (ins(d, "O_TEXT", (long)O_TEXT)) return -1;
2880#endif
2881
2882#if defined(PYOS_OS2)
2883        if (insertvalues(d)) return -1;
2884#endif
2885        return 0;
2886}
2887
2888
2889#if ( defined(_MSC_VER) || defined(__WATCOMC__) ) && !defined(__QNX__)
2890#define INITFUNC initnt
2891#define MODNAME "nt"
2892#else
2893#if defined(PYOS_OS2)
2894#define INITFUNC initos2
2895#define MODNAME "os2"
2896#else
2897#define INITFUNC initposix
2898#define MODNAME "posix"
2899#endif
2900#endif
2901
2902DL_EXPORT(void)
2903INITFUNC()
2904{
2905	PyObject *m, *d, *v;
2906
2907	m = Py_InitModule4(MODNAME,
2908			   posix_methods,
2909			   posix__doc__,
2910			   (PyObject *)NULL,
2911			   PYTHON_API_VERSION);
2912	d = PyModule_GetDict(m);
2913
2914	/* Initialize environ dictionary */
2915	v = convertenviron();
2916	if (v == NULL || PyDict_SetItemString(d, "environ", v) != 0)
2917		return;
2918	Py_DECREF(v);
2919
2920        if (all_ins(d))
2921                return;
2922
2923	Py_INCREF(PyExc_OSError);
2924	PosixError = PyExc_OSError;
2925	PyDict_SetItemString(d, "error", PosixError);
2926}
2927