/*
 * Copyright (C) 2013 Red Hat, Inc. All rights reserved.
 *
 * This file is part of LVM2.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License v.2.1.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
#ifndef _LVM_PROP_COMMON_H
#define _LVM_PROP_COMMON_H

#include <stdint.h>

/*
 * Common code for getting and setting properties.
 */

struct lvm_property_type {
	unsigned type;
	const char *id;
	unsigned is_settable:1;
	unsigned is_string:1;
	unsigned is_integer:1;
	unsigned is_signed:1;
	union {
		const char *string;
		uint64_t integer;
		int64_t signed_integer;
	} value;
	int (*get) (const void *obj, struct lvm_property_type *prop);
	int (*set) (void *obj, struct lvm_property_type *prop);
};

int prop_not_implemented_get(const void *obj, struct lvm_property_type *prop);
int prop_not_implemented_set(void *obj, struct lvm_property_type *prop);

int prop_get_property(struct lvm_property_type *p, const void *obj,
		struct lvm_property_type *prop,
		unsigned type);
int prop_set_property(struct lvm_property_type *p, void *obj,
		struct lvm_property_type *prop,
		unsigned type);

#define GET_NUM_PROPERTY_FN(NAME, VALUE, TYPE, VAR)			\
static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \
{ \
	const struct TYPE *VAR = (const struct TYPE *)obj; \
\
	prop->value.integer = VALUE; \
	return 1; \
}

#define SET_NUM_PROPERTY_FN(NAME, SETFN, TYPE, VAR)			\
static int _ ## NAME ## _set (void *obj, struct lvm_property_type *prop) \
{ \
	struct TYPE *VAR = (struct TYPE *)obj; \
\
	SETFN(VAR, prop->value.integer);		\
	return 1; \
}

#define SET_NUM_PROPERTY(NAME, VALUE, TYPE, VAR)			\
static int _ ## NAME ## _set (void *obj, struct lvm_property_type *prop) \
{ \
	struct TYPE *VAR = (struct TYPE *)obj; \
\
	VALUE = prop->value.integer;		\
	return 1; \
}

#define GET_STR_PROPERTY_FN(NAME, VALUE, TYPE, VAR)			\
static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \
{ \
	const struct TYPE *VAR = (const struct TYPE *)obj; \
\
	prop->value.string = (char *)VALUE;	\
	return 1; \
}

/*
 * The 'FIELD' macro arguments are defined as follows:
 * 1. report_type.  An enum value that selects a specific
 * struct dm_report_object_type in the _report_types array.  The value is
 * used to select the containing base object address (see *obj_get*
 * functions) for any data values of any field in the report.
 * 2. Containing struct.  The structure that either contains the field data
 * as a member or should be used to obtain the field data.  The containing
 * struct should match the base object of the report_type.
 * 3. Field type.  This must be either 'STR' or 'NUM'.
 * 4. Report heading.  This is the field heading that is displayed by the
 * reporting commands.
 * 5. Data value pointer.  This argument is always a member of the
 * containing struct.  It may point directly to the data value (for example,
 * lv_uuid - see _uuid_disp()) or may be used to derive the data value (for
 * example, seg_count - see _lvsegcount_disp()).  In the FIELD macro
 * definition, it is used in an offset calculation to derive the offset to
 * the data value from the containing struct base address.  Note that in some
 * cases, the argument is the first member of the struct, in which case the
 * data value pointer points to the start of the struct itself (for example,
 * 'lvid' field of struct 'lv').
 * 6. Minimum display width.  This is the minimum width used to display
 * the field value, typically matching the width of the column heading.
 * 7. Display function identifier.  Used to derive the full name of the
 * function that displays this field.  Derivation is done by appending '_'
 * then prepending this argument to '_disp'.  For example, if this argument
 * is 'uuid', the display function is _uuid_disp().  Adding a new field may
 * require defining a new display function (for example _myfieldname_disp()),
 * or reuse of an existing one (for example, _uint32_disp()).
 * 8. Unique format identifier / field id.  This name must be unique and is
 * used to select fields via '-o' in the reporting commands (pvs/vgs/lvs).
 * The string used to specify the field - the 'id' member of
 * struct dm_report_field_type.
 * 9. Description of field.  This is a brief (ideally <= 52 chars) description
 * of the field used in the reporting commands.
 * 10. Flags.
 *     FIELD_MODIFIABLE.  A '_set' function exists to change the field's value.
 *     The function name is derived in a similar way to item 7 above.
 */

#define STR 1
#define NUM 2
#define BIN 3
#define SIZ 4
#define PCT 5
#define TIM 6
#define SNUM 7              /* Signed Number */
#define STR_LIST 8

#define FIELD_MODIFIABLE 0x00000001
#define FIELD(type, strct, field_type, head, field, width, fn, id, desc, settable) \
	{ type, #id, settable, (field_type == STR || field_type == STR_LIST), ((field_type == NUM) || (field_type == BIN) || (field_type == SIZ) || (field_type == PCT) || (field_type == SNUM)), ((field_type == SNUM) || (field_type == PCT)), { .integer = 0 }, _ ## id ## _get, _ ## id ## _set },

#endif
