-- 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.