/[pub]/suikawiki/script/wiki.cgi
Suika

Diff of /suikawiki/script/wiki.cgi

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.8 by wakaba, Sun Mar 24 00:51:52 2002 UTC revision 1.10 by wakaba, Sun Mar 24 01:09:03 2002 UTC
# Line 1  Line 1 
1  #!/usr/bin/perl  #!/usr/bin/perl
2  use lib "../lib";  use lib "../lib";
3  use CGI::Carp 'fatalsToBrowser';  use CGI::Carp 'fatalsToBrowser';
4  use Algorithm::Diff qw(traverse_sequences);  use Algorithm::Diff qw(traverse_sequences);
5  # use strict;  # use strict;
6  #  #
7  # yukiwiki.cgi - Yet another WikiWikiWeb clone.  # yukiwiki.cgi - Yet another WikiWikiWeb clone.
8  #  #
9  # Copyright (C) 2000,2001 by Hiroshi Yuki.  # Copyright (C) 2000,2001 by Hiroshi Yuki.
10  # <hyuki@hyuki.com>  # <hyuki@hyuki.com>
11  # http://www.hyuki.com/yukiwiki/  # http://www.hyuki.com/yukiwiki/
12  #  #
13  # This program is free software; you can redistribute it and/or modify  # This program is free software; you can redistribute it and/or modify
14  # it under the terms of the GNU General Public License as published by  # it under the terms of the GNU General Public License as published by
15  # the Free Software Foundation; either version 2 of the License, or  # the Free Software Foundation; either version 2 of the License, or
16  # (at your option) any later version.  # (at your option) any later version.
17  #  #
18  # This program is distributed in the hope that it will be useful,  # This program is distributed in the hope that it will be useful,
19  # but WITHOUT ANY WARRANTY; without even the implied warranty of  # but WITHOUT ANY WARRANTY; without even the implied warranty of
20  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  # GNU General Public License for more details.  # GNU General Public License for more details.
22  #  #
23  # $Id$  # $Id$
24  ##############################  ##############################
25  my $version = "1.6.6";  my $version = "1.6.6";
26  ##############################  ##############################
27  # 単独テストのときには 1 にする。  # 単独テストのときには 1 にする。
28  my $testing = 0;  my $testing = 0;
29  ##############################  ##############################
30  # 漢字ライブラリ  # 漢字ライブラリ
31  my $jcodelib = 'jcode.pl';  my $jcodelib = 'jcode.pl';
32  ##############################  ##############################
33  # 保存・表示の漢字コード  # 保存・表示の漢字コード
34  my $kanjicode = 'euc';     # 'sjis' 'euc'  my $kanjicode = 'euc';     # 'sjis' 'euc'
35  my $charset = 'euc-jisx0213';  # 'Shift_JIS' 'EUC-JP'  my $charset = 'euc-jisx0213';  # 'Shift_JIS' 'EUC-JP'
36  ##############################  ##############################
37  # dbmopenが使えるなら1、使えないなら0  # dbmopenが使えるなら1、使えないなら0
38  my $dbmopen = 0;  my $dbmopen = 0;
39  ##############################  ##############################
40  # データベース名(.pag, .dir, .dbなどは不要)  # データベース名(.pag, .dir, .dbなどは不要)
41  # $dbmopen = 1のときはデータベース名、  # $dbmopen = 1のときはデータベース名、
42  # $dbmopen = 0のときはディレクトリ名になる。  # $dbmopen = 0のときはディレクトリ名になる。
43  my $dbname = './wikidata';  my $dbname = './wikidata';
44  my $diffdbname = './wikidiff';  my $diffdbname = './wikidiff';
45  ##############################  ##############################
46  # 修正者の氏名(自由に変更してください)  # 修正者の氏名(自由に変更してください)
47  my $modifier = 'suika';  my $modifier = 'suika';
48  ##############################  ##############################
49  # 修正者のWebページ(自由に変更してください)  # 修正者のWebページ(自由に変更してください)
50  my $modifierlink = 'http://suika.fam.cx/';  my $modifierlink = 'http://suika.fam.cx/';
51  ##############################  ##############################
52  # このページのURL  # このページのURL
53  my $thisurl = 'wiki';  my $thisurl = 'wiki';
54  ##############################  ##############################
55  # 開始ページ名  # 開始ページ名
56  my $toppage = 'HomePage';  my $toppage = 'HomePage';
57  ##############################  ##############################
58  # 最終更新ページ名  # 最終更新ページ名
59  my $whatsnew = 'RecentChanges';  my $whatsnew = 'RecentChanges';
60  ##############################  ##############################
61  # 最終更新に掲載するページ数  # 最終更新に掲載するページ数
62  my $maxnew = 50;  my $maxnew = 50;
63  ##############################  ##############################
64  # アイコンファイル名(カラー版)  # アイコンファイル名(カラー版)
65  my $iconfile = '';  my $iconfile = '';
66  ##############################  ##############################
67  # アイコンファイル名(モノクロ版)  # アイコンファイル名(モノクロ版)
68  # my $iconfile = '';  # my $iconfile = '';
69  ##############################  ##############################
70  # ページを変更したときにtouchするファイル(''なら何もしない)  # ページを変更したときにtouchするファイル(''なら何もしない)
71  my $touchfile = 'touch.txt';  my $touchfile = 'touch.txt';
72  ##############################  ##############################
73  # プレビュー用の背景色  # プレビュー用の背景色
74  my $preview_color = '#FFCCCC';  my $preview_color = '#FFCCCC';
75  ##############################  ##############################
76  # 全ページのスタイル  # 全ページのスタイル
77  my $style = <<'EOD';  my $style = <<'EOD';
78  pre, dl, ul, ol, p, blockquote { line-height:120%; }  pre, dl, ul, ol, p, blockquote { line-height:120%; }
79  a { text-decoration: none; }  a { text-decoration: none; }
80  a:link { color: #0000FF; background-color: #FFFFFF; }  a:link { color: #0000FF; background-color: #FFFFFF; }
81  a:visited { color: #9900CC; background-color: #FFFFFF; }  a:visited { color: #9900CC; background-color: #FFFFFF; }
82  a:hover { text-decoration: underline; }  a:hover { text-decoration: underline; }
83  EOD  EOD
84  ##############################  ##############################
85  # テキスト入力部分の大きさ  # テキスト入力部分の大きさ
86  my $cols = 80;  my $cols = 80;
87  my $rows = 20;  my $rows = 20;
88  ##############################  ##############################
89  my %form = ();  my %form = ();
90  my %database = ();  my %database = ();
91  my %diffbase = ();  my %diffbase = ();
92  my $diff_text = '';  my $diff_text = '';
93  my @diff_added = ();  my @diff_added = ();
94  my @diff_deleted = ();  my @diff_deleted = ();
95  my $msgrefA;  my $msgrefA;
96  my $msgrefB;  my $msgrefB;
97  ##############################  ##############################
98  # 編集不可ページ名一覧  # 編集不可ページ名一覧
99  my @uneditable = ( $whatsnew );  my @uneditable = ( $whatsnew );
100  ##############################  ##############################
101  # リンク用の正規表現  # リンク用の正規表現
102  # YukiWikiのリンクは2種類ある。  # YukiWikiのリンクは2種類ある。
103  #  #
104  # (1) WikiName (RecentChangesとかFrontPageのようなもの)  # (1) WikiName (RecentChangesとかFrontPageのようなもの)
105  # (2) BracketName ([[結城浩]]とか[[トラブルシュート]]のようなもの)  # (2) BracketName ([[結城浩]]とか[[トラブルシュート]]のようなもの)
106  #  #
107  # ※シフトJISの2バイト目には ']' が来うるので、  # ※シフトJISの2バイト目には ']' が来うるので、
108  # 文字']'を1つ多くとるようにしている。  # 文字']'を1つ多くとるようにしている。
109  #  #
110  my $WikiName = '([A-Z][a-z]+([A-Z][a-z]+)+)';  my $WikiName = '([A-Z][a-z]+([A-Z][a-z]+)+)';
111  my $BracketName = '\[\[([^>\x09]+?\]?)\]\]';  my $BracketName = '\[\[([^>\x09]+?\]?)\]\]';
112    
113  # アイコン部分のタグ  # アイコン部分のタグ
114  my $IconTag = ''; #<<"EOD";  my $IconTag = ''; #<<"EOD";
115  #<a href="http://www.hyuki.com/yukiwiki/"><img src="$iconfile"  #<a href="http://www.hyuki.com/yukiwiki/"><img src="$iconfile"
116  # border="0" width="80" height="80" alt="[YukiWiki]" /></a>  # border="0" width="80" height="80" alt="[YukiWiki]" /></a>
117  #EOD  #EOD
118    
119  require "$jcodelib";  require "$jcodelib";
120    
121  &init_form($kanjicode);  &init_form($kanjicode);
122    
123  if ($testing) {  if ($testing) {
124      %form = (      %form = (
125          # 'mycmd' => 'write',          # 'mycmd' => 'write',
126          'mycmd' => 'read',          'mycmd' => 'read',
127          #'mycmd' => 'search',          #'mycmd' => 'search',
128          #'mycmd' => 'edit',          #'mycmd' => 'edit',
129          'mymsg' => <<"EOD",          'mymsg' => <<"EOD",
130  はじめまして。  はじめまして。
131  これからいろいろ書き込みますね。  これからいろいろ書き込みますね。
132  LinkPageも見てください。  LinkPageも見てください。
133  TestPageはどうでしょうか。  TestPageはどうでしょうか。
134  どうぞよろしく。  どうぞよろしく。
135  http://www.hyuki.com/  http://www.hyuki.com/
136  [[結城浩]]  [[結城浩]]
137  EOD  EOD
138          'mypage' => '<結城浩>',          'mypage' => '<結城浩>',
139          'myword' => '結',          'myword' => '結',
140          # '3C8C8B8FE98D5F3E' => '',          # '3C8C8B8FE98D5F3E' => '',
141          # 'TestPage' => '',          # 'TestPage' => '',
142      );      );
143  }  }
144  &main;  &main;
145  exit(0);  exit(0);
146    
147  # メイン  # メイン
148  sub main {  sub main {
149      &normalize_form;      &normalize_form;
150      if ($dbmopen) {      if ($dbmopen) {
151          if (!dbmopen(%database, $dbname, 0666)) {          if (!dbmopen(%database, $dbname, 0666)) {
152              &print_error("(dbmopen) $dbname が作れません。");              &print_error("(dbmopen) $dbname が作れません。");
153          }          }
154      } else {      } else {
155          if (!tie(%database, "YukiWikiDB", $dbname)) {          if (!tie(%database, "YukiWikiDB", $dbname)) {
156              &print_error("(tie error)");              &print_error("(tie error)");
157          }          }
158      }      }
159    
160      # myspecial対応      # myspecial対応
161      foreach (keys %form) {      foreach (keys %form) {
162          if (/^myspecial_(.*)/) {          if (/^myspecial_(.*)/) {
163              $form{mycmd} = $1;              $form{mycmd} = $1;
164              last;              last;
165          }          }
166      }      }
167    
168      if ($form{mycmd} eq 'read') {      if ($form{mycmd} eq 'read') {
169          &do_read;          &do_read;
170      } elsif ($form{mycmd} eq 'preview') {      } elsif ($form{mycmd} eq 'preview') {
171          &do_preview;          &do_preview;
172      } elsif ($form{mycmd} eq 'write') {      } elsif ($form{mycmd} eq 'write') {
173          &do_write;          &do_write;
174      } elsif ($form{mycmd} eq 'edit') {      } elsif ($form{mycmd} eq 'edit') {
175          &do_edit;          &do_edit;
176      } elsif ($form{mycmd} eq 'reedit') {      } elsif ($form{mycmd} eq 'reedit') {
177          &do_reedit;          &do_reedit;
178      } elsif ($form{mycmd} eq 'search') {      } elsif ($form{mycmd} eq 'search') {
179          &do_search;          &do_search;
180      } elsif ($form{mycmd} eq 'list') {      } elsif ($form{mycmd} eq 'list') {
181          &do_list;          &do_list;
182      } elsif ($form{mycmd} eq 'diff') {      } elsif ($form{mycmd} eq 'diff') {
183          &do_diff;          &do_diff;
184      } else {      } else {
185          $form{mypage} = $toppage;          $form{mypage} = $toppage;
186          &do_read;          &do_read;
187      }      }
188      if ($dbmopen) {      if ($dbmopen) {
189          dbmclose(%database);          dbmclose(%database);
190      } else {      } else {
191          untie(%database);          untie(%database);
192      }      }
193  }  }
194    
195  # ページの表示  # ページの表示
196  sub do_read {  sub do_read {
197      my $page_name = $form{mypage};      my $page_name = $form{mypage};
198      my $percent_name = &encode_percent($page_name);      my $percent_name = &encode_percent($page_name);
199      &print_header($page_name);      &print_header($page_name);
200      print qq|<h1>$IconTag<a href="$thisurl?mycmd=search;myword=$percent_name">$page_name</a></h1>\n|;      print qq|<h1>$IconTag<a href="$thisurl?mycmd=search;myword=$percent_name">$page_name</a></h1>\n|;
201      &print_toolbar($page_name);      &print_toolbar($page_name);
202      print &convert_html(&get_page($page_name));      print &convert_html(&get_page($page_name));
203      &print_footer;      &print_footer;
204  }  }
205    
206  # ページの編集  # ページの編集
207  sub do_edit {  sub do_edit {
208      if (not &is_editable($form{mypage})) {      if (not &is_editable($form{mypage})) {
209          # 編集不可ページは表示のみ          # 編集不可ページは表示のみ
210          &do_read;          &do_read;
211          return;          return;
212      }      }
213      &editpage(&get_page($form{mypage}));      &editpage(&get_page($form{mypage}));
214  }  }
215    
216  # ページの再編集  # ページの再編集
217  sub do_reedit {  sub do_reedit {
218      if (not &is_editable($form{mypage})) {      if (not &is_editable($form{mypage})) {
219          # 編集不可ページは表示のみ          # 編集不可ページは表示のみ
220          &do_read;          &do_read;
221      } else {      } else {
222          &editpage($form{mymsg});          &editpage($form{mymsg});
223      }      }
224  }  }
225    
226  sub editpage {  sub editpage {
227      my $page_msg = shift;      my $page_msg = shift;
228      my $page_name = $form{mypage};      my $page_name = $form{mypage};
229      my $digest = &calc_message_digest($page_msg);      my $digest = &calc_message_digest($page_msg);
230      &print_header($page_name);      &print_header($page_name);
231      print qq|<h1>$IconTag${page_name}の編集</h1>\n|;      print qq|<h1>$IconTag${page_name}の編集</h1>\n|;
232      &print_toolbar($page_name);      &print_toolbar($page_name);
233      $page_msg = &escape($page_msg);      $page_msg = &escape($page_msg);
234      print <<"EOD";      print <<"EOD";
235  <form action="$thisurl" method="post">  <form action="$thisurl" method="post">
236  <!--<input type="hidden" name="mycmd" value="preview">-->  <!--<input type="hidden" name="mycmd" value="preview">-->
237  <input type="hidden" name="mypage" value="$page_name">  <input type="hidden" name="mypage" value="$page_name">
238  <input type="hidden" name="mydigest" value="$digest">  <input type="hidden" name="mydigest" value="$digest">
239  <textarea cols="$cols" rows="$rows" name="mymsg" wrap="virtual">$page_msg</textarea><br>  <textarea cols="$cols" rows="$rows" name="mymsg" wrap="virtual">$page_msg</textarea><br>
240  <input type="submit" name="myspecial_preview" value="確認">  <input type="submit" name="myspecial_preview" value="確認">
241  <input type="submit" name="myspecial_write" value="確認せず変更">  <input type="submit" name="myspecial_write" value="確認せず変更">
242  </form>  </form>
243  <hr>  <hr>
244  <h3>テキスト整形のルール</h3>  <h3>テキスト整形のルール</h3>
245    
246  <p>通常は入力した文字がそのまま出力されますが、  <p>通常は入力した文字がそのまま出力されますが、
247  以下のルールに従ってテキスト整形を行うことができます。</p>  以下のルールに従ってテキスト整形を行うことができます。</p>
248    
249  <ul>  <ul>
250  <li>  <li>
251  空行は段落の区切りとなります。  空行は段落の区切りとなります。
252    
253  <li>  <li>
254  HTMLのタグは書けません。  HTMLのタグは書けません。
255    
256  <li>  <li>
257  ''強調''のようにシングルクォート二つではさむと、強調になります。  ''強調''のようにシングルクォート二つではさむと、強調になります。
258    
259  <li>  <li>
260  '''更に強調'''のようにシングルクォート三つではさむと、更に強調になります。  '''更に強調'''のようにシングルクォート三つではさむと、更に強調になります。
261    
262  <li>  <li>
263  ----のようにマイナス4つがあると、水平線になります。  ----のようにマイナス4つがあると、水平線になります。
264    
265  <li>  <li>
266  *を行頭に書くと大見出しになります。  *を行頭に書くと大見出しになります。
267    
268  <li>  <li>
269  **を行頭に書くと小見出しになります。  **を行頭に書くと小見出しになります。
270    
271  <li>  <li>
272  -を行頭に書くと箇条書きになります。- -- --- の3レベルがあります。  -を行頭に書くと箇条書きになります。- -- --- の3レベルがあります。
273    
274  <li>  <li>
275  :を行頭に書くと用語と解説文が作れます。  :を行頭に書くと用語と解説文が作れます。
276    
277  <pre>  <pre>
278      :用語1:いろいろ書いた解説文1      :用語1:いろいろ書いた解説文1
279      :用語2:いろいろ書いた解説文2      :用語2:いろいろ書いた解説文2
280      :用語3:いろいろ書いた解説文3      :用語3:いろいろ書いた解説文3
281  </pre>  </pre>
282    
283  <li>  <li>
284  http://www.hyuki.com/ のようなURLは自動的にリンクになります。  http://www.hyuki.com/ のようなURLは自動的にリンクになります。
285    
286  <li>  <li>
287  YukiWikiのように大文字小文字を混ぜた英文字列を書くと、  YukiWikiのように大文字小文字を混ぜた英文字列を書くと、
288  YukiWikiのページ名になります。  YukiWikiのページ名になります。
289    
290  <li>  <li>
291  [[結城浩]]のように二重の大かっこ[[ ]]でくくった文字列を書くと、  [[結城浩]]のように二重の大かっこ[[ ]]でくくった文字列を書くと、
292  YukiWikiのページ名になります。  YukiWikiのページ名になります。
293  大かっこの中にはスペースを含めてはいけません。  大かっこの中にはスペースを含めてはいけません。
294  日本語も使えます。  日本語も使えます。
295    
296  <li>  <li>
297  行頭がスペースで始まっていると、  行頭がスペースで始まっていると、
298  その段落は整形済み扱われます。  その段落は整形済み扱われます。
299  プログラムを書き込むときに使うと便利です。  プログラムを書き込むときに使うと便利です。
300    
301  <li>  <li>
302  &gt; を行頭に書くと、  &gt; を行頭に書くと、
303  引用文が書けます。  引用文が書けます。
304  &gt; の数が多いとインデントが深くなります(3レベルまで)。  &gt; の数が多いとインデントが深くなります(3レベルまで)。
305    
306  </ul>  </ul>
307  EOD  EOD
308      &print_footer;      &print_footer;
309  }  }
310    
311  # ページの検索  # ページの検索
312  sub do_search {  sub do_search {
313      if ($form{myword}) {      if ($form{myword}) {
314          &print_header('検索結果');          &print_header('検索結果');
315          print qq|<h1>$IconTag$form{myword}の検索結果</h1>\n|;          print qq|<h1>$IconTag$form{myword}の検索結果</h1>\n|;
316          &print_toolbar();          &print_toolbar();
317          print qq|<ul>\n|;          print qq|<ul>\n|;
318          my $count = 0;          my $count = 0;
319          foreach my $page_name (sort keys %database) {    # sortするのは無謀かな          foreach my $page_name (sort keys %database) {    # sortするのは無謀かな
320              if ($database{$page_name} =~ /\Q$form{'myword'}\E/) {              if ($database{$page_name} =~ /\Q$form{'myword'}\E/) {
321                  my $encoded = &encode_percent($page_name);                  my $encoded = &encode_percent($page_name);
322                  print qq|<li><a href="$thisurl?mycmd=read;mypage=$encoded">$page_name</a>\n|;                  print qq|<li><a href="$thisurl?mycmd=read;mypage=$encoded">$page_name</a>\n|;
323                  $count++;                  $count++;
324              }              }
325          }          }
326          print qq|</ul>\n|;          print qq|</ul>\n|;
327          if ($count > 0) {          if ($count > 0) {
328              print qq|<p><strong>$form{myword}</strong>を含むページは、上に示す<strong>$count</strong> ページです。</p>\n|;              print qq|<p><strong>$form{myword}</strong>を含むページは、上に示す<strong>$count</strong> ページです。</p>\n|;
329          } else {          } else {
330              print qq|<p><strong>$form{myword}</strong>を含むページは見つかりません。</p>\n|;              print qq|<p><strong>$form{myword}</strong>を含むページは見つかりません。</p>\n|;
331          }          }
332      } else {      } else {
333          &print_header('単語検索');          &print_header('単語検索');
334          print qq|<h1>$IconTag単語検索</h1>\n|;          print qq|<h1>$IconTag単語検索</h1>\n|;
335          &print_toolbar();          &print_toolbar();
336      }      }
337      print <<"EOD";      print <<"EOD";
338  <p>  <p>
339  <form action="$thisurl" method="post">  <form action="$thisurl" method="post">
340  <input type="hidden" name="mycmd" value="search">  <input type="hidden" name="mycmd" value="search">
341  <input type="text" name="myword" size="20" value="$form{myword}">  <input type="text" name="myword" size="20" value="$form{myword}">
342  <input type="submit" value="単語検索">  <input type="submit" value="単語検索">
343  </form>  </form>
344  </p>  </p>
345  EOD  EOD
346      &print_footer;      &print_footer;
347  }  }
348    
349  # ページの一覧  # ページの一覧
350  sub do_list {  sub do_list {
351      &print_header('ページ一覧');      &print_header('ページ一覧');
352      print qq|<h1>$IconTag ページ一覧</h1>\n|;      print qq|<h1>$IconTag ページ一覧</h1>\n|;
353      &print_toolbar();      &print_toolbar();
354      print qq|<ul>\n|;      print qq|<ul>\n|;
355      foreach my $page_name (sort keys %database) {    # sortするのは無謀かな      foreach my $page_name (sort keys %database) {    # sortするのは無謀かな
356          my $encoded = &encode_percent($page_name);          my $encoded = &encode_percent($page_name);
357          print qq|<li><a href="$thisurl?mycmd=read;mypage=$encoded">$page_name</a>\n|          print qq|<li><a href="$thisurl?mycmd=read;mypage=$encoded">$page_name</a>\n|
358      }      }
359      print qq|</ul>\n|;      print qq|</ul>\n|;
360      &print_footer;      &print_footer;
361  }  }
362    
363  # プレビュー  # プレビュー
364  sub do_preview {  sub do_preview {
365      my $page_name = $form{mypage};      my $page_name = $form{mypage};
366      my $escapedmsg = &escape($form{mymsg});      my $escapedmsg = &escape($form{mymsg});
367      &print_header($page_name);      &print_header($page_name);
368      print qq|<h1>$IconTag${page_name}のプレビュー</h1>\n|;      print qq|<h1>$IconTag${page_name}のプレビュー</h1>\n|;
369      &print_toolbar($page_name);      &print_toolbar($page_name);
370      # local $percent_name = &encode_percent($page_name);      # local $percent_name = &encode_percent($page_name);
371      print qq|<p>以下のプレビューを確認して、よければページ下部のボタンで更新してください。</p>\n|;      print qq|<p>以下のプレビューを確認して、よければページ下部のボタンで更新してください。</p>\n|;
372      if ($form{mymsg}) {      if ($form{mymsg}) {
373          print qq|<table width="100%" bgcolor="$preview_color" ><tr><td>\n|;          print qq|<table width="100%" bgcolor="$preview_color" ><tr><td>\n|;
374          # print &convert_html($escapedmsg);          # print &convert_html($escapedmsg);
375          print &convert_html($form{mymsg});          print &convert_html($form{mymsg});
376          print qq|</td></tr></table>\n|;          print qq|</td></tr></table>\n|;
377      } else {      } else {
378          print qq|<p>(ページの内容は空です。更新するとこのページは<strong>削除</strong>されます。)</p>\n|;          print qq|<p>(ページの内容は空です。更新するとこのページは<strong>削除</strong>されます。)</p>\n|;
379      }      }
380      &print_preview_buttons($page_name, $escapedmsg, $form{mydigest});      &print_preview_buttons($page_name, $escapedmsg, $form{mydigest});
381      &print_footer;      &print_footer;
382  }  }
383    
384  sub print_preview_buttons {  sub print_preview_buttons {
385      my ($page_name, $escapedmsg, $digest) = @_;      my ($page_name, $escapedmsg, $digest) = @_;
386      print <<"EOD";      print <<"EOD";
387      <form action="$thisurl" method="post">      <form action="$thisurl" method="post">
388      <textarea cols="$cols" rows="$rows" name="mymsg" wrap="virtual">$escapedmsg</textarea>      <textarea cols="$cols" rows="$rows" name="mymsg" wrap="virtual">$escapedmsg</textarea>
389      <br />      <br />
390      <input type="hidden" name="mypage" value="$page_name">      <input type="hidden" name="mypage" value="$page_name">
391      <input type="hidden" name="mydigest" value="$digest">      <input type="hidden" name="mydigest" value="$digest">
392      <input type="submit" name="myspecial_preview" value="再度プレビュー">      <input type="submit" name="myspecial_preview" value="再度プレビュー">
393      <input type="submit" name="myspecial_write" value="ページの更新">      <input type="submit" name="myspecial_write" value="ページの更新">
394      </form>      </form>
395  EOD  EOD
396  }  }
397    
398  # 書き込む  # 書き込む
399  sub do_write {  sub do_write {
400      if (not &is_editable($form{mypage})) {      if (not &is_editable($form{mypage})) {
401          # 編集不可ページは表示のみ          # 編集不可ページは表示のみ
402          &do_read;          &do_read;
403          return;          return;
404      }      }
405    
406      my $page_name = $form{mypage};      my $page_name = $form{mypage};
407    
408      # digestを使って、更新の衝突チェック      # digestを使って、更新の衝突チェック
409      my $original_digest = &calc_message_digest(&get_page($page_name));      my $original_digest = &calc_message_digest(&get_page($page_name));
410      if ($form{mydigest} ne $original_digest) {      if ($form{mydigest} ne $original_digest) {
411          &print_header($page_name);          &print_header($page_name);
412          print qq|<h1>$IconTag${page_name}で【更新の衝突】が起きました</h1>\n|;          print qq|<h1>$IconTag${page_name}で【更新の衝突】が起きました</h1>\n|;
413          print <<"EOD";          print <<"EOD";
414  <p>あなたがこのページを編集している間に、  <p>あなたがこのページを編集している間に、
415  他の人が同じページを更新してしまったようです。  他の人が同じページを更新してしまったようです。
416  </p><p>  </p><p>
417  以下に、あなたの編集したテキストがありますので、  以下に、あなたの編集したテキストがありますので、
418  あなたの編集内容が失われないように、  あなたの編集内容が失われないように、
419  いますぐ、メモ帳などにコピー&ペーストしてください。  いますぐ、メモ帳などにコピー&ペーストしてください。
420  </p><p>  </p><p>
421  コピー&ペーストが済んでから、  コピー&ペーストが済んでから、
422  最新の内容を見て再度編集し直してください。  最新の内容を見て再度編集し直してください。
423  最新の内容は  最新の内容は
424  <a target="_blank" href="$thisurl?mycmd=read;mypage=$form{mypage}">$form{mypage}</a>  <a target="_blank" href="$thisurl?mycmd=read;mypage=$form{mypage}">$form{mypage}</a>
425  で見ることができます。  で見ることができます。
426  </p>  </p>
427  EOD  EOD
428          # &print_toolbar($page_name);          # &print_toolbar($page_name);
429          &print_preview_buttons($page_name, &escape($form{mymsg}), $form{mydigest});          &print_preview_buttons($page_name, &escape($form{mymsg}), $form{mydigest});
430          &print_footer;          &print_footer;
431          return;          return;
432      }      }
433    
434      # diff生成      # diff生成
435      {      {
436          &opendiff;          &opendiff;
437          my @msg1 = split(/\n/, &get_page($page_name));          my @msg1 = split(/\n/, &get_page($page_name));
438          my @msg2 = split(/\n/, $form{mymsg});          my @msg2 = split(/\n/, $form{mymsg});
439          $msgrefA = \@msg1;          $msgrefA = \@msg1;
440          $msgrefB = \@msg2;          $msgrefB = \@msg2;
441          &diff_check;          &diff_check;
442          $diffbase{$form{mypage}} = $diff_text;          $diffbase{$form{mypage}} = $diff_text;
443          $diff_text = '';          $diff_text = '';
444          &closediff;          &closediff;
445      }      }
446    
447      &print_header($page_name);      &print_header($page_name);
448      &set_page($page_name, $form{mymsg});      &set_page($page_name, $form{mymsg});
449      if ($form{mymsg}) {      if ($form{mymsg}) {
450          print qq|<h1>$IconTag${page_name}を更新しました</h1>\n|;          print qq|<h1>$IconTag${page_name}を更新しました</h1>\n|;
451          &print_toolbar($page_name);          &print_toolbar($page_name);
452          print &convert_html(&get_page($page_name));          print &convert_html(&get_page($page_name));
453      } else {      } else {
454          print qq|<h1>$IconTag${page_name}を削除しました</h1>\n|;          print qq|<h1>$IconTag${page_name}を削除しました</h1>\n|;
455          &print_toolbar($page_name);          &print_toolbar($page_name);
456          print qq|<p>${page_name}を削除しました。</p>\n|;          print qq|<p>${page_name}を削除しました。</p>\n|;
457      }      }
458      &print_footer;      &print_footer;
459      # 更新されたのでタッチしておく。      # 更新されたのでタッチしておく。
460      if ($touchfile) {      if ($touchfile) {
461          open(FILE, "> $touchfile");          open(FILE, "> $touchfile");
462          print FILE "\n";          print FILE "\n";
463          close(FILE);          close(FILE);
464      }      }
465  }  }
466    
467  # ページの変更点  # ページの変更点
468  sub do_diff {  sub do_diff {
469      if (not &is_editable($form{mypage})) {      if (not &is_editable($form{mypage})) {
470          # 編集不可ページは表示のみ          # 編集不可ページは表示のみ
471          &do_read;          &do_read;
472          return;          return;
473      }      }
474      &opendiff;      &opendiff;
475      &print_header($form{mypage} . 'の変更点');      &print_header($form{mypage} . 'の変更点');
476      print qq|<h1>$IconTag <a href="$thisurl?mycmd=read&mypage=$form{mypage}">$form{mypage}</a>の変更点</h1>\n|;      print qq|<h1>$IconTag <a href="$thisurl?mycmd=read&mypage=$form{mypage}">$form{mypage}</a>の変更点</h1>\n|;
477      &print_toolbar();      &print_toolbar();
478      $_ = &escape($diffbase{$form{mypage}});      $_ = &escape($diffbase{$form{mypage}});
479      print <<"EOD";      print <<"EOD";
480  <ul>  <ul>
481  <li>追加された行は<ins>青色</ins>です。  <li>追加された行は<ins>青色</ins>です。
482  <li>削除された行は<del>赤色</del>です。  <li>削除された行は<del>赤色</del>です。
483  <li><a href="$thisurl?mycmd=read;mypage=$form{mypage}">$form{mypage}</a>へ行く。  <li><a href="$thisurl?mycmd=read;mypage=$form{mypage}">$form{mypage}</a>へ行く。
484  </ul>  </ul>
485  <hr />  <hr />
486  EOD  EOD
487      print qq|<pre>\n|;      print qq|<pre>\n|;
488      foreach (split(/\n/, $_)) {      foreach (split(/\n/, $_)) {
489          if (/^\+(.*)/) {          if (/^\+(.*)/) {
490              print qq|<ins>$1</ins>\n|;              print qq|<ins>$1</ins>\n|;
491          } elsif (/^\-(.*)/) {          } elsif (/^\-(.*)/) {
492              print qq|<del>$1</del>\n|;              print qq|<del>$1</del>\n|;
493          } elsif (/^\=(.*)/) {          } elsif (/^\=(.*)/) {
494              print qq|$1\n|;              print qq|$1\n|;
495          } else {          } else {
496              print qq|??? $_\n|;              print qq|??? $_\n|;
497          }          }
498      }      }
499      print qq|</pre>\n|;      print qq|</pre>\n|;
500      &print_footer;      &print_footer;
501      &closediff;      &closediff;
502  }  }
503    
504  sub opendiff {  sub opendiff {
505      if ($dbmopen) {      if ($dbmopen) {
506          if (!dbmopen(%diffbase, $diffdbname, 0666)) {          if (!dbmopen(%diffbase, $diffdbname, 0666)) {
507              &print_error("(dbmopen) $diffdbname が作れません。");              &print_error("(dbmopen) $diffdbname が作れません。");
508          }          }
509      } else {      } else {
510          if (!tie(%diffbase, "YukiWikiDB", $diffdbname)) {          if (!tie(%diffbase, "YukiWikiDB", $diffdbname)) {
511              &print_error("(tie error)");              &print_error("(tie error)");
512          }          }
513      }      }
514  }  }
515    
516  sub closediff {  sub closediff {
517      if ($dbmopen) {      if ($dbmopen) {
518          dbmclose(%diffbase);          dbmclose(%diffbase);
519      } else {      } else {
520          untie(%diffbase);          untie(%diffbase);
521      }      }
522  }  }
523    
524  # フォームからの情報を連想配列 %form に入れる  # フォームからの情報を連想配列 %form に入れる
525  # &init_form('euc');  # &init_form('euc');
526  sub init_form {  sub init_form {
527      my ($charcode) = @_;      my ($charcode) = @_;
528      my $query;      my $query;
529      if ($ENV{REQUEST_METHOD} =~ /^post$/i) {      if ($ENV{REQUEST_METHOD} =~ /^post$/i) {
530          read(STDIN, $query, $ENV{CONTENT_LENGTH});          read(STDIN, $query, $ENV{CONTENT_LENGTH});
531      } else {      } else {
532          $query = $ENV{QUERY_STRING};          $query = $ENV{QUERY_STRING};
533      }      }
534      my @assocarray = split(/[&;]/, $query);      my @assocarray = split(/[&;]/, $query);
535      foreach my $assoc (@assocarray) {      foreach my $assoc (@assocarray) {
536          my ($property, $value) = split(/=/, $assoc);          my ($property, $value) = split(/=/, $assoc);
537          $value =~ tr/+/ /;          $value =~ tr/+/ /;
538          $value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg;          $value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg;
539          &jcode::convert(\$value, $charcode);          &jcode::convert(\$value, $charcode);
540          $form{$property} = $value;          $form{$property} = $value;
541      }      }
542  }  }
543    
544  # エラーページを出力する  # エラーページを出力する
545  sub print_error {  sub print_error {
546      my ($msg) = @_;      my ($msg) = @_;
547      &print_header('Error');      &print_header('Error');
548      print "<h1>$IconTag$msg</h1></body></html>";      print "<h1>$IconTag$msg</h1></body></html>";
549      exit(0);      exit(0);
550  }  }
551    
552  sub escape {  sub escape {
553      my ($line) = shift;      my ($line) = shift;
554      $line =~ s|<|&lt;|g;      $line =~ s|<|&lt;|g;
555      $line =~ s|>|&gt;|g;      $line =~ s|>|&gt;|g;
556      $line =~ s|"|&quot;|g;      $line =~ s|"|&quot;|g;
557      # $line =~ s|\&|&amp;|g;      # $line =~ s|\&|&amp;|g;
558      return $line;      return $line;
559  }  }
560    
561  sub inline {  sub inline {
562      my ($line) = shift;      my ($line) = shift;
563      $line = &escape($line);      $line = &escape($line);
564      $line =~ s|'''([^']+?)'''|<strong>$1</strong>|g;      $line =~ s|'''([^']+?)'''|<strong>$1</strong>|g;
565      $line =~ s|''([^']+?)''|<em>$1</em>|g;                $line =~ s|''([^']+?)''|<em>$1</em>|g;          
566      $line =~ s!      $line =~ s!
567         (         (
568           (?:&lt;(?:mailto|http|https|ftp|urn):[\x21-\x7E]*)&gt;           (?:&lt;(?:mailto|http|https|ftp|urn):[\x21-\x7E]*)&gt;
569         #| (?:$WikiName)                         # LocalLinkLikeThis         #| (?:$WikiName)                         # LocalLinkLikeThis
570         | (?:$BracketName)                      # [[日本語リンク]]         | (?:$BracketName)                      # [[日本語リンク]]
571         )         )
572              !              !
573                  &make_link($1)                  &make_link($1)
574              !gex;              !gex;
575      return $line;      return $line;
576  }  }
577    
578  # ページのタイトルからページの内容を得る  # ページのタイトルからページの内容を得る
579  sub get_page {  sub get_page {
580      my $page_name = shift;      my $page_name = shift;
581      return $database{$page_name};      return $database{$page_name} || $database{'[['.$page_name.']]'};
582  }  }
583    
584  # ページの内容を与える  # ページの内容を与える
585  # &set_page($title, $txt)  # &set_page($title, $txt)
586  sub set_page {  sub set_page {
587      # ページを更新する      # ページを更新する
588      my $title = $_[0];      my $title = $_[0];
589      $database{$title} = $_[1];      $database{$title} = $_[1];
590      # 空ページなら削除する      # 空ページなら削除する
591      unless ($database{$title}) {      unless ($database{$title}) {
592          delete $database{$title};          delete $database{$title};
593      }      }
594      # RecentChangesを更新する      # RecentChangesを更新する
595      my $delim = ' - ';      my $delim = ' - ';
596      my @pages = split(/\n/, $database{$whatsnew});      my @pages = split(/\n/, $database{$whatsnew});
597      my $datestr = &get_current_datestr;      my $datestr = &get_current_datestr;
598      unshift(@pages, qq|-$datestr$delim$title|);      unshift(@pages, qq|-$datestr$delim$title|);
599      # 同一ページの更新は最新のもののみにし、      # 同一ページの更新は最新のもののみにし、
600      # 存在しないページはスキップする。      # 存在しないページはスキップする。
601      my %count;      my %count;
602      my @newpages;      my @newpages;
603      foreach my $line (@pages) {      foreach my $line (@pages) {
604          my ($prefix, $title) = split(/$delim/, $line);          my ($prefix, $title) = split(/$delim/, $line);
605          $count{$title}++;          $count{$title}++;
606          if ($count{$title} == 1 and exists($database{$title})) {          if ($count{$title} == 1 and exists($database{$title})) {
607              push(@newpages, qq|$prefix - $title|);              push(@newpages, qq|$prefix - $title|);
608          }          }
609      }      }
610      # ここで本当に更新      # ここで本当に更新
611      $database{$whatsnew} = join("\n", splice(@newpages, 0, $maxnew));      $database{$whatsnew} = join("\n", splice(@newpages, 0, $maxnew));
612  }  }
613    
614  # ページのヘッダを出力  # ページのヘッダを出力
615  sub print_header {  sub print_header {
616      my $title = shift;      my $title = shift;
617      print <<"EOD";      print <<"EOD";
618  Content-type: text/html  Content-type: text/html; charset=${charset}
619    
620  <html><head>  <html><head>
621  <title>$title</title>  <title>$title</title>
622  <style type="text/css">  <style type="text/css">
623  $style  $style
624  </style>  </style>
625  </head>  </head>
626  <body>  <body>
627  EOD  EOD
628  }  }
629    
630  # ツールバーを出力  # ツールバーを出力
631  sub print_toolbar {  sub print_toolbar {
632      my $page_name = shift;      my $page_name = shift;
633      my $percent_name = &encode_percent($page_name);      my $percent_name = &encode_percent($page_name);
634      my $editlink = '';      my $editlink = '';
635      if ($page_name ne '' and &is_editable($page_name)) {      if ($page_name ne '' and &is_editable($page_name)) {
636          $editlink = <<"EOD";          $editlink = <<"EOD";
637  <a href="$thisurl?mycmd=edit;mypage=$percent_name">編集</a> |  <a href="$thisurl?mycmd=edit;mypage=$percent_name">編集</a> |
638  <a href="$thisurl?mycmd=diff;mypage=$percent_name">差分</a> |  <a href="$thisurl?mycmd=diff;mypage=$percent_name">差分</a> |
639  EOD  EOD
640      }      }
641      print <<"EOD";      print <<"EOD";
642  <p>  <p>
643   [   [
644  <a href="$thisurl?mycmd=read;mypage=$toppage">トップ</a> |  <a href="$thisurl?mycmd=read;mypage=$toppage">トップ</a> |
645  <a href="$thisurl?mycmd=list">一覧</a> |  <a href="$thisurl?mycmd=list">一覧</a> |
646  $editlink  $editlink
647  <a href="$thisurl?mycmd=search">単語検索</a> |  <a href="$thisurl?mycmd=search">単語検索</a> |
648  <a href="$thisurl?mycmd=read;mypage=$whatsnew">最終更新</a>  <a href="$thisurl?mycmd=read;mypage=$whatsnew">最近の更新</a>
649   ]   ]
650  </p>  </p>
651  EOD  EOD
652  }  }
653    
654  # ページのフッタを出力  # ページのフッタを出力
655  sub print_footer {  sub print_footer {
656      print <<"EOD";      print <<"EOD";
657  <address>  <div class="navigation">
658  <a href="http://www.hyuki.com/yukiwiki/">YukiWiki</a> 1.6.6 Copyright (C) 2000,2001 by <a href="http://www.hyuki.com/">Hiroshi Yuki.</a>  <a href="http://www.hyuki.com/yukiwiki/">YukiWiki</a> 1.6.6 Copyright (C) 2000,2001 by <a href="http://www.hyuki.com/">Hiroshi Yuki.</a>
659  + <a href="$modifierlink">$modifier</a> ${version}.  + <a href="$modifierlink">$modifier</a> ${version}.
660  [<a href="/" title="このサーバーの首頁">/</a>  [<a href="/" title="このサーバーの首頁">/</a>
661  <a href="/map" title="このサーバーの案内">地図</a>  <a href="/map" title="このサーバーの案内">地図</a>
662  <a href="/search/" title="このサーバーの検索">検索</a>]  <a href="/search/" title="このサーバーの検索">検索</a>]
663  </address>  </div>
664  </body></html>  <div class="update">\$Id$ </div>
665  EOD  </body></html>
666  }  EOD
667    }
668  # URLやページの名前からリンクを作る  
669  sub make_link {  # URLやページの名前からリンクを作る
670      my $name = shift;  sub make_link {
671      $name =~ s/^&lt;(.*)&gt;$/$1/;      my $name = shift;
672      $name =~ s/^\[\[(.*)\]\]$/$1/;      $name =~ s/^&lt;(.*)&gt;$/$1/;
673      if ($name =~ /^(http|https|ftp).*?(\.png|\.jpeg|\.jpg)?$/) {      $name =~ s/^\[\[(.*)\]\]$/$1/;
674          if ($2) {      if ($name =~ /^(http|https|ftp).*?(\.png|\.jpeg|\.jpg)?$/) {
675              return qq|<a href="$name"><img border="0" src="$name" /></a>|;          if ($2) {
676          } else {              return qq|<a href="$name"><img border="0" src="$name" /></a>|;
677              return qq|&lt;<a href="$name">$name</a>&gt;|;          } else {
678          }              return qq|&lt;<a href="$name">$name</a>&gt;|;
679      } elsif ($name =~ /^mailto:(.*)/) {          }
680          my $address = $1;      } elsif ($name =~ /^mailto:(.*)/) {
681          return qq|&lt;<a href="$name">$address</a>&gt;|;          my $address = $1;
682      } elsif ($name =~ /^urn:[0-9A-Za-z_:-]+/) {          return qq|&lt;<a href="$name">$address</a>&gt;|;
683          return qq|&lt;<a href="/uri-res/N2L?${name}">$name</a>&gt;|;      } elsif ($name =~ m#^urn:[0-9A-Za-z_:;/.-]+#) {
684      } else {          return qq|&lt;<a href="/uri-res/N2L?${name}">$name</a>&gt;|;
685        my $name2 = $name; $name2 =~ tr/\x20/-/;      } else {
686        if ($database{$name2}) {        my $name2 = $name; $name2 =~ tr/\x20/-/;
687          my $percent_name = &encode_percent($name2);        if ($database{$name2}) {
688          return qq|<a href="$thisurl?mycmd=read;mypage=$percent_name" class="wiki">$name</a>|;          my $percent_name = &encode_percent($name2);
689        } elsif ($database{'[['.$name2.']]'}) {          return qq|<a href="$thisurl?mycmd=read;mypage=$percent_name" class="wiki">$name</a>|;
690          my $percent_name = &encode_percent('[['.$name2.']]');        } elsif ($database{'[['.$name2.']]'}) {
691          return qq|<a href="$thisurl?mycmd=read;mypage=$percent_name" class="wiki">$name</a>|;          my $percent_name = &encode_percent('[['.$name2.']]');
692        } else {          return qq|<a href="$thisurl?mycmd=read;mypage=$percent_name" class="wiki">$name</a>|;
693          my $percent_name = &encode_percent($name2);        } else {
694          return qq|<a href="$thisurl?mycmd=edit;mypage=$percent_name" class="wiki newpage">$name?</a>|;          my $percent_name = &encode_percent($name2);
695        }          return qq|<a href="$thisurl?mycmd=edit;mypage=$percent_name" class="wiki newpage">$name<span class="mark">?</span></a>|;
696      }        }
697  }      }
698    }
699  # %xx の形式にエンコードする  
700  # これは、  # %xx の形式にエンコードする
701  # http://www.hyuki.com/yukiwiki/yukiwiki.cgi?mycmd=read&mypage=%3C%8C%8B%8F%E9%8D_%3E  # これは、
702  # という形式のために使われる。  # http://www.hyuki.com/yukiwiki/yukiwiki.cgi?mycmd=read&mypage=%3C%8C%8B%8F%E9%8D_%3E
703  # '<結城浩>' → '%3C%8C%8B%8F%E9%8D_%3E'  # という形式のために使われる。
704  sub encode_percent {  # '<結城浩>' → '%3C%8C%8B%8F%E9%8D_%3E'
705      my $name = shift;  sub encode_percent {
706      my $encoded = '';      my $name = shift;
707      foreach my $ch (split(//, $name)) {      my $encoded = '';
708          if ($ch =~ /[A-Za-z0-9_]/) {      foreach my $ch (split(//, $name)) {
709              $encoded .= $ch;          if ($ch =~ /[A-Za-z0-9_]/) {
710          } else {              $encoded .= $ch;
711              $encoded .= '%' . sprintf("%02X", ord($ch));          } else {
712          }              $encoded .= '%' . sprintf("%02X", ord($ch));
713      }          }
714      return $encoded;      }
715  }      return $encoded;
716    }
717  # テキスト本体をHTMLに変換する  
718  sub convert_html {  # テキスト本体をHTMLに変換する
719      my ($txt) = shift;  sub convert_html {
720      my (@txt) = split(/\n/, $txt);      my ($txt) = shift;
721      foreach (@txt) {      my (@txt) = split(/\n/, $txt);
722          chomp;      foreach (@txt) {
723          if (/^\*\*(.*)/) {          chomp;
724              push(@result, splice(@saved), '<h3>' . &inline($1) . '</h3>');          if (/^\*\*(.*)/) {
725          } elsif (/^\*(.*)/) {              push(@result, splice(@saved), '<h3>' . &inline($1) . '</h3>');
726              push(@result, splice(@saved), '<h2>' . &inline($1) . '</h2>');          } elsif (/^\*(.*)/) {
727          } elsif (/^----/) {              push(@result, splice(@saved), '<h2>' . &inline($1) . '</h2>');
728              push(@result, splice(@saved), '<hr>');          } elsif (/^----/) {
729          } elsif (/^(-{1,3})(.*)/) {              push(@result, splice(@saved), '<hr>');
730              &back_push('ul', length($1));          } elsif (/^(-{1,3})(.*)/) {
731              push(@result, '<li>' . &inline($2) . '</li>');              &back_push('ul', length($1));
732          } elsif (/^:([^:]+):(.*)/) {              push(@result, '<li>' . &inline($2) . '</li>');
733              &back_push('dl', 1);          } elsif (/^:([^:]+):(.*)/) {
734              push(@result, '<dt>' . &inline($1) . '</dt>', '<dd>' . &inline($2) . '</dd>');              &back_push('dl', 1);
735          } elsif (/^(>{1,3})(.*)/) {              push(@result, '<dt>' . &inline($1) . '</dt>', '<dd>' . &inline($2) . '</dd>');
736              &back_push('blockquote', length($1));          } elsif (/^(>{1,3})(.*)/) {
737              push(@result, &inline($2));              &back_push('blockquote', length($1));
738          } elsif (/^\s*$/) {              push(@result, &inline($2));
739              push(@result, splice(@saved));          } elsif (/^\s*$/) {
740              unshift(@saved, "</p>");              push(@result, splice(@saved));
741              push(@result, "<p>");              unshift(@saved, "</p>");
742          } elsif (/^(\s+.*)$/) {              push(@result, "<p>");
743              &back_push('pre', 1);          } elsif (/^(\s+.*)$/) {
744              push(@result, &escape($1)); # Not &inline, but &escape              &back_push('pre', 1);
745          } else {              push(@result, &escape($1)); # Not &inline, but &escape
746              push(@result, &inline($_));          } else {
747          }              push(@result, &inline($_));
748      }          }
749      push(@result, splice(@saved));      }
750      return join("\n", @result);      push(@result, splice(@saved));
751  }      return join("\n", @result);
752    }
753  # &back_push($tag, $count)  
754  # $tagのタグを$levelレベルまで詰める。  # &back_push($tag, $count)
755  sub back_push {  # $tagのタグを$levelレベルまで詰める。
756      my ($tag, $level) = @_;  sub back_push {
757      while (@saved > $level) {      my ($tag, $level) = @_;
758          push(@result, shift(@saved));      while (@saved > $level) {
759      }          push(@result, shift(@saved));
760      if ($saved[0] ne "</$tag>") {      }
761          push(@result, splice(@saved));      if ($saved[0] ne "</$tag>") {
762      }          push(@result, splice(@saved));
763      while (@saved < $level) {      }
764          unshift(@saved, "</$tag>");      while (@saved < $level) {
765          push(@result, "<$tag>");          unshift(@saved, "</$tag>");
766      }          push(@result, "<$tag>");
767  }      }
768    }
769  # 編集可能ページか?  
770  sub is_editable {  # 編集可能ページか?
771      my ($pagename) = @_;  sub is_editable {return 1;
772      foreach (@uneditable) {  ## TODO: ...
773          if ($pagename eq $_) {      my ($pagename) = @_;
774              return 0;      foreach (@uneditable) {
775          }          if ($pagename eq $_) {
776      }              return 0;
777      if (&is_valid_name($pagename)) {          }
778          return 1;      }
779      }      if (&is_valid_name($pagename)) {
780      return 0;          return 1;
781  }      }
782        return 0;
783  # Validな名前か?  }
784  sub is_valid_name {  
785      my ($pagename) = @_;  # Validな名前か?
786      if ($pagename =~ /^$WikiName$/) {  sub is_valid_name {
787          return 1;      my ($pagename) = @_;
788      } elsif ($pagename =~ /^$BracketName$/) {      if ($pagename =~ /^$WikiName$/) {
789          return 1;          return 1;
790      } else {      } elsif ($pagename =~ /^$BracketName$/) {
791          return 0;          return 1;
792      }      } else {
793  }          return 0;
794        }
795  # 現在時刻の文字列を得る  }
796  sub get_current_datestr {  
797      my (@wdays) = ( "日", "月", "火", "水", "木", "金", "土" );  # 現在時刻の文字列を得る
798      my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time);  sub get_current_datestr {
799      return sprintf("%4d-%02d-%02d (%s) %02d:%02d:%02d",      my (@wdays) = ( "日", "月", "火", "水", "木", "金", "土" );
800          $year + 1900, $mon + 1, $mday, $wdays[$wday], $hour, $min, $sec);      my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time);
801  }      return sprintf("%4d-%02d-%02d (%s) %02d:%02d:%02d",
802            $year + 1900, $mon + 1, $mday, $wdays[$wday], $hour, $min, $sec);
803  # URL?SomePageや、  }
804  # URL?[[結城浩]]の形式だった場合、(not yet)  
805  # 強制的にmycmdをreadにして$formの内容を設定する。  # URL?SomePageや、
806  sub normalize_form {  # URL?[[結城浩]]の形式だった場合、(not yet)
807      foreach my $key (keys %form) {  # 強制的にmycmdをreadにして$formの内容を設定する。
808          if ($key =~ /^$WikiName$/) {  sub normalize_form {
809              $form{mycmd} = 'read';      foreach my $key (keys %form) {
810              $form{mypage} = $1;          if ($key =~ /^$WikiName$/) {
811              last;              $form{mycmd} = 'read';
812          } elsif ($key =~ /^$BracketName$/) {              $form{mypage} = $1;
813              $form{mycmd} = 'read';              last;
814              $form{mypage} = $1;          } elsif ($key =~ /^$BracketName$/) {
815              last;              $form{mycmd} = 'read';
816          }              $form{mypage} = $1;
817      }              last;
818  }          }
819        }
820  # 変換テストを行なうときのサンプル  }
821  sub print_sample {  
822      my $txt = &convert_html(<<"EOD");  # 変換テストを行なうときのサンプル
823  *大見出し1  sub print_sample {
824  **小見出し1-1      my $txt = &convert_html(<<"EOD");
825  -項目1  *大見出し1
826  -項目2  **小見出し1-1
827  -項目3  -項目1
828  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1  -項目2
829  段落1段落1段落1段落1段落1段落''強調''1段落1段落1段落1段落1段落1  -項目3
830  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1
831    段落1段落1段落1段落1段落1段落''強調''1段落1段落1段落1段落1段落1
832  段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1
833  段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2  
834  段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2  段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2
835  **小見出し1-2  段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2
836  :用語1:いろいろ書いた解説文1と''強調単語''  段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2
837  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1  **小見出し1-2
838  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1  :用語1:いろいろ書いた解説文1と''強調単語''
839  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1
840  :用語2:いろいろ書いた解説文2  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1
841  :用語3:いろいろ書いた解説文3  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1
842  ----  :用語2:いろいろ書いた解説文2
843  *大見出し2  :用語3:いろいろ書いた解説文3
844  **小見出し2-1  ----
845  &lt;http://suika.fam.cx/&gt;  *大見出し2
846  **小見出し2-2  **小見出し2-1
847    &lt;http://suika.fam.cx/&gt;
848  [[結城浩]]  **小見出し2-2
849    
850  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1  [[結城浩]]
851  段落1段落1段落1段落'''強調'''1段落1段落1段落1段落1段落1段落1段落1  
852  段落1段落1段落1段落'''''強い強調'''''1段落1段落1段落1段落1段落1段落1段落1段落1  段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1段落1
853  >段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2  段落1段落1段落1段落'''強調'''1段落1段落1段落1段落1段落1段落1段落1
854  >段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2  段落1段落1段落1段落'''''強い強調'''''1段落1段落1段落1段落1段落1段落1段落1段落1
855  >段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2  >段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2
856    >段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2
857  レベル0レベル0レベル0レベル0レベル0レベル0  >段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2
858    
859  >レベル1  レベル0レベル0レベル0レベル0レベル0レベル0
860  >レベル1  
861  >レベル1  >レベル1
862  >>レベル2  >レベル1
863  >>レベル2  >レベル1
864  >>レベル2  >>レベル2
865  >>>レベル3  >>レベル2
866  -はろ1  >>レベル2
867  --はろ2  >>>レベル3
868  ろろろろ2  -はろ1
869  ---はろ3  --はろ2
870  --はろ2  ろろろろ2
871  ---はろ3  ---はろ3
872  --はろ2  --はろ2
873  ---はろ3  ---はろ3
874  >>>レベル3  --はろ2
875  >>>レベル3  ---はろ3
876  >>>レベル3  >>>レベル3
877  EOD  >>>レベル3
878      print $txt;  >>>レベル3
879      exit;  EOD
880  }      print $txt;
881        exit;
882  sub diff_check {  }
883      traverse_sequences(  
884              $msgrefA, $msgrefB,  sub diff_check {
885              {      traverse_sequences(
886                  MATCH => \&df_match,              $msgrefA, $msgrefB,
887                  DISCARD_A => \&df_delete,              {
888                  DISCARD_B => \&df_add,                  MATCH => \&df_match,
889              }                  DISCARD_A => \&df_delete,
890      );                  DISCARD_B => \&df_add,
891      &diff_flush;              }
892  }      );
893        &diff_flush;
894  sub diff_flush {  }
895      $diff_text .= join('', map { "-$_\n" } splice(@diff_deleted));  
896      $diff_text .= join('', map { "+$_\n" } splice(@diff_added));  sub diff_flush {
897  }      $diff_text .= join('', map { "-$_\n" } splice(@diff_deleted));
898        $diff_text .= join('', map { "+$_\n" } splice(@diff_added));
899  sub df_match {  }
900      my ($a, $b) = @_;  
901      &diff_flush;  sub df_match {
902      $diff_text .= "=$msgrefA->[$a]\n";      my ($a, $b) = @_;
903  }      &diff_flush;
904        $diff_text .= "=$msgrefA->[$a]\n";
905  sub df_delete {  }
906      my ($a, $b) = @_;  
907      push(@diff_deleted, $msgrefA->[$a]);  sub df_delete {
908  }      my ($a, $b) = @_;
909        push(@diff_deleted, $msgrefA->[$a]);
910  sub df_add {  }
911      my ($a, $b) = @_;  
912      push(@diff_added, $msgrefB->[$b]);  sub df_add {
913  }      my ($a, $b) = @_;
914        push(@diff_added, $msgrefB->[$b]);
915  sub calc_message_digest {   # You have to use MD5...  }
916      my $text = shift;  
917      my @text = split(//, $text);  sub calc_message_digest {   # You have to use MD5...
918      my $len = length($text);      my $text = shift;
919      my $checksum = 0;      my @text = split(//, $text);
920      foreach (@text) {      my $len = length($text);
921          $checksum += ord($_);      my $checksum = 0;
922          $checksum = ($checksum * 2) % 65536 + (($checksum & 32768) ? 1 : 0); # 16bit rotate      foreach (@text) {
923      }          $checksum += ord($_);
924      return "$len:$checksum";          $checksum = ($checksum * 2) % 65536 + (($checksum & 32768) ? 1 : 0); # 16bit rotate
925  }      }
926        return "$len:$checksum";
927  # Definition of YukiWikiDB  }
928  package YukiWikiDB;  
929    # Definition of YukiWikiDB
930  my $debug = 1;  package YukiWikiDB;
931    
932  # Constructor  my $debug = 1;
933  sub new {  
934      return shift->TIEHASH(@_);  # Constructor
935  }  sub new {
936        return shift->TIEHASH(@_);
937  # tying  }
938  sub TIEHASH {  
939      my ($class, $dbname) = @_;  # tying
940      my $self = {  sub TIEHASH {
941          dir => $dbname,      my ($class, $dbname) = @_;
942          keys => [],      my $self = {
943      };          dir => $dbname,
944      if (not -d $self->{dir}) {          keys => [],
945          if (!mkdir($self->{dir}, 0777)) {      };
946              print "mkdir(" . $self->{dir} . ") fail\n" if ($debug);      if (not -d $self->{dir}) {
947              return undef;          if (!mkdir($self->{dir}, 0777)) {
948          }              print "mkdir(" . $self->{dir} . ") fail\n" if ($debug);
949      }              return undef;
950      return bless($self, $class);          }
951  }      }
952        return bless($self, $class);
953  # Store  }
954  sub STORE {  
955      my ($self, $key, $val) = @_;  # Store
956      my $file = &make_filename($self, $key);  sub STORE {
957      if (open(FILE,"> $file")) {      my ($self, $key, $val) = @_;
958          binmode(FILE);      my $file = &make_filename($self, $key);
959          print FILE $val;      if (open(FILE,"> $file")) {
960          close(FILE);          binmode(FILE);
961          return $self->{$key} = $val;          print FILE $val;
962      } else {          close(FILE);
963          print "$file create error.";          return $self->{$key} = $val;
964      }      } else {
965  }          print "$file create error.";
966        }
967  # Fetch  }
968  sub FETCH {  
969      my ($self, $key) = @_;  # Fetch
970      my $file = &make_filename($self, $key);  sub FETCH {
971      if (open(FILE, $file)) {      my ($self, $key) = @_;
972          local $/;      my $file = &make_filename($self, $key);
973          $self->{$key} = <FILE>;      if (open(FILE, $file)) {
974          close(FILE);          local $/;
975      }          $self->{$key} = <FILE>;
976      return $self->{$key};          close(FILE);
977  }      }
978        return $self->{$key};
979  # Exists  }
980  sub EXISTS {  
981      my ($self, $key) = @_;  # Exists
982      my $file = &make_filename($self, $key);  sub EXISTS {
983      return -e($file);      my ($self, $key) = @_;
984  }      my $file = &make_filename($self, $key);
985        return -e($file);
986  # Delete  }
987  sub DELETE {  
988      my ($self, $key) = @_;  # Delete
989      my $file = &make_filename($self, $key);  sub DELETE {
990      unlink $file;      my ($self, $key) = @_;
991      return delete $self->{$key};      my $file = &make_filename($self, $key);
992  }      unlink $file;
993        return delete $self->{$key};
994  sub FIRSTKEY {  }
995      my ($self) = @_;  
996      opendir(DIR, $self->{dir}) or die $self->{dir};  sub FIRSTKEY {
997      @{$self->{keys}} = grep /\.txt$/, readdir(DIR);      my ($self) = @_;
998      foreach my $name (@{$self->{keys}}) {      opendir(DIR, $self->{dir}) or die $self->{dir};
999          $name =~ s/\.txt$//;      @{$self->{keys}} = grep /\.txt$/, readdir(DIR);
1000          $name =~ s/[0-9A-F][0-9A-F]/pack("C", hex($&))/eg;      foreach my $name (@{$self->{keys}}) {
1001      }          $name =~ s/\.txt$//;
1002      return shift @{$self->{keys}};          $name =~ s/[0-9A-F][0-9A-F]/pack("C", hex($&))/eg;
1003  }      }
1004        return shift @{$self->{keys}};
1005  sub NEXTKEY {  }
1006      my ($self) = @_;  
1007      return shift @{$self->{keys}};  sub NEXTKEY {
1008  }      my ($self) = @_;
1009        return shift @{$self->{keys}};
1010  sub make_filename {  }
1011      my ($self, $key) = @_;  
1012      my $enkey = '';  sub make_filename {
1013      foreach my $ch (split(//, $key)) {      my ($self, $key) = @_;
1014          $enkey .= sprintf("%02X", ord($ch));      my $enkey = '';
1015      }      foreach my $ch (split(//, $key)) {
1016      return $self->{dir} . "/$enkey.txt";          $enkey .= sprintf("%02X", ord($ch));
1017  }      }
1018  __END__      return $self->{dir} . "/$enkey.txt";
1019    }
1020  =head1 NAME  __END__
1021    
1022  YukiWiki - 自由にページを追加・削除・編集できるWebページ構築CGI  =head1 NAME
1023    
1024      Copyright (C) 2000,2001 by Hiroshi Yuki.  YukiWiki - 自由にページを追加・削除・編集できるWebページ構築CGI
1025      結城浩 <hyuki@hyuki.com>  
1026      http://www.hyuki.com/      Copyright (C) 2000,2001 by Hiroshi Yuki.
1027      http://www.hyuki.com/yukiwiki/      結城浩 <hyuki@hyuki.com>
1028        http://www.hyuki.com/
1029  =head1 SYNOPSIS      http://www.hyuki.com/yukiwiki/
1030    
1031      http://www.hyuki.com/yukiwiki/yukiwiki.cgi  =head1 SYNOPSIS
1032    
1033  =head1 DESCRIPTION      http://www.hyuki.com/yukiwiki/yukiwiki.cgi
1034    
1035  YukiWiki(結城ウィキィ)は参加者が自由にページを追加・削除・編集できる  =head1 DESCRIPTION
1036  不思議なWebページ群を作るCGIです。  
1037  Webで動作する掲示板とちょっと似ていますが、  YukiWiki(結城ウィキィ)は参加者が自由にページを追加・削除・編集できる
1038  Web掲示板が単にメッセージを追加するだけなのに対して、  不思議なWebページ群を作るCGIです。
1039  YukiWikiは、Webページ全体を自由に変更することができます。  Webで動作する掲示板とちょっと似ていますが、
1040    Web掲示板が単にメッセージを追加するだけなのに対して、
1041  YukiWikiは、Cunningham & CunninghamのWikiWikiWebの  YukiWikiは、Webページ全体を自由に変更することができます。
1042  仕様を参考にして独自に作られました。  
1043    YukiWikiは、Cunningham & CunninghamのWikiWikiWebの
1044  YukiWikiはPerlで書かれたCGIスクリプトとして実現されていますので、  仕様を参考にして独自に作られました。
1045  Perlが動作するWebサーバならば比較的容易に設置できます。  
1046    YukiWikiはPerlで書かれたCGIスクリプトとして実現されていますので、
1047  あとはdbmopenが使える環境ならば設置できます(Version 1.5.0以降ならdbmopenが使えなくても設置できます)。  Perlが動作するWebサーバならば比較的容易に設置できます。
1048    
1049    あとはdbmopenが使える環境ならば設置できます(Version 1.5.0以降ならdbmopenが使えなくても設置できます)。
1050  YukiWikiはフリーソフトです。  
1051  ご自由にお使いください。  
1052    YukiWikiはフリーソフトです。
1053  =head1 設置方法  ご自由にお使いください。
1054    
1055  =head2 入手  =head1 設置方法
1056    
1057  YukiWikiの最新版は、  =head2 入手
1058  http://www.hyuki.com/yukiwiki/  
1059  から入手できます。  YukiWikiの最新版は、
1060    http://www.hyuki.com/yukiwiki/
1061  =head2 ファイル一覧  から入手できます。
1062    
1063      readme.txt      ドキュメント  =head2 ファイル一覧
1064      yukiwiki.cgi    YukiWiki本体  
1065      yukiwiki.gif    ロゴ(カラー版)      readme.txt      ドキュメント
1066      yukimono.gif    ロゴ(モノクロ版)      yukiwiki.cgi    YukiWiki本体
1067      jcode.pl        漢字コードライブラリ      yukiwiki.gif    ロゴ(カラー版)
1068        yukimono.gif    ロゴ(モノクロ版)
1069  =head2 インストール      jcode.pl        漢字コードライブラリ
1070    
1071  =over 4  =head2 インストール
1072    
1073  =item 1.  =over 4
1074    
1075  アーカイブを解く。  =item 1.
1076    
1077  =item 2.  アーカイブを解く。
1078    
1079  yukiwiki.cgiのはじめの方にある設定を確認します。  =item 2.
1080  通常は何もしなくてよいが、  
1081  はじめは$touchfileを''にした方がよいでしょう。  yukiwiki.cgiのはじめの方にある設定を確認します。
1082    通常は何もしなくてよいが、
1083  =item 3.  はじめは$touchfileを''にした方がよいでしょう。
1084    
1085  yukiwiki.cgiとjcode.plを同じところに設置します。  =item 3.
1086    
1087  =item 4.  yukiwiki.cgiとjcode.plを同じところに設置します。
1088    
1089  サイズ0のyukiwiki.dbというファイルを設置します。  =item 4.
1090  (Perlシステムによってはyukiwiki.pag, yukiwiki.dir)  
1091    サイズ0のyukiwiki.dbというファイルを設置します。
1092  =item 5.  (Perlシステムによってはyukiwiki.pag, yukiwiki.dir)
1093    
1094  yukiwiki.cgiにブラウザからアクセスします。  =item 5.
1095    
1096  =back  yukiwiki.cgiにブラウザからアクセスします。
1097    
1098  =head2 パーミッション  =back
1099    
1100          ファイル        パーミッション      転送モード  =head2 パーミッション
1101          yukiwiki.cgi    755                 ASCII  
1102          yukiwiki.gif    644                 BINARY          ファイル        パーミッション      転送モード
1103          yukimono.gif    644                 BINARY          yukiwiki.cgi    755                 ASCII
1104          jcode.pl        644                 ASCII          yukiwiki.gif    644                 BINARY
1105            yukimono.gif    644                 BINARY
1106      $dbmopen = 1; にした場合:          jcode.pl        644                 ASCII
1107          yukiwiki.db     666                 BINARY  
1108          (yukiwiki.pag, yukiwiki.dirの場合もあり)      $dbmopen = 1; にした場合:
1109            yukiwiki.db     666                 BINARY
1110      $dbmopen = 0; にした場合: (カレントディレクトリを777にしておく)          (yukiwiki.pag, yukiwiki.dirの場合もあり)
1111          .               777                 (転送しない)  
1112        $dbmopen = 0; にした場合: (カレントディレクトリを777にしておく)
1113  =head1 データのバックアップ方法          .               777                 (転送しない)
1114    
1115  $dbmopen = 1;の場合は、  =head1 データのバックアップ方法
1116  データはすべてyukiwiki.db(.dir, .pag)に入る。  
1117  これをバックアップすればよい。  $dbmopen = 1;の場合は、
1118    データはすべてyukiwiki.db(.dir, .pag)に入る。
1119  $dbmopen = 0;の場合は、  これをバックアップすればよい。
1120  yukiwikiというディレクトリができるので、  
1121  これ以下をバックアップすればよい。  $dbmopen = 0;の場合は、
1122    yukiwikiというディレクトリができるので、
1123  =head1 新しいページの作り方  これ以下をバックアップすればよい。
1124    
1125  =over 4  =head1 新しいページの作り方
1126    
1127  =item 1.  =over 4
1128    
1129  まず、適当なページ(例えばFrontPage)を選び、  =item 1.
1130  ページの下にある「編集」リンクをたどります。  
1131    まず、適当なページ(例えばFrontPage)を選び、
1132  =item 2.  ページの下にある「編集」リンクをたどります。
1133    
1134  するとテキスト入力ができる状態になるので、  =item 2.
1135  そこにNewPageのような単語  
1136  (大文字小文字混在している英文字列)  するとテキスト入力ができる状態になるので、
1137  を書いて「保存」します。  そこにNewPageのような単語
1138    (大文字小文字混在している英文字列)
1139  =item 3.  を書いて「保存」します。
1140    
1141  保存すると、FrontPageのページが書き換わり、  =item 3.
1142  あなたが書いたNewPageという文字列の後ろに ? というリンクが表示されます。  
1143  この ? はそのページがまだ存在しないことを示す印です。  保存すると、FrontPageのページが書き換わり、
1144    あなたが書いたNewPageという文字列の後ろに ? というリンクが表示されます。
1145  =item 4.  この ? はそのページがまだ存在しないことを示す印です。
1146    
1147  その ? をクリックすると新しいページNewPageができますので、  =item 4.
1148  あなたの好きな文章をその新しいページに書いて保存します。  
1149    その ? をクリックすると新しいページNewPageができますので、
1150  =item 5.  あなたの好きな文章をその新しいページに書いて保存します。
1151    
1152  NewPageページができるとFrontPageの ? は消えて、リンクとなります。  =item 5.
1153    
1154  =back  NewPageページができるとFrontPageの ? は消えて、リンクとなります。
1155    
1156  =head1 テキスト整形のルール  =back
1157    
1158  =over 4  =head1 テキスト整形のルール
1159    
1160  =item *  =over 4
1161    
1162  連続した複数行はフィルされて表示されます。  =item *
1163    
1164  =item *  連続した複数行はフィルされて表示されます。
1165    
1166  空行は段落C<< <p> >>の区切りとなります。  =item *
1167    
1168  =item *  空行は段落C<< <p> >>の区切りとなります。
1169    
1170  HTMLのタグは書けません。  =item *
1171    
1172  =item *  HTMLのタグは書けません。
1173    
1174  B<''ボールド''>のようにシングルクォート二つではさむと、  =item *
1175  ボールドC<< <b> >>になります。  
1176    B<''ボールド''>のようにシングルクォート二つではさむと、
1177  =item *  ボールドC<< <b> >>になります。
1178    
1179  B<'''イタリック'''>のようにシングルクォート三つではさむと、  =item *
1180  イタリックC<< <i> >>になります。  
1181    B<'''イタリック'''>のようにシングルクォート三つではさむと、
1182  =item *  イタリックC<< <i> >>になります。
1183    
1184  B<---->のようにマイナス4つがあると、  =item *
1185  水平線C<< <hr> >>になります。  
1186    B<---->のようにマイナス4つがあると、
1187  =item *  水平線C<< <hr> >>になります。
1188    
1189  行をB<*>ではじめると、  =item *
1190  大見出しC<< <h2> >>になります。  
1191    行をB<*>ではじめると、
1192  =item *  大見出しC<< <h2> >>になります。
1193    
1194  行をB<**>ではじめると、  =item *
1195  小見出しC<< <h3> >>になります。  
1196    行をB<**>ではじめると、
1197  =item *  小見出しC<< <h3> >>になります。
1198    
1199  行をマイナス-ではじめると、  =item *
1200  箇条書きC<< <ul> >>になります。  
1201  マイナスの数が増えるとレベルが下がります(3レベルまで)  行をマイナス-ではじめると、
1202    箇条書きC<< <ul> >>になります。
1203      -項目1  マイナスの数が増えるとレベルが下がります(3レベルまで)
1204      --項目1-1  
1205      --項目1-2      -項目1
1206      -項目2      --項目1-1
1207      -項目3      --項目1-2
1208      --項目3-1      -項目2
1209      ---項目3-1-1      -項目3
1210      ---項目3-1-2      --項目3-1
1211      --項目3-2      ---項目3-1-1
1212        ---項目3-1-2
1213  =item *      --項目3-2
1214    
1215  コロンを使うと、  =item *
1216  用語と解説文のリストC<< <dl> >>が書けます。  
1217    コロンを使うと、
1218      :用語1:いろいろ書いた解説文1  用語と解説文のリストC<< <dl> >>が書けます。
1219      :用語2:いろいろ書いた解説文2  
1220      :用語3:いろいろ書いた解説文3      :用語1:いろいろ書いた解説文1
1221        :用語2:いろいろ書いた解説文2
1222  =item *      :用語3:いろいろ書いた解説文3
1223    
1224  リンク  =item *
1225    
1226  =over 4  リンク
1227    
1228  =item *  =over 4
1229    
1230  LinkToSomePageやFrontPageのように、  =item *
1231  英単語の最初の一文字を大文字にしたものが  
1232  二つ以上連続したものはYukiWikiのページ名となり、  LinkToSomePageやFrontPageのように、
1233  それが文章中に含まれるとリンクになります。  英単語の最初の一文字を大文字にしたものが
1234    二つ以上連続したものはYukiWikiのページ名となり、
1235  =item *  それが文章中に含まれるとリンクになります。
1236    
1237  http://www.hyuki.com/ のようなURLは自動的にリンクになります。  =item *
1238    
1239  =item *  http://www.hyuki.com/ のようなURLは自動的にリンクになります。
1240    
1241  二重の大かっこ[[ ]]でくくった文字列も、  =item *
1242  YukiWikiのページ名になります。  
1243  大かっこの中にはスペースを含めてはいけません。  二重の大かっこ[[ ]]でくくった文字列も、
1244  日本語も使えます。  YukiWikiのページ名になります。
1245    大かっこの中にはスペースを含めてはいけません。
1246  =back  日本語も使えます。
1247    
1248  =item *  =back
1249    
1250  行頭がスペースやタブで始まっていると、  =item *
1251  それは整形済みの段落C<< <pre> >>として扱われます。  
1252  プログラムの表示などに使うと便利です。  行頭がスペースやタブで始まっていると、
1253    それは整形済みの段落C<< <pre> >>として扱われます。
1254    プログラムの表示などに使うと便利です。
1255  =item *  
1256    
1257  行を > ではじめると、  =item *
1258  引用文C<< <blockquote> >>が書けます。  
1259  >の数が多いとインデントが深くなります(3レベルまで)。  行を > ではじめると、
1260    引用文C<< <blockquote> >>が書けます。
1261      >文章  >の数が多いとインデントが深くなります(3レベルまで)。
1262      >文章  
1263      >>さらなる引用      >文章
1264      >文章      >文章
1265        >>さらなる引用
1266  =back      >文章
1267    
1268  =head1 更新履歴  =back
1269    
1270  =over 4  =head1 更新履歴
1271    
1272  =item *  =over 4
1273    
1274  2001年10月20日、Version 1.6.6。  =item *
1275    
1276  更新の衝突対策。  2001年10月20日、Version 1.6.6。
1277  元ページの簡単なチェックサムを取っておき、  
1278  更新前にチェックサムを比較する。  更新の衝突対策。
1279  修正個所はdigestという文字列を検索すれば分かる。  元ページの簡単なチェックサムを取っておき、
1280  本来はMD5などでちゃんとやった方がいいのだけれど。  更新前にチェックサムを比較する。
1281    修正個所はdigestという文字列を検索すれば分かる。
1282  衝突時に表示されるメッセージなどは「極悪」さんのページを参考にした。  本来はMD5などでちゃんとやった方がいいのだけれど。
1283    
1284  =item *  衝突時に表示されるメッセージなどは「極悪」さんのページを参考にした。
1285    
1286  2001年10月17日、Version 1.6.5。  =item *
1287    
1288  プレビュー画面で、更新ボタンを押したときに送信される  2001年10月17日、Version 1.6.5。
1289  メッセージの内容をinput要素のtype="hidden"を使って埋め込むのをやめる。  
1290  代わりに、textarea要素を使う。  プレビュー画面で、更新ボタンを押したときに送信される
1291  再プレビュー用にmyspecial_を導入。でもきれいな対策ではない。  メッセージの内容をinput要素のtype="hidden"を使って埋め込むのをやめる。
1292    代わりに、textarea要素を使う。
1293  =item *  再プレビュー用にmyspecial_を導入。でもきれいな対策ではない。
1294    
1295  2001年8月30日、Version 1.6.4。  =item *
1296    
1297  URLでダイレクトにページ名を指定しても、  2001年8月30日、Version 1.6.4。
1298  $WikiNameと$BracketName以外のページを作れないようにした。  
1299  (is_valid_nameとis_editable参照)。  URLでダイレクトにページ名を指定しても、
1300    $WikiNameと$BracketName以外のページを作れないようにした。
1301  =item *  (is_valid_nameとis_editable参照)。
1302    
1303  2001年8月30日、Version 1.6.3。  =item *
1304    
1305  RecentChangesを編集・再編集不可とした。  2001年8月30日、Version 1.6.3。
1306  編集不可ページは@uneditableにページ名を入れる。  
1307    RecentChangesを編集・再編集不可とした。
1308  =item *  編集不可ページは@uneditableにページ名を入れる。
1309    
1310  2001年2月25日、Version 1.6.1, 1.6.2。  =item *
1311    
1312  差分機能のバグ修正。  2001年2月25日、Version 1.6.1, 1.6.2。
1313  do_previewで'>'が扱えないバグを修正  
1314  (ユーザからの指摘)。  差分機能のバグ修正。
1315    do_previewで'>'が扱えないバグを修正
1316  =item *  (ユーザからの指摘)。
1317    
1318  2001年2月22日、Version 1.6.0。  =item *
1319  差分機能を実装した。  
1320    2001年2月22日、Version 1.6.0。
1321  =item *  差分機能を実装した。
1322    
1323  2001年2月19日、Version 1.5.4。  =item *
1324  画像ファイルへのリンクは画像にしてみた。  
1325    2001年2月19日、Version 1.5.4。
1326  =item *  画像ファイルへのリンクは画像にしてみた。
1327    
1328  2001年2月19日、Version 1.5.3。  =item *
1329  RecentChangesの中に削除したページがあるのをやめた。  
1330  use strict;で引っかかる部分を少し整理(完全ではない)。  2001年2月19日、Version 1.5.3。
1331    RecentChangesの中に削除したページがあるのをやめた。
1332  =item *  use strict;で引っかかる部分を少し整理(完全ではない)。
1333    
1334  2001年2月16日、Version 1.5.2。  =item *
1335  textareaに表示およびプレビューする前に < や > を &lt; や &gt; に変換した  
1336  (do_preview, editpage, print_preview_buttons)。  2001年2月16日、Version 1.5.2。
1337    textareaに表示およびプレビューする前に < や > を &lt; や &gt; に変換した
1338  =item *  (do_preview, editpage, print_preview_buttons)。
1339    
1340  2000年12月27日、Version 1.5.1。  =item *
1341  プレビュー画面を整理した。  
1342    2000年12月27日、Version 1.5.1。
1343  =item *  プレビュー画面を整理した。
1344    
1345  2000年12月22日、Version 1.5.0。  =item *
1346  全体的にずいぶん書き直した。  
1347  一覧を別途作成するようにした(do_list)。  2000年12月22日、Version 1.5.0。
1348  書き込む前に確認画面を出すようにした(do_preview)。  全体的にずいぶん書き直した。
1349  テキストの書き方を編集画面に入れた(do_edit, do_reedit)。  一覧を別途作成するようにした(do_list)。
1350  WhatsNew→RecentChanges、TopPage→FrontPageに変更した。  書き込む前に確認画面を出すようにした(do_preview)。
1351    テキストの書き方を編集画面に入れた(do_edit, do_reedit)。
1352  =item *  WhatsNew→RecentChanges、TopPage→FrontPageに変更した。
1353    
1354  2000年12月20日、Version 1.1.0。  =item *
1355  tieを利用して、dbmopenが使えない場合でも動作するように修正。  
1356  利用者の1人である「極悪」さんから  2000年12月20日、Version 1.1.0。
1357  送っていただいたコードを元にしています。  tieを利用して、dbmopenが使えない場合でも動作するように修正。
1358    利用者の1人である「極悪」さんから
1359  =item *  送っていただいたコードを元にしています。
1360    
1361  2000年9月5日、Version 1.0.2。  =item *
1362   <body color=...> → <body bgcolor=...>  
1363  利用者からの指摘による。感謝。  2000年9月5日、Version 1.0.2。
1364     <body color=...> → <body bgcolor=...>
1365  =item *  利用者からの指摘による。感謝。
1366    
1367  2000年8月6日、Version 1.0.1を公開。  =item *
1368  C MAGAZINE(ソフトバンクパブリッシング)  
1369  2000年10月号連載記事向け公開版。  2000年8月6日、Version 1.0.1を公開。
1370  [[ ]] の最後が「望」のようにシフトJISで  C MAGAZINE(ソフトバンクパブリッシング)
1371  0x5Dになる場合の回避を行なった。  2000年10月号連載記事向け公開版。
1372    [[ ]] の最後が「望」のようにシフトJISで
1373  =item *  0x5Dになる場合の回避を行なった。
1374    
1375  2000年8月5日、Version 1.0.0を公開。  =item *
1376    
1377  =item *  2000年8月5日、Version 1.0.0を公開。
1378    
1379  2000年7月23日、Version 0.82を公開。  =item *
1380  編集時のリンクミス。  
1381  <textarea>の属性変更。  2000年7月23日、Version 0.82を公開。
1382    編集時のリンクミス。
1383  =item *  <textarea>の属性変更。
1384    
1385  2000年7月22日、Version 0.81を公開。  =item *
1386  ロゴを組み込む。  
1387    2000年7月22日、Version 0.81を公開。
1388  =item *  ロゴを組み込む。
1389    
1390  2000年7月21日、Version 0.80を公開。  =item *
1391  PODをCGI中に書き込む。  
1392    2000年7月21日、Version 0.80を公開。
1393  =item *  PODをCGI中に書き込む。
1394    
1395  2000年7月19日、Version 0.70を公開。  =item *
1396  '''イタリック'''や、--、---、>>、>>>などを実装。  
1397    2000年7月19日、Version 0.70を公開。
1398  =item *  '''イタリック'''や、--、---、>>、>>>などを実装。
1399    
1400  2000年7月18日、Version 0.60を公開。  =item *
1401  *太字*を''太字''に変更  
1402    2000年7月18日、Version 0.60を公開。
1403  =item *  *太字*を''太字''に変更
1404    
1405  2000年7月17日、Version 0.50を公開。  =item *
1406    
1407  =item *  2000年7月17日、Version 0.50を公開。
1408    
1409  2000年7月17日、さらにいろいろ追加する。  =item *
1410    
1411  =item *  2000年7月17日、さらにいろいろ追加する。
1412    
1413  2000年7月16日、いろいろ追加。  =item *
1414    
1415  =item *  2000年7月16日、いろいろ追加。
1416    
1417  2000年7月15日、公開。  =item *
1418    
1419  =back  2000年7月15日、公開。
1420    
1421  =head1 TODO  =back
1422    
1423      - テキスト表示モード  =head1 TODO
1424      - Charsetを明示。  
1425      - textarea中の閉じタグ対応      - テキスト表示モード
1426      - メニューの英語表記付記      - Charsetを明示。
1427      - プレビューのボタンで、mymsgをinputのvalueに入れているが、改行をそのままvalueにいれてはいけないのではないか。      - textarea中の閉じタグ対応
1428      - 「再編集」の機能はブラウザの back で充分ではないか。プレビューはもっとシンプルに。      - メニューの英語表記付記
1429      - ページタイトル(Wikiname)が検索にかかるようにする。      - プレビューのボタンで、mymsgをinputのvalueに入れているが、改行をそのままvalueにいれてはいけないのではないか。
1430      - InterWiki風の機能「URLを隠しつつ、リンクを張る」      - 「再編集」の機能はブラウザの back で充分ではないか。プレビューはもっとシンプルに。
1431        - ページタイトル(Wikiname)が検索にかかるようにする。
1432  =head1 作者      - InterWiki風の機能「URLを隠しつつ、リンクを張る」
1433    
1434      Copyright (C) 2000 by Hiroshi Yuki.  =head1 作者
1435      結城浩 <hyuki@hyuki.com>  
1436      http://www.hyuki.com/      Copyright (C) 2000 by Hiroshi Yuki.
1437      http://www.hyuki.com/yukiwiki/      結城浩 <hyuki@hyuki.com>
1438        http://www.hyuki.com/
1439  質問、意見、バグ報告は hyuki@hyuki.com にメールしてください。      http://www.hyuki.com/yukiwiki/
1440    
1441  =head1 配布条件  質問、意見、バグ報告は hyuki@hyuki.com にメールしてください。
1442    
1443  YukiWikiは、  =head1 配布条件
1444  GNU General Public Licenseにて公開します。  
1445    YukiWikiは、
1446  YukiWikiはフリーソフトです。  GNU General Public Licenseにて公開します。
1447  ご自由にお使いください。  
1448  自分好みのYukiWikiが作れるようにシンプルにしてあります。  YukiWikiはフリーソフトです。
1449    ご自由にお使いください。
1450  =head1 謝辞  自分好みのYukiWikiが作れるようにシンプルにしてあります。
1451    
1452  本家のWikiWikiを作ったCunningham & Cunningham, Inc.に  =head1 謝辞
1453  感謝します。  
1454    本家のWikiWikiを作ったCunningham & Cunningham, Inc.に
1455  YukiWikiを楽しんで使ってくださる  感謝します。
1456  ネット上の方々に感謝します。  
1457    YukiWikiを楽しんで使ってくださる
1458  YukiWikiのロゴをデザインしてくださった橋本礼奈さん  ネット上の方々に感謝します。
1459  http://city.hokkai.or.jp/~reina/  
1460  に感謝します。  YukiWikiのロゴをデザインしてくださった橋本礼奈さん
1461    http://city.hokkai.or.jp/~reina/
1462  tieを使った版の元になるコードを送ってくださった  に感謝します。
1463  「極悪」さんに感謝します。  
1464    tieを使った版の元になるコードを送ってくださった
1465  =head1 参照リンク  「極悪」さんに感謝します。
1466    
1467  =over 4  =head1 参照リンク
1468    
1469  =item *  =over 4
1470    
1471  YukiWikiホームページ  =item *
1472  http://www.hyuki.com/yukiwiki/  
1473    YukiWikiホームページ
1474  =item *  http://www.hyuki.com/yukiwiki/
1475    
1476  本家のWikiWiki  =item *
1477  http://c2.com/cgi/wiki?WikiWikiWeb  
1478    本家のWikiWiki
1479  =item *  http://c2.com/cgi/wiki?WikiWikiWeb
1480    
1481  本家のWikiWikiの作者(Cunningham & Cunningham, Inc.)  =item *
1482  http://c2.com/  
1483    本家のWikiWikiの作者(Cunningham & Cunningham, Inc.)
1484  =item *  http://c2.com/
1485    
1486  YukiWikiのロゴデザインをしてくださった橋本礼奈さんのページ  =item *
1487  http://city.hokkai.or.jp/~reina/  
1488    YukiWikiのロゴデザインをしてくださった橋本礼奈さんのページ
1489  =back  http://city.hokkai.or.jp/~reina/
1490    
1491  =cut  =back
1492    
1493    =cut

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.10

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24