Skip to content

Commit 0b2fa8f

Browse files
committed
fmemopen: track current and maximum size separately
This is required to be compliant with the POSIX man page. As part of this change also set the position to the first NUL byte when opening the buffer in 'a' mode.
1 parent 63d0abf commit 0b2fa8f

File tree

1 file changed

+37
-6
lines changed

1 file changed

+37
-6
lines changed

newlib/libc/tinystdio/fmemopen.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,21 @@
3333
* OF THE POSSIBILITY OF SUCH DAMAGE.
3434
*/
3535

36+
#define _DEFAULT_SOURCE /* for strnlen */
3637
#include "stdio_private.h"
3738
#include <stdlib.h>
3839
#include <errno.h>
3940
#include <fcntl.h>
41+
#include <string.h>
4042
#include <unistd.h>
4143

4244
#define __MALL 0x01
4345

4446
struct __file_mem {
4547
struct __file_ext xfile;
4648
char *buf;
47-
size_t size;
49+
size_t size; /* Current size. */
50+
size_t bufsize; /* Upper limit on size. */
4851
size_t pos;
4952
uint8_t mflags;
5053
};
@@ -53,11 +56,17 @@ static int
5356
__fmem_put(char c, FILE *f)
5457
{
5558
struct __file_mem *mf = (struct __file_mem *)f;
56-
if ((f->flags & __SWR) && mf->pos < mf->size) {
59+
if ((f->flags & __SWR) == 0) {
60+
return _FDEV_ERR;
61+
} else if (mf->pos < mf->bufsize) {
5762
mf->buf[mf->pos++] = c;
63+
if (mf->pos > mf->size) {
64+
mf->size = mf->pos;
65+
}
5866
return (unsigned char)c;
67+
} else {
68+
return _FDEV_EOF;
5969
}
60-
return _FDEV_ERR;
6170
}
6271

6372
static int
@@ -78,8 +87,12 @@ static int
7887
__fmem_flush(FILE *f)
7988
{
8089
struct __file_mem *mf = (struct __file_mem *)f;
81-
if ((f->flags & __SWR) && mf->pos < mf->size)
90+
if ((f->flags & __SWR) && mf->pos < mf->bufsize) {
8291
mf->buf[mf->pos] = '\0';
92+
if (mf->pos > mf->size) {
93+
mf->size = mf->pos;
94+
}
95+
}
8396
return 0;
8497
}
8598

@@ -122,6 +135,8 @@ fmemopen(void *buf, size_t size, const char *mode)
122135
{
123136
int stdio_flags;
124137
uint8_t mflags = 0;
138+
size_t initial_pos = 0;
139+
size_t initial_size;
125140
struct __file_mem *mf;
126141

127142
stdio_flags = __stdio_sflags(mode);
@@ -155,12 +170,28 @@ fmemopen(void *buf, size_t size, const char *mode)
155170
mflags |= __MALL;
156171
}
157172

173+
/* Check mode directly to avoid _POSIX_IO dependency. */
174+
if (mode[0] == 'a') {
175+
/* For append the position is set to the first NUL byte or the end. */
176+
initial_pos = (mflags & __MALL) ? 0 : strnlen(buf, size);
177+
initial_size = initial_pos;
178+
} else if (mode[0] == 'w') {
179+
initial_size = 0;
180+
/* w+ mode truncates the buffer, writing NUL */
181+
if ((stdio_flags & (__SRD | __SWR)) == (__SRD | __SWR)) {
182+
*((char *)buf) = '\0';
183+
}
184+
} else {
185+
initial_size = size;
186+
}
187+
158188
*mf = (struct __file_mem){
159189
.xfile = FDEV_SETUP_EXT(__fmem_put, __fmem_get, __fmem_flush,
160190
__fmem_close, __fmem_seek, NULL, stdio_flags),
161191
.buf = buf,
162-
.size = size,
163-
.pos = 0,
192+
.size = initial_size,
193+
.bufsize = size,
194+
.pos = initial_pos,
164195
.mflags = mflags,
165196
};
166197

0 commit comments

Comments
 (0)