This repository provides User Manual for setting up a Docker environment tailored for testing DGTD code.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

139 lines
4.8 KiB

# Copyright (c) 2006-2019 Andrey Golovigin
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""parse LaTeX aux file
"""
from __future__ import unicode_literals, with_statement
import re
import pybtex.io
from pybtex.errors import report_error
from pybtex.exceptions import PybtexError
from pybtex import py3compat
@py3compat.python_2_unicode_compatible
class AuxDataError(PybtexError):
def __init__(self, message, context=None):
super(AuxDataError, self).__init__(message, context.filename)
self.context = context
def get_context(self):
if self.context.line:
marker = '^' * len(self.context.line)
return self.context.line + '\n' + marker
def __str__(self):
base_message = py3compat.__str__(super(AuxDataError, self))
lineno = self.context.lineno
location = 'in line {0}: '.format(lineno) if lineno else ''
return location + base_message
class AuxDataContext(object):
lineno = None
line = None
filename = None
def __init__(self, filename):
self.filename = filename
class AuxData(object):
command_re = re.compile(r'\\(citation|bibdata|bibstyle|@input){(.*)}')
context = None
style = None
data = None
citations = None
def __init__(self, encoding):
self.encoding = encoding
self.citations = []
self._canonical_keys = {}
def handle_citation(self, keys):
for key in keys.split(','):
key_lower = key.lower()
if key_lower in self._canonical_keys:
existing_key = self._canonical_keys[key_lower]
if key != existing_key:
msg = 'case mismatch error between cite keys {0} and {1}'
report_error(AuxDataError(msg.format(key, existing_key), self.context))
self.citations.append(key)
self._canonical_keys[key_lower] = key
def handle_bibstyle(self, style):
if self.style is not None:
report_error(AuxDataError(r'illegal, another \bibstyle command', self.context))
else:
self.style = style
def handle_bibdata(self, bibdata):
if self.data is not None:
report_error(AuxDataError(r'illegal, another \bibdata command', self.context))
else:
self.data = bibdata.split(',')
def handle_input(self, filename):
self.parse_file(filename, toplevel=False)
def handle_command(self, command, value):
action = getattr(self, 'handle_%s' % command.lstrip('@'))
action(value)
def parse_line(self, line, lineno):
self.context.lineno = lineno
self.context.line = line.strip()
match = self.command_re.match(line)
if match:
command, value = match.groups()
self.handle_command(command, value)
def parse_file(self, filename, toplevel=True):
previous_context = self.context
self.context = AuxDataContext(filename)
with pybtex.io.open_unicode(filename, encoding=self.encoding) as aux_file:
for lineno, line in enumerate(aux_file, 1):
self.parse_line(line, lineno)
if previous_context:
self.context = previous_context
else:
self.context.line = None
self.context.lineno = None
# these errors are fatal - always raise an exception instead of using
# erorrs.report_error()
if toplevel and self.data is None:
raise AuxDataError(r'found no \bibdata command', self.context)
if toplevel and self.style is None:
raise AuxDataError(r'found no \bibstyle command', self.context)
def parse_file(filename, encoding=None):
"""Parse a file and return an AuxData object."""
data = AuxData(encoding)
data.parse_file(filename)
return data