shithub: mc

ref: 5a07a949b3667e0f0b97156035104d35f6aea2a5
dir: /libstd/optparse.myr/

View raw version
use "alloc.use"
use "die.use"
use "extremum.use"
use "fmt.use"
use "slappend.use"
use "sys.use"
use "types.use"
use "utf.use"

pkg std =
	type optctx = struct
		/* public variables */
		args	: byte[:][:]

		/* data passed in */
		optstr	: byte[:]
		optargs	: byte[:][:]

		/* state */
		optdone	: bool	/* if we've seen '--', everything's an arg */
		finished	: bool	/* if we've processed all the optargs */
		argidx	: size
		curarg	: byte[:]
	;;

	const optinit	: (optstr: byte[:], optargs : byte[:][:] -> optctx#)
	const optnext	: (ctx : optctx# -> [char, byte[:]])
	const optdone	: (ctx : optctx# -> bool)
	const optfin	: (ctx : optctx# -> byte[:][:])
;;

const optinit = {optstr, optargs
	var ctx

	ctx = alloc()
	ctx.optstr= optstr
	ctx.optargs =optargs

	ctx.optdone = false
	ctx.finished = false
	ctx.argidx = 0
	ctx.curarg = [][:]

	ctx.args = [][:]

	next(ctx)
	-> ctx
}

const optfin = {ctx
	var a

	a = ctx.args
	free(ctx)
	-> a
}

const optnext = {ctx
	var c
	var arg
	var valid
	var tryarg
	var needarg

	(c, ctx.curarg) = striter(ctx.curarg)

	(valid, tryarg, needarg) = optinfo(ctx, c)
	if !valid
		put("Unexpected argument %c\n", c)
		exit(1)
	elif tryarg && ctx.curarg.len > 0
		arg = ctx.curarg
		ctx.curarg = ctx.curarg[ctx.curarg.len:]
	elif tryarg && ctx.argidx < (ctx.optargs.len - 1)
		arg = ctx.optargs[ctx.argidx + 1]
		ctx.argidx++
		next(ctx)
	elif needarg
		put("Expected argument for %c\n", c)
		exit(1)
	else
		arg = ""
	;;

	if !ctx.curarg.len
		next(ctx)
	;;

	-> (c, arg)
}

const optdone = {ctx
	-> !ctx.curarg.len && ctx.finished
}

const optinfo = {ctx, arg
	var s
	var c

	s = ctx.optstr
	while s.len != 0
		(c, s) = striter(s)
		if c == arg
			(c, s) = striter(s)
			/* mandatory arg */
			if c == ':'
				-> (true, true, true)
			/* optional arg */
			elif c == '?'
				-> (true, true, false)
			/* no arg */
			else
				-> (true, false, false)
			;;
		;;
	;;
	-> (false, false, false)
}

const next = {ctx
	var i

	for i = ctx.argidx + 1; i < ctx.optargs.len; i++
		if !ctx.optdone && decode(ctx.optargs[i]) == '-'
			goto foundopt
		else
			ctx.args = slappend(ctx.args, ctx.optargs[i])
		;;
	;;
	ctx.finished = true
	-> false
:foundopt
	ctx.argidx = i
	ctx.curarg = ctx.optargs[i][1:]
	-> true
}