From 22fd216de597f1f8e9783d5af520574a2fef4452 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 13 Jun 2020 09:06:57 +0200 Subject: [PATCH 1/3] ADDED: read_line_to_chars/3, reading up to and including "\n" from a stream, yielding a list difference. This works for both binary and text streams. --- src/lib/charsio.pl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index e57a40aa..4e82f23b 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -1,6 +1,7 @@ :- module(charsio, [char_type/2, chars_utf8bytes/2, get_single_char/1, + read_line_to_chars/3, read_term_from_chars/2, write_term_to_chars/3]). @@ -182,3 +183,14 @@ continuation(Code, Chars, Nb) --> [Byte], % invalid continuation byte % each remaining continuation byte (if any) will raise 0xFFFD too continuation(_, ['\xFFFD\'|T], _) --> [_], decode_utf8(T). + + +read_line_to_chars(Stream, Cs0, Cs) :- + '$get_n_chars'(Stream, 1, Char), % this also works for binary streams + ( Char == [] -> Cs0 = Cs + ; Char = [C], + Cs0 = [C|Rest], + ( C == '\n' -> Rest = Cs + ; read_line_to_chars(Stream, Rest, Cs) + ) + ). From 409d3c168dc43f2489502d0599fe7c9e5c4839bb Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sun, 14 Jun 2020 10:06:27 +0200 Subject: [PATCH 2/3] ENHANCED: faster format/3 when writing to binary streams This is also more secure, since it does not change the atom table and therefore leaves little trace of what was processed. --- src/lib/format.pl | 13 +------------ src/machine/system_calls.rs | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/lib/format.pl b/src/lib/format.pl index 2e496730..a3a0f5a4 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -375,20 +375,9 @@ format(Fs, Args) :- format(Stream, Fs, Args) :- phrase(format_(Fs, Args), Cs), ( stream_property(Stream, type(binary)) -> - % maplist(char_code, Cs, Bytes) is currently a lot slower - % than first converting Cs to an atom, and then to codes. - % In the future, we can ideally avoid creating an atom here, - % since an atom leaves traces in the system. - atom_chars(A, Cs), - atom_codes(A, Bytes), - ( member(NonByte, Bytes), NonByte > 255 -> - char_code(Char, NonByte), - throw(error(representation_error(Char), format/3)) - ; true - ), % For binary streams, we use a specialised internal predicate % that uses only a single "write" operation for efficiency. - '$put_bytes'(Stream, Bytes) + '$put_bytes'(Stream, Cs) ; maplist(put_char(Stream), Cs) ). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index e18da09b..025da98b 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2022,8 +2022,24 @@ impl MachineState { let mut stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_bytes", 2)?; - let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2); - let bytes = self.integers_to_bytevec(temp_v!(2), stub); + let mut iter = self.heap_pstr_iter(self[temp_v!(2)]); + let mut bytes = Vec::new(); + for c in iter.to_string().chars() { + if c as u32 > 255 { + + let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2); + + let err = MachineError::type_error( + self.heap.h(), + ValidType::Byte, + Addr::Char(c), + ); + + return Err(self.error_form(err, stub)); + } + + bytes.push(c as u8); + } match stream.write(&bytes) { Ok(_) => { From 10a0f708b974554f596a978d1d193e904b1e094a Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sun, 14 Jun 2020 10:50:21 +0200 Subject: [PATCH 3/3] use format/3 to benefit from efficiency improvements --- src/lib/format.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/format.pl b/src/lib/format.pl index a3a0f5a4..811a4c33 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -460,7 +460,7 @@ portray_clause(Term) :- portray_clause(Stream, Term) :- phrase(portray_clause_(Term), Ls), - maplist(put_char(Stream), Ls). + format(Stream, "~s", [Ls]). portray_clause_(Term) --> { term_variables(Term, Vs),