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

  :Module.      StringConvert.mod
  :Author.      Albert Weinert  [awn]
  :Address.     Krähenweg 21 , D-5000 Köln 30
  :EMail.       Usenet_> aweinert@darkness.gun.de
  :EMail.       Z-Netz_> A.WEINERT@DARKNESS.ZER
  :Phone.       0221 / 580 29 84
  :Revision.    R.0
  :Date.        28-May-1993
  :Copyright.   Albert Weinert
  :Language.    Oberon-2
  :Translator.  Amiga Oberon 3.00d
  :Contents.    <Kurzbeschreibung>
  :Imports.     <Importiertes, Name/ShortCut des Autors>
  :Remarks.     <Was Du willst, evtl. Usage>
  :Bugs.        <Bekannte Fehler>
  :Usage.       <Angaben zur Anwendung>
  :History.     .0     [awn] 28-May-1993 : Erstellt

--------------------------------------------*)
MODULE StringConvert;

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

VAR c : BT.DynString;

PROCEDURE Convert*(s: ARRAY OF CHAR;mod,cs:BOOLEAN;VAR bs : BT.DynString):BOOLEAN;
  VAR i,j,k,z : LONGINT;
      sl : LONGINT;
      w : SHORTINT;
  BEGIN
    IF s = "" THEN
      NEW( bs, 3 );
      bs^ := "";
      RETURN TRUE;
    END;
    sl:=Strings.Length(s);
    IF c = NIL THEN
      NEW(c,sl*2);
    END;
    IF (sl*2) > LEN(c^) THEN
      DISPOSE(c);
      NEW(c,sl*2);
    END;
    j:=0;
    c^:="";
    IF sl < 1 THEN RETURN TRUE END;
    FOR i:= 0 TO sl DO
      IF s[i] # "\\" THEN
        IF mod THEN
          IF (s[i] = '"') THEN
            c[j]:="\\"; INC(j);
            c[j]:='"'; INC(j);
          ELSE
            c[j]:=s[i]; INC(j);
          END;
        ELSE;
          c[j]:=s[i]; INC(j);
        END;
      ELSE
        IF mod THEN
          c[j]:="\\"; INC(j);
        END;
        INC(i);
        CASE s[i] OF
          | "a" : IF mod THEN
                    c[j]:="x"; INC(j);
                    c[j]:="0"; INC(j);
                    c[j]:="7"; INC(j);
                  ELSE
                    c[j]:="\x07";
                  END;
          | "b" : IF mod THEN
                    c[j]:="b"; INC(j);
                  ELSE
                    c[j]:="\b";
                  END;
          | "c", "[" : IF mod THEN
                    c[j]:="["; INC(j);
                  ELSE;
                    c[j]:="\x9B"; INC(j);
                  END;
          | "e" : IF mod THEN
                    c[j]:="e"; INC(j);
                  ELSE
                    c[j]:="\e"; INC(j);
                  END;
          | "f" : IF mod THEN
                    c[j]:="f"; INC(j);
                  ELSE
                    c[j]:="\f"; INC(j);
                  END;
          | "n" : IF mod THEN
                    c[j]:="n"; INC(j);
                  ELSE
                    c[j]:="\n"; INC(j);
                  END;
          | "r" : IF mod THEN
                    c[j]:="r"; INC(j);
                  ELSE
                    c[j]:="\r"; INC(j);
                  END;
          | "t" : IF mod THEN
                    c[j]:="t"; INC(j);
                  ELSE
                    c[j]:="\t"; INC(j);
                  END;

          | "\"" :  c[j]:="\""; INC(j);

          | "v" : IF mod THEN
                    c[j]:="x"; INC(j);
                    c[j]:="0"; INC(j);
                    c[j]:="B"; INC(j);
                  ELSE;
                    c[j]:="\x0B"; INC(j);
                  END;

          | "x" : IF mod THEN
                    INC(i);
                    c[j]:="x"; INC(j);
                    c[j]:=s[i]; INC(i); INC(j);
                    c[j]:=s[i]; INC(j);
                  ELSE
                    INC(i);
                    (* $RangeChk- *)
                    FOR k := 0 TO 1 DO
                      s[i+k]:=CAP(s[i+k]);
                      z:=0;
                      w:=0;
                      CASE s[i+k] OF
                        | "0".."9" : z:=ORD(s[i+k])-ORD("0");
                        | "A".."F" : z:=ORD(s[i+k])-ORD("A") +10;
                      ELSE cd.error := cl.errWrongHex; RETURN FALSE END;
                      w:=w*16+SHORT(SHORT(z));
                    END;
                    INC(i,1);
                    c[j]:=CHR(w); INC(j);
                    (* $RangeChk= *)
                  END;
  
          | "0".."7" : IF mod THEN
                          c[j]:=s[i]; INC(i); INC(j);
                          c[j]:=s[i]; INC(i); INC(j);
                          c[j]:=s[i]; INC(j);
                       ELSE
                          (* $RangeChk- *)
                          FOR k := 0 TO 2 DO
                            z:=0;
                            w:=0;
                            CASE s[i+k] OF
                              | "0".."7" : z:=ORD(s[i+k]) - ORD("0");
                            ELSE cd.error:= cl.errWrongOctal; RETURN FALSE END;
                            w:=w*8+SHORT(SHORT(z));
                          END;
                          INC(i,2);
                          c[j]:=CHR(w); INC(j);
                          (* $RangeChk= *)
                       END;
        ELSE cd.error:=cl.errWrongEscape; RETURN FALSE END;
      END;
    END;
    c[j]:="\o";
    NEW(bs,Strings.Length(c^)+20); (* inkl. Buffer für LengthBytes *)
    COPY(c^,bs^);
    RETURN TRUE;
  END Convert;

  PROCEDURE SetLengthBytes*(VAR s: ARRAY OF CHAR; n : cd.Node; len : LONGINT;source:BOOLEAN):BOOLEAN;
    VAR length : LONGINT;
        int    : SHORTINT;
        char   : CHAR;
        buf    : ARRAY 6 OF CHAR;
    BEGIN
      IF len = 0 THEN RETURN TRUE END;
      IF n.converted = NIL THEN
        IF ~Convert(n.fullstr^,FALSE,FALSE,n.converted) THEN RETURN FALSE END;
      END;
      length:=Strings.Length(n.converted^);
      WHILE len # 0 DO
        int:=SHORT(SHORT(length));
        IF ~ source THEN
          Strings.InsertChar(s,0,CHR(int));
        ELSE
          IF ~Conversions.IntToHex(int, buf, 2) THEN RETURN FALSE END;;
          Strings.Insert(buf,0,"\\x");
          Strings.Delete(buf,4,1);
          Strings.Insert(s,0,buf);
        END;
        DEC(len);
        length:=SYSTEM.ROT(length,-8);
      END;
      RETURN TRUE;
    END SetLengthBytes;

  PROCEDURE CutName*(VAR name:ARRAY OF CHAR;sufonly:BOOLEAN);
  (*------------------------------------------
    :Input.     name = Filename inkl. Pfad und Postfix
    :Output.    name = Filename ohne Pfad und Postfix
    :Semantic.  Entfernt aus dem Filenamen den Pfad und den Postfix
    :Note.
    :Update.    16-May-1993 [awn] - erstellt.
    :Update.    15-Jun-1993 [awn] - Entfernt jetzt auch ":"
  --------------------------------------------*)
    VAR pos : LONGINT;
    BEGIN
      IF ~sufonly THEN
        REPEAT
          pos:=Strings.Occurs(name,"/");
          IF pos = -1 THEN
            pos:=Strings.Occurs(name,":");
          END;
          IF pos # -1 THEN
            Strings.Delete(name,0,pos+1);
          END;
        UNTIL pos = -1;
      END;
      pos:=Strings.Occurs(name,".");
      IF pos # -1 THEN
        Strings.Delete(name,pos,Strings.Length(name)-pos);
      END;
    END CutName;


  PROCEDURE JoinString*(VAR s:BT.DynString; list : ll.List):BOOLEAN;
    VAR n : ll.Node;
    BEGIN
      n:=list.head;
      s:=NIL;
      WHILE n # NIL DO
        ms.AddString(s,n(cd.SNode).string^);
        n:=n.next;
      END;
      RETURN TRUE;
    END JoinString;

  PROCEDURE GetString*(VAR fh:fs.File; node:cd.Node;VAR line:LONGINT):BOOLEAN;
  (*------------------------------------------
    :Input.     fh = FileHandle
    :Output.    string = Zeichenkette die in der Datei steht
    :Semantic.  Erstellt die Zeichenkette aus der Datei die gerade anliegt
    :Note.      Es werden auch mehrzeilige Zeichenketten zu einer zusammen gefügt
    :Note.      dafür müssen die Zeilen, bis auf die letzte mit einem `\` enden.
    :Update.    16-May-1993 [awn] - erstellt.
    :Update.    17-May-1993 [awn] - Fehlernummer werden jetzt gesetzt
  --------------------------------------------*)
    VAR first : BOOLEAN;
        ok : BOOLEAN;
        exit : BOOLEAN;
        pos: LONGINT;
        string : BT.DynString;
        n : cd.SNode;
    BEGIN
      ok:=TRUE;
      exit:=FALSE;
      string:=NIL;
      first:=TRUE;
      node.strings:=ll.Create();
      node.strings.Init();
      WHILE ok & ~exit DO
        IF ~first THEN
          ok:=fs.ReadLongString(fh);
          INC(line);
        END;
        first:=FALSE;
        IF ok THEN
          IF fh.string^ # "" THEN
            pos:=ms.FirstNoSpace(fh.string^);
            IF fh.string[pos] # ";" THEN
              pos:=ms.LastNoSpace(fh.string^);
              IF fh.string[pos-1] = "\\" THEN
                fh.string[pos-1]:= "\o";
              ELSE
                exit:=TRUE;
              END;
              NEW(n);
              NEW(n.string,Strings.Length(fh.string^)+2);
              COPY(fh.string^,n.string^);
              node.strings.AddTail(n);
            END;
          ELSE
            NEW(n);
            NEW(n.string,3);
            n.string^:="";
            node.strings.AddTail(n);
            exit:=TRUE;
          END;
        ELSE
          cd.error:=cl.errCommentInString;
          cd.para1:=line;
          ok:=FALSE;
        END;
      END;
      (* $IFNOT GarbageCollector *)
      DISPOSE(string);
      (* $END *)
      RETURN ok;
    END GetString;

END StringConvert.
