#!/usr/bin/perl -w use strict; use Message::Util::QName::Filter { DIS => q, dis => q, ManakaiDOM => q, swcfg21 => q, }; sub status_msg ($) { my $s = shift; $s .= "\n" unless $s =~ /\n$/; print STDERR $s; } sub status_msg_ ($) { my $s = shift; print STDERR $s; } sub verbose_msg ($) { my $s = shift; $s .= "\n" unless $s =~ /\n$/; print STDERR $s; } sub verbose_msg_ ($) { my $s = shift; print STDERR $s; } use Getopt::Long; use Pod::Usage; my %Opt = (); GetOptions ( 'db-base-directory-path=s' => \$Opt{db_base_path}, 'debug' => \$Opt{debug}, 'for=s' => \$Opt{For}, 'help' => \$Opt{help}, 'input-db-file-name=s' => \$Opt{input_file_name}, 'output-file-name=s' => \$Opt{output_file_name}, 'search-path|I=s' => sub { shift; my @value = split /\s+/, shift; while (my ($ns, $path) = splice @value, 0, 2, ()) { unless (defined $path) { die qq[$0: Search-path parameter without path: "$ns"]; } push @{$Opt{input_search_path}->{$ns} ||= []}, $path; } }, 'search-path-catalog-file-name=s' => sub { shift; require File::Spec; my $path = my $path_base = shift; $path_base =~ s#[^/]+$##; $Opt{search_path_base} = $path_base; open my $file, '<', $path or die "$0: $path: $!"; while (<$file>) { if (s/^\s*\@//) { ## Processing instruction my ($target, $data) = split /\s+/; if ($target eq 'base') { $Opt{search_path_base} = File::Spec->rel2abs ($data, $path_base); } else { die "$0: $target: Unknown target"; } } elsif (/^\s*\#/) { ## Comment # } elsif (/\S/) { ## Catalog entry s/^\s+//; my ($ns, $path) = split /\s+/; push @{$Opt{input_search_path}->{$ns} ||= []}, File::Spec->rel2abs ($path, $Opt{search_path_base}); } } ## NOTE: File paths with SPACEs are not supported ## NOTE: Future version might use file: URI instead of file path. }, 'undef-check!' => \$Opt{no_undef_check}, 'verbose!' => $Opt{verbose}, ) or pod2usage (2); pod2usage ({-exitval => 0, -verbose => 1}) if $Opt{help}; $Opt{file_name} = shift; pod2usage ({-exitval => 2, -verbose => 0}) unless $Opt{file_name}; pod2usage ({-exitval => 2, -verbose => 0}) unless $Opt{output_file_name}; $Opt{no_undef_check} = defined $Opt{no_undef_check} ? $Opt{no_undef_check} ? 0 : 1 : 0; $Message::DOM::DOMFeature::DEBUG = 1 if $Opt{debug}; my $start_time; BEGIN { $start_time = time } use Message::Util::DIS::DNLite; my $limpl = $Message::DOM::ImplementationRegistry->get_implementation ({ExpandedURI q => '3.0', '+' . ExpandedURI q => '1.0'}); my $impl = $limpl->get_feature (ExpandedURI q => '1.0'); my $parser = $impl->create_dis_parser; our $DNi = $impl->get_feature (ExpandedURI q => '1.0'); my $db; if (defined $Opt{input_file_name}) { $db = $impl->pl_load_dis_database ($Opt{input_file_name}); } else { ## New database $db = $impl->create_dis_database; } require Cwd; my $file_name = Cwd::abs_path ($Opt{file_name}); my $base_path = Cwd::abs_path ($Opt{db_base_path}) if length $Opt{db_base_path}; my $doc = dac_load_module_file ($db, $parser, $file_name, $base_path); my $for = $Opt{For}; $for = $doc->module_element->default_for_uri unless length $for; $db->get_for ($for)->is_referred ($doc); status_msg qq...>; my $ResourceCount = 0; $db->load_module ($doc, sub ($$$$$$) { my ($self, $db, $uri, $ns, $ln, $for) = @_; status_msg ''; status_msg qq...>; $ResourceCount = 0; ## -- Already in database my $doc = $db->get_source_file ($ns.$ln); return $doc if $doc; ## -- Finds the source file require File::Spec; for my $dir ('.', @{$Opt{input_search_path}->{$ns}||[]}) { my $name = Cwd::abs_path (File::Spec->canonpath (File::Spec->catfile ($dir, $ln.'.dis'))); if (-f $name) { my $doc = dac_load_module_file ($db, $parser, $name, $base_path); return $doc; } } ## -- Not found return undef; }, for_arg => $for, on_resource_read => sub ($$) { if ((++$ResourceCount % 10) == 0) { status_msg_ "*"; status_msg_ " " if ($ResourceCount % (10 * 10)) == 0; status_msg '' if ($ResourceCount % (10 * 50)) == 0; } }); ## Removes reference from document to database our @Document; for my $dis (@Document) { $dis->unlink_from_document; $dis->dis_database (undef); } status_msg ''; status_msg qq; $ResourceCount = 0; $db->read_properties (on_resource_read => sub ($$) { if ((++$ResourceCount % 10) == 0) { status_msg_ "*"; status_msg_ " " if ($ResourceCount % (10 * 10)) == 0; status_msg '' if ($ResourceCount % (10 * 50)) == 0; } }); status_msg ''; status_msg "done"; status_msg_ qq; $db->pl_store ($Opt{output_file_name}); status_msg "done"; unless ($Opt{no_undef_check}) { status_msg_ "Checking undefined resources..."; $db->check_undefined_resource; print STDERR "done\n"; } status_msg_ "Closing the database..."; $db->free; undef $db; status_msg "done"; undef $DNi; { use integer; my $time = time - $start_time; status_msg sprintf qq<%d'%02d''>, $time / 60, $time % 60; } exit; END { $db->free if $db; } ## (db, parser, abs file path, abs base path) -> dis doc obj sub dac_load_module_file ($$$;$) { my ($db, $parser, $file_name, $base_path) = @_; require URI::file; my $base_uri = length $base_path ? URI::file->new ($base_path.'/') : 'http://dummy.invalid/'; my $file_uri = URI::file->new ($file_name)->rel ($base_uri); my $dis = $db->get_source_file ($file_uri); unless ($dis) { status_msg_ qq...>; open my $file, '<', $file_name or die "$0: $file_name: $!"; $dis = $parser->parse ({character_stream => $file}); $dis->flag (ExpandedURI q => $file_uri); $dis->dis_database ($db); my $mod = $dis->module_element; if ($mod) { my $qn = $mod->get_attribute_ns (ExpandedURI q, 'QName'); if ($qn) { my $prefix = $qn->value; $prefix =~ s/^[^:]*://; unless (defined $dis->lookup_namespace_uri ($prefix)) { $dis->add_namespace_binding ($prefix => $mod->defining_namespace_uri); } } } my $old_dis = $dis; status_msg_ qq<...>; $dis = $DNi->convert_dis_document_to_dnl_document ($old_dis, database_arg => $db); push @Document, $dis; $old_dis->free; $db->set_source_file ($file_uri => $dis); status_msg qq; } $dis; } __END__ =head1 NAME dac.pl - Creating "dac" Database File from "dis" Source Files =head1 SYNOPSIS perl path/to/dac.pl [--input-db-file-name=input.dac] \ --output-file-name=out.dac [options...] \ input.dis perl path/to/dac.pl --help =head1 DESCRIPTION This script, C, compiles "dis" source files into "dac" database file. The generated database file can be used in turn to generate Perl module file, for example, by another script C or can be used to create larger database by specifying its file name as the C<--input-db-file-name> argument of another C execution. This script is part of manakai. =head1 OPTIONS =over 4 =item I (Required) The unnamed option specifies a file name path of the source "dis" file from which a database is created. This option is required. =item C<--input-db-file-name=I> (Default: none) A file path of the base database. This option is optional; if this option is specified, the database file is loaded first and then I file is loaded in the context of it. Otherwise, a new database is created. =item C<--output-file-name=I> (Required) The =back =head1 SEE ALSO L - Generating Perl module from "dac" file. L - The actual implementation of the "dis" interpretation. =head1 LICENSE Copyright 2004-2005 Wakaba . All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut