##################################################################
# This file defines probes for local features that sfio requires.
# Such probes are interpreted by the "iffe" language interpreter.
# Results are stored in the FEATURE directory.
# Written by Kiem-Phong Vo (06/27/92).
# Converted to sfio v10/01/94 by Giampiero Sierra (06/08/95).
##################################################################

hdr string
hdr math
lib qfrexp
lib qldexp

hdr unistd
hdr values
hdr floatingpoint
hdr float
lib atexit
lib onexit

lib lseek64
lib stat64
lib mmap64
typ off64_t
typ struct_stat64 compile{
	#include	<sys/types.h>
	#include	<sys/stat.h>
	main()
	{	struct stat64 statb;
	}
}end

exit    cleanup note{ stuck with standard _cleanup }end execute{
        #include <stdio.h>
        _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

lib bcopy
lib bzero
lib memcpy
lib memset
lib memalign
hdr time
sys time

lib memchr note{ see if memchr is fast }end execute{
	#include	<sys/types.h>
	#include	<sys/times.h>
	#include	<stdlib.h>

	main()
	{	struct tms	stm1, etm1, stm2, etm2;
		register int	i, p;
		register char	*s, *ends;
		long		t1, t2;
		char		buf[128];
	
		for(p = 0; p < 100; ++p)
			buf[p] = '0' + (p%10);
		buf[p++] = '\n';
		buf[p] = 0;
	
		times(&stm1);
		for(i = 0; i < 100000; ++i)
			s = memchr(buf,'\n',p);
		times(&etm1);
	
		times(&stm2);
		for(i = 0; i < 100000; ++i)
		{	ends = (s = buf) + p;
			while(*s != '\n')
				if((s += 1) == ends)
					break;
		}
		times(&etm2);
	
		t1 = (etm1.tms_utime - stm1.tms_utime) +
		     (etm1.tms_stime - stm1.tms_stime);
		t2 = (etm2.tms_utime - stm2.tms_utime) +
		     (etm2.tms_stime - stm2.tms_stime);
	
		return t1 < t2 ? 0 : 1;
	}
}end

lib memccpy note{ see if memccpy is fast }end execute{
	#include	<sys/types.h>
	#include	<sys/times.h>
	#include	<stdlib.h>

	main()
	{	struct tms	stm1, etm1, stm2, etm2;
		register int	i, p;
		register char	*s1, *s2;
		long		t1, t2;
		char		buf1[128], buf2[128];
	
		for(i = 0; i < 100; ++i)
			buf1[i] = '0' + (i%10);
		buf1[i++] = '\n';
		buf1[i] = 0;
	
		times(&stm1);
		for(i = 0; i < 100000; ++i)
		{	p = 128;
			memccpy(buf2,buf1,'\n',p);
		}
		times(&etm1);
	
		times(&stm2);
		for(i = 0; i < 100000; ++i)
		{	s1 = buf1; s2 = buf2; p = 128;
			while((*s2++ = *s1++) != '\n' && --p > 0)
				;
		}
		times(&etm2);
	
		t1 = (etm1.tms_utime - stm1.tms_utime) +
		     (etm1.tms_stime - stm1.tms_stime);
		t2 = (etm2.tms_utime - stm2.tms_utime) +
		     (etm2.tms_stime - stm2.tms_stime);
	
		return t1 < t2 ? 0 : 1;
	}
}end

sys stat note{ stat() in default lib(s) }end link{
	#if _STD_
	#include	<stddef.h>
	#else
	#include	<sys/types.h>
	#endif
	#include	<time.h>
	#include	<sys/stat.h>
	main()
	{	struct stat	st;
		fstat(0,&st);
	}
}end

hdr stat note{ stat() in default lib(s) }end link{
	#if _STD_
	#include	<stddef.h>
	#else
	#include	<sys/types.h>
	#endif
	#include	<time.h>
	#include	<stat.h>
	main()
	{	struct stat	st;
		fstat(0,&st);
	}
}end

#############################################################
# See if  memory mapping is available and fast enough to use
#############################################################
sys mman

tst	output{
	#include	<sys/types.h>
	#include	<sys/mman.h>
	#include	<sys/times.h>
	
	_BEGIN_EXTERNS_
	int creat _ARG_((char*, int));
	int open _ARG_((char*, int));
	int unlink _ARG_((char*));
	int read _ARG_((int, char*, int));
	_END_EXTERNS_
	
	#define MAPSIZE (64*1024)
	#define BUFSIZE	(MAPSIZE/8)
	#define WRITE   (64)
	#define RUN	(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, *f;
		int		i, fd, k, run;
		char		file[1024], buf[MAPSIZE];
		struct tms	stm, etm;
		clock_t		rdtm, mmtm;
	
		/* create data file */
		f = argv[0]; t = file;
		while (*t = *f++)
			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);
	
		/* read time */
		times(&stm);
		for(run = 0; run < RUN; ++run)
		{	if((fd = open(file, 0)) < 0)
				return Failed(file);
			for (i = 0; i < WRITE; ++i)
			{	for(k = 0; k < MAPSIZE; k += BUFSIZE)
					if (read(fd,buf,BUFSIZE) != BUFSIZE)
						return Failed(file);
			}
			close(fd);
		}
		times(&etm);
		rdtm = (etm.tms_utime-stm.tms_utime) + (etm.tms_stime-stm.tms_stime);
	
		/* mmap time */
		times(&stm);
		for(run = 0; run < RUN; ++run)
		{	if ((fd = open(file,0)) < 0)
				return Failed(file);
			for(i = 0, mm = (caddr_t)0; i < WRITE; ++i)
			{	if(mm)
					munmap(mm, MAPSIZE);
				mm = (caddr_t)mmap((caddr_t)0, MAPSIZE,
						   (PROT_READ|PROT_WRITE),
						   MAP_PRIVATE, fd, i*MAPSIZE );
				if(mm == (caddr_t)(-1) || mm == (caddr_t)0)
					return Failed(file);
	
				/* the memcpy is < BUFSIZE to simulate the
				   fact that functions like sfreserve/sfgetr do
				   not do buffer copying.
				*/
				t = (char*)mm;
				for(k = 0; k < MAPSIZE; k += BUFSIZE, t += BUFSIZE)
					memcpy(buf,t,(3*BUFSIZE)/4);
			}
			close(fd);
		}
		times(&etm);
		mmtm = (etm.tms_utime-stm.tms_utime) + (etm.tms_stime-stm.tms_stime);

		unlink(file);
	
		if(4*mmtm <= 3*rdtm)		/* mmap is great! */
			printf("#define _mmap_worthy	2	\n");
		else if(4*mmtm <= 5*rdtm)	/* mmap is good	*/
			printf("#define _mmap_worthy	1	\n");
	
		return 0;
	}
}end

##################################################
# vfork and any associated header files
##################################################

hdr vfork
sys vfork
lib vfork

##################################################
# file control checks
##################################################

hdr filio
sys filio
sys ioctl
lib remove
lib unlink
lib waitpid
lib getpagesize

tmp rmfail note{ file not removable if still opened }end execute{
	#include	<sys/time.h>
	_BEGIN_EXTERNS_
	extern int creat _ARG_((char*, int));
	extern int unlink _ARG_((char*));
	extern int write _ARG_((int, char*, int));
	_END_EXTERNS_
	main()
	{	int		fw, fr;
		char		file[128];
		sprintf(file,"/tmp/iffe%lu",(unsigned long)time(0));
		if((fw = creat(file,0666)) < 0)
			return 0;
		if((fr = open(file,0)) < 0 )
			return 0;
		if(unlink(file) < 0)
			return 0;
		if(write(fw,"0123456789",11) != 11 )
			return 0;
		if(read(fr,file,11) != 11)
			return 0;
		if(strcmp(file,"0123456789") != 0)
			return 0;
		return 1;
	}
}end

more void_int note{ voidptr is larger than int }end execute{
	main() {
	return sizeof(char*) > sizeof(int) ? 0 : 1;
	}
}end

more long_int note{ long is larger than int }end execute{
	main() {
	return sizeof(long) > sizeof(int) ? 0 : 1;
	}
}end

################################################################
# See if there is a preferred block size for a file system
################################################################

stat blksize note{ st_blksize is a field in struct stat }end compile{
	#include	<sys/types.h>
	#include	<sys/stat.h>
	main () {
		struct stat sb;
		sb.st_blksize = 0;
		return 0;
	}
}end

##################################################
# See if certain prototypes are required
##################################################

proto open note{ open() has a vararg prototype }end compile{
	#include	<sys/types.h>
	#include	<errno.h>
	#include	<ctype.h>
	#include	<fcntl.h>

	_BEGIN_EXTERNS_
	extern int open _ARG_((const char*,int,...));
	_END_EXTERNS_
	main()
	{
		open("file",0);
		open("file",0,1);
	}
}end

proto bcopy note{ bcopy() has prototype }end compile{
	#include	<string.h>
	main()
	{	char	buf[128];
		bcopy(buf, "abc", 3);
	}
}end

proto bzero note{ bzero() has prototype }end compile{
	#include	<string.h>
	main()
	{	char	buf[128];
		bzero(buf, 128);
	}
}end

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

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

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

################################################################
## See if we can peek ahead in unseekable devices
################################################################

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

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


################################################################
## See if register layout is ok for vax string operations
################################################################

vax asm note{ register layout ok for vax string operations }end execute{
        main()
        {
        #ifndef vax
                return absurd = -1;
        #else
                register int    r11, r10, r9, r8, r7, r6;
                r11 = r10 = r9 = r8 = r7 = r6 = -1;
                asm("clrw       r11");
                asm("clrw       r10");
                asm("clrw       r9");
                asm("clrw       r8");
                asm("clrw       r7");
                asm("clrw       r6");
                if(sizeof(int) != sizeof(char*) || r11 || r10 || r9 || r8 || r7 || r6 )
                        return -1;
                return 0;
        #endif
        }
}end

lib strtod note{ native strtod exists }end

################################################################
## See if there is "locale" stuff for conditioning printf/scanf
################################################################

lib locale note{ Check for localeconv }end compile{
	#include	<locale.h>
	main()
	{	struct lconv* lv = localeconv();
		return 0;
	}
}end
