mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-23 05:13:48 +00:00
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.
COPYING.LIB:
Add a special linking exception to the LGPL.
*:
Update references to COPYING.LIB.
Clean up some minor errors that have accumulated in copyright
messages.
229 lines
6.2 KiB
Mathematica
229 lines
6.2 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2014-2016, 2018 The Mercury Team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Module: net.streams.
|
|
% Main Author: Paul Bone
|
|
% Stability: low
|
|
%
|
|
% Provide a streams interface for sockets.
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module net.streams.
|
|
:- interface.
|
|
|
|
:- import_module int.
|
|
:- import_module io.
|
|
:- import_module stream.
|
|
:- import_module string.
|
|
|
|
:- import_module net.sockets.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type socket_stream.
|
|
|
|
:- func stream(socket) = socket_stream.
|
|
|
|
:- func socket(socket_stream) = socket.
|
|
|
|
:- type byte
|
|
---> byte(int).
|
|
|
|
:- type error.
|
|
|
|
:- instance error(streams.error).
|
|
|
|
:- instance stream(socket_stream, io).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- instance input(socket_stream, io).
|
|
|
|
% XXX: This does not buffer reads, it is slow.
|
|
%
|
|
:- instance reader(socket_stream, streams.byte, io, streams.error).
|
|
|
|
:- instance reader(socket_stream, line, io, streams.error).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- instance output(socket_stream, io).
|
|
|
|
% XXX: This does not buffer writes, it is slow.
|
|
%
|
|
:- instance writer(socket_stream, streams.byte, io).
|
|
|
|
:- instance writer(socket_stream, string, io).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
:- implementation.
|
|
|
|
:- import_module char.
|
|
:- import_module exception.
|
|
:- import_module bitmap.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
:- import_module require.
|
|
|
|
:- type socket_stream
|
|
---> socket_stream(socket).
|
|
|
|
:- type error
|
|
---> error(string).
|
|
|
|
stream(Socket) = socket_stream(Socket).
|
|
|
|
socket(socket_stream(Socket)) = Socket.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- instance error(streams.error) where [
|
|
error_message(error(Str)) = Str
|
|
].
|
|
|
|
:- instance stream(socket_stream, io) where [
|
|
pred(name/4) is stream_name
|
|
].
|
|
|
|
:- pred stream_name(socket_stream::in, name::out, io::di, io::uo) is det.
|
|
|
|
stream_name(socket_stream(_Socket), Name, !IO) :-
|
|
Name = "a socket".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- instance input(socket_stream, io) where [].
|
|
|
|
:- instance reader(socket_stream, streams.byte, io, streams.error) where [
|
|
pred(get/4) is get_byte
|
|
].
|
|
|
|
:- pred get_byte(socket_stream::in, result(streams.byte, streams.error)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
get_byte(socket_stream(Socket), Result, !IO) :-
|
|
read(Socket, 1, ReadResult, !IO),
|
|
(
|
|
ReadResult = ok(Bitmap),
|
|
( if num_bytes(Bitmap) = 1 then
|
|
Byte = Bitmap ^ byte(0),
|
|
Result = ok(byte(Byte))
|
|
else if num_bytes(Bitmap) = 0 then
|
|
Result = eof
|
|
else
|
|
unexpected($file, $pred,
|
|
"Read returned unexpected number of bytes")
|
|
)
|
|
;
|
|
ReadResult = eof,
|
|
Result = eof
|
|
;
|
|
ReadResult = error(String),
|
|
Result = error(error(String))
|
|
).
|
|
|
|
:- instance reader(socket_stream, line, io, streams.error) where [
|
|
pred(get/4) is get_line
|
|
].
|
|
|
|
:- pred get_line(socket_stream::in, result(line, streams.error)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
get_line(Stream, Result, !IO) :-
|
|
get_chars_until_nl(Stream, [], Result0, !IO),
|
|
(
|
|
Result0 = ok(RevChars),
|
|
Result = ok(line(from_rev_char_list(RevChars)))
|
|
;
|
|
Result0 = eof,
|
|
Result = eof
|
|
;
|
|
Result0 = error(Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
:- pred get_chars_until_nl(Stream::in, list(char)::in,
|
|
result(list(char), Error)::out, State::di, State::uo) is det
|
|
<= reader(Stream, streams.byte, State, Error).
|
|
|
|
get_chars_until_nl(Stream, Chars0, Result, !IO) :-
|
|
get(Stream, ResByte, !IO),
|
|
(
|
|
ResByte = ok(byte(Byte)),
|
|
( char.from_int(Byte, Char) ->
|
|
( if
|
|
( Char = '\n'
|
|
; Char = '\r'
|
|
)
|
|
then
|
|
Result = ok(Chars0)
|
|
else
|
|
Chars1 = [Char | Chars0],
|
|
get_chars_until_nl(Stream, Chars1, Result, !IO)
|
|
)
|
|
;
|
|
unexpected($file, $pred, "Encoding error")
|
|
)
|
|
;
|
|
ResByte = eof,
|
|
Result = eof
|
|
;
|
|
ResByte = error(Error),
|
|
Result = error(Error)
|
|
).
|
|
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- instance output(socket_stream, io) where [
|
|
pred(flush/3) is flush_noop
|
|
].
|
|
|
|
:- pred flush_noop(socket_stream::in, io::di, io::uo) is det.
|
|
|
|
flush_noop(_, !IO).
|
|
|
|
% XXX: This does not buffer writes, it is slow.
|
|
%
|
|
:- instance writer(socket_stream, streams.byte, io) where [
|
|
pred(put/4) is put_byte
|
|
].
|
|
|
|
:- pred put_byte(socket_stream::in, streams.byte::in, io::di, io::uo)
|
|
is det.
|
|
|
|
put_byte(socket_stream(Socket), byte(Byte), !IO) :-
|
|
Bitmap = init(bits_per_byte) ^ byte(0) := Byte,
|
|
write(Socket, Bitmap, Result, !IO),
|
|
(
|
|
Result = ok
|
|
;
|
|
Result = error(Error),
|
|
throw(streams.error(Error))
|
|
).
|
|
|
|
:- instance writer(socket_stream, string, io) where [
|
|
pred(put/4) is put_string
|
|
].
|
|
|
|
:- pred put_string(Stream::in, string::in, State::di, State::uo) is det
|
|
<= writer(Stream, streams.byte, State).
|
|
|
|
put_string(Stream, String, !State) :-
|
|
foldl(put_char(Stream), String, !State).
|
|
|
|
:- pred put_char(Stream::in, char::in, State::di, State::uo) is det
|
|
<= writer(Stream, streams.byte, State).
|
|
|
|
put_char(Stream, Char, !State) :-
|
|
put(Stream, byte(to_int(Char)), !State).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|