--- suikawiki/script/wiki.cgi 2002/02/04 13:19:08 1.1 +++ suikawiki/script/wiki.cgi 2002/02/04 13:31:47 1.2 @@ -1,1482 +1,1482 @@ -#!/usr/local/bin/perl -use lib "../lib"; -use CGI::Carp 'fatalsToBrowser'; -use Algorithm::Diff qw(traverse_sequences); -# use strict; -# -# yukiwiki.cgi - Yet another WikiWikiWeb clone. -# -# Copyright (C) 2000,2001 by Hiroshi Yuki. -# -# http://www.hyuki.com/yukiwiki/ -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# $Id: wiki.cgi,v 1.1 2002/02/04 13:19:08 wakaba Exp $ -############################## -my $version = "1.6.6"; -############################## -# 単独テストのときには 1 にする。 -my $testing = 0; -############################## -# 漢字ライブラリ -my $jcodelib = 'jcode.pl'; -############################## -# 保存・表示の漢字コード -my $kanjicode = 'sjis'; # 'sjis' 'euc' -my $charset = 'Shift_JIS'; # 'Shift_JIS' 'EUC-JP' -############################## -# dbmopenが使えるなら1、使えないなら0 -my $dbmopen = 0; -############################## -# データベース名(.pag, .dir, .dbなどは不要) -# $dbmopen = 1のときはデータベース名、 -# $dbmopen = 0のときはディレクトリ名になる。 -my $dbname = './yukiwiki'; -my $diffdbname = './yukidiff'; -############################## -# 修正者の氏名(自由に変更してください) -my $modifier = 'Hiroshi Yuki'; -############################## -# 修正者のWebページ(自由に変更してください) -my $modifierlink = 'http://www.hyuki.com/'; -############################## -# このページのURL -my $thisurl = 'yukiwiki.cgi'; -############################## -# 開始ページ名 -my $toppage = 'FrontPage'; -############################## -# 最終更新ページ名 -my $whatsnew = 'RecentChanges'; -############################## -# 最終更新に掲載するページ数 -my $maxnew = 50; -############################## -# アイコンファイル名(カラー版) -my $iconfile = 'yukiwiki.gif'; -############################## -# アイコンファイル名(モノクロ版) -# my $iconfile = 'yukimono.gif'; -############################## -# ページを変更したときにtouchするファイル(''なら何もしない) -my $touchfile = 'touch.txt'; -############################## -# プレビュー用の背景色 -my $preview_color = '#FFCCCC'; -############################## -# 全ページのスタイル -my $style = <<'EOD'; -pre, dl, ul, ol, p, blockquote { line-height:120%; } -a { text-decoration: none; } -a:link { color: #0000FF; background-color: #FFFFFF; } -a:visited { color: #9900CC; background-color: #FFFFFF; } -a:hover { text-decoration: underline; } -EOD -############################## -# テキスト入力部分の大きさ -my $cols = 80; -my $rows = 20; -############################## -my %form = (); -my %database = (); -my %diffbase = (); -my $diff_text = ''; -my @diff_added = (); -my @diff_deleted = (); -my $msgrefA; -my $msgrefB; -############################## -# 編集不可ページ名一覧 -my @uneditable = ( $whatsnew ); -############################## -# リンク用の正規表現 -# YukiWikiのリンクは2種類ある。 -# -# (1) WikiName (RecentChangesとかFrontPageのようなもの) -# (2) BracketName ([[結城浩]]とか[[トラブルシュート]]のようなもの) -# -# ※シフトJISの2バイト目には ']' が来うるので、 -# 文字']'を1つ多くとるようにしている。 -# -my $WikiName = '([A-Z][a-z]+([A-Z][a-z]+)+)'; -my $BracketName = '\[\[([^>\s]+?\]?)\]\]'; - -# アイコン部分のタグ -my $IconTag = <<"EOD"; -[YukiWiki] -EOD - -require "$jcodelib"; - -&init_form($kanjicode); - -if ($testing) { - %form = ( - # 'mycmd' => 'write', - 'mycmd' => 'read', - #'mycmd' => 'search', - #'mycmd' => 'edit', - 'mymsg' => <<"EOD", -はじめまして。 -これからいろいろ書き込みますね。 -LinkPageも見てください。 -TestPageはどうでしょうか。 -どうぞよろしく。 -http://www.hyuki.com/ -[[結城浩]] -EOD - 'mypage' => '<結城浩>', - 'myword' => '結', - # '3C8C8B8FE98D5F3E' => '', - # 'TestPage' => '', - ); -} -&main; -exit(0); - -# メイン -sub main { - &normalize_form; - if ($dbmopen) { - if (!dbmopen(%database, $dbname, 0666)) { - &print_error("(dbmopen) $dbname が作れません。"); - } - } else { - if (!tie(%database, "YukiWikiDB", $dbname)) { - &print_error("(tie error)"); - } - } - - # myspecial対応 - foreach (keys %form) { - if (/^myspecial_(.*)/) { - $form{mycmd} = $1; - last; - } - } - - if ($form{mycmd} eq 'read') { - &do_read; - } elsif ($form{mycmd} eq 'preview') { - &do_preview; - } elsif ($form{mycmd} eq 'write') { - &do_write; - } elsif ($form{mycmd} eq 'edit') { - &do_edit; - } elsif ($form{mycmd} eq 'reedit') { - &do_reedit; - } elsif ($form{mycmd} eq 'search') { - &do_search; - } elsif ($form{mycmd} eq 'list') { - &do_list; - } elsif ($form{mycmd} eq 'diff') { - &do_diff; - } else { - $form{mypage} = $toppage; - &do_read; - } - if ($dbmopen) { - dbmclose(%database); - } else { - untie(%database); - } -} - -# ページの表示 -sub do_read { - my $page_name = $form{mypage}; - my $percent_name = &encode_percent($page_name); - &print_header($page_name); - print qq|

$IconTag$page_name

\n|; - &print_toolbar($page_name); - print &convert_html(&get_page($page_name)); - &print_footer; -} - -# ページの編集 -sub do_edit { - if (not &is_editable($form{mypage})) { - # 編集不可ページは表示のみ - &do_read; - return; - } - &editpage(&get_page($form{mypage})); -} - -# ページの再編集 -sub do_reedit { - if (not &is_editable($form{mypage})) { - # 編集不可ページは表示のみ - &do_read; - } else { - &editpage($form{mymsg}); - } -} - -sub editpage { - my $page_msg = shift; - my $page_name = $form{mypage}; - my $digest = &calc_message_digest($page_msg); - &print_header($page_name); - print qq|

$IconTag${page_name}の編集

\n|; - &print_toolbar($page_name); - $page_msg = &escape($page_msg); - print <<"EOD"; -
- - - -
- -
-
-

テキスト整形のルール

- -

通常は入力した文字がそのまま出力されますが、 -以下のルールに従ってテキスト整形を行うことができます。

- - -EOD - &print_footer; -} - -# ページの検索 -sub do_search { - if ($form{myword}) { - &print_header('検索結果'); - print qq|

$IconTag$form{myword}の検索結果

\n|; - &print_toolbar(); - print qq|\n|; - if ($count > 0) { - print qq|

$form{myword}を含むページは、上に示す$countページです。

\n|; - } else { - print qq|

$form{myword}を含むページは見つかりません。

\n|; - } - } else { - &print_header('単語検索'); - print qq|

$IconTag単語検索

\n|; - &print_toolbar(); - } - print <<"EOD"; -

-

- - - -
-

-EOD - &print_footer; -} - -# ページの一覧 -sub do_list { - &print_header('ページ一覧'); - print qq|

$IconTag ページ一覧

\n|; - &print_toolbar(); - print qq|\n|; - &print_footer; -} - -# プレビュー -sub do_preview { - my $page_name = $form{mypage}; - my $escapedmsg = &escape($form{mymsg}); - &print_header($page_name); - print qq|

$IconTag${page_name}のプレビュー

\n|; - &print_toolbar($page_name); - # local $percent_name = &encode_percent($page_name); - print qq|

以下のプレビューを確認して、よければページ下部のボタンで更新してください。

\n|; - if ($form{mymsg}) { - print qq|
\n|; - # print &convert_html($escapedmsg); - print &convert_html($form{mymsg}); - print qq|
\n|; - } else { - print qq|

(ページの内容は空です。更新するとこのページは削除されます。)

\n|; - } - &print_preview_buttons($page_name, $escapedmsg, $form{mydigest}); - &print_footer; -} - -sub print_preview_buttons { - my ($page_name, $escapedmsg, $digest) = @_; - print <<"EOD"; -
- -
- - - - -
-EOD -} - -# 書き込む -sub do_write { - if (not &is_editable($form{mypage})) { - # 編集不可ページは表示のみ - &do_read; - return; - } - - my $page_name = $form{mypage}; - - # digestを使って、更新の衝突チェック - my $original_digest = &calc_message_digest(&get_page($page_name)); - if ($form{mydigest} ne $original_digest) { - &print_header($page_name); - print qq|

$IconTag${page_name}で【更新の衝突】が起きました

\n|; - print <<"EOD"; -

あなたがこのページを編集している間に、 -他の人が同じページを更新してしまったようです。 -

-以下に、あなたの編集したテキストがありますので、 -あなたの編集内容が失われないように、 -いますぐ、メモ帳などにコピー&ペーストしてください。 -

-コピー&ペーストが済んでから、 -最新の内容を見て再度編集し直してください。 -最新の内容は -$form{mypage} -で見ることができます。 -

-EOD - # &print_toolbar($page_name); - &print_preview_buttons($page_name, &escape($form{mymsg}), $form{mydigest}); - &print_footer; - return; - } - - # diff生成 - { - &opendiff; - my @msg1 = split(/\n/, &get_page($page_name)); - my @msg2 = split(/\n/, $form{mymsg}); - $msgrefA = \@msg1; - $msgrefB = \@msg2; - &diff_check; - $diffbase{$form{mypage}} = $diff_text; - $diff_text = ''; - &closediff; - } - - &print_header($page_name); - &set_page($page_name, $form{mymsg}); - if ($form{mymsg}) { - print qq|

$IconTag${page_name}を更新しました

\n|; - &print_toolbar($page_name); - print &convert_html(&get_page($page_name)); - } else { - print qq|

$IconTag${page_name}を削除しました

\n|; - &print_toolbar($page_name); - print qq|

${page_name}を削除しました。

\n|; - } - &print_footer; - # 更新されたのでタッチしておく。 - if ($touchfile) { - open(FILE, "> $touchfile"); - print FILE "\n"; - close(FILE); - } -} - -# ページの変更点 -sub do_diff { - if (not &is_editable($form{mypage})) { - # 編集不可ページは表示のみ - &do_read; - return; - } - &opendiff; - &print_header($form{mypage} . 'の変更点'); - print qq|

$IconTag $form{mypage}の変更点

\n|; - &print_toolbar(); - $_ = &escape($diffbase{$form{mypage}}); - print <<"EOD"; - -
-EOD - print qq|
\n|;
-    foreach (split(/\n/, $_)) {
-        if (/^\+(.*)/) {
-            print qq|$1\n|;
-        } elsif (/^\-(.*)/) {
-            print qq|$1\n|;
-        } elsif (/^\=(.*)/) {
-            print qq|$1\n|;
-        } else {
-            print qq|??? $_\n|;
-        }
-    }
-    print qq|
\n|; - &print_footer; - &closediff; -} - -sub opendiff { - if ($dbmopen) { - if (!dbmopen(%diffbase, $diffdbname, 0666)) { - &print_error("(dbmopen) $diffdbname が作れません。"); - } - } else { - if (!tie(%diffbase, "YukiWikiDB", $diffdbname)) { - &print_error("(tie error)"); - } - } -} - -sub closediff { - if ($dbmopen) { - dbmclose(%diffbase); - } else { - untie(%diffbase); - } -} - -# フォームからの情報を連想配列 %form に入れる -# &init_form('euc'); -sub init_form { - my ($charcode) = @_; - my $query; - if ($ENV{REQUEST_METHOD} =~ /^post$/i) { - read(STDIN, $query, $ENV{CONTENT_LENGTH}); - } else { - $query = $ENV{QUERY_STRING}; - } - my @assocarray = split(/&/, $query); - foreach my $assoc (@assocarray) { - my ($property, $value) = split(/=/, $assoc); - $value =~ tr/+/ /; - $value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg; - &jcode::convert(\$value, $charcode); - $form{$property} = $value; - } -} - -# エラーページを出力する -sub print_error { - my ($msg) = @_; - &print_header('Error'); - print "

$IconTag$msg

"; - exit(0); -} - -sub escape { - my ($line) = shift; - $line =~ s|<|<|g; - $line =~ s|>|>|g; - $line =~ s|"|"|g; - # $line =~ s|\&|&|g; - return $line; -} - -sub inline { - my ($line) = shift; - $line = &escape($line); - $line =~ s|'''([^']+?)'''|$1|g; # Italic - $line =~ s|''([^']+?)''|$1|g; # Bold - $line =~ s! - ( - ((mailto|http|https|ftp):[\x21-\x7E]*) # Direct http://... - | - ($WikiName) # LocalLinkLikeThis - | - ($BracketName) # [[日本語リンク]] - ) - ! - &make_link($1) - !gex; - return $line; -} - -# ページのタイトルからページの内容を得る -sub get_page { - my $page_name = shift; - return $database{$page_name}; -} - -# ページの内容を与える -# &set_page($title, $txt) -sub set_page { - # ページを更新する - my $title = $_[0]; - $database{$title} = $_[1]; - # 空ページなら削除する - unless ($database{$title}) { - delete $database{$title}; - } - # RecentChangesを更新する - my $delim = ' - '; - my @pages = split(/\n/, $database{$whatsnew}); - my $datestr = &get_current_datestr; - unshift(@pages, qq|-$datestr$delim$title|); - # 同一ページの更新は最新のもののみにし、 - # 存在しないページはスキップする。 - my %count; - my @newpages; - foreach my $line (@pages) { - my ($prefix, $title) = split(/$delim/, $line); - $count{$title}++; - if ($count{$title} == 1 and exists($database{$title})) { - push(@newpages, qq|$prefix - $title|); - } - } - # ここで本当に更新 - $database{$whatsnew} = join("\n", splice(@newpages, 0, $maxnew)); -} - -# ページのヘッダを出力 -sub print_header { - my $title = shift; - print <<"EOD"; -Content-type: text/html - - -$title - - - -EOD -} - -# ツールバーを出力 -sub print_toolbar { - my $page_name = shift; - my $percent_name = &encode_percent($page_name); - my $editlink = ''; - if ($page_name ne '' and &is_editable($page_name)) { - $editlink = <<"EOD"; -編集 | -差分 | -EOD - } - print <<"EOD"; -

- [ -トップ | -一覧 | -$editlink -単語検索 | -最終更新 - ] -

-EOD -} - -# ページのフッタを出力 -sub print_footer { - print <<"EOD"; -
-

-YukiWiki $version Copyright (C) 2000,2001 by Hiroshi Yuki.
-Modified by $modifier.
-

- -EOD -} - -# URLやページの名前からリンクを作る -sub make_link { - my $name = shift; - if ($name =~ /^(http|https|ftp).*?(\.gif|\.png|\.jpeg|\.jpg)?$/) { - if ($2) { - return qq||; - } else { - return qq|$name|; - } - } elsif ($name =~ /^mailto:(.*)/) { - my $address = $1; - return qq|$address|; - } elsif ($database{$name}) { - my $percent_name = &encode_percent($name); - return qq|$name|; - } else { - my $percent_name = &encode_percent($name); - return qq|$name?|; - } -} - -# %xx の形式にエンコードする -# これは、 -# http://www.hyuki.com/yukiwiki/yukiwiki.cgi?mycmd=read&mypage=%3C%8C%8B%8F%E9%8D_%3E -# という形式のために使われる。 -# '<結城浩>' → '%3C%8C%8B%8F%E9%8D_%3E' -sub encode_percent { - my $name = shift; - my $encoded = ''; - foreach my $ch (split(//, $name)) { - if ($ch =~ /[A-Za-z0-9_]/) { - $encoded .= $ch; - } else { - $encoded .= '%' . sprintf("%02X", ord($ch)); - } - } - return $encoded; -} - -# テキスト本体をHTMLに変換する -sub convert_html { - my ($txt) = shift; - my (@txt) = split(/\n/, $txt); - foreach (@txt) { - chomp; - if (/^\*\*(.*)/) { - push(@result, splice(@saved), '

' . &inline($1) . '

'); - } elsif (/^\*(.*)/) { - push(@result, splice(@saved), '

' . &inline($1) . '

'); - } elsif (/^----/) { - push(@result, splice(@saved), '
'); - } elsif (/^(-{1,3})(.*)/) { - &back_push('ul', length($1)); - push(@result, '
  • ' . &inline($2) . '
  • '); - } elsif (/^:([^:]+):(.*)/) { - &back_push('dl', 1); - push(@result, '
    ' . &inline($1) . '
    ', '
    ' . &inline($2) . '
    '); - } elsif (/^(>{1,3})(.*)/) { - &back_push('blockquote', length($1)); - push(@result, &inline($2)); - } elsif (/^\s*$/) { - push(@result, splice(@saved)); - unshift(@saved, "

    "); - push(@result, "

    "); - } elsif (/^(\s+.*)$/) { - &back_push('pre', 1); - push(@result, &escape($1)); # Not &inline, but &escape - } else { - push(@result, &inline($_)); - } - } - push(@result, splice(@saved)); - return join("\n", @result); -} - -# &back_push($tag, $count) -# $tagのタグを$levelレベルまで詰める。 -sub back_push { - my ($tag, $level) = @_; - while (@saved > $level) { - push(@result, shift(@saved)); - } - if ($saved[0] ne "") { - push(@result, splice(@saved)); - } - while (@saved < $level) { - unshift(@saved, ""); - push(@result, "<$tag>"); - } -} - -# 編集可能ページか? -sub is_editable { - my ($pagename) = @_; - foreach (@uneditable) { - if ($pagename eq $_) { - return 0; - } - } - if (&is_valid_name($pagename)) { - return 1; - } - return 0; -} - -# Validな名前か? -sub is_valid_name { - my ($pagename) = @_; - if ($pagename =~ /^$WikiName$/) { - return 1; - } elsif ($pagename =~ /^$BracketName$/) { - return 1; - } else { - return 0; - } -} - -# 現在時刻の文字列を得る -sub get_current_datestr { - my (@wdays) = ( "日", "月", "火", "水", "木", "金", "土" ); - my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time); - return sprintf("%4d-%02d-%02d (%s) %02d:%02d:%02d", - $year + 1900, $mon + 1, $mday, $wdays[$wday], $hour, $min, $sec); -} - -# URL?SomePageや、 -# URL?[[結城浩]]の形式だった場合、(not yet) -# 強制的にmycmdをreadにして$formの内容を設定する。 -sub normalize_form { - foreach my $key (keys %form) { - if ($key =~ /^$WikiName$/) { - $form{mycmd} = 'read'; - $form{mypage} = $1; - last; - } elsif ($key =~ /^$BracketName$/) { - $form{mycmd} = 'read'; - $form{mypage} = $1; - last; - } - } -} - -# 変換テストを行なうときのサンプル -sub print_sample { - my $txt = &convert_html(<<"EOD"); -*大見出し1 -**小見出し1-1 --項目1 --項目2 --項目3 -段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1 -段落1段落1段落1段落1段落1段落''強調''1段落1段落1段落1段落1段落1 -段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1 - -段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2 -段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2 -段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2 -**小見出し1-2 -:用語1:いろいろ書いた解説文1と''強調単語'' -段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1 -段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1 -段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1 -:用語2:いろいろ書いた解説文2 -:用語3:いろいろ書いた解説文3 ----- -*大見出し2 -**小見出し2-1 -http://www.hyuki.com/ -**小見出し2-2 - -[[結城浩]] - -段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1 -段落1段落1段落1段落'''イタリック'''1段落1段落1段落1段落1段落1段落1段落1 -段落1段落1段落1段落'''''イタボールド'''''1段落1段落1段落1段落1段落1段落1段落1段落1 ->段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2 ->段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2 ->段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2 - -レベル0レベル0レベル0レベル0レベル0レベル0 - ->レベル1 ->レベル1 ->レベル1 ->>レベル2 ->>レベル2 ->>レベル2 ->>>レベル3 --はろ1 ---はろ2 -ろろろろ2 ----はろ3 ---はろ2 ----はろ3 ---はろ2 ----はろ3 ->>>レベル3 ->>>レベル3 ->>>レベル3 -EOD - print $txt; - exit; -} - -sub diff_check { - traverse_sequences( - $msgrefA, $msgrefB, - { - MATCH => \&df_match, - DISCARD_A => \&df_delete, - DISCARD_B => \&df_add, - } - ); - &diff_flush; -} - -sub diff_flush { - $diff_text .= join('', map { "-$_\n" } splice(@diff_deleted)); - $diff_text .= join('', map { "+$_\n" } splice(@diff_added)); -} - -sub df_match { - my ($a, $b) = @_; - &diff_flush; - $diff_text .= "=$msgrefA->[$a]\n"; -} - -sub df_delete { - my ($a, $b) = @_; - push(@diff_deleted, $msgrefA->[$a]); -} - -sub df_add { - my ($a, $b) = @_; - push(@diff_added, $msgrefB->[$b]); -} - -sub calc_message_digest { # You have to use MD5... - my $text = shift; - my @text = split(//, $text); - my $len = length($text); - my $checksum = 0; - foreach (@text) { - $checksum += ord($_); - $checksum = ($checksum * 2) % 65536 + (($checksum & 32768) ? 1 : 0); # 16bit rotate - } - return "$len:$checksum"; -} - -# Definition of YukiWikiDB -package YukiWikiDB; - -my $debug = 1; - -# Constructor -sub new { - return shift->TIEHASH(@_); -} - -# tying -sub TIEHASH { - my ($class, $dbname) = @_; - my $self = { - dir => $dbname, - keys => [], - }; - if (not -d $self->{dir}) { - if (!mkdir($self->{dir}, 0777)) { - print "mkdir(" . $self->{dir} . ") fail\n" if ($debug); - return undef; - } - } - return bless($self, $class); -} - -# Store -sub STORE { - my ($self, $key, $val) = @_; - my $file = &make_filename($self, $key); - if (open(FILE,"> $file")) { - binmode(FILE); - print FILE $val; - close(FILE); - return $self->{$key} = $val; - } else { - print "$file create error."; - } -} - -# Fetch -sub FETCH { - my ($self, $key) = @_; - my $file = &make_filename($self, $key); - if (open(FILE, $file)) { - local $/; - $self->{$key} = ; - close(FILE); - } - return $self->{$key}; -} - -# Exists -sub EXISTS { - my ($self, $key) = @_; - my $file = &make_filename($self, $key); - return -e($file); -} - -# Delete -sub DELETE { - my ($self, $key) = @_; - my $file = &make_filename($self, $key); - unlink $file; - return delete $self->{$key}; -} - -sub FIRSTKEY { - my ($self) = @_; - opendir(DIR, $self->{dir}) or die $self->{dir}; - @{$self->{keys}} = grep /\.txt$/, readdir(DIR); - foreach my $name (@{$self->{keys}}) { - $name =~ s/\.txt$//; - $name =~ s/[0-9A-F][0-9A-F]/pack("C", hex($&))/eg; - } - return shift @{$self->{keys}}; -} - -sub NEXTKEY { - my ($self) = @_; - return shift @{$self->{keys}}; -} - -sub make_filename { - my ($self, $key) = @_; - my $enkey = ''; - foreach my $ch (split(//, $key)) { - $enkey .= sprintf("%02X", ord($ch)); - } - return $self->{dir} . "/$enkey.txt"; -} -__END__ - -=head1 NAME - -YukiWiki - 自由にページを追加・削除・編集できるWebページ構築CGI - - Copyright (C) 2000,2001 by Hiroshi Yuki. - 結城浩 - http://www.hyuki.com/ - http://www.hyuki.com/yukiwiki/ - -=head1 SYNOPSIS - - http://www.hyuki.com/yukiwiki/yukiwiki.cgi - -=head1 DESCRIPTION - -YukiWiki(結城ウィキィ)は参加者が自由にページを追加・削除・編集できる -不思議なWebページ群を作るCGIです。 -Webで動作する掲示板とちょっと似ていますが、 -Web掲示板が単にメッセージを追加するだけなのに対して、 -YukiWikiは、Webページ全体を自由に変更することができます。 - -YukiWikiは、Cunningham & CunninghamのWikiWikiWebの -仕様を参考にして独自に作られました。 - -YukiWikiはPerlで書かれたCGIスクリプトとして実現されていますので、 -Perlが動作するWebサーバならば比較的容易に設置できます。 - -あとはdbmopenが使える環境ならば設置できます(Version 1.5.0以降ならdbmopenが使えなくても設置できます)。 - - -YukiWikiはフリーソフトです。 -ご自由にお使いください。 - -=head1 設置方法 - -=head2 入手 - -YukiWikiの最新版は、 -http://www.hyuki.com/yukiwiki/ -から入手できます。 - -=head2 ファイル一覧 - - readme.txt ドキュメント - yukiwiki.cgi YukiWiki本体 - yukiwiki.gif ロゴ(カラー版) - yukimono.gif ロゴ(モノクロ版) - jcode.pl 漢字コードライブラリ - -=head2 インストール - -=over 4 - -=item 1. - -アーカイブを解く。 - -=item 2. - -yukiwiki.cgiのはじめの方にある設定を確認します。 -通常は何もしなくてよいが、 -はじめは$touchfileを''にした方がよいでしょう。 - -=item 3. - -yukiwiki.cgiとjcode.plを同じところに設置します。 - -=item 4. - -サイズ0のyukiwiki.dbというファイルを設置します。 -(Perlシステムによってはyukiwiki.pag, yukiwiki.dir) - -=item 5. - -yukiwiki.cgiにブラウザからアクセスします。 - -=back - -=head2 パーミッション - - ファイル パーミッション 転送モード - yukiwiki.cgi 755 ASCII - yukiwiki.gif 644 BINARY - yukimono.gif 644 BINARY - jcode.pl 644 ASCII - - $dbmopen = 1; にした場合: - yukiwiki.db 666 BINARY - (yukiwiki.pag, yukiwiki.dirの場合もあり) - - $dbmopen = 0; にした場合: (カレントディレクトリを777にしておく) - . 777 (転送しない) - -=head1 データのバックアップ方法 - -$dbmopen = 1;の場合は、 -データはすべてyukiwiki.db(.dir, .pag)に入る。 -これをバックアップすればよい。 - -$dbmopen = 0;の場合は、 -yukiwikiというディレクトリができるので、 -これ以下をバックアップすればよい。 - -=head1 新しいページの作り方 - -=over 4 - -=item 1. - -まず、適当なページ(例えばFrontPage)を選び、 -ページの下にある「編集」リンクをたどります。 - -=item 2. - -するとテキスト入力ができる状態になるので、 -そこにNewPageのような単語 -(大文字小文字混在している英文字列) -を書いて「保存」します。 - -=item 3. - -保存すると、FrontPageのページが書き換わり、 -あなたが書いたNewPageという文字列の後ろに ? というリンクが表示されます。 -この ? はそのページがまだ存在しないことを示す印です。 - -=item 4. - -その ? をクリックすると新しいページNewPageができますので、 -あなたの好きな文章をその新しいページに書いて保存します。 - -=item 5. - -NewPageページができるとFrontPageの ? は消えて、リンクとなります。 - -=back - -=head1 テキスト整形のルール - -=over 4 - -=item * - -連続した複数行はフィルされて表示されます。 - -=item * - -空行は段落C<<

    >>の区切りとなります。 - -=item * - -HTMLのタグは書けません。 - -=item * - -B<''ボールド''>のようにシングルクォート二つではさむと、 -ボールドC<< >>になります。 - -=item * - -B<'''イタリック'''>のようにシングルクォート三つではさむと、 -イタリックC<< >>になります。 - -=item * - -B<---->のようにマイナス4つがあると、 -水平線C<<


    >>になります。 - -=item * - -行をB<*>ではじめると、 -大見出しC<<

    >>になります。 - -=item * - -行をB<**>ではじめると、 -小見出しC<<

    >>になります。 - -=item * - -行をマイナス-ではじめると、 -箇条書きC<<
      >>になります。 -マイナスの数が増えるとレベルが下がります(3レベルまで) - - -項目1 - --項目1-1 - --項目1-2 - -項目2 - -項目3 - --項目3-1 - ---項目3-1-1 - ---項目3-1-2 - --項目3-2 - -=item * - -コロンを使うと、 -用語と解説文のリストC<<
      >>が書けます。 - - :用語1:いろいろ書いた解説文1 - :用語2:いろいろ書いた解説文2 - :用語3:いろいろ書いた解説文3 - -=item * - -リンク - -=over 4 - -=item * - -LinkToSomePageやFrontPageのように、 -英単語の最初の一文字を大文字にしたものが -二つ以上連続したものはYukiWikiのページ名となり、 -それが文章中に含まれるとリンクになります。 - -=item * - -http://www.hyuki.com/ のようなURLは自動的にリンクになります。 - -=item * - -二重の大かっこ[[ ]]でくくった文字列も、 -YukiWikiのページ名になります。 -大かっこの中にはスペースを含めてはいけません。 -日本語も使えます。 - -=back - -=item * - -行頭がスペースやタブで始まっていると、 -それは整形済みの段落C<<
       >>として扱われます。
      -プログラムの表示などに使うと便利です。
      -
      -
      -=item *
      -
      -行を > ではじめると、
      -引用文C<< 
      >>が書けます。 ->の数が多いとインデントが深くなります(3レベルまで)。 - - >文章 - >文章 - >>さらなる引用 - >文章 - -=back - -=head1 更新履歴 - -=over 4 - -=item * - -2001年10月20日、Version 1.6.6。 - -更新の衝突対策。 -元ページの簡単なチェックサムを取っておき、 -更新前にチェックサムを比較する。 -修正個所はdigestという文字列を検索すれば分かる。 -本来はMD5などでちゃんとやった方がいいのだけれど。 - -衝突時に表示されるメッセージなどは「極悪」さんのページを参考にした。 - -=item * - -2001年10月17日、Version 1.6.5。 - -プレビュー画面で、更新ボタンを押したときに送信される -メッセージの内容をinput要素のtype="hidden"を使って埋め込むのをやめる。 -代わりに、textarea要素を使う。 -再プレビュー用にmyspecial_を導入。でもきれいな対策ではない。 - -=item * - -2001年8月30日、Version 1.6.4。 - -URLでダイレクトにページ名を指定しても、 -$WikiNameと$BracketName以外のページを作れないようにした。 -(is_valid_nameとis_editable参照)。 - -=item * - -2001年8月30日、Version 1.6.3。 - -RecentChangesを編集・再編集不可とした。 -編集不可ページは@uneditableにページ名を入れる。 - -=item * - -2001年2月25日、Version 1.6.1, 1.6.2。 - -差分機能のバグ修正。 -do_previewで'>'が扱えないバグを修正 -(ユーザからの指摘)。 - -=item * - -2001年2月22日、Version 1.6.0。 -差分機能を実装した。 - -=item * - -2001年2月19日、Version 1.5.4。 -画像ファイルへのリンクは画像にしてみた。 - -=item * - -2001年2月19日、Version 1.5.3。 -RecentChangesの中に削除したページがあるのをやめた。 -use strict;で引っかかる部分を少し整理(完全ではない)。 - -=item * - -2001年2月16日、Version 1.5.2。 -textareaに表示およびプレビューする前に < や > を < や > に変換した -(do_preview, editpage, print_preview_buttons)。 - -=item * - -2000年12月27日、Version 1.5.1。 -プレビュー画面を整理した。 - -=item * - -2000年12月22日、Version 1.5.0。 -全体的にずいぶん書き直した。 -一覧を別途作成するようにした(do_list)。 -書き込む前に確認画面を出すようにした(do_preview)。 -テキストの書き方を編集画面に入れた(do_edit, do_reedit)。 -WhatsNew→RecentChanges、TopPage→FrontPageに変更した。 - -=item * - -2000年12月20日、Version 1.1.0。 -tieを利用して、dbmopenが使えない場合でも動作するように修正。 -利用者の1人である「極悪」さんから -送っていただいたコードを元にしています。 - -=item * - -2000年9月5日、Version 1.0.2。 - → -利用者からの指摘による。感謝。 - -=item * - -2000年8月6日、Version 1.0.1を公開。 -C MAGAZINE(ソフトバンクパブリッシング) -2000年10月号連載記事向け公開版。 -[[ ]] の最後が「望」のようにシフトJISで -0x5Dになる場合の回避を行なった。 - -=item * - -2000年8月5日、Version 1.0.0を公開。 - -=item * - -2000年7月23日、Version 0.82を公開。 -編集時のリンクミス。 -
      + + +
      +

      ・ニ・ュ・ケ・ネターキチ、ホ・。シ・

      + +

      トフセ、マニホマ、キ、ソハクサ、ャ、ス、ホ、゙、゙スミホマ、オ、、゙、ケ、ャ。「 +ーハイシ、ホ・。シ・、ヒスセ、テ、ニ・ニ・ュ・ケ・ネターキチ、ケヤ、ヲ、ウ、ネ、ャ、ヌ、ュ、゙、ケ。」

      + +
        +
      • +カケヤ、マテハヘ、ホカ霏レ、熙ネ、ハ、熙゙、ケ。」 + +
      • +HTML、ホ・ソ・ー、マス、ア、゙、サ、。」 + +
      • +''カットエ''、ホ、隍ヲ、ヒ・キ・・ー・・ッ・ゥ。シ・ネニ、ト、ヌ、マ、オ、爨ネ。「カットエ、ヒ、ハ、熙゙、ケ。」 + +
      • +'''ケケ、ヒカットエ'''、ホ、隍ヲ、ヒ・キ・・ー・・ッ・ゥ。シ・ネサー、ト、ヌ、マ、オ、爨ネ。「ケケ、ヒカットエ、ヒ、ハ、熙゙、ケ。」 + +
      • +----、ホ、隍ヲ、ヒ・゙・、・ハ・ケ4、ト、ャ、「、、ネ。「ソ衞ソタ、ヒ、ハ、熙゙、ケ。」 + +
      • +*、ケヤニャ、ヒス、ッ、ネツ邵ォスミ、キ、ヒ、ハ、熙゙、ケ。」 + +
      • +**、ケヤニャ、ヒス、ッ、ネセョクォスミ、キ、ヒ、ハ、熙゙、ケ。」 + +
      • +-、ケヤニャ、ヒス、ッ、ネイユセス、ュ、ヒ、ハ、熙゙、ケ。」- -- --- 、ホ3・・ル・、ャ、「、熙゙、ケ。」 + +
      • +:、ケヤニャ、ヒス、ッ、ネヘムク、ネイタ簗ク、ャコ、、゙、ケ。」 + +
        +    :ヘムク1:、、、、、、ス、、、ソイタ簗ク1
        +    :ヘムク2:、、、、、、ス、、、ソイタ簗ク2
        +    :ヘムク3:、、、、、、ス、、、ソイタ簗ク3
        +
        + +
      • +http://www.hyuki.com/ 、ホ、隍ヲ、ハURL、マシォニーナェ、ヒ・・・ッ、ヒ、ハ、熙゙、ケ。」 + +
      • +YukiWiki、ホ、隍ヲ、ヒツ醋クサセョハクサ、コョ、シ、ソアムハクサホ、ス、ッ、ネ。「 +YukiWiki、ホ・レ。シ・クフセ、ヒ、ハ、熙゙、ケ。」 + +
      • +[[キセケタ]]、ホ、隍ヲ、ヒニスナ、ホツ遉ォ、テ、ウ[[ ]]、ヌ、ッ、ッ、テ、ソハクサホ、ス、ッ、ネ。「 +YukiWiki、ホ・レ。シ・クフセ、ヒ、ハ、熙゙、ケ。」 +ツ遉ォ、テ、ウ、ホテ讀ヒ、マ・ケ・レ。シ・ケ、エ゙、皃ニ、マ、、、ア、゙、サ、。」 +ニヒワク、篏ネ、ィ、゙、ケ。」 + +
      • +ケヤニャ、ャ・ケ・レ。シ・ケ、ヌサマ、゙、テ、ニ、、、、ネ。「 +、ス、ホテハヘ、マターキチコム、゚ーキ、、、゙、ケ。」 +・ラ・・ー・鬣爨ス、ュケ、爨ネ、ュ、ヒサネ、ヲ、ネハリヘ、ヌ、ケ。」 + +
      • +> 、ケヤニャ、ヒス、ッ、ネ。「 +ーヘムハク、ャス、ア、゙、ケ。」 +> 、ホソ、ャツソ、、、ネ・、・・ヌ・・ネ、ャソシ、ッ、ハ、熙゙、ケ。ハ3・・ル・、゙、ヌ。ヒ。」 + +
      +EOD + &print_footer; +} + +# ・レ。シ・ク、ホク。コ +sub do_search { + if ($form{myword}) { + &print_header('ク。コキイフ'); + print qq|

      $IconTag$form{myword}、ホク。コキイフ

      \n|; + &print_toolbar(); + print qq|
        \n|; + my $count = 0; + foreach my $page_name (sort keys %database) { # sort、ケ、、ホ、マフオヒナ、ォ、ハ + if ($database{$page_name} =~ /\Q$form{'myword'}\E/) { + my $encoded = &encode_percent($page_name); + print qq|
      • $page_name\n|; + $count++; + } + } + print qq|
      \n|; + if ($count > 0) { + print qq|

      $form{myword}、エ゙、爭レ。シ・ク、マ。「セ螟ヒシィ、ケ$count ・レ。シ・ク、ヌ、ケ。」

      \n|; + } else { + print qq|

      $form{myword}、エ゙、爭レ。シ・ク、マクォ、ト、ォ、熙゙、サ、。」

      \n|; + } + } else { + &print_header('テアクク。コ'); + print qq|

      $IconTagテアクク。コ

      \n|; + &print_toolbar(); + } + print <<"EOD"; +

      +

      + + + +
      +

      +EOD + &print_footer; +} + +# ・レ。シ・ク、ホーヘ +sub do_list { + &print_header('・レ。シ・クーヘ'); + print qq|

      $IconTag ・レ。シ・クーヘ

      \n|; + &print_toolbar(); + print qq|
        \n|; + foreach my $page_name (sort keys %database) { # sort、ケ、、ホ、マフオヒナ、ォ、ハ + my $encoded = &encode_percent($page_name); + print qq|
      • $page_name\n| + } + print qq|
      \n|; + &print_footer; +} + +# ・ラ・・モ・蝪シ +sub do_preview { + my $page_name = $form{mypage}; + my $escapedmsg = &escape($form{mymsg}); + &print_header($page_name); + print qq|

      $IconTag${page_name}、ホ・ラ・・モ・蝪シ

      \n|; + &print_toolbar($page_name); + # local $percent_name = &encode_percent($page_name); + print qq|

      ーハイシ、ホ・ラ・・モ・蝪シ、ウホヌァ、キ、ニ。「、隍ア、、ミ・レ。シ・クイシノ、ホ・ワ・ソ・、ヌケケソキ、キ、ニ、ッ、タ、オ、、。」

      \n|; + if ($form{mymsg}) { + print qq|
      \n|; + # print &convert_html($escapedmsg); + print &convert_html($form{mymsg}); + print qq|
      \n|; + } else { + print qq|

      。ハ・レ。シ・ク、ホニ簣ニ、マカ、ヌ、ケ。」ケケソキ、ケ、、ネ、ウ、ホ・レ。シ・ク、マコス、オ、、゙、ケ。」。ヒ

      \n|; + } + &print_preview_buttons($page_name, $escapedmsg, $form{mydigest}); + &print_footer; +} + +sub print_preview_buttons { + my ($page_name, $escapedmsg, $digest) = @_; + print <<"EOD"; +
      + +
      + + + + +
      +EOD +} + +# ス、ュケ、 +sub do_write { + if (not &is_editable($form{mypage})) { + # ハヤスクノヤイト・レ。シ・ク、マノスシィ、ホ、゚ + &do_read; + return; + } + + my $page_name = $form{mypage}; + + # digest、サネ、テ、ニ。「ケケソキ、ホセラニヘ・チ・ァ・テ・ッ + my $original_digest = &calc_message_digest(&get_page($page_name)); + if ($form{mydigest} ne $original_digest) { + &print_header($page_name); + print qq|

      $IconTag${page_name}、ヌ。レケケソキ、ホセラニヘ。ロ、ャオッ、ュ、゙、キ、ソ

      \n|; + print <<"EOD"; +

      、「、ハ、ソ、ャ、ウ、ホ・レ。シ・ク、ハヤスク、キ、ニ、、、エヨ、ヒ。「 +ツセ、ホソヘ、ャニア、ク・レ。シ・ク、ケケソキ、キ、ニ、キ、゙、テ、ソ、隍ヲ、ヌ、ケ。」 +

      +ーハイシ、ヒ。「、「、ハ、ソ、ホハヤスク、キ、ソ・ニ・ュ・ケ・ネ、ャ、「、熙゙、ケ、ホ、ヌ。「 +、「、ハ、ソ、ホハヤスクニ簣ニ、ャシコ、、、ハ、、、隍ヲ、ヒ。「 +、、、゙、ケ、ー。「・皈籠「、ハ、ノ、ヒ・ウ・ヤ。シ。・レ。シ・ケ・ネ、キ、ニ、ッ、タ、オ、、。」 +

      +・ウ・ヤ。シ。・レ。シ・ケ・ネ、ャコム、、ヌ、ォ、鬘「 +コヌソキ、ホニ簣ニ、クォ、ニコニナルハヤスク、キトセ、キ、ニ、ッ、タ、オ、、。」 +コヌソキ、ホニ簣ニ、マ +$form{mypage} +、ヌクォ、、ウ、ネ、ャ、ヌ、ュ、゙、ケ。」 +

      +EOD + # &print_toolbar($page_name); + &print_preview_buttons($page_name, &escape($form{mymsg}), $form{mydigest}); + &print_footer; + return; + } + + # diffタクタョ + { + &opendiff; + my @msg1 = split(/\n/, &get_page($page_name)); + my @msg2 = split(/\n/, $form{mymsg}); + $msgrefA = \@msg1; + $msgrefB = \@msg2; + &diff_check; + $diffbase{$form{mypage}} = $diff_text; + $diff_text = ''; + &closediff; + } + + &print_header($page_name); + &set_page($page_name, $form{mymsg}); + if ($form{mymsg}) { + print qq|

      $IconTag${page_name}、ケケソキ、キ、゙、キ、ソ

      \n|; + &print_toolbar($page_name); + print &convert_html(&get_page($page_name)); + } else { + print qq|

      $IconTag${page_name}、コス、キ、゙、キ、ソ

      \n|; + &print_toolbar($page_name); + print qq|

      ${page_name}、コス、キ、゙、キ、ソ。」

      \n|; + } + &print_footer; + # ケケソキ、オ、、ソ、ホ、ヌ・ソ・テ・チ、キ、ニ、ェ、ッ。」 + if ($touchfile) { + open(FILE, "> $touchfile"); + print FILE "\n"; + close(FILE); + } +} + +# ・レ。シ・ク、ホハムケケナタ +sub do_diff { + if (not &is_editable($form{mypage})) { + # ハヤスクノヤイト・レ。シ・ク、マノスシィ、ホ、゚ + &do_read; + return; + } + &opendiff; + &print_header($form{mypage} . '、ホハムケケナタ'); + print qq|

      $IconTag $form{mypage}、ホハムケケナタ

      \n|; + &print_toolbar(); + $_ = &escape($diffbase{$form{mypage}}); + print <<"EOD"; +
        +
      • トノイテ、オ、、ソケヤ、マタトソァ、ヌ、ケ。」 +
      • コス、オ、、ソケヤ、マタヨソァ、ヌ、ケ。」 +
      • $form{mypage}、リケヤ、ッ。」 +
      +
      +EOD + print qq|
      \n|;
      +    foreach (split(/\n/, $_)) {
      +        if (/^\+(.*)/) {
      +            print qq|$1\n|;
      +        } elsif (/^\-(.*)/) {
      +            print qq|$1\n|;
      +        } elsif (/^\=(.*)/) {
      +            print qq|$1\n|;
      +        } else {
      +            print qq|??? $_\n|;
      +        }
      +    }
      +    print qq|
      \n|; + &print_footer; + &closediff; +} + +sub opendiff { + if ($dbmopen) { + if (!dbmopen(%diffbase, $diffdbname, 0666)) { + &print_error("(dbmopen) $diffdbname 、ャコ、、゙、サ、。」"); + } + } else { + if (!tie(%diffbase, "YukiWikiDB", $diffdbname)) { + &print_error("(tie error)"); + } + } +} + +sub closediff { + if ($dbmopen) { + dbmclose(%diffbase); + } else { + untie(%diffbase); + } +} + +# ・ユ・ゥ。シ・爨ォ、鬢ホセハ、マ「チロヌロホ %form 、ヒニ、、 +# &init_form('euc'); +sub init_form { + my ($charcode) = @_; + my $query; + if ($ENV{REQUEST_METHOD} =~ /^post$/i) { + read(STDIN, $query, $ENV{CONTENT_LENGTH}); + } else { + $query = $ENV{QUERY_STRING}; + } + my @assocarray = split(/[&;]/, $query); + foreach my $assoc (@assocarray) { + my ($property, $value) = split(/=/, $assoc); + $value =~ tr/+/ /; + $value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg; + &jcode::convert(\$value, $charcode); + $form{$property} = $value; + } +} + +# ・ィ・鬘シ・レ。シ・ク、スミホマ、ケ、 +sub print_error { + my ($msg) = @_; + &print_header('Error'); + print "

      $IconTag$msg

      "; + exit(0); +} + +sub escape { + my ($line) = shift; + $line =~ s|<|<|g; + $line =~ s|>|>|g; + $line =~ s|"|"|g; + # $line =~ s|\&|&|g; + return $line; +} + +sub inline { + my ($line) = shift; + $line = &escape($line); + $line =~ s|'''([^']+?)'''|$1|g; + $line =~ s|''([^']+?)''|$1|g; + $line =~ s! + ( + ((mailto|http|https|ftp):[\x21-\x7E]*) # Direct http://... + | + ($WikiName) # LocalLinkLikeThis + | + ($BracketName) # [[ニヒワク・・・ッ]] + ) + ! + &make_link($1) + !gex; + return $line; +} + +# ・レ。シ・ク、ホ・ソ・、・ネ・、ォ、鬣レ。シ・ク、ホニ簣ニ、ニタ、 +sub get_page { + my $page_name = shift; + return $database{$page_name}; +} + +# ・レ。シ・ク、ホニ簣ニ、ヘソ、ィ、 +# &set_page($title, $txt) +sub set_page { + # ・レ。シ・ク、ケケソキ、ケ、 + my $title = $_[0]; + $database{$title} = $_[1]; + # カ・レ。シ・ク、ハ、鮗ス、ケ、 + unless ($database{$title}) { + delete $database{$title}; + } + # RecentChanges、ケケソキ、ケ、 + my $delim = ' - '; + my @pages = split(/\n/, $database{$whatsnew}); + my $datestr = &get_current_datestr; + unshift(@pages, qq|-$datestr$delim$title|); + # ニアー・レ。シ・ク、ホケケソキ、マコヌソキ、ホ、筅ホ、ホ、゚、ヒ、キ。「 + # ツクコ゚、キ、ハ、、・レ。シ・ク、マ・ケ・ュ・テ・ラ、ケ、。」 + my %count; + my @newpages; + foreach my $line (@pages) { + my ($prefix, $title) = split(/$delim/, $line); + $count{$title}++; + if ($count{$title} == 1 and exists($database{$title})) { + push(@newpages, qq|$prefix - $title|); + } + } + # 、ウ、ウ、ヌヒワナ、ヒケケソキ + $database{$whatsnew} = join("\n", splice(@newpages, 0, $maxnew)); +} + +# ・レ。シ・ク、ホ・リ・テ・タ、スミホマ +sub print_header { + my $title = shift; + print <<"EOD"; +Content-type: text/html + + +$title + + + +EOD +} + +# ・ト。シ・・ミ。シ、スミホマ +sub print_toolbar { + my $page_name = shift; + my $percent_name = &encode_percent($page_name); + my $editlink = ''; + if ($page_name ne '' and &is_editable($page_name)) { + $editlink = <<"EOD"; +ハヤスク | +コケハャ | +EOD + } + print <<"EOD"; +

      + [ +・ネ・テ・ラ | +ーヘ | +$editlink +テアクク。コ | +コヌスェケケソキ + ] +

      +EOD +} + +# ・レ。シ・ク、ホ・ユ・テ・ソ、スミホマ +sub print_footer { + print <<"EOD"; +
      +YukiWiki 1.6.6 Copyright (C) 2000,2001 by Hiroshi Yuki. ++ $modifier ${version}. +[/ +テマゾ +ク。コ] +
      + +EOD +} + +# URL、茹レ。シ・ク、ホフセチー、ォ、鬣・・ッ、コ、 +sub make_link { + my $name = shift; + if ($name =~ /^(http|https|ftp).*?(\.gif|\.png|\.jpeg|\.jpg)?$/) { + if ($2) { + return qq||; + } else { + return qq|$name|; + } + } elsif ($name =~ /^mailto:(.*)/) { + my $address = $1; + return qq|$address|; + } elsif ($database{$name}) { + my $percent_name = &encode_percent($name); + return qq|$name|; + } else { + my $percent_name = &encode_percent($name); + return qq|$name?|; + } +} + +# %xx 、ホキチシー、ヒ・ィ・・ウ。シ・ノ、ケ、 +# 、ウ、、マ。「 +# http://www.hyuki.com/yukiwiki/yukiwiki.cgi?mycmd=read&mypage=%3C%8C%8B%8F%E9%8D_%3E +# 、ネ、、、ヲキチシー、ホ、ソ、皃ヒサネ、、、。」 +# '<キセケタ>' 「ェ '%3C%8C%8B%8F%E9%8D_%3E' +sub encode_percent { + my $name = shift; + my $encoded = ''; + foreach my $ch (split(//, $name)) { + if ($ch =~ /[A-Za-z0-9_]/) { + $encoded .= $ch; + } else { + $encoded .= '%' . sprintf("%02X", ord($ch)); + } + } + return $encoded; +} + +# ・ニ・ュ・ケ・ネヒワツホ、HTML、ヒハムエケ、ケ、 +sub convert_html { + my ($txt) = shift; + my (@txt) = split(/\n/, $txt); + foreach (@txt) { + chomp; + if (/^\*\*(.*)/) { + push(@result, splice(@saved), '

      ' . &inline($1) . '

      '); + } elsif (/^\*(.*)/) { + push(@result, splice(@saved), '

      ' . &inline($1) . '

      '); + } elsif (/^----/) { + push(@result, splice(@saved), '
      '); + } elsif (/^(-{1,3})(.*)/) { + &back_push('ul', length($1)); + push(@result, '
    • ' . &inline($2) . '
    • '); + } elsif (/^:([^:]+):(.*)/) { + &back_push('dl', 1); + push(@result, '
      ' . &inline($1) . '
      ', '
      ' . &inline($2) . '
      '); + } elsif (/^(>{1,3})(.*)/) { + &back_push('blockquote', length($1)); + push(@result, &inline($2)); + } elsif (/^\s*$/) { + push(@result, splice(@saved)); + unshift(@saved, "

      "); + push(@result, "

      "); + } elsif (/^(\s+.*)$/) { + &back_push('pre', 1); + push(@result, &escape($1)); # Not &inline, but &escape + } else { + push(@result, &inline($_)); + } + } + push(@result, splice(@saved)); + return join("\n", @result); +} + +# &back_push($tag, $count) +# $tag、ホ・ソ・ー、$level・・ル・、゙、ヌオヘ、皃。」 +sub back_push { + my ($tag, $level) = @_; + while (@saved > $level) { + push(@result, shift(@saved)); + } + if ($saved[0] ne "") { + push(@result, splice(@saved)); + } + while (@saved < $level) { + unshift(@saved, ""); + push(@result, "<$tag>"); + } +} + +# ハヤスクイトヌス・レ。シ・ク、ォ。ゥ +sub is_editable { + my ($pagename) = @_; + foreach (@uneditable) { + if ($pagename eq $_) { + return 0; + } + } + if (&is_valid_name($pagename)) { + return 1; + } + return 0; +} + +# Valid、ハフセチー、ォ。ゥ +sub is_valid_name { + my ($pagename) = @_; + if ($pagename =~ /^$WikiName$/) { + return 1; + } elsif ($pagename =~ /^$BracketName$/) { + return 1; + } else { + return 0; + } +} + +# クスコ゚サケ、ホハクサホ、ニタ、 +sub get_current_datestr { + my (@wdays) = ( "ニ", "キ", "イミ", "ソ", "フレ", "カ", "ナレ" ); + my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time); + return sprintf("%4d-%02d-%02d (%s) %02d:%02d:%02d", + $year + 1900, $mon + 1, $mday, $wdays[$wday], $hour, $min, $sec); +} + +# URL?SomePage、茖「 +# URL?[[キセケタ]]、ホキチシー、タ、テ、ソセケ遑「(not yet) +# カッタゥナェ、ヒmycmd、read、ヒ、キ、ニ$form、ホニ簣ニ、タ゚ト熙ケ、。」 +sub normalize_form { + foreach my $key (keys %form) { + if ($key =~ /^$WikiName$/) { + $form{mycmd} = 'read'; + $form{mypage} = $1; + last; + } elsif ($key =~ /^$BracketName$/) { + $form{mycmd} = 'read'; + $form{mypage} = $1; + last; + } + } +} + +# ハムエケ・ニ・ケ・ネ、ケヤ、ハ、ヲ、ネ、ュ、ホ・オ・・ラ・ +sub print_sample { + my $txt = &convert_html(<<"EOD"); +*ツ邵ォスミ、キ1 +**セョクォスミ、キ1-1 +-ケ猯ワ1 +-ケ猯ワ2 +-ケ猯ワ3 +テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ''カットエ''1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 + +テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2 +テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2 +テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2 +**セョクォスミ、キ1-2 +:ヘムク1:、、、、、、ス、、、ソイタ簗ク1、ネ''カットエテアク'' +テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +:ヘムク2:、、、、、、ス、、、ソイタ簗ク2 +:ヘムク3:、、、、、、ス、、、ソイタ簗ク3 +---- +*ツ邵ォスミ、キ2 +**セョクォスミ、キ2-1 +http://www.hyuki.com/ +**セョクォスミ、キ2-2 + +[[キセケタ]] + +テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +テハヘ1テハヘ1テハヘ1テハヘ'''カットエ'''1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +テハヘ1テハヘ1テハヘ1テハヘ'''''カッ、、カットエ'''''1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1テハヘ1 +>テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2 +>テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2 +>テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2テハヘ2 + +・・ル・0・・ル・0・・ル・0・・ル・0・・ル・0・・ル・0 + +>・・ル・1 +>・・ル・1 +>・・ル・1 +>>・・ル・2 +>>・・ル・2 +>>・・ル・2 +>>>・・ル・3 +-、マ、1 +--、マ、2 +、、、、2 +---、マ、3 +--、マ、2 +---、マ、3 +--、マ、2 +---、マ、3 +>>>・・ル・3 +>>>・・ル・3 +>>>・・ル・3 +EOD + print $txt; + exit; +} + +sub diff_check { + traverse_sequences( + $msgrefA, $msgrefB, + { + MATCH => \&df_match, + DISCARD_A => \&df_delete, + DISCARD_B => \&df_add, + } + ); + &diff_flush; +} + +sub diff_flush { + $diff_text .= join('', map { "-$_\n" } splice(@diff_deleted)); + $diff_text .= join('', map { "+$_\n" } splice(@diff_added)); +} + +sub df_match { + my ($a, $b) = @_; + &diff_flush; + $diff_text .= "=$msgrefA->[$a]\n"; +} + +sub df_delete { + my ($a, $b) = @_; + push(@diff_deleted, $msgrefA->[$a]); +} + +sub df_add { + my ($a, $b) = @_; + push(@diff_added, $msgrefB->[$b]); +} + +sub calc_message_digest { # You have to use MD5... + my $text = shift; + my @text = split(//, $text); + my $len = length($text); + my $checksum = 0; + foreach (@text) { + $checksum += ord($_); + $checksum = ($checksum * 2) % 65536 + (($checksum & 32768) ? 1 : 0); # 16bit rotate + } + return "$len:$checksum"; +} + +# Definition of YukiWikiDB +package YukiWikiDB; + +my $debug = 1; + +# Constructor +sub new { + return shift->TIEHASH(@_); +} + +# tying +sub TIEHASH { + my ($class, $dbname) = @_; + my $self = { + dir => $dbname, + keys => [], + }; + if (not -d $self->{dir}) { + if (!mkdir($self->{dir}, 0777)) { + print "mkdir(" . $self->{dir} . ") fail\n" if ($debug); + return undef; + } + } + return bless($self, $class); +} + +# Store +sub STORE { + my ($self, $key, $val) = @_; + my $file = &make_filename($self, $key); + if (open(FILE,"> $file")) { + binmode(FILE); + print FILE $val; + close(FILE); + return $self->{$key} = $val; + } else { + print "$file create error."; + } +} + +# Fetch +sub FETCH { + my ($self, $key) = @_; + my $file = &make_filename($self, $key); + if (open(FILE, $file)) { + local $/; + $self->{$key} = ; + close(FILE); + } + return $self->{$key}; +} + +# Exists +sub EXISTS { + my ($self, $key) = @_; + my $file = &make_filename($self, $key); + return -e($file); +} + +# Delete +sub DELETE { + my ($self, $key) = @_; + my $file = &make_filename($self, $key); + unlink $file; + return delete $self->{$key}; +} + +sub FIRSTKEY { + my ($self) = @_; + opendir(DIR, $self->{dir}) or die $self->{dir}; + @{$self->{keys}} = grep /\.txt$/, readdir(DIR); + foreach my $name (@{$self->{keys}}) { + $name =~ s/\.txt$//; + $name =~ s/[0-9A-F][0-9A-F]/pack("C", hex($&))/eg; + } + return shift @{$self->{keys}}; +} + +sub NEXTKEY { + my ($self) = @_; + return shift @{$self->{keys}}; +} + +sub make_filename { + my ($self, $key) = @_; + my $enkey = ''; + foreach my $ch (split(//, $key)) { + $enkey .= sprintf("%02X", ord($ch)); + } + return $self->{dir} . "/$enkey.txt"; +} +__END__ + +=head1 NAME + +YukiWiki - シォヘウ、ヒ・レ。シ・ク、トノイテ。ヲコス。ヲハヤスク、ヌ、ュ、Web・レ。シ・クケステロCGI + + Copyright (C) 2000,2001 by Hiroshi Yuki. + キセケタ + http://www.hyuki.com/ + http://www.hyuki.com/yukiwiki/ + +=head1 SYNOPSIS + + http://www.hyuki.com/yukiwiki/yukiwiki.cgi + +=head1 DESCRIPTION + +YukiWiki。ハキセ・ヲ・」・ュ・」。ヒ、マサイイテシヤ、ャシォヘウ、ヒ・レ。シ・ク、トノイテ。ヲコス。ヲハヤスク、ヌ、ュ、 +ノヤサラオト、ハWeb・レ。シ・クキイ、コ、CGI、ヌ、ケ。」 +Web、ヌニーコ、ケ、キヌシィネト、ネ、チ、遉テ、ネサ、ニ、、、゙、ケ、ャ。「 +Webキヌシィネト、ャテア、ヒ・皈テ・サ。シ・ク、トノイテ、ケ、、タ、ア、ハ、ホ、ヒツミ、キ、ニ。「 +YukiWiki、マ。「Web・レ。シ・クチエツホ、シォヘウ、ヒハムケケ、ケ、、ウ、ネ、ャ、ヌ、ュ、゙、ケ。」 + +YukiWiki、マ。「Cunningham & Cunningham、ホWikiWikiWeb、ホ +サナヘヘ、サイケヘ、ヒ、キ、ニニネシォ、ヒコ、鬢、゙、キ、ソ。」 + +YukiWiki、マPerl、ヌス、ォ、、ソCGI・ケ・ッ・・ラ・ネ、ネ、キ、ニシツクス、オ、、ニ、、、゙、ケ、ホ、ヌ。「 +Perl、ャニーコ、ケ、Web・オ。シ・ミ、ハ、鬢ミネ豕モナェヘニーラ、ヒタ゚テヨ、ヌ、ュ、゙、ケ。」 + +、「、ネ、マdbmopen、ャサネ、ィ、エトカュ、ハ、鬢ミタ゚テヨ、ヌ、ュ、゙、ケ(Version 1.5.0ーハケ゚、ハ、馘bmopen、ャサネ、ィ、ハ、ッ、ニ、簑゚テヨ、ヌ、ュ、゙、ケ)。」 + + +YukiWiki、マ・ユ・遙シ・ス・ユ・ネ、ヌ、ケ。」 +、エシォヘウ、ヒ、ェサネ、、、ッ、タ、オ、、。」 + +=head1 タ゚テヨハヒ。 + +=head2 ニシ + +YukiWiki、ホコヌソキネヌ、マ。「 +http://www.hyuki.com/yukiwiki/ +、ォ、鯣シ熙ヌ、ュ、゙、ケ。」 + +=head2 ・ユ・。・、・ーヘ + + readme.txt ・ノ・ュ・螂皈・ネ + yukiwiki.cgi YukiWikiヒワツホ + yukiwiki.gif ・・エ。ハ・ォ・鬘シネヌ。ヒ + yukimono.gif ・・エ。ハ・筵ホ・ッ・ネヌ。ヒ + jcode.pl エチサ・ウ。シ・ノ・鬣、・ヨ・鬣 + +=head2 ・、・・ケ・ネ。シ・ + +=over 4 + +=item 1. + +・「。シ・ォ・、・ヨ、イ、ッ。」 + +=item 2. + +yukiwiki.cgi、ホ、マ、ク、皃ホハ、ヒ、「、タ゚ト熙ウホヌァ、キ、゙、ケ。」 +トフセ、マイソ、筅キ、ハ、ッ、ニ、隍、、ャ。「 +、マ、ク、皃マ$touchfile、''、ヒ、キ、ソハ、ャ、隍、、ヌ、キ、遉ヲ。」 + +=item 3. + +yukiwiki.cgi、ネjcode.pl、ニア、ク、ネ、ウ、、ヒタ゚テヨ、キ、゙、ケ。」 + +=item 4. + +・オ・、・コ0、ホyukiwiki.db、ネ、、、ヲ・ユ・。・、・、タ゚テヨ、キ、゙、ケ。」 +。ハPerl・キ・ケ・ニ・爨ヒ、隍テ、ニ、マyukiwiki.pag, yukiwiki.dir。ヒ + +=item 5. + +yukiwiki.cgi、ヒ・ヨ・鬣ヲ・カ、ォ、鬣「・ッ・サ・ケ、キ、゙、ケ。」 + +=back + +=head2 ・ム。シ・゚・テ・キ・逾 + + ・ユ・。・、・ ・ム。シ・゚・テ・キ・逾 ナセチ・筍シ・ノ + yukiwiki.cgi 755 ASCII + yukiwiki.gif 644 BINARY + yukimono.gif 644 BINARY + jcode.pl 644 ASCII + + $dbmopen = 1; 、ヒ、キ、ソセケ: + yukiwiki.db 666 BINARY + (yukiwiki.pag, yukiwiki.dir、ホセケ遉筅「、遙ヒ + + $dbmopen = 0; 、ヒ、キ、ソセケ: (・ォ・・・ネ・ヌ・」・・ッ・ネ・熙777、ヒ、キ、ニ、ェ、ッ) + . 777 (ナセチ、キ、ハ、、) + +=head1 ・ヌ。シ・ソ、ホ・ミ・テ・ッ・「・テ・ラハヒ。 + +$dbmopen = 1;、ホセケ遉マ。「 +・ヌ。シ・ソ、マ、ケ、ル、ニyukiwiki.db(.dir, .pag)、ヒニ、。」 +、ウ、、・ミ・テ・ッ・「・テ・ラ、ケ、、ミ、隍、。」 + +$dbmopen = 0;、ホセケ遉マ。「 +yukiwiki、ネ、、、ヲ・ヌ・」・・ッ・ネ・熙ャ、ヌ、ュ、、ホ、ヌ。「 +、ウ、ーハイシ、・ミ・テ・ッ・「・テ・ラ、ケ、、ミ、隍、。」 + +=head1 ソキ、キ、、・レ。シ・ク、ホコ、ハ + +=over 4 + +=item 1. + +、゙、コ。「ナャナ、ハ・レ。シ・ク。ハホ网ィ、ミFrontPage。ヒ、チェ、モ。「 +・レ。シ・ク、ホイシ、ヒ、「、。ヨハヤスク。ラ・・・ッ、、ソ、ノ、熙゙、ケ。」 + +=item 2. + +、ケ、、ネ・ニ・ュ・ケ・ネニホマ、ャ、ヌ、ュ、セツヨ、ヒ、ハ、、ホ、ヌ。「 +、ス、ウ、ヒNewPage、ホ、隍ヲ、ハテアク +。ハツ醋クサセョハクサコョコ゚、キ、ニ、、、アムハクサホ。ヒ +、ス、、、ニ。ヨハンツク。ラ、キ、゙、ケ。」 + +=item 3. + +ハンツク、ケ、、ネ。「FrontPage、ホ・レ。シ・ク、ャス、ュエケ、、遙「 +、「、ハ、ソ、ャス、、、ソNewPage、ネ、、、ヲハクサホ、ホク螟、ヒ ? 、ネ、、、ヲ・・・ッ、ャノスシィ、オ、、゙、ケ。」 +、ウ、ホ ? 、マ、ス、ホ・レ。シ・ク、ャ、゙、タツクコ゚、キ、ハ、、、ウ、ネ、シィ、ケー、ヌ、ケ。」 + +=item 4. + +、ス、ホ ? 、・ッ・・テ・ッ、ケ、、ネソキ、キ、、・レ。シ・クNewPage、ャ、ヌ、ュ、゙、ケ、ホ、ヌ。「 +、「、ハ、ソ、ホケ・、ュ、ハハクセマ、、ス、ホソキ、キ、、・レ。シ・ク、ヒス、、、ニハンツク、キ、゙、ケ。」 + +=item 5. + +NewPage・レ。シ・ク、ャ、ヌ、ュ、、ネFrontPage、ホ ? 、マセテ、ィ、ニ。「・・・ッ、ネ、ハ、熙゙、ケ。」 + +=back + +=head1 ・ニ・ュ・ケ・ネターキチ、ホ・。シ・ + +=over 4 + +=item * + +マ「ツウ、キ、ソハ」ソケヤ、マ・ユ・」・、オ、、ニノスシィ、オ、、゙、ケ。」 + +=item * + +カケヤ、マテハヘC<<

      >>、ホカ霏レ、熙ネ、ハ、熙゙、ケ。」 + +=item * + +HTML、ホ・ソ・ー、マス、ア、゙、サ、。」 + +=item * + +B<''・ワ。シ・・ノ''>、ホ、隍ヲ、ヒ・キ・・ー・・ッ・ゥ。シ・ネニ、ト、ヌ、マ、オ、爨ネ。「 +・ワ。シ・・ノC<< >>、ヒ、ハ、熙゙、ケ。」 + +=item * + +B<'''・、・ソ・・テ・ッ'''>、ホ、隍ヲ、ヒ・キ・・ー・・ッ・ゥ。シ・ネサー、ト、ヌ、マ、オ、爨ネ。「 +・、・ソ・・テ・ッC<< >>、ヒ、ハ、熙゙、ケ。」 + +=item * + +B<---->、ホ、隍ヲ、ヒ・゙・、・ハ・ケ4、ト、ャ、「、、ネ。「 +ソ衞ソタC<<


      >>、ヒ、ハ、熙゙、ケ。」 + +=item * + +ケヤ、B<*>、ヌ、マ、ク、皃、ネ。「 +ツ邵ォスミ、キC<<

      >>、ヒ、ハ、熙゙、ケ。」 + +=item * + +ケヤ、B<**>、ヌ、マ、ク、皃、ネ。「 +セョクォスミ、キC<<

      >>、ヒ、ハ、熙゙、ケ。」 + +=item * + +ケヤ、・゙・、・ハ・ケ-、ヌ、マ、ク、皃、ネ。「 +イユセス、ュC<<
        >>、ヒ、ハ、熙゙、ケ。」 +・゙・、・ハ・ケ、ホソ、ャチ、ィ、、ネ・・ル・、ャイシ、ャ、熙゙、ケ。ハ3・・ル・、゙、ヌ。ヒ + + -ケ猯ワ1 + --ケ猯ワ1-1 + --ケ猯ワ1-2 + -ケ猯ワ2 + -ケ猯ワ3 + --ケ猯ワ3-1 + ---ケ猯ワ3-1-1 + ---ケ猯ワ3-1-2 + --ケ猯ワ3-2 + +=item * + +・ウ・・、サネ、ヲ、ネ。「 +ヘムク、ネイタ簗ク、ホ・・ケ・ネC<<
        >>、ャス、ア、゙、ケ。」 + + :ヘムク1:、、、、、、ス、、、ソイタ簗ク1 + :ヘムク2:、、、、、、ス、、、ソイタ簗ク2 + :ヘムク3:、、、、、、ス、、、ソイタ簗ク3 + +=item * + +・・・ッ + +=over 4 + +=item * + +LinkToSomePage、腱rontPage、ホ、隍ヲ、ヒ。「 +アムテアク、ホコヌス鬢ホーハクサ、ツ醋クサ、ヒ、キ、ソ、筅ホ、ャ +ニ、トーハセ袞「ツウ、キ、ソ、筅ホ、マYukiWiki、ホ・レ。シ・クフセ、ネ、ハ、遙「 +、ス、、ャハクセマテ讀ヒエ゙、゙、、、ネ・・・ッ、ヒ、ハ、熙゙、ケ。」 + +=item * + +http://www.hyuki.com/ 、ホ、隍ヲ、ハURL、マシォニーナェ、ヒ・・・ッ、ヒ、ハ、熙゙、ケ。」 + +=item * + +ニスナ、ホツ遉ォ、テ、ウ[[ ]]、ヌ、ッ、ッ、テ、ソハクサホ、筍「 +YukiWiki、ホ・レ。シ・クフセ、ヒ、ハ、熙゙、ケ。」 +ツ遉ォ、テ、ウ、ホテ讀ヒ、マ・ケ・レ。シ・ケ、エ゙、皃ニ、マ、、、ア、゙、サ、。」 +ニヒワク、篏ネ、ィ、゙、ケ。」 + +=back + +=item * + +ケヤニャ、ャ・ケ・レ。シ・ケ、茹ソ・ヨ、ヌサマ、゙、テ、ニ、、、、ネ。「 +、ス、、マターキチコム、゚、ホテハヘC<<
         >>、ネ、キ、ニーキ、、、゙、ケ。」
        +・ラ・・ー・鬣爨ホノスシィ、ハ、ノ、ヒサネ、ヲ、ネハリヘ、ヌ、ケ。」
        +
        +
        +=item *
        +
        +ケヤ、 > 、ヌ、マ、ク、皃、ネ。「
        +ーヘムハクC<< 
        >>、ャス、ア、゙、ケ。」 +>、ホソ、ャツソ、、、ネ・、・・ヌ・・ネ、ャソシ、ッ、ハ、熙゙、ケ。ハ3・・ル・、゙、ヌ。ヒ。」 + + >ハクセマ + >ハクセマ + >>、オ、鬢ハ、ーヘム + >ハクセマ + +=back + +=head1 ケケソキヘホ + +=over 4 + +=item * + +2001ヌッ10キ20ニ。「Version 1.6.6。」 + +ケケソキ、ホセラニヘツミコ。」 +クオ・レ。シ・ク、ホエハテア、ハ・チ・ァ・テ・ッ・オ・爨シ隍テ、ニ、ェ、ュ。「 +ケケソキチー、ヒ・チ・ァ・テ・ッ・オ・爨ネ豕モ、ケ、。」 +ス、タオクトス熙マdigest、ネ、、、ヲハクサホ、ク。コ、ケ、、ミハャ、ォ、。」 +ヒワヘ隍マMD5、ハ、ノ、ヌ、チ、网、ネ、荀テ、ソハ、ャ、、、、、ホ、タ、ア、、ノ。」 + +セラニヘサ、ヒノスシィ、オ、、・皈テ・サ。シ・ク、ハ、ノ、マ。ヨカヒーュ。ラ、オ、、ホ・レ。シ・ク、サイケヘ、ヒ、キ、ソ。」 + +=item * + +2001ヌッ10キ17ニ。「Version 1.6.5。」 + +・ラ・・モ・蝪シイ靂フ、ヌ。「ケケソキ・ワ・ソ・、イ。、キ、ソ、ネ、ュ、ヒチソョ、オ、、 +・皈テ・サ。シ・ク、ホニ簣ニ、inputヘラチヌ、ホtype="hidden"、サネ、テ、ニヒ荀盪、爨ホ、、荀皃。」 +ツ螟、熙ヒ。「textareaヘラチヌ、サネ、ヲ。」 +コニ・ラ・・モ・蝪シヘム、ヒmyspecial_、ニウニ。」、ヌ、筅ュ、、、、ハツミコ、ヌ、マ、ハ、、。」 + +=item * + +2001ヌッ8キ30ニ。「Version 1.6.4。」 + +URL、ヌ・タ・、・・ッ・ネ、ヒ・レ。シ・クフセ、サリト熙キ、ニ、筍「 +$WikiName、ネ$BracketNameーハウー、ホ・レ。シ・ク、コ、、ハ、、、隍ヲ、ヒ、キ、ソ。」 +(is_valid_name、ネis_editableサイセネ)。」 + +=item * + +2001ヌッ8キ30ニ。「Version 1.6.3。」 + +RecentChanges、ハヤスク。ヲコニハヤスクノヤイト、ネ、キ、ソ。」 +ハヤスクノヤイト・レ。シ・ク、マ@uneditable、ヒ・レ。シ・クフセ、ニ、、。」 + +=item * + +2001ヌッ2キ25ニ。「Version 1.6.1, 1.6.2。」 + +コケハャオ。ヌス、ホ・ミ・ース、タオ。」 +do_preview、ヌ'>'、ャーキ、ィ、ハ、、・ミ・ー、ス、タオ +。ハ・譯シ・カ、ォ、鬢ホサリナヲ。ヒ。」 + +=item * + +2001ヌッ2キ22ニ。「Version 1.6.0。」 +コケハャオ。ヌス、シツチ、キ、ソ。」 + +=item * + +2001ヌッ2キ19ニ。「Version 1.5.4。」 +イ霖・ユ・。・、・、リ、ホ・・・ッ、マイ霖、ヒ、キ、ニ、゚、ソ。」 + +=item * + +2001ヌッ2キ19ニ。「Version 1.5.3。」 +RecentChanges、ホテ讀ヒコス、キ、ソ・レ。シ・ク、ャ、「、、ホ、、荀皃ソ。」 +use strict;、ヌー、テ、ォ、ォ、ノハャ、セッ、キターヘ(エーチエ、ヌ、マ、ハ、、)。」 + +=item * + +2001ヌッ2キ16ニ。「Version 1.5.2。」 +textarea、ヒノスシィ、ェ、隍モ・ラ・・モ・蝪シ、ケ、チー、ヒ < 、 > 、 < 、 > 、ヒハムエケ、キ、ソ +(do_preview, editpage, print_preview_buttons)。」 + +=item * + +2000ヌッ12キ27ニ。「Version 1.5.1。」 +・ラ・・モ・蝪シイ靂フ、ターヘ、キ、ソ。」 + +=item * + +2000ヌッ12キ22ニ。「Version 1.5.0。」 +チエツホナェ、ヒ、コ、、、ヨ、ス、ュトセ、キ、ソ。」 +ーヘ、ハフナモコタョ、ケ、、隍ヲ、ヒ、キ、ソ(do_list)。」 +ス、ュケ、狠ー、ヒウホヌァイ靂フ、スミ、ケ、隍ヲ、ヒ、キ、ソ(do_preview)。」 +・ニ・ュ・ケ・ネ、ホス、ュハ、ハヤスクイ靂フ、ヒニ、、ソ(do_edit, do_reedit)。」 +WhatsNew「ェRecentChanges。「TopPage「ェFrontPage、ヒハムケケ、キ、ソ。」 + +=item * + +2000ヌッ12キ20ニ。「Version 1.1.0。」 +tie、ヘヘム、キ、ニ。「dbmopen、ャサネ、ィ、ハ、、セケ遉ヌ、簇ーコ、ケ、、隍ヲ、ヒス、タオ。」 +ヘヘムシヤ、ホ1ソヘ、ヌ、「、。ヨカヒーュ。ラ、オ、、ォ、 +チ、テ、ニ、、、ソ、タ、、、ソ・ウ。シ・ノ、クオ、ヒ、キ、ニ、、、゙、ケ。」 + +=item * + +2000ヌッ9キ5ニ。「Version 1.0.2。」 + 「ェ +ヘヘムシヤ、ォ、鬢ホサリナヲ、ヒ、隍。」エカシユ。」 + +=item * + +2000ヌッ8キ6ニ。「Version 1.0.1、クウォ。」 +C MAGAZINE。ハ・ス・ユ・ネ・ミ・・ッ・ム・ヨ・・テ・キ・・ー。ヒ +2000ヌッ10キケ賺「コワオュサク、アクウォネヌ。」 +[[ ]] 、ホコヌク螟ャ。ヨヒセ。ラ、ホ、隍ヲ、ヒ・キ・ユ・ネJIS、ヌ +0x5D、ヒ、ハ、セケ遉ホイネ、ケヤ、ハ、テ、ソ。」 + +=item * + +2000ヌッ8キ5ニ。「Version 1.0.0、クウォ。」 + +=item * + +2000ヌッ7キ23ニ。「Version 0.82、クウォ。」 +ハヤスクサ、ホ・・・ッ・゚・ケ。」 +