diff options
author | Mike Montague <mikemon@gmail.com> | 2022-07-31 14:58:13 -0700 |
---|---|---|
committer | Mike Montague <mikemon@gmail.com> | 2022-07-31 14:58:13 -0700 |
commit | 54fd0217f83c91276600625b53882cd0472e80a1 (patch) | |
tree | d397745db901ba06f43a96287c39f6fe442678e7 | |
parent | 277d9a4b7d8ca3e8d3b567f25e82dd5a6cfcb02a (diff) |
srfi 207: constructors and conversion
-rw-r--r-- | src/base.scm | 8 | ||||
-rw-r--r-- | src/foment.hpp | 4 | ||||
-rw-r--r-- | src/read.cpp | 81 | ||||
-rw-r--r-- | src/srfi-166.scm | 4 | ||||
-rw-r--r-- | src/vectors.cpp | 350 | ||||
-rw-r--r-- | test/srfi.scm | 361 | ||||
-rw-r--r-- | unix/makefile | 6 | ||||
-rw-r--r-- | windows/makefile | 6 |
8 files changed, 791 insertions, 29 deletions
diff --git a/src/base.scm b/src/base.scm index 85b6db0..ef9c6fa 100644 --- a/src/base.scm +++ b/src/base.scm @@ -696,7 +696,13 @@ set-procedure-property! %procedure->formatter %formatter? - call-with-parameterize) + call-with-parameterize + make-bytestring + bytevector->hex-string + hex-string->bytevector + bytevector->base64 + base64->bytevector + bytestring->list) (cond-expand (unix (export diff --git a/src/foment.hpp b/src/foment.hpp index ae417b2..994341c 100644 --- a/src/foment.hpp +++ b/src/foment.hpp @@ -8,8 +8,9 @@ To Do: -- Bytevectors: R6RS (rnrs bytevectors) as (scheme bytevector) (note singular form) -- SRFI 129: Titlecase Procedures -- SRFI 154: First-class dynamic extents +-- SRFI 158: Generators and Accumulators -- SRFI 195: Multiple-value boxes --- SRIF 207: String-notated bytevectors +-- SRFI 207: String-notated bytevectors -- IO: FAlive, EnterWait, and LeaveWait -- Allow GC on nested executions @@ -1133,6 +1134,7 @@ extern FObject StartThreadOutOfMemory; extern FObject ExecuteStackOverflow; extern FObject FileErrorSymbol; extern FObject PositionErrorSymbol; +extern FObject BytestringErrorSymbol; extern FObject NoValuePrimitive; // ---- Flonums ---- diff --git a/src/read.cpp b/src/read.cpp index fe0392c..f7232d3 100644 --- a/src/read.cpp +++ b/src/read.cpp @@ -25,6 +25,8 @@ Foment #define MAXIMUM_NUMBER 256 #define MAXIMUM_NAME 32 +EternalSymbol(BytestringErrorSymbol, "bytestring-error"); + // ---- Datum Reference ---- #define AsDatumReference(obj) ((FDatumReference *) (obj)) @@ -86,18 +88,18 @@ static long_t DotSubsequentP(FCh ch) #define DotObject ((FObject) -1) #define EolObject ((FObject *) -2) -static FCh ReadStringHexChar(FObject port) +static FCh ReadStringHexChar(FObject port, int bsf) { FAlive ap(&port); FCh s[16]; long_t sl = 2; FCh ch; + FObject n; for (;;) { if (ReadCh(port, &ch) == 0) - RaiseExceptionC(Lexical, "read", "unexpected end-of-file reading string", - List(port)); + goto MissingSemicolon; if (ch == ';') break; @@ -105,25 +107,34 @@ static FCh ReadStringHexChar(FObject port) s[sl] = ch; sl += 1; if (sl == sizeof(s) / sizeof(FCh)) - RaiseExceptionC(Lexical, "read", - "missing ; to terminate \\x<hex-value> in string", List(port)); + goto MissingSemicolon; } - FObject n = StringToNumber(s + 2, sl - 2, 16); + n = StringToNumber(s + 2, sl - 2, 16); if (FixnumP(n) == 0) { s[0] = '\\'; s[1] = 'x'; - RaiseExceptionC(Lexical, "read", "expected a valid hexidecimal value for a character", + RaiseExceptionC(Lexical, "read", bsf ? BytestringErrorSymbol : NoValueObject, + "expected a valid hexidecimal value for a character", List(port, MakeString(s, sl))); } return((FCh) AsFixnum(n)); + +MissingSemicolon: + if (bsf) + RaiseExceptionC(Lexical, "read", BytestringErrorSymbol, + "missing ; to terminate \\x<hex-value> in bytestring", List(port)); + else + RaiseExceptionC(Lexical, "read", + "missing ; to terminate \\x<hex-value> in string", List(port)); + return(0); } -static FObject ReadStringLiteral(FObject port, FCh tch) +static FObject ReadStringLiteral(FObject port, FCh tch, int bsf) { FAlive ap(&port); FCh sb[128]; @@ -184,11 +195,16 @@ Again: case '\\': ch = 0x005C; break; case '|': ch = 0x007C; break; case 'x': - ch = ReadStringHexChar(port); + ch = ReadStringHexChar(port, bsf); break; default: - RaiseExceptionC(Lexical, "read", "unexpected character following \\", - List(port, MakeCharacter(ch))); + if (bsf) + RaiseExceptionC(Lexical, "read", BytestringErrorSymbol, + "unexpected character following \\ in bytestring", + List(port, MakeCharacter(ch))); + else + RaiseExceptionC(Lexical, "read", "unexpected character following \\ in string", + List(port, MakeCharacter(ch))); } } @@ -201,7 +217,8 @@ Again: { if (s != sb) free(s); - RaiseExceptionC(Restriction, "read", "string too long", List(port)); + RaiseExceptionC(Restriction, "read", bsf ? "bytestring too long" : + "string too long", List(port)); } memcpy(ns, s, msl * sizeof(FCh)); @@ -220,10 +237,28 @@ Again: UnexpectedEof: if (s != sb) free(s); - RaiseExceptionC(Lexical, "read", "unexpected end-of-file reading string", List(port)); + RaiseExceptionC(Lexical, "read", bsf ? "unexpected end-of-file reading bytestring" : + "unexpected end-of-file reading string", List(port)); return(NoValueObject); } +static FObject ReadBytestring(FObject port) +{ + FObject s = ReadStringLiteral(port, '"', 1); + long_t sl = StringLength(s); + FObject bv = MakeBytevector(sl); + for (long_t idx = 0; idx < sl; idx += 1) + { + FCh ch = AsString(s)->String[idx]; + if (ch >= 128 ) + RaiseExceptionC(Lexical, "read", BytestringErrorSymbol, + "unexpected character in bytestring", List(MakeCharacter(ch))); + AsBytevector(bv)->Vector[idx] = (FByte) ch; + } + + return(bv); +} + static FObject ReadNumber(FObject port, FCh * s, long_t sdx, long_t rdx, long_t df) { FAlive ap(&port); @@ -448,14 +483,16 @@ static FObject ReadSharp(FObject port, long_t eaf, long_t rlf, FObject * pdlhtbl RaiseExceptionC(Lexical, "read", "unexpected end-of-file reading bytevector", List(port)); if (ch != '8') - RaiseExceptionC(Lexical, "read", "expected #\\u8(", List(port)); + RaiseExceptionC(Lexical, "read", "expected #u8(", List(port)); if (ReadCh(port, &ch) == 0) RaiseExceptionC(Lexical, "read", "unexpected end-of-file reading bytevector", List(port)); - if (ch != '(') - RaiseExceptionC(Lexical, "read", "expected #\\u8(", List(port)); - return(U8ListToBytevector(ReadList(port, pdlhtbl))); + if (ch == '(') + return(U8ListToBytevector(ReadList(port, pdlhtbl))); + else if (ch == '"') + return(ReadBytestring(port)); + RaiseExceptionC(Lexical, "read", "expected #u8( or #u8\"", List(port)); } else if (ch == ';') { @@ -574,7 +611,7 @@ static FObject Read(FObject port, long_t eaf, long_t rlf, FObject * pdlhtbl) return(ReadSharp(port, eaf, rlf, pdlhtbl)); case '"': - return(ReadStringLiteral(port, '"')); + return(ReadStringLiteral(port, '"', 0)); case '|': { @@ -584,8 +621,8 @@ static FObject Read(FObject port, long_t eaf, long_t rlf, FObject * pdlhtbl) ln = GetLineColumn(port, 0); FObject sym = FoldcasePortP(port) - ? StringToSymbol(FoldcaseString(ReadStringLiteral(port, '|'))) - : StringToSymbol(ReadStringLiteral(port, '|')); + ? StringToSymbol(FoldcaseString(ReadStringLiteral(port, '|', 0))) + : StringToSymbol(ReadStringLiteral(port, '|', 0)); return(WantIdentifiersPortP(port) ? MakeIdentifier(sym, GetFilename(port), ln) : sym); } @@ -1024,6 +1061,10 @@ void SetupRead() { FAssert(MAXIMUM_NUMBER == MAXIMUM_IDENTIFIER); + BytestringErrorSymbol = InternSymbol(BytestringErrorSymbol); + + FAssert(BytestringErrorSymbol = StringCToSymbol("bytestring-error")); + for (ulong_t idx = 0; idx < sizeof(Primitives) / sizeof(FPrimitive *); idx++) DefinePrimitive(Bedrock, BedrockLibrary, Primitives[idx]); } diff --git a/src/srfi-166.scm b/src/srfi-166.scm index b30388f..006dbde 100644 --- a/src/srfi-166.scm +++ b/src/srfi-166.scm @@ -1311,8 +1311,8 @@ sign-rule comma-rule comma-sep - word-separator? - )) + word-separator?) + ) (define-library (srfi 166 pretty) (import (srfi 166)) diff --git a/src/vectors.cpp b/src/vectors.cpp index 069d9dc..eb4764c 100644 --- a/src/vectors.cpp +++ b/src/vectors.cpp @@ -4,6 +4,7 @@ Foment */ +#include <stdio.h> #include <string.h> #include "foment.hpp" #include "unicode.hpp" @@ -882,6 +883,347 @@ Define("string->utf8", StringToUtf8Primitive)(long_t argc, FObject argv[]) return(ConvertStringToUtf8(AsString(argv[0])->String + strt, end - strt, 0)); } +// ---- SRFI 207: String-notated bytevectors ---- + +Define("make-bytestring", MakeBytestringPrimitive)(long_t argc, FObject argv[]) +{ + OneArgCheck("make-bytestring", argc); + + FObject lst = argv[0]; + long_t bsl = 0; + + while (PairP(lst)) + { + FObject arg = First(lst); + if (FixnumP(arg)) + { + if (AsFixnum(arg) < 0 || AsFixnum(arg) > 255) + RaiseExceptionC(Assertion, "make-bytestring", BytestringErrorSymbol, + "expected an integer between 0 and 155", List(arg)); + + bsl += 1; + } + else if (CharacterP(arg)) + { + if (AsCharacter(arg) >= 128) + RaiseExceptionC(Assertion, "make-bytestring", BytestringErrorSymbol, + "expected an ascii character", List(arg)); + + bsl += 1; + } + else if (BytevectorP(arg)) + bsl += BytevectorLength(arg); + else if (StringP(arg)) + bsl += StringLength(arg); + else + RaiseExceptionC(Assertion, "make-bytestring", BytestringErrorSymbol, + "expected a character, integer, bytevector, or a string", List(arg)); + + lst = Rest(lst); + } + + if (lst != EmptyListObject) + RaiseExceptionC(Assertion, "make-bytestring", "expected a valid list", List(argv[0])); + + FObject bv = MakeBytevector(bsl); + FByte * bs = AsBytevector(bv)->Vector; + long_t bdx = 0; + + lst = argv[0]; + while (PairP(lst)) + { + FObject arg = First(lst); + if (FixnumP(arg)) + { + bs[bdx] = (FByte) AsFixnum(arg); + bdx += 1; + } + else if (CharacterP(arg)) + { + bs[bdx] = (FByte) AsCharacter(arg); + bdx += 1; + } + else if (BytevectorP(arg)) + { + memcpy(bs + bdx, AsBytevector(arg)->Vector, BytevectorLength(arg)); + bdx += BytevectorLength(arg); + } + else if (StringP(arg)) + { + long_t sl = StringLength(arg); + for (long_t sdx = 0; sdx < sl; sdx += 1) + { + FCh ch = AsString(arg)->String[sdx]; + if (ch >= 128) + RaiseExceptionC(Assertion, "make-bytestring", BytestringErrorSymbol, + "expected a string of ascii characters", List(arg)); + bs[bdx + sdx] = (FByte) ch; + } + + bdx += sl; + } + else + { + FAssert(0); + } + + lst = Rest(lst); + } + + return(bv); +} + +const char * hexdigit = "0123456789abcdef"; + +Define("bytevector->hex-string", BytevectorToHexStringPrimitive)(long_t argc, FObject argv[]) +{ + OneArgCheck("bytevector->hex-string", argc); + BytevectorArgCheck("bytevector->hex-string", argv[0]); + + ulong_t vl = BytevectorLength(argv[0]); + FObject ret = MakeStringCh(vl * 2, 0); + FCh * s = AsString(ret)->String; + FByte * v = AsBytevector(argv[0])->Vector; + + for (ulong_t vdx = 0; vdx < vl; vdx += 1) + { + s[vdx * 2] = hexdigit[(v[vdx] >> 4) & 0x0F]; + s[vdx * 2 + 1] = hexdigit[v[vdx] & 0x0F]; + } + + return(ret); +} + +static FByte ConvertHexDigit(FCh ch) +{ + if (ch >= '0' && ch <= '9') + return(ch - '0'); + else if (ch >= 'a' && ch <= 'f') + return(ch - 'a' + 10); + else if (ch >= 'A' && ch <= 'F') + return(ch - 'A' + 10); + + RaiseExceptionC(Assertion, "hex-string->bytevector", BytestringErrorSymbol, + "expected a hexidecimal digit", List(MakeCharacter(ch))); + return(0); +} + +Define("hex-string->bytevector", HexStringToBytevectorPrimitive)(long_t argc, FObject argv[]) +{ + OneArgCheck("hex-string->bytevector", argc); + StringArgCheck("hex-string->bytevector", argv[0]); + + ulong_t sl = StringLength(argv[0]); + + if (sl % 2 != 0) + RaiseExceptionC(Assertion, "hex-string->bytevector", BytestringErrorSymbol, + "expected a string of pairs of hexidecimal digits", List(argv[0])); + + FObject ret = MakeBytevector(sl / 2, "hex-string->bytevector"); + FCh * s = AsString(argv[0])->String; + FByte * v = AsBytevector(ret)->Vector; + + for (ulong_t sdx = 0; sdx < sl; sdx += 2) + v[sdx / 2] = (ConvertHexDigit(s[sdx]) << 4) | ConvertHexDigit(s[sdx + 1]) ; + + return(ret); +} + +const char * base64digit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static FCh Base64Digit(ulong_t d, FCh digits[2]) +{ + FAssert(d < 64); + + if (d > 61) + return(digits[d - 62]); + return(base64digit[d]); +} + +Define("bytevector->base64", BytevectorToBase64Primitive)(long_t argc, FObject argv[]) +{ + OneOrTwoArgsCheck("bytevector->base64", argc); + BytevectorArgCheck("bytevector->base64", argv[0]); + + FCh digits[2] = {'+', '/'}; + + if (argc == 2) + { + if (StringP(argv[1]) == 0 || StringLength(argv[1]) != 2) + RaiseExceptionC(Assertion, "bytevector->base64", "expected a two character string", + List(argv[1])); + + digits[0] = AsString(argv[1])->String[0]; + digits[1] = AsString(argv[1])->String[1]; + } + + ulong_t vl = BytevectorLength(argv[0]); + FObject ret = MakeStringCh((vl / 3) * 4 + (vl % 3 == 0 ? 0 : 4), 0); + FCh * s = AsString(ret)->String; + FByte * v = AsBytevector(argv[0])->Vector; + + ulong_t sdx = 0; + for (ulong_t vdx = 3; vdx <= vl; vdx += 3) + { + ulong_t d = (v[vdx - 3] << 16) | (v[vdx - 2] << 8) | v[vdx - 1]; + s[sdx] = Base64Digit((d >> 18) & 0x3F, digits); + s[sdx + 1] = Base64Digit((d >> 12) & 0x3F, digits); + s[sdx + 2] = Base64Digit((d >> 6) & 0x3F, digits); + s[sdx + 3] = Base64Digit(d & 0x3F, digits); + sdx += 4; + } + + if (vl % 3 == 1) + { + ulong_t d = v[vl - 1] << 16; + s[sdx] = Base64Digit((d >> 18) & 0x3F, digits); + s[sdx + 1] = Base64Digit((d >> 12) & 0x3F, digits); + s[sdx + 2] = '='; + s[sdx + 3] = '='; + } else if (vl % 3 == 2) + { + ulong_t d = (v[vl - 2] << 16) | (v[vl - 1] << 8); + s[sdx] = Base64Digit((d >> 18) & 0x3F, digits); + s[sdx + 1] = Base64Digit((d >> 12) & 0x3F, digits); + s[sdx + 2] = Base64Digit((d >> 6) & 0x3F, digits); + s[sdx + 3] = '='; + } + + return(ret); +} + +static ulong_t SkipWhitespace(FCh * s, ulong_t sl, ulong_t sdx) +{ + while (sdx < sl && WhitespaceP(s[sdx])) + sdx += 1; + + return(sdx); +} + +static ulong_t ConvertBase64(FCh ch, FCh digits[2]) +{ + if (ch == digits[0]) + return(62); + else if (ch == digits[1]) + return(63); + else if (ch >= 'A' && ch <= 'Z') + return(ch - 'A'); + else if (ch >= 'a' && ch <= 'z') + return(ch - 'a' + 26); + else if (ch >= '0' && ch <= '9') + return(ch - '0' + 52); + + RaiseExceptionC(Assertion, "base64->bytevector", BytestringErrorSymbol, + "expected a base64 digit", List(MakeCharacter(ch))); + return(0); +} + +Define("base64->bytevector", Base64ToBytevectorPrimitive)(long_t argc, FObject argv[]) +{ + OneOrTwoArgsCheck("base64->bytevector", argc); + StringArgCheck("base64->bytevector", argv[0]); + + FCh digits[2] = {'+', '/'}; + + if (argc == 2) + { + if (StringP(argv[1]) == 0 || StringLength(argv[1]) != 2) + RaiseExceptionC(Assertion, "base64->bytevector", "expected a two character string", + List(argv[1])); + + digits[0] = AsString(argv[1])->String[0]; + digits[1] = AsString(argv[1])->String[1]; + } + + ulong_t sl = StringLength(argv[0]); + FCh * s = AsString(argv[0])->String; + ulong_t sdx = 0; + FObject lst = EmptyListObject; + for (;;) + { + ulong_t d = 0; + long_t eq = 0; + for (long_t cnt = 0; cnt < 4; cnt += 1) + { + sdx = SkipWhitespace(s, sl, sdx); + if (sdx == sl) + { + if (cnt > 0) + goto Failed; + + return(U8ListToBytevector(ReverseListModify(lst))); + } + + if (eq > 0 && s[sdx] != '=') + goto Failed; + + if (cnt > 1 && s[sdx] == '=') + { + d = d << 6; + eq += 1; + } + else + d = (d << 6) | ConvertBase64(s[sdx], digits); + sdx += 1; + } + + if (eq > 2) + goto Failed; + else if (eq > 0) + { + sdx = SkipWhitespace(s, sl, sdx); + if (sdx < sl) + goto Failed; + } + + lst = MakePair(MakeFixnum((d >> 16) & 0xFF), lst); + if (eq < 2) + lst = MakePair(MakeFixnum((d >> 8) & 0xFF), lst); + if (eq < 1) + lst = MakePair(MakeFixnum(d & 0xFF), lst); + } + +Failed: + RaiseExceptionC(Assertion, "base64->bytevector", BytestringErrorSymbol, + "expected a base64 string", List(argv[0])); + return(NoValueObject); +} + +Define("bytestring->list", BytestringToListPrimitive)(long_t argc, FObject argv[]) +{ + OneToThreeArgsCheck("bytestring->list", argc); + BytevectorArgCheck("bytestring->list", argv[0]); + + long_t vdx = 0; + long_t end = BytevectorLength(argv[0]); + if (argc > 1) + { + IndexArgCheck("bytestring->list", argv[1], end); + + vdx = AsFixnum(argv[1]); + } + if (argc > 2) + { + EndIndexArgCheck("bytestring->list", argv[1], vdx, end); + + end = AsFixnum(argv[2]); + } + + FByte * v = AsBytevector(argv[0])->Vector; + FObject lst = EmptyListObject; + while (vdx < end) + { + if (v[vdx] >= 32 && v[vdx] <= 127) + lst = MakePair(MakeCharacter(v[vdx]), lst); + else + lst = MakePair(MakeFixnum(v[vdx]), lst); + + vdx += 1; + } + + return(ReverseListModify(lst)); +} + static FObject Primitives[] = { VectorPPrimitive, @@ -913,7 +1255,13 @@ static FObject Primitives[] = BytevectorCopyModifyPrimitive, BytevectorAppendPrimitive, Utf8ToStringPrimitive, - StringToUtf8Primitive + StringToUtf8Primitive, + MakeBytestringPrimitive, + BytevectorToHexStringPrimitive, + HexStringToBytevectorPrimitive, + BytevectorToBase64Primitive, + Base64ToBytevectorPrimitive, + BytestringToListPrimitive }; void SetupVectors() diff --git a/test/srfi.scm b/test/srfi.scm index 4930e3c..93c5497 100644 --- a/test/srfi.scm +++ b/test/srfi.scm @@ -3857,3 +3857,364 @@ (test-end)))) |# + +;; +;; ---- SRFI 207: String-notated bytevectors ---- +;; + +(import (srfi 207)) + +(check-equal #u8(65 66 67 68) #u8"ABCD") +(check-equal #u8(#x9 #x41 #x72 #x74 #x68 #x75 #x72 #xa) #u8"\tArthur\n") +(check-equal #u8(#x41 #x42 #x3d #x1f #x0d #x43 #x44) #u8"AB\x3d;\x1f;\x0d;CD") + +(define (check-read-bytestring s) + (bytestring-error? + (guard (o (else o)) + (let ((port (open-input-string s))) + (read port))))) + +(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))) + +(check-equal #u8(0 97 98 99 127 0 255 0 127) (make-bytestring '("\x0;abc\x7f;" 0 255 #\x0 #\x7F))) + +(define (check-make-bytestring . args) + (bytestring-error? (guard (o (else o)) (make-bytestring args)))) + +(check-equal #t (check-make-bytestring "abc" #x100 "efg")) +(check-equal #t (check-make-bytestring "abc\x3BB;efg")) +(check-equal #t (check-make-bytestring "abc" -1 "efg")) +(check-equal #t (check-make-bytestring "abc" 256 "efg")) +(check-equal #t (check-make-bytestring "abc" #\x80 "efg")) +(check-equal #f (check-make-bytestring "abc" #\x10 "efg")) + +(check-equal #t (check-make-bytestring "\x3BB;")) +(check-equal #t (check-make-bytestring #x100)) + +(check-equal #u8(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16) + (make-bytestring '(#u8(0 1 2 3) #\x4 5 6 7 "\x8;\x9;\xa;" #u8(11 12) 13 14 #\xF #\x10))) + +(check-equal #u8(113 114 115 116 117 118 119 120 121 122 123 124 125 126 127) + (bytestring #u8(113 114 115 116) 117 #\x76 #\x77 "xyz{|}~" 127)) + +(check-equal #u8"lorem" + (let ((bv (make-bytevector 5))) + (make-bytestring! bv 0 '(#x6c #x6f #x72 #x65 #x6d)) + bv)) + +(check-equal #u8" lorem " + (let ((bv (make-bytevector 9 #x20))) + (make-bytestring! bv 2 '("lo" #\r #x65 #u8(#x6d))) + bv)) + +(check-equal #u8" scheme " + (let ((bv (make-bytevector 10 #x20))) + (make-bytestring! bv 2 '(#\s #\c "he" #u8(#x6d #x65))) + bv)) + +(check-equal #u8(#x46 #x6f #x72 #x64) #u8"Ford") +(check-equal "466f7264" (bytevector->hex-string #u8"Ford")) +(check-equal #u8"Zaphod" (hex-string->bytevector "5a6170686f64")) + +(check-equal "6c6f72656d" (bytevector->hex-string #u8"lorem")) +(check-equal #u8"lorem" (hex-string->bytevector "6c6f72656d")) +(check-equal #t + (bytestring-error? (guard (o (else o)) (hex-string->bytevector "c6f72656d")))) +(check-equal #t + (bytestring-error? (guard (o (else o)) (hex-string->bytevector "6czf72656d")))) + +(define homer + (bytestring "The Man, O Muse, informe, who many a way / \ + Wound in his wisedome to his wished stay;")) + +(define homer64 + "VGhlIE1hbiwgTyBNdXNlLCBpbmZvcm1lLCB3aG8gbWFueSBhIHdheSAvIFdvd\ + W5kIGluIGhpcyB3aXNlZG9tZSB0byBoaXMgd2lzaGVkIHN0YXk7") + +(define homer64-w + "VGhlIE1hb iwgTyBNdXNlL CBpbmZvcm1lL\nCB3aG8gbWF\tueSBhIH\rdheSAvIFdvd\ + W5kIGluI GhpcyB 3aXNlZ\t\t\nG9tZSB0b yBoaXMgd\t2lzaGVkIHN0YXk7") + +(check-equal #t + (equal? (hex-string->bytevector (bytevector->hex-string homer)) homer)) +(check-equal #u8() (hex-string->bytevector (bytevector->hex-string #u8()))) + +(check-equal "bG9yZW0=" (bytevector->base64 (bytestring "lorem"))) +(check-equal "/+//" (bytevector->base64 #u8(#xff #xef #xff))) +(check-equal "@*@@" (bytevector->base64 #u8(#xff #xef #xff) "*@")) +(check-equal #t (equal? (bytevector->base64 homer) homer64)) +(check-equal "AQ==" (bytevector->base64 #u8(1))) +(check-equal "" (bytevector->base64 #u8())) +(check-equal #u8"lorem" (base64->bytevector "bG9yZW0=")) +(check-equal #u8(#xff #xef #xff) (base64->bytevector "/+//")) +(check-equal #u8(#xff #xef #xff) (base64->bytevector "@*@@" "*@")) +(check-equal #t (equal? (base64->bytevector homer64) homer)) +(check-equal #t (equal? (base64->bytevector homer64-w) homer)) +(check-equal #u8(1) (base64->bytevector "AQ==")) +(check-equal #u8() (base64->bytevector "")) +;(check-equal #u8() (base64->bytevector "\n\n\n==\t\r\n")) + +(check-equal "AQIDBAUG" (bytevector->base64 #u8(1 2 3 4 5 6))) +(check-equal "QXJ0aHVyIERlbnQ=" (bytevector->base64 #u8"Arthur Dent")) +(check-equal #u8(#xfb #xff #xfe) (base64->bytevector "+/ /+")) + +(check-equal #t + (bytestring-error? (guard (o (else o)) (base64->bytevector "bG9@frob")))) + +(check-equal "" (bytevector->base64 #u8"")) +(check-equal "Zg==" (bytevector->base64 #u8"f")) +(check-equal "Zm8=" (bytevector->base64 #u8"fo")) +(check-equal "Zm9v" (bytevector->base64 #u8"foo")) +(check-equal "Zm9vYg==" (bytevector->base64 #u8"foob")) +(check-equal "Zm9vYmE=" (bytevector->base64 #u8"fooba")) +(check-equal "Zm9vYmFy" (bytevector->base64 #u8"foobar")) + +(check-equal #u8"" (base64->bytevector "")) +(check-equal #u8"f" (base64->bytevector "Zg = =")) +(check-equal #u8"fo" (base64->bytevector "Zm 8=")) +(check-equal #u8"foo" (base64->bytevector " Zm9v")) +(check-equal #u8"foob" (base64->bytevector "Zm9vYg ==")) +(check-equal #u8"fooba" (base64->bytevector "Zm9vYmE= ")) +(check-equal #u8"foobar" (base64->bytevector "Zm 9vYmFy ")) + +(check-equal () (bytestring->list #u8())) +(check-equal (#\F #\R 0 #\B) (bytestring->list (bytestring 70 82 0 66))) +(check-equal (7 9 9 10 200) (bytestring->list (bytestring "\a\t\t\n" 200))) +(check-equal #u8"lorem" (make-bytestring (bytestring->list #u8"lorem"))) +(check-equal #u8"rem" (make-bytestring (bytestring->list #u8"lorem" 2))) +(check-equal #u8"or" (make-bytestring (bytestring->list #u8"lorem" 1 3))) + +(define (generator->list gen) + (define (generate gen lst) + (let ((val (gen))) + (if (eof-object? val) + (reverse lst) + (generate gen (cons val lst))))) + (generate gen '())) +(check-equal (#x6c #x6f #x72 #x65 #x6d) + (let ((g (make-bytestring-generator "lo" #\r #x65 #u8(#x6d)))) + (generator->list g))) +(check-equal #t + (bytestring-error? (guard (o (else o)) (make-bytestring-generator "abc\x3BB;efg" #\m #\u)))) +(check-equal #t + (bytestring-error? (guard (o (else o)) (make-bytestring-generator 89 90 300)))) +#| +(define test-bstring (bytestring "lorem")) + + +(define (check-selection) + (print-header "Running selection tests...") + + (check (bytestring-pad #u8"lorem" (bytevector-length #u8"lorem") #x7a) + => #u8"lorem") + (check (utf8->string (bytestring-pad #u8"lorem" 8 #x7a)) + => "zzzlorem") + (check (equal? (bytestring-pad #u8"lorem" 8 #\z) + (bytestring-pad #u8"lorem" 8 (char->integer #\z))) + => #t) + (check (bytestring-pad-right #u8"lorem" + (bytevector-length #u8"lorem") + #x7a) + => #u8"lorem") + (check (utf8->string (bytestring-pad-right #u8"lorem" 8 #x7a)) + => "loremzzz") + (check (equal? (bytestring-pad-right #u8"lorem" 8 #\z) + (bytestring-pad-right #u8"lorem" 8 (char->integer #\z))) + => #t) + + (check (bytestring-trim #u8"lorem" always) => #u8()) + (check (bytestring-trim #u8"lorem" never) => #u8"lorem") + (check (bytestring-trim #u8"lorem" (lambda (u8) (< u8 #x70))) + => #u8(#x72 #x65 #x6d)) + (check (bytestring-trim-right #u8"lorem" always) => #u8()) + (check (bytestring-trim-right #u8"lorem" never) => #u8"lorem") + (check (bytestring-trim-right #u8"lorem" (lambda (u8) (< u8 #x70))) + => #u8(#x6c #x6f #x72)) + (check (bytestring-trim-both #u8"lorem" always) => #u8()) + (check (bytestring-trim-both #u8"lorem" never) => #u8"lorem") + (check (bytestring-trim-both #u8"lorem" (lambda (u8) (< u8 #x70))) + => #u8(#x72))) + +(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 (bytestring-index #u8"lorem" always) => 0) + (check (bytestring-index #u8"lorem" never) => #f) + (check (bytestring-index #u8"lorem" always 3) => 3) + (check (bytestring-index #u8"lorem" eq-r?) => 2) + + (check (bytestring-index-right #u8"lorem" always) => 4) + (check (bytestring-index-right #u8"lorem" never) => #f) + (check (bytestring-index-right #u8"lorem" always 3) => 4) + (check (bytestring-index-right #u8"lorem" eq-r?) => 2) + + (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)) +) +|# diff --git a/unix/makefile b/unix/makefile index 7636d7b..3bab9a5 100644 --- a/unix/makefile +++ b/unix/makefile @@ -91,10 +91,12 @@ profile: debug/base.cpp: debug/txt2cpp makefile ../src/base.scm ../src/srfi-106.scm ../src/srfi-60.scm\ ../src/srfi-1.scm ../src/srfi-128.scm ../src/srfi-125.scm ../src/srfi-133.scm\ - ../src/srfi-14.scm ../src/srfi-193.scm ../src/srfi-151.scm ../src/srfi-166.scm + ../src/srfi-14.scm ../src/srfi-193.scm ../src/srfi-151.scm ../src/srfi-166.scm\ + ../src/srfi-207.scm debug/txt2cpp debug/base.cpp ../src/base.scm ../src/srfi-106.scm ../src/srfi-60.scm\ ../src/srfi-1.scm ../src/srfi-128.scm ../src/srfi-125.scm ../src/srfi-133.scm\ - ../src/srfi-14.scm ../src/srfi-193.scm ../src/srfi-151.scm ../src/srfi-166.scm + ../src/srfi-14.scm ../src/srfi-193.scm ../src/srfi-151.scm ../src/srfi-166.scm\ + ../src/srfi-207.scm debug/foment: debug/foment.o debug/gc.o debug/syncthrd.o debug/compile.o debug/io.o\ debug/synrules.o debug/synpass.o debug/midpass.o debug/genpass.o\ diff --git a/windows/makefile b/windows/makefile index 003d85e..5e3e9a6 100644 --- a/windows/makefile +++ b/windows/makefile @@ -65,10 +65,12 @@ release: debug\base.cpp: debug\txt2cpp.exe makefile ..\src\base.scm ..\src\srfi-106.scm ..\src\srfi-60.scm\ ..\src\srfi-1.scm ..\src\srfi-128.scm ..\src\srfi-125.scm ..\src\srfi-133.scm\ - ..\src\srfi-14.scm ..\src\srfi-193.scm ..\src\srfi-151.scm ..\src\srfi-166.scm + ..\src\srfi-14.scm ..\src\srfi-193.scm ..\src\srfi-151.scm ..\src\srfi-166.scm\ + ..\src\srfi-207.scm debug\txt2cpp debug\base.cpp ..\src\base.scm ..\src\srfi-106.scm ..\src\srfi-60.scm\ ..\src\srfi-1.scm ..\src\srfi-128.scm ..\src\srfi-125.scm ..\src\srfi-133.scm\ - ..\src\srfi-14.scm ..\src\srfi-193.scm ..\src\srfi-151.scm ..\src\srfi-166.scm + ..\src\srfi-14.scm ..\src\srfi-193.scm ..\src\srfi-151.scm ..\src\srfi-166.scm\ + ..\src\srfi-207.scm debug\foment.exe: debug\foment.obj debug\gc.obj debug\syncthrd.obj debug\compile.obj debug\io.obj\ debug\synrules.obj debug\synpass.obj debug\midpass.obj debug\genpass.obj\ |