FSWikiLite 0.1.0リリース
@@ -0,0 +1 @@ | ||
1 | +{{lastmodified}} | |
\ No newline at end of file |
@@ -0,0 +1,19 @@ | ||
1 | +!!!FSWikiLite | |
2 | +FSWikiLiteはPerlによるWikiクローンです。 | |
3 | +元になっているFreeStyleWikiほど高機能ではありませんが、機能を限定することで軽快に動作します。 | |
4 | +プラグインは一部しか使用できませんが、文法はFSWikiと完全互換です。 | |
5 | +また、FSWikiと比べると構造がシンプルな分、設置も容易です。 | |
6 | + | |
7 | +その他にFSWikiLiteは以下のような特徴があります。 | |
8 | + | |
9 | +*Perlで書かれておりDBも使用しないため、CGIが動作するサーバであればほとんどのサーバに設置可能。 | |
10 | +*FSWikiとは異なるシンプルなプラグイン機構を備えている。 | |
11 | +*全ページ共通のヘッダ、フッタ、サイドバーを表示可能。 | |
12 | +*[tDiary|http://www.tdiary.org]のテーマを使用可能。 | |
13 | +*.htaccessを使用することで編集を管理人のみに限定することが可能。 | |
14 | +*ページのカテゴライズが可能。 | |
15 | +*ファイルの添付が可能。 | |
16 | + | |
17 | +*PDF生成、キーワードリンク、InterWikiなどは使用不可。 | |
18 | + | |
19 | +FreeStyle WikiはGNU GPLライセンスの元で配布、改変が許可されるフリーソフトウェアです。 |
@@ -0,0 +1 @@ | ||
1 | +{{outline}} | |
\ No newline at end of file |
@@ -0,0 +1,122 @@ | ||
1 | +!!!見出し | |
2 | +行を!ではじめると見出しになります。見出しは3レベルあります。 | |
3 | + !!!大見出し | |
4 | + !!中見出し | |
5 | + !小見出し | |
6 | +!!!大見出し | |
7 | +!!中見出し | |
8 | +!小見出し | |
9 | + | |
10 | +!!!テキスト装飾 | |
11 | + シングルクォート2つで囲むと''イタリック''になります。 | |
12 | + シングルクォート3つで囲むと'''ボールド'''になります。 | |
13 | + これは==打ち消し線==です。 | |
14 | + これは__下線__です。 | |
15 | +シングルクォート2つで囲むと''イタリック''になります。 | |
16 | +シングルクォート3つで囲むと'''ボールド'''になります。 | |
17 | +これは==打ち消し線==です。 | |
18 | +これは__下線__です。 | |
19 | + | |
20 | +!!!引用 | |
21 | + ""これは引用です。 | |
22 | + ""これも引用です。 | |
23 | +""これは引用です。 | |
24 | +""これも引用です。 | |
25 | + | |
26 | +!!!説明 | |
27 | + :項目:説明文 | |
28 | +:項目:説明文 | |
29 | + | |
30 | + ::項目 | |
31 | + :::説明文は複数行にわけて書くこともできます。 | |
32 | + :::こんな感じで。 | |
33 | +::項目 | |
34 | +:::説明文は複数行にわけて書くこともできます。 | |
35 | +:::こんな感じで。 | |
36 | + | |
37 | +!!!項目 | |
38 | +行を*ではじめるとリストになります。リストは*の個数に応じて3段階までネストすることができます。 | |
39 | + *項目1-1 | |
40 | + **項目2-1 | |
41 | + **項目2-2 | |
42 | + ***項目3-1 | |
43 | + *項目1-2 | |
44 | + **項目2-3 | |
45 | +*項目1-1 | |
46 | +**項目2-1 | |
47 | +**項目2-2 | |
48 | +***項目3-1 | |
49 | +*項目1-2 | |
50 | +**項目2-3 | |
51 | +行を+ではじめると番号付きリストになります。 | |
52 | + +番号付き項目1 | |
53 | + ++番号付き項目1-1 | |
54 | + +番号付き項目2 | |
55 | + +番号付き項目3 | |
56 | ++番号付き項目1 | |
57 | +++番号付き項目1-1 | |
58 | ++番号付き項目2 | |
59 | ++番号付き項目3 | |
60 | + | |
61 | +!!!リンク | |
62 | + *http://www.yahoo.co.jp/ | |
63 | + *[Google|http://www.google.co.jp/] | |
64 | + *[[FrontPage]] | |
65 | + *[[トップ|FrontPage]] | |
66 | + *[[トップの最初の見出し|FrontPage#p0]] | |
67 | + *[[このページの「リンク」見出し|#p8]] | |
68 | + *mailto:foo@xxx.dom | |
69 | + *[メールはこちら|mailto:foo@xxx.dom?subject=TEST&body=TESTMAIL] | |
70 | +*http://www.yahoo.co.jp/ | |
71 | +*[Google|http://www.google.co.jp/] | |
72 | +*[[FrontPage]] | |
73 | +*[[トップ|FrontPage]] | |
74 | +*[[トップの最初の見出し|FrontPage#p0]] | |
75 | +*[[このページの「リンク」見出し|#p8]] | |
76 | +*mailto:foo@xxx.dom | |
77 | +*[メールはこちら|mailto:foo@xxx.dom?subject=TEST&body=TESTMAIL] | |
78 | + | |
79 | +!!!テーブル | |
80 | +CSVはテーブルになります。1行目がヘッダになります。 | |
81 | + | |
82 | + ,h-1,h-2,h-3 | |
83 | + ,1-1,1-2,1-3 | |
84 | + ,2-1,2-2,2-3 | |
85 | +,h-1,h-2,h-3 | |
86 | +,1-1,1-2,1-3 | |
87 | +,2-1,2-2,2-3 | |
88 | + | |
89 | +セル内にカンマを含めたい場合は値をダブルクォートで囲みます。また、ダブルクォートで囲んだセルにダブルクォートを表示したい場合はダブルクォートを2つ続けて記述します。 | |
90 | + | |
91 | + ,カンマ,ダブルクォート | |
92 | + ,"セルの中にカンマ,を表示","セルの中にダブルクォート""を表示" | |
93 | +,カンマ,ダブルクォート | |
94 | +,"セルの中にカンマ,を表示","セルの中にダブルクォート""を表示" | |
95 | + | |
96 | +セル内に"<<"を記述すると左側のセルと結合します。 | |
97 | + ,h-1,h-2,h-3 | |
98 | + ,1-1,1-2,1-3 | |
99 | + ,2-1,<<,2-3 | |
100 | +,h-1,h-2,h-3 | |
101 | +,1-1,1-2,1-3 | |
102 | +,2-1,<<,2-3 | |
103 | + | |
104 | + | |
105 | +!!!整形済テキスト | |
106 | +行頭をスペースまたはタブではじめると整形済テキストとして扱われます。 | |
107 | + これは整形済テキストです。 | |
108 | + 入力したとおりに表示されます。 | |
109 | + | |
110 | +!!!水平線 | |
111 | +行頭に----と書くと水平線になります。 | |
112 | + ---- | |
113 | +---- | |
114 | + | |
115 | +!!!コメント | |
116 | +行を//ではじめるとその行はコメントとみなされます。コメント行は一切出力されません。 | |
117 | + | |
118 | + //これはコメントになります。画面には出力されません。 | |
119 | +//これはコメントになります。画面には出力されません。 | |
120 | + | |
121 | +!!!ヘッダ、フッタ、サイドバー | |
122 | +[[Header]]、[[Footer]]、[[Menu]]という名前のページを作成するとそれぞれヘッダ、フッタ、サイドバーが表示されます。また、[[EditHelper]]というページを作成するとページの編集画面の下部にヘルプとして表示されます。 |
@@ -0,0 +1,12 @@ | ||
1 | +{{search v}} | |
2 | + | |
3 | +!!!メニュー | |
4 | +*[[トップ|FrontPage]] | |
5 | +*[[ヘルプ|Help]] | |
6 | +*[[プラグイン|PluginHelp]] | |
7 | + | |
8 | +*[FSWikiLiteとは?|./docs/readme.html] | |
9 | +*[プラグイン開発|./docs/plugindev.html] | |
10 | + | |
11 | +!!!最新 | |
12 | +{{recentdays 10}} |
@@ -0,0 +1,117 @@ | ||
1 | +!!!使用可能なプラグイン | |
2 | + | |
3 | +!!category | |
4 | + | |
5 | +ページをカテゴライズするためのプラグインです。引数にカテゴリ名を指定します。 | |
6 | + | |
7 | + {{category カテゴリ名}} | |
8 | + | |
9 | +!!category_list | |
10 | + | |
11 | +カテゴリごとのページ一覧を表示します。 | |
12 | + | |
13 | + {{category_list}} | |
14 | + | |
15 | +引数として表示するカテゴリを指定することもできます。 | |
16 | + | |
17 | + {{category_list カテゴリ名}} | |
18 | + | |
19 | +!!lastmodified | |
20 | + | |
21 | +ページの最終更新日時を表示します。 | |
22 | + | |
23 | + {{lastmodified}} | |
24 | + | |
25 | +引数でページ名を指定すると指定したページの最終更新日時を表示します。 | |
26 | + | |
27 | + {{lastmodified ページ名}} | |
28 | + | |
29 | +!!outline | |
30 | + | |
31 | +ページのアウトラインを表示します。見出しがツリー形式で表示され、クリックするとその見出しにジャンプします。Headerなどに入れておくと便利です。 | |
32 | + | |
33 | + {{outline}} | |
34 | + | |
35 | +引数でページ名を指定すると指定したページを対象とします。 | |
36 | + | |
37 | + {{outline ページ名}} | |
38 | + | |
39 | +!!pre | |
40 | + | |
41 | +preタグを出力するブロックプラグインです。 | |
42 | + | |
43 | + {{pre | |
44 | + ここにテキストを書く | |
45 | + }} | |
46 | + | |
47 | +引数に"num"を指定すると行番号付きになります。 | |
48 | + {{pre num | |
49 | + ここにテキストを書く | |
50 | + }} | |
51 | + | |
52 | +!!raw | |
53 | + | |
54 | +引数で指定した文字列をそのまま表示します。 | |
55 | + | |
56 | + {{raw テキスト}} | |
57 | + | |
58 | +!!recent | |
59 | + | |
60 | +更新日時順にページ名の一覧を出力します。引数で表示件数を指定できます。引数に"v"を指定すると縦に表示します。表示件数を省略すると全件出力します。 | |
61 | + | |
62 | + {{recent 10}} | |
63 | + {{recent 10,v}} | |
64 | + | |
65 | +!!recentdays | |
66 | + | |
67 | +日付ごとに更新されたページを一覧表示します。引数で表示日数を指定できます。表示日数を省略すると最新の5日分を出力します。 | |
68 | + | |
69 | + {{recentdays 10}} | |
70 | + | |
71 | +!!ref | |
72 | + | |
73 | +添付ファイルへのリンクを出力するプラグインです。 | |
74 | + | |
75 | + {{ref ファイル名}} | |
76 | + | |
77 | +引数でページ名を指定すると指定したページの添付ファイルを対象とします。 | |
78 | + | |
79 | + {{ref ファイル名,ページ名}} | |
80 | + | |
81 | +通常はアンカとしてファイル名が表示されますが、 別名として任意の文字列を表示することもできます。 | |
82 | + | |
83 | + {{ref ファイル名,ページ名,別名}} | |
84 | + | |
85 | +!!ref_image | |
86 | + | |
87 | +添付ファイルを画像として表示するプラグインです。 | |
88 | + | |
89 | + {{ref_image ファイル名}} | |
90 | + | |
91 | +オプションで画像のサイズを指定することができます。 以下の例では幅650ピクセル、高さ400ピクセルで画像を表示します。 | |
92 | + | |
93 | + {{ref_image ファイル名,w650,h400}} | |
94 | + | |
95 | +別のページに添付されたファイルを参照することもできます。 | |
96 | + | |
97 | + {{ref_image ファイル名,ページ名}} | |
98 | + | |
99 | +!!ref_text | |
100 | + | |
101 | +添付ファイルを整形済テキストとして表示するプラグインです。 | |
102 | + | |
103 | + {{ref_text ファイル名}} | |
104 | + | |
105 | +別のページに添付されたファイルを参照することもできます。 | |
106 | + | |
107 | + {{ref_text ファイル名,ページ名}} | |
108 | + | |
109 | +!!search | |
110 | + | |
111 | +検索フォームを表示します。 | |
112 | + | |
113 | + {{search}} | |
114 | + | |
115 | +引数に"v"を指定すると縦に表示します。サイドバーなどに入れておくと便利です。 | |
116 | + | |
117 | + {{search v}} |
@@ -0,0 +1,129 @@ | ||
1 | +body { | |
2 | + background-color: #FFFFFF; | |
3 | + color : #000000; | |
4 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
5 | +} | |
6 | + | |
7 | +p.adminmenu { | |
8 | + text-align : right; | |
9 | + padding-bottom : 5px; | |
10 | + margin-bottom : 5px; | |
11 | + border-bottom : #000088 1px dotted; | |
12 | + font-size : 80%; | |
13 | + text-indent : 10px; | |
14 | +} | |
15 | + | |
16 | +.footer { | |
17 | + border-top : #000088 1px dotted; | |
18 | + margin-top : 20px; | |
19 | + padding-top : 5px; | |
20 | + text-align : right; | |
21 | + font-size : 80%; | |
22 | + font-style : italic; | |
23 | +} | |
24 | + | |
25 | +hr { | |
26 | + color : #FFFFFF; | |
27 | +} | |
28 | + | |
29 | +pre { | |
30 | + border : #888888 1px solid; | |
31 | + padding : 4px; | |
32 | + margin-left : 40px; | |
33 | +} | |
34 | + | |
35 | +p { | |
36 | + padding-left : 20pt; | |
37 | +} | |
38 | + | |
39 | +strong { | |
40 | + font-weight : normal; | |
41 | +} | |
42 | + | |
43 | +h1 { | |
44 | + background-color : #FFFFFF; | |
45 | + border-bottom : #AABBFF 1px solid; | |
46 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
47 | + padding-left : 4pt; | |
48 | +} | |
49 | + | |
50 | + | |
51 | +h2 { | |
52 | + background-color : #AABBFF; | |
53 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
54 | + padding-left : 4pt; | |
55 | +} | |
56 | + | |
57 | +h3 { | |
58 | + border-left : #AABBFF 10px solid; | |
59 | + border-top : #AABBFF 5px solid; | |
60 | + border-right : #AABBFF 1px solid; | |
61 | + border-bottom : #AABBFF 1px solid; | |
62 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
63 | + font-size : 100%; | |
64 | + padding-left : 4pt; | |
65 | +} | |
66 | + | |
67 | +h4 { | |
68 | + border-left : #AABBFF 10px solid; | |
69 | + padding-left : 4px; | |
70 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
71 | + padding-left : 4pt; | |
72 | +} | |
73 | + | |
74 | +table { | |
75 | + border : #888888 2px solid; | |
76 | +} | |
77 | + | |
78 | +th { | |
79 | + border : #888888 1px solid; | |
80 | + background-color : #88AAFF; | |
81 | +} | |
82 | + | |
83 | +td { | |
84 | + border : #888888 1px solid; | |
85 | +} | |
86 | + | |
87 | +A:link { | |
88 | + color : #4444FF; | |
89 | + text-decoration : none; | |
90 | +} | |
91 | +A:visited { | |
92 | + color : #4444FF; | |
93 | + text-decoration : none; | |
94 | +} | |
95 | +A:hover { | |
96 | + color : #FF4444; | |
97 | + text-decoration : underline; | |
98 | +} | |
99 | + | |
100 | +div.main { | |
101 | + margin-left: 20%; | |
102 | +} | |
103 | + | |
104 | +div.sidebar { | |
105 | + position : absolute; | |
106 | + top : 0px; | |
107 | + left : 0px; | |
108 | + width : 20%; | |
109 | + font-size : x-small; | |
110 | + padding: 2px 2px 100% 2px; | |
111 | + border-style: solid; | |
112 | + border-color: #CCCCFF; | |
113 | + border-width: 2px; | |
114 | + color : #000000; | |
115 | + background-color: #EEEEFF; | |
116 | +} | |
117 | + | |
118 | +div.comment { | |
119 | + margin-top : 10px; | |
120 | + margin-bottom : 10px; | |
121 | + background-color : DDDDFF; | |
122 | + border : AAAAFF 2px solid; | |
123 | + font-size : 80%; | |
124 | +} | |
125 | + | |
126 | +.error { | |
127 | + color : #FF0000; | |
128 | + font-weight : bold; | |
129 | +} |
@@ -0,0 +1,4 @@ | ||
1 | +#!/bin/sh | |
2 | +# HTMLファイルに変換 | |
3 | +perl ../../tools/wiki2html.pl "http://fswiki.osdn.jp/cgi-bin/wiki.cgi/docs?action=SOURCE&page=FSWikiLite%2Freadme" -css=default.css -title=README > readme.html | |
4 | +perl ../../tools/wiki2html.pl "http://fswiki.osdn.jp/cgi-bin/wiki.cgi/docs?action=SOURCE&page=FSWikiLite%2F%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3%B3%AB%C8%AF" -css=default.css -title=プラグイン開発 > plugindev.html |
@@ -0,0 +1,124 @@ | ||
1 | +<html> | |
2 | +<head> | |
3 | + <title>プラグイン開発</title> | |
4 | + <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP"> | |
5 | + <link rel="stylesheet" type="text/css" href="default.css"> | |
6 | +</head> | |
7 | +<body> | |
8 | +<h1>プラグイン開発</h1> | |
9 | +<h2>サポートするプラグイン</h2> | |
10 | +<p>FSWikiLiteはFSWikiとは違い、Wikiページに記述して使用するタイプのプラグイン(インラインプラグインとパラグラフプラグイン、ブロックプラグイン)しかサポートしていません。ただし、FSWikiでアクションプラグインと呼ばれているものについては別のCGIスクリプトを用意することで対応することができます(Liteのcategory.cgiなどがこれにあたります)。</p> | |
11 | +<p>プラグインは〜.plという名前を付けてpluginディレクトリに配置します。そしてlib/setup.plでrequireします。デフォルトのsetup.plではcore.plのみ読み込むよう設定されています。</p> | |
12 | +<pre>require "./plugin/core.pl"; | |
13 | +</pre> | |
14 | +<h2>インラインプラグイン</h2> | |
15 | +<p>インラインプラグインはWiki::Pluginパッケージで定義されたPerl関数のリファレンスです。関数の引数にはWikiソースで記述した引数がそのまま渡されます。関数は戻り値としてHTMLを返すように実装します。また、スクリプトのBEGIN節で関数のリファレンスをインラインプラグインとして登録します。</p> | |
16 | +<pre>package Wiki::Plugin; | |
17 | +BEGIN { | |
18 | + $main::I_PLUGIN->{hello} = \&hello; | |
19 | +} | |
20 | +sub hello { | |
21 | + my $name = shift; | |
22 | + if($name eq ''){ | |
23 | + return "名前を入力してください。"; | |
24 | + } else { | |
25 | + return "こんにちは".&Util::escapeHTML($name)."さん"; | |
26 | + } | |
27 | +} | |
28 | +1; | |
29 | +</pre> | |
30 | +<p>ページ編集時に以下の書式で使用することができます。</p> | |
31 | +<pre>{{hello たろう}} | |
32 | +</pre> | |
33 | +<h2>パラグラフプラグイン</h2> | |
34 | +<p>パラグラフプラグインも実装方法はインラインプラグインと同様です。ブロック要素を含むHTMLを返却する場合にはパラグラフプラグインとして実装します。BEGIN節での登録方法のみが異なります。</p> | |
35 | +<pre>BEGIN { | |
36 | + $main::P_PLUGIN->{hello} = \&hello; | |
37 | +} | |
38 | +</pre> | |
39 | +<h2>ブロックプラグイン</h2> | |
40 | +<p>ブロックプラグインも実装方法はインラインプラグインと同様です。複数行に渡るパラメータを使用する場合にはブロックプラグインとして実装します。</p> | |
41 | +<pre>BEGIN { | |
42 | + $main::B_PLUGIN-&gt;{hello} = \&amp;hello; | |
43 | +} | |
44 | +sub hello { | |
45 | + my $text = shift; | |
46 | + my $name = shift; | |
47 | + if($name eq ''){ | |
48 | + return "名前を入力してください。"; | |
49 | + } else { | |
50 | + return "こんにちは".&Util::escapeHTML($name)."さん&lt;br&gt;\n".$text; | |
51 | + } | |
52 | +} | |
53 | +---- Wikiコード ---- | |
54 | +{{hello たろう | |
55 | +ご機嫌いかがですか? | |
56 | +今日は良い天気ですね。 | |
57 | +}} | |
58 | +</pre> | |
59 | +<h2>リクエストパラメータへのアクセス</h2> | |
60 | +<p>プラグイン内部からリクエストパラメータにアクセスするには%main::inという変数を利用します。これはcgi-lib.plでパースされたリクエストパラメータが格納された連想配列です。</p> | |
61 | +<pre># ページ名を取得 | |
62 | +my $p = $main::in{'p'}; | |
63 | +</pre> | |
64 | +<h2>プラグインから利用可能なユーティリティ</h2> | |
65 | +<p>プラグイン内部ではUtilパッケージに定義されたユーティリティ関数を使用することができます。Utilパッケージには以下のような関数が定義されています。</p> | |
66 | +<table> | |
67 | +<tr> | |
68 | +<th colspan="1">関数名</th> | |
69 | +<th colspan="1">説明</th> | |
70 | +</tr> | |
71 | +<tr> | |
72 | +<td colspan="1">url_encode</td> | |
73 | +<td colspan="1">URLエンコードします。</td> | |
74 | +</tr> | |
75 | +<tr> | |
76 | +<td colspan="1">url_decode</td> | |
77 | +<td colspan="1">URLエンコードされた文字列をデコードします。</td> | |
78 | +</tr> | |
79 | +<tr> | |
80 | +<td colspan="1">escapeHTML</td> | |
81 | +<td colspan="1">HTMLをエスケープします。</td> | |
82 | +</tr> | |
83 | +<tr> | |
84 | +<td colspan="1">format_date</td> | |
85 | +<td colspan="1">日付をフォーマットします。</td> | |
86 | +</tr> | |
87 | +<tr> | |
88 | +<td colspan="1">trim</td> | |
89 | +<td colspan="1">文字列の前後の空白を取り除きます。</td> | |
90 | +</tr> | |
91 | +<tr> | |
92 | +<td colspan="1">delete_tag</td> | |
93 | +<td colspan="1">タグを削除して文字列のみを取得します。</td> | |
94 | +</tr> | |
95 | +<tr> | |
96 | +<td colspan="1">check_pagename</td> | |
97 | +<td colspan="1">文字列が使用可能なページ名かどうかチェックします。</td> | |
98 | +</tr> | |
99 | +<tr> | |
100 | +<td colspan="1">check_numeric</td> | |
101 | +<td colspan="1">文字列が数値かどうかチェックします。</td> | |
102 | +</tr> | |
103 | +<tr> | |
104 | +<td colspan="1">send_mail</td> | |
105 | +<td colspan="1">メールを送信します。</td> | |
106 | +</tr> | |
107 | +<tr> | |
108 | +<td colspan="1">error</td> | |
109 | +<td colspan="1">エラー画面を表示します。</td> | |
110 | +</tr> | |
111 | +<tr> | |
112 | +<td colspan="1">handyphone</td> | |
113 | +<td colspan="1">携帯電話かどうかを判断します。</td> | |
114 | +</tr> | |
115 | +<tr> | |
116 | +<td colspan="1">smartphone</td> | |
117 | +<td colspan="1">スマートフォンかどうかチェックします。</td> | |
118 | +</tr> | |
119 | +</table> | |
120 | +<h2>アクションスクリプト</h2> | |
121 | +<p>FSWikiでアクションプラグインとして実装されているプラグインは別途CGIスクリプトを作成することで対応することが出来ます。actionパラメータの代わりにそのCGIスクリプトを呼び出すようにします。CGIスクリプトからはcommon.plに定義された関数群を使用してページの取得や保存などを行うことが出来ます。</p> | |
122 | +<p>FSWikiLiteではデフォルトでedit.cgi(ページの編集)、download.cgi(添付ファイルのダウンロード)、category.cgi(カテゴリ表示)という3つのアクションスクリプトが用意されていますので、これらを参考にしてください。</p> | |
123 | +</body> | |
124 | +</html> |
@@ -0,0 +1,172 @@ | ||
1 | +<html> | |
2 | +<head> | |
3 | + <title>README</title> | |
4 | + <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP"> | |
5 | + <link rel="stylesheet" type="text/css" href="default.css"> | |
6 | +</head> | |
7 | +<body> | |
8 | +<h1>README</h1> | |
9 | +<h2>FSWikiLiteとは?</h2> | |
10 | +<p>FSWikiLiteの元になっているFreeStyleWikiはPerlによるmodulableなWikiクローンです。プラグインによって様々な機能を追加することができます。ただし、高機能な分、通常のCGIスクリプトと比較すると動作が重いという欠点がありました。</p> | |
11 | +<p>FSWikiLiteはFSWikiほど高機能ではありませんが、機能を限定することで軽快に動作します。プラグインは一部しか使用できませんが、文法はFSWikiと完全互換です。また、FSWikiと比べると構造がシンプルな分、設置も容易です。</p> | |
12 | +<p>その他にFSWikiLiteは以下のような特徴があります。</p> | |
13 | +<ul> | |
14 | +<li>tDiaryのテーマを使用可能。</li> | |
15 | +<li>サイドバーやヘッダ、フッタを表示可能。</li> | |
16 | +<li>FSWikiとは異なるシンプルなプラグイン機構を備えている。</li> | |
17 | +<li>.htaccessを使用することで編集を管理人のみに限定することが可能。</li> | |
18 | +<li>ページのカテゴライズが可能。</li> | |
19 | +<li>ファイルの添付が可能。</li> | |
20 | +<li>PDF生成、キーワードリンク、InterWikiなどは使用不可。</li> | |
21 | +</ul> | |
22 | +<h2>インストール</h2> | |
23 | +<p>lib/setup.plを編集し、各自の設定を行います。</p> | |
24 | +<ul> | |
25 | +<li>$DATA_DIR - データファイルの格納場所。</li> | |
26 | +<li>$BACKUP_DIR - バックアップファイルの格納場所。</li> | |
27 | +<li>$ATTACH_DIR - 添付ファイルの格納場所。</li> | |
28 | +<li>$THEME_URL - テーマ(CSS)の場所。</li> | |
29 | +<li>$SEND_MAIL - sendmailのパス。更新通知を受け取る場合は設定してください。</li> | |
30 | +<li>$ADMIN_MAIL- 管理者のメールアドレス。更新通知を受け取る場合は設定してください。</li> | |
31 | +<li>$WIKI_NAME - WikiNameを使用する場合は1、使用しない場合は0を指定してください。</li> | |
32 | +<li>$BR_MODE - 改行箇所でBRタグを出力したい場合は1、BRタグを出力したくない場合は0を指定してください。</li> | |
33 | +<li>$DISPLAY_IMAGE - 画像のURLをIMGタグで表示する場合は1、通常のリンクとして表示する場合は0を指定してください。</li> | |
34 | +<li>$MAIN_SCRIPT - メインスクリプトのファイル名。変更しなくてもいいです。</li> | |
35 | +<li>$EDIT_SCRIPT - 編集用スクリプトのファイル名。変更しなくてもいいです。</li> | |
36 | +<li>$DOWNLOAD_SCRIPT - 添付ファイルのダウンロード用スクリプトのファイル名。変更しなくてもいいです。</li> | |
37 | +<li>$CATEGORY_SCRIPT - カテゴリ表示用スクリプトのファイル名。変更しなくてもいいです。</li> | |
38 | +<li>$SITE_TITLE - サイト名。自由に変更してください。</li> | |
39 | +<li>$VERSION - FSWikiLiteのバージョン。変更しなくてもいいです。</li> | |
40 | +<li>$SITE_URL - FSWiki公式サイトのURL。変更しなくてもいいです。</li> | |
41 | +</ul> | |
42 | +<p>FTPなどで以下のようにファイルを配置します(デフォルトの設定の場合)。</p> | |
43 | +<pre>-+- wiki.cgi | |
44 | + | | |
45 | + +- edit.cgi | |
46 | + | | |
47 | + +- category.cgi | |
48 | + | | |
49 | + +- download.cgi | |
50 | + | | |
51 | + +- /lib (ライブラリを配置します) | |
52 | + | | | |
53 | + | +- jcode.pl | |
54 | + | | | |
55 | + | +- cgi-lib.pl | |
56 | + | | | |
57 | + | +- setup.pl | |
58 | + | | | |
59 | + | +- common.pl | |
60 | + | | | |
61 | + | +- mimew.pl | |
62 | + | | |
63 | + +- /plugin (プラグインを配置します) | |
64 | + | | | |
65 | + | +- core.pl | |
66 | + | | |
67 | + +- /data (ページデータが出力されます) | |
68 | + | | |
69 | + +- /backup (バックアップファイルが出力されます) | |
70 | + | | |
71 | + +- /attach(添付ファイルが出力されます) | |
72 | + | | |
73 | + +-/theme (テーマを配置します) | |
74 | + | | |
75 | + +- /default | |
76 | + | | |
77 | + +- default.css | |
78 | +</pre> | |
79 | +<p>wiki.cgi、edit.cgi、category.cgi、download.cgiのパーミッションをCGIとして実行可能なように設定します。また、dataディレクトリ、backupディレクトリ、attachディレクトリはCGIから書き込み可能なパーミッションに設定します。なお、ディレクトリ構成に関してはsetup.plを編集することで任意の構造に変更することができます。</p> | |
80 | +<p>テーマに関しては現在のFSWikiLiteの配布アーカイブには同梱されていません。FSWikiのディストリビューションや、tDiaryのWebサイトよりお好みのテーマを取得してください。</p> | |
81 | +<h2>編集を管理者に限定する</h2> | |
82 | +<p>.htaccessを使ってedit.cgiにアクセス制限をかけます。詳細についてはそのうち。</p> | |
83 | +<h2>使用可能なプラグイン</h2> | |
84 | +<h3>category</h3> | |
85 | +<p>ページをカテゴライズするためのプラグインです。引数にカテゴリ名を指定します。</p> | |
86 | +<pre>{{category カテゴリ名}} | |
87 | +</pre> | |
88 | +<h3>category_list</h3> | |
89 | +<p>カテゴリごとのページ一覧を表示します。</p> | |
90 | +<pre>{{category_list}} | |
91 | +</pre> | |
92 | +<p>引数として表示するカテゴリを指定することもできます。</p> | |
93 | +<pre>{{category_list カテゴリ名}} | |
94 | +</pre> | |
95 | +<h3>lastmodified</h3> | |
96 | +<p>ページの最終更新日時を表示します。</p> | |
97 | +<pre>{{lastmodified}} | |
98 | +</pre> | |
99 | +<p>引数でページ名を指定すると指定したページの最終更新日時を表示します。</p> | |
100 | +<pre>{{lastmodified ページ名}} | |
101 | +</pre> | |
102 | +<h3>outline</h3> | |
103 | +<p>ページのアウトラインを表示します。見出しがツリー形式で表示され、クリックするとその見出しにジャンプします。Headerなどに入れておくと便利です。</p> | |
104 | +<pre>{{outline}} | |
105 | +</pre> | |
106 | +<p>引数でページ名を指定すると指定したページを対象とします。</p> | |
107 | +<pre>{{outline ページ名}} | |
108 | +</pre> | |
109 | +<h3>pre</h3> | |
110 | +<p>preタグを出力するブロックプラグインです。</p> | |
111 | +<pre>{{pre | |
112 | +ここにテキストを書く | |
113 | +}} | |
114 | +</pre> | |
115 | +<p>引数に"num"を指定すると行番号付きになります。</p> | |
116 | +<pre>{{pre num | |
117 | +ここにテキストを書く | |
118 | +}} | |
119 | +</pre> | |
120 | +<h3>raw</h3> | |
121 | +<p>引数で指定した文字列をそのまま表示します。</p> | |
122 | +<pre>{{raw テキスト}} | |
123 | +</pre> | |
124 | +<h3>recent</h3> | |
125 | +<p>更新日時順にページ名の一覧を出力します。引数で表示件数を指定できます。引数に"v"を指定すると縦に表示します。表示件数を省略すると全件出力します。</p> | |
126 | +<pre>{{recent 10}} | |
127 | +{{recent 10,v}} | |
128 | +</pre> | |
129 | +<h3>recentdays</h3> | |
130 | +<p>日付ごとに更新されたページを一覧表示します。引数で表示日数を指定できます。表示日数を省略すると最新の5日分を出力します。</p> | |
131 | +<pre>{{recentdays 10}} | |
132 | +</pre> | |
133 | +<h3>ref</h3> | |
134 | +<p>添付ファイルへのリンクを出力するプラグインです。</p> | |
135 | +<pre>{{ref ファイル名}} | |
136 | +</pre> | |
137 | +<p>別のページに添付されたファイルを参照することもできます。</p> | |
138 | +<pre>{{ref ファイル名,ページ名}} | |
139 | +</pre> | |
140 | +<p>通常はアンカとしてファイル名が表示されますが、 別名として任意の文字列を表示することもできます。</p> | |
141 | +<pre>{{ref ファイル名,ページ名,別名}} | |
142 | +</pre> | |
143 | +<h3>ref_image</h3> | |
144 | +<p>添付ファイルを画像として表示するプラグインです。</p> | |
145 | +<pre>{{ref_image ファイル名}} | |
146 | +</pre> | |
147 | +<p>オプションで画像のサイズを指定することができます。 以下の例では幅650ピクセル、高さ400ピクセルで画像を表示します。 </p> | |
148 | +<pre>{{ref_image ファイル名,w650,h400}} | |
149 | +</pre> | |
150 | +<p>別のページに添付されたファイルを参照することもできます。</p> | |
151 | +<pre>{{ref_image ファイル名,ページ名}} | |
152 | +</pre> | |
153 | +<h3>ref_text</h3> | |
154 | +<p>添付ファイルを整形済テキストとして表示するプラグインです。</p> | |
155 | +<pre>{{ref_text ファイル名}} | |
156 | +</pre> | |
157 | +<p>別のページに添付されたファイルを参照することもできます。</p> | |
158 | +<pre>{{ref_text ファイル名,ページ名}} | |
159 | +</pre> | |
160 | +<h3>search</h3> | |
161 | +<p>検索フォームを表示します。</p> | |
162 | +<pre>{{search}} | |
163 | +</pre> | |
164 | +<p>引数に"v"を指定すると縦に表示します。サイドバーなどに入れておくと便利です。</p> | |
165 | +<pre>{{search v}} | |
166 | +</pre> | |
167 | +<h2>ライセンス</h2> | |
168 | +<p>FSWikiLiteはGNUL GPLライセンスに基づいて改変、再配布が可能です。</p> | |
169 | +<h2>作成者</h2> | |
170 | +<p>Copyright (C) 2002 Naoki Takezoe, FreeStyleWiki Development Team.</p> | |
171 | +</body> | |
172 | +</html> |
@@ -0,0 +1,340 @@ | ||
1 | + GNU GENERAL PUBLIC LICENSE | |
2 | + Version 2, June 1991 | |
3 | + | |
4 | + Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |
5 | + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
6 | + Everyone is permitted to copy and distribute verbatim copies | |
7 | + of this license document, but changing it is not allowed. | |
8 | + | |
9 | + Preamble | |
10 | + | |
11 | + The licenses for most software are designed to take away your | |
12 | +freedom to share and change it. By contrast, the GNU General Public | |
13 | +License is intended to guarantee your freedom to share and change free | |
14 | +software--to make sure the software is free for all its users. This | |
15 | +General Public License applies to most of the Free Software | |
16 | +Foundation's software and to any other program whose authors commit to | |
17 | +using it. (Some other Free Software Foundation software is covered by | |
18 | +the GNU Library General Public License instead.) You can apply it to | |
19 | +your programs, too. | |
20 | + | |
21 | + When we speak of free software, we are referring to freedom, not | |
22 | +price. Our General Public Licenses are designed to make sure that you | |
23 | +have the freedom to distribute copies of free software (and charge for | |
24 | +this service if you wish), that you receive source code or can get it | |
25 | +if you want it, that you can change the software or use pieces of it | |
26 | +in new free programs; and that you know you can do these things. | |
27 | + | |
28 | + To protect your rights, we need to make restrictions that forbid | |
29 | +anyone to deny you these rights or to ask you to surrender the rights. | |
30 | +These restrictions translate to certain responsibilities for you if you | |
31 | +distribute copies of the software, or if you modify it. | |
32 | + | |
33 | + For example, if you distribute copies of such a program, whether | |
34 | +gratis or for a fee, you must give the recipients all the rights that | |
35 | +you have. You must make sure that they, too, receive or can get the | |
36 | +source code. And you must show them these terms so they know their | |
37 | +rights. | |
38 | + | |
39 | + We protect your rights with two steps: (1) copyright the software, and | |
40 | +(2) offer you this license which gives you legal permission to copy, | |
41 | +distribute and/or modify the software. | |
42 | + | |
43 | + Also, for each author's protection and ours, we want to make certain | |
44 | +that everyone understands that there is no warranty for this free | |
45 | +software. If the software is modified by someone else and passed on, we | |
46 | +want its recipients to know that what they have is not the original, so | |
47 | +that any problems introduced by others will not reflect on the original | |
48 | +authors' reputations. | |
49 | + | |
50 | + Finally, any free program is threatened constantly by software | |
51 | +patents. We wish to avoid the danger that redistributors of a free | |
52 | +program will individually obtain patent licenses, in effect making the | |
53 | +program proprietary. To prevent this, we have made it clear that any | |
54 | +patent must be licensed for everyone's free use or not licensed at all. | |
55 | + | |
56 | + The precise terms and conditions for copying, distribution and | |
57 | +modification follow. | |
58 | + | |
59 | + GNU GENERAL PUBLIC LICENSE | |
60 | + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
61 | + | |
62 | + 0. This License applies to any program or other work which contains | |
63 | +a notice placed by the copyright holder saying it may be distributed | |
64 | +under the terms of this General Public License. The "Program", below, | |
65 | +refers to any such program or work, and a "work based on the Program" | |
66 | +means either the Program or any derivative work under copyright law: | |
67 | +that is to say, a work containing the Program or a portion of it, | |
68 | +either verbatim or with modifications and/or translated into another | |
69 | +language. (Hereinafter, translation is included without limitation in | |
70 | +the term "modification".) Each licensee is addressed as "you". | |
71 | + | |
72 | +Activities other than copying, distribution and modification are not | |
73 | +covered by this License; they are outside its scope. The act of | |
74 | +running the Program is not restricted, and the output from the Program | |
75 | +is covered only if its contents constitute a work based on the | |
76 | +Program (independent of having been made by running the Program). | |
77 | +Whether that is true depends on what the Program does. | |
78 | + | |
79 | + 1. You may copy and distribute verbatim copies of the Program's | |
80 | +source code as you receive it, in any medium, provided that you | |
81 | +conspicuously and appropriately publish on each copy an appropriate | |
82 | +copyright notice and disclaimer of warranty; keep intact all the | |
83 | +notices that refer to this License and to the absence of any warranty; | |
84 | +and give any other recipients of the Program a copy of this License | |
85 | +along with the Program. | |
86 | + | |
87 | +You may charge a fee for the physical act of transferring a copy, and | |
88 | +you may at your option offer warranty protection in exchange for a fee. | |
89 | + | |
90 | + 2. You may modify your copy or copies of the Program or any portion | |
91 | +of it, thus forming a work based on the Program, and copy and | |
92 | +distribute such modifications or work under the terms of Section 1 | |
93 | +above, provided that you also meet all of these conditions: | |
94 | + | |
95 | + a) You must cause the modified files to carry prominent notices | |
96 | + stating that you changed the files and the date of any change. | |
97 | + | |
98 | + b) You must cause any work that you distribute or publish, that in | |
99 | + whole or in part contains or is derived from the Program or any | |
100 | + part thereof, to be licensed as a whole at no charge to all third | |
101 | + parties under the terms of this License. | |
102 | + | |
103 | + c) If the modified program normally reads commands interactively | |
104 | + when run, you must cause it, when started running for such | |
105 | + interactive use in the most ordinary way, to print or display an | |
106 | + announcement including an appropriate copyright notice and a | |
107 | + notice that there is no warranty (or else, saying that you provide | |
108 | + a warranty) and that users may redistribute the program under | |
109 | + these conditions, and telling the user how to view a copy of this | |
110 | + License. (Exception: if the Program itself is interactive but | |
111 | + does not normally print such an announcement, your work based on | |
112 | + the Program is not required to print an announcement.) | |
113 | + | |
114 | +These requirements apply to the modified work as a whole. If | |
115 | +identifiable sections of that work are not derived from the Program, | |
116 | +and can be reasonably considered independent and separate works in | |
117 | +themselves, then this License, and its terms, do not apply to those | |
118 | +sections when you distribute them as separate works. But when you | |
119 | +distribute the same sections as part of a whole which is a work based | |
120 | +on the Program, the distribution of the whole must be on the terms of | |
121 | +this License, whose permissions for other licensees extend to the | |
122 | +entire whole, and thus to each and every part regardless of who wrote it. | |
123 | + | |
124 | +Thus, it is not the intent of this section to claim rights or contest | |
125 | +your rights to work written entirely by you; rather, the intent is to | |
126 | +exercise the right to control the distribution of derivative or | |
127 | +collective works based on the Program. | |
128 | + | |
129 | +In addition, mere aggregation of another work not based on the Program | |
130 | +with the Program (or with a work based on the Program) on a volume of | |
131 | +a storage or distribution medium does not bring the other work under | |
132 | +the scope of this License. | |
133 | + | |
134 | + 3. You may copy and distribute the Program (or a work based on it, | |
135 | +under Section 2) in object code or executable form under the terms of | |
136 | +Sections 1 and 2 above provided that you also do one of the following: | |
137 | + | |
138 | + a) Accompany it with the complete corresponding machine-readable | |
139 | + source code, which must be distributed under the terms of Sections | |
140 | + 1 and 2 above on a medium customarily used for software interchange; or, | |
141 | + | |
142 | + b) Accompany it with a written offer, valid for at least three | |
143 | + years, to give any third party, for a charge no more than your | |
144 | + cost of physically performing source distribution, a complete | |
145 | + machine-readable copy of the corresponding source code, to be | |
146 | + distributed under the terms of Sections 1 and 2 above on a medium | |
147 | + customarily used for software interchange; or, | |
148 | + | |
149 | + c) Accompany it with the information you received as to the offer | |
150 | + to distribute corresponding source code. (This alternative is | |
151 | + allowed only for noncommercial distribution and only if you | |
152 | + received the program in object code or executable form with such | |
153 | + an offer, in accord with Subsection b above.) | |
154 | + | |
155 | +The source code for a work means the preferred form of the work for | |
156 | +making modifications to it. For an executable work, complete source | |
157 | +code means all the source code for all modules it contains, plus any | |
158 | +associated interface definition files, plus the scripts used to | |
159 | +control compilation and installation of the executable. However, as a | |
160 | +special exception, the source code distributed need not include | |
161 | +anything that is normally distributed (in either source or binary | |
162 | +form) with the major components (compiler, kernel, and so on) of the | |
163 | +operating system on which the executable runs, unless that component | |
164 | +itself accompanies the executable. | |
165 | + | |
166 | +If distribution of executable or object code is made by offering | |
167 | +access to copy from a designated place, then offering equivalent | |
168 | +access to copy the source code from the same place counts as | |
169 | +distribution of the source code, even though third parties are not | |
170 | +compelled to copy the source along with the object code. | |
171 | + | |
172 | + 4. You may not copy, modify, sublicense, or distribute the Program | |
173 | +except as expressly provided under this License. Any attempt | |
174 | +otherwise to copy, modify, sublicense or distribute the Program is | |
175 | +void, and will automatically terminate your rights under this License. | |
176 | +However, parties who have received copies, or rights, from you under | |
177 | +this License will not have their licenses terminated so long as such | |
178 | +parties remain in full compliance. | |
179 | + | |
180 | + 5. You are not required to accept this License, since you have not | |
181 | +signed it. However, nothing else grants you permission to modify or | |
182 | +distribute the Program or its derivative works. These actions are | |
183 | +prohibited by law if you do not accept this License. Therefore, by | |
184 | +modifying or distributing the Program (or any work based on the | |
185 | +Program), you indicate your acceptance of this License to do so, and | |
186 | +all its terms and conditions for copying, distributing or modifying | |
187 | +the Program or works based on it. | |
188 | + | |
189 | + 6. Each time you redistribute the Program (or any work based on the | |
190 | +Program), the recipient automatically receives a license from the | |
191 | +original licensor to copy, distribute or modify the Program subject to | |
192 | +these terms and conditions. You may not impose any further | |
193 | +restrictions on the recipients' exercise of the rights granted herein. | |
194 | +You are not responsible for enforcing compliance by third parties to | |
195 | +this License. | |
196 | + | |
197 | + 7. If, as a consequence of a court judgment or allegation of patent | |
198 | +infringement or for any other reason (not limited to patent issues), | |
199 | +conditions are imposed on you (whether by court order, agreement or | |
200 | +otherwise) that contradict the conditions of this License, they do not | |
201 | +excuse you from the conditions of this License. If you cannot | |
202 | +distribute so as to satisfy simultaneously your obligations under this | |
203 | +License and any other pertinent obligations, then as a consequence you | |
204 | +may not distribute the Program at all. For example, if a patent | |
205 | +license would not permit royalty-free redistribution of the Program by | |
206 | +all those who receive copies directly or indirectly through you, then | |
207 | +the only way you could satisfy both it and this License would be to | |
208 | +refrain entirely from distribution of the Program. | |
209 | + | |
210 | +If any portion of this section is held invalid or unenforceable under | |
211 | +any particular circumstance, the balance of the section is intended to | |
212 | +apply and the section as a whole is intended to apply in other | |
213 | +circumstances. | |
214 | + | |
215 | +It is not the purpose of this section to induce you to infringe any | |
216 | +patents or other property right claims or to contest validity of any | |
217 | +such claims; this section has the sole purpose of protecting the | |
218 | +integrity of the free software distribution system, which is | |
219 | +implemented by public license practices. Many people have made | |
220 | +generous contributions to the wide range of software distributed | |
221 | +through that system in reliance on consistent application of that | |
222 | +system; it is up to the author/donor to decide if he or she is willing | |
223 | +to distribute software through any other system and a licensee cannot | |
224 | +impose that choice. | |
225 | + | |
226 | +This section is intended to make thoroughly clear what is believed to | |
227 | +be a consequence of the rest of this License. | |
228 | + | |
229 | + 8. If the distribution and/or use of the Program is restricted in | |
230 | +certain countries either by patents or by copyrighted interfaces, the | |
231 | +original copyright holder who places the Program under this License | |
232 | +may add an explicit geographical distribution limitation excluding | |
233 | +those countries, so that distribution is permitted only in or among | |
234 | +countries not thus excluded. In such case, this License incorporates | |
235 | +the limitation as if written in the body of this License. | |
236 | + | |
237 | + 9. The Free Software Foundation may publish revised and/or new versions | |
238 | +of the General Public License from time to time. Such new versions will | |
239 | +be similar in spirit to the present version, but may differ in detail to | |
240 | +address new problems or concerns. | |
241 | + | |
242 | +Each version is given a distinguishing version number. If the Program | |
243 | +specifies a version number of this License which applies to it and "any | |
244 | +later version", you have the option of following the terms and conditions | |
245 | +either of that version or of any later version published by the Free | |
246 | +Software Foundation. If the Program does not specify a version number of | |
247 | +this License, you may choose any version ever published by the Free Software | |
248 | +Foundation. | |
249 | + | |
250 | + 10. If you wish to incorporate parts of the Program into other free | |
251 | +programs whose distribution conditions are different, write to the author | |
252 | +to ask for permission. For software which is copyrighted by the Free | |
253 | +Software Foundation, write to the Free Software Foundation; we sometimes | |
254 | +make exceptions for this. Our decision will be guided by the two goals | |
255 | +of preserving the free status of all derivatives of our free software and | |
256 | +of promoting the sharing and reuse of software generally. | |
257 | + | |
258 | + NO WARRANTY | |
259 | + | |
260 | + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
261 | +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
262 | +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
263 | +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |
264 | +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
265 | +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |
266 | +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |
267 | +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |
268 | +REPAIR OR CORRECTION. | |
269 | + | |
270 | + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
271 | +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
272 | +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |
273 | +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |
274 | +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |
275 | +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |
276 | +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |
277 | +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |
278 | +POSSIBILITY OF SUCH DAMAGES. | |
279 | + | |
280 | + END OF TERMS AND CONDITIONS | |
281 | + | |
282 | + How to Apply These Terms to Your New Programs | |
283 | + | |
284 | + If you develop a new program, and you want it to be of the greatest | |
285 | +possible use to the public, the best way to achieve this is to make it | |
286 | +free software which everyone can redistribute and change under these terms. | |
287 | + | |
288 | + To do so, attach the following notices to the program. It is safest | |
289 | +to attach them to the start of each source file to most effectively | |
290 | +convey the exclusion of warranty; and each file should have at least | |
291 | +the "copyright" line and a pointer to where the full notice is found. | |
292 | + | |
293 | + <one line to give the program's name and a brief idea of what it does.> | |
294 | + Copyright (C) <year> <name of author> | |
295 | + | |
296 | + This program is free software; you can redistribute it and/or modify | |
297 | + it under the terms of the GNU General Public License as published by | |
298 | + the Free Software Foundation; either version 2 of the License, or | |
299 | + (at your option) any later version. | |
300 | + | |
301 | + This program is distributed in the hope that it will be useful, | |
302 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
303 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
304 | + GNU General Public License for more details. | |
305 | + | |
306 | + You should have received a copy of the GNU General Public License | |
307 | + along with this program; if not, write to the Free Software | |
308 | + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
309 | + | |
310 | + | |
311 | +Also add information on how to contact you by electronic and paper mail. | |
312 | + | |
313 | +If the program is interactive, make it output a short notice like this | |
314 | +when it starts in an interactive mode: | |
315 | + | |
316 | + Gnomovision version 69, Copyright (C) year name of author | |
317 | + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |
318 | + This is free software, and you are welcome to redistribute it | |
319 | + under certain conditions; type `show c' for details. | |
320 | + | |
321 | +The hypothetical commands `show w' and `show c' should show the appropriate | |
322 | +parts of the General Public License. Of course, the commands you use may | |
323 | +be called something other than `show w' and `show c'; they could even be | |
324 | +mouse-clicks or menu items--whatever suits your program. | |
325 | + | |
326 | +You should also get your employer (if you work as a programmer) or your | |
327 | +school, if any, to sign a "copyright disclaimer" for the program, if | |
328 | +necessary. Here is a sample; alter the names: | |
329 | + | |
330 | + Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |
331 | + `Gnomovision' (which makes passes at compilers) written by James Hacker. | |
332 | + | |
333 | + <signature of Ty Coon>, 1 April 1989 | |
334 | + Ty Coon, President of Vice | |
335 | + | |
336 | +This General Public License does not permit incorporating your program into | |
337 | +proprietary programs. If your program is a subroutine library, you may | |
338 | +consider it more useful to permit linking proprietary applications with the | |
339 | +library. If this is what you want to do, use the GNU Library General | |
340 | +Public License instead of this License. |
@@ -0,0 +1,1589 @@ | ||
1 | +################################################################################ | |
2 | +# | |
3 | +# FSWikiLite 共通関数ファイル | |
4 | +# | |
5 | +################################################################################ | |
6 | +require "./lib/cgi-lib.pl"; | |
7 | +require "./lib/jcode.pl"; | |
8 | +require "./lib/mimew.pl"; | |
9 | +require "./lib/setup.pl"; | |
10 | +#------------------------------------------------------------------------------- | |
11 | +# ヘッダを表示 | |
12 | +#------------------------------------------------------------------------------- | |
13 | +sub print_header { | |
14 | + my $title = shift; | |
15 | + my $show = shift; | |
16 | + | |
17 | + print "Content-Type: text/html;charset=EUC-JP\n"; | |
18 | + print "Pragma: no-cache\n"; | |
19 | + print "Cache-Control: no-cache\n\n"; | |
20 | + print "<html>\n"; | |
21 | + print "<head>\n"; | |
22 | + print "<title>".&Util::escapeHTML($title)." - $SITE_TITLE</title>\n"; | |
23 | + print "<link rel=\"stylesheet\" type=\"text/css\" href=\"$THEME_URL\">\n"; | |
24 | + print "</head>\n"; | |
25 | + print "<body>\n"; | |
26 | + | |
27 | + print "<div class=\"adminmenu\">\n"; | |
28 | + print " <span class=\"adminmenu\">\n"; | |
29 | + print " <a href=\"".&Wiki::create_url({p=>"FrontPage"})."\">FrontPage</a>\n"; | |
30 | + print " <a href=\"".&Wiki::create_url({a=>"new"})."\">新規</a>\n"; | |
31 | + if($show==1){ | |
32 | + print " <a href=\"".&Wiki::create_url({a=>"edit",p=>$in{"p"}})."\">編集</a>\n"; | |
33 | + } | |
34 | + print " <a href=\"".&Wiki::create_url({a=>"search"})."\">検索</a>\n"; | |
35 | + print " <a href=\"".&Wiki::create_url({a=>"list"})."\">一覧</a>\n"; | |
36 | + print " <a href=\"".&Wiki::create_url({p=>"Help"})."\">ヘルプ</a>\n"; | |
37 | + print " </span>\n"; | |
38 | + print "</div>\n"; | |
39 | + | |
40 | + print "<h1>".&Util::escapeHTML($title)."</h1>\n"; | |
41 | + if(&Wiki::page_exists("Menu")){ | |
42 | + print "<div class=\"main\">\n"; | |
43 | + } | |
44 | +} | |
45 | + | |
46 | +#------------------------------------------------------------------------------- | |
47 | +# フッタを表示 | |
48 | +#------------------------------------------------------------------------------- | |
49 | +sub print_footer { | |
50 | + if(&Wiki::page_exists("Menu")){ | |
51 | + print "</div>\n"; | |
52 | + print "<div class=\"sidebar\">\n"; | |
53 | + print &Wiki::process_wiki(&Wiki::get_page("Menu")); | |
54 | + print "</div>\n"; | |
55 | + } | |
56 | + print "<div class=\"footer\">Powered by <a href=\"".$main::SITE_URL."\">FreeStyleWikiLite ".$main::VERSION."</a></div>\n"; | |
57 | + print "</body></html>\n"; | |
58 | +} | |
59 | + | |
60 | +#------------------------------------------------------------------------------- | |
61 | +# 旧Ver(0.0.11)互換性維持 | |
62 | +# 次期バージョンで削除されます。 | |
63 | +#------------------------------------------------------------------------------- | |
64 | +sub redirect { return &Wiki::redirect($@); } | |
65 | +sub redirectURL { return &Wiki::redirectURL($@); } | |
66 | + | |
67 | +package Wiki; | |
68 | +sub exists_page { return &page_exists(shift); } | |
69 | +sub send_mail { return &Util::send_mail($@); } | |
70 | + | |
71 | +package HTMLParser; | |
72 | + | |
73 | +package Util; | |
74 | +sub parse_plugin { return &Wiki::parse_inline_plugin($@); } | |
75 | + | |
76 | +############################################################################### | |
77 | +# | |
78 | +# Wiki関連の関数を提供するパッケージ | |
79 | +# | |
80 | +############################################################################### | |
81 | +package Wiki; | |
82 | + | |
83 | +local @current_parser = []; | |
84 | + | |
85 | +#============================================================================== | |
86 | +# プラグインの情報を取得します | |
87 | +#============================================================================== | |
88 | +sub get_plugin_info { | |
89 | + my $name = shift; | |
90 | + return defined($main::P_PLUGIN->{$name}) ? {FUNCTION=>$main::P_PLUGIN->{$name}, TYPE=>'paragraph'} : | |
91 | + defined($main::I_PLUGIN->{$name}) ? {FUNCTION=>$main::I_PLUGIN->{$name}, TYPE=>'inline' } : | |
92 | + defined($main::B_PLUGIN->{$name}) ? {FUNCTION=>$main::B_PLUGIN->{$name}, TYPE=>'block' } : | |
93 | + {}; | |
94 | +} | |
95 | + | |
96 | +#============================================================================== | |
97 | +# Wikiソースを渡してHTMLを取得します | |
98 | +#============================================================================== | |
99 | +sub process_wiki { | |
100 | + my $source = shift; | |
101 | + my $mainflg = shift; | |
102 | + my $parser = HTMLParser->new($mainflg); | |
103 | + | |
104 | + # 裏技用(プラグイン内部からパーサを使う場合) | |
105 | + push(@current_parser, $parser); | |
106 | + | |
107 | + $parser->parse($source); | |
108 | + | |
109 | + # パーサの参照を解放 | |
110 | + pop(@current_parser); | |
111 | + | |
112 | + return $parser->{html}; | |
113 | +} | |
114 | + | |
115 | +#============================================================================== | |
116 | +# パース中の場合、現在有効なHTMLParserのインスタンスを返却します。 | |
117 | +# パース中の内容をプラグインから変更したい場合に使用します。 | |
118 | +#============================================================================== | |
119 | +sub get_current_parser { | |
120 | + return $current_parser[$#current_parser]; | |
121 | +} | |
122 | + | |
123 | +#=============================================================================== | |
124 | +# インラインプラグインをパースしてコマンドと引数に分割 | |
125 | +#=============================================================================== | |
126 | +sub parse_inline_plugin { | |
127 | + my $text = shift; | |
128 | + my ($cmd, @args_tmp) = split(/ /,$text); | |
129 | + my $args_txt = &Util::trim(join(" ",@args_tmp)); | |
130 | + if($cmd =~ s/\}\}(.*?)$//){ | |
131 | + return { command=>$cmd, args=>[], post=>"$1 $args_txt"}; | |
132 | + } | |
133 | + | |
134 | + my @ret_args; | |
135 | + my $tmp = ""; | |
136 | + my $escape = 0; | |
137 | + my $quote = 0; | |
138 | + my $i = 0; | |
139 | + | |
140 | + for($i = 0; $i<length($args_txt); $i++){ | |
141 | + my $c = substr($args_txt,$i,1); | |
142 | + if($quote!=1 && $c eq ","){ | |
143 | + if($quote==3){ | |
144 | + $tmp .= '}'; | |
145 | + } | |
146 | + push(@ret_args,$tmp); | |
147 | + $tmp = ""; | |
148 | + $quote = 0; | |
149 | + } elsif($quote==1 && $c eq "\\"){ | |
150 | + if($escape==0){ | |
151 | + $escape = 1; | |
152 | + } else { | |
153 | + $tmp .= $c; | |
154 | + $escape = 0; | |
155 | + } | |
156 | + } elsif($quote==0 && $c eq '"'){ | |
157 | + if($tmp eq ""){ | |
158 | + $quote = 1; | |
159 | + } else { | |
160 | + $tmp .= $c; | |
161 | + } | |
162 | + } elsif($quote==1 && $c eq '"'){ | |
163 | + if($escape==1){ | |
164 | + $tmp .= $c; | |
165 | + $escape = 0; | |
166 | + } else { | |
167 | + $quote = 2; | |
168 | + } | |
169 | + } elsif(($quote==0 || $quote==2) && $c eq '}'){ | |
170 | + $quote = 3; | |
171 | + } elsif($quote==3){ | |
172 | + if($c eq '}'){ | |
173 | + last; | |
174 | + } else { | |
175 | + $tmp .= '}'.$c; | |
176 | + $quote = 0; | |
177 | + } | |
178 | + } elsif($quote==2){ | |
179 | + return {error=>"インラインプラグインの構文が不正です。"}; | |
180 | + } else { | |
181 | + $tmp .= $c; | |
182 | + $escape = 0; | |
183 | + } | |
184 | + } | |
185 | + | |
186 | + if($quote!=3){ | |
187 | + my $info = &Wiki::get_plugin_info($cmd); | |
188 | + return undef if (defined($info->{TYPE}) && $info->{TYPE} ne 'block'); | |
189 | + } | |
190 | + | |
191 | + if($tmp ne ""){ | |
192 | + push(@ret_args,$tmp); | |
193 | + } | |
194 | + | |
195 | + return { command=>$cmd, args=>\@ret_args, | |
196 | + post=>substr($args_txt, $i + 1, length($args_txt) - $i)}; | |
197 | +} | |
198 | + | |
199 | +#============================================================================== | |
200 | +# ページ表示のURLを生成 | |
201 | +#============================================================================== | |
202 | +sub create_page_url { | |
203 | + my $page = shift; | |
204 | + return create_url({p=>$page}); | |
205 | +} | |
206 | + | |
207 | +#============================================================================== | |
208 | +# 任意のURLを生成 | |
209 | +#============================================================================== | |
210 | +sub create_url { | |
211 | + my $params = shift; | |
212 | + my $script = shift; | |
213 | + my $url = ''; | |
214 | + my $query = ''; | |
215 | + my $action = ''; | |
216 | + foreach my $key (keys(%$params)){ | |
217 | + my $val = $params->{$key}; | |
218 | + if ($key eq 'a') { | |
219 | + $action = $val; | |
220 | + } | |
221 | + if($query ne ''){ | |
222 | + $query .= '&'; | |
223 | + } | |
224 | + $query .= Util::url_encode($key)."=".Util::url_encode($val); | |
225 | + } | |
226 | + if(!defined($script)){ | |
227 | + if ($action =~ /^(edit|new|delconf)$/){ | |
228 | + $script = $main::EDIT_SCRIPT; | |
229 | + }else{ | |
230 | + $script = $main::MAIN_SCRIPT; | |
231 | + } | |
232 | + } | |
233 | + $url = $script; | |
234 | + if($query ne ''){ | |
235 | + $url .= '?'.$query; | |
236 | + } | |
237 | + return $url; | |
238 | +} | |
239 | + | |
240 | +#============================================================================== | |
241 | +# ページの一覧を取得 | |
242 | +#============================================================================== | |
243 | +sub get_page_list { | |
244 | + opendir(DIR, $main::DATA_DIR); | |
245 | + my ($fileentry, @files); | |
246 | + while($fileentry = readdir(DIR)){ | |
247 | + my $type = substr($fileentry,rindex($fileentry,".")); | |
248 | + if($type eq ".wiki"){ | |
249 | + push(@files, "$main::DATA_DIR/$fileentry"); | |
250 | + } | |
251 | + } | |
252 | + closedir(DIR); | |
253 | + | |
254 | + my @pages; | |
255 | + foreach my $entry (@files){ | |
256 | + my @stat = stat($entry); | |
257 | + my $time = $stat[9]; | |
258 | + | |
259 | + $entry = substr($entry,length($main::DATA_DIR)+1); | |
260 | + $entry =~ /(.+?)\.wiki/; | |
261 | + my $page = &Util::url_decode($1); | |
262 | + push(@pages,{NAME=>$page,TIME=>$time}); | |
263 | + } | |
264 | + | |
265 | + @pages = sort { $b->{TIME}<=>$a->{TIME} } @pages; | |
266 | + return @pages; | |
267 | +} | |
268 | + | |
269 | +#============================================================================== | |
270 | +# ページの更新日時を取得 | |
271 | +#============================================================================== | |
272 | +sub get_last_modified { | |
273 | + my $page = shift; | |
274 | + if(&page_exists($page)){ | |
275 | + my $file = sprintf("%s/%s.wiki",$main::DATA_DIR,&Util::url_encode($page)); | |
276 | + my @stat = stat($file); | |
277 | + return $stat[9]; | |
278 | + } else { | |
279 | + return undef; | |
280 | + } | |
281 | +} | |
282 | + | |
283 | +#============================================================================== | |
284 | +# ページを取得 | |
285 | +#============================================================================== | |
286 | +sub get_page { | |
287 | + my $page = &Util::url_encode(shift); | |
288 | + | |
289 | + open(DATA,"$main::DATA_DIR/$page.wiki") or &Util::error("$main::DATA_DIR/$page.wikiのオープンに失敗しました。"); | |
290 | + my $content = ""; | |
291 | + while(<DATA>){ | |
292 | + $content .= $_; | |
293 | + } | |
294 | + close(DATA); | |
295 | + | |
296 | + return $content; | |
297 | +} | |
298 | +#============================================================================== | |
299 | +# ページを保存 | |
300 | +#============================================================================== | |
301 | +sub save_page { | |
302 | + my $page = shift; | |
303 | + my $source = shift; | |
304 | + | |
305 | + $page = &Util::trim($page); | |
306 | + $source =~ s/\r\n/\n/g; | |
307 | + $source =~ s/\r/\n/g; | |
308 | + | |
309 | + my $enc_page = &Util::url_encode($page); | |
310 | + my $action = 'MODIFY'; | |
311 | + unless(-e "$main::DATA_DIR/$enc_page.wiki"){ | |
312 | + $action = 'CREATE'; | |
313 | + } | |
314 | + | |
315 | + # バックアップファイルを作成 | |
316 | + if(-e "$main::DATA_DIR/$enc_page.wiki"){ | |
317 | + open(BACKUP,">$main::BACKUP_DIR/$enc_page.bak") or &Util::error("$main::BACKUP_DIR/$enc_page.bakのオープンに失敗しました。"); | |
318 | + open(DATA ,"$main::DATA_DIR/$enc_page.wiki") or &Util::error("$main::DATA_DIR/$enc_page.wikiのオープンに失敗しました。"); | |
319 | + while(<DATA>){ | |
320 | + print BACKUP $_; | |
321 | + } | |
322 | + close(DATA); | |
323 | + close(BACKUP); | |
324 | + } | |
325 | + | |
326 | + # 入力内容を保存 | |
327 | + open(DATA,">$main::DATA_DIR/$enc_page.wiki") or &Util::error("$main::DATA_DIR/$enc_page.wikiのオープンに失敗しました。"); | |
328 | + print DATA $source; | |
329 | + close(DATA); | |
330 | + | |
331 | + &Util::send_mail($action,$page); | |
332 | +} | |
333 | + | |
334 | +#============================================================================== | |
335 | +# ページが存在するかどうか | |
336 | +#============================================================================== | |
337 | +sub page_exists { | |
338 | + my $page = &Util::url_encode(shift); | |
339 | + if(-e "$main::DATA_DIR/$page.wiki"){ | |
340 | + return 1; | |
341 | + } else { | |
342 | + return 0; | |
343 | + } | |
344 | +} | |
345 | + | |
346 | +#============================================================================== | |
347 | +# 引数で渡したページに遷移 | |
348 | +#============================================================================== | |
349 | +sub redirect { | |
350 | + my $page = shift; | |
351 | + my $url = &Wiki::create_url({p=>$page}); | |
352 | + &redirectURL($url); | |
353 | +} | |
354 | + | |
355 | +#============================================================================== | |
356 | +# 引数で渡したURLに遷移 | |
357 | +#============================================================================== | |
358 | +sub redirectURL { | |
359 | + my $url = shift; | |
360 | + | |
361 | + print "Content-Type: text/html;charset=EUC-JP\n"; | |
362 | + print "Pragma: no-cache\n"; | |
363 | + print "Cache-Control: no-cache\n\n"; | |
364 | + print "<html>\n"; | |
365 | + print " <head>\n"; | |
366 | + print " <title>moving...</title>\n"; | |
367 | + print " <meta http-equiv=\"Refresh\" content=\"0;URL=$url\">\n"; | |
368 | + print " </head>\n"; | |
369 | + print " <body>\n"; | |
370 | + print " Wait or <a href=\"$url\">Click Here!!</a>\n"; | |
371 | + print " </body>\n"; | |
372 | + print "</html>\n"; | |
373 | + | |
374 | + exit; | |
375 | +} | |
376 | + | |
377 | +#============================================================================== | |
378 | +# ページを削除 | |
379 | +#============================================================================== | |
380 | +sub remove_page { | |
381 | + my $page = shift; | |
382 | + my $enc_page = &Util::url_encode($page); | |
383 | + unlink("$main::DATA_DIR/$enc_page.wiki") or &Util::error("$main::DATA_DIR/$enc_page.wikiの削除に失敗しました。"); | |
384 | + | |
385 | + &Util::send_mail('DELETE',$page); | |
386 | +} | |
387 | + | |
388 | +############################################################################### | |
389 | +# | |
390 | +# HTMLパーサ | |
391 | +# | |
392 | +############################################################################### | |
393 | +package HTMLParser; | |
394 | +#============================================================================== | |
395 | +# コンストラクタ | |
396 | +#============================================================================== | |
397 | +sub new { | |
398 | + my $class = shift; | |
399 | + my $mainflg = shift; | |
400 | + my $self = {}; | |
401 | + | |
402 | + if(!defined($mainflg) || $mainflg eq ""){ $mainflg = 0; } | |
403 | + | |
404 | + $self->{dl_flag} = 0; | |
405 | + $self->{dt} = ""; | |
406 | + $self->{dd} = ""; | |
407 | + | |
408 | + $self->{html} = ""; | |
409 | + $self->{pre} = ""; | |
410 | + $self->{quote} = ""; | |
411 | + $self->{table} = 0; | |
412 | + $self->{level} = 0; | |
413 | + $self->{list} = 0; | |
414 | + $self->{para} = 0; | |
415 | + $self->{p_cnt} = 0; | |
416 | + $self->{main} = $mainflg; | |
417 | + return bless $self,$class; | |
418 | +} | |
419 | + | |
420 | +#=============================================================================== | |
421 | +# パース | |
422 | +#=============================================================================== | |
423 | +sub parse { | |
424 | + my $self = shift; | |
425 | + my $source = shift; | |
426 | + | |
427 | + $self->start_parse; | |
428 | + $source =~ s/\r//g; | |
429 | + | |
430 | + my @lines = split(/\n/,$source); | |
431 | + | |
432 | + foreach my $line (@lines){ | |
433 | + chomp $line; | |
434 | + | |
435 | + # 複数行の説明 | |
436 | + $self->multi_explanation($line); | |
437 | + | |
438 | + my $word1 = substr($line,0,1); | |
439 | + my $word2 = substr($line,0,2); | |
440 | + my $word3 = substr($line,0,3); | |
441 | + | |
442 | + # 空行 | |
443 | + if($line eq "" && !$self->{block}){ | |
444 | + $self->l_paragraph(); | |
445 | + next; | |
446 | + } | |
447 | + | |
448 | + # ブロック書式のエスケープ | |
449 | + if($word2 eq "\\\\" || $word1 eq "\\"){ | |
450 | + my @obj = $self->parse_line(substr($line, 1)); | |
451 | + $self->l_text(\@obj); | |
452 | + next; | |
453 | + } | |
454 | + | |
455 | + # パラグラフプラグイン | |
456 | + if($line =~ /^\{\{(.+\}\})$/){ | |
457 | + if(!$self->{block}){ | |
458 | + my $plugin = &Wiki::parse_inline_plugin($1); | |
459 | + my $info = &Wiki::get_plugin_info($plugin->{command}); | |
460 | + if($info->{TYPE} eq "paragraph"){ | |
461 | + $self->l_plugin($plugin); | |
462 | + } else { | |
463 | + my @obj = $self->parse_line($line); | |
464 | + $self->l_text(\@obj); | |
465 | + } | |
466 | + next; | |
467 | + } | |
468 | + } elsif($line =~ /^\{\{(.+)$/){ | |
469 | + if ($self->{block}) { | |
470 | + my $plugin = &Wiki::parse_inline_plugin($1); | |
471 | + my $info = &Wiki::get_plugin_info($plugin->{command}); | |
472 | + $self->{block}->{level}++ if($info->{TYPE} eq "block"); | |
473 | + $self->{block}->{args}->[0] .= $line."\n"; | |
474 | + next; | |
475 | + } | |
476 | + my $plugin = &Wiki::parse_inline_plugin($1); | |
477 | + my $info = &Wiki::get_plugin_info($plugin->{command}); | |
478 | + if($info->{TYPE} eq "block"){ | |
479 | + unshift(@{$plugin->{args}}, ""); | |
480 | + $self->{block} = $plugin; | |
481 | + $self->{block}->{level} = 0; | |
482 | + } else { | |
483 | + my @obj = $self->parse_line($line); | |
484 | + $self->l_text(\@obj); | |
485 | + } | |
486 | + next; | |
487 | + } | |
488 | + if($self->{block}){ | |
489 | + if($line eq "}}"){ | |
490 | + if ($self->{block}->{level} > 0) { | |
491 | + $self->{block}->{level}--; | |
492 | + $self->{block}->{args}->[0] .= $line."\n"; | |
493 | + next; | |
494 | + } | |
495 | + my $plugin = $self->{block}; | |
496 | + delete($self->{block}); | |
497 | + $self->l_plugin($plugin); | |
498 | + } else { | |
499 | + $self->{block}->{args}->[0] .= $line."\n"; | |
500 | + } | |
501 | + next; | |
502 | + } | |
503 | + | |
504 | + # PRE | |
505 | + if($word1 eq " " || $word1 eq "\t"){ | |
506 | + $self->l_verbatim($line); | |
507 | + | |
508 | + # 見出し | |
509 | + } elsif($word3 eq "!!!"){ | |
510 | + my @obj = $self->parse_line(substr($line,3)); | |
511 | + $self->l_headline(1,\@obj); | |
512 | + | |
513 | + } elsif($word2 eq "!!"){ | |
514 | + my @obj = $self->parse_line(substr($line,2)); | |
515 | + $self->l_headline(2,\@obj); | |
516 | + | |
517 | + } elsif($word1 eq "!"){ | |
518 | + my @obj = $self->parse_line(substr($line,1)); | |
519 | + $self->l_headline(3,\@obj); | |
520 | + | |
521 | + # 項目 | |
522 | + } elsif($word3 eq "***"){ | |
523 | + my @obj = $self->parse_line(substr($line,3)); | |
524 | + $self->l_list(3,\@obj); | |
525 | + | |
526 | + } elsif($word2 eq "**"){ | |
527 | + my @obj = $self->parse_line(substr($line,2)); | |
528 | + $self->l_list(2,\@obj); | |
529 | + | |
530 | + } elsif($word1 eq "*"){ | |
531 | + my @obj = $self->parse_line(substr($line,1)); | |
532 | + $self->l_list(1,\@obj); | |
533 | + | |
534 | + # 番号付き項目 | |
535 | + } elsif($word3 eq "+++"){ | |
536 | + my @obj = $self->parse_line(substr($line,3)); | |
537 | + $self->l_numlist(3,\@obj); | |
538 | + | |
539 | + } elsif($word2 eq "++"){ | |
540 | + my @obj = $self->parse_line(substr($line,2)); | |
541 | + $self->l_numlist(2,\@obj); | |
542 | + | |
543 | + } elsif($word1 eq "+"){ | |
544 | + my @obj = $self->parse_line(substr($line,1)); | |
545 | + $self->l_numlist(1,\@obj); | |
546 | + | |
547 | + # 水平線 | |
548 | + } elsif($line eq "----"){ | |
549 | + $self->l_line(); | |
550 | + | |
551 | + # 引用 | |
552 | + } elsif($word2 eq '""'){ | |
553 | + my @obj = $self->parse_line(substr($line,2)); | |
554 | + $self->l_quotation(\@obj); | |
555 | + | |
556 | + # 説明 | |
557 | + } elsif(index($line,":")==0 && index($line,":",1)!=-1){ | |
558 | + if(index($line,":::")==0){ | |
559 | + $self->{dd} .= substr($line,3); | |
560 | + next; | |
561 | + } | |
562 | + if($self->{dt} ne "" || $self->{dd} ne ""){ | |
563 | + $self->multi_explanation; | |
564 | + } | |
565 | + if(index($line,"::")==0){ | |
566 | + $self->{dt} = substr($line,2); | |
567 | + $self->{dl_flag} = 1; | |
568 | + next; | |
569 | + } | |
570 | + my $dt = substr($line,1,index($line,":",1)-1); | |
571 | + my $dd = substr($line,index($line,":",1)+1); | |
572 | + my @obj1 = $self->parse_line($dt); | |
573 | + my @obj2 = $self->parse_line($dd); | |
574 | + $self->l_explanation(\@obj1,\@obj2); | |
575 | + | |
576 | + # テーブル | |
577 | + } elsif($word1 eq ","){ | |
578 | + if($line =~ /,$/){ | |
579 | + $line .= " "; | |
580 | + } | |
581 | + my @spl = map {/^"(.*)"$/ ? scalar($_ = $1, s/\"\"/\"/g, $_) : $_} | |
582 | + ($line =~ /,\s*(\"[^\"]*(?:\"\"[^\"]*)*\"|[^,]*)/g); | |
583 | + my @array; | |
584 | + foreach my $value (@spl){ | |
585 | + my @cell = $self->parse_line($value); | |
586 | + push @array,\@cell; | |
587 | + } | |
588 | + $self->l_table(\@array); | |
589 | + | |
590 | + # コメント | |
591 | + } elsif($word2 eq "//"){ | |
592 | + | |
593 | + # 何もない行 | |
594 | + } else { | |
595 | + my @obj = $self->parse_line($line); | |
596 | + $self->l_text(\@obj); | |
597 | + } | |
598 | + } | |
599 | + | |
600 | + # 複数行の説明 | |
601 | + $self->multi_explanation; | |
602 | + | |
603 | + # パース中のブロックプラグインがあった場合、とりあえず評価しておく? | |
604 | + if($self->{block}){ | |
605 | + my $plugin = $self->{block}; | |
606 | + delete($self->{block}); | |
607 | + $self->l_plugin($plugin); | |
608 | + } | |
609 | + | |
610 | + $self->end_parse; | |
611 | +} | |
612 | + | |
613 | +#=============================================================================== | |
614 | +# 複数行の説明 | |
615 | +#=============================================================================== | |
616 | +sub multi_explanation { | |
617 | + my $self = shift; | |
618 | + my $line = shift; | |
619 | + if($self->{dl_flag}==1 && (index($line,":")!=0 || !defined($line))){ | |
620 | + my @obj1 = $self->parse_line($self->{dt}); | |
621 | + my @obj2 = $self->parse_line($self->{dd}); | |
622 | + $self->l_explanation(\@obj1,\@obj2); | |
623 | + $self->{dl_flag} = 0; | |
624 | + $self->{dt} = ""; | |
625 | + $self->{dd} = ""; | |
626 | + } | |
627 | +} | |
628 | + | |
629 | +#=============================================================================== | |
630 | +# 1行分をパース | |
631 | +#=============================================================================== | |
632 | +sub parse_line { | |
633 | + my ($self, $source) = @_; | |
634 | + | |
635 | + return () if (not defined $source); | |
636 | + | |
637 | + my @array = (); | |
638 | + my $pre = q{}; | |
639 | + my @parsed = (); | |
640 | + | |
641 | + # $source が空になるまで繰り返す。 | |
642 | + SOURCE: | |
643 | + while ($source ne q{}) { | |
644 | + | |
645 | + # どのインライン Wiki 書式の先頭にも match しない場合 | |
646 | + if (!($source =~ /^(.*?)((?:\{\{|\[\[?|https?:|mailto:|f(?:tp:|ile:)|'''?|==|__|<<).*)$/)) { | |
647 | + # WikiName検索・置換処理のみ実施して終了する | |
648 | + push @array, $self->_parse_line_wikiname($pre . $source); | |
649 | + return @array; | |
650 | + } | |
651 | + | |
652 | + $pre .= $1; # match しなかった先頭部分は溜めておいて後で処理する | |
653 | + $source = $2; # match 部分は後続処理にて詳細チェックを行う | |
654 | + @parsed = (); | |
655 | + | |
656 | + # プラグイン | |
657 | + if ($source =~ /^\{\{/) { | |
658 | + $source = $'; | |
659 | + my $plugin = &Wiki::parse_inline_plugin($source); | |
660 | + unless($plugin){ | |
661 | + push @parsed, '{{'; | |
662 | + push @parsed, $self->parse_line($source); | |
663 | + } else { | |
664 | + my $info = &Wiki::get_plugin_info($plugin->{command}); | |
665 | + if($info->{TYPE} eq "inline"){ | |
666 | + push @parsed, $self->plugin($plugin); | |
667 | + } else { | |
668 | + push @parsed, $self->parse_line("<<".$plugin->{command}."プラグインは存在しません。>>"); | |
669 | + } | |
670 | + if ($source ne "") { | |
671 | + $source = $plugin->{post}; | |
672 | + } | |
673 | + } | |
674 | + } | |
675 | + | |
676 | + # ページ別名リンク | |
677 | + elsif ($source =~ /^\[\[([^\[]+?)\|([^\|\[]+?)\]\]/) { | |
678 | + my $label = $1; | |
679 | + my $page = $2; | |
680 | + $source = $'; | |
681 | + push @parsed, $self->wiki_anchor($page, $label); | |
682 | + } | |
683 | + | |
684 | + # URL別名リンク | |
685 | + elsif ($source | |
686 | + =~ /^\[([^\[]+?)\|((?:http|https|ftp|mailto):[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!&=:;\*#\@'\$]*)\]/ | |
687 | + || $source =~ /^\[([^\[]+?)\|(file:[^\[\]]*)\]/ | |
688 | + || $source | |
689 | + =~ /^\[([^\[]+?)\|((?:\/|\.\/|\.\.\/)+[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!&=:;\*#\@'\$]*)\]/ | |
690 | + ) | |
691 | + { | |
692 | + my $label = $1; | |
693 | + my $url = $2; | |
694 | + $source = $'; | |
695 | + if ( index($url, q{"}) >= 0 | |
696 | + || index($url, '><') >= 0 | |
697 | + || index($url, 'javascript:') >= 0) | |
698 | + { | |
699 | + push @parsed, $self->parse_line('<<不正なリンクです。>>'); | |
700 | + } | |
701 | + else { | |
702 | + push @parsed, $self->url_anchor($url, $label); | |
703 | + } | |
704 | + } | |
705 | + | |
706 | + # URLリンク | |
707 | + elsif ($source | |
708 | + =~ /^(?:https?|ftp|mailto):[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!&=:;\*#\@'\$]*/ | |
709 | + || $source =~ /^file:[^\[\]]*/) | |
710 | + { | |
711 | + my $url = $&; | |
712 | + $source = $'; | |
713 | + if ( index($url, q{"}) >= 0 | |
714 | + || index($url, '><') >= 0 | |
715 | + || index($url, 'javascript:') >= 0) | |
716 | + { | |
717 | + push @parsed, $self->parse_line('<<不正なリンクです。>>'); | |
718 | + } | |
719 | + else { | |
720 | + push @parsed, $self->url_anchor($url); | |
721 | + } | |
722 | + } | |
723 | + | |
724 | + # ページリンク | |
725 | + elsif ($source =~ /^\[\[([^\|]+?)\]\]/) { | |
726 | + my $page = $1; | |
727 | + $source = $'; | |
728 | + push @parsed, $self->wiki_anchor($page); | |
729 | + } | |
730 | + | |
731 | + # 任意のURLリンク | |
732 | + elsif ($source =~ /^\[([^\[]+?)\|(.+?)\]/) { | |
733 | + my $label = $1; | |
734 | + my $url = $2; | |
735 | + $source = $'; | |
736 | + if ( index($url, q{"}) >= 0 | |
737 | + || index($url, '><') >= 0 | |
738 | + || index($url, 'javascript:') >= 0) | |
739 | + { | |
740 | + push @parsed, $self->parse_line('<<不正なリンクです。>>'); | |
741 | + } | |
742 | + else { | |
743 | + # URIを作成 | |
744 | + my $uri = &main::MyBaseUrl().$ENV{"PATH_INFO"}; | |
745 | + push @parsed, $self->url_anchor($uri . '/../' . $url, $label); | |
746 | + } | |
747 | + } | |
748 | + | |
749 | + # ボールド、イタリック、取り消し線、下線 | |
750 | + elsif ($source =~ /^('''?|==|__)(.+?)\1/) { | |
751 | + my $type = $1; | |
752 | + my $label = $2; | |
753 | + $source = $'; | |
754 | + if ($type eq q{'''}) { | |
755 | + push @parsed, $self->bold($label); | |
756 | + } | |
757 | + elsif ($type eq q{__}) { | |
758 | + push @parsed, $self->underline($label); | |
759 | + } | |
760 | + elsif ($type eq q{''}) { | |
761 | + push @parsed, $self->italic($label); | |
762 | + } | |
763 | + else { ## elsif ($type eq q{==}) { | |
764 | + push @parsed, $self->denialline($label); | |
765 | + } | |
766 | + } | |
767 | + | |
768 | + # エラーメッセージ | |
769 | + elsif ($source =~ /^<<(.+?)>>/) { | |
770 | + my $label = $1; | |
771 | + $source = $'; | |
772 | + push @parsed, $self->error($label); | |
773 | + } | |
774 | + | |
775 | + # インライン Wiki 書式全体には macth しなかったとき | |
776 | + else { | |
777 | + # 1 文字進む。 | |
778 | + if ($source =~ /^(.)/) { | |
779 | + $pre .= $1; | |
780 | + $source = $'; | |
781 | + } | |
782 | + | |
783 | + # parse 結果を @array に保存する処理を飛ばして繰り返し。 | |
784 | + next SOURCE; | |
785 | + } | |
786 | + | |
787 | + # インライン Wiki 書式全体に macth した後の | |
788 | + # parse 結果を @array に保存する処理。 | |
789 | + | |
790 | + # もし $pre が溜まっているなら、WikiNameの処理を実施。 | |
791 | + if ($pre ne q{}) { | |
792 | + push @array, $self->_parse_line_wikiname($pre); | |
793 | + $pre = q{}; | |
794 | + } | |
795 | + | |
796 | + push @array, @parsed; | |
797 | + } | |
798 | + | |
799 | + # もし $pre が溜まっているなら、WikiNameの処理を実施。 | |
800 | + if ($pre ne q{}) { | |
801 | + push @array, $self->_parse_line_wikiname($pre); | |
802 | + } | |
803 | + | |
804 | + return @array; | |
805 | +} | |
806 | + | |
807 | +#======================================================================== | |
808 | +# parse_line() から呼び出され、WikiNameの検索・置換処理を行います。 | |
809 | +#======================================================================== | |
810 | +sub _parse_line_wikiname { | |
811 | + my $self = shift; | |
812 | + my $source = shift; | |
813 | + | |
814 | + return () if (not defined $source); | |
815 | + | |
816 | + my @array = (); | |
817 | + | |
818 | + # $source が空になるまで繰り返す。 | |
819 | + while ($source ne q{}) { | |
820 | + | |
821 | + # WikiName | |
822 | + if ($main::WIKI_NAME == 1 && $source =~ /[A-Z]+?[a-z]+?(?:[A-Z]+?[a-z]+)+/) { | |
823 | + my $pre = $`; | |
824 | + my $page = $&; | |
825 | + $source = $'; | |
826 | + if ($pre ne q{}) { | |
827 | + push @array, $self->_parse_line_wikiname($pre); | |
828 | + } | |
829 | + push @array, $self->wiki_anchor($page); | |
830 | + } | |
831 | + | |
832 | + # WikiName も見つからなかったとき | |
833 | + else { | |
834 | + push @array, $self->text($source); | |
835 | + return @array; | |
836 | + } | |
837 | + } | |
838 | + return @array; | |
839 | +} | |
840 | + | |
841 | +#=============================================================================== | |
842 | +# <p> | |
843 | +# パースを開始前に呼び出されます。 | |
844 | +# サブクラスで必要な処理がある場合はオーバーライドしてください。 | |
845 | +# </p> | |
846 | +#=============================================================================== | |
847 | +sub start_parse {} | |
848 | + | |
849 | +#============================================================================== | |
850 | +# リスト | |
851 | +#============================================================================== | |
852 | +sub l_list { | |
853 | + my $self = shift; | |
854 | + my $level = shift; | |
855 | + my $obj = shift; | |
856 | + | |
857 | + if($self->{para}==1){ | |
858 | + $self->{html} .= "</p>\n"; | |
859 | + $self->{para} = 0; | |
860 | + } | |
861 | + | |
862 | + if($self->{list} == 1 && $level <= $self->{level}){ | |
863 | + $self->end_list; | |
864 | + } | |
865 | + $self->{list} = 0; | |
866 | + | |
867 | + $self->end_verbatim; | |
868 | + $self->end_table; | |
869 | + $self->end_quote; | |
870 | + | |
871 | + my $html = join("",@$obj); | |
872 | + | |
873 | + if($level > $self->{level}){ | |
874 | + while($level != $self->{level}){ | |
875 | + $self->{html} .= "<ul>\n"; | |
876 | + push(@{$self->{close_list}},"</ul>\n"); | |
877 | + $self->{level}++; | |
878 | + } | |
879 | + } elsif($level <= $self->{level}){ | |
880 | + while($level-1 != $self->{level}){ | |
881 | + if($self->{'list_close_'.$self->{level}} == 1){ | |
882 | + $self->{html} .= "</li>\n"; | |
883 | + $self->{'list_close_'.$self->{level}} = 0; | |
884 | + } | |
885 | + if($level == $self->{level}){ | |
886 | + last; | |
887 | + } | |
888 | + $self->{html} .= pop(@{$self->{close_list}}); | |
889 | + $self->{level}--; | |
890 | + } | |
891 | + } | |
892 | + | |
893 | + $self->{html} .= "<li>".$html; | |
894 | + $self->{'list_close_'.$level} = 1; | |
895 | +} | |
896 | + | |
897 | +#============================================================================== | |
898 | +# 番号付きリスト | |
899 | +#============================================================================== | |
900 | +sub l_numlist { | |
901 | + my $self = shift; | |
902 | + my $level = shift; | |
903 | + my $obj = shift; | |
904 | + | |
905 | + if($self->{para}==1){ | |
906 | + $self->{html} .= "</p>\n"; | |
907 | + $self->{para} = 0; | |
908 | + } | |
909 | + | |
910 | + if($self->{list} == 0 && $level <= $self->{level}){ | |
911 | + $self->end_list; | |
912 | + } | |
913 | + $self->{list} = 1; | |
914 | + | |
915 | + $self->end_verbatim; | |
916 | + $self->end_table; | |
917 | + $self->end_quote; | |
918 | + | |
919 | + my $html = join("",@$obj); | |
920 | + | |
921 | + if($level > $self->{level}){ | |
922 | + while($level != $self->{level}){ | |
923 | + $self->{html} .= "<ol>\n"; | |
924 | + push(@{$self->{close_list}},"</ol>\n"); | |
925 | + $self->{level}++; | |
926 | + } | |
927 | + } elsif($level <= $self->{level}){ | |
928 | + while($level-1 != $self->{level}){ | |
929 | + if($self->{'list_close_'.$self->{level}} == 1){ | |
930 | + $self->{html} .= "</li>\n"; | |
931 | + $self->{'list_close_'.$self->{level}} = 0; | |
932 | + } | |
933 | + if($level == $self->{level}){ | |
934 | + last; | |
935 | + } | |
936 | + $self->{html} .= pop(@{$self->{close_list}}); | |
937 | + $self->{level}--; | |
938 | + } | |
939 | + } | |
940 | + | |
941 | + $self->{html} .= "<li>".$html; | |
942 | + $self->{'list_close_'.$level} = 1; | |
943 | +} | |
944 | + | |
945 | +#============================================================================== | |
946 | +# リストの終了 | |
947 | +#============================================================================== | |
948 | +sub end_list { | |
949 | + my $self = shift; | |
950 | + while($self->{level} != 0){ | |
951 | + if($self->{'list_close_'.($self->{level})} == 1){ | |
952 | + $self->{html} .= "</li>\n"; | |
953 | + $self->{'list_close_'.$self->{level}} = 0; | |
954 | + } | |
955 | + $self->{html} .= pop(@{$self->{close_list}}); | |
956 | + $self->{level}--; | |
957 | + } | |
958 | +} | |
959 | + | |
960 | +#============================================================================== | |
961 | +# ヘッドライン | |
962 | +#============================================================================== | |
963 | +sub l_headline { | |
964 | + my $self = shift; | |
965 | + my $level = shift; | |
966 | + my $obj = shift; | |
967 | + | |
968 | + if($self->{para}==1){ | |
969 | + $self->{html} .= "</p>\n"; | |
970 | + $self->{para} = 0; | |
971 | + } | |
972 | + | |
973 | + $self->end_list; | |
974 | + $self->end_verbatim; | |
975 | + $self->end_table; | |
976 | + $self->end_quote; | |
977 | + | |
978 | + my $html = join("",@$obj); | |
979 | + | |
980 | + # メインの表示領域でないとき | |
981 | + if(!$self->{main}){ | |
982 | + $self->{html} .= "<h".($level+1).">".$html."</h".($level+1).">\n"; | |
983 | + | |
984 | + # メインの表示領域の場合はアンカを出力 | |
985 | + } else { | |
986 | + if($level==2){ | |
987 | + $self->{html} .= "<h".($level+1)."><a name=\"p".$self->{p_cnt}."\"><span class=\"sanchor\"> </span>". | |
988 | + $html."</a></h".($level+1).">\n"; | |
989 | + } else { | |
990 | + $self->{html} .= "<h".($level+1)."><a name=\"p".$self->{p_cnt}."\">".$html."</a></h".($level+1).">\n"; | |
991 | + } | |
992 | + } | |
993 | + $self->{p_cnt}++; | |
994 | +} | |
995 | + | |
996 | +#============================================================================== | |
997 | +# 水平線 | |
998 | +#============================================================================== | |
999 | +sub l_line { | |
1000 | + my $self = shift; | |
1001 | + | |
1002 | + if($self->{para}==1){ | |
1003 | + $self->{html} .= "</p>\n"; | |
1004 | + $self->{para} = 0; | |
1005 | + } | |
1006 | + | |
1007 | + $self->end_list; | |
1008 | + $self->end_verbatim; | |
1009 | + $self->end_table; | |
1010 | + $self->end_quote; | |
1011 | + | |
1012 | + $self->{html} .= "<hr>\n"; | |
1013 | +} | |
1014 | + | |
1015 | +#============================================================================== | |
1016 | +# 段落区切り | |
1017 | +#============================================================================== | |
1018 | +sub l_paragraph { | |
1019 | + my $self = shift; | |
1020 | + | |
1021 | + $self->end_list; | |
1022 | + $self->end_verbatim; | |
1023 | + $self->end_table; | |
1024 | + $self->end_quote; | |
1025 | + | |
1026 | + if($self->{para}==1){ | |
1027 | + $self->{html} .= "</p>\n"; | |
1028 | + $self->{para} = 0; | |
1029 | + } elsif($main::BR_MODE==1){ | |
1030 | + $self->{html} .= "<br>\n"; | |
1031 | + } | |
1032 | +} | |
1033 | + | |
1034 | +#============================================================================== | |
1035 | +# 整形済テキスト | |
1036 | +#============================================================================== | |
1037 | +sub l_verbatim { | |
1038 | + my $self = shift; | |
1039 | + my $text = shift; | |
1040 | + | |
1041 | + if($self->{para}==1){ | |
1042 | + $self->{html} .= "</p>\n"; | |
1043 | + $self->{para} = 0; | |
1044 | + } | |
1045 | + | |
1046 | + $self->end_list; | |
1047 | + $self->end_table; | |
1048 | + $self->end_quote; | |
1049 | + | |
1050 | + $text =~ s/^\s//; | |
1051 | + $self->{pre} .= Util::escapeHTML($text)."\n"; | |
1052 | +} | |
1053 | + | |
1054 | +sub end_verbatim { | |
1055 | + my $self = shift; | |
1056 | + if($self->{pre} ne ""){ | |
1057 | + $self->{html} .= "<pre>".$self->{pre}."</pre>\n"; | |
1058 | + $self->{pre} = ""; | |
1059 | + } | |
1060 | +} | |
1061 | + | |
1062 | +#============================================================================== | |
1063 | +# テーブル | |
1064 | +#============================================================================== | |
1065 | +sub l_table { | |
1066 | + my $self = shift; | |
1067 | + my $row = shift; | |
1068 | + $self->end_list; | |
1069 | + $self->end_verbatim; | |
1070 | + $self->end_quote; | |
1071 | + | |
1072 | + my $tag = "td"; | |
1073 | + | |
1074 | + if($self->{table}==0){ | |
1075 | + $self->{table}=1; | |
1076 | + $self->{html} .= "<table>\n"; | |
1077 | + $tag = "th"; | |
1078 | + } else { | |
1079 | + $self->{table}=2; | |
1080 | + } | |
1081 | + | |
1082 | + my @columns = (); | |
1083 | + foreach(@$row){ | |
1084 | + my $html = join("",@$_); | |
1085 | + if($#columns != -1 && $html eq '<<'){ | |
1086 | + @columns[$#columns]->{colspan}++; | |
1087 | + } else { | |
1088 | + push(@columns, {colspan => 1, html => $html}); | |
1089 | + } | |
1090 | + } | |
1091 | + $self->{html} .= "<tr>\n"; | |
1092 | + foreach(@columns){ | |
1093 | + $self->{html} .= "<$tag colspan=\"".$_->{colspan}."\">".$_->{html}."</$tag>\n"; | |
1094 | + } | |
1095 | + $self->{html} .= "</tr>\n"; | |
1096 | +} | |
1097 | + | |
1098 | +sub end_table { | |
1099 | + my $self = shift; | |
1100 | + if($self->{table}!=0){ | |
1101 | + $self->{table} = 0; | |
1102 | + $self->{html} .= "</table>\n"; | |
1103 | + } | |
1104 | +} | |
1105 | + | |
1106 | +#============================================================================== | |
1107 | +# パース終了時の処理 | |
1108 | +#============================================================================== | |
1109 | +sub end_parse { | |
1110 | + my $self = shift; | |
1111 | + $self->end_list; | |
1112 | + $self->end_verbatim; | |
1113 | + $self->end_table; | |
1114 | + $self->end_quote; | |
1115 | + | |
1116 | + if($self->{para}==1){ | |
1117 | + $self->{html} .= "</p>\n"; | |
1118 | + $self->{para} = 0; | |
1119 | + } | |
1120 | +} | |
1121 | + | |
1122 | +#============================================================================== | |
1123 | +# 行書式に該当しない行 | |
1124 | +#============================================================================== | |
1125 | +sub l_text { | |
1126 | + my $self = shift; | |
1127 | + my $obj = shift; | |
1128 | + $self->end_list; | |
1129 | + $self->end_verbatim; | |
1130 | + $self->end_table; | |
1131 | + $self->end_quote; | |
1132 | + my $html = join("",@$obj); | |
1133 | + | |
1134 | + if($self->{para}==0){ | |
1135 | + $self->{html} .= "<p>"; | |
1136 | + $self->{para} = 1; | |
1137 | + } | |
1138 | + $self->{html} .= $html; | |
1139 | + | |
1140 | + # brモードに設定されている場合は<br>を足す | |
1141 | + if($main::BR_MODE==1){ | |
1142 | + $self->{html} .= "<br>\n"; | |
1143 | + } | |
1144 | +} | |
1145 | + | |
1146 | +#============================================================================== | |
1147 | +# 引用 | |
1148 | +#============================================================================== | |
1149 | +sub l_quotation { | |
1150 | + my $self = shift; | |
1151 | + my $obj = shift; | |
1152 | + $self->end_list; | |
1153 | + $self->end_verbatim; | |
1154 | + $self->end_table; | |
1155 | + my $html = join("",@$obj); | |
1156 | + $self->{quote} .= "<p>".$html."</p>\n"; | |
1157 | +} | |
1158 | + | |
1159 | +sub end_quote { | |
1160 | + my $self = shift; | |
1161 | + if($self->{quote} ne ""){ | |
1162 | + $self->{html} .= "<blockquote>".$self->{quote}."</blockquote>\n"; | |
1163 | + $self->{quote} = ""; | |
1164 | + } | |
1165 | +} | |
1166 | + | |
1167 | +#============================================================================== | |
1168 | +# 説明 | |
1169 | +#============================================================================== | |
1170 | +sub l_explanation { | |
1171 | + my $self = shift; | |
1172 | + my $obj1 = shift; | |
1173 | + my $obj2 = shift; | |
1174 | + | |
1175 | + $self->end_list; | |
1176 | + $self->end_verbatim; | |
1177 | + $self->end_table; | |
1178 | + $self->end_quote; | |
1179 | + | |
1180 | + my $html1 = join("",@$obj1); | |
1181 | + my $html2 = join("",@$obj2); | |
1182 | + | |
1183 | + $self->{html} .= "<dl>\n<dt>".$html1."</dt>\n<dd>".$html2."</dd>\n</dl>\n"; | |
1184 | +} | |
1185 | + | |
1186 | +#============================================================================== | |
1187 | +# ボールド | |
1188 | +#============================================================================== | |
1189 | +sub bold { | |
1190 | + my $self = shift; | |
1191 | + my $text = shift; | |
1192 | + return "<strong>".join("",$self->parse_line($text))."</strong>"; | |
1193 | +} | |
1194 | + | |
1195 | +#============================================================================== | |
1196 | +# イタリック | |
1197 | +#============================================================================== | |
1198 | +sub italic { | |
1199 | + my $self = shift; | |
1200 | + my $text = shift; | |
1201 | + return "<em>".join("",$self->parse_line($text))."</em>"; | |
1202 | +} | |
1203 | + | |
1204 | +#============================================================================== | |
1205 | +# 下線 | |
1206 | +#============================================================================== | |
1207 | +sub underline { | |
1208 | + my $self = shift; | |
1209 | + my $text = shift; | |
1210 | + return "<ins>".join("",$self->parse_line($text))."</ins>"; | |
1211 | +} | |
1212 | + | |
1213 | +#============================================================================== | |
1214 | +# 打ち消し線 | |
1215 | +#============================================================================== | |
1216 | +sub denialline { | |
1217 | + my $self = shift; | |
1218 | + my $text = shift; | |
1219 | + return "<del>".join("",$self->parse_line($text))."</del>"; | |
1220 | +} | |
1221 | + | |
1222 | +#============================================================================== | |
1223 | +# URLアンカ | |
1224 | +#============================================================================== | |
1225 | +sub url_anchor { | |
1226 | + my $self = shift; | |
1227 | + my $url = shift; | |
1228 | + my $name = shift; | |
1229 | + | |
1230 | + if($name eq ""){ | |
1231 | + $name = $url; | |
1232 | + } | |
1233 | + | |
1234 | + if($url eq $name && $url=~/\.(gif|jpg|jpeg|bmp|png)$/i && $main::DISPLAY_IMAGE==1){ | |
1235 | + return "<img src=\"".$url."\">"; | |
1236 | + } else { | |
1237 | + return "<a href=\"$url\">".Util::escapeHTML($name)."</a>"; | |
1238 | + } | |
1239 | +} | |
1240 | + | |
1241 | +#============================================================================== | |
1242 | +# Wikiページへのアンカ | |
1243 | +#============================================================================== | |
1244 | +sub wiki_anchor { | |
1245 | + my $self = shift; | |
1246 | + my $page = shift; | |
1247 | + my $name = shift; | |
1248 | + | |
1249 | + my $anchor = undef; | |
1250 | + my $ppage = $page; | |
1251 | + | |
1252 | + if(!defined($name) || $name eq ""){ | |
1253 | + $name = $page; | |
1254 | + } | |
1255 | + | |
1256 | + if(&Wiki::page_exists($page)){ | |
1257 | + #アンカーを含むページが存在する場合はリンクを優先 | |
1258 | + return "<a href=\"".&Wiki::create_page_url($page)."\" class=\"wikipage\">". | |
1259 | + &Util::escapeHTML($name)."</a>"; | |
1260 | + } else { | |
1261 | + #最後の"#"以降をアンカーとする | |
1262 | + if($page =~ m/#([^#]+)$/) { | |
1263 | + $page = $`; | |
1264 | + $anchor = $1; | |
1265 | + } | |
1266 | + if(defined($anchor) && $page eq '') { | |
1267 | + #同一ページのアンカーリンク | |
1268 | + return "<a href=\"#$anchor\" class=\"wikipage\">". | |
1269 | + &Util::escapeHTML($name)."</a>"; | |
1270 | + } elsif(&Wiki::page_exists($page)) { | |
1271 | + #指定ページのアンカーリンク | |
1272 | + return "<a href=\"".&Wiki::create_page_url($page).(defined($anchor)?"#".$anchor:"")."\" class=\"wikipage\">". | |
1273 | + &Util::escapeHTML($name)."</a>"; | |
1274 | + } else { | |
1275 | + #新規ページ作成用リンク | |
1276 | + return "<span class=\"nopage\">".&Util::escapeHTML($name)."</span>". | |
1277 | + "<a href=\"".&Wiki::create_page_url($page)."\">?</a>"; | |
1278 | + } | |
1279 | + } | |
1280 | +} | |
1281 | + | |
1282 | +#============================================================================== | |
1283 | +# ただのテキスト | |
1284 | +#============================================================================== | |
1285 | +sub text { | |
1286 | + my $self = shift; | |
1287 | + my $text = shift; | |
1288 | + return &Util::escapeHTML($text); | |
1289 | +} | |
1290 | + | |
1291 | +#============================================================================== | |
1292 | +# インラインプラグイン | |
1293 | +#============================================================================== | |
1294 | +sub plugin { | |
1295 | + my $self = shift; | |
1296 | + my $plugin = shift; | |
1297 | + | |
1298 | + my $func_ref = &Wiki::get_plugin_info($plugin->{command})->{FUNCTION}; | |
1299 | + my $result = &$func_ref(@{$plugin->{args}}); | |
1300 | + if(defined($result) && $result ne ""){ | |
1301 | + return ($result); | |
1302 | + } | |
1303 | + | |
1304 | + return undef; | |
1305 | +} | |
1306 | + | |
1307 | +#============================================================================== | |
1308 | +# パラグラフプラグイン | |
1309 | +#============================================================================== | |
1310 | +sub l_plugin { | |
1311 | + my $self = shift; | |
1312 | + my $plugin = shift; | |
1313 | + | |
1314 | + if($self->{para}==1){ | |
1315 | + $self->{html} .= "</p>\n"; | |
1316 | + $self->{para} = 0; | |
1317 | + } | |
1318 | + | |
1319 | + $self->end_list; | |
1320 | + $self->end_verbatim; | |
1321 | + $self->end_table; | |
1322 | + $self->end_quote; | |
1323 | + | |
1324 | + my $func_ref = &Wiki::get_plugin_info($plugin->{command})->{FUNCTION}; | |
1325 | + my $result = &$func_ref(@{$plugin->{args}}); | |
1326 | + if(defined($result) && $result ne ""){ | |
1327 | + $self->{html} .= $result; | |
1328 | + } | |
1329 | +} | |
1330 | + | |
1331 | +#============================================================================== | |
1332 | +# イメージ | |
1333 | +#============================================================================== | |
1334 | +sub l_image { | |
1335 | + my $self = shift; | |
1336 | + my $page = shift; | |
1337 | + my $file = shift; | |
1338 | + my $width = shift; | |
1339 | + my $height = shift; | |
1340 | + | |
1341 | + if($self->{para}==1){ | |
1342 | + $self->{html} .= "</p>\n"; | |
1343 | + $self->{para} = 0; | |
1344 | + } | |
1345 | + | |
1346 | + $self->end_list; | |
1347 | + $self->end_verbatim; | |
1348 | + $self->end_table; | |
1349 | + $self->end_quote; | |
1350 | + | |
1351 | + $self->{html} .= "<div class=\"image\">"; | |
1352 | + $self->{html} .= "<img src=\"".&Wiki::create_url({'p'=>$page,'f'=>$file},$main::DOWNLOAD_SCRIPT)."\""; | |
1353 | + $self->{html} .= " width=\"$width\"" if ($width ne ""); | |
1354 | + $self->{html} .= " height=\"$height\"" if ($height ne ""); | |
1355 | + $self->{html} .= "/>"; | |
1356 | + $self->{html} .= "</div>\n"; | |
1357 | +} | |
1358 | + | |
1359 | +#============================================================================== | |
1360 | +# エラーメッセージ | |
1361 | +#============================================================================== | |
1362 | +sub error { | |
1363 | + my $self = shift; | |
1364 | + my $label = shift; | |
1365 | + | |
1366 | + return "<span class=\"error\">".Util::escapeHTML($label)."</span>"; | |
1367 | +} | |
1368 | + | |
1369 | +################################################################################ | |
1370 | +# | |
1371 | +# ユーティリティ関数を提供するパッケージ | |
1372 | +# | |
1373 | +################################################################################ | |
1374 | +package Util; | |
1375 | +#=============================================================================== | |
1376 | +# 引数で渡された文字列をURLエンコードして返します。 | |
1377 | +#=============================================================================== | |
1378 | +sub url_encode { | |
1379 | + my $retstr = shift; | |
1380 | + &jcode::convert(\$retstr,"euc"); | |
1381 | + | |
1382 | + $retstr =~ s/([^ 0-9A-Za-z])/sprintf("%%%.2X", ord($1))/eg; | |
1383 | + $retstr =~ tr/ /+/; | |
1384 | + return $retstr; | |
1385 | +} | |
1386 | + | |
1387 | +#=============================================================================== | |
1388 | +# 引数で渡された文字列をURLデコードして返します。 | |
1389 | +#=============================================================================== | |
1390 | +sub url_decode{ | |
1391 | + my $retstr = shift; | |
1392 | + | |
1393 | + $retstr =~ tr/+/ /; | |
1394 | + $retstr =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; | |
1395 | + return $retstr; | |
1396 | +} | |
1397 | + | |
1398 | +#=============================================================================== | |
1399 | +# 引数で渡された文字列のHTMLタグをエスケープして返します。 | |
1400 | +#=============================================================================== | |
1401 | +sub escapeHTML { | |
1402 | + my($retstr) = shift; | |
1403 | + &jcode::convert(\$retstr,"euc"); | |
1404 | + | |
1405 | + my %table = ( | |
1406 | + '&' => '&', | |
1407 | + '"' => '"', | |
1408 | + '<' => '<', | |
1409 | + '>' => '>', | |
1410 | + ); | |
1411 | + $retstr =~ s/([&\"<>])/$table{$1}/go; | |
1412 | + $retstr =~ s/&#([0-9]{1,5});/&#$1;/go; | |
1413 | + $retstr =~ s/&#(0*(0|9|10|13|38|60|62));/&#$1;/g; | |
1414 | +# $retstr =~ s/&([a-zA-Z0-9]{2,8});/&$1;/go; | |
1415 | + return $retstr; | |
1416 | +} | |
1417 | + | |
1418 | + | |
1419 | +#=============================================================================== | |
1420 | +# 日付をフォーマットします。 | |
1421 | +#=============================================================================== | |
1422 | +sub format_date { | |
1423 | + my $t = shift; | |
1424 | + my ($sec, $min, $hour, $mday, $mon, $year) = localtime($t); | |
1425 | + return sprintf("%04d年%02d月%02d日 %02d時%02d分%02d秒", | |
1426 | + $year+1900,$mon+1,$mday,$hour,$min,$sec); | |
1427 | +} | |
1428 | + | |
1429 | +#=============================================================================== | |
1430 | +# 文字列の両端の空白を切り落とします。 | |
1431 | +#=============================================================================== | |
1432 | +sub trim { | |
1433 | + my $text = shift; | |
1434 | + if(!defined($text)){ | |
1435 | + return ""; | |
1436 | + } | |
1437 | + $text =~ s/^(?:\s)+//o; | |
1438 | + $text =~ s/(?:\s)+$//o; | |
1439 | + return $text; | |
1440 | +} | |
1441 | + | |
1442 | + | |
1443 | +#=============================================================================== | |
1444 | +# タグを削除して文字列のみを取得します。 | |
1445 | +#=============================================================================== | |
1446 | +sub delete_tag { | |
1447 | + my $text = shift; | |
1448 | + $text =~ s/<(.|\s)+?>//g; | |
1449 | + return $text; | |
1450 | +} | |
1451 | + | |
1452 | +#=============================================================================== | |
1453 | +# ページ名が使用可能かどうかチェックします。 | |
1454 | +#=============================================================================== | |
1455 | +sub check_pagename { | |
1456 | + my $pagename = shift; | |
1457 | + | |
1458 | + #ページ名をチェック | |
1459 | + if( !defined($pagename) | |
1460 | + || $pagename eq "" # 空 | |
1461 | + || $pagename =~ /[\|\[\]]/ # |[] | |
1462 | + || $pagename =~ /^:/ # コロンで始まる | |
1463 | + || $pagename =~ /[^:]:[^:]/ # コロン単体での使用 | |
1464 | + || $pagename =~ /^\s+$/ # 空白のみ | |
1465 | + ){ | |
1466 | + return 0; | |
1467 | + } | |
1468 | + return 1; | |
1469 | +} | |
1470 | + | |
1471 | +#=============================================================================== | |
1472 | +# 数値かどうかチェックします。 | |
1473 | +#=============================================================================== | |
1474 | +sub check_numeric { | |
1475 | + my $text = shift; | |
1476 | + if($text =~ /^[0-9]+$/){ | |
1477 | + return 1; | |
1478 | + } else { | |
1479 | + return 0; | |
1480 | + } | |
1481 | +} | |
1482 | + | |
1483 | +#============================================================================== | |
1484 | +# メール送信 | |
1485 | +#============================================================================== | |
1486 | +sub send_mail { | |
1487 | + my $action = shift; | |
1488 | + my $page = shift; | |
1489 | + my $enc_page = &Util::url_encode($page); | |
1490 | + | |
1491 | + if($main::ADMIN_MAIL eq "" || $main::SEND_MAIL eq ""){ | |
1492 | + return; | |
1493 | + } | |
1494 | + | |
1495 | + my $subject = ""; | |
1496 | + if($action eq 'CREATE'){ | |
1497 | + $subject = "[FSWikiLite]$pageが作成されました"; | |
1498 | + | |
1499 | + } elsif($action eq 'MODIFY'){ | |
1500 | + $subject = "[FSWikiLite]$pageが更新されました"; | |
1501 | + | |
1502 | + } elsif($action eq 'DELETE'){ | |
1503 | + $subject = "[FSWikiLite]$pageが削除されました"; | |
1504 | + } | |
1505 | + | |
1506 | + # MIMEエンコード | |
1507 | + $subject = &main::mimeencode($subject); | |
1508 | + | |
1509 | + my $head = "Subject: $subject\n". | |
1510 | + "From: $main::ADMIN_MAIL\n". | |
1511 | + "Content-Transfer-Encoding: 7bit\n". | |
1512 | + "Content-Type: text/plain; charset=\"ISO-2022-JP\"\n". | |
1513 | + "Reply-To: $main::ADMIN_MAIL\n". | |
1514 | + "\n"; | |
1515 | + | |
1516 | + my $body = "IP:".$ENV{'REMOTE_ADDR'}."\n". | |
1517 | + "UA:".$ENV{'HTTP_USER_AGENT'}."\n"; | |
1518 | + | |
1519 | + if($action eq 'MODIFY' || $action eq 'DELETE'){ | |
1520 | + if(-e "$main::BACKUP_DIR/$enc_page.bak"){ | |
1521 | + $body .= "以下は変更前のソースです。\n". | |
1522 | + "-----------------------------------------------------\n"; | |
1523 | + open(BACKUP,"$main::BACKUP_DIR/$enc_page.bak"); | |
1524 | + while(my $line = <BACKUP>){ | |
1525 | + $body .= $line; | |
1526 | + } | |
1527 | + close(BACKUP); | |
1528 | + } | |
1529 | + } | |
1530 | + | |
1531 | + # 文字コードの変換(jcode.plを使用する) | |
1532 | + &jcode::convert(\$body,'jis'); | |
1533 | + | |
1534 | + open(MAIL,"| $main::SEND_MAIL $main::ADMIN_MAIL"); | |
1535 | + print MAIL $head; | |
1536 | + print MAIL $body; | |
1537 | + close(MAIL); | |
1538 | +} | |
1539 | + | |
1540 | +#=============================================================================== | |
1541 | +# エラーを通知 | |
1542 | +#=============================================================================== | |
1543 | +sub error { | |
1544 | + my $error = shift; | |
1545 | + | |
1546 | + print "Content-Type: text/html;charset=EUC-JP\n\n"; | |
1547 | + print "<html>\n"; | |
1548 | + print "<head><title>エラー - FSWikiLite</title></head>\n"; | |
1549 | + print "<body>\n"; | |
1550 | + print "<h1>エラーが発生しました</h1>\n"; | |
1551 | + print "<pre>\n"; | |
1552 | + print &Util::escapeHTML($error); | |
1553 | + print "</pre>\n"; | |
1554 | + print "</body><html>\n"; | |
1555 | + | |
1556 | + exit; | |
1557 | +} | |
1558 | + | |
1559 | +#=============================================================================== | |
1560 | +# 携帯電話かどうかチェックします。 | |
1561 | +#=============================================================================== | |
1562 | +sub handyphone { | |
1563 | + my $ua = $ENV{'HTTP_USER_AGENT'}; | |
1564 | + if(!defined($ua)){ | |
1565 | + return 0; | |
1566 | + } | |
1567 | + if($ua=~/^DoCoMo\// || $ua=~ /^J-PHONE\// || $ua=~ /UP\.Browser/ || $ua=~ /\(DDIPOCKET\;/ || $ua=~ /\(WILLCOM\;/ || $ua=~ /^Vodafone\// || $ua=~ /^SoftBank\//){ | |
1568 | + return 1; | |
1569 | + } else { | |
1570 | + return 0; | |
1571 | + } | |
1572 | +} | |
1573 | + | |
1574 | +#=============================================================================== | |
1575 | +# スマートフォンかどうかチェックします。 | |
1576 | +#=============================================================================== | |
1577 | +sub smartphone { | |
1578 | + my $ua = $ENV{'HTTP_USER_AGENT'}; | |
1579 | + if(!defined($ua)){ | |
1580 | + return 0; | |
1581 | + } | |
1582 | + if($ua =~ /Android/ || $ua =~ /iPhone/){ | |
1583 | + return 1; | |
1584 | + } else { | |
1585 | + return 0; | |
1586 | + } | |
1587 | +} | |
1588 | + | |
1589 | +1; |
@@ -0,0 +1,35 @@ | ||
1 | +################################################################################ | |
2 | +# | |
3 | +# 設定ファイル | |
4 | +# | |
5 | +################################################################################ | |
6 | +#=============================================================================== | |
7 | +# 初期設定 | |
8 | +#=============================================================================== | |
9 | +$DATA_DIR = './data'; | |
10 | +$BACKUP_DIR = './backup'; | |
11 | +$ATTACH_DIR = './attach'; | |
12 | +$THEME_URL = './theme/default/default.css'; | |
13 | +$ADMIN_MAIL = ''; | |
14 | +$SEND_MAIL = ''; | |
15 | +$WIKI_NAME = 0; | |
16 | +$BR_MODE = 0; | |
17 | +$DISPLAY_IMAGE = 1; | |
18 | +$MAIN_SCRIPT = 'wiki.cgi'; | |
19 | +$EDIT_SCRIPT = 'edit.cgi'; | |
20 | +$CATEGORY_SCRIPT = 'category.cgi'; | |
21 | +$DOWNLOAD_SCRIPT = 'download.cgi'; | |
22 | +$SITE_TITLE = 'FSWikiLite'; | |
23 | + | |
24 | +#=============================================================================== | |
25 | +# プロダクト情報 | |
26 | +#=============================================================================== | |
27 | +$VERSION = '0.1.0'; | |
28 | +$SITE_URL = 'http://fswiki.osdn.jp/cgi-bin/wiki.cgi'; | |
29 | + | |
30 | +#=============================================================================== | |
31 | +# プラグインの設定 | |
32 | +#=============================================================================== | |
33 | +require "./plugin/core.pl"; | |
34 | + | |
35 | +1; |
@@ -0,0 +1,785 @@ | ||
1 | +package jcode; | |
2 | +;###################################################################### | |
3 | +;# | |
4 | +;# jcode.pl: Perl library for Japanese character code conversion | |
5 | +;# | |
6 | +;# Copyright (c) 1995-2000 Kazumasa Utashiro <utashiro@iij.ad.jp> | |
7 | +;# Internet Initiative Japan Inc. | |
8 | +;# 3-13 Kanda Nishiki-cho, Chiyoda-ku, Tokyo 101-0054, Japan | |
9 | +;# | |
10 | +;# Copyright (c) 1992,1993,1994 Kazumasa Utashiro | |
11 | +;# Software Research Associates, Inc. | |
12 | +;# | |
13 | +;# Use and redistribution for ANY PURPOSE are granted as long as all | |
14 | +;# copyright notices are retained. Redistribution with modification | |
15 | +;# is allowed provided that you make your modified version obviously | |
16 | +;# distinguishable from the original one. THIS SOFTWARE IS PROVIDED | |
17 | +;# BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES ARE | |
18 | +;# DISCLAIMED. | |
19 | +;# | |
20 | +;# Original version was developed under the name of srekcah@sra.co.jp | |
21 | +;# February 1992 and it was called kconv.pl at the beginning. This | |
22 | +;# address was a pen name for group of individuals and it is no longer | |
23 | +;# valid. | |
24 | +;# | |
25 | +;# The latest version is available here: | |
26 | +;# | |
27 | +;# ftp://ftp.iij.ad.jp/pub/IIJ/dist/utashiro/perl/ | |
28 | +;# | |
29 | +;; $rcsid = q$Id: jcode.pl,v 2.13 2000/09/29 16:10:05 utashiro Exp $; | |
30 | +;# | |
31 | +;###################################################################### | |
32 | +;# | |
33 | +;# PERL4 INTERFACE: | |
34 | +;# | |
35 | +;# &jcode'getcode(*line) | |
36 | +;# Return 'jis', 'sjis', 'euc' or undef according to | |
37 | +;# Japanese character code in $line. Return 'binary' if | |
38 | +;# the data has non-character code. | |
39 | +;# | |
40 | +;# When evaluated in array context, it returns a list | |
41 | +;# contains two items. First value is the number of | |
42 | +;# characters which matched to the expected code, and | |
43 | +;# second value is the code name. It is useful if and | |
44 | +;# only if the number is not 0 and the code is undef; | |
45 | +;# that case means it couldn't tell 'euc' or 'sjis' | |
46 | +;# because the evaluation score was exactly same. This | |
47 | +;# interface is too tricky, though. | |
48 | +;# | |
49 | +;# Code detection between euc and sjis is very difficult | |
50 | +;# or sometimes impossible or even lead to wrong result | |
51 | +;# when it includes JIS X0201 KANA characters. So JIS | |
52 | +;# X0201 KANA is ignored for automatic code detection. | |
53 | +;# | |
54 | +;# &jcode'convert(*line, $ocode [, $icode [, $option]]) | |
55 | +;# Convert the contents of $line to the specified | |
56 | +;# Japanese code given in the second argument $ocode. | |
57 | +;# $ocode can be any of "jis", "sjis" or "euc", or use | |
58 | +;# "noconv" when you don't want the code conversion. | |
59 | +;# Input code is recognized automatically from the line | |
60 | +;# itself when $icode is not supplied (JIS X0201 KANA is | |
61 | +;# ignored in code detection. See the above descripton | |
62 | +;# of &getcode). $icode also can be specified, but | |
63 | +;# xxx2yyy routine is more efficient when both codes are | |
64 | +;# known. | |
65 | +;# | |
66 | +;# It returns the code of input string in scalar context, | |
67 | +;# and a list of pointer of convert subroutine and the | |
68 | +;# input code in array context. | |
69 | +;# | |
70 | +;# Japanese character code JIS X0201, X0208, X0212 and | |
71 | +;# ASCII code are supported. X0212 characters can not be | |
72 | +;# represented in SJIS and they will be replased by | |
73 | +;# "geta" character when converted to SJIS. | |
74 | +;# | |
75 | +;# See next paragraph for $option parameter. | |
76 | +;# | |
77 | +;# &jcode'xxx2yyy(*line [, $option]) | |
78 | +;# Convert the Japanese code from xxx to yyy. String xxx | |
79 | +;# and yyy are any convination from "jis", "euc" or | |
80 | +;# "sjis". They return *approximate* number of converted | |
81 | +;# bytes. So return value 0 means the line was not | |
82 | +;# converted at all. | |
83 | +;# | |
84 | +;# Optional parameter $option is used to specify optional | |
85 | +;# conversion method. String "z" is for JIS X0201 KANA | |
86 | +;# to X0208 KANA, and "h" is for reverse. | |
87 | +;# | |
88 | +;# $jcode'convf{'xxx', 'yyy'} | |
89 | +;# The value of this associative array is pointer to the | |
90 | +;# subroutine jcode'xxx2yyy(). | |
91 | +;# | |
92 | +;# &jcode'to($ocode, $line [, $icode [, $option]]) | |
93 | +;# &jcode'jis($line [, $icode [, $option]]) | |
94 | +;# &jcode'euc($line [, $icode [, $option]]) | |
95 | +;# &jcode'sjis($line [, $icode [, $option]]) | |
96 | +;# These functions are prepared for easy use of | |
97 | +;# call/return-by-value interface. You can use these | |
98 | +;# funcitons in s///e operation or any other place for | |
99 | +;# convenience. | |
100 | +;# | |
101 | +;# &jcode'jis_inout($in, $out) | |
102 | +;# Set or inquire JIS start and end sequences. Default | |
103 | +;# is "ESC-$-B" and "ESC-(-B". If you supplied only one | |
104 | +;# character, "ESC-$" or "ESC-(" is prepended for each | |
105 | +;# character respectively. Acutually "ESC-(-B" is not a | |
106 | +;# sequence to end JIS code but a sequence to start ASCII | |
107 | +;# code set. So `in' and `out' are somewhat misleading. | |
108 | +;# | |
109 | +;# &jcode'get_inout($string) | |
110 | +;# Get JIS start and end sequences from $string. | |
111 | +;# | |
112 | +;# &jcode'cache() | |
113 | +;# &jcode'nocache() | |
114 | +;# &jcode'flush() | |
115 | +;# Usually, converted character is cached in memory to | |
116 | +;# avoid same calculations have to be done many times. | |
117 | +;# To disable this caching, call &jcode'nocache(). It | |
118 | +;# can be revived by &jcode'cache() and cache is flushed | |
119 | +;# by calling &jcode'flush(). &cache() and &nocache() | |
120 | +;# functions return previous caching state. | |
121 | +;# | |
122 | +;# --------------------------------------------------------------- | |
123 | +;# | |
124 | +;# &jcode'h2z_xxx(*line) | |
125 | +;# JIS X0201 KANA (so-called Hankaku-KANA) to X0208 KANA | |
126 | +;# (Zenkaku-KANA) code conversion routine. String xxx is | |
127 | +;# any of "jis", "sjis" and "euc". From the difficulty | |
128 | +;# of recognizing code set from 1-byte KATAKANA string, | |
129 | +;# automatic code recognition is not supported. | |
130 | +;# | |
131 | +;# &jcode'z2h_xxx(*line) | |
132 | +;# X0208 to X0201 KANA code conversion routine. String | |
133 | +;# xxx is any of "jis", "sjis" and "euc". | |
134 | +;# | |
135 | +;# $jcode'z2hf{'xxx'} | |
136 | +;# $jcode'h2zf{'xxx'} | |
137 | +;# These are pointer to the corresponding function just | |
138 | +;# as $jcode'convf. | |
139 | +;# | |
140 | +;# --------------------------------------------------------------- | |
141 | +;# | |
142 | +;# &jcode'tr(*line, $from, $to [, $option]) | |
143 | +;# &jcode'tr emulates tr operator for 2 byte code. Only 'd' | |
144 | +;# is interpreted as an option. | |
145 | +;# | |
146 | +;# Range operator like `A-Z' for 2 byte code is partially | |
147 | +;# supported. Code must be JIS or EUC, and first byte | |
148 | +;# have to be same on first and last character. | |
149 | +;# | |
150 | +;# CAUTION: Handling range operator is a kind of trick | |
151 | +;# and it is not perfect. So if you need to transfer `-' | |
152 | +;# character, please be sure to put it at the beginning | |
153 | +;# or the end of $from and $to strings. | |
154 | +;# | |
155 | +;# &jcode'trans($line, $from, $to [, $option) | |
156 | +;# Same as &jcode'tr but accept string and return string | |
157 | +;# after translation. | |
158 | +;# | |
159 | +;# --------------------------------------------------------------- | |
160 | +;# | |
161 | +;# &jcode'init() | |
162 | +;# Initialize the variables used in this package. You | |
163 | +;# don't have to call this when using jocde.pl by `do' or | |
164 | +;# `require' interface. Call it first if you embedded | |
165 | +;# the jcode.pl at the end of your script. | |
166 | +;# | |
167 | +;###################################################################### | |
168 | +;# | |
169 | +;# PERL5 INTERFACE: | |
170 | +;# | |
171 | +;# Current jcode.pl is written in Perl 4 but it is possible to use | |
172 | +;# from Perl 5 using `references'. Fully perl5 capable version is | |
173 | +;# future issue. | |
174 | +;# | |
175 | +;# Since lexical variable is not a subject of typeglob, *string style | |
176 | +;# call doesn't work if the variable is declared as `my'. Same thing | |
177 | +;# happens to special variable $_ if the perl is compiled to use | |
178 | +;# thread capability. So using reference is generally recommented to | |
179 | +;# avoid the mysterious error. | |
180 | +;# | |
181 | +;# jcode::getcode(\$line) | |
182 | +;# jcode::convert(\$line, $ocode [, $icode [, $option]]) | |
183 | +;# jcode::xxx2yyy(\$line [, $option]) | |
184 | +;# &{$jcode::convf{'xxx', 'yyy'}}(\$line) | |
185 | +;# jcode::to($ocode, $line [, $icode [, $option]]) | |
186 | +;# jcode::jis($line [, $icode [, $option]]) | |
187 | +;# jcode::euc($line [, $icode [, $option]]) | |
188 | +;# jcode::sjis($line [, $icode [, $option]]) | |
189 | +;# jcode::jis_inout($in, $out) | |
190 | +;# jcode::get_inout($string) | |
191 | +;# jcode::cache() | |
192 | +;# jcode::nocache() | |
193 | +;# jcode::flush() | |
194 | +;# jcode::h2z_xxx(\$line) | |
195 | +;# jcode::z2h_xxx(\$line) | |
196 | +;# &{$jcode::z2hf{'xxx'}}(\$line) | |
197 | +;# &{$jcode::h2zf{'xxx'}}(\$line) | |
198 | +;# jcode::tr(\$line, $from, $to [, $option]) | |
199 | +;# jcode::trans($line, $from, $to [, $option) | |
200 | +;# jcode::init() | |
201 | +;# | |
202 | +;###################################################################### | |
203 | +;# | |
204 | +;# SAMPLES | |
205 | +;# | |
206 | +;# Convert any Kanji code to JIS and print each line with code name. | |
207 | +;# | |
208 | +;# while (defined($s = <>)) { | |
209 | +;# $code = &jcode'convert(*s, 'jis'); | |
210 | +;# print $code, "\t", $s; | |
211 | +;# } | |
212 | +;# | |
213 | +;# Convert all lines to JIS according to the first recognized line. | |
214 | +;# | |
215 | +;# while (defined($s = <>)) { | |
216 | +;# print, next unless $s =~ /[\033\200-\377]/; | |
217 | +;# (*f, $icode) = &jcode'convert(*s, 'jis'); | |
218 | +;# print; | |
219 | +;# defined(&f) || next; | |
220 | +;# while (<>) { &f(*s); print; } | |
221 | +;# last; | |
222 | +;# } | |
223 | +;# | |
224 | +;# The safest way of JIS conversion. | |
225 | +;# | |
226 | +;# while (defined($s = <>)) { | |
227 | +;# ($matched, $icode) = &jcode'getcode(*s); | |
228 | +;# if (@buf == 0 && $matched == 0) { | |
229 | +;# print $s; | |
230 | +;# next; | |
231 | +;# } | |
232 | +;# push(@buf, $s); | |
233 | +;# next unless $icode; | |
234 | +;# while (defined($s = shift(@buf))) { | |
235 | +;# &jcode'convert(*s, 'jis', $icode); | |
236 | +;# print $s; | |
237 | +;# } | |
238 | +;# while (defined($s = <>)) { | |
239 | +;# &jcode'convert(*s, 'jis', $icode); | |
240 | +;# print $s; | |
241 | +;# } | |
242 | +;# last; | |
243 | +;# } | |
244 | +;# print @buf if @buf; | |
245 | +;# | |
246 | +;###################################################################### | |
247 | + | |
248 | +;# | |
249 | +;# Call initialize function if it is not called yet. This may sound | |
250 | +;# strange but it makes easy to embed the jcode.pl at the end of | |
251 | +;# script. Call &jcode'init at the beginning of the script in that | |
252 | +;# case. | |
253 | +;# | |
254 | +&init unless defined $version; | |
255 | + | |
256 | +;# | |
257 | +;# Initialize variables. | |
258 | +;# | |
259 | +sub init { | |
260 | + $version = $rcsid =~ /,v ([\d.]+)/ ? $1 : 'unknown'; | |
261 | + | |
262 | + $re_bin = '[\000-\006\177\377]'; | |
263 | + | |
264 | + $re_jis0208_1978 = '\e\$\@'; | |
265 | + $re_jis0208_1983 = '\e\$B'; | |
266 | + $re_jis0208_1990 = '\e&\@\e\$B'; | |
267 | + $re_jis0208 = "$re_jis0208_1978|$re_jis0208_1983|$re_jis0208_1990"; | |
268 | + $re_jis0212 = '\e\$\(D'; | |
269 | + $re_jp = "$re_jis0208|$re_jis0212"; | |
270 | + $re_asc = '\e\([BJ]'; | |
271 | + $re_kana = '\e\(I'; | |
272 | + | |
273 | + $esc_0208 = "\e\$B"; | |
274 | + $esc_0212 = "\e\$(D"; | |
275 | + $esc_asc = "\e(B"; | |
276 | + $esc_kana = "\e(I"; | |
277 | + | |
278 | + $re_sjis_c = '[\201-\237\340-\374][\100-\176\200-\374]'; | |
279 | + $re_sjis_kana = '[\241-\337]'; | |
280 | + | |
281 | + $re_euc_c = '[\241-\376][\241-\376]'; | |
282 | + $re_euc_kana = '\216[\241-\337]'; | |
283 | + $re_euc_0212 = '\217[\241-\376][\241-\376]'; | |
284 | + | |
285 | + # Use `geta' for undefined character code | |
286 | + $undef_sjis = "\x81\xac"; | |
287 | + | |
288 | + $cache = 1; | |
289 | + | |
290 | + # X0201 -> X0208 KANA conversion table. Looks weird? Not that | |
291 | + # much. This is simply JIS text without escape sequences. | |
292 | + ($h2z_high = $h2z = <<'__TABLE_END__') =~ tr/\041-\176/\241-\376/; | |
293 | +! !# $ !" % !& " !V # !W | |
294 | +^ !+ _ !, 0 !< | |
295 | +' %! ( %# ) %% * %' + %) | |
296 | +, %c - %e . %g / %C | |
297 | +1 %" 2 %$ 3 %& 4 %( 5 %* | |
298 | +6 %+ 7 %- 8 %/ 9 %1 : %3 | |
299 | +6^ %, 7^ %. 8^ %0 9^ %2 :^ %4 | |
300 | +; %5 < %7 = %9 > %; ? %= | |
301 | +;^ %6 <^ %8 =^ %: >^ %< ?^ %> | |
302 | +@ %? A %A B %D C %F D %H | |
303 | +@^ %@ A^ %B B^ %E C^ %G D^ %I | |
304 | +E %J F %K G %L H %M I %N | |
305 | +J %O K %R L %U M %X N %[ | |
306 | +J^ %P K^ %S L^ %V M^ %Y N^ %\ | |
307 | +J_ %Q K_ %T L_ %W M_ %Z N_ %] | |
308 | +O %^ P %_ Q %` R %a S %b | |
309 | +T %d U %f V %h | |
310 | +W %i X %j Y %k Z %l [ %m | |
311 | +\ %o ] %s & %r 3^ %t | |
312 | +__TABLE_END__ | |
313 | + %h2z = split(/\s+/, $h2z . $h2z_high); | |
314 | + %z2h = reverse %h2z; | |
315 | + | |
316 | + $convf{'jis' , 'jis' } = *jis2jis; | |
317 | + $convf{'jis' , 'sjis'} = *jis2sjis; | |
318 | + $convf{'jis' , 'euc' } = *jis2euc; | |
319 | + $convf{'euc' , 'jis' } = *euc2jis; | |
320 | + $convf{'euc' , 'sjis'} = *euc2sjis; | |
321 | + $convf{'euc' , 'euc' } = *euc2euc; | |
322 | + $convf{'sjis' , 'jis' } = *sjis2jis; | |
323 | + $convf{'sjis' , 'sjis'} = *sjis2sjis; | |
324 | + $convf{'sjis' , 'euc' } = *sjis2euc; | |
325 | + $h2zf{'jis' } = *h2z_jis; | |
326 | + $z2hf{'jis' } = *z2h_jis; | |
327 | + $h2zf{'euc' } = *h2z_euc; | |
328 | + $z2hf{'euc' } = *z2h_euc; | |
329 | + $h2zf{'sjis'} = *h2z_sjis; | |
330 | + $z2hf{'sjis'} = *z2h_sjis; | |
331 | +} | |
332 | + | |
333 | +;# | |
334 | +;# Set escape sequences which should be put before and after Japanese | |
335 | +;# (JIS X0208) string. | |
336 | +;# | |
337 | +sub jis_inout { | |
338 | + $esc_0208 = shift || $esc_0208; | |
339 | + $esc_0208 = "\e\$$esc_0208" if length($esc_0208) == 1; | |
340 | + $esc_asc = shift || $esc_asc; | |
341 | + $esc_asc = "\e\($esc_asc" if length($esc_asc) == 1; | |
342 | + ($esc_0208, $esc_asc); | |
343 | +} | |
344 | + | |
345 | +;# | |
346 | +;# Get JIS in and out sequences from the string. | |
347 | +;# | |
348 | +sub get_inout { | |
349 | + local($esc_0208, $esc_asc); | |
350 | + $_[$[] =~ /($re_jis0208)/o && ($esc_0208 = $1); | |
351 | + $_[$[] =~ /($re_asc)/o && ($esc_asc = $1); | |
352 | + ($esc_0208, $esc_asc); | |
353 | +} | |
354 | + | |
355 | +;# | |
356 | +;# Recognize character code. | |
357 | +;# | |
358 | +sub getcode { | |
359 | + local(*s) = @_; | |
360 | + local($matched, $code); | |
361 | + | |
362 | + if ($s !~ /[\e\200-\377]/) { # not Japanese | |
363 | + $matched = 0; | |
364 | + $code = undef; | |
365 | + } # 'jis' | |
366 | + elsif ($s =~ /$re_jp|$re_asc|$re_kana/o) { | |
367 | + $matched = 1; | |
368 | + $code = 'jis'; | |
369 | + } | |
370 | + elsif ($s =~ /$re_bin/o) { # 'binary' | |
371 | + $matched = 0; | |
372 | + $code = 'binary'; | |
373 | + } | |
374 | + else { # should be 'euc' or 'sjis' | |
375 | + local($sjis, $euc) = (0, 0); | |
376 | + | |
377 | + while ($s =~ /(($re_sjis_c)+)/go) { | |
378 | + $sjis += length($1); | |
379 | + } | |
380 | + while ($s =~ /(($re_euc_c|$re_euc_kana|$re_euc_0212)+)/go) { | |
381 | + $euc += length($1); | |
382 | + } | |
383 | + $matched = &max($sjis, $euc); | |
384 | + $code = ('euc', undef, 'sjis')[($sjis<=>$euc) + $[ + 1]; | |
385 | + } | |
386 | + wantarray ? ($matched, $code) : $code; | |
387 | +} | |
388 | +sub max { $_[ $[ + ($_[ $[ ] < $_[ $[ + 1 ]) ]; } | |
389 | + | |
390 | +;# | |
391 | +;# Convert any code to specified code. | |
392 | +;# | |
393 | +sub convert { | |
394 | + local(*s, $ocode, $icode, $opt) = @_; | |
395 | + return (undef, undef) unless $icode = $icode || &getcode(*s); | |
396 | + return (undef, $icode) if $icode eq 'binary'; | |
397 | + $ocode = 'jis' unless $ocode; | |
398 | + $ocode = $icode if $ocode eq 'noconv'; | |
399 | + local(*f) = $convf{$icode, $ocode}; | |
400 | + &f(*s, $opt); | |
401 | + wantarray ? (*f, $icode) : $icode; | |
402 | +} | |
403 | + | |
404 | +;# | |
405 | +;# Easy return-by-value interfaces. | |
406 | +;# | |
407 | +sub jis { &to('jis', @_); } | |
408 | +sub euc { &to('euc', @_); } | |
409 | +sub sjis { &to('sjis', @_); } | |
410 | +sub to { | |
411 | + local($ocode, $s, $icode, $opt) = @_; | |
412 | + &convert(*s, $ocode, $icode, $opt); | |
413 | + $s; | |
414 | +} | |
415 | +sub what { | |
416 | + local($s) = @_; | |
417 | + &getcode(*s); | |
418 | +} | |
419 | +sub trans { | |
420 | + local($s) = shift; | |
421 | + &tr(*s, @_); | |
422 | + $s; | |
423 | +} | |
424 | + | |
425 | +;# | |
426 | +;# SJIS to JIS | |
427 | +;# | |
428 | +sub sjis2jis { | |
429 | + local(*s, $opt, $n) = @_; | |
430 | + &sjis2sjis(*s, $opt) if $opt; | |
431 | + $s =~ s/(($re_sjis_c|$re_sjis_kana)+)/&_sjis2jis($1) . $esc_asc/geo; | |
432 | + $n; | |
433 | +} | |
434 | +sub _sjis2jis { | |
435 | + local($s) = shift; | |
436 | + $s =~ s/(($re_sjis_c)+|($re_sjis_kana)+)/&__sjis2jis($1)/geo; | |
437 | + $s; | |
438 | +} | |
439 | +sub __sjis2jis { | |
440 | + local($s) = shift; | |
441 | + if ($s =~ /^$re_sjis_kana/o) { | |
442 | + $n += $s =~ tr/\241-\337/\041-\137/; | |
443 | + $esc_kana . $s; | |
444 | + } else { | |
445 | + $n += $s =~ s/($re_sjis_c)/$s2e{$1}||&s2e($1)/geo; | |
446 | + $s =~ tr/\241-\376/\041-\176/; | |
447 | + $esc_0208 . $s; | |
448 | + } | |
449 | +} | |
450 | + | |
451 | +;# | |
452 | +;# EUC to JIS | |
453 | +;# | |
454 | +sub euc2jis { | |
455 | + local(*s, $opt, $n) = @_; | |
456 | + &euc2euc(*s, $opt) if $opt; | |
457 | + $s =~ s/(($re_euc_c|$re_euc_kana|$re_euc_0212)+)/ | |
458 | + &_euc2jis($1) . $esc_asc | |
459 | + /geo; | |
460 | + $n; | |
461 | +} | |
462 | +sub _euc2jis { | |
463 | + local($s) = shift; | |
464 | + $s =~ s/(($re_euc_c)+|($re_euc_kana)+|($re_euc_0212)+)/&__euc2jis($1)/geo; | |
465 | + $s; | |
466 | +} | |
467 | +sub __euc2jis { | |
468 | + local($s) = shift; | |
469 | + local($esc); | |
470 | + | |
471 | + if ($s =~ tr/\216//d) { | |
472 | + $esc = $esc_kana; | |
473 | + } elsif ($s =~ tr/\217//d) { | |
474 | + $esc = $esc_0212; | |
475 | + } else { | |
476 | + $esc = $esc_0208; | |
477 | + } | |
478 | + | |
479 | + $n += $s =~ tr/\241-\376/\041-\176/; | |
480 | + $esc . $s; | |
481 | +} | |
482 | + | |
483 | +;# | |
484 | +;# JIS to EUC | |
485 | +;# | |
486 | +sub jis2euc { | |
487 | + local(*s, $opt, $n) = @_; | |
488 | + $s =~ s/($re_jp|$re_asc|$re_kana)([^\e]*)/&_jis2euc($1,$2)/geo; | |
489 | + &euc2euc(*s, $opt) if $opt; | |
490 | + $n; | |
491 | +} | |
492 | +sub _jis2euc { | |
493 | + local($esc, $s) = @_; | |
494 | + if ($esc !~ /^$re_asc/o) { | |
495 | + $n += $s =~ tr/\041-\176/\241-\376/; | |
496 | + if ($esc =~ /^$re_kana/o) { | |
497 | + $s =~ s/([\241-\337])/\216$1/g; | |
498 | + } | |
499 | + elsif ($esc =~ /^$re_jis0212/o) { | |
500 | + $s =~ s/([\241-\376][\241-\376])/\217$1/g; | |
501 | + } | |
502 | + } | |
503 | + $s; | |
504 | +} | |
505 | + | |
506 | +;# | |
507 | +;# JIS to SJIS | |
508 | +;# | |
509 | +sub jis2sjis { | |
510 | + local(*s, $opt, $n) = @_; | |
511 | + &jis2jis(*s, $opt) if $opt; | |
512 | + $s =~ s/($re_jp|$re_asc|$re_kana)([^\e]*)/&_jis2sjis($1,$2)/geo; | |
513 | + $n; | |
514 | +} | |
515 | +sub _jis2sjis { | |
516 | + local($esc, $s) = @_; | |
517 | + if ($esc =~ /^$re_jis0212/o) { | |
518 | + $s =~ s/../$undef_sjis/g; | |
519 | + $n = length; | |
520 | + } | |
521 | + elsif ($esc !~ /^$re_asc/o) { | |
522 | + $n += $s =~ tr/\041-\176/\241-\376/; | |
523 | + if ($esc =~ /^$re_jp/o) { | |
524 | + $s =~ s/($re_euc_c)/$e2s{$1}||&e2s($1)/geo; | |
525 | + } | |
526 | + } | |
527 | + $s; | |
528 | +} | |
529 | + | |
530 | +;# | |
531 | +;# SJIS to EUC | |
532 | +;# | |
533 | +sub sjis2euc { | |
534 | + local(*s, $opt,$n) = @_; | |
535 | + $n = $s =~ s/($re_sjis_c|$re_sjis_kana)/$s2e{$1}||&s2e($1)/geo; | |
536 | + &euc2euc(*s, $opt) if $opt; | |
537 | + $n; | |
538 | +} | |
539 | +sub s2e { | |
540 | + local($c1, $c2, $code); | |
541 | + ($c1, $c2) = unpack('CC', $code = shift); | |
542 | + | |
543 | + if (0xa1 <= $c1 && $c1 <= 0xdf) { | |
544 | + $c2 = $c1; | |
545 | + $c1 = 0x8e; | |
546 | + } elsif (0x9f <= $c2) { | |
547 | + $c1 = $c1 * 2 - ($c1 >= 0xe0 ? 0xe0 : 0x60); | |
548 | + $c2 += 2; | |
549 | + } else { | |
550 | + $c1 = $c1 * 2 - ($c1 >= 0xe0 ? 0xe1 : 0x61); | |
551 | + $c2 += 0x60 + ($c2 < 0x7f); | |
552 | + } | |
553 | + if ($cache) { | |
554 | + $s2e{$code} = pack('CC', $c1, $c2); | |
555 | + } else { | |
556 | + pack('CC', $c1, $c2); | |
557 | + } | |
558 | +} | |
559 | + | |
560 | +;# | |
561 | +;# EUC to SJIS | |
562 | +;# | |
563 | +sub euc2sjis { | |
564 | + local(*s, $opt,$n) = @_; | |
565 | + &euc2euc(*s, $opt) if $opt; | |
566 | + $n = $s =~ s/($re_euc_c|$re_euc_kana|$re_euc_0212)/$e2s{$1}||&e2s($1)/geo; | |
567 | +} | |
568 | +sub e2s { | |
569 | + local($c1, $c2, $code); | |
570 | + ($c1, $c2) = unpack('CC', $code = shift); | |
571 | + | |
572 | + if ($c1 == 0x8e) { # SS2 | |
573 | + return substr($code, 1, 1); | |
574 | + } elsif ($c1 == 0x8f) { # SS3 | |
575 | + return $undef_sjis; | |
576 | + } elsif ($c1 % 2) { | |
577 | + $c1 = ($c1>>1) + ($c1 < 0xdf ? 0x31 : 0x71); | |
578 | + $c2 -= 0x60 + ($c2 < 0xe0); | |
579 | + } else { | |
580 | + $c1 = ($c1>>1) + ($c1 < 0xdf ? 0x30 : 0x70); | |
581 | + $c2 -= 2; | |
582 | + } | |
583 | + if ($cache) { | |
584 | + $e2s{$code} = pack('CC', $c1, $c2); | |
585 | + } else { | |
586 | + pack('CC', $c1, $c2); | |
587 | + } | |
588 | +} | |
589 | + | |
590 | +;# | |
591 | +;# JIS to JIS, SJIS to SJIS, EUC to EUC | |
592 | +;# | |
593 | +sub jis2jis { | |
594 | + local(*s, $opt) = @_; | |
595 | + $s =~ s/$re_jis0208/$esc_0208/go; | |
596 | + $s =~ s/$re_asc/$esc_asc/go; | |
597 | + &h2z_jis(*s) if $opt =~ /z/; | |
598 | + &z2h_jis(*s) if $opt =~ /h/; | |
599 | +} | |
600 | +sub sjis2sjis { | |
601 | + local(*s, $opt) = @_; | |
602 | + &h2z_sjis(*s) if $opt =~ /z/; | |
603 | + &z2h_sjis(*s) if $opt =~ /h/; | |
604 | +} | |
605 | +sub euc2euc { | |
606 | + local(*s, $opt) = @_; | |
607 | + &h2z_euc(*s) if $opt =~ /z/; | |
608 | + &z2h_euc(*s) if $opt =~ /h/; | |
609 | +} | |
610 | + | |
611 | +;# | |
612 | +;# Cache control functions | |
613 | +;# | |
614 | +sub cache { | |
615 | + ($cache, $cache = 1)[$[]; | |
616 | +} | |
617 | +sub nocache { | |
618 | + ($cache, $cache = 0)[$[]; | |
619 | +} | |
620 | +sub flushcache { | |
621 | + undef %e2s; | |
622 | + undef %s2e; | |
623 | +} | |
624 | + | |
625 | +;# | |
626 | +;# X0201 -> X0208 KANA conversion routine | |
627 | +;# | |
628 | +sub h2z_jis { | |
629 | + local(*s, $n) = @_; | |
630 | + if ($s =~ s/$re_kana([^\e]*)/$esc_0208 . &_h2z_jis($1)/geo) { | |
631 | + 1 while $s =~ s/(($re_jis0208)[^\e]*)($re_jis0208)/$1/o; | |
632 | + } | |
633 | + $n; | |
634 | +} | |
635 | +sub _h2z_jis { | |
636 | + local($s) = @_; | |
637 | + $n += $s =~ s/(([\041-\137])([\136\137])?)/ | |
638 | + $h2z{$1} || $h2z{$2} . $h2z{$3} | |
639 | + /ge; | |
640 | + $s; | |
641 | +} | |
642 | + | |
643 | +sub h2z_euc { | |
644 | + local(*s) = @_; | |
645 | + $s =~ s/\216([\241-\337])(\216([\336\337]))?/ | |
646 | + $h2z{"$1$3"} || $h2z{$1} . $h2z{$3} | |
647 | + /ge; | |
648 | +} | |
649 | + | |
650 | +sub h2z_sjis { | |
651 | + local(*s, $n) = @_; | |
652 | + $s =~ s/(($re_sjis_c)+)|(([\241-\337])([\336\337])?)/ | |
653 | + $1 || ($n++, $h2z{$3} ? $e2s{$h2z{$3}} || &e2s($h2z{$3}) | |
654 | + : &e2s($h2z{$4}) . ($5 && &e2s($h2z{$5}))) | |
655 | + /geo; | |
656 | + $n; | |
657 | +} | |
658 | + | |
659 | +;# | |
660 | +;# X0208 -> X0201 KANA conversion routine | |
661 | +;# | |
662 | +sub z2h_jis { | |
663 | + local(*s, $n) = @_; | |
664 | + $s =~ s/($re_jis0208)([^\e]+)/&_z2h_jis($2)/geo; | |
665 | + $n; | |
666 | +} | |
667 | +sub _z2h_jis { | |
668 | + local($s) = @_; | |
669 | + $s =~ s/((\%[!-~]|![\#\"&VW+,<])+|([^!%][!-~]|![^\#\"&VW+,<])+)/ | |
670 | + &__z2h_jis($1) | |
671 | + /ge; | |
672 | + $s; | |
673 | +} | |
674 | +sub __z2h_jis { | |
675 | + local($s) = @_; | |
676 | + return $esc_0208 . $s unless $s =~ /^%/ || $s =~ /^![\#\"&VW+,<]/; | |
677 | + $n += length($s) / 2; | |
678 | + $s =~ s/(..)/$z2h{$1}/g; | |
679 | + $esc_kana . $s; | |
680 | +} | |
681 | + | |
682 | +sub z2h_euc { | |
683 | + local(*s, $n) = @_; | |
684 | + &init_z2h_euc if !%z2h_euc; | |
685 | + $s =~ s/($re_euc_c|$re_euc_kana)/ | |
686 | + $z2h_euc{$1} ? ($n++, $z2h_euc{$1}) : $1 | |
687 | + /geo; | |
688 | + $n; | |
689 | +} | |
690 | + | |
691 | +sub z2h_sjis { | |
692 | + local(*s, $n) = @_; | |
693 | + &init_z2h_sjis if !%z2h_sjis; | |
694 | + $s =~ s/($re_sjis_c)/$z2h_sjis{$1} ? ($n++, $z2h_sjis{$1}) : $1/geo; | |
695 | + $n; | |
696 | +} | |
697 | + | |
698 | +;# | |
699 | +;# Initializing JIS X0208 to X0201 KANA table for EUC and SJIS. This | |
700 | +;# can be done in &init but it's not worth doing. Similarly, | |
701 | +;# precalculated table is not worth to occupy the file space and | |
702 | +;# reduce the readability. The author personnaly discourages to use | |
703 | +;# X0201 Kana character in the any situation. | |
704 | +;# | |
705 | +sub init_z2h_euc { | |
706 | + local($k, $s); | |
707 | + while (($k, $s) = each %z2h) { | |
708 | + $s =~ s/([\241-\337])/\216$1/g && ($z2h_euc{$k} = $s); | |
709 | + } | |
710 | +} | |
711 | +sub init_z2h_sjis { | |
712 | + local($s, $v); | |
713 | + while (($s, $v) = each %z2h) { | |
714 | + $s =~ /[\200-\377]/ && ($z2h_sjis{&e2s($s)} = $v); | |
715 | + } | |
716 | +} | |
717 | + | |
718 | +;# | |
719 | +;# TR function for 2-byte code | |
720 | +;# | |
721 | +sub tr { | |
722 | + # $prev_from, $prev_to, %table are persistent variables | |
723 | + local(*s, $from, $to, $opt) = @_; | |
724 | + local(@from, @to); | |
725 | + local($jis, $n) = (0, 0); | |
726 | + | |
727 | + $jis++, &jis2euc(*s) if $s =~ /$re_jp|$re_asc|$re_kana/o; | |
728 | + $jis++ if $to =~ /$re_jp|$re_asc|$re_kana/o; | |
729 | + | |
730 | + if (!defined($prev_from) || $from ne $prev_from || $to ne $prev_to) { | |
731 | + ($prev_from, $prev_to) = ($from, $to); | |
732 | + undef %table; | |
733 | + &_maketable; | |
734 | + } | |
735 | + | |
736 | + $s =~ s/([\200-\377][\000-\377]|[\000-\377])/ | |
737 | + defined($table{$1}) && ++$n ? $table{$1} : $1 | |
738 | + /ge; | |
739 | + | |
740 | + &euc2jis(*s) if $jis; | |
741 | + | |
742 | + $n; | |
743 | +} | |
744 | + | |
745 | +sub _maketable { | |
746 | + local($ascii) = '(\\\\[\\-\\\\]|[\0-\133\135-\177])'; | |
747 | + | |
748 | + &jis2euc(*to) if $to =~ /$re_jp|$re_asc|$re_kana/o; | |
749 | + &jis2euc(*from) if $from =~ /$re_jp|$re_asc|$re_kana/o; | |
750 | + | |
751 | + grep(s/(([\200-\377])[\200-\377]-\2[\200-\377])/&_expnd2($1)/ge, | |
752 | + $from, $to); | |
753 | + grep(s/($ascii-$ascii)/&_expnd1($1)/geo, | |
754 | + $from, $to); | |
755 | + | |
756 | + @to = $to =~ /[\200-\377][\000-\377]|[\000-\377]/g; | |
757 | + @from = $from =~ /[\200-\377][\000-\377]|[\000-\377]/g; | |
758 | + push(@to, ($opt =~ /d/ ? '' : $to[$#to]) x (@from - @to)) if @to < @from; | |
759 | + @table{@from} = @to; | |
760 | +} | |
761 | + | |
762 | +sub _expnd1 { | |
763 | + local($s) = @_; | |
764 | + $s =~ s/\\(.)/$1/g; | |
765 | + local($c1, $c2) = unpack('CxC', $s); | |
766 | + if ($c1 <= $c2) { | |
767 | + for ($s = ''; $c1 <= $c2; $c1++) { | |
768 | + $s .= pack('C', $c1); | |
769 | + } | |
770 | + } | |
771 | + $s; | |
772 | +} | |
773 | + | |
774 | +sub _expnd2 { | |
775 | + local($s) = @_; | |
776 | + local($c1, $c2, $c3, $c4) = unpack('CCxCC', $s); | |
777 | + if ($c1 == $c3 && $c2 <= $c4) { | |
778 | + for ($s = ''; $c2 <= $c4; $c2++) { | |
779 | + $s .= pack('CC', $c1, $c2); | |
780 | + } | |
781 | + } | |
782 | + $s; | |
783 | +} | |
784 | + | |
785 | +1; |
@@ -0,0 +1,456 @@ | ||
1 | +# Perl Routines to Manipulate CGI input | |
2 | +# S.E.Brenner@bioc.cam.ac.uk | |
3 | +# $Id: cgi-lib.pl,v 1.2 2004/05/24 14:35:08 takezoe Exp $ | |
4 | +# | |
5 | +# Copyright (c) 1996 Steven E. Brenner | |
6 | +# Unpublished work. | |
7 | +# Permission granted to use and modify this library so long as the | |
8 | +# copyright above is maintained, modifications are documented, and | |
9 | +# credit is given for any use of the library. | |
10 | +# | |
11 | +# Thanks are due to many people for reporting bugs and suggestions | |
12 | +# especially Meng Weng Wong, Maki Watanabe, Bo Frese Rasmussen, | |
13 | +# Andrew Dalke, Mark-Jason Dominus, Dave Dittrich, Jason Mathews | |
14 | + | |
15 | +# For more information, see: | |
16 | +# http://www.bio.cam.ac.uk/cgi-lib/ | |
17 | + | |
18 | +$cgi_lib'version = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/); | |
19 | + | |
20 | + | |
21 | +# Parameters affecting cgi-lib behavior | |
22 | +# User-configurable parameters affecting file upload. | |
23 | +$cgi_lib'maxdata = 131072; # maximum bytes to accept via POST - 2^17 | |
24 | +$cgi_lib'writefiles = 0; # directory to which to write files, or | |
25 | + # 0 if files should not be written | |
26 | +$cgi_lib'filepre = "cgi-lib"; # Prefix of file names, in directory above | |
27 | + | |
28 | +# Do not change the following parameters unless you have special reasons | |
29 | +$cgi_lib'bufsize = 8192; # default buffer size when reading multipart | |
30 | +$cgi_lib'maxbound = 100; # maximum boundary length to be encounterd | |
31 | +$cgi_lib'headerout = 0; # indicates whether the header has been printed | |
32 | + | |
33 | + | |
34 | +# ReadParse | |
35 | +# Reads in GET or POST data, converts it to unescaped text, and puts | |
36 | +# key/value pairs in %in, using "\0" to separate multiple selections | |
37 | + | |
38 | +# Returns >0 if there was input, 0 if there was no input | |
39 | +# undef indicates some failure. | |
40 | + | |
41 | +# Now that cgi scripts can be put in the normal file space, it is useful | |
42 | +# to combine both the form and the script in one place. If no parameters | |
43 | +# are given (i.e., ReadParse returns FALSE), then a form could be output. | |
44 | + | |
45 | +# If a reference to a hash is given, then the data will be stored in that | |
46 | +# hash, but the data from $in and @in will become inaccessable. | |
47 | +# If a variable-glob (e.g., *cgi_input) is the first parameter to ReadParse, | |
48 | +# information is stored there, rather than in $in, @in, and %in. | |
49 | +# Second, third, and fourth parameters fill associative arrays analagous to | |
50 | +# %in with data relevant to file uploads. | |
51 | + | |
52 | +# If no method is given, the script will process both command-line arguments | |
53 | +# of the form: name=value and any text that is in $ENV{'QUERY_STRING'} | |
54 | +# This is intended to aid debugging and may be changed in future releases | |
55 | + | |
56 | +sub ReadParse { | |
57 | + local (*in) = shift if @_; # CGI input | |
58 | + local (*incfn, # Client's filename (may not be provided) | |
59 | + *inct, # Client's content-type (may not be provided) | |
60 | + *insfn) = @_; # Server's filename (for spooled files) | |
61 | + local ($len, $type, $meth, $errflag, $cmdflag, $perlwarn, $got); | |
62 | + | |
63 | + # Disable warnings as this code deliberately uses local and environment | |
64 | + # variables which are preset to undef (i.e., not explicitly initialized) | |
65 | + $perlwarn = $^W; | |
66 | + $^W = 0; | |
67 | + | |
68 | + binmode(STDIN); # we need these for DOS-based systems | |
69 | + binmode(STDOUT); # and they shouldn't hurt anything else | |
70 | + binmode(STDERR); | |
71 | + | |
72 | + # Get several useful env variables | |
73 | + $type = $ENV{'CONTENT_TYPE'}; | |
74 | + $len = $ENV{'CONTENT_LENGTH'}; | |
75 | + $meth = $ENV{'REQUEST_METHOD'}; | |
76 | + | |
77 | + if ($len > $cgi_lib'maxdata) { #' | |
78 | + &CgiDie("cgi-lib.pl: Request to receive too much data: $len bytes\n"); | |
79 | + } | |
80 | + | |
81 | + if (!defined $meth || $meth eq '' || $meth eq 'GET' || $meth eq 'HEAD' || | |
82 | + $type eq 'application/x-www-form-urlencoded') { | |
83 | + local ($key, $val, $i); | |
84 | + | |
85 | + # Read in text | |
86 | + if (!defined $meth || $meth eq '') { | |
87 | + $in = $ENV{'QUERY_STRING'}; | |
88 | + $cmdflag = 1; # also use command-line options | |
89 | + } elsif($meth eq 'GET' || $meth eq 'HEAD') { | |
90 | + $in = $ENV{'QUERY_STRING'}; | |
91 | + } elsif ($meth eq 'POST') { | |
92 | + if (($got = read(STDIN, $in, $len) != $len)) | |
93 | + {$errflag="Short Read: wanted $len, got $got\n";}; | |
94 | + } else { | |
95 | + &CgiDie("cgi-lib.pl: Unknown request method: $meth\n"); | |
96 | + } | |
97 | + | |
98 | + @in = split(/[&;]/,$in); | |
99 | + push(@in, @ARGV) if $cmdflag; # add command-line parameters | |
100 | + | |
101 | + foreach $i (0 .. $#in) { | |
102 | + # Convert plus to space | |
103 | + $in[$i] =~ s/\+/ /g; | |
104 | + | |
105 | + # Split into key and value. | |
106 | + ($key, $val) = split(/=/,$in[$i],2); # splits on the first =. | |
107 | + | |
108 | + # Convert %XX from hex numbers to alphanumeric | |
109 | + $key =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; | |
110 | + $val =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge; | |
111 | + | |
112 | + # Associate key and value | |
113 | + $in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator | |
114 | + $in{$key} .= $val; | |
115 | + } | |
116 | + | |
117 | + } elsif ($ENV{'CONTENT_TYPE'} =~ m#^multipart/form-data#) { | |
118 | + # for efficiency, compile multipart code only if needed | |
119 | +$errflag = !(eval <<'END_MULTIPART'); | |
120 | + | |
121 | + local ($buf, $boundary, $head, @heads, $cd, $ct, $fname, $ctype, $blen); | |
122 | + local ($bpos, $lpos, $left, $amt, $fn, $ser); | |
123 | + local ($bufsize, $maxbound, $writefiles) = | |
124 | + ($cgi_lib'bufsize, $cgi_lib'maxbound, $cgi_lib'writefiles); | |
125 | + | |
126 | + | |
127 | + # The following lines exist solely to eliminate spurious warning messages | |
128 | + $buf = ''; | |
129 | + | |
130 | + ($boundary) = $type =~ /boundary="([^"]+)"/; #"; # find boundary | |
131 | + ($boundary) = $type =~ /boundary=(\S+)/ unless $boundary; | |
132 | + &CgiDie ("Boundary not provided: probably a bug in your server") | |
133 | + unless $boundary; | |
134 | + $boundary = "--" . $boundary; | |
135 | + $blen = length ($boundary); | |
136 | + | |
137 | + if ($ENV{'REQUEST_METHOD'} ne 'POST') { | |
138 | + &CgiDie("Invalid request method for multipart/form-data: $meth\n"); | |
139 | + } | |
140 | + | |
141 | + if ($writefiles) { | |
142 | + local($me); | |
143 | + stat ($writefiles); | |
144 | + $writefiles = "/tmp" unless -d _ && -r _ && -w _; | |
145 | + # ($me) = $0 =~ m#([^/]*)$#; | |
146 | + $writefiles .= "/$cgi_lib'filepre"; | |
147 | + } | |
148 | + | |
149 | + # read in the data and split into parts: | |
150 | + # put headers in @in and data in %in | |
151 | + # General algorithm: | |
152 | + # There are two dividers: the border and the '\r\n\r\n' between | |
153 | + # header and body. Iterate between searching for these | |
154 | + # Retain a buffer of size(bufsize+maxbound); the latter part is | |
155 | + # to ensure that dividers don't get lost by wrapping between two bufs | |
156 | + # Look for a divider in the current batch. If not found, then | |
157 | + # save all of bufsize, move the maxbound extra buffer to the front of | |
158 | + # the buffer, and read in a new bufsize bytes. If a divider is found, | |
159 | + # save everything up to the divider. Then empty the buffer of everything | |
160 | + # up to the end of the divider. Refill buffer to bufsize+maxbound | |
161 | + # Note slightly odd organization. Code before BODY: really goes with | |
162 | + # code following HEAD:, but is put first to 'pre-fill' buffers. BODY: | |
163 | + # is placed before HEAD: because we first need to discard any 'preface,' | |
164 | + # which would be analagous to a body without a preceeding head. | |
165 | + | |
166 | + $left = $len; | |
167 | + PART: # find each part of the multi-part while reading data | |
168 | + while (1) { | |
169 | + die $@ if $errflag; | |
170 | + | |
171 | + $amt = ($left > $bufsize+$maxbound-length($buf) | |
172 | + ? $bufsize+$maxbound-length($buf): $left); | |
173 | + $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); | |
174 | + die "Short Read: wanted $amt, got $got\n" if $errflag; | |
175 | + $left -= $amt; | |
176 | + | |
177 | + $in{$name} .= "\0" if defined $in{$name}; | |
178 | + $in{$name} .= $fn if $fn; | |
179 | + | |
180 | + $name=~/([-\w]+)/; # This allows $insfn{$name} to be untainted | |
181 | + if (defined $1) { | |
182 | + $insfn{$1} .= "\0" if defined $insfn{$1}; | |
183 | + $insfn{$1} .= $fn if $fn; | |
184 | + } | |
185 | + | |
186 | + BODY: | |
187 | + while (($bpos = index($buf, $boundary)) == -1) { | |
188 | + die $@ if $errflag; | |
189 | + if ($name) { # if no $name, then it's the prologue -- discard | |
190 | + if ($fn) { print FILE substr($buf, 0, $bufsize); } | |
191 | + else { $in{$name} .= substr($buf, 0, $bufsize); } | |
192 | + } | |
193 | + $buf = substr($buf, $bufsize); | |
194 | + $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==length($buf); | |
195 | + $errflag = (($got = read(STDIN, $buf, $amt, $maxbound)) != $amt); | |
196 | + die "Short Read: wanted $amt, got $got\n" if $errflag; | |
197 | + $left -= $amt; | |
198 | + } | |
199 | + if (defined $name) { # if no $name, then it's the prologue -- discard | |
200 | + if ($fn) { print FILE substr($buf, 0, $bpos-2); } | |
201 | + else { $in {$name} .= substr($buf, 0, $bpos-2); } # kill last \r\n | |
202 | + } | |
203 | + close (FILE); | |
204 | + last PART if substr($buf, $bpos + $blen, 4) eq "--\r\n"; | |
205 | + substr($buf, 0, $bpos+$blen+2) = ''; | |
206 | + $amt = ($left > $bufsize+$maxbound-length($buf) | |
207 | + ? $bufsize+$maxbound-length($buf) : $left); | |
208 | + $errflag = (($got = read(STDIN, $buf, $amt, length($buf))) != $amt); | |
209 | + die "Short Read: wanted $amt, got $got\n" if $errflag; | |
210 | + $left -= $amt; | |
211 | + | |
212 | + | |
213 | + undef $head; undef $fn; | |
214 | + HEAD: | |
215 | + while (($lpos = index($buf, "\r\n\r\n")) == -1) { | |
216 | + die $@ if $errflag; | |
217 | + $head .= substr($buf, 0, $bufsize); | |
218 | + $buf = substr($buf, $bufsize); | |
219 | + $amt = ($left > $bufsize ? $bufsize : $left); #$maxbound==length($buf); | |
220 | + $errflag = (($got = read(STDIN, $buf, $amt, $maxbound)) != $amt); | |
221 | + die "Short Read: wanted $amt, got $got\n" if $errflag; | |
222 | + $left -= $amt; | |
223 | + } | |
224 | + $head .= substr($buf, 0, $lpos+2); | |
225 | + push (@in, $head); | |
226 | + @heads = split("\r\n", $head); | |
227 | + ($cd) = grep (/^\s*Content-Disposition:/i, @heads); | |
228 | + ($ct) = grep (/^\s*Content-Type:/i, @heads); | |
229 | + | |
230 | + ($name) = $cd =~ /\bname="([^"]+)"/i; #"; | |
231 | + ($name) = $cd =~ /\bname=([^\s:;]+)/i unless defined $name; | |
232 | + | |
233 | + ($fname) = $cd =~ /\bfilename="([^"]*)"/i; #"; # filename can be null-str | |
234 | + ($fname) = $cd =~ /\bfilename=([^\s:;]+)/i unless defined $fname; | |
235 | + $incfn{$name} .= (defined $in{$name} ? "\0" : "") . | |
236 | + (defined $fname ? $fname : ""); | |
237 | + | |
238 | + ($ctype) = $ct =~ /^\s*Content-type:\s*"([^"]+)"/i; #"; | |
239 | + ($ctype) = $ct =~ /^\s*Content-Type:\s*([^\s:;]+)/i unless defined $ctype; | |
240 | + $inct{$name} .= (defined $in{$name} ? "\0" : "") . $ctype; | |
241 | + | |
242 | + if ($writefiles && defined $fname) { | |
243 | + $ser++; | |
244 | + $fn = $writefiles . ".$$.$ser"; | |
245 | + open (FILE, ">$fn") || &CgiDie("Couldn't open $fn\n"); | |
246 | + binmode (FILE); # write files accurately | |
247 | + } | |
248 | + substr($buf, 0, $lpos+4) = ''; | |
249 | + undef $fname; | |
250 | + undef $ctype; | |
251 | + } | |
252 | + | |
253 | +1; | |
254 | +END_MULTIPART | |
255 | + if ($errflag) { | |
256 | + local ($errmsg, $value); | |
257 | + $errmsg = $@ || $errflag; | |
258 | + foreach $value (values %insfn) { | |
259 | + unlink(split("\0",$value)); | |
260 | + } | |
261 | + &CgiDie($errmsg); | |
262 | + } else { | |
263 | + # everything's ok. | |
264 | + } | |
265 | + } else { | |
266 | + &CgiDie("cgi-lib.pl: Unknown Content-type: $ENV{'CONTENT_TYPE'}\n"); | |
267 | + } | |
268 | + | |
269 | + # no-ops to avoid warnings | |
270 | + $insfn = $insfn; | |
271 | + $incfn = $incfn; | |
272 | + $inct = $inct; | |
273 | + | |
274 | + $^W = $perlwarn; | |
275 | + | |
276 | + return ($errflag ? undef : scalar(@in)); | |
277 | +} | |
278 | + | |
279 | + | |
280 | +# PrintHeader | |
281 | +# Returns the magic line which tells WWW that we're an HTML document | |
282 | + | |
283 | +sub PrintHeader { | |
284 | + return "Content-type: text/html\n\n"; | |
285 | +} | |
286 | + | |
287 | + | |
288 | +# HtmlTop | |
289 | +# Returns the <head> of a document and the beginning of the body | |
290 | +# with the title and a body <h1> header as specified by the parameter | |
291 | + | |
292 | +sub HtmlTop | |
293 | +{ | |
294 | + local ($title) = @_; | |
295 | + | |
296 | + return <<END_OF_TEXT; | |
297 | +<html> | |
298 | +<head> | |
299 | +<title>$title</title> | |
300 | +</head> | |
301 | +<body> | |
302 | +<h1>$title</h1> | |
303 | +END_OF_TEXT | |
304 | +} | |
305 | + | |
306 | + | |
307 | +# HtmlBot | |
308 | +# Returns the </body>, </html> codes for the bottom of every HTML page | |
309 | + | |
310 | +sub HtmlBot | |
311 | +{ | |
312 | + return "</body>\n</html>\n"; | |
313 | +} | |
314 | + | |
315 | + | |
316 | +# SplitParam | |
317 | +# Splits a multi-valued parameter into a list of the constituent parameters | |
318 | + | |
319 | +sub SplitParam | |
320 | +{ | |
321 | + local ($param) = @_; | |
322 | + local (@params) = split ("\0", $param); | |
323 | + return (wantarray ? @params : $params[0]); | |
324 | +} | |
325 | + | |
326 | + | |
327 | +# MethGet | |
328 | +# Return true if this cgi call was using the GET request, false otherwise | |
329 | + | |
330 | +sub MethGet { | |
331 | + return (defined $ENV{'REQUEST_METHOD'} && $ENV{'REQUEST_METHOD'} eq "GET"); | |
332 | +} | |
333 | + | |
334 | + | |
335 | +# MethPost | |
336 | +# Return true if this cgi call was using the POST request, false otherwise | |
337 | + | |
338 | +sub MethPost { | |
339 | + return (defined $ENV{'REQUEST_METHOD'} && $ENV{'REQUEST_METHOD'} eq "POST"); | |
340 | +} | |
341 | + | |
342 | + | |
343 | +# MyBaseUrl | |
344 | +# Returns the base URL to the script (i.e., no extra path or query string) | |
345 | +sub MyBaseUrl { | |
346 | + local ($ret, $perlwarn); | |
347 | + $perlwarn = $^W; $^W = 0; | |
348 | + $ret = 'http://' . $ENV{'SERVER_NAME'} . | |
349 | + ($ENV{'SERVER_PORT'} != 80 ? ":$ENV{'SERVER_PORT'}" : '') . | |
350 | + $ENV{'SCRIPT_NAME'}; | |
351 | + $^W = $perlwarn; | |
352 | + return $ret; | |
353 | +} | |
354 | + | |
355 | + | |
356 | +# MyFullUrl | |
357 | +# Returns the full URL to the script (i.e., with extra path or query string) | |
358 | +sub MyFullUrl { | |
359 | + local ($ret, $perlwarn); | |
360 | + $perlwarn = $^W; $^W = 0; | |
361 | + $ret = 'http://' . $ENV{'SERVER_NAME'} . | |
362 | + ($ENV{'SERVER_PORT'} != 80 ? ":$ENV{'SERVER_PORT'}" : '') . | |
363 | + $ENV{'SCRIPT_NAME'} . $ENV{'PATH_INFO'} . | |
364 | + (length ($ENV{'QUERY_STRING'}) ? "?$ENV{'QUERY_STRING'}" : ''); | |
365 | + $^W = $perlwarn; | |
366 | + return $ret; | |
367 | +} | |
368 | + | |
369 | + | |
370 | +# MyURL | |
371 | +# Returns the base URL to the script (i.e., no extra path or query string) | |
372 | +# This is obsolete and will be removed in later versions | |
373 | +sub MyURL { | |
374 | + return &MyBaseUrl; | |
375 | +} | |
376 | + | |
377 | + | |
378 | +# CgiError | |
379 | +# Prints out an error message which which containes appropriate headers, | |
380 | +# markup, etcetera. | |
381 | +# Parameters: | |
382 | +# If no parameters, gives a generic error message | |
383 | +# Otherwise, the first parameter will be the title and the rest will | |
384 | +# be given as different paragraphs of the body | |
385 | + | |
386 | +sub CgiError { | |
387 | + local (@msg) = @_; | |
388 | + local ($i,$name); | |
389 | + | |
390 | + if (!@msg) { | |
391 | + $name = &MyFullUrl; | |
392 | + @msg = ("Error: script $name encountered fatal error\n"); | |
393 | + }; | |
394 | + | |
395 | + if (!$cgi_lib'headerout) { #') | |
396 | + print &PrintHeader; | |
397 | + print "<html>\n<head>\n<title>$msg[0]</title>\n</head>\n<body>\n"; | |
398 | + } | |
399 | + print "<h1>$msg[0]</h1>\n"; | |
400 | + foreach $i (1 .. $#msg) { | |
401 | + print "<p>$msg[$i]</p>\n"; | |
402 | + } | |
403 | + | |
404 | + $cgi_lib'headerout++; | |
405 | +} | |
406 | + | |
407 | + | |
408 | +# CgiDie | |
409 | +# Identical to CgiError, but also quits with the passed error message. | |
410 | + | |
411 | +sub CgiDie { | |
412 | + local (@msg) = @_; | |
413 | + &CgiError (@msg); | |
414 | + die @msg; | |
415 | +} | |
416 | + | |
417 | + | |
418 | +# PrintVariables | |
419 | +# Nicely formats variables. Three calling options: | |
420 | +# A non-null associative array - prints the items in that array | |
421 | +# A type-glob - prints the items in the associated assoc array | |
422 | +# nothing - defaults to use %in | |
423 | +# Typical use: &PrintVariables() | |
424 | + | |
425 | +sub PrintVariables { | |
426 | + local (*in) = @_ if @_ == 1; | |
427 | + local (%in) = @_ if @_ > 1; | |
428 | + local ($out, $key, $output); | |
429 | + | |
430 | + $output = "\n<dl compact>\n"; | |
431 | + foreach $key (sort keys(%in)) { | |
432 | + foreach (split("\0", $in{$key})) { | |
433 | + ($out = $_) =~ s/\n/<br>\n/g; | |
434 | + $output .= "<dt><b>$key</b>\n <dd>:<i>$out</i>:<br>\n"; | |
435 | + } | |
436 | + } | |
437 | + $output .= "</dl>\n"; | |
438 | + | |
439 | + return $output; | |
440 | +} | |
441 | + | |
442 | +# PrintEnv | |
443 | +# Nicely formats all environment variables and returns HTML string | |
444 | +sub PrintEnv { | |
445 | + &PrintVariables(*ENV); | |
446 | +} | |
447 | + | |
448 | + | |
449 | +# The following lines exist only to avoid warning messages | |
450 | +$cgi_lib'writefiles = $cgi_lib'writefiles; | |
451 | +$cgi_lib'bufsize = $cgi_lib'bufsize ; | |
452 | +$cgi_lib'maxbound = $cgi_lib'maxbound; | |
453 | +$cgi_lib'version = $cgi_lib'version; | |
454 | +$cgi_lib'filepre = $cgi_lib'filepre; | |
455 | + | |
456 | +1; #return true | |
\ No newline at end of file |
@@ -0,0 +1,322 @@ | ||
1 | +package MIME; | |
2 | +# Copyright (C) 1993-94,1997 Noboru Ikuta <noboru@ikuta.ichihara.chiba.jp> | |
3 | +# | |
4 | +# mimew.pl: MIME encoder library Ver.2.02 (1997/12/30) | |
5 | + | |
6 | +$main'mimew_version = "2.02"; | |
7 | + | |
8 | +# インストール : @INC のディレクトリ(通常は /usr/local/lib/perl)にコピー | |
9 | +# して下さい。 | |
10 | +# | |
11 | +# 使用例1 : require 'mimew.pl'; | |
12 | +# $from = "From: 生田 昇 <noboru\@ikuta.ichihara.chiba.jp>"; | |
13 | +# print &mimeencode($from); | |
14 | +# | |
15 | +# 使用例2 : # UNIXでBase64エンコードする場合 | |
16 | +# require 'mimew.pl'; | |
17 | +# undef $/; | |
18 | +# $body = <>; | |
19 | +# print &bodyencode($body); | |
20 | +# print &benflush; | |
21 | +# | |
22 | +# &bodyencode($data,$coding): | |
23 | +# データをBase64形式またはQuoted-Printable形式でエンコードする。 | |
24 | +# 第2パラメータに"qp"または"b64"を指定することによりコーディング形式 | |
25 | +# を指示することができる。第2パラメータを省略するとBase64形式でエン | |
26 | +# コードする。 | |
27 | +# Base64形式のエンコードの場合は、$foldcol*3/4 バイト単位で変換する | |
28 | +# ので、渡されたデータのうち半端な部分はバッファに保存され次に呼ばれ | |
29 | +# たときに処理される。最後にバッファに残ったデータは&benflushを呼ぶ | |
30 | +# ことにより処理されバッファからクリアされる。 | |
31 | +# Quoted-Printable形式のエンコードの場合は、行単位で変換するため、 | |
32 | +# データの最後に改行文字が無い場合、最後の改行文字の後ろのデータは | |
33 | +# バッファに保存され、次に呼ばれたときに処理される。最後にバッファ | |
34 | +# に残ったデータは&benflush("qp")を呼ぶことにより処理されバッファ | |
35 | +# からクリアされる。 | |
36 | +# | |
37 | +# &benflush($coding): | |
38 | +# 第1パラメータに"b64"または"qp"を指定することにより、それぞれBase64 | |
39 | +# 形式またはQuoted-Printable形式のエンコードを指定することができる。 | |
40 | +# 第1パラメータに何も指定しなければBase64形式でエンコードされる。 | |
41 | +# Base64のエンコードの場合、&bodyencodeが処理し残したデータを処理し | |
42 | +# pad文字を出力する。Quoted-Printableの場合、行単位でなくブロック単 | |
43 | +# 位で&bodyencodeを呼ぶ場合、&bodyencodeが処理し残したデータがもし | |
44 | +# バッファに残っていればそれを処理する。 | |
45 | +# 一つのデータを(1回または何回かに分けて)&bodyencodeした後に必ず1回 | |
46 | +# 呼ぶ必要がある。 | |
47 | +# | |
48 | +# &mimeencode($text): | |
49 | +# 第1パラメータが日本語文字列を含んでいれば、その部分をISO-2022-JPに | |
50 | +# 変換したあと、MIME encoded-word(RFC2047参照)に変換する。必要に応じ | |
51 | +# てencoded-wordの分割とencoded-wordの前後での行分割を行う。 | |
52 | +# | |
53 | +# 文字コードの自動判定は、同一行にShiftJISとEUCが混在している場合を | |
54 | +# 除いて漢字コードの混在にも対応している。ShiftJISかEUCかどうしても | |
55 | +# 判断できないときは$often_use_kanjiに設定されているコードと判定する。 | |
56 | +# ISO-2022-JPのエスケープシーケンスは$jis_inと$jis_outに設定すること | |
57 | +# により変更可能である。 | |
58 | + | |
59 | +$often_use_kanji = 'EUC'; # or 'SJIS' | |
60 | + | |
61 | +$jis_in = "\x1b\$B"; # ESC-$-B ( or ESC-$-@ ) | |
62 | +$jis_out = "\x1b\(B"; # ESC-(-B ( or ESC-(-J ) | |
63 | + | |
64 | +# 配布条件 : 著作権は放棄しませんが、配布・改変は自由とします。改変して | |
65 | +# 配布する場合は、オリジナルと異なることを明記し、オリジナル | |
66 | +# のバージョンナンバーに改変版バージョンナンバーを付加した形 | |
67 | +# 例えば Ver.2.02-XXXXX のようなバージョンナンバーを付けて下 | |
68 | +# さい。なお、Copyright表示は変更しないでください。 | |
69 | +# | |
70 | +# 注意 : &mimeencodeをjperl1.X(の2バイト文字対応モード)で使用すると、SJIS | |
71 | +# とEUCをうまく7bit JIS(ISO-2022-JP)に変換できません。 | |
72 | +# 入力に含まれる文字が7bit JIS(ISO-2022-JP)とASCIIのみであること | |
73 | +# が保証されている場合を除き、必ずoriginalの英語版のperl(または | |
74 | +# jperl1.4以上を -Llatin オプション付き)で動かしてください。 | |
75 | +# なお、Perl5対応のjperlは試したことがないのでどのような動作になる | |
76 | +# かわかりません。 | |
77 | +# | |
78 | +# 参照 : RFC1468, RFC2045, RFC2047 | |
79 | + | |
80 | +## MIME base64 アルファベットテーブル(RFC2045より) | |
81 | +%mime = ( | |
82 | +"000000", "A", "000001", "B", "000010", "C", "000011", "D", | |
83 | +"000100", "E", "000101", "F", "000110", "G", "000111", "H", | |
84 | +"001000", "I", "001001", "J", "001010", "K", "001011", "L", | |
85 | +"001100", "M", "001101", "N", "001110", "O", "001111", "P", | |
86 | +"010000", "Q", "010001", "R", "010010", "S", "010011", "T", | |
87 | +"010100", "U", "010101", "V", "010110", "W", "010111", "X", | |
88 | +"011000", "Y", "011001", "Z", "011010", "a", "011011", "b", | |
89 | +"011100", "c", "011101", "d", "011110", "e", "011111", "f", | |
90 | +"100000", "g", "100001", "h", "100010", "i", "100011", "j", | |
91 | +"100100", "k", "100101", "l", "100110", "m", "100111", "n", | |
92 | +"101000", "o", "101001", "p", "101010", "q", "101011", "r", | |
93 | +"101100", "s", "101101", "t", "101110", "u", "101111", "v", | |
94 | +"110000", "w", "110001", "x", "110010", "y", "110011", "z", | |
95 | +"110100", "0", "110101", "1", "110110", "2", "110111", "3", | |
96 | +"111000", "4", "111001", "5", "111010", "6", "111011", "7", | |
97 | +"111100", "8", "111101", "9", "111110", "+", "111111", "/", | |
98 | +); | |
99 | + | |
100 | +## JISコード(byte数)→encoded-word の文字数対応 | |
101 | +%mimelen = ( | |
102 | + 8,30, 10,34, 12,34, 14,38, 16,42, | |
103 | +18,42, 20,46, 22,50, 24,50, 26,54, | |
104 | +28,58, 30,58, 32,62, 34,66, 36,66, | |
105 | +38,70, 40,74, 42,74, | |
106 | +); | |
107 | + | |
108 | +## ヘッダエンコード時の行の長さの制限 | |
109 | +$limit=74; ## *注意* $limitを75より大きい数字に設定してはいけない。 | |
110 | + | |
111 | +## ボディbase64エンコード時の行の長さの制限 | |
112 | +$foldcol=72; ## *注意* $foldcolは76以下の4の倍数に設定すること。 | |
113 | + | |
114 | +## ボディQuoted-Printableエンコード時の行の長さの制限 | |
115 | +$qfoldcol=75; ## *注意* $foldcolは76以下に設定すること。 | |
116 | + | |
117 | +## null bitの挿入と pad文字の挿入のためのテーブル | |
118 | +@zero = ( "", "00000", "0000", "000", "00", "0" ); | |
119 | +@pad = ( "", "===", "==", "=" ); | |
120 | + | |
121 | +## ASCII, 7bit JIS, Shift-JIS 及び EUC の各々にマッチするパターン | |
122 | +$match_ascii = '\x1b\([BHJ]([\t\x20-\x7e]*)'; | |
123 | +$match_jis = '\x1b\$[@B](([\x21-\x7e]{2})*)'; | |
124 | +$match_sjis = '([\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc])+'; | |
125 | +$match_euc = '([\xa1-\xfe]{2})+'; | |
126 | + | |
127 | +## MIME Part 2(charset=`ISO-2022-JP',encoding=`B') の head と tail | |
128 | +$mime_head = '=?ISO-2022-JP?B?'; | |
129 | +$mime_tail = '?='; | |
130 | + | |
131 | +## &bodyencode が使う処理残しデータ用バッファ | |
132 | +$benbuf = ""; | |
133 | + | |
134 | +## &bodyencode の処理単位(バイト) | |
135 | +$bensize = int($foldcol/4)*3; | |
136 | + | |
137 | +## &mimeencode interface ## | |
138 | +sub main'mimeencode { | |
139 | + local($_) = @_; | |
140 | + s/$match_jis/$jis_in$1/go; | |
141 | + s/$match_ascii/$jis_out$1/go; | |
142 | + $kanji = &checkkanji; | |
143 | + s/$match_sjis/&s2j($&)/geo if ($kanji eq 'SJIS'); | |
144 | + s/$match_euc/&e2j($&)/geo if ($kanji eq 'EUC'); | |
145 | + s/(\x1b[\$\(][BHJ@])+/$1/g; | |
146 | + 1 while s/(\x1b\$[B@][\x21-\x7e]+)\x1b\$[B@]/$1/; | |
147 | + 1 while s/$match_jis/&mimeencode($&,$`,$')/eo; | |
148 | + s/$match_ascii/$1/go; | |
149 | + $_; | |
150 | +} | |
151 | + | |
152 | +## &bodyencode interface ## | |
153 | +sub main'bodyencode { | |
154 | + local($_,$coding) = @_; | |
155 | + if (!defined($coding) || $coding eq "" || $coding eq "b64"){ | |
156 | + $_ = $benbuf . $_; | |
157 | + local($cut) = int((length)/$bensize)*$bensize; | |
158 | + $benbuf = substr($_, $cut+$[); | |
159 | + $_ = substr($_, $[, $cut); | |
160 | + $_ = &base64encode($_); | |
161 | + s/.{$foldcol}/$&\n/g; | |
162 | + }elsif ($coding eq "qp"){ | |
163 | + # $benbuf が空でなければデータの最初に追加する | |
164 | + $_ = $benbuf . $_; | |
165 | + | |
166 | + # 改行文字を正規化する | |
167 | + s/\r\n/\n/g; | |
168 | + s/\r/\n/g; | |
169 | + | |
170 | + # データを行単位に分割する(最後の改行文字以降を $benbuf に保存する) | |
171 | + @line = split(/\n/,$_,-1); | |
172 | + $benbuf = pop(@line); | |
173 | + | |
174 | + local($result) = ""; | |
175 | + foreach (@line){ | |
176 | + $_ = &qpencode($_); | |
177 | + $result .= $_ . "\n"; | |
178 | + } | |
179 | + $_ = $result; | |
180 | + } | |
181 | + $_; | |
182 | +} | |
183 | + | |
184 | +## &benflush interface ## | |
185 | +sub main'benflush { | |
186 | + local($coding) = @_; | |
187 | + local($ret) = ""; | |
188 | + if ((!defined($coding) || $coding eq "" || $coding eq "b64") | |
189 | + && $benbuf ne ""){ | |
190 | + $ret = &base64encode($benbuf) . "\n"; | |
191 | + $benbuf = ""; | |
192 | + }elsif ($coding eq "qp" && $benbuf ne ""){ | |
193 | + $ret = &qpencode($benbuf) . "\n"; | |
194 | + $benbuf = ""; | |
195 | + } | |
196 | + $ret; | |
197 | +} | |
198 | + | |
199 | +## MIME ヘッダエンコーディング | |
200 | +sub mimeencode { | |
201 | + local($_, $befor, $after) = @_; | |
202 | + local($back, $forw, $blen, $len, $flen, $str); | |
203 | + $befor = substr($befor, rindex($befor, "\n")+1); | |
204 | + $after = substr($after, 0, index($after, "\n")-$[); | |
205 | + $back = " " unless ($befor eq "" | |
206 | + || $befor =~ /[ \t\(]$/); | |
207 | + $forw = " " unless ($after =~ /^\x1b\([BHJ]$/ | |
208 | + || $after =~ /^\x1b\([BHJ][ \t\)]/); | |
209 | + $blen = length($befor); | |
210 | + $flen = length($forw)+length($&)-3 if ($after =~ /^$match_ascii/o); | |
211 | + $len = length($_); | |
212 | + return "" if ($len <= 3); | |
213 | + if ($len > 39 || $blen + $mimelen{$len+3} > $limit){ | |
214 | + if ($limit-$blen < 30){ | |
215 | + $len = 0; | |
216 | + }else{ | |
217 | + $len = int(($limit-$blen-26)/4)*2+3; | |
218 | + } | |
219 | + if ($len >= 5){ | |
220 | + $str = substr($_, 0, $len).$jis_out; | |
221 | + $str = &base64encode($str); | |
222 | + $str = $mime_head.$str.$mime_tail; | |
223 | + $back.$str."\n ".$jis_in.substr($_, $len); | |
224 | + }else{ | |
225 | + "\n ".$_; | |
226 | + } | |
227 | + }else{ | |
228 | + $_ .= $jis_out; | |
229 | + $_ = &base64encode($_); | |
230 | + $_ = $back.$mime_head.$_.$mime_tail; | |
231 | + if ($blen + (length) + $flen > $limit){ | |
232 | + $_."\n "; | |
233 | + }else{ | |
234 | + $_.$forw; | |
235 | + } | |
236 | + } | |
237 | +} | |
238 | + | |
239 | +## MIME base64 エンコーディング | |
240 | +sub base64encode { | |
241 | + local($_) = @_; | |
242 | + $_ = unpack("B".((length)<<3), $_); | |
243 | + $_ .= $zero[(length)%6]; | |
244 | + s/.{6}/$mime{$&}/go; | |
245 | + $_.$pad[(length)%4]; | |
246 | +} | |
247 | + | |
248 | +## Quoted-Printable エンコーディング | |
249 | +sub qpencode { | |
250 | + local($_) = @_; | |
251 | + | |
252 | + # `=' 文字を16進表現に変換する | |
253 | + s/=/=3D/g; | |
254 | + | |
255 | + # 行末のタブとスペースを16進表現に変換する | |
256 | + s/\t$/=09/; | |
257 | + s/ $/=20/; | |
258 | + | |
259 | + # 印字可能文字(`!'〜`~')以外の文字を16進表現に変換する | |
260 | + s/([^!-~ \t])/&qphex($1)/ge; | |
261 | + | |
262 | + # 1行が$qfoldcol文字以下になるようにソフト改行をいれる | |
263 | + local($folded, $line) = ""; | |
264 | + while (length($_) > $qfoldcol){ | |
265 | + $line = substr($_, 0, $qfoldcol-1); | |
266 | + if ($line =~ /=$/){ | |
267 | + $line = substr($_, 0, $qfoldcol-2); | |
268 | + $_ = substr($_, $qfoldcol-2); | |
269 | + }elsif ($line =~ /=[0-9A-Fa-f]$/){ | |
270 | + $line = substr($_, 0, $qfoldcol-3); | |
271 | + $_ = substr($_, $qfoldcol-3); | |
272 | + }else{ | |
273 | + $_ = substr($_, $qfoldcol-1); | |
274 | + } | |
275 | + $folded .= $line . "=\n"; | |
276 | + } | |
277 | + $folded . $_; | |
278 | +} | |
279 | + | |
280 | +sub qphex { | |
281 | + local($_) = @_; | |
282 | + $_ = '=' . unpack("H2", $_); | |
283 | + tr/a-f/A-F/; | |
284 | + $_; | |
285 | +} | |
286 | + | |
287 | +## Shift-JIS と EUC のどちらの漢字コードが含まれるかをチェック | |
288 | +sub checkkanji { | |
289 | + local($sjis,$euc); | |
290 | + $sjis += length($&) while(/$match_sjis/go); | |
291 | + $euc += length($&) while(/$match_euc/go); | |
292 | + return 'NONE' if ($sjis == 0 && $euc == 0); | |
293 | + return 'SJIS' if ($sjis > $euc); | |
294 | + return 'EUC' if ($sjis < $euc); | |
295 | + $often_use_kanji; | |
296 | +} | |
297 | + | |
298 | +## EUC を 7bit JIS に変換 | |
299 | +sub e2j { | |
300 | + local($_) = @_; | |
301 | + tr/\xa1-\xfe/\x21-\x7e/; | |
302 | + $jis_in.$_.$jis_out; | |
303 | +} | |
304 | + | |
305 | +## Shift-JIS を 7bit JIS に変換 | |
306 | +sub s2j { | |
307 | + local($string); | |
308 | + local(@ch) = split(//, $_[0]); | |
309 | + while(($j1,$j2)=unpack("CC",shift(@ch).shift(@ch))){ | |
310 | + if ($j2 > 0x9e){ | |
311 | + $j1 = (($j1>0x9f ? $j1-0xb1 : $j1-0x71)<<1)+2; | |
312 | + $j2 -= 0x7e; | |
313 | + } | |
314 | + else{ | |
315 | + $j1 = (($j1>0x9f ? $j1-0xb1 : $j1-0x71)<<1)+1; | |
316 | + $j2 -= ($j2>0x7e ? 0x20 : 0x1f); | |
317 | + } | |
318 | + $string .= pack("CC", $j1, $j2); | |
319 | + } | |
320 | + $jis_in.$string.$jis_out; | |
321 | +} | |
322 | +1; |
@@ -0,0 +1,419 @@ | ||
1 | +################################################################################ | |
2 | +# | |
3 | +# コアプラグインの実装 | |
4 | +# | |
5 | +################################################################################ | |
6 | +package Wiki::Plugin; | |
7 | + | |
8 | +BEGIN { | |
9 | + # パラグラフプラグインのエントリ | |
10 | + $main::P_PLUGIN->{recent} = \&Wiki::Plugin::recent; | |
11 | + $main::P_PLUGIN->{recentdays} = \&Wiki::Plugin::recentdays; | |
12 | + $main::P_PLUGIN->{category_list} = \&Wiki::Plugin::category_list; | |
13 | + $main::P_PLUGIN->{ref_image} = \&Wiki::Plugin::ref_image; | |
14 | + $main::P_PLUGIN->{ref_text} = \&Wiki::Plugin::ref_text; | |
15 | + $main::P_PLUGIN->{outline} = \&Wiki::Plugin::outline; | |
16 | + $main::P_PLUGIN->{search} = \&Wiki::Plugin::search; | |
17 | + | |
18 | + # インラインプラグインのエントリ | |
19 | + $main::I_PLUGIN->{category} = \&Wiki::Plugin::category; | |
20 | + $main::I_PLUGIN->{lastmodified} = \&Wiki::Plugin::lastmodified; | |
21 | + $main::I_PLUGIN->{ref} = \&Wiki::Plugin::ref; | |
22 | + $main::I_PLUGIN->{raw} = \&Wiki::Plugin::raw; | |
23 | + | |
24 | + # ブロックプラグインのエントリ | |
25 | + $main::B_PLUGIN->{pre} = \&Wiki::Plugin::pre; | |
26 | + $main::B_PLUGIN->{bq} = \&Wiki::Plugin::bq; | |
27 | +} | |
28 | + | |
29 | +#============================================================================== | |
30 | +# ページの一覧を更新日時順に表示するプラグイン。 | |
31 | +#============================================================================== | |
32 | +sub recent { | |
33 | + my $max = shift; | |
34 | + my $way = shift; | |
35 | + | |
36 | + # 表示方式を決定 | |
37 | + if($way eq ""){ | |
38 | + $way = "H"; | |
39 | + } | |
40 | + if($max eq "V" || $max eq "v"){ | |
41 | + $way = "V"; | |
42 | + $max = 0; | |
43 | + } elsif($max eq "H" || $max eq "h"){ | |
44 | + $way = "H"; | |
45 | + $max = 0; | |
46 | + } elsif($max eq ""){ | |
47 | + $max = 0; | |
48 | + } | |
49 | + | |
50 | + # 表示内容を作成 | |
51 | + my $buf = ""; | |
52 | + my $content = ""; | |
53 | + | |
54 | + my @pages = &Wiki::get_page_list(); | |
55 | + my $count = 0; | |
56 | + | |
57 | + foreach my $page (@pages){ | |
58 | + $content = "<a href=\"".&Wiki::create_url({p=>$page->{NAME}})."\">".&Util::escapeHTML($page->{NAME})."</a>"; | |
59 | + if($way eq "H" || $way eq "h"){ | |
60 | + if($count!=0){ | |
61 | + $buf .= " / "; | |
62 | + } | |
63 | + $buf .= $content; | |
64 | + } else { | |
65 | + if($count==0){ | |
66 | + $buf .= "<ul>\n"; | |
67 | + } | |
68 | + $buf .= "<li>".$content."</li>\n"; | |
69 | + } | |
70 | + $count++; | |
71 | + last if($count==$max && $max!=0); | |
72 | + } | |
73 | + if($count>0 && $way ne "H" && $way ne "h"){ | |
74 | + $buf .= "</ul>\n"; | |
75 | + } | |
76 | + return $buf; | |
77 | +} | |
78 | + | |
79 | +#============================================================================== | |
80 | +# 日付ごとに更新されたページを一覧表示するプラグイン。 | |
81 | +#============================================================================== | |
82 | +sub recentdays { | |
83 | + my $max = shift; | |
84 | + $max = 5 if($max eq ""); | |
85 | + my $buf = ""; | |
86 | + | |
87 | + my @pages = &Wiki::get_page_list(); | |
88 | + my $count = 0; | |
89 | + | |
90 | + my $last_year = 0; | |
91 | + my $last_mon = 0; | |
92 | + my $last_day = 0; | |
93 | + | |
94 | + foreach my $page (@pages){ | |
95 | + my ($sec, $min, $hour, $day, $mon, $year) = localtime($page->{TIME}); | |
96 | + | |
97 | + $year += 1900; | |
98 | + $mon += 1; | |
99 | + | |
100 | + if($last_year!=$year || $last_mon!=$mon || $last_day!=$day){ | |
101 | + | |
102 | + $count++; | |
103 | + last if($count == $max+1); | |
104 | + | |
105 | + $last_year = $year; | |
106 | + $last_mon = $mon; | |
107 | + $last_day = $day; | |
108 | + | |
109 | + $buf .= "</ul>\n" if($buf ne ""); | |
110 | + $buf .= sprintf("<b>%04d/%02d/%02d</b>\n",$year,$mon,$day); | |
111 | + $buf .= "<ul>\n"; | |
112 | + } | |
113 | + | |
114 | + $buf .= "<li><a href=\"".&Wiki::create_url({p=>$page->{NAME}})."\">". | |
115 | + &Util::escapeHTML($page->{NAME})."</a></li>\n"; | |
116 | + } | |
117 | + | |
118 | + if($buf ne ""){ | |
119 | + $buf .= "</UL>\n"; | |
120 | + } | |
121 | + | |
122 | + return $buf; | |
123 | +} | |
124 | + | |
125 | +#============================================================================== | |
126 | +# ページをカテゴライズするためのプラグイン。 | |
127 | +#============================================================================== | |
128 | +sub category { | |
129 | + my $category = shift; | |
130 | + if($category eq ""){ | |
131 | + return "<span class=\"error\">カテゴリが指定されていません。</span>"; | |
132 | + } else { | |
133 | + return "[<a href=\"".&Wiki::create_url({c=>$category},$main::CATEGORY_SCRIPT)."\">". | |
134 | + "カテゴリ:".&Util::escapeHTML($category)."</a>]"; | |
135 | + } | |
136 | +} | |
137 | + | |
138 | +#============================================================================= | |
139 | +# ページの最終更新日時を表示するプラグイン。 | |
140 | +#============================================================================= | |
141 | +sub lastmodified { | |
142 | + my $page = shift || $main::in{"p"}; | |
143 | + if(&Wiki::page_exists($page)){ | |
144 | + return "最終更新時間:".&Util::format_date(&Wiki::get_last_modified($page)); | |
145 | + } else { | |
146 | + return undef; | |
147 | + } | |
148 | +} | |
149 | + | |
150 | +#============================================================================= | |
151 | +# カテゴリごとのページ一覧を表示するプラグイン。 | |
152 | +#============================================================================= | |
153 | +sub category_list { | |
154 | + my $category = shift; | |
155 | + my $buf = ""; | |
156 | + | |
157 | + # 指定されたカテゴリを表示 | |
158 | + if($category ne ""){ | |
159 | + my @pages = &Wiki::get_page_list(); | |
160 | + $buf .= "<h2>".&Util::escapeHTML($category)."</h2>\n"; | |
161 | + $buf .= "<ul>\n"; | |
162 | + #foreach my $page (sort(@pages)){ | |
163 | + foreach my $page (sort {$a->{NAME} cmp $b->{NAME}} @pages){ | |
164 | + my $source = &Wiki::get_page($page->{NAME}); | |
165 | + foreach my $line (split(/\n/,$source)){ | |
166 | + # コメントか整形済テキストの場合は飛ばす | |
167 | + next if($line =~ /^(\t| |\/\/)/); | |
168 | + | |
169 | + # カテゴリにマッチしたらリスティング | |
170 | + if($line =~ /{{category\s+$category}}/){ | |
171 | + $buf .= "<li><a href=\"".&Wiki::create_url({p=>$page->{NAME}})."\">". | |
172 | + &Util::escapeHTML($page->{NAME})."</a></li>"; | |
173 | + last; | |
174 | + } | |
175 | + } | |
176 | + } | |
177 | + $buf .= "</ul>\n"; | |
178 | + | |
179 | + # 全てのカテゴリを表示 | |
180 | + } else { | |
181 | + my $category = {}; | |
182 | + my @pages = &Wiki::get_page_list(); | |
183 | + | |
184 | + foreach my $page (@pages){ | |
185 | + my $source = &Wiki::get_page($page->{NAME}); | |
186 | + foreach my $line (split(/\n/,$source)){ | |
187 | + # コメントか整形済テキストの場合は飛ばす | |
188 | + next if($line =~ /^(\t| |\/\/)/); | |
189 | + | |
190 | + # カテゴリにマッチしたらリスティング | |
191 | + while($line =~ /\{\{category\s+(.+?)\}\}/g){ | |
192 | + $category->{$1}->{$page->{NAME}} = 1; | |
193 | + } | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + foreach my $name (sort(keys(%$category))){ | |
198 | + $buf .= "<h2>".&Util::escapeHTML($name)."</h2>\n"; | |
199 | + $buf .= "<ul>\n"; | |
200 | + foreach my $page (sort(keys(%{$category->{$name}}))){ | |
201 | + $buf .= "<li><a href=\"".&Wiki::create_url({p=>$page})."\">". | |
202 | + &Util::escapeHTML($page)."</a></li>\n"; | |
203 | + } | |
204 | + $buf .= "</ul>\n"; | |
205 | + } | |
206 | + } | |
207 | + return $buf; | |
208 | +} | |
209 | + | |
210 | +#============================================================================= | |
211 | +# 添付ファイルへのリンクを表示するためのプラグイン。 | |
212 | +#============================================================================= | |
213 | +sub ref { | |
214 | + my $file = shift; | |
215 | + my $page = shift; | |
216 | + my $alias = shift; | |
217 | + | |
218 | + if($file eq ""){ | |
219 | + return "<p class=\"error\">ファイルが指定されていません。</p>\n"; | |
220 | + } | |
221 | + if(!defined($page) || $page eq ""){ | |
222 | + $page = $main::in{"p"}; | |
223 | + } | |
224 | + if(!defined($alias) || $alias eq ""){ | |
225 | + $alias = $file; | |
226 | + } | |
227 | + | |
228 | + my $filename = sprintf("$main::ATTACH_DIR/%s.%s", | |
229 | + &Util::url_encode($page),&Util::url_encode($file)); | |
230 | + unless(-e $filename){ | |
231 | + return "<p class=\"error\">ファイルが存在しません。</p>\n"; | |
232 | + } | |
233 | + | |
234 | + return "<a href=\"".&Wiki::create_url({p=>$page,f=>$file},$main::DOWNLOAD_SCRIPT)."\">".&Util::escapeHTML($alias)."</a>"; | |
235 | +} | |
236 | + | |
237 | +#============================================================================= | |
238 | +# 添付ファイルを画像として表示するためのプラグイン。 | |
239 | +#============================================================================= | |
240 | +sub ref_image { | |
241 | + my $file = shift; | |
242 | + my $page = ""; | |
243 | + | |
244 | + my @options = @_; | |
245 | + my $width = ""; | |
246 | + my $height = ""; | |
247 | + | |
248 | + if($file eq ""){ | |
249 | + return "<p class=\"error\">ファイルが指定されていません。</p>\n"; | |
250 | + } | |
251 | + foreach my $option (@options){ | |
252 | + if($option =~ /^w([0-9]+)$/){ | |
253 | + $width = $1; | |
254 | + } elsif($option =~ /^h([0-9]+)$/){ | |
255 | + $height = $1; | |
256 | + } else { | |
257 | + $page = $option; | |
258 | + } | |
259 | + } | |
260 | + if($page eq ""){ | |
261 | + $page = $main::in{"p"}; | |
262 | + } | |
263 | + | |
264 | + my $filename = sprintf("$main::ATTACH_DIR/%s.%s", | |
265 | + &Util::url_encode($page),&Util::url_encode($file)); | |
266 | + unless(-e $filename){ | |
267 | + return "<p class=\"error\">ファイルが存在しません。</p>\n"; | |
268 | + } | |
269 | + | |
270 | + &Wiki::get_current_parser()->l_image($page, $file, $width, $height); | |
271 | + return undef; | |
272 | +} | |
273 | + | |
274 | +#============================================================================= | |
275 | +# 添付ファイルを画像として表示するためのプラグイン。 | |
276 | +#============================================================================= | |
277 | +sub ref_text { | |
278 | + my $file = shift; | |
279 | + my $page = shift || $main::in{"p"}; | |
280 | + | |
281 | + if($file eq ""){ | |
282 | + return "<p class=\"error\">ファイルが指定されていません。</p>\n"; | |
283 | + } | |
284 | + | |
285 | + my $filename = sprintf("$main::ATTACH_DIR/%s.%s", | |
286 | + &Util::url_encode($page),&Util::url_encode($file)); | |
287 | + unless(-e $filename){ | |
288 | + return "<p class=\"error\">ファイルが存在しません。</p>\n"; | |
289 | + } | |
290 | + | |
291 | + my $text = ""; | |
292 | + open(DATA,$filename); | |
293 | + while(<DATA>){ | |
294 | + $text .= $_; | |
295 | + } | |
296 | + close(DATA); | |
297 | + | |
298 | + # 改行コードを変換 | |
299 | + $text =~ s/\r\n/\n/g; | |
300 | + $text =~ s/\r/\n/g; | |
301 | + # 文字コードを変換 | |
302 | + &jcode::convert(\$text,"euc"); | |
303 | + | |
304 | + # preタグをつけて返却 | |
305 | + return "<pre>".&Util::escapeHTML($text)."</pre>\n"; | |
306 | +} | |
307 | + | |
308 | +#============================================================================= | |
309 | +# アウトラインを表示するためのプラグイン | |
310 | +# 出力されるHTMLはちょっと手抜きです… | |
311 | +#============================================================================= | |
312 | +sub outline { | |
313 | + my $page = shift; | |
314 | + my $url = ""; | |
315 | + | |
316 | + if (!defined($page)) { | |
317 | + $page = $main::in{'p'}; | |
318 | + } else { | |
319 | + $url = &Wiki::create_url({p=>$page}); | |
320 | + } | |
321 | + | |
322 | + my $source = ""; | |
323 | + my $level = 0; | |
324 | + my $count = 0; | |
325 | + my $buf = ""; | |
326 | + | |
327 | + if(&Wiki::page_exists($page)){ | |
328 | + $source = &Wiki::get_page($page); | |
329 | + } | |
330 | + | |
331 | + foreach my $line (split(/\n/,$source)){ | |
332 | + if($line=~/^(!{1,3})(.+)$/){ | |
333 | + my $find_level = 4 - length($1); | |
334 | + | |
335 | + while($level < $find_level){ | |
336 | + $buf .= "<ul>\n"; | |
337 | + $level++; | |
338 | + } | |
339 | + | |
340 | + while($level > $find_level){ | |
341 | + $buf .= "</ul>\n"; | |
342 | + $level--; | |
343 | + } | |
344 | + my $section = &Util::delete_tag(&Wiki::process_wiki($2)); | |
345 | + | |
346 | + $buf .= "<li><a href=\"".$url."#p$count\">$section</a></li>\n"; | |
347 | + $count++; | |
348 | + } | |
349 | + } | |
350 | + while($level > 0){ | |
351 | + $buf .= "</ul>\n"; | |
352 | + $level--; | |
353 | + } | |
354 | + return $buf; | |
355 | +} | |
356 | + | |
357 | +#============================================================================= | |
358 | +# 検索フォームを表示するためのプラグイン | |
359 | +#============================================================================= | |
360 | +sub search { | |
361 | + my $way = shift; | |
362 | + my $or_checked = $main::in{'t'} eq 'or'; | |
363 | + my $with_content = $main::in{'c'} eq 'true'; | |
364 | + return "<form action=\"".&Wiki::create_url({},$main::MAIN_SCRIPT)."\" method=\"GET\">\n". | |
365 | + " キーワード <input type=\"text\" name=\"w\" size=\"20\" value=\"".&Util::escapeHTML($main::in{'w'})."\">\n". | |
366 | + ($way eq "v" ? "<br>" : ""). | |
367 | + " <input type=\"radio\" name=\"t\" id=\"and\" value=\"and\"".(!$or_checked?" checked":"")."><label for=\"and\">AND</label>". | |
368 | + " <input type=\"radio\" name=\"t\" id=\"or\" value=\"or\"".($or_checked?" checked":"")."><label for=\"or\">OR</label>". | |
369 | + ($way eq "v" ? "<br>" : ""). | |
370 | + " <input type=\"checkbox\" name=\"c\" id=\"contents\" value=\"true\"".($with_content?" checked":"")."><label for=\"contents\">ページ内容も含める</label>". | |
371 | + " <input type=\"submit\" value=\" 検 索 \">\n". | |
372 | + " <input type=\"hidden\" name=\"a\" value=\"search\">\n". | |
373 | + "</form>\n"; | |
374 | +} | |
375 | + | |
376 | +#============================================================================= | |
377 | +# 引数で指定した文字列をそのまま表示するインラインプラグイン | |
378 | +#============================================================================= | |
379 | +sub raw { | |
380 | + my $text = shift; | |
381 | + return &Util::escapeHTML($text); | |
382 | +} | |
383 | + | |
384 | +#============================================================================= | |
385 | +# preタグを出力する複数行プラグイン | |
386 | +#============================================================================= | |
387 | +sub pre { | |
388 | + my $text = shift; | |
389 | + my $option = shift; | |
390 | + | |
391 | + my $count = 1; | |
392 | + my $buf = "<pre>"; | |
393 | + my @lines = split(/\n/, $text); | |
394 | + my $len = length($#lines + 1); | |
395 | + foreach my $line (@lines){ | |
396 | + if($option eq "num"){ | |
397 | + $buf .= sprintf("%0${len}d", $count) . "|"; | |
398 | + } | |
399 | + $buf .= Util::escapeHTML($line) . "\n"; | |
400 | + $count++; | |
401 | + } | |
402 | + | |
403 | + return $buf . "</pre>"; | |
404 | +} | |
405 | + | |
406 | +#============================================================================= | |
407 | +# blockquoteタグを出力する複数行プラグイン | |
408 | +#============================================================================= | |
409 | +sub bq { | |
410 | + my $text = shift; | |
411 | + my $buf = "<blockquote>"; | |
412 | + foreach my $line (split(/(\r\n)|\n|\r/,&Util::escapeHTML($text))){ | |
413 | + $buf .= "<p>$line<p>"; | |
414 | + } | |
415 | + $buf .= "</blockquote>"; | |
416 | + return $buf; | |
417 | +} | |
418 | + | |
419 | +1; |
@@ -0,0 +1,309 @@ | ||
1 | +body { | |
2 | + background-color: #FFFFFF; | |
3 | + color : #000000; | |
4 | +} | |
5 | + | |
6 | +div.adminmenu { | |
7 | + text-align : right; | |
8 | + padding-bottom : 5px; | |
9 | + margin-bottom : 5px; | |
10 | + border-bottom : #000088 1px dotted; | |
11 | + font-size : 80%; | |
12 | +} | |
13 | + | |
14 | +div.footer { | |
15 | + border-top : #000088 1px dotted; | |
16 | + margin-top : 20px; | |
17 | + padding-top : 5px; | |
18 | + text-align : right; | |
19 | + font-size : 80%; | |
20 | + font-style : italic; | |
21 | +} | |
22 | + | |
23 | +hr { | |
24 | + color : #AABBFF; | |
25 | +} | |
26 | + | |
27 | +pre { | |
28 | + border : #888888 1px dotted; | |
29 | + padding : 4px; | |
30 | + margin-left : 20px; | |
31 | + color : #666666; | |
32 | +} | |
33 | + | |
34 | +blockquote { | |
35 | + border : #AABBFF 1px solid; | |
36 | + padding : 4px; | |
37 | + margin-left : 20px; | |
38 | + font-style : italic; | |
39 | +} | |
40 | + | |
41 | +h1 { | |
42 | + text-align : right; | |
43 | + background-color : #FFFFFF; | |
44 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
45 | +} | |
46 | + | |
47 | + | |
48 | +h2 { | |
49 | + background-color : #AABBFF; | |
50 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
51 | + padding-left : 4pt; | |
52 | + margin-bottom : 5px; | |
53 | +} | |
54 | + | |
55 | +h3 { | |
56 | + border-left : #AABBFF 10px solid; | |
57 | + border-top : #AABBFF 5px solid; | |
58 | + border-right : #AABBFF 1px solid; | |
59 | + border-bottom : #AABBFF 1px solid; | |
60 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
61 | + padding-left : 3pt; | |
62 | + margin-bottom : 5px; | |
63 | +} | |
64 | + | |
65 | +h4 { | |
66 | + border-left : #AABBFF 10px solid; | |
67 | + padding-left : 4px; | |
68 | + font-family : Verdana,Arial,Helvetica,sans-serif; | |
69 | + padding-left : 2pt; | |
70 | + margin-bottom : 5px; | |
71 | +} | |
72 | + | |
73 | +div.body { | |
74 | + padding-left : 5px; | |
75 | +} | |
76 | + | |
77 | +div.body p { | |
78 | + text-indent : 10px; | |
79 | + line-height : 150%; | |
80 | + margin-top : 10px; | |
81 | + margin-bottom : 20px; | |
82 | +} | |
83 | + | |
84 | +div.body blockquote p { | |
85 | + margin-top : 0px; | |
86 | + margin-bottom : 0px; | |
87 | + text-indent : 0px; | |
88 | +} | |
89 | + | |
90 | +table { | |
91 | + border : #888888 2px solid; | |
92 | +} | |
93 | + | |
94 | +th { | |
95 | + border : #888888 1px solid; | |
96 | + background-color : #88AAFF; | |
97 | +} | |
98 | + | |
99 | +td { | |
100 | + border : #888888 1px solid; | |
101 | +} | |
102 | + | |
103 | +A:link { | |
104 | + color : #4444FF; | |
105 | + text-decoration : none; | |
106 | +} | |
107 | + | |
108 | +A:visited { | |
109 | + color : #4444FF; | |
110 | + text-decoration : none; | |
111 | +} | |
112 | + | |
113 | +A:hover { | |
114 | + color : #FF4444; | |
115 | + text-decoration : underline; | |
116 | +} | |
117 | + | |
118 | +dt { | |
119 | + border-bottom : #4444FF 1px dotted; | |
120 | + margin-bottom : 5px; | |
121 | + font-weight : bold; | |
122 | +} | |
123 | + | |
124 | +dd { | |
125 | + margin-left : 20pt; | |
126 | + margin-bottom : 5pt; | |
127 | +} | |
128 | + | |
129 | +div.main { | |
130 | + margin-left: 150px; | |
131 | +} | |
132 | + | |
133 | +div.sidebar { | |
134 | + position : absolute; | |
135 | + top : 0px; | |
136 | + left : 0px; | |
137 | + width : 150px; | |
138 | + font-size : x-small; | |
139 | + padding : 2pt; | |
140 | + border-right : #AABBFF 1px solid; | |
141 | + border-bottom : #AABBFF 1px solid; | |
142 | + color : #000000; | |
143 | + background-color: #EEEEFF; | |
144 | + word-break : break-all; | |
145 | +} | |
146 | + | |
147 | +div.comment { | |
148 | + margin-top : 10px; | |
149 | + margin-bottom : 10px; | |
150 | + background-color : #EEEEFF; | |
151 | + border : #AABBFF 1px solid; | |
152 | + font-size : 80%; | |
153 | +} | |
154 | + | |
155 | +div.comment p { | |
156 | + margin-top : 5pt; | |
157 | + margin-bottom : 5pt; | |
158 | +} | |
159 | + | |
160 | +div.sidebar ul,div.sidebar li { | |
161 | + padding-left : 0pt; | |
162 | + margin-left : 10pt; | |
163 | +} | |
164 | + | |
165 | +div.sidebar ol,div.sidebar li { | |
166 | + padding-left : 0pt; | |
167 | + margin-left : 10pt; | |
168 | +} | |
169 | + | |
170 | +div.sidebar h2,div.sidebar h3,div.sidebar h4 { | |
171 | + margin-top : 0px; | |
172 | +} | |
173 | + | |
174 | +/* calendar plugin */ | |
175 | +table.calendar { | |
176 | + font-size: 90%; | |
177 | + line-height: 1.1em; | |
178 | +} | |
179 | + | |
180 | +table.calendar td { | |
181 | + margin: 0px; | |
182 | + text-align: right; | |
183 | + padding: 0px; | |
184 | +} | |
185 | + | |
186 | +table.calendar td.calendar-prev-month, | |
187 | +table.calendar td.calendar-current-month, | |
188 | +table.calendar td.calendar-next-month { | |
189 | + text-align: center; | |
190 | +} | |
191 | + | |
192 | +.calendar-sunday { | |
193 | + color: #f00; | |
194 | +} | |
195 | + | |
196 | +.calendar-saturday { | |
197 | + color: #00f; | |
198 | +} | |
199 | + | |
200 | +.calendar-weekday { | |
201 | + color: #000; | |
202 | +} | |
203 | + | |
204 | +.calendar-prev-month, .calendar-current-month, .calendar-next-month, | |
205 | +.calendar-sunday, .calendar-weekday, .calendar-saturday { | |
206 | + background-color : #88AAFF; | |
207 | +} | |
208 | + | |
209 | +@media print { | |
210 | + div.sidebar { | |
211 | + display: none; | |
212 | + } | |
213 | + | |
214 | + div.main { | |
215 | + margin-left: 0px; | |
216 | + } | |
217 | + | |
218 | + div.adminmenu { | |
219 | + display: none; | |
220 | + } | |
221 | + | |
222 | + div.footer { | |
223 | + display: none; | |
224 | + } | |
225 | + | |
226 | + h1 { | |
227 | + display: none; | |
228 | + } | |
229 | + | |
230 | + div.header { | |
231 | + display: none; | |
232 | + } | |
233 | + | |
234 | + div.comment { | |
235 | + display: none; | |
236 | + } | |
237 | + | |
238 | + a.partedit { | |
239 | + display: none; | |
240 | + } | |
241 | +} | |
242 | + | |
243 | +textarea.edit { | |
244 | + width: 100%; | |
245 | +} | |
246 | + | |
247 | +div.diff { | |
248 | + border : #888888 1px dotted; | |
249 | + padding : 4px; | |
250 | + margin-left : 20px; | |
251 | + color : #666666; | |
252 | +} | |
253 | + | |
254 | +ins.diff { | |
255 | + background-color: #AAFFAA; | |
256 | + text-decoration: none; | |
257 | +} | |
258 | + | |
259 | +del.diff { | |
260 | + background-color: #FFAAAA; | |
261 | + text-decoration: none; | |
262 | +} | |
263 | + | |
264 | +/*----------------------------------------------------------------------------*/ | |
265 | +/* User CSS */ | |
266 | +/*----------------------------------------------------------------------------*/ | |
267 | +/* エラーメッセージ */ | |
268 | +.error { | |
269 | + color : #FF0000; | |
270 | + font-weight : bold; | |
271 | +} | |
272 | + | |
273 | +/* 存在しないWikiページ */ | |
274 | +span.nopage { | |
275 | + background-color : #FFFF88; | |
276 | +} | |
277 | + | |
278 | +/* Wikiページへのアンカ */ | |
279 | +a.wikipage:link { | |
280 | + text-decoration : underline; | |
281 | +} | |
282 | + | |
283 | +a.wikipage:visited { | |
284 | + text-decoration : underline; | |
285 | +} | |
286 | + | |
287 | +a.wikipage:hover { | |
288 | + background-color: #DDDDDD; | |
289 | + text-decoration : underline; | |
290 | +} | |
291 | + | |
292 | +/* parteditプラグイン */ | |
293 | +div.partedit { | |
294 | + text-align : right; | |
295 | + font-size : 80%; | |
296 | +} | |
297 | + | |
298 | +/* calendarプラグイン */ | |
299 | +td.today { | |
300 | + background-color : #FF8888; | |
301 | +} | |
302 | + | |
303 | +td.have { | |
304 | + font-weight : bold; | |
305 | +} | |
306 | + | |
307 | +.calendar td { | |
308 | + text-align : right; | |
309 | +} |
@@ -0,0 +1,70 @@ | ||
1 | +#!/bin/sh | |
2 | +########################################################################## | |
3 | +# | |
4 | +# FSWikiLiteリリース用シェルスクリプト | |
5 | +# | |
6 | +########################################################################## | |
7 | +#========================================================================= | |
8 | +# 引数のチェック | |
9 | +#========================================================================= | |
10 | +if [ $# -lt 1 ] | |
11 | +then | |
12 | + echo "./release.sh version" | |
13 | + exit 1 | |
14 | +fi | |
15 | + | |
16 | +#========================================================================= | |
17 | +# バージョン情報 | |
18 | +#========================================================================= | |
19 | +VERSION=$1 | |
20 | +RELEASE="fswiki_lite_$VERSION" | |
21 | + | |
22 | +#========================================================================= | |
23 | +# テンポラリディレクトリがある場合は削除 | |
24 | +#========================================================================= | |
25 | +if [ -e $RELEASE ]; then | |
26 | + echo "delete temp directory..." | |
27 | + rm -rf $RELEASE | |
28 | +fi | |
29 | + | |
30 | +#========================================================================= | |
31 | +# zipファイルがある場合は削除 | |
32 | +#========================================================================= | |
33 | +if [ -e $RELEASE.zip ]; then | |
34 | + echo "delete zip file..." | |
35 | + rm -f $RELEASE.zip | |
36 | +fi | |
37 | + | |
38 | +#========================================================================= | |
39 | +# テンポラリディレクトリの作成 | |
40 | +#========================================================================= | |
41 | +echo "create temp directory..." | |
42 | +mkdir $RELEASE | |
43 | + | |
44 | +#========================================================================= | |
45 | +# ファイルのコピー | |
46 | +#========================================================================= | |
47 | +echo "copy to temp directory..." | |
48 | +cp ./*.cgi $RELEASE | |
49 | +cp -r ./data $RELEASE | |
50 | +cp -r ./docs $RELEASE | |
51 | +cp -r ./lib $RELEASE | |
52 | +cp -r ./plugin $RELEASE | |
53 | +cp -r ./theme $RELEASE | |
54 | + | |
55 | +#========================================================================= | |
56 | +# zipファイルの作成 | |
57 | +#========================================================================= | |
58 | +echo "create zip file..." | |
59 | +find ./$RELEASE \! -path '*/CVS*' -exec zip $RELEASE.zip {} \; | |
60 | + | |
61 | +#========================================================================= | |
62 | +# テンポラリディレクトリを削除 | |
63 | +#========================================================================= | |
64 | +echo "remove temp directory..." | |
65 | +rm -rf $RELEASE | |
66 | + | |
67 | +#========================================================================= | |
68 | +# 終了 | |
69 | +#========================================================================= | |
70 | +echo "complete." |