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 : C - Requête flexible de gadgets de chaîne de caractères utilisant l'allocation dynamique de mémoire
(Article écrit par Randy Finch et extrait du Randy Finch's Web Site - février 1990)
|
|
J'ai travaillé sur un programme en C (sur AmigaOS 1.3) qui nécessite plusieurs requêtes contenant uniquement des gadgets
de type chaîne de caractères et deux gadgets booléens ("OK" et "Cancel"). Le problème que j'ai rencontré
est que chaque requête a besoin d'un nombre différent de gadgets de type chaîne. Ne voulant pas écrire
une fonction différente pour chaque requête, j'ai décidé d'écrire une fonction capable de générer toutes
les requêtes dont j'avais besoin. Pour accomplir cette tâche, l'allocation dynamique de la mémoire a été utilisée.
Allocation dynamique de la mémoire sur l'Amiga
Après avoir étudié les différentes méthodes d'allocation de la mémoire sur Amiga, j'ai décidé qu'utiliser
la fonction AllocRemember fournie par la bibliothèque Intuition serait la méthode la plus simple.
Cette fonction crée une liste liée de blocs mémoire en utilisant une structure Remember (définie dans
intuition.h). Une structure Remember a la forme suivante :
struct Remember {
struct Remember *NextRemember;
ULONG RememberSize;
UBYTE *Memory;
}
|
Cette structure contient un pointeur vers une autre structure Remember, un entier long non signé contenant
la taille du bloc mémoire, et un pointeur vers le bloc mémoire alloué. Le pointeur NextRemember rend
possible la liste liée de blocs mémoire.
Afin de créer une liste liée, un pointeur vers une structure Remember doit être déclaré et initialisé
à NULL comme suit :
struct Remember *MyMemBlocks = NULL ;
|
Supposons que deux blocs mémoire, l'un de 100 octets et l'autre de 200 octets, soient nécessaires
au programme. La fonction AllocRemember est appelée comme suit :
mem_pointer1 = AllocRemember(&MyMemBlocks,100,MEMF_CLEAR) ;
|
Le premier argument est l'adresse du pointeur de la structure Remember. Il est important de garder à
l'esprit que ce n'est pas un pointeur vers une structure Remember, mais un pointeur vers ce pointeur.
Ceci est illustré dans la figure 1.
Le deuxième argument est la quantité mémoire à allouer, dans ce cas 100 octets. Le troisième argument
contient des drapeaux (définis dans memory.h) ; MEMF_CLEAR signifie remplir le bloc mémoire avec des
zéros après l'allocation. Les autres drapeaux incluent :
MEMF_FAST Allocate fast (external) memory
MEMF_CHIP Allocate chip (internal 512K) memory
MEMF_PUBLIC Allocate memory for different tasks or interrupt code
such as task control blocks, messages, ports, etc.
|
Si aucun des drapeaux ci-dessus n'est activé, MEMF_FAST est supposé être le premier. Si aucune mémoire
Fast n'est disponible, la mémoire Chip est utilisée.
La fonction AllocRemember renvoie un pointeur vers le bloc mémoire alloué si elle est réussie ou NULL
si elle échoue. AllocRemember effectue en fait deux allocations de mémoire, une pour la structure Remember
et une pour le bloc mémoire demandé. Il remplit également la structure Remember et définit la variable
MyMemBlocks pour qu'elle pointe sur la structure. Ceci est représenté graphiquement dans les Figures 2a et 2b.
Afin d'allouer le bloc mémoire de 200 octets, la fonction AllocRemember est à nouveau appelée de la même
manière que précédemment.
mem_pointer2 = AllocRemember(&MyMemBlocks,200,MEMF_CLEAR) ;
|
Ici, la fonction crée une autre structure Remember et définit l'élément NextRemember de la structure Remember
précédente pour qu'il pointe vers cette nouvelle structure. De plus, un bloc mémoire de 200 octets est
alloué (voir figure 2c).
En raison de la manière dont la fonction AllocRemember est appelée, il est très facile d'allouer plusieurs
blocs mémoire de taille égale. Par exemple, pour créer 10 blocs mémoire qui contiendront chacun une
structure IntuiText, la méthode présentée dans le listing 1 peut être utilisée.
Listing 1
Fragment de code C illustrant comment allouer
Dix blocs de mémoire à utiliser pour les structures IntuiText
UBYTE *pointer;
ULONG i;
struct Remember *IntuiTextBlocks = NULL;
...
...
for( i = 0 ; i < 10 ; ++i) {
pointer = AllocRemember(&IntuiTextBlocks,
sizeof(struct IntuiText), MEMF_CLEAR);
/* Exit if allocation fails */
if (pointer = NULL) ExitRoutine();
}
...
...
|
Après l'exécution de ce code, IntuiTextBlocks pointera vers la première des 10 structures Remember qui
sont liées entre elles par les pointeurs NextRemember. Chaque bloc mémoire est accessible via
l'élément Memory de la structure Remember correspondante. Ces pointeurs peuvent être convertis en
"pointeur vers une structure IntuiText", puis les blocs mémoire peuvent être remplis de données, comme
le montre le listing 2.
Listing 2
Fragment de code C illustrant la manière de remplir
dix blocs de mémoire avec des informations IntuiText
UBYTE i;
STRPTR Titles[10];
struct Remember *ITextPointer;
struct Remember *IntuiTextBlocks;
struct IntuiText *CurITextPointer;
...
...
/* Assign temporary pointer to Remember structures */
ITextPointer = IntuiTextBlocks;
for (i = 0; i < 10; ++i) {
/* Cast a memory block pointer to IntuiText structure
pointer */
CurITextPointer = (struct IntuiText *) ITextPointer->Memory;
CurITextPointer->FrontPen = 0;
CurITextPointer->BackPen = 1;
CurITextPointer->DrawMode = JAM2;
CurITextPointer->LeftEdge = 80;
CurITextPointer->TopEdge = 0;
CurITextPointer->ITextFont = NULL;
CurITextPointer->IText = Titles[i];
CurITextPointer->NextText = NULL;
/* Get next memory block in the linked list */
ITextPointer = ITextPointer->NextRemember;
}
...
...
|
Lorsque les blocs mémoire ne sont plus nécessaires, la fonction FreeRemember peut être appelée.
FreeRemember(&IntuiTextBlocks, TRUE);
|
Cette fonction va désallouer tous les blocs mémoire de la liste ainsi que la mémoire utilisée par
les structures Remember. Si le deuxième argument est "FALSE" (FAUX), toutes les structures Remember seront effacées
mais les blocs mémoire resteront intacts.
La méthode qui vient d'être décrite a été utilisée pour allouer dynamiquement de la mémoire pour diverses
structures et tampons mémoire dans une fonction qui peut créer une requête contenant un nombre variable
de gadgets de chaîne. Cette fonction est intitulée "StringsRequest" et fait partie du programme intitulé
"StrReq.c" présenté dans le listing 3.
La fonction StringsRequest
Six listes liées distinctes de blocs mémoire sont utilisées dans la fonction StringsRequest. Quatre de
ces listes liées contiennent chacune des structures Remember NumEntrys, où "NumEntrys" est le nombre de
gadgets de chaîne de caractères requis dans la requête. Ces structures Remember pointent vers des blocs
mémoire contenant toutes les structures Gadget et leurs structures IntuiText et StringInfo associées,
ainsi que la mémoire tampon pour les chaînes de gadgets. Les cinquième et sixième listes liées ne contiennent
en fait qu'une seule structure Remember chacune. L'une pointe vers un bloc mémoire contenant une structure
Requester tandis que l'autre pointe vers un tampon d'annulation.
Les structures IntuiText fournissent des informations sur le texte lié à chaque gadget. Ce texte apparaît
à gauche de chaque gadget de chaîne et peut être utilisé pour identifier le type d'information que
l'utilisateur doit fournir dans le gadget. Les structures StringInfo fournissent des informations sur
les chaînes de caractères qui apparaissent réellement dans les gadgets. L'une des informations de cette
structure est un pointeur vers un tampon où le texte réel est stocké. Il existe un tampon distinct pour
chaque gadget. La structure contient également un pointeur vers un tampon d'annulation. Ce tampon mémoire est
rempli avec une copie d'un tampon mémoire de gadget de chaîne de caractères lorsque le gadget est sélectionné
pour la première fois. Une fois les modifications apportées à la chaîne de caractères dans le gadget,
l'utilisateur peut revenir au contenu original du gadget en appuyant sur les touches "Amiga droite+Q".
Un seul tampon d'annulation est suffisant pour tous les gadgets, car un seul gadget peut être actif à la
fois. La structure de requête relie toutes les informations ci-dessus.
Utilisation de la fonction StringsRequest
La fonction StringsRequest est de type "Bool" ; elle renvoie "TRUE" (VRAI) si la requête est ouverte et
fermée avec succès, sinon elle renvoie "FASLE" (FAUX). Les huit paramètres passés à la fonction sont décrits
dans le tableau ci-dessous.
Tableau 1 : description des huit paramètres à passer à la fonction StringsRequest
- HeaderText : pointeur vers une chaîne de caractères à terminaison nulle contenant le texte
à centrer en haut de la page de la requête.
- NumEntrys : nombre de gadgets de chaîne devant apparaître dans la requête.
- BoxWidth : tableau de nombres entiers courts contenant la largeur, en caractères, des
cases devant contenir les chaînes de caractères dans les gadgets. Ce tableau doit comporter au moins
"NumEntrys" éléments.
- Titles : ttableau de pointeurs vers des chaînes à terminaison nulle contenant le texte devant
apparaître à la gauche de chaque gadget de chaîne. Ce texte permet d'identifier le type d'information
que contient chaque gadget de chaîne. Ce tableau doit comporter au moins "NumEntrys" éléments.
- DefText : tableau de pointeurs vers des chaînes de caractères à terminaison nulle contenant le
texte initial devant apparaître à l'intérieur de chaque gadget de chaîne. Assurez-vous que les tampons
mémoire contenant les chaînes sont suffisamment longs pour contenir leurs longueurs de chaîne
maximale respective. Ce tableau doit comporter au moins "NumEntrys" éléments.
- MaxLenDefText : tableau de petits nombres entiers contenant la longueur maximale des
chaînes de caractères dans chaque gadget de chaîne. Cette longueur inclut le terminateur nul.
Ce tableau doit comporter au moins "NumEntrys" éléments.
- TypeDefText : tableau d'entiers courts contenant soit un zéro, soit un LONGINT (défini dans
intuition.h). Un zéro indique que le gadget correspondant est un gadget standard de type
chaîne de caractères standard. LONGINT indique que le gadget ne doit accepter que des entiers longs.
Ce tableau doit comporter au moins "NumEntrys" éléments.
- Window : pointeur vers la structure Window de la fenêtre dans laquelle la requête apparaîtra.
Intuition ne permet pas à un gadget de chaîne de caractères d'être plus large que la longueur maximale
de la chaîne qu'il contient. Par conséquent, si un élément du tableau MaxLenDefText est plus petit que
l'élément correspondant du tableau BoxWidth, la largeur du gadget sera égale à MaxLenDefText plutôt
qu'à BoxWidth. La fonction StringsRequest en tient compte lorsqu'elle détermine la taille de la requête.
Si un élément du tableau TypeDefText est égal à LONGINT, Intuition n'autorisera la saisie que d'entiers
longs dans le gadget de chaîne. Ceci est utile si l'information requise est un nombre. La valeur initiale
dans l'élément correspondant du tableau DefText doit toujours être une chaîne de caractères ; il est donc
nécessaire de convertir le long entier en une chaîne ASCII avant d'appeler StringsRequest. Une fois que
la fonction renvoie le contrôle à la routine d'appel, la chaîne ASCII doit être reconvertie en un nombre
entier.
La fonction StringsRequest utilise les informations fournies par ses paramètres pour déterminer la largeur
et la hauteur nécessaires de la requête afin qu'elle puisse contenir les gadgets de chaîne et le texte
associé. Elle commence par allouer la quantité de mémoire requise, remplit cette mémoire avec toutes
les structures de données nécessaires, puis affiche la requête. La figure 3 montre un exemple de requête
contenant cinq gadgets de type chaîne.
Comme les gadgets sont affichés en colonnes, la requête est limitée à 10 gadgets de chaîne dans une fenêtre
plein écran en mode non entrelacé ou à 20 gadgets en mode entrelacé.
La requête contient également deux gadgets booléens, l'un affichant "OK" et l'autre affichant "Cancel" (Annuler).
Après avoir modifié le texte dans les gadgets de chaîne, le gadget "OK" peut être sélectionné pour
affecter les nouvelles entrées aux chaînes de caractères pointées par le tableau DefText. Si vous sélectionnez
"Cancel", le texte qui se trouvait dans les gadgets au moment de l'affichage de la requête reste intact.
Après avoir choisi "OK" ou "Cancel", la requête disparaît, la mémoire allouée aux différentes structures
de données retourne dans le pool de mémoire libre et le contrôle revient au programme appelant.
Le programme court intitulé TestSR présenté dans le listing 4 peut être compilé et lié à StrReq.c.
Il démontre le fonctionnement de la fonction StringsRequest. Le programme demande à l'utilisateur à
l'écran des informations sur les gadgets de chaîne à afficher dans la requête. Alternativement, un fichier
texte contenant toutes ces informations peut être créé et le programme peut être exécuté avec l'entrée
redirigée vers ce fichier. TestSR lira les informations, ouvrira une fenêtre et affichera la requête.
Une fois les modifications effectuées et le gadget "OK" ou "Cancel" choisi, la fenêtre se fermera et
le texte actuel de chaque gadget sera affiché.
J'espère que cette fonction et les techniques de programmation qu'elle utilise vous seront utiles.
|