Skip to content

Instantly share code, notes, and snippets.

@lifthrasiir
Last active March 12, 2020 17:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lifthrasiir/4ce6e3ce2b62919e7ec5c8a0d7d3705e to your computer and use it in GitHub Desktop.
Save lifthrasiir/4ce6e3ce2b62919e7ec5c8a0d7d3705e to your computer and use it in GitHub Desktop.
# 2020-02-13 Kang Seonghoon
# Public Domain
import os
import xml.etree.ElementTree as ET
from collections import namedtuple
class Entry(namedtuple('Entry', 'category emergency lang')):
def __repr__(self):
return f'{self.category}{"!" if self.emergency else ""}{"#" if self.lang else ""}'
CATEGORIES = {
'cmas_presidential_alerts_channels_range_strings': 'cmas1',
'cmas_alert_extreme_channels_range_strings': 'cmas2',
'cmas_alerts_severe_range_strings': 'cmas3',
'cmas_amber_alerts_channels_range_strings': 'amber',
'required_monthly_test_range_strings': 'monthly',
'exercise_alert_range_strings': 'exercise',
'operator_defined_alert_range_strings': 'operator',
'etws_alerts_range_strings': 'etws',
'etws_test_alerts_range_strings': 'etwstest',
'additional_cbs_channels_strings': 'cbs',
'emergency_alerts_channels_range_strings': 'alert',
'public_safety_messages_channels_range_strings': 'safety',
'state_local_test_alert_range_strings': 'cmastest',
'geo_fencing_trigger_messages_range_strings': 'geofence',
'alert_reminder_interval_values': None,
'alert_reminder_interval_active_values': None,
}
def handleitem(s, category):
ids, _, flags = s.partition(':')
idstart, _, idend = ids.partition('-')
idend = int(idend or idstart, 0)
idstart = int(idstart, 0)
emergency = None
lang = False
for flag in flags.split(','):
key, _, value = flag.strip().partition('=')
if key == 'rat':
if value != 'gsm': return
elif key == 'emergency':
emergency = value == 'true'
elif key == 'filter_language':
lang = True
return idstart, idend, Entry(category=category, emergency=emergency, lang=lang)
def handlexml(xmlpath):
tree = ET.parse(xmlpath)
entries = {}
for e in tree.findall('string-array'):
category = CATEGORIES[e.attrib['name']]
if not category: continue
ientries = {}
for item in e.findall('item'):
entry = handleitem(item.text, category)
if not entry: continue
idstart, idend, entry = entry
for i in range(idstart, idend + 1):
if i < 40960: # XXX
ientries[i] = entry
entries[category] = ientries
return entries
def tocolumns(entries):
columns = {}
for ientries in entries.values():
for i, entry in ientries.items():
assert i not in columns
columns[i] = entry
return columns
def main():
baseentries = handlexml(os.path.join('values', 'config.xml'))
basecolumns = tocolumns(baseentries)
allcolumns = {}
for root, dirs, files in os.walk('.', followlinks=True):
dirname = os.path.basename(root)
if dirname == 'values': continue
if 'config.xml' not in files: continue
xmlpath = os.path.join(root, 'config.xml')
entries = handlexml(xmlpath)
if entries:
entries = dict(baseentries, **entries)
allcolumns[dirname] = dict((k, '<>' if basecolumns.get(k) == v else v) for k, v in tocolumns(entries).items())
allcolumns['values'] = basecolumns
allids = sorted(set().union(*[entries.keys() for entries in allcolumns.values()]))
maxdirlen = max(len(k) for k in allcolumns.keys())
def z(s): return '\t'.join(s.split())
print(z('.' + ' ' * (maxdirlen + 3) + ''.join('%-12d' % id for id in allids)))
for k, entries in sorted(allcolumns.items()):
print(z(k.ljust(maxdirlen + 4) + ''.join('%-12s' % str(entries.get(id, '.')) for id in allids)))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment