File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libpdel / structs / structs.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:25:53 2012 UTC (13 years, 1 month ago) by misho
Branches: libpdel, MAIN
CVS tags: v0_5_3, HEAD
libpdel

    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: 	}
  335: 	assert(clen <= code->length);
  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;
  631: 	int i;
  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,
  675: 			    &ename, "%s%s%d", name, dot, i) == -1)
  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,
  699: 			    &ename, "%s%s%d", name, dot, i) == -1)
  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>