Return to string_fp.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / contrib / libpdel / io |
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 * 1.1.1.2 ! misho 259: string_buf_input(void *buf, size_t len, int copy) 1.1 misho 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 1.1.1.2 ! misho 276: r->data = buf; 1.1 misho 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: