cmd/bitwise_or.py
2022-02-12 19:50:00 -08:00

81 lines
2.3 KiB
Python

import argparse
import sys
from voussoirkit import betterhelp
from voussoirkit import interactive
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'bitwise_or')
CHUNK_SIZE = 2**20
def bitwise_or_argparse(args):
patterns = pipeable.input_many(args.files, skip_blank=True, strip=True)
files = list(pathclass.glob_many_files(patterns))
if len(files) < 2:
log.fatal('Need at least two input files.')
return 1
output = pathclass.Path(args.output)
if output.is_dir:
log.fatal('Output path "%s" is a directory.', args.output)
return 1
if any(output == file for file in files):
log.fatal('Output cannot be one of the inputs.')
return 1
if not output.exists:
pass
elif args.overwrite:
pass
elif not pipeable.in_tty():
return 1
elif not interactive.getpermission(f'Overwrite "{output.absolute_path}"?'):
return 1
handles = [file.open('rb') for file in files]
output_handle = output.open('wb')
while True:
chunk = 0
length = 1
for handle in handles[:]:
read = handle.read(CHUNK_SIZE)
length = max(length, len(read))
if not read:
handles.remove(handle)
chunk |= int.from_bytes(read, 'big')
if not handles:
break
output_handle.write(chunk.to_bytes(length, 'big'))
pipeable.stdout(output.absolute_path)
@vlogging.main_decorator
def main(argv):
parser = argparse.ArgumentParser(
description='''
Merge two or more files by performing bitwise or on their bits.
That is, every byte of the output file will be the bitwise or of the
corresponding byte from all of the input files.
''',
)
parser.add_argument('files', nargs='+')
parser.add_argument('--output', required=True, type=pathclass.Path)
parser.add_argument(
'--overwrite',
action='store_true',
help='''
Provide this flag if the output file already exists and you'd like to
overwrite it.
''',
)
parser.set_defaults(func=bitwise_or_argparse)
return betterhelp.go(parser, argv)
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))