fopencookie(3) Library Functions Manual fopencookie(3) fopencookie - open a custom stream LIBRARY Standard C library (libc, -lc) #define _GNU_SOURCE /* See feature_test_macros(7) */ #define _FILE_OFFSET_BITS 64 #include FILE *fopencookie(void *restrict cookie, const char *restrict mode, cookie_io_functions_t io_funcs); fopencookie() -. ; , fopencookie() fmemopen(3), , . : o <<>> (hook) , - - . o Define a "cookie" data type, a structure that provides bookkeeping information (e.g., where to store data) used by the aforementioned hook functions. The standard I/O package knows nothing about the contents of this cookie (thus it is typed as void * when passed to fopencookie()), but automatically supplies the cookie as the first argument when calling the hook functions. o fopencookie() cookie . fopencookie() fopen(3): FILE, . cookie -- cookie , . , - , . mode fopen(3). : r, w, a, r+, w+ a+. fopen(3). io_funcs -- , , . 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; : cookie_read_function_t *read . : ssize_t read(void *cookie, char *buf, size_t size); buf size -- . read , buf, 0 -- -1 . read . *read null, . cookie_write_function_t *write . : ssize_t write(void *cookie, const char *buf, size_t size); buf size -- (, ). write , buf, 0 ( ). write . *write null, . cookie_seek_function_t *seek . : int seek(void *cookie, off_t *offset, int whence); *offset , whence: SEEK_SET *offset . SEEK_CUR *offset . SEEK_END *offset. seek *offset, . seek 0 -1 . *seek null, . cookie_close_function_t *close . , . : int close(void *cookie); cookie -- cookie, fopencookie(). close 0 EOF . *close NULL, . fopencookie() . NULL. attributes(7). +----------------------------+----------------------------------------------------------+--------------------------+ | | | | +----------------------------+----------------------------------------------------------+--------------------------+ |fopencookie() | | MT-Safe | +----------------------------+----------------------------------------------------------+--------------------------+ GNU. , , , ( ) , fmemopen(3). , . , , . , : $ ./a.out 'hello world' /he/ / w/ /d/ Reached end of file , , (, cookie, ; , ). #define _GNU_SOURCE #include #include #include #include #include #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); } _FILE_OFFSET_BITS should be defined to be 64 in code that uses non-null seek or that takes the address of fopencookie, if the code is intended to be portable to traditional 32-bit x86 and ARM platforms where off_t's width defaults to 32 bits. . fclose(3), fmemopen(3), fopen(3), fseek(3) Azamat Hackimov , Dmitry Bolkhovskikh , Yuri Kozlov ; GNU 3 , . . , , . Linux man-pages 6.06 29 2023 . fopencookie(3)