cmd	universe

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

dat	_tzname,tzname

lib	BSDsetpgrp NutForkExecve
lib	_cleanup
lib	atexit,bcopy,bzero,catclose,catgets,catopen,confstr,dirread,dup2
lib	execlp,execve,execvp,execvpe
lib	fchmod,fcntl,fmtmsg,fnmatch,fork,fsync,getconf,getdents,getdirentries
lib	getdtablesize,getgroups,getlogin,getpagesize,getrlimit,getuniverse
lib	glob,index,iswblank,iswctype,killpg,link,localeconv,madvise,mbtowc
lib	memalign,memccpy,memchr,memcmp,memcpy,memdup,memmove,memset
lib	mkdir,mkfifo,mktemp,mktime
lib	mount,on_exit,onexit,opendir,pathconf,pcreateve
lib	readlink,remove,rename,rewinddir,rindex,rmdir,setlocale
lib	setpgid,setpgrp,setpgrp2,setreuid,setsid,setuid,sigaction
lib	sigprocmask,sigsetmask,sigunblock,sigvec,socketpair,spawnlp
lib	spawnve,spawnveg,spawnvp,spawnvpe,strchr,strcoll,strdup,strerror
lib	strcasecmp,strncasecmp,strrchr,strtod,strtol,strtoll,strtoul,strtoull
lib	strxfrm,strftime,swab,symlink,sysconf,syslog
lib	telldir,tmpnam,tzset,universe,unlink,utime,vfork,wctype
lib	ftruncate,truncate
lib	creat64,fstat64,fstatvfs64,ftruncate64 -D_LARGEFILE64_SOURCE
lib	lseek64,lstat64,mmap64 -D_LARGEFILE64_SOURCE
lib	open64,readdir64,stat64,statvfs64,truncate64 -D_LARGEFILE64_SOURCE

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 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

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

typ	off64_t -D_LARGEFILE64_SOURCE
typ	struct.dirent64 -D_LARGEFILE64_SOURCE dirent.h

tst	tst_errno note{ errno can be assigned }end link{
	_BEGIN_EXTERNS_
	extern int errno;
	error() { }
	strerror() { }
	_END_EXTERNS_
	main() { errno = 0; error(); strerror(); }
}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_
	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(&fd, 1, 0) < 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_
	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;
	}
}end

cat{
	#if _lib_poll_fd_1 || _lib_poll_fd_2
	#define _lib_poll	1
	#endif
	#if _lib_NutForkExecve
	#define _map_spawnve	NutForkExecve
	#endif
}end

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
	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 note{ select() has standard 5 arg interface }end link{
	#include <sys/types.h>
	#include <sys/time.h>
	#include <sys/socket.h>
	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_
	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	real_vfork note{ vfork child shares data with parent }end execute{
	_BEGIN_EXTERNS_
	extern int	exit _ARG_((int));
	extern int	vfork();
	_END_EXTERNS_
	int		code;
	main()
	{
		code = 1;
		if (!vfork()) code = 0;
		exit(code);
	}
}end

tst	stream_peek note{ ioctl(I_PEEK) works }end link{
	#include <sys/types.h>
	#include <stropts.h>
	main()
	{	struct strpeek	pbuf;
		pbuf.flags = 0;
		pbuf.ctlbuf.maxlen = pbuf.databuf.maxlen =
		pbuf.ctlbuf.len = pbuf.databuf.len = 0;
		pbuf.ctlbuf.buf = pbuf.databuf.buf = 0;
		ioctl(0,I_PEEK,&pbuf);
		return 0;
	}
}end

tst	socket_peek note{ recv(MSG_PEEK) works }end link{
	#include <sys/types.h>
	#include <sys/socket.h>
	main()
	{	char	buf[128];
		recv(0,buf,sizeof(buf),MSG_PEEK);
		return 0;
	}
}end

tst	lib_mmap sys/types.h sys/stat.h unistd.h fcntl.h mman.h sys/mman.h sys/times.h note{ standard mmap interface that works }end execute{
	#define MAPSIZE (64*1024)
	#define BUFSIZE	(8*1024)
	#define WRITE   (64)

	#define Failed(file)	(unlink(file),1)

	#if _STD_
	main(int argc, char** argv)
	#else
	main(argc,argv)
	int     argc;
	char**  argv;
	#endif
	{
		caddr_t		mm;
		char		*t, *u, *f;
		int		i, fd, okfixed;
		char		file[1024], buf[MAPSIZE];
		struct tms	stm, etm;
		clock_t		rdtm, mmtm;

		/* create data file in a local fs if possible */
		t = file;
		if (access(f = "/tmp", 0) == 0 ||
		    access(f = "/usr/tmp", 0) == 0)
		{
			while (*t = *f++)
				t++;
			*t++ = '/';
		}
		u = t;
		f = argv[0];
		while (*t = *f++)
			if (*t == '/')
				t = u;
			else if (*t != '.')
				t++;
		*t++ = '.'; *t++ = 'D'; *t = 0;
		if ((fd = creat(file,0666)) < 0)
			return 1;

		for (i = 0; i < sizeof(buf); ++i)
			buf[i] = '0' + (i%10);
		for (i = 0; i < WRITE; ++i)
			if (write(fd,buf,sizeof(buf)) != sizeof(buf))
				return Failed(file);
		close(fd);

		/* see if can overwrite fixed map */
	#ifndef MAP_VARIABLE
	#define MAP_VARIABLE	0
	#endif
		if ((fd = open(file,0)) < 0)
			return Failed(file);

		mm = mmap((caddr_t)0, sizeof(buf), (PROT_READ|PROT_WRITE),
			  (MAP_PRIVATE|MAP_VARIABLE), fd, 0);
		if(mm == (caddr_t)0 || mm == (caddr_t)(-1))
			return Failed(file);
		mm = mmap(mm, sizeof(buf), (PROT_READ|PROT_WRITE),
			  (MAP_PRIVATE|MAP_FIXED), fd, 0);
		okfixed = (mm == (caddr_t)0 || mm == (caddr_t)(-1)) ? 0 : 1;
		munmap(mm, sizeof(buf));
		close(fd);

		/* read time */
		if((fd = open(file, 0)) < 0)
			return Failed(file);
		times(&stm);
		for (i = 0; i < WRITE; ++i)
			if (read(fd,buf,BUFSIZE) != BUFSIZE)
				return Failed(file);
		times(&etm);
		close(fd);
		rdtm = (etm.tms_utime-stm.tms_utime) + (etm.tms_stime-stm.tms_utime);

		/* mmap time */
		if ((fd = open(file,0)) < 0)
			return Failed(file);
		times(&stm);
		for(i = 0, mm = (caddr_t)0; i < WRITE; ++i)
		{	if(okfixed)
			{	mm = (caddr_t)mmap(mm, MAPSIZE,
					(PROT_READ|PROT_WRITE),
					(MAP_PRIVATE | (mm ? MAP_FIXED : MAP_VARIABLE)),
					fd, i*MAPSIZE );
			}
			else
			{	if(mm)
					munmap(mm, MAPSIZE);
				mm = (caddr_t)mmap((caddr_t)0, MAPSIZE,
					(PROT_READ|PROT_WRITE),
					(MAP_PRIVATE|MAP_VARIABLE),
					fd, i*MAPSIZE );
			}
			if(mm == (caddr_t)(-1) || mm == (caddr_t)0)
				return Failed(file);
		}
		times(&etm);
		close(fd);
		unlink(file);
		mmtm = (etm.tms_utime-stm.tms_utime) + (etm.tms_stime-stm.tms_utime);

		return rdtm+60 < mmtm ? 1 : 0;
	}
}end

tst	ptr_dd_buf sys/types.h - dirent.h - ndir.h - sys/dir.h note{ DIR.dd_buf is a pointer }end compile{
	main()
	{
		DIR*	dirp;
		dirp->dd_buf = 0;
		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_
	main()
	{
		return utime(".", (void*)0) == -1;
	}
}end

tst	run{
	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_
	main() { printf("cleanup\n"); exit(1); }
}end

std	malloc note{ stuck with standard malloc }end noexecute{
	_BEGIN_EXTERNS_
	extern void _exit _ARG_((int));
	extern void* calloc _ARG_((unsigned, unsigned));
	#if !defined(NeXT) && !defined(__NeXT)
	#if _STD_
	char* malloc(unsigned n) { _exit(0); return 0; }
	#else
	char* malloc(n) unsigned n; { _exit(0); return 0; }
	#endif
	#endif
	_END_EXTERNS_
	main() { calloc(1, 1); _exit(1); }
}end

std	malloc note{ stuck with standard malloc -- wimp-o mach? }end noexecute{
	_BEGIN_EXTERNS_
	#if _STD_
	void* calloc(unsigned n, unsigned m) { return 0; }
	#else
	void* calloc(n, m) unsigned n, m; { return 0; }
	#endif
	_END_EXTERNS_
	main() { return 0; }
}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
	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_
	main() { signal(); abort(); return 0; }
}end

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

cat{
	/* ignore solaris 5.4 incompatibilities -- they aren't worth it */
	#if __sparc__ || __sparc || sparc
	#undef	_lib_confstr
	#undef	_lib_fnmatch
	#endif

	/* override some uwin feature tests */
	#if _WIN32
	#undef	_lib_execlp
	#undef	_lib_execvp
	#undef	_lib_execvpe
	#undef	_lib_fork
	#undef	_lib_spawnlp
	#undef	_lib_spawnvp
	#undef	_lib_spawnvpe
	#undef	_std_malloc
	#define _std_malloc 1
	#undef	_std_string
	#define _std_string 1
	#undef	_stream_peek
	#endif

	/* mvs.390 hacks */
	#if __MVS__
	#undef	_mem_dd_fd_DIR
	#undef	_typ_long_double
	#endif

}end

tst	no64 note{ largefile 64 broken }end execute{
	#define _LARGEFILE64_SOURCE 1
	#include <sys/types.h>
	#include <sys/stat.h>
	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

tst	rotten note{ rotten apple? }end execute{
	#include <string.h>
	main()
	{
		char	buf[1024];
		return memccpy(buf, "abc", 0, sizeof(buf)) == (buf + 4);	
	}
}end pass{
	echo "#undef	_lib_memccpy	/* rotten apple? */"
}end
