OpenSolaris_b135/lib/libtnf/array.c

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 *	Copyright (c) 1994, by Sun Microsytems, Inc.
 */

#pragma	ident	"%Z%%M%	%I%	%E% SMI"

#include "libtnf.h"

/*
 * XXX This module assumes that all arrays are self-sized records.
 */

/*
 *
 */

static struct taginfo *	get_array_info(
	tnf_datum_t,
	struct taginfo **base,
	struct taginfo **elt,
	struct taginfo **elt_base);

/*
 * XXX Assumes arrays are (self-sized) records
 */

void
_tnf_check_array(tnf_datum_t datum)
{
	struct taginfo	*info;

	CHECK_RECORD(datum);		/* XXX */

	info = DATUM_INFO(datum);

	if (!INFO_ARRAY(info))
		_tnf_error(DATUM_TNF(datum), TNF_ERR_TYPEMISMATCH);

}

/*
 * Helper
 */

static struct taginfo *
get_array_info(
	tnf_datum_t datum,
	struct taginfo **basep,
	struct taginfo **eltp,
	struct taginfo **elt_basep)
{
	struct taginfo	*info, *base, *elt, *elt_base;

	info	= DATUM_INFO(datum);
	base	= INFO_DERIVED(info) ? info->base : info;

	if (INFO_DERIVED(base) || (!INFO_ARRAY(base)))
		_tnf_error(DATUM_TNF(datum), TNF_ERR_INTERNAL);

	elt 	= base->base;	/* XXX base slot is reused for elttype */
	elt_base = INFO_DERIVED(elt) ? elt->base : elt;

	*basep	= base;
	*eltp	= elt;
	*elt_basep = elt_base;
	return (info);
}

/*
 * Return number of elements in array
 */

unsigned
tnf_get_element_count(tnf_datum_t datum)
{
	size_t		hdr_size, elt_size, self_size;
	struct taginfo	*base, *elt, *elt_base;

	CHECK_ARRAY(datum);

	(void) get_array_info(datum, &base, &elt, &elt_base);
	hdr_size	= base->hdrsize;
	elt_size	= INFO_ELEMENT_SIZE(elt_base);
	self_size	= _tnf_get_self_size(DATUM_TNF(datum),
		/* LINTED pointer cast may result in improper alignment */
				DATUM_RECORD(datum));
	return (((self_size - hdr_size) / elt_size));
}

/*
 * Fetch indexed element
 */

tnf_datum_t
tnf_get_element(tnf_datum_t datum, unsigned index)
{
	size_t		hdr_size, elt_size, self_size;
	struct taginfo	*base, *elt, *elt_base;
	unsigned	count, offset;

	CHECK_ARRAY(datum);

	(void) get_array_info(datum, &base, &elt, &elt_base);
	hdr_size	= base->hdrsize;
	elt_size	= INFO_ELEMENT_SIZE(elt_base);
	self_size	= _tnf_get_self_size(DATUM_TNF(datum),
		/* LINTED pointer cast may result in improper alignment */
				DATUM_RECORD(datum));

	count		= (self_size - hdr_size) / elt_size;

	if (index >= count)
		_tnf_error(DATUM_TNF(datum), TNF_ERR_BADINDEX);

	offset		= hdr_size + (index * elt_size);

	/*
	 * If tagged, use the tag to construct datum
	 */
	if (INFO_TAGGED(elt)) {
		TNF		*tnf;
		tnf_ref32_t	*rec;

		tnf = DATUM_TNF(datum);
		/* LINTED pointer cast may result in improper alignment */
		rec = _GET_REF32(tnf, (tnf_ref32_t *)
			(DATUM_VAL(datum) + offset));
		/* NULL elements are allowed */
		return ((rec == TNF_NULL)? TNF_DATUM_NULL :
			RECORD_DATUM(tnf, rec));
	} else
		return (DATUM(elt, DATUM_VAL(datum) + offset));
}

/*
 * Return element type of array
 */

tnf_datum_t
tnf_get_element_type(tnf_datum_t datum)
{
	struct taginfo	*base, *elt, *elt_base;

	CHECK_ARRAY(datum);

	(void) get_array_info(datum, &base, &elt, &elt_base);

	return (RECORD_DATUM(DATUM_TNF(datum), elt->tag));
}

/*
 * Return a char pointer for string record
 */

char *
tnf_get_chars(tnf_datum_t datum)
{
	struct taginfo	*info, *base, *elt, *elt_base;

	CHECK_ARRAY(datum);

	info = get_array_info(datum, &base, &elt, &elt_base);

	if (!INFO_STRING(info))
		_tnf_error(DATUM_TNF(datum), TNF_ERR_TYPEMISMATCH);

	return (DATUM_VAL(datum) + base->hdrsize);
}

/*
 * Return the base pointer of array
 */

caddr_t
tnf_get_elements(tnf_datum_t datum)
{
	struct taginfo	*base, *elt, *elt_base;

	CHECK_ARRAY(datum);

	(void) get_array_info(datum, &base, &elt, &elt_base);

	return ((caddr_t)(DATUM_VAL(datum) + base->hdrsize));
}