Librairie Apr : tutoriels 8 et 9
8. gestion des chaines de caractères
Je suppose que vous connaissez les bases de manipulation de chaine en C, notamment les fonctions strlen(3) et strcpy(3). La librairie libapr propose des fonctions extrêmement utiles de gestion des chaines. Elles sont pratiquement les mêmes que leur équivalent en ANSI C. Pourquoi libapr fournit encore une autre possibilité de gestion de chaines ? L’intérêt est directement lié avec le principe de gestion par pool mémoire. Dans une gestion habituelle de chaine en C, il faut écrire du code de gestion de mémoire : allocation, libération, etc. Le code qui suit en est l’exemple.
/* exemple de manipulation de chaine ANSI C */ /* (code simpliste) */ /* on concatène 3 chaines : s1, s2, s3 */ int len1 = strlen(s1); int len2 = strlen(s2); int len3 = strlen(s3); int total_len = len1 + len2 + len3; char *cat_str = malloc(total_len + 1); strcpy(cat_str, s1); strcat(cat_str, s2); strcat(cat_str, s3); /* plus tard, il nous faut libérer la mémoire allouée */ free(cat_str);
La même chose avec la librairie libapr s’écrira ainsi :
/* pseudo code sur la gestion des chaines de libapr */ apr_pool_t *mp; apr_pool_create(&mp, NULL); /* apr_pstrcat() gère à la fois l'allocation * mémoire et la concaténation des chaines * Si la chaine concaténée est en lecture seule, * il nous faut utiliser le type 'const char*'. */ const char *cat_str = apr_pstrcat(mp, s1, s2, s3, NULL); /* plus tard, la seule chose à faire * est de détuire le pool mémoire * pour tout libérer */ apr_pool_destroy(mp);
De la même façon que apr_pstrcat(), apr_psprintf() vous aide à écrire un code beaucoup plus simple. Vous trouvez d’autres fonctions sur les chaines dans apr_strings.h.
9. Gestion de de l’heure
Les fonctions mises à disposition par libapr sont basées sur le schéma POSIX. Une valeur de type apr_time_t représente le temps écoulé depuis une époque UNIX c’est à dire depuis le 1/1/1970. Seulement il y a deux différences de taille :
- apr_time_t est géré sur 64 bits (long long)
- apr_time_t réprésente des microsecondes
La fonction la plus utile est apr_time_now(). Comme vous l’imaginez, elle renvoie la date et l’heure courante. Vous trouverez sa déclaration dans apr_time.h.
/* extrait de apr_time.h */ APR_DECLARE(apr_time_t) apr_time_now(void);
Très souvent nous avons à convertir une valeur apr_time_t dans d’autres formats. Il y a principalement deux formats qui vous seront utiles :
- Une structure temps : apr_time_exp_t (time structure)
- Les formats exprimant les dates sous forme de chaines (p.ex. la rfc822)
Pour convertir apr_time_t en une structure apr_time_exp_t, il faut utiliser les fonctions de la libapr suivantes :
/* extrait de apr_time.h */ APR_DECLARE(apr_status_t) apr_time_exp_gmt( apr_time_exp_t *result, apr_time_t input); APR_DECLARE(apr_status_t) apr_time_exp_lt( apr_time_exp_t *result, apr_time_t input);
La fonction apr_time_exp_gmt() renvoie le résultat qui est dans une zone GMT, et apr_time_exp_lt() renvoie le résultat en se basant sur la zone de temps locale. Le premier argument des deux fonctions est un argument résultat.
Il est possible de faire la conversion dans l’autre sens : convertir une structure apr_time_exp_t en une valeur apr_time_t.
/* extrait de apr_time.h */ APR_DECLARE(apr_status_t) apr_time_exp_get( apr_time_t *result, apr_time_exp_t *input);
Il y a plusieurs fonctions pour convertir une valeur apr_time_t en différents formats de chaines représentant une date / heure :
/* extrait de apr_time.h */ APR_DECLARE(apr_status_t) apr_rfc822_date( char *date_str, apr_time_t t); APR_DECLARE(apr_status_t) apr_ctime( char *date_str, apr_time_t t); APR_DECLARE(apr_status_t) apr_strftime( char *s, apr_size_t *retsize, apr_size_t max, const char *format, apr_time_exp_t *tm);
A l’inverse, si on a des chaines dans ces formats, et qu’on veut les convertir en une valeur apr_time_t, il faut appeler des fonctions utilitaires de apr-util (un sous ensemble de la libapr), définis dans apr_date.h.
Regardez l’exemple de time-sample.c pour avoir un exemple concret de l’utilisation de ces fonctions.
REMARQUE : Comme expliqué juste avant, apr_time_t est un type long long (64 bits). Notez bien que le code suivant déclenchera un débordement.
/* Exemple BOGUE. Génération de débordement */ const apr_time_t UNE_HEURE = 1000 * 1000 * 60 * 60;
On le résoud en faisant une conversion de type explicite, mais je vous recommande d’utiliser simplement le type que fournit la librairie libapr. Le code suivant le montre.
/* deux exemples pour contourner * le débordement expliqué juste avant */ const apr_time_t UNE_HEURE = APR_TIME_C(1000) * 1000 * 60 * 60;
ou bien :
const apr_time_t UNE_HEURE = APR_USEC_PER_SEC * 60 * 60;
REMARQUE : Parfois, souvent en déboguant, on veut afficher des valeurs de temps en clair. Malheureusement, Unix et Windows ont des manière différentes de spécifier le type 64 bits quand on se sert de printf(3). Sur Unix c’est “%lld” est sur Windows c’est “%I64d”. Pour de tels problèmes de portabilité, la librairie libapr fournit des spécificateurs de format, p.ex. APR_INT64_T_FMT. Il y a aussi APR_TIME_T_FMT dans apr_time.h. On peut écrire du code parfaitement portable en utilisant ces spécificateurs.
/* Sur Unix, APR_INT64_T_FMT est défini dans apr.h */ #define APR_INT64_T_FMT "lld" /* Sur Windows, APR_INT64_T_FMT est défini dans apr.h */ #define APR_INT64_T_FMT "I64d"
/* extrait de apr_time.h */ #define APR_TIME_T_FMT APR_INT64_T_FMT
/* On peut utiliser APR_TIME_T_FMT de cette façon : */ printf("L'heure courante est : %" APR_TIME_T_FMT "[us]\n", apr_time_now());