<> <> <> DIRECTORY Args, Commander, CommandTool, Convert, IO, Rope; ArgsImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, IO, Rope EXPORTS Args ~ { Arg: TYPE ~ Args.Arg; NArgs: PUBLIC PROC [cmd: Commander.Handle] RETURNS [INTEGER] ~ { RETURN[CommandTool.Parse[cmd].argc-1]; }; GetRope: PUBLIC PROC [cmd: Commander.Handle, nArg: INTEGER _ 0] RETURNS [Rope.ROPE] ~ { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd]; RETURN [IF argv.argc < nArg+2 OR nArg < 0 THEN NIL ELSE argv[nArg+1]]; }; ArgRope: PUBLIC PROC [cmd: Commander.Handle, nArg: INTEGER _ 0] RETURNS [a: Arg] ~ { a.rope _ GetRope[cmd, nArg]; a.ok _ a.rope # NIL; }; ArgReal: PUBLIC PROC [cmd: Commander.Handle, nArg: INTEGER _ 0] RETURNS [a: Arg] ~ { r: Rope.ROPE _ GetRope[cmd, nArg]; a.ok _ r # NIL; IF a.ok THEN a.real _ Convert.RealFromRope[r ! Convert.Error => {a.ok _ FALSE; CONTINUE}]; }; ArgInt: PUBLIC PROC [cmd: Commander.Handle, nArg: INTEGER _ 0] RETURNS [a: Arg] ~ { r: Rope.ROPE _ GetRope[cmd, nArg]; a.ok _ r # NIL; IF a.ok THEN a.int _ Convert.IntFromRope[r ! Convert.Error => {a.ok _ FALSE; CONTINUE}]; }; ArgIntDef: PUBLIC PROC [cmd: Commander.Handle, nArg: INTEGER _ 0, defVal: INT] RETURNS [a: Arg] ~ { r: Rope.ROPE _ GetRope[cmd, nArg]; a.ok _ TRUE; a.int _ IF r = NIL THEN defVal ELSE Convert.IntFromRope[r ! Convert.Error => {a.ok _ FALSE; CONTINUE}]; }; ArgIntRange: PUBLIC PROC [cmd: Commander.Handle, n, min, max: INT] RETURNS [arg: Arg] ~ { arg _ ArgInt[cmd, n]; IF NOT arg.ok THEN RETURN; IF arg.ok THEN arg.ok _ arg.int >= min AND arg.int <= max; }; ArgsGet: PUBLIC PROC [cmd: Commander.Handle, fmt: Rope.ROPE] RETURNS [BOOL, Arg, Arg, Arg, Arg, Arg, Arg, Arg, Arg, Arg, Arg, Arg, Arg] ~ { retOK: BOOL _ TRUE; maxNRet: INTEGER ~ 12; maxNArgs: INTEGER ~ 100; retArgs: ARRAY[0..maxNRet) OF Arg; usedArgs: PACKED ARRAY [0..maxNArgs) OF BOOL _ ALL[FALSE]; nArgs: INTEGER _ MIN[maxNArgs, NArgs[cmd]]; fmtLength: INTEGER _ Rope.Length[fmt]; argIndex: INTEGER _ 0; fmtIndex: INTEGER _ 0; retIndex: INTEGER _ 0; <<>> <> SetRets: PROC ~ { optional: BOOL _ Rope.Fetch[fmt, fmtIndex] = '[; fmtIndex _ fmtIndex+1; WHILE fmtIndex < fmtLength AND retIndex < maxNRet DO c: CHAR _ Rope.Fetch[fmt, fmtIndex]; SELECT c FROM '%, '[, '-, IO.SP => RETURN; 'b => retArgs[retIndex] _ [ok: TRUE, bool: TRUE]; 'i, 's, 'r => { WHILE argIndex < nArgs AND usedArgs[argIndex] DO argIndex _ argIndex+1; ENDLOOP; IF argIndex >= nArgs THEN { IF NOT optional THEN retOK _ FALSE; fmtIndex _ Rope.SkipTo[fmt, fmtIndex, "-"]; RETURN }; retArgs[retIndex] _ SELECT c FROM 'i => ArgInt[cmd, argIndex], 's => ArgRope[cmd, argIndex], 'r => ArgReal[cmd, argIndex], ENDCASE => []; IF NOT retArgs[retIndex].ok THEN retOK _ FALSE; usedArgs[argIndex] _ TRUE; argIndex _ argIndex+1; }; ENDCASE => { retOK _ FALSE; fmtIndex _ Rope.SkipTo[fmt, fmtIndex, "%[-"]; RETURN }; fmtIndex _ fmtIndex+1; retIndex _ retIndex+1; ENDLOOP; }; <<>> <> SkipTokens: PROC ~ { fmtIndex _ fmtIndex+1; WHILE fmtIndex < fmtLength DO SELECT Rope.Fetch[fmt, fmtIndex] FROM 'i, 's, 'r, 'b => retIndex _ retIndex+1; '%, '[, '- => RETURN; ENDCASE => {retOK _ FALSE; RETURN}; fmtIndex _ fmtIndex+1; ENDLOOP; }; WHILE fmtIndex < fmtLength DO -- first, set hyphenated arguments: SELECT Rope.Fetch[fmt, fmtIndex] FROM '%, '[ => SkipTokens[]; '- => { key: Rope.ROPE; n: INTEGER _ Rope.SkipTo[fmt, fmtIndex, "[%"]; IF n = fmtLength THEN {retOK _ FALSE; EXIT}; key _ Rope.Substr[fmt, fmtIndex, n-fmtIndex]; fmtIndex _ n; argIndex _ 1; WHILE argIndex <= nArgs DO IF GetRope[cmd, argIndex-1].Equal[key] THEN { usedArgs[argIndex-1] _ TRUE; SetRets[]; EXIT; }; argIndex _ argIndex+1; REPEAT FINISHED => fmtIndex _ Rope.SkipTo[fmt, fmtIndex, "-%["]; ENDLOOP; }; ENDCASE => {fmtIndex _ Rope.SkipTo[fmt, fmtIndex, "-%["]; retOK _ FALSE}; ENDLOOP; argIndex _ retIndex _ fmtIndex _ 0; -- now set non-hyphenated arguments: WHILE fmtIndex < fmtLength DO SELECT Rope.Fetch[fmt, fmtIndex] FROM '- => {fmtIndex _ Rope.SkipTo[fmt, fmtIndex, "%"]; SkipTokens[]}; '%, '[ => SetRets[]; ENDCASE => {retOK _ FALSE; fmtIndex _ fmtIndex+1}; ENDLOOP; FOR n: INTEGER IN[0..nArgs) DO IF NOT usedArgs[n] THEN retOK _ FALSE; ENDLOOP; RETURN[retOK, retArgs[0], retArgs[1], retArgs[2], retArgs[3], retArgs[4], retArgs[5], retArgs[6], retArgs[7], retArgs[8], retArgs[9], retArgs[10], retArgs[11]]; }; TestArgs: Commander.CommandProc ~ { PrintArg: PROC [arg: Arg] ~ { cmd.out.PutF["ok: %g\tbool: %g\tint: %g\treal: %g\trope: %g\n", IO.bool[arg.ok], IO.bool[arg.bool], IO.int[arg.int], IO.real[arg.real], IO.rope[arg.rope]]; }; ok: BOOL; args: ARRAY[0..6) OF Arg; <<[ok, args[0], args[1], args[2], args[3], args[4], args[5]] _ ArgsGet[cmd, "-i%ii-b%b%r%s"];>> [ok, args[0], args[1], args[2], args[3], args[4], args[5]] _ ArgsGet[cmd, "-i%ii-b%b"]; cmd.out.PutF["ok is %g\n", IO.bool[ok]]; FOR n: INTEGER IN[0..6) DO PrintArg[args[n]]; ENDLOOP; }; Commander.Register["///Commands/TestArgs", TestArgs, "\nTestArgs [argument list]."]; }.