-- UserProfileImpl.mesa; Edited by McGregor on 18-Feb-82 11:23:34
DIRECTORY
Convert USING [Int, Parse, Value],
IOStream USING [Close, CreateFileStream, EndOf, GetChar, Handle, SetIndex],
Rope USING [Compare, FromString, Ref, Size],
UserProfile;
UserProfileImpl: MONITOR
IMPORTS Convert, IOStream, Rope
EXPORTS UserProfile =
BEGIN
name: Rope.Ref = "User.profile";
openCount: CARDINAL ← 0;
profile: IOStream.Handle;
missing: BOOLEAN ← FALSE;
Boolean: PUBLIC PROC [key: Rope.Ref, default: BOOLEAN ← FALSE]
RETURNS [value: BOOLEAN] = BEGIN
val: Rope.Ref;
Open;
IF missing THEN RETURN[default];
val ← GetLineValue[key];
Close;
IF val=NIL THEN RETURN[default];
IF Rope.Compare[val, "TRUE", FALSE]=0 THEN RETURN[TRUE];
IF Rope.Compare[val, "FALSE", FALSE]=0 THEN RETURN[FALSE];
RETURN[default];
END;
Number: PUBLIC PROC [key: Rope.Ref, default: LONG INTEGER ← 0]
RETURNS [value: LONG INTEGER] = BEGIN
-- we'd like to use Convert.IntFromRope here, but the resultant
-- fatal compiler errors in pass 5 wasted one afternoon already...
IntFromRope: PROC [r: Rope.Ref] RETURNS [i: Convert.Int] = BEGIN
v: Convert.Value ← Convert.Parse[[rope[r]]].value;
RETURN[NARROW[v, Convert.Value[signed]].signed];
END;
val: Rope.Ref;
Open;
IF missing THEN RETURN[default];
val ← GetLineValue[key];
Close;
IF val=NIL THEN RETURN[default];
value ← IntFromRope[val ! ANY => {value ← default; CONTINUE}]
END;
String: PUBLIC PROC [key: Rope.Ref, default: Rope.Ref ← NIL]
RETURNS [value: Rope.Ref] = BEGIN
Open;
IF missing THEN RETURN[default];
value ← GetLineValue[key];
Close;
IF value=NIL OR Rope.Size[value]=0 THEN RETURN[default];
END;
Open: PUBLIC ENTRY PROC = BEGIN
openCount ← openCount+1;
IF openCount#1 OR missing THEN RETURN; -- already open
profile ← IOStream.CreateFileStream[fileName: name,
accessOptions: read, createOptions: oldOnly
! ANY => {MissingProfile[]; CONTINUE}];
IF missing THEN RETURN;
lineKey ← NEW[TEXT[50]];
lineValue ← NEW[TEXT[250]];
END;
Close: PUBLIC ENTRY PROC = BEGIN
IF openCount=0 THEN ERROR; -- Closed once too many
openCount ← openCount-1;
IF openCount#0 OR missing THEN RETURN; -- already open
IOStream.Close[profile];
profile ← NIL;
lineKey ← lineValue ← NIL;
END;
MissingProfile: INTERNAL PROC = BEGIN
-- maybe should notify the user someday
missing ← TRUE;
END;
lineKey, lineValue: REF TEXT;
GetLineValue: ENTRY PROC [key: Rope.Ref] RETURNS [value: Rope.Ref ← NIL] = BEGIN
ReadALine: PROC RETURNS [eof: BOOLEAN] = BEGIN
char: CHARACTER;
lineKey.length ← lineValue.length ← 0;
-- read key
UNTIL (eof ← IOStream.EndOf[profile]) OR
(char ← IOStream.GetChar[profile]) = ': DO
IF char=15C THEN {lineKey.length ← 0; LOOP};
lineKey[lineKey.length] ← char;
lineKey.length ← lineKey.length+1;
ENDLOOP;
-- skip spaces
UNTIL (eof ← IOStream.EndOf[profile]) OR
(char ← IOStream.GetChar[profile]) # ' OR
char = 15C DO ENDLOOP;
-- read value
UNTIL (eof ← IOStream.EndOf[profile]) OR
char = 15C DO
lineValue[lineValue.length] ← char;
lineValue.length ← lineValue.length+1;
char ← IOStream.GetChar[profile];
ENDLOOP;
END;
IOStream.SetIndex[profile, 0];
UNTIL ReadALine[] DO
IF Rope.Compare[key, LOOPHOLE[lineKey], FALSE]=0 THEN
RETURN[Rope.FromString[lineValue]];
ENDLOOP;
END;
END.