| 1 | #!/usr/bin/perl -w | 
| 2 | use strict; | 
| 3 | use Message::Util::QName::Filter { | 
| 4 | c => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/dom-core#>, | 
| 5 | DIS => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/DIS#>, | 
| 6 | dis => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/lang#dis-->, | 
| 7 | dp => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/DIS#Perl/>, | 
| 8 | fe => q<http://suika.fam.cx/www/2006/feature/>, | 
| 9 | ManakaiDOM => q<http://suika.fam.cx/~wakaba/archive/2004/8/18/manakai-dom#>, | 
| 10 | pc => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/PerlCode#>, | 
| 11 | swcfg21 => q<http://suika.fam.cx/~wakaba/archive/2005/swcfg21#>, | 
| 12 | Util => q<http://suika.fam.cx/~wakaba/archive/2005/manakai/Util/>, | 
| 13 | }; | 
| 14 |  | 
| 15 | use Cwd; | 
| 16 | use Getopt::Long; | 
| 17 | use Pod::Usage; | 
| 18 | my %Opt = (create_module => []); | 
| 19 | my @target_modules; | 
| 20 | GetOptions ( | 
| 21 | 'create-dtd-modules=s' => sub { | 
| 22 | shift; | 
| 23 | my $i = [split /\s+/, shift, 3]; | 
| 24 | $i->[3] = 'dtd-modules'; | 
| 25 | push @{$Opt{create_module}}, $i; | 
| 26 | }, | 
| 27 | 'create-perl-module=s' => sub { | 
| 28 | shift; | 
| 29 | my $i = [split /\s+/, shift, 3]; | 
| 30 | $i->[3] = 'perl-pm'; | 
| 31 | push @{$Opt{create_module}}, $i; | 
| 32 | push @target_modules, [$i->[0], $i->[2]]; | 
| 33 | }, | 
| 34 | 'create-perl-test=s' => sub { | 
| 35 | shift; | 
| 36 | my $i = [split /\s+/, shift, 3]; | 
| 37 | $i->[3] = 'perl-t'; | 
| 38 | push @{$Opt{create_module}}, $i; | 
| 39 | push @target_modules, [$i->[0], $i->[2]]; | 
| 40 | }, | 
| 41 | 'debug' => \$Opt{debug}, | 
| 42 | 'dis-file-suffix=s' => \$Opt{dis_suffix}, | 
| 43 | 'daem-file-suffix=s' => \$Opt{daem_suffix}, | 
| 44 | 'dafs-file-suffix=s' => \$Opt{dafs_suffix}, | 
| 45 | 'dafx-file-suffix=s' => \$Opt{dafx_suffix}, | 
| 46 | 'help' => \$Opt{help}, | 
| 47 | 'load-module=s' => sub { | 
| 48 | shift; | 
| 49 | my $i = [split /\s+/, shift, 2]; | 
| 50 | push @target_modules, [$i->[0], $i->[1]]; | 
| 51 | }, | 
| 52 | 'search-path|I=s' => sub { | 
| 53 | shift; | 
| 54 | my @value = split /\s+/, shift; | 
| 55 | while (my ($ns, $path) = splice @value, 0, 2, ()) { | 
| 56 | unless (defined $path) { | 
| 57 | die qq[$0: Search-path parameter without path: "$ns"]; | 
| 58 | } | 
| 59 | push @{$Opt{input_search_path}->{$ns} ||= []}, $path; | 
| 60 | } | 
| 61 | }, | 
| 62 | 'search-path-catalog-file-name=s' => sub { | 
| 63 | shift; | 
| 64 | require File::Spec; | 
| 65 | my $path = my $path_base = shift; | 
| 66 | $path_base =~ s#[^/]+$##; | 
| 67 | $Opt{search_path_base} = $path_base; | 
| 68 | open my $file, '<', $path or die "$0: $path: $!"; | 
| 69 | while (<$file>) { | 
| 70 | if (s/^\s*\@//) {     ## Processing instruction | 
| 71 | my ($target, $data) = split /\s+/; | 
| 72 | if ($target eq 'base') { | 
| 73 | $Opt{search_path_base} = File::Spec->rel2abs ($data, $path_base); | 
| 74 | } else { | 
| 75 | die "$0: $target: Unknown target"; | 
| 76 | } | 
| 77 | } elsif (/^\s*\#/) {  ## Comment | 
| 78 | # | 
| 79 | } elsif (/\S/) {      ## Catalog entry | 
| 80 | s/^\s+//; | 
| 81 | my ($ns, $path) = split /\s+/; | 
| 82 | push @{$Opt{input_search_path}->{$ns} ||= []}, | 
| 83 | File::Spec->rel2abs ($path, $Opt{search_path_base}); | 
| 84 | } | 
| 85 | } | 
| 86 | ## NOTE: File paths with SPACEs are not supported | 
| 87 | ## NOTE: Future version might use file: URI instead of file path. | 
| 88 | }, | 
| 89 | 'undef-check!' => \$Opt{no_undef_check}, | 
| 90 | 'verbose!' => \$Opt{verbose}, | 
| 91 | ) or pod2usage (2); | 
| 92 | pod2usage ({-exitval => 0, -verbose => 1}) if $Opt{help}; | 
| 93 | $Opt{no_undef_check} = defined $Opt{no_undef_check} | 
| 94 | ? $Opt{no_undef_check} ? 0 : 1 : 0; | 
| 95 | $Opt{dis_suffix} = '.dis' unless defined $Opt{dis_suffix}; | 
| 96 | $Opt{daem_suffix} = '.dafm' unless defined $Opt{daem_suffix}; | 
| 97 | $Opt{dafx_suffix} = '.dafx' unless defined $Opt{dafx_suffix}; | 
| 98 | $Opt{dafs_suffix} = '.dafs' unless defined $Opt{dafs_suffix}; | 
| 99 | $Message::DOM::DOMFeature::DEBUG = 1 if $Opt{debug}; | 
| 100 | require Error; | 
| 101 | $Error::Debug = 1 if $Opt{debug}; | 
| 102 | $Message::Util::Error::VERBOSE = 1 if $Opt{verbose}; | 
| 103 |  | 
| 104 | sub status_msg ($) { | 
| 105 | my $s = shift; | 
| 106 | $s .= "\n" unless $s =~ /\n$/; | 
| 107 | print STDERR $s; | 
| 108 | } | 
| 109 |  | 
| 110 | sub status_msg_ ($) { | 
| 111 | my $s = shift; | 
| 112 | print STDERR $s; | 
| 113 | } | 
| 114 |  | 
| 115 | sub verbose_msg ($) { | 
| 116 | my $s = shift; | 
| 117 | $s .= "\n" unless $s =~ /\n$/; | 
| 118 | print STDERR $s if $Opt{verbose}; | 
| 119 | } | 
| 120 |  | 
| 121 | sub verbose_msg_ ($) { | 
| 122 | my $s = shift; | 
| 123 | print STDERR $s if $Opt{verbose}; | 
| 124 | } | 
| 125 |  | 
| 126 | ## ---- The MAIN Program | 
| 127 |  | 
| 128 | my $start_time; | 
| 129 | BEGIN { $start_time = time } | 
| 130 |  | 
| 131 | use Message::Util::DIS::DNLite; | 
| 132 |  | 
| 133 | my %feature; | 
| 134 |  | 
| 135 | for (@{$Opt{create_module}}) { | 
| 136 | my (undef, undef, undef, $out_type) = @$_; | 
| 137 |  | 
| 138 | if ($out_type eq 'perl-pm') { | 
| 139 | require 'manakai/daf-perl-pm.pl'; | 
| 140 | $feature{'+' . ExpandedURI q<Util:PerlCode>} = '1.0'; | 
| 141 | } elsif ($out_type eq 'perl-t') { | 
| 142 | require 'manakai/daf-perl-t.pl'; | 
| 143 | $feature{ExpandedURI q<fe:GenericLS>} = '3.0'; | 
| 144 | $feature{'+' . ExpandedURI q<DIS:TDT>} = '1.0'; | 
| 145 | $feature{'+' . ExpandedURI q<Util:PerlCode>} = '1.0'; | 
| 146 | } elsif ($out_type eq 'dtd-modules') { | 
| 147 | require 'manakai/daf-dtd-modules.pl'; | 
| 148 | $feature{ExpandedURI q<fe:GenericLS>} = '3.0'; | 
| 149 | $feature{'+' . ExpandedURI q<fe:XDP>} = '3.0'; | 
| 150 | } | 
| 151 | } | 
| 152 |  | 
| 153 | our $limpl = $Message::DOM::ImplementationRegistry->get_implementation | 
| 154 | ({ExpandedURI q<fe:Min> => '3.0', | 
| 155 | '+' . ExpandedURI q<DIS:DNLite> => '1.0', | 
| 156 | '+' . ExpandedURI q<DIS:Core> => '1.0', | 
| 157 | %feature, | 
| 158 | }); | 
| 159 | our $impl = $limpl->get_feature (ExpandedURI q<DIS:Core> => '1.0'); | 
| 160 |  | 
| 161 | ## --- Loading and Updating the Database | 
| 162 |  | 
| 163 | my $HasError; | 
| 164 | our $db = $impl->create_dis_database; | 
| 165 | $db->pl_database_module_resolver (\&daf_db_module_resolver); | 
| 166 | $db->dom_config->set_parameter ('error-handler' => \&daf_on_error); | 
| 167 |  | 
| 168 | my $parser = $impl->create_dis_parser; | 
| 169 | my $DNi = $impl->get_feature (ExpandedURI q<DIS:DNLite> => '1.0'); | 
| 170 | my %ModuleSourceDISDocument; | 
| 171 | my %ModuleSourceDNLDocument; | 
| 172 | my %ModuleNameNamespaceBinding = ( | 
| 173 | DISCore => q<http://suika.fam.cx/~wakaba/archive/2004/dis/Core#>, | 
| 174 | ## This builtin binding is required since | 
| 175 | ## some module has |DISCore:author| property before |dis:Require| | 
| 176 | ## property. | 
| 177 | ); | 
| 178 |  | 
| 179 | my $ResourceCount = 0; | 
| 180 | $db->pl_update_module (\@target_modules, | 
| 181 | get_module_index_file_name => sub { | 
| 182 | shift; # $db | 
| 183 | daf_get_module_index_file_name (@_); | 
| 184 | }, | 
| 185 | get_module_source_document_from_uri => sub { | 
| 186 | my ($db, $module_uri, $module_for) = @_; | 
| 187 | status_msg ''; | 
| 188 | status_msg qq<Loading module <$module_uri> for <$module_for>...>; | 
| 189 | $ResourceCount = 0; | 
| 190 |  | 
| 191 | unless (defined $ModuleSourceDNLDocument{$module_uri}) { | 
| 192 | unless (defined $ModuleSourceDISDocument{$module_uri}) { | 
| 193 | daf_open_source_dis_document ($module_uri); | 
| 194 | } | 
| 195 | daf_convert_dis_document_to_dnl_document (); | 
| 196 | } | 
| 197 | return $ModuleSourceDNLDocument{$module_uri}; | 
| 198 | }, | 
| 199 | get_module_source_document_from_resource => sub ($$$$$$) { | 
| 200 | my ($self, $db, $uri, $ns, $ln, $for) = @_; | 
| 201 | status_msg ''; | 
| 202 | status_msg qq<Loading module "$ln" for <$for>...>; | 
| 203 | $ResourceCount = 0; | 
| 204 |  | 
| 205 | my $module_uri = $ns.$ln; | 
| 206 | unless (defined $ModuleSourceDNLDocument{$module_uri}) { | 
| 207 | unless (defined $ModuleSourceDISDocument{$module_uri}) { | 
| 208 | daf_open_source_dis_document ($module_uri); | 
| 209 | } | 
| 210 | daf_convert_dis_document_to_dnl_document (); | 
| 211 | } | 
| 212 | return $ModuleSourceDNLDocument{$module_uri}; | 
| 213 | }, | 
| 214 | get_module_source_revision => sub { | 
| 215 | my ($db, $module_uri) = @_; | 
| 216 | my $ns = $module_uri; | 
| 217 | $ns =~ s/(\w+)\z//; | 
| 218 | my $ln = $1; | 
| 219 |  | 
| 220 | my $name = dac_search_file_path_stem ($ns, $ln, $Opt{dis_suffix}); | 
| 221 | if (defined $name) { | 
| 222 | return [stat $name.$Opt{dis_suffix}]->[9]; | 
| 223 | } else { | 
| 224 | return 0; | 
| 225 | } | 
| 226 | }, | 
| 227 | get_referring_module_uri_list => sub { | 
| 228 | my ($db, $module_uri) = @_; | 
| 229 | unless (defined $ModuleSourceDNLDocument{$module_uri}) { | 
| 230 | unless (defined $ModuleSourceDISDocument{$module_uri}) { | 
| 231 | daf_open_source_dis_document ($module_uri); | 
| 232 | } | 
| 233 | } | 
| 234 | return daf_get_referring_module_uri_list ($module_uri); | 
| 235 | }, | 
| 236 | on_resource_read => sub ($$) { | 
| 237 | if ((++$ResourceCount % 10) == 0) { | 
| 238 | status_msg_ "*"; | 
| 239 | status_msg_ " " if ($ResourceCount % (10 * 10)) == 0; | 
| 240 | status_msg '' if ($ResourceCount % (10 * 50)) == 0; | 
| 241 | } | 
| 242 | }); | 
| 243 |  | 
| 244 |  | 
| 245 | ## Removes reference from document to database | 
| 246 | our @Document; | 
| 247 | for my $dis (@Document) { | 
| 248 | $dis->unlink_from_document; | 
| 249 | $dis->dis_database (undef); | 
| 250 | } | 
| 251 |  | 
| 252 | status_msg ''; | 
| 253 |  | 
| 254 | status_msg qq<Reading properties...>; | 
| 255 | $ResourceCount = 0; | 
| 256 | $db->read_properties (on_resource_read => sub ($$) { | 
| 257 | if ((++$ResourceCount % 10) == 0) { | 
| 258 | status_msg_ "*"; | 
| 259 | status_msg_ " " if ($ResourceCount % (10 * 10)) == 0; | 
| 260 | status_msg '' if ($ResourceCount % (10 * 50)) == 0; | 
| 261 | } | 
| 262 | }); | 
| 263 | status_msg ''; | 
| 264 | status_msg "done"; | 
| 265 |  | 
| 266 | status_msg_ qq<Writing database files...>; | 
| 267 | $db->pl_store ('dummy', sub ($$) { | 
| 268 | my ($db, $mod, $type) = @_; | 
| 269 | my $ns = $mod->namespace_uri; | 
| 270 | my $ln = $mod->local_name; | 
| 271 | my $suffix = $type eq ExpandedURI q<dp:ModuleIndexFile> | 
| 272 | ? $Opt{dafx_suffix} : $Opt{daem_suffix}; | 
| 273 | my $name = dac_search_file_path_stem ($ns, $ln, $suffix); | 
| 274 | if (defined $name) { | 
| 275 | $name .= $suffix; | 
| 276 | } elsif (defined ($name = dac_search_file_path_stem | 
| 277 | ($ns, $ln, $Opt{dis_suffix}))) { | 
| 278 | $name .= $suffix; | 
| 279 | } else { | 
| 280 | $name = Cwd::abs_path | 
| 281 | (File::Spec->canonpath | 
| 282 | (File::Spec->catfile | 
| 283 | (defined $Opt{input_search_path}->{$ns}->[0] | 
| 284 | ? $Opt{input_search_path}->{$ns}->[0] : '.', | 
| 285 | $ln.$suffix))); | 
| 286 | } | 
| 287 | verbose_msg qq<Database >. | 
| 288 | ($type eq <Q::dp|ModuleIndexFile> ? 'index' : 'module'). | 
| 289 | qq< <$ns$ln> is written to "$name">; | 
| 290 | return $name; | 
| 291 | }, no_main_database => 1); | 
| 292 | status_msg "done"; | 
| 293 |  | 
| 294 | daf_check_undefined (); | 
| 295 |  | 
| 296 | undef $DNi; | 
| 297 | undef %ModuleSourceDNLDocument; | 
| 298 | exit $HasError if $HasError; | 
| 299 |  | 
| 300 | ## --- Creating Files | 
| 301 |  | 
| 302 | for (@{$Opt{create_module}}) { | 
| 303 | my ($mod_uri, $out_file_path, $mod_for, $out_type) = @$_; | 
| 304 |  | 
| 305 | if ($out_type eq 'perl-pm') { | 
| 306 | daf_perl_pm ($mod_uri, $out_file_path, $mod_for); | 
| 307 | } elsif ($out_type eq 'perl-t') { | 
| 308 | daf_perl_t ($mod_uri, $out_file_path, $mod_for); | 
| 309 | } elsif ($out_type eq 'dtd-modules') { | 
| 310 | daf_dtd_modules ($mod_uri, $out_file_path, $mod_for); | 
| 311 | } | 
| 312 | } | 
| 313 |  | 
| 314 | daf_check_undefined (); | 
| 315 |  | 
| 316 | ## --- The END | 
| 317 |  | 
| 318 | status_msg_ "Closing the database..."; | 
| 319 | $db->free; | 
| 320 | undef $db; | 
| 321 | status_msg "done"; | 
| 322 |  | 
| 323 | undef $limpl; | 
| 324 | undef $impl; | 
| 325 |  | 
| 326 | { | 
| 327 | use integer; | 
| 328 | my $time = time - $start_time; | 
| 329 | status_msg sprintf qq<%d'%02d''>, $time / 60, $time % 60; | 
| 330 | } | 
| 331 | exit $HasError; | 
| 332 |  | 
| 333 | END { | 
| 334 | $db->free if $db; | 
| 335 | } | 
| 336 |  | 
| 337 | ## ---- Subroutines | 
| 338 |  | 
| 339 | sub daf_open_source_dis_document ($) { | 
| 340 | my ($module_uri) = @_; | 
| 341 |  | 
| 342 | ## -- Finds |dis| source file | 
| 343 | my $ns = $module_uri; | 
| 344 | $ns =~ s/(\w+)\z//; | 
| 345 | my $ln = $1; | 
| 346 | my $file_name = dac_search_file_path_stem ($ns, $ln, $Opt{dis_suffix}); | 
| 347 | unless (defined $file_name) { | 
| 348 | die "$0: Source file for <$ns$ln> is not found"; | 
| 349 | } | 
| 350 | $file_name .= $Opt{dis_suffix}; | 
| 351 |  | 
| 352 | status_msg_ qq<Opening dis source file "$file_name"...>; | 
| 353 |  | 
| 354 | ## -- Opens |dis| file and construct |DISDocument| tree | 
| 355 | open my $file, '<', $file_name or die "$0: $file_name: $!"; | 
| 356 | my $dis = $parser->parse ({character_stream => $file}); | 
| 357 | require File::Spec; | 
| 358 | $dis->flag (ExpandedURI q<swcfg21:fileName> => | 
| 359 | File::Spec->abs2rel ($file_name)); | 
| 360 | $dis->dis_namespace_resolver (\&daf_module_name_namespace_resolver); | 
| 361 | close $file; | 
| 362 |  | 
| 363 | ## -- Registers namespace URI | 
| 364 | my $mod = $dis->module_element; | 
| 365 | if ($mod) { | 
| 366 | my $qn = $mod->get_attribute_ns (ExpandedURI q<dis:>, 'QName'); | 
| 367 | if ($qn) { | 
| 368 | my $prefix = $qn->value; | 
| 369 | $prefix =~ s/^[^:|]*[:|]\s*//; | 
| 370 | $prefix =~ s/\s+$//; | 
| 371 | unless (defined $ModuleNameNamespaceBinding{$prefix}) { | 
| 372 | $ModuleNameNamespaceBinding{$prefix} = $mod->defining_namespace_uri; | 
| 373 | } | 
| 374 | } | 
| 375 | } | 
| 376 |  | 
| 377 | $ModuleSourceDISDocument{$module_uri} = $dis; | 
| 378 | status_msg q<done>; | 
| 379 |  | 
| 380 | R: for (@{daf_get_referring_module_uri_list ($module_uri)}) { | 
| 381 | next R if defined $db->{modDef}->{$_}; | 
| 382 | next R if defined $ModuleSourceDNLDocument{$_}; | 
| 383 | next R if defined $ModuleSourceDISDocument{$_}; | 
| 384 | my $idx_file_name = daf_get_module_index_file_name ($_); | 
| 385 | if (-f $idx_file_name) { | 
| 386 | daf_open_current_module_index ($_, $idx_file_name); | 
| 387 | } else { | 
| 388 | daf_open_source_dis_document ($_); | 
| 389 | } | 
| 390 | } | 
| 391 | } # daf_open_source_dis_document | 
| 392 |  | 
| 393 | sub daf_open_current_module_index ($$) { | 
| 394 | my ($module_uri, $file_name) = @_; | 
| 395 | $db->pl_load_dis_database_index ($file_name); | 
| 396 |  | 
| 397 | R: for (@{$db->get_module ($module_uri) | 
| 398 | ->get_referring_module_uri_list}) { | 
| 399 | next R if defined $db->{modDef}->{$_}; | 
| 400 | next R if defined $ModuleSourceDNLDocument{$_}; | 
| 401 | next R if defined $ModuleSourceDISDocument{$_}; | 
| 402 | my $idx_file_name = daf_get_module_index_file_name ($_); | 
| 403 | if (-f $idx_file_name) { | 
| 404 | daf_open_current_module_index ($_, $idx_file_name); | 
| 405 | } else { | 
| 406 | daf_open_source_dis_document ($_); | 
| 407 | } | 
| 408 | } | 
| 409 | } # daf_open_current_module_index | 
| 410 |  | 
| 411 | sub daf_convert_dis_document_to_dnl_document () { | 
| 412 | M: for my $module_uri (keys %ModuleSourceDISDocument) { | 
| 413 | my $dis_doc = $ModuleSourceDISDocument{$module_uri}; | 
| 414 | next M unless $dis_doc; | 
| 415 | verbose_msg_ qq<Converting <$module_uri>...>; | 
| 416 | my $dnl_doc = $DNi->convert_dis_document_to_dnl_document | 
| 417 | ($dis_doc, database_arg => $db, | 
| 418 | base_namespace_binding => | 
| 419 | {(map {$_->local_name => $_->target_namespace_uri} | 
| 420 | grep {$_} values %{$db->{modDef}}), | 
| 421 | %ModuleNameNamespaceBinding}); | 
| 422 | push @Document, $dnl_doc; | 
| 423 | $ModuleSourceDNLDocument{$module_uri} = $dnl_doc; | 
| 424 | $dis_doc->free; | 
| 425 | delete $ModuleSourceDISDocument{$module_uri}; | 
| 426 | verbose_msg q<done>; | 
| 427 | } | 
| 428 | } # daf_convert_dis_document_to_dnl_document | 
| 429 |  | 
| 430 | sub daf_get_referring_module_uri_list ($) { | 
| 431 | my $module_uri = shift; | 
| 432 | my $ns = $module_uri; | 
| 433 | $ns =~ s/\w+\z//; | 
| 434 | my $src = $ModuleSourceDNLDocument{$module_uri}; | 
| 435 | $src = $ModuleSourceDISDocument{$module_uri} unless defined $src; | 
| 436 | my $mod_el = $src->module_element; | 
| 437 | my $r = []; | 
| 438 | if ($mod_el) { | 
| 439 | my $req_el = $mod_el->require_element; | 
| 440 | if ($req_el) { | 
| 441 | M: for my $m_el (@{$req_el->child_nodes}) { | 
| 442 | next M unless $m_el->node_type eq '#element'; | 
| 443 | next M unless $m_el->expanded_uri eq ExpandedURI q<dis:Module>; | 
| 444 | my $qn_el = $m_el->get_attribute_ns (ExpandedURI q<dis:>, 'QName'); | 
| 445 | if ($qn_el) { | 
| 446 | push @$r, $qn_el->qname_value_uri; | 
| 447 | } else { | 
| 448 | my $n_el = $m_el->get_attribute_ns (ExpandedURI q<dis:>, 'Name'); | 
| 449 | if ($n_el) { | 
| 450 | push @$r, $ns.$n_el->value; | 
| 451 | } else { | 
| 452 | # The module itself | 
| 453 | } | 
| 454 | } | 
| 455 | } | 
| 456 | } | 
| 457 | } | 
| 458 | return $r; | 
| 459 | } # daf_get_referring_module_uri_list | 
| 460 |  | 
| 461 | sub dac_search_file_path_stem ($$$) { | 
| 462 | my ($ns, $ln, $suffix) = @_; | 
| 463 | require File::Spec; | 
| 464 | for my $dir (@{$Opt{input_search_path}->{$ns}||[]}) { | 
| 465 | my $name = Cwd::abs_path | 
| 466 | (File::Spec->canonpath | 
| 467 | (File::Spec->catfile ($dir, $ln))); | 
| 468 | if (-f $name.$suffix) { | 
| 469 | return $name; | 
| 470 | } | 
| 471 | } | 
| 472 | return undef; | 
| 473 | } # dac_search_file_path_stem; | 
| 474 |  | 
| 475 | sub daf_get_module_index_file_name ($$) { | 
| 476 | my ($module_uri) = @_; | 
| 477 | my $ns = $module_uri; | 
| 478 | $ns =~ s/(\w+)\z//; | 
| 479 | my $ln = $1; | 
| 480 |  | 
| 481 | verbose_msg qq<Database module index <$module_uri> is requested>; | 
| 482 | my $suffix = $Opt{dafx_suffix}; | 
| 483 | my $name = dac_search_file_path_stem ($ns, $ln, $suffix); | 
| 484 | if (defined $name) { | 
| 485 | $name .= $suffix; | 
| 486 | } elsif (defined ($name = dac_search_file_path_stem | 
| 487 | ($ns, $ln, $Opt{dis_suffix}))) { | 
| 488 | $name .= $suffix; | 
| 489 | } else { | 
| 490 | $name = Cwd::abs_path | 
| 491 | (File::Spec->canonpath | 
| 492 | (File::Spec->catfile | 
| 493 | (defined $Opt{input_search_path}->{$ns}->[0] | 
| 494 | ? $Opt{input_search_path}->{$ns}->[0] : '.', | 
| 495 | $ln.$suffix))); | 
| 496 | } | 
| 497 | return $name; | 
| 498 | } # daf_get_module_index_file_name | 
| 499 |  | 
| 500 | sub daf_module_name_namespace_resolver ($) { | 
| 501 | my $prefix = shift; | 
| 502 |  | 
| 503 | ## -- From modules in database | 
| 504 | M: for (values %{$db->{modDef}}) { | 
| 505 | my $mod = $_; | 
| 506 | next M unless defined $mod; | 
| 507 | if ($mod->local_name eq $prefix) { | 
| 508 | return $mod->target_namespace_uri; | 
| 509 | } | 
| 510 | } | 
| 511 |  | 
| 512 | ## -- From not-in-database-yet module list | 
| 513 | if (defined $ModuleNameNamespaceBinding{$prefix}) { | 
| 514 | return $ModuleNameNamespaceBinding{$prefix}; | 
| 515 | } | 
| 516 | return undef; | 
| 517 | } # daf_module_name_namespace_resolver | 
| 518 |  | 
| 519 | sub daf_db_module_resolver ($$$) { | 
| 520 | my ($db, $mod, $type) = @_; | 
| 521 | my $ns = $mod->namespace_uri; | 
| 522 | my $ln = $mod->local_name; | 
| 523 | my $suffix = { | 
| 524 | ExpandedURI q<dp:ModuleIndexFile> => $Opt{dafx_suffix}, | 
| 525 | ExpandedURI q<dp:ModuleResourceFile> => $Opt{daem_suffix}, | 
| 526 | ExpandedURI q<dp:ModuleNodeStorageFile> => $Opt{dafs_suffix}, | 
| 527 | }->{$type} or die "Unsupported type: <$type>"; | 
| 528 | verbose_msg qq<Database module <$ns$ln> is requested>; | 
| 529 | my $name = dac_search_file_path_stem ($ns, $ln, $suffix); | 
| 530 | if (defined $name) { | 
| 531 | return $name.$suffix; | 
| 532 | } else { | 
| 533 | return undef; | 
| 534 | } | 
| 535 | } # daf_db_module_resolver | 
| 536 |  | 
| 537 | sub daf_on_error ($$) { | 
| 538 | my ($self, $err) = @_; | 
| 539 | if ($err->severity == $err->SEVERITY_WARNING) { | 
| 540 | my $info = ExpandedURI q<dp:info>; | 
| 541 | if ($err->type =~ /\Q$info\E/) { | 
| 542 | my $msg = $err->text; | 
| 543 | if ($msg =~ /\.\.\.\z/) { | 
| 544 | verbose_msg_ $msg; | 
| 545 | } else { | 
| 546 | verbose_msg $msg; | 
| 547 | } | 
| 548 | } else { | 
| 549 | my $msg = $err->text; | 
| 550 | if ($msg =~ /\.\.\.\z/) { | 
| 551 | status_msg_ $msg; | 
| 552 | } else { | 
| 553 | status_msg $msg; | 
| 554 | } | 
| 555 | } | 
| 556 | } else { | 
| 557 | warn $err; | 
| 558 | $HasError = 1; | 
| 559 | } | 
| 560 | } # daf_on_error | 
| 561 |  | 
| 562 | sub daf_check_undefined () { | 
| 563 | unless ($Opt{no_undef_check}) { | 
| 564 | status_msg_ "Checking undefined resources..."; | 
| 565 | $db->check_undefined_resource; | 
| 566 | print STDERR "done\n"; | 
| 567 | } | 
| 568 | } # daf_check_undefined | 
| 569 |  | 
| 570 | __END__ | 
| 571 |  | 
| 572 | =head1 NAME | 
| 573 |  | 
| 574 | dac.pl - Creating "dac" Database File from "dis" Source Files | 
| 575 |  | 
| 576 | =head1 SYNOPSIS | 
| 577 |  | 
| 578 | perl path/to/dac.pl [--input-db-file-name=input.dac] \ | 
| 579 | --output-file-name=out.dac [options...] \ | 
| 580 | input.dis | 
| 581 | perl path/to/dac.pl --help | 
| 582 |  | 
| 583 | =head1 DESCRIPTION | 
| 584 |  | 
| 585 | This script, C<dac.pl>, compiles "dis" source files into "dac" | 
| 586 | database file.  The generated database file can be used | 
| 587 | in turn to generate Perl module file, for example, by another | 
| 588 | script C<dac2pm.pl> or can be used to create larger database | 
| 589 | by specifying its file name as the C<--input-db-file-name> | 
| 590 | argument of another C<dac.pl> execution. | 
| 591 |  | 
| 592 | This script is part of manakai. | 
| 593 |  | 
| 594 | =head1 OPTIONS | 
| 595 |  | 
| 596 | =over 4 | 
| 597 |  | 
| 598 | =item I<input.dis> (Required) | 
| 599 |  | 
| 600 | The unnamed option specifies a file name path of the source "dis" file | 
| 601 | from which a database is created.  This option is required. | 
| 602 |  | 
| 603 | =item C<--input-db-file-name=I<file-name>> (Default: none) | 
| 604 |  | 
| 605 | A file path of the base database.  This option is optional; if this | 
| 606 | option is specified, the database file is loaded first | 
| 607 | and then I<input.dis> file is loaded in the context of it. | 
| 608 | Otherwise, a new database is created. | 
| 609 |  | 
| 610 | =back | 
| 611 |  | 
| 612 | =head1 SEE ALSO | 
| 613 |  | 
| 614 | L<lib/Message/Util/DIS.dis> - The actual implementation | 
| 615 | of the "dis" interpretation. | 
| 616 |  | 
| 617 | =head1 LICENSE | 
| 618 |  | 
| 619 | Copyright 2004-2006 Wakaba <w@suika.fam.cx>.  All rights reserved. | 
| 620 |  | 
| 621 | This program is free software; you can redistribute it and/or | 
| 622 | modify it under the same terms as Perl itself. | 
| 623 |  | 
| 624 | =cut |