shithub: mc

ref: a34a7853e4b85b5993b6c7b1ea169725c7090cca
dir: /lib/std/env+posixy.myr/

View raw version
use sys

use "alloc"
use "cstrconv"
use "die"
use "extremum"
use "fmt"
use "sleq"
use "memops"
use "option"
use "slcp"
use "sldup"
use "slpush"
use "threadhooks"
use "traits"

pkg std =
	const getenv	: (name : byte[:] -> option(byte[:]))
	const getenvv	: (name : byte[:], default : byte[:] -> byte[:])
	const setenv	: (name : byte[:], val : byte[:] -> void)
;;

const Zenvp = (0 : byte#)

var envduped	: bool = false
var environ	: byte#[:]

const getenv = {name
	var n, env

	envinit()
	for envp : environ
		if envp != Zenvp
			env = cstrconvp(envp)
			n = min(name.len, env.len)
			if eq(name, env[:n]) && eq(env[n:n+1], "=")
				-> `Some env[n+1:]
			;;
		;;
	;;
	-> `None
}

const getenvv = {name, default
	match getenv(name)
	| `Some v:	-> v
	| `None:	-> default
	;;
}

const setenv = {name, val
	var n, e, env, idx, found

	envinit()

	idx = 0
	found = false
	e = fmt("{}={}\0", name, val)

	lock(envlck)
	for envp : environ
		if envp == Zenvp
			break
		;;

		env = cstrconvp(envp)
		n = min(name.len, env.len - 1)
		if eq(name, env[:n]) && env[n] == ('=' : byte)
			found = true
			break
		;;
		idx++
	;;
	if found
		std.slfree(cstrconvp(environ[idx]))
	else
		idx = environ.len - 1
		std.slpush(&environ, Zenvp)
	;;
	environ[idx] = (e : byte#)
	sys.__cenvp = (environ : byte##)
	unlock(envlck)
}

const envinit = {
	var len, e, p

	lock(envlck)
	if environ.len != 0
		unlock(envlck)
		-> void
	;;

	/* 
	  Here, we duplicate the environment so we can
	  modify it. We take progressively bigger slices
	  as we go, until we find the terminating null.

	  It's a bit ugly, but what do?
	 */
	len = 0
	environ = [][:]
	while true
		p = sys.__cenvp[:len+1][len]
		if p != Zenvp
			e = sldup(cstrconvp(p))
			slpush(&e, 0)
			p = (e : byte#)
		;;
		std.slpush(&environ, p)
		if environ[len] == Zenvp
			break
		;;
		len++
	;;
	sys.__cenvp = (environ : byte##)
	unlock(envlck)
}