texdown

changeset 25:fb623913bfb4 tip

Moved lost of localmacros into texdown2latex and the rest into macros. The only stuff in localmacros now is stuff that is really report-specific, i.e. Apkudo-testing-report stuff for Apkudo testing reports.
author Nicholas FitzRoy-Dale (on multihonk2) <nicholas@fitzroydale.org>
date Mon, 28 Nov 2011 18:01:53 +0000
parents 6b09b796daaa
children
files localmacros.py macros.py texdown2latex.py
diffstat 3 files changed, 439 insertions(+), 362 deletions(-) [+]
line diff
     1.1 --- a/localmacros.py	Wed Feb 09 17:59:54 2011 +0000
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,346 +0,0 @@
     1.4 -import re
     1.5 -
     1.6 -AFFILIATIONS = {
     1.7 -	'NICTAUNSWThanks': r"""NICTA\thanks{
     1.8 -      NICTA is funded by the Australian Government as represented by the
     1.9 -      Department of Broadband, Communications and the Digital Economy
    1.10 -      and the Australian Research Council through the ICT Centre of
    1.11 -      Excellence program.
    1.12 -    } and The University of New South Wales\\
    1.13 -    Sydney, Australia""",
    1.14 -	'GEN_AFFIL': r"""Insert Affiliation Here\\
    1.15 -		City, Country""",
    1.16 -}
    1.17 -
    1.18 -SIGPLANPAPER = r"""\documentclass[preprint,natbib,10pt]{sigplanconf}
    1.19 -
    1.20 -\usepackage{graphicx}
    1.21 -\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth}
    1.22 -\usepackage{url}
    1.23 -\usepackage{amsmath}
    1.24 -\usepackage[pdfborder={0 0 0}]{hyperref}
    1.25 -
    1.26 -\makeatletter 
    1.27 -\g@addto@macro\@verbatim\small 
    1.28 -\makeatother 
    1.29 -
    1.30 -\begin{document}
    1.31 -  \conferenceinfo{%(conference0)s}{%(conference1)s}
    1.32 -  \copyrightyear{%(copyrightyear0)s}
    1.33 -  \title{%(title0)s}
    1.34 -
    1.35 -  %(AUTHORS)s
    1.36 -  \maketitle
    1.37 -"""
    1.38 -
    1.39 -TECHREPORT = r"""\documentclass[preprint,natbib,10pt]{article}
    1.40 -
    1.41 -\usepackage{graphicx}
    1.42 -\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth}
    1.43 -\usepackage{url}
    1.44 -\usepackage{amsmath}
    1.45 -\usepackage[pdfborder={0 0 0}]{hyperref}
    1.46 -
    1.47 -\makeatletter 
    1.48 -\g@addto@macro\@verbatim\small 
    1.49 -\makeatother 
    1.50 -
    1.51 -\begin{document}
    1.52 -  \title{%(title0)s}
    1.53 -
    1.54 -  %(AUTHORS)s
    1.55 -  \maketitle
    1.56 -"""
    1.57 -
    1.58 -NICTATR = r"""\documentclass[preprint,natbib,10pt]{article}
    1.59 -
    1.60 -\usepackage{graphicx}
    1.61 -\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth}
    1.62 -\usepackage{url}
    1.63 -\usepackage{amsmath}
    1.64 -\usepackage[pdfborder={0 0 0}]{hyperref}
    1.65 -
    1.66 -\makeatletter 
    1.67 -\g@addto@macro\@verbatim\small 
    1.68 -\makeatother 
    1.69 -
    1.70 -\begin{document}
    1.71 -  \title{%(title0)s}
    1.72 -
    1.73 -	%(AUTHORS)s
    1.74 -  \maketitle
    1.75 -"""
    1.76 -
    1.77 -END_DOCUMENT=r"""
    1.78 -	\bibliographystyle{plainnat}
    1.79 -	\bibliography{papers}
    1.80 -	\end{document}
    1.81 -"""
    1.82 -
    1.83 -END_DOCUMENT_PLAIN=r"""
    1.84 -	\bibliographystyle{plain}
    1.85 -	\bibliography{papers}
    1.86 -	\end{document}
    1.87 -"""
    1.88 -
    1.89 -END_DOCUMENT_NIL = ''
    1.90 -
    1.91 -
    1.92 -def separate_tabs(line):
    1.93 -	return re.split(r'\t+', line)
    1.94 -
    1.95 -def make_author(name, email, affiliation):
    1.96 -	all_info = [name]
    1.97 -	if email:
    1.98 -		all_info.append(r"\\" + "\n\t\t%s" % (email))
    1.99 -	if affiliation:
   1.100 -		all_info.append(r"\\" + "\n\t\t%s" % (affiliation))
   1.101 -	return r"	\authorinfo{%s}" % (''.join(all_info))+ "\n" 
   1.102 -
   1.103 -def make_author_plain(name, email, affiliation):
   1.104 -	all_info = [name]
   1.105 -	if email:
   1.106 -		all_info.append(r"\\" + "\n\t\t%s" % (email))
   1.107 -	if affiliation:
   1.108 -		all_info.append(r"\\" + "\n\t\t%s" % (affiliation))
   1.109 -	return r"	\author{%s}" % (''.join(all_info))+ "\n" 
   1.110 -
   1.111 -class Macros(object):
   1.112 -	def __init__(self, convert_cmd = None):
   1.113 -		self.end_document = END_DOCUMENT_NIL
   1.114 -		self.convert_cmd = convert_cmd
   1.115 -		self.page_width_mm = 210 - 89 # subtract margins
   1.116 -
   1.117 -	def macro_sigplanpaper(self, block_lines):
   1.118 -		self.end_document = END_DOCUMENT_PLAIN
   1.119 -		self.author = make_author
   1.120 -		return SIGPLANPAPER % self.anypaper(block_lines)
   1.121 -
   1.122 -	def macro_techreport(self, block_lines):
   1.123 -		self.end_document = END_DOCUMENT_PLAIN
   1.124 -		self.author = make_author_plain
   1.125 -		return TECHREPORT % self.anypaper(block_lines)
   1.126 -
   1.127 -	def macro_nictatr(self, block_lines):
   1.128 -		self.end_document = END_DOCUMENT_PLAIN
   1.129 -		self.author = make_author_plain
   1.130 -		return NICTATR % self.anypaper(block_lines)
   1.131 -	
   1.132 -	def anypaper(self, block_lines):
   1.133 -		info = {'AUTHORS': '?authors',
   1.134 -			'conference': ('?conf', '?conf'), 
   1.135 -			'copyrightyear': '?year',
   1.136 -			'title': '?title'}
   1.137 -
   1.138 -		authors = []
   1.139 -
   1.140 -		for line in block_lines:
   1.141 -			line = separate_tabs(line)
   1.142 -			key = line.pop(0)
   1.143 -
   1.144 -			if key == 'author':
   1.145 -				author_name = line[0]
   1.146 -				if len(line) >= 2:
   1.147 -					author_email = line[1]
   1.148 -				else:
   1.149 -					author_email = None
   1.150 -				if len(line) >= 3:
   1.151 -					if line[2].startswith('"'):
   1.152 -						# Directly-written affiliation
   1.153 -						assert line[2].endswith('"')
   1.154 -						author_affil = line[2][1:-1]
   1.155 -					else:
   1.156 -						author_affil = AFFILIATIONS[line[2]]
   1.157 -				else:
   1.158 -					author_affil = None
   1.159 -				authors.append(self.author(author_name, author_email, author_affil))
   1.160 -			else:
   1.161 -				for idx in range(len(line)):
   1.162 -					info[key + str(idx)] = line[idx]
   1.163 -
   1.164 -		if authors:
   1.165 -			info['AUTHORS'] = '\n'.join(authors)
   1.166 -		return info
   1.167 -	
   1.168 -	def fancy_table(self, block_lines, check_for_sizes = False,
   1.169 -				make_float = True):
   1.170 -		"""
   1.171 -		Produces a table containing data. Numbers must be tab separated. EG:
   1.172 -			X	Y	!!numericresults
   1.173 -			37	1
   1.174 -			38	2
   1.175 -		"""
   1.176 -
   1.177 -		if block_lines[-1].startswith('~~'):
   1.178 -			caption = block_lines.pop()
   1.179 -		else:
   1.180 -			caption = None
   1.181 -		result = []
   1.182 -		if make_float:
   1.183 -			result.append('\\begin{table}\n')
   1.184 -
   1.185 -		block_lines = [separate_tabs(line) for line in block_lines]
   1.186 -		cols = len(block_lines[0])
   1.187 -
   1.188 -		latex_sizes = ['l'] * cols # The default
   1.189 -
   1.190 -		if check_for_sizes:
   1.191 -			# The first row may contain size information of the form !\d+%. If
   1.192 -			# it does, use 'p' rather than 'l' to lay out the table, and base
   1.193 -			# the overall size on the known page width.
   1.194 -			all_sizes_percent = [-1] * cols
   1.195 -			found_one = False
   1.196 -			for col_num, element in enumerate(block_lines[0]):
   1.197 -				matcher = re.match(r'.*!([0-9]+)%$', element)
   1.198 -				if matcher:
   1.199 -					found_one = True
   1.200 -					all_sizes_percent[col_num] = int(matcher.group(1))
   1.201 -					block_lines[0][col_num] = element[:element.rfind('!')]
   1.202 -
   1.203 -			if found_one:
   1.204 -				# Assign any missing numbers
   1.205 -				perc_left = 100
   1.206 -				for col_num in range(cols):
   1.207 -					if all_sizes_percent[col_num] == -1:
   1.208 -						all_sizes_percent[col_num] = perc_left
   1.209 -					else:
   1.210 -						perc_left -= all_sizes_percent[col_num]
   1.211 -
   1.212 -				# Convert to mm
   1.213 -				all_sizes_mm = [(self.page_width_mm * col_size) / 100 \
   1.214 -						for col_size \
   1.215 -						in all_sizes_percent]
   1.216 -				latex_sizes = ['p{%dmm}' % (size_mm) for size_mm in all_sizes_mm]
   1.217 -
   1.218 -		# Check for magical alignment of columns.
   1.219 -		# Left-alignment (the default): cells neither start nor end with a space.
   1.220 -		# Right-alignment: At least one cell starts with a space; no cell ends with one.
   1.221 -		# Centered alignment: At least one cell both starts and ends with a space.
   1.222 -		# at least one entry with a space.
   1.223 -		for col_num in range(cols):
   1.224 -			align = latex_sizes[col_num]
   1.225 -			if len(align) == 1 and align in 'lcr':
   1.226 -				for line in block_lines:
   1.227 -					cell = line[col_num]
   1.228 -					if cell.startswith(' ') and align == 'l':
   1.229 -						align = 'r'
   1.230 -					if cell.endswith(' '):
   1.231 -						align = 'c'
   1.232 -				latex_sizes[col_num] = align
   1.233 -
   1.234 -		latex_sizecmd = ''.join(latex_sizes)
   1.235 -		result.append('	\\begin{tabular}{%s}\n' % latex_sizecmd)
   1.236 -
   1.237 -		count = 0
   1.238 -		for line in block_lines:
   1.239 -			elements = [self.convert_cmd(element) for element in line]
   1.240 -			result.append('\t' + ' & '.join(elements) + r'\\' + '\n')
   1.241 -			count += 1
   1.242 -
   1.243 -		result.append('	\\end{tabular}\n')
   1.244 -		if caption:
   1.245 -			result.append(caption)
   1.246 -		if make_float:
   1.247 -			result.append('\\end{table}\n')
   1.248 -		return ''.join(result)
   1.249 -
   1.250 -	def macro_numericresults(self, block_lines):
   1.251 -		return self.fancy_table(block_lines)
   1.252 -	
   1.253 -	def macro_floatgraphic(self, args):
   1.254 -		"""
   1.255 -		Includes a graphic, places it in a figure, and gives it a label. Usage:
   1.256 -		!!floatgraphic filename, Caption goes here
   1.257 -		"""
   1.258 -		if ',' in args:
   1.259 -			filename, caption = args.split(',', 1)
   1.260 -			caption = caption.strip()
   1.261 -		else:
   1.262 -			filename = args
   1.263 -			caption = None
   1.264 -
   1.265 -		label = filename
   1.266 -		if '/' in label:
   1.267 -			label = label.split('/')[-1]
   1.268 -		if '#' in label:
   1.269 -			filename = filename.split('#')[0]
   1.270 -			label = label.replace('#', '.')
   1.271 -		label = label.replace('-', '.')
   1.272 -
   1.273 -		result = [
   1.274 -			'\\begin{figure}[htb]',
   1.275 -			'	\\begin{center}',
   1.276 -			'		\\includegraphics{figures/%s}' % (filename),
   1.277 -			'	\\end{center}',
   1.278 -			'	\\caption{\\label{figure.%s}%s}' % (label, caption),
   1.279 -			'\\end{figure}',
   1.280 -		]
   1.281 -
   1.282 -		return '\n'.join(result)
   1.283 -
   1.284 -	def macro_floatgraphic_wholepage(self, args):
   1.285 -		result = [self.macro_floatgraphic(args),
   1.286 -				'\\afterpage{\\clearpage}']
   1.287 -		return '\n'.join(result)
   1.288 -	
   1.289 -
   1.290 -	def macro_absolutegraphic(self, args):
   1.291 -		"""
   1.292 -		Includes an absolutely-positioned graphic without label.
   1.293 -		"""
   1.294 -		filename, left, top, height= \
   1.295 -			[arg.strip() for arg in args.split(',')]
   1.296 -		result = [
   1.297 -			r'\begin{picture}(0.0, 0.0)',
   1.298 -			r'	\put(%s,%s) {' % (left, top),
   1.299 -			r'		\includegraphics[height=%s]{figures/%s}' % (height, filename),
   1.300 -			r'	}',
   1.301 -			r'\end{picture}',
   1.302 -		]
   1.303 -		return '\n'.join(result)
   1.304 -	
   1.305 -	def macro_floatcode(self, block_lines, placement_spec = None):
   1.306 -		"""
   1.307 -		Code inside a figure. If the final line is a caption, does the right
   1.308 -		thing. Usage:
   1.309 -			code line 1	!!floatcode
   1.310 -			final code line
   1.311 -			~~ <<label.if.wanted>> Caption if wanted ~~
   1.312 -		"""
   1.313 -		if placement_spec is None:
   1.314 -			placement_spec = 'htb'
   1.315 -
   1.316 -		caption = None
   1.317 -		if block_lines[-1].startswith('~~'):
   1.318 -			caption = block_lines.pop()
   1.319 -		block_lines = [line.replace('\t', '  ') for line in block_lines]
   1.320 -		result = ['\\begin{figure}[%s]' % (placement_spec)]
   1.321 -		result.append('\\begin{verbatim}')
   1.322 -		result.extend(block_lines)
   1.323 -		result.append('\\end{verbatim}')
   1.324 -		if caption:
   1.325 -			result.append(caption)
   1.326 -		result.append('\\end{figure}')
   1.327 -		return '\n'.join(result)
   1.328 -	
   1.329 -	def macro_exactfloatcode(self, block_lines):
   1.330 -		return self.macro_floatcode(block_lines, 'h!')
   1.331 -	
   1.332 -	def macro_floattable(self, block_lines):
   1.333 -		return self.fancy_table(block_lines, check_for_sizes = True)
   1.334 -	
   1.335 -	def macro_inlinetable(self, block_lines):
   1.336 -		return self.fancy_table(block_lines, check_for_sizes = True, make_float = False)
   1.337 -	
   1.338 -	def macro_blockquote(self, block_lines):
   1.339 -		# Special-case attribution line.
   1.340 -		if block_lines[-1].startswith('--'):
   1.341 -			block_lines[-1] = r'\begin{flushright} --' +\
   1.342 -				self.convert_cmd(block_lines[-1][2:]) +\
   1.343 -				r'\end{flushright}'
   1.344 -		result = [r'\begin{quote}'] + block_lines + [r'\end{quote}']
   1.345 -		return '\n'.join(result) + '\n'
   1.346 -
   1.347 -	def macro_end_document(self, args):
   1.348 -		return self.end_document
   1.349 -
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/macros.py	Mon Nov 28 18:01:53 2011 +0000
     2.3 @@ -0,0 +1,116 @@
     2.4 +
     2.5 +AFFILIATIONS = {
     2.6 +	'NICTAUNSWThanks': r"""NICTA\thanks{
     2.7 +      NICTA is funded by the Australian Government as represented by the
     2.8 +      Department of Broadband, Communications and the Digital Economy
     2.9 +      and the Australian Research Council through the ICT Centre of
    2.10 +      Excellence program.
    2.11 +    } and The University of New South Wales\\
    2.12 +    Sydney, Australia""",
    2.13 +	'GEN_AFFIL': r"""Insert Affiliation Here\\
    2.14 +		City, Country""",
    2.15 +}
    2.16 +
    2.17 +SIGPLANPAPER = r"""\documentclass[preprint,natbib,10pt]{sigplanconf}
    2.18 +
    2.19 +\usepackage{graphicx}
    2.20 +\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth}
    2.21 +\usepackage{url}
    2.22 +\usepackage{amsmath}
    2.23 +\usepackage[pdfborder={0 0 0}]{hyperref}
    2.24 +
    2.25 +\makeatletter 
    2.26 +\g@addto@macro\@verbatim\small 
    2.27 +\makeatother 
    2.28 +
    2.29 +\begin{document}
    2.30 +  \conferenceinfo{%(conference0)s}{%(conference1)s}
    2.31 +  \copyrightyear{%(copyrightyear0)s}
    2.32 +  \title{%(title0)s}
    2.33 +
    2.34 +  %(AUTHORS)s
    2.35 +  \maketitle
    2.36 +"""
    2.37 +
    2.38 +TECHREPORT = r"""\documentclass[preprint,natbib,10pt]{article}
    2.39 +
    2.40 +\usepackage{graphicx}
    2.41 +\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth}
    2.42 +\usepackage{url}
    2.43 +\usepackage{amsmath}
    2.44 +\usepackage[pdfborder={0 0 0}]{hyperref}
    2.45 +\usepackage{caption}
    2.46 +
    2.47 +\makeatletter 
    2.48 +\g@addto@macro\@verbatim\small 
    2.49 +\makeatother 
    2.50 +
    2.51 +\begin{document}
    2.52 +  \title{%(title0)s}
    2.53 +
    2.54 +  %(AUTHORS)s
    2.55 +  \maketitle
    2.56 +"""
    2.57 +
    2.58 +NICTATR = r"""\documentclass[preprint,natbib,10pt]{article}
    2.59 +
    2.60 +\usepackage{graphicx}
    2.61 +\setkeys{Gin}{keepaspectratio=true,clip=true,draft=false,width=\linewidth}
    2.62 +\usepackage{url}
    2.63 +\usepackage{amsmath}
    2.64 +\usepackage[pdfborder={0 0 0}]{hyperref}
    2.65 +
    2.66 +\makeatletter 
    2.67 +\g@addto@macro\@verbatim\small 
    2.68 +\makeatother 
    2.69 +
    2.70 +\begin{document}
    2.71 +  \title{%(title0)s}
    2.72 +
    2.73 +	%(AUTHORS)s
    2.74 +  \maketitle
    2.75 +"""
    2.76 +
    2.77 +END_DOCUMENT=r"""
    2.78 +	\bibliographystyle{plainnat}
    2.79 +	\bibliography{papers}
    2.80 +	\end{document}
    2.81 +"""
    2.82 +
    2.83 +END_DOCUMENT_PLAIN=r"""
    2.84 +	\bibliographystyle{plain}
    2.85 +	\bibliography{papers}
    2.86 +	\end{document}
    2.87 +"""
    2.88 +
    2.89 +END_DOCUMENT_NIL = ''
    2.90 +
    2.91 +class Macros(object):
    2.92 +	def __init__(self, texdown):
    2.93 +		self.texdown = texdown
    2.94 +		self.end_document = END_DOCUMENT_NIL
    2.95 +
    2.96 +	def macro_sigplanpaper(self, block_lines):
    2.97 +		self.end_document = END_DOCUMENT_PLAIN
    2.98 +		self.author = self.texdown.make_author
    2.99 +		return SIGPLANPAPER % self.texdown.anypaper(block_lines)
   2.100 +
   2.101 +	def macro_techreport(self, block_lines):
   2.102 +		self.end_document = END_DOCUMENT_PLAIN
   2.103 +		self.author = self.texdown.make_author_plain
   2.104 +		return TECHREPORT % self.texdown.anypaper(block_lines)
   2.105 +
   2.106 +	def macro_acceptancetestingreport(self, block_lines):
   2.107 +		self.end_document = END_DOCUMENT_PLAIN
   2.108 +		self.author = self.texdown.make_author_plain
   2.109 +		return ACCEPTANCE_TESTING_REPORT % self.texdown.anypaper(block_lines)
   2.110 +
   2.111 +	def macro_nictatr(self, block_lines):
   2.112 +		self.end_document = END_DOCUMENT_PLAIN
   2.113 +		self.author = self.texdown.make_author_plain
   2.114 +		return NICTATR % self.texdown.anypaper(block_lines)
   2.115 +
   2.116 +	def macro_end_document(self, args):
   2.117 +		return self.end_document
   2.118 +
   2.119 +
     3.1 --- a/texdown2latex.py	Wed Feb 09 17:59:54 2011 +0000
     3.2 +++ b/texdown2latex.py	Mon Nov 28 18:01:53 2011 +0000
     3.3 @@ -20,6 +20,7 @@
     3.4  """
     3.5  import re
     3.6  import sys
     3.7 +import macros as builtinmacros
     3.8  # Attempt to import 'localmacros' from cwd preferentially.
     3.9  sys.path.insert(0, '.')
    3.10  import localmacros
    3.11 @@ -56,19 +57,23 @@
    3.12  	repl	\\chapter*{\1}
    3.13  	incl	label
    3.14  chapter:
    3.15 -	match	^##(.*)##
    3.16 +	match	^## *(.*) *##
    3.17  	repl	\\chapter{\1}
    3.18  	incl	label
    3.19  section:
    3.20 -	match	^==(.*)==
    3.21 +	match	^== *(.*) *==
    3.22  	repl	\\section{\1}
    3.23  	incl	label escape_underscores escape_percents teletype
    3.24 +usenixabstract:
    3.25 +	match	^\^ *(.*) *\^
    3.26 +	repl	\\subsection*{\1}
    3.27 +	incl	label escape_underscores escape_percents teletype
    3.28  subsection:
    3.29 -	match	^=(.*)=
    3.30 +	match	^= *(.*) *=
    3.31  	repl	\\subsection{\1}
    3.32  	incl	label escape_underscores escape_percents teletype
    3.33  subsubsection:
    3.34 -	match	^-(.*)-
    3.35 +	match	^- *(.*) *-
    3.36  	repl	\\subsubsection{\1}
    3.37  	incl	label escape_underscores escape_percents teletype
    3.38  label:
    3.39 @@ -146,7 +151,8 @@
    3.40  		self.macros = {}
    3.41  
    3.42  		self.register_macros(self)
    3.43 -		self.register_macros(localmacros.Macros(self.convert))
    3.44 +		self.register_macros(builtinmacros.Macros(self))
    3.45 +		self.register_macros(localmacros.Macros(self))
    3.46  
    3.47  		self.enum_depth = 0 # Keep track, so we can set the counter in \enumerate
    3.48  
    3.49 @@ -157,13 +163,17 @@
    3.50  			if key.startswith('macro_'):
    3.51  				self.macros[key[6:]] = getattr(obj, key)
    3.52  
    3.53 -	def convert(self, texdown, magic = False):
    3.54 +	def convert(self, texdown, magic = False, fragment = False):
    3.55  		"""
    3.56  		Conversion:
    3.57  			Text is list of (chunk, names of conversions for this chunk),
    3.58  			conceptually. Do a depth-first conversion and join up a
    3.59  			complete text block in reality.
    3.60  		"""
    3.61 +		if fragment:
    3.62 +			# Hack to ensure that ^ and $ don't match anything important.
    3.63 +			texdown = ' ' + texdown + ' '
    3.64 +
    3.65  		texdown = self.do_convert(texdown, CONVERSIONS_ORDER)
    3.66  		#for match, replacement in CONVERSIONS:
    3.67  		#	texdown = self.convert_one(texdown, match, replacement)
    3.68 @@ -173,14 +183,18 @@
    3.69  			texdown += self.macros['end_document'](None)
    3.70  
    3.71  			# Hack: magical abstract conversion.
    3.72 -			abstract_start = texdown.find('\section{ Abstract }')
    3.73 -			if abstract_start != -1:
    3.74 -				abstract_end = texdown.find('\section', abstract_start + 1)
    3.75 -				texdown = texdown[:abstract_start] \
    3.76 -					+ '\\begin{abstract}\n' \
    3.77 -					+ texdown[abstract_start + 20: abstract_end] \
    3.78 -					+ '\\end{abstract}\n' \
    3.79 -					+ texdown[abstract_end:]
    3.80 +			if 0:
    3.81 +				abstract_start = texdown.find('\section{ Abstract }')
    3.82 +				if abstract_start != -1:
    3.83 +					abstract_end = texdown.find('\section', abstract_start + 1)
    3.84 +					texdown = texdown[:abstract_start] \
    3.85 +						+ '\\begin{abstract}\n' \
    3.86 +						+ texdown[abstract_start + 20: abstract_end] \
    3.87 +						+ '\\end{abstract}\n' \
    3.88 +						+ texdown[abstract_end:]
    3.89 +
    3.90 +		if fragment:
    3.91 +			texdown = texdown[1:-1]
    3.92  
    3.93  		return texdown
    3.94  	
    3.95 @@ -194,7 +208,7 @@
    3.96  		children = match_names[1:]
    3.97  		conv = CONVERSIONS[match_name]
    3.98  
    3.99 -		for pre_match, match in self.convert_one(text, conv):
   3.100 +		for pre_match, match in self.convert_one(text, match_name, conv):
   3.101  			if children:
   3.102  				pre_match = self.do_convert(pre_match, children)
   3.103  			if 'incl' in conv:
   3.104 @@ -205,7 +219,7 @@
   3.105  		return ''.join(result)
   3.106  			
   3.107  
   3.108 -	def convert_one(self, texdown, conv):
   3.109 +	def convert_one(self, texdown, match_name, conv):
   3.110  		match = conv['match']
   3.111  
   3.112  		matches = list(match.finditer(texdown))
   3.113 @@ -265,6 +279,11 @@
   3.114  			else:
   3.115  				raise NotImplementedError()
   3.116  
   3.117 +			# If there is a post-processing handler, call it here.
   3.118 +			postprocess_handler = self.macros.get('postproc_%s' % (match_name))
   3.119 +			if postprocess_handler:
   3.120 +				result = postprocess_handler(result)
   3.121 +
   3.122  			yield before_match, result
   3.123  
   3.124  		if matches:
   3.125 @@ -342,6 +361,294 @@
   3.126  		except KeyError:
   3.127  			raise ConversionError("Macro '%s' not found." % (command))
   3.128  		return handler(args)
   3.129 +
   3.130 +	# Functions to make available to macros.py and localmacros.py.
   3.131 +	def separate_tabs(self, line):
   3.132 +		return re.split(r'\t+', line)
   3.133 +
   3.134 +	def make_author(self, name, email, affiliation):
   3.135 +		all_info = [name]
   3.136 +		if email:
   3.137 +			all_info.append(r"\\" + "\n\t\t%s" % (email))
   3.138 +		if affiliation:
   3.139 +			all_info.append(r"\\" + "\n\t\t%s" % (affiliation))
   3.140 +		return r"	\authorinfo{%s}" % (''.join(all_info))+ "\n" 
   3.141 +
   3.142 +	def make_author_plain(self, name, email, affiliation):
   3.143 +		all_info = [name]
   3.144 +		if email:
   3.145 +			all_info.append(r"\\" + "\n\t\t%s" % (email))
   3.146 +		if affiliation:
   3.147 +			all_info.append(r"\\" + "\n\t\t%s" % (affiliation))
   3.148 +		return r"	\author{%s}" % (''.join(all_info))+ "\n" 
   3.149 +
   3.150 +	def anypaper(self, block_lines):
   3.151 +		info = {'AUTHORS': '?authors',
   3.152 +			'conference': ('?conf', '?conf'), 
   3.153 +			'copyrightyear': '?year',
   3.154 +			'title': '?title'}
   3.155 +
   3.156 +		authors = []
   3.157 +
   3.158 +		for line in block_lines:
   3.159 +			line = self.texdown.separate_tabs(line)
   3.160 +			key = line.pop(0)
   3.161 +
   3.162 +			if key == 'author':
   3.163 +				author_name = line[0]
   3.164 +				if len(line) >= 2:
   3.165 +					author_email = line[1]
   3.166 +				else:
   3.167 +					author_email = None
   3.168 +				if len(line) >= 3:
   3.169 +					if line[2].startswith('"'):
   3.170 +						# Directly-written affiliation
   3.171 +						assert line[2].endswith('"')
   3.172 +						author_affil = line[2][1:-1]
   3.173 +					else:
   3.174 +						author_affil = AFFILIATIONS[line[2]]
   3.175 +				else:
   3.176 +					author_affil = None
   3.177 +				authors.append(self.author(author_name, author_email, author_affil))
   3.178 +			else:
   3.179 +				for idx in range(len(line)):
   3.180 +					info[key + str(idx)] = line[idx]
   3.181 +
   3.182 +		if authors:
   3.183 +			info['AUTHORS'] = '\n'.join(authors)
   3.184 +		return info
   3.185 +
   3.186 +	# Popular stuff from localmacros.py
   3.187 +	def fancy_table(self, block_lines, check_for_sizes = False, make_float = True, cell_func = None, horizborders = None, vertborders = None):
   3.188 +		"""
   3.189 +		Produces a table containing data. Numbers must be tab separated. EG:
   3.190 +			X	Y	!!numericresults
   3.191 +			37	1
   3.192 +			38	2
   3.193 +		"""
   3.194 +
   3.195 +		if block_lines[-1].startswith('~~'):
   3.196 +			caption = block_lines.pop()
   3.197 +		else:
   3.198 +			caption = None
   3.199 +		result = []
   3.200 +		if make_float:
   3.201 +			result.append('\\begin{table}\n')
   3.202 +
   3.203 +		block_lines = [self.separate_tabs(line) for line in block_lines]
   3.204 +		cols = len(block_lines[0])
   3.205 +
   3.206 +		if cell_func:
   3.207 +			for rownum in range(len(block_lines)):
   3.208 +				line = block_lines[rownum]
   3.209 +				for colnum in range(len(line)):
   3.210 +					line[colnum] = cell_func(rownum, colnum, line[colnum])
   3.211 +				block_lines[rownum] = line
   3.212 +
   3.213 +
   3.214 +		latex_sizes = ['l'] * cols # The default
   3.215 +
   3.216 +		if check_for_sizes:
   3.217 +			# The first row may contain size information of the form !\d+%. If
   3.218 +			# it does, use 'p' rather than 'l' to lay out the table, and base
   3.219 +			# the overall size on the known page width.
   3.220 +			all_sizes_percent = [-1] * cols
   3.221 +			found_one = False
   3.222 +			for col_num, element in enumerate(block_lines[0]):
   3.223 +				matcher = re.match(r'.*!([0-9]+)%$', element)
   3.224 +				if matcher:
   3.225 +					found_one = True
   3.226 +					all_sizes_percent[col_num] = int(matcher.group(1))
   3.227 +					block_lines[0][col_num] = element[:element.rfind('!')]
   3.228 +
   3.229 +			if found_one:
   3.230 +				# Assign any missing numbers
   3.231 +				perc_left = 100
   3.232 +				for col_num in range(cols):
   3.233 +					if all_sizes_percent[col_num] == -1:
   3.234 +						all_sizes_percent[col_num] = perc_left
   3.235 +					else:
   3.236 +						perc_left -= all_sizes_percent[col_num]
   3.237 +
   3.238 +				# Convert to mm
   3.239 +				all_sizes_mm = [(self.page_width_mm * col_size) / 100 \
   3.240 +						for col_size \
   3.241 +						in all_sizes_percent]
   3.242 +				latex_sizes = ['p{%dmm}' % (size_mm) for size_mm in all_sizes_mm]
   3.243 +
   3.244 +		# Check for magical alignment of columns.
   3.245 +		# Left-alignment (the default): cells neither start nor end with a space.
   3.246 +		# Right-alignment: At least one cell starts with a space; no cell ends with one.
   3.247 +		# Centered alignment: At least one cell both starts and ends with a space.
   3.248 +		# at least one entry with a space.
   3.249 +		for col_num in range(cols):
   3.250 +			align = latex_sizes[col_num]
   3.251 +			if len(align) == 1 and align in 'lcr':
   3.252 +				for line in block_lines:
   3.253 +					cell = line[col_num]
   3.254 +					if cell.startswith(' ') and align == 'l':
   3.255 +						align = 'r'
   3.256 +					if cell.endswith(' '):
   3.257 +						align = 'c'
   3.258 +				latex_sizes[col_num] = align
   3.259 +
   3.260 +
   3.261 +		# Borders
   3.262 +		if horizborders:
   3.263 +			if horizborders[1] == '|':
   3.264 +				latex_sizes = [item for sublist in zip(latex_sizes, ['|'] * len(latex_sizes))
   3.265 +						for item in sublist][:-1]
   3.266 +			if horizborders[0] == '|':
   3.267 +				latex_sizes.insert(0, '|')
   3.268 +			if horizborders[2] == '|':
   3.269 +				latex_sizes.append('|')
   3.270 +
   3.271 +		# Start output
   3.272 +		latex_sizecmd = ''.join(latex_sizes)
   3.273 +		result.append('	\\begin{tabular}{%s}\n' % latex_sizecmd)
   3.274 +
   3.275 +
   3.276 +		if vertborders and vertborders[0] == '-':
   3.277 +			result.append('\\hline\n')
   3.278 +
   3.279 +		count = 0
   3.280 +		for line in block_lines:
   3.281 +			if vertborders and vertborders[1] == '-' and count > 0:
   3.282 +				result.append('\\hline\n')
   3.283 +			if vertborders and vertborders[1] == 't' and count == 1:
   3.284 +				result.append('\\hline\n')
   3.285 +			elements = [self.convert(element) for element in line]
   3.286 +
   3.287 +			result.append('\t')
   3.288 +
   3.289 +			result.append(' & '.join(elements))
   3.290 +
   3.291 +			result.append(r'\\' + '\n')
   3.292 +			count += 1
   3.293 +
   3.294 +		if vertborders and vertborders[2] == '-':
   3.295 +			result.append('\\hline\n')
   3.296 +
   3.297 +		result.append('	\\end{tabular}\n')
   3.298 +		if caption:
   3.299 +			result.append(caption)
   3.300 +		if make_float:
   3.301 +			result.append('\\end{table}\n')
   3.302 +		return ''.join(result)
   3.303 +
   3.304 +	def macro_floatgraphic(self, args):
   3.305 +		"""
   3.306 +		Includes a graphic, places it in a figure, and gives it a label. Usage:
   3.307 +		!!floatgraphic filename, Caption goes here
   3.308 +		"""
   3.309 +		return self.macro_anygraphic(args, floating = True)
   3.310 +
   3.311 +	def macro_inlinegraphic(self, args):
   3.312 +		return self.macro_anygraphic(args, floating = False)
   3.313 +
   3.314 +	def macro_anygraphic(self, args, floating = True, centered = False, floatspec = None, extra = ""):
   3.315 +		if ',' in args:
   3.316 +			filename, caption = args.split(',', 1)
   3.317 +			caption = caption.strip()
   3.318 +		else:
   3.319 +			filename = args
   3.320 +			caption = None
   3.321 +
   3.322 +		label = filename
   3.323 +		if '/' in label:
   3.324 +			label = label.split('/')[-1]
   3.325 +		if '#' in label:
   3.326 +			filename = filename.split('#')[0]
   3.327 +			label = label.replace('#', '.')
   3.328 +		label = label.replace('-', '.')
   3.329 +
   3.330 +		if floatspec is None:
   3.331 +			floatspec = '[htb]'
   3.332 +
   3.333 +		result = []
   3.334 +
   3.335 +		if floating:
   3.336 +			result.append('\\begin{figure}%s' % (floatspec))
   3.337 +
   3.338 +		if centered:
   3.339 +			result.append('\\begin{center}')
   3.340 +
   3.341 +		result.append('\\includegraphics%s{figures/%s}' % (extra, filename))
   3.342 +	
   3.343 +		if centered:
   3.344 +			result.append('		\\end{center}')
   3.345 +
   3.346 +		if floating:
   3.347 +			result.append('	\\caption{\\label{figure.%s}%s}' % (label, caption))
   3.348 +			result.append('\\end{figure}')
   3.349 +
   3.350 +		else:
   3.351 +			result.append('\\captionof{figure}{%s}' % (caption))
   3.352 +		return '\n'.join(result)
   3.353 +
   3.354 +	def macro_floatgraphic_wholepage(self, args):
   3.355 +		result = [self.macro_floatgraphic(args),
   3.356 +				'\\afterpage{\\clearpage}']
   3.357 +		return '\n'.join(result)
   3.358 +	
   3.359 +
   3.360 +	def macro_absolutegraphic(self, args):
   3.361 +		"""
   3.362 +		Includes an absolutely-positioned graphic without label.
   3.363 +		"""
   3.364 +		filename, left, top, height= \
   3.365 +			[arg.strip() for arg in args.split(',')]
   3.366 +		result = [
   3.367 +			r'\begin{picture}(0.0, 0.0)',
   3.368 +			r'	\put(%s,%s) {' % (left, top),
   3.369 +			r'		\includegraphics[height=%s]{figures/%s}' % (height, filename),
   3.370 +			r'	}',
   3.371 +			r'\end{picture}',
   3.372 +		]
   3.373 +		return '\n'.join(result)
   3.374 +	
   3.375 +	def macro_floatcode(self, block_lines, placement_spec = None):
   3.376 +		"""
   3.377 +		Code inside a figure. If the final line is a caption, does the right
   3.378 +		thing. Usage:
   3.379 +			code line 1	!!floatcode
   3.380 +			final code line
   3.381 +			~~ <<label.if.wanted>> Caption if wanted ~~
   3.382 +		"""
   3.383 +		if placement_spec is None:
   3.384 +			placement_spec = 'htb'
   3.385 +
   3.386 +		caption = None
   3.387 +		if block_lines[-1].startswith('~~'):
   3.388 +			caption = block_lines.pop()
   3.389 +		block_lines = [line.replace('\t', '  ') for line in block_lines]
   3.390 +		result = ['\\begin{figure}[%s]' % (placement_spec)]
   3.391 +		result.append('\\begin{verbatim}')
   3.392 +		result.extend(block_lines)
   3.393 +		result.append('\\end{verbatim}')
   3.394 +		if caption:
   3.395 +			result.append(caption)
   3.396 +		result.append('\\end{figure}')
   3.397 +		return '\n'.join(result)
   3.398 +	
   3.399 +	def macro_exactfloatcode(self, block_lines):
   3.400 +		return self.macro_floatcode(block_lines, 'h!')
   3.401 +	
   3.402 +	def macro_floattable(self, block_lines):
   3.403 +		return self.fancy_table(block_lines, check_for_sizes = True)
   3.404 +	
   3.405 +	def macro_inlinetable(self, block_lines):
   3.406 +		return self.fancy_table(block_lines, check_for_sizes = True, make_float = False)
   3.407 +	
   3.408 +	def macro_blockquote(self, block_lines):
   3.409 +		# Special-case attribution line.
   3.410 +		if block_lines[-1].startswith('--'):
   3.411 +			block_lines[-1] = r'\begin{flushright} --' +\
   3.412 +				self.convert(block_lines[-1][2:]) +\
   3.413 +				r'\end{flushright}'
   3.414 +		result = [r'\begin{quote}'] + block_lines + [r'\end{quote}']
   3.415 +		return '\n'.join(result) + '\n'
   3.416 +
   3.417  	
   3.418  if __name__ == '__main__':
   3.419  	handle = codecs.open(sys.argv[1], 'r', encoding = 'utf-8')