/[suikacvs]/messaging/manakai/bin/mkdisdump.pl
Suika

Contents of /messaging/manakai/bin/mkdisdump.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.12 - (hide annotations) (download)
Fri Sep 30 13:06:13 2005 UTC (19 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.11: +242 -54 lines
File MIME type: text/plain
++ manakai/bin/ChangeLog	30 Sep 2005 12:38:36 -0000
2005-09-30  Wakaba  <wakaba@suika.fam.cx>

	* mkdisdump.pl (append_module_group_documentation,
	append_document_documentation): New functions.
	(append_class_documentation, append_interface_documentation):
	Generates method/attribute/constgroup information (in partial mode)
	even if "is_partial" option is true to compute inheriting
	class member information correctly.
	(--resource-uri): New option.

	* Makefile (error.xml, minimpl.xml): New rules.

++ manakai/lib/Message/Util/ChangeLog	30 Sep 2005 12:50:16 -0000
2005-09-30  Wakaba  <wakaba@suika.fam.cx>

	* DIS.dis (readProperties): Saves property name to values.
	(getPropertyModuleList): New method.


	* ManakaiNode.dis: Use "disPerl:H" instead
	of "disPerl:Q" for hash keys.
	(NodeStem): Property value "mn:treeID"
	has changed to scalar reference.
++ manakai/lib/Message/Util/Error/ChangeLog	30 Sep 2005 12:49:59 -0000
2005-09-30  Wakaba  <wakaba@suika.fam.cx>
	* DOMException.dis (dx:ManakaiErrorModules): New documentation.
++ manakai/lib/Message/Util/DIS/ChangeLog	30 Sep 2005 12:48:08 -0000
2005-09-30  Wakaba  <wakaba@suika.fam.cx>

	* Value.dis (name): New attribute.

	* Perl.dis (plFullyQualifiedName): Use module's package
	name properties if available.

++ manakai/lib/Message/DOM/ChangeLog	30 Sep 2005 12:40:49 -0000
2005-09-30  Wakaba  <wakaba@suika.fam.cx>

	* DOMCore.dis, SimpleLS.dis: Shares namespace URIs and local
	names where possible.

	* DOMFeature.dis: Documentation for DOM Minimum Implementation
	added (still work in progress).

	* Makefile (feature.dae, feature-spec.dae): New rules.

++ manakai/lib/manakai/ChangeLog	30 Sep 2005 12:53:24 -0000
2005-09-30  Wakaba  <wakaba@suika.fam.cx>

	* DISCore.dis: Documentation-related and meta-informational
	resoruces are moved to new "Document.dis" module.  The
	module now references "Document.dis".
	(DISCore:module, DISCore:resource): New properties.

	* DISRDF.dis: Some resources added from FOAF vocabulary.

	* Document.dis: New module.

	* DISIDL.dis: Some IDL comcepts added.  New name
	given to IDL datatypes.

	* DISLang.dis (dis:prefix): Removed.  (Moved to "DISIDL.dis"
	and it is now obsolete.)

2005-09-29  Wakaba  <wakaba@suika.fam.cx>

	* DISPerl.dis (DISPerl:HashStringRef, DISPerl:StringRef): New.

1 wakaba 1.1 #!/usr/bin/perl -w
2     use strict;
3    
4     =head1 NAME
5    
6 wakaba 1.5 mkdisdump.pl - Generating Perl Module Documentation Source
7 wakaba 1.1
8     =head1 SYNOPSIS
9    
10 wakaba 1.5 perl path/to/mkdisdump.pl input.cdis \
11 wakaba 1.1 {--module-name=ModuleName | --module-uri=module-uri} \
12     [--for=for-uri] [options] > ModuleName.pm
13     perl path/to/cdis2pm.pl --help
14    
15     =head1 DESCRIPTION
16    
17     The C<cdis2pm> script generates a Perl module from a compiled "dis"
18     ("cdis") file. It is intended to be used to generate a manakai
19     DOM Perl module files, although it might be useful for other purpose.
20    
21     This script is part of manakai.
22    
23     =cut
24    
25     use Message::Util::QName::Filter {
26 wakaba 1.3 ddel => q<http://suika.fam.cx/~wakaba/archive/2005/disdoc#>,
27 wakaba 1.1 ddoct => q<http://suika.fam.cx/~wakaba/archive/2005/8/disdump-xslt#>,
28     DIS => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/DIS#>,
29     dis => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#dis-->,
30     dis2pm => q<http://suika.fam.cx/~wakaba/archive/2004/11/8/dis2pm#>,
31     DISCore => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Core#>,
32     DISLang => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Lang#>,
33     DISPerl => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Perl#>,
34 wakaba 1.12 doc => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Document#>,
35 wakaba 1.1 DOMLS => q<http://suika.fam.cx/~wakaba/archive/2004/dom/ls#>,
36     dump => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/DIS#DISDump/>,
37 wakaba 1.8 dx => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/Error/DOMException#>,
38 wakaba 1.5 ecore => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/Error/Core/>,
39 wakaba 1.3 infoset => q<http://www.w3.org/2001/04/infoset#>,
40 wakaba 1.12 lang => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#>,
41 wakaba 1.1 ManakaiDOM => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/manakai-dom#>,
42     Markup => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Markup#>,
43     Util => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/>,
44     xml => q<http://www.w3.org/XML/1998/namespace>,
45 wakaba 1.3 xmlns => q<http://www.w3.org/2000/xmlns/>,
46 wakaba 1.1 };
47    
48     =head1 OPTIONS
49    
50     =over 4
51    
52     =item --for=I<for-uri> (Optional)
53    
54     Specifies the "For" URI reference for which the outputed module is.
55     If this parameter is ommitted, the default "For" URI reference
56     for the module, if any, or the C<ManakaiDOM:all> is assumed.
57    
58     =item --help
59    
60     Shows the help message.
61    
62     =item --module-uri=I<module-uri>
63    
64     A URI reference that identifies a module to output. Either
65     C<--module-name> or C<--module-uri> is required.
66    
67 wakaba 1.5 =item --verbose / --noverbose (default)
68 wakaba 1.1
69 wakaba 1.5 Whether a verbose message mode should be selected or not.
70 wakaba 1.1
71 wakaba 1.5 =item --with-implementators-note / --nowith-implementators-note (default)
72 wakaba 1.1
73 wakaba 1.5 Whether the implemetator's notes should also be included
74     in the result or not.
75 wakaba 1.1
76     =back
77    
78     =cut
79    
80     use Getopt::Long;
81     use Pod::Usage;
82     use Storable;
83     use Message::Util::Error;
84 wakaba 1.4 my %Opt = (
85     module_uri => {},
86 wakaba 1.12 resource_uri => {},
87 wakaba 1.4 );
88 wakaba 1.1 GetOptions (
89 wakaba 1.8 'debug' => \$Opt{debug},
90 wakaba 1.10 'dis-file-suffix=s' => \$Opt{dis_suffix},
91     'daem-file-suffix=s' => \$Opt{daem_suffix},
92 wakaba 1.1 'for=s' => \$Opt{For},
93     'help' => \$Opt{help},
94 wakaba 1.4 'module-uri=s' => sub {
95     shift;
96 wakaba 1.12 my ($nuri, $furi) = split /\s+/, shift, 2;
97     $furi ||= '';
98     $Opt{module_uri}->{$nuri}->{$furi} = 1;
99     },
100     'resource-uri=s' => sub {
101     shift;
102     my ($nuri, $furi) = split /\s+/, shift, 2;
103     $furi ||= '';
104     $Opt{resource_uri}->{$nuri}->{$furi} = 1;
105 wakaba 1.4 },
106 wakaba 1.10 'search-path|I=s' => sub {
107     shift;
108     my @value = split /\s+/, shift;
109     while (my ($ns, $path) = splice @value, 0, 2, ()) {
110     unless (defined $path) {
111     die qq[$0: Search-path parameter without path: "$ns"];
112     }
113     push @{$Opt{input_search_path}->{$ns} ||= []}, $path;
114     }
115     },
116     'search-path-catalog-file-name=s' => sub {
117     shift;
118     require File::Spec;
119     my $path = my $path_base = shift;
120     $path_base =~ s#[^/]+$##;
121     $Opt{search_path_base} = $path_base;
122     open my $file, '<', $path or die "$0: $path: $!";
123     while (<$file>) {
124     if (s/^\s*\@//) { ## Processing instruction
125     my ($target, $data) = split /\s+/;
126     if ($target eq 'base') {
127     $Opt{search_path_base} = File::Spec->rel2abs ($data, $path_base);
128     } else {
129     die "$0: $target: Unknown target";
130     }
131     } elsif (/^\s*\#/) { ## Comment
132     #
133     } elsif (/\S/) { ## Catalog entry
134     s/^\s+//;
135     my ($ns, $path) = split /\s+/;
136     push @{$Opt{input_search_path}->{$ns} ||= []},
137     File::Spec->rel2abs ($path, $Opt{search_path_base});
138     }
139     }
140     ## NOTE: File paths with SPACEs are not supported
141     ## NOTE: Future version might use file: URI instead of file path.
142     },
143 wakaba 1.5 'with-implementators-note' => \$Opt{with_impl_note},
144 wakaba 1.10 'verbose!' => \$Opt{verbose},
145 wakaba 1.1 ) or pod2usage (2);
146     pod2usage ({-exitval => 0, -verbose => 1}) if $Opt{help};
147     $Opt{file_name} = shift;
148     pod2usage ({-exitval => 2, -verbose => 0}) unless $Opt{file_name};
149 wakaba 1.12 pod2usage (2) unless (keys %{$Opt{module_uri}}) + (keys %{$Opt{resource_uri}});
150 wakaba 1.8 $Message::DOM::DOMFeature::DEBUG = 1 if $Opt{debug};
151 wakaba 1.10 $Opt{dis_suffix} = '.dis' unless defined $Opt{dis_suffix};
152     $Opt{daem_suffix} = '.daem' unless defined $Opt{daem_suffix};
153 wakaba 1.1
154     sub status_msg ($) {
155     my $s = shift;
156     $s .= "\n" unless $s =~ /\n$/;
157     print STDERR $s;
158     }
159    
160     sub status_msg_ ($) {
161     my $s = shift;
162     print STDERR $s;
163     }
164    
165     sub verbose_msg ($) {
166     my $s = shift;
167     $s .= "\n" unless $s =~ /\n$/;
168 wakaba 1.10 print STDERR $s if $Opt{verbose};
169 wakaba 1.1 }
170    
171     sub verbose_msg_ ($) {
172     my $s = shift;
173 wakaba 1.10 print STDERR $s if $Opt{verbose};
174 wakaba 1.1 }
175    
176 wakaba 1.7 {
177     my $ResourceCount = 0;
178 wakaba 1.8 sub progress_inc (;$) {
179     $ResourceCount += (shift || 1);
180     if (($ResourceCount % 10) == 0) {
181 wakaba 1.7 print STDERR "*";
182     print STDERR " " if ($ResourceCount % (10 * 10)) == 0;
183     print STDERR "\n" if ($ResourceCount % (10 * 50)) == 0;
184     }
185     }
186    
187     sub progress_reset () {
188     $ResourceCount = 0;
189     }
190     }
191    
192 wakaba 1.8 my $start_time;
193     BEGIN { $start_time = time }
194    
195     use Message::DOM::GenericLS;
196     use Message::DOM::SimpleLS;
197     use Message::Util::DIS::DISDump;
198 wakaba 1.12 use Message::Util::DIS::DISDoc;
199 wakaba 1.8 use Message::Util::DIS::DNLite;
200    
201 wakaba 1.5 my $impl = $Message::DOM::ImplementationRegistry->get_implementation
202 wakaba 1.1 ({
203     ExpandedURI q<ManakaiDOM:Minimum> => '3.0',
204     '+' . ExpandedURI q<DOMLS:LS> => '3.0',
205     '+' . ExpandedURI q<DIS:Doc> => '2.0',
206 wakaba 1.8 '+' . ExpandedURI q<DIS:DNLite> => '1.0',
207 wakaba 1.1 ExpandedURI q<DIS:Dump> => '1.0',
208     });
209    
210     ## -- Load input dac database file
211     status_msg_ qq<Opening dac file "$Opt{file_name}"...>;
212 wakaba 1.8 our $db = $impl->get_feature (ExpandedURI q<DIS:DNLite> => '1.0')
213 wakaba 1.10 ->pl_load_dis_database ($Opt{file_name}, sub ($$) {
214     my ($db, $mod) = @_;
215     my $ns = $mod->namespace_uri;
216     my $ln = $mod->local_name;
217     verbose_msg qq<Database module <$ns$ln> is requested>;
218     my $name = dac_search_file_path_stem ($ns, $ln, $Opt{daem_suffix});
219     if (defined $name) {
220     return $name.$Opt{daem_suffix};
221     } else {
222     return $ln.$Opt{daem_suffix};
223     }
224     });
225 wakaba 1.1 status_msg qq<done\n>;
226    
227 wakaba 1.2 our %ReferredResource;
228 wakaba 1.5 our %ClassMembers;
229     our %ClassInheritance;
230     our @ClassInheritance;
231     our %ClassImplements;
232 wakaba 1.2
233 wakaba 1.12 sub append_module_group_documentation (%) {
234     my %opt = @_;
235     my $section = $opt{result_parent}
236     ->append_child ($opt{result_parent}->owner_document
237     ->create_element_ns (ExpandedURI q<dump:>, 'moduleGroup'));
238    
239     add_uri ($opt{source_resource} => $section);
240    
241     my $path = $opt{source_resource}->get_property_text
242     (ExpandedURI q<dis:FileName>,
243     $opt{source_resource}->local_name);
244     $section->resource_file_path_stem ($path);
245    
246     $section->set_attribute_ns
247     (ExpandedURI q<ddoct:>, 'ddoct:basePath', '../' x ($path =~ tr#/#/#));
248    
249     append_description (source_resource => $opt{source_resource},
250     result_parent => $section,
251     has_label => 1);
252    
253     ## -- Member modules
254    
255     for my $rres (@{$opt{source_resource}->get_property_module_list
256     (ExpandedURI q<DISCore:module>)}) {
257     $Opt{module_uri}->{$rres->name_uri}->{$rres->for_uri} = 1;
258     my $mod_el = $section->append_child
259     ($section->owner_document
260     ->create_element_ns (ExpandedURI q<dump:>, 'module'));
261     $mod_el->ref ($rres->uri);
262     }
263    
264     ## -- Member resources
265    
266     for my $rres (@{$opt{source_resource}->get_property_resource_list
267     (ExpandedURI q<DISCore:resource>)}) {
268     progress_inc;
269     if ($rres->is_type_uri (ExpandedURI q<doc:Document>)) {
270     append_document_documentation (source_resource => $rres,
271     result_parent => $section);
272     } else {
273     #
274     }
275     }
276     status_msg "";
277     } # append_module_group_documentation
278    
279     sub append_document_documentation (%) {
280     my %opt = @_;
281     my $section = $opt{result_parent}
282     ->append_child ($opt{result_parent}->owner_document
283     ->create_element_ns (ExpandedURI q<dump:>, 'document'));
284     my $od = $section->owner_document;
285    
286     add_uri ($opt{source_resource} => $section);
287    
288     my $path = $opt{source_resource}->get_property_text
289     (ExpandedURI q<dis:FileName>,
290     lcfirst $opt{source_resource}->local_name);
291     $section->resource_file_path_stem ($path);
292    
293     $section->set_attribute_ns
294     (ExpandedURI q<ddoct:>, 'ddoct:basePath', '../' x ($path =~ tr#/#/#));
295    
296     $section->set_attribute_ns (ExpandedURI q<dump:>,
297     'dump:docType' => ExpandedURI q<doc:Document>)
298     if $opt{source_resource}->is_type_uri (ExpandedURI q<doc:Document>);
299    
300     ## TODO: Conneg
301     for my $con (@{$opt{source_resource}->get_property_value_list
302     (ExpandedURI q<doc:content>)}) {
303     my $cond = $con->get_feature (ExpandedURI q<DIS:Doc>, '2.0');
304     my $tree = $cond->get_disdoc_tree
305     ($od, ExpandedURI q<lang:disdoc>,
306     $opt{source_resource}->database,
307     default_name_uri => $opt{source_resource}->source_node_id,
308     default_for_uri => $opt{source_resource}->for_uri);
309     $section
310     ->append_child ($od->create_element_ns (ExpandedURI q<doc:>, 'content'))
311     ->append_child (transform_disdoc_tree ($tree));
312     }
313    
314     for my $con (@{$opt{source_resource}->get_property_value_list
315     (ExpandedURI q<dis:Label>)}) {
316     my $cond = $con->get_feature (ExpandedURI q<DIS:Doc>, '2.0');
317     my $tree = $cond->get_disdoc_tree
318     ($od, ExpandedURI q<lang:disdocInline>,
319     $opt{source_resource}->database,
320     default_name_uri => $opt{source_resource}->source_node_id,
321     default_for_uri => $opt{source_resource}->for_uri);
322     my $ns = $con->name;
323     my $ln = $1 if ($ns =~ s/(\w+)$//);
324     $section->append_child ($od->create_element_ns ($ns, $ln))
325     ->append_child (transform_disdoc_tree ($tree));
326     }
327    
328     for my $v (@{$opt{source_resource}->get_property_value_list
329     (ExpandedURI q<doc:part>)}) {
330     my $res = $v->get_resource ($opt{source_resource}->database);
331     $ReferredResource{$res->uri} ||= 1;
332     my $doc = $section->append_child
333     ($od->create_element_ns (ExpandedURI q<dump:>, 'document'));
334     $doc->ref ($res->uri);
335     $doc->set_attribute_ns (ExpandedURI q<dump:>, 'dump:docType' => $v->name);
336     }
337     } # append_document_documentation
338    
339 wakaba 1.1 sub append_module_documentation (%) {
340     my %opt = @_;
341     my $section = $opt{result_parent}->create_module ($opt{source_resource}->uri);
342 wakaba 1.2
343     add_uri ($opt{source_resource} => $section);
344 wakaba 1.1
345     my $pl_full_name = $opt{source_resource}->pl_fully_qualified_name;
346     if (defined $pl_full_name) {
347     $section->perl_package_name ($pl_full_name);
348 wakaba 1.5
349     my $path = $opt{source_resource}->get_property_text
350     (ExpandedURI q<dis:FileName>, $pl_full_name);
351 wakaba 1.1 $path =~ s#::#/#g;
352     $section->resource_file_path_stem ($path);
353 wakaba 1.5
354 wakaba 1.1 $section->set_attribute_ns
355     (ExpandedURI q<ddoct:>, 'ddoct:basePath', '../' x ($path =~ tr#/#/#));
356 wakaba 1.2 $pl_full_name =~ s/.*:://g;
357     $section->perl_name ($pl_full_name);
358 wakaba 1.1 }
359    
360     append_description (source_resource => $opt{source_resource},
361     result_parent => $section);
362    
363 wakaba 1.2 if ($opt{is_partial}) {
364     $section->resource_is_partial (1);
365     return;
366     }
367    
368 wakaba 1.11 for my $rres (@{$opt{source_resource}->get_resource_list}) {
369 wakaba 1.4 if ($rres->owner_module eq $opt{source_resource} and## Defined in this module
370     not ($ReferredResource{$rres->uri} < 0)) {
371 wakaba 1.1 ## TODO: Modification required to support modplans
372 wakaba 1.7 progress_inc;
373 wakaba 1.8 if ($rres->is_type_uri (ExpandedURI q<DISLang:Class>)) {
374 wakaba 1.1 append_class_documentation
375     (result_parent => $section,
376     source_resource => $rres);
377 wakaba 1.8 } elsif ($rres->is_type_uri (ExpandedURI q<DISLang:Interface>)) {
378 wakaba 1.1 append_interface_documentation
379     (result_parent => $section,
380     source_resource => $rres);
381 wakaba 1.12 } elsif ($rres->is_type_uri (ExpandedURI q<DISCore:AnyType>)) {
382 wakaba 1.3 append_datatype_documentation
383     (result_parent => $section,
384     source_resource => $rres);
385 wakaba 1.1 }
386     } else { ## Aliases
387     #
388     }
389     }
390 wakaba 1.2 status_msg "";
391 wakaba 1.1 } # append_module_documentation
392    
393 wakaba 1.3 sub append_datatype_documentation (%) {
394     my %opt = @_;
395     my $section = $opt{result_parent}->create_data_type
396     ($opt{source_resource}->uri);
397    
398     add_uri ($opt{source_resource} => $section);
399    
400 wakaba 1.4 my $uri = $opt{source_resource}->name_uri;
401     if ($uri) {
402     my $fu = $opt{source_resource}->for_uri;
403     unless ($fu eq ExpandedURI q<ManakaiDOM:all>) {
404     $fu =~ /([\w.-]+)[^\w.-]*$/;
405     $uri .= '-' . $1;
406     }
407     } else {
408     $opt{source_resource}->uri;
409     }
410     $uri =~ s#\b(\d\d\d\d+)/(\d\d?)/(\d\d?)#sprintf '%04d%02d%02d', $1, $2, $3#ge;
411     my @file = map {s/[^\w-]/_/g; $_} split m{[/:#?]+}, $uri;
412 wakaba 1.3
413     $section->resource_file_path_stem (join '/', @file);
414 wakaba 1.5 $section->set_attribute_ns
415     (ExpandedURI q<ddoct:>, 'ddoct:basePath', '../' x (@file - 1));
416 wakaba 1.3
417     append_description (source_resource => $opt{source_resource},
418 wakaba 1.12 result_parent => $section,
419     has_label => 1);
420 wakaba 1.3
421     if ($opt{is_partial}) {
422     $section->resource_is_partial (1);
423     return;
424     }
425    
426 wakaba 1.5 append_subclassof (source_resource => $opt{source_resource},
427     result_parent => $section);
428 wakaba 1.3 } # append_datatype_documentation
429    
430 wakaba 1.1 sub append_interface_documentation (%) {
431     my %opt = @_;
432     my $section = $opt{result_parent}->create_interface
433 wakaba 1.5 (my $class_uri = $opt{source_resource}->uri);
434     push @ClassInheritance, $class_uri;
435 wakaba 1.2
436     add_uri ($opt{source_resource} => $section);
437 wakaba 1.1
438     my $pl_full_name = $opt{source_resource}->pl_fully_qualified_name;
439     if (defined $pl_full_name) {
440     $section->perl_package_name ($pl_full_name);
441 wakaba 1.5
442     my $path = $opt{source_resource}->get_property_text
443     (ExpandedURI q<dis:FileName>, $pl_full_name);
444 wakaba 1.1 $path =~ s#::#/#g;
445     $section->resource_file_path_stem ($path);
446 wakaba 1.5
447 wakaba 1.1 $section->set_attribute_ns
448     (ExpandedURI q<ddoct:>, 'ddoct:basePath',
449     join '', '../' x ($path =~ tr#/#/#));
450 wakaba 1.2 $pl_full_name =~ s/.*:://g;
451     $section->perl_name ($pl_full_name);
452 wakaba 1.1 }
453    
454     $section->is_exception_interface (1)
455 wakaba 1.8 if $opt{source_resource}->is_type_uri (ExpandedURI q<dx:Interface>);
456 wakaba 1.1
457     append_description (source_resource => $opt{source_resource},
458     result_parent => $section);
459    
460 wakaba 1.2 if ($opt{is_partial}) {
461     $section->resource_is_partial (1);
462     }
463    
464 wakaba 1.11 for my $memres (@{$opt{source_resource}->get_child_resource_list}) {
465 wakaba 1.1 if ($memres->is_type_uri (ExpandedURI q<DISLang:Method>)) {
466     append_method_documentation (source_resource => $memres,
467 wakaba 1.5 result_parent => $section,
468 wakaba 1.12 class_uri => $class_uri,
469     is_partial => $opt{is_partial});
470 wakaba 1.1 } elsif ($memres->is_type_uri (ExpandedURI q<DISLang:Attribute>)) {
471     append_attr_documentation (source_resource => $memres,
472 wakaba 1.5 result_parent => $section,
473 wakaba 1.12 class_uri => $class_uri,
474     is_partial => $opt{is_partial});
475 wakaba 1.8 } elsif ($memres->is_type_uri (ExpandedURI q<DISLang:ConstGroup>)) {
476 wakaba 1.3 append_constgroup_documentation (source_resource => $memres,
477 wakaba 1.5 result_parent => $section,
478 wakaba 1.12 class_uri => $class_uri,
479     is_partial => $opt{is_partial});
480 wakaba 1.1 }
481     }
482 wakaba 1.12
483     return if $opt{is_partial};
484    
485     ## Inheritance
486     append_inheritance (source_resource => $opt{source_resource},
487     result_parent => $section,
488     class_uri => $class_uri);
489    
490 wakaba 1.1 } # append_interface_documentation
491    
492     sub append_class_documentation (%) {
493     my %opt = @_;
494 wakaba 1.5 my $section = $opt{result_parent}->create_class
495     (my $class_uri = $opt{source_resource}->uri);
496     push @ClassInheritance, $class_uri;
497 wakaba 1.2
498     add_uri ($opt{source_resource} => $section);
499 wakaba 1.1
500     my $pl_full_name = $opt{source_resource}->pl_fully_qualified_name;
501     if (defined $pl_full_name) {
502     $section->perl_package_name ($pl_full_name);
503 wakaba 1.5
504     my $path = $opt{source_resource}->get_property_text
505     (ExpandedURI q<dis:FileName>, $pl_full_name);
506 wakaba 1.1 $path =~ s#::#/#g;
507 wakaba 1.5
508 wakaba 1.1 $section->resource_file_path_stem ($path);
509     $section->set_attribute_ns
510     (ExpandedURI q<ddoct:>, 'ddoct:basePath', '../' x ($path =~ tr#/#/#));
511 wakaba 1.2 $pl_full_name =~ s/.*:://g;
512     $section->perl_name ($pl_full_name);
513 wakaba 1.1 }
514    
515     append_description (source_resource => $opt{source_resource},
516     result_parent => $section);
517    
518 wakaba 1.2 if ($opt{is_partial}) {
519     $section->resource_is_partial (1);
520     }
521    
522 wakaba 1.5 my $has_const = 0;
523 wakaba 1.11 for my $memres (@{$opt{source_resource}->get_child_resource_list}) {
524 wakaba 1.1 if ($memres->is_type_uri (ExpandedURI q<DISLang:Method>)) {
525     append_method_documentation (source_resource => $memres,
526 wakaba 1.5 result_parent => $section,
527 wakaba 1.12 class_uri => $class_uri,
528     is_partial => $opt{is_partial});
529 wakaba 1.1 } elsif ($memres->is_type_uri (ExpandedURI q<DISLang:Attribute>)) {
530     append_attr_documentation (source_resource => $memres,
531 wakaba 1.5 result_parent => $section,
532 wakaba 1.12 class_uri => $class_uri,
533     is_partial => $opt{is_partial});
534 wakaba 1.8 } elsif ($memres->is_type_uri (ExpandedURI q<DISLang:ConstGroup>)) {
535 wakaba 1.5 $has_const = 1;
536 wakaba 1.3 append_constgroup_documentation
537     (source_resource => $memres,
538 wakaba 1.5 result_parent => $section,
539 wakaba 1.12 class_uri => $class_uri,
540     is_partial => $opt{is_partial});
541 wakaba 1.1 }
542     }
543 wakaba 1.5
544 wakaba 1.12 return if $opt{is_partial};
545    
546 wakaba 1.5 ## Inheritance
547     append_inheritance (source_resource => $opt{source_resource},
548     result_parent => $section,
549     append_implements => 1,
550     class_uri => $class_uri,
551     has_const => $has_const,
552     is_class => 1);
553    
554 wakaba 1.1 } # append_class_documentation
555    
556     sub append_method_documentation (%) {
557     my %opt = @_;
558     my $perl_name = $opt{source_resource}->pl_name;
559     my $m;
560     if (defined $perl_name) {
561     $m = $opt{result_parent}->create_method ($perl_name);
562 wakaba 1.5 $ClassMembers{$opt{class_uri}}->{$perl_name}
563     = {
564     resource => $opt{source_resource},
565     type => 'method',
566     };
567 wakaba 1.1
568     } else { ## Anonymous
569     ## TODO
570     return;
571     }
572 wakaba 1.2
573     add_uri ($opt{source_resource} => $m);
574 wakaba 1.1
575     append_description (source_resource => $opt{source_resource},
576 wakaba 1.4 result_parent => $m,
577     method_resource => $opt{source_resource});
578 wakaba 1.1
579 wakaba 1.12 $m->resource_access ('private')
580     if $opt{source_resource}->get_property_boolean
581     (ExpandedURI q<ManakaiDOM:isForInternal>, 0);
582    
583     if ($opt{is_partial}) {
584     $m->resource_is_partial (1);
585     return;
586     }
587    
588 wakaba 1.1 my $ret = $opt{source_resource}->get_child_resource_by_type
589     (ExpandedURI q<DISLang:MethodReturn>);
590     if ($ret) {
591     my $r = $m->dis_return;
592    
593     try {
594 wakaba 1.2 $r->resource_data_type (my $u = $ret->dis_data_type_resource->uri);
595     $ReferredResource{$u} ||= 1;
596     $r->resource_actual_data_type
597     ($u = $ret->dis_actual_data_type_resource->uri);
598     $ReferredResource{$u} ||= 1;
599    
600 wakaba 1.1 ## TODO: Exceptions
601     } catch Message::Util::DIS::ManakaiDISException with {
602    
603     };
604 wakaba 1.4
605     append_description (source_resource => $ret,
606     result_parent => $r,
607     has_case => 1,
608     method_resource => $opt{source_resource});
609 wakaba 1.5
610     append_raises (source_resource => $ret,
611     result_parent => $r,
612     method_resource => $opt{source_resource});
613 wakaba 1.1 }
614    
615 wakaba 1.11 for my $cr (@{$opt{source_resource}->get_child_resource_list}) {
616 wakaba 1.1 if ($cr->is_type_uri (ExpandedURI q<DISLang:MethodParameter>)) {
617     append_param_documentation (source_resource => $cr,
618 wakaba 1.4 result_parent => $m,
619     method_resource => $opt{source_resource});
620 wakaba 1.1 }
621     }
622     } # append_method_documentation
623    
624     sub append_attr_documentation (%) {
625     my %opt = @_;
626     my $perl_name = $opt{source_resource}->pl_name;
627     my $m;
628     if (defined $perl_name) {
629     $m = $opt{result_parent}->create_attribute ($perl_name);
630 wakaba 1.5 $ClassMembers{$opt{class_uri}}->{$perl_name}
631     = {
632     resource => $opt{source_resource},
633     type => 'attr',
634     };
635 wakaba 1.1
636     } else { ## Anonymous
637     ## TODO
638     return;
639     }
640 wakaba 1.2
641     add_uri ($opt{source_resource} => $m);
642 wakaba 1.12
643     $m->resource_access ('private')
644     if $opt{source_resource}->get_property_boolean
645     (ExpandedURI q<ManakaiDOM:isForInternal>, 0);
646    
647     if ($opt{is_partial}) {
648     $m->resource_is_partial (1);
649     $m->is_read_only_attribute (1)
650     if $opt{source_resource}->get_child_resource_by_type
651     (ExpandedURI q<DISLang:AttributeSet>);
652     return;
653     }
654 wakaba 1.1
655     append_description (source_resource => $opt{source_resource},
656     result_parent => $m,
657     has_case => 1);
658    
659     my $ret = $opt{source_resource}->get_child_resource_by_type
660     (ExpandedURI q<DISLang:AttributeGet>);
661     if ($ret) {
662     my $r = $m->dis_get;
663    
664 wakaba 1.2 $r->resource_data_type (my $u = $ret->dis_data_type_resource->uri);
665     $ReferredResource{$u} ||= 1;
666     $r->resource_actual_data_type
667     ($u = $ret->dis_actual_data_type_resource->uri);
668     $ReferredResource{$u} ||= 1;
669    
670 wakaba 1.1 append_description (source_resource => $ret,
671     result_parent => $r,
672     has_case => 1);
673    
674 wakaba 1.5 append_raises (source_resource => $ret,
675     result_parent => $r);
676 wakaba 1.1 }
677    
678     my $set = $opt{source_resource}->get_child_resource_by_type
679     (ExpandedURI q<DISLang:AttributeSet>);
680     if ($set) {
681     my $r = $m->dis_set;
682    
683 wakaba 1.2 $r->resource_data_type (my $u = $set->dis_data_type_resource->uri);
684     $ReferredResource{$u} ||= 1;
685 wakaba 1.1 $r->resource_actual_data_type ($set->dis_actual_data_type_resource->uri);
686 wakaba 1.2 $ReferredResource{$u} ||= 1;
687 wakaba 1.1
688     append_description (source_resource => $set,
689     result_parent => $r,
690     has_case => 1);
691    
692 wakaba 1.5 append_raises (source_resource => $set,
693     result_parent => $r);
694 wakaba 1.1 } else {
695     $m->is_read_only_attribute (1);
696     }
697     } # append_attr_documentation
698    
699 wakaba 1.3 sub append_constgroup_documentation (%) {
700     my %opt = @_;
701     my $perl_name = $opt{source_resource}->pl_name;
702     my $m = $opt{result_parent}->create_const_group ($perl_name);
703 wakaba 1.5 $ClassMembers{$opt{class_uri}}->{$perl_name}
704     = {
705     resource => $opt{source_resource},
706     type => 'const-group',
707     };
708 wakaba 1.3
709     add_uri ($opt{source_resource} => $m);
710 wakaba 1.12
711     if ($opt{is_partial}) {
712     $m->resource_is_partial (1);
713     return;
714     }
715 wakaba 1.3
716     append_description (source_resource => $opt{source_resource},
717     result_parent => $m);
718    
719     $m->resource_data_type
720     (my $u = $opt{source_resource}->dis_data_type_resource->uri);
721     $ReferredResource{$u} ||= 1;
722     $m->resource_actual_data_type
723     ($u = $opt{source_resource}->dis_actual_data_type_resource->uri);
724     $ReferredResource{$u} ||= 1;
725    
726 wakaba 1.5 append_subclassof (source_resource => $opt{source_resource},
727     result_parent => $m);
728 wakaba 1.3
729 wakaba 1.11 for my $cr (@{$opt{source_resource}->get_child_resource_list}) {
730 wakaba 1.3 if ($cr->is_type_uri (ExpandedURI q<ManakaiDOM:Const>)) {
731     append_const_documentation (source_resource => $cr,
732     result_parent => $m);
733     }
734     }
735     } # append_constgroup_documentation
736    
737     sub append_const_documentation (%) {
738     my %opt = @_;
739     my $perl_name = $opt{source_resource}->pl_name;
740     my $m = $opt{result_parent}->create_const ($perl_name);
741    
742     add_uri ($opt{source_resource} => $m);
743    
744     append_description (source_resource => $opt{source_resource},
745     result_parent => $m);
746    
747     $m->resource_data_type
748     (my $u = $opt{source_resource}->dis_data_type_resource->uri);
749     $ReferredResource{$u} ||= 1;
750     $m->resource_actual_data_type
751     ($u = $opt{source_resource}->dis_actual_data_type_resource->uri);
752     $ReferredResource{$u} ||= 1;
753    
754     my $value = $opt{source_resource}->pl_code_fragment;
755     if ($value) {
756     $m->create_value->text_content ($value->stringify);
757     }
758    
759 wakaba 1.11 for my $cr (@{$opt{source_resource}->get_child_resource_list}) {
760 wakaba 1.3 if ($cr->is_type_uri (ExpandedURI q<ManakaiDOM:ExceptionOrWarningSubType>)) {
761     append_xsubtype_documentation (source_resource => $cr,
762     result_parent => $m);
763     }
764     }
765     ## TODO: xparam
766     } # append_const_documentation
767    
768     sub append_xsubtype_documentation (%) {
769     my %opt = @_;
770     my $m = $opt{result_parent}->create_exception_sub_code
771     ($opt{source_resource}->uri);
772     add_uri ($opt{source_resource} => $m);
773    
774     append_description (source_resource => $opt{source_resource},
775     result_parent => $m);
776    
777     ## TODO: xparam
778     } # append_xsubtype_documentation
779    
780 wakaba 1.1 sub append_param_documentation (%) {
781     my %opt = @_;
782    
783     my $is_named_param = $opt{source_resource}->get_property_boolean
784     (ExpandedURI q<DISPerl:isNamedParameter>, 0);
785    
786     my $perl_name = $is_named_param
787     ? $opt{source_resource}->pl_name
788     : $opt{source_resource}->pl_variable_name;
789    
790     my $p = $opt{result_parent}->create_parameter ($perl_name, $is_named_param);
791    
792 wakaba 1.2 add_uri ($opt{source_resource} => $p);
793    
794 wakaba 1.1 $p->is_nullable_parameter ($opt{source_resource}->pl_is_nullable);
795 wakaba 1.2 $p->resource_data_type
796     (my $u = $opt{source_resource}->dis_data_type_resource->uri);
797     $ReferredResource{$u} ||= 1;
798 wakaba 1.1 $p->resource_actual_data_type
799 wakaba 1.2 ($u = $opt{source_resource}->dis_actual_data_type_resource->uri);
800     $ReferredResource{$u} ||= 1;
801 wakaba 1.1
802     append_description (source_resource => $opt{source_resource},
803     result_parent => $p,
804 wakaba 1.4 has_case => 1,
805     method_resource => $opt{method_resource});
806 wakaba 1.1 } # append_param_documentation
807    
808     sub append_description (%) {
809     my %opt = @_;
810 wakaba 1.2
811 wakaba 1.1 my $od = $opt{result_parent}->owner_document;
812     my $resd = $opt{source_resource}->get_feature (ExpandedURI q<DIS:Doc>, '2.0');
813 wakaba 1.5 my $doc = transform_disdoc_tree
814     ($resd->get_description
815     ($od, undef,
816     $Opt{with_impl_note},
817 wakaba 1.8 parent_value_arg => $opt{source_value}),
818 wakaba 1.5 method_resource => $opt{method_resource});
819 wakaba 1.1 $opt{result_parent}->create_description->append_child ($doc);
820     ## TODO: Negotiation
821    
822 wakaba 1.3 my $fn = $resd->get_full_name ($od);
823     if ($fn) {
824     $opt{result_parent}->create_full_name
825 wakaba 1.4 ->append_child (transform_disdoc_tree
826     ($fn,
827     method_resource => $opt{method_resource}));
828 wakaba 1.3 }
829    
830 wakaba 1.12 if ($opt{has_label}) {
831     my $label = $resd->get_label ($od);
832     if ($label) {
833     if ($opt{result_parent}->can ('create_label')) {
834     $opt{result_parent}->create_label
835     ->append_child (transform_disdoc_tree ($label));
836     } else {
837     $opt{result_parent}->append_child
838     ($od->create_element_ns (ExpandedURI q<dump:>, 'label'))
839     ->append_child (transform_disdoc_tree ($label));;
840     }
841     }
842     }
843    
844 wakaba 1.1 if ($opt{has_case}) {
845 wakaba 1.11 for my $caser (@{$opt{source_resource}->get_child_resource_list}) {
846 wakaba 1.1 if ($caser->is_type_uri (ExpandedURI q<ManakaiDOM:InCase>)) {
847     my $case = $opt{result_parent}->append_case;
848     my $cased = $caser->get_feature (ExpandedURI q<DIS:Doc>, '2.0');
849     my $label = $cased->get_label ($od);
850     if ($label) {
851 wakaba 1.4 $case->create_label->append_child
852     (transform_disdoc_tree ($label,
853     method_resource => $opt{method_resource}));
854 wakaba 1.1 }
855     my $value = $caser->pl_code_fragment;
856     if ($value) {
857     $case->create_value->text_content ($value->stringify);
858     }
859 wakaba 1.3 $case->resource_data_type
860     (my $u = $caser->dis_data_type_resource->uri);
861     $ReferredResource{$u} ||= 1;
862     $case->resource_actual_data_type
863     ($u = $caser->dis_actual_data_type_resource->uri);
864     $ReferredResource{$u} ||= 1;
865    
866 wakaba 1.1 append_description (source_resource => $caser,
867 wakaba 1.4 result_parent => $case,
868     method_resource => $opt{method_resource});
869 wakaba 1.1 }
870     }
871     }
872     } # append_description
873    
874 wakaba 1.3 sub transform_disdoc_tree ($;%) {
875     my ($el, %opt) = @_;
876     my @el = ($el);
877     EL: while (defined (my $el = shift @el)) {
878     if ($el->node_type == $el->ELEMENT_NODE and
879     defined $el->namespace_uri) {
880     my $mmParsed = $el->get_attribute_ns (ExpandedURI q<ddel:>, 'mmParsed');
881     if ($mmParsed) {
882     my $lextype = $el->get_attribute_ns (ExpandedURI q<ddel:>, 'lexType');
883 wakaba 1.8 if ($lextype eq ExpandedURI q<DISCore:TFQNames>) {
884 wakaba 1.4 my $uri = dd_get_tfqnames_uri ($el);
885     if (defined $uri) {
886     $ReferredResource{$uri} ||= 1;
887     next EL;
888     }
889 wakaba 1.8 } elsif ($lextype eq ExpandedURI q<DISCore:QName> or
890 wakaba 1.5 $lextype eq ExpandedURI q<DISCore:NCNameOrQName>) {
891     my $uri = dd_get_qname_uri ($el);
892     if (defined $uri) {
893     $ReferredResource{$uri} ||= 1;
894     next EL;
895     }
896 wakaba 1.8 } elsif ($lextype eq ExpandedURI q<DISLang:MemberRef> or
897     $lextype eq ExpandedURI q<dx:XCRef>) {
898 wakaba 1.4 my @nm = @{$el->get_elements_by_tag_name_ns
899     (ExpandedURI q<ddel:>, 'name')};
900     if (@nm == 1) {
901 wakaba 1.5 my $uri = dd_get_tfqnames_uri ($nm[0]);
902     if (defined $uri) {
903     $el->set_attribute_ns (ExpandedURI q<dump:>, 'dump:uri', $uri);
904     $ReferredResource{$uri} ||= 1;
905     next EL;
906     }
907     } elsif (@nm == 3) {
908     my $uri = dd_get_tfqnames_uri ($nm[2]);
909 wakaba 1.4 if (defined $uri) {
910 wakaba 1.5 $el->set_attribute_ns (ExpandedURI q<dump:>, 'dump:uri', $uri);
911 wakaba 1.4 $ReferredResource{$uri} ||= 1;
912     next EL;
913     }
914     } elsif (@nm == 2) {
915     my $uri = dd_get_tfqnames_uri ($nm[0]);
916     if (not defined $uri) {
917     #
918     } elsif ($nm[1]->get_elements_by_tag_name_ns
919     (ExpandedURI q<ddel:>, 'prefix')->[0]) {
920     #my $luri = dd_get_qname_uri ($nm[1]);
921     ## QName: Currently not used
922     } else {
923     my $lnel = $nm[1]->get_elements_by_tag_name_ns
924     (ExpandedURI q<ddel:>, 'localName')->[0];
925     my $lname = $lnel ? $lnel->text_content : '';
926 wakaba 1.5 my $res;
927 wakaba 1.8 if ($lextype eq ExpandedURI q<dx:XCRef> or
928 wakaba 1.5 {
929     ExpandedURI q<ddel:C> => 1,
930     ExpandedURI q<ddel:X> => 1,
931     }->{$el->namespace_uri . $el->local_name}) {
932     ## NOTE: $db
933     $res = $db->get_resource ($uri)
934     ->get_const_resource_by_name ($lname);
935     } else {
936     ## NOTE: $db
937     $res = $db->get_resource ($uri)
938     ->get_child_resource_by_name_and_type
939 wakaba 1.4 ($lname, ExpandedURI q<DISLang:AnyMethod>);
940 wakaba 1.5 }
941 wakaba 1.4 if ($res) {
942     $el->set_attribute_ns
943     (ExpandedURI q<dump:>, 'dump:uri', $res->uri);
944     $ReferredResource{$res->uri} ||= 1;
945     }
946     next EL;
947     }
948     }
949     } # lextype
950     } # mmParsed
951     elsif ($opt{method_resource} and
952     $el->namespace_uri eq ExpandedURI q<ddel:> and
953     $el->local_name eq 'P') {
954     my $res = $opt{method_resource}
955     ->get_child_resource_by_name_and_type
956     ($el->text_content, ExpandedURI q<DISLang:MethodParameter>);
957     if ($res) {
958     $el->set_attribute_ns
959     (ExpandedURI q<dump:>, 'dump:uri', $res->uri);
960     $ReferredResource{$res->uri} ||= 1;
961 wakaba 1.3 }
962 wakaba 1.4 next EL;
963 wakaba 1.3 }
964 wakaba 1.4 push @el, @{$el->child_nodes};
965 wakaba 1.3 } elsif ($el->node_type == $el->DOCUMENT_FRAGMENT_NODE or
966     $el->node_type == $el->DOCUMENT_NODE) {
967 wakaba 1.4 push @el, @{$el->child_nodes};
968 wakaba 1.3 }
969     } # EL
970     $el;
971     } # transform_disdoc_tree
972    
973 wakaba 1.4 sub dd_get_tfqnames_uri ($;%) {
974     my ($el, %opt) = @_;
975     return '' unless $el;
976     my $turi = dd_get_qname_uri ($el->get_elements_by_tag_name_ns
977     (ExpandedURI q<ddel:>, 'nameQName')->[0]);
978     my $furi = dd_get_qname_uri ($el->get_elements_by_tag_name_ns
979     (ExpandedURI q<ddel:>, 'forQName')->[0]);
980     return undef if not defined $turi or not defined $furi;
981     my $uri = tfuris2uri ($turi, $furi);
982     $el->set_attribute_ns (ExpandedURI q<dump:>, 'dump:uri', $uri);
983     $uri;
984     } # dd_get_tfqnames_uri
985 wakaba 1.3
986     sub dd_get_qname_uri ($;%) {
987     my ($el, %opt) = @_;
988 wakaba 1.4 return undef unless $el;
989 wakaba 1.3 my $plel = $el->get_elements_by_tag_name_ns
990     (ExpandedURI q<ddel:>, 'prefix')->[0];
991     my $lnel = $el->get_elements_by_tag_name_ns
992     (ExpandedURI q<ddel:>, 'localName')->[0];
993     my $nsuri = ($plel ? $plel : $el)->lookup_namespace_uri
994     ($plel ? $plel->text_content : undef);
995     $nsuri = '' unless defined $nsuri;
996     if ($plel and $nsuri eq '') {
997     $plel->remove_attribute_ns
998 wakaba 1.4 (ExpandedURI q<xmlns:>, $plel->text_content);
999     $el->set_attribute_ns (ExpandedURI q<dump:>, 'dump:namespaceURI', $nsuri);
1000     return undef;
1001     } else {
1002     $el->set_attribute_ns (ExpandedURI q<dump:>, 'dump:namespaceURI', $nsuri);
1003 wakaba 1.3 }
1004     if ($lnel) {
1005     $nsuri . $lnel->text_content;
1006     } else {
1007     $el->get_attribute_ns (ExpandedURI q<ddel:>, 'defaultURI');
1008     }
1009     } # dd_get_qname_uri
1010    
1011     sub tfuris2uri ($$) {
1012     my ($turi, $furi) = @_;
1013     my $uri;
1014 wakaba 1.5 if ($furi eq ExpandedURI q<ManakaiDOM:all>) {
1015 wakaba 1.3 $uri = $turi;
1016     } else {
1017     my $__turi = $turi;
1018     my $__furi = $furi;
1019     for my $__uri ($__turi, $__furi) {
1020 wakaba 1.12 $__uri =~ s{([^0-9A-Za-z!\$'()*,:;=?\@_./~-])}{sprintf '%%%02X', ord $1}ge;
1021 wakaba 1.3 }
1022 wakaba 1.12 $uri = qq<tag:suika.fam.cx,2005-09:$__turi+$__furi>;
1023 wakaba 1.3 }
1024     $uri;
1025     } # tfuris2uri
1026    
1027 wakaba 1.1 sub append_inheritance (%) {
1028     my %opt = @_;
1029     if (($opt{depth} ||= 0) == 100) {
1030     warn "<".$opt{source_resource}->uri.">: Loop in inheritance";
1031     return;
1032     }
1033 wakaba 1.5
1034     my $has_isa = 0;
1035 wakaba 1.1
1036     for my $isa (@{$opt{source_resource}->get_property_resource_list
1037     (ExpandedURI q<dis:ISA>,
1038 wakaba 1.8 default_media_type => ExpandedURI q<DISCore:TFQNames>)}) {
1039 wakaba 1.5 $has_isa = 1;
1040 wakaba 1.1 append_inheritance
1041     (source_resource => $isa,
1042     result_parent => $opt{result_parent}->append_new_extends ($isa->uri),
1043 wakaba 1.5 depth => $opt{depth} + 1,
1044     is_class => $opt{is_class});
1045     $ReferredResource{$isa->uri} ||= 1;
1046     if ($opt{class_uri}) {
1047     unshift @ClassInheritance, $isa->uri;
1048     push @{$ClassInheritance{$opt{class_uri}} ||= []}, $isa->uri;
1049     }
1050     }
1051    
1052     if ($opt{source_resource}->is_defined) {
1053     for my $isa_pack (@{$opt{source_resource}->pl_additional_isa_packages}) {
1054     my $isa;
1055     if ($isa_pack eq 'Message::Util::Error') {
1056     ## NOTE: $db
1057     $isa = $db->get_resource (ExpandedURI q<ecore:MUError>,
1058     for_arg => ExpandedURI q<ManakaiDOM:Perl>);
1059     } elsif ($isa_pack eq 'Tie::Array') {
1060     ## NOTE: $db
1061     $isa = $db->get_resource (ExpandedURI q<DISPerl:TieArray>);
1062     } elsif ($isa_pack eq 'Error') {
1063     ## NOTE: $db
1064     $isa = $db->get_resource (ExpandedURI q<ecore:Error>,
1065     for_arg => ExpandedURI q<ManakaiDOM:Perl>);
1066     } else {
1067     ## TODO: What to do?
1068     }
1069     if ($isa) {
1070     $has_isa = 1;
1071     append_inheritance
1072     (source_resource => $isa,
1073     result_parent => $opt{result_parent}->append_new_extends ($isa->uri),
1074     depth => $opt{depth} + 1,
1075     is_class => $opt{is_class});
1076     $ReferredResource{$isa->uri} ||= 1;
1077     if ($opt{class_uri}) {
1078     unshift @ClassInheritance, $isa->uri;
1079     push @{$ClassInheritance{$opt{class_uri}} ||= []}, $isa->uri;
1080     }
1081     }
1082     }} # AppISA
1083    
1084     if ($opt{has_const}) {
1085     ## NOTE: $db
1086     my $isa = $db->get_resource (ExpandedURI q<DISPerl:Exporter>);
1087     append_inheritance
1088     (source_resource => $isa,
1089     result_parent => $opt{result_parent}->append_new_extends ($isa->uri),
1090     depth => $opt{depth} + 1,
1091     is_class => $opt{is_class});
1092     $ReferredResource{$isa->uri} ||= 1;
1093     if ($opt{class_uri}) {
1094     unshift @ClassInheritance, $isa->uri;
1095     push @{$ClassInheritance{$opt{class_uri}} ||= []}, $isa->uri;
1096     }
1097     }
1098    
1099     if (not $has_isa and $opt{is_class} and
1100     $opt{source_resource}->uri ne ExpandedURI q<DISPerl:UNIVERSAL>) {
1101     ## NOTE: $db
1102     my $isa = $db->get_resource (ExpandedURI q<DISPerl:UNIVERSAL>);
1103     append_inheritance
1104     (source_resource => $isa,
1105     result_parent => $opt{result_parent}->append_new_extends ($isa->uri),
1106     depth => $opt{depth} + 1,
1107     is_class => $opt{is_class});
1108 wakaba 1.2 $ReferredResource{$isa->uri} ||= 1;
1109 wakaba 1.5 if ($opt{class_uri}) {
1110     unshift @ClassInheritance, $isa->uri;
1111     push @{$ClassInheritance{$opt{class_uri}} ||= []}, $isa->uri;
1112     }
1113 wakaba 1.1 }
1114    
1115     if ($opt{append_implements}) {
1116 wakaba 1.5 ## NOTE: $db
1117     my $u = $db->get_resource (ExpandedURI q<DISPerl:UNIVERSALInterface>);
1118 wakaba 1.1 for my $impl (@{$opt{source_resource}->get_property_resource_list
1119     (ExpandedURI q<dis:Implement>,
1120 wakaba 1.8 default_media_type => ExpandedURI q<DISCore:TFQNames>,
1121 wakaba 1.5 isa_recursive => 1)}, $u) {
1122 wakaba 1.1 append_inheritance
1123     (source_resource => $impl,
1124     result_parent => $opt{result_parent}->append_new_implements
1125     ($impl->uri),
1126     depth => $opt{depth});
1127 wakaba 1.2 $ReferredResource{$impl->uri} ||= 1;
1128 wakaba 1.5 $ClassImplements{$opt{class_uri}}->{$impl->uri} = 1
1129     if $opt{class_uri};
1130 wakaba 1.1 }
1131     }
1132     } # append_inheritance
1133    
1134 wakaba 1.5 sub append_subclassof (%) {
1135     my %opt = @_;
1136    
1137     ## NOTE: This subroutine directly access to internal structure
1138     ## of ManakaiDISResourceDefinition
1139    
1140     my $a;
1141     $a = sub ($$) {
1142     my ($gdb, $s) = @_;
1143     my %s = keys %$s;
1144     while (my $i = [keys %s]->[0]) {
1145     ## Removes itself
1146     delete $s->{$i};
1147     #warn $i;
1148    
1149     my $ires = $gdb->get_resource ($i);
1150     for my $j (keys %$s) {
1151     next if $i eq $j;
1152     if ($ires->{subOf}->{$j}) {
1153     $s->{$i}->{$j} = $s->{$j};
1154     delete $s->{$j};
1155     delete $s{$j};
1156     }
1157     }
1158    
1159     delete $s{$i};
1160     } # %s
1161    
1162     for my $i (keys %$s) {
1163     $a->($s->{$i}) if keys %{$s->{$i}};
1164     }
1165     };
1166    
1167     my $b;
1168     $b = sub ($$) {
1169     my ($s, $p) = @_;
1170     for my $i (keys %$s) {
1171     my $el = $p->append_new_sub_class_of ($i);
1172     $b->($s->{$i}, $el) if keys %{$s->{$i}};
1173     }
1174     };
1175    
1176    
1177     my $sub = {$opt{source_resource}->uri =>
1178     {map {$_ => {}} keys %{$opt{source_resource}->{subOf}}}};
1179     ## NOTE: $db
1180     $a->($db, $sub);
1181     $b->($sub, $opt{result_parent});
1182     } # append_subclassof
1183    
1184 wakaba 1.2 sub add_uri ($$;%) {
1185     my ($res, $el, %opt) = @_;
1186     my $canon_uri = $res->uri;
1187     for my $uri (@{$res->uris}) {
1188     $el->add_uri ($uri, $canon_uri eq $uri ? 0 : 1);
1189     $ReferredResource{$uri} = -1;
1190     }
1191 wakaba 1.3
1192     my $nsuri = $res->namespace_uri;
1193     $el->resource_namespace_uri ($nsuri) if defined $nsuri;
1194     my $lname = $res->local_name;
1195     $el->resource_local_name ($lname) if defined $lname;
1196 wakaba 1.2 } # add_uri
1197    
1198 wakaba 1.5 sub append_raises (%) {
1199     my %opt = @_;
1200    
1201 wakaba 1.8 for my $el (@{$opt{source_resource}->get_property_value_list
1202     (ExpandedURI q<dx:raises>)}) {
1203     next unless $el->isa ('Message::Util::IF::DVURIValue');
1204     my $e = $el->get_resource ($db);
1205     my ($a, $b, $c); ## NOTE: $db
1206     if ($e->is_type_uri (ExpandedURI q<ManakaiDOM:ExceptionOrWarningSubType>)) {
1207     $c = $e;
1208 wakaba 1.10 $b = $c->parent_resource;
1209     $a = $b->parent_resource->parent_resource;
1210 wakaba 1.8 } elsif ($e->is_type_uri (ExpandedURI q<DISLang:Const>)) {
1211     $b = $e;
1212 wakaba 1.10 $a = $b->parent_resource->parent_resource;
1213 wakaba 1.8 } else {
1214     $a = $e;
1215     }
1216     my $rel = $opt{result_parent}->create_raises
1217 wakaba 1.5 ($a->uri, $b ? $b->uri : undef, $c ? $c->uri : undef);
1218    
1219 wakaba 1.8 append_description (source_resource => $opt{source_resource},
1220     source_value => $el,
1221     result_parent => $rel,
1222     method_resource => $opt{method_resource});
1223 wakaba 1.5 }
1224     } # append_raises
1225 wakaba 1.4
1226    
1227 wakaba 1.1 my $doc = $impl->create_disdump_document;
1228    
1229     my $body = $doc->document_element;
1230    
1231 wakaba 1.4 ## -- Outputs requested modules
1232    
1233 wakaba 1.12 for my $res_nuri (keys %{$Opt{resource_uri}}) {
1234     for my $res_furi (keys %{$Opt{resource_uri}->{$res_nuri}}) {
1235     $res_furi = ExpandedURI q<ManakaiDOM:all> unless length $res_furi;
1236     my $res = $db->get_resource ($res_nuri, for_arg => $res_furi);
1237     unless ($res->is_defined) {
1238     die qq{$0: Resource <$res_nuri> for <$res_furi> is not defined};
1239 wakaba 1.4 }
1240    
1241 wakaba 1.12 if ($res->is_type_uri (ExpandedURI q<doc:Documentation>)) {
1242     status_msg_ qq<Document <$res_nuri> for <$res_furi>...>;
1243    
1244     append_document_documentation
1245     (result_parent => $body,
1246     source_resource => $res);
1247 wakaba 1.4
1248 wakaba 1.12 status_msg qq<done>;
1249     } elsif ($res->is_type_uri (ExpandedURI q<dis:ModuleGroup>)) {
1250     status_msg qq<Module group <$res_nuri> for <$res_furi>...>;
1251    
1252     append_module_group_documentation
1253     (result_parent => $body,
1254     source_resource => $res);
1255    
1256     status_msg qq<done>;
1257     } else {
1258     die qq{$0: --resource-uri: Resource <$res_nuri> for <$res_furi>}.
1259     qq{ is not a resource set};
1260     }
1261     } # res_furi
1262     } # res_nuri
1263 wakaba 1.5
1264 wakaba 1.12 for my $mod_uri (keys %{$Opt{module_uri}}) {
1265     for my $mod_for (keys %{$Opt{module_uri}->{$mod_uri}}) {
1266     $mod_for = $Opt{For} unless length $mod_for;
1267     my $mod = $db->get_module ($mod_uri, for_arg => $mod_for);
1268     unless (defined $mod_for) {
1269     $mod_for = $mod->get_property_text (ExpandedURI q<dis:DefaultFor>);
1270     if (defined $mod_for) {
1271     $mod = $db->get_module ($mod_uri, for_arg => $mod_for);
1272     }
1273     }
1274     unless ($mod->is_defined) {
1275     die qq<$0: Module <$mod_uri> for <$mod_for> is not defined>;
1276     }
1277    
1278     status_msg qq<Module <$mod_uri> for <$mod_for>...>;
1279     progress_reset;
1280    
1281     append_module_documentation
1282     (result_parent => $body,
1283     source_resource => $mod);
1284    
1285     status_msg qq<done>;
1286     } # mod_for
1287 wakaba 1.4 } # mod_uri
1288    
1289     ## -- Outputs referenced resources in external modules
1290 wakaba 1.2
1291 wakaba 1.5 status_msg q<Other modules...>;
1292 wakaba 1.7 progress_reset;
1293 wakaba 1.5
1294 wakaba 1.10 my %debug_res_list;
1295 wakaba 1.2 while (my @ruri = grep {$ReferredResource{$_} > 0} keys %ReferredResource) {
1296     U: while (defined (my $uri = shift @ruri)) {
1297     next U if $ReferredResource{$uri} < 0; ## Already done
1298 wakaba 1.10 if ($Opt{debug}) {
1299     warn "Resource <$uri>: $debug_res_list{$uri} times\n"
1300     if ++$debug_res_list{$uri} > 10;
1301     }
1302 wakaba 1.7 progress_inc;
1303 wakaba 1.2 my $res = $db->get_resource ($uri);
1304     unless ($res->is_defined) {
1305     $res = $db->get_module ($uri);
1306     unless ($res->is_defined) {
1307     $ReferredResource{$uri} = -1;
1308     next U;
1309     }
1310     append_module_documentation
1311     (result_parent => $body,
1312     source_resource => $res,
1313     is_partial => 1);
1314 wakaba 1.8 } elsif ($res->is_type_uri (ExpandedURI q<DISLang:Class>)) {
1315 wakaba 1.2 my $mod = $res->owner_module;
1316     unless ($ReferredResource{$mod->uri} < 0) {
1317     unshift @ruri, $uri;
1318     unshift @ruri, $mod->uri;
1319     next U;
1320     }
1321     append_class_documentation
1322     (result_parent => $body->create_module ($mod->uri),
1323     source_resource => $res,
1324     is_partial => 1);
1325 wakaba 1.8 } elsif ($res->is_type_uri (ExpandedURI q<DISLang:Interface>)) {
1326 wakaba 1.2 my $mod = $res->owner_module;
1327     unless ($mod->is_defined) {
1328     $ReferredResource{$uri} = -1;
1329     next U;
1330     } elsif (not ($ReferredResource{$mod->uri} < 0)) {
1331     unshift @ruri, $uri;
1332     unshift @ruri, $mod->uri;
1333     next U;
1334     }
1335     append_interface_documentation
1336     (result_parent => $body->create_module ($mod->uri),
1337     source_resource => $res,
1338     is_partial => 1);
1339 wakaba 1.12 } elsif ($res->is_type_uri (ExpandedURI q<DISCore:AnyType>)) {
1340 wakaba 1.3 my $mod = $res->owner_module;
1341     unless ($mod->is_defined) {
1342     $ReferredResource{$uri} = -1;
1343     next U;
1344     } elsif (not ($ReferredResource{$mod->uri} < 0)) {
1345     unshift @ruri, $uri;
1346     unshift @ruri, $mod->uri;
1347     next U;
1348     }
1349     append_datatype_documentation
1350     (result_parent => $body->create_module ($mod->uri),
1351     source_resource => $res);
1352     } elsif ($res->is_type_uri (ExpandedURI q<DISLang:AnyMethod>) or
1353 wakaba 1.8 $res->is_type_uri (ExpandedURI q<DISLang:ConstGroup>)) {
1354 wakaba 1.10 my $cls = $res->parent_resource;
1355 wakaba 1.2 if (not ($ReferredResource{$cls->uri} < 0) and
1356 wakaba 1.8 ($cls->is_type_uri (ExpandedURI q<DISLang:Class>) or
1357     $cls->is_type_uri (ExpandedURI q<DISLang:Interface>))) {
1358 wakaba 1.2 unshift @ruri, $uri;
1359     unshift @ruri, $cls->uri;
1360     next U;
1361     }
1362     my $model = $body->create_module ($cls->owner_module->uri);
1363 wakaba 1.8 my $clsel = $cls->is_type_uri (ExpandedURI q<DISLang:Class>)
1364 wakaba 1.2 ? $model->create_class ($cls->uri)
1365     : $model->create_interface ($cls->uri);
1366     if ($res->is_type_uri (ExpandedURI q<DISLang:Method>)) {
1367     append_method_documentation
1368     (result_parent => $clsel,
1369     source_resource => $res);
1370 wakaba 1.3 } elsif ($res->is_type_uri (ExpandedURI q<DISLang:Attribute>)) {
1371 wakaba 1.2 append_attr_documentation
1372 wakaba 1.3 (result_parent => $clsel,
1373     source_resource => $res);
1374 wakaba 1.8 } elsif ($res->is_type_uri (ExpandedURI q<DISLang:ConstGroup>)) {
1375 wakaba 1.3 append_constgroup_documentation
1376     (result_parent => $clsel,
1377 wakaba 1.2 source_resource => $res);
1378 wakaba 1.8 } else {
1379     $ReferredResource{$res->uri} = -1;
1380 wakaba 1.2 }
1381     } elsif ($res->is_type_uri (ExpandedURI q<DISLang:MethodParameter>)) {
1382 wakaba 1.10 my $m = $res->parent_resource;
1383 wakaba 1.2 if (not ($ReferredResource{$m->uri} < 0) and
1384     $m->is_type_uri (ExpandedURI q<DISLang:Method>)) {
1385     unshift @ruri, $m->uri;
1386 wakaba 1.4 $ReferredResource{$res->uri} = -1;
1387 wakaba 1.2 next U;
1388 wakaba 1.10 } else {
1389     $ReferredResource{$res->uri} = -1;
1390     }
1391 wakaba 1.8 } elsif ($res->is_type_uri (ExpandedURI q<DISLang:Const>)) {
1392 wakaba 1.10 my $m = $res->parent_resource;
1393 wakaba 1.3 if (not ($ReferredResource{$m->uri} < 0) and
1394 wakaba 1.8 $m->is_type_uri (ExpandedURI q<DISLang:ConstGroup>)) {
1395 wakaba 1.3 unshift @ruri, $m->uri;
1396 wakaba 1.4 $ReferredResource{$res->uri} = -1;
1397 wakaba 1.3 next U;
1398 wakaba 1.8 } else {
1399     $ReferredResource{$res->uri} = -1;
1400     next U;
1401     }
1402 wakaba 1.3 } elsif ($res->is_type_uri
1403     (ExpandedURI q<ManakaiDOM:ExceptionOrWarningSubType>)) {
1404 wakaba 1.10 my $m = $res->parent_resource;
1405 wakaba 1.3 if (not ($ReferredResource{$m->uri} < 0) and
1406 wakaba 1.8 $m->is_type_uri (ExpandedURI q<DISLang:Const>)) {
1407 wakaba 1.3 unshift @ruri, $m->uri;
1408 wakaba 1.4 $ReferredResource{$res->uri} = -1;
1409 wakaba 1.3 next U;
1410 wakaba 1.8 } else {
1411     $ReferredResource{$res->uri} = -1;
1412     next U;
1413     }
1414 wakaba 1.12 } elsif ($res->is_type_uri (ExpandedURI q<doc:Documentation>)) {
1415     append_document_documentation (source_resource => $res,
1416     result_parent => $body);
1417 wakaba 1.2 } else { ## Unsupported type
1418     $ReferredResource{$uri} = -1;
1419     }
1420     } # U
1421     }
1422    
1423 wakaba 1.8 status_msg '';
1424 wakaba 1.5 status_msg q<done>;
1425    
1426     ## -- Inheriting methods information
1427 wakaba 1.1
1428 wakaba 1.5 {
1429     verbose_msg_ q<Adding inheritance information...>;
1430     my %class_done;
1431     for my $class_uri (@ClassInheritance) {
1432     next if $class_done{$class_uri};
1433     $class_done{$class_uri};
1434     for my $sclass_uri (@{$ClassInheritance{$class_uri}}) {
1435     for my $scm_name (keys %{$ClassMembers{$sclass_uri}}) {
1436     if ($ClassMembers{$class_uri}->{$scm_name}) {
1437     $ClassMembers{$class_uri}->{$scm_name}->{overrides}
1438     ->{$ClassMembers{$sclass_uri}->{$scm_name}->{resource}->uri} = 1;
1439     } else {
1440     $ClassMembers{$class_uri}->{$scm_name}
1441     = {
1442     %{$ClassMembers{$sclass_uri}->{$scm_name}},
1443     is_inherited => 1,
1444     };
1445     }
1446     }
1447     } # superclasses
1448     } # classes
1449 wakaba 1.1
1450 wakaba 1.8 verbose_msg_ q<...>;
1451    
1452 wakaba 1.5 for my $class_uri (keys %ClassImplements) {
1453     for my $if_uri (keys %{$ClassImplements{$class_uri}||{}}) {
1454     for my $mem_name (keys %{$ClassMembers{$if_uri}}) {
1455     unless ($ClassMembers{$class_uri}->{$mem_name}) {
1456     ## Not defined - error
1457     $ClassMembers{$class_uri}->{$mem_name}
1458     = {
1459     %{$ClassMembers{$if_uri}->{$mem_name}},
1460     is_inherited => 1,
1461     };
1462     }
1463     $ClassMembers{$class_uri}->{$mem_name}->{implements}
1464     ->{$ClassMembers{$if_uri}->{$mem_name}->{resource}->uri} = 1;
1465     }
1466     } # interfaces
1467     } # classes
1468    
1469 wakaba 1.8 verbose_msg_ q<...>;
1470    
1471 wakaba 1.5 for my $class_uri (keys %ClassMembers) {
1472     my $cls_res = $db->get_resource ($class_uri);
1473     next unless $cls_res->is_defined;
1474     verbose_msg_ q<.>;
1475     my $cls_el = $body->create_module ($cls_res->owner_module->uri);
1476 wakaba 1.8 if ($cls_res->is_type_uri (ExpandedURI q<DISLang:Interface>)) {
1477 wakaba 1.5 $cls_el = $cls_el->create_interface ($class_uri);
1478     } else {
1479     $cls_el = $cls_el->create_class ($class_uri);
1480     }
1481     for my $mem_name (keys %{$ClassMembers{$class_uri}}) {
1482     my $mem_info = $ClassMembers{$class_uri}->{$mem_name};
1483     my $el;
1484     if ($mem_info->{type} eq 'const-group') {
1485     $el = $cls_el->create_const_group ($mem_name);
1486     } elsif ($mem_info->{type} eq 'attr') {
1487     $el = $cls_el->create_attribute ($mem_name);
1488     } else {
1489     $el = $cls_el->create_method ($mem_name);
1490     }
1491     if ($mem_info->{is_inherited}) {
1492     $el->ref ($mem_info->{resource}->uri);
1493     }
1494     for my $or (keys %{$mem_info->{overrides}||{}}) {
1495     $el->append_new_overrides ($or);
1496     }
1497     for my $or (keys %{$mem_info->{implements}||{}}) {
1498     $el->append_new_implements ($or);
1499     }
1500     } # members
1501     } # classes
1502    
1503     verbose_msg q<done>;
1504     undef %ClassMembers;
1505     }
1506    
1507     {
1508     status_msg_ qq<Writing file ""...>;
1509    
1510     require Encode;
1511     my $lsimpl = $impl->get_feature (ExpandedURI q<DOMLS:LS> => '3.0');
1512     my $serializer = $lsimpl->create_mls_serializer
1513 wakaba 1.1 ({ExpandedURI q<DOMLS:SerializeDocumentInstance> => ''});
1514 wakaba 1.10 print STDOUT Encode::encode ('utf8', $serializer->write_to_string ($doc));
1515 wakaba 1.5 close STDOUT;
1516     status_msg qq<done>;
1517 wakaba 1.9 $doc->free;
1518 wakaba 1.5 }
1519 wakaba 1.1
1520     verbose_msg_ qq<Checking undefined resources...>;
1521     $db->check_undefined_resource;
1522     verbose_msg qq<done>;
1523    
1524     verbose_msg_ qq<Closing database...>;
1525 wakaba 1.5 $db->free;
1526 wakaba 1.1 undef $db;
1527     verbose_msg qq<done>;
1528    
1529 wakaba 1.8 {
1530     use integer;
1531     my $time = time - $start_time;
1532     status_msg sprintf qq<%d'%02d''>, $time / 60, $time % 60;
1533     }
1534    
1535 wakaba 1.10 exit;
1536    
1537 wakaba 1.5 END {
1538     $db->free if $db;
1539     }
1540    
1541 wakaba 1.10 sub dac_search_file_path_stem ($$$) {
1542     my ($ns, $ln, $suffix) = @_;
1543     require Cwd;
1544     require File::Spec;
1545     for my $dir ('.', @{$Opt{input_search_path}->{$ns}||[]}) {
1546     my $name = Cwd::abs_path
1547     (File::Spec->canonpath
1548     (File::Spec->catfile ($dir, $ln)));
1549     if (-f $name.$suffix) {
1550     return $name;
1551     }
1552     }
1553     return undef;
1554     } # dac_search_file_path_stem;
1555    
1556 wakaba 1.1 =head1 SEE ALSO
1557    
1558     L<lib/manakai/dis.pl> and L<bin/cdis2pm.pl> - Old version of
1559     this script.
1560    
1561 wakaba 1.5 L<lib/Message/Util/DIS.dis> - The I<dis> object implementation.
1562 wakaba 1.1
1563     L<lib/Message/Util/PerlCode.dis> - The Perl code generator.
1564    
1565     L<lib/manakai/DISCore.dis> - The definition for the "dis" format.
1566    
1567     L<lib/manakai/DISPerl.dis> - The definition for the "dis" Perl-specific
1568     vocabulary.
1569    
1570     =head1 LICENSE
1571    
1572     Copyright 2004-2005 Wakaba <w@suika.fam.cx>. All rights reserved.
1573    
1574     This program is free software; you can redistribute it and/or
1575     modify it under the same terms as Perl itself.
1576    
1577     =cut
1578    
1579 wakaba 1.12 1; # $Date: 2005/09/26 14:37:34 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24