# RENDER.pm: Rendering Command Library package RDA::Request::RENDER; # $Id: RENDER.pm,v 1.46 2015/08/26 10:16:52 RDA Exp $ # ARCS: $Header: /home/cvs/cvs/RDA_8/src/scripting/lib/RDA/Request/RENDER.pm,v 1.46 2015/08/26 10:16:52 RDA Exp $ # # Change History # 20150826 MSC Enhance tracker generation. =head1 NAME RDA::Request::RENDER - Rendering Command Library =head1 SYNOPSIS require RDA::Request::RENDER; =head1 DESCRIPTION The objects of the C class are used to format collected information based on formatting specifications. The following methods are available: =cut use strict; BEGIN { use Exporter; use File::Copy qw(copy); use IO::File; use RDA::Text qw(add_string get_string); use RDA::Object; use RDA::Object::Message; use RDA::Object::Rda qw($CREATE $FIL_PERMS); } # Define the global public variables use vars qw($STRINGS $VERSION @ISA); $VERSION = sprintf('%d.%02d', q$Revision: 1.46 $ =~ /(\d+)\.(\d+)/); @ISA = qw(Exporter); # Define the global private constants my $CMD = q{%COL\d+%|%END(?:COL|JSM|KMS|LIST|SEQ|TBL|SEQ)%|} .q{%JSM%|%KMS[^%]*%|%LIST%|%TBL%|%SEQ%}; my $NBD = q{ style='border-style:none;padding:0px;'}; my $NBT = q{ style='border-style:none;padding:0px 0px 0px 4px;'}; my $SEP = qq{    }; # Define the global private variables my %tb_beg = ( q{*} => q{}, q{1} => q{}, q{A} => q{}, q{a} => q{}, q{I} => q{}, q{i} => q{}, ); my @tb_jus = ( q{ align='left'}, q{ align='right'}, q{ align='left'}, q{ align='center'}, ); my %tb_mos = ( ARU => ['MosAru', # Text:MosAru 'https://updates.oracle.com/Orion/PatchDetails/'. 'process_form?aru=%s&patch_password=&no_header=0'], BUG => ['MosBug', # Text:MosBug 'https://support.oracle.com/rs?type=bug&id=%s'], DOC => ['MosDoc', # Text:MosDoc 'https://support.oracle.com/rs?type=doc&id=%s'], PATCH => ['MosPatch', # Text:MosPatch 'https://support.oracle.com/rs?type=patch&id=%s'], ); my %tb_row = ( BOTTOM => q{ valign='bottom'}, MIDDLE => q{ valign='middle'}, TOP => q{ valign='top'}, ROWS => q{}, ); my %tb_thm = ( alta => {nwl => qq{\n}, lnk => 1, css => 'alta.css'}, odf => {nwl => q{}, lnk => 0, css => 'odf.css'}, rda => {nwl => qq{\n}, lnk => 1, css => 'rda.css'}, skyros => {nwl => qq{\n}, lnk => 1, css => 'skyros.css'}, tst => {nwl => qq{\n}, lnk => 0, css => 'odf.css'}, ); # Report the package version sub Version { return $VERSION; } =head2 S<$h = RDA::Request::RENDER-Enew($agt)> The object constructor. This method enables you to specify the agent reference as an argument. C is represented by a blessed hash reference. The following special keys are used: =over 10 =item S< B<'_acr'> > Acronym hash =item S< B<'_agt'> > Reference to the agent object =item S< B<'_cas'> > Indicates a case-sensitive context =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'> > Reference to the collector object =item S< B<'_cpm'> > Code page mapping =item S< B<'_css'> > Cascading style sheet (CSS) file name =item S< B<'_ctl'> > Reference to the input/output control object =item S< B<'_dft'> > Default theme name =item S< B<'_dir'> > Collector directory =item S< B<'_dsp'> > Reference to the display control object when verbose =item S< B<'_hdr'> > Header reference counter =item S< B<'_hom'> > Context home directory =item S< B<'_jsm'> > Java Stack Match URL =item S< B<'_own'> > Ownership alignment indicator =item S< B<'_rpt'> > Report to present in the report frame at initial load =item S< B<'_thm'> > Theme name =item S< B<'_trk'> > Usage tracking directive =item S< B<'_var'> > Render variable hash =item S< B<'_ver'> > Software release/version =back Internal keys are prefixed by an underscore. =cut sub new { my ($cls, $agt) = @_; my ($cfg, $cnt, $col, $def, $ifh, $key, $pth, $slf, $tbl, $val); # Create the library object $cfg = $agt->get_config; $cnt = $agt->get_content; $col = $agt->get_collector; $def = $col->get_definition; $slf = bless { _acr => {}, _agt => $agt, _cas => $cfg->get_value('B_CASE', 1), _cpm => {}, _cfg => $cfg, _cnt => $cnt, _col => $col, _dft => $def->get_first('RENDER.W_THEME', 'rda'), _dsp => $agt->is_verbose, _hom => $col->get_data, _own => 1, _rpt => $def->get_first('RENDER.T_REPORT', 'RDA__blank.htm'), _var => {}, _ver => $cfg->get_version, }, ref($cls) || $cls; # Load additional themes if (opendir(DIR, $cfg->get_group('D_RDA_CSS'))) { foreach my $fil (readdir(DIR)) { $tb_thm{$2} = {nwl => qq{\n}, lnk => 0, css => $1} if $fil =~ m/^(([a-z]+_[a-z\d]+)\.css)$/ && !exists($tb_thm{$2}); } closedir(DIR); } # Validate the theme $slf->{'_dft'} = 'rda' unless exists($tb_thm{$slf->{'_dft'}}); # Load the acronyms and render variable definitions $ifh = IO::File->new; $tbl = $cnt->get_module_groups; foreach my $dir (values(%{$tbl})) { _load_acronyms($slf, $ifh) if -f ($pth = $cfg->cat_file($dir, 'acronyms.txt')) && $ifh->open(q{<}.$pth); } _load_acronyms($slf, $ifh) if $ifh->open(q{<}.$cfg->get_file('D_RDA_DAT', 'acronyms.txt')); if ($ifh->open(q{<}.$cfg->get_file('D_RDA_DAT', 'render.txt'))) { while (<$ifh>) { next if m/^#$/; s/[\n\r\s]*$//; ($key, $val) = split(/=/, $_, 2); $slf->{'_var'}->{$key} = $val if $key && $val; } $ifh->close; } # Load the code page mappings if ($ifh->open(q{<}.$cfg->get_file('D_RDA_DAT', 'cp.txt'))) { while(<$ifh>) { $slf->{'_cpm'}->{$1} = $2 if m/^(\d+)\s+(\S+)/; } $ifh->close; } # Return the object reference return $slf; } sub _load_acronyms { my ($slf, $ifh) = @_; my ($key, $val); while (<$ifh>) { next if m/^#$/; s/[\n\r\s]*$//; ($key, $val) = split(/=/, $_, 2); $slf->{'_acr'}->{$key} = $val if $key && $val; } $ifh->close; return; } =head2 S<$h-Edelete_object> This method deletes the library object. =cut sub delete_object { RDA::Object::dump_caller($_[0], 'Commands') if $RDA::Object::DELETE; undef %{$_[0]}; undef $_[0]; return; } =head2 S<$h-Eexec_command($req)> This method executes the command specified in the message. =cut sub exec_command { my ($slf, $req) = @_; my $cmd = $req->{'msg'}; return exists($tb_cmd{$cmd}) ? &{$tb_cmd{$cmd}}($slf, $req) : $req->error('NotImplemented', get_string('BAD_COMMAND', $cmd)); } =head1 RENDER COMMANDS =head2 RENDER.ADD_MOS - Define a MOS Wiki directive This command adds or modifies a C Wiki directive. You cannot modify internal entries. It supports the following attributes: =over 8 =item B< type> Specifies its type, which contains uppercase letters only. =item B< text> Specifies the associated text. =item B< url> Specifies the associated URL. =back =cut sub _do_mos { my ($slf, $req) = @_; my ($abr, $txt, $typ, $url); eval { die get_string('BAD_MOS_TYPE') unless defined($typ = $req->get_first('type')) && $typ =~ m{^[A-Z]+$}; die get_string('ERR_MOS_TYPE', $typ) if exists($tb_mos{$typ}) && !$tb_mos{$typ}->[2]; die get_string('BAD_MOS_TEXT', $typ) unless defined($txt = $req->get_first('text')) && $txt =~ m{\%s}; die get_string('BAD_MOS_URL', $typ) unless defined($url = $req->get_first('url')) && $url =~ m{^https?://[^:/]+(:\d+)?/.*%s}; $abr = 'Mos_'.lc($typ); $tb_mos{$typ} = [$abr, $url, 1] if defined(add_string($abr, $txt)); }; return $req->reply($@, 'AddMos'); } =head2 RENDER.GEN_CSS - Cascade style sheet generation command This command generates the cascade style sheet file for the collection. It supports the following attributes: =over 11 =item B< force> Forces the CSS file generation. =item B< set> Specifies an optional archive result set identifier. =item B< theme> Specifies the rendering theme (C by default). =item B< verbose> When specified, controls the rendering verbosity. =back =cut sub _do_css { my ($slf, $req) = @_; my ($css, $dsp); # Get the request context information _get_context($slf, $req); # Generate the cascade style sheet file $dsp->dsp_line(get_string('V_Css')) if ($dsp = _is_verbose($slf, $req->get_first('verbose'))); eval {$css = $slf->gen_css($req->get_first('force'))}; # Indicate the completion status return $req->reply($@, 'CssGeneration', css => $css); } sub _is_verbose { my ($slf, $flg) = @_; return !defined($flg) ? $slf->{'_dsp'} : $flg ? $slf->{'_agt'}->get_display: undef; } =head2 RENDER.GEN_HTML - HTML generation command This command transforms the formatting specifications in a HTML file. You can specify the report by its name or by its file name. By default, it derives the title the report or file name. The Cascade Style Sheet file is generated if it does not already exist. It supports the following attributes: =over 13 =item B< align> When false, disables ownership alignment (true by default) =item B< css> When set, recreates the Cascade Style Sheet file. =item B< directory> When specified, indicates the directory containing the report. =item B< force> Regenerates all reports. =item B< index> When specified, indicates the start index. =item B< reports> Lists reports to render. =item B< save> Allows to overwrite the incremental save indicator. =item B< set> Specifies an optional archive result set identifier. =item B< start> When specified, indicates the start report. =item B< theme> Specifies the rendering theme (C by default). =item B< title> Specifies a default title. =item B< type> Specifies an optional report type. =item B< verbose> When specified, controls the rendering verbosity. =back =cut sub _do_html ## no critic (Complex) { my ($slf, $req) = @_; my ($cnt, $dft, $dsp, $nam, $rpt, $sub, $ttl, @tbl); # Render files $dft = $req->get_first('title'); $dsp = _is_verbose($slf, $req->get_first('verbose')); eval { local $slf->{'_own'} = $req->get_first('align', 1); ## no critic (Local) # Generate the reports $dsp->dsp_line(get_string('V_Generate')) if $dsp; if (@tbl = $req->get_value('files')) { # Get the default context information _dft_context($slf, $req); # Treat all specified reports $rpt = []; foreach my $arg (@tbl) { ($nam, $ttl) = split(/\|/, $arg, 2); $dsp->dsp_line(get_string('VI_Report', $nam)) if $dsp; push(@{$rpt}, $slf->gen_html($nam, defined($ttl) ? $ttl : $dft)); } } elsif (@tbl = $req->get_value('reports')) { # Get the collector context information _get_context($slf, $req); # Treat all specified reports $sub = $slf->{'_col'}->get_sub($sub) if defined($sub = $req->get_first('type')); $rpt = []; foreach my $arg (@tbl) { ($nam, $ttl) = split(/\|/, $arg, 2); $dsp->dsp_line(get_string('VI_Report', $nam)) if $dsp; push(@{$rpt}, $slf->gen_html( defined($sub) ? RDA::Object::Rda->cat_file($sub, $nam) : $nam, defined($ttl) ? $ttl : $dft, $sub)); } } elsif (defined($req->get_first('directory'))) { # Get the default context information _dft_context($slf, $req); # Treat existing reports $cnt = 0; foreach my $fil ($slf->get_reports($req->get_first('force'))) { $dsp->dsp_line(get_string('VI_Report', $fil)) if $dsp; push(@{$rpt}, $slf->gen_html($fil, $dft)); ++$cnt; } $dsp->dsp_line(get_string('VI_Nothing')) if $dsp && !$cnt; } else { my ($col, $sav); # Get the collector context information _get_context($slf, $req); $col = $slf->{'_col'}; # Treat existing reports $cnt = 0; foreach my $fil ($slf->get_reports($req->get_first('force'))) { $dsp->dsp_line(get_string('VI_Report', $fil)) if $dsp; $slf->gen_html($fil, $dft, 1); ++$cnt; } $dsp->dsp_line(get_string('VI_Nothing')) if $dsp && !$cnt; # Generate the common files and the index page if ($cnt || -d RDA::Object::Rda->cat_dir($slf->{'_dir'}, 'extern')) { $dsp->dsp_line(get_string('VI_Index')) if $dsp; $slf->gen_index($req->get_first('index'), $req->get_first('start'), $req->get_first('css')); } # Execute the post-render steps $sav = $req->get_first('save'); $col->save unless $col->is_new || $col->post('POST_RENDER', $sav) == 0 || defined($sav) || $col->should_save; } }; # Indicate the completion status return $req->reply($@, 'ReportGeneration', reports => $rpt); } =head2 RENDER.GEN_INDEX - Index generation command This command generates the index file and the start file. It supports the following attributes: =over 11 =item B< css> When set, recreates the Cascade Style Sheet file. =item B< index> When specified, indicates the start index. =item B< set> Specifies an optional archive result set identifier. =item B< start> When specified, indicates the start report. =item B< theme> Specifies the rendering theme (C by default). =item B< verbose> When specified, controls the rendering verbosity. =back =cut sub _do_index { my ($slf, $req) = @_; my ($dsp); # Get the request context information _get_context($slf, $req); # Generate the index $dsp->dsp_line(get_string('V_Index')) if ($dsp = _is_verbose($slf, $req->get_first('verbose'))); eval {$slf->gen_index($req->get_first('index'), $req->get_first('start'), $req->get_first('css'))}; # Indicate the completion status return $req->reply($@, 'IndexGeneration'); } # Set a default context sub _dft_context { my ($slf, $req) = @_; my ($ctl, $nam); $slf->{'_ctl'} = (($nam = $req->get_first('set')) && defined($ctl = $slf->{'_agt'}->get_registry('WEB.ARC')) && defined($ctl = $ctl->get_archive($nam))) ? $ctl : $slf; $slf->{'_dir'} = RDA::Object::Rda->is_path($req->get_first('directory')) || RDA::Object::Rda->current_dir; $slf->{'_thm'} = exists($tb_thm{$nam = $req->get_first('theme', q{?})}) ? $nam : $slf->{'_dft'}; return $slf->{'_ver'} = $req->get_first('version', $slf->{'_cfg'}->get_version); } # Get the context information sub _get_context { my ($slf, $req) = @_; my ($ctl, $nam); $slf->{'_ctl'} = (($nam = $req->get_first('set')) && defined($ctl = $slf->{'_agt'}->get_registry('WEB.ARC')) && defined($ctl = $ctl->get_archive($nam))) ? $ctl : $slf; $slf->{'_dir'} = RDA::Object::Rda->is_path($req->get_first('directory')) || $slf->{'_col'}->get_data; $slf->{'_thm'} = exists($tb_thm{$nam = $req->get_first('theme', q{?})}) ? $nam : $slf->{'_dft'}; return $slf->{'_ver'} = $req->get_first('version', $slf->{'_cfg'}->get_version); } =head2 RENDER.GEN_OUTPUT - Immediate rendering command This commands reads formatting specifications from standard input and transforms them into HTML code. =cut sub _do_output { my ($slf, $req) = @_; my ($ifh, $nwl, %dsc); eval { # Initialization $dsc{'nwl'} = $nwl = $tb_thm{$slf->{'_dft'}}->{'nwl'}; # Insert the style $ifh = IO::File->new; if ($ifh->open(q{<}.$slf->{'_cfg'}->get_file('D_RDA_CSS', 'out.css'))) { while(<$ifh>) { s{\/\*.*?\*\/}{}g; s{[\n\r\s]+$}{}; print "$nwl" if $_; } $ifh->close; } # Generate the HTML code _gen_html($slf, $slf->{'_agt'}->get_screen, *STDIN, 0, \%dsc); }; # Indicate the completion status return $req->reply($@, 'Output'); } =head1 RENDER METHODS =head2 S<$h-Egen_css($flg)> This method generates the Cascade Style Sheet file for the collection if it does not exist. When the flag is set, it recreates the Cascade Style Sheet file. It returns the name of the Cascade Style Sheet file. =cut sub gen_css { my ($slf, $flg) = @_; my ($cfg, $css, $dst, $src, $thm); # Return directly the CSS file name on multiple calls return $slf->{'_css'} if exists($slf->{'_css'}) && !$flg; # Stop if the CSS file already exists $cfg = $slf->{'_cfg'}; $slf->{'_css'} = $css = $slf->{'_cas'} ? 'RDA_rda.css' : 'rda_rda.css'; $dst = $cfg->cat_file($slf->{'_dir'}, $css); if ($flg) { 1 while unlink($dst); } elsif ($slf->{'_ctl'}->is_available($dst)) { return $css; } # Generate the CSS file $slf->{'_ctl'}->copy_file( $cfg->get_file('D_RDA_CSS', $tb_thm{$slf->{'_thm'}}->{'css'}), $dst); # Return the name of the CSS file return $css; } =head2 S<$h-Egen_html($name[,$title[,$sub]])> This method transforms formatting specifications in a HTML file. You can specify the report by its name or by its file name. By default, it derives the title from the report or file name. It generates the Cascade Style Sheet file is generated if it does not exist and then it returns the name of the generated file. =cut sub gen_html ## no critic (Complex) { my ($slf, $src, $ttl, $sub, $idx) = @_; my ($cfh, $ctl, $dir, $dst, $ifh, $nwl, $ofh, $set, $thm, %dsc); # Initialization $ctl = $slf->{'_ctl'}; $dir = $slf->{'_dir'}; $src = RDA::Object::Rda->is_path($src); $thm = $tb_thm{$slf->{'_thm'}}; $dsc{'dat'} = RDA::Object::Rda->basename($src); $dsc{'def'} = {}; $dsc{'lnk'} = $thm->{'lnk'}; $dsc{'nwl'} = $nwl = $thm->{'nwl'}; $dsc{'toc'} = []; # Set a default title unless ($ttl) { $ttl = ($src =~ m/(\w*)(\.(dat|txt))?$/i) ? $1 : 'RDA Report'; $ttl =~ s/_/ /g; $ttl =~ s/\b([a-z])/\U$1/g; } $dsc{'ttl'} = $ttl; # Correct the CSS path if ($thm->{'lnk'}) { $dsc{'css'} = $slf->gen_css; $dsc{'css'} = '../'.$dsc{'css'} if $sub; } else { $dsc{'css'} = $slf->{'_cfg'}->get_file('D_RDA_CSS', $thm->{'css'}); } # Determine the file names and get extra rendering information if ($src =~ m/\.dat$/i) { $dst = $slf->{'_cas'} ? $src : lc($src); $dst =~ s/\.dat$/.htm/i; $src = $slf->{'_cfg'}->get_file('D_RDA_DAT', 'dat.txt'); $dsc{'hdr'} = 1; } else { $src = "$src.txt" unless $src =~ m/\.txt$/i; $dst = $slf->{'_cas'} ? $src : lc($src); $dst =~ s/\.txt$/.htm/i; $src = RDA::Object::Rda->cat_file($dir, $src) unless RDA::Object::Rda->is_absolute($src); # Get the table of content _gen_toc($slf, $src, $dsc{'toc'}, $dsc{'def'}, $ttl); $dsc{'ttl'} = $dsc{'def'}->{'title'} if exists($dsc{'def'}->{'title'}); } $dst = RDA::Object::Rda->cat_file($dir, $dst) unless RDA::Object::Rda->is_absolute($dst); # Determine the page character set if (exists($dsc{'def'}->{'codepage'})) { $set = $dsc{'def'}->{'codepage'}; $set = exists($slf->{'_cpm'}->{$set}) ? $slf->{'_cpm'}->{$set} : "IBM-$set"; } else { $set = exists($dsc{'def'}->{'charset'}) ? $dsc{'def'}->{'charset'} : 'UTF-8'; } # Generate the HTML file $ifh = $ctl->open_file($src); $ofh = $ctl->create_file($dst, 'ERR_REPORT'); $ctl->check_free($ifh); print {$ofh} q{}.$nwl. q{}.$nwl. q{}.$nwl. q{}.$dsc{'ttl'}.q{}.$nwl; if ($dsc{'lnk'}) { print {$ofh} q{}.$nwl; } elsif (($cfh = IO::File->new)->open(q{<}.$dsc{'css'})) { while (<$cfh>) { s{\/\*.*?\*\/}{}g; s{[\n\r\s]+$}{}; print {$ofh} qq{$nwl} if $_; } $cfh->close; } _gen_tracker($slf, $ofh, $dsc{'def'}->{'trackid'}) if exists($dsc{'def'}->{'trackid'}); print {$ofh} qq{$nwl}; _gen_html($slf, $ofh, $ifh, $idx, \%dsc); print {$ofh} qq{$nwl}; $ofh->close; $ifh->close; # Return the result file return $dst; } # Generate the HTML file sub _gen_html ## no critic (Complex) { my ($slf, $dst, $src, $flg, $dsc) = @_; my ($blk, $ctl, $cur, $eob, $hdr, $lfh, $lin, $lst, $lvl, $max, $nxt, $nwl, $rec, $sct, $sum, $tbl, $tid, @lvl); # Treat the input file $ctl = $slf->{'_ctl'}; $lin = <$src> if $dsc->{'hdr'}; $eob = $lin = q{}; $slf->{'_hdr'} = $blk = $hdr = $lvl = $nxt = $rec = $sct = $tbl = $tid = 0; $nwl = $dsc->{'nwl'}; print {$dst} q{

$nwl}; while (<$src>) { # Detect if there is a continuation line s/[\r\n]*$//; $lin .= $_ unless m/^\000*$/; unless ($blk) { next if $lin =~ s/\\$//; } $lin =~ s/\s+$//; # Detect a context change if ($lvl) { # Close an open list unless ($lin =~ m/^( {3,})[\*1AaIi]./ && (length($1) % 3) == 0) { my ($typ); while ($typ = pop(@lvl)) { print {$dst} $tb_end{$typ}.$nwl; } $lvl = $nxt = 0; } } elsif ($rec) { # Close an open table unless ($lin =~ m/^\|[^\|].*\|$/) { print {$dst} qq{$nwl}; $nxt = $rec = 0; $tid = $max; } } # Treat a line if ($blk) { if ($lin eq $eob) { print {$dst} qq{$nwl} if defined(&$blk($slf, q{})); $blk = 0; } elsif (defined($lin = &$blk($slf, $lin))) { print {$dst} qq{$lin\n}; } } elsif ($lin =~ m/^\|<([^>]*)>\|$/) { unless ($rec) { ++$tbl; $sum = _clr_var($slf, $1); $sum =~ s/'/"/g; print {$dst} qq{$nwl}; $sum = undef; $lst = $max = $tid + 1; ++$rec; } } elsif ($lin =~ s/^\|([^\|].*\|)$/$1/) { my ($col, $dir, $hid, $jus, $new, $spn, $txt); unless ($rec) { ++$tbl; $sum = _clr_var($slf, $sum) if $sum; $sum = $sum ? qq{$sum Information} : qq{RDA Result Set $tbl}; $sum =~ s/'/"/g; print {$dst} qq{
$nwl}; $sum = undef; $lst = $max = $tid + 1; } print {$dst} q{}, $nwl; $new = $tid + 1; $col = $dir = 0; while ($lin =~ s/([^\|]+)(\|{1,})//) { $new = 0 if ($cur = length($2)) > 1; $txt = $1; $spn = ($cur > 1) ? qq{ colspan='$cur'} : q{}; if ($txt =~ s/^%(BOTTOM|MIDDLE|TOP|ROWS):([1-9]\d*)%//) { $spn .= qq{ rowspan='$2'} if $2 > 1; $spn .= $tb_row{$1}; } $spn .= q{ style='white-space:nowrap'} if $txt =~ s/^(\s*)%NOWRAP%/$1/; unless ($txt =~ m/^\^{3,}$/) { $jus = 0; $jus += 1 if $txt =~ s/^\s+//; $jus += 2 if $txt =~ s/\s+$//; $txt = q{ } unless length($txt); if ($txt =~ s/^\*(.+)\*$/$1/) { ++$tid; $max = $tid if $tid > $max; print {$dst} qq{}. _rpl_var($slf, $txt).qq{$nwl}; $dir = 1; } else { $hid = ($dir) ? $tid : $lst + $col; $max = $tid = $hid if $hid > $max; print {$dst} qq{}. _rpl_var($slf, $txt).qq{$nwl}; $dir = $new = 0; } } $col += $cur; } print {$dst} q{}, $nwl; $lst = $new if $new; ++$rec; } elsif ($lin eq q{}) { $nxt = 0; } elsif ($lin =~ m/^-{3,}$/) { print {$dst} q{
}, $nwl; $nxt = 0; } elsif ($lin =~ m/^-{3}(\+{1,6})(!!)?\s*(.*)$/) { my ($idn, $tag); $tag = sprintf('h%d', length($1)); if ($2) { $idn = 'Sct'.++$sct; } else { $idn = 'Hdr'.++$hdr; $slf->{'_hdr'} = $hdr if $hdr > $slf->{'_hdr'}; } print {$dst} qq{<$tag id='$idn'>}._rpl_var($slf, $3).qq{$nwl}; $sum = $3; $nxt = 0; } elsif ($lin =~ m/^-{3}(\#{1,6})\s*(.*)$/) { my $tag = sprintf('h%d', length($1)); print {$dst} qq{<$tag>}._rpl_var($slf, $2).qq{$nwl}; $nxt = 0; } elsif ($lin =~ m/^$/) { $blk = \&_rpl_enc; $eob = q{}; print {$dst} qq{
\n};
    }
    elsif ($lin eq q{
})
    { $blk = \&_rpl_none;
      $eob = q{
}; print {$dst} qq{
\n};
    }
    elsif ($lin eq q{})
    { $blk = \&_rpl_var;
      $eob = q{};
      print {$dst} qq{
\n};
    }
    elsif ($lin eq q{})
    { $blk = \&_skp_line;
      $eob = q{};
    }
    elsif ($lin =~ m/^( {3,})([\*1AaIi])\s*(.+)$/ && (length($1) % 3) == 0)
    { $cur = int(length($1) / 3);
      while ($lvl > $cur || ($lvl == $cur && $2 ne $lvl[-1]))
      { print {$dst} $tb_end{pop(@lvl)}.$nwl;
        --$lvl;
      }
      while ($lvl < $cur)
      { print {$dst} $tb_beg{$2}.$nwl;
        push(@lvl, $2);
        ++$lvl;
      }
      print {$dst} q{
  • }._rpl_var($slf, $3).$nwl; } elsif ($lin =~ m/^#(\w+)(\s(---(#{1,6})\s)?(.*))?$/) { my $txt = _rpl_var($slf, ($5 || q{})); if ($3) { my $tag = sprintf('h%d', length($4)); print {$dst} qq{<$tag>$txt$nwl}; $nxt = 0; } else { print {$dst} q{

    } unless $nxt++; print {$dst} qq{$txt$nwl}; } } elsif ($lin =~ m/^\%DATA\%$/) { print {$dst} q{

    } unless $nxt++; print {$dst} q{}.$dsc->{'dat'}.qq{$nwl} if exists($dsc->{'dat'}); } elsif ($lin =~ m/^\%TOC\%$/) { $cur = $lvl = 0; if (exists($dsc->{'toc'})) { print {$dst} qq{

    $nwl}; foreach my $itm (@{$dsc->{'toc'}}) { while ($lvl > $itm->[0]) { print {$dst} qq{$nwl}; --$lvl; } while ($lvl < $itm->[0]) { print {$dst} qq{$nwl}; --$lvl; } print {$dst} qq{
    $nwl}; } $nxt = 0; } elsif ($lin =~ m/^\%TOC(\d+)(-(\d+))?\%$/) { my ($col, $sep); $col = $1 || 1; $lvl = $3 || 1; $cur = 0; if (exists($dsc->{'toc'})) { foreach my $itm (@{$dsc->{'toc'}}) { ++$cur unless $itm->[0] > $lvl; ## no critic (Unless) } $nxt = $cur % $col; $col = int($cur / $col); print {$dst} q{
    }.$nwl. qq{
  • $nwl$SEP$nwl}; $sep = q{}; $cur = ($nxt-- > 0) ? $col + 1 : $col; foreach my $itm (@{$dsc->{'toc'}}) { next if $itm->[0] > $lvl; print {$dst} qq{$sep}. _rpl_var($slf, $itm->[2]).q{}; if (--$cur) { $sep = q{
    }; } else { $sep = qq{$nwl$SEP$nwl}; $cur = ($nxt-- > 0) ? $col + 1 : $col; } } print {$dst} qq{$nwl

    $nwl}; } $nxt = 0; } elsif ($lin =~ m/^\%INCLUDE\{"([^"]+)"\}\%$/) { print {$dst} q{

    } unless $nxt++; if ($lfh = $ctl->open_file(RDA::Object::Rda->is_absolute($1) ? $1 : RDA::Object::Rda->cat_file($slf->{'_dir'}, $1), 1)) { while (<$lfh>) { print {$dst} _rpl_var($slf, $_); } $lfh->close; } } elsif ($lin =~ m/^\%PRE\{"([^"]+)"\}\%$/) { if ($lfh = $ctl->open_file(RDA::Object::Rda->is_absolute($1) ? $1 : RDA::Object::Rda->cat_file($slf->{'_dir'}, $1), 1)) { print {$dst} qq{

    $nwl};
            while (<$lfh>)
            { print {$dst} _rpl_none($slf, $_);
            }
            print {$dst} qq{
    $nwl}; $lfh->close; } } elsif ($lin =~ m/^\%VERBATIM\{"([^"]+)"\}\%$/) { if ($lfh = $ctl->open_file(RDA::Object::Rda->is_absolute($1) ? $1 : RDA::Object::Rda->cat_file($slf->{'_dir'}, $1), 1)) { print {$dst} qq{
    $nwl};
            while (<$lfh>)
            { print {$dst} _rpl_enc($slf, $_);
            }
            $lfh->close;
            print {$dst} qq{
    $nwl}; } } elsif ($lin =~ m/^$/) { print {$dst} q{

    } unless $nxt++; print {$dst} $lin.$nwl; } elsif ($lin !~ m/^<\?.*\?>$/) { print {$dst} q{

    } unless $nxt++; print {$dst} _rpl_var($slf, $lin).$nwl; } $lin = q{}; } # Terminate and close the HTML file if ($lvl) # Open list { my ($typ); while ($typ = pop(@lvl)) { print {$dst} $tb_end{$typ}.$nwl; } } elsif ($rec) # Open table { print {$dst} qq{$nwl}; } elsif ($blk) # Open block { print {$dst} qq{$nwl}; } print {$dst} q{}; return; } # Generate the table of content sub _gen_toc { my ($slf, $src, $toc, $def) = @_; my ($blk, $hdr, $ifh, $lin); $blk = undef; $hdr = 0; $ifh = $slf->{'_ctl'}->open_file($src); $lin = q{}; while (<$ifh>) { # Detect if there is a continuation line s/[\r\n]*$//; $lin .= $_ unless m/^\000*$/; next if $lin =~ s/\\$//; $lin =~ s/\s+$//; # Minimal parsing to get the heading lines if ($blk) { $blk = undef if $lin eq $blk; } elsif ($lin =~ m/^-{3}(\+{1,6})(!!)?\s*(.*)$/) { push(@{$toc}, [length($1), ++$hdr, _clr_var($slf, $3, 1)]) unless $2; } elsif ($lin =~ m/^<\?\s*(\w+):(.*?)\s*\?>$/) { $def->{lc($1)} = $2; } elsif ($lin =~ m/^$/) { $blk = q{}; } elsif ($lin eq q{

    })
        { $blk = q{
    }; } elsif ($lin eq q{}) { $blk = q{}; } $lin = q{}; } $ifh->close; return; } # Generate the use tracker sub _gen_tracker { my ($slf, $ofh, $nam) = @_; my ($agt, $ifh, $str, $url, %tbl); # Identify tracking needs of first use unless (exists($slf->{'_trk'})) { $slf->{'_trk'} = undef; $ifh = IO::File->new; $ifh->open(q{<}.$slf->{'_cfg'}->get_file('D_RDA_DAT', 'track.txt')) or return;; $agt = $slf->{'_agt'}; $str = q{}; $str .= $_ while <$ifh>; $ifh->close; return unless $str =~ m{} && defined($url = $agt->get_env('TRACK_URL')) && $url =~ m{^https?://([\w\-]+(\.[\w\-]+)*):(\d+)(/[\w+\.\-]+)+$} && defined($agt->get_system->is_host($1, 1)) && defined($agt->get_system->is_port($3, 1)) && $str =~ s//$url/g; $slf->{'_trk'} = $str; } # Add use tracking details when appropriate if (defined($str = $slf->{'_trk'})) { $tbl{$1} = $2 while $nam =~ s/^([a-z]+)="([^"]*)",?//; return unless exists($tbl{'id'}); $str =~ s/<([a-z]+)>/exists($tbl{$1}) ? $tbl{$1} : q{}/eg; print {$ofh} $str; } return; } # Remove variables and other enhancements sub _clr_var { my ($slf, $str, $flg) = @_; $str =~ s{\%COL\d+\%}{ }g; $str =~ s{\%(?:ACRONYM|R):(\w+)\%}{$1}g; $str =~ s{\%(BR|(END)?LIST|NEXT|(END)?SEQ)\%}{ }g; $str =~ s{\%ID(:\w+)*\%}{}g; $str =~ s{\%(BLUE|RED)\%}{}g; $str =~ s{\%ENDCOL(OR)?\%}{}g; $str =~ s{\%HDR\%}{ }g; $str =~ s{\%MOS_([A-Z]+):([\.\w]+)\%}{_rpl_mos($slf, $1, $2)}eg; $str =~ s{\%MRC:(\w+\.)*\w+\%}{}gi; $str =~ s{\%NA\%}{Not applicable}g; $str =~ s{\%NONE\%}{None}g; $str =~ s{\%NULL\%}{Null value}g; $str =~ s{\%NV\%}{No value}g; $str =~ s{\%VERSION\%}{$slf->{'_ver'}}g; $str =~ s{\}{}g; $str =~ s{\*\*(.*?)\*\*}{$1}g; $str =~ s{\'\'(.*?)\'\'}{$1}g; $str =~ s{\`\`(.*?)\`\`}{$1}g unless $flg; $str =~ s{\^\^(.*?)\^\^}{$1}g unless $flg; $str =~ s{\{\{[^\|\}]+?\}\}}{}g; $str =~ s{\{\{.+?\|(.*?)\}\}}{[$2]}g; $str =~ s{\[\[([^\[\]]+)\]\[([^\[\]]+)\]\[(.+?)\]\]}{$3}g; $str =~ s{\[\[([^\[\]]+)\]\[(.+?)\]\]}{$2}g; $str =~ s{\s+}{ }g; $str =~ s{([\042\045\047\050\051\053\055\074\076])} {sprintf("&#x%X;", ord($1))}ge; return $str; } # Convert a column sub _cnv_col { my ($slf, $str, $ctl) = @_; my ($col, $cur, $nxt, @col, @tbl); $col = $ctl->{'num'}; $str =~ s/\%NEXT\%/\%BR\%/g; $cur = scalar(@tbl = split(/\%BR\%/, $str, -1)); $nxt = $cur % $col; $col = int($cur / $col); while (scalar @tbl) { $cur = ($nxt-- > 0) ? $col + 1 : $col; push(@col, join('
    ', splice(@tbl, 0, $cur))); } return qq{} .join(qq{$SEP}, @col).q{
    }; } # Convert a Java Stack Match form sub _cnv_jsm { my ($slf, $str) = @_; my ($act, @tbl); return (defined($act = _get_jsm_url($slf)) && (@tbl = split(/%BR%/, $str))) ? q{
    } : q{}; } sub _get_jsm_url { my ($slf) = @_; my ($agt, $url); return $slf->{'_jsm'} if exists($slf->{'_jsm'}); $agt = $slf->{'_agt'}; if (defined($url = $agt->get_env('JSM_URL'))) { $url = undef unless $url =~ m{^https?://([\w\-]+(\.[\w\-]+)*):(\d+)(/[\w+\.]+)+$} && defined($agt->get_system->is_host($1, 1)) && defined($agt->get_system->is_port($3, 1)); } return $slf->{'_jsm'} = $url; } # Convert a knowledge management search sub _cnv_kms { my ($slf, $str, $ctl) = @_; my ($src, $txt, @tbl); return q{} unless (@tbl = grep {length($_)} split(/%NEXT%/, $str)); $src = $txt = ($ctl->{'src'} =~ m/^(\w+(,\w+)*)$/) ? $1 : 'ALLSOURCES'; $txt =~ s{,}{, }g; $txt = get_string('MosSearch', q{}.join(q{, }, @tbl).q{}, q{}.$txt.q{}); $str = join(q{%20}, map {_cnv_term(_clr_var($slf, $_))} @tbl); return q{$txt}; } sub _cnv_term { my ($str) = @_; $str =~ s{([^\041-\176])}{sprintf('%%%02x', ord($1))}eg; return q{%2522}.$str.q{%2522}; } # Convert a list sub _cnv_list { my ($slf, $str) = @_; return ($str =~ m{^\s*$}) ? $str : q{
    • } .join(q{
    • }, map {_rpl_ref($slf, $_)} split(/\%NEXT\%/, $str, -1)) .q{
    }; } # Convert a sequence sub _cnv_seq { my ($slf, $str) = @_; return ($str =~ m{^\s*$}) ? $str : q{
    1. } .join(q{
    2. }, map {_rpl_ref($slf, $_)} split(/\%NEXT\%/, $str, -1)) .q{
    }; } # Convert a table sub _cnv_tbl { my ($slf, $str, $ctl) = @_; my ($buf, @row); $str =~ s/\%ID(:\w+)*\%//; return q{} unless (@row = split(/\%BR\%/, $str, -1)); $buf = qq{}; foreach my $row (@row) { $buf .= "" .join(q{}, map {_cnv_cell($slf, $_)} split(/\%NEXT\%/, $row, -1)) .q{}; } return $buf.q{
    }; } sub _cnv_cell { my ($slf, $txt) = @_; my ($jus); $jus = 0; $jus += 1 if $txt =~ s/^\s+//; $jus += 2 if $txt =~ s/\s+$//; return q{}._rpl_ref($slf, $txt).q{}; } # Convert a text sub _cnv_text { return _rpl_ref(@_); } # Convert a tree sub _cnv_tree { my ($slf, $ctl) = @_; foreach my $itm (@{$ctl->{'det'}}) { $itm->{'txt'} = _cnv_tree($slf, $itm) unless $itm->{'typ'} eq 'F'; } return &{$tb_cnv{$ctl->{'typ'}}}($slf, join(q{}, map {$_->{'txt'}} @{$ctl->{'det'}}), $ctl); } # Parse a string sub _prs_tree { my ($tbl, $ctl) = @_; my ($itm); while (defined($itm = shift(@{$tbl}))) { next if $itm eq q{}; return $ctl if exists($ctl->{'end'}) && $itm eq $ctl->{'end'}; if ($itm =~ m{^\%COL(\d*)\%$}) { push(@{$ctl->{'det'}}, _prs_tree($tbl, {typ => 'C', det => [], end => '%ENDCOL%', num => $1 || 1})); } elsif ($itm eq '%JSM%') { push(@{$ctl->{'det'}}, _prs_tree($tbl, {typ => 'J', det => [], end => '%ENDJSM%'})); } elsif ($itm =~ m{^\%KMS(\:(.*))?\%$}) { push(@{$ctl->{'det'}}, _prs_tree($tbl, {typ => 'K', det => [], end => '%ENDKMS%', src => $2 || 'ALLSOURCES'})); } elsif ($itm eq '%LIST%') { push(@{$ctl->{'det'}}, _prs_tree($tbl, {typ => 'L', det => [], end => '%ENDLIST%'})); } elsif ($itm eq '%SEQ%') { push(@{$ctl->{'det'}}, _prs_tree($tbl, {typ => 'S', det => [], end => '%ENDSEQ%'})); } elsif ($itm eq '%TBL%') { push(@{$ctl->{'det'}}, _prs_tree($tbl, {typ => 'T', det => [], end => '%ENDTBL%'})); } elsif ($itm !~ m{^\%END(?:COL|FND|FRM|LIST|SEQ|TBL)\%$}) { push(@{$ctl->{'det'}}, {typ => 'F', txt => $itm}); } } return $ctl; } # Treat an acronym sub _rpl_acr { my ($slf, $nam) = @_; return exists($slf->{'_acr'}->{$nam}) ? q{{$nam}.q{'>}.$nam.q{} : $nam; } # Encode some characters sub _rpl_enc { my ($slf, $str) = @_; $str =~ s{([\042\046\047\050\051\053\055\074\076])} {sprintf('&#x%X;', ord($1))}ge; $str =~ s{\%R:(\w+)\%}{_rpl_rdr($slf, $1)}eg; $str =~ s{\045}{%}g; return $str; } # Replace multi-run collection variales sub _rpl_mrc { my ($slf, $mod) = @_; return $slf->{'_col'}->get_sub( $slf->{'_col'}->get_first("STATUS.$mod.B_MRC", 0) ? 'M' : 'C').q{/}; } # No replacement sub _rpl_none { my ($slf, $str) = @_; $str =~ s{\%R:(\w+)\%}{_rpl_rdr($slf, $1)}eg; return $str; } # Replace My Oracle Support variables sub _rpl_mos { my ($slf, $var, $val, $flg) = @_; return exists($tb_mos{$var}) ? get_string($tb_mos{$var}->[0], $flg ? q{[[}.sprintf($tb_mos{$var}->[1], _clr_var($slf, $val)). q{][_blank][}.$val.q{]]} : $val) : get_string('Mos', $val); } # Replace render variables sub _rpl_rdr { my ($slf, $var) = @_; $var = $slf->{'_var'}->{$var} if exists($slf->{'_var'}->{$var}); return qq{<$var>}; } # Replace references sub _rpl_ref { my ($slf, $str) = @_; my ($blk); $blk = '([^\[\]]+)'; $str =~ s{\%ACRONYM:(\w+)\%}{_rpl_acr($slf, $1)}eg; $str =~ s{\%BR\%}{
    }g; $str =~ s{\%ID(:\w+)*\%}{}g; $str =~ s{\%RED\%}{}g; $str =~ s{\%BLUE\%}{}g; $str =~ s{\%ENDCOLOR\%}{}g; $str =~ s{\%R:(\w+)\%}{_rpl_rdr($slf, $1)}eg; $str =~ s{\%MRC:((\w+\.)*\w+)\%}{_rpl_mrc($slf, $1)}egi; $str =~ s{\%MOS_([A-Z]+):([\.\w]+)\%}{_rpl_mos($slf, $1, $2, 1)}eg; $str =~ s{\%NA\%}{Not applicable}g; $str =~ s{\%NONE\%}{None}g; $str =~ s{\%NULL\%}{Null value}g; $str =~ s{\%NV\%}{No value}g; $str =~ s{\{\{([^\|\}]+?)\}\}}{}g; $str =~ s{\{\{(.+?)\|(.*?)\}\}}{$2}g; $str =~ s{\[\[$blk\]\[$blk\]\[(.+?)\]\]}{$3}g; $str =~ s{\[\[$blk\]\[(.+?)\]\]}{$2}g; return $str; } # Replace variables sub _rpl_var { my ($slf, $str) = @_; my (@tbl); $str =~ s{([\042\050\051\053\055\074\076])} {sprintf("&#x%X;", ord($1))}ge; while ($str =~ m{\%HDR\%}) { ++$slf->{'_hdr'}; $str =~ s{\%HDR\%}{Hdr$slf->{'_hdr'}}; } $str =~ s{\*\*(.*?)\*\*}{$1}g; $str =~ s{}{}g; $str =~ s{}{}g; $str =~ s{\'\'(.*?)\'\'}{$1}g; $str =~ s{}{}g; $str =~ s{}{}g; $str =~ s{\`\`(.*?)\`\`}{$1}g; $str =~ s{\^\^(.*?)\^\^}{''._cnv_spc($1).''}eg; $str =~ s{
    }{}g; $str =~ s{}{}g; $str =~ s{\'}{'}g; $str =~ s{\%VERSION\%}{$slf->{'_ver'}}g; # Parse the string and convert the resulting tree @tbl = split(/($CMD)/, $str); $str = _cnv_tree($slf, _prs_tree(\@tbl, {typ => 'F', det => []})); $str =~ s{
  • ()+}{
  • }g; $str =~ s{
  • }{}g; $str =~ s{\%}{%}g; return $str; } sub _cnv_tab { my ($str) = @_; my ($off, $tmp, @lin); $str =~ s/ / /g; foreach my $lin (split(/%BR%/, $str, -1)) { while (($off = index($lin, "\011")) >= 0) { $tmp = substr($lin, 0, $off); $tmp =~ s/&(\w+|#(.*?));/./g; substr($lin, $off, 1) = q{ } x (8 - (length($tmp) % 8)); } push(@lin, $lin); } return join('%BR%', @lin); } sub _cnv_spc { my ($str) = @_; $str = _cnv_tab($str) if $str =~ m/\011/; $str =~ s/ / /g; return $str; } # Skip a line sub _skp_line { return; } =head2 S<$h-Egen_index([$index,$report,$flag])> This method generates the index file and the start file. When the flag is set, it recreates the Cascading Style Sheet file. =cut sub gen_index { my ($slf, $sub, $rpt, $flg) = @_; my ($bot, $cas, $ctl, $dat, $dir, $fct, $idx, $ifh, $lst, $sta, $str, $top, @all, @toc, %toc); # Initialization $cas = $slf->{'_cas'}; $ctl = $slf->{'_ctl'}; $dat = $slf->{'_cfg'}->get_group('D_RDA_DAT'); $dir = $slf->{'_dir'}; $sta = $slf->{'_col'}->get_info('sta'); # Get the report list return unless (@all = $ctl->scan_dir); # Generate the stylesheet generation as appropriate $slf->gen_css($flg); # Delete the old global index files _del_files($dir, \@all, qr/^(RDA__(blank|index|start)\.(htm|txt))$/i); # Sort the table of content files foreach my $fil (@all) { $toc{$fil} = _get_seq($slf, $sta, uc($1), $2) if $fil =~ m/^([A-Z][A-Z\d]*)_([A-Z][A-Z\d]*)_T\.toc$/i; } return unless ## no critic (Unless) (@toc = sort {$toc{$a} <=> $toc{$b} || $a cmp $b} keys(%toc)); # Create the index specifications file $idx = 'RDA__index.txt'; $fct = \&_cat_split; $ifh = $ctl->create_file(RDA::Object::Rda->cat_file($dir, $idx), 'ERR_INDEX'); # Insert the index top _cat_index($ifh, RDA::Object::Rda->cat_file($dat, 'rdamtop.txt')); # Insert the module contributions $lst = q{}; $top = RDA::Object::Rda->cat_file($dat, 'rdastop.txt'); $bot = RDA::Object::Rda->cat_file($dat, 'rdasbot.txt'); foreach my $toc (@toc) { # Delete the old index files $str = substr($toc, 0, -4); _del_files($dir, \@all, qr/^($str\d*\.(htm|txt))$/i); # Generate the new index $toc = lc($toc) unless $cas; $lst = &$fct($slf, $ifh, $toc, $lst, $top, $bot); } # Insert the index bottom _cat_index($ifh, RDA::Object::Rda->cat_file($dat, 'rdambot.txt')); # Render the index file close($ifh); $slf->gen_html($idx, 'RDA Report Index', 0, 1); # Generate the start file return $slf->gen_start( defined($sub) ? $sub : $toc[0], defined($rpt) ? $rpt : $ctl->get_default); } sub _cat_index { my ($ofh, $fil) = @_; my ($ifh); $ifh = IO::File->new; if ($ifh->open(q{<}.$fil)) { while (<$ifh>) { if (s/^(\d+):// && $1 > 0) { print {$ofh} q{ }x$1.'* '.$_; } elsif (!m/^#/) { print {$ofh} $_; } } $ifh->close; } return; } sub _cat_single ## no critic (Complex,Unused) { my ($slf, $ofh, $toc, $lst) = @_; my ($ctl, $dir, $lin, $lvl, $min, $off, $tfh, @stk, @toc, @ttl); $ctl = $slf->{'_ctl'}; $dir = $slf->{'_dir'}; $off = 0; $min = 1; if ($tfh = $ctl->open_file(RDA::Object::Rda->cat_file($dir, $toc), 1)) { # Load all specifications @toc = <$tfh>; $tfh->close; # Convert the module table contents in format specifications while (defined($lin = shift(@toc))) { $lin =~ s/[\r\n]+$//; if ($lin =~ m/^(\^?)(\d+)\+*:(.*)$/ && $2 > 0) { $lvl = $2 - $off; if ($3 eq $lst || $1 || $lvl < $min) { $lst = q{}; } elsif (@ttl) { unshift (@toc, splice(@ttl), $lin); } else { print {$ofh} q{ }x$lvl."* $3\n"; $lst = q{}; } } elsif ($lin =~ s/^\-://) { $lst = $lin; } elsif ($lin =~ m/^\%FOCUS(\-?\d+)?(:([1-9]\d*))?\%\s*$/) { $off = defined($1) ? $1 : 0; $min = defined($3) ? $3 : 1; } elsif ($lin =~ m/^\%INCLUDE\("([^"]+)"(,(\d+))?\)\%$/) { my ($lfh, $str); if ($lfh = $ctl->open_file(RDA::Object::Rda->is_absolute($1) ? $1 : RDA::Object::Rda->cat_file($dir, $1), 1)) { if ($2 && $3 > 0) { $str = q{+} x $3; unshift (@toc, splice(@ttl), splice(@stk), map {_indent_top($_, $str)} ); } else { unshift (@toc, splice(@ttl), splice(@stk), ); } $lfh->close; } } elsif ($lin =~ m/^\%(LEVEL([1-9])|SPLIT)\%\s*$/) { } elsif ($lin =~ m/^\%POP(\d+)?\%\s*$/) { my $val = defined($1) ? $1 : 1; pop(@stk) while $val-- > 0; } elsif ($lin =~ m/^\%PUSH\("([^"]+)"\)\%\s*$/) { push(@stk, $1); } elsif ($lin =~ m/^\%TITLE\("([^"]+)"\)\%\s*$/) { push(@ttl, $1); } elsif ($lin =~ m/^\%UNTITLE(\d+)?\%\s*$/) { my $val = defined($1) ? $1 : 1; pop(@ttl) while $val-- > 0; } elsif ($lin !~ m/^#---\[.*\]---$/) { if (@ttl) { unshift (@toc, splice(@ttl), $lin); } else { print {$ofh} "$lin\n"; } } } } return $lst; } sub _cat_split ## no critic (Complex) { my ($slf, $ofh, $toc, $lst, $top, $bot) = @_; my ($bas, $cnt, $ctl, $dir, $lim, $lin, $min, $off, $sfh, $spl, $tfh, @stk, @toc, @ttl); $ctl = $slf->{'_ctl'}; $dir = $slf->{'_dir'}; $off = 0; $min = 1; if ($tfh = $ctl->open_file(RDA::Object::Rda->cat_file($dir, $toc), 1)) { # Load all specifications @toc = <$tfh>; $tfh->close; # Create the subindex file and insert subindex top $toc =~ s/\.toc$//i; $sfh = $ctl->create_file( RDA::Object::Rda->cat_file($dir, "$toc.txt"), 'ERR_SUB_INDEX'); _cat_index($sfh, $top); # Split the module table of content $bas = $toc; $spl = $cnt = 0; $lim = 1; while (defined($lin = shift(@toc))) { $lin =~ s/[\r\n]+$//; if ($lin =~ m/^(\^?)(\d+)(\+*):(.*)$/) { my ($dsc, $flg, $idx, $lvl, $str, $txt); ($flg, $lvl, $str, $txt) = ($1, $2, $3, $4); if ($txt eq $lst) { $lst = q{}; } elsif ($lvl && ($lvl -= $off) < $min) { $lst = q{}; } elsif (@ttl) { unshift (@toc, splice(@ttl), $lin); } elsif ($lvl > $lim) { print {$sfh} q{ }x($lvl - $lim)."* $txt\n" unless $flg; $lst = q{}; } elsif ($lvl == $lim) { $dsc = ($txt =~ m/\[\[([^\[\]]*\]\[){1,2}(.*?)\]\]/) ? $2 : $txt; $lvl += length($str); if ($flg) { print {$ofh} q{ }x$lvl."* $dsc\n"; } else { if ($cnt++) { $idx = "#Idx$cnt"; print {$sfh} "$idx\n"; } else { $idx = q{}; } print {$sfh} qq{---+ $txt\n}; print {$ofh} q{ }x$lvl. qq{* [[$toc.htm$idx][rda_sub_index][$dsc]]\n}; } $lst = q{}; } elsif ($lvl > 0) { print {$ofh} q{ }x($lvl + length($str)).qq{* $txt\n}; $lst = q{}; } else { print {$ofh} "$txt\n"; } } elsif ($lin =~ s/^\-://) { $lst = $lin; } elsif ($lin =~ m/^\%FOCUS(\-?\d+)?(:([1-9]\d*))?\%\s*$/) { $off = defined($1) ? $1 : 0; $min = defined($3) ? $3 : 1; } elsif ($lin =~ m/^\%INCLUDE\("([^"]+)"(,(\d+))?\)\%$/) { my ($lfh, $str); if ($lfh = $ctl->open_file(RDA::Object::Rda->is_absolute($1) ? $1 : RDA::Object::Rda->cat_file($dir, $1), 1)) { if ($2 && $3 > 0) { $str = q{+} x $3; unshift (@toc, splice(@ttl), splice(@stk), map {_indent_top($_, $str)} <$lfh>); } else { unshift (@toc, splice(@ttl), splice(@stk), <$lfh>); } $lfh->close; } } elsif ($lin =~ m/^\%LEVEL([1-9])\%\s*$/) { $lim = $1; } elsif ($lin =~ m/^\%POP(\d+)?\%\s*$/) { my $val = defined($1) ? $1 : 1; pop(@stk) while $val-- > 0; } elsif ($lin =~ m/^\%PUSH\("([^"]+)"\)\%\s*$/) { push(@stk, $1); } elsif ($lin =~ m/^\%SPLIT\%\s*$/) { # Insert the subindex bottom and render the subindex file _cat_index($sfh, $bot); close($sfh); $slf->gen_html("$toc.txt", "$toc Sub Index", 0, 1); # Create the next subindex file and insert subindex top $cnt = 0; $toc = sprintf('%s_%02d', $bas, ++$spl); $sfh = $ctl->create_file( RDA::Object::Rda->cat_file($dir, "$toc.txt"), 'ERR_SUB_INDEX'); _cat_index($sfh, $top); } elsif ($lin =~ m/^\%TITLE\("([^"]+)"\)\%\s*$/) { push(@ttl, $1); } elsif ($lin =~ m/^\%UNTITLE(\d+)?\%\s*$/) { my $val = defined($1) ? $1 : 1; pop(@ttl) while $val-- > 0; } elsif ($lin !~ m/^#---\[.*\]---$/) { if (@ttl) { unshift (@toc, splice(@ttl), $lin); } else { print {$sfh} "$lin\n"; } } } # Insert the subindex bottom and render the subindex file _cat_index($sfh, $bot); close($sfh); $slf->gen_html("$toc.txt", "$toc Sub Index", 0, 1); } return $lst; } sub _del_files { my ($rpt, $tbl, $re) = @_; my ($pth); foreach my $nam (@{$tbl}) { next unless $nam =~ $re; $pth = RDA::Object::Rda->cat_file($rpt, $1); 1 while unlink($pth); } return; } sub _get_seq { my ($slf, $sta, $grp, $mod) = @_; my ($seq); return $seq if defined($seq = $sta->get_first(["$grp.$mod.R_RUN","$grp.$mod.R_CFG"])); ($seq) = $slf->{'_cnt'}->get_sequence('DC', $grp.':DC'.lc($mod)); return ($seq =~ m/^(E)?(\d{3})?$/) ? $slf->{'_col'}->load_group($grp)->get_first($1 ? ['N_END', 'N_RUN'] : 'N_RUN', 500) + "0.$2" ## no critic (Mismatch) : 500.5; ## no critic (Number) } sub _indent_top { my ($lin, $str) = @_; $lin =~ s/^(1\+*):/$1$str:/; return $lin; } =head2 S<$h-Egen_start([$sub[,$nam]])> This method generates the start page. You can specify the default sub-index page and report name as arguments. =cut sub gen_start { my ($slf, $sub, $nam) = @_; my ($ctl, $dir, $flg, $idx, $ofh, $rpt, $ver); # Initialization $ctl = $slf->{'_ctl'}; $flg = $slf->{'_cas'}; $ver = $slf->{'_ver'}; $ver .= " ($rpt)" if ($rpt = $slf->{'_cfg'}->get_host) && !$slf->{'_col'}->get_first('FILTER.B_ENABLED'); $dir = $slf->{'_dir'}; $nam = $slf->{'_rpt'} unless defined($nam); $rpt = 'RDA__blank.htm' unless $ctl->is_available( RDA::Object::Rda->cat_file($dir, $rpt = $nam)) || $ctl->is_available( RDA::Object::Rda->cat_file($dir, $rpt = "collect/$nam")) || $ctl->is_available( RDA::Object::Rda->cat_file($dir, $rpt = "mrc/$nam")); $idx = 'RDA__index.htm'; if (defined($sub)) { $sub =~ s/\.(toc|txt)$/.htm/i; } else { $sub = 'RDA__blank.htm'; } unless ($flg) { $idx = lc($idx); $rpt = lc($rpt); $sub = lc($sub); } # Generate the frameset file ## no critic (Long,Newline) $ofh = $ctl->create_file( RDA::Object::Rda->cat_file($dir, 'RDA__start.htm'), 'ERR_START'); print {$ofh} qq{ Remote Diagnostic Agent $ver This page requires a frames capable browser to view. }; $ofh->close; # Generate the blank page $ofh = $ctl->create_file( RDA::Object::Rda->cat_file($dir, 'RDA__blank.htm'), 'ERR_BLANK'); print {$ofh} qq{ Remote Diagnostic Agent $ver }; return $ofh->close; } =head2 S<$h-Eget_reports($flg)> This method retrieves all related reports that must be rendered. When the flag is set, it returns all related reports. =cut sub get_reports { my ($slf, $flg) = @_; my ($dir, $pat, $sub, @tbl); # Initialization $dir = defined($sub = $slf->{'_col'}->get_sub('C')) ? RDA::Object::Rda->cat_dir($slf->{'_dir'}, $sub) : $slf->{'_dir'}; $pat = qr/^([A-Za-z]\w*(-\d+)?\.(dat|txt))$/i; # Scan the directory for report files if (opendir(DIR, $dir)) { foreach my $fil (readdir(DIR)) { push(@tbl, $1) if $fil =~ $pat && ($flg || _chk_report($dir, $fil)); } closedir(DIR); } # Return the files found return (map {RDA::Object::Rda->cat_file($sub, $_)} @tbl); } # Compare the modification times sub _chk_report { my ($dir, $fil) = @_; my ($dmt, $pth, $smt, @sta); @sta = stat($pth = RDA::Object::Rda->cat_file($dir, $fil)); $smt = $sta[9]; $pth =~ s/\.(dat|txt)$/.htm/i; @sta = stat($pth); $dmt = $sta[9]; return ($smt && $dmt && $smt <= $dmt) ? 0 : 1; } =head1 DEFAULT INPUT/OUTPUT CONTROL INTERFACE =head2 S<$h-Echeck_free($ofh)> This method checks whether there is enough free space. =cut sub check_free { my ($slf, $ofh) = @_; my (@sta); $slf->{'_col'}->get_output->check_free(3 * $sta[7]) if (@sta = stat($ofh)); return; } =head2 S<$h-Ecopy_file($src,$dst)> This method copies a file. =cut sub copy_file { my ($slf, $src, $dst) = @_; my ($stk); return copy($src, $dst) && chmod($FIL_PERMS, $dst) && $slf->{'_own'} && ref($stk = $slf->{'_agt'}->should_align) && push(@{$stk}, $dst); } =head2 S<$h-Ecreate_file($pth)> This method creates the specified file. =cut sub create_file { my ($slf, $pth, $err) = @_; my ($ofh, $stk); $ofh = IO::File->new; $ofh->open($pth, $CREATE, $FIL_PERMS) or die get_string($err, $pth, $!); # Text:ERR_BLANK # Text:ERR_INDEX # Text:ERR_REPORT # Text:ERR_START # Text:ERR_SUB_INDEX push(@{$stk}, $pth) if $slf->{'_own'} && ref($stk = $slf->{'_agt'}->should_align); binmode($ofh); return $ofh; } =head2 S<$h-Edelete_file($pth)> This method deletes the specified file. =cut sub delete_file { my ($slf, $pth) = @_; 1 while unlink($pth); return; } =head2 S<$h-Eget_default> This method indicates which is the default report to display. =cut sub get_default { return shift->{'_col'}->get_first('RENDER.T_REPORT'); } =head2 S<$h-Eis_available($pth)> This method indicates whether the corresponding file exists. =cut sub is_available { my ($slf, $pth) = @_; return -e $pth; } =head2 S<$h-Eopen_file($pth[,$flg])> This method opens the specified file. When the flag is set, it returns an undefined value instead of generating an error. =cut sub open_file { my ($slf, $pth, $flg) = @_; my ($ifh); $ifh = IO::File->new; return $ifh->open(q{<}.$pth) ? $ifh : $flg ? undef : die get_string('ERR_OPEN', $pth, $!); } =head2 S<$h-Escan_dir> This method scans the result directory. =cut sub scan_dir { my ($slf) = @_; my (@all); if ( -d $slf->{'_dir'}) { opendir(DIR, $slf->{'_dir'}) or die get_string('ERR_SCAN', $!); @all = grep {!m/^RDA.log/i} readdir(DIR); closedir(DIR); } return @all; } 1; __END__ =head1 SEE ALSO 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