Catalog.pm revision 12388:1bc8d55b0dfd
1# 2# Copyright (c) 2002, 2008 Oracle and/or its affiliates. All rights reserved. 3# 4 5# 6# Catalog.pm contains perl code for exacct catalog tag manipulation. 7# 8 9require 5.8.4; 10use strict; 11use warnings; 12 13package Sun::Solaris::Exacct::Catalog; 14 15our $VERSION = '1.3'; 16use Carp; 17use XSLoader; 18XSLoader::load(__PACKAGE__, $VERSION); 19 20# %_Constants and @_Constants are set up by the XSUB bootstrap() function. 21our (@EXPORT_OK, %EXPORT_TAGS, @_Constants, %_Constants); 22@EXPORT_OK = @_Constants; 23%EXPORT_TAGS = (CONSTANTS => \@_Constants, ALL => \@EXPORT_OK); 24 25use base qw(Exporter); 26 27# 28# Class interface. 29# 30 31# 32# Register a foreign catalog. Arguments are as follows: 33# <catalog prefix> Used to uniquely identify the catalog being defined. 34# Must be composed only of uppercase characters. 35# <catalog id> Numeric identifier for the catalog. 36# Must be between 1 and 15. 37# <export flag> If true, the constants defined by the register sub will 38# be exported into the caller's namespace. 39# <id list> List of (name, value) pairs. These are prefixed with 40# "<catalog_prefix>_" and are used for defining constants 41# that can be used as catalog id field values. 42# An example: 43# Sun::Solaris::Exacct::Catalog->register("FROB", 0x01, 1, 44# FLUB => 0x00000001, WURB => 0x00000010) 45# results in the definition of the following constants: 46# EXC_FROB 0x01 << 24 47# FROB_FLUB 0x00000001 48# FROB_WURB 0x00000010 49# 50# Returns 'undef' on success, otherwise an error message. 51# 52sub register 53{ 54 my ($class, $cat_pfx, $cat_id, $export, %idlist) = @_; 55 56 # Sanity checks. 57 my $cat = 'EXC_'. $cat_pfx; 58 return ("Invalid catalog prefix \"$cat_pfx\"") 59 if ($cat_pfx !~ /^[A-Z][A-Z0-9]*$/ || $cat_pfx =~ /^EX[TCD]$/); 60 return ("Duplicate catalog prefix") 61 if (exists($_Constants{catlg}{name}{$cat})); 62 my $id = $cat_id << 24; 63 return ("Invalid catalog id \"$cat_id\"") 64 if ($cat_id < 1 || $cat_id > 0xf); # 4-bit field 65 66 # Validate the (name, value) pairs. 67 my %seen; 68 while (my ($n, $v) = each(%idlist)) { 69 return ("Invalid id name \"$n\"") 70 if ($n !~ /^[A-Z][A-Z0-9_]*[A-Z0-9]$/); 71 return ("Invalid id value \"$v\"") 72 if ($v < 0 || $v > 0xffffff); # 24-bit field 73 return ("Redefinition of id value \"$v\"") 74 if ($seen{$v}++); 75 } 76 undef(%seen); 77 78 # Initialise new lookup data members 79 $_Constants{catlg}{name}{$cat} = $id; 80 $_Constants{catlg}{value}{$id} = $cat; 81 my $id_by_name = $_Constants{id}{name}{$cat_pfx}{name} = {}; 82 my $id_by_val = $_Constants{id}{name}{$cat_pfx}{value} = {}; 83 $_Constants{id}{value}{$id} = $_Constants{id}{name}{$cat_pfx}; 84 85 # Put the passed (name, value) pairs into the appropriate hashes. 86 my @export_ok = ($cat); 87 while (my ($n, $v) = each(%idlist)) { 88 my $pn = "${cat_pfx}_${n}"; 89 $id_by_name->{$pn} = $v; 90 $id_by_val->{$v} = $pn; 91 push(@export_ok, $pn); 92 } 93 94 # Export the new symbols into the caller's namespace if required. 95 if ($export) { 96 our (%EXPORT, @EXPORT_OK); 97 @EXPORT{@export_ok} = (1) x @export_ok; 98 push(@EXPORT_OK, @export_ok); 99 __PACKAGE__->export_to_level(1, undef, @export_ok); 100 } 101} 102 103# 104# Create a new Catalog object. Arguments are either an integer, an existing 105# Catalog object or a (type, catalog, id) triplet. 106# 107sub new 108{ 109 my ($class, @vals) = @_; 110 my $value; 111 112 # A single value must be a full catalog tag 113 if (@vals == 1) { 114 $value = _catalog_value($vals[0]); 115 116 # A list of 3 values is (type, catalog, id) 117 } elsif (@vals == 3) { 118 my ($t, $c, $d) = @vals; 119 my ($which); 120 121 $which = _is_iv($t) ? 'value' : 'name'; 122 croak("Invalid data type \"$t\"") 123 if (! exists($_Constants{type}{$which}{$t})); 124 $t = $_Constants{type}{name}{$t} if ($which eq 'name'); 125 126 $which = _is_iv($c) ? 'value' : 'name'; 127 croak("Invalid catalog \"$c\"") 128 if (! exists($_Constants{catlg}{$which}{$c})); 129 $c = $_Constants{catlg}{name}{$c} if ($which eq 'name'); 130 131 $which = _is_iv($d) ? 'value' : 'name'; 132 croak("Invalid data id \"$d\"") 133 if (! exists($_Constants{id}{value}{$c}{$which}{$d})); 134 $d = $_Constants{id}{value}{$c}{name}{$d} if ($which eq 'name'); 135 136 $value = $t | $c | $d; 137 138 # Only 1 or 3 arguments are valid 139 } else { 140 croak("Invalid number of arguments"); 141 } 142 143 # Create a readonly catalog object. 144 return (_new_catalog($value)); 145} 146 147# 148# Object interface. 149# 150 151# 152# Get the value of a Catalog object. In a scalar context it returns the 32-bit 153# integer representing the tag. In a list context it returns a 154# (type, catalog, id) triplet. Each of these is a dual-typed SV that in a 155# string context returns a representation of the appropriate constant, e.g. 156# 'EXD_HOSTNAME', and in a numeric context returns the integer value of the 157# associated constant. 158# 159sub value 160{ 161 my ($self) = @_; 162 163 # In an array context return the split out catalog components 164 if (wantarray()) { 165 my $t = $$self & &EXT_TYPE_MASK; 166 $t = _double_type($t, exists($_Constants{type}{value}{$t}) 167 ? $_Constants{type}{value}{$t} 168 : 'UNKNOWN_TYPE'); 169 170 my $c = $$self & &EXC_CATALOG_MASK; 171 $c = _double_type($c, 172 exists($_Constants{catlg}{value}{$c}) 173 ? $_Constants{catlg}{value}{$c} 174 : 'UNKNOWN_CATALOG'); 175 176 my $d = $$self & &EXD_DATA_MASK; 177 $d = _double_type($d, 178 exists($_Constants{id}{value}{int($c)}{value}{$d}) 179 ? $_Constants{id}{value}{int($c)}{value}{$d} 180 : 'UNKNOWN_ID'); 181 182 return($t, $c, $d); 183 184 # In a scalar context return the whole thing 185 } else { 186 return($$self); 187 } 188} 189 190# 191# Fetch the type field of the Catalog object. The return value is a dual-typed 192# SV that in a string context returns a representation of the appropriate 193# constant, e.g. 'EXT_STRING', and in a numeric context returns the integer 194# value of the associated constant. 195# 196sub type 197{ 198 my ($self) = @_; 199 200 # Extract the type field and look up the string representation. 201 my $t = $$self & &EXT_TYPE_MASK; 202 $t = _double_type($t, exists($_Constants{type}{value}{$t}) 203 ? $_Constants{type}{value}{$t} : 'UNKNOWN_TYPE'); 204 return ($t); 205} 206 207# 208# Fetch the catalog field of the Catalog object. (see type()). 209# 210sub catalog 211{ 212 my ($self, $val) = @_; 213 214 # Extract the catalog field and look up the string representation. 215 my $c = $$self & &EXC_CATALOG_MASK; 216 $c = _double_type($c, exists($_Constants{catlg}{value}{$c}) 217 ? $_Constants{catlg}{value}{$c} : 'UNKNOWN_CATALOG'); 218 return ($c); 219} 220 221# 222# Fetch the id field of the Catalog object. (see type()). 223# 224sub id 225{ 226 my ($self, $val) = @_; 227 228 # 229 # Extract the catalog and id field and look up the 230 # string representation of the id field. 231 # 232 my $c = $$self & &EXC_CATALOG_MASK; 233 my $d = $$self & &EXD_DATA_MASK; 234 $d = _double_type($d, exists($_Constants{id}{value}{$c}{value}{$d}) 235 ? $_Constants{id}{value}{$c}{value}{$d} : 'UNKNOWN_ID'); 236 return ($d); 237} 238 239# 240# Return a string representation of the type field. 241# 242sub type_str 243{ 244 my ($self) = @_; 245 246 # Lookup the type and fabricate a string from it. 247 my $t = $$self & &EXT_TYPE_MASK; 248 if (exists($_Constants{type}{value}{$t})) { 249 $t = $_Constants{type}{value}{$t}; 250 $t =~ s/^EXT_//; 251 $t =~ s/_/ /g; 252 return(lc($t)); 253 } else { 254 return('UNKNOWN TYPE'); 255 } 256} 257 258# 259# Return a string representation of the catalog field. 260# 261sub catalog_str 262{ 263 my ($self) = @_; 264 265 # Lookup the catalog and fabricate a string from it. 266 my $c = $$self & &EXC_CATALOG_MASK; 267 if (exists($_Constants{catlg}{value}{$c})) { 268 $c = $_Constants{catlg}{value}{$c}; 269 $c =~ s/^EXC_//; 270 $c =~ s/_/ /g; 271 return(lc($c)); 272 } else { 273 return('UNKNOWN CATALOG'); 274 } 275} 276 277# 278# Return a string representation of the id field. 279# 280sub id_str 281{ 282 my ($self) = @_; 283 284 # Lookup the id and fabricate a string from it. 285 my $c = $$self & &EXC_CATALOG_MASK; 286 my $d = $$self & &EXD_DATA_MASK; 287 if (exists($_Constants{id}{value}{$c}) && 288 exists($_Constants{id}{value}{$c}{value}{$d})) { 289 $d = $_Constants{id}{value}{$c}{value}{$d}; 290 $d =~ s/^[A-Z]+_//; 291 $d =~ s/_/ /g; 292 return(lc($d)); 293 } else { 294 return('UNKNOWN ID'); 295 } 296} 297 298# 299# AUTOLOAD for constant definitions. Values are looked up in the %_Constants 300# hash, and then used to create an anonymous sub that will return the correct 301# value. This is then placed into the appropriate symbol table so that future 302# calls will bypass the AUTOLOAD and call the sub directly. 303# 304sub AUTOLOAD 305{ 306 # Extract the name of the constant we are looking for, and its prefix. 307 our $AUTOLOAD; 308 my $const = $AUTOLOAD; 309 $const =~ s/.*:://; 310 my ($prefix) = $const =~ /^([^_]+)/; 311 312 # Try to find the appropriate prefix hash. 313 my $href; 314 if ($prefix eq 'EXT') { 315 $href = $_Constants{type}{name}; 316 } elsif ($prefix eq 'EXC') { 317 $href = $_Constants{catlg}{name}; 318 } elsif (exists($_Constants{id}{name}{$prefix})) { 319 $href = $_Constants{id}{name}{$prefix}{name}; 320 } 321 322 # Look first in the prefix hash, otherwise try the 'other' hash. 323 my $val = undef; 324 if (exists($href->{$const})) { 325 $val = $href->{$const}; 326 } elsif (exists($_Constants{other}{name}{$const})) { 327 $val = $_Constants{other}{name}{$const}; 328 } 329 330 # 331 # Generate the const sub, place in the appropriate glob 332 # and finally goto it to return the value. 333 # 334 croak("Undefined constant \"$const\"") if (! defined($val)); 335 my $sub = sub { return $val; }; 336 no strict qw(refs); 337 *{$AUTOLOAD} = $sub; 338 goto &$sub; 339} 340 341# 342# To quieten AUTOLOAD - if this isn't defined AUTLOAD will be called 343# unnecessarily during object destruction. 344# 345sub DESTROY 346{ 347} 348 3491; 350