ref	-D_def_map_ast=1

cmd	universe

sys	mman
hdr	fcntl,dirent,direntry,filio,fmtmsg,fnmatch,jioctl,libgen,limits
hdr	locale,ndir,nl_types,process,spawn,utime
hdr	linux/fs,linux/msdos_fs
hdr	wctype
hdr	wchar note{ <wchar.h> and isw*() really work }end execute{
	#include <wchar.h>
	#if _hdr_wctype
	#include <wctype.h>
	#endif
	int
	main(void)
	{
		wchar_t	w = 'a';
		return iswalnum(w) == 0;
	}
}end

dat	_tzname,tzname

lib	BSDsetpgrp
lib	_cleanup
lib	bcopy,bzero,confstr,dirread
lib	fchmod,fcntl,fmtmsg,fnmatch,fork,fsync
lib	getconf,getdents,getdirentries,getdtablesize
lib	gethostname,getpagesize,getrlimit,getuniverse
lib	glob,iswblank,iswctype,killpg,link,localeconv,madvise
lib	mbtowc,mbrtowc,memalign,memdup
lib	mkdir,mkfifo,mktemp,mktime
lib	mount,opendir,pathconf
lib	readlink,remove,rename,rewinddir,rmdir,setlocale
lib	setpgrp,setpgrp2,setreuid,setuid,sigaction
lib	sigprocmask,sigsetmask,sigunblock,sigvec,socketpair
lib	spawn,spawnve
lib	strcoll,strdup,strerror,strcasecmp,strncasecmp,strlcat,strlcpy
lib	strmode,strxfrm,strftime,swab,symlink,sysconf,sysinfo
lib	telldir,tmpnam,tzset,universe,unlink,utime,wctype
lib	ftruncate,truncate

lib,npt	strtod,strtold,strtol,strtoll,strtoul,strtoull stdlib.h
lib,npt	sigflag signal.h

mem	direct.d_reclen sys/types.h sys/dir.h
mem	dirent.d_fileno,dirent.d_ino,dirent.d_namlen,dirent.d_off,dirent.d_reclen,dirent.d_type sys/types.h dirent.h
mem	DIR sys/types.h - dirent.h - sys/dir.h
mem	DIR.dd_fd sys/types.h - dirent.h - sys/dir.h
mem	inheritance.pgroup spawn.h
mem	tm.tm_zone time.h

sys	dir,filio,ioctl,jioctl,localedef,ptem,resource
sys	socket,stream,systeminfo,universe

tst	tst_errno note{ errno can be assigned }end link{
	#define error		______error
	#define strerror	______strerror
	#include <errno.h>
	#undef	error
	#undef	strerror
	#ifndef errno
	extern int errno;
	#endif
	void error(void) { }
	void strerror(void) { }
	int main(void) { errno = 0; error(); strerror(); return 0; }
}end

tst	lib_poll note{ poll() args comply with the POSIX standard }end execute{
	#include <poll.h>
	#include <unistd.h>
	extern int	pipe(int*);
	int
	main(void)
	{	int		rw[2];
		struct pollfd	fd;
		if (pipe(rw) < 0) return 1;
		fd.fd = rw[0];
		fd.events = POLLIN;
		fd.revents = 0;
		if (poll(&fd, 1, 0) < 0 || fd.revents != 0) return 1;
		if (write(rw[1], "x", 1) != 1) return 1;
		if (poll(&fd, 1, 0) < 0 || fd.revents == 0) return 1;
		return 0;
	}
}end

tst	lib_poll_notimer note{ poll with no fds ignores timeout }end execute{
	#include <sys/types.h>
	#include <poll.h>
	extern time_t	time(time_t*);
	#define TIMEOUT		4
	int
	main(void)
	{
		unsigned long	start;
		unsigned long	finish;
		struct pollfd	fd;
		start = time(NULL);
		if (poll(&fd, 0, TIMEOUT * 1000) < 0)
			return 0;
		finish = time(NULL);
		return (finish - start) > (TIMEOUT / 2);
	}
}end

tst	lib_select sys/select.h note{ select() has standard 5 arg interface }end link{
	#include <sys/types.h>
	#include <sys/time.h>
	#include <sys/socket.h>
	int
	main(void)
	{	struct timeval	tmb;
		fd_set		rd;
		FD_ZERO(&rd);
		FD_SET(0,&rd);
		tmb.tv_sec = 0;
		tmb.tv_usec = 0;
		select(1,&rd,NULL,NULL,&tmb);
		return 0;
	}
}end

tst	sys_select note{ select() requires <sys/select.h> }end link{
	#include <sys/select.h>
	int
	main(void)
	{	struct timeval	tmb;
		fd_set		rd;
		FD_ZERO(&rd);
		FD_SET(0,&rd);
		tmb.tv_sec = 0;
		tmb.tv_usec = 0;
		select(1,&rd,NULL,NULL,&tmb);
		return 0;
	}
}end

tst	pipe_rw note{ full duplex pipes }end execute{
	extern int	pipe(int*);
	extern int	read(int, void*, int);
	extern int	strcmp(const char*, const char*);
	extern int	write(int, void*, int);
	int
	main(void)
	{
	#if defined(__sgi) || defined(_sgi) || defined(sgi)
		/* boot tuneable pipes force one way for bin compatibility */
		return 1;
	#else
		static char	test[] = "test\n";
		int		io[2];
		char		buf[sizeof(test)];
		if (pipe(io)) return 1;
		if (write(io[1], test, sizeof(test)) != sizeof(test)) return 1;
		if (read(io[0], buf, sizeof(test)) != sizeof(test)) return 1;
		if (strcmp(test, buf)) return 1;
		if (write(io[0], test, sizeof(test)) != sizeof(test)) return 1;
		if (read(io[1], buf, sizeof(test)) != sizeof(test)) return 1;
		if (strcmp(test, buf)) return 1;
		return 0;
	#endif
	}
}end

tst	lib_posix_spawn unistd.h stdlib.h spawn.h -Dfork=______fork note{ posix_spawn exists, it works and it's worth using }end status{
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <sys/wait.h>
	#include <spawn.h>
	#include <signal.h>
	#include <fcntl.h>
	#include <string.h>
	/* if it uses fork() why bother? */
	#undef fork
	pid_t fork(void) { NOTE("uses fork()"); return -1; }
	pid_t _fork(void) { NOTE("uses _fork()"); return -1; }
	pid_t __fork(void) { NOTE("uses __fork()"); return -1; }
	int
	main(int argc, char **argv)
	{
		char*			s;
		pid_t			pid;
		posix_spawnattr_t	attr;
		int			n;
		int			status;
		char*			cmd[3];
		char			tmp[1024];
		if (argv[1])
			_exit(signal(SIGHUP, SIG_DFL) != SIG_IGN);
		signal(SIGHUP, SIG_IGN);
		if (posix_spawnattr_init(&attr))
		{
			NOTE("posix_spawnattr_init() FAILED");
			_exit(0);
		}
		if (posix_spawnattr_setpgroup(&attr, 0))
		{
			NOTE("posix_spawnattr_setpgroup() FAILED");
			_exit(0);
		}
		if (posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP))
		{
			NOTE("posix_spawnattr_setflags() FAILED");
			_exit(0);
		}
		/* first try an a.out and verify that SIGHUP is ignored */
		cmd[0] = argv[0];
		cmd[1] = "test";
		cmd[2] = 0;
		if (posix_spawn(&pid, cmd[0], 0, &attr, cmd, 0))
		{
			NOTE("posix_spawn() FAILED");
			_exit(0);
		}
		status = 1;
		if (wait(&status) < 0)
		{
			NOTE("wait() FAILED");
			_exit(0);
		}
		if (status != 0)
		{
			NOTE("SIGHUP ignored in parent not ignored in child");
			_exit(0);
		}
		/* must return exec-type errors or it's useless to us *unless* there is no [v]fork() */
		n = strlen(cmd[0]);
		if (n >= (sizeof(tmp) - 3))
		{
			NOTE("test executable path too long");
			_exit(0);
		}
		strcpy(tmp, cmd[0]);
		tmp[n] = '.';
		tmp[n+1] = 's';
		tmp[n+2] = 'h';
		tmp[n+3] = 0;
		if ((n = open(tmp, O_CREAT|O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO)) < 0 ||
		    chmod(tmp, S_IRWXU|S_IRWXG|S_IRWXO) < 0 ||
		    write(n, "exit 99\n", 8) != 8 ||
		    close(n) < 0)
		{
			NOTE("test script create FAILED");
			_exit(0);
		}
		cmd[0] = tmp;
		n = 0; /* 0 means reject */
		pid = -1;
		if (posix_spawn(&pid, cmd[0], 0, &attr, cmd, 0))
		{
			n = 2;
			NOTE("ENOEXEC produces posix_spawn() error (BEST)");
		}
		else if (pid == -1)
			NOTE("ENOEXEC returns pid == -1");
		else if (wait(&status) != pid)
			NOTE("ENOEXEC produces no child process");
		else if (!WIFEXITED(status))
			NOTE("ENOEXEC produces signal exit");
		else
		{
			status = WEXITSTATUS(status);
			if (status == 127)
			{
				n = 1;
				NOTE("ENOEXEC produces exit status 127 (GOOD)");
			}
			else if (status == 99)
				NOTE("ENOEXEC invokes sh");
			else if (status == 0)
				NOTE("ENOEXEC reports no error");
		}
		_exit(n);
 	}
}end
lib	posix_spawn_file_actions_addtcsetpgrp_np

tst	lib_spawn_mode unistd.h stdlib.h note{ first spawn arg is mode and it works }end execute{
	#include <signal.h>
	#include <process.h>
	#ifndef P_NOWAIT
	#define P_NOWAIT _P_NOWAIT
	#endif
	int
	main(int argc, char **argv)
	{
		int	status;
		char*	cmd[3];
		if (argv[1])
			_exit(signal(SIGHUP, SIG_DFL) != SIG_IGN);
		signal(SIGHUP, SIG_IGN);
		cmd[0] = argv[0];
		cmd[1] = "test";
		cmd[2] = 0;
		if (spawnv(P_NOWAIT, cmd[0], cmd) < 0)
			_exit(1);
		status = 1;
		_exit(wait(&status) < 0 || status != 0);
	}
}end

tst	stream_peek note{ ioctl(I_PEEK) works on pipe() }end execute{
	#include <sys/types.h>
	#include <unistd.h>
	#include <stropts.h>
	int
	main(void)
	{	struct strpeek	peek;
		int		fds[2];
		char		ctlbuf[32];
		char		databuf[32];
		peek.flags = 0;
		peek.ctlbuf.maxlen = peek.ctlbuf.len = sizeof(ctlbuf);
		peek.ctlbuf.buf = ctlbuf;
		peek.databuf.maxlen = peek.databuf.len = sizeof(databuf);
		peek.databuf.buf = databuf;
		pipe(fds);
		return ioctl(fds[0],I_PEEK,&peek) < 0;
	}
}end

tst	socket_peek note{ recv(MSG_PEEK) works on socketpair() }end execute{
	#include <unistd.h>
	#include <sys/types.h>
	#include <sys/socket.h>
	int
	main(void)
	{	
		int		i;
		int		fds[2];
		char		buf[128];

		static char	msg[] = "abcd";

	#ifdef __HAIKU__
		/* On Haiku this test will either fail (without additional LDFLAGS),
		   or with -lnetwork it will lock up. */
		return 1;
	#else
		if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
			return 1;
		if (write(fds[1], msg, sizeof(msg)) != sizeof(msg))
				return 1;
		if (recv(fds[0], buf, sizeof(buf), MSG_PEEK) != sizeof(msg))
			return 1;
		for (i = 0; i < sizeof(msg); i++)
			if (buf[i] != msg[i])
				return 1;
		if (read(fds[0], buf, sizeof(msg)) != sizeof(msg))
			return 1;
		for (i = 0; i < sizeof(msg); i++)
			if (buf[i] != msg[i])
				return 1;
		return 0;
	#endif
	}
}end

tst	lib_utime_now note{ utime works with 0 time vector }end execute{
	#include <sys/types.h>
	extern int	utime(const char*, void*);
	int
	main(void)
	{
		return utime(".", NULL) == -1;
	}
}end

tst	cross{
	u=att
	case `/bin/cat -s /dev/null/foo 2>&1` in
	'')	;;
	*)	case `/bin/echo '\\t'` in
		'\t')	u=ucb ;;
		esac
		;;
	esac
	echo "#define _UNIV_DEFAULT	\"$u\"	/* default universe name */"
}end

std	cleanup note{ stuck with standard _cleanup }end noexecute{
	extern void exit(int);
	extern void _exit(int);
	extern void _cleanup(void);
	void _cleanup(void) { _exit(0); }
	int main(void) { printf("cleanup\n"); exit(1); }
}end

std	remove note{ stuck with standard remove() }end nostatic{
	extern int unlink(const char*);
	int remove(const char* path) { return 0; }
	int main(void) { return unlink("foo"); }
}end

std	signal note{ stuck with standard signal }end nolink{
	extern void abort(void);
	int signal(void) { return 0; }
	int main(void) { signal(); abort(); return 0; }
}end

std	strcoll note{ standard strcoll works }end execute{
	#include <string.h>
	#define S	"hello world"
	int
	main(void)
	{
		char	s[] = S;
		char	t[] = S;
		return strcoll(s, t) || strcmp(s, t);
	}
}end

std	strtod stdlib.h note{ stuck with standard strtod }end nostatic{
	double strtod(const char* s, char** e) { return 0.0; }
	int main(void) { printf(""); return strtod("1",0) != 0; }
}end

std	strtold stdlib.h note{ stuck with standard strtold }end nostatic{
	long double strtold(const char* s, char** e) { return 0.0; }
	int main(void) { printf(""); return strtold("1",0) != 0; }
}end

std	strtol note{ stuck with standard strtol }end nostatic{
	extern long atol(const char*);
	long strtol(const char* s, char** e, int b) { return 0; }
	int main(void) { printf(""); return (atol("1") + strtol("1",NULL,0)) != 0; }
}end

tst	- output{
	int
	main(void)
	{
	#if _lib_posix_spawn || _lib_spawn_mode || _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance
		printf("#if !_AST_no_spawnveg\n");
		printf("#define _use_spawnveg	1\n");
		printf("#endif\n");
		printf("\n");
	#endif

		return 0;
	}

}end fail{
	echo "$0: Output block failed to compile. Export IFFEFLAGS=-d1 to debug." >&2
	exit 1
}end
