| Tripletail documentation | Contained in the Tripletail distribution. |
Tripletail::Error - 内部クラス
Tripletail によって内部的及び fault_handler で使用される。
messageエラーメッセージ。($@)
title短い説明。
省略時は "Error: $message";
typeエラー情報の種別。
error'実行時エラーに関する情報。
warn'警告に関する情報。
file-update'スクリプト等の更新検出。
memory-leak'メモリ制限。
toHtmlHTML化。
is_trace_allowed内部メソッド
Copyright 2006 YMIRLINK Inc.
This framework is free software; you can redistribute it and/or modify it under the same terms as Perl itself
このフレームワークはフリーソフトウェアです。あなたは Perl と同じライセンスの 元で再配布及び変更を行うことが出来ます。
Address bug reports and comments to: tl@tripletail.jp
HP : http://tripletail.jp/
| Tripletail documentation | Contained in the Tripletail distribution. |
# ----------------------------------------------------------------------------- # Tripletail::Error - å é¨ã¯ã©ã¹ # ----------------------------------------------------------------------------- package Tripletail::Error; use strict; use warnings; use Data::Dumper; #use Smart::Comments; use Tripletail; use overload '""' => \&_stringify, fallback => 1; sub _POST_REQUEST_HOOK_PRIORITY() { 2_000_000_000 } # Debug ãããå¾ my $PADWALKER_AVAILABLE; # PadWalker ãå©ç¨å¯è½ã§ãããã©ãããundef / 1 / 0 my $VARIABLE_LENGTH_LIMIT = 32 * 1024; # 1夿°ãããã®è¡¨ç¤ºããæå¤§é· (ãã¤ã) my $DEFAULT_ERROR_TEMPLATE = &__load_default_error_template(); my $TRACE_ALLOWANCE_OF_CURRENT_REQUEST; 1; # ----------------------------------------------------------------------------- # $TL->newError($type, $msg); # $TL->newError($type, $msg, $title); # sub _new { # ã¹ã¿ãã¯ãã¬ã¼ã¹ãæã£ãä¾å¤ãªãã¸ã§ã¯ããçæããã # è¿ãããã¤ã³ã¹ã¿ã³ã¹ã¯ "" æ¼ç®åã«ãã£ã¦æåååãå¯è½ã§ããã my $class = shift; my $type = shift; # 'error' / 'warn' / 'file-update' / 'memory-leak' my $msg = shift; # $@ my $title = shift; # ä»»æã®æåå my $this = bless {} => $class; $this->{message} = $msg; $this->{type} = $type; $this->{title} = $title || "Error: $msg"; $this->{frames} = []; # Tripletail::Error::Frame $this->{source} = {}; # ãã¡ã¤ã«ãã¹ => ä¸èº« $this->{show_trace} = undef; $this->{show_vars} = undef; $this->{show_src} = undef; $this->{suppress_internal} = 1; $this->{appear} = 'sudden'; # sudden/usertrap $this->{on_require} = undef; # undef/1. $this->{http_status_code} = undef; $this->{http_status_line} = undef; $this->{db_error} = undef; if( $msg =~ /: we are getting too large (file|request) which exceeds the limit. |: Post Error: request size was too big to accept. / ) { $this->{http_status_code} = 413; $this->{http_status_line} = "413 Request Entity Too Large"; }else { $this->{http_status_code} = 500; $this->{http_status_line} = "500 Internal Server Error"; } my $switch = $TL->INI->get(TL => 'stacktrace', 'onlystack'); if ($switch eq 'none') { # skip } elsif ($switch eq 'onlystack') { $this->{show_trace} = 1; } elsif ($switch eq 'full') { $this->{show_trace} = 1; $this->{show_vars} = 1; $this->{show_src} = 1; } else { die "Unknown stacktrace type: $switch (stacktraceã®æå®ã䏿£ã§ã)"; } if ($this->{show_trace} and not $this->is_trace_allowed) { $this->{show_trace} = undef; } if ($this->{show_trace}) { # TLã®dieãã³ãã©ããå¼ã°ããããç¥ããªãã®ã§ãç¡éå帰ãé²ãã local $SIG{__DIE__} = 'DEFAULT'; local($@); eval { $this->_fetch_frames; }; if ($@) { print STDERR $@; exit 1; } } if( our $LAST_DBH ) { for( my $i=0; my @c=caller($i); ++$i ) { my $sub = $c[3]; $sub =~ /^DB[ID]::|^Tripletail::DB::/ or next; my ($type, $dbh); if( UNIVERSAL::isa($LAST_DBH, 'ARRAY') ) { ($type, $dbh) = @$LAST_DBH; }else { $type = $LAST_DBH->getType(); $dbh = $LAST_DBH->getDbh(); } if( $type eq 'error' ) { $this->{db_error} = $dbh; }else { $this->{db_error} = Tripletail::DB->_errinfo($dbh, $type); } last; } } $TL->setHook( 'postRequest', _POST_REQUEST_HOOK_PRIORITY, sub { $TRACE_ALLOWANCE_OF_CURRENT_REQUEST = undef; }); $this; } sub type { shift->{type}; } sub title { shift->{title}; } sub message { my $this = shift; my $new = shift; if ($new) { $this->{message} = $new; } $this->{message}; } sub _fetch_frames { my $this = shift; if (not defined $PADWALKER_AVAILABLE) { eval { require PadWalker; }; $PADWALKER_AVAILABLE = ($@ ? 0 : 1); } my $found_die_handler; my $level = 0; my $pad_level = 0; $this->{appear} = 'sudden'; # sudden/usertrap for (my $i = 0; my @c = caller $i; $i++) { my ($package, $filename, $line, $sub, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask) = @c; if ($sub =~ /^Tripletail::__die_handler_for_(localeval|startup)$/) { $sub = 'Tripletail::((die handler))'; $found_die_handler = 1; } elsif ($sub eq '(eval)') { if ($is_require) { $sub = "((require/use $package))"; if( $this->{appear} eq 'sudden' ) { $this->{on_require} = 1; } } else { if( $this->{appear} eq 'sudden' && $package!~/^Tripletail\b/ ) { $this->{appear} = 'usertrap'; } if (defined $evaltext) { $evaltext =~ s!\s*|\s*!!g; if (length($evaltext) > 30) { substr($evaltext, 27) = '...'; } $sub = sprintf '((eval "%s"))', $evaltext; } else { $sub = '((eval))'; } } $sub = $package . '::' . $sub; } if ($hasargs) { $pad_level++; } else { next; # 颿°å¼åºãã®ã¿èæ ®ãevalã§ä½ããããã¬ã¼ã ã¯é£ã°ãã # peek_my/peek_our ã§ã eval ã®ãã¬ã¼ã ã¯é£ã°ãããã # (pod ã«ã¯åã弿°ã caller ã¨åãã ã¨æ¸ãã¦ãããã©åâ¦) } $this->{suppress_internal} and not $found_die_handler and next; # ã¾ã die ãã³ãã©ãè¦ãã¦ããªã my $frame = Tripletail::Error::Frame->new( $level++, $filename, $line, $sub); if ($this->{show_vars} and $PADWALKER_AVAILABLE) { # ãã¼ã«ã«å¤æ°ãåå¾ my $mines = PadWalker::peek_my($pad_level); my $ours = PadWalker::peek_our($pad_level); while (my ($name, $ref) = each %$mines) { $frame->set_variable("my $name", $ref); } while (my ($name, $ref) = each %$ours) { $frame->set_variable("our $name", $ref); } #my @args; #do { # package DB; # @c = caller $i + 1; # @args = @DB::args; #}; #$frame->set_variable('@_', \@args); } if ($this->{show_src}) { # ã½ã¼ã¹ã³ã¼ããåå¾ if (not exists $this->{source}{$filename}) { my $src; if (-r $filename) { $src = $TL->readTextFile($filename); } $this->{source}{$filename} = $src; } } push @{$this->{frames}}, $frame; } } sub is_trace_allowed { my $this = shift; if (defined(my $ret = $TRACE_ALLOWANCE_OF_CURRENT_REQUEST)) { $ret; } else { my $ret; my $masks = $TL->INI->get( TL => 'stackallow', ''); if (my $remote = $ENV{REMOTE_ADDR}) { if($TL->newValue->set($remote)->isIpAddress($masks)) { # ããããã $TL->log(__PACKAGE__, "[$remote] matched to [$masks]. stack trace is allowed"); $ret = 1; } else { # ã©ãã«ããããããªãã£ãã $TL->log( __PACKAGE__, sprintf( "[%s] didn't match to any of [%s]. stack trace is not allowed", $remote, $masks)); $ret = 0; } } else { # CGI ã¨ãã¦èµ·åãããã®ã§ã¯ãªããããªã®ã§ã # ç¡æ¡ä»¶ã«ã¹ã¿ãã¯ãã¬ã¼ã¹ã®è¡¨ç¤ºã許ãã $TL->log(__PACKAGE__, "\$ENV{REMOTE_ADDR} is not set. stack trace is allowed."); $ret = 1; } $TRACE_ALLOWANCE_OF_CURRENT_REQUEST = $ret; $ret; } } sub toHtml { my $this = shift; my $t = $TL->newTemplate->setTemplate($DEFAULT_ERROR_TEMPLATE); if ($this->{show_trace} and $this->is_trace_allowed) { my $msg = $this->{message}; if( my $dberr = $this->{db_error} ) { $msg .= "\nDB Error: ".Data::Dumper->new([$dberr])->Terse(1)->Dump(); } $t->node('style-for-detail')->add({}); $t->node('detail')->setAttr({ MESSAGE => 'br', })->expand( TYPE => $this->{type}, MESSAGE => "$msg", ); } else { $t->node('style-for-header-only')->add({}); $t->node('header-only')->setAttr({ MESSAGE => 'br', })->add( TYPE => $this->{type}, MESSAGE => "$this->{message}", ); $t->expand( SELECTED_LV => 0, LAST_HILITED => 0, ); return $t->toStr; } # åæç¶æ ã§é¸æããã¹ã¿ãã¯ã¬ãã«ã¯ãï¼ããé ã«ãã¬ã¼ã ã辿ã£ã¦è¡ # ããæåã«è¦ä»ãã Tripletail:: åå空éå¤ã®ãã¬ã¼ã ã®ã¬ãã«ã¨ãããä½ã # å ¨ã¦ã®ãã¬ã¼ã ã Tripletail:: ã§ããã°ãã¬ãã«ï¼ã使ç¨ããã my $default_level = 0; for (my $i = 0; $i < @{$this->{frames}}; $i++) { my $frame = $this->{frames}[$i]; my $next = ($i == @{$this->{frames}} - 1 ? undef : $this->{frames}[$i + 1]); if ($next and $next->func !~ m/^Tripletail::/) { $default_level = $i; last; } } for (my $i = 0; $i < @{$this->{frames}}; $i++) { my $frame = $this->{frames}[$i]; my $next = ($i == @{$this->{frames}} - 1 ? undef : $this->{frames}[$i + 1]); if ($i == $default_level) { $t->node('detail')->node('frame')->node('selected')->add; } $t->node('detail')->node('frame')->add( LEVEL => $i, FILE => $frame->fpath, LINE => $frame->line, CALLER => (defined $next ? $next->func : '((basement))'), CALLEE => $frame->func, ); } # JavaScript ããèªãçºã®ãã¼ã¿ãå±é for (my $i = 0; $i < @{$this->{frames}}; $i++) { my $frame = $this->{frames}[$i]; my $next = ($i == @{$this->{frames}} - 1 ? undef : $this->{frames}[$i + 1]); # 夿° while (my ($name, $value) = each %{$frame->vars}) { $value =~ s!</script>!</sc"+"ript>!ig; $t->node('scripts')->node('js-vars')->node('var')->setAttr( NAME => 'js', VALUE => 'js', ); $t->node('scripts')->node('js-vars')->node('var')->add( NAME => $name, VALUE => $value, ); } $t->node('scripts')->node('js-vars')->add( LEVEL => $frame->level, ); while (my ($name, $value) = each %{$frame->vars_shallow}) { $value =~ s!</script>!</sc"+"ript>!ig; $t->node('scripts')->node('js-vars-shallow')->node('var')->setAttr( NAME => 'js', VALUE => 'js', ); $t->node('scripts')->node('js-vars-shallow')->node('var')->add( NAME => $name, VALUE => $value, ); } $t->node('scripts')->node('js-vars-shallow')->add( LEVEL => $frame->level, ); # ãã¬ã¼ã $t->node('scripts')->node('js-frame')->setAttr( FILE => 'js', FUNC => 'js', ); $t->node('scripts')->node('js-frame')->add( LEVEL => $frame->level, FILE => $frame->fpath, LINE => $frame->line, FUNC => (defined $next ? $next->func : '((basement))'), ); } # ã½ã¼ã¹ foreach my $fpath (keys %{$this->{source}}) { $this->_foreach_source_line( $fpath, sub { my ($linenum, $src) = @_; $src = $TL->escapeJs($src); $src =~ s!</script>!</sc"+"ript>!i; $t->node('scripts')->node('js-src')->node('line')->setAttr( LINE => 'raw', ); $t->node('scripts')->node('js-src')->node('line')->add( LINE => $src, ); }); $t->node('scripts')->node('js-src')->setAttr( FILE => 'js', ); $t->node('scripts')->node('js-src')->add( FILE => $fpath, ); } my $frame = $this->{frames}[$default_level]; # ããã©ã«ãã§è¡¨ç¤ºããã夿°ã¯ Lv. 0 ã®å¤æ°ã§ããã表示ãããã½ã¼ã¹ # 㯠Lv. 0 ã®ã½ã¼ã¹ã§ãããããã¯å¾ã§ JavaScript ã«ãã£ã¦æ¸ãæãã # ããå¯è½æ§ãããã if (not $this->{show_vars}) { $t->node('detail')->node('vars-unavail')->add( REASON => 'iniãã¡ã¤ã«ã[TL]ã°ã«ã¼ãã® "stacktrace" ã®è¨å®å¤ã'. ' "full" ã«ãªã£ã¦ãã¾ããã'); } elsif (not $frame) { $t->node('detail')->node('vars-unavail')->setAttr( REASON => 'raw', ); $t->node('detail')->node('vars-unavail')->add( REASON => q{ã¹ã¿ãã¯ãã¬ã¼ã¹ãåå¾ã§ãã¾ããã§ããã} . q{$SIG{__DIE__} ãã³ãã©ãç½®ãæããããç¶æ ã§ã¨ã©ã¼ãçºçããå¯è½æ§ãããã¾ãã<br />} . q{ã¨ã©ã¼å 容ãåæã«æ¸ãæããããã®ãé²ããªã©ã®çç±ã§ä¸æçã« $SIG{__DIE__} } . q{ãã³ãã©ãç½®ãæããéã«ã¯ã次ã®ããã«ãã¦ãçºçããã¨ã©ã¼ãå度 die ãã¦ä¸ããã<br /><br />} . q[<pre>eval {] . "\n" . q[ $SIG{__DIE__} = 'DEFAULT';] . "\n" . q[ # ã¨ã©ã¼ãçºçããå¦ç] . "\n" . q[};] . "\n" . q[if ($@) {] . "\n" . q[ die $@; # å度ã¨ã©ã¼ãçºçããã] . "\n" . q[}</pre>], ); } elsif (not $PADWALKER_AVAILABLE) { $t->node('detail')->node('vars-unavail')->setAttr( REASON => 'raw', ); $t->node('detail')->node('vars-unavail')->add( REASON => '<a href="http://search.cpan.org/~robin/PadWalker/">PadWalker</a> ãå©ç¨ä¸å¯è½ã§ãã'); } else { foreach my $name (sort {$a cmp $b} keys %{$frame->vars_shallow}) { $t->node('detail')->node('vars-avail')->node('var')->add( NAME => $name, VALUE => $frame->vars_shallow->{$name}, ); } $t->node('detail')->node('vars-avail')->add; } if (not $this->{show_src}) { $t->node('detail')->node('src-unavail')->add( REASON => 'iniãã¡ã¤ã«ã[TL]ã°ã«ã¼ãã® "stacktrace" ã®è¨å®å¤ã'. ' "full" ã«ãªã£ã¦ãã¾ããã'); } elsif (not $frame) { $t->node('detail')->node('src-unavail')->add( REASON => q{ã¹ã¿ãã¯ãã¬ã¼ã¹ãåå¾ã§ãã¾ããã§ããã} ); } elsif (not defined $this->{source}{$frame->fpath}) { $t->node('detail')->node('src-unavail')->add( REASON => 'ã½ã¼ã¹ãã¡ã¤ã« "%s" ãèªã¿è¾¼ãäºãåºæ¥ã¾ããã'); } else { $this->_foreach_source_line( $frame, sub { my ($linenum, $src) = @_; $t->node('detail')->node('src-avail')->node('line')->node( $frame->line == $linenum ? 'caller-line' : 'other-line')->add( SOURCE => $src, LINE_NUM => $linenum, ); $t->node('detail')->node('src-avail')->node('line')->add; }); $t->node('detail')->node('src-avail')->add; } if ($frame) { $t->node('scripts')->add({ SELECTED_LV => $frame->level, LAST_HILITED => $frame->line, }); $t->expand( SELECTED_LV => $frame->level, LAST_HILITED => $frame->line, ); } else { $t->node('scripts')->add({ SELECTED_LV => 0, LAST_HILITED => 0, }); $t->expand( SELECTED_LV => 0, LAST_HILITED => 0, ); } $t->node('detail')->add; $t->toStr; } sub _stringify { # æåååã¯æ¨æºã¨ã©ã¼ãã¡ã¼ã«çã¸ã®åºåãç®çã¨ãã¦è¡ãããçºãã½ã¼ # ã¹ã³ã¼ãã¯çãããããã¼ã«ã«å¤æ°ãçããããã©ããã¯è¨å®ã«ä¾ãã my $this = shift; my $dump_vars = ($TL->INI->get(TL => 'errorlog', 1) > 2); my $omission_threshold = 100; # 100 ãã¤ããè¶ãã夿°ã¯äºå以ä¸åºåããªã my $already_dumped = {}; # å¤ => [åå, ã¬ãã«] my $ret; $ret = sprintf "[%s] message: %s\n", $this->{type}, $this->{message}; for (my $i = 0; $i < @{$this->{frames}}; $i++) { my $frame = $this->{frames}[$i]; my $next = ($i == @{$this->{frames}} - 1 ? undef : $this->{frames}[$i + 1]); $ret .= sprintf( "[stack][%d] file: %s (line %d) \@ %s ==> %s\n", $i, $frame->fpath, $frame->line, (defined $next ? $next->func : '((basement))'), $frame->func, ); if ($dump_vars) { my @sorted = sort keys %{$frame->vars}; foreach my $name (@sorted) { my $value = $frame->vars->{$name}; $ret .= sprintf(" %s = ", $name); if (length($value) >= $omission_threshold) { if (my $before = $already_dumped->{$value}) { $ret .= sprintf( "already dumped as %s at frame %d. skip...\n", $before->[0], $before->[1]); next; } else { $already_dumped->{$value} = [$name, $i]; } } my @lines = split /\r?\n|\n/, $value; for (my $i = 0; $i < @lines; $i++) { if ($i == 0) { $ret .= "$lines[$i]\n"; } elsif ($i == @lines - 1) { $ret .= " $lines[$i];\n"; } else { $ret .= " $lines[$i]\n"; } } } } } $ret; } sub _foreach_source_line { my ($this, $fpath, $f) = @_; ref $fpath and $fpath = $fpath->fpath; # Tripletail::Error::Frame ã許ã my $src = $this->{source}{$fpath}; my @lines = split /\r?\n|\r/, (defined $src ? $src : ''); for (my $i = 0; $i < @lines; $i++) { $f->( $i + 1, sprintf('%5d | %s', $i + 1, $lines[$i])); } } package Tripletail::Error::Frame; use strict; use warnings; sub new { my $class = shift; my $this = bless {} => $class; $this->{level} = shift; $this->{fpath} = shift; $this->{line} = shift; $this->{func} = shift; $this->{vars} = {}; # '$foo' => 666 $this->{vars_shallow} = {}; # '$doo' => 'ARRAY(0x81940f8)' $this; } sub level { shift->{level} } sub fpath { shift->{fpath} } sub line { shift->{line} } sub func { shift->{func} } sub vars { shift->{vars} } sub vars_shallow { shift->{vars_shallow} } sub set_variable { my $this = shift; my $name = shift; my $ref = shift; my $postprocess = sub { local($_); $_ = shift; s!^\\!!; s!^\s*|\s*$!!g; ($name =~ m/[\@\%]/) and do { s!^[\[\{]!(!; s![\]\}]$!)!; }; if (length > $VARIABLE_LENGTH_LIMIT) { substr($_, $VARIABLE_LENGTH_LIMIT - 3) = '...'; } $_; }; my $dump = Data::Dumper->new([$ref]) ->Indent(1)->Purity(0)->Useqq(1)->Terse(1)->Deepcopy(1) ->Quotekeys(0)->Sortkeys(1)->Deparse(1)->Maxdepth(7)->Dump; $this->{vars}{$name} = $postprocess->($dump); my $shallow = Data::Dumper->new([$ref]) ->Indent(1)->Purity(0)->Useqq(1)->Terse(1)->Deepcopy(1) ->Quotekeys(0)->Sortkeys(1)->Deparse(1)->Maxdepth(1)->Dump; $this->{vars_shallow}{$name} = $postprocess->($shallow); $this; } package Tripletail::Error; sub __load_default_error_template { # {{ DEFAULT_ERROR_TEMPLATE: <<'END'; <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11.dtd"> <html xml:lang="ja" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <meta name="robots" content="noindex,nofollow,noarchive" /> <title>[TL] å é¨ã¨ã©ã¼</title> <style> * { margin: 0; padding: 0; } body { background-color: #ddddbb; color: #333322; padding: 0px; font-size: 90%; } h1 { font-size: 150%; background-color: #eeeecc; border-style: inset; border-color: #ddddbb; border-width: 1px; padding: 3px; } h2 { font-size: 120%; background-color: #ccccaa; padding: 2px 3px; } .message { padding: 3px; font-size: 110%; font-weight: bold; } </style> <!begin:style-for-header-only> <!end:style-for-header-only> <!begin:style-for-detail> <style> table { width: 100%; } th, td { margin: 1px; border-style: dashed; border-width: 1px; border-color: #aaaa88; padding: 2px; } th { background-color: #d4d4b2; } .small { font-size: 85%; } /* ããã */ .header-pane { position: absolute; width: 50%; height: 15%; overflow: auto; background-color: #ddbbbb; } /* ã¹ã¿ã㯠*/ .stack-pane { position: absolute; width: 50%; height: 45%; top: 15%; background-color: #d8d8b6; overflow: auto; } .stack-pane .selected { color: #cc0000; } #stack-description { display: none; } /* 夿°è©³ç´° */ #variable-detail { position: absolute; width: 50%; height: 60%; background-color: #554433; opacity: 0.90; z-index: 1; color: white; overflow: auto; } #variable-detail pre { padding: 15px; } #variable-detail .header { font-size: 200%; font-weight: bold; } /* 夿° */ .variables-pane { position: absolute; width: 50%; height: 60%; left: 50%; overflow: auto; } .variables-pane .name { width: 15%; } .variables-pane pre { max-height: 100px; /* ãã®å¤ã¯ã¹ã¯ãªããã§ä¸æ¸ãããå¾ã */ overflow: auto; width: 100%; } #var-description { display: none; } /* ã½ã¼ã¹ */ .source-pane { position: absolute; width: 100%; height: 40%; top: 60%; background-color: #d5d5b3; overflow: auto; } .source-pane .caller { background-color: #ddbbbb; border-style: solid; border-width: 1px; border-color: #ccaaaa; margin-left: -1px; } </style> <!--[if IE]> <style> #variable-detail { filter:alpha(opacity=90); } </style> <![endif]--> <!end:style-for-detail> <!begin:scripts> <script type="text/javascript"> var env = { selected_lv : <&SELECTED_LV>, last_hilited: <&LAST_HILITED> }; var colours = { general: { inactive: "#ddddbb", active: "#eeeecc" }, tl : { inactive: "#ddddcc", active: "#eeeedd" }, cgi : { inactive: "#ddeecc", active: "#eeffdd" }, other : { inactive: "#eeddbb", active: "#ffeecc" } }; var vars_data = { <!begin:js-vars> <&LEVEL>: { <!begin:var>"<&NAME>": "<&VALUE>",<!end:var> "": null }, <!end:js-vars> "": null }; var vars_shallow_data = { <!begin:js-vars-shallow> <&LEVEL>: { <!begin:var>"<&NAME>": "<&VALUE>",<!end:var> "": null }, <!end:js-vars-shallow> "": null }; var frame_data = { <!begin:js-frame> <&LEVEL>: { fpath: "<&FILE>", line: <&LINE>, func: "<&FUNC>" }, <!end:js-frame> "": null }; var src_data = { <!begin:js-src> "<&FILE>": [ <!begin:line>"<&LINE>",<!end:line> null], <!end:js-src> "": null }; function on_load() { jump_to_caller_line(); show_hiddens(); adjust_pre_size(); fix_stack_colour(); } function is_var_worth_expanding(lv, name) { var data = vars_data[lv]; var value = data[name]; var shallow_data = vars_shallow_data[lv]; var shallow = shallow_data[name]; return value != shallow; } function enter_var(name) { var lv = env.selected_lv; if (!is_var_worth_expanding(lv, name)) { return; } foreach_var_cols( name, function (td) { td.style.backgroundColor = colours.general.active; }); } function leave_var(name) { var lv = env.selected_lv; if (!is_var_worth_expanding(lv, name)) { return; } foreach_var_cols( name, function (td) { td.style.backgroundColor = colours.general.inactive; }); } function expand_var(name) { var lv = env.selected_lv; if (!is_var_worth_expanding(lv, name)) { return; } var old = document.getElementById("variable-detail"); if (old) { old.parentNode.removeChild(old); } var div = document.createElement("variable-detail"); div.id = "variable-detail"; div.onclick = function () { div.parentNode.removeChild(div); }; var data = vars_data[lv]; var value = data[name]; var header = document.createElement("span"); header.className = "header"; header.appendChild( document.createTextNode(name)); var text = " = " + value.replace(/\r?\n|\n/g, "\r\n") + ";"; var pre = document.createElement("pre"); pre.appendChild(header); pre.appendChild(document.createTextNode(text)); div.appendChild(pre); var body = document.getElementsByTagName("body")[0]; body.appendChild(div); } function adjust_pre_size() { // IE ã®çºã®èª¿æ´ãIEã¯ã¹ã¯ãªãããæå®ãã width ã height ãç¡è¦ãã // éå ¬éã®åºæºã«å¾ã£ã¦å¤§ãããèªå¨ã«æ±ºå®ããã // ãã®åºæºãå¤é¨ããæ¨ãéãäºã¯å ¨ãä¸å¯è½ã§ããã if (navigator.appName.indexOf("Internet Explorer") == -1) { return; } var limit = 100; var vars = document.getElementById("variables"); if (!vars) { return; } var pres = vars.getElementsByTagName("pre"); for (var i = 0; i < pres.length; i++) { var pre = pres[i]; if (pre.className == "limit-size") { if (limit < pre.offsetHeight) { pre.style.height = limit + "px"; } var wwidth = document.body.clientWidth; pre.style.width = (wwidth / 2 * 0.85 - 20) + "px"; } } } function jump_to_caller_line() { var src_pane = document.getElementById("source-pane"); var frame = frame_data[env.selected_lv]; if (!frame) { return; } var caller = document.getElementById("srcline-" + frame.line); if (!caller) { return; } /* src_pane ã® scrollTop ã caller ã®ä½ç½®ã«ãã調æ´ãã */ var y = caller.offsetTop - src_pane.offsetHeight / 2 + caller.offsetHeight / 2; if (y < 0) { y = 0; } src_pane.scrollTop = y; } function show_hiddens() { var hiddens = ["stack-description", "var-description"]; for (var i in hiddens) { var elem = document.getElementById(hiddens[i]); if (elem) { var cond_val = 1; if (elem.getAttribute("condition")) { cond_val = eval(elem.getAttribute("condition")); } if (cond_val) { elem.style.display = "block"; } } } } function fix_stack_colour() { var stack = document.getElementById("stack"); if (!stack) { return; } var tbody = stack.getElementsByTagName("tbody")[0]; var child = tbody.firstChild; while (child) { if (child.tagName && child.tagName.toLowerCase() == "tr") { var tr = child; var m = /^frame:(\d+)$/.exec(tr.id); if (m) { var lv = m[1]; foreach_stack_cols( lv, function(td) { td.style.backgroundColor = get_stack_colour(lv).inactive; }); } } child = child.nextSibling; } } function get_stack_colour(lv) { var frame = frame_data[lv]; if (frame.func.indexOf("Tripletail::") == 0) { return colours.tl; } var deepest_frame; var deepest_lv; for (var i in frame_data) { if (deepest_lv == null || deepest_lv < i) { deepest_frame = frame_data[i]; deepest_lv = i; } } if (frame.fpath == deepest_frame.fpath) { return colours.cgi; } return colours.other; } function is_stack_worth_selecting() { /* 夿°ã¾ãã¯ã½ã¼ã¹ã³ã¼ãã®å°ãªãã¨ã䏿¹ãå©ç¨å¯è½ã§ãªããã°ã ã¹ã¿ãã¯ã鏿ããäºã®æå³ãç¡ãã*/ var variables = document.getElementById("variables"); var source = document.getElementById("source-lines"); return variables || source; } function enter_stack(lv) { if (!is_stack_worth_selecting() || lv == env.selected_lv) { return; } foreach_stack_cols( lv, function(td) { td.style.backgroundColor = get_stack_colour(lv).active; }); } function leave_stack(lv) { foreach_stack_cols( lv, function(td) { td.style.backgroundColor = get_stack_colour(lv).inactive; }); } function select_stack(lv) { if (!is_stack_worth_selecting()) { return; } if (lv == env.selected_lv) { jump_to_caller_line(); return; } /* selected ã¯ã©ã¹ã«æå®ãããè¡ã夿´ */ var old = document.getElementById("frame:" + env.selected_lv); old.className = "frame"; var tr = document.getElementById("frame:" + lv); tr.className = "frame selected"; /* 夿°ä¸è¦§ãä½ãç´ã */ rebuild_var_list(lv); /* ã½ã¼ã¹ã³ã¼ãåè¡ãä½ãç´ã */ rebuild_src_list(lv); update_src_hilite(lv); env.selected_lv = lv; adjust_pre_size(); jump_to_caller_line(); } function rebuild_var_list(lv) { var table = document.getElementById("variables"); if (!table) { return; } remove_rows_except_the_first(table); var data = vars_shallow_data[lv]; var sorted_keys = []; for (var key in data) { if (key != "") { sorted_keys.push(key); } } sorted_keys = sorted_keys.sort(); var tbody = table.getElementsByTagName("tbody")[0]; for (var i in sorted_keys) { var name = sorted_keys[i]; var value = data[name]; var tr = document.createElement("tr"); tr.id = "var:" + name; var tmp = { name: name }; with (tmp) { tr.onmouseover = function () { enter_var(name); }; tr.onmouseout = function () { leave_var(name); }; tr.onmousedown = function () { expand_var(name); }; } var td_name = document.createElement("td"); td_name.className = "name"; td_name.appendChild( document.createTextNode(name)); var td_value = document.createElement("td"); td_value.className = "value small"; /* IE ã¯ãæ¹è¡ã³ã¼ãã CRLF ã«ããªãã¨æ¹è¡ãã¦ãããªãããã°ï¼ */ var pre = document.createElement("pre"); pre.appendChild( document.createTextNode(value.replace(/\r?\n|\n/g, "\r\n"))); td_value.appendChild(pre); tr.appendChild(td_name); tr.appendChild(td_value); tbody.appendChild(tr); } } function rebuild_src_list(lv) { // è¡çªå·ãéãã ãã§ã½ã¼ã¹ãã¡ã¤ã«ãåãã§ããã°ã // åè¡ã® class ã夿´ããã ãã§è¯ãã if (frame_data[env.selected_lv].fpath == frame_data[lv].fpath) { return; } var area = document.getElementById("source-lines-area"); if (!area) { return; } remove_children(area); var lines = document.createElement("div"); lines.className = "lines"; lines.id = "source-lines"; var frame = frame_data[lv]; var src = src_data[frame.fpath]; for (var i = 0; i < src.length; i++) { if (src[i] == null) { continue; } var pre = document.createElement("pre"); pre.id = "srcline-" + (i + 1); pre.appendChild( document.createTextNode(src[i])); lines.appendChild(pre); } area.appendChild(lines); } function update_src_hilite(lv) { var old = document.getElementById("srcline-" + env.last_hilited); if (old) { old.className = ""; } var frame = frame_data[lv]; var caller = document.getElementById("srcline-" + frame.line); if (!caller) { return; } caller.className = "caller"; env.last_hilited = frame.line; } function remove_children(elem) { var child = elem.firstChild; while (child) { var next = child.nextSibling; elem.removeChild(child); child = next; } } function remove_rows_except_the_first(table) { // table è¦ç´ ã®å é 以å¤ã® tr ãæ¶ãã var tbody = table.getElementsByTagName("tbody")[0]; var skipped; var child = tbody.firstChild; while (child) { if (child.tagName && child.tagName.toLowerCase() == "tr") { if (skipped) { var next = child.nextSibling; tbody.removeChild(child); child = next; continue; } else { skipped = true; } } child = child.nextSibling; } } function foreach_cols(tr, name, f) { var child = tr.firstChild; while (child) { if (child.tagName && child.tagName.toLowerCase() == "td") { f(child); } child = child.nextSibling; } } function foreach_var_cols(name, f) { var tr = document.getElementById("var:" + name); foreach_cols(tr, name, f); } function foreach_stack_cols(lv, f) { var tr = document.getElementById("frame:" + lv); foreach_cols(tr, name, f); } </script> <!end:scripts> </head> <body onload="on_load()"> <!begin:header-only> <h1>[TL] å é¨ã¨ã©ã¼</h1> <h2>ã¿ã¤ã: <&TYPE></h2> <p class="message"> <&MESSAGE> </p> <!end:header-only> <!begin:detail> <div class="header-pane"> <p class="message"> <&MESSAGE> </p> </div> <div class="stack-pane"> <table id="stack"> <tr> <th>Lv.</th> <th>ãã¡ã¤ã«</th> <th>è¡</th> <th>å¼åºãå </th> <th>å¼åºãå </th> </tr> <!begin:frame> <tr class="frame <!begin:selected>selected<!end:selected>" id="frame:<&LEVEL>" onmouseover="enter_stack(<&LEVEL>)" onmouseout="leave_stack(<&LEVEL>)" onmousedown="select_stack(<&LEVEL>)"> <td><&LEVEL></td> <td class="small"><&FILE></td> <td><&LINE></td> <td><&CALLER></td> <td><&CALLEE></td> </tr> <!end:frame> </table> <p id="stack-description" condition="is_stack_worth_selecting()"> ãã¬ã¼ã ãã¯ãªãã¯ããã¨ããã®ãã¬ã¼ã ã鏿ããã¾ãã </p> </div> <div class="variables-pane"> <h1>[TL] å é¨ã¨ã©ã¼</h1> <h2>ã¿ã¤ã: <&TYPE></h2> <!begin:vars-avail> <table id="variables"> <tr> <th>夿°å</th> <th>å¤</th> </tr> <!begin:var> <tr id="var:<&NAME>" onmouseover="enter_var('<&NAME>')" onmouseout="leave_var('<&NAME>')" onmousedown="expand_var('<&NAME>')"> <td class="name"><&NAME></td> <td class="value small"><pre><&VALUE></pre></td> </tr> <!end:var> </table> <p id="var-description"> å é¨ãçç¥è¡¨ç¤ºããã¦ãã夿°ãã¯ãªãã¯ããã¨ããã®å 容ãå±é表示ããã¾ãã </p> <!end:vars-avail> <!begin:vars-unavail> <p> 夿°ä¸è¦§ã表示ããäºãåºæ¥ã¾ããã çç±: </p> <p> <&REASON> </p> <!end:vars-unavail> </div> <div class="source-pane" id="source-pane"> <h2>ã½ã¼ã¹ã³ã¼ã</h2> <!begin:src-avail> <div id="source-lines-area"> <div class="lines" id="source-lines"> <!begin:line> <!begin:caller-line> <pre class="caller" id="srcline-<&LINE_NUM>"><&SOURCE></pre> <!end:caller-line> <!begin:other-line><pre id="srcline-<&LINE_NUM>"><&SOURCE></pre><!end:other-line> <!end:line> </div> </div> <!end:src-avail> <!begin:src-unavail> <p> ã½ã¼ã¹ã³ã¼ãã表示ããäºãåºæ¥ã¾ããã çç±: </p> <p> <&REASON> </p> <!end:src-unavail> </div> <!end:detail> </body> </html> END # DEFAULT_ERROR_TEMPLATE:}} } __END__