Please note:The SCons wiki is now restored from the attack in March 2013. All old passwords have been invalidated. Please reset your password if you have an account. If you note missing pages, please report them to webmaster@scons.org. Also, new account creation is currently disabled due to an ongoing spam flood (2013/08/27).

Attachment 'doxygen.py'

Download

   1 # vim: set et sw=3 tw=0 fo=awqorc ft=python:
   2 #
   3 # Astxx, the Asterisk C++ API and Utility Library.
   4 # Copyright (C) 2005, 2006  Matthew A. Nicholson
   5 # Copyright (C) 2006  Tim Blechmann
   6 #
   7 # This library is free software; you can redistribute it and/or
   8 # modify it under the terms of the GNU Lesser General Public
   9 # License version 2.1 as published by the Free Software Foundation.
  10 #
  11 # This library is distributed in the hope that it will be useful,
  12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 # Lesser General Public License for more details.
  15 #
  16 # You should have received a copy of the GNU Lesser General Public
  17 # License along with this library; if not, write to the Free Software
  18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 
  20 import os
  21 import os.path
  22 import glob
  23 from fnmatch import fnmatch
  24 
  25 def DoxyfileParse(file_contents):
  26    """
  27    Parse a Doxygen source file and return a dictionary of all the values.
  28    Values will be strings and lists of strings.
  29    """
  30    data = {}
  31 
  32    import shlex
  33    lex = shlex.shlex(instream = file_contents, posix = True)
  34    lex.wordchars += "*+./-:"
  35    lex.whitespace = lex.whitespace.replace("\n", "")
  36    lex.escape = ""
  37 
  38    lineno = lex.lineno
  39    token = lex.get_token()
  40    key = token   # the first token should be a key
  41    last_token = ""
  42    key_token = False
  43    next_key = False
  44    new_data = True
  45 
  46    def append_data(data, key, new_data, token):
  47       if new_data or len(data[key]) == 0:
  48          data[key].append(token)
  49       else:
  50          data[key][-1] += token
  51 
  52    while token:
  53       if token in ['\n']:
  54          if last_token not in ['\\']:
  55             key_token = True
  56       elif token in ['\\']:
  57          pass
  58       elif key_token:
  59          key = token
  60          key_token = False
  61       else:
  62          if token == "+=":
  63             if not data.has_key(key):
  64                data[key] = list()
  65          elif token == "=":
  66             if key == "TAGFILES" and data.has_key(key):
  67                append_data( data, key, False, "=" )
  68                new_data=False
  69             else:
  70                data[key] = list()
  71          else:
  72             append_data( data, key, new_data, token )
  73             new_data = True
  74 
  75       last_token = token
  76       token = lex.get_token()
  77 
  78       if last_token == '\\' and token != '\n':
  79          new_data = False
  80          append_data( data, key, new_data, '\\' )
  81 
  82    # compress lists of len 1 into single strings
  83    for (k, v) in data.items():
  84       if len(v) == 0:
  85          data.pop(k)
  86 
  87       # items in the following list will be kept as lists and not converted to strings
  88       if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS", "TAGFILES"]:
  89          continue
  90 
  91       if len(v) == 1:
  92          data[k] = v[0]
  93 
  94    return data
  95 
  96 def DoxySourceScan(node, env, path):
  97    """
  98    Doxygen Doxyfile source scanner.  This should scan the Doxygen file and add
  99    any files used to generate docs to the list of source files.
 100    """
 101    default_file_patterns = [
 102       '*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx',
 103       '*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++',
 104       '*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm',
 105       '*.py',
 106    ]
 107 
 108    default_exclude_patterns = [
 109       '*~',
 110    ]
 111 
 112    sources = []
 113 
 114    data = DoxyfileParse(node.get_contents())
 115 
 116    if data.get("RECURSIVE", "NO") == "YES":
 117       recursive = True
 118    else:
 119       recursive = False
 120 
 121    file_patterns = data.get("FILE_PATTERNS", default_file_patterns)
 122    exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns)
 123 
 124    # We're running in the top-level directory, but the doxygen
 125    # configuration file is in the same directory as node; this means
 126    # that relative pathnames in node must be adjusted before they can
 127    # go onto the sources list
 128    conf_dir = os.path.dirname(str(node))
 129    
 130    for node in data.get("INPUT", []):
 131       if not os.path.isabs(node):
 132          node = os.path.join(conf_dir, node)
 133       if os.path.isfile(node):
 134          sources.append(node)
 135       elif os.path.isdir(node):
 136          if recursive:
 137             for root, dirs, files in os.walk(node):
 138                for f in files:
 139                   filename = os.path.join(root, f)
 140 
 141                   pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False)
 142                   exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True)
 143 
 144                   if pattern_check and not exclude_check:
 145                      sources.append(filename)
 146          else:
 147             for pattern in file_patterns:
 148                sources.extend(glob.glob("/".join([node, pattern])))
 149 
 150    # Add tagfiles to the list of source files:
 151    for node in data.get("TAGFILES", []):
 152       file = node.split("=")[0]
 153       if not os.path.isabs(file):
 154          file = os.path.join(conf_dir, file)
 155       sources.append(file)
 156    
 157    # Add additional files to the list of source files:
 158    def append_additional_source(option):
 159       file = data.get(option, "")
 160       if file != "":
 161          if not os.path.isabs(file):
 162             file = os.path.join(conf_dir, file)
 163          if os.path.isfile(file):
 164             sources.append(file)
 165 
 166    append_additional_source("HTML_STYLESHEET")
 167    append_additional_source("HTML_HEADER")
 168    append_additional_source("HTML_FOOTER")
 169 
 170    sources = map( lambda path: env.File(path), sources )
 171    return sources
 172 
 173 
 174 def DoxySourceScanCheck(node, env):
 175    """Check if we should scan this file"""
 176    return os.path.isfile(node.path)
 177 
 178 def DoxyEmitter(source, target, env):
 179    """Doxygen Doxyfile emitter"""
 180    # possible output formats and their default values and output locations
 181    output_formats = {
 182       "HTML": ("YES", "html"),
 183       "LATEX": ("YES", "latex"),
 184       "RTF": ("NO", "rtf"),
 185       "MAN": ("YES", "man"),
 186       "XML": ("NO", "xml"),
 187    }
 188 
 189    data = DoxyfileParse(source[0].get_contents())
 190 
 191    targets = []
 192    out_dir = data.get("OUTPUT_DIRECTORY", ".")
 193    if not os.path.isabs(out_dir):
 194       conf_dir = os.path.dirname(str(source[0]))
 195       out_dir = os.path.join(conf_dir, out_dir)
 196 
 197    # add our output locations
 198    for (k, v) in output_formats.items():
 199       if data.get("GENERATE_" + k, v[0]) == "YES":
 200          targets.append(env.Dir( os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) )
 201 
 202    # add the tag file if neccessary:
 203    tagfile = data.get("GENERATE_TAGFILE", "")
 204    if tagfile != "":
 205       if not os.path.isabs(tagfile):
 206          conf_dir = os.path.dirname(str(source[0]))
 207          tagfile = os.path.join(conf_dir, tagfile)
 208       targets.append(env.File(tagfile))
 209 
 210    # don't clobber targets
 211    for node in targets:
 212       env.Precious(node)
 213 
 214    # set up cleaning stuff
 215    for node in targets:
 216       env.Clean(node, node)
 217 
 218    return (targets, source)
 219 
 220 def generate(env):
 221    """
 222    Add builders and construction variables for the
 223    Doxygen tool.  This is currently for Doxygen 1.4.6.
 224    """
 225    doxyfile_scanner = env.Scanner(
 226       DoxySourceScan,
 227       "DoxySourceScan",
 228       scan_check = DoxySourceScanCheck,
 229    )
 230 
 231    import SCons.Builder
 232    doxyfile_builder = SCons.Builder.Builder(
 233       action = "cd ${SOURCE.dir}  &&  ${DOXYGEN} ${SOURCE.file}",
 234       emitter = DoxyEmitter,
 235       target_factory = env.fs.Entry,
 236       single_source = True,
 237       source_scanner =  doxyfile_scanner,
 238    )
 239 
 240    env.Append(BUILDERS = {
 241       'Doxygen': doxyfile_builder,
 242    })
 243 
 244    env.AppendUnique(
 245       DOXYGEN = 'doxygen',
 246    )
 247 
 248 def exists(env):
 249    """
 250    Make sure doxygen exists.
 251    """
 252    return env.Detect("doxygen")

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.