# HG changeset patch # User Paul Boddie # Date 1481229909 -3600 # Node ID 17317598efd2909187e69b1a564264d25c32f30d # Parent 77b70c880119d138dc88be3e5873e3410304e82d Added support for fopen and opening files. Moved common stream functionality into the __builtins__.file module. Moved common type checking functionality into the __builtins__.types module. diff -r 77b70c880119 -r 17317598efd2 lib/__builtins__/file.py --- a/lib/__builtins__/file.py Thu Dec 08 19:29:12 2016 +0100 +++ b/lib/__builtins__/file.py Thu Dec 08 21:45:09 2016 +0100 @@ -19,14 +19,65 @@ this program. If not, see . """ -class file(object): +from __builtins__.types import check_int, check_string +import native + +class filestream: + + "Generic file-oriented stream functionality." + + def __init__(self, bufsize=1024): + self.bufsize = bufsize + + def read(self, n=0): + + "Read 'n' bytes from the stream." + + check_int(n) + + # Read any indicated number of bytes. + + if n > 0: + return native._fread(self.__data__, n) + + # Read all remaining bytes. + + else: + l = [] + + # Read until end-of-file. + + try: + while True: + l.append(native._fread(self.__data__, self.bufsize)) + + # Handle end-of-file reads. + + except EOFError: + pass + + return "".join(l) + + def write(self, s): + + "Write string 's' to the stream." + + check_string(s) + native._fwrite(self.__data__, s) + + def close(self): pass + +class file(filestream): "A file abstraction." - def __init__(self, name, mode=None, buffering=None): pass - def read(self, n=None): pass - def write(self, s): pass - def close(self): pass + def __init__(self, filename, mode="r", bufsize=1024): + + "Open the file with the given 'filename' using the given access 'mode'." + + get_using(filestream.__init__, self)(bufsize) + self.__data__ = native._fopen(filename, mode) + def readline(self, size=None): pass def readlines(self, size=None): pass diff -r 77b70c880119 -r 17317598efd2 lib/__builtins__/io.py --- a/lib/__builtins__/io.py Thu Dec 08 19:29:12 2016 +0100 +++ b/lib/__builtins__/io.py Thu Dec 08 21:45:09 2016 +0100 @@ -19,14 +19,7 @@ this program. If not, see . """ -def open(name, mode=None, buffering=None): - - """ - Open the file with the given 'name', using the given 'mode' and applying the - indicated 'buffering'. - """ - - return file(name, mode, buffering) +open = file def raw_input(prompt=None): pass diff -r 77b70c880119 -r 17317598efd2 lib/__builtins__/types.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/__builtins__/types.py Thu Dec 08 21:45:09 2016 +0100 @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +Common type validation functions. + +Copyright (C) 2016 Paul Boddie + +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 3 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. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +import native + +def check_int(i): + + "Check the given int 'i'." + + if not native._isinstance(i, int): + raise ValueError(i) + +def check_string(s): + + "Check the given string 's'." + + if not native._isinstance(s, string): + raise ValueError(s) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 77b70c880119 -r 17317598efd2 lib/native.py --- a/lib/native.py Thu Dec 08 19:29:12 2016 +0100 +++ b/lib/native.py Thu Dec 08 21:45:09 2016 +0100 @@ -100,6 +100,7 @@ # Input/output. +def _fopen(filename, mode): IOError def _fdopen(fd, mode): IOError def _read(fd, n): IOError def _write(fd, str): pass diff -r 77b70c880119 -r 17317598efd2 lib/posix/io.py --- a/lib/posix/io.py Thu Dec 08 19:29:12 2016 +0100 +++ b/lib/posix/io.py Thu Dec 08 21:45:09 2016 +0100 @@ -19,6 +19,8 @@ this program. If not, see . """ +from __builtins__.file import filestream +from __builtins__.types import check_int, check_string import native # Abstractions for system-level files and streams. @@ -37,17 +39,17 @@ "Read 'n' bytes from the file, returning a string." - _check_int(n) + check_int(n) return read(self.fd, n) def write(self, s): "Write string 's' to the file." - _check_string(s) + check_string(s) write(self.fd, s) -class sysstream: +class sysstream(filestream): "A system-level stream object." @@ -55,44 +57,8 @@ "Initialise the stream with the given 'fd' and 'mode'." + get_using(filestream.__init__, self)(bufsize) self.__data__ = fdopen(fd, mode) - self.bufsize = bufsize - - def read(self, n=0): - - "Read 'n' bytes from the stream." - - _check_int(n) - - # Read any indicated number of bytes. - - if n > 0: - return native._fread(self.__data__, n) - - # Read all remaining bytes. - - else: - l = [] - - # Read until end-of-file. - - try: - while True: - l.append(native._fread(self.__data__, self.bufsize)) - - # Handle end-of-file reads. - - except EOFError: - pass - - return "".join(l) - - def write(self, s): - - "Write string 's' to the stream." - - _check_string(s) - native._fwrite(self.__data__, s) # Standard streams. @@ -118,8 +84,8 @@ 'mode'. """ - _check_fd(fd) - _check_string(mode) + check_int(fd) + check_string(mode) return native._fdopen(fd, mode) def fpathconf(fd, name): pass @@ -145,8 +111,8 @@ Read using the low-level file descriptor 'fd' the given number of bytes 'n'. """ - _check_fd(fd) - _check_int(n) + check_int(fd) + check_int(n) return native._read(fd, n) def times(): pass @@ -159,8 +125,8 @@ "Write using the low-level file descriptor 'fd' the given string 's'." - _check_fd(fd) - _check_string(s) + check_int(fd) + check_string(s) native._write(fd, s) # Constants. @@ -185,27 +151,4 @@ O_TRUNC = 512 O_WRONLY = 1 -# Type validation functions. - -def _check_fd(fd): - - "Check the given low-level file descriptor 'fd'." - - if not native._isinstance(fd, int): - raise ValueError(fd) - -def _check_int(i): - - "Check the given int 'i'." - - if not native._isinstance(i, int): - raise ValueError(i) - -def _check_string(s): - - "Check the given string 's'." - - if not native._isinstance(s, string): - raise ValueError(s) - # vim: tabstop=4 expandtab shiftwidth=4 diff -r 77b70c880119 -r 17317598efd2 templates/native.c --- a/templates/native.c Thu Dec 08 19:29:12 2016 +0100 +++ b/templates/native.c Thu Dec 08 21:45:09 2016 +0100 @@ -680,13 +680,42 @@ /* Input/output. */ +__attr __fn_native__fopen(__attr __args[]) +{ + __attr * const filename = &__args[1]; + __attr * const mode = &__args[2]; + /* filename.__data__ interpreted as string */ + char *fn = __load_via_object(filename->value, __pos___data__).strvalue; + /* mode.__data__ interpreted as string */ + char *s = __load_via_object(mode->value, __pos___data__).strvalue; + FILE *f; + __attr attr; + + errno = 0; + f = fopen(fn, s); + + /* Produce an exception if the operation failed. */ + + if (f == NULL) + __raise_io_error(__new_int(errno)); + + /* Return the __data__ attribute. */ + + else + { + attr.context = 0; + attr.datavalue = (void *) f; + return attr; + } +} + __attr __fn_native__fdopen(__attr __args[]) { __attr * const fd = &__args[1]; __attr * const mode = &__args[2]; /* fd.__data__ interpreted as int */ int i = __load_via_object(fd->value, __pos___data__).intvalue; - /* str.__data__ interpreted as string */ + /* mode.__data__ interpreted as string */ char *s = __load_via_object(mode->value, __pos___data__).strvalue; FILE *f; __attr attr; diff -r 77b70c880119 -r 17317598efd2 templates/native.h --- a/templates/native.h Thu Dec 08 19:29:12 2016 +0100 +++ b/templates/native.h Thu Dec 08 21:45:09 2016 +0100 @@ -100,6 +100,7 @@ /* Input/output. */ +__attr __fn_native__fopen(__attr __args[]); __attr __fn_native__fdopen(__attr __args[]); __attr __fn_native__fread(__attr __args[]); __attr __fn_native__fwrite(__attr __args[]); diff -r 77b70c880119 -r 17317598efd2 tests/read_file.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/read_file.py Thu Dec 08 21:45:09 2016 +0100 @@ -0,0 +1,15 @@ +try: + f = open("tests/read_file.py") # this file! +except IOError, exc: + print "I/O error occurred:", exc.value + raise + +try: + s = f.read(5) + print s # try: + s = f.read(49) + print s # f = open("tests/read_file.py") # this file! + s = f.read() + print s +finally: + f.close() diff -r 77b70c880119 -r 17317598efd2 tests/read_stream.py --- a/tests/read_stream.py Thu Dec 08 19:29:12 2016 +0100 +++ b/tests/read_stream.py Thu Dec 08 21:45:09 2016 +0100 @@ -1,7 +1,9 @@ from sys import stdin +print "Reading 10 bytes..." s = stdin.read(10) print s +print "Reading to end of file..." s = stdin.read() print s