commit bbb9cc6dae1094fe32e4df69b38842b1f12d65e4
parent a971a17d08f3ed3543a2240ffe771704730c4957
Author: Remy Noulin <loader2x@gmail.com>
Date: Thu, 27 Jan 2022 21:14:29 +0200
add bt (bytes type): a pointer with length
buildAsan.sh | 5 +-
buildMemcheck.sh | 5 +-
buildMusl.sh | 5 +-
buildMuslMemcheck.sh | 5 +-
buildStaticAnalysis.sh | 4 +-
clean.sh | 2 +-
cleanObjects.sh | 2 +-
example/README.template | 2 +-
install.sh | 3 +-
installOpenIndiana.sh | 1 +
release/libsheepyBt.c | 871 ++++++++++++++++++++++++++++++++++++++++++++++
release/libsheepyBt.h | 830 +++++++++++++++++++++++++++++++++++++++++++
release/libsheepyObject.h | 1 +
src/libsheepyBt.c | 871 ++++++++++++++++++++++++++++++++++++++++++++++
src/libsheepyBt.h | 830 +++++++++++++++++++++++++++++++++++++++++++
src/libsheepyObject.h | 1 +
uninstall.sh | 2 +-
17 files changed, 3426 insertions(+), 14 deletions(-)
Diffstat:
17 files changed, 3426 insertions(+), 14 deletions(-)
diff --git a/buildAsan.sh b/buildAsan.sh
@@ -7,6 +7,7 @@ DYNAMIC="-shared -fsanitize=address -lasan"
echo "Compiling C files"
$CC -c release/libsheepy.c
$CC -c release/libsheepySmall.c
+$CC -c release/libsheepyBt.c
$CC -c src/json/libsheepyObject.c
$CC -c src/json/libsheepyCSmallJson.c
$CC -c src/json/libsheepyCUndefined.c
@@ -28,7 +29,7 @@ $CC -c src/tpool.c
wait
echo "Building static lib"
-$STATIC release/libsheepyAsan.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$STATIC release/libsheepyAsan.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
echo "Building dynamic lib"
-$CC $DYNAMIC -o release/libsheepyAsan.so libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$CC $DYNAMIC -o release/libsheepyAsan.so libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
diff --git a/buildMemcheck.sh b/buildMemcheck.sh
@@ -7,6 +7,7 @@ DYNAMIC="-shared"
echo "Compiling C files"
$CC -c release/libsheepy.c
$CC -c release/libsheepySmall.c
+$CC -c release/libsheepyBt.c
$CC -c src/json/libsheepyObject.c
$CC -c src/json/libsheepyCSmallJson.c
$CC -c src/json/libsheepyCUndefined.c
@@ -26,7 +27,7 @@ $CC -c src/json/ymlReader.c
$CC -c src/tpool.c
echo "Building static lib"
-$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
echo "Building dynamic lib"
-$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
diff --git a/buildMusl.sh b/buildMusl.sh
@@ -5,6 +5,7 @@ DYNAMIC="-shared"
echo "Compiling C files"
$CC -c release/libsheepy.c
$CC -c release/libsheepySmall.c
+$CC -c release/libsheepyBt.c
$CC -c src/json/libsheepyObject.c
$CC -c src/json/libsheepyCSmallJson.c
$CC -c src/json/libsheepyCUndefined.c
@@ -24,7 +25,7 @@ $CC -c src/json/ymlReader.c
$CC -c src/tpool.c
echo "Building static lib"
-$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
echo "Building dynamic lib"
-$CC $DYNAMIC -o release/libsheepy.so libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$CC $DYNAMIC -o release/libsheepy.so libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
diff --git a/buildMuslMemcheck.sh b/buildMuslMemcheck.sh
@@ -7,6 +7,7 @@ DYNAMIC="-shared"
echo "Compiling C files"
$CC -c release/libsheepy.c
$CC -c release/libsheepySmall.c
+$CC -c release/libsheepyBt.c
$CC -c src/json/libsheepyObject.c
$CC -c src/json/libsheepyCSmallJson.c
$CC -c src/json/libsheepyCUndefined.c
@@ -26,7 +27,7 @@ $CC -c src/json/ymlReader.c
$CC -c src/tpool.c
echo "Building static lib"
-$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$STATIC release/libsheepyMemcheck.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
echo "Building dynamic lib"
-$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$CC $DYNAMIC -o release/libsheepyMemcheck.so libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
diff --git a/buildStaticAnalysis.sh b/buildStaticAnalysis.sh
@@ -8,10 +8,12 @@ $CC11 ./release/libsheepyObject.h
$CC ./release/libsheepy.h
$CC ./release/json/recycleContainers.h
$CC ./release/libsheepySmall.h
+$CC ./release/libsheepyBt.h
echo "Compiling C files"
$CC -c release/libsheepy.c
$CC -c release/libsheepySmall.c
+$CC -c release/libsheepyBt.c
$CC -c src/json/libsheepyObject.c
$CC -c src/json/libsheepyCSmallJson.c
$CC -c src/json/libsheepyCUndefined.c
@@ -31,4 +33,4 @@ $CC -c src/json/ymlReader.c
$CC -c src/tpool.c
echo "Building static lib"
-$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+$STATIC release/libsheepy.a libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
diff --git a/clean.sh b/clean.sh
@@ -1,2 +1,2 @@
-rm libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o release/libsheepy.a release/libsheepy.so release/libsheepyMemcheck.a release/libsheepyMemcheck.so release/libsheepyAsan.a release/libsheepyAsan.so
+rm libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o release/libsheepy.a release/libsheepy.so release/libsheepyMemcheck.a release/libsheepyMemcheck.so release/libsheepyAsan.a release/libsheepyAsan.so
rm release/*.gch
diff --git a/cleanObjects.sh b/cleanObjects.sh
@@ -1,2 +1,2 @@
# clean objects only, keep libsheepy.a and .so, because libsheepyMemcheck is built after libsheepy with recycling
-rm libsheepy.o libsheepySmall.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
+rm libsheepy.o libsheepySmall.o libsheepyBt.o libsheepyObject.o libsheepyCSmallJson.o libsheepyCUndefined.o libsheepyCSmallDict.o libsheepyCSmallArray.o libsheepyCSmallBytes.o libsheepyCSmallBool.o libsheepyCSmallContainer.o libsheepyCSmallDouble.o libsheepyCSmallInt.o libsheepyCSmallString.o laxjson.o ymlParser.o ymlApi.o ymlScanner.o ymlReader.o tpool.o
diff --git a/example/README.template b/example/README.template
@@ -62,7 +62,7 @@ libsheepy is NULL safe and any parameter can be NULL.
- the list*S functions assume the list elements are not NULL
- the listn*S functions can process lists with NULL elements. When there are NULL elements, the developer has to keep track of the list length.
-Check out the [user guide](http://spartatek.se/libsheepyUserGuide/) to learn how to use libsheepy and read the more detailed documentation at [http://spartatek.se/libsheepy/](http://spartatek.se/libsheepy/)
+Check out the [user guide](https://spartatek.se/libsheepyUserGuide/) to learn how to use libsheepy and read the more detailed documentation at [https://spartatek.se/libsheepy/](https://spartatek.se/libsheepy/)
__Status__: (libsheepy.h and libsheepy.c)
- Unit tests: 97% code coverage of the core functionality - 98% branch coverage (mainly malloc failures are not tested)
diff --git a/install.sh b/install.sh
@@ -1,9 +1,10 @@
cp release/libsheepy.h /usr/local/include/
cp release/libsheepySmall.h /usr/local/include/
+cp release/libsheepyBt.h /usr/local/include/
cp release/libsheepyObject.h /usr/local/include/
cp release/tpool.h /usr/local/include/
cp -R release/json /usr/local/include/
-cp ./release/libsheepySmall.h.gch /usr/local/include/
+cp ./release/libsheepyBt.h.gch /usr/local/include/
cp ./release/json/recycleContainers.h.gch /usr/local/include/json/
cp ./release/libsheepy.h.gch /usr/local/include/
cp ./release/libsheepyObject.h.gch /usr/local/include/
diff --git a/installOpenIndiana.sh b/installOpenIndiana.sh
@@ -1,5 +1,6 @@
cp release/libsheepy.h /usr/include/
cp release/libsheepySmall.h /usr/include/
+cp release/libsheepyBt.h /usr/include/
cp release/libsheepyObject.h /usr/include/
cp release/tpool.h /usr/include/
cp -R release/json /usr/include/
diff --git a/release/libsheepyBt.c b/release/libsheepyBt.c
@@ -0,0 +1,871 @@
+#include "libsheepyBt.h"
+
+#ifndef LIBSHEEPY_VERSION
+#define libsheepyPrealloc (1024*1024)
+#define makeRoom(length, alloc, addlength) funcbegin\
+ typeof(alloc) r;\
+ typeof(alloc) newlen = (length) + (addlength);\
+ if (newlen < (alloc)) {\
+ r = alloc;\
+ } \
+ else {\
+ if (newlen < libsheepyPrealloc) {\
+ r = newlen * 2;\
+ }\
+ else {\
+ r = newlen + libsheepyPrealloc;\
+ }\
+ }\
+ r;\
+ funcend
+#endif
+
+/**
+ * return a bt object with s as buffer
+ */
+bt initCharB(char *s) {
+ ret charB(s);
+}
+
+/**
+ * return a bt object with s as buffer
+ * the buffer is not going to be reallocated
+ */
+bt initCCharB(char *s) {
+ ret ccharB(s);
+}
+
+/**
+ * return a bt object with buf as buffer
+ */
+bt initB(void *buf, u32 len, bool allocated) {
+ ret voidB(buf, len, allocated);
+}
+
+/**
+ * return a bt object with a heap allocated buffer of size allocateSize
+ */
+bt newB(u32 allocateSize) {
+ bt r = {.len = 0};
+ r.b = malloc(allocateSize);
+ if (!r.b) ret emptybt;
+ r.alloc = allocateSize;
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with a heap allocated buffer of size allocateSize
+ */
+bt *allocNewB(u32 allocateSize) {
+ bt *r = malloc(sizeof(*r));
+ *r = newB(allocateSize);
+ ret r;
+}
+
+// not needed, use charB or ccharB
+// /**
+// * set buf in the b bt object
+// */
+// bt *setB(bt *b, char *buf, bool allocated) {
+// if (!b or !buf) ret null;
+// b->b = buf;
+// b->len = strlen(buf);
+// b->alloc = (allocated) ? b->len : 0;
+// ret b;
+// }
+
+/**
+ * return a heap allocated bt object with buf assigned to it
+ */
+bt *allocCharB(char *buf) {
+ if (!buf) ret null;
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = charB(buf);
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with buf assigned to it
+ */
+bt *allocCCharB(char *buf) {
+ if (!buf) ret null;
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = ccharB(buf);
+ ret r;
+}
+
+bt *allocBufB(void *buf, u32 len, bool allocated) {
+ if (!buf) ret null;
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = voidB(buf, len, allocated);
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with b assigned to it
+ */
+bt *allocB(const bt b) {
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = b;
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with *b assigned to it
+ */
+bt *allocPB(const bt *b) {
+ if (!b) ret null;
+ ret allocB(*b);
+}
+
+/**
+ * return a bt object with a heap allocated copy of b.b
+ */
+bt copyB(const bt b) {
+ bt r = b;
+ r.b = malloc(b.len);
+ r.alloc = b.len;
+ memcpy(r.b, b.b, b.len);
+ ret r;
+}
+
+bt copyPB(bt *b) {
+ if (!b) ret emptybt;
+ ret copyB(*b);
+}
+
+/**
+ * return a heap allocated bt object with a heap allocated copy of b.b
+ */
+bt *dupB(const bt b) {
+ bt *r = malloc(sizeof(*r));
+ *r = copyB(b);
+ ret r;
+}
+
+bt *dupPB(bt *b) {
+ if (!b) ret null;
+ ret dupB(*b);
+}
+
+/**
+ * free heap allocated .b
+ * nothing if not heap allocated
+ */
+void freeB(bt b) {
+ if (b.alloc) {
+ free(b.b);
+ }
+}
+
+/**
+ * free heap allocated .b and assign null to .b
+ * nothing if not heap allocated
+ */
+void freenB(bt *b) {
+ if (b and b->alloc) {
+ freen(b->b);
+ b->len = 0;
+ b->alloc = 0;
+ }
+}
+
+/**
+ * free the heap allocated bt object (container only, not .b)
+ */
+void finishB(bt **b) {
+ if (b) {
+ free(*b);
+ *b = null;
+ }
+}
+
+/**
+ * free the heap allocated bt object and free .b
+ */
+void terminateB(bt **b) {
+ if (b) {
+ if (*b and (*b)->alloc) {
+ free((*b)->b);
+ }
+ free(*b);
+ *b = null;
+ }
+}
+
+// terminate val when it is out of scope
+void cleanUpTerminateB(bt **val) {
+ terminateB(val);
+}
+
+// free local val when it is out of scope
+void cleanUpFreeLocalB(bt *val) {
+ freeB(*val);
+}
+
+// free val when it is out of scope
+void cleanUpFreeB(bt **val) {
+ freeB(**val);
+}
+
+// finish val when it is out of scope
+void cleanUpFinishB(bt **val) {
+ finishB(val);
+}
+
+/**
+ * return a bt object with s appended to b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushB(const bt b, const char *s) {
+ // duplicate b.b
+ // copy s to b end
+ bt r = copyB(b);
+ bt *p = bPushB(&r, s);
+ if (p) ret r;
+ else {
+ freeB(r);
+ ret emptybt;
+ }
+}
+
+// TODO pushManyB
+
+/**
+ * update b and append s
+ * b.b is reallocated
+ */
+bt *bPushB(bt *b, const char *s) {
+ if (!b or !b->b or !s) ret null;
+
+ size_t len = strlen(s);
+ u32 newsize = makeRoom(b->len, b->alloc, len);
+ // check if there is enough space
+ if (newsize > b->alloc) {
+ u8 *tmp = realloc(b->b, newsize);
+ if (!tmp) ret null;
+ b->b = tmp;
+ b->alloc = newsize;
+ }
+ // copy s to b end
+ memcpy(b->b+b->len, s, len);
+ b->len += len;
+ ret b;
+}
+
+// TODO bPushManyB
+
+/**
+ * return a bt object with s bt object appended to b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushBB(const bt b, const bt s) {
+ // duplicate b.b
+ // copy s to b end
+ bt r = copyB(b);
+ bt *p = bPushBB(&r, s);
+ if (p) ret r;
+ else {
+ freeB(r);
+ ret emptybt;
+ }
+ ret r;
+}
+
+// TODO bPushManyBB
+
+/**
+ * update b and append s bt object
+ * b.b is reallocated
+ */
+bt *bPushBB(bt *b, const bt s) {
+
+ if (!b or !b->b or !s.b) ret null;
+ if (!s.len) ret b;
+
+ u32 newsize = makeRoom(b->len, b->alloc, s.len);
+ // check if there is enough space
+ if (newsize > b->alloc) {
+ u8 *tmp = realloc(b->b, newsize);
+ if (!tmp) ret null;
+ b->b = tmp;
+ b->alloc = newsize;
+ }
+ // copy s to b end
+ memcpy(b->b+b->len, s.b, s.len);
+ b->len += s.len;
+ ret b;
+}
+
+// TODO bPushManyBB
+
+/**
+ * return a bt object with *s bt object appended to b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushBPB(const bt b, const bt *s) {
+ if (!s) ret emptybt;
+ // duplicate b.b
+ // copy s to b end
+ ret pushBB(b, *s);
+}
+
+// TODO bPushManyBPB
+
+/**
+ * update b and append *s bt object
+ * b.b is reallocated
+ */
+bt *bPushBPB(bt *b, const bt *s) {
+ if (!s) ret null;
+ // copy s to b end
+ ret bPushBB(b, *s);
+}
+
+// TODO bPushManyBB
+
+/**
+ * return a bt object with s appended to *b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushPB(const bt *b, const char *s) {
+ if (!b) ret emptybt;
+ ret pushB(*b, s);
+}
+// TODO pushManyPB...
+
+/**
+ * return a bt object with s bt object appended to *b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushPBB(const bt *b, const bt s) {
+ if (!b) ret emptybt;
+ ret pushBB(*b, s);
+}
+// TODO pushManyPBB...
+
+/**
+ * return a bt object with *s bt object appended to *b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushPBPB(const bt *b, const bt *s) {
+ if (!b) ret emptybt;
+ ret pushBPB(*b, s);
+}
+// TODO pushManyPBPB...
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitB(vbt *vb, const bt b, const bt delim) {
+ if (!vb or !b.b or !delim.b) ret null;
+
+ vb->count = 0;
+
+ if (!delim.len or !b.len) {
+ // empty delimiter empty string, return string in a list
+ if (vb->count >= vb->maxCount) ret null;
+ vectorAppend(vb, b);
+ ret vb;
+ }
+
+ u8 *working = b.b;
+ u8 *nextTokenStart = working;
+ u32 i = 0;
+ if (delim.len == 1) {
+ while (i < b.len) {
+ u8 *ptr = memchr(working, delim.b[0], b.len-i);
+ if (!ptr)
+ break;
+ if (vb->count >= vb->maxCount) ret null;
+ nextTokenStart = ptr + 1;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ else {
+ while (i < b.len) {
+ u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
+ if (!ptr)
+ break;
+ if (vb->count >= vb->maxCount) ret null;
+ nextTokenStart = ptr + delim.len;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ if (vb->count >= vb->maxCount) ret null;
+ bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
+ vectorAppend(vb, tok);
+
+ ret vb;
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitCharB(vbt *vb, const bt b, char *delim) {
+ bt d = ccharB(delim);
+ ret sasplitB(vb, b, d);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim) {
+ if (!delim) ret null;
+ ret sasplitB(vb, b, *delim);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitPB(vbt *vb, const bt *b, const bt delim) {
+ if (!b) ret null;
+ ret sasplitB(vb, *b, delim);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim) {
+ if (!b) ret null;
+ ret sasplitCharB(vb, *b, delim);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim) {
+ if (!b or !delim) ret null;
+ ret sasplitB(vb, *b, *delim);
+}
+
+/**
+ * allocate elements
+ * only when the vector is full
+ */
+#undef vectorAlloc
+#define vectorAlloc(name) do{\
+ if (!(name)->array) {\
+ (name)->array = malloc(vectorSz * sizeof (name)->array[0]);\
+ (name)->maxCount = vectorSz;\
+ }\
+ else {\
+ u32 length = (name)->count * sizeof (name)->array[0];\
+ u32 alloc = (name)->maxCount * sizeof (name)->array[0];\
+ u32 addlength = sizeof (name)->array[0];\
+ u32 newsize = makeRoom(length,\
+ alloc,\
+ addlength\
+ );\
+ (name)->maxCount = newsize / sizeof (name)->array[0];\
+ (name)->array = realloc((name)->array, newsize);\
+ }\
+ } while(0)
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitB(vbt *vb, const bt b, const bt delim) {
+ if (!vb or !b.b or !delim.b) ret null;
+
+ vb->count = 0;
+
+ if (!delim.len or !b.len) {
+ // empty delimiter empty string, return string in a list
+ vectorAppend(vb, b);
+ ret vb;
+ }
+
+ u8 *working = b.b;
+ u8 *nextTokenStart = working;
+ u32 i = 0;
+ if (delim.len == 1) {
+ while (i < b.len) {
+ u8 *ptr = memchr(working, delim.b[0], b.len-i);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + 1;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ else {
+ while (i < b.len) {
+ u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + delim.len;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
+ vectorAppend(vb, tok);
+
+ ret vb;
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitCharB(vbt *vb, const bt b, char *delim) {
+ bt d = ccharB(delim);
+ ret asplitB(vb, b, d);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitDPB(vbt *vb, const bt b, const bt *delim) {
+ if (!delim) ret null;
+ ret asplitB(vb, b, *delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitPB(vbt *vb, const bt *b, const bt delim) {
+ if (!b) ret null;
+ ret asplitB(vb, *b, delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitPCharB(vbt *vb, const bt *b, char *delim) {
+ if (!b) ret null;
+ ret asplitCharB(vb, *b, delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim) {
+ if (!b or !delim) ret null;
+ ret asplitB(vb, *b, *delim);
+}
+
+/**
+ * return vbt vector with tokens from b
+ * this function has good performance for small element counts
+ */
+vbt splitB(const bt b, const bt delim) {
+ vbt r;
+ if (!b.b or !delim.b) ret emptyvbt;
+
+ vectorInitCount(&r, 5);
+
+ asplitB(&r, b, delim);
+
+ ret r;
+}
+
+/**
+ * return vbt vector with tokens from b
+ * this function has good performance for small element counts
+ */
+vbt splitCharB(const bt b, char *delim) {
+ vbt r;
+
+ if (!b.b or !delim) ret emptyvbt;
+
+ vectorInitCount(&r, 5);
+
+ bt d = ccharB(delim);
+ asplitB(&r, b, d);
+
+ ret r;
+}
+
+/**
+ * split b in vb vector
+ */
+vbt splitDPB(const bt b, const bt *delim) {
+ if (!delim) ret emptyvbt;
+ ret splitB(b, *delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt splitPB(const bt *b, const bt delim) {
+ if (!b) ret emptyvbt;
+ ret splitB(*b, delim);
+}
+
+/**
+ * return vbt vector with tokens from b
+ * this function has good performance for small element counts
+ */
+vbt splitPCharB(const bt *b, char *delim) {
+ if (!b) ret emptyvbt;
+ ret splitCharB(*b, delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt splitPDPB(const bt *b, const bt *delim) {
+ if (!b or !delim) ret emptyvbt;
+ ret splitB(*b, *delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitB(const bt b, const bt delim) {
+ dbt r;
+
+ if (!b.b or !delim.b) ret emptydbt;
+
+ dVectorInit(&r);
+
+ if (!delim.len or !b.len) {
+ // empty delimiter empty string, return string in a list
+ dVectorAppend(&r, b);
+ ret r;
+ }
+
+ u8 *working = b.b;
+ u8 *nextTokenStart = working;
+ u32 i = 0;
+ if (delim.len == 1) {
+ while (i < b.len) {
+ u8 *ptr = memchr(working, delim.b[0], b.len-i);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + 1;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ dVectorAppend(&r, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ else {
+ while (i < b.len) {
+ u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + delim.len;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ dVectorAppend(&r, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
+ dVectorAppend(&r, tok);
+
+ ret r;
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitCharB(const bt b, char *delim) {
+ bt d = ccharB(delim);
+ ret dsplitB(b, d);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitDPB(const bt b, const bt *delim) {
+ if (!delim) ret emptydbt;
+ ret dsplitB(b, *delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitPB(const bt *b, const bt delim) {
+ if (!b) ret emptydbt;
+ ret dsplitB(*b, delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitPCharB(const bt *b, char *delim) {
+ if (!b) ret emptydbt;
+ ret dsplitCharB(*b, delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitPDPB(const bt *b, const bt *delim) {
+ if (!b or !delim) ret emptydbt;
+ ret dsplitB(*b, *delim);
+}
+
+/**
+ * slice String
+ * return a bt object which is the string between start and end
+ * negative indexes are allowed
+ */
+bt sliceB(const bt b, int64_t start, int64_t end) {
+ bt r = {0};
+ if (!b.b) ret emptybt;
+
+ #define checkRange(B, rval)\
+ i64 len = (B).len;\
+ if (start > len)\
+ ret rval;\
+ if (end > len)\
+ end = len;\
+ if (start <= -len)\
+ start = -len;\
+ if (end <= -len)\
+ ret rval;\
+ if (start < 0)\
+ start = len + start;\
+ if (end <= 0)\
+ end = len + end;\
+ if (end < start)\
+ ret rval
+ checkRange(b, emptybt);
+
+ r.b = b.b + start;
+ if (start == end) {
+ // empty string
+ r.len = 0;
+ }
+ else {
+ // start < end < len
+ r.len = end - start;
+ }
+ ret r;
+}
+
+/**
+ * slice String
+ * update the b bt object and keep only the string between start and end
+ * negative indexes are allowed
+ */
+bt *bSliceB(bt *b, int64_t start, int64_t end) {
+ if (!b) ret null;
+
+ checkRange(*b, null);
+
+ if (start == end) {
+ // empty string
+ b->len = 0;
+ }
+ else {
+ // start < end < len
+ b->len = end - start;
+ if (start)
+ memmove(b->b, b->b+start, b->len);
+ }
+ ret b;
+}
+
+/**
+ * slice String
+ * return a bt object which is the string between start and end
+ * negative indexes are allowed
+ */
+bt slicePB(const bt *b, int64_t start, int64_t end) {
+ if (!b) ret emptybt;
+ ret sliceB(*b, start, end);
+}
+
+/**
+ * return a bt object without the leading and trailing spaces
+ */
+bt trimB(const bt b) {
+ bt r = {0};
+ if (!b.b) ret emptybt;
+
+ r.b = b.b;
+
+ u32 i = 0;
+
+ // remove leading spaces
+ while (i < b.len and isspace(*r.b)) {
+ i++; r.b++;
+ }
+
+ if (i == b.len) {
+ // all spaces
+ r.b = b.b;
+ ret r;
+ }
+
+ // remove trailing spaces
+ u8 *end = b.b + b.len - 1;
+ while (isspace(*end))
+ end--;
+
+ r.len = end - r.b + 1;
+
+ ret r;
+}
+
+/**
+ * update b bt object and remove the leading and trailing spaces
+ */
+// memmove data
+bt *bTrimB(bt *b) {
+ if (!b or !b->b) ret null;
+
+ bt t = trimB(*b);
+
+ if (t.b != b->b)
+ memmove(b->b, t.b, t.len);
+ b->len = t.len;
+
+ ret b;
+}
+
+/**
+ * return a bt object without the leading and trailing spaces
+ */
+bt trimPB(const bt *b) {
+ if (!b) emptybt;
+ ret trimB(*b);
+}
+
+void printB(const bt b) {
+ write(STDOUT_FILENO, b.b, b.len);
+}
+
+void printDebugB(const bt b) {
+ write(STDOUT_FILENO, "\"", 1);
+ printB(b);
+ write(STDOUT_FILENO, "\"", 1);
+ put;
+}
+
+void printDebugInfoB(const bt b) {
+ logD("b: %p, len: %"PRIu32", alloc: %"PRIu32, b.b, b.len, b.alloc);
+ printDebugB(b);
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/release/libsheepyBt.h b/release/libsheepyBt.h
@@ -0,0 +1,830 @@
+/*
+ * bt is a dynamic Byte buffer Type (Bytes Type)
+ *
+ * Status: under development, not tested, the comments don't match the implementation
+ *
+ * # How bt works
+ *
+ * When a bt object represents a string, it doesn't need to be NUL terminated,
+ * this allow spliting string more efficiently.
+ *
+ * - simple to use
+ * - binary safe
+ * - computationally efficient
+ * - works with memcheck
+ *
+ *
+ * # Advantages and disadvantages of bt
+ *
+ * bt is implemented using a structure defining the byte buffer like this:
+ * ```
+ * struct {
+ * u8 *b;
+ * u32 len;
+ * u32 alloc;
+ * } bt;
+ * ```
+ * The bt structure is managed by the *B functions.
+ *
+ * - Disadvantage 1: bt doesn't work with standard C string functions
+ *
+ * - Advantage 1: Giving the address of a bt to B functions, updates the bt in place:
+ * ```
+ * pushBG(&b, s);
+ * ```
+ *
+ * - Advantage 2: trimming and slicing buffers don't need memory allocations and spliting uses less memory allocations
+ *
+ * - Advantage 3: the index for accessing the bytes in bt is range check in the getB, setB functions and it works even the buffer in bt is reallocated
+ *
+ *
+ * # bt basics
+ *
+ * Here is how to declare a bt, assign a string (RO) and print it:
+ *
+ * ```
+ * bt mystring = ccharB("Hello World!");
+ * printB(mystring);
+ *
+ * output> Hello World!
+ * ```
+ *
+ * The above small program shows a few important things about bt:
+ * - bt are stack allocated (or heap allocated)
+ * - printB prints the bt content
+ * - there is no memory allocations so there is no free.
+ *
+ *
+ * # Creating bt strings
+ *
+ * ```
+ * bt mystring = ccharB("Hello World!");
+ * bt mystring2 = charB(strdup("Hello World!"), true);
+ * bt mybuf = voidB("Binary", sizeof("Binary"), false);
+ * createCharB(mystring3, "bytes", false);
+ * // from another string:
+ * bt mirror = mystring;
+ * bt empty = {0};
+ * // preallocate buf
+ * bt pre = newB(allocateSize);
+ * // allocate bt struct and buf
+ * bt *heap = allocNewB(allocateSize);
+ *
+ * // allocate and set string
+ * bt *new = allocB("STR", false);
+ * finishB(new);
+ * ```
+ *
+ * # Obtaining the string length
+ *
+ * ```
+ * int len = mystring.len;
+ * ```
+ *
+ *
+ * # Destroying strings
+ *
+ * - freeB frees the buffer pointed by .b and can be called with non allocated bt objects (it does nothing)
+ * - terminateB frees the buffer if allocated and the bt struct
+ * - finishB frees the bt struct only (doesn't touch the .b buffer)
+ *
+ *
+ * # Concatenating strings
+ *
+ * ```
+ * createCharB(str, strdup("Hello "), true);
+ * pushBG(&str, "World!");
+ * printB(str);
+ * freeB(str);
+ *
+ * output> Hello World!
+ * ```
+ *
+ *
+ * # TODO Formatting strings
+ *
+ *
+ * # Trimming and slicing
+ *
+ * ```
+ * bt T = ccharB(" trim ");
+ * bt r = trimB(T);
+ * bt s = sliceB(T, 2, 6);
+ * ```
+ *
+ *
+ * # String copying
+ *
+ * ```
+ * // copy bt
+ * bt mystringCopy = copyB(mystring);
+ * // the buffer in mystringCopy is heap allocated
+ * freeB(mystringCopy);
+ *
+ * // duplicate bt
+ * bt *dup = dupB(mystring);
+ * // dup and the buffer in dup are heap allocated
+ * terminateB(dup);
+ * ```
+ *
+ * # Splitting strings
+ *
+ * ```
+ * bt ss = ccharB("Hello World!");
+ * vbt lsspl = splitB(ss, " ");
+ * puts("");
+ * vectorForEach(&ll, e) {
+ * printB(*e);
+ * puts("");
+ * }
+ * vectorFree(&lsspl);
+ * ```
+ *
+ *
+ * # Inner workings
+ *
+ * When alloc is 0 and len > 0, the buffer has not been allocated
+ *
+ * createCharB declares a bt object with the given string, there is no allocation
+ *
+ * Appending strings:
+ * s is updated, b or i are same
+ * bPushB(&s, "qwqw");
+ * bPushManyB(&s, "qwqw", "qweqw");
+ *
+ * New string:
+ * 1 malloc (better cache locality):
+ * bt s2 = pushB(s, "qweqwe");
+ * bt s3 = pushManyB(s, "qweqwe", "wer");
+ *
+ * //2 mallocs:
+ * //bt *s4 = appendB(s, "qweqwe");
+ * //bt *s5 = appendManyB(s, "qweqwe", "wer");
+ *
+ * bt s6 = catB("1","2");
+ *
+ * pushB(&s, s2);
+ *
+ * Printing string:
+ * logI("%q", &s);
+ * printf("%c %c\n", s.b[0], s.b[1]);
+ *
+ * Spliting string doesn't require any buffer copying
+ * createCharB(h, "Hello World!", 0);
+ *
+ * bt h2 = {0};
+ * h2.b = h.b+6;
+ * h2.len = 5;
+ *
+ * Example:
+ * Empty bt:
+ * bt s = {0};
+ * Assign C string:
+ * s = charB("a string", no);
+ * s.b = "asdasd";
+ * b.len = strlen(s.b);
+ *
+ */
+#pragma once
+
+#include "libsheepy.h"
+
+// bt bytes type
+// point to a byte buffer at .b of length .len
+// .alloc is the allocated size of the buffer
+typ struct {
+ u8 *b;
+ u32 len;
+ u32 alloc;
+} bt;
+
+typ struct {
+ u8 *b;
+ u64 len;
+ u64 alloc;
+} b64t;
+// TODO functions supporting b64t
+
+// vector of bt elements
+// This data structure has good performance for small element counts
+typ struct {
+ u32 count;
+ u32 maxCount;
+ bt *array;
+} vbt;
+
+// dynamic segmented vector of bt elements
+// This data structure has good performance for large element counts
+typ struct {
+ u32 count;
+ u32 maxCount;
+ void** buffers;
+ bt element;
+} dbt;
+
+// object returned by some functions
+#define emptybt ((bt){0})
+#define emptyvbt ((vbt){0})
+#define emptydbt ((dbt){0})
+
+
+// assign a u8 a[count] array to bt object
+// Example:
+// u8 s[10] = {0};
+// bt b;
+// arrayB(b, s);
+#define arrayB(name, a)\
+ (name).b = a; (name).len = 0; (name).alloc = ARRAY_SIZE(a)
+
+// declare name vbt object and assign the a array defined as bt a[maxCnt] with cnt element already initialized
+#define vectorB(name, a, cnt, maxCnt)\
+ vbt name; name.count = cnt; name.maxCount = maxCnt; name.array = a
+
+// declare name vbt object, declare the a array of count bt elements and assign it to name the vbt object
+#define listB(name, a, maxCnt)\
+ bt a[maxCnt] = {0}; vbt name; name.count = 0; name.maxCount = maxCnt; name.array = a
+
+// declare name vbt object and assign the empty a array defined as bt a[maxCnt]
+#define listAB(name, a)\
+ vbt name; name.count = 0; name.maxCount = ARRAY_SIZE(a); name.array = a
+
+// initialize a bt object with a heap allocated string
+#define charB(string) (bt){.b = string, .len = strlen(string), .alloc = strlen(string)}
+// initialize a bt object with a string that can't be reallocated
+#define ccharB(string) (bt){.b = string, .len = strlen(string), .alloc = 0 }
+// initialize a bt object with a heap allocated binary buffer
+#define voidB( buf, length, allocated) (bt){.b = buf, .len = length, .alloc = (allocated) ? length : 0 }
+
+
+/**
+ * declare pointer name with type bt and terminate name when it is out of scope
+ */
+#define cleanBP(name) bt *name CLEANUP(cleanUpTerminateB)
+
+/**
+ * allocate bt (pointer) and clean up when it is out of scope
+ */
+#define cleanAllocateB(obj) ;cleanBP(obj); obj = allocNewB(8)
+
+/**
+ * declare local object name with type bt and free name when it is out of scope
+ */
+#define cleanB(name) bt name CLEANUP(cleanUpFreeLocalB)
+
+/**
+ * declare pointer name with type bt and free name when it is out of scope
+ */
+#define cleanFreeBP(name) bt *name CLEANUP(cleanUpFreeB)
+
+/**
+ * declare pointer name with type bt and finish name when it is out of scope
+ */
+#define cleanFinishBP(name) bt *name CLEANUP(cleanUpFinishB)
+
+// create name bt object and initialize it with a string
+// string is char* and is evaluated one time, allocated true/false
+#define createCharB(name, string, allocated) bt name;u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = (allocated) ? name.len : 0
+
+// create name bt object and initialize it with a binary buffer
+#define createB(name, buf, length, allocated) bt name;name.b = buf; name.len = len; name.alloc = (allocated) ? name.length : 0
+
+#define createAllocateCharB(name, string, allocated)\
+ bt *name = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0
+
+#define createAllocateB(name, buf, length, allocated)\
+ bt *name = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0
+
+// create clean name bt object and initialize it with a string
+// string is char* and is evaluated one time
+#define cleanCharB(name, string) cleanB(name);u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = name.len
+
+// create clean name bt object and initialize it with a binary buffer
+#define ccleanB(name, buf, length) cleanB(name);name.b = buf; name.len = len; name.alloc = name.length
+
+#define cleanAllocateCharB(name, string, allocated)\
+ cleanBP(name) = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0
+
+#define ccleanAllocateB(name, buf, length, allocated)\
+ cleanBP(name) = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0
+
+
+// return a bt object with s as buffer
+bt initCharB(char *s);
+
+// return a bt object with s as buffer
+// the buffer is not going to be reallocated
+bt initCCharB(char *s);
+
+// return a bt object with buf as buffer
+bt initB(void *buf, u32 len, bool allocated);
+
+// return a bt object with a heap allocated buffer of size allocateSize
+bt newB(u32 allocateSize);
+
+// return a heap allocated bt object with a heap allocated buffer of size allocateSize
+bt *allocNewB(u32 allocateSize);
+
+// return a heap allocated bt object with buf assigned to it
+bt *allocCharB(char *buf);
+
+// return a heap allocated bt object with buf assigned to it
+bt *allocCCharB(char *buf);
+
+bt *allocBufB(void *buf, u32 len, bool allocated);
+
+// return a heap allocated bt object with b assigned to it
+bt *allocB(const bt b);
+
+/**
+ * return a heap allocated bt object with *b assigned to it
+ */
+bt *allocPB(const bt *b);
+
+#define allocBG(b) _Generic(b,\
+ bt: allocB,\
+ const bt: allocB,\
+ bt*: allocPB,\
+ const bt*: allocPB,\
+ char*: allocCharB,\
+ const char*: allocCCharB\
+ )(b)
+
+// return a bt object with a heap allocated copy of b.b
+bt copyB(const bt b);
+
+bt copyPB(bt *b);
+
+#define copyBG(b) _Generic(b,\
+ bt: copyB,\
+ bt*: copyPB\
+ )(b)
+
+// return a heap allocated bt object with a heap allocated copy of b.b
+bt *dupB(const bt b);
+
+bt *dupPB(bt *b);
+
+#define dupBG(b) _Generic(b,\
+ bt: dupB,\
+ bt*: dupPB\
+ )(b)
+
+// TODO:
+// ..lenB
+// ..freeB
+// ..terminateB(bt *b)
+// ..pushBB
+// ..pushManyBB
+// // NO - growzero: memset 0 to new part
+// ..slice
+// ..trim
+// formatB
+// iFormatB
+// bFormatB
+// ..copyB
+// ..splitB
+// splitLenB
+// listFreeB
+// join
+// toCharB convert to char*
+// getB setB setBB set .b getBB get .b
+//
+// extra sds splitargs
+// splitArgs quoted string, multiple spaces
+
+
+// use b.b instead
+// u8* bufferB(bt b) {
+// ret b.b;
+// }
+
+// use b.len instead
+// size_t lenB(bt b) {
+// ret b.len;
+// }
+
+/**
+ * free heap allocated .b
+ * nothing if not heap allocated
+ */
+void freeB(bt b);
+
+/**
+ * free heap allocated .b and assign null to .b
+ * nothing if not heap allocated
+ */
+void freenB(bt *b);
+
+/**
+ * free the heap allocated bt object (container only, not .b)
+ */
+void finishB(bt **b);
+
+/**
+ * free the heap allocated bt object and free .b
+ */
+void terminateB(bt **b);
+
+// terminate val when it is out of scope
+void cleanUpTerminateB(bt **val);
+
+// free local val when it is out of scope
+void cleanUpFreeLocalB(bt *val);
+
+// free val when it is out of scope
+void cleanUpFreeB(bt **val);
+
+// finish val when it is out of scope
+void cleanUpFinishB(bt **val);
+
+// return a bt object with s appended to b
+// b doesn't need to have a heap allocated buffer
+#define appendB pushB
+bt pushB(const bt b, const char *s);
+
+// TODO pushManyB
+
+// update b and append s
+// b.b is reallocated
+#define bAppendB bPushB
+bt *bPushB(bt *b, const char *s);
+
+// TODO bPushManyB
+
+// return a bt object with s bt object appended to b
+// b doesn't need to have a heap allocated buffer
+#define appendBB pushBB
+bt pushBB(const bt b, const bt s);
+
+// TODO bPushManyBB
+
+// update b and append s bt object
+// b.b is reallocated
+#define bAppendBB bPushBB
+bt *bPushBB(bt *b, const bt s);
+
+// TODO bPushManyBB
+
+// return a bt object with *s bt object appended to b
+// b doesn't need to have a heap allocated buffer
+#define appendBPB pushBPB
+bt pushBPB(const bt b, const bt *s);
+
+// TODO bPushManyBPB
+
+// update b and append *s bt object
+// b.b is reallocated
+#define bAppendBPB bPushBPB
+bt *bPushBPB(bt *b, const bt *s);
+
+// TODO bPushManyBB
+
+// return a bt object with s appended to *b
+// b doesn't need to have a heap allocated buffer
+#define appendPB pushPB
+bt pushPB(const bt *b, const char *s);
+// TODO pushManyPB...
+
+// return a bt object with s bt object appended to *b
+// b doesn't need to have a heap allocated buffer
+#define appendPBB pushPBB
+bt pushPBB(const bt *b, const bt s);
+// TODO pushManyPBB...
+
+// return a bt object with *s bt object appended to *b
+// b doesn't need to have a heap allocated buffer
+#define appendPBPB pushPBPB
+bt pushPBPB(const bt *b, const bt *s);
+// TODO pushManyPBPB...
+
+#define appendBG pushBG
+#define pushBG(b, s) _Generic( b,\
+ bt: _Generic(s,\
+ const char *: pushB,\
+ char *: pushB,\
+ const bt: pushBB,\
+ bt: pushBB,\
+ const bt*: pushBPB,\
+ bt*: pushBPB\
+ ),\
+ bt*: _Generic(s,\
+ const char *: bPushB,\
+ char *: bPushB,\
+ const bt: bPushBB,\
+ bt: bPushBB,\
+ const bt*: bPushBPB,\
+ bt*: bPushBPB\
+ ),\
+ const bt*: _Generic(s,\
+ const char *: pushPB,\
+ char *: pushPB,\
+ const bt: pushPBB,\
+ bt: pushPBB,\
+ const bt*: pushPBPB,\
+ bt*: pushPBPB\
+ )\
+ )(b, s)
+
+// bt catBF(const char *paramType, ...) MUST_CHECK;
+#define catB(...) catBF("", __VA_ARGS__, NULL)
+
+// add allocates bt object
+// bt *addBF(const char *paramType, ...) MUST_CHECK;
+#define addB(...) catBF("", __VA_ARGS__, NULL)
+
+// %q to print bt
+// %Q to print bt*
+// printB(char *fmt, ...)
+
+// register %q and %Q
+// register_printf_specifier('q', print_q, print_q_arginfo);
+// register_printf_specifier('Q', print_Q, print_Q_arginfo);
+
+/**
+ * %q printf type specifier, RGB foreground, uint32_t
+ */
+// int print_q(FILE *stream, const struct printf_info *info, const void *const *args) {
+// u32 rgbColor;
+// char b[20];
+// int len;
+//
+// rgbColor = *((const u32*) args[0]);
+// snprintf(b, sizeof(b), TERMRGB "%u;%u;%um", rgbColor>>16, (rgbColor&0xFF00)>>8, rgbColor&0xFF);
+//
+// /* Pad to the minimum field width and print to the stream. */
+// //len = fprintf(stream, "%*s", (info->left ? -info->width : info->width), b)
+// sheepyRGBFP;
+// return(len);
+// }
+
+/**
+ * procress printf argument
+ */
+// int print_q_arginfo(const struct printf_info *info UNUSED, size_t n, int *argtypes, int* size) {
+//
+// if (n > 0) {
+// argtypes[0] = PA_POINTER;
+// size[0] = sizeof(u32);
+// }
+// return(1);
+// }
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitB(vbt *vb, const bt b, const bt delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitCharB(vbt *vb, const bt b, char *delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitPB(vbt *vb, const bt *b, const bt delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim);
+
+#define sasplitBG(vb, b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: sasplitCharB,\
+ const char*: sasplitCharB,\
+ bt: sasplitB,\
+ const bt: sasplitB,\
+ bt*: sasplitDPB,\
+ const bt*: sasplitDPB),\
+ const bt: _Generic(delim,\
+ char*: sasplitCharB,\
+ const char*: sasplitCharB,\
+ bt: sasplitB,\
+ const bt: sasplitB,\
+ bt*: sasplitDPB,\
+ const bt*: sasplitDPB),\
+ bt*: _Generic(delim,\
+ char*: sasplitPCharB,\
+ const char*: sasplitPCharB,\
+ bt: sasplitPB,\
+ const bt: sasplitPB,\
+ bt*: sasplitPDPB,\
+ const bt*: sasplitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: sasplitPCharB,\
+ const char*: sasplitPCharB,\
+ bt: sasplitPB,\
+ const bt: sasplitPB,\
+ bt*: sasplitPDPB,\
+ const bt*: sasplitPDPB)\
+ )(vb, b, delim)
+
+// split b in vb vector
+vbt *asplitB(vbt *vb, const bt b, const bt delim);
+
+// split b in vb vector
+vbt *asplitCharB(vbt *vb, const bt b, char *delim);
+
+// split b in vb vector
+vbt *asplitDPB(vbt *vb, const bt b, const bt *delim);
+
+// split b in vb vector
+vbt *asplitPB(vbt *vb, const bt *b, const bt delim);
+
+// split b in vb vector
+vbt *asplitPCharB(vbt *vb, const bt *b, char *delim);
+
+// split b in vb vector
+vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim);
+
+#define asplitBG(vb, b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: asplitCharB,\
+ const char*: asplitCharB,\
+ bt: asplitB,\
+ const bt: asplitB,\
+ bt*: asplitDPB,\
+ const bt*: asplitDPB),\
+ const bt: _Generic(delim,\
+ char*: asplitCharB,\
+ const char*: asplitCharB,\
+ bt: asplitB,\
+ const bt: asplitB,\
+ bt*: asplitDPB,\
+ const bt*: asplitDPB),\
+ bt*: _Generic(delim,\
+ char*: asplitPCharB,\
+ const char*: asplitPCharB,\
+ bt: asplitPB,\
+ const bt: asplitPB,\
+ bt*: asplitPDPB,\
+ const bt*: asplitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: asplitPCharB,\
+ const char*: asplitPCharB,\
+ bt: asplitPB,\
+ const bt: asplitPB,\
+ bt*: asplitPDPB,\
+ const bt*: asplitPDPB)\
+ )(vb, b, delim)
+
+// return vbt vector with tokens from b
+// this function has good performance for small element counts
+vbt splitB(const bt b, const bt delim);
+
+// return vbt vector with tokens from b
+// this function has good performance for small element counts
+vbt splitCharB(const bt b, char *delim);
+
+// split b in vb vector
+vbt splitDPB(const bt b, const bt *delim);
+
+// split b in vb vector
+vbt splitPB(const bt *b, const bt delim);
+
+// return vbt vector with tokens from b
+// this function has good performance for small element counts
+vbt splitPCharB(const bt *b, char *delim);
+
+// split b in vb vector
+vbt splitPDPB(const bt *b, const bt *delim);
+
+#define splitBG(b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: splitCharB,\
+ const char*: splitCharB,\
+ bt: splitB,\
+ const bt: splitB,\
+ bt*: splitDPB,\
+ const bt*: splitDPB),\
+ const bt: _Generic(delim,\
+ char*: splitCharB,\
+ const char*: splitCharB,\
+ bt: splitB,\
+ const bt: splitB,\
+ bt*: splitDPB,\
+ const bt*: splitDPB),\
+ bt*: _Generic(delim,\
+ char*: splitPCharB,\
+ const char*: splitPCharB,\
+ bt: splitPB,\
+ const bt: splitPB,\
+ bt*: splitPDPB,\
+ const bt*: splitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: splitPCharB,\
+ const char*: splitPCharB,\
+ bt: splitPB,\
+ const bt: splitPB,\
+ bt*: splitPDPB,\
+ const bt*: splitPDPB)\
+ )(b, delim)
+
+
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitB(const bt b, const bt delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitCharB(const bt b, char *delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitDPB(const bt b, const bt *delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitPB(const bt *b, const bt delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitPCharB(const bt *b, char *delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitPDPB(const bt *b, const bt *delim);
+
+#define dsplitBG(b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: dsplitCharB,\
+ const char*: dsplitCharB,\
+ bt: dsplitB,\
+ const bt: dsplitB,\
+ bt*: dsplitDPB,\
+ const bt*: dsplitDPB),\
+ const bt: _Generic(delim,\
+ char*: dsplitCharB,\
+ const char*: dsplitCharB,\
+ bt: dsplitB,\
+ const bt: dsplitB,\
+ bt*: dsplitDPB,\
+ const bt*: dsplitDPB),\
+ bt*: _Generic(delim,\
+ char*: dsplitPCharB,\
+ const char*: dsplitPCharB,\
+ bt: dsplitPB,\
+ const bt: dsplitPB,\
+ bt*: dsplitPDPB,\
+ const bt*: dsplitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: dsplitPCharB,\
+ const char*: dsplitPCharB,\
+ bt: dsplitPB,\
+ const bt: dsplitPB,\
+ bt*: dsplitPDPB,\
+ const bt*: dsplitPDPB)\
+ )(b, delim)
+
+
+// slice String
+// return a bt object which is the string between start and end
+// negative indexes are allowed
+bt sliceB(const bt b, int64_t start, int64_t end);
+
+// slice String
+// update the b bt object and keep only the string between start and end
+// negative indexes are allowed
+bt *bSliceB(bt *b, int64_t start, int64_t end);
+
+// slice String
+// return a bt object which is the string between start and end
+// negative indexes are allowed
+bt slicePB(const bt *b, int64_t start, int64_t end);
+
+#define sliceBG(b, start, end) _Generic(b,\
+ bt: sliceB,\
+ const bt: sliceB,\
+ bt*: bSliceB,\
+ const bt*: slicePB\
+ )(b, start, end);
+
+// return a bt object without the leading and trailing spaces
+bt trimB(const bt b);
+
+// update b bt object and remove the leading and trailing spaces
+bt *bTrimB(bt *b);
+
+// return a bt object without the leading and trailing spaces
+bt trimPB(const bt *b);
+
+#define trimBG(b) _Generic(b,\
+ bt: trimB,\
+ const bt: trimB,\
+ bt*: bTrimB,\
+ const bt*: trimPB\
+ )(b)
+
+void printB(const bt b);
+
+void printDebugB(const bt b);
+
+void printDebugInfoB(const bt b);
+
+// vim: set expandtab ts=2 sw=2:
diff --git a/release/libsheepyObject.h b/release/libsheepyObject.h
@@ -50,6 +50,7 @@
#include "libsheepy.h"
#include "libsheepySmall.h"
+#include "libsheepyBt.h"
#if (!__OpenBSD__) && ! defined(__TINYC__) && (__GNUC__ > 4)
#include "stdatomic.h"
#endif
diff --git a/src/libsheepyBt.c b/src/libsheepyBt.c
@@ -0,0 +1,871 @@
+#include "libsheepyBt.h"
+
+#ifndef LIBSHEEPY_VERSION
+#define libsheepyPrealloc (1024*1024)
+#define makeRoom(length, alloc, addlength) funcbegin\
+ typeof(alloc) r;\
+ typeof(alloc) newlen = (length) + (addlength);\
+ if (newlen < (alloc)) {\
+ r = alloc;\
+ } \
+ else {\
+ if (newlen < libsheepyPrealloc) {\
+ r = newlen * 2;\
+ }\
+ else {\
+ r = newlen + libsheepyPrealloc;\
+ }\
+ }\
+ r;\
+ funcend
+#endif
+
+/**
+ * return a bt object with s as buffer
+ */
+bt initCharB(char *s) {
+ ret charB(s);
+}
+
+/**
+ * return a bt object with s as buffer
+ * the buffer is not going to be reallocated
+ */
+bt initCCharB(char *s) {
+ ret ccharB(s);
+}
+
+/**
+ * return a bt object with buf as buffer
+ */
+bt initB(void *buf, u32 len, bool allocated) {
+ ret voidB(buf, len, allocated);
+}
+
+/**
+ * return a bt object with a heap allocated buffer of size allocateSize
+ */
+bt newB(u32 allocateSize) {
+ bt r = {.len = 0};
+ r.b = malloc(allocateSize);
+ if (!r.b) ret emptybt;
+ r.alloc = allocateSize;
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with a heap allocated buffer of size allocateSize
+ */
+bt *allocNewB(u32 allocateSize) {
+ bt *r = malloc(sizeof(*r));
+ *r = newB(allocateSize);
+ ret r;
+}
+
+// not needed, use charB or ccharB
+// /**
+// * set buf in the b bt object
+// */
+// bt *setB(bt *b, char *buf, bool allocated) {
+// if (!b or !buf) ret null;
+// b->b = buf;
+// b->len = strlen(buf);
+// b->alloc = (allocated) ? b->len : 0;
+// ret b;
+// }
+
+/**
+ * return a heap allocated bt object with buf assigned to it
+ */
+bt *allocCharB(char *buf) {
+ if (!buf) ret null;
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = charB(buf);
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with buf assigned to it
+ */
+bt *allocCCharB(char *buf) {
+ if (!buf) ret null;
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = ccharB(buf);
+ ret r;
+}
+
+bt *allocBufB(void *buf, u32 len, bool allocated) {
+ if (!buf) ret null;
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = voidB(buf, len, allocated);
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with b assigned to it
+ */
+bt *allocB(const bt b) {
+ bt *r = malloc(sizeof(*r));
+ if (!r) ret null;
+ *r = b;
+ ret r;
+}
+
+/**
+ * return a heap allocated bt object with *b assigned to it
+ */
+bt *allocPB(const bt *b) {
+ if (!b) ret null;
+ ret allocB(*b);
+}
+
+/**
+ * return a bt object with a heap allocated copy of b.b
+ */
+bt copyB(const bt b) {
+ bt r = b;
+ r.b = malloc(b.len);
+ r.alloc = b.len;
+ memcpy(r.b, b.b, b.len);
+ ret r;
+}
+
+bt copyPB(bt *b) {
+ if (!b) ret emptybt;
+ ret copyB(*b);
+}
+
+/**
+ * return a heap allocated bt object with a heap allocated copy of b.b
+ */
+bt *dupB(const bt b) {
+ bt *r = malloc(sizeof(*r));
+ *r = copyB(b);
+ ret r;
+}
+
+bt *dupPB(bt *b) {
+ if (!b) ret null;
+ ret dupB(*b);
+}
+
+/**
+ * free heap allocated .b
+ * nothing if not heap allocated
+ */
+void freeB(bt b) {
+ if (b.alloc) {
+ free(b.b);
+ }
+}
+
+/**
+ * free heap allocated .b and assign null to .b
+ * nothing if not heap allocated
+ */
+void freenB(bt *b) {
+ if (b and b->alloc) {
+ freen(b->b);
+ b->len = 0;
+ b->alloc = 0;
+ }
+}
+
+/**
+ * free the heap allocated bt object (container only, not .b)
+ */
+void finishB(bt **b) {
+ if (b) {
+ free(*b);
+ *b = null;
+ }
+}
+
+/**
+ * free the heap allocated bt object and free .b
+ */
+void terminateB(bt **b) {
+ if (b) {
+ if (*b and (*b)->alloc) {
+ free((*b)->b);
+ }
+ free(*b);
+ *b = null;
+ }
+}
+
+// terminate val when it is out of scope
+void cleanUpTerminateB(bt **val) {
+ terminateB(val);
+}
+
+// free local val when it is out of scope
+void cleanUpFreeLocalB(bt *val) {
+ freeB(*val);
+}
+
+// free val when it is out of scope
+void cleanUpFreeB(bt **val) {
+ freeB(**val);
+}
+
+// finish val when it is out of scope
+void cleanUpFinishB(bt **val) {
+ finishB(val);
+}
+
+/**
+ * return a bt object with s appended to b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushB(const bt b, const char *s) {
+ // duplicate b.b
+ // copy s to b end
+ bt r = copyB(b);
+ bt *p = bPushB(&r, s);
+ if (p) ret r;
+ else {
+ freeB(r);
+ ret emptybt;
+ }
+}
+
+// TODO pushManyB
+
+/**
+ * update b and append s
+ * b.b is reallocated
+ */
+bt *bPushB(bt *b, const char *s) {
+ if (!b or !b->b or !s) ret null;
+
+ size_t len = strlen(s);
+ u32 newsize = makeRoom(b->len, b->alloc, len);
+ // check if there is enough space
+ if (newsize > b->alloc) {
+ u8 *tmp = realloc(b->b, newsize);
+ if (!tmp) ret null;
+ b->b = tmp;
+ b->alloc = newsize;
+ }
+ // copy s to b end
+ memcpy(b->b+b->len, s, len);
+ b->len += len;
+ ret b;
+}
+
+// TODO bPushManyB
+
+/**
+ * return a bt object with s bt object appended to b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushBB(const bt b, const bt s) {
+ // duplicate b.b
+ // copy s to b end
+ bt r = copyB(b);
+ bt *p = bPushBB(&r, s);
+ if (p) ret r;
+ else {
+ freeB(r);
+ ret emptybt;
+ }
+ ret r;
+}
+
+// TODO bPushManyBB
+
+/**
+ * update b and append s bt object
+ * b.b is reallocated
+ */
+bt *bPushBB(bt *b, const bt s) {
+
+ if (!b or !b->b or !s.b) ret null;
+ if (!s.len) ret b;
+
+ u32 newsize = makeRoom(b->len, b->alloc, s.len);
+ // check if there is enough space
+ if (newsize > b->alloc) {
+ u8 *tmp = realloc(b->b, newsize);
+ if (!tmp) ret null;
+ b->b = tmp;
+ b->alloc = newsize;
+ }
+ // copy s to b end
+ memcpy(b->b+b->len, s.b, s.len);
+ b->len += s.len;
+ ret b;
+}
+
+// TODO bPushManyBB
+
+/**
+ * return a bt object with *s bt object appended to b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushBPB(const bt b, const bt *s) {
+ if (!s) ret emptybt;
+ // duplicate b.b
+ // copy s to b end
+ ret pushBB(b, *s);
+}
+
+// TODO bPushManyBPB
+
+/**
+ * update b and append *s bt object
+ * b.b is reallocated
+ */
+bt *bPushBPB(bt *b, const bt *s) {
+ if (!s) ret null;
+ // copy s to b end
+ ret bPushBB(b, *s);
+}
+
+// TODO bPushManyBB
+
+/**
+ * return a bt object with s appended to *b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushPB(const bt *b, const char *s) {
+ if (!b) ret emptybt;
+ ret pushB(*b, s);
+}
+// TODO pushManyPB...
+
+/**
+ * return a bt object with s bt object appended to *b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushPBB(const bt *b, const bt s) {
+ if (!b) ret emptybt;
+ ret pushBB(*b, s);
+}
+// TODO pushManyPBB...
+
+/**
+ * return a bt object with *s bt object appended to *b
+ * b doesn't need to have a heap allocated buffer
+ */
+bt pushPBPB(const bt *b, const bt *s) {
+ if (!b) ret emptybt;
+ ret pushBPB(*b, s);
+}
+// TODO pushManyPBPB...
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitB(vbt *vb, const bt b, const bt delim) {
+ if (!vb or !b.b or !delim.b) ret null;
+
+ vb->count = 0;
+
+ if (!delim.len or !b.len) {
+ // empty delimiter empty string, return string in a list
+ if (vb->count >= vb->maxCount) ret null;
+ vectorAppend(vb, b);
+ ret vb;
+ }
+
+ u8 *working = b.b;
+ u8 *nextTokenStart = working;
+ u32 i = 0;
+ if (delim.len == 1) {
+ while (i < b.len) {
+ u8 *ptr = memchr(working, delim.b[0], b.len-i);
+ if (!ptr)
+ break;
+ if (vb->count >= vb->maxCount) ret null;
+ nextTokenStart = ptr + 1;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ else {
+ while (i < b.len) {
+ u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
+ if (!ptr)
+ break;
+ if (vb->count >= vb->maxCount) ret null;
+ nextTokenStart = ptr + delim.len;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ if (vb->count >= vb->maxCount) ret null;
+ bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
+ vectorAppend(vb, tok);
+
+ ret vb;
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitCharB(vbt *vb, const bt b, char *delim) {
+ bt d = ccharB(delim);
+ ret sasplitB(vb, b, d);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim) {
+ if (!delim) ret null;
+ ret sasplitB(vb, b, *delim);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitPB(vbt *vb, const bt *b, const bt delim) {
+ if (!b) ret null;
+ ret sasplitB(vb, *b, delim);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim) {
+ if (!b) ret null;
+ ret sasplitCharB(vb, *b, delim);
+}
+
+/**
+ * split b in vb static vector
+ * the vector is not reallocated
+ */
+vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim) {
+ if (!b or !delim) ret null;
+ ret sasplitB(vb, *b, *delim);
+}
+
+/**
+ * allocate elements
+ * only when the vector is full
+ */
+#undef vectorAlloc
+#define vectorAlloc(name) do{\
+ if (!(name)->array) {\
+ (name)->array = malloc(vectorSz * sizeof (name)->array[0]);\
+ (name)->maxCount = vectorSz;\
+ }\
+ else {\
+ u32 length = (name)->count * sizeof (name)->array[0];\
+ u32 alloc = (name)->maxCount * sizeof (name)->array[0];\
+ u32 addlength = sizeof (name)->array[0];\
+ u32 newsize = makeRoom(length,\
+ alloc,\
+ addlength\
+ );\
+ (name)->maxCount = newsize / sizeof (name)->array[0];\
+ (name)->array = realloc((name)->array, newsize);\
+ }\
+ } while(0)
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitB(vbt *vb, const bt b, const bt delim) {
+ if (!vb or !b.b or !delim.b) ret null;
+
+ vb->count = 0;
+
+ if (!delim.len or !b.len) {
+ // empty delimiter empty string, return string in a list
+ vectorAppend(vb, b);
+ ret vb;
+ }
+
+ u8 *working = b.b;
+ u8 *nextTokenStart = working;
+ u32 i = 0;
+ if (delim.len == 1) {
+ while (i < b.len) {
+ u8 *ptr = memchr(working, delim.b[0], b.len-i);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + 1;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ else {
+ while (i < b.len) {
+ u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + delim.len;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ vectorAppend(vb, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
+ vectorAppend(vb, tok);
+
+ ret vb;
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitCharB(vbt *vb, const bt b, char *delim) {
+ bt d = ccharB(delim);
+ ret asplitB(vb, b, d);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitDPB(vbt *vb, const bt b, const bt *delim) {
+ if (!delim) ret null;
+ ret asplitB(vb, b, *delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitPB(vbt *vb, const bt *b, const bt delim) {
+ if (!b) ret null;
+ ret asplitB(vb, *b, delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitPCharB(vbt *vb, const bt *b, char *delim) {
+ if (!b) ret null;
+ ret asplitCharB(vb, *b, delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim) {
+ if (!b or !delim) ret null;
+ ret asplitB(vb, *b, *delim);
+}
+
+/**
+ * return vbt vector with tokens from b
+ * this function has good performance for small element counts
+ */
+vbt splitB(const bt b, const bt delim) {
+ vbt r;
+ if (!b.b or !delim.b) ret emptyvbt;
+
+ vectorInitCount(&r, 5);
+
+ asplitB(&r, b, delim);
+
+ ret r;
+}
+
+/**
+ * return vbt vector with tokens from b
+ * this function has good performance for small element counts
+ */
+vbt splitCharB(const bt b, char *delim) {
+ vbt r;
+
+ if (!b.b or !delim) ret emptyvbt;
+
+ vectorInitCount(&r, 5);
+
+ bt d = ccharB(delim);
+ asplitB(&r, b, d);
+
+ ret r;
+}
+
+/**
+ * split b in vb vector
+ */
+vbt splitDPB(const bt b, const bt *delim) {
+ if (!delim) ret emptyvbt;
+ ret splitB(b, *delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt splitPB(const bt *b, const bt delim) {
+ if (!b) ret emptyvbt;
+ ret splitB(*b, delim);
+}
+
+/**
+ * return vbt vector with tokens from b
+ * this function has good performance for small element counts
+ */
+vbt splitPCharB(const bt *b, char *delim) {
+ if (!b) ret emptyvbt;
+ ret splitCharB(*b, delim);
+}
+
+/**
+ * split b in vb vector
+ */
+vbt splitPDPB(const bt *b, const bt *delim) {
+ if (!b or !delim) ret emptyvbt;
+ ret splitB(*b, *delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitB(const bt b, const bt delim) {
+ dbt r;
+
+ if (!b.b or !delim.b) ret emptydbt;
+
+ dVectorInit(&r);
+
+ if (!delim.len or !b.len) {
+ // empty delimiter empty string, return string in a list
+ dVectorAppend(&r, b);
+ ret r;
+ }
+
+ u8 *working = b.b;
+ u8 *nextTokenStart = working;
+ u32 i = 0;
+ if (delim.len == 1) {
+ while (i < b.len) {
+ u8 *ptr = memchr(working, delim.b[0], b.len-i);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + 1;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ dVectorAppend(&r, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ else {
+ while (i < b.len) {
+ u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
+ if (!ptr)
+ break;
+ nextTokenStart = ptr + delim.len;
+ bt tok = {.b = working, .len = ptr-working, .alloc = 0};
+ dVectorAppend(&r, tok);
+ i += tok.len + delim.len;
+ working = b.b + i;
+ }
+ }
+ bt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
+ dVectorAppend(&r, tok);
+
+ ret r;
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitCharB(const bt b, char *delim) {
+ bt d = ccharB(delim);
+ ret dsplitB(b, d);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitDPB(const bt b, const bt *delim) {
+ if (!delim) ret emptydbt;
+ ret dsplitB(b, *delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitPB(const bt *b, const bt delim) {
+ if (!b) ret emptydbt;
+ ret dsplitB(*b, delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitPCharB(const bt *b, char *delim) {
+ if (!b) ret emptydbt;
+ ret dsplitCharB(*b, delim);
+}
+
+/**
+ * return dbt vector with tokens from b
+ * this function has good performance for large element counts
+ */
+dbt dsplitPDPB(const bt *b, const bt *delim) {
+ if (!b or !delim) ret emptydbt;
+ ret dsplitB(*b, *delim);
+}
+
+/**
+ * slice String
+ * return a bt object which is the string between start and end
+ * negative indexes are allowed
+ */
+bt sliceB(const bt b, int64_t start, int64_t end) {
+ bt r = {0};
+ if (!b.b) ret emptybt;
+
+ #define checkRange(B, rval)\
+ i64 len = (B).len;\
+ if (start > len)\
+ ret rval;\
+ if (end > len)\
+ end = len;\
+ if (start <= -len)\
+ start = -len;\
+ if (end <= -len)\
+ ret rval;\
+ if (start < 0)\
+ start = len + start;\
+ if (end <= 0)\
+ end = len + end;\
+ if (end < start)\
+ ret rval
+ checkRange(b, emptybt);
+
+ r.b = b.b + start;
+ if (start == end) {
+ // empty string
+ r.len = 0;
+ }
+ else {
+ // start < end < len
+ r.len = end - start;
+ }
+ ret r;
+}
+
+/**
+ * slice String
+ * update the b bt object and keep only the string between start and end
+ * negative indexes are allowed
+ */
+bt *bSliceB(bt *b, int64_t start, int64_t end) {
+ if (!b) ret null;
+
+ checkRange(*b, null);
+
+ if (start == end) {
+ // empty string
+ b->len = 0;
+ }
+ else {
+ // start < end < len
+ b->len = end - start;
+ if (start)
+ memmove(b->b, b->b+start, b->len);
+ }
+ ret b;
+}
+
+/**
+ * slice String
+ * return a bt object which is the string between start and end
+ * negative indexes are allowed
+ */
+bt slicePB(const bt *b, int64_t start, int64_t end) {
+ if (!b) ret emptybt;
+ ret sliceB(*b, start, end);
+}
+
+/**
+ * return a bt object without the leading and trailing spaces
+ */
+bt trimB(const bt b) {
+ bt r = {0};
+ if (!b.b) ret emptybt;
+
+ r.b = b.b;
+
+ u32 i = 0;
+
+ // remove leading spaces
+ while (i < b.len and isspace(*r.b)) {
+ i++; r.b++;
+ }
+
+ if (i == b.len) {
+ // all spaces
+ r.b = b.b;
+ ret r;
+ }
+
+ // remove trailing spaces
+ u8 *end = b.b + b.len - 1;
+ while (isspace(*end))
+ end--;
+
+ r.len = end - r.b + 1;
+
+ ret r;
+}
+
+/**
+ * update b bt object and remove the leading and trailing spaces
+ */
+// memmove data
+bt *bTrimB(bt *b) {
+ if (!b or !b->b) ret null;
+
+ bt t = trimB(*b);
+
+ if (t.b != b->b)
+ memmove(b->b, t.b, t.len);
+ b->len = t.len;
+
+ ret b;
+}
+
+/**
+ * return a bt object without the leading and trailing spaces
+ */
+bt trimPB(const bt *b) {
+ if (!b) emptybt;
+ ret trimB(*b);
+}
+
+void printB(const bt b) {
+ write(STDOUT_FILENO, b.b, b.len);
+}
+
+void printDebugB(const bt b) {
+ write(STDOUT_FILENO, "\"", 1);
+ printB(b);
+ write(STDOUT_FILENO, "\"", 1);
+ put;
+}
+
+void printDebugInfoB(const bt b) {
+ logD("b: %p, len: %"PRIu32", alloc: %"PRIu32, b.b, b.len, b.alloc);
+ printDebugB(b);
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/src/libsheepyBt.h b/src/libsheepyBt.h
@@ -0,0 +1,830 @@
+/*
+ * bt is a dynamic Byte buffer Type (Bytes Type)
+ *
+ * Status: under development, not tested, the comments don't match the implementation
+ *
+ * # How bt works
+ *
+ * When a bt object represents a string, it doesn't need to be NUL terminated,
+ * this allow spliting string more efficiently.
+ *
+ * - simple to use
+ * - binary safe
+ * - computationally efficient
+ * - works with memcheck
+ *
+ *
+ * # Advantages and disadvantages of bt
+ *
+ * bt is implemented using a structure defining the byte buffer like this:
+ * ```
+ * struct {
+ * u8 *b;
+ * u32 len;
+ * u32 alloc;
+ * } bt;
+ * ```
+ * The bt structure is managed by the *B functions.
+ *
+ * - Disadvantage 1: bt doesn't work with standard C string functions
+ *
+ * - Advantage 1: Giving the address of a bt to B functions, updates the bt in place:
+ * ```
+ * pushBG(&b, s);
+ * ```
+ *
+ * - Advantage 2: trimming and slicing buffers don't need memory allocations and spliting uses less memory allocations
+ *
+ * - Advantage 3: the index for accessing the bytes in bt is range check in the getB, setB functions and it works even the buffer in bt is reallocated
+ *
+ *
+ * # bt basics
+ *
+ * Here is how to declare a bt, assign a string (RO) and print it:
+ *
+ * ```
+ * bt mystring = ccharB("Hello World!");
+ * printB(mystring);
+ *
+ * output> Hello World!
+ * ```
+ *
+ * The above small program shows a few important things about bt:
+ * - bt are stack allocated (or heap allocated)
+ * - printB prints the bt content
+ * - there is no memory allocations so there is no free.
+ *
+ *
+ * # Creating bt strings
+ *
+ * ```
+ * bt mystring = ccharB("Hello World!");
+ * bt mystring2 = charB(strdup("Hello World!"), true);
+ * bt mybuf = voidB("Binary", sizeof("Binary"), false);
+ * createCharB(mystring3, "bytes", false);
+ * // from another string:
+ * bt mirror = mystring;
+ * bt empty = {0};
+ * // preallocate buf
+ * bt pre = newB(allocateSize);
+ * // allocate bt struct and buf
+ * bt *heap = allocNewB(allocateSize);
+ *
+ * // allocate and set string
+ * bt *new = allocB("STR", false);
+ * finishB(new);
+ * ```
+ *
+ * # Obtaining the string length
+ *
+ * ```
+ * int len = mystring.len;
+ * ```
+ *
+ *
+ * # Destroying strings
+ *
+ * - freeB frees the buffer pointed by .b and can be called with non allocated bt objects (it does nothing)
+ * - terminateB frees the buffer if allocated and the bt struct
+ * - finishB frees the bt struct only (doesn't touch the .b buffer)
+ *
+ *
+ * # Concatenating strings
+ *
+ * ```
+ * createCharB(str, strdup("Hello "), true);
+ * pushBG(&str, "World!");
+ * printB(str);
+ * freeB(str);
+ *
+ * output> Hello World!
+ * ```
+ *
+ *
+ * # TODO Formatting strings
+ *
+ *
+ * # Trimming and slicing
+ *
+ * ```
+ * bt T = ccharB(" trim ");
+ * bt r = trimB(T);
+ * bt s = sliceB(T, 2, 6);
+ * ```
+ *
+ *
+ * # String copying
+ *
+ * ```
+ * // copy bt
+ * bt mystringCopy = copyB(mystring);
+ * // the buffer in mystringCopy is heap allocated
+ * freeB(mystringCopy);
+ *
+ * // duplicate bt
+ * bt *dup = dupB(mystring);
+ * // dup and the buffer in dup are heap allocated
+ * terminateB(dup);
+ * ```
+ *
+ * # Splitting strings
+ *
+ * ```
+ * bt ss = ccharB("Hello World!");
+ * vbt lsspl = splitB(ss, " ");
+ * puts("");
+ * vectorForEach(&ll, e) {
+ * printB(*e);
+ * puts("");
+ * }
+ * vectorFree(&lsspl);
+ * ```
+ *
+ *
+ * # Inner workings
+ *
+ * When alloc is 0 and len > 0, the buffer has not been allocated
+ *
+ * createCharB declares a bt object with the given string, there is no allocation
+ *
+ * Appending strings:
+ * s is updated, b or i are same
+ * bPushB(&s, "qwqw");
+ * bPushManyB(&s, "qwqw", "qweqw");
+ *
+ * New string:
+ * 1 malloc (better cache locality):
+ * bt s2 = pushB(s, "qweqwe");
+ * bt s3 = pushManyB(s, "qweqwe", "wer");
+ *
+ * //2 mallocs:
+ * //bt *s4 = appendB(s, "qweqwe");
+ * //bt *s5 = appendManyB(s, "qweqwe", "wer");
+ *
+ * bt s6 = catB("1","2");
+ *
+ * pushB(&s, s2);
+ *
+ * Printing string:
+ * logI("%q", &s);
+ * printf("%c %c\n", s.b[0], s.b[1]);
+ *
+ * Spliting string doesn't require any buffer copying
+ * createCharB(h, "Hello World!", 0);
+ *
+ * bt h2 = {0};
+ * h2.b = h.b+6;
+ * h2.len = 5;
+ *
+ * Example:
+ * Empty bt:
+ * bt s = {0};
+ * Assign C string:
+ * s = charB("a string", no);
+ * s.b = "asdasd";
+ * b.len = strlen(s.b);
+ *
+ */
+#pragma once
+
+#include "libsheepy.h"
+
+// bt bytes type
+// point to a byte buffer at .b of length .len
+// .alloc is the allocated size of the buffer
+typ struct {
+ u8 *b;
+ u32 len;
+ u32 alloc;
+} bt;
+
+typ struct {
+ u8 *b;
+ u64 len;
+ u64 alloc;
+} b64t;
+// TODO functions supporting b64t
+
+// vector of bt elements
+// This data structure has good performance for small element counts
+typ struct {
+ u32 count;
+ u32 maxCount;
+ bt *array;
+} vbt;
+
+// dynamic segmented vector of bt elements
+// This data structure has good performance for large element counts
+typ struct {
+ u32 count;
+ u32 maxCount;
+ void** buffers;
+ bt element;
+} dbt;
+
+// object returned by some functions
+#define emptybt ((bt){0})
+#define emptyvbt ((vbt){0})
+#define emptydbt ((dbt){0})
+
+
+// assign a u8 a[count] array to bt object
+// Example:
+// u8 s[10] = {0};
+// bt b;
+// arrayB(b, s);
+#define arrayB(name, a)\
+ (name).b = a; (name).len = 0; (name).alloc = ARRAY_SIZE(a)
+
+// declare name vbt object and assign the a array defined as bt a[maxCnt] with cnt element already initialized
+#define vectorB(name, a, cnt, maxCnt)\
+ vbt name; name.count = cnt; name.maxCount = maxCnt; name.array = a
+
+// declare name vbt object, declare the a array of count bt elements and assign it to name the vbt object
+#define listB(name, a, maxCnt)\
+ bt a[maxCnt] = {0}; vbt name; name.count = 0; name.maxCount = maxCnt; name.array = a
+
+// declare name vbt object and assign the empty a array defined as bt a[maxCnt]
+#define listAB(name, a)\
+ vbt name; name.count = 0; name.maxCount = ARRAY_SIZE(a); name.array = a
+
+// initialize a bt object with a heap allocated string
+#define charB(string) (bt){.b = string, .len = strlen(string), .alloc = strlen(string)}
+// initialize a bt object with a string that can't be reallocated
+#define ccharB(string) (bt){.b = string, .len = strlen(string), .alloc = 0 }
+// initialize a bt object with a heap allocated binary buffer
+#define voidB( buf, length, allocated) (bt){.b = buf, .len = length, .alloc = (allocated) ? length : 0 }
+
+
+/**
+ * declare pointer name with type bt and terminate name when it is out of scope
+ */
+#define cleanBP(name) bt *name CLEANUP(cleanUpTerminateB)
+
+/**
+ * allocate bt (pointer) and clean up when it is out of scope
+ */
+#define cleanAllocateB(obj) ;cleanBP(obj); obj = allocNewB(8)
+
+/**
+ * declare local object name with type bt and free name when it is out of scope
+ */
+#define cleanB(name) bt name CLEANUP(cleanUpFreeLocalB)
+
+/**
+ * declare pointer name with type bt and free name when it is out of scope
+ */
+#define cleanFreeBP(name) bt *name CLEANUP(cleanUpFreeB)
+
+/**
+ * declare pointer name with type bt and finish name when it is out of scope
+ */
+#define cleanFinishBP(name) bt *name CLEANUP(cleanUpFinishB)
+
+// create name bt object and initialize it with a string
+// string is char* and is evaluated one time, allocated true/false
+#define createCharB(name, string, allocated) bt name;u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = (allocated) ? name.len : 0
+
+// create name bt object and initialize it with a binary buffer
+#define createB(name, buf, length, allocated) bt name;name.b = buf; name.len = len; name.alloc = (allocated) ? name.length : 0
+
+#define createAllocateCharB(name, string, allocated)\
+ bt *name = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0
+
+#define createAllocateB(name, buf, length, allocated)\
+ bt *name = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0
+
+// create clean name bt object and initialize it with a string
+// string is char* and is evaluated one time
+#define cleanCharB(name, string) cleanB(name);u8 *UNIQVAR(s) = (u8*)string;name.b = UNIQVAR(s); name.len = strlen(UNIQVAR(s)); name.alloc = name.len
+
+// create clean name bt object and initialize it with a binary buffer
+#define ccleanB(name, buf, length) cleanB(name);name.b = buf; name.len = len; name.alloc = name.length
+
+#define cleanAllocateCharB(name, string, allocated)\
+ cleanBP(name) = malloc(sizeof(*name)); u8 *UNIQVAR(s) = (u8*)string;name->b = UNIQVAR(s); name->len = strlen(UNIQVAR(s)); name->alloc = (allocated) ? name->len : 0
+
+#define ccleanAllocateB(name, buf, length, allocated)\
+ cleanBP(name) = malloc(sizeof(*name));name->b = buf; name->len = length; name->alloc = (allocated) ? name->len : 0
+
+
+// return a bt object with s as buffer
+bt initCharB(char *s);
+
+// return a bt object with s as buffer
+// the buffer is not going to be reallocated
+bt initCCharB(char *s);
+
+// return a bt object with buf as buffer
+bt initB(void *buf, u32 len, bool allocated);
+
+// return a bt object with a heap allocated buffer of size allocateSize
+bt newB(u32 allocateSize);
+
+// return a heap allocated bt object with a heap allocated buffer of size allocateSize
+bt *allocNewB(u32 allocateSize);
+
+// return a heap allocated bt object with buf assigned to it
+bt *allocCharB(char *buf);
+
+// return a heap allocated bt object with buf assigned to it
+bt *allocCCharB(char *buf);
+
+bt *allocBufB(void *buf, u32 len, bool allocated);
+
+// return a heap allocated bt object with b assigned to it
+bt *allocB(const bt b);
+
+/**
+ * return a heap allocated bt object with *b assigned to it
+ */
+bt *allocPB(const bt *b);
+
+#define allocBG(b) _Generic(b,\
+ bt: allocB,\
+ const bt: allocB,\
+ bt*: allocPB,\
+ const bt*: allocPB,\
+ char*: allocCharB,\
+ const char*: allocCCharB\
+ )(b)
+
+// return a bt object with a heap allocated copy of b.b
+bt copyB(const bt b);
+
+bt copyPB(bt *b);
+
+#define copyBG(b) _Generic(b,\
+ bt: copyB,\
+ bt*: copyPB\
+ )(b)
+
+// return a heap allocated bt object with a heap allocated copy of b.b
+bt *dupB(const bt b);
+
+bt *dupPB(bt *b);
+
+#define dupBG(b) _Generic(b,\
+ bt: dupB,\
+ bt*: dupPB\
+ )(b)
+
+// TODO:
+// ..lenB
+// ..freeB
+// ..terminateB(bt *b)
+// ..pushBB
+// ..pushManyBB
+// // NO - growzero: memset 0 to new part
+// ..slice
+// ..trim
+// formatB
+// iFormatB
+// bFormatB
+// ..copyB
+// ..splitB
+// splitLenB
+// listFreeB
+// join
+// toCharB convert to char*
+// getB setB setBB set .b getBB get .b
+//
+// extra sds splitargs
+// splitArgs quoted string, multiple spaces
+
+
+// use b.b instead
+// u8* bufferB(bt b) {
+// ret b.b;
+// }
+
+// use b.len instead
+// size_t lenB(bt b) {
+// ret b.len;
+// }
+
+/**
+ * free heap allocated .b
+ * nothing if not heap allocated
+ */
+void freeB(bt b);
+
+/**
+ * free heap allocated .b and assign null to .b
+ * nothing if not heap allocated
+ */
+void freenB(bt *b);
+
+/**
+ * free the heap allocated bt object (container only, not .b)
+ */
+void finishB(bt **b);
+
+/**
+ * free the heap allocated bt object and free .b
+ */
+void terminateB(bt **b);
+
+// terminate val when it is out of scope
+void cleanUpTerminateB(bt **val);
+
+// free local val when it is out of scope
+void cleanUpFreeLocalB(bt *val);
+
+// free val when it is out of scope
+void cleanUpFreeB(bt **val);
+
+// finish val when it is out of scope
+void cleanUpFinishB(bt **val);
+
+// return a bt object with s appended to b
+// b doesn't need to have a heap allocated buffer
+#define appendB pushB
+bt pushB(const bt b, const char *s);
+
+// TODO pushManyB
+
+// update b and append s
+// b.b is reallocated
+#define bAppendB bPushB
+bt *bPushB(bt *b, const char *s);
+
+// TODO bPushManyB
+
+// return a bt object with s bt object appended to b
+// b doesn't need to have a heap allocated buffer
+#define appendBB pushBB
+bt pushBB(const bt b, const bt s);
+
+// TODO bPushManyBB
+
+// update b and append s bt object
+// b.b is reallocated
+#define bAppendBB bPushBB
+bt *bPushBB(bt *b, const bt s);
+
+// TODO bPushManyBB
+
+// return a bt object with *s bt object appended to b
+// b doesn't need to have a heap allocated buffer
+#define appendBPB pushBPB
+bt pushBPB(const bt b, const bt *s);
+
+// TODO bPushManyBPB
+
+// update b and append *s bt object
+// b.b is reallocated
+#define bAppendBPB bPushBPB
+bt *bPushBPB(bt *b, const bt *s);
+
+// TODO bPushManyBB
+
+// return a bt object with s appended to *b
+// b doesn't need to have a heap allocated buffer
+#define appendPB pushPB
+bt pushPB(const bt *b, const char *s);
+// TODO pushManyPB...
+
+// return a bt object with s bt object appended to *b
+// b doesn't need to have a heap allocated buffer
+#define appendPBB pushPBB
+bt pushPBB(const bt *b, const bt s);
+// TODO pushManyPBB...
+
+// return a bt object with *s bt object appended to *b
+// b doesn't need to have a heap allocated buffer
+#define appendPBPB pushPBPB
+bt pushPBPB(const bt *b, const bt *s);
+// TODO pushManyPBPB...
+
+#define appendBG pushBG
+#define pushBG(b, s) _Generic( b,\
+ bt: _Generic(s,\
+ const char *: pushB,\
+ char *: pushB,\
+ const bt: pushBB,\
+ bt: pushBB,\
+ const bt*: pushBPB,\
+ bt*: pushBPB\
+ ),\
+ bt*: _Generic(s,\
+ const char *: bPushB,\
+ char *: bPushB,\
+ const bt: bPushBB,\
+ bt: bPushBB,\
+ const bt*: bPushBPB,\
+ bt*: bPushBPB\
+ ),\
+ const bt*: _Generic(s,\
+ const char *: pushPB,\
+ char *: pushPB,\
+ const bt: pushPBB,\
+ bt: pushPBB,\
+ const bt*: pushPBPB,\
+ bt*: pushPBPB\
+ )\
+ )(b, s)
+
+// bt catBF(const char *paramType, ...) MUST_CHECK;
+#define catB(...) catBF("", __VA_ARGS__, NULL)
+
+// add allocates bt object
+// bt *addBF(const char *paramType, ...) MUST_CHECK;
+#define addB(...) catBF("", __VA_ARGS__, NULL)
+
+// %q to print bt
+// %Q to print bt*
+// printB(char *fmt, ...)
+
+// register %q and %Q
+// register_printf_specifier('q', print_q, print_q_arginfo);
+// register_printf_specifier('Q', print_Q, print_Q_arginfo);
+
+/**
+ * %q printf type specifier, RGB foreground, uint32_t
+ */
+// int print_q(FILE *stream, const struct printf_info *info, const void *const *args) {
+// u32 rgbColor;
+// char b[20];
+// int len;
+//
+// rgbColor = *((const u32*) args[0]);
+// snprintf(b, sizeof(b), TERMRGB "%u;%u;%um", rgbColor>>16, (rgbColor&0xFF00)>>8, rgbColor&0xFF);
+//
+// /* Pad to the minimum field width and print to the stream. */
+// //len = fprintf(stream, "%*s", (info->left ? -info->width : info->width), b)
+// sheepyRGBFP;
+// return(len);
+// }
+
+/**
+ * procress printf argument
+ */
+// int print_q_arginfo(const struct printf_info *info UNUSED, size_t n, int *argtypes, int* size) {
+//
+// if (n > 0) {
+// argtypes[0] = PA_POINTER;
+// size[0] = sizeof(u32);
+// }
+// return(1);
+// }
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitB(vbt *vb, const bt b, const bt delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitCharB(vbt *vb, const bt b, char *delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitDPB(vbt *vb, const bt b, const bt *delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitPB(vbt *vb, const bt *b, const bt delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitPCharB(vbt *vb, const bt *b, char *delim);
+
+// split b in vb static vector
+// the vector is not reallocated
+vbt *sasplitPDPB(vbt *vb, const bt *b, const bt *delim);
+
+#define sasplitBG(vb, b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: sasplitCharB,\
+ const char*: sasplitCharB,\
+ bt: sasplitB,\
+ const bt: sasplitB,\
+ bt*: sasplitDPB,\
+ const bt*: sasplitDPB),\
+ const bt: _Generic(delim,\
+ char*: sasplitCharB,\
+ const char*: sasplitCharB,\
+ bt: sasplitB,\
+ const bt: sasplitB,\
+ bt*: sasplitDPB,\
+ const bt*: sasplitDPB),\
+ bt*: _Generic(delim,\
+ char*: sasplitPCharB,\
+ const char*: sasplitPCharB,\
+ bt: sasplitPB,\
+ const bt: sasplitPB,\
+ bt*: sasplitPDPB,\
+ const bt*: sasplitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: sasplitPCharB,\
+ const char*: sasplitPCharB,\
+ bt: sasplitPB,\
+ const bt: sasplitPB,\
+ bt*: sasplitPDPB,\
+ const bt*: sasplitPDPB)\
+ )(vb, b, delim)
+
+// split b in vb vector
+vbt *asplitB(vbt *vb, const bt b, const bt delim);
+
+// split b in vb vector
+vbt *asplitCharB(vbt *vb, const bt b, char *delim);
+
+// split b in vb vector
+vbt *asplitDPB(vbt *vb, const bt b, const bt *delim);
+
+// split b in vb vector
+vbt *asplitPB(vbt *vb, const bt *b, const bt delim);
+
+// split b in vb vector
+vbt *asplitPCharB(vbt *vb, const bt *b, char *delim);
+
+// split b in vb vector
+vbt *asplitPDPB(vbt *vb, const bt *b, const bt *delim);
+
+#define asplitBG(vb, b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: asplitCharB,\
+ const char*: asplitCharB,\
+ bt: asplitB,\
+ const bt: asplitB,\
+ bt*: asplitDPB,\
+ const bt*: asplitDPB),\
+ const bt: _Generic(delim,\
+ char*: asplitCharB,\
+ const char*: asplitCharB,\
+ bt: asplitB,\
+ const bt: asplitB,\
+ bt*: asplitDPB,\
+ const bt*: asplitDPB),\
+ bt*: _Generic(delim,\
+ char*: asplitPCharB,\
+ const char*: asplitPCharB,\
+ bt: asplitPB,\
+ const bt: asplitPB,\
+ bt*: asplitPDPB,\
+ const bt*: asplitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: asplitPCharB,\
+ const char*: asplitPCharB,\
+ bt: asplitPB,\
+ const bt: asplitPB,\
+ bt*: asplitPDPB,\
+ const bt*: asplitPDPB)\
+ )(vb, b, delim)
+
+// return vbt vector with tokens from b
+// this function has good performance for small element counts
+vbt splitB(const bt b, const bt delim);
+
+// return vbt vector with tokens from b
+// this function has good performance for small element counts
+vbt splitCharB(const bt b, char *delim);
+
+// split b in vb vector
+vbt splitDPB(const bt b, const bt *delim);
+
+// split b in vb vector
+vbt splitPB(const bt *b, const bt delim);
+
+// return vbt vector with tokens from b
+// this function has good performance for small element counts
+vbt splitPCharB(const bt *b, char *delim);
+
+// split b in vb vector
+vbt splitPDPB(const bt *b, const bt *delim);
+
+#define splitBG(b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: splitCharB,\
+ const char*: splitCharB,\
+ bt: splitB,\
+ const bt: splitB,\
+ bt*: splitDPB,\
+ const bt*: splitDPB),\
+ const bt: _Generic(delim,\
+ char*: splitCharB,\
+ const char*: splitCharB,\
+ bt: splitB,\
+ const bt: splitB,\
+ bt*: splitDPB,\
+ const bt*: splitDPB),\
+ bt*: _Generic(delim,\
+ char*: splitPCharB,\
+ const char*: splitPCharB,\
+ bt: splitPB,\
+ const bt: splitPB,\
+ bt*: splitPDPB,\
+ const bt*: splitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: splitPCharB,\
+ const char*: splitPCharB,\
+ bt: splitPB,\
+ const bt: splitPB,\
+ bt*: splitPDPB,\
+ const bt*: splitPDPB)\
+ )(b, delim)
+
+
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitB(const bt b, const bt delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitCharB(const bt b, char *delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitDPB(const bt b, const bt *delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitPB(const bt *b, const bt delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitPCharB(const bt *b, char *delim);
+
+// return dbt vector with tokens from b
+// this function has good performance for large element counts
+dbt dsplitPDPB(const bt *b, const bt *delim);
+
+#define dsplitBG(b, delim) _Generic(b,\
+ bt: _Generic(delim,\
+ char*: dsplitCharB,\
+ const char*: dsplitCharB,\
+ bt: dsplitB,\
+ const bt: dsplitB,\
+ bt*: dsplitDPB,\
+ const bt*: dsplitDPB),\
+ const bt: _Generic(delim,\
+ char*: dsplitCharB,\
+ const char*: dsplitCharB,\
+ bt: dsplitB,\
+ const bt: dsplitB,\
+ bt*: dsplitDPB,\
+ const bt*: dsplitDPB),\
+ bt*: _Generic(delim,\
+ char*: dsplitPCharB,\
+ const char*: dsplitPCharB,\
+ bt: dsplitPB,\
+ const bt: dsplitPB,\
+ bt*: dsplitPDPB,\
+ const bt*: dsplitPDPB),\
+ const bt*: _Generic(delim,\
+ char*: dsplitPCharB,\
+ const char*: dsplitPCharB,\
+ bt: dsplitPB,\
+ const bt: dsplitPB,\
+ bt*: dsplitPDPB,\
+ const bt*: dsplitPDPB)\
+ )(b, delim)
+
+
+// slice String
+// return a bt object which is the string between start and end
+// negative indexes are allowed
+bt sliceB(const bt b, int64_t start, int64_t end);
+
+// slice String
+// update the b bt object and keep only the string between start and end
+// negative indexes are allowed
+bt *bSliceB(bt *b, int64_t start, int64_t end);
+
+// slice String
+// return a bt object which is the string between start and end
+// negative indexes are allowed
+bt slicePB(const bt *b, int64_t start, int64_t end);
+
+#define sliceBG(b, start, end) _Generic(b,\
+ bt: sliceB,\
+ const bt: sliceB,\
+ bt*: bSliceB,\
+ const bt*: slicePB\
+ )(b, start, end);
+
+// return a bt object without the leading and trailing spaces
+bt trimB(const bt b);
+
+// update b bt object and remove the leading and trailing spaces
+bt *bTrimB(bt *b);
+
+// return a bt object without the leading and trailing spaces
+bt trimPB(const bt *b);
+
+#define trimBG(b) _Generic(b,\
+ bt: trimB,\
+ const bt: trimB,\
+ bt*: bTrimB,\
+ const bt*: trimPB\
+ )(b)
+
+void printB(const bt b);
+
+void printDebugB(const bt b);
+
+void printDebugInfoB(const bt b);
+
+// vim: set expandtab ts=2 sw=2:
diff --git a/src/libsheepyObject.h b/src/libsheepyObject.h
@@ -50,6 +50,7 @@
#include "libsheepy.h"
#include "libsheepySmall.h"
+#include "libsheepyBt.h"
#if (!__OpenBSD__) && ! defined(__TINYC__) && (__GNUC__ > 4)
#include "stdatomic.h"
#endif
diff --git a/uninstall.sh b/uninstall.sh
@@ -1,2 +1,2 @@
-rm -rf /usr/local/include/libsheepy.h /usr/local/include/libsheepySmall.h /usr/local/include/libsheepyObject.h /usr/local/include/tpool.h /usr/local/include/json /usr/local/lib/libsheepy.a /usr/local/lib/libsheepy.so /usr/local/lib/libsheepyAsan.a /usr/local/lib/libsheepyAsan.so
+rm -rf /usr/local/include/libsheepy.h /usr/local/include/libsheepySmall.h /usr/local/include/libsheepyBt.h /usr/local/include/libsheepyObject.h /usr/local/include/tpool.h /usr/local/include/json /usr/local/lib/libsheepy.a /usr/local/lib/libsheepy.so /usr/local/lib/libsheepyAsan.a /usr/local/lib/libsheepyAsan.so