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

    Modul      :  ZPEingabe, V1.0
    Author     :  Raymond Horn
    Contents   :  Modul für 'ZapPrint'
                  Analyse von Steuerbefehlsworten und entsprechendes
                  Setzen der Druckparameter.

**********************************************************************)
(* Vorbereitete, aber noch nicht vollständig implementierte Strukturen,
   für folgende Versionen sind auskommentiert.  *)

IMPLEMENTATION MODULE ZPEingabe;

FROM  Terminal      IMPORT   Write, WriteLn, WriteInt, WriteString;
FROM  Conversions   IMPORT   StrToVal;
FROM  String        IMPORT   Length, CopyPart;

CONST ZeichendichtenAnzahl = 6;

VAR   Defaults, LocalMem         : PrintParameter;
      KopfDefaults               : Kopfformat;

(*      Zeichendichte     : ARRAY [1..ZeichendichtenAnzahl] OF CARDINAL;
         (* Enthält alle ansteuerbaren Zeichendichten *)
*)

PROCEDURE InitDefaults();
(* Sollten in einer späteren Version aus Preferences eingelesen werden *)
   BEGIN
(*      Zeichendichte[ 1 ] := 5;
      Zeichendichte[ 2 ] := 6;
      Zeichendichte[ 3 ] := 10;
      Zeichendichte[ 4 ] := 12;
      Zeichendichte[ 5 ] := 17;
      Zeichendichte[ 6 ] := 20; *)
      WITH Defaults DO
         ErsteSeite           := 1;                    (*    Anfangsseite    *)
         LetzteSeite          := MAX( CARDINAL );      (*      bis Ende      *)
         Seitenlaenge         := 60;                 (*   Zeilen pro Seite   *)
         Zeilenlaenge         := 80;               (*   Zeichen pro Zeile    *)
         LinkerRand           := 10;               (*       in Zeichen       *)
         Tabulator            := 3;          (* Tabulator bei Zeilenüberlauf *)
         Zeichendichte        := 12;      (*** noch nicht implementiert!   ***)
         SeitenSprung         := FALSE;          (*  Nur jede zweite Seite?  *)
         NurGerade            := FALSE;          (* Auswahl: gerade/ungerade *)
         Zeilennummer         := FALSE;         (* Ausdruck mit Zeilennummern *)
         FFamEnde             := TRUE;     (* Seitenvorschub nach Dateiende? *)
         KopfAbSeite          := 0;
               (* Start für Kopfzeilendruck. 0 -> keine Kopfzeile *)
            Seitennummer         := TRUE;     (*    Seitennummer im Kopf?    *)
            NameImKopf           := TRUE;
            DatumImKopf          := FALSE;
            ZeitImKopf           := FALSE;
      END;  (* WITH *)
      WITH KopfDefaults DO
         DivisionChar   := '*';     (* Zeichen für Trennzeile *)
         DivOben        := TRUE;    (* Auswahl: Trennzeile oben *)
         DivUnten       := TRUE;    (* Auswahl: Trennzeile unten *)
         NummerText     := TRUE;    (* Auswahl: Text vor Seitennummer *)
         NameText       := TRUE;    (* Auswahl: Text vor Dateiname *)
         NummerPos      := mittig;  (* Position der Seitennummer *)
         NamePos        := rechts;  (* Position des Dateinamens *)
         ZeitPos        := links;   (* Position der Zeit *)
         DatumPos       := links;   (* Position der Datums *)
      END;  (* WITH *)
   END InitDefaults;

PROCEDURE LoadDefaultPPars();
(* Lädt die Defaults als aktuelle Printparameter. *)
   BEGIN
      PPars := Defaults;
      Kopf  := KopfDefaults
   END LoadDefaultPPars;
(*
PROCEDURE SaveAsDefaults();
(* Speichert die aktuellen Printparameter auf Diskette -> S: *)
   BEGIN
      WriteString
         ( "** Defaults speichern ist leider noch nicht implementiert! **\n" );
   END SaveAsDefaults;
*)
PROCEDURE SaveCurrentPPars();
(* Speichert die aktuellen Printparameter in einer internen Variablen. *)
   BEGIN
      LocalMem := PPars
   END SaveCurrentPPars;

PROCEDURE RestoreSavedPPars();
(* Schreibt die gespeicherten Printparameter wieder nach PPars. *)
   BEGIN
      PPars := LocalMem
   END RestoreSavedPPars;

PROCEDURE DruckeSatzteil( String : ARRAY OF CHAR; VAR Komma : BOOLEAN );
   BEGIN
      IF Komma THEN Write( ',' ) ELSE Komma := TRUE END;
      WriteString( String )
   END DruckeSatzteil;

PROCEDURE DisplaySettings();
(* Zeigt die aktuelle Einstellung der Druckparameter an. *)
   VAR   Komma    : BOOLEAN;
   BEGIN
      WITH PPars DO
         WriteString( "\naktuelle Programmeinstellung:\n\n" );
         WriteString( "Ausdruck" );
         IF ErsteSeite = 1 THEN WriteString( " von Anfang" )
         ELSE WriteString( " ab Seite " ); WriteInt( ErsteSeite, 1 )
         END;  (* IF *)
         IF LetzteSeite = MAX( CARDINAL ) THEN WriteString( " bis Ende" )
         ELSE WriteString( " bis Seite " ); WriteInt( LetzteSeite, 1 )
         END;  (* IF *)
         WriteString( ".\n" );
         WriteInt( Seitenlaenge, 2 ); WriteString( " Zeilen pro Seite\n" );
         WriteInt( Zeilenlaenge, 2 ); WriteString( " Zeichen pro Zeile\n" );
(*         WriteString( "Linker Rand: " );WriteInt( LinkerRand, 1 ); WriteLn;
         WriteLn;
         WriteString( "Zeichendichte: " ); WriteInt( Zeichendichte, 1 );
         WriteLn; *)
         IF SeitenSprung THEN
            IF NurGerade THEN WriteString( "Nur gerade Seiten!\n\n" )
            ELSE WriteString( "Nur ungerade Seiten!\n\n" )
            END
         ELSE WriteString( "Alle Seiten!\n\n" )
         END;
         IF KopfAbSeite > 0 THEN
            WriteString( "Kopfzeile ab Seite " ); WriteInt( KopfAbSeite, 1 );
            WriteString( " mit" );
            Komma := FALSE;
            IF NameImKopf THEN DruckeSatzteil( " Dateiname", Komma ) END;
            IF Seitennummer THEN DruckeSatzteil( " Seitennummer", Komma ) END;
(*            IF DatumImKopf THEN DruckeSatzteil( " Datum", Komma )  END;
            IF ZeitImKopf THEN DruckeSatzteil( " Zeit", Komma ) END;       *)
            WriteString( ".\n" );
         ELSE WriteString( "Ohne Kopfzeile!\n" )
         END;
         IF Zeilennummer THEN WriteString("Mit Zeilennummern\n")
         ELSE WriteString("Keine Zeilennummern\n")
         END;
         IF FFamEnde THEN WriteString("Seitenvorschub nach der letzten Seite.\n")
         ELSE WriteString("KEIN Seitenvorschub nach der letzten Seite.\n")
         END;
         WriteLn
      END
   END DisplaySettings;
(*
PROCEDURE ZeichendichteAnpassung( ZD : CARDINAL );
   VAR   Zaehler  :  CARDINAL;
         found    :  BOOLEAN;
   BEGIN
      Zaehler := 1;
      WHILE ( Zaehler <= ZeichendichtenAnzahl ) AND
            ( ZD # Zeichendichte[ Zaehler ] ) DO
         INC( Zaehler )
      END;  (* WHILE *)
      IF Zaehler <= ZeichendichtenAnzahl THEN
            PPars.Zeichendichte := ZD
      ELSE
         IF ZD = 0 THEN
            PPars.Zeichendichte := Defaults.Zeichendichte
         ELSE
            WriteString( "*** Zeichendichte " );WriteInt( ZD, 1 );
            WriteString( " CPI noch nicht implementiert -> keine Änderung. ***\n" )
         END   (* IF 2 *)
      END   (* IF *)
   END ZeichendichteAnpassung;
*)
PROCEDURE IsDigit( VAR C : CHAR) : BOOLEAN;
(* überprüft ob C eine Ziffer ist *)
   BEGIN
      RETURN ( C >= '0' ) AND ( C <= '9' )
   END IsDigit;

PROCEDURE HowLongIsNumber( VAR String : ARRAY OF CHAR;
                           Pos : CARDINAL ) : CARDINAL;
(* gibt die in 'String' ab 'Pos' aufeinanderfolgenden Ziffern an *)
   VAR   Zaehler, Len  :  CARDINAL;
   BEGIN
      Zaehler := 0;
      Len := Length( String );
      WHILE ( Pos + Zaehler < Len-1 ) AND
            IsDigit( String[ Pos + Zaehler + 1 ] ) DO
         INC( Zaehler )
      END;
      RETURN Zaehler
   END HowLongIsNumber;

PROCEDURE GetNumber( SearchText : ARRAY OF CHAR; VAR Pos, Num : CARDINAL;
                     VAR truncated : BOOLEAN );
(* Liest aus 'SearchText' nach 'Pos' eine positive Zahl ein und gibt diese
   in Num zurück. 'Pos' wird auf das Ende dieser Zahl  gesetzt.
   'truncated' zeigt an, ob der gelesene Wert tatsächlich übernommen wurde.
   Kein Problem -> truncated = FALSE   *)
   VAR   TextLen, NumLen      : CARDINAL;
         Nummer               : LONGINT;
         NStr                 : ARRAY [0..5] OF CHAR;
         err, signed          : BOOLEAN;
   BEGIN
      Nummer := 0;
      NumLen := HowLongIsNumber( SearchText, Pos );
      IF NumLen > 0 THEN
         CopyPart( NStr, SearchText, Pos+1, NumLen ); (* String *)
            StrToVal( NStr, Nummer, signed, 10, err); (* Conversions *)
            IF err THEN
               WriteString("StrToVal failed!\n");
               Nummer := 0;
               NumLen := 0;
               truncated := TRUE
            END;  (* IF 2 *)
         INC( Pos, NumLen )
      END;  (* IF *)
      IF Nummer < MAX( CARDINAL ) THEN Num := Nummer; truncated := FALSE
      ELSE Num := MAX( CARDINAL ); truncated := TRUE
      END;   (* IF *)
   END GetNumber;

PROCEDURE NeuerZustand( Befehlswort : ARRAY OF CHAR );
(* Setzt die Steuervariablen wie gefordert *)
   VAR   Eingabe,           (* Zwischenwertspeicher *)
         Len, NumLen,
         Pos   :  CARDINAL; (* zeigt auf die aktuelle Position im Befehlswort *)
         Positiv,           (* Steuert die Zuordnung der Druckparameter *)
         trunc :  BOOLEAN;  (* zeigt an, ob GetNumber Probleme hatte *)
         ZahlWort : ARRAY [0..5] OF CHAR;
   BEGIN
      Pos := 0;
      Len := (* String *) Length( Befehlswort );
      WHILE Pos < Len DO
         CASE Befehlswort[ Pos ] OF
            '-' :    Positiv  := FALSE    |
            '+' :    Positiv  := TRUE     |
            'a' :    GetNumber( Befehlswort, Pos, PPars.ErsteSeite, trunc );
                     IF PPars.ErsteSeite = 0 THEN
                        PPars.ErsteSeite := Defaults.ErsteSeite;
                     END;
                     IF PPars.LetzteSeite < PPars.ErsteSeite THEN
                        PPars.ErsteSeite := PPars.LetzteSeite;
                     END                                 |
            'e' :    GetNumber( Befehlswort, Pos, PPars.LetzteSeite, trunc );
                     IF PPars.LetzteSeite = 0 THEN
                        PPars.LetzteSeite := Defaults.LetzteSeite;
                     END;
                     IF PPars.LetzteSeite < PPars.ErsteSeite THEN
                        PPars.LetzteSeite := PPars.ErsteSeite;
                     END                                 |
            'v' :    PPars.SeitenSprung      := FALSE    |
            'u' :    PPars.SeitenSprung      := TRUE;
                     PPars.NurGerade         := FALSE    |
            'g' :    PPars.SeitenSprung      := TRUE;
                     PPars.NurGerade         := TRUE     |
            'f' :    PPars.FFamEnde          := Positiv  |
            'z' :    GetNumber( Befehlswort, Pos, PPars.Zeilenlaenge, trunc );
                     IF PPars.Zeilenlaenge = 0 THEN
                        PPars.Zeilenlaenge := Defaults.Zeilenlaenge;
                     END                                 |
            'l' :    GetNumber( Befehlswort, Pos, PPars.Seitenlaenge, trunc );
                     IF PPars.Seitenlaenge = 0 THEN
                        PPars.Seitenlaenge := Defaults.Seitenlaenge;
                     END                                 |
(*            'r' :    GetNumber( Befehlswort, Pos, PPars.LinkerRand, trunc );
                     IF PPars.LinkerRand = 0 THEN
                        PPars.LinkerRand := Defaults.LinkerRand;
                     END                                 |
            'c' :    GetNumber( Befehlswort, Pos, Eingabe, trunc );
                     ZeichendichteAnpassung( Eingabe )   |              *)
            'n' :    PPars.Zeilennummer   := Positiv  |
            'k' :    IF IsDigit( Befehlswort[ Pos+1 ] ) THEN
                        GetNumber( Befehlswort, Pos, PPars.KopfAbSeite, trunc );
                     ELSIF Positiv THEN
                        PPars.KopfAbSeite := 1;
                     END;  (* IF *)
                     IF NOT Positiv THEN
                        PPars.KopfAbSeite := 0;
                     END   (* IF *)                      |
               's' :    PPars.Seitennummer   := Positiv  |
               'd' :    PPars.NameImKopf     := Positiv  |
(*               'x' :    PPars.DatumImKopf    := Positiv  |
               't' :    PPars.ZeitImKopf     := Positiv  |              *)
            'q' :    Quiet    := Positiv
         ELSE
            IF IsDigit( Befehlswort[ Pos ] ) THEN
               NumLen := HowLongIsNumber( Befehlswort, Pos-1 );
               CopyPart( ZahlWort, Befehlswort, Pos, NumLen ); (* String *)
               INC( Pos, NumLen-1 );
               WriteString( "*** Die Zahl '" ); WriteString( ZahlWort );
               WriteString( "' wird ignoriert! ***\n" )
            ELSE
               WriteString( "*** Befehl '" ); Write( Befehlswort[ Pos ] );
               WriteString( "' leider noch nicht implementiert! ***\n" )
            END;  (* IF *)
         END;  (* CASE *)
         INC( Pos )
      END;   (* WHILE *)
      IF ( Len = 1 ) OR NOT Quiet THEN DisplaySettings END
   END NeuerZustand;

BEGIN

   InitDefaults;
   LoadDefaultPPars

END ZPEingabe.
