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