fopencookie
Table des matières
Retour à l'index
NOM
fopencookie – Ouvrir un flux particulier
BIBLIOTHÈQUE
Bibliothèque C standard (libc, -lc)
SYNOPSIS
#define _GNU_SOURCE /* Consultez feature_test_macros(7) */
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
FILE *fopencookie(void *restrict cookie, const char *restrict mode,
cookie_io_functions_t io_funcs);
DESCRIPTION
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 :
- -
-
Implémenter quatre fonctions de « hook » qui seront utilisées en interne
par la bibliothèque standard d'entrées-sorties lors d'opération d'E/S.
- -
-
Définit un type de données « cookie », une structure permettant de
sauvegarder des informations (par exemple, où sauvegarder les données)
utilisée par les fonctions de hook. Les fonctions E/S standards ne
connaissent rien à propos du contenu de ce cookie (il est passé comme un
type void * à fopencookie()) et celui-ci est automatiquement passé en
premier argument des fonctions de hook.
- -
-
Appeler fopencookie() pour ouvrir un nouveau flux et associer le cookie
et les fonctions de « hook » à ce flux.
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 :
- cookie_read_function_t *read
-
Cette fonction implémente les opérations de lecture du flux. Lorsqu'elle est
appelée, elle reçoit trois arguments.
-
ssize_t read(void *cookie, char *buf, size_t size);
-
Les argument buf et size sont respectivement, un tampon de données
pour sauvegarder les données en provenance du flux et la taille du
tampon. La fonction read renvoie le nombre d'octets copiés depuis le flux
ou -1 en cas d'erreur. La fonction read doit mettre à jour la position
dans le flux en conséquence.
-
Si *read est un pointeur NULL, alors les lectures du flux renvoient
toujours fin de fichier.
- cookie_write_function_t *write
-
Cette fonction implémente les opérations d'écriture du flux. Lorsqu'elle est
appelée, elle reçoit trois arguments :
-
ssize_t write(void *cookie, const char *buf, size_t size);
-
Les argument buf et size sont respectivement, un tampon de données à
écrire dans le flux et la taille du tampon. La fonction write renvoie le
nombre d'octets copiés depuis buf ou 0 en cas d'erreur (la fonction ne
doit pas renvoyer de valeur négative). La fonction write doit mettre à
jour la position dans le flux en conséquence.
-
Si *write est un pointeur NULL, alors les écritures dans le flux ne sont
pas réalisées.
- cookie_seek_function_t *seek
-
Cette fonction implémente les opérations de positionnement dans le
flux. Lorsqu'elle est appelée, elle prend trois arguments :
-
int seek(void *cookie, off_t *offset, int whence);
-
L'argument *offset spécifie le nouveau décalage du fichier selon les
trois valeurs suivantes fournies à whence :
-
- SEEK_SET
-
Le décalage du flux doit être défini à *offset octets après le début du
flux.
- SEEK_CUR
-
*offset doit être ajouté à l'offset actuel du flux.
- SEEK_END
-
L'offset du flux doit être défini à la taille du flux plus *offset.
-
La fonction seek doit mettre à jour *offset pour indiquer le nouvel
offset du flux avant de renvoyer.
-
La function seek devrait renvoyer 0 en cas de succès et -1 en cas
d'erreur.
-
Si *seek est un pointeur NULL, alors il est impossible de se positionner
dans le flux.
- cookie_close_function_t *close
-
Cette fonction ferme le flux. Par exemple, la fonction de hook peut
désallouer des tampons alloués pour le flux. Lorsqu'elle est appelée, elle
prend un argument :
-
int close(void *cookie);
-
L'argument cookie est le cookie que le programmeur fournit à
fopencookie().
-
La function close devrait renvoyée 0 en cas de succès et EOF en cas
d'erreur.
-
Si *close est NULL, alors aucune action n'est réalisée lorsque le flux
est fermé.
VALEUR RENVOYÉE
En cas de succès, fopencookie() renvoie un pointeur sur le nouveau
flux. En cas d'erreur, NULL est renvoyé.
ATTRIBUTS
Pour une explication des termes utilisés dans cette section, consulter
attributes(7).
| Interface | Attribut | Valeur
|
|
fopencookie()
| Sécurité des threads | MT-Safe
|
STANDARDS
GNU.
EXEMPLES
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/
Fin de fichier atteinte
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é).
Source du programme
#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, off_t *offset, int whence)
{
off_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);
}
NOTES
_FILE_OFFSET_BITS devrait être défini à 64 dans du code qui utilise une
valeur de seek non NULL ou qui prend l'adresse de fopencookie, si le
code est destiné à être portable pour les plateformes traditionelles x86 et
ARM 32 bits où la taille par défaut de off_t est 32 bits.
VOIR AUSSI
fclose(3), fmemopen(3), fopen(3), fseek(3)
TRADUCTION
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>,
Frédéric Hantrais <fhantrais@gmail.com>
et
Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>
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 à
Index
- NOM
-
- BIBLIOTHÈQUE
-
- SYNOPSIS
-
- DESCRIPTION
-
- VALEUR RENVOYÉE
-
- ATTRIBUTS
-
- STANDARDS
-
- EXEMPLES
-
- Source du programme
-
- NOTES
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 05:06:13 GMT, September 19, 2025