Copyright (C) 1994, Digital Equipment Corporation
All rights reserved.
See the file COPYRIGHT for a full description.
Last modified on Mon Jan 30 15:01:03 PST 1995 by kalsow
modified on Fri Sep 2 03:32:09 PDT 1994 by stolfi
modified on Wed Mar 13 01:30:31 1991 by muller
modified on Fri Jun 2 18:25:43 1989 by ellis
MODULE ParseParams;
IMPORT Text, Wr, Fmt, Scan, Lex, Thread, Params, FloatMode;
REVEAL
T = Public BRANDED OBJECT
wr: Wr.T; (* Writer for error messages *)
OVERRIDES
init := Init;
keywordPresent := KeywordPresent;
getKeyword := GetKeyword;
getNext := GetNext;
testNext := TestNext;
getNextInt := GetNextInt;
getNextReal := GetNextReal;
getNextLongReal := GetNextLongReal;
error := PrintError;
skipParsed := SkipParsed;
finish := Finish;
END;
PROCEDURE Init(t: T; wr: Wr.T): T =
BEGIN
t.wr := wr;
WITH num = Params.Count DO
t.arg := NEW(REF ARRAY OF TEXT, num);
t.parsed := NEW(REF ARRAY OF BOOLEAN, num);
WITH a = t.arg^, p = t.parsed^ DO
FOR i := 0 TO num-1 DO
a[i] := Params.Get(i); p[i] := FALSE
END;
p[0] := TRUE;
t.next := 1
END;
END;
RETURN t
END Init;
PROCEDURE KeywordPresent(t: T; key: TEXT): BOOLEAN =
BEGIN
WITH a = t.arg^, p = t.parsed^ DO
FOR i := 0 TO LAST(a) DO
IF NOT p[i] AND Text.Equal(key, a[i]) THEN
t.next := i + 1;
p[i] := TRUE;
RETURN TRUE;
END
END
END;
RETURN FALSE
END KeywordPresent;
PROCEDURE GetKeyword(t: T; key: TEXT) RAISES {Error} =
BEGIN
IF NOT t.keywordPresent(key) THEN
t.error("keyword \"" & key & "\" not found.");
END;
END GetKeyword;
PROCEDURE GetNext(t: T): TEXT RAISES {Error} =
BEGIN
WITH a = t.arg^, p = t.parsed^ DO
IF (t.next > LAST(a)) OR p[t.next] THEN
t.error("missing argument after argument " &
Fmt.Int(t.next-1) & " = \"" &
a[t.next-1] & "\"."
)
END;
p[t.next] := TRUE;
INC(t.next);
RETURN a[t.next-1]
END;
END GetNext;
PROCEDURE TestNext (t: T; key: TEXT): BOOLEAN RAISES {} =
BEGIN
WITH a = t.arg^, p = t.parsed^ DO
IF (t.next > LAST(a)) OR p[t.next]
OR NOT Text.Equal(key, a[t.next]) THEN
RETURN FALSE
ELSE
p[t.next] := TRUE;
INC(t.next);
RETURN TRUE
END
END
END TestNext;
PROCEDURE GetNextInt(
t: T;
min := FIRST(INTEGER);
max := LAST(INTEGER)
): INTEGER RAISES {Error} =
VAR nn: INTEGER;
BEGIN
WITH txt = t.getNext() DO
TRY
nn := Scan.Int(txt);
EXCEPT
Lex.Error, FloatMode.Trap =>
t.error(
"parameter " & Fmt.Int(t.next-1) & " = \"" & txt &
"\" should be an integer."
)
END;
IF (nn < min) OR (nn > max) THEN
t.error (
"parameter " & Fmt.Int(t.next-1) & " = " & Fmt.Int(nn) &
" should be in [" & Fmt.Int(min) & ".." & Fmt.Int(max) & "]."
)
END;
END;
RETURN nn
END GetNextInt;
PROCEDURE GetNextReal(
t: T;
min := FIRST(REAL);
max := LAST(REAL)
): REAL RAISES {Error} =
VAR x: REAL;
BEGIN
WITH txt = t.getNext() DO
TRY
x := Scan.Real(txt);
EXCEPT
Lex.Error, FloatMode.Trap =>
t.error(
"parameter " & Fmt.Int(t.next-1) & " = \"" & txt &
"\" should be a real number."
)
END;
IF (x < min) OR (x > max) THEN
t.error (
"parameter " & Fmt.Int(t.next-1) & " = " & Fmt.Real(x) &
" should be in [" & Fmt.Real(min) &
" __ " & Fmt.Real(max) & "]."
)
END
END;
RETURN x
END GetNextReal;
PROCEDURE GetNextLongReal(
t: T;
min := FIRST(LONGREAL);
max := LAST(LONGREAL)
): LONGREAL RAISES {Error} =
VAR x: LONGREAL;
BEGIN
WITH txt = t.getNext() DO
TRY
x := Scan.LongReal(txt);
EXCEPT
Lex.Error, FloatMode.Trap =>
t.error(
"parameter " & Fmt.Int(t.next-1) & " = \"" & txt &
"\" should be a real number."
)
END;
IF (x < min) OR (x > max) THEN
t.error (
"parameter " & Fmt.Int(t.next-1) & " = " & Fmt.LongReal(x) &
" should be in [" & Fmt.LongReal(min) &
" __ " & Fmt.LongReal(max) & "]."
)
END
END;
RETURN x
END GetNextLongReal;
PROCEDURE SkipParsed(t: T) RAISES {Error} =
CONST MaxBogus = 5;
VAR bogus: CARDINAL := 0;
BEGIN
WITH a = t.arg^, p = t.parsed^ DO
t.next := NUMBER(a);
WHILE (t.next > 0) AND NOT p[t.next-1] DO DEC(t.next) END;
(* Check for unparsed arguments: *)
FOR i := 0 TO t.next-1 DO
IF NOT p[i] THEN
INC (bogus);
IF bogus <= 5 THEN
Message(
t.wr,
"parameter " & Fmt.Int(i) & " = \"" & a[i] &
"\" extraneous or misplaced."
);
END;
END;
END;
IF bogus > MaxBogus THEN
Message(t.wr, "(and " & Fmt.Int (bogus - MaxBogus) & " more).");
END;
IF bogus > 0 THEN RAISE Error END;
END
END SkipParsed;
PROCEDURE Finish(t: T) RAISES {Error} =
CONST MaxBogus = 5;
VAR bogus: CARDINAL := 0;
BEGIN
WITH a = t.arg^, p = t.parsed^ DO
FOR i := 0 TO LAST(a) DO
IF NOT p[i] THEN
INC (bogus);
IF bogus <= 5 THEN
Message(
t.wr,
"parameter " & Fmt.Int(i) & " = \"" & a[i] &
"\" extraneous or misplaced."
);
END;
END;
END;
IF bogus > MaxBogus THEN
Message(t.wr, "(and " & Fmt.Int (bogus - MaxBogus) & " more).");
END;
t.parsed := NIL;
t.arg := NIL;
t.wr := NIL;
IF bogus > 0 THEN RAISE Error END;
END
END Finish;
PROCEDURE Message(wr: Wr.T; msg: TEXT) =
<*FATAL Wr.Failure, Thread.Alerted*>
BEGIN
IF (wr # NIL) THEN
Wr.PutText(wr, "ParseParams: ");
Wr.PutText(wr, msg);
Wr.PutChar(wr, '\n');
Wr.Flush(wr);
END
END Message;
PROCEDURE PrintError (t: T; msg: TEXT) RAISES {Error} =
BEGIN
Message(t.wr, msg);
RAISE Error
END PrintError;
BEGIN
END ParseParams.