diff options
Diffstat (limited to 'libio')
-rw-r--r-- | libio/Makefile | 4 | ||||
-rw-r--r-- | libio/Versions | 2 | ||||
-rw-r--r-- | libio/fmemopen.c | 242 | ||||
-rw-r--r-- | libio/stdio.h | 3 | ||||
-rw-r--r-- | libio/test-fmemopen.c | 40 |
5 files changed, 288 insertions, 3 deletions
diff --git a/libio/Makefile b/libio/Makefile index e41e78e..4208de6 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -41,10 +41,10 @@ routines := \ iovdprintf vscanf vsnprintf obprintf fcloseall fseeko ftello \ freopen64 fseeko64 ftello64 \ \ - libc_fatal + libc_fatal fmemopen tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ - tst_wprintf2 tst-widetext + tst_wprintf2 tst-widetext test-fmemopen all: # Make this the default target; it will be defined in Rules. diff --git a/libio/Versions b/libio/Versions index 0b57cce..8c1f35d 100644 --- a/libio/Versions +++ b/libio/Versions @@ -121,7 +121,7 @@ libc { # f* fgetpos; fgetpos64; fgetwc; fgetwc_unlocked; fgetws; fgetws_unlocked; fputwc; fputwc_unlocked; fputws; fputws_unlocked; fsetpos; fsetpos64; - fwide; fwprintf; fwscanf; fopencookie; + fwide; fwprintf; fwscanf; fopencookie; fmemopen; # g* getwc; getwc_unlocked; getwchar; getwchar_unlocked; diff --git a/libio/fmemopen.c b/libio/fmemopen.c new file mode 100644 index 0000000..d98b671 --- /dev/null +++ b/libio/fmemopen.c @@ -0,0 +1,242 @@ +/* Fmemopen implementation. + Copyright (C) 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Hanno Mueller, kontakt@hanno.de, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* + * fmemopen() - "my" version of a string stream + * Hanno Mueller, kontakt@hanno.de + * + * + * I needed fmemopen() for an application that I currently work on, + * but couldn't find it in libio. The following snippet of code is an + * attempt to implement what glibc's documentation describes. + * + * No, it isn't really tested yet. :-) + * + * + * + * I already see some potential problems: + * + * - I never used the "original" fmemopen(). I am sure that "my" + * fmemopen() behaves differently than the original version. + * + * - The documentation doesn't say wether a string stream allows + * seeks. I checked the old fmemopen implementation in glibc's stdio + * directory, wasn't quite able to see what is going on in that + * source, but as far as I understand there was no seek there. For + * my application, I needed fseek() and ftell(), so it's here. + * + * - "append" mode and fseek(p, SEEK_END) have two different ideas + * about the "end" of the stream. + * + * As described in the documentation, when opening the file in + * "append" mode, the position pointer will be set to the first null + * character of the string buffer (yet the buffer may already + * contain more data). For fseek(), the last byte of the buffer is + * used as the end of the stream. + * + * - It is unclear to me what the documentation tries to say when it + * explains what happens when you use fmemopen with a NULL + * buffer. + * + * Quote: "fmemopen [then] allocates an array SIZE bytes long. This + * is really only useful if you are going to write things to the + * buffer and then read them back in again." + * + * What does that mean if the original fmemopen() did not allow + * seeking? How do you read what you just wrote without seeking back + * to the beginning of the stream? + * + * - I think there should be a second version of fmemopen() that does + * not add null characters for each write. (At least in my + * application, I am not actually using strings but binary data and + * so I don't need the stream to add null characters on its own.) + */ + +#include <libio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +typedef struct fmemopen_cookie_struct fmemopen_cookie_t; +struct fmemopen_cookie_struct +{ + char *buffer; + int mybuffer; + size_t size; + _IO_off64_t pos; + size_t maxpos; +}; + + +ssize_t +fmemopen_read (void *cookie, char *b, size_t s) +{ + fmemopen_cookie_t *c; + + c = (fmemopen_cookie_t *) cookie; + + if ((c->pos + s) > c->size) + { + if (c->pos == c->size) + return -1; + s = c->size - c->pos; + } + + memcpy (b, &(c->buffer[c->pos]), s); + + c->pos += s; + if (c->pos > c->maxpos) + c->maxpos = c->pos; + + return s; +} + + +ssize_t +fmemopen_write (void *cookie, const char *b, size_t s) +{ + fmemopen_cookie_t *c; + int addnullc; + + c = (fmemopen_cookie_t *) cookie; + + addnullc = ((s == 0) || (b[s - 1] != '\0')) ? 1 : 0; + + if ((c->pos + s + addnullc) > c->size) + { + if ((c->pos + addnullc) == c->size) + return -1; + s = c->size - c->pos - addnullc; + } + + memcpy (&(c->buffer[c->pos]), b, s); + + c->pos += s; + if (c->pos > c->maxpos) + { + c->maxpos = c->pos; + if (addnullc) + c->buffer[c->maxpos] = '\0'; + } + + return s; +} + + +int +fmemopen_seek (void *cookie, _IO_off64_t * p, int w) +{ + _IO_off64_t np; + fmemopen_cookie_t *c; + + c = (fmemopen_cookie_t *) cookie; + + switch (w) + { + + case SEEK_SET: + np = *p; + break; + + case SEEK_CUR: + np = c->pos + *p; + break; + + case SEEK_END: + np = c->size - *p; + break; + + } + + if ((np < 0) || (np > c->size)) + return -1; + + c->pos = np; + + return np; +} + + +int +fmemopen_close (void *cookie) +{ + fmemopen_cookie_t *c; + + c = (fmemopen_cookie_t *) cookie; + + if (c->mybuffer) + free (c->buffer); + free (c); + + return 0; +} + + +FILE * +fmemopen (void *buf, size_t len, const char *mode) +{ + cookie_io_functions_t iof; + fmemopen_cookie_t *c; + + c = (fmemopen_cookie_t *) malloc (sizeof (fmemopen_cookie_t)); + if (c == NULL) + return NULL; + + c->mybuffer = (buf == NULL); + + if (c->mybuffer) + { + c->buffer = (char *) malloc (len); + if (c->buffer == NULL) + { + free (c); + return NULL; + } + c->buffer[0] = '\0'; + } + else + { + c->buffer = buf; + } + + c->size = len; + + if (mode[0] == 'w') + c->buffer[0] = '\0'; + + c->maxpos = strlen (c->buffer); + + if (mode[0] == 'a') + { + c->pos = c->maxpos; + } + else + { + c->pos = 0; + } + + iof.read = fmemopen_read; + iof.write = fmemopen_write; + iof.seek = fmemopen_seek; + iof.close = fmemopen_close; + + return fopencookie (c, mode, iof); +} diff --git a/libio/stdio.h b/libio/stdio.h index 7a18261..ccab90b 100644 --- a/libio/stdio.h +++ b/libio/stdio.h @@ -219,6 +219,9 @@ extern FILE *fopencookie (void *__restrict __magic_cookie, __const char *__restrict __modes, _IO_cookie_io_functions_t __io_funcs) __THROW; +/* Create a new stream that refers to a memory buffer. */ +extern FILE *fmemopen (void *__s, size_t __len, __const char *__modes) __THROW; + /* Open a stream that writes into a malloc'd buffer that is expanded as necessary. *BUFLOC and *SIZELOC are updated with the buffer's location and the number of characters written on fflush or fclose. */ diff --git a/libio/test-fmemopen.c b/libio/test-fmemopen.c new file mode 100644 index 0000000..6c2782d --- /dev/null +++ b/libio/test-fmemopen.c @@ -0,0 +1,40 @@ +/* Test for fmemopen implementation. + Copyright (C) 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Hanno Mueller, kontakt@hanno.de, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +static char buffer[] = "foobar"; + +#include <stdio.h> +#include <string.h> + +int +main (void) +{ + int ch; + FILE *stream; + + stream = fmemopen (buffer, strlen (buffer), "r"); + + while ((ch = fgetc (stream)) != EOF) + printf ("Got %c\n", ch); + + fclose (stream); + + return 0; +} |