1N/A/*
1N/A * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
1N/A *
1N/A * File.xs contains XS code for exacct file manipulation.
1N/A */
1N/A
1N/A#include <pwd.h>
1N/A#include "../exacct_common.xh"
1N/A
1N/A/* Pull in the file generated by extract_defines. */
1N/A#include "FileDefs.xi"
1N/A
1N/A/*
1N/A * The XS code exported to perl is below here. Note that the XS preprocessor
1N/A * has its own commenting syntax, so all comments from this point on are in
1N/A * that form.
1N/A */
1N/A
1N/AMODULE = Sun::Solaris::Exacct::File PACKAGE = Sun::Solaris::Exacct::File
1N/APROTOTYPES: ENABLE
1N/A
1N/A #
1N/A # Define the stash pointers if required and create and populate @_Constants.
1N/A #
1N/ABOOT:
1N/A {
1N/A init_stashes();
1N/A define_constants(PKGBASE "::File", constants);
1N/A }
1N/A
1N/A #
1N/A # Open an exacct file and return an object with which to manipulate it.
1N/A # The parameters are the filename, the open mode and a list of optional
1N/A # (key => value) parameters where the key may be one of creator, aflags or
1N/A # mode. For a full explanation of the various combinations, see the manpage
1N/A # for ea_open_file(3EXACCT).
1N/A #
1N/Aea_file_t *
1N/Anew(class, name, oflags, ...)
1N/A char *class;
1N/A char *name;
1N/A int oflags;
1N/APREINIT:
1N/A int i;
1N/A /* Assume usernames are <= 32 chars (pwck(1M) assumes <= 8) */
1N/A char user[33];
1N/A char *creator = NULL;
1N/A int aflags = -1;
1N/A mode_t mode = 0666;
1N/ACODE:
1N/A /*
1N/A * Account for the mandatory parameters,
1N/A * and the rest must be an even number.
1N/A */
1N/A i = items - 3;
1N/A if ((i % 2) != 0) {
1N/A croak("Usage: Sun::Solaris::Exacct::File::new"
1N/A "(class, name, oflags, ...)");
1N/A }
1N/A
1N/A /* Process any optional parameters. */
1N/A for (i = 3; i < items; i += 2) {
1N/A if (strEQ(SvPV_nolen(ST(i)), "creator")) {
1N/A creator = SvPV_nolen(ST(i + 1));
1N/A } else if (strEQ(SvPV_nolen(ST(i)), "aflags")) {
1N/A aflags = SvIV(ST(i + 1));
1N/A } else if (strEQ(SvPV_nolen(ST(i)), "mode")) {
1N/A mode = SvIV(ST(i + 1));
1N/A } else {
1N/A croak("invalid named argument %s", SvPV_nolen(ST(i)));
1N/A }
1N/A }
1N/A
1N/A /* Check and default the creator parameter. */
1N/A if (oflags & O_CREAT && creator == NULL) {
1N/A uid_t uid;
1N/A struct passwd *pwent;
1N/A
1N/A uid = getuid();
1N/A if ((pwent = getpwuid(uid)) == NULL) {
1N/A snprintf(user, sizeof (user), "%d", uid);
1N/A } else {
1N/A strlcpy(user, pwent->pw_name, sizeof (user));
1N/A }
1N/A creator = user;
1N/A }
1N/A
1N/A /* Check and default the aflags parameter. */
1N/A if (aflags == -1) {
1N/A if (oflags == O_RDONLY) {
1N/A aflags = EO_HEAD;
1N/A } else {
1N/A aflags = EO_TAIL;
1N/A }
1N/A }
1N/A RETVAL = ea_alloc(sizeof (ea_file_t));
1N/A PERL_ASSERT(RETVAL != NULL);
1N/A if (ea_open(RETVAL, name, creator, aflags, oflags, mode) == -1) {
1N/A ea_free(RETVAL, sizeof (ea_file_t));
1N/A RETVAL = NULL;
1N/A }
1N/AOUTPUT:
1N/A RETVAL
1N/A
1N/Avoid
1N/ADESTROY(self)
1N/A ea_file_t *self;
1N/ACODE:
1N/A ea_close(self);
1N/A ea_free(self, sizeof(ea_file_t));
1N/A
1N/A #
1N/A # Return the creator of the file.
1N/A #
1N/ASV*
1N/Acreator(self)
1N/A ea_file_t *self;
1N/APREINIT:
1N/A const char *creator;
1N/ACODE:
1N/A if ((creator = ea_get_creator(self)) == NULL) {
1N/A RETVAL = &PL_sv_undef;
1N/A } else {
1N/A RETVAL = newSVpv(creator, 0);
1N/A }
1N/AOUTPUT:
1N/A RETVAL
1N/A
1N/A #
1N/A # Return the hostname the file was created on.
1N/A #
1N/ASV*
1N/Ahostname(self)
1N/A ea_file_t *self;
1N/APREINIT:
1N/A const char *hostname;
1N/ACODE:
1N/A if ((hostname = ea_get_hostname(self)) == NULL) {
1N/A RETVAL = &PL_sv_undef;
1N/A } else {
1N/A RETVAL = newSVpv(hostname, 0);
1N/A }
1N/AOUTPUT:
1N/A RETVAL
1N/A
1N/A #
1N/A # Get the next/previous record from the file and return its type.
1N/A # These two operations are so similar that the XSUB ALIAS functionality is
1N/A # used to merge them into one function.
1N/A #
1N/Avoid
1N/Anext(self)
1N/A ea_file_t *self;
1N/AALIAS:
1N/A previous = 1
1N/APREINIT:
1N/A ea_object_type_t type;
1N/A const char *type_str;
1N/A ea_object_t object;
1N/A SV *sv;
1N/A static const char *const type_map[] =
1N/A { "EO_NONE", "EO_GROUP", "EO_ITEM" };
1N/APPCODE:
1N/A /* Call the appropriate next/last function. */
1N/A if (ix == 0) {
1N/A type = ea_next_object(self, &object);
1N/A } else {
1N/A type = ea_previous_object(self, &object);
1N/A }
1N/A
1N/A /* Work out the call context. */
1N/A switch (GIMME_V) {
1N/A case G_SCALAR:
1N/A /* In a scalar context, just return the type. */
1N/A EXTEND(SP, 1);
1N/A if (type == EO_ERROR) {
1N/A PUSHs(&PL_sv_undef);
1N/A } else {
1N/A sv = newSVuv(type);
1N/A sv_setpv(sv, type_map[type]);
1N/A SvIOK_on(sv);
1N/A PUSHs(sv_2mortal(sv));
1N/A }
1N/A break;
1N/A case G_ARRAY:
1N/A /* In a list contect, return the type and catalog. */
1N/A EXTEND(SP, 2);
1N/A if (type == EO_ERROR) {
1N/A PUSHs(&PL_sv_undef);
1N/A PUSHs(&PL_sv_undef);
1N/A } else {
1N/A sv = newSVuv(type);
1N/A sv_setpv(sv, type_map[type]);
1N/A SvIOK_on(sv);
1N/A PUSHs(sv_2mortal(sv));
1N/A PUSHs(sv_2mortal(new_catalog(object.eo_catalog)));
1N/A }
1N/A break;
1N/A case G_VOID:
1N/A default:
1N/A /* In a void context, return nothing. */
1N/A break;
1N/A }
1N/A
1N/A #
1N/A # Get the next object from the file and return as an ::Object.
1N/A #
1N/ASV*
1N/Aget(self)
1N/A ea_file_t *self;
1N/APREINIT:
1N/A ea_object_t *obj;
1N/ACODE:
1N/A if ((obj = ea_get_object_tree(self, 1)) != NULL) {
1N/A RETVAL = new_xs_ea_object(obj);
1N/A } else {
1N/A RETVAL = &PL_sv_undef;
1N/A }
1N/AOUTPUT:
1N/A RETVAL
1N/A
1N/A #
1N/A # Write the passed list of ::Objects to the file.
1N/A # Returns true on success and false on failure.
1N/A #
1N/ASV*
1N/Awrite(self, ...)
1N/A ea_file_t *self;
1N/APREINIT:
1N/A int i;
1N/A SV *sv;
1N/A HV *stash;
1N/A ea_object_t *obj;
1N/ACODE:
1N/A for (i = 1; i < items; i++) {
1N/A /* Check the value is either an ::Item or a ::Group. */
1N/A sv = SvRV(ST(i));
1N/A stash = sv ? SvSTASH(sv) : NULL;
1N/A if (stash != Sun_Solaris_Exacct_Object_Item_stash &&
1N/A stash != Sun_Solaris_Exacct_Object_Group_stash) {
1N/A XSRETURN_NO;
1N/A }
1N/A
1N/A /* Deflate and write the object. */
1N/A obj = deflate_xs_ea_object(ST(i));
1N/A PERL_ASSERT(obj != NULL);
1N/A if (ea_write_object(self, obj) == -1) {
1N/A XSRETURN_NO;
1N/A }
1N/A }
1N/A RETVAL = &PL_sv_yes;
1N/AOUTPUT:
1N/A RETVAL