Librairie Apr : tutoriels 10 et 11
10. Options de la ligne de commande
Pour les outils en ligne de commande (CLI, Command Line Interface), les options qu’on donne en ligne de commandes sont souvent utilisées. La librairie libapr met des fonctions à disposition qui facilitent grandement la gestion des options fournies en ligne de commande. Voici un extrat de getopt-sample.c.
/* extrait de getopt-sample.c */ static const apr_getopt_option_t opt_option[] = { /* énumération comme suit : * {opt. longue}, {opt. courte}, * {flag "argument qui suit"}, {description} : */ /* -i nomfichier or --in nomfichier : */ { "in", 'i', TRUE, "fichier entrant" }, /* -o nomfichier or --out nomfichier : */ { "out", 'o', TRUE, "fichier sortant" }, /* -h or --help : */ { "help", 'h', FALSE, "voir l'aide" }, /* sentinelle de fin : */ { NULL, 0, 0, NULL }, };
En premier lieu, il faut fournir un tableau d’éléments apr_getopt_option_t. On l’appelle (ici) option-list. Chaque élément a quatre variables :
- une option longue ;
- une option courte ;
- un flag “argument qui suit”, pour préciser si cette option nécessite un argument qui doit la suivre ;
- une description.
Par exemple, pour l’option “help” :
- Une option longue : ‘–help’ :
- Une option courte : ‘-h’.
Les options courtes sont obligatoires et les options longues sont optionnelles. On peut tout à fait mettre NULL pour une option longue. La troisième variable précise si un argument supplémentaire doit suivre cette option. Par exemple si une option de ligne de commande fonctionne ainsi ‘–in nomfichier’, c’est à dire qu’il faut obligatoirement préciser un nom de fichier, il faut mettre ce flag à vrai (TRUE). Ainsi, si le programme est exécuté et qu’on donne cette option sans donner un argument, par exemple ‘./a.out -in’, une erreur est levée.
Enfin, le tableau de la liste des options doit se terminer par une sentinelle vide qui précise que la liste est finie (voir l’exemple précédent).
Pour parcourir les options fournies dans la ligne de commande, if faut tout d’abord initialiser le parser en appelant ‘apr_getopt_init()’ (pour initialiser un objet apr_getopt_t) puis faire une boucle en s’aidant du tableau des options. Ensuite, on appelle en boucle apr_getopt_long() tant qu’il renvoie APR_SUCCESS. Voici un extrait de getopt-sample.c :
/* extrait de getopt-sample.c */ /* initialiser apr_getopt_t */ apr_getopt_t *opt; apr_getopt_init(&opt, mp, argc, argv); /* parcourir toutes les options via opt_option[] */ while ((rv = apr_getopt_long(opt,opt_option, &optch, &optarg)) == APR_SUCCESS) { ...etc.
Dans la boucle, apr_getopt_long() enumère les options passées en ligne de commande une par une. Si l’option trouvée fait partie de la liste des options, apr_getopt_long() renvoie APR_SUCCESS et initialise la valeur de optch en conséquence. Si l’option a un argument supplémentaire apr_getopt_long() le lit et initialise la valeur de optarg.
Voyons un exemple concret. Imaginons que vous lanciez le programme en y ajoutant une option et une valeur associée : ‘./getopt-sample -h -i foo.txt’. Lors de la première boucle, apr_getopt_long() trouve ‘h’ dans la liste des option. Donc, apr_getopt_long() renvoie APR_SUCCESS et initialise optch avec la valeur ‘h’. Sur la boucle suivante, apr_getopt_long() trouve ‘i’ dans la liste des options, et comme ‘i’ nécessite un argument qui doit le suivre, il y a lecture de l’argument suivant, ‘foo.txt’. Ainsi, apr_getopt_long() renvoie APR_SUCCESS, avec optch qui vaut ‘i’ et optarg qui vaut “foo.txt”. Lors de la boucle suivante, apr_getopt_long() ne trouve plus d’options et renvoie par conséquent APR_EOF.
11. memory map (mmap)
mmap signifie “mapping mémoire”. Ce qui veut dire “mapper” des fichiers en mémoire. mmap est principalement utilisé pour :
- Lire/écrire dans des fichiers le plus rapidement possible ;
- Allouer un espace mémoire consécutif plus gros (gestion spécifique à chaque système d’exploitation) ;
- Partage mémoire entre différents processus.
Pensez au cas où vous voulez lire un fichier en entier en une fois. Dans ce cas il faut faire un buffer, lire du début jusqu’à la fin dans une boucle. Le code ressemblerait à cela :
/* code simpliste pour lire le contenu d'un fichier */ apr_file_t *fp; apr_file_open(&fp, filename, APR_READ, APR_OS_DEFAULT, mp); while (1) { char buf[1024]; apr_size_t len = sizeof(buf); rv = apr_file_read(fp, buf, &len); if (rv != APR_SUCCESS) { break; } /* scan buf */ } apr_file_close(fp);
On peut faire mieux, avec apr_mmap_t :
/* extrait de mmap-sample.c, vérif. des erreurs omise */ apr_file_open(&fp, filename, APR_READ, APR_OS_DEFAULT, mp); apr_finfo_t finfo; apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); apr_mmap_t *mmap; apr_mmap_create(&mmap, fp, 0, finfo.size, APR_MMAP_READ, mp); /* scan mmap->mm */ apr_mmap_delete(mmap);
Si le fichier est suffisamment gros, le code basé sur mmap sera plus rapide.
Plus important encore, mmap aide à éviter la fragmentation mémoire. La plupart des systèmes (qui doivent gérer les allocations mémoire) se trouvent confronté au problème de fragmentation mémoire, mais mmap n’entre pas dans le cadre d’allocation mémoire dans l’espace utilisateur. Malheureusement, sur certains systèmes, mmap est parfois lent et bogué.
On peut utiliser mmap pour modifier des fichiers. On ouvre le fichier avec APR_WRITE, puis on “mmap” le fichier en précisant le flag APR_MMAP_WRITE.
REMARQUE : Il est interdit de “mmap-er” un fichier ouvert avec le flag APR_BUFFERED. Le code suivant renverra toujours l’erreur APR_EBADF :
/* Exemple mmap BOGUE */ apr_file_t *fp; apr_mmap_t *mm; apr_file_open(&fp, fname, APR_READ|APR_BUFFERED, APR_OS_DEFAULT, mp); rv = apr_mmap_create(&mm, fp, 0, finfo.size, APR_MMAP_READ, mp); /* BOGUE : le résultat sera TOUJOURS : * rv==APR_EBADF */