STRUCTS_TYPE(3)

NAME
structs_type - data structure description structure

LIBRARY
PDEL Library (libpdel, -lpdel)

SYNOPSIS
#include <sys/types.h>
#include <pdel/structs/structs.h>

DESCRIPTION
A structs type defines information about, and provides methods for dealing with, instances of a particular data structure. This information enables the structs(3) library to access instances of the data structure in a consistent and automated fashion.

A structs type is defined by a struct structs_type:

    struct structs_type {
        size_t                  size;       /* size of an instance */
        const char              *name;      /* human informative name */
        int                     tclass;     /* type class */
        structs_init_t          *init;      /* type "init" method */
        structs_copy_t          *copy;      /* type "copy" method */
        structs_equal_t         *equal;     /* type "equal" method */
        structs_ascify_t        *ascify;    /* type "ascify" method */
        structs_binify_t        *binify;    /* type "binify" method */
        structs_encode_t        *encode;    /* type "encode" method */
        structs_decode_t        *decode;    /* type "decode" method */
        structs_uninit_t        *uninit;    /* type "uninit" method */
        union {                             /* type specific arguments */
                const void      *v;
                const char      *s;
                int             i;
        }                       args[3];
    };

size is equal to the size of one instance of the data structure.

The name is ignored by the structs library, but is useful for debugging purposes.

tclass is an internal field used by the structs library. For completeness, the possible values are:

    STRUCTS_TYPE_PRIMITIVE      Primitive type
    STRUCTS_TYPE_POINTER        Pointer
    STRUCTS_TYPE_ARRAY          Variable length array
    STRUCTS_TYPE_FIXEDARRAY     Fixed length array
    STRUCTS_TYPE_STRUCTURE      Structure type
    STRUCTS_TYPE_UNION          Union

For user-defined types, STRUCTS_TYPE_PRIMITIVE should always be used.

The init() method has this type:

    typedef int structs_init_t(const struct structs_type *type,
                    void *data);

It should initialize the uninitialized region of memory pointed to by data to be an instance of the type. The instance should be equal to the default value for the type. On success, init() returns zero; otherwise, it returns -1 and sets errno appropriately, and no resources have been allocated.

The copy() method has this type:

    typedef int structs_copy_t(const struct structs_type *type,
                    const void *from, void *to);

It should initialize the uninitialized region of memory pointed to by to to be a new instance of the type equal to the instance pointed to by from. On success, copy() returns zero; otherwise, it returns -1 and sets errno appropriately, and no resources have been allocated.

The equal() method has this type:

    typedef int structs_equal_t(const struct structs_type *type,
                    const void *data1, const void *data2);

data1 and data2 point to initialized instances of the type type. equal() should return 1 if the two instances are equal, or 0 if not. If an error occurs, equal() returns -1 and sets errno appropriately.

The ascify() method has this type:

    typedef char *structs_ascify_t(const struct structs_type *type,
                      const char *mtype, const void *data);

data points to an initialized instance of the type type. ascify() should convert this instance into an ASCII string terminated with '\0' and stored in a buffer allocated with typed_mem(3) type mtype. The ASCII string must be unique, in the sense that it can be used as input to the binify() method to create an instance equal to the original data. If successful, ascify() returns the ASCII string buffer; otherwise it returns NULL and sets errno appropriately.

The binify() method has this type:

    typedef int structs_binify_t(const struct structs_type *type,
                    const char *ascii, void *data,
                    char *ebuf, size_t emax);

data points to an uninitialized region of memory large enough to hold an instance of the type type. binify() should convert the ASCII string pointed to by ascii into an instance stored at data, thus initializing the memory, and return zero. If an error occurs, data should remain uninitialized and binify() should return -1; it may also optionally write an explanatory error message, including '\0' byte, into the character buffer having length emax and pointed to by ebuf (see snprintf(3)). binify() must successfully convert any ASCII string returned by ascify(). However, ascii is by no means guaranteed to be valid; binify() must gracefully handle any invalid input string by returning an error instead of crashing.

The encode() method has this type:

    typedef int structs_encode_t(const struct structs_type *type,
                    const char *mtype, struct structs_data *code,
                    const void *data);

data points to an initialized instance of the type type. encode() should encode the instance into a machine independent, self-delimiting sequence of bytes. The sequence should be stored in a buffer allocated with typed_mem(3) type mtype. The code structure, shown below, should be filled in with the buffer start and length:

    struct structs_data {
            u_int     length;       /* number of bytes */
            u_char    *data;        /* byte sequence */
    };

The binary sequence must be unique, in the sense that it can be used as input to the decode() method to create an instance equal to the original data. encode() returns 0 if successful; otherwise it returns -1 and sets errno appropriately and does not allocate any memory.

The decode() method has this type:

    typedef int structs_decode_t(const struct structs_type *type,
                    const u_char *code, size_t cmax, void *data,
                    char *ebuf, size_t emax);

data points to an uninitialized region of memory large enough to hold an instance of the type type. decode() should convert the binary sequence pointed to by code into an instance stored at data, thus initializing the memory. decode() should return the number of bytes consumed, of the cmax total bytes available. Note that cmax bytes may include additional bytes beyond those necessary for decoding one instance of type; this is why encodings generated by encode() must be self-delimiting. If an error occurs, data should remain uninitialized and decode() should return -1; it may also optionally write an explanatory error message, including '\0' byte, into the character buffer having length emax and pointed to by ebuf (see snprintf(3)). decode() must successfully convert any byte sequence generated by encode(). However, the sequence defined by code and cmax is by no means guaranteed to be valid, have any particular length, etc. decode() must gracefully handle any invalid input sequence by returning an error instead of crashing.

The uninit() method has this type:

    typedef void structs_uninit_t(const struct structs_type *type,
                     void *data);

data points to an initialized instance of the type type. uninit() should free any resources allocated on behalf of the instance, returning the memory region to an uninitialized state.

The args array is useful for when the same functions are used to implement several distinct but related types.

  Predefined Methods
The following structs type methods are defined in the structs(3) library:

structs_region_init()
    init() method that fills in the region of memory with zeros.

structs_region_copy()
    copy() method that copies the instance using memcpy(3).

structs_region_equal()
    equal() method that compares two instances using memcmp(3).

structs_region_encode()
    encode() method that encodes an instance by directly copying the bytes. Note: this method is incorrect for host-order dependent data.

structs_region_decode()
    Decodes data encoded by structs_region_encode().

structs_region_encode_netorder()
    encode() method that encodes an instance by copying it, after arranging the bytes in network order. Only valid for data types that have size 16 bytes or less.

structs_region_decode_netorder()
    Decodes data encoded by structs_region_encode_netorder().

structs_nothing_free()
    free() method that does nothing.

structs_ascii_copy()
    copy() method that copies an instance by converting it to ASCII and back. This should work for any primitive type.

structs_string_encode()

structs_string_decode()
    encode() and decode() methods that encode an instance by converting it to a NUL-terminated ASCII string. These methods should work for any primitive type.

structs_notsupp_init()
    encode() method that always returns -1 with errno set to ENOTSUPP.

structs_notsupp_copy()
    copy() method that always returns -1 with errno set to ENOTSUPP.

structs_notsupp_equal()
    equal() method that always returns -1 with errno set to ENOTSUPP.

structs_notsupp_ascify()
    ascify() method that always returns -1 with errno set to ENOTSUPP.

structs_notsupp_binify()
    binify() method that always returns -1 with errno set to ENOTSUPP.

structs_notsupp_encode()
    encode() method that always returns -1 with errno set to ENOTSUPP.

structs_notsupp_decode()
    decode() method that always returns -1 with errno set to ENOTSUPP.

RETURN VALUES
All of the above functions indicate an error condition by returning either -1 or NULL and setting errno to an appropriate value.

Whenever there is an error, no partial work is done: the state of the parameters has not changed, and nothing has been allocated or freed.

SEE ALSO
libpdel(3), snprintf(3), structs(3), structs_type_array(3), structs_type_boolean(3), structs_type_bpf(3), structs_type_data(3), structs_type_dnsname(3), structs_type_ether(3), structs_type_float(3), structs_type_id(3), structs_type_int(3), structs_type_ip4(3), structs_type_ip6(3), structs_type_null(3), structs_type_pointer(3), structs_type_regex(3), structs_type_string(3), structs_type_struct(3), structs_type_time(3), structs_type_union(3), typed_mem(3)

HISTORY
The PDEL library was developed at Packet Design, LLC. http://www.packetdesign.com/

AUTHORS
Archie Cobbs <archie@packetdesign.com>

BUGS
Instead of the tclass field, each type should provide its own method for accessing sub-elements as appropriate.