xref: /onnv-gate/usr/src/cmd/perl/contrib/Sun/Solaris/Exacct/Object/Object.xs (revision 12388:1bc8d55b0dfd)
10Sstevel@tonic-gate /*
2*12388SJohn.Sonnenschein@Sun.COM  * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
3*12388SJohn.Sonnenschein@Sun.COM  *
40Sstevel@tonic-gate  * Object.xs contains XS code for exacct file manipulation.
50Sstevel@tonic-gate  */
60Sstevel@tonic-gate 
70Sstevel@tonic-gate #include <strings.h>
80Sstevel@tonic-gate #include "../exacct_common.xh"
90Sstevel@tonic-gate 
100Sstevel@tonic-gate /* Pull in the file generated by extract_defines. */
110Sstevel@tonic-gate #include "ObjectDefs.xi"
120Sstevel@tonic-gate 
130Sstevel@tonic-gate /* From Catalog.xs. */
140Sstevel@tonic-gate extern char *catalog_id_str(ea_catalog_t catalog);
150Sstevel@tonic-gate 
160Sstevel@tonic-gate /*
170Sstevel@tonic-gate  * Copy an xs_ea_object_t.  If the perl_obj part is null, we just copy the
180Sstevel@tonic-gate  * ea_object_t part.  If the perl_obj part is not null and the Object is an
190Sstevel@tonic-gate  * Item it must be because the Item contains an embedded Object, which will be
200Sstevel@tonic-gate  * recursively copied.  Otherwise the Object must be a Group, so the Group will
210Sstevel@tonic-gate  * be copied, and the list of Objects it contains will be recursively copied.
220Sstevel@tonic-gate  */
230Sstevel@tonic-gate static SV *
copy_xs_ea_object(SV * src_sv)240Sstevel@tonic-gate copy_xs_ea_object(SV *src_sv)
250Sstevel@tonic-gate {
260Sstevel@tonic-gate 	xs_ea_object_t	*src, *dst;
270Sstevel@tonic-gate 	SV		*dst_sv, *dst_rv;
280Sstevel@tonic-gate 
290Sstevel@tonic-gate 	/* Get the source xs_ea_object_t and make a new one. */
300Sstevel@tonic-gate 	PERL_ASSERT(src_sv != NULL);
310Sstevel@tonic-gate 	src_sv = SvRV(src_sv);
320Sstevel@tonic-gate 	PERL_ASSERT(src_sv != NULL);
330Sstevel@tonic-gate 	src = INT2PTR(xs_ea_object_t *, SvIV(src_sv));
340Sstevel@tonic-gate 	PERL_ASSERT(src != NULL);
350Sstevel@tonic-gate 	New(0, dst, 1, xs_ea_object_t);
360Sstevel@tonic-gate 	dst->flags = src->flags;
370Sstevel@tonic-gate 
380Sstevel@tonic-gate 	/* If the Object is a plain Item only the ea_obj part needs copying. */
390Sstevel@tonic-gate 	if (IS_PLAIN_ITEM(src)) {
400Sstevel@tonic-gate 		dst->ea_obj = ea_copy_object_tree(src->ea_obj);
410Sstevel@tonic-gate 		PERL_ASSERT(dst->ea_obj != NULL);
420Sstevel@tonic-gate 		dst->perl_obj = NULL;
430Sstevel@tonic-gate 
440Sstevel@tonic-gate 	/*
450Sstevel@tonic-gate 	 * Otherwise if it is an Item with a perl_obj part, it means that it
460Sstevel@tonic-gate 	 * must be an Item containing an unpacked nested Object.  In this case
470Sstevel@tonic-gate 	 * the nested Object can be copied by a recursive call.
480Sstevel@tonic-gate 	 */
490Sstevel@tonic-gate 	} else if (IS_EMBED_ITEM(src)) {
500Sstevel@tonic-gate 		dst->ea_obj = ea_copy_object(src->ea_obj);
510Sstevel@tonic-gate 		PERL_ASSERT(dst->ea_obj != NULL);
520Sstevel@tonic-gate 		dst->perl_obj = copy_xs_ea_object(src->perl_obj);
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 	/*
550Sstevel@tonic-gate 	 * If we get here it must be a Group, so perl_obj will point to a tied
560Sstevel@tonic-gate 	 * AV.  We therefore copy the exacct part then create a new tied array
570Sstevel@tonic-gate 	 * and recursively copy each Item individually.
580Sstevel@tonic-gate 	 */
590Sstevel@tonic-gate 	} else {
600Sstevel@tonic-gate 		MAGIC	*mg;
610Sstevel@tonic-gate 		AV	*src_av, *dst_av, *tied_av;
620Sstevel@tonic-gate 		SV	*sv;
630Sstevel@tonic-gate 		int	i, len;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 		/* Copy the exacct part of the Group. */
660Sstevel@tonic-gate 		dst->ea_obj = ea_copy_object(src->ea_obj);
670Sstevel@tonic-gate 		PERL_ASSERT(dst->ea_obj != NULL);
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 		/* Find the AV underlying the tie. */
700Sstevel@tonic-gate 		mg = mg_find(SvRV(src->perl_obj), 'P');
710Sstevel@tonic-gate 		PERL_ASSERT(mg != NULL);
720Sstevel@tonic-gate 		src_av = (AV *)SvRV(mg->mg_obj);
730Sstevel@tonic-gate 		PERL_ASSERT(src_av != NULL);
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 		/* Create a new AV and copy across into it. */
760Sstevel@tonic-gate 		dst_av = newAV();
770Sstevel@tonic-gate 		len = av_len(src_av) + 1;
780Sstevel@tonic-gate 		av_extend(dst_av, len);
790Sstevel@tonic-gate 		for (i = 0; i < len; i++) {
800Sstevel@tonic-gate 			SV **svp;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 			/* undef elements don't need copying. */
830Sstevel@tonic-gate 			if ((svp = av_fetch(src_av, i, FALSE)) != NULL) {
840Sstevel@tonic-gate 				sv = copy_xs_ea_object(*svp);
850Sstevel@tonic-gate 				if (av_store(dst_av, i, sv) == NULL) {
860Sstevel@tonic-gate 					SvREFCNT_dec(sv);
870Sstevel@tonic-gate 				}
880Sstevel@tonic-gate 			}
890Sstevel@tonic-gate 		}
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 		/* Create a new AV and tie the filled AV to it. */
920Sstevel@tonic-gate 		sv = newRV_noinc((SV *)dst_av);
930Sstevel@tonic-gate 		sv_bless(sv, Sun_Solaris_Exacct_Object__Array_stash);
940Sstevel@tonic-gate 		tied_av = newAV();
950Sstevel@tonic-gate 		sv_magic((SV *)tied_av, sv, 'P', Nullch, 0);
960Sstevel@tonic-gate 		SvREFCNT_dec(sv);
970Sstevel@tonic-gate 		dst->perl_obj = newRV_noinc((SV *)tied_av);
980Sstevel@tonic-gate 	}
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	/* Wrap the new xs_ea_object_t in a blessed RV and return it.  */
1010Sstevel@tonic-gate 	dst_sv = newSViv(PTR2IV(dst));
1020Sstevel@tonic-gate 	dst_rv = newRV_noinc(dst_sv);
1030Sstevel@tonic-gate 	sv_bless(dst_rv, SvSTASH(src_sv));
1040Sstevel@tonic-gate 	SvREADONLY_on(dst_sv);
1050Sstevel@tonic-gate 	return (dst_rv);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * If an ea_xs_object_t only has the ea_obj part populated, create the
1100Sstevel@tonic-gate  * corresponding perl_obj part.  For plain Items this is a no-op.  If the
1110Sstevel@tonic-gate  * object is embedded, the embedded part will be unpacked and stored in the
1120Sstevel@tonic-gate  * perl part.  If the object is a Group, the linked list of Items will be
1130Sstevel@tonic-gate  * wrapped in the corresponding perl structure and stored in a tied perl array.
1140Sstevel@tonic-gate  */
1150Sstevel@tonic-gate static int
inflate_xs_ea_object(xs_ea_object_t * xs_obj)1160Sstevel@tonic-gate inflate_xs_ea_object(xs_ea_object_t *xs_obj)
1170Sstevel@tonic-gate {
1180Sstevel@tonic-gate 	ea_object_t	*ea_obj;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* Check there is not already a perl_obj part. */
1210Sstevel@tonic-gate 	PERL_ASSERT(xs_obj != NULL);
1220Sstevel@tonic-gate 	PERL_ASSERT(xs_obj->perl_obj == NULL);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	/* Deal with Items containing embedded Objects. */
1250Sstevel@tonic-gate 	if (IS_EMBED_ITEM(xs_obj)) {
1260Sstevel@tonic-gate 		/* unpack & wrap in an xs_ea_object_t. */
1270Sstevel@tonic-gate 		if (ea_unpack_object(&ea_obj, EUP_ALLOC,
1280Sstevel@tonic-gate 		    xs_obj->ea_obj->eo_item.ei_object,
1290Sstevel@tonic-gate 		    xs_obj->ea_obj->eo_item.ei_size) == -1) {
1300Sstevel@tonic-gate 			return (0);
1310Sstevel@tonic-gate 		}
1320Sstevel@tonic-gate 		xs_obj->perl_obj = new_xs_ea_object(ea_obj);
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	/* Deal with Groups. */
1350Sstevel@tonic-gate 	} else if (IS_GROUP(xs_obj)) {
1360Sstevel@tonic-gate 		int	i, len;
1370Sstevel@tonic-gate 		AV	*av, *tied_av;
1380Sstevel@tonic-gate 		SV	*rv, *sv;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		/* Create a new array. */
1410Sstevel@tonic-gate 		av = newAV();
1420Sstevel@tonic-gate 		ea_obj = xs_obj->ea_obj;
1430Sstevel@tonic-gate 		len = ea_obj->eo_group.eg_nobjs;
1440Sstevel@tonic-gate 		ea_obj = ea_obj->eo_group.eg_objs;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 		/* Copy each object from the old array into the new array. */
1470Sstevel@tonic-gate 		for (i = 0; i < len; i++) {
1480Sstevel@tonic-gate 			rv = new_xs_ea_object(ea_obj);
1490Sstevel@tonic-gate 			if (av_store(av, i, rv) == NULL) {
1500Sstevel@tonic-gate 				SvREFCNT_dec(rv);
1510Sstevel@tonic-gate 			}
1520Sstevel@tonic-gate 			ea_obj = ea_obj->eo_next;
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 		/* Create a new AV and tie the filled AV to it. */
1560Sstevel@tonic-gate 		rv = newRV_noinc((SV *)av);
1570Sstevel@tonic-gate 		sv_bless(rv, Sun_Solaris_Exacct_Object__Array_stash);
1580Sstevel@tonic-gate 		tied_av = newAV();
1590Sstevel@tonic-gate 		sv_magic((SV *)tied_av, rv, 'P', Nullch, 0);
1600Sstevel@tonic-gate 		SvREFCNT_dec(rv);
1610Sstevel@tonic-gate 		xs_obj->perl_obj = newRV_noinc((SV *)tied_av);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	return (1);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate  * The XS code exported to perl is below here.  Note that the XS preprocessor
1680Sstevel@tonic-gate  * has its own commenting syntax, so all comments from this point on are in
1690Sstevel@tonic-gate  * that form.
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object
1730Sstevel@tonic-gate PROTOTYPES: ENABLE
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate  #
1760Sstevel@tonic-gate  # Define the stash pointers if required and create and populate @_Constants.
1770Sstevel@tonic-gate  #
1780Sstevel@tonic-gate BOOT:
1790Sstevel@tonic-gate 	{
1800Sstevel@tonic-gate 	init_stashes();
1810Sstevel@tonic-gate 	define_constants(PKGBASE "::Object", constants);
1820Sstevel@tonic-gate 	}
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate  #
1850Sstevel@tonic-gate  # Return a dual-typed SV containing the type of the object.
1860Sstevel@tonic-gate  #
1870Sstevel@tonic-gate SV *
1880Sstevel@tonic-gate type(self)
1890Sstevel@tonic-gate 	xs_ea_object_t	*self;
1900Sstevel@tonic-gate CODE:
1910Sstevel@tonic-gate 	RETVAL = newSViv(self->ea_obj->eo_type);
1920Sstevel@tonic-gate 	switch (self->ea_obj->eo_type) {
1930Sstevel@tonic-gate 	case EO_ITEM:
1940Sstevel@tonic-gate 		sv_setpv(RETVAL, "EO_ITEM");
1950Sstevel@tonic-gate 		break;
1960Sstevel@tonic-gate 	case EO_GROUP:
1970Sstevel@tonic-gate 		sv_setpv(RETVAL, "EO_GROUP");
1980Sstevel@tonic-gate 		break;
1990Sstevel@tonic-gate 	case EO_NONE:
2000Sstevel@tonic-gate 	default:
2010Sstevel@tonic-gate 		sv_setpv(RETVAL, "EO_NONE");
2020Sstevel@tonic-gate 		break;
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 	SvIOK_on(RETVAL);
2050Sstevel@tonic-gate OUTPUT:
2060Sstevel@tonic-gate 	RETVAL
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate  #
2090Sstevel@tonic-gate  # Return a copy of the catalog of the object.
2100Sstevel@tonic-gate  #
2110Sstevel@tonic-gate SV *
2120Sstevel@tonic-gate catalog(self)
2130Sstevel@tonic-gate 	xs_ea_object_t	*self;
2140Sstevel@tonic-gate CODE:
2150Sstevel@tonic-gate 	RETVAL = new_catalog(self->ea_obj->eo_catalog);
2160Sstevel@tonic-gate OUTPUT:
2170Sstevel@tonic-gate 	RETVAL
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate  #
2200Sstevel@tonic-gate  # Return the value of the object.  For simple Items, a SV containing the value
2210Sstevel@tonic-gate  # of the underlying exacct ea_item_t is returned.  For nested Items or Groups,
2220Sstevel@tonic-gate  # a reference to the nested Item or Group is returned.  For Groups, in a scalar
2230Sstevel@tonic-gate  # context a reference to the tied array used to store the objects in the Group
2240Sstevel@tonic-gate  # is returned; in a list context the objects within the Group are returned on
2250Sstevel@tonic-gate  # the perl stack as a list.
2260Sstevel@tonic-gate  #
2270Sstevel@tonic-gate void
value(self)2280Sstevel@tonic-gate value(self)
2290Sstevel@tonic-gate 	xs_ea_object_t	*self;
2300Sstevel@tonic-gate PPCODE:
2310Sstevel@tonic-gate 	/*
2320Sstevel@tonic-gate 	 * For Items, return the perl representation
2330Sstevel@tonic-gate 	 * of the underlying ea_object_t.
2340Sstevel@tonic-gate 	 */
2350Sstevel@tonic-gate 	if (IS_ITEM(self)) {
2360Sstevel@tonic-gate 		SV	*retval;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		switch (self->ea_obj->eo_catalog & EXT_TYPE_MASK) {
2390Sstevel@tonic-gate 		case EXT_UINT8:
2400Sstevel@tonic-gate 			retval = newSVuv(self->ea_obj->eo_item.ei_uint8);
2410Sstevel@tonic-gate 			break;
2420Sstevel@tonic-gate 		case EXT_UINT16:
2430Sstevel@tonic-gate 			retval = newSVuv(self->ea_obj->eo_item.ei_uint16);
2440Sstevel@tonic-gate 			break;
2450Sstevel@tonic-gate 		case EXT_UINT32:
2460Sstevel@tonic-gate 			retval = newSVuv(self->ea_obj->eo_item.ei_uint32);
2470Sstevel@tonic-gate 			break;
2480Sstevel@tonic-gate 		case EXT_UINT64:
2490Sstevel@tonic-gate 			retval = newSVuv(self->ea_obj->eo_item.ei_uint64);
2500Sstevel@tonic-gate 			break;
2510Sstevel@tonic-gate 		case EXT_DOUBLE:
2520Sstevel@tonic-gate 			retval = newSVnv(self->ea_obj->eo_item.ei_double);
2530Sstevel@tonic-gate 			break;
2540Sstevel@tonic-gate 		case EXT_STRING:
2550Sstevel@tonic-gate 			retval = newSVpvn(self->ea_obj->eo_item.ei_string,
2560Sstevel@tonic-gate 			    self->ea_obj->eo_item.ei_size - 1);
2570Sstevel@tonic-gate 			break;
2580Sstevel@tonic-gate 		case EXT_RAW:
2590Sstevel@tonic-gate 			retval = newSVpvn(self->ea_obj->eo_item.ei_raw,
2600Sstevel@tonic-gate 			    self->ea_obj->eo_item.ei_size);
2610Sstevel@tonic-gate 			break;
2620Sstevel@tonic-gate 		/*
2630Sstevel@tonic-gate 		 * For embedded objects and Groups, return a ref to the perl SV.
2640Sstevel@tonic-gate 		 */
2650Sstevel@tonic-gate 		case EXT_EXACCT_OBJECT:
2660Sstevel@tonic-gate 			if (self->perl_obj == NULL) {
2670Sstevel@tonic-gate 				/* Make sure the object is inflated. */
2680Sstevel@tonic-gate 				if (! inflate_xs_ea_object(self)) {
2690Sstevel@tonic-gate 					XSRETURN_UNDEF;
2700Sstevel@tonic-gate 				}
2710Sstevel@tonic-gate 			}
2720Sstevel@tonic-gate 			retval = SvREFCNT_inc(self->perl_obj);
2730Sstevel@tonic-gate 			break;
2740Sstevel@tonic-gate 		case EXT_GROUP:
2750Sstevel@tonic-gate 			retval = SvREFCNT_inc(self->perl_obj);
2760Sstevel@tonic-gate 			break;
2770Sstevel@tonic-gate 		case EXT_NONE:
2780Sstevel@tonic-gate 		default:
2790Sstevel@tonic-gate 			croak("Invalid object type");
2800Sstevel@tonic-gate 			break;
2810Sstevel@tonic-gate 		}
2820Sstevel@tonic-gate 		EXTEND(SP, 1);
2830Sstevel@tonic-gate 		PUSHs(sv_2mortal(retval));
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	/*
2860Sstevel@tonic-gate 	 * Now we deal with Groups.
2870Sstevel@tonic-gate 	 */
2880Sstevel@tonic-gate 	} else {
2890Sstevel@tonic-gate 		/* Make sure the object is inflated. */
2900Sstevel@tonic-gate 		if (self->perl_obj == NULL) {
2910Sstevel@tonic-gate 			if (! inflate_xs_ea_object(self)) {
2920Sstevel@tonic-gate 				XSRETURN_UNDEF;
2930Sstevel@tonic-gate 			}
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 		/* In a list context return the contents of the AV. */
2970Sstevel@tonic-gate 		if (GIMME_V == G_ARRAY) {
2980Sstevel@tonic-gate 			MAGIC   *mg;
2990Sstevel@tonic-gate 			AV	*av;
3000Sstevel@tonic-gate 			int	len, i;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 			/* Find the AV underlying the tie. */
3030Sstevel@tonic-gate 			mg = mg_find(SvRV(self->perl_obj), 'P');
3040Sstevel@tonic-gate 			PERL_ASSERT(mg != NULL);
3050Sstevel@tonic-gate 			av = (AV *)SvRV(mg->mg_obj);
3060Sstevel@tonic-gate 			PERL_ASSERT(av != NULL);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 			/*
3090Sstevel@tonic-gate 			 * Push the contents of the array onto the stack.
3100Sstevel@tonic-gate 			 * Push undef for any empty array slots.
3110Sstevel@tonic-gate 			 */
3120Sstevel@tonic-gate 			len = av_len(av) + 1;
3130Sstevel@tonic-gate 			EXTEND(SP, len);
3140Sstevel@tonic-gate 			for (i = 0; i < len; i++) {
3150Sstevel@tonic-gate 				SV	**svp;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 			if ((svp = av_fetch(av, i, FALSE)) == NULL) {
3180Sstevel@tonic-gate 					PUSHs(&PL_sv_undef);
3190Sstevel@tonic-gate 				} else {
3200Sstevel@tonic-gate 					PERL_ASSERT(*svp != NULL);
3210Sstevel@tonic-gate 					PUSHs(sv_2mortal(SvREFCNT_inc(*svp)));
3220Sstevel@tonic-gate 				}
3230Sstevel@tonic-gate 			}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		/* In a scalar context, return a ref to the array of Items. */
3260Sstevel@tonic-gate 		} else {
3270Sstevel@tonic-gate 			EXTEND(SP, 1);
3280Sstevel@tonic-gate 			PUSHs(sv_2mortal(SvREFCNT_inc(self->perl_obj)));
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate  #
3330Sstevel@tonic-gate  # Call the ea_match_catalog function.
3340Sstevel@tonic-gate  #
3350Sstevel@tonic-gate int
3360Sstevel@tonic-gate match_catalog(self, catalog)
3370Sstevel@tonic-gate 	xs_ea_object_t	*self;
3380Sstevel@tonic-gate 	SV		*catalog;
3390Sstevel@tonic-gate CODE:
3400Sstevel@tonic-gate 	RETVAL = ea_match_object_catalog(self->ea_obj, catalog_value(catalog));
3410Sstevel@tonic-gate OUTPUT:
3420Sstevel@tonic-gate 	RETVAL
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate  #
3450Sstevel@tonic-gate  # Destroy an Object.
3460Sstevel@tonic-gate  #
3470Sstevel@tonic-gate void
3480Sstevel@tonic-gate DESTROY(self)
3490Sstevel@tonic-gate 	xs_ea_object_t	*self;
3500Sstevel@tonic-gate PREINIT:
3510Sstevel@tonic-gate 	ea_object_t	*ea_obj;
3520Sstevel@tonic-gate 	SV		*perl_obj;
3530Sstevel@tonic-gate CODE:
3540Sstevel@tonic-gate 	/*
3550Sstevel@tonic-gate 	 * Because both libexacct and perl know about the ea_object_t, we have
3560Sstevel@tonic-gate 	 * to make sure that they don't both end up freeing the object.  First
3570Sstevel@tonic-gate 	 * we break any link to the next ea_object_t in the chain.  Next, if
3580Sstevel@tonic-gate 	 * the object is a Group and there is an active perl_obj chain, we will
3590Sstevel@tonic-gate 	 * let perl clean up the Objects, so we zero the eo_group chain.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	perl_obj = self->perl_obj;
3620Sstevel@tonic-gate 	ea_obj = self->ea_obj;
3630Sstevel@tonic-gate 	ea_obj->eo_next = NULL;
3640Sstevel@tonic-gate 	if (IS_GROUP(self) && perl_obj != NULL) {
3650Sstevel@tonic-gate 		ea_obj->eo_group.eg_nobjs = 0;
3660Sstevel@tonic-gate 		ea_obj->eo_group.eg_objs = NULL;
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 	ea_free_object(ea_obj, EUP_ALLOC);
3690Sstevel@tonic-gate 	if (perl_obj != NULL) {
3700Sstevel@tonic-gate 		SvREFCNT_dec(perl_obj);
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 	Safefree(self);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object::Item
3750Sstevel@tonic-gate PROTOTYPES: ENABLE
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate  #
3780Sstevel@tonic-gate  # Create a new Item.
3790Sstevel@tonic-gate  #
3800Sstevel@tonic-gate xs_ea_object_t *
3810Sstevel@tonic-gate new(class, catalog, value)
3820Sstevel@tonic-gate 	char	*class;
3830Sstevel@tonic-gate 	SV	*catalog;
3840Sstevel@tonic-gate 	SV	*value;
3850Sstevel@tonic-gate PREINIT:
3860Sstevel@tonic-gate 	ea_object_t	*ea_obj;
3870Sstevel@tonic-gate 	HV		*stash;
3880Sstevel@tonic-gate CODE:
3890Sstevel@tonic-gate 	/* Create a new xs_ea_object_t and subsiduary structures. */
3900Sstevel@tonic-gate 	New(0, RETVAL, 1, xs_ea_object_t);
3910Sstevel@tonic-gate 	RETVAL->ea_obj = ea_obj = ea_alloc(sizeof (ea_object_t));
3920Sstevel@tonic-gate 	bzero(ea_obj, sizeof (*ea_obj));
3930Sstevel@tonic-gate 	ea_obj->eo_type = EO_ITEM;
3940Sstevel@tonic-gate 	ea_obj->eo_catalog = catalog_value(catalog);
3950Sstevel@tonic-gate 	INIT_PLAIN_ITEM_FLAGS(RETVAL);
3960Sstevel@tonic-gate 	RETVAL->perl_obj = NULL;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	/* Assign the Item's value. */
3990Sstevel@tonic-gate 	switch (ea_obj->eo_catalog & EXT_TYPE_MASK) {
4000Sstevel@tonic-gate 	case EXT_UINT8:
4010Sstevel@tonic-gate 		ea_obj->eo_item.ei_uint8 = SvIV(value);
4020Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = sizeof (uint8_t);
4030Sstevel@tonic-gate 		break;
4040Sstevel@tonic-gate 	case EXT_UINT16:
4050Sstevel@tonic-gate 		ea_obj->eo_item.ei_uint16 = SvIV(value);
4060Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = sizeof (uint16_t);
4070Sstevel@tonic-gate 		break;
4080Sstevel@tonic-gate 	case EXT_UINT32:
4090Sstevel@tonic-gate 		ea_obj->eo_item.ei_uint32 = SvIV(value);
4100Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = sizeof (uint32_t);
4110Sstevel@tonic-gate 		break;
4120Sstevel@tonic-gate 	case EXT_UINT64:
4130Sstevel@tonic-gate 		ea_obj->eo_item.ei_uint64 = SvIV(value);
4140Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = sizeof (uint64_t);
4150Sstevel@tonic-gate 		break;
4160Sstevel@tonic-gate 	case EXT_DOUBLE:
4170Sstevel@tonic-gate 		ea_obj->eo_item.ei_double = SvNV(value);
4180Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = sizeof (double);
4190Sstevel@tonic-gate 		break;
4200Sstevel@tonic-gate 	case EXT_STRING:
4210Sstevel@tonic-gate 		ea_obj->eo_item.ei_string = ea_strdup(SvPV_nolen(value));
4220Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = SvCUR(value) + 1;
4230Sstevel@tonic-gate 		break;
4240Sstevel@tonic-gate 	case EXT_RAW:
4250Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = SvCUR(value);
4260Sstevel@tonic-gate 		ea_obj->eo_item.ei_raw = ea_alloc(ea_obj->eo_item.ei_size);
4270Sstevel@tonic-gate 		bcopy(SvPV_nolen(value), ea_obj->eo_item.ei_raw,
4280Sstevel@tonic-gate 		    (size_t)ea_obj->eo_item.ei_size);
4290Sstevel@tonic-gate 		break;
4300Sstevel@tonic-gate 	case EXT_EXACCT_OBJECT:
4310Sstevel@tonic-gate 		/*
4320Sstevel@tonic-gate 		 * The ea_obj part is initially empty, and will be populated
4330Sstevel@tonic-gate 		 * from the perl_obj part  when required.
4340Sstevel@tonic-gate 		 */
4350Sstevel@tonic-gate 		stash = SvROK(value) ? SvSTASH(SvRV(value)) : NULL;
4360Sstevel@tonic-gate 		if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
4370Sstevel@tonic-gate 		    stash != Sun_Solaris_Exacct_Object_Group_stash) {
4380Sstevel@tonic-gate 			croak("value is not of type " PKGBASE "::Object");
4390Sstevel@tonic-gate 		}
4400Sstevel@tonic-gate 		RETVAL->perl_obj = copy_xs_ea_object(value);
4410Sstevel@tonic-gate 		ea_obj->eo_item.ei_object = NULL;
4420Sstevel@tonic-gate 		ea_obj->eo_item.ei_size = 0;
4430Sstevel@tonic-gate 		INIT_EMBED_ITEM_FLAGS(RETVAL);
4440Sstevel@tonic-gate 		break;
4450Sstevel@tonic-gate 	/*
4460Sstevel@tonic-gate 	 * EXT_NONE is an invalid type,
4470Sstevel@tonic-gate 	 * EXT_GROUP is created by the Group subclass constructor.
4480Sstevel@tonic-gate 	 */
4490Sstevel@tonic-gate 	case EXT_NONE:
4500Sstevel@tonic-gate 	case EXT_GROUP:
4510Sstevel@tonic-gate 	default:
4520Sstevel@tonic-gate 		ea_free(RETVAL->ea_obj, sizeof (RETVAL->ea_obj));
4530Sstevel@tonic-gate 		Safefree(RETVAL);
4540Sstevel@tonic-gate 		croak("Invalid object type");
4550Sstevel@tonic-gate 		break;
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate OUTPUT:
4580Sstevel@tonic-gate 	RETVAL
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object::Group
4610Sstevel@tonic-gate PROTOTYPES: ENABLE
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate xs_ea_object_t *
4640Sstevel@tonic-gate new(class, catalog, ...)
4650Sstevel@tonic-gate 	char	*class;
4660Sstevel@tonic-gate 	SV	*catalog;
4670Sstevel@tonic-gate PREINIT:
4680Sstevel@tonic-gate 	ea_catalog_t	tag;
4690Sstevel@tonic-gate 	ea_object_t	*ea_obj;
4700Sstevel@tonic-gate 	AV		*tied_av, *av;
4710Sstevel@tonic-gate 	SV		*sv, *rv;
4720Sstevel@tonic-gate 	int		i;
4730Sstevel@tonic-gate CODE:
4740Sstevel@tonic-gate 	tag = catalog_value(catalog);
4750Sstevel@tonic-gate 	if ((tag & EXT_TYPE_MASK) != EXT_GROUP) {
4760Sstevel@tonic-gate 		croak("Invalid object type");
4770Sstevel@tonic-gate 	}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	/* Create a new xs_ea_object_t and subsiduary structures. */
4800Sstevel@tonic-gate 	New(0, RETVAL, 1, xs_ea_object_t);
4810Sstevel@tonic-gate 	RETVAL->ea_obj = ea_obj = ea_alloc(sizeof (ea_object_t));
4820Sstevel@tonic-gate 	bzero(ea_obj, sizeof (*ea_obj));
4830Sstevel@tonic-gate 	ea_obj->eo_type = EO_GROUP;
4840Sstevel@tonic-gate 	ea_obj->eo_catalog = tag;
4850Sstevel@tonic-gate 	INIT_GROUP_FLAGS(RETVAL);
4860Sstevel@tonic-gate 	RETVAL->perl_obj = NULL;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/* Create a new AV and copy in all the passed Items. */
4890Sstevel@tonic-gate 	av = newAV();
4900Sstevel@tonic-gate 	av_extend(av, items - 2);
4910Sstevel@tonic-gate 	for (i = 2; i < items; i++) {
4920Sstevel@tonic-gate 		HV	*stash;
4930Sstevel@tonic-gate 		stash = SvROK(ST(i)) ? SvSTASH(SvRV(ST(i))) : NULL;
4940Sstevel@tonic-gate 		if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
4950Sstevel@tonic-gate 		    stash != Sun_Solaris_Exacct_Object_Group_stash) {
4960Sstevel@tonic-gate 			croak("item is not of type " PKGBASE "::Object");
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 		av_store(av, i - 2, copy_xs_ea_object(ST(i)));
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	/* Bless the copied AV and tie it to a new AV */
5020Sstevel@tonic-gate 	rv = newRV_noinc((SV *)av);
5030Sstevel@tonic-gate 	sv_bless(rv, Sun_Solaris_Exacct_Object__Array_stash);
5040Sstevel@tonic-gate 	tied_av = newAV();
5050Sstevel@tonic-gate 	sv_magic((SV *)tied_av, rv, 'P', Nullch, 0);
5060Sstevel@tonic-gate 	SvREFCNT_dec(rv);
5070Sstevel@tonic-gate 	RETVAL->perl_obj = newRV_noinc((SV *)tied_av);
5080Sstevel@tonic-gate OUTPUT:
5090Sstevel@tonic-gate 	RETVAL
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate  #
5120Sstevel@tonic-gate  # Return the contents of the group as a hashref, using the string value of each
5130Sstevel@tonic-gate  # item's catalog id as the key.  There are two forms - as_hash() which stores
5140Sstevel@tonic-gate  # each hash value as a scalar, and should be used when it is known the group
5150Sstevel@tonic-gate  # does not contain duplicate catalog tags, and as_hashlist wich stores each
5160Sstevel@tonic-gate  # hash value as an array of values, and can therefore be used when the group
5170Sstevel@tonic-gate  # may contain duplicate catalog tags.
5180Sstevel@tonic-gate  #
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate SV *
5210Sstevel@tonic-gate as_hash(self)
5220Sstevel@tonic-gate 	xs_ea_object_t	*self;
5230Sstevel@tonic-gate ALIAS:
5240Sstevel@tonic-gate 	as_hashlist = 1
5250Sstevel@tonic-gate PREINIT:
5260Sstevel@tonic-gate 	MAGIC   *mg;
5270Sstevel@tonic-gate 	HV	*hv;
5280Sstevel@tonic-gate 	AV	*av;
5290Sstevel@tonic-gate 	int	len, i;
5300Sstevel@tonic-gate CODE:
5310Sstevel@tonic-gate 	/* Make sure the object is inflated. */
5320Sstevel@tonic-gate 	if (self->perl_obj == NULL) {
5330Sstevel@tonic-gate 		if (! inflate_xs_ea_object(self)) {
5340Sstevel@tonic-gate 			XSRETURN_UNDEF;
5350Sstevel@tonic-gate 		}
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/* Find the AV underlying the tie and create the new HV. */
5390Sstevel@tonic-gate 	mg = mg_find(SvRV(self->perl_obj), 'P');
5400Sstevel@tonic-gate 	PERL_ASSERT(mg != NULL);
5410Sstevel@tonic-gate 	av = (AV *)SvRV(mg->mg_obj);
5420Sstevel@tonic-gate 	PERL_ASSERT(av != NULL);
5430Sstevel@tonic-gate 	hv = newHV();
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	/*
5460Sstevel@tonic-gate 	 * Traverse the value array, saving the values in the hash,
5470Sstevel@tonic-gate 	 * keyed by the string value of the catalog id field.
5480Sstevel@tonic-gate 	 */
5490Sstevel@tonic-gate 	len = av_len(av) + 1;
5500Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
5510Sstevel@tonic-gate 		SV		**svp, *val;
5520Sstevel@tonic-gate 		xs_ea_object_t	*xs_obj;
5530Sstevel@tonic-gate 		const char	*key;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		/* Ignore undef values. */
5560Sstevel@tonic-gate 		if ((svp = av_fetch(av, i, FALSE)) == NULL) {
5570Sstevel@tonic-gate 			continue;
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 		PERL_ASSERT(*svp != NULL);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 		/* Figure out the key. */
5620Sstevel@tonic-gate 		xs_obj = INT2PTR(xs_ea_object_t *, SvIV(SvRV(*svp)));
5630Sstevel@tonic-gate 		key = catalog_id_str(xs_obj->ea_obj->eo_catalog);
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 		/*
5660Sstevel@tonic-gate 		 * For Items, save the perl representation
5670Sstevel@tonic-gate 		 * of the underlying ea_object_t.
5680Sstevel@tonic-gate 		 */
5690Sstevel@tonic-gate 		if (IS_ITEM(xs_obj)) {
5700Sstevel@tonic-gate 			switch (xs_obj->ea_obj->eo_catalog & EXT_TYPE_MASK) {
5710Sstevel@tonic-gate 			case EXT_UINT8:
5720Sstevel@tonic-gate 				val =
5730Sstevel@tonic-gate 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint8);
5740Sstevel@tonic-gate 				break;
5750Sstevel@tonic-gate 			case EXT_UINT16:
5760Sstevel@tonic-gate 				val =
5770Sstevel@tonic-gate 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint16);
5780Sstevel@tonic-gate 				break;
5790Sstevel@tonic-gate 			case EXT_UINT32:
5800Sstevel@tonic-gate 				val =
5810Sstevel@tonic-gate 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint32);
5820Sstevel@tonic-gate 				break;
5830Sstevel@tonic-gate 			case EXT_UINT64:
5840Sstevel@tonic-gate 				val =
5850Sstevel@tonic-gate 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint64);
5860Sstevel@tonic-gate 				break;
5870Sstevel@tonic-gate 			case EXT_DOUBLE:
5880Sstevel@tonic-gate 				val =
5890Sstevel@tonic-gate 				    newSVnv(xs_obj->ea_obj->eo_item.ei_double);
5900Sstevel@tonic-gate 				break;
5910Sstevel@tonic-gate 			case EXT_STRING:
5920Sstevel@tonic-gate 				val =
5930Sstevel@tonic-gate 				    newSVpvn(xs_obj->ea_obj->eo_item.ei_string,
5940Sstevel@tonic-gate 				    xs_obj->ea_obj->eo_item.ei_size - 1);
5950Sstevel@tonic-gate 				break;
5960Sstevel@tonic-gate 			case EXT_RAW:
5970Sstevel@tonic-gate 				val =
5980Sstevel@tonic-gate 				    newSVpvn(xs_obj->ea_obj->eo_item.ei_raw,
5990Sstevel@tonic-gate 				    xs_obj->ea_obj->eo_item.ei_size);
6000Sstevel@tonic-gate 				break;
6010Sstevel@tonic-gate 			/*
6020Sstevel@tonic-gate 			 * For embedded objects and Groups, return a ref
6030Sstevel@tonic-gate 			 * to the perl SV.
6040Sstevel@tonic-gate 			 */
6050Sstevel@tonic-gate 			case EXT_EXACCT_OBJECT:
6060Sstevel@tonic-gate 				if (xs_obj->perl_obj == NULL) {
6070Sstevel@tonic-gate 					/* Make sure the object is inflated. */
6080Sstevel@tonic-gate 					if (! inflate_xs_ea_object(xs_obj)) {
6090Sstevel@tonic-gate 						SvREFCNT_dec(hv);
6100Sstevel@tonic-gate 						XSRETURN_UNDEF;
6110Sstevel@tonic-gate 					}
6120Sstevel@tonic-gate 				}
6130Sstevel@tonic-gate 				val = SvREFCNT_inc(xs_obj->perl_obj);
6140Sstevel@tonic-gate 				break;
6150Sstevel@tonic-gate 			case EXT_GROUP:
6160Sstevel@tonic-gate 				val = SvREFCNT_inc(xs_obj->perl_obj);
6170Sstevel@tonic-gate 				break;
6180Sstevel@tonic-gate 			case EXT_NONE:
6190Sstevel@tonic-gate 			default:
6200Sstevel@tonic-gate 				croak("Invalid object type");
6210Sstevel@tonic-gate 				break;
6220Sstevel@tonic-gate 			}
6230Sstevel@tonic-gate 		/*
6240Sstevel@tonic-gate 		 * Now we deal with Groups.
6250Sstevel@tonic-gate 		 */
6260Sstevel@tonic-gate 		} else {
6270Sstevel@tonic-gate 			/* Make sure the object is inflated. */
6280Sstevel@tonic-gate 			if (xs_obj->perl_obj == NULL) {
6290Sstevel@tonic-gate 				if (! inflate_xs_ea_object(xs_obj)) {
6300Sstevel@tonic-gate 					SvREFCNT_dec(hv);
6310Sstevel@tonic-gate 					XSRETURN_UNDEF;
6320Sstevel@tonic-gate 				}
6330Sstevel@tonic-gate 			}
6340Sstevel@tonic-gate 			val = SvREFCNT_inc(xs_obj->perl_obj);
6350Sstevel@tonic-gate 		}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 		/*
6380Sstevel@tonic-gate 		 * If called as as_hash(), store the value directly in the
6390Sstevel@tonic-gate 		 * hash, if called as as_hashlist(), store the value in an
6400Sstevel@tonic-gate 		 * array within the hash.
6410Sstevel@tonic-gate 		 */
6420Sstevel@tonic-gate 		if (ix == 0) {
6430Sstevel@tonic-gate 			hv_store(hv, key, strlen(key), val, FALSE);
6440Sstevel@tonic-gate 		} else {
6450Sstevel@tonic-gate 			AV *ary;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 			/* If the key already exists in the hash. */
6480Sstevel@tonic-gate 			svp = hv_fetch(hv, key, strlen(key), TRUE);
6490Sstevel@tonic-gate 			if (SvOK(*svp)) {
6500Sstevel@tonic-gate 				ary = (AV *)SvRV(*svp);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 			/* Otherwise, add a new array to the hash. */
6530Sstevel@tonic-gate 			} else {
6540Sstevel@tonic-gate 				SV *rv;
6550Sstevel@tonic-gate 				ary = newAV();
6560Sstevel@tonic-gate 				rv = newRV_noinc((SV *)ary);
6570Sstevel@tonic-gate 				sv_setsv(*svp, rv);
6580Sstevel@tonic-gate 				SvREFCNT_dec(rv);
6590Sstevel@tonic-gate 			}
6600Sstevel@tonic-gate 			av_push(ary, val);
6610Sstevel@tonic-gate 		}
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 	RETVAL = newRV_noinc((SV *)hv);
6640Sstevel@tonic-gate OUTPUT:
6650Sstevel@tonic-gate 	RETVAL
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object::_Array
6680Sstevel@tonic-gate PROTOTYPES: ENABLE
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate  #
6710Sstevel@tonic-gate  # Copy the passed list of xs_ea_object_t.
6720Sstevel@tonic-gate  #
6730Sstevel@tonic-gate void
6740Sstevel@tonic-gate copy_xs_ea_objects(...)
6750Sstevel@tonic-gate PREINIT:
6760Sstevel@tonic-gate 	int	i;
6770Sstevel@tonic-gate PPCODE:
6780Sstevel@tonic-gate 	EXTEND(SP, items);
6790Sstevel@tonic-gate 	for (i = 0; i < items; i++) {
6800Sstevel@tonic-gate 		HV	*stash;
6810Sstevel@tonic-gate 		stash = SvROK(ST(i)) ? SvSTASH(SvRV(ST(i))) : NULL;
6820Sstevel@tonic-gate 		if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
6830Sstevel@tonic-gate 		    stash != Sun_Solaris_Exacct_Object_Group_stash) {
6840Sstevel@tonic-gate 			croak("item is not of type " PKGBASE "::Object");
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 		PUSHs(sv_2mortal(copy_xs_ea_object(ST(i))));
6870Sstevel@tonic-gate 	}
688