1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2022 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include "stdio_private.h"
37 #include <stdlib.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40
41 #define __MALL 0x01
42
43 struct __file_mem {
44 struct __file_ext xfile;
45 char *buf;
46 size_t size;
47 size_t pos;
48 uint8_t mflags;
49 };
50
__fmem_put(char c,FILE * f)51 static int __fmem_put(char c, FILE *f)
52 {
53 struct __file_mem *mf = (struct __file_mem *) f;
54 if ((f->flags & __SWR) && mf->pos < mf->size) {
55 mf->buf[mf->pos++] = c;
56 return (unsigned char) c;
57 }
58 return _FDEV_ERR;
59 }
60
__fmem_get(FILE * f)61 static int __fmem_get(FILE *f)
62 {
63 struct __file_mem *mf = (struct __file_mem *) f;
64 int c;
65 if ((f->flags & __SRD) && mf->pos < mf->size) {
66 c = (unsigned char) mf->buf[mf->pos++];
67 if (c == '\0')
68 c = _FDEV_EOF;
69 } else
70 c = _FDEV_ERR;
71 return c;
72 }
73
__fmem_flush(FILE * f)74 static int __fmem_flush(FILE *f)
75 {
76 struct __file_mem *mf = (struct __file_mem *) f;
77 if ((f->flags & __SWR) && mf->pos < mf->size)
78 mf->buf[mf->pos] = '\0';
79 return 0;
80 }
81
__fmem_seek(FILE * f,off_t pos,int whence)82 static off_t __fmem_seek(FILE *f, off_t pos, int whence)
83 {
84 struct __file_mem *mf = (struct __file_mem *) f;
85
86 switch (whence) {
87 case SEEK_SET:
88 break;
89 case SEEK_CUR:
90 pos += mf->pos;
91 break;
92 case SEEK_END:
93 pos += mf->size;
94 break;
95 }
96 if (pos < 0 || mf->size < (size_t) pos)
97 return EOF;
98 mf->pos = pos;
99 return pos;
100 }
101
__fmem_close(FILE * f)102 static int __fmem_close(FILE *f)
103 {
104 struct __file_mem *mf = (struct __file_mem *) f;
105
106 if (mf->mflags & __MALL)
107 free (mf->buf);
108 else
109 __fmem_flush(f);
110 free(f);
111 return 0;
112 }
113
114 FILE *
fmemopen(void * buf,size_t size,const char * mode)115 fmemopen(void *buf, size_t size, const char *mode)
116 {
117 int stdio_flags;
118 uint8_t mflags = 0;
119 int open_flags;
120 struct __file_mem *mf;
121
122 stdio_flags = __posix_sflags(mode, &open_flags);
123 if (stdio_flags == 0)
124 return NULL;
125
126 /* Allocate file structure and necessary buffers */
127 mf = calloc(1, sizeof(struct __file_mem));
128
129 if (mf == NULL)
130 return NULL;
131
132 if (buf == NULL) {
133 buf = malloc(size);
134 if (!buf) {
135 free(mf);
136 return NULL;
137 }
138 mflags |= __MALL;
139 }
140
141 *mf = (struct __file_mem) {
142 .xfile = FDEV_SETUP_EXT(__fmem_put, __fmem_get, __fmem_flush, __fmem_close,
143 __fmem_seek, NULL, stdio_flags),
144 .buf = buf,
145 .size = size,
146 .pos = 0,
147 .mflags = mflags,
148 };
149
150 return &(mf->xfile.cfile.file);
151 }
152