/[suikacvs]/markup/html/whatpm/Whatpm/HTML/Tokenizer.pm
Suika

Diff of /markup/html/whatpm/Whatpm/HTML/Tokenizer.pm

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

revision 1.15 by wakaba, Sat Oct 18 08:05:29 2008 UTC revision 1.28 by wakaba, Sun Jul 5 04:38:45 2009 UTC
# Line 177  sub DOCTYPE_ATTLIST_ATTRIBUTE_DECLARATIO Line 177  sub DOCTYPE_ATTLIST_ATTRIBUTE_DECLARATIO
177  sub DOCTYPE_ATTLIST_ATTRIBUTE_DECLARATION_STATE () { 82 }  sub DOCTYPE_ATTLIST_ATTRIBUTE_DECLARATION_STATE () { 82 }
178  sub DOCTYPE_ATTLIST_ATTRIBUTE_DECLARATION_AFTER_STATE () { 83 }  sub DOCTYPE_ATTLIST_ATTRIBUTE_DECLARATION_AFTER_STATE () { 83 }
179  sub AFTER_ATTLIST_ATTR_VALUE_QUOTED_STATE () { 84 }  sub AFTER_ATTLIST_ATTR_VALUE_QUOTED_STATE () { 84 }
180    sub BEFORE_NDATA_STATE () { 85 }
181    sub NDATA_STATE () { 86 }
182    sub AFTER_NDATA_STATE () { 87 }
183    sub BEFORE_NOTATION_NAME_STATE () { 88 }
184    sub NOTATION_NAME_STATE () { 89 }
185    sub DOCTYPE_ENTITY_VALUE_DOUBLE_QUOTED_STATE () { 90 }
186    sub DOCTYPE_ENTITY_VALUE_SINGLE_QUOTED_STATE () { 91 }
187    sub ENTITY_VALUE_ENTITY_STATE () { 92 }
188    sub AFTER_ELEMENT_NAME_STATE () { 93 }
189    sub BEFORE_ELEMENT_CONTENT_STATE () { 94 }
190    sub CONTENT_KEYWORD_STATE () { 95 }
191    sub AFTER_CM_GROUP_OPEN_STATE () { 96 }
192    sub CM_ELEMENT_NAME_STATE () { 97 }
193    sub AFTER_CM_ELEMENT_NAME_STATE () { 98 }
194    sub AFTER_CM_GROUP_CLOSE_STATE () { 99 }
195    sub AFTER_MD_DEF_STATE () { 100 }
196    sub BOGUS_MD_STATE () { 101 }
197    
198  ## Tree constructor state constants (see Whatpm::HTML for the full  ## Tree constructor state constants (see Whatpm::HTML for the full
199  ## list and descriptions)  ## list and descriptions)
# Line 1723  sub _get_next_token ($) { Line 1740  sub _get_next_token ($) {
1740    
1741          redo A;          redo A;
1742        } else {        } else {
1743          if ($self->{nc} == 0x003D) { # =          if ($self->{nc} == 0x003D or $self->{nc} == 0x003C) { # =, <
1744                        
1745            ## XML5: Not a parse error.            ## XML5: Not a parse error.
1746            $self->{parse_error}->(level => $self->{level}->{must}, type => 'bad attribute value');            $self->{parse_error}->(level => $self->{level}->{must}, type => 'bad attribute value');
# Line 1799  sub _get_next_token ($) { Line 1816  sub _get_next_token ($) {
1816      }      }
1817        
1818          redo A;          redo A;
1819          } elsif ($self->{is_xml} and
1820                   $is_space->{$self->{nc}}) {
1821            
1822            $self->{ca}->{value} .= ' ';
1823            ## Stay in the state.
1824            
1825        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
1826          $self->{line_prev} = $self->{line};
1827          $self->{column_prev} = $self->{column};
1828          $self->{column}++;
1829          $self->{nc}
1830              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
1831        } else {
1832          $self->{set_nc}->($self);
1833        }
1834      
1835            redo A;
1836        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
1837          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed attribute value');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed attribute value');
1838          if ($self->{ct}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
# Line 1846  sub _get_next_token ($) { Line 1880  sub _get_next_token ($) {
1880          }          }
1881          $self->{ca}->{value} .= chr ($self->{nc});          $self->{ca}->{value} .= chr ($self->{nc});
1882          $self->{read_until}->($self->{ca}->{value},          $self->{read_until}->($self->{ca}->{value},
1883                                q["&<],                                qq["&<\x09\x0C\x20],
1884                                length $self->{ca}->{value});                                length $self->{ca}->{value});
1885    
1886          ## Stay in the state          ## Stay in the state
# Line 1913  sub _get_next_token ($) { Line 1947  sub _get_next_token ($) {
1947      }      }
1948        
1949          redo A;          redo A;
1950          } elsif ($self->{is_xml} and
1951                   $is_space->{$self->{nc}}) {
1952            
1953            $self->{ca}->{value} .= ' ';
1954            ## Stay in the state.
1955            
1956        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
1957          $self->{line_prev} = $self->{line};
1958          $self->{column_prev} = $self->{column};
1959          $self->{column}++;
1960          $self->{nc}
1961              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
1962        } else {
1963          $self->{set_nc}->($self);
1964        }
1965      
1966            redo A;
1967        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
1968          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed attribute value');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed attribute value');
1969          if ($self->{ct}->{type} == START_TAG_TOKEN) {          if ($self->{ct}->{type} == START_TAG_TOKEN) {
# Line 1960  sub _get_next_token ($) { Line 2011  sub _get_next_token ($) {
2011          }          }
2012          $self->{ca}->{value} .= chr ($self->{nc});          $self->{ca}->{value} .= chr ($self->{nc});
2013          $self->{read_until}->($self->{ca}->{value},          $self->{read_until}->($self->{ca}->{value},
2014                                q['&<],                                qq['&<\x09\x0C\x20],
2015                                length $self->{ca}->{value});                                length $self->{ca}->{value});
2016    
2017          ## Stay in the state          ## Stay in the state
# Line 2132  sub _get_next_token ($) { Line 2183  sub _get_next_token ($) {
2183               0x0022 => 1, # "               0x0022 => 1, # "
2184               0x0027 => 1, # '               0x0027 => 1, # '
2185               0x003D => 1, # =               0x003D => 1, # =
2186                 0x003C => 1, # <
2187              }->{$self->{nc}}) {              }->{$self->{nc}}) {
2188                        
2189            ## XML5: Not a parse error.            ## XML5: Not a parse error.
# Line 2141  sub _get_next_token ($) { Line 2193  sub _get_next_token ($) {
2193          }          }
2194          $self->{ca}->{value} .= chr ($self->{nc});          $self->{ca}->{value} .= chr ($self->{nc});
2195          $self->{read_until}->($self->{ca}->{value},          $self->{read_until}->($self->{ca}->{value},
2196                                q["'=& >],                                qq["'=& \x09\x0C>],
2197                                length $self->{ca}->{value});                                length $self->{ca}->{value});
2198    
2199          ## Stay in the state          ## Stay in the state
# Line 2947  sub _get_next_token ($) { Line 2999  sub _get_next_token ($) {
2999          redo A;          redo A;
3000        } else {        } else {
3001                    
         ## XML5: Not a parse error.  
         $self->{parse_error}->(level => $self->{level}->{must}, type => 'dash in comment',  
                         line => $self->{line_prev},  
                         column => $self->{column_prev});  
3002          $self->{ct}->{data} .= '--' . chr ($self->{nc}); # comment          $self->{ct}->{data} .= '--' . chr ($self->{nc}); # comment
3003          $self->{state} = COMMENT_STATE;          $self->{state} = COMMENT_STATE;
3004                    
# Line 2982  sub _get_next_token ($) { Line 3030  sub _get_next_token ($) {
3030      }      }
3031        
3032          redo A;          redo A;
3033          } elsif ($self->{nc} == -1) {
3034            
3035            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');
3036            $self->{ct}->{quirks} = 1;
3037    
3038            $self->{state} = DATA_STATE;
3039            ## Reconsume.
3040            return  ($self->{ct}); # DOCTYPE (quirks)
3041    
3042            redo A;
3043        } else {        } else {
3044                    
3045          ## XML5: Unless EOF, swith to the bogus comment state.          ## XML5: Swith to the bogus comment state.
3046          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no space before DOCTYPE name');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no space before DOCTYPE name');
3047          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;          $self->{state} = BEFORE_DOCTYPE_NAME_STATE;
3048          ## reconsume          ## reconsume
# Line 3182  sub _get_next_token ($) { Line 3240  sub _get_next_token ($) {
3240        
3241          redo A;          redo A;
3242        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
3243            if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3244              
3245              $self->{state} = DATA_STATE;
3246              $self->{s_kwd} = '';
3247            } else {
3248              
3249              $self->{parse_error}->(level => $self->{level}->{must}, type => 'no md def'); ## TODO: type
3250              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3251            }
3252                    
         $self->{state} = DATA_STATE;  
         $self->{s_kwd} = '';  
3253                    
3254      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3255        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3196  sub _get_next_token ($) { Line 3261  sub _get_next_token ($) {
3261        $self->{set_nc}->($self);        $self->{set_nc}->($self);
3262      }      }
3263        
3264            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         return  ($self->{ct}); # DOCTYPE  
   
3265          redo A;          redo A;
3266        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
3267            if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3268              
3269              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');
3270              $self->{state} = DATA_STATE;
3271              $self->{s_kwd} = '';
3272              $self->{ct}->{quirks} = 1;
3273            } else {
3274              
3275              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
3276              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3277            }
3278                    
3279          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');          ## Reconsume.
3280          $self->{state} = DATA_STATE;          return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{s_kwd} = '';  
         ## reconsume  
   
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
3281          redo A;          redo A;
3282        } elsif ($self->{nc} == 0x0050 or # P        } elsif ($self->{nc} == 0x0050 or # P
3283                 $self->{nc} == 0x0070) { # p                 $self->{nc} == 0x0070) { # p
# Line 3245  sub _get_next_token ($) { Line 3313  sub _get_next_token ($) {
3313      }      }
3314        
3315          redo A;          redo A;
3316        } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [        } elsif ($self->{nc} == 0x0022 and # "
3317                   ($self->{ct}->{type} == GENERAL_ENTITY_TOKEN or
3318                    $self->{ct}->{type} == PARAMETER_ENTITY_TOKEN)) {
3319            
3320            $self->{state} = DOCTYPE_ENTITY_VALUE_DOUBLE_QUOTED_STATE;
3321            $self->{ct}->{value} = ''; # ENTITY
3322            
3323        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3324          $self->{line_prev} = $self->{line};
3325          $self->{column_prev} = $self->{column};
3326          $self->{column}++;
3327          $self->{nc}
3328              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
3329        } else {
3330          $self->{set_nc}->($self);
3331        }
3332      
3333            redo A;
3334          } elsif ($self->{nc} == 0x0027 and # '
3335                   ($self->{ct}->{type} == GENERAL_ENTITY_TOKEN or
3336                    $self->{ct}->{type} == PARAMETER_ENTITY_TOKEN)) {
3337            
3338            $self->{state} = DOCTYPE_ENTITY_VALUE_SINGLE_QUOTED_STATE;
3339            $self->{ct}->{value} = ''; # ENTITY
3340            
3341        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3342          $self->{line_prev} = $self->{line};
3343          $self->{column_prev} = $self->{column};
3344          $self->{column}++;
3345          $self->{nc}
3346              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
3347        } else {
3348          $self->{set_nc}->($self);
3349        }
3350      
3351            redo A;
3352          } elsif ($self->{is_xml} and
3353                   $self->{ct}->{type} == DOCTYPE_TOKEN and
3354                   $self->{nc} == 0x005B) { # [
3355                    
3356          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3357          $self->{ct}->{has_internal_subset} = 1; # DOCTYPE          $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
# Line 3264  sub _get_next_token ($) { Line 3370  sub _get_next_token ($) {
3370          return  ($self->{ct}); # DOCTYPE          return  ($self->{ct}); # DOCTYPE
3371          redo A;          redo A;
3372        } else {        } else {
3373                    $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after DOCTYPE name'); ## TODO: type
3374          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after DOCTYPE name');  
3375          $self->{ct}->{quirks} = 1;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3376              
3377              $self->{ct}->{quirks} = 1;
3378              $self->{state} = BOGUS_DOCTYPE_STATE;
3379            } else {
3380              
3381              $self->{state} = BOGUS_MD_STATE;
3382            }
3383    
         $self->{state} = BOGUS_DOCTYPE_STATE;  
3384                    
3385      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3386        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3340  sub _get_next_token ($) { Line 3452  sub _get_next_token ($) {
3452        
3453          redo A;          redo A;
3454        } else {        } else {
3455                    $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after DOCTYPE name', ## TODO: type
         $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after DOCTYPE name',  
3456                          line => $self->{line_prev},                          line => $self->{line_prev},
3457                          column => $self->{column_prev} + 1 - length $self->{kwd});                          column => $self->{column_prev} + 1 - length $self->{kwd});
3458          $self->{ct}->{quirks} = 1;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3459              
3460          $self->{state} = BOGUS_DOCTYPE_STATE;            $self->{ct}->{quirks} = 1;
3461              $self->{state} = BOGUS_DOCTYPE_STATE;
3462            } else {
3463              
3464              $self->{state} = BOGUS_MD_STATE;
3465            }
3466          ## Reconsume.          ## Reconsume.
3467          redo A;          redo A;
3468        }        }
# Line 3408  sub _get_next_token ($) { Line 3524  sub _get_next_token ($) {
3524        
3525          redo A;          redo A;
3526        } else {        } else {
3527                    $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after DOCTYPE name', ## TODO: type
         $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after DOCTYPE name',  
3528                          line => $self->{line_prev},                          line => $self->{line_prev},
3529                          column => $self->{column_prev} + 1 - length $self->{kwd});                          column => $self->{column_prev} + 1 - length $self->{kwd});
3530          $self->{ct}->{quirks} = 1;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3531              
3532          $self->{state} = BOGUS_DOCTYPE_STATE;            $self->{ct}->{quirks} = 1;
3533              $self->{state} = BOGUS_DOCTYPE_STATE;
3534            } else {
3535              
3536              $self->{state} = BOGUS_MD_STATE;
3537            }
3538          ## Reconsume.          ## Reconsume.
3539          redo A;          redo A;
3540        }        }
# Line 3467  sub _get_next_token ($) { Line 3587  sub _get_next_token ($) {
3587        
3588          redo A;          redo A;
3589        } elsif ($self->{nc} eq 0x003E) { # >        } elsif ($self->{nc} eq 0x003E) { # >
           
3590          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no PUBLIC literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no PUBLIC literal');
3591            
3592          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3593          $self->{s_kwd} = '';            
3594              $self->{state} = DATA_STATE;
3595              $self->{s_kwd} = '';
3596              $self->{ct}->{quirks} = 1;
3597            } else {
3598              
3599              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3600            }
3601            
3602                    
3603      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3604        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3483  sub _get_next_token ($) { Line 3610  sub _get_next_token ($) {
3610        $self->{set_nc}->($self);        $self->{set_nc}->($self);
3611      }      }
3612        
3613            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
3614          redo A;          redo A;
3615        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
3616            if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3617              
3618              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');
3619              $self->{state} = DATA_STATE;
3620              $self->{s_kwd} = '';
3621              $self->{ct}->{quirks} = 1;
3622            } else {
3623              
3624              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
3625              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3626            }
3627                    
         $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         $self->{s_kwd} = '';  
3628          ## reconsume          ## reconsume
   
         $self->{ct}->{quirks} = 1;  
3629          return  ($self->{ct}); # DOCTYPE          return  ($self->{ct}); # DOCTYPE
   
3630          redo A;          redo A;
3631        } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [        } elsif ($self->{is_xml} and
3632                   $self->{ct}->{type} == DOCTYPE_TOKEN and
3633                   $self->{nc} == 0x005B) { # [
3634                    
3635          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no PUBLIC literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no PUBLIC literal');
3636          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
# Line 3520  sub _get_next_token ($) { Line 3650  sub _get_next_token ($) {
3650          return  ($self->{ct}); # DOCTYPE          return  ($self->{ct}); # DOCTYPE
3651          redo A;          redo A;
3652        } else {        } else {
           
3653          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after PUBLIC');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after PUBLIC');
         $self->{ct}->{quirks} = 1;  
3654    
3655          $self->{state} = BOGUS_DOCTYPE_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3656              
3657              $self->{ct}->{quirks} = 1;
3658              $self->{state} = BOGUS_DOCTYPE_STATE;
3659            } else {
3660              
3661              $self->{state} = BOGUS_MD_STATE;
3662            }
3663    
3664                    
3665      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3666        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3555  sub _get_next_token ($) { Line 3691  sub _get_next_token ($) {
3691        
3692          redo A;          redo A;
3693        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
           
3694          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');
3695    
3696          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3697          $self->{s_kwd} = '';            
3698              $self->{state} = DATA_STATE;
3699              $self->{s_kwd} = '';
3700              $self->{ct}->{quirks} = 1;
3701            } else {
3702              
3703              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3704            }
3705    
3706                    
3707      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3708        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3571  sub _get_next_token ($) { Line 3714  sub _get_next_token ($) {
3714        $self->{set_nc}->($self);        $self->{set_nc}->($self);
3715      }      }
3716        
3717            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
3718          redo A;          redo A;
3719        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
           
3720          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');
3721    
3722          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3723          $self->{s_kwd} = '';            
3724          ## reconsume            $self->{state} = DATA_STATE;
3725              $self->{s_kwd} = '';
3726          $self->{ct}->{quirks} = 1;            $self->{ct}->{quirks} = 1;
3727            } else {
3728              
3729              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3730            }
3731            
3732            ## Reconsume.
3733          return  ($self->{ct}); # DOCTYPE          return  ($self->{ct}); # DOCTYPE
   
3734          redo A;          redo A;
3735        } else {        } else {
3736                    
3737          $self->{ct}->{pubid} # DOCTYPE          $self->{ct}->{pubid} .= chr $self->{nc}; # DOCTYPE/ENTITY/NOTATION
             .= chr $self->{nc};  
3738          $self->{read_until}->($self->{ct}->{pubid}, q[">],          $self->{read_until}->($self->{ct}->{pubid}, q[">],
3739                                length $self->{ct}->{pubid});                                length $self->{ct}->{pubid});
3740    
# Line 3626  sub _get_next_token ($) { Line 3769  sub _get_next_token ($) {
3769        
3770          redo A;          redo A;
3771        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
           
3772          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');
3773    
3774          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3775          $self->{s_kwd} = '';            
3776              $self->{state} = DATA_STATE;
3777              $self->{s_kwd} = '';
3778              $self->{ct}->{quirks} = 1;
3779            } else {
3780              
3781              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3782            }
3783    
3784                    
3785      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3786        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3642  sub _get_next_token ($) { Line 3792  sub _get_next_token ($) {
3792        $self->{set_nc}->($self);        $self->{set_nc}->($self);
3793      }      }
3794        
3795            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
3796          redo A;          redo A;
3797        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
           
3798          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed PUBLIC literal');
3799    
3800          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3801          $self->{s_kwd} = '';            
3802              $self->{state} = DATA_STATE;
3803              $self->{s_kwd} = '';
3804              $self->{ct}->{quirks} = 1;
3805            } else {
3806              
3807              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3808            }
3809          
3810          ## reconsume          ## reconsume
3811            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
3812          redo A;          redo A;
3813        } else {        } else {
3814                    
3815          $self->{ct}->{pubid} # DOCTYPE          $self->{ct}->{pubid} .= chr $self->{nc}; # DOCTYPE/ENTITY/NOTATION
             .= chr $self->{nc};  
3816          $self->{read_until}->($self->{ct}->{pubid}, q['>],          $self->{read_until}->($self->{ct}->{pubid}, q['>],
3817                                length $self->{ct}->{pubid});                                length $self->{ct}->{pubid});
3818    
# Line 3698  sub _get_next_token ($) { Line 3848  sub _get_next_token ($) {
3848          redo A;          redo A;
3849        } elsif ($self->{nc} == 0x0022) { # "        } elsif ($self->{nc} == 0x0022) { # "
3850                    
3851          $self->{ct}->{sysid} = ''; # DOCTYPE          $self->{ct}->{sysid} = ''; # DOCTYPE/ENTITY/NOTATION
3852          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED_STATE;
3853                    
3854      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
# Line 3714  sub _get_next_token ($) { Line 3864  sub _get_next_token ($) {
3864          redo A;          redo A;
3865        } elsif ($self->{nc} == 0x0027) { # '        } elsif ($self->{nc} == 0x0027) { # '
3866                    
3867          $self->{ct}->{sysid} = ''; # DOCTYPE          $self->{ct}->{sysid} = ''; # DOCTYPE/ENTITY/NOTATION
3868          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;          $self->{state} = DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED_STATE;
3869                    
3870      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
# Line 3729  sub _get_next_token ($) { Line 3879  sub _get_next_token ($) {
3879        
3880          redo A;          redo A;
3881        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
3882          if ($self->{is_xml}) {          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3883                        if ($self->{is_xml}) {
3884            $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');              
3885                $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');
3886              } else {
3887                
3888              }
3889              $self->{state} = DATA_STATE;
3890              $self->{s_kwd} = '';
3891          } else {          } else {
3892                        if ($self->{ct}->{type} == NOTATION_TOKEN) {
3893                
3894              } else {
3895                
3896                $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');            
3897              }
3898              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3899          }          }
3900          $self->{state} = DATA_STATE;          
         $self->{s_kwd} = '';  
3901                    
3902      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3903        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3748  sub _get_next_token ($) { Line 3909  sub _get_next_token ($) {
3909        $self->{set_nc}->($self);        $self->{set_nc}->($self);
3910      }      }
3911        
3912            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         return  ($self->{ct}); # DOCTYPE  
   
3913          redo A;          redo A;
3914        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
3915            if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3916              
3917              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');
3918              
3919              $self->{state} = DATA_STATE;
3920              $self->{s_kwd} = '';
3921              $self->{ct}->{quirks} = 1;
3922            } else {
3923              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
3924              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
3925            }
3926                    
         $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         $self->{s_kwd} = '';  
3927          ## reconsume          ## reconsume
3928            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
3929          redo A;          redo A;
3930        } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [        } elsif ($self->{is_xml} and
3931                   $self->{ct}->{type} == DOCTYPE_TOKEN and
3932                   $self->{nc} == 0x005B) { # [
3933                    
3934          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');
3935          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
# Line 3784  sub _get_next_token ($) { Line 3949  sub _get_next_token ($) {
3949          return  ($self->{ct}); # DOCTYPE          return  ($self->{ct}); # DOCTYPE
3950          redo A;          redo A;
3951        } else {        } else {
           
3952          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after PUBLIC literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after PUBLIC literal');
         $self->{ct}->{quirks} = 1;  
3953    
3954          $self->{state} = BOGUS_DOCTYPE_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
3955              
3956              $self->{ct}->{quirks} = 1;
3957              $self->{state} = BOGUS_DOCTYPE_STATE;
3958            } else {
3959              
3960              $self->{state} = BOGUS_MD_STATE;
3961            }
3962    
3963                    
3964      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
3965        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3851  sub _get_next_token ($) { Line 4022  sub _get_next_token ($) {
4022        
4023          redo A;          redo A;
4024        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
           
4025          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');
         $self->{state} = DATA_STATE;  
         $self->{s_kwd} = '';  
4026                    
4027      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4028        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3867  sub _get_next_token ($) { Line 4035  sub _get_next_token ($) {
4035      }      }
4036        
4037    
4038          $self->{ct}->{quirks} = 1;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4039          return  ($self->{ct}); # DOCTYPE            
4040              $self->{state} = DATA_STATE;
4041              $self->{s_kwd} = '';
4042              $self->{ct}->{quirks} = 1;
4043            } else {
4044              
4045              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4046            }
4047    
4048            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
4049          redo A;          redo A;
4050        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
4051            if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4052              
4053              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');
4054              $self->{state} = DATA_STATE;
4055              $self->{s_kwd} = '';
4056              $self->{ct}->{quirks} = 1;
4057            } else {
4058              
4059              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
4060              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4061            }
4062                    
         $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');  
   
         $self->{state} = DATA_STATE;  
         $self->{s_kwd} = '';  
4063          ## reconsume          ## reconsume
4064            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
4065          redo A;          redo A;
4066        } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [        } elsif ($self->{is_xml} and
4067                   $self->{ct}->{type} == DOCTYPE_TOKEN and
4068                   $self->{nc} == 0x005B) { # [
4069                    
4070          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no SYSTEM literal');
4071    
# Line 3904  sub _get_next_token ($) { Line 4086  sub _get_next_token ($) {
4086          return  ($self->{ct}); # DOCTYPE          return  ($self->{ct}); # DOCTYPE
4087          redo A;          redo A;
4088        } else {        } else {
           
4089          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after SYSTEM');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after SYSTEM');
         $self->{ct}->{quirks} = 1;  
4090    
4091          $self->{state} = BOGUS_DOCTYPE_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4092                        
4093              $self->{ct}->{quirks} = 1;
4094              $self->{state} = BOGUS_DOCTYPE_STATE;
4095            } else {
4096              
4097              $self->{state} = BOGUS_MD_STATE;
4098            }
4099    
4100                    
4101      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4102        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3939  sub _get_next_token ($) { Line 4127  sub _get_next_token ($) {
4127        
4128          redo A;          redo A;
4129        } elsif (not $self->{is_xml} and $self->{nc} == 0x003E) { # >        } elsif (not $self->{is_xml} and $self->{nc} == 0x003E) { # >
           
4130          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed SYSTEM literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed SYSTEM literal');
4131    
4132          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4133          $self->{s_kwd} = '';            
4134              $self->{state} = DATA_STATE;
4135              $self->{s_kwd} = '';
4136              $self->{ct}->{quirks} = 1;
4137            } else {
4138              
4139              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4140            }
4141            
4142                    
4143      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4144        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 3955  sub _get_next_token ($) { Line 4150  sub _get_next_token ($) {
4150        $self->{set_nc}->($self);        $self->{set_nc}->($self);
4151      }      }
4152        
4153            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
4154          redo A;          redo A;
4155        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
           
4156          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed SYSTEM literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed SYSTEM literal');
4157    
4158          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4159          $self->{s_kwd} = '';            
4160              $self->{state} = DATA_STATE;
4161              $self->{s_kwd} = '';
4162              $self->{ct}->{quirks} = 1;
4163            } else {
4164              
4165              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4166            }
4167            
4168          ## reconsume          ## reconsume
4169            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
         $self->{ct}->{quirks} = 1;  
         return  ($self->{ct}); # DOCTYPE  
   
4170          redo A;          redo A;
4171        } else {        } else {
4172                    
4173          $self->{ct}->{sysid} # DOCTYPE          $self->{ct}->{sysid} .= chr $self->{nc}; # DOCTYPE/ENTITY/NOTATION
             .= chr $self->{nc};  
4174          $self->{read_until}->($self->{ct}->{sysid}, q[">],          $self->{read_until}->($self->{ct}->{sysid}, q[">],
4175                                length $self->{ct}->{sysid});                                length $self->{ct}->{sysid});
4176    
# Line 4032  sub _get_next_token ($) { Line 4227  sub _get_next_token ($) {
4227    
4228          redo A;          redo A;
4229        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
           
4230          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed SYSTEM literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed SYSTEM literal');
4231    
4232          $self->{state} = DATA_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4233          $self->{s_kwd} = '';            
4234          ## reconsume            $self->{state} = DATA_STATE;
4235              $self->{s_kwd} = '';
4236          $self->{ct}->{quirks} = 1;            $self->{ct}->{quirks} = 1;
4237          return  ($self->{ct}); # DOCTYPE          } else {
4238              
4239              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4240            }
4241    
4242            ## reconsume
4243            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
4244          redo A;          redo A;
4245        } else {        } else {
4246                    
4247          $self->{ct}->{sysid} # DOCTYPE          $self->{ct}->{sysid} .= chr $self->{nc}; # DOCTYPE/ENTITY/NOTATION
             .= chr $self->{nc};  
4248          $self->{read_until}->($self->{ct}->{sysid}, q['>],          $self->{read_until}->($self->{ct}->{sysid}, q['>],
4249                                length $self->{ct}->{sysid});                                length $self->{ct}->{sysid});
4250    
# Line 4066  sub _get_next_token ($) { Line 4264  sub _get_next_token ($) {
4264        }        }
4265      } elsif ($self->{state} == AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {      } elsif ($self->{state} == AFTER_DOCTYPE_SYSTEM_IDENTIFIER_STATE) {
4266        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
4267                    if ($self->{ct}->{type} == GENERAL_ENTITY_TOKEN) {
4268          ## Stay in the state            
4269              $self->{state} = BEFORE_NDATA_STATE;
4270            } else {
4271              
4272              ## Stay in the state
4273            }
4274                    
4275      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4276        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 4081  sub _get_next_token ($) { Line 4284  sub _get_next_token ($) {
4284        
4285          redo A;          redo A;
4286        } elsif ($self->{nc} == 0x003E) { # >        } elsif ($self->{nc} == 0x003E) { # >
4287            if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4288              
4289              $self->{state} = DATA_STATE;
4290              $self->{s_kwd} = '';
4291            } else {
4292              
4293              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4294            }
4295    
4296                    
4297          $self->{state} = DATA_STATE;      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4298          $self->{s_kwd} = '';        $self->{line_prev} = $self->{line};
4299          $self->{column_prev} = $self->{column};
4300          $self->{column}++;
4301          $self->{nc}
4302              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
4303        } else {
4304          $self->{set_nc}->($self);
4305        }
4306      
4307            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
4308            redo A;
4309          } elsif ($self->{ct}->{type} == GENERAL_ENTITY_TOKEN and
4310                   ($self->{nc} == 0x004E or # N
4311                    $self->{nc} == 0x006E)) { # n
4312            
4313            $self->{parse_error}->(level => $self->{level}->{must}, type => 'no space before NDATA'); ## TODO: type
4314            $self->{state} = NDATA_STATE;
4315            $self->{kwd} = chr $self->{nc};
4316                    
4317      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4318        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 4095  sub _get_next_token ($) { Line 4324  sub _get_next_token ($) {
4324        $self->{set_nc}->($self);        $self->{set_nc}->($self);
4325      }      }
4326        
   
         return  ($self->{ct}); # DOCTYPE  
   
4327          redo A;          redo A;
4328        } elsif ($self->{nc} == -1) {        } elsif ($self->{nc} == -1) {
4329                    if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4330          $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');            
4331          $self->{state} = DATA_STATE;            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed DOCTYPE');
4332          $self->{s_kwd} = '';            $self->{state} = DATA_STATE;
4333          ## reconsume            $self->{s_kwd} = '';
4334              $self->{ct}->{quirks} = 1;
4335          $self->{ct}->{quirks} = 1;          } else {
4336          return  ($self->{ct}); # DOCTYPE            
4337              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
4338              $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4339            }
4340    
4341            ## reconsume
4342            return  ($self->{ct}); # DOCTYPE/ENTITY/NOTATION
4343          redo A;          redo A;
4344        } elsif ($self->{is_xml} and $self->{nc} == 0x005B) { # [        } elsif ($self->{is_xml} and
4345                   $self->{ct}->{type} == DOCTYPE_TOKEN and
4346                   $self->{nc} == 0x005B) { # [
4347                    
4348          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4349          $self->{ct}->{has_internal_subset} = 1; # DOCTYPE          $self->{ct}->{has_internal_subset} = 1; # DOCTYPE
# Line 4129  sub _get_next_token ($) { Line 4362  sub _get_next_token ($) {
4362          return  ($self->{ct}); # DOCTYPE          return  ($self->{ct}); # DOCTYPE
4363          redo A;          redo A;
4364        } else {        } else {
           
4365          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after SYSTEM literal');          $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after SYSTEM literal');
         #$self->{ct}->{quirks} = 1;  
4366    
4367          $self->{state} = BOGUS_DOCTYPE_STATE;          if ($self->{ct}->{type} == DOCTYPE_TOKEN) {
4368              
4369              #$self->{ct}->{quirks} = 1;
4370              $self->{state} = BOGUS_DOCTYPE_STATE;
4371            } else {
4372              
4373              $self->{state} = BOGUS_MD_STATE;
4374            }
4375    
4376            
4377        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4378          $self->{line_prev} = $self->{line};
4379          $self->{column_prev} = $self->{column};
4380          $self->{column}++;
4381          $self->{nc}
4382              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
4383        } else {
4384          $self->{set_nc}->($self);
4385        }
4386      
4387            redo A;
4388          }
4389        } elsif ($self->{state} == BEFORE_NDATA_STATE) {
4390          if ($is_space->{$self->{nc}}) {
4391            
4392            ## Stay in the state.
4393            
4394        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4395          $self->{line_prev} = $self->{line};
4396          $self->{column_prev} = $self->{column};
4397          $self->{column}++;
4398          $self->{nc}
4399              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
4400        } else {
4401          $self->{set_nc}->($self);
4402        }
4403      
4404            redo A;
4405          } elsif ($self->{nc} == 0x003E) { # >
4406            
4407            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4408            
4409        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4410          $self->{line_prev} = $self->{line};
4411          $self->{column_prev} = $self->{column};
4412          $self->{column}++;
4413          $self->{nc}
4414              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
4415        } else {
4416          $self->{set_nc}->($self);
4417        }
4418      
4419            return  ($self->{ct}); # ENTITY
4420            redo A;
4421          } elsif ($self->{nc} == 0x004E or # N
4422                   $self->{nc} == 0x006E) { # n
4423            
4424            $self->{state} = NDATA_STATE;
4425            $self->{kwd} = chr $self->{nc};
4426            
4427        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4428          $self->{line_prev} = $self->{line};
4429          $self->{column_prev} = $self->{column};
4430          $self->{column}++;
4431          $self->{nc}
4432              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
4433        } else {
4434          $self->{set_nc}->($self);
4435        }
4436      
4437            redo A;
4438          } elsif ($self->{nc} == -1) {
4439            
4440            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
4441            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
4442            ## reconsume
4443            return  ($self->{ct}); # ENTITY
4444            redo A;
4445          } else {
4446            
4447            $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after SYSTEM literal');
4448            $self->{state} = BOGUS_MD_STATE;
4449                    
4450      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4451        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 4357  sub _get_next_token ($) { Line 4669  sub _get_next_token ($) {
4669              0x003C => 1, 0x0026 => 1, -1 => 1, # <, &              0x003C => 1, 0x0026 => 1, -1 => 1, # <, &
4670              $self->{entity_add} => 1,              $self->{entity_add} => 1,
4671            }->{$self->{nc}}) {            }->{$self->{nc}}) {
4672                    if ($self->{is_xml}) {
4673              
4674              $self->{parse_error}->(level => $self->{level}->{must}, type => 'bare ero',
4675                              line => $self->{line_prev},
4676                              column => $self->{column_prev}
4677                                  + ($self->{nc} == -1 ? 1 : 0));
4678            } else {
4679              
4680              ## No error
4681            }
4682          ## Don't consume          ## Don't consume
         ## No error  
4683          ## Return nothing.          ## Return nothing.
4684          #          #
4685        } elsif ($self->{nc} == 0x0023) { # #        } elsif ($self->{nc} == 0x0023) { # #
# Line 4378  sub _get_next_token ($) { Line 4698  sub _get_next_token ($) {
4698      }      }
4699        
4700          redo A;          redo A;
4701        } elsif ((0x0041 <= $self->{nc} and        } elsif ($self->{is_xml} or
4702                   (0x0041 <= $self->{nc} and
4703                  $self->{nc} <= 0x005A) or # A..Z                  $self->{nc} <= 0x005A) or # A..Z
4704                 (0x0061 <= $self->{nc} and                 (0x0061 <= $self->{nc} and
4705                  $self->{nc} <= 0x007A)) { # a..z                  $self->{nc} <= 0x007A)) { # a..z
# Line 4432  sub _get_next_token ($) { Line 4753  sub _get_next_token ($) {
4753          redo A;          redo A;
4754        }        }
4755      } elsif ($self->{state} == ENTITY_HASH_STATE) {      } elsif ($self->{state} == ENTITY_HASH_STATE) {
4756        if ($self->{nc} == 0x0078 or # x        if ($self->{nc} == 0x0078) { # x
           $self->{nc} == 0x0058) { # X  
4757                    
4758          $self->{state} = HEXREF_X_STATE;          $self->{state} = HEXREF_X_STATE;
4759          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
# Line 4449  sub _get_next_token ($) { Line 4769  sub _get_next_token ($) {
4769      }      }
4770        
4771          redo A;          redo A;
4772          } elsif ($self->{nc} == 0x0058) { # X
4773            
4774            if ($self->{is_xml}) {
4775              $self->{parse_error}->(level => $self->{level}->{must}, type => 'uppercase hcro'); ## TODO: type
4776            }
4777            $self->{state} = HEXREF_X_STATE;
4778            $self->{kwd} .= chr $self->{nc};
4779            
4780        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
4781          $self->{line_prev} = $self->{line};
4782          $self->{column_prev} = $self->{column};
4783          $self->{column}++;
4784          $self->{nc}
4785              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
4786        } else {
4787          $self->{set_nc}->($self);
4788        }
4789      
4790            redo A;
4791        } elsif (0x0030 <= $self->{nc} and        } elsif (0x0030 <= $self->{nc} and
4792                 $self->{nc} <= 0x0039) { # 0..9                 $self->{nc} <= 0x0039) { # 0..9
4793                    
# Line 4539  sub _get_next_token ($) { Line 4878  sub _get_next_token ($) {
4878        my $code = $self->{kwd};        my $code = $self->{kwd};
4879        my $l = $self->{line_prev};        my $l = $self->{line_prev};
4880        my $c = $self->{column_prev};        my $c = $self->{column_prev};
4881        if ($charref_map->{$code}) {        if ((not $self->{is_xml} and $charref_map->{$code}) or
4882              ($self->{is_xml} and 0xD800 <= $code and $code <= 0xDFFF) or
4883              ($self->{is_xml} and $code == 0x0000)) {
4884                    
4885          $self->{parse_error}->(level => $self->{level}->{must}, type => 'invalid character reference',          $self->{parse_error}->(level => $self->{level}->{must}, type => 'invalid character reference',
4886                          text => (sprintf 'U+%04X', $code),                          text => (sprintf 'U+%04X', $code),
# Line 4692  sub _get_next_token ($) { Line 5033  sub _get_next_token ($) {
5033        my $code = $self->{kwd};        my $code = $self->{kwd};
5034        my $l = $self->{line_prev};        my $l = $self->{line_prev};
5035        my $c = $self->{column_prev};        my $c = $self->{column_prev};
5036        if ($charref_map->{$code}) {        if ((not $self->{is_xml} and $charref_map->{$code}) or
5037              ($self->{is_xml} and 0xD800 <= $code and $code <= 0xDFFF) or
5038              ($self->{is_xml} and $code == 0x0000)) {
5039                    
5040          $self->{parse_error}->(level => $self->{level}->{must}, type => 'invalid character reference',          $self->{parse_error}->(level => $self->{level}->{must}, type => 'invalid character reference',
5041                          text => (sprintf 'U+%04X', $code),                          text => (sprintf 'U+%04X', $code),
# Line 4726  sub _get_next_token ($) { Line 5069  sub _get_next_token ($) {
5069          redo A;          redo A;
5070        }        }
5071      } elsif ($self->{state} == ENTITY_NAME_STATE) {      } elsif ($self->{state} == ENTITY_NAME_STATE) {
5072        if (length $self->{kwd} < 30 and        if ((0x0041 <= $self->{nc} and # a
5073            ## NOTE: Some number greater than the maximum length of entity name             $self->{nc} <= 0x005A) or # x
5074            ((0x0041 <= $self->{nc} and # a            (0x0061 <= $self->{nc} and # a
5075              $self->{nc} <= 0x005A) or # x             $self->{nc} <= 0x007A) or # z
5076             (0x0061 <= $self->{nc} and # a            (0x0030 <= $self->{nc} and # 0
5077              $self->{nc} <= 0x007A) or # z             $self->{nc} <= 0x0039) or # 9
5078             (0x0030 <= $self->{nc} and # 0            $self->{nc} == 0x003B or # ;
5079              $self->{nc} <= 0x0039) or # 9            ($self->{is_xml} and
5080             $self->{nc} == 0x003B)) { # ;             not ($is_space->{$self->{nc}} or
5081                    {
5082                      0x003C => 1, 0x0026 => 1, -1 => 1, # <, &
5083                      $self->{entity_add} => 1,
5084                    }->{$self->{nc}}))) {
5085          our $EntityChar;          our $EntityChar;
5086          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
5087          if (defined $EntityChar->{$self->{kwd}}) {          if (defined $EntityChar->{$self->{kwd}} or
5088                $self->{ge}->{$self->{kwd}}) {
5089            if ($self->{nc} == 0x003B) { # ;            if ($self->{nc} == 0x003B) { # ;
5090                            if (defined $self->{ge}->{$self->{kwd}}) {
5091              $self->{entity__value} = $EntityChar->{$self->{kwd}};                if ($self->{ge}->{$self->{kwd}}->{only_text}) {
5092                    
5093                    $self->{entity__value} = $self->{ge}->{$self->{kwd}}->{value};
5094                  } else {
5095                    if (defined $self->{ge}->{$self->{kwd}}->{notation}) {
5096                      
5097                      $self->{parse_error}->(level => $self->{level}->{must}, type => 'unparsed entity', ## TODO: type
5098                                      value => $self->{kwd});
5099                    } else {
5100                      
5101                    }
5102                    $self->{entity__value} = '&' . $self->{kwd}; ## TODO: expand
5103                  }
5104                } else {
5105                  if ($self->{is_xml}) {
5106                    
5107                    $self->{parse_error}->(level => $self->{level}->{must}, type => 'entity not declared', ## TODO: type
5108                                    value => $self->{kwd},
5109                                    level => {
5110                                              'amp;' => $self->{level}->{warn},
5111                                              'quot;' => $self->{level}->{warn},
5112                                              'lt;' => $self->{level}->{warn},
5113                                              'gt;' => $self->{level}->{warn},
5114                                              'apos;' => $self->{level}->{warn},
5115                                             }->{$self->{kwd}} ||
5116                                             $self->{level}->{must});
5117                  } else {
5118                    
5119                  }
5120                  $self->{entity__value} = $EntityChar->{$self->{kwd}};
5121                }
5122              $self->{entity__match} = 1;              $self->{entity__match} = 1;
5123                            
5124      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
# Line 5136  sub _get_next_token ($) { Line 5514  sub _get_next_token ($) {
5514          ## XML5: Not defined yet.          ## XML5: Not defined yet.
5515    
5516          ## TODO:          ## TODO:
5517    
5518            if (not $self->{stop_processing} and
5519                not $self->{document}->xml_standalone) {
5520              $self->{parse_error}->(level => $self->{level}->{must}, type => 'stop processing', ## TODO: type
5521                              level => $self->{level}->{info});
5522              $self->{stop_processing} = 1;
5523            }
5524    
5525                    
5526      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
5527        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 5358  sub _get_next_token ($) { Line 5744  sub _get_next_token ($) {
5744      }      }
5745        
5746          redo A;          redo A;
5747        } elsif ($self->{nc} == 0x0045) { # E        } elsif ($self->{nc} == 0x0045 or # E
5748                   $self->{nc} == 0x0065) { # e
5749          $self->{state} = MD_E_STATE;          $self->{state} = MD_E_STATE;
5750          $self->{kwd} = chr $self->{nc};          $self->{kwd} = chr $self->{nc};
5751                    
# Line 5373  sub _get_next_token ($) { Line 5760  sub _get_next_token ($) {
5760      }      }
5761        
5762          redo A;          redo A;
5763        } elsif ($self->{nc} == 0x0041) { # A        } elsif ($self->{nc} == 0x0041 or # A
5764                   $self->{nc} == 0x0061) { # a
5765          $self->{state} = MD_ATTLIST_STATE;          $self->{state} = MD_ATTLIST_STATE;
5766          $self->{kwd} = chr $self->{nc};          $self->{kwd} = chr $self->{nc};
5767                    
# Line 5388  sub _get_next_token ($) { Line 5776  sub _get_next_token ($) {
5776      }      }
5777        
5778          redo A;          redo A;
5779        } elsif ($self->{nc} == 0x004E) { # N        } elsif ($self->{nc} == 0x004E or # N
5780                   $self->{nc} == 0x006E) { # n
5781          $self->{state} = MD_NOTATION_STATE;          $self->{state} = MD_NOTATION_STATE;
5782          $self->{kwd} = chr $self->{nc};          $self->{kwd} = chr $self->{nc};
5783                    
# Line 5416  sub _get_next_token ($) { Line 5805  sub _get_next_token ($) {
5805        $self->{ct} = {type => COMMENT_TOKEN, data => ''}; ## Will be discarded.        $self->{ct} = {type => COMMENT_TOKEN, data => ''}; ## Will be discarded.
5806        redo A;        redo A;
5807      } elsif ($self->{state} == MD_E_STATE) {      } elsif ($self->{state} == MD_E_STATE) {
5808        if ($self->{nc} == 0x004E) { # N        if ($self->{nc} == 0x004E or # N
5809              $self->{nc} == 0x006E) { # n
5810          $self->{state} = MD_ENTITY_STATE;          $self->{state} = MD_ENTITY_STATE;
5811          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
5812                    
# Line 5431  sub _get_next_token ($) { Line 5821  sub _get_next_token ($) {
5821      }      }
5822        
5823          redo A;          redo A;
5824        } elsif ($self->{nc} == 0x004C) { # L        } elsif ($self->{nc} == 0x004C or # L
5825                   $self->{nc} == 0x006C) { # l
5826          ## XML5: <!ELEMENT> not supported.          ## XML5: <!ELEMENT> not supported.
5827          $self->{state} = MD_ELEMENT_STATE;          $self->{state} = MD_ELEMENT_STATE;
5828          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
# Line 5459  sub _get_next_token ($) { Line 5850  sub _get_next_token ($) {
5850          redo A;          redo A;
5851        }        }
5852      } elsif ($self->{state} == MD_ENTITY_STATE) {      } elsif ($self->{state} == MD_ENTITY_STATE) {
5853        if ($self->{nc} == {        if ($self->{nc} == [
5854              'EN' => 0x0054, # T              undef,
5855              'ENT' => 0x0049, # I              undef,
5856              'ENTI' => 0x0054, # T              0x0054, # T
5857            }->{$self->{kwd}}) {              0x0049, # I
5858                0x0054, # T
5859              ]->[length $self->{kwd}] or
5860              $self->{nc} == [
5861                undef,
5862                undef,
5863                0x0074, # t
5864                0x0069, # i
5865                0x0074, # t
5866              ]->[length $self->{kwd}]) {
5867          ## Stay in the state.          ## Stay in the state.
5868          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
5869                    
# Line 5478  sub _get_next_token ($) { Line 5878  sub _get_next_token ($) {
5878      }      }
5879        
5880          redo A;          redo A;
5881        } elsif ($self->{kwd} eq 'ENTIT' and        } elsif ((length $self->{kwd}) == 5 and
5882                 $self->{nc} == 0x0059) { # Y                 ($self->{nc} == 0x0059 or # Y
5883          $self->{ct} = {type => GENERAL_ENTITY_TOKEN, name => '', text => '',                  $self->{nc} == 0x0079)) { # y
5884            if ($self->{kwd} ne 'ENTIT' or $self->{nc} == 0x0079) {
5885              $self->{parse_error}->(level => $self->{level}->{must}, type => 'lowercase keyword', ## TODO: type
5886                              text => 'ENTITY',
5887                              line => $self->{line_prev},
5888                              column => $self->{column_prev} - 4);
5889            }
5890            $self->{ct} = {type => GENERAL_ENTITY_TOKEN, name => '',
5891                         line => $self->{line_prev},                         line => $self->{line_prev},
5892                         column => $self->{column_prev} - 6};                         column => $self->{column_prev} - 6};
5893          $self->{state} = DOCTYPE_MD_STATE;          $self->{state} = DOCTYPE_MD_STATE;
# Line 5508  sub _get_next_token ($) { Line 5915  sub _get_next_token ($) {
5915          redo A;          redo A;
5916        }        }
5917      } elsif ($self->{state} == MD_ELEMENT_STATE) {      } elsif ($self->{state} == MD_ELEMENT_STATE) {
5918        if ($self->{nc} == {        if ($self->{nc} == [
5919              'EL' => 0x0045, # E             undef,
5920              'ELE' => 0x004D, # M             undef,
5921              'ELEM' => 0x0045, # E             0x0045, # E
5922              'ELEME' => 0x004E, # N             0x004D, # M
5923            }->{$self->{kwd}}) {             0x0045, # E
5924               0x004E, # N
5925              ]->[length $self->{kwd}] or
5926              $self->{nc} == [
5927               undef,
5928               undef,
5929               0x0065, # e
5930               0x006D, # m
5931               0x0065, # e
5932               0x006E, # n
5933              ]->[length $self->{kwd}]) {
5934          ## Stay in the state.          ## Stay in the state.
5935          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
5936                    
# Line 5528  sub _get_next_token ($) { Line 5945  sub _get_next_token ($) {
5945      }      }
5946        
5947          redo A;          redo A;
5948        } elsif ($self->{kwd} eq 'ELEMEN' and        } elsif ((length $self->{kwd}) == 6 and
5949                 $self->{nc} == 0x0054) { # T                 ($self->{nc} == 0x0054 or # T
5950                    $self->{nc} == 0x0074)) { # t
5951            if ($self->{kwd} ne 'ELEMEN' or $self->{nc} == 0x0074) {
5952              $self->{parse_error}->(level => $self->{level}->{must}, type => 'lowercase keyword', ## TODO: type
5953                              text => 'ELEMENT',
5954                              line => $self->{line_prev},
5955                              column => $self->{column_prev} - 5);
5956            }
5957          $self->{ct} = {type => ELEMENT_TOKEN, name => '',          $self->{ct} = {type => ELEMENT_TOKEN, name => '',
5958                         line => $self->{line_prev},                         line => $self->{line_prev},
5959                         column => $self->{column_prev} - 6};                         column => $self->{column_prev} - 7};
5960          $self->{state} = DOCTYPE_MD_STATE;          $self->{state} = DOCTYPE_MD_STATE;
5961                    
5962      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
# Line 5558  sub _get_next_token ($) { Line 5982  sub _get_next_token ($) {
5982          redo A;          redo A;
5983        }        }
5984      } elsif ($self->{state} == MD_ATTLIST_STATE) {      } elsif ($self->{state} == MD_ATTLIST_STATE) {
5985        if ($self->{nc} == {        if ($self->{nc} == [
5986              'A' => 0x0054, # T             undef,
5987              'AT' => 0x0054, # T             0x0054, # T
5988              'ATT' => 0x004C, # L             0x0054, # T
5989              'ATTL' => 0x0049, # I             0x004C, # L
5990              'ATTLI' => 0x0053, # S             0x0049, # I
5991            }->{$self->{kwd}}) {             0x0053, # S
5992              ]->[length $self->{kwd}] or
5993              $self->{nc} == [
5994               undef,
5995               0x0074, # t
5996               0x0074, # t
5997               0x006C, # l
5998               0x0069, # i
5999               0x0073, # s
6000              ]->[length $self->{kwd}]) {
6001          ## Stay in the state.          ## Stay in the state.
6002          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
6003                    
# Line 5579  sub _get_next_token ($) { Line 6012  sub _get_next_token ($) {
6012      }      }
6013        
6014          redo A;          redo A;
6015        } elsif ($self->{kwd} eq 'ATTLIS' and        } elsif ((length $self->{kwd}) == 6 and
6016                 $self->{nc} == 0x0054) { # T                 ($self->{nc} == 0x0054 or # T
6017                    $self->{nc} == 0x0074)) { # t
6018            if ($self->{kwd} ne 'ATTLIS' or $self->{nc} == 0x0074) {
6019              $self->{parse_error}->(level => $self->{level}->{must}, type => 'lowercase keyword', ## TODO: type
6020                              text => 'ATTLIST',
6021                              line => $self->{line_prev},
6022                              column => $self->{column_prev} - 5);
6023            }
6024          $self->{ct} = {type => ATTLIST_TOKEN, name => '',          $self->{ct} = {type => ATTLIST_TOKEN, name => '',
6025                         attrdefs => [],                         attrdefs => [],
6026                         line => $self->{line_prev},                         line => $self->{line_prev},
6027                         column => $self->{column_prev} - 6};                         column => $self->{column_prev} - 7};
6028          $self->{state} = DOCTYPE_MD_STATE;          $self->{state} = DOCTYPE_MD_STATE;
6029                    
6030      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
# Line 5610  sub _get_next_token ($) { Line 6050  sub _get_next_token ($) {
6050          redo A;          redo A;
6051        }        }
6052      } elsif ($self->{state} == MD_NOTATION_STATE) {      } elsif ($self->{state} == MD_NOTATION_STATE) {
6053        if ($self->{nc} == {        if ($self->{nc} == [
6054              'N' => 0x004F, # O             undef,
6055              'NO' => 0x0054, # T             0x004F, # O
6056              'NOT' => 0x0041, # A             0x0054, # T
6057              'NOTA' => 0x0054, # T             0x0041, # A
6058              'NOTAT' => 0x0049, # I             0x0054, # T
6059              'NOTATI' => 0x004F, # O             0x0049, # I
6060            }->{$self->{kwd}}) {             0x004F, # O
6061              ]->[length $self->{kwd}] or
6062              $self->{nc} == [
6063               undef,
6064               0x006F, # o
6065               0x0074, # t
6066               0x0061, # a
6067               0x0074, # t
6068               0x0069, # i
6069               0x006F, # o
6070              ]->[length $self->{kwd}]) {
6071          ## Stay in the state.          ## Stay in the state.
6072          $self->{kwd} .= chr $self->{nc};          $self->{kwd} .= chr $self->{nc};
6073                    
# Line 5632  sub _get_next_token ($) { Line 6082  sub _get_next_token ($) {
6082      }      }
6083        
6084          redo A;          redo A;
6085        } elsif ($self->{kwd} eq 'NOTATIO' and        } elsif ((length $self->{kwd}) == 7 and
6086                 $self->{nc} == 0x004E) { # N                 ($self->{nc} == 0x004E or # N
6087                    $self->{nc} == 0x006E)) { # n
6088            if ($self->{kwd} ne 'NOTATIO' or $self->{nc} == 0x006E) {
6089              $self->{parse_error}->(level => $self->{level}->{must}, type => 'lowercase keyword', ## TODO: type
6090                              text => 'NOTATION',
6091                              line => $self->{line_prev},
6092                              column => $self->{column_prev} - 6);
6093            }
6094          $self->{ct} = {type => NOTATION_TOKEN, name => '',          $self->{ct} = {type => NOTATION_TOKEN, name => '',
6095                         line => $self->{line_prev},                         line => $self->{line_prev},
6096                         column => $self->{column_prev} - 6};                         column => $self->{column_prev} - 8};
6097          $self->{state} = DOCTYPE_MD_STATE;          $self->{state} = DOCTYPE_MD_STATE;
6098                    
6099      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
# Line 5845  sub _get_next_token ($) { Line 6302  sub _get_next_token ($) {
6302        ## XML5: "DOCTYPE ENTITY name state" and "DOCTYPE ATTLIST name state".        ## XML5: "DOCTYPE ENTITY name state" and "DOCTYPE ATTLIST name state".
6303                
6304        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
6305          ## TODO:          if ($self->{ct}->{type} == ATTLIST_TOKEN) {
6306          $self->{state} = DOCTYPE_ATTLIST_NAME_AFTER_STATE;            $self->{state} = DOCTYPE_ATTLIST_NAME_AFTER_STATE;
6307            } elsif ($self->{ct}->{type} == ELEMENT_TOKEN) {
6308              $self->{state} = AFTER_ELEMENT_NAME_STATE;
6309            } else { # ENTITY/NOTATION
6310              $self->{state} = AFTER_DOCTYPE_NAME_STATE;
6311            }
6312                    
6313      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {      if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
6314        $self->{line_prev} = $self->{line};        $self->{line_prev} = $self->{line};
# Line 5863  sub _get_next_token ($) { Line 6325  sub _get_next_token ($) {
6325          if ($self->{ct}->{type} == ATTLIST_TOKEN) {          if ($self->{ct}->{type} == ATTLIST_TOKEN) {
6326            #            #
6327          } else {          } else {
6328            $self->{parse_error}->(level => $self->{level}->{must}, type => 'no md body'); ## TODO: type            $self->{parse_error}->(level => $self->{level}->{must}, type => 'no md def'); ## TODO: type
6329          }          }
6330          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;          $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
6331                    
# Line 6853  sub _get_next_token ($) { Line 7315  sub _get_next_token ($) {
7315        if ($is_space->{$self->{nc}}) {        if ($is_space->{$self->{nc}}) {
7316          ## XML5: No parse error.          ## XML5: No parse error.
7317          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no default type'); ## TODO: type          $self->{parse_error}->(level => $self->{level}->{must}, type => 'no default type'); ## TODO: type
7318          $self->{state} = BOGUS_COMMENT_STATE;          $self->{state} = BOGUS_MD_STATE;
         $self->{ct} = {type => COMMENT_TOKEN, data => ''}; ## Will be discarded  
7319          ## Reconsume.          ## Reconsume.
7320          redo A;          redo A;
7321        } elsif ($self->{nc} == 0x0022) { # "        } elsif ($self->{nc} == 0x0022) { # "
# Line 7141  sub _get_next_token ($) { Line 7602  sub _get_next_token ($) {
7602          $self->{state} = DOCTYPE_ATTLIST_NAME_AFTER_STATE;          $self->{state} = DOCTYPE_ATTLIST_NAME_AFTER_STATE;
7603          ## Reconsume.          ## Reconsume.
7604          redo A;          redo A;
7605        }              }
7606        } elsif ($self->{state} == NDATA_STATE) {
7607          ## ASCII case-insensitive
7608          if ($self->{nc} == [
7609                undef,
7610                0x0044, # D
7611                0x0041, # A
7612                0x0054, # T
7613              ]->[length $self->{kwd}] or
7614              $self->{nc} == [
7615                undef,
7616                0x0064, # d
7617                0x0061, # a
7618                0x0074, # t
7619              ]->[length $self->{kwd}]) {
7620            
7621            ## Stay in the state.
7622            $self->{kwd} .= chr $self->{nc};
7623            
7624        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7625          $self->{line_prev} = $self->{line};
7626          $self->{column_prev} = $self->{column};
7627          $self->{column}++;
7628          $self->{nc}
7629              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7630        } else {
7631          $self->{set_nc}->($self);
7632        }
7633      
7634            redo A;
7635          } elsif ((length $self->{kwd}) == 4 and
7636                   ($self->{nc} == 0x0041 or # A
7637                    $self->{nc} == 0x0061)) { # a
7638            if ($self->{kwd} ne 'NDAT' or $self->{nc} == 0x0061) { # a
7639              
7640              $self->{parse_error}->(level => $self->{level}->{must}, type => 'lowercase keyword', ## TODO: type
7641                              text => 'NDATA',
7642                              line => $self->{line_prev},
7643                              column => $self->{column_prev} - 4);
7644            } else {
7645              
7646            }
7647            $self->{state} = AFTER_NDATA_STATE;
7648            
7649        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7650          $self->{line_prev} = $self->{line};
7651          $self->{column_prev} = $self->{column};
7652          $self->{column}++;
7653          $self->{nc}
7654              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7655        } else {
7656          $self->{set_nc}->($self);
7657        }
7658      
7659            redo A;
7660          } else {
7661            $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after literal', ## TODO: type
7662                            line => $self->{line_prev},
7663                            column => $self->{column_prev} + 1
7664                                - length $self->{kwd});
7665            
7666            $self->{state} = BOGUS_MD_STATE;
7667            ## Reconsume.
7668            redo A;
7669          }
7670        } elsif ($self->{state} == AFTER_NDATA_STATE) {
7671          if ($is_space->{$self->{nc}}) {
7672            $self->{state} = BEFORE_NOTATION_NAME_STATE;
7673            
7674        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7675          $self->{line_prev} = $self->{line};
7676          $self->{column_prev} = $self->{column};
7677          $self->{column}++;
7678          $self->{nc}
7679              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7680        } else {
7681          $self->{set_nc}->($self);
7682        }
7683      
7684            redo A;
7685          } elsif ($self->{nc} == 0x003E) { # >
7686            $self->{parse_error}->(level => $self->{level}->{must}, type => 'no notation name'); ## TODO: type
7687            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7688            
7689        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7690          $self->{line_prev} = $self->{line};
7691          $self->{column_prev} = $self->{column};
7692          $self->{column}++;
7693          $self->{nc}
7694              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7695        } else {
7696          $self->{set_nc}->($self);
7697        }
7698      
7699            return  ($self->{ct}); # ENTITY
7700            redo A;
7701          } elsif ($self->{nc} == -1) {
7702            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
7703            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7704            
7705        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7706          $self->{line_prev} = $self->{line};
7707          $self->{column_prev} = $self->{column};
7708          $self->{column}++;
7709          $self->{nc}
7710              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7711        } else {
7712          $self->{set_nc}->($self);
7713        }
7714      
7715            return  ($self->{ct}); # ENTITY
7716            redo A;
7717          } else {
7718            $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after literal', ## TODO: type
7719                            line => $self->{line_prev},
7720                            column => $self->{column_prev} + 1
7721                                - length $self->{kwd});
7722            $self->{state} = BOGUS_MD_STATE;
7723            ## Reconsume.
7724            redo A;
7725          }
7726        } elsif ($self->{state} == BEFORE_NOTATION_NAME_STATE) {
7727          if ($is_space->{$self->{nc}}) {
7728            ## Stay in the state.
7729            
7730        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7731          $self->{line_prev} = $self->{line};
7732          $self->{column_prev} = $self->{column};
7733          $self->{column}++;
7734          $self->{nc}
7735              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7736        } else {
7737          $self->{set_nc}->($self);
7738        }
7739      
7740            redo A;
7741          } elsif ($self->{nc} == 0x003E) { # >
7742            $self->{parse_error}->(level => $self->{level}->{must}, type => 'no notation name'); ## TODO: type
7743            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7744            
7745        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7746          $self->{line_prev} = $self->{line};
7747          $self->{column_prev} = $self->{column};
7748          $self->{column}++;
7749          $self->{nc}
7750              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7751        } else {
7752          $self->{set_nc}->($self);
7753        }
7754      
7755            return  ($self->{ct}); # ENTITY
7756            redo A;
7757          } elsif ($self->{nc} == -1) {
7758            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
7759            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7760            
7761        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7762          $self->{line_prev} = $self->{line};
7763          $self->{column_prev} = $self->{column};
7764          $self->{column}++;
7765          $self->{nc}
7766              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7767        } else {
7768          $self->{set_nc}->($self);
7769        }
7770      
7771            return  ($self->{ct}); # ENTITY
7772            redo A;
7773          } else {
7774            $self->{ct}->{notation} = chr $self->{nc}; # ENTITY
7775            $self->{state} = NOTATION_NAME_STATE;
7776            
7777        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7778          $self->{line_prev} = $self->{line};
7779          $self->{column_prev} = $self->{column};
7780          $self->{column}++;
7781          $self->{nc}
7782              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7783        } else {
7784          $self->{set_nc}->($self);
7785        }
7786      
7787            redo A;
7788          }
7789        } elsif ($self->{state} == NOTATION_NAME_STATE) {
7790          if ($is_space->{$self->{nc}}) {
7791            $self->{state} = AFTER_MD_DEF_STATE;
7792            
7793        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7794          $self->{line_prev} = $self->{line};
7795          $self->{column_prev} = $self->{column};
7796          $self->{column}++;
7797          $self->{nc}
7798              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7799        } else {
7800          $self->{set_nc}->($self);
7801        }
7802      
7803            redo A;
7804          } elsif ($self->{nc} == 0x003E) { # >
7805            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7806            
7807        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7808          $self->{line_prev} = $self->{line};
7809          $self->{column_prev} = $self->{column};
7810          $self->{column}++;
7811          $self->{nc}
7812              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7813        } else {
7814          $self->{set_nc}->($self);
7815        }
7816      
7817            return  ($self->{ct}); # ENTITY
7818            redo A;
7819          } elsif ($self->{nc} == -1) {
7820            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
7821            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7822            
7823        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7824          $self->{line_prev} = $self->{line};
7825          $self->{column_prev} = $self->{column};
7826          $self->{column}++;
7827          $self->{nc}
7828              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7829        } else {
7830          $self->{set_nc}->($self);
7831        }
7832      
7833            return  ($self->{ct}); # ENTITY
7834            redo A;
7835          } else {
7836            $self->{ct}->{notation} .= chr $self->{nc}; # ENTITY
7837            ## Stay in the state.
7838            
7839        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7840          $self->{line_prev} = $self->{line};
7841          $self->{column_prev} = $self->{column};
7842          $self->{column}++;
7843          $self->{nc}
7844              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7845        } else {
7846          $self->{set_nc}->($self);
7847        }
7848      
7849            redo A;
7850          }
7851        } elsif ($self->{state} == DOCTYPE_ENTITY_VALUE_DOUBLE_QUOTED_STATE) {
7852          if ($self->{nc} == 0x0022) { # "
7853            $self->{state} = AFTER_MD_DEF_STATE;
7854            
7855        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7856          $self->{line_prev} = $self->{line};
7857          $self->{column_prev} = $self->{column};
7858          $self->{column}++;
7859          $self->{nc}
7860              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7861        } else {
7862          $self->{set_nc}->($self);
7863        }
7864      
7865            redo A;
7866          } elsif ($self->{nc} == 0x0026) { # &
7867            $self->{prev_state} = $self->{state};
7868            $self->{state} = ENTITY_VALUE_ENTITY_STATE;
7869            $self->{entity_add} = 0x0022; # "
7870            
7871        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7872          $self->{line_prev} = $self->{line};
7873          $self->{column_prev} = $self->{column};
7874          $self->{column}++;
7875          $self->{nc}
7876              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7877        } else {
7878          $self->{set_nc}->($self);
7879        }
7880      
7881            redo A;
7882    ## TODO: %
7883          } elsif ($self->{nc} == -1) {
7884            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed entity value'); ## TODO: type
7885            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7886            ## Reconsume.
7887            return  ($self->{ct}); # ENTITY
7888            redo A;
7889          } else {
7890            $self->{ct}->{value} .= chr $self->{nc}; # ENTITY
7891            
7892        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7893          $self->{line_prev} = $self->{line};
7894          $self->{column_prev} = $self->{column};
7895          $self->{column}++;
7896          $self->{nc}
7897              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7898        } else {
7899          $self->{set_nc}->($self);
7900        }
7901      
7902            redo A;
7903          }
7904        } elsif ($self->{state} == DOCTYPE_ENTITY_VALUE_SINGLE_QUOTED_STATE) {
7905          if ($self->{nc} == 0x0027) { # '
7906            $self->{state} = AFTER_MD_DEF_STATE;
7907            
7908        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7909          $self->{line_prev} = $self->{line};
7910          $self->{column_prev} = $self->{column};
7911          $self->{column}++;
7912          $self->{nc}
7913              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7914        } else {
7915          $self->{set_nc}->($self);
7916        }
7917      
7918            redo A;
7919          } elsif ($self->{nc} == 0x0026) { # &
7920            $self->{prev_state} = $self->{state};
7921            $self->{state} = ENTITY_VALUE_ENTITY_STATE;
7922            $self->{entity_add} = 0x0027; # '
7923            
7924        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7925          $self->{line_prev} = $self->{line};
7926          $self->{column_prev} = $self->{column};
7927          $self->{column}++;
7928          $self->{nc}
7929              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7930        } else {
7931          $self->{set_nc}->($self);
7932        }
7933      
7934            redo A;
7935    ## TODO: %
7936          } elsif ($self->{nc} == -1) {
7937            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed entity value'); ## TODO: type
7938            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
7939            ## Reconsume.
7940            return  ($self->{ct}); # ENTITY
7941            redo A;
7942          } else {
7943            $self->{ct}->{value} .= chr $self->{nc}; # ENTITY
7944            
7945        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7946          $self->{line_prev} = $self->{line};
7947          $self->{column_prev} = $self->{column};
7948          $self->{column}++;
7949          $self->{nc}
7950              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7951        } else {
7952          $self->{set_nc}->($self);
7953        }
7954      
7955            redo A;
7956          }
7957        } elsif ($self->{state} == ENTITY_VALUE_ENTITY_STATE) {
7958          if ($is_space->{$self->{nc}} or
7959              {
7960                0x003C => 1, 0x0026 => 1, -1 => 1, # <, &
7961                $self->{entity_add} => 1,
7962              }->{$self->{nc}}) {
7963            $self->{parse_error}->(level => $self->{level}->{must}, type => 'bare ero',
7964                            line => $self->{line_prev},
7965                            column => $self->{column_prev}
7966                                + ($self->{nc} == -1 ? 1 : 0));
7967            ## Don't consume
7968            ## Return nothing.
7969            #
7970          } elsif ($self->{nc} == 0x0023) { # #
7971            $self->{ca} = $self->{ct};
7972            $self->{state} = ENTITY_HASH_STATE;
7973            $self->{kwd} = '#';
7974            
7975        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7976          $self->{line_prev} = $self->{line};
7977          $self->{column_prev} = $self->{column};
7978          $self->{column}++;
7979          $self->{nc}
7980              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
7981        } else {
7982          $self->{set_nc}->($self);
7983        }
7984      
7985            redo A;
7986          } else {
7987            #
7988          }
7989    
7990          $self->{ct}->{value} .= '&';
7991          $self->{state} = $self->{prev_state};
7992          ## Reconsume.
7993          redo A;
7994        } elsif ($self->{state} == AFTER_ELEMENT_NAME_STATE) {
7995          if ($is_space->{$self->{nc}}) {
7996            $self->{state} = BEFORE_ELEMENT_CONTENT_STATE;
7997            
7998        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
7999          $self->{line_prev} = $self->{line};
8000          $self->{column_prev} = $self->{column};
8001          $self->{column}++;
8002          $self->{nc}
8003              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8004        } else {
8005          $self->{set_nc}->($self);
8006        }
8007      
8008            redo A;
8009          } elsif ($self->{nc} == 0x0028) { # (
8010            $self->{state} = AFTER_CM_GROUP_OPEN_STATE;
8011            $self->{ct}->{content} = ['('];
8012            $self->{group_depth} = 1;
8013            
8014        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8015          $self->{line_prev} = $self->{line};
8016          $self->{column_prev} = $self->{column};
8017          $self->{column}++;
8018          $self->{nc}
8019              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8020        } else {
8021          $self->{set_nc}->($self);
8022        }
8023      
8024            redo A;
8025          } elsif ($self->{nc} == 0x003E) { # >
8026            $self->{parse_error}->(level => $self->{level}->{must}, type => 'no md def'); ## TODO: type
8027            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8028            
8029        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8030          $self->{line_prev} = $self->{line};
8031          $self->{column_prev} = $self->{column};
8032          $self->{column}++;
8033          $self->{nc}
8034              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8035        } else {
8036          $self->{set_nc}->($self);
8037        }
8038      
8039            return  ($self->{ct}); # ELEMENT
8040            redo A;
8041          } elsif ($self->{nc} == -1) {
8042            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
8043            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8044            
8045        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8046          $self->{line_prev} = $self->{line};
8047          $self->{column_prev} = $self->{column};
8048          $self->{column}++;
8049          $self->{nc}
8050              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8051        } else {
8052          $self->{set_nc}->($self);
8053        }
8054      
8055            return  ($self->{ct}); # ELEMENT
8056            redo A;
8057          } else {
8058            $self->{ct}->{content} = [chr $self->{nc}];
8059            $self->{state} = CONTENT_KEYWORD_STATE;
8060            
8061        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8062          $self->{line_prev} = $self->{line};
8063          $self->{column_prev} = $self->{column};
8064          $self->{column}++;
8065          $self->{nc}
8066              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8067        } else {
8068          $self->{set_nc}->($self);
8069        }
8070      
8071            redo A;
8072          }
8073        } elsif ($self->{state} == CONTENT_KEYWORD_STATE) {
8074          if ($is_space->{$self->{nc}}) {
8075            $self->{state} = AFTER_MD_DEF_STATE;
8076            
8077        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8078          $self->{line_prev} = $self->{line};
8079          $self->{column_prev} = $self->{column};
8080          $self->{column}++;
8081          $self->{nc}
8082              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8083        } else {
8084          $self->{set_nc}->($self);
8085        }
8086      
8087            redo A;
8088          } elsif ($self->{nc} == 0x003E) { # >
8089            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8090            
8091        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8092          $self->{line_prev} = $self->{line};
8093          $self->{column_prev} = $self->{column};
8094          $self->{column}++;
8095          $self->{nc}
8096              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8097        } else {
8098          $self->{set_nc}->($self);
8099        }
8100      
8101            return  ($self->{ct}); # ELEMENT
8102            redo A;
8103          } elsif ($self->{nc} == -1) {
8104            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
8105            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8106            
8107        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8108          $self->{line_prev} = $self->{line};
8109          $self->{column_prev} = $self->{column};
8110          $self->{column}++;
8111          $self->{nc}
8112              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8113        } else {
8114          $self->{set_nc}->($self);
8115        }
8116      
8117            return  ($self->{ct}); # ELEMENT
8118            redo A;
8119          } else {
8120            $self->{ct}->{content}->[-1] .= chr $self->{nc}; # ELEMENT
8121            ## Stay in the state.
8122            
8123        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8124          $self->{line_prev} = $self->{line};
8125          $self->{column_prev} = $self->{column};
8126          $self->{column}++;
8127          $self->{nc}
8128              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8129        } else {
8130          $self->{set_nc}->($self);
8131        }
8132      
8133            redo A;
8134          }
8135        } elsif ($self->{state} == AFTER_CM_GROUP_OPEN_STATE) {
8136          if ($is_space->{$self->{nc}}) {
8137            ## Stay in the state.
8138            
8139        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8140          $self->{line_prev} = $self->{line};
8141          $self->{column_prev} = $self->{column};
8142          $self->{column}++;
8143          $self->{nc}
8144              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8145        } else {
8146          $self->{set_nc}->($self);
8147        }
8148      
8149            redo A;
8150          } elsif ($self->{nc} == 0x0028) { # (
8151            $self->{group_depth}++;
8152            push @{$self->{ct}->{content}}, chr $self->{nc};
8153            ## Stay in the state.
8154            
8155        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8156          $self->{line_prev} = $self->{line};
8157          $self->{column_prev} = $self->{column};
8158          $self->{column}++;
8159          $self->{nc}
8160              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8161        } else {
8162          $self->{set_nc}->($self);
8163        }
8164      
8165            redo A;
8166          } elsif ($self->{nc} == 0x007C or # |
8167                   $self->{nc} == 0x002C) { # ,
8168            $self->{parse_error}->(level => $self->{level}->{must}, type => 'empty element name'); ## TODO: type
8169            ## Stay in the state.
8170            
8171        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8172          $self->{line_prev} = $self->{line};
8173          $self->{column_prev} = $self->{column};
8174          $self->{column}++;
8175          $self->{nc}
8176              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8177        } else {
8178          $self->{set_nc}->($self);
8179        }
8180      
8181            redo A;
8182          } elsif ($self->{nc} == 0x0029) { # )
8183            $self->{parse_error}->(level => $self->{level}->{must}, type => 'empty element name'); ## TODO: type
8184            push @{$self->{ct}->{content}}, chr $self->{nc};
8185            $self->{group_depth}--;
8186            $self->{state} = AFTER_CM_GROUP_CLOSE_STATE;
8187            
8188        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8189          $self->{line_prev} = $self->{line};
8190          $self->{column_prev} = $self->{column};
8191          $self->{column}++;
8192          $self->{nc}
8193              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8194        } else {
8195          $self->{set_nc}->($self);
8196        }
8197      
8198            redo A;
8199          } elsif ($self->{nc} == 0x003E) { # >
8200            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed cm group'); ## TODO: type
8201            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8202            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8203            
8204        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8205          $self->{line_prev} = $self->{line};
8206          $self->{column_prev} = $self->{column};
8207          $self->{column}++;
8208          $self->{nc}
8209              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8210        } else {
8211          $self->{set_nc}->($self);
8212        }
8213      
8214            return  ($self->{ct}); # ELEMENT
8215            redo A;
8216          } elsif ($self->{nc} == -1) {
8217            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
8218            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8219            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8220            
8221        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8222          $self->{line_prev} = $self->{line};
8223          $self->{column_prev} = $self->{column};
8224          $self->{column}++;
8225          $self->{nc}
8226              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8227        } else {
8228          $self->{set_nc}->($self);
8229        }
8230      
8231            return  ($self->{ct}); # ELEMENT
8232            redo A;
8233          } else {
8234            push @{$self->{ct}->{content}}, chr $self->{nc};
8235            $self->{state} = CM_ELEMENT_NAME_STATE;
8236            
8237        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8238          $self->{line_prev} = $self->{line};
8239          $self->{column_prev} = $self->{column};
8240          $self->{column}++;
8241          $self->{nc}
8242              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8243        } else {
8244          $self->{set_nc}->($self);
8245        }
8246      
8247            redo A;
8248          }
8249        } elsif ($self->{state} == CM_ELEMENT_NAME_STATE) {
8250          if ($is_space->{$self->{nc}}) {
8251            $self->{state} = AFTER_CM_ELEMENT_NAME_STATE;
8252            
8253        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8254          $self->{line_prev} = $self->{line};
8255          $self->{column_prev} = $self->{column};
8256          $self->{column}++;
8257          $self->{nc}
8258              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8259        } else {
8260          $self->{set_nc}->($self);
8261        }
8262      
8263            redo A;
8264          } elsif ($self->{nc} == 0x002A or # *
8265                   $self->{nc} == 0x002B or # +
8266                   $self->{nc} == 0x003F) { # ?
8267            push @{$self->{ct}->{content}}, chr $self->{nc};
8268            $self->{state} = AFTER_CM_ELEMENT_NAME_STATE;
8269            
8270        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8271          $self->{line_prev} = $self->{line};
8272          $self->{column_prev} = $self->{column};
8273          $self->{column}++;
8274          $self->{nc}
8275              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8276        } else {
8277          $self->{set_nc}->($self);
8278        }
8279      
8280            redo A;
8281          } elsif ($self->{nc} == 0x007C or # |
8282                   $self->{nc} == 0x002C) { # ,
8283            push @{$self->{ct}->{content}}, $self->{nc} == 0x007C ? ' | ' : ', ';
8284            $self->{state} = AFTER_CM_GROUP_OPEN_STATE;
8285            
8286        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8287          $self->{line_prev} = $self->{line};
8288          $self->{column_prev} = $self->{column};
8289          $self->{column}++;
8290          $self->{nc}
8291              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8292        } else {
8293          $self->{set_nc}->($self);
8294        }
8295      
8296            redo A;
8297          } elsif ($self->{nc} == 0x0029) { # )
8298            $self->{group_depth}--;
8299            push @{$self->{ct}->{content}}, chr $self->{nc};
8300            $self->{state} = AFTER_CM_GROUP_CLOSE_STATE;
8301            
8302        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8303          $self->{line_prev} = $self->{line};
8304          $self->{column_prev} = $self->{column};
8305          $self->{column}++;
8306          $self->{nc}
8307              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8308        } else {
8309          $self->{set_nc}->($self);
8310        }
8311      
8312            redo A;
8313          } elsif ($self->{nc} == 0x003E) { # >
8314            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed cm group'); ## TODO: type
8315            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8316            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8317            
8318        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8319          $self->{line_prev} = $self->{line};
8320          $self->{column_prev} = $self->{column};
8321          $self->{column}++;
8322          $self->{nc}
8323              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8324        } else {
8325          $self->{set_nc}->($self);
8326        }
8327      
8328            return  ($self->{ct}); # ELEMENT
8329            redo A;
8330          } elsif ($self->{nc} == -1) {
8331            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
8332            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8333            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8334            
8335        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8336          $self->{line_prev} = $self->{line};
8337          $self->{column_prev} = $self->{column};
8338          $self->{column}++;
8339          $self->{nc}
8340              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8341        } else {
8342          $self->{set_nc}->($self);
8343        }
8344      
8345            return  ($self->{ct}); # ELEMENT
8346            redo A;
8347          } else {
8348            $self->{ct}->{content}->[-1] .= chr $self->{nc};
8349            ## Stay in the state.
8350            
8351        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8352          $self->{line_prev} = $self->{line};
8353          $self->{column_prev} = $self->{column};
8354          $self->{column}++;
8355          $self->{nc}
8356              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8357        } else {
8358          $self->{set_nc}->($self);
8359        }
8360      
8361            redo A;
8362          }
8363        } elsif ($self->{state} == AFTER_CM_ELEMENT_NAME_STATE) {
8364          if ($is_space->{$self->{nc}}) {
8365            ## Stay in the state.
8366            
8367        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8368          $self->{line_prev} = $self->{line};
8369          $self->{column_prev} = $self->{column};
8370          $self->{column}++;
8371          $self->{nc}
8372              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8373        } else {
8374          $self->{set_nc}->($self);
8375        }
8376      
8377            redo A;
8378          } elsif ($self->{nc} == 0x007C or # |
8379                   $self->{nc} == 0x002C) { # ,
8380            push @{$self->{ct}->{content}}, $self->{nc} == 0x007C ? ' | ' : ', ';
8381            $self->{state} = AFTER_CM_GROUP_OPEN_STATE;
8382            
8383        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8384          $self->{line_prev} = $self->{line};
8385          $self->{column_prev} = $self->{column};
8386          $self->{column}++;
8387          $self->{nc}
8388              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8389        } else {
8390          $self->{set_nc}->($self);
8391        }
8392      
8393            redo A;
8394          } elsif ($self->{nc} == 0x0029) { # )
8395            $self->{group_depth}--;
8396            push @{$self->{ct}->{content}}, chr $self->{nc};
8397            $self->{state} = AFTER_CM_GROUP_CLOSE_STATE;
8398            
8399        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8400          $self->{line_prev} = $self->{line};
8401          $self->{column_prev} = $self->{column};
8402          $self->{column}++;
8403          $self->{nc}
8404              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8405        } else {
8406          $self->{set_nc}->($self);
8407        }
8408      
8409            redo A;
8410          } elsif ($self->{nc} == 0x003E) { # >
8411            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed cm group'); ## TODO: type
8412            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8413            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8414            
8415        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8416          $self->{line_prev} = $self->{line};
8417          $self->{column_prev} = $self->{column};
8418          $self->{column}++;
8419          $self->{nc}
8420              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8421        } else {
8422          $self->{set_nc}->($self);
8423        }
8424      
8425            return  ($self->{ct}); # ELEMENT
8426            redo A;
8427          } elsif ($self->{nc} == -1) {
8428            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
8429            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8430            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8431            
8432        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8433          $self->{line_prev} = $self->{line};
8434          $self->{column_prev} = $self->{column};
8435          $self->{column}++;
8436          $self->{nc}
8437              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8438        } else {
8439          $self->{set_nc}->($self);
8440        }
8441      
8442            return  ($self->{ct}); # ELEMENT
8443            redo A;
8444          } else {
8445            $self->{parse_error}->(level => $self->{level}->{must}, type => 'after element name'); ## TODO: type
8446            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8447            $self->{state} = BOGUS_MD_STATE;
8448            
8449        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8450          $self->{line_prev} = $self->{line};
8451          $self->{column_prev} = $self->{column};
8452          $self->{column}++;
8453          $self->{nc}
8454              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8455        } else {
8456          $self->{set_nc}->($self);
8457        }
8458      
8459            redo A;
8460          }
8461        } elsif ($self->{state} == AFTER_CM_GROUP_CLOSE_STATE) {
8462          if ($is_space->{$self->{nc}}) {
8463            if ($self->{group_depth}) {
8464              $self->{state} = AFTER_CM_ELEMENT_NAME_STATE;
8465            } else {
8466              $self->{state} = AFTER_MD_DEF_STATE;
8467            }
8468            
8469        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8470          $self->{line_prev} = $self->{line};
8471          $self->{column_prev} = $self->{column};
8472          $self->{column}++;
8473          $self->{nc}
8474              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8475        } else {
8476          $self->{set_nc}->($self);
8477        }
8478      
8479            redo A;
8480          } elsif ($self->{nc} == 0x002A or # *
8481                   $self->{nc} == 0x002B or # +
8482                   $self->{nc} == 0x003F) { # ?
8483            push @{$self->{ct}->{content}}, chr $self->{nc};
8484            if ($self->{group_depth}) {
8485              $self->{state} = AFTER_CM_ELEMENT_NAME_STATE;
8486            } else {
8487              $self->{state} = AFTER_MD_DEF_STATE;
8488            }
8489            
8490        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8491          $self->{line_prev} = $self->{line};
8492          $self->{column_prev} = $self->{column};
8493          $self->{column}++;
8494          $self->{nc}
8495              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8496        } else {
8497          $self->{set_nc}->($self);
8498        }
8499      
8500            redo A;
8501          } elsif ($self->{nc} == 0x0029) { # )
8502            if ($self->{group_depth}) {
8503              $self->{group_depth}--;
8504              push @{$self->{ct}->{content}}, chr $self->{nc};
8505              ## Stay in the state.
8506              
8507        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8508          $self->{line_prev} = $self->{line};
8509          $self->{column_prev} = $self->{column};
8510          $self->{column}++;
8511          $self->{nc}
8512              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8513        } else {
8514          $self->{set_nc}->($self);
8515        }
8516      
8517              redo A;
8518            } else {
8519              $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after md def'); ## TODO: type
8520              $self->{state} = BOGUS_MD_STATE;
8521              ## Reconsume.
8522              redo A;
8523            }
8524          } elsif ($self->{nc} == 0x003E) { # >
8525            if ($self->{group_depth}) {
8526              $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed cm group'); ## TODO: type
8527              push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8528            }
8529            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8530            
8531        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8532          $self->{line_prev} = $self->{line};
8533          $self->{column_prev} = $self->{column};
8534          $self->{column}++;
8535          $self->{nc}
8536              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8537        } else {
8538          $self->{set_nc}->($self);
8539        }
8540      
8541            return  ($self->{ct}); # ELEMENT
8542            redo A;
8543          } elsif ($self->{nc} == -1) {
8544            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
8545            push @{$self->{ct}->{content}}, (')') x $self->{group_depth};
8546            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8547            
8548        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8549          $self->{line_prev} = $self->{line};
8550          $self->{column_prev} = $self->{column};
8551          $self->{column}++;
8552          $self->{nc}
8553              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8554        } else {
8555          $self->{set_nc}->($self);
8556        }
8557      
8558            return  ($self->{ct}); # ELEMENT
8559            redo A;
8560          } else {
8561            if ($self->{group_depth}) {
8562              $self->{state} = AFTER_CM_ELEMENT_NAME_STATE;
8563            } else {
8564              $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after md def'); ## TODO: type
8565              $self->{state} = BOGUS_MD_STATE;
8566            }
8567            ## Reconsume.
8568            redo A;
8569          }
8570        } elsif ($self->{state} == AFTER_MD_DEF_STATE) {
8571          if ($is_space->{$self->{nc}}) {
8572            ## Stay in the state.
8573            
8574        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8575          $self->{line_prev} = $self->{line};
8576          $self->{column_prev} = $self->{column};
8577          $self->{column}++;
8578          $self->{nc}
8579              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8580        } else {
8581          $self->{set_nc}->($self);
8582        }
8583      
8584            redo A;
8585          } elsif ($self->{nc} == 0x003E) { # >
8586            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8587            
8588        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8589          $self->{line_prev} = $self->{line};
8590          $self->{column_prev} = $self->{column};
8591          $self->{column}++;
8592          $self->{nc}
8593              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8594        } else {
8595          $self->{set_nc}->($self);
8596        }
8597      
8598            return  ($self->{ct}); # ENTITY/ELEMENT
8599            redo A;
8600          } elsif ($self->{nc} == -1) {
8601            $self->{parse_error}->(level => $self->{level}->{must}, type => 'unclosed md'); ## TODO: type
8602            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8603            
8604        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8605          $self->{line_prev} = $self->{line};
8606          $self->{column_prev} = $self->{column};
8607          $self->{column}++;
8608          $self->{nc}
8609              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8610        } else {
8611          $self->{set_nc}->($self);
8612        }
8613      
8614            return  ($self->{ct}); # ENTITY/ELEMENT
8615            redo A;
8616          } else {
8617            $self->{parse_error}->(level => $self->{level}->{must}, type => 'string after md def'); ## TODO: type
8618            $self->{state} = BOGUS_MD_STATE;
8619            ## Reconsume.
8620            redo A;
8621          }
8622        } elsif ($self->{state} == BOGUS_MD_STATE) {
8623          if ($self->{nc} == 0x003E) { # >
8624            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8625            
8626        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8627          $self->{line_prev} = $self->{line};
8628          $self->{column_prev} = $self->{column};
8629          $self->{column}++;
8630          $self->{nc}
8631              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8632        } else {
8633          $self->{set_nc}->($self);
8634        }
8635      
8636            return  ($self->{ct}); # ATTLIST/ENTITY/NOTATION
8637            redo A;
8638          } elsif ($self->{nc} == -1) {
8639            $self->{state} = DOCTYPE_INTERNAL_SUBSET_STATE;
8640            ## Reconsume.
8641            return  ($self->{ct}); # ATTLIST/ENTITY/NOTATION
8642            redo A;
8643          } else {
8644            ## Stay in the state.
8645            
8646        if ($self->{char_buffer_pos} < length $self->{char_buffer}) {
8647          $self->{line_prev} = $self->{line};
8648          $self->{column_prev} = $self->{column};
8649          $self->{column}++;
8650          $self->{nc}
8651              = ord substr ($self->{char_buffer}, $self->{char_buffer_pos}++, 1);
8652        } else {
8653          $self->{set_nc}->($self);
8654        }
8655      
8656            redo A;
8657          }
8658      } else {      } else {
8659        die "$0: $self->{state}: Unknown state";        die "$0: $self->{state}: Unknown state";
8660      }      }

Legend:
Removed from v.1.15  
changed lines
  Added in v.1.28

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24