1################################################################################
2# <p>
3#   Wiki�ե����ޥåȤ�ʸ�����ѡ������������б������եå��᥽�åɤθƤӽФ���Ԥ��ޤ���
4#   Wiki::Parser��Ѿ����������Υեå��᥽�åɤ����С��饤�ɤ��뤳�Ȥ�Ǥ�դΥե����ޥåȤؤ��Ѵ�����ǽ�Ǥ���
5# </p>
6################################################################################
7package Wiki::Parser;
8use strict;
9use Wiki::Keyword;
10use Wiki::InterWiki;
11
12$Wiki::Parser::keyword   = undef;
13$Wiki::Parser::interwiki = undef;
14
15#===============================================================================
16# <p>
17# �����ȥ饯����
18# </p>
19# <pre>
20# my $parser = Wiki::HTMLParser-&gt;new($wiki);
21# </pre>
22#===============================================================================
23sub new {
24	my $class = shift;
25	my $wiki  = shift;
26
27	my $self = {};
28	$self->{wiki} = $wiki;
29
30	# Keyword��InterWiki�Ϲ�®���Τ���⥸�塼���ѿ��Ȥ����ݻ�����
31	#�ʤ�����mod_perl+Farm�ξ��ϥ���ʤΤ����new�����
32	if(exists $ENV{MOD_PERL}){
33		$self->{interwiki} = Wiki::InterWiki->new($wiki);
34		$self->{keyword}   = Wiki::Keyword->new($wiki,$self->{interwiki});
35	} else {
36		unless(defined($Wiki::Parser::keyword)){
37			$Wiki::Parser::interwiki = Wiki::InterWiki->new($wiki);
38			$Wiki::Parser::keyword   = Wiki::Keyword->new($wiki,$Wiki::Parser::interwiki);
39		}
40		$self->{interwiki} = $Wiki::Parser::interwiki;
41		$self->{keyword}   = $Wiki::Parser::keyword;
42	}
43
44	$self->{dl_flag} = 0;
45	$self->{dt} = "";
46	$self->{dd} = "";
47
48	return bless $self,$class;
49}
50
51#===============================================================================
52# <p>
53# �ѡ����������Ϥ��ޤ���
54# </p>
55# <pre>
56# $parser-&gt;parse($source);
57# </pre>
58#===============================================================================
59sub parse {
60	my $self   = shift;
61	my $source = shift;
62
63	$self->start_parse;
64	$source =~ s/\r//g;
65
66	my @lines = split(/\n/,$source);
67
68	foreach my $line (@lines){
69		chomp $line;
70
71		# ʣ���Ԥ�����
72		$self->multi_explanation($line);
73
74		my $word1 = substr($line,0,1);
75		my $word2 = substr($line,0,2);
76		my $word3 = substr($line,0,3);
77
78		# ����
79		if($line eq ""){
80			$self->l_paragraph();
81			next;
82		}
83
84		# �ѥ饰��եץ饰����
85		if($line =~ /^{{((.|\s)+?)}}$/){
86			my $plugin = $self->{wiki}->parse_inline_plugin($1);
87			my $info   = $self->{wiki}->get_plugin_info($plugin->{command});
88			if($info->{TYPE} eq "paragraph"){
89				$self->l_plugin($plugin);
90			} else {
91				my @obj = $self->parse_line($line);
92				$self->l_text(\@obj);
93			}
94			next;
95		}
96
97		# PRE
98		if($word1 eq " " || $word1 eq "\t"){
99			$self->l_verbatim($line);
100
101		# ����
102		} elsif($word3 eq "!!!"){
103			my @obj = $self->parse_line(substr($line,3));
104			$self->l_headline(1,\@obj);
105
106		} elsif($word2 eq "!!"){
107			my @obj = $self->parse_line(substr($line,2));
108			$self->l_headline(2,\@obj);
109
110		} elsif($word1 eq "!"){
111			my @obj = $self->parse_line(substr($line,1));
112			$self->l_headline(3,\@obj);
113
114		# ����
115		} elsif($word3 eq "***"){
116			my @obj = $self->parse_line(substr($line,3));
117			$self->l_list(3,\@obj);
118
119		} elsif($word2 eq "**"){
120			my @obj = $self->parse_line(substr($line,2));
121			$self->l_list(2,\@obj);
122
123		} elsif($word1 eq "*"){
124			my @obj = $self->parse_line(substr($line,1));
125			$self->l_list(1,\@obj);
126
127		# �ֹ��դ�����
128		} elsif($word3 eq "+++"){
129			my @obj = $self->parse_line(substr($line,3));
130			$self->l_numlist(3,\@obj);
131
132		} elsif($word2 eq "++"){
133			my @obj = $self->parse_line(substr($line,2));
134			$self->l_numlist(2,\@obj);
135
136		} elsif($word1 eq "+"){
137			my @obj = $self->parse_line(substr($line,1));
138			$self->l_numlist(1,\@obj);
139
140		# ��ʿ��
141		} elsif($line eq "----"){
142			$self->l_line();
143
144		# ����
145		} elsif($word2 eq '""'){
146			my @obj = $self->parse_line(substr($line,2));
147			$self->l_quotation(\@obj);
148
149		# ����
150		} elsif(index($line,":")==0 && index($line,":",1)!=-1){
151			if(index($line,":::")==0){
152				$self->{dd} .= substr($line,3);
153				next;
154			}
155			if(index($line,"::")==0){
156				if($self->{dt} ne "" || $self->{dd} ne ""){
157					$self->multi_explanation;
158				}
159				$self->{dt} = substr($line,2);
160				$self->{dl_flag} = 1;
161				next;
162			}
163			my $dt = substr($line,1,index($line,":",1)-1);
164			my $dd = substr($line,index($line,":",1)+1);
165			my @obj1 = $self->parse_line($dt);
166			my @obj2 = $self->parse_line($dd);
167			$self->l_explanation(\@obj1,\@obj2);
168
169		# �ơ��֥�
170		} elsif($word1 eq ","){
171			if($line =~ /,$/){
172				$line .= " ";
173			}
174			my @spl = map {/^"(.*)"$/ ? scalar($_ = $1, s/\"\"/\"/g, $_) : $_}
175			              ($line =~ /,\s*(\"[^\"]*(?:\"\"[^\"]*)*\"|[^,]*)/g);
176			my @array;
177			foreach my $value (@spl){
178				my @cell = $self->parse_line($value);
179				push @array,\@cell;
180			}
181			$self->l_table(\@array);
182
183		# ������
184		} elsif($word2 eq "//"){
185
186		# ����ʤ���
187		} else {
188			my @obj = $self->parse_line($line);
189			$self->l_text(\@obj);
190		}
191	}
192
193	# ʣ���Ԥ�����
194	$self->multi_explanation;
195
196	$self->end_parse;
197}
198
199#===============================================================================
200# <p>
201# ʣ���Ԥ�����ʸ��������ޤ���
202# </p>
203#===============================================================================
204sub multi_explanation {
205	my $self = shift;
206	my $line = shift;
207	if($self->{dl_flag}==1 && (index($line,":")!=0 || !defined($line))){
208		my @obj1 = $self->parse_line($self->{dt});
209		my @obj2 = $self->parse_line($self->{dd});
210		$self->l_explanation(\@obj1,\@obj2);
211		$self->{dl_flag} = 0;
212		$self->{dt} = "";
213		$self->{dd} = "";
214	}
215}
216
217#===============================================================================
218# <p>
219# ����ʬ��ѡ������ޤ���parse�᥽�åɤ��椫��ɬ�פ˱����ƸƤӽФ���ޤ���
220# </p>
221#===============================================================================
222sub parse_line {
223	my $self   = shift;
224	my $source = shift;
225	my @array  = ();
226
227	# �ץ饰����
228	if($source =~ /{{((.|\s)+?)}}/){
229		my $pre  = $`;
230		my $post = $';
231		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
232		my $plugin = $self->{wiki}->parse_inline_plugin($1);
233		my $info   = $self->{wiki}->get_plugin_info($plugin->{command});
234		if($info->{TYPE} eq "inline"){
235			push @array,$self->plugin($plugin);
236		} else {
237			push @array,$self->text("{{$1}}");
238		}
239		if($post ne ""){ push(@array,$self->parse_line($post)); }
240
241	# �ܡ���ɡ�������å������ä���������
242	} elsif($source =~ /((''')|('')|(==)|(__))(.+?)(\1)/){
243		my $pre   = $`;
244		my $post  = $';
245		my $type  = $1;
246		my $label = $6;
247		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
248		if($type eq "'''"){
249			push @array,$self->bold($label);
250		} elsif($type eq "__"){
251			push @array,$self->underline($label);
252		} elsif($type eq "''"){
253			push @array,$self->italic($label);
254		} elsif($type eq "=="){
255			push @array,$self->denialline($label);
256		}
257		if($post ne ""){ push(@array,$self->parse_line($post)); }
258
259	# InterWikiName
260	} elsif($self->{interwiki}->exists_interwiki($source)){
261		my $pre   = $self->{interwiki}->{g_pre};
262		my $post  = $self->{interwiki}->{g_post};
263		my $label = $self->{interwiki}->{g_label};
264		my $url   = $self->{interwiki}->{g_url};
265		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
266		push @array,$self->url_anchor($url,$label);
267		if($post ne ""){ push(@array,$self->parse_line($post)); }
268
269	# �ڡ�����̾���
270	} elsif($source =~ /\[\[([^\[]+?)\|(.+?)\]\]/){
271		my $pre   = $`;
272		my $post  = $';
273		my $label = $1;
274		my $page  = $2;
275		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
276		push @array,$self->wiki_anchor($page,$label);
277		if($post ne ""){ push(@array,$self->parse_line($post)); }
278
279	# URL��̾���
280	} elsif($source =~ /\[([^\[]+?)\|((http|https|ftp|mailto):[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!\$&=:;\*#\@']*)\]/
281	    ||  $source =~ /\[([^\[]+?)\|(file:[^\[\]]*)\]/
282	    ||  $source =~ /\[([^\[]+?)\|((\/|\.\/|\.\.\/)+[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!\$&=:;\*#\@']*)\]/){
283		my $pre   = $`;
284		my $post  = $';
285		my $label = $1;
286		my $url   = $2;
287		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
288		if(index($url,'"') >= 0 || index($url,'><') >= 0 || index($url, 'javascript:') >= 0){
289			push @array,"<span class=\"error\">�����ʥ���Ǥ���</span>";
290		} else {
291			push @array,$self->url_anchor($url,$label);
292		}
293		if($post ne ""){ push(@array,$self->parse_line($post)); }
294
295	# URL���
296	} elsif($source =~ /(http|https|ftp|mailto):[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!\$&=:;\*#\@']*/
297	    ||  $source =~ /\[([^\[]+?)\|(file:[^\[\]]*)\]/){
298		my $pre   = $`;
299		my $post  = $';
300		my $url = $&;
301		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
302		if(index($url,'"') >= 0 || index($url,'><') >= 0 || index($url, 'javascript:') >= 0){
303			push @array,"<span class=\"error\">�����ʥ���Ǥ���</span>";
304		} else {
305			push @array,$self->url_anchor($url);
306		}
307		if($post ne ""){ push(@array,$self->parse_line($post)); }
308
309	# �ڡ������
310	} elsif($source =~ /\[\[([^\|]+?)\]\]/){
311		my $pre   = $`;
312		my $post  = $';
313		my $page = $1;
314		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
315		push @array,$self->wiki_anchor($page);
316		if($post ne ""){ push(@array,$self->parse_line($post)); }
317
318	# Ǥ�դ�URL���
319	} elsif($source =~ /\[([^\[]+?)\|(.+?)\]/){
320		my $pre   = $`;
321		my $post  = $';
322		my $label = $1;
323		my $url   = $2;
324		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
325		if(index($url,'"') >= 0 || index($url,'><') >= 0 || index($url, 'javascript:') >= 0){
326			push @array,"<span class=\"error\">�����ʥ���Ǥ���</span>";
327		} else {
328			# URI�����
329			my $wiki = $self->{wiki};
330			my $uri = $wiki->config('server_host');
331			if($uri eq ""){
332				$uri = $wiki->get_CGI()->url(-path_info => 1);
333			} else {
334				$uri = $uri . $wiki->get_CGI->url(-absolute => 1) . $wiki->get_CGI()->path_info();
335			}
336			push @array,$self->url_anchor($uri."/../".$url, $label);
337		}
338		if($post ne ""){ push(@array,$self->parse_line($post)); }
339
340	# �������
341	} elsif($self->{keyword}->exists_keyword($source)){
342		my $pre   = $self->{keyword}->{g_pre};
343		my $post  = $self->{keyword}->{g_post};
344		my $label = $self->{keyword}->{g_label};
345		my $url   = $self->{keyword}->{g_url};
346		my $page  = $self->{keyword}->{g_page};
347		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
348		if(defined($url) && $url ne ""){
349			push @array,$self->url_anchor($url,$label);
350		} else {
351			push @array,$self->wiki_anchor($page,$label);
352		}
353		if($post ne ""){ push(@array,$self->parse_line($post)); }
354
355	# WikiName
356	} elsif($self->{wiki}->config('wikiname')==1 && $source =~ /[A-Z]+?[a-z]+?([A-Z]+?[a-z]+)+/){
357		my $pre   = $`;
358		my $post  = $';
359		my $page  = $&;
360		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
361		push @array,$self->wiki_anchor($page);
362		if($post ne ""){ push(@array,$self->parse_line($post)); }
363
364	# ���顼��å�����
365	} elsif($source =~ /(<<)(.+?)(>>)/){
366		my $pre   = $`;
367		my $post  = $';
368		my $label = $2;
369		if($pre ne ""){ push(@array,$self->parse_line($pre)); }
370		push @array,$self->error($label);
371		if($post ne ""){ push(@array,$self->parse_line($post)); }
372
373	} else {
374		push @array,$self->text($source);
375	}
376
377	return @array;
378}
379
380#===============================================================================
381# <p>
382# �ѡ����������˸ƤӽФ���ޤ���
383# ���֥��饹��ɬ�פʽ�����������ϥ����С��饤�ɤ��Ƥ���������
384# </p>
385#===============================================================================
386sub start_parse {}
387
388#===============================================================================
389# <p>
390# �ѡ�����λ��˸ƤӽФ���ޤ���
391# ���֥��饹��ɬ�פʽ�����������ϥ����С��饤�ɤ��Ƥ���������
392# </p>
393#===============================================================================
394sub end_parse {}
395
396#===============================================================================
397# <p>
398# URL�����˥ޥå��������˸ƤӽФ���ޤ���
399# ���֥��饹�ˤƽ�����������ޤ���
400# </p>
401#===============================================================================
402sub url_anchor {}
403
404#===============================================================================
405# <p>
406# �ڡ���̾�����˥ޥå��������˸ƤӽФ���ޤ���
407# ���֥��饹�ˤƽ�����������ޤ���
408# </p>
409#===============================================================================
410sub wiki_anchor {}
411
412#===============================================================================
413# <p>
414# ������å��˥ޥå��������˸ƤӽФ���ޤ���
415# ���֥��饹�ˤƽ�����������ޤ���
416# </p>
417#===============================================================================
418sub italic {}
419
420#===============================================================================
421# <p>
422# �ܡ���ɤ˥ޥå��������˸ƤӽФ���ޤ���
423# ���֥��饹�ˤƽ�����������ޤ���
424# </p>
425#===============================================================================
426sub bold {}
427
428#===============================================================================
429# <p>
430# �����˥ޥå��������˸ƤӽФ���ޤ���
431# ���֥��饹�ˤƽ�����������ޤ���
432# </p>
433#===============================================================================
434sub underline {}
435
436#===============================================================================
437# <p>
438# �Ǥ��ä����˥ޥå��������˸ƤӽФ���ޤ���
439# ���֥��饹�ˤƽ�����������ޤ���
440# </p>
441#===============================================================================
442sub denialline {}
443
444#===============================================================================
445# <p>
446# �ץ饰����˥ޥå��������˸ƤӽФ���ޤ���
447# ���֥��饹�ˤƽ�����������ޤ���
448# </p>
449#===============================================================================
450sub plugin {}
451
452#===============================================================================
453# <p>
454# �ƥ����Ȥ˥ޥå��������˸ƤӽФ���ޤ���
455# ���֥��饹�ˤƽ�����������ޤ���
456# </p>
457#===============================================================================
458sub text{}
459
460#===============================================================================
461# <p>
462# ���ܤ˥ޥå��������˸ƤӽФ���ޤ���
463# ���֥��饹�ˤƽ�����������ޤ���
464# </p>
465#===============================================================================
466sub l_list {}
467
468#===============================================================================
469# <p>
470# �ֹ��դ����ܤ˥ޥå��������˸ƤӽФ���ޤ���
471# ���֥��饹�ˤƽ�����������ޤ���
472# </p>
473#===============================================================================
474sub l_numlist {}
475
476#===============================================================================
477# <p>
478# ���Ф��˥ޥå��������˸ƤӽФ���ޤ���
479# ���֥��饹�ˤƽ�����������ޤ���
480# </p>
481#===============================================================================
482sub l_headline {}
483
484#===============================================================================
485# <p>
486# PRE�����˥ޥå��������˸ƤӽФ���ޤ���
487# ���֥��饹�ˤƽ�����������ޤ���
488# </p>
489#===============================================================================
490sub l_verbatim {}
491
492#===============================================================================
493# <p>
494# ��ʿ���˥ޥå��������˸ƤӽФ���ޤ���
495# ���֥��饹�ˤƽ�����������ޤ���
496# </p>
497#===============================================================================
498sub l_line {}
499
500#===============================================================================
501# <p>
502# �äˤʤˤ�ʤ��Ԥ˥ޥå��������˸ƤӽФ���ޤ���
503# ���֥��饹�ˤƽ�����������ޤ���
504# </p>
505#===============================================================================
506sub l_text {}
507
508#===============================================================================
509# <p>
510# �����˥ޥå��������˸ƤӽФ���ޤ���
511# ���֥��饹�ˤƽ�����������ޤ���
512# </p>
513#===============================================================================
514sub l_explanation {}
515
516#===============================================================================
517# <p>
518# ���Ѥ˥ޥå��������˸ƤӽФ���ޤ���
519# ���֥��饹�ˤƽ�����������ޤ���
520# </p>
521#===============================================================================
522sub l_quotation {}
523
524#===============================================================================
525# <p>
526# �ѥ饰��դζ��ڤ�˥ޥå��������˸ƤӽФ���ޤ���
527# ���֥��饹�ˤƽ�����������ޤ���
528# </p>
529#===============================================================================
530sub l_paragraph {}
531
532#===============================================================================
533# <p>
534# �ơ��֥�˥ޥå��������˸ƤӽФ���ޤ���
535# ���֥��饹�ˤƽ�����������ޤ���
536# </p>
537#===============================================================================
538sub l_table {}
539
540#===============================================================================
541# <p>
542# �ѥ饰��եץ饰����˥ޥå��������˸ƤӽФ���ޤ���
543# ���֥��饹�ˤƽ�����������ޤ���
544# </p>
545#===============================================================================
546sub l_plugin {}
547
548#===============================================================================
549# <p>
550# �����˥ޥå��������˸ƤӽФ���ޤ���
551# ���֥��饹�ˤƽ�����������ޤ���
552# </p>
553#===============================================================================
554sub l_image {}
555
556#===============================================================================
557# <p>
558# ���顼��å������˥ޥå��������˸ƤӽФ���ޤ���
559# ���֥��饹�ˤƽ�����������ޤ���
560# </p>
561#===============================================================================
562sub error {}
563
5641;
565