home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_939 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  46.8 KB  |  1,408 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. version = '1.7'
  5. version_info = (1, 7, 0, 'rc-2')
  6. __revision__ = '$Rev: 72 $'
  7. import re
  8. import sys
  9. import codecs
  10. from logging import getLogger, StreamHandler, Formatter, DEBUG, INFO, WARN, ERROR, CRITICAL
  11. MESSAGE_THRESHOLD = CRITICAL
  12. logger = getLogger('MARKDOWN')
  13. logger.setLevel(DEBUG)
  14. console_hndlr = StreamHandler()
  15. formatter = Formatter('%(name)s-%(levelname)s: "%(message)s"')
  16. console_hndlr.setFormatter(formatter)
  17. console_hndlr.setLevel(MESSAGE_THRESHOLD)
  18. logger.addHandler(console_hndlr)
  19.  
  20. def message(level, text):
  21.     logger.log(level, text)
  22.  
  23. TAB_LENGTH = 4
  24. ENABLE_ATTRIBUTES = True
  25. SMART_EMPHASIS = 1
  26. HTML_REMOVED_TEXT = '[HTML_REMOVED]'
  27. RTL_BIDI_RANGES = ((u'╓É', u'▀┐'), (u'Γ┤░', u'Γ╡┐'))
  28. BOMS = {
  29.     'utf-8': (codecs.BOM_UTF8,),
  30.     'utf-16': (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE) }
  31.  
  32. def removeBOM(text, encoding):
  33.     convert = isinstance(text, unicode)
  34.     for bom in BOMS[encoding]:
  35.         if not convert or bom.decode(encoding):
  36.             pass
  37.         bom = bom
  38.         if text.startswith(bom):
  39.             return text.lstrip(bom)
  40.     
  41.     return text
  42.  
  43. EXECUTABLE_NAME_FOR_USAGE = 'python markdown.py'
  44. HTML_PLACEHOLDER_PREFIX = 'qaodmasdkwaspemas'
  45. HTML_PLACEHOLDER = HTML_PLACEHOLDER_PREFIX + '%dajkqlsmdqpakldnzsdfls'
  46. BLOCK_LEVEL_ELEMENTS = [
  47.     'p',
  48.     'div',
  49.     'blockquote',
  50.     'pre',
  51.     'table',
  52.     'dl',
  53.     'ol',
  54.     'ul',
  55.     'script',
  56.     'noscript',
  57.     'form',
  58.     'fieldset',
  59.     'iframe',
  60.     'math',
  61.     'ins',
  62.     'del',
  63.     'hr',
  64.     'hr/',
  65.     'style']
  66.  
  67. def isBlockLevel(tag):
  68.     if tag in BLOCK_LEVEL_ELEMENTS and tag[0] == 'h':
  69.         pass
  70.     return tag[1] in '0123456789'
  71.  
  72. ENTITY_NORMALIZATION_EXPRESSIONS = [
  73.     (re.compile('&'), '&'),
  74.     (re.compile('<'), '<'),
  75.     (re.compile('>'), '>')]
  76. ENTITY_NORMALIZATION_EXPRESSIONS_SOFT = [
  77.     (re.compile('&(?!\\#)'), '&'),
  78.     (re.compile('<'), '<'),
  79.     (re.compile('>'), '>'),
  80.     (re.compile('"'), '"')]
  81.  
  82. def getBidiType(text):
  83.     if not text:
  84.         return None
  85.     ch = text[0]
  86.     if not isinstance(ch, unicode) or not ch.isalpha():
  87.         return None
  88.     for min, max in RTL_BIDI_RANGES:
  89.         if ch >= min and ch <= max:
  90.             return 'rtl'
  91.     else:
  92.         return 'ltr'
  93.     return ch <= max
  94.  
  95.  
  96. class Document:
  97.     
  98.     def __init__(self):
  99.         self.bidi = 'ltr'
  100.  
  101.     
  102.     def appendChild(self, child):
  103.         self.documentElement = child
  104.         child.isDocumentElement = True
  105.         child.parent = self
  106.         self.entities = { }
  107.  
  108.     
  109.     def setBidi(self, bidi):
  110.         if bidi:
  111.             self.bidi = bidi
  112.         
  113.  
  114.     
  115.     def createElement(self, tag, textNode = None):
  116.         el = Element(tag)
  117.         el.doc = self
  118.         if textNode:
  119.             el.appendChild(self.createTextNode(textNode))
  120.         
  121.         return el
  122.  
  123.     
  124.     def createTextNode(self, text):
  125.         node = TextNode(text)
  126.         node.doc = self
  127.         return node
  128.  
  129.     
  130.     def createEntityReference(self, entity):
  131.         if entity not in self.entities:
  132.             self.entities[entity] = EntityReference(entity)
  133.         
  134.         return self.entities[entity]
  135.  
  136.     
  137.     def createCDATA(self, text):
  138.         node = CDATA(text)
  139.         node.doc = self
  140.         return node
  141.  
  142.     
  143.     def toxml(self):
  144.         return self.documentElement.toxml()
  145.  
  146.     
  147.     def normalizeEntities(self, text, avoidDoubleNormalizing = False):
  148.         if avoidDoubleNormalizing:
  149.             regexps = ENTITY_NORMALIZATION_EXPRESSIONS_SOFT
  150.         else:
  151.             regexps = ENTITY_NORMALIZATION_EXPRESSIONS
  152.         for regexp, substitution in regexps:
  153.             text = regexp.sub(substitution, text)
  154.         
  155.         return text
  156.  
  157.     
  158.     def find(self, test):
  159.         return self.documentElement.find(test)
  160.  
  161.     
  162.     def unlink(self):
  163.         self.documentElement.unlink()
  164.         self.documentElement = None
  165.  
  166.  
  167.  
  168. class CDATA:
  169.     type = 'cdata'
  170.     
  171.     def __init__(self, text):
  172.         self.text = text
  173.  
  174.     
  175.     def handleAttributes(self):
  176.         pass
  177.  
  178.     
  179.     def toxml(self):
  180.         return '<![CDATA[' + self.text + ']]>'
  181.  
  182.  
  183.  
  184. class Element:
  185.     type = 'element'
  186.     
  187.     def __init__(self, tag):
  188.         self.nodeName = tag
  189.         self.attributes = []
  190.         self.attribute_values = { }
  191.         self.childNodes = []
  192.         self.bidi = None
  193.         self.isDocumentElement = False
  194.  
  195.     
  196.     def setBidi(self, bidi):
  197.         if bidi:
  198.             orig_bidi = self.bidi
  199.             if not (self.bidi) or self.isDocumentElement:
  200.                 self.bidi = bidi
  201.                 self.parent.setBidi(bidi)
  202.             
  203.         
  204.  
  205.     
  206.     def unlink(self):
  207.         for child in self.childNodes:
  208.             if child.type == 'element':
  209.                 child.unlink()
  210.                 continue
  211.         
  212.         self.childNodes = None
  213.  
  214.     
  215.     def setAttribute(self, attr, value):
  216.         if attr not in self.attributes:
  217.             self.attributes.append(attr)
  218.         
  219.         self.attribute_values[attr] = value
  220.  
  221.     
  222.     def insertChild(self, position, child):
  223.         self.childNodes.insert(position, child)
  224.         child.parent = self
  225.  
  226.     
  227.     def removeChild(self, child):
  228.         self.childNodes.remove(child)
  229.  
  230.     
  231.     def replaceChild(self, oldChild, newChild):
  232.         position = self.childNodes.index(oldChild)
  233.         self.removeChild(oldChild)
  234.         self.insertChild(position, newChild)
  235.  
  236.     
  237.     def appendChild(self, child):
  238.         self.childNodes.append(child)
  239.         child.parent = self
  240.  
  241.     
  242.     def handleAttributes(self):
  243.         pass
  244.  
  245.     
  246.     def find(self, test, depth = 0):
  247.         matched_nodes = []
  248.         for child in self.childNodes:
  249.             if test(child):
  250.                 matched_nodes.append(child)
  251.             
  252.             if child.type == 'element':
  253.                 matched_nodes += child.find(test, depth + 1)
  254.                 continue
  255.         
  256.         return matched_nodes
  257.  
  258.     
  259.     def toxml(self):
  260.         if ENABLE_ATTRIBUTES:
  261.             for child in self.childNodes:
  262.                 child.handleAttributes()
  263.             
  264.         
  265.         buffer = ''
  266.         if self.nodeName in ('h1', 'h2', 'h3', 'h4'):
  267.             buffer += '\n'
  268.         elif self.nodeName in ('li',):
  269.             buffer += '\n '
  270.         
  271.         childBuffer = ''
  272.         if self.childNodes or self.nodeName in ('blockquote',):
  273.             childBuffer += '>'
  274.             for child in self.childNodes:
  275.                 childBuffer += child.toxml()
  276.             
  277.             if self.nodeName == 'p':
  278.                 childBuffer += '\n'
  279.             elif self.nodeName == 'li':
  280.                 childBuffer += '\n '
  281.             
  282.             childBuffer += '</%s>' % self.nodeName
  283.         else:
  284.             childBuffer += '/>'
  285.         buffer += '<' + self.nodeName
  286.         if self.nodeName in ('p', 'li', 'ul', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'):
  287.             if not self.attribute_values.has_key('dir'):
  288.                 if self.bidi:
  289.                     bidi = self.bidi
  290.                 else:
  291.                     bidi = self.doc.bidi
  292.                 if bidi == 'rtl':
  293.                     self.setAttribute('dir', 'rtl')
  294.                 
  295.             
  296.         
  297.         for attr in self.attributes:
  298.             value = self.attribute_values[attr]
  299.             value = self.doc.normalizeEntities(value, avoidDoubleNormalizing = True)
  300.             buffer += ' %s="%s"' % (attr, value)
  301.         
  302.         buffer += childBuffer
  303.         if self.nodeName in ('p', 'br ', 'li', 'ul', 'ol', 'h1', 'h2', 'h3', 'h4'):
  304.             buffer += '\n'
  305.         
  306.         return buffer
  307.  
  308.  
  309.  
  310. class TextNode:
  311.     type = 'text'
  312.     attrRegExp = re.compile('\\{@([^\\}]*)=([^\\}]*)}')
  313.     
  314.     def __init__(self, text):
  315.         self.value = text
  316.  
  317.     
  318.     def attributeCallback(self, match):
  319.         self.parent.setAttribute(match.group(1), match.group(2))
  320.  
  321.     
  322.     def handleAttributes(self):
  323.         self.value = self.attrRegExp.sub(self.attributeCallback, self.value)
  324.  
  325.     
  326.     def toxml(self):
  327.         text = self.value
  328.         self.parent.setBidi(getBidiType(text))
  329.         if not text.startswith(HTML_PLACEHOLDER_PREFIX):
  330.             if self.parent.nodeName == 'p':
  331.                 text = text.replace('\n', '\n   ')
  332.             elif self.parent.nodeName == 'li' and self.parent.childNodes[0] == self:
  333.                 text = '\n     ' + text.replace('\n', '\n     ')
  334.             
  335.         
  336.         text = self.doc.normalizeEntities(text)
  337.         return text
  338.  
  339.  
  340.  
  341. class EntityReference:
  342.     type = 'entity_ref'
  343.     
  344.     def __init__(self, entity):
  345.         self.entity = entity
  346.  
  347.     
  348.     def handleAttributes(self):
  349.         pass
  350.  
  351.     
  352.     def toxml(self):
  353.         return '&' + self.entity + ';'
  354.  
  355.  
  356.  
  357. class TextPreprocessor:
  358.     
  359.     def run(self, text):
  360.         pass
  361.  
  362.  
  363.  
  364. class Preprocessor:
  365.     
  366.     def run(self, lines):
  367.         pass
  368.  
  369.  
  370.  
  371. class HtmlBlockPreprocessor(TextPreprocessor):
  372.     
  373.     def _get_left_tag(self, block):
  374.         return block[1:].replace('>', ' ', 1).split()[0].lower()
  375.  
  376.     
  377.     def _get_right_tag(self, left_tag, block):
  378.         return block.rstrip()[-len(left_tag) - 2:-1].lower()
  379.  
  380.     
  381.     def _equal_tags(self, left_tag, right_tag):
  382.         if left_tag == 'div' or left_tag[0] in ('?', '@', '%'):
  383.             return True
  384.         if '/' + left_tag == right_tag:
  385.             return True
  386.         if right_tag == '--' and left_tag == '--':
  387.             return True
  388.         if left_tag == right_tag[1:] and right_tag[0] != '<':
  389.             return True
  390.         return False
  391.  
  392.     
  393.     def _is_oneliner(self, tag):
  394.         return tag in ('hr', 'hr/')
  395.  
  396.     
  397.     def run(self, text):
  398.         new_blocks = []
  399.         text = text.split('\n\n')
  400.         items = []
  401.         left_tag = ''
  402.         right_tag = ''
  403.         in_tag = False
  404.         for block in text:
  405.             if block.startswith('\n'):
  406.                 block = block[1:]
  407.             
  408.             if not in_tag:
  409.                 if block.startswith('<'):
  410.                     left_tag = self._get_left_tag(block)
  411.                     right_tag = self._get_right_tag(left_tag, block)
  412.                     if not isBlockLevel(left_tag) or block[1] in ('!', '?', '@', '%'):
  413.                         new_blocks.append(block)
  414.                         continue
  415.                     
  416.                     if self._is_oneliner(left_tag):
  417.                         new_blocks.append(block.strip())
  418.                         continue
  419.                     
  420.                     if block[1] == '!':
  421.                         left_tag = '--'
  422.                         right_tag = self._get_right_tag(left_tag, block)
  423.                     
  424.                     if block.rstrip().endswith('>') and self._equal_tags(left_tag, right_tag):
  425.                         new_blocks.append(self.stash.store(block.strip()))
  426.                         continue
  427.                     else:
  428.                         items.append(block.strip())
  429.                         in_tag = True
  430.                 
  431.                 new_blocks.append(block)
  432.                 continue
  433.             items.append(block.strip())
  434.             right_tag = self._get_right_tag(left_tag, block)
  435.             if self._equal_tags(left_tag, right_tag):
  436.                 in_tag = False
  437.                 new_blocks.append(self.stash.store('\n\n'.join(items)))
  438.                 items = []
  439.                 continue
  440.         
  441.         if items:
  442.             new_blocks.append(self.stash.store('\n\n'.join(items)))
  443.             new_blocks.append('\n')
  444.         
  445.         return '\n\n'.join(new_blocks)
  446.  
  447.  
  448. HTML_BLOCK_PREPROCESSOR = HtmlBlockPreprocessor()
  449.  
  450. class HeaderPreprocessor(Preprocessor):
  451.     
  452.     def run(self, lines):
  453.         i = -1
  454.         while i + 1 < len(lines):
  455.             i = i + 1
  456.             if not lines[i].strip():
  457.                 continue
  458.             
  459.             if lines[i].startswith('#'):
  460.                 lines.insert(i + 1, '\n')
  461.             
  462.             if i + 1 <= len(lines) and lines[i + 1] and lines[i + 1][0] in ('-', '='):
  463.                 underline = lines[i + 1].strip()
  464.                 if underline == '=' * len(underline):
  465.                     lines[i] = '# ' + lines[i].strip()
  466.                     lines[i + 1] = ''
  467.                 elif underline == '-' * len(underline):
  468.                     lines[i] = '## ' + lines[i].strip()
  469.                     lines[i + 1] = ''
  470.                 
  471.             underline == '=' * len(underline)
  472.         return lines
  473.  
  474.  
  475. HEADER_PREPROCESSOR = HeaderPreprocessor()
  476.  
  477. class LinePreprocessor(Preprocessor):
  478.     blockquote_re = re.compile('^(> )+')
  479.     
  480.     def run(self, lines):
  481.         for i in range(len(lines)):
  482.             prefix = ''
  483.             m = self.blockquote_re.search(lines[i])
  484.             if m:
  485.                 prefix = m.group(0)
  486.             
  487.             if self._isLine(lines[i][len(prefix):]):
  488.                 lines[i] = prefix + self.stash.store('<hr />', safe = True)
  489.                 continue
  490.         
  491.         return lines
  492.  
  493.     
  494.     def _isLine(self, block):
  495.         if block.startswith('    '):
  496.             return 0
  497.         text = [](_[1])
  498.         if len(text) <= 2:
  499.             return 0
  500.         for pattern in [
  501.             'isline1',
  502.             'isline2',
  503.             'isline3']:
  504.             m = RE.regExp[pattern].match(text)
  505.             if m and m.group(1):
  506.                 return 1
  507.         else:
  508.             return 0
  509.         return m.group(1)
  510.  
  511.  
  512. LINE_PREPROCESSOR = LinePreprocessor()
  513.  
  514. class ReferencePreprocessor(Preprocessor):
  515.     
  516.     def run(self, lines):
  517.         new_text = []
  518.         for line in lines:
  519.             m = RE.regExp['reference-def'].match(line)
  520.             if m:
  521.                 id = m.group(2).strip().lower()
  522.                 t = m.group(4).strip()
  523.                 if not t:
  524.                     self.references[id] = (m.group(3), t)
  525.                 elif len(t) >= 2:
  526.                     if t[-1] == t[-1]:
  527.                         pass
  528.                     elif not t[-1] == '"':
  529.                         if t[-1] == t[-1]:
  530.                             pass
  531.                         elif (t[-1] == "'" or t[0] == '(') and t[-1] == ')':
  532.                             self.references[id] = (m.group(3), t[1:-1])
  533.                         else:
  534.                             new_text.append(line)
  535.                         t[-1] == ')'
  536.                         new_text.append(line)
  537.                     return new_text
  538.  
  539.  
  540. REFERENCE_PREPROCESSOR = ReferencePreprocessor()
  541. NOBRACKET = '[^\\]\\[]*'
  542. BRK = '\\[(' + (NOBRACKET + '(\\[') * 6 + (NOBRACKET + '\\])*') * 6 + NOBRACKET + ')\\]'
  543. NOIMG = '(?<!\\!)'
  544. BACKTICK_RE = '\\`([^\\`]*)\\`'
  545. DOUBLE_BACKTICK_RE = '\\`\\`(.*)\\`\\`'
  546. ESCAPE_RE = '\\\\(.)'
  547. EMPHASIS_RE = '\\*([^\\*]*)\\*'
  548. STRONG_RE = '\\*\\*(.*)\\*\\*'
  549. STRONG_EM_RE = '\\*\\*\\*([^_]*)\\*\\*\\*'
  550. if SMART_EMPHASIS:
  551.     EMPHASIS_2_RE = '(?<!\\S)_(\\S[^_]*)_'
  552. else:
  553.     EMPHASIS_2_RE = '_([^_]*)_'
  554. STRONG_2_RE = '__([^_]*)__'
  555. STRONG_EM_2_RE = '___([^_]*)___'
  556. LINK_RE = NOIMG + BRK + '\\s*\\(([^\\)]*)\\)'
  557. LINK_ANGLED_RE = NOIMG + BRK + '\\s*\\(<([^\\)]*)>\\)'
  558. IMAGE_LINK_RE = '\\!' + BRK + '\\s*\\(([^\\)]*)\\)'
  559. REFERENCE_RE = NOIMG + BRK + '\\s*\\[([^\\]]*)\\]'
  560. IMAGE_REFERENCE_RE = '\\!' + BRK + '\\s*\\[([^\\]]*)\\]'
  561. NOT_STRONG_RE = '( \\* )'
  562. AUTOLINK_RE = '<(http://[^>]*)>'
  563. AUTOMAIL_RE = '<([^> \\!]*@[^> ]*)>'
  564. HTML_RE = '(\\<[a-zA-Z/][^\\>]*\\>)'
  565. ENTITY_RE = '(&[\\#a-zA-Z0-9]*;)'
  566. LINE_BREAK_RE = '  \\n'
  567. LINE_BREAK_2_RE = '  $'
  568.  
  569. class Pattern:
  570.     
  571.     def __init__(self, pattern):
  572.         self.pattern = pattern
  573.         self.compiled_re = re.compile('^(.*)%s(.*)$' % pattern, re.DOTALL)
  574.  
  575.     
  576.     def getCompiledRegExp(self):
  577.         return self.compiled_re
  578.  
  579.  
  580. BasePattern = Pattern
  581.  
  582. class SimpleTextPattern(Pattern):
  583.     
  584.     def handleMatch(self, m, doc):
  585.         return doc.createTextNode(m.group(2))
  586.  
  587.  
  588.  
  589. class SimpleTagPattern(Pattern):
  590.     
  591.     def __init__(self, pattern, tag):
  592.         Pattern.__init__(self, pattern)
  593.         self.tag = tag
  594.  
  595.     
  596.     def handleMatch(self, m, doc):
  597.         el = doc.createElement(self.tag)
  598.         el.appendChild(doc.createTextNode(m.group(2)))
  599.         return el
  600.  
  601.  
  602.  
  603. class SubstituteTagPattern(SimpleTagPattern):
  604.     
  605.     def handleMatch(self, m, doc):
  606.         return doc.createElement(self.tag)
  607.  
  608.  
  609.  
  610. class BacktickPattern(Pattern):
  611.     
  612.     def __init__(self, pattern):
  613.         Pattern.__init__(self, pattern)
  614.         self.tag = 'code'
  615.  
  616.     
  617.     def handleMatch(self, m, doc):
  618.         el = doc.createElement(self.tag)
  619.         text = m.group(2).strip()
  620.         el.appendChild(doc.createTextNode(text))
  621.         return el
  622.  
  623.  
  624.  
  625. class DoubleTagPattern(SimpleTagPattern):
  626.     
  627.     def handleMatch(self, m, doc):
  628.         (tag1, tag2) = self.tag.split(',')
  629.         el1 = doc.createElement(tag1)
  630.         el2 = doc.createElement(tag2)
  631.         el1.appendChild(el2)
  632.         el2.appendChild(doc.createTextNode(m.group(2)))
  633.         return el1
  634.  
  635.  
  636.  
  637. class HtmlPattern(Pattern):
  638.     
  639.     def handleMatch(self, m, doc):
  640.         rawhtml = m.group(2)
  641.         inline = True
  642.         place_holder = self.stash.store(rawhtml)
  643.         return doc.createTextNode(place_holder)
  644.  
  645.  
  646.  
  647. class LinkPattern(Pattern):
  648.     
  649.     def handleMatch(self, m, doc):
  650.         el = doc.createElement('a')
  651.         el.appendChild(doc.createTextNode(m.group(2)))
  652.         parts = m.group(9).split('"')
  653.         if parts:
  654.             el.setAttribute('href', parts[0].strip())
  655.         else:
  656.             el.setAttribute('href', '')
  657.         if len(parts) > 1:
  658.             title = '"' + '"'.join(parts[1:]).strip()
  659.             title = dequote(title)
  660.             el.setAttribute('title', title)
  661.         
  662.         return el
  663.  
  664.  
  665.  
  666. class ImagePattern(Pattern):
  667.     
  668.     def handleMatch(self, m, doc):
  669.         el = doc.createElement('img')
  670.         src_parts = m.group(9).split()
  671.         if src_parts:
  672.             el.setAttribute('src', src_parts[0])
  673.         else:
  674.             el.setAttribute('src', '')
  675.         if len(src_parts) > 1:
  676.             el.setAttribute('title', dequote(' '.join(src_parts[1:])))
  677.         
  678.         if ENABLE_ATTRIBUTES:
  679.             text = doc.createTextNode(m.group(2))
  680.             el.appendChild(text)
  681.             text.handleAttributes()
  682.             truealt = text.value
  683.             el.childNodes.remove(text)
  684.         else:
  685.             truealt = m.group(2)
  686.         el.setAttribute('alt', truealt)
  687.         return el
  688.  
  689.  
  690.  
  691. class ReferencePattern(Pattern):
  692.     
  693.     def handleMatch(self, m, doc):
  694.         if m.group(9):
  695.             id = m.group(9).lower()
  696.         else:
  697.             id = m.group(2).lower()
  698.         if not self.references.has_key(id):
  699.             return None
  700.         (href, title) = self.references[id]
  701.         text = m.group(2)
  702.         return self.makeTag(href, title, text, doc)
  703.  
  704.     
  705.     def makeTag(self, href, title, text, doc):
  706.         el = doc.createElement('a')
  707.         el.setAttribute('href', href)
  708.         if title:
  709.             el.setAttribute('title', title)
  710.         
  711.         el.appendChild(doc.createTextNode(text))
  712.         return el
  713.  
  714.  
  715.  
  716. class ImageReferencePattern(ReferencePattern):
  717.     
  718.     def makeTag(self, href, title, text, doc):
  719.         el = doc.createElement('img')
  720.         el.setAttribute('src', href)
  721.         if title:
  722.             el.setAttribute('title', title)
  723.         
  724.         el.setAttribute('alt', text)
  725.         return el
  726.  
  727.  
  728.  
  729. class AutolinkPattern(Pattern):
  730.     
  731.     def handleMatch(self, m, doc):
  732.         el = doc.createElement('a')
  733.         el.setAttribute('href', m.group(2))
  734.         el.appendChild(doc.createTextNode(m.group(2)))
  735.         return el
  736.  
  737.  
  738.  
  739. class AutomailPattern(Pattern):
  740.     
  741.     def handleMatch(self, m, doc):
  742.         el = doc.createElement('a')
  743.         email = m.group(2)
  744.         if email.startswith('mailto:'):
  745.             email = email[len('mailto:'):]
  746.         
  747.         for letter in email:
  748.             entity = doc.createEntityReference('#%d' % ord(letter))
  749.             el.appendChild(entity)
  750.         
  751.         mailto = 'mailto:' + email
  752.         mailto = []([ '&#%d;' % ord(letter) for letter in mailto ])
  753.         el.setAttribute('href', mailto)
  754.         return el
  755.  
  756.  
  757. ESCAPE_PATTERN = SimpleTextPattern(ESCAPE_RE)
  758. NOT_STRONG_PATTERN = SimpleTextPattern(NOT_STRONG_RE)
  759. BACKTICK_PATTERN = BacktickPattern(BACKTICK_RE)
  760. DOUBLE_BACKTICK_PATTERN = BacktickPattern(DOUBLE_BACKTICK_RE)
  761. STRONG_PATTERN = SimpleTagPattern(STRONG_RE, 'strong')
  762. STRONG_PATTERN_2 = SimpleTagPattern(STRONG_2_RE, 'strong')
  763. EMPHASIS_PATTERN = SimpleTagPattern(EMPHASIS_RE, 'em')
  764. EMPHASIS_PATTERN_2 = SimpleTagPattern(EMPHASIS_2_RE, 'em')
  765. STRONG_EM_PATTERN = DoubleTagPattern(STRONG_EM_RE, 'strong,em')
  766. STRONG_EM_PATTERN_2 = DoubleTagPattern(STRONG_EM_2_RE, 'strong,em')
  767. LINE_BREAK_PATTERN = SubstituteTagPattern(LINE_BREAK_RE, 'br ')
  768. LINE_BREAK_PATTERN_2 = SubstituteTagPattern(LINE_BREAK_2_RE, 'br ')
  769. LINK_PATTERN = LinkPattern(LINK_RE)
  770. LINK_ANGLED_PATTERN = LinkPattern(LINK_ANGLED_RE)
  771. IMAGE_LINK_PATTERN = ImagePattern(IMAGE_LINK_RE)
  772. IMAGE_REFERENCE_PATTERN = ImageReferencePattern(IMAGE_REFERENCE_RE)
  773. REFERENCE_PATTERN = ReferencePattern(REFERENCE_RE)
  774. HTML_PATTERN = HtmlPattern(HTML_RE)
  775. ENTITY_PATTERN = HtmlPattern(ENTITY_RE)
  776. AUTOLINK_PATTERN = AutolinkPattern(AUTOLINK_RE)
  777. AUTOMAIL_PATTERN = AutomailPattern(AUTOMAIL_RE)
  778.  
  779. class Postprocessor:
  780.     
  781.     def run(self, dom):
  782.         pass
  783.  
  784.  
  785.  
  786. class TextPostprocessor:
  787.     
  788.     def run(self, text):
  789.         pass
  790.  
  791.  
  792.  
  793. class RawHtmlTextPostprocessor(TextPostprocessor):
  794.     
  795.     def __init__(self):
  796.         pass
  797.  
  798.     
  799.     def run(self, text):
  800.         for i in range(self.stash.html_counter):
  801.             (html, safe) = self.stash.rawHtmlBlocks[i]
  802.             if self.safeMode and not safe:
  803.                 if str(self.safeMode).lower() == 'escape':
  804.                     html = self.escape(html)
  805.                 elif str(self.safeMode).lower() == 'remove':
  806.                     html = ''
  807.                 else:
  808.                     html = HTML_REMOVED_TEXT
  809.             
  810.             text = text.replace('<p>%s\n</p>' % HTML_PLACEHOLDER % i, html + '\n')
  811.             text = text.replace(HTML_PLACEHOLDER % i, html)
  812.         
  813.         return text
  814.  
  815.     
  816.     def escape(self, html):
  817.         html = html.replace('&', '&')
  818.         html = html.replace('<', '<')
  819.         html = html.replace('>', '>')
  820.         return html.replace('"', '"')
  821.  
  822.  
  823. RAWHTMLTEXTPOSTPROCESSOR = RawHtmlTextPostprocessor()
  824.  
  825. class HtmlStash:
  826.     
  827.     def __init__(self):
  828.         self.html_counter = 0
  829.         self.rawHtmlBlocks = []
  830.  
  831.     
  832.     def store(self, html, safe = False):
  833.         self.rawHtmlBlocks.append((html, safe))
  834.         placeholder = HTML_PLACEHOLDER % self.html_counter
  835.         self.html_counter += 1
  836.         return placeholder
  837.  
  838.  
  839.  
  840. class BlockGuru:
  841.     
  842.     def _findHead(self, lines, fn, allowBlank = 0):
  843.         items = []
  844.         item = -1
  845.         i = 0
  846.         for line in lines:
  847.             if not line.strip() and not allowBlank:
  848.                 return (items, lines[i:])
  849.             if not line.strip() and allowBlank:
  850.                 i += 1
  851.                 for j in range(i, len(lines)):
  852.                     if lines[j].strip():
  853.                         next = lines[j]
  854.                         break
  855.                         continue
  856.                     not allowBlank
  857.                 else:
  858.                     break
  859.                 part = fn(next)
  860.                 if part:
  861.                     items.append('')
  862.                     continue
  863.                 else:
  864.                     break
  865.             
  866.             part = fn(line)
  867.             if part:
  868.                 items.append(part)
  869.                 i += 1
  870.                 continue
  871.                 continue
  872.             return (items, lines[i:])
  873.         else:
  874.             i += 1
  875.         return (items, lines[i:])
  876.  
  877.     
  878.     def detabbed_fn(self, line):
  879.         m = RE.regExp['tabbed'].match(line)
  880.         if m:
  881.             return m.group(4)
  882.         return None
  883.  
  884.     
  885.     def detectTabbed(self, lines):
  886.         return self._findHead(lines, self.detabbed_fn, allowBlank = 1)
  887.  
  888.  
  889.  
  890. def print_error(string):
  891.     sys.stderr.write(string + '\n')
  892.  
  893.  
  894. def dequote(string):
  895.     if (string.startswith('"') or string.endswith('"') or string.startswith("'")) and string.endswith("'"):
  896.         return string[1:-1]
  897.     return string
  898.  
  899.  
  900. class CorePatterns:
  901.     patterns = {
  902.         'header': '(#*)([^#]*)(#*)',
  903.         'reference-def': '(\\ ?\\ ?\\ ?)\\[([^\\]]*)\\]:\\s*([^ ]*)(.*)',
  904.         'containsline': '([-]*)$|^([=]*)',
  905.         'ol': '[ ]{0,3}[\\d]*\\.\\s+(.*)',
  906.         'ul': '[ ]{0,3}[*+-]\\s+(.*)',
  907.         'isline1': '(\\**)',
  908.         'isline2': '(\\-*)',
  909.         'isline3': '(\\_*)',
  910.         'tabbed': '((\\t)|(    ))(.*)',
  911.         'quoted': '> ?(.*)' }
  912.     
  913.     def __init__(self):
  914.         self.regExp = { }
  915.         for key in self.patterns.keys():
  916.             self.regExp[key] = re.compile('^%s$' % self.patterns[key], re.DOTALL)
  917.         
  918.         self.regExp['containsline'] = re.compile('^([-]*)$|^([=]*)$', re.M)
  919.  
  920.  
  921. RE = CorePatterns()
  922.  
  923. class Markdown:
  924.     
  925.     def __init__(self, source = None, extensions = [], extension_configs = None, safe_mode = False):
  926.         self.source = source
  927.         if source is not None:
  928.             message(WARN, 'The `source` arg of Markdown.__init__() is depreciated and will be removed in the future. Use `instance.convert(source)` instead.')
  929.         
  930.         self.safeMode = safe_mode
  931.         self.blockGuru = BlockGuru()
  932.         self.registeredExtensions = []
  933.         self.stripTopLevelTags = 1
  934.         self.docType = ''
  935.         self.textPreprocessors = [
  936.             HTML_BLOCK_PREPROCESSOR]
  937.         self.preprocessors = [
  938.             HEADER_PREPROCESSOR,
  939.             LINE_PREPROCESSOR,
  940.             REFERENCE_PREPROCESSOR]
  941.         self.postprocessors = []
  942.         self.textPostprocessors = [
  943.             RAWHTMLTEXTPOSTPROCESSOR]
  944.         self.prePatterns = []
  945.         self.inlinePatterns = [
  946.             DOUBLE_BACKTICK_PATTERN,
  947.             BACKTICK_PATTERN,
  948.             ESCAPE_PATTERN,
  949.             REFERENCE_PATTERN,
  950.             LINK_ANGLED_PATTERN,
  951.             LINK_PATTERN,
  952.             IMAGE_LINK_PATTERN,
  953.             IMAGE_REFERENCE_PATTERN,
  954.             AUTOLINK_PATTERN,
  955.             AUTOMAIL_PATTERN,
  956.             LINE_BREAK_PATTERN,
  957.             HTML_PATTERN,
  958.             ENTITY_PATTERN,
  959.             NOT_STRONG_PATTERN,
  960.             STRONG_EM_PATTERN,
  961.             STRONG_EM_PATTERN_2,
  962.             STRONG_PATTERN,
  963.             STRONG_PATTERN_2,
  964.             EMPHASIS_PATTERN,
  965.             EMPHASIS_PATTERN_2]
  966.         self.registerExtensions(extensions = extensions, configs = extension_configs)
  967.         self.reset()
  968.  
  969.     
  970.     def registerExtensions(self, extensions, configs):
  971.         if not configs:
  972.             configs = { }
  973.         
  974.         for ext in extensions:
  975.             extension_module_name = 'calibre.ebooks.markdown.mdx_' + ext
  976.             
  977.             try:
  978.                 module = sys.modules[extension_module_name]
  979.             except:
  980.                 message(CRITICAL, "couldn't load extension %s (looking for %s module)" % (ext, extension_module_name))
  981.                 continue
  982.  
  983.             if configs.has_key(ext):
  984.                 configs_for_ext = configs[ext]
  985.             else:
  986.                 configs_for_ext = []
  987.             extension = module.makeExtension(configs_for_ext)
  988.             extension.extendMarkdown(self, globals())
  989.         
  990.  
  991.     
  992.     def registerExtension(self, extension):
  993.         self.registeredExtensions.append(extension)
  994.  
  995.     
  996.     def reset(self):
  997.         self.references = { }
  998.         self.htmlStash = HtmlStash()
  999.         HTML_BLOCK_PREPROCESSOR.stash = self.htmlStash
  1000.         LINE_PREPROCESSOR.stash = self.htmlStash
  1001.         REFERENCE_PREPROCESSOR.references = self.references
  1002.         HTML_PATTERN.stash = self.htmlStash
  1003.         ENTITY_PATTERN.stash = self.htmlStash
  1004.         REFERENCE_PATTERN.references = self.references
  1005.         IMAGE_REFERENCE_PATTERN.references = self.references
  1006.         RAWHTMLTEXTPOSTPROCESSOR.stash = self.htmlStash
  1007.         RAWHTMLTEXTPOSTPROCESSOR.safeMode = self.safeMode
  1008.         for extension in self.registeredExtensions:
  1009.             extension.reset()
  1010.         
  1011.  
  1012.     
  1013.     def _transform(self):
  1014.         self.doc = Document()
  1015.         self.top_element = self.doc.createElement('span')
  1016.         self.top_element.appendChild(self.doc.createTextNode('\n'))
  1017.         self.top_element.setAttribute('class', 'markdown')
  1018.         self.doc.appendChild(self.top_element)
  1019.         text = self.source
  1020.         text = text.replace('\r\n', '\n').replace('\r', '\n')
  1021.         text += '\n\n'
  1022.         text = text.expandtabs(TAB_LENGTH)
  1023.         self.lines = text.split('\n')
  1024.         for prep in self.preprocessors:
  1025.             self.lines = prep.run(self.lines)
  1026.         
  1027.         buffer = []
  1028.         for line in self.lines:
  1029.             if line.startswith('#'):
  1030.                 self._processSection(self.top_element, buffer)
  1031.                 buffer = [
  1032.                     line]
  1033.                 continue
  1034.             buffer.append(line)
  1035.         
  1036.         self._processSection(self.top_element, buffer)
  1037.         self.top_element.appendChild(self.doc.createTextNode('\n'))
  1038.         for postprocessor in self.postprocessors:
  1039.             postprocessor.run(self.doc)
  1040.         
  1041.         return self.doc
  1042.  
  1043.     
  1044.     def _processSection(self, parent_elem, lines, inList = 0, looseList = 0):
  1045.         while lines:
  1046.             processFn = {
  1047.                 'ul': self._processUList,
  1048.                 'ol': self._processOList,
  1049.                 'quoted': self._processQuote,
  1050.                 'tabbed': self._processCodeBlock }
  1051.             for regexp in [
  1052.                 'ul',
  1053.                 'ol',
  1054.                 'quoted',
  1055.                 'tabbed']:
  1056.                 m = RE.regExp[regexp].match(lines[0])
  1057.                 if m:
  1058.                     processFn[regexp](parent_elem, lines, inList)
  1059.                     return None
  1060.             
  1061.             if inList:
  1062.                 (start, lines) = self._linesUntil(lines, (lambda line: if not RE.regExp['ul'].match(line) and RE.regExp['ol'].match(line):
  1063. passnot line.strip()))
  1064.                 self._processSection(parent_elem, start, inList - 1, looseList = looseList)
  1065.                 inList = inList - 1
  1066.             else:
  1067.                 (paragraph, lines) = self._linesUntil(lines, (lambda line: not line.strip()))
  1068.                 if len(paragraph) and paragraph[0].startswith('#'):
  1069.                     self._processHeader(parent_elem, paragraph)
  1070.                 elif paragraph:
  1071.                     self._processParagraph(parent_elem, paragraph, inList, looseList)
  1072.                 
  1073.             if lines and not lines[0].strip():
  1074.                 lines = lines[1:]
  1075.                 continue
  1076.  
  1077.     
  1078.     def _processHeader(self, parent_elem, paragraph):
  1079.         m = RE.regExp['header'].match(paragraph[0])
  1080.         if m:
  1081.             level = len(m.group(1))
  1082.             h = self.doc.createElement('h%d' % level)
  1083.             parent_elem.appendChild(h)
  1084.             for item in self._handleInline(m.group(2).strip()):
  1085.                 h.appendChild(item)
  1086.             
  1087.         else:
  1088.             message(CRITICAL, "We've got a problem header!")
  1089.  
  1090.     
  1091.     def _processParagraph(self, parent_elem, paragraph, inList, looseList):
  1092.         list = self._handleInline('\n'.join(paragraph))
  1093.         if parent_elem.nodeName == 'li':
  1094.             if not looseList:
  1095.                 pass
  1096.             if not (parent_elem.childNodes):
  1097.                 el = parent_elem
  1098.             else:
  1099.                 el = self.doc.createElement('p')
  1100.                 parent_elem.appendChild(el)
  1101.         for item in list:
  1102.             el.appendChild(item)
  1103.         
  1104.  
  1105.     
  1106.     def _processUList(self, parent_elem, lines, inList):
  1107.         self._processList(parent_elem, lines, inList, listexpr = 'ul', tag = 'ul')
  1108.  
  1109.     
  1110.     def _processOList(self, parent_elem, lines, inList):
  1111.         self._processList(parent_elem, lines, inList, listexpr = 'ol', tag = 'ol')
  1112.  
  1113.     
  1114.     def _processList(self, parent_elem, lines, inList, listexpr, tag):
  1115.         ul = self.doc.createElement(tag)
  1116.         parent_elem.appendChild(ul)
  1117.         looseList = 0
  1118.         items = []
  1119.         item = -1
  1120.         i = 0
  1121.         for line in lines:
  1122.             loose = 0
  1123.             if not line.strip():
  1124.                 i += 1
  1125.                 loose = 1
  1126.                 for j in range(i, len(lines)):
  1127.                     if lines[j].strip():
  1128.                         next = lines[j]
  1129.                         break
  1130.                         continue
  1131.                 else:
  1132.                     break
  1133.                 if RE.regExp['ul'].match(next) and RE.regExp['ol'].match(next) or RE.regExp['tabbed'].match(next):
  1134.                     items[item].append(line.strip())
  1135.                     if not loose:
  1136.                         pass
  1137.                     looseList = looseList
  1138.                     continue
  1139.                 else:
  1140.                     break
  1141.             
  1142.             for expr in [
  1143.                 'ul',
  1144.                 'ol',
  1145.                 'tabbed']:
  1146.                 m = RE.regExp[expr].match(line)
  1147.                 if m:
  1148.                     if expr in ('ul', 'ol'):
  1149.                         items.append([
  1150.                             m.group(1)])
  1151.                         item += 1
  1152.                     elif expr == 'tabbed':
  1153.                         items[item].append(m.group(4))
  1154.                     
  1155.                     i += 1
  1156.                     break
  1157.                     continue
  1158.             else:
  1159.                 i += 1
  1160.         else:
  1161.             i += 1
  1162.         for item in items:
  1163.             li = self.doc.createElement('li')
  1164.             ul.appendChild(li)
  1165.             self._processSection(li, item, inList + 1, looseList = looseList)
  1166.         
  1167.         self._processSection(parent_elem, lines[i:], inList)
  1168.  
  1169.     
  1170.     def _linesUntil(self, lines, condition):
  1171.         i = -1
  1172.         for line in lines:
  1173.             i += 1
  1174.             if condition(line):
  1175.                 break
  1176.                 continue
  1177.         else:
  1178.             i += 1
  1179.         return (lines[:i], lines[i:])
  1180.  
  1181.     
  1182.     def _processQuote(self, parent_elem, lines, inList):
  1183.         dequoted = []
  1184.         i = 0
  1185.         blank_line = False
  1186.         for line in lines:
  1187.             m = RE.regExp['quoted'].match(line)
  1188.             if m:
  1189.                 dequoted.append(m.group(1))
  1190.                 i += 1
  1191.                 blank_line = False
  1192.                 continue
  1193.             if not blank_line and line.strip() != '':
  1194.                 dequoted.append(line)
  1195.                 i += 1
  1196.                 continue
  1197.             if not blank_line and line.strip() == '':
  1198.                 dequoted.append(line)
  1199.                 i += 1
  1200.                 blank_line = True
  1201.                 continue
  1202.         
  1203.         blockquote = self.doc.createElement('blockquote')
  1204.         parent_elem.appendChild(blockquote)
  1205.         self._processSection(blockquote, dequoted, inList)
  1206.         self._processSection(parent_elem, lines[i:], inList)
  1207.  
  1208.     
  1209.     def _processCodeBlock(self, parent_elem, lines, inList):
  1210.         (detabbed, theRest) = self.blockGuru.detectTabbed(lines)
  1211.         pre = self.doc.createElement('pre')
  1212.         code = self.doc.createElement('code')
  1213.         parent_elem.appendChild(pre)
  1214.         pre.appendChild(code)
  1215.         text = '\n'.join(detabbed).rstrip() + '\n'
  1216.         code.appendChild(self.doc.createTextNode(text))
  1217.         self._processSection(parent_elem, theRest, inList)
  1218.  
  1219.     
  1220.     def _handleInline(self, line, patternIndex = 0):
  1221.         parts = [
  1222.             line]
  1223.         while patternIndex < len(self.inlinePatterns):
  1224.             i = 0
  1225.             while i < len(parts):
  1226.                 x = parts[i]
  1227.                 if isinstance(x, (str, unicode)):
  1228.                     result = self._applyPattern(x, self.inlinePatterns[patternIndex], patternIndex)
  1229.                     if result:
  1230.                         i -= 1
  1231.                         parts.remove(x)
  1232.                         for y in result:
  1233.                             parts.insert(i + 1, y)
  1234.                         
  1235.                     
  1236.                 
  1237.                 i += 1
  1238.             patternIndex += 1
  1239.         for i in range(len(parts)):
  1240.             x = parts[i]
  1241.             if isinstance(x, (str, unicode)):
  1242.                 parts[i] = self.doc.createTextNode(x)
  1243.                 continue
  1244.         
  1245.         return parts
  1246.  
  1247.     
  1248.     def _applyPattern(self, line, pattern, patternIndex):
  1249.         m = pattern.getCompiledRegExp().match(line)
  1250.         if not m:
  1251.             return None
  1252.         node = pattern.handleMatch(m, self.doc)
  1253.         if node:
  1254.             return (m.groups()[-1], node, m.group(1))
  1255.         return None
  1256.  
  1257.     
  1258.     def convert(self, source = None):
  1259.         if source is not None:
  1260.             self.source = source
  1261.         
  1262.         if not self.source:
  1263.             return u''
  1264.         
  1265.         try:
  1266.             self.source = unicode(self.source)
  1267.         except UnicodeDecodeError:
  1268.             self.source
  1269.             self.source
  1270.             message(CRITICAL, 'UnicodeDecodeError: Markdown only accepts unicode or ascii  input.')
  1271.             return u''
  1272.  
  1273.         for pp in self.textPreprocessors:
  1274.             self.source = pp.run(self.source)
  1275.         
  1276.         doc = self._transform()
  1277.         xml = doc.toxml()
  1278.         if self.stripTopLevelTags:
  1279.             xml = xml.strip()[23:-7] + '\n'
  1280.         
  1281.         for pp in self.textPostprocessors:
  1282.             xml = pp.run(xml)
  1283.         
  1284.         return (self.docType + xml).strip()
  1285.  
  1286.     
  1287.     def __str__(self):
  1288.         if self.source is None:
  1289.             status = 'in which no source text has been assinged.'
  1290.         else:
  1291.             status = 'which contains %d chars and %d line(s) of source.' % (len(self.source), self.source.count('\n') + 1)
  1292.         return 'An instance of "%s" %s' % (self.__class__, status)
  1293.  
  1294.     __unicode__ = convert
  1295.  
  1296.  
  1297. def markdownFromFile(input = None, output = None, extensions = [], encoding = None, message_threshold = CRITICAL, safe = False):
  1298.     console_hndlr.setLevel(message_threshold)
  1299.     message(DEBUG, 'input file: %s' % input)
  1300.     if not encoding:
  1301.         encoding = 'utf-8'
  1302.     
  1303.     input_file = codecs.open(input, mode = 'r', encoding = encoding)
  1304.     text = input_file.read()
  1305.     input_file.close()
  1306.     text = removeBOM(text, encoding)
  1307.     new_text = markdown(text, extensions, safe_mode = safe)
  1308.     if output:
  1309.         output_file = codecs.open(output, 'w', encoding = encoding)
  1310.         output_file.write(new_text)
  1311.         output_file.close()
  1312.     else:
  1313.         sys.stdout.write(new_text.encode(encoding))
  1314.  
  1315.  
  1316. def markdown(text, extensions = [], safe_mode = False):
  1317.     message(DEBUG, 'in markdown.markdown(), received text:\n%s' % text)
  1318.     extension_names = []
  1319.     extension_configs = { }
  1320.     for ext in extensions:
  1321.         pos = ext.find('(')
  1322.         if pos == -1:
  1323.             extension_names.append(ext)
  1324.             continue
  1325.         name = ext[:pos]
  1326.         extension_names.append(name)
  1327.         pairs = [ x.split('=') for x in ext[pos + 1:-1].split(',') ]
  1328.         configs = [ (x.strip(), y.strip()) for x, y in pairs ]
  1329.         extension_configs[name] = configs
  1330.     
  1331.     md = Markdown(extensions = extension_names, extension_configs = extension_configs, safe_mode = safe_mode)
  1332.     return md.convert(text)
  1333.  
  1334.  
  1335. class Extension:
  1336.     
  1337.     def __init__(self, configs = { }):
  1338.         self.config = configs
  1339.  
  1340.     
  1341.     def getConfig(self, key):
  1342.         if self.config.has_key(key):
  1343.             return self.config[key][0]
  1344.         return ''
  1345.  
  1346.     
  1347.     def getConfigInfo(self):
  1348.         return [ (key, self.config[key][1]) for key in self.config.keys() ]
  1349.  
  1350.     
  1351.     def setConfig(self, key, value):
  1352.         self.config[key][0] = value
  1353.  
  1354.  
  1355. OPTPARSE_WARNING = '\nPython 2.3 or higher required for advanced command line options.\nFor lower versions of Python use:\n\n      %s INPUT_FILE > OUTPUT_FILE\n    \n' % EXECUTABLE_NAME_FOR_USAGE
  1356.  
  1357. def parse_options():
  1358.     
  1359.     try:
  1360.         optparse = __import__('optparse')
  1361.     except:
  1362.         if len(sys.argv) == 2:
  1363.             return {
  1364.                 'input': sys.argv[1],
  1365.                 'output': None,
  1366.                 'message_threshold': CRITICAL,
  1367.                 'safe': False,
  1368.                 'extensions': [],
  1369.                 'encoding': None }
  1370.         print OPTPARSE_WARNING
  1371.         return None
  1372.  
  1373.     parser = optparse.OptionParser(usage = '%prog INPUTFILE [options]')
  1374.     parser.add_option('-f', '--file', dest = 'filename', help = 'write output to OUTPUT_FILE', metavar = 'OUTPUT_FILE')
  1375.     parser.add_option('-e', '--encoding', dest = 'encoding', help = 'encoding for input and output files')
  1376.     parser.add_option('-q', '--quiet', default = CRITICAL, action = 'store_const', const = 60, dest = 'verbose', help = 'suppress all messages')
  1377.     parser.add_option('-v', '--verbose', action = 'store_const', const = INFO, dest = 'verbose', help = 'print info messages')
  1378.     parser.add_option('-s', '--safe', dest = 'safe', default = False, metavar = 'SAFE_MODE', help = "same mode ('replace', 'remove' or 'escape'  user's HTML tag)")
  1379.     parser.add_option('--noisy', action = 'store_const', const = DEBUG, dest = 'verbose', help = 'print debug messages')
  1380.     parser.add_option('-x', '--extension', action = 'append', dest = 'extensions', help = 'load extension EXTENSION', metavar = 'EXTENSION')
  1381.     (options, args) = parser.parse_args()
  1382.     if not len(args) == 1:
  1383.         parser.print_help()
  1384.         return None
  1385.     input_file = args[0]
  1386.     if not options.extensions:
  1387.         options.extensions = []
  1388.     
  1389.     return {
  1390.         'input': input_file,
  1391.         'output': options.filename,
  1392.         'message_threshold': options.verbose,
  1393.         'safe': options.safe,
  1394.         'extensions': options.extensions,
  1395.         'encoding': options.encoding }
  1396.  
  1397.  
  1398. def main():
  1399.     options = parse_options()
  1400.     if not options:
  1401.         sys.exit(0)
  1402.     
  1403.     markdownFromFile(**options)
  1404.  
  1405. if __name__ == '__main__':
  1406.     sys.exit(main())
  1407.  
  1408.