code interne des fonctions Scol contient le code interne des fonctions de l'API Scol Plus de détails...
Aller au code source de ce fichier.
Fonctions | |
int | sc_getFile (mmachine m) |
Récupère un fichier sur le net et l'enregistre localement. | |
void | sc_newUrlCBend (struct StrExample *strEx) |
Callback interne appelée lorsque le trnasfert de données est terminé après un appel à sc_newGetUrl. | |
size_t | sc_newUrlCB (void *ptr, size_t size, size_t nmemb, void *p_strEx) |
Callback interne appelée lorsque le transfert est en cours (à chaque paquet reçu). | |
int | sc_newGetUrl (mmachine m) |
Code interne de la fonction Scol example_newUrl. | |
int | sc_delGetUrl (mmachine m) |
Destruction explicite d'un objet Scol. |
code interne des fonctions Scol contient le code interne des fonctions de l'API Scol
Définition dans le fichier functions.c.
int sc_delGetUrl | ( | mmachine | m | ) |
Destruction explicite d'un objet Scol.
structure | mmachine |
Cettedestruction, après le test sur la validité de l'objet, consiste à appeler la fonction OBJdelTM en lui passant le handle Scol en argument. C'est tout.
Définition à la ligne 450 du fichier functions.c.
00451 { 00452 int obj; 00453 00454 MMechostr (MSKDEBUG, "sc_delGetUrl entering ...\n"); 00455 00456 /* On récupère l'objet et on le teste */ 00457 obj = MTOP (MMget (m, 0)); 00458 if (obj == NIL) 00459 { 00460 MMechostr (MSKDEBUG, "sc_delGetUrl : object aleady destroyed\n"); 00461 MMset (m, 0, NIL); 00462 return 0; 00463 } 00464 00465 /* On utilise la fonctiond e conversion \a PTOM car ns avons besoin de l'objet Scol */ 00466 OBJdelTM (m, OBJCURL_HANDLE, PTOM (obj)); 00467 /* On fait retourner 0 à la fonction Scol appelante */ 00468 MMset (m, 0, 0); 00469 00470 return 0; 00471 }
int sc_getFile | ( | mmachine | m | ) |
Récupère un fichier sur le net et l'enregistre localement.
struct | mmachine |
Code interne de la fonction Scol example_getFile
On récupère les valeurs des arguments passés à la fonction Scol grâce aux fonctions habituelles. On teste leur validité.
On code normalement la partie correspondante à la bibliothèque libcurl, comme si c'était un programme C quelconque (ce qui est d'ailleurs le cas !). On n'oublie pas de libérer les ressources précédemment allouées et on retourne 0 à la fonction Scol si tout est ok.
Notez qu'en cas d'erreurs sur les arguments, la fonctions Scol renverra d'autres valeurs :
1 - si le fichier distant ou local vaut nil; 2 - si la bibliothèque libcuel n'a pu s'initialiser correctement; 3 - si le fichier local n'a pu être ouvert en écriture.
Définition à la ligne 50 du fichier functions.c.
00051 { 00052 int murl, mlocalfile, len; 00053 char * url, * localfile, * err = NULL; 00054 00055 CURL * hCurl; /* handle */ 00056 CURLcode rCurl; /* result */ 00057 FILE * fp = NULL; 00058 00059 MMechostr (MSKDEBUG, "sc_getFile : entering ...\n"); 00060 00061 mlocalfile = MTOP (MMpull (m)); 00062 murl = MTOP (MMpull (m)); 00063 00064 if ((mlocalfile == NIL) || (murl == NIL)) 00065 { 00066 MMechostr (MSKDEBUG, "sc_getFile error : url or localfile is nil\n"); 00067 MMpush (m, ITOM (1)); 00068 return 0; 00069 } 00070 00071 hCurl = curl_easy_init(); 00072 if (hCurl) /* init ok */ 00073 { 00074 len = sizeof (char) * (MMsizestr (m, mlocalfile)); 00075 localfile = (char *) malloc (len+1); 00076 strncpy (localfile, MMstartstr (m, mlocalfile), len); 00077 localfile[len] = '\0'; 00078 00079 fp = fopen (localfile, "w"); 00080 if (fp == NULL) 00081 { 00082 curl_easy_cleanup (hCurl); 00083 free (localfile); localfile = NULL; 00084 MMpush (m, ITOM (3)); 00085 return 0; 00086 } 00087 00088 err = (char *) malloc (sizeof (char) * (CURL_ERROR_SIZE +1)); 00089 len = sizeof (char) * (MMsizestr (m, murl)); 00090 url = (char *) malloc (len+1); 00091 strncpy (url, MMstartstr (m, murl), len); 00092 url[len] = '\0'; 00093 00094 curl_easy_setopt (hCurl, CURLOPT_URL, url); 00095 curl_easy_setopt (hCurl, CURLOPT_WRITEFUNCTION, fwrite); 00096 curl_easy_setopt (hCurl, CURLOPT_WRITEDATA, (FILE *) fp); 00097 curl_easy_setopt (hCurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); 00098 curl_easy_setopt (hCurl, CURLOPT_ERRORBUFFER, err); 00099 rCurl = curl_easy_perform (hCurl); 00100 00101 MMechostr (MSKDEBUG, "sc_getFile : err = %s ...\n", err); 00102 curl_easy_cleanup (hCurl); 00103 fclose (fp); 00104 00105 free (localfile); localfile = NULL; 00106 free (url); url = NULL; 00107 free (err); err = NULL; 00108 00109 MMpush (m, ITOM (0)); 00110 return 0; 00111 } 00112 00113 MMpush (m, ITOM (2)); 00114 return 0; 00115 }
int sc_newGetUrl | ( | mmachine | m | ) |
Code interne de la fonction Scol example_newUrl.
struct | mmachine |
Cette fonction propose d'envoyer une requête simple de type GET à un serveur et d'exécuter une fonction Scol spécifique (callback) à chaque réception de paquets en réponse à la requête.
Ce code présente :
Pour créer un objet Scol, il est impératif de connaître le canal sur lequel le créer. D'autres paramètres peuvent être requis suivant les cas mais le canal est le seul requis dans tous les cas. Il n'y a aucun traitement à faire au sujet du canal, c'est transparent, le traitement est fait bien en profondeur, au niveau du kernel. Cependant, le canal doit être présent dans la pile, en position 0, lors de l'appel de la fonction de création. Ceci est impératif ! Le canal doit être à l'étage 0 de la pile ! Si ce n'est pas le cas, vous devez le déplacer.
Pour créer un objet Scol, il faut tout d'abord lui allouer de la mémoire (c'est le cas le plus fréquent (si ce n'est le seul dans une pratique usuelle) d'allocation directe de mémoire d'un objet de la VM). Ce sera fait avec MMalloc avec pour argument, la machine Scol courante, la taille à allouer et le type (tableau (TYPETAB) ou buffer (TYPEBUF)) :
int objtab = MMalloc (m, sizeof (type), TYPEDEF);
Comme toute allocation, celle-ci doit être testée. On stocke alors le nouvel objet via la fonction MMstore : la machine Scol, le retour de MMalloc, un flag correspondant à l'objet et le pointeur système.
MMstore (m, objtab, OBJ_HANDLE, (int) obj_handle);
Alors, il est possible d'inclure ledit objet dans la pile afin de le retourner à la fonction appelante de création, généralement via un \æ MMpush des plus classiques.
Enfin, création de l'objet du type Scol défini, via OBJcreate qui prend en arguments : la machine Scol, le type d'objet, l'objet système, le type del'objet parent (peut être NULL) et l'objet système du parent (peut être NULL).
Récapitulatif :
Pour ajouter une fonction réflexe à un objet Scol :
Il faut un objet valide (c'est une évidence mais il convient donc de tester sa validité !); et appeler la fonction OBJaddreflex. Celle-ci prend en argument :
La fonction exemple demande une url en entrée et retourne un objet Scol de type ObjCurl en sortie. Entre temps, la fonction Scol aura également définie une callback qui sera exécutée à chaque paquet reçu. Son proptotype Scol : fun [Chn S S fun [ObjCurl u0 S I S S] u1 u0] ObjCurl
En entrée :
En retour, un nouvel objet de type ObjCurl.
La callback, dont le type est (rappel) : fun [ObjCurl u0 S I S S] u1 est ainsi définie :
Définition à la ligne 325 du fichier functions.c.
00326 { 00327 int mchannel, murl; 00328 int curltab, sizetab, tmp_res, n; 00329 CURLcode rCurl; 00330 struct StrExample strEx; 00331 00332 MMechostr (MSKDEBUG, "sc_newGetUrl : entering ...\n"); 00333 00334 memset (strEx.cerr, '\0', CURL_ERROR_SIZE); 00335 00336 /* Récupération du canal dans lequel se déroule toute notre action ! */ 00337 mchannel = MMget (m, 4); 00338 if (mchannel == NIL) 00339 { 00340 MMechostr (0, "sc_newGetUrl error : channel is nil\n"); 00341 MMpull (m); 00342 MMpush (m, NIL); 00343 return 0; 00344 } 00345 00346 /* Récupération de l'url distante */ 00347 murl = MTOP (MMget (m, 3)); 00348 if (murl == NIL) 00349 { 00350 MMechostr (0, "sc_newGetUrl error : url is nil\n"); 00351 MMpull (m); 00352 MMpush (m, NIL); 00353 return 0; 00354 } 00355 00356 /* On place le canal à l'étage 0 de la pile ! C'est IMPORTANT ! L'étage 0 (paramèter utilisateur 00357 de la callback) se retrouve en 4 on en aura besoin plus tard d'où la non-utilisation de MMset ... */ 00358 INVERT (m, 0, 4); 00359 00360 /* initialisation globale de la libcurl */ 00361 if (curl_global_init (CURL_GLOBAL_ALL) != CURLE_OK) 00362 { /* échec de l'initialisation globale, on arrête tout */ 00363 MMechostr (0, "sc_newGetUrl error : global init failed\n"); 00364 MMpull (m); 00365 MMpush (m, NIL); 00366 return 0; 00367 } 00368 00369 /* initialisation d'une session de la libcurl */ 00370 strEx.hcurl = curl_easy_init(); 00371 /* initialisation OK, on continue */ 00372 if (strEx.hcurl) 00373 { 00374 /* calcul de la taille nécessaire en mémoire pour l'objet concerné */ 00375 sizetab = sizeof (strEx.hcurl) + 1; 00376 /* allocation de la mémoire de la taille précédemment retournée */ 00377 curltab = MMmalloc (m, sizetab, TYPETAB); 00378 /* test du retour de l'allocation */ 00379 if ((curltab == NIL)) 00380 { 00381 MMechostr (0, "sc_newGetUrl error : insufficient memory\n"); 00382 curl_easy_cleanup (strEx.hcurl); 00383 MMpull (m); 00384 MMpush (m, NIL); 00385 return 0; 00386 } 00387 /* stockage de l'objet dans l'espace mémoire alloué */ 00388 MMstore (m, curltab, OBJCURL_HANDLE, (int) strEx.hcurl); 00389 /* empile de l'objet pour son utilisation en retour de la fonction Scol appelante */ 00390 MMpush (m, PTOM (curltab)); 00391 /* Création de l'objet Scol proprement dit 00392 après le MMpushprécédent, le canal se tretrouve donc en position 1 dans la pile, ce qui 00393 est ok pour l'appel de OBJcreate. Après, on aura plus besoin de connaître le canal 00394 et on pourra sacrifier l'étage 1 si besoin est */ 00395 OBJcreate (m, ObjCurl, (int) strEx.hcurl, -1, -1); 00396 00397 n = sizeof (char) * (MMsizestr (m, murl)); 00398 strEx.url = (char *) malloc (n+1); 00399 strncpy (strEx.url, MMstartstr (m, murl), n); 00400 strEx.url[n] = '\0'; 00401 00402 strEx.m2m = m; 00403 00404 /* on intervertit des étages dans la pile : 00405 l'objet session de libcurl passe à l'étage 2 00406 le paramètreutilisateur repasse en position 0, comme au départ */ 00407 INVERT (m, 0, 2); /* hCurl se retrouve en 2 */ 00408 INVERT (m, 0, 4); /* user param se retrouve en 0 */ 00409 /* On ajoute la callback définie dans le package Scol */ 00410 OBJaddreflex (m, ObjCurl, CURL_CB_GET); 00411 00412 curl_easy_setopt (strEx.hcurl, CURLOPT_URL, strEx.url); 00413 curl_easy_setopt (strEx.hcurl, CURLOPT_ERRORBUFFER, strEx.cerr); 00414 curl_easy_setopt (strEx.hcurl, CURLOPT_WRITEDATA, &strEx); 00415 curl_easy_setopt (strEx.hcurl, CURLOPT_WRITEFUNCTION, sc_newUrlCB); 00416 curl_easy_setopt (strEx.hcurl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); 00417 00418 rCurl = curl_easy_perform (strEx.hcurl); 00419 sc_newUrlCBend (&strEx); 00420 00421 curl_easy_cleanup (strEx.hcurl); 00422 curl_global_cleanup(); 00423 00424 free (strEx.url); 00425 /*free (strEx.cerr);*/ 00426 00427 return 0; 00428 } 00429 00430 /* l'initialisation a échoué */ 00431 MMechostr (0, "sc_newGetUrl error : easy init failed\n"); 00432 curl_global_cleanup(); 00433 00434 MMpull (m); 00435 MMpush (m, NIL); 00436 return 0; 00437 }
size_t sc_newUrlCB | ( | void * | ptr, | |
size_t | size, | |||
size_t | nmemb, | |||
void * | p_strEx | |||
) |
Callback interne appelée lorsque le transfert est en cours (à chaque paquet reçu).
void | * ptr : pointeur sur les dernières données reçues | |
size_t | size : taille d'un bloc | |
size_t | nmemb : nombre de blocs | |
void | * strEx : pointeur sur la structure strExample associée à la connexion |
Cette fonction va appeler la callback Scol définie lors de la demande de transfert.
Pour appeler une telle callback, il faut savoir si elle existe (si une telle fonction Scol a été définie dans l'environnement appelant) : c'est ce que va entre autres réalisée OBJbeginreflex : elle retournera 0 si c'est OK.
Cette fonction prend les arguments suivants : la machine Scol courante; l'objet Scol concerné, le pointeur objet système concerné un flag spécifique au type de callback souhaité (une même machine Scol, un objet Scol et un même objet système peuvent avoir plusieurs callbacks telles que clic, rollover, création, destruction, ...). Si tout est ok, elle retournera 0. Il est donc impératif de tester son retour.
Chaque callback Scol contient au moins deux arguments implicites dans le code interne :
Il est possible d'en ajouter d'autres. Pour cela, il est nécessaire de les empiler sur la pile courante dans l'ordre de la fonction callback Scol :
callback_Scol : objet_Scol paramètre_utilisateur paramètre_supplémentaire_1 paramètre_supplémentaire_2... paramètre_supplémentaire_n
Dans le code interne, il faudra alors empiler d'abord paramètre_supplémentaire_1 puis paramètre_supplémentaire_2 ... jusqu'à paramètre_supplémentaire_n.
Comme on a vu; l'objet_scol et le paramètre_utulisateur ne sont pas explicités dans la pile MAIS ils doivent être présents lors de la déclaration de la callback (cf commentaire de sc_newGetUrl).
Enfin, on peut appeler la fonction (si et seulement si OBJbeginreflex a retourné 0) OBJcallreflex qui elle-même demandera l'exécution de la fonction Scol correspondante.
OBJcallreflex prend deux arguments : la machine Scol courante et le nombre d'arguments supplémentaires, c'est-à-dire ceux qu'on a explicité juste avant.
Définition à la ligne 203 du fichier functions.c.
00204 { 00205 mmachine m; 00206 char * data = NULL; 00207 int cb; 00208 size_t n; 00209 struct StrExample * strEx; 00210 CURL * hCurl; 00211 00212 MMechostr (MSKDEBUG, "sc_newUrlCB : entering ...\n"); 00213 strEx = (struct StrExample *) p_strEx; 00214 00215 m = (mmachine) strEx->m2m; 00216 hCurl = (CURL *) strEx->hcurl; 00217 00218 cb = OBJbeginreflex (m, ObjCurl, (int) hCurl, CURL_CB_GET); 00219 if (cb) /* pas de callback Scol enregistré avec ces paramètres */ 00220 { 00221 MMechostr (0, "sc_newUrlCB error : no callback defined ! errcode = %d\n", cb); 00222 return -1; 00223 } 00224 00225 n = (sizeof (char) * size * nmemb); 00226 data = (char *) malloc (n+1); 00227 if (data == NULL) 00228 return -1; 00229 strncpy (data, ptr, n); 00230 data[n] = '\0'; 00231 00232 /* ajout des paramètres supplémentaires (en plus de 00233 l'objet 'ObjCurl' et du paramètre utilisateur 'u0') */ 00234 Mpushstrbloc (m, data); /* données reçues */ 00235 MMpush (m, ITOM (size*nmemb)); /* taille du paquet reçu */ 00236 Mpushstrbloc (m, strEx->url); /* url (rappel) */ 00237 Mpushstrbloc (m, strEx->cerr); /* message d'erreur éventuel de libcurl */ 00238 /* appel de la callback Scol avec 4 paramètres supplémentaires qui seront cherchés dans la pile */ 00239 OBJcallreflex (m, 4); 00240 if (data) 00241 free (data); 00242 00243 return size*nmemb; 00244 }
void sc_newUrlCBend | ( | struct StrExample * | strEx | ) |
Callback interne appelée lorsque le trnasfert de données est terminé après un appel à sc_newGetUrl.
structstrExample |
Lorsque le transfert est terminée, la callback Scol est une dernière fois appelée : aucune donnée n'est évidemment transmise; aune taille n'est tramise; l'url est transmise; l'erreur est transmise.
Comme c'est la même callback Scol qui est appelée, les 4 arguments supplémentaires sont ajoutées et la fonction Scol définie appelée (OBJcallreflex).
Définition à la ligne 133 du fichier functions.c.
00134 { 00135 mmachine m; 00136 CURL * hCurl; 00137 int cb; 00138 00139 MMechostr (MSKDEBUG, "sc_newUrlCBend : entering ...\n"); 00140 00141 m = (mmachine) strEx->m2m; 00142 hCurl = (CURL *) strEx->hcurl; 00143 00144 cb = OBJbeginreflex (m, ObjCurl, (int) hCurl, CURL_CB_GET); 00145 if (cb) 00146 { 00147 MMechostr (0, "sc_newUrlCBend error : no callback defined ! errcode = %d\n", cb); 00148 return; 00149 } 00150 00151 MMpush (m, NIL); 00152 MMpush (m, NIL); 00153 Mpushstrbloc (m, strEx->url); 00154 Mpushstrbloc (m, strEx->cerr); 00155 OBJcallreflex (m, 4); 00156 return; 00157 }