shithub: mc

ref: ddb327c92ebe3f96c5c816ec61996440551de401
dir: /lib/std/strsplit.myr/

View raw version
use "alloc"
use "chartype"
use "die"
use "extremum"
use "option"
use "slpush"
use "strfind"
use "strstrip"
use "types"
use "utf"

pkg std =
	const strsplit	: (s : byte[:], delim : byte[:] -> byte[:][:])
	const bstrsplit	: (sp : byte[:][:], s : byte[:], delim : byte[:] -> byte[:][:])
	const strtok	: (s : byte[:] -> byte[:][:])
	const bstrtok	: (sp : byte[:][:], s : byte[:] -> byte[:][:])
;;

extern const put	: (fmt : byte[:], args : ... -> size)

const strsplit = {s, delim
	var sp

	sp = [][:]
	-> dostrsplit(&sp, s, delim, true)
}

const bstrsplit = {sp, s, delim
	-> dostrsplit(&sp, s, delim, false)
}

const dostrsplit : (sp : byte[:][:]#, s : byte[:], delim : byte[:], grow : bool -> byte[:][:]) = {sp : byte[:][:]#, s, delim, grow
	var last
	var idx

	last = 0
	idx = 0

	if s.len == 0
		-> sp#[:idx]
	;;

	while true
		match strfind(s, delim)
		| `Some i:
			if grow
				slpush(sp, s[:i])
			elif idx < sp#.len - 1
				sp#[idx] = s[:i]
			else
				goto donesplit
			;;
			s = s[i + delim.len:]
			idx++
		| `None:
			goto donesplit
		;;
	;;
:donesplit
	if grow
		slpush(sp, s)
	else
		sp#[idx] = s
	;;
	idx++
	-> sp#[:idx]
}

const strtok = {s
	var toks
	toks = [][:]

	-> dostrtok(&toks, s, true)
}

const bstrtok = {toks, s
	-> dostrtok(&toks, s, false)
}

const dostrtok = {toks, s, grow
	var i, j
	var idx

	i = 0
	idx = 0
	while i != s.len
		while isspace(std.decode(s[i:])) && i < s.len
			i++
		;;
		j = i
		while !std.isspace(std.decode(s[j:])) && j < s.len
			j++
		;;
		if i != j
			if grow
				slpush(toks, s[i:j])
			elif idx < toks#.len - 1
				toks#[idx] = s[i:j]
			else
				toks#[idx] = strrstrip(s[i:])
				idx++
				break
			;;
			idx++
		;;
		i = j
	;;
	-> toks#[:idx]
}