diff options
Diffstat (limited to 'bin/fnio.py')
-rw-r--r-- | bin/fnio.py | 135 |
1 files changed, 85 insertions, 50 deletions
diff --git a/bin/fnio.py b/bin/fnio.py index b9f07512fc3e..e2b31914e913 100644 --- a/bin/fnio.py +++ b/bin/fnio.py @@ -1,15 +1,19 @@ # -# Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com> +# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com> # -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # import codecs @@ -17,42 +21,46 @@ import struct import sys import os - -BINARY_ENCODING = '_fnio_binary' - -class InputStream: - def __init__(self, file_name, encoding=BINARY_ENCODING): +# -- InputFileStream -- +class InputFileStream: + def __init__(self, file_name, encoding='binary'): if file_name is not None: - if encoding == BINARY_ENCODING: - self.file = open(file_name, 'rb') - else: - self.file = open(file_name, 'r', encoding=encoding) - + self.file = open(file_name, 'r') if encoding is None else open(file_name, 'rb') self.st_name = file_name else: - if encoding == BINARY_ENCODING: - self.file = sys.stdin.buffer - elif encoding is None: - self.file = sys.stdin - else: - self.file = codecs.getreader(encoding)(sys.stdin.buffer) - + self.file = sys.stdin if encoding is None else sys.stdin.buffer self.st_name = '<stdin>' + if encoding not in [None, 'binary']: + self.file = codecs.getreader(encoding)(self.file) + self.line_no = 0 self.eof = False def close(self): - self.line_no = 0 - self.eof = False + self.unseek() self.file.close() + def fstat(self): + return None if (self.file == sys.stdin.buffer or self.file.isatty()) else os.fstat(self.file.fileno()) + + def location(self): return '%s:%s' % (self.st_name, 'EOF: ' if self.eof else '%d: ' % self.line_no if self.line_no > 0 else ' ') + def process(self, callback): + try: + result = callback(self) + self.close() + return result + except Exception as ex: + ex.message = self.location() + getattr(ex, 'message', str(ex)) + raise + + def read_line(self): return self.read_lines(lambda line: line) @@ -66,16 +74,21 @@ class InputStream: if line is not None: return line except OSError: - self.line_no = 0 - self.eof = False + self.unseek() raise self.eof = True return None -class OutputStream: - def __init__(self, file_name): + def unseek(self): + self.line_no = 0 + self.eof = False + + +# -- OutputFileStream -- +class OutputFileStream: + def __init__(self, file_name, encoding='binary'): if file_name is not None: self.file = open(file_name, 'wb') self.st_name = file_name @@ -83,59 +96,81 @@ class OutputStream: self.file = sys.stdout.buffer self.st_name = '<stdout>' - self.close_attempt = False + if encoding is None and self.file.isatty(): + raise Exception(self.location() + 'binary output may not be send to a terminal') - - def close(self): - self.close_attempt = True - self.file.close() + self.encoding = (None if encoding == 'binary' else encoding) + self.close_attempt = False - def destroy(self): + def abort(self): errors = '' if self.file != sys.stdout.buffer: if not self.close_attempt: try: - self.file.close() + self.close() except Exception as ex: - errors += '\n%s: close: %s' % (self.st_name, str(ex)) + errors += '\n%sclose: %s' % (self.location(), str(ex)) try: os.remove(self.st_name) except Exception as ex: - errors += '\n%s: unlink: %s' % (self.st_name, str(ex)) + errors += '\n%sunlink: %s' % (self.location(), str(ex)) return errors + def close(self): + self.close_attempt = True + self.file.close() + + def location(self): return self.st_name + ': ' - def write(self, buffer): - self.file.write(buffer) + def process(self, callback): + try: + callback(self) + self.close() + except Exception as ex: + ex.message = self.location() + getattr(ex, 'message', str(ex)) + self.abort() + raise + + + def write(self, data): + self.file.write(data) def write8(self, value): - self.file.write(struct.pack('B', value)) + self.write(struct.pack('B', value)) def write16(self, value): - self.file.write(struct.pack('<H', value)) + self.write(struct.pack('<H', value)) def write32(self, value): - self.file.write(struct.pack('<L', value)) + self.write(struct.pack('<L', value)) - def write_line(self, bstr): - self.file.write(bstr + b'\n') + def write_line(self, text): + self.write((text if self.encoding is None else bytes(text, self.encoding)) + b'\n') def write_prop(self, name, value): - self.write_line((bytes(name, 'ascii') + b' ' + value).strip()) + self.write_line((bytes(name, 'ascii') + b' ' + value).rstrip()) def write_zstr(self, bstr, num_zeros): - self.file.write(bstr + bytes(num_zeros)) + self.write(bstr + bytes(num_zeros)) + + +# -- read/write file -- +def read_file(file_name, callback, encoding='binary'): + return InputFileStream(file_name, encoding).process(callback) + + +def write_file(file_name, callback, encoding='binary'): + return OutputFileStream(file_name, encoding).process(callback) |