Files
littlefs/scripts/parity.py
Christopher Haster 55ea13b994 scripts: Reverted del to resolve shadowed builtins
I don't know how I completely missed that this doesn't actually work!

Using del _does_ work in Python's repl, but it makes sense the repl may
differ from actual function execution in this case.

The problem is Python still thinks the relevant builtin is a local
variables after deletion, raising an UnboundLocalError instead of
performing a global lookup. In theory this would work if the variable
could be made global, but since global/nonlocal statements are lifted,
Python complains with "SyntaxError: name 'list' is parameter and
global".

And that's A-Ok! Intentionally shadowing language builtins already puts
this code deep into ugly hacks territory.
2025-05-15 14:10:42 -05:00

109 lines
2.8 KiB
Python
Executable File

#!/usr/bin/env python3
# prevent local imports
if __name__ == "__main__":
__import__('sys').path.pop(0)
import io
import os
import struct
import sys
import functools as ft
import operator as op
try:
import crc32c as crc32c_lib
except ModuleNotFoundError:
crc32c_lib = None
# open with '-' for stdin/stdout
def openio(path, mode='r', buffering=-1):
import os
if path == '-':
if 'r' in mode:
return os.fdopen(os.dup(sys.stdin.fileno()), mode, buffering)
else:
return os.fdopen(os.dup(sys.stdout.fileno()), mode, buffering)
else:
return open(path, mode, buffering)
def crc32c(data, crc=0):
if crc32c_lib is not None:
return crc32c_lib.crc32c(data, crc)
else:
crc ^= 0xffffffff
for b in data:
crc ^= b
for j in range(8):
crc = (crc >> 1) ^ ((crc & 1) * 0x82f63b78)
return 0xffffffff ^ crc
def popc(x):
return bin(x).count('1')
def parity(x):
return popc(x) & 1
def main(paths, *,
hex=False,
string=False):
import builtins
hex_, hex = hex, builtins.hex
# interpret as sequence of hex bytes
if hex_:
bytes_ = [b for path in paths for b in path.split()]
print('%01x' % parity(crc32c(bytes(int(b, 16) for b in bytes_))))
# interpret as strings
elif string:
for path in paths:
print('%01x %s' % (parity(crc32c(path.encode('utf8'))), path))
# default to interpreting as paths
else:
if not paths:
paths = [None]
for path in paths:
with openio(path or '-', 'rb') as f:
# calculate crc, crc32c preserves parity
crc = 0
while True:
block = f.read(io.DEFAULT_BUFFER_SIZE)
if not block:
break
crc = crc32c(block, crc)
# print what we found
if path is not None:
print('%01x %s' % (parity(crc), path))
else:
print('%01x' % parity(crc))
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(
description="Calculates parity.",
allow_abbrev=False)
parser.add_argument(
'paths',
nargs='*',
help="Paths to read. Reads stdin by default.")
parser.add_argument(
'-x', '--hex',
action='store_true',
help="Interpret as a sequence of hex bytes.")
parser.add_argument(
'-s', '--string',
action='store_true',
help="Interpret as strings.")
sys.exit(main(**{k: v
for k, v in vars(parser.parse_intermixed_args()).items()
if v is not None}))