Coder une bibliothèque Scol en C - Niveau 3 » History » Version 1
iri, 01/29/2013 10:09 PM
1 | 1 | iri | h1. Coder une bibliothèque Scol en C - Niveau 3 |
---|---|---|---|
2 | |||
3 | Objectif : nouvel objet Scol, fonctions callbacks |
||
4 | |||
5 | Moyens : |
||
6 | |||
7 | * définir un nouveau type Scol; |
||
8 | * fonctions de création et de destruction d'un objet; |
||
9 | * manipulation de l'objet; |
||
10 | * fonctions réflexes (callbacks) sur cet objet; |
||
11 | * intégration simple de la librairie "libcurl":http://curl.haxx.se/libcurl/; |
||
12 | * code source de la bibliothèque; |
||
13 | * exemple d'utilisation dans une application Scol. |
||
14 | |||
15 | STATUT : COMPLET |
||
16 | Version : 1.0 |
||
17 | Date : Novembre 2010 (initialement diffusé sur http://www.irizone.net) |
||
18 | Auteur : iri |
||
19 | Licence du tutoriel : GNU FDL v1.3 |
||
20 | Licence du code source : GNU/GPL v3 |
||
21 | Téléchargement : http://www.irizone.net/dl/tutos/vmscol/vm_example_3.tar.gz |
||
22 | Langage : *C* |
||
23 | Ok pour toute version de Scol Windows et GNU/Linux (> 4.0). |
||
24 | |||
25 | h2. La bibliothèque _libcurl_, exemple d'intégration |
||
26 | |||
27 | "Libcurl":http://curl.haxx.se/libcurl/ est une bibliothèque "libre":http://curl.haxx.se/docs/copyright.html |
||
28 | et gratuite pour de très nombreux systèmes et langages. Elle est très utilisée et |
||
29 | a atteint un bon degré de robustesse. Elle est capable d'utiliser de nombreux |
||
30 | protocoles, sous divers formats. |
||
31 | |||
32 | En Scol, les connexions au réseau sont actuellement codées en bas niveau, grâce |
||
33 | aux sockets. Peu de protocoles sont disponibles (http et telnet) et sous certaines |
||
34 | conditions. Utiliser une telle librairie de plus haut niveau permettrait de s'affranchir |
||
35 | du code bas niveau, toujours plus fastidieux, d'intégrer une biliothèque robuste |
||
36 | et éprouvée et d'élargir les capacités de Scol. En contrepartie, son utilisation |
||
37 | rend Scol plus dépendant. C'est pourquoi les "anciennes" fonctions ne devraient |
||
38 | pas être dépréciées. |
||
39 | |||
40 | h3. Comment intégrer une telle bibliothèque ? |
||
41 | |||
42 | Au niveau de Scol, il n'y a rien de particulier à faire. Au niveau du code |
||
43 | source, il faut bien évidemment inclure les fichiers d'en-tête nécessaires. Au |
||
44 | niveau du binaire à diffuser, deux solutions s'offrent à vous : |
||
45 | |||
46 | # inclure la bibliothèque dans la votre. Cela rend l'utilisateur final indépendant, |
||
47 | il n'a pas à installer libcurl de façon disjointe. Cependant, s'il la possède déjà, |
||
48 | c'est un peu inutile. De plus, le poids de votre bibliothèque sera plus important. |
||
49 | # ne pas inclure la bibliothèque dans la votre. Cela la rendra plus légère au |
||
50 | niveau du poids et si l'utilisateur final la possède déjà, il n'y aura pas d'effet |
||
51 | doublon. En revanche, s'il ne la possède pas, elle ne fonctionnera pas tant qu'il |
||
52 | ne l'aura pas installé. |
||
53 | |||
54 | Il n'y a pas de solutions idéales mais un compromis à faire. À vous de voir. |
||
55 | |||
56 | h3. Exemple : Se connecter à un serveur et récupérer un fichier |
||
57 | |||
58 | Il s'agit de l'utilisation la plus simple de libcurl : lui donner une url et |
||
59 | enregistrer la réponse du serveur dans un fichier local. Nous allons donc le faire. |
||
60 | |||
61 | Il n'y a rien de particulier par rapport à ce qui a été vu dans les niveaux |
||
62 | précédents. Le reste du code C est pour appeler et interfacer la bibliothèque libcurl. |
||
63 | |||
64 | # On récupère les données depuis la pile Scol et on teste leur validité; |
||
65 | # On initialise la bibliothèque; |
||
66 | # On alloue dynamiquement nos ressources (il ne faudra donc pas oublier de les |
||
67 | libérer !); |
||
68 | # On envoie la requête à libcurl et on définit la callback d'écriture des données |
||
69 | reçues. À ce sujet, nous ne verrons pas ici (mais plus bas dans ce tutoriel) |
||
70 | l'ajout d'une callback Scol. C'est libcurl qui se chargera d'écrire dans notre |
||
71 | fichier. En effet, par défaut, celle-ci écrit les données reçues dans un fichier |
||
72 | (et si ce fichier n'est pas défini, ce sera sur la sortie standard).</li><br /> |
||
73 | # Nous libérons nos ressources; |
||
74 | # Nous empilons notre réponse dans la pile Scol. |
||
75 | |||
76 | La fonction Scol retournera 0 si tout s'est correctment passé. Autrement, nil |
||
77 | sera retourné si l'url ou le fichier local valent eux-même nil, si le fichier local |
||
78 | ne peut être ouvert en écriture ou si la libcurl n'a pas pu s'initialiser. Dans les |
||
79 | autres cas, elle retournera un entier positif indiquant le type d'erreur que |
||
80 | libcurl a rencontré. Pour avoir une liste complète des erreurs possibles, consultez |
||
81 | cette "page":http://curl.haxx.se/libcurl/c/libcurl-errors.html. |
||
82 | |||
83 | Notez que plus loin une méthode plus conviviale de gestion des erreurs sera |
||
84 | proposée (voir dans l'archive téléchargeable). |
||
85 | |||
86 | Code source de la fonction : |
||
87 | |||
88 | <pre>int sc_getFile (mmachine m) |
||
89 | { |
||
90 | int murl, mlocalfile, len; |
||
91 | char * url, * localfile, * err = NULL; |
||
92 | |||
93 | CURL * hCurl; /* handle système */ |
||
94 | CURLcode rCurl; /* result */ |
||
95 | FILE * fp = NULL; |
||
96 | |||
97 | MMechostr (MSKDEBUG, "sc_getFile : entering ...n"); |
||
98 | |||
99 | mlocalfile = MTOP (MMpull (m)); |
||
100 | murl = MTOP (MMpull (m)); |
||
101 | |||
102 | if ((mlocalfile == NIL) || (murl == NIL)) |
||
103 | { |
||
104 | MMechostr (MSKDEBUG, "sc_getFile error : url or localfile is niln"); |
||
105 | MMpush (m, NIL); |
||
106 | return 0; |
||
107 | } |
||
108 | |||
109 | hCurl = curl_easy_init(); |
||
110 | if (hCurl) /* init ok */ |
||
111 | { |
||
112 | /* Nous n'avons pas besoin d'avoir cette donnée dans la pile, |
||
113 | nous n'utilisons donc pas les fonctions d'allocation de la machine Scol |
||
114 | mais les fonctions d'allocation (et de libération) standard du C.*/ |
||
115 | len = sizeof (char) * (MMsizestr (m, mlocalfile)); |
||
116 | localfile = (char *) malloc (len+1); |
||
117 | strncpy (localfile, MMstartstr (m, mlocalfile), len); |
||
118 | localfile[len] = '\0'; |
||
119 | |||
120 | fp = fopen (localfile, "w"); |
||
121 | if (fp == NULL) |
||
122 | { |
||
123 | curl_easy_cleanup (hCurl); |
||
124 | free (localfile); localfile = NULL; |
||
125 | MMpush (m, NIL); |
||
126 | return 0; |
||
127 | } |
||
128 | |||
129 | err = (char *) malloc (sizeof (char) * (CURL_ERROR_SIZE +1)); |
||
130 | len = sizeof (char) * (MMsizestr (m, murl)); |
||
131 | url = (char *) malloc (len+1); |
||
132 | strncpy (url, MMstartstr (m, murl), len); |
||
133 | url[len] = '\0'; |
||
134 | |||
135 | curl_easy_setopt (hCurl, CURLOPT_URL, url); |
||
136 | curl_easy_setopt (hCurl, CURLOPT_WRITEFUNCTION, fwrite); |
||
137 | curl_easy_setopt (hCurl, CURLOPT_WRITEDATA, (FILE *) fp); |
||
138 | curl_easy_setopt (hCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); |
||
139 | curl_easy_setopt (hCurl, CURLOPT_ERRORBUFFER, err); |
||
140 | rCurl = curl_easy_perform (hCurl); |
||
141 | |||
142 | MMechostr (MSKDEBUG, "sc_getFile : err = %s ...n", err); |
||
143 | curl_easy_cleanup (hCurl); |
||
144 | fclose (fp); |
||
145 | |||
146 | free (localfile); localfile = NULL; |
||
147 | free (url); url = NULL; |
||
148 | free (err); err = NULL; |
||
149 | |||
150 | MMpush (m, ITOM (rCurl)); |
||
151 | return 0; |
||
152 | } |
||
153 | |||
154 | MMpush (m, NIL); |
||
155 | return 0; |
||
156 | }</pre> |
||
157 | |||
158 | |||
159 | h3. Exemple d'utilisation avancée |
||
160 | |||
161 | h4. Nouveau type Scol |
||
162 | |||
163 | À présent, nous allons voir comment ajouter un nouveau type Scol et comment |
||
164 | gérer des callbacks Scol, le tout en utilisant libcurl comme fil rouge. |
||
165 | |||
166 | Pour créer un nouveau type Scol, il faut : |
||
167 | |||
168 | # L'enregistrer au sein de la machine Scol, afin qu'il soit connu; |
||
169 | # Le paramétrer et, notamment, définir sa fonction de destruction (ou plus |
||
170 | exactemement sa fonction réflexe de destruction). |
||
171 | |||
172 | L'enregistrement se réalise grâce à la fonction _OBJregister_ : elle est |
||
173 | définie dans le kernel, au sein du fichier "kernel/scolobj.c". |
||
174 | |||
175 | Elle prend 4 arguments : |
||
176 | |||
177 | # Le nombre de callbacks attendues, associées aux objets Scol de ce type. Si vous |
||
178 | définissez par exemple 4 callbacks associées aux objets de ce type (par exemple, |
||
179 | création, destruction, affectation et récupération), alors il faudra indiquer 4; |
||
180 | # Un flag indiquant si les objets de ce type sont détruits si leur objet parent |
||
181 | est détruit (si un tel type objet parent est défini, ce qui est rare). Généralement, |
||
182 | on laisse à 1, ce qui implique la destruction si le parent est détruit (et comme |
||
183 | il n'y a généralement pas de parent, cela ne change rien !); |
||
184 | # La callback interne de destruction, appelée lorsqu'un objet de ce type est |
||
185 | implicitement ou explicitement détruit; |
||
186 | # Le nom interne de ce type (qui sera utilisé dans certains cas particuliers, autant |
||
187 | lui donner un nom suffisamment explicite). |
||
188 | |||
189 | Par exemple : |
||
190 | <pre>#define NB_REFLEX 4 |
||
191 | int MyObjectType; |
||
192 | MyObjectType = OBJregister (NB_REFLEX, 1, MyObjTypeDestroy, "MyNewObjectType"); |
||
193 | </pre> |
||
194 | |||
195 | h4. Comment est définie la callback de destruction ? |
||
196 | |||
197 | Son prototype C est : |
||
198 | |||
199 | @int MyObjTypeDestroy (mmachine, int, int);@ |
||
200 | |||
201 | Son premier argument est bien sur la machine Scol concernée, son second est le |
||
202 | pointeur vers l'objet système et le troisième est le pointeur vers l'objet Scol. |
||
203 | Cette fonction n'a théoriquement pas à être appelée directement, son appel devrait |
||
204 | rester transparente pour le programeur. |
||
205 | Nous pouvons lui faire faire tout un tas de choses, selon les cas. De manière |
||
206 | générale, son application minimale consiste à supprimer la référence de l'objet |
||
207 | dans la machine Scol, via _MMstore_ à NULL. Le code habituellement minimal est le suivant : |
||
208 | |||
209 | <pre>int MyObjTypeDestroy (mmachine m, int handlesys, int handlem) |
||
210 | { |
||
211 | TYPE_C * obj; |
||
212 | |||
213 | obj = (TYPE_C *) MMfetch (m, MTOP (handlem), OBJTYPE_C_HANDLE); |
||
214 | if (obj == NULL) |
||
215 | { |
||
216 | MMechostr(MSKDEBUG, "MyObjTypeDestroy : object already destroyedn"); |
||
217 | return 0; |
||
218 | } |
||
219 | |||
220 | MMstore (m, MTOP (handlem), OBJTYPE_C_HANDLE, (int) NULL); |
||
221 | MMechostr(MSKDEBUG, "MyObjTypeDestroy: object has been destroyedn"); |
||
222 | |||
223 | return 0; |
||
224 | }</pre> |
||
225 | |||
226 | Le flag _OBJTYPE_C_HANDLE_ est un flag utilisé lors de la création de l'objet, ce que nous verrons ci-après. |
||
227 | |||
228 | h4. Nouvel objet Scol |
||
229 | |||
230 | Pour créer un objet d'un type Scol, il est nécessaire de suivre ces étapes : |
||
231 | |||
232 | # Création de l'objet système (en C ou en C++), avec tout ce que cela peut impliquer. |
||
233 | Ici, l'utilisation de libcurl va nous simplifier la tâche et nous n'aurons donc |
||
234 | pas à coder des processus de plus ou moins bas niveaux comme l'allocation mémoire |
||
235 | et tout le reste; |
||
236 | # Allouer la mémoire au sein de la machine Scol. Nous utiliserons pour cela la |
||
237 | fonction <em>MMalloc</em> (ne confondez pas avec l'allocation système, via malloc); |
||
238 | # Stocker l'objet dans la machine Scol, grâce à la fonction _MMstore_; |
||
239 | # Empiler l'objet dans la pile Scol, afin de le rendre disponible au programmeur |
||
240 | Scol (_MMpush_); |
||
241 | # Créer la référence de l'objet avec le nouveau type avec OBJcreate. |
||
242 | |||
243 | Exemple : |
||
244 | |||
245 | <pre>sizetab = sizeof (TYPE_OBJECT_C) + 1; |
||
246 | objtab = MMalloc (m, sizetab, TYPETAB); |
||
247 | if (objtab == NIL) |
||
248 | { |
||
249 | MMpush (m, NIL); |
||
250 | return 0; |
||
251 | } |
||
252 | MMstore (m, objtab, OBJTYPE_C_HANDLE, (int) handle_sys); |
||
253 | MMpush (m, PTOM (objtab)); |
||
254 | OBJcreate (m, MyObjectType, (int) handle_sys, parent_type, parent);</pre> |
||
255 | |||
256 | _MMalloc_ prend donc trois arguments. Les deux premiers sont logiques : |
||
257 | respectivement la machine Scol dans laquelle allouée et la taille à allouer. Le |
||
258 | troisième est un flag qui peut prendre la valeur de TYPETAB (array) ou TYPEBUF |
||
259 | (buffer). |
||
260 | |||
261 | _MMstore_ attend 4 arguments : la machine Scol, le pointeur qui vient |
||
262 | d'être alloué et qui contiendra l'objet, un flag spécifique que vous définissez |
||
263 | vous-même et le pointeur système pour la liaison. |
||
264 | |||
265 | _MMpush_ empile le pointeur de l'objet (normal !). |
||
266 | |||
267 | _OBJcreate_ s'approprie 5 arguments : la machine Scol, une variable |
||
268 | interne qui contient le type Scol, le pointeur système et, de façon optionnelle, |
||
269 | le type de l'objet parent et le parent lui-même, s'il y a lieu (sinon, une valeur |
||
270 | comme -1 ou NIL pour ses deux derniers convient). |
||
271 | |||
272 | Il y a un élément dont nous n'avons absolument pas parler, c'est le canal, qui est |
||
273 | à la base de Scol, dans lequel cet objet doit être crée. Il est *impératif* |
||
274 | qu'il soit parmi les éléments de la pile, typiquement présent dans les arguments |
||
275 | de la fonction Scol appelant à la création de l'objet. Lors de l'appel à OBJcreate, |
||
276 | il *faut* que le canal considéré soit à l'étage 1 de la pile, l'étage |
||
277 | 0 étant occupé par le pointeur objet (MMpush précédent). Si le canal n'est pas présent |
||
278 | à cet étage 1 (assurez vous en !), vous devez l'y placer, grâce à MMset ou à la macro |
||
279 | INVERT suivant les cas. Ou, à défaut, en récupérant le canal courant dans la pile. |
||
280 | N'oubliez pas ! |
||
281 | |||
282 | L'histoire du canal est cruciale. C'est la principale raison de plantage ou de |
||
283 | non création d'objet lorsque vous testerez votre code. Le canal n'est jamais |
||
284 | explicitement utilisé et il est ainsi facilement oublié. Il convient également |
||
285 | de tester sa validité <strong>avant</strong> toutes manipulations de création C ou |
||
286 | Scol. De plus, ce test permet de ne pas l'oublier .... |
||
287 | |||
288 | En étudiant le code existant, la "ruse" suivante est souvent utilisée : tous |
||
289 | les arguments envoyés par la fonction Scol sont dépilés (MMpull) excepté le dernier |
||
290 | (qui est donc le prmier argument dans la fonction Scol). Remarquez que ce premier |
||
291 | argument est le canal. Ainsi, alors qu'on a utilisé MMpull pour les autres arguments, |
||
292 | l'utilisation de MMget (m, 0) pour tester le canal permet de le garder à l'étage 0. |
||
293 | Ensuite, grâce au MMpush sur le pointeur, il remonte à l'étage 1 ...:) Ceci dit, |
||
294 | cette technique n'est pas toujours faisable et nous ne l'appliquerons pas. |
||
295 | |||
296 | h4. Ajouter une callback à un objet Scol |
||
297 | |||
298 | Lorsqu'on crée un objet Scol, il est généralement utile de lui associer une |
||
299 | ou plusieurs fonctions réflexes pour traiter des évènements. |
||
300 | |||
301 | Cela passe par _OBJaddreflex_ avec ses trois arguments : la machine Scol, |
||
302 | la variable qui contient le type Scol et un flag spécifique à votre callback. |
||
303 | Ce flag, vous le définissez vous-même et sa valeur devrait être inférieure au nombre |
||
304 | total de callbacks définis pour ce type Scol (voir plus haut la création d'un type |
||
305 | Scol avec _OBJregister_). Dans un exemple donné lui aussi plus haut, nous |
||
306 | avions défini 4 callbacks pour un type Scol (création, destruction, affectation et |
||
307 | récupération). Nous pourrions alors définir (via un simple <code>#define</code>) |
||
308 | la valeur 0 pour la création, 1 pour la destruction, 2 pour l'affectation et 3 |
||
309 | pour la récupération. |
||
310 | |||
311 | La configuration de la callback se fait donc en amont de cet appel, par |
||
312 | empilement ou affectation dans la pile. Nous avons vu tout à l'heure la position |
||
313 | du canal dans la pile lors de la création d'un objet. C'est un peu la même chose ici. |
||
314 | À l'étage 2 doit se trouver l'objet de type Scol, |
||
315 | À l'étage 1 doit se trouver la référence à la callback (le _@myCallback_ |
||
316 | dans les arguments de la fonction Scol),<br /> |
||
317 | À l'étage 0 doit se trouver le paramètre utilisateur, laissé à la discrétion du |
||
318 | programmeur Scol. |
||
319 | Là encore, si nécessaire, usez de la fonction MMset ou de la macro INVERT. |
||
320 | |||
321 | Par exemple, soit la fonction Scol <em>_CBfunction</em> qui demande en argument : |
||
322 | l'objet d'un type A, une fonction callback et un paramètre utilisateur. C'est un cas |
||
323 | fréquent dans l'API Scol. Nous avons en langage Scol : |
||
324 | |||
325 | <pre>typeof objA = A;; |
||
326 | ... |
||
327 | _CBfunction objA @cbA "toto"; |
||
328 | ...</pre></code> |
||
329 | Le pseudo-code C correspondant à _CBfunction : |
||
330 | <code><pre>CBfunction (mmachine m) |
||
331 | { |
||
332 | int mobj; |
||
333 | mobj = MTOP (MMget (m, 2)); |
||
334 | if (mobj == NIL) |
||
335 | return 0 |
||
336 | OBJaddreflex (m, typeA, FLAG_CB_TYPE_A); |
||
337 | return 0; |
||
338 | }</pre> |
||
339 | |||
340 | h4. Appeler une callback d'un objet Scol |
||
341 | |||
342 | Avant d'appeler une telle callback, il convient de s'assurer qu'elle existe ! |
||
343 | Si tel est le cas, elle est "préparée" à être exécutée puis enfin lancée. |
||
344 | |||
345 | Pour tester sa présence et la préparer éventuellement, _OBJbeginreflex_ est prévue. |
||
346 | Elle attend quatre argument : la machine Scol, la variable contenant le type objet |
||
347 | concerné, le pointeur système et le flag qui a servi à l'ajouter (voir ci-dessus). |
||
348 | Les premier, second et quatrième arguments sont aisément accessibles. |
||
349 | Le troisième, le pointeur système de l'objet Scol, est parfois plus retors. On |
||
350 | peut faire en sorte qu'il soit inclus dans la pile, à une position connue. Ce |
||
351 | n'est cependant pas toujours réalisable lorsqu'une bibliothèque tierce gère les |
||
352 | évènements de l'objet. Plusieurs méthodes s'offrent à vous ; nous emploierons ici |
||
353 | une structure qui le contiendra et qui sera passé en paramètre de la fonction tierce. |
||
354 | |||
355 | _OBJbeginreflex_ doit retourner 0 en cas de succès. N'oubliez donc pas de tester |
||
356 | son retour. |
||
357 | |||
358 | <pre>int cb = 0; |
||
359 | cb = OBJbeginreflex (m, MyObjectType, (int) handle_sys, FLAG_CB_TYPE_A); |
||
360 | if (cb) /* pas de callback définie dans le script Scol */ |
||
361 | return 0;</pre> |
||
362 | |||
363 | Une fois la callback préparée, il ne reste plus qu'à l'appeler avec <em>OBJcallreflex</em>. |
||
364 | Celle-ci ne prend que deux arguments : la machine Scol et le nombre de paramètres |
||
365 | supplémentaires de la callback. |
||
366 | |||
367 | h5. Arguments ? |
||
368 | |||
369 | Que sont ces paramètres supplémentaires de la callback ? |
||
370 | |||
371 | Toutes les callbacks Scol ont au moins deux arguments : l'objet Scol sur lequel |
||
372 | l'évènement a été généré et le paramètre utilisateur, paramètre à la convenance |
||
373 | du développeur Scol. |
||
374 | Il est tout à fait possible de donner au programmeur Scol d'autres paramètres. |
||
375 | Par exemple, lors d'un clic sur un objet Scol graphique, il est probablement |
||
376 | intéressant non seulement de fournir les deux paramètres cités mais aussi d'y adjoindre |
||
377 | les coordonnées du clic, du bouton de la souris qui a été cliqué, etc. Ce sont ça |
||
378 | les <em>paramètres supplémentaires</em>. |
||
379 | |||
380 | Reprenons notre exemple de clic dans un élément graphique. Nous désirons joindre |
||
381 | les coordonnées du clic (x, y), le bouton de souris (button) et la touche de clavier |
||
382 | éventuellement appuyée (mask). Nous pouvons décider que chacune de ces informations |
||
383 | correspondra à un argument de la callback : x y button mask. Cela fera donc 4 paramètres |
||
384 | supplémentaires. Nous pouvons aussi décider de grouper les coordonnées en un seul argument |
||
385 | pour former un tuple : [x y] button mask. Cela fera donc 3 arguments supplémentaires. |
||
386 | Ou encore de les regrouper tous en un seul tuple : [[x y] button mask]. Cela fera |
||
387 | 1 argument supplémentaire. |
||
388 | |||
389 | Bien entendu, il peut très bien n'y avoir aucun paramètres supplémentaires à |
||
390 | transmettre et nous noterons, dans ce cas, 0. |
||
391 | |||
392 | Ces fameux paramètres doivent être connus de la pile Scol lors de l'appel à |
||
393 | _OBJcallreflex_. Vous devez donc, si ce n'est déjà fait, les empiler au |
||
394 | préalable. Cela se code de la façon habituelle (MMpush avec construction de |
||
395 | tuple(s) ou de liste(s) éventuel(s)). Cet empliment doit se faire dans l'ordre |
||
396 | des arguments de la callback. |
||
397 | |||
398 | Avec notre exemple précédent : |
||
399 | <pre>int cb; |
||
400 | cb = OBJbeginreflex (m, MyObjectType, (int) handle_sys, FLAG_CB_TYPE_A); |
||
401 | if (cb) |
||
402 | { |
||
403 | MMechostr ("No callback ...n"); |
||
404 | MMpush (m, NIL); |
||
405 | return 0; |
||
406 | } |
||
407 | MMpush (m, ITOM (x)); |
||
408 | MMpush (m, ITOM (y)); |
||
409 | MMpush (m, ITOM (button)); |
||
410 | MMpush (m, ITOM (mask)); |
||
411 | OBJcallreflex (m, 4);</pre> |
||
412 | |||
413 | donnera un prototype Scol : <code>fun [ObjTypeA u0 I I I I] u1</code> |
||
414 | ou |
||
415 | |||
416 | <pre>int cb; |
||
417 | cb = OBJbeginreflex (m, MyObjectType, (int) handle_sys, FLAG_CB_TYPE_A); |
||
418 | if (cb) |
||
419 | { |
||
420 | MMechostr ("No callback ...n"); |
||
421 | MMpush (m, NIL); |
||
422 | return 0; |
||
423 | } |
||
424 | MMpush (m, ITOM (x)); |
||
425 | MMpush (m, ITOM (y)); |
||
426 | MMpush (m, ITOM (2)); |
||
427 | MBdeftab (m); |
||
428 | MMpush (m, ITOM (button)); |
||
429 | MMpush (m, ITOM (mask)); |
||
430 | OBJcallreflex (m, 3);</pre>< |
||
431 | |||
432 | donnera un prototype Scol : <code>fun [ObjTypeA u0 [I I] I I] u1</code> |
||
433 | ou encore |
||
434 | |||
435 | <pre>int cb; |
||
436 | cb = OBJbeginreflex (m, MyObjectType, (int) handle_sys, FLAG_CB_TYPE_A); |
||
437 | if (cb) |
||
438 | { |
||
439 | MMechostr ("No callback ...n"); |
||
440 | MMpush (m, NIL); |
||
441 | return 0; |
||
442 | } |
||
443 | MMpush (m, ITOM (x)); |
||
444 | MMpush (m, ITOM (y)); |
||
445 | MMpush (m, ITOM (button)); |
||
446 | MMpush (m, ITOM (mask)); |
||
447 | MMpush (m, ITOM (4)); |
||
448 | MBdeftab (m); |
||
449 | OBJcallreflex (m, 1);</pre> |
||
450 | |||
451 | donnera un prototype Scol : <code>fun [ObjTypeA u0 [I I I I]] u1</code> |
||
452 | |||
453 | h4. Détruire un objet Scol |
||
454 | |||
455 | Lors de la création d'un nouveau type, nous avons codé une callback de destruction. |
||
456 | Cette dernière sera appelée à chaque objet de ce type détruit. Mais comment détruire |
||
457 | un tel objet une fois que le programmeur Scol n'en a plus besoin ? |
||
458 | |||
459 | C'est très simple. La fonction _OBJdelTM_ est faîte pour ça ! Elle prend |
||
460 | 3 arguments : la machine Scol, le flag utilisé lors de la création (étape de stockage |
||
461 | avec _MMstore_) et le pointeur Scol de l'objet (c'est bien le pointeur |
||
462 | Scol et non le pointeur système qui est attendu). |
||
463 | |||
464 | Généralement, les fonctions Scol de destruction ne prennent qu'un seul argument : |
||
465 | l'objet à détruire. Le code minimal est alors : |
||
466 | |||
467 | <pre>int obj; |
||
468 | obj = MTOP (MMpull (m)); |
||
469 | if (obj == NIL) |
||
470 | { |
||
471 | MMechostr ("Object already destroyedn"); |
||
472 | MMpush (m, NIL); |
||
473 | return 0; |
||
474 | } |
||
475 | OBJdelTM (m, OBJTYPE_C_HANDLE, PTOM (obj)); |
||
476 | MMpush (m, 0); |
||
477 | return 0;</pre> |
||
478 | |||
479 | h2. Code source complet |
||
480 | |||
481 | Il est trop long pour être écrit sur cette page déjà ... longue ! Veuillez donc |
||
482 | vous reporter à l'archive associée à ce tutoriel (en haut de page). |
||
483 | |||
484 | Si vous souhaitez le compiler, n'oubliez pas d'indiquer à votre compilateur les |
||
485 | headers de libcurl et de linker vers les librairies de libcurl. Le linkage peut |
||
486 | se faire simplement avec un <code>-lcurl</code>. |
||
487 | "Curl-config":http://curl.haxx.se/libcurl/using/curl-config.html peut |
||
488 | vous apporter une aide précieuse. |
||
489 | |||
490 | À l'exécution, si vous avez décidé de ne pas inclure libcurl à votre bibliothèque, |
||
491 | il faudra avoir préalablement installé les binaires libcurl sur la machine de test. |
||
492 | Sous GNU/Linux, l'installation du paquet libcurl de votre distribution est |
||
493 | suffisante. Pour MS Windows, les quatre dll suivantes sont requises pour tester |
||
494 | cet exemple (mais si vous rajoutez des fonctionalités, d'autres pourront être |
||
495 | nécessaires) : libcurl.dll, libeay32.dll (ou 64 sur 64 bits), libidn-11.dll, |
||
496 | libssl32.dll (64 sur 64 bits). |
||
497 | |||
498 | h2. Exemple de code Scol</h2> |
||
499 | |||
500 | <pre>typeof w_file = W;; |
||
501 | |||
502 | fun cbNewUrl (objCurl, user_param, data_received, size_data, url, error)= |
||
503 | _appendpack data w_file; |
||
504 | _fooS user_param; |
||
505 | 0;; |
||
506 | |||
507 | fun main ()= |
||
508 | _showconsole; |
||
509 | |||
510 | set w_file = _getmodifypack "tests/seeks.txt"; |
||
511 | example_getFile |
||
512 | "http://www.seeks.fr/" |
||
513 | w_file; |
||
514 | |||
515 | _fooS "example_getFile : ok !"; |
||
516 | |||
517 | example_newUrl |
||
518 | _channel |
||
519 | "http://www.seeks.fr/search?q=irizone&expansion=1&action=expand" |
||
520 | nil |
||
521 | @cbNewUrl |
||
522 | "Youpi !!"; |
||
523 | |||
524 | _fooS "example_newUrl : ok !"; |
||
525 | 0;; |
||
526 | </pre> |
||
527 |