;
;    programme de conversion Ascii Mac <--> Amiga
;
;    conçu et réalisé par Jean-Pierre Rivière en février 1991
;

ExecBase        = $4
OpenLibrary     = -$228
CloseLibrary    = -$19e
AllocMem        = -$c6
FreeMem         = -$d2
MemfPublic      = $1
ModeOldFile     = $3ed  ; ModeNewFile = ModeOldFile ^ 3
Open            = -$1e
Close           = -$24
Read            = -$2a
Write           = -$30

DefTaille       = 7808  ; = 16 * 488 : taille du tampon d'E/S par défaut

LgrUsageMess    = 264   ; ne changez pas la longueur des messages!!
LgrOuvrirMess   = 26
LgrEcrireMess   = 42
LgrLireMess     = 42
LgrMemMess      = 40

EUH             = $c9   ; caractère Amiga sans équivalent Macintosh

;###############################################################################

; --- d'abord les initialisations d'usage ---

init:
    move.l  d0,d5               ; sauvegarde de d0
    movea.l a0,a3               ; sauvegarde de a0
    move.l  ExecBase,a6
    lea.l   DosName,a1
    move.l  #0,d0               ; version indifferente
    jsr     OpenLibrary(a6)
    move.l  d0,DosBase
    beq     fermerTout

; --- maintenant on va explorer la ligne de commande ---

; === utilisation des registres ===
; d3.b : nombre de caractère du mot actuel de la ligne de commande
; d4.b : nombre d'arguments passés hors option(s)
; d6.l : mode d'ouverture du prochain fichier
; a0.l : poisition actuelle dans la ligne de commande
; a1.l : dernier caractère de la ligne de commande
; a2.l : premier caractère utile de la ligne de commande
; a3.l : premier caractère unitile après le caractère repéré par a2.l
; a5.l : pointe sur le premier pointeur de fichier
; a6.l : base pour appels aux fonctions des bibliothèque

; === utilisation de la mémoire ===
; Source    : pointeur de fichier source - suivi immédiatement par Cible
; Cible     : pointeur de fichier cible
; optionMem : octet indiquant si l'unique option a déjà été activée

    moveq.b #0,d4       ; nombre d'arguments
    movea.l a3,a1       ; restauration de l'adresse de la ligne de commande
    add.l   d5,a1       ; on ajoute le nombre de caractères
    subq.l  #1,a1       ; pointe sur la fin de la ligne de commande
    lea.l   Source,a5   ; debut des pointeurs de fichiers
    move.l  #ModeOldFile,d6

encore:
    move.l  a3,a0       ; c'est ici qu'est la ruse :
                        ; cela permet de reboucler directement ici au cas où
                        ; on aboutit à un mot vide (et assure aussi la
                        ; progression quand il n'y a pas d'erreur).
    jsr     traiter     ; examen de la ligne de commande
    cmpa.l  #0,a3       ; a3 nul indique une erreur
    beq.s   suite
    cmpi.b  #1,d3       ; mot vide ?
    beq.s   encore      ; fausse alerte (mot = "", ce qui est ignoré)
    move.b  #0,(a3)+    ; on finit le mot selon la convention du C.
                        ; c'est nécessaire pour l'ouverture d'un fichier.
                        ; La postincrémentation est là pour permettre
                        ; l'astuce en cas de mot vide (aller au delà du
                        ; second guillemet est obligatoire).
    cmpi.b  #$2d,(a2)+  ; un tiret ?
    beq     option
    cmpi.b  #2,d4       ; a-t-on déjà eu deux arguments ?
    beq     modedEmploi ; si oui message d'explication affiché et terminé
    addq.b  #1,d4       ; et un argument de plus
    move.l  DosBase,a6
    subq.l  #1,a2
    move.l  a2,d1
    move.l  a1,a2       ; sauvegarde a1 dans a2
    move.l  d6,d2
    jsr     Open(a6)
    move.l  d0,(a5)+    ; sauvegarde du pointeur de fichier à sa place
    beq     uneErreur   ; fichier refusant de s'ouvrir !
    eori.b  #$3,d6      ; ModeOldFile <##> ModeNewFile (addq.l en toute rigueur)
    move.l  a2,a1       ; restaure a1
    move.b  #32,-(a3)   ; ici nécessaire pour reprendre l'algo
                        ; la prédécrémentation est là suite à la ruse
    move.b  #10,(a1)    ; et cela pour le cas extrême l'est aussi par suite
    bra     encore

; --- la ligne de commande est finie d'être explorée  ---
; --- peut-on travailler ou y a-t-il eu un problème ? ---

suite:
    cmpi.b  #2,d4       ; les 2 fichiers sont-ils ouverts ?
    bne     uneErreur   ; non : il y a eu une erreur.
    movea.l ExecBase,a6
    move.l  Taille,d0
    moveq.l #MemfPublic,d1
    jsr     AllocMem(a6)
    tst.l   d0
    beq     erreurMem
    move.l  d0,Tampon
    move.l  -(a5),a3    ; fichier cible
    move.l  -(a5),a2    ; fichier source
    move.l  d0,(Tampon)
    tst.b   optionMem
    bne.s   suite2
    jsr     MacToAmiga  ; conversion de Mac vers Amiga (blessing)

; --- C'est fini, on ferme ! ---

fermerTout:
    lea.l   Source,a5
    tst.l   (a5)
    beq.s   fermerTout2
    move.l  (a5)+,d1
    move.l  DosBase,a6  ; on ferme le fichier source (ouvert en premier)
    jsr     Close(a6)
    tst.l   (a5)
    beq.s   fermerTout2
    move.l  (a5),d1     ; on ferme le fichier destination
    jsr     Close(a6)
fermerTout2:
    movea.l ExecBase,a6
    move.l  Tampon,a1
    cmpa.l  #0,a1
    beq.s   fermerTout3
    move.l  Taille,d0   ; on libère la mémoire
    jsr     FreeMem(a6)
fermerTout3:
    movea.l DosBase,a1
    jsr     CloseLibrary(a6)

    rts                 ; programme terminé !

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; --- conversion avec option -i ---

suite2:                 ; option -i active
    jsr     AmigaToMac  ; conversion Amiga vers Mac (doom, bane & cursing)
    bra.s   fermerTout

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; --- première option ---

option:
    ori.b   #32,(a2)    ; majuscule ##> minuscule
    cmpi.b  #$62,(a2)+  ; est-ce un b ?
    bne.s   option2
    move.b  (a2)+,d0
    cmpi.b  #$39,d0     ; ensuite, est-ce un chiffre ?
    bgt     modedEmploi
    subi.b  #$30,d0     ; si oui, on le transforme en chiffre binaire
    blt     modedEmploi
    tst.b  (a2)         ; encore un signe ?
    bne     modedEmploi
    move.l  #488,d1
    lsl.l   d0,d1       ; on décale à gauche d'autant que le chiffre l'indique
    move.l  d1,Taille
    move.b  #32,-(a3)   ; pour bien repartir sur la ligne (de commande)
    move.b  #10,(a1)    ; et sans oublier ça
    bra     encore

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; --- seconde option ---

option2:
    cmpi.b  #$69,-1(a2) ; est-ce un i ?
    bne.s   modedEmploi ; option inconnu
    st      optionMem   ; on peut répéter l'option plusieurs fois...
    tst.b   (a2)        ; encore un signe ?
    bne     modedEmploi
    move.b  #32,-(a3)   ; pour bien repartir sur la ligne (de commande)
    move.b  #10,(a1)    ; et sans oublier ça
    bra     encore

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; --- pas d'allocation mémoire possible ---

erreurMem:
    jsr     OuvrirStd
    beq     fermerTout
    move.l  #MemMess,d2
    move.l  #LgrMemMess,d3
    jsr     Write(a6)
    bra     fermerTout

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; --- quelle erreur ? ---

uneErreur:
    jsr     OuvrirStd
    beq     fermerTout
    cmpa.l  #0,a3       ; une erreur de syntaxe avant tout ?
    beq.s   modedEmploi
    move.l  a3,d2
    sub.l   d3,d2
    move.l  d1,d4       ; sauvvegarde d1 = entrée standard
    jsr     Write(a6)   ; longueur déjà en d3
    move.l  d4,d1
    move.l  #ouvrirMess,d2
    move.l  #LgrOuvrirMess,d3
    jsr     Write(a6)
    bra     fermerTout

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; --- - Comment ça marche, ce truc ? - T'as qu'à lire ! ---

modedEmploi:
    jsr     OuvrirStd
    beq     fermerTout
    move.l  #usageMess,d2
    move.l  #LgrUsageMess,d3
    jsr     Write(a6)
    bra     fermerTout

;################################################################

; *** ouvrir le canal du Shell d'appel ***

; === sortie ===
; d0.l : contient le canal du Shell (ou 0)
; d1.l : égal à d0.l
; ccr  : Z est à 1 ssi une erreur est survenue
; a0.l et a1.l sont modifiés
; a6.l : DosBase

OuvrirStd:
    movea.l DosBase,a6
    move.l  #Shell,d1
    move.l  #ModeOldFile,d2
    jsr     Open(a6)
    move.l  d0,d1       ; teste si erreur en même temps
    rts

;################################################################

; *** erreur en lecture ***

LireErreur:
    jsr     OuvrirStd
    beq     fermerTout  ; Qu'avez-vous fait du Shell ?
    move.l  #LireMess,d2
    move.l  #LgrLireMess,d3
    jsr     Write(a6)
    rts

;################################################################

; *** erreur en écriture ***

EcrireErreur:
    jsr     OuvrirStd
    beq     fermerTout  ; Qu'avez-vous fait du Shell ?
    move.l  #ecrireMess,d2
    move.l  #LgrEcrireMess,d3
    jsr     Write(a6)
    rts

;################################################################

; *** trouve le premier mot (sa partie "efficace") et le mesure ***
; ***    version adaptée spécialement à la ligne de commande    ***

; === entrée ===
; a0.l  : pointe sur le premier caractère
; a1.l  : pointe sur le dernier caractère

; === sortie ===
; a0 et a1  : inchangés
; a2.l  : pointe sur le premier caractère "efficace" du premier mot
; a3.l  : pointe juste après le dernier caractère "efficace" du premier mot
;         a3.l est nul s'il y a une erreur de repérée
; d3.b  : longueur "efficace" du premier mot, plus un

; on exploite le fait que le dernier caractère est toujours LF, de code 10
; et donc en particulier on n'a pas particulièreement à le sauver.
; il s'en suit que pour explorer autre chose qu'une ligne de commande,
; il faut encore adapter ce bout de code.

traiter:
    movea.l a0,a2
                        ; ici la sentinelle vaut LF
sauter:
    cmp.b   #32,(a2)+
    beq.s   sauter
    cmp.b   #10,-(a2)   ; dernier caractère (en fait) ?
    beq.s   erreurTrait
    movea.l a2,a3
    cmp.b   #$22,(a2)   ; un guillemet (") ?
    beq.s   guillemets
    move.b  #32,(a1)    ; sentinelle = espace
compter:
    cmp.b   #32,(a3)+   ; sentinelle = espace
    bne.s   compter
                        ; remarque: le dernier caractère d'une ligne
                        ; de commande est LF (code 10). Donc on a
                        ; plus de test à faire sur a3 avant de placer
                        ; la sentinelle dessus.
finTraiter:
    move.b  #10,(a1)
    move.l  a3,d3
    sub.l   a2,d3
    cmp.b   #1,d3
    beq     finDeLigne
    sub.l   #1,a3       ; il faut revenir un caractère en arrière
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

finDeLigne:
    movea.l #0,a3       ; erreur : il n'y a plus de mots sur la ligne
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

guillemets:
    move.b  #$22,(a1)   ; sentinelle = guillemet
    addq.l  #1,a3
compter2:
    cmp.b   #$22,(a3)+
    bne.s   compter2
    move.b  #10,(a1)
    cmp.b   #$22,-(a3)  ; si pas un guillemet alors erreur
    bne.s   erreurTrait
    move.l  a3,d3
    sub.l   a2,d3
    addq.l  #1,a2
    cmpi.b  #1,d3       ; rien entre les guillemets ?
    beq     special
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

special:                ; il n'y a rien entre les guillemets
    addq.l  #1,a3       ; dans ce cas il faut incrémenter a3
                        ; de façon à ne pas retomber sur le second
                        ; guillemet lors du prochain appel
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

erreurTrait:
    movea.l #0,a3       ; signale une erreur (EOL ou guillemet manquant)
    rts

; ##########################################################################

; *** convertit le fichier source Macintosh en fichier Amiga ***

; === entrée ===
; a2.l : pointeur du fichier source
; a3.l : pointeur du fichier cible

; === sortie ===
; a2.l et a3.l pointent à la fin de leur fichier.
; a4.l : inchangé
; a6.l : DosBase
; d0,d1,d2,d3,d4,a0,a1,a4,a5 sont modifiés
; le fichier cible est entièrement constitué.

MacToAmiga:
    lea.l   Mac2Amiga,a4; tableau utilisé pour la conversion
    move.l  Taille,d3
    movea.l Tampon,a5
    movea.l DosBase,a6

AccesDisqueMtoA:
    move.l  a2,d1
    move.l  a5,d2
    jsr     Read(a6)
    tst.l   d0
    ble.s   MtoA_erreur1  ; erreur (EOF ou autre)
    move.l  d0,d2   ; nombre d'octets lus et donc à traduire
    move.w  d0,d4
    subq.w  #1,d2
    moveq.b #0,d0   ; sinon bug pour conversion ascii étendu

MtoA:
    move.b  (a5)+,d0
    cmpi.b  #127,d0     ; code ascii étendu ( > 127 ) ?
    bvs.s   MtoA_Ext
    cmpi.b  #13,d0      ; code = CR ?
    beq.s   MtoA_CR
MtoA_fin:
    dbf.s   d2,MtoA     ; a-t-on tout traduit ?
    move.l  a3,d1
    movea.l Tampon,a5
    move.l  a5,d2
    move.l  d4,d3       ; nombre d'octets à recopier (et evt à relire)
    jsr     Write(a6)
    tst.l   d0          ; erreur d'écriture ?
    blt.s   MtoA_erreur2
    cmp.l   Taille,d4
    beq.s   AccesDisqueMtoA
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MtoA_erreur1:
    jsr     LireErreur
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MtoA_erreur2:
    jsr     EcrireErreur
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MtoA_Ext:
    and.b   #$7F,d0         ; --> indice du tableau Mac2Amiga correspondant
    move.b  0(a4,d0),-1(a5); conversion en le caractère Mac équivalent
    bra.s   MtoA_fin
MtoA_CR:
    move.b  #10,-1(a5)  ; code devenu LF
    bra.s   MtoA_fin

; ################################################################

; *** convertit le fichier source Amiga en fichier Macintosh ***

; === entrée ===
; a2.l  : pointeur du fichier source
; a3.l  : pointeur du fichier cible

; === sortie ===
; a2.l et a3.l pointent à la fin de leur fichier.
; a4.l : inchangé
; a6.l : DosBase
; d0,d1,d2,d3,d4,a1,a4,a5 sont modifiés
; le fichier cible est entièrement constitué.

AmigaToMac:
    lea.l   Amiga2Mac,a4; tableau utilisé pour la conversion
    move.l  Taille,d3
    movea.l Tampon,a5
    movea.l DosBase,a6

AccesDisqueAtoM:
    move.l  a2,d1
    move.l  a5,d2
    jsr     Read(a6)
    tst.l   d0
    ble.s   AtoM_erreur1  ; erreur (EOF)
    move.l  d0,d2   ; nombre d'octets lus et donc à traduire
    move.w  d0,d4
    subq.w  #1,d2
    moveq.b #0,d0   ; sinon bug pour conversion ascii étendu

AtoM:
    move.b  (a5)+,d0
    cmp.b   #127,d0     ; code ascii étendu ( > 127 ) ?
    bvs.s   AtoM_Ext
    cmp.b   #10,d0      ; code = LF ?
    beq.s   AtoM_CR
AtoM_fin:
    dbf.s   d2,AtoM     ; a-t-on tout traduit ?
    move.l  a3,d1
    movea.l Tampon,a5
    move.l  a5,d2
    move.l  d4,d3       ; nombre d'octets à recopier (et evt à relire)
    jsr     Write(a6)
    tst.l   d0          ; erreur d'écritue ?
    blt.s   AtoM_erreur2
    cmp.l   Taille,d4
    beq.s   AccesDisqueAtoM
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

AtoM_erreur1:
    jsr     LireErreur
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

AtoM_erreur2:
    jsr     EcrireErreur
    rts

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

AtoM_Ext:
    and.b   #$7F,d0         ; --> indice du tableau Amiga2Mac correspondant
    move.b  0(a4,d0),-1(a5); conversion en le caractère Amiga équivalent
    bra.s   AtoM_fin
AtoM_CR:
    move.b  #13,-1(a5)  ; code devenu CR
    bra.s   AtoM_fin

; *********************************************************************

; === variables & constantes ===

DosBase:    dc.l    0   ; pointeur sur DosBase
Source:     dc.l    0   ; pointeur de fichier source
Cible:      dc.l    0   ; pointeur de fichier cible
Tampon:     dc.l    0   ; pointeur sur le tampon de mémoire dynamique
Taille:     dc.l    DefTaille   ; taille du tampon d'E/S

optionMem   dc.b    0   ; drapeau sur l'option

DosName:    dc.b    "dos.library",0

Shell:      dc.b    "*",0

usageMess:  dc.b    "USAGE : m2a [-i] [-b#] source cible",10
            dc.b    "m2a traduit un fichier ascii Macintosh en un fichier ascii Amiga.",10
            dc.b    "Utilisez l'option -i pour faire le travail inverse.",10
            dc.b    "La taille du buffer en octets est de 488*2^# avec l'option -b#",10
            dc.b    "Sa taille par défaut est de 7808 octets. (-b4)",10,0

ouvrirMess: dc.b    " : ouverture impossible.",10,0

ecrireMess: dc.b    "erreur en écriture sur le fichier cible.",10,0

LireMess:   dc.b    "erreur en lecture sur le fichier source.",10,0

MemMess:    dc.b    "impossible d'allouer assez de mémoire.",10,0

Mac2Amiga:
        dc.b    'Ä','Â',
        dc.b    'Ç',
        dc.b    'É',
        dc.b    'Ñ',
        dc.b    'Ö',
        dc.b    'Ü',
        dc.b    'á','à','â','ä','ã','å',
        dc.b    'ç',
        dc.b    'é','è','ê','ë',
        dc.b    'í','ì','î','ï',
        dc.b    'ñ',
        dc.b    'ó','ò','ô','ö','õ',
        dc.b    'ú','ù','û','ü',
        dc.b    $80,'°','¢','£','§','·','¶','ß',
        dc.b    '®','©',$81,'´','¨',$82,'Æ','Ø',
        dc.b    $83,'±',$84,$85,'¥','µ','ð',$86,
        dc.b    $87,$88,$89,'ª','º',$8a,'æ','ø',
        dc.b    '¿','¡','¬',$8b,$8c,$8d,$8e,'«',
        dc.b    '»',$8f,$a0,'À','Ã','Õ',$90,$91,
        dc.b    '­','¯','"','"','`',$2c,'÷',$92,
        dc.b    'ÿ',$93,'/','¤',$94,$95,$96,$97,
        dc.b    $98,'.','¸',$99,$9a,'Â','Ê','Á',
        dc.b    'Ë','È','Í','Î','Ï','Ì','Ó','Ô',
        dc.b    $9b,'Ò','Ú','Û','Ù',$9c,'^','~',
        dc.b    '­',$9d,'·','°',$9e,'"','.',$9f

Amiga2Mac:
        dc.b    $a0,$aa,$ad,$b0,$b2,$b3,$b7,$b8,
        dc.b    $b9,$ba,$bd,$c3,$c4,$c5,$c6,$c9,
        dc.b    $ce,$cf,$d7,$d9,$dc,$dd,$de,$df,
        dc.b    $e0,$e3,$e4,$f0,$f5,$f9,$fc,$ff,

        dc.b    $ca,$c1,$a2,$a3,$db,$b4,EUH,$a4,
        dc.b    $ac,$a9,$bb,$c7,$c2,$d0,$a8,$d1,
        dc.b    $a1,$b1,EUH,EUH,$ab,$b5,$a6,$a5,
        dc.b    $e2,EUH,$bc,$c8,EUH,EUH,EUH,$c0,
        dc.b    $cb,$e7,$e5,$cc,$80,$81,$ae,
        dc.b    $82,
        dc.b    $e9,$83,$e6,$e8,
        dc.b    $ed,$ea,$eb,$ec,
        dc.b    EUH,$84,
        dc.b    $f1,$ee,$ef,$cd,$85,
        dc.b    EUH,$a0,
        dc.b    $f4,$f2,$f3,$86,
        dc.b    EUH,
        dc.b    EUH,$a7,
        dc.b    $88,$87,$89,$8b,$8a,$8c,$be,
        dc.b    $8d,
        dc.b    $8f,$8e,$90,$91,
        dc.b    $93,$92,$94,$95,
        dc.b    $b6,$96,
        dc.b    $98,$97,$99,$9b,$9a,
        dc.b    $d6,$bf,
        dc.b    $9d,$9c,$9e,$9f,
        dc.b    EUH,EUH,$d8

        end
