Référence du fichier functions.c

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.

Description détaillée

code interne des fonctions Scol contient le code interne des fonctions de l'API Scol

Auteur:
iri <iri-@-irizone.net>
Date:
novembre 2010

Définition dans le fichier functions.c.


Documentation des fonctions

int sc_delGetUrl ( mmachine  m  ) 

Destruction explicite d'un objet Scol.

Paramètres:
structure mmachine
Renvoie:
int 0 (or NIL)

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.

Paramètres:
struct mmachine
Renvoie:
0

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.

Paramètres:
struct mmachine
Renvoie:
0

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 :

  • la création d'objet de type Scol
  • la définition d'une fonction réflexe Scol

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 :

  • création de l'objet en C ou en C++ selon les cas
  • allocation de émmoire pour l'objet au sein de la VM (MMalloc)
  • stockage de l'objet (MMstore)
  • empilement pour le retour de la fonction Scol (MMpush)
  • creation de l'objet Scol (OBJcreate)

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 machine Scol en cours,
  • le type Scol de l'objet,
  • un flag spécifique à la callback

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 :

  • le canal
  • l'url
  • un paramètre non traité ici mais qui pourrait être un header pour la requête par exemple
  • une callback
  • un paramètre utilisateur utilisée dans la callback

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 :

  • l'objet de type ObjCurl dont dépend la callback,
  • le paramètre utilisateur,
  • le paquet de données reçu,
  • la taille du paquet reçu,
  • l'url d'origine,
  • le message d'erreur éventuel de libcurl.

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).

Paramètres:
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
Renvoie:
la taille total du paquet reçu (ou -1 pour stopper la transaction)

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 :

  • l'objet Scol appelant;
  • le paramètre utilisateur, laissé à la discrétion du programmeur Scol

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.

Paramètres:
structstrExample 
Renvoie:
(void)

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 }

Généré le Sat Nov 20 23:18:18 2010 pour example par  doxygen 1.6.3