Return to structs.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / contrib / libpdel / structs |
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: } 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: