[m-rev.] diff 1/2: [net] Networking library improvments

Paul Bone paul at bone.id.au
Sat Jan 10 15:20:32 AEDT 2015


Branches: master

---

[net] Networking library improvments

extras/net/streams.m:
    Add a socket/1 function to get the socket of a stream.

    Add a reader instance for lines and a writer instance for strings.
    These don't do any character encoding or buffering.  They're pretty
    terrible but better than nothing.

extras/net/sockets.m:
    Use shutdown() rather than close() for sockets.
---
 extras/net/sockets.m |  2 +-
 extras/net/streams.m | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/extras/net/sockets.m b/extras/net/sockets.m
index c7a654c..7d0dfdb 100644
--- a/extras/net/sockets.m
+++ b/extras/net/sockets.m
@@ -399,7 +399,7 @@ close(Socket, Result, !IO) :-
     struct linger sockets_linger = { MR_TRUE, 2 };
     setsockopt(Socket, SOL_SOCKET, SO_LINGER,
         &sockets_linger, sizeof(sockets_linger));
-    if (-1 == close(Socket)) {
+    if (-1 == shutdown(Socket, SHUT_RDWR)) {
         Errno = error();
         Success = MR_NO;
     } else {
diff --git a/extras/net/streams.m b/extras/net/streams.m
index 164d31d..12172cb 100644
--- a/extras/net/streams.m
+++ b/extras/net/streams.m
@@ -19,6 +19,7 @@
 :- import_module int.
 :- import_module io.
 :- import_module stream.
+:- import_module string.
 
 :- import_module net.sockets.
 
@@ -28,6 +29,8 @@
 
 :- func stream(socket) = socket_stream.
 
+:- func socket(socket_stream) = socket.
+
 :- type byte
     --->    byte(int).
 
@@ -45,6 +48,8 @@
     %
 :- instance reader(socket_stream, streams.byte, io, streams.error).
 
+:- instance reader(socket_stream, line, io, streams.error).
+
 %-----------------------------------------------------------------------------%
 
 :- instance output(socket_stream, io).
@@ -53,12 +58,16 @@
     %
 :- 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.
 
@@ -70,6 +79,8 @@
 
 stream(Socket) = socket_stream(Socket).
 
+socket(socket_stream(Socket)) = Socket.
+
 %-----------------------------------------------------------------------------%
 
 :- instance error(streams.error) where [
@@ -117,6 +128,57 @@ get_byte(socket_stream(Socket), Result, !IO) :-
         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) ->
+            (
+                ( Char = '\n'
+                ; Char = '\r'
+                )
+            ->
+                Result = ok(Chars0)
+            ;
+                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 [
@@ -146,5 +208,21 @@ put_byte(socket_stream(Socket), byte(Byte), !IO) :-
         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).
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
-- 
2.1.3




More information about the reviews mailing list