|
|
||
hyuki さんの YukiWiki 2.1.3 CGI スクリプト解読のために、グローバル変数とグローバル定数をどの手続きが参照しているのかリストアップしてみました。
⇒ http://www.hyuki.com/yukiwiki/
$plugin_context
init_plugin print_plugin_log
$plugin_manager
init_plugin make_link print_editform
print_plugin_log text_to_html
%database
close_db do_adminedit do_comment
do_edit do_index do_read
do_search do_write get_subjectline
init_InterWikiName init_form is_exist_page
make_link open_db send_mail_to_admin
update_recent_changes update_rssfile
%diffbase
close_diff do_diff do_write
open_diff
%fixedpage
do_FrontPage is_editable
%form
conflict do_FrontPage do_adminchangepassword
do_adminedit do_comment do_diff
do_edit do_read do_search
do_write embedded_to_html frozen_reject
init_form keyword_reject length_reject
main print_editform print_header
update_recent_changes
%infobase
close_db do_write get_info
open_db set_info
%interwiki
init_InterWikiName make_link
%page_command
init_form make_link
%resource
do_adminchangepassword do_adminedit do_create
do_diff do_edit do_search
do_write embedded_to_html frozen_reject
init_resource length_reject make_link
print_editform print_header print_passwordform
print_searchform text_to_html
%command_do
main
$AdminChangePassword
do_adminchangepasswordform
$AdminSpecialPage
do_adminchangepassword valid_password
$CompletedSuccessfully
do_adminchangepassword do_write
$CreatePage
do_create print_header
$ErrorPage
print_error
$FrontPage
do_FrontPage init_form print_header
$IndexPage
do_index print_header
$InterWikiName
init_InterWikiName
$RecentChanges
do_search print_header update_recent_changes
update_rssfile
$RssPage
$SearchPage
do_search do_searchform print_header
$bracket_name
inline is_bracket_name unarmor_name
$charset
print_header update_rssfile
$cols
print_editform
$dataname
open_db
$diffname
open_diff
$editchar
make_link
$embed_comment
do_comment embedded_to_html
$embed_rcomment
do_comment embedded_to_html
$embedded_name
make_link
$file_FrontPage
do_FrontPage
$file_conflict
conflict
$file_format
print_editform
$file_resource
init_resource
$file_rss
do_rss update_recent_changes update_rssfile
$file_touch
update_recent_changes
$icontag
print_footer
$info_AdminPassword
do_adminchangepassword valid_password
$info_ConflictChecker
conflict do_adminedit do_edit
do_write embedded_to_html
$info_IsFrozen
do_write frozen_reject is_frozen
$info_LastModified
do_write
$infoname
open_db
$inline_plugin
inline make_link
$interwiki_definition
inline make_link
$interwiki_name
is_editable make_link
$kanjicode
code_convert conflict do_FrontPage
init_form init_resource print_editform
$lang
print_header
$max_message_length
length_reject
$maxrecent
update_recent_changes
$modifier_dbtype
close_db close_diff open_db
open_diff
$modifier_dir_data
$modifier_dir_plugin
init_plugin
$modifier_mail
print_header send_mail_to_admin
$modifier_name
print_footer
$modifier_rss_about
do_rss print_header update_rssfile
$modifier_rss_description
update_rssfile
$modifier_rss_link
update_rssfile
$modifier_rss_timezone
update_rssfile
$modifier_rss_title
update_rssfile
$modifier_sendmail
send_mail_to_admin
$modifier_url
print_footer
$modifier_url_data
$rows
print_editform
$subject_delimiter
get_subjectline
$url_cgi
do_create do_index do_search
embedded_to_html make_link print_editform
print_header print_passwordform print_searchform
$url_stylesheet
print_header
$use_FixedFrontPage
$use_autoimg
make_link
$use_exists
is_exist_page
$version
print_footer
$wiki_name
armor_name init_form inline
interwiki_convert
YukiWiki 2.1.3 のソースの中に WalWiki からバックポートした CSV データをテーブルに組み立てる部分が組み込まれています。カラムの前後にスペースを置いておくと、左右詰め・中央詰めになり、イコールを2つ置いたカラムは直左のカラムを colspan するようにマークアップします。この部分、パズルのようで、私にはぱっと読んで動作を理解することができませんでした。
⇒ yukiwiki213.zip の $BASE/wiki.cgi より
} elsif (/^\,(.*?)[\x0D\x0A]*$/) { &back_push('table', 1, \@saved, \@result, ' border="1"'); ####### # This part is taken from Mr. Ohzaki's Perl Memo and Makio Tsukamoto's WalWiki. # XXXXX my $tmp = "$1,"; my @value = map { /^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_ } ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g); my @align = map { (s/^\s+//) ? ((s/\s+$//) ? ' align="center"' : ' align="right"') : '' } @value; my @colspan = map {($_ eq '==') ? 0 : 1} @value; for (my $i = 0; $i < @value; $i++) { if ($colspan[$i]) { while ($i + $colspan[$i] < @value and $value[$i + $colspan[$i]] eq '==') { $colspan[$i]++; } $colspan[$i] = ($colspan[$i] > 1) ? sprintf(' colspan="%d"', $colspan[$i]) : ''; $value[$i] = sprintf('<td%s%s>%s</td>', $align[$i], $colspan[$i], &inline($value[$i])); } else { $value[$i] = ''; } } push(@result, join('', '<tr>', @value, '</tr>')); # XXXXX #######
そこで、数行長くなるのですけど、わかりやすさ優先で書き直してみました。
⇒ https://gist.github.com/1751969 (ユニット・テスト)
} elsif (/^\,(.*?)[\x0D\x0A]*$/) {
back_push('table', 1, \@saved, \@result, q{ border="1"});
my $csv = "$1,";
my @td;
while ($csv =~ m{
\G(?:"([^"]*(?:""[^"]*)*)"|([^,]*)), ((?:(?:"=="|==),)*)
}gmosx) {
my($data, $span_mark) = (defined $1 ? $1 : $2, $3);
if ($1) {
$data =~ s/""/"/gmosx;
}
my $align = q{};
if ($data =~ m/\A([ ]+)?(.*?)([ ]+)?\z/mosx) {
if ($1) {
$align = $3 ? q{ align="center"} : q{ align="right"};
}
$data = $2;
}
my $colspan = q{};
if ($span_mark) {
my $n = 1 + ($span_mark =~ tr/,/,/);
$colspan = qq{ colspan="$n"};
}
push @td, sprintf '<td%s%s>', $align, $colspan;
push @td, inline($data);
push @td, '</td>';
}
push @result, (join q{}, '<tr>', @td, '</tr>');
1つだけ、オリジナルから仕様を変更しています。CSV の先頭カラムに colspan マークを置いても、colspan マークとはみなさずに、カラムのデータ扱いするようにしました。この辺の挙動は、ユニット・テストに記述してあります。
和田先生のユリウス暦とグレゴリオ暦両方対応の「パラメトロン計算機: ユリウス日」計算コードを perl に意訳してみました。通常、ユリウス日は天文計算に使う目的が多く、倍精度浮動小数点演算で求めるものですが、和田先生のコードは整数演算で求めているのがポイントでしょう。オリジナルから変更した箇所は、うるう年かどうかの判定式をユリウス暦とグレゴリオ暦の両方一発で求めるようにしたぐらいです。グレゴリオ暦への切替日より後かどうかの判定には、Perl はリストの比較ができないので、日付をパックしてから文字列比較してみました。
my @YDAY = ( [-31, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365], [-31, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366], ); sub julian_date { my($y, $m, $d) = @_; use integer; my $leap = $y > 1600 && $y % 100 == 0 ? $y % 400 == 0 : $y % 4 == 0; my $a = ($y + 4712) * 365; my $b = ($y + 4712 + 3) / 4; my $c = 0; if ($y > 1601) { my $j = $y - 1601; $c = $j / 400 - $j / 100; } my $e = (pack 'nnn', $y, $m, $d) ge (pack 'nnn', 1582, 10, 15) ? -10 : 0; my $f = $YDAY[$leap ? 1 : 0][$m]; my $g = $d - 1; return $a + $b + $c + $e + $f + $g; }
ついでに、自分が普段使っている天文計算用の倍精度浮動小数点演算を使う C 言語のコードは、グレゴリオ暦の時代だけを計算する方法です。ユリウス暦のずれを補正しないで良いので、短くなります。こっちも Perl に訳してみました。
sub julian_date { my($yyyy, $mm, $dd, $hh) = @_; my($y, $m) = $mm > 2 ? ($yyyy, $mm) : ($yyyy - 1, $mm + 12); my $c = (int $y / 400) - (int $y / 100); return (int 365.25 * $y) + (int 30.6001 * ($m + 1)) + $dd + $hh / 24 + 1720996.5 + $c; }
これをどこで拾ったのか30年以上も前のことなので、はっきり覚えてないのですけど、確か古の FORTRAN の数値計算ライブラリにあったもののような記憶があります。