summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Montague <mikemon@gmail.com>2022-09-06 21:42:16 -0700
committerMike Montague <mikemon@gmail.com>2022-09-06 21:42:16 -0700
commit96eb779221be4ddf4bf1d3af48208f7c8ae934fa (patch)
tree277bb7057b2632ff4b8ee45f4843ca6383e36dee
parent86afa0639b713b6a9a97b2aeea3b3049fbdb98b0 (diff)
srfi 207
-rw-r--r--README.md1
-rw-r--r--src/base.scm9
-rw-r--r--src/foment.hpp2
-rw-r--r--src/read.cpp12
-rw-r--r--src/srfi-207.scm90
-rw-r--r--src/vectors.cpp164
-rw-r--r--test/srfi.scm348
-rw-r--r--unix/makefile6
-rw-r--r--windows/makefile6
9 files changed, 452 insertions, 186 deletions
diff --git a/README.md b/README.md
index 366c943..d108e96 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@
* SRFI 181: Custom ports (including transcoded ports)
* SRFI 192: Port Positioning
* SRFI 193: Command line
+* SRFI 207: String-notated bytevectors
* SRFI 229: Tagged Procedures
See [Foment](https://github.com/leftmike/foment/wiki/Foment) for more details.
diff --git a/src/base.scm b/src/base.scm
index ef9c6fa..e4bc040 100644
--- a/src/base.scm
+++ b/src/base.scm
@@ -702,7 +702,14 @@
hex-string->bytevector
bytevector->base64
base64->bytevector
- bytestring->list)
+ bytestring->list
+ bytevector=?
+ bytevector<?
+ bytevector>?
+ bytevector<=?
+ bytevector>=?
+ read-textual-bytestring
+ write-textual-bytestring)
(cond-expand
(unix
(export
diff --git a/src/foment.hpp b/src/foment.hpp
index 994341c..745d5e4 100644
--- a/src/foment.hpp
+++ b/src/foment.hpp
@@ -10,7 +10,6 @@ To Do:
-- SRFI 154: First-class dynamic extents
-- SRFI 158: Generators and Accumulators
-- SRFI 195: Multiple-value boxes
--- SRFI 207: String-notated bytevectors
-- IO: FAlive, EnterWait, and LeaveWait
-- Allow GC on nested executions
@@ -629,6 +628,7 @@ void FoldcasePort(FObject port, long_t fcf);
void WantIdentifiersPort(FObject port, long_t wif);
FObject Read(FObject port);
+FObject ReadBytestring(FObject port);
void WriteCh(FObject port, FCh ch);
void WriteString(FObject port, FCh * s, ulong_t sl);
diff --git a/src/read.cpp b/src/read.cpp
index f7232d3..9f18604 100644
--- a/src/read.cpp
+++ b/src/read.cpp
@@ -237,12 +237,16 @@ Again:
UnexpectedEof:
if (s != sb)
free(s);
- RaiseExceptionC(Lexical, "read", bsf ? "unexpected end-of-file reading bytestring" :
- "unexpected end-of-file reading string", List(port));
+ if (bsf)
+ RaiseExceptionC(Lexical, "read", BytestringErrorSymbol,
+ "unexpected end-of-file reading bytestring", List(port));
+ else
+ RaiseExceptionC(Lexical, "read", "unexpected end-of-file reading string",
+ List(port));
return(NoValueObject);
}
-static FObject ReadBytestring(FObject port)
+FObject ReadBytestring(FObject port)
{
FObject s = ReadStringLiteral(port, '"', 1);
long_t sl = StringLength(s);
@@ -250,7 +254,7 @@ static FObject ReadBytestring(FObject port)
for (long_t idx = 0; idx < sl; idx += 1)
{
FCh ch = AsString(s)->String[idx];
- if (ch >= 128 )
+ if (ch >= 256)
RaiseExceptionC(Lexical, "read", BytestringErrorSymbol,
"unexpected character in bytestring", List(MakeCharacter(ch)));
AsBytevector(bv)->Vector[idx] = (FByte) ch;
diff --git a/src/srfi-207.scm b/src/srfi-207.scm
index 9f3dfa6..9f7f45b 100644
--- a/src/srfi-207.scm
+++ b/src/srfi-207.scm
@@ -15,10 +15,26 @@
bytestring-trim
bytestring-trim-right
bytestring-trim-both
-
+ bytestring-replace
+ bytevector=?
+ bytevector<?
+ bytevector>?
+ bytevector<=?
+ bytevector>=?
+ (rename bytevector=? bytestring=?)
+ (rename bytevector<? bytestring<?)
+ (rename bytevector>? bytestring>?)
+ (rename bytevector<=? bytestring<=?)
+ (rename bytevector>=? bytestring>=?)
bytestring-index
bytestring-index-right
-
+ bytestring-break
+ bytestring-span
+ bytestring-join
+ bytestring-split
+ read-textual-bytestring
+ write-textual-bytestring
+ write-binary-bytestring
bytestring-error?)
(begin
(define (bytestring . args)
@@ -62,7 +78,19 @@
(bytevector-copy bv start
(+ (bytestring-index-right bv (lambda (n) (not (pred n)))) 1))
#u8())))
-
+ (define bytestring-replace
+ (case-lambda
+ ((bv1 bv2 start1 end1)
+ (%bytestring-replace bv1 bv2 start1 end1 0 (bytevector-length bv2)))
+ ((bv1 bv2 start1 end1 start2 end2)
+ (%bytestring-replace bv1 bv2 start1 end1 start2 end2))))
+ (define (%bytestring-replace bv1 bv2 start1 end1 start2 end2)
+ (let* ((len (+ (- (bytevector-length bv1) (- end1 start1)) (- end2 start2)))
+ (bv (make-bytevector len)))
+ (bytevector-copy! bv 0 bv1 0 start1)
+ (bytevector-copy! bv start1 bv2 start2 end2)
+ (bytevector-copy! bv (+ start1 (- end2 start2)) bv1 end1 (bytevector-length bv1))
+ bv))
(define (%bytestring-index bv pred start end)
(if (>= start end)
#f
@@ -86,7 +114,61 @@
((bv pred) (%bytestring-index-right bv pred 0 (bytevector-length bv)))
((bv pred start) (%bytestring-index-right bv pred start (bytevector-length bv)))
((bv pred start end) (%bytestring-index-right bv pred start end))))
-
+ (define (bytestring-break bv pred)
+ (let ((idx (bytestring-index bv pred)))
+ (if (not idx)
+ (values (bytevector-copy bv) (bytevector))
+ (values (bytevector-copy bv 0 idx) (bytevector-copy bv idx)))))
+ (define (bytestring-span bv pred)
+ (bytestring-break bv (lambda (b) (not (pred b)))))
+ (define bytestring-join
+ (case-lambda
+ ((lst delim) (%bytestring-join lst (bytestring delim) 'infix))
+ ((lst delim grammar) (%bytestring-join lst (bytestring delim) grammar))))
+ (define (%bytestring-join lst delim grammar)
+ (if (null? lst)
+ (if (eq? grammar 'strict-infix)
+ (full-error 'assertion-violation 'bytestring-join 'bytestring-error
+ "bytestring-join: list must not be empty with strict-inflix")
+ (bytevector))
+ (let ((port (open-output-bytevector)))
+ (if (eq? grammar 'prefix)
+ (write-bytevector delim port))
+ (write-bytevector (car lst) port)
+ (for-each
+ (lambda (bv)
+ (write-bytevector delim port)
+ (write-bytevector bv port))
+ (cdr lst))
+ (if (eq? grammar 'suffix)
+ (write-bytevector delim port))
+ (get-output-bytevector port))))
+ (define bytestring-split
+ (case-lambda
+ ((bv delim)
+ (%bytestring-split bv (if (char? delim) (char->integer delim) delim) 'infix))
+ ((bv delim grammar)
+ (%bytestring-split bv (if (char? delim) (char->integer delim) delim)
+ grammar))))
+ (define (%bytestring-split bv delim grammar)
+ (let* ((len (bytevector-length bv))
+ (len (if (and (eq? grammar 'suffix)
+ (= (bytevector-u8-ref bv (- len 1)) delim))
+ (- len 1)
+ len)))
+ (define (split sdx idx)
+ (if (= idx len)
+ (list (bytevector-copy bv sdx idx))
+ (if (= (bytevector-u8-ref bv idx) delim)
+ (cons (bytevector-copy bv sdx idx) (split (+ idx 1) (+ idx 1)))
+ (split sdx (+ idx 1)))))
+ (if (= len 0)
+ '()
+ (if (and (eq? grammar 'prefix) (= (bytevector-u8-ref bv 0) delim))
+ (split 1 1)
+ (split 0 0)))))
+ (define (write-binary-bytestring port . args)
+ (write-bytevector (apply bytestring args) port))
(define (bytestring-error? obj)
(and (error-object? obj) (eq? (error-object-kind obj) 'bytestring-error)))
)
diff --git a/src/vectors.cpp b/src/vectors.cpp
index eb4764c..a2afa71 100644
--- a/src/vectors.cpp
+++ b/src/vectors.cpp
@@ -4,9 +4,17 @@ Foment
*/
+#ifdef FOMENT_WINDOWS
+#include <windows.h>
+#endif // FOMENT_WINDOWS
+#ifdef FOMENT_UNIX
+#include <pthread.h>
+#endif // FOMENT_UNIX
#include <stdio.h>
#include <string.h>
#include "foment.hpp"
+#include "syncthrd.hpp"
+#include "io.hpp"
#include "unicode.hpp"
// ---- Vectors ----
@@ -1224,6 +1232,153 @@ Define("bytestring->list", BytestringToListPrimitive)(long_t argc, FObject argv[
return(ReverseListModify(lst));
}
+static int BytevectorCompare(FObject bv1, FObject bv2)
+{
+ FAssert(BytevectorP(bv1));
+ FAssert(BytevectorP(bv2));
+
+ ulong_t bvl1 = BytevectorLength(bv1);
+ ulong_t bvl2 = BytevectorLength(bv2);
+
+ if (bvl1 < bvl2)
+ {
+ int ret = memcmp(AsBytevector(bv1)->Vector, AsBytevector(bv2)->Vector, bvl1);
+ return(ret > 0 ? 1 : -1);
+ }
+ else if (bvl1 > bvl2)
+ {
+ int ret = memcmp(AsBytevector(bv1)->Vector, AsBytevector(bv2)->Vector, bvl2);
+ return(ret < 0 ? -1 : 1);
+ }
+ return(memcmp(AsBytevector(bv1)->Vector, AsBytevector(bv2)->Vector, bvl1));
+}
+
+Define("bytevector=?", BytevectorEqualPPrimitive)(long_t argc, FObject argv[])
+{
+ TwoArgsCheck("bytevector=?", argc);
+ BytevectorArgCheck("bytevector=?", argv[0]);
+ BytevectorArgCheck("bytevector=?", argv[1]);
+
+ return(BytevectorCompare(argv[0], argv[1]) == 0 ? TrueObject : FalseObject);
+}
+
+Define("bytevector<?", BytevectorLessThanPPrimitive)(long_t argc, FObject argv[])
+{
+ TwoArgsCheck("bytevector<?", argc);
+ BytevectorArgCheck("bytevector<?", argv[0]);
+ BytevectorArgCheck("bytevector<?", argv[1]);
+
+ return(BytevectorCompare(argv[0], argv[1]) < 0 ? TrueObject : FalseObject);
+}
+
+Define("bytevector>?", BytevectorGreaterThanPPrimitive)(long_t argc, FObject argv[])
+{
+ TwoArgsCheck("bytevector>?", argc);
+ BytevectorArgCheck("bytevector>?", argv[0]);
+ BytevectorArgCheck("bytevector>?", argv[1]);
+
+ return(BytevectorCompare(argv[0], argv[1]) > 0 ? TrueObject : FalseObject);
+}
+
+Define("bytevector<=?", BytevectorLessThanEqualPPrimitive)(long_t argc, FObject argv[])
+{
+ TwoArgsCheck("bytevector<=?", argc);
+ BytevectorArgCheck("bytevector<=?", argv[0]);
+ BytevectorArgCheck("bytevector<=?", argv[1]);
+
+ return(BytevectorCompare(argv[0], argv[1]) <= 0 ? TrueObject : FalseObject);
+}
+
+Define("bytevector>=?", BytevectorGreaterThanEqualPPrimitive)(long_t argc, FObject argv[])
+{
+ TwoArgsCheck("bytevector>=?", argc);
+ BytevectorArgCheck("bytevector>=?", argv[0]);
+ BytevectorArgCheck("bytevector>=?", argv[1]);
+
+ return(BytevectorCompare(argv[0], argv[1]) >= 0 ? TrueObject : FalseObject);
+}
+
+static FCh ReadBytestringCh(FObject port)
+{
+ FCh ch;
+ if (ReadCh(port, &ch) == 0)
+ RaiseExceptionC(Lexical, "read-textual-bytestring", BytestringErrorSymbol,
+ "unexpected end-of-file reading bytestring", List(port));
+
+ return(ch);
+}
+
+Define("read-textual-bytestring", ReadTextualBytestringPrimitive)(long_t argc, FObject argv[])
+{
+ OneOrTwoArgsCheck("read-textual-bytestring", argc);
+ FObject port = (argc == 2 ? argv[1] : CurrentInputPort());
+ TextualInputPortArgCheck("read-textual-bytestring", port);
+
+ if (argv[0] == FalseObject)
+ {
+ if (ReadBytestringCh(port) != '"')
+ RaiseExceptionC(Lexical, "read-textual-bytestring", BytestringErrorSymbol,
+ "expected \" starting bytestring", List(port));
+ }
+ else
+ {
+ if (ReadBytestringCh(port) != '#')
+ goto MissingPrefix;
+ if (ReadBytestringCh(port) != 'u')
+ goto MissingPrefix;
+ if (ReadBytestringCh(port) != '8')
+ goto MissingPrefix;
+ if (ReadBytestringCh(port) != '"')
+ goto MissingPrefix;
+ }
+
+ return(ReadBytestring(port));
+
+MissingPrefix:
+ RaiseExceptionC(Lexical, "read-textual-bytestring", BytestringErrorSymbol,
+ "expected #u8\" starting bytestring", List(port));
+ return(NoValueObject);
+}
+
+Define("write-textual-bytestring", WriteTextualBytestringPrimitive)(long_t argc, FObject argv[])
+{
+ OneOrTwoArgsCheck("write-textual-bytestring", argc);
+ BytevectorArgCheck("write-textual-bytestring", argv[0]);
+ FObject port = (argc == 2 ? argv[1] : CurrentOutputPort());
+ TextualOutputPortArgCheck("write-textual-bytestring", port);
+
+ WriteStringC(port, "#u8\"");
+ for (ulong_t idx = 0; idx < BytevectorLength(argv[0]); idx += 1)
+ {
+ FByte b = AsBytevector(argv[0])->Vector[idx];
+ switch (b)
+ {
+ case 0x07: WriteStringC(port, "\\a"); break;
+ case 0x08: WriteStringC(port, "\\b"); break;
+ case 0x09: WriteStringC(port, "\\t"); break;
+ case 0x0A: WriteStringC(port, "\\n"); break;
+ case 0x0D: WriteStringC(port, "\\r"); break;
+ case 0x22: WriteStringC(port, "\\\""); break;
+ case 0x5C: WriteStringC(port, "\\\\"); break;
+ case 0x7C: WriteStringC(port, "\\|"); break;
+ default:
+ if (b >= 0x20 && b <= 0x7E)
+ WriteCh(port, b);
+ else
+ {
+ FCh s[4];
+ long_t sl = FixnumAsString((long_t) b, s, 16);
+
+ WriteStringC(port, "\\x");
+ WriteString(port, s, sl);
+ WriteCh(port, ';');
+ }
+ }
+ }
+ WriteCh(port, '"');
+ return(NoValueObject);
+}
+
static FObject Primitives[] =
{
VectorPPrimitive,
@@ -1261,7 +1416,14 @@ static FObject Primitives[] =
HexStringToBytevectorPrimitive,
BytevectorToBase64Primitive,
Base64ToBytevectorPrimitive,
- BytestringToListPrimitive
+ BytestringToListPrimitive,
+ BytevectorEqualPPrimitive,
+ BytevectorLessThanPPrimitive,
+ BytevectorGreaterThanPPrimitive,
+ BytevectorLessThanEqualPPrimitive,
+ BytevectorGreaterThanEqualPPrimitive,
+ ReadTextualBytestringPrimitive,
+ WriteTextualBytestringPrimitive
};
void SetupVectors()
diff --git a/test/srfi.scm b/test/srfi.scm
index c0dee35..7f232b4 100644
--- a/test/srfi.scm
+++ b/test/srfi.scm
@@ -3877,7 +3877,6 @@
(check-equal #t (check-read-bytestring "#u8\"\\x100;\""))
(check-equal #t (check-read-bytestring "#u8\"\\x0ABC\""))
(check-equal #t (check-read-bytestring "#u8\"\\xE000;\""))
-(check-equal #t (check-read-bytestring "#u8\"\\x80;\""))
(check-equal #u8(108 111 114 101 109) (bytestring "lo" #\r #x65 #u8(#x6d)))
(check-equal #t (equal? (bytestring) (bytevector)))
@@ -3894,6 +3893,9 @@
(check-equal #t (check-make-bytestring "abc" #\x80 "efg"))
(check-equal #f (check-make-bytestring "abc" #\x10 "efg"))
+(check-equal #u8"lorem" (bytestring "lo" #\r #x65 #u8(#x6d)))
+(check-equal #u8() (bytestring))
+
(check-equal #t (check-make-bytestring "\x3BB;"))
(check-equal #t (check-make-bytestring #x100))
@@ -4039,6 +4041,49 @@
(check-equal #u8"lorem" (bytestring-trim-both #u8"lorem" never))
(check-equal #u8(#x72) (bytestring-trim-both #u8"lorem" (lambda (u8) (< u8 #x70))))
+(check-equal #u8"Vogon poetry" (bytestring-replace #u8"Vogon torture" #u8"poetry" 6 13))
+
+(check-equal #u8"lists" (bytestring-replace #u8"lorem" (bytestring "mists") 1 5 1 5))
+(check-equal #u8"loaded" (bytestring-replace #u8"lorem" (bytestring "faded") 2 5 1 5))
+(check-equal #u8"lorem"
+ (bytestring-replace (make-bytevector 5) #u8"lorem" 0 (bytevector-length #u8"lorem")))
+(check-equal #u8"food food"
+ (let ((bv1 (bytestring "food")) (bv2 (bytestring "od fo")))
+ (bytestring-replace bv1 bv2 2 2 0 5)))
+(check-equal #u8"food"
+ (let ((bv1 (bytestring "food food")))
+ (bytestring-replace bv1 (bytevector) 2 7 0 0)))
+
+(check-equal #t (bytestring=? #u8"lorem" #u8"lorem"))
+(check-equal #f (bytestring=? #u8"lore" #u8"lorem"))
+(check-equal #f (bytestring=? #u8"lorem" #u8"lore"))
+(check-equal #f (bytestring=? #u8"abcdef" #u8"ghijklmno"))
+
+(check-equal #t (bytestring<? #u8"Heart Of Gold" #u8"Heart of Gold"))
+(check-equal #f (bytestring<=? #u8(#x81 #x95) #u8(#x80 #xa0)))
+(check-equal #t (bytestring>? #u8(1 2 3) #u8(1 2)))
+
+(define short-bstring (bytestring "lore"))
+(define long-bstring (bytestring "lorem "))
+(define mixed-case-bstring (bytestring "loreM"))
+
+(check-equal #f (bytestring<? #u8"lorem" #u8"lorem"))
+(check-equal #t (bytestring<? short-bstring #u8"lorem"))
+(check-equal #t (bytestring<? mixed-case-bstring #u8"lorem"))
+(check-equal #f (bytestring>? #u8"lorem" #u8"lorem"))
+(check-equal #t (bytestring>? #u8"lorem" short-bstring))
+(check-equal #t (bytestring>? #u8"lorem" mixed-case-bstring))
+(check-equal #t (bytestring<=? #u8"lorem" #u8"lorem"))
+(check-equal #t (bytestring<=? short-bstring #u8"lorem"))
+(check-equal #t (bytestring<=? mixed-case-bstring #u8"lorem"))
+(check-equal #f (bytestring<=? #u8"lorem" mixed-case-bstring))
+(check-equal #f (bytestring<=? long-bstring #u8"lorem"))
+(check-equal #t (bytestring>=? #u8"lorem" #u8"lorem"))
+(check-equal #t (bytestring>=? #u8"lorem" short-bstring))
+(check-equal #t (bytestring>=? #u8"lorem" mixed-case-bstring))
+(check-equal #f (bytestring>=? mixed-case-bstring #u8"lorem"))
+(check-equal #f (bytestring>=? short-bstring #u8"lorem"))
+
(check-equal 2 (bytestring-index #u8(#x65 #x72 #x83 #x6f) (lambda (b) (> b #x7f))))
(check-equal #f (bytestring-index #u8"Beeblebrox" (lambda (b) (> b #x7f))))
(check-equal 4 (bytestring-index-right #u8"Zaphod" odd?))
@@ -4053,173 +4098,134 @@
(check-equal 4 (bytestring-index-right #u8"lorem" always 3))
(check-equal 2 (bytestring-index-right #u8"lorem" eq-r?))
-#|
-(define test-bstring (bytestring "lorem"))
-
-(define (check-replacement)
- (print-header "Running bytestring-replace tests...")
-
- (check (bytestring-replace #u8"lorem" (bytestring "mists") 1 5 1 5)
- => (bytestring "lists"))
- (check (bytestring-replace #u8"lorem" (bytestring "faded") 2 5 1 5)
- => (bytestring "loaded"))
- (check (bytestring-replace (make-bytevector 5)
- #u8"lorem"
- 0
- (bytevector-length #u8"lorem"))
- => #u8"lorem")
-
- (let ((bv1 (bytestring "food")) (bv2 (bytestring "od fo")))
- (check (bytestring-replace bv1 bv2 2 2 0 5) => (bytestring "food food")))
- (let ((bv1 (bytestring "food food")))
- (check (bytestring-replace bv1 (bytevector) 2 7 0 0)
- => (bytestring "food")))
-)
-
-(define (check-comparison)
- (define short-bstring (bytestring "lore"))
- (define long-bstring (bytestring "lorem "))
- (define mixed-case-bstring (bytestring "loreM"))
- (print-header "Runnng comparison tests...")
-
- (check (bytestring<? #u8"lorem" #u8"lorem") => #f)
- (check (bytestring<? short-bstring #u8"lorem") => #t)
- (check (bytestring<? mixed-case-bstring #u8"lorem") => #t)
- (check (bytestring>? #u8"lorem" #u8"lorem") => #f)
- (check (bytestring>? #u8"lorem" short-bstring) => #t)
- (check (bytestring>? #u8"lorem" mixed-case-bstring) => #t)
- (check (bytestring<=? #u8"lorem" #u8"lorem") => #t)
- (check (bytestring<=? short-bstring #u8"lorem") => #t)
- (check (bytestring<=? mixed-case-bstring #u8"lorem") => #t)
- (check (bytestring<=? #u8"lorem" mixed-case-bstring) => #f)
- (check (bytestring<=? long-bstring #u8"lorem") => #f)
- (check (bytestring>=? #u8"lorem" #u8"lorem") => #t)
- (check (bytestring>=? #u8"lorem" short-bstring) => #t)
- (check (bytestring>=? #u8"lorem" mixed-case-bstring) => #t)
- (check (bytestring>=? mixed-case-bstring #u8"lorem") => #f)
- (check (bytestring>=? short-bstring #u8"lorem") => #f)
-)
-
-(define (check-searching)
- (define (eq-r? b) (= b #x72))
- (define (lt-r? b) (< b #x72))
- (print-header "Running search tests...")
-
- (check (values~>list (bytestring-span #u8"lorem" always))
- => (list #u8"lorem" (bytevector)))
- (check (values~>list (bytestring-span #u8"lorem" never))
- => (list (bytevector) #u8"lorem"))
- (check (values~>list (bytestring-span #u8"lorem" lt-r?))
- => (list (bytestring "lo") (bytestring "rem")))
-
- (check (values~>list (bytestring-break #u8"lorem" always))
- => (list (bytevector) #u8"lorem"))
- (check (values~>list (bytestring-break #u8"lorem" never))
- => (list #u8"lorem" (bytevector)))
- (check (values~>list (bytestring-break #u8"lorem" eq-r?))
- => (list (bytestring "lo") (bytestring "rem"))))
-
-(define (check-join-and-split)
- (define test-segments '(#u8(1) #u8(2) #u8(3)))
- (print-header "Running joining and splitting tests...")
-
- (check (bytestring-join test-segments #u8(0)) => #u8(1 0 2 0 3))
- (check (bytestring-join test-segments #u8(0) 'prefix) => #u8(0 1 0 2 0 3))
- (check (bytestring-join test-segments #u8(0) 'suffix) => #u8(1 0 2 0 3 0))
- (check (bytestring-join '() #u8(0)) => #u8())
- (check (bytestring-join test-segments #\space) => #u8(1 32 2 32 3))
- (check (bytestring-join test-segments 0) => #u8(1 0 2 0 3))
- (check (bytestring-join test-segments "AB")
- => #u8(1 65 66 2 65 66 3))
- (check (bytestring-join test-segments #u8(7 8)) => #u8(1 7 8 2 7 8 3))
- (check (catch-bytestring-error
- (bytestring-join test-segments 300)) => 'bytestring-error)
- (check (catch-bytestring-error
- (bytestring-join test-segments "λ")) => 'bytestring-error)
- (check (catch-bytestring-error
- (bytestring-join '() #u8(0) 'strict-infix)) => 'bytestring-error)
- (check (catch-bytestring-error
- (bytestring-join '() #u8(0) 'foofix)) => 'bytestring-error)
-
- (check (bytestring-split #u8(1 0 2 0 3) 0 'infix) => test-segments)
- (check (bytestring-split #u8(0 1 0 2 0 3) 0 'prefix) => test-segments)
- (check (bytestring-split #u8(1 0 2 0 3 0) 0 'suffix) => test-segments)
- (check (bytestring-split #u8(0 0) 0) => '(#u8() #u8() #u8()))
- (check (bytestring-split #u8() 0) => '())
- (check (catch-bytestring-error
- (bytestring-split #u8() 0 'foofix)) => 'bytestring-error))
-
-(define (check-io)
- (print-header "Running I/O tests...")
-
- (check (%bytestring/IO "lo" #\r #x65 #u8(#x6d)) => #u8"lorem")
- (check (%bytestring/IO) => #u8())
- (check (catch-bytestring-error (%bytestring/IO #x100)) => 'bytestring-error)
- (check (catch-bytestring-error (%bytestring/IO "λ")) => 'bytestring-error)
-
- ;;; read-textual-bytestring
-
- (check (parse-SNB/prefix "#u8\"\"") => #u8())
- (check (parse-SNB/prefix "#u8\"lorem\"") => #u8"lorem")
- (check (parse-SNB/prefix "#u8\"\\xde;\\xad;\\xf0;\\x0d;\"")
- => (bytevector #xde #xad #xf0 #x0d))
- (check (parse-SNB/prefix "#u8\"\\\"\\\\\\a\\b\\t\\n\\r\\\|\"")
- => (bytestring #\" #\\ #\alarm #\backspace #\tab #\newline #\return #\|))
- (check (parse-SNB/prefix "#u8\"lor\\\n\te\\ \r\n\tm\"")
- => #u8"lorem")
- (check (parse-SNB "\"lorem\"") => #u8"lorem")
-
- ;; Invalid SNB detection.
- (check (catch-bytestring-error (parse-SNB/prefix "#u\"lorem\""))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8lorem\""))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8\"lorem"))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8\"lorem"))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8\"l\\orem\""))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8\"l\\ orem\""))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8\"l\\x6frem\""))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8\"l\\x6z;rem\""))
- => 'bytestring-error)
- (check (catch-bytestring-error (parse-SNB/prefix "#u8\"α equivalence\""))
- => 'bytestring-error)
-
- ;;; write-textual-bytestring
-
- (check (%bytestring->SNB #u8()) => "#u8\"\"")
- (check (%bytestring->SNB #u8"lorem") => "#u8\"lorem\"")
- (check (%bytestring->SNB (bytevector #xde #xad #xbe #xef))
- => "#u8\"\\xde;\\xad;\\xbe;\\xef;\"")
- (check (%bytestring->SNB
- (bytestring #\" #\\ #\alarm #\backspace #\tab #\newline #\return #\|))
- => "#u8\"\\\"\\\\\\a\\b\\t\\n\\r\\\|\"")
-
- (let ((#u8"lorem"s
- '(#u8(124 199 173 212 209 232 249 16 198 32 123 111 130 92 64 155)
- #u8(50 133 193 27 177 105 10 186 61 149 177 105 96 70 223 190)
- #u8(0 117 226 155 110 0 66 216 27 129 187 81 17 210 71 152)
- #u8(123 31 159 25 100 135 246 47 249 137 243 241 45 241 240 221)
- #u8(207 186 70 110 118 231 79 195 153 253 93 101 126 198 70 235)
- #u8(138 176 92 152 208 107 28 236 198 254 111 37 241 116 191 206)
- #u8(221 254 214 90 0 155 132 92 157 246 199 224 224 142 91 114)
- #u8(228 216 233 80 142 15 158 54 5 85 174 101 111 75 126 209)
- #u8(191 16 83 245 45 98 72 212 148 202 135 19 213 150 141 121)
- #u8(41 169 182 96 47 184 16 116 196 251 243 93 81 162 175 140)
- #u8(85 49 218 138 132 11 27 11 182 27 120 71 254 169 132 166)
- #u8(89 216 175 23 97 10 237 112 208 195 112 80 198 154 241 254)
- #u8(187 54 6 57 250 137 129 89 188 19 225 217 168 178 174 129)
- #u8(88 164 89 40 175 194 108 56 12 124 109 96 148 149 119 109)
- #u8(241 66 32 115 203 71 128 154 240 111 194 137 73 44 146 3)
- #u8(177 185 177 233 18 14 178 106 110 109 222 147 111 157 216 208))))
- (check
- (every (lambda (bvec)
- (equal? bvec (parse-SNB/prefix (%bytestring->SNB bvec))))
- #u8"lorem"s)
- => #t))
-)
-|#
+(check-equal (#u8(#x50 #x4b) #u8(0 0 #x1 #x5))
+ (call-with-values (lambda () (bytestring-break #u8(#x50 #x4b 0 0 #x1 #x5) zero?)) list))
+
+(check-equal (#u8"ABCD" #u8"efg")
+ (call-with-values
+ (lambda () (bytestring-span #u8"ABCDefg" (lambda (b) (and (> b 40) (< b 91)))))
+ list))
+
+(define (eq-r? b) (= b #x72))
+(define (lt-r? b) (< b #x72))
+
+(check-equal (#u8"lorem" #u8())
+ (call-with-values (lambda () (bytestring-span #u8"lorem" always)) list))
+(check-equal (#u8() #u8"lorem")
+ (call-with-values (lambda () (bytestring-span #u8"lorem" never)) list))
+(check-equal (#u8"lo" #u8"rem")
+ (call-with-values (lambda () (bytestring-span #u8"lorem" lt-r?)) list))
+
+(check-equal (#u8() #u8"lorem")
+ (call-with-values (lambda () (bytestring-break #u8"lorem" always)) list))
+(check-equal (#u8"lorem" #u8())
+ (call-with-values (lambda () (bytestring-break #u8"lorem" never)) list))
+(check-equal (#u8"lo" #u8"rem")
+ (call-with-values (lambda () (bytestring-break #u8"lorem" eq-r?)) list))
+
+(check-equal #u8"Heart of Gold" (bytestring-join '(#u8"Heart" #u8"of" #u8"Gold") #x20))
+(check-equal #u8(0 #xef #xbb 0 #xbf) (bytestring-join '(#u8(#xef #xbb) #u8(#xbf)) 0 'prefix))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (bytestring-join '() 0 'strict-infix))))
+
+(define test-segments '(#u8(1) #u8(2) #u8(3)))
+(check-equal #u8(1 0 2 0 3) (bytestring-join test-segments #u8(0)))
+(check-equal #u8(0 1 0 2 0 3) (bytestring-join test-segments #u8(0) 'prefix))
+(check-equal #u8(1 0 2 0 3 0) (bytestring-join test-segments #u8(0) 'suffix))
+(check-equal #u8() (bytestring-join '() #u8(0)))
+(check-equal #u8(1 32 2 32 3) (bytestring-join test-segments #\space))
+(check-equal #u8(1 0 2 0 3) (bytestring-join test-segments 0))
+(check-equal #u8(1 65 66 2 65 66 3) (bytestring-join test-segments "AB"))
+(check-equal #u8(1 7 8 2 7 8 3) (bytestring-join test-segments #u8(7 8)))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (bytestring-join test-segments 300))))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (bytestring-join '() #u8(0) 'strict-infix))))
+
+(check-equal (#u8"Bee" #u8"le" #u8"rox") (bytestring-split #u8"Beeblebrox" #x62))
+(check-equal (#u8(1) #u8(2)) (bytestring-split #u8(1 0 2 0) 0 'suffix))
+(check-equal (#u8(1) #u8(2) #u8(3)) (bytestring-split #u8(1 0 2 0 3) 0 'infix))
+(check-equal (#u8(1) #u8(2) #u8(3)) (bytestring-split #u8(0 1 0 2 0 3) 0 'prefix))
+(check-equal (#u8(1) #u8(2) #u8(3)) (bytestring-split #u8(1 0 2 0 3 0) 0 'suffix))
+(check-equal (#u8() #u8() #u8()) (bytestring-split #u8(0 0) 0))
+(check-equal () (bytestring-split #u8() 0))
+
+(define (read-bs prefix bs)
+ (call-with-port (open-input-string bs)
+ (lambda (port) (read-textual-bytestring prefix port))))
+
+(check-equal #u8(#x41 #x42 #xad #xf0 #x0d #x43 #x44)
+ (read-bs #t "#u8\"AB\\xad;\\xf0;\\x0d;CD\""))
+(check-equal #u8() (read-bs #t "#u8\"\""))
+(check-equal #u8"lorem" (read-bs #t "#u8\"lorem\""))
+(check-equal #t
+ (equal?
+ (bytevector #xde #xad #xf0 #x0d)
+ (read-bs #t "#u8\"\\xde;\\xad;\\xf0;\\x0d;\"")))
+(check-equal #t
+ (equal?
+ (bytestring #\" #\\ #\alarm #\backspace #\tab #\newline #\return #\|)
+ (read-bs #t "#u8\"\\\"\\\\\\a\\b\\t\\n\\r\\\|\"")))
+(check-equal #u8"lorem" (read-bs #t "#u8\"lor\\\n\te\\ \r\n\tm\""))
+(check-equal #u8"lorem" (read-bs #f "\"lorem\""))
+
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (read-bs #t "#u\"lorem\""))))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (read-bs #t "#u8lorem\""))))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (read-bs #t "#u8\"lorem"))))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (read-bs #t "#u8\"l\\orem\""))))
+;(check-equal #t
+; (bytestring-error? (guard (o (else o)) (read-bs #t "#u8\"l\\ orem\""))))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (read-bs #t "#u8\"l\\x6frem\""))))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (read-bs #t "#u8\"l\\x6z;rem\""))))
+(check-equal #t
+ (bytestring-error? (guard (o (else o)) (read-bs #t "#u8\"\x100; equivalence\""))))
+
+(define (write-textual-bs bs)
+ (call-with-port (open-output-string)
+ (lambda (port)
+ (write-textual-bytestring bs port)
+ (get-output-string port))))
+
+(check-equal "#u8\"\\tArthur\\n\"" (write-textual-bs #u8(#x9 #x41 #x72 #x74 #x68 #x75 #x72 #xa)))
+(check-equal "#u8\"\"" (write-textual-bs #u8()))
+(check-equal "#u8\"lorem\"" (write-textual-bs #u8"lorem"))
+(check-equal "#u8\"\\xde;\\xad;\\xbe;\\xef;\"" (write-textual-bs (bytevector #xde #xad #xbe #xef)))
+(check-equal "#u8\"\\\"\\\\\\a\\b\\t\\n\\r\\\|\""
+ (write-textual-bs (bytestring #\" #\\ #\alarm #\backspace #\tab #\newline #\return #\|)))
+
+(check-equal #t
+ (let ((lorems
+ '(#u8(124 199 173 212 209 232 249 16 198 32 123 111 130 92 64 155)
+ #u8(50 133 193 27 177 105 10 186 61 149 177 105 96 70 223 190)
+ #u8(0 117 226 155 110 0 66 216 27 129 187 81 17 210 71 152)
+ #u8(123 31 159 25 100 135 246 47 249 137 243 241 45 241 240 221)
+ #u8(207 186 70 110 118 231 79 195 153 253 93 101 126 198 70 235)
+ #u8(138 176 92 152 208 107 28 236 198 254 111 37 241 116 191 206)
+ #u8(221 254 214 90 0 155 132 92 157 246 199 224 224 142 91 114)
+ #u8(228 216 233 80 142 15 158 54 5 85 174 101 111 75 126 209)
+ #u8(191 16 83 245 45 98 72 212 148 202 135 19 213 150 141 121)
+ #u8(41 169 182 96 47 184 16 116 196 251 243 93 81 162 175 140)
+ #u8(85 49 218 138 132 11 27 11 182 27 120 71 254 169 132 166)
+ #u8(89 216 175 23 97 10 237 112 208 195 112 80 198 154 241 254)
+ #u8(187 54 6 57 250 137 129 89 188 19 225 217 168 178 174 129)
+ #u8(88 164 89 40 175 194 108 56 12 124 109 96 148 149 119 109)
+ #u8(241 66 32 115 203 71 128 154 240 111 194 137 73 44 146 3)
+ #u8(177 185 177 233 18 14 178 106 110 109 222 147 111 157 216 208))))
+ (every
+ (lambda (bvec)
+ (equal? bvec (read-bs #t (write-textual-bs bvec))))
+ lorems)))
+
+(define (write-binary-bs . args)
+ (call-with-port (open-output-bytevector)
+ (lambda (port)
+ (apply write-binary-bytestring port args)
+ (get-output-bytevector port))))
+
+(check-equal #u8"Zaphod" (write-binary-bs #\Z #x61 #x70 "hod"))
diff --git a/unix/makefile b/unix/makefile
index 3bab9a5..9f6e0bf 100644
--- a/unix/makefile
+++ b/unix/makefile
@@ -148,7 +148,8 @@ debug/pairs.o: ../src/pairs.cpp ../src/foment.hpp
debug/unicode.o: ../src/unicode.cpp ../src/foment.hpp ../src/unicode.hpp ../src/unicase.hpp
debug/chars.o: ../src/chars.cpp ../src/foment.hpp ../src/unicode.hpp
debug/strings.o: ../src/strings.cpp ../src/foment.hpp ../src/unicode.hpp
-debug/vectors.o: ../src/vectors.cpp ../src/foment.hpp ../src/unicode.hpp
+debug/vectors.o: ../src/vectors.cpp ../src/foment.hpp ../src/syncthrd.hpp ../src/io.hpp\
+ ../src/unicode.hpp
debug/library.o: ../src/library.cpp ../src/foment.hpp ../src/compile.hpp
debug/execute.o: ../src/execute.cpp ../src/foment.hpp ../src/execute.hpp ../src/syncthrd.hpp
debug/numbers.o: ../src/numbers.cpp ../src/foment.hpp ../src/unicode.hpp ../src/bignums.hpp
@@ -181,7 +182,8 @@ release/pairs.o: ../src/pairs.cpp ../src/foment.hpp
release/unicode.o: ../src/unicode.cpp ../src/foment.hpp ../src/unicode.hpp ../src/unicase.hpp
release/chars.o: ../src/chars.cpp ../src/foment.hpp ../src/unicode.hpp
release/strings.o: ../src/strings.cpp ../src/foment.hpp ../src/unicode.hpp
-release/vectors.o: ../src/vectors.cpp ../src/foment.hpp ../src/unicode.hpp
+release/vectors.o: ../src/vectors.cpp ../src/foment.hpp ../src/syncthrd.hpp ../src/io.hpp\
+ ../src/unicode.hpp
release/library.o: ../src/library.cpp ../src/foment.hpp ../src/compile.hpp
release/execute.o: ../src/execute.cpp ../src/foment.hpp ../src/execute.hpp ../src/syncthrd.hpp
release/numbers.o: ../src/numbers.cpp ../src/foment.hpp ../src/unicode.hpp ../src/bignums.hpp
diff --git a/windows/makefile b/windows/makefile
index 5e3e9a6..8b29b7b 100644
--- a/windows/makefile
+++ b/windows/makefile
@@ -135,7 +135,8 @@ debug\pairs.obj: ..\src\pairs.cpp ..\src\foment.hpp
debug\unicode.obj: ..\src\unicode.cpp ..\src\foment.hpp ..\src\unicode.hpp ..\src\unicase.hpp
debug\chars.obj: ..\src\chars.cpp ..\src\foment.hpp ..\src\unicode.hpp
debug\strings.obj: ..\src\strings.cpp ..\src\foment.hpp ..\src\unicode.hpp
-debug\vectors.obj: ..\src\vectors.cpp ..\src\foment.hpp ..\src\unicode.hpp
+debug\vectors.obj: ..\src\vectors.cpp ..\src\foment.hpp ..\src\syncthrd.hpp ..\src\io.hpp\
+ ..\src\unicode.hpp
debug\library.obj: ..\src\library.cpp ..\src\foment.hpp ..\src\compile.hpp
debug\execute.obj: ..\src\execute.cpp ..\src\foment.hpp ..\src\execute.hpp ..\src\syncthrd.hpp
debug\numbers.obj: ..\src\numbers.cpp ..\src\foment.hpp ..\src\unicode.hpp ..\src\bignums.hpp
@@ -167,7 +168,8 @@ release\pairs.obj: ..\src\pairs.cpp ..\src\foment.hpp
release\unicode.obj: ..\src\unicode.cpp ..\src\foment.hpp ..\src\unicode.hpp ..\src\unicase.hpp
release\chars.obj: ..\src\chars.cpp ..\src\foment.hpp ..\src\unicode.hpp
release\strings.obj: ..\src\strings.cpp ..\src\foment.hpp ..\src\unicode.hpp
-release\vectors.obj: ..\src\vectors.cpp ..\src\foment.hpp ..\src\unicode.hpp
+release\vectors.obj: ..\src\vectors.cpp ..\src\foment.hpp ..\src\syncthrdhpp ..\src\io.hpp\
+ ..\src\unicode.hpp
release\library.obj: ..\src\library.cpp ..\src\foment.hpp ..\src\compile.hpp
release\execute.obj: ..\src\execute.cpp ..\src\foment.hpp ..\src\execute.hpp ..\src\syncthrd.hpp
release\numbers.obj: ..\src\numbers.cpp ..\src\foment.hpp ..\src\unicode.hpp ..\src\bignums.hpp