Obligement - L'Amiga au maximum

Mercredi 20 septembre 2017 - 07:48  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : Assembleur - une commande Touch
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - mars 1996)


Aujourd'hui, je vous propose, à travers un exemple concret, l'examen des puissantes fonctions de motifs de l'AmigaDOS 2.0 et supérieurs.

Présentation

Ceux d'entre vous qui connaissent Unix ne seront pas dépaysés, puisqu'il s'agit de la commande Touch, dont le rôle est de modifier la date de dernière altération d'un ou plusieurs fichiers et/ou répertoires. Il en existe plusieurs versions pour l'Amiga, mais le but n'était pas d'innover. J'ai visé, à l'écriture de ce programme, la symétrie parfaite avec des commandes dont vous avez l'habitude, comme Copy. Vous entrez donc une ligne de commandes avec différents arguments dont seul FILES est obligatoire (voir le code source pour les autres). Il s'agit d'une liste de motifs. Tous les fichiers correspondant à l'un de ces motifs seront pris en compte par la commande, grâce à l'utilisation des fonctions Match#? de la dos.library.

Les fonctions

Avant de pouvoir utiliser ces fonctions, dérivées des fonctions correspondantes de l'ARP, il faut initialiser une structure AnchorPath (définie dans dos/dosasl.i) :

    struct      AnchorPath {
        struct AChain   *ap_Base;
    #define             ap_First ap_Base
        struct AChain   *ap_Last;
    #define             ap_Current ap_Last
        LONG            ap_BreakBits;
        LONG            ap_FoundBreak;
        BYTE            ap_Flags;
        BYTE            ap_Reserved;
        WORD            ap_Strlen;
        struct          FileInfoBlock ap_Info;
        UBYTE           ap_Buf[1];
    };

Cette structure, comme son nom l'indique, sert surtout de point d'ancrage et réalise ainsi une sorte de chaînage pour les appels consécutifs à MatchFirst() et MatchNext(). Le champ le plus important est la structure FileInfoBlock qu'elle contient, donnant la description du fichier trouvé (grâce à Examine()). On peut également trouver un FileLock sur son répertoire dans le champ an_Lock de la structure AChain pointée par le champ ap_Current. Les champs ap_BreakBits et ap_FoundBreak permettent d'arrêter la recherche à la réception d'un signal Ctrl-C|D|E|F.

Après l'initialisation de cette structure, on la passe en paramètre, ainsi que le motif à confronter, à la fonction MatchFirst(), qui détermine le premier objet convenable. Sa description est placée dans ap_Info et une structure AChain est allouée. Les appels suivants se font avec MatchNext(), qui retourne à chaque fois les objets suivants de la même façon (plus besoin du motif). En retour, en D0, ces fonctions retournent un code d'erreur, ou 0 si tout s'est bien passé. S'il n'y a plus d'objets correspondants, ERROR_NO_MORE_ENTRIES est dans D0. Rien de bien sorcier. Lorsque vous avez terminé, vous devez appeler MatchEnd() pour libérer toute la mémoire nécessaire.

Les drapeaux

Examinons le champ ap_Flags de la structure AnchorPath : elle contient un masque de drapeaux.

APF_ITSWILD : signale que le motif en est bien un, qu'il contenait des jokers. Dans le cas contraire, si l'objet n'existe pas, c'est ERROR_OBJECT_NOT_FOUND qui est retourné à la place de NO_MORE_ENTRIES. Ce drapeau est initialisé par MatchFirst().

APF_DODIR : c'est à vous de mettre ce drapeau à 1 quand vous voulez que Match#? vous retourne tout le contenu du répertoire actuellement examiné (option ALL du programme).

APF_DIDDIR : lorsque le contenu d'un répertoire entré avec DODIR est épuisé, le répertoire est ramené avec ce drapeau, pour bien signaler qu'on en sort. Vous devez alors effacer ce drapeau. Les autres drapeaux sont sans grand intérêt pour nous et la place m'est comptée, je ne m'étendrai donc pas.

La modification

Le changement se fait par la fonction SetFileDate() du DOS, avec la structure DateStamp initialisée par DateStamp()... vous verrez tout cela dans les commentaires du programme. Comme "Touch ENV: All" vous le prouvera, cela est considéré comme une modification et déclenche des notifications (Amiga News n°72).

    include exec/exec.i
    include exec/exec_lib.i
    include dos/dos.i
    include dos/dos_lib.i
    include dos/dosasl.i
    include dos/dosextens.i

; le programme, pour pouvoir être résident, doit être ré-entrant.
; pour cela, il est nécessaire de ne pas stocker les variables dans
; la mémoire du programme, mais dans un bloc alloué en début de
; programme et dont l'adresse est conservé dans un registre.
; On pourrait aussi utiliser la pile, mais c'est du masochisme en
; assembleur.
    STRUCTURE   Mesvariables,0
     APTR   var_ExecBase    ; struct ExecBase *
     APTR   var_DOSBase ; struct DOSBase *
     LABEL  var_ArgArray
      APTR  var_Files_Arg   ; STRPTR *
      LONG  var_All_Arg ; booléen
      LONG  var_Quiet_Arg   ; booléen
      LONG  var_NoReq_Arg   ; booléen
     APTR   var_RDArgs  ; struct RDArgs *
     APTR   var_OldWindowPtr    ; struct Window *
     UWORD  var_PrintOffset
    LABEL   variables_SIZEOF

    move.l  4.w,a6
    moveq   #20,d7  ; code de retour: FAIL
    moveq   #variables_SIZEOF,d0
    move.l  #MEMF_CLEAR!MEMF_PUBLIC,d1
    jsr     _LVOAllocMem(a6)
    move.l  d0,a3   ; a3= pointeur sur les variables (dans
    move.l  a3,d0   ; tout le programme)
    beq Xit
    move.l  a6,var_ExecBase(a3)

    lea DOS.Name(pc),a1 ; ouverture du DOS
    moveq   #37,d0
    jsr     _LVOOpenLibrary(a6)
    move.l  d0,var_DOSBase(a3)
    beq.s   FreeVars

    move.l  d0,a6   ; lecture des arguments
    move.l  #Args.Template,d1
    lea     var_ArgArray(a3),a0
    move.l  a0,d2
    moveq   #0,d3
    jsr     _LVOReadArgs(a6)
    move.l  d0,var_RDArgs(a3)
    bne.s   ArgsOK
    bsr     PrintError
    bra.s   CloseDOS

; le champ pr_WindowPtr de la structure Process est un pointeur
; sur une structure Window, décrivant la fenêtre utilisée comme
; référence pour l'apparition de requêtes DOS du style "Veuillez
; insérer le volume...". Les valeurs spéciales sont 0 (écran public
; par défaut) et -1 (pas de requête du tout, annulation automatique).
; Si l'argument NOREQ a été donné, on y met -1 en sauvegardant
; l'ancienne valeur.
ArgsOK  move.l  var_ExecBase(a3),a6
        move.l  ThisTask(a6),a4
        move.l  pr_WindowPtr(a4),var_OldWindowPtr(a3)
        tst.l   var_NoReq_Arg(a3)
        beq.s   ReqOK
        move.l  #-1,pr_WindowPtr(a4)

ReqOK   move.l  var_Files_Arg(a3),a1
ArgLoop move.l  (a1)+,d0    ; argument FILES suivant
        beq.s   ArgEnd
        move.l  d0,a0
        moveq   #10,d7
        bsr.s   TouchFiles  ; toucher ces fichiers
        bne.s   ArgLoop

ArgEnd  move.l  var_OldWindowPtr(a3),pr_WindowPtr(a4)
        move.l  var_RDArgs(a3),d1   ; libération des arguments
        move.l  var_DOSBase(a3),a6
        jsr     _LVOFreeArgs(a6)
CloseDOS
        move.l  var_DOSBase(a3),a1  ; fermeture du DOS
        move.l  var_ExecBase(a3),a6
        jsr     _LVOCloseLibrary(a6)
FreeVars
        move.l  a3,a1   ; libération des variables
        moveq   #variables_SIZEOF,d0
        jsr     _LVOFreeMem(a6)
Xit     move.l  d7,d0
        rts

; La routine suivante prend en paramètre un pointeur sur un
; motif (l'un de ceux donnés sur la ligne de commande) et touche
; tous les fichiers qui le concernent.
TouchFiles  ; (Z=0)Success=TouchFiles(Pattern)(A0)
    movem.l d0-d2/a0-a1/a4-a6,-(sp)
    moveq   #0,d2   ; code de retour
    move.l  a0,a4
    move.l  #ap_SIZEOF+ds_SIZEOF,d0 ; allocation de AnchorPath
    move.l  #MEMF_PUBLIC!MEMF_CLEAR,d1  ; +DateStamp
    move.l  var_ExecBase(a3),a6
    jsr     _LVOAllocMem(a6)
    move.l  d0,a5
    move.l  a5,d0
    beq.s   .Fail
    move.l  var_DOSBase(a3),a6
    move.l  a4,d1
    move.l  a5,d2
    jsr     _LVOMatchFirst(a6)  ; premier
    cmp.l   #ERROR_NO_MORE_ENTRIES,d0   ; fini?
    beq.s   .End
    tst.l   d0
    bne.s   .ScanError
    move.l  a5,a0
    bsr.s   TouchFile   ; toucher cet objet
    beq.s   .TouchError
.TouchLoop
    move.l  a5,d1
    jsr     _LVOMatchNext(a6)   ; suivant
    cmp.l   #ERROR_NO_MORE_ENTRIES,d0   ; fini?
    beq.s   .End
    tst.l   d0
    bne.s   .ScanError
    move.l  a5,a0
    bsr.s   TouchFile   ; toucher celui-ci
    bne.s   .TouchLoop
    bra.s   .TouchError
.ScanError
    bsr     PrintFault  ; afficher l'erreur
    jsr     _LVOSetIoErr(a6)    ; régler le résultat secondaire
.TouchError
.Ret    move.l  a5,d1
        jsr     _LVOMatchEnd(a6)    ; fin
        move.l  a5,a1
        move.l  var_ExecBase(a3),a6
        move.l  #ap_SIZEOF+ds_SIZEOF,d0 ; libération d'AnchorPath
        jsr     _LVOFreeMem(a6)     ; et DateStamp
.Fail   move.l  d2,d0
        movem.l (sp)+,d0-d2/a0-a1/a4-a6
        rts
.End    moveq   #-1,d2  ; pour Z
        moveq   #0,d7
        moveq   #0,d1
        jsr     _LVOSetIoErr(a6)
        bra.s   .Ret

; La routine suivante se charge de modifier la date d'altération de
; l'objet (fichier ou répertoire) représenté dans la structure AnchorPath
; passée en paramètre. Toutes les informations qui le concernent se
; trouve dans la structure FileInfoBlock qu'elle contient. On peut
; également trouver un FileLock de son répertoire dans la dernière
; structure AChain, utilisé ici pour un CurrentDir().
TouchFile   ; (Z=0)Success=TouchFile(AnchorPath)(A0)
    movem.l d0-d3/a0-a2/a6,-(sp)
    move.l  a0,a2
    move.l  ap_Current(a2),a0
    move.l  an_Lock(a0),d1
    move.l  var_DOSBase(a3),a6
    jsr     _LVOCurrentDir(a6)
    move.l  d0,d3
    lea     ap_SIZEOF(a2),a0
    move.l  a0,d1   ; on a une structute DateStamp ici
    jsr     _LVODateStamp(a6)   ; quelle heure est-il?
    move.l  d0,d2

    btst    #APB_DIDDIR,ap_Flags(a2)    ; on sort d'un
    beq.s   .Touch          ; répertoire?
    subq.w  #1,var_PrintOffset(a3)  ; alors 1 décalage en
    bra.s   .DirDone        ; moins

.Touch  move.w  var_PrintOffset(a3),d0  ; affiche autant d'espace qu'indiqué
    lea Spaces.Msg(pc),a0   ; dans ce compteur (incrémenté chaque
.SpaceLoop              ; fois qu'on entre dans un
    bsr.s   Print           ; répertoire
    dbra    d0,.SpaceLoop

    lea     ap_Info+fib_FileName(a2),a0 ; affiche le nom
    bsr.s   Print
    lea     Dots.Msg(pc),a0 ; des points de suspension
    bsr.s   Print
    bsr     Flush

    tst.l   ap_Info+fib_DirEntryType(a2)    ; fichier ou rép?
    bmi.s   .File
    tst.l   var_All_Arg(a3) ; entrer dans ce répertoire (argument ALL)?
    beq.s   .File
    bset    #APB_DODIR,ap_Flags(a2) ; le signaler.
    addq.w  #1,var_PrintOffset(a3)  ; décaler d'1 cran vers la droite

.Filelea    ap_Info+fib_FileName(a2),a0
            move.l  a0,d1   ; le nom de l'objet à toucher
            jsr     _LVOSetFileDate(a6) ; la DateStamp est dans D2
.DirDone
            move.l  d3,d1
            move.l  d0,d3   ; conserve le code d'erreur
            jsr     _LVOCurrentDir(a6)  ; ancien répertoire
            tst.l   d3
            bne.s   .OK
            bsr.s   PrintError
            bra.s   .Ret
.OK         btst    #APB_DIDDIR,ap_Flags(a2)    ; ne pas répéter "touched"
            bne.s   .Ret                ; dans si on sort d'un rep
            lea     Touched.Msg(pc),a0
            bsr.s   Print
.Ret        bclr    #APB_DIDDIR,ap_Flags(a2)    ; on efface ce drapeau
            tst.l   d3  ; règle Z
            movem.l (sp)+,d0-d3/a0-a2/a6
            rts

; Cette routine affiche le message pointé par A0 si l'argument
; QUIET n'a pas été donné. L'avantage de QUIET sur >NIL: est que
; les messages d'erreur seront quand même affichés (autre routine)
Print           ; Print(Str)(A0)
        movem.l d0-d1/a0-a1/a6,-(sp)
        tst.l   var_Quiet_Arg(a3)
        bne.s   .Quiet
        move.l  a0,d1
        move.l  var_DOSBase(a3),a6
        jsr     _LVOPutStr(a6)
.Quiet  movem.l (sp)+,d0-d1/a0-a1/a6
        rts

; Affiche le contenu de IoErr()
PrintError      ; PrintError()
        movem.l d0-d1/a0-a1/a6,-(sp)
        move.l  var_DOSBase(a3),a6
        jsr     _LVOIoErr(a6)
        bsr.s   PrintFault
        move.l  d0,d1
        jsr     _LVOSetIoErr(a6)
        movem.l (sp)+,d0-d1/a0-a1/a6
        rts

; affiche le message d'erreur correspondant au code
PrintFault      ; PrintFault(Code)(D0)
        movem.l d0-d2/a0-a1/a6,-(sp)
        move.l  d0,d1
        moveq   #0,d2
        move.l  var_DOSBase(a3),a6
        jsr     _LVOPrintFault(a6)
        movem.l (sp)+,d0-d2/a0-a1/a6
        rts

; Cette routine est nécessaire si on veut que le DOS affiche les
; messages sans attendre un LineFeed lorsqu'on utilise les routines
; tamponnées (comme PutStr).
Flush           ; Flush(): force l'écriture sur la console
        movem.l d0-d1/a0-a1/a6,-(sp)
        move.l  var_DOSBase(a3),a6
        jsr     _LVOOutput(a6)
        move.l  d0,d1
        jsr     _LVOFlush(a6)
        movem.l (sp)+,d0-d1/a0-a1/a6
        rts

DOS.Name        dc.b    'dos.library',0
Args.Template   dc.b    'FILES/M/A,ALL/S,QUIET/S,NOREQ/S',0
Spaces.Msg      dc.b    '   ',0
Dots.Msg        dc.b    '..',0
Touched.Msg     dc.b    'touched.',10,0


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]