shithub: mc

ref: 4bbf79843d318582ae08b2e2d656a0dd1217fe42
dir: /libstd/optparse.myr/

View raw version
use "alloc.use"
use "die.use"
use "extremum.use"
use "fmt.use"
use "option.use"
use "slpush.use"
use "syswrap.use"
use "syswrap-ss.use"
use "types.use"
use "utf.use"

pkg std =
	type optdef = struct
		argdesc	: byte[:]
		opts	: optdesc[:]
	;;

	type optdesc = struct
		opt	: char
		arg	: byte[:]
		desc	: byte[:]
		needed	: bool
	;;

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

		/* data passed in */
		optdef	: optdef#
		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	: (optargs : byte[:][:], def : optdef# -> optctx#)
	const optnext	: (ctx : optctx# -> (char, byte[:]))
	const optdone	: (ctx : optctx# -> bool)
	const optfin	: (ctx : optctx# -> byte[:][:])
	const optusage	: (ctx : optctx# -> void)
;;

const optinit = {args, def
	var ctx

	ctx = alloc()
	ctx.optargs = args
	ctx.optdef = def

	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

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

	match optinfo(ctx, c)
	| `None:
		if c == 'h' || c == '?'
			optusage(ctx)
			exit(0)
		else
			fatal(1, "unexpected argument '%c'\n", c)
		;;
	| `Some (true, needed):
		/* -arg => '-a' 'rg' */
		if ctx.curarg.len > 0
			arg = ctx.curarg
			ctx.curarg = ctx.curarg[ctx.curarg.len:]
			next(ctx)
		/* '-a rg' => '-a' 'rg' */
		elif ctx.argidx < (ctx.optargs.len - 1)
			arg = ctx.optargs[ctx.argidx + 1]
			ctx.argidx++
			next(ctx)
		elif needed
			put("Expected argument for %c\n", c)
			exit(1)
		;;
	| `Some (false, _):
		arg = ""
		if ctx.curarg.len == 0
			next(ctx)
		;;
	;;


	-> (c, arg)
}

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

const optinfo = {ctx, opt
	for o in ctx.optdef.opts
		if o.opt == opt
			-> `Some (o.arg.len != 0, o.needed)
		;;
	;;
	-> `None
}

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 = slpush(ctx.args, ctx.optargs[i])
		;;
	;;
	ctx.finished = true
	-> false
:foundopt
	ctx.argidx = i
	ctx.curarg = ctx.optargs[i][1:]
	-> true
}

const optusage = {ctx
	std.put("usage: %s [-h?]", ctx.optargs[0])
	for o in ctx.optdef.opts
		std.put("[-%c%s%s] ", o.opt, sep(o.arg), o.arg)
	;;
	std.put("%s\n", ctx.optdef.argdesc)
	std.put("\t-h\tprint this help message\n")
	std.put("\t-?\tprint this help message\n")
	for o in ctx.optdef.opts
		std.put("\t%c%s%s\t%s\n", o.opt, sep(o.arg), o.arg, o.desc)
	;;
}

const sep = {s
	if s.len > 0
		-> " "
	else
		-> ""
	;;
}