Suivez-nous sur X

|
|
|
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,
ALL
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : asl.library et GFA Basic
(Article écrit par Guillaume Guittenit et extrait de lesdocs.fr/amiga - juin 2025, mis à jour en juillet 2025)
|
|
Sous AmigaOS, la bibliothèque ASL
(Application Support Library) affiche une boite de dialogue pour choisir
des fichiers, des modes d'écran et des typographies. Cette bibliothèque fut judicieusement implémentée
dans le Kickstart 2.0 en 1990, puis mise à jour à chaque évolution du Workbench, jusqu'au dernier Kickstart 3.2.3
sorti en 2025.
La traditionnelle requête ASL dans OctaMED SoundStudio
Le Blitz Basic, le HiSoft BASIC,
AQB et le
PureBasic fournissent dans leurs exemples d'installation, des
codes de requêtes ASL prêts à l'emploi.
Exemple de requête ASL simple avec le HiSoft BASIC
Hélas, le GFA Basic
ne reconnaît pas l'asl.library. Pour sélectionner des fichiers, il existe la commande
FILESELECT mais elle est peu ergonomique et a un style ancien.
La boite de dialogue du GFA (FILESELECT) est un poil austère...
Mon amour pour ce langage obsolète étant ignoré par la raison, je décide de créer un code 100% GFA
pour lancer des requêtes ASL. Je m'appuie sur sa syntaxe "moderne" qui intègre beaucoup de routines
du système et permet de gérer les pointeurs.
1. Création de la procédure
Je commence par créer une procédure aslreq() avec quelques paramètres afin que ce code puisse être
réutilisable dans n'importe quel autre programme GFA Basic.
@aslreq("Choisis ton fichier","OK","Cancel","","RAM:")
PROCEDURE aslreq(titre$,oktexte$,canceltexte$,fichierdep$,dossierdep$)
...
RETURN
|
2. Ouverture de l'asl.library
J'ouvre l'asl.library avec la fonction système OpenLibrary() gérée nativement par le GFA, puis
je récupère en retour l'adresse de base ASL dans la variable "aslbase%" :
aslname$="asl.library"+CHR$(0)
aslbase%=OpenLibrary(V:aslname$,0)
|
Le nom de la bibliothèque doit se terminer par un caractère nul qui correspond au code ASCII numéro 0
indiquant la fin d'une chaîne de caractères. Il faut donc concaténer un CHR$(0) à la chaîne "asl.library".
Si l'ajout du CHR$(0) vous semble un odieux bricolage, le GFA Basic propose l'instruction CHAR{} permettant
de lire ou écrire un texte au format C en ponctuant les textes d'un octet nul :
aslname$="asl.library"
CHAR{aslname$}=aslname$
aslbase%=OpenLibrary(V:aslname$,0)
|
Dans le premier paramètre d'OpenLibrary(), "V:" désigne le pointeur de la variable "aslname$".
3. Structure FileRequester
Vient ensuite l'allocation d'une structure FileRequester dans laquelle sont indiqués les "tags",
à savoir le titre de la fenêtre de la requête, le texte du bouton "OK", le texte du bouton "Cancel",
le fichier et le dossier initiaux. Ces indications sont transmises via les paramètres de ma fonction
GFA aslreq().
Le GFA Basic ne gérant pas les structures, elle est reconstituée dans la mémoire en se documentant
sur le fichier libraries/asl.h
des Includes et Autodocs. En voici un extrait
permettant de définir les tags utilisés dans le code GFA :
/************************************************************************/
/* Tags for AllocAslRequest() and AslRequest() */
/************************************************************************/
#define ASL_Dummy (TAG_USER + 0x80000)
#define ASL_Hail ASL_Dummy+1 /* Hailing text follows */
#define ASL_Window ASL_Dummy+2 /* Parent window for IDCMP & screen */
#define ASL_LeftEdge ASL_Dummy+3 /* Initialize LeftEdge */
#define ASL_TopEdge ASL_Dummy+4 /* Initialize TopEdge */
#define ASL_Width ASL_Dummy+5
#define ASL_Height ASL_Dummy+6
#define ASL_HookFunc ASL_Dummy+7 /* Hook function pointer */
/* Tags specific to file request */
#define ASL_File ASL_Dummy+8 /* Initial name of file follows */
#define ASL_Dir ASL_Dummy+9 /* Initial string of filerequest dir */
/* Tags specific to font request */
#define ASL_FontName ASL_Dummy+10 /* Initial font name */
#define ASL_FontHeight ASL_Dummy+11 /* Initial font height */
#define ASL_FontStyles ASL_Dummy+12 /* Initial font styles */
#define ASL_FontFlags ASL_Dummy+13 /* Initial font flags for textattr */
#define ASL_FrontPen ASL_Dummy+14 /* Initial frontpen color */
#define ASL_BackPen ASL_Dummy+15 /* Initial backpen color */
#define ASL_MinHeight ASL_Dummy+16 /* Minimum font height to display */
#define ASL_MaxHeight ASL_Dummy+17 /* Max font height to display */
#define ASL_OKText ASL_Dummy+18 /* Text displayed in OK gadget */
#define ASL_CancelText ASL_Dummy+19 /* Text displayed in CANCEL gadget */
|
Une Taglist est un tableau de paires : tag-valeur. Le tag est un entier de 32 bits. La valeur
a également une taille de 32 bits. Il peut s'agir d'un entier ou d'un pointeur. La Taglist doit se
terminer par le tag 0 (Fin de liste). Voici la Taglist que je vais créer :
Tag (4 octets) |
Valeur (4 octets) |
Adresse ASL_Hail |
Pointeur vers "Choisis ton fichier" |
Adresse ASL_OKText |
Pointeur vers "OK" |
Adresse ASL_CancelText |
Pointeur vers "Cancel" |
Adresse ASL_File |
Pointeur vers "" |
Adresse ASL_Dir |
Pointeur vers "RAM:" |
Adresse TAG_END |
0 |
Pour commencer, je réserve une zone de mémoire de 88 octets remplis de zéros (paramètre 65536). La
variable "tags%" reçoit l'adresse de départ de la zone réservée :
Pour déterminer l'adresse de base des tags de la requête ASL, j'additionne le TAG_USER qui vaut &H80000000
et le décalage ("offset") des tags de la requête ASL qui vaut &H80000. La somme des deux donne
&H80080000. Le TAG_USER est défini dans utility/tagitem.h et vaut ((ULONG)(1UL<<31)), ce qui
fait &H80000000 en hexadécimal (1 décalé de 31 bits vers la gauche). J'écris donc en GFA :
En référence à l'inclusion asl.h, j'écris chaque tag-valeur pour personnaliser la boite de dialogue ASL :
LONG{tags%}=tagasl%+1 ! Titre du requester (ASL_Hail)
titre$=titre$+CHR$(0)
LONG{tags%+4}=V:titre$
LONG{tags%+8}=tagasl%+18 ! Texte OK (ASL_OKText)
oktexte$=oktexte$+CHR$(0)
LONG{tags%+12}=V:oktexte$
LONG{tags%+16}=tagasl%+19 ! Texte Cancel (ASL_CancelText)
canceltexte$=canceltexte$+CHR$(0)
LONG{tags%+20}=V:canceltexte$
LONG{tags%+24}=tagasl%+8 ! Fichier de départ (ASL_File)
fichierdep$=fichierdep$+CHR$(0)
LONG{tags%+28}=V:fichierdep$
LONG{tags%+32}=tagasl%+9 ! Dossier de départ (ASL_Dir)
dossierdep$=dossierdep$+CHR$(0)
LONG{tags%+36}=V:dossierdep$
LONG{tags%+40}=0 ! Fin de liste
|
En GFA Basic, "LONG{adr%}=x%" écrit la valeur de la variable "x%" sur quatre octets à l'adresse "adr%".
Après avoir renseigné les tags, j'écris un pointeur vers l'endroit où la liste des tags est stockée
dans registre "a0" qui correspond à "regs%(8)" :
4. Appel des fonctions AllocAslRequest() et AslRequest()
La fonction système AllocAslRequest() n'est pas gérée nativement par le GFA. Je vais donc l'appeler à
l'aide de l'instruction GFA Basic "RCALL" dont la syntaxe est :
L'instruction "RCALL" stocke certaines valeurs dans les registres du processeur avant de lancer une
routine assembleur, puis de tester le contenu des registres après exécution de la routine. J'utilise
un tableau de seize entiers de quatre octets : reg%(). Avant le lancement de la routine, les entrées du
tableau sont copiées dans les registres, et après exécution de la routine, le contenu des registres est
écrit dans les éléments correspondants du tableau :
Registres de données |
d0 à d7 dans reg%(0) à reg%(7) |
Registres d'adresse |
a0 à a6 dans reg%(8) à reg%(14) |
User Stack Pointer |
a7 dans reg%(15) (retour seulement) |
Pour appeler une fonction d'une bibliothèque système, je dois placer l'adresse de base de la bibliothèque
dans le registre "a6" qui correspond à "regs%(14)" :
Sous AmigaOS, l'espace d'adressage d'une bibliothèque peut se faire dans les deux sens, ce qui permet
l'usage d'un seul pointeur (Library Base). L'adressage avec un décalage négatif permet d'appeler les
fonctions de la bibliothèque.
Structure de la bibliothèque de l'Amiga et table de saut
Une fois qu'une application a ouvert une bibliothèque, elle peut commencer à utiliser ses fonctions.
Pour accéder à une fonction, une application a besoin de l'adresse de base de la bibliothèque renvoyée
par OpenLibrary() et du décalage du vecteur de bibliothèque (Library Vector Offset) de la fonction. Le
LVO d'une fonction est le décalage entre l'adresse de base de la bibliothèque et le vecteur de la fonction.
Un LVO est un nombre négatif car les vecteurs précèdent la base de la bibliothèque en mémoire.
Voici les décalages indiqués dans le ROM Kernel Manual Includes And Autodocs :
***************** asl
* "asl.library"
##base _AslBase
##bias 30
##public
*--- functions in V36 or higher (distributed as Release 2.0) ---
*
30 $ffe2 -$001e AllocFileRequest()()
36 $ffdc -$0024 FreeFileRequest(fileReq)(a0)
42 $ffd6 -$002a RequestFile(fileReq)(a0)
48 $ffd0 -$0030 AllocAslRequest(type,tagList)(d0/a0)
54 $ffca -$0036 FreeAslRequest(request)(a0)
60 $ffc4 -$003c AslRequest(request,tagList)(a0/a1)
##end
|
D'après les indications du RKM ci-dessus, la fonction AllocAslRequest() est accessible au décalage -48 en
décimal, c'est-à-dire -&H30 en hexadécimal. J'écris donc en GFA Basic :
RCALL aslbase%-&H30,regs%()
|
Je lance AllocASLRequest() pour réserver une zone mémoire qui servira à inscrire la sélection de l'utilisateur.
La boite de dialogue ASL va finalement apparaître grâce à la fonction AslRequest() qui est appelée avec
l'instruction "RCALL" car cette fonction n'est pas gérée nativement par le GFA.
RCALL aslbase%-&H3C,regs%()
|
Whaouuuuu ! C'est de toute beauté !
Quand l'utilisateur valide sa sélection, le nom du fichier et du dossier sont écrits dans la mémoire.
Au décalage 4, j'ai un pointeur vers le nom du fichier, et au décalage 8, un pointeur vers le chemin.
Le résultat de la requête est mis dans le registre "d0" correspondant à "regs%(0)". C'est ce que je teste
pour savoir si l'utilisateur a cliqué sur "Cancel".
IF regs%(0)
' L'utilisateur a choisi un fichier
fichier$=CHAR{LONG{monfilereq%+4}}
chemin$=CHAR{LONG{monfilereq%+8}}
PRINT "Fichier sélectionné : ";fichier$
PRINT "Chemin : ";chemin$
PAUSE 100
ENDIF
|
Le fichier et le dossier sélectionnés seront ensuite lus avec l'instruction "LONG" puis publiés dans une
fenêtre avec l'incontournable "PRINT". C'est du BASIC, n'oublions pas !
5. Le code final
Le code complet fonctionne aussi bien en mode interprété que compilé. J'ai tenté de l'écrire de la façon
la plus concise possible afin de ne pas trop rougir de la comparaison avec les autres langages.
' ASL Requester en GFA Basic par Guillaume Guittenit
' Ouverture d'une fenêtre
OPENW #5
@aslreq("Choisis ton fichier","OK","Cancel","","RAM:")
PROCEDURE aslreq(titre$,oktexte$,canceltexte$,fichierdep$,dossierdep$)
' Ouverture de la asl.library
aslname$="asl.library"+CHR$(0)
aslbase%=OpenLibrary(V:aslname$,0)
IF aslbase%=0
PRINT "Impossible d'ouvrir la asl.library"
END
ENDIF
' Allocation d'une structure FileRequester
tags%=MALLOC(88,65536) ! Réserve 88 octets remplis de zéros
tagasl%=&H80080000
LONG{tags%}=tagasl%+1 ! Titre du requester ASL
titre$=titre$+CHR$(0)
LONG{tags%+4}=V:titre$
LONG{tags%+8}=tagasl%+18 ! Texte OK
oktexte$=oktexte$+CHR$(0)
LONG{tags%+12}=V:oktexte$
LONG{tags%+16}=tagasl%+19 ! Texte Cancel
canceltexte$=canceltexte$+CHR$(0)
LONG{tags%+20}=V:canceltexte$
LONG{tags%+24}=tagasl%+8 ! Fichier de départ
fichierdep$=fichierdep$+CHR$(0)
LONG{tags%+28}=V:fichierdep$
LONG{tags%+32}=tagasl%+9 ! Dossier de départ
dossierdep$=dossierdep$+CHR$(0)
LONG{tags%+36}=V:dossierdep$
LONG{tags%+40}=0 ! Fin de liste
' Dimensionnement du tableau de registres pour l'instruction RCALL
DIM regs%(15)
regs%(8)=tags% ! Registre A0
regs%(14)=aslbase% ! Base dans le registre A6
RCALL aslbase%-&H30,regs%()
monfilereq%=regs%(0)
' Appel du sélecteur de fichiers
regs%(8)=regs%(0)
RCALL aslbase%-&H3C,regs%()
' Le résultat est lu. Si on a zéro, l'utilisateur a sélectionné Cancel
IF regs%(0)
' L'utilisateur a choisi un fichier
fichier$=CHAR{LONG{monfilereq%+4}}
chemin$=CHAR{LONG{monfilereq%+8}}
PRINT "Fichier sélectionné : ";fichier$
PRINT "Chemin : ";chemin$
PAUSE 100
ENDIF
RETURN
' Fermeture de la asl.library et libération de la mémoire
~CloseLibrary(aslbase%)
~MFREE(tags%,88)
CLOSEW #5
|
Les fichiers sont disponibles ici :
6. Résultat
Le code interprété ou compilé fonctionne nickel sur mon Amiga 1200 avec AmigaOS 3.2.3 :
Le code 68k compilé fonctionne également sous MorphOS. Merci à son compilateur Trance Just In Time :
Étonnant, non ?
Soutenez le travail de l'auteur
|
|
|