Blame src/marshal.h

Packit e9ba0d
/* -*- mode: c; c-file-style: "openbsd" -*- */
Packit e9ba0d
/*
Packit e9ba0d
 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
Packit e9ba0d
 *
Packit e9ba0d
 * Permission to use, copy, modify, and/or distribute this software for any
Packit e9ba0d
 * purpose with or without fee is hereby granted, provided that the above
Packit e9ba0d
 * copyright notice and this permission notice appear in all copies.
Packit e9ba0d
 *
Packit e9ba0d
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Packit e9ba0d
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Packit e9ba0d
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Packit e9ba0d
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit e9ba0d
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Packit e9ba0d
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Packit e9ba0d
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
#ifndef _MARSHAL_H
Packit e9ba0d
#define _MARSHAL_H
Packit e9ba0d
Packit e9ba0d
#include <stddef.h>
Packit e9ba0d
#include <sys/types.h>
Packit e9ba0d
Packit e9ba0d
struct marshal_info;
Packit e9ba0d
enum marshal_subinfo_kind {
Packit e9ba0d
	pointer,
Packit e9ba0d
	substruct,
Packit e9ba0d
	ignore,
Packit e9ba0d
};
Packit e9ba0d
#define MARSHAL_INFO_POINTER 1
Packit e9ba0d
#define MARSHAL_INFO_SUB     2
Packit e9ba0d
struct marshal_subinfo {
Packit e9ba0d
	size_t offset;	     /* Offset compared to parent structure */
Packit e9ba0d
	size_t offset2;	     /* Ancillary offset (for related data) */
Packit e9ba0d
	enum marshal_subinfo_kind kind; /* Kind of substructure */
Packit e9ba0d
	struct  marshal_info *mi;
Packit e9ba0d
};
Packit e9ba0d
#define MARSHAL_SUBINFO_NULL { .offset = 0, .offset2 = 0, .kind = ignore, .mi = NULL }
Packit e9ba0d
struct marshal_info {
Packit e9ba0d
	char   *name;		/* Name of structure */
Packit e9ba0d
	size_t  size;		/* Size of the structure */
Packit e9ba0d
#if defined __GNUC__ && __GNUC__ < 3
Packit e9ba0d
	/* With gcc 2.96, flexible arrays are not supported, even with
Packit e9ba0d
	 * -std=gnu99. And with gcc 3.x, zero-sized arrays cannot be statically
Packit e9ba0d
	 * initialized (with more than one element). */
Packit e9ba0d
	struct marshal_subinfo pointers[0]; /* Pointer to other structures */
Packit e9ba0d
#else
Packit e9ba0d
	struct marshal_subinfo pointers[]; /* Pointer to other structures */
Packit e9ba0d
#endif
Packit e9ba0d
};
Packit e9ba0d
/* Special case for strings */
Packit e9ba0d
extern struct marshal_info marshal_info_string;
Packit e9ba0d
extern struct marshal_info marshal_info_fstring;
Packit e9ba0d
extern struct marshal_info marshal_info_ignore;
Packit e9ba0d
Packit e9ba0d
/* Declare a new marshal_info struct named after the type we want to
Packit e9ba0d
   marshal. The marshalled type has to be a structure. */
Packit e9ba0d
#define MARSHAL_INFO(type) marshal_info_##type
Packit e9ba0d
#ifdef MARSHAL_EXPORT
Packit e9ba0d
#define MARSHAL_HELPER_FUNCTIONS(type, ttype)			\
Packit e9ba0d
	ssize_t							\
Packit e9ba0d
	type ## _serialize(ttype *source, void *buffer) {	\
Packit e9ba0d
		return marshal_serialize(type,			\
Packit e9ba0d
		    source, buffer);				\
Packit e9ba0d
	}							\
Packit e9ba0d
	size_t							\
Packit e9ba0d
	type ## _unserialize(void *buffer, size_t len,		\
Packit e9ba0d
	    ttype **destination) {				\
Packit e9ba0d
		void *p;					\
Packit e9ba0d
		size_t rc;					\
Packit e9ba0d
		rc = marshal_unserialize(type,			\
Packit e9ba0d
		    buffer, len, &p);				\
Packit e9ba0d
		if (rc <= 0) return rc;				\
Packit e9ba0d
		*destination = p;				\
Packit e9ba0d
		return rc;					\
Packit e9ba0d
	}
Packit e9ba0d
#define MARSHAL_BEGIN(type) struct marshal_info MARSHAL_INFO(type) =	\
Packit e9ba0d
	{								\
Packit e9ba0d
		.name = #type,						\
Packit e9ba0d
		.size = sizeof(struct type),				\
Packit e9ba0d
		.pointers = {
Packit e9ba0d
#define MARSHAL_ADD(_kind, type, subtype, member)		\
Packit e9ba0d
	{ .offset = offsetof(struct type, member),		\
Packit e9ba0d
	  .offset2 = 0,						\
Packit e9ba0d
	  .kind = _kind,					\
Packit e9ba0d
	  .mi = &MARSHAL_INFO(subtype) },
Packit e9ba0d
#define MARSHAL_FSTR(type, member, len)				\
Packit e9ba0d
	{ .offset = offsetof(struct type, member),		\
Packit e9ba0d
	  .offset2 = offsetof(struct type, len),		\
Packit e9ba0d
	  .kind = pointer,					\
Packit e9ba0d
	  .mi = &marshal_info_fstring },
Packit e9ba0d
#define MARSHAL_END(type) MARSHAL_SUBINFO_NULL }};		\
Packit e9ba0d
	MARSHAL_HELPER_FUNCTIONS(type, struct type)
Packit e9ba0d
#else
Packit e9ba0d
#define MARSHAL_HELPER_FUNCTIONS(type, ttype)			\
Packit e9ba0d
	ssize_t type ## _serialize(ttype*, void*);		\
Packit e9ba0d
	size_t type ## _unserialize(void*, size_t, ttype**);
Packit e9ba0d
#define MARSHAL_BEGIN(type) extern struct marshal_info MARSHAL_INFO(type);
Packit e9ba0d
#define MARSHAL_ADD(...)
Packit e9ba0d
#define MARSHAL_FSTR(...)
Packit e9ba0d
#define MARSHAL_END(type) MARSHAL_HELPER_FUNCTIONS(type, struct type)
Packit e9ba0d
#endif
Packit e9ba0d
/* Shortcuts */
Packit e9ba0d
#define MARSHAL_POINTER(...) MARSHAL_ADD(pointer, ##__VA_ARGS__)
Packit e9ba0d
#define MARSHAL_SUBSTRUCT(...) MARSHAL_ADD(substruct, ##__VA_ARGS__)
Packit e9ba0d
#define MARSHAL_STR(type, member) MARSHAL_ADD(pointer, type, string, member)
Packit e9ba0d
#define MARSHAL_IGNORE(type, member) MARSHAL_ADD(ignore, type, ignore, member)
Packit e9ba0d
#define MARSHAL_TQE(type, field)			 \
Packit e9ba0d
	MARSHAL_POINTER(type, type, field.tqe_next)	 \
Packit e9ba0d
	MARSHAL_IGNORE(type, field.tqe_prev)
Packit e9ba0d
/* Support for TAILQ list is partial. Access to last and previous
Packit e9ba0d
   elements is not available. Some operations are therefore not
Packit e9ba0d
   possible. However, TAILQ_FOREACH is still
Packit e9ba0d
   available. */
Packit e9ba0d
#define MARSHAL_TQH(type, subtype)			 \
Packit e9ba0d
	MARSHAL_POINTER(type, subtype, tqh_first)	 \
Packit e9ba0d
	MARSHAL_IGNORE(type, tqh_last)
Packit e9ba0d
#define MARSHAL_SUBTQ(type, subtype, field)		 \
Packit e9ba0d
	MARSHAL_POINTER(type, subtype, field.tqh_first)	 \
Packit e9ba0d
	MARSHAL_IGNORE(type, field.tqh_last)
Packit e9ba0d
#define MARSHAL(type)			\
Packit e9ba0d
	MARSHAL_BEGIN(type)		\
Packit e9ba0d
	MARSHAL_END(type)
Packit e9ba0d
#define MARSHAL_TQ(type, subtype)	\
Packit e9ba0d
	MARSHAL_BEGIN(type)		\
Packit e9ba0d
	MARSHAL_TQH(type, subtype)	\
Packit e9ba0d
	MARSHAL_END(type)
Packit e9ba0d
Packit e9ba0d
/* Serialization */
Packit e9ba0d
ssize_t  marshal_serialize_(struct marshal_info *, void *, void **, int, void *, int)
Packit e9ba0d
	__attribute__((nonnull (1, 2, 3) ));
Packit e9ba0d
#define marshal_serialize(type, o, output) marshal_serialize_(&MARSHAL_INFO(type), o, output, 0, NULL, 0)
Packit e9ba0d
Packit e9ba0d
/* Unserialization */
Packit e9ba0d
size_t  marshal_unserialize_(struct marshal_info *, void *, size_t, void **, void*, int, int)
Packit e9ba0d
	__attribute__((nonnull (1, 2, 4) ));
Packit e9ba0d
#define marshal_unserialize(type, o, l, input) \
Packit e9ba0d
	marshal_unserialize_(&MARSHAL_INFO(type), o, l, input, NULL, 0, 0)
Packit e9ba0d
Packit e9ba0d
#define marshal_repair_tailq(type, head, field)				\
Packit e9ba0d
	do {								\
Packit e9ba0d
		struct type *__item, *__item_next;			\
Packit e9ba0d
		(head)->tqh_last = &(head)->tqh_first;			\
Packit e9ba0d
		for (__item = TAILQ_FIRST(head);			\
Packit e9ba0d
		     __item != NULL;					\
Packit e9ba0d
		     __item = __item_next) {				\
Packit e9ba0d
			__item_next = TAILQ_NEXT(__item, field);	\
Packit e9ba0d
			__item->field.tqe_prev = (head)->tqh_last;	\
Packit e9ba0d
			*(head)->tqh_last = __item;			\
Packit e9ba0d
			(head)->tqh_last = &__item->field.tqe_next;	\
Packit e9ba0d
		}							\
Packit e9ba0d
	} while(0)
Packit e9ba0d
Packit e9ba0d
#endif