
;******************************************************************************
;                  Vergleichsprogramm Version 1.0 - Cmp
; Das Programm vergleicht zwei Binärfiles miteinander und meldet, ob und wo
; sie unterschiedlich sind.
;
;                  Copyright in 1990 by Dietmar Heidrich.
; Dieses Programm ist Bestandteil von OMA V1.7 und nur als Beispiel vorhan-
; den.  Seine Vervielfältigung, Veränderung oder Verbreitung ist verboten.
;
;   Dieses Cmp kann NICHT gleichzeitig von mehreren Tasks benutzt werden,
;          wenn es unter der Workbench 1.3 resident gehalten wird.
;******************************************************************************

      SECTION  CmpCODE,CODE

      NOPAGE
      NOLIST

      INCLUDE  "exec/types.i"
      INCLUDE  "exec/alerts.i"
      INCLUDE  "exec/tasks.i"
      INCLUDE  "libraries/dos.i"
      INCLUDE  "libraries/dosextens.i"
      INCLUDE  "lvo/exec.i"
      INCLUDE  "lvo/dos.i"

      LIST




BP                EQUR  A5

_SysBase          EQU   4

TAB               EQU   9
LF                EQU   10
CR                EQU   13
SPACE             EQU   ' '
PUFFERGROESSE     EQU   10000
MAXIMUM_ARGUMENTS EQU   6
MAXIMUM_ARGBUFFER EQU   256



CALL  MACRO
   IFEQ  NARG-2
      move.l   \2,a6
   ENDC
   IFLE  NARG-2
      jsr      _LVO\1(a6)
      MEXIT
   ENDC
      FAIL  CALL MACRO ERROR
      ENDM



STRINGLF MACRO
      dc.b  '\1',LF,0
         ENDM










;****************************************************************************
; Der Beginn.

Startup
      lea      Basisadresse+32768,BP

      BASEREG  BP










;****************************************************************************
; Variablen.

      SECTION  CmpBSS,BSS

      CNOP    0,4

Basisadresse

_DOSBase    ds.l  1
HauptSP     ds.l  1
_stdout     ds.l  1

argvArray   ds.l  MAXIMUM_ARGUMENTS
argvBuffer  ds.b  MAXIMUM_ARGBUFFER



   CNOP  0,4

AnfangBss


Seitennummer   ds.l  1
Fehlerflag     ds.l  1

Filename1   ds.l  1
Filename2   ds.l  1

File1       ds.l  1
File2       ds.l  1

Filepuffer1 ds.b  PUFFERGROESSE
Filepuffer2 ds.b  PUFFERGROESSE

Formatierstring   ds.b  256


   CNOP  0,4

EndeBss










;****************************************************************************
; Parse die CLI-Argumente.

      SECTION  CmpCODE,CODE

ParseArgumente

      ; Öffne DOS.
      move.l   SP,HauptSP
      movem.l  d0/a0,-(SP)
      lea      DOSName(PC),a1
      moveq    #LIBRARY_VERSION,d0
      CALL     OpenLibrary,_SysBase
      move.l   d0,_DOSBase
      bne.s    1$

      BASEREG  OFF

      ; Fehler: DOS nicht offen.
      move.l   #(AG_OpenLib!AO_DOSLib),d7
      lea      AlertWert(PC),a5
      CALL     Alert
      addq     #2*4,SP              ; korrigiere Stack
      moveq    #100,d0
      rts                           ; zurück zum DOS

      BASEREG  BP

      ; Initialisiere Zähler und Zeiger.
1$    move.l   d0,a6
      CALL     Output
      move.l   d0,_stdout
      move.l   #MAXIMUM_ARGBUFFER-1,d7
      moveq    #MAXIMUM_ARGUMENTS-1,d6 ; Argumentzähler
      lea      argvArray,a1
      lea      argvBuffer,a3
      movem.l  (SP)+,d0/a0
      cmp.l    d7,d0                ; Kommandozeile zu lang ?
      bhs.s    FehlerBufferOverflow ; ja

      ; Parse die Argumente.
      moveq    #SPACE,d5            ; verkürzt Code
      moveq    #'"',d3              ; verkürzt Code
      bra      NächstesArgument



ArgumentSchleife
      move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; legales Zeichen ?
      bls.s    NächstesArgument     ; nein, nächstes Zeichen

      move.l   a3,a2                ; Zeiger auf Argumentpuffer-Stelle merken
      cmp.b    d3,d4                ; ist es doppeltes Hochkomma ?
      bne.s    1$                   ; nein
      bra.s    3$                   ; ja



      ; Argument darf mit einem SPACE enden.
2$    move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; Argument beendet ?
      bls.s    ArgumentEnde         ; ja
1$    cmp.b    #'=',d4              ; ein '=' ist nicht erlaubt
      beq.s    FehlerEquateUse      ; wenn Fehler
      move.b   d4,(a3)+             ; speichere Zeichen
      dbra     d0,2$                ; Zeichen übrig ?
      bra.s    ArgumentEnde         ; nein



      ; Argument ist in doppelte Hochkommata eingefaßt.
4$    move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; Argument beendet ?
      blo.s    FehlerIllegalArgEnd  ; ja, Fehler

      ; Endet Argument mit doppeltem Hochkomma ?
      cmp.b    d3,d4
      bne.s    5$                   ; nein
      subq     #1,d0                ; Zeichen übrig ?
      blt.s    ArgumentEnde         ; nein, alles OK
      move.b   (a0)+,d4             ; ja, nächstes Zeichen
      cmp.b    d5,d4                ; legales Zeichen ?
      bls.s    ArgumentEnde         ; ja, alles OK
      bra.s    FehlerIllegalArgEnd  ; nein, Fehler

      ; Ist es ein Stern ?
5$    cmp.b    #'*',d4
      bne.s    6$                   ; nein, speichere Zeichen
      subq     #1,d0                ; Zeichen übrig ?
      blt.s    FehlerIllegalArgEnd  ; nein, Fehler
      move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; Argument beendet ?
      blo.s    FehlerIllegalArgEnd  ; ja, Fehler

6$    move.b   d4,(a3)+             ; speichere Zeichen

      ; Es MUß noch Zeichen geben, oder Fehler.
3$    dbra     d0,4$                ; Zeichen übrig ?



FehlerIllegalArgEnd
      lea      TextBadArgs(PC),a0
      bra.s    ArgumentFehler

FehlerBufferOverflow
      lea      TextBufferOverflow(PC),a0
      bra.s    ArgumentFehler

FehlerEquateUse
      lea      TextEquateUse(PC),a0
      bra.s    ArgumentFehler

FehlerTooManyArguments
      lea      TextTooManyArgs(PC),a0

ArgumentFehler
      bra      Programmende



ArgumentEnde
      clr.b    (a3)+                ; Argumentende
      subq.l   #1,d6                ; noch freie Zeiger übrig ?
      ble.s    FehlerTooManyArguments  ; nein
      move.l   a2,(a1)+             ; merke Zeiger auf Argumentstring

NächstesArgument
      dbra     d0,ArgumentSchleife  ; Zeichen übrig ?

      ; Setze die Startwerte.
      lea      argvArray,a0
      neg      d6
      add      #MAXIMUM_ARGUMENTS-1,d6
      move.l   d6,d0










;****************************************************************************
; Beginn des Programmes.  D0 enthält die Anzahl der CLI-Parameter und A0 den
; Zeiger auf das Feld der Zeiger auf die CLI-Argumente.

_main
      ; Initialisierung.
      lea      AnfangBss,a1
      move     #(EndeBss-AnfangBss)/4-1,d1
1$    clr.l    (a1)+
      dbra     d1,1$
      move.l   a0,a2                ; retten

      ; Es müssen 2 Argumente sein.
      subq.l   #2,d0
      bne      FehlerIllegalArgEnd
      move.l   (a0)+,Filename1
      move.l   (a0)+,Filename2

      ; Lösche die Signale.
      moveq    #0,d0
      move.l   #SIGBREAKF_CTRL_D!SIGBREAKF_CTRL_C,d1
      CALL     SetSignal,_SysBase

      ; Öffne das erste File.
      move.l   Filename1,d1
      move.l   d1,a4
      move.l   #MODE_OLDFILE,d2
      CALL     Open,_DOSBase
      move.l   d0,File1
      bne.s    2$
      ; Fehler: File nicht offen.
3$    CALL     IoErr
      move.l   a4,-(SP)
      move.l   d0,-(SP)
      lea      TextErrorOpen(PC),a0
      bra      Programmende

      ; Öffne das zweite File.
2$    move.l   Filename2,d1
      move.l   d1,a4
      move.l   #MODE_OLDFILE,d2
      CALL     Open
      move.l   d0,File2
      beq.s    3$




      ; Fülle die Puffer.  A4 & A3 sind Pufferzeiger, D7 & D6 Restbytezähler.
8$    move.l   File1,d1
      move.l   Filename1,a2
      lea      Filepuffer1,a4
      move.l   a4,a0
      bsr      FuelleFilepuffer
      move.l   d0,d7
      move.l   File2,d1
      move.l   Filename2,a2
      lea      Filepuffer2,a3
      move.l   a3,a0
      bsr      FuelleFilepuffer
      addq.l   #1,Seitennummer
      move.l   d0,d6

      ; Sind beide Längen Null ?
      suba.l   a0,a0
      or.l     d7,d0
      beq.s    Programmende         ; ja, Files zu Ende und beide gleich


      ; Sind die Längen verschieden ?
      cmp.l    d6,d7
      beq.s    4$                   ; nein (BNE ist falsch)
      lea      TextDifferentLength(PC),a0
      bsr      Stringausgabe
      move     d6,d0
      cmp      d6,d7
      bhs.s    0$
      move     d7,d0
0$    moveq    #0,d1                ; mache BNE falsch
      bra.s    6$

7$    cmp.b    (a3)+,(a4)+
6$    dbne     d0,7$
      bne      Verschieden
      suba.l   a0,a0
      bra      Programmende         ; Files zu Ende


      ; Vergleiche die Bytes.
5$    cmp.b    (a3)+,(a4)+
4$    dbne     d6,5$

      beq      8$                   ; wenn bis hier gleich



Verschieden
      ; Berechne die Byteposition.
      move.l   Seitennummer,d0
      subq.l   #1,d0                ; da immer eine Seite zuviel
      move.l   d0,d1
      mulu     #PUFFERGROESSE,d0
      swap     d1
      mulu     #PUFFERGROESSE,d1
      swap     d1
      clr      d1
      add.l    d1,d0                ; Beginn der Seite
      lea      Filepuffer1,a0
      sub.l    a0,a4
      subq     #1,a4                ; da A4 einen zu weit zeigte
      add.l    a4,d0
      move.l   d0,-(SP)
      lea      TextFilesDiffer(PC),a0
      ; und durchfallen...










;******************************************************************************
; Beende das Programm.
; Eingabe:  A0 zeigt auf den Fehlerstring oder ist Null.

Programmende
      move.l   _DOSBase,a6
      move.l   a0,Fehlerflag        ; existiert String ?
      beq.s    1$                   ; nein
      bsr      Stringausgabe

      ; Schließe File 1.
1$    move.l   File1,d1
      beq.s    2$
      CALL     Close

      ; Schließe File 2.
2$    move.l   File2,d1
      beq.s    3$
      CALL     Close

      ; Schließe DOS.
3$    move.l   _DOSBase,d0
      beq.s    4$
      move.l   d0,a1
      CALL     CloseLibrary,_SysBase

      ; Zurück ins DOS.
4$    move.l   Fehlerflag,d0        ; trat Fehler auf ?
      beq.s    5$                   ; nein, D0=0 und fertig
      moveq    #RETURN_FAIL,d0      ; ja, melde AmigaDOS einen Fehler
5$    move.l   HauptSP,SP
      rts










;******************************************************************************
; Fülle einen Filepuffer.
; Eingabe:  A0 zeigt auf den Puffer.
;           A2 zeigt auf den Namen.
;           D1 enthält den Filezeiger.
; Ausgabe:  D0 enthält die Restbytes.

FuelleFilepuffer_REG REG   d1-d3/a0-a1/a6

FuelleFilepuffer
      movem.l  FuelleFilepuffer_REG,-(SP)
      move.l   a0,d2                ; Pufferzeiger
      move.l   #PUFFERGROESSE,d3
      CALL     Read,_DOSBase
      moveq    #-1,d1
      cmp.l    d0,d1                ; Lesefehler ?
      beq.s    1$                   ; ja
      movem.l  (SP)+,FuelleFilepuffer_REG
      rts

      ; Lesefehler im File.
1$    CALL     IoErr
      move.l   a2,-(SP)             ; Filename
      move.l   d0,-(SP)
      lea      TextReadError(PC),a0
      bra      Programmende










;******************************************************************************
; Konvertiere ein Langwort in einen maximal 11 Stellen langen Dezimalstring.
; Die Routine vermeidet überflüssige Nullen am Zahlenanfang wie z.B. 0019.
; Eingabe:  D0 enthält das Langwort.
;           A0 zeigt auf den Ablagestring.
; Ausgabe:  A0 zeigt direkt hinter den Dezimalstring.  Der Dezimalstring landet
;           im Ablagestring.

ErzeugeDezimalZahl_REG  REG   d0-d4/a1

ErzeugeDezimalZahl
      movem.l  ErzeugeDezimalZahl_REG,-(SP)
      lea      DezimalTabelle(PC),a1
      moveq    #9,d1                ; Stellenzähler
2$    cmp.l    (a1)+,d0             ; ist Stellenwertigkeit zu hoch ?
      bhs.s    1$
      dbra     d1,2$                ; ja, nächste Stelle
      moveq    #0,d1                ; hier landen wir, falls D0 = 0

1$    subq     #4,a1                ; ergibt die richtige Stellenwertigkeit

5$    move.l   d0,d3                ; Rest der Zahl retten
      moveq    #'0',d2
      move.l   (a1)+,d4             ; Stellenwertigkeit holen
      bra.s    3$

4$    addq     #1,d2                ; Ziffer höher stellen
3$    move.l   d3,d0                ; Rest der Zahl
      sub.l    d4,d3                ; ist Stellenwertigkeit zu hoch ?
      bcc.s    4$                   ; nein

      move.b   d2,(a0)+             ; ja, erhaltene Ziffer in Ausgabepuffer
      dbra     d1,5$                ; alle Stellen durch ?

      movem.l  (SP)+,ErzeugeDezimalZahl_REG
      rts










;******************************************************************************
; Die Stringausgabe formatiert einen String und gibt ihn auf _stdout aus.
; Eingabe:  A0 zeigt auf den auszugebenden String.

Stringausgabe_REG REG   d0-d3/a0-a3/a6

Stringausgabe
      movem.l  Stringausgabe_REG,-(SP)
      move.l   a0,a1
      lea      Formatierstring,a0   ; hier hinein kommt der fertige String
      move.l   a0,d2                ; merken für DOS-Write und Längenberechnung

      ; Beachte, daß 9 Register auf den Stack gerettet wurden.
      lea      4+4*9(SP),a3         ; Zeiger auf die Parameter
      bra.s    1$



      ; Setze Dezimalzahl ein.
2$    move.b   (a1)+,d0             ; hole Zeichen
      move.b   d0,d1
      bclr     #5,d1                ; wandele in Großbuchstaben
      cmp.b    #'D',d1              ; soll eine Dezimalzahl eingesetzt werden ?
      bne.s    4$                   ; nein
      move.l   (a3)+,d0             ; hole Parameter (Dezimalzahl)
      bsr      ErzeugeDezimalZahl   ; und schreibe Dezimalstring nach A0
      bra.s    1$                   ; hole das nächste Zeichen


      ; Setze einen String ein.
4$    cmp.b    #'S',d1              ; soll ein String eingesetzt werden ?
      bne.s    5$                   ; nein
      move.l   (a3)+,a2             ; hole Parameter (Stringzeiger)
6$    move.b   (a2)+,(a0)+          ; kopiere Zeichen
      bne.s    6$                   ; bis String zu Ende
      subq     #1,a0                ; zeigt jetzt direkt hinter String
      bra.s    1$


      ; Setze Hexzahl ein.
5$    cmp.b    #'X',d1
      bne.s    3$
      move.l   (a3)+,d0             ; hole Parameter
      moveq    #8-1,d1              ; ein Langwort hat 8 Nibbles
7$    rol.l    #4,d0
      move.b   d0,d3
      and.b    #%1111,d3
      cmp.b    #10,d3
      blt.s    8$
      addq     #('A'-'0'-10),d3
8$    add.b    #'0',d3
      move.b   d3,(a0)+             ; Nibble ausgeben
      dbra     d1,7$                ; bis alle Nibbles durch sind


      ; Hole ein Zeichen.
1$    move.b   (a1)+,d0             ; hole Zeichen
      cmp.b    #'%',d0              ; ist es '%' ?
      beq.s    2$                   ; ja, ersetze einen Parameter
      ; Speichere das Zeichen nur.
3$    move.b   d0,(a0)+             ; Zeichen speichern
      bne.s    1$                   ; bis String zu Ende ist


      ; Wir sind fertig mit Formatieren.
      subq     #1,a0                ; da A0 einen zu weit zeigt
      move.l   a0,d3
      sub.l    d2,d3                ; ergibt Stringlänge
      move.l   _stdout,d1           ; Filezeiger
      CALL     Write,_DOSBase       ; scher dich nicht darum, ob's klappt
      movem.l  (SP)+,Stringausgabe_REG
      rts










;******************************************************************************
; Die Tabellen.

AlertWert   dc.l  -1

DezimalTabelle
   dc.l  1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1










;******************************************************************************
; Hier kommen die Texte.

DOSName     DOSNAME


   IFND  DEUTSCH

TextBadArgs          STRINGLF <Bad args>
TextBufferOverflow   STRINGLF <Argument buffer overflow>
TextEquateUse        STRINGLF <Illegally used ''=''>
TextTooManyArgs      STRINGLF <Too many arguments>

TextErrorOpen        STRINGLF [DOS error %d opening file <%s>]
TextReadError        STRINGLF [DOS error %d reading file <%s>]
TextDifferentLength  STRINGLF [Files have different length]
TextFilesDiffer      STRINGLF [Files differ at byte $%x]

   ELSE

TextBadArgs          STRINGLF <Falsche Argumente>
TextBufferOverflow   STRINGLF <Argumentpuffer-Überlauf>
TextEquateUse        STRINGLF <Unzulässiges ''=''>
TextTooManyArgs      STRINGLF <Zu viele Argumente>

TextErrorOpen        STRINGLF [DOS-Fehler %d beim Öffnen von File <%s>]
TextReadError        STRINGLF [DOS-Lesefehler %d im File <%s>]
TextDifferentLength  STRINGLF [Files sind verschieden lang]
TextFilesDiffer      STRINGLF [Files sind verschieden am Byte $%x]

   ENDC










; Ende des Programmes

      END

