Obligement - L'Amiga au maximum

Dimanche 24 septembre 2017 - 12:35  

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 - XPK et ARexx : concepts et préliminaires
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - novembre 1996)


Ce mois-ci et les suivants, nous nous lançons dans un grand projet d'interfaçage entre l'ensemble de compression de données bien connu, XPK, et le langage de programmation natif de l'Amiga, ARexx. Cela va nous mener à l'écriture de la bibliothèque rexxxpk.library.

Les hôtes ARexx

On ne présente plus ce langage et cet article suppose que vous soyez un peu familier avec la philosophie, sinon le langage, ARexx. Nous nous attacherons donc à comprendre comment ARexx communique avec ses hôtes et, plus précisément, son comportement avec les bibliothèques de fonctions (si le cas des autres hôtes et des commandes vous intéresse, faites-le moi savoir).

Lorsque l'interpréteur d'ARexx rencontre dans un script un nom de fonction qu'il ne comprend pas, il cherche dans sa liste de bibliothèques. Celle-ci regroupe une liste d'hôtes de fonctions déclarés en tant que programmes séparés ou en tant que bibliothèques. L'ordre de recherche est déterminé par les priorités relatives des différents hôtes, de 100 à -100. Le processus principal REXX est lui-même un hôte de fonctions de priorité -60. On trouve beaucoup, dans le domaine public, de bibliothèques de fonctions pour ARexx comme rexxarplib.library ou rexxreqtools.library.

Comme je l'ai dit plus haut, je me limiterai ici au cas des bibliothèques de fonctions. Une bibliothèque doit d'abord être ajoutée à la liste maintenue par ARexx avant de pouvoir être utilisée. Ceci peut se faire par le programme "RXLIB", la commande "SHOWLIB" au sein d'un programme ARexx, ou l'envoi d'un message de type "RXADDLIB" à "REXX". La seconde méthode est la plus pratique, mais les trois sont possibles.

Les caractéristiques d'une bibliothèque de fonctions sont les suivantes : un nom de bibliothèque (tel qu'on en a l'habitude, se terminant par ".library"), un numéro de version, une priorité (définie au moment de l'ajout à la liste des hôtes) et une fonction d'interrogation. Cette fonction d'interrogation est destinée à être appelée par la tâche de l'interpréteur quand il doit résoudre un nom de fonction. Elle est d'abord appelée pour demander à la bibliothèque si elle connaît le nom de fonction incriminé. Dans l'affirmative, elle doit alors exécuter la routine demandée, en tenant compte des informations de contexte fournies par ARexx.

Structure d'une bibliothèque ARexx

La bibliothèque écrite doit respecter la même structure qu'une bibliothèque Exec normale et résider au sein d'un fichier du répertoire Libs:. Cela a déjà été décrit dans un article d'Amiga News il y a quelque temps mais je vais résumer pour les absents.

Après deux lignes de code pour empêcher l'exécution depuis un CLI, on doit trouver, une structure Resident (Cf. exec/resident.i) correctement initialisée, destinée à indiquer au module ramlib qu'il a bien chargé une bibliothèque valide. En supposant le flag RTF_AUTOINIT à 1 dans rt_Flags, on devra placer dans rt_Init un pointeur sur une table de quatre mots longs.

Le premier contient la taille de la zone mémoire à réserver pour la structure de base de la bibliothèque, le second, un pointeur sur une table de pointeurs de fonctions terminée par -1. Le troisième est un pointeur sur une table utilisée par la fonction InitStruct() d'exec.library pour initialiser la structure et le dernier pointe sur une routine à exécuter afin de terminer l'initialisation.

Les trois premières fonctions sont réservées respectivement à l'ouverture, la fermeture et la purge de la bibliothèque. La quatrième est réservée à une extension future et doit se contenter de mettre D0 à 0. Il ne nous reste donc que la fonction d'interrogation ARexx à détailler. Je dois pour cela commencer un petit aparté sur les différentes structures utilisées.

Les structures RexxMsg et RexxArg

Commençons par la structure RexxArg. Il s'agit d'un compromis entre la facilité, pour les chaînes de caractères à la mode BCPL, de connaître leur longueur, et la facilité de manipuler les chaînes C, allié à des facilités d'allocation et de conversion.

struct RexxArg {
    LONG    ra_Size;
    UWORD   ra_Length;
    UBYTE   ra_Flags;
    UBYTE   ra_Hash;
    BYTE    ra_Buff[8];
};

Le champ ra_Size désigne la taille de la zone mémoire allouée pour cette chaîne de caractères, il sert surtout à la copie et la destruction de la chaîne. Le champ ra_Length contient sa longueur, le champ ra_Flags contient différents attributs indiquant par exemple si la chaîne de caractères représente un nombre ou si elle fait partie du code source d'un programme. Je ne m'y attarderai pas plus longtemps, pas plus que sur ra_Hash. Le champ ra_Buff, enfin, contient la chaîne de caractères elle-même, toujours terminée par un octet nul.

Il se trouve qu'il est toujours plus commode de traiter les chaînes de caractères avec un pointeur sur des caractères plutôt que sur une structure. C'est pourquoi on fait toujours référence aux structures RexxArg en tant que "ArgStrings". Il s'agit d'un pointeur sur le champ ra_Buf d'une structure RexxArg, de sorte que les autres champs de la structure soient accessibles aux offsets négatifs à partir de l'ArgString. Nous en savons maintenant assez pour passer à l'autre structure importante, la structure RexxMsg, tout en notant que la rexxsyslib.library contient moult fonctions rendant enfantine la gestion des ArgStrings. Il en est de même de la structure RexxMsg :

struct RexxMsg {
    struct Message  rm_Node;
    APTR            rm_TaskBlock;
    APTR            rm_LibBase;
    LONG            rm_Action;
    LONG            rm_Result1;
    LONG            rm_Result2;
    STRPTR          rm_Args[16];
    struct MsgPort  *rm_PassPort;
    STRPTR          rm_CommAddr;
    STRPTR          rm_FileExt;
    LONG            rm_Stdin;
    LONG            rm_Stdout;
    LONG            rm_avail;
};

Même s'il commence par une structure Message, ce RexxMsg n'est pas toujours utilisé comme tel, et c'est le cas qui nous intéresse pour les bibliothèques de fonctions (ne jamais utiliser GetMsg() ou Remove() dans ce cas : le message n'est attaché à aucune liste). Les arguments rm_Args sont la seule chose qui nous importe réellement dans ce message, les autres servant surtout quand ARexx communique avec des applications hôtes en mode commande ou fonction, et lorsque des applications lancent des programmes ARexx.

Sur ce, je vous laisse avec le début du code de la bibliothèque, concernant la gestion de sa "partie Exec". Le mois prochain, nous attaquerons tout ce qui concerne la fonction d'interrogation.

    opt AMIGA
    opt NOSYMTAB,NODEBUG
    OUTPUT  LIBS:rexxxpk.library

REVISION    MACRO
    dc.b "1.00"
    ENDM
REVDATE MACRO
    dc.b "01.10.96"
    ENDM
VERNUM  EQU  01
REVNUM  EQU  00

    include HISOFT_DEVPAC:Macro/Header.i    ; nécessite
    include HISOFT_DEVPAC:Macro/defines.i   ; HiSoft Devpac 3.50
    include HISOFT_DEVPAC:Macro/exec.i
    IMPORT  exec,initializers
    IMPORT  exec,resident
    IMPORT  exec,alerts
    IMPORT  exec,execbase
    IMPORT  exec,exec_lib
    IMPORT  rexx,storage
    IMPORT  rexx,rxslib
    IMPORT  utility,utility
    IMPORT  utility,utility_lib

; déclaration de la structure de base de la bibliothèque
    STRUCTURE   RexxXPKBase
        STRUCT  RexxXPKLib,Library
        BPTR    rxpk_SegList
        APTR    rxpk_ExecBase
        APTR    rxpk_XPKBase
        APTR    rxpk_UtilityBase
        APTR    rxpk_RexxSysLibBase
    ENDSTRUCT   RexxXPKBase

ST  moveq   #-1,d0
    rts

RomTag  Uword   RTC_MATCHWORD
    Aptr    RomTag
    Aptr    EndLib
    Flag.b  RTF_AUTOINIT    ; initialisation par MakeLibrary()
    Ubyte   VERNUM
    Ubyte   NT_LIBRARY
    Byte    0
    Aptr    RexxXPK.Name
    Aptr    Library.ID
    Aptr    Library.Init

    dc.b    0,'$VER: '
Library.ID
    dc.b    'rexxxpk.library '
    REVISION
    dc.b    ' ('
    REVDATE
    dc.b    ')',10,13,0

    even
Library.Init
    Ulong   SIZEOF_RexxXPKBase  ; zone à réserver
    Aptr    Functions.Table ; table des fonctions
    Aptr    Data.Table  ; table d'initialisation
    Aptr    Lib.InitRoutine ; routine d'initialisation

Functions.Table
    Fptr    Lib.Open    ; ouverture
    Fptr    Lib.Close   ; fermeture
    Fptr    Lib.Expunge ; purge
    Fptr    NullFunc    ; réservée
    Fptr    ARexxQuery  ; interrogation par ARexx
    Ulong   -1  ; fin de la table

Data.Table
    INITBYTE    LN_TYPE,NT_LIBRARY
    INITLONG    LN_NAME,RexxXPK.Name
    INITLONG    LIB_IDSTRING,Library.ID
    INITBYTE    LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
    INITWORD    LIB_VERSION,VERNUM
    INITWORD    LIB_REVISION,REVNUM
EndLib  dc.l    0

; cette routine est appelée lors de l'initialisation de la bibliothèque
; on y ouvre les bibliothèques nécessaires. Le paramètre SegList est
; à stocker.
Lib.InitRoutine ; (D0)Success=Lib.InitRoutine(Base,SegList)(D0,A0)
    PUSH    d7/a2/a5-a6,Lib.InitRoutine
    move.l  d0,a5
    move.l  a6,rxpk_ExecBase(a5)
    move.l  a0,rxpk_SegList(a5)
    OPENLIB XpkMaster,2 ; ouverture de l'xpkmaster.library
    move.l  d0,rxpk_XPKBase(a5)
    bne.s   .XPKOpened
    move.l  #AN_Unknown!AG_OpenLib!AO_Unknown,d7
    CALL    Alert
    bra.s   .NoXPK
.XPKOpened
    OPENLIB Utility,37  ; ouverture de l'utility.library
    move.l  d0,rxpk_UtilityBase(a5)
    bne.s   .UtilityOpened
    move.l  #AN_Unknown!AG_OpenLib!AO_UtilityLib,d7
    CALL    Alert
    bra.s   .NoUtility
.UtilityOpened
    OPENLIB RexxSysLib,36   ; ouverture de la rexxsyslib.library
    move.l  d0,rxpk_RexxSysLibBase(a5)  ; peu l'échec

    move.l  a5,d0
.Back   POP Lib.InitRoutine
    rts
.NoUtility
    move.l  rxpk_UtilityBase(a5),a1
    CALL    CloseLibrary
.NoXPK  move.l  a5,a1   ; libération des ressources en cas
    moveq   #0,d0   ; d'erreur d'initialisation de la
    move.w  LIB_NEGSIZE(a5),d0  ; bibliothèque
    sub.l   d0,a1
    add.w   LIB_POSSIZE(a5),d0
    CALL    FreeMem
    moveq   #0,d0
    bra.s   .Back

; fonction d'ouverture de la bibliothèque: incrémentation du compteur
; de clients et effacement du bit de demande de purge. Si la
; rexxsyslib.library n'est pas encore ouverte, on l'ouvre.
Lib.Open    ; (D0)Base=Lib.Open(Base,Version)(A6,D0)
    addq.w  #1,LIB_OPENCNT(a6)
    bclr    #LIBB_DELEXP,LIB_FLAGS(a6)
    tst.l   rxpk_RexxSysLibBase(a6)
    bne.s   .OK
    move.l  a6,-(sp)
    move.l  rxpk_ExecBase(a6),a6
    OPENLIB RexxSysLib,36
    move.l  (sp)+,a6
    move.l  d0,rxpk_RexxSysLibBase(a6)
    bne.s   .OK
    moveq   #0,d0
    subq.w  #1,LIB_OPENCNT(a6)
    rts
.Ret  POP   Lib.Expunge
    rts

; fonction de fermeture de la bibliothèque: décrémentation du compteur
; de clients et purge de la bibliothèque si nécessaire et possible. Dans
; ce cas, la fonction de purge renvoie le paramètre SegList. Sinon, on
; doit retourner 0.
Lib.Close   ; (D0)SegList=Lib.Close(Base)(A6)
    subq.w  #1,LIB_OPENCNT(a6)
    bne.s   NullFunc
    btst    #LIBB_DELEXP,LIB_FLAGS(a6)
    bne.s   Lib.Expunge
NullFunc
    moveq   #0,d0
    rts

; fonction de purge de la bibliothèque: appelée par RemLibrary(), par
; exemple lorsque le système manque de mémoire. Si le compteur de clients
; est nul, toutes les ressources allouées par la fonction d'initialisation
; sont libérées et le paramètre SegList est retourné. Sinon, le bit de
; demande de purge est mis à 1 et 0 est retourné.
Lib.Expunge ; (D0)SegList=Lib.Expunge(Base)(A6)
    PUSH    d2/a5-a6,Lib.Expunge
    move.l  a6,a5
    tst.w   LIB_OPENCNT(a5) ; encore du monde?
    beq.s   .DoTheExpunge
    bset    #LIBB_DELEXP,LIB_FLAGS(a5)
    moveq   #0,d0
    bra.s   .Ret
.DoTheExpunge
    move.l  a5,a1   ; retire la bibliothèque de la liste
    CALL    Remove,rxpk_ExecBase(a5)    ; d'Exec
    move.l  rxpk_RexxSysLibBase(a5),d0
    beq.s   .NoRexxSysLib
    move.l  d0,a1
    CALL    CloseLibrary
.NoRexxSysLib
    move.l  rxpk_UtilityBase(a5),a1
    CALL    CloseLibrary
    move.l  rxpk_XPKBase(a5),a1
    CALL    CloseLibrary
    move.l  rxpk_SegList(a5),d2
    moveq   #0,d0
    move.l  a5,a1   ; libère la mémoire occupée par la structure
    move.w  LIB_NEGSIZE(a5),d0  ; de base de la bibliothèque
    sub.l   d0,a1
    add.w   LIB_POSSIZE(a5),d0
    CALL    FreeMem
    move.l  d2,d0   ; retourne le paramètre SegList
.Ret    movem.l (sp)+,d2/a5-a6
    rts


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