File Coverage

blib/lib/Text/WikiCreole.pm
Criterion Covered Total %
statement 93 128 72.6
branch 37 66 56.0
condition 8 15 53.3
subroutine 12 20 60.0
pod 9 14 64.2
total 159 243 65.4


\n", close => " \n", \n", \n",
line stmt bran cond sub pod time code
1             package Text::WikiCreole;
2             require Exporter;
3             @ISA = (Exporter);
4             @EXPORT = qw(creole_parse creole_plugin creole_tag creole_img creole_customimgs
5             creole_link creole_barelink creole_customlinks creole_custombarelinks);
6 8     8   148258 use vars qw($VERSION);
  8         26  
  8         424  
7 8     8   50 use strict;
  8         16  
  8         295  
8 8     8   50 use warnings;
  8         19  
  8         43505  
9              
10             our $VERSION = "0.07";
11              
12             sub strip_head_eq { # strip lead/trail white/= from headings
13 4     4 0 23 $_[0] =~ s/^\s*=*\s*//o;
14 4         98 $_[0] =~ s/\s*=*\s*$//o;
15 4         16 return $_[0];
16             }
17              
18             sub strip_list { # strip list markup trickery
19 19     19 0 90 $_[0] =~ s/(?:`*| *)[\*\#]/`/o;
20 19         120 $_[0] =~ s/\n(?:`*| *)[\*\#]/\n`/gso;
21 19         69 return $_[0];
22             }
23              
24             # characters that may indicate inline wiki markup
25             my @specialchars = ('^', '\\', '*', '/', '_', ',', '{', '[',
26             '<', '~', '|', "\n", '#', ':', ';', '(', '-', '.');
27             # plain characters - auto-generated below (ascii printable minus @specialchars)
28             my @plainchars;
29              
30             # non-plain text inline widgets
31             my @inline = ('strong', 'em', 'br', 'esc', 'img', 'link', 'ilink',
32             'inowiki', 'sub', 'sup', 'mono', 'u', 'plug', 'plug2', 'tm',
33             'reg', 'copy', 'ndash', 'ellipsis', 'amp');
34             my @all_inline = (@inline, 'plain', 'any'); # including plain text
35              
36             # blocks
37             my @blocks = ('h1', 'h2', 'h3', 'hr', 'nowiki', 'h4', 'h5', 'h6',
38             'ul', 'ol', 'table', 'p', 'ip', 'dl', 'plug', 'plug2', 'blank');
39              
40             # handy - used several times in %chunks
41             my $eol = '(?:\n|$)'; # end of line (or string)
42             my $bol = '(?:^|\n)'; # beginning of line (or string)
43              
44             # user-supplied plugin parser function
45             my $plugin_function;
46             # user-supplied link URL parser function
47             my $link_function;
48             # user-supplied bare link parser function
49             my $barelink_function;
50             # user-supplied image URL parser function
51             my $img_function;
52              
53             # initialize once
54             my $initialized = 0;
55              
56             my %chunks = (
57             top => {
58             contains => \@blocks,
59             },
60             blank => {
61             curpat => "(?= *$eol)",
62             fwpat => "(?=(?:^|\n) *$eol)",
63             stops => '(?=\S)',
64             hint => ["\n"],
65             filter => sub { return ""; }, # whitespace into the bit bucket
66             open => "", close => "",
67             },
68             p => {
69             curpat => '(?=.)',
70             stops => ['blank', 'ip', 'h', 'hr', 'nowiki', 'ul', 'ol', 'dl', 'table'],
71             hint => \@plainchars,
72             contains => \@all_inline,
73             filter => sub { chomp $_[0]; return $_[0]; },
74             open => "

", close => "

\n\n",
75             },
76             ip => {
77             curpat => '(?=:)',
78             fwpat => '\n(?=:)',
79             stops => ['blank', 'h', 'hr', 'nowiki', 'ul', 'ol', 'dl', 'table'],
80             hint => [':'],
81             contains => ['p', 'ip'],
82             filter => sub {
83             $_[0] =~ s/://o;
84             $_[0] =~ s/\n:/\n/so;
85             return $_[0];
86             },
87             open => "
", close => "
\n",
88             },
89             dl => {
90             curpat => '(?=;)',
91             fwpat => '\n(?=;)',
92             stops => ['blank', 'h', 'hr', 'nowiki', 'ul', 'ol', 'table'],
93             hint => [';'],
94             contains => ['dt', 'dd'],
95             open => "
\n", close => "
\n",
96             },
97             dt => {
98             curpat => '(?=;)',
99             fwpat => '\n(?=;)',
100             stops => '(?=:|\n)',
101             hint => [';'],
102             contains => \@all_inline,
103             filter => sub { $_[0] =~ s/^;\s*//o; return $_[0]; },
104             open => "
", close => "
\n",
105             },
106             dd => {
107             curpat => '(?=\n|:)',
108             fwpat => '(?:\n|:)',
109             stops => '(?=:)|\n(?=;)',
110             hint => [':', "\n"],
111             contains => \@all_inline,
112             filter => sub {
113             $_[0] =~ s/(?:\n|:)\s*//so;
114             $_[0] =~ s/\s*$//so;
115             return $_[0];
116             },
117             open => "
", close => "
\n",
118             },
119             table => {
120             curpat => '(?= *\|.)',
121             fwpat => '\n(?= *\|.)',
122             stops => '\n(?= *[^\|])',
123             contains => ['tr'],
124             hint => ['|', ' '],
125             open => "\n", close => "
\n\n",
126             },
127             tr => {
128             curpat => '(?= *\|)',
129             stops => '\n',
130             contains => ['td', 'th'],
131             hint => ['|', ' '],
132             filter => sub { $_[0] =~ s/^ *//o; $_[0] =~ s/\| *$//o; return $_[0]; },
133             open => "
134             },
135             td => {
136             curpat => '(?=\|[^=])',
137             # this gnarly regex fixes ambiguous '|' for links/imgs/nowiki in tables
138             stops => '[^~](?=\|(?!(?:[^\[]*\]\])|(?:[^\{]*\}\})))',
139             contains => \@all_inline,
140             hint => ['|'],
141             filter => sub {$_[0] =~ s/^ *\| *//o; $_[0] =~ s/\s*$//so; return $_[0]; },
142             open => " ", close => "
143             },
144             th => {
145             curpat => '(?=\|=)',
146             # this gnarly regex fixes ambiguous '|' for links/imgs/nowiki in tables
147             stops => '[^~](?=\|(?!(?:[^\[]*\]\])|(?:[^\{]*\}\})))',
148             contains => \@all_inline,
149             hint => ['|'],
150             filter => sub {$_[0] =~ s/^ *\|= *//o; $_[0] =~ s/\s*$//so; return $_[0]; },
151             open => " ", close => "
152             },
153             ul => {
154             curpat => '(?=(?:`| *)\*[^\*])',
155             fwpat => '(?=\n(?:`| *)\*[^\*])',
156             stops => ['blank', 'ip', 'h', 'nowiki', 'li', 'table', 'hr', 'dl'],
157             contains => ['ul', 'ol', 'li'],
158             hint => ['*', ' '],
159             filter => \&strip_list,
160             open => "
    \n", close => "
\n",
161             },
162             ol => {
163             curpat => '(?=(?:`| *)\#[^\#])',
164             fwpat => '(?=\n(?:`| *)\#[^\#])',
165             stops => ['blank', 'ip', 'h', 'nowiki', 'li', 'table', 'hr', 'dl'],
166             contains => ['ul', 'ol', 'li'],
167             hint => ['#', ' '],
168             filter => \&strip_list,
169             open => "
    \n", close => "
\n",
170             },
171             li => {
172             curpat => '(?=`[^\*\#])',
173             fwpat => '\n(?=`[^\*\#])',
174             stops => '\n(?=`)',
175             hint => ['`'],
176             filter => sub {
177             $_[0] =~ s/` *//o;
178             chomp $_[0];
179             return $_[0];
180             },
181             contains => \@all_inline,
182             open => "
  • ", close => "
  • \n",
    183             },
    184             nowiki => {
    185             curpat => '(?=\{\{\{ *\n)',
    186             fwpat => '\n(?=\{\{\{ *\n)',
    187             stops => "\n\}\}\} *$eol",
    188             hint => ['{'],
    189             filter => sub {
    190             substr($_[0], 0, 3, '');
    191             $_[0] =~ s/\}\}\}\s*$//o;
    192             $_[0] =~ s/&/&/go;
    193             $_[0] =~ s/
    194             $_[0] =~ s/>/>/go;
    195             return $_[0];
    196             },
    197             open => "
    ", close => "
    \n\n",
    198             },
    199             hr => {
    200             curpat => "(?= *-{4,} *$eol)",
    201             fwpat => "\n(?= *-{4,} *$eol)",
    202             hint => ['-', ' '],
    203             stops => $eol,
    204             open => "
    \n\n", close => "",
    205             filter => sub { return ""; } # ----- into the bit bucket
    206             },
    207             h => { curpat => '(?=(?:^|\n) *=)' }, # matches any heading
    208             h1 => {
    209             curpat => '(?= *=[^=])',
    210             hint => ['=', ' '],
    211             stops => '\n',
    212             contains => \@all_inline,
    213             open => "

    ", close => "

    \n\n",
    214             filter => \&strip_head_eq,
    215             },
    216             h2 => {
    217             curpat => '(?= *={2}[^=])',
    218             hint => ['=', ' '],
    219             stops => '\n',
    220             contains => \@all_inline,
    221             open => "

    ", close => "

    \n\n",
    222             filter => \&strip_head_eq,
    223             },
    224             h3 => {
    225             curpat => '(?= *={3}[^=])',
    226             hint => ['=', ' '],
    227             stops => '\n',
    228             contains => \@all_inline,
    229             open => "

    ", close => "

    \n\n",
    230             filter => \&strip_head_eq,
    231             },
    232             h4 => {
    233             curpat => '(?= *={4}[^=])',
    234             hint => ['=', ' '],
    235             stops => '\n',
    236             contains => \@all_inline,
    237             open => "

    ", close => "

    \n\n",
    238             filter => \&strip_head_eq,
    239             },
    240             h5 => {
    241             curpat => '(?= *={5}[^=])',
    242             hint => ['=', ' '],
    243             stops => '\n',
    244             contains => \@all_inline,
    245             open => "
    ", close => "
    \n\n",
    246             filter => \&strip_head_eq,
    247             },
    248             h6 => {
    249             curpat => '(?= *={6,})',
    250             hint => ['=', ' '],
    251             stops => '\n',
    252             contains => \@all_inline,
    253             open => "
    ", close => "
    \n\n",
    254             filter => \&strip_head_eq,
    255             },
    256             plain => {
    257             curpat => '(?=[^\*\/_\,\^\\\\{\[\<\|])',
    258             stops => \@inline,
    259             hint => \@plainchars,
    260             open => '', close => ''
    261             },
    262             any => { # catch-all
    263             curpat => '(?=.)',
    264             stops => \@inline,
    265             open => '', close => ''
    266             },
    267             br => {
    268             curpat => '(?=\\\\\\\\)',
    269             stops => '\\\\\\\\',
    270             hint => ['\\'],
    271             filter => sub { return ''; },
    272             open => '
    ', close => '',
    273             },
    274             esc => {
    275             curpat => '(?=~[\S])',
    276             stops => '~.',
    277             hint => ['~'],
    278             filter => sub { substr($_[0], 0, 1, ''); return $_[0]; },
    279             open => '', close => '',
    280             },
    281             inowiki => {
    282             curpat => '(?=\{{3}.*?\}*\}{3})',
    283             stops => '.*?\}*\}{3}',
    284             hint => ['{'],
    285             filter => sub {
    286             substr($_[0], 0, 3, '');
    287             $_[0] =~ s/\}{3}$//o;
    288             $_[0] =~ s/&/&/go;
    289             $_[0] =~ s/
    290             $_[0] =~ s/>/>/go;
    291             return $_[0];
    292             },
    293             open => "", close => "",
    294             },
    295             plug => {
    296             curpat => '(?=\<{3}.*?\>*\>{3})',
    297             stops => '.*?\>*\>{3}',
    298             hint => ['<'],
    299             filter => sub {
    300             substr($_[0], 0, 3, '');
    301             $_[0] =~ s/\>{3}$//o;
    302             if($plugin_function) {
    303             return &$plugin_function($_[0]);
    304             }
    305             return "<<<$_[0]>>>";
    306             },
    307             open => "", close => "",
    308             },
    309             plug2 => {
    310             curpat => '(?=\<{2}.*?\>*\>{2})',
    311             stops => '.*?\>*\>{2}',
    312             hint => ['<'],
    313             filter => sub {
    314             substr($_[0], 0, 2, '');
    315             $_[0] =~ s/\>{2}$//o;
    316             if($plugin_function) {
    317             return &$plugin_function($_[0]);
    318             }
    319             return "<<$_[0]>>";
    320             },
    321             open => "", close => "",
    322             },
    323             ilink => {
    324             curpat => '(?=(?:https?|ftp):\/\/)',
    325             stops => '(?=[[:punct:]]?(?:\s|$))',
    326             hint => ['h', 'f'],
    327             filter => sub {
    328             $_[0] =~ s/^\s*//o;
    329             $_[0] =~ s/\s*$//o;
    330             if($barelink_function) {
    331             $_[0] = &$barelink_function($_[0]);
    332             }
    333             return "href=\"$_[0]\">$_[0]"; },
    334             open => " "",
    335             },
    336             link => {
    337             curpat => '(?=\[\[[^\n]+?\]\])',
    338             stops => '\]\]',
    339             hint => ['['],
    340             contains => ['href', 'atext'],
    341             filter => sub {
    342             substr($_[0], 0, 2, '');
    343             substr($_[0], -2, 2, '');
    344             $_[0] .= "|$_[0]" unless $_[0] =~ tr/|/|/; # text = url unless given
    345             return $_[0];
    346             },
    347             open => " "",
    348             },
    349             href => {
    350             curpat => '(?=[^\|])',
    351             stops => '(?=\|)',
    352             filter => sub {
    353             $_[0] =~ s/^\s*//o;
    354             $_[0] =~ s/\s*$//o;
    355             if($link_function) {
    356             $_[0] = &$link_function($_[0]);
    357             }
    358             return $_[0];
    359             },
    360             open => 'href="', close => '">',
    361             },
    362             atext => {
    363             curpat => '(?=\|)',
    364             stops => '\n',
    365             hint => ['|'],
    366             contains => \@all_inline,
    367             filter => sub {
    368             $_[0] =~ s/^\|\s*//o;
    369             $_[0] =~ s/\s*$//o;
    370             return $_[0];
    371             },
    372             open => '', close => '',
    373             },
    374             img => {
    375             curpat => '(?=\{\{[^\{][^\n]*?\}\})',
    376             stops => '\}\}',
    377             hint => ['{'],
    378             contains => ['imgsrc', 'imgalt'],
    379             filter => sub {
    380             substr($_[0], 0, 2, '');
    381             $_[0] =~ s/\}\}$//o;
    382             return $_[0];
    383             },
    384             open => " " />",
    385             },
    386             imgalt => {
    387             curpat => '(?=\|)',
    388             stops => '\n',
    389             hint => ['|'],
    390             filter => sub { $_[0] =~ s/^\|\s*//o; $_[0] =~ s/\s*$//o; return $_[0]; },
    391             open => ' alt="', close => '"',
    392             },
    393             imgsrc => {
    394             curpat => '(?=[^\|])',
    395             stops => '(?=\|)',
    396             filter => sub {
    397             $_[0] =~ s/^\s*//o;
    398             $_[0] =~ s/\s*$//o;
    399             if($img_function) {
    400             $_[0] = &$img_function($_[0]);
    401             }
    402             return $_[0];
    403             },
    404             open => 'src="', close => '"',
    405             },
    406             strong => {
    407             curpat => '(?=\*\*)',
    408             stops => '\*\*.*?\*\*',
    409             hint => ['*'],
    410             contains => \@all_inline,
    411             filter => sub {
    412             substr($_[0], 0, 2, '');
    413             $_[0] =~ s/\*\*$//o;
    414             return $_[0];
    415             },
    416             open => "", close => "",
    417             },
    418             em => {
    419             curpat => '(?=\/\/)',
    420             stops => '\/\/.*?(?
    421             hint => ['/'],
    422             contains => \@all_inline,
    423             filter => sub {
    424             substr($_[0], 0, 2, '');
    425             $_[0] =~ s/\/\/$//o;
    426             return $_[0];
    427             },
    428             open => "", close => "",
    429             },
    430             mono => {
    431             curpat => '(?=\#\#)',
    432             stops => '\#\#.*?\#\#',
    433             hint => ['#'],
    434             contains => \@all_inline,
    435             filter => sub {
    436             substr($_[0], 0, 2, '');
    437             $_[0] =~ s/\#\#$//o;
    438             return $_[0];
    439             },
    440             open => "", close => "",
    441             },
    442             sub => {
    443             curpat => '(?=,,)',
    444             stops => ',,.*?,,',
    445             hint => [','],
    446             contains => \@all_inline,
    447             filter => sub {
    448             substr($_[0], 0, 2, '');
    449             $_[0] =~ s/\,\,$//o;
    450             return $_[0];
    451             },
    452             open => "", close => "",
    453             },
    454             sup => {
    455             curpat => '(?=\^\^)',
    456             stops => '\^\^.*?\^\^',
    457             hint => ['^'],
    458             contains => \@all_inline,
    459             filter => sub {
    460             substr($_[0], 0, 2, '');
    461             $_[0] =~ s/\^\^$//o;
    462             return $_[0];
    463             },
    464             open => "", close => "",
    465             },
    466             u => {
    467             curpat => '(?=__)',
    468             stops => '__.*?__',
    469             hint => ['_'],
    470             contains => \@all_inline,
    471             filter => sub {
    472             substr($_[0], 0, 2, '');
    473             $_[0] =~ s/__$//o;
    474             return $_[0];
    475             },
    476             open => "", close => "",
    477             },
    478             amp => {
    479             curpat => '(?=\&(?!\w+\;))',
    480             stops => '.',
    481             hint => ['&'],
    482             filter => sub { return "&"; },
    483             open => "", close => "",
    484             },
    485             tm => {
    486             curpat => '(?=\(TM\))',
    487             stops => '\(TM\)',
    488             hint => ['('],
    489             filter => sub { return "™"; },
    490             open => "", close => "",
    491             },
    492             reg => {
    493             curpat => '(?=\(R\))',
    494             stops => '\(R\)',
    495             hint => ['('],
    496             filter => sub { return "®"; },
    497             open => "", close => "",
    498             },
    499             copy => {
    500             curpat => '(?=\(C\))',
    501             stops => '\(C\)',
    502             hint => ['('],
    503             filter => sub { return "©"; },
    504             open => "", close => "",
    505             },
    506             ndash => {
    507             curpat => '(?=--)',
    508             stops => '--',
    509             hint => ['-'],
    510             filter => sub { return "–"; },
    511             open => "", close => "",
    512             },
    513             ellipsis => {
    514             curpat => '(?=\.\.\.)',
    515             stops => '\.\.\.',
    516             hint => ['.'],
    517             filter => sub { return "…"; },
    518             open => "", close => "",
    519             },
    520             );
    521              
    522            
    523             sub parse; # predeclared because it's recursive
    524            
    525             sub parse {
    526 173     173 0 379 my ($tref, $chunk) = @_;
    527 173         180 my ($html, $ch);
    528 173         303 my $pos = 0; my $lpos = 0;
      173         187  
    529 173         192 while(1) {
    530 605 100       1244 if($ch) { # if we already know what kind of chunk this is
    531 432 100       7910 if ($$tref =~ /$chunks{$ch}{delim}/g) { # find where it stops...
    532 279         472 $pos = pos($$tref); # another chunk
    533             } else {
    534 153         283 $pos = length $$tref; # end of string
    535             }
    536              
    537 432         1003 $html .= $chunks{$ch}{open}; # print the open tag
    538            
    539 432         1538 my $t = substr($$tref, $lpos, $pos - $lpos); # grab the chunk
    540 432 100       1233 if($chunks{$ch}{filter}) { # filter it, if applicable
    541 260         293 $t = &{$chunks{$ch}{filter}}($t);
      260         742  
    542             }
    543 432         800 $lpos = $pos; # remember where this chunk ends (where next begins)
    544 432 100 100     2550 if($t && $chunks{$ch}{contains}) { # if it contains other chunks...
    545 165         434 $html .= parse(\$t, $ch); # recurse.
    546             } else {
    547 267         628 $html .= $t; # otherwise, print it
    548             }
    549 432         1280 $html .= $chunks{$ch}{close}; # print the close tag
    550             }
    551              
    552 605 100 100     17836 if($pos && $pos == length($$tref)) { # we've eaten the whole string
    553 173         275 last;
    554             } else { # more string to come
    555 432         627 $ch = undef;
    556 432         1110 my $fc = substr($$tref, $pos, 1); # get a hint about the next chunk
    557 432         583 foreach (@{$chunks{$chunk}{hints}{$fc}}) {
      432         1548  
    558             # print "trying $_ for -$fc- on -" . substr($$tref, $pos, 2) . "-\n";
    559 438 100       2851 if($$tref =~ $chunks{$_}{curpatcmp}) { # hint helped id the chunk
    560 382         576 $ch = $_; last;
      382         554  
    561             }
    562             }
    563 432 100       1284 unless($ch) { # hint didn't help
    564 50         71 foreach (@{$chunks{$chunk}{contains}}) { # check all possible chunks
      50         142  
    565             # print "trying $_ on -" . substr($$tref, $pos, 2) . "-\n";
    566 844 100       4499 if ($$tref =~ $chunks{$_}{curpatcmp}) { # found one
    567 50         83 $ch = $_; last;
      50         89  
    568             }
    569             }
    570 50 50       185 last unless $ch; # no idea what this is. ditch the rest and give up.
    571             }
    572             }
    573             }
    574 173         784 return $html; # voila!
    575             }
    576              
    577             # compile a regex that matches any of the patterns that interrupt the
    578             # current chunk.
    579             sub delim {
    580 376 100   376 0 960 if(ref $chunks{$_[0]}{stops}) {
    581 56         77 my $regex;
    582 56         82 foreach(@{$chunks{$_[0]}{stops}}) {
      56         155  
    583 640 100       1384 if($chunks{$_}{fwpat}) {
    584 280         743 $regex .= "$chunks{$_}{fwpat}|";
    585             } else {
    586 360         791 $regex .= "$chunks{$_}{curpat}|";
    587             }
    588             }
    589 56         138 chop $regex;
    590 56         4735 return qr/$regex/s;
    591             } else {
    592 320         4568 return qr/$chunks{$_[0]}{stops}/s;
    593             }
    594             }
    595              
    596             # one-time optimization of the grammar - speeds the parser up a ton
    597             sub init {
    598 8 50   8 0 45 return if $initialized;
    599              
    600 8         20 $initialized = 1;
    601              
    602             # build an array of "plain content" characters by subtracting @specialchars
    603             # from ascii printable (ascii 32 to 126)
    604 8         33 my %is_special = map({$_ => 1} @specialchars);
      144         478  
    605 8         46 for (32 .. 126) {
    606 760 100       7916 push(@plainchars, chr($_)) unless $is_special{chr($_)};
    607             }
    608              
    609             # precompile a bunch of regexes
    610 8         162 foreach my $c (keys %chunks) {
    611 392 100       1152 if($chunks{$c}{curpat}) {
    612 384         7888 $chunks{$c}{curpatcmp} = qr/\G$chunks{$c}{curpat}/s;
    613             }
    614 392 100       1346 if($chunks{$c}{stops}) {
    615 376         747 $chunks{$c}{delim} = delim $c;
    616             }
    617 392 100       1544 if($chunks{$c}{contains}) { # store hints about each chunk to speed id
    618 224         286 foreach my $ct (@{$chunks{$c}{contains}}) {
      224         578  
    619 3616         3880 foreach (@{$chunks{$ct}{hint}}) {
      3616         8087  
    620 16664         18200 push @{$chunks{$c}{hints}{$_}}, $ct;
      16664         61206  
    621             }
    622             }
    623             }
    624             }
    625             }
    626              
    627             sub creole_parse {
    628 8 50 33 8 1 1081 return unless defined $_[0] && length $_[0] > 0;
    629 8         27 my $text = $_[0];
    630 8         44 init;
    631 8         81 my $html = parse(\$text, "top");
    632 8         77 return $html;
    633             }
    634              
    635             sub creole_plugin {
    636 1 50   1 1 17 return unless defined $_[0];
    637 1         5 $plugin_function = $_[0];
    638             }
    639              
    640             sub creole_link {
    641 1 50   1 1 17 return unless defined $_[0];
    642 1         4 $link_function = $_[0];
    643             }
    644              
    645             sub creole_customlinks {
    646 0     0 1 0 $chunks{href}{open} = "";
    647 0         0 $chunks{href}{close} = "";
    648 0         0 $chunks{link}{open} = "";
    649 0         0 $chunks{link}{close} = "";
    650 0         0 delete $chunks{link}{contains};
    651             $chunks{link}{filter} = sub {
    652 0 0   0   0 if($link_function) {
    653 0         0 $_[0] = &$link_function($_[0]);
    654             }
    655 0         0 return $_[0];
    656             }
    657 0         0 }
    658              
    659             sub creole_barelink {
    660 0 0   0 1 0 return unless defined $_[0];
    661 0         0 $barelink_function = $_[0];
    662             }
    663              
    664             sub creole_custombarelinks {
    665 0     0 1 0 $chunks{ilink}{open} = "";
    666 0         0 $chunks{ilink}{close} = "";
    667             $chunks{ilink}{filter} = sub {
    668 0 0   0   0 if($barelink_function) {
    669 0         0 $_[0] = &$barelink_function($_[0]);
    670             }
    671 0         0 return $_[0];
    672             }
    673 0         0 }
    674              
    675             sub creole_customimgs {
    676 0     0 1 0 $chunks{img}{open} = "";
    677 0         0 $chunks{img}{close} = "";
    678 0         0 delete $chunks{img}{contains};
    679             $chunks{img}{filter} = sub {
    680 0 0   0   0 if($img_function) {
    681 0         0 $_[0] = &$img_function($_[0]);
    682             }
    683 0         0 return $_[0];
    684             }
    685 0         0 }
    686              
    687             sub creole_img {
    688 0 0   0 1 0 return unless defined $_[0];
    689 0         0 $img_function = $_[0];
    690             }
    691              
    692             sub creole_tag {
    693 1     1 1 14 my ($tag, $type, $text) = @_;
    694 1 50       5 if(! $tag) {
    695 0         0 foreach (sort keys %chunks) {
    696 0         0 my $o = $chunks{$_}{open};
    697 0         0 my $c = $chunks{$_}{close};
    698 0 0 0     0 next unless $o && $o =~ /
    699 0 0       0 $o =~ s/\n/\\n/gso if $o; $o = "" unless $o;
      0 0       0  
    700 0 0       0 $c =~ s/\n/\\n/gso if $c; $c = "" unless $c;
      0 0       0  
    701 0         0 print "$_: open($o) close($c)\n";
    702             }
    703             } else {
    704 1 50 33     8 return unless ($type eq "open" || $type eq "close");
    705 1 50       7 return unless $chunks{$tag};
    706 1 50       8 $chunks{$tag}{$type} = $text ? $text : "";
    707             }
    708             }
    709              
    710             1;
    711             __END__