~ {
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: enter at '% or ']; return at next '%, '[, '-, or end of format string.
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: enter at '% or ']; return at next '%, '[, '-, or end of format string.
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]."];
}.