Blame lib/dbtexmf/dblatex/grubber/index.py.enable-python3

Packit 5164a5
# This file is part of Rubber and thus covered by the GPL
Packit 5164a5
# (c) Emmanuel Beffara, 2004--2006
Packit 5164a5
"""
Packit 5164a5
Indexing support with package 'index'.
Packit 5164a5
Packit 5164a5
This module handles the processing of the document's indices using a tool like
Packit 5164a5
makeindex or xindy. It stores an MD5 sum of the source (.idx) file between two
Packit 5164a5
runs, in order to detect modifications.
Packit 5164a5
Packit 5164a5
The following directives are provided to specify options for makeindex:
Packit 5164a5
Packit 5164a5
  tool <tool> =
Packit 5164a5
    Choose which indexing tool should be used. Currently this can be either
Packit 5164a5
    "makeindex" (by default) or "xindy".
Packit 5164a5
Packit 5164a5
  language <lang> =
Packit 5164a5
    Choose the language used for sorting the index (xindy only).
Packit 5164a5
Packit 5164a5
  modules <mod> <mod> ... =
Packit 5164a5
      Specify which modules xindy should use for the index.
Packit 5164a5
Packit 5164a5
  order <ordering> =
Packit 5164a5
    Modify the ordering to be used (makeindex only, supported by xindy with
Packit 5164a5
    warnings). The argument must be a space separated list of:
Packit 5164a5
    - standard = use default ordering (no options, this is the default)
Packit 5164a5
    - german = use German ordering (option "-g")
Packit 5164a5
    - letter = use letter instead of word ordering (option "-l")
Packit 5164a5
Packit 5164a5
  path <directory> =
Packit 5164a5
    Add the specified directory to the search path for styles.
Packit 5164a5
Packit 5164a5
  style <name> =
Packit 5164a5
    Use the specified style file.
Packit 5164a5
Packit 5164a5
They all accept an optional argument first, enclosed in parentheses as in
Packit 5164a5
"index.path (foo,bar) here/", to specify which index they apply to. Without
Packit 5164a5
this argument, they apply to all indices declared at the point where they
Packit 5164a5
occur.
Packit 5164a5
"""
Packit 5164a5
Packit 5164a5
import os
Packit 5164a5
from os.path import *
Packit 5164a5
import re, string
Packit 5164a5
import subprocess
Packit 5164a5
import xml.dom.minidom
Packit 5164a5
Packit 5164a5
from subprocess import Popen, PIPE
Packit 5164a5
from msg import _, msg
Packit 5164a5
from plugins import TexModule
Packit 5164a5
from util import md5_file
Packit 5164a5
Packit 5164a5
Packit 5164a5
class Xindy:
Packit 5164a5
    """
Packit 5164a5
    Xindy command wrapper
Packit 5164a5
    """
Packit 5164a5
    def __init__(self, doc, idxfile, target, transcript="",
Packit 5164a5
                 opts=None, modules=None,
Packit 5164a5
                 index_lang="", style=""):
Packit 5164a5
        self.doc = doc
Packit 5164a5
        self.idxfile = idxfile
Packit 5164a5
        self.target = target
Packit 5164a5
        self.transcript = transcript
Packit 5164a5
        self.opts = opts or []
Packit 5164a5
        self.modules = modules or []
Packit 5164a5
        self.index_lang = index_lang
Packit 5164a5
        self.path_var = "XINDY_SEARCHPATH"
Packit 5164a5
        mapfile = os.path.join(os.path.dirname(__file__), "xindylang.xml")
Packit 5164a5
        self.languages = self.map_languages(mapfile)
Packit 5164a5
        self._re_hyperindex = re.compile(r"hyperindexformat{\\(.*?)}}{",
Packit 5164a5
                                         re.M|re.DOTALL)
Packit 5164a5
        self.invalid_index_ranges = []
Packit 5164a5
Packit 5164a5
    def map_languages(self, mapfile):
Packit 5164a5
        languages = {}
Packit 5164a5
        dom_document = xml.dom.minidom.parse(mapfile)
Packit 5164a5
        for dom_fontspec in dom_document.getElementsByTagName('map'):
Packit 5164a5
            lang = dom_fontspec.getAttribute('lang')
Packit 5164a5
            xindylang = dom_fontspec.getAttribute('xindylang')
Packit 5164a5
            if xindylang:
Packit 5164a5
                languages[lang] = xindylang
Packit 5164a5
        dom_document.unlink()
Packit 5164a5
        return languages
Packit 5164a5
Packit 5164a5
    def command(self):
Packit 5164a5
        cmd = []
Packit 5164a5
        if self.doc.program == "xelatex":
Packit 5164a5
            # If raw index is in UTF-8 the texindy command cannot be used
Packit 5164a5
            cmd.extend(["xindy", "-M", "texindy", "-C", self.doc.encoding])
Packit 5164a5
            # To behave even more like texindy
Packit 5164a5
            cmd.extend(["-q", "-M", "page-ranges"])
Packit 5164a5
        else:
Packit 5164a5
            # Call texindy to handle LICR encoded raw index
Packit 5164a5
            # Equivalent to xindy arguments (beware of module order):
Packit 5164a5
            #   "xindy", "-M", "tex/inputenc/latin",
Packit 5164a5
            #            "-M", "texindy", "-C", "latin",
Packit 5164a5
            #            "-I", "latex"
Packit 5164a5
            cmd.extend(["texindy"])
Packit 5164a5
Packit 5164a5
        # Specific output files?
Packit 5164a5
        if self.target:
Packit 5164a5
            cmd.extend(["-o", self.target])
Packit 5164a5
        if self.transcript:
Packit 5164a5
            cmd.extend(["-t", self.transcript])
Packit 5164a5
Packit 5164a5
        # Find out which language to use
Packit 5164a5
        if self.index_lang:
Packit 5164a5
            lang = self.index_lang
Packit 5164a5
        elif self.doc.lang:
Packit 5164a5
            lang = self.languages.get(self.doc.lang)
Packit 5164a5
            if not(lang):
Packit 5164a5
                msg.warn(_("xindy: lang '%s' not found" % \
Packit 5164a5
                           self.doc.lang), pkg="index")
Packit 5164a5
            else:
Packit 5164a5
                msg.log(_("xindy: lang '%s' mapped to '%s'" % \
Packit 5164a5
                           (self.doc.lang, lang)), pkg="index")
Packit 5164a5
        else:
Packit 5164a5
            lang = None
Packit 5164a5
Packit 5164a5
        if lang:
Packit 5164a5
            cmd.extend(["-L", lang])
Packit 5164a5
Packit 5164a5
        for mod in self.modules:
Packit 5164a5
            cmd.extend(["-M", mod])
Packit 5164a5
Packit 5164a5
        if self.opts:
Packit 5164a5
            cmd.extend(self.opts)
Packit 5164a5
Packit 5164a5
        cmd.append(self.idxfile)
Packit 5164a5
        return cmd
Packit 5164a5
Packit 5164a5
    def _find_index_encoding(self, logname):
Packit 5164a5
        # Texindy produces latin-* indexes. Try to find out which one from
Packit 5164a5
        # the modules loaded by the script (language dependent)
Packit 5164a5
        re_lang = re.compile("loading module \"lang/.*/(latin[^.-]*)")
Packit 5164a5
        logfile = open(logname)
Packit 5164a5
        encoding = ""
Packit 5164a5
        for line in logfile:
Packit 5164a5
            m = re_lang.search(line)
Packit 5164a5
            if m:
Packit 5164a5
                encoding = m.group(1)
Packit 5164a5
                break
Packit 5164a5
Packit 5164a5
        logfile.close()
Packit 5164a5
        return encoding
Packit 5164a5
Packit 5164a5
    def _index_is_unicode(self):
Packit 5164a5
        f = file(self.target, "r")
Packit 5164a5
        is_unicode = True 
Packit 5164a5
        for line in f:
Packit 5164a5
            try:
Packit 5164a5
                line.decode("utf8")
Packit 5164a5
            except:
Packit 5164a5
                is_unicode = False
Packit 5164a5
                break
Packit 5164a5
        f.close()
Packit 5164a5
        return is_unicode
Packit 5164a5
Packit 5164a5
    def _sanitize_idxfile(self):
Packit 5164a5
        #
Packit 5164a5
        # Remove the 'hyperindexformat' of the new hyperref that makes a mess
Packit 5164a5
        # with Xindy. If not, the following error is raised by Xindy:
Packit 5164a5
        # "WARNING: unknown cross-reference-class `hyperindexformat'! (ignored)"
Packit 5164a5
        #
Packit 5164a5
        f = file(self.idxfile, "r")
Packit 5164a5
        data = f.read()
Packit 5164a5
        f.close()
Packit 5164a5
        data, nsub = self._re_hyperindex.subn(r"\1}{", data)
Packit 5164a5
        if not(nsub):
Packit 5164a5
            return
Packit 5164a5
        msg.debug("Remove %d unsupported 'hyperindexformat' calls" % nsub)
Packit 5164a5
        f = file(self.idxfile, "w")
Packit 5164a5
        f.write(data)
Packit 5164a5
        f.close()
Packit 5164a5
Packit 5164a5
    def _fix_invalid_ranges(self):
Packit 5164a5
        if not(self.invalid_index_ranges): return
Packit 5164a5
        f = open(self.idxfile)
Packit 5164a5
        lines = f.readlines()
Packit 5164a5
        f.close()
Packit 5164a5
Packit 5164a5
        # Track the lines with the wrong index ranges
Packit 5164a5
        for i, line in enumerate(lines):
Packit 5164a5
            for entry in self.invalid_index_ranges:
Packit 5164a5
                if entry.index_key in line:
Packit 5164a5
                    entry.add_line(i, line)
Packit 5164a5
Packit 5164a5
        # Summary of the lines to remove in order to fix the ranges
Packit 5164a5
        skip_lines = []
Packit 5164a5
        for entry in self.invalid_index_ranges:
Packit 5164a5
            skip_lines.extend(entry.skip_lines)
Packit 5164a5
            entry.reinit()
Packit 5164a5
        if not(skip_lines): return
Packit 5164a5
        
Packit 5164a5
        # Remove the lines starting from the end to always have valid line num
Packit 5164a5
        msg.debug("xindy: lines to remove from %s to fix ranges: %s" %\
Packit 5164a5
                  (self.idxfile, skip_lines))
Packit 5164a5
        skip_lines.sort()
Packit 5164a5
        skip_lines.reverse()
Packit 5164a5
        for line_num in skip_lines:
Packit 5164a5
            del lines[line_num]
Packit 5164a5
        f = open(self.idxfile, "w")
Packit 5164a5
        f.writelines(lines)
Packit 5164a5
        f.close()
Packit 5164a5
Packit 5164a5
    def _detect_invalid_ranges(self, data):
Packit 5164a5
        # Look for warnings like this:
Packit 5164a5
        #
Packit 5164a5
        # WARNING: Found a :close-range in the index that wasn't opened before!
Packit 5164a5
        #          Location-reference is 76 in keyword (Statute of Anne (1710))
Packit 5164a5
        #          I'll continue and ignore this.
Packit 5164a5
        #
Packit 5164a5
        # Do it only once on the first run to find wrong indexes.
Packit 5164a5
        if (self.invalid_index_ranges): return
Packit 5164a5
        blocks = re.split("(WARNING:|ERROR:)", data, re.M)
Packit 5164a5
        check_next_block = False
Packit 5164a5
        for block in blocks:
Packit 5164a5
            if "WARNING" in block:
Packit 5164a5
                check_next_block = True
Packit 5164a5
            elif check_next_block:
Packit 5164a5
                m = re.search("Found.*?-range .*"\
Packit 5164a5
                              "Location-reference is \d+ in keyword \((.*)\)",
Packit 5164a5
                              block, re.M|re.DOTALL)
Packit 5164a5
                if m: self.invalid_index_ranges.append(Indexentry(m.group(1)))
Packit 5164a5
                check_next_block = False
Packit 5164a5
Packit 5164a5
    def run(self):
Packit 5164a5
        self._sanitize_idxfile()
Packit 5164a5
        self._fix_invalid_ranges()
Packit 5164a5
        cmd = self.command()
Packit 5164a5
        msg.debug(" ".join(cmd))
Packit 5164a5
Packit 5164a5
        # Collect the script output, and errors
Packit 5164a5
        logname = join(dirname(self.target), "xindy.log")
Packit 5164a5
        logfile = open(logname, "w")
Packit 5164a5
        p = Popen(cmd, stdout=logfile, stderr=PIPE)
Packit 5164a5
        errdata = p.communicate()[1]
Packit 5164a5
        rc = p.wait()
Packit 5164a5
        if msg.stdout:
Packit 5164a5
            msg.stdout.write(errdata)
Packit 5164a5
        else:
Packit 5164a5
            msg.warn(_(errdata.strip()))
Packit 5164a5
        logfile.close()
Packit 5164a5
        if (rc != 0):
Packit 5164a5
            msg.error(_("could not make index %s") % self.target)
Packit 5164a5
            return 1
Packit 5164a5
Packit 5164a5
        self._detect_invalid_ranges(errdata)
Packit 5164a5
Packit 5164a5
        # Now convert the built index to UTF-8 if required
Packit 5164a5
        if cmd[0] == "texindy" and self.doc.encoding == "utf8":
Packit 5164a5
            if not(self._index_is_unicode()):
Packit 5164a5
                encoding = self._find_index_encoding(logname)
Packit 5164a5
                tmpindex = join(dirname(self.target), "new.ind")
Packit 5164a5
                cmd = ["iconv", "-f", encoding, "-t", "utf8",
Packit 5164a5
                       "-o", tmpindex, self.target]
Packit 5164a5
                msg.debug(" ".join(cmd))
Packit 5164a5
                rc = subprocess.call(cmd)
Packit 5164a5
                if rc == 0: os.rename(tmpindex, self.target)
Packit 5164a5
Packit 5164a5
        return rc
Packit 5164a5
Packit 5164a5
class Indexentry:
Packit 5164a5
    """
Packit 5164a5
    Index entry wrapper from idxfile. Its role is to detect range anomalies
Packit 5164a5
    """
Packit 5164a5
    _re_entry = re.compile("\indexentry{(.*)\|([\(\)]?).*}{(\d+)}", re.DOTALL)
Packit 5164a5
Packit 5164a5
    def __init__(self, index_key):
Packit 5164a5
        self.index_key = index_key
Packit 5164a5
        self.skip_lines = []
Packit 5164a5
        self.last_range_page = 0
Packit 5164a5
        self.last_range_line = -1
Packit 5164a5
        self.last_range_open = False
Packit 5164a5
Packit 5164a5
    def reinit(self):
Packit 5164a5
        self.__init__(self.index_key)
Packit 5164a5
Packit 5164a5
    def add_line(self, line_num, indexentry):
Packit 5164a5
        m = self._re_entry.search(indexentry)
Packit 5164a5
        if not(m):
Packit 5164a5
            return
Packit 5164a5
        index_key = m.group(1).split("!")[-1]
Packit 5164a5
        if index_key != self.index_key:
Packit 5164a5
            return
Packit 5164a5
        range_state = m.group(2)
Packit 5164a5
        page = int(m.group(3))
Packit 5164a5
Packit 5164a5
        #print "Found %s at %d" % (index_key, page)
Packit 5164a5
        if range_state == "(":
Packit 5164a5
            # If a starting range overlap the previous range remove
Packit 5164a5
            # this intermediate useless range close/open
Packit 5164a5
            if page <= self.last_range_page:
Packit 5164a5
                self.skip_lines += [self.last_range_line, line_num]
Packit 5164a5
            self.last_range_page = page
Packit 5164a5
            self.last_range_line = line_num
Packit 5164a5
            self.last_range_open = True
Packit 5164a5
        elif range_state == ")":
Packit 5164a5
            self.last_range_page = page
Packit 5164a5
            self.last_range_line = line_num
Packit 5164a5
            self.last_range_open = False
Packit 5164a5
        elif range_state == "":
Packit 5164a5
            # If a single indexentry is within a range, skip it
Packit 5164a5
            if self.last_range_open == True:
Packit 5164a5
                self.skip_lines += [line_num]
Packit 5164a5
        
Packit 5164a5
Packit 5164a5
class Makeindex:
Packit 5164a5
    """
Packit 5164a5
    Makeindex command wrapper
Packit 5164a5
    """
Packit 5164a5
    def __init__(self, doc, idxfile, target, transcript="",
Packit 5164a5
                 opts=None, modules=None,
Packit 5164a5
                 index_lang="", style=""):
Packit 5164a5
        self.doc = doc
Packit 5164a5
        self.idxfile = idxfile
Packit 5164a5
        self.target = target
Packit 5164a5
        self.transcript = transcript
Packit 5164a5
        self.opts = opts or []
Packit 5164a5
        self.path_var = "INDEXSTYLE"
Packit 5164a5
        self.style = style
Packit 5164a5
Packit 5164a5
    def command(self):
Packit 5164a5
        cmd = ["makeindex", "-o", self.target] + self.opts
Packit 5164a5
        if self.transcript:
Packit 5164a5
            cmd.extend(["-t", self.transcript])
Packit 5164a5
        if self.style:
Packit 5164a5
            cmd.extend(["-s", self.style])
Packit 5164a5
        cmd.append(self.idxfile)
Packit 5164a5
        return cmd
Packit 5164a5
Packit 5164a5
    def _index_is_unicode(self):
Packit 5164a5
        f = file(self.target, "r")
Packit 5164a5
        is_unicode = True 
Packit 5164a5
        for line in f:
Packit 5164a5
            try:
Packit 5164a5
                line.decode("utf8")
Packit 5164a5
            except:
Packit 5164a5
                is_unicode = False
Packit 5164a5
                break
Packit 5164a5
        f.close()
Packit 5164a5
        return is_unicode
Packit 5164a5
Packit 5164a5
    def run(self):
Packit 5164a5
        cmd = self.command()
Packit 5164a5
        msg.debug(" ".join(cmd))
Packit 5164a5
Packit 5164a5
        # Makeindex outputs everything to stderr, even progress messages
Packit 5164a5
        rc = subprocess.call(cmd, stderr=msg.stdout)
Packit 5164a5
        if (rc != 0):
Packit 5164a5
            msg.error(_("could not make index %s") % self.target)
Packit 5164a5
            return 1
Packit 5164a5
Packit 5164a5
        # Beware with UTF-8 encoding, makeindex with headings can be messy
Packit 5164a5
        # because it puts in the headings the first 8bits char of the words
Packit 5164a5
        # under the heading which can be an invalid character in UTF-8
Packit 5164a5
        if (self.style and self.doc.encoding == "utf8"):
Packit 5164a5
            if not(self._index_is_unicode()):
Packit 5164a5
                # Retry without style to avoid headings
Packit 5164a5
                msg.warn(_("makeindex on UTF8 failed. Retry..."))
Packit 5164a5
                self.style = ""
Packit 5164a5
                return self.run()
Packit 5164a5
Packit 5164a5
        return rc
Packit 5164a5
Packit 5164a5
Packit 5164a5
class Index(TexModule):
Packit 5164a5
    """
Packit 5164a5
    This class represents a single index.
Packit 5164a5
    """
Packit 5164a5
    def __init__ (self, doc, source, target, transcript):
Packit 5164a5
        """
Packit 5164a5
        Initialize the index, by specifying the source file (generated by
Packit 5164a5
        LaTeX), the target file (the output of makeindex) and the transcript
Packit 5164a5
        (e.g. .ilg) file.  Transcript is used by glosstex.py.
Packit 5164a5
        """
Packit 5164a5
        self.paranoid = True
Packit 5164a5
        self.doc = doc
Packit 5164a5
        self.pbase = doc.src_base
Packit 5164a5
        self.source = doc.src_base + "." + source
Packit 5164a5
        self.target = doc.src_base + "." + target
Packit 5164a5
        self.transcript = doc.src_base + "." + transcript
Packit 5164a5
Packit 5164a5
        # In paranoid mode, can output only in current working dir
Packit 5164a5
        if self.paranoid and (os.path.dirname(self.target) == os.getcwd()):
Packit 5164a5
            self.target = os.path.basename(self.target)
Packit 5164a5
            self.transcript = os.path.basename(self.transcript)
Packit 5164a5
Packit 5164a5
        if os.path.exists(self.source):
Packit 5164a5
            self.md5 = md5_file(self.source)
Packit 5164a5
        else:
Packit 5164a5
            self.md5 = None
Packit 5164a5
Packit 5164a5
        self.tool = "makeindex"
Packit 5164a5
        self.tool_obj = None
Packit 5164a5
        self.lang = None   # only for xindy
Packit 5164a5
        self.modules = []  # only for xindy
Packit 5164a5
        self.opts = []
Packit 5164a5
        self.path = []
Packit 5164a5
        self.style = None  # only for makeindex
Packit 5164a5
Packit 5164a5
Packit 5164a5
    def do_language (self, lang):
Packit 5164a5
        self.lang = lang
Packit 5164a5
Packit 5164a5
    def do_modules (self, *args):
Packit 5164a5
        self.modules.extend(args)
Packit 5164a5
Packit 5164a5
    def do_order (self, *args):
Packit 5164a5
        for opt in args:
Packit 5164a5
            if opt == "standard": self.opts = []
Packit 5164a5
            elif opt == "german": self.opts.append("-g")
Packit 5164a5
            elif opt == "letter": self.opts.append("-l")
Packit 5164a5
            else: msg.warn(
Packit 5164a5
                _("unknown option '%s' for 'makeidx.order'") % opt)
Packit 5164a5
Packit 5164a5
    def do_path (self, path):
Packit 5164a5
        self.path.append(self.doc.abspath(path))
Packit 5164a5
Packit 5164a5
    def do_style (self, style):
Packit 5164a5
        self.style = style
Packit 5164a5
Packit 5164a5
    def do_tool (self, tool):
Packit 5164a5
        if tool not in ("makeindex", "xindy"):
Packit 5164a5
            msg.error(_("unknown indexing tool '%s'") % tool)
Packit 5164a5
        self.tool = tool
Packit 5164a5
Packit 5164a5
Packit 5164a5
    def post_compile (self):
Packit 5164a5
        """
Packit 5164a5
        Run the indexer tool
Packit 5164a5
        """
Packit 5164a5
        if not os.path.exists(self.source):
Packit 5164a5
            msg.log(_("strange, there is no %s") % self.source, pkg="index")
Packit 5164a5
            return 0
Packit 5164a5
        if not self.run_needed():
Packit 5164a5
            return 0
Packit 5164a5
Packit 5164a5
        msg.progress(_("processing index %s") % self.source)
Packit 5164a5
Packit 5164a5
        if not(self.tool_obj):
Packit 5164a5
            if self.tool == "makeindex":
Packit 5164a5
                index_cls = Makeindex
Packit 5164a5
            elif self.tool == "xindy":
Packit 5164a5
                index_cls = Xindy
Packit 5164a5
Packit 5164a5
            self.tool_obj = index_cls(self.doc,
Packit 5164a5
                              self.source,
Packit 5164a5
                              self.target,
Packit 5164a5
                              transcript=self.transcript,
Packit 5164a5
                              opts=self.opts,
Packit 5164a5
                              modules=self.modules,
Packit 5164a5
                              index_lang=self.lang,
Packit 5164a5
                              style=self.style)
Packit 5164a5
Packit 5164a5
        rc = self.tool_obj.run()
Packit 5164a5
        if rc != 0:
Packit 5164a5
            return rc
Packit 5164a5
Packit 5164a5
        self.doc.must_compile = 1
Packit 5164a5
        return 0
Packit 5164a5
Packit 5164a5
    def run_needed (self):
Packit 5164a5
        """
Packit 5164a5
        Check if makeindex has to be run. This is the case either if the
Packit 5164a5
        target file does not exist or if the source file has changed.
Packit 5164a5
        """
Packit 5164a5
        if os.path.getsize(self.source) == 0:
Packit 5164a5
            msg.log(_("the index file %s is empty") % self.source, pkg="index")
Packit 5164a5
            return 0
Packit 5164a5
        new = md5_file(self.source)
Packit 5164a5
        if not os.path.exists(self.target):
Packit 5164a5
            self.md5 = new
Packit 5164a5
            return 1
Packit 5164a5
        if not self.md5:
Packit 5164a5
            self.md5 = new
Packit 5164a5
            msg.log(_("the index file %s is new") % self.source, pkg="index")
Packit 5164a5
            return 1
Packit 5164a5
        if self.md5 == new:
Packit 5164a5
            msg.log(_("the index %s did not change") % self.source, pkg="index")
Packit 5164a5
            return 0
Packit 5164a5
        self.md5 = new
Packit 5164a5
        msg.log(_("the index %s has changed") % self.source, pkg="index")
Packit 5164a5
        return 1
Packit 5164a5
Packit 5164a5
    def clean (self):
Packit 5164a5
        """
Packit 5164a5
        Remove all generated files related to the index.
Packit 5164a5
        """
Packit 5164a5
        for file in self.source, self.target, self.transcript:
Packit 5164a5
            if exists(file):
Packit 5164a5
                msg.log(_("removing %s") % file, pkg="index")
Packit 5164a5
                os.unlink(file)
Packit 5164a5
Packit 5164a5
re_newindex = re.compile(" *{(?P<idx>[^{}]*)} *{(?P<ind>[^{}]*)}")
Packit 5164a5
re_optarg = re.compile("\((?P<list>[^()]*)\) *")
Packit 5164a5
Packit 5164a5
class Module (TexModule):
Packit 5164a5
    def __init__ (self, doc, dict):
Packit 5164a5
        """
Packit 5164a5
        Initialize the module with no index.
Packit 5164a5
        """
Packit 5164a5
        self.doc = doc
Packit 5164a5
        self.indices = {}
Packit 5164a5
        self.defaults = []
Packit 5164a5
        self.commands = {}
Packit 5164a5
        doc.parser.add_hook("makeindex", self.makeindex)
Packit 5164a5
        doc.parser.add_hook("newindex", self.newindex)
Packit 5164a5
Packit 5164a5
    def register (self, name, idx, ind, ilg):
Packit 5164a5
        """
Packit 5164a5
        Register a new index.
Packit 5164a5
        """
Packit 5164a5
        index = self.indices[name] = Index(self.doc, idx, ind, ilg)
Packit 5164a5
        for cmd in self.defaults:
Packit 5164a5
            index.command(*cmd)
Packit 5164a5
        if self.commands.has_key(name):
Packit 5164a5
            for cmd in self.commands[name]:
Packit 5164a5
                index.command(*cmd)
Packit 5164a5
Packit 5164a5
    def makeindex (self, dict):
Packit 5164a5
        """
Packit 5164a5
        Register the standard index.
Packit 5164a5
        """
Packit 5164a5
        self.register("default", "idx", "ind", "ilg")
Packit 5164a5
Packit 5164a5
    def newindex (self, dict):
Packit 5164a5
        """
Packit 5164a5
        Register a new index.
Packit 5164a5
        """
Packit 5164a5
        m = re_newindex.match(dict["line"])
Packit 5164a5
        if not m:
Packit 5164a5
            return
Packit 5164a5
        index = dict["arg"]
Packit 5164a5
        d = m.groupdict()
Packit 5164a5
        self.register(index, d["idx"], d["ind"], "ilg")
Packit 5164a5
        msg.log(_("index %s registered") % index, pkg="index")
Packit 5164a5
Packit 5164a5
    def command (self, cmd, args):
Packit 5164a5
        indices = self.indices
Packit 5164a5
        names = None
Packit 5164a5
        if len(args) > 0:
Packit 5164a5
            m = re_optarg.match(args[0])
Packit 5164a5
            if m:
Packit 5164a5
                names = m.group("list").split(",")
Packit 5164a5
                args = args[1:]
Packit 5164a5
        if names is None:
Packit 5164a5
            self.defaults.append([cmd, args])
Packit 5164a5
            names = indices.keys()
Packit 5164a5
        for index in names:
Packit 5164a5
            if indices.has_key(index):
Packit 5164a5
                indices[index].command(cmd, args[1:])
Packit 5164a5
            elif self.commands.has_key(index):
Packit 5164a5
                self.commands[index].append([cmd, args])
Packit 5164a5
            else:
Packit 5164a5
                self.commands[index] = [[cmd, args]]
Packit 5164a5
Packit 5164a5
    def post_compile (self):
Packit 5164a5
        for index in self.indices.values():
Packit 5164a5
            if index.post_compile():
Packit 5164a5
                return 1
Packit 5164a5
        return 0
Packit 5164a5
Packit 5164a5
    def clean (self):
Packit 5164a5
        for index in self.indices.values():
Packit 5164a5
            index.clean()
Packit 5164a5
        return 0
Packit 5164a5