2022-04-04 17:54:37 +00:00
|
|
|
"""Extract various constants from Mac OS header files.
|
|
|
|
|
|
|
|
This program reads Script.h and TextCommon.h from Macintosh headers. Pass the
|
|
|
|
paths to one or both of these files when invoking this program, and the program
|
|
|
|
will write out the corresponding CSV files.
|
|
|
|
|
|
|
|
It does not matter what line endings or character encodings the headers use, as
|
|
|
|
long as the encoding is ASCII-compatible.
|
|
|
|
"""
|
2022-03-15 16:07:16 +00:00
|
|
|
import csv
|
2022-04-01 16:05:15 +00:00
|
|
|
import os
|
2022-03-15 16:07:16 +00:00
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
|
2022-04-01 16:05:15 +00:00
|
|
|
from typing import Iterator, List, Tuple
|
2022-03-15 16:07:16 +00:00
|
|
|
|
|
|
|
Item = Tuple[str, int]
|
|
|
|
|
2022-04-01 16:05:15 +00:00
|
|
|
def list_enums(filename: str) -> Iterator[Item]:
|
2022-04-04 17:54:37 +00:00
|
|
|
"""List enum definitions in a header file."""
|
2022-04-01 16:05:15 +00:00
|
|
|
with open(filename, 'rb') as fp:
|
|
|
|
data = fp.read()
|
2022-04-01 16:17:43 +00:00
|
|
|
for item in re.finditer(
|
|
|
|
rb'^\s*(\w+)\s*=\s*((?:0x)?\d+)u?l?\b',
|
|
|
|
data, re.MULTILINE | re.IGNORECASE):
|
2022-04-01 16:05:15 +00:00
|
|
|
name, value = item.groups()
|
2022-04-01 16:17:43 +00:00
|
|
|
yield name.decode('ASCII'), int(value, 0)
|
2022-04-01 16:05:15 +00:00
|
|
|
|
2022-03-15 16:07:16 +00:00
|
|
|
def index_of(data: List[Item], key: str) -> int:
|
2022-04-04 17:54:37 +00:00
|
|
|
"""Return the index of the enum with the given name."""
|
2022-03-15 16:07:16 +00:00
|
|
|
for i, (name, _) in enumerate(data):
|
|
|
|
if name == key:
|
|
|
|
return i
|
|
|
|
raise ValueError('missing value: {!r}'.format(key))
|
|
|
|
|
|
|
|
def slice(data: List[Item], first: str, last: str) -> List[Item]:
|
2022-04-04 17:54:37 +00:00
|
|
|
"""Return a slice of enums, by giving the name of the first and last."""
|
2022-03-15 16:07:16 +00:00
|
|
|
return data[index_of(data, first):index_of(data, last)+1]
|
|
|
|
|
|
|
|
def write_csv(fname: str, data: List[Item]) -> None:
|
2022-04-04 17:54:37 +00:00
|
|
|
"""Write a CSV file containing enum values."""
|
2022-04-01 16:05:15 +00:00
|
|
|
print('Writing', fname, file=sys.stderr)
|
2022-03-15 16:07:16 +00:00
|
|
|
with open(fname, 'w') as fp:
|
|
|
|
w = csv.writer(fp)
|
|
|
|
w.writerow(['Name', 'Value'])
|
|
|
|
for item in data:
|
|
|
|
w.writerow(item)
|
|
|
|
|
2022-04-01 16:05:15 +00:00
|
|
|
def process_script(filename: str) -> None:
|
2022-04-04 17:54:37 +00:00
|
|
|
"""Process the <Script.h> header file."""
|
2022-03-15 16:07:16 +00:00
|
|
|
scripts: List[Item] = []
|
|
|
|
regions: List[Item] = []
|
2022-04-01 16:05:15 +00:00
|
|
|
for name, value in list_enums(filename):
|
|
|
|
if name.startswith('sm'):
|
|
|
|
scripts.append((name, value))
|
|
|
|
elif name.startswith('ver'):
|
|
|
|
regions.append((name, value))
|
2022-03-15 16:07:16 +00:00
|
|
|
write_csv('script.csv', slice(scripts, 'smRoman', 'smUninterp'))
|
|
|
|
write_csv('region.csv', slice(regions, 'verUS', 'verGreenland'))
|
|
|
|
|
2022-04-01 16:05:15 +00:00
|
|
|
def process_textcommon(filename: str) -> None:
|
2022-04-04 17:54:37 +00:00
|
|
|
"""Process the <TextCommon.h> header file."""
|
2022-04-01 16:05:15 +00:00
|
|
|
encodings: List[Item] = []
|
|
|
|
for name, value in list_enums(filename):
|
|
|
|
if name.startswith('kTextEncoding'):
|
|
|
|
encodings.append((name, value))
|
2022-04-01 16:17:43 +00:00
|
|
|
write_csv('encoding.csv', encodings)
|
2022-04-01 16:05:15 +00:00
|
|
|
|
|
|
|
def process(filename: str) -> None:
|
2022-04-04 17:54:37 +00:00
|
|
|
"""Process any header file."""
|
2022-04-01 16:05:15 +00:00
|
|
|
name = os.path.basename(filename).lower()
|
|
|
|
if name == 'script.h':
|
|
|
|
process_script(filename)
|
|
|
|
elif name == 'textcommon.h':
|
|
|
|
process_textcommon(filename)
|
|
|
|
else:
|
|
|
|
print('Error: unknown header file:', repr(filename), file=sys.stderr)
|
|
|
|
raise SystemExit(1)
|
|
|
|
|
|
|
|
def main(argv: List[str]) -> None:
|
|
|
|
if not argv:
|
|
|
|
sys.stderr.write(
|
|
|
|
'Usage: script_gen.py [<file.h>...]\n'
|
|
|
|
'This will read Script.h and TextCommon.h\n')
|
|
|
|
raise SystemExit(2)
|
|
|
|
for arg in argv:
|
|
|
|
process(arg)
|
|
|
|
|
2022-03-15 16:07:16 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
main(sys.argv[1:])
|