@ -36,7 +36,7 @@ my ($hasxml, $hasxml_err); BEGIN { ($hasxml, $hasxml_err) = (0, "") }
my ( $ hasxmlp , $ hasxmlp_err ) ; BEGIN { ( $ hasxmlp , $ hasxmlp_err ) = ( 0 , "" ) }
@ ISA = qw( Exporter ) ;
@ EXPORT_OK = qw( Markdown ProcessRaw GenerateStyleSheet SetWikiOpts SplitURL
escapeXML unescapeXML ) ;
escapeXML unescapeXML ResolveFragment ) ;
$ INC { __PACKAGE__ . '.pm' } = $ INC { basename ( __FILE__ ) } unless exists $ INC { __PACKAGE__ . '.pm' } ;
close ( DATA ) if fileno ( DATA ) ;
@ -751,6 +751,7 @@ sub ProcessRaw {
# fancy style sheet when calling Markdown directly.
# auto_number => <= 0 (default) no numbering, 1 number h1s,
# 2 number h1s, h2s, 3 number h1-h3s, ... >= 6 number h1-h6s
# anchors => existence of this key triggers return of anchors HASH
# yamlmode => 0 (no YAML processing), > 0 (YAML on), < 0 (YAML ignore)
# if 0, the YAML front matter processor is completely
# disabled and any YAML front matter that might be present
@ -827,6 +828,18 @@ sub ProcessRaw {
# The following are OUTPUT values that can only be retrieved when
# Markdown is called with a HASH ref as the second argument
#
# anchors => if the 'anchors' key exists in the input HASH ref
# will be set to a HASH ref containing lookup keys
# for valid fragment ids in the document (only those
# created from Markdown markup) with the value the
# actual fragment link to use. Do not use this directly
# but pass it as the first argument to the ResolveFragment
# function to resolve a "fuzzy" fragment name to its
# actual fragment name in the generated output.
# NOTE: to activate return of anchors the 'anchors' key
# simply must exist in the input HASH ref passed to the
# Markdown function, its value will be replaced on output.
#
# h1 => will be set to the tag-stripped value of the first
# non-empty H1 generated by Markdown-style markup.
# note that literal <h1>...</h1> values are NOT picked up.
@ -912,6 +925,11 @@ sub _SanitizeOpts {
$ o - > { yamlmode } = - 1 unless looks_like_number ( $ o - > { yamlmode } ) ;
$ o - > { yamlvis } = 0 unless looks_like_number ( $ o - > { yamlvis } ) ;
delete $ o - > { yaml } ;
# The anchors hash will only be returned if the key exists
# (the key's value doesn't matter), set the value to an empty
# HASH ref just in case to make sure it's always a HASH ref.
$ o - > { anchors } = { } if exists ( $ o - > { anchors } ) ;
}
my % _yamlopts ;
@ -1064,6 +1082,7 @@ sub Markdown {
utf8:: encode ( $ text ) ;
if ( ref ( $ _ [ 0 ] ) eq "HASH" ) {
$ { $ _ [ 0 ] } { anchors } = { % g_anchors_id } if exists ( $ { $ _ [ 0 ] } { anchors } ) ;
if ( defined ( $ opt { h1 } ) && $ opt { h1 } ) {
utf8:: encode ( $ opt { h1 } ) ;
$ { $ _ [ 0 ] } { h1 } = $ opt { h1 } ;
@ -1735,28 +1754,29 @@ sub _SplitUrlTitlePart {
}
sub _FindFragmentMatch {
my $ url = shift ;
sub _FindFragmentMatchInternal {
my ( $ anchors_id , $ url , $ undefifnomatch ) = @ _ ;
if ( defined ( $ url ) && $ url =~ /^#\S/ ) {
# try very hard to find a match
my $ idbase = _strip ( lc ( substr ( $ url , 1 ) ) ) ;
my $ idbase0 = $ idbase ;
my $ id = _MakeAnchorId ( $ idbase ) ;
if ( defined ( $ g_anchors_id { $ id } ) ) {
$ url = $ g_anchors_id { $ id } ;
$ undefifnomatch and $ url = undef ;
if ( defined ( $$ anchors_id { $ id } ) ) {
$ url = $$ anchors_id { $ id } ;
} else {
$ idbase =~ s/-/_/gs ;
$ id = _MakeAnchorId ( $ idbase ) ;
if ( defined ( $ g_ anchors_id{ $ id } ) ) {
$ url = $ g_ anchors_id{ $ id } ;
if ( defined ( $$ anchors_id { $ id } ) ) {
$ url = $$ anchors_id { $ id } ;
} else {
$ id = _MakeAnchorId ( $ idbase0 , 1 ) ;
if ( defined ( $ g_ anchors_id{ $ id } ) ) {
$ url = $ g_ anchors_id{ $ id } ;
if ( defined ( $$ anchors_id { $ id } ) ) {
$ url = $$ anchors_id { $ id } ;
} else {
$ id = _MakeAnchorId ( $ idbase , 1 ) ;
if ( defined ( $ g_ anchors_id{ $ id } ) ) {
$ url = $ g_ anchors_id{ $ id } ;
if ( defined ( $$ anchors_id { $ id } ) ) {
$ url = $$ anchors_id { $ id } ;
}
}
}
@ -1766,6 +1786,47 @@ sub _FindFragmentMatch {
}
sub _FindFragmentMatch {
return _FindFragmentMatchInternal ( \ % g_anchors_id , @ _ ) ;
}
sub _ToUTF8 {
my $ input = shift ;
my $ output ;
if ( Encode:: is_utf8 ( $ input ) || utf8:: decode ( $ input ) ) {
$ output = $ input ;
} else {
$ output = $ encoder - > decode ( $ input , Encode:: FB_DEFAULT ) ;
}
return $ output ;
}
# $_[0] -> HASH ref of anchors (e.g. the "anchors" OUTPUT from Markdown)
# $_[1] -> fragment to resolve, may optionally start with '#'
# An empty string ("") or hash ("#") is returned as-is.
# returns undef if no match otherwise resolved fragment name
# which will start with a '#' if $_[1] started with '#' otherwise will not.
# This function can be used to connect up links to "implicit" anchors.
# All Markdown-format H1-H6 headers have an implicit anchor added
# based on the header item text. Passing that text to this function
# will cough up the matching implicit anchor if there is one.
sub ResolveFragment
{
my ( $ anchors , $ frag ) = @ _ ;
defined ( $ frag ) or return undef ;
$ frag eq "" || $ frag eq "#" and return $ frag ;
my $ hadhash = ( $ frag =~ s/^#// ) ;
$ frag =~ /^\S/ or return undef ;
ref ( $ anchors ) eq 'HASH' or return undef ;
my $ ans = _FindFragmentMatchInternal ( $ anchors , '#' . _ToUTF8 ( $ frag ) , 1 ) ;
$ hadhash || ! defined ( $ ans ) or $ ans =~ s/^#// ;
defined ( $ ans ) and utf8:: encode ( $ ans ) ;
return $ ans ;
}
# Return a suitably encoded <img...> tag string
# On input NONE of $url, $alt or $title should be xmlencoded
# but $url should already be url-encoded if needed, but NOT g_escape_table'd