Annotation of embedaddon/libpdel/io/string_fp.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43:
44: #include <stdio.h>
45: #include <stdlib.h>
46: #include <stdarg.h>
47: #include <string.h>
48: #include <assert.h>
49: #include <errno.h>
50:
51: #include "structs/structs.h"
52: #include "structs/type/array.h"
53:
54: #include "io/string_fp.h"
55: #include "util/typed_mem.h"
56:
57: #define ROUNDUP2(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
58:
59: #ifndef __linux__
60: #define GET_COOKIE(fp) ((fp)->_cookie)
61: #else
62: #define GET_COOKIE(fp) (((void **)(fp + 1))[1])
63: #endif
64:
65: /***********************************************************************
66: STRING BUFFER OUTPUT STREAMS
67: ***********************************************************************/
68:
69: #define STRING_BUF_COOKIE 0x3f8209ec
70:
71: /* Internal state for a string_buf_output() stream */
72: struct output_buf {
73: u_int32_t cookie; /* sanity check id */
74: char *buf; /* output buffer */
75: size_t length; /* chars in buf */
76: size_t alloc; /* amount allocated */
77: int error; /* write error */
78: char *mtype; /* memory type */
79: char mtype_buf[TYPED_MEM_TYPELEN];
80: };
81:
82: /* Stream methods */
83: static int string_buf_output_write(void *arg, const char *data, int len);
84: static int string_buf_output_close(void *arg);
85:
86: /*
87: * Create a new output string buffer stream.
88: */
89: FILE *
90: string_buf_output(const char *mtype)
91: {
92: struct output_buf *sbuf;
93: int esave;
94: FILE *fp;
95:
96: if ((sbuf = MALLOC(mtype, sizeof(*sbuf))) == NULL)
97: return (NULL);
98: memset(sbuf, 0, sizeof(*sbuf));
99: sbuf->cookie = STRING_BUF_COOKIE;
100: if (mtype != NULL) {
101: strlcpy(sbuf->mtype_buf, mtype, sizeof(sbuf->mtype_buf));
102: sbuf->mtype = sbuf->mtype_buf;
103: }
104: if ((fp = funopen(sbuf, NULL, string_buf_output_write,
105: NULL, string_buf_output_close)) == NULL) {
106: esave = errno;
107: FREE(mtype, sbuf);
108: errno = esave;
109: return (NULL);
110: }
111: return (fp);
112: }
113:
114: /*
115: * Get current buffer contents.
116: */
117: char *
118: string_buf_content(FILE *fp, int reset)
119: {
120: struct output_buf *const sbuf = GET_COOKIE(fp);
121: char *s;
122:
123: /* Sanity check */
124: assert((size_t)sbuf >= 2048 && sbuf->cookie == STRING_BUF_COOKIE);
125:
126: /* Check for previous error */
127: if (sbuf->error != 0) {
128: errno = sbuf->error;
129: return (NULL);
130: }
131:
132: /* Flush all output to buffer */
133: fflush(fp);
134:
135: /* If no data, initialize with empty string */
136: if ((s = sbuf->buf) == NULL) {
137: if (string_buf_output_write(sbuf, NULL, 0) == -1)
138: return (NULL);
139: s = sbuf->buf;
140: }
141:
142: /* Reset buffer if desired */
143: if (reset) {
144: sbuf->buf = NULL;
145: sbuf->length = 0;
146: sbuf->alloc = 0;
147: }
148:
149: /* Done */
150: return (s);
151: }
152:
153: /*
154: * Get length of buffer.
155: */
156: int
157: string_buf_length(FILE *fp)
158: {
159: struct output_buf *const sbuf = GET_COOKIE(fp);
160:
161: /* Sanity check */
162: assert((size_t)sbuf >= 2048 && sbuf->cookie == STRING_BUF_COOKIE);
163:
164: /* Flush output */
165: fflush(fp);
166:
167: /* Return length of current buffer */
168: return (sbuf->length);
169: }
170:
171: /*
172: * Output stream write function.
173: */
174: static int
175: string_buf_output_write(void *arg, const char *data, int len)
176: {
177: struct output_buf *const sbuf = arg;
178: int esave;
179:
180: /* Was there a previous error? */
181: if (sbuf->error) {
182: errno = sbuf->error;
183: return (-1);
184: }
185:
186: /* Expand buffer */
187: if (sbuf->length + len + 1 > sbuf->alloc) {
188: const size_t new_size = ROUNDUP2(sbuf->length + len + 1, 256);
189: void *mem;
190:
191: if ((mem = REALLOC(sbuf->mtype, sbuf->buf, new_size)) == NULL) {
192: esave = errno;
193: FREE(sbuf->mtype, sbuf->buf);
194: sbuf->buf = NULL;
195: sbuf->length = 0;
196: sbuf->alloc = 0;
197: sbuf->error = errno = esave;
198: return (-1);
199: }
200: sbuf->buf = mem;
201: sbuf->alloc = new_size;
202: }
203:
204: /* Done */
205: memcpy(sbuf->buf + sbuf->length, data, len);
206: sbuf->length += len;
207: sbuf->buf[sbuf->length] = '\0';
208: return (len);
209: }
210:
211: /*
212: * Output stream close function.
213: */
214: static int
215: string_buf_output_close(void *arg)
216: {
217: struct output_buf *const sbuf = arg;
218:
219: sbuf->error = EINVAL;
220: FREE(sbuf->mtype, sbuf->buf);
221: FREE(sbuf->mtype, sbuf);
222: return (0);
223: }
224:
225: /***********************************************************************
226: STRING BUFFER INPUT STREAMS
227: ***********************************************************************/
228:
229: /* Internally used memory type for input streams */
230: #define INPUT_MEM_TYPE "string_buf_input"
231:
232: /* Internal state for a string_buf_input() stream */
233: struct input_buf {
234: char *data; /* input data */
235: int copied; /* data was copied */
236: #ifndef __linux__
237: fpos_t len; /* input length */
238: fpos_t pos; /* read position */
239: #else
240: _IO_off64_t len; /* input length */
241: _IO_off64_t pos; /* read position */
242: #endif
243: };
244:
245: /* Stream methods */
246: static int string_buf_input_read(void *cookie, char *buf, int len);
247: #ifndef __linux__
248: static fpos_t string_buf_input_seek(void *cookie, fpos_t pos, int whence);
249: #else
250: static int string_buf_input_seek(void *cookie,
251: _IO_off64_t *posp, int whence);
252: #endif
253: static int string_buf_input_close(void *arg);
254:
255: /*
256: * Create a new input string buffer stream.
257: */
258: FILE *
259: string_buf_input(const void *buf, size_t len, int copy)
260: {
261: struct input_buf *r;
262: int esave;
263: FILE *fp;
264:
265: if ((r = MALLOC(INPUT_MEM_TYPE, sizeof(*r))) == NULL)
266: return (NULL);
267: memset(r, 0, sizeof(*r));
268: if (copy) {
269: if ((r->data = MALLOC(INPUT_MEM_TYPE, len)) == NULL) {
270: FREE(INPUT_MEM_TYPE, r);
271: return (NULL);
272: }
273: memcpy(r->data, buf, len);
274: r->copied = 1;
275: } else
276: r->data = (char *)buf;
277: r->pos = 0;
278: r->len = len;
279: if ((fp = funopen(r, string_buf_input_read,
280: NULL, string_buf_input_seek, string_buf_input_close)) == NULL) {
281: esave = errno;
282: if (r->copied)
283: FREE(INPUT_MEM_TYPE, r->data);
284: FREE(INPUT_MEM_TYPE, r);
285: errno = esave;
286: }
287: return (fp);
288: }
289:
290: /*
291: * Seeker for input streams.
292: */
293: #ifndef __linux__
294: static fpos_t
295: string_buf_input_seek(void *cookie, fpos_t pos, int whence)
296: {
297: struct input_buf *const r = cookie;
298:
299: switch (whence) {
300: case SEEK_SET:
301: break;
302: case SEEK_CUR:
303: pos += r->pos;
304: break;
305: case SEEK_END:
306: pos += r->len;
307: break;
308: default:
309: errno = EINVAL;
310: return (-1);
311: }
312: if (pos < 0) {
313: errno = EINVAL;
314: return (-1);
315: }
316: if (pos > r->len) {
317: errno = EINVAL;
318: return (-1);
319: }
320: r->pos = pos;
321: return (pos);
322: }
323: #else
324: static int
325: string_buf_input_seek(void *cookie, _IO_off64_t *posp, int whence)
326: {
327: struct input_buf *const r = cookie;
328: _IO_off64_t newpos = *posp;
329:
330: switch (whence) {
331: case SEEK_SET:
332: break;
333: case SEEK_CUR:
334: newpos += r->pos;
335: break;
336: case SEEK_END:
337: newpos += r->len;
338: break;
339: default:
340: errno = EINVAL;
341: return (-1);
342: }
343: if (newpos < 0) {
344: errno = EINVAL;
345: return (-1);
346: }
347: if (newpos > r->len) {
348: errno = EINVAL;
349: return (-1);
350: }
351: *posp = r->pos = newpos;
352: return (0);
353: }
354: #endif
355:
356: /*
357: * Reader for input streams.
358: */
359: static int
360: string_buf_input_read(void *cookie, char *buf, int len)
361: {
362: struct input_buf *const r = cookie;
363:
364: if (len > r->len - r->pos)
365: len = r->len - r->pos;
366: memcpy(buf, r->data + r->pos, len);
367: r->pos += len;
368: return (len);
369: }
370:
371: /*
372: * Closer for input streams.
373: */
374: static int
375: string_buf_input_close(void *cookie)
376: {
377: struct input_buf *const r = cookie;
378:
379: if (r->copied)
380: FREE(INPUT_MEM_TYPE, r->data);
381: FREE(INPUT_MEM_TYPE, r);
382: return (0);
383: }
384:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>