/[suikacvs]/test/html-webhacc/cc.cgi
Suika

Diff of /test/html-webhacc/cc.cgi

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

revision 1.52 by wakaba, Fri Jul 18 14:44:16 2008 UTC revision 1.53 by wakaba, Sun Jul 20 14:58:24 2008 UTC
# Line 6  use lib qw[/home/httpd/html/www/markup/h Line 6  use lib qw[/home/httpd/html/www/markup/h
6             /home/wakaba/work/manakai2/lib];             /home/wakaba/work/manakai2/lib];
7  use CGI::Carp qw[fatalsToBrowser];  use CGI::Carp qw[fatalsToBrowser];
8  use Scalar::Util qw[refaddr];  use Scalar::Util qw[refaddr];
 use Time::HiRes qw/time/;  
9    
10  sub htescape ($) {    require WebHACC::Input;
11    my $s = $_[0];    require WebHACC::Result;
12    $s =~ s/&/&/g;    require WebHACC::Output;
13    $s =~ s/</&lt;/g;  
14    $s =~ s/>/&gt;/g;  my $out;
   $s =~ s/"/&quot;/g;  
   $s =~ s{([\x00-\x09\x0B-\x1F\x7F-\xA0\x{FEFF}\x{FFFC}-\x{FFFF}])}{  
     sprintf '<var>U+%04X</var>', ord $1;  
   }ge;  
   return $s;  
 } # htescape  
15    
   my @nav;  
   my %time;  
16    require Message::DOM::DOMImplementation;    require Message::DOM::DOMImplementation;
17    my $dom = Message::DOM::DOMImplementation->new;    my $dom = Message::DOM::DOMImplementation->new;
18  {  {
# Line 32  sub htescape ($) { Line 23  sub htescape ($) {
23      print STDOUT "Status: 404 Not Found\nContent-Type: text/plain; charset=us-ascii\n\n400";      print STDOUT "Status: 404 Not Found\nContent-Type: text/plain; charset=us-ascii\n\n400";
24      exit;      exit;
25    }    }
26      
   binmode STDOUT, ':utf8';  
   $| = 1;  
   
27    load_text_catalog ('en'); ## TODO: conneg    load_text_catalog ('en'); ## TODO: conneg
28    
29    print STDOUT qq[Content-Type: text/html; charset=utf-8    $out = WebHACC::Output->new;
30      $out->handle (*STDOUT);
31      $out->set_utf8;
32      $out->set_flush;
33      $out->html (qq[Content-Type: text/html; charset=utf-8
34    
35  <!DOCTYPE html>  <!DOCTYPE html>
36  <html lang="en">  <html lang="en">
# Line 49  sub htescape ($) { Line 41  sub htescape ($) {
41  <body>  <body>
42  <h1><a href="../cc-interface">Web Document Conformance Checker</a>  <h1><a href="../cc-interface">Web Document Conformance Checker</a>
43  (<em>beta</em>)</h1>  (<em>beta</em>)</h1>
44  ];  ]);
45    
   $| = 0;  
46    my $input = get_input_document ($http, $dom);    my $input = get_input_document ($http, $dom);
47      $out->input ($input);
48      $out->unset_flush;
49    
50    my $char_length = 0;    my $char_length = 0;
51    
52    print qq[    $out->start_section (id => 'document-info', title => 'Information');
53  <div id="document-info" class="section">    $out->html (qq[<dl>
54  <dl>  <dt>Request URL</dt>
55  <dt>Request URI</dt>      <dd>]);
56      <dd><code class="URI" lang="">&lt;<a href="@{[htescape $input->{request_uri}]}">@{[htescape $input->{request_uri}]}</a>&gt;</code></dd>    $out->url ($input->{request_uri});
57  <dt>Document URI</dt>    $out->html (q[<dt>Document URL<!-- HTML5 document's address? -->
58      <dd><code class="URI" lang="">&lt;<a href="@{[htescape $input->{uri}]}" id=anchor-document-uri>@{[htescape $input->{uri}]}</a>&gt;</code>      <dd>]);
59      $out->url ($input->{uri}, id => 'anchor-document-url');
60      $out->html (q[
61      <script>      <script>
62        document.title = '<'        document.title = '<'
63            + document.getElementById ('anchor-document-uri').href + '> \\u2014 '            + document.getElementById ('anchor-document-url').href + '> \\u2014 '
64            + document.title;            + document.title;
65      </script></dd>      </script>]);
66  ]; # no </dl> yet    ## NOTE: no </dl> yet
   push @nav, ['#document-info' => 'Information'];  
67    
68  if (defined $input->{s}) {    if (defined $input->{s}) {
69    $char_length = length $input->{s};      $char_length = length $input->{s};
70    
71    print STDOUT qq[      $out->html (qq[<dt>Base URI<dd>]);
72  <dt>Base URI</dt>      $out->url ($input->{base_uri});
73      <dd><code class="URI" lang="">&lt;<a href="@{[htescape $input->{base_uri}]}">@{[htescape $input->{base_uri}]}</a>&gt;</code></dd>      $out->html (qq[<dt>Internet Media Type</dt>
74  <dt>Internet Media Type</dt>      <dd><code class="MIME" lang="en">]);
75      <dd><code class="MIME" lang="en">@{[htescape $input->{media_type}]}</code>      $out->text ($input->{media_type});
76      @{[$input->{media_type_overridden} ? '<em>(overridden)</em>' : defined $input->{official_type} ? $input->{media_type} eq $input->{official_type} ? '' : '<em>(sniffed; official type is: <code class=MIME lang=en>'.htescape ($input->{official_type}).'</code>)' : '<em>(sniffed)</em>']}</dd>      $out->html (qq[</code> ]);
77  <dt>Character Encoding</dt>      if ($input->{media_type_overridden}) {
78      <dd>@{[defined $input->{charset} ? '<code class="charset" lang="en">'.htescape ($input->{charset}).'</code>' : '(none)']}        $out->html ('<em>(overridden)</em>');
79      @{[$input->{charset_overridden} ? '<em>(overridden)</em>' : '']}</dd>      } elsif (defined $input->{official_type}) {
80          if ($input->{media_type} eq $input->{official_type}) {
81            #
82          } else {
83            $out->html ('<em>(sniffed; official type is: <code class=MIME lang=en>');
84            $out->text ($input->{official_type});
85            $out->html ('</code>)');
86          }
87        } else {
88          $out->html ('<em>(sniffed)</em>');
89        }
90        $out->html (q[<dt>Character Encoding<dd>]);
91        if (defined $input->{charset}) {
92          $out->html ('<code class="charset" lang="en">');
93          $out->text ($input->{charset});
94          $out->html ('</code>');
95        } else {
96          $out->text ('(none)');
97        }
98        $out->html (' <em>overridden</em>') if $input->{charset_overridden};
99        $out->html (qq[
100  <dt>Length</dt>  <dt>Length</dt>
101      <dd>$char_length byte@{[$char_length == 1 ? '' : 's']}</dd>      <dd>$char_length byte@{[$char_length == 1 ? '' : 's']}</dd>
102  </dl>  </dl>
 </div>  
103    
104  <script src="../cc-script.js"></script>  <script src="../cc-script.js"></script>
105  ];  ]);
106        $out->end_section;
   $input->{id_prefix} = '';  
   #$input->{nested} = 0;  
   my $result = {conforming_min => 1, conforming_max => 1};  
   check_and_print ($input => $result);  
   print_result_section ($result);  
 } else {  
   print STDOUT qq[</dl></div>];  
   print_result_input_error_section ($input);  
 }  
107    
108    print STDOUT qq[      my $result = WebHACC::Result->new;
109  <ul class="navigation" id="nav-items">      $result->{conforming_min} = 1;
110  ];      $result->{conforming_max} = 1;
111    for (@nav) {      check_and_print ($input => $result => $out);
112      print STDOUT qq[<li><a href="$_->[0]">$_->[1]</a></li>];      print_result_section ($result);
113      } else {
114        $out->html ('</dl>');
115        $out->end_section;
116        print_result_input_error_section ($input);
117    }    }
   print STDOUT qq[  
 </ul>  
 </body>  
 </html>  
 ];  
118    
119    for (qw/decode parse parse_html parse_xml parse_manifest    $out->nav_list;
           check check_manifest/) {  
     next unless defined $time{$_};  
     open my $file, '>>', ".cc-$_.txt" or die ".cc-$_.txt: $!";  
     print $file $char_length, "\t", $time{$_}, "\n";  
   }  
120    
121  exit;    exit;
122  }  }
123    
124  sub add_error ($$$) {  sub add_error ($$$) {
# Line 152  sub add_error ($$$) { Line 151  sub add_error ($$$) {
151    }    }
152  } # add_error  } # add_error
153    
154  sub check_and_print ($$) {  sub check_and_print ($$$) {
155    my ($input, $result) = @_;    my ($input, $result, $out) = @_;
156      my $original_input = $out->input;
157      $out->input ($input);
158    
159    print_http_header_section ($input, $result);    print_http_header_section ($input, $result);
160    
   my $doc;  
   my $el;  
   my $cssom;  
   my $manifest;  
   my $idl;  
161    my @subdoc;    my @subdoc;
162    
163    if ($input->{media_type} eq 'text/html') {    my $checker_class = {
164      ($doc, $el) = print_syntax_error_html_section ($input, $result);      'text/cache-manifest' => 'WebHACC::Language::CacheManifest',
165      print_source_string_section      'text/css' => 'WebHACC::Language::CSS',
166          ($input,      'text/html' => 'WebHACC::Language::HTML',
167           \($input->{s}),      'text/x-webidl' => 'WebHACC::Language::WebIDL',
168           $input->{charset} || $doc->input_encoding);  
169    } elsif ({      'text/xml' => 'WebHACC::Language::XML',
170              'text/xml' => 1,      'application/atom+xml' => 'WebHACC::Language::XML',
171              'application/atom+xml' => 1,      'application/rss+xml' => 'WebHACC::Language::XML',
172              'application/rss+xml' => 1,      'image/svg+xml' => 'WebHACC::Language::XML',
173              'image/svg+xml' => 1,      'application/xhtml+xml' => 'WebHACC::Language::XML',
174              'application/xhtml+xml' => 1,      'application/xml' => 'WebHACC::Language::XML',
175              'application/xml' => 1,      ## TODO: Should we make all XML MIME Types fall
176              ## TODO: Should we make all XML MIME Types fall      ## into this category?
177              ## into this category?  
178        ## NOTE: This type has different model from normal XML types.
179              'application/rdf+xml' => 1, ## NOTE: This type has different model.      'application/rdf+xml' => 'WebHACC::Language::XML',
180             }->{$input->{media_type}}) {    }->{$input->{media_type}} || 'WebHACC::Language::Default';
181      ($doc, $el) = print_syntax_error_xml_section ($input, $result);  
182      print_source_string_section ($input,    eval qq{ require $checker_class } or die "$0: Loading $checker_class: $@";
183                                   \($input->{s}),    my $checker = $checker_class->new;
184                                   $doc->input_encoding);    $checker->input ($input);
185    } elsif ($input->{media_type} eq 'text/css') {    $checker->output ($out);
186      $cssom = print_syntax_error_css_section ($input, $result);    $checker->result ($result);
187      print_source_string_section  
188          ($input, \($input->{s}),    ## TODO: A cache manifest MUST be text/cache-manifest
189           $cssom->manakai_input_encoding);    ## TODO: WebIDL media type "text/x-webidl"
190    } elsif ($input->{media_type} eq 'text/cache-manifest') {  
191  ## TODO: MUST be text/cache-manifest    $checker->generate_syntax_error_section;
192      $manifest = print_syntax_error_manifest_section ($input, $result);    $checker->generate_source_string_section;
193      print_source_string_section ($input, \($input->{s}),  
194                                   'utf-8');    $checker->onsubdoc (sub {
195    } elsif ($input->{media_type} eq 'text/x-webidl') { ## TODO: type      push @subdoc, shift;
196      $idl = print_syntax_error_webidl_section ($input, $result);    });
197      print_source_string_section ($input, \($input->{s}),  
198                                   'utf-8'); ## TODO: charset    $checker->generate_structure_dump_section;
199    } else {    $checker->generate_structure_error_section;
200      ## TODO: Change HTTP status code??    $checker->generate_additional_sections;
201      print_result_unknown_type_section ($input, $result);  
202    }  =pod
203    
204    if (defined $doc or defined $el) {    if (defined $doc or defined $el) {
205      $doc->document_uri ($input->{uri});  
     $doc->manakai_entity_base_uri ($input->{base_uri});  
     print_structure_dump_dom_section ($input, $doc, $el);  
     my $elements = print_structure_error_dom_section  
         ($input, $doc, $el, $result, sub {  
           push @subdoc, shift;  
         });  
206      print_table_section ($input, $elements->{table}) if @{$elements->{table}};      print_table_section ($input, $elements->{table}) if @{$elements->{table}};
207      print_listing_section ({      print_listing_section ({
208        id => 'identifiers', label => 'IDs', heading => 'Identifiers',        id => 'identifiers', label => 'IDs', heading => 'Identifiers',
# Line 223  sub check_and_print ($$) { Line 213  sub check_and_print ($$) {
213      print_listing_section ({      print_listing_section ({
214        id => 'classes', label => 'Classes', heading => 'Classes',        id => 'classes', label => 'Classes', heading => 'Classes',
215      }, $input, $elements->{class}) if keys %{$elements->{class}};      }, $input, $elements->{class}) if keys %{$elements->{class}};
216      print_uri_section ($input, $elements->{uri}) if keys %{$elements->{uri}};    
217      print_rdf_section ($input, $elements->{rdf}) if @{$elements->{rdf}};      print_rdf_section ($input, $elements->{rdf}) if @{$elements->{rdf}};
   } elsif (defined $cssom) {  
     print_structure_dump_cssom_section ($input, $cssom);  
     ## TODO: CSSOM validation  
     add_error ('structure', {level => 'u'} => $result);  
   } elsif (defined $manifest) {  
     print_structure_dump_manifest_section ($input, $manifest);  
     print_structure_error_manifest_section ($input, $manifest, $result);  
   } elsif (defined $idl) {  
     print_structure_dump_webidl_section ($input, $idl);  
     print_structure_error_webidl_section ($input, $idl, $result);  
218    }    }
219    
220    =cut
221    
222    my $id_prefix = 0;    my $id_prefix = 0;
223    for my $subinput (@subdoc) {    for my $_subinput (@subdoc) {
224      $subinput->{id_prefix} = 'subdoc-' . ++$id_prefix;      my $subinput = WebHACC::Input->new;
225      $subinput->{nested} = 1;      $subinput->{$_} = $_subinput->{$_} for keys %$_subinput;
226        $subinput->id_prefix ('subdoc-' . ++$id_prefix);
227        $subinput->nested (1);
228      $subinput->{base_uri} = $subinput->{container_node}->base_uri      $subinput->{base_uri} = $subinput->{container_node}->base_uri
229          unless defined $subinput->{base_uri};          unless defined $subinput->{base_uri};
230      my $ebaseuri = htescape ($subinput->{base_uri});      my $ebaseuri = htescape ($subinput->{base_uri});
231      push @nav, ['#' . $subinput->{id_prefix} => 'Sub #' . $id_prefix];      $out->start_section (id => $subinput->id_prefix,
232      print STDOUT qq[<div id="$subinput->{id_prefix}" class=section>                           title => qq[Subdocument #$id_prefix]);
233        <h2>Subdocument #$id_prefix</h2>      print STDOUT qq[
   
234        <dl>        <dl>
235        <dt>Internet Media Type</dt>        <dt>Internet Media Type</dt>
236          <dd><code class="MIME" lang="en">@{[htescape $subinput->{media_type}]}</code>          <dd><code class="MIME" lang="en">@{[htescape $subinput->{media_type}]}</code>
# Line 258  sub check_and_print ($$) { Line 241  sub check_and_print ($$) {
241        </dl>];                      </dl>];              
242    
243      $subinput->{id_prefix} .= '-';      $subinput->{id_prefix} .= '-';
244      check_and_print ($subinput => $result);      check_and_print ($subinput => $result => $out);
245    
246      print STDOUT qq[</div>];      $out->end_section;
247    }    }
248    
249      $out->input ($original_input);
250  } # check_and_print  } # check_and_print
251    
252  sub print_http_header_section ($$) {  sub print_http_header_section ($$) {
# Line 270  sub print_http_header_section ($$) { Line 255  sub print_http_header_section ($$) {
255        defined $input->{header_status_text} or        defined $input->{header_status_text} or
256        @{$input->{header_field} or []};        @{$input->{header_field} or []};
257        
258    push @nav, ['#source-header' => 'HTTP Header'] unless $input->{nested};    $out->start_section (id => 'source-header', title => 'HTTP Header');
259    print STDOUT qq[<div id="$input->{id_prefix}source-header" class="section">    print STDOUT qq[<p><strong>Note</strong>: Due to the limitation of the
 <h2>HTTP Header</h2>  
   
 <p><strong>Note</strong>: Due to the limitation of the  
260  network library in use, the content of this section might  network library in use, the content of this section might
261  not be the real header.</p>  not be the real header.</p>
262    
# Line 283  not be the real header.</p> Line 265  not be the real header.</p>
265    
266    if (defined $input->{header_status_code}) {    if (defined $input->{header_status_code}) {
267      print STDOUT qq[<tr><th scope="row">Status code</th>];      print STDOUT qq[<tr><th scope="row">Status code</th>];
268      print STDOUT qq[<td><code>@{[htescape ($input->{header_status_code})]}</code></td></tr>];      print STDOUT qq[<td>];
269        $out->code ($input->{header_status_code});
270    }    }
271    if (defined $input->{header_status_text}) {    if (defined $input->{header_status_text}) {
272      print STDOUT qq[<tr><th scope="row">Status text</th>];      print STDOUT qq[<tr><th scope="row">Status text</th>];
273      print STDOUT qq[<td><code>@{[htescape ($input->{header_status_text})]}</code></td></tr>];      print STDOUT qq[<td>];
274        $out->code ($input->{header_status_text});
275    }    }
276        
277    for (@{$input->{header_field}}) {    for (@{$input->{header_field}}) {
278      print STDOUT qq[<tr><th scope="row"><code>@{[htescape ($_->[0])]}</code></th>];      print STDOUT qq[<tr><th scope="row">];
279      print STDOUT qq[<td><code>@{[htescape ($_->[1])]}</code></td></tr>];      $out->code ($_->[0]);
280    }      print STDOUT qq[<td>];
281        $out->code ($_->[1]);
   print STDOUT qq[</tbody></table></div>];  
 } # print_http_header_section  
   
 sub print_syntax_error_html_section ($$) {  
   my ($input, $result) = @_;  
     
   require Encode;  
   require Whatpm::HTML;  
     
   print STDOUT qq[  
 <div id="$input->{id_prefix}parse-errors" class="section">  
 <h2>Parse Errors</h2>  
   
 <dl id="$input->{id_prefix}parse-errors-list">];  
   push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{nested};  
   
   my $onerror = sub {  
     my (%opt) = @_;  
     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level});  
     print STDOUT qq[<dt class="$cls">], get_error_label ($input, \%opt),  
         qq[</dt>];  
     $type =~ tr/ /-/;  
     $type =~ s/\|/%7C/g;  
     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];  
     print STDOUT qq[<dd class="$cls">], get_error_level_label (\%opt);  
     print STDOUT qq[$msg</dd>\n];  
   
     add_error ('syntax', \%opt => $result);  
   };  
   
   my $doc = $dom->create_document;  
   my $el;  
   my $inner_html_element = $input->{inner_html_element};  
   if (defined $inner_html_element and length $inner_html_element) {  
     $input->{charset} ||= 'windows-1252'; ## TODO: for now.  
     my $time1 = time;  
     my $t = \($input->{s});  
     unless ($input->{is_char_string}) {  
       $t = \(Encode::decode ($input->{charset}, $$t));  
     }  
     $time{decode} = time - $time1;  
       
     $el = $doc->create_element_ns  
         ('http://www.w3.org/1999/xhtml', [undef, $inner_html_element]);  
     $time1 = time;  
     Whatpm::HTML->set_inner_html ($el, $$t, $onerror);  
     $time{parse} = time - $time1;  
   } else {  
     my $time1 = time;  
     if ($input->{is_char_string}) {  
       Whatpm::HTML->parse_char_string ($input->{s} => $doc, $onerror);  
     } else {  
       Whatpm::HTML->parse_byte_string  
           ($input->{charset}, $input->{s} => $doc, $onerror);  
     }  
     $time{parse_html} = time - $time1;  
   }  
   $doc->manakai_charset ($input->{official_charset})  
       if defined $input->{official_charset};  
     
   print STDOUT qq[</dl></div>];  
   
   return ($doc, $el);  
 } # print_syntax_error_html_section  
   
 sub print_syntax_error_xml_section ($$) {  
   my ($input, $result) = @_;  
     
   require Message::DOM::XMLParserTemp;  
     
   print STDOUT qq[  
 <div id="$input->{id_prefix}parse-errors" class="section">  
 <h2>Parse Errors</h2>  
   
 <dl id="$input->{id_prefix}parse-errors-list">];  
   push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{prefix};  
   
   my $onerror = sub {  
     my $err = shift;  
     my $line = $err->location->line_number;  
     print STDOUT qq[<dt><a href="#$input->{id_prefix}line-$line">Line $line</a> column ];  
     print STDOUT $err->location->column_number, "</dt><dd>";  
     print STDOUT htescape $err->text, "</dd>\n";  
   
     add_error ('syntax', {type => $err->text,  
                 level => [  
                           $err->SEVERITY_FATAL_ERROR => 'm',  
                           $err->SEVERITY_ERROR => 'm',  
                           $err->SEVERITY_WARNING => 's',  
                          ]->[$err->severity]} => $result);  
   
     return 1;  
   };  
   
   my $t = \($input->{s});  
   if ($input->{is_char_string}) {  
     require Encode;  
     $t = \(Encode::encode ('utf8', $$t));  
     $input->{charset} = 'utf-8';  
   }  
   
   my $time1 = time;  
   open my $fh, '<', $t;  
   my $doc = Message::DOM::XMLParserTemp->parse_byte_stream  
       ($fh => $dom, $onerror, charset => $input->{charset});  
   $time{parse_xml} = time - $time1;  
   $doc->manakai_charset ($input->{official_charset})  
       if defined $input->{official_charset};  
   
   print STDOUT qq[</dl></div>];  
   
   return ($doc, undef);  
 } # print_syntax_error_xml_section  
   
 sub get_css_parser () {  
   our $CSSParser;  
   return $CSSParser if $CSSParser;  
   
   require Whatpm::CSS::Parser;  
   my $p = Whatpm::CSS::Parser->new;  
   
   $p->{prop}->{$_} = 1 for qw/  
     alignment-baseline  
     background background-attachment background-color background-image  
     background-position background-position-x background-position-y  
     background-repeat border border-bottom border-bottom-color  
     border-bottom-style border-bottom-width border-collapse border-color  
     border-left border-left-color  
     border-left-style border-left-width border-right border-right-color  
     border-right-style border-right-width  
     border-spacing -manakai-border-spacing-x -manakai-border-spacing-y  
     border-style border-top border-top-color border-top-style border-top-width  
     border-width bottom  
     caption-side clear clip color content counter-increment counter-reset  
     cursor direction display dominant-baseline empty-cells float font  
     font-family font-size font-size-adjust font-stretch  
     font-style font-variant font-weight height left  
     letter-spacing line-height  
     list-style list-style-image list-style-position list-style-type  
     margin margin-bottom margin-left margin-right margin-top marker-offset  
     marks max-height max-width min-height min-width opacity -moz-opacity  
     orphans outline outline-color outline-style outline-width overflow  
     overflow-x overflow-y  
     padding padding-bottom padding-left padding-right padding-top  
     page page-break-after page-break-before page-break-inside  
     position quotes right size table-layout  
     text-align text-anchor text-decoration text-indent text-transform  
     top unicode-bidi vertical-align visibility white-space width widows  
     word-spacing writing-mode z-index  
   /;  
   $p->{prop_value}->{display}->{$_} = 1 for qw/  
     block clip inline inline-block inline-table list-item none  
     table table-caption table-cell table-column table-column-group  
     table-header-group table-footer-group table-row table-row-group  
     compact marker  
   /;  
   $p->{prop_value}->{position}->{$_} = 1 for qw/  
     absolute fixed relative static  
   /;  
   $p->{prop_value}->{float}->{$_} = 1 for qw/  
     left right none  
   /;  
   $p->{prop_value}->{clear}->{$_} = 1 for qw/  
     left right none both  
   /;  
   $p->{prop_value}->{direction}->{ltr} = 1;  
   $p->{prop_value}->{direction}->{rtl} = 1;  
   $p->{prop_value}->{marks}->{crop} = 1;  
   $p->{prop_value}->{marks}->{cross} = 1;  
   $p->{prop_value}->{'unicode-bidi'}->{$_} = 1 for qw/  
     normal bidi-override embed  
   /;  
   for my $prop_name (qw/overflow overflow-x overflow-y/) {  
     $p->{prop_value}->{$prop_name}->{$_} = 1 for qw/  
       visible hidden scroll auto -webkit-marquee -moz-hidden-unscrollable  
     /;  
   }  
   $p->{prop_value}->{visibility}->{$_} = 1 for qw/  
     visible hidden collapse  
   /;  
   $p->{prop_value}->{'list-style-type'}->{$_} = 1 for qw/  
     disc circle square decimal decimal-leading-zero  
     lower-roman upper-roman lower-greek lower-latin  
     upper-latin armenian georgian lower-alpha upper-alpha none  
     hebrew cjk-ideographic hiragana katakana hiragana-iroha  
     katakana-iroha  
   /;  
   $p->{prop_value}->{'list-style-position'}->{outside} = 1;  
   $p->{prop_value}->{'list-style-position'}->{inside} = 1;  
   $p->{prop_value}->{'page-break-before'}->{$_} = 1 for qw/  
     auto always avoid left right  
   /;  
   $p->{prop_value}->{'page-break-after'}->{$_} = 1 for qw/  
     auto always avoid left right  
   /;  
   $p->{prop_value}->{'page-break-inside'}->{auto} = 1;  
   $p->{prop_value}->{'page-break-inside'}->{avoid} = 1;  
   $p->{prop_value}->{'background-repeat'}->{$_} = 1 for qw/  
     repeat repeat-x repeat-y no-repeat  
   /;  
   $p->{prop_value}->{'background-attachment'}->{scroll} = 1;  
   $p->{prop_value}->{'background-attachment'}->{fixed} = 1;  
   $p->{prop_value}->{'font-size'}->{$_} = 1 for qw/  
     xx-small x-small small medium large x-large xx-large  
     -manakai-xxx-large -webkit-xxx-large  
     larger smaller  
   /;  
   $p->{prop_value}->{'font-style'}->{normal} = 1;  
   $p->{prop_value}->{'font-style'}->{italic} = 1;  
   $p->{prop_value}->{'font-style'}->{oblique} = 1;  
   $p->{prop_value}->{'font-variant'}->{normal} = 1;  
   $p->{prop_value}->{'font-variant'}->{'small-caps'} = 1;  
   $p->{prop_value}->{'font-stretch'}->{$_} = 1 for  
       qw/normal wider narrower ultra-condensed extra-condensed  
         condensed semi-condensed semi-expanded expanded  
         extra-expanded ultra-expanded/;  
   $p->{prop_value}->{'text-align'}->{$_} = 1 for qw/  
     left right center justify begin end  
   /;  
   $p->{prop_value}->{'text-transform'}->{$_} = 1 for qw/  
     capitalize uppercase lowercase none  
   /;  
   $p->{prop_value}->{'white-space'}->{$_} = 1 for qw/  
     normal pre nowrap pre-line pre-wrap -moz-pre-wrap  
   /;  
   $p->{prop_value}->{'writing-mode'}->{$_} = 1 for qw/  
     lr rl tb lr-tb rl-tb tb-rl  
   /;  
   $p->{prop_value}->{'text-anchor'}->{$_} = 1 for qw/  
     start middle end  
   /;  
   $p->{prop_value}->{'dominant-baseline'}->{$_} = 1 for qw/  
     auto use-script no-change reset-size ideographic alphabetic  
     hanging mathematical central middle text-after-edge text-before-edge  
   /;  
   $p->{prop_value}->{'alignment-baseline'}->{$_} = 1 for qw/  
     auto baseline before-edge text-before-edge middle central  
     after-edge text-after-edge ideographic alphabetic hanging  
     mathematical  
   /;  
   $p->{prop_value}->{'text-decoration'}->{$_} = 1 for qw/  
     none blink underline overline line-through  
   /;  
   $p->{prop_value}->{'caption-side'}->{$_} = 1 for qw/  
     top bottom left right  
   /;  
   $p->{prop_value}->{'table-layout'}->{auto} = 1;  
   $p->{prop_value}->{'table-layout'}->{fixed} = 1;  
   $p->{prop_value}->{'border-collapse'}->{collapse} = 1;  
   $p->{prop_value}->{'border-collapse'}->{separate} = 1;  
   $p->{prop_value}->{'empty-cells'}->{show} = 1;  
   $p->{prop_value}->{'empty-cells'}->{hide} = 1;  
   $p->{prop_value}->{cursor}->{$_} = 1 for qw/  
     auto crosshair default pointer move e-resize ne-resize nw-resize n-resize  
     se-resize sw-resize s-resize w-resize text wait help progress  
   /;  
   for my $prop (qw/border-top-style border-left-style  
                    border-bottom-style border-right-style outline-style/) {  
     $p->{prop_value}->{$prop}->{$_} = 1 for qw/  
       none hidden dotted dashed solid double groove ridge inset outset  
     /;  
   }  
   for my $prop (qw/color background-color  
                    border-bottom-color border-left-color border-right-color  
                    border-top-color border-color/) {  
     $p->{prop_value}->{$prop}->{transparent} = 1;  
     $p->{prop_value}->{$prop}->{flavor} = 1;  
     $p->{prop_value}->{$prop}->{'-manakai-default'} = 1;  
   }  
   $p->{prop_value}->{'outline-color'}->{invert} = 1;  
   $p->{prop_value}->{'outline-color'}->{'-manakai-invert-or-currentcolor'} = 1;  
   $p->{pseudo_class}->{$_} = 1 for qw/  
     active checked disabled empty enabled first-child first-of-type  
     focus hover indeterminate last-child last-of-type link only-child  
     only-of-type root target visited  
     lang nth-child nth-last-child nth-of-type nth-last-of-type not  
     -manakai-contains -manakai-current  
   /;  
   $p->{pseudo_element}->{$_} = 1 for qw/  
     after before first-letter first-line  
   /;  
   
   return $CSSParser = $p;  
 } # get_css_parser  
   
 sub print_syntax_error_css_section ($$) {  
   my ($input, $result) = @_;  
   
   print STDOUT qq[  
 <div id="$input->{id_prefix}parse-errors" class="section">  
 <h2>Parse Errors</h2>  
   
 <dl id="$input->{id_prefix}parse-errors-list">];  
   push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{nested};  
   
   my $p = get_css_parser ();  
   $p->init;  
   $p->{onerror} = sub {  
     my (%opt) = @_;  
     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level});  
     if ($opt{token}) {  
       print STDOUT qq[<dt class="$cls"><a href="#$input->{id_prefix}line-$opt{token}->{line}">Line $opt{token}->{line}</a> column $opt{token}->{column}];  
     } else {  
       print STDOUT qq[<dt class="$cls">Unknown location];  
     }  
     if (defined $opt{value}) {  
       print STDOUT qq[ (<code>@{[htescape ($opt{value})]}</code>)];  
     } elsif (defined $opt{token}) {  
       print STDOUT qq[ (<code>@{[htescape (Whatpm::CSS::Tokenizer->serialize_token ($opt{token}))]}</code>)];  
     }  
     $type =~ tr/ /-/;  
     $type =~ s/\|/%7C/g;  
     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];  
     print STDOUT qq[<dd class="$cls">], get_error_level_label (\%opt);  
     print STDOUT qq[$msg</dd>\n];  
   
     add_error ('syntax', \%opt => $result);  
   };  
   $p->{href} = $input->{uri};  
   $p->{base_uri} = $input->{base_uri};  
   
 #  if ($parse_mode eq 'q') {  
 #    $p->{unitless_px} = 1;  
 #    $p->{hashless_color} = 1;  
 #  }  
   
 ## TODO: Make $input->{s} a ref.  
   
   my $s = \$input->{s};  
   my $charset;  
   unless ($input->{is_char_string}) {  
     require Encode;  
     if (defined $input->{charset}) {## TODO: IANA->Perl  
       $charset = $input->{charset};  
       $s = \(Encode::decode ($input->{charset}, $$s));  
     } else {  
       ## TODO: charset detection  
       $s = \(Encode::decode ($charset = 'utf-8', $$s));  
     }  
   }  
     
   my $cssom = $p->parse_char_string ($$s);  
   $cssom->manakai_input_encoding ($charset) if defined $charset;  
   
   print STDOUT qq[</dl></div>];  
   
   return $cssom;  
 } # print_syntax_error_css_section  
   
 sub print_syntax_error_manifest_section ($$) {  
   my ($input, $result) = @_;  
   
   require Whatpm::CacheManifest;  
   
   print STDOUT qq[  
 <div id="$input->{id_prefix}parse-errors" class="section">  
 <h2>Parse Errors</h2>  
   
 <dl id="$input->{id_prefix}parse-errors-list">];  
   push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{nested};  
   
   my $onerror = sub {  
     my (%opt) = @_;  
     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level});  
     print STDOUT qq[<dt class="$cls">], get_error_label ($input, \%opt),  
         qq[</dt>];  
     $type =~ tr/ /-/;  
     $type =~ s/\|/%7C/g;  
     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];  
     print STDOUT qq[<dd class="$cls">], get_error_level_label (\%opt);  
     print STDOUT qq[$msg</dd>\n];  
   
     add_error ('syntax', \%opt => $result);  
   };  
   
   my $m = $input->{is_char_string} ? 'parse_char_string' : 'parse_byte_string';  
   my $time1 = time;  
   my $manifest = Whatpm::CacheManifest->$m  
       ($input->{s}, $input->{uri}, $input->{base_uri}, $onerror);  
   $time{parse_manifest} = time - $time1;  
   
   print STDOUT qq[</dl></div>];  
   
   return $manifest;  
 } # print_syntax_error_manifest_section  
   
 sub print_syntax_error_webidl_section ($$) {  
   my ($input, $result) = @_;  
   
   require Whatpm::WebIDL;  
   
   print STDOUT qq[  
 <div id="$input->{id_prefix}parse-errors" class="section">  
 <h2>Parse Errors</h2>  
   
 <dl id="$input->{id_prefix}parse-errors-list">];  
   push @nav, ['#parse-errors' => 'Parse Error'] unless $input->{nested};  
   
   my $onerror = sub {  
     my (%opt) = @_;  
     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level});  
     print STDOUT qq[<dt class="$cls">], get_error_label ($input, \%opt),  
         qq[</dt>];  
     $type =~ tr/ /-/;  
     $type =~ s/\|/%7C/g;  
     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];  
     print STDOUT qq[<dd class="$cls">], get_error_level_label (\%opt);  
     print STDOUT qq[$msg</dd>\n];  
   
     add_error ('syntax', \%opt => $result);  
   };  
   
   require Encode;  
   my $s = $input->{is_char_string} ? $input->{s} : Encode::decode ($input->{charset} || 'utf-8', $input->{s}); ## TODO: charset  
   my $parser = Whatpm::WebIDL::Parser->new;  
   my $idl = $parser->parse_char_string ($input->{s}, $onerror);  
   
   print STDOUT qq[</dl></div>];  
   
   return $idl;  
 } # print_syntax_error_webidl_section  
   
 sub print_source_string_section ($$$) {  
   my $input = shift;  
   my $s;  
   unless ($input->{is_char_string}) {  
     open my $byte_stream, '<', $_[0];  
     require Message::Charset::Info;  
     my $charset = Message::Charset::Info->get_by_iana_name ($_[1]);  
     my ($char_stream, $e_status) = $charset->get_decode_handle  
         ($byte_stream, allow_error_reporting => 1, allow_fallback => 1);  
     return unless $char_stream;  
   
     $char_stream->onerror (sub {  
       my (undef, $type, %opt) = @_;  
       if ($opt{octets}) {  
         ${$opt{octets}} = "\x{FFFD}";  
       }  
     });  
   
     my $t = '';  
     while (1) {  
       my $c = $char_stream->getc;  
       last unless defined $c;  
       $t .= $c;  
     }  
     $s = \$t;  
     ## TODO: Output for each line, don't concat all of lines.  
   } else {  
     $s = $_[0];  
   }  
   
   my $i = 1;                              
   push @nav, ['#source-string' => 'Source'] unless $input->{nested};  
   print STDOUT qq[<div id="$input->{id_prefix}source-string" class="section">  
 <h2>Document Source</h2>  
 <ol lang="">\n];  
   if (length $$s) {  
     while ($$s =~ /\G([^\x0D\x0A]*?)(?>\x0D\x0A?|\x0A)/gc) {  
       print STDOUT qq[<li id="$input->{id_prefix}line-$i">], htescape $1,  
           "</li>\n";  
       $i++;  
     }  
     if ($$s =~ /\G([^\x0D\x0A]+)/gc) {  
       print STDOUT qq[<li id="$input->{id_prefix}line-$i">], htescape $1,  
           "</li>\n";  
     }  
   } else {  
     print STDOUT q[<li id="$input->{id_prefix}line-1"></li>];  
   }  
   print STDOUT "</ol></div>  
 <script>  
   addSourceToParseErrorList ('$input->{id_prefix}', 'parse-errors-list');  
 </script>";  
 } # print_input_string_section  
   
 sub print_document_tree ($$) {  
   my ($input, $node) = @_;  
   
   my $r = '<ol class="xoxo">';  
   
   my @node = ($node);  
   while (@node) {  
     my $child = shift @node;  
     unless (ref $child) {  
       $r .= $child;  
       next;  
     }  
   
     my $node_id = $input->{id_prefix} . 'node-'.refaddr $child;  
     my $nt = $child->node_type;  
     if ($nt == $child->ELEMENT_NODE) {  
       my $child_nsuri = $child->namespace_uri;  
       $r .= qq[<li id="$node_id" class="tree-element"><code title="@{[defined $child_nsuri ? $child_nsuri : '']}">] . htescape ($child->tag_name) .  
           '</code>'; ## ISSUE: case  
   
       if ($child->has_attributes) {  
         $r .= '<ul class="attributes">';  
         for my $attr (sort {$a->[0] cmp $b->[0]} map { [$_->name, $_->value, $_->namespace_uri, 'node-'.refaddr $_] }  
                       @{$child->attributes}) {  
           $r .= qq[<li id="$input->{id_prefix}$attr->[3]" class="tree-attribute"><code title="@{[defined $attr->[2] ? htescape ($attr->[2]) : '']}">] . htescape ($attr->[0]) . '</code> = '; ## ISSUE: case?  
           $r .= '<q>' . htescape ($attr->[1]) . '</q></li>'; ## TODO: children  
         }  
         $r .= '</ul>';  
       }  
   
       if ($child->has_child_nodes) {  
         $r .= '<ol class="children">';  
         unshift @node, @{$child->child_nodes}, '</ol></li>';  
       } else {  
         $r .= '</li>';  
       }  
     } elsif ($nt == $child->TEXT_NODE) {  
       $r .= qq'<li id="$node_id" class="tree-text"><q lang="">' . htescape ($child->data) . '</q></li>';  
     } elsif ($nt == $child->CDATA_SECTION_NODE) {  
       $r .= qq'<li id="$node_id" class="tree-cdata"><code>&lt;[CDATA[</code><q lang="">' . htescape ($child->data) . '</q><code>]]&gt;</code></li>';  
     } elsif ($nt == $child->COMMENT_NODE) {  
       $r .= qq'<li id="$node_id" class="tree-comment"><code>&lt;!--</code><q lang="">' . htescape ($child->data) . '</q><code>--&gt;</code></li>';  
     } elsif ($nt == $child->DOCUMENT_NODE) {  
       $r .= qq'<li id="$node_id" class="tree-document">Document';  
       $r .= qq[<ul class="attributes">];  
       my $cp = $child->manakai_charset;  
       if (defined $cp) {  
         $r .= qq[<li><code>charset</code> parameter = <code>];  
         $r .= htescape ($cp) . qq[</code></li>];  
       }  
       $r .= qq[<li><code>inputEncoding</code> = ];  
       my $ie = $child->input_encoding;  
       if (defined $ie) {  
         $r .= qq[<code>@{[htescape ($ie)]}</code>];  
         if ($child->manakai_has_bom) {  
           $r .= qq[ (with <code class=charname><abbr>BOM</abbr></code>)];  
         }  
       } else {  
         $r .= qq[(<code>null</code>)];  
       }  
       $r .= qq[<li>@{[scalar get_text ('manakaiIsHTML:'.($child->manakai_is_html?1:0))]}</li>];  
       $r .= qq[<li>@{[scalar get_text ('manakaiCompatMode:'.$child->manakai_compat_mode)]}</li>];  
       unless ($child->manakai_is_html) {  
         $r .= qq[<li>XML version = <code>@{[htescape ($child->xml_version)]}</code></li>];  
         if (defined $child->xml_encoding) {  
           $r .= qq[<li>XML encoding = <code>@{[htescape ($child->xml_encoding)]}</code></li>];  
         } else {  
           $r .= qq[<li>XML encoding = (null)</li>];  
         }  
         $r .= qq[<li>XML standalone = @{[$child->xml_standalone ? 'true' : 'false']}</li>];  
       }  
       $r .= qq[</ul>];  
       if ($child->has_child_nodes) {  
         $r .= '<ol class="children">';  
         unshift @node, @{$child->child_nodes}, '</ol></li>';  
       }  
     } elsif ($nt == $child->DOCUMENT_TYPE_NODE) {  
       $r .= qq'<li id="$node_id" class="tree-doctype"><code>&lt;!DOCTYPE&gt;</code><ul class="attributes">';  
       $r .= qq[<li class="tree-doctype-name">Name = <q>@{[htescape ($child->name)]}</q></li>];  
       $r .= qq[<li class="tree-doctype-publicid">Public identifier = <q>@{[htescape ($child->public_id)]}</q></li>];  
       $r .= qq[<li class="tree-doctype-systemid">System identifier = <q>@{[htescape ($child->system_id)]}</q></li>];  
       $r .= '</ul></li>';  
     } elsif ($nt == $child->PROCESSING_INSTRUCTION_NODE) {  
       $r .= qq'<li id="$node_id" class="tree-id"><code>&lt;?@{[htescape ($child->target)]}</code> <q>@{[htescape ($child->data)]}</q><code>?&gt;</code></li>';  
     } else {  
       $r .= qq'<li id="$node_id" class="tree-unknown">@{[$child->node_type]} @{[htescape ($child->node_name)]}</li>'; # error  
     }  
282    }    }
283    
284    $r .= '</ol>';    print STDOUT qq[</tbody></table>];
   print STDOUT $r;  
 } # print_document_tree  
   
 sub print_structure_dump_dom_section ($$$) {  
   my ($input, $doc, $el) = @_;  
   
   print STDOUT qq[  
 <div id="$input->{id_prefix}document-tree" class="section">  
 <h2>Document Tree</h2>  
 ];  
   push @nav, [qq[#$input->{id_prefix}document-tree] => 'Tree']  
       unless $input->{nested};  
   
   print_document_tree ($input, $el || $doc);  
   
   print STDOUT qq[</div>];  
 } # print_structure_dump_dom_section  
   
 sub print_structure_dump_cssom_section ($$) {  
   my ($input, $cssom) = @_;  
   
   print STDOUT qq[  
 <div id="$input->{id_prefix}document-tree" class="section">  
 <h2>Document Tree</h2>  
 ];  
   push @nav, [qq[#$input->{id_prefix}document-tree] => 'Tree']  
       unless $input->{nested};  
   
   ## TODO:  
   print STDOUT "<pre>".htescape ($cssom->css_text)."</pre>";  
   
   print STDOUT qq[</div>];  
 } # print_structure_dump_cssom_section  
   
 sub print_structure_dump_manifest_section ($$) {  
   my ($input, $manifest) = @_;  
   
   print STDOUT qq[  
 <div id="$input->{id_prefix}dump-manifest" class="section">  
 <h2>Cache Manifest</h2>  
 ];  
   push @nav, [qq[#$input->{id_prefix}dump-manifest] => 'Cache Manifest']  
       unless $input->{nested};  
   
   print STDOUT qq[<dl><dt>Explicit entries</dt>];  
   my $i = 0;  
   for my $uri (@{$manifest->[0]}) {  
     my $euri = htescape ($uri);  
     print STDOUT qq[<dd id="$input->{id_prefix}index-@{[$i++]}"><code class=uri>&lt;<a href="$euri">$euri</a>></code></dd>];  
   }  
   
   print STDOUT qq[<dt>Fallback entries</dt><dd>  
       <table><thead><tr><th scope=row>Oppotunistic Caching Namespace</th>  
       <th scope=row>Fallback Entry</tr><tbody>];  
   for my $uri (sort {$a cmp $b} keys %{$manifest->[1]}) {  
     my $euri = htescape ($uri);  
     my $euri2 = htescape ($manifest->[1]->{$uri});  
     print STDOUT qq[<tr><td id="$input->{id_prefix}index-@{[$i++]}"><code class=uri>&lt;<a href="$euri">$euri</a>></code></td>  
         <td id="$input->{id_prefix}index-@{[$i++]}"><code class=uri>&lt;<a href="$euri2">$euri2</a>></code></td>];  
   }  
   
   print STDOUT qq[</table><dt>Online whitelist</dt>];  
   for my $uri (@{$manifest->[2]}) {  
     my $euri = htescape ($uri);  
     print STDOUT qq[<dd id="$input->{id_prefix}index-@{[$i++]}"><code class=uri>&lt;<a href="$euri">$euri</a>></code></dd>];  
   }  
   
   print STDOUT qq[</dl></div>];  
 } # print_structure_dump_manifest_section  
   
 sub print_structure_dump_webidl_section ($$) {  
   my ($input, $idl) = @_;  
   
   print STDOUT qq[  
 <div id="$input->{id_prefix}dump-webidl" class="section">  
 <h2>WebIDL</h2>  
 ];  
   push @nav, [qq[#$input->{id_prefix}dump-webidl] => 'WebIDL']  
       unless $input->{nested};  
   
   print STDOUT "<pre>";  
   print STDOUT htescape ($idl->idl_text);  
   print STDOUT "</pre>";  
   
   print STDOUT qq[</div>];  
 } # print_structure_dump_webidl_section  
   
 sub print_structure_error_dom_section ($$$$$) {  
   my ($input, $doc, $el, $result, $onsubdoc) = @_;  
   
   print STDOUT qq[<div id="$input->{id_prefix}document-errors" class="section">  
 <h2>Document Errors</h2>  
   
 <dl id=document-errors-list>];  
   push @nav, [qq[#$input->{id_prefix}document-errors] => 'Document Error']  
       unless $input->{nested};  
   
   require Whatpm::ContentChecker;  
   my $onerror = sub {  
     my %opt = @_;  
     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level}, $opt{node});  
     $type =~ tr/ /-/;  
     $type =~ s/\|/%7C/g;  
     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];  
     print STDOUT qq[<dt class="$cls">] . get_error_label ($input, \%opt) .  
         qq[</dt>\n<dd class="$cls">], get_error_level_label (\%opt);  
     print STDOUT $msg, "</dd>\n";  
     add_error ('structure', \%opt => $result);  
   };  
   
   my $elements;  
   my $time1 = time;  
   if ($el) {  
     $elements = Whatpm::ContentChecker->check_element  
         ($el, $onerror, $onsubdoc);  
   } else {  
     $elements = Whatpm::ContentChecker->check_document  
         ($doc, $onerror, $onsubdoc);  
   }  
   $time{check} = time - $time1;  
   
   print STDOUT qq[</dl>  
 <script>  
   addSourceToParseErrorList ('$input->{id_prefix}', 'document-errors-list');  
 </script></div>];  
   
   return $elements;  
 } # print_structure_error_dom_section  
   
 sub print_structure_error_manifest_section ($$$) {  
   my ($input, $manifest, $result) = @_;  
   
   print STDOUT qq[<div id="$input->{id_prefix}document-errors" class="section">  
 <h2>Document Errors</h2>  
   
 <dl>];  
   push @nav, [qq[#$input->{id_prefix}document-errors] => 'Document Error']  
       unless $input->{nested};  
   
   require Whatpm::CacheManifest;  
   Whatpm::CacheManifest->check_manifest ($manifest, sub {  
     my %opt = @_;  
     my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level}, $opt{node});  
     $type =~ tr/ /-/;  
     $type =~ s/\|/%7C/g;  
     $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]];  
     print STDOUT qq[<dt class="$cls">] . get_error_label ($input, \%opt) .  
         qq[</dt>\n<dd class="$cls">], $msg, "</dd>\n";  
     add_error ('structure', \%opt => $result);  
   });  
   
   print STDOUT qq[</div>];  
 } # print_structure_error_manifest_section  
   
 sub print_structure_error_webidl_section ($$$) {  
   my ($input, $idl, $result) = @_;  
   
   print STDOUT qq[<div id="$input->{id_prefix}document-errors" class="section">  
 <h2>Document Errors</h2>  
285    
286  <dl>];    $out->end_section;
287    push @nav, [qq[#$input->{id_prefix}document-errors] => 'Document Error']  } # print_http_header_section
       unless $input->{nested};  
   
 ## TODO:  
   
   print STDOUT qq[</div>];  
 } # print_structure_error_webidl_section  
288    
289  sub print_table_section ($$) {  sub print_table_section ($$) {
290    my ($input, $tables) = @_;    my ($input, $tables) = @_;
291        
292    push @nav, [qq[#$input->{id_prefix}tables] => 'Tables']  #  push @nav, [qq[#$input->{id_prefix}tables] => 'Tables']
293        unless $input->{nested};  #      unless $input->{nested};
294    print STDOUT qq[    print STDOUT qq[
295  <div id="$input->{id_prefix}tables" class="section">  <div id="$input->{id_prefix}tables" class="section">
296  <h2>Tables</h2>  <h2>Tables</h2>
# Line 1093  sub print_table_section ($$) { Line 349  sub print_table_section ($$) {
349  sub print_listing_section ($$$) {  sub print_listing_section ($$$) {
350    my ($opt, $input, $ids) = @_;    my ($opt, $input, $ids) = @_;
351        
352    push @nav, ['#' . $input->{id_prefix} . $opt->{id} => $opt->{label}]  #  push @nav, ['#' . $input->{id_prefix} . $opt->{id} => $opt->{label}]
353        unless $input->{nested};  #      unless $input->{nested};
354    print STDOUT qq[    print STDOUT qq[
355  <div id="$input->{id_prefix}$opt->{id}" class="section">  <div id="$input->{id_prefix}$opt->{id}" class="section">
356  <h2>$opt->{heading}</h2>  <h2>$opt->{heading}</h2>
# Line 1110  sub print_listing_section ($$$) { Line 366  sub print_listing_section ($$$) {
366    print STDOUT qq[</dl></div>];    print STDOUT qq[</dl></div>];
367  } # print_listing_section  } # print_listing_section
368    
 sub print_uri_section ($$$) {  
   my ($input, $uris) = @_;  
   
   ## NOTE: URIs contained in the DOM (i.e. in HTML or XML documents),  
   ## except for those in RDF triples.  
   ## TODO: URIs in CSS  
     
   push @nav, ['#' . $input->{id_prefix} . 'uris' => 'URIs']  
       unless $input->{nested};  
   print STDOUT qq[  
 <div id="$input->{id_prefix}uris" class="section">  
 <h2>URIs</h2>  
   
 <dl>];  
   for my $uri (sort {$a cmp $b} keys %$uris) {  
     my $euri = htescape ($uri);  
     print STDOUT qq[<dt><code class=uri>&lt;<a href="$euri">$euri</a>></code>];  
     my $eccuri = htescape (get_cc_uri ($uri));  
     print STDOUT qq[<dd><a href="$eccuri">Check conformance of this document</a>];  
     print STDOUT qq[<dd>Found at: <ul>];  
     for my $entry (@{$uris->{$uri}}) {  
       print STDOUT qq[<li>], get_node_link ($input, $entry->{node});  
       if (keys %{$entry->{type} or {}}) {  
         print STDOUT ' (';  
         print STDOUT join ', ', map {  
           {  
             hyperlink => 'Hyperlink',  
             resource => 'Link to an external resource',  
             namespace => 'Namespace URI',  
             cite => 'Citation or link to a long description',  
             embedded => 'Link to an embedded content',  
             base => 'Base URI',  
             action => 'Submission URI',  
           }->{$_}  
             or  
           htescape ($_)  
         } keys %{$entry->{type}};  
         print STDOUT ')';  
       }  
     }  
     print STDOUT qq[</ul>];  
   }  
   print STDOUT qq[</dl></div>];  
 } # print_uri_section  
369    
370  sub print_rdf_section ($$$) {  sub print_rdf_section ($$$) {
371    my ($input, $rdfs) = @_;    my ($input, $rdfs) = @_;
372        
373    push @nav, ['#' . $input->{id_prefix} . 'rdf' => 'RDF']  #  push @nav, ['#' . $input->{id_prefix} . 'rdf' => 'RDF']
374        unless $input->{nested};  #      unless $input->{nested};
375    print STDOUT qq[    print STDOUT qq[
376  <div id="$input->{id_prefix}rdf" class="section">  <div id="$input->{id_prefix}rdf" class="section">
377  <h2>RDF Triples</h2>  <h2>RDF Triples</h2>
# Line 1213  sub get_rdf_resource_html ($) { Line 425  sub get_rdf_resource_html ($) {
425  sub print_result_section ($) {  sub print_result_section ($) {
426    my $result = shift;    my $result = shift;
427    
428    print STDOUT qq[    $out->start_section (id => 'result-summary',
429  <div id="result-summary" class="section">                         title => 'Result');
 <h2>Result</h2>];  
430    
431    if ($result->{unsupported} and $result->{conforming_max}) {      if ($result->{unsupported} and $result->{conforming_max}) {  
432      print STDOUT qq[<p class=uncertain id=result-para>The conformance      print STDOUT qq[<p class=uncertain id=result-para>The conformance
# Line 1297  Errors</a></th> Line 508  Errors</a></th>
508  </table>  </table>
509    
510  <p><strong>Important</strong>: This conformance checking service  <p><strong>Important</strong>: This conformance checking service
511  is <em>under development</em>.  The result above might be <em>wrong</em>.</p>  is <em>under development</em>.  The result above might be <em>wrong</em>.</p>];
512  </div>];    $out->end_section;
   push @nav, ['#result-summary' => 'Result'];  
513  } # print_result_section  } # print_result_section
514    
 sub print_result_unknown_type_section ($$) {  
   my ($input, $result) = @_;  
   
   my $euri = htescape ($input->{uri});  
   print STDOUT qq[  
 <div id="$input->{id_prefix}parse-errors" class="section">  
 <h2>Errors</h2>  
   
 <dl>  
 <dt class=unsupported><code>&lt;<a href="$euri">$euri</a>&gt;</code></dt>  
     <dd class=unsupported><strong><a href="../error-description#level-u">Not  
         supported</a></strong>:  
     Media type  
     <code class="MIME" lang="en">@{[htescape $input->{media_type}]}</code>  
     is not supported.</dd>  
 </dl>  
 </div>  
 ];  
   push @nav, [qq[#$input->{id_prefix}parse-errors] => 'Errors']  
       unless $input->{nested};  
   add_error (char => {level => 'u'} => $result);  
   add_error (syntax => {level => 'u'} => $result);  
   add_error (structure => {level => 'u'} => $result);  
 } # print_result_unknown_type_section  
   
515  sub print_result_input_error_section ($) {  sub print_result_input_error_section ($) {
516    my $input = shift;    my $input = shift;
517    print STDOUT qq[<div class="section" id="result-summary">    $out->start_section (id => 'result-summary', title => 'Result');
518  <p><em><strong>Input Error</strong>: @{[htescape ($input->{error_status_text})]}</em></p>    print STDOUT qq[
519  </div>];  <p><em><strong>Input Error</strong>: @{[htescape ($input->{error_status_text})]}</em></p>];
520    push @nav, ['#result-summary' => 'Result'];    $out->end_section;
521  } # print_result_input_error_section  } # print_result_input_error_section
522    
 sub get_error_label ($$) {  
   my ($input, $err) = @_;  
   
   my $r = '';  
   
   my $line;  
   my $column;  
       
   if (defined $err->{node}) {  
     $line = $err->{node}->get_user_data ('manakai_source_line');  
     if (defined $line) {  
       $column = $err->{node}->get_user_data ('manakai_source_column');  
     } else {  
       if ($err->{node}->node_type == $err->{node}->ATTRIBUTE_NODE) {  
         my $owner = $err->{node}->owner_element;  
         $line = $owner->get_user_data ('manakai_source_line');  
         $column = $owner->get_user_data ('manakai_source_column');  
       } else {  
         my $parent = $err->{node}->parent_node;  
         if ($parent) {  
           $line = $parent->get_user_data ('manakai_source_line');  
           $column = $parent->get_user_data ('manakai_source_column');  
         }  
       }  
     }  
   }  
   unless (defined $line) {  
     if (defined $err->{token} and defined $err->{token}->{line}) {  
       $line = $err->{token}->{line};  
       $column = $err->{token}->{column};  
     } elsif (defined $err->{line}) {  
       $line = $err->{line};  
       $column = $err->{column};  
     }  
   }  
   
   if (defined $line) {  
     if (defined $column and $column > 0) {  
       $r = qq[<a href="#$input->{id_prefix}line-$line">Line $line</a> column $column];  
     } else {  
       $line = $line - 1 || 1;  
       $r = qq[<a href="#$input->{id_prefix}line-$line">Line $line</a>];  
     }  
   }  
   
   if (defined $err->{node}) {  
     $r .= ' ' if length $r;  
     $r .= get_node_link ($input, $err->{node});  
   }  
   
   if (defined $err->{index}) {  
     if (length $r) {  
       $r .= ', Index ' . (0+$err->{index});  
     } else {  
       $r .= "<a href='#$input->{id_prefix}index-@{[0+$err->{index}]}'>Index "  
           . (0+$err->{index}) . '</a>';  
     }  
   }  
   
   if (defined $err->{value}) {  
     $r .= ' ' if length $r;  
     $r .= '<q><code>' . htescape ($err->{value}) . '</code></q>';  
   }  
   
   return $r;  
 } # get_error_label  
   
 sub get_error_level_label ($) {  
   my $err = shift;  
   
   my $r = '';  
   
   if (not defined $err->{level} or $err->{level} eq 'm') {  
     $r = qq[<strong><a href="../error-description#level-m"><em class=rfc2119>MUST</em>‐level  
         error</a></strong>: ];  
   } elsif ($err->{level} eq 's') {  
     $r = qq[<strong><a href="../error-description#level-s"><em class=rfc2119>SHOULD</em>‐level  
         error</a></strong>: ];  
   } elsif ($err->{level} eq 'w') {  
     $r = qq[<strong><a href="../error-description#level-w">Warning</a></strong>:  
         ];  
   } elsif ($err->{level} eq 'u' or $err->{level} eq 'unsupported') {  
     $r = qq[<strong><a href="../error-description#level-u">Not  
         supported</a></strong>: ];  
   } elsif ($err->{level} eq 'i') {  
     $r = qq[<strong><a href="../error-description#level-i">Information</a></strong>: ];  
   } else {  
     my $elevel = htescape ($err->{level});  
     $r = qq[<strong><a href="../error-description#level-$elevel">$elevel</a></strong>:  
         ];  
   }  
   
   return $r;  
 } # get_error_level_label  
   
 sub get_node_path ($) {  
   my $node = shift;  
   my @r;  
   while (defined $node) {  
     my $rs;  
     if ($node->node_type == 1) {  
       $rs = $node->node_name;  
       $node = $node->parent_node;  
     } elsif ($node->node_type == 2) {  
       $rs = '@' . $node->node_name;  
       $node = $node->owner_element;  
     } elsif ($node->node_type == 3) {  
       $rs = '"' . $node->data . '"';  
       $node = $node->parent_node;  
     } elsif ($node->node_type == 9) {  
       @r = ('') unless @r;  
       $rs = '';  
       $node = $node->parent_node;  
     } else {  
       $rs = '#' . $node->node_type;  
       $node = $node->parent_node;  
     }  
     unshift @r, $rs;  
   }  
   return join '/', @r;  
 } # get_node_path  
   
 sub get_node_link ($$) {  
   return qq[<a href="#$_[0]->{id_prefix}node-@{[refaddr $_[1]]}">] .  
       htescape (get_node_path ($_[1])) . qq[</a>];  
 } # get_node_link  
   
523  {  {
524    my $Msg = {};    my $Msg = {};
525    
526  sub load_text_catalog ($) {  sub load_text_catalog ($) {
527    #  my $self = shift;
528    my $lang = shift; # MUST be a canonical lang name    my $lang = shift; # MUST be a canonical lang name
529    open my $file, '<:utf8', "cc-msg.$lang.txt"    open my $file, '<:utf8', "cc-msg.$lang.txt"
530        or die "$0: cc-msg.$lang.txt: $!";        or die "$0: cc-msg.$lang.txt: $!";
# Line 1478  sub load_text_catalog ($) { Line 537  sub load_text_catalog ($) {
537    }    }
538  } # load_text_catalog  } # load_text_catalog
539    
540  sub get_text ($) {  sub get_text ($;$$) {
541    #  my $self = shift;
542    my ($type, $level, $node) = @_;    my ($type, $level, $node) = @_;
543    $type = $level . ':' . $type if defined $level;    $type = $level . ':' . $type if defined $level;
544    $level = 'm' unless defined $level;    $level = 'm' unless defined $level;
# Line 1487  sub get_text ($) { Line 547  sub get_text ($) {
547      if (defined $Msg->{$type}) {      if (defined $Msg->{$type}) {
548        my $msg = $Msg->{$type}->[1];        my $msg = $Msg->{$type}->[1];
549        $msg =~ s{<var>\$([0-9]+)</var>}{        $msg =~ s{<var>\$([0-9]+)</var>}{
550          defined $arg[$1] ? htescape ($arg[$1]) : '(undef)';          defined $arg[$1] ? ($arg[$1]) : '(undef)';
551        }ge;        }ge;                 ##BUG: ^ must be escaped
552        $msg =~ s{<var>{\@([A-Za-z0-9:_.-]+)}</var>}{        $msg =~ s{<var>{\@([A-Za-z0-9:_.-]+)}</var>}{
553          UNIVERSAL::can ($node, 'get_attribute_ns')          UNIVERSAL::can ($node, 'get_attribute_ns')
554              ? htescape ($node->get_attribute_ns (undef, $1)) : ''              ?  ($node->get_attribute_ns (undef, $1)) : ''
555        }ge;        }ge; ## BUG: ^ must be escaped
556        $msg =~ s{<var>{\@}</var>}{        $msg =~ s{<var>{\@}</var>}{        ## BUG: v must be escaped
557          UNIVERSAL::can ($node, 'value') ? htescape ($node->value) : ''          UNIVERSAL::can ($node, 'value') ? ($node->value) : ''
558        }ge;        }ge;
559        $msg =~ s{<var>{local-name}</var>}{        $msg =~ s{<var>{local-name}</var>}{
560          UNIVERSAL::can ($node, 'manakai_local_name')          UNIVERSAL::can ($node, 'manakai_local_name')
561            ? htescape ($node->manakai_local_name) : ''            ? ($node->manakai_local_name) : ''
562        }ge;        }ge;  ## BUG: ^ must be escaped
563        $msg =~ s{<var>{element-local-name}</var>}{        $msg =~ s{<var>{element-local-name}</var>}{
564          (UNIVERSAL::can ($node, 'owner_element') and          (UNIVERSAL::can ($node, 'owner_element') and
565           $node->owner_element)           $node->owner_element)
566            ? htescape ($node->owner_element->manakai_local_name)            ?  ($node->owner_element->manakai_local_name)
567            : ''            : '' ## BUG: ^ must be escaped
568        }ge;        }ge;
569        return ($type, 'level-' . $level . ' ' . $Msg->{$type}->[0], $msg);        return ($type, 'level-' . $level . ' ' . $Msg->{$type}->[0], $msg);
570      } elsif ($type =~ s/:([^:]*)$//) {      } elsif ($type =~ s/:([^:]*)$//) {
# Line 1512  sub get_text ($) { Line 572  sub get_text ($) {
572        redo;        redo;
573      }      }
574    }    }
575    return ($type, 'level-'.$level, htescape ($_[0]));    return ($type, 'level-'.$level, ($_[0]));
576                                     ## BUG: ^ must be escaped
577  } # get_text  } # get_text
578    
579  }  }
580    
 sub encode_uri_component ($) {  
   require Encode;  
   my $s = Encode::encode ('utf8', shift);  
   $s =~ s/([^0-9A-Za-z_.~-])/sprintf '%%%02X', ord $1/ge;  
   return $s;  
 } # encode_uri_component  
   
 sub get_cc_uri ($) {  
   return './?uri=' . encode_uri_component ($_[0]);  
 } # get_cc_uri  
   
581  sub get_input_document ($$) {  sub get_input_document ($$) {
582    my ($http, $dom) = @_;    my ($http, $dom) = @_;
583    
584    my $request_uri = $http->get_parameter ('uri');    my $request_uri = $http->get_parameter ('uri');
585    my $r = {};    my $r = WebHACC::Input->new;
586    if (defined $request_uri and length $request_uri) {    if (defined $request_uri and length $request_uri) {
587      my $uri = $dom->create_uri_reference ($request_uri);      my $uri = $dom->create_uri_reference ($request_uri);
588      unless ({      unless ({

Legend:
Removed from v.1.52  
changed lines
  Added in v.1.53

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24