1package OS2::PrfDB; 2 3use strict; 4 5require Exporter; 6use XSLoader; 7use Tie::Hash; 8 9our $debug; 10our @ISA = qw(Exporter Tie::Hash); 11# Items to export into callers namespace by default. Note: do not export 12# names by default without a very good reason. Use EXPORT_OK instead. 13# Do not simply export all your public functions/methods/constants. 14our @EXPORT = qw( 15 AnyIni UserIni SystemIni 16 ); 17our $VERSION = '0.04'; 18 19XSLoader::load 'OS2::PrfDB', $VERSION; 20 21# Preloaded methods go here. 22 23sub AnyIni { 24 new_from_int OS2::PrfDB::Hini OS2::Prf::System(0), 25 'Anyone of two "systemish" databases', 1; 26} 27 28sub UserIni { 29 new_from_int OS2::PrfDB::Hini OS2::Prf::System(1), 'User settings database', 1; 30} 31 32sub SystemIni { 33 new_from_int OS2::PrfDB::Hini OS2::Prf::System(2),'System settings database',1; 34} 35 36# Internal structure 0 => HINI, 1 => array of entries, 2 => iterator. 37 38sub TIEHASH { 39 die "Usage: tie %arr, OS2::PrfDB, filename\n" unless @_ == 2; 40 my ($obj, $file) = @_; 41 my $hini = ref $file eq 'OS2::PrfDB::Hini' ? $file 42 : new OS2::PrfDB::Hini $file; 43 die "Error opening profile database `$file': $!" unless $hini; 44 # print "tiehash `@_', hini $hini\n" if $debug; 45 bless [$hini, undef, undef]; 46} 47 48sub STORE { 49 my ($self, $key, $val) = @_; 50 die unless @_ == 3; 51 die unless ref $val eq 'HASH'; 52 my %sub; 53 tie %sub, 'OS2::PrfDB::Sub', $self->[0], $key; 54 %sub = %$val; 55} 56 57sub FETCH { 58 my ($self, $key) = @_; 59 die unless @_ == 2; 60 my %sub; 61 tie %sub, 'OS2::PrfDB::Sub', $self->[0], $key; 62 \%sub; 63} 64 65sub DELETE { 66 my ($self, $key) = @_; 67 die unless @_ == 2; 68 my %sub; 69 tie %sub, 'OS2::PrfDB::Sub', $self->[0], $key; 70 %sub = (); 71} 72 73# CLEAR ???? - deletion of the whole 74 75sub EXISTS { 76 my ($self, $key) = @_; 77 die unless @_ == 2; 78 return OS2::Prf::GetLength($self->[0]->[0], $key, undef) >= 0; 79} 80 81sub FIRSTKEY { 82 my $self = shift; 83 my $keys = OS2::Prf::Get($self->[0]->[0], undef, undef); 84 return undef unless defined $keys; 85 chop($keys); 86 $self->[1] = [split /\0/, $keys]; 87 # print "firstkey1 $self, `$self->[3]->[0], $self->[3]->[1]'\n" if $debug; 88 $self->[2] = 0; 89 return $self->[1]->[0]; 90 # OS2::Prf::Get($self->[0]->[0], $self->[2], $self->[3]->[0])); 91} 92 93sub NEXTKEY { 94 # print "nextkey `@_'\n" if $debug; 95 my $self = shift; 96 return undef unless $self->[2]++ < $#{$self->[1]}; 97 my $key = $self->[1]->[$self->[2]]; 98 return $key; #, OS2::Prf::Get($self->[0]->[0], $self->[2], $key)); 99} 100 101package OS2::PrfDB::Hini; 102 103sub new { 104 die "Usage: new OS2::PrfDB::Hini filename\n" unless @_ == 2; 105 shift; 106 my $file = shift; 107 my $hini = OS2::Prf::Open($file); 108 die "Error opening profile database `$file': $!" unless $hini; 109 bless [$hini, $file]; 110} 111 112# Takes HINI and file name: 113 114sub new_from_int { shift; bless [@_] } 115 116# Internal structure 0 => HINI, 1 => filename, 2 => do-not-close. 117 118sub DESTROY { 119 my $self = shift; 120 my $hini = $self->[0]; 121 unless ($self->[2]) { 122 OS2::Prf::Close($hini) or die "Error closing profile `$self->[1]': $!"; 123 } 124} 125 126package OS2::PrfDB::Sub; 127use Tie::Hash; 128 129our $debug; 130our @ISA = qw{Tie::Hash}; 131 132# Internal structure 0 => HINI, 1 => array of entries, 2 => iterator, 133# 3 => appname. 134 135sub TIEHASH { 136 die "Usage: tie %arr, OS2::PrfDB::Sub, filename, appname\n" unless @_ == 3; 137 my ($obj, $file, $app) = @_; 138 my $hini = ref $file eq 'OS2::PrfDB::Hini' ? $file 139 : new OS2::PrfDB::Hini $file; 140 die "Error opening profile database `$file': $!" unless $hini; 141 # print "tiehash `@_', hini $hini\n" if $debug; 142 bless [$hini, undef, undef, $app]; 143} 144 145sub STORE { 146 my ($self, $key, $val) = @_; 147 die unless @_ == 3; 148 OS2::Prf::Set($self->[0]->[0], $self->[3], $key, $val); 149} 150 151sub FETCH { 152 my ($self, $key) = @_; 153 die unless @_ == 2; 154 OS2::Prf::Get($self->[0]->[0], $self->[3], $key); 155} 156 157sub DELETE { 158 my ($self, $key) = @_; 159 die unless @_ == 2; 160 OS2::Prf::Set($self->[0]->[0], $self->[3], $key, undef); 161} 162 163# CLEAR ???? - deletion of the whole 164 165sub EXISTS { 166 my ($self, $key) = @_; 167 die unless @_ == 2; 168 return OS2::Prf::GetLength($self->[0]->[0], $self->[3], $key) >= 0; 169} 170 171sub FIRSTKEY { 172 my $self = shift; 173 my $keys = OS2::Prf::Get($self->[0]->[0], $self->[3], undef); 174 return undef unless defined $keys; 175 chop($keys); 176 $self->[1] = [split /\0/, $keys]; 177 # print "firstkey1 $self, `$self->[3]->[0], $self->[3]->[1]'\n" if $debug; 178 $self->[2] = 0; 179 return $self->[1]->[0]; 180 # OS2::Prf::Get($self->[0]->[0], $self->[2], $self->[3]->[0])); 181} 182 183sub NEXTKEY { 184 # print "nextkey `@_'\n" if $debug; 185 my $self = shift; 186 return undef unless $self->[2]++ < $#{$self->[1]}; 187 my $key = $self->[1]->[$self->[2]]; 188 return $key; #, OS2::Prf::Get($self->[0]->[0], $self->[2], $key)); 189} 190 191# Autoload methods go after =cut, and are processed by the autosplit program. 192 1931; 194__END__ 195# Below is the stub of documentation for your module. You better edit it! 196 197=head1 NAME 198 199OS2::PrfDB - Perl extension for access to OS/2 setting database. 200 201=head1 SYNOPSIS 202 203 use OS2::PrfDB; 204 tie %settings, OS2::PrfDB, 'my.ini'; 205 tie %subsettings, OS2::PrfDB::Sub, 'my.ini', 'mykey'; 206 207 print "$settings{firstkey}{subkey}\n"; 208 print "$subsettings{subkey}\n"; 209 210 tie %system, OS2::PrfDB, SystemIni; 211 $system{myapp}{mykey} = "myvalue"; 212 213 214=head1 DESCRIPTION 215 216The extension provides both high-level and low-level access to .ini 217files. 218 219=head2 High level access 220 221High-level access is the tie-hash access via two packages: 222C<OS2::PrfDB> and C<OS2::PrfDB::Sub>. First one supports one argument, 223the name of the file to open, the second one the name of the file to 224open and so called I<Application name>, or the primary key of the 225database. 226 227 tie %settings, OS2::PrfDB, 'my.ini'; 228 tie %subsettings, OS2::PrfDB::Sub, 'my.ini', 'mykey'; 229 230One may substitute a handle for already opened ini-file instead of the 231file name (obtained via low-level access functions). In particular, 3 232functions SystemIni(), UserIni(), and AnyIni() provide handles to the 233"systemish" databases. AniIni will read from both, and write into User 234database. 235 236=head2 Low-level access 237 238Low-level access functions reside in the package C<OS2::Prf>. They are 239 240=over 14 241 242=item C<Open(file)> 243 244Opens the database, returns an I<integer handle>. 245 246=item C<Close(hndl)> 247 248Closes the database given an I<integer handle>. 249 250=item C<Get(hndl, appname, key)> 251 252Retrieves data from the database given 2-part-key C<appname> C<key>. 253If C<key> is C<undef>, return the "\0" delimited list of C<key>s, 254terminated by \0. If C<appname> is C<undef>, returns the list of 255possible C<appname>s in the same form. 256 257=item C<GetLength(hndl, appname, key)> 258 259Same as above, but returns the length of the value. 260 261=item C<Set(hndl, appname, key, value [ , length ])> 262 263Sets the value. If the C<value> is not defined, removes the C<key>. If 264the C<key> is not defined, removes the C<appname>. 265 266=item C<System(val)> 267 268Return an I<integer handle> associated with the system database. If 269C<val> is 1, it is I<User> database, if 2, I<System> database, if 2700, handle for "both" of them: the handle works for read from any one, 271and for write into I<User> one. 272 273=item C<Profiles()> 274 275returns a reference to a list of two strings, giving names of the 276I<User> and I<System> databases. 277 278=item C<SetUser(file)> 279 280B<(Not tested.)> Sets the profile name of the I<User> database. The 281application should have a message queue to use this function! 282 283=back 284 285=head2 Integer handles 286 287To convert a name or an integer handle into an object acceptable as 288argument to tie() interface, one may use the following functions from 289the package C<OS2::Prf::Hini>: 290 291=over 14 292 293=item C<new(package, file)> 294 295=item C<new_from_int(package, int_hndl [ , filename ])> 296 297=back 298 299=head2 Exports 300 301SystemIni(), UserIni(), and AnyIni(). 302 303=head1 AUTHOR 304 305Ilya Zakharevich, ilya@math.ohio-state.edu 306 307=head1 SEE ALSO 308 309perl(1). 310 311=cut 312 313