Annotation of embedaddon/libpdel/io/string_fp.c, revision 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>