Index: /trunk/src/kash/Makefile.kmk
===================================================================
--- /trunk/src/kash/Makefile.kmk	(revision 1205)
+++ /trunk/src/kash/Makefile.kmk	(revision 1206)
@@ -49,4 +49,5 @@
 	miscbltin.c \
 	bltin/echo.c \
+	bltin/test.c \
 	\
 	jobs.c \
@@ -56,5 +57,4 @@
 	var.c \
 	bltin/kill.c \
-	bltin/test.c \
 	$(PATH_TARGET)/arith.c \
 	$(PATH_TARGET)/arith_lex.c \
Index: /trunk/src/kash/bltin/echo.c
===================================================================
--- /trunk/src/kash/bltin/echo.c	(revision 1205)
+++ /trunk/src/kash/bltin/echo.c	(revision 1206)
@@ -52,5 +52,6 @@
  */
 
-#include "bltin.h"
+#include "shinstance.h"
+#include "builtins.h"
 
 int
Index: /trunk/src/kash/bltin/test.c
===================================================================
--- /trunk/src/kash/bltin/test.c	(revision 1205)
+++ /trunk/src/kash/bltin/test.c	(revision 1206)
@@ -18,17 +18,16 @@
 #endif
 
-#include <sys/stat.h>
 #include <sys/types.h>
 
 #include <ctype.h>
-#ifndef __sun__
-#include <err.h>
-#endif
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #include <stdarg.h>
+
+#include "error.h"
+#include "shinstance.h"
+
 
 /* test(1) accepts the following grammar:
@@ -146,58 +145,30 @@
 };
 
-static char **t_wp;
-static struct t_op const *t_wp_op;
-
-static void syntax(const char *, const char *);
-static int oexpr(enum token);
-static int aexpr(enum token);
-static int nexpr(enum token);
-static int primary(enum token);
-static int binop(void);
-static int filstat(char *, enum token);
-static enum token t_lex(char *);
-static int isoperand(void);
-static int getn(const char *);
-static int newerf(const char *, const char *);
-static int olderf(const char *, const char *);
-static int equalf(const char *, const char *);
-
-#if defined(SHELL)
-extern void error(const char *, ...) __attribute__((__noreturn__));
-#else
-static void error(const char *, ...) __attribute__((__noreturn__));
-
-static void
-error(const char *msg, ...)
-{
-	va_list ap;
-
-	va_start(ap, msg);
-	verrx(2, msg, ap);
-	/*NOTREACHED*/
-	va_end(ap);
-}
-#endif
-
-#ifdef SHELL
-int testcmd(int, char **);
+//static char **t_wp;
+//static struct t_op const *t_wp_op;
+
+static void syntax(shinstance *, const char *, const char *);
+static int oexpr(shinstance *, enum token);
+static int aexpr(shinstance *, enum token);
+static int nexpr(shinstance *, enum token);
+static int primary(shinstance *, enum token);
+static int binop(shinstance *);
+static int filstat(shinstance *, char *, enum token);
+static enum token t_lex(shinstance *, char *);
+static int isoperand(shinstance *);
+static int getn(shinstance *, const char *);
+static int newerf(shinstance *, const char *, const char *);
+static int olderf(shinstance *, const char *, const char *);
+static int equalf(shinstance *, const char *, const char *);
+
 
 int
-testcmd(int argc, char **argv)
-#else
-int main(int, char *[]);
-
-int
-main(int argc, char *argv[])
-#endif
+testcmd(shinstance *psh, int argc, char **argv)
 {
 	int res;
 
-#ifdef HAVE_SETPROGNAME
-	setprogname(argv[0]);
-#endif
 	if (strcmp(argv[0], "[") == 0) {
 		if (strcmp(argv[--argc], "]"))
-			error("missing ]");
+			error(psh, "missing ]");
 		argv[argc] = NULL;
 	}
@@ -206,9 +177,10 @@
 		return 1;
 
-	t_wp = &argv[1];
-	res = !oexpr(t_lex(*t_wp));
-
-	if (*t_wp != NULL && *++t_wp != NULL)
-		syntax(*t_wp, "unexpected operator");
+	psh->t_wp_op = NULL;
+	psh->t_wp = &argv[1];
+	res = !oexpr(psh, t_lex(psh, *psh->t_wp));
+
+	if (*psh->t_wp != NULL && *++psh->t_wp != NULL)
+		syntax(psh, *psh->t_wp, "unexpected operator");
 
 	return res;
@@ -216,48 +188,48 @@
 
 static void
-syntax(const char *op, const char *msg)
+syntax(shinstance *psh, const char *op, const char *msg)
 {
 
 	if (op && *op)
-		error("%s: %s", op, msg);
+		error(psh, "%s: %s", op, msg);
 	else
-		error("%s", msg);
-}
-
-static int
-oexpr(enum token n)
+		error(psh, "%s", msg);
+}
+
+static int
+oexpr(shinstance *psh, enum token n)
 {
 	int res;
 
-	res = aexpr(n);
-	if (t_lex(*++t_wp) == BOR)
-		return oexpr(t_lex(*++t_wp)) || res;
-	t_wp--;
+	res = aexpr(psh, n);
+	if (t_lex(psh, *++psh->t_wp) == BOR)
+		return oexpr(psh, t_lex(psh, *++psh->t_wp)) || res;
+	psh->t_wp--;
 	return res;
 }
 
 static int
-aexpr(enum token n)
+aexpr(shinstance *psh, enum token n)
 {
 	int res;
 
-	res = nexpr(n);
-	if (t_lex(*++t_wp) == BAND)
-		return aexpr(t_lex(*++t_wp)) && res;
-	t_wp--;
+	res = nexpr(psh, n);
+	if (t_lex(psh, *++psh->t_wp) == BAND)
+		return aexpr(psh, t_lex(psh, *++psh->t_wp)) && res;
+	psh->t_wp--;
 	return res;
 }
 
 static int
-nexpr(enum token n)
+nexpr(shinstance *psh, enum token n)
 {
 
 	if (n == UNOT)
-		return !nexpr(t_lex(*++t_wp));
-	return primary(n);
-}
-
-static int
-primary(enum token n)
+		return !nexpr(psh, t_lex(psh, *++psh->t_wp));
+	return primary(psh, n);
+}
+
+static int
+primary(shinstance *psh, enum token n)
 {
 	enum token nn;
@@ -267,46 +239,46 @@
 		return 0;		/* missing expression */
 	if (n == LPAREN) {
-		if ((nn = t_lex(*++t_wp)) == RPAREN)
+		if ((nn = t_lex(psh, *++psh->t_wp)) == RPAREN)
 			return 0;	/* missing expression */
-		res = oexpr(nn);
-		if (t_lex(*++t_wp) != RPAREN)
-			syntax(NULL, "closing paren expected");
+		res = oexpr(psh, nn);
+		if (t_lex(psh, *++psh->t_wp) != RPAREN)
+			syntax(psh, NULL, "closing paren expected");
 		return res;
 	}
-	if (t_wp_op && t_wp_op->op_type == UNOP) {
+	if (psh->t_wp_op && psh->t_wp_op->op_type == UNOP) {
 		/* unary expression */
-		if (*++t_wp == NULL)
-			syntax(t_wp_op->op_text, "argument expected");
+		if (*++psh->t_wp == NULL)
+			syntax(psh, psh->t_wp_op->op_text, "argument expected");
 		switch (n) {
 		case STREZ:
-			return strlen(*t_wp) == 0;
+			return strlen(*psh->t_wp) == 0;
 		case STRNZ:
-			return strlen(*t_wp) != 0;
+			return strlen(*psh->t_wp) != 0;
 		case FILTT:
-			return isatty(getn(*t_wp));
+			return shfile_isatty(&psh->fdtab, getn(psh, *psh->t_wp));
 		default:
-			return filstat(*t_wp, n);
+			return filstat(psh, *psh->t_wp, n);
 		}
 	}
 
-	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
-		return binop();
-	}
-
-	return strlen(*t_wp) > 0;
-}
-
-static int
-binop(void)
+	if (t_lex(psh, psh->t_wp[1]), psh->t_wp_op && psh->t_wp_op->op_type == BINOP) {
+		return binop(psh);
+	}
+
+	return strlen(*psh->t_wp) > 0;
+}
+
+static int
+binop(shinstance *psh)
 {
 	const char *opnd1, *opnd2;
 	struct t_op const *op;
 
-	opnd1 = *t_wp;
-	(void) t_lex(*++t_wp);
-	op = t_wp_op;
-
-	if ((opnd2 = *++t_wp) == NULL)
-		syntax(op->op_text, "argument expected");
+	opnd1 = *psh->t_wp;
+	(void) t_lex(psh, *++psh->t_wp);
+	op = psh->t_wp_op;
+
+	if ((opnd2 = *++psh->t_wp) == NULL)
+		syntax(psh, op->op_text, "argument expected");
 
 	switch (op->op_num) {
@@ -320,44 +292,47 @@
 		return strcmp(opnd1, opnd2) > 0;
 	case INTEQ:
-		return getn(opnd1) == getn(opnd2);
+		return getn(psh, opnd1) == getn(psh, opnd2);
 	case INTNE:
-		return getn(opnd1) != getn(opnd2);
+		return getn(psh, opnd1) != getn(psh, opnd2);
 	case INTGE:
-		return getn(opnd1) >= getn(opnd2);
+		return getn(psh, opnd1) >= getn(psh, opnd2);
 	case INTGT:
-		return getn(opnd1) > getn(opnd2);
+		return getn(psh, opnd1) > getn(psh, opnd2);
 	case INTLE:
-		return getn(opnd1) <= getn(opnd2);
+		return getn(psh, opnd1) <= getn(psh, opnd2);
 	case INTLT:
-		return getn(opnd1) < getn(opnd2);
+		return getn(psh, opnd1) < getn(psh, opnd2);
 	case FILNT:
-		return newerf(opnd1, opnd2);
+		return newerf(psh, opnd1, opnd2);
 	case FILOT:
-		return olderf(opnd1, opnd2);
+		return olderf(psh, opnd1, opnd2);
 	case FILEQ:
-		return equalf(opnd1, opnd2);
+		return equalf(psh, opnd1, opnd2);
 	default:
 		abort();
 		/* NOTREACHED */
-	}
-}
-
-static int
-filstat(char *nm, enum token mode)
+		return -1;
+	}
+}
+
+static int
+filstat(shinstance *psh, char *nm, enum token mode)
 {
 	struct stat s;
 
-	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
+	if (mode == FILSYM
+		? shfile_lstat(&psh->fdtab, nm, &s)
+		: shfile_stat(&psh->fdtab, nm, &s))
 		return 0;
 
 	switch (mode) {
 	case FILRD:
-		return access(nm, R_OK) == 0;
+		return shfile_access(&psh->fdtab, nm, R_OK) == 0;
 	case FILWR:
-		return access(nm, W_OK) == 0;
+		return shfile_access(&psh->fdtab, nm, W_OK) == 0;
 	case FILEX:
-		return access(nm, X_OK) == 0;
+		return shfile_access(&psh->fdtab, nm, X_OK) == 0;
 	case FILEXIST:
-		return access(nm, F_OK) == 0;
+		return shfile_access(&psh->fdtab, nm, F_OK) == 0;
 	case FILREG:
 		return S_ISREG(s.st_mode);
@@ -403,7 +378,7 @@
 		return s.st_size > (off_t)0;
 	case FILUID:
-		return s.st_uid == geteuid();
+		return s.st_uid == sh_geteuid(psh);
 	case FILGID:
-		return s.st_gid == getegid();
+		return s.st_gid == sh_getegid(psh);
 	default:
 		return 1;
@@ -412,5 +387,5 @@
 
 static enum token
-t_lex(char *s)
+t_lex(shinstance *psh, char *s)
 {
 	struct t_op const *op;
@@ -419,23 +394,23 @@
 
 	if (s == 0) {
-		t_wp_op = NULL;
+		psh->t_wp_op = NULL;
 		return EOI;
 	}
 	while (op->op_text) {
 		if (strcmp(s, op->op_text) == 0) {
-			if ((op->op_type == UNOP && isoperand()) ||
-			    (op->op_num == LPAREN && *(t_wp+1) == 0))
+			if ((op->op_type == UNOP && isoperand(psh)) ||
+			    (op->op_num == LPAREN && *(psh->t_wp+1) == 0))
 				break;
-			t_wp_op = op;
+			psh->t_wp_op = op;
 			return op->op_num;
 		}
 		op++;
 	}
-	t_wp_op = NULL;
+	psh->t_wp_op = NULL;
 	return OPERAND;
 }
 
 static int
-isoperand(void)
+isoperand(shinstance *psh)
 {
 	struct t_op const *op;
@@ -443,7 +418,7 @@
 
 	op = ops;
-	if ((s  = *(t_wp+1)) == 0)
+	if ((s  = *(psh->t_wp+1)) == 0)
 		return 1;
-	if ((t = *(t_wp+2)) == 0)
+	if ((t = *(psh->t_wp+2)) == 0)
 		return 0;
 	while (op->op_text) {
@@ -458,5 +433,5 @@
 /* atoi with error detection */
 static int
-getn(const char *s)
+getn(shinstance *psh, const char *s)
 {
 	char *p;
@@ -467,5 +442,5 @@
 
 	if (errno != 0)
-	      error("%s: out of range", s);
+	      error(psh, "%s: out of range", s);
 
 	while (isspace((unsigned char)*p))
@@ -473,5 +448,5 @@
 
 	if (*p)
-	      error("%s: bad number", s);
+	      error(psh, "%s: bad number", s);
 
 	return (int) r;
@@ -479,30 +454,30 @@
 
 static int
-newerf(const char *f1, const char *f2)
+newerf(shinstance *psh, const char *f1, const char *f2)
 {
 	struct stat b1, b2;
 
-	return (stat(f1, &b1) == 0 &&
-		stat(f2, &b2) == 0 &&
+	return (shfile_stat(&psh->fdtab, f1, &b1) == 0 &&
+		shfile_stat(&psh->fdtab, f2, &b2) == 0 &&
 		b1.st_mtime > b2.st_mtime);
 }
 
 static int
-olderf(const char *f1, const char *f2)
+olderf(shinstance *psh, const char *f1, const char *f2)
 {
 	struct stat b1, b2;
 
-	return (stat(f1, &b1) == 0 &&
-		stat(f2, &b2) == 0 &&
+	return (shfile_stat(&psh->fdtab, f1, &b1) == 0 &&
+		shfile_stat(&psh->fdtab, f2, &b2) == 0 &&
 		b1.st_mtime < b2.st_mtime);
 }
 
 static int
-equalf(const char *f1, const char *f2)
+equalf(shinstance *psh, const char *f1, const char *f2)
 {
 	struct stat b1, b2;
 
-	return (stat(f1, &b1) == 0 &&
-		stat(f2, &b2) == 0 &&
+	return (shfile_stat(&psh->fdtab, f1, &b1) == 0 &&
+		shfile_stat(&psh->fdtab, f2, &b2) == 0 &&
 		b1.st_dev == b2.st_dev &&
 		b1.st_ino == b2.st_ino);
Index: /trunk/src/kash/shfile.h
===================================================================
--- /trunk/src/kash/shfile.h	(revision 1205)
+++ /trunk/src/kash/shfile.h	(revision 1206)
@@ -29,4 +29,53 @@
 
 #include "shtypes.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifndef _MSC_VER
+# include <sys/fcntl.h>
+# include <unistd.h>
+# ifndef O_BINARY
+#  define O_BINARY  0
+# endif
+# ifndef O_TEXT
+#  define O_TEXT    0
+# endif
+
+#else
+# include <io.h>
+# include <direct.h>
+
+# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
+# define S_ISLNK(m) 0
+# define S_IRWXU    (_S_IREAD | _S_IWRITE | _S_IEXEC)
+# define S_IXUSR    _S_IEXEC
+# define S_IWUSR    _S_IWRITE
+# define S_IRUSR    _S_IREAD
+# define S_IRWXG    0000070
+# define S_IRGRP    0000040
+# define S_IWGRP    0000020
+# define S_IXGRP    0000010
+# define S_IRWXO    0000007
+# define S_IROTH    0000004
+# define S_IWOTH    0000002
+# define S_IXOTH    0000001
+# define S_ISUID    0004000
+# define S_ISGID    0002000
+# define ALLPERMS   0000777
+
+# define F_DUPFD    0
+# define F_GETFD    1
+# define F_SETFD    2
+# define F_GETFL    3
+# define F_SETFL    4
+# define FD_CLOEXEC 1
+
+# define F_OK       0
+# define X_OK       1
+# define W_OK       2
+# define R_OK       4
+
+#endif
+
 
 /**
@@ -51,5 +100,4 @@
 } shfdtab;
 
-
 int shfile_open(shfdtab *, const char *, unsigned);
 int shfile_pipe(shfdtab *, int [2]);
@@ -59,14 +107,4 @@
 long shfile_lseek(shfdtab *, int, long, int);
 int shfile_fcntl(shfdtab *, int fd, int cmd, int arg);
-#ifdef _MSC_VER
-# define F_DUPFD    0
-# define F_GETFD    1
-# define F_SETFD    2
-# define F_GETFL    3
-# define F_SETFL    4
-# define FD_CLOEXEC 1
-#else
-# include <sys/fcntl.h>
-#endif
 
 int shfile_stat(shfdtab *, const char *, struct stat *);
@@ -75,5 +113,6 @@
 char *shfile_getcwd(shfdtab *, char *, int);
 int shfile_isatty(shfdtab *, int);
-/*int shfile_ioctl(shfdtab *, int, unsigned long, char *);*/
+int shfile_ioctl(shfdtab *, int, unsigned long, char *);
+int shfile_access(shfdtab *, const char *, int);
 
 #endif
Index: /trunk/src/kash/shinstance.h
===================================================================
--- /trunk/src/kash/shinstance.h	(revision 1205)
+++ /trunk/src/kash/shinstance.h	(revision 1206)
@@ -258,4 +258,8 @@
     int                 nmboxes;        /**< number of mailboxes */
     time_t              mailtime[MAXMBOXES]; /**< times of mailboxes */
+
+    /* bltin/test.c */
+    char              **t_wp;
+    struct t_op const  *t_wp_op;
 
 } shinstance;
@@ -323,4 +327,8 @@
 void sh__exit(shinstance *, int);
 int sh_execve(shinstance *, const char *, const char * const*, const char * const *);
-
-#endif
+uid_t sh_getuid(shinstance *);
+uid_t sh_geteuid(shinstance *);
+gid_t sh_getgid(shinstance *);
+gid_t sh_getegid(shinstance *);
+
+#endif
Index: /trunk/src/kash/show.c
===================================================================
--- /trunk/src/kash/show.c	(revision 1205)
+++ /trunk/src/kash/show.c	(revision 1206)
@@ -382,5 +382,5 @@
 {
 	char s[100];
-#ifdef O_APPEND
+#if defined(O_APPEND) && !defined(_MSC_VER)
 	int flags;
 #endif
@@ -420,5 +420,5 @@
 		}
 	}
-#ifdef O_APPEND
+#if defined(O_APPEND) && !defined(_MSC_VER)
 	if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
 		fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
Index: /trunk/src/kash/shtypes.h
===================================================================
--- /trunk/src/kash/shtypes.h	(revision 1205)
+++ /trunk/src/kash/shtypes.h	(revision 1206)
@@ -69,4 +69,8 @@
 #define UINT64_MAX      0xffffffffffffffffULL
 
+typedef int             pid_t;
+typedef unsigned short  uid_t;
+typedef unsigned short  gid_t;
+
 #else
 # include <stdint.h>
