1e5c31af7Sopenharmony_ci#!/usr/bin/python3
2e5c31af7Sopenharmony_ci#
3e5c31af7Sopenharmony_ci# Copyright 2016-2024 The Khronos Group Inc.
4e5c31af7Sopenharmony_ci#
5e5c31af7Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0
6e5c31af7Sopenharmony_ci
7e5c31af7Sopenharmony_ci# genRef.py - create API ref pages from spec source files
8e5c31af7Sopenharmony_ci#
9e5c31af7Sopenharmony_ci# Usage: genRef.py files
10e5c31af7Sopenharmony_ci
11e5c31af7Sopenharmony_ciimport argparse
12e5c31af7Sopenharmony_ciimport io
13e5c31af7Sopenharmony_ciimport os
14e5c31af7Sopenharmony_ciimport re
15e5c31af7Sopenharmony_ciimport sys
16e5c31af7Sopenharmony_cifrom collections import OrderedDict
17e5c31af7Sopenharmony_cifrom reflib import (findRefs, fixupRefs, loadFile, logDiag, logWarn, logErr,
18e5c31af7Sopenharmony_ci                    printPageInfo, setLogFile)
19e5c31af7Sopenharmony_cifrom reg import Registry
20e5c31af7Sopenharmony_cifrom generator import GeneratorOptions
21e5c31af7Sopenharmony_cifrom parse_dependency import dependencyNames
22e5c31af7Sopenharmony_cifrom apiconventions import APIConventions
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci
25e5c31af7Sopenharmony_ci# refpage 'type' attributes which are API entities and contain structured
26e5c31af7Sopenharmony_ci# content such as API includes, valid usage blocks, etc.
27e5c31af7Sopenharmony_cirefpage_api_types = (
28e5c31af7Sopenharmony_ci    'basetypes',
29e5c31af7Sopenharmony_ci    'consts',
30e5c31af7Sopenharmony_ci    'defines',
31e5c31af7Sopenharmony_ci    'enums',
32e5c31af7Sopenharmony_ci    'flags',
33e5c31af7Sopenharmony_ci    'funcpointers',
34e5c31af7Sopenharmony_ci    'handles',
35e5c31af7Sopenharmony_ci    'protos',
36e5c31af7Sopenharmony_ci    'structs',
37e5c31af7Sopenharmony_ci)
38e5c31af7Sopenharmony_ci
39e5c31af7Sopenharmony_ci# Other refpage types - SPIR-V builtins, API feature blocks, etc. - which do
40e5c31af7Sopenharmony_ci# not have structured content.
41e5c31af7Sopenharmony_cirefpage_other_types = (
42e5c31af7Sopenharmony_ci    'builtins',
43e5c31af7Sopenharmony_ci    'feature',
44e5c31af7Sopenharmony_ci    'freeform',
45e5c31af7Sopenharmony_ci    'spirv'
46e5c31af7Sopenharmony_ci)
47e5c31af7Sopenharmony_ci
48e5c31af7Sopenharmony_ci
49e5c31af7Sopenharmony_cidef makeExtensionInclude(name):
50e5c31af7Sopenharmony_ci    """Return an include command for a generated extension interface.
51e5c31af7Sopenharmony_ci       - name - extension name"""
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_ci    return 'include::{}/meta/refpage.{}{}[]'.format(
54e5c31af7Sopenharmony_ci            conventions.generated_include_path,
55e5c31af7Sopenharmony_ci            name,
56e5c31af7Sopenharmony_ci            conventions.file_suffix)
57e5c31af7Sopenharmony_ci
58e5c31af7Sopenharmony_ci
59e5c31af7Sopenharmony_cidef makeAPIInclude(type, name):
60e5c31af7Sopenharmony_ci    """Return an include command for a generated API interface
61e5c31af7Sopenharmony_ci       - type - type of the API, e.g. 'flags', 'handles', etc
62e5c31af7Sopenharmony_ci       - name - name of the API"""
63e5c31af7Sopenharmony_ci
64e5c31af7Sopenharmony_ci    return 'include::{}/api/{}/{}{}\n'.format(
65e5c31af7Sopenharmony_ci            conventions.generated_include_path,
66e5c31af7Sopenharmony_ci            type, name, conventions.file_suffix)
67e5c31af7Sopenharmony_ci
68e5c31af7Sopenharmony_ci
69e5c31af7Sopenharmony_cidef isextension(name):
70e5c31af7Sopenharmony_ci    """Return True if name is an API extension name (ends with an upper-case
71e5c31af7Sopenharmony_ci    author ID).
72e5c31af7Sopenharmony_ci
73e5c31af7Sopenharmony_ci    This assumes that author IDs are at least two characters."""
74e5c31af7Sopenharmony_ci    return name[-2:].isalpha() and name[-2:].isupper()
75e5c31af7Sopenharmony_ci
76e5c31af7Sopenharmony_ci
77e5c31af7Sopenharmony_cidef printCopyrightSourceComments(fp):
78e5c31af7Sopenharmony_ci    """Print Khronos CC-BY copyright notice on open file fp.
79e5c31af7Sopenharmony_ci
80e5c31af7Sopenharmony_ci    Writes an asciidoc comment block, which copyrights the source
81e5c31af7Sopenharmony_ci    file."""
82e5c31af7Sopenharmony_ci    print('// Copyright 2014-2024 The Khronos Group Inc.', file=fp)
83e5c31af7Sopenharmony_ci    print('//', file=fp)
84e5c31af7Sopenharmony_ci    # This works around constraints of the 'reuse' tool
85e5c31af7Sopenharmony_ci    print('// SPDX' + '-License-Identifier: CC-BY-4.0', file=fp)
86e5c31af7Sopenharmony_ci    print('', file=fp)
87e5c31af7Sopenharmony_ci
88e5c31af7Sopenharmony_ci
89e5c31af7Sopenharmony_cidef printFooter(fp, leveloffset=0):
90e5c31af7Sopenharmony_ci    """Print footer material at the end of each refpage on open file fp.
91e5c31af7Sopenharmony_ci
92e5c31af7Sopenharmony_ci    If generating separate refpages, adds the copyright.
93e5c31af7Sopenharmony_ci    If generating the single combined refpage, just add a separator.
94e5c31af7Sopenharmony_ci
95e5c31af7Sopenharmony_ci    - leveloffset - number of levels to bias section titles up or down."""
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_ci    # Generate the section header.
98e5c31af7Sopenharmony_ci    # Default depth is 2.
99e5c31af7Sopenharmony_ci    depth = max(0, leveloffset + 2)
100e5c31af7Sopenharmony_ci    prefix = '=' * depth
101e5c31af7Sopenharmony_ci
102e5c31af7Sopenharmony_ci    print('ifdef::doctype-manpage[]',
103e5c31af7Sopenharmony_ci          f'{prefix} Copyright',
104e5c31af7Sopenharmony_ci          '',
105e5c31af7Sopenharmony_ci          'include::{config}/copyright-ccby' + conventions.file_suffix + '[]',
106e5c31af7Sopenharmony_ci          'endif::doctype-manpage[]',
107e5c31af7Sopenharmony_ci          '',
108e5c31af7Sopenharmony_ci          'ifndef::doctype-manpage[]',
109e5c31af7Sopenharmony_ci          '<<<',
110e5c31af7Sopenharmony_ci          'endif::doctype-manpage[]',
111e5c31af7Sopenharmony_ci          '',
112e5c31af7Sopenharmony_ci          sep='\n', file=fp)
113e5c31af7Sopenharmony_ci
114e5c31af7Sopenharmony_ci
115e5c31af7Sopenharmony_cidef macroPrefix(name):
116e5c31af7Sopenharmony_ci    """Add a spec asciidoc macro prefix to an API name, depending on its type
117e5c31af7Sopenharmony_ci    (protos, structs, enums, etc.).
118e5c31af7Sopenharmony_ci
119e5c31af7Sopenharmony_ci    If the name is not recognized, use the generic link macro 'reflink:'."""
120e5c31af7Sopenharmony_ci    if name in api.basetypes:
121e5c31af7Sopenharmony_ci        return 'basetype:' + name
122e5c31af7Sopenharmony_ci    if name in api.defines:
123e5c31af7Sopenharmony_ci        return 'dlink:' + name
124e5c31af7Sopenharmony_ci    if name in api.enums:
125e5c31af7Sopenharmony_ci        return 'elink:' + name
126e5c31af7Sopenharmony_ci    if name in api.flags:
127e5c31af7Sopenharmony_ci        return 'tlink:' + name
128e5c31af7Sopenharmony_ci    if name in api.funcpointers:
129e5c31af7Sopenharmony_ci        return 'tlink:' + name
130e5c31af7Sopenharmony_ci    if name in api.handles:
131e5c31af7Sopenharmony_ci        return 'slink:' + name
132e5c31af7Sopenharmony_ci    if name in api.protos:
133e5c31af7Sopenharmony_ci        return 'flink:' + name
134e5c31af7Sopenharmony_ci    if name in api.structs:
135e5c31af7Sopenharmony_ci        return 'slink:' + name
136e5c31af7Sopenharmony_ci    if name == 'TBD':
137e5c31af7Sopenharmony_ci        return 'No cross-references are available'
138e5c31af7Sopenharmony_ci    return 'reflink:' + name
139e5c31af7Sopenharmony_ci
140e5c31af7Sopenharmony_ci
141e5c31af7Sopenharmony_cidef seeAlsoList(apiName, explicitRefs=None, apiAliases=[]):
142e5c31af7Sopenharmony_ci    """Return an asciidoc string with a list of 'See Also' references for the
143e5c31af7Sopenharmony_ci    API entity 'apiName', based on the relationship mapping in the api module.
144e5c31af7Sopenharmony_ci
145e5c31af7Sopenharmony_ci    'explicitRefs' is a list of additional cross-references.
146e5c31af7Sopenharmony_ci
147e5c31af7Sopenharmony_ci    If apiAliases is not None, it is a list of aliases of apiName whose
148e5c31af7Sopenharmony_ci    cross-references will also be included.
149e5c31af7Sopenharmony_ci
150e5c31af7Sopenharmony_ci    If no relationships are available, return None."""
151e5c31af7Sopenharmony_ci
152e5c31af7Sopenharmony_ci    refs = set(())
153e5c31af7Sopenharmony_ci
154e5c31af7Sopenharmony_ci    # apiName and its aliases are treated equally
155e5c31af7Sopenharmony_ci    allApis = apiAliases.copy()
156e5c31af7Sopenharmony_ci    allApis.append(apiName)
157e5c31af7Sopenharmony_ci
158e5c31af7Sopenharmony_ci    # Add all the implicit references to refs
159e5c31af7Sopenharmony_ci    for name in allApis:
160e5c31af7Sopenharmony_ci        if name in api.mapDict:
161e5c31af7Sopenharmony_ci            refs.update(api.mapDict[name])
162e5c31af7Sopenharmony_ci
163e5c31af7Sopenharmony_ci    # Add all the explicit references
164e5c31af7Sopenharmony_ci    if explicitRefs is not None:
165e5c31af7Sopenharmony_ci        if isinstance(explicitRefs, str):
166e5c31af7Sopenharmony_ci            explicitRefs = explicitRefs.split()
167e5c31af7Sopenharmony_ci        refs.update(name for name in explicitRefs)
168e5c31af7Sopenharmony_ci
169e5c31af7Sopenharmony_ci    # Add extensions / core versions based on dependencies
170e5c31af7Sopenharmony_ci    for name in allApis:
171e5c31af7Sopenharmony_ci        if name in api.requiredBy:
172e5c31af7Sopenharmony_ci            for (base,dependency) in api.requiredBy[name]:
173e5c31af7Sopenharmony_ci                refs.add(base)
174e5c31af7Sopenharmony_ci                if dependency is not None:
175e5c31af7Sopenharmony_ci                    # 'dependency' may be a boolean expression of extension
176e5c31af7Sopenharmony_ci                    # names.
177e5c31af7Sopenharmony_ci                    # Extract them for use in cross-references.
178e5c31af7Sopenharmony_ci                    for extname in dependencyNames(dependency):
179e5c31af7Sopenharmony_ci                        refs.add(extname)
180e5c31af7Sopenharmony_ci
181e5c31af7Sopenharmony_ci    if len(refs) == 0:
182e5c31af7Sopenharmony_ci        return None
183e5c31af7Sopenharmony_ci    else:
184e5c31af7Sopenharmony_ci        return ', '.join(macroPrefix(name) for name in sorted(refs)) + '\n'
185e5c31af7Sopenharmony_ci
186e5c31af7Sopenharmony_ci
187e5c31af7Sopenharmony_cidef remapIncludes(lines, baseDir, specDir):
188e5c31af7Sopenharmony_ci    """Remap include directives in a list of lines so they can be extracted to a
189e5c31af7Sopenharmony_ci    different directory.
190e5c31af7Sopenharmony_ci
191e5c31af7Sopenharmony_ci    Returns remapped lines.
192e5c31af7Sopenharmony_ci
193e5c31af7Sopenharmony_ci    - lines - text to remap
194e5c31af7Sopenharmony_ci    - baseDir - target directory
195e5c31af7Sopenharmony_ci    - specDir - source directory"""
196e5c31af7Sopenharmony_ci    # This should be compiled only once
197e5c31af7Sopenharmony_ci    includePat = re.compile(r'^include::(?P<path>.*)\[\]')
198e5c31af7Sopenharmony_ci
199e5c31af7Sopenharmony_ci    newLines = []
200e5c31af7Sopenharmony_ci    for line in lines:
201e5c31af7Sopenharmony_ci        matches = includePat.search(line)
202e5c31af7Sopenharmony_ci        if matches is not None:
203e5c31af7Sopenharmony_ci            path = matches.group('path')
204e5c31af7Sopenharmony_ci
205e5c31af7Sopenharmony_ci            if path[0] != '{':
206e5c31af7Sopenharmony_ci                # Relative path to include file from here
207e5c31af7Sopenharmony_ci                incPath = specDir + '/' + path
208e5c31af7Sopenharmony_ci                # Remap to be relative to baseDir
209e5c31af7Sopenharmony_ci                newPath = os.path.relpath(incPath, baseDir)
210e5c31af7Sopenharmony_ci                newLine = 'include::' + newPath + '[]\n'
211e5c31af7Sopenharmony_ci                logDiag('remapIncludes: remapping', line, '->', newLine)
212e5c31af7Sopenharmony_ci                newLines.append(newLine)
213e5c31af7Sopenharmony_ci            else:
214e5c31af7Sopenharmony_ci                # An asciidoctor variable starts the path.
215e5c31af7Sopenharmony_ci                # This must be an absolute path, not needing to be rewritten.
216e5c31af7Sopenharmony_ci                newLines.append(line)
217e5c31af7Sopenharmony_ci        else:
218e5c31af7Sopenharmony_ci            newLines.append(line)
219e5c31af7Sopenharmony_ci    return newLines
220e5c31af7Sopenharmony_ci
221e5c31af7Sopenharmony_ci
222e5c31af7Sopenharmony_cidef refPageShell(pageName, pageDesc, fp, head_content = None, sections=None, tail_content=None, man_section=3):
223e5c31af7Sopenharmony_ci    """Generate body of a reference page.
224e5c31af7Sopenharmony_ci
225e5c31af7Sopenharmony_ci    - pageName - string name of the page
226e5c31af7Sopenharmony_ci    - pageDesc - string short description of the page
227e5c31af7Sopenharmony_ci    - fp - file to write to
228e5c31af7Sopenharmony_ci    - head_content - text to include before the sections
229e5c31af7Sopenharmony_ci    - sections - iterable returning (title,body) for each section.
230e5c31af7Sopenharmony_ci    - tail_content - text to include after the sections
231e5c31af7Sopenharmony_ci    - man_section - Unix man page section"""
232e5c31af7Sopenharmony_ci
233e5c31af7Sopenharmony_ci    printCopyrightSourceComments(fp)
234e5c31af7Sopenharmony_ci
235e5c31af7Sopenharmony_ci    print(':data-uri:',
236e5c31af7Sopenharmony_ci          ':icons: font',
237e5c31af7Sopenharmony_ci          ':attribute-missing: warn',
238e5c31af7Sopenharmony_ci          conventions.extra_refpage_headers,
239e5c31af7Sopenharmony_ci          '',
240e5c31af7Sopenharmony_ci          sep='\n', file=fp)
241e5c31af7Sopenharmony_ci
242e5c31af7Sopenharmony_ci    s = '{}({})'.format(pageName, man_section)
243e5c31af7Sopenharmony_ci    print('= ' + s,
244e5c31af7Sopenharmony_ci          '',
245e5c31af7Sopenharmony_ci          conventions.extra_refpage_body,
246e5c31af7Sopenharmony_ci          '',
247e5c31af7Sopenharmony_ci          sep='\n', file=fp)
248e5c31af7Sopenharmony_ci    if pageDesc.strip() == '':
249e5c31af7Sopenharmony_ci        pageDesc = 'NO SHORT DESCRIPTION PROVIDED'
250e5c31af7Sopenharmony_ci        logWarn('refPageHead: no short description provided for', pageName)
251e5c31af7Sopenharmony_ci
252e5c31af7Sopenharmony_ci    print('== Name',
253e5c31af7Sopenharmony_ci          '{} - {}'.format(pageName, pageDesc),
254e5c31af7Sopenharmony_ci          '',
255e5c31af7Sopenharmony_ci          sep='\n', file=fp)
256e5c31af7Sopenharmony_ci
257e5c31af7Sopenharmony_ci    if head_content is not None:
258e5c31af7Sopenharmony_ci        print(head_content,
259e5c31af7Sopenharmony_ci              '',
260e5c31af7Sopenharmony_ci              sep='\n', file=fp)
261e5c31af7Sopenharmony_ci
262e5c31af7Sopenharmony_ci    if sections is not None:
263e5c31af7Sopenharmony_ci        for title, content in sections.items():
264e5c31af7Sopenharmony_ci            print('== {}'.format(title),
265e5c31af7Sopenharmony_ci                  '',
266e5c31af7Sopenharmony_ci                  content,
267e5c31af7Sopenharmony_ci                  '',
268e5c31af7Sopenharmony_ci                  sep='\n', file=fp)
269e5c31af7Sopenharmony_ci
270e5c31af7Sopenharmony_ci    if tail_content is not None:
271e5c31af7Sopenharmony_ci        print(tail_content,
272e5c31af7Sopenharmony_ci              '',
273e5c31af7Sopenharmony_ci              sep='\n', file=fp)
274e5c31af7Sopenharmony_ci
275e5c31af7Sopenharmony_ci
276e5c31af7Sopenharmony_cidef refPageHead(pageName, pageDesc, specText, fieldName, fieldText, descText, fp):
277e5c31af7Sopenharmony_ci    """Generate header of a reference page.
278e5c31af7Sopenharmony_ci
279e5c31af7Sopenharmony_ci    - pageName - string name of the page
280e5c31af7Sopenharmony_ci    - pageDesc - string short description of the page
281e5c31af7Sopenharmony_ci    - specType - string containing 'spec' field from refpage open block, or None.
282e5c31af7Sopenharmony_ci      Used to determine containing spec name and URL.
283e5c31af7Sopenharmony_ci    - specText - string that goes in the "C Specification" section
284e5c31af7Sopenharmony_ci    - fieldName - string heading an additional section following specText, if not None
285e5c31af7Sopenharmony_ci    - fieldText - string that goes in the additional section
286e5c31af7Sopenharmony_ci    - descText - string that goes in the "Description" section
287e5c31af7Sopenharmony_ci    - fp - file to write to"""
288e5c31af7Sopenharmony_ci    sections = OrderedDict()
289e5c31af7Sopenharmony_ci
290e5c31af7Sopenharmony_ci    if specText is not None:
291e5c31af7Sopenharmony_ci        sections['C Specification'] = specText
292e5c31af7Sopenharmony_ci
293e5c31af7Sopenharmony_ci    if fieldName is not None:
294e5c31af7Sopenharmony_ci        sections[fieldName] = fieldText
295e5c31af7Sopenharmony_ci
296e5c31af7Sopenharmony_ci    if descText is None or descText.strip() == '':
297e5c31af7Sopenharmony_ci        logWarn('refPageHead: no description provided for', pageName)
298e5c31af7Sopenharmony_ci
299e5c31af7Sopenharmony_ci    if descText is not None:
300e5c31af7Sopenharmony_ci        sections['Description'] = descText
301e5c31af7Sopenharmony_ci
302e5c31af7Sopenharmony_ci    refPageShell(pageName, pageDesc, fp, head_content=None, sections=sections)
303e5c31af7Sopenharmony_ci
304e5c31af7Sopenharmony_ci
305e5c31af7Sopenharmony_cidef refPageTail(pageName,
306e5c31af7Sopenharmony_ci                specType=None,
307e5c31af7Sopenharmony_ci                specAnchor=None,
308e5c31af7Sopenharmony_ci                seeAlso=None,
309e5c31af7Sopenharmony_ci                fp=None,
310e5c31af7Sopenharmony_ci                auto=False,
311e5c31af7Sopenharmony_ci                leveloffset=0):
312e5c31af7Sopenharmony_ci    """Generate end boilerplate of a reference page.
313e5c31af7Sopenharmony_ci
314e5c31af7Sopenharmony_ci    - pageName - name of the page
315e5c31af7Sopenharmony_ci    - specType - None or the 'spec' attribute from the refpage block,
316e5c31af7Sopenharmony_ci      identifying the specification name and URL this refpage links to.
317e5c31af7Sopenharmony_ci    - specAnchor - None or the 'anchor' attribute from the refpage block,
318e5c31af7Sopenharmony_ci      identifying the anchor in the specification this refpage links to. If
319e5c31af7Sopenharmony_ci      None, the pageName is assumed to be a valid anchor.
320e5c31af7Sopenharmony_ci    - seeAlso - text of the "See Also" section
321e5c31af7Sopenharmony_ci    - fp - file to write the page to
322e5c31af7Sopenharmony_ci    - auto - True if this is an entirely generated refpage, False if it is
323e5c31af7Sopenharmony_ci      handwritten content from the spec.
324e5c31af7Sopenharmony_ci    - leveloffset - number of levels to bias section titles up or down."""
325e5c31af7Sopenharmony_ci
326e5c31af7Sopenharmony_ci    specName = conventions.api_name(specType)
327e5c31af7Sopenharmony_ci    specURL = conventions.specURL(specType)
328e5c31af7Sopenharmony_ci    if specAnchor is None:
329e5c31af7Sopenharmony_ci        specAnchor = pageName
330e5c31af7Sopenharmony_ci
331e5c31af7Sopenharmony_ci    if seeAlso is None:
332e5c31af7Sopenharmony_ci        seeAlso = 'No cross-references are available\n'
333e5c31af7Sopenharmony_ci
334e5c31af7Sopenharmony_ci    notes = [
335e5c31af7Sopenharmony_ci        'For more information, see the {}#{}[{} Specification^]'.format(
336e5c31af7Sopenharmony_ci            specURL, specAnchor, specName),
337e5c31af7Sopenharmony_ci        '',
338e5c31af7Sopenharmony_ci    ]
339e5c31af7Sopenharmony_ci
340e5c31af7Sopenharmony_ci    if auto:
341e5c31af7Sopenharmony_ci        notes.extend((
342e5c31af7Sopenharmony_ci            'This page is a generated document.',
343e5c31af7Sopenharmony_ci            'Fixes and changes should be made to the generator scripts, '
344e5c31af7Sopenharmony_ci            'not directly.',
345e5c31af7Sopenharmony_ci        ))
346e5c31af7Sopenharmony_ci    else:
347e5c31af7Sopenharmony_ci        notes.extend((
348e5c31af7Sopenharmony_ci            'This page is extracted from the ' + specName + ' Specification. ',
349e5c31af7Sopenharmony_ci            'Fixes and changes should be made to the Specification, '
350e5c31af7Sopenharmony_ci            'not directly.',
351e5c31af7Sopenharmony_ci        ))
352e5c31af7Sopenharmony_ci
353e5c31af7Sopenharmony_ci    # Generate the section header.
354e5c31af7Sopenharmony_ci    # Default depth is 2.
355e5c31af7Sopenharmony_ci    depth = max(0, leveloffset + 2)
356e5c31af7Sopenharmony_ci    prefix = '=' * depth
357e5c31af7Sopenharmony_ci
358e5c31af7Sopenharmony_ci    print(f'{prefix} See Also',
359e5c31af7Sopenharmony_ci          '',
360e5c31af7Sopenharmony_ci          seeAlso,
361e5c31af7Sopenharmony_ci          '',
362e5c31af7Sopenharmony_ci          sep='\n', file=fp)
363e5c31af7Sopenharmony_ci
364e5c31af7Sopenharmony_ci    print(f'{prefix} Document Notes',
365e5c31af7Sopenharmony_ci          '',
366e5c31af7Sopenharmony_ci          '\n'.join(notes),
367e5c31af7Sopenharmony_ci          '',
368e5c31af7Sopenharmony_ci          sep='\n', file=fp)
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci    printFooter(fp, leveloffset)
371e5c31af7Sopenharmony_ci
372e5c31af7Sopenharmony_ci
373e5c31af7Sopenharmony_cidef xrefRewriteInitialize():
374e5c31af7Sopenharmony_ci    """Initialize substitution patterns for asciidoctor xrefs."""
375e5c31af7Sopenharmony_ci
376e5c31af7Sopenharmony_ci    global refLinkPattern, refLinkSubstitute
377e5c31af7Sopenharmony_ci    global refLinkTextPattern, refLinkTextSubstitute
378e5c31af7Sopenharmony_ci    global specLinkPattern, specLinkSubstitute
379e5c31af7Sopenharmony_ci
380e5c31af7Sopenharmony_ci    # These are xrefs to API entities, rewritten to link to refpages
381e5c31af7Sopenharmony_ci    # The refLink variants are for xrefs with only an anchor and no text.
382e5c31af7Sopenharmony_ci    # The refLinkText variants are for xrefs with both anchor and text
383e5c31af7Sopenharmony_ci    refLinkPattern = re.compile(r'<<([Vv][Kk][A-Za-z0-9_]+)>>')
384e5c31af7Sopenharmony_ci    refLinkSubstitute = r'link:\1.html[\1^]'
385e5c31af7Sopenharmony_ci
386e5c31af7Sopenharmony_ci    refLinkTextPattern = re.compile(r'<<([Vv][Kk][A-Za-z0-9_]+)[,]?[ \t\n]*([^>,]*)>>')
387e5c31af7Sopenharmony_ci    refLinkTextSubstitute = r'link:\1.html[\2^]'
388e5c31af7Sopenharmony_ci
389e5c31af7Sopenharmony_ci    # These are xrefs to other anchors, rewritten to link to the spec
390e5c31af7Sopenharmony_ci    specLinkPattern = re.compile(r'<<([-A-Za-z0-9_.(){}:]+)[,]?[ \t\n]*([^>,]*)>>')
391e5c31af7Sopenharmony_ci
392e5c31af7Sopenharmony_ci    # Unfortunately, specLinkSubstitute depends on the link target,
393e5c31af7Sopenharmony_ci    # so cannot be constructed in advance.
394e5c31af7Sopenharmony_ci    specLinkSubstitute = None
395e5c31af7Sopenharmony_ci
396e5c31af7Sopenharmony_ci
397e5c31af7Sopenharmony_cidef xrefRewrite(text, specURL):
398e5c31af7Sopenharmony_ci    """Rewrite asciidoctor xrefs in text to resolve properly in refpages.
399e5c31af7Sopenharmony_ci    Xrefs which are to refpages are rewritten to link to those
400e5c31af7Sopenharmony_ci    refpages. The remainder are rewritten to generate external links into
401e5c31af7Sopenharmony_ci    the supplied specification document URL.
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci    - text - string to rewrite, or None
404e5c31af7Sopenharmony_ci    - specURL - URL to target
405e5c31af7Sopenharmony_ci
406e5c31af7Sopenharmony_ci    Returns rewritten text, or None, respectively"""
407e5c31af7Sopenharmony_ci
408e5c31af7Sopenharmony_ci    global refLinkPattern, refLinkSubstitute
409e5c31af7Sopenharmony_ci    global refLinkTextPattern, refLinkTextSubstitute
410e5c31af7Sopenharmony_ci    global specLinkPattern, specLinkSubstitute
411e5c31af7Sopenharmony_ci
412e5c31af7Sopenharmony_ci    specLinkSubstitute = r'link:{}#\1[\2^]'.format(specURL)
413e5c31af7Sopenharmony_ci
414e5c31af7Sopenharmony_ci    if text is not None:
415e5c31af7Sopenharmony_ci        text, _ = refLinkPattern.subn(refLinkSubstitute, text)
416e5c31af7Sopenharmony_ci        text, _ = refLinkTextPattern.subn(refLinkTextSubstitute, text)
417e5c31af7Sopenharmony_ci        text, _ = specLinkPattern.subn(specLinkSubstitute, text)
418e5c31af7Sopenharmony_ci
419e5c31af7Sopenharmony_ci    return text
420e5c31af7Sopenharmony_ci
421e5c31af7Sopenharmony_cidef emitPage(baseDir, specDir, pi, file):
422e5c31af7Sopenharmony_ci    """Extract a single reference page into baseDir.
423e5c31af7Sopenharmony_ci
424e5c31af7Sopenharmony_ci    - baseDir - base directory to emit page into
425e5c31af7Sopenharmony_ci    - specDir - directory extracted page source came from
426e5c31af7Sopenharmony_ci    - pi - pageInfo for this page relative to file
427e5c31af7Sopenharmony_ci    - file - list of strings making up the file, indexed by pi"""
428e5c31af7Sopenharmony_ci    pageName = f'{baseDir}/{pi.name}{conventions.file_suffix}'
429e5c31af7Sopenharmony_ci
430e5c31af7Sopenharmony_ci    # Add a dictionary entry for this page
431e5c31af7Sopenharmony_ci    global genDict
432e5c31af7Sopenharmony_ci    genDict[pi.name] = None
433e5c31af7Sopenharmony_ci    logDiag('emitPage:', pageName)
434e5c31af7Sopenharmony_ci
435e5c31af7Sopenharmony_ci    # Short description
436e5c31af7Sopenharmony_ci    if pi.desc is None:
437e5c31af7Sopenharmony_ci        pi.desc = '(no short description available)'
438e5c31af7Sopenharmony_ci
439e5c31af7Sopenharmony_ci    # Member/parameter section label and text, if there is one
440e5c31af7Sopenharmony_ci    field = None
441e5c31af7Sopenharmony_ci    fieldText = None
442e5c31af7Sopenharmony_ci
443e5c31af7Sopenharmony_ci    # Only do structural checks on API pages
444e5c31af7Sopenharmony_ci    if pi.type in refpage_api_types:
445e5c31af7Sopenharmony_ci        if pi.include is None:
446e5c31af7Sopenharmony_ci            logWarn('emitPage:', pageName, 'INCLUDE is None, no page generated')
447e5c31af7Sopenharmony_ci            return
448e5c31af7Sopenharmony_ci
449e5c31af7Sopenharmony_ci        # Specification text from beginning to just before the parameter
450e5c31af7Sopenharmony_ci        # section. This covers the description, the prototype, the version
451e5c31af7Sopenharmony_ci        # note, and any additional version note text. If a parameter section
452e5c31af7Sopenharmony_ci        # is absent then go a line beyond the include.
453e5c31af7Sopenharmony_ci        remap_end = pi.include + 1 if pi.param is None else pi.param
454e5c31af7Sopenharmony_ci        lines = remapIncludes(file[pi.begin:remap_end], baseDir, specDir)
455e5c31af7Sopenharmony_ci        specText = ''.join(lines)
456e5c31af7Sopenharmony_ci
457e5c31af7Sopenharmony_ci        if pi.param is not None:
458e5c31af7Sopenharmony_ci            if pi.type == 'structs':
459e5c31af7Sopenharmony_ci                field = 'Members'
460e5c31af7Sopenharmony_ci            elif pi.type in ['protos', 'funcpointers']:
461e5c31af7Sopenharmony_ci                field = 'Parameters'
462e5c31af7Sopenharmony_ci            else:
463e5c31af7Sopenharmony_ci                logWarn('emitPage: unknown field type:', pi.type,
464e5c31af7Sopenharmony_ci                        'for', pi.name)
465e5c31af7Sopenharmony_ci            lines = remapIncludes(file[pi.param:pi.body], baseDir, specDir)
466e5c31af7Sopenharmony_ci            fieldText = ''.join(lines)
467e5c31af7Sopenharmony_ci
468e5c31af7Sopenharmony_ci        # Description text
469e5c31af7Sopenharmony_ci        if pi.body != pi.include:
470e5c31af7Sopenharmony_ci            lines = remapIncludes(file[pi.body:pi.end + 1], baseDir, specDir)
471e5c31af7Sopenharmony_ci            descText = ''.join(lines)
472e5c31af7Sopenharmony_ci        else:
473e5c31af7Sopenharmony_ci            descText = None
474e5c31af7Sopenharmony_ci            logWarn('emitPage: INCLUDE == BODY, so description will be empty for', pi.name)
475e5c31af7Sopenharmony_ci            if pi.begin != pi.include:
476e5c31af7Sopenharmony_ci                logWarn('emitPage: Note: BEGIN != INCLUDE, so the description might be incorrectly located before the API include!')
477e5c31af7Sopenharmony_ci    elif pi.type in refpage_other_types:
478e5c31af7Sopenharmony_ci        specText = None
479e5c31af7Sopenharmony_ci        descText = ''.join(file[pi.begin:pi.end + 1])
480e5c31af7Sopenharmony_ci    else:
481e5c31af7Sopenharmony_ci        # This should be caught in the spec markup checking tests
482e5c31af7Sopenharmony_ci        logErr(f"emitPage: refpage type='{pi.type}' is unrecognized")
483e5c31af7Sopenharmony_ci
484e5c31af7Sopenharmony_ci    # Rewrite asciidoctor xrefs to resolve properly in refpages
485e5c31af7Sopenharmony_ci    specURL = conventions.specURL(pi.spec)
486e5c31af7Sopenharmony_ci
487e5c31af7Sopenharmony_ci    specText = xrefRewrite(specText, specURL)
488e5c31af7Sopenharmony_ci    fieldText = xrefRewrite(fieldText, specURL)
489e5c31af7Sopenharmony_ci    descText = xrefRewrite(descText, specURL)
490e5c31af7Sopenharmony_ci
491e5c31af7Sopenharmony_ci    fp = open(pageName, 'w', encoding='utf-8')
492e5c31af7Sopenharmony_ci    refPageHead(pi.name,
493e5c31af7Sopenharmony_ci                pi.desc,
494e5c31af7Sopenharmony_ci                specText,
495e5c31af7Sopenharmony_ci                field, fieldText,
496e5c31af7Sopenharmony_ci                descText,
497e5c31af7Sopenharmony_ci                fp)
498e5c31af7Sopenharmony_ci    refPageTail(pageName=pi.name,
499e5c31af7Sopenharmony_ci                specType=pi.spec,
500e5c31af7Sopenharmony_ci                specAnchor=pi.anchor,
501e5c31af7Sopenharmony_ci                seeAlso=seeAlsoList(pi.name, pi.refs, pi.alias.split()),
502e5c31af7Sopenharmony_ci                fp=fp,
503e5c31af7Sopenharmony_ci                auto=False)
504e5c31af7Sopenharmony_ci    fp.close()
505e5c31af7Sopenharmony_ci
506e5c31af7Sopenharmony_ci
507e5c31af7Sopenharmony_cidef autoGenEnumsPage(baseDir, pi, file):
508e5c31af7Sopenharmony_ci    """Autogenerate a single reference page in baseDir.
509e5c31af7Sopenharmony_ci
510e5c31af7Sopenharmony_ci    Script only knows how to do this for /enums/ pages, at present.
511e5c31af7Sopenharmony_ci
512e5c31af7Sopenharmony_ci    - baseDir - base directory to emit page into
513e5c31af7Sopenharmony_ci    - pi - pageInfo for this page relative to file
514e5c31af7Sopenharmony_ci    - file - list of strings making up the file, indexed by pi"""
515e5c31af7Sopenharmony_ci    pageName = f'{baseDir}/{pi.name}{conventions.file_suffix}'
516e5c31af7Sopenharmony_ci    fp = open(pageName, 'w', encoding='utf-8')
517e5c31af7Sopenharmony_ci
518e5c31af7Sopenharmony_ci    # Add a dictionary entry for this page
519e5c31af7Sopenharmony_ci    global genDict
520e5c31af7Sopenharmony_ci    genDict[pi.name] = None
521e5c31af7Sopenharmony_ci    logDiag('autoGenEnumsPage:', pageName)
522e5c31af7Sopenharmony_ci
523e5c31af7Sopenharmony_ci    # Short description
524e5c31af7Sopenharmony_ci    if pi.desc is None:
525e5c31af7Sopenharmony_ci        pi.desc = '(no short description available)'
526e5c31af7Sopenharmony_ci
527e5c31af7Sopenharmony_ci    # Description text. Allow for the case where an enum definition
528e5c31af7Sopenharmony_ci    # is not embedded.
529e5c31af7Sopenharmony_ci    if not pi.embed:
530e5c31af7Sopenharmony_ci        embedRef = ''
531e5c31af7Sopenharmony_ci    else:
532e5c31af7Sopenharmony_ci        embedRef = ''.join((
533e5c31af7Sopenharmony_ci                           '  * The reference page for ',
534e5c31af7Sopenharmony_ci                           macroPrefix(pi.embed),
535e5c31af7Sopenharmony_ci                           ', where this interface is defined.\n'))
536e5c31af7Sopenharmony_ci
537e5c31af7Sopenharmony_ci    txt = ''.join((
538e5c31af7Sopenharmony_ci        'For more information, see:\n\n',
539e5c31af7Sopenharmony_ci        embedRef,
540e5c31af7Sopenharmony_ci        '  * The See Also section for other reference pages using this type.\n',
541e5c31af7Sopenharmony_ci        '  * The ' + apiName + ' Specification.\n'))
542e5c31af7Sopenharmony_ci
543e5c31af7Sopenharmony_ci    refPageHead(pi.name,
544e5c31af7Sopenharmony_ci                pi.desc,
545e5c31af7Sopenharmony_ci                ''.join(file[pi.begin:pi.include + 1]),
546e5c31af7Sopenharmony_ci                None, None,
547e5c31af7Sopenharmony_ci                txt,
548e5c31af7Sopenharmony_ci                fp)
549e5c31af7Sopenharmony_ci    refPageTail(pageName=pi.name,
550e5c31af7Sopenharmony_ci                specType=pi.spec,
551e5c31af7Sopenharmony_ci                specAnchor=pi.anchor,
552e5c31af7Sopenharmony_ci                seeAlso=seeAlsoList(pi.name, pi.refs, pi.alias.split()),
553e5c31af7Sopenharmony_ci                fp=fp,
554e5c31af7Sopenharmony_ci                auto=True)
555e5c31af7Sopenharmony_ci    fp.close()
556e5c31af7Sopenharmony_ci
557e5c31af7Sopenharmony_ci
558e5c31af7Sopenharmony_ci# Pattern to break apart an API *Flags{authorID} name, used in
559e5c31af7Sopenharmony_ci# autoGenFlagsPage.
560e5c31af7Sopenharmony_ciflagNamePat = re.compile(r'(?P<name>\w+)Flags(?P<author>[A-Z]*)')
561e5c31af7Sopenharmony_ci
562e5c31af7Sopenharmony_ci
563e5c31af7Sopenharmony_cidef autoGenFlagsPage(baseDir, flagName):
564e5c31af7Sopenharmony_ci    """Autogenerate a single reference page in baseDir for an API *Flags type.
565e5c31af7Sopenharmony_ci
566e5c31af7Sopenharmony_ci    - baseDir - base directory to emit page into
567e5c31af7Sopenharmony_ci    - flagName - API *Flags name"""
568e5c31af7Sopenharmony_ci    pageName = f'{baseDir}/{flagName}{conventions.file_suffix}'
569e5c31af7Sopenharmony_ci    fp = open(pageName, 'w', encoding='utf-8')
570e5c31af7Sopenharmony_ci
571e5c31af7Sopenharmony_ci    # Add a dictionary entry for this page
572e5c31af7Sopenharmony_ci    global genDict
573e5c31af7Sopenharmony_ci    genDict[flagName] = None
574e5c31af7Sopenharmony_ci    logDiag('autoGenFlagsPage:', pageName)
575e5c31af7Sopenharmony_ci
576e5c31af7Sopenharmony_ci    # Short description
577e5c31af7Sopenharmony_ci    matches = flagNamePat.search(flagName)
578e5c31af7Sopenharmony_ci    if matches is not None:
579e5c31af7Sopenharmony_ci        name = matches.group('name')
580e5c31af7Sopenharmony_ci        author = matches.group('author')
581e5c31af7Sopenharmony_ci        logDiag('autoGenFlagsPage: split name into', name, 'Flags', author)
582e5c31af7Sopenharmony_ci        flagBits = name + 'FlagBits' + author
583e5c31af7Sopenharmony_ci        desc = 'Bitmask of ' + flagBits
584e5c31af7Sopenharmony_ci    else:
585e5c31af7Sopenharmony_ci        logWarn('autoGenFlagsPage:', pageName, 'does not end in "Flags{author ID}". Cannot infer FlagBits type.')
586e5c31af7Sopenharmony_ci        flagBits = None
587e5c31af7Sopenharmony_ci        desc = 'Unknown ' + apiName + ' flags type'
588e5c31af7Sopenharmony_ci
589e5c31af7Sopenharmony_ci    # Description text
590e5c31af7Sopenharmony_ci    if flagBits is not None:
591e5c31af7Sopenharmony_ci        txt = ''.join((
592e5c31af7Sopenharmony_ci            'etext:' + flagName,
593e5c31af7Sopenharmony_ci            ' is a mask of zero or more elink:' + flagBits + '.\n',
594e5c31af7Sopenharmony_ci            'It is used as a member and/or parameter of the structures and commands\n',
595e5c31af7Sopenharmony_ci            'in the See Also section below.\n'))
596e5c31af7Sopenharmony_ci    else:
597e5c31af7Sopenharmony_ci        txt = ''.join((
598e5c31af7Sopenharmony_ci            'etext:' + flagName,
599e5c31af7Sopenharmony_ci            ' is an unknown ' + apiName + ' type, assumed to be a bitmask.\n'))
600e5c31af7Sopenharmony_ci
601e5c31af7Sopenharmony_ci    refPageHead(flagName,
602e5c31af7Sopenharmony_ci                desc,
603e5c31af7Sopenharmony_ci                makeAPIInclude('flags', flagName),
604e5c31af7Sopenharmony_ci                None, None,
605e5c31af7Sopenharmony_ci                txt,
606e5c31af7Sopenharmony_ci                fp)
607e5c31af7Sopenharmony_ci    refPageTail(pageName=flagName,
608e5c31af7Sopenharmony_ci                specType=pi.spec,
609e5c31af7Sopenharmony_ci                specAnchor=pi.anchor,
610e5c31af7Sopenharmony_ci                seeAlso=seeAlsoList(flagName, None),
611e5c31af7Sopenharmony_ci                fp=fp,
612e5c31af7Sopenharmony_ci                auto=True)
613e5c31af7Sopenharmony_ci    fp.close()
614e5c31af7Sopenharmony_ci
615e5c31af7Sopenharmony_ci
616e5c31af7Sopenharmony_cidef autoGenHandlePage(baseDir, handleName):
617e5c31af7Sopenharmony_ci    """Autogenerate a single handle page in baseDir for an API handle type.
618e5c31af7Sopenharmony_ci
619e5c31af7Sopenharmony_ci    - baseDir - base directory to emit page into
620e5c31af7Sopenharmony_ci    - handleName - API handle name"""
621e5c31af7Sopenharmony_ci    # @@ Need to determine creation function & add handles/ include for the
622e5c31af7Sopenharmony_ci    # @@ interface in generator.py.
623e5c31af7Sopenharmony_ci    pageName = f'{baseDir}/{handleName}{conventions.file_suffix}'
624e5c31af7Sopenharmony_ci    fp = open(pageName, 'w', encoding='utf-8')
625e5c31af7Sopenharmony_ci
626e5c31af7Sopenharmony_ci    # Add a dictionary entry for this page
627e5c31af7Sopenharmony_ci    global genDict
628e5c31af7Sopenharmony_ci    genDict[handleName] = None
629e5c31af7Sopenharmony_ci    logDiag('autoGenHandlePage:', pageName)
630e5c31af7Sopenharmony_ci
631e5c31af7Sopenharmony_ci    # Short description
632e5c31af7Sopenharmony_ci    desc = apiName + ' object handle'
633e5c31af7Sopenharmony_ci
634e5c31af7Sopenharmony_ci    descText = ''.join((
635e5c31af7Sopenharmony_ci        'sname:' + handleName,
636e5c31af7Sopenharmony_ci        ' is an object handle type, referring to an object used\n',
637e5c31af7Sopenharmony_ci        'by the ' + apiName + ' implementation. These handles are created or allocated\n',
638e5c31af7Sopenharmony_ci        'by the @@ TBD @@ function, and used by other ' + apiName + ' structures\n',
639e5c31af7Sopenharmony_ci        'and commands in the See Also section below.\n'))
640e5c31af7Sopenharmony_ci
641e5c31af7Sopenharmony_ci    refPageHead(handleName,
642e5c31af7Sopenharmony_ci                desc,
643e5c31af7Sopenharmony_ci                makeAPIInclude('handles', handleName),
644e5c31af7Sopenharmony_ci                None, None,
645e5c31af7Sopenharmony_ci                descText,
646e5c31af7Sopenharmony_ci                fp)
647e5c31af7Sopenharmony_ci    refPageTail(pageName=handleName,
648e5c31af7Sopenharmony_ci                specType=pi.spec,
649e5c31af7Sopenharmony_ci                specAnchor=pi.anchor,
650e5c31af7Sopenharmony_ci                seeAlso=seeAlsoList(handleName, None),
651e5c31af7Sopenharmony_ci                fp=fp,
652e5c31af7Sopenharmony_ci                auto=True)
653e5c31af7Sopenharmony_ci    fp.close()
654e5c31af7Sopenharmony_ci
655e5c31af7Sopenharmony_ci
656e5c31af7Sopenharmony_cidef genRef(specFile, baseDir):
657e5c31af7Sopenharmony_ci    """Extract reference pages from a spec asciidoc source file.
658e5c31af7Sopenharmony_ci
659e5c31af7Sopenharmony_ci    - specFile - filename to extract from
660e5c31af7Sopenharmony_ci    - baseDir - output directory to generate page in"""
661e5c31af7Sopenharmony_ci    # We do not care the newline format used here.
662e5c31af7Sopenharmony_ci    file, _ = loadFile(specFile)
663e5c31af7Sopenharmony_ci    if file is None:
664e5c31af7Sopenharmony_ci        return
665e5c31af7Sopenharmony_ci
666e5c31af7Sopenharmony_ci    # Save the path to this file for later use in rewriting relative includes
667e5c31af7Sopenharmony_ci    specDir = os.path.dirname(os.path.abspath(specFile))
668e5c31af7Sopenharmony_ci
669e5c31af7Sopenharmony_ci    pageMap = findRefs(file, specFile)
670e5c31af7Sopenharmony_ci    logDiag(specFile + ': found', len(pageMap.keys()), 'potential pages')
671e5c31af7Sopenharmony_ci
672e5c31af7Sopenharmony_ci    sys.stderr.flush()
673e5c31af7Sopenharmony_ci
674e5c31af7Sopenharmony_ci    # Fix up references in pageMap
675e5c31af7Sopenharmony_ci    fixupRefs(pageMap, specFile, file)
676e5c31af7Sopenharmony_ci
677e5c31af7Sopenharmony_ci    # Create each page, if possible
678e5c31af7Sopenharmony_ci    pages = {}
679e5c31af7Sopenharmony_ci
680e5c31af7Sopenharmony_ci    for name in sorted(pageMap):
681e5c31af7Sopenharmony_ci        pi = pageMap[name]
682e5c31af7Sopenharmony_ci
683e5c31af7Sopenharmony_ci        # Only generate the page if it is in the requested build
684e5c31af7Sopenharmony_ci        # 'freeform' pages are always generated
685e5c31af7Sopenharmony_ci        # 'feature' pages (core versions & extensions) are generated if they are in
686e5c31af7Sopenharmony_ci        # the requested feature list
687e5c31af7Sopenharmony_ci        # All other pages (APIs) are generated if they are in the API map for
688e5c31af7Sopenharmony_ci        # the build.
689e5c31af7Sopenharmony_ci        if pi.type in refpage_api_types:
690e5c31af7Sopenharmony_ci            if name not in api.typeCategory:
691e5c31af7Sopenharmony_ci                # Also check aliases of name - api.nonexistent is the same
692e5c31af7Sopenharmony_ci                # mapping used to rewrite *link: macros in this build.
693e5c31af7Sopenharmony_ci                if name not in api.nonexistent:
694e5c31af7Sopenharmony_ci                    logWarn(f'genRef: NOT generating feature page {name} - API not in this build')
695e5c31af7Sopenharmony_ci                    continue
696e5c31af7Sopenharmony_ci                else:
697e5c31af7Sopenharmony_ci                    logWarn(f'genRef: generating feature page {name} because its alias {api.nonexistent[name]} exists')
698e5c31af7Sopenharmony_ci        elif pi.type in refpage_other_types:
699e5c31af7Sopenharmony_ci            # The only non-API type which can be checked is a feature refpage
700e5c31af7Sopenharmony_ci            if pi.type == 'feature':
701e5c31af7Sopenharmony_ci                if name not in api.features:
702e5c31af7Sopenharmony_ci                    logWarn(f'genRef: NOT generating feature page {name} - feature not in this build')
703e5c31af7Sopenharmony_ci                    continue
704e5c31af7Sopenharmony_ci
705e5c31af7Sopenharmony_ci        printPageInfo(pi, file)
706e5c31af7Sopenharmony_ci
707e5c31af7Sopenharmony_ci        if pi.Warning:
708e5c31af7Sopenharmony_ci            logDiag('genRef:', pi.name + ':', pi.Warning)
709e5c31af7Sopenharmony_ci
710e5c31af7Sopenharmony_ci        if pi.extractPage:
711e5c31af7Sopenharmony_ci            emitPage(baseDir, specDir, pi, file)
712e5c31af7Sopenharmony_ci        elif pi.type == 'enums':
713e5c31af7Sopenharmony_ci            autoGenEnumsPage(baseDir, pi, file)
714e5c31af7Sopenharmony_ci        elif pi.type == 'flags':
715e5c31af7Sopenharmony_ci            autoGenFlagsPage(baseDir, pi.name)
716e5c31af7Sopenharmony_ci        else:
717e5c31af7Sopenharmony_ci            # Do not extract this page
718e5c31af7Sopenharmony_ci            logWarn('genRef: Cannot extract or autogenerate:', pi.name)
719e5c31af7Sopenharmony_ci
720e5c31af7Sopenharmony_ci        pages[pi.name] = pi
721e5c31af7Sopenharmony_ci        for alias in pi.alias.split():
722e5c31af7Sopenharmony_ci            pages[alias] = pi
723e5c31af7Sopenharmony_ci
724e5c31af7Sopenharmony_ci    return pages
725e5c31af7Sopenharmony_ci
726e5c31af7Sopenharmony_ci
727e5c31af7Sopenharmony_cidef genSinglePageRef(baseDir):
728e5c31af7Sopenharmony_ci    """Generate the single-page version of the ref pages.
729e5c31af7Sopenharmony_ci
730e5c31af7Sopenharmony_ci    This assumes there is a page for everything in the api module dictionaries.
731e5c31af7Sopenharmony_ci    Extensions (KHR, EXT, etc.) are currently skipped"""
732e5c31af7Sopenharmony_ci    # Accumulate head of page
733e5c31af7Sopenharmony_ci    head = io.StringIO()
734e5c31af7Sopenharmony_ci
735e5c31af7Sopenharmony_ci    printCopyrightSourceComments(head)
736e5c31af7Sopenharmony_ci
737e5c31af7Sopenharmony_ci    print('= ' + apiName + ' API Reference Pages',
738e5c31af7Sopenharmony_ci          ':data-uri:',
739e5c31af7Sopenharmony_ci          ':icons: font',
740e5c31af7Sopenharmony_ci          ':doctype: book',
741e5c31af7Sopenharmony_ci          ':numbered!:',
742e5c31af7Sopenharmony_ci          ':max-width: 200',
743e5c31af7Sopenharmony_ci          ':data-uri:',
744e5c31af7Sopenharmony_ci          ':toc2:',
745e5c31af7Sopenharmony_ci          ':toclevels: 2',
746e5c31af7Sopenharmony_ci          ':attribute-missing: warn',
747e5c31af7Sopenharmony_ci          '',
748e5c31af7Sopenharmony_ci          sep='\n', file=head)
749e5c31af7Sopenharmony_ci
750e5c31af7Sopenharmony_ci    print('== Copyright', file=head)
751e5c31af7Sopenharmony_ci    print('', file=head)
752e5c31af7Sopenharmony_ci    print('include::{config}/copyright-ccby' + conventions.file_suffix + '[]', file=head)
753e5c31af7Sopenharmony_ci    print('', file=head)
754e5c31af7Sopenharmony_ci
755e5c31af7Sopenharmony_ci    # Inject the table of contents. Asciidoc really ought to be generating
756e5c31af7Sopenharmony_ci    # this for us.
757e5c31af7Sopenharmony_ci
758e5c31af7Sopenharmony_ci    sections = [
759e5c31af7Sopenharmony_ci        [api.protos,       'protos',       apiName + ' Commands'],
760e5c31af7Sopenharmony_ci        [api.handles,      'handles',      'Object Handles'],
761e5c31af7Sopenharmony_ci        [api.structs,      'structs',      'Structures'],
762e5c31af7Sopenharmony_ci        [api.enums,        'enums',        'Enumerations'],
763e5c31af7Sopenharmony_ci        [api.flags,        'flags',        'Flags'],
764e5c31af7Sopenharmony_ci        [api.funcpointers, 'funcpointers', 'Function Pointer Types'],
765e5c31af7Sopenharmony_ci        [api.basetypes,    'basetypes',    apiName + ' Scalar types'],
766e5c31af7Sopenharmony_ci        [api.defines,      'defines',      'C Macro Definitions'],
767e5c31af7Sopenharmony_ci        [extensions,       'extensions',   apiName + ' Extensions']
768e5c31af7Sopenharmony_ci    ]
769e5c31af7Sopenharmony_ci
770e5c31af7Sopenharmony_ci    # Accumulate body of page
771e5c31af7Sopenharmony_ci    body = io.StringIO()
772e5c31af7Sopenharmony_ci
773e5c31af7Sopenharmony_ci    for (apiDict, label, title) in sections:
774e5c31af7Sopenharmony_ci        # Add section title/anchor header to body
775e5c31af7Sopenharmony_ci        anchor = '[[' + label + ',' + title + ']]'
776e5c31af7Sopenharmony_ci        print(anchor,
777e5c31af7Sopenharmony_ci              '== ' + title,
778e5c31af7Sopenharmony_ci              '',
779e5c31af7Sopenharmony_ci              ':leveloffset: 2',
780e5c31af7Sopenharmony_ci              '',
781e5c31af7Sopenharmony_ci              sep='\n', file=body)
782e5c31af7Sopenharmony_ci
783e5c31af7Sopenharmony_ci        if label == 'extensions':
784e5c31af7Sopenharmony_ci            # preserve order of extensions since we already sorted the way we want.
785e5c31af7Sopenharmony_ci            keys = apiDict.keys()
786e5c31af7Sopenharmony_ci        else:
787e5c31af7Sopenharmony_ci            keys = sorted(apiDict.keys())
788e5c31af7Sopenharmony_ci
789e5c31af7Sopenharmony_ci        for refPage in keys:
790e5c31af7Sopenharmony_ci            # Do not generate links for aliases, which are included with the
791e5c31af7Sopenharmony_ci            # aliased page
792e5c31af7Sopenharmony_ci            if refPage not in api.alias:
793e5c31af7Sopenharmony_ci                # Add page to body
794e5c31af7Sopenharmony_ci                if 'FlagBits' in refPage and conventions.unified_flag_refpages:
795e5c31af7Sopenharmony_ci                    # OpenXR does not create separate ref pages for FlagBits:
796e5c31af7Sopenharmony_ci                    # the FlagBits includes go in the Flags refpage.
797e5c31af7Sopenharmony_ci                    # Previously the Vulkan script would only emit non-empty
798e5c31af7Sopenharmony_ci                    # Vk*Flags pages, via the logic
799e5c31af7Sopenharmony_ci                    #   if refPage not in api.flags or api.flags[refPage] is not None
800e5c31af7Sopenharmony_ci                    #       emit page
801e5c31af7Sopenharmony_ci                    # Now, all are emitted.
802e5c31af7Sopenharmony_ci                    continue
803e5c31af7Sopenharmony_ci                else:
804e5c31af7Sopenharmony_ci                    print(f'include::{refPage}{conventions.file_suffix}[]', file=body)
805e5c31af7Sopenharmony_ci            else:
806e5c31af7Sopenharmony_ci                # Alternatively, we could (probably should) link to the
807e5c31af7Sopenharmony_ci                # aliased refpage
808e5c31af7Sopenharmony_ci                logWarn('(Benign) Not including', refPage,
809e5c31af7Sopenharmony_ci                        'in single-page reference',
810e5c31af7Sopenharmony_ci                        'because it is an alias of', api.alias[refPage])
811e5c31af7Sopenharmony_ci
812e5c31af7Sopenharmony_ci        print('\n' + ':leveloffset: 0' + '\n', file=body)
813e5c31af7Sopenharmony_ci
814e5c31af7Sopenharmony_ci    # Write head and body to the output file
815e5c31af7Sopenharmony_ci    pageName = f'{baseDir}/apispec{conventions.file_suffix}'
816e5c31af7Sopenharmony_ci    fp = open(pageName, 'w', encoding='utf-8')
817e5c31af7Sopenharmony_ci
818e5c31af7Sopenharmony_ci    print(head.getvalue(), file=fp, end='')
819e5c31af7Sopenharmony_ci    print(body.getvalue(), file=fp, end='')
820e5c31af7Sopenharmony_ci
821e5c31af7Sopenharmony_ci    head.close()
822e5c31af7Sopenharmony_ci    body.close()
823e5c31af7Sopenharmony_ci    fp.close()
824e5c31af7Sopenharmony_ci
825e5c31af7Sopenharmony_ci
826e5c31af7Sopenharmony_cidef genExtension(baseDir, extpath, name, info):
827e5c31af7Sopenharmony_ci    """Generate refpage, and add dictionary entry for an extension
828e5c31af7Sopenharmony_ci
829e5c31af7Sopenharmony_ci    - baseDir - output directory to generate page in
830e5c31af7Sopenharmony_ci    - extpath - None, or path to per-extension specification sources if
831e5c31af7Sopenharmony_ci                those are to be included in extension refpages
832e5c31af7Sopenharmony_ci    - name - extension name
833e5c31af7Sopenharmony_ci    - info - <extension> Element from XML"""
834e5c31af7Sopenharmony_ci
835e5c31af7Sopenharmony_ci    # Add a dictionary entry for this page
836e5c31af7Sopenharmony_ci    global genDict
837e5c31af7Sopenharmony_ci    genDict[name] = None
838e5c31af7Sopenharmony_ci    declares = []
839e5c31af7Sopenharmony_ci    elem = info.elem
840e5c31af7Sopenharmony_ci
841e5c31af7Sopenharmony_ci    # Type of extension (instance, device, etc.)
842e5c31af7Sopenharmony_ci    ext_type = elem.get('type')
843e5c31af7Sopenharmony_ci
844e5c31af7Sopenharmony_ci    # Autogenerate interfaces from <extension> entry
845e5c31af7Sopenharmony_ci    for required in elem.find('require'):
846e5c31af7Sopenharmony_ci        req_name = required.get('name')
847e5c31af7Sopenharmony_ci        if not req_name:
848e5c31af7Sopenharmony_ci            # This is not what we are looking for
849e5c31af7Sopenharmony_ci            continue
850e5c31af7Sopenharmony_ci        if req_name.endswith('_SPEC_VERSION') or req_name.endswith('_EXTENSION_NAME'):
851e5c31af7Sopenharmony_ci            # Do not link to spec version or extension name - those ref pages are not created.
852e5c31af7Sopenharmony_ci            continue
853e5c31af7Sopenharmony_ci
854e5c31af7Sopenharmony_ci        if required.get('extends'):
855e5c31af7Sopenharmony_ci            # These are either extensions of enumerated types, or const enum
856e5c31af7Sopenharmony_ci            # values: neither of which get a ref page - although we could
857e5c31af7Sopenharmony_ci            # include the enumerated types in the See Also list.
858e5c31af7Sopenharmony_ci            continue
859e5c31af7Sopenharmony_ci
860e5c31af7Sopenharmony_ci        if req_name not in genDict:
861e5c31af7Sopenharmony_ci            if req_name in api.alias:
862e5c31af7Sopenharmony_ci                logWarn(f'WARN: {req_name} (in extension {name}) is an alias, so does not have a ref page')
863e5c31af7Sopenharmony_ci            else:
864e5c31af7Sopenharmony_ci                logWarn(f'ERROR: {req_name} (in extension {name}) does not have a ref page.')
865e5c31af7Sopenharmony_ci
866e5c31af7Sopenharmony_ci        declares.append(req_name)
867e5c31af7Sopenharmony_ci
868e5c31af7Sopenharmony_ci    appbody = None
869e5c31af7Sopenharmony_ci    tail_content = None
870e5c31af7Sopenharmony_ci    if extpath is not None:
871e5c31af7Sopenharmony_ci        try:
872e5c31af7Sopenharmony_ci            appPath = extpath + '/' + conventions.extension_file_path(name)
873e5c31af7Sopenharmony_ci            appfp = open(appPath, 'r', encoding='utf-8')
874e5c31af7Sopenharmony_ci            appbody = appfp.read()
875e5c31af7Sopenharmony_ci            appfp.close()
876e5c31af7Sopenharmony_ci
877e5c31af7Sopenharmony_ci            # Transform internal links to crosslinks
878e5c31af7Sopenharmony_ci            specURL = conventions.specURL()
879e5c31af7Sopenharmony_ci            appbody = xrefRewrite(appbody, specURL)
880e5c31af7Sopenharmony_ci        except FileNotFoundError:
881e5c31af7Sopenharmony_ci            print('Cannot find extension appendix for', name)
882e5c31af7Sopenharmony_ci            logWarn('Cannot find extension appendix for', name)
883e5c31af7Sopenharmony_ci
884e5c31af7Sopenharmony_ci            # Fall through to autogenerated page
885e5c31af7Sopenharmony_ci            extpath = None
886e5c31af7Sopenharmony_ci            appbody = None
887e5c31af7Sopenharmony_ci
888e5c31af7Sopenharmony_ci            appbody = f'Cannot find extension appendix {appPath} for {name}\n'
889e5c31af7Sopenharmony_ci    else:
890e5c31af7Sopenharmony_ci        tail_content = makeExtensionInclude(name)
891e5c31af7Sopenharmony_ci
892e5c31af7Sopenharmony_ci    # Write the extension refpage
893e5c31af7Sopenharmony_ci    pageName = f'{baseDir}/{name}{conventions.file_suffix}'
894e5c31af7Sopenharmony_ci    logDiag('genExtension:', pageName)
895e5c31af7Sopenharmony_ci    fp = open(pageName, 'w', encoding='utf-8')
896e5c31af7Sopenharmony_ci
897e5c31af7Sopenharmony_ci    # There are no generated titled sections
898e5c31af7Sopenharmony_ci    sections = None
899e5c31af7Sopenharmony_ci
900e5c31af7Sopenharmony_ci    refPageShell(name,
901e5c31af7Sopenharmony_ci                 "{} extension".format(ext_type),
902e5c31af7Sopenharmony_ci                 fp,
903e5c31af7Sopenharmony_ci                 appbody,
904e5c31af7Sopenharmony_ci                 sections=sections,
905e5c31af7Sopenharmony_ci                 tail_content=tail_content)
906e5c31af7Sopenharmony_ci
907e5c31af7Sopenharmony_ci    # Restore leveloffset for boilerplate in refPageTail
908e5c31af7Sopenharmony_ci    if conventions.include_extension_appendix_in_refpage:
909e5c31af7Sopenharmony_ci        # The generated metadata include (refpage.extensionname.adoc) moved
910e5c31af7Sopenharmony_ci        # the leveloffset attribute by -1 to account for the relative
911e5c31af7Sopenharmony_ci        # structuring of the spec extension appendix section structure vs.
912e5c31af7Sopenharmony_ci        # the refpages.
913e5c31af7Sopenharmony_ci        # This restores leveloffset for the boilerplate in refPageTail.
914e5c31af7Sopenharmony_ci        leveloffset = 1
915e5c31af7Sopenharmony_ci    else:
916e5c31af7Sopenharmony_ci        leveloffset = 0
917e5c31af7Sopenharmony_ci
918e5c31af7Sopenharmony_ci    refPageTail(pageName=name,
919e5c31af7Sopenharmony_ci                specType=None,
920e5c31af7Sopenharmony_ci                specAnchor=name,
921e5c31af7Sopenharmony_ci                seeAlso=seeAlsoList(name, declares),
922e5c31af7Sopenharmony_ci                fp=fp,
923e5c31af7Sopenharmony_ci                auto=True,
924e5c31af7Sopenharmony_ci                leveloffset=leveloffset)
925e5c31af7Sopenharmony_ci    fp.close()
926e5c31af7Sopenharmony_ci
927e5c31af7Sopenharmony_ci
928e5c31af7Sopenharmony_ciif __name__ == '__main__':
929e5c31af7Sopenharmony_ci    global genDict, extensions, conventions, apiName
930e5c31af7Sopenharmony_ci    genDict = {}
931e5c31af7Sopenharmony_ci    extensions = OrderedDict()
932e5c31af7Sopenharmony_ci    conventions = APIConventions()
933e5c31af7Sopenharmony_ci    apiName = conventions.api_name('api')
934e5c31af7Sopenharmony_ci
935e5c31af7Sopenharmony_ci    parser = argparse.ArgumentParser()
936e5c31af7Sopenharmony_ci
937e5c31af7Sopenharmony_ci    parser.add_argument('-diag', action='store', dest='diagFile',
938e5c31af7Sopenharmony_ci                        help='Set the diagnostic file')
939e5c31af7Sopenharmony_ci    parser.add_argument('-warn', action='store', dest='warnFile',
940e5c31af7Sopenharmony_ci                        help='Set the warning file')
941e5c31af7Sopenharmony_ci    parser.add_argument('-log', action='store', dest='logFile',
942e5c31af7Sopenharmony_ci                        help='Set the log file for both diagnostics and warnings')
943e5c31af7Sopenharmony_ci    parser.add_argument('-genpath', action='store',
944e5c31af7Sopenharmony_ci                        default='gen',
945e5c31af7Sopenharmony_ci                        help='Path to directory containing generated files')
946e5c31af7Sopenharmony_ci    parser.add_argument('-basedir', action='store', dest='baseDir',
947e5c31af7Sopenharmony_ci                        default=None,
948e5c31af7Sopenharmony_ci                        help='Set the base directory in which pages are generated')
949e5c31af7Sopenharmony_ci    parser.add_argument('-noauto', action='store_true',
950e5c31af7Sopenharmony_ci                        help='Don\'t generate inferred ref pages automatically')
951e5c31af7Sopenharmony_ci    parser.add_argument('files', metavar='filename', nargs='*',
952e5c31af7Sopenharmony_ci                        help='a filename to extract ref pages from')
953e5c31af7Sopenharmony_ci    parser.add_argument('--version', action='version', version='%(prog)s 1.0')
954e5c31af7Sopenharmony_ci    parser.add_argument('-extension', action='append',
955e5c31af7Sopenharmony_ci                        default=[],
956e5c31af7Sopenharmony_ci                        help='Specify an extension or extensions to add to targets')
957e5c31af7Sopenharmony_ci    parser.add_argument('-rewrite', action='store',
958e5c31af7Sopenharmony_ci                        default=None,
959e5c31af7Sopenharmony_ci                        help='Name of output file to write Apache mod_rewrite directives to')
960e5c31af7Sopenharmony_ci    parser.add_argument('-toc', action='store',
961e5c31af7Sopenharmony_ci                        default=None,
962e5c31af7Sopenharmony_ci                        help='Name of output file to write an alphabetical TOC to')
963e5c31af7Sopenharmony_ci    parser.add_argument('-registry', action='store',
964e5c31af7Sopenharmony_ci                        default=conventions.registry_path,
965e5c31af7Sopenharmony_ci                        help='Use specified registry file instead of default')
966e5c31af7Sopenharmony_ci    parser.add_argument('-extpath', action='store',
967e5c31af7Sopenharmony_ci                        default=None,
968e5c31af7Sopenharmony_ci                        help='Use extension descriptions from this directory instead of autogenerating extension refpages')
969e5c31af7Sopenharmony_ci
970e5c31af7Sopenharmony_ci    results = parser.parse_args()
971e5c31af7Sopenharmony_ci
972e5c31af7Sopenharmony_ci    # Load the generated apimap module
973e5c31af7Sopenharmony_ci    sys.path.insert(0, results.genpath)
974e5c31af7Sopenharmony_ci    import apimap as api
975e5c31af7Sopenharmony_ci
976e5c31af7Sopenharmony_ci    setLogFile(True,  True, results.logFile)
977e5c31af7Sopenharmony_ci    setLogFile(True, False, results.diagFile)
978e5c31af7Sopenharmony_ci    setLogFile(False, True, results.warnFile)
979e5c31af7Sopenharmony_ci
980e5c31af7Sopenharmony_ci    # Initialize static rewrite patterns for spec xrefs
981e5c31af7Sopenharmony_ci    xrefRewriteInitialize()
982e5c31af7Sopenharmony_ci
983e5c31af7Sopenharmony_ci    if results.baseDir is None:
984e5c31af7Sopenharmony_ci        baseDir = results.genpath + '/ref'
985e5c31af7Sopenharmony_ci    else:
986e5c31af7Sopenharmony_ci        baseDir = results.baseDir
987e5c31af7Sopenharmony_ci
988e5c31af7Sopenharmony_ci    # Dictionary of pages & aliases
989e5c31af7Sopenharmony_ci    pages = {}
990e5c31af7Sopenharmony_ci
991e5c31af7Sopenharmony_ci    for file in results.files:
992e5c31af7Sopenharmony_ci        d = genRef(file, baseDir)
993e5c31af7Sopenharmony_ci        pages.update(d)
994e5c31af7Sopenharmony_ci
995e5c31af7Sopenharmony_ci    # Now figure out which pages were not generated from the spec.
996e5c31af7Sopenharmony_ci    # This relies on the dictionaries of API constructs in the api module.
997e5c31af7Sopenharmony_ci
998e5c31af7Sopenharmony_ci    if not results.noauto:
999e5c31af7Sopenharmony_ci        # Must have an apiname selected to avoid complaints from
1000e5c31af7Sopenharmony_ci        # registry.loadFile, even though it is irrelevant to our uses.
1001e5c31af7Sopenharmony_ci        genOpts = GeneratorOptions(apiname = conventions.xml_api_name)
1002e5c31af7Sopenharmony_ci        registry = Registry(genOpts = genOpts)
1003e5c31af7Sopenharmony_ci        registry.loadFile(results.registry)
1004e5c31af7Sopenharmony_ci
1005e5c31af7Sopenharmony_ci        if conventions.write_refpage_include:
1006e5c31af7Sopenharmony_ci            # Only extensions with a supported="..." attribute in this set
1007e5c31af7Sopenharmony_ci            # will be considered for extraction/generation.
1008e5c31af7Sopenharmony_ci            ext_names = set(k for k, v in registry.extdict.items()
1009e5c31af7Sopenharmony_ci                            if conventions.xml_api_name in v.supported.split(','))
1010e5c31af7Sopenharmony_ci
1011e5c31af7Sopenharmony_ci            desired_extensions = ext_names.intersection(set(results.extension))
1012e5c31af7Sopenharmony_ci            for prefix in conventions.extension_index_prefixes:
1013e5c31af7Sopenharmony_ci                # Splits up into chunks, sorted within each chunk.
1014e5c31af7Sopenharmony_ci                filtered_extensions = sorted(
1015e5c31af7Sopenharmony_ci                    [name for name in desired_extensions
1016e5c31af7Sopenharmony_ci                     if name.startswith(prefix) and name not in extensions])
1017e5c31af7Sopenharmony_ci                for name in filtered_extensions:
1018e5c31af7Sopenharmony_ci                    # logWarn('NOT autogenerating extension refpage for', name)
1019e5c31af7Sopenharmony_ci                    extensions[name] = None
1020e5c31af7Sopenharmony_ci                    genExtension(baseDir, results.extpath, name, registry.extdict[name])
1021e5c31af7Sopenharmony_ci
1022e5c31af7Sopenharmony_ci        # autoGenFlagsPage is no longer needed because they are added to
1023e5c31af7Sopenharmony_ci        # the spec sources now.
1024e5c31af7Sopenharmony_ci        # for page in api.flags:
1025e5c31af7Sopenharmony_ci        #     if page not in genDict:
1026e5c31af7Sopenharmony_ci        #         autoGenFlagsPage(baseDir, page)
1027e5c31af7Sopenharmony_ci
1028e5c31af7Sopenharmony_ci        # autoGenHandlePage is no longer needed because they are added to
1029e5c31af7Sopenharmony_ci        # the spec sources now.
1030e5c31af7Sopenharmony_ci        # for page in api.structs:
1031e5c31af7Sopenharmony_ci        #    if typeCategory[page] == 'handle':
1032e5c31af7Sopenharmony_ci        #        autoGenHandlePage(baseDir, page)
1033e5c31af7Sopenharmony_ci
1034e5c31af7Sopenharmony_ci        sections = [
1035e5c31af7Sopenharmony_ci            (api.flags,        'Flag Types'),
1036e5c31af7Sopenharmony_ci            (api.enums,        'Enumerated Types'),
1037e5c31af7Sopenharmony_ci            (api.structs,      'Structures'),
1038e5c31af7Sopenharmony_ci            (api.protos,       'Prototypes'),
1039e5c31af7Sopenharmony_ci            (api.funcpointers, 'Function Pointers'),
1040e5c31af7Sopenharmony_ci            (api.basetypes,    apiName + ' Scalar Types'),
1041e5c31af7Sopenharmony_ci            (extensions,       apiName + ' Extensions'),
1042e5c31af7Sopenharmony_ci        ]
1043e5c31af7Sopenharmony_ci
1044e5c31af7Sopenharmony_ci        # Summarize pages that were not generated, for good or bad reasons
1045e5c31af7Sopenharmony_ci
1046e5c31af7Sopenharmony_ci        for (apiDict, title) in sections:
1047e5c31af7Sopenharmony_ci            # OpenXR was keeping a 'flagged' state which only printed out a
1048e5c31af7Sopenharmony_ci            # warning for the first non-generated page, but was otherwise
1049e5c31af7Sopenharmony_ci            # unused. This does not seem helpful.
1050e5c31af7Sopenharmony_ci            for page in apiDict:
1051e5c31af7Sopenharmony_ci                if page not in genDict:
1052e5c31af7Sopenharmony_ci                    # Page was not generated - why not?
1053e5c31af7Sopenharmony_ci                    if page in api.alias:
1054e5c31af7Sopenharmony_ci                        logDiag('(Benign, is an alias) Ref page for', title, page, 'is aliased into', api.alias[page])
1055e5c31af7Sopenharmony_ci                    elif page in api.flags and api.flags[page] is None:
1056e5c31af7Sopenharmony_ci                        logDiag('(Benign, no FlagBits defined) No ref page generated for ', title,
1057e5c31af7Sopenharmony_ci                                page)
1058e5c31af7Sopenharmony_ci                    else:
1059e5c31af7Sopenharmony_ci                        # Could introduce additional logic to detect
1060e5c31af7Sopenharmony_ci                        # external types and not emit them.
1061e5c31af7Sopenharmony_ci                        logWarn('No ref page generated for  ', title, page)
1062e5c31af7Sopenharmony_ci
1063e5c31af7Sopenharmony_ci        genSinglePageRef(baseDir)
1064e5c31af7Sopenharmony_ci
1065e5c31af7Sopenharmony_ci    if results.rewrite:
1066e5c31af7Sopenharmony_ci        # Generate Apache rewrite directives for refpage aliases
1067e5c31af7Sopenharmony_ci        fp = open(results.rewrite, 'w', encoding='utf-8')
1068e5c31af7Sopenharmony_ci
1069e5c31af7Sopenharmony_ci        for page in sorted(pages):
1070e5c31af7Sopenharmony_ci            p = pages[page]
1071e5c31af7Sopenharmony_ci            rewrite = p.name
1072e5c31af7Sopenharmony_ci
1073e5c31af7Sopenharmony_ci            if page != rewrite:
1074e5c31af7Sopenharmony_ci                print('RewriteRule ^', page, '.html$ ', rewrite, '.html',
1075e5c31af7Sopenharmony_ci                      sep='', file=fp)
1076e5c31af7Sopenharmony_ci        fp.close()
1077e5c31af7Sopenharmony_ci
1078e5c31af7Sopenharmony_ci    if results.toc:
1079e5c31af7Sopenharmony_ci        # Generate dynamic portion of refpage TOC
1080e5c31af7Sopenharmony_ci        fp = open(results.toc, 'w', encoding='utf-8')
1081e5c31af7Sopenharmony_ci
1082e5c31af7Sopenharmony_ci        # Run through dictionary of pages generating an TOC
1083e5c31af7Sopenharmony_ci        print(12 * ' ', '<li class="Level1">Alphabetic Contents', sep='', file=fp)
1084e5c31af7Sopenharmony_ci        print(16 * ' ', '<ul class="Level2">', sep='', file=fp)
1085e5c31af7Sopenharmony_ci        lastLetter = None
1086e5c31af7Sopenharmony_ci
1087e5c31af7Sopenharmony_ci        for page in sorted(pages, key=str.upper):
1088e5c31af7Sopenharmony_ci            p = pages[page]
1089e5c31af7Sopenharmony_ci            letter = page[0:1].upper()
1090e5c31af7Sopenharmony_ci
1091e5c31af7Sopenharmony_ci            if letter != lastLetter:
1092e5c31af7Sopenharmony_ci                if lastLetter:
1093e5c31af7Sopenharmony_ci                    # End previous block
1094e5c31af7Sopenharmony_ci                    print(24 * ' ', '</ul>', sep='', file=fp)
1095e5c31af7Sopenharmony_ci                    print(20 * ' ', '</li>', sep='', file=fp)
1096e5c31af7Sopenharmony_ci                # Start new block
1097e5c31af7Sopenharmony_ci                print(20 * ' ', '<li>', letter, sep='', file=fp)
1098e5c31af7Sopenharmony_ci                print(24 * ' ', '<ul class="Level3">', sep='', file=fp)
1099e5c31af7Sopenharmony_ci                lastLetter = letter
1100e5c31af7Sopenharmony_ci
1101e5c31af7Sopenharmony_ci            # Add this page to the list
1102e5c31af7Sopenharmony_ci            print(28 * ' ', '<li><a href="', p.name, '.html" ',
1103e5c31af7Sopenharmony_ci                  'target="pagedisplay">', page, '</a></li>',
1104e5c31af7Sopenharmony_ci                  sep='', file=fp)
1105e5c31af7Sopenharmony_ci
1106e5c31af7Sopenharmony_ci        if lastLetter:
1107e5c31af7Sopenharmony_ci            # Close the final letter block
1108e5c31af7Sopenharmony_ci            print(24 * ' ', '</ul>', sep='', file=fp)
1109e5c31af7Sopenharmony_ci            print(20 * ' ', '</li>', sep='', file=fp)
1110e5c31af7Sopenharmony_ci
1111e5c31af7Sopenharmony_ci        # Close the list
1112e5c31af7Sopenharmony_ci        print(16 * ' ', '</ul>', sep='', file=fp)
1113e5c31af7Sopenharmony_ci        print(12 * ' ', '</li>', sep='', file=fp)
1114e5c31af7Sopenharmony_ci
1115e5c31af7Sopenharmony_ci        # print('name {} -> page {}'.format(page, pages[page].name))
1116e5c31af7Sopenharmony_ci
1117e5c31af7Sopenharmony_ci        fp.close()
1118