diff options
Diffstat (limited to 'src/engine/SCons/Scanner/LaTeX.py')
| -rw-r--r-- | src/engine/SCons/Scanner/LaTeX.py | 129 | 
1 files changed, 88 insertions, 41 deletions
diff --git a/src/engine/SCons/Scanner/LaTeX.py b/src/engine/SCons/Scanner/LaTeX.py index 0a68b7e..69154bd 100644 --- a/src/engine/SCons/Scanner/LaTeX.py +++ b/src/engine/SCons/Scanner/LaTeX.py @@ -5,7 +5,7 @@ This module implements the dependency scanner for LaTeX code.  """  # -# Copyright (c) 2001 - 2016 The SCons Foundation +# Copyright (c) 2001 - 2017 The SCons Foundation  #  # Permission is hereby granted, free of charge, to any person obtaining  # a copy of this software and associated documentation files (the @@ -27,7 +27,7 @@ This module implements the dependency scanner for LaTeX code.  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  # -__revision__ = "src/engine/SCons/Scanner/LaTeX.py rel_2.5.1:3735:9dc6cee5c168 2016/11/03 14:02:02 bdbaddog" +__revision__ = "src/engine/SCons/Scanner/LaTeX.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"  import os.path  import re @@ -37,7 +37,9 @@ import SCons.Util  # list of graphics file extensions for TeX and LaTeX  TexGraphics   = ['.eps', '.ps'] -LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] +#LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif'] +LatexGraphics = [ '.png', '.jpg', '.gif', '.tif'] +  # Used as a return value of modify_env_var if the variable is not set.  class _Null(object): @@ -76,8 +78,10 @@ def modify_env_var(env, var, abspath):      return save  class FindENVPathDirs(object): -    """A class to bind a specific *PATH variable name to a function that -    will return all of the *path directories.""" +    """ +    A class to bind a specific E{*}PATH variable name to a function that +    will return all of the E{*}path directories. +    """      def __init__(self, variable):          self.variable = variable      def __call__(self, env, dir=None, target=None, source=None, argument=None): @@ -94,7 +98,8 @@ class FindENVPathDirs(object):  def LaTeXScanner(): -    """Return a prototype Scanner instance for scanning LaTeX source files +    """ +    Return a prototype Scanner instance for scanning LaTeX source files      when built with latex.      """      ds = LaTeX(name = "LaTeXScanner", @@ -105,7 +110,8 @@ def LaTeXScanner():      return ds  def PDFLaTeXScanner(): -    """Return a prototype Scanner instance for scanning LaTeX source files +    """ +    Return a prototype Scanner instance for scanning LaTeX source files      when built with pdflatex.      """      ds = LaTeX(name = "PDFLaTeXScanner", @@ -116,7 +122,8 @@ def PDFLaTeXScanner():      return ds  class LaTeX(SCons.Scanner.Base): -    """Class for scanning LaTeX files for included files. +    """ +    Class for scanning LaTeX files for included files.      Unlike most scanners, which use regular expressions that just      return the included file name, this returns a tuple consisting @@ -133,10 +140,12 @@ class LaTeX(SCons.Scanner.Base):      The actual subset and search order may be altered by      DeclareGraphicsExtensions command. This complication is ignored. -    The default order corresponds to experimentation with teTeX +    The default order corresponds to experimentation with teTeX:: +          $ latex --version          pdfeTeX 3.141592-1.21a-2.2 (Web2C 7.5.4)          kpathsea version 3.5.4 +      The order is:          ['.eps', '.ps'] for latex          ['.png', '.pdf', '.jpg', '.tif']. @@ -148,8 +157,7 @@ class LaTeX(SCons.Scanner.Base):      env['TEXINPUTS'] for "lstinputlisting" keyword      env['BIBINPUTS'] for "bibliography" keyword      env['BSTINPUTS'] for "bibliographystyle" keyword -    env['INDEXSTYLE'] for "makeindex" keyword, no scanning support needed -                      just allows user to set it if needed. +    env['INDEXSTYLE'] for "makeindex" keyword, no scanning support needed just allows user to set it if needed.      FIXME: also look for the class or style in document[class|style]{}      FIXME: also look for the argument of bibliographystyle{} @@ -166,6 +174,9 @@ class LaTeX(SCons.Scanner.Base):                       'usepackage': 'TEXINPUTS',                       'lstinputlisting': 'TEXINPUTS'}      env_variables = SCons.Util.unique(list(keyword_paths.values())) +    two_arg_commands = ['import', 'subimport', +                        'includefrom', 'subincludefrom', +                        'inputfrom', 'subinputfrom']      def __init__(self, name, suffixes, graphics_extensions, *args, **kw): @@ -175,8 +186,29 @@ class LaTeX(SCons.Scanner.Base):          # line followed by one or more newline characters (i.e. blank          # lines), interfering with a match on the next line.          # add option for whitespace before the '[options]' or the '{filename}' -        regex = r'^[^%\n]*\\(include|includegraphics(?:\s*\[[^\]]+\])?|lstinputlisting(?:\[[^\]]+\])?|input|bibliography|addbibresource|addglobalbib|addsectionbib|usepackage)\s*{([^}]*)}' -        self.cre = re.compile(regex, re.M) +        regex = r''' +            ^[^%\n]* +            \\( +                include +              | includegraphics(?:\s*\[[^\]]+\])? +              | lstinputlisting(?:\[[^\]]+\])? +              | input +              | import +              | subimport +              | includefrom +              | subincludefrom +              | inputfrom +              | subinputfrom +              | bibliography +              | addbibresource +              | addglobalbib +              | addsectionbib +              | usepackage +              ) +                  \s*{([^}]*)}       # first arg +              (?: \s*{([^}]*)} )?    # maybe another arg +        ''' +        self.cre = re.compile(regex, re.M | re.X)          self.comment_re = re.compile(r'^((?:(?:\\%)|[^%\n])*)(.*)$', re.M)          self.graphics_extensions = graphics_extensions @@ -236,23 +268,26 @@ class LaTeX(SCons.Scanner.Base):          SCons.Scanner.Base.__init__(self, *args, **kw) -    def _latex_names(self, include): -        filename = include[1] -        if include[0] == 'input': +    def _latex_names(self, include_type, filename): +        if include_type == 'input': +            base, ext = os.path.splitext( filename ) +            if ext == "": +                return [filename + '.tex'] +        if include_type in ('include', 'import', 'subimport', +                            'includefrom', 'subincludefrom', +                            'inputfrom', 'subinputfrom'):              base, ext = os.path.splitext( filename )              if ext == "":                  return [filename + '.tex'] -        if (include[0] == 'include'): -            return [filename + '.tex'] -        if include[0] == 'bibliography': +        if include_type == 'bibliography':              base, ext = os.path.splitext( filename )              if ext == "":                  return [filename + '.bib'] -        if include[0] == 'usepackage': +        if include_type == 'usepackage':              base, ext = os.path.splitext( filename )              if ext == "":                  return [filename + '.sty'] -        if include[0] == 'includegraphics': +        if include_type == 'includegraphics':              base, ext = os.path.splitext( filename )              if ext == "":                  #return [filename+e for e in self.graphics_extensions + TexGraphics] @@ -267,21 +302,26 @@ class LaTeX(SCons.Scanner.Base):          return SCons.Node.FS._my_normcase(str(include))      def find_include(self, include, source_dir, path): +        inc_type, inc_subdir, inc_filename = include          try: -            sub_path = path[include[0]] +            sub_paths = path[inc_type]          except (IndexError, KeyError): -            sub_path = () -        try_names = self._latex_names(include) +            sub_paths = ((), ()) +        try_names = self._latex_names(inc_type, inc_filename) + +        # There are three search paths to try: +        #  1. current directory "source_dir" +        #  2. env[var] +        #  3. env['ENV'][var] +        search_paths = [(source_dir,)] + list(sub_paths) +          for n in try_names: -            # see if we find it using the path in env[var] -            i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[0]) -            if i: -                return i, include -            # see if we find it using the path in env['ENV'][var] -            i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[1]) -            if i: -                return i, include -        return i, include +            for search_path in search_paths: +                paths = tuple([d.Dir(inc_subdir) for d in search_path]) +                i = SCons.Node.FS.find_file(n, paths) +                if i: +                    return i, include +        return None, include      def canonical_text(self, text):          """Standardize an input TeX-file contents. @@ -300,7 +340,7 @@ class LaTeX(SCons.Scanner.Base):              line_continues_a_comment = len(comment) > 0          return '\n'.join(out).rstrip()+'\n' -    def scan(self, node): +    def scan(self, node, subdir='.'):          # Modify the default scan function to allow for the regular          # expression to return a comma separated list of file names          # as can be the case with the bibliography keyword. @@ -326,9 +366,14 @@ class LaTeX(SCons.Scanner.Base):              split_includes = []              for include in includes:                  inc_type = noopt_cre.sub('', include[0]) -                inc_list = include[1].split(',') +                inc_subdir = subdir +                if inc_type in self.two_arg_commands: +                    inc_subdir = os.path.join(subdir, include[1]) +                    inc_list = include[2].split(',') +                else: +                    inc_list = include[1].split(',')                  for j in range(len(inc_list)): -                    split_includes.append( (inc_type, inc_list[j]) ) +                    split_includes.append( (inc_type, inc_subdir, inc_list[j]) )              #              includes = split_includes              node.includes = includes @@ -359,11 +404,13 @@ class LaTeX(SCons.Scanner.Base):          while queue:              include = queue.pop() +            inc_type, inc_subdir, inc_filename = include +              try: -                if seen[include[1]] == 1: +                if seen[inc_filename] == 1:                      continue              except KeyError: -                seen[include[1]] = 1 +                seen[inc_filename] = 1              #              # Handle multiple filenames in include[1] @@ -372,14 +419,14 @@ class LaTeX(SCons.Scanner.Base):              if n is None:                  # Do not bother with 'usepackage' warnings, as they most                  # likely refer to system-level files -                if include[0] != 'usepackage': +                if inc_type != 'usepackage':                      SCons.Warnings.warn(SCons.Warnings.DependencyWarning,                                          "No dependency generated for file: %s (included from: %s) -- file not found" % (i, node))              else:                  sortkey = self.sort_key(n)                  nodes.append((sortkey, n)) -                # recurse down  -                queue.extend( self.scan(n) ) +                # recurse down +                queue.extend( self.scan(n, inc_subdir) )          return [pair[1] for pair in sorted(nodes)]  | 
