______________________________________________________________

Aufgabe 10.1
___________
Quelltext:

MODULE CD EXPORTS Main;
IMPORT IO, FileRd, Rd, FileWr, Wr, Text, Pathname, OSError, Thread;

TYPE
          RefT = REF ELEMENT;
    ELEMENT = RECORD
              key : TEXT;
              interpret : TEXT;
              titel : TEXT;
              label : TEXT;
              srnr : TEXT;
              parent : RefT;
              right : RefT;
              left : RefT;
END;

VAR Wahl, Sort : CHAR;
VAR neueCD, tree : REF ELEMENT;
VAR Channel : Wr.T;
VAR Pfad : Pathname.T;
VAR RdChannel : Rd.T;
VAR Line : TEXT;
VAR Von, Bis : INTEGER;

(*-------------------------------------------------------------------*)
(* Prozedur insert, liest Argumente: Baum in den eingefuegt wird,    *)
(* (tree) einzufuegendes Element (neueCD), keine Rueckgabewerte.     *)
(* Fuegt Datensatz (neueCD) in den Baum ein.                         *)
(*-------------------------------------------------------------------*)

PROCEDURE insert(VAR tree : RefT; VAR neueCD : RefT) =

BEGIN

  (* sucht (rekursiv) passende Position und fuegt, wenn gefunden *)
  (* als neues Element in den Baum ein                           *)

  (*Baum leer? Einfuegen!*)
  IF tree = NIL THEN tree := neueCD;

  (*Element gleich? Genauer vergleichen! Wenn alles gleich, ignorieren.*)
  ELSIF Text.Compare(tree^.key,neueCD^.key)=0 THEN
    IF Text.Compare(tree^.interpret,neueCD^.interpret)=1 THEN
      neueCD^.left := tree^.left;
      neueCD^.parent := tree;
      tree^.left:= neueCD;
    ELSIF Text.Compare(tree^.interpret,neueCD^.interpret)=-1 THEN
      neueCD^.right := tree^.right;
      neueCD^.parent := tree;
      tree^.right:= neueCD;
    ELSIF Text.Compare(tree^.titel,neueCD^.titel)=1 THEN
      neueCD^.left := tree^.left;
      neueCD^.parent := tree;
      tree^.left:= neueCD;
    ELSIF Text.Compare(tree^.titel,neueCD^.titel)=-1 THEN
      neueCD^.right := tree^.right;
      neueCD^.parent := tree;
      tree^.right:= neueCD;
    ELSIF Text.Compare(tree^.label,neueCD^.label)=1 THEN
      neueCD^.left := tree^.left;
      neueCD^.parent := tree;
      tree^.left:= neueCD;
    ELSIF Text.Compare(tree^.label,neueCD^.label)=-1 THEN
      neueCD^.right := tree^.right;
      neueCD^.parent := tree;
      tree^.right:= neueCD;
    ELSIF Text.Compare(tree^.srnr,neueCD^.srnr)=1 THEN
      neueCD^.left := tree^.left;
      neueCD^.parent := tree;
      tree^.left:= neueCD;
    ELSIF Text.Compare(tree^.srnr,neueCD^.srnr)=-1 THEN
      neueCD^.right := tree^.right;
      neueCD^.parent := tree;
      tree^.right:= neueCD;
    ELSE
    END;

  (*Passende Stelle gefunden? Einfuegen!*)
  ELSIF tree^.left#NIL AND Text.Compare(tree^.key,neueCD^.key)=1 THEN
    insert(tree^.left, neueCD);
  ELSIF tree^.right#NIL AND Text.Compare(tree^.key,neueCD^.key)=-1 THEN
    insert(tree^.right, neueCD);
  ELSIF tree^.left=NIL AND Text.Compare(tree^.key,neueCD^.key)=1 THEN
    neueCD^.parent := tree;
    tree^.left     := neueCD;
  ELSIF tree^.right=NIL AND Text.Compare(tree^.key,neueCD^.key)=-1 THEN
    neueCD^.parent := tree;
    tree^.right    := neueCD;
 
  END;

END insert;

(*-------------------------------------------------------------------*)
(* Prozedur write, liest Argumente: Baum (tree) aus dem gelesen wird,*)
(* Datei, in die geschrieben wird (Pfad), keine Rueckgabewerte.      *)
(* Schreibt aktuellen Datensatz (tree) in die Datei.                 *)
(*-------------------------------------------------------------------*)

PROCEDURE write(tree : RefT; Pfad : Pathname.T) =

BEGIN
   LOOP
    TRY
      Channel:= FileWr.OpenAppend(Pfad);
      Wr.PutText(Channel,Text.Cat(tree^.interpret,Text.Cat(";",Text.Cat(tree^.titel,Text.Cat(";",Text.Cat(tree^.label,Text.Cat(";",Text.Cat(tree^.srnr,"\n"))))))));
      Wr.Close(Channel);
      EXIT;
    EXCEPT
      | Wr.Failure => IO.Put("\nSchreibfehler! Wiederholen [j/n]");
        Wahl:= IO.GetChar();EVAL IO.GetLine();
        IF Wahl#'J' AND Wahl#'j' THEN EXIT; END;
      | OSError.E => IO.Put("\nSchreibfehler! Wiederholen [j/n]");
        Wahl:= IO.GetChar();EVAL IO.GetLine();
        IF Wahl#'J' AND Wahl#'j' THEN EXIT; END;
      | Thread.Alerted => IO.Put("\nSchreibfehler! Wiederholen [j/n]");
        Wahl:= IO.GetChar();EVAL IO.GetLine();
        IF Wahl#'J' AND Wahl#'j' THEN EXIT; END;
    END;
   END;
END write;

(*-------------------------------------------------------------------*)
(* Prozedur put, liest Argumente: Baum (tree) der ausgelesen wird,   *)
(* Datei auf die geschrieben wird(Pfad), keine Rueckgabewerte.       *)
(* Ruft 'Write' mit Datensaetzen in geordenter Reihenfolge auf.      *)
(*  Aufrufe:                                                         *)
(* put -> write                                                      *)
(* put -> minimum                                                    *)
(*-------------------------------------------------------------------*)

PROCEDURE put(VAR tree : RefT; Pfad : Pathname.T) =

BEGIN

  IF tree^.left#NIL THEN  (* Lower Branch ausgeben *)
    put(tree^.left,Pfad);
    write(tree,Pfad);
  END;

 IF tree=minimum(tree) THEN
   write(tree,Pfad);
 END;


  IF tree^.right#NIL THEN  (* Upper Branch ausgeben *)
    put(tree^.right,Pfad);
  END;

END put;

(*-------------------------------------------------------------------*)
(* Prozedur read, liest Argumente: Baum(tree) in den eingefuegt wird,*)
(* Datei aus der gelesen wird, keine Rueckgabewerte.                 *)
(* Liest die Datensaetze der Datei aus und fuegt sie mit Aufruf      *)
(* insert in den Baum ein.                                           *)
(*  Aufrufe:                                                         *)
(* read -> insert                                                    *)
(*-------------------------------------------------------------------*)

PROCEDURE read(VAR tree : RefT; Pfad : Pathname.T) =

BEGIN

  TRY
    RdChannel:= FileRd.Open(Pfad);
    WHILE NOT Rd.EOF(RdChannel) DO
      Line:= Rd.GetLine(RdChannel);
      neueCD := NEW(RefT);
      FOR j:=1 TO 4 DO
        IF j>1 THEN
          Von:= Bis+1;
          Line:= Text.Sub(Line,Von);
        END;
        IF j<4 THEN
          Bis:= Text.FindChar(Line,';');
        END;
        CASE j OF
          | 1 => neueCD^.interpret:= Text.Sub(Line,0,Bis);
          | 2 => neueCD^.titel:= Text.Sub(Line,0,Bis);
          | 3 => neueCD^.label:= Text.Sub(Line,0,Bis);
          | 4 => neueCD^.srnr:= Text.Sub(Line,0,Text.Length(Line));
        ELSE 
        END;
      END;
      CASE Sort OF
        | '1' => neueCD^.key := neueCD^.interpret;
        | '2' => neueCD^.key := neueCD^.titel;
        | '3' => neueCD^.key := neueCD^.label;
        | '4' => neueCD^.key := neueCD^.srnr;
      ELSE 
      END;
      insert(tree, neueCD);
    END;
  EXCEPT
    | Rd.EndOfFile =>
    | Rd.Failure => IO.Put("Lesefehler!\n");
    | Thread.Alerted => IO.Put("Lesefehler!\n");
    | OSError.E => IO.Put("Lesefehler!\n");
  END;

  TRY Rd.Close(RdChannel);
  EXCEPT
    | Rd.Failure =>
    | Thread.Alerted =>
  END;

END read;

(*-------------------------------------------------------------------*)
(* Prozedur minimum, liest Argumente: Baum in dem gesucht wird,      *)
(* gibt Zeiger auf gefundes Element zureck. Geht so weit nach links *)
(* wie moeglich, gibt Zeiger auf dieses Element zurueck.             *)
(*-------------------------------------------------------------------*)

PROCEDURE minimum(tree : RefT) : RefT =

BEGIN

  (*Rufe solange mit lower part auf bis kl. Element*)
  IF tree^.left#NIL THEN
    tree:= minimum(tree^.left)
  END;

  RETURN tree

END minimum;

BEGIN

  (* Dateiname abfragen, wiederhole bis Erfolg, oder Abbruch*)

  LOOP
    IO.Put("Bitte geben sie den Namen der Zieldatei an:\n");
    Pfad:= IO.GetLine();
    TRY
      Channel:= FileWr.OpenAppend(Pfad);
      Wr.Close(Channel);
      EXIT
    EXCEPT
      | Wr.Failure => IO.Put("\nKann Datei nicht oeffnen! Wiederholen [j/n]");
        Wahl:= IO.GetChar();EVAL IO.GetLine();
        IF Wahl#'J' AND Wahl#'j' THEN EXIT; END;
      | OSError.E => IO.Put("\nKann Datei nicht oeffnen! Wiederholen [j/n]");
        Wahl:= IO.GetChar();EVAL IO.GetLine();
        IF Wahl#'J' AND Wahl#'j' THEN EXIT; END;
      | Thread.Alerted => EXIT;
    END;
  END;

  (* Sortierkriterien abfragen, wiederhole bis Erfolg*)

  LOOP
    IO.Put("\n");
    IO.Put("Bitte waehlen sie den Schluessel, nach dem sortiert werden soll:");
    IO.Put("\n[1] Kuenstler\n");
    IO.Put("[2] CD-Titel\n");
    IO.Put("[3] CD-Label\n");
    IO.Put("[4] Ser-Nr.\n");
    Sort:= IO.GetChar();
    EVAL IO.GetLine();
    IF Sort='4' OR Sort='3' OR Sort='2' OR Sort='1' THEN EXIT; END;
    IO.Put("\nIhre Wahl war ungueltig, versuchen sie es erneut.\n")
  END;  

  (* Datei auslesen*)

  read(tree, Pfad);

  (* Datei leeren*)

  TRY
    Channel:= FileWr.Open(Pfad);Wr.Close(Channel);
  EXCEPT
    | Wr.Failure => IO.Put("\nSchreibfehler!");
    | OSError.E => IO.Put("\nSchreibfehler!");
    | Thread.Alerted => IO.Put("\nSchreibfehler!");
  END;

  (* Baum in Datei schreiben*)

  put(tree, Pfad);


END CD.

Testlauf:

DATEIINHALT NACH EINFUEGEN:

alpha;123;emma;079753
alpha;25vdf;45g54;dfsgj
betha;mvkrs;s;45g54
opa;opas zeug;omas prod;0190-susi
;;;
ich;langer Text01;ganz lange Texte 01;01
acm;mca;cma;cam
cam;mca;cma;acm
wheat;corn;water;987..21 Damn! Grow!
this;that;so;what

PROGRAMMSTART:

Bitte geben sie den Namen der Zieldatei an:
neu.txt

Bitte waehlen sie den Schluessel, nach dem sortiert werden soll:
[1] Kuenstler
[2] CD-Titel
[3] CD-Label
[4] Ser-Nr.
1

PROGRAMMENDE

DATEIINHALT NACH SORTIEREN:

;;;
acm;mca;cma;cam
alpha;123;emma;079753
alpha;25vdf;45g54;dfsgj
betha;mvkrs;s;45g54
cam;mca;cma;acm
ich;langer Text01;ganz lange Texte 01;01
opa;opas zeug;omas prod;0190-susi
this;that;so;what
wheat;corn;water;987..21 Damn! Grow!

Testlaufende.