# Help.pm: Help Web Service package RDA::Web::Help; # $Id: Help.pm,v 1.24 2015/06/06 18:59:18 RDA Exp $ # ARCS: $Header: /home/cvs/cvs/RDA_8/src/scripting/lib/RDA/Web/Help.pm,v 1.24 2015/06/06 18:59:18 RDA Exp $ # # Change History # 20150606 MSC Add models and themes. =head1 NAME RDA::Web::Help - Help Web Service =head1 SYNOPSIS require RDA::Web::Help; =head1 DESCRIPTION The objects of the C class are used to perform help requests. The following methods are available: =cut use strict; BEGIN { use Exporter; use IO::File; use RDA::Text qw(get_string); use RDA::Driver::Sgml; use RDA::Driver::Web qw(encode_uri); use RDA::Handle::Data; use RDA::Handle::Memory; use RDA::Object; use RDA::Object::Content; use RDA::Object::Rda; use RDA::SDCL::Block; use RDA::SDSL::Module; } # Define the global public variables use vars qw($DUMP $STRINGS $VERSION @ISA); $DUMP = 0; $VERSION = sprintf('%d.%02d', q$Revision: 1.24 $ =~ /(\d+)\.(\d+)/); @ISA = qw(Exporter); # Define the global constants my $DOC = q{}; my $EOL = "\015\012"; # Define the global private variables # Define the main tabs my @tb_tab = ( ['help', 'TabMain', '/help/man', 'rda_man'], # Text:TabMain ['help', 'TabUI', '/help/dir/ui', 'ui'], # Text:TabUI ['help', 'TabEngine', '/help/engine', 'RDA::Agent'], # Text:TabEngine ['help', 'TabContent', '/help/collect', 'collect'], # Text:TabContent ['package', 'TabData', '/package/', 'package'], # Text:TabData ); # Define the related link sections my $tb_cnt = [ [[get_string('SctMan'), [ [get_string('LnkListDc'), '/help/collect/list/dc', 'collect_list_dc'], [get_string('LnkHCVE'), '/help/hcve', 'hcve'], [get_string('LnkListMc'), '/help/collect/list/mc', 'collect_list_mc'], [get_string('LnkListPr'), '/help/profile', 'profile'], [get_string('LnkListSc'), '/help/collect/list/sc', 'collect_list_sc'], [get_string('LnkListTl'), '/help/collect/list/tl', 'collect_list_tl'], [get_string('LnkListTm'), '/help/collect/list/tm', 'collect_list_tm'], [get_string('LnkListCb'), '/help/bundle', 'bundle'], ]]], [[get_string('SctSetup'), [ [get_string('LnkListDc'), '/help/setup/list/dc', 'setup_list_dc'], [get_string('LnkListMc'), '/help/setup/list/mc', 'setup_list_mc'], [get_string('LnkListTl'), '/help/setup/list/tl', 'setup_list_tl'], [get_string('LnkListTm'), '/help/setup/list/tm', 'setup_list_tm'], ]]], [[get_string('SctXref'), [ [get_string('LnkXrefCollect'), '/help/dir/ctl', 'ctl'], [get_string('LnkXrefMrc'), '/help/xref/mrc', 'xref_mrc'], [get_string('LnkXrefProfile'), '/help/xref/prf', 'xref_prf'], [get_string('LnkXrefSetup'), '/help/dir/cfg', 'cfg'], [get_string('LnkXrefConvert'), '/help/xref/cnv', 'xref_cnv'], [get_string('LnkConvert'), '/help/dir/Convert', 'convert'], ]]], [[get_string('SctXplr'), [ [get_string('LnkXplrNam'), '/help/xplr/nam', 'xplr_nam'], [get_string('LnkXplrSyn'), '/help/xplr/syn', 'xplr_syn'], [get_string('LnkXplrGrp'), '/help/xplr/grp', 'xplr_grp'], ]]], ]; my $tb_eng = [ [[get_string('SctRda'), [ [get_string('LnkAgent'), '/help/engine/RDA/Agent', 'RDA::Agent'], [get_string('LnkCommand'), '/help/dir/RDA/Request', 'rda_request'], [get_string('LnkDriver'), '/help/dir/RDA/Driver', 'rda_driver'], [get_string('LnkHandle'), '/help/dir/RDA/Handle', 'rda_handle'], [get_string('LnkObject'), '/help/dir/RDA/Object', 'rda_object'], [get_string('LnkPackage'), '/help/dir/RDA', 'rda'], [get_string('LnkTarget'), '/help/dir/RDA/Target', 'rda_target'], ]]], [[get_string('SctIrda'), [ [get_string('LnkPackage'), '/help/dir/IRDA', 'irda'], [get_string('LnkMechanism'), '/help/dir/IRDA/CV0200', 'irda_cv0200'], [get_string('LnkRule'), '/help/dir/dfw0200', 'dfw_cv0200'], ]]], [['SDCL', [ [get_string('LnkPackage'), '/help/dir/RDA/SDCL', 'rda_sdcl'], [get_string('LnkLibrary'), '/help/dir/RDA/Library', 'rda_library'], [get_string('LnkOperator'), '/help/dir/RDA/Operator', 'rda_operator'], [get_string('LnkApi'), '/help/dir/api', 'api'], [get_string('LnkValue'), '/help/dir/RDA/Value', 'rda_value'], ]], ['SDSL', [ [get_string('LnkPackage'), '/help/dir/RDA/SDSL', 'rda_sdsl'], ]]], [[get_string('SctMisc'), [ [get_string('LnkModel'), '/help/dir/model', 'model'], [get_string('LnkError'), '/help/error', 'error'], [get_string('LnkPod'), '/help/dir/pod', 'pod'], [get_string('LnkReadme'), '/help/dir/txt', 'txt'], [get_string('LnkTheme'), '/help/dir/theme', 'theme'], ]]], ]; # Define the generation directives my %tb_dsp = ( q{*} => {}, collect => {collect => q{#}}, engine => {RDA => q{#RDA::}}, hcve => {hcve => q{#}}, irda => {IRDA => q{#IRDA::}}, module => {module => q{#}, modules => q{#}}, mrc => {mrc => q{#}}, profile => {profile => q{#}}, setup => {setup => q{#}}, xplr => {collect => q{#}}, ); my %tb_hlp = ( bundle => {fct => \&do_bundle, rel => $tb_cnt, }, cat => {fct => \&do_text, rel => $tb_eng, }, collect => {fct => \&do_collect, rel => $tb_cnt, }, dir => {fct => \&do_dir, rel => $tb_eng, }, engine => {fct => \&do_engine, }, error => {fct => \&do_error, rel => $tb_eng, }, hcve => {fct => \&do_hcve, rel => $tb_cnt, }, irda => {fct => \&do_engine, }, man => {fct => \&do_man, }, mrc => {fct => \&do_mrc, rel => $tb_cnt, }, profile => {fct => \&do_profile, rel => $tb_cnt, }, setup => {fct => \&do_setup, rel => $tb_cnt, }, text => {fct => \&do_text, rel => $tb_eng, }, xplr => {fct => \&do_xplr, rel => $tb_cnt, }, xref => {fct => \&do_xref, rel => $tb_cnt, }, ); my %tb_lnk = ( Convert => '/help/engine/Convert', IRDA => '/help/engine/IRDA', RDA => '/help/engine/RDA', api => '/help/xref/api', cat => '/help/cat', collect => '/help/collect', cfg => '/help/xref/cfg', ctl => '/help/xref/ctl', dir => '/help/dir', hcve => '/help/hcve', mrc => '/help/mrc', profile => '/help/profile', setup => '/help/setup', ); my %tb_opt = ( api => {ext => '.pm', fil => 0, grp => 'D_RDA_INC', lnk => 0, req => ['api', 'RDA/Object', 'RDA', 'Object'], ttl => 'TtlApi', # Text:TtlApi typ => 'api:RDA/Object/', }, cfg => {ext => '.cfg', dir => 1, fil => 1, grp => 'D_RDA_COL', lnk => 0, par => -1, rel => $tb_cnt, skp => '(convert|group|mrc|profile)\.cfg', sub => 1, ttl => 'TtlCfgDir', # Text:TtlCfgDir typ => 'cfg:', }, ctl => {ext => '.ctl', dir => 1, fil => 1, grp => 'D_RDA_COL', lnk => 0, par => -1, rel => $tb_cnt, sub => 1, ttl => 'TtlRunDir', # Text:TtlRunDir typ => 'ctl:', }, dfw0200 => {ext => '.cfg', fil => 1, grp => 'D_RDA_DFW', req => ['dfw_cv0200', 'dfw/cv0200', 'cv0200'], ttl => 'TtlDfwV2', # Text:TtlDfwV2 typ => 'cat:dfw/cv0200/', }, model => {ext => '.cfg', fil => 1, grp => 'D_RDA_ADM', req => ['model', 'model', 'model'], ttl => 'TtlModel', # Text:TtlModel typ => 'cat:admin/model/', }, pod => {ext => '.pod', dir => 1, fil => 0, grp => 'D_RDA_POD', par => -1, typ => 'engine:', }, theme => {ext => '.css', fil => 1, grp => 'D_RDA_ADM', req => ['theme', 'theme', 'css'], skp => '(odf|out)\.css', ttl => 'TtlTheme', # Text:TtlTheme typ => 'cat:admin/css/', }, top => {ext => '.pm', dir => [qw(Convert IRDA RDA)], typ => 'engine:', }, txt => {ext => '.txt', dir => {engine => 1}, fil => 1, grp => 'D_RDA', par => -1, typ => 'cat:', }, ui => {ext => '.pm', fil => 0, grp => 'D_RDA_INC', lnk => 0, rel => undef, req => ['ui', q{}, 'RDA', 'UI'], typ => 'ui:UI/', }, Convert => {ext => '.pm', dir => 1, par => 1, rel => $tb_cnt, typ => 'engine:', }, IRDA => {ext => '.pm', dir => 1, par => 1, typ => 'engine:', }, RDA => {ext => '.pm', dir => 1, par => 1, typ => 'engine:', }, ); my %tb_ttl = ( api => 'TtlApi', # Text:TtlApi cat_dfw_cv0200 => 'TtlDfwV2', # Text:TtlDfwV2 cfg => 'TtlCfg', # Text:TtlCfg ctl => 'TtlRun', # Text:TtlRun convert => 'TtlConvert', # Text:TtlConvert hcve => 'TtlHcve', # Text:TtlHcve irda => 'TtlIrdaPackage', # Text:TtlIrdaPackage irda_cv0200 => 'TtlIrdaV2', # Text:TtlIrdaV2 model => 'TtlModel', # Text:TtlModel pod => 'TtlPod', # Text:TtlPod rda => 'TtlPackage', # Text:TtlPackage rda_driver => 'TtlDriver', # Text:TtlDriver rda_extern => 'TtlExtern', # Text:TtlExtern rda_handle => 'TtlHandle', # Text:TtlHandle rda_library => 'TtlMacro', # Text:TtlMacro rda_local => 'TtlOS', # Text:TtlOS rda_object => 'TtlObject', # Text:TtlObject rda_operator => 'TtlOperator', # Text:TtlOperator rda_request => 'TtlCommand', # Text:TtlCommand rda_sdcl => 'TtlSdcl', # Text:TtlSdcl rda_sdsl => 'TtlSdsl', # Text:TtlSdsl rda_target => 'TtlTarget', # Text:TtlTarget rda_token => 'TtlToken', # Text:TtlToken rda_ui => 'TtlUI', # Text:TtlUI rda_value => 'TtlValue', # Text:TtlValue rda_web => 'TtlWeb', # Text:TtlWeb setup => 'TtlCfg', # Text:TtlCfg txt => 'TtlReadme', # Text:TtlReadme txt_engine => 'TtlEngineReadme', # Text:TtlEngineReadme ui => 'TtlUI', # Text:TtlUI ); my %tb_typ = ( Convert => '/help/engine/Convert/', IRDA => '/help/engine/IRDA/', RDA => '/help/engine/RDA/', api => '/help/xref/api/', bundle => '/help/bundle/', cat => '/help/cat/', cfg => '/help/xref/cfg/', ctl => '/help/xref/ctl/', collect => '/help/collect/', dir => '/help/dir/', engine => '/help/engine/', hcve => '/help/hcve/', mrc => '/help/mrc/', pod => '/help/engine/pod/', profile => '/help/profile/', setup => '/help/setup/', txt => '/help/text/top/', ui => '/help/man/', ); # Report the package version sub Version { return $VERSION; } =head2 S<$h = RDA::Web::Help-Enew($req,$agt,$svc)> The object constructor. This method enables you to specify the request, the agent and service hash references as arguments. C is represented by a blessed hash reference. The following special key is used: =over 12 =item S< B<'_agt'> > Reference to the agent object =item S< B<'_cfg'> > Reference to the RDA software configuration =item S< B<'_cnt'> > Reference to the RDA content control object =item S< B<'_col'> > Screen width (in columns) =item S< B<'_css'> > Style definition =item S< B<'_man'> > Rule set manual page cache =item S< B<'_not'> > Page notice definition =item S< B<'_pre'> > URL prefix =item S< B<'_sdc'> > Reference to the SDCL language control object =item S< B<'_sds'> > Reference to the SDSL language control object =item S< B<'_svc'> > Service hash =item S< B<'_tab'> > Tab definition =item S< B<'_ttl'> > Rule set title cache =item S< B<'_web'> > Web rendering object =back Internal keys are prefixed by an underscore. =cut sub new { my ($cls, $req, $agt, $svc) = @_; my ($cfg); # Create the service object and return the object reference $cfg = $agt->get_config; return bless { _agt => $agt, _cfg => $cfg, _cnt => $agt->get_content, _col => $cfg->get_columns, _css => $req->get_first('css'), _man => {}, _not => $req->get_first('notice'), _pre => $req->get_first('prefix', q{}), _sdc => $agt->get_lang('SDCL'), _sds => $agt->get_lang('SDSL'), _svc => $svc, _ttl => {}, _web => RDA::Driver::Web->new($cfg), }, ref($cls) || $cls; } =head2 S<$h-Edelete_object> This method deletes the help object. =cut sub delete_object { RDA::Object::dump_caller($_[0], 'Web') if $RDA::Object::DELETE; undef %{$_[0]}; undef $_[0]; return; } =head2 S<$h-Edisplay($ofh,$met,$url,$cnt)> This method executes a display request. It returns 0 on successful completion. Otherwise, it returns a non-zero value. =cut sub display { my ($slf, $ofh, $met, $req, $cnt) = @_; my ($det, $nam, $tbl, $ttl, $typ, %lnk, %typ); # Normalize the URL $req = 'man' unless $req; # Validate the request ($typ, $req) = split(/\//, $req, 2); return 1 if !exists($tb_hlp{$typ}) || (defined($req) && $req =~ m{(^|\/)\.}); $tbl = $tb_hlp{$typ}; ($nam, $ttl, $det) = eval{&{$tbl->{'fct'}}($slf, $req, $tbl->{'rel'}, $cnt)}; return 2 if $@; return 3 unless defined($det); # Generate the page %lnk = %tb_lnk; %typ = %tb_typ; %tb_lnk = (); %tb_typ = %{$tb_dsp{exists($tb_dsp{$typ}) ? $typ : q{*}}}; eval { $slf->{'_web'}->render($ofh, { det => $det, dsp => 1, fct => \&_fmt_link, nam => $nam, ttl => $ttl, }); }; %tb_lnk = %lnk; %tb_typ = %typ; syswrite($ofh, $@, length($@)) if $@; # Indicate a successful completion return 0; } =head2 S<$h-Erequest($ofh,$met,$url,$cnt)> This method executes a help request. It returns 0 on successful completion. Otherwise, it returns a non-zero value. =cut sub request { my ($slf, $ofh, $met, $req, $cnt) = @_; my ($det, $hdr, $nam, $rel, $tbl, $ttl, $typ); # Normalize the URL $req = 'man' unless $req; # Define the available tabs on first use unless (exists($slf->{'_tab'})) { my ($svc, $tab, @tbl); $slf->{'_tab'} = $tab = []; $svc = $slf->{'_svc'}; foreach my $rec (@tb_tab) { ($nam, $ttl, @tbl) = @{$rec}; push(@{$tab}, [get_string($ttl), @tbl]) if exists($svc->{$nam}); } } # Validate the request ($typ, $req) = split(/\//, $req, 2); return 1 if !exists($tb_hlp{$typ}) || (defined($req) && $req =~ m{(^|\/)\.}); $tbl = $tb_hlp{$typ}; ($nam, $ttl, $det, $rel) = eval {&{$tbl->{'fct'}}($slf, $req, $tbl->{'rel'}, $cnt)}; return [$slf->{'_agt'}->add_error($@)->pop_errors(1)] if $@; return 2 unless defined($det) || defined($rel); # Generate the page $hdr = qq{HTTP/1.0 200 OK$EOL}. qq{Content-Type: text/html; charset=UTF-8$EOL$EOL}; syswrite($ofh, $hdr, length($hdr)); eval { $slf->{'_web'}->render($ofh, { css => $slf->{'_css'}, det => $det, fct => \&_fmt_link, nam => $nam, not => $slf->{'_not'}, pre => $slf->{'_pre'}, rel => $rel, tab => $slf->{'_tab'}, ttl => $ttl, }); }; syswrite($ofh, $@, length($@)) if $@; # Indicate a successful completion return 0; } # Treat a XML conversion bundle help request sub do_bundle { my ($slf, $req, $rel) = @_; my ($agt, $buf, $def, $nam, $ttl, @tbl); # Treat a XML conversion bundle documentation request $agt = $slf->{'_agt'}; if ($req) { ($def, $nam) = $agt->get_library('CONVERT')->get_bundle([], $req); $ttl = get_string('TtlBundle', $req); return ($req, $ttl, _as_report($slf, $def->display($nam, 1, 1), $ttl, $slf->{'_col'}), $rel); } # Get the XML conversion bundle list $buf = q{}; $def = $agt->get_library('CONVERT')->get_bundles; foreach my $nam (sort keys(%{$def})) { next unless ($ttl = $def->{$nam}->[0]->get_title($def->{$nam}->[1])); $buf .= q{!!bundle:}.$nam.q{!}.$nam.q{!!|}.$ttl.qq{\n}; } $buf = get_string('NotFound').qq{|\040\n} unless $buf; $ttl = get_string('TtlBundles'); return ('bundle', $ttl, _as_report($slf, qq{.M 2 'NAME'\n$buf\n}, $ttl, $slf->{'_col'}), $rel); } # Treat a data collection module help request sub do_collect { my ($slf, $req, $rel) = @_; my ($abr, $buf, $ctl, $fil, $nam, $ttl); $req = 'list/dc' unless $req; if ($req eq 'list/dc') { $abr = 1; $nam = 'collect_list_dc'; $ttl = get_string('TtlCollectDc'); $ctl = $slf->{'_cnt'}->get_modules('DC', undef, 'abr', 'dsc'); } elsif ($req eq 'list/mc') { $abr = 0; $nam = 'collect_list_mc'; $ttl = get_string('TtlCollectMc'); $ctl = $slf->{'_cnt'}->get_modules('MC', undef, 'dsc'); } elsif ($req eq 'list/sc') { $abr = 1; $nam = 'collect_list_sc'; $ttl = get_string('TtlCollectSc'); $ctl = $slf->{'_cnt'}->get_modules('SC', undef, 'abr', 'dsc'); } elsif ($req eq 'list/tl') { $abr = 1; $nam = 'collect_list_tl'; $ttl = get_string('TtlCollectTl'); $ctl = $slf->{'_cnt'}->get_modules('TL', undef, 'abr', 'dsc'); } elsif ($req eq 'list/tm') { $abr = 1; $nam = 'collect_list_tm'; $ttl = get_string('TtlCollectTm'); $ctl = $slf->{'_cnt'}->get_modules('TM', undef, 'abr', 'dsc'); } elsif ($req) { $fil = $req; $fil =~ s/:/\//g; return ($req, get_string('TtlModule', $req), [[$req, $fil]], $rel) if -r ($fil = $slf->{'_cfg'}->get_file('D_RDA_COL', $fil, '.ctl')); return (); } $buf = q{}; if ($abr) { foreach my $mod (sort {$ctl->{$a}->[0] cmp $ctl->{$b}->[0]} keys(%{$ctl})) { $buf .= qq{!!collect:$mod!} ._as_string($ctl->{$mod}->[0], $mod).q{!!|} ._as_string($ctl->{$mod}->[1], q{\\040}).qq{\n}; } } else { foreach my $mod (sort keys(%{$ctl})) { $buf .= qq{!!collect:$mod!$mod!!|} ._as_string($ctl->{$mod}->[0], q{\\040}).qq{\n}; } } $buf = get_string('NotFound').qq{|\040\n} unless $buf; return ($nam, $ttl, _as_report($slf, qq{.M 2 'NAME'\n$buf\n}, $ttl, $slf->{'_col'}), $rel); } # Treat a directory help request sub do_dir ## no critic (Complex) { my ($slf, $req, $rel) = @_; my ($buf, $cfg, $cls, $cur, $dir, $lnk, $nam, $opt, $par, $pre, $top, $ttl, $typ, @dir, @pkg, @sub, @tbl); # Get the file list $cfg = $slf->{'_cfg'}; if ($req) { ($dir, @sub) = split(/\//, $req); return () unless exists($tb_opt{$dir}); $opt = $tb_opt{$dir}; if (exists($opt->{'req'})) { ($nam, $req, @sub) = @{$opt->{'req'}}; $pre = qq{$nam\_}; $typ = $opt->{'typ'}; } elsif ($opt->{'sub'}) { $typ = $opt->{'typ'}.join(q{:}, @sub).q{:}; $nam = lc($req); $pre = q{}; } else { $req =~ s{/+$}{}; $nam = lc($req); $nam =~ s{/}{_}g; $pre = qq{$nam\_}; $typ = $opt->{'typ'}.$req.q{/}; } $par = $cur = qq{dir:$req/}; $par =~ s{[^\:\/]+/$}{}; $ttl = get_string(exists($tb_ttl{$nam}) ? $tb_ttl{$nam} : exists($opt->{'ttl'}) ? $opt->{'ttl'} : 'TtlDir', $cfg->cat_dir(@sub)); # Text:TtlDir $top = exists($opt->{'grp'}) ? $cfg->cat_dir($cfg->get_group($opt->{'grp'}), @sub) : $cfg->cat_dir($cfg->get_group('D_RDA_INC'), $req); return () unless opendir(DIR, $top); @tbl = readdir(DIR); closedir(DIR); if (exists($opt->{'dir'})) { if (ref($opt->{'dir'}) eq 'HASH') { @dir = sort grep {exists($opt->{'dir'}->{$_})} @tbl; } else { @dir = sort grep {m/^[^\.]/ && -d $cfg->cat_dir($top, $_)} @tbl; } } @pkg = sort grep {m/\Q$opt->{'ext'}\E$/i} @tbl; @pkg = sort grep {!m/$opt->{'skp'}$/i} @pkg if exists($opt->{'skp'}); } else { $cur = q{dir:}; $pre = q{}; $opt = $tb_opt{'top'}; $top = $cfg->get_group('D_RDA_INC'); $nam = 'rda_perl'; $ttl = get_string('TtlPerl'); @dir = sort grep {-d $cfg->cat_dir($top, $_)} @{$opt->{'dir'}}; } # Generate the report $buf = q{}; $buf .= qq{!!$par!..!!|}.get_string('DirParent').qq{\n} if ($opt->{'par'} > 0) || ($opt->{'par'} < 0 && @sub); foreach my $itm (@dir) { $cls = $pre.lc($itm); $buf .= qq{!!$cur$itm!$itm!!|} .get_string(exists($tb_ttl{$cls}) ? $tb_ttl{$cls} : 'TtlDirItem', qq{``$itm``}) .qq{\n}; # Text:TtlDirItem } $req =~ s{/}{::}g; foreach my $itm (@pkg) { $lnk = $itm; $lnk =~ s/\Q$opt->{'ext'}\E$//i if exists($opt->{'lnk'}); if (exists($opt->{'fil'})) { $cls = $itm; $cls =~ s/\Q$opt->{'ext'}\E$//i unless $opt->{'fil'}; } else { $cls = qq{$req\::$itm}; $cls =~ s/\Q$opt->{'ext'}\E$//i; } $buf .= "!!$typ$lnk!$cls!!|".$cfg->get_title($top, $itm, qq{``$cls``}) .qq{\n}; } $buf = get_string('NotFound').qq{|\040\n} unless $buf; # Return the page definition return ($nam, $ttl, _as_report($slf, qq{.M 2 'NAME'\n$buf\n}, $ttl, $slf->{'_col'}), exists($opt->{'rel'}) ? $opt->{'rel'} : $rel); } # Treat an engine help request sub do_engine { my ($slf, $req, $rel) = @_; my ($dir, $fil, $nam, $opt, $ttl); $req = 'RDA/Agent' unless $req; ($dir, $nam) = split(/\//, $req, 2); $rel = ($dir eq 'Convert') ? $tb_cnt : $tb_eng; return () unless exists($tb_opt{$dir}) && $nam; $opt = $tb_opt{$dir}; $fil = exists($opt->{'grp'}) ? $slf->{'_cfg'}->get_file($opt->{'grp'}, $nam, $opt->{'ext'}) : $slf->{'_cfg'}->get_file('D_RDA_INC', $req, $opt->{'ext'}); return () unless -r $fil; if ($dir eq 'pod') { $nam =~ s{^\w+\/}{}; $nam =~ s{\.(pm|pod)$}{}; $nam = qq{RDA::$nam} if $nam =~ s{/}{::}g; $ttl = get_string('TtlManFile', $nam); $nam = qq{Pod::$nam}; } else { $nam = $req; $nam =~ s{\.(pm|pod)$}{}; $nam =~ s{/}{::}g; $ttl = get_string('TtlEngine', $nam); } return ($nam, $ttl, [[$nam, $fil]], $rel); } # Treat an error explanation request sub do_error { my ($slf, $req, $rel, $cnt) = @_; my ($rpt, $ttl, $txt, %qry); $ttl = get_string('TtlError'); $rpt = qq{.R '$ttl'\n.Q error='}.get_string('ErrQuery').qq{'\n}; if (parse_query(\%qry, $cnt) && exists($qry{'error'})) { $rpt .= eval {qq{.S\n}.$slf->{'_agt'}->get_display->explain($qry{'error'})}; $rpt .= qq{.S\n.P\n}.get_string('ErrNotFound', $qry{'error'}).qq{\n\n} if $@; } return ('error', $ttl, _as_report($slf, $rpt, $ttl, $slf->{'_col'}), $rel); } # Treat a HCVE help request sub do_hcve { my ($slf, $req, $rel) = @_; my ($ifh, $pth, $rsp, $ttl); # List available sets unless ($req) { my ($buf, $set); # Generate the rule set list $rsp = $slf->{'_agt'}->submit(q{.}, 'DIAGLET.LIST', all => 1, description => 1); $buf = $rsp->get_data || get_string('NotFound').qq{|\040\n}; # Return the page definition $ttl = get_string('TtlHcve'); return ('hcve', $ttl, _as_report($slf, qq{.M 2 'NAME'\n$buf\n}, $ttl, $slf->{'_col'}), $rel); } # Display the rule set $ifh = IO::File->new; return () unless defined($pth = _get_hcve_man($slf, $req)) && $ifh->open("<$pth"); $ttl = exists($slf->{'_ttl'}->{$req}) ? "Rule set $req / ".$slf->{'_ttl'}->{$req} : "Rule set $req"; return ($req, $ttl, [[\&_cat_html, $ifh]], $rel); } # Treat a RDA manual page help request sub do_man { my ($slf, $req) = @_; my ($cfg, $fil, $ifh, $nam); $cfg = $slf->{'_cfg'}; return ($ifh = $cfg->get_text->get_handle('rda.pod')) ? ('rda_man', get_string('TtlMain'), [[get_string('TtlMain'), $ifh]]) : (-r ($fil = $cfg->get_file('D_RDA_POD', 'en/rda.pod'))) ? ('rda_man', get_string('TtlMain'), [[get_string('TtlMain'), $fil]]) : () unless $req; $nam = lc($req); $nam =~ s/\//_/g; return ($ifh = $cfg->get_text->get_handle("$req.pod")) ? ($nam, get_string('TtlMan', $req), [[get_string('ManTop'), $ifh]]) : (-r ($fil = $cfg->get_file('D_RDA_INC', "RDA/$req.pm"))) ? ($nam, get_string('TtlMan', $req), [[get_string('ManTop'), $fil]]) : (); } # Treat a multi-run collection help request sub do_mrc { my ($slf, $req, $rel) = @_; my ($buf, $cfg, $def, $nam, $ttl); # Treat a group documentation request return () unless $req; ($def, $nam) = $slf->{'_agt'}->get_collector->get_mrc->get_collection($req); $ttl = get_string('TtlMrc', $req); return ($req, $ttl, _as_report($slf, $def->display($nam, 1, 1), $ttl, $slf->{'_col'}), $rel); } # Treat a profile help request sub do_profile { my ($slf, $req, $rel) = @_; my ($agt, $buf, $def, $nam, $ttl, @tbl); # Treat a profile documentation request $agt = $slf->{'_agt'}; if ($req) { ($def, $nam) = $agt->get_library('PROFILE')->get_profile([], $req); $ttl = get_string('TtlProfile', $req); return ($req, $ttl, _as_report($slf, $def->display($nam, 1, 1), $ttl, $slf->{'_col'}), $rel); } # Get the profile list $buf = q{}; $def = $agt->get_library('PROFILE')->get_profiles; foreach my $nam (sort keys(%{$def})) { next unless ($ttl = $def->{$nam}->[0]->get_title($def->{$nam}->[1])); $buf .= q{!!profile:}.$nam.q{!}.$nam.q{!!|}.$ttl.qq{\n}; } $buf = get_string('NotFound').qq{|\040\n} unless $buf; $ttl = get_string('TtlProfiles'); return ('profile', $ttl, _as_report($slf, qq{.M 2 'NAME'\n$buf\n}, $ttl, $slf->{'_col'}), $rel); } # Treat a setup help request sub do_setup { my ($slf, $req, $rel, $cnt) = @_; my ($abr, $buf, $ctl, $fil, $nam, $ttl); $req = 'list/dc' unless $req; if ($req eq 'list/dc') { $abr = 1; $nam = 'setup_list_dc'; $ttl = get_string('TtlSetupDc'); $ctl = $slf->{'_cnt'}->get_modules('DC', undef, 'abr', 'dsc'); } elsif ($req eq 'list/mc') { $abr = 0; $nam = 'setup_list_mc'; $ttl = get_string('TtlSetupMc'); $ctl = $slf->{'_cnt'}->get_modules('MC', undef, 'dsc'); } elsif ($req eq 'list/tl') { $abr = 1; $nam = 'setup_list_tl'; $ttl = get_string('TtlSetupTl'); $ctl = $slf->{'_cnt'}->get_modules('TL', undef, 'abr', 'dsc'); } elsif ($req eq 'list/tm') { $abr = 1; $nam = 'setup_list_tm'; $ttl = get_string('TtlSetupTm'); $ctl = $slf->{'_cnt'}->get_modules('TM', undef, 'abr', 'dsc'); } else { my ($all, $lvl, $obj); if ($cnt) { foreach my $arg (split(/&/, $cnt)) { $all = $1 if $arg =~ m/^all=(.*)$/; $lvl = $1 if $arg =~ m/^lvl=(\d+)$/; } } return ($req, get_string('TtlSetup', $req), ($obj = $slf->{'_sds'}->load_package($req, 1)) ? _as_report($slf, $obj->display($lvl, $all, 1), $req, $slf->{'_col'}) : [[\&_cat_string, get_string('NoSetup'), $req]], $rel); } $buf = q{}; if ($abr) { foreach my $mod (sort {$ctl->{$a}->[0] cmp $ctl->{$b}->[0]} keys(%{$ctl})) { $buf .= qq{!!setup:$mod!}.$ctl->{$mod}->[0].q{!!|}.$ctl->{$mod}->[1] .qq{\n}; } } else { foreach my $mod (sort keys(%{$ctl})) { $buf .= qq{!!setup:$mod!$mod!!|}.$ctl->{$mod}->[0].qq{\\040\n}; } } $buf = get_string('NotFound').qq{|\040\n} unless $buf; # Return the page definition return ($nam, $ttl, _as_report($slf, qq{.M 2 'NAME'\n$buf\n}, $ttl, $slf->{'_col'}), $rel); } # Treat a text file display request sub do_text { my ($slf, $req, $rel) = @_; my ($ifh, $pth, $ttl, $typ); ($typ, $req) = split(/\//, $req, 2); if ($typ eq 'admin') { $pth = $slf->{'_cfg'}->get_file('D_RDA_ADM', $req); } elsif ($typ eq 'dfw') { $pth = $slf->{'_cfg'}->get_file('D_RDA_DFW', $req); } else { $pth = $slf->{'_cfg'}->get_file('D_RDA', $req); $req = $req; } $ifh = IO::File->new; return () unless $req && $ifh->open("<$pth"); $ttl = get_string('TtlFile', $req); return ($req, $ttl, [[\&_cat_file, $ifh, $ttl]], $rel); } # Treat an Explorer request sub do_xplr { my ($slf, $req, $rel) = @_; my ($agt, $buf, $ifh, $rsp, $set, $ttl, $typ, %mod); return () unless $req; ($typ) = split(/\//, $req, 2); # Get the name/module mappings $agt = $slf->{'_agt'}; %mod = $agt->submit(q{.}, 'EXPLORER.LIST', beta => (scalar $agt->get_env('XPL_EXP')), description => 1, set => $agt->get_collector->get_first('DEFAULT.K_FORCE_SET'), type => 'mappings')->get_value('list'); # Produce the report if ($typ eq 'grp') { $rsp = $agt->submit(q{.}, 'EXPLORER.LIST', beta => (scalar $agt->get_env('XPL_EXP')), description => 1, set => $agt->get_collector->get_first('DEFAULT.K_FORCE_SET'), type => 'groups'); if ($ifh = RDA::Handle::Data->new($rsp)) { $buf = q{}; while (<$ifh>) { ($set, $ttl) = split(/\|/, $_, 2); $buf .= $set.q{|} .join(q{, }, map {q{!!collect:}.$mod{$_}.q{!}.$_.q{!!}} split(/,\s*/, $ttl)) .qq{\n}; } } else { $buf = get_string('NotFound').qq{|\040\n}; } $ttl = get_string('TtlXplrGrp'); } elsif ($typ eq 'nam') { $rsp = $agt->submit(q{.}, 'EXPLORER.LIST', beta => (scalar $agt->get_env('XPL_EXP')), description => 1, set => $agt->get_collector->get_first('DEFAULT.K_FORCE_SET'), type => 'names'); if ($ifh = RDA::Handle::Data->new($rsp)) { $buf = q{}; while (<$ifh>) { ($set, $ttl) = split(/\|/, $_, 2); $buf .= q{!!collect:}.$mod{$set}.q{!}.$set.q{!!|}.$ttl.qq{\n}; } } else { $buf = get_string('NotFound').qq{|\040\n}; } $ttl = get_string('TtlXplrNam'); } elsif ($typ eq 'syn') { $rsp = $agt->submit(q{.}, 'EXPLORER.LIST', beta => (scalar $agt->get_env('XPL_EXP')), description => 1, set => $agt->get_collector->get_first('DEFAULT.K_FORCE_SET'), type => 'aliases'); if ($ifh = RDA::Handle::Data->new($rsp)) { $buf = q{}; while (<$ifh>) { ($set, $ttl) = split(/\|/, $_, 2); $buf .= m/^([^\|]*)\|(\S+)/ ? $1.q{|!!collect:}.$mod{$2}.q{!}.$2.qq{!! alias\n} : qq{$_\n}; } } else { $buf = get_string('NotFound').qq{|\040\n}; } $ttl = get_string('TtlXplrSyn'); } else { return (); } return ('xplr_'.$typ, $ttl, _as_report($slf, qq{.M 2 'NAME'\n$buf\n}, $ttl, $slf->{'_col'}), $rel); } # Treat a cross-reference request sub do_xref { my ($slf, $req, $rel) = @_; my ($agt, $nam, $obj, $rpt, $ttl, $typ); return () unless $req; ($typ, $nam) = split(/\//, $req, 2); $agt = $slf->{'_agt'}; $rpt = q{}; if ($typ eq 'api') { $nam =~ s{/}{::}g; $rpt = RDA::Object::xref($nam, 1); $ttl = get_string('TtlXrefApi', $nam); $nam =~ s{::}{_}g; $nam = 'xref_'.lc($nam); $rel = $tb_eng; } elsif ($typ eq 'cfg') { $ttl = get_string('TtlXref', $nam); if ($nam =~ m/^(.*)\/convert$/i) { $obj = $agt->get_library('CONVERT'); $rpt = $obj->xref({$1 => $obj->load("$nam.cfg")}, 0, $ttl); } elsif ($nam =~ m/\/group$/i) { $rpt = get_string('NoSetup'); } elsif ($nam =~ m/^(.*)\/mrc$/i) { $obj = $agt->get_collector->get_mrc; $rpt = $obj->xref({$1 => $obj->load("$nam.cfg")}, 0, $ttl); } elsif ($nam =~ m/^(.*)\/profile$/i) { $obj = $agt->get_library('PROFILE'); $rpt = $obj->xref({$1 => $obj->load("$nam.cfg")}, 0, $ttl); } elsif ($obj = $slf->{'_sds'}->load_package($nam)) { $rpt = $obj->xref; } else { $rpt = get_string('NoSetup'); } $nam = "xref_cfg_$nam"; } elsif ($typ eq 'ctl') { $rpt = $obj->xref if ($obj = $slf->{'_sdc'}->load_package($nam, undef, [])); $ttl = get_string('TtlXref', $nam); $nam = "xref_ctl_$nam"; } elsif ($typ eq 'cnv') { $obj = $agt->get_library('CONVERT'); $ttl = get_string('TtlXrefConvert'); $rpt = $obj->xref($obj->select, 0, $ttl); $nam = 'xref_cnv'; } elsif ($typ eq 'mrc') { $obj = $agt->get_collector->get_mrc; $ttl = get_string('TtlXrefMrc'); $rpt = $obj->xref($obj->select, 0, $ttl); $nam = 'xref_mrc'; } elsif ($typ eq 'prf') { $obj = $agt->get_library('PROFILE'); $ttl = get_string('TtlXrefProfile'); $rpt = $obj->xref($obj->select, 0, $ttl); $nam = 'xref_prf'; } else { return (); } return ($nam, $ttl, _as_report($slf, $rpt, $ttl, $slf->{'_col'}), $rel); } # --- Internal routines ------------------------------------------------------- # Convert a buffer into a report sub _as_report { my ($slf, $buf, @arg) = @_; syswrite($RDA::Text::TRACE, $buf, length($buf)) if $DUMP; return [[\&_cat_report, $slf, RDA::Handle::Memory->new($buf), @arg]]; } # Convert as a string sub _as_string { my ($str, $dft) = @_; return defined($str) ? $str : $dft; } # Insert a file sub _cat_file { my ($ofh, $ifh, $ttl) = @_; my ($buf); $buf = defined($ttl) ? qq{

$ttl

\n} : qq{
\n};
  syswrite($ofh, $buf, length($buf));
  while (defined($buf = $ifh->getline))
  { $buf =~ s{&}{&}g;
    $buf =~ s{<}{<}g;
    $buf =~ s{>}{>}g;
    $buf =~ s{(https?://\S+)}{$1};
    syswrite($ofh, $buf, length($buf));
  }
  $buf = qq{
\n}; syswrite($ofh, $buf, length($buf)); $ifh->close; return; } # Insert a HTML file sub _cat_html { my ($ofh, $ifh) = @_; my ($lin); # Skip the head section for (;;) ## no critic (Loop) { return unless defined($lin = $ifh->getline); last if $lin =~ m/\/i; } # Transfer the HTML code $lin = qq{
\n}; for (;;) ## no critic (Loop) { syswrite($ofh, $lin, length($lin)); return unless defined($lin = $ifh->getline); $lin =~ s{\<\/body\>.*}{}i; } $ifh->close; return; } # Insert a RDA report sub _cat_report ## no critic (Complex) { my ($ofh, $slf, $ifh, $nam, $wdt) = @_; my ($buf, $flg, $mrk, $pre, $str); while (<$ifh>) { if (m/^\.I\s*'(.*)'(\s+(\d+))?$/) ## no critic (Unused) { $buf = q{}; $buf .= qq{\n} unless $flg++; ($pre, $mrk) = split(/\001/, $1, 2); if (defined($mrk)) { $buf .= q{\n}; } else { $buf .= q{\n}; } if (defined($3) && $3 > 1) { $buf .= qq{
} ._encode_prefix($slf, $pre) .q{} ._encode_prefix($slf, $mrk) .q{}._encode_block($slf, $ifh).qq{
} ._encode_prefix($slf, $pre) .q{}._encode_block($slf, $ifh).qq{
\n}; $flg = 0; } } else { if ($flg) { $buf = qq{\n}; syswrite($ofh, $buf, length($buf)); $flg = 0; } if (m/^\.C(\s*(\d+))?$/) ## no critic (Unused) { $buf = _encode_columns($slf, $ifh, $wdt, $1); } elsif (m/^\.M\s*(\d+)\s*'(.*?)\|((.*?)\|)?(.*)'$/) ## no critic (Unused) { $buf = qq{\n} .q{\n} ._encode_table($slf, $ifh, $2, $4).qq{
} ._encode_prefix($slf, $pre).q{} ._encode_string($slf, $5).qq{
\n}; } elsif (m/^\.M\s*\d+\s*'(.*)'$/) { if ($nam && $1 eq 'NAME') { $str = $nam; $str =~ s{[^A-Za-z\d\-\:\.]+}{_}g; $str =~ s{_$}{}; $str =~ s{^_}{}; $buf = qq{

$nam

\n}; } else { $buf = qq{

$1

\n}; } $buf .= qq{\n}._encode_table($slf, $ifh) .qq{
\n}; } elsif (m/^\.N(\s*\d+)?$/) ## no critic (Unused) { next; } elsif (m/^\.P(\s*\d+)?$/) ## no critic (Unused) { $buf = q{

}._encode_block($slf, $ifh).qq{

\n}; } elsif (m/^\.Q\s*(\w+)='(.*)'$/) { $buf = q{
} .qq{} .q{  
\n}; } elsif (m/^\.R\s*'(.*)'$/) { $buf = qq{

$1

\n}; } elsif (m/^\.S$/) { $buf = qq{
\n}; } elsif (m/^\.T\s*'(.*)'$/) { if ($nam && $1 eq 'NAME') { $str = $nam; $str =~ s{[^A-Za-z\d\-\:\.]+}{_}g; $str =~ s{_$}{}; $str =~ s{^_}{}; $buf = qq{

$nam

\n}; } else { $buf = qq{

$1

\n}; } } else { $buf = qq{

$_

\n}; } } syswrite($ofh, $buf, length($buf)); } if ($flg) { $buf = qq{\n}; syswrite($ofh, $buf, length($buf)); } $ifh->close; return; } sub _encode_block { my ($slf, $ifh) = @_; local $/ = q{}; # Treat multiple empty lines as a single empty line my $lin = _encode_string($slf, $ifh->getline); $lin =~ s{\n}{
}g; return $lin; } sub _encode_columns { my ($slf, $ifh, $wdt, $sep) = @_; my ($buf, $cnt, $col, $lgt, $lin, $max, $pre, $txt, @tbl); $buf = q{}; $cnt = $max = 0; $sep = 0 unless defined($sep); while (defined($lin = $ifh->getline)) { last if $lin =~ m/^$/; ## no critic (Fixed) push(@tbl, $lin); $lin =~ s{\001}{}; $lin =~ s{\\([0-3][0-7]{2}|0x[0-9A-Fa-f]{2})}{chr(oct($1))}eg; $max = $lgt if ($lgt = length($lin)) > $max; ++$cnt; } if ($max && ($col = int($wdt / ($max + $sep)))) { for (; $cnt % $col ; ++$cnt) ## no critic (Loop) { push(@tbl, q{}); } $lgt = $cnt / $col; } if ($col > 1) { $sep = q{ }x$sep; for (my $row = 0 ; $row < $lgt ; ++$row) ## no critic (Loop) { $buf .= qq{\n}; for (my $off = $row ; $off < $cnt ; $off += $lgt) ## no critic (Loop) { $txt = $tbl[$off]; $txt =~ s{\001}{}; $txt =~ s{\\([0-3][0-7]{2}|0x[0-9A-Fa-f]{2})}{chr(oct($1))}eg; $buf .= qq{$sep} ._encode_string($slf, $txt).q{}; } $buf .= qq{\n}; } } else { foreach my $row (@tbl) { ($pre, $txt) = split(/\001/, $row, 2); $buf .= defined($txt) ? q{} ._encode_prefix($slf, $pre) .q{} ._encode_string($slf, $txt) .qq{\n} : q{}._encode_string($slf, $pre).qq{\n}; } } return $buf ? qq{$buf
} : q{}; } sub _encode_link { my ($slf, $typ, $lnk, $txt) = @_; my ($str); return exists($tb_typ{$typ}) ? q{$txt} : qq{$txt}; } sub _encode_prefix { my ($slf, $str) = @_; $str =~ s{\\([0-3][0-7]{2}|0x[0-9A-Fa-f]{2})}{chr(oct($1))}eg; $str =~ s{\s}{\240}g; $str = _encode_style($slf, RDA::Driver::Sgml::encode($str, 1)); $str =~ s{^(( )*)[o\*\-](( )*)$}{$1·$3}; return $str; } sub _encode_string { my ($slf, $str) = @_; $str =~ s{[\n\r\s]+$}{}; $str =~ s{\\([0-3][0-7]{2}|0x[0-9A-Fa-f]{2})}{chr(oct($1))}eg; return _encode_style($slf, RDA::Driver::Sgml::encode($str, 1)); } sub _encode_style { my ($slf, $str) = @_; $str =~ s{``(.*?)``}{$1}g; $str =~ s{~~(.*?)~~}{$1}g; $str =~ s{\*\*(.*?)\*\*}{$1}g; $str =~ s{!!(\w+):(.*?)!(.*?)!!}{_encode_link($slf, $1, $2, $3)}eg; return $str; } sub _encode_table { my ($slf, $ifh, $pre, $mrk) = @_; my ($buf, $lin); $buf = q{}; $pre = q{} unless defined($mrk); $pre =~ s{\S}{ }g; $mrk = q{ } unless defined($mrk); $pre = q{} ._encode_prefix($slf, $pre) .q{} ._encode_prefix($slf, $mrk) .q{}; while (defined($lin = $ifh->getline)) { last if $lin =~ m/^$/; ## no critic (Fixed) $buf .= $pre .join(q{  }, map {_encode_string($slf, $_)} split(/\|/, $lin)) .qq{\n}; } return $buf; } # Insert a string sub _cat_string { my ($ofh, $str, $ttl) = @_; my ($buf); $buf = defined($ttl) ? qq{

$ttl

\n$str\n} : qq{$str\n}; syswrite($ofh, $buf, length($buf)); return; } # Format anchors sub _fmt_anchor { my ($typ, $str) = @_; $str =~ s{[\\\/]}{::}g if $typ =~ m/^\#/; return $typ.encode_uri($str); } # Format links sub _fmt_link { my ($txt, $url, $pre) = @_; my ($typ); $url =~ s{::}{/}g; ($typ, $url) = split(/\//, $url, 2); return exists($tb_typ{$typ}) ? qq{\001a href='}.$pre._fmt_anchor($tb_typ{$typ}, $url) .qq{'\002$txt\001/a\002} : qq{\001code\002$txt\001/code\002} if defined($url); return exists($tb_lnk{$typ}) ? qq{\001a href='}.encode_uri($pre.$tb_lnk{$typ}).qq{'\002$txt\001/a\002} : qq{\001code\002$txt\001/code\002}; } # Get the manual page of a rule set sub _get_hcve_man { my ($slf, $set) = @_; my ($man, $pth, $tim, @sta); # Check for a file in cache if (exists($slf->{'_man'}->{$set})) { ($tim, $pth) = @{$slf->{'_man'}->{$set}}; return $pth if _get_hcve_time($slf, $set) < $tim && -f $pth; delete($slf->{'_man'}->{$set}); } # Check the existence of existing documentation if ($set =~ m/^([A-Z][A-Z\d]*):([A-Z])([A-Za-z\d]+)_(.*)$/) { $pth = RDA::Object::Rda->cat_file( $slf->{'_agt'}->get_collector->get_dir('C'), join(q{_}, uc($1), 'HCVE', uc($2), uc($3), $4, 'man.htm')); if (-f $pth && (@sta = stat($pth)) && _get_hcve_time($slf, $set) < $sta[9]) { $slf->{'_man'}->{$set} = [$sta[9], $pth]; return $pth; } } # Generate the rule set documentation return unless defined($man = $slf->{'_agt'}->submit(q{.}, 'DIAGLET.MAN', diaglet => $set, keep => 1)->get_first('man')); $slf->{'_man'}->{$set} = [$tim, $man]; return $man; } # Get the last modification date/time of a rule set sub _get_hcve_time { my ($slf, $set) = @_; my (@sta); @sta = stat($slf->{'_cfg'}->get_file('D_RDA_CHK', $set, '.xml')); return $sta[9] || 0; } # Parse the query string sub parse_query { my ($hsh, $qry) = @_; my ($cnt); if (defined($qry)) { foreach my $arg (split(/\&/, $qry)) { next unless $arg =~ m/^(\w+)=(.*)$/; $hsh->{$1} = $2; ++$cnt; } } return $cnt; } 1; __END__ =head1 SEE ALSO L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L =head1 COPYRIGHT NOTICE Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. =head1 TRADEMARK NOTICE Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. =cut