(*******************************************************************)
(** Release history:                                              **)
(**    17th January 1985   version 1.0.0 First port to new world  **)
(*******************************************************************)
IMPLEMENTATION MODULE GenDict;
(*
    Title    :  GenDict
    LastEdit :  Thu Jan 10 16:56:24 1985
    Author   :  Graham Toal
    Acorn Computers VLSI Design Aids Group
    
    This is called internally from 'Defaults', but is sufficiently
    general as to be used from other programs. (e.g. Graphics)
*)
FROM SYSTEM IMPORT WORD;
FROM Strings IMPORT String;
IMPORT Streams;
IMPORT Dict;
IMPORT ScanS;
IMPORT SysStreams;
IMPORT WriteF;
IMPORT Strings;

PROCEDURE ReadDict(in: Streams.Stream; masDict: Dict.DICT);
  PROCEDURE StoI (s: String): INTEGER;
  VAR c, idx, i: INTEGER;
  BEGIN;
    IF s=NIL THEN RETURN (0) END (* if *);
    idx := 0; i := 0;
    LOOP;
      c := INTEGER(s^[idx]);
      IF (c>57) OR (c<48) THEN EXIT END;
      i := i*10+c-48; INC(idx);
      IF idx>6 THEN EXIT END;
    END;
    RETURN(i);
  END StoI;
  
  PROCEDURE Readln(VAR line: String);
  CONST MaxArray = 255;
  VAR cLine: ARRAY[0..MaxArray] OF CHAR; ch: CHAR; next: CARDINAL;
  BEGIN;
    next := 0;
    LOOP;
      ch := CHAR(Streams.Get(in));
      IF in^.status<>Streams.Success THEN EXIT END;
      IF ORD(ch)<32 THEN EXIT END;
      cLine[next] := ch; INC(next);
      IF next+1=MaxArray THEN EXIT END;
    END;
    WHILE (next>0) AND (cLine[next-1]=" ") DO DEC(next) END (* while *);
    cLine[next] := CHR(10); INC(next);
    cLine[next] := CHR(0); line := Strings.CopyCS(cLine);
  END Readln;
  
VAR line, newLine, dictName, key, strVal, intVal: String;
  groupDict, curDict: Dict.DICT; oldDispose: WORD;
BEGIN;
  LOOP;
    Readln(line);
    IF in^.status<>Streams.Success THEN EXIT END;
    IF ScanS.ParseF1('*.{*.}*.$', line, "%*0%*2$", newLine) THEN;
      Strings.Dispose(line); line := newLine;
    END (* if *);
    IF ScanS.ParseF1('*~ ^ $', line, "%~0$", newLine) THEN;
      Strings.Dispose(line); line := newLine;
    END;
    (* CASE-statement below simulated by PRIORITY-ORDERED if-then sequence *)
    IF line^[0]=CHR(10) THEN
      (*WriteF.WriteF0(SysStreams.sysErr, "<Blank line>*N")*)
    ELSIF ScanS.ParseF2('* "^~""* ^#* $', line, "%^0", key, "%^1", intVal)
     THEN;
      Dict.EnterS(curDict, key, Dict.KeyAttr{}, StoI(intVal));
      Strings.Dispose(key); Strings.Dispose(intVal);
    ELSIF ScanS.ParseF2('* "^~""* "^~""* $', line, "%~0", key, "%~1", strVal)
     THEN;
      Dict.EnterS(curDict, key, Dict.KeyAttr{}, strVal);
      Strings.Dispose(key); Strings.Dispose(strVal);
    ELSIF ScanS.ParseF1('* using* "^~""* $', line, "%~0", dictName) THEN;
      IF NOT(Dict.Found(masDict, dictName, groupDict)) THEN
        WriteF.WriteF1(SysStreams.sysErr,
         "WARNING: Cannot find section %S*N", WriteF.S(dictName));
        groupDict := Dict.NewDictS(dictName);
        Dict.EnterS(masDict, dictName, Dict.KeyAttr{}, groupDict);
      END;
      Strings.Dispose(dictName);
    ELSIF ScanS.ParseF1('* dict* "^~""* $', line, "%^0", dictName) THEN;
      IF NOT(Dict.Found(groupDict, dictName, curDict)) THEN
        WriteF.WriteF1(SysStreams.sysErr,
         "WARNING: Cannot find table %S*N", WriteF.S(dictName));
        oldDispose := WORD(NIL);
      ELSE
        (* Dispose previous contents *)
        oldDispose := curDict^.Dispose;
        Dict.RemoveS(groupDict, dictName);
        Dict.DeleteDict(curDict)
      END;
      curDict := Dict.NewDictS(dictName);
      IF INTEGER(oldDispose) <> INTEGER(NIL) THEN
       curDict^.Dispose := oldDispose
      END;
      Dict.EnterS(groupDict, dictName, Dict.KeyAttr{Dict.ExactLength},
       curDict);
      curDict^.Silent := FALSE;
      Strings.Dispose(dictName);
    ELSIF ScanS.ParseF1('* dict* "^~""* silent* $', line, "%^0", dictName)
     THEN;
(* stuff below should be exactly as above *)
      IF NOT(Dict.Found(groupDict, dictName, curDict)) THEN
        WriteF.WriteF1(SysStreams.sysErr,
         "WARNING: Cannot find table %S*N", WriteF.S(dictName));
        oldDispose := WORD(NIL);
      ELSE
        (* Dispose previous contents *)
        oldDispose := curDict^.Dispose;
        Dict.RemoveS(groupDict, dictName);
        Dict.DeleteDict(curDict)
      END;
      curDict := Dict.NewDictS(dictName);
      IF INTEGER(oldDispose) <> INTEGER(NIL) THEN
       curDict^.Dispose := oldDispose
      END;
      Dict.EnterS(groupDict, dictName, Dict.KeyAttr{Dict.ExactLength},
       curDict);
(* ...................................... *)
      curDict^.Silent := TRUE;
      Strings.Dispose(dictName);
    ELSIF ScanS.ParseF1('* end* "^~""* $', line, "%^0", dictName) THEN;
      (*WriteF.WriteF1(SysStreams.sysErr, "End of section %S*N",
       WriteF.S(dictName));*)
      Strings.Dispose(dictName);
    ELSE;
      WriteF.WriteF1(SysStreams.sysErr, "%S** Error !*N", WriteF.S(line));
    END (* if *);
    Strings.Dispose(line);
  END;
END ReadDict;
   
END GenDict.
