-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
stdio.h: add open_memstream of (OS X < 10.13)
The implementation originates from https://piumarta.com/software/memstream/
- Loading branch information
1 parent
1d2eccf
commit d24f1d5
Showing
5 changed files
with
226 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
/* memstream.c | ||
* | ||
* This file is licensed under the MIT license by | ||
* | ||
* Copyright (c) 2013 Ian Piumarta. | ||
* | ||
* Modifications for inclusion in macports-legacy-support | ||
* Copyright (c) 2023 Dennis Camera. | ||
* | ||
* ---------------------------------------------------------------------------- | ||
* | ||
* OPEN_MEMSTREAM(3) BSD and Linux Library Functions OPEN_MEMSTREAM(3) | ||
* | ||
* SYNOPSIS | ||
* FILE *open_memstream(char **bufp, size_t *sizep); | ||
* | ||
* DESCRIPTION | ||
* The open_memstream() function opens a stream for writing to a buffer. | ||
* The buffer is dynamically allocated (as with malloc(3)), and | ||
* automatically grows as required. After closing the stream, the caller | ||
* should free(3) this buffer. | ||
* | ||
* When the stream is closed (fclose(3)) or flushed (fflush(3)), the | ||
* locations pointed to by bufp and sizep are updated to contain, | ||
* respectively, a pointer to the buffer and the current size of the | ||
* buffer. These values remain valid only as long as the caller performs | ||
* no further output on the stream. If further output is performed, then | ||
* the stream must again be flushed before trying to access these | ||
* variables. | ||
* | ||
* A null byte is maintained at the end of the buffer. This byte is not | ||
* included in the size value stored at sizep. | ||
* | ||
* The stream's file position can be changed with fseek(3) or fseeko(3). | ||
* Moving the file position past the end of the data already written fills | ||
* the intervening space with zeros. | ||
* | ||
* RETURN VALUE | ||
* Upon successful completion open_memstream() returns a FILE pointer. | ||
* Otherwise, NULL is returned and errno is set to indicate the error. | ||
* | ||
* CONFORMING TO | ||
* POSIX.1-2008 | ||
* | ||
* ---------------------------------------------------------------------------- | ||
*/ | ||
|
||
/* MP support header */ | ||
#include "MacportsLegacySupport.h" | ||
#if __MP_LEGACY_SUPPORT_OPEN_MEMSTREAM__ | ||
|
||
#include "stdio.h" | ||
|
||
#include <stddef.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <errno.h> | ||
#include <assert.h> | ||
|
||
#define min(X, Y) (((X) < (Y)) ? (X) : (Y)) | ||
|
||
struct memstream | ||
{ | ||
int position; | ||
int size; | ||
int capacity; | ||
char *contents; | ||
char **ptr; | ||
size_t *sizeloc; | ||
}; | ||
|
||
#if MEMSTREAM_DEBUG | ||
static void memstream_print(struct memstream *ms) | ||
{ | ||
printf("memstream %p {", ms); | ||
printf(" %i", ms->position); | ||
printf(" %i", ms->size); | ||
printf(" %i", ms->capacity); | ||
printf(" %p", ms->contents); | ||
printf(" }\n"); | ||
} | ||
# define memstream_info(ARGS) printf ARGS | ||
#else | ||
# define memstream_print(ms) | ||
# define memstream_info(ARGS) | ||
#endif | ||
|
||
#define memstream_check(MS) if (!(MS)->contents) { errno= ENOMEM; return -1; } | ||
|
||
static int memstream_grow(struct memstream *ms, int minsize) | ||
{ | ||
int newcap= ms->capacity * 2; memstream_check(ms); | ||
while (newcap <= minsize) newcap *= 2; memstream_info(("grow %p to %i\n", ms, newcap)); | ||
ms->contents= realloc(ms->contents, newcap); | ||
if (!ms->contents) return -1; /* errno == ENOMEM */ | ||
memset(ms->contents + ms->capacity, 0, newcap - ms->capacity); | ||
ms->capacity= newcap; | ||
*ms->ptr= ms->contents; /* size has not changed */ | ||
return 0; | ||
} | ||
|
||
static int memstream_read(void *cookie, char *buf, int count) | ||
{ | ||
struct memstream *ms= (struct memstream *)cookie; memstream_check(ms); | ||
int n= min(ms->size - ms->position, count); memstream_info(("memstream_read %p %i\n", ms, count)); | ||
if (n < 1) return 0; | ||
memcpy(buf, ms->contents, n); | ||
ms->position += n; memstream_print(ms); | ||
return n; | ||
} | ||
|
||
static int memstream_write(void *cookie, const char *buf, int count) | ||
{ | ||
struct memstream *ms= (struct memstream *)cookie; memstream_check(ms); | ||
if (ms->capacity <= ms->position + count) | ||
if (memstream_grow(ms, ms->position + count) < 0) /* errno == ENOMEM */ | ||
return -1; | ||
memcpy(ms->contents + ms->position, buf, count); memstream_info(("memstream_write %p %i\n", ms, count)); | ||
ms->position += count; | ||
if (ms->size < ms->position) *ms->sizeloc= ms->size= ms->position; memstream_print(ms); | ||
assert(ms->size < ms->capacity); | ||
assert(ms->contents[ms->size] == 0); | ||
return count; | ||
} | ||
|
||
static fpos_t memstream_seek(void *cookie, fpos_t offset, int whence) | ||
{ | ||
struct memstream *ms= (struct memstream *)cookie; | ||
fpos_t pos= 0; memstream_check(ms); | ||
memstream_info(("memstream_seek %p %i %i\n", ms, (int)offset, whence)); | ||
switch (whence) { | ||
case SEEK_SET: pos= offset; break; | ||
case SEEK_CUR: pos= ms->position + offset; break; | ||
case SEEK_END: pos= ms->size + offset; break; | ||
default: errno= EINVAL; return -1; | ||
} | ||
if (pos >= ms->capacity) memstream_grow(ms, pos); | ||
ms->position= pos; | ||
if (ms->size < ms->position) *ms->sizeloc= ms->size= ms->position; memstream_print(ms); memstream_info(("=> %i\n", (int)pos)); | ||
assert(ms->size < ms->capacity && ms->contents[ms->size] == 0); | ||
return pos; | ||
} | ||
|
||
static int memstream_close(void *cookie) | ||
{ | ||
struct memstream *ms= (struct memstream *)cookie; if (!ms->contents) { free(ms); errno= ENOMEM; return -1; } | ||
ms->size= min(ms->size, ms->position); | ||
*ms->ptr= ms->contents; | ||
*ms->sizeloc= ms->size; assert(ms->size < ms->capacity); | ||
ms->contents[ms->size]= 0; | ||
free(ms); | ||
return 0; | ||
} | ||
|
||
FILE *open_memstream(char **ptr, size_t *sizeloc) | ||
{ | ||
if (ptr && sizeloc) { | ||
struct memstream *ms= calloc(1, sizeof(struct memstream)); | ||
FILE *fp= 0; if (!ms) return 0; /* errno == ENOMEM */ | ||
ms->position= ms->size= 0; | ||
ms->capacity= 4096; | ||
ms->contents= calloc(ms->capacity, 1); if (!ms->contents) { free(ms); return 0; } /* errno == ENOMEM */ | ||
ms->ptr= ptr; | ||
ms->sizeloc= sizeloc; | ||
memstream_print(ms); | ||
fp= funopen(ms, memstream_read, memstream_write, memstream_seek, memstream_close); | ||
if (!fp) { | ||
free(ms->contents); | ||
free(ms); | ||
return 0; /* errno set by funopen */ | ||
} | ||
*ptr= ms->contents; | ||
*sizeloc= ms->size; | ||
return fp; | ||
} | ||
errno= EINVAL; | ||
return 0; | ||
} | ||
|
||
#endif /* __MP_LEGACY_SUPPORT_OPEN_MEMSTREAM__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/*#include "memstream.h"*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <assert.h> | ||
|
||
int main() | ||
{ | ||
char *buffer = 0; | ||
size_t size = 0; | ||
FILE *fp = open_memstream(&buffer, &size); | ||
int i; | ||
for (i = 0; i < 10240; ++i) { | ||
static char c = 42; | ||
fflush(fp); | ||
assert(size == i); | ||
fwrite(&c, 1, 1, fp); | ||
} | ||
fclose(fp); | ||
assert(size == 10240); | ||
free(buffer); | ||
fp = open_memstream(&buffer, &size); | ||
fprintf(fp, "This is a test of memstream, from main at %p.\n", main); | ||
fclose(fp); | ||
fputs(buffer, stdout); | ||
free(buffer); | ||
|
||
return 0; | ||
} |