xref: /onnv-gate/usr/src/cmd/perl/contrib/Sun/Solaris/Exacct/Object/Object.xs (revision 12388:1bc8d55b0dfd)
1 /*
2  * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Object.xs contains XS code for exacct file manipulation.
5  */
6 
7 #include <strings.h>
8 #include "../exacct_common.xh"
9 
10 /* Pull in the file generated by extract_defines. */
11 #include "ObjectDefs.xi"
12 
13 /* From Catalog.xs. */
14 extern char *catalog_id_str(ea_catalog_t catalog);
15 
16 /*
17  * Copy an xs_ea_object_t.  If the perl_obj part is null, we just copy the
18  * ea_object_t part.  If the perl_obj part is not null and the Object is an
19  * Item it must be because the Item contains an embedded Object, which will be
20  * recursively copied.  Otherwise the Object must be a Group, so the Group will
21  * be copied, and the list of Objects it contains will be recursively copied.
22  */
23 static SV *
copy_xs_ea_object(SV * src_sv)24 copy_xs_ea_object(SV *src_sv)
25 {
26 	xs_ea_object_t	*src, *dst;
27 	SV		*dst_sv, *dst_rv;
28 
29 	/* Get the source xs_ea_object_t and make a new one. */
30 	PERL_ASSERT(src_sv != NULL);
31 	src_sv = SvRV(src_sv);
32 	PERL_ASSERT(src_sv != NULL);
33 	src = INT2PTR(xs_ea_object_t *, SvIV(src_sv));
34 	PERL_ASSERT(src != NULL);
35 	New(0, dst, 1, xs_ea_object_t);
36 	dst->flags = src->flags;
37 
38 	/* If the Object is a plain Item only the ea_obj part needs copying. */
39 	if (IS_PLAIN_ITEM(src)) {
40 		dst->ea_obj = ea_copy_object_tree(src->ea_obj);
41 		PERL_ASSERT(dst->ea_obj != NULL);
42 		dst->perl_obj = NULL;
43 
44 	/*
45 	 * Otherwise if it is an Item with a perl_obj part, it means that it
46 	 * must be an Item containing an unpacked nested Object.  In this case
47 	 * the nested Object can be copied by a recursive call.
48 	 */
49 	} else if (IS_EMBED_ITEM(src)) {
50 		dst->ea_obj = ea_copy_object(src->ea_obj);
51 		PERL_ASSERT(dst->ea_obj != NULL);
52 		dst->perl_obj = copy_xs_ea_object(src->perl_obj);
53 
54 	/*
55 	 * If we get here it must be a Group, so perl_obj will point to a tied
56 	 * AV.  We therefore copy the exacct part then create a new tied array
57 	 * and recursively copy each Item individually.
58 	 */
59 	} else {
60 		MAGIC	*mg;
61 		AV	*src_av, *dst_av, *tied_av;
62 		SV	*sv;
63 		int	i, len;
64 
65 		/* Copy the exacct part of the Group. */
66 		dst->ea_obj = ea_copy_object(src->ea_obj);
67 		PERL_ASSERT(dst->ea_obj != NULL);
68 
69 		/* Find the AV underlying the tie. */
70 		mg = mg_find(SvRV(src->perl_obj), 'P');
71 		PERL_ASSERT(mg != NULL);
72 		src_av = (AV *)SvRV(mg->mg_obj);
73 		PERL_ASSERT(src_av != NULL);
74 
75 		/* Create a new AV and copy across into it. */
76 		dst_av = newAV();
77 		len = av_len(src_av) + 1;
78 		av_extend(dst_av, len);
79 		for (i = 0; i < len; i++) {
80 			SV **svp;
81 
82 			/* undef elements don't need copying. */
83 			if ((svp = av_fetch(src_av, i, FALSE)) != NULL) {
84 				sv = copy_xs_ea_object(*svp);
85 				if (av_store(dst_av, i, sv) == NULL) {
86 					SvREFCNT_dec(sv);
87 				}
88 			}
89 		}
90 
91 		/* Create a new AV and tie the filled AV to it. */
92 		sv = newRV_noinc((SV *)dst_av);
93 		sv_bless(sv, Sun_Solaris_Exacct_Object__Array_stash);
94 		tied_av = newAV();
95 		sv_magic((SV *)tied_av, sv, 'P', Nullch, 0);
96 		SvREFCNT_dec(sv);
97 		dst->perl_obj = newRV_noinc((SV *)tied_av);
98 	}
99 
100 	/* Wrap the new xs_ea_object_t in a blessed RV and return it.  */
101 	dst_sv = newSViv(PTR2IV(dst));
102 	dst_rv = newRV_noinc(dst_sv);
103 	sv_bless(dst_rv, SvSTASH(src_sv));
104 	SvREADONLY_on(dst_sv);
105 	return (dst_rv);
106 }
107 
108 /*
109  * If an ea_xs_object_t only has the ea_obj part populated, create the
110  * corresponding perl_obj part.  For plain Items this is a no-op.  If the
111  * object is embedded, the embedded part will be unpacked and stored in the
112  * perl part.  If the object is a Group, the linked list of Items will be
113  * wrapped in the corresponding perl structure and stored in a tied perl array.
114  */
115 static int
inflate_xs_ea_object(xs_ea_object_t * xs_obj)116 inflate_xs_ea_object(xs_ea_object_t *xs_obj)
117 {
118 	ea_object_t	*ea_obj;
119 
120 	/* Check there is not already a perl_obj part. */
121 	PERL_ASSERT(xs_obj != NULL);
122 	PERL_ASSERT(xs_obj->perl_obj == NULL);
123 
124 	/* Deal with Items containing embedded Objects. */
125 	if (IS_EMBED_ITEM(xs_obj)) {
126 		/* unpack & wrap in an xs_ea_object_t. */
127 		if (ea_unpack_object(&ea_obj, EUP_ALLOC,
128 		    xs_obj->ea_obj->eo_item.ei_object,
129 		    xs_obj->ea_obj->eo_item.ei_size) == -1) {
130 			return (0);
131 		}
132 		xs_obj->perl_obj = new_xs_ea_object(ea_obj);
133 
134 	/* Deal with Groups. */
135 	} else if (IS_GROUP(xs_obj)) {
136 		int	i, len;
137 		AV	*av, *tied_av;
138 		SV	*rv, *sv;
139 
140 		/* Create a new array. */
141 		av = newAV();
142 		ea_obj = xs_obj->ea_obj;
143 		len = ea_obj->eo_group.eg_nobjs;
144 		ea_obj = ea_obj->eo_group.eg_objs;
145 
146 		/* Copy each object from the old array into the new array. */
147 		for (i = 0; i < len; i++) {
148 			rv = new_xs_ea_object(ea_obj);
149 			if (av_store(av, i, rv) == NULL) {
150 				SvREFCNT_dec(rv);
151 			}
152 			ea_obj = ea_obj->eo_next;
153 		}
154 
155 		/* Create a new AV and tie the filled AV to it. */
156 		rv = newRV_noinc((SV *)av);
157 		sv_bless(rv, Sun_Solaris_Exacct_Object__Array_stash);
158 		tied_av = newAV();
159 		sv_magic((SV *)tied_av, rv, 'P', Nullch, 0);
160 		SvREFCNT_dec(rv);
161 		xs_obj->perl_obj = newRV_noinc((SV *)tied_av);
162 	}
163 	return (1);
164 }
165 
166 /*
167  * The XS code exported to perl is below here.  Note that the XS preprocessor
168  * has its own commenting syntax, so all comments from this point on are in
169  * that form.
170  */
171 
172 MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object
173 PROTOTYPES: ENABLE
174 
175  #
176  # Define the stash pointers if required and create and populate @_Constants.
177  #
178 BOOT:
179 	{
180 	init_stashes();
181 	define_constants(PKGBASE "::Object", constants);
182 	}
183 
184  #
185  # Return a dual-typed SV containing the type of the object.
186  #
187 SV *
188 type(self)
189 	xs_ea_object_t	*self;
190 CODE:
191 	RETVAL = newSViv(self->ea_obj->eo_type);
192 	switch (self->ea_obj->eo_type) {
193 	case EO_ITEM:
194 		sv_setpv(RETVAL, "EO_ITEM");
195 		break;
196 	case EO_GROUP:
197 		sv_setpv(RETVAL, "EO_GROUP");
198 		break;
199 	case EO_NONE:
200 	default:
201 		sv_setpv(RETVAL, "EO_NONE");
202 		break;
203 	}
204 	SvIOK_on(RETVAL);
205 OUTPUT:
206 	RETVAL
207 
208  #
209  # Return a copy of the catalog of the object.
210  #
211 SV *
212 catalog(self)
213 	xs_ea_object_t	*self;
214 CODE:
215 	RETVAL = new_catalog(self->ea_obj->eo_catalog);
216 OUTPUT:
217 	RETVAL
218 
219  #
220  # Return the value of the object.  For simple Items, a SV containing the value
221  # of the underlying exacct ea_item_t is returned.  For nested Items or Groups,
222  # a reference to the nested Item or Group is returned.  For Groups, in a scalar
223  # context a reference to the tied array used to store the objects in the Group
224  # is returned; in a list context the objects within the Group are returned on
225  # the perl stack as a list.
226  #
227 void
value(self)228 value(self)
229 	xs_ea_object_t	*self;
230 PPCODE:
231 	/*
232 	 * For Items, return the perl representation
233 	 * of the underlying ea_object_t.
234 	 */
235 	if (IS_ITEM(self)) {
236 		SV	*retval;
237 
238 		switch (self->ea_obj->eo_catalog & EXT_TYPE_MASK) {
239 		case EXT_UINT8:
240 			retval = newSVuv(self->ea_obj->eo_item.ei_uint8);
241 			break;
242 		case EXT_UINT16:
243 			retval = newSVuv(self->ea_obj->eo_item.ei_uint16);
244 			break;
245 		case EXT_UINT32:
246 			retval = newSVuv(self->ea_obj->eo_item.ei_uint32);
247 			break;
248 		case EXT_UINT64:
249 			retval = newSVuv(self->ea_obj->eo_item.ei_uint64);
250 			break;
251 		case EXT_DOUBLE:
252 			retval = newSVnv(self->ea_obj->eo_item.ei_double);
253 			break;
254 		case EXT_STRING:
255 			retval = newSVpvn(self->ea_obj->eo_item.ei_string,
256 			    self->ea_obj->eo_item.ei_size - 1);
257 			break;
258 		case EXT_RAW:
259 			retval = newSVpvn(self->ea_obj->eo_item.ei_raw,
260 			    self->ea_obj->eo_item.ei_size);
261 			break;
262 		/*
263 		 * For embedded objects and Groups, return a ref to the perl SV.
264 		 */
265 		case EXT_EXACCT_OBJECT:
266 			if (self->perl_obj == NULL) {
267 				/* Make sure the object is inflated. */
268 				if (! inflate_xs_ea_object(self)) {
269 					XSRETURN_UNDEF;
270 				}
271 			}
272 			retval = SvREFCNT_inc(self->perl_obj);
273 			break;
274 		case EXT_GROUP:
275 			retval = SvREFCNT_inc(self->perl_obj);
276 			break;
277 		case EXT_NONE:
278 		default:
279 			croak("Invalid object type");
280 			break;
281 		}
282 		EXTEND(SP, 1);
283 		PUSHs(sv_2mortal(retval));
284 
285 	/*
286 	 * Now we deal with Groups.
287 	 */
288 	} else {
289 		/* Make sure the object is inflated. */
290 		if (self->perl_obj == NULL) {
291 			if (! inflate_xs_ea_object(self)) {
292 				XSRETURN_UNDEF;
293 			}
294 		}
295 
296 		/* In a list context return the contents of the AV. */
297 		if (GIMME_V == G_ARRAY) {
298 			MAGIC   *mg;
299 			AV	*av;
300 			int	len, i;
301 
302 			/* Find the AV underlying the tie. */
303 			mg = mg_find(SvRV(self->perl_obj), 'P');
304 			PERL_ASSERT(mg != NULL);
305 			av = (AV *)SvRV(mg->mg_obj);
306 			PERL_ASSERT(av != NULL);
307 
308 			/*
309 			 * Push the contents of the array onto the stack.
310 			 * Push undef for any empty array slots.
311 			 */
312 			len = av_len(av) + 1;
313 			EXTEND(SP, len);
314 			for (i = 0; i < len; i++) {
315 				SV	**svp;
316 
317 			if ((svp = av_fetch(av, i, FALSE)) == NULL) {
318 					PUSHs(&PL_sv_undef);
319 				} else {
320 					PERL_ASSERT(*svp != NULL);
321 					PUSHs(sv_2mortal(SvREFCNT_inc(*svp)));
322 				}
323 			}
324 
325 		/* In a scalar context, return a ref to the array of Items. */
326 		} else {
327 			EXTEND(SP, 1);
328 			PUSHs(sv_2mortal(SvREFCNT_inc(self->perl_obj)));
329 		}
330 	}
331 
332  #
333  # Call the ea_match_catalog function.
334  #
335 int
336 match_catalog(self, catalog)
337 	xs_ea_object_t	*self;
338 	SV		*catalog;
339 CODE:
340 	RETVAL = ea_match_object_catalog(self->ea_obj, catalog_value(catalog));
341 OUTPUT:
342 	RETVAL
343 
344  #
345  # Destroy an Object.
346  #
347 void
348 DESTROY(self)
349 	xs_ea_object_t	*self;
350 PREINIT:
351 	ea_object_t	*ea_obj;
352 	SV		*perl_obj;
353 CODE:
354 	/*
355 	 * Because both libexacct and perl know about the ea_object_t, we have
356 	 * to make sure that they don't both end up freeing the object.  First
357 	 * we break any link to the next ea_object_t in the chain.  Next, if
358 	 * the object is a Group and there is an active perl_obj chain, we will
359 	 * let perl clean up the Objects, so we zero the eo_group chain.
360 	 */
361 	perl_obj = self->perl_obj;
362 	ea_obj = self->ea_obj;
363 	ea_obj->eo_next = NULL;
364 	if (IS_GROUP(self) && perl_obj != NULL) {
365 		ea_obj->eo_group.eg_nobjs = 0;
366 		ea_obj->eo_group.eg_objs = NULL;
367 	}
368 	ea_free_object(ea_obj, EUP_ALLOC);
369 	if (perl_obj != NULL) {
370 		SvREFCNT_dec(perl_obj);
371 	}
372 	Safefree(self);
373 
374 MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object::Item
375 PROTOTYPES: ENABLE
376 
377  #
378  # Create a new Item.
379  #
380 xs_ea_object_t *
381 new(class, catalog, value)
382 	char	*class;
383 	SV	*catalog;
384 	SV	*value;
385 PREINIT:
386 	ea_object_t	*ea_obj;
387 	HV		*stash;
388 CODE:
389 	/* Create a new xs_ea_object_t and subsiduary structures. */
390 	New(0, RETVAL, 1, xs_ea_object_t);
391 	RETVAL->ea_obj = ea_obj = ea_alloc(sizeof (ea_object_t));
392 	bzero(ea_obj, sizeof (*ea_obj));
393 	ea_obj->eo_type = EO_ITEM;
394 	ea_obj->eo_catalog = catalog_value(catalog);
395 	INIT_PLAIN_ITEM_FLAGS(RETVAL);
396 	RETVAL->perl_obj = NULL;
397 
398 	/* Assign the Item's value. */
399 	switch (ea_obj->eo_catalog & EXT_TYPE_MASK) {
400 	case EXT_UINT8:
401 		ea_obj->eo_item.ei_uint8 = SvIV(value);
402 		ea_obj->eo_item.ei_size = sizeof (uint8_t);
403 		break;
404 	case EXT_UINT16:
405 		ea_obj->eo_item.ei_uint16 = SvIV(value);
406 		ea_obj->eo_item.ei_size = sizeof (uint16_t);
407 		break;
408 	case EXT_UINT32:
409 		ea_obj->eo_item.ei_uint32 = SvIV(value);
410 		ea_obj->eo_item.ei_size = sizeof (uint32_t);
411 		break;
412 	case EXT_UINT64:
413 		ea_obj->eo_item.ei_uint64 = SvIV(value);
414 		ea_obj->eo_item.ei_size = sizeof (uint64_t);
415 		break;
416 	case EXT_DOUBLE:
417 		ea_obj->eo_item.ei_double = SvNV(value);
418 		ea_obj->eo_item.ei_size = sizeof (double);
419 		break;
420 	case EXT_STRING:
421 		ea_obj->eo_item.ei_string = ea_strdup(SvPV_nolen(value));
422 		ea_obj->eo_item.ei_size = SvCUR(value) + 1;
423 		break;
424 	case EXT_RAW:
425 		ea_obj->eo_item.ei_size = SvCUR(value);
426 		ea_obj->eo_item.ei_raw = ea_alloc(ea_obj->eo_item.ei_size);
427 		bcopy(SvPV_nolen(value), ea_obj->eo_item.ei_raw,
428 		    (size_t)ea_obj->eo_item.ei_size);
429 		break;
430 	case EXT_EXACCT_OBJECT:
431 		/*
432 		 * The ea_obj part is initially empty, and will be populated
433 		 * from the perl_obj part  when required.
434 		 */
435 		stash = SvROK(value) ? SvSTASH(SvRV(value)) : NULL;
436 		if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
437 		    stash != Sun_Solaris_Exacct_Object_Group_stash) {
438 			croak("value is not of type " PKGBASE "::Object");
439 		}
440 		RETVAL->perl_obj = copy_xs_ea_object(value);
441 		ea_obj->eo_item.ei_object = NULL;
442 		ea_obj->eo_item.ei_size = 0;
443 		INIT_EMBED_ITEM_FLAGS(RETVAL);
444 		break;
445 	/*
446 	 * EXT_NONE is an invalid type,
447 	 * EXT_GROUP is created by the Group subclass constructor.
448 	 */
449 	case EXT_NONE:
450 	case EXT_GROUP:
451 	default:
452 		ea_free(RETVAL->ea_obj, sizeof (RETVAL->ea_obj));
453 		Safefree(RETVAL);
454 		croak("Invalid object type");
455 		break;
456 	}
457 OUTPUT:
458 	RETVAL
459 
460 MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object::Group
461 PROTOTYPES: ENABLE
462 
463 xs_ea_object_t *
464 new(class, catalog, ...)
465 	char	*class;
466 	SV	*catalog;
467 PREINIT:
468 	ea_catalog_t	tag;
469 	ea_object_t	*ea_obj;
470 	AV		*tied_av, *av;
471 	SV		*sv, *rv;
472 	int		i;
473 CODE:
474 	tag = catalog_value(catalog);
475 	if ((tag & EXT_TYPE_MASK) != EXT_GROUP) {
476 		croak("Invalid object type");
477 	}
478 
479 	/* Create a new xs_ea_object_t and subsiduary structures. */
480 	New(0, RETVAL, 1, xs_ea_object_t);
481 	RETVAL->ea_obj = ea_obj = ea_alloc(sizeof (ea_object_t));
482 	bzero(ea_obj, sizeof (*ea_obj));
483 	ea_obj->eo_type = EO_GROUP;
484 	ea_obj->eo_catalog = tag;
485 	INIT_GROUP_FLAGS(RETVAL);
486 	RETVAL->perl_obj = NULL;
487 
488 	/* Create a new AV and copy in all the passed Items. */
489 	av = newAV();
490 	av_extend(av, items - 2);
491 	for (i = 2; i < items; i++) {
492 		HV	*stash;
493 		stash = SvROK(ST(i)) ? SvSTASH(SvRV(ST(i))) : NULL;
494 		if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
495 		    stash != Sun_Solaris_Exacct_Object_Group_stash) {
496 			croak("item is not of type " PKGBASE "::Object");
497 		}
498 		av_store(av, i - 2, copy_xs_ea_object(ST(i)));
499 	}
500 
501 	/* Bless the copied AV and tie it to a new AV */
502 	rv = newRV_noinc((SV *)av);
503 	sv_bless(rv, Sun_Solaris_Exacct_Object__Array_stash);
504 	tied_av = newAV();
505 	sv_magic((SV *)tied_av, rv, 'P', Nullch, 0);
506 	SvREFCNT_dec(rv);
507 	RETVAL->perl_obj = newRV_noinc((SV *)tied_av);
508 OUTPUT:
509 	RETVAL
510 
511  #
512  # Return the contents of the group as a hashref, using the string value of each
513  # item's catalog id as the key.  There are two forms - as_hash() which stores
514  # each hash value as a scalar, and should be used when it is known the group
515  # does not contain duplicate catalog tags, and as_hashlist wich stores each
516  # hash value as an array of values, and can therefore be used when the group
517  # may contain duplicate catalog tags.
518  #
519 
520 SV *
521 as_hash(self)
522 	xs_ea_object_t	*self;
523 ALIAS:
524 	as_hashlist = 1
525 PREINIT:
526 	MAGIC   *mg;
527 	HV	*hv;
528 	AV	*av;
529 	int	len, i;
530 CODE:
531 	/* Make sure the object is inflated. */
532 	if (self->perl_obj == NULL) {
533 		if (! inflate_xs_ea_object(self)) {
534 			XSRETURN_UNDEF;
535 		}
536 	}
537 
538 	/* Find the AV underlying the tie and create the new HV. */
539 	mg = mg_find(SvRV(self->perl_obj), 'P');
540 	PERL_ASSERT(mg != NULL);
541 	av = (AV *)SvRV(mg->mg_obj);
542 	PERL_ASSERT(av != NULL);
543 	hv = newHV();
544 
545 	/*
546 	 * Traverse the value array, saving the values in the hash,
547 	 * keyed by the string value of the catalog id field.
548 	 */
549 	len = av_len(av) + 1;
550 	for (i = 0; i < len; i++) {
551 		SV		**svp, *val;
552 		xs_ea_object_t	*xs_obj;
553 		const char	*key;
554 
555 		/* Ignore undef values. */
556 		if ((svp = av_fetch(av, i, FALSE)) == NULL) {
557 			continue;
558 		}
559 		PERL_ASSERT(*svp != NULL);
560 
561 		/* Figure out the key. */
562 		xs_obj = INT2PTR(xs_ea_object_t *, SvIV(SvRV(*svp)));
563 		key = catalog_id_str(xs_obj->ea_obj->eo_catalog);
564 
565 		/*
566 		 * For Items, save the perl representation
567 		 * of the underlying ea_object_t.
568 		 */
569 		if (IS_ITEM(xs_obj)) {
570 			switch (xs_obj->ea_obj->eo_catalog & EXT_TYPE_MASK) {
571 			case EXT_UINT8:
572 				val =
573 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint8);
574 				break;
575 			case EXT_UINT16:
576 				val =
577 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint16);
578 				break;
579 			case EXT_UINT32:
580 				val =
581 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint32);
582 				break;
583 			case EXT_UINT64:
584 				val =
585 				    newSVuv(xs_obj->ea_obj->eo_item.ei_uint64);
586 				break;
587 			case EXT_DOUBLE:
588 				val =
589 				    newSVnv(xs_obj->ea_obj->eo_item.ei_double);
590 				break;
591 			case EXT_STRING:
592 				val =
593 				    newSVpvn(xs_obj->ea_obj->eo_item.ei_string,
594 				    xs_obj->ea_obj->eo_item.ei_size - 1);
595 				break;
596 			case EXT_RAW:
597 				val =
598 				    newSVpvn(xs_obj->ea_obj->eo_item.ei_raw,
599 				    xs_obj->ea_obj->eo_item.ei_size);
600 				break;
601 			/*
602 			 * For embedded objects and Groups, return a ref
603 			 * to the perl SV.
604 			 */
605 			case EXT_EXACCT_OBJECT:
606 				if (xs_obj->perl_obj == NULL) {
607 					/* Make sure the object is inflated. */
608 					if (! inflate_xs_ea_object(xs_obj)) {
609 						SvREFCNT_dec(hv);
610 						XSRETURN_UNDEF;
611 					}
612 				}
613 				val = SvREFCNT_inc(xs_obj->perl_obj);
614 				break;
615 			case EXT_GROUP:
616 				val = SvREFCNT_inc(xs_obj->perl_obj);
617 				break;
618 			case EXT_NONE:
619 			default:
620 				croak("Invalid object type");
621 				break;
622 			}
623 		/*
624 		 * Now we deal with Groups.
625 		 */
626 		} else {
627 			/* Make sure the object is inflated. */
628 			if (xs_obj->perl_obj == NULL) {
629 				if (! inflate_xs_ea_object(xs_obj)) {
630 					SvREFCNT_dec(hv);
631 					XSRETURN_UNDEF;
632 				}
633 			}
634 			val = SvREFCNT_inc(xs_obj->perl_obj);
635 		}
636 
637 		/*
638 		 * If called as as_hash(), store the value directly in the
639 		 * hash, if called as as_hashlist(), store the value in an
640 		 * array within the hash.
641 		 */
642 		if (ix == 0) {
643 			hv_store(hv, key, strlen(key), val, FALSE);
644 		} else {
645 			AV *ary;
646 
647 			/* If the key already exists in the hash. */
648 			svp = hv_fetch(hv, key, strlen(key), TRUE);
649 			if (SvOK(*svp)) {
650 				ary = (AV *)SvRV(*svp);
651 
652 			/* Otherwise, add a new array to the hash. */
653 			} else {
654 				SV *rv;
655 				ary = newAV();
656 				rv = newRV_noinc((SV *)ary);
657 				sv_setsv(*svp, rv);
658 				SvREFCNT_dec(rv);
659 			}
660 			av_push(ary, val);
661 		}
662 	}
663 	RETVAL = newRV_noinc((SV *)hv);
664 OUTPUT:
665 	RETVAL
666 
667 MODULE = Sun::Solaris::Exacct::Object PACKAGE = Sun::Solaris::Exacct::Object::_Array
668 PROTOTYPES: ENABLE
669 
670  #
671  # Copy the passed list of xs_ea_object_t.
672  #
673 void
674 copy_xs_ea_objects(...)
675 PREINIT:
676 	int	i;
677 PPCODE:
678 	EXTEND(SP, items);
679 	for (i = 0; i < items; i++) {
680 		HV	*stash;
681 		stash = SvROK(ST(i)) ? SvSTASH(SvRV(ST(i))) : NULL;
682 		if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
683 		    stash != Sun_Solaris_Exacct_Object_Group_stash) {
684 			croak("item is not of type " PKGBASE "::Object");
685 		}
686 		PUSHs(sv_2mortal(copy_xs_ea_object(ST(i))));
687 	}
688