1 |
#!/usr/bin/perl |
2 |
use strict; |
3 |
require 'uricls.pl'; |
4 |
our $LIST; |
5 |
|
6 |
my %argv; |
7 |
for (@ARGV) { |
8 |
$argv{$1} = 1 if /^--([^\s=]+)$/; |
9 |
} |
10 |
if ($argv{help}) { |
11 |
require Pod::Usage; |
12 |
Pod::Usage::pod2usage (-exitval => 0, -verbose => 1); |
13 |
} |
14 |
|
15 |
sub add (%) { |
16 |
my (%opt) = @_; |
17 |
push @{$opt{table}->[0]}, $opt{name}; |
18 |
push @{$opt{table}->[$_]}, [] for 1..$#{$opt{table}}; |
19 |
for my $class (sort keys %{$opt{list}}) { |
20 |
ELEMENT: for my $element (@{$opt{list}->{$class}}) { |
21 |
for (@{$opt{table}}) { |
22 |
if ($_->[0] eq $element) { |
23 |
push @{$_->[-1]}, $class; |
24 |
next ELEMENT; |
25 |
} |
26 |
} |
27 |
my $row = [$element]; |
28 |
for (my $i = $#{$opt{table}->[0]} - 1; $i > 0; $i--) { |
29 |
push @$row, []; |
30 |
} |
31 |
push @$row, [$class]; |
32 |
push @{$opt{table}}, $row; |
33 |
} |
34 |
} |
35 |
} |
36 |
|
37 |
sub element ($) { |
38 |
my $el = shift; |
39 |
if (length $el > 1 || $el =~ /[A-Z%]/) { |
40 |
qq<<code>$el</code>>; |
41 |
} else { |
42 |
qq<<code class="char">$el</code>>; |
43 |
} |
44 |
} |
45 |
|
46 |
sub elements ($) { |
47 |
join ', ', map {element $_} @{$_[0]}; |
48 |
} |
49 |
|
50 |
sub serialize ($$) { |
51 |
my ($tbl, $span) = @_; |
52 |
my $r = q<<table border><thead><tr>>; |
53 |
$r .= join '', map {qq<<th>$_</th>>} @{$tbl->[0]}; |
54 |
$r .= q<</tr></thead><tbody>>; |
55 |
for my $i (1..$#$tbl) { |
56 |
$r .= q<<tr>>; |
57 |
$r .= q<<th>>.element ($tbl->[$i]->[0]).q<</th>>; |
58 |
for my $j (1..$#{$tbl->[$i]}) { |
59 |
if ($tbl->[$i]->[$j]) { |
60 |
$r .= q{<td}; |
61 |
$r .= q< rowspan=">.$span->[$i]->[$j]->{row}.q<"> if $span->[$i]->[$j]->{row}; |
62 |
$r .= q< colspan=">.$span->[$i]->[$j]->{col}.q<"> if $span->[$i]->[$j]->{col}; |
63 |
$r .= q{>}; |
64 |
$r .= elements ($tbl->[$i]->[$j]) || '-'; |
65 |
$r .= q<</td>>; |
66 |
} |
67 |
} |
68 |
$r .= qq<</tr>\n>; |
69 |
} |
70 |
$r .= qq<</tbody></table>\n>; |
71 |
$r; |
72 |
} |
73 |
|
74 |
sub equal ($$) { |
75 |
my ($x, $y) = @_; |
76 |
return 0 unless @$x and @$y; |
77 |
return 0 unless @$x == @$y; |
78 |
for (0..$#$x) { |
79 |
return 0 unless $x->[$_] eq $y->[$_]; |
80 |
} |
81 |
return 1; |
82 |
} |
83 |
|
84 |
sub merge_row ($$) { |
85 |
my ($tbl, $span) = @_; |
86 |
for my $i (1..($#$tbl-1)) { |
87 |
for my $j (1..$#{$tbl->[$i]}) { |
88 |
if ($tbl->[$i]->[$j]) { |
89 |
my $s = 1; |
90 |
for my $ii (($i+1)..$#$tbl) { |
91 |
if (equal $tbl->[$i]->[$j] => $tbl->[$ii]->[$j]) { |
92 |
$s++; |
93 |
$tbl->[$ii]->[$j] = 0; |
94 |
} else { |
95 |
last; |
96 |
} |
97 |
} |
98 |
$span->[$i]->[$j]->{row} = $s if $s > 1; |
99 |
} |
100 |
} |
101 |
} |
102 |
} |
103 |
|
104 |
sub merge_col ($$) { |
105 |
my ($tbl, $span) = @_; |
106 |
for my $i (1..$#$tbl) { |
107 |
for my $j (1..($#{$tbl->[$i]}-1)) { |
108 |
if ($tbl->[$i]->[$j]) { |
109 |
my $s = 1; |
110 |
for my $jj (($j+1)..$#{$tbl->[$i]}) { |
111 |
if ($tbl->[$i]->[$jj] and |
112 |
$span->[$i]->[$j]->{row} == $span->[$i]->[$jj]->{row} and |
113 |
equal $tbl->[$i]->[$j] => $tbl->[$i]->[$jj]) { |
114 |
$s++; |
115 |
$tbl->[$i]->[$jj] = 0; |
116 |
} else { |
117 |
last; |
118 |
} |
119 |
} |
120 |
$span->[$i]->[$j]->{col} = $s if $s > 1; |
121 |
} |
122 |
} |
123 |
} |
124 |
} |
125 |
|
126 |
sub remove_empty_row ($) { |
127 |
my @tbl = @{+shift}; |
128 |
ROW: for (my $i = $#tbl; $i > 1; $i--) { |
129 |
for my $j (1..$#{$tbl[$i]}) { |
130 |
next ROW if not $tbl[$i]->[$j] or |
131 |
@{$tbl[$i]->[$j]}; |
132 |
} |
133 |
delete $tbl[$i]; |
134 |
} |
135 |
[grep defined $_, @tbl]; |
136 |
} |
137 |
|
138 |
my $tbl = [map {[$_]} '', qw<alpha digit - _ . * ! ' ( ) , + : ; = $ @ & ? / [ ] { } \ ^ | ` % # " < > >, 'SP', '%x00-1F', '%x7F']; |
139 |
my @span; |
140 |
|
141 |
for (@$LIST) { |
142 |
add table => $tbl, name => $_->{name}, list => $_->{class}; |
143 |
} |
144 |
$tbl = remove_empty_row $tbl; |
145 |
merge_row $tbl, \@span; |
146 |
merge_col $tbl, \@span; |
147 |
|
148 |
print STDOUT qq<<!DOCTYPE table SYSTEM>\n>; |
149 |
print STDOUT serialize $tbl, \@span; |
150 |
|
151 |
=head1 NAME |
152 |
|
153 |
mkclstbl - URI Character Class History Table Generator |
154 |
|
155 |
=head1 SYNOPSIS |
156 |
|
157 |
mkclstbl.pl > table.html |
158 |
mkclstbl.pl --help |
159 |
|
160 |
=head1 DESCRIPTION |
161 |
|
162 |
This script generates an HTML table that describes what character belongs |
163 |
to what character class(es) in versions of URI specification. |
164 |
|
165 |
=head1 OPTIONS |
166 |
|
167 |
This script can be specified an arguments: |
168 |
|
169 |
=over 4 |
170 |
|
171 |
=item --help |
172 |
|
173 |
Show help message. |
174 |
|
175 |
=back |
176 |
|
177 |
=head1 SEE ALSO |
178 |
|
179 |
URI Specifications and DTDs. |
180 |
|
181 |
<http://suika.fam.cx/www/2004/uri/>. |
182 |
|
183 |
=head1 LICENSE |
184 |
|
185 |
Copyright 2004 Wakaba <w@suika.fam.cx> |
186 |
|
187 |
This program is free software; you can redistribute it and/or |
188 |
modify it under the same terms as Perl itself. |
189 |
|
190 |
=cut |
191 |
|
192 |
# $Date: 2004/07/18 13:42:08 $ |