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>