| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # $Id: SAX.pm,v 1.5 2003/01/04 00:27:25 matt Exp $ | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | package Text::WikiFormat::SAX; | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | $VERSION = '0.03'; | 
| 6 | 4 |  |  | 4 |  | 32876 | use XML::SAX::Base; | 
|  | 4 |  |  |  |  | 99646 |  | 
|  | 4 |  |  |  |  | 168 |  | 
| 7 |  |  |  |  |  |  | @ISA = qw(XML::SAX::Base); | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 4 |  |  | 4 |  | 50 | use strict; | 
|  | 4 |  |  |  |  | 9 |  | 
|  | 4 |  |  |  |  | 153 |  | 
| 10 | 4 |  |  | 4 |  | 3625 | use XML::SAX::DocumentLocator; | 
|  | 4 |  |  |  |  | 2136 |  | 
|  | 4 |  |  |  |  | 1466 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | sub _parse_bytestream { | 
| 13 | 1 |  |  | 1 |  | 903 | my ($self, $fh) = @_; | 
| 14 | 1 |  |  |  |  | 10 | my $parser = Wiki::SAX::Parser->new(); | 
| 15 | 1 |  |  |  |  | 4 | $parser->set_parent($self); | 
| 16 | 1 |  |  |  |  | 4 | local $/; | 
| 17 | 1 |  |  |  |  | 23 | my $text = <$fh>; | 
| 18 | 1 |  |  |  |  | 5 | $parser->parse($text); | 
| 19 |  |  |  |  |  |  | } | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | sub _parse_characterstream { | 
| 22 | 0 |  |  | 0 |  | 0 | my ($self, $fh) = @_; | 
| 23 | 0 |  |  |  |  | 0 | die "parse_characterstream not supported"; | 
| 24 |  |  |  |  |  |  | } | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | sub _parse_string { | 
| 27 | 1 |  |  | 1 |  | 388 | my ($self, $str) = @_; | 
| 28 | 1 |  |  |  |  | 7 | my $parser = Wiki::SAX::Parser->new(); | 
| 29 | 1 |  |  |  |  | 3 | $parser->set_parent($self); | 
| 30 | 1 |  |  |  |  | 4 | $parser->parse($str); | 
| 31 |  |  |  |  |  |  | } | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | sub _parse_systemid { | 
| 34 | 1 |  |  | 1 |  | 680 | my ($self, $sysid) = @_; | 
| 35 | 1 |  |  |  |  | 8 | my $parser = Wiki::SAX::Parser->new(); | 
| 36 | 1 |  |  |  |  | 4 | $parser->set_parent($self); | 
| 37 | 1 | 50 |  |  |  | 40 | open(FILE, $sysid) || die "Can't open $sysid: $!"; | 
| 38 | 1 |  |  |  |  | 3 | local $/; | 
| 39 | 1 |  |  |  |  | 28 | my $text = ; | 
| 40 | 1 |  |  |  |  | 5 | $parser->parse($text); | 
| 41 |  |  |  |  |  |  | } | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | package Wiki::SAX::Parser; | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 4 |  |  | 4 |  | 23 | use strict; | 
|  | 4 |  |  |  |  | 8 |  | 
|  | 4 |  |  |  |  | 1974 |  | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | sub new { | 
| 48 | 3 |  |  | 3 |  | 6 | my $class = shift; | 
| 49 | 3 |  |  |  |  | 8 | my $self = bless {}, $class; | 
| 50 | 3 |  |  |  |  | 10 | return $self; | 
| 51 |  |  |  |  |  |  | } | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | sub set_parent { | 
| 54 | 3 |  |  | 3 |  | 5 | my $self = shift; | 
| 55 | 3 |  |  |  |  | 19 | $self->{parent} = shift; | 
| 56 |  |  |  |  |  |  | } | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | sub parent { | 
| 59 | 78 |  |  | 78 |  | 101 | my $self = shift; | 
| 60 | 78 |  |  |  |  | 455 | return $self->{parent}; | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | sub parse { | 
| 64 | 3 |  |  | 3 |  | 5 | my $self = shift; | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 3 |  |  |  |  | 10 | my $sysid = $self->parent->{ParserOptions}->{Source}{SystemId}; | 
| 67 |  |  |  |  |  |  | $self->parent->set_document_locator( | 
| 68 |  |  |  |  |  |  | XML::SAX::DocumentLocator->new( | 
| 69 | 0 |  |  | 0 |  | 0 | sub { "" }, | 
| 70 | 0 |  |  | 0 |  | 0 | sub { $sysid }, | 
| 71 | 0 |  |  | 0 |  | 0 | sub { $self->{line_number} }, | 
| 72 | 0 |  |  | 0 |  | 0 | sub { 0 }, | 
| 73 | 3 |  |  |  |  | 10 | ), | 
| 74 |  |  |  |  |  |  | ); | 
| 75 | 3 |  |  |  |  | 342 | $self->parent->start_document({}); | 
| 76 | 3 |  |  |  |  | 1276 | $self->parent->start_element(_element('wiki')); | 
| 77 | 3 |  |  |  |  | 327 | $self->parent->characters({Data => "\n"}); | 
| 78 | 3 |  |  |  |  | 95 | $self->parent->comment({Data => " Text::WikiFormat::SAX v$Text::WikiFormat::SAX::VERSION "}); | 
| 79 | 3 |  |  |  |  | 704 | $self->parent->characters({Data => "\n"}); | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 3 |  |  |  |  | 42 | $self->parse_wiki(shift); | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 3 |  |  |  |  | 57 | $self->parent->end_element(_element('wiki', 1)); | 
| 84 | 3 |  |  |  |  | 254 | $self->parent->end_document({}); | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub start_list { | 
| 88 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 89 | 0 |  |  |  |  | 0 | my $type = shift; | 
| 90 | 0 |  |  |  |  | 0 | $self->parent->start_element(_element("${type}list")); | 
| 91 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => "\n"}); | 
| 92 | 0 |  |  |  |  | 0 | $self->{in_list} = $type; | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | sub end_list { | 
| 96 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 97 | 0 |  |  |  |  | 0 | $self->parent->end_element(_element("$self->{in_list}list")); | 
| 98 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => "\n"}); | 
| 99 | 0 |  |  |  |  | 0 | $self->{in_list} = ''; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 4 |  |  | 4 |  | 22 | use vars qw($indent); | 
|  | 4 |  |  |  |  | 6 |  | 
|  | 4 |  |  |  |  | 6394 |  | 
| 103 |  |  |  |  |  |  | $indent = qr/^(?:\t+|\s{4,})/; | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | sub parse_wiki { | 
| 106 | 3 |  |  | 3 |  | 8 | my $self = shift; | 
| 107 | 3 |  |  |  |  | 6 | my ($text) = @_; | 
| 108 | 3 |  |  |  |  | 14 | foreach my $line (split(/\n/, $text)) { | 
| 109 | 10 | 50 |  |  |  | 267 | if ($line =~ /$indent(.*)$/) { | 
| 110 | 0 |  |  |  |  | 0 | my $match = $1; | 
| 111 | 0 | 0 |  |  |  | 0 | if ($match =~ /([\dA-Za-z]+)\.\s*(.*)$/) { | 
|  |  | 0 |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | # ordered list | 
| 113 | 0 |  |  |  |  | 0 | my $value = $1; | 
| 114 | 0 |  |  |  |  | 0 | my $data = $2; | 
| 115 | 0 | 0 |  |  |  | 0 | if ($self->{in_list} ne 'ordered') { | 
| 116 | 0 | 0 |  |  |  | 0 | if ($self->{in_list}) { | 
| 117 | 0 |  |  |  |  | 0 | $self->end_list(); | 
| 118 |  |  |  |  |  |  | } | 
| 119 | 0 |  |  |  |  | 0 | $self->start_list('ordered'); | 
| 120 |  |  |  |  |  |  | } | 
| 121 | 0 |  |  |  |  | 0 | my $el = _element('listitem'); | 
| 122 | 0 |  |  |  |  | 0 | _add_attrib($el, value => $value); | 
| 123 | 0 |  |  |  |  | 0 | $self->parent->start_element($el); | 
| 124 | 0 |  |  |  |  | 0 | $self->format_line($data); | 
| 125 | 0 |  |  |  |  | 0 | $self->parent->end_element(_element('listitem', 1)); | 
| 126 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => "\n"}); | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  | elsif ($match =~ /\*\s*(.*)$/) { | 
| 129 |  |  |  |  |  |  | # bulleted list | 
| 130 | 0 |  |  |  |  | 0 | my $data = $1; | 
| 131 | 0 | 0 |  |  |  | 0 | if ($self->{in_list} ne 'itemized') { | 
| 132 | 0 | 0 |  |  |  | 0 | if ($self->{in_list}) { | 
| 133 | 0 |  |  |  |  | 0 | $self->end_list(); | 
| 134 |  |  |  |  |  |  | } | 
| 135 | 0 |  |  |  |  | 0 | $self->start_list('itemized'); | 
| 136 |  |  |  |  |  |  | } | 
| 137 | 0 |  |  |  |  | 0 | $self->parent->start_element(_element('listitem')); | 
| 138 | 0 |  |  |  |  | 0 | $self->format_line($data); | 
| 139 | 0 |  |  |  |  | 0 | $self->parent->end_element(_element('listitem', 1)); | 
| 140 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => "\n"}); | 
| 141 |  |  |  |  |  |  | } | 
| 142 |  |  |  |  |  |  | else { | 
| 143 |  |  |  |  |  |  | # code | 
| 144 | 0 | 0 |  |  |  | 0 | if ($self->{in_list}) { | 
| 145 | 0 |  |  |  |  | 0 | $self->end_list(); | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 0 |  |  |  |  | 0 | $self->parent->start_element(_element('code')); | 
| 149 | 0 |  |  |  |  | 0 | $self->format_line($match); | 
| 150 | 0 |  |  |  |  | 0 | $self->parent->end_element(_element('code', 1)); | 
| 151 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => "\n"}); | 
| 152 |  |  |  |  |  |  | } | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  | else { | 
| 155 | 10 | 50 |  |  |  | 37 | if ($self->{in_list}) { | 
| 156 | 0 |  |  |  |  | 0 | $self->end_list(); | 
| 157 |  |  |  |  |  |  | } | 
| 158 | 10 |  |  |  |  | 24 | $self->format_line($line); | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | sub format_line { | 
| 164 | 10 |  |  | 10 |  | 16 | my $self = shift; | 
| 165 | 10 |  |  |  |  | 14 | my ($text) = @_; | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | my $strong = sub { | 
| 168 | 0 |  |  | 0 |  | 0 | $self->parent->start_element(_element('strong')); | 
| 169 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => $_[0]}); | 
| 170 | 0 |  |  |  |  | 0 | $self->parent->end_element(_element('strong',1)); | 
| 171 | 0 |  |  |  |  | 0 | return ''; | 
| 172 | 10 |  |  |  |  | 53 | }; | 
| 173 |  |  |  |  |  |  | my $emphasized = sub { | 
| 174 | 0 |  |  | 0 |  | 0 | $self->parent->start_element(_element('em')); | 
| 175 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => $_[0]}); | 
| 176 | 0 |  |  |  |  | 0 | $self->parent->end_element(_element('em',1)); | 
| 177 | 0 |  |  |  |  | 0 | return ''; | 
| 178 | 10 |  |  |  |  | 57 | }; | 
| 179 |  |  |  |  |  |  | my $line = sub { | 
| 180 | 0 |  |  | 0 |  | 0 | $self->parent->start_element(_element('hr')); | 
| 181 | 0 |  |  |  |  | 0 | $self->parent->end_element(_element('hr',1)); | 
| 182 | 0 |  |  |  |  | 0 | $self->parent->characters({Data => "\n"}); | 
| 183 | 0 |  |  |  |  | 0 | return ''; | 
| 184 | 10 |  |  |  |  | 32 | }; | 
| 185 |  |  |  |  |  |  | my $link = sub { | 
| 186 | 3 |  |  | 3 |  | 9 | $self->make_link($_[0]); | 
| 187 | 3 |  |  |  |  | 299 | return ''; | 
| 188 | 10 |  |  |  |  | 31 | }; | 
| 189 |  |  |  |  |  |  | my $data = sub { | 
| 190 | 12 |  |  | 12 |  | 27 | $self->parent->characters({Data => $_[0]}); | 
| 191 | 12 |  |  |  |  | 131 | return ''; | 
| 192 | 10 |  |  |  |  | 27 | }; | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 10 |  |  |  |  | 29 | $self->_format_line($text, $strong, $emphasized, $line, $link, $data); | 
| 195 | 10 |  |  |  |  | 21 | $self->parent->start_element(_element('br')); | 
| 196 | 10 |  |  |  |  | 881 | $self->parent->end_element(_element('br',1)); | 
| 197 | 10 |  |  |  |  | 653 | $self->parent->characters({Data => "\n"}); | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | sub _format_line { | 
| 201 | 13 |  |  | 13 |  | 42 | my ($self, $text, $strong, $emphasized, $line, $link, $data) = @_; | 
| 202 |  |  |  |  |  |  |  | 
| 203 | 13 | 50 |  |  |  | 58 | if ($text =~ s/^-{4,}//) { | 
| 204 | 0 |  |  |  |  | 0 | $line->(); | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 13 | 100 |  |  |  | 109 | if ($text =~ s/^(.*?)('')/$2/) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 208 | 1 |  |  |  |  | 7 | $self->_format_line($1, $strong, $emphasized, $line, $link, $data); | 
| 209 | 1 | 50 |  |  |  | 19 | if ($text =~ s/^'''(.*?)'''//) { | 
|  |  | 50 |  |  |  |  |  | 
| 210 | 0 |  |  |  |  | 0 | $strong->($1); | 
| 211 |  |  |  |  |  |  | } | 
| 212 |  |  |  |  |  |  | elsif ($text =~ s/^''(.*?)''//) { | 
| 213 | 0 |  |  |  |  | 0 | $emphasized->($1); | 
| 214 |  |  |  |  |  |  | } | 
| 215 |  |  |  |  |  |  | else { | 
| 216 | 1 |  |  |  |  | 4 | $text =~ s/^(.*)$//; | 
| 217 | 1 |  |  |  |  | 2 | $data->($1); | 
| 218 |  |  |  |  |  |  | } | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | elsif ($text =~ s/^(.*?)\[([^\]]+)\]//) { | 
| 221 | 1 |  |  |  |  | 5 | $self->_format_line($1, $strong, $emphasized, $line, $link, $data); | 
| 222 | 1 |  |  |  |  | 10 | $link->($2); | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  | elsif ($text =~ s|^(.*?)(?=])\b([A-Za-z]+(?:[A-Z]\w+)+)||) { | 
| 225 | 2 |  |  |  |  | 6 | $data->($1); | 
| 226 | 2 |  |  |  |  | 10 | $link->($2); | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  | else { | 
| 229 | 9 |  |  |  |  | 208 | $text =~ s/^(.*)$//; | 
| 230 | 9 |  |  |  |  | 21 | $data->($1); | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  |  | 
| 233 | 13 | 100 |  |  |  | 61 | if (length($text)) { | 
| 234 |  |  |  |  |  |  | # warn("re-parsing $text\n"); | 
| 235 | 1 |  |  |  |  | 4 | return $self->_format_line($text, $strong, $emphasized, $line, $link, $data); | 
| 236 |  |  |  |  |  |  | } | 
| 237 |  |  |  |  |  |  |  | 
| 238 | 12 |  |  |  |  | 22 | return undef; | 
| 239 |  |  |  |  |  |  | } | 
| 240 |  |  |  |  |  |  |  | 
| 241 |  |  |  |  |  |  | sub make_link { | 
| 242 | 3 |  |  | 3 |  | 8 | my ($self, $link) = @_; | 
| 243 |  |  |  |  |  |  |  | 
| 244 | 3 |  |  |  |  | 4 | my $title; | 
| 245 | 3 |  |  |  |  | 8 | ($link, $title) = split(/\|/, $link, 2); | 
| 246 | 3 |  | 33 |  |  | 18 | $title ||= $link; | 
| 247 |  |  |  |  |  |  |  | 
| 248 | 3 |  |  |  |  | 15 | my $el = _element('link'); | 
| 249 | 3 |  |  |  |  | 9 | _add_attrib($el, href => $link); | 
| 250 | 3 |  |  |  |  | 8 | $self->parent->start_element($el); | 
| 251 | 3 |  |  |  |  | 296 | $self->parent->characters({Data => $title}); | 
| 252 | 3 |  |  |  |  | 28 | $self->parent->end_element(_element('link')); | 
| 253 |  |  |  |  |  |  | } | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | sub _element { | 
| 256 | 32 |  |  | 32 |  | 51 | my ($name, $end) = @_; | 
| 257 |  |  |  |  |  |  | return { | 
| 258 | 32 | 100 |  |  |  | 274 | Name => $name, | 
| 259 |  |  |  |  |  |  | LocalName => $name, | 
| 260 |  |  |  |  |  |  | $end ? () : (Attributes => {}), | 
| 261 |  |  |  |  |  |  | NamespaceURI => '', | 
| 262 |  |  |  |  |  |  | Prefix => '', | 
| 263 |  |  |  |  |  |  | }; | 
| 264 |  |  |  |  |  |  | } | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | sub _add_attrib { | 
| 267 | 3 |  |  | 3 |  | 6 | my ($el, $name, $value) = @_; | 
| 268 |  |  |  |  |  |  |  | 
| 269 | 3 |  |  |  |  | 17 | $el->{Attributes}{"{}$name"} = | 
| 270 |  |  |  |  |  |  | { | 
| 271 |  |  |  |  |  |  | Name => $name, | 
| 272 |  |  |  |  |  |  | LocalName => $name, | 
| 273 |  |  |  |  |  |  | Prefix => "", | 
| 274 |  |  |  |  |  |  | NamespaceURI => "", | 
| 275 |  |  |  |  |  |  | Value => $value, | 
| 276 |  |  |  |  |  |  | }; | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | 1; | 
| 282 |  |  |  |  |  |  | __END__ |