• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3
2#
3# Copyright (c) 2013-2014 The Khronos Group Inc.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and/or associated documentation files (the
7# "Materials"), to deal in the Materials without restriction, including
8# without limitation the rights to use, copy, modify, merge, publish,
9# distribute, sublicense, and/or sell copies of the Materials, and to
10# permit persons to whom the Materials are furnished to do so, subject to
11# the following conditions:
12#
13# The above copyright notice and this permission notice shall be included
14# in all copies or substantial portions of the Materials.
15#
16# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
23
24import io, os, re, string, sys;
25
26if __name__ == '__main__':
27    if (len(sys.argv) != 5):
28        print('Usage:', sys.argv[0], ' gendir srcdir accordfilename flatfilename', file=sys.stderr)
29        exit(1)
30    else:
31        gendir = sys.argv[1]
32        srcdir = sys.argv[2]
33        accordfilename = sys.argv[3]
34        flatfilename = sys.argv[4]
35        # print(' gendir = ', gendir, ' srcdir = ', srcdir, 'accordfilename = ', accordfilename, 'flatfilename = ', flatfilename)
36else:
37    print('Unknown invocation mode', file=sys.stderr)
38    exit(1)
39
40# Various levels of indentation in generated HTML
41ind1 = '    '
42ind2 = ind1 + ind1
43ind3 = ind2 + ind1
44ind4 = ind2 + ind2
45
46# Symbolic names
47notAlias = False
48isAlias = True
49
50# Page title
51pageTitle = 'EGL Reference Pages'
52
53# Docbook source and generated HTML 5 file extensions
54srcext = '.xml'
55genext = '.xhtml'
56
57# List of generated files
58files = os.listdir(gendir)
59
60# Feature - class representing a command or function to be indexed, used
61# as dictionary values keyed by the feature name to be indexed.
62#
63# Members
64#   file - name of file containing the feature
65#   feature - feature name for the index (basis for the dictionary key).
66#   alias - True if this is an alias of another feature in the file.
67#       Usually if alias is False, feature is the basename of file.
68#   apiCommand - True if this is an API command, or should be grouped
69#       like one
70class Feature:
71    def __init__(self,
72                 file = None,
73                 feature = None,
74                 alias = False,
75                 apiCommand = None):
76        self.file = file
77        self.feature = feature
78        self.alias = alias
79        self.apiCommand = apiCommand
80        # This is the API-dependent command prefix
81        self.prefix = 'egl'
82        self.prefixLen = len(self.prefix)
83    def makeKey(self):
84        # Return dictionary / sort key based on the feature name
85        if (self.apiCommand and self.feature[0:self.prefixLen]
86              == self.prefix):
87            return self.feature[self.prefixLen:]
88        else:
89            return self.feature
90
91# Add dictionary entry for specified Feature.
92# The key used is the feature name, with the leading 'gl' stripped
93#  off if this is an API command
94def addkey(dict, feature):
95    key = feature.makeKey()
96    if (key in dict.keys()):
97        print('Key', key, ' already exists in dictionary!')
98    else:
99        dict[key] = feature
100
101# Create list of entry point names to be indexed.
102# Unlike the old Perl script, this proceeds as follows:
103# - Each .xhtml page with a parent .xml page gets an
104#   index entry for its base name.
105# - Additionally, each <function> tag inside a <funcdef>
106#   in the parent page gets an aliased index entry.
107# - Each .xhtml page *without* a parent is reported but
108#   not indexed.
109# - Each collision in index terms is reported.
110# - Index terms are keys in a dictionary whose entries
111#   are [ pagename, alias, glPrefix ] where pagename is
112#   the base name of the indexed page and alias is True
113#   if this index isn't the same as pagename.
114# - API keys have their glPrefix value set to True,
115#   GLSL keys to False. There is a simplistic way of
116#   telling the files apart based on the file name:
117#
118#   * Everything starting with 'egl[A-Z]' is API
119#   * 'removedTypes.*' is API (more may be added)
120#   * Everything else is GLSL
121
122def isAPIfile(entrypoint):
123    if (re.match('^egl[A-Z]', entrypoint) or entrypoint == 'removedTypes'):
124        return True
125    else:
126        return False
127
128# Dictionary of all keys mapped to Feature values
129refIndex = {}
130
131for file in files:
132    # print('Processing file', file)
133    (entrypoint,ext) = os.path.splitext(file)
134    if (ext == genext):
135        parent = srcdir + '/' + entrypoint + srcext
136        # Determine if this is an API or GLSL page
137        apiCommand = isAPIfile(entrypoint)
138        if (os.path.exists(parent)):
139            addkey(refIndex, Feature(file, entrypoint, False, apiCommand))
140            # Search parent file for <function> tags inside <funcdef> tags
141            # This doesn't search for <varname> inside <fieldsynopsis>, because
142            #   those aren't on the same line and it's hard.
143            fp = open(parent)
144            for line in fp.readlines():
145                # Look for <function> tag contents and add as aliases
146                # Don't add the same key twice
147                for m in re.finditer(r"<funcdef>.*<function>(.*)</function>.*</funcdef>", line):
148                    funcname = m.group(1)
149                    if (funcname != entrypoint):
150                        addkey(refIndex, Feature(file, funcname, True, apiCommand))
151            fp.close()
152        else:
153            print('No parent page for', file, ', will not be indexed')
154
155# Some utility functions for generating the navigation table
156# Opencl_tofc.html uses style.css instead of style-index.css
157# flatMenu - if True, don't include accordion JavaScript,
158#   generating a flat (expanded) menu.
159# letters - if not None, include per-letter links to within
160#   the indices for each letter in the list.
161# altMenu - if not None, the name of the alternate index to
162#   link to.
163def printHeader(fp, flatMenu = False, letters = None, altMenu = None):
164    if (flatMenu):
165        scriptInclude = '    <!-- Don\'t include accord.js -->'
166    else:
167        scriptInclude = '    <?php include \'accord.js\'; ?>'
168
169    print('<html>',
170          '<head>',
171          '    <link rel="stylesheet" type="text/css" href="style-index.css" />',
172          '    <title>' + pageTitle + '</title>',
173               scriptInclude,
174          '</head>',
175          '<body>',
176          sep='\n', file=fp)
177
178    if (altMenu):
179        if (flatMenu):
180            altLabel = '(accordion-style)'
181        else:
182            altLabel = '(flat)'
183        print('    <a href="' + altMenu + '">' +
184              'Use alternate ' + altLabel + ' index' +
185              '</a>', file=fp)
186
187    if (letters):
188        print('    <center>\n<div id="container">', file=fp)
189        for letter in letters:
190            print('        <b><a href="#' +
191                  letter +
192                  '" style="text-decoration:none">' +
193                  letter +
194                  '</a></b> &nbsp;', file=fp)
195        print('    </div>\n</center>', file=fp)
196
197    print('    <div id="navwrap">',
198          '    <ul id="containerul"> <!-- Must wrap entire list for expand/contract -->',
199          '    <li class="Level1">',
200          '        <a href="start.html" target="pagedisplay">Introduction</a>',
201          '    </li>',
202          sep='\n', file=fp)
203
204def printFooter(fp, flatMenu = False):
205    print('    </div> <!-- End containerurl -->', file=fp)
206    if (not flatMenu):
207        print('    <script type="text/javascript">initiate();</script>', file=fp)
208    print('</body>',
209          '</html>',
210          sep='\n', file=fp)
211
212# Add a nav table entry. key = link name, feature = Feature info for key
213def addMenuLink(key, feature, fp):
214    file = feature.file
215    linkname = feature.feature
216
217    print(ind4 + '<li><a href="' + file + '" target="pagedisplay">'
218               + linkname + '</a></li>',
219          sep='\n', file=fp)
220
221# Begin index section for a letter, include an anchor to link to
222def beginLetterSection(letter, fp):
223    print(ind2 + '<a name="' + letter + '"></a>',
224          ind2 + '<li>' + letter,
225          ind3 + '<ul class="Level3">',
226          sep='\n', file=fp)
227
228# End index section for a letter
229def endLetterSection(opentable, fp):
230    if (opentable == 0):
231        return
232    print(ind3 + '</ul> <!-- End Level3 -->',
233          ind2 + '</li>',
234          sep='\n', file=fp)
235
236# Return the keys in a dictionary sorted by name.
237# Select only keys matching whichKeys (see genDict below)
238def sortedKeys(dict, whichKeys):
239    list = []
240    for key in dict.keys():
241        if (whichKeys == 'all' or
242            (whichKeys == 'api' and dict[key].apiCommand) or
243            (whichKeys == 'glsl' and not dict[key].apiCommand)):
244            list.append(key)
245    list.sort(key=str.lower)
246    return list
247
248# Generate accordion menu for this dictionary, titled as specified.
249#
250# If whichKeys is 'all', generate index for all features
251# If whichKeys is 'api', generate index only for API features
252# If whichKeys is 'glsl', generate index only for GLSL features
253#
254# fp is the file to write to
255def genDict(dict, title, whichKeys, fp):
256    print(ind1 + '<li class="Level1">' + title,
257          ind2 + '<ul class="Level2">',
258          sep='\n', file=fp)
259
260    # Print links for sorted keys in each letter section
261    curletter = ''
262    opentable = 0
263
264    # Determine which letters are in the table of contents for this
265    # dictionary. If apiPrefix is set, strip the API prefix from each
266    # key containing it first.
267
268    # Generatesorted list of page indexes. Select keys matching whichKeys.
269    keys = sortedKeys(dict, whichKeys)
270
271    # print('@ Sorted list of page indexes:\n', keys)
272
273    for key in keys:
274        # Character starting this key
275        c = str.lower(key[0])
276
277        if (c != curletter):
278            endLetterSection(opentable, fp)
279            # Start a new subtable for this letter
280            beginLetterSection(c, fp)
281            opentable = 1
282            curletter = c
283        addMenuLink(key, dict[key], fp)
284    endLetterSection(opentable, fp)
285
286    print(ind2 + '</ul> <!-- End Level2 -->',
287          ind1 + '</li> <!-- End Level1 -->',
288          sep='\n', file=fp)
289
290######################################################################
291
292# Generate the accordion menu
293fp = open(accordfilename, 'w')
294printHeader(fp, flatMenu = False, altMenu = flatfilename)
295
296genDict(refIndex, 'EGL Entry Points', 'all', fp)
297
298printFooter(fp, flatMenu = False)
299fp.close()
300
301######################################################################
302
303# Generate the non-accordion menu, with combined API and GLSL sections
304fp = open(flatfilename, 'w')
305
306# Set containing all index letters
307indices = { key[0].lower() for key in refIndex.keys() }
308letters = [c for c in indices]
309letters.sort()
310
311printHeader(fp, flatMenu = True, letters = letters, altMenu = accordfilename)
312
313genDict(refIndex, 'EGL Entry Points', 'all', fp)
314
315printFooter(fp, flatMenu = True)
316fp.close()
317