# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # use xmlHandlers; package externalEvent; 1; sub new { my $pkg = shift; my $id = shift; my $obj = shift; my @kid = $obj->getKids(); # kids of event are entry or allowed_types # separate kids into classes and create hash of entries and an # array of includes my %entry = (); my @entry = (); my @allowed_types = (); my @include = (); my $internalName = ''; my $kid; foreach $kid (@kid) { my $class = $kid->getClass(); my $kidId = $kid->getAttr('id'); if ($class eq 'entry') { my $tokenId = 'undefined'; my $format = ''; my $internal = $kid->getKid('internal'); if (defined $internal) { $tokenId = $internal->getAttr('token'); $format = $internal->getAttr('format'); $format = '' unless defined $format; } my $comment; my $commentKid = $kid->getKid('comment'); if (defined $commentKid) { $comment = $commentKid->getContent; } my $external = $kid->getKid('external'); if (defined ($external)) { $entry{$kidId} = [$external, $kid, $tokenId, $format, $comment]; push (@entry, $kidId); } else { print STDERR "no external attributes defined for $id/$kidId\n"; } } # handle event id translation... elsif ($class eq 'altname') { $internalName = $kid->getAttr('id'); unless (defined $internalName) { print STDERR "missing id for internal name of $id\n"; $internalName = 'error'; } } elsif ($class eq 'allowed_types') { my $content = $kid->getContent(); @allowed_types = (@allowed_types, split(/\s*,\s*/, $content)); } } my @entryCopy = @entry; return bless {'id' => $id, 'internalName' => $internalName, 'allowed_types' => \@allowed_types, 'entry' => \%entry, 'entryList' => \@entry, 'entryListCopy' => \@entryCopy, 'include' => \@include, 'xmlObj' => $obj}, $pkg; } # return id sub getExternalName { my $pkg = shift; return $pkg->{'id'}; } # return internal name if it exists, else id sub getInternalName { $pkg = shift; if ($pkg->{'internalName'}) { return $pkg->{'internalName'}; } else { return $pkg->{'id'}; } } # getNextEntry reads from 'entryList' destructively # but resets when the list after the list is emptied sub getNextEntry { my $pkg = shift; unless (@{$pkg->{'entryList'}}) { @{$pkg->{'entryList'}} = @{$pkg->{'entryListCopy'}}; return undef; } my $id = shift @{$pkg->{'entryList'}}; return ($pkg->getEntry($id)); # getEntry returns an array } # getEntryIds returns list of all ids from entryList sub getEntryIds { my $pkg = shift; return (@{$pkg->{'entryList'}}); } # getEntry returns a selected entry for the current event sub getEntry { my $pkg = shift; my $id = shift; #entry id my $ref = $pkg->{'entry'}; my $array = $$ref{$id}; return @$array; } # getNextInclude reads from 'include' destructively sub getNextInclude { my $pkg = shift; return shift @{$pkg->{'include'}}; } # getIncludes returns list of 'include' sub getIncludes { my $pkg = shift; return @{$pkg->{'include'}}; } # return a reference to the list of event id's allowed for # this generic event sub getAllowedTypes { my $pkg = shift; return $pkg->{'allowed_types'}; } package internalEvent; 1; sub new { my $pkg = shift; my $id = shift; my $obj = shift; my @kid = $obj->getKids(); # kids of event are entry my @entry = (); my $reorder = 0; if ($reorder = $obj->getAttr('reorder')) { $reorder = 1 if $reorder eq 'yes'; } my $kid; foreach $kid (@kid) { my $class = $kid->getClass(); my $id = $kid->getAttr('id'); if ($class eq 'entry') { my $internal = $kid->getKid('internal'); if (defined ($internal)) { push (@entry, [$internal, $kid]); } else { print STDERR "no internal attributes defined for $id\n"; } } } return bless {'id' => $id, 'reorder' => $reorder, 'entry' => \@entry, 'xmlObj' => $obj}, $pkg; } # getEntries returns a list of all entry references sub getEntries { my $pkg = shift; return undef unless @{$pkg->{'entry'}}; return @{$pkg->{'entry'}}; } sub isReorder { my $pkg = shift; return $pkg->{'reorder'}; } sub getId { my $pkg = shift; return $pkg->{'id'}; } package eventDef; %uniqueId = (); 1; sub new { my $pkg = shift; my $id = shift; my $obj = shift; my $super = shift; my $omit; my $type; my $header; my $idNo; my $javaToo; my $title = ''; my @program = (); my @see = (); $omit = '' unless $omit = $obj->getAttr('omit'); $type = '' unless $type = $obj->getAttr('type'); $header = 0 unless $header = $obj->getAttr('header'); $idNo = '' unless $idNo = $obj->getAttr('idNo'); if ($idNo ne '' && $uniqueId{$idNo}) { print STDERR "$uniqueId{$idNo} and $id have the same id ($idNo)\n"; } else { $uniqueId{$idNo} = $id; } return bless {'id' => $id, 'header' => $header, 'idNo' => $idNo, 'omit' => $omit, 'super' => $super, 'type' => $type, 'title' => $title, 'program' => \@program, 'see' => \@see, 'external' => 0, 'internal' => 0}, $pkg; } # putDef is called at the end of an block, so # it sees a completed object. sub putDef { my $pkg = shift; my $obj = shift; # ref to xmlHandlers event object my $context = shift; my $id = $pkg->{'id'}; if ($context eq 'internal') { $pkg->{$context} = new internalEvent($id, $obj); return undef; } elsif ($context eq 'external') { my $ref = $pkg->{$context} = new externalEvent($id, $obj); return $ref->{'internalName'}; } } sub getId { my $pkg = shift; return $pkg->{'id'}; } sub getHeader { my $pkg = shift; return $pkg->{'header'}; } sub getIdNo { my $pkg = shift; return $pkg->{'idNo'}; } sub getSuperClass { my $pkg = shift; return $pkg->{'super'}; } sub getOmit { my $pkg = shift; return $pkg->{'omit'}; } sub getType { my $pkg = shift; return $pkg->{'type'}; } sub getTitle { return shift->{'title'}; } sub getProgram { return shift->{'program'}; } sub getSee { return shift->{'see'}; } sub getInternal { my $pkg = shift; return $pkg->{'internal'}; } sub getExternal { my $pkg = shift; return $pkg->{'external'}; } # this isn't fully implemented; just a skeleton package tokenDef; 1; sub new { my $pkg = shift; my $obj = shift; my $id = shift; $usage = $obj->getAttr('usage'); $usage = '' unless defined $usage; return bless {'id' => $id, 'usage' => $usage }, $pkg; } sub getId { my $pkg = shift; return $pkg->{'id'}; } sub getUsage { my $pkg = shift; return $pkg->{'usage'}; } package messageList; 1; sub new { my $pkg = shift; my $obj = shift; my $id = shift; my $header = shift; my $start = shift; my $public = shift; my $deprecated = shift; my @msg = (); my @kid = $obj->getKids(); # kids of msg_list are msg my $kid; foreach $kid (@kid) { my $class = $kid->getClass(); if ($class eq 'msg') { my $text = $kid->getContent(); $text = '' unless defined ($text); my $msgId = $kid->getAttr('id'); if (defined ($msgId)) { push(@msg, join('::', $msgId, $text)); } else { print STDERR "missing id for $class \n"; } } else { print STDERR "invalid tag in block: $class\n"; } } return bless {'id' => $id, 'header' => $header, 'msg' => \@msg, 'start' => $start, 'public' => $public, 'deprecated' => $deprecated }, $pkg; } sub getId { my $pkg = shift; return $pkg->{'id'}; } sub getMsgStart { my $pkg = shift; return $pkg->{'start'}; } sub getDeprecated { my $pkg = shift; return $pkg->{'deprecated'}; } sub getMsgPublic { my $pkg = shift; return $pkg->{'public'}; } sub getHeader { my $pkg = shift; return $pkg->{'header'}; } # destructive read of @msg... sub getNextMsg { my $pkg = shift; my @msg = @{$pkg->{'msg'}}; return undef unless @msg; my $text = pop(@msg); $pkg->{'msg'} = \@msg; return $text; } # returns all msgs sub getMsgs { my $pkg = shift; return @{$pkg->{'msg'}}; } package auditxml; # These aren't internal state because the callback functions don't # have the object handle. @debug = (); # stack for nesting debug state %event = (); # event name => $objRef @event = (); # event id %token = (); # token name => $objRef @token = (); # token id %msg_list = (); # messageList string list id to obj @msg_list = (); # id list %service = (); # valid service names %externalToInternal = (); # map external event name to internal event name 1; sub new { my $pkg = shift; my $file = shift; # xml file to be parsed register('event', \&eventStart, \&eventEnd); register('entry', 0, \&entry); register('external', 0, \&external); register('internal', 0, \&internal); register('include', 0, \&include); register('token', 0, \&token); register('service', 0, \&service); register('msg_list', 0, \&msg_list); register('msg', 0, \&msg); # do not use register() for debug because register generates extra # debug information xmlHandlers::registerStartCallback('debug', \&debugStart); xmlHandlers::registerEndCallback('debug', \&debugEnd); $xml = new xmlHandlers(0, 'top level', $file); return bless {'xmlObj' => $xml, 'firstToken' => 1, 'firstEvent' => 1}, $pkg; } # local function -- register both the auditxml function and the # xmlHandler callback sub register { my $localName = shift; my $startFunction = shift; my $endFunction = shift; if ($startFunction) { xmlHandlers::registerStartCallback($localName, \&completed); $startFunction{$localName} = $startFunction; } if ($endFunction) { xmlHandlers::registerEndCallback($localName, \&completed); $endFunction{$localName} = $endFunction; } } sub completed { my $obj = shift; my $callbackSource = shift; my $id = $obj->getAttr('id'); my $class = $obj->getClass(); if ($main::debug) { print "*** $callbackSource: $class", (defined ($id)) ? "= $id\n" : "\n"; my %attributes = $obj->getAttributes(); my $attribute; foreach $attribute (keys %attributes) { print "*** $attribute = $attributes{$attribute}\n"; } my $content = $obj->getContent(); print "*** content = $content\n" if defined $content; } if ($callbackSource eq 'start') { &{$startFunction{$class}}($obj); } elsif ($callbackSource eq 'end') { &{$endFunction{$class}}($obj); } else { print STDERR "no auditxml function defined for $class\n"; } } # getNextEvent reads from @event destructively. 'firstEvent' could # be used to make a copy from which to read. sub getNextEvent { my $pkg = shift; return undef unless (@event); if ($pkg->{'firstEvent'}) { @token = sort @token; $pkg->{'firstEvent'} = 1; } my $id = shift @event; return $event{$id}; } # returns all event ids sub getEventIds { my $pkg = shift; return @event; } # returns event for id sub getEvent { my $pkg = shift; my $id = shift; return $event{$id}; } sub getToken { my $pkg = shift; my $id = shift; return $token{$id}; } # getNextToken reads from @token destructively. 'firstToken' could # be used to make a copy from which to read. sub getNextToken { my $pkg = shift; return undef unless (@token); if ($pkg->{'firstToken'}) { @token = sort @token; $pkg->{'firstToken'} = 1; } my $id = shift @token; return $token{$id}; } # return token Ids sub getTokenIds { my $pkg = shift; return @token; } # getNextMsgId reads from @msg_list destructively. sub getNextMsgId { my $pkg = shift; return undef unless (@msg_list); my $id = shift @msg_list; return ($id, $msg_list{$id}); } sub getMsgIds { my $pkg = shift; return @msg_list; } sub getMsg { my $pkg = shift; my $id = shift; return $msg_list{$id}; } sub external { } sub internal { } sub eventStart { my $obj = shift; my $id = $obj->getAttr('id'); unless ($id) { print STDERR "eventStart can't get a valid id\n"; return; } unless (defined $event{$id}) { my $super; if ($super = $obj->getAttr('instance_of')) { $super = $event{$super}; } else { $super = 0; } $event{$id} = new eventDef($id, $obj, $super); push (@event, $id); } else { print STDERR "duplicate event id: $id\n"; } } sub eventEnd { my $obj = shift; my $id = $obj->getAttr('id'); unless (defined $id) { print STDERR "event element is missing required id attribute\n"; return; } print "event = $id\n" if $main::debug; foreach my $kid ($obj->getKids) { my $class = $kid->getClass; next unless ($class =~ /title|program|see/); my $content = $kid->getContent; if ($class eq 'title') { $event{$id}->{$class} = $content; } else { push @{$event{$id}->{$class}}, $content; } } $event{$id}->putDef($obj, 'internal'); my $internalName = $event{$id}->putDef($obj, 'external'); $externalToInternal{$id} = $internalName if $internalName; } # class method #sub getInternalName { # my $name = shift; # # return $externalToInternal{$name}; #} sub entry { } #sub include { # my $obj = shift; # # my $id = $obj->getAttr('id'); # # if (defined $id) { # print "include = $id\n" if $main::debug; # } # else { # print STDERR "include element is missing required id attribute\n"; # } #} sub token { my $obj = shift; my $id = $obj->getAttr('id'); if (defined $id) { print "token = $id\n" if $main::debug; $token{$id} = new tokenDef($obj, $id); push (@token, $id); } else { print STDERR "token element is missing required id attribute\n"; } } sub msg_list { my $obj = shift; my $id = $obj->getAttr('id'); my $header = $obj->getAttr('header'); my $start = $obj->getAttr('start'); my $public = $obj->getAttr('public'); my $deprecated = $obj->getAttr('deprecated'); $header = 0 unless $header; $start = 0 unless $start; $public = ($public) ? 1 : 0; $deprecated = ($deprecated) ? 1 : 0; if (defined $id) { print "msg_list = $id\n" if $main::debug; $msg_list{$id} = new messageList($obj, $id, $header, $start, $public, $deprecated); push (@msg_list, $id); } else { print STDERR "msg_list element is missing required id attribute\n"; } } sub msg { # my $obj = shift; } # Service name was dropped during PSARC review sub service { my $obj = shift; my $name = $obj->getAttr('name'); my $id = $obj->getAttr('id'); if ((defined $id) && (defined $name)) { print "service $name = $id\n" if $main::debug; $service{$name} = $id; } elsif (defined $name) { print STDERR "service $name is missing an id number\n"; } elsif (defined $id) { print STDERR "service name missing for id = $id\n"; } else { print STDERR "missing both name and id for a service entry\n"; } } #sub getServices { # # return %service; #} # or or # if the set attribute is omitted, debug state is toggled # debugStart / debugEnd are used to insure debug state is # scoped to the block between and sub debugStart { my $obj = shift; push (@debug, $main::debug); my $debug = $main::debug; my $state = $obj->getAttr('set'); if (defined $state) { $main::debug = ($state eq 'on') ? 1 : 0; } else { $main::debug = !$debug; } if ($debug != $main::debug) { print 'debug is ', $main::debug ? 'on' : 'off', "\n"; } } sub debugEnd { my $obj = shift; my $debug = $main::debug; $main::debug = pop (@debug); if ($debug != $main::debug) { print 'debug is ', $main::debug ? 'on' : 'off', "\n"; } }