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