#! /usr/bin/env python

# This software carries the following license:
#
# Modified BSD license
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Steinar Knutsen

"""HTOutl 1.6

Converts plain text outlines to HTML 2.0. ` at the end of a line signifies
forced line break. Links are automatically added to URLs for HTTP and FTP.
(./|../)<path> makes a link with no defined transport layer.
"""

import string, sys, sre

indentsize = 3 # Number of spaces equal to a level of indentation,
   # a tab is always considered a level of indentation

htmlhead = """\
<title></title>
<dl><dt>
"""
linefeed = "<br>\n"
empty_line = "<br>&nbsp;<br>\n"
url_pattern = r"(?<!\S)((http|ftp)://|\.\.?/)[^\s`]+"

class converter:
   def __init__(self, input):
      self.input = input
      self.output = [htmlhead, ""]
      self.tagstack = ["dt"]
   def indent(self, currindent, previndent):
      n = previndent + 1
      while n <= currindent:
         if self.tagstack[-1] == "dd":
            self.output[-1:] = ["<dl><dt>\n", self.output[-1], '<dd>\n', '']
            self.tagstack.extend(["dt","dd"])
         else:
            self.output.extend(["<dd>\n", ''])
            self.tagstack.append("dd")
         n += 1
   def outdent(self, currindent, previndent):
      n = previndent
      while n > currindent:
         x = self.tagstack.pop()
         if x == 'dt':
            self.output.append("</dl>\n")
            self.tagstack.pop()
         n -= 1
      self.output.extend(["<dt>\n", ''])
   def end_doc(self):
      while len(self.tagstack):
         x = self.tagstack.pop()
         if x == "dt":
            self.output.append("</dl>\n")
   def insert_line(self):
      self.output[-1] += empty_line
   def insert_break(self):
      self.output[-1] += linefeed
   def htquote(self, line, replace=string.replace):
      return replace(
            replace(
               replace(line, '&', '&amp;'),
            '<', '&lt;'),
         '>', '&gt;')
   def translate(self, line):
      tmp = sre.search(url_pattern, line)
      line_constr = []
      while tmp:
         reference = tmp.group()
         line_constr.append(self.htquote(line[:tmp.start()]))
         line_constr.append('<a href="%s">%s</a>' %
            (reference, self.htquote(reference)))
         line = line[tmp.end():]
         tmp = sre.search(url_pattern, line)
      line_constr.append(self.htquote(line))
      return string.join(line_constr, '')
   def count_tabs(self, line):
      indent = 0
      spaceindex = 0
      i = 0
      while i < len(line) and line[i] == '\t' or line[i] == ' ':
         if line[i] == '\t':
            indent += 1
         else:
            spaceindex += 1
            if spaceindex == indentsize:
               indent += 1
               spaceindex = 0
         i += 1
      return indent
   def add_line_cooked(self, line):
      if line[-2] == '`':
         line = line[:-2]+"\n"
         self.output[-1] += line
         self.insert_break()
      else:
         self.output[-1] += line
   def close(self, strip = string.strip):
      currindentlvl, previndentlvl = 0, 0
      for line in self.input:
         if len(strip(line)) == 0:
            self.insert_line()
            continue
         previndentlvl = currindentlvl
         currindentlvl = self.count_tabs(line)
         line = self.translate(line)
         if currindentlvl > previndentlvl:
            self.indent(currindentlvl, previndentlvl)
         elif currindentlvl < previndentlvl:
            self.outdent(currindentlvl, previndentlvl)
         self.add_line_cooked(line)
      self.end_doc()
      return string.join(self.output, '')

if __name__ == "__main__":
   filter = converter(sys.stdin.readlines())
   sys.stdout.write(filter.close())
