/[suikacvs]/markup/html/whatpm/Whatpm/SWML/Parser.pm
Suika

Contents of /markup/html/whatpm/Whatpm/SWML/Parser.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.10 - (show annotations) (download)
Sat Nov 15 13:18:12 2008 UTC (15 years, 11 months ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
++ whatpm/t/swml/ChangeLog	15 Nov 2008 13:17:15 -0000
2008-11-15  Wakaba  <wakaba@suika.fam.cx>

	* tables-1.dat: Added a test case.

++ whatpm/Whatpm/SWML/ChangeLog	15 Nov 2008 13:17:52 -0000
2008-11-15  Wakaba  <wakaba@suika.fam.cx>

	* Parser.pm (parse_char_string): Not all quoted-pairs in table
	cells were unescaped.

1 package Whatpm::SWML::Parser;
2 use strict;
3
4 sub AA_NS () { q<http://pc5.2ch.net/test/read.cgi/hp/1096723178/aavocab#> }
5 sub HTML_NS () { q<http://www.w3.org/1999/xhtml> }
6 sub SW09_NS () { q<urn:x-suika-fam-cx:markup:suikawiki:0:9:> }
7 sub SW10_NS () { q<urn:x-suika-fam-cx:markup:suikawiki:0:10:> }
8 sub XML_NS () { q<http://www.w3.org/XML/1998/namespace> }
9
10 sub IN_SECTION_IM () { 0 }
11 sub IN_TABLE_ROW_IM () { 1 }
12 sub IN_PARAGRAPH_IM () { 2 }
13
14 sub BLOCK_START_TAG_TOKEN () { 1 }
15 sub BLOCK_END_TAG_TOKEN () { 2 }
16 sub CHARACTER_TOKEN () { 3 }
17 sub COMMENT_PARAGRAPH_START_TOKEN () { 4 }
18 sub EDITORIAL_NOTE_START_TOKEN () { 5 }
19 sub ELEMENT_TOKEN () { 6 }
20 sub EMPHASIS_TOKEN () { 7 }
21 sub EMPTY_LINE_TOKEN () { 8 }
22 sub END_OF_FILE_TOKEN () { 9 }
23 sub FORM_TOKEN () { 10 }
24 sub HEADING_START_TOKEN () { 11 }
25 sub HEADING_END_TOKEN () { 12 }
26 sub INLINE_START_TAG_TOKEN () { 13 }
27 sub INLINE_MIDDLE_TAG_TOKEN () { 14 }
28 sub INLINE_END_TAG_TOKEN () { 15 }
29 sub LABELED_LIST_START_TOKEN () { 16 }
30 sub LABELED_LIST_MIDDLE_TOKEN () { 17 }
31 sub LIST_START_TOKEN () { 18 }
32 sub PREFORMATTED_START_TOKEN () { 19 }
33 sub PREFORMATTED_END_TOKEN () { 20 }
34 sub QUOTATION_START_TOKEN () { 21 }
35 sub STRONG_TOKEN () { 22 }
36 sub TABLE_ROW_START_TOKEN () { 23 }
37 sub TABLE_ROW_END_TOKEN () { 24 }
38 sub TABLE_CELL_START_TOKEN () { 25 }
39 sub TABLE_CELL_END_TOKEN () { 26 }
40 sub TABLE_COLSPAN_CELL_TOKEN () { 27 }
41
42 sub new ($) {
43 my $self = bless {
44 }, $_[0];
45 return $self;
46 } # new
47
48 sub parse_char_string ($$$;$) {
49 my $self = shift;
50 my @s = split /\x0D\x0A?|\x0A/, ref $_[0] ? ${$_[0]} : $_[0], -1;
51
52 my $doc = $_[1];
53 @{$doc->child_nodes} = ();
54 my $html_el = $doc->create_element_ns (HTML_NS, [undef, 'html']);
55 $doc->append_child ($html_el);
56 $html_el->set_attribute_ns
57 ('http://www.w3.org/2000/xmlns/', [undef, 'xmlns'] => HTML_NS);
58 my $head_el = $doc->create_element_ns (HTML_NS, [undef, 'head']);
59 $html_el->append_child ($head_el);
60 my $body_el = $doc->create_element_ns (HTML_NS, [undef, 'body']);
61 $html_el->append_child ($body_el);
62 for ($doc, $html_el, $head_el, $body_el) {
63 $_->set_user_data (manakai_source_line => 1);
64 $_->set_user_data (manakai_source_column => 1);
65 }
66
67 my $_onerror = $_[2] || sub {
68 my %opt = @_;
69 my $r = 'Line ' . $opt{line} . ' column ' . $opt{column} . ': ';
70
71 if ($opt{token}) {
72 $r .= 'Token ' . (defined $opt{token}->{value}
73 ? $opt{token}->{value} : $opt{token}->{type}) . ': ';
74 }
75
76 $r .= $opt{type} . ';' . $opt{level};
77
78 warn $r . "\n";
79 }; # $_onerror
80
81 my $line = 0;
82 my $column = 0;
83 my $token;
84 my @nt;
85
86 my $onerror = sub {
87 $_onerror->(line => $line, column => $column, token => $token, @_);
88 }; # $onerror
89
90 my $continuous_line;
91
92 my $tokenize_text = sub {
93 my $s = shift; # ref
94
95 my $nest_level = 0;
96
97 if ($$s =~ s/^\[([0-9]+)\]//) {
98 push @nt, {type => ELEMENT_TOKEN,
99 local_name => 'anchor-end', namespace => SW09_NS,
100 anchor => $1, content => '[' . $1 . ']'};
101 $column += $+[0] - $-[0];
102 }
103
104 while (length $$s) {
105 if ($$s =~ s/^\[\[#([a-z-]+)//) {
106 $column = $+[0] - $-[0];
107 my $t = {type => FORM_TOKEN, name => $1,
108 line => $line, column => $column};
109 if ($$s =~ s/^\(([^()\\]*)\)//) {
110 $t->{id} = $1;
111 $column += $+[0] - $-[0];
112 }
113 my @param;
114 while ($$s =~ s/^://) {
115 if ($$s =~ s/^'((?>[^'\\]|\\.)*)//) {
116 $column += 1 + $+[0] - $-[0];
117 my $n = $1;
118 $n =~ tr/\\//d;
119 push @param, $n;
120 $column++ if $$s =~ s/\A\\\z//;
121 $column++ if $$s =~ s/^'//;
122 } elsif ($$s =~ s/^([^':\]][^:\]]*)//) {
123 $column += 1 + $+[0] - $-[0];
124 push @param, $1;
125 }
126 }
127 $t->{parameters} = \@param;
128 $column += 2 if $$s =~ s/^\]\]//;
129 push @nt, $t;
130 } elsif ($$s =~ s/^\[\[//) {
131 push @nt, {type => INLINE_START_TAG_TOKEN};
132 $column += 2;
133 $nest_level++;
134 } elsif ($$s =~ s/^\[([A-Z]+)(?>\(([^()\\]*)\))?(?>\@([0-9A-Za-z-]*))?\[//) {
135 push @nt, {type => INLINE_START_TAG_TOKEN,
136 tag_name => $1, classes => $2, language => $3,
137 line => $line, column => $column};
138 $column += $+[0] - $-[0];
139 $nest_level++;
140 } elsif ($$s =~ s/^\]\]//) {
141 push @nt, {type => INLINE_END_TAG_TOKEN,
142 line => $line, column => $column};
143 $column += 2;
144 $nest_level-- if $nest_level > 0;
145 } elsif ($$s =~ s/^(\]?)<([0-9A-Za-z%+._-]+)://) {
146 my $t = {type => $1 ? INLINE_END_TAG_TOKEN : ELEMENT_TOKEN,
147 res_scheme => $2, res_parameter => '',
148 line => $line, column => $column};
149 $column += $+[0] - $-[0];
150
151 while (length $$s) {
152 if ($$s =~ s/^([^>"]+)//) {
153 $t->{res_parameter} .= $1;
154 $column += $+[0] - $-[0];
155 } elsif ($$s =~ s/^("(?>[^"\\]|\\.)*)//) {
156 $t->{res_parameter} .= $1;
157 $column += $+[0] - $-[0];
158 $column++ if $$s =~ s/\A\\\z//;
159 $t->{res_parameter} .= '"' and $column++ if $$s =~ s/^"//;
160 } else {
161 last;
162 }
163 }
164
165 $column++ if $$s =~ s/^>//;
166
167 $t->{content} = $t->{res_scheme} . ':' . $t->{res_parameter};
168 if ($t->{res_scheme} !~ /[A-Z]/) {
169 $t->{res_parameter} = $t->{content};
170 $t->{res_scheme} = 'URI';
171 }
172
173 if ($t->{type} == INLINE_END_TAG_TOKEN) {
174 $column++ if $$s =~ s/^\]//;
175 $nest_level-- if $nest_level > 0;
176 } else {
177 $t->{local_name} = 'anchor-external';
178 $t->{namespace} = SW09_NS;
179 }
180 push @nt, $t;
181 } elsif ($$s =~ s/^\]>>([0-9]+)\]//) {
182 push @nt, {type => INLINE_END_TAG_TOKEN,
183 anchor => $1,
184 line => $line, column => $column};
185 $column += $+[0] - $-[0];
186 $nest_level-- if $nest_level > 0;
187 } elsif ($nest_level > 0 and
188 $$s =~ s/^\][\x09\x20]*(?>\@([0-9a-zA-Z-]*))?\[//) {
189 push @nt, {type => INLINE_MIDDLE_TAG_TOKEN,
190 language => $1,
191 line => $line, column => $column};
192 $column += $+[0] - $-[0];
193 } elsif ($$s =~ s/^''('?)//) {
194 push @nt, {type => $1 ? STRONG_TOKEN : EMPHASIS_TOKEN,
195 line => $line, column => $column};
196 $column += $+[0] - $-[0];
197 } elsif ($$s =~ s/^>>([0-9]+)//) {
198 push @nt, {type => ELEMENT_TOKEN,
199 local_name => 'anchor-internal', namespace => SW09_NS,
200 anchor => $1, content => '>>' . $1,
201 line => $line, column => $column};
202 $column += $+[0] - $-[0];
203 } elsif ($$s =~ s/^__&&//) {
204 if ($$s =~ s/^(.+?)&&__//) {
205 push @nt, {type => ELEMENT_TOKEN,
206 local_name => 'replace', namespace => SW09_NS,
207 by => $1,
208 line => $line, column => $column};
209 $column += 4 + $+[0] - $-[0];
210 } else {
211 push @nt, {type => CHARACTER_TOKEN,
212 data => '__&&',
213 line => $line, column => $column};
214 $column += 4;
215 }
216 } elsif ($$s =~ s/^([^<>\[\]'_]+)//) {
217 push @nt, {type => CHARACTER_TOKEN, data => $1,
218 line => $line, column => $column};
219 $column += $+[0] - $-[0];
220 } else {
221 push @nt, {type => CHARACTER_TOKEN, data => substr ($$s, 0, 1),
222 line => $line, column => $column};
223 substr ($$s, 0, 1) = '';
224 $column++;
225 }
226 }
227 }; # $tokenize_text
228
229 my $get_next_token = sub {
230 if (@nt) {
231 return shift @nt;
232 }
233
234 if (not @s) {
235 return {type => END_OF_FILE_TOKEN, line => $line, column => $column};
236 }
237
238 my $s = shift @s;
239 ($line, $column) = ($line + 1, 1);
240 if ($s eq '') {
241 undef $continuous_line;
242 return {type => EMPTY_LINE_TOKEN, line => $line, column => $column};
243 } elsif ($s =~ /^[\x09\x20]/) {
244 push @nt, {type => PREFORMATTED_START_TOKEN,
245 line => $line, column => $column};
246 $tokenize_text->(\$s);
247 while (@s) {
248 my $s = shift @s;
249 ($line, $column) = ($line + 1, 1);
250 if ($s eq '') {
251 push @nt, {type => PREFORMATTED_END_TOKEN,
252 line => $line, column => $column};
253 unshift @s, $s;
254 $line--;
255 last;
256 } elsif ($s =~ /\A\](INS|DEL)\][\x09\x20]*\z/) {
257 push @nt, {type => PREFORMATTED_END_TOKEN,
258 line => $line, column => $column};
259 push @nt, {type => BLOCK_END_TAG_TOKEN, tag_name => $1,
260 line => $line, column => $column};
261 last;
262 } else {
263 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
264 line => $line, column => $column};
265 $tokenize_text->(\$s);
266 }
267 }
268 return shift @nt;
269 } elsif ($s =~ s/^(\*+)[\x09\x20]*//) {
270 push @nt, {type => HEADING_START_TOKEN, depth => length $1,
271 line => $line, column => $column};
272 $column += $+[0] - $-[0];
273 $tokenize_text->(\$s);
274 push @nt, {type => HEADING_END_TOKEN,
275 line => $line, column => $column};
276 undef $continuous_line;
277 return shift @nt;
278 } elsif ($s =~ s/^([-=]+)[\x09\x20]*//) {
279 push @nt, {type => LIST_START_TOKEN, depth => $1,
280 line => $line, column => $column};
281 $column += $+[0] - $-[0];
282 $tokenize_text->(\$s);
283 $continuous_line = 1;
284 return shift @nt;
285 } elsif ($s =~ s/^:([^:]*)//) {
286 my $name = $1;
287 if ($s eq '') {
288 push @nt, {type => CHARACTER_TOKEN, data => ':',
289 line => $line, column => $column};
290 $column++;
291 $tokenize_text->(\$name);
292 } else {
293 my $real_column = $column + 1 + length $name;
294 push @nt, {type => LABELED_LIST_START_TOKEN,
295 line => $line, column => $column};
296 $name =~ s/\A[\x09\x20]*//;
297 $column += 1 + $+[0] - $-[0];
298 $name =~ s/[\x09\x20]+\z//;
299 $tokenize_text->(\$name);
300 $column = $real_column;
301 push @nt, {type => LABELED_LIST_MIDDLE_TOKEN,
302 line => $line, column => $column};
303 $column += $+[0] - $-[0] if $s =~ s/^:[\x09\x20]*//;
304 $tokenize_text->(\$s);
305 }
306 $continuous_line = 1;
307 return shift @nt;
308 } elsif ($s =~ s/^(>+)//) {
309 my $depth = length $1;
310 if ($depth == 2 and $s =~ /^[0-9]/) {
311 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
312 line => $line, column => $column}
313 if $continuous_line;
314 $s = '>>' . $s;
315 $tokenize_text->(\$s);
316 $continuous_line = 1;
317 } else {
318 push @nt, {type => QUOTATION_START_TOKEN, depth => $depth,
319 line => $line, column => $column};
320 $column += $depth;
321 $column += $+[0] - $-[0] if $s =~ s/^[\x09\x20]+//;
322 if ($s =~ s/^\@\@[\x09\x20]*//) {
323 push @nt, {type => EDITORIAL_NOTE_START_TOKEN,
324 line => $line, column => $column};
325 $column += $+[0] - $-[0];
326 $continuous_line = 1;
327 } elsif ($s =~ s/^;;[\x09\x20]*//) {
328 push @nt, {type => COMMENT_PARAGRAPH_START_TOKEN,
329 line => $line, column => $column};
330 $column += $+[0] - $-[0];
331 $continuous_line = 1;
332 } elsif (length $s) {
333 $continuous_line = 1;
334 } else {
335 $continuous_line = 0;
336 }
337 $tokenize_text->(\$s);
338 }
339 return shift @nt;
340 } elsif ($s =~ /\A\[(INS|DEL)(?>\(([^()\\]*)\))?\[[\x09\x20]*\z/) {
341 undef $continuous_line;
342 return {type => BLOCK_START_TAG_TOKEN, tag_name => $1,
343 classes => $2,
344 line => $line, column => $column};
345 } elsif ($s =~ /\A\[PRE(?>\(([^()\\]*)\))?\[[\x09\x20]*\z/) {
346 undef $continuous_line;
347 push @nt, {type => BLOCK_START_TAG_TOKEN, tag_name => 'PRE',
348 classes => $1,
349 line => $line, column => $column};
350 while (@s) {
351 my $s = shift @s;
352 ($line, $column) = ($line + 1, 1);
353 if ($s =~ /\A\]PRE\][\x09\x20]*\z/) {
354 push @nt, {type => BLOCK_END_TAG_TOKEN, tag_name => 'PRE',
355 line => $line, column => $column};
356 undef $continuous_line;
357 last;
358 } else {
359 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
360 line => $line, column => $column}
361 if $continuous_line;
362 $tokenize_text->(\$s);
363 $continuous_line = 1;
364 }
365 }
366 return shift @nt;
367 } elsif ($s =~ s/^\@\@[\x09\x20]*//) {
368 push @nt, {type => EDITORIAL_NOTE_START_TOKEN,
369 line => $line, column => $column};
370 $column += $+[0] - $-[0];
371 $tokenize_text->(\$s);
372 $continuous_line = 1;
373 return shift @nt;
374 } elsif ($s =~ s/^;;[\x09\x20]*//) {
375 push @nt, {type => COMMENT_PARAGRAPH_START_TOKEN,
376 line => $line, column => $column};
377 $column += $+[0] - $-[0];
378 $tokenize_text->(\$s);
379 $continuous_line = 1;
380 return shift @nt;
381 } elsif ($s =~ /\A\](INS|DEL)\][\x09\x20]*\z/) {
382 $continuous_line = 1;
383 return {type => BLOCK_END_TAG_TOKEN, tag_name => $1,
384 line => $line, column => $column};
385 } elsif ($s =~ /^,/) {
386 push @nt, {type => TABLE_ROW_START_TOKEN,
387 line => $line, column => $column};
388 while ($s =~ s/^,[\x09\x20]*//) {
389 $column += $+[0] - $-[0];
390 my $cell;
391 my $cell_quoted;
392 my $column_quoted = $column;
393 my $column_cell = $column;
394 if ($s =~ s/^"//) {
395 $s =~ s/^((?>[^"\\]|\\.)*)//;
396 $cell_quoted = $1;
397 $column += 1 + length $cell_quoted;
398 $cell_quoted =~ s/\\(.)/$1/sg;
399 $column++ if $s =~ s/\A\\\z//;
400 $column++ if $s =~ s/^"//;
401 }
402 if ($s =~ s/^([^,]+)//) {
403 $cell = $1;
404 $column += length $cell;
405 $cell =~ s/[\x09\x20]+\z//;
406 }
407 if (not defined $cell_quoted and defined $cell and
408 $cell eq '==') {
409 push @nt, {type => TABLE_COLSPAN_CELL_TOKEN,
410 line => $line, column => $column_cell};
411 } else {
412 push @nt, {type => TABLE_CELL_START_TOKEN,
413 line => $line,
414 column => defined $column_quoted ? $column_quoted: $column_cell};
415 my $real_column = $column;
416 $column = $column_quoted + 1;
417 $tokenize_text->(\$cell_quoted) if defined $cell_quoted;
418 ## NOTE: When a quoted-pair is used, column numbers
419 ## reported in this $tokenize_text call might be wrong.
420 $column = $column_cell;
421 $tokenize_text->(\$cell) if defined $cell;
422 $column = $column_quoted;
423 push @nt, {type => TABLE_CELL_END_TOKEN,
424 line => $line,
425 column => $column};
426 }
427 }
428 push @nt, {type => TABLE_ROW_END_TOKEN,
429 line => $line, column => $column};
430 undef $continuous_line;
431 return shift @nt;
432 } elsif ($s eq '__IMAGE__') {
433 my $image = $doc->create_element_ns (SW09_NS, [undef, 'image']);
434 $image->set_user_data (manakai_source_line => $line);
435 $image->set_user_data (manakai_source_column => 1);
436 $image->text_content (join "\x0A", @s);
437 ($line, $column) = ($line + @s, 1);
438 @s = ();
439 $doc->document_element->append_child ($image);
440 return {type => END_OF_FILE_TOKEN,
441 line => $line, column => $column};
442 } else {
443 push @nt, {type => CHARACTER_TOKEN, data => "\x0A",
444 line => $line, column => $column} if $continuous_line;
445 $tokenize_text->(\$s);
446 $continuous_line = 1;
447 return shift @nt;
448 }
449 }; # $get_next_token
450
451 ## NOTE: The "initial" mode.
452 if (@s and $s[0] =~ s/^#\?//) {
453 ## NOTE: "Parse a magic line".
454
455 my $s = shift @s;
456 if ($s =~ s/^([^\x09\x20]+)//) {
457 $column += $+[0] - $-[0];
458 my ($name, $version) = split m#/#, $1, 2;
459 my $el = $doc->document_element;
460 $el->set_attribute_ns (SW09_NS, ['sw', 'Name'] => $name);
461 $el->set_attribute_ns (SW09_NS, ['sw', 'Version'] => $version)
462 if defined $version;
463 }
464
465 while (length $s) {
466 $column += $+[0] - $-[0] and next if $s =~ s/^[\x09\x20]+//;
467 my $name = '';
468 if ($s =~ s/^([^=]*)=//) {
469 $name = $1;
470 $column += length $name + 1;
471 }
472 my $param = $doc->create_element_ns (SW09_NS, [undef, 'parameter']);
473 $param->set_attribute_ns (undef, [undef, 'name'] => $name);
474 $param->set_user_data (manakai_source_line => $line);
475 $param->set_user_data (manakai_source_column => $column);
476 $head_el->append_child ($param);
477
478 $column++ if $s =~ s/^"//;
479 if ($s =~ s/^([^"]*)//) {
480 my $values = $1;
481 $column += length $values;
482 $values =~ tr/\\//d;
483 my @values = split /,/, $values, -1;
484 push @values, '' unless length $values;
485 for (@values) {
486 my $value = $doc->create_element_ns (SW09_NS, [undef, 'value']);
487 $value->text_content ($_);
488 $value->set_user_data (manakai_source_line => $line);
489 $value->set_user_data (manakai_source_column => $column);
490 $param->append_child ($value);
491 }
492 }
493 $column++ if $s =~ s/^"//;
494 }
495
496 $line = 2;
497 $column = 1;
498 }
499
500 ## NOTE: Switched to the "body" mode.
501
502 my $oe = [{node => $body_el,
503 section_depth => 0,
504 quotation_depth => 0,
505 list_depth => 0}];
506 my $structural_elements = {
507 body => 1, section => 1, insert => 1, delete => 1, blockquote => 1,
508 h1 => 1, ul => 1, ol => 1, dl => 1, li => 1, dt => 1, dd => 1,
509 table => 1, tbody => 1, tr => 1, td => 1, p => 1, 'comment-p' => 1,
510 ed => 1, pre => 1,
511 };
512
513 my $im = IN_SECTION_IM;
514 $token = $get_next_token->();
515
516 A: {
517 if ($im == IN_PARAGRAPH_IM) {
518 if ($token->{type} == CHARACTER_TOKEN) {
519 $oe->[-1]->{node}->manakai_append_text ($token->{data});
520 $token = $get_next_token->();
521 redo A;
522 } elsif ($token->{type} == INLINE_START_TAG_TOKEN) {
523 if (not defined $token->{tag_name}) {
524 my $el = $doc->create_element_ns (SW09_NS, [undef, 'anchor']);
525 $oe->[-1]->{node}->append_child ($el);
526 push @$oe, {%{$oe->[-1]}, node => $el};
527 $el->set_user_data (manakai_source_line => $token->{line});
528 $el->set_user_data (manakai_source_column => $token->{column});
529
530 $token = $get_next_token->();
531 redo A;
532 } else {
533 my $type = {
534 AA => [AA_NS, 'aa'],
535 ABBR => [HTML_NS, 'abbr'],
536 CITE => [HTML_NS, 'cite'],
537 CODE => [HTML_NS, 'code'],
538 CSECTION => [SW10_NS, 'csection'],
539 DEL => [HTML_NS, 'del'],
540 DFN => [HTML_NS, 'dfn'],
541 INS => [HTML_NS, 'ins'],
542 KBD => [HTML_NS, 'kbd'],
543 KEY => [SW10_NS, 'key'],
544 Q => [HTML_NS, 'q'],
545 QN => [SW10_NS, 'qn'],
546 RUBY => [HTML_NS, 'ruby'],
547 RUBYB => [SW09_NS, 'rubyb'],
548 SAMP => [HTML_NS, 'samp'],
549 SPAN => [HTML_NS, 'span'],
550 SRC => [SW10_NS, 'src'],
551 SUB => [HTML_NS, 'sub'],
552 SUP => [HTML_NS, 'sup'],
553 TIME => [HTML_NS, 'time'],
554 VAR => [HTML_NS, 'var'],
555 WEAK => [SW09_NS, 'weak'],
556 }->{$token->{tag_name}} || [SW10_NS, $token->{tag_name}];
557 my $el = $doc->create_element_ns ($type->[0], [undef, $type->[1]]);
558 $oe->[-1]->{node}->append_child ($el);
559 push @$oe, {%{$oe->[-1]}, node => $el};
560 $el->set_user_data (manakai_source_line => $token->{line});
561 $el->set_user_data (manakai_source_column => $token->{column});
562
563 $el->set_attribute_ns (undef, [undef, 'class'] => $token->{classes})
564 if defined $token->{classes};
565 $el->set_attribute_ns (XML_NS, ['xml', 'lang'] => $token->{language})
566 if defined $token->{language};
567
568 $token = $get_next_token->();
569 redo A;
570 }
571 } elsif ($token->{type} == INLINE_MIDDLE_TAG_TOKEN) {
572 my ($ns, $ln, $pop) = @{{
573 rt => [HTML_NS, 'rt', 1],
574 title => [SW10_NS, 'attrvalue', 1],
575 nsuri => [SW10_NS, 'attrvalue', 1],
576 qn => [SW10_NS, 'nsuri'],
577 ruby => [HTML_NS, 'rt'],
578 rubyb => [HTML_NS, 'rt'],
579 }->{$oe->[-1]->{node}->manakai_local_name} || [SW10_NS, 'title']};
580 pop @$oe if $pop;
581
582 my $el = $doc->create_element_ns ($ns, [undef, $ln]);
583 $oe->[-1]->{node}->append_child ($el);
584 push @$oe, {%{$oe->[-1]}, node => $el};
585 $el->set_user_data (manakai_source_line => $token->{line});
586 $el->set_user_data (manakai_source_column => $token->{column});
587
588 $el->set_attribute_ns (XML_NS, ['xml', 'lang'] => $token->{language})
589 if defined $token->{language};
590
591 $token = $get_next_token->();
592 redo A;
593 } elsif ($token->{type} == INLINE_END_TAG_TOKEN) {
594 pop @$oe if {
595 rt => 1, title => 1, nsuri => 1, attrvalue => 1,
596 }->{$oe->[-1]->{node}->manakai_local_name};
597
598 if ({%$structural_elements,
599 strong => 1, em => 1}->{$oe->[-1]->{node}->manakai_local_name}) {
600 unless (defined $token->{res_scheme} or defined $token->{anchor}) {
601 $oe->[-1]->{node}->manakai_append_text (']]');
602 push @$oe, $oe->[-1];
603 } else {
604 my $el = $doc->create_element_ns
605 (SW09_NS,
606 [undef, defined $token->{res_scheme}
607 ? 'anchor-external' : 'anchor-internal']);
608 $oe->[-1]->{node}->append_child ($el);
609 push @$oe, {%{$oe->[-1]}, node => $el};
610 $el->set_user_data (manakai_source_line => $token->{line});
611 $el->set_user_data (manakai_source_column => $token->{column});
612 $el->text_content (']]');
613 }
614 }
615
616 $oe->[-1]->{node}->set_attribute_ns (SW09_NS, ['sw', 'anchor'],
617 $token->{anchor})
618 if defined $token->{anchor};
619 $oe->[-1]->{node}->set_attribute_ns (SW09_NS, ['sw', 'resScheme'],
620 $token->{res_scheme})
621 if defined $token->{res_scheme};
622 $oe->[-1]->{node}->set_attribute_ns (SW09_NS, ['sw', 'resParameter'],
623 $token->{res_parameter})
624 if defined $token->{res_parameter};
625
626 pop @$oe;
627
628 $token = $get_next_token->();
629 redo A;
630 } elsif ($token->{type} == STRONG_TOKEN) {
631 if ($oe->[-1]->{node}->manakai_local_name eq 'strong') {
632 pop @$oe;
633 } else {
634 my $el = $doc->create_element_ns (HTML_NS, [undef, 'strong']);
635 $oe->[-1]->{node}->append_child ($el);
636 push @$oe, {%{$oe->[-1]}, node => $el};
637 $el->set_user_data (manakai_source_line => $token->{line});
638 $el->set_user_data (manakai_source_column => $token->{column});
639 }
640 $token = $get_next_token->();
641 redo A;
642 } elsif ($token->{type} == EMPHASIS_TOKEN) {
643 if ($oe->[-1]->{node}->manakai_local_name eq 'em') {
644 pop @$oe;
645 } else {
646 my $el = $doc->create_element_ns (HTML_NS, [undef, 'em']);
647 $oe->[-1]->{node}->append_child ($el);
648 push @$oe, {%{$oe->[-1]}, node => $el};
649 $el->set_user_data (manakai_source_line => $token->{line});
650 $el->set_user_data (manakai_source_column => $token->{column});
651 }
652 $token = $get_next_token->();
653 redo A;
654 } elsif ($token->{type} == FORM_TOKEN) {
655 ## There is an exact code clone.
656 if ($token->{name} eq 'form') {
657 my $el = $doc->create_element_ns (SW09_NS, [undef, 'form']);
658 $oe->[-1]->{node}->append_child ($el);
659 $el->set_user_data (manakai_source_line => $token->{line});
660 $el->set_user_data (manakai_source_column => $token->{column});
661
662 $el->set_attribute_ns (undef, [undef, 'id']
663 => $token->{id}) if defined $token->{id};
664 $el->set_attribute_ns (undef, [undef, 'input']
665 => shift @{$token->{parameters}})
666 if @{$token->{parameters}};
667 $el->set_attribute_ns (undef, [undef, 'template']
668 => shift @{$token->{parameters}})
669 if @{$token->{parameters}};
670 $el->set_attribute_ns (undef, [undef, 'option']
671 => shift @{$token->{parameters}})
672 if @{$token->{parameters}};
673 $el->set_attribute_ns (undef, [undef, 'parameter']
674 => join ':', @{$token->{parameters}})
675 if @{$token->{parameters}};
676
677 $token = $get_next_token->();
678 redo A;
679 } else {
680 my $el = $doc->create_element_ns (SW09_NS, [undef, 'form']);
681 $oe->[-1]->{node}->append_child ($el);
682 $el->set_user_data (manakai_source_line => $token->{line});
683 $el->set_user_data (manakai_source_column => $token->{column});
684
685 $el->set_attribute_ns (undef, [undef, 'ref']
686 => $token->{name});
687 $el->set_attribute_ns (undef, [undef, 'id']
688 => $token->{id}) if defined $token->{id};
689 $el->set_attribute_ns (undef, [undef, 'parameter']
690 => join ':', @{$token->{parameters}})
691 if @{$token->{parameters}};
692
693 $token = $get_next_token->();
694 redo A;
695 }
696 } elsif ($token->{type} == ELEMENT_TOKEN) {
697 ## NOTE: There is an exact code clone.
698 my $el = $doc->create_element_ns
699 ($token->{namespace}, [undef, $token->{local_name}]);
700 $oe->[-1]->{node}->append_child ($el);
701 $el->set_user_data (manakai_source_line => $token->{line});
702 $el->set_user_data (manakai_source_column => $token->{column});
703
704 $el->set_attribute_ns (SW09_NS, ['sw', 'anchor'], $token->{anchor})
705 if defined $token->{anchor};
706 $el->set_attribute_ns (undef, [undef, 'by']
707 => $token->{by}) if defined $token->{by};
708 $el->set_attribute_ns (SW09_NS, ['sw', 'resScheme'],
709 $token->{res_scheme})
710 if defined $token->{res_scheme};
711 $el->set_attribute_ns (SW09_NS, ['sw', 'resParameter'],
712 $token->{res_parameter})
713 if defined $token->{res_parameter};
714 $el->text_content ($token->{content}) if defined $token->{content};
715
716 $token = $get_next_token->();
717 redo A;
718 } elsif ($token->{type} == LABELED_LIST_MIDDLE_TOKEN) {
719 pop @$oe while not $structural_elements
720 ->{$oe->[-1]->{node}->manakai_local_name};
721 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'dt';
722
723 my $el = $doc->create_element_ns (HTML_NS, [undef, 'dd']);
724 $oe->[-1]->{node}->append_child ($el);
725 push @$oe, {%{$oe->[-1]}, node => $el};
726 $el->set_user_data (manakai_source_line => $token->{line});
727 $el->set_user_data (manakai_source_column => $token->{column});
728
729 $token = $get_next_token->();
730 redo A;
731 } elsif ($token->{type} == HEADING_END_TOKEN) {
732 pop @$oe while not $structural_elements
733 ->{$oe->[-1]->{node}->manakai_local_name};
734 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'h1';
735
736 $im = IN_SECTION_IM;
737 $token = $get_next_token->();
738 redo A;
739 } elsif ($token->{type} == TABLE_CELL_END_TOKEN) {
740 pop @$oe while not $structural_elements
741 ->{$oe->[-1]->{node}->manakai_local_name};
742 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'td';
743
744 $im = IN_TABLE_ROW_IM;
745 $token = $get_next_token->();
746 redo A;
747 } elsif (($token->{type} == BLOCK_END_TAG_TOKEN and
748 $token->{tag_name} eq 'PRE') or
749 $token->{type} == PREFORMATTED_END_TOKEN) {
750 pop @$oe while not $structural_elements
751 ->{$oe->[-1]->{node}->manakai_local_name};
752 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'pre';
753
754 $im = IN_SECTION_IM;
755 $token = $get_next_token->();
756 redo A;
757 } else {
758 pop @$oe while not $structural_elements
759 ->{$oe->[-1]->{node}->manakai_local_name};
760
761 $im = IN_SECTION_IM;
762 ## Reconsume.
763 redo A;
764 }
765 } elsif ($im == IN_SECTION_IM) {
766 if ($token->{type} == HEADING_START_TOKEN) {
767 B: {
768 pop @$oe and redo B
769 if not {body => 1, section => 1, insert => 1, delete => 1}
770 ->{$oe->[-1]->{node}->manakai_local_name} or
771 $token->{depth} <= $oe->[-1]->{section_depth};
772 if ($token->{depth} > $oe->[-1]->{section_depth} + 1) {
773 my $el = $doc->create_element_ns (HTML_NS, [undef, 'section']);
774 $oe->[-1]->{node}->append_child ($el);
775 push @$oe, {node => $el,
776 section_depth => $oe->[-1]->{section_depth} + 1,
777 quotation_depth => 0, list_depth => 0};
778 redo B;
779 }
780 } # B
781
782 my $el = $doc->create_element_ns (HTML_NS, [undef, 'section']);
783 $oe->[-1]->{node}->append_child ($el);
784 push @$oe, {node => $el,
785 section_depth => $oe->[-1]->{section_depth} + 1,
786 quotation_depth => 0, list_depth => 0};
787
788 my $el2 = $doc->create_element_ns (HTML_NS, [undef, 'h1']);
789 $oe->[-1]->{node}->append_child ($el2);
790 push @$oe, {%{$oe->[-1]}, node => $el2};
791
792 $im = IN_PARAGRAPH_IM;
793 $token = $get_next_token->();
794 redo A;
795 } elsif ($token->{type} == BLOCK_START_TAG_TOKEN and
796 ($token->{tag_name} eq 'INS' or
797 $token->{tag_name} eq 'DEL')) {
798 my $el = $doc->create_element_ns
799 (SW09_NS,
800 [undef, $token->{tag_name} eq 'INS' ? 'insert' : 'delete']);
801 $oe->[-1]->{node}->append_child ($el);
802 push @$oe, {node => $el, section_depth => 0,
803 quotation_depth => 0, list_depth => 0};
804 $el->set_attribute_ns (undef, [undef, 'class'] => $token->{classes})
805 if defined $token->{classes};
806 $token = $get_next_token->();
807 redo A;
808 } elsif ($token->{type} == QUOTATION_START_TOKEN) {
809 B: {
810 pop @$oe and redo B
811 if not {body => 1, section => 1, insert => 1, delete => 1,
812 blockquote => 1}
813 ->{$oe->[-1]->{node}->manakai_local_name} or
814 $token->{depth} < $oe->[-1]->{quotation_depth};
815 if ($token->{depth} > $oe->[-1]->{quotation_depth}) {
816 my $el = $doc->create_element_ns (HTML_NS, [undef, 'blockquote']);
817 $oe->[-1]->{node}->append_child ($el);
818 push @$oe, {node => $el, section_depth => 0,
819 quotation_depth => $oe->[-1]->{quotation_depth} + 1,
820 list_depth => 0};
821 redo B;
822 }
823 } # B
824
825 $token = $get_next_token->();
826 redo A;
827 } elsif ($token->{type} == LIST_START_TOKEN) {
828 my $depth = length $token->{depth};
829 my $list_type = substr ($token->{depth}, -1, 1) eq '-' ? 'ul' : 'ol';
830 B: {
831 pop @$oe and redo B if $oe->[-1]->{list_depth} > $depth;
832 pop @$oe and redo B if $oe->[-1]->{list_depth} == $depth and
833 $list_type ne $oe->[-1]->{node}->manakai_local_name;
834 if ($oe->[-1]->{list_depth} < $depth) {
835 my $type = substr $token->{depth}, $oe->[-1]->{list_depth}, 1;
836 my $el = $doc->create_element_ns
837 (HTML_NS, [undef, $type eq '-' ? 'ul' : 'ol']);
838 $oe->[-1]->{node}->append_child ($el);
839 push @$oe, {%{$oe->[-1]}, node => $el,
840 list_depth => $oe->[-1]->{list_depth} + 1};
841 if ($oe->[-1]->{list_depth} < $depth) {
842 my $el = $doc->create_element_ns (HTML_NS, [undef, 'li']);
843 $oe->[-1]->{node}->append_child ($el);
844 push @$oe, {%{$oe->[-1]}, node => $el};
845 }
846 redo B;
847 }
848 } # B
849
850 my $el = $doc->create_element_ns (HTML_NS, [undef, 'li']);
851 $oe->[-1]->{node}->append_child ($el);
852 push @$oe, {%{$oe->[-1]}, node => $el};
853
854 $im = IN_PARAGRAPH_IM;
855 $token = $get_next_token->();
856 redo A;
857 } elsif ($token->{type} == LABELED_LIST_START_TOKEN) {
858 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'dd';
859 if ($oe->[-1]->{node}->manakai_local_name ne 'dl') {
860 my $el = $doc->create_element_ns (HTML_NS, [undef, 'dl']);
861 $oe->[-1]->{node}->append_child ($el);
862 push @$oe, {%{$oe->[-1]}, node => $el};
863 }
864
865 my $el = $doc->create_element_ns (HTML_NS, [undef, 'dt']);
866 $oe->[-1]->{node}->append_child ($el);
867 push @$oe, {%{$oe->[-1]}, node => $el};
868
869 $im = IN_PARAGRAPH_IM;
870 $token = $get_next_token->();
871 redo A;
872 } elsif ($token->{type} == TABLE_ROW_START_TOKEN) {
873 my $el = $doc->create_element_ns (HTML_NS, [undef, 'table']);
874 $oe->[-1]->{node}->append_child ($el);
875 push @$oe, {%{$oe->[-1]}, node => $el};
876
877 $el = $doc->create_element_ns (HTML_NS, [undef, 'tbody']);
878 $oe->[-1]->{node}->append_child ($el);
879 push @$oe, {%{$oe->[-1]}, node => $el};
880
881 $el = $doc->create_element_ns (HTML_NS, [undef, 'tr']);
882 $oe->[-1]->{node}->append_child ($el);
883 push @$oe, {%{$oe->[-1]}, node => $el};
884
885 $im = IN_TABLE_ROW_IM;
886 $token = $get_next_token->();
887 redo A;
888 } elsif (($token->{type} == BLOCK_START_TAG_TOKEN and
889 $token->{tag_name} eq 'PRE') or
890 $token->{type} == PREFORMATTED_START_TOKEN) {
891 my $el = $doc->create_element_ns (HTML_NS, [undef, 'pre']);
892 $oe->[-1]->{node}->append_child ($el);
893 push @$oe, {%{$oe->[-1]}, node => $el};
894
895 $el->set_attribute_ns (undef, [undef, 'class'] => $token->{classes})
896 if defined $token->{classes};
897
898 $im = IN_PARAGRAPH_IM;
899 $token = $get_next_token->();
900 redo A;
901 } elsif ($token->{type} == COMMENT_PARAGRAPH_START_TOKEN) {
902 my $el = $doc->create_element_ns (SW10_NS, [undef, 'comment-p']);
903 $oe->[-1]->{node}->append_child ($el);
904 push @$oe, {%{$oe->[-1]}, node => $el};
905
906 $im = IN_PARAGRAPH_IM;
907 $token = $get_next_token->();
908 redo A;
909 } elsif ($token->{type} == EDITORIAL_NOTE_START_TOKEN) {
910 my $el = $doc->create_element_ns (SW10_NS, [undef, 'ed']);
911 $oe->[-1]->{node}->append_child ($el);
912 push @$oe, {%{$oe->[-1]}, node => $el};
913
914 $im = IN_PARAGRAPH_IM;
915 $token = $get_next_token->();
916 redo A;
917 } elsif ($token->{type} == EMPTY_LINE_TOKEN) {
918 pop @$oe while not {body => 1, section => 1, insert => 1, delete => 1}
919 ->{$oe->[-1]->{node}->manakai_local_name};
920 $token = $get_next_token->();
921 redo A;
922 } elsif ($token->{type} == BLOCK_END_TAG_TOKEN) {
923 if ($token->{tag_name} eq 'INS') {
924 for (reverse 1..$#$oe) {
925 if ($oe->[$_]->{node}->manakai_local_name eq 'insert') {
926 splice @$oe, $_;
927 last;
928 }
929 }
930 } elsif ($token->{tag_name} eq 'DEL') {
931 for (reverse 1..$#$oe) {
932 if ($oe->[$_]->{node}->manakai_local_name eq 'delete') {
933 splice @$oe, $_;
934 last;
935 }
936 }
937 } else {
938 ## NOTE: Ignore the token.
939 }
940 undef $continuous_line;
941 $token = $get_next_token->();
942 redo A;
943 } elsif ($token->{type} == FORM_TOKEN) {
944 ## There is an exact code clone.
945 if ($token->{name} eq 'form') {
946 my $el = $doc->create_element_ns (SW09_NS, [undef, 'form']);
947 $oe->[-1]->{node}->append_child ($el);
948 $el->set_user_data (manakai_source_line => $token->{line});
949 $el->set_user_data (manakai_source_column => $token->{column});
950
951 $el->set_attribute_ns (undef, [undef, 'id']
952 => $token->{id}) if defined $token->{id};
953 $el->set_attribute_ns (undef, [undef, 'input']
954 => shift @{$token->{parameters}})
955 if @{$token->{parameters}};
956 $el->set_attribute_ns (undef, [undef, 'template']
957 => shift @{$token->{parameters}})
958 if @{$token->{parameters}};
959 $el->set_attribute_ns (undef, [undef, 'option']
960 => shift @{$token->{parameters}})
961 if @{$token->{parameters}};
962 $el->set_attribute_ns (undef, [undef, 'parameter']
963 => join ':', @{$token->{parameters}})
964 if @{$token->{parameters}};
965
966 $token = $get_next_token->();
967 redo A;
968 } else {
969 my $el = $doc->create_element_ns (SW09_NS, [undef, 'form']);
970 $oe->[-1]->{node}->append_child ($el);
971 $el->set_user_data (manakai_source_line => $token->{line});
972 $el->set_user_data (manakai_source_column => $token->{column});
973
974 $el->set_attribute_ns (undef, [undef, 'ref'] => $token->{name});
975 $el->set_attribute_ns (undef, [undef, 'id']
976 => $token->{id}) if defined $token->{id};
977 $el->set_attribute_ns (undef, [undef, 'parameter']
978 => join ':', @{$token->{parameters}})
979 if @{$token->{parameters}};
980
981 $token = $get_next_token->();
982 redo A;
983 }
984 } elsif ($token->{type} == ELEMENT_TOKEN and
985 $token->{local_name} eq 'replace') {
986 ## NOTE: There is an exact code clone.
987 my $el = $doc->create_element_ns
988 ($token->{namespace}, [undef, $token->{local_name}]);
989 $oe->[-1]->{node}->append_child ($el);
990 $el->set_user_data (manakai_source_line => $token->{line});
991 $el->set_user_data (manakai_source_column => $token->{column});
992
993 $el->set_attribute_ns (SW09_NS, ['sw', 'anchor'], $token->{anchor})
994 if defined $token->{anchor};
995 $el->set_attribute_ns (undef, [undef, 'by']
996 => $token->{by}) if defined $token->{by};
997 $el->set_attribute_ns (SW09_NS, ['sw', 'resScheme'],
998 $token->{res_scheme})
999 if defined $token->{res_scheme};
1000 $el->set_attribute_ns (SW09_NS, ['sw', 'resParameter'],
1001 $token->{res_parameter})
1002 if defined $token->{res_parameter};
1003 $el->text_content ($token->{content}) if defined $token->{content};
1004
1005 $token = $get_next_token->();
1006 redo A;
1007 } elsif ($token->{type} == END_OF_FILE_TOKEN) {
1008 return;
1009 } elsif ({LABELED_LIST_MIDDLE_TOKEN => 1,
1010 HEADING_END_TOKEN => 1,
1011 PREFORMATTED_END_TOKEN => 1,
1012 TABLE_ROW_END_TOKEN => 1,
1013 TABLE_CELL_START_TOKEN => 1,
1014 TABLE_CELL_END_TOKEN => 1,
1015 TABLE_COLSPAN_CELL_TOKEN => 1}->{$token->{type}}) {
1016 ## NOTE: Ignore the token.
1017 } else {
1018 unless ({dd => 1,
1019 li => 1,
1020 'comment-p' => 1,
1021 ed => 1}->{$oe->[-1]->{node}->manakai_local_name}) {
1022 my $el = $doc->create_element_ns (HTML_NS, [undef, 'p']);
1023 $oe->[-1]->{node}->append_child ($el);
1024 push @$oe, {%{$oe->[-1]}, node => $el};
1025 }
1026
1027 $im = IN_PARAGRAPH_IM;
1028 ## Reprocess.
1029 redo A;
1030 }
1031 } elsif ($im == IN_TABLE_ROW_IM) {
1032 if ($token->{type} == TABLE_CELL_START_TOKEN) {
1033 my $el = $doc->create_element_ns (HTML_NS, [undef, 'td']);
1034 $oe->[-1]->{node}->append_child ($el);
1035 push @$oe, {%{$oe->[-1]}, node => $el};
1036 $el->set_user_data (manakai_source_line => $token->{line});
1037 $el->set_user_data (manakai_source_column => $token->{column});
1038
1039 $im = IN_PARAGRAPH_IM;
1040 $token = $get_next_token->();
1041 redo A;
1042 } elsif ($token->{type} == TABLE_COLSPAN_CELL_TOKEN) {
1043 my $lc = $oe->[-1]->{node}->last_child;
1044 if ($lc and $lc->manakai_local_name eq 'td') {
1045 $lc->set_attribute_ns
1046 (undef, [undef, 'colspan'],
1047 ($lc->get_attribute_ns (undef, 'colspan') || 1) + 1);
1048 } else {
1049 my $el = $doc->create_element_ns (HTML_NS, [undef, 'td']);
1050 $oe->[-1]->{node}->append_child ($el);
1051 $el->set_user_data (manakai_source_line => $token->{line});
1052 $el->set_user_data (manakai_source_column => $token->{column});
1053 }
1054
1055 $token = $get_next_token->();
1056 redo A;
1057 } elsif ($token->{type} == TABLE_ROW_END_TOKEN) {
1058 pop @$oe if $oe->[-1]->{node}->manakai_local_name eq 'tr';
1059 $token = $get_next_token->();
1060 redo A;
1061 } elsif ($token->{type} == TABLE_ROW_START_TOKEN) {
1062 my $el = $doc->create_element_ns (HTML_NS, [undef, 'tr']);
1063 $oe->[-1]->{node}->append_child ($el);
1064 push @$oe, {%{$oe->[-1]}, node => $el};
1065 $el->set_user_data (manakai_source_line => $token->{line});
1066 $el->set_user_data (manakai_source_column => $token->{column});
1067
1068 $token = $get_next_token->();
1069 redo A;
1070 } else {
1071 $im = IN_SECTION_IM;
1072 ## Reprocess.
1073 redo A;
1074 }
1075 } else {
1076 die "$0: Unknown insertion mode: $im";
1077 }
1078 } # A
1079 } # parse_char_string
1080
1081 1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24