ref	-D_def_map_ast=1

cmd	universe

hdr	dirent,direntry,filio,fmtmsg,fnmatch,jioctl,libgen,limits
hdr	locale,ndir,nl_types,process,syslog,utime,vfork
hdr	netdb,netinet/in
hdr	wchar note{ <wchar.h> and isw*() really work }end execute{
	#include <wchar.h>
	int
	main()
	{
		wchar_t	w = 'a';
		return iswalnum(w) == 0;
	}
}end
hdr	wctype wchar.h

dat	_tzname,tzname

if	mac AT_FDCWD fcntl.h {
}
elif	mac AT_FDCWD -D_ATFILE_SOURCE fcntl.h {
	#ifndef _ATFILE_SOURCE
	#define _ATFILE_SOURCE 1
	#endif
}
endif

lib	BSDsetpgrp
lib	_cleanup
lib	atexit,bcopy,bzero,catclose,catgets,catopen,confstr,dirread,dup2
lib	execlp,execve,execvp,execvpe
lib	fchmod,fcntl,fdopendir,fmtmsg,fnmatch,fork
lib	fsync,fdatasync,sync,syncfs
lib	getaddrinfo netdb.h netinet/in.h -lsocket
lib	getconf,getdents,getdirentries,getdtablesize,getdate
lib	getgroups,gethostname,getlogin,getpagesize,getrlimit,getuniverse
lib	getopt,getsubopt,getopt_long,getopt_long_only
lib	glob,index,iswblank,iswctype,killpg,link,localeconv,madvise
lib	htons,htonl sys/types.h sys/socket.h netinet/in.h
lib	mbtowc,mbrtowc,memalign,memchr,memcpy,memdup,memmove,memset
lib	mkdir,mkfifo,mktemp,mktime
lib	mount,on_exit,onexit,opendir,pathconf,fpathconf,pipe2,qsort,qsort_r
lib	readlink,remove,rename,rewinddir,rindex,rmdir,setlocale
lib	setpgid,setpgrp,setpgrp2,setregid,setreuid,setsid,setuid,sigaction
lib	sigprocmask,sigsetmask,sigunblock,sigvec
lib	strchr,strcoll,strdup,strerror,strcasecmp,strncasecmp,strrchr,strstr
lib	strmode,strxfrm,strftime,swab,symlink,sysconf,sysinfo,syslog
lib	stpcpy,stpncpy,strlcat,strlcpy
lib	telldir,tmpnam,tzset,universe,unlink,utime,wctype
lib	ftruncate,truncate
lib	creat64,ftruncate64,lseek64,open64,truncate64 -D_LARGEFILE64_SOURCE fcntl.h unistd.h
lib	fstat64,lstat64,stat64 -D_LARGEFILE64_SOURCE sys/stat.h
lib	fstatvfs64,statvfs64 -D_LARGEFILE64_SOURCE sys/statvfs.h
lib	fdopendir64,opendir64,readdir64,rewinddir64,seekdir64,telldir64,closedir64 -D_LARGEFILE64_SOURCE dirent.h
lib	accept4,socketpair sys/socket.h

lib	faccessat,fchmodat,fchownat,fstatat,linkat,mkdirat,mkfifoat,mknodat,openat,readlinkat,renameat,symlinkat,unlinkat -D_ATFILE_SOURCE fcntl.h unistd.h
lib	fstatat64,openat64 -D_ATFILE_SOURCE -D_LARGEFILE64_SOURCE fcntl.h unistd.h sys/stat.h

lib	lchmod note{ lchmod implemented }end execute{
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <errno.h>
	int
	main()
	{
		lchmod("No-FiLe", 0);
		return errno != ENOENT;
	}
}end

lib	lchown note{ lchown implemented }end execute{
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <errno.h>
	int
	main()
	{
		lchown("No-FiLe", 0, 0);
		return errno != ENOENT;
	}
}end

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	flock.l_type fcntl.h

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

typ	ino64_t,off64_t -D_LARGEFILE64_SOURCE
typ	struct.dirent64,DIR64 -D_LARGEFILE64_SOURCE dirent.h

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

tst	lib_poll_fd_1 note{ fd is first arg to poll() }end execute{
	#include <poll.h>
	_BEGIN_EXTERNS_
	extern int	pipe _ARG_((int*));
	_END_EXTERNS_
	int
	main()
	{	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_fd_2 note{ fd is second arg to poll() }end execute{
	#include <poll.h>
	_BEGIN_EXTERNS_
	extern int	pipe _ARG_((int*));
	_END_EXTERNS_
	int
	main()
	{	int		rw[2];
		struct pollfd	fd;
		if (pipe(rw) < 0) return 1;
		fd.fd = rw[0];
		fd.events = POLLIN;
		fd.revents = 0;
		return poll(1, &fd, 0) < 0;
		if (poll(1, &fd, 0) < 0 || fd.revents != 0) return 1;
		if (write(rw[1], "x", 1) != 1) return 1;
		if (poll(1, &fd, 0) < 0 || fd.revents == 0) return 1;
		return 0;
	}
}end

exp	_lib_poll	_lib_poll_fd_1||_lib_poll_fd_2

tst	lib_poll_notimer note{ poll with no fds ignores timeout }end execute{
	#include <sys/types.h>
	#include <poll.h>
	_BEGIN_EXTERNS_
	extern time_t	time _ARG_((time_t*));
	_END_EXTERNS_
	#define TIMEOUT		4
	int
	main()
	{
		unsigned long	start;
		unsigned long	finish;
		struct pollfd	fd;
		start = time((time_t*)0);
		if (poll(&fd, 0, TIMEOUT * 1000) < 0)
			return 0;
		finish = time((time_t*)0);
		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()
	{	struct timeval	tmb;
		fd_set		rd;
		FD_ZERO(&rd);
		FD_SET(0,&rd);
		tmb.tv_sec = 0;
		tmb.tv_usec = 0;
		select(1,&rd,(fd_set*)0,(fd_set*)0,&tmb);
		return 0;
	}
}end

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

tst	pipe_rw note{ full duplex pipes }end execute{
	_BEGIN_EXTERNS_
	extern int	pipe _ARG_((int*));
	extern int	read _ARG_((int, void*, int));
	extern int	strcmp _ARG_((const char*, const char*));
	extern int	write _ARG_((int, void*, int));
	_END_EXTERNS_
	int
	main()
	{
	#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_vfork unistd.h stdlib.h vfork.h note{ vfork exists and it works }end execute{
	#include <signal.h>
	int
	main(argc, argv)
	int	argc;
	char**	argv;
	{
		int	status;
		char*	cmd[4];
		if (argv[2])
			_exit(signal(SIGHUP, SIG_DFL) != SIG_IGN);
		signal(SIGHUP, SIG_IGN);
		switch (vfork())
		{
		case -1:
			_exit(1);
		case 0:
			cmd[0] = argv[0];
			cmd[1] = argv[1];
			cmd[2] = "test";
			cmd[3] = 0;
			execv(cmd[0], cmd);
			_exit(2);
		}
		status = 1;
		_exit(wait(&status) < 0 || status != 0);
 	}
}end
 
tst	real_vfork note{ vfork child shares data with parent }end execute{
	_BEGIN_EXTERNS_
	extern int	_exit _ARG_((int));
	extern int	vfork _ARG_((void));
	_END_EXTERNS_
	int		code;
	int
	main()
	{
		code = 1;
		if (!vfork())
			code = 0;
		_exit(code);
	}
}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()
	{	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()
	{	
		int		i;
		int		fds[2];
		char		buf[128];

		static char	msg[] = "abcd";

		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;
	}
}end

tst	lib_memcmp string.h note{ standard memcmp interface that works }end execute{
	/* sgi again -- we're sick of being their regression test */
	#define L	8
	char		a[L] = { '0' };
	char		b[L] = { '1' };
	int
	main()
	{
		return memcmp(a, b, L) >= 0;
	}
}end

tst	lib_memccpy string.h unistd.h stdlib.h fcntl.h signal.h sys/types.h sys/stat.h sys/mman.h fcntl.h note{ standard memccpy interface that works }end execute{
	#if _STD_
	static void gotcha(int sig)
	#else
	static int gotcha(sig) int sig;
	#endif
	{
		exit(1);
	}
	#ifdef MAP_PRIVATE
	static const char x[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxN";
	#if _STD_
	static int indict_sgi_ia64_4Q_2004(int n)
	#else
	static int indict_sgi_ia64_4Q_2004(n) int n;
	#endif
	{
		char*		b;
		char*		s;
		char*		e;
		char*		t;
		long		m;
		int		d;
		char		u[1024];

		static char	p[32] = {'/','t','m','p','/','m','m'};

		for (d = 7; d < 13; d++)
			p[d] = 'X';
		p[d] = 0;
		if ((d = mkstemp(p)) < 0)
			return 1;
		remove(p);
		for (m = 0; m < n; m++)
			if (write(d, x, sizeof(x)-1) != sizeof(x)-1)
			{
				close(d);
				return 1;
			}
		if (lseek(d, (off_t)0, SEEK_SET))
		{
			close(d);
			return 1;
		}
		m = n * (sizeof(x)-1);
		b = mmap((void*)0, m, PROT_READ|PROT_WRITE, MAP_PRIVATE, d, (off_t)0);
		if (b == (caddr_t)0 || b == (caddr_t)(-1))
		{
			close(d);
			return 1;
		}
		for (e = (s = b) + m; s < e && (t = memccpy(u, s, 'N', (e-s) > sizeof(u) ? sizeof(u) : (e-s))); s += (t-u))
			if ((t-u) != (sizeof(x)-1) || memcmp(u, s, t-u))
			{
				close(d);
				return 1;
			}
		if (s < e)
		{
			close(d);
			return 1;
		}
		close(d);
		return 0;
	}
	#endif

	int
	main ()
	{
		char	buf[1024];
	#ifdef MAP_PRIVATE
		char*	srcbuf;
		char*	addbuf;
		char*	dstbuf;
		int	fd;
		size_t	siz;
		int	i;
	#endif

	#if defined(__ia64) || defined(__ia64__) || defined(__itanium__)
		/*
		 * 0 faith that the itanium coders will ever get this right
		 * prove me wrong
		 */

		return 1;
	#endif
	
		/*
		 * early mac osx failed here -- fixed 3Q 2001
		 */

		if (memccpy(buf, "abc", 0, sizeof(buf)) != (buf + 4))
			return 1;
	#ifdef MAP_PRIVATE
		siz = 64 * 1024;
		if (!(dstbuf = malloc(2 * siz)))
			return 0;
		if ((fd = open("/dev/zero", O_RDWR)) < 0)
			return 0;
		srcbuf = (char*)mmap(NULL, siz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
		if (srcbuf == (caddr_t)0 || srcbuf == (caddr_t)(-1))
			return 0;
		addbuf i= mmap(srcbuf + siz, siz, PROT_NONE, MAP_PRIVATE, fd, 0);
		if (addbuf == (caddr_t)0 || addbuf == (caddr_t)(-1))
			return 0;
		for (i = 0; i < siz; i++)
			srcbuf[i] = 'x';
		srcbuf[siz - 1] = 0;
		alarm(10);
		signal(SIGSEGV, gotcha);
		signal(SIGBUS, gotcha);
		signal(SIGALRM, gotcha);
		/*
		 * sgi ia64 dumps here as of 3Q 2001
		 * bug acknowleged 1Q 2003
		 */
		memccpy(dstbuf, srcbuf, 0, siz + 10);
		alarm(0);
		if (strcmp(srcbuf, dstbuf))
			return 1;
		if (indict_sgi_ia64_4Q_2004(1))
			return 1;
		if (indict_sgi_ia64_4Q_2004(257))
			return 1;
	#endif
		return 0;
	}
}end

tst	lib_utime_now note{ utime works with 0 time vector }end execute{
	#include <sys/types.h>
	_BEGIN_EXTERNS_
	extern int	utime _ARG_((const char*, void*));
	_END_EXTERNS_
	int
	main()
	{
		return utime(".", (void*)0) == -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{
	_BEGIN_EXTERNS_
	extern void exit _ARG_((int));
	extern void _exit _ARG_((int));
	extern void _cleanup();
	void _cleanup() { _exit(0); }
	_END_EXTERNS_
	int main() { printf("cleanup\n"); exit(1); }
}end

std	remove note{ stuck with standard remove() }end nostatic{
	_BEGIN_EXTERNS_
	extern int unlink _ARG_((const char*));
	_END_EXTERNS_
	#if _STD_
	int remove(const char* path) { return 0; }
	#else
	int remove(path) char* path; { return 0; }
	#endif
	int main() { return unlink("foo"); }
}end

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

std	strcoll note{ standard strcoll works }end execute{
	#include <string.h>
	#define S	"hello world"
	int
	main()
	{
		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{
	_BEGIN_EXTERNS_
	#if _STD_
	double strtod(const char* s, char** e) { return 0.0; }
	#else
	double strtod(s, e) char* s; char** e; { return 0.0; }
	#endif
	_END_EXTERNS_
	int main() { printf(""); return strtod("1",0) != 0; }
}end

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

std	strtol note{ stuck with standard strtol }end nostatic{
	_BEGIN_EXTERNS_
	#if _STD_
	extern long atol(const char*);
	long strtol(const char* s, char** e, int b) { return 0; }
	#else
	extern long atol();
	long strtol(s, e, b) char* s; char** e; int b; { return 0; }
	#endif
	_END_EXTERNS_
	int main() { printf(""); return (atol("1") + strtol("1",(char**)0,0)) != 0; }
}end

tst	- note{ [ pid ] + fd + directory path format }end output{
	#include <stdio.h>
	#include <unistd.h>
	#include <fcntl.h>
	int main()
	{
		int	oflags;
		int	i;
		int	cwd;
		int	fd;
		char	path[1024];

		static const char* fmtself[] = { "/proc/self/fd/%d%s%s", "/dev/fd/%d%s%s" };

		static const char* fmtpid[] =  { "/proc/%d/fd/%d%s%s" };

		oflags = O_RDONLY;
#ifdef O_SEARCH
		oflags |= O_SEARCH;
#endif
		if ((cwd = open(".", oflags)) < 0)
			return 1;
		for (i = 0; i < sizeof(fmtself) / sizeof(fmtself[0]); i++)
		{
			sprintf(path, fmtself[i], cwd, "/", ".");
			if ((fd = open(path, oflags)) >= 0)
			{
				close(fd);
				printf("#define _fd_self_dir_fmt\t\"%s\"\n", fmtself[i]);
				fflush(stdout);
				break;
			}
		}
		switch (fork())
		{
		case 0:
			for (i = 0; i < sizeof(fmtpid) / sizeof(fmtpid[0]); i++)
			{
				sprintf(path, fmtpid[i], getppid(), cwd, "/", ".");
				if ((fd = open(path, oflags)) >= 0)
				{
					close(fd);
					printf("#define _fd_pid_dir_fmt\t\t\"%s\"\n", fmtpid[i]);
					fflush(stdout);
					break;
				}
			}
			return 0;
		case -1:
			return 1;
		}
		wait((int*)0);
		return 0;
	}
}end

tst	- output{
	int
	main()
	{
	#if _UWIN
		printf("\n");
		printf("/* override some uwin feature tests */\n");
		printf("#undef	_lib_execlp\n");
		printf("#undef	_lib_execvp\n");
		printf("#undef	_lib_execvpe\n");
		printf("#undef	_lib_fork\n");
		printf("#undef	_std_string\n");
		printf("#define _std_string	1\n");
		printf("#undef	_stream_peek\n");
		printf("\n");
	#endif

	#if _lib_spawnveg || _lib_posix_spawn || _lib_spawn_mode || _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance || _lib_vfork && _real_vfork
		printf("#if !_AST_no_spawnveg\n");
		printf("#define _use_spawnveg	1\n");
		printf("#endif\n");
		printf("\n");
	#endif

		return 0;
	}

}end

tst	no64 -D_LARGEFILE64_SOURCE note{ largefile 64 broken }end execute{
	#include <sys/types.h>
	#include <sys/stat.h>
	int
	main()
	{
		struct stat64	st;
		return !stat64(".", &st) && st.st_mode && st.st_mtime;
	}
}end pass{
	echo "/* can we at least agree that a successful return means success? */"
	echo "#undef	_lib_creat64"
	echo "#undef	_lib_fstat64"
	echo "#undef	_lib_fstatvfs64"
	echo "#undef	_lib_ftruncate64"
	echo "#undef	_lib_lseek64"
	echo "#undef	_lib_lstat64"
	echo "#undef	_lib_mmap64"
	echo "#undef	_lib_stat64"
	echo "#undef	_lib_statvfs64"
	echo "#undef	_lib_truncate64"
}end
