(**********************************************************************

:Program.    SimpleSort.mod
:Contens.    Einfaches Programm zu sortieren von Dateien.
:Contens.    Gebrauch wie das Amiga-DOS Sort ohne weitere Optionen.
:Author.     Bernd Braun
:Address.    Lippestr. 11, D-3300 Braunschweig
:Phone.      0531/845498
:Copyright.  Public Domain
:Language.   Modula-2
:Translator. M2Amiga A+L V3.32d
:Imports.    DynStr, NewInOut, SortLib
:History.    V1.0 20.Dez.1990

***********************************************************************)

MODULE SimpleSort;

(* $S- $V- $F- *)

   FROM Arguments IMPORT
      NumArgs, GetArg;
   FROM Arts IMPORT
      Assert;
   FROM ASCII IMPORT
      nul, eol, eof;
   FROM DynStr IMPORT
      DynString, MakeDynString, DynStringCompare, StatString;
   FROM NewInOut IMPORT
      WriteStringFile, FILE, Open, Close, ModeNew,
      ModeOld, stdout, done, WriteString, WriteLn, ReadFile;
   FROM SortLib IMPORT
      QuickSort;
   FROM SYSTEM IMPORT
      ADR, ADDRESS, TSIZE;

   CONST
      maxfeld        = 10000;
      (* Maximale Anzahl von Zeilen. Reicht hoffentlich immer aus,
         Wenn nicht einfach erhöhen. *)
      maxlen         = 160;
      (* Maximale Länge einer Zeile. Reicht hoffentlich immer aus,
         Wenn nicht einfach erhöhen. *)

   VAR
      cmdargs,
      arglen,
      n, m           : INTEGER;
      Str,
      nameinfile,
      nameoutfile    : StatString;
      DynS           : DynString;
      infile,
      outfile        : FILE;
      DynStrFeld     : ARRAY [ 0 .. maxfeld - 1 ] OF DynString;

   PROCEDURE Gebrauch ();
   BEGIN
      WriteString ( 'SimpleSort infile [outfile]' );
      WriteLn; WriteLn;
      WriteString ( 'Sortiert ein File infile.' );
      WriteLn;
      WriteString ( 'Ausgabe wird nach outfile geschickt, ' );
      WriteLn;
      WriteString ( 'falls angegeben, sonst nach stdout.' );
      WriteLn;
   END Gebrauch;

   (* Liest eine Zeile aus file und liefert sie in Str zurück.
      Gibt FALSE zurück, falls Fileende erreicht, sonst TRUE. *)
   PROCEDURE LiesZeile ( VAR Str  : StatString;
                             file : FILE ) : BOOLEAN;
      VAR
         n  : INTEGER;
         c  : CHAR;
         ok : BOOLEAN;
   BEGIN
      ok := TRUE;
      n  := 0;
      LOOP
         ReadFile ( file, c );
         IF c = eof THEN
            ok := FALSE;
            EXIT
         END;
         Str [ n ] := c;
         INC ( n );
         IF c = eol THEN
            EXIT;
         END;
      END;
      Str [ n ] := nul;
      RETURN ok;
   END LiesZeile;

   (* Kopiert die Adresse von DynString sour nach Adresse von
      DynString dest. *)
   PROCEDURE CopyStr ( dest, sour : ADDRESS );
      VAR
         x, y : POINTER TO DynString;
   BEGIN
      x := dest;
      y := sour;
      x ^ := y ^;
   END CopyStr;

   (* Vergleicht zwei DynStrings. *)
   PROCEDURE CompStr ( a, b : ADDRESS ) : INTEGER;
      VAR
         x, y : POINTER TO DynString;
   BEGIN
      x := a;
      y := b;
      RETURN DynStringCompare ( x ^, y ^ );
   END CompStr;

BEGIN
   (* Argumente feststellen und Files öffnen. *)
   cmdargs := NumArgs();
   IF ( cmdargs = 0 ) OR ( cmdargs > 2 ) THEN
      Gebrauch ();
      RETURN;
   END;
   IF cmdargs = 2 THEN
      GetArg ( 2, nameoutfile, arglen );
      outfile := Open ( nameoutfile, ModeNew );
      Assert ( done, ADR ( "Kann Ausgabefile nicht öffnen!" ) );
   ELSE
      outfile := stdout;
   END;
   GetArg ( 1, nameinfile, arglen );
   infile := Open ( nameinfile, ModeOld );
   Assert ( done, ADR ( "Kann Eingabefile nicht öffnen!" ) );

   (* Eingabefile einlesen. *)
   n := 0;
   LOOP
      IF NOT LiesZeile ( Str, infile ) THEN
         EXIT;
      END;
      MakeDynString ( Str, DynS );
      DynStrFeld [ n ] := DynS;
      INC ( n );
   END;

   (* StrFeld sortieren. *)
   QuickSort ( DynStrFeld, CompStr, CopyStr, n, TSIZE ( ADDRESS ) );

   (* Sortiertes Feld ausgeben. *)
   m := 0;
   LOOP
      WriteStringFile ( outfile, DynStrFeld [ m ] ^ );
      INC ( m );
      IF ( m > n ) THEN EXIT END;
   END;
END SimpleSort.
