fmemopen(): Style & whitespace fixes.
[dragonfly.git] / lib / libc / stdio / fmemopen.c
1 /*
2  * Copyright (c) 2011 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Venkatesh Srinivas <me@endeavour.zapto.org>.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * ----------------------------------------------------------------------------
36  * "THE BEER-WARE LICENSE" (Revision 42):
37  * <hiten@uk.FreeBSD.ORG> wrote this file.  As long as you retain this notice
38  * you can do whatever you want with this stuff. If we meet some day, and you
39  * think this stuff is worth it, you can buy me a beer in return. Hiten Pandya.
40  * ----------------------------------------------------------------------------
41  *
42  * $FreeBSD: src/sys/dev/md/md.c,v 1.8.2.2 2002/08/19 17:43:34 jdp Exp $
43  */
44
45 /*
46  * fmemopen -- Open a memory buffer stream
47  *
48  * POSIX 1003.1-2008
49  */
50
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <sys/types.h>
55 #include <errno.h>
56
57 static int __fmemopen_closefn (void *);
58 static int __fmemopen_readfn(void *, char *, int);
59 static fpos_t __fmemopen_seekfn (void *, fpos_t, int);
60 static int __fmemopen_writefn(void *, const char *, int);
61
62 FILE *fmemopen (void *, size_t, const char *);
63
64 struct fmemopen_cookie {
65         char *buffer;
66         int mybuffer;
67         size_t size;
68         size_t pos;
69         size_t maxpos;
70 };
71
72 static int
73 __fmemopen_readfn(void *cookie, char *buf, int len)
74 {
75         struct fmemopen_cookie *c;
76         c = (struct fmemopen_cookie *) cookie;
77
78         if (c == NULL) {
79                 errno = EBADF;
80                 return (-1);
81         }
82
83         if ((c->pos + len) > c->size) {
84                 if (c->pos == c->size)
85                         return -1;
86                 len = c->size - c->pos;
87         }
88
89         memcpy(buf, &(c->buffer[c->pos]), len);
90
91         c->pos += len;
92
93         if (c->pos > c->maxpos)
94                 c->maxpos = c->pos;
95
96         return (len);
97 }
98
99 static int
100 __fmemopen_writefn (void *cookie, const char *buf, int len)
101 {
102         struct fmemopen_cookie *c;
103         int addnullc;
104
105         c = (struct fmemopen_cookie *) cookie;
106         if (c == NULL) {
107                 errno = EBADF;
108                 return (-1);
109         }
110
111         addnullc = ((len == 0) || (buf[len - 1] != '\0') ) ? 1 : 0;
112
113         if ((c->pos + len + addnullc) > c->size) {
114                 if ((c->pos + addnullc) == c->size)
115                         return -1;
116                 len = c->size - c->pos - addnullc;
117         }
118
119         memcpy(&(c->buffer[c->pos]), buf, len);
120
121         c->pos += len;
122         if (c->pos > c->maxpos) {
123                 c->maxpos = c->pos;
124                 if (addnullc)
125                         c->buffer[c->maxpos] = '\0';
126         }
127
128         return (len);
129 }
130
131 static fpos_t
132 __fmemopen_seekfn(void *cookie, fpos_t pos, int whence)
133 {
134         fpos_t np = 0;
135         struct fmemopen_cookie *c;
136
137         c = (struct fmemopen_cookie *) cookie;
138
139         switch(whence) {
140         case (SEEK_SET):
141                 np = pos;
142                 break;
143         case (SEEK_CUR):
144                 np = c->pos + pos;
145                 break;
146         case (SEEK_END):
147                 np = c->size - pos;
148                 break;
149         }
150
151         if ((np < 0) || (np > c->size))
152                 return (-1);
153
154         c->pos = np;
155
156         return (np);
157 }
158
159 static int
160 __fmemopen_closefn (void *cookie)
161 {
162         struct fmemopen_cookie *c;
163         c = (struct fmemopen_cookie*) cookie;
164
165         if (c->mybuffer)
166                 free(c->buffer);
167         free(c);
168
169         return (0);
170 }
171
172 FILE *
173 fmemopen(void *restrict buffer, size_t s, const char *restrict mode)
174 {
175         FILE *f = NULL;
176         struct fmemopen_cookie *c;
177         c = malloc(sizeof (struct fmemopen_cookie));
178
179         if (c == NULL)
180                 return NULL;
181
182         c->mybuffer = (buffer == NULL);
183
184         if (c->mybuffer) {
185                 c->buffer = malloc(s);
186                 if (c->buffer == NULL) {
187                         free(c);
188                         return NULL;
189                 }
190                 c->buffer[0] = '\0';
191         } else {
192                 c->buffer = buffer;
193         }
194         c->size = s;
195         if (mode[0] == 'w')
196                 c->buffer[0] = '\0';
197         c->maxpos = strlen(c->buffer);
198
199         if (mode[0] == 'a')
200                 c->pos = c->maxpos;
201         else
202                 c->pos = 0;
203
204         f = funopen(c,
205                     __fmemopen_readfn, /* string stream read */
206                     __fmemopen_writefn, /* string stream write */
207                     __fmemopen_seekfn, /* string stream seek */
208                     __fmemopen_closefn /* string stream close */
209                     );
210
211         if (f == NULL)
212                 free(c);
213
214         return (f);
215 }