(*------------------------------------------

  :Module.      CDInput.mod
  :Author.      Albert Weinert  [awn]
  :Address.     Krähenweg 21 , 50829 Köln
  :EMail.       Usenet_> aweinert@darkness.gun.de
  :EMail.       Z-Netz_> A.WEINERT@DARKNESS.ZER
  :Phone.       0221 / 580 29 84
  :Revision.    R.3
  :Date.        23-Jun-1993
  :Copyright.   Albert Weinert
  :Language.    Oberon-2
  :Translator.  Amiga Oberon 3.00d
  :Contents.    Liest eine Catalog Description Datei und legt dies in einer Liste ab.
  :Imports.     MoreStrings.mod [hG|awn], C2OData.mod, Cd2OberonLocale.mod [awn]
  :Remarks.     <Was Du willst, evtl. Usage>
  :Bugs.        <Bekannte Fehler>
  :Usage.       <Angaben zur Anwendung>
  :History.     .0     [awn] 16-May-1993 : Erstellt
  :History.     .1     [awn] 17-May-1993 : Fehlernummern werden nun gesetzt
  :History.            so das der User auf weiss wo und woran der Fehler lag.
  :History.     .2     [awn] 03-Jun-1993 : Die ID-Nummern wurden falsch vergeben wenn
  :History.            keine Nummer im ersten String der CD-Datei vorlag.
  :History.     .3     [awn] 23-Jun-1993 : Minimale und Maximale Länge werden rausgesucht.

--------------------------------------------*)
MODULE CDInput;

IMPORT  ms:=MoreStrings,
        str:=Strings,
        cd:=C2OData,
        Conversions,
        BT:=BasicTypes,
        fs:=FastRead,
        sc:=StringConvert,
        SYSTEM,
        Dos,
        ll:=LinkedLists,
        cl:=KitCatLocale;

CONST
  header      = "#header";
  array       = "#array";
  arrayopts   = "#arrayopts";
  function    = "#function";
  catname     = "#catalogname";
  basename    = "#basename";
  lengthbytes = "#lengthbytes";
  language    = "#language";
  version     = "#version";
  prototypes  = "#prototypes";

VAR line    : LONGINT;

  PROCEDURE GetID(string: ARRAY OF CHAR;VAR idname:ARRAY OF CHAR; VAR idnum,min,max:LONGINT):BOOLEAN;
  (*------------------------------------------
    :Input.     string = Zeichekette
    :Input.     idnum = Letzte IDNummer
    :Output.    idname = Bezeichnung der ID, idnum = Nummer der ID
    :Output.    min, max = Minimale und Maximale Länge des Strings
    :Semantic.  Extrahiert den ID Namen und die ID Nummer aus einem ID Strings und teste
    :Semantic.  dabei auf deren korrektheit.
    :Note.      Wenn keine Länge angeben wird, dann ist in die entsprechende Länge = -1
    :Update.    16-May-1993 [awn] - erstellt.
    :Update.    03-Jun-1993 [awn] - es wurde das mit "lastnum" entfernt wegen Bug und
    :Update.                unötig.
    :Update.    23-Jun-1993 [awn] - Minimale und Maximale Länge wird jetzt auch heraus gesucht.
  --------------------------------------------*)
    VAR num : ARRAY 64 OF CHAR;
        pos, npos : LONGINT;
        ok: BOOLEAN;
        id : BOOLEAN;
        puf : ARRAY 32 OF CHAR;
    BEGIN
      min:=-1; max:=-1;
      IF string # "" THEN
        ms.GetWord(idname,string,1);
        ms.GetWord(num,string,2);
        IF (num[0] # "(") OR (num[str.Length(num)-1] # ")") THEN
            cd.error:=cl.errIWrongIDDesc;
            cd.para1:=line;
           RETURN FALSE;
        END;
        str.Delete(num,  0, 1);     (* Erstes ( löschen *)
        IF num[0] # "/" THEN     (* Wenn kein Schrägstrich, dann wohl nummer *)
          pos:=str.Occurs(num,"/");
          str.Cut(num, 0, pos, puf);
          IF ~Conversions.StrToInt(puf, idnum, 10) THEN;
            cd.error:=cl.errIDNum;
            cd.para1:=line;
            RETURN FALSE;
          END;
          str.Delete(num, 0, pos);
        ELSE;
          INC(idnum);
        END;

        str.Delete(num,  0, 1);     (* / löschen *)
        IF num[0] # "/" THEN     (* Wenn kein Schrägstrich, dann wohl nummer *)
          pos:=str.Occurs(num,"/");
          str.Cut(num, 0, pos, puf);
          IF ~Conversions.StrToInt(puf, min, 10) THEN;
            cd.error:=cl.errIDNum;
            cd.para1:=line;
            RETURN FALSE;
          END;
          str.Delete(num, 0, pos);
        END;

        str.Delete(num,  0, 1);  (* / * löschen *)
        IF num[0] # ")" THEN     (* Wenn kein (, dann wohl nummer *)
          pos:=str.Occurs(num,")");
          str.Cut(num, 0, pos, puf);
          IF ~Conversions.StrToInt(puf, max, 10) THEN;
            cd.error:=cl.errIDNum;
            cd.para1:=line;
            RETURN FALSE;
          END;
        END;
        RETURN TRUE;
      ELSE
        cd.error:=cl.errIdExpect;
        cd.para1:=line;
        RETURN FALSE;
      END;
    END GetID;


  PROCEDURE Import*(VAR name:ARRAY OF CHAR):BOOLEAN;
  (*------------------------------------------
    :Input.     name = Name der Catalog Description Datei
    :Output.
    :Semantic.
    :Note.
    :Update.    16-May-1993 [awn] - erstellt.
    :Update.    17-May-1993 [awn] - Fehlernummer werden jetzt gesetzt
    :Update.    03-Jun-1993 [awn] - idnum, wird nun bei beginn auf -1 gesetzt
    :Update.    26-Sep-1993 [awn] - Es dürfen nun auch Leerzeilen im Text
    :Update.                sein.
  --------------------------------------------*)
    VAR fh: fs.File;
        ok, ID : BOOLEAN;
        pos : LONGINT;
        idname : ARRAY 128 OF CHAR;
        buffer : ARRAY 128 OF CHAR;
        idnum, min, max  : LONGINT;
        node : cd.CDNode;
        string : BT.DynString;
        length : LONGINT;
        sl : ll.List;
        scn : cd.SNode;
    BEGIN
      length:=0;
      ms.AddString(cd.CDList.filename,name);
      ok:=FALSE;
      ID:=TRUE;
      sl:=NIL;
      idnum:=-1;
      IF fs.Open(fh, name) THEN
        ok:=TRUE;
        WHILE fs.ReadLongString(fh) AND ok DO
          INC(line);
          pos:=ms.FirstNoSpace(fh.string^);
          IF pos = -1 THEN pos:= 0 END;
          IF fh.string[pos] = ";" THEN
            IF sl = NIL THEN
              sl:=ll.Create();
              sl.Init();
            END;
            NEW(scn);
            IF scn # NIL THEN
              NEW(scn.string,str.Length(fh.string^)+2);
              IF scn.string # NIL THEN
                COPY(fh.string^,scn.string^);
                sl.AddTail(scn);
              ELSE;
                ok:=FALSE;
              END;
            ELSE
              ok:=FALSE;
            END;
          ELSIF fh.string[pos] = "#" THEN
            ms.GetWord(idname,fh.string^,1);
            IF idname = header THEN
              ms.GetWord(cd.CDList.header,fh.string^,2);
            ELSIF idname = function THEN
              ms.GetWord(cd.CDList.function,fh.string^,2);
            ELSIF idname = array THEN
              ms.GetWord(cd.CDList.array,fh.string^,2);
            ELSIF idname = catname THEN
              ms.GetWord(cd.CDList.cdname,fh.string^,2);
            ELSIF idname = basename THEN
              ms.GetWord(cd.CDList.basename,fh.string^,2);
            ELSIF idname = language THEN
              ms.GetWord(cd.CDList.language,fh.string^,2);
            ELSIF idname = version THEN
              buffer:="";
              ms.GetWord(buffer,fh.string^,2);
              IF (buffer = "") OR ~Conversions.StringToInt(buffer,cd.CDList.version) THEN
                ok:=FALSE;
                cd.error:=cl.errWrongVersion;
                cd.para1:=SYSTEM.ADR(version);
                cd.para2:=line;
              END;
            ELSIF idname = arrayopts THEN
              pos:=str.Occurs(fh.string^," ");
              IF pos # -1 THEN
                str.Cut(fh.string^,pos+1,str.Length(fh.string^)-1,cd.CDList.arrayopts)
              END;
            ELSIF idname = lengthbytes THEN
              buffer:="";
              ms.GetWord(buffer,fh.string^,2);
              IF (buffer = "") OR ~Conversions.StringToInt(buffer,length) THEN
                ok:=FALSE;
                cd.error:=cl.errWrongLength;
                cd.para1:=SYSTEM.ADR(lengthbytes);
                cd.para2:=line;
              ELSE;
                IF length > 4 THEN
                  ok:=FALSE;
                  cd.error:=cl.errLengthToHigh;
                  cd.para1:=SYSTEM.ADR(lengthbytes);
                  cd.para2:=line;
                END;
              END;
            ELSIF idname = prototypes THEN
              ok:=sc.GetString(fh, cd.CDList.prototypes, line);
              IF ok THEN
                ok:=sc.JoinString(cd.CDList.prototypes.fullstr,cd.CDList.prototypes.strings);
                IF ok THEN
                  ok:=sc.Convert(cd.CDList.prototypes.fullstr^,FALSE,FALSE,cd.CDList.prototypes.converted);
                END;
              END;
            ELSE
              cd.error:=cl.errUnknownCommand;
              COPY(idname,cd.buf);
              cd.para1:=SYSTEM.ADR(cd.buf);
              cd.para2:=line;
              ok:=FALSE;
            END;
          ELSE
            IF ID THEN
              ok:=GetID(fh.string^,idname,idnum, min, max);
              IF ok THEN
                NEW(node);
                IF node # NIL THEN
                  ms.AddString(node.idName,idname);
                  node.line:=line;
                  node.idNumber:=idnum;
                  node.minLen:=min;
                  node.maxLen:=max;
                  node.lengthbytes:=length;
                  node.comments:=sl;
                  sl:=NIL;
                  ID:=FALSE;
                  cd.CDList.AddTail(node);
                  IF idnum < cd.CDList.minId THEN cd.CDList.minId:=idnum END;
                  IF idnum > cd.CDList.maxId THEN cd.CDList.maxId:=idnum END;
                ELSE
                  cd.error:=cl.errNoMemory;
                  cd.para1:=SYSTEM.ADR(name);
                  ok:=FALSE;
                END;
              END;
            ELSE
              ok:=sc.GetString(fh,node,line);
              IF ok THEN
                ok:=sc.JoinString(node.fullstr,node.strings);
              END;
              ID:=TRUE;
            END;
          END;
        END;
        IF ok & ~ID THEN
          cd.error:=cl.errCDEnd;
          ok:=FALSE;
        END;
        IF fs.Close(fh) THEN END;
      END;
      RETURN ok;
    END Import;
END CDInput.
