fopencookie(3) | Library Functions Manual | fopencookie(3) |
fopencookie - Ouvrir un flux particulier
Bibliothèque C standard (libc, -lc)
#define _GNU_SOURCE /* Consultez feature_test_macros(7) */ #include <stdio.h>
FILE *fopencookie(void *restrict cookie, const char *restrict mode, cookie_io_functions_t io_funcs);
La fonction fopencookie() permet au programmeur de créer des implémentations particulières de flux d'entrées-sorties. Cette implémentation peut sauvegarder les flux de données dans une location choisie. Par exemple, fopencookie() est utilisée pour implémenter fmemopen(3), qui fournit une interface qui sauvegarde les flux de données dans un tampon en mémoire.
Pour créer un flux particulier, le programmeur doit :
La fonction fopencookie() effectue une tâche similaire à celle de fopen(3) : elle ouvre un nouveau flux et renvoie un pointeur vers un objet FILE utilisé pour manipuler le flux.
L'argument cookie est un pointeur vers la structure cookie appelante qui est associée au nouveau flux. Ce pointeur est passé en premier argument lorsque les bibliothèques d'E/S standard appellent une des fonctions de hook.
L'argument mode a le même sens que pour fopen(3). Les modes suivants sont gérés : r, w, a, r+, w+ et a+. Consultez fopen(3) pour plus de détails.
L'argument io_funcs est une structure qui contient quatre champs pointant vers les fonctions de « hook » définies par le programmeur qui seront utilisées dans l'implémentation du flux. La structure est définie comme suit :
typedef struct { cookie_read_function_t *read; cookie_write_function_t *write; cookie_seek_function_t *seek; cookie_close_function_t *close; } cookie_io_functions_t;
Les quatre membres sont définis comme suit :
ssize_t read(void *cookie, char *buf, size_t size);
ssize_t write(void *cookie, const char *buf, size_t size);
int seek(void *cookie, off64_t *offset, int whence);
int close(void *cookie);
En cas de succès, fopencookie() renvoie un pointeur sur le nouveau flux. En cas d'erreur, NULL est renvoyé.
Pour une explication des termes utilisés dans cette section, consulter attributes(7).
Interface | Attribut | Valeur |
fopencookie() | Sécurité des threads | MT-Safe |
Cette fonction est une extension GNU non standard.
Le programme ci-dessous implémente un flux particulier dont la fonctionnalité est similaire (mais non identique) à celle de fmemopen(3). Il implémente un flux dont les données sont sauvegardées dans un tampon. Le programme écrit les options de sa ligne de commande dans le flux et se positionne dans le flux afin de lire 2 caractères sur 5 et les écrit sur la sortie standard. La session shell suivante explique comment utiliser ce programme.
$ ./a.out 'hello world' /he/ / w/ /d/ Reached end of file
Notez qu'une version plus générique et plus robuste du programme ci-dessous, avec une gestion des erreurs pourrait être implémenté (par exemple, l'ouverture d'un flux avec un cookie en cours d'utilisation par un autre flux ; la fermeture d'un flux déjà fermé).
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #define INIT_BUF_SIZE 4 struct memfile_cookie { char *buf; /* Dynamically sized buffer for data */ size_t allocated; /* Size of buf */ size_t endpos; /* Number of characters in buf */ off_t offset; /* Current file offset in buf */ }; ssize_t memfile_write(void *c, const char *buf, size_t size) { char *new_buff; struct memfile_cookie *cookie = c; /* Buffer too small? Keep doubling size until big enough. */ while (size + cookie->offset > cookie->allocated) { new_buff = realloc(cookie->buf, cookie->allocated * 2); if (new_buff == NULL) return -1; cookie->allocated *= 2; cookie->buf = new_buff; } memcpy(cookie->buf + cookie->offset, buf, size); cookie->offset += size; if (cookie->offset > cookie->endpos) cookie->endpos = cookie->offset; return size; } ssize_t memfile_read(void *c, char *buf, size_t size) { ssize_t xbytes; struct memfile_cookie *cookie = c; /* Fetch minimum of bytes requested and bytes available. */ xbytes = size; if (cookie->offset + size > cookie->endpos) xbytes = cookie->endpos - cookie->offset; if (xbytes < 0) /* offset may be past endpos */ xbytes = 0; memcpy(buf, cookie->buf + cookie->offset, xbytes); cookie->offset += xbytes; return xbytes; } int memfile_seek(void *c, off64_t *offset, int whence) { off64_t new_offset; struct memfile_cookie *cookie = c; if (whence == SEEK_SET) new_offset = *offset; else if (whence == SEEK_END) new_offset = cookie->endpos + *offset; else if (whence == SEEK_CUR) new_offset = cookie->offset + *offset; else return -1; if (new_offset < 0) return -1; cookie->offset = new_offset; *offset = new_offset; return 0; } int memfile_close(void *c) { struct memfile_cookie *cookie = c; free(cookie->buf); cookie->allocated = 0; cookie->buf = NULL; return 0; } int main(int argc, char *argv[]) { cookie_io_functions_t memfile_func = { .read = memfile_read, .write = memfile_write, .seek = memfile_seek, .close = memfile_close }; FILE *stream; struct memfile_cookie mycookie; size_t nread; char buf[1000]; /* Set up the cookie before calling fopencookie(). */ mycookie.buf = malloc(INIT_BUF_SIZE); if (mycookie.buf == NULL) { perror("malloc"); exit(EXIT_FAILURE); } mycookie.allocated = INIT_BUF_SIZE; mycookie.offset = 0; mycookie.endpos = 0; stream = fopencookie(&mycookie, "w+", memfile_func); if (stream == NULL) { perror("fopencookie"); exit(EXIT_FAILURE); } /* Write command-line arguments to our file. */ for (size_t j = 1; j < argc; j++) if (fputs(argv[j], stream) == EOF) { perror("fputs"); exit(EXIT_FAILURE); } /* Read two bytes out of every five, until EOF. */ for (long p = 0; ; p += 5) { if (fseek(stream, p, SEEK_SET) == -1) { perror("fseek"); exit(EXIT_FAILURE); } nread = fread(buf, 1, 2, stream); if (nread == 0) { if (ferror(stream) != 0) { fprintf(stderr, "fread failed\n"); exit(EXIT_FAILURE); } printf("Reached end of file\n"); break; } printf("/%.*s/\n", (int) nread, buf); } free(mycookie.buf); exit(EXIT_SUCCESS); }
fclose(3), fmemopen(3), fopen(3), fseek(3)
La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org> et Frédéric Hantrais <fhantrais@gmail.com>
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.
5 février 2023 | Pages du manuel de Linux 6.03 |