Annotation of embedaddon/mpd/src/contrib/libpdel/structs/structs.c, revision 1.1.1.2

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: 
                     43: #include <stdlib.h>
                     44: #include <stdio.h>
                     45: #include <stdarg.h>
                     46: #include <assert.h>
                     47: #include <string.h>
                     48: #include <ctype.h>
                     49: #include <errno.h>
                     50: 
                     51: #include "structs/structs.h"
                     52: #include "structs/type/int.h"
                     53: #include "structs/type/array.h"
                     54: #include "structs/type/string.h"
                     55: #include "structs/type/struct.h"
                     56: #include "structs/type/union.h"
                     57: #include "util/typed_mem.h"
                     58: 
                     59: /* Special handling for array length as a read-only field */
                     60: static const struct structs_type structs_type_array_length = {
                     61:        sizeof(u_int),
                     62:        "uint",
                     63:        STRUCTS_TYPE_PRIMITIVE,
                     64:        structs_region_init,
                     65:        structs_region_copy,
                     66:        structs_region_equal,
                     67:        structs_int_ascify,
                     68:        structs_notsupp_binify,
                     69:        structs_region_encode_netorder,
                     70:        structs_notsupp_decode,
                     71:        structs_nothing_free,
                     72:        { { (void *)2 }, { (void *)0 } }    /* args for structs_int_ascify */
                     73: };
                     74: 
                     75: /* Special handling for union field name as a read-only field */
                     76: static const struct structs_type structs_type_union_field_name = {
                     77:        sizeof(char *),
                     78:        "string",
                     79:        STRUCTS_TYPE_PRIMITIVE,
                     80:        structs_notsupp_init,
                     81:        structs_notsupp_copy,
                     82:        structs_string_equal,
                     83:        structs_string_ascify,
                     84:        structs_notsupp_binify,
                     85:        structs_notsupp_encode,
                     86:        structs_notsupp_decode,
                     87:        structs_nothing_free,
                     88:        { { (void *)"union field_name" },    /* args for structs_type_string */
                     89:        { (void *)0 } }
                     90: };
                     91: 
                     92: /*
                     93:  * Initialize an item.
                     94:  */
                     95: int
                     96: structs_init(const struct structs_type *type, const char *name, void *data)
                     97: {
                     98:        /* Find item */
                     99:        if ((type = structs_find(type, name, &data, 0)) == NULL)
                    100:                return (-1);
                    101: 
                    102:        /* Initialize it */
                    103:        return ((*type->init)(type, data));
                    104: }
                    105: 
                    106: /*
                    107:  * Reset an item.
                    108:  */
                    109: int
                    110: structs_reset(const struct structs_type *type, const char *name, void *data)
                    111: {
                    112:        void *temp;
                    113: 
                    114:        /* Find item */
                    115:        if ((type = structs_find(type, name, &data, 0)) == NULL)
                    116:                return (-1);
                    117: 
                    118:        /* Make a temporary new copy */
                    119:        if ((temp = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
                    120:                return (-1);
                    121:        memset(temp, 0, type->size);
                    122:        if ((*type->init)(type, temp) == -1) {
                    123:                FREE(TYPED_MEM_TEMP, temp);
                    124:                return (-1);
                    125:        }
                    126: 
                    127:        /* Replace existing item, freeing it first */
                    128:        (*type->uninit)(type, data);
                    129:        memcpy(data, temp, type->size);
                    130:        FREE(TYPED_MEM_TEMP, temp);
                    131:        return (0);
                    132: }
                    133: 
                    134: /*
                    135:  * Free an item, returning it to its initialized state.
                    136:  *
                    137:  * If "name" is NULL or empty string, the entire structure is free'd.
                    138:  */
                    139: int
                    140: structs_free(const struct structs_type *type, const char *name, void *data)
                    141: {
                    142:        const int errno_save = errno;
                    143: 
                    144:        /* Find item */
                    145:        if ((type = structs_find(type, name, &data, 0)) == NULL)
                    146:                return (-1);
                    147: 
                    148:        /* Free it */
                    149:        (*type->uninit)(type, data);
                    150:        errno = errno_save;
                    151:        return (0);
                    152: }
                    153: 
                    154: /*
                    155:  * Get a copy of an item.
                    156:  *
                    157:  * If "name" is NULL or empty string, the entire structure is copied.
                    158:  *
                    159:  * It is assumed that "to" points to a region big enough to hold
                    160:  * the copy of the item. "to" will not be free'd first, so it should
                    161:  * not already be initialized.
                    162:  *
                    163:  * Note: "name" is only applied to "from". The structs types of
                    164:  * "from.<name>" and "to" must be the same.
                    165:  */
                    166: int
                    167: structs_get(const struct structs_type *type,
                    168:        const char *name, const void *from, void *to)
                    169: {
                    170:        /* Find item */
                    171:        if ((type = structs_find(type, name, (void **)&from, 0)) == NULL)
                    172:                return (-1);
                    173: 
                    174:        /* Copy item */
                    175:        return ((*type->copy)(type, from, to));
                    176: }
                    177: 
                    178: /*
                    179:  * Set an item in a structure.
                    180:  *
                    181:  * If "name" is NULL or empty string, the entire structure is copied.
                    182:  *
                    183:  * It is assumed that "to" is already initialized.
                    184:  *
                    185:  * Note: "name" is only applied to "to". The structs types of
                    186:  * "from" and "to.<name>" must be the same.
                    187:  */
                    188: int
                    189: structs_set(const struct structs_type *type,
                    190:        const void *from, const char *name, void *to)
                    191: {
                    192:        void *copy;
                    193: 
                    194:        /* Find item */
                    195:        if ((type = structs_find(type, name, &to, 0)) == NULL)
                    196:                return (-1);
                    197: 
                    198:        /* Make a new copy of 'from' */
                    199:        if ((copy = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
                    200:                return (-1);
                    201:        if ((*type->copy)(type, from, copy) == -1) {
                    202:                FREE(TYPED_MEM_TEMP, copy);
                    203:                return (-1);
                    204:        }
                    205: 
                    206:        /* Free overwritten item in 'to' */
                    207:        (*type->uninit)(type, to);
                    208: 
                    209:        /* Move new item in its place */
                    210:        memcpy(to, copy, type->size);
                    211: 
                    212:        /* Done */
                    213:        FREE(TYPED_MEM_TEMP, copy);
                    214:        return (0);
                    215: }
                    216: 
                    217: /*
                    218:  * Get the ASCII form of an item.
                    219:  */
                    220: char *
                    221: structs_get_string(const struct structs_type *type,
                    222:        const char *name, const void *data, const char *mtype)
                    223: {
                    224:        /* Find item */
                    225:        if ((type = structs_find(type, name, (void **)&data, 0)) == NULL)
                    226:                return (NULL);
                    227: 
                    228:        /* Ascify it */
                    229:        return ((*type->ascify)(type, mtype, data));
                    230: }
                    231: 
                    232: /*
                    233:  * Set an item's value from a string.
                    234:  *
                    235:  * The referred to item must be of a type that supports ASCII encoding,
                    236:  * and is assumed to be already initialized.
                    237:  */
                    238: int
                    239: structs_set_string(const struct structs_type *type, const char *name,
                    240:        const char *ascii, void *data, char *ebuf, size_t emax)
                    241: {
                    242:        void *temp;
                    243:        char dummy[1];
                    244: 
                    245:        /* Sanity check */
                    246:        if (ascii == NULL)
                    247:                ascii = "";
                    248:        if (ebuf == NULL) {
                    249:                ebuf = dummy;
                    250:                emax = sizeof(dummy);
                    251:        }
                    252: 
                    253:        /* Initialize error buffer */
                    254:        if (emax > 0)
                    255:                *ebuf = '\0';
                    256: 
                    257:        /* Find item */
                    258:        if ((type = structs_find(type, name, &data, 1)) == NULL) {
                    259:                strlcpy(ebuf, strerror(errno), emax);
                    260:                return (-1);
                    261:        }
                    262: 
                    263:        /* Binify item into temporary storage */
                    264:        if ((temp = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
                    265:                return (-1);
                    266:        memset(temp, 0, type->size);
                    267:        if ((*type->binify)(type, ascii, temp, ebuf, emax) == -1) {
                    268:                FREE(TYPED_MEM_TEMP, temp);
                    269:                if (emax > 0 && *ebuf == '\0')
                    270:                        strlcpy(ebuf, strerror(errno), emax);
                    271:                return (-1);
                    272:        }
                    273: 
                    274:        /* Replace existing item, freeing it first */
                    275:        (*type->uninit)(type, data);
                    276:        memcpy(data, temp, type->size);
                    277:        FREE(TYPED_MEM_TEMP, temp);
                    278:        return (0);
                    279: }
                    280: 
                    281: /*
                    282:  * Get the binary encoded form of an item, allocated with type 'mtype'.
                    283:  */
                    284: int
                    285: structs_get_binary(const struct structs_type *type, const char *name,
                    286:        const void *data, const char *mtype, struct structs_data *code)
                    287: {
                    288:        /* Find item */
                    289:        if ((type = structs_find(type, name, (void **)&data, 0)) == NULL) {
                    290:                memset(code, 0, sizeof(*code));
                    291:                return (-1);
                    292:        }
                    293: 
                    294:        /* Encode it */
                    295:        if ((*type->encode)(type, mtype, code, data) == -1) {
                    296:                memset(code, 0, sizeof(*code));
                    297:                return (-1);
                    298:        }
                    299: 
                    300:        /* Done */
                    301:        return (0);
                    302: }
                    303: 
                    304: /*
                    305:  * Set an item's value from its binary encoded value.
                    306:  */
                    307: int
                    308: structs_set_binary(const struct structs_type *type, const char *name,
                    309:        const struct structs_data *code, void *data, char *ebuf, size_t emax)
                    310: {
                    311:        void *temp;
                    312:        int clen;
                    313: 
                    314:        /* Initialize error buffer */
                    315:        if (emax > 0)
                    316:                *ebuf = '\0';
                    317: 
                    318:        /* Find item */
                    319:        if ((type = structs_find(type, name, (void **)&data, 0)) == NULL) {
                    320:                strlcpy(ebuf, strerror(errno), emax);
                    321:                return (-1);
                    322:        }
                    323: 
                    324:        /* Decode item into temporary storage */
                    325:        if ((temp = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
                    326:                return (-1);
                    327:        memset(temp, 0, type->size);
                    328:        if ((clen = (*type->decode)(type, code->data,
                    329:            code->length, temp, ebuf, emax)) == -1) {
                    330:                FREE(TYPED_MEM_TEMP, temp);
                    331:                if (emax > 0 && *ebuf == '\0')
                    332:                        strlcpy(ebuf, strerror(errno), emax);
                    333:                return (-1);
                    334:        }
1.1.1.2 ! misho     335:        assert((unsigned)clen <= code->length);
1.1       misho     336: 
                    337:        /* Replace existing item, freeing it first */
                    338:        (*type->uninit)(type, data);
                    339:        memcpy(data, temp, type->size);
                    340:        FREE(TYPED_MEM_TEMP, temp);
                    341: 
                    342:        /* Done */
                    343:        return (clen);
                    344: }
                    345: 
                    346: /*
                    347:  * Test for equality.
                    348:  */
                    349: int
                    350: structs_equal(const struct structs_type *type,
                    351:        const char *name, const void *data1, const void *data2)
                    352: {
                    353:        /* Find items */
                    354:        if (structs_find(type, name, (void **)&data1, 0) == NULL)
                    355:                return (-1);
                    356:        if ((type = structs_find(type, name, (void **)&data2, 0)) == NULL)
                    357:                return (-1);
                    358: 
                    359:        /* Compare them */
                    360:        return ((*type->equal)(type, data1, data2));
                    361: }
                    362: 
                    363: /*
                    364:  * Find an item in a structure.
                    365:  */
                    366: const struct structs_type *
                    367: structs_find(const struct structs_type *type, const char *name,
                    368:        void **datap, int set_union)
                    369: {
                    370:        void *data = *datap;
                    371:        const char *next;
                    372: 
                    373:        /* Empty string means stop recursing */
                    374:        if (name == NULL || *name == '\0')
                    375:                return (type);
                    376: 
                    377:        /* Primitive types don't have sub-elements */
                    378:        if (type->tclass == STRUCTS_TYPE_PRIMITIVE) {
                    379:                errno = ENOENT;
                    380:                return (NULL);
                    381:        }
                    382: 
                    383:        /* Dereference through pointer(s) */
                    384:        while (type->tclass == STRUCTS_TYPE_POINTER) {
                    385:                type = type->args[0].v;
                    386:                data = *((void **)data);
                    387:        }
                    388: 
                    389:        /* Get next name component */
                    390:        if ((next = strchr(name, STRUCTS_SEPARATOR)) != NULL)
                    391:                next++;
                    392: 
                    393:        /* Find element of aggregate structure update type and data */
                    394:        switch (type->tclass) {
                    395:        case STRUCTS_TYPE_ARRAY:
                    396:            {
                    397:                const struct structs_type *const etype = type->args[0].v;
                    398:                const struct structs_array *const ary = data;
                    399:                u_long index;
                    400:                char *eptr;
                    401: 
                    402:                /* Special handling for "length" */
                    403:                if (strcmp(name, "length") == 0) {
                    404:                        type = &structs_type_array_length;
                    405:                        data = (void *)&ary->length;
                    406:                        break;
                    407:                }
                    408: 
                    409:                /* Decode an index */
                    410:                index = strtoul(name, &eptr, 10);
                    411:                if (!isdigit(*name)
                    412:                    || eptr == name
                    413:                    || (*eptr != '\0' && *eptr != STRUCTS_SEPARATOR)) {
                    414:                        errno = ENOENT;
                    415:                        return (NULL);
                    416:                }
                    417:                if (index >= ary->length) {
                    418:                        errno = EDOM;
                    419:                        return (NULL);
                    420:                }
                    421:                type = etype;
                    422:                data = (char *)ary->elems + (index * etype->size);
                    423:                break;
                    424:            }
                    425:        case STRUCTS_TYPE_FIXEDARRAY:
                    426:            {
                    427:                const struct structs_type *const etype = type->args[0].v;
                    428:                const u_int length = type->args[2].i;
                    429:                u_long index;
                    430:                char *eptr;
                    431: 
                    432:                /* Special handling for "length" */
                    433:                if (strcmp(name, "length") == 0) {
                    434:                        type = &structs_type_array_length;
                    435:                        data = (void *)&type->args[2].i;
                    436:                        break;
                    437:                }
                    438: 
                    439:                /* Decode an index */
                    440:                index = strtoul(name, &eptr, 10);
                    441:                if (!isdigit(*name)
                    442:                    || eptr == name
                    443:                    || (*eptr != '\0' && *eptr != STRUCTS_SEPARATOR)) {
                    444:                        errno = ENOENT;
                    445:                        return (NULL);
                    446:                }
                    447:                if (index >= length) {
                    448:                        errno = EDOM;
                    449:                        return (NULL);
                    450:                }
                    451:                type = etype;
                    452:                data = (char *)data + (index * etype->size);
                    453:                break;
                    454:            }
                    455:        case STRUCTS_TYPE_STRUCTURE:
                    456:            {
                    457:                const struct structs_field *field;
                    458: 
                    459:                /* Find the field */
                    460:                for (field = type->args[0].v; field->name != NULL; field++) {
                    461:                        const size_t fnlen = strlen(field->name);
                    462: 
                    463:                        /* Handle field names with separator in them */
                    464:                        if (strncmp(name, field->name, fnlen) == 0
                    465:                            && (name[fnlen] == '\0'
                    466:                              || name[fnlen] == STRUCTS_SEPARATOR)) {
                    467:                                next = (name[fnlen] != '\0') ?
                    468:                                    name + fnlen + 1 : NULL;
                    469:                                break;
                    470:                        }
                    471:                }
                    472:                if (field->name == NULL) {
                    473:                        errno = ENOENT;
                    474:                        return (NULL);
                    475:                }
                    476:                type = field->type;
                    477:                data = (char *)data + field->offset;
                    478:                break;
                    479:            }
                    480:        case STRUCTS_TYPE_UNION:
                    481:            {
                    482:                const struct structs_ufield *const fields = type->args[0].v;
                    483:                const char *const mtype = type->args[1].s;
                    484:                struct structs_union *const un = data;
                    485:                const size_t oflen = strlen(un->field_name);
                    486:                const struct structs_ufield *ofield;
                    487:                const struct structs_ufield *field;
                    488:                void *new_un;
                    489:                void *data2;
                    490: 
                    491:                /* Special handling for "field_name" */
                    492:                if (strcmp(name, "field_name") == 0) {
                    493:                        type = &structs_type_union_field_name;
                    494:                        data = (void *)&un->field_name;
                    495:                        break;
                    496:                }
                    497: 
                    498:                /* Find the old field */
                    499:                for (ofield = fields; ofield->name != NULL; ofield++) {
                    500:                        if (strcmp(ofield->name, un->field_name) == 0)
                    501:                                break;
                    502:                }
                    503:                if (ofield->name == NULL) {
                    504:                        assert(0);
                    505:                        errno = EINVAL;
                    506:                        return (NULL);
                    507:                }
                    508: 
                    509:                /*
                    510:                 * Check if the union is already set to the desired field,
                    511:                 * handling field names with the separator char in them.
                    512:                 */
                    513:                if (strncmp(name, un->field_name, oflen) == 0
                    514:                    && (name[oflen] == '\0'
                    515:                      || name[oflen] == STRUCTS_SEPARATOR)) {
                    516:                        next = (name[oflen] != '\0') ? name + oflen + 1 : NULL;
                    517:                        field = ofield;
                    518:                        goto union_done;
                    519:                }
                    520: 
                    521:                /* Is modifying the union to get the right name acceptable? */
                    522:                if (!set_union) {
                    523:                        errno = ENOENT;
                    524:                        return (NULL);
                    525:                }
                    526: 
                    527:                /* Find the new field */
                    528:                for (field = fields; field->name != NULL; field++) {
                    529:                        const size_t fnlen = strlen(field->name);
                    530: 
                    531:                        /* Handle field names with separator in them */
                    532:                        if (strncmp(name, field->name, fnlen) == 0
                    533:                            && (name[fnlen] == '\0'
                    534:                              || name[fnlen] == STRUCTS_SEPARATOR)) {
                    535:                                next = (name[fnlen] != '\0') ?
                    536:                                    name + fnlen + 1 : NULL;
                    537:                                break;
                    538:                        }
                    539:                }
                    540:                if (field->name == NULL) {
                    541:                        errno = ENOENT;
                    542:                        return (NULL);
                    543:                }
                    544: 
                    545:                /* Create a new union with the new field type */
                    546:                if ((new_un = MALLOC(mtype, field->type->size)) == NULL)
                    547:                        return (NULL);
                    548:                if ((*field->type->init)(field->type, new_un) == -1) {
                    549:                        FREE(mtype, new_un);
                    550:                        return (NULL);
                    551:                }
                    552: 
                    553:                /* See if name would be found with new union instead of old */
                    554:                data2 = new_un;
                    555:                if (next != NULL
                    556:                    && structs_find(field->type, next, &data2, 1) == NULL) {
                    557:                        (*field->type->uninit)(field->type, new_un);
                    558:                        FREE(mtype, new_un);
                    559:                        return (NULL);
                    560:                }
                    561: 
                    562:                /* Replace existing union with new one having desired type */
                    563:                (*ofield->type->uninit)(ofield->type, un->un);
                    564:                FREE(mtype, un->un);
                    565:                un->un = new_un;
                    566:                *((const char **)&un->field_name) = field->name;
                    567: 
                    568:        union_done:
                    569:                /* Continue recursing */
                    570:                type = field->type;
                    571:                data = un->un;
                    572:                break;
                    573:            }
                    574:        default:
                    575:                assert(0);
                    576:                return (NULL);
                    577:        }
                    578: 
                    579:        /* Recurse on sub-element */
                    580:        if ((type = structs_find(type, next, &data, set_union)) == NULL)
                    581:                return (NULL);
                    582: 
                    583:        /* Done */
                    584:        *datap = data;
                    585:        return (type);
                    586: }
                    587: 
                    588: /*
                    589:  * Traverse a structure.
                    590:  */
                    591: 
                    592: struct structs_trav {
                    593:        char            **list;
                    594:        u_int           len;
                    595:        u_int           alloc;
                    596:        const char      *mtype;
                    597: };
                    598: 
                    599: static int     structs_trav(struct structs_trav *t, const char *name,
                    600:                        const struct structs_type *type, const void *data);
                    601: 
                    602: int
                    603: structs_traverse(const struct structs_type *type,
                    604:        const void *data, char ***listp, const char *mtype)
                    605: {
                    606:        struct structs_trav t;
                    607: 
                    608:        /* Initialize traversal structure */
                    609:        memset(&t, 0, sizeof(t));
                    610:        t.mtype = mtype;
                    611: 
                    612:        /* Recurse */
                    613:        if (structs_trav(&t, "", type, data) == -1) {
                    614:                while (t.len > 0)
                    615:                        FREE(t.mtype, t.list[--t.len]);
                    616:                FREE(t.mtype, t.list);
                    617:                return (-1);
                    618:        }
                    619: 
                    620:        /* Return the result */
                    621:        *listp = t.list;
                    622:        return (t.len);
                    623: }
                    624: 
                    625: static int
                    626: structs_trav(struct structs_trav *t, const char *name,
                    627:        const struct structs_type *type, const void *data)
                    628: {
                    629:        const char *const dot = (*name == '\0' ? "" : ".");
                    630:        char *ename;
1.1.1.2 ! misho     631:        unsigned i;
1.1       misho     632: 
                    633:        /* Dereference through pointer(s) */
                    634:        while (type->tclass == STRUCTS_TYPE_POINTER) {
                    635:                type = type->args[0].v;
                    636:                data = *((void **)data);
                    637:        }
                    638: 
                    639:        switch (type->tclass) {
                    640:        case STRUCTS_TYPE_PRIMITIVE:
                    641:            {
                    642:                /* Grow list as necessary */
                    643:                if (t->len == t->alloc) {
                    644:                        u_int new_alloc;
                    645:                        char **new_list;
                    646: 
                    647:                        new_alloc = (t->alloc + 32) * 2;
                    648:                        if ((new_list = REALLOC(t->mtype,
                    649:                            t->list, new_alloc * sizeof(*t->list))) == NULL)
                    650:                                return (-1);
                    651:                        t->list = new_list;
                    652:                        t->alloc = new_alloc;
                    653:                }
                    654: 
                    655:                /* Add new name to list */
                    656:                if ((t->list[t->len] = STRDUP(t->mtype, name)) == NULL)
                    657:                        return (-1);
                    658:                t->len++;
                    659: 
                    660:                /* Done */
                    661:                return (0);
                    662:            }
                    663: 
                    664:        case STRUCTS_TYPE_ARRAY:
                    665:            {
                    666:                const struct structs_type *const etype = type->args[0].v;
                    667:                const struct structs_array *const ary = data;
                    668: 
                    669:                /* Iterate over array elements */
                    670:                for (i = 0; i < ary->length; i++) {
                    671:                        const void *const edata
                    672:                            = (char *)ary->elems + (i * etype->size);
                    673: 
                    674:                        if (ASPRINTF(t->mtype,
1.1.1.2 ! misho     675:                            &ename, "%s%s%u", name, dot, i) == -1)
1.1       misho     676:                                return (-1);
                    677:                        if (structs_trav(t, ename, etype, edata) == -1) {
                    678:                                FREE(t->mtype, ename);
                    679:                                return (-1);
                    680:                        }
                    681:                        FREE(t->mtype, ename);
                    682:                }
                    683: 
                    684:                /* Done */
                    685:                return (0);
                    686:            }
                    687: 
                    688:        case STRUCTS_TYPE_FIXEDARRAY:
                    689:            {
                    690:                const struct structs_type *const etype = type->args[0].v;
                    691:                const u_int length = type->args[2].i;
                    692: 
                    693:                /* Iterate over array elements */
                    694:                for (i = 0; i < length; i++) {
                    695:                        const void *const edata
                    696:                            = (char *)data + (i * etype->size);
                    697: 
                    698:                        if (ASPRINTF(t->mtype,
1.1.1.2 ! misho     699:                            &ename, "%s%s%u", name, dot, i) == -1)
1.1       misho     700:                                return (-1);
                    701:                        if (structs_trav(t, ename, etype, edata) == -1) {
                    702:                                FREE(t->mtype, ename);
                    703:                                return (-1);
                    704:                        }
                    705:                        FREE(t->mtype, ename);
                    706:                }
                    707: 
                    708:                /* Done */
                    709:                return (0);
                    710:            }
                    711: 
                    712:        case STRUCTS_TYPE_STRUCTURE:
                    713:            {
                    714:                const struct structs_field *field;
                    715: 
                    716:                /* Iterate over structure fields */
                    717:                for (field = type->args[0].v; field->name != NULL; field++) {
                    718:                        const void *const edata
                    719:                            = (char *)data + field->offset;
                    720: 
                    721:                        if (ASPRINTF(t->mtype,
                    722:                            &ename, "%s%s%s", name, dot, field->name) == -1)
                    723:                                return (-1);
                    724:                        if (structs_trav(t, ename, field->type, edata) == -1) {
                    725:                                FREE(t->mtype, ename);
                    726:                                return (-1);
                    727:                        }
                    728:                        FREE(t->mtype, ename);
                    729:                }
                    730: 
                    731:                /* Done */
                    732:                return (0);
                    733:            }
                    734: 
                    735:        case STRUCTS_TYPE_UNION:
                    736:            {
                    737:                const struct structs_ufield *const fields = type->args[0].v;
                    738:                const struct structs_union *const un = data;
                    739:                const struct structs_ufield *field;
                    740: 
                    741:                /* Find field */
                    742:                for (field = fields; field->name != NULL
                    743:                    && strcmp(un->field_name, field->name) != 0; field++);
                    744:                if (field->name == NULL) {
                    745:                        assert(0);
                    746:                        errno = EINVAL;
                    747:                        return (-1);
                    748:                }
                    749: 
                    750:                /* Do selected union field */
                    751:                if (ASPRINTF(t->mtype,
                    752:                    &ename, "%s%s%s", name, dot, field->name) == -1)
                    753:                        return (-1);
                    754:                if (structs_trav(t, ename, field->type, un->un) == -1) {
                    755:                        FREE(t->mtype, ename);
                    756:                        return (-1);
                    757:                }
                    758:                FREE(t->mtype, ename);
                    759: 
                    760:                /* Done */
                    761:                return (0);
                    762:            }
                    763: 
                    764:        default:
                    765:                assert(0);
                    766:                errno = ECONNABORTED;
                    767:                return (-1);
                    768:        }
                    769: }
                    770: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>