Initial revision
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
new file mode 100644
index 0000000..0c1a487
--- /dev/null
+++ b/Modules/posixmodule.c
@@ -0,0 +1,444 @@
+/* POSIX module implementation */
+
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#ifdef SYSV
+#include <dirent.h>
+#define direct dirent
+#else
+#include <sys/dir.h>
+#endif
+
+#include "PROTO.h"
+#include "object.h"
+#include "intobject.h"
+#include "stringobject.h"
+#include "tupleobject.h"
+#include "listobject.h"
+#include "dictobject.h"
+#include "methodobject.h"
+#include "moduleobject.h"
+#include "objimpl.h"
+#include "import.h"
+#include "sigtype.h"
+#include "modsupport.h"
+#include "errors.h"
+
+extern char *strerror();
+
+#ifdef AMOEBA
+#define NO_LSTAT
+#endif
+
+
+/* Return a dictionary corresponding to the POSIX environment table */
+
+extern char **environ;
+
+static object *
+convertenviron()
+{
+	object *d;
+	char **e;
+	d = newdictobject();
+	if (d == NULL)
+		return NULL;
+	if (environ == NULL)
+		return d;
+	/* XXX This part ignores errors */
+	for (e = environ; *e != NULL; e++) {
+		object *v;
+		char *p = strchr(*e, '=');
+		if (p == NULL)
+			continue;
+		v = newstringobject(p+1);
+		if (v == NULL)
+			continue;
+		*p = '\0';
+		(void) dictinsert(d, *e, v);
+		*p = '=';
+		DECREF(v);
+	}
+	return d;
+}
+
+
+static object *PosixError; /* Exception posix.error */
+
+/* Set a POSIX-specific error from errno, and return NULL */
+
+static object *
+posix_error()
+{
+	object *v = newtupleobject(2);
+	if (v != NULL) {
+		settupleitem(v, 0, newintobject((long)errno));
+		settupleitem(v, 1, newstringobject(strerror(errno)));
+	}
+	err_setval(PosixError, v);
+	if (v != NULL)
+		DECREF(v);
+	return NULL;
+}
+
+
+/* POSIX generic methods */
+
+static object *
+posix_1str(args, func)
+	object *args;
+	int (*func) FPROTO((const char *));
+{
+	object *path1;
+	if (!getstrarg(args, &path1))
+		return NULL;
+	if ((*func)(getstringvalue(path1)) < 0)
+		return posix_error();
+	INCREF(None);
+	return None;
+}
+
+static object *
+posix_2str(args, func)
+	object *args;
+	int (*func) FPROTO((const char *, const char *));
+{
+	object *path1, *path2;
+	if (!getstrstrarg(args, &path1, &path2))
+		return NULL;
+	if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0)
+		return posix_error();
+	INCREF(None);
+	return None;
+}
+
+static object *
+posix_strint(args, func)
+	object *args;
+	int (*func) FPROTO((const char *, int));
+{
+	object *path1;
+	int i;
+	if (!getstrintarg(args, &path1, &i))
+		return NULL;
+	if ((*func)(getstringvalue(path1), i) < 0)
+		return posix_error();
+	INCREF(None);
+	return None;
+}
+
+static object *
+posix_do_stat(self, args, statfunc)
+	object *self;
+	object *args;
+	int (*statfunc) FPROTO((const char *, struct stat *));
+{
+	struct stat st;
+	object *path;
+	object *v;
+	if (!getstrarg(args, &path))
+		return NULL;
+	if ((*statfunc)(getstringvalue(path), &st) != 0)
+		return posix_error();
+	v = newtupleobject(10);
+	if (v == NULL)
+		return NULL;
+	errno = 0;
+#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member))
+	SET(0, st_mode);
+	SET(1, st_ino);
+	SET(2, st_dev);
+	SET(3, st_nlink);
+	SET(4, st_uid);
+	SET(5, st_gid);
+	SET(6, st_size);
+	SET(7, st_atime);
+	SET(8, st_mtime);
+	SET(9, st_ctime);
+#undef SET
+	if (errno != 0) {
+		DECREF(v);
+		return err_nomem();
+	}
+	return v;
+}
+
+
+/* POSIX methods */
+
+static object *
+posix_chdir(self, args)
+	object *self;
+	object *args;
+{
+	extern int chdir PROTO((const char *));
+	return posix_1str(args, chdir);
+}
+
+static object *
+posix_chmod(self, args)
+	object *self;
+	object *args;
+{
+	extern int chmod PROTO((const char *, mode_t));
+	return posix_strint(args, chmod);
+}
+
+static object *
+posix_getcwd(self, args)
+	object *self;
+	object *args;
+{
+	char buf[1026];
+	extern char *getcwd PROTO((char *, int));
+	if (!getnoarg(args))
+		return NULL;
+	if (getcwd(buf, sizeof buf) == NULL)
+		return posix_error();
+	return newstringobject(buf);
+}
+
+static object *
+posix_link(self, args)
+	object *self;
+	object *args;
+{
+	extern int link PROTO((const char *, const char *));
+	return posix_2str(args, link);
+}
+
+static object *
+posix_listdir(self, args)
+	object *self;
+	object *args;
+{
+	object *name, *d, *v;
+	DIR *dirp;
+	struct direct *ep;
+	if (!getstrarg(args, &name))
+		return NULL;
+	if ((dirp = opendir(getstringvalue(name))) == NULL)
+		return posix_error();
+	if ((d = newlistobject(0)) == NULL) {
+		closedir(dirp);
+		return NULL;
+	}
+	while ((ep = readdir(dirp)) != NULL) {
+		v = newstringobject(ep->d_name);
+		if (v == NULL) {
+			DECREF(d);
+			d = NULL;
+			break;
+		}
+		if (addlistitem(d, v) != 0) {
+			DECREF(v);
+			DECREF(d);
+			d = NULL;
+			break;
+		}
+		DECREF(v);
+	}
+	closedir(dirp);
+	return d;
+}
+
+static object *
+posix_mkdir(self, args)
+	object *self;
+	object *args;
+{
+	extern int mkdir PROTO((const char *, mode_t));
+	return posix_strint(args, mkdir);
+}
+
+static object *
+posix_rename(self, args)
+	object *self;
+	object *args;
+{
+	extern int rename PROTO((const char *, const char *));
+	return posix_2str(args, rename);
+}
+
+static object *
+posix_rmdir(self, args)
+	object *self;
+	object *args;
+{
+	extern int rmdir PROTO((const char *));
+	return posix_1str(args, rmdir);
+}
+
+static object *
+posix_stat(self, args)
+	object *self;
+	object *args;
+{
+	extern int stat PROTO((const char *, struct stat *));
+	return posix_do_stat(self, args, stat);
+}
+
+static object *
+posix_system(self, args)
+	object *self;
+	object *args;
+{
+	object *command;
+	int sts;
+	if (!getstrarg(args, &command))
+		return NULL;
+	sts = system(getstringvalue(command));
+	return newintobject((long)sts);
+}
+
+static object *
+posix_umask(self, args)
+	object *self;
+	object *args;
+{
+	int i;
+	if (!getintarg(args, &i))
+		return NULL;
+	i = umask(i);
+	if (i < 0)
+		return posix_error();
+	return newintobject((long)i);
+}
+
+static object *
+posix_unlink(self, args)
+	object *self;
+	object *args;
+{
+	extern int unlink PROTO((const char *));
+	return posix_1str(args, unlink);
+}
+
+static object *
+posix_utimes(self, args)
+	object *self;
+	object *args;
+{
+	object *path;
+	struct timeval tv[2];
+	if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
+		err_badarg();
+		return NULL;
+	}
+	if (!getstrarg(gettupleitem(args, 0), &path) ||
+				!getlonglongargs(gettupleitem(args, 1),
+					&tv[0].tv_sec, &tv[1].tv_sec))
+		return NULL;
+	tv[0].tv_usec = tv[1].tv_usec = 0;
+	if (utimes(getstringvalue(path), tv) < 0)
+		return posix_error();
+	INCREF(None);
+	return None;
+}
+
+#ifdef NO_GETCWD
+
+/* Quick hack to get posix.getcwd() working for pure BSD 4.3 */
+/* XXX This assumes MAXPATHLEN = 1024 !!! */
+
+static char *
+getcwd(buf, size)
+	char *buf;
+	int size;
+{
+	extern char *getwd PROTO((char *));
+	register char *ret = getwd(buf);
+	if (ret == NULL)
+		errno = EACCES; /* Most likely error */
+	return ret;
+}
+
+#endif /* NO_GETCWD */
+
+
+#ifndef NO_LSTAT
+
+static object *
+posix_lstat(self, args)
+	object *self;
+	object *args;
+{
+	extern int lstat PROTO((const char *, struct stat *));
+	return posix_do_stat(self, args, lstat);
+}
+
+static object *
+posix_readlink(self, args)
+	object *self;
+	object *args;
+{
+	char buf[1024]; /* XXX Should use MAXPATHLEN */
+	object *path;
+	int n;
+	if (!getstrarg(args, &path))
+		return NULL;
+	n = readlink(getstringvalue(path), buf, sizeof buf);
+	if (n < 0)
+		return posix_error();
+	return newsizedstringobject(buf, n);
+}
+
+static object *
+posix_symlink(self, args)
+	object *self;
+	object *args;
+{
+	extern int symlink PROTO((const char *, const char *));
+	return posix_2str(args, symlink);
+}
+
+#endif /* NO_LSTAT */
+
+
+static struct methodlist posix_methods[] = {
+	{"chdir",	posix_chdir},
+	{"chmod",	posix_chmod},
+	{"getcwd",	posix_getcwd},
+	{"link",	posix_link},
+	{"listdir",	posix_listdir},
+	{"mkdir",	posix_mkdir},
+	{"rename",	posix_rename},
+	{"rmdir",	posix_rmdir},
+	{"stat",	posix_stat},
+	{"system",	posix_system},
+	{"umask",	posix_umask},
+	{"unlink",	posix_unlink},
+	{"utimes",	posix_utimes},
+#ifndef NO_LSTAT
+	{"lstat",	posix_lstat},
+	{"readlink",	posix_readlink},
+	{"symlink",	posix_symlink},
+#endif
+	{NULL,		NULL}		 /* Sentinel */
+};
+
+
+void
+initposix()
+{
+	object *m, *d, *v;
+	
+	m = initmodule("posix", posix_methods);
+	d = getmoduledict(m);
+	
+	/* Initialize posix.environ dictionary */
+	v = convertenviron();
+	if (v == NULL || dictinsert(d, "environ", v) != 0)
+		fatal("can't define posix.environ");
+	DECREF(v);
+	
+	/* Initialize posix.error exception */
+	PosixError = newstringobject("posix.error");
+	if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0)
+		fatal("can't define posix.error");
+}