/[pub]/suikawiki/script/lib/SuikaWiki/DB/FileSystem/SuikaWikiMetaInfo09.pm
Suika

Contents of /suikawiki/script/lib/SuikaWiki/DB/FileSystem/SuikaWikiMetaInfo09.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (show annotations) (download)
Thu Apr 1 04:45:16 2004 UTC (22 years, 4 months ago) by wakaba
Branch: MAIN
CVS Tags: suikawiki3-redirect, release-3-0-0, HEAD
Branch point for: paragraph-200404, helowiki, helowiki-2005
Changes since 1.7: +5 -4 lines
Typo fixed

1
2 =head1 NAME
3
4 SuikaWiki::DB::FileSystem::SuikaWikiMetaInfo09 --- SuikaWiki WikiDatabase: SuikaWikiMetaInfo/0.9 one-file meta properties database
5
6 =head1 DESCRIPTION
7
8 This module provides SuikaWiki WikiDatabase interface to SuikaWikiMetaInfo/0.9
9 format of database. It can keep keys with multiple properties into
10 one file. It is originally implemented as supplemental database of
11 Yuki::YukiWikiDBMeta.
12
13 This module is part of SuikaWiki.
14
15 =cut
16
17 package SuikaWiki::DB::FileSystem::SuikaWikiMetaInfo09;
18 use strict;
19 our $VERSION=do{my @r=(q$Revision: 1.7 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
20 require SuikaWiki::DB::Util;
21 push our @ISA, 'SuikaWiki::DB::Util::template';
22 my $Sep = '//';
23 my $Self = '.';
24 my $Parent = '..';
25
26 sub new ($%) {
27 my $self = shift->SUPER::new (@_);
28 my %opt = @_;
29 $self->{directory} = $opt{directory}
30 or report SuikaWiki::DB::Util::Error
31 -type => 'DB_METHOD_PARAMETER_REQUIRED',
32 -object => $self, method => 'new',
33 parameter => 'directory';
34 $self->{directory} .= '/' unless substr ($self->{directory}, -1, 1) eq '/';
35 $self->{prefix} = $opt{prefix} || 'mt--';
36 $self->{suffix} = $opt{suffix} || '.dat';
37 $self;
38 }
39
40 sub __encode_base16 ($$) {
41 my ($self, $s) = @_;
42 $s =~ s/(.)/sprintf '%02X', ord $1/ges;
43 $s;
44 }
45 sub __decode_base16 ($$) {
46 my ($self, $s) = @_;
47 $s =~ s/([0-9A-Fa-f]{2})/chr hex $1/ge;
48 $s;
49 }
50
51 sub ___open_prop ($$) {
52 my ($self, $opt) = @_;
53 local $Error::Depth = $Error::Depth + 1;
54 my $file = $self->{directory}
55 .$self->{prefix}
56 .$self->__encode_base16 ($opt->{prop})
57 .$self->{suffix};
58 unless (-e $file) {
59 $self->{db_hash}->{$opt->{prop}} = {};
60 } else {
61 CORE::open DB, '<', $file
62 or report SuikaWiki::DB::Util::Error
63 -type => 'STOP_DB_PROP_CANT_OPEN', file => $file,
64 msg => $!, prop => $opt->{prop},
65 -object => $self, method => '__read_meta';
66 binmode DB;
67 local $/ = undef;
68 my $val = <DB>;
69 CORE::close DB;
70
71 if ($val =~ s!^\#\?SuikaWikiMetaInfo/0.9[^\x02]*\x02!!s) {
72 $self->{db_hash}->{$opt->{prop}} = {map {split /\x1F/, $_, 2}
73 split /\x1E/, $val};
74 } elsif (length $val) {
75 report SuikaWiki::DB::Util::Error
76 -type => 'DB_UNSUPPORTED_FORMAT', file => $file,
77 method => '__read_meta', -object => $self,
78 prop => $opt->{prop};
79 } else { ## Blank file
80 $self->{db_hash}->{$opt->{prop}} = {};
81 }
82 }
83 $self->{prop_modified}->{$opt->{prop}} = 0;
84 }
85
86 sub ___close_prop ($$) {
87 my ($self, $opt) = @_;
88 local $Error::Depth = $Error::Depth + 1;
89 unless ($self->{prop_modified}->{$opt->{prop}}) {
90 report SuikaWiki::DB::Util::Error
91 -type => 'INFO_DB_PROP_NOT_MODIFIED',
92 -object => $self, method => '___close_prop',
93 prop => $opt->{prop};
94 return;
95 }
96 if ($self->{lock} and not $self->{lock}->locked) {
97 $self->{lock}->lock
98 or report SuikaWiki::DB::Util::Error
99 -type => 'LOCK_START', method => '__write_meta',
100 -object => $self, prop => $opt->{prop};
101 }
102 report SuikaWiki::DB::Util::Error
103 -type => 'DB_READ_ONLY', method => '___close_prop'
104 -object => $self,
105 if $self->{lock} and not $self->{lock}->writable;
106 my $file = $opt->{prop};
107 $file = $self->{directory}.$self->{prefix}.$self->__encode_base16 ($file)
108 .$self->{suffix};
109
110 my $temp = $file.'.'.time.'.tmp';
111 CORE::open FILE, '>', $temp
112 or report SuikaWiki::DB::Util::Error
113 -type => 'STOP_DB_PROP_CANT_SAVE', msg => $!,
114 method => '___close_prop', file => $file,
115 prop => $opt->{prop}, -object => $self;
116 binmode FILE;
117 print FILE "#?SuikaWikiMetaInfo/0.9\n\x02"
118 .join "\x1E",
119 map {
120 my ($n, $v) = ($_, $self->{db_hash}->{$opt->{prop}}->{$_});
121 for ($n, $v) {s/([\x02\x1C-\x1F])/sprintf '\\x%02X', ord $1/ge}
122 $n."\x1F".$v;
123 }
124 grep {length $self->{db_hash}->{$opt->{prop}}->{$_}}
125 keys %{$self->{db_hash}->{$opt->{prop}}};
126 CORE::close FILE;
127 if (-e $file) {
128 unlink $file or report SuikaWiki::DB::Util::Error
129 -type => 'STOP_DB_PROP_CANT_SAVE', file => $file,
130 method => '___close_prop (unlink)',
131 msg => $!, prop => $opt->{prop},
132 -object => $self;
133 }
134 rename $temp => $file
135 or report SuikaWiki::DB::Util::Error
136 -type => 'STOP_DB_PROP_CANT_SAVE', file => $file,
137 method => '___close_prop (rename)',
138 msg => $!, prop => $opt->{prop},
139 -object => $self;
140 $self->{prop_modified}->{$opt->{prop}} = 0;
141 report SuikaWiki::DB::Util::Error
142 -type => 'INFO_DB_PROP_WROTE',
143 -object => $self, method => '___close_prop',
144 file => $file, prop => $opt->{prop};
145 CORE::delete $self->{db_hash}->{$opt->{prop}};
146 }
147
148 sub __name2name ($$) {
149 my ($self, $key) = @_;
150 join $Sep, @$key;
151 }
152
153 sub __check_name ($$) {
154 my ($self, $key) = @_;
155 return 0 unless ref $key;
156 for (@$key) {
157 return 0 unless $_; # '' or 0 or undef
158 return 0 if index ($_, $Sep) > -1;
159 return 0 if $_ eq $Self || $_ eq $Parent;
160 }
161 return 1;
162 }
163
164 sub get ($$$) {
165 my ($self, $prop, $key) = @_;
166 unless ($self->{opened}->{$prop}) {
167 local $Error::Depth = $Error::Depth + 1;
168 $self->open_prop (prop => $prop);
169 }
170 $self->{db_hash}->{$prop}->{ $self->__name2name ($key) };
171 }
172
173 sub set ($$$$) {
174 my ($self, $prop, $key => $value) = @_;
175 report SuikaWiki::DB::Util::Error
176 -type => 'KEY_INVALID_NAME',
177 -object => $self, method => 'set',
178 prop => $prop, key => $key
179 unless $self->__check_name ($key);
180 unless ($self->{opened}->{$prop}) {
181 local $Error::Depth = $Error::Depth + 1;
182 $self->open_prop (prop => $prop);
183 }
184 $self->{prop_modified}->{$prop} = 1;
185 $self->{db_hash}->{$prop}->{ $self->__name2name ($key) } = $value;
186 }
187
188 sub exist ($$$) {
189 my ($self, $prop, $key) = @_;
190 return 0 unless $self->__check_name ($key);
191 unless ($self->{opened}->{$prop}) {
192 local $Error::Depth = $Error::Depth + 1;
193 $self->open_prop (prop => $prop);
194 }
195 CORE::exists $self->{db_hash}->{$prop}->{ $self->__name2name ($key) };
196 }
197
198 sub delete ($$$) {
199 my ($self, $prop, $key) = @_;
200 unless ($self->{opened}->{$prop}) {
201 local $Error::Depth = $Error::Depth + 1;
202 $self->open_prop (prop => $prop);
203 }
204 $self->{prop_modified}->{$prop} = 1;
205 CORE::delete $self->{db_hash}->{$prop}->{ $self->__name2name ($key) };
206 }
207
208 sub keys ($$;%) {
209 my ($self, $prop, %opt) = @_;
210 unless ($self->{opened}->{$prop}) {
211 local $Error::Depth = $Error::Depth + 1;
212 $self->open_prop (prop => $prop);
213 }
214 my $ns = $self->__name2name ($opt{-ns});
215 $ns .= $Sep if length $ns;
216 my $ns_l = length $ns;
217 my @result;
218 for (CORE::keys %{$self->{db_hash}->{$prop}}) {
219 ## Namespace matchs
220 if (substr ($_, 0, $ns_l) eq $ns) {
221 ## Child or grandchild in recursive mode
222 if ($opt{-recursive} || not (index ($_, $Sep) > $ns_l - 1)) {
223 push @result, $_;
224 }
225 }
226 }
227 return map {[split /\Q$Sep\E/, $_]} @result;
228 }
229
230 # close: Inherited
231
232 # DESTROY: Inherited
233
234 =head1 METHODS
235
236 This module provides common interface of SuikaWiki WikiDatabase
237 modules. See C<SuikaWiki::DB>.
238
239 =head1 AUTHOR
240
241 Wakaba <[email protected]>.
242
243 =head1 LICENSE
244
245 Copyright 2003-2004 Wakaba <[email protected]>. All rights reserved.
246
247 This program is free software; you can redistribute it and/or
248 modify it under the same terms as Perl itself.
249
250 =cut
251
252 1; # $Date: 2004/02/08 08:54:52 $

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24