forsyth20121205-174063a80cc13 years agoHistory
181 lines · 3.8 KB · Brainfuck
RawDownload
implement Shellbuiltin; include "sys.m";	sys: Sys;include "draw.m";include "sh.m";	sh: Sh;	Listnode, Context: import sh;	myself: Shellbuiltin; initbuiltin(ctxt: ref Context, shmod: Sh): string{	sys = load Sys Sys->PATH;	sh = shmod;	myself = load Shellbuiltin "$self";	if (myself == nil)		ctxt.fail("bad module", sys->sprint("arg: cannot load self: %r"));	ctxt.addbuiltin("arg", myself);	return nil;} whatis(nil: ref Sh->Context, nil: Sh, nil: string, nil: int): string{	return nil;} getself(): Shellbuiltin{	return myself;} runbuiltin(ctxt: ref Context, nil: Sh,			argv: list of ref Listnode, last: int): string{	case (hd argv).word {	"arg" =>		return builtin_arg(ctxt, argv, last);	}	return nil;} runsbuiltin(nil: ref Sh->Context, nil: Sh,			nil: list of ref Listnode): list of ref Listnode{	return nil;} argusage(ctxt: ref Context){	ctxt.fail("usage", "usage: arg [opts {command}]... - args");} builtin_arg(ctxt: ref Context, argv: list of ref Listnode, nil: int): string{	for (args := tl argv; args != nil; args = tl tl args) {		if ((hd args).word == "-")			break;		if ((hd args).cmd != nil && (hd args).word == nil)			argusage(ctxt);		if (tl args == nil)			argusage(ctxt);		if ((hd tl args).cmd == nil)			argusage(ctxt);	}	if (args == nil)		args = ctxt.get("*");	else		args = tl args;	laststatus := "";	ctxt.push();	{		arg := Arg.init(args);		while ((opt := arg.opt()) != 0) {			for (argt := tl argv; argt != nil && (hd argt).word != "-"; argt = tl tl argt) {				w := (hd argt).word;				argcount := 0;				for (e := len w - 1; e >= 0; e--) {					if (w[e] != '+')						break;					argcount++;				}				w = w[0:e+1];				if (w == nil)					continue;				for (i := 0; i < len w; i++)					if (w[i] == opt || w[i] == '*')						break;				if (i < len w) {					optstr := ""; optstr[0] = opt;					ctxt.setlocal("opt", ref Listnode(nil, optstr) :: nil);					args = arg.arg(argcount);					if (argcount > 0 && args == nil)						ctxt.fail("usage", sys->sprint("option -%c requires %d arguments", opt, argcount));					ctxt.setlocal("arg", args);					laststatus = ctxt.run(hd tl argt :: nil, 0);					break;				}			}			if (argt == nil || (hd argt).word == "-")				ctxt.fail("usage", sys->sprint("unknown option -%c", opt));		}		ctxt.pop();		ctxt.set("args", arg.args);		# XXX backward compatibility - should go		ctxt.set("*", arg.args);		return laststatus;	}	exception e{	"fail:*" =>		ctxt.pop();		if (e[5:] == "break")			return laststatus;		raise e;	}} Arg: adt {	args: list of ref Listnode;	curropt: string;	init: fn(argv: list of ref Listnode): ref Arg;	arg: fn(ctxt: self ref Arg, n: int): list of ref Listnode;	opt: fn(ctxt: self ref Arg): int;};	 Arg.init(argv: list of ref Listnode): ref Arg{	return ref Arg(argv, nil);} # get next n option arguments (nil list if not enough arguments found)Arg.arg(ctxt: self ref Arg, n: int): list of ref Listnode{	if (n == 0)		return nil; 	args: list of ref Listnode;	while (--n >= 0) {		if (ctxt.curropt != nil) {			args = ref Listnode(nil, ctxt.curropt) :: args;			ctxt.curropt = nil;		} else if (ctxt.args == nil)			return nil;		else {			args = hd ctxt.args :: args;			ctxt.args = tl ctxt.args;		}	}	r: list of ref Listnode;	for (; args != nil; args = tl args)		r = hd args :: r;	return r;} # get next option letter# return 0 at end of optionsArg.opt(ctxt: self ref Arg): int{	if (ctxt.curropt != "") {		opt := ctxt.curropt[0];		ctxt.curropt = ctxt.curropt[1:];		return opt;	} 	if (ctxt.args == nil)		return 0; 	nextarg := (hd ctxt.args).word;	if (len nextarg < 2 || nextarg[0] != '-')		return 0; 	if (nextarg == "--") {		ctxt.args = tl ctxt.args;		return 0;	} 	opt := nextarg[1];	if (len nextarg > 2)		ctxt.curropt = nextarg[2:];	ctxt.args = tl ctxt.args;	return opt;}