| #!/usr/bin/python3 |
| # |
| # Copyright (c) 2013-2014 The Khronos Group Inc. |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining a |
| # copy of this software and/or associated documentation files (the |
| # "Materials"), to deal in the Materials without restriction, including |
| # without limitation the rights to use, copy, modify, merge, publish, |
| # distribute, sublicense, and/or sell copies of the Materials, and to |
| # permit persons to whom the Materials are 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 Materials. |
| # |
| # THE MATERIALS ARE 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 |
| # MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. |
| |
| import io, os, re, string, sys; |
| |
| if __name__ == '__main__': |
| if (len(sys.argv) != 5): |
| print('Usage:', sys.argv[0], ' gendir srcdir accordfilename flatfilename', file=sys.stderr) |
| exit(1) |
| else: |
| gendir = sys.argv[1] |
| srcdir = sys.argv[2] |
| accordfilename = sys.argv[3] |
| flatfilename = sys.argv[4] |
| # print(' gendir = ', gendir, ' srcdir = ', srcdir, 'accordfilename = ', accordfilename, 'flatfilename = ', flatfilename) |
| else: |
| print('Unknown invocation mode', file=sys.stderr) |
| exit(1) |
| |
| # Various levels of indentation in generated HTML |
| ind1 = ' ' |
| ind2 = ind1 + ind1 |
| ind3 = ind2 + ind1 |
| ind4 = ind2 + ind2 |
| |
| # Symbolic names |
| notAlias = False |
| isAlias = True |
| |
| # Page title |
| pageTitle = 'EGL Reference Pages' |
| |
| # Docbook source and generated HTML 5 file extensions |
| srcext = '.xml' |
| genext = '.xhtml' |
| |
| # List of generated files |
| files = os.listdir(gendir) |
| |
| # Feature - class representing a command or function to be indexed, used |
| # as dictionary values keyed by the feature name to be indexed. |
| # |
| # Members |
| # file - name of file containing the feature |
| # feature - feature name for the index (basis for the dictionary key). |
| # alias - True if this is an alias of another feature in the file. |
| # Usually if alias is False, feature is the basename of file. |
| # apiCommand - True if this is an API command, or should be grouped |
| # like one |
| class Feature: |
| def __init__(self, |
| file = None, |
| feature = None, |
| alias = False, |
| apiCommand = None): |
| self.file = file |
| self.feature = feature |
| self.alias = alias |
| self.apiCommand = apiCommand |
| # This is the API-dependent command prefix |
| self.prefix = 'egl' |
| self.prefixLen = len(self.prefix) |
| def makeKey(self): |
| # Return dictionary / sort key based on the feature name |
| if (self.apiCommand and self.feature[0:self.prefixLen] |
| == self.prefix): |
| return self.feature[self.prefixLen:] |
| else: |
| return self.feature |
| |
| # Add dictionary entry for specified Feature. |
| # The key used is the feature name, with the leading 'gl' stripped |
| # off if this is an API command |
| def addkey(dict, feature): |
| key = feature.makeKey() |
| if (key in dict.keys()): |
| print('Key', key, ' already exists in dictionary!') |
| else: |
| dict[key] = feature |
| |
| # Create list of entry point names to be indexed. |
| # Unlike the old Perl script, this proceeds as follows: |
| # - Each .xhtml page with a parent .xml page gets an |
| # index entry for its base name. |
| # - Additionally, each <function> tag inside a <funcdef> |
| # in the parent page gets an aliased index entry. |
| # - Each .xhtml page *without* a parent is reported but |
| # not indexed. |
| # - Each collision in index terms is reported. |
| # - Index terms are keys in a dictionary whose entries |
| # are [ pagename, alias, glPrefix ] where pagename is |
| # the base name of the indexed page and alias is True |
| # if this index isn't the same as pagename. |
| # - API keys have their glPrefix value set to True, |
| # GLSL keys to False. There is a simplistic way of |
| # telling the files apart based on the file name: |
| # |
| # * Everything starting with 'egl[A-Z]' is API |
| # * 'removedTypes.*' is API (more may be added) |
| # * Everything else is GLSL |
| |
| def isAPIfile(entrypoint): |
| if (re.match('^egl[A-Z]', entrypoint) or entrypoint == 'removedTypes'): |
| return True |
| else: |
| return False |
| |
| # Dictionary of all keys mapped to Feature values |
| refIndex = {} |
| |
| for file in files: |
| # print('Processing file', file) |
| (entrypoint,ext) = os.path.splitext(file) |
| if (ext == genext): |
| parent = srcdir + '/' + entrypoint + srcext |
| # Determine if this is an API or GLSL page |
| apiCommand = isAPIfile(entrypoint) |
| if (os.path.exists(parent)): |
| addkey(refIndex, Feature(file, entrypoint, False, apiCommand)) |
| # Search parent file for <function> tags inside <funcdef> tags |
| # This doesn't search for <varname> inside <fieldsynopsis>, because |
| # those aren't on the same line and it's hard. |
| fp = open(parent) |
| for line in fp.readlines(): |
| # Look for <function> tag contents and add as aliases |
| # Don't add the same key twice |
| for m in re.finditer(r"<funcdef>.*<function>(.*)</function>.*</funcdef>", line): |
| funcname = m.group(1) |
| if (funcname != entrypoint): |
| addkey(refIndex, Feature(file, funcname, True, apiCommand)) |
| fp.close() |
| else: |
| print('No parent page for', file, ', will not be indexed') |
| |
| # Some utility functions for generating the navigation table |
| # Opencl_tofc.html uses style.css instead of style-index.css |
| # flatMenu - if True, don't include accordion JavaScript, |
| # generating a flat (expanded) menu. |
| # letters - if not None, include per-letter links to within |
| # the indices for each letter in the list. |
| # altMenu - if not None, the name of the alternate index to |
| # link to. |
| def printHeader(fp, flatMenu = False, letters = None, altMenu = None): |
| if (flatMenu): |
| scriptInclude = ' <!-- Don\'t include accord.js -->' |
| else: |
| scriptInclude = ' <?php include \'accord.js\'; ?>' |
| |
| print('<html>', |
| '<head>', |
| ' <link rel="stylesheet" type="text/css" href="style-index.css" />', |
| ' <title>' + pageTitle + '</title>', |
| scriptInclude, |
| '</head>', |
| '<body>', |
| sep='\n', file=fp) |
| |
| if (altMenu): |
| if (flatMenu): |
| altLabel = '(accordion-style)' |
| else: |
| altLabel = '(flat)' |
| print(' <a href="' + altMenu + '">' + |
| 'Use alternate ' + altLabel + ' index' + |
| '</a>', file=fp) |
| |
| if (letters): |
| print(' <center>\n<div id="container">', file=fp) |
| for letter in letters: |
| print(' <b><a href="#' + |
| letter + |
| '" style="text-decoration:none">' + |
| letter + |
| '</a></b> ', file=fp) |
| print(' </div>\n</center>', file=fp) |
| |
| print(' <div id="navwrap">', |
| ' <ul id="containerul"> <!-- Must wrap entire list for expand/contract -->', |
| ' <li class="Level1">', |
| ' <a href="start.html" target="pagedisplay">Introduction</a>', |
| ' </li>', |
| sep='\n', file=fp) |
| |
| def printFooter(fp, flatMenu = False): |
| print(' </div> <!-- End containerurl -->', file=fp) |
| if (not flatMenu): |
| print(' <script type="text/javascript">initiate();</script>', file=fp) |
| print('</body>', |
| '</html>', |
| sep='\n', file=fp) |
| |
| # Add a nav table entry. key = link name, feature = Feature info for key |
| def addMenuLink(key, feature, fp): |
| file = feature.file |
| linkname = feature.feature |
| |
| print(ind4 + '<li><a href="' + file + '" target="pagedisplay">' |
| + linkname + '</a></li>', |
| sep='\n', file=fp) |
| |
| # Begin index section for a letter, include an anchor to link to |
| def beginLetterSection(letter, fp): |
| print(ind2 + '<a name="' + letter + '"></a>', |
| ind2 + '<li>' + letter, |
| ind3 + '<ul class="Level3">', |
| sep='\n', file=fp) |
| |
| # End index section for a letter |
| def endLetterSection(opentable, fp): |
| if (opentable == 0): |
| return |
| print(ind3 + '</ul> <!-- End Level3 -->', |
| ind2 + '</li>', |
| sep='\n', file=fp) |
| |
| # Return the keys in a dictionary sorted by name. |
| # Select only keys matching whichKeys (see genDict below) |
| def sortedKeys(dict, whichKeys): |
| list = [] |
| for key in dict.keys(): |
| if (whichKeys == 'all' or |
| (whichKeys == 'api' and dict[key].apiCommand) or |
| (whichKeys == 'glsl' and not dict[key].apiCommand)): |
| list.append(key) |
| list.sort(key=str.lower) |
| return list |
| |
| # Generate accordion menu for this dictionary, titled as specified. |
| # |
| # If whichKeys is 'all', generate index for all features |
| # If whichKeys is 'api', generate index only for API features |
| # If whichKeys is 'glsl', generate index only for GLSL features |
| # |
| # fp is the file to write to |
| def genDict(dict, title, whichKeys, fp): |
| print(ind1 + '<li class="Level1">' + title, |
| ind2 + '<ul class="Level2">', |
| sep='\n', file=fp) |
| |
| # Print links for sorted keys in each letter section |
| curletter = '' |
| opentable = 0 |
| |
| # Determine which letters are in the table of contents for this |
| # dictionary. If apiPrefix is set, strip the API prefix from each |
| # key containing it first. |
| |
| # Generatesorted list of page indexes. Select keys matching whichKeys. |
| keys = sortedKeys(dict, whichKeys) |
| |
| # print('@ Sorted list of page indexes:\n', keys) |
| |
| for key in keys: |
| # Character starting this key |
| c = str.lower(key[0]) |
| |
| if (c != curletter): |
| endLetterSection(opentable, fp) |
| # Start a new subtable for this letter |
| beginLetterSection(c, fp) |
| opentable = 1 |
| curletter = c |
| addMenuLink(key, dict[key], fp) |
| endLetterSection(opentable, fp) |
| |
| print(ind2 + '</ul> <!-- End Level2 -->', |
| ind1 + '</li> <!-- End Level1 -->', |
| sep='\n', file=fp) |
| |
| ###################################################################### |
| |
| # Generate the accordion menu |
| fp = open(accordfilename, 'w') |
| printHeader(fp, flatMenu = False, altMenu = flatfilename) |
| |
| genDict(refIndex, 'EGL Entry Points', 'all', fp) |
| |
| printFooter(fp, flatMenu = False) |
| fp.close() |
| |
| ###################################################################### |
| |
| # Generate the non-accordion menu, with combined API and GLSL sections |
| fp = open(flatfilename, 'w') |
| |
| # Set containing all index letters |
| indices = { key[0].lower() for key in refIndex.keys() } |
| letters = [c for c in indices] |
| letters.sort() |
| |
| printHeader(fp, flatMenu = True, letters = letters, altMenu = accordfilename) |
| |
| genDict(refIndex, 'EGL Entry Points', 'all', fp) |
| |
| printFooter(fp, flatMenu = True) |
| fp.close() |