| #!/usr/bin/python3 |
| # |
| # Copyright 2016-2023 The Khronos Group Inc. |
| # |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| # fixupRef.py - replace old // refBegin .. // refEnd syntax with new |
| # open block syntax |
| # |
| # Usage: fixupRef.py [-outdir path] [-overwrite] files |
| |
| from reflib import * |
| from vkapi import * |
| import argparse, copy, io, os, pdb, re, string, sys |
| |
| # Return 'None' for None, the string otherwise |
| def noneStr(str): |
| if str == None: |
| return '(None)' |
| else: |
| return str |
| |
| # Escape single quotes in a string for asciidoc |
| def escapeQuote(str): |
| return str.replace("'", "\'") |
| |
| # Start a refpage open block |
| def openBlock(pi, fp): |
| if pi.refs != '': |
| print("[open,refpage='" + pi.name + |
| "',desc='" + pi.desc + |
| "',type='" + pi.type + |
| "',xrefs='" + pi.refs + "']", |
| file=fp) |
| else: |
| print("[open,refpage='" + pi.name + |
| "',desc='" + pi.desc + |
| "',type='" + pi.type + "']", |
| file=fp) |
| print('--', file=fp) |
| |
| # End a refpage open block |
| def closeBlock(pi, fp): |
| print('--', file=fp) |
| # Just for finding block ends while debugging |
| # print("// end [open,refpage='" + pi.name + "']", file=fp) |
| |
| # Replace old // refBegin .. // refEnd references in an asciidoc |
| # file with open blocks, per # ??? . |
| # specFile - filename to extract from |
| # outDir - output directory to write updated file to, if not overwritten |
| # overwrite - True if the file should be overwritten in place |
| # skipped - set of filenames containing commands which were not |
| # rewritten with open blocks (e.g. enums). Updated in place. |
| def replaceRef(specFile, outDir, overwrite = False, skipped = set()): |
| file = loadFile(specFile) |
| if file == None: |
| return |
| |
| # Save the path to this file for later use in rewriting relative includes |
| specDir = os.path.dirname(os.path.abspath(specFile)) |
| |
| pageMap = findRefs(file) |
| logDiag(specFile + ': found', len(pageMap.keys()), 'potential pages') |
| |
| sys.stderr.flush() |
| |
| # Fix up references in pageMap |
| fixupRefs(pageMap, specFile, file) |
| |
| # Map the page info dictionary into a dictionary of actions |
| # keyed by line number they are performed on/after: |
| # 'action' : 'begin' or 'end'. What to do on a refBegin or refEnd line |
| # 'replace': True if this line needs to be replaced |
| # 'name' : Name of the ref page being defined |
| # 'desc' : One-line description of the ref page being defined |
| # 'type' : Type of the ref page being defined, 'structs', 'protos', etc. |
| # 'refs' : Space-separated string of cross-referenced pages |
| |
| actions = { } |
| |
| for name in pageMap.keys(): |
| pi = pageMap[name] |
| |
| # Cleanup parameters for output |
| pi.name = noneStr(pi.name) |
| pi.desc = escapeQuote(noneStr(pi.desc)) |
| |
| if pi.extractPage: |
| if (file[pi.begin][0:11] == '// refBegin'): |
| # Replace line |
| actions[pi.begin] = { |
| 'action' : 'begin', |
| 'replace' : True, |
| 'pageinfo' : pi |
| } |
| else: |
| # Insert line |
| actions[pi.begin] = { |
| 'action' : 'begin', |
| 'replace' : False, |
| 'pageinfo' : pi |
| } |
| |
| if (file[pi.end][0:9] == '// refEnd'): |
| # Replace line |
| actions[pi.end] = { |
| 'action' : 'end', |
| 'replace' : True, |
| 'pageinfo' : pi |
| } |
| else: |
| # Insert line |
| actions[pi.end] = { |
| 'action' : 'end', |
| 'replace' : False, |
| 'pageinfo' : pi |
| } |
| else: |
| logWarn('Skipping replacement for', pi.name, 'at', specFile, |
| 'line', pi.begin) |
| print('Skipping replacement for', pi.name, 'at', specFile, |
| 'line', pi.begin) |
| printPageInfo(pi, file) |
| skipped.add(specFile) |
| |
| if overwrite: |
| pageName = specFile |
| else: |
| pageName = outDir + '/' + os.path.basename(specFile) |
| |
| fp = open(pageName, 'w', encoding='utf-8') |
| |
| line = 0 |
| for text in file: |
| if line in actions.keys(): |
| action = actions[line]['action'] |
| replace = actions[line]['replace'] |
| pi = actions[line]['pageinfo'] |
| |
| logDiag('ACTION:', action, 'REPLACE:', replace, 'at line', line) |
| logDiag('PageInfo of action:') |
| printPageInfo(pi, file) |
| |
| if action == 'begin': |
| openBlock(pi, fp) |
| if not replace: |
| print(text, file=fp, end='') |
| elif action == 'end': |
| if not replace: |
| print(text, file=fp, end='') |
| closeBlock(pi, fp) |
| else: |
| print('ERROR: unrecognized action:', action, 'in', |
| specFile, 'at line', line) |
| print(text, file=fp, end='') |
| else: |
| print(text, file=fp, end='') |
| line = line + 1 |
| |
| fp.close() |
| |
| #for line in sorted(actions.keys()): |
| # action = actions[line] |
| # print('action at line', line, '\t', |
| # action[0], action[1], action[2]) |
| |
| if __name__ == '__main__': |
| global genDict |
| genDict = {} |
| |
| parser = argparse.ArgumentParser() |
| |
| parser.add_argument('-diag', action='store', dest='diagFile', |
| help='Set the diagnostic file') |
| parser.add_argument('-warn', action='store', dest='warnFile', |
| help='Set the warning file') |
| parser.add_argument('-log', action='store', dest='logFile', |
| help='Set the log file for both diagnostics and warnings') |
| parser.add_argument('-outdir', action='store', dest='outDir', |
| default='out', |
| help='Set the base directory in which pages are generated') |
| parser.add_argument('-overwrite', action='store_true', |
| help='Overwrite input filenames instead of writing different output filenames') |
| parser.add_argument('files', metavar='filename', nargs='*', |
| help='a filename to extract ref pages from') |
| parser.add_argument('--version', action='version', version='%(prog)s 1.0') |
| |
| results = parser.parse_args() |
| |
| setLogFile(True, True, results.logFile) |
| setLogFile(True, False, results.diagFile) |
| setLogFile(False, True, results.warnFile) |
| |
| skipped = set() |
| for file in results.files: |
| replaceRef(file, results.outDir, results.overwrite, skipped) |
| |
| if len(skipped) > 0: |
| print('Files containing skipped feature blocks:') |
| for file in sorted(skipped): |
| print('\t' + file) |