[PATCH] Escaping attribute list for better processing of nested macros

37 views
Skip to first unread message

Stas Bushuev

unread,
Nov 24, 2009, 11:39:24 PM11/24/09
to asciidoc
There was a bug when macros nested each other:
Example:
Simple paragraph footnoteref:[1,"foonote body with an image
image:image.png[]"]

produced this docbook fragment

<simpara>Simple paragraph <footnote id="1"><simpara>"foonote body with
an image <inlinemediaobject> <imageobject> <imagedata
fileref="image.png"/> </imageobject>
<textobject><phrase>image.png</phrase></textobject> </
inlinemediaobject>"</simpara></footnote></simpara>

with a needless quotes, but correct.

if I quote first attribute,

Simple paragraph footnoteref:["1","foonote body with an image
image:image.png[]"]

then I get
...<footnote id=""1"">... which not xml-correct.

That happened because when nested macro image had expanded it
produced ...fileref="image.png"... and these quotes broke attribute
list parsing (because of syntax error in eval) for embracing macro.

The best I could think of is escaping expanded quotes and commas (just
in case):
[diff is agains asciidoc 8.5.1]

=== modified file 'asciidoc.py'
--- asciidoc.py 2009-11-24 14:04:18 +0000
+++ asciidoc.py 2009-11-25 03:59:50 +0000
@@ -390,6 +390,7 @@
dict.update(d)
assert len(d) > 0

+
def parse_named_attributes(s,attrs):
"""Update a attrs dictionary with name="value" attributes from
the s string.
Returns False if invalid syntax.
@@ -3373,11 +3374,18 @@
def subs(self,text,prefix='',callouts=False):
# If callouts is True then only callout macros are processed,
if False
# then all non-callout macros are processed.
+
+ # Escaping text
+ text = text.replace('#','#diez;');
result = text
for m in self.macros:
if m.prefix == prefix:
if callouts ^ (m.name != 'callout'):
result = m.subs(result)
+ # Unescaping
+ result = result.replace('#34;','"');
+ result = result.replace('#44;',',');
+ result = result.replace('#diez;','#');
return result
def isnext(self):
"""Return matching macro if block macro is next on reader."""
@@ -3466,6 +3474,9 @@
# Parse and validate passthrough subs.
subslist = parse_options(subslist, SUBS_OPTIONS,
'illegal subs in macro entry: %s' %
entry)
+
+ # Escaping pattern to match escaped text
+ pattern = pattern.replace('#','#diez;')
self.pattern = pattern
self.reo = re.compile(pattern)
self.prefix = prefix
@@ -3551,6 +3562,10 @@
result = '\n'.join(body)
if a0:
result = result.replace(chr(0), a0)
+
+ #Escaping symbols deluding eval
+ result = result.replace(',','#44;');
+ result = result.replace('"','#34;');
return result

return self.reo.sub(subs_func, text)

Stas Bushuev

unread,
Nov 25, 2009, 12:21:02 AM11/25/09
to asciidoc
Sorry I've missed block macros:
patch should look so:

=== modified file 'asciidoc.py'
--- asciidoc.py 2009-11-24 14:04:18 +0000
+++ asciidoc.py 2009-11-25 05:11:39 +0000
@@ -3373,11 +3373,18 @@
def subs(self,text,prefix='',callouts=False):
# If callouts is True then only callout macros are processed,
if False
# then all non-callout macros are processed.
+
+ # Escaping text
+ text = text.replace('#','#diez;');
result = text
for m in self.macros:
if m.prefix == prefix:
if callouts ^ (m.name != 'callout'):
result = m.subs(result)
+ # Unescaping
+ result = result.replace('#34;','"');
+ result = result.replace('#44;',',');
+ result = result.replace('#diez;','#');
return result
def isnext(self):
"""Return matching macro if block macro is next on reader."""
@@ -3466,6 +3473,9 @@
# Parse and validate passthrough subs.
subslist = parse_options(subslist, SUBS_OPTIONS,
'illegal subs in macro entry: %s' %
entry)
+
+ # Escaping pattern to match escaped text
+ pattern = pattern.replace('#','#diez;')
self.pattern = pattern
self.reo = re.compile(pattern)
self.prefix = prefix
@@ -3551,6 +3561,10 @@
result = '\n'.join(body)
if a0:
result = result.replace(chr(0), a0)
+
+ #Escaping symbols deluding eval
+ result = result.replace(',','#44;');
+ result = result.replace('"','#34;');
return result

return self.reo.sub(subs_func, text)
@@ -3568,6 +3582,10 @@
if self.has_passthrough():
s = macros.restore_passthroughs(s)
if s:
+ # Unescaping
+ s = s.replace('#34;','"');
+ s = s.replace('#44;',',');
+ s = s.replace('#diez;','#');
trace('macro',before,s)
writer.write(s)


Stuart Rackham

unread,
Nov 25, 2009, 3:09:46 PM11/25/09
to asci...@googlegroups.com
Hi Stas

Stas Bushuev wrote:
> There was a bug when macros nested each other:
> Example:
> Simple paragraph footnoteref:[1,"foonote body with an image
> image:image.png[]"]
>
> produced this docbook fragment
>
> <simpara>Simple paragraph <footnote id="1"><simpara>"foonote body with
> an image <inlinemediaobject> <imageobject> <imagedata
> fileref="image.png"/> </imageobject>
> <textobject><phrase>image.png</phrase></textobject> </
> inlinemediaobject>"</simpara></footnote></simpara>

The easiest solution in this case is not to quote the macro arguments:

Simple paragraph footnoteref:[1,footnote body with an image
image:image.png[]]

Which generates:

Simple paragraph <footnote id="1"><simpara>footnote body with an image
<inlinemediaobject> <imageobject> <imagedata fileref="image.png"/>
</imageobject> <textobject><phrase>image.png</phrase></textobject>
</inlinemediaobject></simpara></footnote>

But there are still two problems remaining:

1. "1" is not a valid ID, easily fixed though.

2. The DocBook simpara element cannot contain an inlinemediaobject element. In
this case the fix is to adjust the footnote templates, replacing simpara with
para -- I've just added this change to the trunk:

http://hg.sharesource.org/asciidoc/rev/0eaebee6812a


Cheers, Stuart
> --
>
> You received this message because you are subscribed to the Google Groups "asciidoc" group.
> To post to this group, send email to asci...@googlegroups.com.
> To unsubscribe from this group, send email to asciidoc+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/asciidoc?hl=en.
>
>
>

srackham

unread,
Nov 25, 2009, 3:34:22 PM11/25/09
to asciidoc
This is incorrect: simpara is fine, changeset reverted:

http://hg.sharesource.org/asciidoc/rev/37566cb7c3f7


Cheers, Stuart

Stas Bushuev

unread,
Nov 25, 2009, 10:52:00 PM11/25/09
to asciidoc


On 26 ноя, 01:09, Stuart Rackham <srack...@gmail.com> wrote:
>
> The easiest solution in this case is not to quote the macro arguments:
>
Yes, I know, but in real life I've encountered a footnote body with a
comma, so was forced to seek for solution.

Stuart Rackham

unread,
Nov 25, 2009, 11:22:16 PM11/25/09
to asci...@googlegroups.com
Use the &#44; entity to put a comma in the macro argument e.g.

Simple paragraph footnoteref:[F1,footnote&#44; body with an image
image:images/smallnew.png[]]

I'm trying to hardwire as little syntax as possible into asciidoc which is why I
prefer this solution for corner cases like this. I'll add an FAQ to the docs.


Cheers, Stuart
Reply all
Reply to author
Forward
0 new messages