ref: 85e3adbca63041d3628e9f8d55d83aa34d084008
dir: /lib/std/syswrap+plan9.myr/
use sys
use "option"
use "types"
use "errno"
use "result"
use "cstrconv"
use "strfind"
use "syswrap-ss"
pkg std =
	type fd		= sys.fd
	type pid	= sys.pid
	type fdopt	= sys.fdopt
	type whence = int64
	type sysinfo = struct
		system	: byte[:]
		version	: byte[:]
		release	: byte[:]
		arch	: byte[:]
	;;
	const Seekset	: whence = 0
	const Seekcur	: whence = 1
	const Seekend	: whence = 2
	const Failmem	: byte#	= (-1 : byte#)
	const Oread  	: fdopt = (sys.Oread	: fdopt)
	const Owrite  	: fdopt = (sys.Owrite	: fdopt)
	const Ordwr    	: fdopt = (sys.Ordwr	: fdopt)
	const Otrunc   	: fdopt = (sys.Otrunc	: fdopt)
	const Ocexec	: fdopt = (sys.Ocexec	: fdopt)
	const Ocreat   	: fdopt = 0x1000000	/* emulated by redirecting to creat(). */
	const Oappend  	: fdopt = 0x2000000	/* emulated by seeking to EOF */
	const Odir	: fdopt = 0x0	/* no-op on plan9 */
	/* fd stuff */
	const open	: (path : byte[:], opts : fdopt -> result(fd, errno))
	const openmode	: (path : byte[:], opts : fdopt, mode : int64 -> result(fd, errno))
	const close	: (fd : fd -> errno)
	const read	: (fd : fd, buf : byte[:] -> result(size, errno))
	const pread	: (fd : fd, buf : byte[:], off : off -> result(size, errno))
	const write	: (fd : fd, buf : byte[:] -> result(size, errno))
	const pwrite	: (fd : fd, buf : byte[:], off : off -> result(size, errno))
	const seek	: (fd : fd, delta : off, whence : whence -> result(off, errno))
	const pipe	: (fds : fd[2]# -> errno)
	const dup2	: (ofd : fd, nfd : fd -> result(fd, errno))
	/* useful/portable bits of stat */
	const fmtime	: (f : byte[:]	-> result(time, errno))
	const fsize	: (f : byte[:]	-> result(off, errno))
	const fexists	: (f : byte[:]	-> bool)
	const fisdir	: (f : byte[:]	-> bool)
	const fisreg	: (f : byte[:]	-> bool)
	/* the important bits that uname provides */
	const getsysinfo	: (si : sysinfo# -> void)
	/* path manipulation */
	const mkdir	: (path : byte[:], mode : int64 -> errno)
	const chdir	: (path : byte[:] -> bool)
	const remove	: (path : byte[:] -> bool)
	/* process stuff */
	const getpid	: ( -> pid)
	$noret const suicide	: ( -> void)
	const fork	: (-> pid)
	const execv	: (cmd : byte[:], args : byte[:][:] -> errno)
	const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno)
	pkglocal const Canunmap	: bool = true
	pkglocal const getmem	: (sz : size -> byte#)
	pkglocal const freemem	: (p : byte#, sz : size -> void)
	pkglocal const curtime	: (-> time)
	pkglocal const p9errstr	: (buf : byte[:] -> byte[:])
	/* statbuf offsets */
	pkglocal const Sizeoff	: int64 = 0
	pkglocal const Sizesz	: int64 = 2
	pkglocal const Typeoff	: int64 = Sizeoff + Sizesz
	pkglocal const Typesz	: int64 = 2
	pkglocal const Devoff	: int64 = Typeoff + Typesz
	pkglocal const Devsz	: int64 = 4
	pkglocal const Qidtypeoff	: int64 = Devoff + Devsz
	pkglocal const Qidtypesz	: int64 = 1
	pkglocal const Qidversoff	: int64 = Qidtypeoff + Qidtypesz
	pkglocal const Qidverssz	: int64	= 4
	pkglocal const Qidpathoff	: int64 = Qidversoff + Qidverssz
	pkglocal const Qidpathsz	: int64 = 8
	pkglocal const Modeoff	: int64 = Qidpathoff + Qidpathsz
	pkglocal const Modesz	: int64 = 4
	pkglocal const Atimeoff	: int64 = Modeoff + Modesz
	pkglocal const Atimesz	: int64 = 4
	pkglocal const Mtimeoff	: int64 = Atimeoff + Atimesz
	pkglocal const Mtimesz	: int64 = 4
	pkglocal const Lengthoff	: int64 = Mtimeoff + Mtimesz
	pkglocal const Lengthsz	: int64 = 8
	pkglocal const Stringsoff	: int64 = Lengthoff + Lengthsz
;;
/* UGLY: circular dependency breaking... */
extern const getenvv : (name : byte[:], default : byte[:] -> byte[:])
/* fd stuff */
const open	= {path, opts;	-> check(sys.open(path, (opts : sys.fdopt)))}
const openmode	= {path, opts, mode;
	var fd
	if opts & Ocreat != 0
		opts &= ~Ocreat
		fd = sys.create(path, (opts : sys.fdopt), (mode : int))
	else
		fd = sys.open(path, (opts : sys.fdopt))
	;;
	if opts & Oappend != 0
		sys.seek(fd, 0, 2)
	;;
	-> check(fd)
}
/* useful/portable bits of stat */
const fexists = {path
	var buf : byte[4]	/* big enough for size, nothing else. */
	-> sys.stat(path, buf[:]) >= 0
}
const fmtime = {path
	var buf	: byte[Stringsoff + 512]	/* enough space for some strings */
	if sys.stat(path, buf[:]) < Stringsoff
		-> `Err Emisc
	;;
	-> `Ok ((_getle32(buf[Mtimeoff:Mtimeoff + 8]) : time)*1_000_000)
}
const fsize = {path
	var buf	: byte[Stringsoff + 512]	/* enough space for some strings */
	if sys.stat(path, buf[:]) < Stringsoff
		-> `Err Emisc
	;;
	-> `Ok (_getle64(buf[Lengthoff:Lengthoff + 8]) : off)
}
extern const put : (fmt : byte[:], args : ... -> int64)
const fisdir = {path
	var buf	: byte[Stringsoff + 39]	/* enough space for qid type */
	if sys.stat(path, buf[:]) < Stringsoff
		-> false
	;;
	-> (_getle32(buf[Modeoff:Modeoff + 4]) & sys.Dmdir) != 0
}
const fisreg = {path
	var buf	: byte[Stringsoff + 512]	/* enough space for some strings */
	var ty
	if sys.stat(path, buf[:]) < Stringsoff
		-> false
	;;
	ty = _getle16(buf[Typeoff:Typeoff + 2])
	if (_getle32(buf[Modeoff:Modeoff + 4]) & sys.Dmdir) != 0
		-> false
	/* ugh. maybe this call should just be '!fisdir()' */
	elif ty == '|' || ty == 's' || ty == 'm'
		-> false
	else
		-> true
	;;
}
const getsysinfo = {si
	si.system = getenvv("osname", "Plan9")
	si.release = "4"
	si.version = "0"
	si.arch = getenvv("objtype", "amd64")
}
const close	= {fd;		-> (sys.close((fd : sys.fd)) : errno)}
const read	= {fd, buf;	-> check(sys.pread((fd : sys.fd), buf, -1))}
const pread	= {fd, buf,off;	-> check(sys.pread((fd : sys.fd), buf, (off : sys.off)))}
const write	= {fd, buf;	-> check(sys.pwrite((fd : sys.fd), buf, -1))}
const pwrite	= {fd, buf,off;	-> check(sys.pwrite((fd : sys.fd), buf, (off : sys.off)))}
const seek	= {fd, off, whence; 	-> check(sys.seek((fd : sys.fd), (off : sys.off), (whence : int64)))}
const pipe	= {fds;		-> (sys.pipe((fds : sys.fd[2]#)) : errno)}
const dup2	= {ofd, nfd;	-> check(sys.dup((ofd : sys.fd), (nfd : sys.fd)))}
/* path manipulation */
const remove	= {path;	-> sys.remove(path) == 0}
const chdir	= {path;	-> sys.chdir(path) == 0}
const mkdir	= {path, mode;
	var fd
	fd = sys.create(path, sys.Oread, sys.Dmdir | (mode : int))
	if fd < 0
		-> lasterr()
	;;
	sys.close(fd)
	-> 0
}
/* process stuff */
const getpid	= {;	-> (sys.tosptr.pid : pid)}
const suicide	= {;	(0 : byte#)#}	/* let's happy segfault!! t */
const fork	= {;		-> (sys.rfork(sys.Rffdg | sys.Rfrend | sys.Rfproc) : pid)}
const execv	= {cmd, args;
	sys.exec(cmd, args)
	-> lasterr()
}
const execve	= {cmd, args, env;
	sys.exec(cmd, args)
	-> lasterr()
}
/* memory stuff */
const getmem	= {sz
	var endp, oldp
	oldp = sys.curbrk
	endp = (sys.curbrk : intptr) + (sz : intptr)
	endp = (endp + 4095) & ~4095
	if sys.brk_((endp : byte#)) < 0
		-> Failmem
	;;
	sys.curbrk = (endp : byte#)
	-> oldp
}
	
const freemem = {p, sz
	/* FIXME: we leak address space */
	sys.segfree(p, (sz : sys.size))
}
const curtime = {
	-> (sys.nsec()/1000 : time)
}
const p9errstr = {errbuf
	var i
	sys.errstr(errbuf)
	for i = 0; errbuf[i] != 0 && i < errbuf.len; i++
		continue
	;;
	-> errbuf[:i]
}
/* FIXME: will be needed when we resize stat bufs when statting.
const statsz = {buf
	-> (buf[0] : int64)) | ((buf[1] << 8 : int64))
}
*/
generic check = {e : @a -> result(@b, errno) :: integral, numeric @a
	if e < 0
		-> `Err lasterr()
	else
		-> `Ok (e : @b)
	;;
}
/* duplicated code to break dependency cycle */
generic _getle16 = {buf -> @a :: numeric,integral @a
	-> ((buf[0] : @a) << 0) | \
		((buf[1] : @a) << 8)
}
generic _getle32 = {buf -> @a :: numeric,integral @a
	-> ((buf[0] : @a) << 0) | \
		((buf[1] : @a) << 8) | \
		((buf[2] : @a) << 16) | \
		((buf[3] : @a) << 24)
}
generic _getle64 = {buf -> @a :: numeric,integral @a
	-> ((buf[0] : @a)  << 0) | \
		((buf[1] : @a)  << 8) | \
		((buf[2] : @a)  << 16) | \
		((buf[3] : @a)  << 24) | \
		((buf[4] : @a)  << 32) | \
		((buf[5] : @a)  << 40) | \
		((buf[6] : @a)  << 48) | \
		((buf[7] : @a)  << 56)
}