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