Lichen

Changeset

529:d6a50fe5b3ad
2017-02-02 Paul Boddie raw files shortlog changelog graph Moved C library functionality into a separate package, adjusting built-in object dependencies and making the POSIX functionality more specific (and less likely to be included by many programs).
lib/__builtins__/file.py (file) lib/__builtins__/stream.py (file) lib/libc/__init__.py (file) lib/libc/io.py (file) lib/posix/io.py (file) lib/sys.py (file)
     1.1 --- a/lib/__builtins__/file.py	Thu Feb 02 22:38:26 2017 +0100
     1.2 +++ b/lib/__builtins__/file.py	Thu Feb 02 22:41:07 2017 +0100
     1.3 @@ -3,7 +3,7 @@
     1.4  """
     1.5  File objects.
     1.6  
     1.7 -Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
     1.8 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     1.9  
    1.10  This program is free software; you can redistribute it and/or modify it under
    1.11  the terms of the GNU General Public License as published by the Free Software
    1.12 @@ -19,141 +19,8 @@
    1.13  this program.  If not, see <http://www.gnu.org/licenses/>.
    1.14  """
    1.15  
    1.16 -from __builtins__.types import check_int, check_string
    1.17 -from native import isinstance as _isinstance, fclose, fflush, fopen, fread, fwrite
    1.18 -
    1.19 -class filestream:
    1.20 -
    1.21 -    "Generic file-oriented stream functionality."
    1.22 -
    1.23 -    def __init__(self, encoding=None, bufsize=1024):
    1.24 -
    1.25 -        "Initialise the stream with the given 'encoding' and 'bufsize'."
    1.26 -
    1.27 -        self.encoding = encoding
    1.28 -        self.bufsize = bufsize
    1.29 -
    1.30 -        # Internal stream details.
    1.31 -
    1.32 -        self.__data__ = None
    1.33 -
    1.34 -    def _convert(self, bytes):
    1.35 -
    1.36 -        "Convert 'bytes' to text if necessary."
    1.37 -
    1.38 -        if self.encoding:
    1.39 -            return unicode(bytes, self.encoding)
    1.40 -        else:
    1.41 -            return bytes
    1.42 -
    1.43 -    def flush(self):
    1.44 -
    1.45 -        "Flush the stream."
    1.46 -
    1.47 -        fflush(self.__data__)
    1.48 -
    1.49 -    def read(self, n=0):
    1.50 -
    1.51 -        "Read 'n' bytes from the stream."
    1.52 -
    1.53 -        check_int(n)
    1.54 -
    1.55 -        # Read any indicated number of bytes.
    1.56 -
    1.57 -        if n > 0:
    1.58 -            s = fread(self.__data__, n)
    1.59 -
    1.60 -        # Read all remaining bytes.
    1.61 -
    1.62 -        else:
    1.63 -            l = []
    1.64 -
    1.65 -            # Read until end-of-file.
    1.66 -
    1.67 -            try:
    1.68 -                while True:
    1.69 -                    self._read_data(l)
    1.70 -
    1.71 -            # Handle end-of-file reads.
    1.72 -
    1.73 -            except EOFError:
    1.74 -                pass
    1.75 -
    1.76 -            s = "".join(l)
    1.77 -
    1.78 -        return self._convert(s)
    1.79 -
    1.80 -    def readline(self, n=0):
    1.81 -
    1.82 -        """
    1.83 -        Read until an end-of-line indicator is encountered or at most 'n' bytes,
    1.84 -        if indicated.
    1.85 -        """
    1.86 -
    1.87 -        check_int(n)
    1.88 -
    1.89 -        # Read any indicated number of bytes.
    1.90 -
    1.91 -        if n > 0:
    1.92 -            s = fread(self.__data__, n)
    1.93 -
    1.94 -        # Read until an end-of-line indicator.
    1.95 -
    1.96 -        else:
    1.97 -            l = []
    1.98 -
    1.99 -            # Read until end-of-line or end-of-file.
   1.100 -
   1.101 -            try:
   1.102 -                while not self._read_until_newline(l):
   1.103 -                    pass
   1.104 -
   1.105 -            # Handle end-of-file reads.
   1.106 -
   1.107 -            except EOFError:
   1.108 -                pass
   1.109 -
   1.110 -            s = "".join(l)
   1.111 -
   1.112 -        return self._convert(s)
   1.113 -
   1.114 -    def _read_data(self, l):
   1.115 -
   1.116 -        "Read data into 'l'."
   1.117 -
   1.118 -        l.append(fread(self.__data__, self.bufsize))
   1.119 -
   1.120 -    def _read_until_newline(self, l):
   1.121 -
   1.122 -        "Read data into 'l', returning whether a newline has been read."
   1.123 -
   1.124 -        # NOTE: Only POSIX newlines are supported currently.
   1.125 -
   1.126 -        s = fread(self.__data__, 1)
   1.127 -        l.append(s)
   1.128 -        return s == "\n"
   1.129 -
   1.130 -    def readlines(self, n=None): pass
   1.131 -
   1.132 -    def write(self, s):
   1.133 -
   1.134 -        "Write string 's' to the stream."
   1.135 -
   1.136 -        check_string(s)
   1.137 -
   1.138 -        # Encode text as bytes if necessary. When the encoding is not set, any
   1.139 -        # original encoding of the text will be applied.
   1.140 -
   1.141 -        if _isinstance(s, utf8string):
   1.142 -            s = s.encode(self.encoding)
   1.143 -
   1.144 -        fwrite(self.__data__, s)
   1.145 -
   1.146 -    def close(self):
   1.147 -
   1.148 -        "Close the stream."
   1.149 -
   1.150 -        fclose(self.__data__)
   1.151 +from __builtins__.stream import filestream
   1.152 +from native import fopen, fread
   1.153  
   1.154  class file(filestream):
   1.155  
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/lib/__builtins__/stream.py	Thu Feb 02 22:41:07 2017 +0100
     2.3 @@ -0,0 +1,158 @@
     2.4 +#!/usr/bin/env python
     2.5 +
     2.6 +"""
     2.7 +Stream objects.
     2.8 +
     2.9 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    2.10 +
    2.11 +This program is free software; you can redistribute it and/or modify it under
    2.12 +the terms of the GNU General Public License as published by the Free Software
    2.13 +Foundation; either version 3 of the License, or (at your option) any later
    2.14 +version.
    2.15 +
    2.16 +This program is distributed in the hope that it will be useful, but WITHOUT
    2.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.18 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    2.19 +details.
    2.20 +
    2.21 +You should have received a copy of the GNU General Public License along with
    2.22 +this program.  If not, see <http://www.gnu.org/licenses/>.
    2.23 +"""
    2.24 +
    2.25 +from __builtins__.types import check_int, check_string
    2.26 +from native import isinstance as _isinstance, fclose, fflush, fread, fwrite
    2.27 +
    2.28 +class filestream:
    2.29 +
    2.30 +    "Generic file-oriented stream functionality."
    2.31 +
    2.32 +    def __init__(self, encoding=None, bufsize=1024):
    2.33 +
    2.34 +        "Initialise the stream with the given 'encoding' and 'bufsize'."
    2.35 +
    2.36 +        self.encoding = encoding
    2.37 +        self.bufsize = bufsize
    2.38 +
    2.39 +        # Internal stream details.
    2.40 +
    2.41 +        self.__data__ = None
    2.42 +
    2.43 +    def _convert(self, bytes):
    2.44 +
    2.45 +        "Convert 'bytes' to text if necessary."
    2.46 +
    2.47 +        if self.encoding:
    2.48 +            return unicode(bytes, self.encoding)
    2.49 +        else:
    2.50 +            return bytes
    2.51 +
    2.52 +    def flush(self):
    2.53 +
    2.54 +        "Flush the stream."
    2.55 +
    2.56 +        fflush(self.__data__)
    2.57 +
    2.58 +    def read(self, n=0):
    2.59 +
    2.60 +        "Read 'n' bytes from the stream."
    2.61 +
    2.62 +        check_int(n)
    2.63 +
    2.64 +        # Read any indicated number of bytes.
    2.65 +
    2.66 +        if n > 0:
    2.67 +            s = fread(self.__data__, n)
    2.68 +
    2.69 +        # Read all remaining bytes.
    2.70 +
    2.71 +        else:
    2.72 +            l = []
    2.73 +
    2.74 +            # Read until end-of-file.
    2.75 +
    2.76 +            try:
    2.77 +                while True:
    2.78 +                    self._read_data(l)
    2.79 +
    2.80 +            # Handle end-of-file reads.
    2.81 +
    2.82 +            except EOFError:
    2.83 +                pass
    2.84 +
    2.85 +            s = "".join(l)
    2.86 +
    2.87 +        return self._convert(s)
    2.88 +
    2.89 +    def readline(self, n=0):
    2.90 +
    2.91 +        """
    2.92 +        Read until an end-of-line indicator is encountered or at most 'n' bytes,
    2.93 +        if indicated.
    2.94 +        """
    2.95 +
    2.96 +        check_int(n)
    2.97 +
    2.98 +        # Read any indicated number of bytes.
    2.99 +
   2.100 +        if n > 0:
   2.101 +            s = fread(self.__data__, n)
   2.102 +
   2.103 +        # Read until an end-of-line indicator.
   2.104 +
   2.105 +        else:
   2.106 +            l = []
   2.107 +
   2.108 +            # Read until end-of-line or end-of-file.
   2.109 +
   2.110 +            try:
   2.111 +                while not self._read_until_newline(l):
   2.112 +                    pass
   2.113 +
   2.114 +            # Handle end-of-file reads.
   2.115 +
   2.116 +            except EOFError:
   2.117 +                pass
   2.118 +
   2.119 +            s = "".join(l)
   2.120 +
   2.121 +        return self._convert(s)
   2.122 +
   2.123 +    def _read_data(self, l):
   2.124 +
   2.125 +        "Read data into 'l'."
   2.126 +
   2.127 +        l.append(fread(self.__data__, self.bufsize))
   2.128 +
   2.129 +    def _read_until_newline(self, l):
   2.130 +
   2.131 +        "Read data into 'l', returning whether a newline has been read."
   2.132 +
   2.133 +        # NOTE: Only POSIX newlines are supported currently.
   2.134 +
   2.135 +        s = fread(self.__data__, 1)
   2.136 +        l.append(s)
   2.137 +        return s == "\n"
   2.138 +
   2.139 +    def readlines(self, n=None): pass
   2.140 +
   2.141 +    def write(self, s):
   2.142 +
   2.143 +        "Write string 's' to the stream."
   2.144 +
   2.145 +        check_string(s)
   2.146 +
   2.147 +        # Encode text as bytes if necessary. When the encoding is not set, any
   2.148 +        # original encoding of the text will be applied.
   2.149 +
   2.150 +        if _isinstance(s, utf8string):
   2.151 +            s = s.encode(self.encoding)
   2.152 +
   2.153 +        fwrite(self.__data__, s)
   2.154 +
   2.155 +    def close(self):
   2.156 +
   2.157 +        "Close the stream."
   2.158 +
   2.159 +        fclose(self.__data__)
   2.160 +
   2.161 +# vim: tabstop=4 expandtab shiftwidth=4
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/lib/libc/__init__.py	Thu Feb 02 22:41:07 2017 +0100
     3.3 @@ -0,0 +1,5 @@
     3.4 +#!/usr/bin/env python
     3.5 +
     3.6 +"C library support package."
     3.7 +
     3.8 +# vim: tabstop=4 expandtab shiftwidth=4
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/lib/libc/io.py	Thu Feb 02 22:41:07 2017 +0100
     4.3 @@ -0,0 +1,129 @@
     4.4 +#!/usr/bin/env python
     4.5 +
     4.6 +"""
     4.7 +C library input/output.
     4.8 +
     4.9 +Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk>
    4.10 +
    4.11 +This program is free software; you can redistribute it and/or modify it under
    4.12 +the terms of the GNU General Public License as published by the Free Software
    4.13 +Foundation; either version 3 of the License, or (at your option) any later
    4.14 +version.
    4.15 +
    4.16 +This program is distributed in the hope that it will be useful, but WITHOUT
    4.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.18 +FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    4.19 +details.
    4.20 +
    4.21 +You should have received a copy of the GNU General Public License along with
    4.22 +this program.  If not, see <http://www.gnu.org/licenses/>.
    4.23 +"""
    4.24 +
    4.25 +from __builtins__.stream import filestream
    4.26 +from __builtins__.types import check_int, check_string
    4.27 +
    4.28 +import locale
    4.29 +
    4.30 +from native import (
    4.31 +    close as _close,
    4.32 +    fdopen as _fdopen,
    4.33 +    read as _read,
    4.34 +    write as _write
    4.35 +    )
    4.36 +
    4.37 +# Abstractions for system-level files and streams.
    4.38 +
    4.39 +class sysfile:
    4.40 +
    4.41 +    "A system-level file object."
    4.42 +
    4.43 +    def __init__(self, fd):
    4.44 +
    4.45 +        "Initialise the file with the given 'fd'."
    4.46 +
    4.47 +        self.fd = fd
    4.48 +
    4.49 +    def read(self, n):
    4.50 +
    4.51 +        "Read 'n' bytes from the file, returning a string."
    4.52 +
    4.53 +        return read(self.fd, n)
    4.54 +
    4.55 +    def write(self, s):
    4.56 +
    4.57 +        "Write string 's' to the file."
    4.58 +
    4.59 +        return write(self.fd, s)
    4.60 +
    4.61 +    def close(self):
    4.62 +
    4.63 +        "Close the file."
    4.64 +
    4.65 +        close(self.fd)
    4.66 +
    4.67 +class sysstream(filestream):
    4.68 +
    4.69 +    "A system-level stream object."
    4.70 +
    4.71 +    def __init__(self, fd, mode="r", encoding=None, bufsize=1024):
    4.72 +
    4.73 +        """
    4.74 +        Initialise the stream with the given 'fd', 'mode', 'encoding' and
    4.75 +        'bufsize'.
    4.76 +        """
    4.77 +
    4.78 +        check_int(fd)
    4.79 +        check_string(mode)
    4.80 +
    4.81 +        get_using(filestream.__init__, self)(encoding, bufsize)
    4.82 +        self.__data__ = _fdopen(fd, mode)
    4.83 +
    4.84 +# Standard streams.
    4.85 +
    4.86 +stdin = sysstream(0)
    4.87 +stdout = sysstream(1, "w")
    4.88 +stderr = sysstream(2, "w")
    4.89 +
    4.90 +# Localised streams.
    4.91 +# Perform locale initialisation explicitly to ensure that the locale module
    4.92 +# and various function defaults have been initialised.
    4.93 +
    4.94 +locale.initlocale()
    4.95 +lstdin = sysstream(0, "r", locale.getpreferredencoding())
    4.96 +
    4.97 +# Input/output functions.
    4.98 +
    4.99 +def close(fd):
   4.100 +
   4.101 +    "Close the file descriptor 'fd'."
   4.102 +
   4.103 +    _close(fd)
   4.104 +
   4.105 +def fdopen(fd, mode="r"):
   4.106 +
   4.107 +    """
   4.108 +    Open a stream for the given file descriptor 'fd', operating in the given
   4.109 +    'mode'.
   4.110 +    """
   4.111 +
   4.112 +    return sysstream(fd, mode)
   4.113 +
   4.114 +def read(fd, n):
   4.115 +
   4.116 +    """
   4.117 +    Read using the low-level file descriptor 'fd' the given number of bytes 'n'.
   4.118 +    """
   4.119 +
   4.120 +    check_int(fd)
   4.121 +    check_int(n)
   4.122 +    return _read(fd, n)
   4.123 +
   4.124 +def write(fd, s):
   4.125 +
   4.126 +    "Write using the low-level file descriptor 'fd' the given string 's'."
   4.127 +
   4.128 +    check_int(fd)
   4.129 +    check_string(s)
   4.130 +    return _write(fd, s)
   4.131 +
   4.132 +# vim: tabstop=4 expandtab shiftwidth=4
     5.1 --- a/lib/posix/io.py	Thu Feb 02 22:38:26 2017 +0100
     5.2 +++ b/lib/posix/io.py	Thu Feb 02 22:41:07 2017 +0100
     5.3 @@ -19,85 +19,7 @@
     5.4  this program.  If not, see <http://www.gnu.org/licenses/>.
     5.5  """
     5.6  
     5.7 -from __builtins__.file import filestream
     5.8 -from __builtins__.types import check_int, check_string
     5.9 -
    5.10 -from native import (
    5.11 -    close as _close,
    5.12 -    fdopen as _fdopen,
    5.13 -    read as _read,
    5.14 -    write as _write
    5.15 -    )
    5.16 -
    5.17 -import locale
    5.18 -
    5.19 -# Abstractions for system-level files and streams.
    5.20 -
    5.21 -class sysfile:
    5.22 -
    5.23 -    "A system-level file object."
    5.24 -
    5.25 -    def __init__(self, fd):
    5.26 -
    5.27 -        "Initialise the file with the given 'fd'."
    5.28 -
    5.29 -        self.fd = fd
    5.30 -
    5.31 -    def read(self, n):
    5.32 -
    5.33 -        "Read 'n' bytes from the file, returning a string."
    5.34 -
    5.35 -        return read(self.fd, n)
    5.36 -
    5.37 -    def write(self, s):
    5.38 -
    5.39 -        "Write string 's' to the file."
    5.40 -
    5.41 -        return write(self.fd, s)
    5.42 -
    5.43 -    def close(self):
    5.44 -
    5.45 -        "Close the file."
    5.46 -
    5.47 -        close(self.fd)
    5.48 -
    5.49 -class sysstream(filestream):
    5.50 -
    5.51 -    "A system-level stream object."
    5.52 -
    5.53 -    def __init__(self, fd, mode="r", encoding=None, bufsize=1024):
    5.54 -
    5.55 -        """
    5.56 -        Initialise the stream with the given 'fd', 'mode', 'encoding' and
    5.57 -        'bufsize'.
    5.58 -        """
    5.59 -
    5.60 -        check_int(fd)
    5.61 -        check_string(mode)
    5.62 -
    5.63 -        get_using(filestream.__init__, self)(encoding, bufsize)
    5.64 -        self.__data__ = _fdopen(fd, mode)
    5.65 -
    5.66 -# Standard streams.
    5.67 -
    5.68 -stdin = sysstream(0)
    5.69 -stdout = sysstream(1, "w")
    5.70 -stderr = sysstream(2, "w")
    5.71 -
    5.72 -# Localised streams.
    5.73 -# Perform locale initialisation explicitly to ensure that the locale module
    5.74 -# and various function defaults have been initialised.
    5.75 -
    5.76 -locale.initlocale()
    5.77 -lstdin = sysstream(0, "r", locale.getpreferredencoding())
    5.78 -
    5.79 -# Input/output functions.
    5.80 -
    5.81 -def close(fd):
    5.82 -
    5.83 -    "Close the file descriptor 'fd'."
    5.84 -
    5.85 -    _close(fd)
    5.86 +from libc.io import close, fdopen, read, write
    5.87  
    5.88  def closerange(fd_low, fd_high): pass
    5.89  def dup(fd): pass
    5.90 @@ -106,16 +28,6 @@
    5.91  def fchmod(fd, mode): pass
    5.92  def fchown(fd, uid, gid): pass
    5.93  def fdatasync(fd): pass
    5.94 -
    5.95 -def fdopen(fd, mode="r"):
    5.96 -
    5.97 -    """
    5.98 -    Open a stream for the given file descriptor 'fd', operating in the given
    5.99 -    'mode'.
   5.100 -    """
   5.101 -
   5.102 -    return sysstream(fd, mode)
   5.103 -
   5.104  def fpathconf(fd, name): pass
   5.105  def fstat(fd): pass
   5.106  def fstatvfs(fd): pass
   5.107 @@ -132,31 +44,12 @@
   5.108  def openpty(): pass
   5.109  def pipe(): pass
   5.110  def putenv(key, value): pass
   5.111 -
   5.112 -def read(fd, n):
   5.113 -
   5.114 -    """
   5.115 -    Read using the low-level file descriptor 'fd' the given number of bytes 'n'.
   5.116 -    """
   5.117 -
   5.118 -    check_int(fd)
   5.119 -    check_int(n)
   5.120 -    return _read(fd, n)
   5.121 -
   5.122  def times(): pass
   5.123  def ttyname(fd): pass
   5.124  def umask(new_mask): pass
   5.125  def uname(): pass
   5.126  def unsetenv(key): pass
   5.127  
   5.128 -def write(fd, s):
   5.129 -
   5.130 -    "Write using the low-level file descriptor 'fd' the given string 's'."
   5.131 -
   5.132 -    check_int(fd)
   5.133 -    check_string(s)
   5.134 -    return _write(fd, s)
   5.135 -
   5.136  # Constants.
   5.137  
   5.138  O_APPEND = 1024
     6.1 --- a/lib/sys.py	Thu Feb 02 22:38:26 2017 +0100
     6.2 +++ b/lib/sys.py	Thu Feb 02 22:41:07 2017 +0100
     6.3 @@ -3,7 +3,7 @@
     6.4  """
     6.5  System functions and objects.
     6.6  
     6.7 -Copyright (C) 2008, 2012, 2014, 2016 Paul Boddie <paul@boddie.org.uk>
     6.8 +Copyright (C) 2008, 2012, 2014, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     6.9  
    6.10  This program is free software; you can redistribute it and/or modify it under
    6.11  the terms of the GNU General Public License as published by the Free Software
    6.12 @@ -20,7 +20,7 @@
    6.13  """
    6.14  
    6.15  from __builtins__.int import maxint, minint
    6.16 -from posix.io import lstdin, stdin, stdout, stderr
    6.17 +from libc.io import lstdin, stdin, stdout, stderr
    6.18  
    6.19  from native import (
    6.20      exit as _exit,